aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2011-10-20 21:14:49 +0000
committerDimitry Andric <dim@FreeBSD.org>2011-10-20 21:14:49 +0000
commit36981b17ed939300f6f8fc2355a255f711fcef71 (patch)
treeee2483e98b09cac943dc93a6969d83ca737ff139
parent180abc3db9ae3b4fc63cd65b15697e6ffcc8a657 (diff)
downloadsrc-36981b17ed939300f6f8fc2355a255f711fcef71.tar.gz
src-36981b17ed939300f6f8fc2355a255f711fcef71.zip
Vendor import of clang release_30 branch r142614:vendor/clang/clang-r142614
Notes
Notes: svn path=/vendor/clang/dist/; revision=226586 svn path=/vendor/clang/clang-r142614/; revision=226587; tag=vendor/clang/clang-r142614
-rw-r--r--.gitignore25
-rw-r--r--CMakeLists.txt18
-rw-r--r--INPUTS/cfg-nested-var-scopes.cpp59
-rw-r--r--Makefile14
-rw-r--r--NOTES.txt18
-rw-r--r--TODO.txt75
-rw-r--r--bindings/python/clang/cindex.py484
-rw-r--r--bindings/python/tests/cindex/test_cursor.py6
-rw-r--r--bindings/python/tests/cindex/test_diagnostics.py2
-rw-r--r--bindings/python/tests/cindex/test_location.py50
-rw-r--r--bindings/python/tests/cindex/test_type.py76
-rw-r--r--clang.xcodeproj/project.pbxproj2103
-rw-r--r--docs/AutomaticReferenceCounting.html83
-rw-r--r--docs/InternalsManual.html223
-rw-r--r--docs/LanguageExtensions.html392
-rw-r--r--docs/UsersManual.html37
-rw-r--r--docs/doxygen.cfg.in2
-rw-r--r--docs/doxygen.css30
-rw-r--r--docs/tools/clang.pod8
-rw-r--r--examples/PrintFunctionNames/PrintFunctionNames.cpp4
-rw-r--r--examples/analyzer-plugin/CMakeLists.txt14
-rw-r--r--examples/analyzer-plugin/MainCallChecker.cpp52
-rw-r--r--examples/analyzer-plugin/Makefile20
-rw-r--r--examples/clang-interpreter/main.cpp8
-rw-r--r--include/clang-c/Index.h651
-rw-r--r--include/clang/ARCMigrate/ARCMT.h46
-rw-r--r--include/clang/ARCMigrate/ARCMTActions.h6
-rw-r--r--include/clang/ARCMigrate/FileRemapper.h23
-rw-r--r--include/clang/AST/APValue.h10
-rw-r--r--include/clang/AST/ASTContext.h311
-rw-r--r--include/clang/AST/ASTDiagnostic.h16
-rw-r--r--include/clang/AST/ASTImporter.h4
-rw-r--r--include/clang/AST/ASTMutationListener.h6
-rw-r--r--include/clang/AST/Attr.h46
-rw-r--r--include/clang/AST/BaseSubobject.h87
-rw-r--r--include/clang/AST/CXXInheritance.h14
-rw-r--r--include/clang/AST/CharUnits.h6
-rw-r--r--include/clang/AST/Decl.h183
-rw-r--r--include/clang/AST/DeclBase.h110
-rw-r--r--include/clang/AST/DeclCXX.h113
-rw-r--r--include/clang/AST/DeclContextInternals.h2
-rw-r--r--include/clang/AST/DeclObjC.h305
-rw-r--r--include/clang/AST/DeclTemplate.h67
-rw-r--r--include/clang/AST/DeclVisitor.h2
-rw-r--r--include/clang/AST/DeclarationName.h10
-rw-r--r--include/clang/AST/Expr.h336
-rw-r--r--include/clang/AST/ExprCXX.h79
-rw-r--r--include/clang/AST/ExprObjC.h136
-rw-r--r--include/clang/AST/ExternalASTSource.h199
-rw-r--r--include/clang/AST/Makefile16
-rw-r--r--include/clang/AST/Mangle.h58
-rw-r--r--include/clang/AST/NestedNameSpecifier.h8
-rw-r--r--include/clang/AST/OperationKinds.h52
-rw-r--r--include/clang/AST/ParentMap.h1
-rw-r--r--include/clang/AST/PrettyPrinter.h16
-rw-r--r--include/clang/AST/RecordLayout.h10
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h25
-rw-r--r--include/clang/AST/SelectorLocationsKind.h83
-rw-r--r--include/clang/AST/Stmt.h62
-rw-r--r--include/clang/AST/StmtVisitor.h6
-rw-r--r--include/clang/AST/TemplateBase.h51
-rw-r--r--include/clang/AST/TemplateName.h7
-rw-r--r--include/clang/AST/Type.h104
-rw-r--r--include/clang/AST/TypeLoc.h68
-rw-r--r--include/clang/AST/TypeNodes.def3
-rw-r--r--include/clang/AST/TypeVisitor.h2
-rw-r--r--include/clang/AST/UnresolvedSet.h4
-rw-r--r--include/clang/AST/VTTBuilder.h176
-rw-r--r--include/clang/AST/VTableBuilder.h357
-rw-r--r--include/clang/Analysis/Analyses/FormatString.h8
-rw-r--r--include/clang/Analysis/Analyses/LiveVariables.h175
-rw-r--r--include/clang/Analysis/Analyses/ReachableCode.h2
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafety.h153
-rw-r--r--include/clang/Analysis/Analyses/UninitializedValues.h8
-rw-r--r--include/clang/Analysis/AnalysisContext.h97
-rw-r--r--include/clang/Analysis/AnalysisDiagnostic.h2
-rw-r--r--include/clang/Analysis/CFG.h154
-rw-r--r--include/clang/Analysis/DomainSpecific/CocoaConventions.h11
-rw-r--r--include/clang/Analysis/FlowSensitive/DataflowSolver.h62
-rw-r--r--include/clang/Analysis/FlowSensitive/DataflowValues.h12
-rw-r--r--include/clang/Analysis/ProgramPoint.h163
-rw-r--r--include/clang/Analysis/Support/BlkExprDeclBitVector.h24
-rw-r--r--include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h18
-rw-r--r--include/clang/Analysis/Visitors/CFGRecStmtVisitor.h6
-rw-r--r--include/clang/Analysis/Visitors/CFGStmtVisitor.h22
-rw-r--r--include/clang/Basic/Attr.td149
-rw-r--r--include/clang/Basic/Builtins.def62
-rw-r--r--include/clang/Basic/Builtins.h17
-rw-r--r--include/clang/Basic/DeclNodes.td1
-rw-r--r--include/clang/Basic/DelayedCleanupPool.h5
-rw-r--r--include/clang/Basic/Diagnostic.h296
-rw-r--r--include/clang/Basic/Diagnostic.td10
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td4
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td15
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td6
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td157
-rw-r--r--include/clang/Basic/DiagnosticGroups.td54
-rw-r--r--include/clang/Basic/DiagnosticIDs.h137
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td69
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td90
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td783
-rw-r--r--include/clang/Basic/FileManager.h33
-rw-r--r--include/clang/Basic/IdentifierTable.h46
-rw-r--r--include/clang/Basic/LLVM.h53
-rw-r--r--include/clang/Basic/LangOptions.def158
-rw-r--r--include/clang/Basic/LangOptions.h277
-rw-r--r--include/clang/Basic/MacroBuilder.h10
-rw-r--r--include/clang/Basic/Makefile20
-rw-r--r--include/clang/Basic/OnDiskHashTable.h18
-rw-r--r--include/clang/Basic/OpenCLExtensions.def4
-rw-r--r--include/clang/Basic/PartialDiagnostic.h31
-rw-r--r--include/clang/Basic/PrettyStackTrace.h2
-rw-r--r--include/clang/Basic/SourceLocation.h70
-rw-r--r--include/clang/Basic/SourceManager.h780
-rw-r--r--include/clang/Basic/SourceManagerInternals.h14
-rw-r--r--include/clang/Basic/Specifiers.h3
-rw-r--r--include/clang/Basic/StmtNodes.td3
-rw-r--r--include/clang/Basic/TargetInfo.h74
-rw-r--r--include/clang/Basic/TokenKinds.def28
-rw-r--r--include/clang/Basic/VersionTuple.h7
-rw-r--r--include/clang/CMakeLists.txt1
-rw-r--r--include/clang/CodeGen/BackendUtil.h9
-rw-r--r--include/clang/CodeGen/CodeGenAction.h2
-rw-r--r--include/clang/CodeGen/ModuleBuilder.h4
-rw-r--r--include/clang/Config/config.h.cmake3
-rw-r--r--include/clang/Driver/Action.h22
-rw-r--r--include/clang/Driver/Arg.h6
-rw-r--r--include/clang/Driver/ArgList.h62
-rw-r--r--include/clang/Driver/CC1Options.td71
-rw-r--r--include/clang/Driver/Compilation.h16
-rw-r--r--include/clang/Driver/Driver.h67
-rw-r--r--include/clang/Driver/DriverDiagnostic.h2
-rw-r--r--include/clang/Driver/Job.h13
-rw-r--r--include/clang/Driver/Makefile12
-rw-r--r--include/clang/Driver/OptTable.h8
-rw-r--r--include/clang/Driver/Option.h13
-rw-r--r--include/clang/Driver/Options.td27
-rw-r--r--include/clang/Driver/Tool.h6
-rw-r--r--include/clang/Driver/ToolChain.h27
-rw-r--r--include/clang/Driver/Types.def3
-rw-r--r--include/clang/Driver/Util.h8
-rw-r--r--include/clang/Frontend/ASTConsumers.h9
-rw-r--r--include/clang/Frontend/ASTUnit.h292
-rw-r--r--include/clang/Frontend/Analyses.def20
-rw-r--r--include/clang/Frontend/AnalyzerOptions.h15
-rw-r--r--include/clang/Frontend/ChainedDiagnosticConsumer.h (renamed from include/clang/Frontend/ChainedDiagnosticClient.h)30
-rw-r--r--include/clang/Frontend/CodeGenOptions.h3
-rw-r--r--include/clang/Frontend/CommandLineSourceLoc.h7
-rw-r--r--include/clang/Frontend/CompilerInstance.h116
-rw-r--r--include/clang/Frontend/CompilerInvocation.h12
-rw-r--r--include/clang/Frontend/DiagnosticOptions.h4
-rw-r--r--include/clang/Frontend/FrontendAction.h31
-rw-r--r--include/clang/Frontend/FrontendActions.h38
-rw-r--r--include/clang/Frontend/FrontendDiagnostic.h2
-rw-r--r--include/clang/Frontend/FrontendOptions.h15
-rw-r--r--include/clang/Frontend/HeaderSearchOptions.h40
-rw-r--r--include/clang/Frontend/LangStandard.h3
-rw-r--r--include/clang/Frontend/LangStandards.def18
-rw-r--r--include/clang/Frontend/LogDiagnosticPrinter.h18
-rw-r--r--include/clang/Frontend/PreprocessorOptions.h36
-rw-r--r--include/clang/Frontend/TextDiagnosticBuffer.h10
-rw-r--r--include/clang/Frontend/TextDiagnosticPrinter.h29
-rw-r--r--include/clang/Frontend/Utils.h16
-rw-r--r--include/clang/Frontend/VerifyDiagnosticConsumer.h (renamed from include/clang/Frontend/VerifyDiagnosticsClient.h)33
-rw-r--r--include/clang/Index/ASTLocation.h6
-rw-r--r--include/clang/Index/CallGraph.h2
-rw-r--r--include/clang/Index/Entity.h3
-rw-r--r--include/clang/Index/Handlers.h3
-rw-r--r--include/clang/Index/TranslationUnit.h4
-rw-r--r--include/clang/Lex/CodeCompletionHandler.h4
-rw-r--r--include/clang/Lex/DirectoryLookup.h47
-rw-r--r--include/clang/Lex/HeaderMap.h6
-rw-r--r--include/clang/Lex/HeaderSearch.h84
-rw-r--r--include/clang/Lex/LexDiagnostic.h2
-rw-r--r--include/clang/Lex/Lexer.h53
-rw-r--r--include/clang/Lex/LiteralSupport.h43
-rw-r--r--include/clang/Lex/MacroInfo.h33
-rw-r--r--include/clang/Lex/Makefile4
-rw-r--r--include/clang/Lex/ModuleLoader.h55
-rw-r--r--include/clang/Lex/PPCallbacks.h74
-rw-r--r--include/clang/Lex/PTHManager.h6
-rw-r--r--include/clang/Lex/Pragma.h9
-rw-r--r--include/clang/Lex/PreprocessingRecord.h377
-rw-r--r--include/clang/Lex/Preprocessor.h220
-rw-r--r--include/clang/Lex/PreprocessorLexer.h18
-rw-r--r--include/clang/Lex/Token.h5
-rw-r--r--include/clang/Lex/TokenConcatenation.h9
-rw-r--r--include/clang/Lex/TokenLexer.h16
-rw-r--r--include/clang/Makefile2
-rw-r--r--include/clang/Parse/CMakeLists.txt4
-rw-r--r--include/clang/Parse/Makefile13
-rw-r--r--include/clang/Parse/ParseAST.h8
-rw-r--r--include/clang/Parse/ParseDiagnostic.h2
-rw-r--r--include/clang/Parse/Parser.h346
-rw-r--r--include/clang/Rewrite/ASTConsumers.h12
-rw-r--r--include/clang/Rewrite/FixItRewriter.h22
-rw-r--r--include/clang/Rewrite/FrontendActions.h8
-rw-r--r--include/clang/Rewrite/Rewriter.h28
-rw-r--r--include/clang/Rewrite/Rewriters.h7
-rw-r--r--include/clang/Sema/AnalysisBasedWarnings.h1
-rw-r--r--include/clang/Sema/AttributeList.h67
-rw-r--r--include/clang/Sema/CXXFieldCollector.h4
-rw-r--r--include/clang/Sema/CodeCompleteConsumer.h80
-rw-r--r--include/clang/Sema/DeclSpec.h110
-rw-r--r--include/clang/Sema/DelayedDiagnostic.h6
-rw-r--r--include/clang/Sema/Designator.h2
-rw-r--r--include/clang/Sema/ExternalSemaSource.h120
-rw-r--r--include/clang/Sema/IdentifierResolver.h2
-rw-r--r--include/clang/Sema/Initialization.h58
-rw-r--r--include/clang/Sema/Lookup.h36
-rw-r--r--include/clang/Sema/MultiInitializer.h72
-rw-r--r--include/clang/Sema/Overload.h44
-rw-r--r--include/clang/Sema/Ownership.h3
-rw-r--r--include/clang/Sema/ParsedTemplate.h2
-rw-r--r--include/clang/Sema/PrettyDeclStackTrace.h2
-rw-r--r--include/clang/Sema/Scope.h4
-rw-r--r--include/clang/Sema/ScopeInfo.h12
-rw-r--r--include/clang/Sema/Sema.h844
-rw-r--r--include/clang/Sema/SemaDiagnostic.h2
-rw-r--r--include/clang/Sema/SemaFixItUtils.h91
-rw-r--r--include/clang/Sema/Template.h19
-rw-r--r--include/clang/Sema/TemplateDeduction.h4
-rw-r--r--include/clang/Sema/TypoCorrection.h73
-rw-r--r--include/clang/Sema/Weak.h46
-rw-r--r--include/clang/Serialization/ASTBitCodes.h199
-rw-r--r--include/clang/Serialization/ASTDeserializationListener.h2
-rw-r--r--include/clang/Serialization/ASTReader.h828
-rw-r--r--include/clang/Serialization/ASTSerializationListener.h44
-rw-r--r--include/clang/Serialization/ASTWriter.h136
-rw-r--r--include/clang/Serialization/ChainedIncludesSource.h3
-rw-r--r--include/clang/Serialization/ContinuousRangeMap.h120
-rw-r--r--include/clang/Serialization/Makefile8
-rw-r--r--include/clang/Serialization/Module.h319
-rw-r--r--include/clang/Serialization/ModuleManager.h156
-rw-r--r--include/clang/StaticAnalyzer/Checkers/ClangCheckers.h22
-rw-r--r--include/clang/StaticAnalyzer/Checkers/LocalCheckers.h22
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h360
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h183
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugType.h10
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h231
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h81
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h117
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerOptInfo.h43
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerProvider.h58
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerRegistry.h132
-rw-r--r--include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h (renamed from include/clang/StaticAnalyzer/Core/PathDiagnosticClients.h)18
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h43
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h22
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h9
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h118
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h40
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h246
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h8
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h49
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h215
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h18
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h164
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h184
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h (renamed from include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h)433
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h (renamed from include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h)57
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h37
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h50
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Store.h57
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h3
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h36
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h238
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h93
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h10
-rw-r--r--include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h14
-rw-r--r--include/clang/StaticAnalyzer/Frontend/FrontendActions.h4
-rw-r--r--lib/ARCMigrate/ARCMT.cpp154
-rw-r--r--lib/ARCMigrate/ARCMTActions.cpp18
-rw-r--r--lib/ARCMigrate/CMakeLists.txt2
-rw-r--r--lib/ARCMigrate/FileRemapper.cpp82
-rw-r--r--lib/ARCMigrate/Internals.h47
-rw-r--r--lib/ARCMigrate/PlistReporter.cpp195
-rw-r--r--lib/ARCMigrate/TransAPIUses.cpp109
-rw-r--r--lib/ARCMigrate/TransARCAssign.cpp1
-rw-r--r--lib/ARCMigrate/TransAutoreleasePool.cpp24
-rw-r--r--lib/ARCMigrate/TransBlockObjCVariable.cpp5
-rw-r--r--lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp86
-rw-r--r--lib/ARCMigrate/TransProperties.cpp105
-rw-r--r--lib/ARCMigrate/TransRetainReleaseDealloc.cpp8
-rw-r--r--lib/ARCMigrate/TransUnbridgedCasts.cpp127
-rw-r--r--lib/ARCMigrate/TransUnusedInitDelegate.cpp1
-rw-r--r--lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp1
-rw-r--r--lib/ARCMigrate/TransformActions.cpp81
-rw-r--r--lib/ARCMigrate/Transforms.cpp30
-rw-r--r--lib/ARCMigrate/Transforms.h13
-rw-r--r--lib/AST/APValue.cpp50
-rw-r--r--lib/AST/ASTContext.cpp705
-rw-r--r--lib/AST/ASTDiagnostic.cpp46
-rw-r--r--lib/AST/ASTImporter.cpp612
-rw-r--r--lib/AST/CMakeLists.txt5
-rw-r--r--lib/AST/CXXInheritance.cpp12
-rw-r--r--lib/AST/Decl.cpp172
-rw-r--r--lib/AST/DeclBase.cpp141
-rw-r--r--lib/AST/DeclCXX.cpp97
-rw-r--r--lib/AST/DeclObjC.cpp179
-rw-r--r--lib/AST/DeclPrinter.cpp277
-rw-r--r--lib/AST/DeclTemplate.cpp52
-rw-r--r--lib/AST/DeclarationName.cpp25
-rw-r--r--lib/AST/DumpXML.cpp39
-rw-r--r--lib/AST/Expr.cpp423
-rw-r--r--lib/AST/ExprCXX.cpp38
-rw-r--r--lib/AST/ExprClassification.cpp3
-rw-r--r--lib/AST/ExprConstant.cpp180
-rw-r--r--lib/AST/ExternalASTSource.cpp4
-rw-r--r--lib/AST/InheritViz.cpp8
-rw-r--r--lib/AST/ItaniumCXXABI.cpp2
-rw-r--r--lib/AST/ItaniumMangle.cpp116
-rw-r--r--lib/AST/Mangle.cpp16
-rw-r--r--lib/AST/MicrosoftCXXABI.cpp4
-rw-r--r--lib/AST/MicrosoftMangle.cpp149
-rw-r--r--lib/AST/NestedNameSpecifier.cpp4
-rw-r--r--lib/AST/ParentMap.cpp8
-rw-r--r--lib/AST/RecordLayout.cpp12
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp419
-rw-r--r--lib/AST/SelectorLocationsKind.cpp128
-rw-r--r--lib/AST/Stmt.cpp30
-rw-r--r--lib/AST/StmtDumper.cpp36
-rw-r--r--lib/AST/StmtPrinter.cpp102
-rw-r--r--lib/AST/StmtProfile.cpp9
-rw-r--r--lib/AST/TemplateBase.cpp72
-rw-r--r--lib/AST/TemplateName.cpp6
-rw-r--r--lib/AST/Type.cpp116
-rw-r--r--lib/AST/TypeLoc.cpp3
-rw-r--r--lib/AST/TypePrinter.cpp15
-rw-r--r--lib/AST/VTTBuilder.cpp212
-rw-r--r--lib/AST/VTableBuilder.cpp2404
-rw-r--r--lib/Analysis/AnalysisContext.cpp93
-rw-r--r--lib/Analysis/CFG.cpp488
-rw-r--r--lib/Analysis/CFGReachabilityAnalysis.cpp2
-rw-r--r--lib/Analysis/CFGStmtMap.cpp2
-rw-r--r--lib/Analysis/CMakeLists.txt2
-rw-r--r--lib/Analysis/CocoaConventions.cpp33
-rw-r--r--lib/Analysis/FormatString.cpp8
-rw-r--r--lib/Analysis/LiveVariables.cpp874
-rw-r--r--lib/Analysis/PrintfFormatString.cpp11
-rw-r--r--lib/Analysis/ProgramPoint.cpp51
-rw-r--r--lib/Analysis/PseudoConstantAnalysis.cpp2
-rw-r--r--lib/Analysis/ReachableCode.cpp377
-rw-r--r--lib/Analysis/ThreadSafety.cpp799
-rw-r--r--lib/Analysis/UninitializedValues.cpp326
-rw-r--r--lib/Basic/Builtins.cpp10
-rw-r--r--lib/Basic/CMakeLists.txt1
-rw-r--r--lib/Basic/Diagnostic.cpp239
-rw-r--r--lib/Basic/DiagnosticIDs.cpp397
-rw-r--r--lib/Basic/FileManager.cpp50
-rw-r--r--lib/Basic/IdentifierTable.cpp47
-rw-r--r--lib/Basic/LangOptions.cpp30
-rw-r--r--lib/Basic/SourceLocation.cpp22
-rw-r--r--lib/Basic/SourceManager.cpp797
-rw-r--r--lib/Basic/TargetInfo.cpp29
-rw-r--r--lib/Basic/Targets.cpp1102
-rw-r--r--lib/Basic/Version.cpp9
-rw-r--r--lib/Basic/VersionTuple.cpp2
-rw-r--r--lib/CodeGen/BackendUtil.cpp52
-rw-r--r--lib/CodeGen/CGBlocks.cpp162
-rw-r--r--lib/CodeGen/CGBlocks.h2
-rw-r--r--lib/CodeGen/CGBuiltin.cpp495
-rw-r--r--lib/CodeGen/CGCUDANV.cpp126
-rw-r--r--lib/CodeGen/CGCUDARuntime.cpp55
-rw-r--r--lib/CodeGen/CGCUDARuntime.h54
-rw-r--r--lib/CodeGen/CGCXX.cpp42
-rw-r--r--lib/CodeGen/CGCXXABI.cpp10
-rw-r--r--lib/CodeGen/CGCXXABI.h8
-rw-r--r--lib/CodeGen/CGCall.cpp285
-rw-r--r--lib/CodeGen/CGCall.h10
-rw-r--r--lib/CodeGen/CGClass.cpp92
-rw-r--r--lib/CodeGen/CGCleanup.cpp383
-rw-r--r--lib/CodeGen/CGCleanup.h323
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp499
-rw-r--r--lib/CodeGen/CGDebugInfo.h71
-rw-r--r--lib/CodeGen/CGDecl.cpp184
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp25
-rw-r--r--lib/CodeGen/CGException.cpp692
-rw-r--r--lib/CodeGen/CGException.h12
-rw-r--r--lib/CodeGen/CGExpr.cpp502
-rw-r--r--lib/CodeGen/CGExprAgg.cpp156
-rw-r--r--lib/CodeGen/CGExprCXX.cpp284
-rw-r--r--lib/CodeGen/CGExprComplex.cpp83
-rw-r--r--lib/CodeGen/CGExprConstant.cpp111
-rw-r--r--lib/CodeGen/CGExprScalar.cpp204
-rw-r--r--lib/CodeGen/CGObjC.cpp1362
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp378
-rw-r--r--lib/CodeGen/CGObjCMac.cpp383
-rw-r--r--lib/CodeGen/CGObjCRuntime.cpp45
-rw-r--r--lib/CodeGen/CGObjCRuntime.h3
-rw-r--r--lib/CodeGen/CGOpenCLRuntime.cpp28
-rw-r--r--lib/CodeGen/CGOpenCLRuntime.h46
-rw-r--r--lib/CodeGen/CGRTTI.cpp50
-rw-r--r--lib/CodeGen/CGRecordLayout.h11
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp32
-rw-r--r--lib/CodeGen/CGStmt.cpp129
-rw-r--r--lib/CodeGen/CGVTT.cpp421
-rw-r--r--lib/CodeGen/CGVTables.cpp2688
-rw-r--r--lib/CodeGen/CGVTables.h168
-rw-r--r--lib/CodeGen/CGValue.h109
-rw-r--r--lib/CodeGen/CMakeLists.txt3
-rw-r--r--lib/CodeGen/CodeGenAction.cpp29
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp96
-rw-r--r--lib/CodeGen/CodeGenFunction.h197
-rw-r--r--lib/CodeGen/CodeGenModule.cpp712
-rw-r--r--lib/CodeGen/CodeGenModule.h156
-rw-r--r--lib/CodeGen/CodeGenTBAA.cpp4
-rw-r--r--lib/CodeGen/CodeGenTBAA.h4
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp44
-rw-r--r--lib/CodeGen/CodeGenTypes.h10
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp128
-rw-r--r--lib/CodeGen/MicrosoftCXXABI.cpp4
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp12
-rw-r--r--lib/CodeGen/TargetInfo.cpp420
-rw-r--r--lib/CodeGen/TargetInfo.h42
-rw-r--r--lib/Driver/Action.cpp9
-rw-r--r--lib/Driver/ArgList.cpp53
-rw-r--r--lib/Driver/Compilation.cpp45
-rw-r--r--lib/Driver/Driver.cpp367
-rw-r--r--lib/Driver/HostInfo.cpp2
-rw-r--r--lib/Driver/Job.cpp6
-rw-r--r--lib/Driver/OptTable.cpp13
-rw-r--r--lib/Driver/Option.cpp12
-rw-r--r--lib/Driver/Phases.cpp4
-rw-r--r--lib/Driver/ToolChain.cpp34
-rw-r--r--lib/Driver/ToolChains.cpp792
-rw-r--r--lib/Driver/ToolChains.h27
-rw-r--r--lib/Driver/Tools.cpp880
-rw-r--r--lib/Driver/Tools.h16
-rw-r--r--lib/Driver/Types.cpp10
-rw-r--r--lib/Frontend/ASTConsumers.cpp77
-rw-r--r--lib/Frontend/ASTMerge.cpp12
-rw-r--r--lib/Frontend/ASTUnit.cpp674
-rw-r--r--lib/Frontend/CMakeLists.txt3
-rw-r--r--lib/Frontend/CacheTokens.cpp20
-rw-r--r--lib/Frontend/CompilerInstance.cpp674
-rw-r--r--lib/Frontend/CompilerInvocation.cpp388
-rw-r--r--lib/Frontend/CreateInvocationFromCommandLine.cpp10
-rw-r--r--lib/Frontend/DependencyFile.cpp44
-rw-r--r--lib/Frontend/FrontendAction.cpp30
-rw-r--r--lib/Frontend/FrontendActions.cpp90
-rw-r--r--lib/Frontend/FrontendOptions.cpp2
-rw-r--r--lib/Frontend/HeaderIncludeGen.cpp14
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp204
-rw-r--r--lib/Frontend/InitPreprocessor.cpp175
-rw-r--r--lib/Frontend/LangStandards.cpp2
-rw-r--r--lib/Frontend/LogDiagnosticPrinter.cpp67
-rw-r--r--lib/Frontend/MultiplexConsumer.cpp4
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp44
-rw-r--r--lib/Frontend/TextDiagnosticBuffer.cpp33
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp1368
-rw-r--r--lib/Frontend/VerifyDiagnosticConsumer.cpp (renamed from lib/Frontend/VerifyDiagnosticsClient.cpp)104
-rw-r--r--lib/Frontend/Warnings.cpp47
-rw-r--r--lib/FrontendTool/CMakeLists.txt4
-rw-r--r--lib/FrontendTool/ExecuteCompilerInvocation.cpp39
-rw-r--r--lib/Headers/CMakeLists.txt1
-rw-r--r--lib/Headers/Makefile4
-rw-r--r--lib/Headers/avxintrin.h2
-rw-r--r--lib/Headers/emmintrin.h70
-rw-r--r--lib/Headers/float.h2
-rw-r--r--lib/Headers/mm_malloc.h4
-rw-r--r--lib/Headers/pmmintrin.h6
-rw-r--r--lib/Headers/stdalign.h30
-rw-r--r--lib/Headers/tgmath.h7
-rw-r--r--lib/Headers/xmmintrin.h41
-rw-r--r--lib/Index/ASTLocation.cpp11
-rw-r--r--lib/Index/CallGraph.cpp2
-rw-r--r--lib/Index/Entity.cpp8
-rw-r--r--lib/Index/EntityImpl.h2
-rw-r--r--lib/Index/GlobalSelector.cpp4
-rw-r--r--lib/Lex/HeaderMap.cpp4
-rw-r--r--lib/Lex/HeaderSearch.cpp208
-rw-r--r--lib/Lex/Lexer.cpp650
-rw-r--r--lib/Lex/LiteralSupport.cpp394
-rw-r--r--lib/Lex/MacroArgs.cpp48
-rw-r--r--lib/Lex/MacroArgs.h13
-rw-r--r--lib/Lex/MacroInfo.cpp6
-rw-r--r--lib/Lex/PPCaching.cpp2
-rw-r--r--lib/Lex/PPDirectives.cpp140
-rw-r--r--lib/Lex/PPExpressions.cpp56
-rw-r--r--lib/Lex/PPLexerChange.cpp64
-rw-r--r--lib/Lex/PPMacroExpansion.cpp182
-rw-r--r--lib/Lex/PTHLexer.cpp19
-rw-r--r--lib/Lex/Pragma.cpp95
-rw-r--r--lib/Lex/PreprocessingRecord.cpp283
-rw-r--r--lib/Lex/Preprocessor.cpp268
-rw-r--r--lib/Lex/PreprocessorLexer.cpp8
-rw-r--r--lib/Lex/ScratchBuffer.cpp2
-rw-r--r--lib/Lex/TokenConcatenation.cpp72
-rw-r--r--lib/Lex/TokenLexer.cpp219
-rw-r--r--lib/Parse/CMakeLists.txt2
-rw-r--r--lib/Parse/ParseAST.cpp6
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp140
-rw-r--r--lib/Parse/ParseDecl.cpp810
-rw-r--r--lib/Parse/ParseDeclCXX.cpp418
-rw-r--r--lib/Parse/ParseExpr.cpp184
-rw-r--r--lib/Parse/ParseExprCXX.cpp577
-rw-r--r--lib/Parse/ParseInit.cpp25
-rw-r--r--lib/Parse/ParseObjc.cpp631
-rw-r--r--lib/Parse/ParsePragma.cpp19
-rw-r--r--lib/Parse/ParseStmt.cpp395
-rw-r--r--lib/Parse/ParseTemplate.cpp115
-rw-r--r--lib/Parse/ParseTentative.cpp26
-rw-r--r--lib/Parse/Parser.cpp187
-rw-r--r--lib/Parse/RAIIObjectsForParser.h4
-rw-r--r--lib/Rewrite/DeltaTree.cpp4
-rw-r--r--lib/Rewrite/FixItRewriter.cpp20
-rw-r--r--lib/Rewrite/FrontendActions.cpp16
-rw-r--r--lib/Rewrite/HTMLPrint.cpp6
-rw-r--r--lib/Rewrite/HTMLRewrite.cpp40
-rw-r--r--lib/Rewrite/RewriteMacros.cpp6
-rw-r--r--lib/Rewrite/RewriteObjC.cpp571
-rw-r--r--lib/Rewrite/RewriteRope.cpp4
-rw-r--r--lib/Rewrite/RewriteTest.cpp2
-rw-r--r--lib/Rewrite/Rewriter.cpp25
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp476
-rw-r--r--lib/Sema/AttributeList.cpp26
-rw-r--r--lib/Sema/CMakeLists.txt4
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp52
-rw-r--r--lib/Sema/DeclSpec.cpp92
-rw-r--r--lib/Sema/DelayedDiagnostic.cpp2
-rw-r--r--lib/Sema/IdentifierResolver.cpp2
-rw-r--r--lib/Sema/JumpDiagnostics.cpp79
-rw-r--r--lib/Sema/MultiInitializer.cpp92
-rw-r--r--lib/Sema/Sema.cpp388
-rw-r--r--lib/Sema/SemaAccess.cpp57
-rw-r--r--lib/Sema/SemaAttr.cpp16
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp30
-rw-r--r--lib/Sema/SemaCast.cpp (renamed from lib/Sema/SemaCXXCast.cpp)659
-rw-r--r--lib/Sema/SemaChecking.cpp808
-rw-r--r--lib/Sema/SemaCodeComplete.cpp473
-rw-r--r--lib/Sema/SemaDecl.cpp1787
-rw-r--r--lib/Sema/SemaDeclAttr.cpp1126
-rw-r--r--lib/Sema/SemaDeclCXX.cpp2643
-rw-r--r--lib/Sema/SemaDeclObjC.cpp909
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp14
-rw-r--r--lib/Sema/SemaExpr.cpp4508
-rw-r--r--lib/Sema/SemaExprCXX.cpp322
-rw-r--r--lib/Sema/SemaExprMember.cpp99
-rw-r--r--lib/Sema/SemaExprObjC.cpp539
-rw-r--r--lib/Sema/SemaFixItUtils.cpp160
-rw-r--r--lib/Sema/SemaInit.cpp1022
-rw-r--r--lib/Sema/SemaLookup.cpp285
-rw-r--r--lib/Sema/SemaObjCProperty.cpp422
-rw-r--r--lib/Sema/SemaOverload.cpp622
-rw-r--r--lib/Sema/SemaStmt.cpp417
-rw-r--r--lib/Sema/SemaTemplate.cpp206
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp233
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp88
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp636
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp55
-rw-r--r--lib/Sema/SemaType.cpp332
-rw-r--r--lib/Sema/TargetAttributesSema.cpp20
-rw-r--r--lib/Sema/TreeTransform.h249
-rw-r--r--lib/Serialization/ASTCommon.cpp1
-rw-r--r--lib/Serialization/ASTCommon.h8
-rw-r--r--lib/Serialization/ASTReader.cpp4300
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp798
-rw-r--r--lib/Serialization/ASTReaderInternals.h243
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp352
-rw-r--r--lib/Serialization/ASTWriter.cpp1259
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp121
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp50
-rw-r--r--lib/Serialization/CMakeLists.txt4
-rw-r--r--lib/Serialization/ChainedIncludesSource.cpp52
-rw-r--r--lib/Serialization/GeneratePCH.cpp34
-rw-r--r--lib/Serialization/Module.cpp109
-rw-r--r--lib/Serialization/ModuleManager.cpp253
-rw-r--r--lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp7
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp17
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp32
-rw-r--r--lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp17
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp45
-rw-r--r--lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CMakeLists.txt5
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp303
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp52
-rw-r--r--lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp68
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp28
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp103
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp12
-rw-r--r--lib/StaticAnalyzer/Checkers/Checkers.td40
-rw-r--r--lib/StaticAnalyzer/Checkers/ChrootChecker.cpp20
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangCheckers.cpp32
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp289
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.h29
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangSACheckers.h1
-rw-r--r--lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp120
-rw-r--r--lib/StaticAnalyzer/Checkers/DebugCheckers.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp38
-rw-r--r--lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp10
-rw-r--r--lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp21
-rw-r--r--lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp74
-rw-r--r--lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp25
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp632
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/Makefile4
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp140
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp268
-rw-r--r--lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp17
-rw-r--r--lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp30
-rw-r--r--lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp73
-rw-r--r--lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp101
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp17
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp35
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp18
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp185
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp (renamed from lib/StaticAnalyzer/Core/CFRefCount.cpp)2855
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp10
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp6
-rw-r--r--lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp33
-rw-r--r--lib/StaticAnalyzer/Checkers/StreamChecker.cpp58
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp33
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp6
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp13
-rw-r--r--lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp29
-rw-r--r--lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp29
-rw-r--r--lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp20
-rw-r--r--lib/StaticAnalyzer/Core/AggExprVisitor.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/AnalysisManager.cpp52
-rw-r--r--lib/StaticAnalyzer/Core/BasicConstraintManager.cpp179
-rw-r--r--lib/StaticAnalyzer/Core/BasicStore.cpp605
-rw-r--r--lib/StaticAnalyzer/Core/BasicValueFactory.cpp14
-rw-r--r--lib/StaticAnalyzer/Core/BlockCounter.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp580
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp746
-rw-r--r--lib/StaticAnalyzer/Core/CMakeLists.txt16
-rw-r--r--lib/StaticAnalyzer/Core/Checker.cpp22
-rw-r--r--lib/StaticAnalyzer/Core/CheckerContext.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp136
-rw-r--r--lib/StaticAnalyzer/Core/CheckerRegistry.cpp149
-rw-r--r--lib/StaticAnalyzer/Core/CoreEngine.cpp239
-rw-r--r--lib/StaticAnalyzer/Core/Environment.cpp76
-rw-r--r--lib/StaticAnalyzer/Core/ExplodedGraph.cpp31
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp1961
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp752
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (renamed from lib/StaticAnalyzer/Core/CXXExprEngine.cpp)87
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp253
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineObjC.cpp279
-rw-r--r--lib/StaticAnalyzer/Core/FlatStore.cpp217
-rw-r--r--lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp62
-rw-r--r--lib/StaticAnalyzer/Core/MemRegion.cpp77
-rw-r--r--lib/StaticAnalyzer/Core/ObjCMessage.cpp52
-rw-r--r--lib/StaticAnalyzer/Core/PathDiagnostic.cpp225
-rw-r--r--lib/StaticAnalyzer/Core/PlistDiagnostics.cpp79
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp (renamed from lib/StaticAnalyzer/Core/GRState.cpp)297
-rw-r--r--lib/StaticAnalyzer/Core/RangeConstraintManager.cpp73
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp162
-rw-r--r--lib/StaticAnalyzer/Core/SValBuilder.cpp21
-rw-r--r--lib/StaticAnalyzer/Core/SVals.cpp18
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp20
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.h26
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp43
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp28
-rw-r--r--lib/StaticAnalyzer/Core/SymbolManager.cpp153
-rw-r--r--lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp20
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp245
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.h6
-rw-r--r--lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp108
-rw-r--r--lib/StaticAnalyzer/Frontend/FrontendActions.cpp5
-rw-r--r--lib/StaticAnalyzer/README.txt12
-rw-r--r--runtime/CMakeLists.txt1
-rw-r--r--runtime/Makefile2
-rw-r--r--runtime/compiler-rt/Makefile2
-rw-r--r--runtime/libcxx/Makefile35
-rw-r--r--test/ARCMT/Common.h10
-rw-r--r--test/ARCMT/api.m9
-rw-r--r--test/ARCMT/api.m.result9
-rw-r--r--test/ARCMT/assign-prop-no-arc-runtime.m4
-rw-r--r--test/ARCMT/assign-prop-no-arc-runtime.m.result4
-rw-r--r--test/ARCMT/assign-prop-with-arc-runtime.m17
-rw-r--r--test/ARCMT/assign-prop-with-arc-runtime.m.result17
-rw-r--r--test/ARCMT/atautorelease-2.m4
-rw-r--r--test/ARCMT/atautorelease-2.m.result4
-rw-r--r--test/ARCMT/atautorelease-3.m4
-rw-r--r--test/ARCMT/atautorelease-3.m.result4
-rw-r--r--test/ARCMT/atautorelease-check.m2
-rw-r--r--test/ARCMT/atautorelease.m18
-rw-r--r--test/ARCMT/atautorelease.m.result18
-rw-r--r--test/ARCMT/autoreleases.m4
-rw-r--r--test/ARCMT/autoreleases.m.result4
-rw-r--r--test/ARCMT/check-api.m43
-rw-r--r--test/ARCMT/checking.m2
-rw-r--r--test/ARCMT/cxx-checking.mm2
-rw-r--r--test/ARCMT/cxx-rewrite.mm6
-rw-r--r--test/ARCMT/cxx-rewrite.mm.result4
-rw-r--r--test/ARCMT/dealloc.m4
-rw-r--r--test/ARCMT/dealloc.m.result4
-rw-r--r--test/ARCMT/driver-migrate.m9
-rw-r--r--test/ARCMT/init.m4
-rw-r--r--test/ARCMT/init.m.result4
-rw-r--r--test/ARCMT/migrate-emit-errors.m12
-rw-r--r--test/ARCMT/migrate-plist-output.m50
-rw-r--r--test/ARCMT/migrate-space-in-path.m5
-rw-r--r--test/ARCMT/migrate.m5
-rw-r--r--test/ARCMT/nonobjc-to-objc-cast-2.m25
-rw-r--r--test/ARCMT/nonobjc-to-objc-cast.m27
-rw-r--r--test/ARCMT/nonobjc-to-objc-cast.m.result27
-rw-r--r--test/ARCMT/releases-driver.m4
-rw-r--r--test/ARCMT/releases-driver.m.result4
-rw-r--r--test/ARCMT/releases.m16
-rw-r--r--test/ARCMT/releases.m.result15
-rw-r--r--test/ARCMT/remove-dealloc-method.m4
-rw-r--r--test/ARCMT/remove-dealloc-method.m.result4
-rw-r--r--test/ARCMT/remove-dealloc-zerouts.m4
-rw-r--r--test/ARCMT/remove-dealloc-zerouts.m.result4
-rw-r--r--test/ARCMT/remove-statements.m4
-rw-r--r--test/ARCMT/remove-statements.m.result4
-rw-r--r--test/ARCMT/retains.m4
-rw-r--r--test/ARCMT/retains.m.result4
-rw-r--r--test/ARCMT/rewrite-block-var.m4
-rw-r--r--test/ARCMT/rewrite-block-var.m.result4
-rw-r--r--test/ARCMT/safe-arc-assign.m4
-rw-r--r--test/ARCMT/safe-arc-assign.m.result4
-rw-r--r--test/ARCMT/with space/test.h15
-rw-r--r--test/ARCMT/with space/test.h.result13
-rw-r--r--test/ARCMT/with space/test1.m.in6
-rw-r--r--test/ARCMT/with space/test1.m.in.result5
-rw-r--r--test/ARCMT/with space/test2.m.in6
-rw-r--r--test/ARCMT/with space/test2.m.in.result5
-rw-r--r--test/ARCMT/with-arc-mode-check.m2
-rw-r--r--test/ARCMT/with-arc-mode-migrate.m5
-rw-r--r--test/ARCMT/with-arc-mode-migrate.m.result5
-rw-r--r--test/ARCMT/with-arc-mode-modify.m4
-rw-r--r--test/ARCMT/with-arc-mode-modify.m.result4
-rw-r--r--test/ASTMerge/interface.m8
-rw-r--r--test/Analysis/CFDateGC.m7
-rw-r--r--test/Analysis/CFNumber.c6
-rw-r--r--test/Analysis/CFRetainRelease_NSAssertionHandler.m14
-rw-r--r--test/Analysis/CGColorSpace.c6
-rw-r--r--test/Analysis/CheckNSError.m2
-rw-r--r--test/Analysis/MissingDealloc.m2
-rw-r--r--test/Analysis/NSPanel.m6
-rw-r--r--test/Analysis/NSString.m15
-rw-r--r--test/Analysis/NSWindow.m6
-rw-r--r--test/Analysis/NoReturn.m6
-rw-r--r--test/Analysis/ObjCProperties.m6
-rw-r--r--test/Analysis/ObjCRetSigs.m2
-rw-r--r--test/Analysis/PR2599.m5
-rw-r--r--test/Analysis/PR2978.m2
-rw-r--r--test/Analysis/PR3991.m6
-rw-r--r--test/Analysis/PR9741.cpp2
-rw-r--r--test/Analysis/additive-folding-range-constraints.c2
-rw-r--r--test/Analysis/additive-folding.c4
-rw-r--r--test/Analysis/analyzeOneFunction.m56
-rw-r--r--test/Analysis/array-struct-region.c4
-rw-r--r--test/Analysis/array-struct.c6
-rw-r--r--test/Analysis/auto-obj-dtors-cfg-output.cpp1365
-rw-r--r--test/Analysis/bstring.c8
-rw-r--r--test/Analysis/casts.c4
-rw-r--r--test/Analysis/casts.m23
-rw-r--r--test/Analysis/cfref_PR2519.c6
-rw-r--r--test/Analysis/cfref_rdar6080742.c6
-rw-r--r--test/Analysis/chroot.c2
-rw-r--r--test/Analysis/complex.c2
-rw-r--r--test/Analysis/concrete-address.c3
-rw-r--r--test/Analysis/constant-folding.c2
-rw-r--r--test/Analysis/dead-stores.c2
-rw-r--r--test/Analysis/dead-stores.cpp2
-rw-r--r--test/Analysis/dead-stores.m2
-rw-r--r--test/Analysis/default-diagnostic-visitors.c13
-rw-r--r--test/Analysis/delegates.m3
-rw-r--r--test/Analysis/div-zero.cpp13
-rw-r--r--test/Analysis/elementtype.c2
-rw-r--r--test/Analysis/exercise-ps.c3
-rw-r--r--test/Analysis/fields.c3
-rw-r--r--test/Analysis/flat-store.c11
-rw-r--r--test/Analysis/free.c2
-rw-r--r--test/Analysis/func.c3
-rw-r--r--test/Analysis/idempotent-operations.m2
-rw-r--r--test/Analysis/initializers-cfg-output.cpp105
-rw-r--r--test/Analysis/iterators.cpp2
-rw-r--r--test/Analysis/keychainAPI-diagnostic-visitor.m35
-rw-r--r--test/Analysis/keychainAPI.m323
-rw-r--r--test/Analysis/malloc-overflow.c113
-rw-r--r--test/Analysis/malloc-overflow.cpp11
-rw-r--r--test/Analysis/malloc.c4
-rw-r--r--test/Analysis/misc-ps-64.m6
-rw-r--r--test/Analysis/misc-ps-basic-store.m35
-rw-r--r--test/Analysis/misc-ps-cxx0x.cpp61
-rw-r--r--test/Analysis/misc-ps-eager-assume.m2
-rw-r--r--test/Analysis/misc-ps-flat-store.c10
-rw-r--r--test/Analysis/misc-ps-ranges.m3
-rw-r--r--test/Analysis/misc-ps-region-store-i386.m2
-rw-r--r--test/Analysis/misc-ps-region-store-x86_64.m2
-rw-r--r--test/Analysis/misc-ps-region-store.cpp57
-rw-r--r--test/Analysis/misc-ps-region-store.m4
-rw-r--r--test/Analysis/misc-ps-region-store.mm4
-rw-r--r--test/Analysis/misc-ps.m13
-rw-r--r--test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m2
-rw-r--r--test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m9
-rw-r--r--test/Analysis/no-exit-cfg.c3
-rw-r--r--test/Analysis/no-outofbounds.c3
-rw-r--r--test/Analysis/null-deref-ps-region.c2
-rw-r--r--test/Analysis/null-deref-ps.c6
-rw-r--r--test/Analysis/nullptr.cpp2
-rw-r--r--test/Analysis/objc-arc.m8
-rw-r--r--test/Analysis/operator-calls.cpp2
-rw-r--r--test/Analysis/out-of-bounds.c5
-rw-r--r--test/Analysis/outofbound-notwork.c32
-rw-r--r--test/Analysis/outofbound.c11
-rw-r--r--test/Analysis/override-werror.c3
-rw-r--r--test/Analysis/plist-output-alternate.m316
-rw-r--r--test/Analysis/plist-output.m2
-rw-r--r--test/Analysis/pr4209.m3
-rw-r--r--test/Analysis/pr_2542_rdar_6793404.m3
-rw-r--r--test/Analysis/pr_4164.c3
-rw-r--r--test/Analysis/properties.m2
-rw-r--r--test/Analysis/pthreadlock.c137
-rw-r--r--test/Analysis/ptr-arith.c4
-rw-r--r--test/Analysis/rdar-6442306-1.m3
-rw-r--r--test/Analysis/rdar-6540084.m2
-rw-r--r--test/Analysis/rdar-6541136-region.c2
-rw-r--r--test/Analysis/rdar-6541136.c20
-rw-r--r--test/Analysis/rdar-6562655.m3
-rw-r--r--test/Analysis/rdar-6582778-basic-store.c22
-rw-r--r--test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m3
-rw-r--r--test/Analysis/rdar-7168531.m3
-rw-r--r--test/Analysis/refcnt_naming.m3
-rw-r--r--test/Analysis/reference.cpp3
-rw-r--r--test/Analysis/region-1.m3
-rw-r--r--test/Analysis/retain-release-basic-store.m104
-rw-r--r--test/Analysis/retain-release-gc-only.m5
-rw-r--r--test/Analysis/retain-release-path-notes-gc.m3
-rw-r--r--test/Analysis/retain-release-path-notes.m3
-rw-r--r--test/Analysis/retain-release-region-store.m2
-rw-r--r--test/Analysis/retain-release.m76
-rw-r--r--test/Analysis/retain-release.mm12
-rw-r--r--test/Analysis/security-syntax-checks-no-emit.c2
-rw-r--r--test/Analysis/security-syntax-checks.m19
-rw-r--r--test/Analysis/self-init.m2
-rw-r--r--test/Analysis/sizeofpointer.c2
-rw-r--r--test/Analysis/stack-addr-ps.c3
-rw-r--r--test/Analysis/stack-addr-ps.cpp30
-rw-r--r--test/Analysis/stack-block-returned.cpp9
-rw-r--r--test/Analysis/stream.c2
-rw-r--r--test/Analysis/string-fail.c4
-rw-r--r--test/Analysis/string.c8
-rw-r--r--test/Analysis/temp-obj-dtors-cfg-output.cpp1141
-rw-r--r--test/Analysis/undef-buffers.c13
-rw-r--r--test/Analysis/uninit-msg-expr.m1
-rw-r--r--test/Analysis/uninit-ps-rdar6145427.m1
-rw-r--r--test/Analysis/uninit-vals-ps.c1
-rw-r--r--test/Analysis/uninit-vals.m1
-rw-r--r--test/Analysis/unix-fns.c1
-rw-r--r--test/Analysis/unreachable-code-path.c2
-rw-r--r--test/Analysis/unused-ivars.m4
-rw-r--r--test/Analysis/variadic-method-types.m1
-rw-r--r--test/CMakeLists.txt14
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp18
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.classref/p3.cpp2
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.qual/p6-0x.cpp2
-rw-r--r--test/CXX/basic/basic.scope/basic.scope.local/p4-0x.cpp2
-rw-r--r--test/CXX/basic/basic.scope/basic.scope.pdecl/p3.cpp2
-rw-r--r--test/CXX/basic/basic.types/p10.cpp127
-rw-r--r--test/CXX/class.access/class.friend/p1.cpp13
-rw-r--r--test/CXX/class.access/class.friend/p2-cxx03.cpp2
-rw-r--r--test/CXX/class.access/class.friend/p3-cxx0x.cpp2
-rw-r--r--test/CXX/class.access/class.friend/p6.cpp20
-rw-r--r--test/CXX/class.access/class.protected/p1.cpp2
-rw-r--r--test/CXX/class.access/p6.cpp22
-rw-r--r--test/CXX/class.derived/class.virtual/p3-0x.cpp2
-rw-r--r--test/CXX/class/class.bit/p2.cpp22
-rw-r--r--test/CXX/class/class.friend/p2.cpp2
-rw-r--r--test/CXX/class/class.friend/p6.cpp2
-rw-r--r--test/CXX/class/class.mem/p5-0x.cpp2
-rw-r--r--test/CXX/class/class.mem/p8-0x.cpp2
-rw-r--r--test/CXX/class/class.nest/p1-cxx0x.cpp2
-rw-r--r--test/CXX/class/class.static/class.static.data/p3.cpp26
-rw-r--r--test/CXX/class/p1-0x.cpp2
-rw-r--r--test/CXX/class/p2-0x.cpp2
-rw-r--r--test/CXX/class/p6-0x.cpp2
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp2
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp2
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp92
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p2.cpp26
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp125
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp226
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp74
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp28
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp37
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp4
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp17
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp3
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp20
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp15
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p4-cxx0x.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp10
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp9
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p4.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x-fixits.cpp33
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp175
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp40
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx0x-no-extra-copy.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp7
-rw-r--r--test/CXX/dcl.decl/dcl.init/p14-0x.cpp4
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.array/p1-cxx0x.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp62
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/p2-cxx0x.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/p8-0x.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.ref/p6-0x.cpp2
-rw-r--r--test/CXX/dcl.decl/p4-0x.cpp2
-rw-r--r--test/CXX/except/except.spec/canonical.cpp2
-rw-r--r--test/CXX/except/except.spec/p1.cpp14
-rw-r--r--test/CXX/except/except.spec/p11.cpp2
-rw-r--r--test/CXX/except/except.spec/p14.cpp2
-rw-r--r--test/CXX/except/except.spec/p15.cpp2
-rw-r--r--test/CXX/except/except.spec/p2-places.cpp2
-rw-r--r--test/CXX/except/except.spec/p3.cpp2
-rw-r--r--test/CXX/except/except.spec/p5-pointers.cpp2
-rw-r--r--test/CXX/except/except.spec/p5-virtual.cpp2
-rw-r--r--test/CXX/except/except.spec/p9-dynamic.cpp5
-rw-r--r--test/CXX/except/except.spec/p9-noexcept.cpp5
-rw-r--r--test/CXX/except/except.spec/template.cpp2
-rw-r--r--test/CXX/expr/expr.cast/p4-0x.cpp2
-rw-r--r--test/CXX/expr/expr.const/p2-0x.cpp2
-rw-r--r--test/CXX/expr/expr.mptr.oper/p6-0x.cpp2
-rw-r--r--test/CXX/expr/expr.post/expr.call/p7-0x.cpp15
-rw-r--r--test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp2
-rw-r--r--test/CXX/expr/expr.post/expr.dynamic.cast/p3-0x.cpp2
-rw-r--r--test/CXX/expr/expr.post/expr.reinterpret.cast/p1-0x.cpp2
-rw-r--r--test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp2
-rw-r--r--test/CXX/expr/expr.post/expr.static.cast/p9-0x.cpp2
-rw-r--r--test/CXX/expr/expr.prim/p12-0x.cpp2
-rw-r--r--test/CXX/expr/expr.prim/p4-0x.cpp2
-rw-r--r--test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp2
-rw-r--r--test/CXX/expr/expr.unary/expr.new/p20-0x.cpp2
-rw-r--r--test/CXX/expr/expr.unary/expr.sizeof/p5-0x.cpp2
-rw-r--r--test/CXX/expr/expr.unary/expr.unary.noexcept/cg.cpp6
-rw-r--r--test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp2
-rw-r--r--test/CXX/expr/expr.unary/expr.unary.op/p6.cpp7
-rw-r--r--test/CXX/lex/lex.literal/lex.ccon/p1.cpp7
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p1.cpp7
-rw-r--r--test/CXX/lex/lex.pptoken/p3-0x.cpp2
-rw-r--r--test/CXX/over/over.built/p23.cpp25
-rw-r--r--test/CXX/over/over.built/p25.cpp2
-rw-r--r--test/CXX/over/over.load/p2-0x.cpp2
-rw-r--r--test/CXX/over/over.match/over.match.best/over.best.ics/over.ics.user/p3-0x.cpp2
-rw-r--r--test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp2
-rw-r--r--test/CXX/over/over.match/over.match.funcs/p4-0x.cpp2
-rw-r--r--test/CXX/over/over.over/p2-resolve-single-template-id.cpp30
-rw-r--r--test/CXX/special/class.copy/implicit-move-def.cpp116
-rw-r--r--test/CXX/special/class.copy/implicit-move.cpp164
-rw-r--r--test/CXX/special/class.copy/p11.0x.copy.cpp90
-rw-r--r--test/CXX/special/class.copy/p11.0x.move.cpp85
-rw-r--r--test/CXX/special/class.copy/p15-0x.cpp18
-rw-r--r--test/CXX/special/class.copy/p33-0x.cpp2
-rw-r--r--test/CXX/special/class.ctor/p4-0x.cpp2
-rw-r--r--test/CXX/special/class.ctor/p5-0x.cpp6
-rw-r--r--test/CXX/special/class.dtor/p2-0x.cpp2
-rw-r--r--test/CXX/special/class.dtor/p3-0x.cpp2
-rw-r--r--test/CXX/special/class.inhctor/elsewhere.cpp2
-rw-r--r--test/CXX/special/class.inhctor/p3.cpp6
-rw-r--r--test/CXX/special/class.inhctor/p7.cpp2
-rw-r--r--test/CXX/special/class.init/class.base.init/p8-0x.cpp40
-rw-r--r--test/CXX/special/class.init/class.base.init/p9-0x.cpp2
-rw-r--r--test/CXX/special/class.temporary/p1.cpp58
-rw-r--r--test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp2
-rw-r--r--test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp7
-rw-r--r--test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp2
-rw-r--r--test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp2
-rw-r--r--test/CXX/temp/temp.decls/p3.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.alias/p1.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.alias/p2.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.alias/p3.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.class.spec/p9-0x.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3-0x.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p1.cpp24
-rw-r--r--test/CXX/temp/temp.decls/temp.mem/p5.cpp5
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/deduction.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/example-bind.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/example-function.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/example-tuple.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/ext-blocks.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/injected-class-name.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp17
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/p1.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/p2.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/p4.cpp3
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/p5.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/parameter-matching.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/partial-ordering.cpp2
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-0x.cpp2
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp6
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp2
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/cwg1170.cpp2
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp2
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp2
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp12
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p12.cpp2
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p9-0x.cpp2
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p10-0x.cpp2
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp2
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p21.cpp2
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p22.cpp2
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p5-0x.cpp2
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp2
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp2
-rw-r--r--test/CXX/temp/temp.param/p10-0x.cpp2
-rw-r--r--test/CXX/temp/temp.param/p11-0x.cpp2
-rw-r--r--test/CXX/temp/temp.param/p15-cxx0x.cpp2
-rw-r--r--test/CXX/temp/temp.param/p15.cpp2
-rw-r--r--test/CXX/temp/temp.param/p9-0x.cpp2
-rw-r--r--test/CXX/temp/temp.param/p9.cpp4
-rw-r--r--test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp2
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp2
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp11
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp2
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p9-linkage.cpp2
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p9.cpp2
-rw-r--r--test/CXX/temp/temp.type/p1-0x.cpp2
-rw-r--r--test/CodeCompletion/truncation.c11
-rw-r--r--test/CodeGen/2002-01-23-LoadQISIReloadFailure.c11
-rw-r--r--test/CodeGen/2002-01-24-ComplexSpaceInType.c11
-rw-r--r--test/CodeGen/2002-01-24-HandleCallInsnSEGV.c9
-rw-r--r--test/CodeGen/2002-02-13-ConditionalInCall.c11
-rw-r--r--test/CodeGen/2002-02-13-ReloadProblem.c18
-rw-r--r--test/CodeGen/2002-02-13-TypeVarNameCollision.c16
-rw-r--r--test/CodeGen/2002-02-13-UnnamedLocal.c21
-rw-r--r--test/CodeGen/2002-02-14-EntryNodePreds.c37
-rw-r--r--test/CodeGen/2002-02-16-RenamingTest.c18
-rw-r--r--test/CodeGen/2002-02-17-ArgumentAddress.c39
-rw-r--r--test/CodeGen/2002-02-18-64bitConstant.c10
-rw-r--r--test/CodeGen/2002-02-18-StaticData.c13
-rw-r--r--test/CodeGen/2002-03-11-LargeCharInString.c10
-rw-r--r--test/CodeGen/2002-03-12-ArrayInitialization.c19
-rw-r--r--test/CodeGen/2002-03-12-StructInitialize.c14
-rw-r--r--test/CodeGen/2002-03-12-StructInitializer.c18
-rw-r--r--test/CodeGen/2002-03-14-BrokenPHINode.c19
-rw-r--r--test/CodeGen/2002-03-14-BrokenSSA.c17
-rw-r--r--test/CodeGen/2002-03-14-QuotesInStrConst.c10
-rw-r--r--test/CodeGen/2002-04-07-SwitchStmt.c22
-rw-r--r--test/CodeGen/2002-04-08-LocalArray.c14
-rw-r--r--test/CodeGen/2002-04-09-StructRetVal.c12
-rw-r--r--test/CodeGen/2002-04-10-StructParameters.c25
-rw-r--r--test/CodeGen/2002-05-23-StaticValues.c15
-rw-r--r--test/CodeGen/2002-05-23-TypeNameCollision.c19
-rw-r--r--test/CodeGen/2002-05-24-Alloca.c11
-rw-r--r--test/CodeGen/2002-06-25-FWriteInterfaceFailure.c9
-rw-r--r--test/CodeGen/2002-07-14-MiscListTests.c71
-rw-r--r--test/CodeGen/2002-07-14-MiscTests.c57
-rw-r--r--test/CodeGen/2002-07-14-MiscTests2.c13
-rw-r--r--test/CodeGen/2002-07-14-MiscTests3.c182
-rw-r--r--test/CodeGen/2002-07-16-HardStringInit.c8
-rw-r--r--test/CodeGen/2002-07-17-StringConstant.c4
-rw-r--r--test/CodeGen/2002-07-30-SubregSetAssertion.c12
-rw-r--r--test/CodeGen/2002-07-30-UnionTest.c22
-rw-r--r--test/CodeGen/2002-07-30-VarArgsCallFailure.c8
-rw-r--r--test/CodeGen/2002-07-31-BadAssert.c16
-rw-r--r--test/CodeGen/2002-07-31-SubregFailure.c14
-rw-r--r--test/CodeGen/2002-08-02-UnionTest.c19
-rw-r--r--test/CodeGen/2002-08-19-RecursiveLocals.c18
-rw-r--r--test/CodeGen/2002-09-08-PointerShifts.c6
-rw-r--r--test/CodeGen/2002-09-18-UnionProblem.c26
-rw-r--r--test/CodeGen/2002-09-19-StarInLabel.c9
-rw-r--r--test/CodeGen/2002-10-12-TooManyArguments.c8
-rw-r--r--test/CodeGen/2002-12-15-GlobalBoolTest.c5
-rw-r--r--test/CodeGen/2002-12-15-GlobalConstantTest.c8
-rw-r--r--test/CodeGen/2002-12-15-GlobalRedefinition.c5
-rw-r--r--test/CodeGen/2002-12-15-StructParameters.c18
-rw-r--r--test/CodeGen/2003-01-30-UnionInit.c8
-rw-r--r--test/CodeGen/2003-03-03-DeferredType.c12
-rw-r--r--test/CodeGen/2003-06-22-UnionCrash.c13
-rw-r--r--test/CodeGen/2003-06-23-GCC-fold-infinite-recursion.c6
-rw-r--r--test/CodeGen/2003-06-26-CFECrash.c19
-rw-r--r--test/CodeGen/2003-06-29-MultipleFunctionDefinition.c8
-rw-r--r--test/CodeGen/2003-07-22-ArrayAccessTypeSafety.c7
-rw-r--r--test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c14
-rw-r--r--test/CodeGen/2003-08-17-DeadCodeShortCircuit.c6
-rw-r--r--test/CodeGen/2003-08-18-SigSetJmp.c10
-rw-r--r--test/CodeGen/2003-08-18-StructAsValue.c11
-rw-r--r--test/CodeGen/2003-08-20-BadBitfieldRef.c8
-rw-r--r--test/CodeGen/2003-08-20-PrototypeMismatch.c15
-rw-r--r--test/CodeGen/2003-08-20-vfork-bug.c6
-rw-r--r--test/CodeGen/2003-08-21-BinOp-Type-Mismatch.c10
-rw-r--r--test/CodeGen/2003-08-21-StmtExpr.c12
-rw-r--r--test/CodeGen/2003-08-21-WideString.c16
-rw-r--r--test/CodeGen/2003-08-23-LocalUnionTest.c11
-rw-r--r--test/CodeGen/2003-08-29-BitFieldStruct.c13
-rw-r--r--test/CodeGen/2003-08-29-HugeCharConst.c5
-rw-r--r--test/CodeGen/2003-08-29-StructLayoutBug.c10
-rw-r--r--test/CodeGen/2003-08-30-AggregateInitializer.c16
-rw-r--r--test/CodeGen/2003-08-30-LargeIntegerBitfieldMember.c9
-rw-r--r--test/CodeGen/2003-09-18-BitfieldTests.c30
-rw-r--r--test/CodeGen/2003-09-30-StructLayout.c18
-rw-r--r--test/CodeGen/2003-10-02-UnionLValueError.c11
-rw-r--r--test/CodeGen/2003-10-06-NegateExprType.c8
-rw-r--r--test/CodeGen/2003-10-09-UnionInitializerBug.c17
-rw-r--r--test/CodeGen/2003-10-28-ident.c4
-rw-r--r--test/CodeGen/2003-10-29-AsmRename.c22
-rw-r--r--test/CodeGen/2003-11-01-C99-CompoundLiteral.c8
-rw-r--r--test/CodeGen/2003-11-01-EmptyStructCrash.c6
-rw-r--r--test/CodeGen/2003-11-01-GlobalUnionInit.c7
-rw-r--r--test/CodeGen/2003-11-03-AddrArrayElement.c11
-rw-r--r--test/CodeGen/2003-11-04-EmptyStruct.c6
-rw-r--r--test/CodeGen/2003-11-04-OutOfMemory.c9
-rw-r--r--test/CodeGen/2003-11-08-PointerSubNotGetelementptr.c10
-rw-r--r--test/CodeGen/2003-11-12-VoidString.c4
-rw-r--r--test/CodeGen/2003-11-13-TypeSafety.c5
-rw-r--r--test/CodeGen/2003-11-16-StaticArrayInit.c8
-rw-r--r--test/CodeGen/2003-11-18-CondExprLValue.c9
-rw-r--r--test/CodeGen/2003-11-19-AddressOfRegister.c11
-rw-r--r--test/CodeGen/2003-11-19-BitFieldArray.c12
-rw-r--r--test/CodeGen/2003-11-20-Bitfields.c12
-rw-r--r--test/CodeGen/2003-11-20-ComplexDivision.c7
-rw-r--r--test/CodeGen/2003-11-20-UnionBitfield.c12
-rw-r--r--test/CodeGen/2003-11-26-PointerShift.c6
-rw-r--r--test/CodeGen/2003-11-27-ConstructorCast.c14
-rw-r--r--test/CodeGen/2003-11-27-UnionCtorInitialization.c16
-rw-r--r--test/CodeGen/2003-12-14-ExternInlineSupport.c3
-rw-r--r--test/CodeGen/2004-01-01-UnknownInitSize.c14
-rw-r--r--test/CodeGen/2004-01-08-ExternInlineRedefine.c14
-rw-r--r--test/CodeGen/2004-02-12-LargeAggregateCopy.c8
-rw-r--r--test/CodeGen/2004-02-13-BuiltinFrameReturnAddress.c10
-rw-r--r--test/CodeGen/2004-02-13-IllegalVararg.c9
-rw-r--r--test/CodeGen/2004-02-13-Memset.c12
-rw-r--r--test/CodeGen/2004-02-14-ZeroInitializer.c4
-rw-r--r--test/CodeGen/2004-02-20-Builtins.c5
-rw-r--r--test/CodeGen/2004-03-07-ComplexDivEquals.c6
-rw-r--r--test/CodeGen/2004-03-07-ExternalConstant.c7
-rw-r--r--test/CodeGen/2004-03-09-LargeArrayInitializers.c32
-rw-r--r--test/CodeGen/2004-03-15-SimpleIndirectGoto.c23
-rw-r--r--test/CodeGen/2004-03-16-AsmRegisterCrash.c12
-rw-r--r--test/CodeGen/2004-05-07-VarArrays.c5
-rw-r--r--test/CodeGen/2004-05-21-IncompleteEnum.c5
-rw-r--r--test/CodeGen/2004-06-08-OpaqueStructArg.c7
-rw-r--r--test/CodeGen/2004-06-17-UnorderedBuiltins.c24
-rw-r--r--test/CodeGen/2004-06-17-UnorderedCompares.c19
-rw-r--r--test/CodeGen/2004-06-18-VariableLengthArrayOfStructures.c10
-rw-r--r--test/CodeGen/2004-07-06-FunctionCast.c10
-rw-r--r--test/CodeGen/2004-08-06-LargeStructTest.c19
-rw-r--r--test/CodeGen/2004-11-25-UnnamedBitfieldPadding.c8
-rw-r--r--test/CodeGen/2004-11-27-InvalidConstantExpr.c10
-rw-r--r--test/CodeGen/2004-11-27-StaticFunctionRedeclare.c15
-rw-r--r--test/CodeGen/2005-01-02-ConstantInits.c24
-rw-r--r--test/CodeGen/2005-01-02-PointerDifference.c4
-rw-r--r--test/CodeGen/2005-01-02-VAArgError-ICE.c9
-rw-r--r--test/CodeGen/2005-02-20-AggregateSAVEEXPR.c5
-rw-r--r--test/CodeGen/2005-02-27-MarkGlobalConstant.c12
-rw-r--r--test/CodeGen/2005-03-05-OffsetOfHack.c12
-rw-r--r--test/CodeGen/2005-03-06-OffsetOfStructCrash.c14
-rw-r--r--test/CodeGen/2005-03-11-Prefetch.c7
-rw-r--r--test/CodeGen/2005-04-09-ComplexOps.c8
-rw-r--r--test/CodeGen/2005-05-06-CountBuiltins.c17
-rw-r--r--test/CodeGen/2005-05-10-GlobalUnionInit.c6
-rw-r--r--test/CodeGen/2005-06-15-ExpandGotoInternalProblem.c14
-rw-r--r--test/CodeGen/2005-07-20-SqrtNoErrno.c10
-rw-r--r--test/CodeGen/2005-07-26-UnionInitCrash.c3
-rw-r--r--test/CodeGen/2005-07-28-IncorrectWeakGlobal.c5
-rw-r--r--test/CodeGen/2005-09-20-ComplexConstants.c4
-rw-r--r--test/CodeGen/2005-09-24-AsmUserPrefix.c8
-rw-r--r--test/CodeGen/2005-09-24-BitFieldCrash.c33
-rw-r--r--test/CodeGen/2005-12-04-AttributeUsed.c7
-rw-r--r--test/CodeGen/2005-12-04-DeclarationLineNumbers.c23
-rw-r--r--test/CodeGen/2006-01-13-Includes.c10
-rw-r--r--test/CodeGen/2006-01-13-StackSave.c11
-rw-r--r--test/CodeGen/2006-01-16-BitCountIntrinsicsUnsigned.c12
-rw-r--r--test/CodeGen/2006-01-23-FileScopeAsm.c12
-rw-r--r--test/CodeGen/2006-03-03-MissingInitializer.c10
-rw-r--r--test/CodeGen/2006-03-16-VectorCtor.c10
-rw-r--r--test/CodeGen/2006-03-17-KnRMismatch.c8
-rw-r--r--test/CodeGen/2006-05-19-SingleEltReturn.c23
-rw-r--r--test/CodeGen/2006-07-31-PR854.c12
-rw-r--r--test/CodeGen/2006-09-11-BitfieldRefCrash.c12
-rw-r--r--test/CodeGen/2006-09-18-fwrite-cast-crash.c12
-rw-r--r--test/CodeGen/2006-09-21-IncompleteElementType.c3
-rw-r--r--test/CodeGen/2006-09-25-DebugFilename.c4
-rw-r--r--test/CodeGen/2006-09-25-DebugFilename.h6
-rw-r--r--test/CodeGen/2006-09-28-SimpleAsm.c12
-rw-r--r--test/CodeGen/2006-10-30-ArrayCrash.c17
-rw-r--r--test/CodeGen/2006-12-14-ordered_expr.c6
-rw-r--r--test/CodeGen/2007-01-06-KNR-Proto.c10
-rw-r--r--test/CodeGen/2007-01-20-VectorICE.c11
-rw-r--r--test/CodeGen/2007-01-24-InlineAsmCModifier.c12
-rw-r--r--test/CodeGen/2007-02-04-AddrLValue-2.c13
-rw-r--r--test/CodeGen/2007-02-04-AddrLValue.c23
-rw-r--r--test/CodeGen/2007-02-04-EmptyStruct.c9
-rw-r--r--test/CodeGen/2007-02-07-AddrLabel.c10
-rw-r--r--test/CodeGen/2007-02-16-VoidPtrDiff.c5
-rw-r--r--test/CodeGen/2007-02-25-C-DotDotDot.c10
-rw-r--r--test/CodeGen/2007-03-01-VarSizeArrayIdx.c7
-rw-r--r--test/CodeGen/2007-03-05-DataLayout.c55
-rw-r--r--test/CodeGen/2007-03-26-BitfieldAfterZeroWidth.c6
-rw-r--r--test/CodeGen/2007-03-26-ZeroWidthBitfield.c2
-rw-r--r--test/CodeGen/2007-03-27-VarLengthArray.c9
-rw-r--r--test/CodeGen/2007-04-05-PackedBitFields-2.c16
-rw-r--r--test/CodeGen/2007-04-05-PackedBitFields.c16
-rw-r--r--test/CodeGen/2007-04-05-PackedStruct.c18
-rw-r--r--test/CodeGen/2007-04-05-PadBeforeZeroLengthField.c9
-rw-r--r--test/CodeGen/2007-04-05-UnPackedStruct.c16
-rw-r--r--test/CodeGen/2007-04-11-InlineAsmStruct.c8
-rw-r--r--test/CodeGen/2007-04-11-InlineAsmUnion.c7
-rw-r--r--test/CodeGen/2007-04-11-PR1321.c12
-rw-r--r--test/CodeGen/2007-04-13-InlineAsmStruct2.c9
-rw-r--r--test/CodeGen/2007-04-13-InlineAsmUnion2.c8
-rw-r--r--test/CodeGen/2007-04-14-FNoBuiltin.c7
-rw-r--r--test/CodeGen/2007-04-17-ZeroSizeBitFields.c4
-rw-r--r--test/CodeGen/2007-04-24-VolatileStructCopy.c11
-rw-r--r--test/CodeGen/2007-04-24-bit-not-expr.c7
-rw-r--r--test/CodeGen/2007-04-24-str-const.c17
-rw-r--r--test/CodeGen/2007-05-07-PaddingElements.c12
-rw-r--r--test/CodeGen/2007-05-08-PCH.c7
-rw-r--r--test/CodeGen/2007-05-11-str-const.c5
-rw-r--r--test/CodeGen/2007-05-15-PaddingElement.c23
-rw-r--r--test/CodeGen/2007-05-16-EmptyStruct.c5
-rw-r--r--test/CodeGen/2007-05-29-UnionCopy.c18
-rw-r--r--test/CodeGen/2007-06-05-NoInlineAttribute.c13
-rw-r--r--test/CodeGen/2007-06-15-AnnotateAttribute.c21
-rw-r--r--test/CodeGen/2007-06-18-SextAttrAggregate.c12
-rw-r--r--test/CodeGen/2007-07-29-RestrictPtrArg.c6
-rw-r--r--test/CodeGen/2007-08-01-LoadStoreAlign.c18
-rw-r--r--test/CodeGen/2007-08-21-ComplexCst.c3
-rw-r--r--test/CodeGen/2007-08-22-CTTZ.c8
-rw-r--r--test/CodeGen/2007-09-05-ConstCtor.c14
-rw-r--r--test/CodeGen/2007-09-12-PragmaPack.c32
-rw-r--r--test/CodeGen/2007-09-14-NegatePointer.c7
-rw-r--r--test/CodeGen/2007-09-17-WeakRef.c10
-rw-r--r--test/CodeGen/2007-09-26-Alignment.c8
-rw-r--r--test/CodeGen/2007-09-27-ComplexIntCompare.c15
-rw-r--r--test/CodeGen/2007-09-28-PackedUnionMember.c38
-rw-r--r--test/CodeGen/2007-10-02-VolatileArray.c7
-rw-r--r--test/CodeGen/2007-10-15-VoidPtr.c4
-rw-r--r--test/CodeGen/2007-10-30-Volatile.c6
-rw-r--r--test/CodeGen/2007-11-07-AlignedMemcpy.c4
-rw-r--r--test/CodeGen/2007-11-07-CopyAggregateAlign.c7
-rw-r--r--test/CodeGen/2007-11-07-ZeroAggregateAlign.c5
-rw-r--r--test/CodeGen/2007-11-28-GlobalInitializer.c8
-rw-r--r--test/CodeGen/2007-12-16-AsmNoUnwind.c3
-rw-r--r--test/CodeGen/2008-01-04-WideBitfield.c12
-rw-r--r--test/CodeGen/2008-01-07-UnusualIntSize.c15
-rw-r--r--test/CodeGen/2008-01-11-ChainConsistency.c3
-rw-r--r--test/CodeGen/2008-01-21-PackedBitFields.c7
-rw-r--r--test/CodeGen/2008-01-21-PackedStructField.c18
-rw-r--r--test/CodeGen/2008-01-24-StructAlignAndBitFields.c4
-rw-r--r--test/CodeGen/2008-01-25-ByValReadNone.c16
-rw-r--r--test/CodeGen/2008-01-25-ZeroSizedAggregate.c39
-rw-r--r--test/CodeGen/2008-01-28-PragmaMark.c6
-rw-r--r--test/CodeGen/2008-01-28-UnionSize.c24
-rw-r--r--test/CodeGen/2008-03-03-CtorAttrType.c6
-rw-r--r--test/CodeGen/2008-03-05-syncPtr.c40
-rw-r--r--test/CodeGen/2008-03-24-BitField-And-Alloca.c89
-rw-r--r--test/CodeGen/2008-03-26-PackedBitFields.c7
-rw-r--r--test/CodeGen/2008-04-08-NoExceptions.c10
-rw-r--r--test/CodeGen/2008-05-06-CFECrash.c4
-rw-r--r--test/CodeGen/2008-05-12-TempUsedBeforeDef.c10
-rw-r--r--test/CodeGen/2008-05-19-AlwaysInline.c12
-rw-r--r--test/CodeGen/2008-08-07-AlignPadding1.c32
-rw-r--r--test/CodeGen/2008-08-07-AlignPadding2.c18
-rw-r--r--test/CodeGen/2008-08-07-GEPIntToPtr.c15
-rw-r--r--test/CodeGen/2008-09-03-WeakAlias.c9
-rw-r--r--test/CodeGen/2008-10-13-FrontendCrash.c9
-rw-r--r--test/CodeGen/2008-10-30-ZeroPlacement.c9
-rw-r--r--test/CodeGen/2008-11-02-WeakAlias.c6
-rw-r--r--test/CodeGen/2008-11-08-InstCombineSelect.c17
-rw-r--r--test/CodeGen/2008-12-23-AsmIntPointerTie.c8
-rw-r--r--test/CodeGen/2009-01-05-BlockInlining.c29
-rw-r--r--test/CodeGen/2009-01-21-InvalidIterator.c74
-rw-r--r--test/CodeGen/2009-02-13-zerosize-union-field-ppc.c14
-rw-r--r--test/CodeGen/2009-02-13-zerosize-union-field.c16
-rw-r--r--test/CodeGen/2009-03-01-MallocNoAlias.c3
-rw-r--r--test/CodeGen/2009-03-08-ZeroEltStructCrash.c14
-rw-r--r--test/CodeGen/2009-03-13-dbg.c2
-rw-r--r--test/CodeGen/2009-04-28-UnionArrayCrash.c11
-rw-r--r--test/CodeGen/2009-05-04-EnumInreg.c17
-rw-r--r--test/CodeGen/2009-06-14-HighlyAligned.c8
-rw-r--r--test/CodeGen/2009-06-18-StaticInitTailPadPack.c26
-rw-r--r--test/CodeGen/2009-07-14-VoidPtr.c6
-rw-r--r--test/CodeGen/2009-07-15-pad-wchar_t-array.c17
-rw-r--r--test/CodeGen/2009-07-22-StructLayout.c34
-rw-r--r--test/CodeGen/2009-09-24-SqrtErrno.c12
-rw-r--r--test/CodeGen/2009-12-07-BitFieldAlignment.c15
-rw-r--r--test/CodeGen/2010-01-13-MemBarrier.c11
-rw-r--r--test/CodeGen/2010-01-14-FnType-DebugInfo.c4
-rw-r--r--test/CodeGen/2010-01-18-Inlined-Debug.c12
-rw-r--r--test/CodeGen/2010-02-10-PointerName.c7
-rw-r--r--test/CodeGen/2010-02-15-DbgStaticVar.c13
-rw-r--r--test/CodeGen/2010-03-5-LexicalScope.c10
-rw-r--r--test/CodeGen/2010-05-26-AsmSideEffect.c9
-rw-r--r--test/CodeGen/2010-06-11-SaveExpr.c8
-rw-r--r--test/CodeGen/2010-06-17-asmcrash.c16
-rw-r--r--test/CodeGen/2010-07-08-DeclDebugLineNo.c10
-rw-r--r--test/CodeGen/2010-07-14-overconservative-align.c14
-rw-r--r--test/CodeGen/2010-07-14-ref-off-end.c24
-rw-r--r--test/CodeGen/2010-08-12-asm-aggr-arg.c16
-rw-r--r--test/CodeGen/2010-12-01-CommonGlobal.c7
-rw-r--r--test/CodeGen/2011-02-21-DATA-common.c5
-rw-r--r--test/CodeGen/2011-03-02-UnionInitializer.c2
-rw-r--r--test/CodeGen/2011-03-08-ZeroFieldUnionInitializer.c7
-rw-r--r--test/CodeGen/2011-03-31-ArrayRefFolding.c15
-rw-r--r--test/CodeGen/Atomics.c203
-rw-r--r--test/CodeGen/BasicInstrs.c25
-rw-r--r--test/CodeGen/always-inline.c12
-rw-r--r--test/CodeGen/annotate.c10
-rw-r--r--test/CodeGen/annotations-builtin.c52
-rw-r--r--test/CodeGen/annotations-field.c27
-rw-r--r--test/CodeGen/annotations-global.c41
-rw-r--r--test/CodeGen/annotations-loc.c10
-rw-r--r--test/CodeGen/annotations-var.c48
-rw-r--r--test/CodeGen/arm-aapcs-vfp.c82
-rw-r--r--test/CodeGen/arm-apcs-zerolength-bitfield.c240
-rw-r--r--test/CodeGen/arm-arguments.c28
-rw-r--r--test/CodeGen/arm-inline-asm.c6
-rw-r--r--test/CodeGen/arm-vaarg-align.c33
-rw-r--r--test/CodeGen/arm-vector-arguments.c6
-rw-r--r--test/CodeGen/arrayderef.c16
-rw-r--r--test/CodeGen/asm-reg-var-local.c24
-rw-r--r--test/CodeGen/asm.c18
-rw-r--r--test/CodeGen/assign.c6
-rw-r--r--test/CodeGen/atomic-ops.c77
-rw-r--r--test/CodeGen/atomic.c111
-rw-r--r--test/CodeGen/attr-naked.c11
-rw-r--r--test/CodeGen/attribute_constructor.c6
-rw-r--r--test/CodeGen/avx-shuffle-builtins.c16
-rw-r--r--test/CodeGen/block-3.c8
-rw-r--r--test/CodeGen/block-copy.c20
-rw-r--r--test/CodeGen/block-decl-merging.c20
-rw-r--r--test/CodeGen/blocks.c4
-rw-r--r--test/CodeGen/builtin-attributes.c41
-rw-r--r--test/CodeGen/capture-complex-expr-in-block.c20
-rw-r--r--test/CodeGen/char-literal.c78
-rw-r--r--test/CodeGen/complex-init-list.c12
-rw-r--r--test/CodeGen/debug-dead-local-var.c14
-rw-r--r--test/CodeGen/debug-info-iv.c10
-rw-r--r--test/CodeGen/debug-info-line.c14
-rw-r--r--test/CodeGen/debug-info-line3.c16
-rw-r--r--test/CodeGen/debug-info-member.c2
-rw-r--r--test/CodeGen/decl.c8
-rw-r--r--test/CodeGen/exact-div-expr.c6
-rw-r--r--test/CodeGen/exceptions.c6
-rw-r--r--test/CodeGen/extern-weak.c12
-rw-r--r--test/CodeGen/fp16-ops.c283
-rw-r--r--test/CodeGen/func-aligned.c7
-rw-r--r--test/CodeGen/funccall.c17
-rw-r--r--test/CodeGen/function-attributes.c22
-rw-r--r--test/CodeGen/functions.c4
-rw-r--r--test/CodeGen/hidden-visibility.c4
-rw-r--r--test/CodeGen/implicit-arg.c10
-rw-r--r--test/CodeGen/inline-asm-mrv.c12
-rw-r--r--test/CodeGen/inline.c20
-rw-r--r--test/CodeGen/kr-call.c12
-rw-r--r--test/CodeGen/libcalls-d.c16
-rw-r--r--test/CodeGen/libcalls-ld.c19
-rw-r--r--test/CodeGen/libcalls.c6
-rw-r--r--test/CodeGen/microsoft-call-conv.c2
-rw-r--r--test/CodeGen/misaligned-param.c13
-rw-r--r--test/CodeGen/mrtd.c2
-rw-r--r--test/CodeGen/ms_struct-bitfield-1.c62
-rw-r--r--test/CodeGen/pascal-wchar-string.c2
-rw-r--r--test/CodeGen/pr2394.c7
-rw-r--r--test/CodeGen/pr3518.c29
-rw-r--r--test/CodeGen/pr4349.c38
-rw-r--r--test/CodeGen/pr5406.c17
-rw-r--r--test/CodeGen/pragma-weak.c15
-rw-r--r--test/CodeGen/redef-ext-inline.c6
-rw-r--r--test/CodeGen/sret.c15
-rw-r--r--test/CodeGen/sret2.c9
-rw-r--r--test/CodeGen/sse-builtins.c104
-rw-r--r--test/CodeGen/stdcall-fastcall.c2
-rw-r--r--test/CodeGen/string-literal-short-wstring.c2
-rw-r--r--test/CodeGen/string-literal.c78
-rw-r--r--test/CodeGen/struct-init.c10
-rw-r--r--test/CodeGen/struct-matching-constraint.c13
-rw-r--r--test/CodeGen/struct-passing.c4
-rw-r--r--test/CodeGen/target-data.c6
-rw-r--r--test/CodeGen/unaligned-memcpy.c5
-rw-r--r--test/CodeGen/union-align.c17
-rw-r--r--test/CodeGen/vla-2.c10
-rw-r--r--test/CodeGen/vla-3.c11
-rw-r--r--test/CodeGen/volatile-1.c254
-rw-r--r--test/CodeGen/volatile-2.c12
-rw-r--r--test/CodeGen/wchar-const.c24
-rw-r--r--test/CodeGen/weak_constant.c13
-rw-r--r--test/CodeGen/x86_32-arguments-darwin.c18
-rw-r--r--test/CodeGen/x86_64-arguments.c6
-rw-r--r--test/CodeGenCUDA/device-stub.cu13
-rw-r--r--test/CodeGenCUDA/filter-decl.cu40
-rw-r--r--test/CodeGenCUDA/kernel-call.cu13
-rw-r--r--test/CodeGenCUDA/ptx-kernels.cu12
-rw-r--r--test/CodeGenCXX/2003-11-02-WeakLinkage.cpp13
-rw-r--r--test/CodeGenCXX/2003-11-18-PtrMemConstantInitializer.cpp13
-rw-r--r--test/CodeGenCXX/2003-11-27-MultipleInheritanceThunk.cpp28
-rw-r--r--test/CodeGenCXX/2003-11-29-DuplicatedCleanupTest.cpp41
-rw-r--r--test/CodeGenCXX/2003-12-08-ArrayOfPtrToMemberFunc.cpp12
-rw-r--r--test/CodeGenCXX/2004-01-11-DynamicInitializedConstant.cpp6
-rw-r--r--test/CodeGenCXX/2004-03-08-ReinterpretCastCopy.cpp21
-rw-r--r--test/CodeGenCXX/2004-03-09-UnmangledBuiltinMethods.cpp8
-rw-r--r--test/CodeGenCXX/2004-03-15-CleanupsAndGotos.cpp14
-rw-r--r--test/CodeGenCXX/2004-06-08-LateTemplateInstantiation.cpp18
-rw-r--r--test/CodeGenCXX/2004-09-27-DidntEmitTemplate.cpp22
-rw-r--r--test/CodeGenCXX/2004-11-27-ExceptionCleanupAssertion.cpp14
-rw-r--r--test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp9
-rw-r--r--test/CodeGenCXX/2005-01-03-StaticInitializers.cpp8
-rw-r--r--test/CodeGenCXX/2005-02-11-AnonymousUnion.cpp32
-rw-r--r--test/CodeGenCXX/2005-02-13-BadDynamicInit.cpp9
-rw-r--r--test/CodeGenCXX/2005-02-14-BitFieldOffset.cpp12
-rw-r--r--test/CodeGenCXX/2005-02-19-BitfieldStructCrash.cpp14
-rw-r--r--test/CodeGenCXX/2005-02-19-UnnamedVirtualThunkArgument.cpp22
-rw-r--r--test/CodeGenCXX/2005-02-20-BrokenReferenceTest.cpp10
-rw-r--r--test/CodeGenCXX/2006-03-01-GimplifyCrash.cpp14
-rw-r--r--test/CodeGenCXX/2006-03-06-C++RecurseCrash.cpp23
-rw-r--r--test/CodeGenCXX/2006-09-12-OpaqueStructCrash.cpp27
-rw-r--r--test/CodeGenCXX/2006-10-30-ClassBitfield.cpp16
-rw-r--r--test/CodeGenCXX/2006-11-20-GlobalSymbols.cpp11
-rw-r--r--test/CodeGenCXX/2006-11-30-ConstantExprCrash.cpp21
-rw-r--r--test/CodeGenCXX/2007-01-02-UnboundedArray.cpp14
-rw-r--r--test/CodeGenCXX/2007-01-06-PtrMethodInit.cpp75
-rw-r--r--test/CodeGenCXX/2007-04-05-PackedBitFields-1.cpp22
-rw-r--r--test/CodeGenCXX/2007-04-05-PackedBitFieldsOverlap-2.cpp23
-rw-r--r--test/CodeGenCXX/2007-04-05-PackedBitFieldsOverlap.cpp23
-rw-r--r--test/CodeGenCXX/2007-04-05-PackedBitFieldsSmall.cpp27
-rw-r--r--test/CodeGenCXX/2007-04-05-StructPackedFieldUnpacked.cpp24
-rw-r--r--test/CodeGenCXX/2007-04-10-PackedUnion.cpp41
-rw-r--r--test/CodeGenCXX/2007-04-14-FNoBuiltin.cpp8
-rw-r--r--test/CodeGenCXX/2007-05-03-VectorInit.cpp17
-rw-r--r--test/CodeGenCXX/2007-07-29-RestrictPtrArg.cpp7
-rw-r--r--test/CodeGenCXX/2007-07-29-RestrictRefArg.cpp7
-rw-r--r--test/CodeGenCXX/2007-09-10-RecursiveTypeResolution.cpp87
-rw-r--r--test/CodeGenCXX/2007-10-01-StructResize.cpp13
-rw-r--r--test/CodeGenCXX/2008-01-12-VecInit.cpp5
-rw-r--r--test/CodeGenCXX/2008-05-07-CrazyOffsetOf.cpp8
-rw-r--r--test/CodeGenCXX/2009-03-17-dbg.cpp15
-rw-r--r--test/CodeGenCXX/2009-04-23-bool2.cpp15
-rw-r--r--test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp15
-rw-r--r--test/CodeGenCXX/2009-06-16-DebugInfoCrash.cpp10
-rw-r--r--test/CodeGenCXX/2009-07-16-Using.cpp8
-rw-r--r--test/CodeGenCXX/2009-08-05-ZeroInitWidth.cpp11
-rw-r--r--test/CodeGenCXX/2009-08-11-VectorRetTy.cpp13
-rw-r--r--test/CodeGenCXX/2009-09-09-packed-layout.cpp18
-rw-r--r--test/CodeGenCXX/2009-10-27-crash.cpp43
-rw-r--r--test/CodeGenCXX/2009-12-23-MissingSext.cpp16
-rw-r--r--test/CodeGenCXX/2010-05-10-Var-DbgInfo.cpp42
-rw-r--r--test/CodeGenCXX/2010-05-11-alwaysinlineinstantiation.cpp33
-rw-r--r--test/CodeGenCXX/2010-05-12-PtrToMember-Dbg.cpp17
-rw-r--r--test/CodeGenCXX/2010-06-21-LocalVarDbg.cpp14
-rw-r--r--test/CodeGenCXX/2010-06-22-BitfieldInit.cpp20
-rw-r--r--test/CodeGenCXX/2010-06-22-ZeroBitfield.cpp5
-rw-r--r--test/CodeGenCXX/2010-07-23-DeclLoc.cpp86
-rw-r--r--test/CodeGenCXX/PR5050-constructor-conversion.cpp4
-rw-r--r--test/CodeGenCXX/abstract-class-ctors-dtors.cpp2
-rw-r--r--test/CodeGenCXX/anonymous-union-member-initializer.cpp49
-rw-r--r--test/CodeGenCXX/apple-kext-linkage.C12
-rw-r--r--test/CodeGenCXX/arm.cpp10
-rw-r--r--test/CodeGenCXX/array-construction.cpp4
-rw-r--r--test/CodeGenCXX/array-operator-delete-call.cpp4
-rw-r--r--test/CodeGenCXX/blocks.cpp24
-rw-r--r--test/CodeGenCXX/builtins.cpp12
-rw-r--r--test/CodeGenCXX/cast-conversion.cpp4
-rw-r--r--test/CodeGenCXX/class-layout.cpp32
-rw-r--r--test/CodeGenCXX/conditional-expr-lvalue.cpp13
-rw-r--r--test/CodeGenCXX/constructor-conversion.cpp4
-rw-r--r--test/CodeGenCXX/constructor-convert.cpp1
-rw-r--r--test/CodeGenCXX/constructor-default-arg.cpp4
-rw-r--r--test/CodeGenCXX/constructor-for-array-members.cpp4
-rw-r--r--test/CodeGenCXX/constructor-init.cpp74
-rw-r--r--test/CodeGenCXX/constructor-template.cpp4
-rw-r--r--test/CodeGenCXX/conversion-function.cpp4
-rw-r--r--test/CodeGenCXX/convert-to-fptr.cpp4
-rw-r--r--test/CodeGenCXX/copy-assign-synthesis-1.cpp4
-rw-r--r--test/CodeGenCXX/copy-assign-volatile-synthesis.cpp43
-rw-r--r--test/CodeGenCXX/cxx0x-defaulted-templates.cpp2
-rw-r--r--test/CodeGenCXX/cxx0x-delegating-ctors.cpp2
-rw-r--r--test/CodeGenCXX/cxx0x-initializer-scalars.cpp7
-rw-r--r--test/CodeGenCXX/debug-info-char16.cpp9
-rw-r--r--test/CodeGenCXX/debug-info-cxx0x.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-nullptr.cpp8
-rw-r--r--test/CodeGenCXX/debug-info-wchar.cpp5
-rw-r--r--test/CodeGenCXX/debug-info.cpp12
-rw-r--r--test/CodeGenCXX/delete.cpp13
-rw-r--r--test/CodeGenCXX/derived-to-base-conv.cpp4
-rw-r--r--test/CodeGenCXX/destructors.cpp36
-rw-r--r--test/CodeGenCXX/dynamic-cast-always-null.cpp2
-rw-r--r--test/CodeGenCXX/dynamic-cast.cpp3
-rw-r--r--test/CodeGenCXX/eh.cpp46
-rw-r--r--test/CodeGenCXX/exceptions.cpp37
-rw-r--r--test/CodeGenCXX/for-range-temporaries.cpp14
-rw-r--r--test/CodeGenCXX/for-range.cpp2
-rw-r--r--test/CodeGenCXX/fp16-mangle.cpp12
-rw-r--r--test/CodeGenCXX/fp16-overload.cpp10
-rw-r--r--test/CodeGenCXX/global-array-destruction.cpp2
-rw-r--r--test/CodeGenCXX/goto.cpp1
-rw-r--r--test/CodeGenCXX/incomplete-types.cpp (renamed from test/CodeGenCXX/init-incomplete-type.cpp)14
-rw-r--r--test/CodeGenCXX/m64-ptr.cpp18
-rw-r--r--test/CodeGenCXX/mangle-alias-template.cpp2
-rw-r--r--test/CodeGenCXX/mangle-exprs.cpp2
-rw-r--r--test/CodeGenCXX/mangle-ref-qualifiers.cpp2
-rw-r--r--test/CodeGenCXX/mangle-subst-std.cpp6
-rw-r--r--test/CodeGenCXX/mangle-unnameable-conversions.cpp2
-rw-r--r--test/CodeGenCXX/mangle-variadic-templates.cpp2
-rw-r--r--test/CodeGenCXX/mangle.cpp13
-rw-r--r--test/CodeGenCXX/member-alignment.cpp20
-rw-r--r--test/CodeGenCXX/member-function-pointers.cpp2
-rw-r--r--test/CodeGenCXX/member-init-anon-union.cpp35
-rw-r--r--test/CodeGenCXX/member-init-ctor.cpp2
-rw-r--r--test/CodeGenCXX/nrvo.cpp13
-rw-r--r--test/CodeGenCXX/nullptr.cpp2
-rw-r--r--test/CodeGenCXX/partial-destruction.cpp21
-rw-r--r--test/CodeGenCXX/pr9965.cpp2
-rw-r--r--test/CodeGenCXX/ptr-to-member-function.cpp4
-rw-r--r--test/CodeGenCXX/reference-cast.cpp24
-rw-r--r--test/CodeGenCXX/reinterpret-cast.cpp2
-rw-r--r--test/CodeGenCXX/rvalue-references.cpp28
-rw-r--r--test/CodeGenCXX/scoped-enums.cpp2
-rw-r--r--test/CodeGenCXX/sizeof-unwind-exception.cpp28
-rw-r--r--test/CodeGenCXX/static-assert.cpp2
-rw-r--r--test/CodeGenCXX/static-init.cpp4
-rw-r--r--test/CodeGenCXX/template-instantiation.cpp36
-rw-r--r--test/CodeGenCXX/temporaries.cpp6
-rw-r--r--test/CodeGenCXX/threadsafe-statics-exceptions.cpp7
-rw-r--r--test/CodeGenCXX/thunk-linkonce-odr.cpp33
-rw-r--r--test/CodeGenCXX/typeid.cpp3
-rw-r--r--test/CodeGenCXX/union-dtor.cpp42
-rw-r--r--test/CodeGenCXX/value-init.cpp19
-rw-r--r--test/CodeGenCXX/vararg-conversion-ctor.cpp2
-rw-r--r--test/CodeGenCXX/varargs.cpp43
-rw-r--r--test/CodeGenCXX/variadic-templates.cpp2
-rw-r--r--test/CodeGenCXX/visibility.cpp2
-rw-r--r--test/CodeGenCXX/volatile-1.cpp288
-rw-r--r--test/CodeGenCXX/vtable-layout-abi-examples.cpp435
-rw-r--r--test/CodeGenCXX/weak-external.cpp66
-rw-r--r--test/CodeGenCXX/x86-64-abi-sret-vs-2word-struct-param.cpp29
-rw-r--r--test/CodeGenCXX/x86_32-arguments.cpp8
-rw-r--r--test/CodeGenObjC/2007-04-03-ObjcEH.m27
-rw-r--r--test/CodeGenObjC/2007-05-02-Strong.m23
-rw-r--r--test/CodeGenObjC/2007-10-18-ProDescriptor.m18
-rw-r--r--test/CodeGenObjC/2007-10-23-GC-WriteBarrier.m9
-rw-r--r--test/CodeGenObjC/2008-10-3-EhValue.m50
-rw-r--r--test/CodeGenObjC/2008-11-12-Metadata.m14
-rw-r--r--test/CodeGenObjC/2008-11-24-ConstCFStrings.m13
-rw-r--r--test/CodeGenObjC/2008-11-25-Blocks.m17
-rw-r--r--test/CodeGenObjC/2009-01-26-WriteBarrier-2.m19
-rw-r--r--test/CodeGenObjC/2009-02-05-VolatileProp.m10
-rw-r--r--test/CodeGenObjC/2009-08-05-utf16.m5
-rw-r--r--test/CodeGenObjC/2010-02-01-utf16-with-null.m5
-rw-r--r--test/CodeGenObjC/2010-02-23-DbgInheritance.m10
-rw-r--r--test/CodeGenObjC/2010-03-17-StructRef.m43
-rw-r--r--test/CodeGenObjC/2011-03-08-IVarLookup.m30
-rw-r--r--test/CodeGenObjC/arc-arm.m2
-rw-r--r--test/CodeGenObjC/arc-block-copy-escape.m22
-rw-r--r--test/CodeGenObjC/arc-block-ivar-layout.m2
-rw-r--r--test/CodeGenObjC/arc-bridged-cast.m2
-rw-r--r--test/CodeGenObjC/arc-compound-stmt.m2
-rw-r--r--test/CodeGenObjC/arc-foreach.m107
-rw-r--r--test/CodeGenObjC/arc-ivar-layout.m2
-rw-r--r--test/CodeGenObjC/arc-no-runtime.m2
-rw-r--r--test/CodeGenObjC/arc-related-result-type.m2
-rw-r--r--test/CodeGenObjC/arc-unbridged-cast.m4
-rw-r--r--test/CodeGenObjC/arc-unopt.m2
-rw-r--r--test/CodeGenObjC/arc-weak-property.m2
-rw-r--r--test/CodeGenObjC/arc-with-atthrow.m17
-rw-r--r--test/CodeGenObjC/arc.m394
-rw-r--r--test/CodeGenObjC/arm-atomic-scalar-setter-getter.m2
-rw-r--r--test/CodeGenObjC/assign.m2
-rw-r--r--test/CodeGenObjC/atomic-aggregate-property.m25
-rw-r--r--test/CodeGenObjC/attr-availability.m6
-rw-r--r--test/CodeGenObjC/autorelease.m4
-rw-r--r--test/CodeGenObjC/bitfield-1.m6
-rw-r--r--test/CodeGenObjC/bitfield-access.m4
-rw-r--r--test/CodeGenObjC/bitfield-ivar-offsets.m2
-rw-r--r--test/CodeGenObjC/bitfield_encoding.m4
-rw-r--r--test/CodeGenObjC/block-6.m2
-rw-r--r--test/CodeGenObjC/block-var-layout.m2
-rw-r--r--test/CodeGenObjC/blocks-1.m4
-rw-r--r--test/CodeGenObjC/blocks-2.m9
-rw-r--r--test/CodeGenObjC/blocks-3.m2
-rw-r--r--test/CodeGenObjC/blocks-4.m2
-rw-r--r--test/CodeGenObjC/blocks-5.m2
-rw-r--r--test/CodeGenObjC/blocks.m2
-rw-r--r--test/CodeGenObjC/builtins.m7
-rw-r--r--test/CodeGenObjC/category-class.m2
-rw-r--r--test/CodeGenObjC/class-type.m6
-rw-r--r--test/CodeGenObjC/complex-property.m2
-rw-r--r--test/CodeGenObjC/constant-string-class-1.m2
-rw-r--r--test/CodeGenObjC/constant-string-class.m4
-rw-r--r--test/CodeGenObjC/deadcode_strip_used_var.m4
-rw-r--r--test/CodeGenObjC/debug-info-block-helper.m2
-rw-r--r--test/CodeGenObjC/debug-info-blocks.m2
-rw-r--r--test/CodeGenObjC/debug-info-class-extension.m2
-rw-r--r--test/CodeGenObjC/debug-info-class-extension2.m2
-rw-r--r--test/CodeGenObjC/debug-info-class-extension3.m2
-rw-r--r--test/CodeGenObjC/debug-info-crash-2.m15
-rw-r--r--test/CodeGenObjC/debug-info-crash.m2
-rw-r--r--test/CodeGenObjC/debug-info-default-synth-ivar.m2
-rw-r--r--test/CodeGenObjC/debug-info-fnname.m15
-rw-r--r--test/CodeGenObjC/debug-info-getter-name.m2
-rw-r--r--test/CodeGenObjC/debug-info-property2.m14
-rw-r--r--test/CodeGenObjC/debug-info-static-var.m2
-rw-r--r--test/CodeGenObjC/default-property-synthesis.m2
-rw-r--r--test/CodeGenObjC/encode-cstyle-method.m2
-rw-r--r--test/CodeGenObjC/encode-test-4.m7
-rw-r--r--test/CodeGenObjC/encode-test.m2
-rw-r--r--test/CodeGenObjC/exceptions-nonfragile.m2
-rw-r--r--test/CodeGenObjC/exceptions.m2
-rw-r--r--test/CodeGenObjC/forward-class-impl-metadata.m2
-rw-r--r--test/CodeGenObjC/fpret.m6
-rw-r--r--test/CodeGenObjC/gc-weak-attribute.m28
-rw-r--r--test/CodeGenObjC/gc.m2
-rw-r--r--test/CodeGenObjC/gnu-exceptions.m6
-rw-r--r--test/CodeGenObjC/hidden-visibility.m2
-rw-r--r--test/CodeGenObjC/id-isa-codegen.m4
-rw-r--r--test/CodeGenObjC/image-info.m4
-rw-r--r--test/CodeGenObjC/implicit-objc_msgSend.m2
-rw-r--r--test/CodeGenObjC/instance-method-metadata.m2
-rw-r--r--test/CodeGenObjC/interface-layout-64.m2
-rw-r--r--test/CodeGenObjC/interface.m2
-rw-r--r--test/CodeGenObjC/ivar-layout-64-bitfields.m4
-rw-r--r--test/CodeGenObjC/ivar-layout-64.m4
-rw-r--r--test/CodeGenObjC/ivar-layout-array0-struct.m2
-rw-r--r--test/CodeGenObjC/ivar-layout-no-optimize.m4
-rw-r--r--test/CodeGenObjC/ivar-layout-nonfragile-abi2.m4
-rw-r--r--test/CodeGenObjC/ivars.m4
-rw-r--r--test/CodeGenObjC/link-errors.m4
-rw-r--r--test/CodeGenObjC/local-static-block.m2
-rw-r--r--test/CodeGenObjC/messages-2.m4
-rw-r--r--test/CodeGenObjC/messages.m8
-rw-r--r--test/CodeGenObjC/metadata-symbols-32.m2
-rw-r--r--test/CodeGenObjC/metadata-symbols-64.m2
-rw-r--r--test/CodeGenObjC/metadata_symbols.m6
-rw-r--r--test/CodeGenObjC/misc-atomic-property.m4
-rw-r--r--test/CodeGenObjC/mrr-autorelease.m4
-rw-r--r--test/CodeGenObjC/nested-rethrow.m2
-rw-r--r--test/CodeGenObjC/next-objc-dispatch.m8
-rw-r--r--test/CodeGenObjC/no-category-class.m2
-rw-r--r--test/CodeGenObjC/no-vararg-messaging.m2
-rw-r--r--test/CodeGenObjC/non-lazy-classes.m2
-rw-r--r--test/CodeGenObjC/nonlazy-msgSend.m2
-rw-r--r--test/CodeGenObjC/ns-constant-strings.m4
-rw-r--r--test/CodeGenObjC/objc-align.m2
-rw-r--r--test/CodeGenObjC/objc-assign-ivar.m2
-rw-r--r--test/CodeGenObjC/objc-gc-aggr-assign.m4
-rw-r--r--test/CodeGenObjC/objc-read-weak-byref.m4
-rw-r--r--test/CodeGenObjC/objc2-assign-global.m2
-rw-r--r--test/CodeGenObjC/objc2-ivar-assign.m2
-rw-r--r--test/CodeGenObjC/objc2-legacy-dispatch.m4
-rw-r--r--test/CodeGenObjC/objc2-new-gc-api-strongcast.m4
-rw-r--r--test/CodeGenObjC/objc2-no-write-barrier.m4
-rw-r--r--test/CodeGenObjC/objc2-nonfragile-abi-impl.m2
-rw-r--r--test/CodeGenObjC/objc2-retain-codegen.m4
-rw-r--r--test/CodeGenObjC/objc2-strong-cast-1.m4
-rw-r--r--test/CodeGenObjC/objc2-strong-cast-block-import.m25
-rw-r--r--test/CodeGenObjC/objc2-weak-assign.m4
-rw-r--r--test/CodeGenObjC/objc2-weak-block-call.m4
-rw-r--r--test/CodeGenObjC/objc2-weak-compare.m4
-rw-r--r--test/CodeGenObjC/objc2-weak-import-attribute.m2
-rw-r--r--test/CodeGenObjC/objc2-weak-ivar-debug.m8
-rw-r--r--test/CodeGenObjC/objc2-weak-ivar.m4
-rw-r--r--test/CodeGenObjC/objc2-write-barrier-2.m4
-rw-r--r--test/CodeGenObjC/objc2-write-barrier-3.m4
-rw-r--r--test/CodeGenObjC/objc2-write-barrier-4.m4
-rw-r--r--test/CodeGenObjC/objc2-write-barrier-5.m25
-rw-r--r--test/CodeGenObjC/objc2-write-barrier.m4
-rw-r--r--test/CodeGenObjC/object-incr-decr-1.m2
-rw-r--r--test/CodeGenObjC/predefined-expr.m2
-rw-r--r--test/CodeGenObjC/property-aggr-type.m50
-rw-r--r--test/CodeGenObjC/property-aggregate.m31
-rw-r--r--test/CodeGenObjC/property-category-impl.m2
-rw-r--r--test/CodeGenObjC/property-complex.m4
-rw-r--r--test/CodeGenObjC/property-list-in-class.m2
-rw-r--r--test/CodeGenObjC/property-ref-cast-to-void.m4
-rw-r--r--test/CodeGenObjC/property-type-mismatch.m2
-rw-r--r--test/CodeGenObjC/property.m9
-rw-r--r--test/CodeGenObjC/protocol-in-extended-class.m4
-rw-r--r--test/CodeGenObjC/protocol-property-synth.m2
-rw-r--r--test/CodeGenObjC/protocols-lazy.m2
-rw-r--r--test/CodeGenObjC/rdr-6732143-dangling-block-reference.m2
-rw-r--r--test/CodeGenObjC/simplify-exceptions.mm2
-rw-r--r--test/CodeGenObjC/stand-alone-implementation.m2
-rw-r--r--test/CodeGenObjC/super-dotsyntax-struct-property.m2
-rw-r--r--test/CodeGenObjC/super-message-fragileabi.m2
-rw-r--r--test/CodeGenObjC/synchronized.m2
-rw-r--r--test/CodeGenObjC/synthesize_ivar-cont-class.m2
-rw-r--r--test/CodeGenObjC/synthesize_ivar.m2
-rw-r--r--test/CodeGenObjC/terminate.m12
-rw-r--r--test/CodeGenObjC/variadic-sends.m4
-rw-r--r--test/CodeGenObjC/x86_64-struct-return-gc.m2
-rw-r--r--test/CodeGenObjCXX/2007-10-03-MetadataPointers.mm7
-rw-r--r--test/CodeGenObjCXX/2010-08-04-Template.mm10
-rw-r--r--test/CodeGenObjCXX/2010-08-06-X.Y-syntax.mm16
-rw-r--r--test/CodeGenObjCXX/arc-globals.mm2
-rw-r--r--test/CodeGenObjCXX/arc-mangle.mm2
-rw-r--r--test/CodeGenObjCXX/arc-move.mm2
-rw-r--r--test/CodeGenObjCXX/arc-new-delete.mm2
-rw-r--r--test/CodeGenObjCXX/arc-pseudo-destructors.mm2
-rw-r--r--test/CodeGenObjCXX/arc-references.mm7
-rw-r--r--test/CodeGenObjCXX/arc-returns-inner-reference-ptr.mm22
-rw-r--r--test/CodeGenObjCXX/arc-special-member-functions.mm18
-rw-r--r--test/CodeGenObjCXX/arc.mm47
-rw-r--r--test/CodeGenObjCXX/block-in-template-inst.mm2
-rw-r--r--test/CodeGenObjCXX/block-var-layout.mm2
-rw-r--r--test/CodeGenObjCXX/blocks.mm6
-rw-r--r--test/CodeGenObjCXX/catch-id-type.mm7
-rw-r--r--test/CodeGenObjCXX/copy.mm17
-rw-r--r--test/CodeGenObjCXX/copyable-property-object.mm2
-rw-r--r--test/CodeGenObjCXX/encode.mm41
-rw-r--r--test/CodeGenObjCXX/exceptions.mm5
-rw-r--r--test/CodeGenObjCXX/gc.mm2
-rw-r--r--test/CodeGenObjCXX/implicit-copy-assign-operator.mm2
-rw-r--r--test/CodeGenObjCXX/implicit-copy-constructor.mm2
-rw-r--r--test/CodeGenObjCXX/mangle-blocks.mm2
-rw-r--r--test/CodeGenObjCXX/message-reference.mm2
-rw-r--r--test/CodeGenObjCXX/nrvo.mm32
-rw-r--r--test/CodeGenObjCXX/property-derived-to-base-conv.mm2
-rw-r--r--test/CodeGenObjCXX/property-dot-copy.mm2
-rw-r--r--test/CodeGenObjCXX/property-dot-reference.mm2
-rw-r--r--test/CodeGenObjCXX/property-object-conditional-exp.mm2
-rw-r--r--test/CodeGenObjCXX/property-object-reference.mm23
-rw-r--r--test/CodeGenObjCXX/property-objects.mm2
-rw-r--r--test/CodeGenObjCXX/property-reference.mm52
-rw-r--r--test/CodeGenObjCXX/refence-assign-write-barrier.mm2
-rw-r--r--test/CodeGenObjCXX/selector-expr-lvalue.mm2
-rw-r--r--test/CodeGenObjCXX/write-barrier-global-assign.mm2
-rw-r--r--test/CodeGenOpenCL/local.cl7
-rw-r--r--test/CodeGenOpenCL/ptx-calls.cl12
-rw-r--r--test/CodeGenOpenCL/ptx-kernels.cl10
-rw-r--r--test/Driver/Inputs/basic_linux_tree/lib/.keep0
-rw-r--r--test/Driver/Inputs/basic_linux_tree/usr/i386-unknown-linux/lib/.keep0
-rw-r--r--test/Driver/Inputs/basic_linux_tree/usr/lib/.keep0
-rw-r--r--test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/crtbegin.o0
-rw-r--r--test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbegin.o0
-rw-r--r--test/Driver/Inputs/basic_linux_tree/usr/x86_64-unknown-linux/lib/.keep0
-rw-r--r--test/Driver/Inputs/fake_install_tree/bin/.keep0
-rw-r--r--test/Driver/Inputs/fake_install_tree/lib/gcc/i386-unknown-linux/4.7.0/crtbegin.o0
-rw-r--r--test/Driver/Inputs/fake_install_tree/lib/gcc/x86_64-unknown-linux/4.5.0/crtbegin.o0
-rw-r--r--test/Driver/Inputs/gcc_version_parsing1/bin/.keep0
-rw-r--r--test/Driver/Inputs/gcc_version_parsing1/lib/gcc/i386-unknown-linux/4.7/crtbegin.o0
-rw-r--r--test/Driver/Inputs/gcc_version_parsing2/bin/.keep0
-rw-r--r--test/Driver/Inputs/gcc_version_parsing2/lib/gcc/i386-unknown-linux/4.7.x/crtbegin.o0
-rw-r--r--test/Driver/Inputs/gcc_version_parsing3/bin/.keep0
-rw-r--r--test/Driver/Inputs/gcc_version_parsing3/lib/gcc/i386-unknown-linux/4.7.99-rc5/crtbegin.o0
-rw-r--r--test/Driver/Inputs/multilib_32bit_linux_tree/lib/.keep0
-rw-r--r--test/Driver/Inputs/multilib_32bit_linux_tree/lib32/.keep0
-rw-r--r--test/Driver/Inputs/multilib_32bit_linux_tree/lib64/.keep0
-rw-r--r--test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/lib/.keep0
-rw-r--r--test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/lib32/.keep0
-rw-r--r--test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/lib64/.keep0
-rw-r--r--test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib/.keep0
-rw-r--r--test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/crtbegin.o0
-rw-r--r--test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib32/.keep0
-rw-r--r--test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib64/.keep0
-rw-r--r--test/Driver/Inputs/multilib_64bit_linux_tree/lib/.keep0
-rw-r--r--test/Driver/Inputs/multilib_64bit_linux_tree/lib32/.keep0
-rw-r--r--test/Driver/Inputs/multilib_64bit_linux_tree/lib64/.keep0
-rw-r--r--test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib/.keep0
-rw-r--r--test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/32/crtbegin.o0
-rw-r--r--test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbegin.o0
-rw-r--r--test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib32/.keep0
-rw-r--r--test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib64/.keep0
-rw-r--r--test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/lib/.keep0
-rw-r--r--test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/lib32/.keep0
-rw-r--r--test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/lib64/.keep0
-rw-r--r--test/Driver/apple-kext-i386.cpp33
-rw-r--r--test/Driver/cc-log-diagnostics.c2
-rw-r--r--test/Driver/ccc-host-triple-no-integrated-as.c17
-rw-r--r--test/Driver/cpath.c20
-rw-r--r--test/Driver/darwin-objc-defaults.m18
-rw-r--r--test/Driver/darwin-objc-options.m4
-rw-r--r--test/Driver/darwin-verify-debug.c34
-rw-r--r--test/Driver/index-header-map.c4
-rw-r--r--test/Driver/le32-unknown-nacl.cpp141
-rw-r--r--test/Driver/linux-ld.c139
-rw-r--r--test/Driver/mno-global-merge.c12
-rw-r--r--test/Driver/nostdlibinc.c10
-rw-r--r--test/Driver/objc++-cpp-output.mm8
-rw-r--r--test/Driver/objc-cpp-output.m7
-rw-r--r--test/Driver/rewrite-objc.m4
-rw-r--r--test/Driver/std.cpp24
-rw-r--r--test/FixIt/dereference-addressof.c22
-rw-r--r--test/FixIt/fixit-cxx0x.cpp41
-rw-r--r--test/FixIt/fixit-errors.c2
-rw-r--r--test/FixIt/fixit-function-call.cpp118
-rw-r--r--test/FixIt/fixit-missing-method-return-type.m24
-rw-r--r--test/FixIt/fixit-objc-message.m4
-rw-r--r--test/FixIt/fixit-objc.m14
-rw-r--r--test/FixIt/fixit-static-object-decl.m29
-rw-r--r--test/FixIt/fixit.c15
-rw-r--r--test/FixIt/fixit.cpp13
-rw-r--r--test/FixIt/typo-crash.cpp11
-rw-r--r--test/FixIt/typo.m6
-rw-r--r--test/Frontend/Weverything.c9
-rw-r--r--test/Frontend/diagnostics-option-names.c8
-rw-r--r--test/Frontend/warning-mapping-1.c6
-rw-r--r--test/Frontend/warning-mapping-2.c5
-rw-r--r--test/Frontend/warning-mapping-3.c10
-rw-r--r--test/Frontend/warning-mapping-4.c6
-rw-r--r--test/Frontend/warning-mapping-5.c9
-rw-r--r--test/Headers/wchar_limits.cpp9
-rw-r--r--test/Index/IBOutletCollection.m18
-rw-r--r--test/Index/Inputs/preamble_macro_template.h6
-rw-r--r--test/Index/TestClassDecl.m2
-rw-r--r--test/Index/TestClassForwardDecl.m4
-rw-r--r--test/Index/annotate-attribute.cpp33
-rw-r--r--test/Index/annotate-context-sensitive.cpp6
-rw-r--r--test/Index/annotate-macro-args.h16
-rw-r--r--test/Index/annotate-macro-args.m23
-rw-r--r--test/Index/annotate-nested-name-specifier.cpp60
-rw-r--r--test/Index/annotate-tokens-cxx0x.cpp12
-rw-r--r--test/Index/annotate-tokens-pp.c70
-rw-r--r--test/Index/annotate-tokens-preamble.c20
-rw-r--r--test/Index/annotate-tokens-with-default-args.cpp16
-rw-r--r--test/Index/annotate-tokens-with-default-args.h3
-rw-r--r--test/Index/annotate-tokens.c91
-rw-r--r--test/Index/annotate-tokens.cpp32
-rw-r--r--test/Index/annotate-tokens.m193
-rw-r--r--test/Index/blocks.c20
-rw-r--r--test/Index/c-index-api-loadTU-test.m22
-rw-r--r--test/Index/c-index-getCursor-pp.c4
-rw-r--r--test/Index/c-index-getCursor-test.m44
-rw-r--r--test/Index/c-index-pch.c5
-rw-r--r--test/Index/code-completion.cpp3
-rw-r--r--test/Index/complete-access-checks.cpp89
-rw-r--r--test/Index/complete-cxx-inline-methods.cpp24
-rw-r--r--test/Index/complete-exprs.m4
-rw-r--r--test/Index/complete-in-stringify.c17
-rw-r--r--test/Index/complete-interfaces.m4
-rw-r--r--test/Index/complete-macro-args.c22
-rw-r--r--test/Index/complete-macros.c14
-rw-r--r--test/Index/complete-member-access.m15
-rw-r--r--test/Index/complete-objc-message.m23
-rw-r--r--test/Index/complete-qualified.cpp20
-rw-r--r--test/Index/complete-stmt.c12
-rw-r--r--test/Index/complete-synthesized.m30
-rw-r--r--test/Index/complete-with-annotations.cpp23
-rw-r--r--test/Index/cursor-ref-names.cpp47
-rw-r--r--test/Index/file-refs.c57
-rw-r--r--test/Index/file-refs.cpp104
-rw-r--r--test/Index/file-refs.m87
-rw-r--r--test/Index/get-cursor-macro-args.h16
-rw-r--r--test/Index/get-cursor-macro-args.m19
-rw-r--r--test/Index/get-cursor.c14
-rw-r--r--test/Index/get-cursor.cpp12
-rw-r--r--test/Index/get-cursor.m37
-rw-r--r--test/Index/getcursor-pp-pch.c43
-rw-r--r--test/Index/getcursor-pp-pch.c.h5
-rw-r--r--test/Index/in-class-init.cpp6
-rw-r--r--test/Index/index-templates.cpp10
-rw-r--r--test/Index/load-stmts.cpp16
-rw-r--r--test/Index/local-symbols.m8
-rw-r--r--test/Index/nested-binaryoperators.cpp2179
-rw-r--r--test/Index/nested-macro-instantiations.cpp4
-rw-r--r--test/Index/preamble-reparse-cmd-define.c9
-rw-r--r--test/Index/preamble-reparse-cmd-define.c.h1
-rw-r--r--test/Index/preamble-reparse-cmd-define.c.remap8
-rw-r--r--test/Index/preamble.c4
-rw-r--r--test/Index/preamble_macro_template.cpp15
-rw-r--r--test/Index/print-typekind.c11
-rw-r--r--test/Index/properties-class-extensions.m4
-rw-r--r--test/Index/rdar-8288645-invalid-code.mm1
-rw-r--r--test/Index/recursive-cxx-member-calls.cpp1016
-rw-r--r--test/Index/recursive-member-access.c272
-rw-r--r--test/Index/remap-load.c2
-rw-r--r--test/Index/usrs-cxx0x.cpp2
-rw-r--r--test/Index/usrs.m81
-rw-r--r--test/Lexer/bcpl-escaped-newline.c12
-rw-r--r--test/Lexer/constants.c2
-rw-r--r--test/Lexer/cxx0x_keyword.cpp2
-rw-r--r--test/Lexer/cxx0x_keyword_as_cxx98.cpp37
-rw-r--r--test/Lexer/cxx0x_raw_string_delim_length.cpp3
-rw-r--r--test/Lexer/cxx0x_raw_string_unterminated.cpp4
-rw-r--r--test/Lexer/has_extension.c8
-rw-r--r--test/Lexer/has_extension_cxx.cpp5
-rw-r--r--test/Lexer/has_feature_c1x.c9
-rw-r--r--test/Lexer/has_feature_cxx0x.cpp20
-rw-r--r--test/Lexer/has_feature_objc_arc.m4
-rw-r--r--test/Lexer/has_feature_type_traits.cpp5
-rw-r--r--test/Lexer/hexfloat.cpp9
-rw-r--r--test/Lexer/newline-eof.c5
-rw-r--r--test/Lexer/preamble.c4
-rw-r--r--test/Lexer/string_concat.cpp33
-rw-r--r--test/Lexer/utf8-char-literal.cpp4
-rw-r--r--test/Lexer/wchar.c4
-rw-r--r--test/Misc/ast-dump-templates.cpp39
-rw-r--r--test/Misc/caret-diags-macros.c9
-rw-r--r--test/Misc/diag-aka-types.cpp2
-rw-r--r--test/Misc/diag-line-wrapping.cpp13
-rw-r--r--test/Misc/error-limit-multiple-notes.cpp23
-rw-r--r--test/Misc/error-limit.c15
-rw-r--r--test/Misc/show-diag-options.c27
-rw-r--r--test/Misc/warning-flags.c317
-rw-r--r--test/Modules/Inputs/CmdLine.framework/Headers/CmdLine.h6
-rw-r--r--test/Modules/Inputs/DependsOnModule.framework/Headers/DependsOnModule.h3
-rw-r--r--test/Modules/Inputs/Module.framework/Headers/Module.h12
-rw-r--r--test/Modules/Inputs/MutuallyRecursive1.framework/Headers/MutuallyRecursive1.h3
-rw-r--r--test/Modules/Inputs/MutuallyRecursive2.framework/Headers/MutuallyRecursive2.h6
-rw-r--r--test/Modules/Inputs/diamond_bottom.h4
-rw-r--r--test/Modules/Inputs/diamond_left.h9
-rw-r--r--test/Modules/Inputs/diamond_right.h7
-rw-r--r--test/Modules/Inputs/diamond_top.h4
-rw-r--r--test/Modules/Inputs/load_failure.h1
-rw-r--r--test/Modules/Inputs/lookup_left.h3
-rw-r--r--test/Modules/Inputs/lookup_left.hpp5
-rw-r--r--test/Modules/Inputs/lookup_right.h5
-rw-r--r--test/Modules/Inputs/lookup_right.hpp1
-rw-r--r--test/Modules/Inputs/point.h2
-rw-r--r--test/Modules/auto-module-import.c13
-rw-r--r--test/Modules/cycles.c12
-rw-r--r--test/Modules/diamond.c27
-rw-r--r--test/Modules/driver.c6
-rw-r--r--test/Modules/header-import.m7
-rw-r--r--test/Modules/irgen.c15
-rw-r--r--test/Modules/load_failure.c19
-rw-r--r--test/Modules/lookup.cpp25
-rw-r--r--test/Modules/lookup.m19
-rw-r--r--test/Modules/macros.c41
-rw-r--r--test/Modules/module-private.cpp140
-rw-r--r--test/Modules/objc-categories.m89
-rw-r--r--test/Modules/on-demand-build-warnings.m5
-rw-r--r--test/Modules/on-demand-build.m17
-rw-r--r--test/Modules/on-demand-macros.m13
-rw-r--r--test/PCH/Inputs/cxx-method.h6
-rw-r--r--test/PCH/arc.m14
-rw-r--r--test/PCH/chain-categories.m51
-rw-r--r--test/PCH/chain-conversion-lookup.cpp26
-rw-r--r--test/PCH/chain-decls.c2
-rw-r--r--test/PCH/chain-ext_vector.c2
-rw-r--r--test/PCH/chain-external-defs.c2
-rw-r--r--test/PCH/chain-friend-instantiation.cpp61
-rw-r--r--test/PCH/chain-macro-override.c2
-rw-r--r--test/PCH/chain-macro.c2
-rw-r--r--test/PCH/chain-predecl.m2
-rw-r--r--test/PCH/chain-remap-types.m4
-rw-r--r--test/PCH/chain-selectors.m2
-rw-r--r--test/PCH/chain-trivial.c2
-rw-r--r--test/PCH/cxx-alias-decl.cpp6
-rw-r--r--test/PCH/cxx-for-range.cpp6
-rw-r--r--test/PCH/cxx-implicit-moves.cpp23
-rw-r--r--test/PCH/cxx-member-init.cpp6
-rw-r--r--test/PCH/cxx-method.cpp11
-rw-r--r--test/PCH/cxx-ms-function-specialization-class-scope.cpp13
-rw-r--r--test/PCH/cxx-ms-function-specialization-class-scope.h29
-rw-r--r--test/PCH/cxx-reference.cpp6
-rw-r--r--test/PCH/cxx-static_assert.cpp6
-rw-r--r--test/PCH/cxx-variadic-templates.cpp10
-rw-r--r--test/PCH/cxx0x-default-delete.cpp6
-rw-r--r--test/PCH/cxx0x-delegating-ctors.cpp6
-rw-r--r--test/PCH/cxx_exprs.cpp6
-rw-r--r--test/PCH/functions.c2
-rw-r--r--test/PCH/method-redecls.m18
-rw-r--r--test/PCH/modified-header-error.c2
-rw-r--r--test/PCH/objc_methods.h2
-rw-r--r--test/PCH/objc_methods.m2
-rw-r--r--test/PCH/preamble.c6
-rw-r--r--test/PCH/reinclude.cpp2
-rw-r--r--test/PCH/types.c6
-rw-r--r--test/PCH/types.h5
-rw-r--r--test/Parser/DelayedTemplateParsing.cpp23
-rw-r--r--test/Parser/MicrosoftExtensions.c8
-rw-r--r--test/Parser/PR11000.cpp9
-rw-r--r--test/Parser/access-spec-attrs.cpp12
-rw-r--r--test/Parser/c1x-alignas.c7
-rw-r--r--test/Parser/char-literal-printing.c36
-rw-r--r--test/Parser/cxx-casting.cpp23
-rw-r--r--test/Parser/cxx-class.cpp17
-rw-r--r--test/Parser/cxx-default-delete.cpp2
-rw-r--r--test/Parser/cxx-ext-delete-default.cpp10
-rw-r--r--test/Parser/cxx-member-init-missing-paren-crash.cpp12
-rw-r--r--test/Parser/cxx-member-initializers.cpp5
-rw-r--r--test/Parser/cxx-reference.cpp2
-rw-r--r--test/Parser/cxx0x-attributes.cpp13
-rw-r--r--test/Parser/cxx0x-in-cxx98.cpp8
-rw-r--r--test/Parser/cxx0x-lambda-expressions.cpp27
-rw-r--r--test/Parser/cxx0x-literal-operators.cpp7
-rw-r--r--test/Parser/cxx0x-member-initializers.cpp16
-rw-r--r--test/Parser/cxx0x-override-control-keywords.cpp2
-rw-r--r--test/Parser/cxx0x-rvalue-reference.cpp2
-rw-r--r--test/Parser/ms-inline-asm.c25
-rw-r--r--test/Parser/objc-init.m4
-rw-r--r--test/Parser/objc-messaging-neg-1.m1
-rw-r--r--test/Parser/objcxx-lambda-expressions-neg.mm5
-rw-r--r--test/Parser/objcxx0x-lambda-expressions.mm26
-rw-r--r--test/Parser/opencl-pragma.cl3
-rw-r--r--test/Parser/opencl-storage-class.cl6
-rw-r--r--test/Parser/parser_overflow.c7
-rw-r--r--test/Parser/pragma-visibility2.c19
-rw-r--r--test/Parser/switch-recovery.cpp2
-rw-r--r--test/Parser/top-level-semi-cxx0x.cpp2
-rw-r--r--test/Preprocessor/comment_save_if.c7
-rw-r--r--test/Preprocessor/expr_define_expansion.c5
-rw-r--r--test/Preprocessor/init.c20
-rw-r--r--test/Preprocessor/missing-system-header.c2
-rw-r--r--test/Preprocessor/missing-system-header.h2
-rw-r--r--test/Preprocessor/non_fragile_feature.m2
-rw-r--r--test/Preprocessor/non_fragile_feature1.m2
-rw-r--r--test/Preprocessor/pp-record.c9
-rw-r--r--test/Preprocessor/pp-record.h1
-rw-r--r--test/Preprocessor/predefined-arch-macros.c866
-rw-r--r--test/Preprocessor/predefined-exceptions.m15
-rw-r--r--test/Preprocessor/warning_tests.c19
-rw-r--r--test/Rewriter/inner-block-helper-funcs.mm32
-rw-r--r--test/Rewriter/instancetype-test.mm75
-rw-r--r--test/Rewriter/protocol-rewrite-2.m7
-rw-r--r--test/Rewriter/rewrite-cast-to-bool.mm17
-rw-r--r--test/Rewriter/rewrite-foreach-in-block.mm28
-rw-r--r--test/Rewriter/rewrite-forward-class.m29
-rw-r--r--test/Rewriter/rewrite-forward-class.mm44
-rw-r--r--test/Sema/2007-10-01-BuildArrayRef.c20
-rw-r--r--test/Sema/2009-03-09-WeakDeclarations-1.c16
-rw-r--r--test/Sema/2009-04-22-UnknownSize.c4
-rw-r--r--test/Sema/2009-07-17-VoidParameter.c4
-rw-r--r--test/Sema/2010-05-31-palignr.c22
-rw-r--r--test/Sema/Inputs/pragma-arc-cf-code-audited.h16
-rw-r--r--test/Sema/address_spaces.c4
-rw-r--r--test/Sema/alignas.c19
-rw-r--r--test/Sema/annotate.c3
-rw-r--r--test/Sema/array-bounds-ptr-arith.c14
-rw-r--r--test/Sema/array-init.c2
-rw-r--r--test/Sema/atomic-ops.c37
-rw-r--r--test/Sema/atomic-type.c22
-rw-r--r--test/Sema/attr-availability.c3
-rw-r--r--test/Sema/attr-deprecated.c2
-rw-r--r--test/Sema/attr-returns-twice.c12
-rw-r--r--test/Sema/attr-sentinel.c7
-rw-r--r--test/Sema/attr-unavailable-message.c21
-rw-r--r--test/Sema/complex-init-list.c45
-rw-r--r--test/Sema/conditional-expr.c25
-rw-r--r--test/Sema/conversion.c4
-rw-r--r--test/Sema/crash-invalid-array.c17
-rw-r--r--test/Sema/dllimport-dllexport.c1
-rw-r--r--test/Sema/exprs.c34
-rw-r--r--test/Sema/flexible-array-init.c35
-rw-r--r--test/Sema/format-strings-fixit.c2
-rw-r--r--test/Sema/format-strings.c17
-rw-r--r--test/Sema/fp16-sema.c30
-rw-r--r--test/Sema/fpack-struct.c9
-rw-r--r--test/Sema/i-c-e.c3
-rw-r--r--test/Sema/implicit-int.c6
-rw-r--r--test/Sema/init.c4
-rw-r--r--test/Sema/initialize-noreturn.c16
-rw-r--r--test/Sema/knr-def-call.c6
-rw-r--r--test/Sema/many-parameters.c310
-rw-r--r--test/Sema/ms-fuzzy-asm.c9
-rw-r--r--test/Sema/ms_class_layout.cpp176
-rw-r--r--test/Sema/parentheses.c3
-rw-r--r--test/Sema/parentheses.cpp2
-rw-r--r--test/Sema/pragma-arc-cf-code-audited.c18
-rw-r--r--test/Sema/return-noreturn.c4
-rw-r--r--test/Sema/types.c13
-rw-r--r--test/Sema/uninit-variables.c117
-rw-r--r--test/Sema/unused-expr.c20
-rw-r--r--test/Sema/warn-cast-align.c2
-rw-r--r--test/Sema/warn-strlcpycat-size.c55
-rw-r--r--test/Sema/warn-unreachable.c20
-rw-r--r--test/Sema/warn-unused-parameters.c10
-rw-r--r--test/SemaCUDA/cuda.h2
-rw-r--r--test/SemaCUDA/function-target.cu44
-rw-r--r--test/SemaCUDA/kernel-call.cu3
-rw-r--r--test/SemaCXX/2008-01-11-BadWarning.cpp5
-rw-r--r--test/SemaCXX/MicrosoftCompatibility.cpp158
-rw-r--r--test/SemaCXX/MicrosoftExtensions.cpp61
-rw-r--r--test/SemaCXX/PR10243.cpp2
-rw-r--r--test/SemaCXX/PR10458.cpp7
-rw-r--r--test/SemaCXX/PR5086-ambig-resolution-enum.cpp2
-rw-r--r--test/SemaCXX/PR7944.cpp2
-rw-r--r--test/SemaCXX/PR8012.cpp2
-rw-r--r--test/SemaCXX/PR9572.cpp2
-rw-r--r--test/SemaCXX/PR9902.cpp2
-rw-r--r--test/SemaCXX/PR9908.cpp2
-rw-r--r--test/SemaCXX/abstract.cpp2
-rw-r--r--test/SemaCXX/address-of.cpp11
-rw-r--r--test/SemaCXX/aggregate-initialization.cpp8
-rw-r--r--test/SemaCXX/alias-template.cpp2
-rw-r--r--test/SemaCXX/alignof-sizeof-reference.cpp15
-rw-r--r--test/SemaCXX/ambig-user-defined-conversions.cpp2
-rw-r--r--test/SemaCXX/ambiguous-builtin-unary-operator.cpp2
-rw-r--r--test/SemaCXX/array-bounds-ptr-arith.cpp33
-rw-r--r--test/SemaCXX/array-bounds.cpp80
-rw-r--r--test/SemaCXX/attr-cxx0x.cpp14
-rw-r--r--test/SemaCXX/attr-deprecated.cpp4
-rw-r--r--test/SemaCXX/auto-cxx0x.cpp4
-rw-r--r--test/SemaCXX/auto-cxx98.cpp7
-rw-r--r--test/SemaCXX/auto-subst-failure.cpp2
-rw-r--r--test/SemaCXX/bool.cpp7
-rw-r--r--test/SemaCXX/builtin-ptrtomember-ambig.cpp2
-rw-r--r--test/SemaCXX/builtin-ptrtomember-overload-1.cpp2
-rw-r--r--test/SemaCXX/builtin-ptrtomember-overload.cpp2
-rw-r--r--test/SemaCXX/cast-conversion.cpp5
-rw-r--r--test/SemaCXX/class.cpp13
-rw-r--r--test/SemaCXX/compare.cpp11
-rw-r--r--test/SemaCXX/complex-init-list.cpp14
-rw-r--r--test/SemaCXX/conditional-expr.cpp23
-rw-r--r--test/SemaCXX/conversion-delete-expr.cpp2
-rw-r--r--test/SemaCXX/convert-to-bool.cpp6
-rw-r--r--test/SemaCXX/cxx0x-class.cpp28
-rw-r--r--test/SemaCXX/cxx0x-compat.cpp24
-rw-r--r--test/SemaCXX/cxx0x-constexpr-const.cpp2
-rw-r--r--test/SemaCXX/cxx0x-cursory-default-delete.cpp4
-rw-r--r--test/SemaCXX/cxx0x-defaulted-functions.cpp2
-rw-r--r--test/SemaCXX/cxx0x-delegating-ctors.cpp2
-rw-r--r--test/SemaCXX/cxx0x-deleted-default-ctor.cpp14
-rw-r--r--test/SemaCXX/cxx0x-initializer-scalars.cpp34
-rw-r--r--test/SemaCXX/cxx0x-nontrivial-union.cpp2
-rw-r--r--test/SemaCXX/cxx0x-return-init-list.cpp6
-rw-r--r--test/SemaCXX/cxx0x-type-convert-construct.cpp21
-rw-r--r--test/SemaCXX/cxx98-compat-pedantic.cpp11
-rw-r--r--test/SemaCXX/cxx98-compat.cpp30
-rw-r--r--test/SemaCXX/decl-init-ref.cpp2
-rw-r--r--test/SemaCXX/decltype-crash.cpp2
-rw-r--r--test/SemaCXX/decltype-overloaded-functions.cpp14
-rw-r--r--test/SemaCXX/decltype-pr4444.cpp2
-rw-r--r--test/SemaCXX/decltype-pr4448.cpp2
-rw-r--r--test/SemaCXX/decltype-this.cpp2
-rw-r--r--test/SemaCXX/decltype.cpp2
-rw-r--r--test/SemaCXX/defaulted-ctor-loop.cpp2
-rw-r--r--test/SemaCXX/delete.cpp2
-rw-r--r--test/SemaCXX/deleted-function.cpp2
-rw-r--r--test/SemaCXX/deleted-operator.cpp13
-rw-r--r--test/SemaCXX/dependent-auto.cpp2
-rw-r--r--test/SemaCXX/dependent-noexcept-unevaluated.cpp2
-rw-r--r--test/SemaCXX/dependent-types.cpp2
-rw-r--r--test/SemaCXX/destructor.cpp2
-rw-r--r--test/SemaCXX/enum-bitfield.cpp2
-rw-r--r--test/SemaCXX/enum-scoped.cpp2
-rw-r--r--test/SemaCXX/explicit.cpp147
-rw-r--r--test/SemaCXX/expression-traits.cpp40
-rw-r--r--test/SemaCXX/expressions.cpp75
-rw-r--r--test/SemaCXX/for-range-examples.cpp2
-rw-r--r--test/SemaCXX/for-range-no-std.cpp3
-rw-r--r--test/SemaCXX/for-range-unused.cpp2
-rw-r--r--test/SemaCXX/function-overload-typo-crash.cpp20
-rw-r--r--test/SemaCXX/function-redecl.cpp71
-rw-r--r--test/SemaCXX/generalized-initializers.cpp23
-rw-r--r--test/SemaCXX/generic-selection.cpp2
-rw-r--r--test/SemaCXX/i-c-e-cxx.cpp6
-rw-r--r--test/SemaCXX/implicit-exception-spec.cpp2
-rw-r--r--test/SemaCXX/issue547.cpp2
-rw-r--r--test/SemaCXX/libstdcxx_is_pod_hack.cpp4
-rw-r--r--test/SemaCXX/linkage-spec.cpp13
-rw-r--r--test/SemaCXX/literal-operators.cpp40
-rw-r--r--test/SemaCXX/literal-type.cpp2
-rw-r--r--test/SemaCXX/member-expr.cpp30
-rw-r--r--test/SemaCXX/member-init.cpp20
-rw-r--r--test/SemaCXX/microsoft-cxx0x.cpp10
-rw-r--r--test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp14
-rw-r--r--test/SemaCXX/nested-name-spec.cpp10
-rw-r--r--test/SemaCXX/new-array-size-conv.cpp4
-rw-r--r--test/SemaCXX/new-delete.cpp19
-rw-r--r--test/SemaCXX/null_in_arithmetic_ops.cpp14
-rw-r--r--test/SemaCXX/nullptr.cpp2
-rw-r--r--test/SemaCXX/nullptr_in_arithmetic_ops.cpp2
-rw-r--r--test/SemaCXX/out-of-line-def-mismatch.cpp24
-rw-r--r--test/SemaCXX/overload-0x.cpp11
-rw-r--r--test/SemaCXX/overload-call.cpp9
-rw-r--r--test/SemaCXX/overloaded-builtin-operators-0x.cpp2
-rw-r--r--test/SemaCXX/overloaded-name.cpp17
-rw-r--r--test/SemaCXX/overloaded-operator-decl.cpp5
-rw-r--r--test/SemaCXX/overloaded-operator.cpp6
-rw-r--r--test/SemaCXX/ptrtomember-overload-resolution.cpp2
-rw-r--r--test/SemaCXX/ptrtomember.cpp18
-rw-r--r--test/SemaCXX/redeclared-alias-template.cpp2
-rw-r--r--test/SemaCXX/redeclared-auto.cpp2
-rw-r--r--test/SemaCXX/ref-init-ambiguous.cpp2
-rw-r--r--test/SemaCXX/references.cpp3
-rw-r--r--test/SemaCXX/return-noreturn.cpp99
-rw-r--r--test/SemaCXX/rval-references-examples.cpp2
-rw-r--r--test/SemaCXX/rval-references.cpp2
-rw-r--r--test/SemaCXX/scope-check.cpp38
-rw-r--r--test/SemaCXX/static-assert.cpp2
-rw-r--r--test/SemaCXX/switch-0x.cpp2
-rw-r--r--test/SemaCXX/trailing-return-0x.cpp2
-rw-r--r--test/SemaCXX/trivial-constructor.cpp2
-rw-r--r--test/SemaCXX/trivial-destructor.cpp2
-rw-r--r--test/SemaCXX/type-traits.cpp36
-rw-r--r--test/SemaCXX/typo-correction.cpp31
-rw-r--r--test/SemaCXX/underlying_type.cpp2
-rw-r--r--test/SemaCXX/uninit-variables-conditional.cpp2
-rw-r--r--test/SemaCXX/uninit-variables.cpp36
-rw-r--r--test/SemaCXX/uninitialized.cpp74
-rw-r--r--test/SemaCXX/unknown-anytype.cpp11
-rw-r--r--test/SemaCXX/unused-functions.cpp2
-rw-r--r--test/SemaCXX/user-defined-conversions.cpp15
-rw-r--r--test/SemaCXX/using-decl-templates.cpp17
-rw-r--r--test/SemaCXX/value-initialization.cpp2
-rw-r--r--test/SemaCXX/vararg-non-pod.cpp1
-rw-r--r--test/SemaCXX/virtual-override.cpp2
-rw-r--r--test/SemaCXX/virtuals.cpp2
-rw-r--r--test/SemaCXX/warn-assignment-condition.cpp6
-rw-r--r--test/SemaCXX/warn-bad-memaccess.cpp17
-rw-r--r--test/SemaCXX/warn-bool-conversion.cpp12
-rw-r--r--test/SemaCXX/warn-dangling-field.cpp37
-rw-r--r--test/SemaCXX/warn-literal-conversion.cpp18
-rw-r--r--test/SemaCXX/warn-memset-bad-sizeof.cpp38
-rw-r--r--test/SemaCXX/warn-missing-noreturn.cpp34
-rw-r--r--test/SemaCXX/warn-sign-compare.cpp72
-rw-r--r--test/SemaCXX/warn-sign-conversion.cpp80
-rw-r--r--test/SemaCXX/warn-string-conversion.cpp18
-rw-r--r--test/SemaCXX/warn-thread-safety-analysis.cpp1422
-rw-r--r--test/SemaCXX/warn-thread-safety-parsing.cpp1255
-rw-r--r--test/SemaCXX/warn-unreachable.cpp8
-rw-r--r--test/SemaCXX/warn-unused-comparison.cpp94
-rw-r--r--test/SemaCXX/warn-unused-value.cpp15
-rw-r--r--test/SemaCXX/warn-weak-vtables.cpp27
-rw-r--r--test/SemaObjC/arc-bridged-cast.m4
-rw-r--r--test/SemaObjC/arc-cf.m20
-rw-r--r--test/SemaObjC/arc-decls.m21
-rw-r--r--test/SemaObjC/arc-jump-block.m2
-rw-r--r--test/SemaObjC/arc-no-runtime.m2
-rw-r--r--test/SemaObjC/arc-non-pod-memaccess.m12
-rw-r--r--test/SemaObjC/arc-nsconsumed-errors.m20
-rw-r--r--test/SemaObjC/arc-peformselector.m2
-rw-r--r--test/SemaObjC/arc-property-decl-attrs.m16
-rw-r--r--test/SemaObjC/arc-property-lifetime.m21
-rw-r--r--test/SemaObjC/arc-property.m2
-rw-r--r--test/SemaObjC/arc-retain-block-property.m30
-rw-r--r--test/SemaObjC/arc-setter-property-match.m35
-rw-r--r--test/SemaObjC/arc-system-header.m4
-rw-r--r--test/SemaObjC/arc-type-conversion.m2
-rw-r--r--test/SemaObjC/arc-unavailable-for-weakref.m2
-rw-r--r--test/SemaObjC/arc-unavailable-system-function.m13
-rw-r--r--test/SemaObjC/arc-unbridged-cast.m78
-rw-r--r--test/SemaObjC/arc-unsafe-assigns.m2
-rw-r--r--test/SemaObjC/arc-unsafe_unretained.m4
-rw-r--r--test/SemaObjC/arc.m89
-rw-r--r--test/SemaObjC/assign-rvalue-message.m4
-rw-r--r--test/SemaObjC/at-defs.m2
-rw-r--r--test/SemaObjC/atomoic-property-synnthesis-rules.m24
-rw-r--r--test/SemaObjC/attr-availability.m13
-rw-r--r--test/SemaObjC/attr-deprecated.m15
-rw-r--r--test/SemaObjC/attr-ns-bridged.m15
-rw-r--r--test/SemaObjC/bad-property-synthesis-crash.m23
-rw-r--r--test/SemaObjC/blocks.m12
-rw-r--r--test/SemaObjC/builtin_objc_assign_ivar.m6
-rw-r--r--test/SemaObjC/class-bitfield.m2
-rw-r--r--test/SemaObjC/class-protocol-method-match.m48
-rw-r--r--test/SemaObjC/class-unavail-warning.m20
-rw-r--r--test/SemaObjC/comptypes-10.m18
-rw-r--r--test/SemaObjC/comptypes-7.m2
-rw-r--r--test/SemaObjC/conflict-atomic-property.m10
-rw-r--r--test/SemaObjC/conflict-nonfragile-abi2.m2
-rw-r--r--test/SemaObjC/conflicting-ivar-test-1.m2
-rw-r--r--test/SemaObjC/continuation-class-property.m19
-rw-r--r--test/SemaObjC/crash-label.m11
-rw-r--r--test/SemaObjC/default-synthesize-1.m26
-rw-r--r--test/SemaObjC/default-synthesize-2.m116
-rw-r--r--test/SemaObjC/default-synthesize.m8
-rw-r--r--test/SemaObjC/deref-interface.m2
-rw-r--r--test/SemaObjC/direct-synthesized-ivar-access.m7
-rw-r--r--test/SemaObjC/duplicate-ivar-in-class-extension.m2
-rw-r--r--test/SemaObjC/enum-fixed-type.m27
-rw-r--r--test/SemaObjC/error-property-gc-attr.m2
-rw-r--r--test/SemaObjC/iboutletcollection-attr.m5
-rw-r--r--test/SemaObjC/id-isa-ref.m2
-rw-r--r--test/SemaObjC/incomplete-implementation.m9
-rw-r--r--test/SemaObjC/instancetype.m190
-rw-r--r--test/SemaObjC/interface-1.m2
-rw-r--r--test/SemaObjC/interface-layout.m2
-rw-r--r--test/SemaObjC/ivar-in-class-extension-error.m2
-rw-r--r--test/SemaObjC/ivar-in-class-extension.m2
-rw-r--r--test/SemaObjC/ivar-in-implementations.m2
-rw-r--r--test/SemaObjC/ivar-sem-check-2.m2
-rw-r--r--test/SemaObjC/method-no-context.m3
-rw-r--r--test/SemaObjC/missing-atend-metadata.m2
-rw-r--r--test/SemaObjC/missing-method-return-type.m11
-rw-r--r--test/SemaObjC/nested-typedef-decl.m21
-rw-r--r--test/SemaObjC/objc-buffered-methods.m25
-rw-r--r--test/SemaObjC/property-and-class-extension.m2
-rw-r--r--test/SemaObjC/property-and-ivar-use.m2
-rw-r--r--test/SemaObjC/property-category-1.m4
-rw-r--r--test/SemaObjC/property-category-2.m6
-rw-r--r--test/SemaObjC/property-category-3.m2
-rw-r--r--test/SemaObjC/property-category-impl.m4
-rw-r--r--test/SemaObjC/property-inherited.m4
-rw-r--r--test/SemaObjC/property-nonfragile-abi.m2
-rw-r--r--test/SemaObjC/property-ns-returns-not-retained-attr.m2
-rw-r--r--test/SemaObjC/property.m10
-rw-r--r--test/SemaObjC/protocol-archane.m7
-rw-r--r--test/SemaObjC/protocol-implementing-class-methods.m41
-rw-r--r--test/SemaObjC/provisional-ivar-lookup.m2
-rw-r--r--test/SemaObjC/qualified-protocol-method-conflicts.m39
-rw-r--r--test/SemaObjC/related-result-type-inference.m6
-rw-r--r--test/SemaObjC/return.m11
-rw-r--r--test/SemaObjC/self-declared-in-block.m4
-rw-r--r--test/SemaObjC/sizeof-interface.m2
-rw-r--r--test/SemaObjC/super-class-protocol-conformance.m12
-rw-r--r--test/SemaObjC/synth-provisional-ivars-1.m2
-rw-r--r--test/SemaObjC/synth-provisional-ivars.m12
-rw-r--r--test/SemaObjC/synthesized-ivar.m10
-rw-r--r--test/SemaObjC/undeclared-selector.m2
-rw-r--r--test/SemaObjC/unimplemented-protocol-prop.m29
-rw-r--r--test/SemaObjC/uninit-variables.m2
-rw-r--r--test/SemaObjC/warn-deprecated-implementations.m3
-rw-r--r--test/SemaObjC/warn-implicit-atomic-property.m2
-rw-r--r--test/SemaObjC/warn-missing-super.m57
-rw-r--r--test/SemaObjC/warn-retain-cycle.m4
-rw-r--r--test/SemaObjC/weak-property.m2
-rw-r--r--test/SemaObjCXX/arc-0x.mm2
-rw-r--r--test/SemaObjCXX/arc-bool-conversion.mm2
-rw-r--r--test/SemaObjCXX/arc-bridged-cast.mm2
-rw-r--r--test/SemaObjCXX/arc-libcxx.mm11
-rw-r--r--test/SemaObjCXX/arc-libstdcxx.mm2
-rw-r--r--test/SemaObjCXX/arc-memfunc.mm2
-rw-r--r--test/SemaObjCXX/arc-non-pod.mm2
-rw-r--r--test/SemaObjCXX/arc-nsconsumed-errors.mm20
-rw-r--r--test/SemaObjCXX/arc-object-init-destroy.mm2
-rw-r--r--test/SemaObjCXX/arc-overloading.mm29
-rw-r--r--test/SemaObjCXX/arc-system-header.mm2
-rw-r--r--test/SemaObjCXX/arc-templates.mm16
-rw-r--r--test/SemaObjCXX/arc-type-conversion.mm2
-rw-r--r--test/SemaObjCXX/arc-type-traits.mm2
-rw-r--r--test/SemaObjCXX/arc-unavailable-for-weakref.mm2
-rw-r--r--test/SemaObjCXX/exceptions-fragile.mm2
-rw-r--r--test/SemaObjCXX/linkage-spec.mm9
-rw-r--r--test/SemaObjCXX/message.mm2
-rw-r--r--test/SemaObjCXX/nullptr.mm2
-rw-r--r--test/SemaObjCXX/propert-dot-error.mm17
-rw-r--r--test/SemaObjCXX/property-reference.mm4
-rw-r--r--test/SemaObjCXX/property-synthesis-error.mm44
-rw-r--r--test/SemaObjCXX/unknown-anytype.mm8
-rw-r--r--test/SemaOpenCL/local.cl6
-rw-r--r--test/SemaOpenCL/vector_conv_invalid.cl14
-rw-r--r--test/SemaOpenCL/vector_literals_invalid.cl2
-rw-r--r--test/SemaTemplate/alias-church-numerals.cpp2
-rw-r--r--test/SemaTemplate/alias-nested-nontag.cpp2
-rw-r--r--test/SemaTemplate/alias-template-template-param.cpp2
-rw-r--r--test/SemaTemplate/alias-templates.cpp2
-rw-r--r--test/SemaTemplate/atomics.cpp8
-rw-r--r--test/SemaTemplate/attributes.cpp13
-rw-r--r--test/SemaTemplate/canonical-expr-type-0x.cpp2
-rw-r--r--test/SemaTemplate/current-instantiation.cpp20
-rw-r--r--test/SemaTemplate/default-arguments-cxx0x.cpp2
-rw-r--r--test/SemaTemplate/delegating-constructors.cpp18
-rw-r--r--test/SemaTemplate/dependent-names.cpp2
-rw-r--r--test/SemaTemplate/instantiate-array.cpp2
-rw-r--r--test/SemaTemplate/instantiate-expr-1.cpp13
-rw-r--r--test/SemaTemplate/instantiate-expr-4.cpp17
-rw-r--r--test/SemaTemplate/instantiate-expr-basic.cpp2
-rw-r--r--test/SemaTemplate/instantiate-function-2.cpp2
-rw-r--r--test/SemaTemplate/instantiate-member-class.cpp2
-rw-r--r--test/SemaTemplate/instantiate-static-var.cpp2
-rw-r--r--test/SemaTemplate/instantiate-try-catch.cpp2
-rw-r--r--test/SemaTemplate/lookup-dependent-bases.cpp19
-rw-r--r--test/SemaTemplate/member-inclass-init-value-dependent.cpp7
-rw-r--r--test/SemaTemplate/missing-class-keyword-crash.cpp7
-rw-r--r--test/SemaTemplate/ms-function-specialization-class-scope.cpp71
-rw-r--r--test/SemaTemplate/ms-lookup-template-base-classes.cpp31
-rw-r--r--test/SemaTemplate/nested-template.cpp16
-rw-r--r--test/SemaTemplate/operator-template.cpp10
-rw-r--r--test/SemaTemplate/overload-uneval.cpp2
-rw-r--r--test/SemaTemplate/resolve-single-template-id.cpp38
-rw-r--r--test/SemaTemplate/temp_arg_nontype.cpp64
-rw-r--r--test/SemaTemplate/temp_explicit_cxx0x.cpp2
-rw-r--r--test/SemaTemplate/typename-specifier.cpp13
-rw-r--r--test/SemaTemplate/unresolved-construct.cpp2
-rw-r--r--test/lit.cfg4
-rw-r--r--tools/CMakeLists.txt1
-rw-r--r--tools/Makefile2
-rw-r--r--tools/arcmt-test/arcmt-test.cpp47
-rw-r--r--tools/c-index-test/CMakeLists.txt1
-rw-r--r--tools/c-index-test/Makefile3
-rw-r--r--tools/c-index-test/c-index-test.c264
-rw-r--r--tools/diagtool/CMakeLists.txt24
-rw-r--r--tools/diagtool/DiagTool.cpp68
-rw-r--r--tools/diagtool/DiagTool.h70
-rw-r--r--tools/diagtool/ListWarnings.cpp106
-rw-r--r--tools/diagtool/Makefile25
-rw-r--r--tools/diagtool/diagtool_main.cpp26
-rw-r--r--tools/driver/Makefile9
-rw-r--r--tools/driver/cc1_main.cpp17
-rw-r--r--tools/driver/cc1as_main.cpp94
-rw-r--r--tools/driver/driver.cpp71
-rw-r--r--tools/libclang/CIndex.cpp1403
-rw-r--r--tools/libclang/CIndexCXX.cpp11
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp185
-rw-r--r--tools/libclang/CIndexDiagnostic.cpp18
-rw-r--r--tools/libclang/CIndexHigh.cpp315
-rw-r--r--tools/libclang/CIndexInclusionStack.cpp19
-rw-r--r--tools/libclang/CIndexUSRs.cpp106
-rw-r--r--tools/libclang/CIndexer.cpp2
-rw-r--r--tools/libclang/CMakeLists.txt1
-rw-r--r--tools/libclang/CXCursor.cpp697
-rw-r--r--tools/libclang/CXCursor.h37
-rw-r--r--tools/libclang/CXString.cpp6
-rw-r--r--tools/libclang/CXString.h6
-rw-r--r--tools/libclang/CXTranslationUnit.h9
-rw-r--r--tools/libclang/CXType.cpp36
-rw-r--r--tools/libclang/Index_Internal.h43
-rw-r--r--tools/libclang/libclang.darwin.exports143
-rw-r--r--tools/libclang/libclang.exports26
-rwxr-xr-xtools/scan-build/ccc-analyzer29
-rwxr-xr-xtools/scan-build/scan-build4
-rw-r--r--unittests/AST/APValueTest.cpp83
-rw-r--r--unittests/AST/Makefile15
-rw-r--r--unittests/Basic/FileManagerTest.cpp3
-rw-r--r--unittests/CMakeLists.txt5
-rw-r--r--unittests/Makefile2
-rw-r--r--utils/TableGen/CMakeLists.txt12
-rw-r--r--utils/TableGen/ClangASTNodesEmitter.cpp168
-rw-r--r--utils/TableGen/ClangASTNodesEmitter.h84
-rw-r--r--utils/TableGen/ClangAttrEmitter.cpp788
-rw-r--r--utils/TableGen/ClangAttrEmitter.h114
-rw-r--r--utils/TableGen/ClangDiagnosticsEmitter.cpp378
-rw-r--r--utils/TableGen/ClangDiagnosticsEmitter.h54
-rw-r--r--utils/TableGen/ClangSACheckersEmitter.cpp319
-rw-r--r--utils/TableGen/ClangSACheckersEmitter.h31
-rw-r--r--utils/TableGen/Makefile19
-rw-r--r--utils/TableGen/NeonEmitter.cpp1551
-rw-r--r--utils/TableGen/NeonEmitter.h176
-rw-r--r--utils/TableGen/OptParserEmitter.cpp194
-rw-r--r--utils/TableGen/OptParserEmitter.h34
-rw-r--r--utils/TableGen/TableGen.cpp176
-rwxr-xr-xutils/analyzer/CmpRuns.py (renamed from utils/analyzer/CmpRuns)60
-rw-r--r--utils/analyzer/SATestAdd.py71
-rw-r--r--utils/analyzer/SATestBuild.py307
-rw-r--r--utils/clangVisualizers.txt44
-rw-r--r--www/OpenProjects.html4
-rw-r--r--www/analyzer/latest_checker.html.incl2
-rw-r--r--www/analyzer/release_notes.html13
-rw-r--r--www/comparison.html4
-rw-r--r--www/compatibility.html40
-rw-r--r--www/cxx_status.html977
-rw-r--r--www/demo/index.cgi2
-rw-r--r--www/diagnostics.html33
-rw-r--r--www/get_involved.html31
-rw-r--r--www/get_started.html2
-rw-r--r--www/hacking.html22
-rw-r--r--www/index.html2
-rw-r--r--www/menu.html.incl5
2436 files changed, 101599 insertions, 47629 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000000..ddd66380adf8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,25 @@
+#==============================================================================#
+# This file specifies intentionally untracked files that git should ignore.
+# See: http://www.kernel.org/pub/software/scm/git/docs/gitignore.html
+#
+# This file is intentionally different from the output of `git svn show-ignore`,
+# as most of those are useless.
+#==============================================================================#
+
+#==============================================================================#
+# File extensions to be ignored anywhere in the tree.
+#==============================================================================#
+# Temp files created by most text editors.
+*~
+# Merge files created by git.
+*.orig
+# Byte compiled python modules.
+*.pyc
+# vim swap files
+.*.swp
+
+#==============================================================================#
+# Explicit files to ignore (only matches one).
+#==============================================================================#
+cscope.files
+cscope.out
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3ad60eaff516..019168f5a915 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,10 +19,10 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
endif()
endif()
- if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
- # Looking for bin/Debug/tblgen is a complete hack. How can we get
+ if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
+ # Looking for bin/Debug/llvm-tblgen is a complete hack. How can we get
# around this?
- if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/Debug/tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
+ if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/Debug/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
message(FATAL_ERROR "Please set CLANG_PATH_TO_LLVM_BUILD to a directory containing a LLVM build.")
endif()
endif()
@@ -46,11 +46,11 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
include_directories("${PATH_TO_LLVM_BUILD}/include" "${LLVM_MAIN_INCLUDE_DIR}")
link_directories("${PATH_TO_LLVM_BUILD}/lib")
- if( EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
- set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/tblgen")
+ if( EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
+ set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
else()
# FIXME: This is an utter hack.
- set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/Debug/tblgen")
+ set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/Debug/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
endif()
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
@@ -153,7 +153,7 @@ function(clang_tablegen)
endif()
set( LLVM_TARGET_DEFINITIONS ${CTG_SOURCE} )
- tablegen( ${CTG_DEFAULT_ARGS} )
+ tablegen( CLANG ${CTG_DEFAULT_ARGS} )
list( GET CTG_DEFAULT_ARGS 0 output_file )
if( CTG_TARGET )
@@ -244,6 +244,7 @@ set(LIBCLANG_LIBRARY_VERSION
"Version number that will be placed into the libclang library , in the form XX.YY")
mark_as_advanced(CLANG_EXECUTABLE_VERSION LIBCLANG_LIBRARY_VERSION)
+add_subdirectory(utils/TableGen)
option(CLANG_BUILD_EXAMPLES "Build CLANG example programs." OFF)
if(CLANG_BUILD_EXAMPLES)
@@ -272,3 +273,6 @@ if( CLANG_BUILT_STANDALONE AND MSVC_VERSION EQUAL 1600 )
file(APPEND "${CLANG_SLN_FILENAME}" "\n# This should be regenerated!\n")
endif()
endif()
+
+set(BUG_REPORT_URL "http://llvm.org/bugs/" CACHE STRING
+ "Default URL where bug reports are to be submitted.")
diff --git a/INPUTS/cfg-nested-var-scopes.cpp b/INPUTS/cfg-nested-var-scopes.cpp
new file mode 100644
index 000000000000..0944ec268f1b
--- /dev/null
+++ b/INPUTS/cfg-nested-var-scopes.cpp
@@ -0,0 +1,59 @@
+// Hammer the CFG with large numbers of overlapping variable scopes, which
+// implicit destructors triggered at each edge.
+
+#define EXPAND_BASIC_STRUCT(i) struct X##i { X##i(int); ~X##i(); };
+#define EXPAND_NORET_STRUCT(i) struct X##i { X##i(int); ~X##i() __attribute__((noreturn)); };
+EXPAND_BASIC_STRUCT(0000); EXPAND_NORET_STRUCT(0001);
+EXPAND_BASIC_STRUCT(0010); EXPAND_BASIC_STRUCT(0011);
+EXPAND_BASIC_STRUCT(0100); EXPAND_NORET_STRUCT(0101);
+EXPAND_NORET_STRUCT(0110); EXPAND_BASIC_STRUCT(0111);
+EXPAND_BASIC_STRUCT(1000); EXPAND_NORET_STRUCT(1001);
+EXPAND_BASIC_STRUCT(1010); EXPAND_BASIC_STRUCT(1011);
+EXPAND_NORET_STRUCT(1100); EXPAND_NORET_STRUCT(1101);
+EXPAND_BASIC_STRUCT(1110); EXPAND_BASIC_STRUCT(1111);
+
+#define EXPAND_2_VARS(c, i, x) const X##i var_##c##_##i##0(x), &var_##c##_##i##1 = X##i(x)
+#define EXPAND_4_VARS(c, i, x) EXPAND_2_VARS(c, i##0, x); EXPAND_2_VARS(c, i##1, x)
+#define EXPAND_8_VARS(c, i, x) EXPAND_4_VARS(c, i##0, x); EXPAND_4_VARS(c, i##1, x)
+#define EXPAND_16_VARS(c, i, x) EXPAND_8_VARS(c, i##0, x); EXPAND_8_VARS(c, i##1, x)
+#define EXPAND_32_VARS(c, x) EXPAND_16_VARS(c, 0, x); EXPAND_16_VARS(c, 1, x)
+
+#define EXPAND_2_INNER_CASES(i, x, y) INNER_CASE(i, x, y); INNER_CASE(i + 1, x, y);
+#define EXPAND_4_INNER_CASES(i, x, y) EXPAND_2_INNER_CASES(i, x, y) EXPAND_2_INNER_CASES(i + 2, x, y)
+#define EXPAND_8_INNER_CASES(i, x, y) EXPAND_4_INNER_CASES(i, x, y) EXPAND_4_INNER_CASES(i + 4, x, y)
+#define EXPAND_16_INNER_CASES(i, x, y) EXPAND_8_INNER_CASES(i, x, y) EXPAND_8_INNER_CASES(i + 8, x, y)
+#define EXPAND_32_INNER_CASES(i, x, y) EXPAND_16_INNER_CASES(i, x, y) EXPAND_16_INNER_CASES(i + 16, x, y)
+
+#define EXPAND_2_OUTER_CASES(i, x, y) OUTER_CASE(i, x, y); OUTER_CASE(i + 1, x, y);
+#define EXPAND_4_OUTER_CASES(i, x, y) EXPAND_2_OUTER_CASES(i, x, y) EXPAND_2_OUTER_CASES(i + 2, x, y)
+#define EXPAND_8_OUTER_CASES(i, x, y) EXPAND_4_OUTER_CASES(i, x, y) EXPAND_4_OUTER_CASES(i + 4, x, y)
+#define EXPAND_16_OUTER_CASES(i, x, y) EXPAND_8_OUTER_CASES(i, x, y) EXPAND_8_OUTER_CASES(i + 8, x, y)
+#define EXPAND_32_OUTER_CASES(i, x, y) EXPAND_16_OUTER_CASES(i, x, y) EXPAND_16_OUTER_CASES(i + 16, x, y)
+
+unsigned cfg_nested_vars(int x) {
+ int y = 0;
+ while (x > 0) {
+ EXPAND_32_VARS(a, x);
+ switch (x) {
+#define INNER_CASE(i, x, y) \
+ case i: { \
+ int case_var = 3*x + i; \
+ EXPAND_32_VARS(c, case_var); \
+ y += case_var - 1; \
+ break; \
+ }
+#define OUTER_CASE(i, x, y) \
+ case i: { \
+ int case_var = y >> 8; \
+ EXPAND_32_VARS(b, y); \
+ switch (case_var) { \
+ EXPAND_32_INNER_CASES(0, x, y); \
+ } \
+ break; \
+ }
+EXPAND_32_OUTER_CASES(0, x, y);
+ }
+ --x;
+ }
+ return y;
+}
diff --git a/Makefile b/Makefile
index b6c630aa10af..bf1a77210b5e 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ ifndef CLANG_LEVEL
IS_TOP_LEVEL := 1
CLANG_LEVEL := .
-DIRS := include lib tools runtime docs unittests
+DIRS := utils/TableGen include lib tools runtime docs unittests
PARALLEL_DIRS :=
@@ -60,6 +60,16 @@ endif
# We can revisit this when LLVM/Clang support it.
CXX.Flags += -fno-strict-aliasing
+# Set up Clang's tblgen.
+ifndef CLANG_TBLGEN
+ ifeq ($(LLVM_CROSS_COMPILING),1)
+ CLANG_TBLGEN := $(BuildLLVMToolDir)/clang-tblgen$(BUILD_EXEEXT)
+ else
+ CLANG_TBLGEN := $(LLVMToolDir)/clang-tblgen$(EXEEXT)
+ endif
+endif
+ClangTableGen = $(CLANG_TBLGEN) $(TableGen.Flags)
+
###
# Clang Top Level specific stuff.
@@ -68,7 +78,7 @@ ifeq ($(IS_TOP_LEVEL),1)
ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
$(RecursiveTargets)::
$(Verb) for dir in test unittests; do \
- if [ ! -f $${dir}/Makefile ]; then \
+ if [ -f $(PROJ_SRC_DIR)/$${dir}/Makefile ] && [ ! -f $${dir}/Makefile ]; then \
$(MKDIR) $${dir}; \
$(CP) $(PROJ_SRC_DIR)/$${dir}/Makefile $${dir}/Makefile; \
fi \
diff --git a/NOTES.txt b/NOTES.txt
index f66a96120a81..9f7ed4b9591c 100644
--- a/NOTES.txt
+++ b/NOTES.txt
@@ -83,3 +83,21 @@ enum VerifyConstraintResult {
};
//===---------------------------------------------------------------------===//
+
+Blocks should not capture variables that are only used in dead code.
+
+The rule that we came up with is that blocks are required to capture
+variables if they're referenced in evaluated code, even if that code
+doesn't actually rely on the value of the captured variable.
+
+For example, this requires a capture:
+ (void) var;
+But this does not:
+ if (false) puts(var);
+
+Summary of <rdar://problem/9851835>: if we implement this, we should
+warn about non-POD variables that are referenced but not captured, but
+only if the non-reachability is not due to macro or template
+metaprogramming.
+
+//===---------------------------------------------------------------------===//
diff --git a/TODO.txt b/TODO.txt
deleted file mode 100644
index 8c27515ae74a..000000000000
--- a/TODO.txt
+++ /dev/null
@@ -1,75 +0,0 @@
-//===---------------------------------------------------------------------===//
-// Minor random things that can be improved
-//===---------------------------------------------------------------------===//
-
-Warn about "X && 0x1000" saying that the user may mean "X & 0x1000".
-We should do this for any immediate except zero, so long as it doesn't come
-from a macro expansion. Likewise for ||.
-
-//===---------------------------------------------------------------------===//
-
-Lexer-related diagnostics should point to the problematic character, not the
-start of the token. For example:
-
-int y = 0000\
-00080;
-
-diag.c:4:9: error: invalid digit '8' in octal constant
-int y = 0000\
- ^
-
-should be:
-
-diag.c:4:9: error: invalid digit '8' in octal constant
-00080;
- ^
-
-This specific diagnostic is implemented, but others should be updated.
-
-//===---------------------------------------------------------------------===//
-
-C++ (checker): For iterators, warn of the use of "iterator++" instead
- of "++iterator" when when the value returned by operator++(int) is
- ignored.
-
-//===---------------------------------------------------------------------===//
-
-We want to keep more source range information in Declarator to help
-produce better diagnostics. Declarator::getSourceRange() should be
-implemented to give a range for the whole declarator with all of its
-specifiers, and DeclaratorChunk::ParamInfo should also have a source
-range covering the whole parameter, so that an error message like this:
-
-overloaded-operator-decl.cpp:37:23: error: parameter of overloaded post-increment operator must have type 'int' (not 'float')
-X operator++(X&, const float& f);
- ^
-can be turned into something like this:
-
-overloaded-operator-decl.cpp:37:23: error: parameter of overloaded post-increment operator must have type 'int' (not 'float')
-X operator++(X&, const float& f);
- ^ ~~~~~~~~~~~~~~
-
-//===---------------------------------------------------------------------===//
-
-For terminal output, we should consider limiting the amount of
-diagnostic text we print once the first error has been
-encountered. For example, once we have produced an error diagnostic,
-we should only continue producing diagnostics until we have produced a
-page full of results (say, 50 lines of text). Beyond that, (1) the
-remaining errors are likely to be less interesting, and (2) the poor
-user has to scroll his terminal to find out where things went wrong.
-
-//===---------------------------------------------------------------------===//
-More ideas for code modification hints:
- - If no member of a given name is found in a class/struct, search through the names of entities that do exist in the class and suggest the closest candidate. e.g., if I write "DS.setTypeSpecType", it would suggest "DS.SetTypeSpecType" (edit distance = 1).
- - If a class member is defined out-of-line but isn't in the class declaration (and there are no close matches!), provide the option to add an in-class declaration.
- - Fix-it hints for the inclusion of headers when needed for particular features (e.g., <typeinfo> for typeid)
-
-//===---------------------------------------------------------------------===//
-
-Options to support:
- -ftabstop=width
- -fpreprocessed mode.
- -nostdinc++
- -imultilib
-
diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py
index 8cadcaa7ad06..35c423d7d898 100644
--- a/bindings/python/clang/cindex.py
+++ b/bindings/python/clang/cindex.py
@@ -112,7 +112,7 @@ class SourceLocation(Structure):
f, l, c, o = c_object_p(), c_uint(), c_uint(), c_uint()
SourceLocation_loc(self, byref(f), byref(l), byref(c), byref(o))
f = File(f) if f else None
- self._data = (f, int(l.value), int(c.value), int(c.value))
+ self._data = (f, int(l.value), int(c.value), int(o.value))
return self._data
@property
@@ -451,6 +451,19 @@ CursorKind.USING_DIRECTIVE = CursorKind(34)
# A C++ using declaration
CursorKind.USING_DECLARATION = CursorKind(35)
+# A Type alias decl.
+CursorKind.TYPE_ALIAS_DECL = CursorKind(36)
+
+# A Objective-C synthesize decl
+CursorKind.OBJC_SYNTHESIZE_DECL = CursorKind(37)
+
+# A Objective-C dynamic decl
+CursorKind.OBJC_DYNAMIC_DECL = CursorKind(38)
+
+# A C++ access specifier decl.
+CursorKind.CXX_ACCESS_SPEC_DECL = CursorKind(39)
+
+
###
# Reference Kinds
@@ -524,6 +537,154 @@ CursorKind.OBJC_MESSAGE_EXPR = CursorKind(104)
# An expression that represents a block literal.
CursorKind.BLOCK_EXPR = CursorKind(105)
+# An integer literal.
+CursorKind.INTEGER_LITERAL = CursorKind(106)
+
+# A floating point number literal.
+CursorKind.FLOATING_LITERAL = CursorKind(107)
+
+# An imaginary number literal.
+CursorKind.IMAGINARY_LITERAL = CursorKind(108)
+
+# A string literal.
+CursorKind.STRING_LITERAL = CursorKind(109)
+
+# A character literal.
+CursorKind.CHARACTER_LITERAL = CursorKind(110)
+
+# A parenthesized expression, e.g. "(1)".
+#
+# This AST node is only formed if full location information is requested.
+CursorKind.PAREN_EXPR = CursorKind(111)
+
+# This represents the unary-expression's (except sizeof and
+# alignof).
+CursorKind.UNARY_OPERATOR = CursorKind(112)
+
+# [C99 6.5.2.1] Array Subscripting.
+CursorKind.ARRAY_SUBSCRIPT_EXPR = CursorKind(113)
+
+# A builtin binary operation expression such as "x + y" or
+# "x <= y".
+CursorKind.BINARY_OPERATOR = CursorKind(114)
+
+# Compound assignment such as "+=".
+CursorKind.COMPOUND_ASSIGNMENT_OPERATOR = CursorKind(115)
+
+# The ?: ternary operator.
+CursorKind.CONDITONAL_OPERATOR = CursorKind(116)
+
+# An explicit cast in C (C99 6.5.4) or a C-style cast in C++
+# (C++ [expr.cast]), which uses the syntax (Type)expr.
+#
+# For example: (int)f.
+CursorKind.CSTYLE_CAST_EXPR = CursorKind(117)
+
+# [C99 6.5.2.5]
+CursorKind.COMPOUND_LITERAL_EXPR = CursorKind(118)
+
+# Describes an C or C++ initializer list.
+CursorKind.INIT_LIST_EXPR = CursorKind(119)
+
+# The GNU address of label extension, representing &&label.
+CursorKind.ADDR_LABEL_EXPR = CursorKind(120)
+
+# This is the GNU Statement Expression extension: ({int X=4; X;})
+CursorKind.StmtExpr = CursorKind(121)
+
+# Represents a C1X generic selection.
+CursorKind.GENERIC_SELECTION_EXPR = CursorKind(122)
+
+# Implements the GNU __null extension, which is a name for a null
+# pointer constant that has integral type (e.g., int or long) and is the same
+# size and alignment as a pointer.
+#
+# The __null extension is typically only used by system headers, which define
+# NULL as __null in C++ rather than using 0 (which is an integer that may not
+# match the size of a pointer).
+CursorKind.GNU_NULL_EXPR = CursorKind(123)
+
+# C++'s static_cast<> expression.
+CursorKind.CXX_STATIC_CAST_EXPR = CursorKind(124)
+
+# C++'s dynamic_cast<> expression.
+CursorKind.CXX_DYNAMIC_CAST_EXPR = CursorKind(125)
+
+# C++'s reinterpret_cast<> expression.
+CursorKind.CXX_REINTERPRET_CAST_EXPR = CursorKind(126)
+
+# C++'s const_cast<> expression.
+CursorKind.CXX_CONST_CAST_EXPR = CursorKind(127)
+
+# Represents an explicit C++ type conversion that uses "functional"
+# notion (C++ [expr.type.conv]).
+#
+# Example:
+# \code
+# x = int(0.5);
+# \endcode
+CursorKind.CXX_FUNCTIONAL_CAST_EXPR = CursorKind(128)
+
+# A C++ typeid expression (C++ [expr.typeid]).
+CursorKind.CXX_TYPEID_EXPR = CursorKind(129)
+
+# [C++ 2.13.5] C++ Boolean Literal.
+CursorKind.CXX_BOOL_LITERAL_EXPR = CursorKind(130)
+
+# [C++0x 2.14.7] C++ Pointer Literal.
+CursorKind.CXX_NULL_PTR_LITERAL_EXPR = CursorKind(131)
+
+# Represents the "this" expression in C++
+CursorKind.CXX_THIS_EXPR = CursorKind(132)
+
+# [C++ 15] C++ Throw Expression.
+#
+# This handles 'throw' and 'throw' assignment-expression. When
+# assignment-expression isn't present, Op will be null.
+CursorKind.CXX_THROW_EXPR = CursorKind(133)
+
+# A new expression for memory allocation and constructor calls, e.g:
+# "new CXXNewExpr(foo)".
+CursorKind.CXX_NEW_EXPR = CursorKind(134)
+
+# A delete expression for memory deallocation and destructor calls,
+# e.g. "delete[] pArray".
+CursorKind.CXX_DELETE_EXPR = CursorKind(135)
+
+# Represents a unary expression.
+CursorKind.CXX_UNARY_EXPR = CursorKind(136)
+
+# ObjCStringLiteral, used for Objective-C string literals i.e. "foo".
+CursorKind.OBJC_STRING_LITERAL = CursorKind(137)
+
+# ObjCEncodeExpr, used for in Objective-C.
+CursorKind.OBJC_ENCODE_EXPR = CursorKind(138)
+
+# ObjCSelectorExpr used for in Objective-C.
+CursorKind.OBJC_SELECTOR_EXPR = CursorKind(139)
+
+# Objective-C's protocol expression.
+CursorKind.OBJC_PROTOCOL_EXPR = CursorKind(140)
+
+# An Objective-C "bridged" cast expression, which casts between
+# Objective-C pointers and C pointers, transferring ownership in the process.
+#
+# \code
+# NSString *str = (__bridge_transfer NSString *)CFCreateString();
+# \endcode
+CursorKind.OBJC_BRIDGE_CAST_EXPR = CursorKind(141)
+
+# Represents a C++0x pack expansion that produces a sequence of
+# expressions.
+#
+# A pack expansion expression contains a pattern (which itself is an
+# expression) followed by an ellipsis. For example:
+CursorKind.PACK_EXPANSION_EXPR = CursorKind(142)
+
+# Represents an expression that computes the length of a parameter
+# pack.
+CursorKind.SIZE_OF_PACK_EXPR = CursorKind(143)
+
# A statement whose specific kind is not exposed via this interface.
#
# Unexposed statements have the same operations as any other kind of statement;
@@ -534,6 +695,92 @@ CursorKind.UNEXPOSED_STMT = CursorKind(200)
# A labelled statement in a function.
CursorKind.LABEL_STMT = CursorKind(201)
+# A compound statement
+CursorKind.COMPOUND_STMT = CursorKind(202)
+
+# A case statement.
+CursorKind.CASE_STMT = CursorKind(203)
+
+# A default statement.
+CursorKind.DEFAULT_STMT = CursorKind(204)
+
+# An if statement.
+CursorKind.IF_STMT = CursorKind(205)
+
+# A switch statement.
+CursorKind.SWITCH_STMT = CursorKind(206)
+
+# A while statement.
+CursorKind.WHILE_STMT = CursorKind(207)
+
+# A do statement.
+CursorKind.DO_STMT = CursorKind(208)
+
+# A for statement.
+CursorKind.FOR_STMT = CursorKind(209)
+
+# A goto statement.
+CursorKind.GOTO_STMT = CursorKind(210)
+
+# An indirect goto statement.
+CursorKind.INDIRECT_GOTO_STMT = CursorKind(211)
+
+# A continue statement.
+CursorKind.CONTINUE_STMT = CursorKind(212)
+
+# A break statement.
+CursorKind.BREAK_STMT = CursorKind(213)
+
+# A return statement.
+CursorKind.RETURN_STMT = CursorKind(214)
+
+# A GNU-style inline assembler statement.
+CursorKind.ASM_STMT = CursorKind(215)
+
+# Objective-C's overall @try-@catch-@finally statement.
+CursorKind.OBJC_AT_TRY_STMT = CursorKind(216)
+
+# Objective-C's @catch statement.
+CursorKind.OBJC_AT_CATCH_STMT = CursorKind(217)
+
+# Objective-C's @finally statement.
+CursorKind.OBJC_AT_FINALLY_STMT = CursorKind(218)
+
+# Objective-C's @throw statement.
+CursorKind.OBJC_AT_THROW_STMT = CursorKind(219)
+
+# Objective-C's @synchronized statement.
+CursorKind.OBJC_AT_SYNCHRONIZED_STMT = CursorKind(220)
+
+# Objective-C's autorealease pool statement.
+CursorKind.OBJC_AUTORELEASE_POOL_STMT = CursorKind(221)
+
+# Objective-C's for collection statement.
+CursorKind.OBJC_FOR_COLLECTION_STMT = CursorKind(222)
+
+# C++'s catch statement.
+CursorKind.CXX_CATCH_STMT = CursorKind(223)
+
+# C++'s try statement.
+CursorKind.CXX_TRY_STMT = CursorKind(224)
+
+# C++'s for (* : *) statement.
+CursorKind.CXX_FOR_RANGE_STMT = CursorKind(225)
+
+# Windows Structured Exception Handling's try statement.
+CursorKind.SEH_TRY_STMT = CursorKind(226)
+
+# Windows Structured Exception Handling's except statement.
+CursorKind.SEH_EXCEPT_STMT = CursorKind(227)
+
+# Windows Structured Exception Handling's finally statement.
+CursorKind.SEH_FINALLY_STMT = CursorKind(228)
+
+# The null statement.
+CursorKind.NULL_STMT = CursorKind(230)
+
+# Adaptor class for mixing declarations with statements and expressions.
+CursorKind.DECL_STMT = CursorKind(231)
###
# Other Kinds
@@ -616,7 +863,22 @@ class Cursor(Structure):
# FIXME: clang_getCursorSpelling should be fixed to not assert on
# this, for consistency with clang_getCursorUSR.
return None
- return Cursor_spelling(self)
+ if not hasattr(self, '_spelling'):
+ self._spelling = Cursor_spelling(self)
+ return self._spelling
+
+ @property
+ def displayname(self):
+ """
+ Return the display name for the entity referenced by this cursor.
+
+ The display name contains extra information that helps identify the cursor,
+ such as the parameters of a function or template or the arguments of a
+ class template specialization.
+ """
+ if not hasattr(self, '_displayname'):
+ self._displayname = Cursor_displayname(self)
+ return self._displayname
@property
def location(self):
@@ -624,7 +886,9 @@ class Cursor(Structure):
Return the source location (the starting character) of the entity
pointed at by the cursor.
"""
- return Cursor_loc(self)
+ if not hasattr(self, '_loc'):
+ self._loc = Cursor_loc(self)
+ return self._loc
@property
def extent(self):
@@ -632,7 +896,19 @@ class Cursor(Structure):
Return the source range (the range of text) occupied by the entity
pointed at by the cursor.
"""
- return Cursor_extent(self)
+ if not hasattr(self, '_extent'):
+ self._extent = Cursor_extent(self)
+ return self._extent
+
+ @property
+ def type(self):
+ """
+ Retrieve the type (if any) of of the entity pointed at by the
+ cursor.
+ """
+ if not hasattr(self, '_type'):
+ self._type = Cursor_type(self)
+ return self._type
def get_children(self):
"""Return an iterator for accessing the children of this cursor."""
@@ -656,6 +932,165 @@ class Cursor(Structure):
return None
return res
+
+### Type Kinds ###
+
+class TypeKind(object):
+ """
+ Describes the kind of type.
+ """
+
+ # The unique kind objects, indexed by id.
+ _kinds = []
+ _name_map = None
+
+ def __init__(self, value):
+ if value >= len(TypeKind._kinds):
+ TypeKind._kinds += [None] * (value - len(TypeKind._kinds) + 1)
+ if TypeKind._kinds[value] is not None:
+ raise ValueError,'TypeKind already loaded'
+ self.value = value
+ TypeKind._kinds[value] = self
+ TypeKind._name_map = None
+
+ def from_param(self):
+ return self.value
+
+ @property
+ def name(self):
+ """Get the enumeration name of this cursor kind."""
+ if self._name_map is None:
+ self._name_map = {}
+ for key,value in TypeKind.__dict__.items():
+ if isinstance(value,TypeKind):
+ self._name_map[value] = key
+ return self._name_map[self]
+
+ @staticmethod
+ def from_id(id):
+ if id >= len(TypeKind._kinds) or TypeKind._kinds[id] is None:
+ raise ValueError,'Unknown cursor kind'
+ return TypeKind._kinds[id]
+
+ def __repr__(self):
+ return 'TypeKind.%s' % (self.name,)
+
+
+
+TypeKind.INVALID = TypeKind(0)
+TypeKind.UNEXPOSED = TypeKind(1)
+TypeKind.VOID = TypeKind(2)
+TypeKind.BOOL = TypeKind(3)
+TypeKind.CHAR_U = TypeKind(4)
+TypeKind.UCHAR = TypeKind(5)
+TypeKind.CHAR16 = TypeKind(6)
+TypeKind.CHAR32 = TypeKind(7)
+TypeKind.USHORT = TypeKind(8)
+TypeKind.UINT = TypeKind(9)
+TypeKind.ULONG = TypeKind(10)
+TypeKind.ULONGLONG = TypeKind(11)
+TypeKind.UINT128 = TypeKind(12)
+TypeKind.CHAR_S = TypeKind(13)
+TypeKind.SCHAR = TypeKind(14)
+TypeKind.WCHAR = TypeKind(15)
+TypeKind.SHORT = TypeKind(16)
+TypeKind.INT = TypeKind(17)
+TypeKind.LONG = TypeKind(18)
+TypeKind.LONGLONG = TypeKind(19)
+TypeKind.INT128 = TypeKind(20)
+TypeKind.FLOAT = TypeKind(21)
+TypeKind.DOUBLE = TypeKind(22)
+TypeKind.LONGDOUBLE = TypeKind(23)
+TypeKind.NULLPTR = TypeKind(24)
+TypeKind.OVERLOAD = TypeKind(25)
+TypeKind.DEPENDENT = TypeKind(26)
+TypeKind.OBJCID = TypeKind(27)
+TypeKind.OBJCCLASS = TypeKind(28)
+TypeKind.OBJCSEL = TypeKind(29)
+TypeKind.COMPLEX = TypeKind(100)
+TypeKind.POINTER = TypeKind(101)
+TypeKind.BLOCKPOINTER = TypeKind(102)
+TypeKind.LVALUEREFERENCE = TypeKind(103)
+TypeKind.RVALUEREFERENCE = TypeKind(104)
+TypeKind.RECORD = TypeKind(105)
+TypeKind.ENUM = TypeKind(106)
+TypeKind.TYPEDEF = TypeKind(107)
+TypeKind.OBJCINTERFACE = TypeKind(108)
+TypeKind.OBJCOBJECTPOINTER = TypeKind(109)
+TypeKind.FUNCTIONNOPROTO = TypeKind(110)
+TypeKind.FUNCTIONPROTO = TypeKind(111)
+
+
+class Type(Structure):
+ """
+ The type of an element in the abstract syntax tree.
+ """
+ _fields_ = [("_kind_id", c_int), ("data", c_void_p * 2)]
+
+ @property
+ def kind(self):
+ """Return the kind of this type."""
+ return TypeKind.from_id(self._kind_id)
+
+ @staticmethod
+ def from_result(res, fn, args):
+ assert isinstance(res, Type)
+ return res
+
+ def get_canonical(self):
+ """
+ Return the canonical type for a Type.
+
+ Clang's type system explicitly models typedefs and all the
+ ways a specific type can be represented. The canonical type
+ is the underlying type with all the "sugar" removed. For
+ example, if 'T' is a typedef for 'int', the canonical type for
+ 'T' would be 'int'.
+ """
+ return Type_get_canonical(self)
+
+ def is_const_qualified(self):
+ """
+ Determine whether a Type has the "const" qualifier set,
+ without looking through typedefs that may have added "const"
+ at a different level.
+ """
+ return Type_is_const_qualified(self)
+
+ def is_volatile_qualified(self):
+ """
+ Determine whether a Type has the "volatile" qualifier set,
+ without looking through typedefs that may have added
+ "volatile" at a different level.
+ """
+ return Type_is_volatile_qualified(self)
+
+ def is_restrict_qualified(self):
+ """
+ Determine whether a Type has the "restrict" qualifier set,
+ without looking through typedefs that may have added
+ "restrict" at a different level.
+ """
+ return Type_is_restrict_qualified(self)
+
+ def get_pointee(self):
+ """
+ For pointer types, returns the type of the pointee.
+ """
+ return Type_get_pointee(self)
+
+ def get_declaration(self):
+ """
+ Return the cursor for the declaration of the given type.
+ """
+ return Type_get_declaration(self)
+
+ def get_result(self):
+ """
+ Retrieve the result type associated with a function type.
+ """
+ return Type_get_result(self)
+
## CIndex Objects ##
# CIndex objects (derived from ClangObject) are essentially lightweight
@@ -1210,11 +1645,50 @@ Cursor_ref.argtypes = [Cursor]
Cursor_ref.restype = Cursor
Cursor_ref.errcheck = Cursor.from_result
+Cursor_type = lib.clang_getCursorType
+Cursor_type.argtypes = [Cursor]
+Cursor_type.restype = Type
+Cursor_type.errcheck = Type.from_result
+
Cursor_visit_callback = CFUNCTYPE(c_int, Cursor, Cursor, py_object)
Cursor_visit = lib.clang_visitChildren
Cursor_visit.argtypes = [Cursor, Cursor_visit_callback, py_object]
Cursor_visit.restype = c_uint
+# Type Functions
+Type_get_canonical = lib.clang_getCanonicalType
+Type_get_canonical.argtypes = [Type]
+Type_get_canonical.restype = Type
+Type_get_canonical.errcheck = Type.from_result
+
+Type_is_const_qualified = lib.clang_isConstQualifiedType
+Type_is_const_qualified.argtypes = [Type]
+Type_is_const_qualified.restype = bool
+
+Type_is_volatile_qualified = lib.clang_isVolatileQualifiedType
+Type_is_volatile_qualified.argtypes = [Type]
+Type_is_volatile_qualified.restype = bool
+
+Type_is_restrict_qualified = lib.clang_isRestrictQualifiedType
+Type_is_restrict_qualified.argtypes = [Type]
+Type_is_restrict_qualified.restype = bool
+
+Type_get_pointee = lib.clang_getPointeeType
+Type_get_pointee.argtypes = [Type]
+Type_get_pointee.restype = Type
+Type_get_pointee.errcheck = Type.from_result
+
+Type_get_declaration = lib.clang_getTypeDeclaration
+Type_get_declaration.argtypes = [Type]
+Type_get_declaration.restype = Cursor
+Type_get_declaration.errcheck = Cursor.from_result
+
+Type_get_result = lib.clang_getResultType
+Type_get_result.argtypes = [Type]
+Type_get_result.restype = Type
+Type_get_result.errcheck = Type.from_result
+
+
# Index Functions
Index_create = lib.clang_createIndex
Index_create.argtypes = [c_int, c_int]
@@ -1313,6 +1787,6 @@ _clang_getCompletionPriority.restype = c_int
###
-__all__ = ['Index', 'TranslationUnit', 'Cursor', 'CursorKind',
+__all__ = ['Index', 'TranslationUnit', 'Cursor', 'CursorKind', 'Type', 'TypeKind',
'Diagnostic', 'FixIt', 'CodeCompletionResults', 'SourceRange',
'SourceLocation', 'File']
diff --git a/bindings/python/tests/cindex/test_cursor.py b/bindings/python/tests/cindex/test_cursor.py
index a653ba7bf28e..3dde891a9c26 100644
--- a/bindings/python/tests/cindex/test_cursor.py
+++ b/bindings/python/tests/cindex/test_cursor.py
@@ -1,4 +1,4 @@
-from clang.cindex import Index, CursorKind
+from clang.cindex import Index, CursorKind, TypeKind
kInput = """\
// FIXME: Find nicer way to drop builtins and other cruft.
@@ -47,13 +47,17 @@ def test_get_children():
assert len(s0_nodes) == 2
assert s0_nodes[0].kind == CursorKind.FIELD_DECL
assert s0_nodes[0].spelling == 'a'
+ assert s0_nodes[0].type.kind == TypeKind.INT
assert s0_nodes[1].kind == CursorKind.FIELD_DECL
assert s0_nodes[1].spelling == 'b'
+ assert s0_nodes[1].type.kind == TypeKind.INT
assert tu_nodes[1].kind == CursorKind.STRUCT_DECL
assert tu_nodes[1].spelling == 's1'
+ assert tu_nodes[1].displayname == 's1'
assert tu_nodes[1].is_definition() == False
assert tu_nodes[2].kind == CursorKind.FUNCTION_DECL
assert tu_nodes[2].spelling == 'f0'
+ assert tu_nodes[2].displayname == 'f0(int, int)'
assert tu_nodes[2].is_definition() == True
diff --git a/bindings/python/tests/cindex/test_diagnostics.py b/bindings/python/tests/cindex/test_diagnostics.py
index c1ff0e38baad..98f97d3bd3b1 100644
--- a/bindings/python/tests/cindex/test_diagnostics.py
+++ b/bindings/python/tests/cindex/test_diagnostics.py
@@ -36,7 +36,7 @@ def test_diagnostic_fixit():
assert len(tu.diagnostics) == 1
assert tu.diagnostics[0].severity == Diagnostic.Warning
assert tu.diagnostics[0].location.line == 1
- assert tu.diagnostics[0].location.column == 31
+ assert tu.diagnostics[0].location.column == 26
assert tu.diagnostics[0].spelling.startswith('use of GNU old-style')
assert len(tu.diagnostics[0].fixits) == 1
assert tu.diagnostics[0].fixits[0].range.start.line == 1
diff --git a/bindings/python/tests/cindex/test_location.py b/bindings/python/tests/cindex/test_location.py
new file mode 100644
index 000000000000..47c1c6021f55
--- /dev/null
+++ b/bindings/python/tests/cindex/test_location.py
@@ -0,0 +1,50 @@
+from clang.cindex import Index
+
+baseInput="int one;\nint two;\n"
+
+def assert_location(loc, line, column, offset):
+ assert loc.line == line
+ assert loc.column == column
+ assert loc.offset == offset
+
+def test_location():
+ index = Index.create()
+ tu = index.parse('t.c', unsaved_files = [('t.c',baseInput)])
+
+ for n in tu.cursor.get_children():
+ if n.spelling == 'one':
+ assert_location(n.location,line=1,column=5,offset=4)
+ if n.spelling == 'two':
+ assert_location(n.location,line=2,column=5,offset=13)
+
+ # adding a linebreak at top should keep columns same
+ tu = index.parse('t.c', unsaved_files = [('t.c',"\n"+baseInput)])
+
+ for n in tu.cursor.get_children():
+ if n.spelling == 'one':
+ assert_location(n.location,line=2,column=5,offset=5)
+ if n.spelling == 'two':
+ assert_location(n.location,line=3,column=5,offset=14)
+
+ # adding a space should affect column on first line only
+ tu = index.parse('t.c', unsaved_files = [('t.c'," "+baseInput)])
+
+ for n in tu.cursor.get_children():
+ if n.spelling == 'one':
+ assert_location(n.location,line=1,column=6,offset=5)
+ if n.spelling == 'two':
+ assert_location(n.location,line=2,column=5,offset=14)
+
+def test_extent():
+ index = Index.create()
+ tu = index.parse('t.c', unsaved_files = [('t.c',baseInput)])
+
+ for n in tu.cursor.get_children():
+ if n.spelling == 'one':
+ assert_location(n.extent.start,line=1,column=1,offset=0)
+ assert_location(n.extent.end,line=1,column=8,offset=7)
+ assert baseInput[n.extent.start.offset:n.extent.end.offset] == "int one"
+ if n.spelling == 'two':
+ assert_location(n.extent.start,line=2,column=1,offset=9)
+ assert_location(n.extent.end,line=2,column=8,offset=16)
+ assert baseInput[n.extent.start.offset:n.extent.end.offset] == "int two"
diff --git a/bindings/python/tests/cindex/test_type.py b/bindings/python/tests/cindex/test_type.py
new file mode 100644
index 000000000000..cd27a4cbb98d
--- /dev/null
+++ b/bindings/python/tests/cindex/test_type.py
@@ -0,0 +1,76 @@
+from clang.cindex import Index, CursorKind, TypeKind
+
+kInput = """\
+
+typedef int I;
+
+struct teststruct {
+ int a;
+ I b;
+ long c;
+ unsigned long d;
+ signed long e;
+ const int f;
+ int *g;
+ int ***h;
+};
+
+"""
+
+def test_a_struct():
+ index = Index.create()
+ tu = index.parse('t.c', unsaved_files = [('t.c',kInput)])
+
+ for n in tu.cursor.get_children():
+ if n.spelling == 'teststruct':
+ fields = list(n.get_children())
+
+ assert all(x.kind == CursorKind.FIELD_DECL for x in fields)
+
+ assert fields[0].spelling == 'a'
+ assert not fields[0].type.is_const_qualified()
+ assert fields[0].type.kind == TypeKind.INT
+ assert fields[0].type.get_canonical().kind == TypeKind.INT
+
+ assert fields[1].spelling == 'b'
+ assert not fields[1].type.is_const_qualified()
+ assert fields[1].type.kind == TypeKind.TYPEDEF
+ assert fields[1].type.get_canonical().kind == TypeKind.INT
+ assert fields[1].type.get_declaration().spelling == 'I'
+
+ assert fields[2].spelling == 'c'
+ assert not fields[2].type.is_const_qualified()
+ assert fields[2].type.kind == TypeKind.LONG
+ assert fields[2].type.get_canonical().kind == TypeKind.LONG
+
+ assert fields[3].spelling == 'd'
+ assert not fields[3].type.is_const_qualified()
+ assert fields[3].type.kind == TypeKind.ULONG
+ assert fields[3].type.get_canonical().kind == TypeKind.ULONG
+
+ assert fields[4].spelling == 'e'
+ assert not fields[4].type.is_const_qualified()
+ assert fields[4].type.kind == TypeKind.LONG
+ assert fields[4].type.get_canonical().kind == TypeKind.LONG
+
+ assert fields[5].spelling == 'f'
+ assert fields[5].type.is_const_qualified()
+ assert fields[5].type.kind == TypeKind.INT
+ assert fields[5].type.get_canonical().kind == TypeKind.INT
+
+ assert fields[6].spelling == 'g'
+ assert not fields[6].type.is_const_qualified()
+ assert fields[6].type.kind == TypeKind.POINTER
+ assert fields[6].type.get_pointee().kind == TypeKind.INT
+
+ assert fields[7].spelling == 'h'
+ assert not fields[7].type.is_const_qualified()
+ assert fields[7].type.kind == TypeKind.POINTER
+ assert fields[7].type.get_pointee().kind == TypeKind.POINTER
+ assert fields[7].type.get_pointee().get_pointee().kind == TypeKind.POINTER
+ assert fields[7].type.get_pointee().get_pointee().get_pointee().kind == TypeKind.INT
+
+ break
+
+ else:
+ assert False, "Didn't find teststruct??"
diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj
deleted file mode 100644
index 832e07ab44f2..000000000000
--- a/clang.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,2103 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 42;
- objects = {
-
-/* Begin PBXBuildFile section */
- BD6B0EDF13A1824C00B8E3FE /* Mangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BD6B0EDE13A1824C00B8E3FE /* Mangle.cpp */; };
- BD6B0EE213A182A600B8E3FE /* ItaniumMangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BD6B0EE113A182A600B8E3FE /* ItaniumMangle.cpp */; };
- BD6B0EE413A182DA00B8E3FE /* MicrosoftMangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BD6B0EE313A182DA00B8E3FE /* MicrosoftMangle.cpp */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXCopyFilesBuildPhase section */
- 8DD76F690486A84900D96B5E /* CopyFiles */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 8;
- dstPath = /usr/share/man/man1/;
- dstSubfolderSpec = 0;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 1;
- };
-/* End PBXCopyFilesBuildPhase section */
-
-/* Begin PBXFileReference section */
- 035611470DA6A45C00D2EF2A /* DeclBase.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclBase.h; path = clang/AST/DeclBase.h; sourceTree = "<group>"; tabWidth = 2; };
- 03F50AC50D416EAA00B9CF60 /* Targets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Targets.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A15C407118226980092260D /* ASTImporter.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ASTImporter.h; path = clang/AST/ASTImporter.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A15C408118226980092260D /* ASTVector.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ASTVector.h; path = clang/AST/ASTVector.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A15C409118226980092260D /* CharUnits.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CharUnits.h; path = clang/AST/CharUnits.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A15C40A118226980092260D /* DeclAccessPair.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclAccessPair.h; path = clang/AST/DeclAccessPair.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A15C40B118226980092260D /* DeclFriend.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclFriend.h; path = clang/AST/DeclFriend.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A15C40C118226980092260D /* DependentDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DependentDiagnostic.h; path = clang/AST/DependentDiagnostic.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A15C40D118226980092260D /* TemplateBase.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TemplateBase.h; path = clang/AST/TemplateBase.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A15C40E118226980092260D /* UnresolvedSet.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = UnresolvedSet.h; path = clang/AST/UnresolvedSet.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A15C40F118226980092260D /* UsuallyTinyPtrVector.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = UsuallyTinyPtrVector.h; path = clang/AST/UsuallyTinyPtrVector.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A2193CB0F45EEB700C0713D /* ABIInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ABIInfo.h; path = lib/CodeGen/ABIInfo.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A2193CC0F45EEB700C0713D /* Mangle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Mangle.cpp; path = lib/CodeGen/Mangle.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A2193CD0F45EEB700C0713D /* Mangle.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Mangle.h; path = lib/CodeGen/Mangle.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ASTConsumers.cpp; path = lib/Frontend/ASTConsumers.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A2A54A70FD1DD1C00F4CE45 /* CacheTokens.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CacheTokens.cpp; path = lib/Frontend/CacheTokens.cpp; sourceTree = "<group>"; };
- 1A2A54A80FD1DD1C00F4CE45 /* DependencyFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DependencyFile.cpp; path = lib/Frontend/DependencyFile.cpp; sourceTree = "<group>"; };
- 1A2A54A90FD1DD1C00F4CE45 /* DiagChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DiagChecker.cpp; path = lib/Frontend/DiagChecker.cpp; sourceTree = "<group>"; };
- 1A2A54AA0FD1DD1C00F4CE45 /* DocumentXML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DocumentXML.cpp; path = lib/Frontend/DocumentXML.cpp; sourceTree = "<group>"; };
- 1A2A54AE0FD1DD1C00F4CE45 /* PrintPreprocessedOutput.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PrintPreprocessedOutput.cpp; path = lib/Frontend/PrintPreprocessedOutput.cpp; sourceTree = "<group>"; };
- 1A2A54B30FD1DD1C00F4CE45 /* StmtXML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StmtXML.cpp; path = lib/Frontend/StmtXML.cpp; sourceTree = "<group>"; };
- 1A2A54B40FD1DD1C00F4CE45 /* Warnings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Warnings.cpp; path = lib/Frontend/Warnings.cpp; sourceTree = "<group>"; };
- 1A30A9E80B93A4C800201A91 /* ExprCXX.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ExprCXX.h; path = clang/AST/ExprCXX.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A31B27210ACE6DA009E0C8B /* GlobalDecl.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = GlobalDecl.h; path = lib/CodeGen/GlobalDecl.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprConstant.cpp; path = lib/CodeGen/CGExprConstant.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A3D2C4D12A2CD3D0088C44A /* CGCXXABI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXABI.cpp; path = lib/CodeGen/CGCXXABI.cpp; sourceTree = "<group>"; };
- 1A471AB40F437BC500753CE8 /* CGBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBlocks.cpp; path = lib/CodeGen/CGBlocks.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A4C41BE105B4C0B0047B5E7 /* CGClass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGClass.cpp; path = lib/CodeGen/CGClass.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A535EDB107BC47B000C3AE7 /* CanonicalType.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CanonicalType.h; path = clang/AST/CanonicalType.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A5D5E570E5E81010023C059 /* CGCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXX.cpp; path = lib/CodeGen/CGCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A621BB5110FE6AA009E6834 /* TargetInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = TargetInfo.cpp; path = lib/CodeGen/TargetInfo.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A621BB6110FE6AA009E6834 /* TargetInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TargetInfo.h; path = lib/CodeGen/TargetInfo.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A621C3A11111D61009E6834 /* CIndexCodeCompletion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CIndexCodeCompletion.cpp; path = tools/CIndex/CIndexCodeCompletion.cpp; sourceTree = "<group>"; };
- 1A621C3B11111D61009E6834 /* CIndexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CIndexer.cpp; path = tools/CIndex/CIndexer.cpp; sourceTree = "<group>"; };
- 1A621C3C11111D61009E6834 /* CIndexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CIndexer.h; path = tools/CIndex/CIndexer.h; sourceTree = "<group>"; };
- 1A621C3D11111D61009E6834 /* CIndexInclusionStack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CIndexInclusionStack.cpp; path = tools/CIndex/CIndexInclusionStack.cpp; sourceTree = "<group>"; };
- 1A621C3E11111D61009E6834 /* CIndexUSRs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CIndexUSRs.cpp; path = tools/CIndex/CIndexUSRs.cpp; sourceTree = "<group>"; };
- 1A621C3F11111D61009E6834 /* CXCursor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CXCursor.cpp; path = tools/CIndex/CXCursor.cpp; sourceTree = "<group>"; };
- 1A621C4011111D61009E6834 /* CXCursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CXCursor.h; path = tools/CIndex/CXCursor.h; sourceTree = "<group>"; };
- 1A621C4111111D61009E6834 /* CXSourceLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CXSourceLocation.h; path = tools/CIndex/CXSourceLocation.h; sourceTree = "<group>"; };
- 1A649E1D0F9599D9005B965E /* CGBlocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CGBlocks.h; path = lib/CodeGen/CGBlocks.h; sourceTree = "<group>"; };
- 1A649E1E0F9599DA005B965E /* CGCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGCXX.h; path = lib/CodeGen/CGCXX.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A6B6CD110693FC900BB4A8F /* CodeCompleteConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CodeCompleteConsumer.cpp; path = lib/Sema/CodeCompleteConsumer.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaCodeComplete.cpp; path = lib/Sema/SemaCodeComplete.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A6B6E991069833600BB4A8F /* CGExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprCXX.cpp; path = lib/CodeGen/CGExprCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A6C01F6108128710072DEE4 /* CGRTTI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRTTI.cpp; path = lib/CodeGen/CGRTTI.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A6FE7080FD6F85800E00CA9 /* CGTemporaries.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGTemporaries.cpp; path = lib/CodeGen/CGTemporaries.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A7019E90F79BC1100FEC4D1 /* DiagnosticAnalysisKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticAnalysisKinds.td; sourceTree = "<group>"; };
- 1A7019EA0F79BC1100FEC4D1 /* DiagnosticASTKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticASTKinds.td; sourceTree = "<group>"; };
- 1A7019EB0F79BC1100FEC4D1 /* DiagnosticCommonKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticCommonKinds.td; sourceTree = "<group>"; };
- 1A7019EC0F79BC1100FEC4D1 /* DiagnosticDriverKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticDriverKinds.td; sourceTree = "<group>"; };
- 1A7019ED0F79BC1100FEC4D1 /* DiagnosticFrontendKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticFrontendKinds.td; sourceTree = "<group>"; };
- 1A7019EE0F79BC1100FEC4D1 /* DiagnosticLexKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticLexKinds.td; sourceTree = "<group>"; };
- 1A7019EF0F79BC1100FEC4D1 /* DiagnosticParseKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticParseKinds.td; sourceTree = "<group>"; };
- 1A701A250F79CE1C00FEC4D1 /* DiagnosticSemaKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticSemaKinds.td; sourceTree = "<group>"; };
- 1A701B630F7C8FE400FEC4D1 /* SemaAccess.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaAccess.cpp; path = lib/Sema/SemaAccess.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A72BEAC0D641E9400B085E9 /* Attr.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Attr.h; path = clang/AST/Attr.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A7342470C7B57D500122F56 /* CGObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGObjC.cpp; path = lib/CodeGen/CGObjC.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A81AA18108144F40094E50B /* CGVTables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGVTables.cpp; path = lib/CodeGen/CGVTables.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A81AA5D108278A20094E50B /* CGVTables.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGVTables.h; path = lib/CodeGen/CGVTables.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiteralSupport.h; sourceTree = "<group>"; };
- 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LiteralSupport.cpp; sourceTree = "<group>"; };
- 1A97825A1108BA18002B98FC /* CGVTT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGVTT.cpp; path = lib/CodeGen/CGVTT.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A986AB610D0746D00A8EA9E /* CGDeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGDeclCXX.cpp; path = lib/CodeGen/CGDeclCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AA1D35611BECFF70089CC3F /* CC1AsOptions.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CC1AsOptions.td; path = clang/Driver/CC1AsOptions.td; sourceTree = "<group>"; };
- 1AA1D35711BECFF70089CC3F /* CC1Options.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CC1Options.td; path = clang/Driver/CC1Options.td; sourceTree = "<group>"; };
- 1AA1D35811BECFF70089CC3F /* Options.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Options.td; path = clang/Driver/Options.td; sourceTree = "<group>"; };
- 1AA1D35911BECFF70089CC3F /* OptParser.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = OptParser.td; path = clang/Driver/OptParser.td; sourceTree = "<group>"; };
- 1AA963AB10D8576800786C86 /* FullExpr.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = FullExpr.h; path = clang/AST/FullExpr.h; sourceTree = "<group>"; tabWidth = 2; };
- 1AB290021045858B00FE33D8 /* PartialDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = PartialDiagnostic.h; sourceTree = "<group>"; tabWidth = 2; };
- 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = lib/CodeGen/CGBuiltin.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23B11182449800A48E65 /* APValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = APValue.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23B21182449800A48E65 /* ASTConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ASTConsumer.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23B31182449800A48E65 /* ASTContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ASTContext.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23B41182449800A48E65 /* ASTDiagnostic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ASTDiagnostic.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23B51182449800A48E65 /* ASTImporter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ASTImporter.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23B61182449800A48E65 /* AttrImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = AttrImpl.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23B71182449800A48E65 /* CXXInheritance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = CXXInheritance.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23B81182449800A48E65 /* Decl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Decl.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23B91182449800A48E65 /* DeclarationName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclarationName.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23BA1182449800A48E65 /* DeclBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclBase.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23BB1182449800A48E65 /* DeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23BC1182449800A48E65 /* DeclFriend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclFriend.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23BD1182449800A48E65 /* DeclGroup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclGroup.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23BE1182449800A48E65 /* DeclObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclObjC.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23BF1182449800A48E65 /* DeclPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclPrinter.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23C01182449800A48E65 /* DeclTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclTemplate.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23C11182449800A48E65 /* Expr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Expr.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23C21182449800A48E65 /* ExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ExprConstant.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23C31182449800A48E65 /* ExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ExprCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23C41182449800A48E65 /* FullExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = FullExpr.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23C51182449800A48E65 /* InheritViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = InheritViz.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23C61182449800A48E65 /* NestedNameSpecifier.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = NestedNameSpecifier.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23C71182449800A48E65 /* ParentMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ParentMap.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23C81182449800A48E65 /* RecordLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = RecordLayout.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23C91182449800A48E65 /* RecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = RecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23CB1182449800A48E65 /* Stmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Stmt.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23CC1182449800A48E65 /* StmtDumper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = StmtDumper.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23CD1182449800A48E65 /* StmtIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = StmtIterator.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23CE1182449800A48E65 /* StmtPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = StmtPrinter.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23CF1182449800A48E65 /* StmtProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = StmtProfile.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23D01182449800A48E65 /* StmtViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = StmtViz.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23D11182449800A48E65 /* TemplateBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = TemplateBase.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23D21182449800A48E65 /* TemplateName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = TemplateName.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23D31182449800A48E65 /* Type.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Type.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23D41182449800A48E65 /* TypeLoc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = TypeLoc.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23D51182449800A48E65 /* TypePrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = TypePrinter.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A67212999D8E006FBC77 /* AnalysisContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = AnalysisContext.cpp; path = lib/Analysis/AnalysisContext.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A67312999D8E006FBC77 /* CFG.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CFG.cpp; path = lib/Analysis/CFG.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A67412999D8E006FBC77 /* CFGStmtMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CFGStmtMap.cpp; path = lib/Analysis/CFGStmtMap.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A67512999D8E006FBC77 /* FormatString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = FormatString.cpp; path = lib/Analysis/FormatString.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A67612999D8E006FBC77 /* FormatStringParsing.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = FormatStringParsing.h; path = lib/Analysis/FormatStringParsing.h; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A67712999D8E006FBC77 /* LiveVariables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = LiveVariables.cpp; path = lib/Analysis/LiveVariables.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A67812999D8E006FBC77 /* PrintfFormatString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = PrintfFormatString.cpp; path = lib/Analysis/PrintfFormatString.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A67912999D8E006FBC77 /* PseudoConstantAnalysis.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = PseudoConstantAnalysis.cpp; path = lib/Analysis/PseudoConstantAnalysis.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A67A12999D8E006FBC77 /* ReachableCode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ReachableCode.cpp; path = lib/Analysis/ReachableCode.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A67B12999D8E006FBC77 /* ScanfFormatString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ScanfFormatString.cpp; path = lib/Analysis/ScanfFormatString.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A67C12999D8E006FBC77 /* UninitializedValues.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = UninitializedValues.cpp; path = lib/Analysis/UninitializedValues.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A6881299A284006FBC77 /* AdjustedReturnValueChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = AdjustedReturnValueChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A6891299A284006FBC77 /* AggExprVisitor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = AggExprVisitor.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A68A1299A284006FBC77 /* AnalysisConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = AnalysisConsumer.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A68B1299A284006FBC77 /* AnalysisManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = AnalysisManager.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A68C1299A284006FBC77 /* AnalyzerStatsChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = AnalyzerStatsChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A68D1299A284006FBC77 /* ArrayBoundChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayBoundChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A68E1299A284006FBC77 /* AttrNonNullChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = AttrNonNullChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A68F1299A284006FBC77 /* BasicConstraintManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = BasicConstraintManager.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A6901299A284006FBC77 /* BasicObjCFoundationChecks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = BasicObjCFoundationChecks.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A6911299A284006FBC77 /* BasicObjCFoundationChecks.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = BasicObjCFoundationChecks.h; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A6921299A284006FBC77 /* BasicStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = BasicStore.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A6931299A284006FBC77 /* BasicValueFactory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = BasicValueFactory.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A6941299A284006FBC77 /* BugReporter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = BugReporter.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A6951299A284006FBC77 /* BugReporterVisitors.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = BugReporterVisitors.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A6961299A284006FBC77 /* BuiltinFunctionChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = BuiltinFunctionChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A6971299A284006FBC77 /* CallAndMessageChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = CallAndMessageChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A6981299A284006FBC77 /* CastSizeChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = CastSizeChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A6991299A284006FBC77 /* CastToStructChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = CastToStructChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A69A1299A284006FBC77 /* CFRefCount.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = CFRefCount.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A69B1299A284006FBC77 /* CheckDeadStores.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = CheckDeadStores.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A69C1299A284006FBC77 /* Checker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Checker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A69D1299A284006FBC77 /* CheckerHelpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = CheckerHelpers.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A69E1299A284006FBC77 /* CheckObjCDealloc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = CheckObjCDealloc.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A69F1299A284006FBC77 /* CheckObjCInstMethSignature.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = CheckObjCInstMethSignature.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A6A01299A284006FBC77 /* CheckSecuritySyntaxOnly.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = CheckSecuritySyntaxOnly.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A6A11299A284006FBC77 /* CheckSizeofPointer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = CheckSizeofPointer.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A6A21299A284006FBC77 /* ChrootChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ChrootChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A6A41299A284006FBC77 /* CocoaConventions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = CocoaConventions.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A6A51299A284006FBC77 /* CStringChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = CStringChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7DC1299A285006FBC77 /* DereferenceChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DereferenceChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7DD1299A285006FBC77 /* DivZeroChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DivZeroChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7DE1299A285006FBC77 /* Environment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Environment.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7DF1299A285006FBC77 /* ExplodedGraph.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ExplodedGraph.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7E01299A285006FBC77 /* FixedAddressChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = FixedAddressChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7E11299A285006FBC77 /* FlatStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = FlatStore.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7E21299A285006FBC77 /* FrontendActions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = FrontendActions.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7E31299A285006FBC77 /* GRBlockCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = GRBlockCounter.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7E41299A285006FBC77 /* GRCoreEngine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = GRCoreEngine.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7E51299A285006FBC77 /* GRCXXExprEngine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = GRCXXExprEngine.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7E61299A285006FBC77 /* GRExprEngine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = GRExprEngine.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7E71299A285006FBC77 /* GRExprEngineExperimentalChecks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = GRExprEngineExperimentalChecks.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7E81299A285006FBC77 /* GRExprEngineExperimentalChecks.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = GRExprEngineExperimentalChecks.h; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7E91299A285006FBC77 /* GRExprEngineInternalChecks.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = GRExprEngineInternalChecks.h; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7EA1299A285006FBC77 /* GRState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = GRState.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7EB1299A285006FBC77 /* HTMLDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = HTMLDiagnostics.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7EC1299A285006FBC77 /* IdempotentOperationChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = IdempotentOperationChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7ED1299A285006FBC77 /* LLVMConventionsChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = LLVMConventionsChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7EE1299A285006FBC77 /* MacOSXAPIChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = MacOSXAPIChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7F01299A285006FBC77 /* MallocChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = MallocChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7F11299A285006FBC77 /* ManagerRegistry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ManagerRegistry.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7F21299A285006FBC77 /* MemRegion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = MemRegion.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7F31299A285006FBC77 /* NoReturnFunctionChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = NoReturnFunctionChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7F41299A285006FBC77 /* NSAutoreleasePoolChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = NSAutoreleasePoolChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7F51299A285006FBC77 /* NSErrorChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = NSErrorChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7F61299A285006FBC77 /* ObjCAtSyncChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ObjCAtSyncChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7F71299A285006FBC77 /* ObjCUnusedIVarsChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ObjCUnusedIVarsChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7F81299A285006FBC77 /* OSAtomicChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = OSAtomicChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7F91299A285006FBC77 /* PathDiagnostic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = PathDiagnostic.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7FA1299A285006FBC77 /* PlistDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = PlistDiagnostics.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7FB1299A285006FBC77 /* PointerArithChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = PointerArithChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7FC1299A285006FBC77 /* PointerSubChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = PointerSubChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7FD1299A285006FBC77 /* PthreadLockChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = PthreadLockChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A7FE1299A285006FBC77 /* RangeConstraintManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = RangeConstraintManager.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A8001299A285006FBC77 /* RegionStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = RegionStore.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9DB1299A287006FBC77 /* ReturnPointerRangeChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ReturnPointerRangeChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9DC1299A287006FBC77 /* ReturnUndefChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ReturnUndefChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9DD1299A287006FBC77 /* SimpleConstraintManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = SimpleConstraintManager.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9DE1299A287006FBC77 /* SimpleConstraintManager.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = SimpleConstraintManager.h; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9DF1299A287006FBC77 /* SimpleSValuator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = SimpleSValuator.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9E01299A287006FBC77 /* StackAddrLeakChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = StackAddrLeakChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9E11299A287006FBC77 /* Store.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Store.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9E21299A287006FBC77 /* StreamChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = StreamChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9E31299A287006FBC77 /* SVals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = SVals.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9E41299A287006FBC77 /* SValuator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = SValuator.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9E51299A287006FBC77 /* SymbolManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolManager.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9E61299A287006FBC77 /* UndefBranchChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = UndefBranchChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9E71299A287006FBC77 /* UndefCapturedBlockVarChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = UndefCapturedBlockVarChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9E81299A287006FBC77 /* UndefinedArraySubscriptChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = UndefinedArraySubscriptChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9E91299A287006FBC77 /* UndefinedAssignmentChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = UndefinedAssignmentChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9EA1299A287006FBC77 /* UndefResultChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = UndefResultChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9EB1299A287006FBC77 /* UnixAPIChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = UnixAPIChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9EC1299A287006FBC77 /* UnreachableCodeChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = UnreachableCodeChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9ED1299A287006FBC77 /* ValueManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ValueManager.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AC1A9EE1299A287006FBC77 /* VLASizeChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = VLASizeChecker.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ACB57DB1105820D0047B991 /* CompilerInstance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompilerInstance.cpp; path = lib/Frontend/CompilerInstance.cpp; sourceTree = "<group>"; };
- 1ACB57DC1105820D0047B991 /* CompilerInvocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompilerInvocation.cpp; path = lib/Frontend/CompilerInvocation.cpp; sourceTree = "<group>"; };
- 1ACB57DD1105820D0047B991 /* DeclXML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclXML.cpp; path = lib/Frontend/DeclXML.cpp; sourceTree = "<group>"; };
- 1ACB57DE1105820D0047B991 /* FrontendAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FrontendAction.cpp; path = lib/Frontend/FrontendAction.cpp; sourceTree = "<group>"; };
- 1ACB57DF1105820D0047B991 /* FrontendActions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FrontendActions.cpp; path = lib/Frontend/FrontendActions.cpp; sourceTree = "<group>"; };
- 1ACB57E01105820D0047B991 /* FrontendOptions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FrontendOptions.cpp; path = lib/Frontend/FrontendOptions.cpp; sourceTree = "<group>"; };
- 1ACB57E11105820D0047B991 /* LangStandards.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LangStandards.cpp; path = lib/Frontend/LangStandards.cpp; sourceTree = "<group>"; };
- 1ACB57E21105820D0047B991 /* TypeXML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeXML.cpp; path = lib/Frontend/TypeXML.cpp; sourceTree = "<group>"; };
- 1ACB57E31105820D0047B991 /* VerifyDiagnosticsClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VerifyDiagnosticsClient.cpp; path = lib/Frontend/VerifyDiagnosticsClient.cpp; sourceTree = "<group>"; };
- 1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateDecl.cpp; path = lib/Sema/SemaTemplateInstantiateDecl.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AE4EE3B103B89CA00888A23 /* TreeTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TreeTransform.h; path = lib/Sema/TreeTransform.h; sourceTree = "<group>"; tabWidth = 2; };
- 1AECEFAF12DE387800F1D539 /* AnalysisContext.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = AnalysisContext.h; path = clang/Analysis/AnalysisContext.h; sourceTree = "<group>"; tabWidth = 2; };
- 1AECEFB012DE387800F1D539 /* CFG.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CFG.h; path = clang/Analysis/CFG.h; sourceTree = "<group>"; tabWidth = 2; };
- 1AECEFB112DE387800F1D539 /* CFGStmtMap.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CFGStmtMap.h; path = clang/Analysis/CFGStmtMap.h; sourceTree = "<group>"; tabWidth = 2; };
- 1AF1B50E109A4FB800AFAFAC /* CGException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGException.cpp; path = lib/CodeGen/CGException.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AFDD8701161085D00AE030A /* ASTMerge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTMerge.cpp; path = lib/Frontend/ASTMerge.cpp; sourceTree = "<group>"; };
- 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRecordLayoutBuilder.cpp; path = lib/CodeGen/CGRecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 352246E20F5C6BE000D0D279 /* InitHeaderSearch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InitHeaderSearch.cpp; path = lib/Frontend/InitHeaderSearch.cpp; sourceTree = "<group>"; };
- 352246E50F5C6BE000D0D279 /* TextDiagnosticBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TextDiagnosticBuffer.cpp; path = lib/Frontend/TextDiagnosticBuffer.cpp; sourceTree = "<group>"; };
- 352246E60F5C6BE000D0D279 /* TextDiagnosticPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TextDiagnosticPrinter.cpp; path = lib/Frontend/TextDiagnosticPrinter.cpp; sourceTree = "<group>"; };
- 352712500DAFE54700C76352 /* IdentifierResolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = IdentifierResolver.cpp; path = lib/Sema/IdentifierResolver.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 352C19DC0CA321C80045DB98 /* CFGRecStmtDeclVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFGRecStmtDeclVisitor.h; path = clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h; sourceTree = "<group>"; };
- 352C19DD0CA321C80045DB98 /* CFGRecStmtVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFGRecStmtVisitor.h; path = clang/Analysis/Visitors/CFGRecStmtVisitor.h; sourceTree = "<group>"; };
- 352C19DE0CA321C80045DB98 /* CFGStmtVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFGStmtVisitor.h; path = clang/Analysis/Visitors/CFGStmtVisitor.h; sourceTree = "<group>"; };
- 352C19DF0CA321C80045DB98 /* CFGVarDeclVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFGVarDeclVisitor.h; path = clang/Analysis/Visitors/CFGVarDeclVisitor.h; sourceTree = "<group>"; };
- 3534A01C0E129849002709B2 /* ParseCXXInlineMethods.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseCXXInlineMethods.cpp; path = lib/Parse/ParseCXXInlineMethods.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 3536457C0E2406B0009C6509 /* Environment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Environment.h; path = clang/Analysis/PathSensitive/Environment.h; sourceTree = "<group>"; };
- 3537AA0C0ECD088F008F7CDC /* BlkExprDeclBitVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BlkExprDeclBitVector.h; path = clang/Analysis/Support/BlkExprDeclBitVector.h; sourceTree = "<group>"; };
- 3537AA0D0ECD08A4008F7CDC /* PreprocessorLexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PreprocessorLexer.cpp; sourceTree = "<group>"; };
- 3538FDB60ED24A2C005EC283 /* DeclarationName.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclarationName.h; path = clang/AST/DeclarationName.h; sourceTree = "<group>"; tabWidth = 2; };
- 353959D40EE5F88A00E82461 /* ParseTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseTemplate.cpp; path = lib/Parse/ParseTemplate.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 3547129D0C88881300B3E1D5 /* PrettyPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = PrettyPrinter.h; path = clang/AST/PrettyPrinter.h; sourceTree = "<group>"; tabWidth = 2; };
- 35475B1F0E79973F0000BFE4 /* CGCall.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCall.cpp; path = lib/CodeGen/CGCall.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 35475B220E7997680000BFE4 /* CGCall.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGCall.h; path = lib/CodeGen/CGCall.h; sourceTree = "<group>"; tabWidth = 2; };
- 35475B230E7997680000BFE4 /* CGValue.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGValue.h; path = lib/CodeGen/CGValue.h; sourceTree = "<group>"; tabWidth = 2; };
- 355106880E9A851B006A4E44 /* MemRegion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MemRegion.h; path = clang/Analysis/PathSensitive/MemRegion.h; sourceTree = "<group>"; };
- 3551068A0E9A8546006A4E44 /* ParsePragma.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParsePragma.cpp; path = lib/Parse/ParsePragma.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 3551068B0E9A8546006A4E44 /* ParseTentative.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseTentative.cpp; path = lib/Parse/ParseTentative.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 3551068F0E9A857C006A4E44 /* ParsePragma.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ParsePragma.h; path = lib/Parse/ParsePragma.h; sourceTree = "<group>"; tabWidth = 2; };
- 3552E7540E520D80003A8CA5 /* PPCaching.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PPCaching.cpp; sourceTree = "<group>"; };
- 3552E7580E520DD7003A8CA5 /* CGObjCMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGObjCMac.cpp; path = lib/CodeGen/CGObjCMac.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 3553EB9A0E5F7089007D7359 /* GRStateTrait.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRStateTrait.h; path = clang/Analysis/PathSensitive/GRStateTrait.h; sourceTree = "<group>"; };
- 35544B8B0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiate.cpp; path = lib/Sema/SemaTemplateInstantiate.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 35585DBE0EAFBC4500D0A97A /* SemaOverload.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaOverload.cpp; path = lib/Sema/SemaOverload.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 3558F76F0E267C9A00A5B0DF /* Store.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Store.h; path = clang/Analysis/PathSensitive/Store.h; sourceTree = "<group>"; };
- 35707EFD0CD0F5CC000B2204 /* SourceLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = SourceLocation.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 357EA27C0F2526F300439B60 /* SemaLookup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaLookup.cpp; path = lib/Sema/SemaLookup.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 35847BE30CC7DB9000C40FFF /* StmtIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = StmtIterator.h; path = clang/AST/StmtIterator.h; sourceTree = "<group>"; tabWidth = 2; };
- 358D23090E8BEB850003DDCC /* DeclGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclGroup.h; path = clang/AST/DeclGroup.h; sourceTree = "<group>"; tabWidth = 2; };
- 358F514F0E529A87007F2102 /* GRState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRState.h; path = clang/Analysis/PathSensitive/GRState.h; sourceTree = "<group>"; };
- 3591853E0EFB1088000039AF /* SemaTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplate.cpp; path = lib/Sema/SemaTemplate.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 359378FF0DA486490043B19C /* BugReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BugReporter.h; path = clang/Analysis/PathSensitive/BugReporter.h; sourceTree = "<group>"; };
- 3598EBEB0EDE23EF0070CA16 /* PTHManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PTHManager.h; sourceTree = "<group>"; };
- 3599299A0DE2425300A8A33E /* SemaInit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaInit.cpp; path = lib/Sema/SemaInit.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 35A057D20EAE2D2B0069249F /* SVals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SVals.h; path = clang/Analysis/PathSensitive/SVals.h; sourceTree = "<group>"; };
- 35A3E7000DD3874400757F74 /* CGDebugInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGDebugInfo.cpp; path = lib/CodeGen/CGDebugInfo.cpp; sourceTree = "<group>"; tabWidth = 2; wrapsLines = 1; };
- 35A3E7010DD3874400757F74 /* CGDebugInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGDebugInfo.h; path = lib/CodeGen/CGDebugInfo.h; sourceTree = "<group>"; tabWidth = 2; };
- 35A8FCF60D9B4ADD001C2F97 /* ProgramPoint.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ProgramPoint.h; path = clang/Analysis/ProgramPoint.h; sourceTree = "<group>"; tabWidth = 2; };
- 35B820740ECB811A0020BEC0 /* PreprocessorLexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreprocessorLexer.h; sourceTree = "<group>"; };
- 35BFBD2B0C9EDE1E006CB644 /* ASTConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ASTConsumer.h; path = clang/AST/ASTConsumer.h; sourceTree = "<group>"; tabWidth = 2; };
- 35CEA05A0DF9E82700A41296 /* ExprObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ExprObjC.h; path = clang/AST/ExprObjC.h; sourceTree = "<group>"; tabWidth = 2; };
- 35CFFE010CA1CBDD00E6F2BE /* StmtGraphTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = StmtGraphTraits.h; path = clang/AST/StmtGraphTraits.h; sourceTree = "<group>"; tabWidth = 2; };
- 35D1DDD10CA9C6D50096E967 /* DataflowSolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataflowSolver.h; path = clang/Analysis/FlowSensitive/DataflowSolver.h; sourceTree = "<group>"; };
- 35D1DDD20CA9C6D50096E967 /* DataflowValues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataflowValues.h; path = clang/Analysis/FlowSensitive/DataflowValues.h; sourceTree = "<group>"; };
- 35D55B290D81D8E50092E734 /* BasicValueFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BasicValueFactory.h; path = clang/Analysis/PathSensitive/BasicValueFactory.h; sourceTree = "<group>"; };
- 35E194670ECB82FB00F21733 /* SemaCXXScopeSpec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaCXXScopeSpec.cpp; path = lib/Sema/SemaCXXScopeSpec.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 35E194680ECB82FB00F21733 /* SemaCXXCast.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaCXXCast.cpp; path = lib/Sema/SemaCXXCast.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 35E1946C0ECB83C100F21733 /* PTHLexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PTHLexer.cpp; sourceTree = "<group>"; };
- 35EE48AD0E0C4CB200715C54 /* DeclCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclCXX.h; path = clang/AST/DeclCXX.h; sourceTree = "<group>"; tabWidth = 2; };
- 35EE48AE0E0C4CB200715C54 /* ParentMap.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ParentMap.h; path = clang/AST/ParentMap.h; sourceTree = "<group>"; tabWidth = 2; };
- 35EF676F0DAD1D2C00B19414 /* SemaDeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaDeclCXX.cpp; path = lib/Sema/SemaDeclCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 35F1ACE60E66166C001F4532 /* ConstraintManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConstraintManager.h; path = clang/Analysis/PathSensitive/ConstraintManager.h; sourceTree = "<group>"; };
- 35F2BE7B0DAC2963006E7668 /* HTMLRewrite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTMLRewrite.h; path = clang/Rewrite/HTMLRewrite.h; sourceTree = "<group>"; };
- 35F8D0CA0D9B7E8200D91C5E /* GRSimpleAPICheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRSimpleAPICheck.h; path = clang/Analysis/PathSensitive/GRSimpleAPICheck.h; sourceTree = "<group>"; };
- 35F8D0CB0D9B7E8200D91C5E /* GRAuditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRAuditor.h; path = clang/Analysis/PathSensitive/GRAuditor.h; sourceTree = "<group>"; };
- 35F9B1550D1C6B2E00DDFDAE /* LiveVariables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LiveVariables.h; path = clang/Analysis/Analyses/LiveVariables.h; sourceTree = "<group>"; };
- 35F9B1560D1C6B2E00DDFDAE /* UninitializedValues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UninitializedValues.h; path = clang/Analysis/Analyses/UninitializedValues.h; sourceTree = "<group>"; };
- 574F4C25121B4EF000AEAC20 /* ASTWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTWriter.h; path = clang/Serialization/ASTWriter.h; sourceTree = "<group>"; };
- 57AA924D121C8B9400B4AA6C /* ASTReader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTReader.cpp; sourceTree = "<group>"; };
- 57AA924E121C8B9400B4AA6C /* ASTReaderDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTReaderDecl.cpp; sourceTree = "<group>"; };
- 57AA924F121C8B9400B4AA6C /* ASTReaderStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTReaderStmt.cpp; sourceTree = "<group>"; };
- 57E15B21121C8D2B0051C2CC /* ASTDeserializationListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTDeserializationListener.h; path = clang/Serialization/ASTDeserializationListener.h; sourceTree = "<group>"; };
- 57E15B22121C8D2B0051C2CC /* ASTReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTReader.h; path = clang/Serialization/ASTReader.h; sourceTree = "<group>"; };
- 57F6660F121B4DE600DCE3B7 /* ASTWriter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTWriter.cpp; sourceTree = "<group>"; };
- 57F66610121B4DE600DCE3B7 /* ASTWriterDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTWriterDecl.cpp; sourceTree = "<group>"; };
- 57F66611121B4DE600DCE3B7 /* ASTWriterStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTWriterStmt.cpp; sourceTree = "<group>"; };
- 72D16C1E0D9975C400E6DA4A /* HTMLRewrite.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HTMLRewrite.cpp; path = lib/Rewrite/HTMLRewrite.cpp; sourceTree = "<group>"; };
- 84AF36A00CB17A3B00C820A5 /* DeclObjC.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclObjC.h; path = clang/AST/DeclObjC.h; sourceTree = "<group>"; tabWidth = 2; };
- 8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = clang; sourceTree = BUILT_PRODUCTS_DIR; };
- 9012911510470FCE0083456D /* Index.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Index.h; path = "clang-c/Index.h"; sourceTree = "<group>"; };
- 9012911C1048068D0083456D /* ASTUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTUnit.cpp; path = lib/Frontend/ASTUnit.cpp; sourceTree = "<group>"; };
- 9012911F104812F90083456D /* CIndex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CIndex.cpp; path = tools/CIndex/CIndex.cpp; sourceTree = "<group>"; };
- 904753791096376F00CBDDDD /* CXXInheritance.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CXXInheritance.h; path = clang/AST/CXXInheritance.h; sourceTree = "<group>"; tabWidth = 2; };
- 9047537A1096376F00CBDDDD /* Redeclarable.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Redeclarable.h; path = clang/AST/Redeclarable.h; sourceTree = "<group>"; tabWidth = 2; };
- 9047537B1096376F00CBDDDD /* TypeLoc.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TypeLoc.h; path = clang/AST/TypeLoc.h; sourceTree = "<group>"; tabWidth = 2; };
- 9047537C1096376F00CBDDDD /* TypeLocBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TypeLocBuilder.h; path = clang/AST/TypeLocBuilder.h; sourceTree = "<group>"; tabWidth = 2; };
- 9047537D1096376F00CBDDDD /* TypeLocNodes.def */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text; name = TypeLocNodes.def; path = clang/AST/TypeLocNodes.def; sourceTree = "<group>"; tabWidth = 2; };
- 9047537E1096376F00CBDDDD /* TypeLocVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TypeLocVisitor.h; path = clang/AST/TypeLocVisitor.h; sourceTree = "<group>"; tabWidth = 2; };
- 9047537F1096376F00CBDDDD /* TypeVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TypeVisitor.h; path = clang/AST/TypeVisitor.h; sourceTree = "<group>"; tabWidth = 2; };
- 9063F2280F9E911F002F7251 /* OnDiskHashTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OnDiskHashTable.h; sourceTree = "<group>"; };
- 9063F2290F9E911F002F7251 /* SourceManagerInternals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SourceManagerInternals.h; sourceTree = "<group>"; };
- 9063F22A0F9E911F002F7251 /* TemplateKinds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TemplateKinds.h; sourceTree = "<group>"; };
- 906BF4AE0F83BA16001071FA /* ConvertUTF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConvertUTF.h; sourceTree = "<group>"; };
- 906BF4AF0F83BA2E001071FA /* ConvertUTF.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ConvertUTF.c; sourceTree = "<group>"; };
- 90F9EFA9104ABDED00D09A15 /* c-index-test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "c-index-test.c"; path = "tools/c-index-test/c-index-test.c"; sourceTree = "<group>"; };
- 90FB99DE0F98FB1D008F9415 /* DeclContextInternals.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclContextInternals.h; path = clang/AST/DeclContextInternals.h; sourceTree = "<group>"; tabWidth = 2; };
- 90FB99DF0F98FB1D008F9415 /* DeclVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclVisitor.h; path = clang/AST/DeclVisitor.h; sourceTree = "<group>"; tabWidth = 2; };
- 90FB99E00F98FB1D008F9415 /* ExternalASTSource.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ExternalASTSource.h; path = clang/AST/ExternalASTSource.h; sourceTree = "<group>"; tabWidth = 2; };
- 90FD6D5F103C3D21005F5B73 /* Analyzer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Analyzer.h; path = clang/Index/Analyzer.h; sourceTree = "<group>"; };
- 90FD6D60103C3D21005F5B73 /* ASTLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTLocation.h; path = clang/Index/ASTLocation.h; sourceTree = "<group>"; };
- 90FD6D61103C3D21005F5B73 /* DeclReferenceMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclReferenceMap.h; path = clang/Index/DeclReferenceMap.h; sourceTree = "<group>"; };
- 90FD6D62103C3D21005F5B73 /* Entity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Entity.h; path = clang/Index/Entity.h; sourceTree = "<group>"; };
- 90FD6D63103C3D21005F5B73 /* GlobalSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GlobalSelector.h; path = clang/Index/GlobalSelector.h; sourceTree = "<group>"; };
- 90FD6D64103C3D21005F5B73 /* Handlers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Handlers.h; path = clang/Index/Handlers.h; sourceTree = "<group>"; };
- 90FD6D65103C3D21005F5B73 /* Indexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Indexer.h; path = clang/Index/Indexer.h; sourceTree = "<group>"; };
- 90FD6D66103C3D21005F5B73 /* IndexProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IndexProvider.h; path = clang/Index/IndexProvider.h; sourceTree = "<group>"; };
- 90FD6D67103C3D21005F5B73 /* Program.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Program.h; path = clang/Index/Program.h; sourceTree = "<group>"; };
- 90FD6D68103C3D21005F5B73 /* SelectorMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SelectorMap.h; path = clang/Index/SelectorMap.h; sourceTree = "<group>"; };
- 90FD6D69103C3D21005F5B73 /* STLExtras.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STLExtras.h; path = clang/Index/STLExtras.h; sourceTree = "<group>"; };
- 90FD6D6A103C3D21005F5B73 /* TranslationUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TranslationUnit.h; path = clang/Index/TranslationUnit.h; sourceTree = "<group>"; };
- 90FD6D6B103C3D21005F5B73 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = clang/Index/Utils.h; sourceTree = "<group>"; };
- 90FD6D6D103C3D49005F5B73 /* Analyzer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Analyzer.cpp; path = lib/Index/Analyzer.cpp; sourceTree = "<group>"; };
- 90FD6D6E103C3D49005F5B73 /* ASTLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTLocation.cpp; path = lib/Index/ASTLocation.cpp; sourceTree = "<group>"; };
- 90FD6D6F103C3D49005F5B73 /* ASTVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTVisitor.h; path = lib/Index/ASTVisitor.h; sourceTree = "<group>"; };
- 90FD6D70103C3D49005F5B73 /* DeclReferenceMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclReferenceMap.cpp; path = lib/Index/DeclReferenceMap.cpp; sourceTree = "<group>"; };
- 90FD6D71103C3D49005F5B73 /* Entity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Entity.cpp; path = lib/Index/Entity.cpp; sourceTree = "<group>"; };
- 90FD6D72103C3D49005F5B73 /* EntityImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EntityImpl.h; path = lib/Index/EntityImpl.h; sourceTree = "<group>"; };
- 90FD6D73103C3D49005F5B73 /* GlobalSelector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GlobalSelector.cpp; path = lib/Index/GlobalSelector.cpp; sourceTree = "<group>"; };
- 90FD6D74103C3D49005F5B73 /* Handlers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Handlers.cpp; path = lib/Index/Handlers.cpp; sourceTree = "<group>"; };
- 90FD6D75103C3D49005F5B73 /* Indexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Indexer.cpp; path = lib/Index/Indexer.cpp; sourceTree = "<group>"; };
- 90FD6D76103C3D49005F5B73 /* IndexProvider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IndexProvider.cpp; path = lib/Index/IndexProvider.cpp; sourceTree = "<group>"; };
- 90FD6D77103C3D49005F5B73 /* Program.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Program.cpp; path = lib/Index/Program.cpp; sourceTree = "<group>"; };
- 90FD6D78103C3D49005F5B73 /* ProgramImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProgramImpl.h; path = lib/Index/ProgramImpl.h; sourceTree = "<group>"; };
- 90FD6D7A103C3D49005F5B73 /* SelectorMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SelectorMap.cpp; path = lib/Index/SelectorMap.cpp; sourceTree = "<group>"; };
- 90FD6D86103C3D80005F5B73 /* Analyses.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Analyses.def; path = clang/Frontend/Analyses.def; sourceTree = "<group>"; };
- 90FD6D88103C3D80005F5B73 /* ASTConsumers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTConsumers.h; path = clang/Frontend/ASTConsumers.h; sourceTree = "<group>"; };
- 90FD6D89103C3D80005F5B73 /* ASTUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTUnit.h; path = clang/Frontend/ASTUnit.h; sourceTree = "<group>"; };
- 90FD6D8A103C3D80005F5B73 /* CommandLineSourceLoc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandLineSourceLoc.h; path = clang/Frontend/CommandLineSourceLoc.h; sourceTree = "<group>"; };
- 90FD6D8B103C3D80005F5B73 /* DeclContextXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = DeclContextXML.def; path = clang/Frontend/DeclContextXML.def; sourceTree = "<group>"; };
- 90FD6D8C103C3D80005F5B73 /* DeclXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = DeclXML.def; path = clang/Frontend/DeclXML.def; sourceTree = "<group>"; };
- 90FD6D8D103C3D80005F5B73 /* DocumentXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = DocumentXML.def; path = clang/Frontend/DocumentXML.def; sourceTree = "<group>"; };
- 90FD6D8E103C3D80005F5B73 /* DocumentXML.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DocumentXML.h; path = clang/Frontend/DocumentXML.h; sourceTree = "<group>"; };
- 90FD6D8F103C3D80005F5B73 /* StmtXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = StmtXML.def; path = clang/Frontend/StmtXML.def; sourceTree = "<group>"; };
- 90FD6D90103C3D80005F5B73 /* TypeXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = TypeXML.def; path = clang/Frontend/TypeXML.def; sourceTree = "<group>"; };
- 90FD6D91103C3D80005F5B73 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = clang/Frontend/Utils.h; sourceTree = "<group>"; };
- 90FD6DB5103D977E005F5B73 /* index-test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "index-test.cpp"; path = "tools/index-test/index-test.cpp"; sourceTree = "<group>"; };
- BB20603B131EDDBF003C3343 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
- BB20603C131EDDBF003C3343 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
- BB206041131EDDDA003C3343 /* ARRMT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARRMT.h; sourceTree = "<group>"; };
- BB206043131EDE03003C3343 /* arrmt-test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "arrmt-test.cpp"; sourceTree = "<group>"; };
- BB206044131EDE03003C3343 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
- BB206045131EDE03003C3343 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
- BB5C372812A5057500259F53 /* DumpXML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DumpXML.cpp; path = /Volumes/Data/llvm/tools/clang/lib/AST/DumpXML.cpp; sourceTree = "<absolute>"; };
- BBA5AB141309C2FA000B38F1 /* AdjustedReturnValueChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AdjustedReturnValueChecker.cpp; sourceTree = "<group>"; };
- BBA5AB151309C2FA000B38F1 /* AnalyzerStatsChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AnalyzerStatsChecker.cpp; sourceTree = "<group>"; };
- BBA5AB161309C2FA000B38F1 /* ArrayBoundChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayBoundChecker.cpp; sourceTree = "<group>"; };
- BBA5AB171309C2FA000B38F1 /* ArrayBoundCheckerV2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayBoundCheckerV2.cpp; sourceTree = "<group>"; };
- BBA5AB181309C2FA000B38F1 /* AttrNonNullChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AttrNonNullChecker.cpp; sourceTree = "<group>"; };
- BBA5AB191309C2FA000B38F1 /* BasicObjCFoundationChecks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BasicObjCFoundationChecks.cpp; sourceTree = "<group>"; };
- BBA5AB1A1309C2FA000B38F1 /* BasicObjCFoundationChecks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BasicObjCFoundationChecks.h; sourceTree = "<group>"; };
- BBA5AB1B1309C2FA000B38F1 /* BuiltinFunctionChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BuiltinFunctionChecker.cpp; sourceTree = "<group>"; };
- BBA5AB1C1309C2FA000B38F1 /* CallAndMessageChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallAndMessageChecker.cpp; sourceTree = "<group>"; };
- BBA5AB1D1309C2FA000B38F1 /* CastSizeChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CastSizeChecker.cpp; sourceTree = "<group>"; };
- BBA5AB1E1309C2FA000B38F1 /* CastToStructChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CastToStructChecker.cpp; sourceTree = "<group>"; };
- BBA5AB1F1309C2FA000B38F1 /* Checkers.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Checkers.td; sourceTree = "<group>"; };
- BBA5AB201309C2FA000B38F1 /* CheckObjCDealloc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CheckObjCDealloc.cpp; sourceTree = "<group>"; };
- BBA5AB211309C2FA000B38F1 /* CheckObjCInstMethSignature.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CheckObjCInstMethSignature.cpp; sourceTree = "<group>"; };
- BBA5AB221309C2FA000B38F1 /* CheckSecuritySyntaxOnly.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CheckSecuritySyntaxOnly.cpp; sourceTree = "<group>"; };
- BBA5AB231309C2FA000B38F1 /* CheckSizeofPointer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CheckSizeofPointer.cpp; sourceTree = "<group>"; };
- BBA5AB241309C2FA000B38F1 /* ChrootChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ChrootChecker.cpp; sourceTree = "<group>"; };
- BBA5AB251309C2FA000B38F1 /* ClangSACheckerProvider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClangSACheckerProvider.cpp; sourceTree = "<group>"; };
- BBA5AB261309C2FA000B38F1 /* ClangSACheckerProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClangSACheckerProvider.h; sourceTree = "<group>"; };
- BBA5AB271309C2FA000B38F1 /* ClangSACheckers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClangSACheckers.h; sourceTree = "<group>"; };
- BBA5AB291309C2FA000B38F1 /* CStringChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CStringChecker.cpp; sourceTree = "<group>"; };
- BBA5AB2A1309C2FA000B38F1 /* DeadStoresChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeadStoresChecker.cpp; sourceTree = "<group>"; };
- BBA5AB2B1309C2FA000B38F1 /* DereferenceChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DereferenceChecker.cpp; sourceTree = "<group>"; };
- BBA5AB2C1309C2FA000B38F1 /* DivZeroChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DivZeroChecker.cpp; sourceTree = "<group>"; };
- BBA5AB2D1309C2FA000B38F1 /* ExperimentalChecks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExperimentalChecks.cpp; sourceTree = "<group>"; };
- BBA5AB2E1309C2FA000B38F1 /* ExperimentalChecks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExperimentalChecks.h; sourceTree = "<group>"; };
- BBA5AB2F1309C2FA000B38F1 /* ExprEngine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExprEngine.cpp; sourceTree = "<group>"; };
- BBA5AB301309C2FA000B38F1 /* FixedAddressChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FixedAddressChecker.cpp; sourceTree = "<group>"; };
- BBA5AB311309C2FA000B38F1 /* IdempotentOperationChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IdempotentOperationChecker.cpp; sourceTree = "<group>"; };
- BBA5AB321309C2FA000B38F1 /* InternalChecks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InternalChecks.h; sourceTree = "<group>"; };
- BBA5AB331309C2FA000B38F1 /* LLVMConventionsChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LLVMConventionsChecker.cpp; sourceTree = "<group>"; };
- BBA5AB341309C2FA000B38F1 /* MacOSXAPIChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MacOSXAPIChecker.cpp; sourceTree = "<group>"; };
- BBA5AB361309C2FA000B38F1 /* MallocChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MallocChecker.cpp; sourceTree = "<group>"; };
- BBA5AB371309C2FA000B38F1 /* NoReturnFunctionChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NoReturnFunctionChecker.cpp; sourceTree = "<group>"; };
- BBA5AB381309C2FA000B38F1 /* NSAutoreleasePoolChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NSAutoreleasePoolChecker.cpp; sourceTree = "<group>"; };
- BBA5AB3A1309C2FA000B38F1 /* NSErrorChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NSErrorChecker.cpp; sourceTree = "<group>"; };
- BBA5AB3B1309C2FA000B38F1 /* ObjCAtSyncChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjCAtSyncChecker.cpp; sourceTree = "<group>"; };
- BBA5AB3D1309C2FA000B38F1 /* ObjCSelfInitChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjCSelfInitChecker.cpp; sourceTree = "<group>"; };
- BBA5AB3F1309C2FA000B38F1 /* ObjCUnusedIVarsChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjCUnusedIVarsChecker.cpp; sourceTree = "<group>"; };
- BBA5AB401309C2FA000B38F1 /* OSAtomicChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OSAtomicChecker.cpp; sourceTree = "<group>"; };
- BBA5AB411309C2FA000B38F1 /* PointerArithChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PointerArithChecker.cpp; sourceTree = "<group>"; };
- BBA5AB421309C2FA000B38F1 /* PointerSubChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PointerSubChecker.cpp; sourceTree = "<group>"; };
- BBA5AB431309C2FA000B38F1 /* PthreadLockChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PthreadLockChecker.cpp; sourceTree = "<group>"; };
- BBA5AB441309C2FA000B38F1 /* ReturnPointerRangeChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReturnPointerRangeChecker.cpp; sourceTree = "<group>"; };
- BBA5AB451309C2FA000B38F1 /* ReturnUndefChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReturnUndefChecker.cpp; sourceTree = "<group>"; };
- BBA5AB461309C2FA000B38F1 /* StackAddrLeakChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StackAddrLeakChecker.cpp; sourceTree = "<group>"; };
- BBA5AB471309C2FA000B38F1 /* StreamChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StreamChecker.cpp; sourceTree = "<group>"; };
- BBA5AB481309C2FA000B38F1 /* UndefBranchChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UndefBranchChecker.cpp; sourceTree = "<group>"; };
- BBA5AB491309C2FA000B38F1 /* UndefCapturedBlockVarChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UndefCapturedBlockVarChecker.cpp; sourceTree = "<group>"; };
- BBA5AB4A1309C2FA000B38F1 /* UndefinedArraySubscriptChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UndefinedArraySubscriptChecker.cpp; sourceTree = "<group>"; };
- BBA5AB4B1309C2FA000B38F1 /* UndefinedAssignmentChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UndefinedAssignmentChecker.cpp; sourceTree = "<group>"; };
- BBA5AB4C1309C2FA000B38F1 /* UndefResultChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UndefResultChecker.cpp; sourceTree = "<group>"; };
- BBA5AB4D1309C2FA000B38F1 /* UnixAPIChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnixAPIChecker.cpp; sourceTree = "<group>"; };
- BBA5AB4E1309C2FA000B38F1 /* UnreachableCodeChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnreachableCodeChecker.cpp; sourceTree = "<group>"; };
- BBA5AB4F1309C2FA000B38F1 /* VLASizeChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VLASizeChecker.cpp; sourceTree = "<group>"; };
- BBA5AB521309C2FA000B38F1 /* AggExprVisitor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AggExprVisitor.cpp; sourceTree = "<group>"; };
- BBA5AB531309C2FA000B38F1 /* AnalysisManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AnalysisManager.cpp; sourceTree = "<group>"; };
- BBA5AB541309C2FA000B38F1 /* BasicConstraintManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BasicConstraintManager.cpp; sourceTree = "<group>"; };
- BBA5AB551309C2FA000B38F1 /* BasicStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BasicStore.cpp; sourceTree = "<group>"; };
- BBA5AB561309C2FA000B38F1 /* BasicValueFactory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BasicValueFactory.cpp; sourceTree = "<group>"; };
- BBA5AB571309C2FA000B38F1 /* BlockCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BlockCounter.cpp; sourceTree = "<group>"; };
- BBA5AB581309C2FA000B38F1 /* BugReporter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BugReporter.cpp; sourceTree = "<group>"; };
- BBA5AB591309C2FA000B38F1 /* BugReporterVisitors.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BugReporterVisitors.cpp; sourceTree = "<group>"; };
- BBA5AB5A1309C2FA000B38F1 /* CFRefCount.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CFRefCount.cpp; sourceTree = "<group>"; };
- BBA5AB5B1309C2FA000B38F1 /* Checker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Checker.cpp; sourceTree = "<group>"; };
- BBA5AB5C1309C2FA000B38F1 /* CheckerHelpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CheckerHelpers.cpp; sourceTree = "<group>"; };
- BBA5AB5D1309C2FA000B38F1 /* CheckerManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CheckerManager.cpp; sourceTree = "<group>"; };
- BBA5AB5F1309C2FA000B38F1 /* CoreEngine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CoreEngine.cpp; sourceTree = "<group>"; };
- BBA5AB601309C2FA000B38F1 /* CXXExprEngine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CXXExprEngine.cpp; sourceTree = "<group>"; };
- BBA5AB611309C2FA000B38F1 /* Environment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Environment.cpp; sourceTree = "<group>"; };
- BBA5AB621309C2FA000B38F1 /* ExplodedGraph.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExplodedGraph.cpp; sourceTree = "<group>"; };
- BBA5AB631309C2FA000B38F1 /* FlatStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FlatStore.cpp; sourceTree = "<group>"; };
- BBA5AB641309C2FA000B38F1 /* GRState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GRState.cpp; sourceTree = "<group>"; };
- BBA5AB651309C2FA000B38F1 /* HTMLDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTMLDiagnostics.cpp; sourceTree = "<group>"; };
- BBA5AB671309C2FA000B38F1 /* MemRegion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MemRegion.cpp; sourceTree = "<group>"; };
- BBA5AB681309C2FA000B38F1 /* ObjCMessage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjCMessage.cpp; sourceTree = "<group>"; };
- BBA5AB691309C2FA000B38F1 /* PathDiagnostic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PathDiagnostic.cpp; sourceTree = "<group>"; };
- BBA5AB6A1309C2FA000B38F1 /* PlistDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlistDiagnostics.cpp; sourceTree = "<group>"; };
- BBA5AB6B1309C2FA000B38F1 /* RangeConstraintManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RangeConstraintManager.cpp; sourceTree = "<group>"; };
- BBA5AB6C1309C2FA000B38F1 /* RegionStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegionStore.cpp; sourceTree = "<group>"; };
- BBA5AB6D1309C2FA000B38F1 /* SimpleConstraintManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SimpleConstraintManager.cpp; sourceTree = "<group>"; };
- BBA5AB6E1309C2FA000B38F1 /* SimpleConstraintManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleConstraintManager.h; sourceTree = "<group>"; };
- BBA5AB6F1309C2FA000B38F1 /* SimpleSValBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SimpleSValBuilder.cpp; sourceTree = "<group>"; };
- BBA5AB701309C2FA000B38F1 /* Store.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Store.cpp; sourceTree = "<group>"; };
- BBA5AB711309C2FA000B38F1 /* SValBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SValBuilder.cpp; sourceTree = "<group>"; };
- BBA5AB721309C2FA000B38F1 /* SVals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVals.cpp; sourceTree = "<group>"; };
- BBA5AB731309C2FA000B38F1 /* SymbolManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolManager.cpp; sourceTree = "<group>"; };
- BBA5AB741309C2FA000B38F1 /* TextPathDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextPathDiagnostics.cpp; sourceTree = "<group>"; };
- BBA5AB761309C2FA000B38F1 /* AnalysisConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AnalysisConsumer.cpp; sourceTree = "<group>"; };
- BBA5AB771309C2FA000B38F1 /* AnalysisConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnalysisConsumer.h; sourceTree = "<group>"; };
- BBA5AB781309C2FA000B38F1 /* CheckerRegistration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CheckerRegistration.cpp; sourceTree = "<group>"; };
- BBA5AB7A1309C2FA000B38F1 /* FrontendActions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FrontendActions.cpp; sourceTree = "<group>"; };
- BD59A948121496B9003A5A02 /* AnalysisBasedWarnings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AnalysisBasedWarnings.h; path = clang/Sema/AnalysisBasedWarnings.h; sourceTree = "<group>"; };
- BD59A949121496B9003A5A02 /* CodeCompleteConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CodeCompleteConsumer.h; path = clang/Sema/CodeCompleteConsumer.h; sourceTree = "<group>"; };
- BD59A94A121496B9003A5A02 /* CXXFieldCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CXXFieldCollector.h; path = clang/Sema/CXXFieldCollector.h; sourceTree = "<group>"; };
- BD59A94B121496B9003A5A02 /* ExternalSemaSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExternalSemaSource.h; path = clang/Sema/ExternalSemaSource.h; sourceTree = "<group>"; };
- BD59A94C121496B9003A5A02 /* IdentifierResolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IdentifierResolver.h; path = clang/Sema/IdentifierResolver.h; sourceTree = "<group>"; };
- BD59A94D121496B9003A5A02 /* Initialization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Initialization.h; path = clang/Sema/Initialization.h; sourceTree = "<group>"; };
- BD59A94E121496B9003A5A02 /* Lookup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Lookup.h; path = clang/Sema/Lookup.h; sourceTree = "<group>"; };
- BD59A94F121496B9003A5A02 /* Overload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Overload.h; path = clang/Sema/Overload.h; sourceTree = "<group>"; };
- BD59A951121496B9003A5A02 /* Sema.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Sema.h; path = clang/Sema/Sema.h; sourceTree = "<group>"; };
- BD59A952121496B9003A5A02 /* SemaConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaConsumer.h; path = clang/Sema/SemaConsumer.h; sourceTree = "<group>"; };
- BD59A953121496B9003A5A02 /* SemaDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaDiagnostic.h; path = clang/Sema/SemaDiagnostic.h; sourceTree = "<group>"; };
- BD59A954121496B9003A5A02 /* Template.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Template.h; path = clang/Sema/Template.h; sourceTree = "<group>"; };
- BD6B0EDE13A1824C00B8E3FE /* Mangle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mangle.cpp; sourceTree = "<group>"; };
- BD6B0EE113A182A600B8E3FE /* ItaniumMangle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ItaniumMangle.cpp; sourceTree = "<group>"; };
- BD6B0EE313A182DA00B8E3FE /* MicrosoftMangle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MicrosoftMangle.cpp; sourceTree = "<group>"; };
- BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateDeduction.cpp; path = lib/Sema/SemaTemplateDeduction.cpp; sourceTree = "<group>"; tabWidth = 2; };
- BF89C3E111595818001C2D68 /* AnalysisBasedWarnings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AnalysisBasedWarnings.cpp; path = lib/Sema/AnalysisBasedWarnings.cpp; sourceTree = "<group>"; };
- BF89C3E5115958A1001C2D68 /* TargetAttributesSema.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TargetAttributesSema.h; path = lib/Sema/TargetAttributesSema.h; sourceTree = "<group>"; };
- BF89C3E81159594A001C2D68 /* SemaObjCProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaObjCProperty.cpp; path = lib/Sema/SemaObjCProperty.cpp; sourceTree = "<group>"; };
- BF89C3F811595A01001C2D68 /* SemaType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaType.cpp; path = lib/Sema/SemaType.cpp; sourceTree = "<group>"; };
- BF89C3FA11595A37001C2D68 /* SemaCodeComplete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaCodeComplete.cpp; path = lib/Sema/SemaCodeComplete.cpp; sourceTree = "<group>"; };
- BF89C3FC11595A5D001C2D68 /* SemaExceptionSpec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaExceptionSpec.cpp; path = lib/Sema/SemaExceptionSpec.cpp; sourceTree = "<group>"; };
- BF9FED6E1225DF55003A8B71 /* TemplateDeduction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TemplateDeduction.h; path = clang/Sema/TemplateDeduction.h; sourceTree = "<group>"; };
- BF9FED6F1225DF7F003A8B71 /* Action.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Action.h; path = clang/Sema/Action.h; sourceTree = "<group>"; };
- BF9FED701225DFA1003A8B71 /* AttributeList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AttributeList.h; path = clang/Sema/AttributeList.h; sourceTree = "<group>"; };
- BF9FED711225DFD9003A8B71 /* DeclSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclSpec.h; path = clang/Sema/DeclSpec.h; sourceTree = "<group>"; };
- BF9FED721225DFD9003A8B71 /* Designator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Designator.h; path = clang/Sema/Designator.h; sourceTree = "<group>"; };
- BF9FED731225E005003A8B71 /* Ownership.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Ownership.h; path = clang/Sema/Ownership.h; sourceTree = "<group>"; };
- BF9FED741225E005003A8B71 /* ParsedTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ParsedTemplate.h; path = clang/Sema/ParsedTemplate.h; sourceTree = "<group>"; };
- BF9FED751225E005003A8B71 /* Scope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Scope.h; path = clang/Sema/Scope.h; sourceTree = "<group>"; };
- BF9FED761225E005003A8B71 /* ScopeInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScopeInfo.h; path = clang/Sema/ScopeInfo.h; sourceTree = "<group>"; };
- BF9FED771225E032003A8B71 /* ObjCMethodList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ObjCMethodList.h; path = clang/Sema/ObjCMethodList.h; sourceTree = "<group>"; };
- BF9FED781225E041003A8B71 /* SemaInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaInternal.h; path = clang/Sema/SemaInternal.h; sourceTree = "<group>"; };
- BF9FEDB21225E1D2003A8B71 /* CodeCompletionHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeCompletionHandler.h; sourceTree = "<group>"; };
- BF9FEDB31225E1E1003A8B71 /* ExternalPreprocessorSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExternalPreprocessorSource.h; sourceTree = "<group>"; };
- BF9FEDB41225E1F3003A8B71 /* PreprocessingRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreprocessingRecord.h; sourceTree = "<group>"; };
- BF9FEDB51225E213003A8B71 /* ParseAST.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ParseAST.h; path = clang/Parse/ParseAST.h; sourceTree = "<group>"; };
- BF9FEDB61225E252003A8B71 /* OperationKinds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OperationKinds.h; path = clang/AST/OperationKinds.h; sourceTree = "<group>"; };
- BF9FEDB71225E26A003A8B71 /* RecursiveASTVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RecursiveASTVisitor.h; path = clang/AST/RecursiveASTVisitor.h; sourceTree = "<group>"; };
- BF9FEDB81225E2DE003A8B71 /* BackendUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BackendUtil.h; path = clang/CodeGen/BackendUtil.h; sourceTree = "<group>"; };
- BF9FEDB91225E2DE003A8B71 /* CodeGenAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CodeGenAction.h; path = clang/CodeGen/CodeGenAction.h; sourceTree = "<group>"; };
- BF9FEDBA1225E30E003A8B71 /* ASTBitCodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTBitCodes.h; path = clang/Serialization/ASTBitCodes.h; sourceTree = "<group>"; };
- BF9FEDBB1225E34B003A8B71 /* FixItRewriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FixItRewriter.h; path = clang/Rewrite/FixItRewriter.h; sourceTree = "<group>"; };
- BF9FEDBC1225E34B003A8B71 /* FrontendActions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FrontendActions.h; path = clang/Rewrite/FrontendActions.h; sourceTree = "<group>"; };
- BF9FEDBD1225E35F003A8B71 /* Rewriters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Rewriters.h; path = clang/Rewrite/Rewriters.h; sourceTree = "<group>"; };
- BF9FEDBE1225E373003A8B71 /* ASTConsumers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTConsumers.h; path = clang/Rewrite/ASTConsumers.h; sourceTree = "<group>"; };
- BF9FEDBF1225E392003A8B71 /* AnalyzerOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AnalyzerOptions.h; path = clang/Frontend/AnalyzerOptions.h; sourceTree = "<group>"; };
- BF9FEDC01225E3AB003A8B71 /* ChainedDiagnosticClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ChainedDiagnosticClient.h; path = clang/Frontend/ChainedDiagnosticClient.h; sourceTree = "<group>"; };
- BF9FEDC11225E3AB003A8B71 /* CodeGenOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CodeGenOptions.h; path = clang/Frontend/CodeGenOptions.h; sourceTree = "<group>"; };
- BF9FEDC21225E3C2003A8B71 /* CompilerInstance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CompilerInstance.h; path = clang/Frontend/CompilerInstance.h; sourceTree = "<group>"; };
- BF9FEDC31225E3C2003A8B71 /* CompilerInvocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CompilerInvocation.h; path = clang/Frontend/CompilerInvocation.h; sourceTree = "<group>"; };
- BF9FEDC41225E3DA003A8B71 /* DependencyOutputOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DependencyOutputOptions.h; path = clang/Frontend/DependencyOutputOptions.h; sourceTree = "<group>"; };
- BF9FEDC51225E3DA003A8B71 /* DiagnosticOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DiagnosticOptions.h; path = clang/Frontend/DiagnosticOptions.h; sourceTree = "<group>"; };
- BF9FEDC61225E3F6003A8B71 /* FrontendAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FrontendAction.h; path = clang/Frontend/FrontendAction.h; sourceTree = "<group>"; };
- BF9FEDC71225E3F6003A8B71 /* FrontendActions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FrontendActions.h; path = clang/Frontend/FrontendActions.h; sourceTree = "<group>"; };
- BF9FEDC81225E40A003A8B71 /* FrontendOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FrontendOptions.h; path = clang/Frontend/FrontendOptions.h; sourceTree = "<group>"; };
- BF9FEDC91225E40A003A8B71 /* FrontendPluginRegistry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FrontendPluginRegistry.h; path = clang/Frontend/FrontendPluginRegistry.h; sourceTree = "<group>"; };
- BF9FEDCA1225E40A003A8B71 /* HeaderSearchOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HeaderSearchOptions.h; path = clang/Frontend/HeaderSearchOptions.h; sourceTree = "<group>"; };
- BF9FEDCB1225E40A003A8B71 /* LangStandard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LangStandard.h; path = clang/Frontend/LangStandard.h; sourceTree = "<group>"; };
- BF9FEDCC1225E41D003A8B71 /* PreprocessorOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PreprocessorOptions.h; path = clang/Frontend/PreprocessorOptions.h; sourceTree = "<group>"; };
- BF9FEDCD1225E41D003A8B71 /* PreprocessorOutputOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PreprocessorOutputOptions.h; path = clang/Frontend/PreprocessorOutputOptions.h; sourceTree = "<group>"; };
- BF9FEDCE1225E42C003A8B71 /* VerifyDiagnosticsClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VerifyDiagnosticsClient.h; path = clang/Frontend/VerifyDiagnosticsClient.h; sourceTree = "<group>"; };
- BF9FEDCF1225E443003A8B71 /* LangStandards.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = LangStandards.def; path = clang/Frontend/LangStandards.def; sourceTree = "<group>"; };
- BF9FEDE71225E488003A8B71 /* CC1AsOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CC1AsOptions.h; path = clang/Driver/CC1AsOptions.h; sourceTree = "<group>"; };
- BF9FEDE81225E49D003A8B71 /* CC1Options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CC1Options.h; path = clang/Driver/CC1Options.h; sourceTree = "<group>"; };
- BF9FEDE91225E4BD003A8B71 /* OptSpecifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OptSpecifier.h; path = clang/Driver/OptSpecifier.h; sourceTree = "<group>"; };
- BF9FEDEA1225E4BD003A8B71 /* OptTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OptTable.h; path = clang/Driver/OptTable.h; sourceTree = "<group>"; };
- BF9FEDEB1225E4F2003A8B71 /* AttrKinds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AttrKinds.h; sourceTree = "<group>"; };
- BF9FEDEC1225E514003A8B71 /* Version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Version.h; sourceTree = "<group>"; };
- BF9FEDED1225E52F003A8B71 /* arm_neon.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = arm_neon.td; sourceTree = "<group>"; };
- BF9FEDEE1225E52F003A8B71 /* Attr.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Attr.td; sourceTree = "<group>"; };
- BF9FEDEF1225E55C003A8B71 /* BuiltinsARM.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BuiltinsARM.def; sourceTree = "<group>"; };
- BF9FEDF01225E574003A8B71 /* Specifiers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Specifiers.h; sourceTree = "<group>"; };
- BF9FEDF11225E574003A8B71 /* StmtNodes.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = StmtNodes.td; sourceTree = "<group>"; };
- BF9FEDF21225E58B003A8B71 /* TargetOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TargetOptions.h; sourceTree = "<group>"; };
- BF9FEDF31225E5B6003A8B71 /* DeclNodes.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DeclNodes.td; sourceTree = "<group>"; };
- BF9FEDF41225E5D5003A8B71 /* Linkage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Linkage.h; sourceTree = "<group>"; };
- BF9FEDF51225E5D5003A8B71 /* MacroBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroBuilder.h; sourceTree = "<group>"; };
- BF9FEDF61225E5FB003A8B71 /* Version.inc.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Version.inc.in; sourceTree = "<group>"; };
- BF9FEDF71225E613003A8B71 /* DiagnosticCategories.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticCategories.td; sourceTree = "<group>"; };
- BF9FEDFA1225E6A9003A8B71 /* AttributeList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AttributeList.cpp; path = lib/Sema/AttributeList.cpp; sourceTree = "<group>"; };
- BF9FEDFC1225E6C6003A8B71 /* DeclSpec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclSpec.cpp; path = lib/Sema/DeclSpec.cpp; sourceTree = "<group>"; };
- BF9FEDFE1225E6DD003A8B71 /* TargetAttributesSema.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TargetAttributesSema.cpp; path = lib/Sema/TargetAttributesSema.cpp; sourceTree = "<group>"; };
- BF9FEE001225E718003A8B71 /* CXXABI.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = CXXABI.h; sourceTree = "<group>"; tabWidth = 2; };
- BF9FEE011225E73F003A8B71 /* ExprClassification.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ExprClassification.cpp; sourceTree = "<group>"; tabWidth = 2; };
- BF9FEE031225E759003A8B71 /* ItaniumCXXABI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ItaniumCXXABI.cpp; sourceTree = "<group>"; tabWidth = 2; };
- BF9FEE051225E770003A8B71 /* MicrosoftCXXABI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = MicrosoftCXXABI.cpp; sourceTree = "<group>"; tabWidth = 2; };
- BF9FEE2B1225E7EA003A8B71 /* BackendUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BackendUtil.cpp; path = lib/CodeGen/BackendUtil.cpp; sourceTree = "<group>"; };
- BF9FEE2D1225E80F003A8B71 /* CGCXXABI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CGCXXABI.h; path = lib/CodeGen/CGCXXABI.h; sourceTree = "<group>"; };
- BF9FEE2E1225E82D003A8B71 /* CGException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CGException.h; path = lib/CodeGen/CGException.h; sourceTree = "<group>"; };
- BF9FEE2F1225E854003A8B71 /* CGRecordLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CGRecordLayout.h; path = lib/CodeGen/CGRecordLayout.h; sourceTree = "<group>"; };
- BF9FEE301225E86C003A8B71 /* CodeGenAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CodeGenAction.cpp; path = lib/CodeGen/CodeGenAction.cpp; sourceTree = "<group>"; };
- BF9FEE321225E898003A8B71 /* ItaniumCXXABI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ItaniumCXXABI.cpp; path = lib/CodeGen/ItaniumCXXABI.cpp; sourceTree = "<group>"; };
- BF9FEE341225E8B1003A8B71 /* MicrosoftCXXABI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MicrosoftCXXABI.cpp; path = lib/CodeGen/MicrosoftCXXABI.cpp; sourceTree = "<group>"; };
- BF9FEE361225E8CF003A8B71 /* README.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = README.txt; path = lib/CodeGen/README.txt; sourceTree = "<group>"; };
- BF9FEE451225EA24003A8B71 /* DelayedDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DelayedDiagnostic.h; path = clang/Sema/DelayedDiagnostic.h; sourceTree = "<group>"; };
- BF9FEE511226FE9F003A8B71 /* ParseAST.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ParseAST.cpp; path = lib/Parse/ParseAST.cpp; sourceTree = "<group>"; };
- BF9FEE531226FEC1003A8B71 /* RAIIObjectsForParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RAIIObjectsForParser.h; path = lib/Parse/RAIIObjectsForParser.h; sourceTree = "<group>"; };
- BF9FEEF1122D8068003A8B71 /* PreprocessingRecord.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PreprocessingRecord.cpp; sourceTree = "<group>"; };
- BFE2F69311DA955A0007EDC0 /* DeltaTree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeltaTree.cpp; sourceTree = "<group>"; };
- BFE2F69411DA955A0007EDC0 /* FixItRewriter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FixItRewriter.cpp; sourceTree = "<group>"; };
- BFE2F69511DA955A0007EDC0 /* FrontendActions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FrontendActions.cpp; sourceTree = "<group>"; };
- BFE2F69611DA955A0007EDC0 /* HTMLPrint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTMLPrint.cpp; sourceTree = "<group>"; };
- BFE2F69711DA955A0007EDC0 /* HTMLRewrite.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTMLRewrite.cpp; sourceTree = "<group>"; };
- BFE2F6A511DA955A0007EDC0 /* RewriteMacros.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RewriteMacros.cpp; sourceTree = "<group>"; };
- BFE2F6A611DA955A0007EDC0 /* RewriteObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RewriteObjC.cpp; sourceTree = "<group>"; };
- BFE2F6A711DA955A0007EDC0 /* Rewriter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Rewriter.cpp; sourceTree = "<group>"; };
- BFE2F6A811DA955A0007EDC0 /* RewriteRope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RewriteRope.cpp; sourceTree = "<group>"; };
- BFE2F6A911DA955A0007EDC0 /* RewriteTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RewriteTest.cpp; sourceTree = "<group>"; };
- BFE2F6AA11DA955A0007EDC0 /* TokenRewriter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TokenRewriter.cpp; sourceTree = "<group>"; };
- DE01DA480B12ADA300AC22CE /* PPCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PPCallbacks.h; sourceTree = "<group>"; };
- DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExprCXX.cpp; path = lib/Parse/ParseExprCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE06B73D0A8307640050E87E /* LangOptions.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = LangOptions.h; sourceTree = "<group>"; tabWidth = 2; };
- DE06D42F0A8BB52D0050E87E /* Parser.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Parser.cpp; path = lib/Parse/Parser.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE0FCA620A95859D00248FD5 /* Expr.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Expr.h; path = clang/AST/Expr.h; sourceTree = "<group>"; tabWidth = 2; };
- DE1F22020A7D852A00FBF588 /* Parser.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Parser.h; path = clang/Parse/Parser.h; sourceTree = "<group>"; tabWidth = 2; };
- DE224FF70C7AA98800D370A5 /* CGExprComplex.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprComplex.cpp; path = lib/CodeGen/CGExprComplex.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE22526F0C7E82D000D370A5 /* CGExprScalar.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprScalar.cpp; path = lib/CodeGen/CGExprScalar.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE2255FB0C8004E600D370A5 /* ParseDeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseDeclCXX.cpp; path = lib/Parse/ParseDeclCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE22BCF10E14197E0094DC60 /* SemaDeclAttr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaDeclAttr.cpp; path = lib/Sema/SemaDeclAttr.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE344AB70AE5DF6D00DBC861 /* HeaderSearch.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = HeaderSearch.h; sourceTree = "<group>"; };
- DE344B530AE5E46C00DBC861 /* HeaderSearch.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = HeaderSearch.cpp; sourceTree = "<group>"; };
- DE3450D60AEB543100DBC861 /* DirectoryLookup.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DirectoryLookup.h; sourceTree = "<group>"; };
- DE3452800AEF1B1800DBC861 /* Stmt.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Stmt.h; path = clang/AST/Stmt.h; sourceTree = "<group>"; tabWidth = 2; };
- DE345C190AFC658B00DBC861 /* StmtVisitor.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = StmtVisitor.h; path = clang/AST/StmtVisitor.h; sourceTree = "<group>"; tabWidth = 2; };
- DE345FFF0AFDCC1900DBC861 /* ParseObjc.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseObjc.cpp; path = lib/Parse/ParseObjc.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE3460040AFDCC6500DBC861 /* ParseInit.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseInit.cpp; path = lib/Parse/ParseInit.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE34600A0AFDCCBF00DBC861 /* ParseStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseStmt.cpp; path = lib/Parse/ParseStmt.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE34600E0AFDCCCE00DBC861 /* ParseDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseDecl.cpp; path = lib/Parse/ParseDecl.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE3460120AFDCCDA00DBC861 /* ParseExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExpr.cpp; path = lib/Parse/ParseExpr.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE3464210B03040900DBC861 /* Type.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Type.h; path = clang/AST/Type.h; sourceTree = "<group>"; tabWidth = 2; };
- DE37251C0FE4818000CF2CC2 /* Builtins.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Builtins.h; sourceTree = "<group>"; };
- DE37252A0FE4818F00CF2CC2 /* Builtins.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Builtins.def; sourceTree = "<group>"; };
- DE37252D0FE481AD00CF2CC2 /* Builtins.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Builtins.cpp; sourceTree = "<group>"; };
- DE3725310FE4822800CF2CC2 /* TargetBuiltins.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TargetBuiltins.h; sourceTree = "<group>"; };
- DE3725320FE4826C00CF2CC2 /* BuiltinsX86.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BuiltinsX86.def; sourceTree = "<group>"; };
- DE3725330FE4827200CF2CC2 /* BuiltinsPPC.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BuiltinsPPC.def; sourceTree = "<group>"; };
- DE38CD4E0D794CF900A273B6 /* CGObjCRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGObjCRuntime.h; path = lib/CodeGen/CGObjCRuntime.h; sourceTree = "<group>"; tabWidth = 2; };
- DE38CD4F0D794D0100A273B6 /* CGObjCGNU.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGObjCGNU.cpp; path = lib/CodeGen/CGObjCGNU.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE3986EF0CB8D4B300223765 /* IdentifierTable.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = IdentifierTable.h; sourceTree = "<group>"; tabWidth = 2; };
- DE3986F30CB8D50C00223765 /* IdentifierTable.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = IdentifierTable.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE41211D0D7F1BBE0080F80A /* GRWorkList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRWorkList.h; path = clang/Analysis/PathSensitive/GRWorkList.h; sourceTree = "<group>"; };
- DE41211E0D7F1BBE0080F80A /* SymbolManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SymbolManager.h; path = clang/Analysis/PathSensitive/SymbolManager.h; sourceTree = "<group>"; };
- DE41211F0D7F1BBE0080F80A /* GRBlockCounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRBlockCounter.h; path = clang/Analysis/PathSensitive/GRBlockCounter.h; sourceTree = "<group>"; };
- DE4121200D7F1BBE0080F80A /* ExplodedGraph.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExplodedGraph.h; path = clang/Analysis/PathSensitive/ExplodedGraph.h; sourceTree = "<group>"; };
- DE4121210D7F1BBE0080F80A /* GRExprEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRExprEngine.h; path = clang/Analysis/PathSensitive/GRExprEngine.h; sourceTree = "<group>"; };
- DE4121220D7F1BBE0080F80A /* GRTransferFuncs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRTransferFuncs.h; path = clang/Analysis/PathSensitive/GRTransferFuncs.h; sourceTree = "<group>"; };
- DE4121230D7F1BBE0080F80A /* GRCoreEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRCoreEngine.h; path = clang/Analysis/PathSensitive/GRCoreEngine.h; sourceTree = "<group>"; };
- DE4264FB0C113592005A861D /* CGDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGDecl.cpp; path = lib/CodeGen/CGDecl.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE46BF270AE0A82D00CC047C /* TargetInfo.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = TargetInfo.h; sourceTree = "<group>"; tabWidth = 2; };
- DE4772F90C10EAE5002239E8 /* CGStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGStmt.cpp; path = lib/CodeGen/CGStmt.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE4772FB0C10EAEC002239E8 /* CGExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExpr.cpp; path = lib/CodeGen/CGExpr.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE47999B0D2EBE1A00706D2D /* SemaExprObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaExprObjC.cpp; path = lib/Sema/SemaExprObjC.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE4DC7980EA1BE4400069E5A /* TokenRewriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TokenRewriter.h; path = clang/Rewrite/TokenRewriter.h; sourceTree = "<group>"; };
- DE4DC7A20EA1C33E00069E5A /* TokenRewriter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TokenRewriter.cpp; path = lib/Rewrite/TokenRewriter.cpp; sourceTree = "<group>"; };
- DE53370B0CE2D96F00D9A028 /* RewriteRope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RewriteRope.h; path = clang/Rewrite/RewriteRope.h; sourceTree = "<group>"; };
- DE613EF30E0E148D00B05B79 /* APValue.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = APValue.h; path = clang/AST/APValue.h; sourceTree = "<group>"; tabWidth = 2; };
- DE67E70C0C020ECA00F66BC5 /* SemaStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaStmt.cpp; path = lib/Sema/SemaStmt.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE67E70E0C020ECF00F66BC5 /* SemaExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaExprCXX.cpp; path = lib/Sema/SemaExprCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE67E7100C020ED400F66BC5 /* SemaExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaExpr.cpp; path = lib/Sema/SemaExpr.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE67E7120C020ED900F66BC5 /* SemaDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaDecl.cpp; path = lib/Sema/SemaDecl.cpp; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
- DE67E7160C020EE400F66BC5 /* Sema.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Sema.cpp; path = lib/Sema/Sema.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE6951C60C4D1F5D00A5826B /* RecordLayout.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = RecordLayout.h; path = clang/AST/RecordLayout.h; sourceTree = "<group>"; tabWidth = 2; };
- DE6954630C5121BD00A5826B /* Token.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Token.h; sourceTree = "<group>"; };
- DE704B250D0FBEBE009C7762 /* SemaDeclObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaDeclObjC.cpp; path = lib/Sema/SemaDeclObjC.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE704BD10D1647E7009C7762 /* HeaderMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeaderMap.h; sourceTree = "<group>"; };
- DE704DD10D1668A4009C7762 /* HeaderMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeaderMap.cpp; sourceTree = "<group>"; };
- DE75ED280B044DC90020CF81 /* ASTContext.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ASTContext.h; path = clang/AST/ASTContext.h; sourceTree = "<group>"; tabWidth = 2; };
- DE85CD800D8380B10070E26E /* TokenLexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TokenLexer.cpp; sourceTree = "<group>"; };
- DE85CD840D8380F20070E26E /* TokenLexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TokenLexer.h; sourceTree = "<group>"; };
- DE85CD9E0D8382DD0070E26E /* MacroArgs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroArgs.h; sourceTree = "<group>"; };
- DE85CDA20D8383B20070E26E /* MacroArgs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MacroArgs.cpp; sourceTree = "<group>"; };
- DE85CDAB0D838C120070E26E /* PPMacroExpansion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PPMacroExpansion.cpp; sourceTree = "<group>"; };
- DE85CDAF0D838C390070E26E /* PPDirectives.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PPDirectives.cpp; sourceTree = "<group>"; };
- DE85CDB50D839BAE0070E26E /* PPLexerChange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PPLexerChange.cpp; sourceTree = "<group>"; };
- DE8822350EC80C0A00CBC30A /* CGBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGBuilder.h; path = lib/CodeGen/CGBuilder.h; sourceTree = "<group>"; tabWidth = 2; };
- DE8823DE0ED0B78600CBC30A /* PTHLexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PTHLexer.h; sourceTree = "<group>"; };
- DE8824530ED1243E00CBC30A /* OperatorKinds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OperatorKinds.h; sourceTree = "<group>"; };
- DE8824560ED1244600CBC30A /* OperatorKinds.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = OperatorKinds.def; sourceTree = "<group>"; };
- DE928B120C05659200231DA4 /* ModuleBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ModuleBuilder.cpp; path = lib/CodeGen/ModuleBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE928B1F0C0565B000231DA4 /* ModuleBuilder.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ModuleBuilder.h; path = clang/CodeGen/ModuleBuilder.h; sourceTree = "<group>"; };
- DE928B7C0C0A615100231DA4 /* CodeGenModule.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CodeGenModule.h; path = lib/CodeGen/CodeGenModule.h; sourceTree = "<group>"; tabWidth = 2; };
- DE928B7E0C0A615600231DA4 /* CodeGenModule.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CodeGenModule.cpp; path = lib/CodeGen/CodeGenModule.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE928B800C0A615B00231DA4 /* CodeGenFunction.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CodeGenFunction.h; path = lib/CodeGen/CodeGenFunction.h; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
- DE928B820C0A616000231DA4 /* CodeGenFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CodeGenFunction.cpp; path = lib/CodeGen/CodeGenFunction.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEA09A6E0F31756F000C2258 /* ASTDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ASTDiagnostic.h; path = clang/AST/ASTDiagnostic.h; sourceTree = "<group>"; tabWidth = 2; };
- DEA09A830F3175BF000C2258 /* LexDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LexDiagnostic.h; sourceTree = "<group>"; };
- DEA09A860F3175CA000C2258 /* ParseDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ParseDiagnostic.h; path = clang/Parse/ParseDiagnostic.h; sourceTree = "<group>"; tabWidth = 2; };
- DEAABDF70F5F477C0098928A /* PrettyStackTrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrettyStackTrace.h; sourceTree = "<group>"; };
- DEAEE98A0A5A2B970045101B /* MultipleIncludeOpt.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MultipleIncludeOpt.h; sourceTree = "<group>"; };
- DEAEED4A0A5AF89A0045101B /* NOTES.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = NOTES.txt; sourceTree = "<group>"; };
- DEB076C90F3A221200F5A2BE /* DeclTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclTemplate.h; path = clang/AST/DeclTemplate.h; sourceTree = "<group>"; tabWidth = 2; };
- DEB077930F44F96000F5A2BE /* TokenConcatenation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TokenConcatenation.h; sourceTree = "<group>"; };
- DEB077980F44F97800F5A2BE /* TokenConcatenation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TokenConcatenation.cpp; sourceTree = "<group>"; };
- DEB07AC70F4A427E00F5A2BE /* SemaAttr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaAttr.cpp; path = lib/Sema/SemaAttr.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEB089EE0F12F1D900522C07 /* TypeTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypeTraits.h; sourceTree = "<group>"; };
- DEC8D9900A9433CD00353FCA /* Decl.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Decl.h; path = clang/AST/Decl.h; sourceTree = "<group>"; tabWidth = 2; };
- DEC8D9A30A94346E00353FCA /* AST.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = AST.h; path = clang/AST/AST.h; sourceTree = "<group>"; tabWidth = 2; };
- DECAB0CF0DB3C84200E13CCB /* RewriteRope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteRope.cpp; path = lib/Rewrite/RewriteRope.cpp; sourceTree = "<group>"; };
- DECB6D640F9AE26600F5FBC7 /* JumpDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = JumpDiagnostics.cpp; path = lib/Sema/JumpDiagnostics.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DECB6F060F9D93A800F5FBC7 /* InitPreprocessor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InitPreprocessor.cpp; path = lib/Frontend/InitPreprocessor.cpp; sourceTree = "<group>"; };
- DECB734E0FA3ED8400F5FBC7 /* StmtObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = StmtObjC.h; path = clang/AST/StmtObjC.h; sourceTree = "<group>"; tabWidth = 2; };
- DECB73550FA3EE5A00F5FBC7 /* StmtCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = StmtCXX.h; path = clang/AST/StmtCXX.h; sourceTree = "<group>"; tabWidth = 2; };
- DED626C80AE0C065001E80A4 /* TargetInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = TargetInfo.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DED7D7310A524295003AD0FB /* Diagnostic.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = Diagnostic.h; sourceTree = "<group>"; tabWidth = 2; };
- DED7D7330A524295003AD0FB /* FileManager.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = FileManager.h; sourceTree = "<group>"; tabWidth = 2; };
- DED7D7350A524295003AD0FB /* SourceLocation.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = SourceLocation.h; sourceTree = "<group>"; tabWidth = 2; };
- DED7D7360A524295003AD0FB /* SourceManager.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = SourceManager.h; sourceTree = "<group>"; tabWidth = 2; };
- DED7D7370A524295003AD0FB /* TokenKinds.def */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = text; path = TokenKinds.def; sourceTree = "<group>"; tabWidth = 2; };
- DED7D7380A524295003AD0FB /* TokenKinds.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = TokenKinds.h; sourceTree = "<group>"; tabWidth = 2; };
- DED7D73B0A524295003AD0FB /* Lexer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Lexer.h; sourceTree = "<group>"; };
- DED7D73E0A524295003AD0FB /* MacroInfo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MacroInfo.h; sourceTree = "<group>"; };
- DED7D73F0A524295003AD0FB /* Pragma.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Pragma.h; sourceTree = "<group>"; };
- DED7D7400A524295003AD0FB /* Preprocessor.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Preprocessor.h; sourceTree = "<group>"; };
- DED7D75D0A5242C7003AD0FB /* Diagnostic.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Diagnostic.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DED7D75E0A5242C7003AD0FB /* FileManager.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = FileManager.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DED7D76D0A5242C7003AD0FB /* SourceManager.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = SourceManager.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DED7D76E0A5242C7003AD0FB /* TokenKinds.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = TokenKinds.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DED7D79E0A5242E6003AD0FB /* Lexer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Lexer.cpp; sourceTree = "<group>"; };
- DED7D7A00A5242E6003AD0FB /* MacroInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MacroInfo.cpp; sourceTree = "<group>"; };
- DED7D7A20A5242E6003AD0FB /* PPExpressions.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = PPExpressions.cpp; sourceTree = "<group>"; };
- DED7D7A30A5242E6003AD0FB /* Pragma.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Pragma.cpp; sourceTree = "<group>"; };
- DED7D7A40A5242E6003AD0FB /* Preprocessor.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Preprocessor.cpp; sourceTree = "<group>"; };
- DED7D7D70A524302003AD0FB /* README.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = README.txt; sourceTree = "<group>"; };
- DED7D9170A52518C003AD0FB /* ScratchBuffer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ScratchBuffer.h; sourceTree = "<group>"; };
- DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ScratchBuffer.cpp; sourceTree = "<group>"; };
- DEDFE5CB0F7206CC0035BD10 /* NestedNameSpecifier.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = NestedNameSpecifier.h; path = clang/AST/NestedNameSpecifier.h; sourceTree = "<group>"; tabWidth = 2; };
- DEDFE6450F7B3B4E0035BD10 /* driver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = driver.cpp; path = tools/driver/driver.cpp; sourceTree = "<group>"; };
- DEDFE6480F7B3B830035BD10 /* Types.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Types.cpp; path = lib/Driver/Types.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEDFE6490F7B3B830035BD10 /* Tools.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Tools.h; path = lib/Driver/Tools.h; sourceTree = "<group>"; tabWidth = 2; };
- DEDFE64A0F7B3B830035BD10 /* Tools.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Tools.cpp; path = lib/Driver/Tools.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEDFE64B0F7B3B830035BD10 /* ToolChains.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ToolChains.h; path = lib/Driver/ToolChains.h; sourceTree = "<group>"; tabWidth = 2; };
- DEDFE64C0F7B3B830035BD10 /* Compilation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Compilation.cpp; path = lib/Driver/Compilation.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEDFE64D0F7B3B830035BD10 /* ArgList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ArgList.cpp; path = lib/Driver/ArgList.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEDFE64E0F7B3B830035BD10 /* Arg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Arg.cpp; path = lib/Driver/Arg.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEDFE64F0F7B3B830035BD10 /* Action.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Action.cpp; path = lib/Driver/Action.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEDFE6500F7B3B830035BD10 /* Phases.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Phases.cpp; path = lib/Driver/Phases.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEDFE6510F7B3B830035BD10 /* OptTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = OptTable.cpp; path = lib/Driver/OptTable.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEDFE6520F7B3B830035BD10 /* Option.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Option.cpp; path = lib/Driver/Option.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEDFE6530F7B3B830035BD10 /* Job.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Job.cpp; path = lib/Driver/Job.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEDFE6540F7B3B830035BD10 /* InputInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = InputInfo.h; path = lib/Driver/InputInfo.h; sourceTree = "<group>"; tabWidth = 2; };
- DEDFE6550F7B3B830035BD10 /* ToolChains.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ToolChains.cpp; path = lib/Driver/ToolChains.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEDFE6560F7B3B830035BD10 /* ToolChain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ToolChain.cpp; path = lib/Driver/ToolChain.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEDFE6570F7B3B830035BD10 /* Tool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Tool.cpp; path = lib/Driver/Tool.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEDFE6580F7B3B830035BD10 /* HostInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = HostInfo.cpp; path = lib/Driver/HostInfo.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEDFE6590F7B3B830035BD10 /* Driver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Driver.cpp; path = lib/Driver/Driver.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEDFF87F0F848CE30035BD10 /* TemplateName.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TemplateName.h; path = clang/AST/TemplateName.h; sourceTree = "<group>"; tabWidth = 2; };
- DEDFFF070F959EE60035BD10 /* Diagnostic.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Diagnostic.td; sourceTree = "<group>"; };
- DEDFFF530F9704580035BD10 /* DiagnosticGroups.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticGroups.td; sourceTree = "<group>"; };
- DEEBBD430C19C5D200A9FE82 /* TODO.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = TODO.txt; sourceTree = "<group>"; };
- DEEBC3B90C2363B800A9FE82 /* CodeGenTypes.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CodeGenTypes.h; path = lib/CodeGen/CodeGenTypes.h; sourceTree = "<group>"; tabWidth = 2; };
- DEEBC3BB0C2363BC00A9FE82 /* CodeGenTypes.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CodeGenTypes.cpp; path = lib/CodeGen/CodeGenTypes.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEF161600F65C81C0098507F /* TextDiagnosticBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TextDiagnosticBuffer.h; path = clang/Frontend/TextDiagnosticBuffer.h; sourceTree = "<group>"; };
- DEF161630F65C81C0098507F /* TextDiagnosticPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TextDiagnosticPrinter.h; path = clang/Frontend/TextDiagnosticPrinter.h; sourceTree = "<group>"; };
- DEF165140F8D46980098507F /* Tool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Tool.h; path = clang/Driver/Tool.h; sourceTree = "<group>"; };
- DEF165150F8D46980098507F /* Types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Types.h; path = clang/Driver/Types.h; sourceTree = "<group>"; };
- DEF165160F8D46980098507F /* Action.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Action.h; path = clang/Driver/Action.h; sourceTree = "<group>"; };
- DEF165170F8D46980098507F /* Compilation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Compilation.h; path = clang/Driver/Compilation.h; sourceTree = "<group>"; };
- DEF165190F8D46980098507F /* Option.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Option.h; path = clang/Driver/Option.h; sourceTree = "<group>"; };
- DEF1651A0F8D46980098507F /* Types.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Types.def; path = clang/Driver/Types.def; sourceTree = "<group>"; };
- DEF1651B0F8D46980098507F /* ToolChain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ToolChain.h; path = clang/Driver/ToolChain.h; sourceTree = "<group>"; };
- DEF1651C0F8D46980098507F /* Options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Options.h; path = clang/Driver/Options.h; sourceTree = "<group>"; };
- DEF1651D0F8D46980098507F /* ArgList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ArgList.h; path = clang/Driver/ArgList.h; sourceTree = "<group>"; };
- DEF1651E0F8D46980098507F /* Arg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Arg.h; path = clang/Driver/Arg.h; sourceTree = "<group>"; };
- DEF1651F0F8D46980098507F /* HostInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HostInfo.h; path = clang/Driver/HostInfo.h; sourceTree = "<group>"; };
- DEF165200F8D46980098507F /* Driver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Driver.h; path = clang/Driver/Driver.h; sourceTree = "<group>"; };
- DEF165210F8D46980098507F /* Job.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Job.h; path = clang/Driver/Job.h; sourceTree = "<group>"; };
- DEF165220F8D46980098507F /* Util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Util.h; path = clang/Driver/Util.h; sourceTree = "<group>"; };
- DEF165230F8D46980098507F /* Phases.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Phases.h; path = clang/Driver/Phases.h; sourceTree = "<group>"; };
- DEF165240F8D46980098507F /* DriverDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DriverDiagnostic.h; path = clang/Driver/DriverDiagnostic.h; sourceTree = "<group>"; };
- DEF169220F9645960098507F /* FrontendDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FrontendDiagnostic.h; path = clang/Frontend/FrontendDiagnostic.h; sourceTree = "<group>"; };
- DEF1692C0F9645BF0098507F /* AnalysisDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = AnalysisDiagnostic.h; path = clang/Analysis/AnalysisDiagnostic.h; sourceTree = "<group>"; tabWidth = 2; };
- DEF16BE40FA13A5B0098507F /* TypeNodes.def */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text; name = TypeNodes.def; path = clang/AST/TypeNodes.def; sourceTree = "<group>"; tabWidth = 2; };
- DEF16BE50FA13A650098507F /* TypeOrdering.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TypeOrdering.h; path = clang/AST/TypeOrdering.h; sourceTree = "<group>"; tabWidth = 2; };
- DEF2E95E0C5FBD74000C4259 /* InternalsManual.html */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.html; name = InternalsManual.html; path = docs/InternalsManual.html; sourceTree = "<group>"; };
- DEF2EFF20C6CDD74000C4259 /* CGExprAgg.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprAgg.cpp; path = lib/CodeGen/CGExprAgg.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEF2F00F0C6CFED5000C4259 /* SemaChecking.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaChecking.cpp; path = lib/Sema/SemaChecking.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DEF7D9F60C9C8B1A0001F598 /* Rewriter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Rewriter.h; path = clang/Rewrite/Rewriter.h; sourceTree = "<group>"; };
- DEF7D9F80C9C8B1D0001F598 /* Rewriter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Rewriter.cpp; path = lib/Rewrite/Rewriter.cpp; sourceTree = "<group>"; };
- DEFFECA30DB093D100B4E7C3 /* DeltaTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeltaTree.h; path = clang/Rewrite/DeltaTree.h; sourceTree = "<group>"; };
- DEFFECA60DB1546600B4E7C3 /* DeltaTree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeltaTree.cpp; path = lib/Rewrite/DeltaTree.cpp; sourceTree = "<group>"; };
- E16B523410D30B2400430AC9 /* cc1_main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cc1_main.cpp; path = tools/driver/cc1_main.cpp; sourceTree = "<group>"; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
- 8DD76F660486A84900D96B5E /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- 08FB7794FE84155DC02AAC07 /* clang */ = {
- isa = PBXGroup;
- children = (
- DED7D72E0A524295003AD0FB /* include */,
- 08FB7795FE84155DC02AAC07 /* Libraries */,
- DEDFE61F0F7B3AE10035BD10 /* Tools */,
- C6859E8C029090F304C91782 /* Documentation */,
- 1AB674ADFE9D54B511CA2CBB /* Products */,
- );
- name = clang;
- sourceTree = "<group>";
- };
- 08FB7795FE84155DC02AAC07 /* Libraries */ = {
- isa = PBXGroup;
- children = (
- BB20603A131EDDBF003C3343 /* ARRMigrate */,
- BBA5AB121309C2FA000B38F1 /* StaticAnalyzer */,
- 57EB5660121B034300ECA335 /* Serialization */,
- BFE2F67911DA95590007EDC0 /* Rewrite */,
- 90FD6D6C103C3D2D005F5B73 /* Index */,
- DED7D7500A5242C7003AD0FB /* Basic */,
- DED7D78C0A5242E6003AD0FB /* Lex */,
- DE1F22600A7D8C9B00FBF588 /* Parse */,
- DEC8D9920A9433F400353FCA /* AST */,
- DE67E7070C020EAB00F66BC5 /* Sema */,
- DE927FCC0C0557CD00231DA4 /* CodeGen */,
- 356EF9B30C8F7DCA006650F5 /* Analysis */,
- 1AC1A6871299A284006FBC77 /* Checker */,
- DEF7D9F50C9C8B0C0001F598 /* Rewrite */,
- 352246E00F5C6BC000D0D279 /* Frontend */,
- DEDFE6470F7B3B560035BD10 /* Driver */,
- );
- name = Libraries;
- sourceTree = "<group>";
- };
- 1AB674ADFE9D54B511CA2CBB /* Products */ = {
- isa = PBXGroup;
- children = (
- 8DD76F6C0486A84900D96B5E /* clang */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 1AC1A6871299A284006FBC77 /* Checker */ = {
- isa = PBXGroup;
- children = (
- 1AC1A6881299A284006FBC77 /* AdjustedReturnValueChecker.cpp */,
- 1AC1A6891299A284006FBC77 /* AggExprVisitor.cpp */,
- 1AC1A68A1299A284006FBC77 /* AnalysisConsumer.cpp */,
- 1AC1A68B1299A284006FBC77 /* AnalysisManager.cpp */,
- 1AC1A68C1299A284006FBC77 /* AnalyzerStatsChecker.cpp */,
- 1AC1A68D1299A284006FBC77 /* ArrayBoundChecker.cpp */,
- 1AC1A68E1299A284006FBC77 /* AttrNonNullChecker.cpp */,
- 1AC1A68F1299A284006FBC77 /* BasicConstraintManager.cpp */,
- 1AC1A6901299A284006FBC77 /* BasicObjCFoundationChecks.cpp */,
- 1AC1A6911299A284006FBC77 /* BasicObjCFoundationChecks.h */,
- 1AC1A6921299A284006FBC77 /* BasicStore.cpp */,
- 1AC1A6931299A284006FBC77 /* BasicValueFactory.cpp */,
- 1AC1A6941299A284006FBC77 /* BugReporter.cpp */,
- 1AC1A6951299A284006FBC77 /* BugReporterVisitors.cpp */,
- 1AC1A6961299A284006FBC77 /* BuiltinFunctionChecker.cpp */,
- 1AC1A6971299A284006FBC77 /* CallAndMessageChecker.cpp */,
- 1AC1A6981299A284006FBC77 /* CastSizeChecker.cpp */,
- 1AC1A6991299A284006FBC77 /* CastToStructChecker.cpp */,
- 1AC1A69A1299A284006FBC77 /* CFRefCount.cpp */,
- 1AC1A69B1299A284006FBC77 /* CheckDeadStores.cpp */,
- 1AC1A69C1299A284006FBC77 /* Checker.cpp */,
- 1AC1A69D1299A284006FBC77 /* CheckerHelpers.cpp */,
- 1AC1A69E1299A284006FBC77 /* CheckObjCDealloc.cpp */,
- 1AC1A69F1299A284006FBC77 /* CheckObjCInstMethSignature.cpp */,
- 1AC1A6A01299A284006FBC77 /* CheckSecuritySyntaxOnly.cpp */,
- 1AC1A6A11299A284006FBC77 /* CheckSizeofPointer.cpp */,
- 1AC1A6A21299A284006FBC77 /* ChrootChecker.cpp */,
- 1AC1A6A41299A284006FBC77 /* CocoaConventions.cpp */,
- 1AC1A6A51299A284006FBC77 /* CStringChecker.cpp */,
- 1AC1A7DC1299A285006FBC77 /* DereferenceChecker.cpp */,
- 1AC1A7DD1299A285006FBC77 /* DivZeroChecker.cpp */,
- 1AC1A7DE1299A285006FBC77 /* Environment.cpp */,
- 1AC1A7DF1299A285006FBC77 /* ExplodedGraph.cpp */,
- 1AC1A7E01299A285006FBC77 /* FixedAddressChecker.cpp */,
- 1AC1A7E11299A285006FBC77 /* FlatStore.cpp */,
- 1AC1A7E21299A285006FBC77 /* FrontendActions.cpp */,
- 1AC1A7E31299A285006FBC77 /* GRBlockCounter.cpp */,
- 1AC1A7E41299A285006FBC77 /* GRCoreEngine.cpp */,
- 1AC1A7E51299A285006FBC77 /* GRCXXExprEngine.cpp */,
- 1AC1A7E61299A285006FBC77 /* GRExprEngine.cpp */,
- 1AC1A7E71299A285006FBC77 /* GRExprEngineExperimentalChecks.cpp */,
- 1AC1A7E81299A285006FBC77 /* GRExprEngineExperimentalChecks.h */,
- 1AC1A7E91299A285006FBC77 /* GRExprEngineInternalChecks.h */,
- 1AC1A7EA1299A285006FBC77 /* GRState.cpp */,
- 1AC1A7EB1299A285006FBC77 /* HTMLDiagnostics.cpp */,
- 1AC1A7EC1299A285006FBC77 /* IdempotentOperationChecker.cpp */,
- 1AC1A7ED1299A285006FBC77 /* LLVMConventionsChecker.cpp */,
- 1AC1A7EE1299A285006FBC77 /* MacOSXAPIChecker.cpp */,
- 1AC1A7F01299A285006FBC77 /* MallocChecker.cpp */,
- 1AC1A7F11299A285006FBC77 /* ManagerRegistry.cpp */,
- 1AC1A7F21299A285006FBC77 /* MemRegion.cpp */,
- 1AC1A7F31299A285006FBC77 /* NoReturnFunctionChecker.cpp */,
- 1AC1A7F41299A285006FBC77 /* NSAutoreleasePoolChecker.cpp */,
- 1AC1A7F51299A285006FBC77 /* NSErrorChecker.cpp */,
- 1AC1A7F61299A285006FBC77 /* ObjCAtSyncChecker.cpp */,
- 1AC1A7F71299A285006FBC77 /* ObjCUnusedIVarsChecker.cpp */,
- 1AC1A7F81299A285006FBC77 /* OSAtomicChecker.cpp */,
- 1AC1A7F91299A285006FBC77 /* PathDiagnostic.cpp */,
- 1AC1A7FA1299A285006FBC77 /* PlistDiagnostics.cpp */,
- 1AC1A7FB1299A285006FBC77 /* PointerArithChecker.cpp */,
- 1AC1A7FC1299A285006FBC77 /* PointerSubChecker.cpp */,
- 1AC1A7FD1299A285006FBC77 /* PthreadLockChecker.cpp */,
- 1AC1A7FE1299A285006FBC77 /* RangeConstraintManager.cpp */,
- 1AC1A8001299A285006FBC77 /* RegionStore.cpp */,
- 1AC1A9DB1299A287006FBC77 /* ReturnPointerRangeChecker.cpp */,
- 1AC1A9DC1299A287006FBC77 /* ReturnUndefChecker.cpp */,
- 1AC1A9DD1299A287006FBC77 /* SimpleConstraintManager.cpp */,
- 1AC1A9DE1299A287006FBC77 /* SimpleConstraintManager.h */,
- 1AC1A9DF1299A287006FBC77 /* SimpleSValuator.cpp */,
- 1AC1A9E01299A287006FBC77 /* StackAddrLeakChecker.cpp */,
- 1AC1A9E11299A287006FBC77 /* Store.cpp */,
- 1AC1A9E21299A287006FBC77 /* StreamChecker.cpp */,
- 1AC1A9E31299A287006FBC77 /* SVals.cpp */,
- 1AC1A9E41299A287006FBC77 /* SValuator.cpp */,
- 1AC1A9E51299A287006FBC77 /* SymbolManager.cpp */,
- 1AC1A9E61299A287006FBC77 /* UndefBranchChecker.cpp */,
- 1AC1A9E71299A287006FBC77 /* UndefCapturedBlockVarChecker.cpp */,
- 1AC1A9E81299A287006FBC77 /* UndefinedArraySubscriptChecker.cpp */,
- 1AC1A9E91299A287006FBC77 /* UndefinedAssignmentChecker.cpp */,
- 1AC1A9EA1299A287006FBC77 /* UndefResultChecker.cpp */,
- 1AC1A9EB1299A287006FBC77 /* UnixAPIChecker.cpp */,
- 1AC1A9EC1299A287006FBC77 /* UnreachableCodeChecker.cpp */,
- 1AC1A9ED1299A287006FBC77 /* ValueManager.cpp */,
- 1AC1A9EE1299A287006FBC77 /* VLASizeChecker.cpp */,
- );
- name = Checker;
- path = lib/Checker;
- sourceTree = "<group>";
- };
- 352246E00F5C6BC000D0D279 /* Frontend */ = {
- isa = PBXGroup;
- children = (
- 1AFDD8701161085D00AE030A /* ASTMerge.cpp */,
- 9012911C1048068D0083456D /* ASTUnit.cpp */,
- 1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */,
- 1A2A54A70FD1DD1C00F4CE45 /* CacheTokens.cpp */,
- DE4DC7A20EA1C33E00069E5A /* TokenRewriter.cpp */,
- 1ACB57DB1105820D0047B991 /* CompilerInstance.cpp */,
- 1ACB57DC1105820D0047B991 /* CompilerInvocation.cpp */,
- 1ACB57DD1105820D0047B991 /* DeclXML.cpp */,
- 1A2A54A80FD1DD1C00F4CE45 /* DependencyFile.cpp */,
- 1A2A54A90FD1DD1C00F4CE45 /* DiagChecker.cpp */,
- 1A2A54AA0FD1DD1C00F4CE45 /* DocumentXML.cpp */,
- 1ACB57DE1105820D0047B991 /* FrontendAction.cpp */,
- 1ACB57DF1105820D0047B991 /* FrontendActions.cpp */,
- 1ACB57E01105820D0047B991 /* FrontendOptions.cpp */,
- 352246E20F5C6BE000D0D279 /* InitHeaderSearch.cpp */,
- DECB6F060F9D93A800F5FBC7 /* InitPreprocessor.cpp */,
- 1ACB57E11105820D0047B991 /* LangStandards.cpp */,
- 1A2A54AE0FD1DD1C00F4CE45 /* PrintPreprocessedOutput.cpp */,
- 352246E50F5C6BE000D0D279 /* TextDiagnosticBuffer.cpp */,
- 352246E60F5C6BE000D0D279 /* TextDiagnosticPrinter.cpp */,
- 1ACB57E21105820D0047B991 /* TypeXML.cpp */,
- 1A2A54B30FD1DD1C00F4CE45 /* StmtXML.cpp */,
- 1ACB57E31105820D0047B991 /* VerifyDiagnosticsClient.cpp */,
- 1A2A54B40FD1DD1C00F4CE45 /* Warnings.cpp */,
- );
- name = Frontend;
- sourceTree = "<group>";
- };
- 352C19DB0CA321AC0045DB98 /* Visitors */ = {
- isa = PBXGroup;
- children = (
- 352C19DC0CA321C80045DB98 /* CFGRecStmtDeclVisitor.h */,
- 352C19DD0CA321C80045DB98 /* CFGRecStmtVisitor.h */,
- 352C19DE0CA321C80045DB98 /* CFGStmtVisitor.h */,
- 352C19DF0CA321C80045DB98 /* CFGVarDeclVisitor.h */,
- );
- name = Visitors;
- sourceTree = "<group>";
- };
- 356EF9AF0C8F7DA4006650F5 /* Analysis */ = {
- isa = PBXGroup;
- children = (
- 1AECEFAF12DE387800F1D539 /* AnalysisContext.h */,
- 1AECEFB012DE387800F1D539 /* CFG.h */,
- 1AECEFB112DE387800F1D539 /* CFGStmtMap.h */,
- DEF1692C0F9645BF0098507F /* AnalysisDiagnostic.h */,
- 35A8FCF60D9B4ADD001C2F97 /* ProgramPoint.h */,
- 35F9B1540D1C6AFC00DDFDAE /* Analyses */,
- 35D1DDCF0CA9C6BE0096E967 /* FlowSensitive */,
- DE4121130D7F1B980080F80A /* PathSensitive */,
- 35F9B1520D1C6ACB00DDFDAE /* Support */,
- 352C19DB0CA321AC0045DB98 /* Visitors */,
- );
- name = Analysis;
- sourceTree = "<group>";
- };
- 356EF9B30C8F7DCA006650F5 /* Analysis */ = {
- isa = PBXGroup;
- children = (
- 1AC1A67212999D8E006FBC77 /* AnalysisContext.cpp */,
- 1AC1A67312999D8E006FBC77 /* CFG.cpp */,
- 1AC1A67412999D8E006FBC77 /* CFGStmtMap.cpp */,
- 1AC1A67512999D8E006FBC77 /* FormatString.cpp */,
- 1AC1A67612999D8E006FBC77 /* FormatStringParsing.h */,
- 1AC1A67712999D8E006FBC77 /* LiveVariables.cpp */,
- 1AC1A67812999D8E006FBC77 /* PrintfFormatString.cpp */,
- 1AC1A67912999D8E006FBC77 /* PseudoConstantAnalysis.cpp */,
- 1AC1A67A12999D8E006FBC77 /* ReachableCode.cpp */,
- 1AC1A67B12999D8E006FBC77 /* ScanfFormatString.cpp */,
- 1AC1A67C12999D8E006FBC77 /* UninitializedValues.cpp */,
- );
- name = Analysis;
- sourceTree = "<group>";
- };
- 35D1DDCF0CA9C6BE0096E967 /* FlowSensitive */ = {
- isa = PBXGroup;
- children = (
- 35D1DDD10CA9C6D50096E967 /* DataflowSolver.h */,
- 35D1DDD20CA9C6D50096E967 /* DataflowValues.h */,
- );
- name = FlowSensitive;
- sourceTree = "<group>";
- };
- 35F9B1520D1C6ACB00DDFDAE /* Support */ = {
- isa = PBXGroup;
- children = (
- 3537AA0C0ECD088F008F7CDC /* BlkExprDeclBitVector.h */,
- );
- name = Support;
- sourceTree = "<group>";
- };
- 35F9B1540D1C6AFC00DDFDAE /* Analyses */ = {
- isa = PBXGroup;
- children = (
- 35F9B1550D1C6B2E00DDFDAE /* LiveVariables.h */,
- 35F9B1560D1C6B2E00DDFDAE /* UninitializedValues.h */,
- );
- name = Analyses;
- sourceTree = "<group>";
- };
- 57EB5654121B023900ECA335 /* Serialization */ = {
- isa = PBXGroup;
- children = (
- BF9FEDBA1225E30E003A8B71 /* ASTBitCodes.h */,
- 57E15B21121C8D2B0051C2CC /* ASTDeserializationListener.h */,
- 57E15B22121C8D2B0051C2CC /* ASTReader.h */,
- 574F4C25121B4EF000AEAC20 /* ASTWriter.h */,
- );
- name = Serialization;
- sourceTree = "<group>";
- };
- 57EB5660121B034300ECA335 /* Serialization */ = {
- isa = PBXGroup;
- children = (
- 57AA924D121C8B9400B4AA6C /* ASTReader.cpp */,
- 57AA924E121C8B9400B4AA6C /* ASTReaderDecl.cpp */,
- 57AA924F121C8B9400B4AA6C /* ASTReaderStmt.cpp */,
- 57F6660F121B4DE600DCE3B7 /* ASTWriter.cpp */,
- 57F66610121B4DE600DCE3B7 /* ASTWriterDecl.cpp */,
- 57F66611121B4DE600DCE3B7 /* ASTWriterStmt.cpp */,
- );
- name = Serialization;
- path = lib/Serialization;
- sourceTree = "<group>";
- };
- 9012911210470FAF0083456D /* clang-c */ = {
- isa = PBXGroup;
- children = (
- 9012911510470FCE0083456D /* Index.h */,
- );
- name = "clang-c";
- sourceTree = "<group>";
- };
- 9012911E104812DA0083456D /* CIndex */ = {
- isa = PBXGroup;
- children = (
- 9012911F104812F90083456D /* CIndex.cpp */,
- 1A621C3B11111D61009E6834 /* CIndexer.cpp */,
- 1A621C3A11111D61009E6834 /* CIndexCodeCompletion.cpp */,
- 1A621C3C11111D61009E6834 /* CIndexer.h */,
- 1A621C3D11111D61009E6834 /* CIndexInclusionStack.cpp */,
- 1A621C3E11111D61009E6834 /* CIndexUSRs.cpp */,
- 1A621C3F11111D61009E6834 /* CXCursor.cpp */,
- 1A621C4011111D61009E6834 /* CXCursor.h */,
- 1A621C4111111D61009E6834 /* CXSourceLocation.h */,
- );
- name = CIndex;
- sourceTree = "<group>";
- };
- 90F9EFA8104ABDC400D09A15 /* c-index-test */ = {
- isa = PBXGroup;
- children = (
- 90F9EFA9104ABDED00D09A15 /* c-index-test.c */,
- );
- name = "c-index-test";
- sourceTree = "<group>";
- };
- 90FD6D5E103C3D03005F5B73 /* Index */ = {
- isa = PBXGroup;
- children = (
- 90FD6D5F103C3D21005F5B73 /* Analyzer.h */,
- 90FD6D60103C3D21005F5B73 /* ASTLocation.h */,
- 90FD6D61103C3D21005F5B73 /* DeclReferenceMap.h */,
- 90FD6D62103C3D21005F5B73 /* Entity.h */,
- 90FD6D63103C3D21005F5B73 /* GlobalSelector.h */,
- 90FD6D64103C3D21005F5B73 /* Handlers.h */,
- 90FD6D65103C3D21005F5B73 /* Indexer.h */,
- 90FD6D66103C3D21005F5B73 /* IndexProvider.h */,
- 90FD6D67103C3D21005F5B73 /* Program.h */,
- 90FD6D68103C3D21005F5B73 /* SelectorMap.h */,
- 90FD6D69103C3D21005F5B73 /* STLExtras.h */,
- 90FD6D6A103C3D21005F5B73 /* TranslationUnit.h */,
- 90FD6D6B103C3D21005F5B73 /* Utils.h */,
- );
- name = Index;
- sourceTree = "<group>";
- };
- 90FD6D6C103C3D2D005F5B73 /* Index */ = {
- isa = PBXGroup;
- children = (
- 90FD6D6D103C3D49005F5B73 /* Analyzer.cpp */,
- 90FD6D6E103C3D49005F5B73 /* ASTLocation.cpp */,
- 90FD6D6F103C3D49005F5B73 /* ASTVisitor.h */,
- 90FD6D70103C3D49005F5B73 /* DeclReferenceMap.cpp */,
- 90FD6D71103C3D49005F5B73 /* Entity.cpp */,
- 90FD6D72103C3D49005F5B73 /* EntityImpl.h */,
- 90FD6D73103C3D49005F5B73 /* GlobalSelector.cpp */,
- 90FD6D74103C3D49005F5B73 /* Handlers.cpp */,
- 90FD6D75103C3D49005F5B73 /* Indexer.cpp */,
- 90FD6D76103C3D49005F5B73 /* IndexProvider.cpp */,
- 90FD6D77103C3D49005F5B73 /* Program.cpp */,
- 90FD6D78103C3D49005F5B73 /* ProgramImpl.h */,
- 90FD6D7A103C3D49005F5B73 /* SelectorMap.cpp */,
- );
- name = Index;
- sourceTree = "<group>";
- };
- 90FD6DB4103D9763005F5B73 /* index-test */ = {
- isa = PBXGroup;
- children = (
- 90FD6DB5103D977E005F5B73 /* index-test.cpp */,
- );
- name = "index-test";
- sourceTree = "<group>";
- };
- BB20603A131EDDBF003C3343 /* ARRMigrate */ = {
- isa = PBXGroup;
- children = (
- BB20603B131EDDBF003C3343 /* CMakeLists.txt */,
- BB20603C131EDDBF003C3343 /* Makefile */,
- BDDF60E91337BF40009F1764 /* Transforms.cpp */,
- );
- name = ARRMigrate;
- path = lib/ARRMigrate;
- sourceTree = "<group>";
- };
- BB206040131EDDDA003C3343 /* ARRMigrate */ = {
- isa = PBXGroup;
- children = (
- BB206041131EDDDA003C3343 /* ARRMT.h */,
- );
- name = ARRMigrate;
- path = clang/ARRMigrate;
- sourceTree = "<group>";
- };
- BB206042131EDE03003C3343 /* arrmt-test */ = {
- isa = PBXGroup;
- children = (
- BD8A47E7133D32660066FE40 /* ARRMT.cpp */,
- BB206043131EDE03003C3343 /* arrmt-test.cpp */,
- BB206044131EDE03003C3343 /* CMakeLists.txt */,
- BB206045131EDE03003C3343 /* Makefile */,
- );
- name = "arrmt-test";
- path = "tools/arrmt-test";
- sourceTree = "<group>";
- };
- BBA5AB121309C2FA000B38F1 /* StaticAnalyzer */ = {
- isa = PBXGroup;
- children = (
- BBA5AB131309C2FA000B38F1 /* Checkers */,
- BBA5AB511309C2FA000B38F1 /* Core */,
- BBA5AB751309C2FA000B38F1 /* Frontend */,
- );
- name = StaticAnalyzer;
- path = lib/StaticAnalyzer;
- sourceTree = "<group>";
- };
- BBA5AB131309C2FA000B38F1 /* Checkers */ = {
- isa = PBXGroup;
- children = (
- BBA5AB141309C2FA000B38F1 /* AdjustedReturnValueChecker.cpp */,
- BBA5AB151309C2FA000B38F1 /* AnalyzerStatsChecker.cpp */,
- BBA5AB161309C2FA000B38F1 /* ArrayBoundChecker.cpp */,
- BBA5AB171309C2FA000B38F1 /* ArrayBoundCheckerV2.cpp */,
- BBA5AB181309C2FA000B38F1 /* AttrNonNullChecker.cpp */,
- BBA5AB191309C2FA000B38F1 /* BasicObjCFoundationChecks.cpp */,
- BBA5AB1A1309C2FA000B38F1 /* BasicObjCFoundationChecks.h */,
- BBA5AB1B1309C2FA000B38F1 /* BuiltinFunctionChecker.cpp */,
- BBA5AB1C1309C2FA000B38F1 /* CallAndMessageChecker.cpp */,
- BBA5AB1D1309C2FA000B38F1 /* CastSizeChecker.cpp */,
- BBA5AB1E1309C2FA000B38F1 /* CastToStructChecker.cpp */,
- BBA5AB1F1309C2FA000B38F1 /* Checkers.td */,
- BBA5AB201309C2FA000B38F1 /* CheckObjCDealloc.cpp */,
- BBA5AB211309C2FA000B38F1 /* CheckObjCInstMethSignature.cpp */,
- BBA5AB221309C2FA000B38F1 /* CheckSecuritySyntaxOnly.cpp */,
- BBA5AB231309C2FA000B38F1 /* CheckSizeofPointer.cpp */,
- BBA5AB241309C2FA000B38F1 /* ChrootChecker.cpp */,
- BBA5AB251309C2FA000B38F1 /* ClangSACheckerProvider.cpp */,
- BBA5AB261309C2FA000B38F1 /* ClangSACheckerProvider.h */,
- BBA5AB271309C2FA000B38F1 /* ClangSACheckers.h */,
- BBA5AB291309C2FA000B38F1 /* CStringChecker.cpp */,
- BBA5AB2A1309C2FA000B38F1 /* DeadStoresChecker.cpp */,
- BBA5AB2B1309C2FA000B38F1 /* DereferenceChecker.cpp */,
- BBA5AB2C1309C2FA000B38F1 /* DivZeroChecker.cpp */,
- BBA5AB2D1309C2FA000B38F1 /* ExperimentalChecks.cpp */,
- BBA5AB2E1309C2FA000B38F1 /* ExperimentalChecks.h */,
- BBA5AB2F1309C2FA000B38F1 /* ExprEngine.cpp */,
- BBA5AB301309C2FA000B38F1 /* FixedAddressChecker.cpp */,
- BBA5AB311309C2FA000B38F1 /* IdempotentOperationChecker.cpp */,
- BBA5AB321309C2FA000B38F1 /* InternalChecks.h */,
- BBA5AB331309C2FA000B38F1 /* LLVMConventionsChecker.cpp */,
- BBA5AB341309C2FA000B38F1 /* MacOSXAPIChecker.cpp */,
- BBA5AB361309C2FA000B38F1 /* MallocChecker.cpp */,
- BBA5AB371309C2FA000B38F1 /* NoReturnFunctionChecker.cpp */,
- BBA5AB381309C2FA000B38F1 /* NSAutoreleasePoolChecker.cpp */,
- BBA5AB3A1309C2FA000B38F1 /* NSErrorChecker.cpp */,
- BBA5AB3B1309C2FA000B38F1 /* ObjCAtSyncChecker.cpp */,
- BBA5AB3D1309C2FA000B38F1 /* ObjCSelfInitChecker.cpp */,
- BBA5AB3F1309C2FA000B38F1 /* ObjCUnusedIVarsChecker.cpp */,
- BBA5AB401309C2FA000B38F1 /* OSAtomicChecker.cpp */,
- BBA5AB411309C2FA000B38F1 /* PointerArithChecker.cpp */,
- BBA5AB421309C2FA000B38F1 /* PointerSubChecker.cpp */,
- BBA5AB431309C2FA000B38F1 /* PthreadLockChecker.cpp */,
- BBA5AB441309C2FA000B38F1 /* ReturnPointerRangeChecker.cpp */,
- BBA5AB451309C2FA000B38F1 /* ReturnUndefChecker.cpp */,
- BBA5AB461309C2FA000B38F1 /* StackAddrLeakChecker.cpp */,
- BBA5AB471309C2FA000B38F1 /* StreamChecker.cpp */,
- BBA5AB481309C2FA000B38F1 /* UndefBranchChecker.cpp */,
- BBA5AB491309C2FA000B38F1 /* UndefCapturedBlockVarChecker.cpp */,
- BBA5AB4A1309C2FA000B38F1 /* UndefinedArraySubscriptChecker.cpp */,
- BBA5AB4B1309C2FA000B38F1 /* UndefinedAssignmentChecker.cpp */,
- BBA5AB4C1309C2FA000B38F1 /* UndefResultChecker.cpp */,
- BBA5AB4D1309C2FA000B38F1 /* UnixAPIChecker.cpp */,
- BBA5AB4E1309C2FA000B38F1 /* UnreachableCodeChecker.cpp */,
- BBA5AB4F1309C2FA000B38F1 /* VLASizeChecker.cpp */,
- );
- path = Checkers;
- sourceTree = "<group>";
- };
- BBA5AB511309C2FA000B38F1 /* Core */ = {
- isa = PBXGroup;
- children = (
- BBA5AB521309C2FA000B38F1 /* AggExprVisitor.cpp */,
- BBA5AB531309C2FA000B38F1 /* AnalysisManager.cpp */,
- BBA5AB541309C2FA000B38F1 /* BasicConstraintManager.cpp */,
- BBA5AB551309C2FA000B38F1 /* BasicStore.cpp */,
- BBA5AB561309C2FA000B38F1 /* BasicValueFactory.cpp */,
- BBA5AB571309C2FA000B38F1 /* BlockCounter.cpp */,
- BBA5AB581309C2FA000B38F1 /* BugReporter.cpp */,
- BBA5AB591309C2FA000B38F1 /* BugReporterVisitors.cpp */,
- BBA5AB5A1309C2FA000B38F1 /* CFRefCount.cpp */,
- BBA5AB5B1309C2FA000B38F1 /* Checker.cpp */,
- BBA5AB5C1309C2FA000B38F1 /* CheckerHelpers.cpp */,
- BBA5AB5D1309C2FA000B38F1 /* CheckerManager.cpp */,
- BBA5AB5F1309C2FA000B38F1 /* CoreEngine.cpp */,
- BBA5AB601309C2FA000B38F1 /* CXXExprEngine.cpp */,
- BBA5AB611309C2FA000B38F1 /* Environment.cpp */,
- BBA5AB621309C2FA000B38F1 /* ExplodedGraph.cpp */,
- BBA5AB631309C2FA000B38F1 /* FlatStore.cpp */,
- BBA5AB641309C2FA000B38F1 /* GRState.cpp */,
- BBA5AB651309C2FA000B38F1 /* HTMLDiagnostics.cpp */,
- BBA5AB671309C2FA000B38F1 /* MemRegion.cpp */,
- BBA5AB681309C2FA000B38F1 /* ObjCMessage.cpp */,
- BBA5AB691309C2FA000B38F1 /* PathDiagnostic.cpp */,
- BBA5AB6A1309C2FA000B38F1 /* PlistDiagnostics.cpp */,
- BBA5AB6B1309C2FA000B38F1 /* RangeConstraintManager.cpp */,
- BBA5AB6C1309C2FA000B38F1 /* RegionStore.cpp */,
- BBA5AB6D1309C2FA000B38F1 /* SimpleConstraintManager.cpp */,
- BBA5AB6E1309C2FA000B38F1 /* SimpleConstraintManager.h */,
- BBA5AB6F1309C2FA000B38F1 /* SimpleSValBuilder.cpp */,
- BBA5AB701309C2FA000B38F1 /* Store.cpp */,
- BBA5AB711309C2FA000B38F1 /* SValBuilder.cpp */,
- BBA5AB721309C2FA000B38F1 /* SVals.cpp */,
- BBA5AB731309C2FA000B38F1 /* SymbolManager.cpp */,
- BBA5AB741309C2FA000B38F1 /* TextPathDiagnostics.cpp */,
- );
- path = Core;
- sourceTree = "<group>";
- };
- BBA5AB751309C2FA000B38F1 /* Frontend */ = {
- isa = PBXGroup;
- children = (
- BBA5AB761309C2FA000B38F1 /* AnalysisConsumer.cpp */,
- BBA5AB771309C2FA000B38F1 /* AnalysisConsumer.h */,
- BBA5AB781309C2FA000B38F1 /* CheckerRegistration.cpp */,
- BBA5AB7A1309C2FA000B38F1 /* FrontendActions.cpp */,
- );
- path = Frontend;
- sourceTree = "<group>";
- };
- BFE2F67911DA95590007EDC0 /* Rewrite */ = {
- isa = PBXGroup;
- children = (
- BFE2F69311DA955A0007EDC0 /* DeltaTree.cpp */,
- BFE2F69411DA955A0007EDC0 /* FixItRewriter.cpp */,
- BFE2F69511DA955A0007EDC0 /* FrontendActions.cpp */,
- BFE2F69611DA955A0007EDC0 /* HTMLPrint.cpp */,
- BFE2F69711DA955A0007EDC0 /* HTMLRewrite.cpp */,
- BFE2F6A511DA955A0007EDC0 /* RewriteMacros.cpp */,
- BFE2F6A611DA955A0007EDC0 /* RewriteObjC.cpp */,
- BFE2F6A711DA955A0007EDC0 /* Rewriter.cpp */,
- BFE2F6A811DA955A0007EDC0 /* RewriteRope.cpp */,
- BFE2F6A911DA955A0007EDC0 /* RewriteTest.cpp */,
- BFE2F6AA11DA955A0007EDC0 /* TokenRewriter.cpp */,
- );
- name = Rewrite;
- path = lib/Rewrite;
- sourceTree = "<group>";
- };
- C6859E8C029090F304C91782 /* Documentation */ = {
- isa = PBXGroup;
- children = (
- DEAEED4A0A5AF89A0045101B /* NOTES.txt */,
- DED7D7D70A524302003AD0FB /* README.txt */,
- DEEBBD430C19C5D200A9FE82 /* TODO.txt */,
- DEF2E95E0C5FBD74000C4259 /* InternalsManual.html */,
- );
- name = Documentation;
- sourceTree = "<group>";
- };
- DE1F21F20A7D84E800FBF588 /* Parse */ = {
- isa = PBXGroup;
- children = (
- BF9FEDB51225E213003A8B71 /* ParseAST.h */,
- DEA09A860F3175CA000C2258 /* ParseDiagnostic.h */,
- DE1F22020A7D852A00FBF588 /* Parser.h */,
- );
- name = Parse;
- sourceTree = "<group>";
- };
- DE1F22600A7D8C9B00FBF588 /* Parse */ = {
- isa = PBXGroup;
- children = (
- BF9FEE511226FE9F003A8B71 /* ParseAST.cpp */,
- DE34600E0AFDCCCE00DBC861 /* ParseDecl.cpp */,
- DE2255FB0C8004E600D370A5 /* ParseDeclCXX.cpp */,
- DE3460120AFDCCDA00DBC861 /* ParseExpr.cpp */,
- DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */,
- 3534A01C0E129849002709B2 /* ParseCXXInlineMethods.cpp */,
- DE3460040AFDCC6500DBC861 /* ParseInit.cpp */,
- DE345FFF0AFDCC1900DBC861 /* ParseObjc.cpp */,
- 3551068F0E9A857C006A4E44 /* ParsePragma.h */,
- 3551068A0E9A8546006A4E44 /* ParsePragma.cpp */,
- DE34600A0AFDCCBF00DBC861 /* ParseStmt.cpp */,
- 353959D40EE5F88A00E82461 /* ParseTemplate.cpp */,
- 3551068B0E9A8546006A4E44 /* ParseTentative.cpp */,
- DE06D42F0A8BB52D0050E87E /* Parser.cpp */,
- BF9FEE531226FEC1003A8B71 /* RAIIObjectsForParser.h */,
- );
- name = Parse;
- sourceTree = "<group>";
- };
- DE4121130D7F1B980080F80A /* PathSensitive */ = {
- isa = PBXGroup;
- children = (
- 35D55B290D81D8E50092E734 /* BasicValueFactory.h */,
- 359378FF0DA486490043B19C /* BugReporter.h */,
- 3536457C0E2406B0009C6509 /* Environment.h */,
- DE4121200D7F1BBE0080F80A /* ExplodedGraph.h */,
- 35F1ACE60E66166C001F4532 /* ConstraintManager.h */,
- 35F8D0CB0D9B7E8200D91C5E /* GRAuditor.h */,
- DE41211F0D7F1BBE0080F80A /* GRBlockCounter.h */,
- DE4121230D7F1BBE0080F80A /* GRCoreEngine.h */,
- DE4121210D7F1BBE0080F80A /* GRExprEngine.h */,
- 358F514F0E529A87007F2102 /* GRState.h */,
- 3553EB9A0E5F7089007D7359 /* GRStateTrait.h */,
- 35F8D0CA0D9B7E8200D91C5E /* GRSimpleAPICheck.h */,
- DE4121220D7F1BBE0080F80A /* GRTransferFuncs.h */,
- DE41211D0D7F1BBE0080F80A /* GRWorkList.h */,
- 355106880E9A851B006A4E44 /* MemRegion.h */,
- 3558F76F0E267C9A00A5B0DF /* Store.h */,
- 35A057D20EAE2D2B0069249F /* SVals.h */,
- DE41211E0D7F1BBE0080F80A /* SymbolManager.h */,
- );
- name = PathSensitive;
- sourceTree = "<group>";
- };
- DE67E7070C020EAB00F66BC5 /* Sema */ = {
- isa = PBXGroup;
- children = (
- BF9FEDFE1225E6DD003A8B71 /* TargetAttributesSema.cpp */,
- BF9FEDFC1225E6C6003A8B71 /* DeclSpec.cpp */,
- BF9FEDFA1225E6A9003A8B71 /* AttributeList.cpp */,
- BF89C3E111595818001C2D68 /* AnalysisBasedWarnings.cpp */,
- 1A6B6CD110693FC900BB4A8F /* CodeCompleteConsumer.cpp */,
- 352712500DAFE54700C76352 /* IdentifierResolver.cpp */,
- DECB6D640F9AE26600F5FBC7 /* JumpDiagnostics.cpp */,
- DE67E7160C020EE400F66BC5 /* Sema.cpp */,
- 1A701B630F7C8FE400FEC4D1 /* SemaAccess.cpp */,
- DEB07AC70F4A427E00F5A2BE /* SemaAttr.cpp */,
- DEF2F00F0C6CFED5000C4259 /* SemaChecking.cpp */,
- BF89C3FA11595A37001C2D68 /* SemaCodeComplete.cpp */,
- 35E194670ECB82FB00F21733 /* SemaCXXScopeSpec.cpp */,
- DE67E7120C020ED900F66BC5 /* SemaDecl.cpp */,
- DE22BCF10E14197E0094DC60 /* SemaDeclAttr.cpp */,
- 35EF676F0DAD1D2C00B19414 /* SemaDeclCXX.cpp */,
- DE704B250D0FBEBE009C7762 /* SemaDeclObjC.cpp */,
- BF89C3FC11595A5D001C2D68 /* SemaExceptionSpec.cpp */,
- DE67E7100C020ED400F66BC5 /* SemaExpr.cpp */,
- DE47999B0D2EBE1A00706D2D /* SemaExprObjC.cpp */,
- DE67E70E0C020ECF00F66BC5 /* SemaExprCXX.cpp */,
- 3599299A0DE2425300A8A33E /* SemaInit.cpp */,
- 357EA27C0F2526F300439B60 /* SemaLookup.cpp */,
- 1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */,
- 35E194680ECB82FB00F21733 /* SemaCXXCast.cpp */,
- BF89C3E81159594A001C2D68 /* SemaObjCProperty.cpp */,
- 35585DBE0EAFBC4500D0A97A /* SemaOverload.cpp */,
- DE67E70C0C020ECA00F66BC5 /* SemaStmt.cpp */,
- 3591853E0EFB1088000039AF /* SemaTemplate.cpp */,
- BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */,
- 35544B8B0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp */,
- 1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */,
- BF89C3F811595A01001C2D68 /* SemaType.cpp */,
- 1AE4EE3B103B89CA00888A23 /* TreeTransform.h */,
- BF89C3E5115958A1001C2D68 /* TargetAttributesSema.h */,
- );
- name = Sema;
- sourceTree = "<group>";
- };
- DE67E7260C02108300F66BC5 /* Sema */ = {
- isa = PBXGroup;
- children = (
- BF9FEE451225EA24003A8B71 /* DelayedDiagnostic.h */,
- BF9FED781225E041003A8B71 /* SemaInternal.h */,
- BF9FED771225E032003A8B71 /* ObjCMethodList.h */,
- BF9FED731225E005003A8B71 /* Ownership.h */,
- BF9FED741225E005003A8B71 /* ParsedTemplate.h */,
- BF9FED751225E005003A8B71 /* Scope.h */,
- BF9FED761225E005003A8B71 /* ScopeInfo.h */,
- BF9FED711225DFD9003A8B71 /* DeclSpec.h */,
- BF9FED721225DFD9003A8B71 /* Designator.h */,
- BF9FED701225DFA1003A8B71 /* AttributeList.h */,
- BF9FED6F1225DF7F003A8B71 /* Action.h */,
- BF9FED6E1225DF55003A8B71 /* TemplateDeduction.h */,
- BD59A948121496B9003A5A02 /* AnalysisBasedWarnings.h */,
- BD59A949121496B9003A5A02 /* CodeCompleteConsumer.h */,
- BD59A94A121496B9003A5A02 /* CXXFieldCollector.h */,
- BD59A94B121496B9003A5A02 /* ExternalSemaSource.h */,
- BD59A94C121496B9003A5A02 /* IdentifierResolver.h */,
- BD59A94D121496B9003A5A02 /* Initialization.h */,
- BD59A94E121496B9003A5A02 /* Lookup.h */,
- BD59A94F121496B9003A5A02 /* Overload.h */,
- BD59A951121496B9003A5A02 /* Sema.h */,
- BD59A952121496B9003A5A02 /* SemaConsumer.h */,
- BD59A953121496B9003A5A02 /* SemaDiagnostic.h */,
- BD59A954121496B9003A5A02 /* Template.h */,
- );
- name = Sema;
- sourceTree = "<group>";
- };
- DE927FCC0C0557CD00231DA4 /* CodeGen */ = {
- isa = PBXGroup;
- children = (
- BF9FEE361225E8CF003A8B71 /* README.txt */,
- BF9FEE341225E8B1003A8B71 /* MicrosoftCXXABI.cpp */,
- BF9FEE321225E898003A8B71 /* ItaniumCXXABI.cpp */,
- BF9FEE301225E86C003A8B71 /* CodeGenAction.cpp */,
- BF9FEE2F1225E854003A8B71 /* CGRecordLayout.h */,
- BF9FEE2E1225E82D003A8B71 /* CGException.h */,
- 1A3D2C4D12A2CD3D0088C44A /* CGCXXABI.cpp */,
- BF9FEE2D1225E80F003A8B71 /* CGCXXABI.h */,
- BF9FEE2B1225E7EA003A8B71 /* BackendUtil.cpp */,
- 1A2193CB0F45EEB700C0713D /* ABIInfo.h */,
- 1A471AB40F437BC500753CE8 /* CGBlocks.cpp */,
- 1A649E1D0F9599D9005B965E /* CGBlocks.h */,
- DE8822350EC80C0A00CBC30A /* CGBuilder.h */,
- 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */,
- 35475B1F0E79973F0000BFE4 /* CGCall.cpp */,
- 35475B220E7997680000BFE4 /* CGCall.h */,
- 1A4C41BE105B4C0B0047B5E7 /* CGClass.cpp */,
- 1A5D5E570E5E81010023C059 /* CGCXX.cpp */,
- 1A649E1E0F9599DA005B965E /* CGCXX.h */,
- 35A3E7000DD3874400757F74 /* CGDebugInfo.cpp */,
- 35A3E7010DD3874400757F74 /* CGDebugInfo.h */,
- DE4264FB0C113592005A861D /* CGDecl.cpp */,
- 1A986AB610D0746D00A8EA9E /* CGDeclCXX.cpp */,
- 1AF1B50E109A4FB800AFAFAC /* CGException.cpp */,
- DE4772FB0C10EAEC002239E8 /* CGExpr.cpp */,
- DEF2EFF20C6CDD74000C4259 /* CGExprAgg.cpp */,
- 1A6B6E991069833600BB4A8F /* CGExprCXX.cpp */,
- DE224FF70C7AA98800D370A5 /* CGExprComplex.cpp */,
- 1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */,
- DE22526F0C7E82D000D370A5 /* CGExprScalar.cpp */,
- 1A7342470C7B57D500122F56 /* CGObjC.cpp */,
- DE38CD4E0D794CF900A273B6 /* CGObjCRuntime.h */,
- DE38CD4F0D794D0100A273B6 /* CGObjCGNU.cpp */,
- 3552E7580E520DD7003A8CA5 /* CGObjCMac.cpp */,
- 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */,
- 1A6C01F6108128710072DEE4 /* CGRTTI.cpp */,
- DE4772F90C10EAE5002239E8 /* CGStmt.cpp */,
- 1A6FE7080FD6F85800E00CA9 /* CGTemporaries.cpp */,
- 35475B230E7997680000BFE4 /* CGValue.h */,
- 1A81AA18108144F40094E50B /* CGVTables.cpp */,
- 1A81AA5D108278A20094E50B /* CGVTables.h */,
- 1A97825A1108BA18002B98FC /* CGVTT.cpp */,
- DE928B800C0A615B00231DA4 /* CodeGenFunction.h */,
- DE928B820C0A616000231DA4 /* CodeGenFunction.cpp */,
- DE928B7C0C0A615100231DA4 /* CodeGenModule.h */,
- DE928B7E0C0A615600231DA4 /* CodeGenModule.cpp */,
- DEEBC3BB0C2363BC00A9FE82 /* CodeGenTypes.cpp */,
- DEEBC3B90C2363B800A9FE82 /* CodeGenTypes.h */,
- 1A31B27210ACE6DA009E0C8B /* GlobalDecl.h */,
- 1A2193CC0F45EEB700C0713D /* Mangle.cpp */,
- 1A2193CD0F45EEB700C0713D /* Mangle.h */,
- DE928B120C05659200231DA4 /* ModuleBuilder.cpp */,
- 1A621BB5110FE6AA009E6834 /* TargetInfo.cpp */,
- 1A621BB6110FE6AA009E6834 /* TargetInfo.h */,
- );
- name = CodeGen;
- sourceTree = "<group>";
- };
- DE928B140C05659A00231DA4 /* CodeGen */ = {
- isa = PBXGroup;
- children = (
- BF9FEDB81225E2DE003A8B71 /* BackendUtil.h */,
- BF9FEDB91225E2DE003A8B71 /* CodeGenAction.h */,
- DE928B1F0C0565B000231DA4 /* ModuleBuilder.h */,
- );
- name = CodeGen;
- sourceTree = "<group>";
- };
- DEC8D98B0A9433BC00353FCA /* AST */ = {
- isa = PBXGroup;
- children = (
- BF9FEDB71225E26A003A8B71 /* RecursiveASTVisitor.h */,
- BF9FEDB61225E252003A8B71 /* OperationKinds.h */,
- 1A15C407118226980092260D /* ASTImporter.h */,
- 1A15C408118226980092260D /* ASTVector.h */,
- 1A15C409118226980092260D /* CharUnits.h */,
- 1A15C40A118226980092260D /* DeclAccessPair.h */,
- 1A15C40B118226980092260D /* DeclFriend.h */,
- 1A15C40C118226980092260D /* DependentDiagnostic.h */,
- 1A15C40D118226980092260D /* TemplateBase.h */,
- 1A15C40E118226980092260D /* UnresolvedSet.h */,
- 1A15C40F118226980092260D /* UsuallyTinyPtrVector.h */,
- 904753791096376F00CBDDDD /* CXXInheritance.h */,
- 9047537A1096376F00CBDDDD /* Redeclarable.h */,
- 9047537B1096376F00CBDDDD /* TypeLoc.h */,
- 9047537C1096376F00CBDDDD /* TypeLocBuilder.h */,
- 9047537D1096376F00CBDDDD /* TypeLocNodes.def */,
- 9047537E1096376F00CBDDDD /* TypeLocVisitor.h */,
- 9047537F1096376F00CBDDDD /* TypeVisitor.h */,
- DE613EF30E0E148D00B05B79 /* APValue.h */,
- DEC8D9A30A94346E00353FCA /* AST.h */,
- 35BFBD2B0C9EDE1E006CB644 /* ASTConsumer.h */,
- DE75ED280B044DC90020CF81 /* ASTContext.h */,
- DEA09A6E0F31756F000C2258 /* ASTDiagnostic.h */,
- 1A72BEAC0D641E9400B085E9 /* Attr.h */,
- 1A535EDB107BC47B000C3AE7 /* CanonicalType.h */,
- 90FB99DE0F98FB1D008F9415 /* DeclContextInternals.h */,
- 90FB99DF0F98FB1D008F9415 /* DeclVisitor.h */,
- 90FB99E00F98FB1D008F9415 /* ExternalASTSource.h */,
- DEC8D9900A9433CD00353FCA /* Decl.h */,
- 3538FDB60ED24A2C005EC283 /* DeclarationName.h */,
- 035611470DA6A45C00D2EF2A /* DeclBase.h */,
- 84AF36A00CB17A3B00C820A5 /* DeclObjC.h */,
- 35EE48AD0E0C4CB200715C54 /* DeclCXX.h */,
- 358D23090E8BEB850003DDCC /* DeclGroup.h */,
- DEB076C90F3A221200F5A2BE /* DeclTemplate.h */,
- DE0FCA620A95859D00248FD5 /* Expr.h */,
- 1A30A9E80B93A4C800201A91 /* ExprCXX.h */,
- 35CEA05A0DF9E82700A41296 /* ExprObjC.h */,
- 1AA963AB10D8576800786C86 /* FullExpr.h */,
- DEDFE5CB0F7206CC0035BD10 /* NestedNameSpecifier.h */,
- 35EE48AE0E0C4CB200715C54 /* ParentMap.h */,
- 3547129D0C88881300B3E1D5 /* PrettyPrinter.h */,
- DE6951C60C4D1F5D00A5826B /* RecordLayout.h */,
- DE3452800AEF1B1800DBC861 /* Stmt.h */,
- DECB73550FA3EE5A00F5FBC7 /* StmtCXX.h */,
- DECB734E0FA3ED8400F5FBC7 /* StmtObjC.h */,
- DE345C190AFC658B00DBC861 /* StmtVisitor.h */,
- 35847BE30CC7DB9000C40FFF /* StmtIterator.h */,
- 35CFFE010CA1CBDD00E6F2BE /* StmtGraphTraits.h */,
- DEDFF87F0F848CE30035BD10 /* TemplateName.h */,
- DEF16BE40FA13A5B0098507F /* TypeNodes.def */,
- DEF16BE50FA13A650098507F /* TypeOrdering.h */,
- DE3464210B03040900DBC861 /* Type.h */,
- );
- name = AST;
- sourceTree = "<group>";
- };
- DEC8D9920A9433F400353FCA /* AST */ = {
- isa = PBXGroup;
- children = (
- BD6B0EDE13A1824C00B8E3FE /* Mangle.cpp */,
- BD6B0EE313A182DA00B8E3FE /* MicrosoftMangle.cpp */,
- BD6B0EE113A182A600B8E3FE /* ItaniumMangle.cpp */,
- BF9FEE051225E770003A8B71 /* MicrosoftCXXABI.cpp */,
- BF9FEE031225E759003A8B71 /* ItaniumCXXABI.cpp */,
- BF9FEE011225E73F003A8B71 /* ExprClassification.cpp */,
- BF9FEE001225E718003A8B71 /* CXXABI.h */,
- 1ABD23B11182449800A48E65 /* APValue.cpp */,
- 1ABD23B21182449800A48E65 /* ASTConsumer.cpp */,
- 1ABD23B31182449800A48E65 /* ASTContext.cpp */,
- 1ABD23B41182449800A48E65 /* ASTDiagnostic.cpp */,
- 1ABD23B51182449800A48E65 /* ASTImporter.cpp */,
- 1ABD23B61182449800A48E65 /* AttrImpl.cpp */,
- 1ABD23B71182449800A48E65 /* CXXInheritance.cpp */,
- 1ABD23B81182449800A48E65 /* Decl.cpp */,
- 1ABD23B91182449800A48E65 /* DeclarationName.cpp */,
- 1ABD23BA1182449800A48E65 /* DeclBase.cpp */,
- 1ABD23BB1182449800A48E65 /* DeclCXX.cpp */,
- 1ABD23BC1182449800A48E65 /* DeclFriend.cpp */,
- 1ABD23BD1182449800A48E65 /* DeclGroup.cpp */,
- 1ABD23BE1182449800A48E65 /* DeclObjC.cpp */,
- 1ABD23BF1182449800A48E65 /* DeclPrinter.cpp */,
- 1ABD23C01182449800A48E65 /* DeclTemplate.cpp */,
- BB5C372812A5057500259F53 /* DumpXML.cpp */,
- 1ABD23C11182449800A48E65 /* Expr.cpp */,
- 1ABD23C21182449800A48E65 /* ExprConstant.cpp */,
- 1ABD23C31182449800A48E65 /* ExprCXX.cpp */,
- 1ABD23C41182449800A48E65 /* FullExpr.cpp */,
- 1ABD23C51182449800A48E65 /* InheritViz.cpp */,
- 1ABD23C61182449800A48E65 /* NestedNameSpecifier.cpp */,
- 1ABD23C71182449800A48E65 /* ParentMap.cpp */,
- 1ABD23C81182449800A48E65 /* RecordLayout.cpp */,
- 1ABD23C91182449800A48E65 /* RecordLayoutBuilder.cpp */,
- 1ABD23CB1182449800A48E65 /* Stmt.cpp */,
- 1ABD23CC1182449800A48E65 /* StmtDumper.cpp */,
- 1ABD23CD1182449800A48E65 /* StmtIterator.cpp */,
- 1ABD23CE1182449800A48E65 /* StmtPrinter.cpp */,
- 1ABD23CF1182449800A48E65 /* StmtProfile.cpp */,
- 1ABD23D01182449800A48E65 /* StmtViz.cpp */,
- 1ABD23D11182449800A48E65 /* TemplateBase.cpp */,
- 1ABD23D21182449800A48E65 /* TemplateName.cpp */,
- 1ABD23D31182449800A48E65 /* Type.cpp */,
- 1ABD23D41182449800A48E65 /* TypeLoc.cpp */,
- 1ABD23D51182449800A48E65 /* TypePrinter.cpp */,
- );
- name = AST;
- path = lib/AST;
- sourceTree = "<group>";
- };
- DED7D72E0A524295003AD0FB /* include */ = {
- isa = PBXGroup;
- children = (
- BB206040131EDDDA003C3343 /* ARRMigrate */,
- DED7D7300A524295003AD0FB /* Basic */,
- DED7D7390A524295003AD0FB /* Lex */,
- DE1F21F20A7D84E800FBF588 /* Parse */,
- DEC8D98B0A9433BC00353FCA /* AST */,
- DE67E7260C02108300F66BC5 /* Sema */,
- DE928B140C05659A00231DA4 /* CodeGen */,
- 356EF9AF0C8F7DA4006650F5 /* Analysis */,
- 57EB5654121B023900ECA335 /* Serialization */,
- 90FD6D5E103C3D03005F5B73 /* Index */,
- DEF7D9F40C9C8B020001F598 /* Rewrite */,
- DEF1615D0F65C7FC0098507F /* Frontend */,
- DEF165020F8D46810098507F /* Driver */,
- 9012911210470FAF0083456D /* clang-c */,
- );
- path = include;
- sourceTree = "<group>";
- };
- DED7D7300A524295003AD0FB /* Basic */ = {
- isa = PBXGroup;
- children = (
- BF9FEDF71225E613003A8B71 /* DiagnosticCategories.td */,
- BF9FEDF61225E5FB003A8B71 /* Version.inc.in */,
- BF9FEDF41225E5D5003A8B71 /* Linkage.h */,
- BF9FEDF51225E5D5003A8B71 /* MacroBuilder.h */,
- BF9FEDF31225E5B6003A8B71 /* DeclNodes.td */,
- BF9FEDF21225E58B003A8B71 /* TargetOptions.h */,
- BF9FEDF01225E574003A8B71 /* Specifiers.h */,
- BF9FEDF11225E574003A8B71 /* StmtNodes.td */,
- BF9FEDEF1225E55C003A8B71 /* BuiltinsARM.def */,
- BF9FEDED1225E52F003A8B71 /* arm_neon.td */,
- BF9FEDEE1225E52F003A8B71 /* Attr.td */,
- BF9FEDEC1225E514003A8B71 /* Version.h */,
- BF9FEDEB1225E4F2003A8B71 /* AttrKinds.h */,
- DE37251C0FE4818000CF2CC2 /* Builtins.h */,
- DE37252A0FE4818F00CF2CC2 /* Builtins.def */,
- DE3725330FE4827200CF2CC2 /* BuiltinsPPC.def */,
- DE3725320FE4826C00CF2CC2 /* BuiltinsX86.def */,
- 906BF4AE0F83BA16001071FA /* ConvertUTF.h */,
- DED7D7310A524295003AD0FB /* Diagnostic.h */,
- DEDFFF070F959EE60035BD10 /* Diagnostic.td */,
- 1A7019E90F79BC1100FEC4D1 /* DiagnosticAnalysisKinds.td */,
- 1A7019EA0F79BC1100FEC4D1 /* DiagnosticASTKinds.td */,
- 1A7019EB0F79BC1100FEC4D1 /* DiagnosticCommonKinds.td */,
- 1A7019EC0F79BC1100FEC4D1 /* DiagnosticDriverKinds.td */,
- 1A7019ED0F79BC1100FEC4D1 /* DiagnosticFrontendKinds.td */,
- DEDFFF530F9704580035BD10 /* DiagnosticGroups.td */,
- 1A7019EE0F79BC1100FEC4D1 /* DiagnosticLexKinds.td */,
- 1A7019EF0F79BC1100FEC4D1 /* DiagnosticParseKinds.td */,
- 1A701A250F79CE1C00FEC4D1 /* DiagnosticSemaKinds.td */,
- DED7D7330A524295003AD0FB /* FileManager.h */,
- DE3986EF0CB8D4B300223765 /* IdentifierTable.h */,
- DE06B73D0A8307640050E87E /* LangOptions.h */,
- 9063F2280F9E911F002F7251 /* OnDiskHashTable.h */,
- DE8824560ED1244600CBC30A /* OperatorKinds.def */,
- DE8824530ED1243E00CBC30A /* OperatorKinds.h */,
- 1AB290021045858B00FE33D8 /* PartialDiagnostic.h */,
- DEAABDF70F5F477C0098928A /* PrettyStackTrace.h */,
- DED7D7350A524295003AD0FB /* SourceLocation.h */,
- DED7D7360A524295003AD0FB /* SourceManager.h */,
- 9063F2290F9E911F002F7251 /* SourceManagerInternals.h */,
- DE3725310FE4822800CF2CC2 /* TargetBuiltins.h */,
- DE46BF270AE0A82D00CC047C /* TargetInfo.h */,
- 9063F22A0F9E911F002F7251 /* TemplateKinds.h */,
- DED7D7380A524295003AD0FB /* TokenKinds.h */,
- DED7D7370A524295003AD0FB /* TokenKinds.def */,
- DEB089EE0F12F1D900522C07 /* TypeTraits.h */,
- );
- name = Basic;
- path = clang/Basic;
- sourceTree = "<group>";
- };
- DED7D7390A524295003AD0FB /* Lex */ = {
- isa = PBXGroup;
- children = (
- BF9FEDB41225E1F3003A8B71 /* PreprocessingRecord.h */,
- BF9FEDB31225E1E1003A8B71 /* ExternalPreprocessorSource.h */,
- BF9FEDB21225E1D2003A8B71 /* CodeCompletionHandler.h */,
- DE3450D60AEB543100DBC861 /* DirectoryLookup.h */,
- DE704BD10D1647E7009C7762 /* HeaderMap.h */,
- DE344AB70AE5DF6D00DBC861 /* HeaderSearch.h */,
- DEA09A830F3175BF000C2258 /* LexDiagnostic.h */,
- DED7D73B0A524295003AD0FB /* Lexer.h */,
- 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */,
- DED7D73E0A524295003AD0FB /* MacroInfo.h */,
- DEAEE98A0A5A2B970045101B /* MultipleIncludeOpt.h */,
- DE01DA480B12ADA300AC22CE /* PPCallbacks.h */,
- DE8823DE0ED0B78600CBC30A /* PTHLexer.h */,
- 3598EBEB0EDE23EF0070CA16 /* PTHManager.h */,
- DED7D73F0A524295003AD0FB /* Pragma.h */,
- DED7D7400A524295003AD0FB /* Preprocessor.h */,
- 35B820740ECB811A0020BEC0 /* PreprocessorLexer.h */,
- DED7D9170A52518C003AD0FB /* ScratchBuffer.h */,
- DE6954630C5121BD00A5826B /* Token.h */,
- DEB077930F44F96000F5A2BE /* TokenConcatenation.h */,
- DE85CD840D8380F20070E26E /* TokenLexer.h */,
- );
- name = Lex;
- path = clang/Lex;
- sourceTree = "<group>";
- };
- DED7D7500A5242C7003AD0FB /* Basic */ = {
- isa = PBXGroup;
- children = (
- DE37252D0FE481AD00CF2CC2 /* Builtins.cpp */,
- 906BF4AF0F83BA2E001071FA /* ConvertUTF.c */,
- DED7D75D0A5242C7003AD0FB /* Diagnostic.cpp */,
- DED7D75E0A5242C7003AD0FB /* FileManager.cpp */,
- DE3986F30CB8D50C00223765 /* IdentifierTable.cpp */,
- 35707EFD0CD0F5CC000B2204 /* SourceLocation.cpp */,
- DED7D76D0A5242C7003AD0FB /* SourceManager.cpp */,
- DED626C80AE0C065001E80A4 /* TargetInfo.cpp */,
- 03F50AC50D416EAA00B9CF60 /* Targets.cpp */,
- DED7D76E0A5242C7003AD0FB /* TokenKinds.cpp */,
- );
- name = Basic;
- path = lib/Basic;
- sourceTree = "<group>";
- };
- DED7D78C0A5242E6003AD0FB /* Lex */ = {
- isa = PBXGroup;
- children = (
- BF9FEEF1122D8068003A8B71 /* PreprocessingRecord.cpp */,
- DE704DD10D1668A4009C7762 /* HeaderMap.cpp */,
- DE344B530AE5E46C00DBC861 /* HeaderSearch.cpp */,
- DED7D79E0A5242E6003AD0FB /* Lexer.cpp */,
- 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */,
- DE85CD9E0D8382DD0070E26E /* MacroArgs.h */,
- DE85CDA20D8383B20070E26E /* MacroArgs.cpp */,
- DED7D7A00A5242E6003AD0FB /* MacroInfo.cpp */,
- 3552E7540E520D80003A8CA5 /* PPCaching.cpp */,
- DE85CDAF0D838C390070E26E /* PPDirectives.cpp */,
- DED7D7A20A5242E6003AD0FB /* PPExpressions.cpp */,
- DE85CDB50D839BAE0070E26E /* PPLexerChange.cpp */,
- DE85CDAB0D838C120070E26E /* PPMacroExpansion.cpp */,
- DED7D7A30A5242E6003AD0FB /* Pragma.cpp */,
- DED7D7A40A5242E6003AD0FB /* Preprocessor.cpp */,
- 3537AA0D0ECD08A4008F7CDC /* PreprocessorLexer.cpp */,
- 35E1946C0ECB83C100F21733 /* PTHLexer.cpp */,
- DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */,
- DEB077980F44F97800F5A2BE /* TokenConcatenation.cpp */,
- DE85CD800D8380B10070E26E /* TokenLexer.cpp */,
- );
- name = Lex;
- path = lib/Lex;
- sourceTree = "<group>";
- };
- DEDFE61F0F7B3AE10035BD10 /* Tools */ = {
- isa = PBXGroup;
- children = (
- BB206042131EDE03003C3343 /* arrmt-test */,
- 90F9EFA8104ABDC400D09A15 /* c-index-test */,
- 9012911E104812DA0083456D /* CIndex */,
- 90FD6DB4103D9763005F5B73 /* index-test */,
- DEDFE6210F7B3AF10035BD10 /* clang */,
- );
- name = Tools;
- sourceTree = "<group>";
- };
- DEDFE6210F7B3AF10035BD10 /* clang */ = {
- isa = PBXGroup;
- children = (
- E16B523410D30B2400430AC9 /* cc1_main.cpp */,
- DEDFE6450F7B3B4E0035BD10 /* driver.cpp */,
- );
- name = clang;
- sourceTree = "<group>";
- };
- DEDFE6470F7B3B560035BD10 /* Driver */ = {
- isa = PBXGroup;
- children = (
- DEDFE6480F7B3B830035BD10 /* Types.cpp */,
- DEDFE6490F7B3B830035BD10 /* Tools.h */,
- DEDFE64A0F7B3B830035BD10 /* Tools.cpp */,
- DEDFE64B0F7B3B830035BD10 /* ToolChains.h */,
- DEDFE64C0F7B3B830035BD10 /* Compilation.cpp */,
- DEDFE64D0F7B3B830035BD10 /* ArgList.cpp */,
- DEDFE64E0F7B3B830035BD10 /* Arg.cpp */,
- DEDFE64F0F7B3B830035BD10 /* Action.cpp */,
- DEDFE6500F7B3B830035BD10 /* Phases.cpp */,
- DEDFE6510F7B3B830035BD10 /* OptTable.cpp */,
- DEDFE6520F7B3B830035BD10 /* Option.cpp */,
- DEDFE6530F7B3B830035BD10 /* Job.cpp */,
- DEDFE6540F7B3B830035BD10 /* InputInfo.h */,
- DEDFE6550F7B3B830035BD10 /* ToolChains.cpp */,
- DEDFE6560F7B3B830035BD10 /* ToolChain.cpp */,
- DEDFE6570F7B3B830035BD10 /* Tool.cpp */,
- DEDFE6580F7B3B830035BD10 /* HostInfo.cpp */,
- DEDFE6590F7B3B830035BD10 /* Driver.cpp */,
- );
- name = Driver;
- sourceTree = "<group>";
- };
- DEF1615D0F65C7FC0098507F /* Frontend */ = {
- isa = PBXGroup;
- children = (
- BF9FEDCE1225E42C003A8B71 /* VerifyDiagnosticsClient.h */,
- BF9FEDCC1225E41D003A8B71 /* PreprocessorOptions.h */,
- BF9FEDCD1225E41D003A8B71 /* PreprocessorOutputOptions.h */,
- BF9FEDC81225E40A003A8B71 /* FrontendOptions.h */,
- BF9FEDC91225E40A003A8B71 /* FrontendPluginRegistry.h */,
- BF9FEDCA1225E40A003A8B71 /* HeaderSearchOptions.h */,
- BF9FEDCB1225E40A003A8B71 /* LangStandard.h */,
- BF9FEDC61225E3F6003A8B71 /* FrontendAction.h */,
- BF9FEDC71225E3F6003A8B71 /* FrontendActions.h */,
- BF9FEDC41225E3DA003A8B71 /* DependencyOutputOptions.h */,
- BF9FEDC51225E3DA003A8B71 /* DiagnosticOptions.h */,
- BF9FEDC21225E3C2003A8B71 /* CompilerInstance.h */,
- BF9FEDC31225E3C2003A8B71 /* CompilerInvocation.h */,
- BF9FEDC01225E3AB003A8B71 /* ChainedDiagnosticClient.h */,
- BF9FEDC11225E3AB003A8B71 /* CodeGenOptions.h */,
- BF9FEDBF1225E392003A8B71 /* AnalyzerOptions.h */,
- 90FD6D86103C3D80005F5B73 /* Analyses.def */,
- 90FD6D88103C3D80005F5B73 /* ASTConsumers.h */,
- 90FD6D89103C3D80005F5B73 /* ASTUnit.h */,
- 90FD6D8A103C3D80005F5B73 /* CommandLineSourceLoc.h */,
- 90FD6D8B103C3D80005F5B73 /* DeclContextXML.def */,
- 90FD6D8C103C3D80005F5B73 /* DeclXML.def */,
- 90FD6D8D103C3D80005F5B73 /* DocumentXML.def */,
- BF9FEDCF1225E443003A8B71 /* LangStandards.def */,
- 90FD6D8E103C3D80005F5B73 /* DocumentXML.h */,
- 90FD6D8F103C3D80005F5B73 /* StmtXML.def */,
- 90FD6D90103C3D80005F5B73 /* TypeXML.def */,
- 90FD6D91103C3D80005F5B73 /* Utils.h */,
- DEF169220F9645960098507F /* FrontendDiagnostic.h */,
- DEF161600F65C81C0098507F /* TextDiagnosticBuffer.h */,
- DEF161630F65C81C0098507F /* TextDiagnosticPrinter.h */,
- );
- name = Frontend;
- sourceTree = "<group>";
- };
- DEF165020F8D46810098507F /* Driver */ = {
- isa = PBXGroup;
- children = (
- BF9FEDE91225E4BD003A8B71 /* OptSpecifier.h */,
- BF9FEDEA1225E4BD003A8B71 /* OptTable.h */,
- BF9FEDE81225E49D003A8B71 /* CC1Options.h */,
- BF9FEDE71225E488003A8B71 /* CC1AsOptions.h */,
- DEF165160F8D46980098507F /* Action.h */,
- DEF1651D0F8D46980098507F /* ArgList.h */,
- DEF1651E0F8D46980098507F /* Arg.h */,
- 1AA1D35611BECFF70089CC3F /* CC1AsOptions.td */,
- 1AA1D35711BECFF70089CC3F /* CC1Options.td */,
- DEF165170F8D46980098507F /* Compilation.h */,
- DEF165240F8D46980098507F /* DriverDiagnostic.h */,
- DEF165200F8D46980098507F /* Driver.h */,
- DEF1651F0F8D46980098507F /* HostInfo.h */,
- DEF165210F8D46980098507F /* Job.h */,
- DEF165190F8D46980098507F /* Option.h */,
- 1AA1D35811BECFF70089CC3F /* Options.td */,
- DEF1651C0F8D46980098507F /* Options.h */,
- 1AA1D35911BECFF70089CC3F /* OptParser.td */,
- DEF165230F8D46980098507F /* Phases.h */,
- DEF165140F8D46980098507F /* Tool.h */,
- DEF165150F8D46980098507F /* Types.h */,
- DEF1651A0F8D46980098507F /* Types.def */,
- DEF1651B0F8D46980098507F /* ToolChain.h */,
- DEF165220F8D46980098507F /* Util.h */,
- );
- name = Driver;
- sourceTree = "<group>";
- };
- DEF7D9F40C9C8B020001F598 /* Rewrite */ = {
- isa = PBXGroup;
- children = (
- BF9FEDBE1225E373003A8B71 /* ASTConsumers.h */,
- BF9FEDBD1225E35F003A8B71 /* Rewriters.h */,
- BF9FEDBB1225E34B003A8B71 /* FixItRewriter.h */,
- BF9FEDBC1225E34B003A8B71 /* FrontendActions.h */,
- DEFFECA30DB093D100B4E7C3 /* DeltaTree.h */,
- 35F2BE7B0DAC2963006E7668 /* HTMLRewrite.h */,
- DEF7D9F60C9C8B1A0001F598 /* Rewriter.h */,
- DE53370B0CE2D96F00D9A028 /* RewriteRope.h */,
- DE4DC7980EA1BE4400069E5A /* TokenRewriter.h */,
- );
- name = Rewrite;
- sourceTree = "<group>";
- };
- DEF7D9F50C9C8B0C0001F598 /* Rewrite */ = {
- isa = PBXGroup;
- children = (
- DEFFECA60DB1546600B4E7C3 /* DeltaTree.cpp */,
- 72D16C1E0D9975C400E6DA4A /* HTMLRewrite.cpp */,
- DEF7D9F80C9C8B1D0001F598 /* Rewriter.cpp */,
- DECAB0CF0DB3C84200E13CCB /* RewriteRope.cpp */,
- );
- name = Rewrite;
- sourceTree = "<group>";
- };
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
- 8DD76F620486A84900D96B5E /* clang */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "clang" */;
- buildPhases = (
- 8DD76F640486A84900D96B5E /* Sources */,
- 8DD76F660486A84900D96B5E /* Frameworks */,
- 8DD76F690486A84900D96B5E /* CopyFiles */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = clang;
- productInstallPath = "$(HOME)/bin";
- productName = clang;
- productReference = 8DD76F6C0486A84900D96B5E /* clang */;
- productType = "com.apple.product-type.tool";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- 08FB7793FE84155DC02AAC07 /* Project object */ = {
- isa = PBXProject;
- buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
- compatibilityVersion = "Xcode 2.4";
- developmentRegion = English;
- hasScannedForEncodings = 1;
- knownRegions = (
- English,
- Japanese,
- French,
- German,
- );
- mainGroup = 08FB7794FE84155DC02AAC07 /* clang */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- 8DD76F620486A84900D96B5E /* clang */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXSourcesBuildPhase section */
- 8DD76F640486A84900D96B5E /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- BD6B0EDF13A1824C00B8E3FE /* Mangle.cpp in Sources */,
- BD6B0EE213A182A600B8E3FE /* ItaniumMangle.cpp in Sources */,
- BD6B0EE413A182DA00B8E3FE /* MicrosoftMangle.cpp in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin XCBuildConfiguration section */
- 1DEB923208733DC60010E9CD /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ARCHS = "$(NATIVE_ARCH_ACTUAL)";
- COPY_PHASE_STRIP = NO;
- GCC_CW_ASM_SYNTAX = NO;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_ENABLE_CPP_EXCEPTIONS = NO;
- GCC_ENABLE_CPP_RTTI = NO;
- GCC_ENABLE_PASCAL_STRINGS = NO;
- GCC_ENABLE_SYMBOL_SEPARATION = NO;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = (
- __STDC_CONSTANT_MACROS,
- "__STDC_LIMIT_MACROS=1",
- );
- GCC_STRICT_ALIASING = YES;
- GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- GCC_THREADSAFE_STATICS = NO;
- GCC_USE_GCC3_PFE_SUPPORT = NO;
- INSTALL_PATH = "$(HOME)/bin";
- OTHER_LDFLAGS = (
- "-lLLVMBitWriter",
- "-lLLVMBitReader",
- "-lLLVMAsmPrinter",
- "-lLLVMSelectionDAG",
- "-lLLVMCodeGen",
- "-lLLVMipo",
- "-lLLVMScalarOpts",
- "-lLLVMTransformUtils",
- "-lLLVMipa",
- "-lLLVMAnalysis",
- "-lLLVMTarget",
- "-lLLVMCore",
- "-lLLVMSupport",
- "-lLLVMSystem",
- );
- PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
- PRODUCT_NAME = clang;
- };
- name = Debug;
- };
- 1DEB923308733DC60010E9CD /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ARCHS = "$(NATIVE_ARCH_ACTUAL)";
- GCC_CW_ASM_SYNTAX = NO;
- GCC_ENABLE_CPP_EXCEPTIONS = NO;
- GCC_ENABLE_CPP_RTTI = NO;
- GCC_ENABLE_PASCAL_STRINGS = NO;
- GCC_ENABLE_SYMBOL_SEPARATION = NO;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
- GCC_PREPROCESSOR_DEFINITIONS = (
- __STDC_CONSTANT_MACROS,
- "__STDC_LIMIT_MACROS=1",
- );
- GCC_STRICT_ALIASING = YES;
- GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- GCC_THREADSAFE_STATICS = NO;
- GCC_USE_GCC3_PFE_SUPPORT = NO;
- INSTALL_PATH = "$(HOME)/bin";
- OTHER_LDFLAGS = (
- "-lLLVMBitWriter",
- "-lLLVMBitReader",
- "-lLLVMAsmPrinter",
- "-lLLVMSelectionDAG",
- "-lLLVMCodeGen",
- "-lLLVMipo",
- "-lLLVMScalarOpts",
- "-lLLVMTransformUtils",
- "-lLLVMipa",
- "-lLLVMAnalysis",
- "-lLLVMTarget",
- "-lLLVMCore",
- "-lLLVMSupport",
- "-lLLVMSystem",
- );
- PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
- PRODUCT_NAME = clang;
- };
- name = Release;
- };
- 1DEB923608733DC60010E9CD /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- GCC_VERSION = "";
- GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- HEADER_SEARCH_PATHS = (
- ../../include,
- include,
- );
- LIBRARY_SEARCH_PATHS = ../../Debug/lib;
- OTHER_LDFLAGS = "";
- PREBINDING = NO;
- };
- name = Debug;
- };
- 1DEB923708733DC60010E9CD /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- HEADER_SEARCH_PATHS = (
- ../../include,
- include,
- );
- LIBRARY_SEARCH_PATHS = ../../Release;
- OTHER_LDFLAGS = "";
- PREBINDING = NO;
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "clang" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 1DEB923208733DC60010E9CD /* Debug */,
- 1DEB923308733DC60010E9CD /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 1DEB923608733DC60010E9CD /* Debug */,
- 1DEB923708733DC60010E9CD /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
- };
- rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
-}
diff --git a/docs/AutomaticReferenceCounting.html b/docs/AutomaticReferenceCounting.html
index 5090fa2b7952..bc784578e4cf 100644
--- a/docs/AutomaticReferenceCounting.html
+++ b/docs/AutomaticReferenceCounting.html
@@ -1315,6 +1315,39 @@ 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>
<div id="misc">
@@ -1562,6 +1595,56 @@ 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> <!-- misc -->
<div id="runtime">
diff --git a/docs/InternalsManual.html b/docs/InternalsManual.html
index 5d97609373b7..54f01fca0e7a 100644
--- a/docs/InternalsManual.html
+++ b/docs/InternalsManual.html
@@ -71,6 +71,7 @@ td {
<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>
@@ -1785,6 +1786,228 @@ Check for the attribute's presence using <tt>Decl::getAttr&lt;YourAttr>()</tt>.<
<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/LanguageExtensions.html b/docs/LanguageExtensions.html
index 7ee8f010a32b..c4a8047f1f48 100644
--- a/docs/LanguageExtensions.html
+++ b/docs/LanguageExtensions.html
@@ -4,7 +4,7 @@
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>Clang LanguageExtensions</title>
+ <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">
@@ -38,29 +38,41 @@
<ul>
<li><a href="#cxx0x">C++0x</a>
<ul>
- <li><a href="#cxx_decltype">C++0x <tt>decltype()</tt></a></li>
- <li><a href="#cxx_access_control_sfinae">C++0x SFINAE includes access control</a></li>
+ <li><a href="#cxx_access_control_sfinae">C++0x SFINAE includes access control</a></li>
<li><a href="#cxx_alias_templates">C++0x alias templates</a></li>
+ <li><a href="#cxx_alignas">C++0x alignment specifiers</a></li>
<li><a href="#cxx_attributes">C++0x attributes</a></li>
+ <li><a href="#cxx_constexpr">C++0x generalized constant expressions</a></li>
+ <li><a href="#cxx_decltype">C++0x <tt>decltype()</tt></a></li>
<li><a href="#cxx_default_function_template_args">C++0x default template arguments in function templates</a></li>
<li><a href="#cxx_delegating_constructor">C++0x delegating constructors</a></li>
<li><a href="#cxx_deleted_functions">C++0x deleted functions</a></li>
+ <li><a href="#cxx_explicit_conversions">C++0x explicit conversion functions</a></li>
+ <li><a href="#cxx_generalized_initializers">C++0x generalized initializers</a></li>
+ <li><a href="#cxx_implicit_moves">C++0x implicit move constructors/assignment operators</a></li>
+ <li><a href="#cxx_inheriting_constructors">C++0x inheriting constructors</a></li>
+ <li><a href="#cxx_inline_namespaces">C++0x inline namespaces</a></li>
<li><a href="#cxx_lambdas">C++0x lambdas</a></li>
+ <li><a href="#cxx_noexcept">C++0x noexcept specification</a></li>
+ <li><a href="#cxx_nonstatic_member_init">C++0x in-class non-static data member initialization</a></li>
<li><a href="#cxx_nullptr">C++0x nullptr</a></li>
<li><a href="#cxx_override_control">C++0x override control</a></li>
<li><a href="#cxx_range_for">C++0x range-based for loop</a></li>
+ <li><a href="#cxx_raw_string_literals">C++0x raw string literals</a></li>
<li><a href="#cxx_rvalue_references">C++0x rvalue references</a></li>
<li><a href="#cxx_reference_qualified_functions">C++0x reference-qualified functions</a></li>
<li><a href="#cxx_static_assert">C++0x <tt>static_assert()</tt></a></li>
<li><a href="#cxx_auto_type">C++0x type inference</a></li>
- <li><a href="#cxx_variadic_templates">C++0x variadic templates</a></li>
- <li><a href="#cxx_inline_namespaces">C++0x inline namespaces</a></li>
- <li><a href="#cxx_strong_enums">C++0x strongly-typed enumerations</a></li>
+ <li><a href="#cxx_strong_enums">C++0x strongly-typed enumerations</a></li>
<li><a href="#cxx_trailing_return">C++0x trailing return type</a></li>
- <li><a href="#cxx_noexcept">C++0x noexcept specification</a></li>
- </ul></li>
+ <li><a href="#cxx_unicode_literals">C++0x Unicode string literals</a></li>
+ <li><a href="#cxx_unrestricted_unions">C++0x unrestricted unions</a></li>
+ <li><a href="#cxx_user_literals">C++0x user-defined literals</a></li>
+ <li><a href="#cxx_variadic_templates">C++0x variadic templates</a></li>
+ </ul></li>
<li><a href="#c1x">C1X</a>
<ul>
+ <li><a href="#c_alignas">C1X alignment specifiers</a></li>
<li><a href="#c_generic_selections">C1X generic selections</a></li>
<li><a href="#c_static_assert">C1X <tt>_Static_assert()</tt></a></li>
</ul></li>
@@ -71,9 +83,11 @@
<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>
</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_shufflevector">__builtin_shufflevector</a></li>
@@ -87,6 +101,27 @@
</ul>
</li>
<li><a href="#analyzerspecific">Static Analysis-Specific Extensions</a></li>
+<li><a href="#threadsafety">Thread Safety Annotation Checking</a></li>
+ <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>
</ul>
<!-- ======================================================================= -->
@@ -267,6 +302,23 @@ 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>
<!-- ======================================================================= -->
@@ -416,12 +468,6 @@ noted.</p>
C++0x standard. As a result, all these features are enabled
with the <tt>-std=c++0x</tt> option when compiling C++ code.</p>
-<h4 id="cxx_decltype">C++0x <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.</p>
-
<h4 id="cxx_access_control_sfinae">C++0x 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>
@@ -432,12 +478,30 @@ with the <tt>-std=c++0x</tt> option when compiling C++ code.</p>
<tt>__has_extension(cxx_alias_templates)</tt> to determine if support for
C++0x's alias declarations and alias templates is enabled.</p>
+<h4 id="cxx_alignas">C++0x 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++0x 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++0x's square bracket notation is enabled.</p>
+<h4 id="cxx_constexpr">C++0x 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. Clang does not currently implement this feature.</p>
+
+<h4 id="cxx_decltype">C++0x <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.</p>
+
<h4 id="cxx_default_function_template_args">C++0x default template arguments in function templates</h4>
<p>Use <tt>__has_feature(cxx_default_function_template_args)</tt> or
@@ -455,11 +519,46 @@ support for delegating constructors is enabled.</p>
<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++0x explicit conversion functions</h3>
+<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++0x 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. Clang does not currently implement
+this feature.</p>
+
+<h4 id="cxx_implicit_moves">C++0x 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++0x 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++0x 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++0x 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. clang does not currently implement this feature.</p>
+is enabled. Clang does not currently implement this feature.</p>
+
+<h4 id="cxx_noexcept">C++0x 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++0x 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++0x <tt>nullptr</tt></h4>
@@ -486,6 +585,9 @@ is enabled.</p>
<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++0x 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"foo\bar"</tt>) is enabled.</p>
+
<h4 id="cxx_rvalue_references">C++0x rvalue references</h4>
<p>Use <tt>__has_feature(cxx_rvalue_references)</tt> or
@@ -505,17 +607,11 @@ compile-time assertions using <tt>static_assert</tt> is enabled.</p>
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_variadic_templates">C++0x 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>
-
-<h4 id="cxx_inline_namespaces">C++0x inline namespaces</h4>
+<h4 id="cxx_strong_enums">C++0x strongly typed enumerations</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>
+<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++0x trailing return type</h4>
@@ -523,17 +619,23 @@ inline namespaces is enabled.</p>
<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_noexcept">C++0x noexcept</h4>
+<h4 id="cxx_unicode_literals">C++0x Unicode string literals</h4>
+<p>Use <tt>__has_feature(cxx_unicode_literals)</tt> to determine if
+support for Unicode string literals is enabled.</p>
-<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_unrestricted_unions">C++0x unrestricted unions</h4>
-<h4 id="cxx_strong_enums">C++0x strongly typed enumerations</h4>
+<p>Use <tt>__has_feature(cxx_unrestricted_unions)</tt> to determine if support for unrestricted unions is enabled. Clang does not currently support this feature.</p>
-<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_user_literals">C++0x user-defined literals</h4>
+
+<p>Use <tt>__has_feature(cxx_user_literals)</tt> to determine if support for user-defined literals is enabled. Clang does not currently support this feature.</p>
+
+<h4 id="cxx_variadic_templates">C++0x 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="c1x">C1X</h3>
@@ -541,6 +643,12 @@ strongly typed, scoped enumerations is enabled.</p>
C1X standard. As a result, all these features are enabled
with the <tt>-std=c1x</tt> option when compiling C code.</p>
+<h4 id="c_alignas">C1X 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_generic_selections">C1X generic selections</h4>
<p>Use <tt>__has_feature(c_generic_selections)</tt> or
@@ -599,6 +707,7 @@ struct is_convertible_to {
<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>__underlying_type(type)</code>: Retrieves the underlying type for a given <code>enum</code> type. This trait is required to implement the C++0x standard library.</li>
</ul>
<!-- ======================================================================= -->
@@ -648,7 +757,19 @@ related result type. Similarly, the type of the expression
<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>To determine whether a method has a related result type, the first
+<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 a related result type if its return
type is compatible with the type of its class and if</p>
@@ -677,8 +798,11 @@ with the subclass type. For example:</p>
<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 without a
-related result type.</p>
+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>
@@ -687,6 +811,24 @@ related result type.</p>
<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++0x 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="overloading-in-c">Function Overloading in C</h2>
<!-- ======================================================================= -->
@@ -786,6 +928,41 @@ caveats to this use of name mangling:</p>
<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>
@@ -1087,6 +1264,149 @@ balance in some way.</p>
<p>Query for these features with <tt>__has_attribute(ns_consumed)</tt>,
<tt>__has_attribute(ns_returns_retained)</tt>, etc.</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>
+
</div>
</body>
</html>
diff --git a/docs/UsersManual.html b/docs/UsersManual.html
index 639892714ef8..9d7981919c28 100644
--- a/docs/UsersManual.html
+++ b/docs/UsersManual.html
@@ -39,6 +39,7 @@ td {
<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_enable_everything">Enabling All Warnings</a></li>
<li><a href="#analyzer_diagnositics">Controlling Static Analyzer Diagnostics</a></li>
</ul>
</li>
@@ -626,6 +627,16 @@ 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_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
@@ -1059,18 +1070,28 @@ Clang assumes directories as below;</p>
<h5>MinGW-w64</h5>
-<p>For x32(i686-w64-mingw32), it is not supported yet.</p>
-
-<p>For x64(x86_64-w64-mingw32), <a href="http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20110321/118499.html">an essential patch(LLVM's r128206)</a> would be needed. It is incompatible to <a href="http://tdm-gcc.tdragon.net/development">TDM-GCC</a> due to the definition of symbol &quot;<code>___chkstk</code>&quot;. Clang assumes as below;<p>
+<p>For 32-bit (i686-w64-mingw32), and 64-bit (x86_64-w64-mingw32), Clang assumes as below;<p>
<ul>
-<li><tt>C:/mingw/x86_64-w64-mingw32/include</tt></li>
-<li><tt>C:/mingw/x86_64-w64-mingw32/include/c++/4.5.[23]</tt></li>
-<li>GCC driver &quot;gcc.exe&quot; to build x86_64-w64-mingw32 binary.</li>
+<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><a href="http://llvm.org/bugs/show_bug.cgi?id=8833">Some tests might fail</a>
-on x64.</p>
+<p>This directory layout is standard for any toolchain you will find on the official <a href="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>
diff --git a/docs/doxygen.cfg.in b/docs/doxygen.cfg.in
index ed9ffcb85a53..7f3292c85d56 100644
--- a/docs/doxygen.cfg.in
+++ b/docs/doxygen.cfg.in
@@ -39,7 +39,7 @@ OUTPUT_DIRECTORY = @abs_builddir@/doxygen
# source files, where putting all generated files in the same directory would
# otherwise cause performance problems for the file system.
-CREATE_SUBDIRS = NO
+CREATE_SUBDIRS = YES
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
diff --git a/docs/doxygen.css b/docs/doxygen.css
index f105e202761f..9780b98db2c7 100644
--- a/docs/doxygen.css
+++ b/docs/doxygen.css
@@ -370,9 +370,39 @@ H2 {
H3 {
font-size: 100%;
}
+
+H2, H3 {
+ border-bottom: 2px solid;
+ margin-top: 2em;
+}
+
A.qindex {}
A.qindexRef {}
A.el { text-decoration: none; font-weight: bold }
A.elRef { font-weight: bold }
A.code { text-decoration: none; font-weight: normal; color: #4444ee }
A.codeRef { font-weight: normal; color: #4444ee }
+
+div.memitem {
+ border: 1px solid #999999;
+ margin-top: 1.0em;
+ margin-bottom: 1.0em;
+ -webkit-border-radius: 0.5em;
+ -webkit-box-shadow: 3px 3px 6px #777777;
+ -moz-border-radius: 0.5em;
+ -moz-box-shadow: black 3px 3px 3px;
+}
+
+div.memproto {
+ background-color: #E3E4E5;
+ padding: 0.25em 0.5em;
+ -webkit-border-top-left-radius: 0.5em;
+ -webkit-border-top-right-radius: 0.5em;
+ -moz-border-radius-topleft: 0.5em;
+ -moz-border-radius-topright: 0.5em;
+}
+
+div.memdoc {
+ padding-left: 1em;
+ padding-right: 1em;
+}
diff --git a/docs/tools/clang.pod b/docs/tools/clang.pod
index 704cc8743ba6..964b143ac9eb 100644
--- a/docs/tools/clang.pod
+++ b/docs/tools/clang.pod
@@ -459,7 +459,13 @@ Add the specified directory to the search path for framework include files.
=item B<-nostdinc>
-Do not search the standard system directories for include files.
+Do not search the standard system directories or compiler builtin directories
+for include files.
+
+=item B<-nostdlibinc>
+
+Do not search the standard system directories for include files, but do search
+compiler builting include directories.
=item B<-nobuiltininc>
diff --git a/examples/PrintFunctionNames/PrintFunctionNames.cpp b/examples/PrintFunctionNames/PrintFunctionNames.cpp
index cc138f56dbba..fde60955aa00 100644
--- a/examples/PrintFunctionNames/PrintFunctionNames.cpp
+++ b/examples/PrintFunctionNames/PrintFunctionNames.cpp
@@ -45,9 +45,9 @@ protected:
// Example error handling.
if (args[i] == "-an-error") {
- Diagnostic &D = CI.getDiagnostics();
+ DiagnosticsEngine &D = CI.getDiagnostics();
unsigned DiagID = D.getCustomDiagID(
- Diagnostic::Error, "invalid argument '" + args[i] + "'");
+ DiagnosticsEngine::Error, "invalid argument '" + args[i] + "'");
D.Report(DiagID);
return false;
}
diff --git a/examples/analyzer-plugin/CMakeLists.txt b/examples/analyzer-plugin/CMakeLists.txt
new file mode 100644
index 000000000000..865422684ca5
--- /dev/null
+++ b/examples/analyzer-plugin/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(MODULE TRUE)
+
+set( LLVM_USED_LIBS
+ clangStaticAnalyzerCore
+ )
+
+set( LLVM_LINK_COMPONENTS support mc)
+
+add_clang_library(SampleAnalyzerPlugin SampleAnalyzerPlugin)
+
+set_target_properties(SampleAnalyzerPlugin
+ PROPERTIES
+ LINKER_LANGUAGE CXX
+ PREFIX "")
diff --git a/examples/analyzer-plugin/MainCallChecker.cpp b/examples/analyzer-plugin/MainCallChecker.cpp
new file mode 100644
index 000000000000..85f775483d4d
--- /dev/null
+++ b/examples/analyzer-plugin/MainCallChecker.cpp
@@ -0,0 +1,52 @@
+#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"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class MainCallChecker : public Checker < check::PreStmt<CallExpr> > {
+ mutable llvm::OwningPtr<BugType> BT;
+
+public:
+ void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
+};
+} // end anonymous namespace
+
+void MainCallChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
+ const ProgramState *state = C.getState();
+ const Expr *Callee = CE->getCallee();
+ const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl();
+
+ if (!FD)
+ return;
+
+ // Get the name of the callee.
+ IdentifierInfo *II = FD->getIdentifier();
+ if (!II) // if no identifier, not a simple C function
+ return;
+
+ if (II->isStr("main")) {
+ ExplodedNode *N = C.generateSink();
+ if (!N)
+ return;
+
+ if (!BT)
+ BT.reset(new BugType("call to main", "example analyzer plugin"));
+
+ BugReport *report = new BugReport(*BT, BT->getName(), N);
+ report->addRange(Callee->getSourceRange());
+ C.EmitReport(report);
+ }
+}
+
+// Register plugin!
+extern "C"
+void clang_registerCheckers (CheckerRegistry &registry) {
+ registry.addChecker<MainCallChecker>("example.MainCallChecker", "Disallows calls to functions called main");
+}
+
+extern "C"
+const char clang_analyzerAPIVersionString[] = CLANG_ANALYZER_API_VERSION_STRING;
diff --git a/examples/analyzer-plugin/Makefile b/examples/analyzer-plugin/Makefile
new file mode 100644
index 000000000000..5537ee03d880
--- /dev/null
+++ b/examples/analyzer-plugin/Makefile
@@ -0,0 +1,20 @@
+##===- examples/analyzer-plugin/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 = SampleAnalyzerPlugin
+
+LINK_LIBS_IN_SHARED = 0
+SHARED_LIBRARY = 1
+
+include $(CLANG_LEVEL)/Makefile
+
+ifeq ($(OS),Darwin)
+ LDFLAGS=-Wl,-undefined,dynamic_lookup
+endif
diff --git a/examples/clang-interpreter/main.cpp b/examples/clang-interpreter/main.cpp
index 16f4dab05d70..c9734e5fadac 100644
--- a/examples/clang-interpreter/main.cpp
+++ b/examples/clang-interpreter/main.cpp
@@ -22,12 +22,13 @@
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/config.h"
+#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
-#include "llvm/Target/TargetSelect.h"
+#include "llvm/Support/TargetSelect.h"
using namespace clang;
using namespace clang::driver;
@@ -74,10 +75,9 @@ int main(int argc, const char **argv, char * const *envp) {
new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- Diagnostic Diags(DiagID, DiagClient);
+ DiagnosticsEngine Diags(DiagID, DiagClient);
Driver TheDriver(Path.str(), llvm::sys::getHostTriple(),
- "a.out", /*IsProduction=*/false, /*CXXIsProduction=*/false,
- Diags);
+ "a.out", /*IsProduction=*/false, Diags);
TheDriver.setTitle("clang interpreter");
// FIXME: This is a hack to try to force the driver to do something we can
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 4852ded7f883..1320145a896f 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -115,7 +115,12 @@ enum CXAvailabilityKind {
/**
* \brief The entity is not available; any use of it will be an error.
*/
- CXAvailability_NotAvailable
+ CXAvailability_NotAvailable,
+ /**
+ * \brief The entity is available, but not accessible; any use of it will be
+ * an error.
+ */
+ CXAvailability_NotAccessible
};
/**
@@ -263,7 +268,7 @@ CINDEX_LINKAGE CXFile clang_getFile(CXTranslationUnit tu,
* \brief Identifies a specific source location within a translation
* unit.
*
- * Use clang_getInstantiationLocation() or clang_getSpellingLocation()
+ * Use clang_getExpansionLocation() or clang_getSpellingLocation()
* to map a source location to a particular file, line, and column.
*/
typedef struct {
@@ -328,11 +333,24 @@ CINDEX_LINKAGE CXSourceRange clang_getRange(CXSourceLocation begin,
CXSourceLocation end);
/**
+ * \brief Determine whether two ranges are equivalent.
+ *
+ * \returns non-zero if the ranges are the same, zero if they differ.
+ */
+CINDEX_LINKAGE unsigned clang_equalRanges(CXSourceRange range1,
+ CXSourceRange range2);
+
+/**
+ * \brief Returns non-zero if \arg range is null.
+ */
+CINDEX_LINKAGE int clang_Range_isNull(CXSourceRange range);
+
+/**
* \brief Retrieve the file, line, column, and offset represented by
* the given source location.
*
- * If the location refers into a macro instantiation, retrieves the
- * location of the macro instantiation.
+ * If the location refers into a macro expansion, retrieves the
+ * location of the macro expansion.
*
* \param location the location within a source file that will be decomposed
* into its parts.
@@ -349,6 +367,63 @@ CINDEX_LINKAGE CXSourceRange clang_getRange(CXSourceLocation begin,
* \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_getExpansionLocation(CXSourceLocation location,
+ CXFile *file,
+ unsigned *line,
+ unsigned *column,
+ unsigned *offset);
+
+/**
+ * \brief Retrieve the file, line, column, and offset represented by
+ * the given source location, as specified in a # line directive.
+ *
+ * Example: given the following source code in a file somefile.c
+ *
+ * #123 "dummy.c" 1
+ *
+ * static int func(void)
+ * {
+ * return 0;
+ * }
+ *
+ * the location information returned by this function would be
+ *
+ * File: dummy.c Line: 124 Column: 12
+ *
+ * whereas clang_getExpansionLocation would have returned
+ *
+ * File: somefile.c Line: 3 Column: 12
+ *
+ * \param location the location within a source file that will be decomposed
+ * into its parts.
+ *
+ * \param filename [out] if non-NULL, will be set to the filename of the
+ * source location. Note that filenames returned will be for "virtual" files,
+ * which don't necessarily exist on the machine running clang - e.g. when
+ * parsing preprocessed output obtained from a different environment. If
+ * a non-NULL value is passed in, remember to dispose of the returned value
+ * using \c clang_disposeString() once you've finished with it. For an invalid
+ * source location, an empty string is returned.
+ *
+ * \param line [out] if non-NULL, will be set to the line number of the
+ * source location. For an invalid source location, zero is returned.
+ *
+ * \param column [out] if non-NULL, will be set to the column number of the
+ * source location. For an invalid source location, zero is returned.
+ */
+CINDEX_LINKAGE void clang_getPresumedLocation(CXSourceLocation location,
+ CXString *filename,
+ unsigned *line,
+ unsigned *column);
+
+/**
+ * \brief Legacy API to retrieve the file, line, column, and offset represented
+ * by the given source location.
+ *
+ * This interface has been replaced by the newer interface
+ * \see clang_getExpansionLocation(). See that interface's documentation for
+ * details.
+ */
CINDEX_LINKAGE void clang_getInstantiationLocation(CXSourceLocation location,
CXFile *file,
unsigned *line,
@@ -816,18 +891,18 @@ enum CXTranslationUnit_Flags {
*/
CXTranslationUnit_CacheCompletionResults = 0x08,
/**
- * \brief Enable precompiled preambles in C++.
+ * \brief DEPRECATED: Enable precompiled preambles in C++.
*
* Note: this is a *temporary* option that is available only while
- * we are testing C++ precompiled preamble support.
+ * we are testing C++ precompiled preamble support. It is deprecated.
*/
CXTranslationUnit_CXXPrecompiledPreamble = 0x10,
/**
- * \brief Enabled chained precompiled preambles in C++.
+ * \brief DEPRECATED: Enabled chained precompiled preambles in C++.
*
* Note: this is a *temporary* option that is available only while
- * we are testing C++ precompiled preamble support.
+ * we are testing C++ precompiled preamble support. It is deprecated.
*/
CXTranslationUnit_CXXChainedPCH = 0x20,
@@ -1094,12 +1169,14 @@ enum CXTUResourceUsageKind {
CXTUResourceUsage_ExternalASTSource_Membuffer_MMap = 10,
CXTUResourceUsage_Preprocessor = 11,
CXTUResourceUsage_PreprocessingRecord = 12,
+ CXTUResourceUsage_SourceManager_DataStructures = 13,
+ CXTUResourceUsage_Preprocessor_HeaderSearch = 14,
CXTUResourceUsage_MEMORY_IN_BYTES_BEGIN = CXTUResourceUsage_AST,
CXTUResourceUsage_MEMORY_IN_BYTES_END =
- CXTUResourceUsage_PreprocessingRecord,
+ CXTUResourceUsage_Preprocessor_HeaderSearch,
CXTUResourceUsage_First = CXTUResourceUsage_AST,
- CXTUResourceUsage_Last = CXTUResourceUsage_PreprocessingRecord
+ CXTUResourceUsage_Last = CXTUResourceUsage_Preprocessor_HeaderSearch
};
/**
@@ -1237,8 +1314,11 @@ enum CXCursorKind {
CXCursor_ObjCSynthesizeDecl = 37,
/** \brief An Objective-C @dynamic definition. */
CXCursor_ObjCDynamicDecl = 38,
+ /** \brief An access specifier. */
+ CXCursor_CXXAccessSpecifier = 39,
+
CXCursor_FirstDecl = CXCursor_UnexposedDecl,
- CXCursor_LastDecl = CXCursor_ObjCDynamicDecl,
+ CXCursor_LastDecl = CXCursor_CXXAccessSpecifier,
/* References */
CXCursor_FirstRef = 40, /* Decl references */
@@ -1377,7 +1457,207 @@ enum CXCursorKind {
/** \brief An expression that represents a block literal. */
CXCursor_BlockExpr = 105,
- CXCursor_LastExpr = 105,
+ /** \brief An integer literal.
+ */
+ CXCursor_IntegerLiteral = 106,
+
+ /** \brief A floating point number literal.
+ */
+ CXCursor_FloatingLiteral = 107,
+
+ /** \brief An imaginary number literal.
+ */
+ CXCursor_ImaginaryLiteral = 108,
+
+ /** \brief A string literal.
+ */
+ CXCursor_StringLiteral = 109,
+
+ /** \brief A character literal.
+ */
+ CXCursor_CharacterLiteral = 110,
+
+ /** \brief A parenthesized expression, e.g. "(1)".
+ *
+ * This AST node is only formed if full location information is requested.
+ */
+ CXCursor_ParenExpr = 111,
+
+ /** \brief This represents the unary-expression's (except sizeof and
+ * alignof).
+ */
+ CXCursor_UnaryOperator = 112,
+
+ /** \brief [C99 6.5.2.1] Array Subscripting.
+ */
+ CXCursor_ArraySubscriptExpr = 113,
+
+ /** \brief A builtin binary operation expression such as "x + y" or
+ * "x <= y".
+ */
+ CXCursor_BinaryOperator = 114,
+
+ /** \brief Compound assignment such as "+=".
+ */
+ CXCursor_CompoundAssignOperator = 115,
+
+ /** \brief The ?: ternary operator.
+ */
+ CXCursor_ConditionalOperator = 116,
+
+ /** \brief An explicit cast in C (C99 6.5.4) or a C-style cast in C++
+ * (C++ [expr.cast]), which uses the syntax (Type)expr.
+ *
+ * For example: (int)f.
+ */
+ CXCursor_CStyleCastExpr = 117,
+
+ /** \brief [C99 6.5.2.5]
+ */
+ CXCursor_CompoundLiteralExpr = 118,
+
+ /** \brief Describes an C or C++ initializer list.
+ */
+ CXCursor_InitListExpr = 119,
+
+ /** \brief The GNU address of label extension, representing &&label.
+ */
+ CXCursor_AddrLabelExpr = 120,
+
+ /** \brief This is the GNU Statement Expression extension: ({int X=4; X;})
+ */
+ CXCursor_StmtExpr = 121,
+
+ /** \brief Represents a C1X generic selection.
+ */
+ CXCursor_GenericSelectionExpr = 122,
+
+ /** \brief Implements the GNU __null extension, which is a name for a null
+ * pointer constant that has integral type (e.g., int or long) and is the same
+ * size and alignment as a pointer.
+ *
+ * The __null extension is typically only used by system headers, which define
+ * NULL as __null in C++ rather than using 0 (which is an integer that may not
+ * match the size of a pointer).
+ */
+ CXCursor_GNUNullExpr = 123,
+
+ /** \brief C++'s static_cast<> expression.
+ */
+ CXCursor_CXXStaticCastExpr = 124,
+
+ /** \brief C++'s dynamic_cast<> expression.
+ */
+ CXCursor_CXXDynamicCastExpr = 125,
+
+ /** \brief C++'s reinterpret_cast<> expression.
+ */
+ CXCursor_CXXReinterpretCastExpr = 126,
+
+ /** \brief C++'s const_cast<> expression.
+ */
+ CXCursor_CXXConstCastExpr = 127,
+
+ /** \brief Represents an explicit C++ type conversion that uses "functional"
+ * notion (C++ [expr.type.conv]).
+ *
+ * Example:
+ * \code
+ * x = int(0.5);
+ * \endcode
+ */
+ CXCursor_CXXFunctionalCastExpr = 128,
+
+ /** \brief A C++ typeid expression (C++ [expr.typeid]).
+ */
+ CXCursor_CXXTypeidExpr = 129,
+
+ /** \brief [C++ 2.13.5] C++ Boolean Literal.
+ */
+ CXCursor_CXXBoolLiteralExpr = 130,
+
+ /** \brief [C++0x 2.14.7] C++ Pointer Literal.
+ */
+ CXCursor_CXXNullPtrLiteralExpr = 131,
+
+ /** \brief Represents the "this" expression in C++
+ */
+ CXCursor_CXXThisExpr = 132,
+
+ /** \brief [C++ 15] C++ Throw Expression.
+ *
+ * This handles 'throw' and 'throw' assignment-expression. When
+ * assignment-expression isn't present, Op will be null.
+ */
+ CXCursor_CXXThrowExpr = 133,
+
+ /** \brief A new expression for memory allocation and constructor calls, e.g:
+ * "new CXXNewExpr(foo)".
+ */
+ CXCursor_CXXNewExpr = 134,
+
+ /** \brief A delete expression for memory deallocation and destructor calls,
+ * e.g. "delete[] pArray".
+ */
+ CXCursor_CXXDeleteExpr = 135,
+
+ /** \brief A unary expression.
+ */
+ CXCursor_UnaryExpr = 136,
+
+ /** \brief ObjCStringLiteral, used for Objective-C string literals i.e. "foo".
+ */
+ CXCursor_ObjCStringLiteral = 137,
+
+ /** \brief ObjCEncodeExpr, used for in Objective-C.
+ */
+ CXCursor_ObjCEncodeExpr = 138,
+
+ /** \brief ObjCSelectorExpr used for in Objective-C.
+ */
+ CXCursor_ObjCSelectorExpr = 139,
+
+ /** \brief Objective-C's protocol expression.
+ */
+ CXCursor_ObjCProtocolExpr = 140,
+
+ /** \brief An Objective-C "bridged" cast expression, which casts between
+ * Objective-C pointers and C pointers, transferring ownership in the process.
+ *
+ * \code
+ * NSString *str = (__bridge_transfer NSString *)CFCreateString();
+ * \endcode
+ */
+ CXCursor_ObjCBridgedCastExpr = 141,
+
+ /** \brief Represents a C++0x pack expansion that produces a sequence of
+ * expressions.
+ *
+ * A pack expansion expression contains a pattern (which itself is an
+ * expression) followed by an ellipsis. For example:
+ *
+ * \code
+ * template<typename F, typename ...Types>
+ * void forward(F f, Types &&...args) {
+ * f(static_cast<Types&&>(args)...);
+ * }
+ * \endcode
+ */
+ CXCursor_PackExpansionExpr = 142,
+
+ /** \brief Represents an expression that computes the length of a parameter
+ * pack.
+ *
+ * \code
+ * template<typename ...Types>
+ * struct count {
+ * static const unsigned value = sizeof...(Types);
+ * };
+ * \endcode
+ */
+ CXCursor_SizeOfPackExpr = 143,
+
+ CXCursor_LastExpr = CXCursor_SizeOfPackExpr,
/* Statements */
CXCursor_FirstStmt = 200,
@@ -1404,8 +1684,130 @@ enum CXCursorKind {
*
*/
CXCursor_LabelStmt = 201,
-
- CXCursor_LastStmt = CXCursor_LabelStmt,
+
+ /** \brief A group of statements like { stmt stmt }.
+ *
+ * This cursor kind is used to describe compound statements, e.g. function
+ * bodies.
+ */
+ CXCursor_CompoundStmt = 202,
+
+ /** \brief A case statment.
+ */
+ CXCursor_CaseStmt = 203,
+
+ /** \brief A default statement.
+ */
+ CXCursor_DefaultStmt = 204,
+
+ /** \brief An if statement
+ */
+ CXCursor_IfStmt = 205,
+
+ /** \brief A switch statement.
+ */
+ CXCursor_SwitchStmt = 206,
+
+ /** \brief A while statement.
+ */
+ CXCursor_WhileStmt = 207,
+
+ /** \brief A do statement.
+ */
+ CXCursor_DoStmt = 208,
+
+ /** \brief A for statement.
+ */
+ CXCursor_ForStmt = 209,
+
+ /** \brief A goto statement.
+ */
+ CXCursor_GotoStmt = 210,
+
+ /** \brief An indirect goto statement.
+ */
+ CXCursor_IndirectGotoStmt = 211,
+
+ /** \brief A continue statement.
+ */
+ CXCursor_ContinueStmt = 212,
+
+ /** \brief A break statement.
+ */
+ CXCursor_BreakStmt = 213,
+
+ /** \brief A return statement.
+ */
+ CXCursor_ReturnStmt = 214,
+
+ /** \brief A GNU inline assembly statement extension.
+ */
+ CXCursor_AsmStmt = 215,
+
+ /** \brief Objective-C's overall @try-@catc-@finall statement.
+ */
+ CXCursor_ObjCAtTryStmt = 216,
+
+ /** \brief Objective-C's @catch statement.
+ */
+ CXCursor_ObjCAtCatchStmt = 217,
+
+ /** \brief Objective-C's @finally statement.
+ */
+ CXCursor_ObjCAtFinallyStmt = 218,
+
+ /** \brief Objective-C's @throw statement.
+ */
+ CXCursor_ObjCAtThrowStmt = 219,
+
+ /** \brief Objective-C's @synchronized statement.
+ */
+ CXCursor_ObjCAtSynchronizedStmt = 220,
+
+ /** \brief Objective-C's autorelease pool statement.
+ */
+ CXCursor_ObjCAutoreleasePoolStmt = 221,
+
+ /** \brief Objective-C's collection statement.
+ */
+ CXCursor_ObjCForCollectionStmt = 222,
+
+ /** \brief C++'s catch statement.
+ */
+ CXCursor_CXXCatchStmt = 223,
+
+ /** \brief C++'s try statement.
+ */
+ CXCursor_CXXTryStmt = 224,
+
+ /** \brief C++'s for (* : *) statement.
+ */
+ CXCursor_CXXForRangeStmt = 225,
+
+ /** \brief Windows Structured Exception Handling's try statement.
+ */
+ CXCursor_SEHTryStmt = 226,
+
+ /** \brief Windows Structured Exception Handling's except statement.
+ */
+ CXCursor_SEHExceptStmt = 227,
+
+ /** \brief Windows Structured Exception Handling's finally statement.
+ */
+ CXCursor_SEHFinallyStmt = 228,
+
+ /** \brief The null satement ";": C99 6.8.3p3.
+ *
+ * This cursor kind is used to describe the null statement.
+ */
+ CXCursor_NullStmt = 230,
+
+ /** \brief Adaptor class for mixing declarations with statements and
+ * expressions.
+ */
+ CXCursor_DeclStmt = 231,
+
+ CXCursor_LastStmt = CXCursor_DeclStmt,
/**
* \brief Cursor that represents the translation unit itself.
@@ -1426,7 +1828,10 @@ enum CXCursorKind {
CXCursor_IBActionAttr = 401,
CXCursor_IBOutletAttr = 402,
CXCursor_IBOutletCollectionAttr = 403,
- CXCursor_LastAttr = CXCursor_IBOutletCollectionAttr,
+ CXCursor_CXXFinalAttr = 404,
+ CXCursor_CXXOverrideAttr = 405,
+ CXCursor_AnnotateAttr = 406,
+ CXCursor_LastAttr = CXCursor_AnnotateAttr,
/* Preprocessing */
CXCursor_PreprocessingDirective = 500,
@@ -1458,6 +1863,7 @@ enum CXCursorKind {
*/
typedef struct {
enum CXCursorKind kind;
+ int xdata;
void *data[3];
} CXCursor;
@@ -1486,6 +1892,11 @@ CINDEX_LINKAGE CXCursor clang_getTranslationUnitCursor(CXTranslationUnit);
CINDEX_LINKAGE unsigned clang_equalCursors(CXCursor, CXCursor);
/**
+ * \brief Returns non-zero if \arg cursor is null.
+ */
+int clang_Cursor_isNull(CXCursor);
+
+/**
* \brief Compute a hash value for the given cursor.
*/
CINDEX_LINKAGE unsigned clang_hashCursor(CXCursor);
@@ -1600,6 +2011,11 @@ CINDEX_LINKAGE enum CXLanguageKind {
*/
CINDEX_LINKAGE enum CXLanguageKind clang_getCursorLanguage(CXCursor cursor);
+/**
+ * \brief Returns the translation unit that a cursor originated from.
+ */
+CINDEX_LINKAGE CXTranslationUnit clang_Cursor_getTranslationUnit(CXCursor);
+
/**
* \brief A fast container representing a set of CXCursors.
@@ -1886,7 +2302,8 @@ enum CXTypeKind {
CXType_ObjCInterface = 108,
CXType_ObjCObjectPointer = 109,
CXType_FunctionNoProto = 110,
- CXType_FunctionProto = 111
+ CXType_FunctionProto = 111,
+ CXType_ConstantArray = 112
};
/**
@@ -1978,6 +2395,20 @@ CINDEX_LINKAGE CXType clang_getCursorResultType(CXCursor C);
CINDEX_LINKAGE unsigned clang_isPODType(CXType T);
/**
+ * \brief Return the element type of an array type.
+ *
+ * If a non-array type is passed in, an invalid type is returned.
+ */
+CINDEX_LINKAGE CXType clang_getArrayElementType(CXType T);
+
+/**
+ * \brief Return the the array size of a constant array.
+ *
+ * If a non-array type is passed in, -1 is returned.
+ */
+CINDEX_LINKAGE long long clang_getArraySize(CXType T);
+
+/**
* \brief Returns 1 if the base class specified by the cursor with kind
* CX_CXXBaseSpecifier is virtual.
*/
@@ -1996,7 +2427,8 @@ enum CX_CXXAccessSpecifier {
/**
* \brief Returns the access control level for the C++ base specifier
- * represented by a cursor with kind CX_CXXBaseSpecifier.
+ * represented by a cursor with kind CXCursor_CXXBaseSpecifier or
+ * CXCursor_AccessSpecifier.
*/
CINDEX_LINKAGE enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor);
@@ -2377,6 +2809,54 @@ CINDEX_LINKAGE enum CXCursorKind clang_getTemplateCursorKind(CXCursor C);
* from which it was instantiated. Otherwise, returns a NULL cursor.
*/
CINDEX_LINKAGE CXCursor clang_getSpecializedCursorTemplate(CXCursor C);
+
+/**
+ * \brief Given a cursor that references something else, return the source range
+ * covering that reference.
+ *
+ * \param C A cursor pointing to a member reference, a declaration reference, or
+ * an operator call.
+ * \param NameFlags A bitset with three independent flags:
+ * CXNameRange_WantQualifier, CXNameRange_WantTemplateArgs, and
+ * CXNameRange_WantSinglePiece.
+ * \param PieceIndex For contiguous names or when passing the flag
+ * CXNameRange_WantSinglePiece, only one piece with index 0 is
+ * available. When the CXNameRange_WantSinglePiece flag is not passed for a
+ * non-contiguous names, this index can be used to retreive the individual
+ * pieces of the name. See also CXNameRange_WantSinglePiece.
+ *
+ * \returns The piece of the name pointed to by the given cursor. If there is no
+ * name, or if the PieceIndex is out-of-range, a null-cursor will be returned.
+ */
+CINDEX_LINKAGE CXSourceRange clang_getCursorReferenceNameRange(CXCursor C,
+ unsigned NameFlags,
+ unsigned PieceIndex);
+
+enum CXNameRefFlags {
+ /**
+ * \brief Include the nested-name-specifier, e.g. Foo:: in x.Foo::y, in the
+ * range.
+ */
+ CXNameRange_WantQualifier = 0x1,
+
+ /**
+ * \brief Include the explicit template arguments, e.g. <int> in x.f<int>, in
+ * the range.
+ */
+ CXNameRange_WantTemplateArgs = 0x2,
+
+ /**
+ * \brief If the name is non-contiguous, return the full spanning range.
+ *
+ * Non-contiguous names occur in Objective-C when a selector with two or more
+ * parameters is used, or in C++ when using an operator:
+ * \code
+ * [object doSomething:here withValue:there]; // ObjC
+ * return some_vector[1]; // C++
+ * \endcode
+ */
+ CXNameRange_WantSinglePiece = 0x4
+};
/**
* @}
@@ -2801,8 +3281,7 @@ clang_getCompletionChunkText(CXCompletionString completion_string,
* \param chunk_number the 0-based index of the chunk in the completion string.
*
* \returns the completion string associated with the chunk at index
- * \c chunk_number, or NULL if that chunk is not represented by a completion
- * string.
+ * \c chunk_number.
*/
CINDEX_LINKAGE CXCompletionString
clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
@@ -2841,6 +3320,45 @@ CINDEX_LINKAGE enum CXAvailabilityKind
clang_getCompletionAvailability(CXCompletionString completion_string);
/**
+ * \brief Retrieve the number of annotations associated with the given
+ * completion string.
+ *
+ * \param completion_string the completion string to query.
+ *
+ * \returns the number of annotations associated with the given completion
+ * string.
+ */
+CINDEX_LINKAGE unsigned
+clang_getCompletionNumAnnotations(CXCompletionString completion_string);
+
+/**
+ * \brief Retrieve the annotation associated with the given completion string.
+ *
+ * \param completion_string the completion string to query.
+ *
+ * \param annotation_number the 0-based index of the annotation of the
+ * completion string.
+ *
+ * \returns annotation string associated with the completion at index
+ * \c annotation_number, or a NULL string if that annotation is not available.
+ */
+CINDEX_LINKAGE CXString
+clang_getCompletionAnnotation(CXCompletionString completion_string,
+ unsigned annotation_number);
+
+/**
+ * \brief Retrieve a completion string for an arbitrary declaration or macro
+ * definition cursor.
+ *
+ * \param cursor The cursor to query.
+ *
+ * \returns A non-context-sensitive completion string for declaration and macro
+ * definition cursors, or NULL for other kinds of cursors.
+ */
+CINDEX_LINKAGE CXCompletionString
+clang_getCursorCompletionString(CXCursor cursor);
+
+/**
* \brief Contains the results of code-completion.
*
* This data structure contains the results of code completion, as
@@ -3144,6 +3662,54 @@ CXDiagnostic clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *Results,
CINDEX_LINKAGE
unsigned long long clang_codeCompleteGetContexts(
CXCodeCompleteResults *Results);
+
+/**
+ * \brief Returns the cursor kind for the container for the current code
+ * completion context. The container is only guaranteed to be set for
+ * contexts where a container exists (i.e. member accesses or Objective-C
+ * message sends); if there is not a container, this function will return
+ * CXCursor_InvalidCode.
+ *
+ * \param Results the code completion results to query
+ *
+ * \param IsIncomplete on return, this value will be false if Clang has complete
+ * information about the container. If Clang does not have complete
+ * information, this value will be true.
+ *
+ * \returns the container kind, or CXCursor_InvalidCode if there is not a
+ * container
+ */
+CINDEX_LINKAGE
+enum CXCursorKind clang_codeCompleteGetContainerKind(
+ CXCodeCompleteResults *Results,
+ unsigned *IsIncomplete);
+
+/**
+ * \brief Returns the USR for the container for the current code completion
+ * context. If there is not a container for the current context, this
+ * function will return the empty string.
+ *
+ * \param Results the code completion results to query
+ *
+ * \returns the USR for the container
+ */
+CINDEX_LINKAGE
+CXString clang_codeCompleteGetContainerUSR(CXCodeCompleteResults *Results);
+
+
+/**
+ * \brief Returns the currently-entered selector for an Objective-C message
+ * send, formatted like "initWithFoo:bar:". Only guaranteed to return a
+ * non-empty string for CXCompletionContext_ObjCInstanceMessage and
+ * CXCompletionContext_ObjCClassMessage.
+ *
+ * \param Results the code completion results to query
+ *
+ * \returns the selector (or partial selector) that has been entered thus far
+ * for an Objective-C message send.
+ */
+CINDEX_LINKAGE
+CXString clang_codeCompleteGetObjCSelector(CXCodeCompleteResults *Results);
/**
* @}
@@ -3246,6 +3812,53 @@ CINDEX_LINKAGE void clang_remap_dispose(CXRemapping);
* @}
*/
+/** \defgroup CINDEX_HIGH Higher level API functions
+ *
+ * @{
+ */
+
+enum CXVisitorResult {
+ CXVisit_Break,
+ CXVisit_Continue
+};
+
+typedef struct {
+ void *context;
+ enum CXVisitorResult (*visit)(void *context, CXCursor, CXSourceRange);
+} CXCursorAndRangeVisitor;
+
+/**
+ * \brief Find references of a declaration in a specific file.
+ *
+ * \param cursor pointing to a declaration or a reference of one.
+ *
+ * \param file to search for references.
+ *
+ * \param visitor callback that will receive pairs of CXCursor/CXSourceRange for
+ * 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.
+ */
+CINDEX_LINKAGE void clang_findReferencesInFile(CXCursor cursor, CXFile file,
+ CXCursorAndRangeVisitor visitor);
+
+#ifdef __has_feature
+# if __has_feature(blocks)
+
+typedef enum CXVisitorResult
+ (^CXCursorAndRangeVisitorBlock)(CXCursor, CXSourceRange);
+
+CINDEX_LINKAGE
+void clang_findReferencesInFileWithBlock(CXCursor, CXFile,
+ CXCursorAndRangeVisitorBlock);
+
+# endif
+#endif
+
+/**
+ * @}
+ */
+
/**
* @}
*/
diff --git a/include/clang/ARCMigrate/ARCMT.h b/include/clang/ARCMigrate/ARCMT.h
index ad5cf4a2c16c..d8dea0b3adb9 100644
--- a/include/clang/ARCMigrate/ARCMT.h
+++ b/include/clang/ARCMigrate/ARCMT.h
@@ -15,7 +15,7 @@
namespace clang {
class ASTContext;
- class DiagnosticClient;
+ class DiagnosticConsumer;
namespace arcmt {
class MigrationPass;
@@ -28,35 +28,53 @@ namespace arcmt {
/// It then checks the AST and produces errors/warning for ARC migration issues
/// that the user needs to handle manually.
///
+/// \param emitPremigrationARCErrors if true all ARC errors will get emitted
+/// even if the migrator can fix them, but the function will still return false
+/// if all ARC errors can be fixed.
+///
+/// \param plistOut if non-empty, it is the file path to store the plist with
+/// the pre-migration ARC diagnostics.
+///
/// \returns false if no error is produced, true otherwise.
bool checkForManualIssues(CompilerInvocation &CI,
- llvm::StringRef Filename, InputKind Kind,
- DiagnosticClient *DiagClient);
+ StringRef Filename, InputKind Kind,
+ DiagnosticConsumer *DiagClient,
+ bool emitPremigrationARCErrors = false,
+ StringRef plistOut = StringRef());
/// \brief Works similar to checkForManualIssues but instead of checking, it
/// applies automatic modifications to source files to conform to ARC.
///
/// \returns false if no error is produced, true otherwise.
bool applyTransformations(CompilerInvocation &origCI,
- llvm::StringRef Filename, InputKind Kind,
- DiagnosticClient *DiagClient);
+ StringRef Filename, InputKind Kind,
+ DiagnosticConsumer *DiagClient);
/// \brief Applies automatic modifications and produces temporary files
/// and metadata into the \arg outputDir path.
///
+/// \param emitPremigrationARCErrors if true all ARC errors will get emitted
+/// even if the migrator can fix them, but the function will still return false
+/// if all ARC errors can be fixed.
+///
+/// \param plistOut if non-empty, it is the file path to store the plist with
+/// the pre-migration ARC diagnostics.
+///
/// \returns false if no error is produced, true otherwise.
bool migrateWithTemporaryFiles(CompilerInvocation &origCI,
- llvm::StringRef Filename, InputKind Kind,
- DiagnosticClient *DiagClient,
- llvm::StringRef outputDir);
+ StringRef Filename, InputKind Kind,
+ DiagnosticConsumer *DiagClient,
+ StringRef outputDir,
+ bool emitPremigrationARCErrors,
+ StringRef plistOut);
/// \brief Get the set of file remappings from the \arg outputDir path that
/// migrateWithTemporaryFiles produced.
///
/// \returns false if no error is produced, true otherwise.
bool getFileRemappings(std::vector<std::pair<std::string,std::string> > &remap,
- llvm::StringRef outputDir,
- DiagnosticClient *DiagClient);
+ StringRef outputDir,
+ DiagnosticConsumer *DiagClient);
typedef void (*TransformFn)(MigrationPass &pass);
@@ -64,12 +82,12 @@ std::vector<TransformFn> getAllTransformations();
class MigrationProcess {
CompilerInvocation OrigCI;
- DiagnosticClient *DiagClient;
+ DiagnosticConsumer *DiagClient;
FileRemapper Remapper;
public:
- MigrationProcess(const CompilerInvocation &CI, DiagnosticClient *diagClient,
- llvm::StringRef outputDir = llvm::StringRef());
+ MigrationProcess(const CompilerInvocation &CI, DiagnosticConsumer *diagClient,
+ StringRef outputDir = StringRef());
class RewriteListener {
public:
@@ -78,7 +96,7 @@ public:
virtual void start(ASTContext &Ctx) { }
virtual void finish() { }
- virtual void insert(SourceLocation loc, llvm::StringRef text) { }
+ virtual void insert(SourceLocation loc, StringRef text) { }
virtual void remove(CharSourceRange range) { }
};
diff --git a/include/clang/ARCMigrate/ARCMTActions.h b/include/clang/ARCMigrate/ARCMTActions.h
index 4c714f55b390..4eac4facdd82 100644
--- a/include/clang/ARCMigrate/ARCMTActions.h
+++ b/include/clang/ARCMigrate/ARCMTActions.h
@@ -34,11 +34,15 @@ public:
class MigrateAction : public WrapperFrontendAction {
std::string MigrateDir;
+ std::string PlistOut;
+ bool EmitPremigrationARCErros;
protected:
virtual bool BeginInvocation(CompilerInstance &CI);
public:
- MigrateAction(FrontendAction *WrappedAction, llvm::StringRef migrateDir);
+ MigrateAction(FrontendAction *WrappedAction, StringRef migrateDir,
+ StringRef plistOut,
+ bool emitPremigrationARCErrors);
};
}
diff --git a/include/clang/ARCMigrate/FileRemapper.h b/include/clang/ARCMigrate/FileRemapper.h
index 809f6a5f71be..9a0b690ad691 100644
--- a/include/clang/ARCMigrate/FileRemapper.h
+++ b/include/clang/ARCMigrate/FileRemapper.h
@@ -10,6 +10,7 @@
#ifndef LLVM_CLANG_ARCMIGRATE_FILEREMAPPER_H
#define LLVM_CLANG_ARCMIGRATE_FILEREMAPPER_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/DenseMap.h"
@@ -22,7 +23,7 @@ namespace llvm {
namespace clang {
class FileManager;
class FileEntry;
- class Diagnostic;
+ class DiagnosticsEngine;
class CompilerInvocation;
namespace arcmt {
@@ -41,32 +42,32 @@ public:
FileRemapper();
~FileRemapper();
- bool initFromDisk(llvm::StringRef outputDir, Diagnostic &Diag,
+ bool initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag,
bool ignoreIfFilesChanged);
- bool flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag);
+ bool flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag);
- bool overwriteOriginal(Diagnostic &Diag,
- llvm::StringRef outputDir = llvm::StringRef());
+ bool overwriteOriginal(DiagnosticsEngine &Diag,
+ StringRef outputDir = StringRef());
- void remap(llvm::StringRef filePath, llvm::MemoryBuffer *memBuf);
- void remap(llvm::StringRef filePath, llvm::StringRef newPath);
+ void remap(StringRef filePath, llvm::MemoryBuffer *memBuf);
+ void remap(StringRef filePath, StringRef newPath);
void applyMappings(CompilerInvocation &CI) const;
void transferMappingsAndClear(CompilerInvocation &CI);
- void clear(llvm::StringRef outputDir = llvm::StringRef());
+ void clear(StringRef outputDir = StringRef());
private:
void remap(const FileEntry *file, llvm::MemoryBuffer *memBuf);
void remap(const FileEntry *file, const FileEntry *newfile);
- const FileEntry *getOriginalFile(llvm::StringRef filePath);
+ const FileEntry *getOriginalFile(StringRef filePath);
void resetTarget(Target &targ);
- bool report(const std::string &err, Diagnostic &Diag);
+ bool report(const Twine &err, DiagnosticsEngine &Diag);
- std::string getRemapInfoFile(llvm::StringRef outputDir);
+ std::string getRemapInfoFile(StringRef outputDir);
};
} // end namespace arcmt
diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h
index fec7d29f6d7b..375af28f0c56 100644
--- a/include/clang/AST/APValue.h
+++ b/include/clang/AST/APValue.h
@@ -14,11 +14,13 @@
#ifndef LLVM_CLANG_AST_APVALUE_H
#define LLVM_CLANG_AST_APVALUE_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/APFloat.h"
namespace clang {
class CharUnits;
+ class DiagnosticBuilder;
class Expr;
/// APValue - This class implements a discriminated union of [uninitialized]
@@ -103,7 +105,7 @@ public:
bool isLValue() const { return Kind == LValue; }
bool isVector() const { return Kind == Vector; }
- void print(llvm::raw_ostream &OS) const;
+ void print(raw_ostream &OS) const;
void dump() const;
APSInt &getInt() {
@@ -233,11 +235,15 @@ private:
void MakeLValue();
};
-inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const APValue &V) {
+inline raw_ostream &operator<<(raw_ostream &OS, const APValue &V) {
V.print(OS);
return OS;
}
+// Writes a concise representation of V to DB, in a single << operation.
+const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ const APValue &V);
+
} // end namespace clang.
#endif
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 1526f36ba2fb..c4ffac5341e7 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -37,7 +37,6 @@
namespace llvm {
struct fltSemantics;
- class raw_ostream;
}
namespace clang {
@@ -45,7 +44,7 @@ namespace clang {
class ASTRecordLayout;
class BlockExpr;
class CharUnits;
- class Diagnostic;
+ class DiagnosticsEngine;
class Expr;
class ExternalASTSource;
class ASTMutationListener;
@@ -64,6 +63,7 @@ namespace clang {
class ObjCIvarDecl;
class ObjCIvarRefExpr;
class ObjCPropertyDecl;
+ class ParmVarDecl;
class RecordDecl;
class StoredDeclsMap;
class TagDecl;
@@ -120,6 +120,7 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
mutable llvm::FoldingSet<ObjCObjectTypeImpl> ObjCObjectTypes;
mutable llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
mutable llvm::FoldingSet<AutoType> AutoTypes;
+ mutable llvm::FoldingSet<AtomicType> AtomicTypes;
llvm::FoldingSet<AttributedType> AttributedTypes;
mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
@@ -149,10 +150,19 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
/// \brief Mapping from ObjCContainers to their ObjCImplementations.
llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls;
+
+ /// \brief Mapping from ObjCMethod to its duplicate declaration in the same
+ /// interface.
+ llvm::DenseMap<const ObjCMethodDecl*,const ObjCMethodDecl*> ObjCMethodRedecls;
/// \brief Mapping from __block VarDecls to their copy initialization expr.
llvm::DenseMap<const VarDecl*, Expr*> BlockVarCopyInits;
+ /// \brief Mapping from class scope functions specialization to their
+ /// template patterns.
+ llvm::DenseMap<const FunctionDecl*, FunctionDecl*>
+ ClassScopeSpecializationPattern;
+
/// \brief Representation of a "canonical" template template parameter that
/// is used in canonical template names.
class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode {
@@ -175,34 +185,41 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
TemplateTemplateParmDecl *
getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const;
- /// \brief Whether __[u]int128_t identifier is installed.
- bool IsInt128Installed;
+ /// \brief The typedef for the __int128_t type.
+ mutable TypedefDecl *Int128Decl;
+ /// \brief The typedef for the __uint128_t type.
+ mutable TypedefDecl *UInt128Decl;
+
/// BuiltinVaListType - built-in va list type.
/// This is initially null and set by Sema::LazilyCreateBuiltin when
/// a builtin that takes a valist is encountered.
QualType BuiltinVaListType;
- /// ObjCIdType - a pseudo built-in typedef type (set by Sema).
- QualType ObjCIdTypedefType;
-
- /// ObjCSelType - another pseudo built-in typedef type (set by Sema).
- QualType ObjCSelTypedefType;
+ /// \brief The typedef for the predefined 'id' type.
+ mutable TypedefDecl *ObjCIdDecl;
+
+ /// \brief The typedef for the predefined 'SEL' type.
+ mutable TypedefDecl *ObjCSelDecl;
- /// ObjCProtoType - another pseudo built-in typedef type (set by Sema).
QualType ObjCProtoType;
const RecordType *ProtoStructType;
- /// ObjCClassType - another pseudo built-in typedef type (set by Sema).
- QualType ObjCClassTypedefType;
+ /// \brief The typedef for the predefined 'Class' type.
+ mutable TypedefDecl *ObjCClassDecl;
+
+ // Typedefs which may be provided defining the structure of Objective-C
+ // pseudo-builtins
+ QualType ObjCIdRedefinitionType;
+ QualType ObjCClassRedefinitionType;
+ QualType ObjCSelRedefinitionType;
QualType ObjCConstantStringType;
mutable RecordDecl *CFConstantStringTypeDecl;
- mutable RecordDecl *NSConstantStringTypeDecl;
-
- mutable RecordDecl *ObjCFastEnumerationStateTypeDecl;
-
+ /// \brief The typedef declaration for the Objective-C "instancetype" type.
+ TypedefDecl *ObjCInstanceTypeDecl;
+
/// \brief The type for the C FILE type.
TypeDecl *FILEDecl;
@@ -213,9 +230,15 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
TypeDecl *sigjmp_bufDecl;
/// \brief Type for the Block descriptor for Blocks CodeGen.
+ ///
+ /// Since this is only used for generation of debug info, it is not
+ /// serialized.
mutable RecordDecl *BlockDescriptorType;
/// \brief Type for the Block descriptor for Blocks CodeGen.
+ ///
+ /// Since this is only used for generation of debug info, it is not
+ /// serialized.
mutable RecordDecl *BlockDescriptorExtendedType;
/// \brief Declaration for the CUDA cudaConfigureCall function.
@@ -295,6 +318,12 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
typedef UsuallyTinyPtrVector<const CXXMethodDecl> CXXMethodVector;
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods;
+ /// \brief Mapping that stores parameterIndex values for ParmVarDecls
+ /// when that value exceeds the bitfield size of
+ /// ParmVarDeclBits.ParameterIndex.
+ typedef llvm::DenseMap<const VarDecl *, unsigned> ParameterIndexTable;
+ ParameterIndexTable ParamIndices;
+
TranslationUnitDecl *TUDecl;
/// SourceMgr - The associated SourceManager object.
@@ -302,7 +331,7 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
/// LangOpts - The language options used to create the AST associated with
/// this ASTContext object.
- LangOptions LangOpts;
+ LangOptions &LangOpts;
/// \brief The allocator used to create AST objects.
///
@@ -318,26 +347,29 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
CXXABI *createCXXABI(const TargetInfo &T);
/// \brief The logical -> physical address space map.
- const LangAS::Map &AddrSpaceMap;
+ const LangAS::Map *AddrSpaceMap;
friend class ASTDeclReader;
-
+ friend class ASTReader;
+ friend class ASTWriter;
+
+ const TargetInfo *Target;
+ clang::PrintingPolicy PrintingPolicy;
+
public:
- const TargetInfo &Target;
IdentifierTable &Idents;
SelectorTable &Selectors;
Builtin::Context &BuiltinInfo;
mutable DeclarationNameTable DeclarationNames;
llvm::OwningPtr<ExternalASTSource> ExternalSource;
ASTMutationListener *Listener;
- clang::PrintingPolicy PrintingPolicy;
- // Typedefs which may be provided defining the structure of Objective-C
- // pseudo-builtins
- QualType ObjCIdRedefinitionType;
- QualType ObjCClassRedefinitionType;
- QualType ObjCSelRedefinitionType;
+ clang::PrintingPolicy getPrintingPolicy() const { return PrintingPolicy; }
+ void setPrintingPolicy(clang::PrintingPolicy Policy) {
+ PrintingPolicy = Policy;
+ }
+
SourceManager& getSourceManager() { return SourceMgr; }
const SourceManager& getSourceManager() const { return SourceMgr; }
void *Allocate(unsigned Size, unsigned Align = 8) const {
@@ -357,9 +389,11 @@ public:
return DiagAllocator;
}
+ const TargetInfo &getTargetInfo() const { return *Target; }
+
const LangOptions& getLangOptions() const { return LangOpts; }
- Diagnostic &getDiagnostics() const;
+ DiagnosticsEngine &getDiagnostics() const;
FullSourceLoc getFullLoc(SourceLocation Loc) const {
return FullSourceLoc(Loc,SourceMgr);
@@ -377,6 +411,11 @@ public:
MemberSpecializationInfo *getInstantiatedFromStaticDataMember(
const VarDecl *Var);
+ FunctionDecl *getClassScopeSpecializationPattern(const FunctionDecl *FD);
+
+ void setClassScopeSpecializationPattern(FunctionDecl *FD,
+ FunctionDecl *Pattern);
+
/// \brief Note that the static data member \p Inst is an instantiation of
/// the static data member template \p Tmpl of a class template.
void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
@@ -413,17 +452,17 @@ public:
/// BitfieldFollowsBitfield - return 'true" if 'FD' is a
/// bitfield which follows the bitfield 'LastFD'.
bool BitfieldFollowsBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const;
+ const FieldDecl *LastFD) const;
- /// NoneBitfieldFollowsBitfield - return 'true" if 'FD' is not a
+ /// NonBitfieldFollowsBitfield - return 'true" if 'FD' is not a
/// bitfield which follows the bitfield 'LastFD'.
- bool NoneBitfieldFollowsBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const;
+ bool NonBitfieldFollowsBitfield(const FieldDecl *FD,
+ const FieldDecl *LastFD) const;
- /// BitfieldFollowsNoneBitfield - return 'true" if 'FD' is a
+ /// BitfieldFollowsNonBitfield - return 'true" if 'FD' is a
/// bitfield which follows the none bitfield 'LastFD'.
- bool BitfieldFollowsNoneBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const;
+ bool BitfieldFollowsNonBitfield(const FieldDecl *FD,
+ const FieldDecl *LastFD) const;
// Access to the set of methods overridden by the given C++ method.
typedef CXXMethodVector::iterator overridden_cxx_method_iterator;
@@ -454,6 +493,7 @@ public:
CanQualType UnsignedCharTy, UnsignedShortTy, UnsignedIntTy, UnsignedLongTy;
CanQualType UnsignedLongLongTy, UnsignedInt128Ty;
CanQualType FloatTy, DoubleTy, LongDoubleTy;
+ CanQualType HalfTy; // [OpenCL 6.1.1.1], ARM NEON
CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
CanQualType VoidPtrTy, NullPtrTy;
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
@@ -463,10 +503,11 @@ public:
mutable QualType AutoDeductTy; // Deduction against 'auto'.
mutable QualType AutoRRefDeductTy; // Deduction against 'auto &&'.
- ASTContext(const LangOptions& LOpts, SourceManager &SM, const TargetInfo &t,
+ ASTContext(LangOptions& LOpts, SourceManager &SM, const TargetInfo *t,
IdentifierTable &idents, SelectorTable &sels,
Builtin::Context &builtins,
- unsigned size_reserve);
+ unsigned size_reserve,
+ bool DelayInitialization = false);
~ASTContext();
@@ -497,6 +538,12 @@ public:
void PrintStats() const;
const std::vector<Type*>& getTypes() const { return Types; }
+ /// \brief Retrieve the declaration for the 128-bit signed integer type.
+ TypedefDecl *getInt128Decl() const;
+
+ /// \brief Retrieve the declaration for the 128-bit unsigned integer type.
+ TypedefDecl *getUInt128Decl() const;
+
//===--------------------------------------------------------------------===//
// Type Constructors
//===--------------------------------------------------------------------===//
@@ -560,6 +607,10 @@ public:
return CanQualType::CreateUnsafe(getPointerType((QualType) T));
}
+ /// getAtomicType - Return the uniqued reference to the atomic type for
+ /// the specified type.
+ QualType getAtomicType(QualType T) const;
+
/// getBlockPointerType - Return the uniqued reference to the type for a block
/// of the specified type.
QualType getBlockPointerType(QualType T) const;
@@ -568,29 +619,10 @@ public:
/// blocks.
QualType getBlockDescriptorType() const;
- // Set the type for a Block descriptor type.
- void setBlockDescriptorType(QualType T);
- /// Get the BlockDescriptorType type, or NULL if it hasn't yet been built.
- QualType getRawBlockdescriptorType() {
- if (BlockDescriptorType)
- return getTagDeclType(BlockDescriptorType);
- return QualType();
- }
-
/// This gets the struct used to keep track of the extended descriptor for
/// pointer to blocks.
QualType getBlockDescriptorExtendedType() const;
- // Set the type for a Block descriptor extended type.
- void setBlockDescriptorExtendedType(QualType T);
- /// Get the BlockDescriptorExtendedType type, or NULL if it hasn't yet been
- /// built.
- QualType getRawBlockdescriptorExtendedType() const {
- if (BlockDescriptorExtendedType)
- return getTagDeclType(BlockDescriptorExtendedType);
- return QualType();
- }
-
void setcudaConfigureCallDecl(FunctionDecl *FD) {
cudaConfigureCallDecl = FD;
}
@@ -599,7 +631,7 @@ public:
}
/// This builds the struct used for __block variables.
- QualType BuildByRefType(llvm::StringRef DeclName, QualType Ty) const;
+ QualType BuildByRefType(StringRef DeclName, QualType Ty) const;
/// Returns true iff we need copy/dispose helpers for the given type.
bool BlockRequiresCopying(QualType Ty) const;
@@ -824,19 +856,6 @@ public:
// constant CFStrings.
QualType getCFConstantStringType() const;
- // getNSConstantStringType - Return the C structure type used to represent
- // constant NSStrings.
- QualType getNSConstantStringType() const;
- /// Get the structure type used to representation NSStrings, or NULL
- /// if it hasn't yet been built.
- QualType getRawNSConstantStringType() const {
- if (NSConstantStringTypeDecl)
- return getTagDeclType(NSConstantStringTypeDecl);
- return QualType();
- }
- void setNSConstantStringType(QualType T);
-
-
/// Get the structure type used to representation CFStrings, or NULL
/// if it hasn't yet been built.
QualType getRawCFConstantStringType() const {
@@ -852,19 +871,56 @@ public:
return ObjCConstantStringType;
}
- //// This gets the struct used to keep track of fast enumerations.
- QualType getObjCFastEnumerationStateType() const;
+ /// \brief Retrieve the type that 'id' has been defined to, which may be
+ /// different from the built-in 'id' if 'id' has been typedef'd.
+ QualType getObjCIdRedefinitionType() const {
+ if (ObjCIdRedefinitionType.isNull())
+ return getObjCIdType();
+ return ObjCIdRedefinitionType;
+ }
+
+ /// \brief Set the user-written type that redefines 'id'.
+ void setObjCIdRedefinitionType(QualType RedefType) {
+ ObjCIdRedefinitionType = RedefType;
+ }
- /// Get the ObjCFastEnumerationState type, or NULL if it hasn't yet
- /// been built.
- QualType getRawObjCFastEnumerationStateType() const {
- if (ObjCFastEnumerationStateTypeDecl)
- return getTagDeclType(ObjCFastEnumerationStateTypeDecl);
- return QualType();
+ /// \brief Retrieve the type that 'Class' has been defined to, which may be
+ /// different from the built-in 'Class' if 'Class' has been typedef'd.
+ QualType getObjCClassRedefinitionType() const {
+ if (ObjCClassRedefinitionType.isNull())
+ return getObjCClassType();
+ return ObjCClassRedefinitionType;
+ }
+
+ /// \brief Set the user-written type that redefines 'SEL'.
+ void setObjCClassRedefinitionType(QualType RedefType) {
+ ObjCClassRedefinitionType = RedefType;
+ }
+
+ /// \brief Retrieve the type that 'SEL' has been defined to, which may be
+ /// different from the built-in 'SEL' if 'SEL' has been typedef'd.
+ QualType getObjCSelRedefinitionType() const {
+ if (ObjCSelRedefinitionType.isNull())
+ return getObjCSelType();
+ return ObjCSelRedefinitionType;
+ }
+
+
+ /// \brief Set the user-written type that redefines 'SEL'.
+ void setObjCSelRedefinitionType(QualType RedefType) {
+ ObjCSelRedefinitionType = RedefType;
}
- void setObjCFastEnumerationStateType(QualType T);
+ /// \brief Retrieve the Objective-C "instancetype" type, if already known;
+ /// otherwise, returns a NULL type;
+ QualType getObjCInstanceType() {
+ return getTypeDeclType(getObjCInstanceTypeDecl());
+ }
+ /// \brief Retrieve the typedef declaration corresponding to the Objective-C
+ /// "instancetype" type.
+ TypedefDecl *getObjCInstanceTypeDecl();
+
/// \brief Set the type for the C FILE type.
void setFILEDecl(TypeDecl *FILEDecl) { this->FILEDecl = FILEDecl; }
@@ -950,26 +1006,39 @@ public:
/// purpose in characters.
CharUnits getObjCEncodingTypeSize(QualType t) const;
- /// \brief Whether __[u]int128_t identifier is installed.
- bool isInt128Installed() const { return IsInt128Installed; }
- void setInt128Installed() { IsInt128Installed = true; }
-
+ /// \brief Retrieve the typedef corresponding to the predefined 'id' type
+ /// in Objective-C.
+ TypedefDecl *getObjCIdDecl() const;
+
/// This setter/getter represents the ObjC 'id' type. It is setup lazily, by
/// Sema. id is always a (typedef for a) pointer type, a pointer to a struct.
- QualType getObjCIdType() const { return ObjCIdTypedefType; }
- void setObjCIdType(QualType T);
+ QualType getObjCIdType() const {
+ return getTypeDeclType(getObjCIdDecl());
+ }
- void setObjCSelType(QualType T);
- QualType getObjCSelType() const { return ObjCSelTypedefType; }
+ /// \brief Retrieve the typedef corresponding to the predefined 'SEL' type
+ /// in Objective-C.
+ TypedefDecl *getObjCSelDecl() const;
+
+ /// \brief Retrieve the type that corresponds to the predefined Objective-C
+ /// 'SEL' type.
+ QualType getObjCSelType() const {
+ return getTypeDeclType(getObjCSelDecl());
+ }
void setObjCProtoType(QualType QT);
QualType getObjCProtoType() const { return ObjCProtoType; }
+ /// \brief Retrieve the typedef declaration corresponding to the predefined
+ /// Objective-C 'Class' type.
+ TypedefDecl *getObjCClassDecl() const;
+
/// This setter/getter repreents the ObjC 'Class' type. It is setup lazily, by
/// Sema. 'Class' is always a (typedef for a) pointer type, a pointer to a
/// struct.
- QualType getObjCClassType() const { return ObjCClassTypedefType; }
- void setObjCClassType(QualType T);
+ QualType getObjCClassType() const {
+ return getTypeDeclType(getObjCClassDecl());
+ }
void setBuiltinVaListType(QualType T);
QualType getBuiltinVaListType() const { return BuiltinVaListType; }
@@ -1145,7 +1214,7 @@ public:
const ASTRecordLayout &getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D)
const;
- void DumpRecordLayout(const RecordDecl *RD, llvm::raw_ostream &OS) const;
+ void DumpRecordLayout(const RecordDecl *RD, raw_ostream &OS) const;
/// getASTObjCImplementationLayout - Get or compute information about
/// the layout of the specified Objective-C implementation. This may
@@ -1164,13 +1233,9 @@ public:
bool isNearlyEmpty(const CXXRecordDecl *RD) const;
MangleContext *createMangleContext();
-
- void ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI,
- llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars)
- const;
void DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass,
- llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) const;
+ SmallVectorImpl<const ObjCIvarDecl*> &Ivars) const;
unsigned CountNonClassIvars(const ObjCInterfaceDecl *OI) const;
void CollectInheritedProtocols(const Decl *CDecl,
@@ -1261,7 +1326,7 @@ public:
/// \brief Retrieves the canonical representation of the given
/// calling convention.
CallingConv getCanonicalCallConv(CallingConv CC) const {
- if (CC == CC_C)
+ if (!LangOpts.MRTD && CC == CC_C)
return CC_Default;
return CC;
}
@@ -1400,7 +1465,7 @@ public:
if (AS < LangAS::Offset || AS >= LangAS::Offset + LangAS::Count)
return AS;
else
- return AddrSpaceMap[AS - LangAS::Offset];
+ return (*AddrSpaceMap)[AS - LangAS::Offset];
}
private:
@@ -1421,13 +1486,13 @@ public:
bool typesAreBlockPointerCompatible(QualType, QualType);
bool isObjCIdType(QualType T) const {
- return T == ObjCIdTypedefType;
+ return T == getObjCIdType();
}
bool isObjCClassType(QualType T) const {
- return T == ObjCClassTypedefType;
+ return T == getObjCClassType();
}
bool isObjCSelType(QualType T) const {
- return T == ObjCSelTypedefType;
+ return T == getObjCSelType();
}
bool QualifiedIdConformsQualifiedId(QualType LHS, QualType RHS);
bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS,
@@ -1462,6 +1527,10 @@ public:
bool Unqualified = false);
QualType mergeObjCGCQualifiers(QualType, QualType);
+
+ bool FunctionTypesMatchOnNSConsumedAttrs(
+ const FunctionProtoType *FromFunctionType,
+ const FunctionProtoType *ToFunctionType);
void ResetObjCLayout(const ObjCContainerDecl *CD) {
ObjCLayouts[CD] = 0;
@@ -1521,6 +1590,22 @@ public:
/// \brief Set the implementation of ObjCCategoryDecl.
void setObjCImplementation(ObjCCategoryDecl *CatD,
ObjCCategoryImplDecl *ImplD);
+
+ /// \brief Get the duplicate declaration of a ObjCMethod in the same
+ /// interface, or null if non exists.
+ const ObjCMethodDecl *getObjCMethodRedeclaration(
+ const ObjCMethodDecl *MD) const {
+ llvm::DenseMap<const ObjCMethodDecl*, const ObjCMethodDecl*>::const_iterator
+ I = ObjCMethodRedecls.find(MD);
+ if (I == ObjCMethodRedecls.end())
+ return 0;
+ return I->second;
+ }
+
+ void setObjCMethodRedeclaration(const ObjCMethodDecl *MD,
+ const ObjCMethodDecl *Redecl) {
+ ObjCMethodRedecls[MD] = Redecl;
+ }
/// \brief Set the copy inialization expression of a block var decl.
void setBlockVarCopyInits(VarDecl*VD, Expr* Init);
@@ -1570,6 +1655,15 @@ public:
/// it is not used.
bool DeclMustBeEmitted(const Decl *D);
+
+ /// \brief Used by ParmVarDecl to store on the side the
+ /// index of the parameter when it exceeds the size of the normal bitfield.
+ void setParameterIndex(const ParmVarDecl *D, unsigned index);
+
+ /// \brief Used by ParmVarDecl to retrieve on the side the
+ /// index of the parameter when it exceeds the size of the normal bitfield.
+ unsigned getParameterIndex(const ParmVarDecl *D) const;
+
//===--------------------------------------------------------------------===//
// Statistics
//===--------------------------------------------------------------------===//
@@ -1620,7 +1714,18 @@ private:
ASTContext(const ASTContext&); // DO NOT IMPLEMENT
void operator=(const ASTContext&); // DO NOT IMPLEMENT
- void InitBuiltinTypes();
+public:
+ /// \brief Initialize built-in types.
+ ///
+ /// This routine may only be invoked once for a given ASTContext object.
+ /// It is normally invoked by the ASTContext constructor. However, the
+ /// constructor can be asked to delay initialization, which places the burden
+ /// of calling this function on the user of that object.
+ ///
+ /// \param Target The target
+ void InitBuiltinTypes(const TargetInfo &Target);
+
+private:
void InitBuiltinType(CanQualType &R, BuiltinType::Kind K);
// Return the ObjC type encoding for a given type.
@@ -1644,7 +1749,7 @@ private:
private:
/// \brief A set of deallocations that should be performed when the
/// ASTContext is destroyed.
- llvm::SmallVector<std::pair<void (*)(void*), void *>, 16> Deallocations;
+ SmallVector<std::pair<void (*)(void*), void *>, 16> Deallocations;
// FIXME: This currently contains the set of StoredDeclMaps used
// by DeclContext objects. This probably should not be in ASTContext,
@@ -1660,13 +1765,13 @@ private:
};
/// @brief Utility function for constructing a nullary selector.
-static inline Selector GetNullarySelector(llvm::StringRef name, ASTContext& Ctx) {
+static inline Selector GetNullarySelector(StringRef name, ASTContext& Ctx) {
IdentifierInfo* II = &Ctx.Idents.get(name);
return Ctx.Selectors.getSelector(0, &II);
}
/// @brief Utility function for constructing an unary selector.
-static inline Selector GetUnarySelector(llvm::StringRef name, ASTContext& Ctx) {
+static inline Selector GetUnarySelector(StringRef name, ASTContext& Ctx) {
IdentifierInfo* II = &Ctx.Idents.get(name);
return Ctx.Selectors.getSelector(1, &II);
}
diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h
index 70a548d4e965..b0057113cf8e 100644
--- a/include/clang/AST/ASTDiagnostic.h
+++ b/include/clang/AST/ASTDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM,
+ SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM,
#define ASTSTART
#include "clang/Basic/DiagnosticASTKinds.inc"
#undef DIAG
@@ -24,27 +24,27 @@ namespace clang {
};
} // end namespace diag
- /// \brief Diagnostic argument formatting function for diagnostics that
+ /// \brief DiagnosticsEngine argument formatting function for diagnostics that
/// involve AST nodes.
///
/// This function formats diagnostic arguments for various AST nodes,
/// including types, declaration names, nested name specifiers, and
/// declaration contexts, into strings that can be printed as part of
/// diagnostics. It is meant to be used as the argument to
- /// \c Diagnostic::SetArgToStringFn(), where the cookie is an \c ASTContext
- /// pointer.
+ /// \c DiagnosticsEngine::SetArgToStringFn(), where the cookie is an \c
+ /// ASTContext pointer.
void FormatASTNodeDiagnosticArgument(
- Diagnostic::ArgumentKind Kind,
+ DiagnosticsEngine::ArgumentKind Kind,
intptr_t Val,
const char *Modifier,
unsigned ModLen,
const char *Argument,
unsigned ArgLen,
- const Diagnostic::ArgumentValue *PrevArgs,
+ const DiagnosticsEngine::ArgumentValue *PrevArgs,
unsigned NumPrevArgs,
- llvm::SmallVectorImpl<char> &Output,
+ SmallVectorImpl<char> &Output,
void *Cookie,
- llvm::SmallVectorImpl<intptr_t> &QualTypeVals);
+ SmallVectorImpl<intptr_t> &QualTypeVals);
} // end namespace clang
#endif
diff --git a/include/clang/AST/ASTImporter.h b/include/clang/AST/ASTImporter.h
index e1535965b1e4..b583fbf9061b 100644
--- a/include/clang/AST/ASTImporter.h
+++ b/include/clang/AST/ASTImporter.h
@@ -25,7 +25,7 @@ namespace clang {
class ASTContext;
class Decl;
class DeclContext;
- class Diagnostic;
+ class DiagnosticsEngine;
class Expr;
class FileManager;
class IdentifierInfo;
@@ -67,7 +67,7 @@ namespace clang {
/// \brief Imported, anonymous tag declarations that are missing their
/// corresponding typedefs.
- llvm::SmallVector<TagDecl *, 4> AnonTagsWithPendingTypedefs;
+ SmallVector<TagDecl *, 4> AnonTagsWithPendingTypedefs;
/// \brief Declaration (from, to) pairs that are known not to be equivalent
/// (which we have already complained about).
diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h
index 470cca8ee76e..793d3ee2b1fb 100644
--- a/include/clang/AST/ASTMutationListener.h
+++ b/include/clang/AST/ASTMutationListener.h
@@ -22,6 +22,8 @@ namespace clang {
class ClassTemplateSpecializationDecl;
class FunctionDecl;
class FunctionTemplateDecl;
+ class ObjCCategoryDecl;
+ class ObjCInterfaceDecl;
/// \brief An abstract interface that should be implemented by listeners
/// that want to be notified when an AST entity gets modified after its
@@ -54,6 +56,10 @@ public:
/// \brief A static data member was implicitly instantiated.
virtual void StaticDataMemberInstantiated(const VarDecl *D) {}
+
+ /// \brief A new objc category class was added for an interface.
+ virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
+ const ObjCInterfaceDecl *IFD) {}
};
} // end namespace clang
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index 719023926bae..cf2e3c5d25b6 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -14,18 +14,18 @@
#ifndef LLVM_CLANG_AST_ATTR_H
#define LLVM_CLANG_AST_ATTR_H
-#include "llvm/Support/Casting.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
+#include "clang/Basic/LLVM.h"
#include "clang/Basic/AttrKinds.h"
#include "clang/AST/Type.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/VersionTuple.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
#include <cassert>
#include <cstring>
#include <algorithm>
-using llvm::dyn_cast;
namespace clang {
class ASTContext;
@@ -58,7 +58,7 @@ namespace clang {
/// Attr - This represents one attribute.
class Attr {
private:
- SourceLocation Loc;
+ SourceRange Range;
unsigned AttrKind : 16;
protected:
@@ -67,11 +67,10 @@ protected:
virtual ~Attr();
void* operator new(size_t bytes) throw() {
- assert(0 && "Attrs cannot be allocated with regular 'new'.");
- return 0;
+ llvm_unreachable("Attrs cannot be allocated with regular 'new'.");
}
void operator delete(void* data) throw() {
- assert(0 && "Attrs cannot be released with regular 'delete'.");
+ llvm_unreachable("Attrs cannot be released with regular 'delete'.");
}
public:
@@ -86,8 +85,8 @@ public:
}
protected:
- Attr(attr::Kind AK, SourceLocation L)
- : Loc(L), AttrKind(AK), Inherited(false) {}
+ Attr(attr::Kind AK, SourceRange R)
+ : Range(R), AttrKind(AK), Inherited(false) {}
public:
@@ -95,8 +94,9 @@ public:
return static_cast<attr::Kind>(AttrKind);
}
- SourceLocation getLocation() const { return Loc; }
- void setLocation(SourceLocation L) { Loc = L; }
+ SourceLocation getLocation() const { return Range.getBegin(); }
+ SourceRange getRange() const { return Range; }
+ void setRange(SourceRange R) { Range = R; }
bool isInherited() const { return Inherited; }
@@ -109,8 +109,8 @@ public:
class InheritableAttr : public Attr {
protected:
- InheritableAttr(attr::Kind AK, SourceLocation L)
- : Attr(AK, L) {}
+ InheritableAttr(attr::Kind AK, SourceRange R)
+ : Attr(AK, R) {}
public:
void setInherited(bool I) { Inherited = I; }
@@ -124,8 +124,8 @@ public:
class InheritableParamAttr : public InheritableAttr {
protected:
- InheritableParamAttr(attr::Kind AK, SourceLocation L)
- : InheritableAttr(AK, L) {}
+ InheritableParamAttr(attr::Kind AK, SourceRange R)
+ : InheritableAttr(AK, R) {}
public:
// Implement isa/cast/dyncast/etc.
@@ -138,8 +138,8 @@ public:
#include "clang/AST/Attrs.inc"
/// AttrVec - A vector of Attr, which is how they are stored on the AST.
-typedef llvm::SmallVector<Attr*, 2> AttrVec;
-typedef llvm::SmallVector<const Attr*, 2> ConstAttrVec;
+typedef SmallVector<Attr*, 2> AttrVec;
+typedef SmallVector<const Attr*, 2> ConstAttrVec;
/// DestroyAttrs - Destroy the contents of an AttrVec.
inline void DestroyAttrs (AttrVec& V, ASTContext &C) {
@@ -159,12 +159,12 @@ class specific_attr_iterator {
mutable AttrVec::const_iterator Current;
void AdvanceToNext() const {
- while (!llvm::isa<SpecificAttr>(*Current))
+ while (!isa<SpecificAttr>(*Current))
++Current;
}
void AdvanceToNext(AttrVec::const_iterator I) const {
- while (Current != I && !llvm::isa<SpecificAttr>(*Current))
+ while (Current != I && !isa<SpecificAttr>(*Current))
++Current;
}
@@ -180,11 +180,11 @@ public:
reference operator*() const {
AdvanceToNext();
- return llvm::cast<SpecificAttr>(*Current);
+ return cast<SpecificAttr>(*Current);
}
pointer operator->() const {
AdvanceToNext();
- return llvm::cast<SpecificAttr>(*Current);
+ return cast<SpecificAttr>(*Current);
}
specific_attr_iterator& operator++() {
diff --git a/include/clang/AST/BaseSubobject.h b/include/clang/AST/BaseSubobject.h
new file mode 100644
index 000000000000..6a036bb62cf4
--- /dev/null
+++ b/include/clang/AST/BaseSubobject.h
@@ -0,0 +1,87 @@
+//===--- BaseSubobject.h - BaseSubobject class ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides a definition of the BaseSubobject class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_BASESUBOBJECT_H
+#define LLVM_CLANG_AST_BASESUBOBJECT_H
+
+#include "clang/AST/CharUnits.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/type_traits.h"
+
+namespace clang {
+ class CXXRecordDecl;
+
+// BaseSubobject - Uniquely identifies a direct or indirect base class.
+// Stores both the base class decl and the offset from the most derived class to
+// the base class. Used for vtable and VTT generation.
+class BaseSubobject {
+ /// Base - The base class declaration.
+ const CXXRecordDecl *Base;
+
+ /// BaseOffset - The offset from the most derived class to the base class.
+ CharUnits BaseOffset;
+
+public:
+ BaseSubobject() { }
+ BaseSubobject(const CXXRecordDecl *Base, CharUnits BaseOffset)
+ : Base(Base), BaseOffset(BaseOffset) { }
+
+ /// getBase - Returns the base class declaration.
+ const CXXRecordDecl *getBase() const { return Base; }
+
+ /// getBaseOffset - Returns the base class offset.
+ CharUnits getBaseOffset() const { return BaseOffset; }
+
+ friend bool operator==(const BaseSubobject &LHS, const BaseSubobject &RHS) {
+ return LHS.Base == RHS.Base && LHS.BaseOffset == RHS.BaseOffset;
+ }
+};
+
+} // end namespace clang
+
+namespace llvm {
+
+template<> struct DenseMapInfo<clang::BaseSubobject> {
+ static clang::BaseSubobject getEmptyKey() {
+ return clang::BaseSubobject(
+ DenseMapInfo<const clang::CXXRecordDecl *>::getEmptyKey(),
+ clang::CharUnits::fromQuantity(DenseMapInfo<int64_t>::getEmptyKey()));
+ }
+
+ static clang::BaseSubobject getTombstoneKey() {
+ return clang::BaseSubobject(
+ DenseMapInfo<const clang::CXXRecordDecl *>::getTombstoneKey(),
+ clang::CharUnits::fromQuantity(DenseMapInfo<int64_t>::getTombstoneKey()));
+ }
+
+ static unsigned getHashValue(const clang::BaseSubobject &Base) {
+ return
+ DenseMapInfo<const clang::CXXRecordDecl *>::getHashValue(Base.getBase()) ^
+ DenseMapInfo<int64_t>::getHashValue(Base.getBaseOffset().getQuantity());
+ }
+
+ static bool isEqual(const clang::BaseSubobject &LHS,
+ const clang::BaseSubobject &RHS) {
+ return LHS == RHS;
+ }
+};
+
+// It's OK to treat BaseSubobject as a POD type.
+template <> struct isPodLike<clang::BaseSubobject> {
+ static const bool value = true;
+};
+
+}
+
+#endif
diff --git a/include/clang/AST/CXXInheritance.h b/include/clang/AST/CXXInheritance.h
index d712e7d0c751..44c554b606c4 100644
--- a/include/clang/AST/CXXInheritance.h
+++ b/include/clang/AST/CXXInheritance.h
@@ -66,7 +66,7 @@ struct CXXBasePathElement {
/// structure, which captures both the link from a derived class to one of its
/// direct bases and identification describing which base class
/// subobject is being used.
-class CXXBasePath : public llvm::SmallVector<CXXBasePathElement, 4> {
+class CXXBasePath : public SmallVector<CXXBasePathElement, 4> {
public:
CXXBasePath() : Access(AS_public) {}
@@ -80,7 +80,7 @@ public:
DeclContext::lookup_result Decls;
void clear() {
- llvm::SmallVectorImpl<CXXBasePathElement>::clear();
+ SmallVectorImpl<CXXBasePathElement>::clear();
Access = AS_public;
}
};
@@ -272,14 +272,14 @@ struct UniqueVirtualMethod {
/// pair is the virtual method that overrides it (including the
/// subobject in which that virtual function occurs).
class OverridingMethods {
- llvm::DenseMap<unsigned, llvm::SmallVector<UniqueVirtualMethod, 4> >
+ llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> >
Overrides;
public:
// Iterate over the set of subobjects that have overriding methods.
- typedef llvm::DenseMap<unsigned, llvm::SmallVector<UniqueVirtualMethod, 4> >
+ typedef llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> >
::iterator iterator;
- typedef llvm::DenseMap<unsigned, llvm::SmallVector<UniqueVirtualMethod, 4> >
+ typedef llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> >
::const_iterator const_iterator;
iterator begin() { return Overrides.begin(); }
const_iterator begin() const { return Overrides.begin(); }
@@ -289,9 +289,9 @@ public:
// Iterate over the set of overriding virtual methods in a given
// subobject.
- typedef llvm::SmallVector<UniqueVirtualMethod, 4>::iterator
+ typedef SmallVector<UniqueVirtualMethod, 4>::iterator
overriding_iterator;
- typedef llvm::SmallVector<UniqueVirtualMethod, 4>::const_iterator
+ typedef SmallVector<UniqueVirtualMethod, 4>::const_iterator
overriding_const_iterator;
// Add a new overriding method for a particular subobject.
diff --git a/include/clang/AST/CharUnits.h b/include/clang/AST/CharUnits.h
index d7cbd08e6c2e..5be35826a964 100644
--- a/include/clang/AST/CharUnits.h
+++ b/include/clang/AST/CharUnits.h
@@ -125,6 +125,12 @@ namespace clang {
/// isNegative - Test whether the quantity is less than zero.
bool isNegative() const { return Quantity < 0; }
+ /// isPowerOfTwo - Test whether the quantity is a power of two.
+ /// Zero is not a power of two.
+ bool isPowerOfTwo() const {
+ return (Quantity & -Quantity) == Quantity;
+ }
+
// Arithmetic operators.
CharUnits operator* (QuantityType N) const {
return CharUnits(Quantity * N);
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 5691e99e7297..a02a2ce3369f 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -20,6 +20,7 @@
#include "clang/AST/DeclarationName.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/Basic/Linkage.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
namespace clang {
@@ -32,6 +33,7 @@ class StringLiteral;
class NestedNameSpecifier;
class TemplateParameterList;
class TemplateArgumentList;
+struct ASTTemplateArgumentListInfo;
class MemberSpecializationInfo;
class FunctionTemplateSpecializationInfo;
class DependentFunctionTemplateSpecializationInfo;
@@ -115,7 +117,7 @@ public:
/// getName - Get the name of identifier for this declaration as a StringRef.
/// This requires that the declaration have a name and that it be a simple
/// identifier.
- llvm::StringRef getName() const {
+ StringRef getName() const {
assert(Name.isIdentifier() && "Name is not a simple identifier");
return getIdentifier() ? getIdentifier()->getName() : "";
}
@@ -132,7 +134,7 @@ public:
// FIXME: Deprecated, move clients to getName().
std::string getNameAsString() const { return Name.getAsString(); }
- void printName(llvm::raw_ostream &os) const { return Name.printName(os); }
+ void printName(raw_ostream &os) const { return Name.printName(os); }
/// getDeclName - Get the actual, stored name of the declaration,
/// which may be a special name.
@@ -180,6 +182,16 @@ public:
/// \brief Determine whether this declaration has linkage.
bool hasLinkage() const;
+ /// \brief Whether this declaration was marked as being private to the
+ /// module in which it was defined.
+ bool isModulePrivate() const { return ModulePrivate; }
+
+ /// \brief Specify whether this declaration was marked as being private
+ /// to the module in which it was defined.
+ void setModulePrivate(bool MP = true) {
+ ModulePrivate = MP;
+ }
+
/// \brief Determine whether this declaration is a C++ class member.
bool isCXXClassMember() const {
const DeclContext *DC = getDeclContext();
@@ -294,9 +306,8 @@ public:
static bool classofKind(Kind K) { return K >= firstNamed && K <= lastNamed; }
};
-inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
- const NamedDecl *ND) {
- ND->getDeclName().printName(OS);
+inline raw_ostream &operator<<(raw_ostream &OS, const NamedDecl &ND) {
+ ND.printName(OS);
return OS;
}
@@ -706,13 +717,18 @@ private:
/// \brief Whether this variable is an ARC pseudo-__strong
/// variable; see isARCPseudoStrong() for details.
unsigned ARCPseudoStrong : 1;
+
+ /// \brief Whether this variable is (C++0x) constexpr.
+ unsigned IsConstexpr : 1;
};
- enum { NumVarDeclBits = 13 }; // one reserved bit
+ enum { NumVarDeclBits = 13 };
friend class ASTDeclReader;
friend class StmtIteratorBase;
protected:
+ enum { NumParameterIndexBits = 8 };
+
class ParmVarDeclBitfields {
friend class ParmVarDecl;
friend class ASTDeclReader;
@@ -737,7 +753,7 @@ protected:
/// The number of parameters preceding this parameter in the
/// function parameter scope in which it was declared.
- unsigned ParameterIndex : 8;
+ unsigned ParameterIndex : NumParameterIndexBits;
};
union {
@@ -802,7 +818,7 @@ public:
return !isFileVarDecl();
// Return true for: Auto, Register.
- // Return false for: Extern, Static, PrivateExtern.
+ // Return false for: Extern, Static, PrivateExtern, OpenCLWorkGroupLocal.
return getStorageClass() >= SC_Auto;
}
@@ -1128,6 +1144,10 @@ public:
bool isARCPseudoStrong() const { return VarDeclBits.ARCPseudoStrong; }
void setARCPseudoStrong(bool ps) { VarDeclBits.ARCPseudoStrong = ps; }
+ /// Whether this variable is (C++0x) constexpr.
+ bool isConstexpr() const { return VarDeclBits.IsConstexpr; }
+ void setConstexpr(bool IC) { VarDeclBits.IsConstexpr = IC; }
+
/// \brief If this variable is an instantiated static data member of a
/// class template specialization, returns the templated static data member
/// from which it was instantiated.
@@ -1198,11 +1218,11 @@ public:
StorageClass S, StorageClass SCAsWritten,
Expr *DefArg);
+ virtual SourceRange getSourceRange() const;
+
void setObjCMethodScopeInfo(unsigned parameterIndex) {
ParmVarDeclBits.IsObjCMethodParam = true;
-
- ParmVarDeclBits.ParameterIndex = parameterIndex;
- assert(ParmVarDeclBits.ParameterIndex == parameterIndex && "truncation!");
+ setParameterIndex(parameterIndex);
}
void setScopeInfo(unsigned scopeDepth, unsigned parameterIndex) {
@@ -1211,8 +1231,7 @@ public:
ParmVarDeclBits.ScopeDepthOrObjCQuals = scopeDepth;
assert(ParmVarDeclBits.ScopeDepthOrObjCQuals == scopeDepth && "truncation!");
- ParmVarDeclBits.ParameterIndex = parameterIndex;
- assert(ParmVarDeclBits.ParameterIndex == parameterIndex && "truncation!");
+ setParameterIndex(parameterIndex);
}
bool isObjCMethodParameter() const {
@@ -1226,7 +1245,7 @@ public:
/// Returns the index of this parameter in its prototype or method scope.
unsigned getFunctionScopeIndex() const {
- return ParmVarDeclBits.ParameterIndex;
+ return getParameterIndex();
}
ObjCDeclQualifier getObjCDeclQualifier() const {
@@ -1343,6 +1362,26 @@ public:
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ParmVarDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ParmVar; }
+
+private:
+ enum { ParameterIndexSentinel = (1 << NumParameterIndexBits) - 1 };
+
+ void setParameterIndex(unsigned parameterIndex) {
+ if (parameterIndex >= ParameterIndexSentinel) {
+ setParameterIndexLarge(parameterIndex);
+ return;
+ }
+
+ ParmVarDeclBits.ParameterIndex = parameterIndex;
+ assert(ParmVarDeclBits.ParameterIndex == parameterIndex && "truncation!");
+ }
+ unsigned getParameterIndex() const {
+ unsigned d = ParmVarDeclBits.ParameterIndex;
+ return d == ParameterIndexSentinel ? getParameterIndexLarge() : d;
+ }
+
+ void setParameterIndexLarge(unsigned parameterIndex);
+ unsigned getParameterIndexLarge() const;
};
/// FunctionDecl - An instance of this class is created to represent a
@@ -1394,6 +1433,7 @@ private:
bool IsExplicitlyDefaulted : 1; //sunk from CXXMethodDecl
bool HasImplicitReturnZero : 1;
bool IsLateTemplateParsed : 1;
+ bool IsConstexpr : 1;
/// \brief End part of this FunctionDecl's source range.
///
@@ -1460,13 +1500,14 @@ private:
void setInstantiationOfMemberFunction(ASTContext &C, FunctionDecl *FD,
TemplateSpecializationKind TSK);
- void setParams(ASTContext &C, ParmVarDecl **NewParamInfo, unsigned NumParams);
+ void setParams(ASTContext &C, llvm::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, StorageClass SCAsWritten, bool isInlineSpecified,
+ bool isConstexprSpecified)
: DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo,
StartLoc),
DeclContext(DK),
@@ -1477,7 +1518,7 @@ protected:
HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false),
IsDefaulted(false), IsExplicitlyDefaulted(false),
HasImplicitReturnZero(false), IsLateTemplateParsed(false),
- EndRangeLoc(NameInfo.getEndLoc()),
+ IsConstexpr(isConstexprSpecified), EndRangeLoc(NameInfo.getEndLoc()),
TemplateOrSpecialization(),
DNLoc(NameInfo.getInfo()) {}
@@ -1500,11 +1541,13 @@ public:
StorageClass SC = SC_None,
StorageClass SCAsWritten = SC_None,
bool isInlineSpecified = false,
- bool hasWrittenPrototype = true) {
+ bool hasWrittenPrototype = true,
+ bool isConstexprSpecified = false) {
DeclarationNameInfo NameInfo(N, NLoc);
return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo,
SC, SCAsWritten,
- isInlineSpecified, hasWrittenPrototype);
+ isInlineSpecified, hasWrittenPrototype,
+ isConstexprSpecified);
}
static FunctionDecl *Create(ASTContext &C, DeclContext *DC,
@@ -1514,7 +1557,8 @@ public:
StorageClass SC = SC_None,
StorageClass SCAsWritten = SC_None,
bool isInlineSpecified = false,
- bool hasWrittenPrototype = true);
+ bool hasWrittenPrototype = true,
+ bool isConstexprSpecified = false);
DeclarationNameInfo getNameInfo() const {
return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc);
@@ -1600,10 +1644,6 @@ public:
bool isPure() const { return IsPure; }
void setPure(bool P = true);
- /// Whether this is a constexpr function or constexpr constructor.
- // FIXME: C++0x: Implement tracking of the constexpr specifier.
- bool isConstExpr() const { return false; }
-
/// Whether this templated function will be late parsed.
bool isLateTemplateParsed() const { return IsLateTemplateParsed; }
void setLateTemplateParsed(bool ILT = true) { IsLateTemplateParsed = ILT; }
@@ -1646,6 +1686,10 @@ public:
bool hasInheritedPrototype() const { return HasInheritedPrototype; }
void setHasInheritedPrototype(bool P = true) { HasInheritedPrototype = P; }
+ /// Whether this is a (C++0x) constexpr function or constexpr constructor.
+ bool isConstexpr() const { return IsConstexpr; }
+ void setConstexpr(bool IC) { IsConstexpr = IC; }
+
/// \brief Whether this function has been deleted.
///
/// A function that is "deleted" (via the C++0x "= delete" syntax)
@@ -1726,8 +1770,8 @@ public:
assert(i < getNumParams() && "Illegal param #");
return ParamInfo[i];
}
- void setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) {
- setParams(getASTContext(), NewParamInfo, NumParams);
+ void setParams(llvm::ArrayRef<ParmVarDecl *> NewParamInfo) {
+ setParams(getASTContext(), NewParamInfo);
}
/// getMinRequiredArguments - Returns the minimum number of arguments
@@ -1768,11 +1812,13 @@ public:
}
/// \brief Determine whether this function should be inlined, because it is
- /// either marked "inline" or is a member function of a C++ class that
- /// was defined in the class body.
+ /// either marked "inline" or "constexpr" or is a member function of a class
+ /// that was defined in the class body.
bool isInlined() const;
bool isInlineDefinitionExternallyVisible() const;
+
+ bool doesDeclarationForceExternallyVisibleDefinition() const;
/// isOverloadedOperator - Whether this function declaration
/// represents an C++ overloaded operator, e.g., "operator+".
@@ -1847,7 +1893,11 @@ public:
bool isFunctionTemplateSpecialization() const {
return getPrimaryTemplate() != 0;
}
-
+
+ /// \brief Retrieve the class scope template pattern that this function
+ /// template specialization is instantiated from.
+ FunctionDecl *getClassScopeSpecializationPattern() const;
+
/// \brief If this function is actually a function template specialization,
/// retrieve information about this function template specialization.
/// Otherwise, returns NULL.
@@ -1887,7 +1937,7 @@ public:
/// or if it had no explicit template argument list, returns NULL.
/// Note that it an explicit template argument list may be written empty,
/// e.g., template<> void foo<>(char* s);
- const TemplateArgumentListInfo*
+ const ASTTemplateArgumentListInfo*
getTemplateSpecializationArgsAsWritten() const;
/// \brief Specify that this function declaration is actually a function
@@ -1945,7 +1995,7 @@ public:
/// specialization or a member of a class template specialization.
///
/// \returns the first point of instantiation, if this function was
- /// instantiated from a template; otherwie, returns an invalid source
+ /// instantiated from a template; otherwise, returns an invalid source
/// location.
SourceLocation getPointOfInstantiation() const;
@@ -2033,6 +2083,7 @@ public:
Expr *getBitWidth() const {
return isBitField() ? InitializerOrBitWidth.getPointer() : 0;
}
+ unsigned getBitWidthValue(const ASTContext &Ctx) const;
void setBitWidth(Expr *BW) {
assert(!InitializerOrBitWidth.getPointer() &&
"bit width or initializer already set");
@@ -2308,9 +2359,10 @@ private:
/// TagDeclKind - The TagKind enum.
unsigned TagDeclKind : 2;
- /// IsDefinition - True if this is a definition ("struct foo {};"), false if
- /// it is a declaration ("struct foo;").
- bool IsDefinition : 1;
+ /// IsCompleteDefinition - True if this is a definition ("struct foo
+ /// {};"), false if it is a declaration ("struct foo;"). It is not
+ /// a definition until the definition has been fully processed.
+ bool IsCompleteDefinition : 1;
/// IsBeingDefined - True if this is currently being defined.
bool IsBeingDefined : 1;
@@ -2320,6 +2372,9 @@ private:
/// in the syntax of a declarator.
bool IsEmbeddedInDeclarator : 1;
+ /// /brief True if this tag is free standing, e.g. "struct foo;".
+ bool IsFreeStanding : 1;
+
protected:
// These are used by (and only defined for) EnumDecl.
unsigned NumPositiveBits : 8;
@@ -2367,9 +2422,10 @@ protected:
assert((DK != Enum || TK == TTK_Enum) &&
"EnumDecl not matched with TTK_Enum");
TagDeclKind = TK;
- IsDefinition = false;
+ IsCompleteDefinition = false;
IsBeingDefined = false;
IsEmbeddedInDeclarator = false;
+ IsFreeStanding = false;
setPreviousDeclaration(PrevDecl);
}
@@ -2408,14 +2464,15 @@ public:
}
/// isThisDeclarationADefinition() - Return true if this declaration
- /// defines the type. Provided for consistency.
+ /// is a completion definintion of the type. Provided for consistency.
bool isThisDeclarationADefinition() const {
- return isDefinition();
+ return isCompleteDefinition();
}
- /// isDefinition - Return true if this decl has its body specified.
- bool isDefinition() const {
- return IsDefinition;
+ /// isCompleteDefinition - Return true if this decl has its body
+ /// fully specified.
+ bool isCompleteDefinition() const {
+ return IsCompleteDefinition;
}
/// isBeingDefined - Return true if this decl is currently being defined.
@@ -2430,6 +2487,11 @@ public:
IsEmbeddedInDeclarator = isInDeclarator;
}
+ bool isFreeStanding() const { return IsFreeStanding; }
+ void setFreeStanding(bool isFreeStanding = true) {
+ IsFreeStanding = isFreeStanding;
+ }
+
/// \brief Whether this declaration declares a type that is
/// dependent, i.e., a type that somehow depends on template
/// parameters.
@@ -2444,14 +2506,15 @@ public:
/// getDefinition - Returns the TagDecl that actually defines this
/// struct/union/class/enum. When determining whether or not a
- /// struct/union/class/enum is completely defined, one should use this method
- /// as opposed to 'isDefinition'. 'isDefinition' indicates whether or not a
- /// specific TagDecl is defining declaration, not whether or not the
- /// struct/union/class/enum type is defined. This method returns NULL if
- /// there is no TagDecl that defines the struct/union/class/enum.
- TagDecl* getDefinition() const;
+ /// struct/union/class/enum has a definition, one should use this
+ /// method as opposed to 'isDefinition'. 'isDefinition' indicates
+ /// whether or not a specific TagDecl is defining declaration, not
+ /// whether or not the struct/union/class/enum type is defined.
+ /// This method returns NULL if there is no TagDecl that defines
+ /// the struct/union/class/enum.
+ TagDecl *getDefinition() const;
- void setDefinition(bool V) { IsDefinition = V; }
+ void setCompleteDefinition(bool V) { IsCompleteDefinition = V; }
const char *getKindName() const {
return TypeWithKeyword::getTagTypeKindName(getTagKind());
@@ -2691,7 +2754,7 @@ public:
/// \brief Returns true if this can be considered a complete type.
bool isComplete() const {
- return isDefinition() || isFixed();
+ return isCompleteDefinition() || isFixed();
}
/// \brief Returns the enumeration (declared within the template)
@@ -2794,14 +2857,15 @@ public:
/// \endcode
bool isInjectedClassName() const;
- /// getDefinition - Returns the RecordDecl that actually defines this
- /// struct/union/class. When determining whether or not a struct/union/class
- /// is completely defined, one should use this method as opposed to
- /// 'isDefinition'. 'isDefinition' indicates whether or not a specific
- /// RecordDecl is defining declaration, not whether or not the record
- /// type is defined. This method returns NULL if there is no RecordDecl
- /// that defines the struct/union/tag.
- RecordDecl* getDefinition() const {
+ /// getDefinition - Returns the RecordDecl that actually defines
+ /// this struct/union/class. When determining whether or not a
+ /// struct/union/class is completely defined, one should use this
+ /// method as opposed to 'isCompleteDefinition'.
+ /// 'isCompleteDefinition' indicates whether or not a specific
+ /// RecordDecl is a completed definition, not whether or not the
+ /// record type is defined. This method returns NULL if there is
+ /// no RecordDecl that defines the struct/union/tag.
+ RecordDecl *getDefinition() const {
return cast_or_null<RecordDecl>(TagDecl::getDefinition());
}
@@ -2967,7 +3031,7 @@ public:
assert(i < getNumParams() && "Illegal param #");
return ParamInfo[i];
}
- void setParams(ParmVarDecl **NewParamInfo, unsigned NumParams);
+ void setParams(llvm::ArrayRef<ParmVarDecl *> NewParamInfo);
/// hasCaptures - True if this block (or its nested blocks) captures
/// anything of local storage from its enclosing scopes.
@@ -3010,8 +3074,9 @@ public:
/// Insertion operator for diagnostics. This allows sending NamedDecl's
/// into a diagnostic with <<.
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
- NamedDecl* ND) {
- DB.AddTaggedVal(reinterpret_cast<intptr_t>(ND), Diagnostic::ak_nameddecl);
+ const NamedDecl* ND) {
+ DB.AddTaggedVal(reinterpret_cast<intptr_t>(ND),
+ DiagnosticsEngine::ak_nameddecl);
return DB;
}
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 8b2ef2a81acb..9f294117682c 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -243,19 +243,23 @@ private:
/// evaluated context or not, e.g. functions used in uninstantiated templates
/// are regarded as "referenced" but not "used".
unsigned Referenced : 1;
-
+
protected:
/// Access - Used by C++ decls for the access specifier.
// NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum
unsigned Access : 2;
friend class CXXClassMemberWrapper;
- /// PCHLevel - the "level" of AST file from which this declaration was built.
- unsigned PCHLevel : 2;
-
+ /// \brief Whether this declaration was loaded from an AST file.
+ unsigned FromASTFile : 1;
+
/// ChangedAfterLoad - if this declaration has changed since being loaded
unsigned ChangedAfterLoad : 1;
+ /// \brief Whether this declaration is private to the module in which it was
+ /// defined.
+ unsigned ModulePrivate : 1;
+
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
unsigned IdentifierNamespace : 12;
@@ -269,7 +273,9 @@ protected:
/// This field is only valid for NamedDecls subclasses.
mutable unsigned CachedLinkage : 2;
-
+ friend class ASTDeclWriter;
+ friend class ASTDeclReader;
+
private:
void CheckAccessDeclContext() const;
@@ -279,7 +285,8 @@ protected:
: NextDeclInContext(0), DeclCtx(DC),
Loc(L), DeclKind(DK), InvalidDecl(0),
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
- Access(AS_none), PCHLevel(0), ChangedAfterLoad(false),
+ Access(AS_none), FromASTFile(0), ChangedAfterLoad(false),
+ ModulePrivate(0),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
HasCachedLinkage(0)
{
@@ -289,7 +296,8 @@ protected:
Decl(Kind DK, EmptyShell Empty)
: NextDeclInContext(0), DeclKind(DK), InvalidDecl(0),
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
- Access(AS_none), PCHLevel(0), ChangedAfterLoad(false),
+ Access(AS_none), FromASTFile(0), ChangedAfterLoad(false),
+ ModulePrivate(0),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
HasCachedLinkage(0)
{
@@ -493,25 +501,10 @@ public:
/// declaration cannot be weak-imported because it has a definition.
bool canBeWeakImported(bool &IsDefinition) const;
- /// \brief Retrieve the level of precompiled header from which this
- /// declaration was generated.
- ///
- /// The PCH level of a declaration describes where the declaration originated
- /// from. A PCH level of 0 indicates that the declaration was parsed from
- /// source. A PCH level of 1 indicates that the declaration was loaded from
- /// a top-level AST file. A PCH level 2 indicates that the declaration was
- /// loaded from a PCH file the AST file depends on, and so on.
- unsigned getPCHLevel() const { return PCHLevel; }
-
- /// \brief The maximum PCH level that any declaration may have.
- static const unsigned MaxPCHLevel = 3;
-
- /// \brief Set the PCH level of this declaration.
- void setPCHLevel(unsigned Level) {
- assert(Level <= MaxPCHLevel && "PCH level exceeds the maximum");
- PCHLevel = Level;
- }
-
+ /// \brief Determine whether this declaration came from an AST file (such as
+ /// a precompiled header or module) rather than having been parsed.
+ bool isFromASTFile() const { return FromASTFile; }
+
/// \brief Query whether this declaration was changed in a significant way
/// since being loaded from an AST file.
///
@@ -574,7 +567,17 @@ public:
/// scoped decl is defined outside the current function or method. This is
/// roughly global variables and functions, but also handles enums (which
/// could be defined inside or outside a function etc).
- bool isDefinedOutsideFunctionOrMethod() const;
+ bool isDefinedOutsideFunctionOrMethod() const {
+ return getParentFunctionOrMethod() == 0;
+ }
+
+ /// \brief If this decl is defined inside a function/method/block it returns
+ /// the corresponding DeclContext, otherwise it returns null.
+ const DeclContext *getParentFunctionOrMethod() const;
+ DeclContext *getParentFunctionOrMethod() {
+ return const_cast<DeclContext*>(
+ const_cast<const Decl*>(this)->getParentFunctionOrMethod());
+ }
/// \brief Retrieves the "canonical" declaration of the given declaration.
virtual Decl *getCanonicalDecl() { return this; }
@@ -671,6 +674,9 @@ public:
/// \brief Whether this declaration is a parameter pack.
bool isParameterPack() const;
+ /// \brief returns true if this declaration is a template
+ bool isTemplateDecl() const;
+
/// \brief Whether this declaration is a function or function template.
bool isFunctionOrFunctionTemplate() const;
@@ -734,15 +740,16 @@ public:
static DeclContext *castToDeclContext(const Decl *);
static Decl *castFromDeclContext(const DeclContext *);
- void print(llvm::raw_ostream &Out, unsigned Indentation = 0) const;
- void print(llvm::raw_ostream &Out, const PrintingPolicy &Policy,
- unsigned Indentation = 0) const;
+ void print(raw_ostream &Out, unsigned Indentation = 0,
+ bool PrintInstantiation = false) const;
+ void print(raw_ostream &Out, const PrintingPolicy &Policy,
+ unsigned Indentation = 0, bool PrintInstantiation = false) const;
static void printGroup(Decl** Begin, unsigned NumDecls,
- llvm::raw_ostream &Out, const PrintingPolicy &Policy,
+ raw_ostream &Out, const PrintingPolicy &Policy,
unsigned Indentation = 0);
void dump() const;
void dumpXML() const;
- void dumpXML(llvm::raw_ostream &OS) const;
+ void dumpXML(raw_ostream &OS) const;
private:
const Attr *getAttrsImpl() const;
@@ -763,7 +770,7 @@ public:
SourceManager &sm, const char *Msg)
: TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {}
- virtual void print(llvm::raw_ostream &OS) const;
+ virtual void print(raw_ostream &OS) const;
};
class DeclContextLookupResult
@@ -839,7 +846,7 @@ protected:
///
/// \returns the first/last pair of declarations.
static std::pair<Decl *, Decl *>
- BuildDeclChain(const llvm::SmallVectorImpl<Decl*> &Decls);
+ BuildDeclChain(const SmallVectorImpl<Decl*> &Decls, bool FieldsAlreadyLoaded);
DeclContext(Decl::Kind K)
: DeclKind(K), ExternalLexicalStorage(false),
@@ -892,6 +899,18 @@ public:
return DeclKind == Decl::Block;
}
+ bool isObjCContainer() const {
+ switch (DeclKind) {
+ case Decl::ObjCCategory:
+ case Decl::ObjCCategoryImpl:
+ case Decl::ObjCImplementation:
+ case Decl::ObjCInterface:
+ case Decl::ObjCProtocol:
+ return true;
+ }
+ return false;
+ }
+
bool isFunctionOrMethod() const {
switch (DeclKind) {
case Decl::Block:
@@ -1243,6 +1262,15 @@ public:
lookup_result lookup(DeclarationName Name);
lookup_const_result lookup(DeclarationName Name) const;
+ /// \brief A simplistic name lookup mechanism that performs name lookup
+ /// into this declaration context without consulting the external source.
+ ///
+ /// This function should almost never be used, because it subverts the
+ /// usual relationship between a DeclContext and the external source.
+ /// See the ASTImporter for the (few, but important) use cases.
+ void localUncachedLookup(DeclarationName Name,
+ llvm::SmallVectorImpl<NamedDecl *> &Results);
+
/// @brief Makes a declaration visible within this context.
///
/// This routine makes the declaration D visible to name lookup
@@ -1263,14 +1291,6 @@ public:
/// the declaration chains.
void makeDeclVisibleInContext(NamedDecl *D, bool Recoverable = true);
- /// \brief Deserialize all the visible declarations from external storage.
- ///
- /// Name lookup deserializes visible declarations lazily, thus a DeclContext
- /// may not have a complete name lookup table. This function deserializes
- /// the rest of visible declarations from the external storage and completes
- /// the name lookup table.
- void MaterializeVisibleDeclsFromExternalStorage();
-
/// udir_iterator - Iterates through the using-directives stored
/// within this context.
typedef UsingDirectiveDecl * const * udir_iterator;
@@ -1317,6 +1337,12 @@ public:
ExternalVisibleStorage = ES;
}
+ /// \brief Determine whether the given declaration is stored in the list of
+ /// declarations lexically within this context.
+ bool isDeclInLexicalTraversal(const Decl *D) const {
+ return D && (D->NextDeclInContext || D == FirstDecl || D == LastDecl);
+ }
+
static bool classof(const Decl *D);
static bool classof(const DeclContext *D) { return true; }
#define DECL(NAME, BASE)
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index dd490f48c52c..7e60773e4416 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -363,10 +363,10 @@ class CXXRecordDecl : public RecordDecl {
/// default constructor.
bool HasTrivialDefaultConstructor : 1;
- /// HasConstExprNonCopyMoveConstructor - True when this class has at least
+ /// HasConstexprNonCopyMoveConstructor - True when this class has at least
/// one constexpr constructor which is neither the copy nor move
/// constructor.
- bool HasConstExprNonCopyMoveConstructor : 1;
+ bool HasConstexprNonCopyMoveConstructor : 1;
/// HasTrivialCopyConstructor - True when this class has a trivial copy
/// constructor.
@@ -468,6 +468,14 @@ class CXXRecordDecl : public RecordDecl {
/// \brief Whether we have already declared a destructor within the class.
bool DeclaredDestructor : 1;
+ /// \brief Whether an implicit move constructor was attempted to be declared
+ /// but would have been deleted.
+ bool FailedImplicitMoveConstructor : 1;
+
+ /// \brief Whether an implicit move assignment operator was attempted to be
+ /// declared but would have been deleted.
+ bool FailedImplicitMoveAssignment : 1;
+
/// NumBases - The number of base class specifiers in Bases.
unsigned NumBases;
@@ -780,6 +788,33 @@ public:
return data().DeclaredMoveConstructor;
}
+ /// \brief Determine whether implicit move constructor generation for this
+ /// class has failed before.
+ bool hasFailedImplicitMoveConstructor() const {
+ return data().FailedImplicitMoveConstructor;
+ }
+
+ /// \brief Set whether implicit move constructor generation for this class
+ /// has failed before.
+ void setFailedImplicitMoveConstructor(bool Failed = true) {
+ data().FailedImplicitMoveConstructor = Failed;
+ }
+
+ /// \brief 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() &&
+ !hasUserDeclaredCopyConstructor() &&
+ !hasUserDeclaredCopyAssignment() &&
+ !hasUserDeclaredMoveAssignment() &&
+ !hasUserDeclaredDestructor();
+ }
+
/// hasUserDeclaredCopyAssignment - Whether this class has a
/// user-declared copy assignment operator. When false, a copy
/// assigment operator will be implicitly declared.
@@ -807,6 +842,33 @@ public:
return data().DeclaredMoveAssignment;
}
+ /// \brief Determine whether implicit move assignment generation for this
+ /// class has failed before.
+ bool hasFailedImplicitMoveAssignment() const {
+ return data().FailedImplicitMoveAssignment;
+ }
+
+ /// \brief Set whether implicit move assignment generation for this class
+ /// has failed before.
+ void setFailedImplicitMoveAssignment(bool Failed = true) {
+ data().FailedImplicitMoveAssignment = Failed;
+ }
+
+ /// \brief 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() &&
+ !hasUserDeclaredCopyConstructor() &&
+ !hasUserDeclaredCopyAssignment() &&
+ !hasUserDeclaredMoveConstructor() &&
+ !hasUserDeclaredDestructor();
+ }
+
/// hasUserDeclaredDestructor - Whether this class has a
/// user-declared destructor. When false, a destructor will be
/// implicitly declared.
@@ -889,10 +951,10 @@ public:
data().DeclaredDefaultConstructor);
}
- // hasConstExprNonCopyMoveConstructor - Whether this class has at least one
- // constexpr constructor other than the copy or move constructors
- bool hasConstExprNonCopyMoveConstructor() const {
- return data().HasConstExprNonCopyMoveConstructor;
+ // hasConstexprNonCopyMoveConstructor - Whether this class has at least one
+ // constexpr constructor other than the copy or move constructors.
+ bool hasConstexprNonCopyMoveConstructor() const {
+ return data().HasConstexprNonCopyMoveConstructor;
}
// hasTrivialCopyConstructor - Whether this class has a trivial copy
@@ -942,6 +1004,25 @@ public:
return isTriviallyCopyable() && hasTrivialDefaultConstructor();
}
+ // isLiteral - Whether this class is a literal type.
+ //
+ // C++0x [basic.types]p10
+ // A class type that has all the following properties:
+ // -- a trivial destructor
+ // -- every constructor call and full-expression in the
+ // brace-or-equal-intializers for non-static data members (if any) is
+ // a constant expression.
+ // -- it is an aggregate type or has at least one constexpr constructor or
+ // constructor template that is not a copy or move constructor, and
+ // -- all non-static data members and base classes of literal types
+ //
+ // We resolve DR1361 by ignoring the second bullet.
+ bool isLiteral() const {
+ return hasTrivialDestructor() &&
+ (isAggregate() || hasConstexprNonCopyMoveConstructor()) &&
+ !hasNonLiteralTypeFieldsOrBases();
+ }
+
/// \brief If this record is an instantiation of a member class,
/// retrieves the member class from which it was instantiated.
///
@@ -1237,10 +1318,10 @@ protected:
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
bool isStatic, StorageClass SCAsWritten, bool isInline,
- SourceLocation EndLocation)
+ bool isConstexpr, SourceLocation EndLocation)
: FunctionDecl(DK, RD, StartLoc, NameInfo, T, TInfo,
(isStatic ? SC_Static : SC_None),
- SCAsWritten, isInline) {
+ SCAsWritten, isInline, isConstexpr) {
if (EndLocation.isValid())
setRangeEnd(EndLocation);
}
@@ -1253,6 +1334,7 @@ public:
bool isStatic,
StorageClass SCAsWritten,
bool isInline,
+ bool isConstexpr,
SourceLocation EndLocation);
bool isStatic() const { return getStorageClass() == SC_Static; }
@@ -1333,6 +1415,7 @@ public:
/// void g() &&;
/// void h();
/// };
+ /// \endcode
RefQualifierKind getRefQualifier() const {
return getType()->getAs<FunctionProtoType>()->getRefQualifier();
}
@@ -1630,9 +1713,9 @@ class CXXConstructorDecl : public CXXMethodDecl {
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
bool isExplicitSpecified, bool isInline,
- bool isImplicitlyDeclared)
+ bool isImplicitlyDeclared, bool isConstexpr)
: CXXMethodDecl(CXXConstructor, RD, StartLoc, NameInfo, T, TInfo, false,
- SC_None, isInline, SourceLocation()),
+ SC_None, isInline, isConstexpr, SourceLocation()),
IsExplicitSpecified(isExplicitSpecified), ImplicitlyDefined(false),
CtorInitializers(0), NumCtorInitializers(0) {
setImplicit(isImplicitlyDeclared);
@@ -1645,7 +1728,8 @@ public:
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
bool isExplicit,
- bool isInline, bool isImplicitlyDeclared);
+ bool isInline, bool isImplicitlyDeclared,
+ bool isConstexpr);
/// isExplicitSpecified - Whether this constructor declaration has the
/// 'explicit' keyword specified.
@@ -1853,7 +1937,7 @@ class CXXDestructorDecl : public CXXMethodDecl {
QualType T, TypeSourceInfo *TInfo,
bool isInline, bool isImplicitlyDeclared)
: CXXMethodDecl(CXXDestructor, RD, StartLoc, NameInfo, T, TInfo, false,
- SC_None, isInline, SourceLocation()),
+ SC_None, isInline, /*isConstexpr=*/false, SourceLocation()),
ImplicitlyDefined(false), OperatorDelete(0) {
setImplicit(isImplicitlyDeclared);
}
@@ -1916,9 +2000,9 @@ class CXXConversionDecl : public CXXMethodDecl {
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
bool isInline, bool isExplicitSpecified,
- SourceLocation EndLocation)
+ bool isConstexpr, SourceLocation EndLocation)
: CXXMethodDecl(CXXConversion, RD, StartLoc, NameInfo, T, TInfo, false,
- SC_None, isInline, EndLocation),
+ SC_None, isInline, isConstexpr, EndLocation),
IsExplicitSpecified(isExplicitSpecified) { }
public:
@@ -1928,6 +2012,7 @@ public:
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
bool isInline, bool isExplicit,
+ bool isConstexpr,
SourceLocation EndLocation);
/// IsExplicitSpecified - Whether this conversion function declaration is
diff --git a/include/clang/AST/DeclContextInternals.h b/include/clang/AST/DeclContextInternals.h
index 97da6ca9a1ef..c5f2aa0b848b 100644
--- a/include/clang/AST/DeclContextInternals.h
+++ b/include/clang/AST/DeclContextInternals.h
@@ -31,7 +31,7 @@ class DependentDiagnostic;
struct StoredDeclsList {
/// DeclsTy - When in vector form, this is what the Data pointer points to.
- typedef llvm::SmallVector<NamedDecl *, 4> DeclsTy;
+ typedef SmallVector<NamedDecl *, 4> DeclsTy;
/// \brief The stored data, which will be either a pointer to a NamedDecl,
/// or a pointer to a vector.
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index d318fc27a8ba..425c89d290a6 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_AST_DECLOBJC_H
#include "clang/AST/Decl.h"
+#include "clang/AST/SelectorLocationsKind.h"
#include "llvm/ADT/STLExtras.h"
namespace clang {
@@ -127,6 +128,12 @@ private:
// Method has a definition.
unsigned IsDefined : 1;
+ /// \brief Method redeclaration in the same interface.
+ unsigned IsRedeclaration : 1;
+
+ /// \brief Is redeclared in the same interface.
+ mutable unsigned HasRedeclaration : 1;
+
// NOTE: VC++ treats enums as signed, avoid using ImplementationControl enum
/// @required/@optional
unsigned DeclImplementation : 2;
@@ -138,8 +145,9 @@ private:
/// \brief Indicates whether this method has a related result type.
unsigned RelatedResultType : 1;
- // Number of args separated by ':' in a method declaration.
- unsigned NumSelectorArgs;
+ /// \brief Whether the locations of the selector identifiers are in a
+ /// "standard" position, a enum SelectorLocationsKind.
+ unsigned SelLocsKind : 2;
// Result type of this method.
QualType MethodDeclType;
@@ -147,9 +155,10 @@ private:
// Type source information for the result type.
TypeSourceInfo *ResultTInfo;
- /// ParamInfo - List of pointers to VarDecls for the formal parameters of this
- /// Method.
- ObjCList<ParmVarDecl> ParamInfo;
+ /// \brief Array of ParmVarDecls for the formal parameters of this method
+ /// and optionally followed by selector locations.
+ void *ParamsAndSelLocs;
+ unsigned NumParams;
/// List of attributes for this method declaration.
SourceLocation EndLoc; // the location of the ';' or '}'.
@@ -165,6 +174,43 @@ private:
/// constructed by createImplicitParams.
ImplicitParamDecl *CmdDecl;
+ SelectorLocationsKind getSelLocsKind() const {
+ return (SelectorLocationsKind)SelLocsKind;
+ }
+ bool hasStandardSelLocs() const {
+ return getSelLocsKind() != SelLoc_NonStandard;
+ }
+
+ /// \brief Get a pointer to the stored selector identifiers locations array.
+ /// No locations will be stored if HasStandardSelLocs is true.
+ SourceLocation *getStoredSelLocs() {
+ return reinterpret_cast<SourceLocation*>(getParams() + NumParams);
+ }
+ const SourceLocation *getStoredSelLocs() const {
+ return reinterpret_cast<const SourceLocation*>(getParams() + NumParams);
+ }
+
+ /// \brief Get a pointer to the stored selector identifiers locations array.
+ /// No locations will be stored if HasStandardSelLocs is true.
+ ParmVarDecl **getParams() {
+ return reinterpret_cast<ParmVarDecl **>(ParamsAndSelLocs);
+ }
+ const ParmVarDecl *const *getParams() const {
+ return reinterpret_cast<const ParmVarDecl *const *>(ParamsAndSelLocs);
+ }
+
+ /// \brief Get the number of stored selector identifiers locations.
+ /// No locations will be stored if HasStandardSelLocs is true.
+ unsigned getNumStoredSelLocs() const {
+ if (hasStandardSelLocs())
+ return 0;
+ return getNumSelectorLocs();
+ }
+
+ void setParamsAndSelLocs(ASTContext &C,
+ ArrayRef<ParmVarDecl*> Params,
+ ArrayRef<SourceLocation> SelLocs);
+
ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc,
Selector SelInfo, QualType T,
TypeSourceInfo *ResultTInfo,
@@ -172,19 +218,23 @@ private:
bool isInstance = true,
bool isVariadic = false,
bool isSynthesized = false,
+ bool isImplicitlyDeclared = false,
bool isDefined = false,
ImplementationControl impControl = None,
- bool HasRelatedResultType = false,
- unsigned numSelectorArgs = 0)
+ bool HasRelatedResultType = false)
: NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo),
DeclContext(ObjCMethod), Family(InvalidObjCMethodFamily),
IsInstance(isInstance), IsVariadic(isVariadic),
IsSynthesized(isSynthesized),
- IsDefined(isDefined),
+ IsDefined(isDefined), IsRedeclaration(0), HasRedeclaration(0),
DeclImplementation(impControl), objcDeclQualifier(OBJC_TQ_None),
- RelatedResultType(HasRelatedResultType), NumSelectorArgs(numSelectorArgs),
+ RelatedResultType(HasRelatedResultType),
+ SelLocsKind(SelLoc_StandardNoSpace),
MethodDeclType(T), ResultTInfo(ResultTInfo),
- EndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) {}
+ ParamsAndSelLocs(0), NumParams(0),
+ EndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) {
+ setImplicit(isImplicitlyDeclared);
+ }
/// \brief A definition will return its interface declaration.
/// An interface declaration will return its definition.
@@ -194,17 +244,18 @@ private:
public:
static ObjCMethodDecl *Create(ASTContext &C,
SourceLocation beginLoc,
- SourceLocation endLoc, Selector SelInfo,
+ SourceLocation endLoc,
+ Selector SelInfo,
QualType T,
TypeSourceInfo *ResultTInfo,
DeclContext *contextDecl,
bool isInstance = true,
bool isVariadic = false,
bool isSynthesized = false,
+ bool isImplicitlyDeclared = false,
bool isDefined = false,
ImplementationControl impControl = None,
- bool HasRelatedResultType = false,
- unsigned numSelectorArgs = 0);
+ bool HasRelatedResultType = false);
virtual ObjCMethodDecl *getCanonicalDecl();
const ObjCMethodDecl *getCanonicalDecl() const {
@@ -222,11 +273,10 @@ public:
/// \brief Note whether this method has a related result type.
void SetRelatedResultType(bool RRT = true) { RelatedResultType = RRT; }
-
- unsigned getNumSelectorArgs() const { return NumSelectorArgs; }
- void setNumSelectorArgs(unsigned numSelectorArgs) {
- NumSelectorArgs = numSelectorArgs;
- }
+
+ /// \brief True if this is a method redeclaration in the same interface.
+ bool isRedeclaration() const { return IsRedeclaration; }
+ void setAsRedeclaration(const ObjCMethodDecl *PrevMethod);
// Location information, modeled after the Stmt API.
SourceLocation getLocStart() const { return getLocation(); }
@@ -236,6 +286,29 @@ public:
return SourceRange(getLocation(), EndLoc);
}
+ SourceLocation getSelectorStartLoc() const { return getSelectorLoc(0); }
+ SourceLocation getSelectorLoc(unsigned Index) const {
+ assert(Index < getNumSelectorLocs() && "Index out of range!");
+ if (hasStandardSelLocs())
+ return getStandardSelectorLoc(Index, getSelector(),
+ getSelLocsKind() == SelLoc_StandardWithSpace,
+ llvm::makeArrayRef(const_cast<ParmVarDecl**>(getParams()),
+ NumParams),
+ EndLoc);
+ return getStoredSelLocs()[Index];
+ }
+
+ void getSelectorLocs(SmallVectorImpl<SourceLocation> &SelLocs) const;
+
+ unsigned getNumSelectorLocs() const {
+ if (isImplicit())
+ return 0;
+ Selector Sel = getSelector();
+ if (Sel.isUnarySelector())
+ return 1;
+ return Sel.getNumArgs();
+ }
+
ObjCInterfaceDecl *getClassInterface();
const ObjCInterfaceDecl *getClassInterface() const {
return const_cast<ObjCMethodDecl*>(this)->getClassInterface();
@@ -256,25 +329,31 @@ public:
void setResultTypeSourceInfo(TypeSourceInfo *TInfo) { ResultTInfo = TInfo; }
// Iterator access to formal parameters.
- unsigned param_size() const { return ParamInfo.size(); }
- typedef ObjCList<ParmVarDecl>::iterator param_iterator;
- param_iterator param_begin() const { return ParamInfo.begin(); }
- param_iterator param_end() const { return ParamInfo.end(); }
+ unsigned param_size() const { return NumParams; }
+ typedef const ParmVarDecl *const *param_const_iterator;
+ typedef ParmVarDecl *const *param_iterator;
+ param_const_iterator param_begin() const { return getParams(); }
+ param_const_iterator param_end() const { return getParams() + NumParams; }
+ param_iterator param_begin() { return getParams(); }
+ param_iterator param_end() { return getParams() + NumParams; }
// This method returns and of the parameters which are part of the selector
// name mangling requirements.
- param_iterator sel_param_end() const {
- return ParamInfo.begin() + NumSelectorArgs;
+ param_const_iterator sel_param_end() const {
+ return param_begin() + getSelector().getNumArgs();
}
- void setMethodParams(ASTContext &C, ParmVarDecl *const *List, unsigned Num,
- unsigned numSelectorArgs) {
- ParamInfo.set(List, Num, C);
- NumSelectorArgs = numSelectorArgs;
- }
+ /// \brief Sets the method's parameters and selector source locations.
+ /// If the method is implicit (not coming from source) \arg SelLocs is
+ /// ignored.
+ void setMethodParams(ASTContext &C,
+ ArrayRef<ParmVarDecl*> Params,
+ ArrayRef<SourceLocation> SelLocs =
+ ArrayRef<SourceLocation>());
// Iterator access to parameter types.
typedef std::const_mem_fun_t<QualType, ParmVarDecl> deref_fun;
- typedef llvm::mapped_iterator<param_iterator, deref_fun> arg_type_iterator;
+ typedef llvm::mapped_iterator<param_const_iterator, deref_fun>
+ arg_type_iterator;
arg_type_iterator arg_type_begin() const {
return llvm::map_iterator(param_begin(), deref_fun(&ParmVarDecl::getType));
@@ -337,6 +416,9 @@ public:
static ObjCMethodDecl *castFromDeclContext(const DeclContext *DC) {
return static_cast<ObjCMethodDecl *>(const_cast<DeclContext*>(DC));
}
+
+ friend class ASTDeclReader;
+ friend class ASTDeclWriter;
};
/// ObjCContainerDecl - Represents a container for method declarations.
@@ -344,14 +426,17 @@ public:
/// ObjCProtocolDecl, and ObjCImplDecl.
///
class ObjCContainerDecl : public NamedDecl, public DeclContext {
+ SourceLocation AtStart;
+
// These two locations in the range mark the end of the method container.
// The first points to the '@' token, and the second to the 'end' token.
SourceRange AtEnd;
public:
- ObjCContainerDecl(Kind DK, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id)
- : NamedDecl(DK, DC, L, Id), DeclContext(DK) {}
+ ObjCContainerDecl(Kind DK, DeclContext *DC,
+ IdentifierInfo *Id, SourceLocation nameLoc,
+ SourceLocation atStartLoc)
+ : NamedDecl(DK, DC, nameLoc, Id), DeclContext(DK), AtStart(atStartLoc) {}
// Iterator access to properties.
typedef specific_decl_iterator<ObjCPropertyDecl> prop_iterator;
@@ -403,6 +488,9 @@ public:
ObjCPropertyDecl *FindPropertyDeclaration(IdentifierInfo *PropertyId) const;
+ SourceLocation getAtStartLoc() const { return AtStart; }
+ void setAtStartLoc(SourceLocation Loc) { AtStart = Loc; }
+
// Marks the end of the container.
SourceRange getAtEndRange() const {
return AtEnd;
@@ -412,7 +500,7 @@ public:
}
virtual SourceRange getSourceRange() const {
- return SourceRange(getLocation(), getAtEndRange().getEnd());
+ return SourceRange(AtStart, getAtEndRange().getEnd());
}
// Implement isa/cast/dyncast/etc.
@@ -485,7 +573,6 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
/// completed by the external AST source when required.
mutable bool ExternallyCompleted : 1;
- SourceLocation ClassLoc; // location of the class identifier.
SourceLocation SuperClassLoc; // location of the super class identifier.
SourceLocation EndLoc; // marks the '>', '}', or identifier.
@@ -576,7 +663,7 @@ public:
typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator;
- ivar_iterator ivar_begin() const { return ivar_iterator(decls_begin()); }
+ ivar_iterator ivar_begin() const { return ivar_iterator(decls_begin()); }
ivar_iterator ivar_end() const { return ivar_iterator(decls_end()); }
unsigned ivar_size() const {
@@ -585,7 +672,12 @@ public:
bool ivar_empty() const { return ivar_begin() == ivar_end(); }
- ObjCIvarDecl *all_declared_ivar_begin();
+ ObjCIvarDecl *all_declared_ivar_begin();
+ const ObjCIvarDecl *all_declared_ivar_begin() const {
+ // Even though this modifies IvarList, it's conceptually const:
+ // the ivar chain is essentially a cached property of ObjCInterfaceDecl.
+ return const_cast<ObjCInterfaceDecl *>(this)->all_declared_ivar_begin();
+ }
void setIvarList(ObjCIvarDecl *ivar) { IvarList = ivar; }
/// setProtocolList - Set the list of protocols that this interface
@@ -675,12 +767,10 @@ public:
ObjCMethodDecl *lookupPrivateMethod(const Selector &Sel, bool Instance=true);
// Location information, modeled after the Stmt API.
- SourceLocation getLocStart() const { return getLocation(); } // '@'interface
+ SourceLocation getLocStart() const { return getAtStartLoc(); } // '@'interface
SourceLocation getLocEnd() const { return EndLoc; }
void setLocEnd(SourceLocation LE) { EndLoc = LE; }
- void setClassLoc(SourceLocation Loc) { ClassLoc = Loc; }
- SourceLocation getClassLoc() const { return ClassLoc; }
void setSuperClassLoc(SourceLocation Loc) { SuperClassLoc = Loc; }
SourceLocation getSuperClassLoc() const { return SuperClassLoc; }
@@ -754,6 +844,7 @@ public:
const ObjCInterfaceDecl *getContainingInterface() const;
ObjCIvarDecl *getNextIvar() { return NextIvar; }
+ const ObjCIvarDecl *getNextIvar() const { return NextIvar; }
void setNextIvar(ObjCIvarDecl *ivar) { NextIvar = ivar; }
void setAccessControl(AccessControl ac) { DeclAccess = ac; }
@@ -837,14 +928,17 @@ class ObjCProtocolDecl : public ObjCContainerDecl {
SourceLocation EndLoc; // marks the '>' or identifier.
- ObjCProtocolDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id)
- : ObjCContainerDecl(ObjCProtocol, DC, L, Id),
+ ObjCProtocolDecl(DeclContext *DC, IdentifierInfo *Id,
+ SourceLocation nameLoc, SourceLocation atStartLoc)
+ : ObjCContainerDecl(ObjCProtocol, DC, Id, nameLoc, atStartLoc),
isForwardProtoDecl(true) {
}
public:
static ObjCProtocolDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id);
+ IdentifierInfo *Id,
+ SourceLocation nameLoc,
+ SourceLocation atStartLoc);
const ObjCProtocolList &getReferencedProtocols() const {
return ReferencedProtocols;
@@ -884,7 +978,7 @@ public:
void setForwardDecl(bool val) { isForwardProtoDecl = val; }
// Location information, modeled after the Stmt API.
- SourceLocation getLocStart() const { return getLocation(); } // '@'protocol
+ SourceLocation getLocStart() const { return getAtStartLoc(); } // '@'protocol
SourceLocation getLocEnd() const { return EndLoc; }
void setLocEnd(SourceLocation LE) { EndLoc = LE; }
@@ -908,29 +1002,23 @@ public:
ObjCInterfaceDecl *getInterface() const { return ID; }
};
private:
- ObjCClassRef *ForwardDecls;
- unsigned NumDecls;
+ ObjCClassRef *ForwardDecl;
ObjCClassDecl(DeclContext *DC, SourceLocation L,
- ObjCInterfaceDecl *const *Elts, const SourceLocation *Locs,
- unsigned nElts, ASTContext &C);
+ ObjCInterfaceDecl *const Elt, const SourceLocation Loc,
+ ASTContext &C);
public:
static ObjCClassDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
- ObjCInterfaceDecl *const *Elts = 0,
- const SourceLocation *Locs = 0,
- unsigned nElts = 0);
+ ObjCInterfaceDecl *const Elt = 0,
+ const SourceLocation Locs = SourceLocation());
+
+ ObjCInterfaceDecl *getForwardInterfaceDecl() { return ForwardDecl->getInterface(); }
+ ObjCClassRef *getForwardDecl() { return ForwardDecl; }
+ void setClass(ASTContext &C, ObjCInterfaceDecl*const Cls,
+ const SourceLocation Locs);
virtual SourceRange getSourceRange() const;
- typedef const ObjCClassRef* iterator;
- iterator begin() const { return ForwardDecls; }
- iterator end() const { return ForwardDecls + NumDecls; }
- unsigned size() const { return NumDecls; }
-
- /// setClassList - Set the list of forward classes.
- void setClassList(ASTContext &C, ObjCInterfaceDecl*const*List,
- const SourceLocation *Locs, unsigned Num);
-
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCClassDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCClass; }
@@ -1013,19 +1101,16 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
/// true of class extension has at least one bitfield ivar.
bool HasSynthBitfield : 1;
-
- /// \brief The location of the '@' in '@interface'
- SourceLocation AtLoc;
/// \brief The location of the category name in this declaration.
SourceLocation CategoryNameLoc;
ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc,
- IdentifierInfo *Id)
- : ObjCContainerDecl(ObjCCategory, DC, ClassNameLoc, Id),
- ClassInterface(0), NextClassCategory(0), HasSynthBitfield(false),
- AtLoc(AtLoc), CategoryNameLoc(CategoryNameLoc) {
+ IdentifierInfo *Id, ObjCInterfaceDecl *IDecl)
+ : ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc),
+ ClassInterface(IDecl), NextClassCategory(0), HasSynthBitfield(false),
+ CategoryNameLoc(CategoryNameLoc) {
}
public:
@@ -1033,11 +1118,12 @@ public:
SourceLocation AtLoc,
SourceLocation ClassNameLoc,
SourceLocation CategoryNameLoc,
- IdentifierInfo *Id);
+ IdentifierInfo *Id,
+ ObjCInterfaceDecl *IDecl);
+ static ObjCCategoryDecl *Create(ASTContext &C, EmptyShell Empty);
ObjCInterfaceDecl *getClassInterface() { return ClassInterface; }
const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; }
- void setClassInterface(ObjCInterfaceDecl *IDecl) { ClassInterface = IDecl; }
ObjCCategoryImplDecl *getImplementation() const;
void setImplementation(ObjCCategoryImplDecl *ImplD);
@@ -1066,14 +1152,6 @@ public:
}
ObjCCategoryDecl *getNextClassCategory() const { return NextClassCategory; }
- void setNextClassCategory(ObjCCategoryDecl *Cat) {
- NextClassCategory = Cat;
- }
- void insertNextClassCategory() {
- NextClassCategory = ClassInterface->getCategoryList();
- ClassInterface->setCategoryList(this);
- ClassInterface->setChangedSinceDeserialization(true);
- }
bool IsClassExtension() const { return getIdentifier() == 0; }
const ObjCCategoryDecl *getNextClassExtension() const;
@@ -1094,20 +1172,16 @@ public:
bool ivar_empty() const {
return ivar_begin() == ivar_end();
}
-
- SourceLocation getAtLoc() const { return AtLoc; }
- void setAtLoc(SourceLocation At) { AtLoc = At; }
SourceLocation getCategoryNameLoc() const { return CategoryNameLoc; }
void setCategoryNameLoc(SourceLocation Loc) { CategoryNameLoc = Loc; }
- virtual SourceRange getSourceRange() const {
- return SourceRange(AtLoc, getAtEndRange().getEnd());
- }
-
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCCategoryDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCCategory; }
+
+ friend class ASTDeclReader;
+ friend class ASTDeclWriter;
};
class ObjCImplDecl : public ObjCContainerDecl {
@@ -1115,10 +1189,12 @@ class ObjCImplDecl : public ObjCContainerDecl {
ObjCInterfaceDecl *ClassInterface;
protected:
- ObjCImplDecl(Kind DK, DeclContext *DC, SourceLocation L,
- ObjCInterfaceDecl *classInterface)
- : ObjCContainerDecl(DK, DC, L,
- classInterface? classInterface->getIdentifier() : 0),
+ ObjCImplDecl(Kind DK, DeclContext *DC,
+ ObjCInterfaceDecl *classInterface,
+ SourceLocation nameLoc, SourceLocation atStartLoc)
+ : ObjCContainerDecl(DK, DC,
+ classInterface? classInterface->getIdentifier() : 0,
+ nameLoc, atStartLoc),
ClassInterface(classInterface) {}
public:
@@ -1175,13 +1251,17 @@ class ObjCCategoryImplDecl : public ObjCImplDecl {
// Category name
IdentifierInfo *Id;
- ObjCCategoryImplDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
- ObjCInterfaceDecl *classInterface)
- : ObjCImplDecl(ObjCCategoryImpl, DC, L, classInterface), Id(Id) {}
+ ObjCCategoryImplDecl(DeclContext *DC, IdentifierInfo *Id,
+ ObjCInterfaceDecl *classInterface,
+ SourceLocation nameLoc, SourceLocation atStartLoc)
+ : ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, nameLoc, atStartLoc),
+ Id(Id) {}
public:
static ObjCCategoryImplDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- ObjCInterfaceDecl *classInterface);
+ IdentifierInfo *Id,
+ ObjCInterfaceDecl *classInterface,
+ SourceLocation nameLoc,
+ SourceLocation atStartLoc);
/// getIdentifier - Get the identifier that names the category
/// interface associated with this implementation.
@@ -1203,7 +1283,7 @@ public:
//
// FIXME: This is a bad API, we are overriding the NamedDecl::getName, to mean
// something different.
- llvm::StringRef getName() const {
+ StringRef getName() const {
return Id ? Id->getNameStart() : "";
}
@@ -1228,7 +1308,7 @@ public:
static bool classofKind(Kind K) { return K == ObjCCategoryImpl;}
};
-llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+raw_ostream &operator<<(raw_ostream &OS,
const ObjCCategoryImplDecl *CID);
/// ObjCImplementationDecl - Represents a class definition - this is where
@@ -1259,17 +1339,19 @@ class ObjCImplementationDecl : public ObjCImplDecl {
/// true of class extension has at least one bitfield ivar.
bool HasSynthBitfield : 1;
- ObjCImplementationDecl(DeclContext *DC, SourceLocation L,
+ ObjCImplementationDecl(DeclContext *DC,
ObjCInterfaceDecl *classInterface,
- ObjCInterfaceDecl *superDecl)
- : ObjCImplDecl(ObjCImplementation, DC, L, classInterface),
+ ObjCInterfaceDecl *superDecl,
+ SourceLocation nameLoc, SourceLocation atStartLoc)
+ : ObjCImplDecl(ObjCImplementation, DC, classInterface, nameLoc, atStartLoc),
SuperClass(superDecl), IvarInitializers(0), NumIvarInitializers(0),
HasCXXStructors(false), HasSynthBitfield(false) {}
public:
static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
ObjCInterfaceDecl *classInterface,
- ObjCInterfaceDecl *superDecl);
+ ObjCInterfaceDecl *superDecl,
+ SourceLocation nameLoc,
+ SourceLocation atStartLoc);
/// init_iterator - Iterates through the ivar initializer list.
typedef CXXCtorInitializer **init_iterator;
@@ -1320,7 +1402,7 @@ public:
//
// FIXME: This is a bad API, we are overriding the NamedDecl::getName, to mean
// something different.
- llvm::StringRef getName() const {
+ StringRef getName() const {
assert(getIdentifier() && "Name is not a simple identifier");
return getIdentifier()->getName();
}
@@ -1368,7 +1450,7 @@ public:
friend class ASTDeclWriter;
};
-llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+raw_ostream &operator<<(raw_ostream &OS,
const ObjCImplementationDecl *ID);
/// ObjCCompatibleAliasDecl - Represents alias of a class. This alias is
@@ -1423,7 +1505,7 @@ public:
NumPropertyAttrsBits = 12
};
- enum SetterKind { Assign, Retain, Copy };
+ enum SetterKind { Assign, Retain, Copy, Weak };
enum PropertyControl { None, Required, Optional };
private:
SourceLocation AtLoc; // location of @property
@@ -1495,14 +1577,29 @@ public:
return (PropertyAttributes & OBJC_PR_readonly);
}
+ /// isAtomic - Return true if the property is atomic.
+ bool isAtomic() const {
+ return (PropertyAttributes & OBJC_PR_atomic);
+ }
+
+ /// isRetaining - Return true if the property retains its value.
+ bool isRetaining() const {
+ return (PropertyAttributes &
+ (OBJC_PR_retain | OBJC_PR_strong | OBJC_PR_copy));
+ }
+
/// getSetterKind - Return the method used for doing assignment in
/// the property setter. This is only valid if the property has been
/// defined to have a setter.
SetterKind getSetterKind() const {
- if (PropertyAttributes & (OBJC_PR_retain|OBJC_PR_strong))
+ if (PropertyAttributes & OBJC_PR_strong)
+ return getType()->isBlockPointerType() ? Copy : Retain;
+ if (PropertyAttributes & OBJC_PR_retain)
return Retain;
if (PropertyAttributes & OBJC_PR_copy)
return Copy;
+ if (PropertyAttributes & OBJC_PR_weak)
+ return Weak;
return Assign;
}
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index d2b1d3990c66..138e47d1a96d 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -264,7 +264,7 @@ class FunctionTemplateSpecializationInfo : public llvm::FoldingSetNode {
FunctionTemplateDecl *Template,
TemplateSpecializationKind TSK,
const TemplateArgumentList *TemplateArgs,
- const TemplateArgumentListInfo *TemplateArgsAsWritten,
+ const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
SourceLocation POI)
: Function(FD),
Template(Template, TSK - 1),
@@ -278,12 +278,7 @@ public:
TemplateSpecializationKind TSK,
const TemplateArgumentList *TemplateArgs,
const TemplateArgumentListInfo *TemplateArgsAsWritten,
- SourceLocation POI) {
- return new (C) FunctionTemplateSpecializationInfo(FD, Template, TSK,
- TemplateArgs,
- TemplateArgsAsWritten,
- POI);
- }
+ SourceLocation POI);
/// \brief The function template specialization that this structure
/// describes.
@@ -300,7 +295,7 @@ public:
const TemplateArgumentList *TemplateArguments;
/// \brief The template arguments as written in the sources, if provided.
- const TemplateArgumentListInfo *TemplateArgumentsAsWritten;
+ const ASTTemplateArgumentListInfo *TemplateArgumentsAsWritten;
/// \brief The point at which this function template specialization was
/// first instantiated.
@@ -913,7 +908,7 @@ protected:
// FIXME: This should probably never be called, but it's here as
TemplateParmPosition()
: Depth(0), Position(0)
- { /* assert(0 && "Cannot create positionless template parameter"); */ }
+ { /* llvm_unreachable("Cannot create positionless template parameter"); */ }
TemplateParmPosition(unsigned D, unsigned P)
: Depth(D), Position(P)
@@ -1864,7 +1859,7 @@ public:
/// \brief Retrieve the partial specializations as an ordered list.
void getPartialSpecializations(
- llvm::SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS);
+ SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS);
/// \brief Find a class template partial specialization with the given
/// type T.
@@ -2097,6 +2092,58 @@ public:
friend class ASTDeclWriter;
};
+/// Declaration of a function specialization at template class scope.
+/// This is a non standard extension needed to support MSVC.
+/// For example:
+/// template <class T>
+/// class A {
+/// template <class U> void foo(U a) { }
+/// template<> void foo(int a) { }
+/// }
+///
+/// "template<> foo(int a)" will be saved in Specialization as a normal
+/// CXXMethodDecl. Then during an instantiation of class A, it will be
+/// transformed into an actual function specialization.
+class ClassScopeFunctionSpecializationDecl : public Decl {
+private:
+ ClassScopeFunctionSpecializationDecl(DeclContext *DC, SourceLocation Loc,
+ CXXMethodDecl *FD)
+ : Decl(Decl::ClassScopeFunctionSpecialization, DC, Loc),
+ Specialization(FD) {}
+
+ ClassScopeFunctionSpecializationDecl(EmptyShell Empty)
+ : Decl(Decl::ClassScopeFunctionSpecialization, Empty) {}
+
+ CXXMethodDecl *Specialization;
+
+public:
+ CXXMethodDecl *getSpecialization() const { return Specialization; }
+
+ static ClassScopeFunctionSpecializationDecl *Create(ASTContext &C,
+ DeclContext *DC,
+ SourceLocation Loc,
+ CXXMethodDecl *FD) {
+ return new (C) ClassScopeFunctionSpecializationDecl(DC , Loc, FD);
+ }
+
+ static ClassScopeFunctionSpecializationDecl *Create(ASTContext &Context,
+ EmptyShell Empty) {
+ return new (Context)ClassScopeFunctionSpecializationDecl(0,
+ SourceLocation(), 0);
+ }
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) {
+ return K == Decl::ClassScopeFunctionSpecialization;
+ }
+ static bool classof(const ClassScopeFunctionSpecializationDecl *D) {
+ return true;
+ }
+
+ friend class ASTDeclReader;
+ friend class ASTDeclWriter;
+};
+
/// Implementation of inline functions that require the template declarations
inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD)
: Function(FTD) { }
diff --git a/include/clang/AST/DeclVisitor.h b/include/clang/AST/DeclVisitor.h
index aee1998028eb..b5b6bd42ddb1 100644
--- a/include/clang/AST/DeclVisitor.h
+++ b/include/clang/AST/DeclVisitor.h
@@ -30,7 +30,7 @@ class DeclVisitor {
public:
RetTy Visit(Decl *D) {
switch (D->getKind()) {
- default: assert(false && "Decl that isn't part of DeclNodes.inc!");
+ default: llvm_unreachable("Decl that isn't part of DeclNodes.inc!");
#define DECL(DERIVED, BASE) \
case Decl::DERIVED: DISPATCH(DERIVED##Decl, DERIVED##Decl);
#define ABSTRACT_DECL(DECL)
diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h
index bb098313ea3a..2170f2b1ef7f 100644
--- a/include/clang/AST/DeclarationName.h
+++ b/include/clang/AST/DeclarationName.h
@@ -203,7 +203,7 @@ public:
std::string getAsString() const;
/// printName - Print the human-readable name to a stream.
- void printName(llvm::raw_ostream &OS) const;
+ void printName(raw_ostream &OS) const;
/// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in
/// this declaration name, or NULL if this declaration name isn't a
@@ -503,7 +503,7 @@ public:
std::string getAsString() const;
/// printName - Print the human-readable name to a stream.
- void printName(llvm::raw_ostream &OS) const;
+ void printName(raw_ostream &OS) const;
/// getBeginLoc - Retrieve the location of the first token.
SourceLocation getBeginLoc() const { return NameLoc; }
@@ -520,7 +520,7 @@ public:
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
DeclarationName N) {
DB.AddTaggedVal(N.getAsOpaqueInteger(),
- Diagnostic::ak_declarationname);
+ DiagnosticsEngine::ak_declarationname);
return DB;
}
@@ -529,11 +529,11 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
DeclarationName N) {
PD.AddTaggedVal(N.getAsOpaqueInteger(),
- Diagnostic::ak_declarationname);
+ DiagnosticsEngine::ak_declarationname);
return PD;
}
-inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+inline raw_ostream &operator<<(raw_ostream &OS,
DeclarationNameInfo DNInfo) {
DNInfo.printName(OS);
return OS;
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index c7f870725c42..1242f4e6c702 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -20,6 +20,7 @@
#include "clang/AST/DeclAccessPair.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/ASTVector.h"
+#include "clang/AST/TemplateBase.h"
#include "clang/AST/UsuallyTinyPtrVector.h"
#include "clang/Basic/TypeTraits.h"
#include "llvm/ADT/APSInt.h"
@@ -41,12 +42,10 @@ namespace clang {
class CXXOperatorCallExpr;
class CXXMemberCallExpr;
class ObjCPropertyRefExpr;
- class TemplateArgumentLoc;
- class TemplateArgumentListInfo;
class OpaqueValueExpr;
/// \brief A simple array of base specifiers.
-typedef llvm::SmallVector<CXXBaseSpecifier*, 4> CXXCastPath;
+typedef SmallVector<CXXBaseSpecifier*, 4> CXXCastPath;
/// Expr - This represents one expression. Note that Expr's are subclasses of
/// Stmt. This allows an expression to be transparently used any place a Stmt
@@ -454,9 +453,14 @@ public:
/// EvaluateAsBooleanCondition - Return true if this is a constant
/// which we we can fold and convert to a boolean condition using
- /// any crazy technique that we want to.
+ /// any crazy technique that we want to, even if the expression has
+ /// side-effects.
bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx) const;
+ /// EvaluateAsInt - Return true if this is a constant which we can fold and
+ /// convert to an integer using any crazy technique that we want to.
+ bool EvaluateAsInt(llvm::APSInt &Result, const ASTContext &Ctx) const;
+
/// isEvaluatable - Call Evaluate to see if this expression can be constant
/// folded, but discard the result.
bool isEvaluatable(const ASTContext &Ctx) const;
@@ -467,9 +471,9 @@ public:
/// variable read.
bool HasSideEffects(const ASTContext &Ctx) const;
- /// EvaluateAsInt - Call Evaluate and return the folded integer. This
+ /// EvaluateKnownConstInt - Call Evaluate and return the folded integer. This
/// must be called on an expression that constant folds to an integer.
- llvm::APSInt EvaluateAsInt(const ASTContext &Ctx) const;
+ llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx) const;
/// EvaluateAsLValue - Evaluate an expression to see if it's a lvalue
/// with link time known address.
@@ -688,39 +692,6 @@ public:
static bool classof(const OpaqueValueExpr *) { return true; }
};
-/// \brief Represents an explicit template argument list in C++, e.g.,
-/// the "<int>" in "sort<int>".
-struct ExplicitTemplateArgumentList {
- /// \brief The source location of the left angle bracket ('<');
- SourceLocation LAngleLoc;
-
- /// \brief The source location of the right angle bracket ('>');
- SourceLocation RAngleLoc;
-
- /// \brief The number of template arguments in TemplateArgs.
- /// The actual template arguments (if any) are stored after the
- /// ExplicitTemplateArgumentList structure.
- unsigned NumTemplateArgs;
-
- /// \brief Retrieve the template arguments
- TemplateArgumentLoc *getTemplateArgs() {
- return reinterpret_cast<TemplateArgumentLoc *> (this + 1);
- }
-
- /// \brief Retrieve the template arguments
- const TemplateArgumentLoc *getTemplateArgs() const {
- return reinterpret_cast<const TemplateArgumentLoc *> (this + 1);
- }
-
- void initializeFrom(const TemplateArgumentListInfo &List);
- void initializeFrom(const TemplateArgumentListInfo &List,
- bool &Dependent, bool &InstantiationDependent,
- bool &ContainsUnexpandedParameterPack);
- void copyInto(TemplateArgumentListInfo &List) const;
- static std::size_t sizeFor(unsigned NumTemplateArgs);
- static std::size_t sizeFor(const TemplateArgumentListInfo &List);
-};
-
/// \brief A reference to a declared variable, function, enum, etc.
/// [C99 6.5.1p2]
///
@@ -804,6 +775,7 @@ public:
DeclRefExprBits.HasQualifier = 0;
DeclRefExprBits.HasExplicitTemplateArgs = 0;
DeclRefExprBits.HasFoundDecl = 0;
+ DeclRefExprBits.HadMultipleCandidates = 0;
computeDependence();
}
@@ -887,29 +859,29 @@ public:
/// \brief Retrieve the explicit template argument list that followed the
/// member template name.
- ExplicitTemplateArgumentList &getExplicitTemplateArgs() {
+ ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
assert(hasExplicitTemplateArgs());
if (hasFoundDecl())
- return *reinterpret_cast<ExplicitTemplateArgumentList *>(
+ return *reinterpret_cast<ASTTemplateArgumentListInfo *>(
&getInternalFoundDecl() + 1);
if (hasQualifier())
- return *reinterpret_cast<ExplicitTemplateArgumentList *>(
+ return *reinterpret_cast<ASTTemplateArgumentListInfo *>(
&getInternalQualifierLoc() + 1);
- return *reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
+ return *reinterpret_cast<ASTTemplateArgumentListInfo *>(this + 1);
}
/// \brief Retrieve the explicit template argument list that followed the
/// member template name.
- const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const {
+ const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
return const_cast<DeclRefExpr *>(this)->getExplicitTemplateArgs();
}
/// \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 ExplicitTemplateArgumentList *getExplicitTemplateArgsOpt() const {
+ const ASTTemplateArgumentListInfo *getExplicitTemplateArgsOpt() const {
if (!hasExplicitTemplateArgs()) return 0;
return &getExplicitTemplateArgs();
}
@@ -957,6 +929,18 @@ public:
return getExplicitTemplateArgs().RAngleLoc;
}
+ /// \brief Returns true if this expression refers to a function that
+ /// was resolved from an overloaded set having size greater than 1.
+ bool hadMultipleCandidates() const {
+ return DeclRefExprBits.HadMultipleCandidates;
+ }
+ /// \brief Sets the flag telling whether this expression refers to
+ /// a function that was resolved from an overloaded set having size
+ /// greater than 1.
+ void setHadMultipleCandidates(bool V = true) {
+ DeclRefExprBits.HadMultipleCandidates = V;
+ }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == DeclRefExprClass;
}
@@ -1112,29 +1096,39 @@ public:
};
class CharacterLiteral : public Expr {
+public:
+ enum CharacterKind {
+ Ascii,
+ Wide,
+ UTF16,
+ UTF32
+ };
+
+private:
unsigned Value;
SourceLocation Loc;
- bool IsWide;
+ unsigned Kind : 2;
public:
// type should be IntTy
- CharacterLiteral(unsigned value, bool iswide, QualType type, SourceLocation l)
+ CharacterLiteral(unsigned value, CharacterKind kind, QualType type,
+ SourceLocation l)
: Expr(CharacterLiteralClass, type, VK_RValue, OK_Ordinary, false, false,
false, false),
- Value(value), Loc(l), IsWide(iswide) {
+ Value(value), Loc(l), Kind(kind) {
}
/// \brief Construct an empty character literal.
CharacterLiteral(EmptyShell Empty) : Expr(CharacterLiteralClass, Empty) { }
SourceLocation getLocation() const { return Loc; }
- bool isWide() const { return IsWide; }
+ CharacterKind getKind() const { return static_cast<CharacterKind>(Kind); }
SourceRange getSourceRange() const { return SourceRange(Loc); }
unsigned getValue() const { return Value; }
void setLocation(SourceLocation Location) { Loc = Location; }
- void setWide(bool W) { IsWide = W; }
+ void setKind(CharacterKind kind) { Kind = kind; }
void setValue(unsigned Val) { Value = Val; }
static bool classof(const Stmt *T) {
@@ -1243,13 +1237,23 @@ public:
/// In this case, getByteLength() will return 6, but the string literal will
/// have type "char[2]".
class StringLiteral : public Expr {
+public:
+ enum StringKind {
+ Ascii,
+ Wide,
+ UTF8,
+ UTF16,
+ UTF32
+ };
+
+private:
friend class ASTStmtReader;
const char *StrData;
unsigned ByteLength;
- bool IsWide;
- bool IsPascal;
unsigned NumConcatenated;
+ unsigned Kind : 3;
+ bool IsPascal : 1;
SourceLocation TokLocs[1];
StringLiteral(QualType Ty) :
@@ -1259,33 +1263,39 @@ class StringLiteral : public Expr {
public:
/// This is the "fully general" constructor that allows representation of
/// strings formed from multiple concatenated tokens.
- static StringLiteral *Create(ASTContext &C, llvm::StringRef Str, bool Wide,
+ static StringLiteral *Create(ASTContext &C, StringRef Str, StringKind Kind,
bool Pascal, QualType Ty,
const SourceLocation *Loc, unsigned NumStrs);
/// Simple constructor for string literals made from one token.
- static StringLiteral *Create(ASTContext &C, llvm::StringRef Str, bool Wide,
- bool Pascal, QualType Ty, SourceLocation Loc) {
- return Create(C, Str, Wide, Pascal, Ty, &Loc, 1);
+ static StringLiteral *Create(ASTContext &C, StringRef Str, StringKind Kind,
+ bool Pascal, QualType Ty,
+ SourceLocation Loc) {
+ return Create(C, Str, Kind, Pascal, Ty, &Loc, 1);
}
/// \brief Construct an empty string literal.
static StringLiteral *CreateEmpty(ASTContext &C, unsigned NumStrs);
- llvm::StringRef getString() const {
- return llvm::StringRef(StrData, ByteLength);
+ StringRef getString() const {
+ return StringRef(StrData, ByteLength);
}
unsigned getByteLength() const { return ByteLength; }
/// \brief Sets the string data to the given string data.
- void setString(ASTContext &C, llvm::StringRef Str);
-
- bool isWide() const { return IsWide; }
+ void setString(ASTContext &C, StringRef Str);
+
+ StringKind getKind() const { return static_cast<StringKind>(Kind); }
+ bool isAscii() const { return Kind == Ascii; }
+ bool isWide() const { return Kind == Wide; }
+ bool isUTF8() const { return Kind == UTF8; }
+ bool isUTF16() const { return Kind == UTF16; }
+ bool isUTF32() const { return Kind == UTF32; }
bool isPascal() const { return IsPascal; }
-
+
bool containsNonAsciiOrNull() const {
- llvm::StringRef Str = getString();
+ StringRef Str = getString();
for (unsigned i = 0, e = Str.size(); i != e; ++i)
if (!isascii(Str[i]) || !Str[i])
return true;
@@ -2029,6 +2039,10 @@ class MemberExpr : public Expr {
/// the MemberNameQualifier structure.
bool HasExplicitTemplateArgumentList : 1;
+ /// \brief True if this member expression refers to a method that
+ /// was resolved from an overloaded set having size greater than 1.
+ bool HadMultipleCandidates : 1;
+
/// \brief Retrieve the qualifier that preceded the member name, if any.
MemberNameQualifier *getMemberQualifier() {
assert(HasQualifierOrFoundDecl);
@@ -2051,7 +2065,8 @@ public:
base->containsUnexpandedParameterPack()),
Base(base), MemberDecl(memberdecl), MemberLoc(NameInfo.getLoc()),
MemberDNLoc(NameInfo.getInfo()), IsArrow(isarrow),
- HasQualifierOrFoundDecl(false), HasExplicitTemplateArgumentList(false) {
+ HasQualifierOrFoundDecl(false), HasExplicitTemplateArgumentList(false),
+ HadMultipleCandidates(false) {
assert(memberdecl->getDeclName() == NameInfo.getName());
}
@@ -2068,7 +2083,8 @@ public:
base->containsUnexpandedParameterPack()),
Base(base), MemberDecl(memberdecl), MemberLoc(l), MemberDNLoc(),
IsArrow(isarrow),
- HasQualifierOrFoundDecl(false), HasExplicitTemplateArgumentList(false) {}
+ HasQualifierOrFoundDecl(false), HasExplicitTemplateArgumentList(false),
+ HadMultipleCandidates(false) {}
static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifierLoc QualifierLoc,
@@ -2136,26 +2152,26 @@ public:
/// \brief Retrieve the explicit template argument list that
/// follow the member template name. This must only be called on an
/// expression with explicit template arguments.
- ExplicitTemplateArgumentList &getExplicitTemplateArgs() {
+ ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
assert(HasExplicitTemplateArgumentList);
if (!HasQualifierOrFoundDecl)
- return *reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
+ return *reinterpret_cast<ASTTemplateArgumentListInfo *>(this + 1);
- return *reinterpret_cast<ExplicitTemplateArgumentList *>(
+ return *reinterpret_cast<ASTTemplateArgumentListInfo *>(
getMemberQualifier() + 1);
}
/// \brief Retrieve the explicit template argument list that
/// followed the member template name. This must only be called on
/// an expression with explicit template arguments.
- const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const {
+ const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
return const_cast<MemberExpr *>(this)->getExplicitTemplateArgs();
}
/// \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 ExplicitTemplateArgumentList *getOptionalExplicitTemplateArgs() const {
+ const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const {
if (!hasExplicitTemplateArgs()) return 0;
return &getExplicitTemplateArgs();
}
@@ -2218,7 +2234,19 @@ public:
bool isImplicitAccess() const {
return getBase() && getBase()->isImplicitCXXThis();
}
-
+
+ /// \brief Returns true if this member expression refers to a method that
+ /// was resolved from an overloaded set having size greater than 1.
+ bool hadMultipleCandidates() const {
+ return HadMultipleCandidates;
+ }
+ /// \brief Sets the flag telling whether this expression refers to
+ /// a method that was resolved from an overloaded set having size
+ /// greater than 1.
+ void setHadMultipleCandidates(bool V = true) {
+ HadMultipleCandidates = V;
+ }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == MemberExprClass;
}
@@ -2301,68 +2329,7 @@ public:
private:
Stmt *Op;
- void CheckCastConsistency() const {
-#ifndef NDEBUG
- switch (getCastKind()) {
- case CK_DerivedToBase:
- case CK_UncheckedDerivedToBase:
- case CK_DerivedToBaseMemberPointer:
- case CK_BaseToDerived:
- case CK_BaseToDerivedMemberPointer:
- assert(!path_empty() && "Cast kind should have a base path!");
- break;
-
- // These should not have an inheritance path.
- case CK_BitCast:
- case CK_Dynamic:
- case CK_ToUnion:
- case CK_ArrayToPointerDecay:
- case CK_FunctionToPointerDecay:
- case CK_NullToMemberPointer:
- case CK_NullToPointer:
- case CK_ConstructorConversion:
- case CK_IntegralToPointer:
- case CK_PointerToIntegral:
- case CK_ToVoid:
- case CK_VectorSplat:
- case CK_IntegralCast:
- case CK_IntegralToFloating:
- case CK_FloatingToIntegral:
- case CK_FloatingCast:
- case CK_AnyPointerToObjCPointerCast:
- case CK_AnyPointerToBlockPointerCast:
- case CK_ObjCObjectLValueCast:
- case CK_FloatingRealToComplex:
- case CK_FloatingComplexToReal:
- case CK_FloatingComplexCast:
- case CK_FloatingComplexToIntegralComplex:
- case CK_IntegralRealToComplex:
- case CK_IntegralComplexToReal:
- case CK_IntegralComplexCast:
- case CK_IntegralComplexToFloatingComplex:
- case CK_ObjCProduceObject:
- case CK_ObjCConsumeObject:
- case CK_ObjCReclaimReturnedObject:
- assert(!getType()->isBooleanType() && "unheralded conversion to bool");
- // fallthrough to check for null base path
-
- case CK_Dependent:
- case CK_LValueToRValue:
- case CK_GetObjCProperty:
- case CK_NoOp:
- case CK_PointerToBoolean:
- case CK_IntegralToBoolean:
- case CK_FloatingToBoolean:
- case CK_MemberPointerToBoolean:
- case CK_FloatingComplexToBoolean:
- case CK_IntegralComplexToBoolean:
- case CK_LValueBitCast: // -> bool&
- case CK_UserDefinedConversion: // operator bool()
- assert(path_empty() && "Cast kind should not have a base path!");
- break;
- }
-#endif
- }
+ void CheckCastConsistency() const;
const CXXBaseSpecifier * const *path_buffer() const {
return const_cast<CastExpr*>(this)->path_buffer();
@@ -2393,7 +2360,9 @@ protected:
assert(kind != CK_Invalid && "creating cast with invalid cast kind");
CastExprBits.Kind = kind;
setBasePathSize(BasePathSize);
+#ifndef NDEBUG
CheckCastConsistency();
+#endif
}
/// \brief Construct an empty cast.
@@ -2746,7 +2715,7 @@ protected:
/// CompoundAssignOperator - For compound assignments (e.g. +=), we keep
/// track of the type the operation is performed in. Due to the semantics of
-/// these operators, the operands are promoted, the aritmetic performed, an
+/// these operators, the operands are promoted, the arithmetic performed, an
/// implicit conversion back to the result type done, then the assignment takes
/// place. This captures the intermediate type which the computation is done
/// in.
@@ -3134,7 +3103,7 @@ public:
unsigned getShuffleMaskIdx(ASTContext &Ctx, unsigned N) {
assert((N < NumExprs - 2) && "Shuffle idx out of range!");
- return getExpr(N+2)->EvaluateAsInt(Ctx).getZExtValue();
+ return getExpr(N+2)->EvaluateKnownConstInt(Ctx).getZExtValue();
}
// Iterators
@@ -4045,7 +4014,7 @@ public:
/// getEncodedElementAccess - Encode the elements accessed into an llvm
/// aggregate Constant of ConstantInt(s).
- void getEncodedElementAccess(llvm::SmallVectorImpl<unsigned> &Elts) const;
+ void getEncodedElementAccess(SmallVectorImpl<unsigned> &Elts) const;
SourceRange getSourceRange() const {
return SourceRange(getBase()->getLocStart(), AccessorLoc);
@@ -4193,6 +4162,101 @@ public:
// Iterators
child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
};
+
+/// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*,
+/// __atomic_load, __atomic_store, and __atomic_compare_exchange_*, for the
+/// similarly-named C++0x instructions. All of these instructions take one
+/// primary pointer and at least one memory order.
+class AtomicExpr : public Expr {
+public:
+ enum AtomicOp { Load, Store, CmpXchgStrong, CmpXchgWeak, Xchg,
+ Add, Sub, And, Or, Xor };
+private:
+ enum { PTR, ORDER, VAL1, ORDER_FAIL, VAL2, END_EXPR };
+ Stmt* SubExprs[END_EXPR];
+ unsigned NumSubExprs;
+ SourceLocation BuiltinLoc, RParenLoc;
+ AtomicOp Op;
+
+public:
+ AtomicExpr(SourceLocation BLoc, Expr **args, unsigned nexpr, QualType t,
+ AtomicOp op, SourceLocation RP);
+
+ /// \brief Build an empty AtomicExpr.
+ explicit AtomicExpr(EmptyShell Empty) : Expr(AtomicExprClass, Empty) { }
+
+ Expr *getPtr() const {
+ return cast<Expr>(SubExprs[PTR]);
+ }
+ void setPtr(Expr *E) {
+ SubExprs[PTR] = E;
+ }
+ Expr *getOrder() const {
+ return cast<Expr>(SubExprs[ORDER]);
+ }
+ void setOrder(Expr *E) {
+ SubExprs[ORDER] = E;
+ }
+ Expr *getVal1() const {
+ assert(NumSubExprs >= 3);
+ return cast<Expr>(SubExprs[VAL1]);
+ }
+ void setVal1(Expr *E) {
+ assert(NumSubExprs >= 3);
+ SubExprs[VAL1] = E;
+ }
+ Expr *getOrderFail() const {
+ assert(NumSubExprs == 5);
+ return cast<Expr>(SubExprs[ORDER_FAIL]);
+ }
+ void setOrderFail(Expr *E) {
+ assert(NumSubExprs == 5);
+ SubExprs[ORDER_FAIL] = E;
+ }
+ Expr *getVal2() const {
+ assert(NumSubExprs == 5);
+ return cast<Expr>(SubExprs[VAL2]);
+ }
+ void setVal2(Expr *E) {
+ assert(NumSubExprs == 5);
+ SubExprs[VAL2] = E;
+ }
+
+ AtomicOp getOp() const { return Op; }
+ void setOp(AtomicOp op) { Op = op; }
+ unsigned getNumSubExprs() { return NumSubExprs; }
+ void setNumSubExprs(unsigned num) { NumSubExprs = num; }
+
+ Expr **getSubExprs() { return reinterpret_cast<Expr **>(SubExprs); }
+
+ bool isVolatile() const {
+ return getPtr()->getType()->getPointeeType().isVolatileQualified();
+ }
+
+ bool isCmpXChg() const {
+ return getOp() == AtomicExpr::CmpXchgStrong ||
+ getOp() == AtomicExpr::CmpXchgWeak;
+ }
+
+ SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
+ void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; }
+
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation L) { RParenLoc = L; }
+
+ SourceRange getSourceRange() const {
+ return SourceRange(BuiltinLoc, RParenLoc);
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == AtomicExprClass;
+ }
+ static bool classof(const AtomicExpr *) { return true; }
+
+ // Iterators
+ child_range children() {
+ return child_range(SubExprs, SubExprs+NumSubExprs);
+ }
+};
} // end namespace clang
#endif
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 19117040ef96..3cc09cdf5e45 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -807,37 +807,41 @@ private:
SourceLocation Loc;
SourceRange ParenRange;
+ unsigned NumArgs : 16;
bool Elidable : 1;
+ bool HadMultipleCandidates : 1;
bool ZeroInitialization : 1;
unsigned ConstructKind : 2;
Stmt **Args;
- unsigned NumArgs;
protected:
CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
SourceLocation Loc,
CXXConstructorDecl *d, bool elidable,
Expr **args, unsigned numargs,
+ bool HadMultipleCandidates,
bool ZeroInitialization = false,
ConstructionKind ConstructKind = CK_Complete,
SourceRange ParenRange = SourceRange());
/// \brief Construct an empty C++ construction expression.
CXXConstructExpr(StmtClass SC, EmptyShell Empty)
- : Expr(SC, Empty), Constructor(0), Elidable(0), ZeroInitialization(0),
- ConstructKind(0), Args(0), NumArgs(0) { }
+ : Expr(SC, Empty), Constructor(0), NumArgs(0), Elidable(0),
+ HadMultipleCandidates(false), ZeroInitialization(0),
+ ConstructKind(0), Args(0) { }
public:
/// \brief Construct an empty C++ construction expression.
explicit CXXConstructExpr(EmptyShell Empty)
: Expr(CXXConstructExprClass, Empty), Constructor(0),
- Elidable(0), ZeroInitialization(0),
- ConstructKind(0), Args(0), NumArgs(0) { }
+ NumArgs(0), Elidable(0), HadMultipleCandidates(false),
+ ZeroInitialization(0), ConstructKind(0), Args(0) { }
static CXXConstructExpr *Create(ASTContext &C, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool Elidable,
Expr **Args, unsigned NumArgs,
+ bool HadMultipleCandidates,
bool ZeroInitialization = false,
ConstructionKind ConstructKind = CK_Complete,
SourceRange ParenRange = SourceRange());
@@ -852,7 +856,12 @@ public:
/// \brief Whether this construction is elidable.
bool isElidable() const { return Elidable; }
void setElidable(bool E) { Elidable = E; }
-
+
+ /// \brief Whether the referred constructor was resolved from
+ /// an overloaded set having size greater than 1.
+ bool hadMultipleCandidates() const { return HadMultipleCandidates; }
+ void setHadMultipleCandidates(bool V) { HadMultipleCandidates = V; }
+
/// \brief Whether this construction first requires
/// zero-initialization before the initializer is called.
bool requiresZeroInitialization() const { return ZeroInitialization; }
@@ -980,6 +989,7 @@ public:
TypeSourceInfo *Type,
Expr **Args,unsigned NumArgs,
SourceRange parenRange,
+ bool HadMultipleCandidates,
bool ZeroInitialization = false);
explicit CXXTemporaryObjectExpr(EmptyShell Empty)
: CXXConstructExpr(CXXTemporaryObjectExprClass, Empty), Type() { }
@@ -1049,8 +1059,11 @@ class CXXNewExpr : public Expr {
// If this is an array allocation, does the usual deallocation
// function for the allocated type want to know the allocated size?
bool UsualArrayDeleteWantsSize : 1;
+ // Whether the referred constructor (if any) was resolved from an
+ // overload set having size greater than 1.
+ bool HadMultipleCandidates : 1;
// The number of placement new arguments.
- unsigned NumPlacementArgs : 14;
+ unsigned NumPlacementArgs : 13;
// The number of constructor arguments. This may be 1 even for non-class
// types; use the pseudo copy constructor.
unsigned NumConstructorArgs : 14;
@@ -1086,6 +1099,7 @@ public:
SourceRange TypeIdParens,
Expr *arraySize, CXXConstructorDecl *constructor, bool initializer,
Expr **constructorArgs, unsigned numConsArgs,
+ bool HadMultipleCandidates,
FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize,
QualType ty, TypeSourceInfo *AllocatedTypeInfo,
SourceLocation startLoc, SourceLocation endLoc,
@@ -1174,6 +1188,11 @@ public:
return cast<Expr>(SubExprs[Array + NumPlacementArgs + i]);
}
+ /// \brief Whether the new expression refers a constructor that was
+ /// resolved from an overloaded set having size greater than 1.
+ bool hadMultipleCandidates() const { return HadMultipleCandidates; }
+ void setHadMultipleCandidates(bool V) { HadMultipleCandidates = V; }
+
typedef ExprIterator arg_iterator;
typedef ConstExprIterator const_arg_iterator;
@@ -1842,16 +1861,16 @@ public:
/// template argument list, e.g. f<int>.
bool hasExplicitTemplateArgs() const { return HasExplicitTemplateArgs; }
- ExplicitTemplateArgumentList &getExplicitTemplateArgs(); // defined far below
+ ASTTemplateArgumentListInfo &getExplicitTemplateArgs(); // defined far below
- const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const {
+ const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
return const_cast<OverloadExpr*>(this)->getExplicitTemplateArgs();
}
/// \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 ExplicitTemplateArgumentList *getOptionalExplicitTemplateArgs() {
+ const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() {
if (!hasExplicitTemplateArgs()) return 0;
return &getExplicitTemplateArgs();
}
@@ -1969,21 +1988,21 @@ public:
// nodes, users are *forbidden* from calling these methods on objects
// without explicit template arguments.
- ExplicitTemplateArgumentList &getExplicitTemplateArgs() {
+ ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
assert(hasExplicitTemplateArgs());
- return *reinterpret_cast<ExplicitTemplateArgumentList*>(this + 1);
+ return *reinterpret_cast<ASTTemplateArgumentListInfo*>(this + 1);
}
/// Gets a reference to the explicit template argument list.
- const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const {
+ const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
assert(hasExplicitTemplateArgs());
- return *reinterpret_cast<const ExplicitTemplateArgumentList*>(this + 1);
+ return *reinterpret_cast<const ASTTemplateArgumentListInfo*>(this + 1);
}
/// \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 ExplicitTemplateArgumentList *getOptionalExplicitTemplateArgs() {
+ const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() {
if (!hasExplicitTemplateArgs()) return 0;
return &getExplicitTemplateArgs();
}
@@ -2094,21 +2113,21 @@ public:
// nodes, users are *forbidden* from calling these methods on objects
// without explicit template arguments.
- ExplicitTemplateArgumentList &getExplicitTemplateArgs() {
+ ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
assert(hasExplicitTemplateArgs());
- return *reinterpret_cast<ExplicitTemplateArgumentList*>(this + 1);
+ return *reinterpret_cast<ASTTemplateArgumentListInfo*>(this + 1);
}
/// Gets a reference to the explicit template argument list.
- const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const {
+ const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
assert(hasExplicitTemplateArgs());
- return *reinterpret_cast<const ExplicitTemplateArgumentList*>(this + 1);
+ return *reinterpret_cast<const ASTTemplateArgumentListInfo*>(this + 1);
}
/// \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 ExplicitTemplateArgumentList *getOptionalExplicitTemplateArgs() {
+ const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() {
if (!hasExplicitTemplateArgs()) return 0;
return &getExplicitTemplateArgs();
}
@@ -2470,14 +2489,14 @@ public:
/// \brief Retrieve the explicit template argument list that followed the
/// member template name, if any.
- ExplicitTemplateArgumentList &getExplicitTemplateArgs() {
+ ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
assert(HasExplicitTemplateArgs);
- return *reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
+ return *reinterpret_cast<ASTTemplateArgumentListInfo *>(this + 1);
}
/// \brief Retrieve the explicit template argument list that followed the
/// member template name, if any.
- const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const {
+ const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
return const_cast<CXXDependentScopeMemberExpr *>(this)
->getExplicitTemplateArgs();
}
@@ -2485,7 +2504,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 ExplicitTemplateArgumentList *getOptionalExplicitTemplateArgs() {
+ const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() {
if (!hasExplicitTemplateArgs()) return 0;
return &getExplicitTemplateArgs();
}
@@ -2663,22 +2682,22 @@ public:
/// \brief Retrieve the explicit template argument list that followed the
/// member template name.
- ExplicitTemplateArgumentList &getExplicitTemplateArgs() {
+ ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
assert(hasExplicitTemplateArgs());
- return *reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
+ return *reinterpret_cast<ASTTemplateArgumentListInfo *>(this + 1);
}
/// \brief Retrieve the explicit template argument list that followed the
/// member template name, if any.
- const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const {
+ const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
assert(hasExplicitTemplateArgs());
- return *reinterpret_cast<const ExplicitTemplateArgumentList *>(this + 1);
+ return *reinterpret_cast<const ASTTemplateArgumentListInfo *>(this + 1);
}
/// \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 ExplicitTemplateArgumentList *getOptionalExplicitTemplateArgs() {
+ const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() {
if (!hasExplicitTemplateArgs()) return 0;
return &getExplicitTemplateArgs();
}
@@ -2856,7 +2875,7 @@ public:
}
};
-inline ExplicitTemplateArgumentList &OverloadExpr::getExplicitTemplateArgs() {
+inline ASTTemplateArgumentListInfo &OverloadExpr::getExplicitTemplateArgs() {
if (isa<UnresolvedLookupExpr>(this))
return cast<UnresolvedLookupExpr>(this)->getExplicitTemplateArgs();
else
diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h
index 49d4cfe67626..55726eb4ae65 100644
--- a/include/clang/AST/ExprObjC.h
+++ b/include/clang/AST/ExprObjC.h
@@ -16,6 +16,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/SelectorLocationsKind.h"
#include "clang/Basic/IdentifierTable.h"
namespace clang {
@@ -359,12 +360,12 @@ public:
QualType ArgType;
if (isImplicitProperty()) {
const ObjCMethodDecl *Setter = getImplicitPropertySetter();
- ObjCMethodDecl::param_iterator P = Setter->param_begin();
+ ObjCMethodDecl::param_const_iterator P = Setter->param_begin();
ArgType = (*P)->getType();
} else {
if (ObjCPropertyDecl *PDecl = getExplicitProperty())
if (const ObjCMethodDecl *Setter = PDecl->getSetterMethodDecl()) {
- ObjCMethodDecl::param_iterator P = Setter->param_begin();
+ ObjCMethodDecl::param_const_iterator P = Setter->param_begin();
ArgType = (*P)->getType();
}
if (ArgType.isNull())
@@ -444,9 +445,21 @@ private:
/// class, and can be distinguished via \c getReceiverKind(). Example:
///
class ObjCMessageExpr : public Expr {
+ /// \brief Stores either the selector that this message is sending
+ /// to (when \c HasMethod is zero) or an \c ObjCMethodDecl pointer
+ /// referring to the method that we type-checked against.
+ uintptr_t SelectorOrMethod;
+
+ enum { NumArgsBitWidth = 16 };
+
/// \brief The number of arguments in the message send, not
/// including the receiver.
- unsigned NumArgs : 16;
+ unsigned NumArgs : NumArgsBitWidth;
+
+ void setNumArgs(unsigned Num) {
+ assert((Num >> NumArgsBitWidth) == 0 && "Num of args is out of range!");
+ NumArgs = Num;
+ }
/// \brief The kind of message send this is, which is one of the
/// ReceiverKind values.
@@ -464,26 +477,24 @@ class ObjCMessageExpr : public Expr {
/// \brief Whether this message send is a "delegate init call",
/// i.e. a call of an init method on self from within an init method.
unsigned IsDelegateInitCall : 1;
+
+ /// \brief Whether the locations of the selector identifiers are in a
+ /// "standard" position, a enum SelectorLocationsKind.
+ unsigned SelLocsKind : 2;
/// \brief When the message expression is a send to 'super', this is
/// the location of the 'super' keyword.
SourceLocation SuperLoc;
- /// \brief Stores either the selector that this message is sending
- /// to (when \c HasMethod is zero) or an \c ObjCMethodDecl pointer
- /// referring to the method that we type-checked against.
- uintptr_t SelectorOrMethod;
-
- /// \brief Location of the selector.
- SourceLocation SelectorLoc;
-
/// \brief The source locations of the open and close square
/// brackets ('[' and ']', respectively).
SourceLocation LBracLoc, RBracLoc;
ObjCMessageExpr(EmptyShell Empty, unsigned NumArgs)
- : Expr(ObjCMessageExprClass, Empty), NumArgs(NumArgs), Kind(0),
- HasMethod(0), IsDelegateInitCall(0), SelectorOrMethod(0) { }
+ : Expr(ObjCMessageExprClass, Empty), SelectorOrMethod(0), Kind(0),
+ HasMethod(0), IsDelegateInitCall(0) {
+ setNumArgs(NumArgs);
+ }
ObjCMessageExpr(QualType T, ExprValueKind VK,
SourceLocation LBracLoc,
@@ -491,27 +502,34 @@ class ObjCMessageExpr : public Expr {
bool IsInstanceSuper,
QualType SuperType,
Selector Sel,
- SourceLocation SelLoc,
+ ArrayRef<SourceLocation> SelLocs,
+ SelectorLocationsKind SelLocsK,
ObjCMethodDecl *Method,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr *> Args,
SourceLocation RBracLoc);
ObjCMessageExpr(QualType T, ExprValueKind VK,
SourceLocation LBracLoc,
TypeSourceInfo *Receiver,
Selector Sel,
- SourceLocation SelLoc,
+ ArrayRef<SourceLocation> SelLocs,
+ SelectorLocationsKind SelLocsK,
ObjCMethodDecl *Method,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr *> Args,
SourceLocation RBracLoc);
ObjCMessageExpr(QualType T, ExprValueKind VK,
SourceLocation LBracLoc,
Expr *Receiver,
Selector Sel,
- SourceLocation SelLoc,
+ ArrayRef<SourceLocation> SelLocs,
+ SelectorLocationsKind SelLocsK,
ObjCMethodDecl *Method,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr *> Args,
SourceLocation RBracLoc);
+ void initArgsAndSelLocs(ArrayRef<Expr *> Args,
+ ArrayRef<SourceLocation> SelLocs,
+ SelectorLocationsKind SelLocsK);
+
/// \brief Retrieve the pointer value of the message receiver.
void *getReceiverPointer() const {
return *const_cast<void **>(
@@ -523,6 +541,40 @@ class ObjCMessageExpr : public Expr {
*reinterpret_cast<void **>(this + 1) = Value;
}
+ SelectorLocationsKind getSelLocsKind() const {
+ return (SelectorLocationsKind)SelLocsKind;
+ }
+ bool hasStandardSelLocs() const {
+ return getSelLocsKind() != SelLoc_NonStandard;
+ }
+
+ /// \brief Get a pointer to the stored selector identifiers locations array.
+ /// No locations will be stored if HasStandardSelLocs is true.
+ SourceLocation *getStoredSelLocs() {
+ return reinterpret_cast<SourceLocation*>(getArgs() + getNumArgs());
+ }
+ const SourceLocation *getStoredSelLocs() const {
+ return reinterpret_cast<const SourceLocation*>(getArgs() + getNumArgs());
+ }
+
+ /// \brief Get the number of stored selector identifiers locations.
+ /// No locations will be stored if HasStandardSelLocs is true.
+ unsigned getNumStoredSelLocs() const {
+ if (hasStandardSelLocs())
+ return 0;
+ return getNumSelectorLocs();
+ }
+
+ static ObjCMessageExpr *alloc(ASTContext &C,
+ ArrayRef<Expr *> Args,
+ SourceLocation RBraceLoc,
+ ArrayRef<SourceLocation> SelLocs,
+ Selector Sel,
+ SelectorLocationsKind &SelLocsK);
+ static ObjCMessageExpr *alloc(ASTContext &C,
+ unsigned NumArgs,
+ unsigned NumStoredSelLocs);
+
public:
/// \brief The kind of receiver this message is sending to.
enum ReceiverKind {
@@ -570,9 +622,9 @@ public:
bool IsInstanceSuper,
QualType SuperType,
Selector Sel,
- SourceLocation SelLoc,
+ ArrayRef<SourceLocation> SelLocs,
ObjCMethodDecl *Method,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr *> Args,
SourceLocation RBracLoc);
/// \brief Create a class message send.
@@ -605,9 +657,9 @@ public:
SourceLocation LBracLoc,
TypeSourceInfo *Receiver,
Selector Sel,
- SourceLocation SelLoc,
+ ArrayRef<SourceLocation> SelLocs,
ObjCMethodDecl *Method,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr *> Args,
SourceLocation RBracLoc);
/// \brief Create an instance message send.
@@ -640,9 +692,9 @@ public:
SourceLocation LBracLoc,
Expr *Receiver,
Selector Sel,
- SourceLocation SelLoc,
+ ArrayRef<SourceLocation> SeLocs,
ObjCMethodDecl *Method,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr *> Args,
SourceLocation RBracLoc);
/// \brief Create an empty Objective-C message expression, to be
@@ -652,7 +704,9 @@ public:
///
/// \param NumArgs The number of message arguments, not including
/// the receiver.
- static ObjCMessageExpr *CreateEmpty(ASTContext &Context, unsigned NumArgs);
+ static ObjCMessageExpr *CreateEmpty(ASTContext &Context,
+ unsigned NumArgs,
+ unsigned NumStoredSelLocs);
/// \brief Determine the kind of receiver that this message is being
/// sent to.
@@ -822,7 +876,27 @@ public:
SourceLocation getLeftLoc() const { return LBracLoc; }
SourceLocation getRightLoc() const { return RBracLoc; }
- SourceLocation getSelectorLoc() const { return SelectorLoc; }
+
+ SourceLocation getSelectorStartLoc() const { return getSelectorLoc(0); }
+ SourceLocation getSelectorLoc(unsigned Index) const {
+ assert(Index < getNumSelectorLocs() && "Index out of range!");
+ if (hasStandardSelLocs())
+ return getStandardSelectorLoc(Index, getSelector(),
+ getSelLocsKind() == SelLoc_StandardWithSpace,
+ llvm::makeArrayRef(const_cast<Expr**>(getArgs()),
+ getNumArgs()),
+ RBracLoc);
+ return getStoredSelLocs()[Index];
+ }
+
+ void getSelectorLocs(SmallVectorImpl<SourceLocation> &SelLocs) const;
+
+ unsigned getNumSelectorLocs() const {
+ Selector Sel = getSelector();
+ if (Sel.isUnarySelector())
+ return 1;
+ return Sel.getNumArgs();
+ }
void setSourceRange(SourceRange R) {
LBracLoc = R.getBegin();
@@ -989,10 +1063,10 @@ class ObjCBridgedCastExpr : public ExplicitCastExpr {
public:
ObjCBridgedCastExpr(SourceLocation LParenLoc, ObjCBridgeCastKind Kind,
- SourceLocation BridgeKeywordLoc, TypeSourceInfo *TSInfo,
- Expr *Operand)
+ CastKind CK, SourceLocation BridgeKeywordLoc,
+ TypeSourceInfo *TSInfo, Expr *Operand)
: ExplicitCastExpr(ObjCBridgedCastExprClass, TSInfo->getType(), VK_RValue,
- CK_BitCast, Operand, 0, TSInfo),
+ CK, Operand, 0, TSInfo),
LParenLoc(LParenLoc), BridgeKeywordLoc(BridgeKeywordLoc), Kind(Kind) { }
/// \brief Construct an empty Objective-C bridged cast.
@@ -1007,7 +1081,7 @@ public:
}
/// \brief Retrieve the kind of bridge being performed as a string.
- llvm::StringRef getBridgeKindName() const;
+ StringRef getBridgeKindName() const;
/// \brief The location of the bridge keyword.
SourceLocation getBridgeKeywordLoc() const { return BridgeKeywordLoc; }
diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h
index ef1f1618ba1d..96d14b29549b 100644
--- a/include/clang/AST/ExternalASTSource.h
+++ b/include/clang/AST/ExternalASTSource.h
@@ -15,11 +15,6 @@
#define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
#include "clang/AST/DeclBase.h"
-#include <cassert>
-
-namespace llvm {
-template <class T> class SmallVectorImpl;
-}
namespace clang {
@@ -129,16 +124,6 @@ public:
virtual DeclContextLookupResult
FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);
- /// \brief Deserialize all the visible declarations from external storage.
- ///
- /// Name lookup deserializes visible declarations lazily, thus a DeclContext
- /// may not have a complete name lookup table. This function deserializes
- /// the rest of visible declarations from the external storage and completes
- /// the name lookup table of the DeclContext.
- ///
- /// The default implementation of this method is a no-op.
- virtual void MaterializeVisibleDecls(const DeclContext *DC);
-
/// \brief Finds all declarations lexically contained within the given
/// DeclContext, after applying an optional filter predicate.
///
@@ -151,20 +136,20 @@ public:
/// The default implementation of this method is a no-op.
virtual ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC,
bool (*isKindWeWant)(Decl::Kind),
- llvm::SmallVectorImpl<Decl*> &Result);
+ SmallVectorImpl<Decl*> &Result);
/// \brief Finds all declarations lexically contained within the given
/// DeclContext.
///
/// \return true if an error occurred
ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC,
- llvm::SmallVectorImpl<Decl*> &Result) {
+ SmallVectorImpl<Decl*> &Result) {
return FindExternalLexicalDecls(DC, 0, Result);
}
template <typename DeclTy>
ExternalLoadResult FindExternalLexicalDeclsBy(const DeclContext *DC,
- llvm::SmallVectorImpl<Decl*> &Result) {
+ SmallVectorImpl<Decl*> &Result) {
return FindExternalLexicalDecls(DC, DeclTy::classofKind, Result);
}
@@ -231,15 +216,11 @@ protected:
static DeclContextLookupResult
SetExternalVisibleDeclsForName(const DeclContext *DC,
DeclarationName Name,
- llvm::SmallVectorImpl<NamedDecl*> &Decls);
+ ArrayRef<NamedDecl*> Decls);
static DeclContextLookupResult
SetNoExternalVisibleDeclsForName(const DeclContext *DC,
DeclarationName Name);
-
- void MaterializeVisibleDeclsForName(const DeclContext *DC,
- DeclarationName Name,
- llvm::SmallVectorImpl<NamedDecl*> &Decls);
};
/// \brief A lazy pointer to an AST node (of base type T) that resides
@@ -305,6 +286,178 @@ public:
}
};
+/// \brief Represents a lazily-loaded vector of data.
+///
+/// The lazily-loaded vector of data contains data that is partially loaded
+/// from an external source and partially added by local translation. The
+/// items loaded from the external source are loaded lazily, when needed for
+/// iteration over the complete vector.
+template<typename T, typename Source,
+ void (Source::*Loader)(SmallVectorImpl<T>&),
+ unsigned LoadedStorage = 2, unsigned LocalStorage = 4>
+class LazyVector {
+ SmallVector<T, LoadedStorage> Loaded;
+ SmallVector<T, LocalStorage> Local;
+
+public:
+ // Iteration over the elements in the vector.
+ class iterator {
+ LazyVector *Self;
+
+ /// \brief Position within the vector..
+ ///
+ /// In a complete iteration, the Position field walks the range [-M, N),
+ /// where negative values are used to indicate elements
+ /// loaded from the external source while non-negative values are used to
+ /// indicate elements added via \c push_back().
+ /// However, to provide iteration in source order (for, e.g., chained
+ /// precompiled headers), dereferencing the iterator flips the negative
+ /// values (corresponding to loaded entities), so that position -M
+ /// corresponds to element 0 in the loaded entities vector, position -M+1
+ /// corresponds to element 1 in the loaded entities vector, etc. This
+ /// gives us a reasonably efficient, source-order walk.
+ int Position;
+
+ friend class LazyVector;
+
+ public:
+ typedef T value_type;
+ typedef value_type& reference;
+ typedef value_type* pointer;
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef int difference_type;
+
+ iterator() : Self(0), Position(0) { }
+
+ iterator(LazyVector *Self, int Position)
+ : Self(Self), Position(Position) { }
+
+ reference operator*() const {
+ if (Position < 0)
+ return Self->Loaded.end()[Position];
+ return Self->Local[Position];
+ }
+
+ pointer operator->() const {
+ if (Position < 0)
+ return &Self->Loaded.end()[Position];
+
+ return &Self->Local[Position];
+ }
+
+ reference operator[](difference_type D) {
+ return *(*this + D);
+ }
+
+ iterator &operator++() {
+ ++Position;
+ return *this;
+ }
+
+ iterator operator++(int) {
+ iterator Prev(*this);
+ ++Position;
+ return Prev;
+ }
+
+ iterator &operator--() {
+ --Position;
+ return *this;
+ }
+
+ iterator operator--(int) {
+ iterator Prev(*this);
+ --Position;
+ return Prev;
+ }
+
+ friend bool operator==(const iterator &X, const iterator &Y) {
+ return X.Position == Y.Position;
+ }
+
+ friend bool operator!=(const iterator &X, const iterator &Y) {
+ return X.Position != Y.Position;
+ }
+
+ friend bool operator<(const iterator &X, const iterator &Y) {
+ return X.Position < Y.Position;
+ }
+
+ friend bool operator>(const iterator &X, const iterator &Y) {
+ return X.Position > Y.Position;
+ }
+
+ friend bool operator<=(const iterator &X, const iterator &Y) {
+ return X.Position < Y.Position;
+ }
+
+ friend bool operator>=(const iterator &X, const iterator &Y) {
+ return X.Position > Y.Position;
+ }
+
+ friend iterator& operator+=(iterator &X, difference_type D) {
+ X.Position += D;
+ return X;
+ }
+
+ friend iterator& operator-=(iterator &X, difference_type D) {
+ X.Position -= D;
+ return X;
+ }
+
+ friend iterator operator+(iterator X, difference_type D) {
+ X.Position += D;
+ return X;
+ }
+
+ friend iterator operator+(difference_type D, iterator X) {
+ X.Position += D;
+ return X;
+ }
+
+ friend difference_type operator-(const iterator &X, const iterator &Y) {
+ return X.Position - Y.Position;
+ }
+
+ friend iterator operator-(iterator X, difference_type D) {
+ X.Position -= D;
+ return X;
+ }
+ };
+ friend class iterator;
+
+ iterator begin(Source *source, bool LocalOnly = false) {
+ if (LocalOnly)
+ return iterator(this, 0);
+
+ if (source)
+ (source->*Loader)(Loaded);
+ return iterator(this, -(int)Loaded.size());
+ }
+
+ iterator end() {
+ return iterator(this, Local.size());
+ }
+
+ void push_back(const T& LocalValue) {
+ Local.push_back(LocalValue);
+ }
+
+ void erase(iterator From, iterator To) {
+ if (From.Position < 0 && To.Position < 0) {
+ Loaded.erase(Loaded.end() + From.Position, Loaded.end() + To.Position);
+ return;
+ }
+
+ if (From.Position < 0) {
+ Loaded.erase(Loaded.end() + From.Position, Loaded.end());
+ From = begin(0, true);
+ }
+
+ Local.erase(Local.begin() + From.Position, Local.begin() + To.Position);
+ }
+};
+
/// \brief A lazy pointer to a statement.
typedef LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt>
LazyDeclStmtPtr;
diff --git a/include/clang/AST/Makefile b/include/clang/AST/Makefile
index 6ba6e897d186..2854b7f40632 100644
--- a/include/clang/AST/Makefile
+++ b/include/clang/AST/Makefile
@@ -6,24 +6,24 @@ TABLEGEN_INC_FILES_COMMON = 1
include $(CLANG_LEVEL)/Makefile
-$(ObjDir)/Attrs.inc.tmp : $(TD_SRC_DIR)/Attr.td $(TBLGEN) \
+$(ObjDir)/Attrs.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
$(ObjDir)/.dir
$(Echo) "Building Clang attribute classes with tblgen"
- $(Verb) $(TableGen) -gen-clang-attr-classes -o $(call SYSPATH, $@) \
+ $(Verb) $(ClangTableGen) -gen-clang-attr-classes -o $(call SYSPATH, $@) \
-I $(PROJ_SRC_DIR)/../../ $<
-$(ObjDir)/AttrImpl.inc.tmp : $(TD_SRC_DIR)/Attr.td $(TBLGEN) \
+$(ObjDir)/AttrImpl.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
$(ObjDir)/.dir
$(Echo) "Building Clang attribute implementations with tblgen"
- $(Verb) $(TableGen) -gen-clang-attr-impl -o $(call SYSPATH, $@) \
+ $(Verb) $(ClangTableGen) -gen-clang-attr-impl -o $(call SYSPATH, $@) \
-I $(PROJ_SRC_DIR)/../../ $<
-$(ObjDir)/StmtNodes.inc.tmp : $(TD_SRC_DIR)/StmtNodes.td $(TBLGEN) \
+$(ObjDir)/StmtNodes.inc.tmp : $(TD_SRC_DIR)/StmtNodes.td $(CLANG_TBLGEN) \
$(ObjDir)/.dir
$(Echo) "Building Clang statement node tables with tblgen"
- $(Verb) $(TableGen) -gen-clang-stmt-nodes -o $(call SYSPATH, $@) $<
+ $(Verb) $(ClangTableGen) -gen-clang-stmt-nodes -o $(call SYSPATH, $@) $<
-$(ObjDir)/DeclNodes.inc.tmp : $(TD_SRC_DIR)/DeclNodes.td $(TBLGEN) \
+$(ObjDir)/DeclNodes.inc.tmp : $(TD_SRC_DIR)/DeclNodes.td $(CLANG_TBLGEN) \
$(ObjDir)/.dir
$(Echo) "Building Clang declaration node tables with tblgen"
- $(Verb) $(TableGen) -gen-clang-decl-nodes -o $(call SYSPATH, $@) $<
+ $(Verb) $(ClangTableGen) -gen-clang-decl-nodes -o $(call SYSPATH, $@) $<
diff --git a/include/clang/AST/Mangle.h b/include/clang/AST/Mangle.h
index 7af7702027a4..f58a83b54b6b 100644
--- a/include/clang/AST/Mangle.h
+++ b/include/clang/AST/Mangle.h
@@ -39,25 +39,25 @@ namespace clang {
/// external memory ownership.
class MangleBuffer {
public:
- void setString(llvm::StringRef Ref) {
+ void setString(StringRef Ref) {
String = Ref;
}
- llvm::SmallVectorImpl<char> &getBuffer() {
+ SmallVectorImpl<char> &getBuffer() {
return Buffer;
}
- llvm::StringRef getString() const {
+ StringRef getString() const {
if (!String.empty()) return String;
return Buffer.str();
}
- operator llvm::StringRef() const {
+ operator StringRef() const {
return getString();
}
private:
- llvm::StringRef String;
+ StringRef String;
llvm::SmallString<256> Buffer;
};
@@ -65,21 +65,21 @@ private:
/// calls to the C++ name mangler.
class MangleContext {
ASTContext &Context;
- Diagnostic &Diags;
+ DiagnosticsEngine &Diags;
llvm::DenseMap<const BlockDecl*, unsigned> GlobalBlockIds;
llvm::DenseMap<const BlockDecl*, unsigned> LocalBlockIds;
public:
explicit MangleContext(ASTContext &Context,
- Diagnostic &Diags)
+ DiagnosticsEngine &Diags)
: Context(Context), Diags(Diags) { }
virtual ~MangleContext() { }
ASTContext &getASTContext() const { return Context; }
- Diagnostic &getDiags() const { return Diags; }
+ DiagnosticsEngine &getDiags() const { return Diags; }
virtual void startNewFunction() { LocalBlockIds.clear(); }
@@ -95,55 +95,55 @@ public:
/// @{
virtual bool shouldMangleDeclName(const NamedDecl *D) = 0;
- virtual void mangleName(const NamedDecl *D, llvm::raw_ostream &)=0;
+ virtual void mangleName(const NamedDecl *D, raw_ostream &)=0;
virtual void mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk,
- llvm::raw_ostream &) = 0;
+ raw_ostream &) = 0;
virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
const ThisAdjustment &ThisAdjustment,
- llvm::raw_ostream &) = 0;
+ raw_ostream &) = 0;
virtual void mangleReferenceTemporary(const VarDecl *D,
- llvm::raw_ostream &) = 0;
+ raw_ostream &) = 0;
virtual void mangleCXXVTable(const CXXRecordDecl *RD,
- llvm::raw_ostream &) = 0;
+ raw_ostream &) = 0;
virtual void mangleCXXVTT(const CXXRecordDecl *RD,
- llvm::raw_ostream &) = 0;
+ raw_ostream &) = 0;
virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
const CXXRecordDecl *Type,
- llvm::raw_ostream &) = 0;
- virtual void mangleCXXRTTI(QualType T, llvm::raw_ostream &) = 0;
- virtual void mangleCXXRTTIName(QualType T, llvm::raw_ostream &) = 0;
+ raw_ostream &) = 0;
+ virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0;
+ virtual void mangleCXXRTTIName(QualType T, raw_ostream &) = 0;
virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
- llvm::raw_ostream &) = 0;
+ raw_ostream &) = 0;
virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
- llvm::raw_ostream &) = 0;
+ raw_ostream &) = 0;
void mangleGlobalBlock(const BlockDecl *BD,
- llvm::raw_ostream &Out);
+ raw_ostream &Out);
void mangleCtorBlock(const CXXConstructorDecl *CD, CXXCtorType CT,
- const BlockDecl *BD, llvm::raw_ostream &Out);
+ const BlockDecl *BD, raw_ostream &Out);
void mangleDtorBlock(const CXXDestructorDecl *CD, CXXDtorType DT,
- const BlockDecl *BD, llvm::raw_ostream &Out);
+ const BlockDecl *BD, raw_ostream &Out);
void mangleBlock(const DeclContext *DC, const BlockDecl *BD,
- llvm::raw_ostream &Out);
+ raw_ostream &Out);
// Do the right thing.
- void mangleBlock(const BlockDecl *BD, llvm::raw_ostream &Out);
+ void mangleBlock(const BlockDecl *BD, raw_ostream &Out);
void mangleObjCMethodName(const ObjCMethodDecl *MD,
- llvm::raw_ostream &);
+ raw_ostream &);
// This is pretty lame.
virtual void mangleItaniumGuardVariable(const VarDecl *D,
- llvm::raw_ostream &) {
- assert(0 && "Target does not support mangling guard variables");
+ raw_ostream &) {
+ llvm_unreachable("Target does not support mangling guard variables");
}
/// @}
};
MangleContext *createItaniumMangleContext(ASTContext &Context,
- Diagnostic &Diags);
+ DiagnosticsEngine &Diags);
MangleContext *createMicrosoftMangleContext(ASTContext &Context,
- Diagnostic &Diags);
+ DiagnosticsEngine &Diags);
}
diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h
index 018041f8ba20..c81c06e332b6 100644
--- a/include/clang/AST/NestedNameSpecifier.h
+++ b/include/clang/AST/NestedNameSpecifier.h
@@ -18,10 +18,6 @@
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerIntPair.h"
-namespace llvm {
- class raw_ostream;
-}
-
namespace clang {
class ASTContext;
@@ -196,7 +192,7 @@ public:
/// \brief Print this nested name specifier to the given output
/// stream.
- void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const;
+ void print(raw_ostream &OS, const PrintingPolicy &Policy) const;
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddPointer(Prefix.getOpaqueValue());
@@ -469,7 +465,7 @@ public:
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
NestedNameSpecifier *NNS) {
DB.AddTaggedVal(reinterpret_cast<intptr_t>(NNS),
- Diagnostic::ak_nestednamespec);
+ DiagnosticsEngine::ak_nestednamespec);
return DB;
}
diff --git a/include/clang/AST/OperationKinds.h b/include/clang/AST/OperationKinds.h
index 92ff6041371c..469da99a8cbf 100644
--- a/include/clang/AST/OperationKinds.h
+++ b/include/clang/AST/OperationKinds.h
@@ -31,9 +31,12 @@ enum CastKind {
/// to be reinterpreted as a bit pattern of another type. Generally
/// the operands must have equivalent size and unrelated types.
///
- /// The pointer conversion char* -> int* is a bitcast. Many other
- /// pointer conversions which are "physically" bitcasts are given
- /// special cast kinds.
+ /// The pointer conversion char* -> int* is a bitcast. A conversion
+ /// from any pointer type to a C pointer type is a bitcast unless
+ /// it's actually BaseToDerived or DerivedToBase. A conversion to a
+ /// block pointer or ObjC pointer type is a bitcast only if the
+ /// operand has the same type kind; otherwise, it's one of the
+ /// specialized casts below.
///
/// Vector coercions are bitcasts.
CK_BitCast,
@@ -186,12 +189,16 @@ enum CastKind {
/// (float) ld
CK_FloatingCast,
- /// CK_AnyPointerToObjCPointerCast - Casting any other pointer kind
- /// to an Objective-C pointer.
- CK_AnyPointerToObjCPointerCast,
+ /// CK_CPointerToObjCPointerCast - Casting a C pointer kind to an
+ /// Objective-C pointer.
+ CK_CPointerToObjCPointerCast,
- /// CK_AnyPointerToBlockPointerCast - Casting any other pointer kind
- /// to a block pointer.
+ /// CK_BlockPointerToObjCPointerCast - Casting a block pointer to an
+ /// ObjC pointer.
+ CK_BlockPointerToObjCPointerCast,
+
+ /// CK_AnyPointerToBlockPointerCast - Casting any non-block pointer
+ /// to a block pointer. Block-to-block casts are bitcasts.
CK_AnyPointerToBlockPointerCast,
/// \brief Converting between two Objective-C object types, which
@@ -247,20 +254,27 @@ enum CastKind {
/// _Complex unsigned -> _Complex float
CK_IntegralComplexToFloatingComplex,
- /// \brief Produces a retainable object pointer so that it may be
- /// consumed, e.g. by being passed to a consuming parameter. Calls
- /// objc_retain.
- CK_ObjCProduceObject,
+ /// \brief [ARC] Produces a retainable object pointer so that it may
+ /// be consumed, e.g. by being passed to a consuming parameter.
+ /// Calls objc_retain.
+ CK_ARCProduceObject,
- /// \brief Consumes a retainable object pointer that has just been
- /// produced, e.g. as the return value of a retaining call. Enters
- /// a cleanup to call objc_release at some indefinite time.
- CK_ObjCConsumeObject,
+ /// \brief [ARC] Consumes a retainable object pointer that has just
+ /// been produced, e.g. as the return value of a retaining call.
+ /// Enters a cleanup to call objc_release at some indefinite time.
+ CK_ARCConsumeObject,
- /// \brief Reclaim a retainable object pointer object that may have
- /// been produced and autoreleased as part of a function return
+ /// \brief [ARC] Reclaim a retainable object pointer object that may
+ /// have been produced and autoreleased as part of a function return
/// sequence.
- CK_ObjCReclaimReturnedObject
+ CK_ARCReclaimReturnedObject,
+
+ /// \brief [ARC] Causes a value of block type to be copied to the
+ /// heap, if it is not already there. A number of other operations
+ /// in ARC cause blocks to be copied; this is for cases where that
+ /// would not otherwise be guaranteed, such as when casting to a
+ /// non-block pointer type.
+ CK_ARCExtendBlockObject
};
#define CK_Invalid ((CastKind) -1)
diff --git a/include/clang/AST/ParentMap.h b/include/clang/AST/ParentMap.h
index 22c1e7269fac..62eae02c1525 100644
--- a/include/clang/AST/ParentMap.h
+++ b/include/clang/AST/ParentMap.h
@@ -32,6 +32,7 @@ public:
Stmt *getParent(Stmt*) const;
Stmt *getParentIgnoreParens(Stmt *) const;
Stmt *getParentIgnoreParenCasts(Stmt *) const;
+ Stmt *getParentIgnoreParenImpCasts(Stmt *) const;
Stmt *getOuterParenParent(Stmt *) const;
const Stmt *getParent(const Stmt* S) const {
diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h
index fc8ac36b3b97..2bdd8d3f4bc4 100644
--- a/include/clang/AST/PrettyPrinter.h
+++ b/include/clang/AST/PrettyPrinter.h
@@ -15,10 +15,7 @@
#define LLVM_CLANG_AST_PRETTY_PRINTER_H
#include "clang/Basic/LangOptions.h"
-
-namespace llvm {
- class raw_ostream;
-}
+#include "clang/Basic/LLVM.h"
namespace clang {
@@ -29,7 +26,7 @@ class LangOptions;
class PrinterHelper {
public:
virtual ~PrinterHelper();
- virtual bool handledStmt(Stmt* E, llvm::raw_ostream& OS) = 0;
+ virtual bool handledStmt(Stmt* E, raw_ostream& OS) = 0;
};
/// \brief Describes how types, statements, expressions, and
@@ -41,13 +38,14 @@ struct PrintingPolicy {
SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false),
SuppressInitializers(false),
Dump(false), ConstantArraySizeAsWritten(false),
- AnonymousTagLocations(true), SuppressStrongLifetime(false) { }
+ AnonymousTagLocations(true), SuppressStrongLifetime(false),
+ Bool(LO.Bool) { }
/// \brief The number of spaces to use to indent each line.
unsigned Indentation : 8;
/// \brief What language we're printing.
- const LangOptions LangOpts;
+ LangOptions LangOpts;
/// \brief Whether we should suppress printing of the actual specifiers for
/// the given type or declaration.
@@ -133,6 +131,10 @@ struct PrintingPolicy {
/// \brief When true, suppress printing of the __strong lifetime qualifier in
/// ARC.
unsigned SuppressStrongLifetime : 1;
+
+ /// \brief Whether we can use 'bool' rather than '_Bool', even if the language
+ /// doesn't actually have 'bool' (because, e.g., it is defined as a macro).
+ unsigned Bool : 1;
};
} // end namespace clang
diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h
index d7bab80afc5e..b0186cea291c 100644
--- a/include/clang/AST/RecordLayout.h
+++ b/include/clang/AST/RecordLayout.h
@@ -63,6 +63,9 @@ class ASTRecordLayout {
/// any empty subobjects.
CharUnits SizeOfLargestEmptySubobject;
+ /// VBPtrOffset - Virtual base table offset.
+ CharUnits VBPtrOffset;
+
/// PrimaryBase - The primary base info for this record.
llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> PrimaryBase;
@@ -89,7 +92,8 @@ class ASTRecordLayout {
// Constructor for C++ records.
typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy;
ASTRecordLayout(const ASTContext &Ctx,
- CharUnits size, CharUnits alignment, CharUnits datasize,
+ CharUnits size, CharUnits alignment, CharUnits vbptroffset,
+ CharUnits datasize,
const uint64_t *fieldoffsets, unsigned fieldcount,
CharUnits nonvirtualsize, CharUnits nonvirtualalign,
CharUnits SizeOfLargestEmptySubobject,
@@ -199,6 +203,10 @@ public:
assert(CXXInfo && "Record layout does not have C++ specific info!");
return CXXInfo->SizeOfLargestEmptySubobject;
}
+
+ CharUnits getVBPtrOffset() const {
+ return CXXInfo->VBPtrOffset;
+ }
};
} // end namespace clang
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 85c5c08853d1..0ec09c9b09e0 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -813,6 +813,10 @@ DEF_TRAVERSE_TYPE(ObjCObjectPointerType, {
TRY_TO(TraverseType(T->getPointeeType()));
})
+DEF_TRAVERSE_TYPE(AtomicType, {
+ TRY_TO(TraverseType(T->getValueType()));
+ })
+
#undef DEF_TRAVERSE_TYPE
// ----------------- TypeLoc traversal -----------------
@@ -1041,6 +1045,10 @@ DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType, {
TRY_TO(TraverseTypeLoc(TL.getPointeeLoc()));
})
+DEF_TRAVERSE_TYPELOC(AtomicType, {
+ TRY_TO(TraverseTypeLoc(TL.getValueLoc()));
+ })
+
#undef DEF_TRAVERSE_TYPELOC
// ----------------- Decl traversal -----------------
@@ -1114,6 +1122,10 @@ DEF_TRAVERSE_DECL(FriendTemplateDecl, {
}
})
+DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, {
+ TRY_TO(TraverseDecl(D->getSpecialization()));
+ })
+
DEF_TRAVERSE_DECL(LinkageSpecDecl, { })
DEF_TRAVERSE_DECL(ObjCClassDecl, {
@@ -1252,7 +1264,7 @@ bool RecursiveASTVisitor<Derived>::TraverseClassInstantiations(
= (U.get<ClassTemplatePartialSpecializationDecl*>() == Pattern);
if (ShouldVisit)
- TRY_TO(TraverseClassTemplateSpecializationDecl(SD));
+ TRY_TO(TraverseDecl(SD));
break;
}
@@ -1280,7 +1292,7 @@ DEF_TRAVERSE_DECL(ClassTemplateDecl, {
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
// By default, we do not traverse the instantiations of
- // class templates since they do not apprear in the user code. The
+ // class templates since they do not appear in the user code. The
// following code optionally traverses them.
if (getDerived().shouldVisitTemplateInstantiations()) {
// If this is the definition of the primary template, visit
@@ -1318,7 +1330,7 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
case TSK_ExplicitSpecialization:
break;
default:
- assert(false && "Unknown specialization kind.");
+ llvm_unreachable("Unknown specialization kind.");
}
}
@@ -1548,10 +1560,10 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
FTSI->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) {
// A specialization might not have explicit template arguments if it has
// a templated return type and concrete arguments.
- if (const TemplateArgumentListInfo *TALI =
+ if (const ASTTemplateArgumentListInfo *TALI =
FTSI->TemplateArgumentsAsWritten) {
- TRY_TO(TraverseTemplateArgumentLocsHelper(TALI->getArgumentArray(),
- TALI->size()));
+ TRY_TO(TraverseTemplateArgumentLocsHelper(TALI->getTemplateArgs(),
+ TALI->NumTemplateArgs));
}
}
}
@@ -1980,6 +1992,7 @@ DEF_TRAVERSE_STMT(SizeOfPackExpr, { })
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { })
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, { })
DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, { })
+DEF_TRAVERSE_STMT(AtomicExpr, { })
// These literals (all of them) do not need any action.
DEF_TRAVERSE_STMT(IntegerLiteral, { })
diff --git a/include/clang/AST/SelectorLocationsKind.h b/include/clang/AST/SelectorLocationsKind.h
new file mode 100644
index 000000000000..cd43a5c49c55
--- /dev/null
+++ b/include/clang/AST/SelectorLocationsKind.h
@@ -0,0 +1,83 @@
+//===--- SelectorLocationsKind.h - Kind of selector locations ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Describes whether the identifier locations for a selector are "standard"
+// or not.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_SELECTORLOCATIONSKIND_H
+#define LLVM_CLANG_AST_SELECTORLOCATIONSKIND_H
+
+#include "clang/Basic/LLVM.h"
+
+namespace clang {
+ class Selector;
+ class SourceLocation;
+ class Expr;
+ class ParmVarDecl;
+
+/// \brief Whether all locations of the selector identifiers are in a
+/// "standard" position.
+enum SelectorLocationsKind {
+ /// \brief Non-standard.
+ SelLoc_NonStandard = 0,
+
+ /// \brief For nullary selectors, immediately before the end:
+ /// "[foo release]" / "-(void)release;"
+ /// Or immediately before the arguments:
+ /// "[foo first:1 second:2]" / "-(id)first:(int)x second:(int)y;
+ SelLoc_StandardNoSpace = 1,
+
+ /// \brief For nullary selectors, immediately before the end:
+ /// "[foo release]" / "-(void)release;"
+ /// Or with a space between the arguments:
+ /// "[foo first: 1 second: 2]" / "-(id)first: (int)x second: (int)y;
+ SelLoc_StandardWithSpace = 2
+};
+
+/// \brief Returns true if all \arg SelLocs are in a "standard" location.
+SelectorLocationsKind hasStandardSelectorLocs(Selector Sel,
+ ArrayRef<SourceLocation> SelLocs,
+ ArrayRef<Expr *> Args,
+ SourceLocation EndLoc);
+
+/// \brief Get the "standard" location of a selector identifier, e.g:
+/// For nullary selectors, immediately before ']': "[foo release]"
+///
+/// \param WithArgSpace if true the standard location is with a space apart
+/// before arguments: "[foo first: 1 second: 2]"
+/// If false: "[foo first:1 second:2]"
+SourceLocation getStandardSelectorLoc(unsigned Index,
+ Selector Sel,
+ bool WithArgSpace,
+ ArrayRef<Expr *> Args,
+ SourceLocation EndLoc);
+
+/// \brief Returns true if all \arg SelLocs are in a "standard" location.
+SelectorLocationsKind hasStandardSelectorLocs(Selector Sel,
+ ArrayRef<SourceLocation> SelLocs,
+ ArrayRef<ParmVarDecl *> Args,
+ SourceLocation EndLoc);
+
+/// \brief Get the "standard" location of a selector identifier, e.g:
+/// For nullary selectors, immediately before ']': "[foo release]"
+///
+/// \param WithArgSpace if true the standard location is with a space apart
+/// before arguments: "-(id)first: (int)x second: (int)y;"
+/// If false: "-(id)first:(int)x second:(int)y;"
+SourceLocation getStandardSelectorLoc(unsigned Index,
+ Selector Sel,
+ bool WithArgSpace,
+ ArrayRef<ParmVarDecl *> Args,
+ SourceLocation EndLoc);
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index bf5f383be5e0..2a6fd6bc964c 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -14,16 +14,15 @@
#ifndef LLVM_CLANG_AST_STMT_H
#define LLVM_CLANG_AST_STMT_H
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/raw_ostream.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 "llvm/ADT/SmallVector.h"
#include "clang/AST/ASTContext.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/SmallVector.h"
#include <string>
-using llvm::dyn_cast_or_null;
namespace llvm {
class FoldingSetNodeID;
@@ -108,11 +107,10 @@ public:
// Make vanilla 'new' and 'delete' illegal for Stmts.
protected:
void* operator new(size_t bytes) throw() {
- assert(0 && "Stmts cannot be allocated with regular 'new'.");
- return 0;
+ llvm_unreachable("Stmts cannot be allocated with regular 'new'.");
}
void operator delete(void* data) throw() {
- assert(0 && "Stmts cannot be released with regular 'delete'.");
+ llvm_unreachable("Stmts cannot be released with regular 'delete'.");
}
class StmtBitfields {
@@ -148,6 +146,7 @@ protected:
friend class CXXUnresolvedConstructExpr; // ctor
friend class CXXDependentScopeMemberExpr; // ctor
friend class OverloadExpr; // ctor
+ friend class AtomicExpr; // ctor
unsigned : NumStmtBits;
unsigned ValueKind : 2;
@@ -167,6 +166,7 @@ protected:
unsigned HasQualifier : 1;
unsigned HasExplicitTemplateArgs : 1;
unsigned HasFoundDecl : 1;
+ unsigned HadMultipleCandidates : 1;
};
class CastExprBitfields {
@@ -270,7 +270,7 @@ public:
/// This is useful in a debugger.
void dump() const;
void dump(SourceManager &SM) const;
- void dump(llvm::raw_ostream &OS, 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;
@@ -279,12 +279,12 @@ public:
/// dumpPretty/printPretty - These two methods do a "pretty print" of the AST
/// back to its original source language syntax.
void dumpPretty(ASTContext& Context) const;
- void printPretty(llvm::raw_ostream &OS, PrinterHelper *Helper,
+ void printPretty(raw_ostream &OS, PrinterHelper *Helper,
const PrintingPolicy &Policy,
unsigned Indentation = 0) const {
printPretty(OS, *(ASTContext*)0, Helper, Policy, Indentation);
}
- void printPretty(llvm::raw_ostream &OS, ASTContext &Context,
+ void printPretty(raw_ostream &OS, ASTContext &Context,
PrinterHelper *Helper,
const PrintingPolicy &Policy,
unsigned Indentation = 0) const;
@@ -297,6 +297,12 @@ public:
/// statement, such as ExprWithCleanups or ImplicitCastExpr nodes.
Stmt *IgnoreImplicit();
+ const Stmt *stripLabelLikeStatements() const;
+ Stmt *stripLabelLikeStatements() {
+ return const_cast<Stmt*>(
+ const_cast<const Stmt*>(this)->stripLabelLikeStatements());
+ }
+
// Implement isa<T> support.
static bool classof(const Stmt *) { return true; }
@@ -407,25 +413,25 @@ public:
class NullStmt : public Stmt {
SourceLocation SemiLoc;
- /// \brief If the null statement was preceded by an empty macro this is
- /// its instantiation source location, e.g:
+ /// \brief True if the null statement was preceded by an empty macro, e.g:
/// @code
/// #define CALL(x)
/// CALL(0);
/// @endcode
- SourceLocation LeadingEmptyMacro;
+ bool HasLeadingEmptyMacro;
public:
- NullStmt(SourceLocation L, SourceLocation LeadingEmptyMacro =SourceLocation())
- : Stmt(NullStmtClass), SemiLoc(L), LeadingEmptyMacro(LeadingEmptyMacro) {}
+ NullStmt(SourceLocation L, bool hasLeadingEmptyMacro = false)
+ : Stmt(NullStmtClass), SemiLoc(L),
+ HasLeadingEmptyMacro(hasLeadingEmptyMacro) {}
/// \brief Build an empty null statement.
- explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty) { }
+ explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty),
+ HasLeadingEmptyMacro(false) { }
SourceLocation getSemiLoc() const { return SemiLoc; }
void setSemiLoc(SourceLocation L) { SemiLoc = L; }
- bool hasLeadingEmptyMacro() const { return LeadingEmptyMacro.isValid(); }
- SourceLocation getLeadingEmptyMacroLoc() const { return LeadingEmptyMacro; }
+ bool hasLeadingEmptyMacro() const { return HasLeadingEmptyMacro; }
SourceRange getSourceRange() const { return SourceRange(SemiLoc); }
@@ -525,6 +531,10 @@ public:
child_range children() {
return child_range(&Body[0], &Body[0]+CompoundStmtBits.NumStmts);
}
+
+ const_child_range children() const {
+ return child_range(&Body[0], &Body[0]+CompoundStmtBits.NumStmts);
+ }
};
// SwitchCase is the base class for CaseStmt and DefaultStmt,
@@ -1308,7 +1318,7 @@ public:
/// true, otherwise return false. This handles canonicalization and
/// translation of strings from GCC syntax to LLVM IR syntax, and handles
//// flattening of named references like %[foo] to Operand AsmStringPiece's.
- unsigned AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece> &Pieces,
+ unsigned AnalyzeAsmString(SmallVectorImpl<AsmStringPiece> &Pieces,
ASTContext &C, unsigned &DiagOffs) const;
@@ -1320,17 +1330,17 @@ public:
return Names[i];
}
- llvm::StringRef getOutputName(unsigned i) const {
+ StringRef getOutputName(unsigned i) const {
if (IdentifierInfo *II = getOutputIdentifier(i))
return II->getName();
- return llvm::StringRef();
+ return StringRef();
}
/// getOutputConstraint - Return the constraint string for the specified
/// output operand. All output constraints are known to be non-empty (either
/// '=' or '+').
- llvm::StringRef getOutputConstraint(unsigned i) const;
+ StringRef getOutputConstraint(unsigned i) const;
const StringLiteral *getOutputConstraintLiteral(unsigned i) const {
return Constraints[i];
@@ -1364,16 +1374,16 @@ public:
return Names[i + NumOutputs];
}
- llvm::StringRef getInputName(unsigned i) const {
+ StringRef getInputName(unsigned i) const {
if (IdentifierInfo *II = getInputIdentifier(i))
return II->getName();
- return llvm::StringRef();
+ return StringRef();
}
/// getInputConstraint - Return the specified input constraint. Unlike output
/// constraints, these can be empty.
- llvm::StringRef getInputConstraint(unsigned i) const;
+ StringRef getInputConstraint(unsigned i) const;
const StringLiteral *getInputConstraintLiteral(unsigned i) const {
return Constraints[i + NumOutputs];
@@ -1403,7 +1413,7 @@ public:
/// getNamedOperand - Given a symbolic operand reference like %[foo],
/// translate this into a numeric value needed to reference the same operand.
/// This returns -1 if the operand name is invalid.
- int getNamedOperand(llvm::StringRef SymbolicName) const;
+ int getNamedOperand(StringRef SymbolicName) const;
unsigned getNumClobbers() const { return NumClobbers; }
StringLiteral *getClobber(unsigned i) { return Clobbers[i]; }
diff --git a/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h
index 29d234754645..48a0123608c9 100644
--- a/include/clang/AST/StmtVisitor.h
+++ b/include/clang/AST/StmtVisitor.h
@@ -42,7 +42,7 @@ public:
// below.
if (PTR(BinaryOperator) BinOp = dyn_cast<BinaryOperator>(S)) {
switch (BinOp->getOpcode()) {
- default: assert(0 && "Unknown binary operator!");
+ default: llvm_unreachable("Unknown binary operator!");
case BO_PtrMemD: DISPATCH(BinPtrMemD, BinaryOperator);
case BO_PtrMemI: DISPATCH(BinPtrMemI, BinaryOperator);
case BO_Mul: DISPATCH(BinMul, BinaryOperator);
@@ -80,7 +80,7 @@ public:
}
} else if (PTR(UnaryOperator) UnOp = dyn_cast<UnaryOperator>(S)) {
switch (UnOp->getOpcode()) {
- default: assert(0 && "Unknown unary operator!");
+ default: llvm_unreachable("Unknown unary operator!");
case UO_PostInc: DISPATCH(UnaryPostInc, UnaryOperator);
case UO_PostDec: DISPATCH(UnaryPostDec, UnaryOperator);
case UO_PreInc: DISPATCH(UnaryPreInc, UnaryOperator);
@@ -99,7 +99,7 @@ public:
// Top switch stmt: dispatch to VisitFooStmt for each FooStmt.
switch (S->getStmtClass()) {
- default: assert(0 && "Unknown stmt kind!");
+ default: llvm_unreachable("Unknown stmt kind!");
#define ABSTRACT_STMT(STMT)
#define STMT(CLASS, PARENT) \
case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS);
diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h
index 1c693e00c8cc..371c27a0d2b2 100644
--- a/include/clang/AST/TemplateBase.h
+++ b/include/clang/AST/TemplateBase.h
@@ -23,7 +23,6 @@
namespace llvm {
class FoldingSetNodeID;
- class raw_ostream;
}
namespace clang {
@@ -354,7 +353,7 @@ public:
TemplateArgument getPackExpansionPattern() const;
/// \brief Print this template argument to the given output stream.
- void print(const PrintingPolicy &Policy, llvm::raw_ostream &Out) const;
+ void print(const PrintingPolicy &Policy, raw_ostream &Out) const;
/// \brief Used to insert TemplateArguments into FoldingSets.
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const;
@@ -515,10 +514,14 @@ public:
/// A convenient class for passing around template argument
/// information. Designed to be passed by reference.
class TemplateArgumentListInfo {
- llvm::SmallVector<TemplateArgumentLoc, 8> Arguments;
+ SmallVector<TemplateArgumentLoc, 8> Arguments;
SourceLocation LAngleLoc;
SourceLocation RAngleLoc;
+ // This can leak if used in an AST node, use ASTTemplateArgumentListInfo
+ // instead.
+ void* operator new(size_t bytes, ASTContext& C);
+
public:
TemplateArgumentListInfo() {}
@@ -547,6 +550,48 @@ public:
}
};
+/// \brief Represents an explicit template argument list in C++, e.g.,
+/// the "<int>" in "sort<int>".
+/// This is safe to be used inside an AST node, in contrast with
+/// TemplateArgumentListInfo.
+struct ASTTemplateArgumentListInfo {
+ /// \brief The source location of the left angle bracket ('<');
+ SourceLocation LAngleLoc;
+
+ /// \brief The source location of the right angle bracket ('>');
+ SourceLocation RAngleLoc;
+
+ /// \brief The number of template arguments in TemplateArgs.
+ /// The actual template arguments (if any) are stored after the
+ /// ExplicitTemplateArgumentList structure.
+ unsigned NumTemplateArgs;
+
+ /// \brief Retrieve the template arguments
+ TemplateArgumentLoc *getTemplateArgs() {
+ return reinterpret_cast<TemplateArgumentLoc *> (this + 1);
+ }
+
+ /// \brief Retrieve the template arguments
+ const TemplateArgumentLoc *getTemplateArgs() const {
+ return reinterpret_cast<const TemplateArgumentLoc *> (this + 1);
+ }
+
+ const TemplateArgumentLoc &operator[](unsigned I) const {
+ return getTemplateArgs()[I];
+ }
+
+ static const ASTTemplateArgumentListInfo *Create(ASTContext &C,
+ const TemplateArgumentListInfo &List);
+
+ void initializeFrom(const TemplateArgumentListInfo &List);
+ void initializeFrom(const TemplateArgumentListInfo &List,
+ bool &Dependent, bool &InstantiationDependent,
+ bool &ContainsUnexpandedParameterPack);
+ void copyInto(TemplateArgumentListInfo &List) const;
+ static std::size_t sizeFor(unsigned NumTemplateArgs);
+ static std::size_t sizeFor(const TemplateArgumentListInfo &List);
+};
+
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
const TemplateArgument &Arg);
diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h
index a180f587eddd..7dc75b19257c 100644
--- a/include/clang/AST/TemplateName.h
+++ b/include/clang/AST/TemplateName.h
@@ -14,14 +14,11 @@
#ifndef LLVM_CLANG_AST_TEMPLATENAME_H
#define LLVM_CLANG_AST_TEMPLATENAME_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerUnion.h"
#include "clang/Basic/OperatorKinds.h"
-namespace llvm {
- class raw_ostream;
-}
-
namespace clang {
class ASTContext;
@@ -308,7 +305,7 @@ public:
/// \param SuppressNNS if true, don't print the
/// nested-name-specifier that precedes the template name (if it has
/// one).
- void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
+ void print(raw_ostream &OS, const PrintingPolicy &Policy,
bool SuppressNNS = false) const;
/// \brief Debugging aid that dumps the template name to standard
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index ef0dbdae037c..dd9aa56ed197 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -22,19 +22,15 @@
#include "clang/Basic/Visibility.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TemplateName.h"
-#include "llvm/Support/Casting.h"
#include "llvm/Support/type_traits.h"
+#include "llvm/Support/ErrorHandling.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 "clang/Basic/LLVM.h"
-using llvm::isa;
-using llvm::cast;
-using llvm::cast_or_null;
-using llvm::dyn_cast;
-using llvm::dyn_cast_or_null;
namespace clang {
enum {
TypeAlignmentInBits = 4,
@@ -508,6 +504,9 @@ public:
const Type *getTypePtrOrNull() const;
+ /// Retrieves a pointer to the name of the base type.
+ const IdentifierInfo *getBaseTypeIdentifier() const;
+
/// Divides a QualType into its unqualified type and a set of local
/// qualifiers.
SplitQualType split() const;
@@ -868,8 +867,9 @@ public:
/// type other than void.
bool isCForbiddenLValueType() const;
- /// \brief Determine whether this type has trivial copy-assignment semantics.
- bool hasTrivialCopyAssignment(ASTContext &Context) 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;
@@ -1362,6 +1362,7 @@ public:
/// various convenient purposes within Clang. All such types are
/// BuiltinTypes.
bool isPlaceholderType() const;
+ const BuiltinType *getAsPlaceholderType() const;
/// isSpecificPlaceholderType - Test for a specific placeholder type.
bool isSpecificPlaceholderType(unsigned K) const;
@@ -1373,6 +1374,8 @@ public:
bool isBooleanType() const;
bool isCharType() const;
bool isWideCharType() const;
+ bool isChar16Type() const;
+ bool isChar32Type() const;
bool isAnyCharacterType() const;
bool isIntegralType(ASTContext &Ctx) const;
@@ -1389,6 +1392,7 @@ public:
bool isComplexType() const; // C99 6.2.5p11 (complex)
bool isAnyComplexType() const; // C99 6.2.5p11 (complex) + Complex Int.
bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex)
+ bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half)
bool isRealType() const; // C99 6.2.5p17 (real floating + integer)
bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating)
bool isVoidType() const; // C99 6.2.5p19
@@ -1447,6 +1451,7 @@ public:
bool isCARCBridgableType() const;
bool isTemplateTypeParmType() const; // C++ template type parameter
bool isNullPtrType() const; // C++0x nullptr_t
+ bool isAtomicType() const; // C1X _Atomic()
/// Determines if this type, which must satisfy
/// isObjCLifetimeType(), is implicitly __unsafe_unretained rather
@@ -1457,7 +1462,9 @@ public:
Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const;
enum ScalarTypeKind {
- STK_Pointer,
+ STK_CPointer,
+ STK_BlockPointer,
+ STK_ObjCObjectPointer,
STK_MemberPointer,
STK_Bool,
STK_Integral,
@@ -1693,6 +1700,8 @@ public:
LongLong,
Int128, // __int128_t
+ Half, // This is the 'half' type in OpenCL,
+ // __fp16 in case of ARM NEON.
Float, Double, LongDouble,
NullPtr, // This is the type of C++0x 'nullptr'.
@@ -1755,7 +1764,7 @@ public:
}
Kind getKind() const { return static_cast<Kind>(BuiltinTypeBits.Kind); }
- const char *getName(const LangOptions &LO) const;
+ const char *getName(const PrintingPolicy &Policy) const;
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
@@ -1773,7 +1782,7 @@ public:
}
bool isFloatingPoint() const {
- return getKind() >= Float && getKind() <= LongDouble;
+ return getKind() >= Half && getKind() <= LongDouble;
}
/// Determines whether this type is a placeholder type, i.e. a type
@@ -2249,7 +2258,7 @@ public:
friend class StmtIteratorBase;
void Profile(llvm::FoldingSetNodeID &ID) {
- assert(0 && "Cannot unique VariableArrayTypes.");
+ llvm_unreachable("Cannot unique VariableArrayTypes.");
}
};
@@ -2635,7 +2644,7 @@ public:
return getResultType().getNonLValueExprType(Context);
}
- static llvm::StringRef getNameForCallConv(CallingConv CC);
+ static StringRef getNameForCallConv(CallingConv CC);
static bool classof(const Type *T) {
return T->getTypeClass() == FunctionNoProto ||
@@ -2696,8 +2705,17 @@ public:
unsigned char TypeQuals;
RefQualifierKind RefQualifier;
unsigned NumExceptions;
+
+ /// Exceptions - A variable size array after that holds the exception types.
const QualType *Exceptions;
+
+ /// NoexceptExpr - Instead of Exceptions, there may be a single Expr*
+ /// pointing to the expression in the noexcept() specifier.
Expr *NoexceptExpr;
+
+ /// ConsumedArgs - A variable size array, following Exceptions
+ /// and of length NumArgs, holding flags indicating which arguments
+ /// are consumed. This only appears if HasAnyConsumedArgs is true.
const bool *ConsumedArguments;
};
@@ -2728,19 +2746,6 @@ private:
/// HasAnyConsumedArgs - Whether this function has any consumed arguments.
unsigned HasAnyConsumedArgs : 1;
- /// ArgInfo - There is an variable size array after the class in memory that
- /// holds the argument types.
-
- /// Exceptions - There is another variable size array after ArgInfo that
- /// holds the exception types.
-
- /// NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing
- /// to the expression in the noexcept() specifier.
-
- /// ConsumedArgs - A variable size array, following Exceptions
- /// and of length NumArgs, holding flags indicating which arguments
- /// are consumed. This only appears if HasAnyConsumedArgs is true.
-
friend class ASTContext; // ASTContext creates these.
const bool *getConsumedArgsBuffer() const {
@@ -4348,6 +4353,37 @@ public:
static bool classof(const ObjCObjectPointerType *) { return true; }
};
+class AtomicType : public Type, public llvm::FoldingSetNode {
+ QualType ValueType;
+
+ AtomicType(QualType ValTy, QualType Canonical)
+ : Type(Atomic, Canonical, ValTy->isDependentType(),
+ ValTy->isInstantiationDependentType(),
+ ValTy->isVariablyModifiedType(),
+ ValTy->containsUnexpandedParameterPack()),
+ ValueType(ValTy) {}
+ friend class ASTContext; // ASTContext creates these.
+
+ public:
+ /// getValueType - Gets the type contained by this atomic type, i.e.
+ /// the type returned by performing an atomic load of this atomic type.
+ QualType getValueType() const { return ValueType; }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getValueType());
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType T) {
+ ID.AddPointer(T.getAsOpaquePtr());
+ }
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == Atomic;
+ }
+ static bool classof(const AtomicType *) { return true; }
+};
+
/// A qualifier set is used to build a set of qualifiers.
class QualifierCollector : public Qualifiers {
public:
@@ -4673,6 +4709,9 @@ inline bool Type::isObjCObjectOrInterfaceType() const {
return isa<ObjCInterfaceType>(CanonicalType) ||
isa<ObjCObjectType>(CanonicalType);
}
+inline bool Type::isAtomicType() const {
+ return isa<AtomicType>(CanonicalType);
+}
inline bool Type::isObjCQualifiedIdType() const {
if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>())
@@ -4714,11 +4753,18 @@ inline bool Type::isSpecificBuiltinType(unsigned K) const {
}
inline bool Type::isPlaceholderType() const {
- if (const BuiltinType *BT = getAs<BuiltinType>())
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(this))
return BT->isPlaceholderType();
return false;
}
+inline const BuiltinType *Type::getAsPlaceholderType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(this))
+ if (BT->isPlaceholderType())
+ return BT;
+ return 0;
+}
+
inline bool Type::isSpecificPlaceholderType(unsigned K) const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(this))
return (BT->getKind() == (BuiltinType::Kind) K);
@@ -4757,7 +4803,7 @@ inline const Type *Type::getBaseElementTypeUnsafe() const {
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
QualType T) {
DB.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()),
- Diagnostic::ak_qualtype);
+ DiagnosticsEngine::ak_qualtype);
return DB;
}
@@ -4766,7 +4812,7 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
QualType T) {
PD.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()),
- Diagnostic::ak_qualtype);
+ DiagnosticsEngine::ak_qualtype);
return PD;
}
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index f5669f7fc05a..20acadab7cf7 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -538,6 +538,10 @@ class InjectedClassNameTypeLoc :
public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
InjectedClassNameTypeLoc,
InjectedClassNameType> {
+public:
+ CXXRecordDecl *getDecl() const {
+ return getTypePtr()->getDecl();
+ }
};
/// \brief Wrapper for source info for unresolved typename using decls.
@@ -561,6 +565,12 @@ class TagTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
TagType> {
public:
TagDecl *getDecl() const { return getTypePtr()->getDecl(); }
+
+ /// \brief True if the tag was defined in this type specifier.
+ bool isDefinition() const {
+ return getDecl()->isCompleteDefinition() &&
+ (getNameLoc().isInvalid() || getNameLoc() == getDecl()->getLocation());
+ }
};
/// \brief Wrapper for source info for record types.
@@ -1408,6 +1418,8 @@ public:
class DecltypeTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
DecltypeTypeLoc,
DecltypeType> {
+public:
+ Expr *getUnderlyingExpr() const { return getTypePtr()->getUnderlyingExpr(); }
};
struct UnaryTransformTypeLocInfo {
@@ -1718,6 +1730,62 @@ public:
}
};
+struct AtomicTypeLocInfo {
+ SourceLocation KWLoc, LParenLoc, RParenLoc;
+};
+
+class AtomicTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, AtomicTypeLoc,
+ AtomicType, AtomicTypeLocInfo> {
+public:
+ TypeLoc getValueLoc() const {
+ return this->getInnerTypeLoc();
+ }
+
+ SourceRange getLocalSourceRange() const {
+ return SourceRange(getKWLoc(), getRParenLoc());
+ }
+
+ SourceLocation getKWLoc() const {
+ return this->getLocalData()->KWLoc;
+ }
+ void setKWLoc(SourceLocation Loc) {
+ this->getLocalData()->KWLoc = Loc;
+ }
+
+ SourceLocation getLParenLoc() const {
+ return this->getLocalData()->LParenLoc;
+ }
+ void setLParenLoc(SourceLocation Loc) {
+ this->getLocalData()->LParenLoc = Loc;
+ }
+
+ SourceLocation getRParenLoc() const {
+ return this->getLocalData()->RParenLoc;
+ }
+ void setRParenLoc(SourceLocation Loc) {
+ this->getLocalData()->RParenLoc = Loc;
+ }
+
+ SourceRange getParensRange() const {
+ return SourceRange(getLParenLoc(), getRParenLoc());
+ }
+ void setParensRange(SourceRange Range) {
+ setLParenLoc(Range.getBegin());
+ setRParenLoc(Range.getEnd());
+ }
+
+ void initializeLocal(ASTContext &Context, SourceLocation Loc) {
+ setKWLoc(Loc);
+ setLParenLoc(Loc);
+ setRParenLoc(Loc);
+ }
+
+ QualType getInnerType() const {
+ return this->getTypePtr()->getValueType();
+ }
+};
+
+
}
#endif
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
index 0792d0d9b30d..d5c485f8a3b9 100644
--- a/include/clang/AST/TypeNodes.def
+++ b/include/clang/AST/TypeNodes.def
@@ -102,9 +102,10 @@ DEPENDENT_TYPE(PackExpansion, Type)
TYPE(ObjCObject, Type)
TYPE(ObjCInterface, ObjCObjectType)
TYPE(ObjCObjectPointer, Type)
+TYPE(Atomic, Type)
#ifdef LAST_TYPE
-LAST_TYPE(ObjCObjectPointer)
+LAST_TYPE(Atomic)
#undef LAST_TYPE
#endif
diff --git a/include/clang/AST/TypeVisitor.h b/include/clang/AST/TypeVisitor.h
index c52926b1fc31..9eebc4b9ea07 100644
--- a/include/clang/AST/TypeVisitor.h
+++ b/include/clang/AST/TypeVisitor.h
@@ -28,7 +28,7 @@ public:
RetTy Visit(const Type *T) {
// Top switch stmt: dispatch to VisitFooType for each FooType.
switch (T->getTypeClass()) {
- default: assert(0 && "Unknown type class!");
+ default: llvm_unreachable("Unknown type class!");
#define ABSTRACT_TYPE(CLASS, PARENT)
#define TYPE(CLASS, PARENT) case Type::CLASS: DISPATCH(CLASS##Type);
#include "clang/AST/TypeNodes.def"
diff --git a/include/clang/AST/UnresolvedSet.h b/include/clang/AST/UnresolvedSet.h
index a548b0b704d1..0918dc44aa73 100644
--- a/include/clang/AST/UnresolvedSet.h
+++ b/include/clang/AST/UnresolvedSet.h
@@ -25,7 +25,7 @@ namespace clang {
/// non-const iterator.
class UnresolvedSetIterator {
private:
- typedef llvm::SmallVectorImpl<DeclAccessPair> DeclsTy;
+ typedef SmallVectorImpl<DeclAccessPair> DeclsTy;
typedef DeclsTy::iterator IteratorTy;
IteratorTy ir;
@@ -177,7 +177,7 @@ private:
/// A set of unresolved declarations
template <unsigned InlineCapacity> class UnresolvedSet :
public UnresolvedSetImpl {
- llvm::SmallVector<DeclAccessPair, InlineCapacity> Decls;
+ SmallVector<DeclAccessPair, InlineCapacity> Decls;
};
diff --git a/include/clang/AST/VTTBuilder.h b/include/clang/AST/VTTBuilder.h
new file mode 100644
index 000000000000..6756dd1e993b
--- /dev/null
+++ b/include/clang/AST/VTTBuilder.h
@@ -0,0 +1,176 @@
+//===--- VTTBuilder.h - C++ VTT layout builder --------------------*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code dealing with generation of the layout of virtual table
+// tables (VTT).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_VTTBUILDER_H
+#define LLVM_CLANG_AST_VTTBUILDER_H
+
+#include "clang/AST/BaseSubobject.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/GlobalDecl.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/Basic/ABI.h"
+#include "llvm/ADT/SetVector.h"
+#include <utility>
+
+namespace clang {
+
+class VTTVTable {
+ llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> BaseAndIsVirtual;
+ CharUnits BaseOffset;
+
+public:
+ VTTVTable() {}
+ VTTVTable(const CXXRecordDecl *Base, CharUnits BaseOffset, bool BaseIsVirtual)
+ : BaseAndIsVirtual(Base, BaseIsVirtual), BaseOffset(BaseOffset) {}
+ VTTVTable(BaseSubobject Base, bool BaseIsVirtual)
+ : BaseAndIsVirtual(Base.getBase(), BaseIsVirtual),
+ BaseOffset(Base.getBaseOffset()) {}
+
+ const CXXRecordDecl *getBase() const {
+ return BaseAndIsVirtual.getPointer();
+ }
+
+ CharUnits getBaseOffset() const {
+ return BaseOffset;
+ }
+
+ bool isVirtual() const {
+ return BaseAndIsVirtual.getInt();
+ }
+
+ BaseSubobject getBaseSubobject() const {
+ return BaseSubobject(getBase(), getBaseOffset());
+ }
+};
+
+struct VTTComponent {
+ uint64_t VTableIndex;
+ BaseSubobject VTableBase;
+
+ VTTComponent() {}
+ VTTComponent(uint64_t VTableIndex, BaseSubobject VTableBase)
+ : VTableIndex(VTableIndex), VTableBase(VTableBase) {}
+};
+
+/// VTT builder - Class for building VTT layout information.
+class VTTBuilder {
+
+ ASTContext &Ctx;
+
+ /// MostDerivedClass - The most derived class for which we're building this
+ /// vtable.
+ const CXXRecordDecl *MostDerivedClass;
+
+ typedef SmallVector<VTTVTable, 64> VTTVTablesVectorTy;
+
+ /// VTTVTables - The VTT vtables.
+ VTTVTablesVectorTy VTTVTables;
+
+ typedef SmallVector<VTTComponent, 64> VTTComponentsVectorTy;
+
+ /// VTTComponents - The VTT components.
+ VTTComponentsVectorTy VTTComponents;
+
+ /// MostDerivedClassLayout - the AST record layout of the most derived class.
+ const ASTRecordLayout &MostDerivedClassLayout;
+
+ typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
+
+ typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy;
+
+ /// SubVTTIndicies - The sub-VTT indices for the bases of the most derived
+ /// class.
+ llvm::DenseMap<BaseSubobject, uint64_t> SubVTTIndicies;
+
+ /// SecondaryVirtualPointerIndices - The secondary virtual pointer indices of
+ /// all subobjects of the most derived class.
+ llvm::DenseMap<BaseSubobject, uint64_t> SecondaryVirtualPointerIndices;
+
+ /// GenerateDefinition - Whether the VTT builder should generate LLVM IR for
+ /// the VTT.
+ 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);
+
+ /// LayoutSecondaryVTTs - Lay out the secondary VTTs of the given base
+ /// subobject.
+ void LayoutSecondaryVTTs(BaseSubobject Base);
+
+ /// LayoutSecondaryVirtualPointers - Lay out the secondary virtual pointers
+ /// for the given base subobject.
+ ///
+ /// \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,
+ const CXXRecordDecl *VTableClass,
+ VisitedVirtualBasesSetTy &VBases);
+
+ /// 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);
+
+ /// LayoutVirtualVTTs - Lay out the VTTs for the virtual base classes of the
+ /// given record decl.
+ void LayoutVirtualVTTs(const CXXRecordDecl *RD,
+ VisitedVirtualBasesSetTy &VBases);
+
+ /// LayoutVTT - Will lay out the VTT for the given subobject, including any
+ /// secondary VTTs, secondary virtual pointers and virtual VTTs.
+ void LayoutVTT(BaseSubobject Base, bool BaseIsVirtual);
+
+public:
+ VTTBuilder(ASTContext &Ctx, const CXXRecordDecl *MostDerivedClass,
+ bool GenerateDefinition);
+
+ // getVTTComponents - Returns a reference to the VTT components.
+ const VTTComponentsVectorTy &getVTTComponents() const {
+ return VTTComponents;
+ }
+
+ // getVTTVTables - Returns a reference to the VTT vtables.
+ const VTTVTablesVectorTy &getVTTVTables() const {
+ return VTTVTables;
+ }
+
+ /// getSubVTTIndicies - Returns a reference to the sub-VTT indices.
+ const llvm::DenseMap<BaseSubobject, uint64_t> &getSubVTTIndicies() const {
+ return SubVTTIndicies;
+ }
+
+ /// getSecondaryVirtualPointerIndices - Returns a reference to the secondary
+ /// virtual pointer indices.
+ const llvm::DenseMap<BaseSubobject, uint64_t> &
+ getSecondaryVirtualPointerIndices() const {
+ return SecondaryVirtualPointerIndices;
+ }
+
+};
+
+}
+
+#endif
diff --git a/include/clang/AST/VTableBuilder.h b/include/clang/AST/VTableBuilder.h
new file mode 100644
index 000000000000..59bab0382604
--- /dev/null
+++ b/include/clang/AST/VTableBuilder.h
@@ -0,0 +1,357 @@
+//===--- VTableBuilder.h - C++ vtable layout builder --------------*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code dealing with generation of the layout of virtual tables.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_VTABLEBUILDER_H
+#define LLVM_CLANG_AST_VTABLEBUILDER_H
+
+#include "clang/AST/BaseSubobject.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/GlobalDecl.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/Basic/ABI.h"
+#include "llvm/ADT/SetVector.h"
+#include <utility>
+
+namespace clang {
+ class CXXRecordDecl;
+
+/// VTableComponent - Represents a single component in a vtable.
+class VTableComponent {
+public:
+ enum Kind {
+ CK_VCallOffset,
+ CK_VBaseOffset,
+ CK_OffsetToTop,
+ CK_RTTI,
+ CK_FunctionPointer,
+
+ /// CK_CompleteDtorPointer - A pointer to the complete destructor.
+ CK_CompleteDtorPointer,
+
+ /// CK_DeletingDtorPointer - A pointer to the deleting destructor.
+ CK_DeletingDtorPointer,
+
+ /// CK_UnusedFunctionPointer - In some cases, a vtable function pointer
+ /// will end up never being called. Such vtable function pointers are
+ /// represented as a CK_UnusedFunctionPointer.
+ CK_UnusedFunctionPointer
+ };
+
+ VTableComponent() { }
+
+ static VTableComponent MakeVCallOffset(CharUnits Offset) {
+ return VTableComponent(CK_VCallOffset, Offset);
+ }
+
+ static VTableComponent MakeVBaseOffset(CharUnits Offset) {
+ return VTableComponent(CK_VBaseOffset, Offset);
+ }
+
+ static VTableComponent MakeOffsetToTop(CharUnits Offset) {
+ return VTableComponent(CK_OffsetToTop, Offset);
+ }
+
+ static VTableComponent MakeRTTI(const CXXRecordDecl *RD) {
+ return VTableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD));
+ }
+
+ static VTableComponent MakeFunction(const CXXMethodDecl *MD) {
+ assert(!isa<CXXDestructorDecl>(MD) &&
+ "Don't use MakeFunction with destructors!");
+
+ return VTableComponent(CK_FunctionPointer,
+ reinterpret_cast<uintptr_t>(MD));
+ }
+
+ static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) {
+ return VTableComponent(CK_CompleteDtorPointer,
+ reinterpret_cast<uintptr_t>(DD));
+ }
+
+ static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) {
+ return VTableComponent(CK_DeletingDtorPointer,
+ reinterpret_cast<uintptr_t>(DD));
+ }
+
+ static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) {
+ assert(!isa<CXXDestructorDecl>(MD) &&
+ "Don't use MakeUnusedFunction with destructors!");
+ return VTableComponent(CK_UnusedFunctionPointer,
+ reinterpret_cast<uintptr_t>(MD));
+ }
+
+ static VTableComponent getFromOpaqueInteger(uint64_t I) {
+ return VTableComponent(I);
+ }
+
+ /// getKind - Get the kind of this vtable component.
+ Kind getKind() const {
+ return (Kind)(Value & 0x7);
+ }
+
+ CharUnits getVCallOffset() const {
+ assert(getKind() == CK_VCallOffset && "Invalid component kind!");
+
+ return getOffset();
+ }
+
+ CharUnits getVBaseOffset() const {
+ assert(getKind() == CK_VBaseOffset && "Invalid component kind!");
+
+ return getOffset();
+ }
+
+ CharUnits getOffsetToTop() const {
+ assert(getKind() == CK_OffsetToTop && "Invalid component kind!");
+
+ return getOffset();
+ }
+
+ const CXXRecordDecl *getRTTIDecl() const {
+ assert(getKind() == CK_RTTI && "Invalid component kind!");
+
+ return reinterpret_cast<CXXRecordDecl *>(getPointer());
+ }
+
+ const CXXMethodDecl *getFunctionDecl() const {
+ assert(getKind() == CK_FunctionPointer);
+
+ return reinterpret_cast<CXXMethodDecl *>(getPointer());
+ }
+
+ const CXXDestructorDecl *getDestructorDecl() const {
+ assert((getKind() == CK_CompleteDtorPointer ||
+ getKind() == CK_DeletingDtorPointer) && "Invalid component kind!");
+
+ return reinterpret_cast<CXXDestructorDecl *>(getPointer());
+ }
+
+ const CXXMethodDecl *getUnusedFunctionDecl() const {
+ assert(getKind() == CK_UnusedFunctionPointer);
+
+ return reinterpret_cast<CXXMethodDecl *>(getPointer());
+ }
+
+private:
+ VTableComponent(Kind ComponentKind, CharUnits Offset) {
+ assert((ComponentKind == CK_VCallOffset ||
+ ComponentKind == CK_VBaseOffset ||
+ ComponentKind == CK_OffsetToTop) && "Invalid component kind!");
+ assert(Offset.getQuantity() <= ((1LL << 56) - 1) && "Offset is too big!");
+
+ Value = ((Offset.getQuantity() << 3) | ComponentKind);
+ }
+
+ VTableComponent(Kind ComponentKind, uintptr_t Ptr) {
+ assert((ComponentKind == CK_RTTI ||
+ ComponentKind == CK_FunctionPointer ||
+ ComponentKind == CK_CompleteDtorPointer ||
+ ComponentKind == CK_DeletingDtorPointer ||
+ ComponentKind == CK_UnusedFunctionPointer) &&
+ "Invalid component kind!");
+
+ assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!");
+
+ Value = Ptr | ComponentKind;
+ }
+
+ CharUnits getOffset() const {
+ assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset ||
+ getKind() == CK_OffsetToTop) && "Invalid component kind!");
+
+ return CharUnits::fromQuantity(Value >> 3);
+ }
+
+ uintptr_t getPointer() const {
+ assert((getKind() == CK_RTTI ||
+ getKind() == CK_FunctionPointer ||
+ getKind() == CK_CompleteDtorPointer ||
+ getKind() == CK_DeletingDtorPointer ||
+ getKind() == CK_UnusedFunctionPointer) &&
+ "Invalid component kind!");
+
+ return static_cast<uintptr_t>(Value & ~7ULL);
+ }
+
+ explicit VTableComponent(uint64_t Value)
+ : Value(Value) { }
+
+ /// The kind is stored in the lower 3 bits of the value. For offsets, we
+ /// make use of the facts that classes can't be larger than 2^55 bytes,
+ /// so we store the offset in the lower part of the 61 bytes that remain.
+ /// (The reason that we're not simply using a PointerIntPair here is that we
+ /// need the offsets to be 64-bit, even when on a 32-bit machine).
+ int64_t Value;
+};
+
+class VTableLayout {
+public:
+ typedef std::pair<uint64_t, ThunkInfo> VTableThunkTy;
+ typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
+
+ typedef const VTableComponent *vtable_component_iterator;
+ typedef const VTableThunkTy *vtable_thunk_iterator;
+
+ typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy;
+private:
+ uint64_t NumVTableComponents;
+ VTableComponent *VTableComponents;
+
+ /// VTableThunks - Contains thunks needed by vtables.
+ uint64_t NumVTableThunks;
+ VTableThunkTy *VTableThunks;
+
+ /// Address points - Address points for all vtables.
+ AddressPointsMapTy AddressPoints;
+
+public:
+ VTableLayout(uint64_t NumVTableComponents,
+ const VTableComponent *VTableComponents,
+ uint64_t NumVTableThunks,
+ const VTableThunkTy *VTableThunks,
+ const AddressPointsMapTy &AddressPoints);
+ ~VTableLayout();
+
+ uint64_t getNumVTableComponents() const {
+ return NumVTableComponents;
+ }
+
+ vtable_component_iterator vtable_component_begin() const {
+ return VTableComponents;
+ }
+
+ vtable_component_iterator vtable_component_end() const {
+ return VTableComponents+NumVTableComponents;
+ }
+
+ uint64_t getNumVTableThunks() const {
+ return NumVTableThunks;
+ }
+
+ vtable_thunk_iterator vtable_thunk_begin() const {
+ return VTableThunks;
+ }
+
+ vtable_thunk_iterator vtable_thunk_end() const {
+ return VTableThunks+NumVTableThunks;
+ }
+
+ uint64_t getAddressPoint(BaseSubobject Base) const {
+ assert(AddressPoints.count(Base) &&
+ "Did not find address point!");
+
+ uint64_t AddressPoint = AddressPoints.lookup(Base);
+ assert(AddressPoint && "Address point must not be zero!");
+
+ return AddressPoint;
+ }
+
+ const AddressPointsMapTy &getAddressPoints() const {
+ return AddressPoints;
+ }
+};
+
+class VTableContext {
+ ASTContext &Context;
+
+public:
+ typedef SmallVector<std::pair<uint64_t, ThunkInfo>, 1>
+ VTableThunksTy;
+ typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
+
+private:
+ /// 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;
+ MethodVTableIndicesTy MethodVTableIndices;
+
+ typedef llvm::DenseMap<const CXXRecordDecl *, const VTableLayout *>
+ VTableLayoutMapTy;
+ VTableLayoutMapTy VTableLayouts;
+
+ /// NumVirtualFunctionPointers - Contains the number of virtual function
+ /// pointers in the vtable for a given record decl.
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers;
+
+ typedef std::pair<const CXXRecordDecl *,
+ const CXXRecordDecl *> ClassPairTy;
+
+ /// VirtualBaseClassOffsetOffsets - Contains the vtable offset (relative to
+ /// the address point) in chars where the offsets for virtual bases of a class
+ /// are stored.
+ typedef llvm::DenseMap<ClassPairTy, CharUnits>
+ VirtualBaseClassOffsetOffsetsMapTy;
+ VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets;
+
+ typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
+
+ /// Thunks - Contains all thunks that a given method decl will need.
+ ThunksMapTy Thunks;
+
+ void ComputeMethodVTableIndices(const CXXRecordDecl *RD);
+
+ /// ComputeVTableRelatedInformation - Compute and store all vtable related
+ /// information (vtable layout, vbase offset offsets, thunks etc) for the
+ /// given record decl.
+ void ComputeVTableRelatedInformation(const CXXRecordDecl *RD);
+
+public:
+ VTableContext(ASTContext &Context) : Context(Context) {}
+ ~VTableContext();
+
+ const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) {
+ ComputeVTableRelatedInformation(RD);
+ assert(VTableLayouts.count(RD) && "No layout for this record decl!");
+
+ return *VTableLayouts[RD];
+ }
+
+ VTableLayout *
+ createConstructionVTableLayout(const CXXRecordDecl *MostDerivedClass,
+ CharUnits MostDerivedClassOffset,
+ bool MostDerivedClassIsVirtual,
+ const CXXRecordDecl *LayoutClass);
+
+ const ThunkInfoVectorTy *getThunkInfo(const CXXMethodDecl *MD) {
+ ComputeVTableRelatedInformation(MD->getParent());
+
+ ThunksMapTy::const_iterator I = Thunks.find(MD);
+ if (I == Thunks.end()) {
+ // We did not find a thunk for this method.
+ return 0;
+ }
+
+ return &I->second;
+ }
+
+ /// getNumVirtualFunctionPointers - Return the number of virtual function
+ /// pointers in the vtable for a given record decl.
+ uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD);
+
+ /// getMethodVTableIndex - Return the index (relative to the vtable address
+ /// point) where the function pointer for the given virtual function is
+ /// stored.
+ uint64_t getMethodVTableIndex(GlobalDecl GD);
+
+ /// getVirtualBaseOffsetOffset - Return the offset in chars (relative to the
+ /// vtable address point) where the offset of the virtual base that contains
+ /// the given base is stored, otherwise, if no virtual base contains the given
+ /// class, return 0. Base must be a virtual base class or an unambigious
+ /// base.
+ CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
+ const CXXRecordDecl *VBase);
+};
+
+}
+
+#endif
diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h
index 7cc76a8d471b..61f416447204 100644
--- a/include/clang/Analysis/Analyses/FormatString.h
+++ b/include/clang/Analysis/Analyses/FormatString.h
@@ -164,8 +164,8 @@ public:
return Position;
}
- llvm::StringRef getCharacters() const {
- return llvm::StringRef(getStart(), getLength());
+ StringRef getCharacters() const {
+ return StringRef(getStart(), getLength());
}
bool consumesDataArgument() const {
@@ -271,7 +271,7 @@ public:
ArgTypeResult getArgType(ASTContext &Ctx) const;
- void toString(llvm::raw_ostream &os) const;
+ void toString(raw_ostream &os) const;
bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
unsigned getPositionalArgIndex() const {
@@ -465,7 +465,7 @@ public:
/// was not successful.
bool fixType(QualType QT);
- void toString(llvm::raw_ostream &os) const;
+ void toString(raw_ostream &os) const;
// Validation methods - to check if any element results in undefined behavior
bool hasValidPlusPrefix() const;
diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h
index fbbd2613e7c2..302ae1c41f95 100644
--- a/include/clang/Analysis/Analyses/LiveVariables.h
+++ b/include/clang/Analysis/Analyses/LiveVariables.h
@@ -1,4 +1,4 @@
-//===- LiveVariables.h - Live Variable Analysis for Source CFGs -*- C++ --*-===//
+//===- LiveVariables.h - Live Variable Analysis for Source CFGs -*- C++ --*-//
//
// The LLVM Compiler Infrastructure
//
@@ -14,110 +14,105 @@
#ifndef LLVM_CLANG_LIVEVARIABLES_H
#define LLVM_CLANG_LIVEVARIABLES_H
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/AST/Decl.h"
-#include "clang/Analysis/Support/BlkExprDeclBitVector.h"
-#include "clang/Analysis/FlowSensitive/DataflowValues.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/ImmutableSet.h"
namespace clang {
+class CFG;
+class CFGBlock;
class Stmt;
class DeclRefExpr;
class SourceManager;
-class AnalysisContext;
-
-struct LiveVariables_ValueTypes {
-
- struct ObserverTy;
-
- // We keep dataflow state for declarations and block-level expressions;
- typedef StmtDeclBitVector_Types::ValTy ValTy;
-
- // We need to keep track of both declarations and CFGBlock-level expressions,
- // (so that we don't explore such expressions twice). We also want
- // to compute liveness information for block-level expressions, since these
- // act as "temporary" values.
-
- struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy {
- ObserverTy* Observer;
- ValTy AlwaysLive;
- AnalysisContext *AC;
- bool killAtAssign;
-
- AnalysisDataTy() : Observer(NULL), AC(NULL), killAtAssign(true) {}
+
+class LiveVariables : public ManagedAnalysis {
+public:
+ class LivenessValues {
+ public:
+
+ llvm::ImmutableSet<const Stmt *> liveStmts;
+ llvm::ImmutableSet<const VarDecl *> liveDecls;
+
+ bool equals(const LivenessValues &V) const;
+
+ LivenessValues()
+ : liveStmts(0), liveDecls(0) {}
+
+ LivenessValues(llvm::ImmutableSet<const Stmt *> LiveStmts,
+ llvm::ImmutableSet<const VarDecl *> LiveDecls)
+ : liveStmts(LiveStmts), liveDecls(LiveDecls) {}
+
+ ~LivenessValues() {}
+
+ bool isLive(const Stmt *S) const;
+ bool isLive(const VarDecl *D) const;
+
+ friend class LiveVariables;
};
-
- //===-----------------------------------------------------===//
- // ObserverTy - Observer for uninitialized values queries.
- //===-----------------------------------------------------===//
-
- struct ObserverTy {
- virtual ~ObserverTy() {}
-
- /// ObserveStmt - A callback invoked right before invoking the
+
+ struct Observer {
+ virtual ~Observer() {}
+
+ /// A callback invoked right before invoking the
/// liveness transfer function on the given statement.
- virtual void ObserveStmt(Stmt* S, const CFGBlock *currentBlock,
- const AnalysisDataTy& AD,
- const ValTy& V) {}
-
- virtual void ObserverKill(DeclRefExpr* DR) {}
- };
-};
-
-class LiveVariables : public DataflowValues<LiveVariables_ValueTypes,
- dataflow::backward_analysis_tag> {
-
-
-public:
- typedef LiveVariables_ValueTypes::ObserverTy ObserverTy;
-
- LiveVariables(AnalysisContext &AC, bool killAtAssign = true);
-
- /// IsLive - Return true if a variable is live at the end of a
+ virtual void observeStmt(const Stmt *S,
+ const CFGBlock *currentBlock,
+ const LivenessValues& V) {}
+
+ /// Called when the live variables analysis registers
+ /// that a variable is killed.
+ virtual void observerKill(const DeclRefExpr *DR) {}
+ };
+
+
+ virtual ~LiveVariables();
+
+ /// Compute the liveness information for a given CFG.
+ static LiveVariables *computeLiveness(AnalysisContext &analysisContext,
+ bool killAtAssign);
+
+ /// Return true if a variable is live at the end of a
/// specified block.
- bool isLive(const CFGBlock* B, const VarDecl* D) const;
-
- /// IsLive - Returns true if a variable is live at the beginning of the
+ bool isLive(const CFGBlock *B, const VarDecl *D);
+
+ /// Returns true if a variable is live at the beginning of the
/// the statement. This query only works if liveness information
/// has been recorded at the statement level (see runOnAllBlocks), and
/// only returns liveness information for block-level expressions.
- bool isLive(const Stmt* S, const VarDecl* D) const;
-
- /// IsLive - Returns true the block-level expression "value" is live
+ bool isLive(const Stmt *S, const VarDecl *D);
+
+ /// Returns true the block-level expression "value" is live
/// before the given block-level expression (see runOnAllBlocks).
- bool isLive(const Stmt* Loc, const Stmt* StmtVal) const;
-
- /// IsLive - Return true if a variable is live according to the
- /// provided livness bitvector.
- bool isLive(const ValTy& V, const VarDecl* D) const;
-
- /// dumpLiveness - Print to stderr the liveness information encoded
- /// by a specified bitvector.
- void dumpLiveness(const ValTy& V, const SourceManager& M) const;
-
- /// dumpBlockLiveness - Print to stderr the liveness information
- /// associated with each basic block.
- void dumpBlockLiveness(const SourceManager& M) const;
-
- /// getNumDecls - Return the number of variables (declarations) that
- /// whose liveness status is being tracked by the dataflow
- /// analysis.
- unsigned getNumDecls() const { return getAnalysisData().getNumDecls(); }
-
- /// IntializeValues - This routine can perform extra initialization, but
- /// for LiveVariables this does nothing since all that logic is in
- /// the constructor.
- void InitializeValues(const CFG& cfg) {}
-
- void runOnCFG(CFG& cfg);
-
- /// runOnAllBlocks - Propagate the dataflow values once for each block,
- /// starting from the current dataflow values. 'recordStmtValues' indicates
- /// whether the method should store dataflow values per each individual
- /// block-level expression.
- void runOnAllBlocks(const CFG& cfg, ObserverTy* Obs,
- bool recordStmtValues=false);
+ bool isLive(const Stmt *Loc, const Stmt *StmtVal);
+
+ /// Print to stderr the liveness information associated with
+ /// each basic block.
+ void dumpBlockLiveness(const SourceManager& M);
+
+ void runOnAllBlocks(Observer &obs);
+
+ static LiveVariables *create(AnalysisContext &analysisContext) {
+ return computeLiveness(analysisContext, true);
+ }
+
+ static const void *getTag();
+
+private:
+ LiveVariables(void *impl);
+ void *impl;
};
-
+
+class RelaxedLiveVariables : public LiveVariables {
+public:
+ static LiveVariables *create(AnalysisContext &analysisContext) {
+ return computeLiveness(analysisContext, false);
+ }
+
+ static const void *getTag();
+};
+
} // end namespace clang
#endif
diff --git a/include/clang/Analysis/Analyses/ReachableCode.h b/include/clang/Analysis/Analyses/ReachableCode.h
index e0c84f97fd33..6cf7fa42ff45 100644
--- a/include/clang/Analysis/Analyses/ReachableCode.h
+++ b/include/clang/Analysis/Analyses/ReachableCode.h
@@ -45,7 +45,7 @@ public:
/// ScanReachableFromBlock - Mark all blocks reachable from Start.
/// Returns the total number of blocks that were marked reachable.
-unsigned ScanReachableFromBlock(const CFGBlock &Start,
+unsigned ScanReachableFromBlock(const CFGBlock *Start,
llvm::BitVector &Reachable);
void FindUnreachableCode(AnalysisContext &AC, Callback &CB);
diff --git a/include/clang/Analysis/Analyses/ThreadSafety.h b/include/clang/Analysis/Analyses/ThreadSafety.h
new file mode 100644
index 000000000000..a32505624a22
--- /dev/null
+++ b/include/clang/Analysis/Analyses/ThreadSafety.h
@@ -0,0 +1,153 @@
+//===- ThreadSafety.h ------------------------------------------*- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//
+// A intra-procedural analysis for thread safety (e.g. deadlocks and race
+// conditions), based off of an annotation system.
+//
+// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety for more
+// information.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_THREADSAFETY_H
+#define LLVM_CLANG_THREADSAFETY_H
+
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+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())
+};
+
+/// 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
+};
+
+/// 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
+};
+
+/// This enum distinguishes between different situations where we warn due to
+/// inconsistent locking.
+/// \enum SK_LockedSomeLoopIterations -- a mutex is locked for some but not all
+/// loop iterations.
+/// \enum SK_LockedSomePredecessors -- a mutex is locked in some but not all
+/// predecessors of a CFGBlock.
+/// \enum SK_LockedAtEndOfFunction -- a mutex is still locked at the end of a
+/// function.
+enum LockErrorKind {
+ LEK_LockedSomeLoopIterations,
+ LEK_LockedSomePredecessors,
+ LEK_LockedAtEndOfFunction
+};
+
+/// Handler class for thread safety warnings.
+class ThreadSafetyHandler {
+public:
+ typedef llvm::StringRef Name;
+ virtual ~ThreadSafetyHandler() = 0;
+
+ /// Warn about lock expressions which fail to resolve to lockable objects.
+ /// \param Loc -- the SourceLocation of the unresolved expression.
+ virtual void handleInvalidLockExp(SourceLocation Loc) {}
+
+ /// Warn about unlock function calls that do not have a prior matching lock
+ /// expression.
+ /// \param LockName -- A StringRef name for the lock expression, to be printed
+ /// in the error message.
+ /// \param Loc -- The SourceLocation of the Unlock
+ virtual void handleUnmatchedUnlock(Name LockName, SourceLocation Loc) {}
+
+ /// Warn about lock function calls for locks which are already held.
+ /// \param LockName -- A StringRef name for the lock expression, to be printed
+ /// in the error message.
+ /// \param Loc -- The location of the second lock expression.
+ virtual void handleDoubleLock(Name LockName, SourceLocation Loc) {}
+
+ /// Warn about situations where a mutex is sometimes held and sometimes not.
+ /// The three situations are:
+ /// 1. a mutex is locked on an "if" branch but not the "else" branch,
+ /// 2, or a mutex is only held at the start of some loop iterations,
+ /// 3. or when a mutex is locked but not unlocked inside a function.
+ /// \param LockName -- A StringRef name for the lock expression, to be printed
+ /// in the error message.
+ /// \param Loc -- The location of the lock expression where the mutex is locked
+ /// \param LEK -- which of the three above cases we should warn for
+ virtual void handleMutexHeldEndOfScope(Name LockName, SourceLocation Loc,
+ LockErrorKind LEK){}
+
+ /// Warn when a mutex is held exclusively and shared at the same point. For
+ /// example, if a mutex is locked exclusively during an if branch and shared
+ /// during the else branch.
+ /// \param LockName -- A StringRef name for the lock expression, to be printed
+ /// in the error message.
+ /// \param Loc1 -- The location of the first lock expression.
+ /// \param Loc2 -- The location of the second lock expression.
+ virtual void handleExclusiveAndShared(Name LockName, SourceLocation Loc1,
+ SourceLocation Loc2) {}
+
+ /// Warn when a protected operation occurs while no locks are held.
+ /// \param D -- The decl for the protected variable or function
+ /// \param POK -- The kind of protected operation (e.g. variable access)
+ /// \param AK -- The kind of access (i.e. read or write) that occurred
+ /// \param Loc -- The location of the protected operation.
+ virtual void handleNoMutexHeld(const NamedDecl *D, ProtectedOperationKind POK,
+ AccessKind AK, SourceLocation Loc) {}
+
+ /// Warn when a protected operation occurs while the specific mutex protecting
+ /// the operation is not locked.
+ /// \param LockName -- A StringRef name for the lock expression, to be printed
+ /// in the error message.
+ /// \param D -- The decl for the protected variable or function
+ /// \param POK -- The kind of protected operation (e.g. variable access)
+ /// \param AK -- The kind of access (i.e. read or write) that occurred
+ /// \param Loc -- The location of the protected operation.
+ virtual void handleMutexNotHeld(const NamedDecl *D,
+ ProtectedOperationKind POK, Name LockName,
+ LockKind LK, SourceLocation Loc) {}
+
+ /// Warn when a function is called while an excluded mutex is locked. For
+ /// example, the mutex may be locked inside the function.
+ /// \param FunName -- The name of the function
+ /// \param LockName -- A StringRef name for the lock expression, to be printed
+ /// in the error message.
+ /// \param Loc -- The location of the function call.
+ virtual void handleFunExcludesLock(Name FunName, Name LockName,
+ SourceLocation Loc) {}
+};
+
+/// \brief Check a function's CFG for thread-safety violations.
+///
+/// We traverse the blocks in the CFG, compute the set of mutexes that are held
+/// at the end of each block, and issue warnings for thread safety violations.
+/// Each block in the CFG is traversed exactly once.
+void runThreadSafetyAnalysis(AnalysisContext &AC, ThreadSafetyHandler &Handler);
+
+/// \brief Helper function that returns a LockKind required for the given level
+/// of access.
+LockKind getLockKindFromAccessKind(AccessKind AK);
+
+}} // end namespace clang::thread_safety
+#endif
diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h
index badb493a9df4..e2e4f35043ee 100644
--- a/include/clang/Analysis/Analyses/UninitializedValues.h
+++ b/include/clang/Analysis/Analyses/UninitializedValues.h
@@ -27,10 +27,16 @@ class UninitVariablesHandler {
public:
UninitVariablesHandler() {}
virtual ~UninitVariablesHandler();
-
+
+ /// Called when the uninitialized variable is used at the given expression.
virtual void handleUseOfUninitVariable(const Expr *ex,
const VarDecl *vd,
bool isAlwaysUninit) {}
+
+ /// 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) {}
};
struct UninitVariablesAnalysisStats {
diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h
index 6a1876e65900..3d0e88a51d8a 100644
--- a/include/clang/Analysis/AnalysisContext.h
+++ b/include/clang/Analysis/AnalysisContext.h
@@ -19,6 +19,7 @@
#include "clang/AST/Expr.h"
#include "clang/Analysis/CFG.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/DenseMap.h"
@@ -31,14 +32,35 @@ class Stmt;
class CFGReverseBlockReachabilityAnalysis;
class CFGStmtMap;
class LiveVariables;
+class ManagedAnalysis;
class ParentMap;
class PseudoConstantAnalysis;
class ImplicitParamDecl;
class LocationContextManager;
class StackFrameContext;
-
+
namespace idx { class TranslationUnit; }
+/// The base class of a hierarchy of objects representing analyses tied
+/// to AnalysisContext.
+class ManagedAnalysis {
+protected:
+ ManagedAnalysis() {}
+public:
+ virtual ~ManagedAnalysis();
+
+ // Subclasses need to implement:
+ //
+ // static const void *getTag();
+ //
+ // Which returns a fixed pointer address to distinguish classes of
+ // analysis objects. They also need to implement:
+ //
+ // static [Derived*] create(AnalysisContext &Ctx);
+ //
+ // which creates the analysis object given an AnalysisContext.
+};
+
/// AnalysisContext contains the context data for the function or method under
/// analysis.
class AnalysisContext {
@@ -54,7 +76,6 @@ class AnalysisContext {
CFG::BuildOptions::ForcedBlkExprs *forcedBlkExprs;
bool builtCFG, builtCompleteCFG;
- const bool useUnoptimizedCFG;
llvm::OwningPtr<LiveVariables> liveness;
llvm::OwningPtr<LiveVariables> relaxedLiveness;
@@ -67,12 +88,13 @@ class AnalysisContext {
// FIXME: remove.
llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars;
+ void *ManagedAnalyses;
+
public:
+ AnalysisContext(const Decl *d, idx::TranslationUnit *tu);
+
AnalysisContext(const Decl *d, idx::TranslationUnit *tu,
- bool useUnoptimizedCFG = false,
- bool addehedges = false,
- bool addImplicitDtors = false,
- bool addInitializers = false);
+ const CFG::BuildOptions &buildOptions);
~AnalysisContext();
@@ -81,13 +103,22 @@ public:
idx::TranslationUnit *getTranslationUnit() const { return TU; }
+ /// Return the build options used to construct the CFG.
+ CFG::BuildOptions &getCFGBuildOptions() {
+ return cfgBuildOptions;
+ }
+
+ const CFG::BuildOptions &getCFGBuildOptions() const {
+ return cfgBuildOptions;
+ }
+
/// getAddEHEdges - Return true iff we are adding exceptional edges from
/// callExprs. If this is false, then try/catch statements and blocks
/// reachable from them can appear to be dead in the CFG, analysis passes must
/// cope with that.
bool getAddEHEdges() const { return cfgBuildOptions.AddEHEdges; }
bool getUseUnoptimizedCFG() const {
- return cfgBuildOptions.PruneTriviallyFalseEdges;
+ return !cfgBuildOptions.PruneTriviallyFalseEdges;
}
bool getAddImplicitDtors() const { return cfgBuildOptions.AddImplicitDtors; }
bool getAddInitializers() const { return cfgBuildOptions.AddInitializers; }
@@ -95,7 +126,7 @@ public:
void registerForcedBlockExpression(const Stmt *stmt);
const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt);
- Stmt *getBody();
+ Stmt *getBody() const;
CFG *getCFG();
CFGStmtMap *getCFGStmtMap();
@@ -114,8 +145,6 @@ public:
ParentMap &getParentMap();
PseudoConstantAnalysis *getPseudoConstantAnalysis();
- LiveVariables *getLiveVariables();
- LiveVariables *getRelaxedLiveVariables();
typedef const VarDecl * const * referenced_decls_iterator;
@@ -125,29 +154,44 @@ public:
/// Return the ImplicitParamDecl* associated with 'self' if this
/// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise.
const ImplicitParamDecl *getSelfDecl() const;
+
+ /// Return the specified analysis object, lazily running the analysis if
+ /// necessary. Return NULL if the analysis could not run.
+ template <typename T>
+ T *getAnalysis() {
+ const void *tag = T::getTag();
+ ManagedAnalysis *&data = getAnalysisImpl(tag);
+ if (!data) {
+ data = T::create(*this);
+ }
+ return static_cast<T*>(data);
+ }
+private:
+ ManagedAnalysis *&getAnalysisImpl(const void* tag);
};
class AnalysisContextManager {
typedef llvm::DenseMap<const Decl*, AnalysisContext*> ContextMap;
ContextMap Contexts;
- bool UseUnoptimizedCFG;
- bool AddImplicitDtors;
- bool AddInitializers;
+ CFG::BuildOptions cfgBuildOptions;
public:
AnalysisContextManager(bool useUnoptimizedCFG = false,
- bool addImplicitDtors = false, bool addInitializers = false)
- : UseUnoptimizedCFG(useUnoptimizedCFG), AddImplicitDtors(addImplicitDtors),
- AddInitializers(addInitializers) {}
+ bool addImplicitDtors = false,
+ bool addInitializers = false);
~AnalysisContextManager();
AnalysisContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0);
- bool getUseUnoptimizedCFG() const { return UseUnoptimizedCFG; }
- bool getAddImplicitDtors() const { return AddImplicitDtors; }
- bool getAddInitializers() const { return AddInitializers; }
+ bool getUseUnoptimizedCFG() const {
+ return !cfgBuildOptions.PruneTriviallyFalseEdges;
+ }
+
+ CFG::BuildOptions &getCFGBuildOptions() {
+ return cfgBuildOptions;
+ }
- // Discard all previously created AnalysisContexts.
+ /// Discard all previously created AnalysisContexts.
void clear();
};
@@ -187,8 +231,9 @@ public:
CFG *getCFG() const { return getAnalysisContext()->getCFG(); }
- LiveVariables *getLiveVariables() const {
- return getAnalysisContext()->getLiveVariables();
+ template <typename T>
+ T *getAnalysis() const {
+ return getAnalysisContext()->getAnalysis<T>();
}
ParentMap &getParentMap() const {
@@ -212,7 +257,7 @@ public:
ContextKind ck,
AnalysisContext *ctx,
const LocationContext *parent,
- const void* data);
+ const void *data);
};
class StackFrameContext : public LocationContext {
@@ -251,7 +296,7 @@ public:
ID.AddInteger(idx);
}
- static bool classof(const LocationContext* Ctx) {
+ static bool classof(const LocationContext *Ctx) {
return Ctx->getKind() == StackFrame;
}
};
@@ -274,7 +319,7 @@ public:
ProfileCommon(ID, Scope, ctx, parent, s);
}
- static bool classof(const LocationContext* Ctx) {
+ static bool classof(const LocationContext *Ctx) {
return Ctx->getKind() == Scope;
}
};
@@ -302,7 +347,7 @@ public:
ProfileCommon(ID, Block, ctx, parent, bd);
}
- static bool classof(const LocationContext* Ctx) {
+ static bool classof(const LocationContext *Ctx) {
return Ctx->getKind() == Block;
}
};
diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h
index dbf4e4c9aefe..16d31b476423 100644
--- a/include/clang/Analysis/AnalysisDiagnostic.h
+++ b/include/clang/Analysis/AnalysisDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM,
+ SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM,
#define ANALYSISSTART
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#undef DIAG
diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h
index ca46459afd9a..f191c802818b 100644
--- a/include/clang/Analysis/CFG.h
+++ b/include/clang/Analysis/CFG.h
@@ -21,15 +21,13 @@
#include "llvm/Support/Casting.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/BitVector.h"
+#include "clang/AST/Stmt.h"
#include "clang/Analysis/Support/BumpVector.h"
#include "clang/Basic/SourceLocation.h"
#include <cassert>
#include <iterator>
-namespace llvm {
- class raw_ostream;
-}
-
namespace clang {
class CXXDestructorDecl;
class Decl;
@@ -98,7 +96,9 @@ class CFGStmt : public CFGElement {
public:
CFGStmt(Stmt *S) : CFGElement(Statement, S) {}
- Stmt *getStmt() const { return static_cast<Stmt *>(Data1.getPointer()); }
+ const Stmt *getStmt() const {
+ return static_cast<const Stmt *>(Data1.getPointer());
+ }
static bool classof(const CFGElement *E) {
return E->getKind() == Statement;
@@ -280,7 +280,7 @@ class CFGBlock {
void push_back(CFGElement e, BumpVectorContext &C) { Impl.push_back(e, C); }
reverse_iterator insert(reverse_iterator I, size_t Cnt, CFGElement E,
- BumpVectorContext& C) {
+ BumpVectorContext &C) {
return Impl.insert(I, Cnt, E, C);
}
@@ -333,10 +333,21 @@ class CFGBlock {
AdjacentBlocks Preds;
AdjacentBlocks Succs;
+ /// NoReturn - This bit is set when the basic block contains a function call
+ /// or implicit destructor that is attributed as 'noreturn'. In that case,
+ /// control cannot technically ever proceed past this block. All such blocks
+ /// will have a single immediate successor: the exit block. This allows them
+ /// to be easily reached from the exit block and using this bit quickly
+ /// recognized without scanning the contents of the block.
+ ///
+ /// Optimization Note: This bit could be profitably folded with Terminator's
+ /// storage if the memory usage of CFGBlock becomes an issue.
+ unsigned HasNoReturnElement : 1;
+
public:
explicit CFGBlock(unsigned blockid, BumpVectorContext &C)
: Elements(C), Label(NULL), Terminator(NULL), LoopTarget(NULL),
- BlockID(blockid), Preds(C, 1), Succs(C, 1) {}
+ BlockID(blockid), Preds(C, 1), Succs(C, 1), HasNoReturnElement(false) {}
~CFGBlock() {}
// Statement iterators
@@ -455,42 +466,45 @@ public:
// Manipulation of block contents
- void setTerminator(Stmt* Statement) { Terminator = Statement; }
- void setLabel(Stmt* Statement) { Label = Statement; }
+ void setTerminator(Stmt *Statement) { Terminator = Statement; }
+ void setLabel(Stmt *Statement) { Label = Statement; }
void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; }
+ void setHasNoReturnElement() { HasNoReturnElement = true; }
CFGTerminator getTerminator() { return Terminator; }
const CFGTerminator getTerminator() const { return Terminator; }
- Stmt* getTerminatorCondition();
+ Stmt *getTerminatorCondition();
- const Stmt* getTerminatorCondition() const {
+ const Stmt *getTerminatorCondition() const {
return const_cast<CFGBlock*>(this)->getTerminatorCondition();
}
const Stmt *getLoopTarget() const { return LoopTarget; }
- Stmt* getLabel() { return Label; }
- const Stmt* getLabel() const { return Label; }
+ Stmt *getLabel() { return Label; }
+ const Stmt *getLabel() const { return Label; }
+
+ bool hasNoReturnElement() const { return HasNoReturnElement; }
unsigned getBlockID() const { return BlockID; }
void dump(const CFG *cfg, const LangOptions &LO) const;
- void print(llvm::raw_ostream &OS, const CFG* cfg, const LangOptions &LO) const;
- void printTerminator(llvm::raw_ostream &OS, const LangOptions &LO) const;
+ void print(raw_ostream &OS, const CFG* cfg, const LangOptions &LO) const;
+ void printTerminator(raw_ostream &OS, const LangOptions &LO) const;
- void addSuccessor(CFGBlock* Block, BumpVectorContext &C) {
+ void addSuccessor(CFGBlock *Block, BumpVectorContext &C) {
if (Block)
Block->Preds.push_back(this, C);
Succs.push_back(Block, C);
}
- void appendStmt(Stmt* statement, BumpVectorContext &C) {
+ void appendStmt(Stmt *statement, BumpVectorContext &C) {
Elements.push_back(CFGStmt(statement), C);
}
void appendInitializer(CXXCtorInitializer *initializer,
- BumpVectorContext& C) {
+ BumpVectorContext &C) {
Elements.push_back(CFGInitializer(initializer), C);
}
@@ -506,14 +520,18 @@ public:
Elements.push_back(CFGTemporaryDtor(E), C);
}
+ void appendAutomaticObjDtor(VarDecl *VD, Stmt *S, BumpVectorContext &C) {
+ Elements.push_back(CFGAutomaticObjDtor(VD, S), C);
+ }
+
// Destructors must be inserted in reversed order. So insertion is in two
// steps. First we prepare space for some number of elements, then we insert
// the elements beginning at the last position in prepared space.
iterator beginAutomaticObjDtorsInsert(iterator I, size_t Cnt,
- BumpVectorContext& C) {
+ BumpVectorContext &C) {
return iterator(Elements.insert(I.base(), Cnt, CFGElement(), C));
}
- iterator insertAutomaticObjDtor(iterator I, VarDecl* VD, Stmt* S) {
+ iterator insertAutomaticObjDtor(iterator I, VarDecl *VD, Stmt *S) {
*I = CFGAutomaticObjDtor(VD, S);
return ++I;
}
@@ -533,30 +551,46 @@ public:
//===--------------------------------------------------------------------===//
class BuildOptions {
+ llvm::BitVector alwaysAddMask;
public:
typedef llvm::DenseMap<const Stmt *, const CFGBlock*> ForcedBlkExprs;
ForcedBlkExprs **forcedBlkExprs;
- bool PruneTriviallyFalseEdges:1;
- bool AddEHEdges:1;
- bool AddInitializers:1;
- bool AddImplicitDtors:1;
+ bool PruneTriviallyFalseEdges;
+ bool AddEHEdges;
+ bool AddInitializers;
+ bool AddImplicitDtors;
+
+ bool alwaysAdd(const Stmt *stmt) const {
+ return alwaysAddMask[stmt->getStmtClass()];
+ }
+
+ BuildOptions &setAlwaysAdd(Stmt::StmtClass stmtClass, bool val = true) {
+ alwaysAddMask[stmtClass] = val;
+ return *this;
+ }
+
+ BuildOptions &setAllAlwaysAdd() {
+ alwaysAddMask.set();
+ return *this;
+ }
BuildOptions()
- : forcedBlkExprs(0), PruneTriviallyFalseEdges(true)
- , AddEHEdges(false)
- , AddInitializers(false)
- , AddImplicitDtors(false) {}
+ : alwaysAddMask(Stmt::lastStmtConstant, false)
+ ,forcedBlkExprs(0), PruneTriviallyFalseEdges(true)
+ ,AddEHEdges(false)
+ ,AddInitializers(false)
+ ,AddImplicitDtors(false) {}
};
/// buildCFG - Builds a CFG from an AST. The responsibility to free the
/// constructed CFG belongs to the caller.
- static CFG* buildCFG(const Decl *D, Stmt* AST, ASTContext *C,
+ static CFG* buildCFG(const Decl *D, Stmt *AST, ASTContext *C,
const BuildOptions &BO);
/// createBlock - Create a new block in the CFG. The CFG owns the block;
/// the caller should not directly free it.
- CFGBlock* createBlock();
+ CFGBlock *createBlock();
/// setEntry - Set the entry block of the CFG. This is typically used
/// only during CFG construction. Most CFG clients expect that the
@@ -565,7 +599,7 @@ public:
/// setIndirectGotoBlock - Set the block used for indirect goto jumps.
/// This is typically used only during CFG construction.
- void setIndirectGotoBlock(CFGBlock* B) { IndirectGotoBlock = B; }
+ void setIndirectGotoBlock(CFGBlock *B) { IndirectGotoBlock = B; }
//===--------------------------------------------------------------------===//
// Block Iterators
@@ -577,8 +611,8 @@ public:
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
- CFGBlock& front() { return *Blocks.front(); }
- CFGBlock& back() { return *Blocks.back(); }
+ CFGBlock & front() { return *Blocks.front(); }
+ CFGBlock & back() { return *Blocks.back(); }
iterator begin() { return Blocks.begin(); }
iterator end() { return Blocks.end(); }
@@ -590,13 +624,25 @@ public:
const_reverse_iterator rbegin() const { return Blocks.rbegin(); }
const_reverse_iterator rend() const { return Blocks.rend(); }
- CFGBlock& getEntry() { return *Entry; }
- const CFGBlock& getEntry() const { return *Entry; }
- CFGBlock& getExit() { return *Exit; }
- const CFGBlock& getExit() const { return *Exit; }
+ CFGBlock & getEntry() { return *Entry; }
+ const CFGBlock & getEntry() const { return *Entry; }
+ CFGBlock & getExit() { return *Exit; }
+ const CFGBlock & getExit() const { return *Exit; }
- CFGBlock* getIndirectGotoBlock() { return IndirectGotoBlock; }
- const CFGBlock* getIndirectGotoBlock() const { return IndirectGotoBlock; }
+ CFGBlock * getIndirectGotoBlock() { return IndirectGotoBlock; }
+ const CFGBlock * getIndirectGotoBlock() const { return IndirectGotoBlock; }
+
+ typedef std::vector<const CFGBlock*>::const_iterator try_block_iterator;
+ try_block_iterator try_blocks_begin() const {
+ return TryDispatchBlocks.begin();
+ }
+ try_block_iterator try_blocks_end() const {
+ return TryDispatchBlocks.end();
+ }
+
+ void addTryDispatchBlock(const CFGBlock *block) {
+ TryDispatchBlocks.push_back(block);
+ }
//===--------------------------------------------------------------------===//
// Member templates useful for various batch operations over CFGs.
@@ -608,7 +654,7 @@ public:
for (CFGBlock::const_iterator BI=(*I)->begin(), BE=(*I)->end();
BI != BE; ++BI) {
if (const CFGStmt *stmt = BI->getAs<CFGStmt>())
- O(stmt->getStmt());
+ O(const_cast<Stmt*>(stmt->getStmt()));
}
}
@@ -624,11 +670,11 @@ public:
operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; }
};
- bool isBlkExpr(const Stmt* S) { return getBlkExprNum(S); }
+ bool isBlkExpr(const Stmt *S) { return getBlkExprNum(S); }
bool isBlkExpr(const Stmt *S) const {
return const_cast<CFG*>(this)->isBlkExpr(S);
}
- BlkExprNumTy getBlkExprNum(const Stmt* S);
+ BlkExprNumTy getBlkExprNum(const Stmt *S);
unsigned getNumBlkExprs();
/// getNumBlockIDs - Returns the total number of BlockIDs allocated (which
@@ -640,7 +686,7 @@ public:
//===--------------------------------------------------------------------===//
void viewCFG(const LangOptions &LO) const;
- void print(llvm::raw_ostream& OS, const LangOptions &LO) const;
+ void print(raw_ostream &OS, const LangOptions &LO) const;
void dump(const LangOptions &LO) const;
//===--------------------------------------------------------------------===//
@@ -661,8 +707,8 @@ public:
}
private:
- CFGBlock* Entry;
- CFGBlock* Exit;
+ CFGBlock *Entry;
+ CFGBlock *Exit;
CFGBlock* IndirectGotoBlock; // Special block to contain collective dispatch
// for indirect gotos
unsigned NumBlockIDs;
@@ -670,11 +716,15 @@ private:
// BlkExprMap - An opaque pointer to prevent inclusion of DenseMap.h.
// It represents a map from Expr* to integers to record the set of
// block-level expressions and their "statement number" in the CFG.
- void* BlkExprMap;
+ void * BlkExprMap;
BumpVectorContext BlkBVC;
CFGBlockListTy Blocks;
+
+ /// C++ 'try' statements are modeled with an indirect dispatch block.
+ /// This is the collection of such blocks present in the CFG.
+ std::vector<const CFGBlock *> TryDispatchBlocks;
};
} // end namespace clang
@@ -703,11 +753,11 @@ template <> struct simplify_type< ::clang::CFGTerminator> {
// Traits for: CFGBlock
-template <> struct GraphTraits< ::clang::CFGBlock* > {
+template <> struct GraphTraits< ::clang::CFGBlock *> {
typedef ::clang::CFGBlock NodeType;
typedef ::clang::CFGBlock::succ_iterator ChildIteratorType;
- static NodeType* getEntryNode(::clang::CFGBlock* BB)
+ static NodeType* getEntryNode(::clang::CFGBlock *BB)
{ return BB; }
static inline ChildIteratorType child_begin(NodeType* N)
@@ -717,11 +767,11 @@ template <> struct GraphTraits< ::clang::CFGBlock* > {
{ return N->succ_end(); }
};
-template <> struct GraphTraits< const ::clang::CFGBlock* > {
+template <> struct GraphTraits< const ::clang::CFGBlock *> {
typedef const ::clang::CFGBlock NodeType;
typedef ::clang::CFGBlock::const_succ_iterator ChildIteratorType;
- static NodeType* getEntryNode(const clang::CFGBlock* BB)
+ static NodeType* getEntryNode(const clang::CFGBlock *BB)
{ return BB; }
static inline ChildIteratorType child_begin(NodeType* N)
@@ -748,7 +798,7 @@ template <> struct GraphTraits<Inverse<const ::clang::CFGBlock*> > {
// Traits for: CFG
template <> struct GraphTraits< ::clang::CFG* >
- : public GraphTraits< ::clang::CFGBlock* > {
+ : public GraphTraits< ::clang::CFGBlock *> {
typedef ::clang::CFG::iterator nodes_iterator;
@@ -758,7 +808,7 @@ template <> struct GraphTraits< ::clang::CFG* >
};
template <> struct GraphTraits<const ::clang::CFG* >
- : public GraphTraits<const ::clang::CFGBlock* > {
+ : public GraphTraits<const ::clang::CFGBlock *> {
typedef ::clang::CFG::const_iterator nodes_iterator;
diff --git a/include/clang/Analysis/DomainSpecific/CocoaConventions.h b/include/clang/Analysis/DomainSpecific/CocoaConventions.h
index 5a4e06ff53e5..fa8afccfcd89 100644
--- a/include/clang/Analysis/DomainSpecific/CocoaConventions.h
+++ b/include/clang/Analysis/DomainSpecific/CocoaConventions.h
@@ -14,12 +14,13 @@
#ifndef LLVM_CLANG_ANALYSIS_DS_COCOA
#define LLVM_CLANG_ANALYSIS_DS_COCOA
+#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/StringRef.h"
-#include "clang/AST/Type.h"
namespace clang {
-
+class FunctionDecl;
class ObjCMethodDecl;
+class QualType;
namespace ento {
namespace cocoa {
@@ -33,8 +34,8 @@ namespace cocoa {
return deriveNamingConvention(S, MD) == CreateRule;
}
- bool isRefType(QualType RetTy, llvm::StringRef Prefix,
- llvm::StringRef Name = llvm::StringRef());
+ bool isRefType(QualType RetTy, StringRef Prefix,
+ StringRef Name = StringRef());
bool isCocoaObjectRef(QualType T);
@@ -43,7 +44,7 @@ namespace cocoa {
namespace coreFoundation {
bool isCFObjectRef(QualType T);
- bool followsCreateRule(llvm::StringRef functionName);
+ bool followsCreateRule(const FunctionDecl *FD);
}
}} // end: "clang:ento"
diff --git a/include/clang/Analysis/FlowSensitive/DataflowSolver.h b/include/clang/Analysis/FlowSensitive/DataflowSolver.h
index 9561b964b5f8..017da636ebf6 100644
--- a/include/clang/Analysis/FlowSensitive/DataflowSolver.h
+++ b/include/clang/Analysis/FlowSensitive/DataflowSolver.h
@@ -30,11 +30,11 @@ namespace clang {
class DataflowWorkListTy {
llvm::DenseMap<const CFGBlock*, unsigned char> BlockSet;
- llvm::SmallVector<const CFGBlock *, 10> BlockQueue;
+ SmallVector<const CFGBlock *, 10> BlockQueue;
public:
/// enqueue - Add a block to the worklist. Blocks already on the
/// worklist are not added a second time.
- void enqueue(const CFGBlock* B) {
+ void enqueue(const CFGBlock *B) {
unsigned char &x = BlockSet[B];
if (x == 1)
return;
@@ -43,7 +43,7 @@ public:
}
/// dequeue - Remove a block from the worklist.
- const CFGBlock* dequeue() {
+ const CFGBlock *dequeue() {
assert(!BlockQueue.empty());
const CFGBlock *B = BlockQueue.back();
BlockQueue.pop_back();
@@ -69,20 +69,20 @@ template <> struct ItrTraits<forward_analysis_tag> {
typedef CFGBlock::const_succ_iterator NextBItr;
typedef CFGBlock::const_iterator StmtItr;
- static PrevBItr PrevBegin(const CFGBlock* B) { return B->pred_begin(); }
- static PrevBItr PrevEnd(const CFGBlock* B) { return B->pred_end(); }
+ static PrevBItr PrevBegin(const CFGBlock *B) { return B->pred_begin(); }
+ static PrevBItr PrevEnd(const CFGBlock *B) { return B->pred_end(); }
- static NextBItr NextBegin(const CFGBlock* B) { return B->succ_begin(); }
- static NextBItr NextEnd(const CFGBlock* B) { return B->succ_end(); }
+ static NextBItr NextBegin(const CFGBlock *B) { return B->succ_begin(); }
+ static NextBItr NextEnd(const CFGBlock *B) { return B->succ_end(); }
- static StmtItr StmtBegin(const CFGBlock* B) { return B->begin(); }
- static StmtItr StmtEnd(const CFGBlock* B) { return B->end(); }
+ static StmtItr StmtBegin(const CFGBlock *B) { return B->begin(); }
+ static StmtItr StmtEnd(const CFGBlock *B) { return B->end(); }
- static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) {
+ static BlockEdge PrevEdge(const CFGBlock *B, const CFGBlock *Prev) {
return BlockEdge(Prev, B, 0);
}
- static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) {
+ static BlockEdge NextEdge(const CFGBlock *B, const CFGBlock *Next) {
return BlockEdge(B, Next, 0);
}
};
@@ -92,20 +92,20 @@ template <> struct ItrTraits<backward_analysis_tag> {
typedef CFGBlock::const_pred_iterator NextBItr;
typedef CFGBlock::const_reverse_iterator StmtItr;
- static PrevBItr PrevBegin(const CFGBlock* B) { return B->succ_begin(); }
- static PrevBItr PrevEnd(const CFGBlock* B) { return B->succ_end(); }
+ static PrevBItr PrevBegin(const CFGBlock *B) { return B->succ_begin(); }
+ static PrevBItr PrevEnd(const CFGBlock *B) { return B->succ_end(); }
- static NextBItr NextBegin(const CFGBlock* B) { return B->pred_begin(); }
- static NextBItr NextEnd(const CFGBlock* B) { return B->pred_end(); }
+ static NextBItr NextBegin(const CFGBlock *B) { return B->pred_begin(); }
+ static NextBItr NextEnd(const CFGBlock *B) { return B->pred_end(); }
- static StmtItr StmtBegin(const CFGBlock* B) { return B->rbegin(); }
- static StmtItr StmtEnd(const CFGBlock* B) { return B->rend(); }
+ static StmtItr StmtBegin(const CFGBlock *B) { return B->rbegin(); }
+ static StmtItr StmtEnd(const CFGBlock *B) { return B->rend(); }
- static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) {
+ static BlockEdge PrevEdge(const CFGBlock *B, const CFGBlock *Prev) {
return BlockEdge(B, Prev, 0);
}
- static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) {
+ static BlockEdge NextEdge(const CFGBlock *B, const CFGBlock *Next) {
return BlockEdge(Next, B, 0);
}
};
@@ -162,7 +162,7 @@ public:
/// dataflow values using runOnCFG, as runOnBlock is intended to
/// only be used for querying the dataflow values within a block
/// with and Observer object.
- void runOnBlock(const CFGBlock* B, bool recordStmtValues) {
+ void runOnBlock(const CFGBlock *B, bool recordStmtValues) {
BlockDataMapTy& M = D.getBlockDataMap();
typename BlockDataMapTy::iterator I = M.find(B);
@@ -172,13 +172,13 @@ public:
}
}
- void runOnBlock(const CFGBlock& B, bool recordStmtValues) {
+ void runOnBlock(const CFGBlock &B, bool recordStmtValues) {
runOnBlock(&B, recordStmtValues);
}
- void runOnBlock(CFG::iterator& I, bool recordStmtValues) {
+ void runOnBlock(CFG::iterator &I, bool recordStmtValues) {
runOnBlock(*I, recordStmtValues);
}
- void runOnBlock(CFG::const_iterator& I, bool recordStmtValues) {
+ void runOnBlock(CFG::const_iterator &I, bool recordStmtValues) {
runOnBlock(*I, recordStmtValues);
}
@@ -199,7 +199,7 @@ private:
EnqueueBlocksOnWorklist(cfg, AnalysisDirTag());
while (!WorkList.isEmpty()) {
- const CFGBlock* B = WorkList.dequeue();
+ const CFGBlock *B = WorkList.dequeue();
ProcessMerge(cfg, B);
ProcessBlock(B, recordStmtValues, AnalysisDirTag());
UpdateEdges(cfg, B, TF.getVal());
@@ -222,7 +222,7 @@ private:
WorkList.enqueue(&**I);
}
- void ProcessMerge(CFG& cfg, const CFGBlock* B) {
+ void ProcessMerge(CFG& cfg, const CFGBlock *B) {
ValTy& V = TF.getVal();
TF.SetTopValue(V);
@@ -270,7 +270,7 @@ private:
}
/// ProcessBlock - Process the transfer functions for a given block.
- void ProcessBlock(const CFGBlock* B, bool recordStmtValues,
+ void ProcessBlock(const CFGBlock *B, bool recordStmtValues,
dataflow::forward_analysis_tag) {
TF.setCurrentBlock(B);
@@ -284,7 +284,7 @@ private:
TF.VisitTerminator(const_cast<CFGBlock*>(B));
}
- void ProcessBlock(const CFGBlock* B, bool recordStmtValues,
+ void ProcessBlock(const CFGBlock *B, bool recordStmtValues,
dataflow::backward_analysis_tag) {
TF.setCurrentBlock(B);
@@ -298,12 +298,12 @@ private:
}
}
- void ProcessStmt(const Stmt* S, bool record, dataflow::forward_analysis_tag) {
+ void ProcessStmt(const Stmt *S, bool record, dataflow::forward_analysis_tag) {
if (record) D.getStmtDataMap()[S] = TF.getVal();
TF.BlockStmt_Visit(const_cast<Stmt*>(S));
}
- void ProcessStmt(const Stmt* S, bool record, dataflow::backward_analysis_tag){
+ void ProcessStmt(const Stmt *S, bool record, dataflow::backward_analysis_tag){
TF.BlockStmt_Visit(const_cast<Stmt*>(S));
if (record) D.getStmtDataMap()[S] = TF.getVal();
}
@@ -312,14 +312,14 @@ private:
/// block, update the dataflow value associated with the block's
/// outgoing/incoming edges (depending on whether we do a
// forward/backward analysis respectively)
- void UpdateEdges(CFG& cfg, const CFGBlock* B, ValTy& V) {
+ void UpdateEdges(CFG& cfg, const CFGBlock *B, ValTy& V) {
for (NextBItr I=ItrTraits::NextBegin(B), E=ItrTraits::NextEnd(B); I!=E; ++I)
if (CFGBlock *NextBlk = *I)
UpdateEdgeValue(ItrTraits::NextEdge(B, NextBlk),V, NextBlk);
}
/// UpdateEdgeValue - Update the value associated with a given edge.
- void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock* TargetBlock) {
+ void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock *TargetBlock) {
EdgeDataMapTy& M = D.getEdgeDataMap();
typename EdgeDataMapTy::iterator I = M.find(E);
diff --git a/include/clang/Analysis/FlowSensitive/DataflowValues.h b/include/clang/Analysis/FlowSensitive/DataflowValues.h
index 7aa15c5b40ef..f86b2b0bfea1 100644
--- a/include/clang/Analysis/FlowSensitive/DataflowValues.h
+++ b/include/clang/Analysis/FlowSensitive/DataflowValues.h
@@ -84,13 +84,13 @@ public:
/// getEdgeData - Retrieves the dataflow values associated with a
/// CFG edge.
- ValTy& getEdgeData(const BlockEdge& E) {
+ ValTy& getEdgeData(const BlockEdge &E) {
typename EdgeDataMapTy::iterator I = EdgeDataMap.find(E);
assert (I != EdgeDataMap.end() && "No data associated with Edge.");
return I->second;
}
- const ValTy& getEdgeData(const BlockEdge& E) const {
+ const ValTy& getEdgeData(const BlockEdge &E) const {
return reinterpret_cast<DataflowValues*>(this)->getEdgeData(E);
}
@@ -98,13 +98,13 @@ public:
/// specified CFGBlock. If the dataflow analysis is a forward analysis,
/// this data is associated with the END of the block. If the analysis
/// is a backwards analysis, it is associated with the ENTRY of the block.
- ValTy& getBlockData(const CFGBlock* B) {
+ ValTy& getBlockData(const CFGBlock *B) {
typename BlockDataMapTy::iterator I = BlockDataMap.find(B);
assert (I != BlockDataMap.end() && "No data associated with block.");
return I->second;
}
- const ValTy& getBlockData(const CFGBlock* B) const {
+ const ValTy& getBlockData(const CFGBlock *B) const {
return const_cast<DataflowValues*>(this)->getBlockData(B);
}
@@ -114,14 +114,14 @@ public:
/// If the analysis is a backwards analysis, it is associated with
/// the point after a Stmt. This data is only computed for block-level
/// expressions, and only when requested when the analysis is executed.
- ValTy& getStmtData(const Stmt* S) {
+ ValTy& getStmtData(const Stmt *S) {
assert (StmtDataMap && "Dataflow values were not computed for statements.");
typename StmtDataMapTy::iterator I = StmtDataMap->find(S);
assert (I != StmtDataMap->end() && "No data associated with statement.");
return I->second;
}
- const ValTy& getStmtData(const Stmt* S) const {
+ const ValTy& getStmtData(const Stmt *S) const {
return const_cast<DataflowValues*>(this)->getStmtData(S);
}
diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h
index 07b4dea987de..7ec4ecd41b2b 100644
--- a/include/clang/Analysis/ProgramPoint.h
+++ b/include/clang/Analysis/ProgramPoint.h
@@ -21,15 +21,18 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/Support/Casting.h"
+#include "llvm/ADT/StringRef.h"
#include <cassert>
#include <utility>
+#include <string>
namespace clang {
-class LocationContext;
class AnalysisContext;
class FunctionDecl;
-
+class LocationContext;
+class ProgramPointTag;
+
class ProgramPoint {
public:
enum Kind { BlockEdgeKind,
@@ -42,7 +45,6 @@ public:
PreStoreKind,
PostStoreKind,
PostPurgeDeadSymbolsKind,
- PostStmtCustomKind,
PostConditionKind,
PostLValueKind,
PostInitializerKind,
@@ -58,25 +60,33 @@ private:
// The LocationContext could be NULL to allow ProgramPoint to be used in
// context insensitive analysis.
const LocationContext *L;
- const void *Tag;
+ const ProgramPointTag *Tag;
+ ProgramPoint();
+
protected:
- ProgramPoint(const void* P, Kind k, const LocationContext *l,
- const void *tag = 0)
+ ProgramPoint(const void *P, Kind k, const LocationContext *l,
+ const ProgramPointTag *tag = 0)
: Data(P, static_cast<const void*>(NULL)), K(k), L(l), Tag(tag) {}
- ProgramPoint(const void* P1, const void* P2, Kind k, const LocationContext *l,
- const void *tag = 0)
+ ProgramPoint(const void *P1, const void *P2, Kind k, const LocationContext *l,
+ const ProgramPointTag *tag = 0)
: Data(P1, P2), K(k), L(l), Tag(tag) {}
protected:
- const void* getData1() const { return Data.first; }
- const void* getData2() const { return Data.second; }
+ const void *getData1() const { return Data.first; }
+ const void *getData2() const { return Data.second; }
public:
+ /// Create a new ProgramPoint object that is the same as the original
+ /// except for using the specified tag value.
+ ProgramPoint withTag(const ProgramPointTag *tag) const {
+ return ProgramPoint(Data.first, Data.second, K, L, tag);
+ }
+
Kind getKind() const { return K; }
- const void *getTag() const { return Tag; }
+ const ProgramPointTag *getTag() const { return Tag; }
const LocationContext *getLocationContext() const { return L; }
@@ -93,7 +103,7 @@ public:
return K == RHS.K && Data == RHS.Data && L == RHS.L && Tag == RHS.Tag;
}
- bool operator!=(const ProgramPoint& RHS) const {
+ bool operator!=(const ProgramPoint &RHS) const {
return K != RHS.K || Data != RHS.Data || L != RHS.L || Tag != RHS.Tag;
}
@@ -104,29 +114,30 @@ public:
ID.AddPointer(L);
ID.AddPointer(Tag);
}
+
+ static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
+ const LocationContext *LC,
+ const ProgramPointTag *tag);
+
};
class BlockEntrance : public ProgramPoint {
public:
- BlockEntrance(const CFGBlock* B, const LocationContext *L,
- const void *tag = 0)
- : ProgramPoint(B, BlockEntranceKind, L, tag) {}
+ BlockEntrance(const CFGBlock *B, const LocationContext *L,
+ const ProgramPointTag *tag = 0)
+ : ProgramPoint(B, BlockEntranceKind, L, tag) {
+ assert(B && "BlockEntrance requires non-null block");
+ }
- const CFGBlock* getBlock() const {
+ const CFGBlock *getBlock() const {
return reinterpret_cast<const CFGBlock*>(getData1());
}
const CFGElement getFirstElement() const {
- const CFGBlock* B = getBlock();
+ const CFGBlock *B = getBlock();
return B->empty() ? CFGElement() : B->front();
}
- /// Create a new BlockEntrance object that is the same as the original
- /// except for using the specified tag value.
- BlockEntrance withTag(const void *tag) {
- return BlockEntrance(getBlock(), getLocationContext(), tag);
- }
-
static bool classof(const ProgramPoint* Location) {
return Location->getKind() == BlockEntranceKind;
}
@@ -134,14 +145,14 @@ public:
class BlockExit : public ProgramPoint {
public:
- BlockExit(const CFGBlock* B, const LocationContext *L)
+ BlockExit(const CFGBlock *B, const LocationContext *L)
: ProgramPoint(B, BlockExitKind, L) {}
- const CFGBlock* getBlock() const {
+ const CFGBlock *getBlock() const {
return reinterpret_cast<const CFGBlock*>(getData1());
}
- const Stmt* getTerminator() const {
+ const Stmt *getTerminator() const {
return getBlock()->getTerminator();
}
@@ -153,7 +164,7 @@ public:
class StmtPoint : public ProgramPoint {
public:
StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L,
- const void *tag)
+ const ProgramPointTag *tag)
: ProgramPoint(S, p2, k, L, tag) {}
const Stmt *getStmt() const { return (const Stmt*) getData1(); }
@@ -170,7 +181,7 @@ public:
class PreStmt : public StmtPoint {
public:
- PreStmt(const Stmt *S, const LocationContext *L, const void *tag,
+ PreStmt(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag,
const Stmt *SubStmt = 0)
: StmtPoint(S, SubStmt, PreStmtKind, L, tag) {}
@@ -183,16 +194,17 @@ public:
class PostStmt : public StmtPoint {
protected:
- PostStmt(const Stmt* S, const void* data, Kind k, const LocationContext *L,
- const void *tag =0)
+ PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L,
+ const ProgramPointTag *tag =0)
: StmtPoint(S, data, k, L, tag) {}
public:
- explicit PostStmt(const Stmt* S, Kind k,
- const LocationContext *L, const void *tag = 0)
+ explicit PostStmt(const Stmt *S, Kind k,
+ const LocationContext *L, const ProgramPointTag *tag = 0)
: StmtPoint(S, NULL, k, L, tag) {}
- explicit PostStmt(const Stmt* S, const LocationContext *L,const void *tag = 0)
+ explicit PostStmt(const Stmt *S, const LocationContext *L,
+ const ProgramPointTag *tag = 0)
: StmtPoint(S, NULL, PostStmtKind, L, tag) {}
static bool classof(const ProgramPoint* Location) {
@@ -201,31 +213,11 @@ public:
}
};
-class PostStmtCustom : public PostStmt {
-public:
- PostStmtCustom(const Stmt* S,
- const std::pair<const void*, const void*>* TaggedData,\
- const LocationContext *L)
- : PostStmt(S, TaggedData, PostStmtCustomKind, L) {}
-
- const std::pair<const void*, const void*>& getTaggedPair() const {
- return
- *reinterpret_cast<const std::pair<const void*, const void*>*>(getData2());
- }
-
- const void* getTag() const { return getTaggedPair().first; }
-
- const void* getTaggedData() const { return getTaggedPair().second; }
-
- static bool classof(const ProgramPoint* Location) {
- return Location->getKind() == PostStmtCustomKind;
- }
-};
-
// PostCondition represents the post program point of a branch condition.
class PostCondition : public PostStmt {
public:
- PostCondition(const Stmt* S, const LocationContext *L, const void *tag = 0)
+ PostCondition(const Stmt *S, const LocationContext *L,
+ const ProgramPointTag *tag = 0)
: PostStmt(S, PostConditionKind, L, tag) {}
static bool classof(const ProgramPoint* Location) {
@@ -236,7 +228,7 @@ public:
class LocationCheck : public StmtPoint {
protected:
LocationCheck(const Stmt *S, const LocationContext *L,
- ProgramPoint::Kind K, const void *tag)
+ ProgramPoint::Kind K, const ProgramPointTag *tag)
: StmtPoint(S, NULL, K, L, tag) {}
static bool classof(const ProgramPoint *location) {
@@ -247,7 +239,8 @@ protected:
class PreLoad : public LocationCheck {
public:
- PreLoad(const Stmt *S, const LocationContext *L, const void *tag = 0)
+ PreLoad(const Stmt *S, const LocationContext *L,
+ const ProgramPointTag *tag = 0)
: LocationCheck(S, L, PreLoadKind, tag) {}
static bool classof(const ProgramPoint *location) {
@@ -257,7 +250,8 @@ public:
class PreStore : public LocationCheck {
public:
- PreStore(const Stmt *S, const LocationContext *L, const void *tag = 0)
+ PreStore(const Stmt *S, const LocationContext *L,
+ const ProgramPointTag *tag = 0)
: LocationCheck(S, L, PreStoreKind, tag) {}
static bool classof(const ProgramPoint *location) {
@@ -267,7 +261,8 @@ public:
class PostLoad : public PostStmt {
public:
- PostLoad(const Stmt* S, const LocationContext *L, const void *tag = 0)
+ PostLoad(const Stmt *S, const LocationContext *L,
+ const ProgramPointTag *tag = 0)
: PostStmt(S, PostLoadKind, L, tag) {}
static bool classof(const ProgramPoint* Location) {
@@ -277,7 +272,8 @@ public:
class PostStore : public PostStmt {
public:
- PostStore(const Stmt* S, const LocationContext *L, const void *tag = 0)
+ PostStore(const Stmt *S, const LocationContext *L,
+ const ProgramPointTag *tag = 0)
: PostStmt(S, PostStoreKind, L, tag) {}
static bool classof(const ProgramPoint* Location) {
@@ -287,7 +283,8 @@ public:
class PostLValue : public PostStmt {
public:
- PostLValue(const Stmt* S, const LocationContext *L, const void *tag = 0)
+ PostLValue(const Stmt *S, const LocationContext *L,
+ const ProgramPointTag *tag = 0)
: PostStmt(S, PostLValueKind, L, tag) {}
static bool classof(const ProgramPoint* Location) {
@@ -297,8 +294,8 @@ public:
class PostPurgeDeadSymbols : public PostStmt {
public:
- PostPurgeDeadSymbols(const Stmt* S, const LocationContext *L,
- const void *tag = 0)
+ PostPurgeDeadSymbols(const Stmt *S, const LocationContext *L,
+ const ProgramPointTag *tag = 0)
: PostStmt(S, PostPurgeDeadSymbolsKind, L, tag) {}
static bool classof(const ProgramPoint* Location) {
@@ -308,14 +305,17 @@ public:
class BlockEdge : public ProgramPoint {
public:
- BlockEdge(const CFGBlock* B1, const CFGBlock* B2, const LocationContext *L)
- : ProgramPoint(B1, B2, BlockEdgeKind, L) {}
+ BlockEdge(const CFGBlock *B1, const CFGBlock *B2, const LocationContext *L)
+ : ProgramPoint(B1, B2, BlockEdgeKind, L) {
+ assert(B1 && "BlockEdge: source block must be non-null");
+ assert(B2 && "BlockEdge: destination block must be non-null");
+ }
- const CFGBlock* getSrc() const {
+ const CFGBlock *getSrc() const {
return static_cast<const CFGBlock*>(getData1());
}
- const CFGBlock* getDst() const {
+ const CFGBlock *getDst() const {
return static_cast<const CFGBlock*>(getData2());
}
@@ -365,6 +365,29 @@ public:
}
};
+/// ProgramPoints can be "tagged" as representing points specific to a given
+/// analysis entity. Tags are abstract annotations, with an associated
+/// description and potentially other information.
+class ProgramPointTag {
+public:
+ ProgramPointTag(void *tagKind = 0) : TagKind(tagKind) {}
+ virtual ~ProgramPointTag();
+ virtual StringRef getTagDescription() const = 0;
+
+protected:
+ /// Used to implement 'classof' in subclasses.
+ const void *getTagKind() { return TagKind; }
+
+private:
+ const void *TagKind;
+};
+
+class SimpleProgramPointTag : public ProgramPointTag {
+ std::string desc;
+public:
+ SimpleProgramPointTag(StringRef description);
+ StringRef getTagDescription() const;
+};
} // end namespace clang
@@ -385,12 +408,12 @@ static inline clang::ProgramPoint getTombstoneKey() {
return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0);
}
-static unsigned getHashValue(const clang::ProgramPoint& Loc) {
+static unsigned getHashValue(const clang::ProgramPoint &Loc) {
return Loc.getHashValue();
}
-static bool isEqual(const clang::ProgramPoint& L,
- const clang::ProgramPoint& R) {
+static bool isEqual(const clang::ProgramPoint &L,
+ const clang::ProgramPoint &R) {
return L == R;
}
diff --git a/include/clang/Analysis/Support/BlkExprDeclBitVector.h b/include/clang/Analysis/Support/BlkExprDeclBitVector.h
index 27ecc66e66e3..d25b84833c54 100644
--- a/include/clang/Analysis/Support/BlkExprDeclBitVector.h
+++ b/include/clang/Analysis/Support/BlkExprDeclBitVector.h
@@ -62,16 +62,16 @@ struct DeclBitVector_Types {
AnalysisDataTy() : NDecls(0) {}
virtual ~AnalysisDataTy() {}
- bool isTracked(const NamedDecl* SD) { return DMap.find(SD) != DMap.end(); }
+ bool isTracked(const NamedDecl *SD) { return DMap.find(SD) != DMap.end(); }
- Idx getIdx(const NamedDecl* SD) const {
+ Idx getIdx(const NamedDecl *SD) const {
DMapTy::const_iterator I = DMap.find(SD);
return I == DMap.end() ? Idx() : Idx(I->second);
}
unsigned getNumDecls() const { return NDecls; }
- void Register(const NamedDecl* SD) {
+ void Register(const NamedDecl *SD) {
if (!isTracked(SD)) DMap[SD] = NDecls++;
}
@@ -117,11 +117,11 @@ struct DeclBitVector_Types {
}
llvm::BitVector::reference
- operator()(const NamedDecl* ND, const AnalysisDataTy& AD) {
+ operator()(const NamedDecl *ND, const AnalysisDataTy& AD) {
return getBit(AD.getIdx(ND));
}
- bool operator()(const NamedDecl* ND, const AnalysisDataTy& AD) const {
+ bool operator()(const NamedDecl *ND, const AnalysisDataTy& AD) const {
return getBit(AD.getIdx(ND));
}
@@ -171,14 +171,14 @@ struct StmtDeclBitVector_Types {
//===--------------------------------------------------------------------===//
class AnalysisDataTy : public DeclBitVector_Types::AnalysisDataTy {
- ASTContext* ctx;
+ ASTContext *ctx;
CFG* cfg;
public:
AnalysisDataTy() : ctx(0), cfg(0) {}
virtual ~AnalysisDataTy() {}
- void setContext(ASTContext& c) { ctx = &c; }
- ASTContext& getContext() {
+ void setContext(ASTContext &c) { ctx = &c; }
+ ASTContext &getContext() {
assert(ctx && "ASTContext should not be NULL.");
return *ctx;
}
@@ -186,10 +186,10 @@ struct StmtDeclBitVector_Types {
void setCFG(CFG& c) { cfg = &c; }
CFG& getCFG() { assert(cfg && "CFG should not be NULL."); return *cfg; }
- bool isTracked(const Stmt* S) { return cfg->isBlkExpr(S); }
+ bool isTracked(const Stmt *S) { return cfg->isBlkExpr(S); }
using DeclBitVector_Types::AnalysisDataTy::isTracked;
- unsigned getIdx(const Stmt* S) const {
+ unsigned getIdx(const Stmt *S) const {
CFG::BlkExprNumTy I = cfg->getBlkExprNum(S);
assert(I && "Stmtession not tracked for bitvector.");
return I;
@@ -248,11 +248,11 @@ struct StmtDeclBitVector_Types {
}
llvm::BitVector::reference
- operator()(const Stmt* S, const AnalysisDataTy& AD) {
+ operator()(const Stmt *S, const AnalysisDataTy& AD) {
return BlkExprBV[AD.getIdx(S)];
}
const llvm::BitVector::reference
- operator()(const Stmt* S, const AnalysisDataTy& AD) const {
+ operator()(const Stmt *S, const AnalysisDataTy& AD) const {
return const_cast<ValTy&>(*this)(S,AD);
}
diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
index 95f4ace76e8c..5c5ec2d7afd8 100644
--- a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
+++ b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
@@ -28,8 +28,8 @@ static_cast<ImplClass*>(this)->Visit##CLASS##Decl( \
static_cast<CLASS##Decl*>(D)); \
break;
-#define DEFAULT_DISPATCH(CLASS) void Visit##CLASS##Decl(CLASS##Decl* D) {}
-#define DEFAULT_DISPATCH_VARDECL(CLASS) void Visit##CLASS##Decl(CLASS##Decl* D)\
+#define DEFAULT_DISPATCH(CLASS) void Visit##CLASS##Decl(CLASS##Decl *D) {}
+#define DEFAULT_DISPATCH_VARDECL(CLASS) void Visit##CLASS##Decl(CLASS##Decl *D)\
{ static_cast<ImplClass*>(this)->VisitVarDecl(D); }
@@ -38,23 +38,23 @@ template <typename ImplClass>
class CFGRecStmtDeclVisitor : public CFGRecStmtVisitor<ImplClass> {
public:
- void VisitDeclRefExpr(DeclRefExpr* DR) {
+ void VisitDeclRefExpr(DeclRefExpr *DR) {
static_cast<ImplClass*>(this)->VisitDecl(DR->getDecl());
}
- void VisitDeclStmt(DeclStmt* DS) {
+ void VisitDeclStmt(DeclStmt *DS) {
for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
DI != DE; ++DI) {
- Decl* D = *DI;
+ Decl *D = *DI;
static_cast<ImplClass*>(this)->VisitDecl(D);
// Visit the initializer.
- if (VarDecl* VD = dyn_cast<VarDecl>(D))
- if (Expr* I = VD->getInit())
+ if (VarDecl *VD = dyn_cast<VarDecl>(D))
+ if (Expr *I = VD->getInit())
static_cast<ImplClass*>(this)->Visit(I);
}
}
- void VisitDecl(Decl* D) {
+ void VisitDecl(Decl *D) {
switch (D->getKind()) {
DISPATCH_CASE(Function)
DISPATCH_CASE(CXXMethod)
@@ -69,7 +69,7 @@ public:
DISPATCH_CASE(UsingDirective)
DISPATCH_CASE(Using)
default:
- assert(false && "Subtype of ScopedDecl not handled.");
+ llvm_unreachable("Subtype of ScopedDecl not handled.");
}
}
diff --git a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h
index bb7cf0b97e53..4d1cabfc5c0b 100644
--- a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h
+++ b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h
@@ -22,7 +22,7 @@ template <typename ImplClass>
class CFGRecStmtVisitor : public CFGStmtVisitor<ImplClass,void> {
public:
- void VisitStmt(Stmt* S) {
+ void VisitStmt(Stmt *S) {
static_cast< ImplClass* >(this)->VisitChildren(S);
}
@@ -45,13 +45,13 @@ break;
CONDVAR_CASE(WhileStmt)
#undef CONDVAR_CASE
default:
- assert(false && "Infeasible");
+ llvm_unreachable("Infeasible");
}
static_cast<ImplClass*>(this)->Visit(CondVar->getInit());
}
// Defining operator() allows the visitor to be used as a C++ style functor.
- void operator()(Stmt* S) { static_cast<ImplClass*>(this)->BlockStmt_Visit(S);}
+ void operator()(Stmt *S) { static_cast<ImplClass*>(this)->BlockStmt_Visit(S);}
};
} // end namespace clang
diff --git a/include/clang/Analysis/Visitors/CFGStmtVisitor.h b/include/clang/Analysis/Visitors/CFGStmtVisitor.h
index 7fb4ab3ebad9..b354ba7b1680 100644
--- a/include/clang/Analysis/Visitors/CFGStmtVisitor.h
+++ b/include/clang/Analysis/Visitors/CFGStmtVisitor.h
@@ -33,7 +33,7 @@ static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S));
template <typename ImplClass, typename RetTy=void>
class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
- Stmt* CurrentBlkStmt;
+ Stmt *CurrentBlkStmt;
struct NullifyStmt {
Stmt*& S;
@@ -45,9 +45,9 @@ class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
public:
CFGStmtVisitor() : CurrentBlkStmt(NULL) {}
- Stmt* getCurrentBlkStmt() const { return CurrentBlkStmt; }
+ Stmt *getCurrentBlkStmt() const { return CurrentBlkStmt; }
- RetTy Visit(Stmt* S) {
+ RetTy Visit(Stmt *S) {
if (S == CurrentBlkStmt ||
!static_cast<ImplClass*>(this)->getCFG().isBlkExpr(S))
return StmtVisitor<ImplClass,RetTy>::Visit(S);
@@ -67,7 +67,7 @@ public:
/// the list of statements in a CFGBlock. For substatements, or when there
/// is no implementation provided for a BlockStmt_XXX method, we default
/// to using StmtVisitor's Visit method.
- RetTy BlockStmt_Visit(Stmt* S) {
+ RetTy BlockStmt_Visit(Stmt *S) {
CurrentBlkStmt = S;
NullifyStmt cleanup(CurrentBlkStmt);
@@ -106,23 +106,23 @@ public:
DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator)
DEFAULT_BLOCKSTMT_VISIT(BinaryConditionalOperator)
- RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
+ RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
}
- RetTy BlockStmt_VisitCXXForRangeStmt(CXXForRangeStmt* S) {
+ RetTy BlockStmt_VisitCXXForRangeStmt(CXXForRangeStmt *S) {
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
}
- RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr* E) {
+ RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr *E) {
return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(E);
}
- RetTy BlockStmt_VisitExpr(Expr* E) {
+ RetTy BlockStmt_VisitExpr(Expr *E) {
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(E);
}
- RetTy BlockStmt_VisitStmt(Stmt* S) {
+ RetTy BlockStmt_VisitStmt(Stmt *S) {
return static_cast<ImplClass*>(this)->Visit(S);
}
@@ -141,14 +141,14 @@ public:
//===--------------------------------------------------------------------===//
/// VisitChildren: Call "Visit" on each child of S.
- void VisitChildren(Stmt* S) {
+ void VisitChildren(Stmt *S) {
switch (S->getStmtClass()) {
default:
break;
case Stmt::StmtExprClass: {
- CompoundStmt* CS = cast<StmtExpr>(S)->getSubStmt();
+ CompoundStmt *CS = cast<StmtExpr>(S)->getSubStmt();
if (CS->body_empty()) return;
static_cast<ImplClass*>(this)->Visit(CS->body_back());
return;
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index e64dc6a2ade0..2a4ba5c6c73c 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -54,7 +54,9 @@ class ExprArgument<string name> : Argument<name>;
class FunctionArgument<string name> : Argument<name>;
class TypeArgument<string name> : Argument<name>;
class UnsignedArgument<string name> : Argument<name>;
+class SourceLocArgument<string name> : Argument<name>;
class VariadicUnsignedArgument<string name> : Argument<name>;
+class VariadicExprArgument<string name> : Argument<name>;
// A version of the form major.minor[.subminor].
class VersionArgument<string name> : Argument<name>;
@@ -89,7 +91,9 @@ class Attr {
// The attribute will not be permitted in C++0x attribute-specifiers if
// this is empty; the empty string can be used as a namespace.
list<string> Namespaces = [];
- // Any additional text that should be included verbatim in the class.
+ // Set to true for attributes with arguments which require delayed parsing.
+ bit LateParsed = 0;
+ // Any additional text that should be included verbatim in the class.
code AdditionalMembers = [{}];
}
@@ -110,7 +114,7 @@ def Alias : InheritableAttr {
}
def Aligned : InheritableAttr {
- let Spellings = ["align", "aligned"];
+ let Spellings = ["aligned"];
let Subjects = [NonBitField, NormalVar, Tag];
let Args = [AlignedArgument<"Alignment">];
let Namespaces = ["", "std"];
@@ -128,7 +132,7 @@ def AnalyzerNoReturn : InheritableAttr {
let Spellings = ["analyzer_noreturn"];
}
-def Annotate : InheritableAttr {
+def Annotate : InheritableParamAttr {
let Spellings = ["annotate"];
let Args = [StringArgument<"Annotation">];
}
@@ -167,6 +171,23 @@ def CDecl : InheritableAttr {
let Spellings = ["cdecl", "__cdecl"];
}
+// cf_audited_transfer indicates that the given function has been
+// audited and has been marked with the appropriate cf_consumed and
+// cf_returns_retained attributes. It is generally applied by
+// '#pragma clang arc_cf_code_audited' rather than explicitly.
+def CFAuditedTransfer : InheritableAttr {
+ let Spellings = ["cf_audited_transfer"];
+ let Subjects = [Function];
+}
+
+// cf_unknown_transfer is an explicit opt-out of cf_audited_transfer.
+// It indicates that the function has unknown or unautomatable
+// transfer semantics.
+def CFUnknownTransfer : InheritableAttr {
+ let Spellings = ["cf_unknown_transfer"];
+ let Subjects = [Function];
+}
+
def CFReturnsRetained : InheritableAttr {
let Spellings = ["cf_returns_retained"];
let Subjects = [ObjCMethod, Function];
@@ -284,7 +305,7 @@ def IBOutlet : InheritableAttr {
def IBOutletCollection : InheritableAttr {
let Spellings = ["iboutletcollection"];
- let Args = [TypeArgument<"InterFace">];
+ let Args = [TypeArgument<"Interface">, SourceLocArgument<"InterfaceLoc">];
}
def Malloc : InheritableAttr {
@@ -317,6 +338,10 @@ def Naked : InheritableAttr {
let Spellings = ["naked"];
}
+def ReturnsTwice : InheritableAttr {
+ let Spellings = ["returns_twice"];
+}
+
def NoCommon : InheritableAttr {
let Spellings = ["nocommon"];
}
@@ -358,6 +383,12 @@ def NoThrow : InheritableAttr {
let Spellings = ["nothrow"];
}
+def NSBridged : InheritableAttr {
+ let Spellings = ["ns_bridged"];
+ let Subjects = [Record];
+ let Args = [IdentifierArgument<"BridgedType">];
+}
+
def NSReturnsRetained : InheritableAttr {
let Spellings = ["ns_returns_retained"];
let Subjects = [ObjCMethod, Function];
@@ -405,6 +436,11 @@ def ObjCPreciseLifetime : Attr {
let Subjects = [Var];
}
+def ObjCReturnsInnerPointer : Attr {
+ let Spellings = ["objc_returns_inner_pointer"];
+ let Subjects = [ObjCMethod];
+}
+
def Overloadable : Attr {
let Spellings = ["overloadable"];
}
@@ -533,3 +569,108 @@ def WeakRef : InheritableAttr {
def X86ForceAlignArgPointer : InheritableAttr {
let Spellings = [];
}
+
+
+// C/C++ Thread safety attributes (e.g. for deadlock, data race checking)
+
+def GuardedVar : InheritableAttr {
+ let Spellings = ["guarded_var"];
+}
+
+def PtGuardedVar : InheritableAttr {
+ let Spellings = ["pt_guarded_var"];
+}
+
+def Lockable : InheritableAttr {
+ let Spellings = ["lockable"];
+}
+
+def ScopedLockable : InheritableAttr {
+ let Spellings = ["scoped_lockable"];
+}
+
+def NoThreadSafetyAnalysis : InheritableAttr {
+ let Spellings = ["no_thread_safety_analysis"];
+}
+
+def GuardedBy : InheritableAttr {
+ let Spellings = ["guarded_by"];
+ let Args = [ExprArgument<"Arg">];
+ let LateParsed = 1;
+}
+
+def PtGuardedBy : InheritableAttr {
+ let Spellings = ["pt_guarded_by"];
+ let Args = [ExprArgument<"Arg">];
+ let LateParsed = 1;
+}
+
+def AcquiredAfter : InheritableAttr {
+ let Spellings = ["acquired_after"];
+ let Args = [VariadicExprArgument<"Args">];
+ let LateParsed = 1;
+}
+
+def AcquiredBefore : InheritableAttr {
+ let Spellings = ["acquired_before"];
+ let Args = [VariadicExprArgument<"Args">];
+ let LateParsed = 1;
+}
+
+def ExclusiveLockFunction : InheritableAttr {
+ let Spellings = ["exclusive_lock_function"];
+ let Args = [VariadicExprArgument<"Args">];
+ let LateParsed = 1;
+}
+
+def SharedLockFunction : InheritableAttr {
+ let Spellings = ["shared_lock_function"];
+ let Args = [VariadicExprArgument<"Args">];
+ let LateParsed = 1;
+}
+
+// The first argument is an integer or boolean value specifying the return value
+// of a successful lock acquisition.
+def ExclusiveTrylockFunction : InheritableAttr {
+ let Spellings = ["exclusive_trylock_function"];
+ let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
+ let LateParsed = 1;
+}
+
+// The first argument is an integer or boolean value specifying the return value
+// of a successful lock acquisition.
+def SharedTrylockFunction : InheritableAttr {
+ let Spellings = ["shared_trylock_function"];
+ let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
+ let LateParsed = 1;
+}
+
+def UnlockFunction : InheritableAttr {
+ let Spellings = ["unlock_function"];
+ let Args = [VariadicExprArgument<"Args">];
+ let LateParsed = 1;
+}
+
+def LockReturned : InheritableAttr {
+ let Spellings = ["lock_returned"];
+ let Args = [ExprArgument<"Arg">];
+ let LateParsed = 1;
+}
+
+def LocksExcluded : InheritableAttr {
+ let Spellings = ["locks_excluded"];
+ let Args = [VariadicExprArgument<"Args">];
+ let LateParsed = 1;
+}
+
+def ExclusiveLocksRequired : InheritableAttr {
+ let Spellings = ["exclusive_locks_required"];
+ let Args = [VariadicExprArgument<"Args">];
+ let LateParsed = 1;
+}
+
+def SharedLocksRequired : InheritableAttr {
+ let Spellings = ["shared_locks_required"];
+ let Args = [VariadicExprArgument<"Args">];
+ let LateParsed = 1;
+}
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index a3cc6156238e..e5690c123393 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -35,6 +35,7 @@
// A -> "reference" to __builtin_va_list
// V -> Vector, following num elements and a base type.
// X -> _Complex, followed by the base type.
+// Y -> ptrdiff_t
// P -> FILE
// J -> jmp_buf
// SJ -> sigjmp_buf
@@ -76,6 +77,7 @@
// in that it accepts its arguments as a va_list rather than
// through an ellipsis
// e -> const, but only when -fmath-errno=0
+// j -> returns_twice (like setjmp)
// FIXME: gcc has nonnull
#if defined(BUILTIN) && !defined(LIBBUILTIN)
@@ -96,9 +98,9 @@ BUILTIN(__builtin_fabsl, "LdLd", "ncF")
BUILTIN(__builtin_fmod , "ddd" , "Fnc")
BUILTIN(__builtin_fmodf, "fff" , "Fnc")
BUILTIN(__builtin_fmodl, "LdLdLd", "Fnc")
-BUILTIN(__builtin_frexp , "ddi*" , "Fnc")
-BUILTIN(__builtin_frexpf, "ffi*" , "Fnc")
-BUILTIN(__builtin_frexpl, "LdLdi*", "Fnc")
+BUILTIN(__builtin_frexp , "ddi*" , "Fn")
+BUILTIN(__builtin_frexpf, "ffi*" , "Fn")
+BUILTIN(__builtin_frexpl, "LdLdi*", "Fn")
BUILTIN(__builtin_huge_val, "d", "nc")
BUILTIN(__builtin_huge_valf, "f", "nc")
BUILTIN(__builtin_huge_vall, "Ld", "nc")
@@ -108,9 +110,9 @@ BUILTIN(__builtin_infl , "Ld" , "nc")
BUILTIN(__builtin_ldexp , "ddi" , "Fnc")
BUILTIN(__builtin_ldexpf, "ffi" , "Fnc")
BUILTIN(__builtin_ldexpl, "LdLdi", "Fnc")
-BUILTIN(__builtin_modf , "ddd*" , "Fnc")
-BUILTIN(__builtin_modff, "fff*" , "Fnc")
-BUILTIN(__builtin_modfl, "LdLdLd*", "Fnc")
+BUILTIN(__builtin_modf , "ddd*" , "Fn")
+BUILTIN(__builtin_modff, "fff*" , "Fn")
+BUILTIN(__builtin_modfl, "LdLdLd*", "Fn")
BUILTIN(__builtin_nan, "dcC*" , "ncF")
BUILTIN(__builtin_nanf, "fcC*" , "ncF")
BUILTIN(__builtin_nanl, "LdcC*", "ncF")
@@ -233,9 +235,9 @@ BUILTIN(__builtin_nexttowardl, "LdLdLd", "Fnc")
BUILTIN(__builtin_remainder , "ddd", "Fnc")
BUILTIN(__builtin_remainderf, "fff", "Fnc")
BUILTIN(__builtin_remainderl, "LdLdLd", "Fnc")
-BUILTIN(__builtin_remquo , "dddi*", "Fnc")
-BUILTIN(__builtin_remquof, "fffi*", "Fnc")
-BUILTIN(__builtin_remquol, "LdLdLdi*", "Fnc")
+BUILTIN(__builtin_remquo , "dddi*", "Fn")
+BUILTIN(__builtin_remquof, "fffi*", "Fn")
+BUILTIN(__builtin_remquol, "LdLdLdi*", "Fn")
BUILTIN(__builtin_rint , "dd", "Fnc")
BUILTIN(__builtin_rintf, "ff", "Fnc")
BUILTIN(__builtin_rintl, "LdLd", "Fnc")
@@ -388,7 +390,7 @@ BUILTIN(__builtin_constant_p, "i.", "nct")
BUILTIN(__builtin_classify_type, "i.", "nct")
BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "nc")
BUILTIN(__builtin___NSStringMakeConstantString, "FC*cC*", "nc")
-BUILTIN(__builtin_va_start, "vA.", "n")
+BUILTIN(__builtin_va_start, "vA.", "nt")
BUILTIN(__builtin_va_end, "vA", "n")
BUILTIN(__builtin_va_copy, "vAA", "n")
BUILTIN(__builtin_stdarg_start, "vA.", "n")
@@ -426,7 +428,7 @@ BUILTIN(__builtin_return_address, "v*IUi", "n")
BUILTIN(__builtin_extract_return_addr, "v*v*", "n")
BUILTIN(__builtin_frame_address, "v*IUi", "n")
BUILTIN(__builtin_flt_rounds, "i", "nc")
-BUILTIN(__builtin_setjmp, "iv**", "")
+BUILTIN(__builtin_setjmp, "iv**", "j")
BUILTIN(__builtin_longjmp, "vv**i", "r")
BUILTIN(__builtin_unwind_init, "v", "")
BUILTIN(__builtin_eh_return_data_regno, "iIi", "nc")
@@ -584,12 +586,21 @@ BUILTIN(__sync_swap_4, "iiD*i.", "n")
BUILTIN(__sync_swap_8, "LLiLLiD*LLi.", "n")
BUILTIN(__sync_swap_16, "LLLiLLLiD*LLLi.", "n")
-
+BUILTIN(__atomic_load, "v.", "t")
+BUILTIN(__atomic_store, "v.", "t")
+BUILTIN(__atomic_exchange, "v.", "t")
+BUILTIN(__atomic_compare_exchange_strong, "v.", "t")
+BUILTIN(__atomic_compare_exchange_weak, "v.", "t")
+BUILTIN(__atomic_fetch_add, "v.", "t")
+BUILTIN(__atomic_fetch_sub, "v.", "t")
+BUILTIN(__atomic_fetch_and, "v.", "t")
+BUILTIN(__atomic_fetch_or, "v.", "t")
+BUILTIN(__atomic_fetch_xor, "v.", "t")
+BUILTIN(__atomic_thread_fence, "vi", "n")
+BUILTIN(__atomic_signal_fence, "vi", "n")
// Non-overloaded atomic builtins.
BUILTIN(__sync_synchronize, "v.", "n")
-// LLVM instruction builtin [Clang extension].
-BUILTIN(__builtin_llvm_memory_barrier,"vbbbbb", "n")
// GCC does not support these, they are a Clang extension.
BUILTIN(__sync_fetch_and_min, "iiD*i", "n")
BUILTIN(__sync_fetch_and_max, "iiD*i", "n")
@@ -661,9 +672,26 @@ LIBBUILTIN(rindex, "c*cC*i", "f", "strings.h", ALL_LANGUAGES)
LIBBUILTIN(bzero, "vv*z", "f", "strings.h", ALL_LANGUAGES)
// POSIX unistd.h
LIBBUILTIN(_exit, "vi", "fr", "unistd.h", ALL_LANGUAGES)
+LIBBUILTIN(vfork, "iJ", "fj", "unistd.h", ALL_LANGUAGES)
// POSIX setjmp.h
+
+// In some systems setjmp is a macro that expands to _setjmp. We undefine
+// it here to avoid having two identical LIBBUILTIN entries.
+#undef setjmp
+LIBBUILTIN(_setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(__sigsetjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(sigsetjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(setjmp_syscall, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(savectx, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(qsetjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(getcontext, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+
LIBBUILTIN(_longjmp, "vJi", "fr", "setjmp.h", ALL_LANGUAGES)
LIBBUILTIN(siglongjmp, "vSJi", "fr", "setjmp.h", ALL_LANGUAGES)
+// non-standard but very common
+LIBBUILTIN(strlcpy, "zc*cC*z", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strlcat, "zc*cC*z", "f", "string.h", ALL_LANGUAGES)
// id objc_msgSend(id, SEL, ...)
LIBBUILTIN(objc_msgSend, "GGH.", "f", "objc/message.h", OBJC_LANG)
@@ -687,8 +715,7 @@ LIBBUILTIN(objc_read_weak, "GG*", "f", "/objc/objc-auto.h", OBJC_LANG)
// id objc_assign_weak(id value, id *location)
LIBBUILTIN(objc_assign_weak, "GGG*", "f", "/objc/objc-auto.h", OBJC_LANG)
// id objc_assign_ivar(id value, id dest, ptrdiff_t offset)
-// FIXME. Darwin has ptrdiff_t typedef'ed to int.
-LIBBUILTIN(objc_assign_ivar, "GGGi", "f", "/objc/objc-auto.h", OBJC_LANG)
+LIBBUILTIN(objc_assign_ivar, "GGGY", "f", "/objc/objc-auto.h", OBJC_LANG)
// id objc_assign_global(id val, id *dest)
LIBBUILTIN(objc_assign_global, "GGG*", "f", "/objc/objc-auto.h", OBJC_LANG)
// id objc_assign_strongCast(id val, id *dest
@@ -738,5 +765,8 @@ LIBBUILTIN(_Block_object_assign, "vv*vC*iC", "f", "Blocks.h", ALL_LANGUAGES)
LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h", ALL_LANGUAGES)
// FIXME: Also declare NSConcreteGlobalBlock and NSConcreteStackBlock.
+// Annotation function
+BUILTIN(__builtin_annotation, "UiUicC*", "nc")
+
#undef BUILTIN
#undef LIBBUILTIN
diff --git a/include/clang/Basic/Builtins.h b/include/clang/Basic/Builtins.h
index 7469e144c150..5afa02010040 100644
--- a/include/clang/Basic/Builtins.h
+++ b/include/clang/Basic/Builtins.h
@@ -15,16 +15,13 @@
#ifndef LLVM_CLANG_BASIC_BUILTINS_H
#define LLVM_CLANG_BASIC_BUILTINS_H
+#include "clang/Basic/LLVM.h"
#include <cstring>
// VC++ defines 'alloca' as an object-like macro, which interferes with our
// builtins.
#undef alloca
-namespace llvm {
- template <typename T> class SmallVectorImpl;
-}
-
namespace clang {
class TargetInfo;
class IdentifierTable;
@@ -65,15 +62,18 @@ class Context {
const Info *TSRecords;
unsigned NumTSRecords;
public:
- Context(const TargetInfo &Target);
+ Context();
+ /// \brief Perform target-specific initialization
+ void InitializeTarget(const TargetInfo &Target);
+
/// InitializeBuiltins - Mark the identifiers for all the builtins with their
/// appropriate builtin ID # and mark any non-portable builtin identifiers as
/// such.
void InitializeBuiltins(IdentifierTable &Table, const LangOptions& LangOpts);
/// \brief Popular the vector with the names of all of the builtins.
- void GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names,
+ void GetBuiltinNames(SmallVectorImpl<const char *> &Names,
bool NoBuiltins);
/// Builtin::GetName - Return the identifier name for the specified builtin,
@@ -103,6 +103,11 @@ public:
return strchr(GetRecord(ID).Attributes, 'r') != 0;
}
+ /// isReturnsTwice - Return true if we know this builtin can return twice.
+ bool isReturnsTwice(unsigned ID) const {
+ return strchr(GetRecord(ID).Attributes, 'j') != 0;
+ }
+
/// isLibFunction - 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/DeclNodes.td b/include/clang/Basic/DeclNodes.td
index ddd08278c37b..a37dc1039891 100644
--- a/include/clang/Basic/DeclNodes.td
+++ b/include/clang/Basic/DeclNodes.td
@@ -74,3 +74,4 @@ def Friend : Decl;
def FriendTemplate : Decl;
def StaticAssert : Decl;
def Block : Decl, DeclContext;
+def ClassScopeFunctionSpecialization : Decl;
diff --git a/include/clang/Basic/DelayedCleanupPool.h b/include/clang/Basic/DelayedCleanupPool.h
index 843205f7b011..8575bc21113f 100644
--- a/include/clang/Basic/DelayedCleanupPool.h
+++ b/include/clang/Basic/DelayedCleanupPool.h
@@ -15,6 +15,7 @@
#ifndef LLVM_CLANG_BASIC_DELAYEDCLEANUPPOOL_H
#define LLVM_CLANG_BASIC_DELAYEDCLEANUPPOOL_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
@@ -66,7 +67,7 @@ public:
}
void doCleanup() {
- for (llvm::SmallVector<std::pair<void *, CleanupFn>, 8>::reverse_iterator
+ for (SmallVector<std::pair<void *, CleanupFn>, 8>::reverse_iterator
I = Cleanups.rbegin(), E = Cleanups.rend(); I != E; ++I)
I->second(I->first);
Cleanups.clear();
@@ -79,7 +80,7 @@ public:
private:
llvm::DenseMap<void *, CleanupFn> Ptrs;
- llvm::SmallVector<std::pair<void *, CleanupFn>, 8> Cleanups;
+ SmallVector<std::pair<void *, CleanupFn>, 8> Cleanups;
template <typename T>
static void cleanupWithDelete(void *ptr) {
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 6f72976bfcf0..fefc44ce7bc6 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -16,6 +16,7 @@
#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/OwningPtr.h"
@@ -25,7 +26,7 @@
#include <list>
namespace clang {
- class DiagnosticClient;
+ class DiagnosticConsumer;
class DiagnosticBuilder;
class IdentifierInfo;
class DeclContext;
@@ -64,7 +65,7 @@ public:
/// \brief Create a code modification hint that inserts the given
/// code string at a specific location.
static FixItHint CreateInsertion(SourceLocation InsertionLoc,
- llvm::StringRef Code) {
+ StringRef Code) {
FixItHint Hint;
Hint.RemoveRange =
CharSourceRange(SourceRange(InsertionLoc, InsertionLoc), false);
@@ -86,7 +87,7 @@ public:
/// \brief Create a code modification hint that replaces the given
/// source range with the given code string.
static FixItHint CreateReplacement(CharSourceRange RemoveRange,
- llvm::StringRef Code) {
+ StringRef Code) {
FixItHint Hint;
Hint.RemoveRange = RemoveRange;
Hint.CodeToInsert = Code;
@@ -94,17 +95,17 @@ public:
}
static FixItHint CreateReplacement(SourceRange RemoveRange,
- llvm::StringRef Code) {
+ StringRef Code) {
return CreateReplacement(CharSourceRange::getTokenRange(RemoveRange), Code);
}
};
-/// Diagnostic - This concrete class is used by the front-end to report
+/// DiagnosticsEngine - This concrete class is used by the front-end to report
/// problems and issues. It massages the diagnostics (e.g. handling things like
-/// "report warnings as errors" and passes them off to the DiagnosticClient for
-/// reporting to the user. Diagnostic is tied to one translation unit and
-/// one SourceManager.
-class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
+/// "report warnings as errors" and passes them off to the DiagnosticConsumer
+/// for reporting to the user. DiagnosticsEngine is tied to one translation unit
+/// and one SourceManager.
+class DiagnosticsEngine : public llvm::RefCountedBase<DiagnosticsEngine> {
public:
/// Level - The level of the diagnostic, after it has been through mapping.
enum Level {
@@ -148,7 +149,8 @@ public:
private:
unsigned char AllExtensionsSilenced; // Used by __extension__
bool IgnoreAllWarnings; // Ignore all warnings: -w
- bool WarningsAsErrors; // Treat warnings like errors:
+ bool WarningsAsErrors; // Treat warnings like errors.
+ bool EnableAllWarnings; // Enable all warnings.
bool ErrorsAsFatal; // Treat errors like fatal errors.
bool SuppressSystemWarnings; // Suppress warnings in system headers.
bool SuppressAllDiagnostics; // Suppress all diagnostics.
@@ -158,7 +160,7 @@ private:
// 0 -> no limit.
ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors?
llvm::IntrusiveRefCntPtr<DiagnosticIDs> Diags;
- DiagnosticClient *Client;
+ DiagnosticConsumer *Client;
bool OwnsDiagClient;
SourceManager *SourceMgr;
@@ -173,22 +175,22 @@ private:
/// the state so that we know what is the diagnostic state at any given
/// source location.
class DiagState {
- llvm::DenseMap<unsigned, unsigned> DiagMap;
+ llvm::DenseMap<unsigned, DiagnosticMappingInfo> DiagMap;
public:
- typedef llvm::DenseMap<unsigned, unsigned>::const_iterator iterator;
+ typedef llvm::DenseMap<unsigned, DiagnosticMappingInfo>::iterator
+ iterator;
+ typedef llvm::DenseMap<unsigned, DiagnosticMappingInfo>::const_iterator
+ const_iterator;
- void setMapping(diag::kind Diag, unsigned Map) { DiagMap[Diag] = Map; }
-
- diag::Mapping getMapping(diag::kind Diag) const {
- iterator I = DiagMap.find(Diag);
- if (I != DiagMap.end())
- return (diag::Mapping)I->second;
- return diag::Mapping();
+ void setMappingInfo(diag::kind Diag, DiagnosticMappingInfo Info) {
+ DiagMap[Diag] = Info;
}
- iterator begin() const { return DiagMap.begin(); }
- iterator end() const { return DiagMap.end(); }
+ DiagnosticMappingInfo &getOrAddMappingInfo(diag::kind Diag);
+
+ const_iterator begin() const { return DiagMap.begin(); }
+ const_iterator end() const { return DiagMap.end(); }
};
/// \brief Keeps and automatically disposes all DiagStates that we create.
@@ -254,10 +256,10 @@ private:
/// \brief Indicates that an unrecoverable error has occurred.
bool UnrecoverableErrorOccurred;
- /// \brief Toggles for DiagnosticErrorTrap to check whether an error occurred
+ /// \brief Counts for DiagnosticErrorTrap to check whether an error occurred
/// during a parsing section, e.g. during parsing a function.
- bool TrapErrorOccurred;
- bool TrapUnrecoverableErrorOccurred;
+ unsigned TrapNumErrorsOccurred;
+ unsigned TrapNumUnrecoverableErrorsOccurred;
/// LastDiagLevel - This is the level of the last diagnostic emitted. This is
/// used to emit continuation diagnostics with the same level as the
@@ -283,9 +285,9 @@ private:
const char *Argument, unsigned ArgumentLen,
const ArgumentValue *PrevArgs,
unsigned NumPrevArgs,
- llvm::SmallVectorImpl<char> &Output,
+ SmallVectorImpl<char> &Output,
void *Cookie,
- llvm::SmallVectorImpl<intptr_t> &QualTypeVals);
+ SmallVectorImpl<intptr_t> &QualTypeVals);
void *ArgToStringCookie;
ArgToStringFnTy ArgToStringFn;
@@ -301,21 +303,25 @@ private:
std::string DelayedDiagArg2;
public:
- explicit Diagnostic(const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &Diags,
- DiagnosticClient *client = 0,
+ explicit DiagnosticsEngine(
+ const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &Diags,
+ DiagnosticConsumer *client = 0,
bool ShouldOwnClient = true);
- ~Diagnostic();
+ ~DiagnosticsEngine();
const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &getDiagnosticIDs() const {
return Diags;
}
- DiagnosticClient *getClient() { return Client; }
- const DiagnosticClient *getClient() const { return Client; }
+ DiagnosticConsumer *getClient() { return Client; }
+ const DiagnosticConsumer *getClient() const { return Client; }
+ /// \brief Determine whether this \c DiagnosticsEngine object own its client.
+ bool ownsClient() const { return OwnsDiagClient; }
+
/// \brief Return the current diagnostic client along with ownership of that
/// client.
- DiagnosticClient *takeClient() {
+ DiagnosticConsumer *takeClient() {
OwnsDiagClient = false;
return Client;
}
@@ -328,8 +334,8 @@ public:
void setSourceManager(SourceManager *SrcMgr) { SourceMgr = SrcMgr; }
//===--------------------------------------------------------------------===//
- // Diagnostic characterization methods, used by a client to customize how
- // diagnostics are emitted.
+ // DiagnosticsEngine characterization methods, used by a client to customize
+ // how diagnostics are emitted.
//
/// pushMappings - Copies the current DiagMappings and pushes the new copy
@@ -346,7 +352,7 @@ public:
///
/// \param ShouldOwnClient true if the diagnostic object should take
/// ownership of \c client.
- void setClient(DiagnosticClient *client, bool ShouldOwnClient = true);
+ void setClient(DiagnosticConsumer *client, bool ShouldOwnClient = true);
/// setErrorLimit - Specify a limit for the number of errors we should
/// emit before giving up. Zero disables the limit.
@@ -369,6 +375,12 @@ public:
void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; }
bool getIgnoreAllWarnings() const { return IgnoreAllWarnings; }
+ /// setEnableAllWarnings - When set to true, any unmapped ignored warnings
+ /// are no longer ignored. If this and IgnoreAllWarnings are both set,
+ /// then that one wins.
+ void setEnableAllWarnings(bool Val) { EnableAllWarnings = Val; }
+ bool getEnableAllWarnngs() const { return EnableAllWarnings; }
+
/// setWarningsAsErrors - When set to true, any warnings reported are issued
/// as errors.
void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; }
@@ -435,10 +447,20 @@ public:
///
/// 'Loc' is the source location that this change of diagnostic state should
/// take affect. It can be null if we are setting the state from command-line.
- bool setDiagnosticGroupMapping(llvm::StringRef Group, diag::Mapping Map,
- SourceLocation Loc = SourceLocation()) {
- return Diags->setDiagnosticGroupMapping(Group, Map, Loc, *this);
- }
+ bool setDiagnosticGroupMapping(StringRef Group, diag::Mapping Map,
+ SourceLocation Loc = SourceLocation());
+
+ /// \brief Set the warning-as-error flag for the given diagnostic group. This
+ /// function always only operates on the current diagnostic state.
+ ///
+ /// \returns True if the given group is unknown, false otherwise.
+ bool setDiagnosticGroupWarningAsError(StringRef Group, bool Enabled);
+
+ /// \brief Set the error-as-fatal flag for the given diagnostic group. This
+ /// function always only operates on the current diagnostic state.
+ ///
+ /// \returns True if the given group is unknown, false otherwise.
+ bool setDiagnosticGroupErrorAsFatal(StringRef Group, bool Enabled);
bool hasErrorOccurred() const { return ErrorOccurred; }
bool hasFatalErrorOccurred() const { return FatalErrorOccurred; }
@@ -457,7 +479,7 @@ public:
/// getCustomDiagID - 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 created, otherwise the existing ID is returned.
- unsigned getCustomDiagID(Level L, llvm::StringRef Message) {
+ unsigned getCustomDiagID(Level L, StringRef Message) {
return Diags->getCustomDiagID((DiagnosticIDs::Level)L, Message);
}
@@ -467,8 +489,8 @@ public:
const char *Modifier, unsigned ModLen,
const char *Argument, unsigned ArgLen,
const ArgumentValue *PrevArgs, unsigned NumPrevArgs,
- llvm::SmallVectorImpl<char> &Output,
- llvm::SmallVectorImpl<intptr_t> &QualTypeVals) const {
+ SmallVectorImpl<char> &Output,
+ SmallVectorImpl<intptr_t> &QualTypeVals) const {
ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen,
PrevArgs, NumPrevArgs, Output, ArgToStringCookie,
QualTypeVals);
@@ -484,18 +506,17 @@ public:
void Reset();
//===--------------------------------------------------------------------===//
- // Diagnostic classification and reporting interfaces.
+ // DiagnosticsEngine classification and reporting interfaces.
//
- /// \brief Based on the way the client configured the Diagnostic
+ /// \brief Based on the way the client configured the DiagnosticsEngine
/// object, classify the specified diagnostic ID into a Level, consumable by
- /// the DiagnosticClient.
+ /// the DiagnosticConsumer.
///
/// \param Loc The source location we are interested in finding out the
/// diagnostic state. Can be null in order to query the latest state.
- Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
- diag::Mapping *mapping = 0) const {
- return (Level)Diags->getDiagnosticLevel(DiagID, Loc, *this, mapping);
+ Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc) const {
+ return (Level)Diags->getDiagnosticLevel(DiagID, Loc, *this);
}
/// Report - Issue the message to the client. @c DiagID is a member of the
@@ -527,13 +548,13 @@ public:
///
/// \param Arg1 A string argument that will be provided to the
/// diagnostic. A copy of this string will be stored in the
- /// Diagnostic object itself.
+ /// DiagnosticsEngine object itself.
///
/// \param Arg2 A string argument that will be provided to the
/// diagnostic. A copy of this string will be stored in the
- /// Diagnostic object itself.
- void SetDelayedDiagnostic(unsigned DiagID, llvm::StringRef Arg1 = "",
- llvm::StringRef Arg2 = "");
+ /// DiagnosticsEngine object itself.
+ void SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1 = "",
+ StringRef Arg2 = "");
/// \brief Clear out the current diagnostic.
void Clear() { CurDiagID = ~0U; }
@@ -542,23 +563,6 @@ private:
/// \brief Report the delayed diagnostic.
void ReportDelayed();
-
- /// getDiagnosticMappingInfo - Return the mapping info currently set for the
- /// specified builtin diagnostic. This returns the high bit encoding, or zero
- /// if the field is completely uninitialized.
- diag::Mapping getDiagnosticMappingInfo(diag::kind Diag,
- DiagState *State) const {
- return State->getMapping(Diag);
- }
-
- void setDiagnosticMappingInternal(unsigned DiagId, unsigned Map,
- DiagState *State,
- bool isUser, bool isPragma) const {
- if (isUser) Map |= 8; // Set the high bit for user mappings.
- if (isPragma) Map |= 0x10; // Set the bit for diagnostic pragma mappings.
- State->setMapping((diag::kind)DiagId, Map);
- }
-
// This is private state used by DiagnosticBuilder. We put it here instead of
// in DiagnosticBuilder in order to keep DiagnosticBuilder a small lightweight
// object. This implementation choice means that we can only have one
@@ -567,7 +571,7 @@ private:
// diagnostic is in flight at a time.
friend class DiagnosticIDs;
friend class DiagnosticBuilder;
- friend class DiagnosticInfo;
+ friend class Diagnostic;
friend class PartialDiagnostic;
friend class DiagnosticErrorTrap;
@@ -614,7 +618,7 @@ private:
/// only support 10 ranges, could easily be extended if needed.
CharSourceRange DiagRanges[10];
- enum { MaxFixItHints = 3 };
+ enum { MaxFixItHints = 6 };
/// FixItHints - If valid, provides a hint with some code
/// to insert, remove, or modify at a particular position.
@@ -637,28 +641,30 @@ private:
/// between the time the instance was created and the time it was
/// queried.
class DiagnosticErrorTrap {
- Diagnostic &Diag;
+ DiagnosticsEngine &Diag;
+ unsigned NumErrors;
+ unsigned NumUnrecoverableErrors;
public:
- explicit DiagnosticErrorTrap(Diagnostic &Diag)
+ explicit DiagnosticErrorTrap(DiagnosticsEngine &Diag)
: Diag(Diag) { reset(); }
/// \brief Determine whether any errors have occurred since this
/// object instance was created.
bool hasErrorOccurred() const {
- return Diag.TrapErrorOccurred;
+ return Diag.TrapNumErrorsOccurred > NumErrors;
}
/// \brief Determine whether any unrecoverable errors have occurred since this
/// object instance was created.
bool hasUnrecoverableErrorOccurred() const {
- return Diag.TrapUnrecoverableErrorOccurred;
+ return Diag.TrapNumUnrecoverableErrorsOccurred > NumUnrecoverableErrors;
}
// Set to initial state of "no errors occurred".
void reset() {
- Diag.TrapErrorOccurred = false;
- Diag.TrapUnrecoverableErrorOccurred = false;
+ NumErrors = Diag.TrapNumErrorsOccurred;
+ NumUnrecoverableErrors = Diag.TrapNumUnrecoverableErrorsOccurred;
}
};
@@ -667,9 +673,9 @@ public:
//===----------------------------------------------------------------------===//
/// DiagnosticBuilder - This is a little helper class used to produce
-/// diagnostics. This is constructed by the Diagnostic::Report method, and
-/// allows insertion of extra information (arguments and source ranges) into the
-/// currently "in flight" diagnostic. When the temporary for the builder is
+/// diagnostics. This is constructed by the DiagnosticsEngine::Report method,
+/// and allows insertion of extra information (arguments and source ranges) into
+/// the currently "in flight" diagnostic. When the temporary for the builder is
/// destroyed, the diagnostic is issued.
///
/// Note that many of these will be created as temporary objects (many call
@@ -678,12 +684,12 @@ public:
/// the common fields to registers, eliminating increments of the NumArgs field,
/// for example.
class DiagnosticBuilder {
- mutable Diagnostic *DiagObj;
+ mutable DiagnosticsEngine *DiagObj;
mutable unsigned NumArgs, NumRanges, NumFixItHints;
void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT
- friend class Diagnostic;
- explicit DiagnosticBuilder(Diagnostic *diagObj)
+ friend class DiagnosticsEngine;
+ explicit DiagnosticBuilder(DiagnosticsEngine *diagObj)
: DiagObj(diagObj), NumArgs(0), NumRanges(0), NumFixItHints(0) {}
friend class PartialDiagnostic;
@@ -731,7 +737,7 @@ public:
///
/// \pre \c isActive()
unsigned getDiagID() const {
- assert(isActive() && "Diagnostic is inactive");
+ assert(isActive() && "DiagnosticsEngine is inactive");
return DiagObj->CurDiagID;
}
@@ -743,17 +749,17 @@ public:
/// return Diag(...);
operator bool() const { return true; }
- void AddString(llvm::StringRef S) const {
- assert(NumArgs < Diagnostic::MaxArguments &&
+ void AddString(StringRef S) const {
+ assert(NumArgs < DiagnosticsEngine::MaxArguments &&
"Too many arguments to diagnostic!");
if (DiagObj) {
- DiagObj->DiagArgumentsKind[NumArgs] = Diagnostic::ak_std_string;
+ DiagObj->DiagArgumentsKind[NumArgs] = DiagnosticsEngine::ak_std_string;
DiagObj->DiagArgumentsStr[NumArgs++] = S;
}
}
- void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const {
- assert(NumArgs < Diagnostic::MaxArguments &&
+ void AddTaggedVal(intptr_t V, DiagnosticsEngine::ArgumentKind Kind) const {
+ assert(NumArgs < DiagnosticsEngine::MaxArguments &&
"Too many arguments to diagnostic!");
if (DiagObj) {
DiagObj->DiagArgumentsKind[NumArgs] = Kind;
@@ -770,15 +776,17 @@ public:
}
void AddFixItHint(const FixItHint &Hint) const {
- assert(NumFixItHints < Diagnostic::MaxFixItHints &&
+ assert(NumFixItHints < DiagnosticsEngine::MaxFixItHints &&
"Too many fix-it hints!");
+ if (NumFixItHints >= DiagnosticsEngine::MaxFixItHints)
+ return; // Don't crash in release builds
if (DiagObj)
DiagObj->FixItHints[NumFixItHints++] = Hint;
}
};
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
- llvm::StringRef S) {
+ StringRef S) {
DB.AddString(S);
return DB;
}
@@ -786,30 +794,30 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
const char *Str) {
DB.AddTaggedVal(reinterpret_cast<intptr_t>(Str),
- Diagnostic::ak_c_string);
+ DiagnosticsEngine::ak_c_string);
return DB;
}
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, int I) {
- DB.AddTaggedVal(I, Diagnostic::ak_sint);
+ DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint);
return DB;
}
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,bool I) {
- DB.AddTaggedVal(I, Diagnostic::ak_sint);
+ DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint);
return DB;
}
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
unsigned I) {
- DB.AddTaggedVal(I, Diagnostic::ak_uint);
+ DB.AddTaggedVal(I, DiagnosticsEngine::ak_uint);
return DB;
}
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
const IdentifierInfo *II) {
DB.AddTaggedVal(reinterpret_cast<intptr_t>(II),
- Diagnostic::ak_identifierinfo);
+ DiagnosticsEngine::ak_identifierinfo);
return DB;
}
@@ -823,7 +831,7 @@ typename llvm::enable_if<llvm::is_same<T, DeclContext>,
const DiagnosticBuilder &>::type
operator<<(const DiagnosticBuilder &DB, T *DC) {
DB.AddTaggedVal(reinterpret_cast<intptr_t>(DC),
- Diagnostic::ak_declcontext);
+ DiagnosticsEngine::ak_declcontext);
return DB;
}
@@ -848,33 +856,33 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
/// Report - Issue the message to the client. DiagID is a member of the
/// diag::kind enum. This actually returns a new instance of DiagnosticBuilder
/// which emits the diagnostics (through ProcessDiag) when it is destroyed.
-inline DiagnosticBuilder Diagnostic::Report(SourceLocation Loc,
+inline DiagnosticBuilder DiagnosticsEngine::Report(SourceLocation Loc,
unsigned DiagID){
assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!");
CurDiagLoc = Loc;
CurDiagID = DiagID;
return DiagnosticBuilder(this);
}
-inline DiagnosticBuilder Diagnostic::Report(unsigned DiagID) {
+inline DiagnosticBuilder DiagnosticsEngine::Report(unsigned DiagID) {
return Report(SourceLocation(), DiagID);
}
//===----------------------------------------------------------------------===//
-// DiagnosticInfo
+// Diagnostic
//===----------------------------------------------------------------------===//
-/// DiagnosticInfo - This is a little helper class (which is basically a smart
-/// pointer that forward info from Diagnostic) that allows clients to enquire
-/// about the currently in-flight diagnostic.
-class DiagnosticInfo {
- const Diagnostic *DiagObj;
- llvm::StringRef StoredDiagMessage;
+/// Diagnostic - This is a little helper class (which is basically a smart
+/// pointer that forward info from DiagnosticsEngine) that allows clients to
+/// enquire about the currently in-flight diagnostic.
+class Diagnostic {
+ const DiagnosticsEngine *DiagObj;
+ StringRef StoredDiagMessage;
public:
- explicit DiagnosticInfo(const Diagnostic *DO) : DiagObj(DO) {}
- DiagnosticInfo(const Diagnostic *DO, llvm::StringRef storedDiagMessage)
+ explicit Diagnostic(const DiagnosticsEngine *DO) : DiagObj(DO) {}
+ Diagnostic(const DiagnosticsEngine *DO, StringRef storedDiagMessage)
: DiagObj(DO), StoredDiagMessage(storedDiagMessage) {}
- const Diagnostic *getDiags() const { return DiagObj; }
+ const DiagnosticsEngine *getDiags() const { return DiagObj; }
unsigned getID() const { return DiagObj->CurDiagID; }
const SourceLocation &getLocation() const { return DiagObj->CurDiagLoc; }
bool hasSourceManager() const { return DiagObj->hasSourceManager(); }
@@ -884,49 +892,49 @@ public:
/// getArgKind - Return the kind of the specified index. Based on the kind
/// of argument, the accessors below can be used to get the value.
- Diagnostic::ArgumentKind getArgKind(unsigned Idx) const {
+ DiagnosticsEngine::ArgumentKind getArgKind(unsigned Idx) const {
assert(Idx < getNumArgs() && "Argument index out of range!");
- return (Diagnostic::ArgumentKind)DiagObj->DiagArgumentsKind[Idx];
+ return (DiagnosticsEngine::ArgumentKind)DiagObj->DiagArgumentsKind[Idx];
}
/// getArgStdStr - Return the provided argument string specified by Idx.
const std::string &getArgStdStr(unsigned Idx) const {
- assert(getArgKind(Idx) == Diagnostic::ak_std_string &&
+ assert(getArgKind(Idx) == DiagnosticsEngine::ak_std_string &&
"invalid argument accessor!");
return DiagObj->DiagArgumentsStr[Idx];
}
/// getArgCStr - Return the specified C string argument.
const char *getArgCStr(unsigned Idx) const {
- assert(getArgKind(Idx) == Diagnostic::ak_c_string &&
+ assert(getArgKind(Idx) == DiagnosticsEngine::ak_c_string &&
"invalid argument accessor!");
return reinterpret_cast<const char*>(DiagObj->DiagArgumentsVal[Idx]);
}
/// getArgSInt - Return the specified signed integer argument.
int getArgSInt(unsigned Idx) const {
- assert(getArgKind(Idx) == Diagnostic::ak_sint &&
+ assert(getArgKind(Idx) == DiagnosticsEngine::ak_sint &&
"invalid argument accessor!");
return (int)DiagObj->DiagArgumentsVal[Idx];
}
/// getArgUInt - Return the specified unsigned integer argument.
unsigned getArgUInt(unsigned Idx) const {
- assert(getArgKind(Idx) == Diagnostic::ak_uint &&
+ assert(getArgKind(Idx) == DiagnosticsEngine::ak_uint &&
"invalid argument accessor!");
return (unsigned)DiagObj->DiagArgumentsVal[Idx];
}
/// getArgIdentifier - Return the specified IdentifierInfo argument.
const IdentifierInfo *getArgIdentifier(unsigned Idx) const {
- assert(getArgKind(Idx) == Diagnostic::ak_identifierinfo &&
+ assert(getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo &&
"invalid argument accessor!");
return reinterpret_cast<IdentifierInfo*>(DiagObj->DiagArgumentsVal[Idx]);
}
/// getRawArg - Return the specified non-string argument in an opaque form.
intptr_t getRawArg(unsigned Idx) const {
- assert(getArgKind(Idx) != Diagnostic::ak_std_string &&
+ assert(getArgKind(Idx) != DiagnosticsEngine::ak_std_string &&
"invalid argument accessor!");
return DiagObj->DiagArgumentsVal[Idx];
}
@@ -959,12 +967,12 @@ public:
/// FormatDiagnostic - Format this diagnostic into a string, substituting the
/// formal arguments into the %0 slots. The result is appended onto the Str
/// array.
- void FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const;
+ void FormatDiagnostic(SmallVectorImpl<char> &OutStr) const;
/// FormatDiagnostic - Format the given format-string into the
/// output buffer using the arguments stored in this diagnostic.
void FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
- llvm::SmallVectorImpl<char> &OutStr) const;
+ SmallVectorImpl<char> &OutStr) const;
};
/**
@@ -973,7 +981,7 @@ public:
*/
class StoredDiagnostic {
unsigned ID;
- Diagnostic::Level Level;
+ DiagnosticsEngine::Level Level;
FullSourceLoc Loc;
std::string Message;
std::vector<CharSourceRange> Ranges;
@@ -981,18 +989,22 @@ class StoredDiagnostic {
public:
StoredDiagnostic();
- StoredDiagnostic(Diagnostic::Level Level, const DiagnosticInfo &Info);
- StoredDiagnostic(Diagnostic::Level Level, unsigned ID,
- llvm::StringRef Message);
+ StoredDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info);
+ StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
+ StringRef Message);
+ StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
+ StringRef Message, FullSourceLoc Loc,
+ ArrayRef<CharSourceRange> Ranges,
+ ArrayRef<FixItHint> Fixits);
~StoredDiagnostic();
/// \brief Evaluates true when this object stores a diagnostic.
operator bool() const { return Message.size() > 0; }
unsigned getID() const { return ID; }
- Diagnostic::Level getLevel() const { return Level; }
+ DiagnosticsEngine::Level getLevel() const { return Level; }
const FullSourceLoc &getLocation() const { return Loc; }
- llvm::StringRef getMessage() const { return Message; }
+ StringRef getMessage() const { return Message; }
void setLocation(FullSourceLoc Loc) { this->Loc = Loc; }
@@ -1007,20 +1019,20 @@ public:
unsigned fixit_size() const { return FixIts.size(); }
};
-/// DiagnosticClient - This is an abstract interface implemented by clients of
+/// DiagnosticConsumer - This is an abstract interface implemented by clients of
/// the front-end, which formats and prints fully processed diagnostics.
-class DiagnosticClient {
+class DiagnosticConsumer {
protected:
unsigned NumWarnings; // Number of warnings reported
unsigned NumErrors; // Number of errors reported
public:
- DiagnosticClient() : NumWarnings(0), NumErrors(0) { }
+ DiagnosticConsumer() : NumWarnings(0), NumErrors(0) { }
unsigned getNumErrors() const { return NumErrors; }
unsigned getNumWarnings() const { return NumWarnings; }
- virtual ~DiagnosticClient();
+ virtual ~DiagnosticConsumer();
/// BeginSourceFile - Callback to inform the diagnostic client that processing
/// of a source file is beginning.
@@ -1043,8 +1055,8 @@ public:
/// IncludeInDiagnosticCounts - This method (whose default implementation
/// returns true) indicates whether the diagnostics handled by this
- /// DiagnosticClient should be included in the number of diagnostics reported
- /// by Diagnostic.
+ /// DiagnosticConsumer should be included in the number of diagnostics
+ /// reported by DiagnosticsEngine.
virtual bool IncludeInDiagnosticCounts() const;
/// HandleDiagnostic - Handle this diagnostic, reporting it to the user or
@@ -1052,8 +1064,24 @@ public:
///
/// Default implementation just keeps track of the total number of warnings
/// and errors.
- virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
- const DiagnosticInfo &Info);
+ virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info);
+
+ /// \brief Clone the diagnostic consumer, producing an equivalent consumer
+ /// that can be used in a different context.
+ virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const = 0;
+};
+
+/// IgnoringDiagConsumer - This is a diagnostic client that just ignores all
+/// diags.
+class IgnoringDiagConsumer : public DiagnosticConsumer {
+ void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) {
+ // Just ignore it.
+ }
+ DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
+ return new IgnoringDiagConsumer();
+ }
};
} // end namespace clang
diff --git a/include/clang/Basic/Diagnostic.td b/include/clang/Basic/Diagnostic.td
index 50a22c4a9120..8ae69fef2783 100644
--- a/include/clang/Basic/Diagnostic.td
+++ b/include/clang/Basic/Diagnostic.td
@@ -18,8 +18,6 @@ def MAP_IGNORE : DiagMapping;
def MAP_WARNING : DiagMapping;
def MAP_ERROR : DiagMapping;
def MAP_FATAL : DiagMapping;
-def MAP_WARNING_NO_WERROR : DiagMapping;
-def MAP_WARNING_SHOW_IN_SYSTEM_HEADER : DiagMapping;
// Define the diagnostic classes.
class DiagClass;
@@ -59,6 +57,8 @@ class Diagnostic<string text, DiagClass DC, DiagMapping defaultmapping> {
DiagClass Class = DC;
bit SFINAE = 1;
bit AccessControl = 0;
+ bit WarningNoWerror = 0;
+ bit WarningShowInSystemHeader = 0;
DiagMapping DefaultMapping = defaultmapping;
DiagGroup Group;
string CategoryName = "";
@@ -77,9 +77,11 @@ class DefaultIgnore { DiagMapping DefaultMapping = MAP_IGNORE; }
class DefaultWarn { DiagMapping DefaultMapping = MAP_WARNING; }
class DefaultError { DiagMapping DefaultMapping = MAP_ERROR; }
class DefaultFatal { DiagMapping DefaultMapping = MAP_FATAL; }
-class DefaultWarnNoWerror { DiagMapping DefaultMapping= MAP_WARNING_NO_WERROR; }
+class DefaultWarnNoWerror {
+ bit WarningNoWerror = 1;
+}
class DefaultWarnShowInSystemHeader {
- DiagMapping DefaultMapping = MAP_WARNING_SHOW_IN_SYSTEM_HEADER;
+ bit WarningShowInSystemHeader = 1;
}
class NoSFINAE { bit SFINAE = 0; }
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index 7d45bc58463c..705c95b7fc27 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -57,6 +57,10 @@ def note_odr_number_of_bases : Note<
def note_odr_enumerator : Note<"enumerator %0 with value %1 here">;
def note_odr_missing_enumerator : Note<"no corresponding enumerator here">;
+def err_odr_field_type_inconsistent : Error<
+ "field %0 declared with incompatible types in different "
+ "translation units (%1 vs. %2)">;
+
// Importing Objective-C ASTs
def err_odr_ivar_type_inconsistent : Error<
"instance variable %0 declared with incompatible types in different "
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index 4b5de366cbc0..f9a910a1c21e 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -52,18 +52,31 @@ def err_invalid_storage_class_in_func_decl : Error<
"invalid storage class specifier in function declarator">;
def err_expected_namespace_name : Error<"expected namespace name">;
def ext_variadic_templates : ExtWarn<
- "variadic templates are a C++0x extension">, InGroup<CXX0x>;
+ "variadic templates are a C++11 extension">, InGroup<CXX11>;
+def warn_cxx98_compat_variadic_templates :
+ Warning<"variadic templates are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_default_special_members : Error<
"only special member functions may be defaulted">;
def err_friends_define_only_namespace_scope : Error<
"cannot define a function with non-namespace scope in a friend declaration">;
def err_deleted_non_function : Error<
"only functions can have deleted definitions">;
+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">;
// Sema && Lex
def ext_longlong : Extension<
"'long long' is an extension when C99 mode is not enabled">,
InGroup<LongLong>;
+def warn_cxx98_compat_longlong : Warning<
+ "'long long' is incompatible with C++98">,
+ InGroup<CXX98CompatPedantic>, DefaultIgnore;
def warn_integer_too_large : Warning<
"integer constant is too large for its type">;
def warn_integer_too_large_for_signed : Warning<
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index e33b67ef7a07..3c0e4f53d3c1 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -65,6 +65,9 @@ def err_drv_command_signalled : Error<
"%0 command failed due to signal %1 (use -v to see invocation)">;
def err_drv_invalid_mfloat_abi : Error<
"invalid float ABI '%0'">;
+def err_drv_invalid_libcxx_deployment : Error<
+ "invalid deployment target for -stdlib=libc++ (requires %0 or later)">;
+
def err_drv_I_dash_not_supported : Error<
"'%0' not supported, please use -iquote instead">;
def err_drv_unknown_argument : Error<"unknown argument: '%0'">;
@@ -123,4 +126,7 @@ def warn_drv_objc_gc_unsupported : Warning<
def warn_drv_pch_not_first_include : Warning<
"precompiled header '%0' was ignored because '%1' is not first '-include'">;
+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 120ba67dc1f6..fffa42feb2fb 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -112,139 +112,11 @@ def err_relocatable_without_isysroot : Error<
def warn_pch_target_triple : Error<
"PCH file was compiled for the target '%0' but the current translation "
"unit is being compiled for target '%1'">;
-def warn_pch_c99 : Error<
- "C99 support was %select{disabled|enabled}0 in PCH file but is "
- "currently %select{disabled|enabled}1">;
-def warn_pch_c1x : Error<
- "C1X support was %select{disabled|enabled}0 in PCH file but is "
- "currently %select{disabled|enabled}1">;
-def warn_pch_cplusplus : Error<
- "C++ support was %select{disabled|enabled}0 in PCH file but is "
- "currently %select{disabled|enabled}1">;
-def warn_pch_cplusplus0x : Error<
- "C++0x support was %select{disabled|enabled}0 in PCH file but is "
- "currently %select{disabled|enabled}1">;
-def warn_pch_objective_c : Error<
- "Objective-C support was %select{disabled|enabled}0 in PCH file but is "
- "currently %select{disabled|enabled}1">;
-def warn_pch_objective_c2 : Error<
- "Objective-C 2.0 support was %select{disabled|enabled}0 in PCH file but "
- "is currently %select{disabled|enabled}1">;
-def warn_pch_nonfragile_abi : Error<
- "PCH file was compiled with the %select{32-bit|non-fragile}0 Objective-C "
- "ABI but the %select{32-bit|non-fragile}1 Objective-C ABI is selected">;
-def warn_pch_nonfragile_abi2 : Error<
- "PCH file was compiled with the %select{32-bit|enhanced non-fragile}0 "
- "Objective-C ABI but the %select{32-bit|enhanced non-fragile}1 "
- "Objective-C ABI is selected">;
-def warn_pch_auto_ref_count : Error<
- "PCH file was compiled %select{without|with} automated reference counting,"
- "which is currently %select{disabled|enabled}">;
-def warn_pch_apple_kext : Error<
- "PCH file was compiled %select{with|without}0 support for Apple's kernel "
- "extensions ABI but it is currently %select{disabled|enabled}1">;
-def warn_pch_objc_auto_properties : Error<
- "PCH file was compiled %select{with|without}0 support for auto-synthesized "
- "@properties but it is currently %select{disabled|enabled}1">;
-def warn_pch_no_constant_cfstrings : Error<
- "Objctive-C NSstring generation support was %select{disabled|enabled}0 "
- "in PCH file but currently %select{disabled|enabled}1">;
-def warn_pch_extensions : Error<
- "extensions were %select{enabled|disabled}0 in PCH file but are "
- "currently %select{enabled|disabled}1">;
-def warn_pch_gnu_extensions : Error<
- "GNU extensions were %select{disabled|enabled}0 in PCH file but are "
- "currently %select{disabled|enabled}1">;
-def warn_pch_gnu_keywords : Error<
- "GNU keywords were %select{disabled|enabled}0 in PCH file but are "
- "currently %select{disabled|enabled}1">;
-def warn_pch_microsoft_extensions : Error<
- "Microsoft extensions were %select{disabled|enabled}0 in PCH file but are "
- "currently %select{disabled|enabled}1">;
-def warn_pch_ms_bitfields : Error<
- "Microsoft-compatible structure layout was %select{disabled|enabled}0 in "
- "PCH file but is currently %select{disabled|enabled}1">;
-def warn_pch_heinous_extensions : Error<
- "heinous extensions were %select{disabled|enabled}0 in PCH file but are "
- "currently %select{disabled|enabled}1">;
-def warn_pch_lax_vector_conversions : Error<
- "lax vector conversions were %select{disabled|enabled}0 in PCH file but "
- "are currently %select{disabled|enabled}1">;
-def warn_pch_altivec : Error<
- "AltiVec initializers were %select{disabled|enabled}0 in PCH file but "
- "are currently %select{disabled|enabled}1">;
-def warn_pch_opencl : Error<
- "OpenCL language extensions were %select{disabled|enabled}0 in PCH file "
- "but are currently %select{disabled|enabled}1">;
-def warn_pch_cuda : Error<
- "CUDA language extensions were %select{disabled|enabled}0 in PCH file "
- "but are currently %select{disabled|enabled}1">;
-def warn_pch_elide_constructors : Error<
- "Elidable copy constructors were %select{disabled|enabled}0 in PCH file "
- "but are currently %select{disabled|enabled}1">;
-def warn_pch_exceptions : Error<
- "exceptions were %select{disabled|enabled}0 in PCH file but "
- "are currently %select{disabled|enabled}1">;
-def warn_pch_objc_exceptions : Error<
- "Objective-C exceptions were %select{disabled|enabled}0 in PCH file but "
- "are currently %select{disabled|enabled}1">;
-def warn_pch_cxx_exceptions : Error<
- "C++ exceptions were %select{disabled|enabled}0 in PCH file but "
- "are currently %select{disabled|enabled}1">;
-def warn_pch_sjlj_exceptions : Error<
- "sjlj-exceptions were %select{disabled|enabled}0 in PCH file but "
- "are currently %select{disabled|enabled}1">;
-def warn_pch_objc_runtime : Error<
- "PCH file was compiled with the %select{NeXT|GNU}0 runtime but the "
- "%select{NeXT|GNU}1 runtime is selected">;
-def warn_pch_freestanding : Error<
- "PCH file was compiled with a %select{hosted|freestanding}0 "
- "implementation but a %select{hosted|freestanding}1 implementation "
- "is selected">;
-def warn_pch_builtins : Error<
- "PCH file was compiled with builtins %select{enabled|disabled}0 but "
- "builtins are currently %select{enabled|disabled}1">;
-def warn_pch_thread_safe_statics : Error<
- "PCH file was compiled %select{without|with}0 thread-safe statics but "
- "thread-safe statics are currently %select{disabled|enabled}1">;
-def warn_pch_posix_threads : Error<
- "PCH file was compiled %select{without|with}0 POSIX thread support but "
- "POSIX threads are currently %select{disabled|enabled}1">;
-def warn_pch_stack_protector : Error<
- "stack protector was %select{off|on|required}0 in PCH file but "
- "is currently %select{off|on|required}1">;
-def warn_pch_blocks : Error<
- "blocks were %select{disabled|enabled}0 in PCH file but "
- "are currently %select{disabled|enabled}1">;
-def warn_pch_math_errno : Error<
- "math functions %select{do not respect|respect}0 'errno' in PCH "
- "file but they are currently set to %select{not respect|respect}1 "
- "'errno'">;
-def warn_pch_optimize : Error<
- "the macro '__OPTIMIZE__' was %select{not defined|defined}0 in "
- "the PCH file but is currently %select{undefined|defined}1">;
-def warn_pch_optimize_size : Error<
- "the macro '__OPTIMIZE_SIZE__' was %select{not defined|defined}0 in "
- "the PCH file but is currently %select{undefined|defined}1">;
-def warn_pch_static : Error<
- "the PCH file was compiled %select{dynamic|static}0 but the "
- "current translation unit is being compiled as %select{dynamic|static}1">;
-def warn_pch_pic_level : Error<
- "PCH file was compiled with PIC level %0, but the current translation "
- "unit will be compiled with PIC level %1">;
-def warn_pch_gnu_inline : Error<
- "PCH file was compiled with %select{C99|GNU|}0 inline semantics but "
- "%select{C99|GNU}1 inline semantics are currently selected">;
-def warn_pch_no_inline : Error<
- "the macro '__NO_INLINE__' was %select{not defined|defined}0 in "
- "the PCH file but is currently %select{undefined|defined}1">;
-def warn_pch_deprecated : Error<
- "the macro '__DEPRECATED' was %select{not defined|defined}0 in "
- "the PCH file but is currently %select{undefined|defined}1">;
-def warn_pch_gc_mode : Error<
- "the PCH file was built with %select{no||hybrid}0 garbage collection but "
- "the current translation unit will compiled with %select{no||hybrid}1 "
- "garbage collection">;
+def err_pch_langopt_mismatch : Error<"%0 was %select{disabled|enabled}1 in "
+ "PCH file but is currently %select{disabled|enabled}2">;
+def err_pch_langopt_value_mismatch : Error<
+ "%0 differs in PCH file vs. current file">;
+
def warn_pch_version_too_old : Error<
"PCH file uses an older PCH format that is no longer supported">;
def warn_pch_version_too_new : Error<
@@ -266,18 +138,6 @@ def warn_macro_name_used_in_pch : Error<
def warn_pch_compiler_options_mismatch : Error<
"compiler options used when building the precompiled header differ from "
"the options used when using the precompiled header">;
-def warn_pch_access_control : Error<
- "C++ access control was %select{disabled|enabled}0 in the PCH file but "
- "is currently %select{disabled|enabled}1">;
-def warn_pch_char_signed : Error<
- "char was %select{unsigned|signed}0 in the PCH file but "
- "is currently %select{unsigned|signed}1">;
-def warn_pch_short_wchar : Error<
- "-fshort-wchar was %select{disabled|enabled}0 in the PCH file but "
- "is currently %select{disabled|enabled}1">;
-def warn_pch_short_enums : Error<
- "-fshort-enums was %select{disabled|enabled}0 in the PCH file but "
- "is currently %select{disabled|enabled}1">;
def err_not_a_pch_file : Error<
"'%0' does not appear to be a precompiled header file">, DefaultFatal;
@@ -291,6 +151,11 @@ def warn_unknown_warning_specifier : Warning<
"unknown %0 warning specifier: '%1'">,
InGroup<DiagGroup<"unknown-warning-option"> >;
-def warn_unkwown_analyzer_checker : Warning<
+def warn_unknown_analyzer_checker : Warning<
"no analyzer checkers are associated with '%0'">;
+def warn_incompatible_analyzer_plugin_api : Warning<
+ "checker plugin '%0' is not compatible with this version of the analyzer">,
+ InGroup<DiagGroup<"analyzer-incompatible-plugin"> >;
+def note_incompatible_analyzer_plugin_api : Note<
+ "current API version is '%0', but plugin was compiled with version '%1'">;
}
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 8a109149884f..49603eb69e44 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -54,9 +54,16 @@ def ExtraTokens : DiagGroup<"extra-tokens">;
def FormatExtraArgs : DiagGroup<"format-extra-args">;
def FormatZeroLength : DiagGroup<"format-zero-length">;
-def CXXHexFloats : DiagGroup<"c++-hex-floats">;
+def CXX98Compat : DiagGroup<"c++98-compat">;
+// Warnings for C++11 features which are Extensions in C++98 mode.
+def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic", [CXX98Compat]>;
+
+def CXX11Narrowing : DiagGroup<"c++11-narrowing">;
+def : DiagGroup<"c++0x-narrowing", [CXX11Narrowing]>;
+
+def CXX11Compat : DiagGroup<"c++11-compat", [CXX11Narrowing]>;
+def : DiagGroup<"c++0x-compat", [CXX11Compat]>;
-def : DiagGroup<"c++0x-compat", [CXXHexFloats]>;
def : DiagGroup<"effc++">;
def ExitTimeDestructors : DiagGroup<"exit-time-destructors">;
def FourByteMultiChar : DiagGroup<"four-char-constants">;
@@ -66,13 +73,15 @@ def BitwiseOpParentheses: DiagGroup<"bitwise-op-parentheses">;
def LogicalOpParentheses: DiagGroup<"logical-op-parentheses">;
def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">;
def : DiagGroup<"import">;
+def IncompatiblePointerTypes : DiagGroup<"incompatible-pointer-types">;
def : DiagGroup<"init-self">;
def : DiagGroup<"inline">;
def : DiagGroup<"int-to-pointer-cast">;
def : DiagGroup<"invalid-pch">;
def LiteralRange : DiagGroup<"literal-range">;
def LocalTypeTemplateArgs : DiagGroup<"local-type-template-args">;
-def : DiagGroup<"main">;
+def MalformedWarningCheck : DiagGroup<"malformed-warning-check">;
+def Main : DiagGroup<"main">;
def MissingBraces : DiagGroup<"missing-braces">;
def MissingDeclarations: DiagGroup<"missing-declarations">;
def : DiagGroup<"missing-format-attribute">;
@@ -84,6 +93,7 @@ def : DiagGroup<"newline-eof">;
def LongLong : DiagGroup<"long-long">;
def MismatchedTags : DiagGroup<"mismatched-tags">;
def MissingFieldInitializers : DiagGroup<"missing-field-initializers">;
+def ModuleBuild : DiagGroup<"module-build">;
def NullDereference : DiagGroup<"null-dereference">;
def InitializerOverrides : DiagGroup<"initializer-overrides">;
def NonNull : DiagGroup<"nonnull">;
@@ -95,6 +105,9 @@ def OutOfLineDeclaration : DiagGroup<"out-of-line-declaration">;
def : DiagGroup<"overflow">;
def OverlengthStrings : DiagGroup<"overlength-strings">;
def OverloadedVirtual : DiagGroup<"overloaded-virtual">;
+def ObjCMissingSuperCalls : DiagGroup<"objc-missing-super-calls">;
+def ObjCRetainBlockProperty : DiagGroup<"objc-noncopy-retain-block-property">;
+def ObjCContinuationPropertyType :DiagGroup<"objc-continuation-property-type">;
def Packed : DiagGroup<"packed">;
def Padded : DiagGroup<"padded">;
def PointerArith : DiagGroup<"pointer-arith">;
@@ -108,6 +121,8 @@ def ReturnType : DiagGroup<"return-type">;
def BindToTemporaryCopy : DiagGroup<"bind-to-temporary-copy">;
def SelfAssignment : DiagGroup<"self-assign">;
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 : DiagGroup<"shorten-64-to-32">;
@@ -152,6 +167,7 @@ def UnknownPragmas : DiagGroup<"unknown-pragmas">;
def UnknownAttributes : DiagGroup<"attributes">;
def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args">;
def UnusedArgument : DiagGroup<"unused-argument">;
+def UnusedComparison : DiagGroup<"unused-comparison">;
def UnusedExceptionParameter : DiagGroup<"unused-exception-parameter">;
def UnneededInternalDecl : DiagGroup<"unneeded-internal-declaration">;
def UnneededMemberFunction : DiagGroup<"unneeded-member-function">;
@@ -160,9 +176,11 @@ def UnusedMemberFunction : DiagGroup<"unused-member-function",
[UnneededMemberFunction]>;
def UnusedLabel : DiagGroup<"unused-label">;
def UnusedParameter : DiagGroup<"unused-parameter">;
-def UnusedValue : DiagGroup<"unused-value">;
+def UnusedResult : DiagGroup<"unused-result">;
+def UnusedValue : DiagGroup<"unused-value", [UnusedComparison, UnusedResult]>;
def UnusedVariable : DiagGroup<"unused-variable">;
def UsedButMarkedUnused : DiagGroup<"used-but-marked-unused">;
+def UserDefinedLiterals : DiagGroup<"user-defined-literals">;
def ReadOnlySetterAttrs : DiagGroup<"readonly-setter-attrs">;
def Reorder : DiagGroup<"reorder">;
def UndeclaredSelector : DiagGroup<"undeclared-selector">;
@@ -183,6 +201,7 @@ def Selector : DiagGroup<"selector">;
def NonfragileAbi2 : DiagGroup<"nonfragile-abi2">;
def Protocol : DiagGroup<"protocol">;
def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">;
+def OverridingMethodMismatch : DiagGroup<"overriding-method-mismatch">;
def : DiagGroup<"variadic-macros">;
def VariadicMacros : DiagGroup<"variadic-macros">;
def VectorConversions : DiagGroup<"vector-conversions">; // clang specific
@@ -202,9 +221,11 @@ def DuplicateArgDecl : DiagGroup<"duplicate-method-arg">;
// missing parentheses; it is off by default. We do not include it
// in -Wparentheses because most users who use -Wparentheses explicitly
// do not want these warnings.
+def ParenthesesOnEquality : DiagGroup<"parentheses-equality">;
def Parentheses : DiagGroup<"parentheses",
[LogicalOpParentheses,
- BitwiseOpParentheses]>;
+ BitwiseOpParentheses,
+ ParenthesesOnEquality]>;
// -Wconversion has its own warnings, but we split a few out for
// legacy reasons:
@@ -216,6 +237,7 @@ def Conversion : DiagGroup<"conversion",
[DiagGroup<"shorten-64-to-32">,
DiagGroup<"constant-conversion">,
DiagGroup<"literal-conversion">,
+ DiagGroup<"string-conversion">,
DiagGroup<"sign-conversion">,
BoolConversions]>,
DiagCategory<"Value Conversion Issue">;
@@ -228,11 +250,12 @@ def Unused : DiagGroup<"unused",
DiagCategory<"Unused Entity Issue">;
// Format settings.
+def FormatInvalidSpecifier : DiagGroup<"format-invalid-specifier">;
def FormatSecurity : DiagGroup<"format-security">;
def FormatY2K : DiagGroup<"format-y2k">;
def Format : DiagGroup<"format",
[FormatExtraArgs, FormatZeroLength, NonNull,
- FormatSecurity, FormatY2K]>,
+ FormatSecurity, FormatY2K, FormatInvalidSpecifier]>,
DiagCategory<"Format String Issue">;
def FormatNonLiteral : DiagGroup<"format-nonliteral", [FormatSecurity]>;
def Format2 : DiagGroup<"format=2",
@@ -243,6 +266,7 @@ def Extra : DiagGroup<"extra", [
IgnoredQualifiers,
InitializerOverrides,
SemiBeforeMethodBody,
+ MissingMethodReturnType,
SignCompare,
UnusedParameter
]>;
@@ -265,12 +289,15 @@ def Most : DiagGroup<"most", [
Uninitialized,
UnknownPragmas,
Unused,
- VectorConversions,
VolatileRegisterVar,
+ ObjCMissingSuperCalls,
OverloadedVirtual
]>;
-// -Wall is -Wmost -Wparentheses
+// Thread Safety warnings
+def ThreadSafety : DiagGroup<"thread-safety">;
+
+// -Wall is -Wmost -Wparentheses -Wtop-level-comparison
def : DiagGroup<"all", [Most, Parentheses]>;
// Aliases.
@@ -283,14 +310,16 @@ def : DiagGroup<"comments", [Comment]>; // -Wcomments = -Wcomment
def NonGCC : DiagGroup<"non-gcc",
[SignCompare, Conversion, LiteralRange]>;
-// A warning group for warnings about using C++0x features as extensions in
+// A warning group for warnings about using C++11 features as extensions in
// earlier C++ versions.
-def CXX0xStaticNonIntegralInitializer :
- DiagGroup<"c++0x-static-nonintegral-init">;
-def CXX0x : DiagGroup<"c++0x-extensions", [CXX0xStaticNonIntegralInitializer]>;
+def CXX11 : DiagGroup<"c++11-extensions">;
+def : DiagGroup<"c++0x-extensions", [CXX11]>;
def DelegatingCtorCycles :
DiagGroup<"delegating-ctor-cycles">;
+// A warning group for warnings about using C1X features as extensions.
+def C1X : DiagGroup<"c1x-extensions">;
+
// A warning group for warnings about GCC extensions.
def GNU : DiagGroup<"gnu", [GNUDesignator, VLA]>;
@@ -299,3 +328,4 @@ def Microsoft : DiagGroup<"microsoft">;
def ObjCNonUnifiedException : DiagGroup<"objc-nonunified-exceptions">;
+def ObjCProtocolMethodImpl : DiagGroup<"objc-protocol-method-implementation">;
diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h
index ae4ed5bbb13c..16d9b39985ed 100644
--- a/include/clang/Basic/DiagnosticIDs.h
+++ b/include/clang/Basic/DiagnosticIDs.h
@@ -16,10 +16,16 @@
#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 Diagnostic;
+ class DiagnosticsEngine;
class SourceLocation;
+ struct WarningOption;
// Import the diagnostic enums themselves.
namespace diag {
@@ -43,7 +49,7 @@ namespace clang {
// Get typedefs for common diagnostics.
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM,
+ SFINAE,ACCESS,CATEGORY,NOWERROR,SHOWINSYSHEADER,BRIEF,FULL) ENUM,
#include "clang/Basic/DiagnosticCommonKinds.inc"
NUM_BUILTIN_COMMON_DIAGNOSTICS
#undef DIAG
@@ -59,20 +65,47 @@ namespace clang {
MAP_IGNORE = 1, //< Map this diagnostic to nothing, ignore it.
MAP_WARNING = 2, //< Map this diagnostic to a warning.
MAP_ERROR = 3, //< Map this diagnostic to an error.
- MAP_FATAL = 4, //< Map this diagnostic to a fatal error.
-
- /// Map this diagnostic to "warning", but make it immune to -Werror. This
- /// happens when you specify -Wno-error=foo.
- MAP_WARNING_NO_WERROR = 5,
- /// Map this diagnostic to "warning", but make it immune to
- /// -Wno-system-headers.
- MAP_WARNING_SHOW_IN_SYSTEM_HEADER = 6,
- /// Map this diagnostic to "error", but make it immune to -Wfatal-errors.
- /// This happens for -Wno-fatal-errors=foo.
- MAP_ERROR_NO_WFATAL = 7
+ MAP_FATAL = 4 //< Map this diagnostic to a fatal error.
};
}
+class DiagnosticMappingInfo {
+ unsigned Mapping : 3;
+ unsigned IsUser : 1;
+ unsigned IsPragma : 1;
+ unsigned HasShowInSystemHeader : 1;
+ unsigned HasNoWarningAsError : 1;
+ unsigned HasNoErrorAsFatal : 1;
+
+public:
+ static DiagnosticMappingInfo Make(diag::Mapping Mapping, bool IsUser,
+ bool IsPragma) {
+ DiagnosticMappingInfo Result;
+ Result.Mapping = Mapping;
+ Result.IsUser = IsUser;
+ Result.IsPragma = IsPragma;
+ Result.HasShowInSystemHeader = 0;
+ Result.HasNoWarningAsError = 0;
+ Result.HasNoErrorAsFatal = 0;
+ return Result;
+ }
+
+ diag::Mapping getMapping() const { return diag::Mapping(Mapping); }
+ void setMapping(diag::Mapping Value) { Mapping = Value; }
+
+ bool isUser() const { return IsUser; }
+ bool isPragma() const { return IsPragma; }
+
+ bool hasShowInSystemHeader() const { return HasShowInSystemHeader; }
+ void setShowInSystemHeader(bool Value) { HasShowInSystemHeader = Value; }
+
+ bool hasNoWarningAsError() const { return HasNoWarningAsError; }
+ void setNoWarningAsError(bool Value) { HasNoWarningAsError = Value; }
+
+ bool hasNoErrorAsFatal() const { return HasNoErrorAsFatal; }
+ void setNoErrorAsFatal(bool Value) { HasNoErrorAsFatal = Value; }
+};
+
/// \brief Used for handling and querying diagnostic IDs. Can be used and shared
/// by multiple Diagnostics for multiple translation units.
class DiagnosticIDs : public llvm::RefCountedBase<DiagnosticIDs> {
@@ -93,7 +126,7 @@ public:
/// getCustomDiagID - 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 created, otherwise the existing ID is returned.
- unsigned getCustomDiagID(Level L, llvm::StringRef Message);
+ unsigned getCustomDiagID(Level L, StringRef Message);
//===--------------------------------------------------------------------===//
// Diagnostic classification and reporting interfaces.
@@ -101,14 +134,18 @@ public:
/// getDescription - Given a diagnostic ID, return a description of the
/// issue.
- llvm::StringRef getDescription(unsigned DiagID) const;
+ StringRef getDescription(unsigned DiagID) const;
- /// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic
- /// level of the specified diagnostic ID is a Warning or Extension.
- /// This only works on builtin diagnostics, not custom ones, and is not legal to
- /// call on NOTEs.
+ /// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic level
+ /// of the specified diagnostic ID is a Warning or Extension. This only works
+ /// on builtin diagnostics, not custom ones, and is not legal to call on
+ /// NOTEs.
static bool isBuiltinWarningOrExtension(unsigned DiagID);
+ /// \brief Return true if the specified diagnostic is mapped to errors by
+ /// default.
+ static bool isDefaultMappingAsError(unsigned DiagID);
+
/// \brief Determine whether the given built-in diagnostic ID is a
/// Note.
static bool isBuiltinNote(unsigned DiagID);
@@ -132,7 +169,7 @@ public:
/// getWarningOptionForDiag - Return the lowest-level warning option that
/// enables the specified diagnostic. If there is no -Wfoo flag that controls
/// the diagnostic, this returns null.
- static llvm::StringRef getWarningOptionForDiag(unsigned DiagID);
+ static StringRef getWarningOptionForDiag(unsigned DiagID);
/// getCategoryNumberForDiag - Return the category number that a specified
/// DiagID belongs to, or 0 if no category.
@@ -143,7 +180,7 @@ public:
/// getCategoryNameFromID - Given a category ID, return the name of the
/// category.
- static llvm::StringRef getCategoryNameFromID(unsigned CategoryID);
+ static StringRef getCategoryNameFromID(unsigned CategoryID);
/// \brief Enumeration describing how the the emission of a diagnostic should
/// be treated when it occurs during C++ template argument deduction.
@@ -182,56 +219,80 @@ public:
static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID);
/// getName - Given a diagnostic ID, return its name
- static llvm::StringRef getName(unsigned DiagID);
+ static StringRef getName(unsigned DiagID);
/// getIdFromName - Given a diagnostic name, return its ID, or 0
- static unsigned getIdFromName(llvm::StringRef Name);
+ static unsigned getIdFromName(StringRef Name);
/// getBriefExplanation - Given a diagnostic ID, return a brief explanation
/// of the issue
- static llvm::StringRef getBriefExplanation(unsigned DiagID);
+ static StringRef getBriefExplanation(unsigned DiagID);
/// getFullExplanation - Given a diagnostic ID, return a full explanation
/// of the issue
- static llvm::StringRef getFullExplanation(unsigned DiagID);
+ static StringRef getFullExplanation(unsigned DiagID);
+
+ /// Iterator class used for traversing all statically declared
+ /// diagnostics.
+ class diag_iterator {
+ const void *impl;
-private:
- /// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g.
- /// "unknown-pragmas" to have the specified mapping. This returns true and
- /// ignores the request if "Group" was unknown, false otherwise.
- bool setDiagnosticGroupMapping(llvm::StringRef Group, diag::Mapping Map,
- SourceLocation Loc, Diagnostic &Diag) const;
+ friend class DiagnosticIDs;
+ diag_iterator(const void *im) : impl(im) {}
+ public:
+ diag_iterator &operator++();
+ bool operator==(const diag_iterator &x) const { return impl == x.impl; }
+ bool operator!=(const diag_iterator &x) const { return impl != x.impl; }
+
+ llvm::StringRef getDiagName() const;
+ unsigned getDiagID() const;
+ };
- /// \brief Based on the way the client configured the Diagnostic
+ static diag_iterator diags_begin();
+ static diag_iterator diags_end();
+
+ /// \brief Get the set of all diagnostic IDs in the group with the given name.
+ ///
+ /// \param Diags [out] - On return, the diagnostics in the group.
+ /// \returns True if the given group is unknown, false otherwise.
+ bool getDiagnosticsInGroup(StringRef Group,
+ llvm::SmallVectorImpl<diag::kind> &Diags) const;
+
+private:
+ /// \brief Get the set of all diagnostic IDs in the given group.
+ ///
+ /// \param Diags [out] - On return, the diagnostics in the group.
+ void getDiagnosticsInGroup(const WarningOption *Group,
+ llvm::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
/// the DiagnosticClient.
///
/// \param Loc The source location we are interested in finding out the
/// diagnostic state. Can be null in order to query the latest state.
DiagnosticIDs::Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
- const Diagnostic &Diag,
- diag::Mapping *mapping = 0) const;
+ const DiagnosticsEngine &Diag) const;
/// getDiagnosticLevel - This is an internal implementation helper used when
/// DiagClass is already known.
DiagnosticIDs::Level getDiagnosticLevel(unsigned DiagID,
unsigned DiagClass,
SourceLocation Loc,
- const Diagnostic &Diag,
- diag::Mapping *mapping = 0) const;
+ const DiagnosticsEngine &Diag) const;
/// ProcessDiag - This is the method used to report a diagnostic that is
/// finally fully formed.
///
/// \returns true if the diagnostic was emitted, false if it was
/// suppressed.
- bool ProcessDiag(Diagnostic &Diag) const;
+ bool ProcessDiag(DiagnosticsEngine &Diag) const;
/// \brief Whether the diagnostic may leave the AST in a state where some
/// invariants can break.
bool isUnrecoverable(unsigned DiagID) const;
- friend class Diagnostic;
+ friend class DiagnosticsEngine;
};
} // end namespace clang
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index 38d6a8001655..9b3a178cac78 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -24,6 +24,11 @@ def escaped_newline_block_comment_end : Warning<
def backslash_newline_space : Warning<
"backslash and newline separated by space">;
+// Digraphs.
+def warn_cxx98_compat_less_colon_colon : Warning<
+ "'<::' is treated as digraph '<:' (aka '[') followed by ':' in C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
+
// Trigraphs.
def trigraph_ignored : Warning<"trigraph ignored">, InGroup<Trigraphs>;
def trigraph_ignored_block_comment : Warning<
@@ -38,12 +43,16 @@ def ext_multi_line_bcpl_comment : Extension<"multi-line // comment">,
def ext_bcpl_comment : Extension<
"// comments are not allowed in this language">,
InGroup<Comment>;
-def ext_no_newline_eof : Extension<"no newline at end of file">;
-def ext_backslash_newline_eof : Extension<"backslash-newline at end of file">;
+def ext_no_newline_eof : Extension<"no newline at end of file">,
+ InGroup<DiagGroup<"newline-eof">>;
def ext_dollar_in_identifier : Extension<"'$' in identifier">;
def charize_microsoft_ext : Extension<"@# is a microsoft extension">;
-def ext_token_used : Extension<"extension used">;
+def ext_token_used : Extension<"extension used">,
+ InGroup<DiagGroup<"language-extension-token">>;
+
+def warn_cxx11_keyword : Warning<"'%0' is a keyword in C++11">,
+ InGroup<CXX11Compat>;
def warn_unterminated_string : ExtWarn<"missing terminating '\"' character">;
def warn_unterminated_char : ExtWarn<"missing terminating ' character">;
@@ -55,6 +64,18 @@ def err_unterminated___pragma : Error<"missing terminating ')' character">;
def err_conflict_marker : Error<"version control conflict marker in file">;
+def err_raw_delim_too_long : Error<
+ "raw string delimiter longer than 16 characters"
+ "; use PREFIX( )PREFIX to delimit raw string">;
+def err_invalid_char_raw_delim : Error<
+ "invalid character '%0' character in raw string delimiter"
+ "; use PREFIX( )PREFIX to delimit raw string">;
+def err_unterminated_raw_string : Error<
+ "raw string missing terminating delimiter )%0\"">;
+def warn_cxx98_compat_raw_string_literal : Warning<
+ "raw string literals are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
+
def ext_multichar_character_literal : ExtWarn<
"multi-character character constant">, InGroup<MultiChar>;
def ext_four_char_character_literal : Extension<
@@ -77,17 +98,14 @@ def err_invalid_suffix_integer_constant : Error<
"invalid suffix '%0' on integer constant">;
def err_invalid_suffix_float_constant : Error<
"invalid suffix '%0' on floating constant">;
-def warn_extraneous_wide_char_constant : Warning<
- "extraneous characters in wide character constant ignored">;
+def warn_extraneous_char_constant : Warning<
+ "extraneous characters in character constant ignored">;
def warn_char_constant_too_large : Warning<
"character constant too long for its type">;
def err_exponent_has_no_digits : Error<"exponent has no digits">;
def ext_imaginary_constant : Extension<"imaginary constants are an extension">;
def err_hexconstant_requires_exponent : Error<
"hexadecimal floating constants require an exponent">;
-def ext_hexconstant_cplusplus : Extension<
- "hexadecimal floating constants are a C99 feature that is incompatible with "
- "C++0x">, InGroup<CXXHexFloats>;
def ext_hexconstant_invalid : Extension<
"hexadecimal floating constants are a C99 feature">;
def ext_binary_literal : Extension<
@@ -102,6 +120,11 @@ def warn_ucn_escape_too_large : ExtWarn<
"character unicode escape sequence too long for its type">;
def warn_ucn_not_valid_in_c89 : ExtWarn<
"unicode escape sequences are only valid in C99 or C++">;
+def warn_cxx98_compat_unicode_literal : Warning<
+ "unicode literals are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
+def err_unsupported_string_concat : Error<
+ "unsupported non-standard concatenation of string literals">;
//===----------------------------------------------------------------------===//
// PTH Diagnostics
@@ -167,6 +190,9 @@ def ext_pp_bad_vaargs_use : Extension<
def ext_pp_macro_redef : ExtWarn<"%0 macro redefined">;
def ext_variadic_macro : Extension<"variadic macros were introduced in C99">,
InGroup<VariadicMacros>;
+def warn_cxx98_compat_variadic_macro : Warning<
+ "variadic macros are incompatible with C++98">,
+ InGroup<CXX98CompatPedantic>, DefaultIgnore;
def ext_named_variadic_macro : Extension<
"named variadic macros are a GNU extension">, InGroup<VariadicMacros>;
def ext_embedded_directive : Extension<
@@ -175,10 +201,13 @@ def ext_missing_varargs_arg : Extension<
"varargs argument missing, but tolerated as an extension">;
def ext_empty_fnmacro_arg : Extension<
"empty macro arguments were standardized in C99">;
+def warn_cxx98_compat_empty_fnmacro_arg : Warning<
+ "empty macro argument list is incompatible with C++98">,
+ InGroup<CXX98CompatPedantic>, DefaultIgnore;
def err_pp_invalid_directive : Error<"invalid preprocessing directive">;
def err_pp_hash_error : Error<"#error%0">;
-def warn_pp_file_not_found : Warning<"'%0' file not found">, DefaultFatal;
+def err_pp_file_not_found : Error<"'%0' file not found">, DefaultFatal;
def err_pp_error_opening_file : Error<
"error opening file '%0': %1">, DefaultFatal;
def err_pp_empty_filename : Error<"empty filename">;
@@ -230,6 +259,13 @@ def err_pp_used_poisoned_id : Error<"attempt to use a poisoned identifier">;
def err_feature_check_malformed : Error<
"builtin feature check macro requires a parenthesized identifier">;
+def err_warning_check_malformed : Error<
+ "builtin warning check macro requires a parenthesized string">,
+ InGroup<MalformedWarningCheck>;
+def warn_has_warning_invalid_option :
+ ExtWarn<"__has_warning expected option name (e.g. \"-Wundef\")">,
+ InGroup<MalformedWarningCheck>;
+
def err__Pragma_malformed : Error<
"_Pragma takes a parenthesized string literal">;
def err_pragma_comment_malformed : Error<
@@ -315,5 +351,20 @@ def err_pp_linemarker_invalid_pop : Error<
"invalid line marker flag '2': cannot pop empty include stack">;
def ext_pp_line_too_big : Extension<
"C requires #line number to be less than %0, allowed as extension">;
+def warn_cxx98_compat_pp_line_too_big : Warning<
+ "#line number greater than 32767 is incompatible with C++98">,
+ InGroup<CXX98CompatPedantic>, DefaultIgnore;
+
+def err_pp_export_non_macro : Error<"no macro named %0 to export">;
+
+def err_pp_arc_cf_code_audited_syntax : Error<"expected 'begin' or 'end'">;
+def err_pp_double_begin_of_arc_cf_code_audited : Error<
+ "already inside '#pragma clang arc_cf_code_audited'">;
+def err_pp_unmatched_end_of_arc_cf_code_audited : Error<
+ "not currently inside '#pragma clang arc_cf_code_audited'">;
+def err_pp_include_in_arc_cf_code_audited : Error<
+ "cannot #include files inside '#pragma clang arc_cf_code_audited'">;
+def err_pp_eof_in_arc_cf_code_audited : Error<
+ "'#pragma clang arc_cf_code_audited' was not ended within this file">;
}
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 3764a4091546..73437b217b18 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -28,10 +28,6 @@ def ext_extra_struct_semi : Extension<
def ext_extra_ivar_semi : Extension<
"extra ';' inside instance variable list">;
-def auto_storage_class : ExtWarn<
- "'auto' storage class specifier is redundant and will be "
- "removed in future releases">;
-
def ext_duplicate_declspec : Extension<"duplicate '%0' declaration specifier">;
def ext_plain_complex : ExtWarn<
"plain '_Complex' requires a type specifier; assuming '_Complex double'">;
@@ -57,7 +53,7 @@ def ext_c99_variable_decl_in_for_loop : Extension<
def ext_c99_compound_literal : Extension<
"compound literals are a C99-specific feature">;
def ext_enumerator_list_comma : Extension<
- "commas at the end of enumerator lists are a %select{C99|C++0x}0-specific "
+ "commas at the end of enumerator lists are a %select{C99|C++11}0-specific "
"feature">;
def err_enumerator_list_missing_comma : Error<
"missing ',' between enumerators">;
@@ -68,12 +64,15 @@ def ext_ms_enum_fixed_underlying_type : Extension<
InGroup<Microsoft>;
def ext_c1x_generic_selection : Extension<
- "generic selections are a C1X-specific feature">;
+ "generic selections are a C1X-specific feature">, InGroup<C1X>;
def err_duplicate_default_assoc : Error<
"duplicate default generic association">;
def note_previous_default_assoc : Note<
"previous default generic association is here">;
+def ext_c1x_alignas : Extension<
+ "_Alignas is a C1X-specific feature">, InGroup<C1X>;
+
def ext_gnu_indirect_goto : Extension<
"use of GNU indirect-goto extension">, InGroup<GNU>;
def ext_gnu_address_of_label : Extension<
@@ -188,16 +187,26 @@ def err_invalid_reference_qualifier_application : Error<
def err_illegal_decl_reference_to_reference : Error<
"%0 declared as a reference to a reference">;
def ext_rvalue_reference : ExtWarn<
- "rvalue references are a C++0x extension">, InGroup<CXX0x>;
+ "rvalue references are a C++11 extension">, InGroup<CXX11>;
def ext_ref_qualifier : ExtWarn<
- "reference qualifiers on functions are a C++0x extension">, InGroup<CXX0x>;
+ "reference qualifiers on functions are a C++11 extension">, InGroup<CXX11>;
def ext_inline_namespace : ExtWarn<
- "inline namespaces are a C++0x feature">, InGroup<CXX0x>;
+ "inline namespaces are a C++11 feature">, InGroup<CXX11>;
def err_generalized_initializer_lists : Error<
- "generalized initializer lists are a C++0x extension unsupported in Clang">;
+ "generalized initializer lists are a C++11 extension unsupported in Clang">;
def ext_generalized_initializer_lists : ExtWarn<
- "generalized initializer lists are a C++0x extension unsupported in Clang">,
- InGroup<CXX0x>;
+ "generalized initializer lists are a C++11 extension unsupported in Clang">,
+ InGroup<CXX11>;
+def ext_auto_type_specifier : ExtWarn<
+ "'auto' type specifier is a C++11 extension">, InGroup<CXX11>;
+def warn_auto_storage_class : Warning<
+ "'auto' storage class specifier is redundant and incompatible with C++11">,
+ InGroup<CXX11Compat>;
+def ext_auto_storage_class : ExtWarn<
+ "'auto' storage class specifier is not permitted in C++11, and will not "
+ "be supported in future releases">;
+def ext_for_range : ExtWarn<
+ "range-based for loop is a C++11 extension">, InGroup<CXX11>;
def err_argument_required_after_attribute : Error<
"argument required after attribute">;
def err_missing_param : Error<"expected parameter declarator">;
@@ -219,6 +228,9 @@ def err_typename_invalid_storageclass : Error<
"type name does not allow storage class to be specified">;
def err_typename_invalid_functionspec : Error<
"type name does not allow function specifier to be specified">;
+def err_typename_identifiers_only : Error<
+ "typename is allowed for identifiers only">;
+
def err_invalid_decl_spec_combination : Error<
"cannot combine with previous '%0' declaration specifier">;
def err_invalid_vector_decl_spec_combination : Error<
@@ -250,7 +262,7 @@ def err_unexected_colon_in_nested_name_spec : Error<
def err_bool_redeclaration : Error<
"redeclaration of C++ built-in type 'bool'">;
def ext_c1x_static_assert : Extension<
- "_Static_assert is a C1X-specific feature">;
+ "_Static_assert is a C1X-specific feature">, InGroup<C1X>;
/// Objective-C parser diagnostics
def err_expected_minus_or_plus : Error<
@@ -342,6 +354,8 @@ 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;
// C++ derived classes
def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
@@ -357,10 +371,15 @@ def err_default_delete_in_multiple_declaration : Error<
"'= %select{default|delete}0' is a function definition and must occur in a "
"standalone declaration">;
+def warn_cxx98_compat_alignas : Warning<"'alignas' is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
+def warn_cxx98_compat_attribute : Warning<
+ "attributes are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_cxx0x_attribute_forbids_arguments : Error<
- "C++0x attribute '%0' cannot have an argument list">;
+ "C++11 attribute '%0' cannot have an argument list">;
def err_cxx0x_attribute_requires_arguments : Error<
- "C++0x attribute '%0' must have an argument list">;
+ "C++1 attribute '%0' must have an argument list">;
def err_attributes_not_allowed : Error<"an attribute list cannot appear here">;
/// C++ Templates
@@ -385,7 +404,7 @@ def err_two_right_angle_brackets_need_space : Error<
"a space is required between consecutive right angle brackets (use '> >')">;
def warn_cxx0x_right_shift_in_template_arg : Warning<
"use of right-shift operator ('>>') in template argument will require "
- "parentheses in C++0x">;
+ "parentheses in C++11">;
def err_multiple_template_declarators : Error<
"%select{|a template declaration|an explicit template specialization|"
"an explicit template instantiation}0 can "
@@ -446,31 +465,31 @@ def err_missing_whitespace_digraph : Error<
" which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?">;
def warn_deleted_function_accepted_as_extension: ExtWarn<
- "deleted function definition accepted as a C++0x extension">, InGroup<CXX0x>;
+ "deleted function definition accepted as a C++11 extension">, InGroup<CXX11>;
def warn_defaulted_function_accepted_as_extension: ExtWarn<
- "defaulted function definition accepted as a C++0x extension">,
- InGroup<CXX0x>;
+ "defaulted function definition accepted as a C++11 extension">,
+ InGroup<CXX11>;
-// C++0x in-class member initialization
+// C++11 in-class member initialization
def warn_nonstatic_member_init_accepted_as_extension: ExtWarn<
- "in-class initialization of non-static data member accepted as a C++0x extension">,
- InGroup<CXX0x>;
+ "in-class initialization of non-static data member accepted as a C++11 extension">,
+ InGroup<CXX11>;
def err_bitfield_member_init: Error<
"bitfield member cannot have an in-class initializer">;
def err_incomplete_array_member_init: Error<
"array bound cannot be deduced from an in-class initializer">;
-// C++0x alias-declaration
+// C++11 alias-declaration
def ext_alias_declaration : ExtWarn<
- "alias declarations accepted as a C++0x extension">, InGroup<CXX0x>;
+ "alias declarations accepted as a C++11 extension">, InGroup<CXX11>;
def err_alias_declaration_not_identifier : Error<
"name defined in alias declaration must be an identifier">;
def err_alias_declaration_specialization : Error<
"%select{partial specialization|explicit specialization|explicit instantiation}0 of alias templates is not permitted">;
-// C++0x override control
+// C++11 override control
def ext_override_control_keyword : Extension<
- "'%0' keyword accepted as a C++0x extension">, InGroup<CXX0x>;
+ "'%0' keyword accepted as a C++11 extension">, InGroup<CXX11>;
def err_duplicate_virt_specifier : Error<
"class member already marked '%0'">;
@@ -487,6 +506,15 @@ def err_paren_sizeof_parameter_pack : Error<
def err_sizeof_parameter_pack : Error<
"expected parenthesized parameter pack name in 'sizeof...' expression">;
+// C++11 lambda expressions
+def err_expected_comma_or_rsquare : Error<
+ "expected ',' or ']' in lambda capture list">;
+def err_this_captured_by_reference : Error<
+ "'this' cannot be captured by reference">;
+def err_expected_capture : Error<
+ "expected variable name or 'this' in lambda capture list">;
+def err_expected_lambda_body : Error<"expected body of lambda expression">;
+
// Availability attribute
def err_expected_version : Error<
"expected a version of the form 'major[.minor[.subminor]]'">;
@@ -559,6 +587,14 @@ def err_seh___except_filter : Error<
def err_seh___finally_block : Error<
"%0 only allowed in __finally block">;
-
+
} // end of Parse Issue category.
+
+let CategoryName = "Modules Issue" in {
+def err_module_expected_ident : Error<
+ "expected a module name after '__import_module__'">;
+def err_module_expected_semi : Error<
+ "expected a semicolon name after module name">;
+}
+
} // end of Parser diagnostics
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 97414f23d796..0fbf0cee0a5d 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -23,7 +23,8 @@ def ext_expr_not_ice : Extension<
// Semantic analysis of constant literals.
def ext_predef_outside_function : Warning<
- "predefined identifier is only valid inside function">;
+ "predefined identifier is only valid inside function">,
+ InGroup<DiagGroup<"predefined-identifier-outside-function">>;
def warn_float_overflow : Warning<
"magnitude of floating-point constant too large for type %0; maximum is %1">,
InGroup<LiteralRange>;
@@ -102,7 +103,7 @@ def ext_flexible_array_init : Extension<
def ext_anon_param_requires_type_specifier : Extension<
"type specifier required for unnamed parameter, defaults to int">;
def err_bad_variable_name : Error<
- "'%0' cannot be the name of a variable or data member">;
+ "%0 cannot be the name of a variable or data member">;
def err_bad_parameter_name : Error<
"'%0' cannot be the name of a parameter">;
def err_parameter_name_omitted : Error<"parameter name omitted">;
@@ -236,10 +237,10 @@ def err_maybe_falloff_nonvoid_block : Error<
def err_falloff_nonvoid_block : Error<
"control reaches end of non-void block">;
def warn_suggest_noreturn_function : Warning<
- "function could be attribute 'noreturn'">,
+ "%select{function|method}0 %1 could be declared with attribute 'noreturn'">,
InGroup<DiagGroup<"missing-noreturn">>, DefaultIgnore;
def warn_suggest_noreturn_block : Warning<
- "block could be attribute 'noreturn'">,
+ "block could be declared with attribute 'noreturn'">,
InGroup<DiagGroup<"missing-noreturn">>, DefaultIgnore;
def warn_unreachable : Warning<"will never be executed">,
InGroup<DiagGroup<"unreachable-code">>, DefaultIgnore;
@@ -264,8 +265,9 @@ def err_types_compatible_p_in_cplusplus : Error<
"__builtin_types_compatible_p is not valid in C++">;
def warn_builtin_unknown : Warning<"use of unknown builtin %0">, DefaultError;
def warn_dyn_class_memaccess : Warning<
- "%select{destination for|source of}0 this %1 call is a pointer to dynamic "
- "class %2; vtable pointer will be overwritten">,
+ "%select{destination for|source of|first operand of|second operand of}0 this "
+ "%1 call is a pointer to dynamic class %2; vtable pointer will be "
+ "%select{overwritten|copied|moved|compared}3">,
InGroup<DiagGroup<"dynamic-class-memaccess">>;
def note_bad_memaccess_silence : Note<
"explicitly cast the pointer to silence this warning">;
@@ -278,18 +280,25 @@ 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">>;
+def warn_strlcpycat_wrong_size : Warning<
+ "size argument in %0 call appears to be size of the source; expected the size of "
+ "the destination">,
+ InGroup<DiagGroup<"strlcpy-strlcat-size">>;
+def note_strlcpycat_wrong_size : Note<
+ "change size argument to be the size of the destination">;
/// main()
// static/inline main() are not errors in C, just in C++.
-def warn_unusual_main_decl : Warning<"'main' should not be declared "
- "%select{static|inline|static or inline}0">;
-def err_unusual_main_decl : Error<"'main' is not allowed to be declared "
- "%select{static|inline|static or inline}0">;
+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 err_main_template_decl : Error<"'main' cannot be a template">;
def err_main_returns_nonint : Error<"'main' must return '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">;
+def warn_main_one_arg : Warning<"only one parameter on 'main' declaration">,
+ InGroup<Main>;
def err_main_arg_wrong : Error<"%select{first|second|third|fourth}0 "
"parameter of 'main' (%select{argument count|argument array|environment|"
"platform-specific data}0) must be of type %1">;
@@ -303,6 +312,8 @@ def err_statically_allocated_object : Error<
def err_object_cannot_be_passed_returned_by_value : Error<
"interface type %1 cannot be %select{returned|passed}0 by value"
"; did you forget * in %1">;
+def err_parameters_retval_cannot_have_fp16_type : Error<
+ "%select{parameters|function return value}0 cannot have __fp16 type; did you forget * ?">;
def warn_enum_value_overflow : Warning<"overflow in enumeration value">;
def warn_pragma_options_align_unsupported_option : Warning<
"unsupported alignment option in '#pragma options align'">;
@@ -383,27 +394,75 @@ 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">;
+def warn_conflicting_overriding_ret_types : Warning<
+ "conflicting return type in "
+ "declaration of %0: %1 vs %2">,
+ InGroup<OverridingMethodMismatch>, DefaultIgnore;
+
def warn_conflicting_ret_types : Warning<
- "conflicting return type in implementation of %0: %1 vs %2">;
+ "conflicting return type in "
+ "implementation of %0: %1 vs %2">;
+
+def warn_conflicting_overriding_ret_type_modifiers : Warning<
+ "conflicting distributed object modifiers on return type "
+ "in declaration of %0">,
+ InGroup<OverridingMethodMismatch>, DefaultIgnore;
+
def warn_conflicting_ret_type_modifiers : Warning<
"conflicting distributed object modifiers on return type "
"in implementation of %0">,
InGroup<DiagGroup<"distributed-object-modifiers">>;
+
+def warn_non_covariant_overriding_ret_types : Warning<
+ "conflicting return type in "
+ "declaration of %0: %1 vs %2">,
+ InGroup<OverridingMethodMismatch>, DefaultIgnore;
+
def warn_non_covariant_ret_types : Warning<
- "conflicting return type in implementation of %0: %1 vs %2">,
+ "conflicting return type in "
+ "implementation of %0: %1 vs %2">,
InGroup<DiagGroup<"method-signatures">>, DefaultIgnore;
+def warn_conflicting_overriding_param_types : Warning<
+ "conflicting parameter types in "
+ "declaration of %0: %1 vs %2">,
+ InGroup<OverridingMethodMismatch>, DefaultIgnore;
+
def warn_conflicting_param_types : Warning<
- "conflicting parameter types in implementation of %0: %1 vs %2">;
+ "conflicting parameter types in "
+ "implementation of %0: %1 vs %2">;
def warn_conflicting_param_modifiers : Warning<
"conflicting distributed object modifiers on parameter type "
"in implementation of %0">,
InGroup<DiagGroup<"distributed-object-modifiers">>;
+
+def warn_conflicting_overriding_param_modifiers : Warning<
+ "conflicting distributed object modifiers on parameter type "
+ "in declaration of %0">,
+ InGroup<OverridingMethodMismatch>, DefaultIgnore;
+
+def warn_non_contravariant_overriding_param_types : Warning<
+ "conflicting parameter types in "
+ "declaration of %0: %1 vs %2">,
+ InGroup<OverridingMethodMismatch>, DefaultIgnore;
+
def warn_non_contravariant_param_types : Warning<
- "conflicting parameter types in implementation of %0: %1 vs %2">,
+ "conflicting parameter types in "
+ "implementation of %0: %1 vs %2">,
InGroup<DiagGroup<"method-signatures">>, DefaultIgnore;
+
+def warn_conflicting_overriding_variadic :Warning<
+ "conflicting variadic declaration of method and its "
+ "implementation">,
+ InGroup<OverridingMethodMismatch>, DefaultIgnore;
+
def warn_conflicting_variadic :Warning<
- "conflicting variadic declaration of method and its implementation">;
+ "conflicting variadic declaration of method and its "
+ "implementation">;
+
+def warn_category_method_impl_match:Warning<
+ "category is implementing a method which will also be implemented"
+ " by its primary class">, InGroup<ObjCProtocolMethodImpl>;
def warn_implements_nscopying : Warning<
"default assign attribute on property %0 which implements "
@@ -437,12 +496,22 @@ def warn_property_attr_mismatch : Warning<
def warn_objc_property_copy_missing_on_block : Warning<
"'copy' attribute must be specified for the block property "
"when -fobjc-gc-only is specified">;
+def warn_objc_property_retain_of_block : Warning<
+ "retain'ed block property does not copy the block "
+ "- use copy attribute instead">, InGroup<ObjCRetainBlockProperty>;
def warn_atomic_property_rule : Warning<
- "writable atomic property %0 cannot pair a synthesized setter/getter "
- "with a user defined setter/getter">;
-def warn_ownin_getter_rule : Warning<
+ "writable atomic property %0 cannot pair a synthesized %select{getter|setter}1 "
+ "with a user defined %select{getter|setter}2">,
+ InGroup<DiagGroup<"atomic-property-with-user-defined-accessor">>;
+def note_atomic_property_fixup_suggest : Note<"setter and getter must both be "
+ "synthesized, or both be user defined,or the property must be nonatomic">;
+def warn_atomic_property_nontrivial_assign_op : Warning<
+ "atomic property of type %0 synthesizing setter using non-trivial assignment"
+ " operator">, InGroup<DiagGroup<"objc-property-atomic-setter-synthesis">>;
+def warn_owning_getter_rule : Warning<
"property's synthesized getter follows Cocoa naming"
- " convention for returning 'owned' objects">;
+ " convention for returning 'owned' objects">,
+ InGroup<DiagGroup<"objc-property-matches-cocoa-ownership-rule">>;
def warn_property_getter_owning_mismatch : Warning<
"property declared as returning non-retained objects"
"; getter returning retained objects">;
@@ -456,6 +525,9 @@ def warn_default_atomic_custom_getter_setter : Warning<
def err_use_continuation_class : Error<
"illegal redeclaration of property in continuation class %0"
" (attribute must be 'readwrite', while its primary must be 'readonly')">;
+def warn_type_mismatch_continuation_class : Warning<
+ "type of property %0 in continuation class does not match "
+ "property type in primary class">, InGroup<ObjCContinuationPropertyType>;
def err_use_continuation_class_redeclaration_readwrite : Error<
"illegal redeclaration of 'readwrite' property in continuation class %0"
" (perhaps you intended this to be a 'readwrite' redeclaration of a "
@@ -489,7 +561,10 @@ def error_synthesize_weak_non_arc_or_gc : Error<
def err_arc_perform_selector_retains : Error<
"performSelector names a selector which retains the object">;
def warn_arc_perform_selector_leaks : Warning<
- "performSelector may cause a leak because its selector is unknown">;
+ "performSelector may cause a leak because its selector is unknown">,
+ InGroup<DiagGroup<"arc-performSelector-leaks">>;
+def err_gc_weak_property_strong_type : Error<
+ "weak attribute declared on a __strong type property in GC mode">;
def error_synthesized_ivar_yet_not_supported : Error<
"instance variable synthesis not yet supported"
@@ -511,6 +586,12 @@ def error_property_implemented : Error<"property %0 is already implemented">;
def warn_objc_property_attr_mutually_exclusive : Warning<
"property attributes '%0' and '%1' are mutually exclusive">,
InGroup<ReadOnlySetterAttrs>, DefaultIgnore;
+def warn_objc_missing_super_dealloc : Warning<
+ "method possibly missing a [super dealloc] call">,
+ InGroup<ObjCMissingSuperCalls>;
+def warn_objc_missing_super_finalize : Warning<
+ "method possibly missing a [super finalize] call">,
+ InGroup<ObjCMissingSuperCalls>;
def warn_undeclared_selector : Warning<
"undeclared selector %0">, InGroup<UndeclaredSelector>, DefaultIgnore;
def warn_implicit_atomic_property : Warning<
@@ -539,12 +620,12 @@ def err_unexpected_friend : Error<
def ext_enum_friend : ExtWarn<
"enumeration type %0 cannot be a friend">;
def ext_nonclass_type_friend : ExtWarn<
- "non-class friend type %0 is a C++0x extension">, InGroup<CXX0x>;
+ "non-class friend type %0 is a C++11 extension">, InGroup<CXX11>;
def err_friend_is_member : Error<
"friends cannot be members of the declaring class">;
def ext_unelaborated_friend_type : ExtWarn<
"specify '%select{struct|union|class|enum}0' to befriend %1; accepted "
- "as a C++0x extension">, InGroup<CXX0x>;
+ "as a C++11 extension">, InGroup<CXX11>;
def err_qualified_friend_not_found : Error<
"no function named %0 with type %1 was found in the specified scope">;
def err_introducing_special_friend : Error<
@@ -554,9 +635,15 @@ def err_tagless_friend_type_template : Error<
"friend type templates must use an elaborated type">;
def err_no_matching_local_friend : Error<
"no matching function found in local scope">;
+def err_no_matching_local_friend_suggest : Error<
+ "no matching function %0 found in local scope; did you mean %2">;
def err_partial_specialization_friend : Error<
"partial specialization cannot be declared as a friend">;
-
+def err_qualified_friend_def : Error<
+ "friend function definition cannot be qualified with '%0'">;
+def err_friend_def_in_local_class : Error<
+ "friend function cannot be defined in a local class">;
+
def err_abstract_type_in_decl : Error<
"%select{return|parameter|variable|field}0 type %1 is an abstract class">;
def err_allocation_of_abstract_type : Error<
@@ -963,7 +1050,7 @@ def warn_maybe_uninit_var_captured_by_block : Warning<
"variable %0 may be uninitialized when captured by block">,
InGroup<UninitializedMaybe>, DefaultIgnore;
def note_var_fixit_add_initialization : Note<
- "add initialization to silence this warning">;
+ "initialize the variable %0 to silence this warning">;
def err_init_incomplete_type : Error<"initialization of incomplete type %0">;
def err_temp_copy_no_viable : Error<
@@ -991,11 +1078,11 @@ def err_temp_copy_deleted : Error<
def err_temp_copy_incomplete : Error<
"copying a temporary object of incomplete type %0">;
-// C++0x decltype
+// C++11 decltype
def err_cannot_determine_declared_type_of_overloaded_function : Error<
"cannot determine the type of an overloaded function">;
-// C++0x auto
+// C++11 auto
def err_auto_variable_cannot_appear_in_own_initializer : Error<
"variable %0 declared with 'auto' type cannot appear in its own initializer">;
def err_illegal_decl_array_of_auto : Error<
@@ -1028,7 +1115,7 @@ def err_auto_new_deduction_failure : Error<
def err_auto_different_deductions : Error<
"'auto' deduced as %0 in declaration of %1 and deduced as %2 in declaration of %3">;
-// C++0x override control
+// C++11 override control
def override_keyword_only_allowed_on_virtual_member_functions : Error<
"only virtual member functions can be marked '%0'">;
def err_function_marked_override_not_overriding : Error<
@@ -1036,16 +1123,16 @@ def err_function_marked_override_not_overriding : Error<
def err_class_marked_final_used_as_base : Error<
"base %0 is marked 'final'">;
-// C++0x attributes
+// C++11 attributes
def err_repeat_attribute : Error<"'%0' attribute cannot be repeated">;
-// C++0x [[final]]
+// C++11 [[final]]
def err_final_function_overridden : Error<
"declaration of %0 overrides a 'final' function">;
def err_final_base : Error<
"derivation from 'final' %0">;
-// C++0x scoped enumerations
+// C++11 scoped enumerations
def err_enum_invalid_underlying : Error<
"non-integral type %0 is an invalid underlying type">;
def err_enumerator_too_large : Error<
@@ -1066,9 +1153,9 @@ def err_only_enums_have_underlying_types : Error<
def err_incomplete_type_no_underlying_type : Error<
"an incomplete enumeration type has no underlying type yet">;
-// C++0x delegating constructors
+// C++11 delegating constructors
def err_delegation_0x_only : Error<
- "delegating constructors are permitted only in C++0x">;
+ "delegating constructors are permitted only in C++11">;
def err_delegating_initializer_alone : Error<
"an initializer for a delegating constructor must appear alone">;
def warn_delegating_ctor_cycle : Warning<
@@ -1081,7 +1168,7 @@ def note_which_delegates_to : Note<
def err_delegating_codegen_not_implemented : Error<
"code generation for delegating constructors not implemented">;
-// C++0x range-based for loop
+// C++11 range-based for loop
def err_for_range_decl_must_be_var : Error<
"for range declaration must declare a variable">;
def err_for_range_storage_class : Error<
@@ -1102,7 +1189,88 @@ def err_for_range_begin_end_types_differ : Error<
def note_for_range_type : Note<"range has type %0">;
def note_for_range_begin_end : Note<
"selected '%select{begin|end}0' %select{function|template }1%2 with iterator type %3">;
-
+
+// C++11 constexpr
+def err_invalid_constexpr : Error<
+ "%select{function parameter|typedef|non-static data member}0 "
+ "cannot be constexpr">;
+def err_constexpr_tag : Error<
+ "%select{class|struct|union|enum}0 cannot be marked constexpr">;
+def err_constexpr_dtor : Error<"destructor cannot be marked constexpr">;
+def err_constexpr_no_declarators : Error<
+ "constexpr can only be used in variable and function declarations">;
+def err_invalid_constexpr_var_decl : Error<
+ "constexpr variable declaration must be a definition">;
+def err_constexpr_var_requires_init : Error<
+ "declaration of constexpr variable %0 requires an initializer">;
+def err_constexpr_var_requires_const_init : Error<
+ "constexpr variable %0 must be initialized by a constant expression">;
+def err_constexpr_redecl_mismatch : Error<
+ "%select{non-constexpr declaration of %0 follows constexpr declaration"
+ "|constexpr declaration of %0 follows non-constexpr declaration}1">;
+def note_constexpr_redecl_mismatch : Note<
+ "previous declaration was %select{not |}0marked constexpr">;
+def err_constexpr_virtual : Error<"virtual function cannot be constexpr">;
+def note_constexpr_tmpl_virtual : Note<"function template instantiation is not "
+ "constexpr because it is virtual">;
+def err_constexpr_virtual_base : Error<"constexpr constructor not allowed in "
+ "%select{class|struct}0 with virtual base %plural{1:class|:classes}1">;
+def note_constexpr_tmpl_virtual_base : Note<"constructor template instantiation is "
+ "not constexpr because %select{class|struct}0 has virtual base "
+ "%plural{1:class|:classes}1">;
+def note_non_literal_virtual_base : Note<"%select{class|struct}0 with virtual "
+ "base %plural{1:class|:classes}1 is not a literal type">;
+def note_constexpr_virtual_base_here : Note<"virtual base class declared here">;
+def err_constexpr_non_literal_return : Error<
+ "constexpr function's return type %0 is not a literal type">;
+def note_constexpr_tmpl_non_literal_return : Note<
+ "function template instantiation is not constexpr because return type %0 is "
+ "not a literal type">;
+def err_constexpr_non_literal_param : Error<
+ "constexpr %select{function|constructor}1's %ordinal0 parameter type %2 is "
+ "not a literal type">;
+def note_constexpr_tmpl_non_literal_param : Note<
+ "%select{function|constructor}1 template instantiation is not constexpr "
+ "because %ordinal0 parameter type %2 is not a literal type">;
+def err_constexpr_body_invalid_stmt : Error<
+ "statement not allowed in constexpr %select{function|constructor}0">;
+def err_constexpr_type_definition : Error<
+ "types cannot be defined in a constexpr %select{function|constructor}0">;
+def err_constexpr_vla : Error<
+ "variably-modified type %0 cannot be used in a constexpr "
+ "%select{function|constructor}1">;
+def err_constexpr_var_declaration : Error<
+ "variables cannot be declared in a constexpr %select{function|constructor}0">;
+def err_constexpr_body_no_return : Error<
+ "no return statement in constexpr function">;
+def err_constexpr_body_multiple_return : Error<
+ "multiple return statements in constexpr function">;
+def note_constexpr_body_previous_return : Note<
+ "previous return statement is here">;
+def err_constexpr_function_try_block : Error<
+ "function try block not allowed in constexpr %select{function|constructor}0">;
+def err_constexpr_union_ctor_no_init : Error<
+ "constexpr union constructor does not initialize any member">;
+def err_constexpr_ctor_missing_init : Error<
+ "constexpr constructor must initialize all members">;
+def note_constexpr_ctor_missing_init : Note<
+ "member not initialized by constructor">;
+def err_constexpr_method_non_literal : Error<
+ "non-literal type %0 cannot have constexpr members">;
+def note_non_literal_no_constexpr_ctors : Note<
+ "%0 is not literal because it is not an aggregate and has no constexpr "
+ "constructors other than copy or move constructors">;
+def note_non_literal_base_class : Note<
+ "%0 is not literal because it has base class %1 of non-literal type">;
+def note_non_literal_field : Note<
+ "%0 is not literal because it has data member %1 of non-literal type %2">;
+def note_non_literal_user_provided_dtor : Note<
+ "%0 is not literal because it has a user-provided destructor">;
+def note_non_literal_nontrivial_dtor : Note<
+ "%0 is not literal because it has a non-trivial destructor">;
+def note_non_literal_mutable_field : Note<
+ "%0 is not literal because it has a mutable data member">;
+
// Objective-C++
def err_objc_decls_may_only_appear_in_global_scope : Error<
"Objective-C declarations may only appear in global scope">;
@@ -1119,11 +1287,8 @@ def err_attribute_wrong_number_arguments : Error<
":requires exactly %0 arguments}0">;
def err_attribute_too_many_arguments : Error<
"attribute takes no more than %0 argument%s0">;
-def err_iboutletcollection_type : Error<
- "invalid type %0 as argument of iboutletcollection attribute">;
-def err_iboutletcollection_object_type : Error<
- "%select{ivar|property}1 with iboutletcollection attribute must "
- "have object type (invalid %0)">;
+def err_attribute_too_few_arguments : Error<
+ "attribute takes at least %0 argument%s0">;
def err_attribute_missing_parameter_name : Error<
"attribute requires unquoted parameter">;
def err_attribute_invalid_vector_type : Error<"invalid vector element type %0">;
@@ -1131,6 +1296,10 @@ def err_attribute_bad_neon_vector_size : Error<
"Neon vector size must be 64 or 128 bits">;
def err_attribute_argument_not_int : Error<
"'%0' attribute requires integer constant">;
+def err_attribute_argument_not_class : Error<
+ "%0 attribute requires arguments that are class type or point to class type">;
+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<
"init_priority attribute requires integer constant between "
"101 and 65535 inclusive">;
@@ -1186,6 +1355,8 @@ def err_attribute_address_space_too_high : Error<
"address space is larger than the maximum supported (%0)">;
def err_attribute_address_multiple_qualifiers : Error<
"multiple address spaces specified for type">;
+def err_attribute_address_function_type : Error<
+ "function type may not be qualified with an address space">;
def err_as_qualified_auto_decl : Error<
"automatic variable qualified with an address space">;
def err_arg_with_address_space : Error<
@@ -1196,6 +1367,8 @@ def err_attr_objc_ownership_redundant : Error<
"the type %0 already has retainment attributes set on it">;
def err_attribute_not_string : Error<
"argument to %0 attribute was not a string literal">;
+def err_only_annotate_after_access_spec : Error<
+ "access specifier can only have annotation attributes">;
def err_attribute_section_invalid_for_target : Error<
"argument to 'section' attribute is not valid for this target: %0">;
def err_attribute_section_local_variable : Error<
@@ -1238,13 +1411,13 @@ def warn_attribute_wrong_decl_type : Warning<
"parameters and methods|functions, methods and blocks|"
"classes and virtual methods|functions, methods, and parameters|"
"classes|virtual methods|class members|variables|methods|"
- "variables, functions and labels}1">;
+ "variables, functions and labels|fields and global variables}1">;
def err_attribute_wrong_decl_type : Error<
"%0 attribute only applies to %select{functions|unions|"
"variables and functions|functions and methods|parameters|"
"parameters and methods|functions, methods and blocks|"
"classes and virtual methods|functions, methods, and parameters|"
- "classes|virtual methods|class members|variables|methods}1">;
+ "classes|virtual methods|class members|variables|methods|structs}1">;
def warn_function_attribute_wrong_type : Warning<
"'%0' only applies to function types; type here is %1">;
def warn_pointer_attribute_wrong_type : Warning<
@@ -1268,6 +1441,9 @@ def err_cconv_varargs : Error<
def err_regparm_mismatch : Error<"function declared with with regparm(%0) "
"attribute was previously declared "
"%plural{0:without the regparm|:with the regparm(%1)}1 attribute">;
+def err_returns_retained_mismatch : Error<
+ "function declared with the ns_returns_retained attribute "
+ "was previously declared without the ns_returns_retained attribute">;
def err_objc_precise_lifetime_bad_type : Error<
"objc_precise_lifetime only applies to retainable types; type here is %0">;
def warn_objc_precise_lifetime_meaningless : Error<
@@ -1276,6 +1452,11 @@ def warn_objc_precise_lifetime_meaningless : Error<
def warn_label_attribute_not_unused : Warning<
"The only valid attribute for labels is 'unused'">;
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">;
+
// Availability attribute
def warn_availability_unknown_platform : Warning<
@@ -1284,6 +1465,68 @@ def warn_availability_version_ordering : Warning<
"feature cannot be %select{introduced|deprecated|obsoleted}0 in %1 version "
"%2 before it was %select{introduced|deprecated|obsoleted}3 in version %4; "
"attribute ignored">;
+
+// Thread Safety Attributes
+// Errors when parsing the attributes
+def err_attribute_argument_out_of_range : Error<
+ "%0 attribute parameter %1 is out of bounds: "
+ "%plural{0:no parameters to index into|"
+ "1:can only be 1, since there is one parameter|"
+ ":must be between 1 and %2}2">;
+def err_attribute_argument_not_lockable : Error<
+ "%0 attribute requires arguments whose type is annotated "
+ "with 'lockable' attribute">;
+def err_attribute_decl_not_lockable : Error<
+ "%0 attribute can only be applied in a context annotated "
+ "with 'lockable' attribute">;
+def warn_unlock_but_no_lock : Warning<
+ "unlocking '%0' that was not locked">,
+ InGroup<ThreadSafety>, DefaultIgnore;
+def warn_double_lock : Warning<
+ "locking '%0' that is already locked">,
+ InGroup<ThreadSafety>, DefaultIgnore;
+def warn_no_unlock : Warning<
+ "mutex '%0' is still locked at the end of function">,
+ InGroup<ThreadSafety>, DefaultIgnore;
+// FIXME: improve the error message about locks not in scope
+def warn_lock_at_end_of_scope : Warning<
+ "mutex '%0' is still locked at the end of its scope">,
+ InGroup<ThreadSafety>, DefaultIgnore;
+def warn_expecting_lock_held_on_loop : Warning<
+ "expecting mutex '%0' to be locked at start of each loop">,
+ InGroup<ThreadSafety>, DefaultIgnore;
+def warn_lock_exclusive_and_shared : Warning<
+ "mutex '%0' is locked exclusively and shared in the same scope">,
+ InGroup<ThreadSafety>, DefaultIgnore;
+def note_lock_exclusive_and_shared : Note<
+ "the other lock of mutex '%0' is here">,
+ InGroup<ThreadSafety>, DefaultIgnore;
+def warn_variable_requires_lock : Warning<
+ "%select{reading|writing}2 variable '%0' requires locking "
+ "%select{'%1'|'%1' exclusively}2">,
+ InGroup<ThreadSafety>, DefaultIgnore;
+def warn_var_deref_requires_lock : Warning<
+ "%select{reading|writing}2 the value pointed to by '%0' requires locking "
+ "%select{'%1'|'%1' exclusively}2">,
+ InGroup<ThreadSafety>, DefaultIgnore;
+def warn_variable_requires_any_lock : Warning<
+ "%select{reading|writing}1 variable '%0' requires locking "
+ "%select{any mutex|any mutex exclusively}1">,
+ InGroup<ThreadSafety>, DefaultIgnore;
+def warn_var_deref_requires_any_lock : Warning<
+ "%select{reading|writing}1 the value pointed to by '%0' requires locking "
+ "%select{any mutex|any mutex exclusively}1">,
+ InGroup<ThreadSafety>, DefaultIgnore;
+def warn_fun_requires_lock : Warning<
+ "calling function '%0' requires %select{shared|exclusive}2 lock on '%1'">,
+ InGroup<ThreadSafety>, DefaultIgnore;
+def warn_fun_excludes_mutex : Warning<
+ "cannot call function '%0' while mutex '%1' is locked">,
+ InGroup<ThreadSafety>, DefaultIgnore;
+def warn_cannot_resolve_lock : Warning<
+ "cannot resolve lock expression to a specific lockable object">,
+ InGroup<ThreadSafety>, DefaultIgnore;
+
def warn_impcast_vector_scalar : Warning<
"implicit conversion turns vector to scalar: %0 to %1">,
@@ -1319,13 +1562,14 @@ def warn_impcast_literal_float_to_integer : Warning<
"implicit conversion turns literal floating-point number into integer: "
"%0 to %1">,
InGroup<DiagGroup<"literal-conversion">>, DefaultIgnore;
-def note_fix_integral_float_as_integer : Note<
- "this can be rewritten as an integer literal with the exact same value">;
+def warn_impcast_string_literal_to_bool : Warning<
+ "implicit conversion turns string literal into bool: %0 to %1">,
+ InGroup<DiagGroup<"string-conversion">>, DefaultIgnore;
def warn_impcast_different_enum_types : Warning<
"implicit conversion from enumeration type %0 to different enumeration type "
"%1">, InGroup<DiagGroup<"conversion">>;
def warn_impcast_bool_to_null_pointer : Warning<
- "initialization of pointer of type %0 to NULL from a constant boolean "
+ "initialization of pointer of type %0 to null from a constant boolean "
"expression">, InGroup<BoolConversions>;
def warn_impcast_null_pointer_to_integer : Warning<
"implicit conversion of NULL constant to integer">,
@@ -1398,6 +1642,11 @@ def warn_attribute_iboutlet : Warning<
"%0 attribute can only be applied to instance variables or properties">;
def warn_attribute_ibaction: Warning<
"ibaction attribute can only be applied to Objective-C instance methods">;
+def err_iboutletcollection_type : Error<
+ "invalid type %0 as argument of iboutletcollection attribute">;
+def err_iboutlet_object_type : Error<
+ "%select{ivar|property}2 with %0 attribute must "
+ "be an object type (invalid %1)">;
def err_attribute_overloadable_not_function : Error<
"'overloadable' attribute can only be applied to a function">;
def err_attribute_overloadable_missing : Error<
@@ -1409,10 +1658,12 @@ def err_attribute_overloadable_no_prototype : Error<
"'overloadable' function %0 must have a prototype">;
def warn_ns_attribute_wrong_return_type : Warning<
"%0 attribute only applies to %select{functions|methods}1 that "
- "return %select{an Objective-C object|a pointer}2">;
+ "return %select{an Objective-C object|a pointer|a non-retainable pointer}2">;
def warn_ns_attribute_wrong_parameter_type : Warning<
"%0 attribute only applies to %select{Objective-C object|pointer}1 "
"parameters">;
+def err_ns_bridged_not_interface : Error<
+ "parameter of 'ns_bridged' attribute does not name an Objective-C class">;
// Function Parameter Semantic Analysis.
def err_param_with_void_type : Error<"argument may not have 'void' type">;
@@ -1572,6 +1823,16 @@ def note_ovl_candidate_bad_conv_incomplete : Note<"candidate "
"function (the implicit move assignment operator)|"
"constructor (inherited)}0%1 "
"not viable: cannot convert argument of incomplete type %2 to %3">;
+def note_ovl_candidate_bad_list_argument : Note<"candidate "
+ "%select{function|function|constructor|"
+ "function |function |constructor |"
+ "constructor (the implicit default constructor)|"
+ "constructor (the implicit copy constructor)|"
+ "constructor (the implicit move constructor)|"
+ "function (the implicit copy assignment operator)|"
+ "function (the implicit move assignment operator)|"
+ "constructor (inherited)}0%1 "
+ "not viable: cannot convert initializer list argument to %3">;
def note_ovl_candidate_bad_overload : Note<"candidate "
"%select{function|function|constructor|"
"function |function |constructor |"
@@ -1592,7 +1853,22 @@ def note_ovl_candidate_bad_conv : Note<"candidate "
"function (the implicit move assignment operator)|"
"constructor (inherited)}0%1"
" not viable: no known conversion from %2 to %3 for "
- "%select{%ordinal5 argument|object argument}4">;
+ "%select{%ordinal5 argument|object argument}4; "
+ "%select{|dereference the argument with *|"
+ "take the address of the argument with &|"
+ "remove *|"
+ "remove &}6">;
+def note_ovl_candidate_bad_arc_conv : Note<"candidate "
+ "%select{function|function|constructor|"
+ "function |function |constructor |"
+ "constructor (the implicit default constructor)|"
+ "constructor (the implicit copy constructor)|"
+ "constructor (the implicit move constructor)|"
+ "function (the implicit copy assignment operator)|"
+ "function (the implicit move assignment operator)|"
+ "constructor (inherited)}0%1"
+ " not viable: cannot implicitly convert argument of type %2 to %3 for "
+ "%select{%ordinal5 argument|object argument}4 under ARC">;
def note_ovl_candidate_bad_addrspace : Note<"candidate "
"%select{function|function|constructor|"
"function |function |constructor |"
@@ -1620,15 +1896,18 @@ def note_ovl_candidate_bad_ownership : Note<"candidate "
"function |function |constructor |"
"constructor (the implicit default constructor)|"
"constructor (the implicit copy constructor)|"
+ "constructor (the implicit move constructor)|"
"function (the implicit copy assignment operator)|"
+ "function (the implicit move assignment operator)|"
"constructor (inherited)}0%1 not viable: "
"%select{%ordinal6|'this'}5 argument (%2) has "
"%select{no|__unsafe_unretained|__strong|__weak|__autoreleasing}3 ownership,"
" but parameter has %select{no|__unsafe_unretained|__strong|__weak|"
"__autoreleasing}4 ownership">;
def note_ovl_candidate_bad_cvr_this : Note<"candidate "
- "%select{|function|||function||||"
- "function (the implicit copy assignment operator)|}0 not viable: "
+ "%select{|function|||function|||||"
+ "function (the implicit copy assignment operator)|"
+ "function (the implicit move assignment operator)|}0 not viable: "
"'this' argument has type %2, but method is not marked "
"%select{const|restrict|const or restrict|volatile|const or volatile|"
"volatile or restrict|const, volatile, or restrict}3">;
@@ -1658,6 +1937,17 @@ def note_ovl_candidate_bad_base_to_derived_conv : Note<"candidate "
"%select{base class pointer|superclass|base class object of type}2 %3 to "
"%select{derived class pointer|subclass|derived class reference}2 %4 for "
"%ordinal5 argument">;
+def note_ovl_candidate_bad_target : Note<
+ "candidate %select{function|function|constructor|"
+ "function |function |constructor |"
+ "constructor (the implicit default constructor)|"
+ "constructor (the implicit copy constructor)|"
+ "constructor (the implicit move constructor)|"
+ "function (the implicit copy assignment operator)|"
+ "function (the implicit move assignment operator)|"
+ "constructor (inherited)}0 not viable: call to "
+ "%select{__device__|__global__|__host__|__host__ __device__}1 function from"
+ " %select{__device__|__global__|__host__|__host__ __device__}2 function">;
def note_ambiguous_type_conversion: Note<
"because of ambiguity in conversion of %0 to %1">;
@@ -1694,9 +1984,13 @@ def err_ovl_no_viable_subscript :
Error<"no viable overloaded operator[] for type %0">;
def err_ovl_no_oper :
Error<"type %0 does not provide a %select{subscript|call}1 operator">;
-def err_ovl_unresolvable :
- Error<"cannot resolve overloaded function %0 from context">;
-
+def err_ovl_unresolvable : Error<
+ "reference to overloaded function could not be resolved; "
+ "did you mean to call it%select{| with no arguments}0?">;
+def err_bound_member_function : Error<
+ "reference to non-static member function must be called"
+ "%select{|; did you mean to call it with no arguments?}0">;
+def note_possible_target_of_call : Note<"possible target for call">;
def err_ovl_no_viable_object_call : Error<
"no matching function for call to object of type %0">;
@@ -1761,8 +2055,8 @@ def note_template_param_prev_default_arg : Note<
def err_template_param_default_arg_missing : Error<
"template parameter missing a default argument">;
def ext_template_parameter_default_in_function_template : ExtWarn<
- "default template arguments for a function template are a C++0x extension">,
- InGroup<CXX0x>;
+ "default template arguments for a function template are a C++11 extension">,
+ InGroup<CXX11>;
def err_template_parameter_default_template_member : Error<
"cannot add a default template argument to the definition of a member of a "
"class template">;
@@ -1774,6 +2068,9 @@ def err_template_template_parm_no_parms : Error<
def err_template_variable : Error<"variable %0 declared as a template">;
def err_template_variable_noparams : Error<
"extraneous 'template<>' in declaration of variable %0">;
+def err_template_member : Error<"member %0 declared as a template">;
+def err_template_member_noparams : Error<
+ "extraneous 'template<>' in declaration of member %0">;
def err_template_tag_noparams : Error<
"extraneous 'template<>' in declaration of %0 %1">;
def err_template_decl_ref : Error<
@@ -1895,8 +2192,8 @@ def err_template_spec_decl_out_of_scope_global : Error<
def ext_template_spec_decl_out_of_scope_global : ExtWarn<
"%select{class template|class template partial|function template|member "
"function|static data member|member class}0 specialization of %1 must "
- "originally be declared in the global scope; accepted as a C++0x extension">,
- InGroup<CXX0x>;
+ "originally be declared in the global scope; accepted as a C++11 extension">,
+ InGroup<CXX11>;
def err_template_spec_decl_out_of_scope : Error<
"%select{class template|class template partial|function template|member "
"function|static data member|member class}0 specialization of %1 must "
@@ -1904,8 +2201,8 @@ def err_template_spec_decl_out_of_scope : Error<
def ext_template_spec_decl_out_of_scope : ExtWarn<
"%select{class template|class template partial|function template|member "
"function|static data member|member class}0 specialization of %1 must "
- "originally be declared in namespace %2; accepted as a C++0x extension">,
- InGroup<CXX0x>;
+ "originally be declared in namespace %2; accepted as a C++11 extension">,
+ InGroup<CXX11>;
def err_template_spec_redecl_out_of_scope : Error<
"%select{class template|class template partial|function template|member "
"function|static data member|member class}0 specialization of %1 not in a "
@@ -1931,6 +2228,9 @@ def err_not_class_template_specialization : Error<
"parameter}0">;
def err_function_specialization_in_class : Error<
"cannot specialize a function %0 within class scope">;
+def ext_function_specialization_in_class : ExtWarn<
+ "explicit specialization of %0 within class scope is a Microsoft extension">,
+ InGroup<Microsoft>;
def ext_explicit_specialization_storage_class : ExtWarn<
"explicit specialization cannot have a storage class">;
def err_explicit_specialization_inconsistent_storage_class : Error<
@@ -2068,8 +2368,8 @@ def note_previous_explicit_instantiation : Note<
"previous explicit instantiation is here">;
def ext_explicit_instantiation_after_specialization : Extension<
"explicit instantiation of %0 that occurs after an explicit "
- "specialization will be ignored (C++0x extension)">,
- InGroup<CXX0x>;
+ "specialization will be ignored (C++11 extension)">,
+ InGroup<CXX11>;
def note_previous_template_specialization : Note<
"previous template specialization is here">;
def err_explicit_instantiation_enum : Error<
@@ -2086,10 +2386,10 @@ def err_explicit_instantiation_must_be_global : Error<
"explicit instantiation of %0 must occur at global scope">;
def warn_explicit_instantiation_out_of_scope_0x : Warning<
"explicit instantiation of %0 not in a namespace enclosing %1">,
- InGroup<DiagGroup<"-Wc++0x-compat"> >;
+ InGroup<CXX11Compat>;
def warn_explicit_instantiation_must_be_global_0x : Warning<
"explicit instantiation of %0 must occur at global scope">,
- InGroup<DiagGroup<"-Wc++0x-compat"> >;
+ InGroup<CXX11Compat>;
def err_explicit_instantiation_requires_name : Error<
"explicit instantiation declaration requires a name">;
@@ -2114,6 +2414,8 @@ def note_explicit_instantiation_candidate : Note<
"explicit instantiation candidate function template here %0">;
def err_explicit_instantiation_inline : Error<
"explicit instantiation cannot be 'inline'">;
+def err_explicit_instantiation_constexpr : Error<
+ "explicit instantiation cannot be 'constexpr'">;
def ext_explicit_instantiation_without_qualified_id : Extension<
"qualifier in explicit instantiation of %q0 requires a template-id "
"(a typedef is not permitted)">;
@@ -2121,7 +2423,7 @@ def err_explicit_instantiation_unqualified_wrong_namespace : Error<
"explicit instantiation of %q0 must occur in %1">;
def warn_explicit_instantiation_unqualified_wrong_namespace_0x : Warning<
"explicit instantiation of %q0 must occur in %1">,
- InGroup<DiagGroup<"c++0x-compat"> >;
+ InGroup<CXX11Compat>;
def err_explicit_instantiation_undefined_member : Error<
"explicit instantiation of undefined %select{member class|member function|"
"static data member}0 %1 of class template %2">;
@@ -2142,9 +2444,10 @@ def note_typename_refers_here : Note<
def err_typename_missing : Error<
"missing 'typename' prior to dependent type name '%0%1'">;
def warn_typename_missing : ExtWarn<
- "missing 'typename' prior to dependent type name '%0%1'">;
+ "missing 'typename' prior to dependent type name '%0%1'">,
+ InGroup<DiagGroup<"typename-missing">>;
def ext_typename_outside_of_template : ExtWarn<
- "'typename' occurs outside of a template">, InGroup<CXX0x>;
+ "'typename' occurs outside of a template">, InGroup<CXX11>;
def err_typename_refers_to_using_value_decl : Error<
"typename specifier refers to a dependent using declaration for a value "
"%0 in %1">;
@@ -2162,7 +2465,7 @@ def note_referenced_class_template : Error<
def err_template_kw_missing : Error<
"missing 'template' keyword prior to dependent template name '%0%1'">;
def ext_template_outside_of_template : ExtWarn<
- "'template' keyword outside of a template">, InGroup<CXX0x>;
+ "'template' keyword outside of a template">, InGroup<CXX11>;
def err_non_type_template_in_nested_name_specifier : Error<
"qualified name refers into a specialization of function template '%0'">;
@@ -2172,7 +2475,7 @@ def note_template_declared_here : Note<
"%select{function template|class template|type alias template|template template parameter}0 "
"%1 declared here">;
-// C++0x Variadic Templates
+// C++11 Variadic Templates
def err_template_param_pack_default_arg : Error<
"template parameter pack cannot have a default argument">;
def err_template_param_pack_must_be_last_template_parameter : Error<
@@ -2240,6 +2543,9 @@ def err_unexpected_typedef : Error<
def err_unexpected_namespace : Error<
"unexpected namespace name %0: expected expression">;
def err_undeclared_var_use : Error<"use of undeclared identifier %0">;
+def warn_found_via_dependent_bases_lookup : ExtWarn<"use of identifier %0 "
+ "found via unqualified lookup into dependent bases of class templates is a "
+ "Microsoft extension">, InGroup<Microsoft>;
def note_dependent_var_use : Note<"must qualify identifier to find this "
"declaration in dependent base class">;
def err_not_found_by_two_phase_lookup : Error<"call to function %0 that is neither "
@@ -2265,9 +2571,11 @@ def note_unavailable_here : Note<
"%select{declaration|function}0 has been explicitly marked "
"%select{unavailable|deleted|deprecated}1 here">;
def warn_not_enough_argument : Warning<
- "not enough variable arguments in %0 declaration to fit a sentinel">;
+ "not enough variable arguments in %0 declaration to fit a sentinel">,
+ InGroup<Sentinel>;
def warn_missing_sentinel : Warning <
- "missing sentinel in %select{function call|method dispatch|block call}0">;
+ "missing sentinel in %select{function call|method dispatch|block call}0">,
+ InGroup<Sentinel>;
def note_sentinel_here : Note<
"%select{function|method|block}0 has been explicitly marked sentinel here">;
def warn_missing_prototype : Warning<
@@ -2410,6 +2718,8 @@ def err_at_least_one_initializer_needed_to_size_array : Error<
def err_array_size_non_int : Error<"size of array has non-integer type %0">;
def err_init_element_not_constant : Error<
"initializer element is not a compile-time constant">;
+def err_local_cant_init : Error<
+ "'__local' variable cannot have an initializer">;
def err_block_extern_cant_init : Error<
"'extern' variable cannot have an initializer">;
def warn_extern_init : Warning<"'extern' variable has an initializer">;
@@ -2436,10 +2746,28 @@ def warn_braces_around_scalar_init : Warning<
"braces around scalar initializer">;
def warn_many_braces_around_scalar_init : ExtWarn<
"too many braces around scalar initializer">;
+def ext_complex_component_init : Extension<
+ "complex initialization specifying real and imaginary components "
+ "is an extension">, InGroup<DiagGroup<"complex-component-init">>;
def err_empty_scalar_initializer : Error<"scalar initializer cannot be empty">;
def err_illegal_initializer : Error<
"illegal initializer (only variables can be initialized)">;
def err_illegal_initializer_type : Error<"illegal initializer type %0">;
+def err_init_list_variable_narrowing : Error<
+ "non-constant-expression cannot be narrowed from type %0 to %1 in "
+ "initializer list">;
+def err_init_list_constant_narrowing : Error<
+ "constant expression evaluates to %0 which cannot be narrowed to type %1">;
+def warn_init_list_variable_narrowing : Warning<
+ "non-constant-expression cannot be narrowed from type %0 to %1 in "
+ "initializer list in C++11">,
+ InGroup<CXX11Narrowing>, DefaultIgnore;
+def warn_init_list_constant_narrowing : Warning<
+ "constant expression evaluates to %0 which cannot be narrowed to type %1 in "
+ "C++11">,
+ InGroup<CXX11Narrowing>, DefaultIgnore;
+def note_init_list_narrowing_override : Note<
+ "override this message by inserting an explicit cast">;
def err_init_objc_class : Error<
"cannot initialize Objective-C class type %0">;
def err_implicit_empty_initializer : Error<
@@ -2474,6 +2802,8 @@ def warn_unused_label : Warning<"unused label %0">,
InGroup<UnusedLabel>, DefaultIgnore;
def err_goto_into_protected_scope : Error<"goto into protected scope">;
+def warn_goto_into_protected_scope : ExtWarn<"goto into protected scope">,
+ InGroup<Microsoft>;
def err_switch_into_protected_scope : Error<
"switch case is in protected scope">;
def err_indirect_goto_without_addrlabel : Error<
@@ -2563,8 +2893,8 @@ def ext_flexible_array_in_struct : Extension<
"%0 may not be nested in a struct due to flexible array member">;
def ext_flexible_array_in_array : Extension<
"%0 may not be used as an array element due to flexible array member">;
-def err_flexible_array_init_nonempty : Error<
- "non-empty initialization of flexible array member inside subobject">;
+def err_flexible_array_init : Error<
+ "initialization of flexible array member is not allowed">;
def ext_flexible_array_empty_aggregate_ms : Extension<
"flexible array member %0 in otherwise empty %select{struct|class}1 "
"is a Microsoft extension">, InGroup<Microsoft>;
@@ -2603,7 +2933,7 @@ def err_arc_objc_object_in_struct : Error<
"ARC forbids Objective-C objects in structs or unions">;
def err_arc_objc_property_default_assign_on_object : Error<
"ARC forbids synthesizing a property of an Objective-C object "
- "with unspecified storage attribute">;
+ "with unspecified ownership or storage attribute">;
def err_arc_illegal_selector : Error<
"ARC forbids use of %0 in a @selector">;
def err_arc_illegal_method_def : Error<
@@ -2672,10 +3002,11 @@ def err_arc_method_not_found : Error<
def err_arc_receiver_forward_class : Error<
"receiver %0 for class message is a forward declaration">;
def err_arc_may_not_respond : Error<
- "receiver type %0 for instance message does not declare a method with "
- "selector %1">;
+ "no visible @interface for %0 declares the selector %1">;
def err_arc_receiver_forward_instance : Error<
"receiver type %0 for instance message is a forward declaration">;
+def err_arc_collection_forward : Error<
+ "collection expression type %0 is a forward declaration">;
def err_arc_multiple_method_decl : Error<
"multiple methods named %0 found with mismatched result, "
"parameter type or attributes">;
@@ -2696,9 +3027,10 @@ def err_arc_strong_property_ownership : Error<
"existing ivar %1 for strong property %0 may not be "
"%select{|__unsafe_unretained||__weak}2">;
def err_arc_assign_property_ownership : Error<
- "existing ivar %1 for unsafe_unretained property %0 must be __unsafe_unretained">;
+ "existing ivar %1 for property %0 with %select{unsafe_unretained| assign}2 "
+ "attribute must be __unsafe_unretained">;
def err_arc_inconsistent_property_ownership : Error<
- "%select{strong|weak|unsafe_unretained}1 property %0 may not also be "
+ "%select{|unsafe_unretained|strong|weak}1 property %0 may not also be "
"declared %select{|__unsafe_unretained|__strong|__weak|__autoreleasing}2">;
def err_arc_atomic_ownership : Error<
"cannot perform atomic operation on a pointer to type %0: type has "
@@ -2759,6 +3091,10 @@ def err_block_with_return_type_requires_args : Error<
"block with explicit return type requires argument list">;
def err_func_def_incomplete_result : Error<
"incomplete result type %0 in function definition">;
+def err_atomic_specifier_bad_type : Error<
+ "_Atomic cannot be applied to "
+ "%select{incomplete |array |function |reference |atomic |qualified |}0type "
+ "%1 %select{||||||which is not trivially copyable}0">;
// Expressions.
def ext_sizeof_function_type : Extension<
@@ -2793,8 +3129,10 @@ def warn_floatingpoint_eq : Warning<
def warn_division_by_zero : Warning<"division by zero is undefined">;
def warn_remainder_by_zero : Warning<"remainder by zero is undefined">;
-def warn_shift_negative : Warning<"shift count is negative">;
-def warn_shift_gt_typewidth : Warning<"shift count >= width of type">;
+def warn_shift_negative : Warning<"shift count is negative">,
+ InGroup<DiagGroup<"shift-count-negative">>;
+def warn_shift_gt_typewidth : Warning<"shift count >= width of type">,
+ InGroup<DiagGroup<"shift-count-overflow">>;
def warn_shift_result_gt_typewidth : Warning<
"signed shift result (%0) requires %1 bits to represent, but %2 only has "
"%3 bits">, InGroup<DiagGroup<"shift-overflow">>;
@@ -2820,8 +3158,12 @@ def note_precedence_conditional_silence : Note<
"place parentheses around the '%0' expression to silence this warning">;
def warn_logical_instead_of_bitwise : Warning<
- "use of logical %0 with constant operand; switch to bitwise %1 or "
- "remove constant">, InGroup<DiagGroup<"constant-logical-operand">>;
+ "use of logical '%0' with constant operand">,
+ InGroup<DiagGroup<"constant-logical-operand">>;
+def note_logical_instead_of_bitwise_change_operator : Note<
+ "use '%0' for a bitwise operation">;
+def note_logical_instead_of_bitwise_remove_constant : Note<
+ "remove constant to silence this warning">;
def warn_bitwise_and_in_bitwise_or : Warning<
"'&' within '|'">, InGroup<BitwiseOpParentheses>;
@@ -2883,10 +3225,8 @@ def err_typecheck_member_reference_type : Error<
def err_typecheck_member_reference_unknown : Error<
"cannot refer to member %0 in %1 with '%select{.|->}2'">;
def err_member_reference_needs_call : Error<
- "base of member reference is %select{a function|an overloaded function}0; "
- "perhaps you meant to call it%select{| with no arguments}1?">;
-def note_member_ref_possible_intended_overload : Note<
- "possibly valid overload here">;
+ "base of member reference is a function; perhaps you meant to call "
+ "it%select{| with no arguments}?">;
def warn_subscript_is_char : Warning<"array subscript is of type 'char'">,
InGroup<CharSubscript>, DefaultIgnore;
@@ -2904,6 +3244,9 @@ def err_member_def_undefined_record : Error<
"out-of-line definition of %0 from class %1 without definition">;
def err_member_def_does_not_match : Error<
"out-of-line definition of %0 does not match any declaration in %1">;
+def err_member_def_does_not_match_suggest : Error<
+ "out-of-line definition of %0 does not match any declaration in %1; "
+ "did you mean %2">;
def err_member_def_does_not_match_ret_type : Error<
"out-of-line definition of %q0 differs from the declaration in the return type">;
def err_nonstatic_member_out_of_line : Error<
@@ -2922,6 +3265,12 @@ def warn_member_extra_qualification : Warning<
def err_member_qualification : Error<
"non-friend class member %0 cannot have a qualified name">;
def note_member_def_close_match : Note<"member declaration nearly matches">;
+def note_member_def_close_const_match : Note<
+ "member declaration does not match because "
+ "it %select{is|is not}0 const qualified">;
+def note_member_def_close_param_match : Note<
+ "type of %ordinal0 parameter of member declaration does not match "
+ "definition (%1 vs %2)">;
def err_typecheck_ivar_variable_size : Error<
"instance variables must have a constant size">;
def err_ivar_reference_type : Error<
@@ -2938,7 +3287,8 @@ def err_typecheck_pointer_arith_void_type : Error<
def err_typecheck_decl_incomplete_type : Error<
"variable has incomplete type %0">;
def ext_typecheck_decl_incomplete_type : ExtWarn<
- "tentative definition of variable with internal linkage has incomplete non-array type %0">;
+ "tentative definition of variable with internal linkage has incomplete non-array type %0">,
+ InGroup<DiagGroup<"tentative-definition-incomplete-type">>;
def err_tentative_def_incomplete_type : Error<
"tentative definition has type %0 that is never completed">;
def err_tentative_def_incomplete_type_arr : Error<
@@ -2969,7 +3319,8 @@ def warn_standalone_specifier : Warning<"'%0' ignored on this declaration">;
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">;
-def err_typecheck_address_of : Error<"address of %0 requested">;
+def err_typecheck_address_of : Error<"address of %select{bit-field"
+ "|vector element|property expression|register variable}0 requested">;
def ext_typecheck_addrof_void : Extension<
"ISO C forbids taking the address of an expression of type 'void'">;
def err_unqualified_pointer_member_function : Error<
@@ -3039,9 +3390,6 @@ def err_stmtexpr_file_scope : Error<
def warn_mixed_sign_comparison : Warning<
"comparison of integers of different signs: %0 and %1">,
InGroup<SignCompare>, DefaultIgnore;
-def warn_mixed_sign_conditional : Warning<
- "operands of ? are integers of different signs: %0 and %1">,
- InGroup<SignCompare>, DefaultIgnore;
def warn_lunsigned_always_true_comparison : Warning<
"comparison of unsigned%select{| enum}2 expression %0 is always %1">,
InGroup<TautologicalCompare>;
@@ -3054,6 +3402,10 @@ def warn_comparison_of_mixed_enum_types : Warning<
def warn_null_in_arithmetic_operation : Warning<
"use of NULL in arithmetic operation">,
InGroup<DiagGroup<"null-arithmetic">>;
+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">>;
def err_invalid_this_use : Error<
"invalid use of 'this' outside of a nonstatic member function">;
@@ -3140,7 +3492,9 @@ def error_nosetter_property_assignment : Error<
"setter method is needed to assign to object using property" " assignment syntax">;
def error_no_subobject_property_setting : Error<
"expression is not assignable">;
-
+def err_qualified_objc_access : Error<
+ "%select{property|ivar}0 access cannot be qualified with '%1'">;
+
def ext_freestanding_complex : Extension<
"complex numbers are an extension in a freestanding C99 implementation">;
@@ -3205,10 +3559,11 @@ def err_incomplete_type_objc_at_encode : Error<
def warn_setter_getter_impl_required : Warning<
"property %0 requires method %1 to be defined - "
- "use @synthesize, @dynamic or provide a method implementation">;
+ "use @synthesize, @dynamic or provide a method implementation "
+ "in this class implementation">;
def warn_setter_getter_impl_required_in_category : Warning<
"property %0 requires method %1 to be defined - "
- "use @dynamic or provide a method implementation in category">;
+ "use @dynamic or provide a method implementation in this category">;
def note_property_impl_required : Note<
"implementation is here">;
def note_parameter_named_here : Note<
@@ -3326,8 +3681,8 @@ def err_array_size_ambiguous_conversion : Error<
"enumeration type">;
def ext_array_size_conversion : Extension<
"implicit conversion from array size expression of type %0 to "
- "%select{integral|enumeration}1 type %2 is a C++0x extension">,
- InGroup<CXX0x>;
+ "%select{integral|enumeration}1 type %2 is a C++11 extension">,
+ InGroup<CXX11>;
def err_address_space_qualified_new : Error<
"'new' cannot allocate objects of type %0 in address space '%1'">;
def err_address_space_qualified_delete : Error<
@@ -3343,7 +3698,7 @@ 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">;
-def err_delete_incomplete_class_type : Warning<
+def err_delete_incomplete_class_type : Error<
"deleting incomplete class type %0; no conversions to pointer type">;
def warn_delete_array_type : Warning<
"'delete' applied to a pointer-to-array type %0 treated as delete[]">;
@@ -3385,6 +3740,9 @@ def warn_non_virtual_dtor : Warning<
def warn_delete_non_virtual_dtor : Warning<
"delete called on %0 that has virtual functions but non-virtual destructor">,
InGroup<DeleteNonVirtualDtor>, DefaultIgnore;
+def warn_delete_abstract_non_virtual_dtor : Warning<
+ "delete called on %0 that is abstract but has non-virtual destructor">,
+ InGroup<DeleteNonVirtualDtor>;
def warn_overloaded_virtual : Warning<
"%q0 hides overloaded virtual %select{function|functions}1">,
InGroup<OverloadedVirtual>, DefaultIgnore;
@@ -3458,8 +3816,6 @@ def err_not_tag_in_scope : Error<
def err_cannot_form_pointer_to_member_of_reference_type : Error<
"cannot form a pointer-to-member to member %0 of reference type %1">;
-def err_invalid_use_of_bound_member_func : Error<
- "a bound member function may only be called">;
def err_incomplete_object_call : Error<
"incomplete type in call to object of type %0">;
def err_incomplete_pointer_to_member_return : Error<
@@ -3480,7 +3836,7 @@ def note_condition_assign_silence : Note<
"place parentheses around the assignment to silence this warning">;
def warn_equality_with_extra_parens : Warning<"equality comparison with "
- "extraneous parentheses">, InGroup<Parentheses>;
+ "extraneous parentheses">, InGroup<ParenthesesOnEquality>;
def note_equality_comparison_to_assign : Note<
"use '=' to turn this equality comparison into an assignment">;
def note_equality_comparison_silence : Note<
@@ -3501,7 +3857,11 @@ def err_typecheck_convert_incompatible : Error<
"%select{from incompatible type|to parameter of incompatible type|"
"from a function with incompatible result type|to incompatible type|"
"with an expression of incompatible type|to parameter of incompatible type|"
- "to incompatible type}2 %1">;
+ "to incompatible type}2 %1; "
+ "%select{|dereference with *|"
+ "take the address with &|"
+ "remove *|"
+ "remove &}3">;
def warn_incompatible_qualified_id : Warning<
"%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
" %0 "
@@ -3514,13 +3874,21 @@ def ext_typecheck_convert_pointer_int : ExtWarn<
"%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
" %0 "
"%select{from|to parameter of type|from a function with result type|to type|"
- "with an expression of type|to parameter of type|to type}2 %1">;
+ "with an expression of type|to parameter of type|to type}2 %1; "
+ "%select{|dereference with *|"
+ "take the address with &|"
+ "remove *|"
+ "remove &}3">;
def ext_typecheck_convert_int_pointer : ExtWarn<
"incompatible integer to pointer conversion "
"%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
" %0 "
"%select{from|to parameter of type|from a function with result type|to type|"
- "with an expression of type|to parameter of type|to type}2 %1">;
+ "with an expression of type|to parameter of type|to type}2 %1; "
+ "%select{|dereference with *|"
+ "take the address with &|"
+ "remove *|"
+ "remove &}3">;
def ext_typecheck_convert_pointer_void_func : Extension<
"%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
" %0 "
@@ -3539,20 +3907,26 @@ def ext_typecheck_convert_incompatible_pointer : ExtWarn<
"%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
" %0 "
"%select{from|to parameter of type|from a function with result type|to type|"
- "with an expression of type|to parameter of type|to type}2 %1">,
- InGroup<DiagGroup<"incompatible-pointer-types">>;
+ "with an expression of type|to parameter of type|to type}2 %1"
+ "%select{|dereference with *|"
+ "take the address with &|"
+ "remove *|"
+ "remove &}3">,
+ InGroup<IncompatiblePointerTypes>;
def ext_typecheck_convert_discards_qualifiers : ExtWarn<
"%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
" %0 "
"%select{from|to parameter of type|from a function with result type|to type|"
"with an expression of type|to parameter of type|to type}2 %1 discards "
- "qualifiers">;
+ "qualifiers">,
+ InGroup<IncompatiblePointerTypes>;
def ext_nested_pointer_qualifier_mismatch : ExtWarn<
"%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
" %0 "
"%select{from|to parameter of type|from a function with result type|to type|"
"with an expression of type|to parameter of type|to type}2 %1 discards "
- "qualifiers in nested pointer types">;
+ "qualifiers in nested pointer types">,
+ InGroup<IncompatiblePointerTypes>;
def warn_incompatible_vectors : Warning<
"incompatible vector types "
"%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
@@ -3621,19 +3995,23 @@ def note_function_with_incomplete_return_type_declared_here : Note<
def err_call_incomplete_argument : Error<
"argument type %0 is incomplete">;
def err_typecheck_call_too_few_args : Error<
- "too few arguments to %select{function|block|method}0 call, "
+ "too few %select{|||execution configuration }0arguments to "
+ "%select{function|block|method|kernel function}0 call, "
"expected %1, have %2">;
def err_typecheck_call_too_few_args_at_least : Error<
- "too few arguments to %select{function|block|method}0 call, "
+ "too few %select{|||execution configuration }0arguments to "
+ "%select{function|block|method|kernel function}0 call, "
"expected at least %1, have %2">;
def err_typecheck_call_too_many_args : Error<
- "too many arguments to %select{function|block|method}0 call, "
+ "too many %select{|||execution configuration }0arguments to "
+ "%select{function|block|method|kernel function}0 call, "
"expected %1, have %2">;
-def note_typecheck_call_too_many_args : Note<
- "%0 declared here">;
def err_typecheck_call_too_many_args_at_most : Error<
- "too many arguments to %select{function|block|method}0 call, "
+ "too many %select{|||execution configuration }0arguments to "
+ "%select{function|block|method|kernel function}0 call, "
"expected at most %1, have %2">;
+def note_callee_decl : Note<
+ "%0 declared here">;
def warn_call_wrong_number_of_arguments : Warning<
"too %select{few|many}0 arguments in call to %1">;
def err_atomic_builtin_must_be_pointer : Error<
@@ -3644,6 +4022,15 @@ def err_atomic_builtin_must_be_pointer_intptr : Error<
def err_atomic_builtin_pointer_size : Error<
"first argument to atomic builtin must be a pointer to 1,2,4,8 or 16 byte "
"type (%0 invalid)">;
+def err_atomic_op_needs_atomic : Error<
+ "first argument to atomic operation must be a pointer to _Atomic "
+ "type (%0 invalid)">;
+def err_atomic_op_needs_atomic_int_or_ptr : Error<
+ "first argument to atomic operation must be a pointer to atomic "
+ "integer or pointer (%0 invalid)">;
+def err_atomic_op_logical_needs_atomic_int : Error<
+ "first argument to logical atomic operation must be a pointer to atomic "
+ "integer (%0 invalid)">;
def err_deleted_function_use : Error<"attempt to use a deleted function">;
@@ -3653,6 +4040,11 @@ def err_config_scalar_return : Error<
"CUDA special function 'cudaConfigureCall' must have scalar return type">;
def err_kern_call_not_global_function : Error<
"kernel call to non-global function %0">;
+def err_global_call_not_config : Error<
+ "call to global function %0 not configured">;
+def err_ref_bad_target : Error<
+ "reference to %select{__device__|__global__|__host__|__host__ __device__}0 "
+ "function %1 in %select{__device__|__global__|__host__|__host__ __device__}2 function">;
def err_cannot_pass_objc_interface_to_vararg : Error<
@@ -3696,9 +4088,11 @@ def ext_typecheck_cond_incompatible_operands_nonstandard : ExtWarn<
def err_cast_selector_expr : Error<
"cannot type cast @selector expression">;
def warn_typecheck_cond_incompatible_pointers : ExtWarn<
- "pointer type mismatch (%0 and %1)">;
+ "pointer type mismatch (%0 and %1)">,
+ InGroup<DiagGroup<"pointer-type-mismatch">>;
def warn_typecheck_cond_pointer_integer_mismatch : ExtWarn<
- "pointer/integer type mismatch in conditional expression (%0 and %1)">;
+ "pointer/integer type mismatch in conditional expression (%0 and %1)">,
+ InGroup<DiagGroup<"conditional-type-mismatch">>;
def err_typecheck_choose_expr_requires_constant : Error<
"'__builtin_choose_expr' requires a constant expression">;
def ext_typecheck_expression_not_constant_but_accepted : Extension<
@@ -3715,6 +4109,14 @@ def warn_unused_property_expr : Warning<
def warn_unused_call : Warning<
"ignoring return value of function declared with %0 attribute">,
InGroup<UnusedValue>;
+def warn_unused_result : Warning<
+ "ignoring return value of function declared with warn_unused_result "
+ "attribute">, InGroup<DiagGroup<"unused-result">>;
+def warn_unused_comparison : Warning<
+ "%select{equality|inequality}0 comparison result unused">,
+ InGroup<UnusedComparison>;
+def note_inequality_comparison_to_or_assign : Note<
+ "use '|=' to turn this inequality comparison into an or-assignment">;
def err_incomplete_type_used_in_type_trait_expr : Error<
"incomplete type %0 used in type trait expression">;
@@ -3798,11 +4200,18 @@ def err_not_direct_base_or_virtual : Error<
def err_in_class_initializer_non_const : Error<
"non-const static data member must be initialized out of line">;
+def err_in_class_initializer_volatile : Error<
+ "static const volatile data member must be initialized out of line">;
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 C++0x extension">, InGroup<CXX0xStaticNonIntegralInitializer>;
+ "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">;
+def err_in_class_initializer_literal_type : Error<
+ "in-class initializer for static data member of type %0 requires "
+ "'constexpr' specifier">;
def err_in_class_initializer_non_constant : Error<
"in-class initializer is not a constant expression">;
@@ -3941,7 +4350,13 @@ def err_literal_operator_outside_namespace : Error<
// FIXME: This diagnostic sucks
def err_literal_operator_params : Error<
"parameter declaration for literal operator %0 is not valid">;
-
+def warn_user_literal_hexfloat : Warning<
+ "user-defined literal with suffix '%0' is preempted by C99 hexfloat "
+ "extension">, InGroup<UserDefinedLiterals>;
+def warn_user_literal_reserved : Warning<
+ "user-defined literals not starting with '_' are reserved by the "
+ "implementation">, InGroup<UserDefinedLiterals>;
+
// C++ conversion functions
def err_conv_function_not_member : Error<
"conversion function must be a non-static member function">;
@@ -3969,11 +4384,11 @@ def warn_conv_to_void_not_used : Warning<
def warn_not_compound_assign : Warning<
"use of unary operator that may be intended as compound assignment (%0=)">;
-// C++0x explicit conversion operators
+// C++11 explicit conversion operators
def warn_explicit_conversion_functions : Warning<
- "explicit conversion functions are a C++0x extension">, InGroup<CXX0x>;
+ "explicit conversion functions are a C++11 extension">, InGroup<CXX11>;
-// C++0x defaulted functions
+// C++11 defaulted functions
def err_defaulted_default_ctor_params : Error<
"an explicitly-defaulted default constructor must have no parameters">;
def err_defaulted_copy_ctor_params : Error<
@@ -4000,8 +4415,34 @@ def err_defaulted_copy_assign_const_param : Error<
"the parameter for this explicitly-defaulted copy assignment operator is "
"const, but a member or base requires it to be non-const">;
def err_defaulted_copy_assign_quals : Error<
- "an explicitly-defaulted copy assignment operator may not have 'const' "
- "or 'volatile' qualifiers">;
+ "an explicitly-defaulted copy assignment operator may not have 'const', "
+ "'constexpr' or 'volatile' qualifiers">;
+def err_defaulted_move_ctor_params : Error<
+ "an explicitly-defaulted move constructor must have exactly one parameter">;
+def err_defaulted_move_ctor_volatile_param : Error<
+ "the parameter for an explicitly-defaulted move constructor may not be "
+ "volatile">;
+def err_defaulted_move_ctor_const_param : Error<
+ "the parameter for an explicitly-defaulted move constructor may not be "
+ "const">;
+def err_defaulted_move_assign_params : Error<
+ "an explicitly-defaulted move assignment operator must have exactly one "
+ "parameter">;
+def err_defaulted_move_assign_return_type : Error<
+ "an explicitly-defaulted move assignment operator must return an unqualified "
+ "lvalue reference to its class type">;
+def err_defaulted_move_assign_not_ref : Error<
+ "the parameter for an explicitly-defaulted move assignment operator must be an "
+ "rvalue reference type">;
+def err_defaulted_move_assign_volatile_param : Error<
+ "the parameter for an explicitly-defaulted move assignment operator may not "
+ "be volatile">;
+def err_defaulted_move_assign_const_param : Error<
+ "the parameter for an explicitly-defaulted move assignment operator may not "
+ "be const">;
+def err_defaulted_move_assign_quals : Error<
+ "an explicitly-defaulted move assignment operator may not have 'const', "
+ "'constexpr' or 'volatile' qualifiers">;
def err_incorrect_defaulted_exception_spec : Error<
"exception specification of explicitly defaulted %select{default constructor|"
"copy constructor|move constructor|copy assignment operator|move assignment "
@@ -4011,15 +4452,20 @@ def err_out_of_line_default_deletes : Error<
"defaulting this %select{default constructor|copy constructor|move "
"constructor|copy assignment operator|move assignment operator|destructor}0 "
"would delete it after its first declaration">;
-def err_defaulted_move_unsupported : Error<
- "defaulting move functions not yet supported">;
+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;
+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;
def warn_array_index_precedes_bounds : Warning<
"array index of '%0' indexes before the beginning of the array">,
InGroup<DiagGroup<"array-bounds">>;
def warn_array_index_exceeds_bounds : Warning<
- "array index of '%0' indexes past the end of an array (that contains %1 elements)">,
- InGroup<DiagGroup<"array-bounds">>;
+ "array index of '%0' indexes past the end of an array (that contains %1 "
+ "element%s2)">, InGroup<DiagGroup<"array-bounds">>;
def note_array_index_out_of_bounds : Note<
"array %0 declared here">;
@@ -4031,7 +4477,7 @@ def warn_printf_insufficient_data_args : Warning<
def warn_printf_data_arg_not_used : Warning<
"data argument not used by format string">, InGroup<FormatExtraArgs>;
def warn_format_invalid_conversion : Warning<
- "invalid conversion specifier '%0'">, InGroup<Format>;
+ "invalid conversion specifier '%0'">, InGroup<FormatInvalidSpecifier>;
def warn_printf_incomplete_specifier : Warning<
"incomplete format specifier">, InGroup<Format>;
def warn_missing_format_string : Warning<
@@ -4086,20 +4532,38 @@ def warn_scanf_scanlist_incomplete : Warning<
// CHECK: returning address/reference of stack memory
def warn_ret_stack_addr : Warning<
- "address of stack memory associated with local variable %0 returned">;
+ "address of stack memory associated with local variable %0 returned">,
+ InGroup<DiagGroup<"return-stack-address">>;
def warn_ret_stack_ref : Warning<
- "reference to stack memory associated with local variable %0 returned">;
+ "reference to stack memory associated with local variable %0 returned">,
+ InGroup<DiagGroup<"return-stack-address">>;
def warn_ret_local_temp_addr : Warning<
- "returning address of local temporary object">;
+ "returning address of local temporary object">,
+ InGroup<DiagGroup<"return-stack-address">>;
def warn_ret_local_temp_ref : Warning<
- "returning reference to local temporary object">;
+ "returning reference to local temporary object">,
+ InGroup<DiagGroup<"return-stack-address">>;
def warn_ret_addr_label : Warning<
- "returning address of label, which is local">;
+ "returning address of label, which is local">,
+ InGroup<DiagGroup<"return-stack-address">>;
def err_ret_local_block : Error<
"returning block that lives on the local stack">;
def note_ref_var_local_bind : Note<
"binding reference variable %0 here">;
+// Check for initializing a member variable with the address or a reference to
+// a constructor parameter.
+def warn_bind_ref_member_to_parameter : Warning<
+ "binding reference member %0 to stack allocated parameter %1">,
+ InGroup<DiagGroup<"dangling-field">>;
+def warn_init_ptr_member_to_parameter_addr : Warning<
+ "initializing pointer member %0 with the stack address of parameter %1">,
+ InGroup<DiagGroup<"dangling-field">>;
+def warn_bind_ref_member_to_temporary : Warning<
+ "binding reference member %0 to a temporary value">,
+ InGroup<DiagGroup<"dangling-field">>;
+def note_ref_or_ptr_member_declared_here : Note<
+ "%select{reference|pointer}0 member declared here">;
// For non-floating point, expressions of the form x == x or x != x
// should result in a warning, since these always evaluate to a constant.
@@ -4110,7 +4574,8 @@ def warn_comparison_always : Warning<
def warn_stringcompare : Warning<
"result of comparison against %select{a string literal|@encode}0 is "
- "unspecified (use strncmp instead)">;
+ "unspecified (use strncmp instead)">,
+ InGroup<DiagGroup<"string-compare">>;
// Generic selections.
def err_assoc_type_incomplete : Error<
@@ -4138,13 +4603,18 @@ def err_return_in_block_expression : Error<
def err_block_returning_array_function : Error<
"block cannot return %select{array|function}0 type %1">;
+// Builtin annotation string.
+def err_builtin_annotation_not_string_constant : Error<
+ "__builtin_annotation requires a non wide string constant">;
// CFString checking
def err_cfstring_literal_not_string_constant : Error<
- "CFString literal is not a string constant">;
+ "CFString literal is not a string constant">,
+ InGroup<DiagGroup<"CFString-literal">>;
def warn_cfstring_truncated : Warning<
"input conversion stopped due to an input byte that does not "
- "belong to the input codeset UTF-8">;
+ "belong to the input codeset UTF-8">,
+ InGroup<DiagGroup<"CFString-literal">>;
// Statements.
def err_continue_not_in_loop : Error<
@@ -4208,6 +4678,9 @@ def err_second_parameter_to_va_arg_abstract: Error<
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;
+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;
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">;
@@ -4306,13 +4779,20 @@ def err_c99_array_usage_cxx : Error<
"C99-specific array features are not permitted in C++">;
def err_double_requires_fp64 : Error<
"use of type 'double' requires cl_khr_fp64 extension to be enabled">;
+def err_nsconsumed_attribute_mismatch : Error<
+ "overriding method has mismatched ns_consumed attribute on its"
+ " parameter">;
+def err_nsreturns_retained_attribute_mismatch : Error<
+ "overriding method has mismatched ns_returns_%select{not_retained|retained}0"
+ " attributes">;
def note_getter_unavailable : Note<
"or because setter is declared here, but no getter method %0 is found">;
def err_invalid_protocol_qualifiers : Error<
"invalid protocol qualifiers on non-ObjC type">;
def warn_ivar_use_hidden : Warning<
- "local declaration of %0 hides instance variable">;
+ "local declaration of %0 hides instance variable">,
+ InGroup<DiagGroup<"shadow-ivar">>;
def error_ivar_use_in_class_method : Error<
"instance variable %0 accessed in class method">;
def error_implicit_ivar_access : Error<
@@ -4327,6 +4807,9 @@ def warn_attribute_method_def : Warning<
def ext_typecheck_base_super : Warning<
"method parameter type %0 does not match "
"super class method parameter type %1">, InGroup<SuperSubClassMismatch>, DefaultIgnore;
+def warn_missing_method_return_type : Warning<
+ "method has no return type specified; defaults to 'id'">,
+ InGroup<MissingMethodReturnType>, DefaultIgnore;
// Spell-checking diagnostics
def err_unknown_typename_suggest : Error<
@@ -4377,9 +4860,12 @@ def err_sizeof_pack_no_pack_name_suggest : Error<
def note_parameter_pack_here : Note<"parameter pack %0 declared here">;
def err_uncasted_use_of_unknown_any : Error<
- "%0 has unknown type; cast it to its declared type to use it">;
+ "%0 has unknown type; cast it to its declared type to use it">;
def err_uncasted_call_of_unknown_any : Error<
- "%0 has unknown return type; cast the call to its declared return type">;
+ "%0 has unknown return type; cast the call to its declared return type">;
+def err_uncasted_send_to_unknown_any_method : Error<
+ "no known method %select{%objcinstance1|%objcclass1}0; cast the "
+ "message send to the method's return type">;
def err_unsupported_unknown_any_decl : Error<
"%0 has unknown type, which is unsupported for this kind of declaration">;
def err_unsupported_unknown_any_expr : Error<
@@ -4391,6 +4877,8 @@ def err_unknown_any_addrof : Error<
"can only be cast to a pointer type">;
def err_unknown_any_var_function_type : Error<
"variable %0 with unknown type cannot be given a function type">;
+def err_unknown_any_function : Error<
+ "function %0 with unknown type must be given a function type">;
def err_filter_expression_integral : Error<
"filter expression type should be an integral value not %0">;
@@ -4409,14 +4897,31 @@ 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 : Note<
+def note_related_result_type_overridden_family : Note<
"overridden method is part of the '%select{|alloc|copy|init|mutableCopy|"
- "new|autorelease|dealloc|release|retain|retainCount|self}0' method family">;
+ "new|autorelease|dealloc|finalize|release|retain|retainCount|self}0' method "
+ "family">;
+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)">;
}
+let CategoryName = "Modules Issue" in {
+def err_module_private_follows_public : Error<
+ "__module_private__ declaration of %0 follows public declaration">;
+def err_module_private_specialization : Error<
+ "%select{template|partial|member}0 specialization cannot be "
+ "declared __module_private__">;
+def err_module_private_local : Error<
+ "%select{local variable|parameter|typedef}0 %1 cannot be declared "
+ "__module_private__">;
+def err_module_private_local_class : Error<
+ "local %select{struct|union|class|enum}0 cannot be declared "
+ "__module_private__">;
+}
+
} // end of sema component.
diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h
index 1324533fa03e..ea8ed9f02fed 100644
--- a/include/clang/Basic/FileManager.h
+++ b/include/clang/Basic/FileManager.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_FILEMANAGER_H
#include "clang/Basic/FileSystemOptions.h"
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
@@ -123,9 +124,9 @@ class FileManager : public llvm::RefCountedBase<FileManager> {
/// \brief The virtual directories that we have allocated. For each
/// virtual file (e.g. foo/bar/baz.cpp), we add all of its parent
/// directories (foo/ and foo/bar/) here.
- llvm::SmallVector<DirectoryEntry*, 4> VirtualDirectoryEntries;
+ SmallVector<DirectoryEntry*, 4> VirtualDirectoryEntries;
/// \brief The virtual files that we have allocated.
- llvm::SmallVector<FileEntry*, 4> VirtualFileEntries;
+ SmallVector<FileEntry*, 4> VirtualFileEntries;
/// SeenDirEntries/SeenFileEntries - This is a cache that maps paths
/// to directory/file entries (either real or virtual) we have
@@ -153,7 +154,7 @@ class FileManager : public llvm::RefCountedBase<FileManager> {
/// Add all ancestors of the given path (pointing to either a file
/// or a directory) as virtual directories.
- void addAncestorsAsVirtualDirs(llvm::StringRef Path);
+ void addAncestorsAsVirtualDirs(StringRef Path);
public:
FileManager(const FileSystemOptions &FileSystemOpts);
@@ -178,41 +179,51 @@ public:
/// getDirectory - Lookup, cache, and verify the specified directory
/// (real or virtual). This returns NULL if the directory doesn't exist.
///
- const DirectoryEntry *getDirectory(llvm::StringRef DirName);
+ /// \param CacheFailure If true and the file does not exist, we'll cache
+ /// the failure to find this file.
+ const DirectoryEntry *getDirectory(StringRef DirName,
+ bool CacheFailure = true);
/// \brief Lookup, cache, and verify the specified file (real or
/// virtual). This returns NULL if the file doesn't exist.
///
- /// \param openFile if true and the file exists, it will be opened.
- const FileEntry *getFile(llvm::StringRef Filename, bool openFile = false);
+ /// \param OpenFile if true and the file exists, it will be opened.
+ ///
+ /// \param CacheFailure If true and the file does not exist, we'll cache
+ /// the failure to find this file.
+ const FileEntry *getFile(StringRef Filename, bool OpenFile = false,
+ bool CacheFailure = true);
+
+ /// \brief Returns the current file system options
+ const FileSystemOptions &getFileSystemOptions() { return FileSystemOpts; }
/// \brief Retrieve a file entry for a "virtual" file that acts as
/// if there were a file with the given name on disk. The file
/// itself is not accessed.
- const FileEntry *getVirtualFile(llvm::StringRef Filename, off_t Size,
+ const FileEntry *getVirtualFile(StringRef Filename, off_t Size,
time_t ModificationTime);
/// \brief Open the specified file as a MemoryBuffer, returning a new
/// MemoryBuffer if successful, otherwise returning null.
llvm::MemoryBuffer *getBufferForFile(const FileEntry *Entry,
std::string *ErrorStr = 0);
- llvm::MemoryBuffer *getBufferForFile(llvm::StringRef Filename,
+ llvm::MemoryBuffer *getBufferForFile(StringRef Filename,
std::string *ErrorStr = 0);
// getNoncachedStatValue - Will get the 'stat' information for the given path.
// If the path is relative, it will be resolved against the WorkingDir of the
// FileManager's FileSystemOptions.
- bool getNoncachedStatValue(llvm::StringRef Path, struct stat &StatBuf);
+ bool getNoncachedStatValue(StringRef Path, struct stat &StatBuf);
/// \brief If path is not absolute and FileSystemOptions set the working
/// directory, the path is modified to be relative to the given
/// working directory.
- void FixupRelativePath(llvm::SmallVectorImpl<char> &path) const;
+ void FixupRelativePath(SmallVectorImpl<char> &path) const;
/// \brief Produce an array mapping from the unique IDs assigned to each
/// file to the corresponding FileEntry pointer.
void GetUniqueIDMapping(
- llvm::SmallVectorImpl<const FileEntry *> &UIDToFiles) const;
+ SmallVectorImpl<const FileEntry *> &UIDToFiles) const;
void PrintStats() const;
};
diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h
index bebcffdddede..5e48a8661974 100644
--- a/include/clang/Basic/IdentifierTable.h
+++ b/include/clang/Basic/IdentifierTable.h
@@ -17,6 +17,7 @@
#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/ADT/SmallString.h"
@@ -49,14 +50,15 @@ namespace clang {
/// set, and all tok::identifier tokens have a pointer to one of these.
class IdentifierInfo {
// Note: DON'T make TokenID a 'tok::TokenKind'; MSVC will treat it as a
- // signed char and TokenKinds > 127 won't be handled correctly.
- unsigned TokenID : 8; // Front-end token ID or tok::identifier.
+ // signed char and TokenKinds > 255 won't be handled correctly.
+ unsigned TokenID : 9; // Front-end token ID or tok::identifier.
// Objective-C keyword ('protocol' in '@protocol') or builtin (__builtin_inf).
// First NUM_OBJC_KEYWORDS values are for Objective-C, the remaining values
// are for builtins.
unsigned ObjCOrBuiltinID :11;
bool HasMacro : 1; // True if there is a #define for this.
bool IsExtension : 1; // True if identifier is a lang extension.
+ bool IsCXX11CompatKeyword : 1; // True if identifier is a keyword in C++11.
bool IsPoisoned : 1; // True if identifier is poisoned.
bool IsCPPOperatorKeyword : 1; // True if ident is a C++ operator keyword.
bool NeedsHandleIdentifier : 1; // See "RecomputeNeedsHandleIdentifier".
@@ -64,7 +66,7 @@ class IdentifierInfo {
// file and wasn't modified since.
bool RevertedTokenID : 1; // True if RevertTokenIDToIdentifier was
// called.
- // 6 bits left in 32-bit word.
+ // 5 bits left in 32-bit word.
void *FETokenInfo; // Managed by the language front-end.
llvm::StringMapEntry<IdentifierInfo*> *Entry;
@@ -113,8 +115,8 @@ public:
}
/// getName - Return the actual identifier string.
- llvm::StringRef getName() const {
- return llvm::StringRef(getNameStart(), getLength());
+ StringRef getName() const {
+ return StringRef(getNameStart(), getLength());
}
/// hasMacroDefinition - Return true if this identifier is #defined to some
@@ -198,6 +200,19 @@ public:
RecomputeNeedsHandleIdentifier();
}
+ /// is/setIsCXX11CompatKeyword - Initialize information about whether or not
+ /// this language token is a keyword in C++11. This controls compatibility
+ /// warnings, and is only true when not parsing C++11. Once a compatibility
+ /// problem has been diagnosed with this keyword, the flag will be cleared.
+ bool isCXX11CompatKeyword() const { return IsCXX11CompatKeyword; }
+ void setIsCXX11CompatKeyword(bool Val) {
+ IsCXX11CompatKeyword = Val;
+ if (Val)
+ NeedsHandleIdentifier = 1;
+ else
+ RecomputeNeedsHandleIdentifier();
+ }
+
/// setIsPoisoned - Mark this identifier as poisoned. After poisoning, the
/// Preprocessor will emit an error every time this token is used.
void setIsPoisoned(bool Value = true) {
@@ -251,7 +266,8 @@ private:
void RecomputeNeedsHandleIdentifier() {
NeedsHandleIdentifier =
(isPoisoned() | hasMacroDefinition() | isCPlusPlusOperatorKeyword() |
- isExtensionToken());
+ isExtensionToken() | isCXX11CompatKeyword() ||
+ (getTokenID() == tok::kw___import_module__));
}
};
@@ -299,8 +315,8 @@ public:
/// advances the iterator for the following string.
///
/// \returns The next string in the identifier table. If there is
- /// no such string, returns an empty \c llvm::StringRef.
- virtual llvm::StringRef Next() = 0;
+ /// no such string, returns an empty \c StringRef.
+ virtual StringRef Next() = 0;
};
/// IdentifierInfoLookup - An abstract class used by IdentifierTable that
@@ -314,7 +330,7 @@ public:
/// Unlike the version in IdentifierTable, this returns a pointer instead
/// of a reference. If the pointer is NULL then the IdentifierInfo cannot
/// be found.
- virtual IdentifierInfo* get(llvm::StringRef Name) = 0;
+ virtual IdentifierInfo* get(StringRef Name) = 0;
/// \brief Retrieve an iterator into the set of all identifiers
/// known to this identifier lookup source.
@@ -376,7 +392,7 @@ public:
/// get - Return the identifier token info for the specified named identifier.
///
- IdentifierInfo &get(llvm::StringRef Name) {
+ IdentifierInfo &get(StringRef Name) {
llvm::StringMapEntry<IdentifierInfo*> &Entry =
HashTable.GetOrCreateValue(Name);
@@ -405,9 +421,10 @@ public:
return *II;
}
- IdentifierInfo &get(llvm::StringRef Name, tok::TokenKind TokenCode) {
+ IdentifierInfo &get(StringRef Name, tok::TokenKind TokenCode) {
IdentifierInfo &II = get(Name);
II.TokenID = TokenCode;
+ assert(II.TokenID == (unsigned) TokenCode && "TokenCode too large");
return II;
}
@@ -417,7 +434,7 @@ public:
/// This is a version of get() meant for external sources that want to
/// introduce or modify an identifier. If they called get(), they would
/// likely end up in a recursion.
- IdentifierInfo &getOwn(llvm::StringRef Name) {
+ IdentifierInfo &getOwn(StringRef Name) {
llvm::StringMapEntry<IdentifierInfo*> &Entry =
HashTable.GetOrCreateValue(Name);
@@ -485,6 +502,7 @@ enum ObjCMethodFamily {
// selector with the given name.
OMF_autorelease,
OMF_dealloc,
+ OMF_finalize,
OMF_release,
OMF_retain,
OMF_retainCount,
@@ -507,7 +525,7 @@ enum { InvalidObjCMethodFamily = (1 << ObjCMethodFamilyBitWidth) - 1 };
/// selectors that take no arguments and selectors that take 1 argument, which
/// accounts for 78% of all selectors in Cocoa.h.
class Selector {
- friend class DiagnosticInfo;
+ friend class Diagnostic;
enum IdentifierInfoFlag {
// MultiKeywordSelector = 0.
@@ -595,7 +613,7 @@ public:
///
/// \returns the name for this slot, which may be the empty string if no
/// name was supplied.
- llvm::StringRef getNameForSlot(unsigned argIndex) const;
+ StringRef getNameForSlot(unsigned argIndex) const;
/// getAsString - Derive the full selector name (e.g. "foo:bar:") and return
/// it as an std::string.
diff --git a/include/clang/Basic/LLVM.h b/include/clang/Basic/LLVM.h
new file mode 100644
index 000000000000..27c459dee4e2
--- /dev/null
+++ b/include/clang/Basic/LLVM.h
@@ -0,0 +1,53 @@
+//===--- LLVM.h - Import various common LLVM datatypes ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file forward declares and imports various common LLVM datatypes that
+// clang wants to use unqualified.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_BASIC_LLVM_H
+#define CLANG_BASIC_LLVM_H
+
+// This should be the only #include, force #includes of all the others on
+// clients.
+#include "llvm/Support/Casting.h"
+
+namespace llvm {
+ // ADT's.
+ class StringRef;
+ class Twine;
+ template<typename T> class ArrayRef;
+ template<typename T, unsigned N> class SmallVector;
+ template<typename T> class SmallVectorImpl;
+
+ class raw_ostream;
+ // TODO: DenseMap, ...
+}
+
+
+namespace clang {
+ // Casting operators.
+ using llvm::isa;
+ using llvm::cast;
+ using llvm::dyn_cast;
+ using llvm::dyn_cast_or_null;
+ using llvm::cast_or_null;
+
+ // ADT's.
+ using llvm::StringRef;
+ using llvm::Twine;
+ using llvm::ArrayRef;
+ using llvm::SmallVector;
+ using llvm::SmallVectorImpl;
+
+ using llvm::raw_ostream;
+} // end namespace clang.
+
+#endif
diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
new file mode 100644
index 000000000000..03882f8cdb09
--- /dev/null
+++ b/include/clang/Basic/LangOptions.def
@@ -0,0 +1,158 @@
+//===--- LangOptions.def - Language option database --------------- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the language options. Users of this file must
+// define the LANGOPT macro to make use of this information.
+// Optionally, the user may also define BENIGN_LANGOPT
+// (for options that don't affect the construction of the AST in an
+// incompatible way), ENUM_LANGOPT (for options that have enumeration,
+// rather than unsigned, type), BENIGN_ENUM_LANGOPT (for benign
+// options that have enumeration type), and VALUE_LANGOPT is a language option
+// that describes a value rather than a flag.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LANGOPT
+# error Define the LANGOPT macro to handle language options
+#endif
+
+#ifndef VALUE_LANGOPT
+# define VALUE_LANGOPT(Name, Bits, Default, Description) \
+ LANGOPT(Name, Bits, Default, Description)
+#endif
+
+#ifndef BENIGN_LANGOPT
+# define BENIGN_LANGOPT(Name, Bits, Default, Description) \
+ LANGOPT(Name, Bits, Default, Description)
+#endif
+
+#ifndef ENUM_LANGOPT
+# define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ LANGOPT(Name, Bits, Default, Description)
+#endif
+
+#ifndef BENIGN_ENUM_LANGOPT
+# define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ ENUM_LANGOPT(Name, Type, Bits, Default, Description)
+#endif
+
+LANGOPT(C99 , 1, 0, "C99")
+LANGOPT(C1X , 1, 0, "C1X")
+LANGOPT(MicrosoftExt , 1, 0, "Microsoft extensions")
+LANGOPT(MicrosoftMode , 1, 0, "Microsoft compatibility mode")
+LANGOPT(Borland , 1, 0, "Borland extensions")
+LANGOPT(CPlusPlus , 1, 0, "C++")
+LANGOPT(CPlusPlus0x , 1, 0, "C++0x")
+LANGOPT(ObjC1 , 1, 0, "Objective-C 1")
+LANGOPT(ObjC2 , 1, 0, "Objective-C 2")
+LANGOPT(ObjCNonFragileABI , 1, 0, "Objective-C modern abi")
+LANGOPT(ObjCNonFragileABI2 , 1, 0, "Objective-C enhanced modern abi")
+BENIGN_LANGOPT(ObjCDefaultSynthProperties , 1, 0,
+ "Objective-C auto-synthesized properties")
+BENIGN_LANGOPT(ObjCInferRelatedResultType , 1, 1,
+ "Objective-C related result type inference")
+LANGOPT(Trigraphs , 1, 0,"trigraphs")
+LANGOPT(BCPLComment , 1, 0, "BCPL-style '//' comments")
+LANGOPT(Bool , 1, 0, "bool, true, and false keywords")
+BENIGN_LANGOPT(DollarIdents , 1, 1, "'$' in identifiers")
+BENIGN_LANGOPT(AsmPreprocessor, 1, 0, "preprocessor in asm mode")
+BENIGN_LANGOPT(GNUMode , 1, 1, "GNU extensions")
+LANGOPT(GNUKeywords , 1, 1, "GNU keywords")
+BENIGN_LANGOPT(ImplicitInt, 1, !C99 && !CPlusPlus, "C89 implicit 'int'")
+LANGOPT(Digraphs , 1, 0, "digraphs")
+BENIGN_LANGOPT(HexFloats , 1, C99, "C99 hexadecimal float constants")
+LANGOPT(CXXOperatorNames , 1, 0, "C++ operator name keywords")
+LANGOPT(AppleKext , 1, 0, "Apple kext support")
+BENIGN_LANGOPT(PascalStrings, 1, 0, "Pascal string support")
+LANGOPT(WritableStrings , 1, 0, "writable string support")
+LANGOPT(ConstStrings , 1, 0, "const-qualified string support")
+LANGOPT(LaxVectorConversions , 1, 1, "lax vector conversions")
+LANGOPT(AltiVec , 1, 0, "AltiVec-style vector initializers")
+LANGOPT(Exceptions , 1, 0, "exception handling")
+LANGOPT(ObjCExceptions , 1, 0, "Objective-C exceptions")
+LANGOPT(CXXExceptions , 1, 0, "C++ exceptions")
+LANGOPT(SjLjExceptions , 1, 0, "setjmp-longjump exception handling")
+LANGOPT(TraditionalCPP , 1, 0, "traditional CPP emulation")
+LANGOPT(RTTI , 1, 1, "run-time type information")
+LANGOPT(MSBitfields , 1, 0, "Microsoft-compatible structure layout")
+LANGOPT(NeXTRuntime , 1, 1, "NeXT Objective-C runtime")
+LANGOPT(Freestanding, 1, 0, "freestanding implementation")
+LANGOPT(NoBuiltin , 1, 0, "disable builtin functions")
+
+BENIGN_LANGOPT(ThreadsafeStatics , 1, 1, "thread-safe static initializers")
+LANGOPT(POSIXThreads , 1, 0, "POSIX thread support")
+LANGOPT(Blocks , 1, 0, "blocks extension to C")
+BENIGN_LANGOPT(EmitAllDecls , 1, 0, "support for emitting all declarations")
+LANGOPT(MathErrno , 1, 1, "errno support for math functions")
+BENIGN_LANGOPT(HeinousExtensions , 1, 0, "Extensions that we really don't like and may be ripped out at any time")
+
+LANGOPT(Optimize , 1, 0, "__OPTIMIZE__ predefined macro")
+LANGOPT(OptimizeSize , 1, 0, "__OPTIMIZE_SIZE__ predefined macro")
+LANGOPT(Static , 1, 0, "__STATIC__ predefined macro (as opposed to __DYNAMIC__)")
+VALUE_LANGOPT(PackStruct , 32, 0,
+ "default struct packing maximum alignment")
+VALUE_LANGOPT(PICLevel , 2, 0, "__PIC__ level")
+LANGOPT(GNUInline , 1, 0, "GNU inline semantics")
+LANGOPT(NoInline , 1, 0, "__NO_INLINE__ predefined macro")
+LANGOPT(Deprecated , 1, 0, "__DEPRECATED predefined macro")
+
+BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __weak/__strong ivars")
+
+BENIGN_LANGOPT(AccessControl , 1, 1, "C++ access control")
+LANGOPT(CharIsSigned , 1, 1, "signed char")
+LANGOPT(ShortWChar , 1, 0, "unsigned short wchar_t")
+
+LANGOPT(ShortEnums , 1, 0, "short enum types")
+
+LANGOPT(OpenCL , 1, 0, "OpenCL")
+LANGOPT(CUDA , 1, 0, "CUDA")
+
+LANGOPT(AssumeSaneOperatorNew , 1, 1, "implicit __attribute__((malloc)) for C++'s new operators")
+BENIGN_LANGOPT(ElideConstructors , 1, 1, "C++ copy constructor elision")
+BENIGN_LANGOPT(CatchUndefined , 1, 0, "catching undefined behavior at run time")
+BENIGN_LANGOPT(DumpRecordLayouts , 1, 0, "dumping the layout of IRgen'd records")
+BENIGN_LANGOPT(DumpVTableLayouts , 1, 0, "dumping the layouts of emitted vtables")
+LANGOPT(NoConstantCFStrings , 1, 0, "no constant CoreFoundation strings")
+BENIGN_LANGOPT(InlineVisibilityHidden , 1, 0, "hidden default visibility for inline C++ methods")
+BENIGN_LANGOPT(ParseUnknownAnytype, 1, 0, "__unknown_anytype")
+BENIGN_LANGOPT(DebuggerSupport , 1, 0, "debugger support")
+
+BENIGN_LANGOPT(SpellChecking , 1, 1, "spell-checking")
+LANGOPT(SinglePrecisionConstants , 1, 0, "treating double-precision floating point constants as single precision constants")
+LANGOPT(FastRelaxedMath , 1, 0, "OpenCL fast relaxed math")
+LANGOPT(DefaultFPContract , 1, 0, "FP_CONTRACT")
+LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment")
+LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated reference counting")
+LANGOPT(ObjCRuntimeHasWeak , 1, 0, "__weak support in the ARC runtime")
+LANGOPT(FakeAddressSpaceMap , 1, 0, "OpenCL fake address space map")
+
+LANGOPT(MRTD , 1, 0, "-mrtd calling convention")
+BENIGN_LANGOPT(DelayedTemplateParsing , 1, 0, "delayed template parsing")
+LANGOPT(BlocksRuntimeOptional , 1, 0, "optional blocks runtime")
+
+ENUM_LANGOPT(GC, GCMode, 2, NonGC, "Objective-C Garbage Collection mode")
+ENUM_LANGOPT(VisibilityMode, Visibility, 3, DefaultVisibility,
+ "symbol visibility")
+ENUM_LANGOPT(StackProtector, StackProtectorMode, 2, SSPOff,
+ "stack protector mode")
+ENUM_LANGOPT(SignedOverflowBehavior, SignedOverflowBehaviorTy, 2, SOB_Undefined,
+ "signed integer overflow handling")
+
+BENIGN_LANGOPT(InstantiationDepth, 32, 1024,
+ "maximum template instantiation 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,
+ "version of Microsoft Visual C/C++")
+
+#undef LANGOPT
+#undef VALUE_LANGOPT
+#undef BENIGN_LANGOPT
+#undef ENUM_LANGOPT
+#undef BENIGN_ENUM_LANGOPT
+
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index dc77d4c1496b..688047ff5bdf 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -23,254 +23,53 @@ namespace clang {
/// enabled, which controls the dialect of C that is accepted.
class LangOptions {
public:
- unsigned Trigraphs : 1; // Trigraphs in source files.
- unsigned BCPLComment : 1; // BCPL-style '//' comments.
- unsigned Bool : 1; // 'bool', 'true', 'false' keywords.
- unsigned DollarIdents : 1; // '$' allowed in identifiers.
- unsigned AsmPreprocessor : 1; // Preprocessor in asm mode.
- unsigned GNUMode : 1; // True in gnu99 mode false in c99 mode (etc)
- unsigned GNUKeywords : 1; // True if GNU-only keywords are allowed
- unsigned ImplicitInt : 1; // C89 implicit 'int'.
- unsigned Digraphs : 1; // C94, C99 and C++
- unsigned HexFloats : 1; // C99 Hexadecimal float constants.
- unsigned C99 : 1; // C99 Support
- unsigned C1X : 1; // C1X Support
- unsigned Microsoft : 1; // Microsoft extensions.
- unsigned Borland : 1; // Borland extensions.
- unsigned CPlusPlus : 1; // C++ Support
- unsigned CPlusPlus0x : 1; // C++0x Support
- unsigned CXXOperatorNames : 1; // Treat C++ operator names as keywords.
-
- unsigned ObjC1 : 1; // Objective-C 1 support enabled.
- unsigned ObjC2 : 1; // Objective-C 2 support enabled.
- unsigned ObjCNonFragileABI : 1; // Objective-C modern abi enabled
- unsigned ObjCNonFragileABI2 : 1; // Objective-C enhanced modern abi enabled
- unsigned ObjCDefaultSynthProperties : 1; // Objective-C auto-synthesized properties.
- unsigned ObjCInferRelatedResultType : 1; // Infer Objective-C related return
- // types
- unsigned AppleKext : 1; // Allow apple kext features.
-
- unsigned PascalStrings : 1; // Allow Pascal strings
- unsigned WritableStrings : 1; // Allow writable strings
- unsigned ConstStrings : 1; // Add const qualifier to strings (-Wwrite-strings)
- unsigned LaxVectorConversions : 1;
- unsigned AltiVec : 1; // Support AltiVec-style vector initializers.
- unsigned Exceptions : 1; // Support exception handling.
- unsigned ObjCExceptions : 1; // Support Objective-C exceptions.
- unsigned CXXExceptions : 1; // Support C++ exceptions.
- unsigned SjLjExceptions : 1; // Use setjmp-longjump exception handling.
- unsigned TraditionalCPP : 1; /// Enable some traditional CPP emulation.
- unsigned RTTI : 1; // Support RTTI information.
-
- unsigned MSBitfields : 1; // MS-compatible structure layout
- unsigned NeXTRuntime : 1; // Use NeXT runtime.
- unsigned Freestanding : 1; // Freestanding implementation
- unsigned NoBuiltin : 1; // Do not use builtin functions (-fno-builtin)
-
- unsigned ThreadsafeStatics : 1; // Whether static initializers are protected
- // by locks.
- unsigned POSIXThreads : 1; // Compiling with POSIX thread support
- // (-pthread)
- unsigned Blocks : 1; // block extension to C
- unsigned EmitAllDecls : 1; // Emit all declarations, even if
- // they are unused.
- unsigned MathErrno : 1; // Math functions must respect errno
- // (modulo the platform support).
-
- unsigned HeinousExtensions : 1; // Extensions that we really don't like and
- // may be ripped out at any time.
-
- unsigned Optimize : 1; // Whether __OPTIMIZE__ should be defined.
- unsigned OptimizeSize : 1; // Whether __OPTIMIZE_SIZE__ should be
- // defined.
- unsigned Static : 1; // Should __STATIC__ be defined (as
- // opposed to __DYNAMIC__).
- unsigned PICLevel : 2; // The value for __PIC__, if non-zero.
-
- unsigned GNUInline : 1; // Should GNU inline semantics be
- // used (instead of C99 semantics).
- unsigned NoInline : 1; // Should __NO_INLINE__ be defined.
-
- unsigned Deprecated : 1; // Should __DEPRECATED be defined.
-
- unsigned ObjCGCBitmapPrint : 1; // Enable printing of gc's bitmap layout
- // for __weak/__strong ivars.
-
- unsigned AccessControl : 1; // Whether C++ access control should
- // be enabled.
- unsigned CharIsSigned : 1; // Whether char is a signed or unsigned type
- unsigned ShortWChar : 1; // Force wchar_t to be unsigned short int.
-
- unsigned ShortEnums : 1; // The enum type will be equivalent to the
- // smallest integer type with enough room.
-
- unsigned OpenCL : 1; // OpenCL C99 language extensions.
- unsigned CUDA : 1; // CUDA C++ language extensions.
-
- unsigned AssumeSaneOperatorNew : 1; // Whether to add __attribute__((malloc))
- // to the declaration of C++'s new
- // operators
- unsigned ElideConstructors : 1; // Whether C++ copy constructors should be
- // elided if possible.
- unsigned CatchUndefined : 1; // Generate code to check for undefined ops.
- unsigned DumpRecordLayouts : 1; /// Dump the layout of IRgen'd records.
- unsigned DumpVTableLayouts : 1; /// Dump the layouts of emitted vtables.
- unsigned NoConstantCFStrings : 1; // Do not do CF strings
- unsigned InlineVisibilityHidden : 1; // Whether inline C++ methods have
- // hidden visibility by default.
- unsigned ParseUnknownAnytype: 1; /// Let the user write __unknown_anytype.
- unsigned DebuggerSupport : 1; /// Do things that only make sense when
- /// supporting a debugger
-
- unsigned SpellChecking : 1; // Whether to perform spell-checking for error
- // recovery.
- unsigned SinglePrecisionConstants : 1; // Whether to treat double-precision
- // floating point constants as
- // single precision constants.
- unsigned FastRelaxedMath : 1; // OpenCL fast relaxed math (on its own,
- // defines __FAST_RELAXED_MATH__).
- unsigned DefaultFPContract : 1; // Default setting for FP_CONTRACT
- // FIXME: This is just a temporary option, for testing purposes.
- unsigned NoBitFieldTypeAlign : 1;
- unsigned ObjCAutoRefCount : 1; // Objective C automated reference counting
- unsigned ObjCRuntimeHasWeak : 1; // The ARC runtime supports __weak
- unsigned ObjCInferRelatedReturnType : 1; // Infer Objective-C related return
- // types
- unsigned FakeAddressSpaceMap : 1; // Use a fake address space map, for
- // testing languages such as OpenCL.
-
- unsigned MRTD : 1; // -mrtd calling convention
- unsigned DelayedTemplateParsing : 1; // Delayed template parsing
-
-private:
- // We declare multibit enums as unsigned because MSVC insists on making enums
- // signed. Set/Query these values using accessors.
- unsigned GC : 2; // Objective-C Garbage Collection modes.
- unsigned SymbolVisibility : 3; // Symbol's visibility.
- unsigned StackProtector : 2; // Whether stack protectors are on.
- unsigned SignedOverflowBehavior : 2; // How to handle signed integer overflow.
-
-public:
- unsigned InstantiationDepth; // Maximum template instantiation depth.
- unsigned NumLargeByValueCopy; // Warn if parameter/return value is larger
- // in bytes than this setting. 0 is no check.
-
- // Version of Microsoft Visual C/C++ we are pretending to be. This is
- // temporary until we support all MS extensions used in Windows SDK and stdlib
- // headers. Sets _MSC_VER.
- unsigned MSCVersion;
-
- std::string ObjCConstantStringClass;
-
+ typedef clang::Visibility Visibility;
+
enum GCMode { NonGC, GCOnly, HybridGC };
enum StackProtectorMode { SSPOff, SSPOn, SSPReq };
-
+
enum SignedOverflowBehaviorTy {
SOB_Undefined, // Default C standard behavior.
SOB_Defined, // -fwrapv
SOB_Trapping // -ftrapv
};
+
+ // Define simple language options (with no accessors).
+#define LANGOPT(Name, Bits, Default, Description) unsigned Name : Bits;
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description)
+#include "clang/Basic/LangOptions.def"
+
+private:
+ // Define language options of enumeration type. These are private, and will
+ // have accessors (below).
+#define LANGOPT(Name, Bits, Default, Description)
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ unsigned Name : Bits;
+#include "clang/Basic/LangOptions.def"
+
+public:
+ std::string ObjCConstantStringClass;
+
/// The name of the handler function to be called when -ftrapv is specified.
/// If none is specified, abort (GCC-compatible behaviour).
std::string OverflowHandler;
- LangOptions() {
- Trigraphs = BCPLComment = Bool = DollarIdents = AsmPreprocessor = 0;
- GNUMode = GNUKeywords = ImplicitInt = Digraphs = 0;
- HexFloats = 0;
- ObjCAutoRefCount = 0;
- ObjCRuntimeHasWeak = 0;
- ObjCInferRelatedReturnType = 0;
- GC = ObjC1 = ObjC2 = ObjCNonFragileABI = ObjCNonFragileABI2 = 0;
- AppleKext = 0;
- ObjCDefaultSynthProperties = 0;
- ObjCInferRelatedResultType = 1;
- NoConstantCFStrings = 0; InlineVisibilityHidden = 0;
- C99 = C1X = Microsoft = Borland = CPlusPlus = CPlusPlus0x = 0;
- CXXOperatorNames = PascalStrings = WritableStrings = ConstStrings = 0;
- Exceptions = ObjCExceptions = CXXExceptions = SjLjExceptions = 0;
- TraditionalCPP = Freestanding = NoBuiltin = 0;
- MSBitfields = 0;
- NeXTRuntime = 1;
- RTTI = 1;
- LaxVectorConversions = 1;
- HeinousExtensions = 0;
- AltiVec = OpenCL = CUDA = StackProtector = 0;
-
- SymbolVisibility = (unsigned) DefaultVisibility;
-
- ThreadsafeStatics = 1;
- POSIXThreads = 0;
- Blocks = 0;
- EmitAllDecls = 0;
- MathErrno = 1;
- SignedOverflowBehavior = SOB_Undefined;
-
- AssumeSaneOperatorNew = 1;
- AccessControl = 1;
- ElideConstructors = 1;
-
- SignedOverflowBehavior = 0;
- ObjCGCBitmapPrint = 0;
-
- InstantiationDepth = 1024;
-
- NumLargeByValueCopy = 0;
- MSCVersion = 0;
-
- Optimize = 0;
- OptimizeSize = 0;
-
- Static = 0;
- PICLevel = 0;
-
- GNUInline = 0;
- NoInline = 0;
-
- Deprecated = 0;
-
- CharIsSigned = 1;
- ShortWChar = 0;
- ShortEnums = 0;
- CatchUndefined = 0;
- DumpRecordLayouts = 0;
- DumpVTableLayouts = 0;
- SpellChecking = 1;
- SinglePrecisionConstants = 0;
- FastRelaxedMath = 0;
- DefaultFPContract = 0;
- NoBitFieldTypeAlign = 0;
- FakeAddressSpaceMap = 0;
- MRTD = 0;
- DelayedTemplateParsing = 0;
- ParseUnknownAnytype = DebuggerSupport = 0;
- }
-
- GCMode getGCMode() const { return (GCMode) GC; }
- void setGCMode(GCMode m) { GC = (unsigned) m; }
-
- StackProtectorMode getStackProtectorMode() const {
- return static_cast<StackProtectorMode>(StackProtector);
- }
- void setStackProtectorMode(StackProtectorMode m) {
- StackProtector = static_cast<unsigned>(m);
- }
-
- Visibility getVisibilityMode() const {
- return (Visibility) SymbolVisibility;
- }
- void setVisibilityMode(Visibility v) { SymbolVisibility = (unsigned) v; }
-
- SignedOverflowBehaviorTy getSignedOverflowBehavior() const {
- return (SignedOverflowBehaviorTy)SignedOverflowBehavior;
- }
- void setSignedOverflowBehavior(SignedOverflowBehaviorTy V) {
- SignedOverflowBehavior = (unsigned)V;
- }
+ LangOptions();
+ // Define accessors/mutators for language options of enumeration type.
+#define LANGOPT(Name, Bits, Default, Description)
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ Type get##Name() const { return static_cast<Type>(Name); } \
+ void set##Name(Type Value) { Name = static_cast<unsigned>(Value); }
+#include "clang/Basic/LangOptions.def"
+
bool isSignedOverflowDefined() const {
return getSignedOverflowBehavior() == SOB_Defined;
}
+
+ /// \brief Reset all of the options that are not considered when building a
+ /// module.
+ void resetNonModularOptions();
};
/// Floating point control options
@@ -296,6 +95,18 @@ public:
}
};
+/// \brief Describes the kind of translation unit being processed.
+enum TranslationUnitKind {
+ /// \brief The translation unit is a complete translation unit.
+ TU_Complete,
+ /// \brief The translation unit is a prefix to a translation unit, and is
+ /// not complete.
+ TU_Prefix,
+ /// \brief The translation unit is a module.
+ TU_Module
+};
+
+ /// \brief
} // end namespace clang
#endif
diff --git a/include/clang/Basic/MacroBuilder.h b/include/clang/Basic/MacroBuilder.h
index 3287b304c97f..1d0f1e899c9e 100644
--- a/include/clang/Basic/MacroBuilder.h
+++ b/include/clang/Basic/MacroBuilder.h
@@ -20,23 +20,23 @@
namespace clang {
class MacroBuilder {
- llvm::raw_ostream &Out;
+ raw_ostream &Out;
public:
- MacroBuilder(llvm::raw_ostream &Output) : Out(Output) {}
+ MacroBuilder(raw_ostream &Output) : Out(Output) {}
/// Append a #define line for macro of the form "#define Name Value\n".
- void defineMacro(const llvm::Twine &Name, const llvm::Twine &Value = "1") {
+ void defineMacro(const Twine &Name, const Twine &Value = "1") {
Out << "#define " << Name << ' ' << Value << '\n';
}
/// Append a #undef line for Name. Name should be of the form XXX
/// and we emit "#undef XXX".
- void undefineMacro(const llvm::Twine &Name) {
+ void undefineMacro(const Twine &Name) {
Out << "#undef " << Name << '\n';
}
/// Directly append Str and a newline to the underlying buffer.
- void append(const llvm::Twine &Str) {
+ void append(const Twine &Str) {
Out << Str << '\n';
}
};
diff --git a/include/clang/Basic/Makefile b/include/clang/Basic/Makefile
index 1338464fd5d9..eeffe2dfb6cd 100644
--- a/include/clang/Basic/Makefile
+++ b/include/clang/Basic/Makefile
@@ -29,26 +29,26 @@ else
CLANG_HAS_VERSION_PATCHLEVEL := 1
endif
-$(ObjDir)/Diagnostic%Kinds.inc.tmp : Diagnostic.td Diagnostic%Kinds.td $(TBLGEN) $(ObjDir)/.dir
+$(ObjDir)/Diagnostic%Kinds.inc.tmp : Diagnostic.td Diagnostic%Kinds.td $(CLANG_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang $(patsubst Diagnostic%Kinds.inc.tmp,%,$(@F)) diagnostic tables with tblgen"
- $(Verb) $(TableGen) -gen-clang-diags-defs -clang-component=$(patsubst Diagnostic%Kinds.inc.tmp,%,$(@F)) -o $(call SYSPATH, $@) $<
+ $(Verb) $(ClangTableGen) -gen-clang-diags-defs -clang-component=$(patsubst Diagnostic%Kinds.inc.tmp,%,$(@F)) -o $(call SYSPATH, $@) $<
-$(ObjDir)/DiagnosticIndexName.inc.tmp : Diagnostic.td $(INPUT_TDS) $(TBLGEN) $(ObjDir)/.dir
+$(ObjDir)/DiagnosticIndexName.inc.tmp : Diagnostic.td $(INPUT_TDS) $(CLANG_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang diagnostic name index with tblgen"
- $(Verb) $(TableGen) -gen-clang-diags-index-name -o $(call SYSPATH, $@) $<
+ $(Verb) $(ClangTableGen) -gen-clang-diags-index-name -o $(call SYSPATH, $@) $<
-$(ObjDir)/DiagnosticGroups.inc.tmp : Diagnostic.td DiagnosticGroups.td $(INPUT_TDS) $(TBLGEN) $(ObjDir)/.dir
+$(ObjDir)/DiagnosticGroups.inc.tmp : Diagnostic.td DiagnosticGroups.td $(INPUT_TDS) $(CLANG_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang diagnostic groups with tblgen"
- $(Verb) $(TableGen) -gen-clang-diag-groups -o $(call SYSPATH, $@) $<
+ $(Verb) $(ClangTableGen) -gen-clang-diag-groups -o $(call SYSPATH, $@) $<
-$(ObjDir)/AttrList.inc.tmp : Attr.td $(TBLGEN) $(ObjDir)/.dir
+$(ObjDir)/AttrList.inc.tmp : Attr.td $(CLANG_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang attribute list with tblgen"
- $(Verb) $(TableGen) -gen-clang-attr-list -o $(call SYSPATH, $@) \
+ $(Verb) $(ClangTableGen) -gen-clang-attr-list -o $(call SYSPATH, $@) \
-I $(PROJ_SRC_DIR)/../.. $<
-$(ObjDir)/arm_neon.inc.tmp : arm_neon.td $(TBLGEN) $(ObjDir)/.dir
+$(ObjDir)/arm_neon.inc.tmp : arm_neon.td $(CLANG_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang arm_neon.inc with tblgen"
- $(Verb) $(TableGen) -gen-arm-neon-sema -o $(call SYSPATH, $@) $<
+ $(Verb) $(ClangTableGen) -gen-arm-neon-sema -o $(call SYSPATH, $@) $<
$(ObjDir)/Version.inc.tmp : Version.inc.in Makefile $(LLVM_OBJ_ROOT)/Makefile.config $(ObjDir)/.dir
$(Echo) "Updating Clang version info."
diff --git a/include/clang/Basic/OnDiskHashTable.h b/include/clang/Basic/OnDiskHashTable.h
index 267ecbcd6df4..7328b1a6bbfa 100644
--- a/include/clang/Basic/OnDiskHashTable.h
+++ b/include/clang/Basic/OnDiskHashTable.h
@@ -28,31 +28,31 @@ namespace io {
typedef uint32_t Offset;
-inline void Emit8(llvm::raw_ostream& Out, uint32_t V) {
+inline void Emit8(raw_ostream& Out, uint32_t V) {
Out << (unsigned char)(V);
}
-inline void Emit16(llvm::raw_ostream& Out, uint32_t V) {
+inline void Emit16(raw_ostream& Out, uint32_t V) {
Out << (unsigned char)(V);
Out << (unsigned char)(V >> 8);
assert((V >> 16) == 0);
}
-inline void Emit24(llvm::raw_ostream& Out, uint32_t V) {
+inline void Emit24(raw_ostream& Out, uint32_t V) {
Out << (unsigned char)(V);
Out << (unsigned char)(V >> 8);
Out << (unsigned char)(V >> 16);
assert((V >> 24) == 0);
}
-inline void Emit32(llvm::raw_ostream& Out, uint32_t V) {
+inline void Emit32(raw_ostream& Out, uint32_t V) {
Out << (unsigned char)(V);
Out << (unsigned char)(V >> 8);
Out << (unsigned char)(V >> 16);
Out << (unsigned char)(V >> 24);
}
-inline void Emit64(llvm::raw_ostream& Out, uint64_t V) {
+inline void Emit64(raw_ostream& Out, uint64_t V) {
Out << (unsigned char)(V);
Out << (unsigned char)(V >> 8);
Out << (unsigned char)(V >> 16);
@@ -63,7 +63,7 @@ inline void Emit64(llvm::raw_ostream& Out, uint64_t V) {
Out << (unsigned char)(V >> 56);
}
-inline void Pad(llvm::raw_ostream& Out, unsigned A) {
+inline void Pad(raw_ostream& Out, unsigned A) {
Offset off = (Offset) Out.tell();
uint32_t n = ((uintptr_t)(off+A-1) & ~(uintptr_t)(A-1)) - off;
for (; n ; --n)
@@ -182,12 +182,12 @@ public:
InfoObj));
}
- io::Offset Emit(llvm::raw_ostream &out) {
+ io::Offset Emit(raw_ostream &out) {
Info InfoObj;
return Emit(out, InfoObj);
}
- io::Offset Emit(llvm::raw_ostream &out, Info &InfoObj) {
+ io::Offset Emit(raw_ostream &out, Info &InfoObj) {
using namespace clang::io;
// Emit the payload of the table.
@@ -464,6 +464,8 @@ public:
}
item_iterator item_end() { return item_iterator(); }
+ Info &getInfoObj() { return InfoObj; }
+
static OnDiskChainedHashTable* Create(const unsigned char* buckets,
const unsigned char* const base,
const Info &InfoObj = Info()) {
diff --git a/include/clang/Basic/OpenCLExtensions.def b/include/clang/Basic/OpenCLExtensions.def
index 95cc1a9a513f..103fa839b8df 100644
--- a/include/clang/Basic/OpenCLExtensions.def
+++ b/include/clang/Basic/OpenCLExtensions.def
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+// OpenCL 1.1.
OPENCLEXT(cl_khr_fp64)
OPENCLEXT(cl_khr_int64_base_atomics)
OPENCLEXT(cl_khr_int64_extended_atomics)
@@ -25,4 +26,7 @@ OPENCLEXT(cl_khr_local_int32_extended_atomics)
OPENCLEXT(cl_khr_byte_addressable_store)
OPENCLEXT(cl_khr_3d_image_writes)
+// Clang Extensions.
+OPENCLEXT(cl_clang_storage_class_specifiers)
+
#undef OPENCLEXT
diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h
index 7d7c0896f505..c6ca98976555 100644
--- a/include/clang/Basic/PartialDiagnostic.h
+++ b/include/clang/Basic/PartialDiagnostic.h
@@ -33,7 +33,7 @@ public:
/// currently only support up to 10 arguments (%0-%9).
/// A single diagnostic with more than that almost certainly has to
/// be simplified anyway.
- MaxArguments = 10
+ MaxArguments = DiagnosticsEngine::MaxArguments
};
/// NumDiagArgs - This contains the number of entries in Arguments.
@@ -65,7 +65,7 @@ public:
/// only support 10 ranges, could easily be extended if needed.
CharSourceRange DiagRanges[10];
- enum { MaxFixItHints = 3 };
+ enum { MaxFixItHints = DiagnosticsEngine::MaxFixItHints };
/// FixItHints - If valid, provides a hint with some code
/// to insert, remove, or modify at a particular position.
@@ -165,6 +165,8 @@ private:
assert(DiagStorage->NumFixItHints < Storage::MaxFixItHints &&
"Too many code modification hints!");
+ if (DiagStorage->NumFixItHints >= Storage::MaxFixItHints)
+ return; // Don't crash in release builds
DiagStorage->FixItHints[DiagStorage->NumFixItHints++]
= Hint;
}
@@ -190,12 +192,12 @@ public:
*this->DiagStorage = *Other.DiagStorage;
}
- PartialDiagnostic(const DiagnosticInfo &Other, StorageAllocator &Allocator)
+ PartialDiagnostic(const Diagnostic &Other, StorageAllocator &Allocator)
: DiagID(Other.getID()), DiagStorage(0), Allocator(&Allocator)
{
// Copy arguments.
for (unsigned I = 0, N = Other.getNumArgs(); I != N; ++I) {
- if (Other.getArgKind(I) == Diagnostic::ak_std_string)
+ if (Other.getArgKind(I) == DiagnosticsEngine::ak_std_string)
AddString(Other.getArgStdStr(I));
else
AddTaggedVal(Other.getRawArg(I), Other.getArgKind(I));
@@ -230,7 +232,7 @@ public:
unsigned getDiagID() const { return DiagID; }
- void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const {
+ void AddTaggedVal(intptr_t V, DiagnosticsEngine::ArgumentKind Kind) const {
if (!DiagStorage)
DiagStorage = getStorage();
@@ -240,14 +242,14 @@ public:
DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V;
}
- void AddString(llvm::StringRef V) const {
+ void AddString(StringRef V) const {
if (!DiagStorage)
DiagStorage = getStorage();
assert(DiagStorage->NumDiagArgs < Storage::MaxArguments &&
"Too many arguments to diagnostic!");
DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs]
- = Diagnostic::ak_std_string;
+ = DiagnosticsEngine::ak_std_string;
DiagStorage->DiagArgumentsStr[DiagStorage->NumDiagArgs++] = V;
}
@@ -257,12 +259,12 @@ public:
// Add all arguments.
for (unsigned i = 0, e = DiagStorage->NumDiagArgs; i != e; ++i) {
- if ((Diagnostic::ArgumentKind)DiagStorage->DiagArgumentsKind[i]
- == Diagnostic::ak_std_string)
+ if ((DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]
+ == DiagnosticsEngine::ak_std_string)
DB.AddString(DiagStorage->DiagArgumentsStr[i]);
else
DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i],
- (Diagnostic::ArgumentKind)DiagStorage->DiagArgumentsKind[i]);
+ (DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]);
}
// Add all ranges.
@@ -285,24 +287,25 @@ public:
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
unsigned I) {
- PD.AddTaggedVal(I, Diagnostic::ak_uint);
+ PD.AddTaggedVal(I, DiagnosticsEngine::ak_uint);
return PD;
}
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
int I) {
- PD.AddTaggedVal(I, Diagnostic::ak_sint);
+ PD.AddTaggedVal(I, DiagnosticsEngine::ak_sint);
return PD;
}
friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
const char *S) {
- PD.AddTaggedVal(reinterpret_cast<intptr_t>(S), Diagnostic::ak_c_string);
+ PD.AddTaggedVal(reinterpret_cast<intptr_t>(S),
+ DiagnosticsEngine::ak_c_string);
return PD;
}
friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
- llvm::StringRef S) {
+ StringRef S) {
PD.AddString(S);
return PD;
diff --git a/include/clang/Basic/PrettyStackTrace.h b/include/clang/Basic/PrettyStackTrace.h
index 5a5d55192b69..06a12644c36e 100644
--- a/include/clang/Basic/PrettyStackTrace.h
+++ b/include/clang/Basic/PrettyStackTrace.h
@@ -30,7 +30,7 @@ namespace clang {
public:
PrettyStackTraceLoc(SourceManager &sm, SourceLocation L, const char *Msg)
: SM(sm), Loc(L), Message(Msg) {}
- virtual void print(llvm::raw_ostream &OS) const;
+ virtual void print(raw_ostream &OS) const;
};
}
diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h
index ee5f96fe937a..154148c16b03 100644
--- a/include/clang/Basic/SourceLocation.h
+++ b/include/clang/Basic/SourceLocation.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_SOURCELOCATION_H
#define LLVM_CLANG_SOURCELOCATION_H
+#include "clang/Basic/LLVM.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include <utility>
#include <functional>
@@ -21,8 +22,6 @@
namespace llvm {
class MemoryBuffer;
- class raw_ostream;
- class StringRef;
template <typename T> struct DenseMapInfo;
template <typename T> struct isPodLike;
}
@@ -35,8 +34,9 @@ class SourceManager;
/// a source file (MemoryBuffer) along with its #include path and #line data.
///
class FileID {
- /// ID - Opaque identifier, 0 is "invalid".
- unsigned ID;
+ /// ID - Opaque identifier, 0 is "invalid". >0 is this module, <-1 is
+ /// something loaded from another module.
+ int ID;
public:
FileID() : ID(0) {}
@@ -49,49 +49,63 @@ public:
bool operator>(const FileID &RHS) const { return RHS < *this; }
bool operator>=(const FileID &RHS) const { return RHS <= *this; }
- static FileID getSentinel() { return get(~0U); }
- unsigned getHashValue() const { return ID; }
+ static FileID getSentinel() { return get(-1); }
+ unsigned getHashValue() const { return static_cast<unsigned>(ID); }
private:
friend class SourceManager;
friend class ASTWriter;
friend class ASTReader;
- static FileID get(unsigned V) {
+ static FileID get(int V) {
FileID F;
F.ID = V;
return F;
}
- unsigned getOpaqueValue() const { return ID; }
+ int getOpaqueValue() const { return ID; }
};
-/// SourceLocation - This is a carefully crafted 32-bit identifier that encodes
-/// a full include stack, line and column number information for a position in
-/// an input translation unit.
+/// \brief Encodes a location in the source. The SourceManager can decode this
+/// to get at the full include stack, line and column information.
+///
+/// Technically, a source location is simply an offset into the manager's view
+/// of the input source, which is all input buffers (including macro
+/// expansions) concatenated in an effectively arbitrary order. The manager
+/// actually maintains two blocks of input buffers. One, starting at offset
+/// 0 and growing upwards, contains all buffers from this module. The other,
+/// starting at the highest possible offset and growing downwards, contains
+/// buffers of loaded modules.
+///
+/// In addition, one bit of SourceLocation is used for quick access to the
+/// information whether the location is in a file or a macro expansion.
+///
+/// It is important that this type remains small. It is currently 32 bits wide.
class SourceLocation {
unsigned ID;
friend class SourceManager;
+ friend class ASTReader;
+ friend class ASTWriter;
enum {
MacroIDBit = 1U << 31
};
public:
- SourceLocation() : ID(0) {} // 0 is an invalid FileID.
+ SourceLocation() : ID(0) {}
bool isFileID() const { return (ID & MacroIDBit) == 0; }
bool isMacroID() const { return (ID & MacroIDBit) != 0; }
- /// isValid - Return true if this is a valid SourceLocation object. Invalid
- /// SourceLocations are often used when events have no corresponding location
- /// in the source (e.g. a diagnostic is required for a command line option).
+ /// \brief Return true if this is a valid SourceLocation object.
///
+ /// Invalid SourceLocations are often used when events have no corresponding
+ /// location in the source (e.g. a diagnostic is required for a command line
+ /// option).
bool isValid() const { return ID != 0; }
bool isInvalid() const { return ID == 0; }
private:
- /// getOffset - Return the index for SourceManager's SLocEntryTable table,
- /// note that this is not an index *into* it though.
+ /// \brief Return the offset into the manager's global input view.
unsigned getOffset() const {
return ID & ~MacroIDBit;
}
@@ -111,10 +125,10 @@ private:
}
public:
- /// getFileLocWithOffset - Return a source location with the specified offset
- /// from this file SourceLocation.
- SourceLocation getFileLocWithOffset(int Offset) const {
- assert(((getOffset()+Offset) & MacroIDBit) == 0 && "invalid location");
+ /// \brief Return a source location with the specified offset from this
+ /// SourceLocation.
+ SourceLocation getLocWithOffset(int Offset) const {
+ assert(((getOffset()+Offset) & MacroIDBit) == 0 && "offset overflow");
SourceLocation L;
L.ID = ID+Offset;
return L;
@@ -150,7 +164,7 @@ public:
return getFromRawEncoding((unsigned)(uintptr_t)Encoding);
}
- void print(llvm::raw_ostream &OS, const SourceManager &SM) const;
+ void print(raw_ostream &OS, const SourceManager &SM) const;
void dump(const SourceManager &SM) const;
};
@@ -261,11 +275,11 @@ public:
FileID getFileID() const;
- FullSourceLoc getInstantiationLoc() const;
+ FullSourceLoc getExpansionLoc() const;
FullSourceLoc getSpellingLoc() const;
- unsigned getInstantiationLineNumber(bool *Invalid = 0) const;
- unsigned getInstantiationColumnNumber(bool *Invalid = 0) const;
+ unsigned getExpansionLineNumber(bool *Invalid = 0) const;
+ unsigned getExpansionColumnNumber(bool *Invalid = 0) const;
unsigned getSpellingLineNumber(bool *Invalid = 0) const;
unsigned getSpellingColumnNumber(bool *Invalid = 0) const;
@@ -276,7 +290,7 @@ public:
/// getBufferData - Return a StringRef to the source buffer data for the
/// specified FileID.
- llvm::StringRef getBufferData(bool *Invalid = 0) const;
+ StringRef getBufferData(bool *Invalid = 0) const;
/// getDecomposedLoc - Decompose the specified location into a raw FileID +
/// Offset pair. The first element is the FileID, the second is the
@@ -326,8 +340,8 @@ public:
/// PresumedLoc - This class represents an unpacked "presumed" location which
/// can be presented to the user. A 'presumed' location can be modified by
-/// #line and GNU line marker directives and is always the instantiation point
-/// of a normal location.
+/// #line and GNU line marker directives and is always the expansion point of
+/// a normal location.
///
/// You can get a PresumedLoc from a SourceLocation with SourceManager.
class PresumedLoc {
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index 6301f3197859..985ddd641271 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_SOURCEMANAGER_H
#define LLVM_CLANG_SOURCEMANAGER_H
+#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/DataTypes.h"
@@ -22,22 +23,37 @@
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/MemoryBuffer.h"
+#include <map>
#include <vector>
#include <cassert>
-namespace llvm {
-class StringRef;
-}
-
namespace clang {
-class Diagnostic;
+class DiagnosticsEngine;
class SourceManager;
class FileManager;
class FileEntry;
class LineTableInfo;
class LangOptions;
-
+class ASTWriter;
+class ASTReader;
+
+/// There are three different types of locations in a file: a spelling
+/// location, an expansion location, and a presumed location.
+///
+/// Given an example of:
+/// #define min(x, y) x < y ? x : y
+///
+/// and then later on a use of min:
+/// #line 17
+/// return min(a, b);
+///
+/// The expansion location is the line in the source code where the macro
+/// was expanded (the return statement), the spelling location is the
+/// location in the source where the macro was originally defined,
+/// and the presumed location is where the line directive states that
+/// the line is 17, or any other line.
+
/// SrcMgr - Public enums and private classes that are part of the
/// SourceManager implementation.
///
@@ -46,7 +62,7 @@ namespace SrcMgr {
/// holds normal user code, system code, or system code which is implicitly
/// 'extern "C"' in C++ mode. Entire directories can be tagged with this
/// (this is maintained by DirectoryLookup and friends) as can specific
- /// FileIDInfos when a #pragma system_header is seen or various other cases.
+ /// FileInfos when a #pragma system_header is seen or various other cases.
///
enum CharacteristicKind {
C_User, C_System, C_ExternCSystem
@@ -61,7 +77,7 @@ namespace SrcMgr {
/// \brief Whether the buffer should not be freed on destruction.
DoNotFreeFlag = 0x02
};
-
+
/// Buffer - The actual buffer containing the characters from the input
/// file. This is owned by the ContentCache object.
/// The bits indicate indicates whether the buffer is invalid.
@@ -92,12 +108,12 @@ namespace SrcMgr {
///
/// \param Diag Object through which diagnostics will be emitted if the
/// buffer cannot be retrieved.
- ///
+ ///
/// \param Loc If specified, is the location that invalid file diagnostics
/// will be emitted at.
///
/// \param Invalid If non-NULL, will be set \c true if an error occurred.
- const llvm::MemoryBuffer *getBuffer(Diagnostic &Diag,
+ const llvm::MemoryBuffer *getBuffer(DiagnosticsEngine &Diag,
const SourceManager &SM,
SourceLocation Loc = SourceLocation(),
bool *Invalid = 0) const;
@@ -109,10 +125,10 @@ namespace SrcMgr {
unsigned getSize() const;
/// getSizeBytesMapped - Returns the number of bytes actually mapped for
- /// this ContentCache. This can be 0 if the MemBuffer was not actually
- /// instantiated.
+ /// this ContentCache. This can be 0 if the MemBuffer was not actually
+ /// expanded.
unsigned getSizeBytesMapped() const;
-
+
/// Returns the kind of memory used to back the memory buffer for
/// this content cache. This is used for performance analysis.
llvm::MemoryBuffer::BufferKind getMemoryBufferKind() const;
@@ -122,7 +138,7 @@ namespace SrcMgr {
Buffer.setPointer(B);
Buffer.setInt(false);
}
-
+
/// \brief Get the underlying buffer, returning NULL if the buffer is not
/// yet available.
const llvm::MemoryBuffer *getRawBuffer() const {
@@ -137,12 +153,12 @@ namespace SrcMgr {
bool isBufferInvalid() const {
return Buffer.getInt() & InvalidFlag;
}
-
+
/// \brief Determine whether the buffer should be freed.
bool shouldFreeBuffer() const {
return (Buffer.getInt() & DoNotFreeFlag) == 0;
}
-
+
ContentCache(const FileEntry *Ent = 0)
: Buffer(0, false), OrigEntry(Ent), ContentsEntry(Ent),
SourceLineCache(0), NumLines(0) {}
@@ -156,14 +172,14 @@ namespace SrcMgr {
/// The copy ctor does not allow copies where source object has either
/// a non-NULL Buffer or SourceLineCache. Ownership of allocated memory
/// is not transferred, so this is a logical error.
- ContentCache(const ContentCache &RHS)
- : Buffer(0, false), SourceLineCache(0)
+ ContentCache(const ContentCache &RHS)
+ : Buffer(0, false), SourceLineCache(0)
{
OrigEntry = RHS.OrigEntry;
ContentsEntry = RHS.ContentsEntry;
- assert (RHS.Buffer.getPointer() == 0 && RHS.SourceLineCache == 0
- && "Passed ContentCache object cannot own a buffer.");
+ assert (RHS.Buffer.getPointer() == 0 && RHS.SourceLineCache == 0 &&
+ "Passed ContentCache object cannot own a buffer.");
NumLines = RHS.NumLines;
}
@@ -177,8 +193,8 @@ namespace SrcMgr {
/// that it represents and include stack information.
///
/// Each FileInfo has include stack information, indicating where it came
- /// from. This information encodes the #include chain that a token was
- /// instantiated from. The main include file has an invalid IncludeLoc.
+ /// from. This information encodes the #include chain that a token was
+ /// expanded from. The main include file has an invalid IncludeLoc.
///
/// FileInfos contain a "ContentCache *", with the contents of the file.
///
@@ -187,16 +203,26 @@ namespace SrcMgr {
/// This is an invalid SLOC for the main file (top of the #include chain).
unsigned IncludeLoc; // Really a SourceLocation
+ /// \brief Number of FileIDs (files and macros) that were created during
+ /// preprocessing of this #include, including this SLocEntry.
+ /// Zero means the preprocessor didn't provide such info for this SLocEntry.
+ unsigned NumCreatedFIDs;
+
/// Data - This contains the ContentCache* and the bits indicating the
/// characteristic of the file and whether it has #line info, all bitmangled
/// together.
uintptr_t Data;
+
+ friend class clang::SourceManager;
+ friend class clang::ASTWriter;
+ friend class clang::ASTReader;
public:
/// get - Return a FileInfo object.
static FileInfo get(SourceLocation IL, const ContentCache *Con,
CharacteristicKind FileCharacter) {
FileInfo X;
X.IncludeLoc = IL.getRawEncoding();
+ X.NumCreatedFIDs = 0;
X.Data = (uintptr_t)Con;
assert((X.Data & 7) == 0 &&"ContentCache pointer insufficiently aligned");
assert((unsigned)FileCharacter < 4 && "invalid file character");
@@ -227,70 +253,68 @@ namespace SrcMgr {
}
};
- /// InstantiationInfo - Each InstantiationInfo encodes the Instantiation
- /// location - where the token was ultimately instantiated, and the
- /// SpellingLoc - where the actual character data for the token came from.
- class InstantiationInfo {
- // Really these are all SourceLocations.
+ /// ExpansionInfo - Each ExpansionInfo encodes the expansion location - where
+ /// the token was ultimately expanded, and the SpellingLoc - where the actual
+ /// character data for the token came from.
+ class ExpansionInfo {
+ // Really these are all SourceLocations.
/// SpellingLoc - Where the spelling for the token can be found.
unsigned SpellingLoc;
- /// InstantiationLocStart/InstantiationLocEnd - In a macro expansion, these
- /// indicate the start and end of the instantiation. In object-like macros,
- /// these will be the same. In a function-like macro instantiation, the
- /// start will be the identifier and the end will be the ')'. Finally, in
+ /// ExpansionLocStart/ExpansionLocEnd - In a macro expansion, these
+ /// indicate the start and end of the expansion. In object-like macros,
+ /// these will be the same. In a function-like macro expansion, the start
+ /// will be the identifier and the end will be the ')'. Finally, in
/// macro-argument instantitions, the end will be 'SourceLocation()', an
/// invalid location.
- unsigned InstantiationLocStart, InstantiationLocEnd;
+ unsigned ExpansionLocStart, ExpansionLocEnd;
public:
SourceLocation getSpellingLoc() const {
return SourceLocation::getFromRawEncoding(SpellingLoc);
}
- SourceLocation getInstantiationLocStart() const {
- return SourceLocation::getFromRawEncoding(InstantiationLocStart);
+ SourceLocation getExpansionLocStart() const {
+ return SourceLocation::getFromRawEncoding(ExpansionLocStart);
}
- SourceLocation getInstantiationLocEnd() const {
+ SourceLocation getExpansionLocEnd() const {
SourceLocation EndLoc =
- SourceLocation::getFromRawEncoding(InstantiationLocEnd);
- return EndLoc.isInvalid() ? getInstantiationLocStart() : EndLoc;
+ SourceLocation::getFromRawEncoding(ExpansionLocEnd);
+ return EndLoc.isInvalid() ? getExpansionLocStart() : EndLoc;
}
- std::pair<SourceLocation,SourceLocation> getInstantiationLocRange() const {
- return std::make_pair(getInstantiationLocStart(),
- getInstantiationLocEnd());
+ std::pair<SourceLocation,SourceLocation> getExpansionLocRange() const {
+ return std::make_pair(getExpansionLocStart(), getExpansionLocEnd());
}
- bool isMacroArgInstantiation() const {
+ bool isMacroArgExpansion() const {
// Note that this needs to return false for default constructed objects.
- return getInstantiationLocStart().isValid() &&
- SourceLocation::getFromRawEncoding(InstantiationLocEnd).isInvalid();
+ return getExpansionLocStart().isValid() &&
+ SourceLocation::getFromRawEncoding(ExpansionLocEnd).isInvalid();
}
- /// create - Return a InstantiationInfo for an expansion. ILStart and
- /// ILEnd specify the instantiation range (where the macro is expanded),
- /// and SL specifies the spelling location (where the characters from the
- /// token come from). All three can refer to normal File SLocs or
- /// instantiation locations.
- static InstantiationInfo create(SourceLocation SL,
- SourceLocation ILStart,
- SourceLocation ILEnd) {
- InstantiationInfo X;
- X.SpellingLoc = SL.getRawEncoding();
- X.InstantiationLocStart = ILStart.getRawEncoding();
- X.InstantiationLocEnd = ILEnd.getRawEncoding();
+ /// create - Return a ExpansionInfo for an expansion. Start and End specify
+ /// the expansion range (where the macro is expanded), and SpellingLoc
+ /// specifies the spelling location (where the characters from the token
+ /// come from). All three can refer to normal File SLocs or expansion
+ /// locations.
+ static ExpansionInfo create(SourceLocation SpellingLoc,
+ SourceLocation Start, SourceLocation End) {
+ ExpansionInfo X;
+ X.SpellingLoc = SpellingLoc.getRawEncoding();
+ X.ExpansionLocStart = Start.getRawEncoding();
+ X.ExpansionLocEnd = End.getRawEncoding();
return X;
}
- /// createForMacroArg - Return a special InstantiationInfo for the
- /// expansion of a macro argument into a function-like macro's body. IL
- /// specifies the instantiation location (where the macro is expanded).
- /// This doesn't need to be a range because a macro is always instantiated
- /// at a macro parameter reference, and macro parameters are always exactly
- /// one token. SL specifies the spelling location (where the characters
- /// from the token come from). IL and SL can both refer to normal File
- /// SLocs or instantiation locations.
+ /// createForMacroArg - Return a special ExpansionInfo for the expansion of
+ /// a macro argument into a function-like macro's body. ExpansionLoc
+ /// specifies the expansion location (where the macro is expanded). This
+ /// doesn't need to be a range because a macro is always expanded at
+ /// a macro parameter reference, and macro parameters are always exactly
+ /// one token. SpellingLoc specifies the spelling location (where the
+ /// characters from the token come from). ExpansionLoc and SpellingLoc can
+ /// both refer to normal File SLocs or expansion locations.
///
/// Given the code:
/// \code
@@ -298,41 +322,41 @@ namespace SrcMgr {
/// F(42);
/// \endcode
///
- /// When expanding '\c F(42)', the '\c x' would call this with an SL
- /// pointing at '\c 42' anad an IL pointing at its location in the
- /// definition of '\c F'.
- static InstantiationInfo createForMacroArg(SourceLocation SL,
- SourceLocation IL) {
+ /// When expanding '\c F(42)', the '\c x' would call this with an
+ /// SpellingLoc pointing at '\c 42' anad an ExpansionLoc pointing at its
+ /// location in the definition of '\c F'.
+ static ExpansionInfo createForMacroArg(SourceLocation SpellingLoc,
+ SourceLocation ExpansionLoc) {
// We store an intentionally invalid source location for the end of the
- // instantiation range to mark that this is a macro argument instantation
- // rather than a normal one.
- return create(SL, IL, SourceLocation());
+ // expansion range to mark that this is a macro argument ion rather than
+ // a normal one.
+ return create(SpellingLoc, ExpansionLoc, SourceLocation());
}
};
/// SLocEntry - This is a discriminated union of FileInfo and
- /// InstantiationInfo. SourceManager keeps an array of these objects, and
+ /// ExpansionInfo. SourceManager keeps an array of these objects, and
/// they are uniquely identified by the FileID datatype.
class SLocEntry {
- unsigned Offset; // low bit is set for instantiation info.
+ unsigned Offset; // low bit is set for expansion info.
union {
FileInfo File;
- InstantiationInfo Instantiation;
+ ExpansionInfo Expansion;
};
public:
unsigned getOffset() const { return Offset >> 1; }
- bool isInstantiation() const { return Offset & 1; }
- bool isFile() const { return !isInstantiation(); }
+ bool isExpansion() const { return Offset & 1; }
+ bool isFile() const { return !isExpansion(); }
const FileInfo &getFile() const {
assert(isFile() && "Not a file SLocEntry!");
return File;
}
- const InstantiationInfo &getInstantiation() const {
- assert(isInstantiation() && "Not an instantiation SLocEntry!");
- return Instantiation;
+ const ExpansionInfo &getExpansion() const {
+ assert(isExpansion() && "Not a macro expansion SLocEntry!");
+ return Expansion;
}
static SLocEntry get(unsigned Offset, const FileInfo &FI) {
@@ -342,10 +366,10 @@ namespace SrcMgr {
return E;
}
- static SLocEntry get(unsigned Offset, const InstantiationInfo &II) {
+ static SLocEntry get(unsigned Offset, const ExpansionInfo &Expansion) {
SLocEntry E;
E.Offset = (Offset << 1) | 1;
- E.Instantiation = II;
+ E.Expansion = Expansion;
return E;
}
};
@@ -356,13 +380,14 @@ class ExternalSLocEntrySource {
public:
virtual ~ExternalSLocEntrySource();
- /// \brief Read the source location entry with index ID.
+ /// \brief Read the source location entry with index ID, which will always be
+ /// less than -1.
///
/// \returns true if an error occurred that prevented the source-location
/// entry from being loaded.
- virtual bool ReadSLocEntry(unsigned ID) = 0;
+ virtual bool ReadSLocEntry(int ID) = 0;
};
-
+
/// IsBeforeInTranslationUnitCache - This class holds the cache used by
/// isBeforeInTranslationUnit. The cache structure is complex enough to be
@@ -371,24 +396,28 @@ class IsBeforeInTranslationUnitCache {
/// L/R QueryFID - These are the FID's of the cached query. If these match up
/// with a subsequent query, the result can be reused.
FileID LQueryFID, RQueryFID;
-
+
+ /// \brief True if LQueryFID was created before RQueryFID. This is used
+ /// to compare macro expansion locations.
+ bool IsLQFIDBeforeRQFID;
+
/// CommonFID - This is the file found in common between the two #include
/// traces. It is the nearest common ancestor of the #include tree.
FileID CommonFID;
-
+
/// L/R CommonOffset - This is the offset of the previous query in CommonFID.
/// Usually, this represents the location of the #include for QueryFID, but if
/// LQueryFID is a parent of RQueryFID (or vise versa) then these can be a
/// random token in the parent.
unsigned LCommonOffset, RCommonOffset;
public:
-
+
/// isCacheValid - Return true if the currently cached values match up with
/// the specified LHS/RHS query. If not, we can't use the cache.
bool isCacheValid(FileID LHS, FileID RHS) const {
return LQueryFID == LHS && RQueryFID == RHS;
}
-
+
/// getCachedResult - If the cache is valid, compute the result given the
/// specified offsets in the LHS/RHS FID's.
bool getCachedResult(unsigned LOffset, unsigned ROffset) const {
@@ -396,38 +425,56 @@ public:
// use the #include loc in the common file.
if (LQueryFID != CommonFID) LOffset = LCommonOffset;
if (RQueryFID != CommonFID) ROffset = RCommonOffset;
+
+ // It is common for multiple macro expansions to be "included" from the same
+ // location (expansion location), in which case use the order of the FileIDs
+ // to determine which came first. This will also take care the case where
+ // one of the locations points at the inclusion/expansion point of the other
+ // in which case its FileID will come before the other.
+ if (LOffset == ROffset &&
+ (LQueryFID != CommonFID || RQueryFID != CommonFID))
+ return IsLQFIDBeforeRQFID;
+
return LOffset < ROffset;
}
-
+
// Set up a new query.
- void setQueryFIDs(FileID LHS, FileID RHS) {
+ void setQueryFIDs(FileID LHS, FileID RHS, bool isLFIDBeforeRFID) {
+ assert(LHS != RHS);
LQueryFID = LHS;
RQueryFID = RHS;
+ IsLQFIDBeforeRQFID = isLFIDBeforeRFID;
+ }
+
+ void clear() {
+ LQueryFID = RQueryFID = FileID();
+ IsLQFIDBeforeRQFID = false;
}
-
+
void setCommonLoc(FileID commonFID, unsigned lCommonOffset,
unsigned rCommonOffset) {
CommonFID = commonFID;
LCommonOffset = lCommonOffset;
RCommonOffset = rCommonOffset;
}
-
+
};
-/// SourceManager - This file handles loading and caching of source files into
-/// memory. This object owns the MemoryBuffer objects for all of the loaded
+/// \brief This class handles loading and caching of source files into memory.
+///
+/// This object owns the MemoryBuffer objects for all of the loaded
/// files and assigns unique FileID's for each unique #include chain.
///
/// The SourceManager can be queried for information about SourceLocation
-/// objects, turning them into either spelling or instantiation locations.
-/// Spelling locations represent where the bytes corresponding to a token came
-/// from and instantiation locations represent where the location is in the
-/// user's view. In the case of a macro expansion, for example, the spelling
-/// location indicates where the expanded token came from and the instantiation
-/// location specifies where it was expanded.
+/// objects, turning them into either spelling or expansion locations. Spelling
+/// locations represent where the bytes corresponding to a token came from and
+/// expansion locations represent where the location is in the user's view. In
+/// the case of a macro expansion, for example, the spelling location indicates
+/// where the expanded token came from and the expansion location specifies
+/// where it was expanded.
class SourceManager : public llvm::RefCountedBase<SourceManager> {
- /// \brief Diagnostic object.
- Diagnostic &Diag;
+ /// \brief DiagnosticsEngine object.
+ DiagnosticsEngine &Diag;
FileManager &FileMgr;
@@ -451,16 +498,37 @@ class SourceManager : public llvm::RefCountedBase<SourceManager> {
/// as they do not refer to a file.
std::vector<SrcMgr::ContentCache*> MemBufferInfos;
- /// SLocEntryTable - This is an array of SLocEntry's that we have created.
- /// FileID is an index into this vector. This array is sorted by the offset.
- std::vector<SrcMgr::SLocEntry> SLocEntryTable;
- /// NextOffset - This is the next available offset that a new SLocEntry can
- /// start at. It is SLocEntryTable.back().getOffset()+size of back() entry.
- unsigned NextOffset;
+ /// \brief The table of SLocEntries that are local to this module.
+ ///
+ /// Positive FileIDs are indexes into this table. Entry 0 indicates an invalid
+ /// expansion.
+ std::vector<SrcMgr::SLocEntry> 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).
+ std::vector<SrcMgr::SLocEntry> LoadedSLocEntryTable;
+
+ /// \brief The starting offset of the next local SLocEntry.
+ ///
+ /// This is LocalSLocEntryTable.back().Offset + the size of that entry.
+ unsigned NextLocalOffset;
+
+ /// \brief The starting offset of the latest batch of loaded SLocEntries.
+ ///
+ /// This is LoadedSLocEntryTable.back().Offset, except that that entry might
+ /// not have been loaded, so that value would be unknown.
+ unsigned CurrentLoadedOffset;
+
+ /// \brief The highest possible offset is 2^31-1, so CurrentLoadedOffset
+ /// starts at 2^31.
+ static const unsigned MaxLoadedOffset = 1U << 31U;
- /// \brief If source location entries are being lazily loaded from
- /// an external source, this vector indicates whether the Ith source
- /// location entry has already been loaded from the external storage.
+ /// \brief A bitmap that indicates whether the entries of LoadedSLocEntryTable
+ /// have already been loaded from the external source.
+ ///
+ /// Same indexing as LoadedSLocEntryTable.
std::vector<bool> SLocEntryLoaded;
/// \brief An external source for source location entries.
@@ -485,6 +553,9 @@ class SourceManager : public llvm::RefCountedBase<SourceManager> {
/// MainFileID - The file ID for the main source file of the translation unit.
FileID MainFileID;
+ /// \brief The file ID for the precompiled preamble there is one.
+ FileID PreambleFileID;
+
// Statistics for -print-stats.
mutable unsigned NumLinearScans, NumBinaryProbes;
@@ -493,17 +564,23 @@ class SourceManager : public llvm::RefCountedBase<SourceManager> {
// Cache for the "fake" buffer used for error-recovery purposes.
mutable llvm::MemoryBuffer *FakeBufferForRecovery;
-
+
+ /// \brief Lazily computed map of macro argument chunks to their expanded
+ /// source location.
+ typedef std::map<unsigned, SourceLocation> MacroArgsMap;
+
+ mutable llvm::DenseMap<FileID, MacroArgsMap *> MacroArgsCacheMap;
+
// SourceManager doesn't support copy construction.
explicit SourceManager(const SourceManager&);
void operator=(const SourceManager&);
public:
- SourceManager(Diagnostic &Diag, FileManager &FileMgr);
+ SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr);
~SourceManager();
void clearIDTables();
- Diagnostic &getDiagnostics() const { return Diag; }
+ DiagnosticsEngine &getDiagnostics() const { return Diag; }
FileManager &getFileManager() const { return FileMgr; }
@@ -513,6 +590,15 @@ public:
OverridenFilesKeepOriginalName = value;
}
+ /// createMainFileIDForMembuffer - Create the FileID for a memory buffer
+ /// that will represent the FileID for the main source. One example
+ /// of when this would be used is when the main source is read from STDIN.
+ FileID createMainFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer) {
+ assert(MainFileID.isInvalid() && "MainFileID already set!");
+ MainFileID = createFileIDForMemBuffer(Buffer);
+ return MainFileID;
+ }
+
//===--------------------------------------------------------------------===//
// MainFileID creation and querying methods.
//===--------------------------------------------------------------------===//
@@ -527,67 +613,56 @@ public:
return MainFileID;
}
- /// \brief Set the file ID for the precompiled preamble, which is also the
- /// main file.
- void SetPreambleFileID(FileID Preamble) {
- assert(MainFileID.isInvalid() && "MainFileID already set!");
- MainFileID = Preamble;
+ /// \brief Set the file ID for the precompiled preamble.
+ void setPreambleFileID(FileID Preamble) {
+ assert(PreambleFileID.isInvalid() && "PreambleFileID already set!");
+ PreambleFileID = Preamble;
}
-
+
+ /// \brief Get the file ID for the precompiled preamble if there is one.
+ FileID getPreambleFileID() const { return PreambleFileID; }
+
//===--------------------------------------------------------------------===//
- // Methods to create new FileID's and instantiations.
+ // Methods to create new FileID's and macro expansions.
//===--------------------------------------------------------------------===//
/// createFileID - Create a new FileID that represents the specified file
/// being #included from the specified IncludePosition. This translates NULL
/// into standard input.
- /// PreallocateID should be non-zero to specify which pre-allocated,
- /// lazily computed source location is being filled in by this operation.
FileID createFileID(const FileEntry *SourceFile, SourceLocation IncludePos,
SrcMgr::CharacteristicKind FileCharacter,
- unsigned PreallocatedID = 0,
- unsigned Offset = 0) {
+ int LoadedID = 0, unsigned LoadedOffset = 0) {
const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile);
assert(IR && "getOrCreateContentCache() cannot return NULL");
- return createFileID(IR, IncludePos, FileCharacter, PreallocatedID, Offset);
+ return createFileID(IR, IncludePos, FileCharacter, LoadedID, LoadedOffset);
}
/// createFileIDForMemBuffer - Create a new FileID that represents the
/// specified memory buffer. This does no caching of the buffer and takes
/// ownership of the MemoryBuffer, so only pass a MemoryBuffer to this once.
FileID createFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer,
- unsigned PreallocatedID = 0,
- unsigned Offset = 0) {
+ int LoadedID = 0, unsigned LoadedOffset = 0) {
return createFileID(createMemBufferContentCache(Buffer), SourceLocation(),
- SrcMgr::C_User, PreallocatedID, Offset);
+ SrcMgr::C_User, LoadedID, LoadedOffset);
}
- /// createMainFileIDForMembuffer - Create the FileID for a memory buffer
- /// that will represent the FileID for the main source. One example
- /// of when this would be used is when the main source is read from STDIN.
- FileID createMainFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer) {
- assert(MainFileID.isInvalid() && "MainFileID already set!");
- MainFileID = createFileIDForMemBuffer(Buffer);
- return MainFileID;
- }
-
- /// createMacroArgInstantiationLoc - Return a new SourceLocation that encodes
- /// the fact that a token from SpellingLoc should actually be referenced from
- /// InstantiationLoc, and that it represents the instantiation of a macro
- /// argument into the function-like macro body.
- SourceLocation createMacroArgInstantiationLoc(SourceLocation Loc,
- SourceLocation InstantiationLoc,
- unsigned TokLength);
+ /// createMacroArgExpansionLoc - Return a new SourceLocation that encodes the
+ /// fact that a token from SpellingLoc should actually be referenced from
+ /// ExpansionLoc, and that it represents the expansion of a macro argument
+ /// into the function-like macro body.
+ SourceLocation createMacroArgExpansionLoc(SourceLocation Loc,
+ SourceLocation ExpansionLoc,
+ unsigned TokLength);
- /// createInstantiationLoc - Return a new SourceLocation that encodes the fact
+ /// createExpansionLoc - Return a new SourceLocation that encodes the fact
/// that a token from SpellingLoc should actually be referenced from
- /// InstantiationLoc.
- SourceLocation createInstantiationLoc(SourceLocation Loc,
- SourceLocation InstantiationLocStart,
- SourceLocation InstantiationLocEnd,
- unsigned TokLength,
- unsigned PreallocatedID = 0,
- unsigned Offset = 0);
+ /// ExpansionLoc.
+ SourceLocation createExpansionLoc(SourceLocation Loc,
+ SourceLocation ExpansionLocStart,
+ SourceLocation ExpansionLocEnd,
+ unsigned TokLength,
+ int LoadedID = 0,
+ unsigned LoadedOffset = 0);
/// \brief Retrieve the memory buffer associated with the given file.
///
@@ -633,11 +708,11 @@ public:
if (MyInvalid || !Entry.isFile()) {
if (Invalid)
*Invalid = true;
-
+
return getFakeBufferForRecovery();
}
-
- return Entry.getFile().getContentCache()->getBuffer(Diag, *this, Loc,
+
+ return Entry.getFile().getContentCache()->getBuffer(Diag, *this, Loc,
Invalid);
}
@@ -647,22 +722,22 @@ public:
if (MyInvalid || !Entry.isFile()) {
if (Invalid)
*Invalid = true;
-
+
return getFakeBufferForRecovery();
}
- return Entry.getFile().getContentCache()->getBuffer(Diag, *this,
- SourceLocation(),
+ return Entry.getFile().getContentCache()->getBuffer(Diag, *this,
+ SourceLocation(),
Invalid);
}
-
+
/// getFileEntryForID - Returns the FileEntry record for the provided FileID.
const FileEntry *getFileEntryForID(FileID FID) const {
bool MyInvalid = false;
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
if (MyInvalid || !Entry.isFile())
return 0;
-
+
return Entry.getFile().getContentCache()->OrigEntry;
}
@@ -677,8 +752,30 @@ public:
///
/// \param FID The file ID whose contents will be returned.
/// \param Invalid If non-NULL, will be set true if an error occurred.
- llvm::StringRef getBufferData(FileID FID, bool *Invalid = 0) const;
+ StringRef getBufferData(FileID FID, bool *Invalid = 0) const;
+ /// \brief Get the number of FileIDs (files and macros) that were created
+ /// during preprocessing of \arg FID, including it.
+ unsigned getNumCreatedFIDsForFileID(FileID FID) const {
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
+ if (Invalid || !Entry.isFile())
+ return 0;
+
+ return Entry.getFile().NumCreatedFIDs;
+ }
+
+ /// \brief Set the number of FileIDs (files and macros) that were created
+ /// during preprocessing of \arg FID, including it.
+ void setNumCreatedFIDsForFileID(FileID FID, unsigned NumFIDs) const {
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
+ if (Invalid || !Entry.isFile())
+ return;
+
+ assert(Entry.getFile().NumCreatedFIDs == 0 && "Already set!");
+ const_cast<SrcMgr::FileInfo &>(Entry.getFile()).NumCreatedFIDs = NumFIDs;
+ }
//===--------------------------------------------------------------------===//
// SourceLocation manipulation methods.
@@ -702,34 +799,52 @@ public:
/// getLocForStartOfFile - Return the source location corresponding to the
/// first byte of the specified file.
SourceLocation getLocForStartOfFile(FileID FID) const {
- assert(FID.ID < SLocEntryTable.size() && "FileID out of range");
bool Invalid = false;
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
if (Invalid || !Entry.isFile())
return SourceLocation();
-
+
unsigned FileOffset = Entry.getOffset();
return SourceLocation::getFileLoc(FileOffset);
}
- /// getInstantiationLoc - Given a SourceLocation object, return the
- /// instantiation location referenced by the ID.
- SourceLocation getInstantiationLoc(SourceLocation Loc) const {
+ /// \brief Returns the include location if \arg FID is a #include'd file
+ /// otherwise it returns an invalid location.
+ SourceLocation getIncludeLoc(FileID FID) const {
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
+ if (Invalid || !Entry.isFile())
+ return SourceLocation();
+
+ return Entry.getFile().getIncludeLoc();
+ }
+
+ /// getExpansionLoc - Given a SourceLocation object, return the expansion
+ /// location referenced by the ID.
+ SourceLocation getExpansionLoc(SourceLocation Loc) const {
// Handle the non-mapped case inline, defer to out of line code to handle
- // instantiations.
+ // expansions.
if (Loc.isFileID()) return Loc;
- return getInstantiationLocSlowCase(Loc);
+ return getExpansionLocSlowCase(Loc);
}
- /// getImmediateInstantiationRange - Loc is required to be an instantiation
- /// location. Return the start/end of the instantiation information.
+ /// \brief Given \arg Loc, if it is a macro location return the expansion
+ /// location or the spelling location, depending on if it comes from a
+ /// macro argument or not.
+ SourceLocation getFileLoc(SourceLocation Loc) const {
+ if (Loc.isFileID()) return Loc;
+ return getFileLocSlowCase(Loc);
+ }
+
+ /// getImmediateExpansionRange - Loc is required to be an expansion location.
+ /// Return the start/end of the expansion information.
std::pair<SourceLocation,SourceLocation>
- getImmediateInstantiationRange(SourceLocation Loc) const;
+ getImmediateExpansionRange(SourceLocation Loc) const;
- /// getInstantiationRange - Given a SourceLocation object, return the
- /// range of tokens covered by the instantiation in the ultimate file.
+ /// getExpansionRange - Given a SourceLocation object, return the range of
+ /// tokens covered by the expansion the ultimate file.
std::pair<SourceLocation,SourceLocation>
- getInstantiationRange(SourceLocation Loc) const;
+ getExpansionRange(SourceLocation Loc) const;
/// getSpellingLoc - Given a SourceLocation object, return the spelling
@@ -737,7 +852,7 @@ public:
/// that make up the lexed token can be found.
SourceLocation getSpellingLoc(SourceLocation Loc) const {
// Handle the non-mapped case inline, defer to out of line code to handle
- // instantiations.
+ // expansions.
if (Loc.isFileID()) return Loc;
return getSpellingLocSlowCase(Loc);
}
@@ -756,11 +871,11 @@ public:
return std::make_pair(FID, Loc.getOffset()-getSLocEntry(FID).getOffset());
}
- /// getDecomposedInstantiationLoc - Decompose the specified location into a
- /// raw FileID + Offset pair. If the location is an instantiation record,
- /// walk through it until we find the final location instantiated.
+ /// getDecomposedExpansionLoc - Decompose the specified location into a raw
+ /// FileID + Offset pair. If the location is an expansion record, walk
+ /// through it until we find the final location expanded.
std::pair<FileID, unsigned>
- getDecomposedInstantiationLoc(SourceLocation Loc) const {
+ getDecomposedExpansionLoc(SourceLocation Loc) const {
FileID FID = getFileID(Loc);
const SrcMgr::SLocEntry *E = &getSLocEntry(FID);
@@ -768,11 +883,11 @@ public:
if (Loc.isFileID())
return std::make_pair(FID, Offset);
- return getDecomposedInstantiationLocSlowCase(E);
+ return getDecomposedExpansionLocSlowCase(E);
}
/// getDecomposedSpellingLoc - Decompose the specified location into a raw
- /// FileID + Offset pair. If the location is an instantiation record, walk
+ /// FileID + Offset pair. If the location is an expansion record, walk
/// through it until we find its spelling record.
std::pair<FileID, unsigned>
getDecomposedSpellingLoc(SourceLocation Loc) const {
@@ -792,12 +907,55 @@ public:
return getDecomposedLoc(SpellingLoc).second;
}
- /// isMacroArgInstantiation - This method tests whether the given source
- /// location represents a macro argument's instantiation into the
- /// function-like macro definition. Such source locations only appear inside
- /// of the instantiation locations representing where a particular
- /// function-like macro was expanded.
- bool isMacroArgInstantiation(SourceLocation Loc) const;
+ /// isMacroArgExpansion - This method tests whether the given source location
+ /// represents a macro argument's expansion into the function-like macro
+ /// definition. Such source locations only appear inside of the expansion
+ /// locations representing where a particular function-like macro was
+ /// expanded.
+ bool isMacroArgExpansion(SourceLocation Loc) const;
+
+ /// \brief Returns true if \arg Loc is inside the [\arg Start, +\arg Length)
+ /// chunk of the source location address space.
+ /// If it's true and \arg RelativeOffset is non-null, it will be set to the
+ /// relative offset of \arg Loc inside the chunk.
+ bool isInSLocAddrSpace(SourceLocation Loc,
+ SourceLocation Start, unsigned Length,
+ unsigned *RelativeOffset = 0) const {
+ assert(((Start.getOffset() < NextLocalOffset &&
+ Start.getOffset()+Length <= NextLocalOffset) ||
+ (Start.getOffset() >= CurrentLoadedOffset &&
+ Start.getOffset()+Length < MaxLoadedOffset)) &&
+ "Chunk is not valid SLoc address space");
+ unsigned LocOffs = Loc.getOffset();
+ unsigned BeginOffs = Start.getOffset();
+ unsigned EndOffs = BeginOffs + Length;
+ if (LocOffs >= BeginOffs && LocOffs < EndOffs) {
+ if (RelativeOffset)
+ *RelativeOffset = LocOffs - BeginOffs;
+ return true;
+ }
+
+ return false;
+ }
+
+ /// \brief Return true if both \arg LHS and \arg RHS are in the local source
+ /// location address space or the loaded one. If it's true and
+ /// \arg RelativeOffset is non-null, it will be set to the offset of \arg RHS
+ /// relative to \arg LHS.
+ bool isInSameSLocAddrSpace(SourceLocation LHS, SourceLocation RHS,
+ int *RelativeOffset) const {
+ unsigned LHSOffs = LHS.getOffset(), RHSOffs = RHS.getOffset();
+ bool LHSLoaded = LHSOffs >= CurrentLoadedOffset;
+ bool RHSLoaded = RHSOffs >= CurrentLoadedOffset;
+
+ if (LHSLoaded == RHSLoaded) {
+ if (RelativeOffset)
+ *RelativeOffset = RHSOffs - LHSOffs;
+ return true;
+ }
+
+ return false;
+ }
//===--------------------------------------------------------------------===//
// Queries about the code at a SourceLocation.
@@ -811,14 +969,14 @@ public:
/// getColumnNumber - Return the column # for the specified file position.
/// This is significantly cheaper to compute than the line number. This
- /// returns zero if the column number isn't known. This may only be called on
- /// a file sloc, so you must choose a spelling or instantiation location
+ /// returns zero if the column number isn't known. This may only be called
+ /// on a file sloc, so you must choose a spelling or expansion location
/// before calling this method.
- unsigned getColumnNumber(FileID FID, unsigned FilePos,
+ unsigned getColumnNumber(FileID FID, unsigned FilePos,
bool *Invalid = 0) const;
unsigned getSpellingColumnNumber(SourceLocation Loc, bool *Invalid = 0) const;
- unsigned getInstantiationColumnNumber(SourceLocation Loc,
- bool *Invalid = 0) const;
+ unsigned getExpansionColumnNumber(SourceLocation Loc,
+ bool *Invalid = 0) const;
unsigned getPresumedColumnNumber(SourceLocation Loc, bool *Invalid = 0) const;
@@ -828,8 +986,7 @@ public:
/// about to emit a diagnostic.
unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid = 0) const;
unsigned getSpellingLineNumber(SourceLocation Loc, bool *Invalid = 0) const;
- unsigned getInstantiationLineNumber(SourceLocation Loc,
- bool *Invalid = 0) const;
+ unsigned getExpansionLineNumber(SourceLocation Loc, bool *Invalid = 0) const;
unsigned getPresumedLineNumber(SourceLocation Loc, bool *Invalid = 0) const;
/// Return the filename or buffer identifier of the buffer the location is in.
@@ -852,8 +1009,8 @@ public:
/// or GNU line marker directives. This provides a view on the data that a
/// user should see in diagnostics, for example.
///
- /// Note that a presumed location is always given as the instantiation point
- /// of an instantiation location, not at the spelling location.
+ /// Note that a presumed location is always given as the expansion point of
+ /// an expansion location, not at the spelling location.
///
/// \returns The presumed location of the specified SourceLocation. If the
/// presumed location cannot be calculate (e.g., because \p Loc is invalid
@@ -884,33 +1041,18 @@ public:
return getFileCharacteristic(Loc) == SrcMgr::C_ExternCSystem;
}
- /// \brief Given a specific chunk of a FileID (FileID with offset+length),
- /// returns true if \arg Loc is inside that chunk and sets relative offset
- /// (offset of \arg Loc from beginning of chunk) to \arg relativeOffset.
- bool isInFileID(SourceLocation Loc,
- FileID FID, unsigned offset, unsigned length,
- unsigned *relativeOffset = 0) const {
- assert(!FID.isInvalid());
- if (Loc.isInvalid())
- return false;
-
- unsigned start = getSLocEntry(FID).getOffset() + offset;
- unsigned end = start + length;
-
-#ifndef NDEBUG
- // Make sure offset/length describe a chunk inside the given FileID.
- unsigned NextOffset;
- if (FID.ID+1 == SLocEntryTable.size())
- NextOffset = getNextOffset();
- else
- NextOffset = getSLocEntry(FID.ID+1).getOffset();
- assert(start < NextOffset);
- assert(end < NextOffset);
-#endif
-
- if (Loc.getOffset() >= start && Loc.getOffset() < end) {
- if (relativeOffset)
- *relativeOffset = Loc.getOffset() - start;
+ /// \brief The size of the SLocEnty that \arg FID represents.
+ unsigned getFileIDSize(FileID FID) const;
+
+ /// \brief Given a specific FileID, returns true if \arg Loc is inside that
+ /// FileID chunk and sets relative offset (offset of \arg Loc from beginning
+ /// of FileID) to \arg relativeOffset.
+ bool isInFileID(SourceLocation Loc, FileID FID,
+ unsigned *RelativeOffset = 0) const {
+ unsigned Offs = Loc.getOffset();
+ if (isOffsetInFileID(FID, Offs)) {
+ if (RelativeOffset)
+ *RelativeOffset = Offs - getSLocEntry(FID).getOffset();
return true;
}
@@ -923,7 +1065,7 @@ public:
/// getLineTableFilenameID - Return the uniqued ID for the specified filename.
///
- unsigned getLineTableFilenameID(llvm::StringRef Str);
+ unsigned getLineTableFilenameID(StringRef Str);
/// AddLineNote - Add a line note to the line table for the FileID and offset
/// specified by Loc. If FilenameID is -1, it is considered to be
@@ -948,11 +1090,11 @@ public:
size_t getContentCacheSize() const {
return ContentCacheAlloc.getTotalMemory();
}
-
+
struct MemoryBufferSizes {
const size_t malloc_bytes;
const size_t mmap_bytes;
-
+
MemoryBufferSizes(size_t malloc_bytes, size_t mmap_bytes)
: malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {}
};
@@ -961,6 +1103,10 @@ public:
/// by heap-backed versus mmap'ed memory.
MemoryBufferSizes getMemoryBufferSizes() const;
+ // Return the amount of memory used for various side tables and
+ // data structures in the SourceManager.
+ size_t getDataStructureSizes() const;
+
//===--------------------------------------------------------------------===//
// Other miscellaneous methods.
//===--------------------------------------------------------------------===//
@@ -969,25 +1115,67 @@ public:
///
/// If the source file is included multiple times, the source location will
/// be based upon the first inclusion.
- SourceLocation getLocation(const FileEntry *SourceFile,
- unsigned Line, unsigned Col);
+ SourceLocation translateFileLineCol(const FileEntry *SourceFile,
+ unsigned Line, unsigned Col) const;
+
+ /// \brief Get the FileID for the given file.
+ ///
+ /// If the source file is included multiple times, the FileID will be the
+ /// first inclusion.
+ FileID translateFile(const FileEntry *SourceFile) const;
+
+ /// \brief Get the source location in \arg FID for the given line:col.
+ /// Returns null location if \arg FID is not a file SLocEntry.
+ SourceLocation translateLineCol(FileID FID,
+ unsigned Line, unsigned Col) const;
+
+ /// \brief If \arg Loc points inside a function macro argument, the returned
+ /// location will be the macro location in which the argument was expanded.
+ /// If a macro argument is used multiple times, the expanded location will
+ /// be at the first expansion of the argument.
+ /// e.g.
+ /// MY_MACRO(foo);
+ /// ^
+ /// Passing a file location pointing at 'foo', will yield a macro location
+ /// where 'foo' was expanded into.
+ SourceLocation getMacroArgExpandedLocation(SourceLocation Loc) const;
/// \brief Determines the order of 2 source locations in the translation unit.
///
/// \returns true if LHS source location comes before RHS, false otherwise.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const;
+ /// \brief Comparison function class.
+ class LocBeforeThanCompare : public std::binary_function<SourceLocation,
+ SourceLocation, bool> {
+ SourceManager &SM;
+
+ public:
+ explicit LocBeforeThanCompare(SourceManager &SM) : SM(SM) { }
+
+ bool operator()(SourceLocation LHS, SourceLocation RHS) const {
+ return SM.isBeforeInTranslationUnit(LHS, RHS);
+ }
+ };
+
/// \brief Determines the order of 2 source locations in the "source location
/// address space".
- static bool isBeforeInSourceLocationOffset(SourceLocation LHS,
- SourceLocation RHS) {
- return isBeforeInSourceLocationOffset(LHS, RHS.getOffset());
+ bool isBeforeInSLocAddrSpace(SourceLocation LHS, SourceLocation RHS) const {
+ return isBeforeInSLocAddrSpace(LHS, RHS.getOffset());
}
/// \brief Determines the order of a source location and a source location
/// offset in the "source location address space".
- static bool isBeforeInSourceLocationOffset(SourceLocation LHS, unsigned RHS) {
- return LHS.getOffset() < RHS;
+ ///
+ /// Note that we always consider source locations loaded from
+ bool isBeforeInSLocAddrSpace(SourceLocation LHS, unsigned RHS) const {
+ unsigned LHSOffset = LHS.getOffset();
+ bool LHSLoaded = LHSOffset >= CurrentLoadedOffset;
+ bool RHSLoaded = RHS >= CurrentLoadedOffset;
+ if (LHSLoaded == RHSLoaded)
+ return LHSOffset < RHS;
+
+ return LHSLoaded;
}
// Iterators over FileInfos.
@@ -1003,53 +1191,80 @@ public:
///
void PrintStats() const;
- unsigned sloc_entry_size() const { return SLocEntryTable.size(); }
-
- // FIXME: Exposing this is a little gross; what we want is a good way
- // to iterate the entries that were not defined in an AST file (or
- // any other external source).
- unsigned sloc_loaded_entry_size() const { return SLocEntryLoaded.size(); }
-
- const SrcMgr::SLocEntry &getSLocEntry(unsigned ID, bool *Invalid = 0) const {
- assert(ID < SLocEntryTable.size() && "Invalid id");
- // If we haven't loaded this source-location entry from the external source
- // yet, do so now.
- if (ExternalSLocEntries &&
- ID < SLocEntryLoaded.size() &&
- !SLocEntryLoaded[ID] &&
- ExternalSLocEntries->ReadSLocEntry(ID) &&
- Invalid)
- *Invalid = true;
-
- return SLocEntryTable[ID];
+ /// \brief Get the number of local SLocEntries we have.
+ unsigned local_sloc_entry_size() const { return LocalSLocEntryTable.size(); }
+
+ /// \brief Get a local SLocEntry. This is exposed for indexing.
+ const SrcMgr::SLocEntry &getLocalSLocEntry(unsigned Index,
+ bool *Invalid = 0) const {
+ assert(Index < LocalSLocEntryTable.size() && "Invalid index");
+ return LocalSLocEntryTable[Index];
+ }
+
+ /// \brief Get the number of loaded SLocEntries we have.
+ unsigned loaded_sloc_entry_size() const { return LoadedSLocEntryTable.size();}
+
+ /// \brief Get a loaded SLocEntry. This is exposed for indexing.
+ const SrcMgr::SLocEntry &getLoadedSLocEntry(unsigned Index, bool *Invalid=0) const {
+ assert(Index < LoadedSLocEntryTable.size() && "Invalid index");
+ if (!SLocEntryLoaded[Index])
+ ExternalSLocEntries->ReadSLocEntry(-(static_cast<int>(Index) + 2));
+ return LoadedSLocEntryTable[Index];
}
const SrcMgr::SLocEntry &getSLocEntry(FileID FID, bool *Invalid = 0) const {
- return getSLocEntry(FID.ID, Invalid);
+ return getSLocEntryByID(FID.ID);
}
- unsigned getNextOffset() const { return NextOffset; }
+ unsigned getNextLocalOffset() const { return NextLocalOffset; }
+
+ void setExternalSLocEntrySource(ExternalSLocEntrySource *Source) {
+ assert(LoadedSLocEntryTable.empty() &&
+ "Invalidating existing loaded entries");
+ ExternalSLocEntries = Source;
+ }
- /// \brief Preallocate some number of source location entries, which
- /// will be loaded as needed from the given external source.
- void PreallocateSLocEntries(ExternalSLocEntrySource *Source,
- unsigned NumSLocEntries,
- unsigned NextOffset);
+ /// \brief Allocate a number of loaded SLocEntries, which will be actually
+ /// loaded on demand from the external source.
+ ///
+ /// NumSLocEntries will be allocated, which occupy a total of TotalSize space
+ /// in the global source view. The lowest ID and the base offset of the
+ /// entries will be returned.
+ std::pair<int, unsigned>
+ AllocateLoadedSLocEntries(unsigned NumSLocEntries, unsigned TotalSize);
+
+ /// \brief Returns true if \arg Loc came from a PCH/Module.
+ bool isLoadedSourceLocation(SourceLocation Loc) const {
+ return Loc.getOffset() >= CurrentLoadedOffset;
+ }
- /// \brief Clear out any preallocated source location entries that
- /// haven't already been loaded.
- void ClearPreallocatedSLocEntries();
+ /// \brief Returns true if \arg Loc did not come from a PCH/Module.
+ bool isLocalSourceLocation(SourceLocation Loc) const {
+ return Loc.getOffset() < NextLocalOffset;
+ }
private:
const llvm::MemoryBuffer *getFakeBufferForRecovery() const;
- /// createInstantiationLoc - Implements the common elements of storing an
- /// instantiation info struct into the SLocEntry table and producing a source
+ /// \brief Get the entry with the given unwrapped FileID.
+ const SrcMgr::SLocEntry &getSLocEntryByID(int ID) const {
+ assert(ID != -1 && "Using FileID sentinel value");
+ if (ID < 0)
+ return getLoadedSLocEntryByID(ID);
+ return getLocalSLocEntry(static_cast<unsigned>(ID));
+ }
+
+ const SrcMgr::SLocEntry &getLoadedSLocEntryByID(int ID) const {
+ return getLoadedSLocEntry(static_cast<unsigned>(-ID - 2));
+ }
+
+ /// createExpansionLoc - Implements the common elements of storing an
+ /// expansion info struct into the SLocEntry table and producing a source
/// location that refers to it.
- SourceLocation createInstantiationLocImpl(const SrcMgr::InstantiationInfo &II,
- unsigned TokLength,
- unsigned PreallocatedID = 0,
- unsigned Offset = 0);
+ SourceLocation createExpansionLocImpl(const SrcMgr::ExpansionInfo &Expansion,
+ unsigned TokLength,
+ int LoadedID = 0,
+ unsigned LoadedOffset = 0);
/// isOffsetInFileID - Return true if the specified FileID contains the
/// specified SourceLocation offset. This is a very hot method.
@@ -1058,10 +1273,17 @@ private:
// If the entry is after the offset, it can't contain it.
if (SLocOffset < Entry.getOffset()) return false;
- // If this is the last entry than it does. Otherwise, the entry after it
- // has to not include it.
- if (FID.ID+1 == SLocEntryTable.size()) return true;
+ // If this is the very last entry then it does.
+ if (FID.ID == -2)
+ return true;
+
+ // If it is the last local entry, then it does if the location is local.
+ if (static_cast<unsigned>(FID.ID+1) == LocalSLocEntryTable.size()) {
+ return SLocOffset < NextLocalOffset;
+ }
+ // Otherwise, the entry after it has to not include it. This works for both
+ // local and loaded entries.
return SLocOffset < getSLocEntry(FileID::get(FID.ID+1)).getOffset();
}
@@ -1071,8 +1293,7 @@ private:
FileID createFileID(const SrcMgr::ContentCache* File,
SourceLocation IncludePos,
SrcMgr::CharacteristicKind DirCharacter,
- unsigned PreallocatedID = 0,
- unsigned Offset = 0);
+ int LoadedID, unsigned LoadedOffset);
const SrcMgr::ContentCache *
getOrCreateContentCache(const FileEntry *SourceFile);
@@ -1083,15 +1304,22 @@ private:
createMemBufferContentCache(const llvm::MemoryBuffer *Buf);
FileID getFileIDSlow(unsigned SLocOffset) const;
+ FileID getFileIDLocal(unsigned SLocOffset) const;
+ FileID getFileIDLoaded(unsigned SLocOffset) const;
- SourceLocation getInstantiationLocSlowCase(SourceLocation Loc) const;
+ SourceLocation getExpansionLocSlowCase(SourceLocation Loc) const;
SourceLocation getSpellingLocSlowCase(SourceLocation Loc) const;
+ SourceLocation getFileLocSlowCase(SourceLocation Loc) const;
std::pair<FileID, unsigned>
- getDecomposedInstantiationLocSlowCase(const SrcMgr::SLocEntry *E) const;
+ getDecomposedExpansionLocSlowCase(const SrcMgr::SLocEntry *E) const;
std::pair<FileID, unsigned>
getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E,
unsigned Offset) const;
+ void computeMacroArgsCache(MacroArgsMap *&MacroArgsCache, FileID FID) const;
+
+ friend class ASTReader;
+ friend class ASTWriter;
};
diff --git a/include/clang/Basic/SourceManagerInternals.h b/include/clang/Basic/SourceManagerInternals.h
index 3f5d1a35e595..1cb16b458f41 100644
--- a/include/clang/Basic/SourceManagerInternals.h
+++ b/include/clang/Basic/SourceManagerInternals.h
@@ -84,7 +84,7 @@ class LineTableInfo {
/// LineEntries - This is a map from FileIDs to a list of line entries (sorted
/// by the offset they occur in the file.
- std::map<unsigned, std::vector<LineEntry> > LineEntries;
+ std::map<int, std::vector<LineEntry> > LineEntries;
public:
LineTableInfo() {
}
@@ -97,32 +97,32 @@ public:
~LineTableInfo() {}
- unsigned getLineTableFilenameID(llvm::StringRef Str);
+ unsigned getLineTableFilenameID(StringRef Str);
const char *getFilename(unsigned ID) const {
assert(ID < FilenamesByID.size() && "Invalid FilenameID");
return FilenamesByID[ID]->getKeyData();
}
unsigned getNumFilenames() const { return FilenamesByID.size(); }
- void AddLineNote(unsigned FID, unsigned Offset,
+ void AddLineNote(int FID, unsigned Offset,
unsigned LineNo, int FilenameID);
- void AddLineNote(unsigned FID, unsigned Offset,
+ void AddLineNote(int FID, unsigned Offset,
unsigned LineNo, int FilenameID,
unsigned EntryExit, SrcMgr::CharacteristicKind FileKind);
/// FindNearestLineEntry - Find the line entry nearest to FID that is before
/// it. If there is no line entry before Offset in FID, return null.
- const LineEntry *FindNearestLineEntry(unsigned FID, unsigned Offset);
+ const LineEntry *FindNearestLineEntry(int FID, unsigned Offset);
// Low-level access
- typedef std::map<unsigned, std::vector<LineEntry> >::iterator iterator;
+ typedef std::map<int, std::vector<LineEntry> >::iterator iterator;
iterator begin() { return LineEntries.begin(); }
iterator end() { return LineEntries.end(); }
/// \brief Add a new line entry that has already been encoded into
/// the internal representation of the line table.
- void AddEntry(unsigned FID, const std::vector<LineEntry> &Entries);
+ void AddEntry(int FID, const std::vector<LineEntry> &Entries);
};
} // end namespace clang
diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
index cfce0ccbc9dd..2a95d6165c0d 100644
--- a/include/clang/Basic/Specifiers.h
+++ b/include/clang/Basic/Specifiers.h
@@ -40,6 +40,7 @@ namespace clang {
TST_char16, // C++0x char16_t
TST_char32, // C++0x char32_t
TST_int,
+ TST_half, // OpenCL half, ARM NEON __fp16
TST_float,
TST_double,
TST_bool, // _Bool
@@ -57,6 +58,7 @@ namespace clang {
TST_underlyingType, // __underlying_type for C++0x
TST_auto, // C++0x auto
TST_unknown_anytype, // __unknown_anytype extension
+ TST_atomic, // C1X _Atomic
TST_error // erroneous type
};
@@ -146,6 +148,7 @@ namespace clang {
SC_PrivateExtern,
// These are only legal on variables.
+ SC_OpenCLWorkGroupLocal,
SC_Auto,
SC_Register
};
diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td
index 73996e43d5da..7b3d7762c24a 100644
--- a/include/clang/Basic/StmtNodes.td
+++ b/include/clang/Basic/StmtNodes.td
@@ -78,6 +78,9 @@ def ParenListExpr : DStmt<Expr>;
def VAArgExpr : DStmt<Expr>;
def GenericSelectionExpr : DStmt<Expr>;
+// Atomic expressions
+def AtomicExpr : DStmt<Expr>;
+
// GNU Extensions.
def AddrLabelExpr : DStmt<Expr>;
def StmtExpr : DStmt<Expr>;
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index 4559cf2f64be..a87af2fbbc7a 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_BASIC_TARGETINFO_H
#define LLVM_CLANG_BASIC_TARGETINFO_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
@@ -31,7 +32,7 @@ struct fltSemantics;
}
namespace clang {
-class Diagnostic;
+class DiagnosticsEngine;
class LangOptions;
class MacroBuilder;
class SourceLocation;
@@ -68,21 +69,24 @@ protected:
unsigned char PointerWidth, PointerAlign;
unsigned char BoolWidth, BoolAlign;
unsigned char IntWidth, IntAlign;
+ unsigned char HalfWidth, HalfAlign;
unsigned char FloatWidth, FloatAlign;
unsigned char DoubleWidth, DoubleAlign;
unsigned char LongDoubleWidth, LongDoubleAlign;
unsigned char LargeArrayMinWidth, LargeArrayAlign;
unsigned char LongWidth, LongAlign;
unsigned char LongLongWidth, LongLongAlign;
+ unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth;
const char *DescriptionString;
const char *UserLabelPrefix;
const char *MCountName;
- const llvm::fltSemantics *FloatFormat, *DoubleFormat, *LongDoubleFormat;
+ const llvm::fltSemantics *HalfFormat, *FloatFormat, *DoubleFormat,
+ *LongDoubleFormat;
unsigned char RegParmMax, SSERegParmMax;
TargetCXXABI CXXABI;
const LangAS::Map *AddrSpaceMap;
- mutable llvm::StringRef PlatformName;
+ mutable StringRef PlatformName;
mutable VersionTuple PlatformMinVersion;
unsigned HasAlignMac68kSupport : 1;
@@ -97,7 +101,8 @@ public:
/// \param Opts - The options to use to initialize the target. The target may
/// modify the options to canonicalize the target feature information to match
/// what the backend expects.
- static TargetInfo* CreateTargetInfo(Diagnostic &Diags, TargetOptions &Opts);
+ static TargetInfo* CreateTargetInfo(DiagnosticsEngine &Diags,
+ TargetOptions &Opts);
virtual ~TargetInfo();
@@ -131,6 +136,16 @@ protected:
/// boundary.
unsigned UseBitFieldTypeAlignment : 1;
+ /// Control whether zero length bitfields (e.g., int : 0;) force alignment of
+ /// the next bitfield. If the alignment of the zero length bitfield is
+ /// greater than the member that follows it, `bar', `bar' will be aligned as
+ /// the type of the zero-length bitfield.
+ unsigned UseZeroLengthBitfieldAlignment : 1;
+
+ /// If non-zero, specifies a fixed alignment value for bitfields that follow
+ /// zero length bitfield, regardless of the zero length bitfield type.
+ unsigned ZeroLengthBitfieldBoundary;
+
public:
IntType getSizeType() const { return SizeType; }
IntType getIntMaxType() const { return IntMaxType; }
@@ -211,6 +226,11 @@ public:
unsigned getChar32Width() const { return getTypeWidth(Char32Type); }
unsigned getChar32Align() const { return getTypeAlign(Char32Type); }
+ /// getHalfWidth/Align/Format - Return the size/align/format of 'half'.
+ unsigned getHalfWidth() const { return HalfWidth; }
+ unsigned getHalfAlign() const { return HalfAlign; }
+ const llvm::fltSemantics &getHalfFormat() const { return *HalfFormat; }
+
/// getFloatWidth/Align/Format - Return the size/align/format of 'float'.
unsigned getFloatWidth() const { return FloatWidth; }
unsigned getFloatAlign() const { return FloatAlign; }
@@ -234,6 +254,14 @@ public:
unsigned getLargeArrayMinWidth() const { return LargeArrayMinWidth; }
unsigned getLargeArrayAlign() const { return LargeArrayAlign; }
+ /// getMaxAtomicPromoteWidth - Return the maximum width lock-free atomic
+ /// operation which will ever be supported for the given target
+ unsigned getMaxAtomicPromoteWidth() const { return MaxAtomicPromoteWidth; }
+ /// getMaxAtomicInlineWidth - Return the maximum width lock-free atomic
+ /// operation which can be inlined given the supported features of the
+ /// given target.
+ unsigned getMaxAtomicInlineWidth() const { return MaxAtomicInlineWidth; }
+
/// getIntMaxTWidth - Return the size of intmax_t and uintmax_t for this
/// target, in bits.
unsigned getIntMaxTWidth() const {
@@ -261,10 +289,24 @@ public:
return MCountName;
}
+ /// useBitFieldTypeAlignment() - Check whether the alignment of bit-field
+ /// types is respected when laying out structures.
bool useBitFieldTypeAlignment() const {
return UseBitFieldTypeAlignment;
}
+ /// useZeroLengthBitfieldAlignment() - Check whether zero length bitfields
+ /// should force alignment of the next member.
+ bool useZeroLengthBitfieldAlignment() const {
+ return UseZeroLengthBitfieldAlignment;
+ }
+
+ /// getZeroLengthBitfieldBoundary() - Get the fixed alignment value in bits
+ /// for a member that follows a zero length bitfield.
+ unsigned getZeroLengthBitfieldBoundary() const {
+ return ZeroLengthBitfieldBoundary;
+ }
+
/// hasAlignMac68kSupport - Check whether this target support '#pragma options
/// align=mac68k'.
bool hasAlignMac68kSupport() const {
@@ -306,16 +348,16 @@ public:
/// isValidClobber - Returns whether the passed in string is
/// a valid clobber in an inline asm statement. This is used by
/// Sema.
- bool isValidClobber(llvm::StringRef Name) const;
+ bool isValidClobber(StringRef Name) const;
/// isValidGCCRegisterName - Returns whether the passed in string
/// is a valid register name according to GCC. This is used by Sema for
/// inline asm statements.
- bool isValidGCCRegisterName(llvm::StringRef Name) const;
+ bool isValidGCCRegisterName(StringRef Name) const;
// getNormalizedGCCRegisterName - Returns the "normalized" GCC register name.
// For example, on x86 it will return "ax" when "eax" is passed in.
- llvm::StringRef getNormalizedGCCRegisterName(llvm::StringRef Name) const;
+ StringRef getNormalizedGCCRegisterName(StringRef Name) const;
struct ConstraintInfo {
enum {
@@ -331,7 +373,7 @@ public:
std::string ConstraintStr; // constraint: "=rm"
std::string Name; // Operand name: [foo] with no []'s.
public:
- ConstraintInfo(llvm::StringRef ConstraintStr, llvm::StringRef Name)
+ ConstraintInfo(StringRef ConstraintStr, StringRef Name)
: Flags(0), TiedOperand(-1), ConstraintStr(ConstraintStr.str()),
Name(Name.str()) {}
@@ -444,7 +486,7 @@ public:
/// and give good diagnostics in cases when the assembler or code generator
/// would otherwise reject the section specifier.
///
- virtual std::string isValidSectionSpecifier(llvm::StringRef SR) const {
+ virtual std::string isValidSectionSpecifier(StringRef SR) const {
return "";
}
@@ -453,11 +495,9 @@ public:
/// language options which change the target configuration.
virtual void setForcedLangOptions(LangOptions &Opts);
- /// getDefaultFeatures - Get the default set of target features for
- /// the \args CPU; this should include all legal feature strings on
- /// the target.
- virtual void getDefaultFeatures(const std::string &CPU,
- llvm::StringMap<bool> &Features) const {
+ /// getDefaultFeatures - Get the default set of target features for the CPU;
+ /// this should include all legal feature strings on the target.
+ virtual void getDefaultFeatures(llvm::StringMap<bool> &Features) const {
}
/// getABI - Get the ABI in use.
@@ -473,10 +513,8 @@ public:
/// setCPU - Target the specific CPU.
///
/// \return - False on error (invalid CPU name).
- //
- // FIXME: Remove this.
virtual bool setCPU(const std::string &Name) {
- return true;
+ return false;
}
/// setABI - Use the specific ABI.
@@ -565,7 +603,7 @@ public:
/// \brief Retrieve the name of the platform as it is used in the
/// availability attribute.
- llvm::StringRef getPlatformName() const { return PlatformName; }
+ StringRef getPlatformName() const { return PlatformName; }
/// \brief Retrieve the minimum desired version of the platform, to
/// which the program should be compiled.
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index 86172b83ff42..35a881c660a2 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -89,6 +89,9 @@ PPKEYWORD(sccs)
PPKEYWORD(assert)
PPKEYWORD(unassert)
+// Clang extensions
+PPKEYWORD(__export_macro__)
+
//===----------------------------------------------------------------------===//
// Language keywords.
//===----------------------------------------------------------------------===//
@@ -114,13 +117,23 @@ TOK(raw_identifier) // Used only in raw lexing mode.
TOK(numeric_constant) // 0x123
// C99 6.4.4: Character Constants
-TOK(char_constant) // 'a' L'b'
+TOK(char_constant) // 'a'
+TOK(wide_char_constant) // L'b'
+
+// C++0x Character Constants
+TOK(utf16_char_constant) // u'a'
+TOK(utf32_char_constant) // U'a'
// C99 6.4.5: String Literals.
TOK(string_literal) // "foo"
TOK(wide_string_literal) // L"foo"
TOK(angle_string_literal)// <foo>
+// C++0x String Literals.
+TOK(utf8_string_literal) // u8"foo"
+TOK(utf16_string_literal)// u"foo"
+TOK(utf32_string_literal)// U"foo"
+
// C99 6.4.6: Punctuators.
PUNCTUATOR(l_square, "[")
PUNCTUATOR(r_square, "]")
@@ -236,6 +249,8 @@ KEYWORD(unsigned , KEYALL)
KEYWORD(void , KEYALL)
KEYWORD(volatile , KEYALL)
KEYWORD(while , KEYALL)
+KEYWORD(_Alignas , KEYALL)
+KEYWORD(_Atomic , KEYALL)
KEYWORD(_Bool , KEYNOCXX)
KEYWORD(_Complex , KEYALL)
KEYWORD(_Generic , KEYALL)
@@ -289,6 +304,7 @@ CXX_KEYWORD_OPERATOR(xor , caret)
CXX_KEYWORD_OPERATOR(xor_eq , caretequal)
// C++0x keywords
+KEYWORD(alignas , KEYCXX0X)
KEYWORD(alignof , KEYCXX0X)
KEYWORD(char16_t , KEYCXX0X)
KEYWORD(char32_t , KEYCXX0X)
@@ -387,6 +403,8 @@ KEYWORD(__array_extent , KEYCXX)
// Apple Extension.
KEYWORD(__private_extern__ , KEYALL)
+KEYWORD(__import_module__ , KEYALL)
+KEYWORD(__module_private__ , KEYALL)
// Microsoft Extension.
KEYWORD(__declspec , KEYALL)
@@ -395,6 +413,7 @@ KEYWORD(__stdcall , KEYALL)
KEYWORD(__fastcall , KEYALL)
KEYWORD(__thiscall , KEYALL)
KEYWORD(__forceinline , KEYALL)
+KEYWORD(__unaligned , KEYMS)
// OpenCL-specific keywords
KEYWORD(__kernel , KEYOPENCL)
@@ -422,6 +441,12 @@ KEYWORD(__pascal , KEYALL)
KEYWORD(__vector , KEYALTIVEC)
KEYWORD(__pixel , KEYALTIVEC)
+// ARM NEON extensions.
+ALIAS("__fp16", half , KEYALL)
+
+// OpenCL Extension.
+KEYWORD(half , KEYOPENCL)
+
// Objective-C ARC keywords.
KEYWORD(__bridge , KEYARC)
KEYWORD(__bridge_transfer , KEYARC)
@@ -455,6 +480,7 @@ ALIAS("__volatile__" , volatile , KEYALL)
// Microsoft extensions which should be disabled in strict conformance mode
KEYWORD(__ptr64 , KEYMS)
+KEYWORD(__ptr32 , KEYMS)
KEYWORD(__w64 , KEYMS)
KEYWORD(__uuidof , KEYMS | KEYBORLAND)
KEYWORD(__try , KEYMS | KEYBORLAND)
diff --git a/include/clang/Basic/VersionTuple.h b/include/clang/Basic/VersionTuple.h
index 91eb68eaad9f..30ef6641efc1 100644
--- a/include/clang/Basic/VersionTuple.h
+++ b/include/clang/Basic/VersionTuple.h
@@ -14,13 +14,10 @@
#ifndef LLVM_CLANG_BASIC_VERSIONTUPLE_H
#define LLVM_CLANG_BASIC_VERSIONTUPLE_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/Optional.h"
#include <string>
-namespace llvm {
- class raw_ostream;
-}
-
namespace clang {
/// \brief Represents a version number in the form major[.minor[.subminor]].
@@ -120,7 +117,7 @@ public:
};
/// \brief Print a version number.
-llvm::raw_ostream& operator<<(llvm::raw_ostream &Out, const VersionTuple &V);
+raw_ostream& operator<<(raw_ostream &Out, const VersionTuple &V);
} // end namespace clang
#endif // LLVM_CLANG_BASIC_VERSIONTUPLE_H
diff --git a/include/clang/CMakeLists.txt b/include/clang/CMakeLists.txt
index 375ae5bdabc8..fb4e04d55b15 100644
--- a/include/clang/CMakeLists.txt
+++ b/include/clang/CMakeLists.txt
@@ -2,4 +2,5 @@ add_subdirectory(AST)
add_subdirectory(Basic)
add_subdirectory(Driver)
add_subdirectory(Lex)
+add_subdirectory(Parse)
add_subdirectory(Serialization)
diff --git a/include/clang/CodeGen/BackendUtil.h b/include/clang/CodeGen/BackendUtil.h
index 9636d6e527c2..135b6a927f9a 100644
--- a/include/clang/CodeGen/BackendUtil.h
+++ b/include/clang/CodeGen/BackendUtil.h
@@ -10,13 +10,14 @@
#ifndef LLVM_CLANG_CODEGEN_BACKEND_UTIL_H
#define LLVM_CLANG_CODEGEN_BACKEND_UTIL_H
+#include "clang/Basic/LLVM.h"
+
namespace llvm {
class Module;
- class raw_ostream;
}
namespace clang {
- class Diagnostic;
+ class DiagnosticsEngine;
class CodeGenOptions;
class TargetOptions;
class LangOptions;
@@ -30,10 +31,10 @@ namespace clang {
Backend_EmitObj ///< Emit native object files
};
- void EmitBackendOutput(Diagnostic &Diags, const CodeGenOptions &CGOpts,
+ void EmitBackendOutput(DiagnosticsEngine &Diags, const CodeGenOptions &CGOpts,
const TargetOptions &TOpts, const LangOptions &LOpts,
llvm::Module *M,
- BackendAction Action, llvm::raw_ostream *OS);
+ BackendAction Action, raw_ostream *OS);
}
#endif
diff --git a/include/clang/CodeGen/CodeGenAction.h b/include/clang/CodeGen/CodeGenAction.h
index 052c6603f5a7..f1a2f6eb455d 100644
--- a/include/clang/CodeGen/CodeGenAction.h
+++ b/include/clang/CodeGen/CodeGenAction.h
@@ -37,7 +37,7 @@ protected:
virtual bool hasIRSupport() const;
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile);
+ StringRef InFile);
virtual void ExecuteAction();
diff --git a/include/clang/CodeGen/ModuleBuilder.h b/include/clang/CodeGen/ModuleBuilder.h
index c45ad08716c6..38aba8900243 100644
--- a/include/clang/CodeGen/ModuleBuilder.h
+++ b/include/clang/CodeGen/ModuleBuilder.h
@@ -23,7 +23,7 @@ namespace llvm {
}
namespace clang {
- class Diagnostic;
+ class DiagnosticsEngine;
class LangOptions;
class CodeGenOptions;
@@ -36,7 +36,7 @@ namespace clang {
/// CreateLLVMCodeGen - Create a CodeGenerator instance.
/// It is the responsibility of the caller to call delete on
/// the allocated CodeGenerator instance.
- CodeGenerator *CreateLLVMCodeGen(Diagnostic &Diags,
+ CodeGenerator *CreateLLVMCodeGen(DiagnosticsEngine &Diags,
const std::string &ModuleName,
const CodeGenOptions &CGO,
llvm::LLVMContext& C);
diff --git a/include/clang/Config/config.h.cmake b/include/clang/Config/config.h.cmake
index 5f13d2faa311..c39932c94613 100644
--- a/include/clang/Config/config.h.cmake
+++ b/include/clang/Config/config.h.cmake
@@ -1,3 +1,6 @@
+/* Bug report URL. */
+#define BUG_REPORT_URL "${BUG_REPORT_URL}"
+
/* Relative directory for resource files */
#define CLANG_RESOURCE_DIR "${CLANG_RESOURCE_DIR}"
diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h
index 4b45c98313c4..a33c33bf734c 100644
--- a/include/clang/Driver/Action.h
+++ b/include/clang/Driver/Action.h
@@ -10,17 +10,9 @@
#ifndef CLANG_DRIVER_ACTION_H_
#define CLANG_DRIVER_ACTION_H_
-#include "llvm/ADT/SmallVector.h"
-
#include "clang/Driver/Types.h"
#include "clang/Driver/Util.h"
-
-#include "llvm/Support/Casting.h"
-using llvm::isa;
-using llvm::cast;
-using llvm::cast_or_null;
-using llvm::dyn_cast;
-using llvm::dyn_cast_or_null;
+#include "llvm/ADT/SmallVector.h"
namespace clang {
namespace driver {
@@ -52,9 +44,10 @@ public:
LinkJobClass,
LipoJobClass,
DsymutilJobClass,
+ VerifyJobClass,
JobClassFirst=PreprocessJobClass,
- JobClassLast=DsymutilJobClass
+ JobClassLast=VerifyJobClass
};
static const char *getClassName(ActionClass AC);
@@ -222,6 +215,15 @@ public:
static bool classof(const DsymutilJobAction *) { return true; }
};
+class VerifyJobAction : public JobAction {
+public:
+ VerifyJobAction(ActionList &Inputs, types::ID Type);
+ static bool classof(const Action *A) {
+ return A->getKind() == VerifyJobClass;
+ }
+ static bool classof(const VerifyJobAction *) { return true; }
+};
+
} // end namespace driver
} // end namespace clang
diff --git a/include/clang/Driver/Arg.h b/include/clang/Driver/Arg.h
index 265d6d871672..e8625bbd5175 100644
--- a/include/clang/Driver/Arg.h
+++ b/include/clang/Driver/Arg.h
@@ -51,7 +51,7 @@ namespace driver {
mutable unsigned OwnsValues : 1;
/// The argument values, as C strings.
- llvm::SmallVector<const char *, 2> Values;
+ SmallVector<const char *, 2> Values;
public:
Arg(const Option *Opt, unsigned Index, const Arg *BaseArg = 0);
@@ -87,11 +87,11 @@ namespace driver {
return Values[N];
}
- llvm::SmallVectorImpl<const char*> &getValues() {
+ SmallVectorImpl<const char*> &getValues() {
return Values;
}
- bool containsValue(llvm::StringRef Value) const {
+ bool containsValue(StringRef Value) const {
for (unsigned i = 0, e = getNumValues(); i != e; ++i)
if (Values[i] == Value)
return true;
diff --git a/include/clang/Driver/ArgList.h b/include/clang/Driver/ArgList.h
index 0fcf821c752c..04faf64dc5ec 100644
--- a/include/clang/Driver/ArgList.h
+++ b/include/clang/Driver/ArgList.h
@@ -10,6 +10,7 @@
#ifndef CLANG_DRIVER_ARGLIST_H_
#define CLANG_DRIVER_ARGLIST_H_
+#include "clang/Basic/LLVM.h"
#include "clang/Driver/OptSpecifier.h"
#include "clang/Driver/Util.h"
#include "llvm/ADT/SmallVector.h"
@@ -19,12 +20,8 @@
#include <string>
#include <vector>
-namespace llvm {
- class Twine;
-}
-
namespace clang {
- class Diagnostic;
+ class DiagnosticsEngine;
namespace driver {
class Arg;
@@ -34,7 +31,7 @@ namespace driver {
/// arg_iterator - Iterates through arguments stored inside an ArgList.
class arg_iterator {
/// The current argument.
- llvm::SmallVectorImpl<Arg*>::const_iterator Current;
+ SmallVectorImpl<Arg*>::const_iterator Current;
/// The argument list we are iterating over.
const ArgList &Args;
@@ -58,7 +55,7 @@ namespace driver {
typedef std::forward_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
- arg_iterator(llvm::SmallVectorImpl<Arg*>::const_iterator it,
+ arg_iterator(SmallVectorImpl<Arg*>::const_iterator it,
const ArgList &_Args, OptSpecifier _Id0 = 0U,
OptSpecifier _Id1 = 0U, OptSpecifier _Id2 = 0U)
: Current(it), Args(_Args), Id0(_Id0), Id1(_Id1), Id2(_Id2) {
@@ -101,7 +98,7 @@ namespace driver {
void operator=(const ArgList &); // DO NOT IMPLEMENT
public:
- typedef llvm::SmallVector<Arg*, 16> arglist_type;
+ typedef SmallVector<Arg*, 16> arglist_type;
typedef arglist_type::iterator iterator;
typedef arglist_type::const_iterator const_iterator;
typedef arglist_type::reverse_iterator reverse_iterator;
@@ -153,6 +150,13 @@ namespace driver {
}
/// @}
+ /// @name Arg Removal
+ /// @{
+
+ /// eraseArg - Remove any option matching \arg Id.
+ void eraseArg(OptSpecifier Id);
+
+ /// @}
/// @name Arg Access
/// @{
@@ -195,13 +199,13 @@ namespace driver {
/// @{
/// getLastArgValue - Return the value of the last argument, or a default.
- llvm::StringRef getLastArgValue(OptSpecifier Id,
- llvm::StringRef Default = "") const;
+ StringRef getLastArgValue(OptSpecifier Id,
+ StringRef Default = "") const;
/// getLastArgValue - Return the value of the last argument as an integer,
/// or a default. Emits an error if the argument is given, but non-integral.
int getLastArgIntValue(OptSpecifier Id, int Default,
- Diagnostic &Diags) const;
+ DiagnosticsEngine &Diags) const;
/// getAllArgValues - Get the values of all instances of the given argument
/// as strings.
@@ -245,25 +249,29 @@ namespace driver {
/// option id.
void ClaimAllArgs(OptSpecifier Id0) const;
+ /// ClaimAllArgs - Claim all arguments.
+ ///
+ void ClaimAllArgs() const;
+
/// @}
/// @name Arg Synthesis
/// @{
/// MakeArgString - Construct a constant string pointer whose
/// lifetime will match that of the ArgList.
- virtual const char *MakeArgString(llvm::StringRef Str) const = 0;
+ virtual const char *MakeArgString(StringRef Str) const = 0;
const char *MakeArgString(const char *Str) const {
- return MakeArgString(llvm::StringRef(Str));
+ return MakeArgString(StringRef(Str));
}
const char *MakeArgString(std::string Str) const {
- return MakeArgString(llvm::StringRef(Str));
+ return MakeArgString(StringRef(Str));
}
- const char *MakeArgString(const llvm::Twine &Str) const;
+ const char *MakeArgString(const Twine &Str) const;
/// \brief Create an arg string for (\arg LHS + \arg RHS), reusing the
/// string at \arg Index if possible.
- const char *GetOrMakeJoinedArgString(unsigned Index, llvm::StringRef LHS,
- llvm::StringRef RHS) const;
+ const char *GetOrMakeJoinedArgString(unsigned Index, StringRef LHS,
+ StringRef RHS) const;
/// @}
};
@@ -304,10 +312,10 @@ namespace driver {
public:
/// MakeIndex - Get an index for the given string(s).
- unsigned MakeIndex(llvm::StringRef String0) const;
- unsigned MakeIndex(llvm::StringRef String0, llvm::StringRef String1) const;
+ unsigned MakeIndex(StringRef String0) const;
+ unsigned MakeIndex(StringRef String0, StringRef String1) const;
- virtual const char *MakeArgString(llvm::StringRef Str) const;
+ virtual const char *MakeArgString(StringRef Str) const;
/// @}
};
@@ -346,7 +354,7 @@ namespace driver {
SynthesizedArgs.push_back(A);
}
- virtual const char *MakeArgString(llvm::StringRef Str) const;
+ virtual const char *MakeArgString(StringRef Str) const;
/// AddFlagArg - Construct a new FlagArg for the given option \arg Id and
/// append it to the argument list.
@@ -358,7 +366,7 @@ namespace driver {
/// \arg Id, with the provided \arg Value and append it to the argument
/// list.
void AddPositionalArg(const Arg *BaseArg, const Option *Opt,
- llvm::StringRef Value) {
+ StringRef Value) {
append(MakePositionalArg(BaseArg, Opt, Value));
}
@@ -367,7 +375,7 @@ namespace driver {
/// \arg Id, with the provided \arg Value and append it to the argument
/// list.
void AddSeparateArg(const Arg *BaseArg, const Option *Opt,
- llvm::StringRef Value) {
+ StringRef Value) {
append(MakeSeparateArg(BaseArg, Opt, Value));
}
@@ -375,7 +383,7 @@ namespace driver {
/// AddJoinedArg - Construct a new Positional arg for the given option \arg
/// Id, with the provided \arg Value and append it to the argument list.
void AddJoinedArg(const Arg *BaseArg, const Option *Opt,
- llvm::StringRef Value) {
+ StringRef Value) {
append(MakeJoinedArg(BaseArg, Opt, Value));
}
@@ -387,17 +395,17 @@ namespace driver {
/// MakePositionalArg - Construct a new Positional arg for the
/// given option \arg Id, with the provided \arg Value.
Arg *MakePositionalArg(const Arg *BaseArg, const Option *Opt,
- llvm::StringRef Value) const;
+ StringRef Value) const;
/// MakeSeparateArg - Construct a new Positional arg for the
/// given option \arg Id, with the provided \arg Value.
Arg *MakeSeparateArg(const Arg *BaseArg, const Option *Opt,
- llvm::StringRef Value) const;
+ StringRef Value) const;
/// MakeJoinedArg - Construct a new Positional arg for the
/// given option \arg Id, with the provided \arg Value.
Arg *MakeJoinedArg(const Arg *BaseArg, const Option *Opt,
- llvm::StringRef Value) const;
+ StringRef Value) const;
/// @}
};
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index d8e9e3d3e88b..4473d46e2b32 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -57,6 +57,10 @@ def analyzer_output : Separate<"-analyzer-output">,
def analyzer_output_EQ : Joined<"-analyzer-output=">,
Alias<analyzer_output>;
+def analyzer_purge : Separate<"-analyzer-purge">,
+ HelpText<"Source Code Analysis - Dead Symbol Removal Frequency">;
+def analyzer_purge_EQ : Joined<"-analyzer-purge=">, Alias<analyzer_purge>;
+
def analyzer_opt_analyze_headers : Flag<"-analyzer-opt-analyze-headers">,
HelpText<"Force the static analyzer to analyze functions defined in header files">;
def analyzer_opt_analyze_nested_blocks : Flag<"-analyzer-opt-analyze-nested-blocks">,
@@ -68,8 +72,6 @@ def analyze_function : Separate<"-analyze-function">,
def analyze_function_EQ : Joined<"-analyze-function=">, Alias<analyze_function>;
def analyzer_eagerly_assume : Flag<"-analyzer-eagerly-assume">,
HelpText<"Eagerly assume the truth/falseness of some symbolic constraints">;
-def analyzer_no_purge_dead : Flag<"-analyzer-no-purge-dead">,
- HelpText<"Don't remove dead symbols, bindings, and constraints before processing a statement">;
def analyzer_no_eagerly_trim_egraph : Flag<"-analyzer-no-eagerly-trim-egraph">,
HelpText<"Don't eagerly remove uninteresting ExplodedNodes from the ExplodedGraph">;
def trim_egraph : Flag<"-trim-egraph">,
@@ -113,9 +115,10 @@ def dwarf_debug_flags : Separate<"-dwarf-debug-flags">,
def fforbid_guard_variables : Flag<"-fforbid-guard-variables">,
HelpText<"Emit an error if a C++ static local initializer would need a guard variable">;
def g : Flag<"-g">, HelpText<"Generate source level debug information">;
-def fno_dwarf2_cfi_asm : Flag<"-fno-dwarf2-cfi-asm">, HelpText<"Don't use the cfi directives">;
+def fno_dwarf2_cfi_asm : Flag<"-fno-dwarf2-cfi-asm">,
+ HelpText<"Don't use the cfi directives">;
def fcatch_undefined_behavior : Flag<"-fcatch-undefined-behavior">,
- HelpText<"Generate runtime checks for undefined behavior.">;
+ HelpText<"Generate runtime checks for undefined behavior.">;
def flimit_debug_info : Flag<"-flimit-debug-info">,
HelpText<"Limit debug information produced to reduce size of debug binary">;
def fno_common : Flag<"-fno-common">,
@@ -157,6 +160,8 @@ def mdisable_fp_elim : Flag<"-mdisable-fp-elim">,
HelpText<"Disable frame pointer elimination optimization">;
def mfloat_abi : Separate<"-mfloat-abi">,
HelpText<"The float ABI to use">;
+def mno_global_merge : Flag<"-mno-global-merge">,
+ HelpText<"Disable merging of globals">;
def mlimit_float_precision : Separate<"-mlimit-float-precision">,
HelpText<"Limit float precision to the given value">;
def mno_exec_stack : Flag<"-mnoexecstack">,
@@ -359,6 +364,8 @@ def ast_view : Flag<"-ast-view">,
HelpText<"Build ASTs and view them with GraphViz">;
def print_decl_contexts : Flag<"-print-decl-contexts">,
HelpText<"Print DeclContexts and their Decls">;
+def emit_module : Flag<"-emit-module">,
+ HelpText<"Generate pre-compiled module file">;
def emit_pth : Flag<"-emit-pth">,
HelpText<"Generate pre-tokenized header file">;
def emit_pch : Flag<"-emit-pch">,
@@ -381,9 +388,6 @@ def rewrite_objc : Flag<"-rewrite-objc">,
HelpText<"Rewrite ObjC into C (code rewriter example)">;
def rewrite_macros : Flag<"-rewrite-macros">,
HelpText<"Expand macros without full preprocessing">;
-
-def create_module : Flag<"-create-module">,
- HelpText<"Create a module definition file">;
}
def arcmt_check : Flag<"-arcmt-check">,
@@ -394,9 +398,10 @@ def arcmt_migrate : Flag<"-arcmt-migrate">,
HelpText<"Apply modifications and produces temporary files that conform to ARC">;
def arcmt_migrate_directory : Separate<"-arcmt-migrate-directory">,
HelpText<"Directory for temporary files produced during ARC migration">;
-
-def import_module : Separate<"-import-module">,
- HelpText<"Import a module definition file">;
+def arcmt_migrate_report_output : Separate<"-arcmt-migrate-report-output">,
+ HelpText<"Output path for the plist report">;
+def arcmt_migrate_emit_arc_errors : Flag<"-arcmt-migrate-emit-errors">,
+ HelpText<"Emit ARC errors even if the migrator can fix them">;
def working_directory : JoinedOrSeparate<"-working-directory">,
HelpText<"Resolve file paths relative to the specified directory">;
@@ -405,8 +410,6 @@ def working_directory_EQ : Joined<"-working-directory=">,
def relocatable_pch : Flag<"-relocatable-pch">,
HelpText<"Whether to build a relocatable precompiled header">;
-def chained_pch : Flag<"-chained-pch">,
- HelpText<"Whether to chain the new precompiled header to the old one.">;
def print_stats : Flag<"-print-stats">,
HelpText<"Print performance metrics and statistics">;
def ftime_report : Flag<"-ftime-report">,
@@ -446,7 +449,9 @@ def fno_dollars_in_identifiers : Flag<"-fno-dollars-in-identifiers">,
def femit_all_decls : Flag<"-femit-all-decls">,
HelpText<"Emit all declarations, even if unused">;
def fblocks : Flag<"-fblocks">,
- HelpText<"enable the 'blocks' language feature">;
+ HelpText<"Enable the 'blocks' language feature">;
+def fblocks_runtime_optional : Flag<"-fblocks-runtime-optional">,
+ HelpText<"Weakly link in the blocks runtime">;
def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">;
def fexceptions : Flag<"-fexceptions">,
HelpText<"Enable support for exception handling">;
@@ -469,7 +474,9 @@ def stdlib_EQ : Joined<"-stdlib=">,
def fmath_errno : Flag<"-fmath-errno">,
HelpText<"Require math functions to indicate errors by setting errno">;
def fms_extensions : Flag<"-fms-extensions">,
- HelpText<"Accept some non-standard constructs used in Microsoft header files ">;
+ HelpText<"Accept some non-standard constructs supported by the Microsoft compiler">;
+def fms_compatibility : Flag<"-fms-compatibility">,
+ HelpText<"Enable Microsoft compatibility mode">;
def fmsc_version : Joined<"-fmsc-version=">,
HelpText<"Version of the Microsoft C/C++ compiler to report in _MSC_VER (0 = don't define it (default))">;
def fborland_extensions : Flag<"-fborland-extensions">,
@@ -517,8 +524,8 @@ def fobjc_default_synthesize_properties : Flag<"-fobjc-default-synthesize-proper
HelpText<"enable the default synthesis of Objective-C properties">;
def print_ivar_layout : Flag<"-print-ivar-layout">,
HelpText<"Enable Objective-C Ivar layout bitmap print trace">;
-def fobjc_nonfragile_abi : Flag<"-fobjc-nonfragile-abi">,
- HelpText<"enable objective-c's nonfragile abi">;
+def fobjc_fragile_abi : Flag<"-fobjc-fragile-abi">,
+ HelpText<"Use Objective-C's fragile ABI">;
def fno_objc_infer_related_result_type : Flag<
"-fno-objc-infer-related-result-type">,
HelpText<
@@ -534,6 +541,8 @@ def pic_level : Separate<"-pic-level">,
HelpText<"Value for __PIC__">;
def pthread : Flag<"-pthread">,
HelpText<"Support POSIX threads in generated code">;
+def fpack_struct : Separate<"-fpack-struct">,
+ HelpText<"Specify the default maximum struct packing alignment">;
def fpascal_strings : Flag<"-fpascal-strings">,
HelpText<"Recognize and construct Pascal-style string literals">;
def fno_rtti : Flag<"-fno-rtti">,
@@ -593,22 +602,41 @@ def fno_deprecated_macro : Flag<"-fno-deprecated-macro">,
// Header Search Options
//===----------------------------------------------------------------------===//
-def nostdinc : Flag<"-nostdinc">,
- HelpText<"Disable standard #include directories">;
+def nostdsysteminc : Flag<"-nostdsysteminc">,
+ HelpText<"Disable standard system #include directories">;
def nostdincxx : Flag<"-nostdinc++">,
HelpText<"Disable standard #include directories for the C++ standard library">;
def nobuiltininc : Flag<"-nobuiltininc">,
HelpText<"Disable builtin #include directories">;
+def fmodule_cache_path : Separate<"-fmodule-cache-path">,
+ MetaVarName<"<directory>">,
+ HelpText<"Specify the module cache path">;
+def fdisable_module_hash : Flag<"-fdisable-module-hash">,
+ HelpText<"Disable the module hash">;
+def fauto_module_import : Flag<"-fauto-module-import">,
+ HelpText<"Automatically translate #include/#import into module imports "
+ "when possible">;
+
def F : JoinedOrSeparate<"-F">, MetaVarName<"<directory>">,
HelpText<"Add directory to framework include search path">;
def I : JoinedOrSeparate<"-I">, MetaVarName<"<directory>">,
HelpText<"Add directory to include search path">;
def idirafter : JoinedOrSeparate<"-idirafter">, MetaVarName<"<directory>">,
HelpText<"Add directory to AFTER include search path">;
+def index_header_map : Flag<"-index-header-map">,
+ HelpText<"Make the next included directory (-I or -F) an indexer header map">;
def iquote : JoinedOrSeparate<"-iquote">, MetaVarName<"<directory>">,
HelpText<"Add directory to QUOTE include search path">;
+def c_isystem : JoinedOrSeparate<"-c-isystem">, MetaVarName<"<directory>">,
+ HelpText<"Add directory to the C SYSTEM include search path">;
def cxx_isystem : JoinedOrSeparate<"-cxx-isystem">, MetaVarName<"<directory>">,
HelpText<"Add directory to the C++ SYSTEM include search path">;
+def objc_isystem : JoinedOrSeparate<"-objc-isystem">,
+ MetaVarName<"<directory>">,
+ HelpText<"Add directory to the ObjC SYSTEM include search path">;
+def objcxx_isystem : JoinedOrSeparate<"-objcxx-isystem">,
+ MetaVarName<"<directory>">,
+ HelpText<"Add directory to the ObjC++ SYSTEM include search path">;
def isystem : JoinedOrSeparate<"-isystem">, MetaVarName<"<directory>">,
HelpText<"Add directory to SYSTEM include search path">;
def iwithsysroot : JoinedOrSeparate<"-iwithsysroot">,MetaVarName<"<directory>">,
@@ -686,3 +714,10 @@ def cl_mad_enable : Flag<"-cl-mad-enable">,
HelpText<"OpenCL only. Enable less precise MAD instructions to be generated.">;
def cl_std_EQ : Joined<"-cl-std=">,
HelpText<"OpenCL language standard to compile for">;
+
+//===----------------------------------------------------------------------===//
+// CUDA Options
+//===----------------------------------------------------------------------===//
+
+def fcuda_is_device : Flag<"-fcuda-is-device">,
+ HelpText<"Generate code for CUDA device">;
diff --git a/include/clang/Driver/Compilation.h b/include/clang/Driver/Compilation.h
index 2db712d9321f..8c9990909ebb 100644
--- a/include/clang/Driver/Compilation.h
+++ b/include/clang/Driver/Compilation.h
@@ -12,12 +12,8 @@
#include "clang/Driver/Job.h"
#include "clang/Driver/Util.h"
-
#include "llvm/ADT/DenseMap.h"
-
-namespace llvm {
- class raw_ostream;
-}
+#include "llvm/Support/Path.h"
namespace clang {
namespace driver {
@@ -60,6 +56,9 @@ class Compilation {
/// Result files which should be removed on failure.
ArgStringList ResultFiles;
+ /// Redirection for stdout, stderr, etc.
+ const llvm::sys::Path **Redirects;
+
public:
Compilation(const Driver &D, const ToolChain &DefaultToolChain,
InputArgList *Args, DerivedArgList *TranslatedArgs);
@@ -120,7 +119,7 @@ public:
/// \param J - The job to print.
/// \param Terminator - A string to print at the end of the line.
/// \param Quote - Should separate arguments be quoted.
- void PrintJob(llvm::raw_ostream &OS, const Job &J,
+ void PrintJob(raw_ostream &OS, const Job &J,
const char *Terminator, bool Quote) const;
/// ExecuteCommand - Execute an actual command.
@@ -136,6 +135,11 @@ public:
/// Command which failed.
/// \return The accumulated result code of the job.
int ExecuteJob(const Job &J, const Command *&FailingCommand) const;
+
+ /// initCompilationForDiagnostics - Remove stale state and suppress output
+ /// so compilation can be reexecuted to generate additional diagnostic
+ /// information (e.g., preprocessed source(s)).
+ void initCompilationForDiagnostics();
};
} // end namespace driver
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index b6951663148b..6fdf6fcfad64 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -13,6 +13,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Driver/Phases.h"
+#include "clang/Driver/Types.h"
#include "clang/Driver/Util.h"
#include "llvm/ADT/StringRef.h"
@@ -24,13 +25,14 @@
#include <string>
namespace llvm {
- class raw_ostream;
template<typename T> class ArrayRef;
}
namespace clang {
namespace driver {
class Action;
+ class Arg;
class ArgList;
+ class Command;
class Compilation;
class DerivedArgList;
class HostInfo;
@@ -45,7 +47,7 @@ namespace driver {
class Driver {
OptTable *Opts;
- Diagnostic &Diags;
+ DiagnosticsEngine &Diags;
public:
// Diag - Forwarding function for diagnostics.
@@ -75,7 +77,7 @@ public:
/// functionality.
/// FIXME: This type of customization should be removed in favor of the
/// universal driver when it is ready.
- typedef llvm::SmallVector<std::string, 4> prefix_list;
+ typedef SmallVector<std::string, 4> prefix_list;
prefix_list PrefixDirs;
/// sysroot, if present
@@ -109,6 +111,9 @@ public:
/// The file to log CC_LOG_DIAGNOSTICS output to, if enabled.
const char *CCLogDiagnosticsFilename;
+ /// A list of inputs and their types for the given arguments.
+ typedef SmallVector<std::pair<types::ID, const Arg*>, 16> InputList;
+
/// Whether the driver should follow g++ like behavior.
unsigned CCCIsCXX : 1;
@@ -134,6 +139,9 @@ public:
/// format.
unsigned CCLogDiagnostics : 1;
+ /// Whether the driver is generating diagnostics for debugging purposes.
+ unsigned CCGenDiagnostics : 1;
+
private:
/// Name to use when invoking gcc/g++.
std::string CCCGenericGCCName;
@@ -172,12 +180,17 @@ private:
/// arguments, after applying the standard argument translations.
DerivedArgList *TranslateInputArgs(const InputArgList &Args) const;
+ // getFinalPhase - Determine which compilation mode we are in and record
+ // which option we used to determine the final phase.
+ phases::ID getFinalPhase(const DerivedArgList &DAL, Arg **FinalPhaseArg = 0)
+ const;
+
public:
- Driver(llvm::StringRef _ClangExecutable,
- llvm::StringRef _DefaultHostTriple,
- llvm::StringRef _DefaultImageName,
- bool IsProduction, bool CXXIsProduction,
- Diagnostic &_Diags);
+ Driver(StringRef _ClangExecutable,
+ StringRef _DefaultHostTriple,
+ StringRef _DefaultImageName,
+ bool IsProduction,
+ DiagnosticsEngine &_Diags);
~Driver();
/// @name Accessors
@@ -189,7 +202,7 @@ public:
const OptTable &getOpts() const { return *Opts; }
- const Diagnostic &getDiags() const { return Diags; }
+ const DiagnosticsEngine &getDiags() const { return Diags; }
bool getCheckInputsExist() const { return CheckInputsExist; }
@@ -209,7 +222,7 @@ public:
return InstalledDir.c_str();
return Dir.c_str();
}
- void setInstalledDir(llvm::StringRef Value) {
+ void setInstalledDir(StringRef Value) {
InstalledDir = Value;
}
@@ -224,14 +237,24 @@ public:
/// argument vector. A null return value does not necessarily
/// indicate an error condition, the diagnostics should be queried
/// to determine if an error occurred.
- Compilation *BuildCompilation(llvm::ArrayRef<const char *> Args);
+ Compilation *BuildCompilation(ArrayRef<const char *> Args);
/// @name Driver Steps
/// @{
/// ParseArgStrings - Parse the given list of strings into an
/// ArgList.
- InputArgList *ParseArgStrings(llvm::ArrayRef<const char *> Args);
+ InputArgList *ParseArgStrings(ArrayRef<const char *> Args);
+
+ /// BuildInputs - Construct the list of inputs and their types from
+ /// the given arguments.
+ ///
+ /// \param TC - The default host tool chain.
+ /// \param Args - The input arguments.
+ /// \param Inputs - The list to store the resulting compilation
+ /// inputs onto.
+ void BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
+ InputList &Inputs) const;
/// BuildActions - Construct the list of actions to perform for the
/// given arguments, which are only done for a single architecture.
@@ -240,7 +263,7 @@ public:
/// \param Args - The input arguments.
/// \param Actions - The list to store the resulting actions onto.
void BuildActions(const ToolChain &TC, const DerivedArgList &Args,
- ActionList &Actions) const;
+ const InputList &Inputs, ActionList &Actions) const;
/// BuildUniversalActions - Construct the list of actions to perform
/// for the given arguments, which may require a universal build.
@@ -249,6 +272,7 @@ public:
/// \param Args - The input arguments.
/// \param Actions - The list to store the resulting actions onto.
void BuildUniversalActions(const ToolChain &TC, const DerivedArgList &Args,
+ const InputList &BAInputs,
ActionList &Actions) const;
/// BuildJobs - Bind actions to concrete tools and translate
@@ -263,7 +287,14 @@ public:
/// This routine handles additional processing that must be done in addition
/// to just running the subprocesses, for example reporting errors, removing
/// temporary files, etc.
- int ExecuteCompilation(const Compilation &C) const;
+ int ExecuteCompilation(const Compilation &C,
+ const Command *&FailingCommand) const;
+
+ /// generateCompilationDiagnostics - Generate diagnostics information
+ /// including preprocessed source file(s).
+ ///
+ void generateCompilationDiagnostics(Compilation &C,
+ const Command *FailingCommand);
/// @}
/// @name Helper Methods
@@ -281,7 +312,7 @@ public:
void PrintOptions(const ArgList &Args) const;
/// PrintVersion - Print the driver version.
- void PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const;
+ void PrintVersion(const Compilation &C, raw_ostream &OS) const;
/// GetFilePath - Lookup \arg Name in the list of file search paths.
///
@@ -342,11 +373,11 @@ public:
const char *BaseInput,
bool AtTopLevel) const;
- /// GetTemporaryPath - Return the pathname of a temporary file to
- /// use as part of compilation; the file will have the given suffix.
+ /// GetTemporaryPath - Return the pathname of a temporary file to use
+ /// as part of compilation; the file will have the given prefix and suffix.
///
/// GCC goes to extra lengths here to be a bit more robust.
- std::string GetTemporaryPath(const char *Suffix) const;
+ std::string GetTemporaryPath(StringRef Prefix, const char *Suffix) const;
/// GetHostInfo - Construct a new host info object for the given
/// host triple.
diff --git a/include/clang/Driver/DriverDiagnostic.h b/include/clang/Driver/DriverDiagnostic.h
index 0f9376b8dea1..844f918c1b2e 100644
--- a/include/clang/Driver/DriverDiagnostic.h
+++ b/include/clang/Driver/DriverDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM,
+ SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM,
#define DRIVERSTART
#include "clang/Basic/DiagnosticDriverKinds.inc"
#undef DIAG
diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h
index d2767d1b877b..367955f59f04 100644
--- a/include/clang/Driver/Job.h
+++ b/include/clang/Driver/Job.h
@@ -12,13 +12,7 @@
#include "clang/Driver/Util.h"
#include "llvm/ADT/SmallVector.h"
-
-#include "llvm/Support/Casting.h"
-using llvm::isa;
-using llvm::cast;
-using llvm::cast_or_null;
-using llvm::dyn_cast;
-using llvm::dyn_cast_or_null;
+#include "clang/Basic/LLVM.h"
namespace clang {
namespace driver {
@@ -88,7 +82,7 @@ public:
/// JobList - A sequence of jobs to perform.
class JobList : public Job {
public:
- typedef llvm::SmallVector<Job*, 4> list_type;
+ typedef SmallVector<Job*, 4> list_type;
typedef list_type::size_type size_type;
typedef list_type::iterator iterator;
typedef list_type::const_iterator const_iterator;
@@ -103,6 +97,9 @@ public:
/// Add a job to the list (taking ownership).
void addJob(Job *J) { Jobs.push_back(J); }
+ /// Clear the job list.
+ void clear();
+
const list_type &getJobs() const { return Jobs; }
size_type size() const { return Jobs.size(); }
diff --git a/include/clang/Driver/Makefile b/include/clang/Driver/Makefile
index d8291662a563..45bc40f3b715 100644
--- a/include/clang/Driver/Makefile
+++ b/include/clang/Driver/Makefile
@@ -5,14 +5,14 @@ TABLEGEN_INC_FILES_COMMON = 1
include $(CLANG_LEVEL)/Makefile
-$(ObjDir)/Options.inc.tmp : Options.td OptParser.td $(TBLGEN) $(ObjDir)/.dir
+$(ObjDir)/Options.inc.tmp : Options.td OptParser.td $(CLANG_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang Driver Option tables with tblgen"
- $(Verb) $(TableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
+ $(Verb) $(ClangTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
-$(ObjDir)/CC1Options.inc.tmp : CC1Options.td OptParser.td $(TBLGEN) $(ObjDir)/.dir
+$(ObjDir)/CC1Options.inc.tmp : CC1Options.td OptParser.td $(CLANG_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang CC1 Option tables with tblgen"
- $(Verb) $(TableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
+ $(Verb) $(ClangTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
-$(ObjDir)/CC1AsOptions.inc.tmp : CC1AsOptions.td OptParser.td $(TBLGEN) $(ObjDir)/.dir
+$(ObjDir)/CC1AsOptions.inc.tmp : CC1AsOptions.td OptParser.td $(CLANG_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang CC1 Assembler Option tables with tblgen"
- $(Verb) $(TableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
+ $(Verb) $(ClangTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
diff --git a/include/clang/Driver/OptTable.h b/include/clang/Driver/OptTable.h
index 3befe1defba9..abd224db449d 100644
--- a/include/clang/Driver/OptTable.h
+++ b/include/clang/Driver/OptTable.h
@@ -10,12 +10,8 @@
#ifndef CLANG_DRIVER_OPTTABLE_H
#define CLANG_DRIVER_OPTTABLE_H
+#include "clang/Basic/LLVM.h"
#include "clang/Driver/OptSpecifier.h"
-#include <cassert>
-
-namespace llvm {
- class raw_ostream;
-}
namespace clang {
namespace driver {
@@ -181,7 +177,7 @@ namespace options {
/// \param Name - The name to use in the usage line.
/// \param Title - The title to use in the usage line.
/// \param ShowHidden - Whether help-hidden arguments should be shown.
- void PrintHelp(llvm::raw_ostream &OS, const char *Name,
+ void PrintHelp(raw_ostream &OS, const char *Name,
const char *Title, bool ShowHidden = false) const;
};
}
diff --git a/include/clang/Driver/Option.h b/include/clang/Driver/Option.h
index 9dfa4614009f..8243f6d69314 100644
--- a/include/clang/Driver/Option.h
+++ b/include/clang/Driver/Option.h
@@ -12,12 +12,7 @@
#include "clang/Driver/OptSpecifier.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Casting.h"
-using llvm::isa;
-using llvm::cast;
-using llvm::cast_or_null;
-using llvm::dyn_cast;
-using llvm::dyn_cast_or_null;
+#include "clang/Basic/LLVM.h"
namespace clang {
namespace driver {
@@ -65,7 +60,7 @@ namespace driver {
OptSpecifier ID;
/// The option name.
- llvm::StringRef Name;
+ StringRef Name;
/// Group this option is a member of, if any.
const OptionGroup *Group;
@@ -104,7 +99,7 @@ namespace driver {
unsigned getID() const { return ID.getID(); }
OptionClass getKind() const { return Kind; }
- llvm::StringRef getName() const { return Name; }
+ StringRef getName() const { return Name; }
const OptionGroup *getGroup() const { return Group; }
const Option *getAlias() const { return Alias; }
@@ -144,7 +139,7 @@ namespace driver {
/// getRenderName - Return the name to use when rendering this
/// option.
- llvm::StringRef getRenderName() const {
+ StringRef getRenderName() const {
return getUnaliasedOption()->getName();
}
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index d5482765e756..ae8c7945cb93 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -122,6 +122,10 @@ def ccc_arcmt_migrate : Separate<"-ccc-arcmt-migrate">, CCCDriverOpt,
HelpText<"Apply modifications and produces temporary files that conform to ARC">;
def ccc_arcmt_migrate_EQ : Joined<"-ccc-arcmt-migrate=">, CCCDriverOpt,
Alias<ccc_arcmt_migrate>;
+def arcmt_migrate_report_output : Separate<"-arcmt-migrate-report-output">,
+ HelpText<"Output path for the plist report">;
+def arcmt_migrate_emit_arc_errors : Flag<"-arcmt-migrate-emit-errors">,
+ HelpText<"Emit ARC errors even if the migrator can fix them">;
// Make sure all other -ccc- options are rejected.
def ccc_ : Joined<"-ccc-">, Group<ccc_Group>, Flags<[Unsupported]>;
@@ -130,6 +134,9 @@ def ccc_ : Joined<"-ccc-">, Group<ccc_Group>, Flags<[Unsupported]>;
def _HASH_HASH_HASH : Flag<"-###">, Flags<[DriverOption]>,
HelpText<"Print the commands to run for this compilation">;
+// The '--' option is here for the sake of compatibility with gcc, but is
+// being ignored by the driver.
+def _DASH_DASH : Flag<"--">, Flags<[DriverOption]>;
def A : JoinedOrSeparate<"-A">;
def B : JoinedOrSeparate<"-B">;
def CC : Flag<"-CC">;
@@ -315,7 +322,7 @@ def fno_gnu89_inline : Flag<"-fno-gnu89-inline">, Group<f_Group>;
def fgnu_runtime : Flag<"-fgnu-runtime">, Group<f_Group>;
def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">;
def filelist : Separate<"-filelist">, Flags<[LinkerInput]>;
-def findirect_virtual_calls : Flag<"-findirect-virtual-calls">, Group<f_Group>;
+def findirect_virtual_calls : Flag<"-findirect-virtual-calls">, Alias<fapple_kext>;
def finline_functions : Flag<"-finline-functions">, Group<clang_ignored_f_Group>;
def finline : Flag<"-finline">, Group<clang_ignored_f_Group>;
def finstrument_functions : Flag<"-finstrument-functions">, Group<f_Group>;
@@ -333,8 +340,14 @@ def fmath_errno : Flag<"-fmath-errno">, Group<f_Group>;
def fmerge_all_constants : Flag<"-fmerge-all-constants">, Group<f_Group>;
def fmessage_length_EQ : Joined<"-fmessage-length=">, Group<f_Group>;
def fms_extensions : Flag<"-fms-extensions">, Group<f_Group>;
+def fms_compatibility : Flag<"-fms-compatibility">, Group<f_Group>;
def fmsc_version : Joined<"-fmsc-version=">, Group<f_Group>;
def fdelayed_template_parsing : Flag<"-fdelayed-template-parsing">, Group<f_Group>;
+def fmodule_cache_path : Separate<"-fmodule-cache-path">, Group<i_Group>,
+ Flags<[NoForward]>;
+def fauto_module_import : Flag <"-fauto-module-import">, Group<f_Group>,
+ Flags<[NoForward]>;
+
def fmudflapth : Flag<"-fmudflapth">, Group<f_Group>;
def fmudflap : Flag<"-fmudflap">, Group<f_Group>;
def fnested_functions : Flag<"-fnested-functions">, Group<f_Group>;
@@ -370,6 +383,7 @@ def fno_lax_vector_conversions : Flag<"-fno-lax-vector-conversions">, Group<f_Gr
def fno_math_errno : Flag<"-fno-math-errno">, Group<f_Group>;
def fno_merge_all_constants : Flag<"-fno-merge-all-constants">, Group<f_Group>;
def fno_ms_extensions : Flag<"-fno-ms-extensions">, Group<f_Group>;
+def fno_ms_compatibility : Flag<"-fno-ms-compatibility">, Group<f_Group>;
def fno_delayed_template_parsing : Flag<"-fno-delayed-template-parsing">, Group<f_Group>;
def fno_objc_default_synthesize_properties
: Flag<"-fno-objc-default-synthesize-properties">, Group<f_Group>;
@@ -426,6 +440,9 @@ def force__cpusubtype__ALL : Flag<"-force_cpusubtype_ALL">;
def force__flat__namespace : Flag<"-force_flat_namespace">;
def force__load : Separate<"-force_load">;
def foutput_class_dir_EQ : Joined<"-foutput-class-dir=">, Group<f_Group>;
+def fpack_struct : Flag<"-fpack-struct">, Group<f_Group>;
+def fno_pack_struct : Flag<"-fno-pack-struct">, Group<f_Group>;
+def fpack_struct_EQ : Joined<"-fpack-struct=">, Group<f_Group>;
def fpascal_strings : Flag<"-fpascal-strings">, Group<f_Group>;
def fpch_preprocess : Flag<"-fpch-preprocess">, Group<f_Group>;
def fpic : Flag<"-fpic">, Group<f_Group>;
@@ -466,7 +483,7 @@ def Wlarger_than_ : Joined<"-Wlarger-than-">, Alias<Wlarger_than>;
def Wframe_larger_than : Separate<"-Wframe-larger-than">, Group<clang_ignored_f_Group>;
def Wframe_larger_than_EQ : Joined<"-Wframe-larger-than=">, Alias<Wframe_larger_than>;
-def fterminated_vtables : Flag<"-fterminated-vtables">, Group<f_Group>;
+def fterminated_vtables : Flag<"-fterminated-vtables">, Alias<fapple_kext>;
def fthreadsafe_statics : Flag<"-fthreadsafe-statics">, Group<f_Group>;
def ftime_report : Flag<"-ftime-report">, Group<f_Group>;
def ftrapv : Flag<"-ftrapv">, Group<f_Group>;
@@ -496,6 +513,7 @@ def gused : Joined<"-gused">, Group<g_Group>;
def g_Flag : Flag<"-g">, Group<g_Group>;
def g_Joined : Joined<"-g">, Group<g_Group>;
def headerpad__max__install__names : Joined<"-headerpad_max_install_names">;
+def index_header_map : Flag<"-index-header-map">;
def idirafter : JoinedOrSeparate<"-idirafter">, Group<clang_i_Group>;
def iframework : JoinedOrSeparate<"-iframework">, Group<clang_i_Group>;
def imacros : JoinedOrSeparate<"-imacros">, Group<clang_i_Group>;
@@ -528,6 +546,7 @@ def mdynamic_no_pic : Joined<"-mdynamic-no-pic">, Group<m_Group>, Flags<[NoArgum
def mfix_and_continue : Flag<"-mfix-and-continue">, Group<clang_ignored_m_Group>;
def mfloat_abi_EQ : Joined<"-mfloat-abi=">, Group<m_Group>;
def mfpu_EQ : Joined<"-mfpu=">, Group<m_Group>;
+def mglobal_merge : Flag<"-mglobal-merge">, Group<m_Group>;
def mhard_float : Flag<"-mhard-float">, Group<m_Group>;
def miphoneos_version_min_EQ : Joined<"-miphoneos-version-min=">, Group<m_Group>;
def mios_version_min_EQ : Joined<"-mios-version-min=">, Alias<miphoneos_version_min_EQ>;
@@ -542,6 +561,7 @@ def mmmx : Flag<"-mmmx">, Group<m_x86_Features_Group>;
def mno_3dnowa : Flag<"-mno-3dnowa">, Group<m_x86_Features_Group>;
def mno_3dnow : Flag<"-mno-3dnow">, Group<m_x86_Features_Group>;
def mno_constant_cfstrings : Flag<"-mno-constant-cfstrings">, Group<m_Group>;
+def mno_global_merge : Flag<"-mno-global-merge">, Group<m_Group>;
def mno_mmx : Flag<"-mno-mmx">, Group<m_x86_Features_Group>;
def mno_pascal_strings : Flag<"-mno-pascal-strings">, Group<m_Group>;
def mno_red_zone : Flag<"-mno-red-zone">, Group<m_Group>;
@@ -604,6 +624,7 @@ def noprebind : Flag<"-noprebind">;
def noseglinkedit : Flag<"-noseglinkedit">;
def nostartfiles : Flag<"-nostartfiles">;
def nostdinc : Flag<"-nostdinc">;
+def nostdlibinc : Flag<"-nostdlibinc">;
def nostdincxx : Flag<"-nostdinc++">;
def nostdlib : Flag<"-nostdlib">;
def object : Flag<"-object">;
@@ -688,6 +709,8 @@ def u : JoinedOrSeparate<"-u">, Group<u_Group>;
def use_gold_plugin : Flag<"-use-gold-plugin">;
def v : Flag<"-v">,
HelpText<"Show commands to run and use verbose output">;
+def verify : Flag<"-verify">, Flags<[DriverOption]>,
+ HelpText<"Verify output using a verifier.">;
def weak_l : Joined<"-weak-l">, Flags<[LinkerInput]>;
def weak__framework : Separate<"-weak_framework">, Flags<[LinkerInput]>;
def weak__library : Separate<"-weak_library">, Flags<[LinkerInput]>;
diff --git a/include/clang/Driver/Tool.h b/include/clang/Driver/Tool.h
index c30fa4c6e731..378b516b39e5 100644
--- a/include/clang/Driver/Tool.h
+++ b/include/clang/Driver/Tool.h
@@ -10,9 +10,7 @@
#ifndef CLANG_DRIVER_TOOL_H_
#define CLANG_DRIVER_TOOL_H_
-namespace llvm {
- template<typename T, unsigned N> class SmallVector;
-}
+#include "clang/Basic/LLVM.h"
namespace clang {
namespace driver {
@@ -23,7 +21,7 @@ namespace driver {
class JobAction;
class ToolChain;
- typedef llvm::SmallVector<InputInfo, 4> InputInfoList;
+ typedef SmallVector<InputInfo, 4> InputInfoList;
/// Tool - Information on a specific compilation tool.
class Tool {
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index 4836d3ffac22..a5d51ca9d7c9 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -32,7 +32,7 @@ namespace driver {
/// ToolChain - Access to tools for a single platform.
class ToolChain {
public:
- typedef llvm::SmallVector<std::string, 4> path_list;
+ typedef SmallVector<std::string, 4> path_list;
enum CXXStdlibType {
CST_Libcxx,
@@ -63,9 +63,9 @@ public:
const llvm::Triple &getTriple() const { return Triple; }
llvm::Triple::ArchType getArch() const { return Triple.getArch(); }
- llvm::StringRef getArchName() const { return Triple.getArchName(); }
- llvm::StringRef getPlatform() const { return Triple.getVendorName(); }
- llvm::StringRef getOS() const { return Triple.getOSName(); }
+ StringRef getArchName() const { return Triple.getArchName(); }
+ StringRef getPlatform() const { return Triple.getVendorName(); }
+ StringRef getOS() const { return Triple.getOSName(); }
std::string getTripleString() const {
return Triple.getTriple();
@@ -139,7 +139,9 @@ public:
/// GetDefaultStackProtectorLevel - Get the default stack protector level for
/// this tool chain (0=off, 1=on, 2=all).
- virtual unsigned GetDefaultStackProtectorLevel() const { return 0; }
+ virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const {
+ return 0;
+ }
/// IsUnwindTablesDefault - Does this tool chain use -funwind-tables
/// by default.
@@ -169,21 +171,30 @@ public:
/// ComputeLLVMTriple - Return the LLVM target triple to use, after taking
/// command line arguments into account.
- virtual std::string ComputeLLVMTriple(const ArgList &Args) const;
+ virtual std::string ComputeLLVMTriple(const ArgList &Args,
+ types::ID InputType = types::TY_INVALID) const;
/// ComputeEffectiveClangTriple - Return the Clang triple to use for this
/// target, which may take into account the command line arguments. For
/// example, on Darwin the -mmacosx-version-min= command line argument (which
/// sets the deployment target) determines the version in the triple passed to
/// Clang.
- virtual std::string ComputeEffectiveClangTriple(const ArgList &Args) const;
+ virtual std::string ComputeEffectiveClangTriple(const ArgList &Args,
+ types::ID InputType = types::TY_INVALID) const;
/// configureObjCRuntime - Configure the known properties of the
/// Objective-C runtime for this platform.
///
- /// FIXME: this doesn't really belong here.
+ /// FIXME: this really belongs on some sort of DeploymentTarget abstraction
virtual void configureObjCRuntime(ObjCRuntime &runtime) const;
+ /// hasBlocksRuntime - Given that the user is compiling with
+ /// -fblocks, does this tool chain guarantee the existence of a
+ /// blocks runtime?
+ ///
+ /// FIXME: this really belongs on some sort of DeploymentTarget abstraction
+ virtual bool hasBlocksRuntime() const { return true; }
+
// GetCXXStdlibType - Determine the C++ standard library type to use with the
// given compilation arguments.
virtual CXXStdlibType GetCXXStdlibType(const ArgList &Args) const;
diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def
index f09a1dcaf26f..8449d639e698 100644
--- a/include/clang/Driver/Types.def
+++ b/include/clang/Driver/Types.def
@@ -44,15 +44,18 @@ TYPE("c", C, PP_C, 0, "u")
TYPE("cl", CL, PP_C, 0, "u")
TYPE("cuda", CUDA, PP_CXX, 0, "u")
TYPE("objective-c-cpp-output", PP_ObjC, INVALID, "mi", "u")
+TYPE("objc-cpp-output", PP_ObjC_Alias, INVALID, "mi", "u")
TYPE("objective-c", ObjC, PP_ObjC, 0, "u")
TYPE("c++-cpp-output", PP_CXX, INVALID, "ii", "u")
TYPE("c++", CXX, PP_CXX, 0, "u")
TYPE("objective-c++-cpp-output", PP_ObjCXX, INVALID, "mii", "u")
+TYPE("objc++-cpp-output", PP_ObjCXX_Alias, INVALID, "mii", "u")
TYPE("objective-c++", ObjCXX, PP_ObjCXX, 0, "u")
// C family input files to precompile.
TYPE("c-header-cpp-output", PP_CHeader, INVALID, "i", "p")
TYPE("c-header", CHeader, PP_CHeader, 0, "pu")
+TYPE("cl-header", CLHeader, PP_CHeader, 0, "pu")
TYPE("objective-c-header-cpp-output", PP_ObjCHeader, INVALID, "mi", "p")
TYPE("objective-c-header", ObjCHeader, PP_ObjCHeader, 0, "pu")
TYPE("c++-header-cpp-output", PP_CXXHeader, INVALID, "ii", "p")
diff --git a/include/clang/Driver/Util.h b/include/clang/Driver/Util.h
index 52f268d182a8..65aef4b31025 100644
--- a/include/clang/Driver/Util.h
+++ b/include/clang/Driver/Util.h
@@ -10,19 +10,17 @@
#ifndef CLANG_DRIVER_UTIL_H_
#define CLANG_DRIVER_UTIL_H_
-namespace llvm {
- template<typename T, unsigned N> class SmallVector;
-}
+#include "clang/Basic/LLVM.h"
namespace clang {
namespace driver {
class Action;
/// ArgStringList - Type used for constructing argv lists for subprocesses.
- typedef llvm::SmallVector<const char*, 16> ArgStringList;
+ typedef SmallVector<const char*, 16> ArgStringList;
/// ActionList - Type used for lists of actions.
- typedef llvm::SmallVector<Action*, 3> ActionList;
+ typedef SmallVector<Action*, 3> ActionList;
} // end namespace driver
} // end namespace clang
diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h
index 3c05834ad6a7..cef9509a9793 100644
--- a/include/clang/Frontend/ASTConsumers.h
+++ b/include/clang/Frontend/ASTConsumers.h
@@ -14,15 +14,16 @@
#ifndef DRIVER_ASTCONSUMERS_H
#define DRIVER_ASTCONSUMERS_H
+#include "clang/Basic/LLVM.h"
+
namespace llvm {
- class raw_ostream;
namespace sys { class Path; }
}
namespace clang {
class ASTConsumer;
class CodeGenOptions;
-class Diagnostic;
+class DiagnosticsEngine;
class FileManager;
class LangOptions;
class Preprocessor;
@@ -32,7 +33,7 @@ class TargetOptions;
// original C code. The output is intended to be in a format such that
// clang could re-parse the output back into the same AST, but the
// implementation is still incomplete.
-ASTConsumer *CreateASTPrinter(llvm::raw_ostream *OS);
+ASTConsumer *CreateASTPrinter(raw_ostream *OS);
// AST dumper: dumps the raw AST in human-readable form to stderr; this is
// intended for debugging.
@@ -40,7 +41,7 @@ ASTConsumer *CreateASTDumper();
// AST XML-dumper: dumps out the AST to stderr in a very detailed XML
// format; this is intended for particularly intense debugging.
-ASTConsumer *CreateASTDumperXML(llvm::raw_ostream &OS);
+ASTConsumer *CreateASTDumperXML(raw_ostream &OS);
// Graphical AST viewer: for each function definition, creates a graph of
// the AST and displays it with the graph viewer "dotty". Also outputs
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 58a60a1f9d87..471476a44477 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -18,6 +18,7 @@
#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/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
@@ -41,10 +42,11 @@ namespace llvm {
namespace clang {
class ASTContext;
+class ASTReader;
class CodeCompleteConsumer;
class CompilerInvocation;
class Decl;
-class Diagnostic;
+class DiagnosticsEngine;
class FileEntry;
class FileManager;
class HeaderSearch;
@@ -65,19 +67,15 @@ class GlobalCodeCompletionAllocator
/// \brief Utility class for loading a ASTContext from an AST file.
///
-class ASTUnit {
-public:
- typedef std::map<FileID, std::vector<PreprocessedEntity *> >
- PreprocessedEntitiesByFileMap;
-
+class ASTUnit : public ModuleLoader {
private:
- llvm::IntrusiveRefCntPtr<Diagnostic> Diagnostics;
- llvm::IntrusiveRefCntPtr<FileManager> FileMgr;
- llvm::IntrusiveRefCntPtr<SourceManager> SourceMgr;
- llvm::OwningPtr<HeaderSearch> HeaderInfo;
- llvm::IntrusiveRefCntPtr<TargetInfo> Target;
- llvm::IntrusiveRefCntPtr<Preprocessor> PP;
- llvm::IntrusiveRefCntPtr<ASTContext> Ctx;
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
+ llvm::IntrusiveRefCntPtr<FileManager> FileMgr;
+ llvm::IntrusiveRefCntPtr<SourceManager> SourceMgr;
+ llvm::OwningPtr<HeaderSearch> HeaderInfo;
+ llvm::IntrusiveRefCntPtr<TargetInfo> Target;
+ llvm::IntrusiveRefCntPtr<Preprocessor> PP;
+ llvm::IntrusiveRefCntPtr<ASTContext> Ctx;
FileSystemOptions FileSystemOpts;
@@ -111,8 +109,8 @@ private:
/// \brief Track whether the main file was loaded from an AST or not.
bool MainFileIsAST;
- /// \brief Whether this AST represents a complete translation unit.
- bool CompleteTranslationUnit;
+ /// \brief What kind of translation unit this AST represents.
+ TranslationUnitKind TUKind;
/// \brief Whether we should time each operation.
bool WantTiming;
@@ -128,14 +126,6 @@ private:
// source. In the long term we should make the Index library use efficient and
// more scalable search mechanisms.
std::vector<Decl*> TopLevelDecls;
-
- /// \brief The list of preprocessed entities which appeared when the ASTUnit
- /// was loaded.
- ///
- /// FIXME: This is just an optimization hack to avoid deserializing large
- /// parts of a PCH file while performing a walk or search. In the long term,
- /// we should provide more scalable search mechanisms.
- std::vector<PreprocessedEntity *> PreprocessedEntities;
/// The name of the original source file used to generate this ASTUnit.
std::string OriginalSourceFile;
@@ -143,9 +133,12 @@ private:
// Critical optimization when using clang_getCursor().
ASTLocation LastLoc;
+ /// \brief The set of diagnostics produced when creating the preamble.
+ SmallVector<StoredDiagnostic, 4> PreambleDiagnostics;
+
/// \brief The set of diagnostics produced when creating this
/// translation unit.
- llvm::SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
+ SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
/// \brief The number of stored diagnostics that come from the driver
/// itself.
@@ -156,27 +149,8 @@ private:
/// \brief Temporary files that should be removed when the ASTUnit is
/// destroyed.
- llvm::SmallVector<llvm::sys::Path, 4> TemporaryFiles;
-
- /// \brief A mapping from file IDs to the set of preprocessed entities
- /// stored in that file.
- ///
- /// FIXME: This is just an optimization hack to avoid searching through
- /// many preprocessed entities during cursor traversal in the CIndex library.
- /// Ideally, we would just be able to perform a binary search within the
- /// list of preprocessed entities.
- PreprocessedEntitiesByFileMap PreprocessedEntitiesByFile;
+ SmallVector<llvm::sys::Path, 4> TemporaryFiles;
- /// \brief Simple hack to allow us to assert that ASTUnit is not being
- /// used concurrently, which is not supported.
- ///
- /// Clients should create instances of the ConcurrencyCheck class whenever
- /// using the ASTUnit in a way that isn't intended to be concurrent, which is
- /// just about any usage.
- unsigned int ConcurrencyCheckValue;
- static const unsigned int CheckLocked = 28573289;
- static const unsigned int CheckUnlocked = 9803453;
-
/// \brief Counter that determines when we want to try building a
/// precompiled preamble.
///
@@ -191,9 +165,53 @@ private:
/// \brief The file in which the precompiled preamble is stored.
std::string PreambleFile;
+public:
+ class PreambleData {
+ const FileEntry *File;
+ std::vector<char> Buffer;
+ mutable unsigned NumLines;
+
+ public:
+ PreambleData() : File(0), NumLines(0) { }
+
+ void assign(const FileEntry *F, const char *begin, const char *end) {
+ File = F;
+ Buffer.assign(begin, end);
+ NumLines = 0;
+ }
+
+ void clear() { Buffer.clear(); File = 0; NumLines = 0; }
+
+ size_t size() const { return Buffer.size(); }
+ bool empty() const { return Buffer.empty(); }
+
+ const char *getBufferStart() const { return &Buffer[0]; }
+
+ unsigned getNumLines() const {
+ if (NumLines)
+ return NumLines;
+ countLines();
+ return NumLines;
+ }
+
+ SourceRange getSourceRange(const SourceManager &SM) const {
+ SourceLocation FileLoc = SM.getLocForStartOfFile(SM.getPreambleFileID());
+ return SourceRange(FileLoc, FileLoc.getLocWithOffset(size()-1));
+ }
+
+ private:
+ void countLines() const;
+ };
+
+ const PreambleData &getPreambleData() const {
+ return Preamble;
+ }
+
+private:
+
/// \brief The contents of the preamble that has been precompiled to
/// \c PreambleFile.
- std::vector<char> Preamble;
+ PreambleData Preamble;
/// \brief Whether the preamble ends at the start of a new line.
///
@@ -224,27 +242,15 @@ private:
/// \brief The number of warnings that occurred while parsing the preamble.
///
- /// This value will be used to restore the state of the \c Diagnostic object
- /// when re-using the precompiled preamble. Note that only the
+ /// This value will be used to restore the state of the \c DiagnosticsEngine
+ /// object when re-using the precompiled preamble. Note that only the
/// number of warnings matters, since we will not save the preamble
/// when any errors are present.
unsigned NumWarningsInPreamble;
- /// \brief The number of diagnostics that were stored when parsing
- /// the precompiled preamble.
- ///
- /// This value is used to determine how many of the stored
- /// diagnostics should be retained when reparsing in the presence of
- /// a precompiled preamble.
- unsigned NumStoredDiagnosticsInPreamble;
-
/// \brief A list of the serialization ID numbers for each of the top-level
/// declarations parsed within the precompiled preamble.
std::vector<serialization::DeclID> TopLevelDeclsInPreamble;
-
- /// \brief A list of the offsets into the precompiled preamble which
- /// correspond to preprocessed entities.
- std::vector<uint64_t> PreprocessedEntitiesInPreamble;
/// \brief Whether we should be caching code-completion results.
bool ShouldCacheCodeCompletionResults;
@@ -252,11 +258,19 @@ private:
/// \brief Whether we want to include nested macro expansions in the
/// detailed preprocessing record.
bool NestedMacroExpansions;
-
- static void ConfigureDiags(llvm::IntrusiveRefCntPtr<Diagnostic> &Diags,
+
+ /// \brief The language options used when we load an AST file.
+ LangOptions ASTFileLangOpts;
+
+ static void ConfigureDiags(llvm::IntrusiveRefCntPtr<DiagnosticsEngine> &Diags,
const char **ArgBegin, const char **ArgEnd,
ASTUnit &AST, bool CaptureDiagnostics);
+ void TranslateStoredDiagnostics(ASTReader *MMan, StringRef ModName,
+ SourceManager &SrcMan,
+ const SmallVectorImpl<StoredDiagnostic> &Diags,
+ SmallVectorImpl<StoredDiagnostic> &Out);
+
public:
/// \brief A cached code-completion result, which may be introduced in one of
/// many different contexts.
@@ -309,10 +323,24 @@ public:
return CachedCompletionAllocator;
}
+ /// \brief Retrieve the allocator used to cache global code completions.
+ /// Creates the allocator if it doesn't already exist.
+ llvm::IntrusiveRefCntPtr<GlobalCodeCompletionAllocator>
+ getCursorCompletionAllocator() {
+ if (!CursorCompletionAllocator.getPtr()) {
+ CursorCompletionAllocator = new GlobalCodeCompletionAllocator;
+ }
+ return CursorCompletionAllocator;
+ }
+
private:
/// \brief Allocator used to store cached code completions.
llvm::IntrusiveRefCntPtr<GlobalCodeCompletionAllocator>
CachedCompletionAllocator;
+
+ /// \brief Allocator used to store code completions for arbitrary cursors.
+ llvm::IntrusiveRefCntPtr<GlobalCodeCompletionAllocator>
+ CursorCompletionAllocator;
/// \brief The set of cached code-completion results.
std::vector<CachedCodeCompletionResult> CachedCompletionResults;
@@ -367,23 +395,38 @@ private:
bool AllowRebuild = true,
unsigned MaxLines = 0);
void RealizeTopLevelDeclsFromPreamble();
- void RealizePreprocessedEntitiesFromPreamble();
+ /// \brief Allows us to assert that ASTUnit is not being used concurrently,
+ /// which is not supported.
+ ///
+ /// Clients should create instances of the ConcurrencyCheck class whenever
+ /// using the ASTUnit in a way that isn't intended to be concurrent, which is
+ /// just about any usage.
+ /// Becomes a noop in release mode; only useful for debug mode checking.
+ class ConcurrencyState {
+ void *Mutex; // a llvm::sys::MutexImpl in debug;
+
+ public:
+ ConcurrencyState();
+ ~ConcurrencyState();
+
+ void start();
+ void finish();
+ };
+ ConcurrencyState ConcurrencyCheckValue;
+
public:
class ConcurrencyCheck {
- volatile ASTUnit &Self;
+ ASTUnit &Self;
public:
explicit ConcurrencyCheck(ASTUnit &Self)
: Self(Self)
{
- assert(Self.ConcurrencyCheckValue == CheckUnlocked &&
- "Concurrent access to ASTUnit!");
- Self.ConcurrencyCheckValue = CheckLocked;
+ Self.ConcurrencyCheckValue.start();
}
-
~ConcurrencyCheck() {
- Self.ConcurrencyCheckValue = CheckUnlocked;
+ Self.ConcurrencyCheckValue.finish();
}
};
friend class ConcurrencyCheck;
@@ -395,8 +438,8 @@ public:
bool isUnsafeToFree() const { return UnsafeToFree; }
void setUnsafeToFree(bool Value) { UnsafeToFree = Value; }
- const Diagnostic &getDiagnostics() const { return *Diagnostics; }
- Diagnostic &getDiagnostics() { return *Diagnostics; }
+ const DiagnosticsEngine &getDiagnostics() const { return *Diagnostics; }
+ DiagnosticsEngine &getDiagnostics() { return *Diagnostics; }
const SourceManager &getSourceManager() const { return *SourceMgr; }
SourceManager &getSourceManager() { return *SourceMgr; }
@@ -407,6 +450,8 @@ public:
const ASTContext &getASTContext() const { return *Ctx; }
ASTContext &getASTContext() { return *Ctx; }
+ void setASTContext(ASTContext *ctx) { Ctx = ctx; }
+
bool hasSema() const { return TheSema; }
Sema &getSema() const {
assert(TheSema && "ASTUnit does not have a Sema object!");
@@ -419,7 +464,6 @@ public:
const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; }
const std::string &getOriginalSourceFileName();
- const std::string &getASTFileName();
/// \brief Add a temporary file that the ASTUnit depends on.
///
@@ -433,15 +477,11 @@ public:
bool getOwnsRemappedFileBuffers() const { return OwnsRemappedFileBuffers; }
void setOwnsRemappedFileBuffers(bool val) { OwnsRemappedFileBuffers = val; }
- /// \brief Retrieve the maximum PCH level of declarations that a
- /// traversal of the translation unit should consider.
- unsigned getMaxPCHLevel() const;
-
void setLastASTLocation(ASTLocation ALoc) { LastLoc = ALoc; }
ASTLocation getLastASTLocation() const { return LastLoc; }
- llvm::StringRef getMainFileName() const;
+ StringRef getMainFileName() const;
typedef std::vector<Decl *>::iterator top_level_iterator;
@@ -484,22 +524,38 @@ public:
///
/// Note: This is used internally by the top-level tracking action
unsigned &getCurrentTopLevelHashValue() { return CurrentTopLevelHashValue; }
-
- typedef std::vector<PreprocessedEntity *>::iterator pp_entity_iterator;
-
- pp_entity_iterator pp_entity_begin();
- pp_entity_iterator pp_entity_end();
-
- /// \brief Add a new preprocessed entity that's stored at the given offset
- /// in the precompiled preamble.
- void addPreprocessedEntityFromPreamble(uint64_t Offset) {
- PreprocessedEntitiesInPreamble.push_back(Offset);
+
+ /// \brief Get the source location for the given file:line:col triplet.
+ ///
+ /// The difference with SourceManager::getLocation is that this method checks
+ /// whether the requested location points inside the precompiled preamble
+ /// in which case the returned source location will be a "loaded" one.
+ SourceLocation getLocation(const FileEntry *File,
+ unsigned Line, unsigned Col) const;
+
+ /// \brief Get the source location for the given file:offset pair.
+ SourceLocation getLocation(const FileEntry *File, unsigned Offset) const;
+
+ /// \brief If \arg Loc is a loaded location from the preamble, returns
+ /// the corresponding local location of the main file, otherwise it returns
+ /// \arg Loc.
+ SourceLocation mapLocationFromPreamble(SourceLocation Loc);
+
+ /// \brief If \arg Loc is a local location of the main file but inside the
+ /// preamble chunk, returns the corresponding loaded location from the
+ /// preamble, otherwise it returns \arg Loc.
+ SourceLocation mapLocationToPreamble(SourceLocation Loc);
+
+ /// \brief \see mapLocationFromPreamble.
+ SourceRange mapRangeFromPreamble(SourceRange R) {
+ return SourceRange(mapLocationFromPreamble(R.getBegin()),
+ mapLocationFromPreamble(R.getEnd()));
}
-
- /// \brief Retrieve the mapping from File IDs to the preprocessed entities
- /// within that file.
- PreprocessedEntitiesByFileMap &getPreprocessedEntitiesByFile() {
- return PreprocessedEntitiesByFile;
+
+ /// \brief \see mapLocationToPreamble.
+ SourceRange mapRangeToPreamble(SourceRange R) {
+ return SourceRange(mapLocationToPreamble(R.getBegin()),
+ mapLocationToPreamble(R.getEnd()));
}
// Retrieve the diagnostics associated with this AST
@@ -512,7 +568,7 @@ public:
}
unsigned stored_diag_size() const { return StoredDiagnostics.size(); }
- llvm::SmallVector<StoredDiagnostic, 4> &getStoredDiagnostics() {
+ SmallVector<StoredDiagnostic, 4> &getStoredDiagnostics() {
return StoredDiagnostics;
}
@@ -531,14 +587,11 @@ public:
return CachedCompletionResults.size();
}
- llvm::MemoryBuffer *getBufferForFile(llvm::StringRef Filename,
+ llvm::MemoryBuffer *getBufferForFile(StringRef Filename,
std::string *ErrorStr = 0);
- /// \brief Whether this AST represents a complete translation unit.
- ///
- /// If false, this AST is only a partial translation unit, e.g., one
- /// that might still be used as a precompiled header or preamble.
- bool isCompleteTranslationUnit() const { return CompleteTranslationUnit; }
+ /// \brief Determine what kind of translation unit this AST represents.
+ TranslationUnitKind getTranslationUnitKind() const { return TUKind; }
typedef llvm::PointerUnion<const char *, const llvm::MemoryBuffer *>
FilenameOrMemBuf;
@@ -548,7 +601,7 @@ public:
/// \brief Create a ASTUnit. Gets ownership of the passed CompilerInvocation.
static ASTUnit *create(CompilerInvocation *CI,
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags);
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags);
/// \brief Create a ASTUnit from an AST file.
///
@@ -559,7 +612,7 @@ public:
///
/// \returns - The initialized ASTUnit or null if the AST failed to load.
static ASTUnit *LoadFromASTFile(const std::string &Filename,
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
const FileSystemOptions &FileSystemOpts,
bool OnlyLocalDecls = false,
RemappedFile *RemappedFiles = 0,
@@ -590,9 +643,13 @@ public:
///
/// \param Action - The ASTFrontendAction to invoke. Its ownership is not
/// transfered.
+ ///
+ /// \param Unit - optionally an already created ASTUnit. Its ownership is not
+ /// transfered.
static ASTUnit *LoadFromCompilerInvocationAction(CompilerInvocation *CI,
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
- ASTFrontendAction *Action = 0);
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ ASTFrontendAction *Action = 0,
+ ASTUnit *Unit = 0);
/// LoadFromCompilerInvocation - Create an ASTUnit from a source file, via a
/// CompilerInvocation object.
@@ -606,11 +663,11 @@ public:
// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we
// shouldn't need to specify them at construction time.
static ASTUnit *LoadFromCompilerInvocation(CompilerInvocation *CI,
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
bool OnlyLocalDecls = false,
bool CaptureDiagnostics = false,
bool PrecompilePreamble = false,
- bool CompleteTranslationUnit = true,
+ TranslationUnitKind TUKind = TU_Complete,
bool CacheCodeCompletionResults = false,
bool NestedMacroExpansions = true);
@@ -630,18 +687,16 @@ public:
// shouldn't need to specify them at construction time.
static ASTUnit *LoadFromCommandLine(const char **ArgBegin,
const char **ArgEnd,
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
- llvm::StringRef ResourceFilesPath,
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ StringRef ResourceFilesPath,
bool OnlyLocalDecls = false,
bool CaptureDiagnostics = false,
RemappedFile *RemappedFiles = 0,
unsigned NumRemappedFiles = 0,
bool RemappedFilesKeepOriginalName = true,
bool PrecompilePreamble = false,
- bool CompleteTranslationUnit = true,
+ TranslationUnitKind TUKind = TU_Complete,
bool CacheCodeCompletionResults = false,
- bool CXXPrecompilePreamble = false,
- bool CXXChainedPCH = false,
bool NestedMacroExpansions = true);
/// \brief Reparse the source files using the same command-line options that
@@ -669,24 +724,31 @@ public:
///
/// FIXME: The Diag, LangOpts, SourceMgr, FileMgr, StoredDiagnostics, and
/// OwnedBuffers parameters are all disgusting hacks. They will go away.
- void CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
+ void CodeComplete(StringRef File, unsigned Line, unsigned Column,
RemappedFile *RemappedFiles, unsigned NumRemappedFiles,
bool IncludeMacros, bool IncludeCodePatterns,
CodeCompleteConsumer &Consumer,
- Diagnostic &Diag, LangOptions &LangOpts,
+ DiagnosticsEngine &Diag, LangOptions &LangOpts,
SourceManager &SourceMgr, FileManager &FileMgr,
- llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics,
- llvm::SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers);
+ SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics,
+ SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers);
/// \brief Save this translation unit to a file with the given name.
///
/// \returns An indication of whether the save was successful or not.
- CXSaveError Save(llvm::StringRef File);
+ CXSaveError Save(StringRef File);
/// \brief Serialize this translation unit with the given output stream.
///
/// \returns True if an error occurred, false otherwise.
- bool serialize(llvm::raw_ostream &OS);
+ bool serialize(raw_ostream &OS);
+
+ virtual ModuleKey loadModule(SourceLocation ImportLoc,
+ IdentifierInfo &ModuleName,
+ SourceLocation ModuleNameLoc) {
+ // ASTUnit doesn't know how to load modules (not that this matters).
+ return 0;
+ }
};
} // namespace clang
diff --git a/include/clang/Frontend/Analyses.def b/include/clang/Frontend/Analyses.def
index f055549b4e24..010f889c0974 100644
--- a/include/clang/Frontend/Analyses.def
+++ b/include/clang/Frontend/Analyses.def
@@ -15,9 +15,7 @@
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN)
#endif
-ANALYSIS_STORE(BasicStore, "basic", "Use basic analyzer store", CreateBasicStoreManager)
ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store", CreateRegionStoreManager)
-ANALYSIS_STORE(FlatStore, "flat", "Use flat analyzer store", CreateFlatStoreManager)
#ifndef ANALYSIS_CONSTRAINTS
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN)
@@ -30,13 +28,21 @@ ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of conc
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE)
#endif
-ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticClient, false)
-ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", createPlistDiagnosticClient, true)
-ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticClient, true)
-ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticClient, true)
+ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer, false)
+ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", createPlistDiagnosticConsumer, true)
+ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer, true)
+ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer, true)
+
+#ifndef ANALYSIS_PURGE
+#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC)
+#endif
+
+ANALYSIS_PURGE(PurgeStmt, "statement", "Purge symbols, bindings, and constraints before every statement")
+ANALYSIS_PURGE(PurgeBlock, "block", "Purge symbols, bindings, and constraints before every basic block")
+ANALYSIS_PURGE(PurgeNone, "none", "Do not purge symbols, bindings, or constraints")
#undef ANALYSIS_STORE
#undef ANALYSIS_CONSTRAINTS
#undef ANALYSIS_DIAGNOSTICS
-#undef ANALYSIS_STORE
+#undef ANALYSIS_PURGE
diff --git a/include/clang/Frontend/AnalyzerOptions.h b/include/clang/Frontend/AnalyzerOptions.h
index ea9f5e38b7b9..3565a51d0751 100644
--- a/include/clang/Frontend/AnalyzerOptions.h
+++ b/include/clang/Frontend/AnalyzerOptions.h
@@ -20,7 +20,7 @@
namespace clang {
class ASTConsumer;
-class Diagnostic;
+class DiagnosticsEngine;
class Preprocessor;
class LangOptions;
@@ -53,6 +53,13 @@ enum AnalysisDiagClients {
NUM_ANALYSIS_DIAG_CLIENTS
};
+/// AnalysisPurgeModes - Set of available strategies for dead symbol removal.
+enum AnalysisPurgeMode {
+#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) NAME,
+#include "clang/Frontend/Analyses.def"
+NumPurgeModes
+};
+
class AnalyzerOptions {
public:
/// \brief Pair of checker name and enable/disable.
@@ -60,6 +67,7 @@ public:
AnalysisStores AnalysisStoreOpt;
AnalysisConstraints AnalysisConstraintsOpt;
AnalysisDiagClients AnalysisDiagOpt;
+ AnalysisPurgeMode AnalysisPurgeOpt;
std::string AnalyzeSpecificFunction;
unsigned MaxNodes;
unsigned MaxLoop;
@@ -68,7 +76,6 @@ public:
unsigned AnalyzerDisplayProgress : 1;
unsigned AnalyzeNestedBlocks : 1;
unsigned EagerlyAssume : 1;
- unsigned PurgeDead : 1;
unsigned TrimGraph : 1;
unsigned VisualizeEGDot : 1;
unsigned VisualizeEGUbi : 1;
@@ -80,15 +87,15 @@ public:
public:
AnalyzerOptions() {
- AnalysisStoreOpt = BasicStoreModel;
+ AnalysisStoreOpt = RegionStoreModel;
AnalysisConstraintsOpt = RangeConstraintsModel;
AnalysisDiagOpt = PD_HTML;
+ AnalysisPurgeOpt = PurgeStmt;
ShowCheckerHelp = 0;
AnalyzeAll = 0;
AnalyzerDisplayProgress = 0;
AnalyzeNestedBlocks = 0;
EagerlyAssume = 0;
- PurgeDead = 1;
TrimGraph = 0;
VisualizeEGDot = 0;
VisualizeEGUbi = 0;
diff --git a/include/clang/Frontend/ChainedDiagnosticClient.h b/include/clang/Frontend/ChainedDiagnosticConsumer.h
index 70f21901db4f..f20cf6fcf4f2 100644
--- a/include/clang/Frontend/ChainedDiagnosticClient.h
+++ b/include/clang/Frontend/ChainedDiagnosticConsumer.h
@@ -1,4 +1,4 @@
-//===--- ChainedDiagnosticClient.h - Chain Diagnostic Clients ---*- C++ -*-===//
+//===- ChainedDiagnosticConsumer.h - Chain Diagnostic Clients ---*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_CHAINEDDIAGNOSTICCLIENT_H
-#define LLVM_CLANG_FRONTEND_CHAINEDDIAGNOSTICCLIENT_H
+#ifndef LLVM_CLANG_FRONTEND_CHAINEDDIAGNOSTICCONSUMER_H
+#define LLVM_CLANG_FRONTEND_CHAINEDDIAGNOSTICCONSUMER_H
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/OwningPtr.h"
@@ -16,17 +16,17 @@
namespace clang {
class LangOptions;
-/// ChainedDiagnosticClient - Chain two diagnostic clients so that diagnostics
+/// ChainedDiagnosticConsumer - Chain two diagnostic clients so that diagnostics
/// go to the first client and then the second. The first diagnostic client
/// should be the "primary" client, and will be used for computing whether the
/// diagnostics should be included in counts.
-class ChainedDiagnosticClient : public DiagnosticClient {
- llvm::OwningPtr<DiagnosticClient> Primary;
- llvm::OwningPtr<DiagnosticClient> Secondary;
+class ChainedDiagnosticConsumer : public DiagnosticConsumer {
+ llvm::OwningPtr<DiagnosticConsumer> Primary;
+ llvm::OwningPtr<DiagnosticConsumer> Secondary;
public:
- ChainedDiagnosticClient(DiagnosticClient *_Primary,
- DiagnosticClient *_Secondary) {
+ ChainedDiagnosticConsumer(DiagnosticConsumer *_Primary,
+ DiagnosticConsumer *_Secondary) {
Primary.reset(_Primary);
Secondary.reset(_Secondary);
}
@@ -46,14 +46,20 @@ public:
return Primary->IncludeInDiagnosticCounts();
}
- virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
- const DiagnosticInfo &Info) {
+ virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) {
// Default implementation (Warnings/errors count).
- DiagnosticClient::HandleDiagnostic(DiagLevel, Info);
+ DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
Primary->HandleDiagnostic(DiagLevel, Info);
Secondary->HandleDiagnostic(DiagLevel, Info);
}
+
+ DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
+ return new ChainedDiagnosticConsumer(Primary->clone(Diags),
+ Secondary->clone(Diags));
+ }
+
};
} // end namspace clang
diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
index 5d040b4f266c..4874c17c7996 100644
--- a/include/clang/Frontend/CodeGenOptions.h
+++ b/include/clang/Frontend/CodeGenOptions.h
@@ -37,6 +37,7 @@ public:
unsigned AsmVerbose : 1; /// -dA, -fverbose-asm.
unsigned ObjCAutoRefCountExceptions : 1; /// Whether ARC should be EH-safe.
+ unsigned CUDAIsDevice : 1; /// Set when compiling for CUDA device.
unsigned CXAAtExit : 1; /// Use __cxa_atexit for calling destructors.
unsigned CXXCtorDtorAliases: 1; /// Emit complete ctors/dtors as linker
/// aliases to base ctors when possible.
@@ -71,6 +72,7 @@ public:
unsigned NoCommon : 1; /// Set when -fno-common or C++ is enabled.
unsigned NoDwarf2CFIAsm : 1; /// Set when -fno-dwarf2-cfi-asm is enabled.
unsigned NoExecStack : 1; /// Set when -Wa,--noexecstack is enabled.
+ unsigned NoGlobalMerge : 1; /// Set when -mno-global-merge is enabled.
unsigned NoImplicitFloat : 1; /// Set when -mno-implicit-float is enabled.
unsigned NoInfsFPMath : 1; /// Assume FP arguments, results not +-Inf.
unsigned NoNaNsFPMath : 1; /// Assume FP arguments, results not NaN.
@@ -142,6 +144,7 @@ public:
public:
CodeGenOptions() {
AsmVerbose = 0;
+ CUDAIsDevice = 0;
CXAAtExit = 1;
CXXCtorDtorAliases = 0;
DataSections = 0;
diff --git a/include/clang/Frontend/CommandLineSourceLoc.h b/include/clang/Frontend/CommandLineSourceLoc.h
index 8911cfadd530..c01f91d6ec27 100644
--- a/include/clang/Frontend/CommandLineSourceLoc.h
+++ b/include/clang/Frontend/CommandLineSourceLoc.h
@@ -15,6 +15,7 @@
#ifndef LLVM_CLANG_FRONTEND_COMMANDLINESOURCELOC_H
#define LLVM_CLANG_FRONTEND_COMMANDLINESOURCELOC_H
+#include "clang/Basic/LLVM.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"
@@ -29,10 +30,10 @@ struct ParsedSourceLocation {
public:
/// Construct a parsed source location from a string; the Filename is empty on
/// error.
- static ParsedSourceLocation FromString(llvm::StringRef Str) {
+ static ParsedSourceLocation FromString(StringRef Str) {
ParsedSourceLocation PSL;
- std::pair<llvm::StringRef, llvm::StringRef> ColSplit = Str.rsplit(':');
- std::pair<llvm::StringRef, llvm::StringRef> LineSplit =
+ std::pair<StringRef, StringRef> ColSplit = Str.rsplit(':');
+ std::pair<StringRef, StringRef> LineSplit =
ColSplit.first.rsplit(':');
// If both tail splits were valid integers, return success.
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index 004c8896e232..881774022d12 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -11,6 +11,7 @@
#define LLVM_CLANG_FRONTEND_COMPILERINSTANCE_H_
#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Lex/ModuleLoader.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/OwningPtr.h"
@@ -19,7 +20,6 @@
#include <string>
namespace llvm {
-class raw_ostream;
class raw_fd_ostream;
class Timer;
}
@@ -27,13 +27,13 @@ class Timer;
namespace clang {
class ASTContext;
class ASTConsumer;
+class ASTReader;
class CodeCompleteConsumer;
-class Diagnostic;
-class DiagnosticClient;
+class DiagnosticsEngine;
+class DiagnosticConsumer;
class ExternalASTSource;
class FileManager;
class FrontendAction;
-class ASTReader;
class Preprocessor;
class Sema;
class SourceManager;
@@ -57,12 +57,12 @@ class TargetInfo;
/// in to the compiler instance for everything. When possible, utility functions
/// come in two forms; a short form that reuses the CompilerInstance objects,
/// and a long form that takes explicit instances of any required objects.
-class CompilerInstance {
+class CompilerInstance : public ModuleLoader {
/// The options used in this compiler instance.
llvm::IntrusiveRefCntPtr<CompilerInvocation> Invocation;
/// The diagnostics engine instance.
- llvm::IntrusiveRefCntPtr<Diagnostic> Diagnostics;
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
/// The target being compiled for.
llvm::IntrusiveRefCntPtr<TargetInfo> Target;
@@ -88,9 +88,12 @@ class CompilerInstance {
/// \brief The semantic analysis object.
llvm::OwningPtr<Sema> TheSema;
- /// The frontend timer
+ /// \brief The frontend timer
llvm::OwningPtr<llvm::Timer> FrontendTimer;
+ /// \brief Non-owning reference to the ASTReader, if one exists.
+ ASTReader *ModuleManager;
+
/// \brief Holds information about the output file.
///
/// If TempFilename is not empty we must rename it to Filename at the end.
@@ -99,10 +102,10 @@ class CompilerInstance {
struct OutputFile {
std::string Filename;
std::string TempFilename;
- llvm::raw_ostream *OS;
+ raw_ostream *OS;
OutputFile(const std::string &filename, const std::string &tempFilename,
- llvm::raw_ostream *os)
+ raw_ostream *os)
: Filename(filename), TempFilename(tempFilename), OS(os) { }
};
@@ -249,15 +252,15 @@ public:
bool hasDiagnostics() const { return Diagnostics != 0; }
/// Get the current diagnostics engine.
- Diagnostic &getDiagnostics() const {
+ DiagnosticsEngine &getDiagnostics() const {
assert(Diagnostics && "Compiler instance has no diagnostics!");
return *Diagnostics;
}
/// setDiagnostics - Replace the current diagnostics engine.
- void setDiagnostics(Diagnostic *Value);
+ void setDiagnostics(DiagnosticsEngine *Value);
- DiagnosticClient &getDiagnosticClient() const {
+ DiagnosticConsumer &getDiagnosticClient() const {
assert(Diagnostics && Diagnostics->getClient() &&
"Compiler instance has no diagnostic client!");
return *Diagnostics->getClient();
@@ -388,6 +391,12 @@ public:
Sema *takeSema() { return TheSema.take(); }
/// }
+ /// @name Module Management
+ /// {
+
+ ASTReader *getModuleManager() const { return ModuleManager; }
+
+ /// }
/// @name Code Completion
/// {
@@ -446,38 +455,48 @@ public:
/// allocating one if one is not provided.
///
/// \param Client If non-NULL, a diagnostic client that will be
- /// attached to (and, then, owned by) the Diagnostic inside this AST
+ /// attached to (and, then, owned by) the DiagnosticsEngine inside this AST
/// unit.
+ ///
+ /// \param ShouldOwnClient If Client is non-NULL, specifies whether
+ /// the diagnostic object should take ownership of the client.
+ ///
+ /// \param ShouldCloneClient If Client is non-NULL, specifies whether that
+ /// client should be cloned.
void createDiagnostics(int Argc, const char* const *Argv,
- DiagnosticClient *Client = 0);
+ DiagnosticConsumer *Client = 0,
+ bool ShouldOwnClient = true,
+ bool ShouldCloneClient = true);
- /// Create a Diagnostic object with a the TextDiagnosticPrinter.
+ /// Create a DiagnosticsEngine object with a the TextDiagnosticPrinter.
///
/// The \arg Argc and \arg 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
- /// DiagnosticClient that is owned by the returned diagnostic
+ /// DiagnosticConsumer that is owned by the returned diagnostic
/// object, if using directly the caller is responsible for
- /// releasing the returned Diagnostic's client eventually.
+ /// releasing the returned DiagnosticsEngine's client eventually.
///
/// \param Opts - The diagnostic options; note that the created text
/// diagnostic object contains a reference to these options and its lifetime
/// must extend past that of the diagnostic engine.
///
/// \param Client If non-NULL, a diagnostic client that will be
- /// attached to (and, then, owned by) the returned Diagnostic
+ /// attached to (and, then, owned by) the returned DiagnosticsEngine
/// object.
///
/// \param CodeGenOpts If non-NULL, the code gen options in use, which may be
/// used by some diagnostics printers (for logging purposes only).
///
/// \return The new object on success, or null on failure.
- static llvm::IntrusiveRefCntPtr<Diagnostic>
+ static llvm::IntrusiveRefCntPtr<DiagnosticsEngine>
createDiagnostics(const DiagnosticOptions &Opts, int Argc,
const char* const *Argv,
- DiagnosticClient *Client = 0,
+ DiagnosticConsumer *Client = 0,
+ bool ShouldOwnClient = true,
+ bool ShouldCloneClient = true,
const CodeGenOptions *CodeGenOpts = 0);
/// Create the file manager and replace any existing one with it.
@@ -490,26 +509,12 @@ public:
/// and replace any existing one with it.
void createPreprocessor();
- /// Create a Preprocessor object.
- ///
- /// Note that this also creates a new HeaderSearch object which will be owned
- /// by the resulting Preprocessor.
- ///
- /// \return The new object on success, or null on failure.
- static Preprocessor *createPreprocessor(Diagnostic &, const LangOptions &,
- const PreprocessorOptions &,
- const HeaderSearchOptions &,
- const DependencyOutputOptions &,
- const TargetInfo &,
- const FrontendOptions &,
- SourceManager &, FileManager &);
-
/// Create the AST context.
void createASTContext();
/// Create an external AST source to read a PCH file and attach it to the AST
/// context.
- void createPCHExternalASTSource(llvm::StringRef Path,
+ void createPCHExternalASTSource(StringRef Path,
bool DisablePCHValidation,
bool DisableStatCache,
void *DeserializationListener);
@@ -518,7 +523,7 @@ public:
///
/// \return - The new object on success, or null on failure.
static ExternalASTSource *
- createPCHExternalASTSource(llvm::StringRef Path, const std::string &Sysroot,
+ createPCHExternalASTSource(StringRef Path, const std::string &Sysroot,
bool DisablePCHValidation,
bool DisableStatCache,
Preprocessor &PP, ASTContext &Context,
@@ -537,10 +542,10 @@ public:
unsigned Line, unsigned Column,
bool ShowMacros,
bool ShowCodePatterns, bool ShowGlobals,
- llvm::raw_ostream &OS);
+ raw_ostream &OS);
/// \brief Create the Sema object to be used for parsing.
- void createSema(bool CompleteTranslationUnit,
+ void createSema(TranslationUnitKind TUKind,
CodeCompleteConsumer *CompletionConsumer);
/// Create the frontend timer and replace any existing one with it.
@@ -551,25 +556,27 @@ public:
///
/// \return - Null on error.
llvm::raw_fd_ostream *
- createDefaultOutputFile(bool Binary = true, llvm::StringRef BaseInput = "",
- llvm::StringRef Extension = "");
+ createDefaultOutputFile(bool Binary = true, StringRef BaseInput = "",
+ StringRef Extension = "");
/// Create a new output file and add it to the list of tracked output files,
/// optionally deriving the output path name.
///
/// \return - Null on error.
llvm::raw_fd_ostream *
- createOutputFile(llvm::StringRef OutputPath,
+ createOutputFile(StringRef OutputPath,
bool Binary = true, bool RemoveFileOnSignal = true,
- llvm::StringRef BaseInput = "",
- llvm::StringRef Extension = "");
+ StringRef BaseInput = "",
+ StringRef Extension = "",
+ bool UseTemporary = false);
/// Create a new output file, optionally deriving the output path name.
///
/// If \arg OutputPath is empty, then createOutputFile will derive an output
/// path location as \arg BaseInput, with any suffix removed, and \arg
- /// Extension appended. If OutputPath is not stdout createOutputFile will
- /// create a new temporary file that must be renamed to OutputPath in the end.
+ /// Extension appended. If OutputPath is not stdout and \arg UseTemporary
+ /// is true, createOutputFile will create a new temporary file that must be
+ /// renamed to OutputPath in the end.
///
/// \param OutputPath - If given, the path to the output file.
/// \param Error [out] - On failure, the error message.
@@ -580,15 +587,18 @@ public:
/// \param RemoveFileOnSignal - Whether the file should be registered with
/// llvm::sys::RemoveFileOnSignal. Note that this is not safe for
/// multithreaded use, as the underlying signal mechanism is not reentrant
+ /// \param UseTemporary - Create a new temporary file that must be renamed to
+ /// OutputPath in the end
/// \param ResultPathName [out] - If given, the result path name will be
/// stored here on success.
/// \param TempPathName [out] - If given, the temporary file path name
/// will be stored here on success.
static llvm::raw_fd_ostream *
- createOutputFile(llvm::StringRef OutputPath, std::string &Error,
+ createOutputFile(StringRef OutputPath, std::string &Error,
bool Binary = true, bool RemoveFileOnSignal = true,
- llvm::StringRef BaseInput = "",
- llvm::StringRef Extension = "",
+ StringRef BaseInput = "",
+ StringRef Extension = "",
+ bool UseTemporary = false,
std::string *ResultPathName = 0,
std::string *TempPathName = 0);
@@ -600,19 +610,23 @@ public:
/// as the main file.
///
/// \return True on success.
- bool InitializeSourceManager(llvm::StringRef InputFile);
+ bool InitializeSourceManager(StringRef InputFile);
/// InitializeSourceManager - Initialize the source manager to set InputFile
/// as the main file.
///
/// \return True on success.
- static bool InitializeSourceManager(llvm::StringRef InputFile,
- Diagnostic &Diags,
+ static bool InitializeSourceManager(StringRef InputFile,
+ DiagnosticsEngine &Diags,
FileManager &FileMgr,
SourceManager &SourceMgr,
const FrontendOptions &Opts);
/// }
+
+ virtual ModuleKey loadModule(SourceLocation ImportLoc,
+ IdentifierInfo &ModuleName,
+ SourceLocation ModuleNameLoc);
};
} // end namespace clang
diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h
index e18f3fe63249..47c70311dda4 100644
--- a/include/clang/Frontend/CompilerInvocation.h
+++ b/include/clang/Frontend/CompilerInvocation.h
@@ -28,13 +28,9 @@
#include <string>
#include <vector>
-namespace llvm {
- template<typename T> class SmallVectorImpl;
-}
-
namespace clang {
-class Diagnostic;
+class DiagnosticsEngine;
/// CompilerInvocation - Helper class for holding the data necessary to invoke
/// the compiler.
@@ -92,7 +88,7 @@ public:
static void CreateFromArgs(CompilerInvocation &Res,
const char* const *ArgBegin,
const char* const *ArgEnd,
- Diagnostic &Diags);
+ DiagnosticsEngine &Diags);
/// GetBuiltinIncludePath - Get the directory where the compiler headers
/// reside, relative to the compiler binary (found by the passed in
@@ -127,6 +123,10 @@ public:
static void setLangDefaults(LangOptions &Opts, InputKind IK,
LangStandard::Kind LangStd = LangStandard::lang_unspecified);
+ /// \brief Retrieve a module hash string that is suitable for uniquely
+ /// identifying the conditions under which the module was built.
+ std::string getModuleHash() const;
+
/// @}
/// @name Option Subgroups
/// @{
diff --git a/include/clang/Frontend/DiagnosticOptions.h b/include/clang/Frontend/DiagnosticOptions.h
index 5ae8eb367788..319abeb4fbf5 100644
--- a/include/clang/Frontend/DiagnosticOptions.h
+++ b/include/clang/Frontend/DiagnosticOptions.h
@@ -43,7 +43,7 @@ public:
unsigned ShowColors : 1; /// Show diagnostics with ANSI color sequences.
unsigned ShowOverloads : 1; /// Overload candidates to show. Values from
- /// Diagnostic::OverloadsShown
+ /// DiagnosticsEngine::OverloadsShown
unsigned VerifyDiagnostics: 1; /// Check that diagnostics match the expected
/// diagnostics, indicated by markers in the
/// input source file.
@@ -82,7 +82,7 @@ public:
PedanticErrors = 0;
ShowCarets = 1;
ShowColors = 0;
- ShowOverloads = Diagnostic::Ovl_All;
+ ShowOverloads = DiagnosticsEngine::Ovl_All;
ShowColumn = 1;
ShowFixits = 1;
ShowLocation = 1;
diff --git a/include/clang/Frontend/FrontendAction.h b/include/clang/Frontend/FrontendAction.h
index f335475665fd..f85cc7ec913c 100644
--- a/include/clang/Frontend/FrontendAction.h
+++ b/include/clang/Frontend/FrontendAction.h
@@ -10,15 +10,13 @@
#ifndef LLVM_CLANG_FRONTEND_FRONTENDACTION_H
#define LLVM_CLANG_FRONTEND_FRONTENDACTION_H
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/OwningPtr.h"
#include <string>
#include <vector>
-namespace llvm {
- class raw_ostream;
-}
-
namespace clang {
class ASTConsumer;
class ASTMergeAction;
@@ -55,7 +53,7 @@ class FrontendAction {
private:
ASTConsumer* CreateWrappedASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile);
+ StringRef InFile);
protected:
/// @name Implementation Action Interface
@@ -76,7 +74,7 @@ protected:
///
/// \return The new AST consumer, or 0 on failure.
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) = 0;
+ StringRef InFile) = 0;
/// \brief Callback before starting processing a single input, giving the
/// opportunity to modify the CompilerInvocation or do some other action
@@ -92,7 +90,7 @@ protected:
/// \return True on success; on failure \see ExecutionAction() and
/// EndSourceFileAction() will not be called.
virtual bool BeginSourceFileAction(CompilerInstance &CI,
- llvm::StringRef Filename) {
+ StringRef Filename) {
return true;
}
@@ -152,7 +150,7 @@ public:
return CurrentASTUnit.take();
}
- void setCurrentFile(llvm::StringRef Value, InputKind Kind, ASTUnit *AST = 0);
+ void setCurrentFile(StringRef Value, InputKind Kind, ASTUnit *AST = 0);
/// @}
/// @name Supported Modes
@@ -163,9 +161,8 @@ public:
/// file inputs.
virtual bool usesPreprocessorOnly() const = 0;
- /// usesCompleteTranslationUnit - For AST based actions, should the
- /// translation unit be completed?
- virtual bool usesCompleteTranslationUnit() { return true; }
+ /// \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?
virtual bool hasPCHSupport() const { return !usesPreprocessorOnly(); }
@@ -205,7 +202,7 @@ public:
///
/// \return True on success; the compilation of this file should be aborted
/// and neither Execute nor EndSourceFile should be called.
- bool BeginSourceFile(CompilerInstance &CI, llvm::StringRef Filename,
+ bool BeginSourceFile(CompilerInstance &CI, StringRef Filename,
InputKind Kind);
/// Execute - Set the source managers main input file, and run the action.
@@ -236,7 +233,7 @@ public:
class PluginASTAction : public ASTFrontendAction {
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) = 0;
+ StringRef InFile) = 0;
public:
/// ParseArgs - Parse the given plugin command line arguments.
@@ -256,7 +253,7 @@ protected:
/// CreateASTConsumer - Provide a default implementation which returns aborts,
/// this method should never be called by FrontendAction clients.
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile);
+ StringRef InFile);
public:
virtual bool usesPreprocessorOnly() const { return true; }
@@ -272,10 +269,10 @@ class WrapperFrontendAction : public FrontendAction {
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile);
+ StringRef InFile);
virtual bool BeginInvocation(CompilerInstance &CI);
virtual bool BeginSourceFileAction(CompilerInstance &CI,
- llvm::StringRef Filename);
+ StringRef Filename);
virtual void ExecuteAction();
virtual void EndSourceFileAction();
@@ -285,7 +282,7 @@ public:
WrapperFrontendAction(FrontendAction *WrappedAction);
virtual bool usesPreprocessorOnly() const;
- virtual bool usesCompleteTranslationUnit();
+ virtual TranslationUnitKind getTranslationUnitKind();
virtual bool hasPCHSupport() const;
virtual bool hasASTFileSupport() const;
virtual bool hasIRSupport() const;
diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h
index b409ad1e0963..72a3d908476a 100644
--- a/include/clang/Frontend/FrontendActions.h
+++ b/include/clang/Frontend/FrontendActions.h
@@ -24,7 +24,7 @@ class InitOnlyAction : public FrontendAction {
virtual void ExecuteAction();
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile);
+ StringRef InFile);
public:
// Don't claim to only use the preprocessor, we want to follow the AST path,
@@ -39,59 +39,65 @@ public:
class ASTPrintAction : public ASTFrontendAction {
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile);
+ StringRef InFile);
};
class ASTDumpAction : public ASTFrontendAction {
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile);
+ StringRef InFile);
};
class ASTDumpXMLAction : public ASTFrontendAction {
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile);
+ StringRef InFile);
};
class ASTViewAction : public ASTFrontendAction {
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile);
+ StringRef InFile);
};
class DeclContextPrintAction : public ASTFrontendAction {
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile);
+ StringRef InFile);
};
class GeneratePCHAction : public ASTFrontendAction {
+ bool MakeModule;
+
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile);
+ StringRef InFile);
- virtual bool usesCompleteTranslationUnit() { return false; }
+ virtual TranslationUnitKind getTranslationUnitKind() {
+ return MakeModule? TU_Module : TU_Prefix;
+ }
virtual bool hasASTFileSupport() const { return false; }
public:
+ /// \brief Create a new action
+ explicit GeneratePCHAction(bool MakeModule) : MakeModule(MakeModule) { }
+
/// \brief Compute the AST consumer arguments that will be used to
/// create the PCHGenerator instance returned by CreateASTConsumer.
///
/// \returns true if an error occurred, false otherwise.
static bool ComputeASTConsumerArguments(CompilerInstance &CI,
- llvm::StringRef InFile,
+ StringRef InFile,
std::string &Sysroot,
std::string &OutputFile,
- llvm::raw_ostream *&OS,
- bool &Chaining);
+ raw_ostream *&OS);
};
class SyntaxOnlyAction : public ASTFrontendAction {
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile);
+ StringRef InFile);
public:
virtual bool hasCodeCompletionSupport() const { return true; }
@@ -114,10 +120,10 @@ class ASTMergeAction : public FrontendAction {
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile);
+ StringRef InFile);
virtual bool BeginSourceFileAction(CompilerInstance &CI,
- llvm::StringRef Filename);
+ StringRef Filename);
virtual void ExecuteAction();
virtual void EndSourceFileAction();
@@ -128,7 +134,7 @@ public:
virtual ~ASTMergeAction();
virtual bool usesPreprocessorOnly() const;
- virtual bool usesCompleteTranslationUnit();
+ virtual TranslationUnitKind getTranslationUnitKind();
virtual bool hasPCHSupport() const;
virtual bool hasASTFileSupport() const;
virtual bool hasCodeCompletionSupport() const;
@@ -137,7 +143,7 @@ public:
class PrintPreambleAction : public FrontendAction {
protected:
void ExecuteAction();
- virtual ASTConsumer *CreateASTConsumer(CompilerInstance &, llvm::StringRef) {
+ virtual ASTConsumer *CreateASTConsumer(CompilerInstance &, StringRef) {
return 0;
}
diff --git a/include/clang/Frontend/FrontendDiagnostic.h b/include/clang/Frontend/FrontendDiagnostic.h
index 3e9508c009c8..21cd2c67910b 100644
--- a/include/clang/Frontend/FrontendDiagnostic.h
+++ b/include/clang/Frontend/FrontendDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM,
+ SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM,
#define FRONTENDSTART
#include "clang/Basic/DiagnosticFrontendKinds.inc"
#undef DIAG
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index 225a955b4ac6..fa6d044ce04b 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -24,7 +24,6 @@ namespace frontend {
ASTDumpXML, ///< Parse ASTs and dump them in XML.
ASTPrint, ///< Parse ASTs and print them.
ASTView, ///< Parse ASTs and view them in Graphviz.
- CreateModule, ///< Create module definition
DumpRawTokens, ///< Dump out raw tokens.
DumpTokens, ///< Dump out preprocessed tokens.
EmitAssembly, ///< Emit a .s file.
@@ -35,6 +34,7 @@ namespace frontend {
EmitCodeGenOnly, ///< Generate machine code, but don't emit anything.
EmitObj, ///< Emit a .o file.
FixIt, ///< Parse and apply any fixits to the source.
+ GenerateModule, ///< Generate pre-compiled module.
GeneratePCH, ///< Generate pre-compiled header.
GeneratePTH, ///< Generate pre-tokenized header.
InitOnly, ///< Only execute frontend initialization.
@@ -58,9 +58,6 @@ public:
unsigned RelocatablePCH : 1; ///< When generating PCH files,
/// instruct the AST writer to create
/// relocatable PCH files.
- unsigned ChainedPCH : 1; ///< When generating PCH files,
- /// instruct the AST writer to create
- /// chained PCH files.
unsigned ShowHelp : 1; ///< Show the -help text.
unsigned ShowMacrosInCodeCompletion : 1; ///< Show macros in code completion
/// results.
@@ -75,6 +72,8 @@ public:
unsigned ShowVersion : 1; ///< Show the -version text.
unsigned FixWhatYouCan : 1; ///< Apply fixes even if there are
/// unfixable errors.
+ unsigned ARCMTMigrateEmitARCErrors : 1; /// Emit ARC errors even if the
+ /// migrator can fix them
enum {
ARCMT_None,
@@ -84,6 +83,7 @@ public:
} ARCMTAction;
std::string ARCMTMigrateDir;
+ std::string ARCMTMigrateReportOut;
/// The input files and their types.
std::vector<std::pair<InputKind, std::string> > Inputs;
@@ -118,9 +118,6 @@ public:
/// \brief The list of AST files to merge.
std::vector<std::string> ASTMergeFiles;
- /// \brief The list of modules to import.
- std::vector<std::string> Modules;
-
/// \brief A list of arguments to forward to LLVM's option processing; this
/// should only be used for debugging and experimental features.
std::vector<std::string> LLVMArgs;
@@ -131,7 +128,6 @@ public:
ProgramAction = frontend::ParseSyntaxOnly;
ActionName = "";
RelocatablePCH = 0;
- ChainedPCH = 0;
ShowHelp = 0;
ShowMacrosInCodeCompletion = 0;
ShowCodePatternsInCodeCompletion = 0;
@@ -140,6 +136,7 @@ public:
ShowTimers = 0;
ShowVersion = 0;
ARCMTAction = ARCMT_None;
+ ARCMTMigrateEmitARCErrors = 0;
}
/// getInputKindForExtension - Return the appropriate input kind for a file
@@ -147,7 +144,7 @@ public:
///
/// \return The input kind for the extension, or IK_None if the extension is
/// not recognized.
- static InputKind getInputKindForExtension(llvm::StringRef Extension);
+ static InputKind getInputKindForExtension(StringRef Extension);
};
} // end namespace clang
diff --git a/include/clang/Frontend/HeaderSearchOptions.h b/include/clang/Frontend/HeaderSearchOptions.h
index 0347f98fd5ba..92790e99d890 100644
--- a/include/clang/Frontend/HeaderSearchOptions.h
+++ b/include/clang/Frontend/HeaderSearchOptions.h
@@ -23,8 +23,13 @@ namespace frontend {
enum IncludeDirGroup {
Quoted = 0, ///< '#include ""' paths, added by'gcc -iquote'.
Angled, ///< Paths for '#include <>' added by '-I'.
+ IndexHeaderMap, ///< Like Angled, but marks header maps used when
+ /// building frameworks.
System, ///< Like Angled, but marks system directories.
+ CSystem, ///< Like System, but only used for C.
CXXSystem, ///< Like System, but only used for C++.
+ ObjCSystem, ///< Like System, but only used for ObjC.
+ ObjCXXSystem, ///< Like System, but only used for ObjC++.
After ///< Like System, but searched after the system directories.
};
}
@@ -44,7 +49,7 @@ public:
/// path.
unsigned IgnoreSysRoot : 1;
- Entry(llvm::StringRef path, frontend::IncludeDirGroup group,
+ Entry(StringRef path, frontend::IncludeDirGroup group,
bool isUserSupplied, bool isFramework, bool ignoreSysRoot)
: Path(path), Group(group), IsUserSupplied(isUserSupplied),
IsFramework(isFramework), IgnoreSysRoot(ignoreSysRoot) {}
@@ -57,27 +62,24 @@ public:
/// User specified include entries.
std::vector<Entry> UserEntries;
- /// A (system-path) delimited list of include paths to be added from the
- /// environment following the user specified includes (but prior to builtin
- /// and standard includes). This is parsed in the same manner as the CPATH
- /// environment variable for gcc.
- std::string EnvIncPath;
-
- /// Per-language environmental include paths, see \see EnvIncPath.
- std::string CEnvIncPath;
- std::string ObjCEnvIncPath;
- std::string CXXEnvIncPath;
- std::string ObjCXXEnvIncPath;
-
/// The directory which holds the compiler resource files (builtin includes,
/// etc.).
std::string ResourceDir;
+ /// \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;
+
/// Include the compiler builtin includes.
unsigned UseBuiltinIncludes : 1;
/// Include the system standard include search directories.
- unsigned UseStandardIncludes : 1;
+ unsigned UseStandardSystemIncludes : 1;
/// Include the system standard C++ library include search directories.
unsigned UseStandardCXXIncludes : 1;
@@ -89,13 +91,13 @@ public:
unsigned Verbose : 1;
public:
- HeaderSearchOptions(llvm::StringRef _Sysroot = "/")
- : Sysroot(_Sysroot), UseBuiltinIncludes(true),
- UseStandardIncludes(true), UseStandardCXXIncludes(true), UseLibcxx(false),
- Verbose(false) {}
+ HeaderSearchOptions(StringRef _Sysroot = "/")
+ : Sysroot(_Sysroot), DisableModuleHash(0), UseBuiltinIncludes(true),
+ UseStandardSystemIncludes(true), UseStandardCXXIncludes(true),
+ UseLibcxx(false), Verbose(false) {}
/// AddPath - Add the \arg Path path to the specified \arg Group list.
- void AddPath(llvm::StringRef Path, frontend::IncludeDirGroup Group,
+ void AddPath(StringRef Path, frontend::IncludeDirGroup Group,
bool IsUserSupplied, bool IsFramework, bool IgnoreSysRoot) {
UserEntries.push_back(Entry(Path, Group, IsUserSupplied, IsFramework,
IgnoreSysRoot));
diff --git a/include/clang/Frontend/LangStandard.h b/include/clang/Frontend/LangStandard.h
index ea37bdd1022b..de2800cd73c9 100644
--- a/include/clang/Frontend/LangStandard.h
+++ b/include/clang/Frontend/LangStandard.h
@@ -10,6 +10,7 @@
#ifndef LLVM_CLANG_FRONTEND_LANGSTANDARD_H
#define LLVM_CLANG_FRONTEND_LANGSTANDARD_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringRef.h"
namespace clang {
@@ -83,7 +84,7 @@ public:
bool hasImplicitInt() const { return Flags & frontend::ImplicitInt; }
static const LangStandard &getLangStandardForKind(Kind K);
- static const LangStandard *getLangStandardForName(llvm::StringRef Name);
+ static const LangStandard *getLangStandardForName(StringRef Name);
};
} // end namespace clang
diff --git a/include/clang/Frontend/LangStandards.def b/include/clang/Frontend/LangStandards.def
index 6055ad51828e..c82290b20d67 100644
--- a/include/clang/Frontend/LangStandards.def
+++ b/include/clang/Frontend/LangStandards.def
@@ -37,6 +37,9 @@ LANGSTANDARD(c94, "iso9899:199409",
LANGSTANDARD(gnu89, "gnu89",
"ISO C 1990 with GNU extensions",
BCPLComment | C89 | Digraphs | GNUMode | ImplicitInt)
+LANGSTANDARD(gnu90, "gnu90",
+ "ISO C 1990 with GNU extensions",
+ BCPLComment | C89 | Digraphs | GNUMode | ImplicitInt)
// C99-ish modes
LANGSTANDARD(c99, "c99",
@@ -75,15 +78,24 @@ LANGSTANDARD(gnu1x, "gnu1x",
LANGSTANDARD(cxx98, "c++98",
"ISO C++ 1998 with amendments",
BCPLComment | CPlusPlus | Digraphs)
+LANGSTANDARD(cxx03, "c++03",
+ "ISO C++ 1998 with amendments",
+ BCPLComment | CPlusPlus | Digraphs)
LANGSTANDARD(gnucxx98, "gnu++98",
- "ISO C++ 1998 with " "amendments and GNU extensions",
+ "ISO C++ 1998 with amendments and GNU extensions",
BCPLComment | CPlusPlus | Digraphs | GNUMode)
LANGSTANDARD(cxx0x, "c++0x",
- "Upcoming ISO C++ 200x with amendments",
+ "ISO C++ 2011 with amendments",
+ BCPLComment | CPlusPlus | CPlusPlus0x | Digraphs)
+LANGSTANDARD(cxx11, "c++11",
+ "ISO C++ 2011 with amendments",
BCPLComment | CPlusPlus | CPlusPlus0x | Digraphs)
LANGSTANDARD(gnucxx0x, "gnu++0x",
- "Upcoming ISO C++ 200x with amendments and GNU extensions",
+ "ISO C++ 2011 with amendments and GNU extensions",
+ BCPLComment | CPlusPlus | CPlusPlus0x | Digraphs | GNUMode)
+LANGSTANDARD(gnucxx11, "gnu++11",
+ "ISO C++ 2011 with amendments and GNU extensions",
BCPLComment | CPlusPlus | CPlusPlus0x | Digraphs | GNUMode)
// OpenCL
diff --git a/include/clang/Frontend/LogDiagnosticPrinter.h b/include/clang/Frontend/LogDiagnosticPrinter.h
index b6fc23ca1f04..4de15f2aed5f 100644
--- a/include/clang/Frontend/LogDiagnosticPrinter.h
+++ b/include/clang/Frontend/LogDiagnosticPrinter.h
@@ -19,7 +19,7 @@ namespace clang {
class DiagnosticOptions;
class LangOptions;
-class LogDiagnosticPrinter : public DiagnosticClient {
+class LogDiagnosticPrinter : public DiagnosticConsumer {
struct DiagEntry {
/// The primary message line of the diagnostic.
std::string Message;
@@ -37,10 +37,10 @@ class LogDiagnosticPrinter : public DiagnosticClient {
unsigned DiagnosticID;
/// The level of the diagnostic.
- Diagnostic::Level DiagnosticLevel;
+ DiagnosticsEngine::Level DiagnosticLevel;
};
- llvm::raw_ostream &OS;
+ raw_ostream &OS;
const LangOptions *LangOpts;
const DiagnosticOptions *DiagOpts;
@@ -48,17 +48,17 @@ class LogDiagnosticPrinter : public DiagnosticClient {
FullSourceLoc LastLoc;
unsigned OwnsOutputStream : 1;
- llvm::SmallVector<DiagEntry, 8> Entries;
+ SmallVector<DiagEntry, 8> Entries;
std::string MainFilename;
std::string DwarfDebugFlags;
public:
- LogDiagnosticPrinter(llvm::raw_ostream &OS, const DiagnosticOptions &Diags,
+ LogDiagnosticPrinter(raw_ostream &OS, const DiagnosticOptions &Diags,
bool OwnsOutputStream = false);
virtual ~LogDiagnosticPrinter();
- void setDwarfDebugFlags(llvm::StringRef Value) {
+ void setDwarfDebugFlags(StringRef Value) {
DwarfDebugFlags = Value;
}
@@ -68,8 +68,10 @@ public:
void EndSourceFile();
- virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
- const DiagnosticInfo &Info);
+ virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info);
+
+ DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const;
};
} // end namespace clang
diff --git a/include/clang/Frontend/PreprocessorOptions.h b/include/clang/Frontend/PreprocessorOptions.h
index 2e16c97e7d43..0ee8cb38744a 100644
--- a/include/clang/Frontend/PreprocessorOptions.h
+++ b/include/clang/Frontend/PreprocessorOptions.h
@@ -50,6 +50,10 @@ public:
/// record of all macro definitions and
/// expansions.
+ /// \brief Whether we should automatically translate #include or #import
+ /// operations into module imports when possible.
+ unsigned AutoModuleImport : 1;
+
/// \brief Whether the detailed preprocessing record includes nested macro
/// expansions.
unsigned DetailedRecordIncludesNestedMacroExpansions : 1;
@@ -117,6 +121,14 @@ public:
/// by providing appropriate definitions to retrofit the standard library
/// 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;
typedef std::vector<std::pair<std::string, std::string> >::iterator
remapped_file_iterator;
@@ -154,6 +166,7 @@ public:
public:
PreprocessorOptions() : UsePredefines(true), DetailedRecord(false),
+ AutoModuleImport(false),
DetailedRecordIncludesNestedMacroExpansions(true),
DisablePCHValidation(false), DisableStatCache(false),
DumpDeserializedPCHDecls(false),
@@ -162,13 +175,13 @@ public:
RetainRemappedFileBuffers(false),
ObjCXXARCStandardLibrary(ARCXX_nolib) { }
- void addMacroDef(llvm::StringRef Name) {
+ void addMacroDef(StringRef Name) {
Macros.push_back(std::make_pair(Name, false));
}
- void addMacroUndef(llvm::StringRef Name) {
+ void addMacroUndef(StringRef Name) {
Macros.push_back(std::make_pair(Name, true));
}
- void addRemappedFile(llvm::StringRef From, llvm::StringRef To) {
+ void addRemappedFile(StringRef From, StringRef To) {
RemappedFiles.push_back(std::make_pair(From, To));
}
@@ -176,7 +189,7 @@ public:
return RemappedFiles.erase(Remapped);
}
- void addRemappedFile(llvm::StringRef From, const llvm::MemoryBuffer * To) {
+ void addRemappedFile(StringRef From, const llvm::MemoryBuffer * To) {
RemappedFileBuffers.push_back(std::make_pair(From, To));
}
@@ -189,6 +202,21 @@ public:
RemappedFiles.clear();
RemappedFileBuffers.clear();
}
+
+ /// \brief Reset any options that are not considered when building a
+ /// module.
+ void resetNonModularOptions() {
+ Includes.clear();
+ MacroIncludes.clear();
+ ChainedIncludes.clear();
+ DumpDeserializedPCHDecls = false;
+ ImplicitPCHInclude.clear();
+ ImplicitPTHInclude.clear();
+ TokenCache.clear();
+ RetainRemappedFileBuffers = true;
+ PrecompiledPreambleBytes.first = 0;
+ PrecompiledPreambleBytes.second = 0;
+ }
};
} // end namespace clang
diff --git a/include/clang/Frontend/TextDiagnosticBuffer.h b/include/clang/Frontend/TextDiagnosticBuffer.h
index 380a1dd224af..6f1c0e8aeaf7 100644
--- a/include/clang/Frontend/TextDiagnosticBuffer.h
+++ b/include/clang/Frontend/TextDiagnosticBuffer.h
@@ -22,7 +22,7 @@ namespace clang {
class Preprocessor;
class SourceManager;
-class TextDiagnosticBuffer : public DiagnosticClient {
+class TextDiagnosticBuffer : public DiagnosticConsumer {
public:
typedef std::vector<std::pair<SourceLocation, std::string> > DiagList;
typedef DiagList::iterator iterator;
@@ -39,12 +39,14 @@ public:
const_iterator note_begin() const { return Notes.begin(); }
const_iterator note_end() const { return Notes.end(); }
- virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
- const DiagnosticInfo &Info);
+ virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info);
/// FlushDiagnostics - Flush the buffered diagnostics to an given
/// diagnostic engine.
- void FlushDiagnostics(Diagnostic &Diags) const;
+ void FlushDiagnostics(DiagnosticsEngine &Diags) const;
+
+ virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const;
};
} // end namspace clang
diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h
index 79a9916cb435..22fa18b05027 100644
--- a/include/clang/Frontend/TextDiagnosticPrinter.h
+++ b/include/clang/Frontend/TextDiagnosticPrinter.h
@@ -22,8 +22,8 @@ namespace clang {
class DiagnosticOptions;
class LangOptions;
-class TextDiagnosticPrinter : public DiagnosticClient {
- llvm::raw_ostream &OS;
+class TextDiagnosticPrinter : public DiagnosticConsumer {
+ raw_ostream &OS;
const LangOptions *LangOpts;
const DiagnosticOptions *DiagOpts;
@@ -36,7 +36,7 @@ class TextDiagnosticPrinter : public DiagnosticClient {
std::string Prefix;
public:
- TextDiagnosticPrinter(llvm::raw_ostream &os, const DiagnosticOptions &diags,
+ TextDiagnosticPrinter(raw_ostream &os, const DiagnosticOptions &diags,
bool OwnsOutputStream = false);
virtual ~TextDiagnosticPrinter();
@@ -53,26 +53,19 @@ public:
LangOpts = 0;
}
- void PrintIncludeStack(Diagnostic::Level Level, SourceLocation Loc,
+ void PrintIncludeStack(DiagnosticsEngine::Level Level, SourceLocation Loc,
const SourceManager &SM);
- void HighlightRange(const CharSourceRange &R,
- const SourceManager &SrcMgr,
- unsigned LineNo, FileID FID,
- std::string &CaretLine,
- const std::string &SourceLine);
+ virtual void HandleDiagnostic(DiagnosticsEngine::Level Level,
+ const Diagnostic &Info);
- virtual void HandleDiagnostic(Diagnostic::Level Level,
- const DiagnosticInfo &Info);
+ DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const;
private:
- void EmitCaretDiagnostic(SourceLocation Loc, CharSourceRange *Ranges,
- unsigned NumRanges, const SourceManager &SM,
- const FixItHint *Hints,
- unsigned NumHints, unsigned Columns,
- unsigned OnMacroInst, unsigned MacroSkipStart,
- unsigned MacroSkipEnd);
-
+ void EmitDiagnosticLoc(DiagnosticsEngine::Level Level,
+ const Diagnostic &Info,
+ const SourceManager &SM,
+ PresumedLoc PLoc);
};
} // end namespace clang
diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h
index 93d2c7d501e7..929beb079efe 100644
--- a/include/clang/Frontend/Utils.h
+++ b/include/clang/Frontend/Utils.h
@@ -31,7 +31,7 @@ class CompilerInstance;
class CompilerInvocation;
class Decl;
class DependencyOutputOptions;
-class Diagnostic;
+class DiagnosticsEngine;
class DiagnosticOptions;
class FileManager;
class HeaderSearch;
@@ -48,7 +48,7 @@ class FrontendOptions;
/// Normalize \arg File for use in a user defined #include directive (in the
/// predefines buffer).
-std::string NormalizeDashIncludePath(llvm::StringRef File,
+std::string NormalizeDashIncludePath(StringRef File,
FileManager &FileMgr);
/// Apply the header search options to get given HeaderSearch object.
@@ -66,10 +66,10 @@ void InitializePreprocessor(Preprocessor &PP,
/// ProcessWarningOptions - Initialize the diagnostic client and process the
/// warning options specified on the command line.
-void ProcessWarningOptions(Diagnostic &Diags, const DiagnosticOptions &Opts);
+void ProcessWarningOptions(DiagnosticsEngine &Diags, const DiagnosticOptions &Opts);
/// DoPrintPreprocessedInput - Implement -E mode.
-void DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream* OS,
+void DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream* OS,
const PreprocessorOutputOptions &Opts);
/// AttachDependencyFileGen - Create a dependency file generator, and attach
@@ -87,7 +87,7 @@ void AttachDependencyFileGen(Preprocessor &PP,
/// \param OutputPath - If non-empty, a path to write the header include
/// information to, instead of writing to stderr.
void AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders = false,
- llvm::StringRef OutputPath = "",
+ StringRef OutputPath = "",
bool ShowDepth = true);
/// CacheTokens - Cache tokens for use with PCH. Note that this requires
@@ -100,9 +100,9 @@ void CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS);
/// \return A CompilerInvocation, or 0 if none was built for the given
/// argument vector.
CompilerInvocation *
-createInvocationFromCommandLine(llvm::ArrayRef<const char *> Args,
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags =
- llvm::IntrusiveRefCntPtr<Diagnostic>());
+createInvocationFromCommandLine(ArrayRef<const char *> Args,
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine>());
} // end namespace clang
diff --git a/include/clang/Frontend/VerifyDiagnosticsClient.h b/include/clang/Frontend/VerifyDiagnosticConsumer.h
index 793cedd8578f..28dc9de03af0 100644
--- a/include/clang/Frontend/VerifyDiagnosticsClient.h
+++ b/include/clang/Frontend/VerifyDiagnosticConsumer.h
@@ -1,4 +1,4 @@
-//===-- VerifyDiagnosticsClient.h - Verifying Diagnostic Client -*- C++ -*-===//
+//===- VerifyDiagnosticConsumer.h - Verifying Diagnostic Client -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -15,12 +15,12 @@
namespace clang {
-class Diagnostic;
+class DiagnosticsEngine;
class TextDiagnosticBuffer;
-/// VerifyDiagnosticsClient - Create a diagnostic client which will use markers
-/// in the input source to check that all the emitted diagnostics match those
-/// expected.
+/// VerifyDiagnosticConsumer - Create a diagnostic client which will use
+/// markers in the input source to check that all the emitted diagnostics match
+/// those expected.
///
/// USING THE DIAGNOSTIC CHECKER:
///
@@ -62,31 +62,34 @@ class TextDiagnosticBuffer;
/// // expected-error-re {{variable has has type 'struct (.*)'}}
/// // expected-error-re {{variable has has type 'struct[[:space:]](.*)'}}
///
-class VerifyDiagnosticsClient : public DiagnosticClient {
+class VerifyDiagnosticConsumer: public DiagnosticConsumer {
public:
- Diagnostic &Diags;
- llvm::OwningPtr<DiagnosticClient> PrimaryClient;
+ DiagnosticsEngine &Diags;
+ DiagnosticConsumer *PrimaryClient;
+ bool OwnsPrimaryClient;
llvm::OwningPtr<TextDiagnosticBuffer> Buffer;
Preprocessor *CurrentPreprocessor;
private:
+ FileID FirstErrorFID; // FileID of first diagnostic
void CheckDiagnostics();
public:
/// Create a new verifying diagnostic client, which will issue errors to \arg
- /// PrimaryClient when a diagnostic does not match what is expected (as
- /// indicated in the source file). The verifying diagnostic client takes
- /// ownership of \arg PrimaryClient.
- VerifyDiagnosticsClient(Diagnostic &Diags, DiagnosticClient *PrimaryClient);
- ~VerifyDiagnosticsClient();
+ /// the currently-attached diagnostic client when a diagnostic does not match
+ /// what is expected (as indicated in the source file).
+ VerifyDiagnosticConsumer(DiagnosticsEngine &Diags);
+ ~VerifyDiagnosticConsumer();
virtual void BeginSourceFile(const LangOptions &LangOpts,
const Preprocessor *PP);
virtual void EndSourceFile();
- virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
- const DiagnosticInfo &Info);
+ virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info);
+
+ virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const;
};
} // end namspace clang
diff --git a/include/clang/Index/ASTLocation.h b/include/clang/Index/ASTLocation.h
index fc18dae1a20c..7b66e7ea4fe3 100644
--- a/include/clang/Index/ASTLocation.h
+++ b/include/clang/Index/ASTLocation.h
@@ -17,10 +17,6 @@
#include "clang/AST/TypeLoc.h"
#include "llvm/ADT/PointerIntPair.h"
-namespace llvm {
- class raw_ostream;
-}
-
namespace clang {
class Decl;
class Stmt;
@@ -150,7 +146,7 @@ public:
SourceRange getSourceRange() const;
- void print(llvm::raw_ostream &OS) const;
+ void print(raw_ostream &OS) const;
};
/// \brief Like ASTLocation but also contains the TranslationUnit that the
diff --git a/include/clang/Index/CallGraph.h b/include/clang/Index/CallGraph.h
index 336bf47a2efc..38baf0f7537f 100644
--- a/include/clang/Index/CallGraph.h
+++ b/include/clang/Index/CallGraph.h
@@ -94,7 +94,7 @@ public:
Decl *getDecl(CallGraphNode *Node);
- void print(llvm::raw_ostream &os);
+ void print(raw_ostream &os);
void dump();
void ViewCallGraph() const;
diff --git a/include/clang/Index/Entity.h b/include/clang/Index/Entity.h
index 9863963ff217..d104458ec249 100644
--- a/include/clang/Index/Entity.h
+++ b/include/clang/Index/Entity.h
@@ -15,6 +15,7 @@
#ifndef LLVM_CLANG_INDEX_ENTITY_H
#define LLVM_CLANG_INDEX_ENTITY_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
@@ -73,7 +74,7 @@ public:
static Entity get(Decl *D, Program &Prog);
/// \brief Get an Entity associated with a name in the global namespace.
- static Entity get(llvm::StringRef Name, Program &Prog);
+ static Entity get(StringRef Name, Program &Prog);
/// \brief true if the Entity is not visible outside the trasnlation unit.
bool isInternalToTU() const {
diff --git a/include/clang/Index/Handlers.h b/include/clang/Index/Handlers.h
index 655aef901cd1..1e017f8a7c83 100644
--- a/include/clang/Index/Handlers.h
+++ b/include/clang/Index/Handlers.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_INDEX_HANDLERS_H
#define LLVM_CLANG_INDEX_HANDLERS_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/SmallVector.h"
namespace clang {
@@ -61,7 +62,7 @@ public:
template <typename handler_type>
class Storing : public handler_type {
typedef typename handler_type::receiving_type receiving_type;
- typedef llvm::SmallVector<receiving_type, 8> StoreTy;
+ typedef SmallVector<receiving_type, 8> StoreTy;
StoreTy Store;
public:
diff --git a/include/clang/Index/TranslationUnit.h b/include/clang/Index/TranslationUnit.h
index 0099d630f164..ba5d48d37321 100644
--- a/include/clang/Index/TranslationUnit.h
+++ b/include/clang/Index/TranslationUnit.h
@@ -16,7 +16,7 @@
namespace clang {
class ASTContext;
- class Diagnostic;
+ class DiagnosticsEngine;
class Preprocessor;
namespace idx {
@@ -29,7 +29,7 @@ public:
virtual ~TranslationUnit();
virtual ASTContext &getASTContext() = 0;
virtual Preprocessor &getPreprocessor() = 0;
- virtual Diagnostic &getDiagnostic() = 0;
+ virtual DiagnosticsEngine &getDiagnostic() = 0;
virtual DeclReferenceMap &getDeclReferenceMap() = 0;
virtual SelectorMap &getSelectorMap() = 0;
};
diff --git a/include/clang/Lex/CodeCompletionHandler.h b/include/clang/Lex/CodeCompletionHandler.h
index d28a3aa7d630..d876776c927c 100644
--- a/include/clang/Lex/CodeCompletionHandler.h
+++ b/include/clang/Lex/CodeCompletionHandler.h
@@ -52,6 +52,10 @@ public:
/// \brief Callback invoked when performing code completion inside a
/// function-like macro argument.
+ ///
+ /// There will be another callback invocation after the macro arguments are
+ /// parsed, so this callback should generally be used to note that the next
+ /// callback is invoked inside a macro argument.
virtual void CodeCompleteMacroArgument(IdentifierInfo *Macro,
MacroInfo *MacroInfo,
unsigned ArgumentIndex) { }
diff --git a/include/clang/Lex/DirectoryLookup.h b/include/clang/Lex/DirectoryLookup.h
index 1ee6953a12b2..f7da61b0ed71 100644
--- a/include/clang/Lex/DirectoryLookup.h
+++ b/include/clang/Lex/DirectoryLookup.h
@@ -14,12 +14,9 @@
#ifndef LLVM_CLANG_LEX_DIRECTORYLOOKUP_H
#define LLVM_CLANG_LEX_DIRECTORYLOOKUP_H
+#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceManager.h"
-namespace llvm {
- class StringRef;
- template <typename T> class SmallVectorImpl;
-}
namespace clang {
class HeaderMap;
class DirectoryEntry;
@@ -59,21 +56,27 @@ private:
/// 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;
+
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),
- LookupType(isFramework ? LT_Framework : LT_NormalDir) {
+ : DirCharacteristic(DT), UserSupplied(isUser),
+ LookupType(isFramework ? LT_Framework : LT_NormalDir),
+ IsIndexHeaderMap(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)
- : DirCharacteristic(DT), UserSupplied(isUser), LookupType(LT_HeaderMap) {
+ bool isUser, bool isIndexHeaderMap)
+ : DirCharacteristic(DT), UserSupplied(isUser), LookupType(LT_HeaderMap),
+ IsIndexHeaderMap(isIndexHeaderMap) {
u.Map = map;
}
@@ -119,7 +122,11 @@ public:
///
bool isUserSupplied() const { return UserSupplied; }
-
+ /// \brief Whether this header map is building a framework or not.
+ bool isIndexHeaderMap() const {
+ return isHeaderMap() && IsIndexHeaderMap;
+ }
+
/// LookupFile - Lookup the specified file in this search path, returning it
/// if it exists or returning null if not.
///
@@ -133,15 +140,25 @@ public:
/// \param RelativePath If not NULL, will be set to the path relative to
/// SearchPath at which the file was found. This only differs from the
/// Filename for framework includes.
- const FileEntry *LookupFile(llvm::StringRef Filename, HeaderSearch &HS,
- llvm::SmallVectorImpl<char> *SearchPath,
- llvm::SmallVectorImpl<char> *RelativePath) const;
+ ///
+ /// \param BuildingModule The name of the module we're currently building.
+ ///
+ /// \param SuggestedModule If non-null, and the file found is semantically
+ /// part of a known module, this will be set to the name of the module that
+ /// could be imported instead of preprocessing/parsing the file found.
+ const FileEntry *LookupFile(StringRef Filename, HeaderSearch &HS,
+ SmallVectorImpl<char> *SearchPath,
+ SmallVectorImpl<char> *RelativePath,
+ StringRef BuildingModule,
+ StringRef *SuggestedModule) const;
private:
const FileEntry *DoFrameworkLookup(
- llvm::StringRef Filename, HeaderSearch &HS,
- llvm::SmallVectorImpl<char> *SearchPath,
- llvm::SmallVectorImpl<char> *RelativePath) const;
+ StringRef Filename, HeaderSearch &HS,
+ SmallVectorImpl<char> *SearchPath,
+ SmallVectorImpl<char> *RelativePath,
+ StringRef BuildingModule,
+ StringRef *SuggestedModule) const;
};
diff --git a/include/clang/Lex/HeaderMap.h b/include/clang/Lex/HeaderMap.h
index e333840b6a9d..08bc5b64bc12 100644
--- a/include/clang/Lex/HeaderMap.h
+++ b/include/clang/Lex/HeaderMap.h
@@ -14,10 +14,10 @@
#ifndef LLVM_CLANG_LEX_HEADERMAP_H
#define LLVM_CLANG_LEX_HEADERMAP_H
+#include "clang/Basic/LLVM.h"
+
namespace llvm {
class MemoryBuffer;
- class StringRef;
- template <typename T> class SmallVectorImpl;
}
namespace clang {
class FileEntry;
@@ -52,7 +52,7 @@ public:
/// raw path at which the file was found in the file system. For example,
/// for a search path ".." and a filename "../file.h" this would be
/// "../../file.h".
- const FileEntry *LookupFile(llvm::StringRef Filename, FileManager &FM) const;
+ const FileEntry *LookupFile(StringRef Filename, FileManager &FM) const;
/// getFileName - Return the filename of the headermap.
const char *getFileName() const;
diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h
index 5e36d8e60821..84d59f793bbb 100644
--- a/include/clang/Lex/HeaderSearch.h
+++ b/include/clang/Lex/HeaderSearch.h
@@ -16,6 +16,8 @@
#include "clang/Lex/DirectoryLookup.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/Allocator.h"
#include <vector>
namespace clang {
@@ -47,6 +49,15 @@ struct HeaderFileInfo {
/// "resolved", meaning that it was loaded from the external source.
unsigned Resolved : 1;
+ /// \brief Whether this is a header inside a framework that is currently
+ /// being built.
+ ///
+ /// When a framework is being built, the headers have not yet been placed
+ /// into the appropriate framework subdirectories, and therefore are
+ /// provided via a header map. This bit indicates when this is one of
+ /// those framework headers.
+ unsigned IndexHeaderMapHeader : 1;
+
/// NumIncludes - This is the number of times the file has been included
/// already.
unsigned short NumIncludes;
@@ -68,10 +79,14 @@ struct HeaderFileInfo {
/// external storage.
const IdentifierInfo *ControllingMacro;
+ /// \brief If this header came from a framework include, this is the name
+ /// of the framework.
+ StringRef Framework;
+
HeaderFileInfo()
: isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User),
- External(false), Resolved(false), NumIncludes(0), ControllingMacroID(0),
- ControllingMacro(0) {}
+ External(false), Resolved(false), IndexHeaderMapHeader(false),
+ NumIncludes(0), ControllingMacroID(0), ControllingMacro(0) {}
/// \brief Retrieve the controlling macro for this header file, if
/// any.
@@ -114,6 +129,12 @@ class HeaderSearch {
unsigned SystemDirIdx;
bool NoCurDirSearch;
+ /// \brief The path to the module cache.
+ std::string ModuleCachePath;
+
+ /// \brief The name of the module we're building.
+ std::string BuildingModule;
+
/// FileInfo - This contains all of the preprocessor-specific data about files
/// that are included. The vector is indexed by the FileEntry's UID.
///
@@ -125,17 +146,23 @@ class HeaderSearch {
/// and this value doesn't match the current query, the cache has to be
/// ignored. The second value is the entry in SearchDirs that satisfied the
/// query.
- llvm::StringMap<std::pair<unsigned, unsigned> > LookupFileCache;
+ llvm::StringMap<std::pair<unsigned, unsigned>, llvm::BumpPtrAllocator>
+ LookupFileCache;
/// FrameworkMap - This is a collection mapping a framework or subframework
/// name like "Carbon" to the Carbon.framework directory.
- llvm::StringMap<const DirectoryEntry *> FrameworkMap;
+ llvm::StringMap<const DirectoryEntry *, llvm::BumpPtrAllocator>
+ FrameworkMap;
/// HeaderMaps - This is a mapping from FileEntry -> HeaderMap, uniquing
/// headermaps. This vector owns the headermap.
std::vector<std::pair<const FileEntry*, const HeaderMap*> > HeaderMaps;
+ /// \brief Uniqued set of framework names, which is used to track which
+ /// headers were included as framework headers.
+ llvm::StringSet<llvm::BumpPtrAllocator> FrameworkNames;
+
/// \brief Entity used to resolve the identifier IDs of controlling
/// macros into IdentifierInfo pointers, as needed.
ExternalIdentifierLookup *ExternalLookup;
@@ -172,6 +199,13 @@ public:
//LookupFileCache.clear();
}
+ /// \brief Set the path to the module cache and the name of the module
+ /// we're building
+ void configureModules(StringRef CachePath, StringRef BuildingModule) {
+ ModuleCachePath = CachePath;
+ this->BuildingModule = BuildingModule;
+ }
+
/// ClearFileInfo - Forget everything we know about headers so far.
void ClearFileInfo() {
FileInfo.clear();
@@ -211,12 +245,17 @@ public:
/// \param RelativePath If non-null, will be set to the path relative to
/// SearchPath at which the file was found. This only differs from the
/// Filename for framework includes.
- const FileEntry *LookupFile(llvm::StringRef Filename, bool isAngled,
+ ///
+ /// \param SuggestedModule If non-null, and the file found is semantically
+ /// part of a known module, this will be set to the name of the module that
+ /// could be imported instead of preprocessing/parsing the file found.
+ const FileEntry *LookupFile(StringRef Filename, bool isAngled,
const DirectoryLookup *FromDir,
const DirectoryLookup *&CurDir,
const FileEntry *CurFileEnt,
- llvm::SmallVectorImpl<char> *SearchPath,
- llvm::SmallVectorImpl<char> *RelativePath);
+ SmallVectorImpl<char> *SearchPath,
+ SmallVectorImpl<char> *RelativePath,
+ StringRef *SuggestedModule);
/// LookupSubframeworkHeader - Look up a subframework for the specified
/// #include file. For example, if #include'ing <HIToolbox/HIToolbox.h> from
@@ -224,15 +263,15 @@ public:
/// is a subframework within Carbon.framework. If so, return the FileEntry
/// for the designated file, otherwise return null.
const FileEntry *LookupSubframeworkHeader(
- llvm::StringRef Filename,
+ StringRef Filename,
const FileEntry *RelativeFileEnt,
- llvm::SmallVectorImpl<char> *SearchPath,
- llvm::SmallVectorImpl<char> *RelativePath);
+ SmallVectorImpl<char> *SearchPath,
+ SmallVectorImpl<char> *RelativePath);
/// LookupFrameworkCache - Look up the specified framework name in our
/// framework cache, returning the DirectoryEntry it is in if we know,
/// otherwise, return null.
- const DirectoryEntry *&LookupFrameworkCache(llvm::StringRef FWName) {
+ const DirectoryEntry *&LookupFrameworkCache(StringRef FWName) {
return FrameworkMap.GetOrCreateValue(FWName).getValue();
}
@@ -287,6 +326,23 @@ public:
/// FileEntry, uniquing them through the the 'HeaderMaps' datastructure.
const HeaderMap *CreateHeaderMap(const FileEntry *FE);
+ /// \brief Search in the module cache path for a module with the given
+ /// name.
+ ///
+ /// \param If non-NULL, will be set to the module file name we expected to
+ /// find (regardless of whether it was actually found or not).
+ ///
+ /// \param UmbrellaHeader If non-NULL, and no module was found in the module
+ /// cache, this routine will search in the framework paths to determine
+ /// whether a module can be built from an umbrella header. If so, the pointee
+ /// will be set to the path of the umbrella header.
+ ///
+ /// \returns A file describing the named module, if available, or NULL to
+ /// indicate that the module could not be found.
+ const FileEntry *lookupModule(StringRef ModuleName,
+ std::string *ModuleFileName = 0,
+ std::string *UmbrellaHeader = 0);
+
void IncrementFrameworkLookupCount() { ++NumFrameworkLookups; }
typedef std::vector<HeaderFileInfo>::const_iterator header_file_iterator;
@@ -322,7 +378,13 @@ public:
}
search_dir_iterator system_dir_end() const { return SearchDirs.end(); }
+ /// \brief Retrieve a uniqued framework name.
+ StringRef getUniqueFrameworkName(StringRef Framework);
+
void PrintStats();
+
+ size_t getTotalMemory() const;
+
private:
/// getFileInfo - Return the HeaderFileInfo structure for the specified
diff --git a/include/clang/Lex/LexDiagnostic.h b/include/clang/Lex/LexDiagnostic.h
index 7d2eb89c50bc..f454e2309acb 100644
--- a/include/clang/Lex/LexDiagnostic.h
+++ b/include/clang/Lex/LexDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM,
+ SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM,
#define LEXSTART
#include "clang/Basic/DiagnosticLexKinds.inc"
#undef DIAG
diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h
index f4297627e86f..e01427f574d2 100644
--- a/include/clang/Lex/Lexer.h
+++ b/include/clang/Lex/Lexer.h
@@ -21,11 +21,24 @@
#include <cassert>
namespace clang {
-class Diagnostic;
+class DiagnosticsEngine;
class SourceManager;
class Preprocessor;
class DiagnosticBuilder;
+/// ConflictMarkerKind - Kinds of conflict marker which the lexer might be
+/// recovering from.
+enum ConflictMarkerKind {
+ /// Not within a conflict marker.
+ CMK_None,
+ /// A normal or diff3 conflict marker, initiated by at least 7 <s,
+ /// separated by at least 7 =s or |s, and terminated by at least 7 >s.
+ CMK_Normal,
+ /// A Perforce-style conflict marker, initiated by 4 >s, separated by 4 =s,
+ /// and terminated by 4 <s.
+ CMK_Perforce
+};
+
/// Lexer - This provides a simple interface that turns a text buffer into a
/// stream of tokens. This provides no support for file reading or buffering,
/// or buffering/seeking of tokens, only forward lexing is supported. It relies
@@ -37,8 +50,7 @@ class Lexer : public PreprocessorLexer {
const char *BufferEnd; // End of the buffer.
SourceLocation FileLoc; // Location for start of file.
LangOptions Features; // Features enabled by this language (cache).
- bool Is_PragmaLexer : 1; // True if lexer for _Pragma handling.
- bool IsInConflictMarker : 1; // True if in a VCS conflict marker '<<<<<<<'
+ bool Is_PragmaLexer; // True if lexer for _Pragma handling.
//===--------------------------------------------------------------------===//
// Context-specific lexing flags set by the preprocessor.
@@ -66,6 +78,9 @@ class Lexer : public PreprocessorLexer {
// line" flag set on it.
bool IsAtStartOfLine;
+ // CurrentConflictMarkerState - The kind of conflict marker we are handling.
+ ConflictMarkerKind CurrentConflictMarkerState;
+
Lexer(const Lexer&); // DO NOT IMPLEMENT
void operator=(const Lexer&); // DO NOT IMPLEMENT
friend class Preprocessor;
@@ -208,7 +223,7 @@ public:
/// Stringify - Convert the specified string into a C string by escaping '\'
/// and " characters. This does not add surrounding ""'s to the string.
- static void Stringify(llvm::SmallVectorImpl<char> &Str);
+ static void Stringify(SmallVectorImpl<char> &Str);
/// getSpelling - This method is used to get the spelling of a token into a
@@ -244,8 +259,8 @@ public:
/// This method lexes at the expansion depth of the given
/// location and does not jump to the expansion or spelling
/// location.
- static llvm::StringRef getSpelling(SourceLocation loc,
- llvm::SmallVectorImpl<char> &buffer,
+ static StringRef getSpelling(SourceLocation loc,
+ SmallVectorImpl<char> &buffer,
const SourceManager &SourceMgr,
const LangOptions &Features,
bool *invalid = 0);
@@ -322,7 +337,8 @@ public:
/// of the file begins along with a boolean value indicating whether
/// the preamble ends at the beginning of a new line.
static std::pair<unsigned, bool>
- ComputePreamble(const llvm::MemoryBuffer *Buffer, unsigned MaxLines = 0);
+ ComputePreamble(const llvm::MemoryBuffer *Buffer, const LangOptions &Features,
+ unsigned MaxLines = 0);
//===--------------------------------------------------------------------===//
// Internal implementation interfaces.
@@ -456,6 +472,18 @@ public:
/// them), skip over them and return the first non-escaped-newline found,
/// otherwise return P.
static const char *SkipEscapedNewLines(const char *P);
+
+ /// \brief Checks that the given token is the first token that occurs after
+ /// the given location (this excludes comments and whitespace). Returns the
+ /// location immediately after the specified token. If the token is not found
+ /// or the location is inside a macro, the returned source location will be
+ /// invalid.
+ static SourceLocation findLocationAfterToken(SourceLocation loc,
+ tok::TokenKind TKind,
+ const SourceManager &SM,
+ const LangOptions &LangOpts,
+ bool SkipTrailingWhitespaceAndNewLine);
+
private:
/// getCharAndSizeSlowNoWarn - Same as getCharAndSizeSlow, but never emits a
@@ -471,9 +499,13 @@ private:
// Helper functions to lex the remainder of a token of the specific type.
void LexIdentifier (Token &Result, const char *CurPtr);
void LexNumericConstant (Token &Result, const char *CurPtr);
- void LexStringLiteral (Token &Result, const char *CurPtr,bool Wide);
+ void LexStringLiteral (Token &Result, const char *CurPtr,
+ tok::TokenKind Kind);
+ void LexRawStringLiteral (Token &Result, const char *CurPtr,
+ tok::TokenKind Kind);
void LexAngledStringLiteral(Token &Result, const char *CurPtr);
- void LexCharConstant (Token &Result, const char *CurPtr);
+ void LexCharConstant (Token &Result, const char *CurPtr,
+ tok::TokenKind Kind);
bool LexEndOfFile (Token &Result, const char *CurPtr);
bool SkipWhitespace (Token &Result, const char *CurPtr);
@@ -483,6 +515,9 @@ private:
bool IsStartOfConflictMarker(const char *CurPtr);
bool HandleEndOfConflictMarker(const char *CurPtr);
+
+ bool isCodeCompletionPoint(const char *CurPtr) const;
+ void cutOffLexing() { BufferPtr = BufferEnd; }
};
diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h
index 0dbcd6d72d63..b33092c753a8 100644
--- a/include/clang/Lex/LiteralSupport.h
+++ b/include/clang/Lex/LiteralSupport.h
@@ -15,14 +15,16 @@
#ifndef CLANG_LITERALSUPPORT_H
#define CLANG_LITERALSUPPORT_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/DataTypes.h"
+#include "clang/Basic/TokenKinds.h"
#include <cctype>
namespace clang {
-class Diagnostic;
+class DiagnosticsEngine;
class Preprocessor;
class Token;
class SourceLocation;
@@ -123,15 +125,19 @@ private:
/// character literal.
class CharLiteralParser {
uint64_t Value;
- bool IsWide;
+ tok::TokenKind Kind;
bool IsMultiChar;
bool HadError;
public:
CharLiteralParser(const char *begin, const char *end,
- SourceLocation Loc, Preprocessor &PP);
+ SourceLocation Loc, Preprocessor &PP,
+ tok::TokenKind kind);
bool hadError() const { return HadError; }
- bool isWide() const { return IsWide; }
+ bool isAscii() const { return Kind == tok::char_constant; }
+ bool isWide() const { return Kind == tok::wide_char_constant; }
+ bool isUTF16() const { return Kind == tok::utf16_char_constant; }
+ bool isUTF32() const { return Kind == tok::utf32_char_constant; }
bool isMultiChar() const { return IsMultiChar; }
uint64_t getValue() const { return Value; }
};
@@ -143,11 +149,12 @@ class StringLiteralParser {
const SourceManager &SM;
const LangOptions &Features;
const TargetInfo &Target;
- Diagnostic *Diags;
+ DiagnosticsEngine *Diags;
unsigned MaxTokenLength;
unsigned SizeBound;
- unsigned wchar_tByteWidth;
+ unsigned CharByteWidth;
+ tok::TokenKind Kind;
llvm::SmallString<512> ResultBuf;
char *ResultPtr; // cursor
public:
@@ -155,27 +162,24 @@ public:
Preprocessor &PP, bool Complain = true);
StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
const SourceManager &sm, const LangOptions &features,
- const TargetInfo &target, Diagnostic *diags = 0)
+ const TargetInfo &target, DiagnosticsEngine *diags = 0)
: SM(sm), Features(features), Target(target), Diags(diags),
- MaxTokenLength(0), SizeBound(0), wchar_tByteWidth(0),
- ResultPtr(ResultBuf.data()), hadError(false), AnyWide(false), Pascal(false) {
+ MaxTokenLength(0), SizeBound(0), CharByteWidth(0), Kind(tok::unknown),
+ ResultPtr(ResultBuf.data()), hadError(false), Pascal(false) {
init(StringToks, NumStringToks);
}
bool hadError;
- bool AnyWide;
bool Pascal;
- llvm::StringRef GetString() const {
- return llvm::StringRef(ResultBuf.data(), GetStringLength());
+ StringRef GetString() const {
+ return StringRef(ResultBuf.data(), GetStringLength());
}
unsigned GetStringLength() const { return ResultPtr-ResultBuf.data(); }
unsigned GetNumStringChars() const {
- if (AnyWide)
- return GetStringLength() / wchar_tByteWidth;
- return GetStringLength();
+ return GetStringLength() / CharByteWidth;
}
/// getOffsetOfStringByte - This function returns the offset of the
/// specified byte of the string data represented by Token. This handles
@@ -184,9 +188,16 @@ public:
/// If the Diagnostics pointer is non-null, then this will do semantic
/// checking of the string literal and emit errors and warnings.
unsigned getOffsetOfStringByte(const Token &TheTok, unsigned ByteNo) const;
-
+
+ bool isAscii() { return Kind == tok::string_literal; }
+ bool isWide() { return Kind == tok::wide_string_literal; }
+ bool isUTF8() { return Kind == tok::utf8_string_literal; }
+ bool isUTF16() { return Kind == tok::utf16_string_literal; }
+ bool isUTF32() { return Kind == tok::utf32_string_literal; }
+
private:
void init(const Token *StringToks, unsigned NumStringToks);
+ void CopyStringFragment(StringRef Fragment);
};
} // end namespace clang
diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h
index 9e9d7cf500a4..b381e0f25f41 100644
--- a/include/clang/Lex/MacroInfo.h
+++ b/include/clang/Lex/MacroInfo.h
@@ -39,9 +39,14 @@ class MacroInfo {
IdentifierInfo **ArgumentList;
unsigned NumArguments;
+ /// \brief The location at which this macro was exported from its module.
+ ///
+ /// If invalid, this macro has not been explicitly exported.
+ SourceLocation ExportLocation;
+
/// ReplacementTokens - This is the list of tokens that the macro is defined
/// to.
- llvm::SmallVector<Token, 8> ReplacementTokens;
+ SmallVector<Token, 8> ReplacementTokens;
/// \brief Length in characters of the macro definition.
mutable unsigned DefinitionLength;
@@ -68,6 +73,9 @@ class MacroInfo {
/// IsFromAST - 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;
+
private:
//===--------------------------------------------------------------------===//
// State that changes as the macro is used.
@@ -209,6 +217,14 @@ public:
/// setIsFromAST - Set whether this macro was loaded from an AST file.
void setIsFromAST(bool FromAST = true) { IsFromAST = FromAST; }
+ /// \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
/// not yet been used.
bool isUsed() const { return IsUsed; }
@@ -235,7 +251,7 @@ public:
return ReplacementTokens[Tok];
}
- typedef llvm::SmallVector<Token, 8>::const_iterator tokens_iterator;
+ typedef SmallVector<Token, 8>::const_iterator tokens_iterator;
tokens_iterator tokens_begin() const { return ReplacementTokens.begin(); }
tokens_iterator tokens_end() const { return ReplacementTokens.end(); }
bool tokens_empty() const { return ReplacementTokens.empty(); }
@@ -262,6 +278,19 @@ public:
IsDisabled = true;
}
+ /// \brief Set the export location for this macro.
+ void setExportLocation(SourceLocation ExportLoc) {
+ ExportLocation = ExportLoc;
+ }
+
+ /// \brief Determine whether this macro was explicitly exported from its
+ /// module.
+ bool isExported() const { return ExportLocation.isValid(); }
+
+ /// \brief Determine the location where this macro was explicitly exported
+ /// from its module.
+ SourceLocation getExportLocation() { return ExportLocation; }
+
private:
unsigned getDefinitionLengthSlow(SourceManager &SM) const;
};
diff --git a/include/clang/Lex/Makefile b/include/clang/Lex/Makefile
index 9874bcffb3e1..762b9a258758 100644
--- a/include/clang/Lex/Makefile
+++ b/include/clang/Lex/Makefile
@@ -6,8 +6,8 @@ TABLEGEN_INC_FILES_COMMON = 1
include $(CLANG_LEVEL)/Makefile
-$(ObjDir)/AttrSpellings.inc.tmp : $(TD_SRC_DIR)/Attr.td $(TBLGEN) \
+$(ObjDir)/AttrSpellings.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
$(ObjDir)/.dir
$(Echo) "Building Clang attribute spellings with tblgen"
- $(Verb) $(TableGen) -gen-clang-attr-spelling-list -o $(call SYSPATH, $@) \
+ $(Verb) $(ClangTableGen) -gen-clang-attr-spelling-list -o $(call SYSPATH, $@) \
-I $(PROJ_SRC_DIR)/../../ $<
diff --git a/include/clang/Lex/ModuleLoader.h b/include/clang/Lex/ModuleLoader.h
new file mode 100644
index 000000000000..72ec0e3ebc9f
--- /dev/null
+++ b/include/clang/Lex/ModuleLoader.h
@@ -0,0 +1,55 @@
+//===--- ModuleLoader.h - Module Loader 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 ModuleLoader interface, which is responsible for
+// loading named modules.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_LEX_MODULE_LOADER_H
+#define LLVM_CLANG_LEX_MODULE_LOADER_H
+
+#include "clang/Basic/SourceLocation.h"
+
+namespace clang {
+
+class IdentifierInfo;
+
+/// \brief An opaque key that is used to describe the module and can be
+/// interpreted by the module loader itself.
+typedef void *ModuleKey;
+
+/// \brief Abstract interface for a module loader.
+///
+/// This abstract interface describes a module loader, which is responsible
+/// for resolving a module name (e.g., "std") to an actual module file, and
+/// then loading that module.
+class ModuleLoader {
+public:
+ virtual ~ModuleLoader();
+
+ /// \brief Attempt to load the given module.
+ ///
+ /// This routine attempts to load the module described by the given
+ /// parameters.
+ ///
+ /// \param ImportLoc The location of the 'import' keyword.
+ /// \param ModuleName The name of the module to be loaded.
+ /// \param ModuleNameLoc The location of the module name.
+ ///
+ /// \returns If successful, a non-NULL module key describing this module.
+ /// Otherwise, returns NULL to indicate that the module could not be
+ /// loaded.
+ virtual ModuleKey loadModule(SourceLocation ImportLoc,
+ IdentifierInfo &ModuleName,
+ SourceLocation ModuleNameLoc) = 0;
+};
+
+}
+
+#endif
diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h
index a7948153a728..1fc1a05db646 100644
--- a/include/clang/Lex/PPCallbacks.h
+++ b/include/clang/Lex/PPCallbacks.h
@@ -42,8 +42,11 @@ public:
/// EnteringFile indicates whether this is because we are entering a new
/// #include'd file (when true) or whether we're exiting one because we ran
/// off the end (when false).
+ ///
+ /// \param PrevFID the file that was exited if \arg Reason is ExitFile.
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
- SrcMgr::CharacteristicKind FileType) {
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID = FileID()) {
}
/// FileSkipped - This callback is invoked whenever a source file is
@@ -90,12 +93,12 @@ public:
/// file was found. This is equal to FileName except for framework includes.
virtual void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
- llvm::StringRef FileName,
+ StringRef FileName,
bool IsAngled,
const FileEntry *File,
SourceLocation EndLoc,
- llvm::StringRef SearchPath,
- llvm::StringRef RelativePath) {
+ StringRef SearchPath,
+ StringRef RelativePath) {
}
/// EndOfMainFile - This callback is invoked when the end of the main file is
@@ -122,31 +125,32 @@ public:
/// \param Loc The location of the message directive.
/// \param str The text of the message directive.
///
- virtual void PragmaMessage(SourceLocation Loc, llvm::StringRef Str) {
+ virtual void PragmaMessage(SourceLocation Loc, StringRef Str) {
}
/// PragmaDiagnosticPush - This callback is invoked when a
/// #pragma gcc dianostic push directive is read.
virtual void PragmaDiagnosticPush(SourceLocation Loc,
- llvm::StringRef Namespace) {
+ StringRef Namespace) {
}
/// PragmaDiagnosticPop - This callback is invoked when a
/// #pragma gcc dianostic pop directive is read.
virtual void PragmaDiagnosticPop(SourceLocation Loc,
- llvm::StringRef Namespace) {
+ StringRef Namespace) {
}
/// PragmaDiagnostic - This callback is invoked when a
/// #pragma gcc dianostic directive is read.
- virtual void PragmaDiagnostic(SourceLocation Loc, llvm::StringRef Namespace,
- diag::Mapping mapping, llvm::StringRef Str) {
+ virtual void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace,
+ diag::Mapping mapping, StringRef Str) {
}
/// MacroExpands - This is 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 MacroInfo* MI,
+ SourceRange Range) {
}
/// MacroDefined - This hook is called whenever a macro definition is seen.
@@ -157,6 +161,16 @@ public:
/// MI is released immediately following this callback.
virtual void MacroUndefined(const Token &MacroNameTok, const MacroInfo *MI) {
}
+
+ /// Defined - This hook is called whenever the 'defined' operator is seen.
+ virtual void Defined(const Token &MacroNameTok) {
+ }
+
+ /// 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.
+ virtual void SourceRangeSkipped(SourceRange Range) {
+ }
/// If -- This hook is called whenever an #if is seen.
/// \param Range The SourceRange of the expression being tested.
@@ -204,9 +218,10 @@ public:
}
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
- SrcMgr::CharacteristicKind FileType) {
- First->FileChanged(Loc, Reason, FileType);
- Second->FileChanged(Loc, Reason, FileType);
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID) {
+ First->FileChanged(Loc, Reason, FileType, PrevFID);
+ Second->FileChanged(Loc, Reason, FileType, PrevFID);
}
virtual void FileSkipped(const FileEntry &ParentFile,
@@ -218,12 +233,12 @@ public:
virtual void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
- llvm::StringRef FileName,
+ StringRef FileName,
bool IsAngled,
const FileEntry *File,
SourceLocation EndLoc,
- llvm::StringRef SearchPath,
- llvm::StringRef RelativePath) {
+ StringRef SearchPath,
+ StringRef RelativePath) {
First->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, File,
EndLoc, SearchPath, RelativePath);
Second->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, File,
@@ -246,32 +261,33 @@ public:
Second->PragmaComment(Loc, Kind, Str);
}
- virtual void PragmaMessage(SourceLocation Loc, llvm::StringRef Str) {
+ virtual void PragmaMessage(SourceLocation Loc, StringRef Str) {
First->PragmaMessage(Loc, Str);
Second->PragmaMessage(Loc, Str);
}
virtual void PragmaDiagnosticPush(SourceLocation Loc,
- llvm::StringRef Namespace) {
+ StringRef Namespace) {
First->PragmaDiagnosticPush(Loc, Namespace);
Second->PragmaDiagnosticPush(Loc, Namespace);
}
virtual void PragmaDiagnosticPop(SourceLocation Loc,
- llvm::StringRef Namespace) {
+ StringRef Namespace) {
First->PragmaDiagnosticPop(Loc, Namespace);
Second->PragmaDiagnosticPop(Loc, Namespace);
}
- virtual void PragmaDiagnostic(SourceLocation Loc, llvm::StringRef Namespace,
- diag::Mapping mapping, llvm::StringRef Str) {
+ virtual void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace,
+ diag::Mapping mapping, StringRef Str) {
First->PragmaDiagnostic(Loc, Namespace, mapping, Str);
Second->PragmaDiagnostic(Loc, Namespace, mapping, Str);
}
- virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI) {
- First->MacroExpands(MacroNameTok, MI);
- Second->MacroExpands(MacroNameTok, MI);
+ virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI,
+ SourceRange Range) {
+ First->MacroExpands(MacroNameTok, MI, Range);
+ Second->MacroExpands(MacroNameTok, MI, Range);
}
virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) {
@@ -284,6 +300,16 @@ public:
Second->MacroUndefined(MacroNameTok, MI);
}
+ virtual void Defined(const Token &MacroNameTok) {
+ First->Defined(MacroNameTok);
+ Second->Defined(MacroNameTok);
+ }
+
+ virtual void SourceRangeSkipped(SourceRange Range) {
+ First->SourceRangeSkipped(Range);
+ Second->SourceRangeSkipped(Range);
+ }
+
/// If -- This hook is called whenever an #if is seen.
virtual void If(SourceRange Range) {
First->If(Range);
diff --git a/include/clang/Lex/PTHManager.h b/include/clang/Lex/PTHManager.h
index 094b7ef66798..25a49038a863 100644
--- a/include/clang/Lex/PTHManager.h
+++ b/include/clang/Lex/PTHManager.h
@@ -30,7 +30,7 @@ namespace clang {
class FileEntry;
class PTHLexer;
-class Diagnostic;
+class DiagnosticsEngine;
class FileSystemStatCache;
class PTHManager : public IdentifierInfoLookup {
@@ -115,11 +115,11 @@ public:
/// Unlike the version in IdentifierTable, this returns a pointer instead
/// of a reference. If the pointer is NULL then the IdentifierInfo cannot
/// be found.
- IdentifierInfo *get(llvm::StringRef Name);
+ IdentifierInfo *get(StringRef Name);
/// Create - This method creates PTHManager objects. The 'file' argument
/// is the name of the PTH file. This method returns NULL upon failure.
- static PTHManager *Create(const std::string& file, Diagnostic &Diags);
+ static PTHManager *Create(const std::string& file, DiagnosticsEngine &Diags);
void setPreprocessor(Preprocessor *pp) { PP = pp; }
diff --git a/include/clang/Lex/Pragma.h b/include/clang/Lex/Pragma.h
index c6ab35c19c1e..4868811e7036 100644
--- a/include/clang/Lex/Pragma.h
+++ b/include/clang/Lex/Pragma.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_PRAGMA_H
#define LLVM_CLANG_PRAGMA_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include <cassert>
@@ -58,11 +59,11 @@ namespace clang {
class PragmaHandler {
std::string Name;
public:
- explicit PragmaHandler(llvm::StringRef name) : Name(name) {}
+ explicit PragmaHandler(StringRef name) : Name(name) {}
PragmaHandler() {}
virtual ~PragmaHandler();
- llvm::StringRef getName() const { return Name; }
+ StringRef getName() const { return Name; }
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) = 0;
@@ -91,14 +92,14 @@ class PragmaNamespace : public PragmaHandler {
///
llvm::StringMap<PragmaHandler*> Handlers;
public:
- explicit PragmaNamespace(llvm::StringRef Name) : PragmaHandler(Name) {}
+ explicit PragmaNamespace(StringRef Name) : PragmaHandler(Name) {}
virtual ~PragmaNamespace();
/// FindHandler - Check to see if there is already a handler for the
/// specified name. If not, return the handler for the null name if it
/// exists, otherwise return null. If IgnoreNull is true (the default) then
/// the null handler isn't returned on failure to match.
- PragmaHandler *FindHandler(llvm::StringRef Name,
+ PragmaHandler *FindHandler(StringRef Name,
bool IgnoreNull = true) const;
/// AddPragma - Add a pragma to this namespace.
diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h
index b38303a2f40b..53da19e6c296 100644
--- a/include/clang/Lex/PreprocessingRecord.h
+++ b/include/clang/Lex/PreprocessingRecord.h
@@ -16,6 +16,7 @@
#include "clang/Lex/PPCallbacks.h"
#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Allocator.h"
#include <vector>
@@ -43,14 +44,14 @@ namespace clang {
public:
/// \brief The kind of preprocessed entity an object describes.
enum EntityKind {
+ /// \brief Indicates a problem trying to load the preprocessed entity.
+ InvalidKind,
+
/// \brief A macro expansion.
MacroExpansionKind,
- /// \brief A preprocessing directive whose kind is not specified.
- ///
- /// This kind will be used for any preprocessing directive that does not
- /// have a more specific kind within the \c DirectiveKind enumeration.
- PreprocessingDirectiveKind,
+ /// \defgroup Preprocessing directives
+ /// @{
/// \brief A macro definition.
MacroDefinitionKind,
@@ -59,7 +60,9 @@ namespace clang {
/// #import, or \c #include_next.
InclusionDirectiveKind,
- FirstPreprocessingDirective = PreprocessingDirectiveKind,
+ /// @}
+
+ FirstPreprocessingDirective = MacroDefinitionKind,
LastPreprocessingDirective = InclusionDirectiveKind
};
@@ -73,7 +76,9 @@ namespace clang {
protected:
PreprocessedEntity(EntityKind Kind, SourceRange Range)
: Kind(Kind), Range(Range) { }
-
+
+ friend class PreprocessingRecord;
+
public:
/// \brief Retrieve the kind of preprocessed entity stored in this object.
EntityKind getKind() const { return Kind; }
@@ -81,7 +86,11 @@ namespace clang {
/// \brief Retrieve the source range that covers this entire preprocessed
/// entity.
SourceRange getSourceRange() const { return Range; }
-
+
+ /// \brief Returns true if there was a problem loading the preprocessed
+ /// entity.
+ bool isInvalid() const { return Kind == InvalidKind; }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const PreprocessedEntity *) { return true; }
@@ -110,34 +119,6 @@ namespace clang {
void operator delete(void* data) throw();
};
- /// \brief Records the location of a macro expansion.
- class MacroExpansion : public PreprocessedEntity {
- /// \brief The name of the macro being expanded.
- IdentifierInfo *Name;
-
- /// \brief The definition of this macro.
- MacroDefinition *Definition;
-
- public:
- MacroExpansion(IdentifierInfo *Name, SourceRange Range,
- MacroDefinition *Definition)
- : PreprocessedEntity(MacroExpansionKind, Range), Name(Name),
- Definition(Definition) { }
-
- /// \brief The name of the macro being expanded.
- IdentifierInfo *getName() const { return Name; }
-
- /// \brief The definition of the macro being expanded.
- MacroDefinition *getDefinition() const { return Definition; }
-
- // Implement isa/cast/dyncast/etc.
- static bool classof(const PreprocessedEntity *PE) {
- return PE->getKind() == MacroExpansionKind;
- }
- static bool classof(const MacroExpansion *) { return true; }
-
- };
-
/// \brief Records the presence of a preprocessor directive.
class PreprocessingDirective : public PreprocessedEntity {
public:
@@ -156,21 +137,16 @@ namespace clang {
class MacroDefinition : public PreprocessingDirective {
/// \brief The name of the macro being defined.
const IdentifierInfo *Name;
-
- /// \brief The location of the macro name in the macro definition.
- SourceLocation Location;
public:
- explicit MacroDefinition(const IdentifierInfo *Name, SourceLocation Location,
- SourceRange Range)
- : PreprocessingDirective(MacroDefinitionKind, Range), Name(Name),
- Location(Location) { }
+ explicit MacroDefinition(const IdentifierInfo *Name, SourceRange Range)
+ : PreprocessingDirective(MacroDefinitionKind, Range), Name(Name) { }
/// \brief Retrieve the name of the macro being defined.
const IdentifierInfo *getName() const { return Name; }
/// \brief Retrieve the location of the macro name in the definition.
- SourceLocation getLocation() const { return Location; }
+ SourceLocation getLocation() const { return getSourceRange().getBegin(); }
// Implement isa/cast/dyncast/etc.
static bool classof(const PreprocessedEntity *PE) {
@@ -178,6 +154,44 @@ namespace clang {
}
static bool classof(const MacroDefinition *) { return true; }
};
+
+ /// \brief Records the location of a macro expansion.
+ class MacroExpansion : public PreprocessedEntity {
+ /// \brief The definition of this macro or the name of the macro if it is
+ /// a builtin macro.
+ llvm::PointerUnion<IdentifierInfo *, MacroDefinition *> NameOrDef;
+
+ public:
+ MacroExpansion(IdentifierInfo *BuiltinName, SourceRange Range)
+ : PreprocessedEntity(MacroExpansionKind, Range),
+ NameOrDef(BuiltinName) { }
+
+ MacroExpansion(MacroDefinition *Definition, SourceRange Range)
+ : PreprocessedEntity(MacroExpansionKind, Range),
+ NameOrDef(Definition) { }
+
+ /// \brief True if it is a builtin macro.
+ bool isBuiltinMacro() const { return NameOrDef.is<IdentifierInfo *>(); }
+
+ /// \brief The name of the macro being expanded.
+ const IdentifierInfo *getName() const {
+ if (MacroDefinition *Def = getDefinition())
+ return Def->getName();
+ return NameOrDef.get<IdentifierInfo*>();
+ }
+
+ /// \brief The definition of the macro being expanded. May return null if
+ /// this is a builtin macro.
+ MacroDefinition *getDefinition() const {
+ return NameOrDef.dyn_cast<MacroDefinition *>();
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const PreprocessedEntity *PE) {
+ return PE->getKind() == MacroExpansionKind;
+ }
+ static bool classof(const MacroExpansion *) { return true; }
+ };
/// \brief Record the location of an inclusion directive, such as an
/// \c #include or \c #import statement.
@@ -199,7 +213,7 @@ namespace clang {
private:
/// \brief The name of the file that was included, as written in
/// the source.
- llvm::StringRef FileName;
+ StringRef FileName;
/// \brief Whether the file name was in quotation marks; otherwise, it was
/// in angle brackets.
@@ -215,14 +229,14 @@ namespace clang {
public:
InclusionDirective(PreprocessingRecord &PPRec,
- InclusionKind Kind, llvm::StringRef FileName,
+ InclusionKind Kind, StringRef FileName,
bool InQuotes, const FileEntry *File, SourceRange Range);
/// \brief Determine what kind of inclusion directive this is.
InclusionKind getKind() const { return static_cast<InclusionKind>(Kind); }
/// \brief Retrieve the included file name as it was written in the source.
- llvm::StringRef getFileName() const { return FileName; }
+ StringRef getFileName() const { return FileName; }
/// \brief Determine whether the included file name was written in quotes;
/// otherwise, it was written in angle brackets.
@@ -245,19 +259,24 @@ namespace clang {
public:
virtual ~ExternalPreprocessingRecordSource();
- /// \brief Read any preallocated preprocessed entities from the external
- /// source.
- virtual void ReadPreprocessedEntities() = 0;
-
- /// \brief Read the preprocessed entity at the given offset.
- virtual PreprocessedEntity *
- ReadPreprocessedEntityAtOffset(uint64_t Offset) = 0;
+ /// \brief Read a preallocated preprocessed entity from the external source.
+ ///
+ /// \returns null if an error occurred that prevented the preprocessed
+ /// entity from being loaded.
+ virtual PreprocessedEntity *ReadPreprocessedEntity(unsigned Index) = 0;
+
+ /// \brief Returns a pair of [Begin, End) indices of preallocated
+ /// preprocessed entities that \arg Range encompasses.
+ virtual std::pair<unsigned, unsigned>
+ findPreprocessedEntitiesInRange(SourceRange Range) = 0;
};
/// \brief A record of the steps taken while preprocessing a source file,
/// including the various preprocessing directives processed, macros
/// expanded, etc.
class PreprocessingRecord : public PPCallbacks {
+ SourceManager &SourceMgr;
+
/// \brief Whether we should include nested macro expansions in
/// the preprocessing record.
bool IncludeNestedMacroExpansions;
@@ -269,24 +288,64 @@ namespace clang {
/// were seen.
std::vector<PreprocessedEntity *> PreprocessedEntities;
+ /// \brief The set of preprocessed entities in this record that have been
+ /// loaded from external sources.
+ ///
+ /// The entries in this vector are loaded lazily from the external source,
+ /// and are referenced by the iterator using negative indices.
+ std::vector<PreprocessedEntity *> LoadedPreprocessedEntities;
+
+ /// \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
+ /// indicate preprocessed entities introduced by the current preprocessor.
+ /// If M is the number of loaded preprocessed entities, value -M
+ /// corresponds to element 0 in the loaded entities vector, position -M+1
+ /// corresponds to element 1 in the loaded entities vector, etc.
+ typedef int PPEntityID;
+
+ PPEntityID getPPEntityID(unsigned Index, bool isLoaded) const {
+ return isLoaded ? PPEntityID(Index) - LoadedPreprocessedEntities.size()
+ : Index;
+ }
+
/// \brief Mapping from MacroInfo structures to their definitions.
- llvm::DenseMap<const MacroInfo *, MacroDefinition *> MacroDefinitions;
+ llvm::DenseMap<const MacroInfo *, PPEntityID> MacroDefinitions;
/// \brief External source of preprocessed entities.
ExternalPreprocessingRecordSource *ExternalSource;
+
+ /// \brief Retrieve the preprocessed entity at the given ID.
+ PreprocessedEntity *getPreprocessedEntity(PPEntityID PPID);
+
+ /// \brief Retrieve the loaded preprocessed entity at the given index.
+ PreprocessedEntity *getLoadedPreprocessedEntity(unsigned Index);
- /// \brief The number of preallocated entities (that are known to the
- /// external source).
- unsigned NumPreallocatedEntities;
-
- /// \brief Whether we have already loaded all of the preallocated entities.
- mutable bool LoadedPreallocatedEntities;
-
- void MaybeLoadPreallocatedEntities() const ;
+ /// \brief Determine the number of preprocessed entities that were
+ /// loaded (or can be loaded) from an external source.
+ unsigned getNumLoadedPreprocessedEntities() const {
+ return LoadedPreprocessedEntities.size();
+ }
+
+ /// \brief Returns a pair of [Begin, End) indices of local preprocessed
+ /// entities that \arg Range encompasses.
+ std::pair<unsigned, unsigned>
+ findLocalPreprocessedEntitiesInRange(SourceRange Range) const;
+ unsigned findBeginLocalPreprocessedEntity(SourceLocation Loc) const;
+ unsigned findEndLocalPreprocessedEntity(SourceLocation Loc) const;
+
+ /// \brief Allocate space for a new set of loaded preprocessed entities.
+ ///
+ /// \returns The index into the set of loaded preprocessed entities, which
+ /// corresponds to the first newly-allocated entity.
+ unsigned allocateLoadedEntities(unsigned NumEntities);
+
+ /// \brief Register a new macro definition.
+ void RegisterMacroDefinition(MacroInfo *Macro, PPEntityID PPID);
public:
- /// \brief Construct
- explicit PreprocessingRecord(bool IncludeNestedMacroExpansions);
+ /// \brief Construct a new preprocessing record.
+ PreprocessingRecord(SourceManager &SM, bool IncludeNestedMacroExpansions);
/// \brief Allocate memory in the preprocessing record.
void *Allocate(unsigned Size, unsigned Align = 8) {
@@ -295,64 +354,180 @@ namespace clang {
/// \brief Deallocate memory in the preprocessing record.
void Deallocate(void *Ptr) { }
-
- size_t getTotalMemory() const {
- return BumpAlloc.getTotalMemory();
- }
-
+
+ size_t getTotalMemory() const;
+
+ SourceManager &getSourceManager() const { return SourceMgr; }
+
// Iteration over the preprocessed entities.
- typedef std::vector<PreprocessedEntity *>::iterator iterator;
- typedef std::vector<PreprocessedEntity *>::const_iterator const_iterator;
- iterator begin(bool OnlyLocalEntities = false);
- iterator end(bool OnlyLocalEntities = false);
- const_iterator begin(bool OnlyLocalEntities = false) const;
- const_iterator end(bool OnlyLocalEntities = false) const;
+ class iterator {
+ PreprocessingRecord *Self;
+
+ /// \brief Position within the preprocessed entity sequence.
+ ///
+ /// In a complete iteration, the Position field walks the range [-M, N),
+ /// where negative values are used to indicate preprocessed entities
+ /// loaded from the external source while non-negative values are used to
+ /// indicate preprocessed entities introduced by the current preprocessor.
+ /// However, to provide iteration in source order (for, e.g., chained
+ /// precompiled headers), dereferencing the iterator flips the negative
+ /// values (corresponding to loaded entities), so that position -M
+ /// corresponds to element 0 in the loaded entities vector, position -M+1
+ /// corresponds to element 1 in the loaded entities vector, etc. This
+ /// gives us a reasonably efficient, source-order walk.
+ PPEntityID Position;
+
+ public:
+ typedef PreprocessedEntity *value_type;
+ typedef value_type& reference;
+ typedef value_type* pointer;
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef int difference_type;
+
+ iterator() : Self(0), Position(0) { }
+
+ iterator(PreprocessingRecord *Self, int Position)
+ : Self(Self), Position(Position) { }
+
+ value_type operator*() const {
+ return Self->getPreprocessedEntity(Position);
+ }
+
+ value_type operator[](difference_type D) {
+ return *(*this + D);
+ }
+
+ iterator &operator++() {
+ ++Position;
+ return *this;
+ }
+
+ iterator operator++(int) {
+ iterator Prev(*this);
+ ++Position;
+ return Prev;
+ }
+
+ iterator &operator--() {
+ --Position;
+ return *this;
+ }
+
+ iterator operator--(int) {
+ iterator Prev(*this);
+ --Position;
+ return Prev;
+ }
+
+ friend bool operator==(const iterator &X, const iterator &Y) {
+ return X.Position == Y.Position;
+ }
+
+ friend bool operator!=(const iterator &X, const iterator &Y) {
+ return X.Position != Y.Position;
+ }
+
+ friend bool operator<(const iterator &X, const iterator &Y) {
+ return X.Position < Y.Position;
+ }
+
+ friend bool operator>(const iterator &X, const iterator &Y) {
+ return X.Position > Y.Position;
+ }
+
+ friend bool operator<=(const iterator &X, const iterator &Y) {
+ return X.Position < Y.Position;
+ }
+
+ friend bool operator>=(const iterator &X, const iterator &Y) {
+ return X.Position > Y.Position;
+ }
+
+ friend iterator& operator+=(iterator &X, difference_type D) {
+ X.Position += D;
+ return X;
+ }
+
+ friend iterator& operator-=(iterator &X, difference_type D) {
+ X.Position -= D;
+ return X;
+ }
+
+ friend iterator operator+(iterator X, difference_type D) {
+ X.Position += D;
+ return X;
+ }
+
+ friend iterator operator+(difference_type D, iterator X) {
+ X.Position += D;
+ return X;
+ }
+
+ friend difference_type operator-(const iterator &X, const iterator &Y) {
+ return X.Position - Y.Position;
+ }
+
+ friend iterator operator-(iterator X, difference_type D) {
+ X.Position -= D;
+ return X;
+ }
+ };
+ friend class iterator;
+
+ /// \brief Begin iterator for all preprocessed entities.
+ iterator begin() {
+ return iterator(this, -(int)LoadedPreprocessedEntities.size());
+ }
+
+ /// \brief End iterator for all preprocessed entities.
+ iterator end() {
+ return iterator(this, PreprocessedEntities.size());
+ }
+
+ /// \brief Begin iterator for local, non-loaded, preprocessed entities.
+ iterator local_begin() {
+ return iterator(this, 0);
+ }
+
+ /// \brief End iterator for local, non-loaded, preprocessed entities.
+ iterator local_end() {
+ return iterator(this, PreprocessedEntities.size());
+ }
+
+ /// \brief Returns a pair of [Begin, End) iterators of preprocessed entities
+ /// that source range \arg R encompasses.
+ std::pair<iterator, iterator> getPreprocessedEntitiesInRange(SourceRange R);
/// \brief Add a new preprocessed entity to this record.
void addPreprocessedEntity(PreprocessedEntity *Entity);
/// \brief Set the external source for preprocessed entities.
- void SetExternalSource(ExternalPreprocessingRecordSource &Source,
- unsigned NumPreallocatedEntities);
+ void SetExternalSource(ExternalPreprocessingRecordSource &Source);
/// \brief Retrieve the external source for preprocessed entities.
ExternalPreprocessingRecordSource *getExternalSource() const {
return ExternalSource;
}
- unsigned getNumPreallocatedEntities() const {
- return NumPreallocatedEntities;
- }
-
- /// \brief Set the preallocated entry at the given index to the given
- /// preprocessed entity.
- void SetPreallocatedEntity(unsigned Index, PreprocessedEntity *Entity);
-
- /// \brief Register a new macro definition.
- void RegisterMacroDefinition(MacroInfo *Macro, MacroDefinition *MD);
-
- /// \brief Retrieve the preprocessed entity at the given index.
- PreprocessedEntity *getPreprocessedEntity(unsigned Index) {
- assert(Index < PreprocessedEntities.size() &&
- "Out-of-bounds preprocessed entity");
- return PreprocessedEntities[Index];
- }
-
/// \brief Retrieve the macro definition that corresponds to the given
/// \c MacroInfo.
MacroDefinition *findMacroDefinition(const MacroInfo *MI);
-
- virtual void MacroExpands(const Token &Id, const MacroInfo* MI);
+
+ virtual void MacroExpands(const Token &Id, const MacroInfo* MI,
+ SourceRange Range);
virtual void MacroDefined(const Token &Id, const MacroInfo *MI);
virtual void MacroUndefined(const Token &Id, const MacroInfo *MI);
virtual void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
- llvm::StringRef FileName,
+ StringRef FileName,
bool IsAngled,
const FileEntry *File,
SourceLocation EndLoc,
- llvm::StringRef SearchPath,
- llvm::StringRef RelativePath);
+ StringRef SearchPath,
+ StringRef RelativePath);
+
+ friend class ASTReader;
+ friend class ASTWriter;
};
} // end namespace clang
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index f6f3205099a0..8b7743316f9c 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -49,6 +49,7 @@ class PPCallbacks;
class CodeCompletionHandler;
class DirectoryLookup;
class PreprocessingRecord;
+class ModuleLoader;
/// Preprocessor - This object engages in a tight little dance with the lexer to
/// efficiently preprocess tokens. Lexers know only about tokens within a
@@ -56,17 +57,19 @@ class PreprocessingRecord;
/// like the #include stack, token expansion, etc.
///
class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
- Diagnostic *Diags;
- LangOptions Features;
- const TargetInfo &Target;
+ DiagnosticsEngine *Diags;
+ LangOptions &Features;
+ const TargetInfo *Target;
FileManager &FileMgr;
SourceManager &SourceMgr;
ScratchBuffer *ScratchBuf;
HeaderSearch &HeaderInfo;
+ ModuleLoader &TheModuleLoader;
/// \brief External source of macros.
ExternalPreprocessorSource *ExternalSource;
+
/// PTH - An optional PTHManager object used for getting tokens from
/// a token cache rather than lexing the original source file.
llvm::OwningPtr<PTHManager> PTH;
@@ -90,6 +93,7 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
IdentifierInfo *Ident__has_attribute; // __has_attribute
IdentifierInfo *Ident__has_include; // __has_include
IdentifierInfo *Ident__has_include_next; // __has_include_next
+ IdentifierInfo *Ident__has_warning; // __has_warning
SourceLocation DATELoc, TIMELoc;
unsigned CounterValue; // Next __COUNTER__ value.
@@ -102,7 +106,9 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
// State that is set before the preprocessor begins.
bool KeepComments : 1;
bool KeepMacroComments : 1;
-
+ bool SuppressIncludeNotFoundError : 1;
+ bool AutoModuleImport : 1;
+
// State that changes while the preprocessor runs:
bool InMacroArgs : 1; // True if parsing fn macro invocation args.
@@ -145,6 +151,29 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
/// \brief The file that we're performing code-completion for, if any.
const FileEntry *CodeCompletionFile;
+ /// \brief The offset in file for the code-completion point.
+ unsigned CodeCompletionOffset;
+
+ /// \brief The location for the code-completion point. This gets instantiated
+ /// when the CodeCompletionFile gets #include'ed for preprocessing.
+ SourceLocation CodeCompletionLoc;
+
+ /// \brief The start location for the file of the code-completion point.
+ /// This gets instantiated when the CodeCompletionFile gets #include'ed
+ /// for preprocessing.
+ SourceLocation CodeCompletionFileLoc;
+
+ /// \brief The source location of the __import_module__ keyword we just
+ /// lexed, if any.
+ SourceLocation ModuleImportLoc;
+
+ /// \brief The source location of the currently-active
+ /// #pragma clang arc_cf_code_audited begin.
+ SourceLocation PragmaARCCFCodeAuditedLoc;
+
+ /// \brief True if we hit the code-completion point.
+ bool CodeCompletionReached;
+
/// \brief The number of bytes that we will initially skip when entering the
/// main file, which is used when loading a precompiled preamble, along
/// with a flag that indicates whether skipping this number of bytes will
@@ -165,7 +194,7 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
/// if not expanding a macro. This is an alias for either CurLexer or
/// CurPTHLexer.
PreprocessorLexer *CurPPLexer;
-
+
/// CurLookup - The DirectoryLookup structure used to find the current
/// FileEntry, if CurLexer is non-null and if applicable. This allows us to
/// implement #include_next and find directory-specific properties.
@@ -175,20 +204,31 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
/// expanding a macro. One of CurLexer and CurTokenLexer must be null.
llvm::OwningPtr<TokenLexer> CurTokenLexer;
+ /// \brief The kind of lexer we're currently working with.
+ enum CurLexerKind {
+ CLK_Lexer,
+ CLK_PTHLexer,
+ CLK_TokenLexer,
+ CLK_CachingLexer,
+ CLK_LexAfterModuleImport
+ } CurLexerKind;
+
/// IncludeMacroStack - This keeps track of the stack of files currently
/// #included, and macros currently being expanded from, not counting
/// CurLexer/CurTokenLexer.
struct IncludeStackInfo {
+ enum CurLexerKind CurLexerKind;
Lexer *TheLexer;
PTHLexer *ThePTHLexer;
PreprocessorLexer *ThePPLexer;
TokenLexer *TheTokenLexer;
const DirectoryLookup *TheDirLookup;
- IncludeStackInfo(Lexer *L, PTHLexer* P, PreprocessorLexer* PPL,
+ IncludeStackInfo(enum CurLexerKind K, Lexer *L, PTHLexer* P,
+ PreprocessorLexer* PPL,
TokenLexer* TL, const DirectoryLookup *D)
- : TheLexer(L), ThePTHLexer(P), ThePPLexer(PPL), TheTokenLexer(TL),
- TheDirLookup(D) {}
+ : CurLexerKind(K), TheLexer(L), ThePTHLexer(P), ThePPLexer(PPL),
+ TheTokenLexer(TL), TheDirLookup(D) {}
};
std::vector<IncludeStackInfo> IncludeMacroStack;
@@ -220,10 +260,6 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
/// previous macro value.
llvm::DenseMap<IdentifierInfo*, std::vector<MacroInfo*> > PragmaPushMacroInfo;
- /// \brief Expansion source location for the last macro that expanded
- /// to no tokens.
- SourceLocation LastEmptyMacroExpansionLoc;
-
// Various statistics we track for performance analysis.
unsigned NumDirectives, NumIncluded, NumDefined, NumUndefined, NumPragma;
unsigned NumIf, NumElse, NumEndif;
@@ -246,7 +282,7 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
/// Works like a stack; a TokenLexer adds the macro expanded tokens that is
/// going to lex in the cache and when it finishes the tokens are removed
/// from the end of the cache.
- llvm::SmallVector<Token, 16> MacroExpandedTokens;
+ SmallVector<Token, 16> MacroExpandedTokens;
std::vector<std::pair<TokenLexer *, size_t> > MacroExpandingLexersStack;
/// \brief A record of the macro definitions and expansions that
@@ -257,7 +293,7 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
PreprocessingRecord *Record;
private: // Cached tokens state.
- typedef llvm::SmallVector<Token, 1> CachedTokensTy;
+ typedef SmallVector<Token, 1> CachedTokensTy;
/// CachedTokens - Cached tokens are stored here when we do backtracking or
/// lookahead. They are "lexed" by the CachingLex() method.
@@ -291,19 +327,27 @@ private: // Cached tokens state.
MacroInfo *getInfoForMacro(IdentifierInfo *II) const;
public:
- Preprocessor(Diagnostic &diags, const LangOptions &opts,
- const TargetInfo &target,
+ Preprocessor(DiagnosticsEngine &diags, LangOptions &opts,
+ const TargetInfo *target,
SourceManager &SM, HeaderSearch &Headers,
+ ModuleLoader &TheModuleLoader,
IdentifierInfoLookup *IILookup = 0,
- bool OwnsHeaderSearch = false);
+ bool OwnsHeaderSearch = false,
+ bool DelayInitialization = false);
~Preprocessor();
- Diagnostic &getDiagnostics() const { return *Diags; }
- void setDiagnostics(Diagnostic &D) { Diags = &D; }
+ /// \brief Initialize the preprocessor, if the constructor did not already
+ /// perform the initialization.
+ ///
+ /// \param Target Information about the target.
+ void Initialize(const TargetInfo &Target);
+
+ DiagnosticsEngine &getDiagnostics() const { return *Diags; }
+ void setDiagnostics(DiagnosticsEngine &D) { Diags = &D; }
const LangOptions &getLangOptions() const { return Features; }
- const TargetInfo &getTargetInfo() const { return Target; }
+ const TargetInfo &getTargetInfo() const { return *Target; }
FileManager &getFileManager() const { return FileMgr; }
SourceManager &getSourceManager() const { return SourceMgr; }
HeaderSearch &getHeaderSearchInfo() const { return HeaderInfo; }
@@ -325,6 +369,9 @@ public:
return ExternalSource;
}
+ /// \brief Retrieve the module loader associated with this preprocessor.
+ ModuleLoader &getModuleLoader() const { return TheModuleLoader; }
+
/// SetCommentRetentionState - Control whether or not the preprocessor retains
/// comments in output.
void SetCommentRetentionState(bool KeepComments, bool KeepMacroComments) {
@@ -334,6 +381,19 @@ public:
bool getCommentRetentionState() const { return KeepComments; }
+ void SetSuppressIncludeNotFoundError(bool Suppress) {
+ SuppressIncludeNotFoundError = Suppress;
+ }
+
+ bool GetSuppressIncludeNotFoundError() {
+ return SuppressIncludeNotFoundError;
+ }
+
+ /// \brief Specify whether automatic module imports are enabled.
+ void setAutoModuleImport(bool AutoModuleImport = true) {
+ this->AutoModuleImport = AutoModuleImport;
+ }
+
/// isCurrentLexer - Return true if we are lexing directly from the specified
/// lexer.
bool isCurrentLexer(const PreprocessorLexer *L) const {
@@ -380,12 +440,6 @@ public:
macro_iterator macro_begin(bool IncludeExternalMacros = true) const;
macro_iterator macro_end(bool IncludeExternalMacros = true) const;
- /// \brief Expansion source location for the last macro that expanded
- /// to no tokens.
- SourceLocation getLastEmptyMacroExpansionLoc() const {
- return LastEmptyMacroExpansionLoc;
- }
-
const std::string &getPredefines() const { return Predefines; }
/// setPredefines - Set the predefines for this Preprocessor. These
/// predefines are automatically injected when parsing the main file.
@@ -397,25 +451,25 @@ public:
/// pointers is preferred unless the identifier is already available as a
/// string (this avoids allocation and copying of memory to construct an
/// std::string).
- IdentifierInfo *getIdentifierInfo(llvm::StringRef Name) const {
+ IdentifierInfo *getIdentifierInfo(StringRef Name) const {
return &Identifiers.get(Name);
}
/// AddPragmaHandler - Add the specified pragma handler to the preprocessor.
/// If 'Namespace' is non-null, then it is a token required to exist on the
/// pragma line before the pragma string starts, e.g. "STDC" or "GCC".
- void AddPragmaHandler(llvm::StringRef Namespace, PragmaHandler *Handler);
+ void AddPragmaHandler(StringRef Namespace, PragmaHandler *Handler);
void AddPragmaHandler(PragmaHandler *Handler) {
- AddPragmaHandler(llvm::StringRef(), Handler);
+ AddPragmaHandler(StringRef(), Handler);
}
/// RemovePragmaHandler - Remove the specific pragma handler from
/// the preprocessor. If \arg Namespace is non-null, then it should
/// be the namespace that \arg Handler was added to. It is an error
/// to remove a handler that has not been registered.
- void RemovePragmaHandler(llvm::StringRef Namespace, PragmaHandler *Handler);
+ void RemovePragmaHandler(StringRef Namespace, PragmaHandler *Handler);
void RemovePragmaHandler(PragmaHandler *Handler) {
- RemovePragmaHandler(llvm::StringRef(), Handler);
+ RemovePragmaHandler(StringRef(), Handler);
}
/// \brief Add the specified comment handler to the preprocessor.
@@ -524,16 +578,17 @@ public:
/// Lex - To lex a token from the preprocessor, just pull a token from the
/// current lexer or macro object.
void Lex(Token &Result) {
- if (CurLexer)
- CurLexer->Lex(Result);
- else if (CurPTHLexer)
- CurPTHLexer->Lex(Result);
- else if (CurTokenLexer)
- CurTokenLexer->Lex(Result);
- else
- CachingLex(Result);
+ switch (CurLexerKind) {
+ case CLK_Lexer: CurLexer->Lex(Result); break;
+ case CLK_PTHLexer: CurPTHLexer->Lex(Result); break;
+ case CLK_TokenLexer: CurTokenLexer->Lex(Result); break;
+ case CLK_CachingLexer: CachingLex(Result); break;
+ case CLK_LexAfterModuleImport: LexAfterModuleImport(Result); break;
+ }
}
+ void LexAfterModuleImport(Token &Result);
+
/// 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.
@@ -556,6 +611,14 @@ public:
DisableMacroExpansion = OldVal;
}
+ /// LexUnexpandedNonComment - Like LexNonComment, but this disables macro
+ /// expansion of identifier tokens.
+ void LexUnexpandedNonComment(Token &Result) {
+ do
+ LexUnexpandedToken(Result);
+ while (Result.getKind() == tok::comment);
+ }
+
/// LookAhead - This peeks ahead N tokens and returns that token without
/// consuming any tokens. LookAhead(0) returns the next token that would be
/// returned by Lex(), LookAhead(1) returns the token after it, etc. This
@@ -635,13 +698,46 @@ public:
bool SetCodeCompletionPoint(const FileEntry *File,
unsigned Line, unsigned Column);
- /// \brief Determine if this source location refers into the file
- /// for which we are performing code completion.
- bool isCodeCompletionFile(SourceLocation FileLoc) const;
-
/// \brief Determine if we are performing code completion.
bool isCodeCompletionEnabled() const { return CodeCompletionFile != 0; }
+ /// \brief Returns the location of the code-completion point.
+ /// Returns an invalid location if code-completion is not enabled or the file
+ /// containing the code-completion point has not been lexed yet.
+ SourceLocation getCodeCompletionLoc() const { return CodeCompletionLoc; }
+
+ /// \brief Returns the start location of the file of code-completion point.
+ /// Returns an invalid location if code-completion is not enabled or the file
+ /// containing the code-completion point has not been lexed yet.
+ SourceLocation getCodeCompletionFileLoc() const {
+ return CodeCompletionFileLoc;
+ }
+
+ /// \brief Returns true if code-completion is enabled and we have hit the
+ /// code-completion point.
+ bool isCodeCompletionReached() const { return CodeCompletionReached; }
+
+ /// \brief Note that we hit the code-completion point.
+ void setCodeCompletionReached() {
+ assert(isCodeCompletionEnabled() && "Code-completion not enabled!");
+ CodeCompletionReached = true;
+ // Silence any diagnostics that occur after we hit the code-completion.
+ getDiagnostics().setSuppressAllDiagnostics(true);
+ }
+
+ /// \brief The location of the currently-active #pragma clang
+ /// arc_cf_code_audited begin. Returns an invalid location if there
+ /// is no such pragma active.
+ SourceLocation getPragmaARCCFCodeAuditedLoc() const {
+ return PragmaARCCFCodeAuditedLoc;
+ }
+
+ /// \brief Set the location of the currently-active #pragma clang
+ /// arc_cf_code_audited begin. An invalid location ends the pragma.
+ void setPragmaARCCFCodeAuditedLoc(SourceLocation Loc) {
+ PragmaARCCFCodeAuditedLoc = Loc;
+ }
+
/// \brief Instruct the preprocessor to skip part of the main
/// the main source file.
///
@@ -657,11 +753,11 @@ public:
/// Diag - Forwarding function for diagnostics. This emits a diagnostic at
/// the specified Token's location, translating the token's start
/// position in the current buffer into a SourcePosition object for rendering.
- DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) {
+ DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const {
return Diags->Report(Loc, DiagID);
}
- DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID) {
+ DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID) const {
return Diags->Report(Tok.getLocation(), DiagID);
}
@@ -672,8 +768,8 @@ public:
/// \param buffer A buffer which will be used only if the token requires
/// "cleaning", e.g. if it contains trigraphs or escaped newlines
/// \param invalid If non-null, will be set \c true if an error occurs.
- llvm::StringRef getSpelling(SourceLocation loc,
- llvm::SmallVectorImpl<char> &buffer,
+ StringRef getSpelling(SourceLocation loc,
+ SmallVectorImpl<char> &buffer,
bool *invalid = 0) const {
return Lexer::getSpelling(loc, buffer, SourceMgr, Features, invalid);
}
@@ -707,8 +803,8 @@ public:
/// getSpelling - This method is used to get the spelling of a token into a
/// SmallVector. Note that the returned StringRef may not point to the
/// supplied buffer if a copy can be avoided.
- llvm::StringRef getSpelling(const Token &Tok,
- llvm::SmallVectorImpl<char> &Buffer,
+ StringRef getSpelling(const Token &Tok,
+ SmallVectorImpl<char> &Buffer,
bool *Invalid = 0) const;
/// getSpellingOfSingleCharacterNumericConstant - Tok is a numeric constant
@@ -731,8 +827,9 @@ public:
/// CreateString - Plop the specified string into a scratch buffer and set the
/// specified token's location and length to it. If specified, the source
/// location provides a location of the expansion point of the token.
- void CreateString(const char *Buf, unsigned Len,
- Token &Tok, SourceLocation SourceLoc = SourceLocation());
+ void CreateString(const char *Buf, unsigned Len, Token &Tok,
+ SourceLocation ExpansionLocStart = SourceLocation(),
+ SourceLocation ExpansionLocEnd = SourceLocation());
/// \brief Computes the source location just past the end of the
/// token at this source location.
@@ -892,16 +989,17 @@ public:
/// caller is expected to provide a buffer that is large enough to hold the
/// spelling of the filename, but is also expected to handle the case when
/// this method decides to use a different buffer.
- bool GetIncludeFilenameSpelling(SourceLocation Loc,llvm::StringRef &Filename);
+ bool GetIncludeFilenameSpelling(SourceLocation Loc,StringRef &Filename);
/// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
/// return null on failure. isAngled indicates whether the file reference is
/// for system #include's or not (i.e. using <> instead of "").
- const FileEntry *LookupFile(llvm::StringRef Filename,
+ const FileEntry *LookupFile(StringRef Filename,
bool isAngled, const DirectoryLookup *FromDir,
const DirectoryLookup *&CurDir,
- llvm::SmallVectorImpl<char> *SearchPath,
- llvm::SmallVectorImpl<char> *RelativePath);
+ SmallVectorImpl<char> *SearchPath,
+ SmallVectorImpl<char> *RelativePath,
+ StringRef *SuggestedModule);
/// GetCurLookup - The DirectoryLookup structure used to find the current
/// FileEntry, if CurLexer is non-null and if applicable. This allows us to
@@ -932,7 +1030,8 @@ public:
private:
void PushIncludeMacroStack() {
- IncludeMacroStack.push_back(IncludeStackInfo(CurLexer.take(),
+ IncludeMacroStack.push_back(IncludeStackInfo(CurLexerKind,
+ CurLexer.take(),
CurPTHLexer.take(),
CurPPLexer,
CurTokenLexer.take(),
@@ -946,6 +1045,7 @@ private:
CurPPLexer = IncludeMacroStack.back().ThePPLexer;
CurTokenLexer.reset(IncludeMacroStack.back().TheTokenLexer);
CurDirLookup = IncludeMacroStack.back().TheDirLookup;
+ CurLexerKind = IncludeMacroStack.back().CurLexerKind;
IncludeMacroStack.pop_back();
}
@@ -976,7 +1076,8 @@ private:
/// already seen one so a #else directive is a duplicate. When this returns,
/// the caller can lex the first valid token.
void SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
- bool FoundNonSkipPortion, bool FoundElse);
+ bool FoundNonSkipPortion, bool FoundElse,
+ SourceLocation ElseLoc = SourceLocation());
/// PTHSkipExcludedConditionalBlock - A fast PTH version of
/// SkipExcludedConditionalBlock.
@@ -1006,7 +1107,7 @@ private:
/// going to lex in the cache and when it finishes the tokens are removed
/// from the end of the cache.
Token *cacheMacroExpandedTokens(TokenLexer *tokLexer,
- llvm::ArrayRef<Token> tokens);
+ ArrayRef<Token> tokens);
void removeCachedMacroExpandedTokensOfLastLexer();
friend void TokenLexer::ExpandFunctionArguments();
@@ -1081,7 +1182,8 @@ private:
void HandleDigitDirective(Token &Tok);
void HandleUserDiagnosticDirective(Token &Tok, bool isWarning);
void HandleIdentSCCSDirective(Token &Tok);
-
+ void HandleMacroExportDirective(Token &Tok);
+
// File inclusion.
void HandleIncludeDirective(SourceLocation HashLoc,
Token &Tok,
diff --git a/include/clang/Lex/PreprocessorLexer.h b/include/clang/Lex/PreprocessorLexer.h
index 7bf041df974f..e2e30bf87837 100644
--- a/include/clang/Lex/PreprocessorLexer.h
+++ b/include/clang/Lex/PreprocessorLexer.h
@@ -30,6 +30,9 @@ protected:
/// The SourceManager FileID corresponding to the file being lexed.
const FileID FID;
+ /// \brief Number of SLocEntries before lexing the file.
+ unsigned InitialNumSLocEntries;
+
//===--------------------------------------------------------------------===//
// Context-specific lexing flags set by the preprocessor.
//===--------------------------------------------------------------------===//
@@ -61,18 +64,16 @@ protected:
/// ConditionalStack - Information about the set of #if/#ifdef/#ifndef blocks
/// we are currently in.
- llvm::SmallVector<PPConditionalInfo, 4> ConditionalStack;
+ SmallVector<PPConditionalInfo, 4> ConditionalStack;
PreprocessorLexer(const PreprocessorLexer&); // DO NOT IMPLEMENT
void operator=(const PreprocessorLexer&); // DO NOT IMPLEMENT
friend class Preprocessor;
- PreprocessorLexer(Preprocessor *pp, FileID fid)
- : PP(pp), FID(fid), ParsingPreprocessorDirective(false),
- ParsingFilename(false), LexingRawMode(false) {}
+ PreprocessorLexer(Preprocessor *pp, FileID fid);
PreprocessorLexer()
- : PP(0),
+ : PP(0), InitialNumSLocEntries(0),
ParsingPreprocessorDirective(false),
ParsingFilename(false),
LexingRawMode(false) {}
@@ -151,13 +152,18 @@ public:
return FID;
}
+ /// \brief Number of SLocEntries before lexing the file.
+ unsigned getInitialNumSLocEntries() const {
+ return InitialNumSLocEntries;
+ }
+
/// getFileEntry - Return the FileEntry corresponding to this FileID. Like
/// getFileID(), this only works for lexers with attached preprocessors.
const FileEntry *getFileEntry() const;
/// \brief Iterator that traverses the current stack of preprocessor
/// conditional directives (#if/#ifdef/#ifndef).
- typedef llvm::SmallVectorImpl<PPConditionalInfo>::const_iterator
+ typedef SmallVectorImpl<PPConditionalInfo>::const_iterator
conditional_iterator;
conditional_iterator conditional_begin() const {
diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h
index 9cf11d9a64c4..e6dd1607e88b 100644
--- a/include/clang/Lex/Token.h
+++ b/include/clang/Lex/Token.h
@@ -96,7 +96,10 @@ public:
/// constant, string, etc.
bool isLiteral() const {
return is(tok::numeric_constant) || is(tok::char_constant) ||
- is(tok::string_literal) || is(tok::wide_string_literal) ||
+ is(tok::wide_char_constant) || is(tok::utf16_char_constant) ||
+ is(tok::utf32_char_constant) || is(tok::string_literal) ||
+ is(tok::wide_string_literal) || is(tok::utf8_string_literal) ||
+ is(tok::utf16_string_literal) || is(tok::utf32_string_literal) ||
is(tok::angle_string_literal);
}
diff --git a/include/clang/Lex/TokenConcatenation.h b/include/clang/Lex/TokenConcatenation.h
index 094990a6e317..551300f402c2 100644
--- a/include/clang/Lex/TokenConcatenation.h
+++ b/include/clang/Lex/TokenConcatenation.h
@@ -63,12 +63,9 @@ namespace clang {
const Token &Tok) const;
private:
- /// StartsWithL - Return true if the spelling of this token starts with 'L'.
- bool StartsWithL(const Token &Tok) const;
-
- /// IsIdentifierL - Return true if the spelling of this token is literally
- /// 'L'.
- bool IsIdentifierL(const Token &Tok) const;
+ /// IsIdentifierStringPrefix - Return true if the spelling of the token
+ /// is literally 'L', 'u', 'U', or 'u8'.
+ bool IsIdentifierStringPrefix(const Token &Tok) const;
};
} // end clang namespace
diff --git a/include/clang/Lex/TokenLexer.h b/include/clang/Lex/TokenLexer.h
index 45ff8a03442e..1330ad5f3143 100644
--- a/include/clang/Lex/TokenLexer.h
+++ b/include/clang/Lex/TokenLexer.h
@@ -71,8 +71,10 @@ class TokenLexer {
/// "source location address space".
unsigned MacroStartSLocOffset;
- /// \brief FileID/offset of the start of the macro definition.
- std::pair<FileID, unsigned> MacroDefStartInfo;
+ /// \brief Location of the macro definition.
+ SourceLocation MacroDefStart;
+ /// \brief Length of the macro definition.
+ unsigned MacroDefLength;
/// Lexical information about the expansion point of the macro: the identifier
/// that the macro expanded from had these properties.
@@ -169,7 +171,15 @@ private:
/// \brief If \arg loc is a FileID and points inside the current macro
/// definition, returns the appropriate source location pointing at the
/// macro expansion source location entry.
- SourceLocation getMacroExpansionLocation(SourceLocation loc) const;
+ SourceLocation getExpansionLocForMacroDefLoc(SourceLocation loc) const;
+
+ /// \brief Creates SLocEntries and updates the locations of macro argument
+ /// tokens to their new expanded locations.
+ ///
+ /// \param ArgIdSpellLoc the location of the macro argument id inside the
+ /// macro definition.
+ void updateLocForMacroArgTokens(SourceLocation ArgIdSpellLoc,
+ Token *begin_tokens, Token *end_tokens);
};
} // end namespace clang
diff --git a/include/clang/Makefile b/include/clang/Makefile
index a7be0319e5fa..a6f2597cb95a 100644
--- a/include/clang/Makefile
+++ b/include/clang/Makefile
@@ -1,5 +1,5 @@
CLANG_LEVEL := ../..
-DIRS := AST Basic Driver Lex Serialization
+DIRS := AST Basic Driver Lex Parse Serialization
include $(CLANG_LEVEL)/Makefile
diff --git a/include/clang/Parse/CMakeLists.txt b/include/clang/Parse/CMakeLists.txt
new file mode 100644
index 000000000000..d1ff2abfee66
--- /dev/null
+++ b/include/clang/Parse/CMakeLists.txt
@@ -0,0 +1,4 @@
+clang_tablegen(AttrLateParsed.inc -gen-clang-attr-late-parsed-list
+ -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+ SOURCE ../Basic/Attr.td
+ TARGET ClangAttrLateParsed)
diff --git a/include/clang/Parse/Makefile b/include/clang/Parse/Makefile
new file mode 100644
index 000000000000..296892c5b6ed
--- /dev/null
+++ b/include/clang/Parse/Makefile
@@ -0,0 +1,13 @@
+CLANG_LEVEL := ../../..
+TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic
+BUILT_SOURCES = AttrLateParsed.inc
+
+TABLEGEN_INC_FILES_COMMON = 1
+
+include $(CLANG_LEVEL)/Makefile
+
+$(ObjDir)/AttrLateParsed.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
+ $(ObjDir)/.dir
+ $(Echo) "Building Clang attribute late-parsed table with tblgen"
+ $(Verb) $(ClangTableGen) -gen-clang-attr-late-parsed-list -o $(call SYSPATH, $@) \
+ -I $(PROJ_SRC_DIR)/../../ $< \ No newline at end of file
diff --git a/include/clang/Parse/ParseAST.h b/include/clang/Parse/ParseAST.h
index 0d37e21becd3..725387024e1f 100644
--- a/include/clang/Parse/ParseAST.h
+++ b/include/clang/Parse/ParseAST.h
@@ -14,6 +14,8 @@
#ifndef LLVM_CLANG_PARSE_PARSEAST_H
#define LLVM_CLANG_PARSE_PARSEAST_H
+#include "clang/Basic/LangOptions.h"
+
namespace clang {
class Preprocessor;
class ASTConsumer;
@@ -27,15 +29,13 @@ namespace clang {
/// This operation inserts the parsed decls into the translation
/// unit held by Ctx.
///
- /// \param CompleteTranslationUnit When true, the parsed file is
- /// considered to be a complete translation unit, and any
- /// end-of-translation-unit wrapup will be performed.
+ /// \param TUKind The kind of translation unit being parsed.
///
/// \param CompletionConsumer If given, an object to consume code completion
/// results.
void ParseAST(Preprocessor &pp, ASTConsumer *C,
ASTContext &Ctx, bool PrintStats = false,
- bool CompleteTranslationUnit = true,
+ TranslationUnitKind TUKind = TU_Complete,
CodeCompleteConsumer *CompletionConsumer = 0);
/// \brief Parse the main file known to the preprocessor, producing an
diff --git a/include/clang/Parse/ParseDiagnostic.h b/include/clang/Parse/ParseDiagnostic.h
index c50ac92f6e8d..0e76c614152f 100644
--- a/include/clang/Parse/ParseDiagnostic.h
+++ b/include/clang/Parse/ParseDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM,
+ SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM,
#define PARSESTART
#include "clang/Basic/DiagnosticParseKinds.inc"
#undef DIAG
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 8f49ddad2cec..0046f88d260d 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -22,6 +22,7 @@
#include "clang/Sema/DeclSpec.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallVector.h"
#include <stack>
namespace clang {
@@ -42,7 +43,7 @@ class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry {
const Parser &P;
public:
PrettyStackTraceParserEntry(const Parser &p) : P(p) {}
- virtual void print(llvm::raw_ostream &OS) const;
+ virtual void print(raw_ostream &OS) const;
};
/// PrecedenceLevels - These are precedences for the binary/ternary
@@ -98,7 +99,7 @@ class Parser : public CodeCompletionHandler {
/// in the file.
Sema &Actions;
- Diagnostic &Diags;
+ DiagnosticsEngine &Diags;
/// ScopeCache - Cache scopes to reduce malloc traffic.
enum { ScopeCacheSize = 16 };
@@ -120,6 +121,9 @@ class Parser : public CodeCompletionHandler {
IdentifierInfo *Ident_vector;
IdentifierInfo *Ident_pixel;
+ /// Objective-C contextual keywords.
+ mutable IdentifierInfo *Ident_instancetype;
+
/// \brief Identifier for "introduced".
IdentifierInfo *Ident_introduced;
@@ -186,19 +190,15 @@ public:
const Token &getCurToken() const { return Tok; }
Scope *getCurScope() const { return Actions.getCurScope(); }
+
+ Decl *getObjCDeclContext() const { return Actions.getObjCDeclContext(); }
// Type forwarding. All of these are statically 'void*', but they may all be
// different actual classes based on the actions in place.
- typedef Expr ExprTy;
- typedef Stmt StmtTy;
typedef OpaquePtr<DeclGroupRef> DeclGroupPtrTy;
- typedef CXXBaseSpecifier BaseTy;
- typedef CXXCtorInitializer MemInitTy;
- typedef NestedNameSpecifier CXXScopeTy;
- typedef TemplateParameterList TemplateParamsTy;
typedef OpaquePtr<TemplateName> TemplateTy;
- typedef llvm::SmallVector<TemplateParameterList *, 4> TemplateParameterLists;
+ typedef SmallVector<TemplateParameterList *, 4> TemplateParameterLists;
typedef clang::ExprResult ExprResult;
typedef clang::StmtResult StmtResult;
@@ -265,7 +265,10 @@ private:
///
bool isTokenStringLiteral() const {
return Tok.getKind() == tok::string_literal ||
- Tok.getKind() == tok::wide_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;
}
/// \brief Returns true if the current token is a '=' or '==' and
@@ -281,11 +284,10 @@ private:
assert(!isTokenStringLiteral() && !isTokenParen() && !isTokenBracket() &&
!isTokenBrace() &&
"Should consume special tokens with Consume*Token");
- if (Tok.is(tok::code_completion)) {
- CodeCompletionRecovery();
- return ConsumeCodeCompletionToken();
- }
-
+
+ if (Tok.is(tok::code_completion))
+ return handleUnexpectedCodeCompletionToken();
+
PrevTokLocation = Tok.getLocation();
PP.Lex(Tok);
return PrevTokLocation;
@@ -371,10 +373,20 @@ private:
return PrevTokLocation;
}
- ///\ brief When we are consuming a code-completion token within having
+ ///\ brief When we are consuming a code-completion token without having
/// matched specific position in the grammar, provide code-completion results
/// based on context.
- void CodeCompletionRecovery();
+ ///
+ /// \returns the source location of the code-completion token.
+ SourceLocation handleUnexpectedCodeCompletionToken();
+
+ /// \brief Abruptly cut off parsing; mainly used when we have reached the
+ /// code-completion point.
+ void cutOffParsing() {
+ PP.setCodeCompletionReached();
+ // Cut off parsing by acting as if we reached the end-of-file.
+ Tok.setKind(tok::eof);
+ }
/// \brief Handle the annotation token produced for #pragma unused(...)
void HandlePragmaUnused();
@@ -397,6 +409,84 @@ private:
return PP.LookAhead(0);
}
+ /// \brief Tracks information about the current nesting depth of
+ /// opening delimiters of each kind.
+ class DelimiterTracker {
+ private:
+ friend class Parser;
+
+ unsigned Paren, Brace, Square, Less, LLLess;
+ unsigned& get(tok::TokenKind t) {
+ switch (t) {
+ default: llvm_unreachable("Unexpected balanced token");
+ case tok::l_brace: return Brace;
+ case tok::l_paren: return Paren;
+ case tok::l_square: return Square;
+ case tok::less: return Less;
+ case tok::lesslessless: return LLLess;
+ }
+ }
+
+ void push(tok::TokenKind t) {
+ get(t)++;
+ }
+
+ void pop(tok::TokenKind t) {
+ get(t)--;
+ }
+
+ unsigned getDepth(tok::TokenKind t) {
+ return get(t);
+ }
+
+ public:
+ DelimiterTracker() : Paren(0), Brace(0), Square(0), Less(0), LLLess(0) { }
+ };
+
+ /// \brief RAII class that helps handle the parsing of an open/close delimiter
+ /// pair, such as braces { ... } or parentheses ( ... ).
+ class BalancedDelimiterTracker {
+ tok::TokenKind Kind, Close;
+ Parser& P;
+ bool Cleanup;
+ const unsigned MaxDepth;
+ SourceLocation LOpen, LClose;
+
+ void assignClosingDelimiter() {
+ switch (Kind) {
+ default: llvm_unreachable("Unexpected balanced token");
+ case tok::l_brace: Close = tok::r_brace; break;
+ case tok::l_paren: Close = tok::r_paren; break;
+ case tok::l_square: Close = tok::r_square; break;
+ case tok::less: Close = tok::greater; break;
+ case tok::lesslessless: Close = tok::greatergreatergreater; break;
+ }
+ }
+
+ public:
+ BalancedDelimiterTracker(Parser& p, tok::TokenKind k)
+ : Kind(k), P(p), Cleanup(false), MaxDepth(256) {
+ assignClosingDelimiter();
+ }
+
+ ~BalancedDelimiterTracker() {
+ if (Cleanup)
+ P.QuantityTracker.pop(Kind);
+ }
+
+ SourceLocation getOpenLocation() const { return LOpen; }
+ SourceLocation getCloseLocation() const { return LClose; }
+ SourceRange getRange() const { return SourceRange(LOpen, LClose); }
+
+ bool consumeOpen();
+ bool expectAndConsume(unsigned DiagID,
+ const char *Msg = "",
+ tok::TokenKind SkipToTok = tok::unknown);
+ bool consumeClose();
+ };
+
+ DelimiterTracker QuantityTracker;
+
/// getTypeAnnotation - Read a parsed type out of an annotation token.
static ParsedType getTypeAnnotation(Token &Tok) {
return ParsedType::getFromOpaquePtr(Tok.getAnnotationValue());
@@ -424,7 +514,10 @@ private:
Tok.setAnnotationValue(ER.get());
}
- bool TryAnnotateTypeOrScopeToken(bool EnteringContext = false);
+ // If NeedType is true, then TryAnnotateTypeOrScopeToken will try harder to
+ // find a type name by attempting typo correction.
+ bool TryAnnotateTypeOrScopeToken(bool EnteringContext = false,
+ bool NeedType = false);
bool TryAnnotateCXXScopeToken(bool EnteringContext = false);
/// TryAltiVecToken - Check for context-sensitive AltiVec identifier tokens,
@@ -498,9 +591,23 @@ private:
}
};
-
- SourceLocation MatchRHSPunctuation(tok::TokenKind RHSTok,
- SourceLocation LHSLoc);
+ /// ObjCDeclContextSwitch - An object used to switch context from
+ /// an objective-c decl context to its enclosing decl context and
+ /// back.
+ class ObjCDeclContextSwitch {
+ Parser &P;
+ Decl *DC;
+ public:
+ explicit ObjCDeclContextSwitch(Parser &p) : P(p),
+ DC(p.getObjCDeclContext()) {
+ if (DC)
+ P.Actions.ActOnObjCTemporaryExitContainerContext();
+ }
+ ~ObjCDeclContextSwitch() {
+ if (DC)
+ P.Actions.ActOnObjCReenterContainerContext();
+ }
+ };
/// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the
/// input. If so, it is consumed and false is returned.
@@ -630,6 +737,7 @@ private:
virtual void ParseLexedMethodDeclarations();
virtual void ParseLexedMemberInitializers();
virtual void ParseLexedMethodDefs();
+ virtual void ParseLexedAttributes();
};
/// Inner node of the LateParsedDeclaration tree that parses
@@ -642,12 +750,39 @@ private:
virtual void ParseLexedMethodDeclarations();
virtual void ParseLexedMemberInitializers();
virtual void ParseLexedMethodDefs();
+ virtual void ParseLexedAttributes();
private:
Parser *Self;
ParsingClass *Class;
};
+ /// Contains the lexed tokens of an attribute with arguments that
+ /// may reference member variables and so need to be parsed at the
+ /// end of the class declaration after parsing all other member
+ /// member declarations.
+ /// FIXME: Perhaps we should change the name of LateParsedDeclaration to
+ /// LateParsedTokens.
+ struct LateParsedAttribute : public LateParsedDeclaration {
+ Parser *Self;
+ CachedTokens Toks;
+ IdentifierInfo &AttrName;
+ SourceLocation AttrNameLoc;
+ Decl *D;
+
+ explicit LateParsedAttribute(Parser *P, IdentifierInfo &Name,
+ SourceLocation Loc)
+ : Self(P), AttrName(Name), AttrNameLoc(Loc), D(0) {}
+
+ virtual void ParseLexedAttributes();
+
+ void setDecl(Decl *Dec) { D = Dec; }
+ };
+
+ /// A list of late parsed attributes. Used by ParseGNUAttributes.
+ typedef llvm::SmallVector<LateParsedAttribute*, 2> LateParsedAttrList;
+
+
/// Contains the lexed tokens of a member function definition
/// which needs to be parsed at the end of the class declaration
/// after parsing all other member declarations.
@@ -711,7 +846,7 @@ private:
/// have a default argument, but all of the parameters of the
/// method will be stored so that they can be reintroduced into
/// scope at the appropriate times.
- llvm::SmallVector<LateParsedDefaultArgument, 8> DefaultArgs;
+ SmallVector<LateParsedDefaultArgument, 8> DefaultArgs;
};
/// LateParsedMemberInitializer - An initializer for a non-static class data
@@ -738,7 +873,7 @@ private:
/// parsed until after the definition is completed (C++ [class.mem]p2),
/// the method declarations and possibly attached inline definitions
/// will be stored here with the tokens that will be parsed to create those entities.
- typedef llvm::SmallVector<LateParsedDeclaration*, 2> LateParsedDeclarationsContainer;
+ typedef SmallVector<LateParsedDeclaration*, 2> LateParsedDeclarationsContainer;
/// \brief Representation of a class that has been parsed, including
/// any member function declarations or definitions that need to be
@@ -990,16 +1125,21 @@ private:
void DeallocateParsedClasses(ParsingClass *Class);
void PopParsingClass(Sema::ParsingClassState);
- Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
+ Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, AttributeList *AccessAttrs,
+ ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo,
const VirtSpecifiers& VS, ExprResult& Init);
void ParseCXXNonStaticMemberInitializer(Decl *VarD);
+ void ParseLexedAttributes(ParsingClass &Class);
+ void ParseLexedAttribute(LateParsedAttribute &LA);
void ParseLexedMethodDeclarations(ParsingClass &Class);
void ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM);
void ParseLexedMethodDefs(ParsingClass &Class);
void ParseLexedMethodDef(LexedMethod &LM);
void ParseLexedMemberInitializers(ParsingClass &Class);
void ParseLexedMemberInitializer(LateParsedMemberInitializer &MI);
+ Decl *ParseLexedObjCMethodDefs(LexedMethod &LM);
+ bool ConsumeAndStoreFunctionPrologue(CachedTokens &Toks);
bool ConsumeAndStoreUntil(tok::TokenKind T1,
CachedTokens &Toks,
bool StopAtSemi = true,
@@ -1038,29 +1178,31 @@ private:
ExprResult ParseAsmStringLiteral();
// Objective-C External Declarations
- Decl *ParseObjCAtDirectives();
- Decl *ParseObjCAtClassDeclaration(SourceLocation atLoc);
+ Parser::DeclGroupPtrTy ParseObjCAtDirectives();
+ Parser::DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc);
Decl *ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
ParsedAttributes &prefixAttrs);
void ParseObjCClassInstanceVariables(Decl *interfaceDecl,
tok::ObjCKeywordKind visibility,
SourceLocation atLoc);
- bool ParseObjCProtocolReferences(llvm::SmallVectorImpl<Decl *> &P,
- llvm::SmallVectorImpl<SourceLocation> &PLocs,
+ bool ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &P,
+ SmallVectorImpl<SourceLocation> &PLocs,
bool WarnOnDeclarations,
SourceLocation &LAngleLoc,
SourceLocation &EndProtoLoc);
bool ParseObjCProtocolQualifiers(DeclSpec &DS);
- void ParseObjCInterfaceDeclList(Decl *interfaceDecl,
- tok::ObjCKeywordKind contextKey);
+ void ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
+ Decl *CDecl);
Decl *ParseObjCAtProtocolDeclaration(SourceLocation atLoc,
ParsedAttributes &prefixAttrs);
Decl *ObjCImpDecl;
- llvm::SmallVector<Decl *, 4> PendingObjCImpDecl;
+ SmallVector<Decl *, 4> PendingObjCImpDecl;
+ typedef SmallVector<LexedMethod*, 2> LateParsedObjCMethodContainer;
+ LateParsedObjCMethodContainer LateParsedObjCMethods;
Decl *ParseObjCAtImplementationDeclaration(SourceLocation atLoc);
- Decl *ParseObjCAtEndDeclaration(SourceRange atEnd);
+ DeclGroupPtrTy ParseObjCAtEndDeclaration(SourceRange atEnd);
Decl *ParseObjCAtAliasDeclaration(SourceLocation atLoc);
Decl *ParseObjCPropertySynthesize(SourceLocation atLoc);
Decl *ParseObjCPropertyDynamic(SourceLocation atLoc);
@@ -1075,22 +1217,16 @@ private:
bool isTokIdentifier_in() const;
- /// \brief The context in which we are parsing an Objective-C type name.
- enum ObjCTypeNameContext {
- OTN_ResultType,
- OTN_ParameterType
- };
-
- ParsedType ParseObjCTypeName(ObjCDeclSpec &DS, ObjCTypeNameContext Context);
+ ParsedType ParseObjCTypeName(ObjCDeclSpec &DS, Declarator::TheContext Ctx,
+ ParsedAttributes *ParamAttrs);
void ParseObjCMethodRequirement();
- Decl *ParseObjCMethodPrototype(Decl *classOrCat,
+ Decl *ParseObjCMethodPrototype(
tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword,
bool MethodDefinition = true);
Decl *ParseObjCMethodDecl(SourceLocation mLoc, tok::TokenKind mType,
- Decl *classDecl,
tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword,
bool MethodDefinition=true);
- void ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl);
+ void ParseObjCPropertyAttribute(ObjCDeclSpec &DS);
Decl *ParseObjCMethodDefinition();
@@ -1134,12 +1270,12 @@ private:
ParsedType &CastTy,
SourceRange &CastRange);
- typedef llvm::SmallVector<Expr*, 20> ExprListTy;
- typedef llvm::SmallVector<SourceLocation, 20> CommaLocsTy;
+ typedef SmallVector<Expr*, 20> ExprListTy;
+ typedef SmallVector<SourceLocation, 20> CommaLocsTy;
/// ParseExpressionList - Used for C/C++ (argument-)expression-list.
- bool ParseExpressionList(llvm::SmallVectorImpl<Expr*> &Exprs,
- llvm::SmallVectorImpl<SourceLocation> &CommaLocs,
+ bool ParseExpressionList(SmallVectorImpl<Expr*> &Exprs,
+ SmallVectorImpl<SourceLocation> &CommaLocs,
void (Sema::*Completer)(Scope *S,
Expr *Data,
Expr **Args,
@@ -1160,10 +1296,8 @@ private:
SourceLocation &RParenLoc);
ExprResult ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
- ParsedType &CastTy,
- SourceLocation LParenLoc,
- SourceLocation &RParenLoc);
-
+ ParsedType &CastTy,
+ BalancedDelimiterTracker &Tracker);
ExprResult ParseCompoundLiteralExpression(ParsedType Ty,
SourceLocation LParenLoc,
SourceLocation RParenLoc);
@@ -1176,6 +1310,10 @@ private:
// C++ Expressions
ExprResult ParseCXXIdExpression(bool isAddressOfOperand = false);
+ void CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectTypePtr,
+ bool EnteringContext, IdentifierInfo &II,
+ CXXScopeSpec &SS);
+
bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
ParsedType ObjectType,
bool EnteringContext,
@@ -1183,6 +1321,17 @@ private:
bool IsTypename = false);
//===--------------------------------------------------------------------===//
+ // C++0x 5.1.2: Lambda expressions
+
+ // [...] () -> type {...}
+ ExprResult ParseLambdaExpression();
+ ExprResult TryParseLambdaExpression();
+ llvm::Optional<unsigned> ParseLambdaIntroducer(LambdaIntroducer &Intro);
+ bool TryParseLambdaIntroducer(LambdaIntroducer &Intro);
+ ExprResult ParseLambdaExpressionAfterIntroducer(
+ LambdaIntroducer &Intro);
+
+ //===--------------------------------------------------------------------===//
// C++ 5.2p1: C++ Casts
ExprResult ParseCXXCasts();
@@ -1211,19 +1360,19 @@ private:
ExceptionSpecificationType MaybeParseExceptionSpecification(
SourceRange &SpecificationRange,
- llvm::SmallVectorImpl<ParsedType> &DynamicExceptions,
- llvm::SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
+ SmallVectorImpl<ParsedType> &DynamicExceptions,
+ SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
ExprResult &NoexceptExpr);
// EndLoc is filled with the location of the last token of the specification.
ExceptionSpecificationType ParseDynamicExceptionSpecification(
SourceRange &SpecificationRange,
- llvm::SmallVectorImpl<ParsedType> &Exceptions,
- llvm::SmallVectorImpl<SourceRange> &Ranges);
+ SmallVectorImpl<ParsedType> &Exceptions,
+ SmallVectorImpl<SourceRange> &Ranges);
//===--------------------------------------------------------------------===//
// C++0x 8: Function declaration trailing-return-type
- TypeResult ParseTrailingReturnType();
+ TypeResult ParseTrailingReturnType(SourceRange &Range);
//===--------------------------------------------------------------------===//
// C++ 2.13.5: C++ Boolean Literals
@@ -1244,7 +1393,7 @@ private:
//===--------------------------------------------------------------------===//
// C++ 5.3.4 and 5.3.5: C++ new and delete
- bool ParseExpressionListOrTypeId(llvm::SmallVectorImpl<Expr*> &Exprs,
+ bool ParseExpressionListOrTypeId(SmallVectorImpl<Expr*> &Exprs,
Declarator &D);
void ParseDirectNewDeclarator(Declarator &D);
ExprResult ParseCXXNewExpression(bool UseGlobal, SourceLocation Start);
@@ -1332,15 +1481,15 @@ private:
StmtResult ParseBreakStatement(ParsedAttributes &Attr);
StmtResult ParseReturnStatement(ParsedAttributes &Attr);
StmtResult ParseAsmStatement(bool &msAsm);
- StmtResult FuzzyParseMicrosoftAsmStatement(SourceLocation AsmLoc);
+ StmtResult ParseMicrosoftAsmStatement(SourceLocation AsmLoc);
bool ParseMicrosoftIfExistsCondition(bool& Result);
void ParseMicrosoftIfExistsStatement(StmtVector &Stmts);
void ParseMicrosoftIfExistsExternalDeclaration();
void ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType,
AccessSpecifier& CurAS);
-bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
- llvm::SmallVectorImpl<ExprTy *> &Constraints,
- llvm::SmallVectorImpl<ExprTy *> &Exprs);
+ bool ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
+ SmallVectorImpl<Expr *> &Constraints,
+ SmallVectorImpl<Expr *> &Exprs);
//===--------------------------------------------------------------------===//
// C++ 6: Statements and Blocks
@@ -1431,8 +1580,8 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
void ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS = AS_none);
- void ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
- ObjCTypeNameContext Context);
+ void ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
+ Declarator::TheContext Context);
void ParseEnumSpecifier(SourceLocation TagLoc, DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
@@ -1607,7 +1756,6 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
TypeResult ParseTypeName(SourceRange *Range = 0,
Declarator::TheContext Context
= Declarator::TypeNameContext,
- ObjCDeclSpec *objcQuals = 0,
AccessSpecifier AS = AS_none,
Decl **OwnedType = 0);
void ParseBlockId();
@@ -1618,21 +1766,28 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
}
void DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs);
- void MaybeParseGNUAttributes(Declarator &D) {
+ void MaybeParseGNUAttributes(Declarator &D,
+ LateParsedAttrList *LateAttrs = 0) {
if (Tok.is(tok::kw___attribute)) {
ParsedAttributes attrs(AttrFactory);
SourceLocation endLoc;
- ParseGNUAttributes(attrs, &endLoc);
+ ParseGNUAttributes(attrs, &endLoc, LateAttrs);
D.takeAttributes(attrs, endLoc);
}
}
void MaybeParseGNUAttributes(ParsedAttributes &attrs,
- SourceLocation *endLoc = 0) {
+ SourceLocation *endLoc = 0,
+ LateParsedAttrList *LateAttrs = 0) {
if (Tok.is(tok::kw___attribute))
- ParseGNUAttributes(attrs, endLoc);
+ ParseGNUAttributes(attrs, endLoc, LateAttrs);
}
void ParseGNUAttributes(ParsedAttributes &attrs,
- SourceLocation *endLoc = 0);
+ SourceLocation *endLoc = 0,
+ LateParsedAttrList *LateAttrs = 0);
+ void ParseGNUAttributeArgs(IdentifierInfo *AttrName,
+ SourceLocation AttrNameLoc,
+ ParsedAttributes &Attrs,
+ SourceLocation *EndLoc);
void MaybeParseCXX0XAttributes(Declarator &D) {
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
@@ -1655,12 +1810,15 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
ParseCXX0XAttributes(attrs, endLoc);
}
+
+ void ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs,
+ SourceLocation *EndLoc = 0);
void ParseCXX0XAttributes(ParsedAttributesWithRange &attrs,
SourceLocation *EndLoc = 0);
void MaybeParseMicrosoftAttributes(ParsedAttributes &attrs,
SourceLocation *endLoc = 0) {
- if (getLang().Microsoft && Tok.is(tok::l_square))
+ if (getLang().MicrosoftExt && Tok.is(tok::l_square))
ParseMicrosoftAttributes(attrs, endLoc);
}
void ParseMicrosoftAttributes(ParsedAttributes &attrs,
@@ -1677,11 +1835,21 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
ParsedAttributes &attrs,
SourceLocation *endLoc);
+ bool IsThreadSafetyAttribute(llvm::StringRef AttrName);
+ void ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
+ SourceLocation AttrNameLoc,
+ ParsedAttributes &Attrs,
+ SourceLocation *EndLoc);
+
+
void ParseTypeofSpecifier(DeclSpec &DS);
void ParseDecltypeSpecifier(DeclSpec &DS);
void ParseUnderlyingTypeSpecifier(DeclSpec &DS);
-
- ExprResult ParseCXX0XAlignArgument(SourceLocation Start);
+ void ParseAtomicSpecifier(DeclSpec &DS);
+
+ ExprResult ParseAlignArgument(SourceLocation Start);
+ void ParseAlignmentSpecifier(ParsedAttributes &Attrs,
+ SourceLocation *endLoc = 0);
VirtSpecifiers::Specifier isCXX0XVirtSpecifier() const;
void ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS);
@@ -1732,17 +1900,18 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
bool CXX0XAttributesAllowed = true);
void ParseDirectDeclarator(Declarator &D);
void ParseParenDeclarator(Declarator &D);
- void ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
+ void ParseFunctionDeclarator(Declarator &D,
ParsedAttributes &attrs,
+ BalancedDelimiterTracker &Tracker,
bool RequiresArg = false);
bool isFunctionDeclaratorIdentifierList();
void ParseFunctionDeclaratorIdentifierList(
Declarator &D,
- llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo);
+ SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo);
void ParseParameterDeclarationClause(
Declarator &D,
ParsedAttributes &attrs,
- llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo,
+ SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo,
SourceLocation &EllipsisLoc);
void ParseBracketDeclarator(Declarator &D);
@@ -1758,8 +1927,8 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
std::vector<IdentifierInfo*>& Ident,
std::vector<SourceLocation>& NamespaceLoc,
unsigned int index, SourceLocation& InlineLoc,
- SourceLocation& LBrace, ParsedAttributes& attrs,
- SourceLocation& RBraceLoc);
+ ParsedAttributes& attrs,
+ BalancedDelimiterTracker &Tracker);
Decl *ParseLinkage(ParsingDeclSpec &DS, unsigned Context);
Decl *ParseUsingDirectiveOrDeclaration(unsigned Context,
const ParsedTemplateInfo &TemplateInfo,
@@ -1793,7 +1962,7 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
Decl *TagDecl);
ExprResult ParseCXXMemberInitializer(bool IsFunction,
SourceLocation &EqualLoc);
- void ParseCXXClassMemberDeclaration(AccessSpecifier AS,
+ void ParseCXXClassMemberDeclaration(AccessSpecifier AS, AttributeList *Attr,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
ParsingDeclRAIIObject *DiagsFromTParams = 0);
void ParseConstructorInitializer(Decl *ConstructorDecl);
@@ -1829,30 +1998,33 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
// C++ 14.1: Template Parameters [temp.param]
Decl *ParseDeclarationStartingWithTemplate(unsigned Context,
- SourceLocation &DeclEnd,
- AccessSpecifier AS = AS_none);
+ SourceLocation &DeclEnd,
+ AccessSpecifier AS = AS_none,
+ AttributeList *AccessAttrs = 0);
Decl *ParseTemplateDeclarationOrSpecialization(unsigned Context,
- SourceLocation &DeclEnd,
- AccessSpecifier AS);
+ SourceLocation &DeclEnd,
+ AccessSpecifier AS,
+ AttributeList *AccessAttrs);
Decl *ParseSingleDeclarationAfterTemplate(
unsigned Context,
const ParsedTemplateInfo &TemplateInfo,
ParsingDeclRAIIObject &DiagsFromParams,
SourceLocation &DeclEnd,
- AccessSpecifier AS=AS_none);
+ AccessSpecifier AS=AS_none,
+ AttributeList *AccessAttrs = 0);
bool ParseTemplateParameters(unsigned Depth,
- llvm::SmallVectorImpl<Decl*> &TemplateParams,
+ SmallVectorImpl<Decl*> &TemplateParams,
SourceLocation &LAngleLoc,
SourceLocation &RAngleLoc);
bool ParseTemplateParameterList(unsigned Depth,
- llvm::SmallVectorImpl<Decl*> &TemplateParams);
+ SmallVectorImpl<Decl*> &TemplateParams);
bool isStartOfTemplateTypeParameter();
Decl *ParseTemplateParameter(unsigned Depth, unsigned Position);
Decl *ParseTypeParameter(unsigned Depth, unsigned Position);
Decl *ParseTemplateTemplateParameter(unsigned Depth, unsigned Position);
Decl *ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position);
// C++ 14.3: Template arguments [temp.arg]
- typedef llvm::SmallVector<ParsedTemplateArgument, 16> TemplateArgList;
+ typedef SmallVector<ParsedTemplateArgument, 16> TemplateArgList;
bool ParseTemplateIdAfterTemplateName(TemplateTy Template,
SourceLocation TemplateNameLoc,
@@ -1877,6 +2049,10 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
SourceLocation &DeclEnd);
//===--------------------------------------------------------------------===//
+ // Modules
+ DeclGroupPtrTy ParseModuleImport();
+
+ //===--------------------------------------------------------------------===//
// GNU G++: Type Traits [Type-Traits.html in the GCC manual]
ExprResult ParseUnaryTypeTrait();
ExprResult ParseBinaryTypeTrait();
diff --git a/include/clang/Rewrite/ASTConsumers.h b/include/clang/Rewrite/ASTConsumers.h
index b7f642764b22..7a636e536955 100644
--- a/include/clang/Rewrite/ASTConsumers.h
+++ b/include/clang/Rewrite/ASTConsumers.h
@@ -14,29 +14,27 @@
#ifndef REWRITE_ASTCONSUMERS_H
#define REWRITE_ASTCONSUMERS_H
+#include "clang/Basic/LLVM.h"
#include <string>
-namespace llvm {
- class raw_ostream;
-}
namespace clang {
class ASTConsumer;
-class Diagnostic;
+class DiagnosticsEngine;
class LangOptions;
class Preprocessor;
// ObjC rewriter: attempts to rewrite ObjC constructs into pure C code.
// This is considered experimental, and only works with Apple's ObjC runtime.
ASTConsumer *CreateObjCRewriter(const std::string &InFile,
- llvm::raw_ostream *OS,
- Diagnostic &Diags,
+ raw_ostream *OS,
+ DiagnosticsEngine &Diags,
const LangOptions &LOpts,
bool SilenceRewriteMacroWarning);
/// CreateHTMLPrinter - Create an AST consumer which rewrites source code to
/// HTML with syntax highlighting suitable for viewing in a web-browser.
-ASTConsumer *CreateHTMLPrinter(llvm::raw_ostream *OS, Preprocessor &PP,
+ASTConsumer *CreateHTMLPrinter(raw_ostream *OS, Preprocessor &PP,
bool SyntaxHighlight = true,
bool HighlightMacros = true);
diff --git a/include/clang/Rewrite/FixItRewriter.h b/include/clang/Rewrite/FixItRewriter.h
index bab99624ba4a..bf7e7911c977 100644
--- a/include/clang/Rewrite/FixItRewriter.h
+++ b/include/clang/Rewrite/FixItRewriter.h
@@ -19,8 +19,6 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Rewrite/Rewriter.h"
-namespace llvm { class raw_ostream; }
-
namespace clang {
class SourceManager;
@@ -38,9 +36,9 @@ public:
bool FixWhatYouCan;
};
-class FixItRewriter : public DiagnosticClient {
+class FixItRewriter : public DiagnosticConsumer {
/// \brief The diagnostics machinery.
- Diagnostic &Diags;
+ DiagnosticsEngine &Diags;
/// \brief The rewriter used to perform the various code
/// modifications.
@@ -48,7 +46,7 @@ class FixItRewriter : public DiagnosticClient {
/// \brief The diagnostic client that performs the actual formatting
/// of error messages.
- DiagnosticClient *Client;
+ DiagnosticConsumer *Client;
/// \brief Turn an input path into an output path. NULL implies overwriting
/// the original.
@@ -61,7 +59,7 @@ public:
typedef Rewriter::buffer_iterator iterator;
/// \brief Initialize a new fix-it rewriter.
- FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr,
+ FixItRewriter(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
const LangOptions &LangOpts, FixItOptions *FixItOpts);
/// \brief Destroy the fix-it rewriter.
@@ -79,7 +77,7 @@ public:
/// \brief Write a single modified source file.
///
/// \returns true if there was an error, false otherwise.
- bool WriteFixedFile(FileID ID, llvm::raw_ostream &OS);
+ bool WriteFixedFile(FileID ID, raw_ostream &OS);
/// \brief Write the modified source files.
///
@@ -88,17 +86,19 @@ public:
/// IncludeInDiagnosticCounts - This method (whose default implementation
/// returns true) indicates whether the diagnostics handled by this
- /// DiagnosticClient should be included in the number of diagnostics
- /// reported by Diagnostic.
+ /// DiagnosticConsumer should be included in the number of diagnostics
+ /// reported by DiagnosticsEngine.
virtual bool IncludeInDiagnosticCounts() const;
/// HandleDiagnostic - Handle this diagnostic, reporting it to the user or
/// capturing it to a log as needed.
- virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
- const DiagnosticInfo &Info);
+ virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info);
/// \brief Emit a diagnostic via the adapted diagnostic client.
void Diag(SourceLocation Loc, unsigned DiagID);
+
+ DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const;
};
}
diff --git a/include/clang/Rewrite/FrontendActions.h b/include/clang/Rewrite/FrontendActions.h
index 6b33183166f8..f7aeefae7e58 100644
--- a/include/clang/Rewrite/FrontendActions.h
+++ b/include/clang/Rewrite/FrontendActions.h
@@ -23,7 +23,7 @@ class FixItOptions;
class HTMLPrintAction : public ASTFrontendAction {
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile);
+ StringRef InFile);
};
class FixItAction : public ASTFrontendAction {
@@ -32,10 +32,10 @@ protected:
llvm::OwningPtr<FixItOptions> FixItOpts;
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile);
+ StringRef InFile);
virtual bool BeginSourceFileAction(CompilerInstance &CI,
- llvm::StringRef Filename);
+ StringRef Filename);
virtual void EndSourceFileAction();
@@ -49,7 +49,7 @@ public:
class RewriteObjCAction : public ASTFrontendAction {
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile);
+ StringRef InFile);
};
class RewriteMacrosAction : public PreprocessorFrontendAction {
diff --git a/include/clang/Rewrite/Rewriter.h b/include/clang/Rewrite/Rewriter.h
index 676744ada36c..f1358a0c8534 100644
--- a/include/clang/Rewrite/Rewriter.h
+++ b/include/clang/Rewrite/Rewriter.h
@@ -23,8 +23,6 @@
#include <map>
#include <string>
-namespace llvm { class raw_ostream; }
-
namespace clang {
class LangOptions;
class Rewriter;
@@ -54,7 +52,7 @@ public:
iterator end() const { return Buffer.end(); }
unsigned size() const { return Buffer.size(); }
- llvm::raw_ostream &write(llvm::raw_ostream &) const;
+ raw_ostream &write(raw_ostream &) const;
/// RemoveText - Remove the specified text.
void RemoveText(unsigned OrigOffset, unsigned Size,
@@ -64,7 +62,7 @@ public:
/// the buffer is specified relative to the original SourceBuffer. The
/// text is inserted after the specified location.
///
- void InsertText(unsigned OrigOffset, llvm::StringRef Str,
+ void InsertText(unsigned OrigOffset, StringRef Str,
bool InsertAfter = true);
@@ -72,14 +70,14 @@ public:
/// offset in the buffer is specified relative to the original
/// SourceBuffer. The text is inserted before the specified location. This is
/// method is the same as InsertText with "InsertAfter == false".
- void InsertTextBefore(unsigned OrigOffset, llvm::StringRef Str) {
+ void InsertTextBefore(unsigned OrigOffset, StringRef Str) {
InsertText(OrigOffset, Str, false);
}
/// InsertTextAfter - Insert some text at the specified point, where the
/// offset in the buffer is specified relative to the original SourceBuffer.
/// The text is inserted after the specified location.
- void InsertTextAfter(unsigned OrigOffset, llvm::StringRef Str) {
+ void InsertTextAfter(unsigned OrigOffset, StringRef Str) {
InsertText(OrigOffset, Str);
}
@@ -87,7 +85,7 @@ public:
/// buffer with a new string. This is effectively a combined "remove/insert"
/// operation.
void ReplaceText(unsigned OrigOffset, unsigned OrigLength,
- llvm::StringRef NewStr);
+ StringRef NewStr);
private: // Methods only usable by Rewriter.
@@ -156,8 +154,8 @@ public:
SourceMgr = &SM;
LangOpts = &LO;
}
- SourceManager &getSourceMgr() { return *SourceMgr; }
- const LangOptions &getLangOpts() { return *LangOpts; }
+ SourceManager &getSourceMgr() const { return *SourceMgr; }
+ const LangOptions &getLangOpts() const { return *LangOpts; }
/// isRewritable - Return true if this location is a raw file location, which
/// is rewritable. Locations from macros, etc are not rewritable.
@@ -186,7 +184,7 @@ public:
///
/// \param indentNewLines if true new lines in the string are indented
/// using the indentation of the source line in position \arg Loc.
- bool InsertText(SourceLocation Loc, llvm::StringRef Str,
+ bool InsertText(SourceLocation Loc, StringRef Str,
bool InsertAfter = true, bool indentNewLines = false);
/// InsertTextAfter - Insert the specified string at the specified location in
@@ -194,20 +192,20 @@ public:
/// the input location was not rewritable, false otherwise. Text is
/// inserted after any other text that has been previously inserted
/// at the some point (the default behavior for InsertText).
- bool InsertTextAfter(SourceLocation Loc, llvm::StringRef Str) {
+ bool InsertTextAfter(SourceLocation Loc, StringRef Str) {
return InsertText(Loc, Str);
}
/// \brief Insert the specified string after the token in the
/// specified location.
- bool InsertTextAfterToken(SourceLocation Loc, llvm::StringRef Str);
+ bool InsertTextAfterToken(SourceLocation Loc, StringRef Str);
/// InsertText - Insert the specified string at the specified location in the
/// original buffer. This method returns true (and does nothing) if the input
/// location was not rewritable, false otherwise. Text is
/// inserted before any other text that has been previously inserted
/// at the some point.
- bool InsertTextBefore(SourceLocation Loc, llvm::StringRef Str) {
+ bool InsertTextBefore(SourceLocation Loc, StringRef Str) {
return InsertText(Loc, Str, false);
}
@@ -230,12 +228,12 @@ public:
/// buffer with a new string. This is effectively a combined "remove/insert"
/// operation.
bool ReplaceText(SourceLocation Start, unsigned OrigLength,
- llvm::StringRef NewStr);
+ StringRef NewStr);
/// ReplaceText - This method replaces a range of characters in the input
/// buffer with a new string. This is effectively a combined "remove/insert"
/// operation.
- bool ReplaceText(SourceRange range, llvm::StringRef NewStr) {
+ bool ReplaceText(SourceRange range, StringRef NewStr) {
return ReplaceText(range.getBegin(), getRangeSize(range), NewStr);
}
diff --git a/include/clang/Rewrite/Rewriters.h b/include/clang/Rewrite/Rewriters.h
index 669cf8c208ec..203b9bc18b35 100644
--- a/include/clang/Rewrite/Rewriters.h
+++ b/include/clang/Rewrite/Rewriters.h
@@ -14,17 +14,16 @@
#ifndef LLVM_CLANG_REWRITE_REWRITERS_H
#define LLVM_CLANG_REWRITE_REWRITERS_H
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/raw_ostream.h"
+#include "clang/Basic/LLVM.h"
namespace clang {
class Preprocessor;
/// RewriteMacrosInInput - Implement -rewrite-macros mode.
-void RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream* OS);
+void RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS);
/// DoRewriteTest - A simple test for the TokenRewriter class.
-void DoRewriteTest(Preprocessor &PP, llvm::raw_ostream* OS);
+void DoRewriteTest(Preprocessor &PP, raw_ostream *OS);
} // end namespace clang
diff --git a/include/clang/Sema/AnalysisBasedWarnings.h b/include/clang/Sema/AnalysisBasedWarnings.h
index 8e781cd521c2..eeac97332dfb 100644
--- a/include/clang/Sema/AnalysisBasedWarnings.h
+++ b/include/clang/Sema/AnalysisBasedWarnings.h
@@ -37,6 +37,7 @@ public:
// The warnings to run.
unsigned enableCheckFallThrough : 1;
unsigned enableCheckUnreachable : 1;
+ unsigned enableThreadSafetyAnalysis : 1;
public:
Policy();
void disableCheckFallThrough() { enableCheckFallThrough = 0; }
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index 5d2d6c2ec691..bcacf7aa142b 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -56,7 +56,7 @@ private:
IdentifierInfo *AttrName;
IdentifierInfo *ScopeName;
IdentifierInfo *ParmName;
- SourceLocation AttrLoc;
+ SourceRange AttrRange;
SourceLocation ScopeLoc;
SourceLocation ParmLoc;
@@ -73,6 +73,9 @@ private:
/// True if already diagnosed as invalid.
mutable unsigned Invalid : 1;
+ /// True if this attribute was used as a type attribute.
+ mutable unsigned UsedAsTypeAttr : 1;
+
/// True if this has the extra information associated with an
/// availability attribute.
unsigned IsAvailability : 1;
@@ -114,21 +117,22 @@ private:
size_t allocated_size() const;
- AttributeList(IdentifierInfo *attrName, SourceLocation attrLoc,
+ AttributeList(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
IdentifierInfo *parmName, SourceLocation parmLoc,
Expr **args, unsigned numArgs,
bool declspec, bool cxx0x)
: AttrName(attrName), ScopeName(scopeName), ParmName(parmName),
- AttrLoc(attrLoc), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
+ AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
NumArgs(numArgs),
DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), Invalid(false),
- IsAvailability(false), NextInPosition(0), NextInPool(0) {
+ UsedAsTypeAttr(false), IsAvailability(false),
+ NextInPosition(0), NextInPool(0) {
if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(Expr*));
AttrKind = getKind(getName());
}
- AttributeList(IdentifierInfo *attrName, SourceLocation attrLoc,
+ AttributeList(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
IdentifierInfo *parmName, SourceLocation parmLoc,
const AvailabilityChange &introduced,
@@ -137,10 +141,10 @@ private:
SourceLocation unavailable,
bool declspec, bool cxx0x)
: AttrName(attrName), ScopeName(scopeName), ParmName(parmName),
- AttrLoc(attrLoc), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
+ AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
NumArgs(0), DeclspecAttribute(declspec), CXX0XAttribute(cxx0x),
- Invalid(false), IsAvailability(true), UnavailableLoc(unavailable),
- NextInPosition(0), NextInPool(0) {
+ Invalid(false), UsedAsTypeAttr(false), IsAvailability(true),
+ UnavailableLoc(unavailable), NextInPosition(0), NextInPool(0) {
new (&getAvailabilitySlot(IntroducedSlot)) AvailabilityChange(introduced);
new (&getAvailabilitySlot(DeprecatedSlot)) AvailabilityChange(deprecated);
new (&getAvailabilitySlot(ObsoletedSlot)) AvailabilityChange(obsoleted);
@@ -152,6 +156,8 @@ private:
public:
enum Kind { // Please keep this list alphabetized.
+ AT_acquired_after,
+ AT_acquired_before,
AT_address_space,
AT_alias,
AT_aligned,
@@ -164,10 +170,12 @@ public:
AT_blocks,
AT_carries_dependency,
AT_cdecl,
+ AT_cf_audited_transfer, // Clang-specific.
AT_cf_consumed, // Clang-specific.
AT_cf_returns_autoreleased, // Clang-specific.
AT_cf_returns_not_retained, // Clang-specific.
AT_cf_returns_retained, // Clang-specific.
+ AT_cf_unknown_transfer, // Clang-specific.
AT_cleanup,
AT_common,
AT_const,
@@ -178,18 +186,26 @@ public:
AT_device,
AT_dllexport,
AT_dllimport,
+ AT_exclusive_lock_function,
+ AT_exclusive_locks_required,
+ AT_exclusive_trylock_function,
AT_ext_vector_type,
AT_fastcall,
AT_format,
AT_format_arg,
AT_global,
AT_gnu_inline,
+ AT_guarded_by,
+ AT_guarded_var,
AT_host,
AT_IBAction, // Clang-specific.
AT_IBOutlet, // Clang-specific.
AT_IBOutletCollection, // Clang-specific.
AT_init_priority,
AT_launch_bounds,
+ AT_lock_returned,
+ AT_lockable,
+ AT_locks_excluded,
AT_malloc,
AT_may_alias,
AT_mode,
@@ -198,12 +214,14 @@ public:
AT_neon_polyvector_type, // Clang-specific.
AT_neon_vector_type, // Clang-specific.
AT_no_instrument_function,
+ AT_no_thread_safety_analysis,
AT_nocommon,
AT_nodebug,
AT_noinline,
AT_nonnull,
AT_noreturn,
AT_nothrow,
+ AT_ns_bridged, // Clang-specific.
AT_ns_consumed, // Clang-specific.
AT_ns_consumes_self, // Clang-specific.
AT_ns_returns_autoreleased, // Clang-specific.
@@ -215,6 +233,7 @@ public:
AT_objc_method_family,
AT_objc_ownership, // Clang-specific.
AT_objc_precise_lifetime, // Clang-specific.
+ AT_objc_returns_inner_pointer, // Clang-specific.
AT_opencl_image_access, // OpenCL-specific.
AT_opencl_kernel_function, // OpenCL-specific.
AT_overloadable, // Clang-specific.
@@ -224,16 +243,23 @@ public:
AT_packed,
AT_pascal,
AT_pcs, // ARM specific
+ AT_pt_guarded_by,
+ AT_pt_guarded_var,
AT_pure,
AT_regparm,
AT_reqd_wg_size,
+ AT_scoped_lockable,
AT_section,
AT_sentinel,
AT_shared,
+ AT_shared_lock_function,
+ AT_shared_locks_required,
+ AT_shared_trylock_function,
AT_stdcall,
AT_thiscall,
AT_transparent_union,
AT_unavailable,
+ AT_unlock_function,
AT_unused,
AT_used,
AT_uuid,
@@ -244,12 +270,14 @@ public:
AT_weak,
AT_weak_import,
AT_weakref,
+ AT_returns_twice,
IgnoredAttribute,
UnknownAttribute
};
IdentifierInfo *getName() const { return AttrName; }
- SourceLocation getLoc() const { return AttrLoc; }
+ SourceLocation getLoc() const { return AttrRange.getBegin(); }
+ SourceRange getRange() const { return AttrRange; }
bool hasScope() const { return ScopeName; }
IdentifierInfo *getScopeName() const { return ScopeName; }
@@ -264,6 +292,9 @@ public:
bool isInvalid() const { return Invalid; }
void setInvalid(bool b = true) const { Invalid = b; }
+ bool isUsedAsTypeAttr() const { return UsedAsTypeAttr; }
+ void setUsedAsTypeAttr() { UsedAsTypeAttr = true; }
+
Kind getKind() const { return Kind(AttrKind); }
static Kind getKind(const IdentifierInfo *Name);
@@ -373,7 +404,7 @@ private:
/// Free lists. The index is determined by the following formula:
/// (size - sizeof(AttributeList)) / sizeof(void*)
- llvm::SmallVector<AttributeList*, InlineFreeListsCapacity> FreeLists;
+ SmallVector<AttributeList*, InlineFreeListsCapacity> FreeLists;
// The following are the private interface used by AttributePool.
friend class AttributePool;
@@ -440,21 +471,21 @@ public:
if (Head) Factory.reclaimPool(Head);
}
- AttributeList *create(IdentifierInfo *attrName, SourceLocation attrLoc,
+ AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
IdentifierInfo *parmName, SourceLocation parmLoc,
Expr **args, unsigned numArgs,
bool declspec = false, bool cxx0x = false) {
void *memory = allocate(sizeof(AttributeList)
+ numArgs * sizeof(Expr*));
- return add(new (memory) AttributeList(attrName, attrLoc,
+ return add(new (memory) AttributeList(attrName, attrRange,
scopeName, scopeLoc,
parmName, parmLoc,
args, numArgs,
declspec, cxx0x));
}
- AttributeList *create(IdentifierInfo *attrName, SourceLocation attrLoc,
+ AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
IdentifierInfo *parmName, SourceLocation parmLoc,
const AvailabilityChange &introduced,
@@ -463,7 +494,7 @@ public:
SourceLocation unavailable,
bool declspec = false, bool cxx0x = false) {
void *memory = allocate(AttributeFactory::AvailabilityAllocSize);
- return add(new (memory) AttributeList(attrName, attrLoc,
+ return add(new (memory) AttributeList(attrName, attrRange,
scopeName, scopeLoc,
parmName, parmLoc,
introduced, deprecated, obsoleted,
@@ -566,19 +597,19 @@ public:
AttributeList *&getListRef() { return list; }
- AttributeList *addNew(IdentifierInfo *attrName, SourceLocation attrLoc,
+ AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
IdentifierInfo *parmName, SourceLocation parmLoc,
Expr **args, unsigned numArgs,
bool declspec = false, bool cxx0x = false) {
AttributeList *attr =
- pool.create(attrName, attrLoc, scopeName, scopeLoc, parmName, parmLoc,
+ pool.create(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc,
args, numArgs, declspec, cxx0x);
add(attr);
return attr;
}
- AttributeList *addNew(IdentifierInfo *attrName, SourceLocation attrLoc,
+ AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
IdentifierInfo *parmName, SourceLocation parmLoc,
const AvailabilityChange &introduced,
@@ -587,7 +618,7 @@ public:
SourceLocation unavailable,
bool declspec = false, bool cxx0x = false) {
AttributeList *attr =
- pool.create(attrName, attrLoc, scopeName, scopeLoc, parmName, parmLoc,
+ pool.create(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc,
introduced, deprecated, obsoleted, unavailable,
declspec, cxx0x);
add(attr);
diff --git a/include/clang/Sema/CXXFieldCollector.h b/include/clang/Sema/CXXFieldCollector.h
index 63c6ee3f74ba..6f3c0b44b148 100644
--- a/include/clang/Sema/CXXFieldCollector.h
+++ b/include/clang/Sema/CXXFieldCollector.h
@@ -26,12 +26,12 @@ class CXXFieldCollector {
/// Fields - Contains all FieldDecls collected during parsing of a C++
/// class. When a nested class is entered, its fields are appended to the
/// fields of its parent class, when it is exited its fields are removed.
- llvm::SmallVector<FieldDecl*, 32> Fields;
+ SmallVector<FieldDecl*, 32> Fields;
/// FieldCount - Each entry represents the number of fields collected during
/// the parsing of a C++ class. When a nested class is entered, a new field
/// count is pushed, when it is exited, the field count is popped.
- llvm::SmallVector<size_t, 4> FieldCount;
+ SmallVector<size_t, 4> FieldCount;
// Example:
//
diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h
index 74b0105b3310..9e2d60d3e015 100644
--- a/include/clang/Sema/CodeCompleteConsumer.h
+++ b/include/clang/Sema/CodeCompleteConsumer.h
@@ -21,11 +21,6 @@
#include "clang-c/Index.h"
#include <string>
-namespace llvm {
- class raw_ostream;
- class Twine;
-}
-
namespace clang {
class Decl;
@@ -136,7 +131,7 @@ QualType getDeclUsageType(ASTContext &C, NamedDecl *ND);
///
/// \param PreferredTypeIsPointer Whether the preferred type for the context
/// of this macro is a pointer type.
-unsigned getMacroUsagePriority(llvm::StringRef MacroName,
+unsigned getMacroUsagePriority(StringRef MacroName,
const LangOptions &LangOpts,
bool PreferredTypeIsPointer = false);
@@ -253,9 +248,9 @@ public:
CCC_ObjCInstanceMessage,
/// \brief Code completion where an Objective-C class message is expected.
CCC_ObjCClassMessage,
- /// \brief Code completion where a superclass of an Objective-C class is
+ /// \brief Code completion where the name of an Objective-C class is
/// expected.
- CCC_ObjCSuperclass,
+ CCC_ObjCInterfaceName,
/// \brief Code completion where an Objective-C category name is expected.
CCC_ObjCCategoryName,
/// \brief An unknown context, in which we are recovering from a parsing
@@ -273,14 +268,26 @@ private:
/// \brief The type of the base object in a member access expression.
QualType BaseType;
+ /// \brief The identifiers for Objective-C selector parts.
+ IdentifierInfo **SelIdents;
+
+ /// \brief The number of Objective-C selector parts.
+ unsigned NumSelIdents;
+
public:
/// \brief Construct a new code-completion context of the given kind.
- CodeCompletionContext(enum Kind Kind) : Kind(Kind) { }
+ CodeCompletionContext(enum Kind Kind) : Kind(Kind), SelIdents(NULL),
+ NumSelIdents(0) { }
/// \brief Construct a new code-completion context of the given kind.
- CodeCompletionContext(enum Kind Kind, QualType T) : Kind(Kind) {
+ CodeCompletionContext(enum Kind Kind, QualType T,
+ IdentifierInfo **SelIdents = NULL,
+ unsigned NumSelIdents = 0) : Kind(Kind),
+ SelIdents(SelIdents),
+ NumSelIdents(NumSelIdents) {
if (Kind == CCC_DotMemberAccess || Kind == CCC_ArrowMemberAccess ||
- Kind == CCC_ObjCPropertyAccess)
+ Kind == CCC_ObjCPropertyAccess || Kind == CCC_ObjCClassMessage ||
+ Kind == CCC_ObjCInstanceMessage)
BaseType = T;
else
PreferredType = T;
@@ -297,6 +304,12 @@ public:
/// \brief Retrieve the type of the base object in a member-access
/// expression.
QualType getBaseType() const { return BaseType; }
+
+ /// \brief Retrieve the Objective-C selector identifiers.
+ IdentifierInfo **getSelIdents() const { return SelIdents; }
+
+ /// \brief Retrieve the number of Objective-C selector identifiers.
+ unsigned getNumSelIdents() const { return NumSelIdents; }
/// \brief Determines whether we want C++ constructors as results within this
/// context.
@@ -415,19 +428,23 @@ public:
private:
/// \brief The number of chunks stored in this string.
- unsigned NumChunks;
+ unsigned NumChunks : 16;
+ /// \brief The number of annotations for this code-completion result.
+ unsigned NumAnnotations : 16;
+
/// \brief The priority of this code-completion string.
unsigned Priority : 30;
/// \brief The availability of this code-completion result.
unsigned Availability : 2;
-
+
CodeCompletionString(const CodeCompletionString &); // DO NOT IMPLEMENT
CodeCompletionString &operator=(const CodeCompletionString &); // DITTO
CodeCompletionString(const Chunk *Chunks, unsigned NumChunks,
- unsigned Priority, CXAvailabilityKind Availability);
+ unsigned Priority, CXAvailabilityKind Availability,
+ const char **Annotations, unsigned NumAnnotations);
~CodeCompletionString() { }
friend class CodeCompletionBuilder;
@@ -451,8 +468,14 @@ public:
/// \brief Retrieve the priority of this code completion result.
unsigned getPriority() const { return Priority; }
- /// \brief Reteirve the availability of this code completion result.
+ /// \brief Retrieve the availability of this code completion result.
unsigned getAvailability() const { return Availability; }
+
+ /// \brief Retrieve the number of annotations for this code completion result.
+ unsigned getAnnotationCount() const;
+
+ /// \brief Retrieve the annotation string specified by \c AnnotationNr.
+ const char *getAnnotation(unsigned AnnotationNr) const;
/// \brief Retrieve a string representation of the code completion string,
/// which is mainly useful for debugging.
@@ -463,19 +486,19 @@ public:
class CodeCompletionAllocator : public llvm::BumpPtrAllocator {
public:
/// \brief Copy the given string into this allocator.
- const char *CopyString(llvm::StringRef String);
+ const char *CopyString(StringRef String);
/// \brief Copy the given string into this allocator.
- const char *CopyString(llvm::Twine String);
+ const char *CopyString(Twine String);
// \brief Copy the given string into this allocator.
const char *CopyString(const char *String) {
- return CopyString(llvm::StringRef(String));
+ return CopyString(StringRef(String));
}
/// \brief Copy the given string into this allocator.
const char *CopyString(const std::string &String) {
- return CopyString(llvm::StringRef(String));
+ return CopyString(StringRef(String));
}
};
@@ -490,7 +513,9 @@ private:
CXAvailabilityKind Availability;
/// \brief The chunks stored in this string.
- llvm::SmallVector<Chunk, 4> Chunks;
+ SmallVector<Chunk, 4> Chunks;
+
+ SmallVector<const char *, 2> Annotations;
public:
CodeCompletionBuilder(CodeCompletionAllocator &Allocator)
@@ -547,6 +572,8 @@ public:
/// \brief Add a new chunk.
void AddChunk(Chunk C) { Chunks.push_back(C); }
+
+ void AddAnnotation(const char *A) { Annotations.push_back(A); }
};
/// \brief Captures a result of code completion.
@@ -619,14 +646,15 @@ public:
/// \brief Build a result that refers to a declaration.
CodeCompletionResult(NamedDecl *Declaration,
NestedNameSpecifier *Qualifier = 0,
- bool QualifierIsInformative = false)
+ bool QualifierIsInformative = false,
+ bool Accessible = true)
: Kind(RK_Declaration), Declaration(Declaration),
Priority(getPriorityFromDecl(Declaration)),
Availability(CXAvailability_Available), StartParameter(0),
Hidden(false), QualifierIsInformative(QualifierIsInformative),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
DeclaringEntity(false), Qualifier(Qualifier) {
- computeCursorKindAndAvailability();
+ computeCursorKindAndAvailability(Accessible);
}
/// \brief Build a result that refers to a keyword or symbol.
@@ -688,7 +716,7 @@ public:
static unsigned getPriorityFromDecl(NamedDecl *ND);
private:
- void computeCursorKindAndAvailability();
+ void computeCursorKindAndAvailability(bool Accessible = true);
};
bool operator<(const CodeCompletionResult &X, const CodeCompletionResult &Y);
@@ -709,7 +737,7 @@ inline bool operator>=(const CodeCompletionResult &X,
}
-llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+raw_ostream &operator<<(raw_ostream &OS,
const CodeCompletionString &CCS);
/// \brief Abstract interface for a consumer of code-completion
@@ -850,7 +878,7 @@ public:
/// receives in a simple format.
class PrintingCodeCompleteConsumer : public CodeCompleteConsumer {
/// \brief The raw output stream.
- llvm::raw_ostream &OS;
+ raw_ostream &OS;
CodeCompletionAllocator Allocator;
@@ -859,7 +887,7 @@ public:
/// results to the given raw output stream.
PrintingCodeCompleteConsumer(bool IncludeMacros, bool IncludeCodePatterns,
bool IncludeGlobals,
- llvm::raw_ostream &OS)
+ raw_ostream &OS)
: CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, IncludeGlobals,
false), OS(OS) {}
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index a66649955c8c..3260a70ebb4f 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -34,7 +34,7 @@ namespace clang {
class ASTContext;
class TypeLoc;
class LangOptions;
- class Diagnostic;
+ class DiagnosticsEngine;
class IdentifierInfo;
class NamespaceAliasDecl;
class NamespaceDecl;
@@ -42,6 +42,7 @@ namespace clang {
class NestedNameSpecifierLoc;
class ObjCDeclSpec;
class Preprocessor;
+ class Sema;
class Declarator;
struct TemplateIdAnnotation;
@@ -242,6 +243,7 @@ public:
static const TST TST_char16 = clang::TST_char16;
static const TST TST_char32 = clang::TST_char32;
static const TST TST_int = clang::TST_int;
+ static const TST TST_half = clang::TST_half;
static const TST TST_float = clang::TST_float;
static const TST TST_double = clang::TST_double;
static const TST TST_bool = clang::TST_bool;
@@ -259,6 +261,7 @@ public:
static const TST TST_underlyingType = clang::TST_underlyingType;
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_error = clang::TST_error;
// type-qualifiers
@@ -345,7 +348,7 @@ private:
SourceRange TypeofParensRange;
SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc;
SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc;
- SourceLocation FriendLoc, ConstexprLoc;
+ SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc;
WrittenBuiltinSpecs writtenBS;
void SaveWrittenBuiltinSpecs();
@@ -355,7 +358,7 @@ private:
static bool isTypeRep(TST T) {
return (T == TST_typename || T == TST_typeofType ||
- T == TST_underlyingType);
+ T == TST_underlyingType || T == TST_atomic);
}
static bool isExprRep(TST T) {
return (T == TST_typeofExpr || T == TST_decltype);
@@ -381,7 +384,7 @@ public:
TypeAltiVecPixel(false),
TypeAltiVecBool(false),
TypeSpecOwned(false),
- TypeQualifiers(TSS_unspecified),
+ TypeQualifiers(TQ_unspecified),
FS_inline_specified(false),
FS_virtual_specified(false),
FS_explicit_specified(false),
@@ -537,8 +540,8 @@ public:
///
/// TODO: use a more general approach that still allows these
/// diagnostics to be ignored when desired.
- bool SetStorageClassSpec(SCS S, SourceLocation Loc, const char *&PrevSpec,
- unsigned &DiagID, const LangOptions &Lang);
+ bool SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc,
+ const char *&PrevSpec, unsigned &DiagID);
bool SetStorageClassSpecThread(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID);
bool SetTypeSpecWidth(TSW W, SourceLocation Loc, const char *&PrevSpec,
@@ -592,13 +595,17 @@ public:
bool SetFriendSpec(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID);
-
+ bool setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID);
bool SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID);
bool isFriendSpecified() const { return Friend_specified; }
SourceLocation getFriendSpecLoc() const { return FriendLoc; }
+ bool isModulePrivateSpecified() const { return ModulePrivateLoc.isValid(); }
+ SourceLocation getModulePrivateSpecLoc() const { return ModulePrivateLoc; }
+
bool isConstexprSpecified() const { return Constexpr_specified; }
SourceLocation getConstexprSpecLoc() const { return ConstexprLoc; }
@@ -657,7 +664,7 @@ public:
/// Finish - This does final analysis of the declspec, issuing diagnostics for
/// things like "_Imaginary" (lacking an FP type). After calling this method,
/// DeclSpec is guaranteed self-consistent, even if an error occurred.
- void Finish(Diagnostic &D, Preprocessor &PP);
+ void Finish(DiagnosticsEngine &D, Preprocessor &PP);
const WrittenBuiltinSpecs& getWrittenBuiltinSpecs() const {
return writtenBS;
@@ -732,6 +739,7 @@ public:
const IdentifierInfo *getSetterName() const { return SetterName; }
IdentifierInfo *getSetterName() { return SetterName; }
void setSetterName(IdentifierInfo *name) { SetterName = name; }
+
private:
// FIXME: These two are unrelated and mutially exclusive. So perhaps
// we can put them in a union to reflect their mutual exclusiveness
@@ -961,7 +969,7 @@ public:
/// CachedTokens - A set of tokens that has been cached for later
/// parsing.
-typedef llvm::SmallVector<Token, 4> CachedTokens;
+typedef SmallVector<Token, 4> CachedTokens;
/// DeclaratorChunk - One instance of this struct is used for each type in a
/// declarator that is parsed.
@@ -1222,7 +1230,7 @@ struct DeclaratorChunk {
void destroy() {
switch (Kind) {
- default: assert(0 && "Unknown decl type!");
+ default: llvm_unreachable("Unknown decl type!");
case DeclaratorChunk::Function: return Fun.destroy();
case DeclaratorChunk::Pointer: return Ptr.destroy();
case DeclaratorChunk::BlockPointer: return Cls.destroy();
@@ -1364,7 +1372,8 @@ public:
enum TheContext {
FileContext, // File scope declaration.
PrototypeContext, // Within a function prototype.
- ObjCPrototypeContext,// Within a method prototype.
+ ObjCResultContext, // An ObjC method result type.
+ ObjCParameterContext,// An ObjC method parameter type.
KNRTypeListContext, // K&R type definition list for formals.
TypeNameContext, // Abstract declarator for types.
MemberContext, // Struct/Union field.
@@ -1395,7 +1404,7 @@ private:
/// parsed. This is pushed from the identifier out, which means that element
/// #0 will be the most closely bound to the identifier, and
/// DeclTypeInfo.back() will be the least closely bound.
- llvm::SmallVector<DeclaratorChunk, 8> DeclTypeInfo;
+ SmallVector<DeclaratorChunk, 8> DeclTypeInfo;
/// InvalidType - Set by Sema::GetTypeForDeclarator().
bool InvalidType : 1;
@@ -1403,6 +1412,12 @@ private:
/// GroupingParens - Set by Parser::ParseParenDeclarator().
bool GroupingParens : 1;
+ /// FunctionDefinition - Is this Declarator for a function or member defintion
+ bool FunctionDefinition : 1;
+
+ // Redeclaration - Is this Declarator is a redeclaration.
+ bool Redeclaration : 1;
+
/// Attrs - Attributes.
ParsedAttributes Attrs;
@@ -1428,8 +1443,9 @@ public:
Declarator(const DeclSpec &ds, TheContext C)
: DS(ds), Range(ds.getSourceRange()), Context(C),
InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error),
- GroupingParens(false), Attrs(ds.getAttributePool().getFactory()),
- AsmLabel(0), InlineParamsUsed(false), Extension(false) {
+ GroupingParens(false), FunctionDefinition(false), Redeclaration(false),
+ Attrs(ds.getAttributePool().getFactory()), AsmLabel(0),
+ InlineParamsUsed(false), Extension(false) {
}
~Declarator() {
@@ -1462,7 +1478,9 @@ public:
TheContext getContext() const { return Context; }
bool isPrototypeContext() const {
- return (Context == PrototypeContext || Context == ObjCPrototypeContext);
+ return (Context == PrototypeContext ||
+ Context == ObjCParameterContext ||
+ Context == ObjCResultContext);
}
/// getSourceRange - Get the source range that spans this declarator.
@@ -1522,7 +1540,8 @@ public:
case AliasDeclContext:
case AliasTemplateContext:
case PrototypeContext:
- case ObjCPrototypeContext:
+ case ObjCParameterContext:
+ case ObjCResultContext:
case TemplateParamContext:
case CXXNewContext:
case CXXCatchContext:
@@ -1555,7 +1574,8 @@ public:
case CXXNewContext:
case AliasDeclContext:
case AliasTemplateContext:
- case ObjCPrototypeContext:
+ case ObjCParameterContext:
+ case ObjCResultContext:
case BlockLiteralContext:
case TemplateTypeArgContext:
return false;
@@ -1578,7 +1598,8 @@ public:
case MemberContext:
case ConditionContext:
case PrototypeContext:
- case ObjCPrototypeContext:
+ case ObjCParameterContext:
+ case ObjCResultContext:
case TemplateParamContext:
case CXXCatchContext:
case ObjCCatchContext:
@@ -1783,6 +1804,12 @@ public:
bool hasEllipsis() const { return EllipsisLoc.isValid(); }
SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
void setEllipsisLoc(SourceLocation EL) { EllipsisLoc = EL; }
+
+ void setFunctionDefinition(bool Val) { FunctionDefinition = Val; }
+ bool isFunctionDefinition() const { return FunctionDefinition; }
+
+ void setRedeclaration(bool Val) { Redeclaration = Val; }
+ bool isRedeclaration() const { return Redeclaration; }
};
/// FieldDeclarator - This little struct is used to capture information about
@@ -1828,6 +1855,53 @@ private:
SourceLocation LastLocation;
};
+/// LambdaCaptureDefault - The default, if any, capture method for a
+/// lambda expression.
+enum LambdaCaptureDefault {
+ LCD_None,
+ LCD_ByCopy,
+ LCD_ByRef
+};
+
+/// LambdaCaptureKind - The different capture forms in a lambda
+/// introducer: 'this' or a copied or referenced variable.
+enum LambdaCaptureKind {
+ LCK_This,
+ LCK_ByCopy,
+ LCK_ByRef
+};
+
+/// LambdaCapture - An individual capture in a lambda introducer.
+struct LambdaCapture {
+ LambdaCaptureKind Kind;
+ SourceLocation Loc;
+ IdentifierInfo* Id;
+
+ LambdaCapture(LambdaCaptureKind Kind,
+ SourceLocation Loc,
+ IdentifierInfo* Id = 0)
+ : Kind(Kind), Loc(Loc), Id(Id)
+ {}
+};
+
+/// LambdaIntroducer - Represents a complete lambda introducer.
+struct LambdaIntroducer {
+ SourceRange Range;
+ LambdaCaptureDefault Default;
+ llvm::SmallVector<LambdaCapture, 4> Captures;
+
+ LambdaIntroducer()
+ : Default(LCD_None) {}
+
+ /// addCapture - Append a capture in a lambda introducer.
+ void addCapture(LambdaCaptureKind Kind,
+ SourceLocation Loc,
+ IdentifierInfo* Id = 0) {
+ Captures.push_back(LambdaCapture(Kind, Loc, Id));
+ }
+
+};
+
} // end namespace clang
#endif
diff --git a/include/clang/Sema/DelayedDiagnostic.h b/include/clang/Sema/DelayedDiagnostic.h
index 8ab938226482..dd2603dbc362 100644
--- a/include/clang/Sema/DelayedDiagnostic.h
+++ b/include/clang/Sema/DelayedDiagnostic.h
@@ -123,7 +123,7 @@ public:
static DelayedDiagnostic makeDeprecation(SourceLocation Loc,
const NamedDecl *D,
- llvm::StringRef Msg);
+ StringRef Msg);
static DelayedDiagnostic makeAccess(SourceLocation Loc,
const AccessedEntity &Entity) {
@@ -163,9 +163,9 @@ public:
return DeprecationData.Decl;
}
- llvm::StringRef getDeprecationMessage() const {
+ StringRef getDeprecationMessage() const {
assert(Kind == Deprecation && "Not a deprecation diagnostic.");
- return llvm::StringRef(DeprecationData.Message,
+ return StringRef(DeprecationData.Message,
DeprecationData.MessageLen);
}
diff --git a/include/clang/Sema/Designator.h b/include/clang/Sema/Designator.h
index 6fe7ab24f0a2..fe01f4d60149 100644
--- a/include/clang/Sema/Designator.h
+++ b/include/clang/Sema/Designator.h
@@ -185,7 +185,7 @@ class Designation {
unsigned InitIndex;
/// Designators - The actual designators for this initializer.
- llvm::SmallVector<Designator, 2> Designators;
+ SmallVector<Designator, 2> Designators;
Designation(unsigned Idx) : InitIndex(Idx) {}
public:
diff --git a/include/clang/Sema/ExternalSemaSource.h b/include/clang/Sema/ExternalSemaSource.h
index 072e1b58d138..7b83625fa332 100644
--- a/include/clang/Sema/ExternalSemaSource.h
+++ b/include/clang/Sema/ExternalSemaSource.h
@@ -14,15 +14,30 @@
#define LLVM_CLANG_SEMA_EXTERNAL_SEMA_SOURCE_H
#include "clang/AST/ExternalASTSource.h"
+#include "clang/Sema/Weak.h"
#include <utility>
namespace clang {
+class CXXConstructorDecl;
+class CXXRecordDecl;
+class DeclaratorDecl;
+class LookupResult;
struct ObjCMethodList;
-class Sema;
class Scope;
-class LookupResult;
-
+class Sema;
+class TypedefNameDecl;
+class ValueDecl;
+class VarDecl;
+
+/// \brief A simple structure that captures a vtable use for the purposes of
+/// the \c ExternalSemaSource.
+struct ExternalVTableUse {
+ CXXRecordDecl *Record;
+ SourceLocation Location;
+ bool DefinitionRequired;
+};
+
/// \brief An abstract interface that should be implemented by
/// external AST sources that also provide information for semantic
/// analysis.
@@ -52,7 +67,7 @@ public:
/// \brief Load the set of namespaces that are known to the external source,
/// which will be used during typo correction.
virtual void ReadKnownNamespaces(
- llvm::SmallVectorImpl<NamespaceDecl *> &Namespaces);
+ SmallVectorImpl<NamespaceDecl *> &Namespaces);
/// \brief Do last resort, unqualified lookup on a LookupResult that
/// Sema cannot find.
@@ -64,12 +79,107 @@ public:
/// \return true to tell Sema to recover using the LookupResult.
virtual bool LookupUnqualified(LookupResult &R, Scope *S) { return false; }
+ /// \brief Read the set of tentative definitions known to the external Sema
+ /// source.
+ ///
+ /// The external source should append its own tentative definitions to the
+ /// given vector of tentative definitions. Note that this routine may be
+ /// invoked multiple times; the external source should take care not to
+ /// introduce the same declarations repeatedly.
+ virtual void ReadTentativeDefinitions(
+ SmallVectorImpl<VarDecl *> &TentativeDefs) {}
+
+ /// \brief Read the set of unused file-scope declarations known to the
+ /// external Sema source.
+ ///
+ /// The external source should append its own unused, filed-scope to the
+ /// given vector of declarations. Note that this routine may be
+ /// invoked multiple times; the external source should take care not to
+ /// introduce the same declarations repeatedly.
+ virtual void ReadUnusedFileScopedDecls(
+ SmallVectorImpl<const DeclaratorDecl *> &Decls) {}
+
+ /// \brief Read the set of delegating constructors known to the
+ /// external Sema source.
+ ///
+ /// The external source should append its own delegating constructors to the
+ /// given vector of declarations. Note that this routine may be
+ /// invoked multiple times; the external source should take care not to
+ /// introduce the same declarations repeatedly.
+ virtual void ReadDelegatingConstructors(
+ SmallVectorImpl<CXXConstructorDecl *> &Decls) {}
+
+ /// \brief Read the set of ext_vector type declarations known to the
+ /// external Sema source.
+ ///
+ /// The external source should append its own ext_vector type declarations to
+ /// the given vector of declarations. Note that this routine may be
+ /// invoked multiple times; the external source should take care not to
+ /// introduce the same declarations repeatedly.
+ virtual void ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl *> &Decls) {}
+
+ /// \brief Read the set of dynamic classes known to the external Sema source.
+ ///
+ /// The external source should append its own dynamic classes to
+ /// the given vector of declarations. Note that this routine may be
+ /// invoked multiple times; the external source should take care not to
+ /// introduce the same declarations repeatedly.
+ virtual void ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls) {}
+
+ /// \brief Read the set of locally-scoped external declarations known to the
+ /// external Sema source.
+ ///
+ /// The external source should append its own locally-scoped external
+ /// declarations to the given vector of declarations. Note that this routine
+ /// may be invoked multiple times; the external source should take care not
+ /// to introduce the same declarations repeatedly.
+ virtual void ReadLocallyScopedExternalDecls(
+ SmallVectorImpl<NamedDecl *> &Decls) {}
+
+ /// \brief Read the set of referenced selectors known to the
+ /// external Sema source.
+ ///
+ /// The external source should append its own referenced selectors to the
+ /// given vector of selectors. Note that this routine
+ /// may be invoked multiple times; the external source should take care not
+ /// to introduce the same selectors repeatedly.
+ virtual void ReadReferencedSelectors(
+ SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels) {}
+
+ /// \brief Read the set of weak, undeclared identifiers known to the
+ /// external Sema source.
+ ///
+ /// The external source should append its own weak, undeclared identifiers to
+ /// the given vector. Note that this routine may be invoked multiple times;
+ /// the external source should take care not to introduce the same identifiers
+ /// repeatedly.
+ virtual void ReadWeakUndeclaredIdentifiers(
+ SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo> > &WI) {}
+
+ /// \brief Read the set of used vtables known to the external Sema source.
+ ///
+ /// The external source should append its own used vtables to the given
+ /// vector. Note that this routine may be invoked multiple times; the external
+ /// source should take care not to introduce the same vtables repeatedly.
+ virtual void ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables) {}
+
+ /// \brief Read the set of pending instantiations known to the external
+ /// Sema source.
+ ///
+ /// The external source should append its own pending instantiations to the
+ /// given vector. Note that this routine may be invoked multiple times; the
+ /// external source should take care not to introduce the same instantiations
+ /// repeatedly.
+ virtual void ReadPendingInstantiations(
+ SmallVectorImpl<std::pair<ValueDecl *,
+ SourceLocation> > &Pending) {}
+
// isa/cast/dyn_cast support
static bool classof(const ExternalASTSource *Source) {
return Source->SemaSource;
}
static bool classof(const ExternalSemaSource *) { return true; }
-};
+};
} // end namespace clang
diff --git a/include/clang/Sema/IdentifierResolver.h b/include/clang/Sema/IdentifierResolver.h
index 8d79fc09f292..85d8ad22bfb0 100644
--- a/include/clang/Sema/IdentifierResolver.h
+++ b/include/clang/Sema/IdentifierResolver.h
@@ -37,7 +37,7 @@ class IdentifierResolver {
/// decl with that declaration name is shadowed in some scope.
class IdDeclInfo {
public:
- typedef llvm::SmallVector<NamedDecl*, 2> DeclsTy;
+ typedef SmallVector<NamedDecl*, 2> DeclsTy;
inline DeclsTy::iterator decls_begin() { return Decls.begin(); }
inline DeclsTy::iterator decls_end() { return Decls.end(); }
diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h
index df6138c7f039..e69bebd56cff 100644
--- a/include/clang/Sema/Initialization.h
+++ b/include/clang/Sema/Initialization.h
@@ -22,10 +22,6 @@
#include "llvm/ADT/SmallVector.h"
#include <cassert>
-namespace llvm {
- class raw_ostream;
-}
-
namespace clang {
class CXXBaseSpecifier;
@@ -71,7 +67,10 @@ public:
EK_VectorElement,
/// \brief The entity being initialized is a field of block descriptor for
/// the copied-in c++ object.
- EK_BlockElement
+ EK_BlockElement,
+ /// \brief The entity being initialized is the real or imaginary part of a
+ /// complex number.
+ EK_ComplexElement
};
private:
@@ -115,8 +114,9 @@ private:
/// virtual base.
uintptr_t Base;
- /// \brief When Kind == EK_ArrayElement or EK_VectorElement, the
- /// index of the array or vector element being initialized.
+ /// \brief When Kind == EK_ArrayElement, EK_VectorElement, or
+ /// EK_ComplexElement, the index of the array or vector element being
+ /// initialized.
unsigned Index;
};
@@ -313,7 +313,8 @@ public:
/// \brief If this is already the initializer for an array or vector
/// element, sets the element index.
void setElementIndex(unsigned Index) {
- assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement);
+ assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement ||
+ EK_ComplexElement);
this->Index = Index;
}
};
@@ -525,8 +526,10 @@ public:
SK_QualificationConversionLValue,
/// \brief Perform an implicit conversion sequence.
SK_ConversionSequence,
- /// \brief Perform list-initialization
+ /// \brief Perform list-initialization without a constructor
SK_ListInitialization,
+ /// \brief Perform list-initialization with a constructor.
+ SK_ListConstructorCall,
/// \brief Perform initialization via a constructor.
SK_ConstructorInitialization,
/// \brief Zero-initialize the object
@@ -562,20 +565,24 @@ public:
/// \brief When Kind == SK_ResolvedOverloadedFunction or Kind ==
/// SK_UserConversion, the function that the expression should be
/// resolved to or the conversion function to call, respectively.
+ /// When Kind == SK_ConstructorInitialization or SK_ListConstruction,
+ /// the constructor to be called.
///
- /// Always a FunctionDecl.
+ /// Always a FunctionDecl, plus a Boolean flag telling if it was
+ /// 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;
-
+
/// \brief When Kind = SK_ConversionSequence, the implicit conversion
/// sequence
ImplicitConversionSequence *ICS;
};
-
+
void Destroy();
};
@@ -584,7 +591,7 @@ private:
enum SequenceKind SequenceKind;
/// \brief Steps taken by this initialization.
- llvm::SmallVector<Step, 4> Steps;
+ SmallVector<Step, 4> Steps;
public:
/// \brief Describes why initialization failed.
@@ -633,11 +640,13 @@ public:
/// \brief Default-initialization of a 'const' object.
FK_DefaultInitOfConst,
/// \brief Initialization of an incomplete type.
- FK_Incomplete
+ FK_Incomplete,
+ /// \brief List initialization failed at some point.
+ FK_ListInitializationFailed
};
private:
- /// \brief The reason why initialization failued.
+ /// \brief The reason why initialization failed.
FailureKind Failure;
/// \brief The failed result of overload resolution.
@@ -722,7 +731,7 @@ public:
/// \brief Determine whether the initialization sequence is invalid.
bool Failed() const { return SequenceKind == FailedSequence; }
- typedef llvm::SmallVector<Step, 4>::const_iterator step_iterator;
+ typedef SmallVector<Step, 4>::const_iterator step_iterator;
step_iterator step_begin() const { return Steps.begin(); }
step_iterator step_end() const { return Steps.end(); }
@@ -736,7 +745,18 @@ public:
/// \brief Determine whether this initialization is direct call to a
/// constructor.
bool isConstructorInitialization() const;
-
+
+ /// \brief Returns whether the last step in this initialization sequence is a
+ /// narrowing conversion, defined by C++0x [dcl.init.list]p7.
+ ///
+ /// If this function returns true, *isInitializerConstant will be set to
+ /// describe whether *Initializer was a constant expression. If
+ /// *isInitializerConstant is set to true, *ConstantValue will be set to the
+ /// evaluated value of *Initializer.
+ bool endsWithNarrowing(ASTContext &Ctx, const Expr *Initializer,
+ bool *isInitializerConstant,
+ APValue *ConstantValue) const;
+
/// \brief Add a new step in the initialization that resolves the address
/// of an overloaded function to a specific function declaration.
///
@@ -792,7 +812,7 @@ public:
void AddConversionSequenceStep(const ImplicitConversionSequence &ICS,
QualType T);
- /// \brief Add a list-initialiation step
+ /// \brief Add a list-initialiation step.
void AddListInitializationStep(QualType T);
/// \brief Add a constructor-initialization step.
@@ -857,7 +877,7 @@ public:
/// \brief Dump a representation of this initialization sequence to
/// the given stream, for debugging purposes.
- void dump(llvm::raw_ostream &OS) const;
+ void dump(raw_ostream &OS) const;
/// \brief Dump a representation of this initialization sequence to
/// standard error, for debugging purposes.
diff --git a/include/clang/Sema/Lookup.h b/include/clang/Sema/Lookup.h
index dceed4efc979..6630bb2981e2 100644
--- a/include/clang/Sema/Lookup.h
+++ b/include/clang/Sema/Lookup.h
@@ -268,7 +268,19 @@ public:
/// \brief Tests whether the given declaration is acceptable.
bool isAcceptableDecl(NamedDecl *D) const {
- return D->isInIdentifierNamespace(IDNS);
+ if (!D->isInIdentifierNamespace(IDNS))
+ return false;
+
+ // So long as this declaration is not module-private or was parsed as
+ // part of this translation unit (i.e., in the module), we're allowed to
+ // find it.
+ if (!D->isModulePrivate() || !D->isFromASTFile())
+ return true;
+
+ // FIXME: We should be allowed to refer to a module-private name from
+ // within the same module, e.g., during template instantiation.
+ // This requires us know which module a particular declaration came from.
+ return false;
}
/// \brief Returns the identifier namespace mask for this lookup.
@@ -282,18 +294,6 @@ public:
return NamingClass != 0;
}
- /// \brief Set whether the name lookup is triggered by a
- /// using declaration.
- void setUsingDeclaration(bool U) {
- UsingDeclaration = U;
- }
-
- /// \brief Returns whether the name lookup is triggered by a
- /// using declaration.
- bool isUsingDeclaration() const {
- return UsingDeclaration;
- }
-
/// \brief Returns the 'naming class' for this lookup, i.e. the
/// class which was looked into to find these results.
///
@@ -468,7 +468,7 @@ public:
configure();
}
- void print(llvm::raw_ostream &);
+ void print(raw_ostream &);
/// Suppress the diagnostics that would normally fire because of this
/// lookup. This happens during (e.g.) redeclaration lookups.
@@ -615,10 +615,6 @@ private:
bool HideTags;
bool Diagnose;
-
- /// \brief True if the lookup is triggered by a using declaration.
- /// Necessary to handle a MSVC bug.
- bool UsingDeclaration;
};
/// \brief Consumes visible declarations found when searching for
@@ -640,9 +636,11 @@ private:
/// \param Hiding a declaration that hides the declaration \p ND,
/// or NULL if no such declaration exists.
///
+ /// \param Ctx the original context from which the lookup started.
+ ///
/// \param InBaseClass whether this declaration was found in base
/// class of the context we searched.
- virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
+ virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
bool InBaseClass) = 0;
};
diff --git a/include/clang/Sema/MultiInitializer.h b/include/clang/Sema/MultiInitializer.h
new file mode 100644
index 000000000000..c44e3934db68
--- /dev/null
+++ b/include/clang/Sema/MultiInitializer.h
@@ -0,0 +1,72 @@
+//===--- MultiInitializer.h - Initializer expression group ------*- 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 MultiInitializer class, which can represent a list
+// initializer or a parentheses-wrapped group of expressions in a C++ member
+// initializer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_MULTIINITIALIZER_H
+#define LLVM_CLANG_SEMA_MULTIINITIALIZER_H
+
+#include "clang/Sema/Ownership.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/PointerUnion.h"
+
+namespace clang {
+ class ASTContext;
+ class Expr;
+ class InitializationKind;
+ class InitializedEntity;
+ class InitListExpr;
+ class Sema;
+
+class MultiInitializer {
+ llvm::PointerUnion<Expr*, Expr**> InitListOrExpressions;
+ unsigned NumInitializers;
+ SourceLocation LParenLoc;
+ SourceLocation RParenLoc;
+
+ InitListExpr *getInitList() const;
+ Expr **getExpressions() const { return InitListOrExpressions.get<Expr**>(); }
+
+public:
+ MultiInitializer(Expr* InitList)
+ : InitListOrExpressions(InitList)
+ {}
+
+ MultiInitializer(SourceLocation LParenLoc, Expr **Exprs, unsigned NumInits,
+ SourceLocation RParenLoc)
+ : InitListOrExpressions(Exprs), NumInitializers(NumInits),
+ LParenLoc(LParenLoc), RParenLoc(RParenLoc)
+ {}
+
+ bool isInitializerList() const { return InitListOrExpressions.is<Expr*>(); }
+
+ SourceLocation getStartLoc() const;
+ SourceLocation getEndLoc() const;
+
+ typedef Expr **iterator;
+ iterator begin() const;
+ iterator end() const;
+
+ bool isTypeDependent() const;
+
+ bool DiagnoseUnexpandedParameterPack(Sema &SemaRef) const;
+
+ // Return the InitListExpr or create a ParenListExpr.
+ Expr *CreateInitExpr(ASTContext &Ctx, QualType T) const;
+
+ ExprResult PerformInit(Sema &SemaRef, InitializedEntity Entity,
+ InitializationKind Kind) const;
+};
+}
+
+#endif
diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h
index 32d4cbdac15e..dbc0926f03af 100644
--- a/include/clang/Sema/Overload.h
+++ b/include/clang/Sema/Overload.h
@@ -21,6 +21,7 @@
#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
#include "clang/AST/UnresolvedSet.h"
+#include "clang/Sema/SemaFixItUtils.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
@@ -243,7 +244,12 @@ namespace clang {
// a gcc code gen. bug which causes a crash in a test. Putting it here seems
// to work around the crash.
bool EllipsisConversion : 1;
-
+
+ /// HadMultipleCandidates - When this is true, it means that the
+ /// conversion function was resolved from an overloaded set having
+ /// size greater than 1.
+ bool HadMultipleCandidates : 1;
+
/// After - Represents the standard conversion that occurs after
/// the actual user-defined conversion.
StandardConversionSequence After;
@@ -255,14 +261,14 @@ namespace clang {
/// \brief The declaration that we found via name lookup, which might be
/// the same as \c ConversionFunction or it might be a using declaration
/// that refers to \c ConversionFunction.
- NamedDecl *FoundConversionFunction;
+ DeclAccessPair FoundConversionFunction;
void DebugPrint() const;
};
/// Represents an ambiguous user-defined conversion sequence.
struct AmbiguousConversionSequence {
- typedef llvm::SmallVector<FunctionDecl*, 4> ConversionSet;
+ typedef SmallVector<FunctionDecl*, 4> ConversionSet;
void *FromTypePtr;
void *ToTypePtr;
@@ -463,6 +469,7 @@ namespace clang {
bool isEllipsis() const { return getKind() == EllipsisConversion; }
bool isAmbiguous() const { return getKind() == AmbiguousConversion; }
bool isUserDefined() const { return getKind() == UserDefinedConversion; }
+ bool isFailure() const { return isBad() || isAmbiguous(); }
/// Determines whether this conversion sequence has been
/// initialized. Most operations should never need to query
@@ -525,7 +532,12 @@ namespace clang {
/// This conversion function template specialization candidate is not
/// viable because the final conversion was not an exact match.
- ovl_fail_final_conversion_not_exact
+ ovl_fail_final_conversion_not_exact,
+
+ /// (CUDA) This candidate was not viable because the callee
+ /// was not accessible from the caller's target (i.e. host->device,
+ /// global->host, device->host).
+ ovl_fail_bad_target
};
/// OverloadCandidate - A single candidate in an overload set (C++ 13.3).
@@ -554,7 +566,10 @@ namespace clang {
/// Conversions - The conversion sequences used to convert the
/// function arguments to the function parameters.
- llvm::SmallVector<ImplicitConversionSequence, 4> Conversions;
+ SmallVector<ImplicitConversionSequence, 4> Conversions;
+
+ /// The FixIt hints which can be used to fix the Bad candidate.
+ ConversionFixItGenerator Fix;
/// Viable - True to indicate that this overload candidate is viable.
bool Viable;
@@ -624,19 +639,32 @@ namespace clang {
/// hasAmbiguousConversion - Returns whether this overload
/// candidate requires an ambiguous conversion or not.
bool hasAmbiguousConversion() const {
- for (llvm::SmallVectorImpl<ImplicitConversionSequence>::const_iterator
+ for (SmallVectorImpl<ImplicitConversionSequence>::const_iterator
I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
if (!I->isInitialized()) return false;
if (I->isAmbiguous()) return true;
}
return false;
}
+
+ bool TryToFixBadConversion(unsigned Idx, Sema &S) {
+ bool CanFix = Fix.tryToFixConversion(
+ Conversions[Idx].Bad.FromExpr,
+ Conversions[Idx].Bad.getFromType(),
+ Conversions[Idx].Bad.getToType(), S);
+
+ // If at least one conversion fails, the candidate cannot be fixed.
+ if (!CanFix)
+ Fix.clear();
+
+ return CanFix;
+ }
};
/// OverloadCandidateSet - A set of overload candidates, used in C++
/// overload resolution (C++ 13.3).
- class OverloadCandidateSet : public llvm::SmallVector<OverloadCandidate, 16> {
- typedef llvm::SmallVector<OverloadCandidate, 16> inherited;
+ class OverloadCandidateSet : public SmallVector<OverloadCandidate, 16> {
+ typedef SmallVector<OverloadCandidate, 16> inherited;
llvm::SmallPtrSet<Decl *, 16> Functions;
SourceLocation Loc;
diff --git a/include/clang/Sema/Ownership.h b/include/clang/Sema/Ownership.h
index cef93fe5832f..fb9e368dde9f 100644
--- a/include/clang/Sema/Ownership.h
+++ b/include/clang/Sema/Ownership.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_SEMA_OWNERSHIP_H
#define LLVM_CLANG_SEMA_OWNERSHIP_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/PointerIntPair.h"
@@ -368,7 +369,7 @@ namespace clang {
/// \brief A small vector that owns a set of AST nodes.
template <class PtrTy, unsigned N = 8>
- class ASTOwningVector : public llvm::SmallVector<PtrTy, N> {
+ class ASTOwningVector : public SmallVector<PtrTy, N> {
ASTOwningVector(ASTOwningVector &); // do not implement
ASTOwningVector &operator=(ASTOwningVector &); // do not implement
diff --git a/include/clang/Sema/ParsedTemplate.h b/include/clang/Sema/ParsedTemplate.h
index 1f572e5df4f3..735a26bd7bc4 100644
--- a/include/clang/Sema/ParsedTemplate.h
+++ b/include/clang/Sema/ParsedTemplate.h
@@ -114,7 +114,7 @@ namespace clang {
KindType Kind;
/// \brief The actual template argument representation, which may be
- /// an \c ActionBase::TypeTy* (for a type), an ActionBase::ExprTy* (for an
+ /// an \c ActionBase::TypeTy* (for a type), an Expr* (for an
/// expression), or an ActionBase::TemplateTy (for a template).
void *Arg;
diff --git a/include/clang/Sema/PrettyDeclStackTrace.h b/include/clang/Sema/PrettyDeclStackTrace.h
index b78a1c01e5e3..a31312cdc6dc 100644
--- a/include/clang/Sema/PrettyDeclStackTrace.h
+++ b/include/clang/Sema/PrettyDeclStackTrace.h
@@ -38,7 +38,7 @@ public:
PrettyDeclStackTraceEntry(Sema &S, Decl *D, SourceLocation Loc, const char *Msg)
: S(S), TheDecl(D), Loc(Loc), Message(Msg) {}
- virtual void print(llvm::raw_ostream &OS) const;
+ virtual void print(raw_ostream &OS) const;
};
}
diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h
index 95d29781e704..cff8b3338d82 100644
--- a/include/clang/Sema/Scope.h
+++ b/include/clang/Sema/Scope.h
@@ -149,14 +149,14 @@ private:
/// maintained by the Action implementation.
void *Entity;
- typedef llvm::SmallVector<UsingDirectiveDecl *, 2> UsingDirectivesTy;
+ typedef SmallVector<UsingDirectiveDecl *, 2> UsingDirectivesTy;
UsingDirectivesTy UsingDirectives;
/// \brief Used to determine if errors occurred in this scope.
DiagnosticErrorTrap ErrorTrap;
public:
- Scope(Scope *Parent, unsigned ScopeFlags, Diagnostic &Diag)
+ Scope(Scope *Parent, unsigned ScopeFlags, DiagnosticsEngine &Diag)
: ErrorTrap(Diag) {
Init(Parent, ScopeFlags);
}
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index 51297ae40205..9ef6d3c4b3d7 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -66,17 +66,17 @@ public:
/// SwitchStack - This is the current set of active switch statements in the
/// block.
- llvm::SmallVector<SwitchStmt*, 8> SwitchStack;
+ SmallVector<SwitchStmt*, 8> SwitchStack;
/// \brief The list of return statements that occur within the function or
/// block, if there is any chance of applying the named return value
/// optimization.
- llvm::SmallVector<ReturnStmt*, 4> Returns;
+ SmallVector<ReturnStmt*, 4> Returns;
/// \brief A list of PartialDiagnostics created but delayed within the
/// current function scope. These diagnostics are vetted for reachability
/// prior to being emitted.
- llvm::SmallVector<PossiblyUnreachableDiag, 4> PossiblyUnreachableDiags;
+ SmallVector<PossiblyUnreachableDiag, 4> PossiblyUnreachableDiags;
void setHasBranchIntoScope() {
HasBranchIntoScope = true;
@@ -95,7 +95,7 @@ public:
(HasBranchProtectedScope && HasBranchIntoScope);
}
- FunctionScopeInfo(Diagnostic &Diag)
+ FunctionScopeInfo(DiagnosticsEngine &Diag)
: IsBlockInfo(false),
HasBranchProtectedScope(false),
HasBranchIntoScope(false),
@@ -132,12 +132,12 @@ public:
llvm::DenseMap<VarDecl*, unsigned> CaptureMap;
/// Captures - The captured variables.
- llvm::SmallVector<BlockDecl::Capture, 4> Captures;
+ SmallVector<BlockDecl::Capture, 4> Captures;
/// CapturesCXXThis - Whether this block captures 'this'.
bool CapturesCXXThis;
- BlockScopeInfo(Diagnostic &Diag, Scope *BlockScope, BlockDecl *Block)
+ BlockScopeInfo(DiagnosticsEngine &Diag, Scope *BlockScope, BlockDecl *Block)
: FunctionScopeInfo(Diag), TheDecl(Block), TheScope(BlockScope),
CapturesCXXThis(false)
{
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 263c1bd49ac9..22d5db294440 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -20,8 +20,11 @@
#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/MultiInitializer.h"
#include "clang/Sema/TypoCorrection.h"
+#include "clang/Sema/Weak.h"
#include "clang/AST/Expr.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/ExternalASTSource.h"
@@ -30,6 +33,7 @@
#include "clang/Basic/TemplateKinds.h"
#include "clang/Basic/TypeTraits.h"
#include "clang/Basic/ExpressionTraits.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
@@ -54,7 +58,7 @@ namespace clang {
class BlockDecl;
class CXXBasePath;
class CXXBasePaths;
- typedef llvm::SmallVector<CXXBaseSpecifier*, 4> CXXCastPath;
+ typedef SmallVector<CXXBaseSpecifier*, 4> CXXCastPath;
class CXXConstructorDecl;
class CXXConversionDecl;
class CXXDestructorDecl;
@@ -175,13 +179,6 @@ public:
typedef OpaquePtr<DeclGroupRef> DeclGroupPtrTy;
typedef OpaquePtr<TemplateName> TemplateTy;
typedef OpaquePtr<QualType> TypeTy;
- typedef Attr AttrTy;
- typedef CXXBaseSpecifier BaseTy;
- typedef CXXCtorInitializer MemInitTy;
- typedef Expr ExprTy;
- typedef Stmt StmtTy;
- typedef TemplateParameterList TemplateParamsTy;
- typedef NestedNameSpecifier CXXScopeTy;
OpenCLOptions OpenCLFeatures;
FPOptions FPFeatures;
@@ -190,7 +187,7 @@ public:
Preprocessor &PP;
ASTContext &Context;
ASTConsumer &Consumer;
- Diagnostic &Diags;
+ DiagnosticsEngine &Diags;
SourceManager &SourceMgr;
/// \brief Flag indicating whether or not to collect detailed statistics.
@@ -205,6 +202,10 @@ public:
/// CurContext - This is the current declaration context of parsing.
DeclContext *CurContext;
+ /// \brief Generally null except when we temporarily switch decl contexts,
+ /// like in \see ActOnObjCTemporaryExitContainerContext.
+ DeclContext *OriginalLexicalContext;
+
/// VAListTagName - The declaration name corresponding to __va_list_tag.
/// This is used as part of a hack to omit that class from ADL results.
DeclarationName VAListTagName;
@@ -228,16 +229,20 @@ public:
/// This array is never empty. Clients should ignore the first
/// element, which is used to cache a single FunctionScopeInfo
/// that's used to parse every top-level function.
- llvm::SmallVector<sema::FunctionScopeInfo *, 4> FunctionScopes;
+ SmallVector<sema::FunctionScopeInfo *, 4> FunctionScopes;
/// ExprTemporaries - This is the stack of temporaries that are created by
/// the current full expression.
- llvm::SmallVector<CXXTemporary*, 8> ExprTemporaries;
+ SmallVector<CXXTemporary*, 8> ExprTemporaries;
+
+ typedef LazyVector<TypedefNameDecl *, ExternalSemaSource,
+ &ExternalSemaSource::ReadExtVectorDecls, 2, 2>
+ ExtVectorDeclsType;
/// ExtVectorDecls - This is a list all the extended vector types. This allows
/// us to associate a raw vector type with one of the ext_vector type names.
/// This is only necessary for issuing pretty diagnostics.
- llvm::SmallVector<TypedefNameDecl*, 24> ExtVectorDecls;
+ ExtVectorDeclsType ExtVectorDecls;
/// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes.
llvm::OwningPtr<CXXFieldCollector> FieldCollector;
@@ -279,22 +284,38 @@ public:
/// we find this declaration of "foo" and complain that it is
/// not visible.
llvm::DenseMap<DeclarationName, NamedDecl *> LocallyScopedExternalDecls;
+
+ /// \brief Look for a locally scoped external declaration by the given name.
+ llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
+ findLocallyScopedExternalDecl(DeclarationName Name);
+
+ typedef LazyVector<VarDecl *, ExternalSemaSource,
+ &ExternalSemaSource::ReadTentativeDefinitions, 2, 2>
+ TentativeDefinitionsType;
/// \brief All the tentative definitions encountered in the TU.
- llvm::SmallVector<VarDecl *, 2> TentativeDefinitions;
+ TentativeDefinitionsType TentativeDefinitions;
+ typedef LazyVector<const DeclaratorDecl *, ExternalSemaSource,
+ &ExternalSemaSource::ReadUnusedFileScopedDecls, 2, 2>
+ UnusedFileScopedDeclsType;
+
/// \brief The set of file scoped decls seen so far that have not been used
/// and must warn if not used. Only contains the first declaration.
- llvm::SmallVector<const DeclaratorDecl*, 4> UnusedFileScopedDecls;
+ UnusedFileScopedDeclsType UnusedFileScopedDecls;
+
+ typedef LazyVector<CXXConstructorDecl *, ExternalSemaSource,
+ &ExternalSemaSource::ReadDelegatingConstructors, 2, 2>
+ DelegatingCtorDeclsType;
/// \brief All the delegating constructors seen so far in the file, used for
/// cycle detection at the end of the TU.
- llvm::SmallVector<CXXConstructorDecl*, 4> DelegatingCtorDecls;
+ DelegatingCtorDeclsType DelegatingCtorDecls;
/// \brief All the overriding destructors seen during a class definition
/// (there could be multiple due to nested classes) that had their exception
/// spec checks delayed, plus the overridden destructor.
- llvm::SmallVector<std::pair<const CXXDestructorDecl*,
+ SmallVector<std::pair<const CXXDestructorDecl*,
const CXXDestructorDecl*>, 2>
DelayedDestructorExceptionSpecChecks;
@@ -431,32 +452,17 @@ public:
/// WeakUndeclaredIdentifiers - Identifiers contained in
/// #pragma weak before declared. rare. may alias another
/// identifier, declared or undeclared
- class WeakInfo {
- IdentifierInfo *alias; // alias (optional)
- SourceLocation loc; // for diagnostics
- bool used; // identifier later declared?
- public:
- WeakInfo()
- : alias(0), loc(SourceLocation()), used(false) {}
- WeakInfo(IdentifierInfo *Alias, SourceLocation Loc)
- : alias(Alias), loc(Loc), used(false) {}
- inline IdentifierInfo * getAlias() const { return alias; }
- inline SourceLocation getLocation() const { return loc; }
- void setUsed(bool Used=true) { used = Used; }
- inline bool getUsed() { return used; }
- bool operator==(WeakInfo RHS) const {
- return alias == RHS.getAlias() && loc == RHS.getLocation();
- }
- bool operator!=(WeakInfo RHS) const { return !(*this == RHS); }
- };
llvm::DenseMap<IdentifierInfo*,WeakInfo> WeakUndeclaredIdentifiers;
+ /// \brief Load weak undeclared identifiers from the external source.
+ void LoadExternalWeakUndeclaredIdentifiers();
+
/// WeakTopLevelDecl - Translation-unit scoped declarations generated by
/// #pragma weak during processing of other Decls.
/// I couldn't figure out a clean way to generate these in-line, so
/// we store them here and handle separately -- which is a hack.
/// It would be best to refactor this.
- llvm::SmallVector<Decl*,2> WeakTopLevelDecl;
+ SmallVector<Decl*,2> WeakTopLevelDecl;
IdentifierResolver IdResolver;
@@ -482,13 +488,21 @@ public:
/// have been declared.
bool GlobalNewDeleteDeclared;
+
+ /// A flag that is set when parsing a -dealloc method and no [super dealloc]
+ /// call was found yet.
+ bool ObjCShouldCallSuperDealloc;
+ /// A flag that is set when parsing a -finalize method and no [super finalize]
+ /// call was found yet.
+ bool ObjCShouldCallSuperFinalize;
+
/// \brief The set of declarations that have been referenced within
/// a potentially evaluated expression.
- typedef llvm::SmallVector<std::pair<SourceLocation, Decl *>, 10>
+ typedef SmallVector<std::pair<SourceLocation, Decl *>, 10>
PotentiallyReferencedDecls;
/// \brief A set of diagnostics that may be emitted.
- typedef llvm::SmallVector<std::pair<SourceLocation, PartialDiagnostic>, 10>
+ typedef SmallVector<std::pair<SourceLocation, PartialDiagnostic>, 10>
PotentiallyEmittedDiagnostics;
/// \brief Describes how the expressions currently being parsed are
@@ -578,7 +592,7 @@ public:
};
/// A stack of expression evaluation contexts.
- llvm::SmallVector<ExpressionEvaluationContextRecord, 8> ExprEvalContexts;
+ SmallVector<ExpressionEvaluationContextRecord, 8> ExprEvalContexts;
/// SpecialMemberOverloadResult - The overloading result for a special member
/// function.
@@ -618,23 +632,21 @@ public:
/// for C++ records.
llvm::FoldingSet<SpecialMemberOverloadResult> SpecialMemberCache;
- /// \brief Whether the code handled by Sema should be considered a
- /// complete translation unit or not.
+ /// \brief The kind of translation unit we are processing.
///
- /// When true (which is generally the case), Sema will perform
+ /// When we're processing a complete translation unit, Sema will perform
/// end-of-translation-unit semantic tasks (such as creating
/// initializers for tentative definitions in C) once parsing has
- /// completed. This flag will be false when building PCH files,
- /// since a PCH file is by definition not a complete translation
- /// unit.
- bool CompleteTranslationUnit;
+ /// completed. Modules and precompiled headers perform different kinds of
+ /// checks.
+ TranslationUnitKind TUKind;
llvm::BumpPtrAllocator BumpAlloc;
/// \brief The number of SFINAE diagnostics that have been trapped.
unsigned NumSFINAEErrors;
- typedef llvm::DenseMap<ParmVarDecl *, llvm::SmallVector<ParmVarDecl *, 1> >
+ typedef llvm::DenseMap<ParmVarDecl *, SmallVector<ParmVarDecl *, 1> >
UnparsedDefaultArgInstantiationsMap;
/// \brief A mapping from parameters with unparsed default arguments to the
@@ -673,7 +685,7 @@ public:
bool isSelfExpr(Expr *RExpr);
public:
Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
- bool CompleteTranslationUnit = true,
+ TranslationUnitKind TUKind = TU_Complete,
CodeCompleteConsumer *CompletionConsumer = 0);
~Sema();
@@ -685,7 +697,7 @@ public:
OpenCLOptions &getOpenCLOptions() { return OpenCLFeatures; }
FPOptions &getFPOptions() { return FPFeatures; }
- Diagnostic &getDiagnostics() const { return Diags; }
+ DiagnosticsEngine &getDiagnostics() const { return Diags; }
SourceManager &getSourceManager() const { return SourceMgr; }
const TargetAttributesSema &getTargetAttributesSema() const;
Preprocessor &getPreprocessor() const { return PP; }
@@ -727,7 +739,7 @@ public:
/// \brief Build a partial diagnostic.
PartialDiagnostic PDiag(unsigned DiagID = 0); // in SemaInternal.h
- bool findMacroSpelling(SourceLocation &loc, llvm::StringRef name);
+ bool findMacroSpelling(SourceLocation &loc, StringRef name);
ExprResult Owned(Expr* E) { return E; }
ExprResult Owned(ExprResult R) { return R; }
@@ -754,7 +766,7 @@ public:
sema::BlockScopeInfo *getCurBlock();
/// WeakTopLevelDeclDecls - access to #pragma weak-generated Decls
- llvm::SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; }
+ SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; }
//===--------------------------------------------------------------------===//
// Type Analysis / Processing: SemaType.cpp.
@@ -785,6 +797,7 @@ public:
QualType BuildBlockPointerType(QualType T,
SourceLocation Loc, DeclarationName Entity);
QualType BuildParenType(QualType T);
+ QualType BuildAtomicType(QualType T, SourceLocation Loc);
TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S);
TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy);
@@ -819,6 +832,10 @@ public:
TypeResult ActOnTypeName(Scope *S, Declarator &D);
+ /// \brief The parser has parsed the context-sensitive type 'instancetype'
+ /// in an Objective-C message declaration. Return the appropriate type.
+ ParsedType ActOnObjCInstanceType(SourceLocation Loc);
+
bool RequireCompleteType(SourceLocation Loc, QualType T,
const PartialDiagnostic &PD,
std::pair<SourceLocation, PartialDiagnostic> Note);
@@ -830,6 +847,9 @@ public:
std::pair<SourceLocation,
PartialDiagnostic> Note);
+ bool RequireLiteralType(SourceLocation Loc, QualType T,
+ const PartialDiagnostic &PD,
+ bool AllowIncompleteType = false);
QualType getElaboratedType(ElaboratedTypeKeyword Keyword,
const CXXScopeSpec &SS, QualType T);
@@ -853,9 +873,10 @@ public:
bool isClassName = false,
bool HasTrailingDot = false,
ParsedType ObjectType = ParsedType(),
- bool WantNontrivialTypeSourceInfo = false);
+ bool WantNontrivialTypeSourceInfo = false,
+ IdentifierInfo **CorrectedII = 0);
TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S);
- bool isMicrosoftMissingTypename(const CXXScopeSpec *SS);
+ bool isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S);
bool DiagnoseUnknownTypeName(const IdentifierInfo &II,
SourceLocation IILoc,
Scope *S,
@@ -966,8 +987,7 @@ public:
Decl *ActOnDeclarator(Scope *S, Declarator &D);
Decl *HandleDeclarator(Scope *S, Declarator &D,
- MultiTemplateParamsArg TemplateParameterLists,
- bool IsFunctionDefinition);
+ MultiTemplateParamsArg TemplateParameterLists);
void RegisterLocallyScopedExternCDecl(NamedDecl *ND,
const LookupResult &Previous,
Scope *S);
@@ -978,31 +998,46 @@ public:
void CheckCastAlign(Expr *Op, QualType T, SourceRange TRange);
void CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *D);
NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R, TypeSourceInfo *TInfo,
- LookupResult &Previous, bool &Redeclaration);
+ TypeSourceInfo *TInfo,
+ LookupResult &Previous);
NamedDecl* ActOnTypedefNameDecl(Scope* S, DeclContext* DC, TypedefNameDecl *D,
LookupResult &Previous, bool &Redeclaration);
NamedDecl* ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R, TypeSourceInfo *TInfo,
+ TypeSourceInfo *TInfo,
LookupResult &Previous,
- MultiTemplateParamsArg TemplateParamLists,
- bool &Redeclaration);
- void CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous,
- bool &Redeclaration);
+ MultiTemplateParamsArg TemplateParamLists);
+ // Returns true if the variable declaration is a redeclaration
+ bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
void CheckCompleteVariableDeclaration(VarDecl *var);
NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R, TypeSourceInfo *TInfo,
+ TypeSourceInfo *TInfo,
LookupResult &Previous,
MultiTemplateParamsArg TemplateParamLists,
- bool IsFunctionDefinition,
- bool &Redeclaration);
+ bool &AddToScope);
bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
+
+ /// \brief The kind of constexpr declaration checking we are performing.
+ ///
+ /// The kind affects which diagnostics (if any) are emitted if the function
+ /// does not satisfy the requirements of a constexpr function declaration.
+ enum CheckConstexprKind {
+ /// \brief Check a constexpr function declaration, and produce errors if it
+ /// does not satisfy the requirements.
+ CCK_Declaration,
+ /// \brief Check a constexpr function template instantiation.
+ CCK_Instantiation,
+ /// \brief Produce notes explaining why an instantiation was not constexpr.
+ CCK_NoteNonConstexprInstantiation
+ };
+ bool CheckConstexprFunctionDecl(const FunctionDecl *FD, CheckConstexprKind CCK);
+ bool CheckConstexprFunctionBody(const FunctionDecl *FD, Stmt *Body);
+
void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
- void CheckFunctionDeclaration(Scope *S,
+ // Returns true if the function declaration is a redeclaration
+ bool CheckFunctionDeclaration(Scope *S,
FunctionDecl *NewFD, LookupResult &Previous,
- bool IsExplicitSpecialization,
- bool &Redeclaration);
- void CheckMain(FunctionDecl *FD);
+ bool IsExplicitSpecialization);
+ void CheckMain(FunctionDecl *FD, const DeclSpec &D);
Decl *ActOnParamDeclarator(Scope *S, Declarator &D);
ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC,
SourceLocation Loc,
@@ -1021,6 +1056,7 @@ public:
bool SetParamDefaultArgument(ParmVarDecl *Param, Expr *DefaultArg,
SourceLocation EqualLoc);
+ void CheckSelfReference(Decl *OrigDecl, Expr *E);
void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit,
bool TypeMayContainAuto);
void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto);
@@ -1041,9 +1077,14 @@ public:
Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D);
void ActOnStartOfObjCMethodDef(Scope *S, Decl *D);
+ void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope);
Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body);
Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation);
+ /// ActOnFinishDelayedAttribute - Invoked when we have finished parsing an
+ /// attribute for which parsing is delayed.
+ void ActOnFinishDelayedAttribute(Scope *S, Decl *D, ParsedAttributes &Attrs);
+
/// \brief Diagnose any unused parameters in the given sequence of
/// ParmVarDecl pointers.
void DiagnoseUnusedParameters(ParmVarDecl * const *Begin,
@@ -1062,6 +1103,26 @@ public:
SourceLocation AsmLoc,
SourceLocation RParenLoc);
+ /// \brief The parser has processed a module import declaration.
+ ///
+ /// \param ImportLoc The location of the '__import_module__' keyword.
+ ///
+ /// \param ModuleName The name of the module.
+ ///
+ /// \param ModuleNameLoc The location of the module name.
+ DeclResult ActOnModuleImport(SourceLocation ImportLoc,
+ IdentifierInfo &ModuleName,
+ SourceLocation ModuleNameLoc);
+
+ /// \brief Diagnose that \p New is a module-private redeclaration of
+ /// \p Old.
+ void diagnoseModulePrivateRedeclaration(NamedDecl *New, NamedDecl *Old,
+ SourceLocation ModulePrivateKeyword
+ = SourceLocation());
+
+ /// \brief Retrieve a suitable printing policy.
+ PrintingPolicy getPrintingPolicy() const;
+
/// Scope actions.
void ActOnPopScope(SourceLocation Loc, Scope *S);
void ActOnTranslationUnitScope(Scope *S);
@@ -1097,6 +1158,7 @@ public:
SourceLocation KWLoc, CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr, AccessSpecifier AS,
+ SourceLocation ModulePrivateLoc,
MultiTemplateParamsArg TemplateParameterLists,
bool &OwnedDecl, bool &IsDependent, bool ScopedEnum,
bool ScopedEnumUsesClassTag, TypeResult UnderlyingType);
@@ -1118,7 +1180,7 @@ public:
void ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart,
IdentifierInfo *ClassName,
- llvm::SmallVectorImpl<Decl *> &Decls);
+ SmallVectorImpl<Decl *> &Decls);
Decl *ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart,
Declarator &D, Expr *BitfieldWidth);
@@ -1146,15 +1208,15 @@ public:
bool CheckNontrivialField(FieldDecl *FD);
void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem);
CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD);
- void ActOnLastBitfield(SourceLocation DeclStart, Decl *IntfDecl,
- llvm::SmallVectorImpl<Decl *> &AllIvarDecls);
- Decl *ActOnIvar(Scope *S, SourceLocation DeclStart, Decl *IntfDecl,
+ void ActOnLastBitfield(SourceLocation DeclStart,
+ SmallVectorImpl<Decl *> &AllIvarDecls);
+ Decl *ActOnIvar(Scope *S, SourceLocation DeclStart,
Declarator &D, Expr *BitfieldWidth,
tok::ObjCKeywordKind visibility);
// This is used for both record definitions and ObjC interface declarations.
void ActOnFields(Scope* S, SourceLocation RecLoc, Decl *TagDecl,
- Decl **Fields, unsigned NumFields,
+ llvm::ArrayRef<Decl *> Fields,
SourceLocation LBrac, SourceLocation RBrac,
AttributeList *AttrList);
@@ -1163,6 +1225,8 @@ public:
/// struct, or union).
void ActOnTagStartDefinition(Scope *S, Decl *TagDecl);
+ Decl *ActOnObjCContainerStartDefinition(Decl *IDecl);
+
/// ActOnStartCXXMemberDeclarations - Invoked when we have parsed a
/// C++ record definition's base-specifiers clause and are starting its
/// member declarations.
@@ -1175,6 +1239,15 @@ public:
void ActOnTagFinishDefinition(Scope *S, Decl *TagDecl,
SourceLocation RBraceLoc);
+ void ActOnObjCContainerFinishDefinition();
+
+ /// \brief Invoked when we must temporarily exit the objective-c container
+ /// scope for parsing/looking-up C constructs.
+ ///
+ /// Must be followed by a call to \see ActOnObjCReenterContainerContext
+ void ActOnObjCTemporaryExitContainerContext();
+ void ActOnObjCReenterContainerContext();
+
/// ActOnTagDefinitionError - Invoked when there was an unrecoverable
/// error parsing the definition of a tag.
void ActOnTagDefinitionError(Scope *S, Decl *TagDecl);
@@ -1205,6 +1278,10 @@ public:
void EnterDeclaratorContext(Scope *S, DeclContext *DC);
void ExitDeclaratorContext(Scope *S);
+ /// Push the parameters of D, which must be a function, into scope.
+ void ActOnReenterFunctionContext(Scope* S, Decl* D);
+ void ActOnExitFunctionContext() { PopDeclContext(); }
+
DeclContext *getFunctionLevelDeclContext();
/// getCurFunctionDecl - If inside of a function body, this returns a pointer
@@ -1314,6 +1391,7 @@ public:
bool FunctionArgTypesAreEqual(const FunctionProtoType *OldType,
const FunctionProtoType *NewType);
+ CastKind PrepareCastToObjCObjectPointer(ExprResult &E);
bool CheckPointerConversion(Expr *From, QualType ToType,
CastKind &Kind,
CXXCastPath& BasePath,
@@ -1337,19 +1415,20 @@ public:
QualType ResultType,
Expr *Value,
bool AllowNRVO = true);
-
+
bool CanPerformCopyInitialization(const InitializedEntity &Entity,
ExprResult Init);
ExprResult PerformCopyInitialization(const InitializedEntity &Entity,
SourceLocation EqualLoc,
- ExprResult Init);
+ ExprResult Init,
+ bool TopLevelOfInitList = false);
ExprResult PerformObjectArgumentInitialization(Expr *From,
NestedNameSpecifier *Qualifier,
NamedDecl *FoundDecl,
CXXMethodDecl *Method);
ExprResult PerformContextuallyConvertToBool(Expr *From);
- ExprResult PerformContextuallyConvertToObjCId(Expr *From);
+ ExprResult PerformContextuallyConvertToObjCPointer(Expr *From);
ExprResult
ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *FromE,
@@ -1475,8 +1554,9 @@ public:
bool Complain = false,
DeclAccessPair* Found = 0);
- ExprResult ResolveAndFixSingleFunctionTemplateSpecialization(
- Expr *SrcExpr, bool DoFunctionPointerConverion = false,
+ bool ResolveAndFixSingleFunctionTemplateSpecialization(
+ ExprResult &SrcExpr,
+ bool DoFunctionPointerConverion = false,
bool Complain = false,
const SourceRange& OpRangeForComplaining = SourceRange(),
QualType DestTypeForComplaining = QualType(),
@@ -1678,6 +1758,9 @@ public:
CXXMethodDecl *LookupCopyingAssignment(CXXRecordDecl *Class, unsigned Quals,
bool RValueThis, unsigned ThisQuals,
bool *ConstParam = 0);
+ CXXConstructorDecl *LookupMovingConstructor(CXXRecordDecl *Class);
+ CXXMethodDecl *LookupMovingAssignment(CXXRecordDecl *Class, bool RValueThis,
+ unsigned ThisQuals);
CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class);
void ArgumentDependentLookup(DeclarationName Name, bool Operator,
@@ -1755,6 +1838,10 @@ public:
bool NonInheritable = true, bool Inheritable = true);
void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL,
bool NonInheritable = true, bool Inheritable = 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);
@@ -1762,15 +1849,26 @@ public:
void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
bool &IncompleteImpl, unsigned DiagID);
- void WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethod,
+ void WarnConflictingTypedMethods(ObjCMethodDecl *Method,
ObjCMethodDecl *MethodDecl,
bool IsProtocolMethodDecl);
+
+ void CheckConflictingOverridingMethod(ObjCMethodDecl *Method,
+ ObjCMethodDecl *Overridden,
+ bool IsProtocolMethodDecl);
+
+ /// WarnExactTypedMethods - This routine issues a warning if method
+ /// implementation declaration matches exactly that of its declaration.
+ void WarnExactTypedMethods(ObjCMethodDecl *Method,
+ ObjCMethodDecl *MethodDecl,
+ bool IsProtocolMethodDecl);
bool isPropertyReadonly(ObjCPropertyDecl *PropertyDecl,
ObjCInterfaceDecl *IDecl);
typedef llvm::DenseSet<Selector, llvm::DenseMapInfo<Selector> > SelectorSet;
-
+ typedef llvm::DenseMap<Selector, ObjCMethodDecl*> ProtocolsMethodsMap;
+
/// CheckProtocolMethodDefs - This routine checks unimplemented
/// methods declared in protocol, and those referenced by it.
/// \param IDecl - Used for checking for methods which may have been
@@ -1788,14 +1886,6 @@ public:
ObjCIvarDecl **Fields, unsigned nIvars,
SourceLocation Loc);
- /// \brief Determine whether we can synthesize a provisional ivar for the
- /// given name.
- ObjCPropertyDecl *canSynthesizeProvisionalIvar(IdentifierInfo *II);
-
- /// \brief Determine whether we can synthesize a provisional ivar for the
- /// given property.
- bool canSynthesizeProvisionalIvar(ObjCPropertyDecl *Property);
-
/// ImplMethodsVsClassMethods - This is main routine to warn if any method
/// remains unimplemented in the class or category @implementation.
void ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
@@ -1812,6 +1902,7 @@ public:
/// properties which must be synthesized in class's @implementation.
void DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl,
ObjCInterfaceDecl *IDecl);
+ void DefaultSynthesizeProperties(Scope *S, Decl *D);
/// CollectImmediateProperties - This routine collects all properties in
/// the class and its conforming protocols; but not those it its super class.
@@ -1828,7 +1919,6 @@ public:
/// Called by ActOnProperty to handle @property declarations in
//// class extensions.
Decl *HandlePropertyInClassExtension(Scope *S,
- ObjCCategoryDecl *CDecl,
SourceLocation AtLoc,
FieldDeclarator &FD,
Selector GetterSel,
@@ -1885,7 +1975,13 @@ public:
ObjCImplDecl* IMPDecl,
ObjCContainerDecl* IDecl,
bool &IncompleteImpl,
- bool ImmediateClass);
+ bool ImmediateClass,
+ bool WarnExactMatch=false);
+
+ /// CheckCategoryVsClassMethodMatches - Checks that methods implemented in
+ /// category matches with those implemented in its primary class and
+ /// warns each time an exact match is found.
+ void CheckCategoryVsClassMethodMatches(ObjCCategoryImplDecl *CatIMP);
private:
/// AddMethodToGlobalPool - Add an instance or factory method to the global
@@ -1912,6 +2008,10 @@ public:
AddMethodToGlobalPool(Method, impl, /*instance*/false);
}
+ /// AddAnyMethodToGlobalPool - Add any method, instance or factory to global
+ /// pool.
+ void AddAnyMethodToGlobalPool(Decl *D);
+
/// LookupInstanceMethodInGlobalPool - Returns the method and warns if
/// there are multiple signatures.
ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R,
@@ -1937,7 +2037,7 @@ public:
/// CollectIvarsToConstructOrDestruct - Collect those ivars which require
/// initialization.
void CollectIvarsToConstructOrDestruct(ObjCInterfaceDecl *OI,
- llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
+ SmallVectorImpl<ObjCIvarDecl*> &Ivars);
//===--------------------------------------------------------------------===//
// Statement Parsing Callbacks: SemaStmt.cpp.
@@ -1978,7 +2078,7 @@ public:
StmtResult ActOnExprStmt(FullExprArg Expr);
StmtResult ActOnNullStmt(SourceLocation SemiLoc,
- SourceLocation LeadingEmptyMacroLoc = SourceLocation());
+ bool HasLeadingEmptyMacro = false);
StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R,
MultiStmtArg Elts,
bool isStmtExpr);
@@ -2022,6 +2122,8 @@ public:
FullExprArg Third,
SourceLocation RParenLoc,
Stmt *Body);
+ ExprResult ActOnObjCForCollectionOperand(SourceLocation forLoc,
+ Expr *collection);
StmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc,
SourceLocation LParenLoc,
Stmt *First, Expr *Second,
@@ -2083,6 +2185,8 @@ public:
StmtResult BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw);
StmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw,
Scope *CurScope);
+ ExprResult ActOnObjCAtSynchronizedOperand(SourceLocation atLoc,
+ Expr *operand);
StmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc,
Expr *SynchExpr,
Stmt *SynchBody);
@@ -2141,19 +2245,20 @@ public:
DelayedDiagnostics.popContext(state);
}
- void EmitDeprecationWarning(NamedDecl *D, llvm::StringRef Message,
+ void EmitDeprecationWarning(NamedDecl *D, StringRef Message,
SourceLocation Loc,
const ObjCInterfaceDecl *UnknownObjCClass=0);
void HandleDelayedDeprecationCheck(sema::DelayedDiagnostic &DD, Decl *Ctx);
bool makeUnavailableInSystemHeader(SourceLocation loc,
- llvm::StringRef message);
+ StringRef message);
//===--------------------------------------------------------------------===//
// Expression Parsing Callbacks: SemaExpr.cpp.
- bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
+ bool CanUseDecl(NamedDecl *D);
+ bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
const ObjCInterfaceDecl *UnknownObjCClass=0);
std::string getDeletedOrUnavailableSuffix(const FunctionDecl *FD);
bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD,
@@ -2172,12 +2277,16 @@ public:
void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
void MarkDeclarationsReferencedInExpr(Expr *E);
+ /// \brief Try to recover by turning the given expression into a
+ /// call. Returns true if recovery was attempted or an error was
+ /// emitted; this may also leave the ExprResult invalid.
+ bool tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD,
+ bool ForceComplain = false,
+ bool (*IsPlausibleResult)(QualType) = 0);
+
/// \brief Figure out if an expression could be turned into a call.
bool isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy,
UnresolvedSetImpl &NonTemplateOverloads);
- /// \brief Give notes for a set of overloads.
- void NoteOverloads(const UnresolvedSetImpl &Overloads,
- const SourceLocation FinalNoteLoc);
/// \brief Conditionally issue a diagnostic based on the current
/// evaluation context.
@@ -2186,17 +2295,13 @@ public:
/// the function body is parsed, and then do a basic reachability analysis to
/// determine if the statement is reachable. If it is unreachable, the
/// diagnostic will not be emitted.
- bool DiagRuntimeBehavior(SourceLocation Loc, const Stmt *stmt,
+ bool DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement,
const PartialDiagnostic &PD);
// Primary Expressions.
SourceRange getExprRange(Expr *E) const;
-
- ObjCIvarDecl *SynthesizeProvisionalIvar(LookupResult &Lookup,
- IdentifierInfo *II,
- SourceLocation NameLoc);
- ExprResult ActOnIdExpression(Scope *S, CXXScopeSpec &SS, UnqualifiedId &Name,
+ ExprResult ActOnIdExpression(Scope *S, CXXScopeSpec &SS, UnqualifiedId &Id,
bool HasTrailingLParen, bool IsAddressOfOperand);
void DecomposeUnqualifiedId(const UnqualifiedId &Id,
@@ -2205,9 +2310,12 @@ public:
const TemplateArgumentListInfo *&TemplateArgs);
bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
- CorrectTypoContext CTC = CTC_Unknown);
+ CorrectTypoContext CTC = CTC_Unknown,
+ TemplateArgumentListInfo *ExplicitTemplateArgs = 0,
+ Expr **Args = 0, unsigned NumArgs = 0);
- ExprResult LookupInObjCMethod(LookupResult &R, Scope *S, IdentifierInfo *II,
+ ExprResult LookupInObjCMethod(LookupResult &LookUp, Scope *S,
+ IdentifierInfo *II,
bool AllowBuiltinCreation=false);
ExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS,
@@ -2248,29 +2356,30 @@ public:
ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS,
LookupResult &R,
- bool ADL);
+ bool NeedsADL);
ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS,
const DeclarationNameInfo &NameInfo,
NamedDecl *D);
ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
- ExprResult ActOnNumericConstant(const Token &);
- ExprResult ActOnCharacterConstant(const Token &);
- ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *Val);
+ ExprResult ActOnNumericConstant(const Token &Tok);
+ ExprResult ActOnCharacterConstant(const Token &Tok);
+ ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E);
ExprResult ActOnParenOrParenListExpr(SourceLocation L,
SourceLocation R,
MultiExprArg Val);
/// ActOnStringLiteral - The specified tokens were lexed as pasted string
/// fragments (e.g. "foo" "bar" L"baz").
- ExprResult ActOnStringLiteral(const Token *Toks, unsigned NumToks);
+ ExprResult ActOnStringLiteral(const Token *StringToks,
+ unsigned NumStringToks);
ExprResult ActOnGenericSelectionExpr(SourceLocation KeyLoc,
SourceLocation DefaultLoc,
SourceLocation RParenLoc,
Expr *ControllingExpr,
- MultiTypeArg Types,
- MultiExprArg Exprs);
+ MultiTypeArg ArgTypes,
+ MultiExprArg ArgExprs);
ExprResult CreateGenericSelectionExpr(SourceLocation KeyLoc,
SourceLocation DefaultLoc,
SourceLocation RParenLoc,
@@ -2281,13 +2390,13 @@ public:
// Binary/Unary Operators. 'Tok' is the token for the operator.
ExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
- Expr *InputArg);
+ Expr *InputExpr);
ExprResult BuildUnaryOp(Scope *S, SourceLocation OpLoc,
- UnaryOperatorKind Opc, Expr *input);
+ UnaryOperatorKind Opc, Expr *Input);
ExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Op, Expr *Input);
- ExprResult CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *T,
+ ExprResult CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
SourceLocation OpLoc,
UnaryExprOrTypeTrait ExprKind,
SourceRange R);
@@ -2296,15 +2405,15 @@ public:
ExprResult
ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc,
UnaryExprOrTypeTrait ExprKind,
- bool isType, void *TyOrEx,
+ bool IsType, void *TyOrEx,
const SourceRange &ArgRange);
ExprResult CheckPlaceholderExpr(Expr *E);
bool CheckVecStepExpr(Expr *E);
bool CheckUnaryExprOrTypeTraitOperand(Expr *E, UnaryExprOrTypeTrait ExprKind);
- bool CheckUnaryExprOrTypeTraitOperand(QualType type, SourceLocation OpLoc,
- SourceRange R,
+ bool CheckUnaryExprOrTypeTraitOperand(QualType ExprType, SourceLocation OpLoc,
+ SourceRange ExprRange,
UnaryExprOrTypeTrait ExprKind);
ExprResult ActOnSizeofParameterPackExpr(Scope *S,
SourceLocation OpLoc,
@@ -2364,30 +2473,34 @@ public:
FunctionDecl *FDecl,
const FunctionProtoType *Proto,
Expr **Args, unsigned NumArgs,
- SourceLocation RParenLoc);
+ SourceLocation RParenLoc,
+ bool ExecConfig = false);
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
/// This provides the location of the left/right parens and a list of comma
/// locations.
ExprResult ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
- MultiExprArg Args, SourceLocation RParenLoc,
- Expr *ExecConfig = 0);
+ MultiExprArg ArgExprs, SourceLocation RParenLoc,
+ Expr *ExecConfig = 0, bool IsExecConfig = false);
ExprResult BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
SourceLocation RParenLoc,
- Expr *ExecConfig = 0);
+ Expr *Config = 0,
+ bool IsExecConfig = false);
ExprResult ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc,
- MultiExprArg ExecConfig, SourceLocation GGGLoc);
+ MultiExprArg ExecConfig,
+ SourceLocation GGGLoc);
ExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
Declarator &D, ParsedType &Ty,
- SourceLocation RParenLoc, Expr *Op);
+ SourceLocation RParenLoc, Expr *CastExpr);
ExprResult BuildCStyleCastExpr(SourceLocation LParenLoc,
TypeSourceInfo *Ty,
SourceLocation RParenLoc,
Expr *Op);
+ CastKind PrepareScalarCast(ExprResult &src, QualType destType);
/// \brief Build an altivec or OpenCL literal.
ExprResult BuildVectorLiteral(SourceLocation LParenLoc,
@@ -2399,16 +2512,16 @@ public:
ExprResult ActOnCompoundLiteral(SourceLocation LParenLoc,
ParsedType Ty,
SourceLocation RParenLoc,
- Expr *Op);
+ Expr *InitExpr);
ExprResult BuildCompoundLiteralExpr(SourceLocation LParenLoc,
TypeSourceInfo *TInfo,
SourceLocation RParenLoc,
- Expr *InitExpr);
+ Expr *LiteralExpr);
- ExprResult ActOnInitList(SourceLocation LParenLoc,
- MultiExprArg InitList,
- SourceLocation RParenLoc);
+ ExprResult ActOnInitList(SourceLocation LBraceLoc,
+ MultiExprArg InitArgList,
+ SourceLocation RBraceLoc);
ExprResult ActOnDesignatedInitializer(Designation &Desig,
SourceLocation Loc,
@@ -2416,21 +2529,21 @@ public:
ExprResult Init);
ExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc,
- tok::TokenKind Kind, Expr *LHS, Expr *RHS);
+ tok::TokenKind Kind, Expr *LHSExpr, Expr *RHSExpr);
ExprResult BuildBinOp(Scope *S, SourceLocation OpLoc,
- BinaryOperatorKind Opc, Expr *lhs, Expr *rhs);
- ExprResult CreateBuiltinBinOp(SourceLocation TokLoc,
- BinaryOperatorKind Opc, Expr *lhs, Expr *rhs);
+ BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr);
+ ExprResult CreateBuiltinBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc,
+ Expr *LHSExpr, Expr *RHSExpr);
/// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
/// in the case of a the GNU conditional expr extension.
ExprResult ActOnConditionalOp(SourceLocation QuestionLoc,
SourceLocation ColonLoc,
- Expr *Cond, Expr *LHS, Expr *RHS);
+ Expr *CondExpr, Expr *LHSExpr, Expr *RHSExpr);
/// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo".
ExprResult ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
- LabelDecl *LD);
+ LabelDecl *TheDecl);
ExprResult ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
SourceLocation RPLoc); // "({..})"
@@ -2441,7 +2554,7 @@ public:
bool isBrackets; // true if [expr], false if .ident
union {
IdentifierInfo *IdentInfo;
- ExprTy *E;
+ Expr *E;
} U;
};
@@ -2454,28 +2567,26 @@ public:
ExprResult ActOnBuiltinOffsetOf(Scope *S,
SourceLocation BuiltinLoc,
SourceLocation TypeLoc,
- ParsedType Arg1,
+ ParsedType ParsedArgTy,
OffsetOfComponent *CompPtr,
unsigned NumComponents,
SourceLocation RParenLoc);
// __builtin_choose_expr(constExpr, expr1, expr2)
ExprResult ActOnChooseExpr(SourceLocation BuiltinLoc,
- Expr *cond, Expr *expr1,
- Expr *expr2, SourceLocation RPLoc);
+ Expr *CondExpr, Expr *LHSExpr,
+ Expr *RHSExpr, SourceLocation RPLoc);
// __builtin_va_arg(expr, type)
- ExprResult ActOnVAArg(SourceLocation BuiltinLoc,
- Expr *expr, ParsedType type,
+ ExprResult ActOnVAArg(SourceLocation BuiltinLoc, Expr *E, ParsedType Ty,
SourceLocation RPLoc);
- ExprResult BuildVAArgExpr(SourceLocation BuiltinLoc,
- Expr *expr, TypeSourceInfo *TInfo,
- SourceLocation RPLoc);
+ ExprResult BuildVAArgExpr(SourceLocation BuiltinLoc, Expr *E,
+ TypeSourceInfo *TInfo, SourceLocation RPLoc);
// __null
ExprResult ActOnGNUNullExpr(SourceLocation TokenLoc);
- bool CheckCaseExpression(Expr *expr);
+ bool CheckCaseExpression(Expr *E);
bool CheckMicrosoftIfExistsSymbol(CXXScopeSpec &SS, UnqualifiedId &Name);
@@ -2495,13 +2606,13 @@ public:
/// ActOnBlockStmtExpr - This is called when the body of a block statement
/// literal was successfully completed. ^(int x){...}
- ExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc,
- Stmt *Body, Scope *CurScope);
+ ExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, Stmt *Body,
+ Scope *CurScope);
//===---------------------------- OpenCL Features -----------------------===//
/// __builtin_astype(...)
- ExprResult ActOnAsTypeExpr(Expr *expr, ParsedType DestTy,
+ ExprResult ActOnAsTypeExpr(Expr *E, ParsedType ParsedDestTy,
SourceLocation BuiltinLoc,
SourceLocation RParenLoc);
@@ -2594,7 +2705,8 @@ public:
/// and sets it as the initializer for the the passed in VarDecl.
bool InitializeVarWithConstructor(VarDecl *VD,
CXXConstructorDecl *Constructor,
- MultiExprArg Exprs);
+ MultiExprArg Exprs,
+ bool HadMultipleCandidates);
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
/// including handling of its default argument expressions.
@@ -2603,16 +2715,16 @@ public:
ExprResult
BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor, MultiExprArg Exprs,
- bool RequiresZeroInit, unsigned ConstructKind,
- SourceRange ParenRange);
+ bool HadMultipleCandidates, bool RequiresZeroInit,
+ unsigned ConstructKind, SourceRange ParenRange);
// FIXME: Can re remove this and have the above BuildCXXConstructExpr check if
// the constructor can be elidable?
ExprResult
BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor, bool Elidable,
- MultiExprArg Exprs, bool RequiresZeroInit,
- unsigned ConstructKind,
+ MultiExprArg Exprs, bool HadMultipleCandidates,
+ bool RequiresZeroInit, unsigned ConstructKind,
SourceRange ParenRange);
/// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating
@@ -2645,7 +2757,7 @@ public:
// any other specification (even 'none', to keep this rule simple).
ExceptionSpecificationType ComputedEST;
llvm::SmallPtrSet<CanQualType, 4> ExceptionsSeen;
- llvm::SmallVector<QualType, 4> Exceptions;
+ SmallVector<QualType, 4> Exceptions;
void ClearExceptions() {
ExceptionsSeen.clear();
@@ -2710,23 +2822,33 @@ public:
std::pair<ImplicitExceptionSpecification, bool>
ComputeDefaultedCopyAssignmentExceptionSpecAndConst(CXXRecordDecl *ClassDecl);
+ /// \brief Determine what sort of exception specification a defaulted move
+ /// constructor of a class will have.
+ ImplicitExceptionSpecification
+ ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl);
+
+ /// \brief Determine what sort of exception specification a defaulted move
+ /// assignment operator of a class will have.
+ ImplicitExceptionSpecification
+ ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl);
+
/// \brief Determine what sort of exception specification a defaulted
/// destructor of a class will have.
ImplicitExceptionSpecification
ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl);
- /// \brief Determine if a defaulted default constructor ought to be
- /// deleted.
- bool ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD);
-
- /// \brief Determine if a defaulted copy constructor ought to be
- /// deleted.
- bool ShouldDeleteCopyConstructor(CXXConstructorDecl *CD);
+ /// \brief Determine if a special member function should have a deleted
+ /// definition when it is defaulted.
+ bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM);
/// \brief Determine if a defaulted copy assignment operator ought to be
/// deleted.
bool ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD);
+ /// \brief Determine if a defaulted move assignment operator ought to be
+ /// deleted.
+ bool ShouldDeleteMoveAssignmentOperator(CXXMethodDecl *MD);
+
/// \brief Determine if a defaulted destructor ought to be deleted.
bool ShouldDeleteDestructor(CXXDestructorDecl *DD);
@@ -2772,9 +2894,6 @@ public:
/// \brief Declare the implicit copy constructor for the given class.
///
- /// \param S The scope of the class, which may be NULL if this is a
- /// template instantiation.
- ///
/// \param ClassDecl The class declaration into which the implicit
/// copy constructor will be added.
///
@@ -2786,21 +2905,45 @@ public:
void DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *Constructor);
- /// \brief Declare the implicit copy assignment operator for the given class.
+ /// \brief Declare the implicit move constructor for the given class.
///
- /// \param S The scope of the class, which may be NULL if this is a
- /// template instantiation.
+ /// \param ClassDecl The Class declaration into which the implicit
+ /// move constructor will be added.
+ ///
+ /// \returns The implicitly-declared move constructor, or NULL if it wasn't
+ /// declared.
+ CXXConstructorDecl *DeclareImplicitMoveConstructor(CXXRecordDecl *ClassDecl);
+
+ /// DefineImplicitMoveConstructor - Checks for feasibility of
+ /// defining this constructor as the move constructor.
+ void DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
+ CXXConstructorDecl *Constructor);
+
+ /// \brief Declare the implicit copy assignment operator for the given class.
///
/// \param ClassDecl The class declaration into which the implicit
- /// copy-assignment operator will be added.
+ /// copy assignment operator will be added.
///
/// \returns The implicitly-declared copy assignment operator.
CXXMethodDecl *DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl);
- /// \brief Defined an implicitly-declared copy assignment operator.
+ /// \brief Defines an implicitly-declared copy assignment operator.
void DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
CXXMethodDecl *MethodDecl);
+ /// \brief Declare the implicit move assignment operator for the given class.
+ ///
+ /// \param ClassDecl The Class declaration into which the implicit
+ /// move assignment operator will be added.
+ ///
+ /// \returns The implicitly-declared move assignment operator, or NULL if it
+ /// wasn't declared.
+ CXXMethodDecl *DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl);
+
+ /// \brief Defines an implicitly-declared move assignment operator.
+ void DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
+ CXXMethodDecl *MethodDecl);
+
/// \brief Force the declaration of any implicitly-declared members of this
/// class.
void ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class);
@@ -3231,7 +3374,8 @@ public:
TypeSourceInfo *EncodedTypeInfo,
SourceLocation RParenLoc);
ExprResult BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl,
- CXXMethodDecl *Method);
+ CXXMethodDecl *Method,
+ bool HadMultipleCandidates);
ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc,
SourceLocation EncodeLoc,
@@ -3259,7 +3403,7 @@ public:
Decl *ActOnStartLinkageSpecification(Scope *S,
SourceLocation ExternLoc,
SourceLocation LangLoc,
- llvm::StringRef Lang,
+ StringRef Lang,
SourceLocation LBraceLoc);
Decl *ActOnFinishLinkageSpecification(Scope *S,
Decl *LinkageSpec,
@@ -3272,16 +3416,16 @@ public:
bool isCurrentClassName(const IdentifierInfo &II, Scope *S,
const CXXScopeSpec *SS = 0);
- Decl *ActOnAccessSpecifier(AccessSpecifier Access,
- SourceLocation ASLoc,
- SourceLocation ColonLoc);
+ bool ActOnAccessSpecifier(AccessSpecifier Access,
+ SourceLocation ASLoc,
+ SourceLocation ColonLoc,
+ AttributeList *Attrs = 0);
Decl *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS,
Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
Expr *BitfieldWidth, const VirtSpecifiers &VS,
- Expr *Init, bool HasDeferredInit,
- bool IsDefinition);
+ bool HasDeferredInit);
void ActOnCXXInClassMemberInitializer(Decl *VarDecl, SourceLocation EqualLoc,
Expr *Init);
@@ -3296,24 +3440,37 @@ public:
SourceLocation RParenLoc,
SourceLocation EllipsisLoc);
- MemInitResult BuildMemberInitializer(ValueDecl *Member, Expr **Args,
- unsigned NumArgs, SourceLocation IdLoc,
- SourceLocation LParenLoc,
- SourceLocation RParenLoc);
+ MemInitResult ActOnMemInitializer(Decl *ConstructorD,
+ Scope *S,
+ CXXScopeSpec &SS,
+ IdentifierInfo *MemberOrBase,
+ ParsedType TemplateTypeTy,
+ SourceLocation IdLoc,
+ Expr *InitList,
+ SourceLocation EllipsisLoc);
+
+ MemInitResult BuildMemInitializer(Decl *ConstructorD,
+ Scope *S,
+ CXXScopeSpec &SS,
+ IdentifierInfo *MemberOrBase,
+ ParsedType TemplateTypeTy,
+ SourceLocation IdLoc,
+ const MultiInitializer &Init,
+ SourceLocation EllipsisLoc);
+
+ MemInitResult BuildMemberInitializer(ValueDecl *Member,
+ const MultiInitializer &Args,
+ SourceLocation IdLoc);
MemInitResult BuildBaseInitializer(QualType BaseType,
TypeSourceInfo *BaseTInfo,
- Expr **Args, unsigned NumArgs,
- SourceLocation LParenLoc,
- SourceLocation RParenLoc,
+ const MultiInitializer &Args,
CXXRecordDecl *ClassDecl,
SourceLocation EllipsisLoc);
MemInitResult BuildDelegatingInitializer(TypeSourceInfo *TInfo,
- Expr **Args, unsigned NumArgs,
+ const MultiInitializer &Args,
SourceLocation BaseLoc,
- SourceLocation RParenLoc,
- SourceLocation LParenLoc,
CXXRecordDecl *ClassDecl);
bool SetDelegatingInitializer(CXXConstructorDecl *Constructor,
@@ -3339,7 +3496,7 @@ public:
/// \brief The list of vtables that are required but have not yet been
/// materialized.
- llvm::SmallVector<VTableUse, 16> VTableUses;
+ SmallVector<VTableUse, 16> VTableUses;
/// \brief The set of classes whose vtables have been used within
/// this translation unit, and a bit that will be true if the vtable is
@@ -3347,9 +3504,16 @@ public:
/// by code generation).
llvm::DenseMap<CXXRecordDecl *, bool> VTablesUsed;
+ /// \brief Load any externally-stored vtable uses.
+ void LoadExternalVTableUses();
+
+ typedef LazyVector<CXXRecordDecl *, ExternalSemaSource,
+ &ExternalSemaSource::ReadDynamicClasses, 2, 2>
+ DynamicClassesType;
+
/// \brief A list of all of the dynamic classes in this translation
/// unit.
- llvm::SmallVector<CXXRecordDecl *, 16> DynamicClasses;
+ DynamicClassesType DynamicClasses;
/// \brief Note that the vtable for the given class was used at the
/// given location.
@@ -3372,7 +3536,8 @@ public:
void ActOnMemInitializers(Decl *ConstructorDecl,
SourceLocation ColonLoc,
- MemInitTy **MemInits, unsigned NumMemInits,
+ CXXCtorInitializer **MemInits,
+ unsigned NumMemInits,
bool AnyErrors);
void CheckCompletedCXXClass(CXXRecordDecl *Record);
@@ -3401,9 +3566,9 @@ public:
FriendDecl *CheckFriendTypeDecl(SourceLocation FriendLoc,
TypeSourceInfo *TSInfo);
Decl *ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
+ MultiTemplateParamsArg TemplateParams);
+ Decl *ActOnFriendFunctionDecl(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParams);
- Decl *ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
- MultiTemplateParamsArg TemplateParams);
QualType CheckConstructorDeclarator(Declarator &D, QualType R,
StorageClass& SC);
@@ -3419,6 +3584,8 @@ public:
void CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *Ctor);
void CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *Ctor);
void CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *Method);
+ void CheckExplicitlyDefaultedMoveConstructor(CXXConstructorDecl *Ctor);
+ void CheckExplicitlyDefaultedMoveAssignment(CXXMethodDecl *Method);
void CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *Dtor);
//===--------------------------------------------------------------------===//
@@ -3441,7 +3608,8 @@ public:
bool AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
unsigned NumBases);
- void ActOnBaseSpecifiers(Decl *ClassDecl, BaseTy **Bases, unsigned NumBases);
+ void ActOnBaseSpecifiers(Decl *ClassDecl, CXXBaseSpecifier **Bases,
+ unsigned NumBases);
bool IsDerivedFrom(QualType Derived, QualType Base);
bool IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths);
@@ -3538,6 +3706,7 @@ public:
bool ForceCheck = false,
bool ForceUnprivileged = false);
void CheckLookupAccess(const LookupResult &R);
+ bool IsSimplyAccessible(NamedDecl *decl, CXXRecordDecl *Class);
void HandleDependentAccessCheck(const DependentDiagnostic &DD,
const MultiLevelTemplateArgumentList &TemplateArgs);
@@ -3626,7 +3795,7 @@ public:
Expr *DefaultArg);
Decl *ActOnTemplateTemplateParameter(Scope *S,
SourceLocation TmpLoc,
- TemplateParamsTy *Params,
+ TemplateParameterList *Params,
SourceLocation EllipsisLoc,
IdentifierInfo *ParamName,
SourceLocation ParamNameLoc,
@@ -3635,7 +3804,7 @@ public:
SourceLocation EqualLoc,
ParsedTemplateArgument DefaultArg);
- TemplateParamsTy *
+ TemplateParameterList *
ActOnTemplateParameterList(unsigned Depth,
SourceLocation ExportLoc,
SourceLocation TemplateLoc,
@@ -3672,7 +3841,8 @@ public:
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr,
TemplateParameterList *TemplateParams,
- AccessSpecifier AS,
+ AccessSpecifier AS,
+ SourceLocation ModulePrivateLoc,
unsigned NumOuterTemplateParamLists,
TemplateParameterList **OuterTemplateParamLists);
@@ -3726,6 +3896,7 @@ public:
DeclResult
ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc,
+ SourceLocation ModulePrivateLoc,
CXXScopeSpec &SS,
TemplateTy Template,
SourceLocation TemplateNameLoc,
@@ -3795,7 +3966,7 @@ public:
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
Decl *Param,
- llvm::SmallVectorImpl<TemplateArgument> &Converted);
+ SmallVectorImpl<TemplateArgument> &Converted);
/// \brief Specifies the context in which a particular template
/// argument is being checked.
@@ -3819,7 +3990,7 @@ public:
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
unsigned ArgumentPackIndex,
- llvm::SmallVectorImpl<TemplateArgument> &Converted,
+ SmallVectorImpl<TemplateArgument> &Converted,
CheckTemplateArgumentKind CTAK = CTAK_Specified);
/// \brief Check that the given template arguments can be be provided to
@@ -3847,11 +4018,11 @@ public:
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs,
bool PartialTemplateArgs,
- llvm::SmallVectorImpl<TemplateArgument> &Converted);
+ SmallVectorImpl<TemplateArgument> &Converted);
bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
const TemplateArgumentLoc &Arg,
- llvm::SmallVectorImpl<TemplateArgument> &Converted);
+ SmallVectorImpl<TemplateArgument> &Converted);
bool CheckTemplateArgument(TemplateTypeParmDecl *Param,
TypeSourceInfo *Arg);
@@ -3963,7 +4134,9 @@ public:
bool RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS);
ExprResult RebuildExprInCurrentInstantiation(Expr *E);
-
+ bool RebuildTemplateParamsInCurrentInstantiation(
+ TemplateParameterList *Params);
+
std::string
getTemplateArgumentBindingsText(const TemplateParameterList *Params,
const TemplateArgumentList &Args);
@@ -4103,7 +4276,7 @@ public:
/// \param Arg The template argument that will be traversed to find
/// unexpanded parameter packs.
void collectUnexpandedParameterPacks(TemplateArgument Arg,
- llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded);
+ SmallVectorImpl<UnexpandedParameterPack> &Unexpanded);
/// \brief Collect the set of unexpanded parameter packs within the given
/// template argument.
@@ -4111,7 +4284,7 @@ public:
/// \param Arg The template argument that will be traversed to find
/// unexpanded parameter packs.
void collectUnexpandedParameterPacks(TemplateArgumentLoc Arg,
- llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded);
+ SmallVectorImpl<UnexpandedParameterPack> &Unexpanded);
/// \brief Collect the set of unexpanded parameter packs within the given
/// type.
@@ -4119,7 +4292,7 @@ public:
/// \param T The type that will be traversed to find
/// unexpanded parameter packs.
void collectUnexpandedParameterPacks(QualType T,
- llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded);
+ SmallVectorImpl<UnexpandedParameterPack> &Unexpanded);
/// \brief Collect the set of unexpanded parameter packs within the given
/// type.
@@ -4127,7 +4300,7 @@ public:
/// \param TL The type that will be traversed to find
/// unexpanded parameter packs.
void collectUnexpandedParameterPacks(TypeLoc TL,
- llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded);
+ SmallVectorImpl<UnexpandedParameterPack> &Unexpanded);
/// \brief Invoked when parsing a template argument followed by an
/// ellipsis, which creates a pack expansion.
@@ -4219,8 +4392,7 @@ public:
/// must be set.
bool CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
SourceRange PatternRange,
- const UnexpandedParameterPack *Unexpanded,
- unsigned NumUnexpanded,
+ llvm::ArrayRef<UnexpandedParameterPack> Unexpanded,
const MultiLevelTemplateArgumentList &TemplateArgs,
bool &ShouldExpand,
bool &RetainExpansion,
@@ -4312,8 +4484,8 @@ public:
TemplateDeductionResult
SubstituteExplicitTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentListInfo &ExplicitTemplateArgs,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- llvm::SmallVectorImpl<QualType> &ParamTypes,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ SmallVectorImpl<QualType> &ParamTypes,
QualType *FunctionType,
sema::TemplateDeductionInfo &Info);
@@ -4333,11 +4505,11 @@ public:
TemplateDeductionResult
FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned NumExplicitlySpecified,
FunctionDecl *&Specialization,
sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs = 0);
+ SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs = 0);
TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
@@ -4392,9 +4564,9 @@ public:
void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
bool OnlyDeduced,
unsigned Depth,
- llvm::SmallVectorImpl<bool> &Used);
+ SmallVectorImpl<bool> &Used);
void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
- llvm::SmallVectorImpl<bool> &Deduced);
+ SmallVectorImpl<bool> &Deduced);
//===--------------------------------------------------------------------===//
// C++ Template Instantiation
@@ -4523,7 +4695,7 @@ public:
/// requires another template instantiation, additional
/// instantiations are pushed onto the stack up to a
/// user-configurable limit LangOptions::InstantiationDepth.
- llvm::SmallVector<ActiveTemplateInstantiation, 16>
+ SmallVector<ActiveTemplateInstantiation, 16>
ActiveTemplateInstantiations;
/// \brief Whether we are in a SFINAE context that is not associated with
@@ -4580,14 +4752,14 @@ public:
///
/// The top of this stack is used by a fixit instantiating unresolved
/// function calls to fix the AST to match the textual change it prints.
- llvm::SmallVector<CallExpr *, 8> CallsUndergoingInstantiation;
+ SmallVector<CallExpr *, 8> CallsUndergoingInstantiation;
/// \brief For each declaration that involved template argument deduction, the
/// set of diagnostics that were suppressed during that template argument
/// deduction.
///
/// FIXME: Serialize this structure to the AST file.
- llvm::DenseMap<Decl *, llvm::SmallVector<PartialDiagnosticAt, 1> >
+ llvm::DenseMap<Decl *, SmallVector<PartialDiagnosticAt, 1> >
SuppressedDiagnostics;
/// \brief A stack object to be created when performing template
@@ -4691,7 +4863,7 @@ public:
};
void PrintInstantiationStack();
-
+
/// \brief Determines whether we are currently in a context where
/// template argument substitution failures are not considered
/// errors.
@@ -4805,8 +4977,8 @@ public:
bool SubstParmTypes(SourceLocation Loc,
ParmVarDecl **Params, unsigned NumParams,
const MultiLevelTemplateArgumentList &TemplateArgs,
- llvm::SmallVectorImpl<QualType> &ParamTypes,
- llvm::SmallVectorImpl<ParmVarDecl *> *OutParams = 0);
+ SmallVectorImpl<QualType> &ParamTypes,
+ SmallVectorImpl<ParmVarDecl *> *OutParams = 0);
ExprResult SubstExpr(Expr *E,
const MultiLevelTemplateArgumentList &TemplateArgs);
@@ -4827,7 +4999,7 @@ public:
/// \returns true if an error occurred, false otherwise.
bool SubstExprs(Expr **Exprs, unsigned NumExprs, bool IsCall,
const MultiLevelTemplateArgumentList &TemplateArgs,
- llvm::SmallVectorImpl<Expr *> &Outputs);
+ SmallVectorImpl<Expr *> &Outputs);
StmtResult SubstStmt(Stmt *S,
const MultiLevelTemplateArgumentList &TemplateArgs);
@@ -4894,6 +5066,11 @@ public:
void InstantiateMemInitializers(CXXConstructorDecl *New,
const CXXConstructorDecl *Tmpl,
const MultiLevelTemplateArgumentList &TemplateArgs);
+ bool InstantiateInitializer(Expr *Init,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ SourceLocation &LParenLoc,
+ ASTOwningVector<Expr*> &NewArgs,
+ SourceLocation &RParenLoc);
NamedDecl *FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs);
@@ -4952,7 +5129,7 @@ public:
IdentifierInfo *CatName,
SourceLocation CatLoc);
- Decl *ActOnForwardClassDeclaration(SourceLocation Loc,
+ DeclGroupPtrTy ActOnForwardClassDeclaration(SourceLocation Loc,
IdentifierInfo **IdentList,
SourceLocation *IdentLocs,
unsigned NumElts);
@@ -4965,7 +5142,7 @@ public:
void FindProtocolDeclaration(bool WarnOnDeclarations,
const IdentifierLocPair *ProtocolId,
unsigned NumProtocols,
- llvm::SmallVectorImpl<Decl *> &Protocols);
+ SmallVectorImpl<Decl *> &Protocols);
/// Ensure attributes are consistent with type.
/// \param [in, out] Attributes The attributes to check; they will
@@ -5003,7 +5180,7 @@ public:
void MatchOneProtocolPropertiesInClass(Decl *CDecl,
ObjCProtocolDecl *PDecl);
- void ActOnAtEnd(Scope *S, SourceRange AtEnd, Decl *classDecl,
+ void ActOnAtEnd(Scope *S, SourceRange AtEnd,
Decl **allMethods = 0, unsigned allNum = 0,
Decl **allProperties = 0, unsigned pNum = 0,
DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0);
@@ -5011,7 +5188,6 @@ public:
Decl *ActOnProperty(Scope *S, SourceLocation AtLoc,
FieldDeclarator &FD, ObjCDeclSpec &ODS,
Selector GetterSel, Selector SetterSel,
- Decl *ClassCategory,
bool *OverridingProperty,
tok::ObjCKeywordKind MethodImplKind,
DeclContext *lexicalDC = 0);
@@ -5019,7 +5195,7 @@ public:
Decl *ActOnPropertyImplDecl(Scope *S,
SourceLocation AtLoc,
SourceLocation PropertyLoc,
- bool ImplKind,Decl *ClassImplDecl,
+ bool ImplKind,
IdentifierInfo *PropertyId,
IdentifierInfo *PropertyIvar,
SourceLocation PropertyIvarLoc);
@@ -5050,8 +5226,8 @@ public:
SourceLocation BeginLoc, // location of the + or -.
SourceLocation EndLoc, // location of the ; or {.
tok::TokenKind MethodType,
- Decl *ClassDecl, ObjCDeclSpec &ReturnQT, ParsedType ReturnType,
- SourceLocation SelectorStartLoc, Selector Sel,
+ ObjCDeclSpec &ReturnQT, ParsedType ReturnType,
+ ArrayRef<SourceLocation> SelectorLocs, Selector Sel,
// optional arguments. The number of types/arguments is obtained
// from the Sel.getNumArgs().
ObjCArgInfo *ArgInfo,
@@ -5112,7 +5288,7 @@ public:
ExprResult ActOnSuperMessage(Scope *S, SourceLocation SuperLoc,
Selector Sel,
SourceLocation LBracLoc,
- SourceLocation SelectorLoc,
+ ArrayRef<SourceLocation> SelectorLocs,
SourceLocation RBracLoc,
MultiExprArg Args);
@@ -5122,7 +5298,7 @@ public:
Selector Sel,
ObjCMethodDecl *Method,
SourceLocation LBracLoc,
- SourceLocation SelectorLoc,
+ ArrayRef<SourceLocation> SelectorLocs,
SourceLocation RBracLoc,
MultiExprArg Args);
@@ -5130,7 +5306,7 @@ public:
ParsedType Receiver,
Selector Sel,
SourceLocation LBracLoc,
- SourceLocation SelectorLoc,
+ ArrayRef<SourceLocation> SelectorLocs,
SourceLocation RBracLoc,
MultiExprArg Args);
@@ -5140,7 +5316,7 @@ public:
Selector Sel,
ObjCMethodDecl *Method,
SourceLocation LBracLoc,
- SourceLocation SelectorLoc,
+ ArrayRef<SourceLocation> SelectorLocs,
SourceLocation RBracLoc,
MultiExprArg Args);
@@ -5148,7 +5324,7 @@ public:
Expr *Receiver,
Selector Sel,
SourceLocation LBracLoc,
- SourceLocation SelectorLoc,
+ ArrayRef<SourceLocation> SelectorLocs,
SourceLocation RBracLoc,
MultiExprArg Args);
@@ -5170,9 +5346,7 @@ public:
/// \brief Check whether the given new method is a valid override of the
/// given overridden method, and set any properties that should be inherited.
- ///
- /// \returns True if an error occurred.
- bool CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
+ void CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
const ObjCMethodDecl *Overridden,
bool IsImplementation);
@@ -5226,7 +5400,8 @@ public:
void ActOnPragmaVisibility(bool IsPush, const IdentifierInfo* VisType,
SourceLocation PragmaLoc);
- NamedDecl *DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II);
+ NamedDecl *DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
+ SourceLocation Loc);
void DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W);
/// ActOnPragmaWeakID - Called on well formed #pragma weak ident.
@@ -5270,13 +5445,14 @@ public:
/// FreeVisContext - Deallocate and null out VisContext.
void FreeVisContext();
- /// AddAlignedAttr - Adds an aligned attribute to a particular declaration.
- void AddAlignedAttr(SourceLocation AttrLoc, Decl *D, Expr *E);
- void AddAlignedAttr(SourceLocation AttrLoc, Decl *D, TypeSourceInfo *T);
+ /// AddCFAuditedAttribute - Check whether we're currently within
+ /// '#pragma clang arc_cf_code_audited' and, if so, consider adding
+ /// the appropriate attribute.
+ void AddCFAuditedAttribute(Decl *D);
- /// CastCategory - Get the correct forwarded implicit cast result category
- /// from the inner expression.
- ExprValueKind CastCategory(Expr *E);
+ /// AddAlignedAttr - Adds an aligned attribute to a particular declaration.
+ void AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E);
+ void AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *T);
/// \brief The kind of conversion being performed.
enum CheckedConversionKind {
@@ -5348,7 +5524,7 @@ public:
const FunctionProtoType *Proto,
unsigned FirstProtoArg,
Expr **Args, unsigned NumArgs,
- llvm::SmallVector<Expr *, 8> &AllArgs,
+ SmallVector<Expr *, 8> &AllArgs,
VariadicCallType CallType = VariadicDoesNotApply);
// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
@@ -5361,8 +5537,8 @@ public:
// 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.
- QualType UsualArithmeticConversions(ExprResult &lExpr, ExprResult &rExpr,
- bool isCompAssign = false);
+ QualType UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
+ bool IsCompAssign = false);
/// AssignConvertType - All of the 'assignment' semantic checks return this
/// enum to indicate whether the assignment was allowed. These checks are
@@ -5449,23 +5625,26 @@ public:
/// argument passing, variable initialization, and function return values.
/// C99 6.5.16.
AssignConvertType CheckAssignmentConstraints(SourceLocation Loc,
- QualType lhs, QualType rhs);
+ QualType LHSType,
+ QualType RHSType);
/// Check assignment constraints and prepare for a conversion of the
/// RHS to the LHS type.
- AssignConvertType CheckAssignmentConstraints(QualType lhs, ExprResult &rhs,
+ AssignConvertType CheckAssignmentConstraints(QualType LHSType,
+ ExprResult &RHS,
CastKind &Kind);
// CheckSingleAssignmentConstraints - Currently used by
// CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking,
// this routine performs the default function/array converions.
- AssignConvertType CheckSingleAssignmentConstraints(QualType lhs,
- ExprResult &rExprRes);
+ AssignConvertType CheckSingleAssignmentConstraints(QualType LHSType,
+ ExprResult &RHS,
+ bool Diagnose = true);
// \brief If the lhs type is a transparent union, check whether we
// can initialize the transparent union with the given expression.
- AssignConvertType CheckTransparentUnionArgumentConstraints(QualType lhs,
- ExprResult &rExpr);
+ AssignConvertType CheckTransparentUnionArgumentConstraints(QualType ArgType,
+ ExprResult &RHS);
bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType);
@@ -5473,11 +5652,13 @@ public:
ExprResult PerformImplicitConversion(Expr *From, QualType ToType,
AssignmentAction Action,
- bool AllowExplicit = false);
+ bool AllowExplicit = false,
+ bool Diagnose = true);
ExprResult PerformImplicitConversion(Expr *From, QualType ToType,
AssignmentAction Action,
bool AllowExplicit,
- ImplicitConversionSequence& ICS);
+ ImplicitConversionSequence& ICS,
+ bool Diagnose = true);
ExprResult PerformImplicitConversion(Expr *From, QualType ToType,
const ImplicitConversionSequence& ICS,
AssignmentAction Action,
@@ -5492,41 +5673,47 @@ public:
/// or a null QualType (indicating an error diagnostic was issued).
/// type checking binary operators (subroutines of CreateBuiltinBinOp).
- QualType InvalidOperands(SourceLocation l, ExprResult &lex, ExprResult &rex);
+ QualType InvalidOperands(SourceLocation Loc, ExprResult &LHS,
+ ExprResult &RHS);
QualType CheckPointerToMemberOperands( // C++ 5.5
- ExprResult &lex, ExprResult &rex, ExprValueKind &VK,
+ ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK,
SourceLocation OpLoc, bool isIndirect);
QualType CheckMultiplyDivideOperands( // C99 6.5.5
- ExprResult &lex, ExprResult &rex, SourceLocation OpLoc, bool isCompAssign,
- bool isDivide);
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign,
+ bool IsDivide);
QualType CheckRemainderOperands( // C99 6.5.5
- ExprResult &lex, ExprResult &rex, SourceLocation OpLoc, bool isCompAssign = false);
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
+ bool IsCompAssign = false);
QualType CheckAdditionOperands( // C99 6.5.6
- ExprResult &lex, ExprResult &rex, SourceLocation OpLoc, QualType* CompLHSTy = 0);
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
+ QualType* CompLHSTy = 0);
QualType CheckSubtractionOperands( // C99 6.5.6
- ExprResult &lex, ExprResult &rex, SourceLocation OpLoc, QualType* CompLHSTy = 0);
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
+ QualType* CompLHSTy = 0);
QualType CheckShiftOperands( // C99 6.5.7
- ExprResult &lex, ExprResult &rex, SourceLocation OpLoc, unsigned Opc,
- bool isCompAssign = false);
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc,
+ bool IsCompAssign = false);
QualType CheckCompareOperands( // C99 6.5.8/9
- ExprResult &lex, ExprResult &rex, SourceLocation OpLoc, unsigned Opc,
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned OpaqueOpc,
bool isRelational);
QualType CheckBitwiseOperands( // C99 6.5.[10...12]
- ExprResult &lex, ExprResult &rex, SourceLocation OpLoc, bool isCompAssign = false);
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
+ bool IsCompAssign = false);
QualType CheckLogicalOperands( // C99 6.5.[13,14]
- ExprResult &lex, ExprResult &rex, SourceLocation OpLoc, unsigned Opc);
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc);
// CheckAssignmentOperands is used for both simple and compound assignment.
// For simple assignment, pass both expressions and a null converted type.
// For compound assignment, pass both expressions and the converted type.
QualType CheckAssignmentOperands( // C99 6.5.16.[1,2]
- Expr *lex, ExprResult &rex, SourceLocation OpLoc, QualType convertedType);
+ Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType);
- void ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType& LHSTy);
+ void ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS,
+ QualType& LHSTy);
ExprResult ConvertPropertyForRValue(Expr *E);
QualType CheckConditionalOperands( // C99 6.5.15
- ExprResult &cond, ExprResult &lhs, ExprResult &rhs,
- ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc);
+ ExprResult &Cond, ExprResult &LHS, ExprResult &RHS,
+ ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc);
QualType CXXCheckConditionalOperands( // C++ 5.16
ExprResult &cond, ExprResult &lhs, ExprResult &rhs,
ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc);
@@ -5542,20 +5729,18 @@ public:
}
QualType FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
- SourceLocation questionLoc);
+ SourceLocation QuestionLoc);
- bool DiagnoseConditionalForNull(Expr *LHS, Expr *RHS,
+ bool DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr,
SourceLocation QuestionLoc);
/// type checking for vector binary operators.
- QualType CheckVectorOperands(ExprResult &lex, ExprResult &rex,
- SourceLocation Loc, bool isCompAssign);
- QualType CheckVectorCompareOperands(ExprResult &lex, ExprResult &rx,
- SourceLocation l, bool isRel);
+ QualType CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
+ SourceLocation Loc, bool IsCompAssign);
+ QualType CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
+ SourceLocation Loc, bool isRelational);
/// type checking declaration initializers (C99 6.7.8)
- bool CheckInitList(const InitializedEntity &Entity,
- InitListExpr *&InitList, QualType &DeclType);
bool CheckForConstantInitializer(Expr *e, QualType t);
// type checking C++ declaration initializers (C++ [dcl.init]).
@@ -5587,16 +5772,9 @@ public:
bool &ObjCConversion,
bool &ObjCLifetimeConversion);
- /// CheckCastTypes - Check type constraints for casting between types under
- /// C semantics, or forward to CXXCheckCStyleCast in C++.
- ExprResult CheckCastTypes(SourceLocation CastStartLoc, SourceRange TyRange,
- QualType CastTy, Expr *CastExpr, CastKind &Kind,
- ExprValueKind &VK, CXXCastPath &BasePath,
- bool FunctionalStyle = false);
-
- ExprResult checkUnknownAnyCast(SourceRange TyRange, QualType castType,
- Expr *castExpr, CastKind &castKind,
- ExprValueKind &valueKind, CXXCastPath &BasePath);
+ ExprResult checkUnknownAnyCast(SourceRange TypeRange, QualType CastType,
+ Expr *CastExpr, CastKind &CastKind,
+ ExprValueKind &VK, CXXCastPath &Path);
// CheckVectorCast - check type constraints for vectors.
// Since vectors are an extension, there are no C standard reference for this.
@@ -5610,19 +5788,14 @@ public:
// We allow casting between vectors and integer datatypes of the same size,
// or vectors and the element type of that vector.
// returns the cast expr
- ExprResult CheckExtVectorCast(SourceRange R, QualType VectorTy, Expr *CastExpr,
+ ExprResult CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *CastExpr,
CastKind &Kind);
- /// CXXCheckCStyleCast - Check constraints of a C-style or function-style
- /// cast under C++ semantics.
- ExprResult CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
- Expr *CastExpr, CastKind &Kind,
- CXXCastPath &BasePath, bool FunctionalStyle);
-
- /// \brief Checks for valid expressions which can be cast to an ObjC
- /// pointer without needing a bridge cast.
- bool ValidObjCARCNoBridgeCastExpr(Expr *&Exp, QualType castType);
-
+ ExprResult BuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo,
+ SourceLocation LParenLoc,
+ Expr *CastExpr,
+ SourceLocation RParenLoc);
+
/// \brief Checks for invalid conversions and casts between
/// retainable pointers and other pointer kinds.
void CheckObjCARCConversion(SourceRange castRange, QualType castType,
@@ -5674,10 +5847,10 @@ public:
/// \param Loc - A location associated with the condition, e.g. the
/// 'if' keyword.
/// \return true iff there were any errors
- ExprResult CheckBooleanCondition(Expr *CondExpr, SourceLocation Loc);
+ ExprResult CheckBooleanCondition(Expr *E, SourceLocation Loc);
ExprResult ActOnBooleanCondition(Scope *S, SourceLocation Loc,
- Expr *SubExpr);
+ Expr *SubExpr);
/// DiagnoseAssignmentAsCondition - Given that an expression is
/// being used as a boolean condition, warn if it's an assignment.
@@ -5685,7 +5858,7 @@ public:
/// \brief Redundant parentheses over an equality comparison can indicate
/// that the user intended an assignment used as condition.
- void DiagnoseEqualityWithExtraParens(ParenExpr *parenE);
+ void DiagnoseEqualityWithExtraParens(ParenExpr *ParenE);
/// CheckCXXBooleanCondition - Returns true if conversion to bool is invalid.
ExprResult CheckCXXBooleanCondition(Expr *CondExpr);
@@ -5715,6 +5888,23 @@ public:
QualType FieldTy, const Expr *BitWidth,
bool *ZeroWidth = 0);
+ enum CUDAFunctionTarget {
+ CFT_Device,
+ CFT_Global,
+ CFT_Host,
+ CFT_HostDevice
+ };
+
+ CUDAFunctionTarget IdentifyCUDATarget(const FunctionDecl *D);
+
+ bool CheckCUDATarget(CUDAFunctionTarget CallerTarget,
+ CUDAFunctionTarget CalleeTarget);
+
+ bool CheckCUDATarget(const FunctionDecl *Caller, const FunctionDecl *Callee) {
+ return CheckCUDATarget(IdentifyCUDATarget(Caller),
+ IdentifyCUDATarget(Callee));
+ }
+
/// \name Code completion
//@{
/// \brief Describes the context in which code completion occurs.
@@ -5782,6 +5972,7 @@ public:
void CodeCompleteCall(Scope *S, Expr *Fn, Expr **Args, unsigned NumArgs);
void CodeCompleteInitializer(Scope *S, Decl *D);
void CodeCompleteReturn(Scope *S);
+ void CodeCompleteAfterIf(Scope *S);
void CodeCompleteAssignmentRHS(Scope *S, Expr *LHS);
void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
@@ -5795,14 +5986,13 @@ public:
CXXCtorInitializer** Initializers,
unsigned NumInitializers);
- void CodeCompleteObjCAtDirective(Scope *S, Decl *ObjCImpDecl,
- bool InInterface);
+ void CodeCompleteObjCAtDirective(Scope *S);
void CodeCompleteObjCAtVisibility(Scope *S);
void CodeCompleteObjCAtStatement(Scope *S);
void CodeCompleteObjCAtExpression(Scope *S);
void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS);
- void CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl);
- void CodeCompleteObjCPropertySetter(Scope *S, Decl *ClassDecl);
+ void CodeCompleteObjCPropertyGetter(Scope *S);
+ void CodeCompleteObjCPropertySetter(Scope *S);
void CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS,
bool IsParameter);
void CodeCompleteObjCMessageReceiver(Scope *S);
@@ -5815,7 +6005,7 @@ public:
unsigned NumSelIdents,
bool AtArgumentExpression,
bool IsSuper = false);
- void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
+ void CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
IdentifierInfo **SelIdents,
unsigned NumSelIdents,
bool AtArgumentExpression,
@@ -5839,14 +6029,12 @@ public:
void CodeCompleteObjCImplementationCategory(Scope *S,
IdentifierInfo *ClassName,
SourceLocation ClassNameLoc);
- void CodeCompleteObjCPropertyDefinition(Scope *S, Decl *ObjCImpDecl);
+ void CodeCompleteObjCPropertyDefinition(Scope *S);
void CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
- IdentifierInfo *PropertyName,
- Decl *ObjCImpDecl);
+ IdentifierInfo *PropertyName);
void CodeCompleteObjCMethodDecl(Scope *S,
bool IsInstanceMethod,
- ParsedType ReturnType,
- Decl *IDecl);
+ ParsedType ReturnType);
void CodeCompleteObjCMethodDeclSelector(Scope *S,
bool IsInstanceMethod,
bool AtParameterName,
@@ -5863,7 +6051,7 @@ public:
unsigned Argument);
void CodeCompleteNaturalLanguage();
void GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator,
- llvm::SmallVectorImpl<CodeCompletionResult> &Results);
+ SmallVectorImpl<CodeCompletionResult> &Results);
//@}
//===--------------------------------------------------------------------===//
@@ -5874,6 +6062,8 @@ public:
unsigned ByteNo) const;
private:
+ void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
+ bool isSubscript=false, bool AllowOnePastEnd=true);
void CheckArrayAccess(const Expr *E);
bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall);
bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall);
@@ -5897,6 +6087,8 @@ private:
bool SemaBuiltinObjectSize(CallExpr *TheCall);
bool SemaBuiltinLongjmp(CallExpr *TheCall);
ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult);
+ ExprResult SemaAtomicOpsOverloaded(ExprResult TheCallResult,
+ AtomicExpr::AtomicOp Op);
bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
llvm::APSInt &Result);
@@ -5918,20 +6110,28 @@ private:
bool isPrintf);
/// \brief Enumeration used to describe which of the memory setting or copying
- /// functions is being checked by \c CheckMemsetcpymoveArguments().
+ /// functions is being checked by \c CheckMemaccessArguments().
enum CheckedMemoryFunction {
CMF_Memset,
CMF_Memcpy,
- CMF_Memmove
+ CMF_Memmove,
+ CMF_Memcmp,
+ CMF_Strncpy,
+ CMF_Strncmp,
+ CMF_Strncasecmp,
+ CMF_Strncat,
+ CMF_Strndup
};
- void CheckMemsetcpymoveArguments(const CallExpr *Call,
- CheckedMemoryFunction CMF,
- IdentifierInfo *FnName);
+ void CheckMemaccessArguments(const CallExpr *Call, CheckedMemoryFunction CMF,
+ IdentifierInfo *FnName);
+
+ void CheckStrlcpycatArguments(const CallExpr *Call,
+ IdentifierInfo *FnName);
void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
SourceLocation ReturnLoc);
- void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex);
+ void CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr* RHS);
void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation());
void CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *Field,
@@ -5958,6 +6158,14 @@ public:
/// itself and in routines directly invoked from the parser and *never* from
/// template substitution or instantiation.
Scope *getCurScope() const { return CurScope; }
+
+ Decl *getObjCDeclContext() const;
+
+ DeclContext *getCurLexicalContext() const {
+ return OriginalLexicalContext ? OriginalLexicalContext : CurContext;
+ }
+
+ AvailabilityResult getCurContextAvailability() const;
};
/// \brief RAII object that enters a new expression evaluation context.
diff --git a/include/clang/Sema/SemaDiagnostic.h b/include/clang/Sema/SemaDiagnostic.h
index 83c0999ad49c..2c4bf4b0d1b7 100644
--- a/include/clang/Sema/SemaDiagnostic.h
+++ b/include/clang/Sema/SemaDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM,
+ SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM,
#define SEMASTART
#include "clang/Basic/DiagnosticSemaKinds.inc"
#undef DIAG
diff --git a/include/clang/Sema/SemaFixItUtils.h b/include/clang/Sema/SemaFixItUtils.h
new file mode 100644
index 000000000000..0c1bba5078fc
--- /dev/null
+++ b/include/clang/Sema/SemaFixItUtils.h
@@ -0,0 +1,91 @@
+//===--- SemaFixItUtils.h - Sema FixIts -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines helper classes for generation of Sema FixItHints.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_SEMA_FIXITUTILS_H
+#define LLVM_CLANG_SEMA_FIXITUTILS_H
+
+#include "clang/AST/Expr.h"
+
+namespace clang {
+
+enum OverloadFixItKind {
+ OFIK_Undefined = 0,
+ OFIK_Dereference,
+ OFIK_TakeAddress,
+ OFIK_RemoveDereference,
+ OFIK_RemoveTakeAddress
+};
+
+class Sema;
+
+/// The class facilities generation and storage of conversion FixIts. Hints for
+/// new conversions are added using TryToFixConversion method. The default type
+/// conversion checker can be reset.
+struct ConversionFixItGenerator {
+ /// Performs a simple check to see if From type can be converted to To type.
+ static bool compareTypesSimple(CanQualType From,
+ CanQualType To,
+ Sema &S,
+ SourceLocation Loc,
+ ExprValueKind FromVK);
+
+ /// The list of Hints generated so far.
+ SmallVector<FixItHint, 1> Hints;
+
+ /// The number of Conversions fixed. This can be different from the size
+ /// of the Hints vector since we allow multiple FixIts per conversion.
+ unsigned NumConversionsFixed;
+
+ /// The type of fix applied. If multiple conversions are fixed, corresponds
+ /// to the kid of the very first conversion.
+ OverloadFixItKind Kind;
+
+ typedef bool (*TypeComparisonFuncTy) (const CanQualType FromTy,
+ const CanQualType ToTy,
+ Sema &S,
+ SourceLocation Loc,
+ ExprValueKind FromVK);
+ /// The type comparison function used to decide if expression FromExpr of
+ /// type FromTy can be converted to ToTy. For example, one could check if
+ /// an implicit conversion exists. Returns true if comparison exists.
+ TypeComparisonFuncTy CompareTypes;
+
+ ConversionFixItGenerator(TypeComparisonFuncTy Foo): NumConversionsFixed(0),
+ Kind(OFIK_Undefined),
+ CompareTypes(Foo) {}
+
+ ConversionFixItGenerator(): NumConversionsFixed(0),
+ Kind(OFIK_Undefined),
+ CompareTypes(compareTypesSimple) {}
+
+ /// Resets the default conversion checker method.
+ void setConversionChecker(TypeComparisonFuncTy Foo) {
+ CompareTypes = Foo;
+ }
+
+ /// If possible, generates and stores a fix for the given conversion.
+ bool tryToFixConversion(const Expr *FromExpr,
+ const QualType FromQTy, const QualType ToQTy,
+ Sema &S);
+
+ void clear() {
+ Hints.clear();
+ NumConversionsFixed = 0;
+ }
+
+ bool isNull() {
+ return (NumConversionsFixed == 0);
+ }
+};
+
+} // endof namespace clang
+#endif // LLVM_CLANG_SEMA_FIXITUTILS_H
diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h
index a257772ee102..78f50fa9ffa4 100644
--- a/include/clang/Sema/Template.h
+++ b/include/clang/Sema/Template.h
@@ -45,7 +45,7 @@ namespace clang {
private:
/// \brief The template argument lists, stored from the innermost template
/// argument list (first) to the outermost template argument list (last).
- llvm::SmallVector<ArgList, 4> TemplateArgumentLists;
+ SmallVector<ArgList, 4> TemplateArgumentLists;
public:
/// \brief Construct an empty set of template argument lists.
@@ -178,7 +178,7 @@ namespace clang {
class LocalInstantiationScope {
public:
/// \brief A set of declarations.
- typedef llvm::SmallVector<Decl *, 4> DeclArgumentPack;
+ typedef SmallVector<Decl *, 4> DeclArgumentPack;
private:
/// \brief Reference to the semantic analysis that is performing
@@ -210,7 +210,7 @@ namespace clang {
LocalDeclsMap LocalDecls;
/// \brief The set of argument packs we've allocated.
- llvm::SmallVector<DeclArgumentPack *, 1> ArgumentPacks;
+ SmallVector<DeclArgumentPack *, 1> ArgumentPacks;
/// \brief The outer scope, which contains local variable
/// definitions from some other instantiation (that may not be
@@ -318,7 +318,7 @@ namespace clang {
/// \brief A list of out-of-line class template partial
/// specializations that will need to be instantiated after the
/// enclosing class's instantiation is complete.
- llvm::SmallVector<std::pair<ClassTemplateDecl *,
+ SmallVector<std::pair<ClassTemplateDecl *,
ClassTemplatePartialSpecializationDecl *>, 4>
OutOfLinePartialSpecs;
@@ -350,7 +350,8 @@ namespace clang {
TemplateParameterList *TemplateParams = 0);
Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
Decl *VisitCXXMethodDecl(CXXMethodDecl *D,
- TemplateParameterList *TemplateParams = 0);
+ TemplateParameterList *TemplateParams = 0,
+ bool IsClassScopeSpecialization = false);
Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D);
Decl *VisitCXXConversionDecl(CXXConversionDecl *D);
@@ -367,11 +368,13 @@ namespace clang {
Decl *VisitUsingShadowDecl(UsingShadowDecl *D);
Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
+ Decl *VisitClassScopeFunctionSpecializationDecl(
+ ClassScopeFunctionSpecializationDecl *D);
// Base case. FIXME: Remove once we can instantiate everything.
Decl *VisitDecl(Decl *D) {
unsigned DiagID = SemaRef.getDiagnostics().getCustomDiagID(
- Diagnostic::Error,
+ DiagnosticsEngine::Error,
"cannot instantiate %0 yet");
SemaRef.Diag(D->getLocation(), DiagID)
<< D->getDeclKindName();
@@ -380,7 +383,7 @@ namespace clang {
}
typedef
- llvm::SmallVectorImpl<std::pair<ClassTemplateDecl *,
+ SmallVectorImpl<std::pair<ClassTemplateDecl *,
ClassTemplatePartialSpecializationDecl *> >
::iterator
delayed_partial_spec_iterator;
@@ -403,7 +406,7 @@ namespace clang {
// Helper functions for instantiating methods.
TypeSourceInfo *SubstFunctionType(FunctionDecl *D,
- llvm::SmallVectorImpl<ParmVarDecl *> &Params);
+ SmallVectorImpl<ParmVarDecl *> &Params);
bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl);
bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl);
diff --git a/include/clang/Sema/TemplateDeduction.h b/include/clang/Sema/TemplateDeduction.h
index c66697963e0d..690129ab34d1 100644
--- a/include/clang/Sema/TemplateDeduction.h
+++ b/include/clang/Sema/TemplateDeduction.h
@@ -41,7 +41,7 @@ class TemplateDeductionInfo {
/// \brief Warnings (and follow-on notes) that were suppressed due to
/// SFINAE while performing template argument deduction.
- llvm::SmallVector<PartialDiagnosticAt, 4> SuppressedDiagnostics;
+ SmallVector<PartialDiagnosticAt, 4> SuppressedDiagnostics;
// do not implement these
TemplateDeductionInfo(const TemplateDeductionInfo&);
@@ -81,7 +81,7 @@ public:
}
/// \brief Iterator over the set of suppressed diagnostics.
- typedef llvm::SmallVectorImpl<PartialDiagnosticAt>::const_iterator
+ typedef SmallVectorImpl<PartialDiagnosticAt>::const_iterator
diag_iterator;
/// \brief Returns an iterator at the beginning of the sequence of suppressed
diff --git a/include/clang/Sema/TypoCorrection.h b/include/clang/Sema/TypoCorrection.h
index 9965953538a1..9537c3031dcb 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 "llvm/ADT/SmallVector.h"
namespace clang {
@@ -23,29 +24,31 @@ namespace clang {
class TypoCorrection {
public:
TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl,
- NestedNameSpecifier *NNS=NULL, unsigned distance=0)
+ NestedNameSpecifier *NNS=0, unsigned distance=0)
: CorrectionName(Name),
CorrectionNameSpec(NNS),
- CorrectionDecl(NameDecl),
- EditDistance(distance) {}
+ EditDistance(distance) {
+ if (NameDecl)
+ CorrectionDecls.push_back(NameDecl);
+ }
- TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS=NULL,
+ TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS=0,
unsigned distance=0)
: CorrectionName(Name->getDeclName()),
CorrectionNameSpec(NNS),
- CorrectionDecl(Name),
- EditDistance(distance) {}
+ EditDistance(distance) {
+ if (Name)
+ CorrectionDecls.push_back(Name);
+ }
- TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS=NULL,
+ TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS=0,
unsigned distance=0)
: CorrectionName(Name),
CorrectionNameSpec(NNS),
- CorrectionDecl(NULL),
- EditDistance(distance) {}
+ EditDistance(distance) {}
TypoCorrection()
- : CorrectionName(), CorrectionNameSpec(NULL), CorrectionDecl(NULL),
- EditDistance(0) {}
+ : CorrectionNameSpec(0), EditDistance(0) {}
/// \brief Gets the DeclarationName of the typo correction
DeclarationName getCorrection() const { return CorrectionName; }
@@ -66,37 +69,69 @@ public:
/// \brief Gets the pointer to the declaration of the typo correction
NamedDecl* getCorrectionDecl() const {
- return isKeyword() ? NULL : CorrectionDecl;
+ return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : 0;
}
template <class DeclClass>
DeclClass *getCorrectionDeclAs() const {
return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
}
+ /// \brief Clears the list of NamedDecls before adding the new one.
void setCorrectionDecl(NamedDecl *CDecl) {
- CorrectionDecl = CDecl;
- if (!CorrectionName)
- CorrectionName = CDecl->getDeclName();
+ CorrectionDecls.clear();
+ addCorrectionDecl(CDecl);
}
+ /// \brief Add the given NamedDecl to the list of NamedDecls that are the
+ /// declarations associated with the DeclarationName of this TypoCorrection
+ void addCorrectionDecl(NamedDecl *CDecl);
+
std::string getAsString(const LangOptions &LO) const;
std::string getQuoted(const LangOptions &LO) const {
return "'" + getAsString(LO) + "'";
}
+ /// \brief Returns whether this TypoCorrection has a non-empty DeclarationName
operator bool() const { return bool(CorrectionName); }
- static inline NamedDecl *KeywordDecl() { return (NamedDecl*)-1; }
- bool isKeyword() const { return CorrectionDecl == KeywordDecl(); }
+ /// \brief Mark this TypoCorrection as being a keyword.
+ /// Since addCorrectionDeclsand setCorrectionDecl don't allow NULL to be
+ /// added to the list of the correction's NamedDecl pointers, NULL is added
+ /// as the only element in the list to mark this TypoCorrection as a keyword.
+ void makeKeyword() {
+ CorrectionDecls.clear();
+ CorrectionDecls.push_back(0);
+ }
+
+ // Check if this TypoCorrection is a keyword by checking if the first
+ // item in CorrectionDecls is NULL.
+ bool isKeyword() const {
+ return !CorrectionDecls.empty() &&
+ CorrectionDecls.front() == 0;
+ }
// Returns true if the correction either is a keyword or has a known decl.
- bool isResolved() const { return CorrectionDecl != NULL; }
+ bool isResolved() const { return !CorrectionDecls.empty(); }
+
+ bool isOverloaded() const {
+ return CorrectionDecls.size() > 1;
+ }
+
+ typedef llvm::SmallVector<NamedDecl*, 1>::iterator decl_iterator;
+ decl_iterator begin() {
+ return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
+ }
+ decl_iterator end() { return CorrectionDecls.end(); }
private:
+ bool hasCorrectionDecl() const {
+ return (!isKeyword() && !CorrectionDecls.empty());
+ }
+
// Results.
DeclarationName CorrectionName;
NestedNameSpecifier *CorrectionNameSpec;
- NamedDecl *CorrectionDecl;
+ llvm::SmallVector<NamedDecl*, 1> CorrectionDecls;
unsigned EditDistance;
};
diff --git a/include/clang/Sema/Weak.h b/include/clang/Sema/Weak.h
new file mode 100644
index 000000000000..d36b97089364
--- /dev/null
+++ b/include/clang/Sema/Weak.h
@@ -0,0 +1,46 @@
+//===-- UnresolvedSet.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 defines the WeakInfo class, which is used to store
+// information about the target of a #pragma weak directive.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_WEAK_H
+#define LLVM_CLANG_SEMA_WEAK_H
+
+#include "clang/Basic/SourceLocation.h"
+
+namespace clang {
+
+class IdentifierInfo;
+
+/// \brief Captures information about a #pragma weak directive.
+class WeakInfo {
+ IdentifierInfo *alias; // alias (optional)
+ SourceLocation loc; // for diagnostics
+ bool used; // identifier later declared?
+public:
+ WeakInfo()
+ : alias(0), loc(SourceLocation()), used(false) {}
+ WeakInfo(IdentifierInfo *Alias, SourceLocation Loc)
+ : alias(Alias), loc(Loc), used(false) {}
+ inline IdentifierInfo * getAlias() const { return alias; }
+ inline SourceLocation getLocation() const { return loc; }
+ void setUsed(bool Used=true) { used = Used; }
+ inline bool getUsed() { return used; }
+ bool operator==(WeakInfo RHS) const {
+ return alias == RHS.getAlias() && loc == RHS.getLocation();
+ }
+ bool operator!=(WeakInfo RHS) const { return !(*this == RHS); }
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_SEMA_WEAK_H
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 11b8bed903d6..dc4d05c6f346 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -47,16 +47,28 @@ namespace clang {
/// should be increased.
const unsigned VERSION_MINOR = 0;
+ /// \brief An ID number that refers to an identifier in an AST file.
+ ///
+ /// The ID numbers of identifiers are consecutive (in order of discovery)
+ /// and start at 1. 0 is reserved for NULL.
+ typedef uint32_t IdentifierID;
+
/// \brief An ID number that refers to a declaration in an AST file.
///
/// The ID numbers of declarations are consecutive (in order of
- /// discovery) and start at 2. 0 is reserved for NULL, and 1 is
- /// reserved for the translation unit declaration.
+ /// discovery), with values below NUM_PREDEF_DECL_IDS being reserved.
+ /// At the start of a chain of precompiled headers, declaration ID 1 is
+ /// used for the translation unit declaration.
typedef uint32_t DeclID;
/// \brief a Decl::Kind/DeclID pair.
typedef std::pair<uint32_t, DeclID> KindDeclIDPair;
+ // FIXME: Turn these into classes so we can have some type safety when
+ // we go from local ID to global and vice-versa.
+ typedef DeclID LocalDeclID;
+ typedef DeclID GlobalDeclID;
+
/// \brief An ID number that refers to a type in an AST file.
///
/// The ID of a type is partitioned into two parts: the lower
@@ -78,9 +90,15 @@ namespace clang {
uint32_t getIndex() const { return Idx; }
TypeID asTypeID(unsigned FastQuals) const {
+ if (Idx == uint32_t(-1))
+ return TypeID(-1);
+
return (Idx << Qualifiers::FastWidth) | FastQuals;
}
static TypeIdx fromTypeID(TypeID ID) {
+ if (ID == TypeID(-1))
+ return TypeIdx(-1);
+
return TypeIdx(ID >> Qualifiers::FastWidth);
}
};
@@ -103,31 +121,44 @@ namespace clang {
}
};
- /// \brief Map that provides the ID numbers of each type within the
- /// output stream, plus those deserialized from a chained PCH.
- ///
- /// The ID numbers of types are consecutive (in order of discovery)
- /// and start at 1. 0 is reserved for NULL. When types are actually
- /// stored in the stream, the ID number is shifted by 2 bits to
- /// allow for the const/volatile qualifiers.
- ///
- /// Keys in the map never have const/volatile qualifiers.
- typedef llvm::DenseMap<QualType, TypeIdx, UnsafeQualTypeDenseMapInfo>
- TypeIdxMap;
-
/// \brief An ID number that refers to an identifier in an AST file.
typedef uint32_t IdentID;
- /// \brief An ID number that refers to a macro in an AST file.
- typedef uint32_t MacroID;
-
+ /// \brief The number of predefined identifier IDs.
+ const unsigned int NUM_PREDEF_IDENT_IDS = 1;
+
/// \brief An ID number that refers to an ObjC selctor in an AST file.
typedef uint32_t SelectorID;
+ /// \brief The number of predefined selector IDs.
+ const unsigned int NUM_PREDEF_SELECTOR_IDS = 1;
+
/// \brief An ID number that refers to a set of CXXBaseSpecifiers in an
/// AST file.
typedef uint32_t CXXBaseSpecifiersID;
+ /// \brief An ID number that refers to an entity in the detailed
+ /// preprocessing record.
+ typedef uint32_t PreprocessedEntityID;
+
+ /// \brief Source range/offset of a preprocessed entity.
+ struct PPEntityOffset {
+ /// \brief Raw source location of beginning of range.
+ unsigned Begin;
+ /// \brief Raw source location of end of range.
+ unsigned End;
+ /// \brief Offset in the AST file.
+ uint32_t BitOffset;
+
+ PPEntityOffset(SourceRange R, uint32_t BitOffset)
+ : Begin(R.getBegin().getRawEncoding()),
+ End(R.getEnd().getRawEncoding()),
+ BitOffset(BitOffset) { }
+ };
+
+ /// \brief The number of predefined preprocessed entity IDs.
+ const unsigned int NUM_PREDEF_PP_ENTITY_IDS = 1;
+
/// \brief Describes the various kinds of blocks that occur within
/// an AST file.
enum BlockIDs {
@@ -290,9 +321,9 @@ namespace clang {
/// \brief Record code for the array of unused file scoped decls.
UNUSED_FILESCOPED_DECLS = 22,
- /// \brief Record code for the table of offsets to macro definition
- /// entries in the preprocessing record.
- MACRO_DEFINITION_OFFSETS = 23,
+ /// \brief Record code for the table of offsets to entries in the
+ /// preprocessing record.
+ PPD_ENTITIES_OFFSETS = 23,
/// \brief Record code for the array of VTable uses.
VTABLE_USES = 24,
@@ -300,9 +331,9 @@ namespace clang {
/// \brief Record code for the array of dynamic classes.
DYNAMIC_CLASSES = 25,
- /// \brief Record code for the chained AST metadata, including the
- /// AST file version and the name of the PCH this depends on.
- CHAINED_METADATA = 26,
+ /// \brief Record code for the list of other AST files imported by
+ /// this AST file.
+ IMPORTS = 26,
/// \brief Record code for referenced selector pool.
REFERENCED_SELECTOR_POOL = 27,
@@ -375,8 +406,21 @@ namespace clang {
/// \brief Record code for the set of known namespaces, which are used
/// for typo correction.
- KNOWN_NAMESPACES = 46
+ KNOWN_NAMESPACES = 46,
+ /// \brief Record code for the remapping information used to relate
+ /// loaded modules to the various offsets and IDs(e.g., source location
+ /// offests, declaration and type IDs) that are used in that module to
+ /// refer to other modules.
+ MODULE_OFFSET_MAP = 47,
+
+ /// \brief Record code for the source manager line table information,
+ /// which stores information about #line directives.
+ SOURCE_MANAGER_LINE_TABLE = 48,
+
+ /// \brief Record code for ObjC categories in a module that are chained to
+ /// an interface.
+ OBJC_CHAINED_CATEGORIES
};
/// \brief Record types used within a source manager block.
@@ -393,10 +437,7 @@ namespace clang {
SM_SLOC_BUFFER_BLOB = 3,
/// \brief Describes a source location entry (SLocEntry) for a
/// macro expansion.
- SM_SLOC_EXPANSION_ENTRY = 4,
- /// \brief Describes the SourceManager's line table, with
- /// information about #line directives.
- SM_LINE_TABLE = 5
+ SM_SLOC_EXPANSION_ENTRY = 4
};
/// \brief Record types used within a preprocessor block.
@@ -507,7 +548,13 @@ namespace clang {
/// \brief The 'unknown any' placeholder type.
PREDEF_TYPE_UNKNOWN_ANY = 29,
/// \brief The placeholder type for bound member functions.
- PREDEF_TYPE_BOUND_MEMBER = 30
+ PREDEF_TYPE_BOUND_MEMBER = 30,
+ /// \brief The "auto" deduction type.
+ PREDEF_TYPE_AUTO_DEDUCT = 31,
+ /// \brief The "auto &&" deduction type.
+ PREDEF_TYPE_AUTO_RREF_DEDUCT = 32,
+ /// \brief The OpenCL 'half' / ARM NEON __fp16 type.
+ PREDEF_TYPE_HALF_ID = 33
};
/// \brief The number of predefined type IDs that are reserved for
@@ -602,7 +649,9 @@ namespace clang {
/// \brief A AutoType record.
TYPE_AUTO = 38,
/// \brief A UnaryTransformType record.
- TYPE_UNARY_TRANSFORM = 39
+ TYPE_UNARY_TRANSFORM = 39,
+ /// \brief An AtomicType record.
+ TYPE_ATOMIC = 40
};
/// \brief The type IDs for special types constructed by semantic
@@ -613,44 +662,65 @@ namespace clang {
enum SpecialTypeIDs {
/// \brief __builtin_va_list
SPECIAL_TYPE_BUILTIN_VA_LIST = 0,
- /// \brief Objective-C "id" type
- SPECIAL_TYPE_OBJC_ID = 1,
- /// \brief Objective-C selector type
- SPECIAL_TYPE_OBJC_SELECTOR = 2,
/// \brief Objective-C Protocol type
- SPECIAL_TYPE_OBJC_PROTOCOL = 3,
- /// \brief Objective-C Class type
- SPECIAL_TYPE_OBJC_CLASS = 4,
+ SPECIAL_TYPE_OBJC_PROTOCOL = 1,
/// \brief CFConstantString type
- SPECIAL_TYPE_CF_CONSTANT_STRING = 5,
- /// \brief Objective-C fast enumeration state type
- SPECIAL_TYPE_OBJC_FAST_ENUMERATION_STATE = 6,
+ SPECIAL_TYPE_CF_CONSTANT_STRING = 2,
/// \brief C FILE typedef type
- SPECIAL_TYPE_FILE = 7,
+ SPECIAL_TYPE_FILE = 3,
/// \brief C jmp_buf typedef type
- SPECIAL_TYPE_jmp_buf = 8,
+ SPECIAL_TYPE_jmp_buf = 4,
/// \brief C sigjmp_buf typedef type
- SPECIAL_TYPE_sigjmp_buf = 9,
+ SPECIAL_TYPE_sigjmp_buf = 5,
/// \brief Objective-C "id" redefinition type
- SPECIAL_TYPE_OBJC_ID_REDEFINITION = 10,
+ SPECIAL_TYPE_OBJC_ID_REDEFINITION = 6,
/// \brief Objective-C "Class" redefinition type
- SPECIAL_TYPE_OBJC_CLASS_REDEFINITION = 11,
- /// \brief Block descriptor type for Blocks CodeGen
- SPECIAL_TYPE_BLOCK_DESCRIPTOR = 12,
- /// \brief Block extedned descriptor type for Blocks CodeGen
- SPECIAL_TYPE_BLOCK_EXTENDED_DESCRIPTOR = 13,
+ SPECIAL_TYPE_OBJC_CLASS_REDEFINITION = 7,
/// \brief Objective-C "SEL" redefinition type
- SPECIAL_TYPE_OBJC_SEL_REDEFINITION = 14,
- /// \brief NSConstantString type
- SPECIAL_TYPE_NS_CONSTANT_STRING = 15,
- /// \brief Whether __[u]int128_t identifier is installed.
- SPECIAL_TYPE_INT128_INSTALLED = 16,
- /// \brief Cached "auto" deduction type.
- SPECIAL_TYPE_AUTO_DEDUCT = 17,
- /// \brief Cached "auto &&" deduction type.
- SPECIAL_TYPE_AUTO_RREF_DEDUCT = 18
+ SPECIAL_TYPE_OBJC_SEL_REDEFINITION = 8
};
+
+ /// \brief The number of special type IDs.
+ const unsigned NumSpecialTypeIDs = 0;
+ /// \brief Predefined declaration IDs.
+ ///
+ /// These declaration IDs correspond to predefined declarations in the AST
+ /// context, such as the NULL declaration ID. Such declarations are never
+ /// actually serialized, since they will be built by the AST context when
+ /// it is created.
+ enum PredefinedDeclIDs {
+ /// \brief The NULL declaration.
+ PREDEF_DECL_NULL_ID = 0,
+
+ /// \brief The translation unit.
+ PREDEF_DECL_TRANSLATION_UNIT_ID = 1,
+
+ /// \brief The Objective-C 'id' type.
+ PREDEF_DECL_OBJC_ID_ID = 2,
+
+ /// \brief The Objective-C 'SEL' type.
+ PREDEF_DECL_OBJC_SEL_ID = 3,
+
+ /// \brief The Objective-C 'Class' type.
+ PREDEF_DECL_OBJC_CLASS_ID = 4,
+
+ /// \brief The signed 128-bit integer type.
+ PREDEF_DECL_INT_128_ID = 5,
+
+ /// \brief The unsigned 128-bit integer type.
+ PREDEF_DECL_UNSIGNED_INT_128_ID = 6,
+
+ /// \brief The internal 'instancetype' typedef.
+ PREDEF_DECL_OBJC_INSTANCETYPE_ID = 7
+ };
+
+ /// \brief The number of declaration IDs that are predefined.
+ ///
+ /// For more information about predefined declarations, see the
+ /// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants.
+ const unsigned int NUM_PREDEF_DECL_IDS = 8;
+
/// \brief Record codes for each kind of declaration.
///
/// These constants describe the declaration records that can occur within
@@ -658,10 +728,8 @@ namespace clang {
/// constant describes a record for a specific declaration class
/// in the AST.
enum DeclCode {
- /// \brief A TranslationUnitDecl record.
- DECL_TRANSLATION_UNIT = 50,
/// \brief A TypedefDecl record.
- DECL_TYPEDEF,
+ DECL_TYPEDEF = 51,
/// \brief A TypeAliasDecl record.
DECL_TYPEALIAS,
/// \brief An EnumDecl record.
@@ -786,7 +854,10 @@ namespace clang {
DECL_INDIRECTFIELD,
/// \brief A NonTypeTemplateParmDecl record that stores an expanded
/// non-type template parameter pack.
- DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK
+ DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK,
+ /// \brief A ClassScopeFunctionSpecializationDecl record a class scope
+ /// function specialization. (Microsoft extension).
+ DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION
};
/// \brief Record codes for each kind of statement or expression.
@@ -904,7 +975,9 @@ namespace clang {
EXPR_BLOCK_DECL_REF,
/// \brief A GenericSelectionExpr record.
EXPR_GENERIC_SELECTION,
-
+ /// \brief An AtomicExpr record.
+ EXPR_ATOMIC,
+
// Objective-C
/// \brief An ObjCStringLiteral record.
diff --git a/include/clang/Serialization/ASTDeserializationListener.h b/include/clang/Serialization/ASTDeserializationListener.h
index f8cdebe5a913..588fe0e63c04 100644
--- a/include/clang/Serialization/ASTDeserializationListener.h
+++ b/include/clang/Serialization/ASTDeserializationListener.h
@@ -45,7 +45,7 @@ public:
/// \brief A selector was read from the AST file.
virtual void SelectorRead(serialization::SelectorID iD, Selector Sel) { }
/// \brief A macro definition was read from the AST file.
- virtual void MacroDefinitionRead(serialization::MacroID,
+ virtual void MacroDefinitionRead(serialization::PreprocessedEntityID,
MacroDefinition *MD) { }
};
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 9e210c3db28c..996a13465944 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -15,6 +15,9 @@
#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"
@@ -23,6 +26,8 @@
#include "clang/Lex/HeaderSearch.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 "llvm/ADT/APFloat.h"
@@ -31,6 +36,7 @@
#include "llvm/ADT/OwningPtr.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>
@@ -49,6 +55,7 @@ class AddrLabelExpr;
class ASTConsumer;
class ASTContext;
class ASTIdentifierIterator;
+class ASTUnit; // FIXME: Layering violation and egregious hack.
class Attr;
class Decl;
class DeclContext;
@@ -64,10 +71,10 @@ class Preprocessor;
class Sema;
class SwitchCase;
class ASTDeserializationListener;
+class ASTWriter;
class ASTReader;
class ASTDeclReader;
class ASTStmtReader;
-class ASTIdentifierLookupTrait;
class TypeLocReader;
struct HeaderFileInfo;
class VersionTuple;
@@ -77,9 +84,9 @@ struct PCHPredefinesBlock {
FileID BufferID;
/// \brief This predefines buffer in a PCH file.
- llvm::StringRef Data;
+ StringRef Data;
};
-typedef llvm::SmallVector<PCHPredefinesBlock, 2> PCHPredefinesBlocks;
+typedef SmallVector<PCHPredefinesBlock, 2> PCHPredefinesBlocks;
/// \brief Abstract interface for callback invocations by the ASTReader.
///
@@ -101,7 +108,7 @@ public:
/// \brief Receives the target triple.
///
/// \returns true to indicate the target triple is invalid or false otherwise.
- virtual bool ReadTargetTriple(llvm::StringRef Triple) {
+ virtual bool ReadTargetTriple(StringRef Triple) {
return false;
}
@@ -117,7 +124,7 @@ public:
///
/// \returns true to indicate the predefines are invalid or false otherwise.
virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
- llvm::StringRef OriginalFileName,
+ StringRef OriginalFileName,
std::string &SuggestedPredefines,
FileManager &FileMgr) {
return false;
@@ -143,9 +150,9 @@ public:
: PP(PP), Reader(Reader), NumHeaderInfos(0) {}
virtual bool ReadLanguageOptions(const LangOptions &LangOpts);
- virtual bool ReadTargetTriple(llvm::StringRef Triple);
+ virtual bool ReadTargetTriple(StringRef Triple);
virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
- llvm::StringRef OriginalFileName,
+ StringRef OriginalFileName,
std::string &SuggestedPredefines,
FileManager &FileMgr);
virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID);
@@ -155,6 +162,16 @@ private:
void Error(const char *Msg);
};
+namespace serialization {
+
+class ReadMethodPoolVisitor;
+
+namespace reader {
+ class ASTIdentifierLookupTrait;
+}
+
+} // end namespace serialization
+
/// \brief Reads an AST files chain containing the contents of a translation
/// unit.
///
@@ -179,18 +196,24 @@ class ASTReader
public:
enum ASTReadResult { Success, Failure, IgnorePCH };
/// \brief Types of AST files.
- enum ASTFileType {
- Module, ///< File is a module proper.
- PCH, ///< File is a PCH file treated as such.
- Preamble, ///< File is a PCH file treated as the preamble.
- MainFile ///< File is a PCH file treated as the actual main file.
- };
friend class PCHValidator;
friend class ASTDeclReader;
friend class ASTStmtReader;
friend class ASTIdentifierIterator;
- friend class ASTIdentifierLookupTrait;
+ friend class serialization::reader::ASTIdentifierLookupTrait;
friend class TypeLocReader;
+ friend class ASTWriter;
+ friend class ASTUnit; // ASTUnit needs to remap source locations.
+ friend class serialization::ReadMethodPoolVisitor;
+
+ typedef serialization::Module Module;
+ typedef serialization::ModuleKind ModuleKind;
+ typedef serialization::ModuleManager ModuleManager;
+
+ typedef ModuleManager::ModuleIterator ModuleIterator;
+ typedef ModuleManager::ModuleConstIterator ModuleConstIterator;
+ typedef ModuleManager::ModuleReverseIterator ModuleReverseIterator;
+
private:
/// \brief The receiver of some callbacks invoked by ASTReader.
llvm::OwningPtr<ASTReaderListener> Listener;
@@ -200,250 +223,50 @@ private:
SourceManager &SourceMgr;
FileManager &FileMgr;
- Diagnostic &Diags;
-
+ DiagnosticsEngine &Diags;
+
/// \brief The semantic analysis object that will be processing the
/// AST files and the translation unit that uses it.
Sema *SemaObj;
/// \brief The preprocessor that will be loading the source file.
- Preprocessor *PP;
+ Preprocessor &PP;
/// \brief The AST context into which we'll read the AST files.
- ASTContext *Context;
+ ASTContext &Context;
/// \brief The AST consumer.
ASTConsumer *Consumer;
- /// \brief AST buffers for chained PCHs created and stored in memory.
- /// First (not depending on another) PCH in chain is in front.
- std::vector<llvm::MemoryBuffer *> ASTBuffers;
-
- /// \brief Information that is needed for every module.
- struct PerFileData {
- PerFileData(ASTFileType Ty);
- ~PerFileData();
-
- // === General information ===
-
- /// \brief The type of this AST file.
- ASTFileType Type;
-
- /// \brief The file name of the AST file.
- std::string FileName;
-
- /// \brief The memory buffer that stores the data associated with
- /// this AST file.
- llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
-
- /// \brief The size of this file, in bits.
- uint64_t SizeInBits;
-
- /// \brief The bitstream reader from which we'll read the AST file.
- llvm::BitstreamReader StreamFile;
-
- /// \brief The main bitstream cursor for the main block.
- llvm::BitstreamCursor Stream;
-
- // === Source Locations ===
-
- /// \brief Cursor used to read source location entries.
- llvm::BitstreamCursor SLocEntryCursor;
-
- /// \brief The number of source location entries in this AST file.
- unsigned LocalNumSLocEntries;
-
- /// \brief Offsets for all of the source location entries in the
- /// AST file.
- const uint32_t *SLocOffsets;
-
- /// \brief The number of source location file entries in this AST file.
- unsigned LocalNumSLocFileEntries;
-
- /// \brief Offsets for all of the source location file entries in the
- /// AST file.
- const uint32_t *SLocFileOffsets;
-
- /// \brief The entire size of this module's source location offset range.
- unsigned LocalSLocSize;
-
- // === Identifiers ===
-
- /// \brief The number of identifiers in this AST file.
- unsigned LocalNumIdentifiers;
-
- /// \brief Offsets into the identifier table data.
- ///
- /// This array is indexed by the identifier ID (-1), and provides
- /// the offset into IdentifierTableData where the string data is
- /// stored.
- const uint32_t *IdentifierOffsets;
-
- /// \brief Actual data for the on-disk hash table of identifiers.
- ///
- /// This pointer points into a memory buffer, where the on-disk hash
- /// table for identifiers actually lives.
- const char *IdentifierTableData;
-
- /// \brief A pointer to an on-disk hash table of opaque type
- /// IdentifierHashTable.
- void *IdentifierLookupTable;
-
- // === Macros ===
-
- /// \brief The cursor to the start of the preprocessor block, which stores
- /// all of the macro definitions.
- llvm::BitstreamCursor MacroCursor;
-
- /// \brief The offset of the start of the set of defined macros.
- uint64_t MacroStartOffset;
-
- // === Detailed PreprocessingRecord ===
-
- /// \brief The cursor to the start of the (optional) detailed preprocessing
- /// record block.
- llvm::BitstreamCursor PreprocessorDetailCursor;
-
- /// \brief The offset of the start of the preprocessor detail cursor.
- uint64_t PreprocessorDetailStartOffset;
-
- /// \brief The number of macro definitions in this file.
- unsigned LocalNumMacroDefinitions;
-
- /// \brief Offsets of all of the macro definitions in the preprocessing
- /// record in the AST file.
- const uint32_t *MacroDefinitionOffsets;
-
- // === Header search information ===
-
- /// \brief The number of local HeaderFileInfo structures.
- unsigned LocalNumHeaderFileInfos;
-
- /// \brief Actual data for the on-disk hash table of header file
- /// information.
- ///
- /// This pointer points into a memory buffer, where the on-disk hash
- /// table for header file information actually lives.
- const char *HeaderFileInfoTableData;
-
- /// \brief The on-disk hash table that contains information about each of
- /// the header files.
- void *HeaderFileInfoTable;
-
- // === Selectors ===
-
- /// \brief The number of selectors new to this file.
- ///
- /// This is the number of entries in SelectorOffsets.
- unsigned LocalNumSelectors;
-
- /// \brief Offsets into the selector lookup table's data array
- /// where each selector resides.
- const uint32_t *SelectorOffsets;
-
- /// \brief A pointer to the character data that comprises the selector table
- ///
- /// The SelectorOffsets table refers into this memory.
- const unsigned char *SelectorLookupTableData;
-
- /// \brief A pointer to an on-disk hash table of opaque type
- /// ASTSelectorLookupTable.
- ///
- /// This hash table provides the IDs of all selectors, and the associated
- /// instance and factory methods.
- void *SelectorLookupTable;
-
- /// \brief Method selectors used in a @selector expression. Used for
- /// implementation of -Wselector.
- llvm::SmallVector<uint64_t, 64> ReferencedSelectorsData;
-
- // === Declarations ===
-
- /// DeclsCursor - This is a cursor to the start of the DECLS_BLOCK block. It
- /// has read all the abbreviations at the start of the block and is ready to
- /// jump around with these in context.
- llvm::BitstreamCursor DeclsCursor;
-
- /// \brief The number of declarations in this AST file.
- unsigned LocalNumDecls;
-
- /// \brief Offset of each declaration within the bitstream, indexed
- /// by the declaration ID (-1).
- const uint32_t *DeclOffsets;
-
- /// \brief A snapshot of the pending instantiations in the chain.
- ///
- /// This record tracks the instantiations that Sema has to perform at the
- /// end of the TU. It consists of a pair of values for every pending
- /// instantiation where the first value is the ID of the decl and the second
- /// is the instantiation location.
- llvm::SmallVector<uint64_t, 64> PendingInstantiations;
-
- /// \brief The number of C++ base specifier sets in this AST file.
- unsigned LocalNumCXXBaseSpecifiers;
-
- /// \brief Offset of each C++ base specifier set within the bitstream,
- /// indexed by the C++ base specifier set ID (-1).
- const uint32_t *CXXBaseSpecifiersOffsets;
-
- // === Types ===
-
- /// \brief The number of types in this AST file.
- unsigned LocalNumTypes;
-
- /// \brief Offset of each type within the bitstream, indexed by the
- /// type ID, or the representation of a Type*.
- const uint32_t *TypeOffsets;
+ /// \brief The module manager which manages modules and their dependencies
+ ModuleManager ModuleMgr;
- // === Miscellaneous ===
+ /// \brief A map of global bit offsets to the module that stores entities
+ /// at those bit offsets.
+ ContinuousRangeMap<uint64_t, Module*, 4> GlobalBitOffsetsMap;
- /// \brief The AST stat cache installed for this file, if any.
- ///
- /// The dynamic type of this stat cache is always ASTStatCache
- void *StatCache;
-
- /// \brief The number of preallocated preprocessing entities in the
- /// preprocessing record.
- unsigned NumPreallocatedPreprocessingEntities;
-
- /// \brief The next module in source order.
- PerFileData *NextInSource;
-
- /// \brief All the modules that loaded this one. Can contain NULL for
- /// directly loaded modules.
- llvm::SmallVector<PerFileData *, 1> Loaders;
- };
-
- /// \brief All loaded modules, indexed by name.
- llvm::StringMap<PerFileData*> Modules;
-
- /// \brief The first module in source order.
- PerFileData *FirstInSource;
-
- /// \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.
- /// That is, the entry I was created with -include-pch I+1.
- llvm::SmallVector<PerFileData*, 2> Chain;
-
- /// \brief SLocEntries that we're going to preload.
- llvm::SmallVector<uint64_t, 64> PreloadSLocEntries;
+ /// \brief A map of negated SLocEntryIDs to the modules containing them.
+ ContinuousRangeMap<unsigned, Module*, 64> GlobalSLocEntryMap;
+ typedef ContinuousRangeMap<unsigned, Module*, 64> GlobalSLocOffsetMapType;
+
+ /// \brief A map of reversed (SourceManager::MaxLoadedOffset - SLocOffset)
+ /// SourceLocation offsets to the modules containing them.
+ GlobalSLocOffsetMapType GlobalSLocOffsetMap;
+
/// \brief Types that have already been loaded from the chain.
///
/// When the pointer at index I is non-NULL, the type with
/// ID = (I + 1) << FastQual::Width has already been loaded
std::vector<QualType> TypesLoaded;
- /// \brief Map that provides the ID numbers of each type within the
- /// output stream, plus those deserialized from a chained PCH.
- ///
- /// The ID numbers of types are consecutive (in order of discovery)
- /// and start at 1. 0 is reserved for NULL. When types are actually
- /// stored in the stream, the ID number is shifted by 2 bits to
- /// allow for the const/volatile qualifiers.
- ///
- /// Keys in the map never have const/volatile qualifiers.
- serialization::TypeIdxMap TypeIdxs;
+ typedef ContinuousRangeMap<serialization::TypeID, Module *, 4>
+ GlobalTypeMapType;
+
+ /// \brief Mapping from global type IDs to the module in which the
+ /// type resides along with the offset that should be added to the
+ /// global type ID to produce a local ID.
+ GlobalTypeMapType GlobalTypeMap;
/// \brief Declarations that have already been loaded from the chain.
///
@@ -451,50 +274,41 @@ private:
/// = I + 1 has already been loaded.
std::vector<Decl *> DeclsLoaded;
- typedef std::pair<PerFileData *, uint64_t> FileOffset;
- typedef llvm::SmallVector<FileOffset, 2> FileOffsetsTy;
+ typedef ContinuousRangeMap<serialization::DeclID, Module *, 4>
+ GlobalDeclMapType;
+
+ /// \brief Mapping from global declaration IDs to the module in which the
+ /// declaration resides.
+ GlobalDeclMapType GlobalDeclMap;
+
+ typedef std::pair<Module *, uint64_t> FileOffset;
+ typedef SmallVector<FileOffset, 2> FileOffsetsTy;
typedef llvm::DenseMap<serialization::DeclID, FileOffsetsTy>
DeclUpdateOffsetsMap;
+
/// \brief Declarations that have modifications residing in a later file
/// in the chain.
DeclUpdateOffsetsMap DeclUpdateOffsets;
typedef llvm::DenseMap<serialization::DeclID,
- std::pair<PerFileData *, uint64_t> >
+ std::pair<Module *, uint64_t> >
DeclReplacementMap;
/// \brief Declarations that have been replaced in a later file in the chain.
DeclReplacementMap ReplacedDecls;
- /// \brief Information about the contents of a DeclContext.
- struct DeclContextInfo {
- void *NameLookupTableData; // a ASTDeclContextNameLookupTable.
- const serialization::KindDeclIDPair *LexicalDecls;
- unsigned NumLexicalDecls;
- };
- // In a full chain, there could be multiple updates to every decl context,
- // so this is a vector. However, typically a chain is only two elements long,
- // with only one file containing updates, so there will be only one update
- // per decl context.
- typedef llvm::SmallVector<DeclContextInfo, 1> DeclContextInfos;
- typedef llvm::DenseMap<const DeclContext *, DeclContextInfos>
- DeclContextOffsetsMap;
// Updates for visible decls can occur for other contexts than just the
// TU, and when we read those update records, the actual context will not
// be available yet (unless it's the TU), so have this pending map using the
// ID as a key. It will be realized when the context is actually loaded.
- typedef llvm::SmallVector<void *, 1> DeclContextVisibleUpdates;
+ typedef SmallVector<std::pair<void *, Module*>, 1> DeclContextVisibleUpdates;
typedef llvm::DenseMap<serialization::DeclID, DeclContextVisibleUpdates>
DeclContextVisibleUpdatesPending;
- /// \brief Offsets of the lexical and visible declarations for each
- /// DeclContext.
- DeclContextOffsetsMap DeclContextOffsets;
-
/// \brief Updates to the visible declarations of declaration contexts that
/// haven't been loaded yet.
DeclContextVisibleUpdatesPending PendingVisibleUpdates;
- typedef llvm::SmallVector<CXXRecordDecl *, 4> ForwardRefs;
+ typedef SmallVector<CXXRecordDecl *, 4> ForwardRefs;
typedef llvm::DenseMap<const CXXRecordDecl *, ForwardRefs>
PendingForwardRefsMap;
/// \brief Forward references that have a definition but the definition decl
@@ -508,10 +322,15 @@ private:
/// most recent declarations in another AST file.
FirstLatestDeclIDMap FirstLatestDeclIDs;
+ /// \brief Set of ObjC interfaces that have categories chained to them in
+ /// other modules.
+ llvm::DenseSet<serialization::GlobalDeclID> ObjCChainedCategoriesInterfaces;
+
/// \brief Read the records that describe the contents of declcontexts.
- bool ReadDeclContextStorage(llvm::BitstreamCursor &Cursor,
+ bool ReadDeclContextStorage(Module &M,
+ llvm::BitstreamCursor &Cursor,
const std::pair<uint64_t, uint64_t> &Offsets,
- DeclContextInfo &Info);
+ serialization::DeclContextInfo &Info);
/// \brief A vector containing identifiers that have already been
/// loaded.
@@ -521,21 +340,42 @@ private:
/// been loaded.
std::vector<IdentifierInfo *> IdentifiersLoaded;
+ typedef ContinuousRangeMap<serialization::IdentID, Module *, 4>
+ GlobalIdentifierMapType;
+
+ /// \brief Mapping from global identifer IDs to the module in which the
+ /// identifier resides along with the offset that should be added to the
+ /// global identifier ID to produce a local ID.
+ GlobalIdentifierMapType GlobalIdentifierMap;
+
/// \brief A vector containing selectors that have already been loaded.
///
/// This vector is indexed by the Selector ID (-1). NULL selector
/// entries indicate that the particular selector ID has not yet
/// been loaded.
- llvm::SmallVector<Selector, 16> SelectorsLoaded;
+ SmallVector<Selector, 16> SelectorsLoaded;
- /// \brief The macro definitions we have already loaded.
- llvm::SmallVector<MacroDefinition *, 16> MacroDefinitionsLoaded;
+ typedef ContinuousRangeMap<serialization::SelectorID, Module *, 4>
+ 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;
/// \brief Mapping from identifiers that represent macros whose definitions
/// have not yet been deserialized to the global offset where the macro
/// record resides.
llvm::DenseMap<IdentifierInfo *, uint64_t> UnreadMacroRecordOffsets;
-
+
+ typedef ContinuousRangeMap<unsigned, Module *, 4>
+ GlobalPreprocessedEntityMapType;
+
+ /// \brief Mapping from global preprocessing entity IDs to the module in
+ /// which the preprocessed entity resides along with the offset that should be
+ /// added to the global preprocessing entitiy ID to produce a local ID.
+ GlobalPreprocessedEntityMapType GlobalPreprocessedEntityMap;
+
/// \name CodeGen-relevant special data
/// \brief Fields containing data that is relevant to CodeGen.
//@{
@@ -546,44 +386,56 @@ private:
/// This contains the data loaded from all EXTERNAL_DEFINITIONS blocks in the
/// chain. The referenced declarations are deserialized and passed to the
/// consumer eagerly.
- llvm::SmallVector<uint64_t, 16> ExternalDefinitions;
+ SmallVector<uint64_t, 16> ExternalDefinitions;
/// \brief The IDs of all tentative definitions stored in the the chain.
///
/// Sema keeps track of all tentative definitions in a TU because it has to
/// complete them and pass them on to CodeGen. Thus, tentative definitions in
/// the PCH chain must be eagerly deserialized.
- llvm::SmallVector<uint64_t, 16> TentativeDefinitions;
+ SmallVector<uint64_t, 16> TentativeDefinitions;
/// \brief The IDs of all CXXRecordDecls stored in the chain whose VTables are
/// used.
///
/// CodeGen has to emit VTables for these records, so they have to be eagerly
/// deserialized.
- llvm::SmallVector<uint64_t, 64> VTableUses;
+ SmallVector<uint64_t, 64> VTableUses;
+
+ /// \brief A snapshot of the pending instantiations in the chain.
+ ///
+ /// This record tracks the instantiations that Sema has to perform at the
+ /// end of the TU. It consists of a pair of values for every pending
+ /// instantiation where the first value is the ID of the decl and the second
+ /// is the instantiation location.
+ SmallVector<uint64_t, 64> PendingInstantiations;
//@}
- /// \name Diagnostic-relevant special data
+ /// \name DiagnosticsEngine-relevant special data
/// \brief Fields containing data that is used for generating diagnostics
//@{
/// \brief A snapshot of Sema's unused file-scoped variable tracking, for
/// generating warnings.
- llvm::SmallVector<uint64_t, 16> UnusedFileScopedDecls;
+ SmallVector<uint64_t, 16> UnusedFileScopedDecls;
/// \brief A list of all the delegating constructors we've seen, to diagnose
/// cycles.
- llvm::SmallVector<uint64_t, 4> DelegatingCtorDecls;
+ SmallVector<uint64_t, 4> DelegatingCtorDecls;
+
+ /// \brief Method selectors used in a @selector expression. Used for
+ /// implementation of -Wselector.
+ SmallVector<uint64_t, 64> ReferencedSelectorsData;
/// \brief A snapshot of Sema's weak undeclared identifier tracking, for
/// generating warnings.
- llvm::SmallVector<uint64_t, 64> WeakUndeclaredIdentifiers;
+ SmallVector<uint64_t, 64> WeakUndeclaredIdentifiers;
/// \brief The IDs of type aliases for ext_vectors that exist in the chain.
///
/// Used by Sema for finding sugared names for ext_vectors in diagnostics.
- llvm::SmallVector<uint64_t, 4> ExtVectorDecls;
+ SmallVector<uint64_t, 4> ExtVectorDecls;
//@}
@@ -595,44 +447,41 @@ private:
///
/// Sema tracks these to validate that the types are consistent across all
/// local external declarations.
- llvm::SmallVector<uint64_t, 16> LocallyScopedExternalDecls;
+ SmallVector<uint64_t, 16> LocallyScopedExternalDecls;
/// \brief The IDs of all dynamic class declarations in the chain.
///
/// Sema tracks these because it checks for the key functions being defined
/// at the end of the TU, in which case it directs CodeGen to emit the VTable.
- llvm::SmallVector<uint64_t, 16> DynamicClasses;
+ SmallVector<uint64_t, 16> DynamicClasses;
/// \brief The IDs of the declarations Sema stores directly.
///
/// Sema tracks a few important decls, such as namespace std, directly.
- llvm::SmallVector<uint64_t, 4> SemaDeclRefs;
+ SmallVector<uint64_t, 4> SemaDeclRefs;
/// \brief The IDs of the types ASTContext stores directly.
///
/// The AST context tracks a few important types, such as va_list, directly.
- llvm::SmallVector<uint64_t, 16> SpecialTypes;
+ SmallVector<uint64_t, 16> SpecialTypes;
/// \brief The IDs of CUDA-specific declarations ASTContext stores directly.
///
/// The AST context tracks a few important decls, currently cudaConfigureCall,
/// directly.
- llvm::SmallVector<uint64_t, 2> CUDASpecialDeclRefs;
+ SmallVector<uint64_t, 2> CUDASpecialDeclRefs;
/// \brief The floating point pragma option settings.
- llvm::SmallVector<uint64_t, 1> FPPragmaOptions;
+ SmallVector<uint64_t, 1> FPPragmaOptions;
/// \brief The OpenCL extension settings.
- llvm::SmallVector<uint64_t, 1> OpenCLExtensions;
+ SmallVector<uint64_t, 1> OpenCLExtensions;
/// \brief A list of the namespaces we've seen.
- llvm::SmallVector<uint64_t, 4> KnownNamespaces;
+ SmallVector<uint64_t, 4> KnownNamespaces;
//@}
- /// \brief Diagnostic IDs and their mappings that the user changed.
- llvm::SmallVector<uint64_t, 8> PragmaDiagMappings;
-
/// \brief The original file name that was used to build the primary AST file,
/// which may have been modified for relocatable-pch support.
std::string OriginalFileName;
@@ -657,7 +506,7 @@ private:
/// \brief The system include root to be used when loading the
/// precompiled header.
- const char *isysroot;
+ std::string isysroot;
/// \brief Whether to disable the normal validation performed on precompiled
/// headers when they are loaded.
@@ -686,9 +535,6 @@ private:
/// \brief The number of source location entries in the chain.
unsigned TotalNumSLocEntries;
- /// \brief The next offset for a SLocEntry after everything in this reader.
- unsigned NextSLocOffset;
-
/// \brief The number of statements (and expressions) de-serialized
/// from the chain.
unsigned NumStatementsRead;
@@ -722,14 +568,20 @@ private:
/// Number of visible decl contexts read/total.
unsigned NumVisibleDeclContextsRead, TotalVisibleDeclContexts;
+ /// Total size of modules, in bits, currently loaded
+ uint64_t TotalModulesSizeInBits;
+
/// \brief Number of Decl/types that are currently deserializing.
unsigned NumCurrentElementsDeserializing;
+ /// 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;
- llvm::SmallVector<uint32_t, 4> DeclIDs;
+ SmallVector<uint32_t, 4> DeclIDs;
};
/// \brief The set of identifiers that were read while the AST reader was
@@ -755,7 +607,7 @@ private:
void loadAndAttachPreviousDecl(Decl *D, serialization::DeclID ID);
/// \brief When reading a Stmt tree, Stmt operands are placed in this stack.
- llvm::SmallVector<Stmt *, 16> StmtStack;
+ SmallVector<Stmt *, 16> StmtStack;
/// \brief What kind of records we are reading.
enum ReadingKind {
@@ -797,36 +649,59 @@ private:
std::string SuggestedPredefines;
/// \brief Reads a statement from the specified cursor.
- Stmt *ReadStmtFromStream(PerFileData &F);
+ Stmt *ReadStmtFromStream(Module &F);
/// \brief Get a FileEntry out of stored-in-PCH filename, making sure we take
/// into account all the necessary relocations.
- const FileEntry *getFileEntry(llvm::StringRef filename);
+ const FileEntry *getFileEntry(StringRef filename);
void MaybeAddSystemRootToFilename(std::string &Filename);
- ASTReadResult ReadASTCore(llvm::StringRef FileName, ASTFileType Type);
- ASTReadResult ReadASTBlock(PerFileData &F);
+ ASTReadResult ReadASTCore(StringRef FileName, ModuleKind Type,
+ Module *ImportedBy);
+ ASTReadResult ReadASTBlock(Module &F);
bool CheckPredefinesBuffers();
- bool ParseLineTable(PerFileData &F, llvm::SmallVectorImpl<uint64_t> &Record);
- ASTReadResult ReadSourceManagerBlock(PerFileData &F);
- ASTReadResult ReadSLocEntryRecord(unsigned ID);
- PerFileData *SLocCursorForID(unsigned ID);
- SourceLocation getImportLocation(PerFileData *F);
- bool ParseLanguageOptions(const llvm::SmallVectorImpl<uint64_t> &Record);
+ bool ParseLineTable(Module &F, SmallVectorImpl<uint64_t> &Record);
+ ASTReadResult ReadSourceManagerBlock(Module &F);
+ ASTReadResult ReadSLocEntryRecord(int ID);
+ llvm::BitstreamCursor &SLocCursorForID(int ID);
+ SourceLocation getImportLocation(Module *F);
+ bool ParseLanguageOptions(const SmallVectorImpl<uint64_t> &Record);
struct RecordLocation {
- RecordLocation(PerFileData *M, uint64_t O)
+ RecordLocation(Module *M, uint64_t O)
: F(M), Offset(O) {}
- PerFileData *F;
+ Module *F;
uint64_t Offset;
};
- QualType ReadTypeRecord(unsigned Index);
+ QualType readTypeRecord(unsigned Index);
RecordLocation TypeCursorForIndex(unsigned Index);
void LoadedDecl(unsigned Index, Decl *D);
- Decl *ReadDeclRecord(unsigned Index, serialization::DeclID ID);
- RecordLocation DeclCursorForIndex(unsigned Index, serialization::DeclID ID);
+ Decl *ReadDeclRecord(serialization::DeclID ID);
+ RecordLocation DeclCursorForID(serialization::DeclID ID);
+ void loadDeclUpdateRecords(serialization::DeclID ID, Decl *D);
+ void loadObjCChainedCategories(serialization::GlobalDeclID ID,
+ ObjCInterfaceDecl *D);
+
+ RecordLocation getLocalBitOffset(uint64_t GlobalOffset);
+ uint64_t getGlobalBitOffset(Module &M, uint32_t LocalOffset);
+
+ /// \brief Returns the first preprocessed entity ID that ends after \arg BLoc.
+ serialization::PreprocessedEntityID
+ findBeginPreprocessedEntity(SourceLocation BLoc) const;
+
+ /// \brief Returns the first preprocessed entity ID that begins after \arg ELoc.
+ serialization::PreprocessedEntityID
+ findEndPreprocessedEntity(SourceLocation ELoc) const;
+
+ /// \brief \arg SLocMapI points at a chunk of a module that contains no
+ /// preprocessed entities or the entities it contains are not the ones we are
+ /// looking for. Find the next module that contains entities and return the ID
+ /// of the first entry.
+ serialization::PreprocessedEntityID
+ findNextPreprocessedEntity(
+ GlobalSLocOffsetMapType::const_iterator SLocMapI) const;
void PassInterestingDeclsToConsumer();
@@ -834,14 +709,14 @@ private:
///
/// This routine should only be used for fatal errors that have to
/// do with non-routine failures (e.g., corrupted AST file).
- void Error(llvm::StringRef Msg);
- void Error(unsigned DiagID, llvm::StringRef Arg1 = llvm::StringRef(),
- llvm::StringRef Arg2 = llvm::StringRef());
+ void Error(StringRef Msg);
+ void Error(unsigned DiagID, StringRef Arg1 = StringRef(),
+ StringRef Arg2 = StringRef());
ASTReader(const ASTReader&); // do not implement
ASTReader &operator=(const ASTReader &); // do not implement
public:
- typedef llvm::SmallVector<uint64_t, 64> RecordData;
+ typedef SmallVector<uint64_t, 64> RecordData;
/// \brief Load the AST file and validate its contents against the given
/// Preprocessor.
@@ -865,46 +740,19 @@ public:
/// help when an AST file is being used in cases where the
/// underlying files in the file system may have changed, but
/// parsing should still continue.
- ASTReader(Preprocessor &PP, ASTContext *Context, const char *isysroot = 0,
+ ASTReader(Preprocessor &PP, ASTContext &Context, StringRef isysroot = "",
bool DisableValidation = false, bool DisableStatCache = false);
- /// \brief Load the AST file without using any pre-initialized Preprocessor.
- ///
- /// The necessary information to initialize a Preprocessor later can be
- /// obtained by setting a ASTReaderListener.
- ///
- /// \param SourceMgr the source manager into which the AST file will be loaded
- ///
- /// \param FileMgr the file manager into which the AST file will be loaded.
- ///
- /// \param Diags the diagnostics system to use for reporting errors and
- /// warnings relevant to loading the AST file.
- ///
- /// \param isysroot If non-NULL, the system include path specified by the
- /// user. This is only used with relocatable PCH files. If non-NULL,
- /// a relocatable PCH file will use the default path "/".
- ///
- /// \param DisableValidation If true, the AST reader will suppress most
- /// of its regular consistency checking, allowing the use of precompiled
- /// headers that cannot be determined to be compatible.
- ///
- /// \param DisableStatCache If true, the AST reader will ignore the
- /// stat cache in the AST files. This performance pessimization can
- /// help when an AST file is being used in cases where the
- /// underlying files in the file system may have changed, but
- /// parsing should still continue.
- ASTReader(SourceManager &SourceMgr, FileManager &FileMgr,
- Diagnostic &Diags, const char *isysroot = 0,
- bool DisableValidation = false, bool DisableStatCache = false);
~ASTReader();
- /// \brief Load the precompiled header designated by the given file
- /// name.
- ASTReadResult ReadAST(const std::string &FileName, ASTFileType Type);
+ SourceManager &getSourceManager() const { return SourceMgr; }
+
+ /// \brief Load the AST file designated by the given file name.
+ ASTReadResult ReadAST(const std::string &FileName, ModuleKind Type);
/// \brief Checks that no file that is stored in PCH is out-of-sync with
/// the actual file in the file system.
- ASTReadResult validateFileEntries();
+ ASTReadResult validateFileEntries(Module &M);
/// \brief Set the AST callbacks listener.
void setListener(ASTReaderListener *listener) {
@@ -914,22 +762,20 @@ public:
/// \brief Set the AST deserialization listener.
void setDeserializationListener(ASTDeserializationListener *Listener);
- /// \brief Set the Preprocessor to use.
- void setPreprocessor(Preprocessor &pp);
+ /// \brief Initializes the ASTContext
+ void InitializeContext();
- /// \brief Sets and initializes the given Context.
- void InitializeContext(ASTContext &Context);
-
- /// \brief Set AST buffers for chained PCHs created and stored in memory.
- /// First (not depending on another) PCH in chain is first in array.
- void setASTMemoryBuffers(llvm::MemoryBuffer **bufs, unsigned numBufs) {
- ASTBuffers.clear();
- ASTBuffers.insert(ASTBuffers.begin(), bufs, bufs + numBufs);
+ /// \brief Add in-memory (virtual file) buffer.
+ void addInMemoryBuffer(StringRef &FileName, llvm::MemoryBuffer *Buffer) {
+ ModuleMgr.addInMemoryBuffer(FileName, Buffer);
}
- /// \brief Retrieve the name of the named (primary) AST file
- const std::string &getFileName() const { return Chain[0]->FileName; }
+ /// \brief Retrieve the module manager.
+ ModuleManager &getModuleManager() { return ModuleMgr; }
+ /// \brief Retrieve the preprocessor.
+ Preprocessor &getPreprocessor() const { return PP; }
+
/// \brief Retrieve the name of the original source file name
const std::string &getOriginalSourceFile() { return OriginalFileName; }
@@ -937,34 +783,34 @@ public:
/// the AST file, without actually loading the AST file.
static std::string getOriginalSourceFile(const std::string &ASTFileName,
FileManager &FileMgr,
- Diagnostic &Diags);
+ DiagnosticsEngine &Diags);
/// \brief Returns the suggested contents of the predefines buffer,
/// which contains a (typically-empty) subset of the predefines
/// build prior to including the precompiled header.
const std::string &getSuggestedPredefines() { return SuggestedPredefines; }
-
- /// \brief Read preprocessed entities into the preprocessing record.
- virtual void ReadPreprocessedEntities();
- /// \brief Read the preprocessed entity at the given offset.
- virtual PreprocessedEntity *ReadPreprocessedEntityAtOffset(uint64_t Offset);
+ /// \brief Read a preallocated preprocessed entity from the external source.
+ ///
+ /// \returns null if an error occurred that prevented the preprocessed
+ /// entity from being loaded.
+ virtual PreprocessedEntity *ReadPreprocessedEntity(unsigned Index);
+
+ /// \brief Returns a pair of [Begin, End) indices of preallocated
+ /// preprocessed entities that \arg Range encompasses.
+ virtual std::pair<unsigned, unsigned>
+ findPreprocessedEntitiesInRange(SourceRange Range);
/// \brief Read the header file information for the given file entry.
virtual HeaderFileInfo GetHeaderFileInfo(const FileEntry *FE);
- void ReadPragmaDiagnosticMappings(Diagnostic &Diag);
+ void ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag);
/// \brief Returns the number of source locations found in the chain.
unsigned getTotalNumSLocs() const {
return TotalNumSLocEntries;
}
- /// \brief Returns the next SLocEntry offset after the chain.
- unsigned getNextSLocOffset() const {
- return NextSLocOffset;
- }
-
/// \brief Returns the number of identifiers found in the chain.
unsigned getTotalNumIdentifiers() const {
return static_cast<unsigned>(IdentifiersLoaded.size());
@@ -985,54 +831,110 @@ public:
return static_cast<unsigned>(SelectorsLoaded.size());
}
- /// \brief Returns the number of macro definitions found in the chain.
- unsigned getTotalNumMacroDefinitions() const {
- return static_cast<unsigned>(MacroDefinitionsLoaded.size());
+ /// \brief Returns the number of preprocessed entities known to the AST
+ /// reader.
+ unsigned getTotalNumPreprocessedEntities() const {
+ unsigned Result = 0;
+ for (ModuleConstIterator I = ModuleMgr.begin(),
+ E = ModuleMgr.end(); I != E; ++I) {
+ Result += (*I)->NumPreprocessedEntities;
+ }
+
+ return Result;
}
/// \brief Returns the number of C++ base specifiers found in the chain.
- unsigned getTotalNumCXXBaseSpecifiers() const;
+ unsigned getTotalNumCXXBaseSpecifiers() const {
+ return NumCXXBaseSpecifiersLoaded;
+ }
/// \brief Reads a TemplateArgumentLocInfo appropriate for the
/// given TemplateArgument kind.
TemplateArgumentLocInfo
- GetTemplateArgumentLocInfo(PerFileData &F, TemplateArgument::ArgKind Kind,
+ GetTemplateArgumentLocInfo(Module &F, TemplateArgument::ArgKind Kind,
const RecordData &Record, unsigned &Idx);
/// \brief Reads a TemplateArgumentLoc.
TemplateArgumentLoc
- ReadTemplateArgumentLoc(PerFileData &F,
+ ReadTemplateArgumentLoc(Module &F,
const RecordData &Record, unsigned &Idx);
/// \brief Reads a declarator info from the given record.
- TypeSourceInfo *GetTypeSourceInfo(PerFileData &F,
+ TypeSourceInfo *GetTypeSourceInfo(Module &F,
const RecordData &Record, unsigned &Idx);
- /// \brief Resolve and return the translation unit declaration.
- TranslationUnitDecl *GetTranslationUnitDecl();
-
/// \brief Resolve a type ID into a type, potentially building a new
/// type.
QualType GetType(serialization::TypeID ID);
- /// \brief Returns the type ID associated with the given type.
- /// If the type didn't come from the AST file the ID that is returned is
- /// marked as "doesn't exist in AST".
- serialization::TypeID GetTypeID(QualType T) const;
-
- /// \brief Returns the type index associated with the given type.
- /// If the type didn't come from the AST file the index that is returned is
- /// marked as "doesn't exist in AST".
- serialization::TypeIdx GetTypeIdx(QualType T) const;
+ /// \brief Resolve a local type ID within a given AST file into a type.
+ QualType getLocalType(Module &F, unsigned LocalID);
+
+ /// \brief Map a local type ID within a given AST file into a global type ID.
+ serialization::TypeID getGlobalTypeID(Module &F, unsigned LocalID) const;
+
+ /// \brief Read a type from the current position in the given record, which
+ /// was read from the given AST file.
+ QualType readType(Module &F, const RecordData &Record, unsigned &Idx) {
+ if (Idx >= Record.size())
+ return QualType();
+
+ return getLocalType(F, Record[Idx++]);
+ }
+
+ /// \brief Map from a local declaration ID within a given module to a
+ /// global declaration ID.
+ serialization::DeclID getGlobalDeclID(Module &F, unsigned LocalID) const;
+ /// \brief Returns true if global DeclID \arg ID originated from module
+ /// \arg M.
+ bool isDeclIDFromModule(serialization::GlobalDeclID ID, Module &M) const;
+
/// \brief Resolve a declaration ID into a declaration, potentially
/// building a new declaration.
Decl *GetDecl(serialization::DeclID ID);
virtual Decl *GetExternalDecl(uint32_t ID);
- /// \brief Resolve a CXXBaseSpecifiers ID into an offset into the chain
- /// of loaded AST files.
- uint64_t GetCXXBaseSpecifiersOffset(serialization::CXXBaseSpecifiersID ID);
+ /// \brief Reads a declaration with the given local ID in the given module.
+ Decl *GetLocalDecl(Module &F, uint32_t LocalID) {
+ return GetDecl(getGlobalDeclID(F, LocalID));
+ }
+
+ /// \brief Reads a declaration with the given local ID in the given module.
+ ///
+ /// \returns The requested declaration, casted to the given return type.
+ template<typename T>
+ T *GetLocalDeclAs(Module &F, uint32_t LocalID) {
+ return cast_or_null<T>(GetLocalDecl(F, LocalID));
+ }
+
+ /// \brief Reads a declaration ID from the given position in a record in the
+ /// given module.
+ ///
+ /// \returns The declaration ID read from the record, adjusted to a global ID.
+ serialization::DeclID ReadDeclID(Module &F, const RecordData &Record,
+ unsigned &Idx);
+
+ /// \brief Reads a declaration from the given position in a record in the
+ /// given module.
+ Decl *ReadDecl(Module &F, const RecordData &R, unsigned &I) {
+ return GetDecl(ReadDeclID(F, R, I));
+ }
+
+ /// \brief Reads a declaration from the given position in a record in the
+ /// given module.
+ ///
+ /// \returns The declaration read from this location, casted to the given
+ /// result type.
+ template<typename T>
+ T *ReadDeclAs(Module &F, const RecordData &R, unsigned &I) {
+ return cast_or_null<T>(GetDecl(ReadDeclID(F, R, I)));
+ }
+
+ /// \brief Read a CXXBaseSpecifiers ID form the given record and
+ /// return its global bit offset.
+ uint64_t readCXXBaseSpecifiers(Module &M, const RecordData &Record,
+ unsigned &Idx);
virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset);
@@ -1055,8 +957,6 @@ public:
FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name);
- virtual void MaterializeVisibleDecls(const DeclContext *DC);
-
/// \brief Read all of the declarations lexically stored in a
/// declaration context.
///
@@ -1072,7 +972,7 @@ public:
/// declarations for this declaration context.
virtual ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC,
bool (*isKindWeWant)(Decl::Kind),
- llvm::SmallVectorImpl<Decl*> &Decls);
+ SmallVectorImpl<Decl*> &Decls);
/// \brief Notify ASTReader that we started deserialization of
/// a decl or type so until FinishedDeserializing is called there may be
@@ -1093,6 +993,9 @@ public:
/// \brief Print some statistics about AST usage.
virtual void PrintStats();
+ /// \brief Dump information about the AST reader to standard error.
+ void dump();
+
/// Return the amount of memory used by memory buffers, breaking down
/// by heap-backed versus mmap'ed memory.
virtual void getMemoryBufferSizes(MemoryBufferSizes &sizes) const;
@@ -1112,7 +1015,7 @@ public:
/// declarations will be deserialized and introduced into the declaration
/// chain of the identifier.
virtual IdentifierInfo *get(const char *NameStart, const char *NameEnd);
- IdentifierInfo *get(llvm::StringRef Name) {
+ IdentifierInfo *get(StringRef Name) {
return get(Name.begin(), Name.end());
}
@@ -1131,14 +1034,42 @@ public:
/// \brief Load the set of namespaces that are known to the external source,
/// which will be used during typo correction.
virtual void ReadKnownNamespaces(
- llvm::SmallVectorImpl<NamespaceDecl *> &Namespaces);
+ SmallVectorImpl<NamespaceDecl *> &Namespaces);
+
+ virtual void ReadTentativeDefinitions(
+ SmallVectorImpl<VarDecl *> &TentativeDefs);
+
+ virtual void ReadUnusedFileScopedDecls(
+ SmallVectorImpl<const DeclaratorDecl *> &Decls);
+
+ virtual void ReadDelegatingConstructors(
+ SmallVectorImpl<CXXConstructorDecl *> &Decls);
+
+ virtual void ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl *> &Decls);
+
+ virtual void ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls);
+
+ virtual void ReadLocallyScopedExternalDecls(
+ SmallVectorImpl<NamedDecl *> &Decls);
+
+ virtual void ReadReferencedSelectors(
+ SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels);
+
+ virtual void ReadWeakUndeclaredIdentifiers(
+ SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo> > &WI);
+
+ virtual void ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables);
+
+ virtual void ReadPendingInstantiations(
+ SmallVectorImpl<std::pair<ValueDecl *,
+ SourceLocation> > &Pending);
/// \brief Load a selector from disk, registering its ID if it exists.
void LoadSelector(Selector Sel);
void SetIdentifierInfo(unsigned ID, IdentifierInfo *II);
void SetGloballyVisibleDecls(IdentifierInfo *II,
- const llvm::SmallVectorImpl<uint32_t> &DeclIDs,
+ const SmallVectorImpl<uint32_t> &DeclIDs,
bool Nonrecursive = false);
/// \brief Report a diagnostic.
@@ -1147,92 +1078,112 @@ public:
/// \brief Report a diagnostic.
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID);
- IdentifierInfo *DecodeIdentifierInfo(unsigned Idx);
+ IdentifierInfo *DecodeIdentifierInfo(serialization::IdentifierID ID);
- IdentifierInfo *GetIdentifierInfo(const RecordData &Record, unsigned &Idx) {
- return DecodeIdentifierInfo(Record[Idx++]);
+ IdentifierInfo *GetIdentifierInfo(Module &M, const RecordData &Record,
+ unsigned &Idx) {
+ return DecodeIdentifierInfo(getGlobalIdentifierID(M, Record[Idx++]));
}
- virtual IdentifierInfo *GetIdentifier(unsigned ID) {
+ virtual IdentifierInfo *GetIdentifier(serialization::IdentifierID ID) {
return DecodeIdentifierInfo(ID);
}
+ IdentifierInfo *getLocalIdentifier(Module &M, unsigned LocalID);
+
+ serialization::IdentifierID getGlobalIdentifierID(Module &M,
+ unsigned LocalID);
+
/// \brief Read the source location entry with index ID.
- virtual bool ReadSLocEntry(unsigned ID);
+ virtual bool ReadSLocEntry(int ID);
+
+ /// \brief Retrieve a selector from the given module with its local ID
+ /// number.
+ Selector getLocalSelector(Module &M, unsigned LocalID);
- Selector DecodeSelector(unsigned Idx);
+ Selector DecodeSelector(serialization::SelectorID Idx);
- virtual Selector GetExternalSelector(uint32_t ID);
+ virtual Selector GetExternalSelector(serialization::SelectorID ID);
uint32_t GetNumExternalSelectors();
- Selector GetSelector(const RecordData &Record, unsigned &Idx) {
- return DecodeSelector(Record[Idx++]);
+ Selector ReadSelector(Module &M, const RecordData &Record, unsigned &Idx) {
+ return getLocalSelector(M, Record[Idx++]);
}
+
+ /// \brief Retrieve the global selector ID that corresponds to this
+ /// the local selector ID in a given module.
+ serialization::SelectorID getGlobalSelectorID(Module &F,
+ unsigned LocalID) const;
/// \brief Read a declaration name.
- DeclarationName ReadDeclarationName(const RecordData &Record, unsigned &Idx);
- void ReadDeclarationNameLoc(PerFileData &F,
+ DeclarationName ReadDeclarationName(Module &F,
+ const RecordData &Record, unsigned &Idx);
+ void ReadDeclarationNameLoc(Module &F,
DeclarationNameLoc &DNLoc, DeclarationName Name,
const RecordData &Record, unsigned &Idx);
- void ReadDeclarationNameInfo(PerFileData &F, DeclarationNameInfo &NameInfo,
+ void ReadDeclarationNameInfo(Module &F, DeclarationNameInfo &NameInfo,
const RecordData &Record, unsigned &Idx);
- void ReadQualifierInfo(PerFileData &F, QualifierInfo &Info,
+ void ReadQualifierInfo(Module &F, QualifierInfo &Info,
const RecordData &Record, unsigned &Idx);
- NestedNameSpecifier *ReadNestedNameSpecifier(const RecordData &Record,
+ NestedNameSpecifier *ReadNestedNameSpecifier(Module &F,
+ const RecordData &Record,
unsigned &Idx);
- NestedNameSpecifierLoc ReadNestedNameSpecifierLoc(PerFileData &F,
+ NestedNameSpecifierLoc ReadNestedNameSpecifierLoc(Module &F,
const RecordData &Record,
unsigned &Idx);
/// \brief Read a template name.
- TemplateName ReadTemplateName(PerFileData &F, const RecordData &Record,
+ TemplateName ReadTemplateName(Module &F, const RecordData &Record,
unsigned &Idx);
/// \brief Read a template argument.
- TemplateArgument ReadTemplateArgument(PerFileData &F,
+ TemplateArgument ReadTemplateArgument(Module &F,
const RecordData &Record,unsigned &Idx);
/// \brief Read a template parameter list.
- TemplateParameterList *ReadTemplateParameterList(PerFileData &F,
+ TemplateParameterList *ReadTemplateParameterList(Module &F,
const RecordData &Record,
unsigned &Idx);
/// \brief Read a template argument array.
void
- ReadTemplateArgumentList(llvm::SmallVector<TemplateArgument, 8> &TemplArgs,
- PerFileData &F, const RecordData &Record,
+ ReadTemplateArgumentList(SmallVector<TemplateArgument, 8> &TemplArgs,
+ Module &F, const RecordData &Record,
unsigned &Idx);
/// \brief Read a UnresolvedSet structure.
- void ReadUnresolvedSet(UnresolvedSetImpl &Set,
+ void ReadUnresolvedSet(Module &F, UnresolvedSetImpl &Set,
const RecordData &Record, unsigned &Idx);
/// \brief Read a C++ base specifier.
- CXXBaseSpecifier ReadCXXBaseSpecifier(PerFileData &F,
+ CXXBaseSpecifier ReadCXXBaseSpecifier(Module &F,
const RecordData &Record,unsigned &Idx);
/// \brief Read a CXXCtorInitializer array.
std::pair<CXXCtorInitializer **, unsigned>
- ReadCXXCtorInitializers(PerFileData &F, const RecordData &Record,
+ ReadCXXCtorInitializers(Module &F, const RecordData &Record,
unsigned &Idx);
/// \brief Read a source location from raw form.
- SourceLocation ReadSourceLocation(PerFileData &Module, unsigned Raw) {
- (void)Module; // No remapping yet
- return SourceLocation::getFromRawEncoding(Raw);
+ SourceLocation ReadSourceLocation(Module &Module, unsigned Raw) const {
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(Raw);
+ assert(Module.SLocRemap.find(Loc.getOffset()) != Module.SLocRemap.end() &&
+ "Cannot find offset to remap.");
+ int Remap = Module.SLocRemap.find(Loc.getOffset())->second;
+ return Loc.getLocWithOffset(Remap);
}
/// \brief Read a source location.
- SourceLocation ReadSourceLocation(PerFileData &Module,
+ SourceLocation ReadSourceLocation(Module &Module,
const RecordData &Record, unsigned& Idx) {
return ReadSourceLocation(Module, Record[Idx++]);
}
/// \brief Read a source range.
- SourceRange ReadSourceRange(PerFileData &F,
+ SourceRange ReadSourceRange(Module &F,
const RecordData &Record, unsigned& Idx);
/// \brief Read an integral value
@@ -1250,17 +1201,18 @@ public:
/// \brief Read a version tuple.
VersionTuple ReadVersionTuple(const RecordData &Record, unsigned &Idx);
- CXXTemporary *ReadCXXTemporary(const RecordData &Record, unsigned &Idx);
+ CXXTemporary *ReadCXXTemporary(Module &F, const RecordData &Record,
+ unsigned &Idx);
/// \brief Reads attributes from the current stream position.
- void ReadAttributes(PerFileData &F, AttrVec &Attrs,
+ void ReadAttributes(Module &F, AttrVec &Attrs,
const RecordData &Record, unsigned &Idx);
/// \brief Reads a statement.
- Stmt *ReadStmt(PerFileData &F);
+ Stmt *ReadStmt(Module &F);
/// \brief Reads an expression.
- Expr *ReadExpr(PerFileData &F);
+ Expr *ReadExpr(Module &F);
/// \brief Reads a sub-statement operand during statement reading.
Stmt *ReadSubStmt() {
@@ -1276,15 +1228,16 @@ public:
Expr *ReadSubExpr();
/// \brief Reads the macro record located at the given offset.
- PreprocessedEntity *ReadMacroRecord(PerFileData &F, uint64_t Offset);
-
- /// \brief Reads the preprocessed entity located at the current stream
- /// position.
- PreprocessedEntity *LoadPreprocessedEntity(PerFileData &F);
+ void ReadMacroRecord(Module &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(Module &M, unsigned LocalID) const;
+
/// \brief Note that the identifier is a macro whose record will be loaded
/// from the given AST file at the given (file-local) offset.
- void SetIdentifierIsMacro(IdentifierInfo *II, PerFileData &F,
+ void SetIdentifierIsMacro(IdentifierInfo *II, Module &F,
uint64_t Offset);
/// \brief Read the set of macros defined by this external macro source.
@@ -1297,16 +1250,13 @@ public:
/// into the unread macro record offsets table.
void LoadMacroDefinition(
llvm::DenseMap<IdentifierInfo *, uint64_t>::iterator Pos);
-
- /// \brief Retrieve the macro definition with the given ID.
- MacroDefinition *getMacroDefinition(serialization::MacroID ID);
-
+
/// \brief Retrieve the AST context that this AST reader supplements.
- ASTContext *getContext() { return Context; }
+ ASTContext &getContext() { return Context; }
// \brief Contains declarations that were loaded before we have
// access to a Sema object.
- llvm::SmallVector<NamedDecl *, 16> PreloadedDecls;
+ SmallVector<NamedDecl *, 16> PreloadedDecls;
/// \brief Retrieve the semantic analysis object used to analyze the
/// translation unit in which the precompiled header is being
diff --git a/include/clang/Serialization/ASTSerializationListener.h b/include/clang/Serialization/ASTSerializationListener.h
deleted file mode 100644
index 0c62e0b9ca5a..000000000000
--- a/include/clang/Serialization/ASTSerializationListener.h
+++ /dev/null
@@ -1,44 +0,0 @@
-//===- ASTSerializationListener.h - Decl/Type PCH Write Events -*- 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 ASTSerializationListener class, which is notified
-// by the ASTWriter when an entity is serialized.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_AST_SERIALIZATION_LISTENER_H
-#define LLVM_CLANG_FRONTEND_AST_SERIALIZATION_LISTENER_H
-
-#include "llvm/Support/DataTypes.h"
-
-namespace clang {
-
-class PreprocessedEntity;
-
-/// \brief Listener object that receives callbacks when certain kinds of
-/// entities are serialized.
-class ASTSerializationListener {
-public:
- virtual ~ASTSerializationListener();
-
- /// \brief Callback invoked whenever a preprocessed entity is serialized.
- ///
- /// This callback will only occur when the translation unit was created with
- /// a detailed preprocessing record.
- ///
- /// \param Entity The entity that has been serialized.
- ///
- /// \param Offset The offset (in bits) of this entity in the resulting
- /// AST file.
- virtual void SerializedPreprocessedEntity(PreprocessedEntity *Entity,
- uint64_t Offset) = 0;
-};
-
-}
-
-#endif
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index 18e15014be70..7a49e485f2a6 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -38,7 +38,6 @@ namespace llvm {
namespace clang {
class ASTContext;
-class ASTSerializationListener;
class NestedNameSpecifier;
class CXXBaseSpecifier;
class CXXCtorInitializer;
@@ -67,20 +66,36 @@ class VersionTuple;
class ASTWriter : public ASTDeserializationListener,
public ASTMutationListener {
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;
friend class ASTDeclWriter;
private:
+ /// \brief Map that provides the ID numbers of each type within the
+ /// output stream, plus those deserialized from a chained PCH.
+ ///
+ /// The ID numbers of types are consecutive (in order of discovery)
+ /// and start at 1. 0 is reserved for NULL. When types are actually
+ /// stored in the stream, the ID number is shifted by 2 bits to
+ /// allow for the const/volatile qualifiers.
+ ///
+ /// Keys in the map never have const/volatile qualifiers.
+ typedef llvm::DenseMap<QualType, serialization::TypeIdx,
+ serialization::UnsafeQualTypeDenseMapInfo>
+ TypeIdxMap;
+
/// \brief The bitstream writer used to emit this precompiled header.
llvm::BitstreamWriter &Stream;
+ /// \brief The ASTContext we're writing.
+ ASTContext *Context;
+
/// \brief The reader of existing AST files, if we're chaining.
ASTReader *Chain;
-
- /// \brief A listener object that receives notifications when certain
- /// entities are serialized.
- ASTSerializationListener *SerializationListener;
+
+ /// \brief Indicates when the AST writing is actively performing
+ /// serialization, rather than just queueing updates.
+ bool WritingAST;
/// \brief Stores a declaration or a type to be written to the AST file.
class DeclOrType {
@@ -142,7 +157,7 @@ private:
/// allow for the const/volatile qualifiers.
///
/// Keys in the map never have const/volatile qualifiers.
- serialization::TypeIdxMap TypeIdxs;
+ TypeIdxMap TypeIdxs;
/// \brief Offset of each type in the bitstream, indexed by
/// the type's ID.
@@ -189,23 +204,13 @@ private:
/// \brief The set of identifiers that had macro definitions at some point.
std::vector<const IdentifierInfo *> DeserializedMacroNames;
-
- /// \brief The first ID number we can use for our own macro definitions.
- serialization::MacroID FirstMacroID;
-
- /// \brief The decl ID that will be assigned to the next new macro definition.
- serialization::MacroID NextMacroID;
/// \brief Mapping from macro definitions (as they occur in the preprocessing
/// record) to the macro IDs.
- llvm::DenseMap<const MacroDefinition *, serialization::MacroID>
+ llvm::DenseMap<const MacroDefinition *, serialization::PreprocessedEntityID>
MacroDefinitions;
-
- /// \brief Mapping from the macro definition indices in \c MacroDefinitions
- /// to the corresponding offsets within the preprocessor block.
- std::vector<uint32_t> MacroDefinitionOffsets;
- typedef llvm::SmallVector<uint64_t, 2> UpdateRecord;
+ typedef SmallVector<uint64_t, 2> UpdateRecord;
typedef llvm::DenseMap<const Decl *, UpdateRecord> DeclUpdateMap;
/// \brief Mapping from declarations that came from a chained PCH to the
/// record containing modifications to them.
@@ -228,7 +233,7 @@ private:
/// headers. The declarations themselves are stored as declaration
/// IDs, since they will be written out to an EXTERNAL_DEFINITIONS
/// record.
- llvm::SmallVector<uint64_t, 16> ExternalDefinitions;
+ SmallVector<uint64_t, 16> ExternalDefinitions;
/// \brief DeclContexts that have received extensions since their serialized
/// form.
@@ -242,22 +247,39 @@ private:
/// \brief Decls that will be replaced in the current dependent AST file.
DeclsToRewriteTy DeclsToRewrite;
+ struct ChainedObjCCategoriesData {
+ /// \brief The interface in the imported module.
+ const ObjCInterfaceDecl *Interface;
+ /// \brief The local tail category ID that got chained to the imported
+ /// interface.
+ const ObjCCategoryDecl *TailCategory;
+
+ /// \brief ID corresponding to \c Interface.
+ serialization::DeclID InterfaceID;
+
+ /// \brief ID corresponding to TailCategoryID.
+ serialization::DeclID TailCategoryID;
+ };
+ /// \brief ObjC categories that got chained to an interface imported from
+ /// another module.
+ SmallVector<ChainedObjCCategoriesData, 16> LocalChainedObjCCategories;
+
/// \brief Decls that have been replaced in the current dependent AST file.
///
/// When a decl changes fundamentally after being deserialized (this shouldn't
/// happen, but the ObjC AST nodes are designed this way), it will be
/// serialized again. In this case, it is registered here, so that the reader
/// knows to read the updated version.
- llvm::SmallVector<std::pair<serialization::DeclID, uint64_t>, 16>
+ SmallVector<std::pair<serialization::DeclID, uint64_t>, 16>
ReplacedDecls;
/// \brief Statements that we've encountered while serializing a
/// declaration or type.
- llvm::SmallVector<Stmt *, 16> StmtsToEmit;
+ SmallVector<Stmt *, 16> StmtsToEmit;
/// \brief Statements collection to use for ASTWriter::AddStmt().
/// It will point to StmtsToEmit unless it is overriden.
- llvm::SmallVector<Stmt *, 16> *CollectedStmts;
+ SmallVector<Stmt *, 16> *CollectedStmts;
/// \brief Mapping from SwitchCase statements to IDs.
std::map<SwitchCase *, unsigned> SwitchCaseIDs;
@@ -280,7 +302,7 @@ private:
unsigned NumVisibleDeclContexts;
/// \brief The offset of each CXXBaseSpecifier set within the AST.
- llvm::SmallVector<uint32_t, 4> CXXBaseSpecifiersOffsets;
+ SmallVector<uint32_t, 4> CXXBaseSpecifiersOffsets;
/// \brief The first ID number we can use for our own base specifiers.
serialization::CXXBaseSpecifiersID FirstCXXBaseSpecifiersID;
@@ -306,23 +328,23 @@ private:
/// \brief Queue of C++ base specifiers to be written to the AST file,
/// in the order they should be written.
- llvm::SmallVector<QueuedCXXBaseSpecifiers, 2> CXXBaseSpecifiersToWrite;
+ SmallVector<QueuedCXXBaseSpecifiers, 2> CXXBaseSpecifiersToWrite;
/// \brief Write the given subexpression to the bitstream.
void WriteSubStmt(Stmt *S);
void WriteBlockInfoBlock();
- void WriteMetadata(ASTContext &Context, const char *isysroot,
+ void WriteMetadata(ASTContext &Context, StringRef isysroot,
const std::string &OutputFile);
void WriteLanguageOptions(const LangOptions &LangOpts);
void WriteStatCache(MemorizeStatCalls &StatCalls);
void WriteSourceManagerBlock(SourceManager &SourceMgr,
const Preprocessor &PP,
- const char* isysroot);
- void WritePreprocessor(const Preprocessor &PP);
- void WriteHeaderSearch(HeaderSearch &HS, const char* isysroot);
+ StringRef isysroot);
+ void WritePreprocessor(const Preprocessor &PP, bool IsModule);
+ void WriteHeaderSearch(HeaderSearch &HS, StringRef isysroot);
void WritePreprocessorDetail(PreprocessingRecord &PPRec);
- void WritePragmaDiagnosticMappings(const Diagnostic &Diag);
+ void WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag);
void WriteCXXBaseSpecifiersOffsets();
void WriteType(QualType T);
uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC);
@@ -330,10 +352,13 @@ private:
void WriteTypeDeclOffsets();
void WriteSelectors(Sema &SemaRef);
void WriteReferencedSelectorsPool(Sema &SemaRef);
- void WriteIdentifierTable(Preprocessor &PP);
+ void WriteIdentifierTable(Preprocessor &PP, bool IsModule);
void WriteAttributes(const AttrVec &Attrs, RecordDataImpl &Record);
+ void ResolveDeclUpdatesBlocks();
void WriteDeclUpdatesBlocks();
void WriteDeclReplacementsBlock();
+ void ResolveChainedObjCCategories();
+ void WriteChainedObjCCategories();
void WriteDeclContextVisibleUpdate(const DeclContext *DC);
void WriteFPPragmaOptions(const FPOptions &Opts);
void WriteOpenCLExtensions(Sema &SemaRef);
@@ -356,20 +381,13 @@ private:
void WriteDecl(ASTContext &Context, Decl *D);
void WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
- const char* isysroot, const std::string &OutputFile);
- void WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
- const char* isysroot);
+ StringRef isysroot, const std::string &OutputFile,
+ bool IsModule);
public:
/// \brief Create a new precompiled header writer that outputs to
/// the given bitstream.
ASTWriter(llvm::BitstreamWriter &Stream);
-
- /// \brief Set the listener that will receive notification of serialization
- /// events.
- void SetSerializationListener(ASTSerializationListener *Listener) {
- SerializationListener = Listener;
- }
/// \brief Write a precompiled header for the given semantic analysis.
///
@@ -379,14 +397,14 @@ public:
/// \param StatCalls the object that cached all of the stat() calls made while
/// searching for source files and headers.
///
- /// \param isysroot if non-NULL, write a relocatable PCH file whose headers
- /// are relative to the given system root.
+ /// \param IsModule Whether we're writing a module (otherwise, we're writing a
+ /// precompiled header).
///
- /// \param PPRec Record of the preprocessing actions that occurred while
- /// preprocessing this file, e.g., macro expansions
+ /// \param isysroot if non-empty, write a relocatable file whose headers
+ /// are relative to the given system root.
void WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
const std::string &OutputFile,
- const char* isysroot);
+ bool IsModule, StringRef isysroot);
/// \brief Emit a source location.
void AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record);
@@ -432,10 +450,6 @@ public:
"Identifier does not name a macro");
return MacroOffsets[II];
}
-
- /// \brief Retrieve the ID number corresponding to the given macro
- /// definition.
- serialization::MacroID getMacroDefinitionID(MacroDefinition *MD);
/// \brief Emit a reference to a type.
void AddTypeRef(QualType T, RecordDataImpl &Record);
@@ -447,7 +461,7 @@ public:
serialization::TypeID getTypeID(QualType T) const;
/// \brief Force a type to be emitted and get its index.
- serialization::TypeIdx GetOrCreateTypeIdx(QualType T);
+ serialization::TypeIdx GetOrCreateTypeIdx( QualType T);
/// \brief Determine the type index of an already-emitted type.
serialization::TypeIdx getTypeIdx(QualType T) const;
@@ -523,7 +537,7 @@ public:
void AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Record);
/// \brief Add a string to the given record.
- void AddString(llvm::StringRef Str, RecordDataImpl &Record);
+ void AddString(StringRef Str, RecordDataImpl &Record);
/// \brief Add a version tuple to the given record
void AddVersionTuple(const VersionTuple &Version, RecordDataImpl &Record);
@@ -597,7 +611,8 @@ public:
void TypeRead(serialization::TypeIdx Idx, QualType T);
void DeclRead(serialization::DeclID ID, const Decl *D);
void SelectorRead(serialization::SelectorID ID, Selector Sel);
- void MacroDefinitionRead(serialization::MacroID ID, MacroDefinition *MD);
+ void MacroDefinitionRead(serialization::PreprocessedEntityID ID,
+ MacroDefinition *MD);
// ASTMutationListener implementation.
virtual void CompletedTagDefinition(const TagDecl *D);
@@ -609,6 +624,8 @@ public:
const FunctionDecl *D);
virtual void CompletedImplicitDefinition(const FunctionDecl *D);
virtual void StaticDataMemberInstantiated(const VarDecl *D);
+ virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
+ const ObjCInterfaceDecl *IFD);
};
/// \brief AST and semantic-analysis consumer that generates a
@@ -616,26 +633,27 @@ public:
class PCHGenerator : public SemaConsumer {
const Preprocessor &PP;
std::string OutputFile;
- const char *isysroot;
- llvm::raw_ostream *Out;
+ bool IsModule;
+ std::string isysroot;
+ raw_ostream *Out;
Sema *SemaPtr;
MemorizeStatCalls *StatCalls; // owned by the FileManager
std::vector<unsigned char> Buffer;
llvm::BitstreamWriter Stream;
ASTWriter Writer;
- bool Chaining;
protected:
ASTWriter &getWriter() { return Writer; }
const ASTWriter &getWriter() const { return Writer; }
public:
- PCHGenerator(const Preprocessor &PP, const std::string &OutputFile, bool Chaining,
- const char *isysroot, llvm::raw_ostream *Out);
+ PCHGenerator(const Preprocessor &PP, StringRef OutputFile,
+ bool IsModule,
+ StringRef isysroot, raw_ostream *Out);
+ ~PCHGenerator();
virtual void InitializeSema(Sema &S) { SemaPtr = &S; }
virtual void HandleTranslationUnit(ASTContext &Ctx);
virtual ASTMutationListener *GetASTMutationListener();
- virtual ASTSerializationListener *GetASTSerializationListener();
virtual ASTDeserializationListener *GetASTDeserializationListener();
};
diff --git a/include/clang/Serialization/ChainedIncludesSource.h b/include/clang/Serialization/ChainedIncludesSource.h
index f547902ef0eb..620dbdf40c48 100644
--- a/include/clang/Serialization/ChainedIncludesSource.h
+++ b/include/clang/Serialization/ChainedIncludesSource.h
@@ -46,10 +46,9 @@ protected:
virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset);
virtual DeclContextLookupResult
FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);
- virtual void MaterializeVisibleDecls(const DeclContext *DC);
virtual ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC,
bool (*isKindWeWant)(Decl::Kind),
- llvm::SmallVectorImpl<Decl*> &Result);
+ SmallVectorImpl<Decl*> &Result);
virtual void CompleteType(TagDecl *Tag);
virtual void CompleteType(ObjCInterfaceDecl *Class);
virtual void StartedDeserializing();
diff --git a/include/clang/Serialization/ContinuousRangeMap.h b/include/clang/Serialization/ContinuousRangeMap.h
new file mode 100644
index 000000000000..7f7832041072
--- /dev/null
+++ b/include/clang/Serialization/ContinuousRangeMap.h
@@ -0,0 +1,120 @@
+//===--- ContinuousRangeMap.h - Map with int range as key -------*- 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 ContinuousRangeMap class, which is a highly
+// specialized container used by serialization.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SERIALIZATION_CONTINUOUS_RANGE_MAP_H
+#define LLVM_CLANG_SERIALIZATION_CONTINUOUS_RANGE_MAP_H
+
+#include "llvm/ADT/SmallVector.h"
+#include <algorithm>
+#include <utility>
+
+namespace clang {
+
+/// \brief A map from continuous integer ranges to some value, with a very
+/// specialized interface.
+///
+/// CRM maps from integer ranges to values. The ranges are continuous, i.e.
+/// where one ends, the next one begins. So if the map contains the stops I0-3,
+/// the first range is from I0 to I1, the second from I1 to I2, the third from
+/// I2 to I3 and the last from I3 to infinity.
+///
+/// Ranges must be inserted in order. Inserting a new stop I4 into the map will
+/// shrink the fourth range to I3 to I4 and add the new range I4 to inf.
+template <typename Int, typename V, unsigned InitialCapacity>
+class ContinuousRangeMap {
+public:
+ typedef std::pair<Int, V> value_type;
+ typedef value_type &reference;
+ typedef const value_type &const_reference;
+ typedef value_type *pointer;
+ typedef const value_type *const_pointer;
+
+private:
+ typedef SmallVector<value_type, InitialCapacity> Representation;
+ Representation Rep;
+
+ struct Compare {
+ bool operator ()(const_reference L, Int R) const {
+ return L.first < R;
+ }
+ bool operator ()(Int L, const_reference R) const {
+ return L < R.first;
+ }
+ bool operator ()(Int L, Int R) const {
+ return L < R;
+ }
+ bool operator ()(const_reference L, const_reference R) const {
+ return L.first < R.first;
+ }
+ };
+
+public:
+ void insert(const value_type &Val) {
+ if (!Rep.empty() && Rep.back() == Val)
+ return;
+
+ assert((Rep.empty() || Rep.back().first < Val.first) &&
+ "Must insert keys in order.");
+ Rep.push_back(Val);
+ }
+
+ typedef typename Representation::iterator iterator;
+ typedef typename Representation::const_iterator const_iterator;
+
+ iterator begin() { return Rep.begin(); }
+ iterator end() { return Rep.end(); }
+ const_iterator begin() const { return Rep.begin(); }
+ const_iterator end() const { return Rep.end(); }
+
+ iterator find(Int K) {
+ iterator I = std::upper_bound(Rep.begin(), Rep.end(), K, Compare());
+ // I points to the first entry with a key > K, which is the range that
+ // follows the one containing K.
+ if (I == Rep.begin())
+ return Rep.end();
+ --I;
+ return I;
+ }
+ const_iterator find(Int K) const {
+ return const_cast<ContinuousRangeMap*>(this)->find(K);
+ }
+
+ reference back() { return Rep.back(); }
+ const_reference back() const { return Rep.back(); }
+
+ /// \brief An object that helps properly build a continuous range map
+ /// from a set of values.
+ class Builder {
+ ContinuousRangeMap &Self;
+
+ Builder(const Builder&); // DO NOT IMPLEMENT
+ Builder &operator=(const Builder&); // DO NOT IMPLEMENT
+
+ public:
+ explicit Builder(ContinuousRangeMap &Self) : Self(Self) { }
+
+ ~Builder() {
+ std::sort(Self.Rep.begin(), Self.Rep.end(), Compare());
+ }
+
+ void insert(const value_type &Val) {
+ Self.Rep.push_back(Val);
+ }
+ };
+ friend class Builder;
+};
+
+}
+
+#endif
diff --git a/include/clang/Serialization/Makefile b/include/clang/Serialization/Makefile
index 79486b11bc68..386f45376175 100644
--- a/include/clang/Serialization/Makefile
+++ b/include/clang/Serialization/Makefile
@@ -6,14 +6,14 @@ TABLEGEN_INC_FILES_COMMON = 1
include $(CLANG_LEVEL)/Makefile
-$(ObjDir)/AttrPCHRead.inc.tmp : $(TD_SRC_DIR)/Attr.td $(TBLGEN) \
+$(ObjDir)/AttrPCHRead.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
$(ObjDir)/.dir
$(Echo) "Building Clang PCH reader with tblgen"
- $(Verb) $(TableGen) -gen-clang-attr-pch-read -o $(call SYSPATH, $@) \
+ $(Verb) $(ClangTableGen) -gen-clang-attr-pch-read -o $(call SYSPATH, $@) \
-I $(PROJ_SRC_DIR)/../../ $<
-$(ObjDir)/AttrPCHWrite.inc.tmp : $(TD_SRC_DIR)/Attr.td $(TBLGEN) \
+$(ObjDir)/AttrPCHWrite.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
$(ObjDir)/.dir
$(Echo) "Building Clang PCH writer with tblgen"
- $(Verb) $(TableGen) -gen-clang-attr-pch-write -o $(call SYSPATH, $@) \
+ $(Verb) $(ClangTableGen) -gen-clang-attr-pch-write -o $(call SYSPATH, $@) \
-I $(PROJ_SRC_DIR)/../../ $<
diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h
new file mode 100644
index 000000000000..42b5a58e085f
--- /dev/null
+++ b/include/clang/Serialization/Module.h
@@ -0,0 +1,319 @@
+//===--- Module.h - Module description --------------------------*- 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 Module class, which describes a module that has
+// been loaded from an AST file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SERIALIZATION_MODULE_H
+#define LLVM_CLANG_SERIALIZATION_MODULE_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"
+#include <string>
+
+namespace clang {
+
+class DeclContext;
+
+namespace serialization {
+
+/// \brief Specifies the kind of module that has been loaded.
+enum ModuleKind {
+ MK_Module, ///< File is a module proper.
+ MK_PCH, ///< File is a PCH file treated as such.
+ MK_Preamble, ///< File is a PCH file treated as the preamble.
+ MK_MainFile ///< File is a PCH file treated as the actual main file.
+};
+
+/// \brief Information about the contents of a DeclContext.
+struct DeclContextInfo {
+ DeclContextInfo()
+ : NameLookupTableData(), LexicalDecls(), NumLexicalDecls() {}
+
+ void *NameLookupTableData; // an ASTDeclContextNameLookupTable.
+ const KindDeclIDPair *LexicalDecls;
+ unsigned NumLexicalDecls;
+};
+
+/// \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
+/// may be a precompiled header, precompiled preamble, a module, or an AST file
+/// of some sort loaded as the main file, all of which are specific formulations of
+/// the general notion of a "module". A module may depend on any number of
+/// other modules.
+class Module {
+public:
+ Module(ModuleKind Kind);
+ ~Module();
+
+ // === General information ===
+
+ /// \brief The type of this module.
+ ModuleKind Kind;
+
+ /// \brief The file name of the module file.
+ std::string FileName;
+
+ /// \brief Whether this module has been directly imported by the
+ /// user.
+ bool DirectlyImported;
+
+ /// \brief The memory buffer that stores the data associated with
+ /// this AST file.
+ llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
+
+ /// \brief The size of this file, in bits.
+ uint64_t SizeInBits;
+
+ /// \brief The global bit offset (or base) of this module
+ uint64_t GlobalBitOffset;
+
+ /// \brief The bitstream reader from which we'll read the AST file.
+ llvm::BitstreamReader StreamFile;
+
+ /// \brief The main bitstream cursor for the main block.
+ llvm::BitstreamCursor Stream;
+
+ /// \brief The source location where this module was first imported.
+ SourceLocation ImportLoc;
+
+ /// \brief The first source location in this module.
+ SourceLocation FirstLoc;
+
+ // === Source Locations ===
+
+ /// \brief Cursor used to read source location entries.
+ llvm::BitstreamCursor SLocEntryCursor;
+
+ /// \brief The number of source location entries in this AST file.
+ unsigned LocalNumSLocEntries;
+
+ /// \brief The base ID in the source manager's view of this module.
+ int SLocEntryBaseID;
+
+ /// \brief The base offset in the source manager's view of this module.
+ unsigned SLocEntryBaseOffset;
+
+ /// \brief Offsets for all of the source location entries in the
+ /// AST file.
+ const uint32_t *SLocEntryOffsets;
+
+ /// \brief SLocEntries that we're going to preload.
+ SmallVector<uint64_t, 4> PreloadSLocEntries;
+
+ /// \brief The number of source location file entries in this AST file.
+ unsigned LocalNumSLocFileEntries;
+
+ /// \brief Offsets for all of the source location file entries in the
+ /// AST file.
+ const uint32_t *SLocFileOffsets;
+
+ /// \brief Remapping table for source locations in this module.
+ ContinuousRangeMap<uint32_t, int, 2> SLocRemap;
+
+ // === Identifiers ===
+
+ /// \brief The number of identifiers in this AST file.
+ unsigned LocalNumIdentifiers;
+
+ /// \brief Offsets into the identifier table data.
+ ///
+ /// This array is indexed by the identifier ID (-1), and provides
+ /// the offset into IdentifierTableData where the string data is
+ /// stored.
+ const uint32_t *IdentifierOffsets;
+
+ /// \brief Base identifier ID for identifiers local to this module.
+ serialization::IdentID BaseIdentifierID;
+
+ /// \brief Remapping table for identifier IDs in this module.
+ ContinuousRangeMap<uint32_t, int, 2> IdentifierRemap;
+
+ /// \brief Actual data for the on-disk hash table of identifiers.
+ ///
+ /// This pointer points into a memory buffer, where the on-disk hash
+ /// table for identifiers actually lives.
+ const char *IdentifierTableData;
+
+ /// \brief A pointer to an on-disk hash table of opaque type
+ /// IdentifierHashTable.
+ void *IdentifierLookupTable;
+
+ // === Macros ===
+
+ /// \brief The cursor to the start of the preprocessor block, which stores
+ /// all of the macro definitions.
+ llvm::BitstreamCursor MacroCursor;
+
+ /// \brief The offset of the start of the set of defined macros.
+ uint64_t MacroStartOffset;
+
+ // === Detailed PreprocessingRecord ===
+
+ /// \brief The cursor to the start of the (optional) detailed preprocessing
+ /// record block.
+ llvm::BitstreamCursor PreprocessorDetailCursor;
+
+ /// \brief The offset of the start of the preprocessor detail cursor.
+ uint64_t PreprocessorDetailStartOffset;
+
+ /// \brief Base preprocessed entity ID for preprocessed entities local to
+ /// this module.
+ serialization::PreprocessedEntityID BasePreprocessedEntityID;
+
+ /// \brief Remapping table for preprocessed entity IDs in this module.
+ ContinuousRangeMap<uint32_t, int, 2> PreprocessedEntityRemap;
+
+ const PPEntityOffset *PreprocessedEntityOffsets;
+ unsigned NumPreprocessedEntities;
+
+ // === Header search information ===
+
+ /// \brief The number of local HeaderFileInfo structures.
+ unsigned LocalNumHeaderFileInfos;
+
+ /// \brief Actual data for the on-disk hash table of header file
+ /// information.
+ ///
+ /// This pointer points into a memory buffer, where the on-disk hash
+ /// table for header file information actually lives.
+ const char *HeaderFileInfoTableData;
+
+ /// \brief The on-disk hash table that contains information about each of
+ /// the header files.
+ void *HeaderFileInfoTable;
+
+ /// \brief Actual data for the list of framework names used in the header
+ /// search information.
+ const char *HeaderFileFrameworkStrings;
+
+ // === Selectors ===
+
+ /// \brief The number of selectors new to this file.
+ ///
+ /// This is the number of entries in SelectorOffsets.
+ unsigned LocalNumSelectors;
+
+ /// \brief Offsets into the selector lookup table's data array
+ /// where each selector resides.
+ const uint32_t *SelectorOffsets;
+
+ /// \brief Base selector ID for selectors local to this module.
+ serialization::SelectorID BaseSelectorID;
+
+ /// \brief Remapping table for selector IDs in this module.
+ ContinuousRangeMap<uint32_t, int, 2> SelectorRemap;
+
+ /// \brief A pointer to the character data that comprises the selector table
+ ///
+ /// The SelectorOffsets table refers into this memory.
+ const unsigned char *SelectorLookupTableData;
+
+ /// \brief A pointer to an on-disk hash table of opaque type
+ /// ASTSelectorLookupTable.
+ ///
+ /// This hash table provides the IDs of all selectors, and the associated
+ /// instance and factory methods.
+ void *SelectorLookupTable;
+
+ // === Declarations ===
+
+ /// DeclsCursor - This is a cursor to the start of the DECLS_BLOCK block. It
+ /// has read all the abbreviations at the start of the block and is ready to
+ /// jump around with these in context.
+ llvm::BitstreamCursor DeclsCursor;
+
+ /// \brief The number of declarations in this AST file.
+ unsigned LocalNumDecls;
+
+ /// \brief Offset of each declaration within the bitstream, indexed
+ /// by the declaration ID (-1).
+ const uint32_t *DeclOffsets;
+
+ /// \brief Base declaration ID for declarations local to this module.
+ serialization::DeclID BaseDeclID;
+
+ /// \brief Remapping table for declaration IDs in this module.
+ ContinuousRangeMap<uint32_t, int, 2> DeclRemap;
+
+ /// \brief The number of C++ base specifier sets in this AST file.
+ unsigned LocalNumCXXBaseSpecifiers;
+
+ /// \brief Offset of each C++ base specifier set within the bitstream,
+ /// indexed by the C++ base specifier set ID (-1).
+ const uint32_t *CXXBaseSpecifiersOffsets;
+
+ typedef llvm::DenseMap<const DeclContext *, DeclContextInfo>
+ DeclContextInfosMap;
+
+ /// \brief Information about the lexical and visible declarations
+ /// for each DeclContext.
+ DeclContextInfosMap DeclContextInfos;
+
+ typedef llvm::DenseMap<serialization::GlobalDeclID,
+ std::pair<serialization::LocalDeclID, serialization::LocalDeclID> >
+ ChainedObjCCategoriesMap;
+ /// \brief ObjC categories that got chained to an interface from another
+ /// module.
+ /// Key is the ID of the interface.
+ /// Value is a pair of linked category DeclIDs (head category, tail category).
+ ChainedObjCCategoriesMap ChainedObjCCategories;
+
+ // === Types ===
+
+ /// \brief The number of types in this AST file.
+ unsigned LocalNumTypes;
+
+ /// \brief Offset of each type within the bitstream, indexed by the
+ /// type ID, or the representation of a Type*.
+ const uint32_t *TypeOffsets;
+
+ /// \brief Base type ID for types local to this module as represented in
+ /// the global type ID space.
+ serialization::TypeID BaseTypeIndex;
+
+ /// \brief Remapping table for type IDs in this module.
+ ContinuousRangeMap<uint32_t, int, 2> TypeRemap;
+
+ // === Miscellaneous ===
+
+ /// \brief Diagnostic IDs and their mappings that the user changed.
+ SmallVector<uint64_t, 8> PragmaDiagMappings;
+
+ /// \brief The AST stat cache installed for this file, if any.
+ ///
+ /// The dynamic type of this stat cache is always ASTStatCache
+ void *StatCache;
+
+ /// \brief List of modules which depend on this module
+ llvm::SetVector<Module *> ImportedBy;
+
+ /// \brief List of modules which this module depends on
+ llvm::SetVector<Module *> Imports;
+
+ /// \brief Determine whether this module was directly imported at
+ /// any point during translation.
+ bool isDirectlyImported() const { return DirectlyImported; }
+
+ /// \brief Dump debugging output for this module.
+ void dump();
+};
+
+} // end namespace serialization
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Serialization/ModuleManager.h b/include/clang/Serialization/ModuleManager.h
new file mode 100644
index 000000000000..f86915a79cd0
--- /dev/null
+++ b/include/clang/Serialization/ModuleManager.h
@@ -0,0 +1,156 @@
+//===--- ModuleManager.cpp - Module Manager ---------------------*- 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 ModuleManager class, which manages a set of loaded
+// modules for the ASTReader.
+//
+//===----------------------------------------------------------------------===//
+
+#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 "llvm/ADT/DenseMap.h"
+
+namespace clang {
+
+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<Module*, 2> Chain;
+
+ /// \brief All loaded modules, indexed by name.
+ llvm::DenseMap<const FileEntry *, Module *> Modules;
+
+ /// \brief FileManager that handles translating between filenames and
+ /// FileEntry *.
+ FileManager FileMgr;
+
+ /// \brief A lookup of in-memory (virtual file) buffers
+ llvm::DenseMap<const FileEntry *, llvm::MemoryBuffer *> InMemoryBuffers;
+
+public:
+ typedef SmallVector<Module*, 2>::iterator ModuleIterator;
+ typedef SmallVector<Module*, 2>::const_iterator ModuleConstIterator;
+ typedef SmallVector<Module*, 2>::reverse_iterator ModuleReverseIterator;
+ typedef std::pair<uint32_t, StringRef> ModuleOffset;
+
+ ModuleManager(const FileSystemOptions &FSO);
+ ~ModuleManager();
+
+ /// \brief Forward iterator to traverse all loaded modules. This is reverse
+ /// source-order.
+ ModuleIterator begin() { return Chain.begin(); }
+ /// \brief Forward iterator end-point to traverse all loaded modules
+ ModuleIterator end() { return Chain.end(); }
+
+ /// \brief Const forward iterator to traverse all loaded modules. This is
+ /// in reverse source-order.
+ ModuleConstIterator begin() const { return Chain.begin(); }
+ /// \brief Const forward iterator end-point to traverse all loaded modules
+ ModuleConstIterator end() const { return Chain.end(); }
+
+ /// \brief Reverse iterator to traverse all loaded modules. This is in
+ /// source order.
+ ModuleReverseIterator rbegin() { return Chain.rbegin(); }
+ /// \brief Reverse iterator end-point to traverse all loaded modules.
+ ModuleReverseIterator rend() { return Chain.rend(); }
+
+ /// \brief Returns the primary module associated with the manager, that is,
+ /// the first module loaded
+ Module &getPrimaryModule() { return *Chain[0]; }
+
+ /// \brief Returns the primary module associated with the manager, that is,
+ /// the first module loaded.
+ Module &getPrimaryModule() const { return *Chain[0]; }
+
+ /// \brief Returns the module associated with the given index
+ Module &operator[](unsigned Index) const { return *Chain[Index]; }
+
+ /// \brief Returns the module associated with the given name
+ Module *lookup(StringRef Name);
+
+ /// \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 Attempts to create a new module and add it to the list of known
+ /// modules.
+ ///
+ /// \param FileName The file name of the module to be loaded.
+ ///
+ /// \param Type The kind of module being loaded.
+ ///
+ /// \param ImportedBy The module that is importing this module, or NULL if
+ /// this module is imported directly by the user.
+ ///
+ /// \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<Module *, bool>
+ addModule(StringRef FileName, ModuleKind Type, Module *ImportedBy,
+ std::string &ErrorStr);
+
+ /// \brief Add an in-memory buffer the list of known buffers
+ void addInMemoryBuffer(StringRef FileName, llvm::MemoryBuffer *Buffer);
+
+ /// \brief Visit each of the modules.
+ ///
+ /// This routine visits each of the modules, starting with the
+ /// "root" modules that no other loaded modules depend on, and
+ /// proceeding to the leaf modules, visiting each module only once
+ /// during the traversal.
+ ///
+ /// This traversal is intended to support various "lookup"
+ /// operations that can find data in any of the loaded modules.
+ ///
+ /// \param Visitor A visitor function that will be invoked with each
+ /// module and the given user data pointer. The return value must be
+ /// convertible to bool; when false, the visitation continues to
+ /// modules that the current module depends on. When true, the
+ /// visitation skips any modules that the current module depends on.
+ ///
+ /// \param UserData User data associated with the visitor object, which
+ /// will be passed along to the visitor.
+ void visit(bool (*Visitor)(Module &M, void *UserData), void *UserData);
+
+ /// \brief Visit each of the modules with a depth-first traversal.
+ ///
+ /// This routine visits each of the modules known to the module
+ /// manager using a depth-first search, starting with the first
+ /// loaded module. The traversal invokes the callback both before
+ /// traversing the children (preorder traversal) and after
+ /// traversing the children (postorder traversal).
+ ///
+ /// \param Visitor A visitor function that will be invoked with each
+ /// module and given a \c Preorder flag that indicates whether we're
+ /// visiting the module before or after visiting its children. The
+ /// visitor may return true at any time to abort the depth-first
+ /// visitation.
+ ///
+ /// \param UserData User data ssociated with the visitor object,
+ /// which will be passed along to the user.
+ void visitDepthFirst(bool (*Visitor)(Module &M, bool Preorder,
+ void *UserData),
+ void *UserData);
+
+ /// \brief View the graphviz representation of the module graph.
+ void viewGraph();
+};
+
+} } // end namespace clang::serialization
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Checkers/ClangCheckers.h b/include/clang/StaticAnalyzer/Checkers/ClangCheckers.h
new file mode 100644
index 000000000000..cf0a30a73d8c
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Checkers/ClangCheckers.h
@@ -0,0 +1,22 @@
+//===--- ClangCheckers.h - Provides builtin checkers ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_CLANGCHECKERS_H
+#define LLVM_CLANG_STATICANALYZER_CHECKERS_CLANGCHECKERS_H
+
+namespace clang {
+namespace ento {
+class CheckerRegistry;
+
+void registerBuiltinCheckers(CheckerRegistry &registry);
+
+} // end namespace ento
+} // end namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h b/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h
index 2a3d43e22325..eee38e920898 100644
--- a/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h
+++ b/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h
@@ -16,33 +16,13 @@
#define LLVM_CLANG_GR_LOCALCHECKERS_H
namespace clang {
-
-class CFG;
-class Decl;
-class Diagnostic;
-class ASTContext;
-class LangOptions;
-class ParentMap;
-class LiveVariables;
-class ObjCImplementationDecl;
-class LangOptions;
-class TranslationUnitDecl;
-
namespace ento {
-class PathDiagnosticClient;
-class TransferFuncs;
-class BugType;
-class BugReporter;
class ExprEngine;
-TransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
- const LangOptions& lopts);
-
void RegisterCallInliner(ExprEngine &Eng);
-} // end GR namespace
-
+} // end namespace ento
} // end namespace clang
#endif
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index 3acbcd685bc0..bfb7ef8964ea 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This file defines BugReporter, a utility class for generating
-// PathDiagnostics for analyses based on GRState.
+// PathDiagnostics for analyses based on ProgramState.
//
//===----------------------------------------------------------------------===//
@@ -16,7 +16,9 @@
#define LLVM_CLANG_GR_BUGREPORTER
#include "clang/Basic/SourceLocation.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/ImmutableSet.h"
@@ -26,121 +28,138 @@
namespace clang {
class ASTContext;
-class Diagnostic;
+class DiagnosticsEngine;
class Stmt;
class ParentMap;
namespace ento {
class PathDiagnostic;
-class PathDiagnosticPiece;
-class PathDiagnosticClient;
class ExplodedNode;
class ExplodedGraph;
+class BugReport;
class BugReporter;
class BugReporterContext;
class ExprEngine;
-class GRState;
class BugType;
//===----------------------------------------------------------------------===//
// Interface for individual bug reports.
//===----------------------------------------------------------------------===//
-class BugReporterVisitor : public llvm::FoldingSetNode {
+/// This class provides an interface through which checkers can create
+/// individual bug reports.
+class BugReport {
public:
- virtual ~BugReporterVisitor();
- virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
- const ExplodedNode* PrevN,
- BugReporterContext& BRC) = 0;
+ class NodeResolver {
+ public:
+ virtual ~NodeResolver() {}
+ virtual const ExplodedNode*
+ getOriginalNode(const ExplodedNode *N) = 0;
+ };
- virtual bool isOwnedByReporterContext() { return true; }
- virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
-};
+ typedef const SourceRange *ranges_iterator;
+ typedef llvm::ImmutableList<BugReporterVisitor*>::iterator visitor_iterator;
+ typedef SmallVector<StringRef, 2> ExtraTextList;
-// FIXME: Combine this with RangedBugReport and remove RangedBugReport.
-class BugReport : public BugReporterVisitor {
protected:
+ friend class BugReporter;
+ friend class BugReportEquivClass;
+
BugType& BT;
std::string ShortDescription;
std::string Description;
+ PathDiagnosticLocation Location;
const ExplodedNode *ErrorNode;
- mutable SourceRange R;
-
-protected:
- friend class BugReporter;
- friend class BugReportEquivClass;
+ SmallVector<SourceRange, 4> Ranges;
+ ExtraTextList ExtraText;
- virtual void Profile(llvm::FoldingSetNodeID& hash) const {
- hash.AddPointer(&BT);
- hash.AddInteger(getLocation().getRawEncoding());
- hash.AddString(Description);
- }
+ // Not the most efficient data structure, but we use an ImmutableList for the
+ // Callbacks because it is safe to make additions to list during iteration.
+ llvm::ImmutableList<BugReporterVisitor*>::Factory F;
+ llvm::ImmutableList<BugReporterVisitor*> Callbacks;
+ llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
public:
- class NodeResolver {
- public:
- virtual ~NodeResolver() {}
- virtual const ExplodedNode*
- getOriginalNode(const ExplodedNode* N) = 0;
- };
-
- BugReport(BugType& bt, llvm::StringRef desc, const ExplodedNode *errornode)
- : BT(bt), Description(desc), ErrorNode(errornode) {}
+ BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode)
+ : BT(bt), Description(desc), ErrorNode(errornode),
+ Callbacks(F.getEmptyList()) {}
- BugReport(BugType& bt, llvm::StringRef shortDesc, llvm::StringRef desc,
+ BugReport(BugType& bt, StringRef shortDesc, StringRef desc,
const ExplodedNode *errornode)
- : BT(bt), ShortDescription(shortDesc), Description(desc),
- ErrorNode(errornode) {}
+ : BT(bt), ShortDescription(shortDesc), Description(desc),
+ ErrorNode(errornode), Callbacks(F.getEmptyList()) {}
- virtual ~BugReport();
+ BugReport(BugType& bt, StringRef desc, PathDiagnosticLocation l)
+ : BT(bt), Description(desc), Location(l), ErrorNode(0),
+ Callbacks(F.getEmptyList()) {}
- virtual bool isOwnedByReporterContext() { return false; }
+ virtual ~BugReport();
const BugType& getBugType() const { return BT; }
BugType& getBugType() { return BT; }
- // FIXME: Perhaps this should be moved into a subclass?
- const ExplodedNode* getErrorNode() const { return ErrorNode; }
-
- // FIXME: Do we need this? Maybe getLocation() should return a ProgramPoint
- // object.
- // FIXME: If we do need it, we can probably just make it private to
- // BugReporter.
- const Stmt* getStmt() const;
+ const ExplodedNode *getErrorNode() const { return ErrorNode; }
- const llvm::StringRef getDescription() const { return Description; }
+ const StringRef getDescription() const { return Description; }
- const llvm::StringRef getShortDescription() const {
+ const StringRef getShortDescription() const {
return ShortDescription.empty() ? Description : ShortDescription;
}
- // FIXME: Is this needed?
- virtual std::pair<const char**,const char**> getExtraDescriptiveText() {
- return std::make_pair((const char**)0,(const char**)0);
+ /// \brief This allows for addition of meta data to the diagnostic.
+ ///
+ /// Currently, only the HTMLDiagnosticClient knows how to display it.
+ void addExtraText(StringRef S) {
+ ExtraText.push_back(S);
}
- // FIXME: Perhaps move this into a subclass.
- virtual PathDiagnosticPiece* getEndPath(BugReporterContext& BRC,
- const ExplodedNode* N);
+ virtual const ExtraTextList &getExtraText() {
+ return ExtraText;
+ }
- /// getLocation - Return the "definitive" location of the reported bug.
+ /// \brief Return the "definitive" location of the reported bug.
+ ///
/// While a bug can span an entire path, usually there is a specific
/// location that can be used to identify where the key issue occurred.
/// This location is used by clients rendering diagnostics.
- virtual SourceLocation getLocation() const;
+ virtual PathDiagnosticLocation getLocation(const SourceManager &SM) const;
- typedef const SourceRange *ranges_iterator;
+ const Stmt *getStmt() const;
+
+ /// \brief Add a range to a bug report.
+ ///
+ /// Ranges are used to highlight regions of interest in the source code.
+ /// They should be at the same source code line as the BugReport location.
+ /// By default, the source range of the statement corresponding to the error
+ /// node will be used; add a single invalid range to specify absence of
+ /// ranges.
+ void addRange(SourceRange R) {
+ assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used "
+ "to specify that the report does not have a range.");
+ Ranges.push_back(R);
+ }
- /// getRanges - Returns the source ranges associated with this bug.
- virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const;
+ /// \brief Get the SourceRanges associated with the report.
+ virtual std::pair<ranges_iterator, ranges_iterator> getRanges();
- virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
- const ExplodedNode* PrevN,
- BugReporterContext& BR);
+ /// \brief Add custom or predefined bug report visitors to this report.
+ ///
+ /// The visitors should be used when the default trace is not sufficient.
+ /// For example, they allow constructing a more elaborate trace.
+ /// \sa registerConditionVisitor(), registerTrackNullOrUndefValue(),
+ /// registerFindLastStore(), registerNilReceiverVisitor(), and
+ /// registerVarDeclsLastStore().
+ void addVisitor(BugReporterVisitor *visitor);
- virtual void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N) {}
+ /// Iterators through the custom diagnostic visitors.
+ visitor_iterator visitor_begin() { return Callbacks.begin(); }
+ visitor_iterator visitor_end() { return Callbacks.end(); }
+
+ /// Profile to identify equivalent bug reports for error report coalescing.
+ /// Reports are uniqued to ensure that we do not emit multiple diagnostics
+ /// for each bug.
+ virtual void Profile(llvm::FoldingSetNodeID& hash) const;
};
//===----------------------------------------------------------------------===//
@@ -148,7 +167,7 @@ public:
//===----------------------------------------------------------------------===//
class BugReportEquivClass : public llvm::FoldingSetNode {
- // List of *owned* BugReport objects.
+ /// List of *owned* BugReport objects.
std::list<BugReport*> Reports;
friend class BugReporter;
@@ -166,9 +185,9 @@ public:
std::list<BugReport*>::iterator impl;
public:
iterator(std::list<BugReport*>::iterator i) : impl(i) {}
- iterator& operator++() { ++impl; return *this; }
- bool operator==(const iterator& I) const { return I.impl == impl; }
- bool operator!=(const iterator& I) const { return I.impl != impl; }
+ iterator &operator++() { ++impl; return *this; }
+ bool operator==(const iterator &I) const { return I.impl == impl; }
+ bool operator!=(const iterator &I) const { return I.impl != impl; }
BugReport* operator*() const { return *impl; }
BugReport* operator->() const { return *impl; }
};
@@ -177,9 +196,9 @@ public:
std::list<BugReport*>::const_iterator impl;
public:
const_iterator(std::list<BugReport*>::const_iterator i) : impl(i) {}
- const_iterator& operator++() { ++impl; return *this; }
- bool operator==(const const_iterator& I) const { return I.impl == impl; }
- bool operator!=(const const_iterator& I) const { return I.impl != impl; }
+ const_iterator &operator++() { ++impl; return *this; }
+ bool operator==(const const_iterator &I) const { return I.impl == impl; }
+ bool operator!=(const const_iterator &I) const { return I.impl != impl; }
const BugReport* operator*() const { return *impl; }
const BugReport* operator->() const { return *impl; }
};
@@ -191,78 +210,6 @@ public:
const_iterator end() const { return const_iterator(Reports.end()); }
};
-
-//===----------------------------------------------------------------------===//
-// Specialized subclasses of BugReport.
-//===----------------------------------------------------------------------===//
-
-// FIXME: Collapse this with the default BugReport class.
-class RangedBugReport : public BugReport {
- llvm::SmallVector<SourceRange, 4> Ranges;
-public:
- RangedBugReport(BugType& D, llvm::StringRef description,
- ExplodedNode *errornode)
- : BugReport(D, description, errornode) {}
-
- RangedBugReport(BugType& D, llvm::StringRef shortDescription,
- llvm::StringRef description, ExplodedNode *errornode)
- : BugReport(D, shortDescription, description, errornode) {}
-
- ~RangedBugReport();
-
- // FIXME: Move this out of line.
- void addRange(SourceRange R) {
- assert(R.isValid());
- Ranges.push_back(R);
- }
-
- virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const {
- return std::make_pair(Ranges.begin(), Ranges.end());
- }
-
- virtual void Profile(llvm::FoldingSetNodeID& hash) const {
- BugReport::Profile(hash);
- for (llvm::SmallVectorImpl<SourceRange>::const_iterator I =
- Ranges.begin(), E = Ranges.end(); I != E; ++I) {
- const SourceRange range = *I;
- if (!range.isValid())
- continue;
- hash.AddInteger(range.getBegin().getRawEncoding());
- hash.AddInteger(range.getEnd().getRawEncoding());
- }
- }
-};
-
-class EnhancedBugReport : public RangedBugReport {
-public:
- typedef void (*VisitorCreator)(BugReporterContext &BRcC, const void *data,
- const ExplodedNode *N);
-
-private:
- typedef std::vector<std::pair<VisitorCreator, const void*> > Creators;
- Creators creators;
-
-public:
- EnhancedBugReport(BugType& D, llvm::StringRef description,
- ExplodedNode *errornode)
- : RangedBugReport(D, description, errornode) {}
-
- EnhancedBugReport(BugType& D, llvm::StringRef shortDescription,
- llvm::StringRef description, ExplodedNode *errornode)
- : RangedBugReport(D, shortDescription, description, errornode) {}
-
- ~EnhancedBugReport() {}
-
- void registerInitialVisitors(BugReporterContext& BRC, const ExplodedNode* N) {
- for (Creators::iterator I = creators.begin(), E = creators.end(); I!=E; ++I)
- I->first(BRC, I->second, N);
- }
-
- void addVisitorCreator(VisitorCreator creator, const void *data) {
- creators.push_back(std::make_pair(creator, data));
- }
-};
-
//===----------------------------------------------------------------------===//
// BugReporter and friends.
//===----------------------------------------------------------------------===//
@@ -270,12 +217,15 @@ public:
class BugReporterData {
public:
virtual ~BugReporterData();
- virtual Diagnostic& getDiagnostic() = 0;
- virtual PathDiagnosticClient* getPathDiagnosticClient() = 0;
- virtual ASTContext& getASTContext() = 0;
+ virtual DiagnosticsEngine& getDiagnostic() = 0;
+ virtual PathDiagnosticConsumer* getPathDiagnosticConsumer() = 0;
+ virtual ASTContext &getASTContext() = 0;
virtual SourceManager& getSourceManager() = 0;
};
+/// BugReporter is a utility class for generating PathDiagnostics for analysis.
+/// It collects the BugReports and BugTypes and knows how to generate
+/// and flush the corresponding diagnostics.
class BugReporter {
public:
enum Kind { BaseBRKind, GRBugReporterKind };
@@ -288,9 +238,13 @@ private:
const Kind kind;
BugReporterData& D;
+ /// Generate and flush the diagnostics for the given bug report.
void FlushReport(BugReportEquivClass& EQ);
+ /// The set of bug reports tracked by the BugReporter.
llvm::FoldingSet<BugReportEquivClass> EQClasses;
+ /// A vector of BugReports for tracking the allocated pointers and cleanup.
+ std::vector<BugReportEquivClass *> EQClassesVector;
protected:
BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k),
@@ -301,63 +255,71 @@ public:
D(d) {}
virtual ~BugReporter();
+ /// \brief Generate and flush diagnostics for all bug reports.
void FlushReports();
Kind getKind() const { return kind; }
- Diagnostic& getDiagnostic() {
+ DiagnosticsEngine& getDiagnostic() {
return D.getDiagnostic();
}
- PathDiagnosticClient* getPathDiagnosticClient() {
- return D.getPathDiagnosticClient();
+ PathDiagnosticConsumer* getPathDiagnosticConsumer() {
+ return D.getPathDiagnosticConsumer();
}
+ /// \brief Iterator over the set of BugTypes tracked by the BugReporter.
typedef BugTypesTy::iterator iterator;
iterator begin() { return BugTypes.begin(); }
iterator end() { return BugTypes.end(); }
+ /// \brief Iterator over the set of BugReports tracked by the BugReporter.
typedef llvm::FoldingSet<BugReportEquivClass>::iterator EQClasses_iterator;
EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); }
EQClasses_iterator EQClasses_end() { return EQClasses.end(); }
- ASTContext& getContext() { return D.getASTContext(); }
+ ASTContext &getContext() { return D.getASTContext(); }
SourceManager& getSourceManager() { return D.getSourceManager(); }
virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic,
- llvm::SmallVectorImpl<BugReport *> &bugReports) {}
+ SmallVectorImpl<BugReport *> &bugReports) {}
void Register(BugType *BT);
+ /// \brief Add the given report to the set of reports tracked by BugReporter.
+ ///
+ /// The reports are usually generated by the checkers. Further, they are
+ /// folded based on the profile value, which is done to coalesce similar
+ /// reports.
void EmitReport(BugReport *R);
- void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
- SourceLocation Loc,
+ void EmitBasicReport(StringRef BugName, StringRef BugStr,
+ PathDiagnosticLocation Loc,
SourceRange* RangeBeg, unsigned NumRanges);
- void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory,
- llvm::StringRef BugStr, SourceLocation Loc,
+ void EmitBasicReport(StringRef BugName, StringRef BugCategory,
+ StringRef BugStr, PathDiagnosticLocation Loc,
SourceRange* RangeBeg, unsigned NumRanges);
- void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
- SourceLocation Loc) {
+ void EmitBasicReport(StringRef BugName, StringRef BugStr,
+ PathDiagnosticLocation Loc) {
EmitBasicReport(BugName, BugStr, Loc, 0, 0);
}
- void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory,
- llvm::StringRef BugStr, SourceLocation Loc) {
+ void EmitBasicReport(StringRef BugName, StringRef BugCategory,
+ StringRef BugStr, PathDiagnosticLocation Loc) {
EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0);
}
- void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
- SourceLocation Loc, SourceRange R) {
+ void EmitBasicReport(StringRef BugName, StringRef BugStr,
+ PathDiagnosticLocation Loc, SourceRange R) {
EmitBasicReport(BugName, BugStr, Loc, &R, 1);
}
- void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef Category,
- llvm::StringRef BugStr, SourceLocation Loc,
+ void EmitBasicReport(StringRef BugName, StringRef Category,
+ StringRef BugStr, PathDiagnosticLocation Loc,
SourceRange R) {
EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1);
}
@@ -369,7 +331,7 @@ private:
/// \brief Returns a BugType that is associated with the given name and
/// category.
- BugType *getBugTypeForName(llvm::StringRef name, llvm::StringRef category);
+ BugType *getBugTypeForName(StringRef name, StringRef category);
};
// FIXME: Get rid of GRBugReporter. It's the wrong abstraction.
@@ -392,10 +354,10 @@ public:
/// getStateManager - Return the state manager used by the analysis
/// engine.
- GRStateManager &getStateManager();
+ ProgramStateManager &getStateManager();
virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic,
- llvm::SmallVectorImpl<BugReport*> &bugReports);
+ SmallVectorImpl<BugReport*> &bugReports);
void addNotableSymbol(SymbolRef Sym) {
NotableSymbols.insert(Sym);
@@ -413,20 +375,10 @@ public:
class BugReporterContext {
GRBugReporter &BR;
- // Not the most efficient data structure, but we use an ImmutableList for the
- // Callbacks because it is safe to make additions to list during iteration.
- llvm::ImmutableList<BugReporterVisitor*>::Factory F;
- llvm::ImmutableList<BugReporterVisitor*> Callbacks;
- llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
public:
- BugReporterContext(GRBugReporter& br) : BR(br), Callbacks(F.getEmptyList()) {}
- virtual ~BugReporterContext();
-
- void addVisitor(BugReporterVisitor* visitor);
+ BugReporterContext(GRBugReporter& br) : BR(br) {}
- typedef llvm::ImmutableList<BugReporterVisitor*>::iterator visitor_iterator;
- visitor_iterator visitor_begin() { return Callbacks.begin(); }
- visitor_iterator visitor_end() { return Callbacks.end(); }
+ virtual ~BugReporterContext() {}
GRBugReporter& getBugReporter() { return BR; }
@@ -442,7 +394,7 @@ public:
return BR.isNotable(Sym);
}
- GRStateManager& getStateManager() {
+ ProgramStateManager& getStateManager() {
return BR.getStateManager();
}
@@ -450,7 +402,7 @@ public:
return getStateManager().getSValBuilder();
}
- ASTContext& getASTContext() {
+ ASTContext &getASTContext() {
return BR.getContext();
}
@@ -461,50 +413,6 @@ public:
virtual BugReport::NodeResolver& getNodeResolver() = 0;
};
-class DiagBugReport : public RangedBugReport {
- std::list<std::string> Strs;
- FullSourceLoc L;
-public:
- DiagBugReport(BugType& D, llvm::StringRef desc, FullSourceLoc l) :
- RangedBugReport(D, desc, 0), L(l) {}
-
- virtual ~DiagBugReport() {}
-
- // FIXME: Move out-of-line (virtual function).
- SourceLocation getLocation() const { return L; }
-
- void addString(llvm::StringRef s) { Strs.push_back(s); }
-
- typedef std::list<std::string>::const_iterator str_iterator;
- str_iterator str_begin() const { return Strs.begin(); }
- str_iterator str_end() const { return Strs.end(); }
-};
-
-//===----------------------------------------------------------------------===//
-//===----------------------------------------------------------------------===//
-
-namespace bugreporter {
-
-const Stmt *GetDerefExpr(const ExplodedNode *N);
-const Stmt *GetDenomExpr(const ExplodedNode *N);
-const Stmt *GetCalleeExpr(const ExplodedNode *N);
-const Stmt *GetRetValExpr(const ExplodedNode *N);
-
-void registerTrackNullOrUndefValue(BugReporterContext& BRC, const void *stmt,
- const ExplodedNode* N);
-
-void registerFindLastStore(BugReporterContext& BRC, const void *memregion,
- const ExplodedNode *N);
-
-void registerNilReceiverVisitor(BugReporterContext &BRC);
-
-void registerVarDeclsLastStore(BugReporterContext &BRC, const void *stmt,
- const ExplodedNode *N);
-
-} // end namespace clang::bugreporter
-
-//===----------------------------------------------------------------------===//
-
} // end GR namespace
} // end clang namespace
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
new file mode 100644
index 000000000000..41c0a3a46b1c
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
@@ -0,0 +1,183 @@
+//===--- BugReporterVisitor.h - Generate PathDiagnostics -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares BugReporterVisitors, which are used to generate enhanced
+// diagnostic traces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_BUGREPORTERVISITOR
+#define LLVM_CLANG_GR_BUGREPORTERVISITOR
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "llvm/ADT/FoldingSet.h"
+
+namespace clang {
+
+namespace ento {
+
+class BugReport;
+class BugReporterContext;
+class ExplodedNode;
+class MemRegion;
+class PathDiagnosticPiece;
+
+class BugReporterVisitor : public llvm::FoldingSetNode {
+public:
+ virtual ~BugReporterVisitor();
+
+ /// \brief Return a diagnostic piece which should be associated with the
+ /// given node.
+ ///
+ /// 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,
+ BugReporterContext &BRC,
+ BugReport &BR) = 0;
+
+ /// \brief Provide custom definition for the final diagnostic piece on the
+ /// path - the piece, which is displayed before the path is expanded.
+ ///
+ /// If returns NULL the default implementation will be used.
+ /// Also note that at most one visitor of a BugReport should generate a
+ /// non-NULL end of path diagnostic piece.
+ virtual PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR);
+
+ virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
+
+ /// \brief Generates the default final diagnostic piece.
+ static PathDiagnosticPiece *getDefaultEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR);
+
+};
+
+class FindLastStoreBRVisitor : public BugReporterVisitor {
+ const MemRegion *R;
+ SVal V;
+ bool satisfied;
+ const ExplodedNode *StoreSite;
+
+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);
+
+ /// Creates a visitor for every VarDecl inside a Stmt and registers it with
+ /// the BugReport.
+ static void registerStatementVarDecls(BugReport &BR, const Stmt *S);
+
+ FindLastStoreBRVisitor(SVal v, const MemRegion *r)
+ : R(r), V(v), satisfied(false), StoreSite(0) {
+ assert (!V.isUnknown() && "Cannot track unknown value.");
+
+ // TODO: Does it make sense to allow undef values here?
+ // (If not, also see UndefCapturedBlockVarChecker)?
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const;
+
+ PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR);
+};
+
+class TrackConstraintBRVisitor : public BugReporterVisitor {
+ DefinedSVal Constraint;
+ const bool Assumption;
+ bool isSatisfied;
+
+public:
+ TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
+ : Constraint(constraint), Assumption(assumption), isSatisfied(false) {}
+
+ void Profile(llvm::FoldingSetNodeID &ID) const;
+
+ PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR);
+};
+
+class NilReceiverBRVisitor : public BugReporterVisitor {
+public:
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ static int x = 0;
+ ID.AddPointer(&x);
+ }
+
+ PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR);
+};
+
+/// Visitor that tries to report interesting diagnostics from conditions.
+class ConditionBRVisitor : public BugReporterVisitor {
+public:
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ static int x = 0;
+ ID.AddPointer(&x);
+ }
+
+ virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+ const ExplodedNode *Prev,
+ BugReporterContext &BRC,
+ BugReport &BR);
+
+ PathDiagnosticPiece *VisitTerminator(const Stmt *Term,
+ const ExplodedNode *N,
+ const CFGBlock *srcBlk,
+ const CFGBlock *dstBlk,
+ BugReporterContext &BRC);
+
+ PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
+ bool tookTrue,
+ BugReporterContext &BRC,
+ const LocationContext *LC);
+
+ PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
+ const DeclRefExpr *DR,
+ const bool tookTrue,
+ BugReporterContext &BRC,
+ const LocationContext *LC);
+
+ PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
+ const BinaryOperator *BExpr,
+ const bool tookTrue,
+ BugReporterContext &BRC,
+ const LocationContext *LC);
+
+ bool patternMatch(const Expr *Ex,
+ llvm::raw_ostream &Out,
+ BugReporterContext &BRC);
+};
+
+namespace bugreporter {
+
+BugReporterVisitor *getTrackNullOrUndefValueVisitor(const ExplodedNode *N,
+ const Stmt *S);
+
+const Stmt *GetDerefExpr(const ExplodedNode *N);
+const Stmt *GetDenomExpr(const ExplodedNode *N);
+const Stmt *GetCalleeExpr(const ExplodedNode *N);
+const Stmt *GetRetValExpr(const ExplodedNode *N);
+
+} // end namespace clang
+} // end namespace ento
+} // end namespace bugreporter
+
+
+#endif //LLVM_CLANG_GR__BUGREPORTERVISITOR
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
index 7b9bb03d8d05..78067cd61c1e 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
@@ -14,7 +14,6 @@
#ifndef LLVM_CLANG_ANALYSIS_BUGTYPE
#define LLVM_CLANG_ANALYSIS_BUGTYPE
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "llvm/ADT/FoldingSet.h"
#include <string>
@@ -22,6 +21,7 @@ namespace clang {
namespace ento {
+class BugReporter;
class ExplodedNode;
class ExprEngine;
@@ -31,13 +31,13 @@ private:
const std::string Category;
bool SuppressonSink;
public:
- BugType(llvm::StringRef name, llvm::StringRef cat)
+ BugType(StringRef name, StringRef cat)
: Name(name), Category(cat), SuppressonSink(false) {}
virtual ~BugType();
// FIXME: Should these be made strings as well?
- llvm::StringRef getName() const { return Name; }
- llvm::StringRef getCategory() const { return Category; }
+ StringRef getName() const { return Name; }
+ StringRef getCategory() const { return Category; }
/// isSuppressOnSink - Returns true if bug reports associated with this bug
/// type should be suppressed if the end node of the report is post-dominated
@@ -57,7 +57,7 @@ public:
BuiltinBug(const char *name)
: BugType(name, "Logic error"), desc(name) {}
- llvm::StringRef getDescription() const { return desc; }
+ StringRef getDescription() const { return desc; }
};
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
index 6d53c097d29f..406be3cc4bd4 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
@@ -16,6 +16,7 @@
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/PointerUnion.h"
#include <deque>
#include <iterator>
#include <string>
@@ -23,42 +24,55 @@
namespace clang {
+class AnalysisContext;
+class BinaryOperator;
+class CompoundStmt;
class Decl;
+class LocationContext;
+class MemberExpr;
+class ParentMap;
+class ProgramPoint;
class SourceManager;
class Stmt;
namespace ento {
+class ExplodedNode;
+
//===----------------------------------------------------------------------===//
// High-level interface for handlers of path-sensitive diagnostics.
//===----------------------------------------------------------------------===//
class PathDiagnostic;
-class PathDiagnosticClient : public DiagnosticClient {
+class PathDiagnosticConsumer {
public:
- PathDiagnosticClient() {}
+ PathDiagnosticConsumer() {}
- virtual ~PathDiagnosticClient() {}
+ virtual ~PathDiagnosticConsumer() {}
virtual void
- FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade = 0) = 0;
+ FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade = 0) = 0;
- void FlushDiagnostics(llvm::SmallVectorImpl<std::string> &FilesMade) {
+ void FlushDiagnostics(SmallVectorImpl<std::string> &FilesMade) {
FlushDiagnostics(&FilesMade);
}
- virtual llvm::StringRef getName() const = 0;
+ virtual StringRef getName() const = 0;
- virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
- const DiagnosticInfo &Info);
- virtual void HandlePathDiagnostic(const PathDiagnostic* D) = 0;
+ void HandlePathDiagnostic(const PathDiagnostic* D);
enum PathGenerationScheme { Minimal, Extensive };
virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
virtual bool supportsLogicalOpControlFlow() const { return false; }
virtual bool supportsAllBlockEdges() const { return false; }
virtual bool useVerboseDescription() const { return true; }
+
+protected:
+ /// The actual logic for handling path diagnostics, as implemented
+ /// by subclasses of PathDiagnosticConsumer.
+ virtual void HandlePathDiagnosticImpl(const PathDiagnostic* D) = 0;
+
};
//===----------------------------------------------------------------------===//
@@ -67,60 +81,143 @@ public:
class PathDiagnosticRange : public SourceRange {
public:
- const bool isPoint;
+ bool isPoint;
PathDiagnosticRange(const SourceRange &R, bool isP = false)
: SourceRange(R), isPoint(isP) {}
+
+ PathDiagnosticRange() : isPoint(false) {}
};
+typedef llvm::PointerUnion<const LocationContext*, AnalysisContext*>
+ LocationOrAnalysisContext;
+
class PathDiagnosticLocation {
private:
enum Kind { RangeK, SingleLocK, StmtK, DeclK } K;
- SourceRange R;
const Stmt *S;
const Decl *D;
const SourceManager *SM;
+ FullSourceLoc Loc;
+ PathDiagnosticRange Range;
+
+ PathDiagnosticLocation(SourceLocation L, const SourceManager &sm,
+ Kind kind)
+ : K(kind), S(0), D(0), SM(&sm),
+ Loc(genLocation(L)), Range(genRange()) {
+ assert(Loc.isValid());
+ assert(Range.isValid());
+ }
+
+ FullSourceLoc
+ genLocation(SourceLocation L = SourceLocation(),
+ LocationOrAnalysisContext LAC = (AnalysisContext*)0) const;
+
+ PathDiagnosticRange
+ genRange(LocationOrAnalysisContext LAC = (AnalysisContext*)0) const;
+
public:
+ /// Create an invalid location.
PathDiagnosticLocation()
: K(SingleLocK), S(0), D(0), SM(0) {}
- PathDiagnosticLocation(FullSourceLoc L)
- : K(SingleLocK), R(L, L), S(0), D(0), SM(&L.getManager()) {}
+ /// Create a location corresponding to the given statement.
+ PathDiagnosticLocation(const Stmt *s,
+ const SourceManager &sm,
+ LocationOrAnalysisContext lac)
+ : K(StmtK), S(s), D(0), SM(&sm),
+ Loc(genLocation(SourceLocation(), lac)),
+ Range(genRange(lac)) {
+ assert(Loc.isValid());
+ assert(Range.isValid());
+ }
- PathDiagnosticLocation(const Stmt *s, const SourceManager &sm)
- : K(StmtK), S(s), D(0), SM(&sm) {}
+ /// Create a location corresponding to the given declaration.
+ PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
+ : K(DeclK), S(0), D(d), SM(&sm),
+ Loc(genLocation()), Range(genRange()) {
+ assert(Loc.isValid());
+ assert(Range.isValid());
+ }
- PathDiagnosticLocation(SourceRange r, const SourceManager &sm)
- : K(RangeK), R(r), S(0), D(0), SM(&sm) {}
+ /// Create a location corresponding to the given declaration.
+ static PathDiagnosticLocation create(const Decl *D,
+ const SourceManager &SM) {
+ return PathDiagnosticLocation(D, SM);
+ }
- PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
- : K(DeclK), S(0), D(d), SM(&sm) {}
+ /// Create a location for the beginning of the declaration.
+ static PathDiagnosticLocation createBegin(const Decl *D,
+ const SourceManager &SM);
+
+ /// Create a location for the beginning of the statement.
+ static PathDiagnosticLocation createBegin(const Stmt *S,
+ const SourceManager &SM,
+ const LocationOrAnalysisContext LAC);
+
+ /// Create the location for the operator of the binary expression.
+ /// Assumes the statement has a valid location.
+ static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO,
+ const SourceManager &SM);
+
+ /// For member expressions, return the location of the '.' or '->'.
+ /// Assumes the statement has a valid location.
+ static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME,
+ const SourceManager &SM);
+
+ /// Create a location for the beginning of the compound statement.
+ /// Assumes the statement has a valid location.
+ static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS,
+ const SourceManager &SM);
+
+ /// Create a location for the end of the compound statement.
+ /// Assumes the statement has a valid location.
+ static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS,
+ const SourceManager &SM);
+
+ /// Create a location for the beginning of the enclosing declaration body.
+ /// Defaults to the beginning of the first statement in the declaration body.
+ static PathDiagnosticLocation createDeclBegin(const LocationContext *LC,
+ const SourceManager &SM);
+
+ /// Constructs a location for the end of the enclosing declaration body.
+ /// Defaults to the end of brace.
+ static PathDiagnosticLocation createDeclEnd(const LocationContext *LC,
+ const SourceManager &SM);
+
+ /// Create a location corresponding to the given valid ExplodedNode.
+ static PathDiagnosticLocation create(const ProgramPoint& P,
+ const SourceManager &SMng);
+
+ /// Create a location corresponding to the next valid ExplodedNode as end
+ /// of path location.
+ static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N,
+ const SourceManager &SM);
+
+ /// Convert the given location into a single kind location.
+ static PathDiagnosticLocation createSingleLocation(
+ const PathDiagnosticLocation &PDL);
bool operator==(const PathDiagnosticLocation &X) const {
- return K == X.K && R == X.R && S == X.S && D == X.D;
+ return K == X.K && Loc == X.Loc && Range == X.Range;
}
bool operator!=(const PathDiagnosticLocation &X) const {
- return K != X.K || R != X.R || S != X.S || D != X.D;;
- }
-
- PathDiagnosticLocation& operator=(const PathDiagnosticLocation &X) {
- K = X.K;
- R = X.R;
- S = X.S;
- D = X.D;
- SM = X.SM;
- return *this;
+ return !(*this == X);
}
bool isValid() const {
return SM != 0;
}
- const SourceManager& getSourceManager() const { assert(isValid());return *SM;}
+ FullSourceLoc asLocation() const {
+ return Loc;
+ }
+
+ PathDiagnosticRange asRange() const {
+ return Range;
+ }
- FullSourceLoc asLocation() const;
- PathDiagnosticRange asRange() const;
const Stmt *asStmt() const { assert(isValid()); return S; }
const Decl *asDecl() const { assert(isValid()); return D; }
@@ -181,7 +278,7 @@ private:
PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P);
protected:
- PathDiagnosticPiece(llvm::StringRef s, Kind k, DisplayHint hint = Below);
+ PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
@@ -191,7 +288,7 @@ public:
const std::string& getString() const { return str; }
/// getDisplayHint - Return a hint indicating where the diagnostic should
- /// be displayed by the PathDiagnosticClient.
+ /// be displayed by the PathDiagnosticConsumer.
DisplayHint getDisplayHint() const { return Hint; }
virtual PathDiagnosticLocation getLocation() const = 0;
@@ -199,9 +296,15 @@ public:
Kind getKind() const { return kind; }
- void addRange(SourceRange R) { ranges.push_back(R); }
+ void addRange(SourceRange R) {
+ if (!R.isValid())
+ return;
+ ranges.push_back(R);
+ }
void addRange(SourceLocation B, SourceLocation E) {
+ if (!B.isValid() || !E.isValid())
+ return;
ranges.push_back(SourceRange(B,E));
}
@@ -230,7 +333,7 @@ public:
: &FixItHints[0] + FixItHints.size();
}
- static inline bool classof(const PathDiagnosticPiece* P) {
+ static inline bool classof(const PathDiagnosticPiece *P) {
return true;
}
@@ -242,11 +345,11 @@ private:
PathDiagnosticLocation Pos;
public:
PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
- llvm::StringRef s,
+ StringRef s,
PathDiagnosticPiece::Kind k,
bool addPosRange = true)
: PathDiagnosticPiece(s, k), Pos(pos) {
- assert(Pos.asLocation().isValid() &&
+ assert(Pos.isValid() && Pos.asLocation().isValid() &&
"PathDiagnosticSpotPiece's must have a valid location.");
if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
}
@@ -261,12 +364,12 @@ class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
public:
PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
- llvm::StringRef s, bool addPosRange = true)
+ StringRef s, bool addPosRange = true)
: PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
~PathDiagnosticEventPiece();
- static inline bool classof(const PathDiagnosticPiece* P) {
+ static inline bool classof(const PathDiagnosticPiece *P) {
return P->getKind() == Event;
}
};
@@ -276,7 +379,7 @@ class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
public:
PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
const PathDiagnosticLocation &endPos,
- llvm::StringRef s)
+ StringRef s)
: PathDiagnosticPiece(s, ControlFlow) {
LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
}
@@ -320,7 +423,7 @@ public:
const_iterator begin() const { return LPairs.begin(); }
const_iterator end() const { return LPairs.end(); }
- static inline bool classof(const PathDiagnosticPiece* P) {
+ static inline bool classof(const PathDiagnosticPiece *P) {
return P->getKind() == ControlFlow;
}
@@ -337,7 +440,7 @@ public:
bool containsEvent() const;
- void push_back(PathDiagnosticPiece* P) { SubPieces.push_back(P); }
+ void push_back(PathDiagnosticPiece *P) { SubPieces.push_back(P); }
typedef std::vector<PathDiagnosticPiece*>::iterator iterator;
iterator begin() { return SubPieces.begin(); }
@@ -352,7 +455,7 @@ public:
const_iterator begin() const { return SubPieces.begin(); }
const_iterator end() const { return SubPieces.end(); }
- static inline bool classof(const PathDiagnosticPiece* P) {
+ static inline bool classof(const PathDiagnosticPiece *P) {
return P->getKind() == Macro;
}
@@ -373,42 +476,42 @@ class PathDiagnostic : public llvm::FoldingSetNode {
public:
PathDiagnostic();
- PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc,
- llvm::StringRef category);
+ PathDiagnostic(StringRef bugtype, StringRef desc,
+ StringRef category);
~PathDiagnostic();
- llvm::StringRef getDescription() const { return Desc; }
- llvm::StringRef getBugType() const { return BugType; }
- llvm::StringRef getCategory() const { return Category; }
+ StringRef getDescription() const { return Desc; }
+ StringRef getBugType() const { return BugType; }
+ StringRef getCategory() const { return Category; }
typedef std::deque<std::string>::const_iterator meta_iterator;
meta_iterator meta_begin() const { return OtherDesc.begin(); }
meta_iterator meta_end() const { return OtherDesc.end(); }
- void addMeta(llvm::StringRef s) { OtherDesc.push_back(s); }
+ void addMeta(StringRef s) { OtherDesc.push_back(s); }
PathDiagnosticLocation getLocation() const {
assert(Size > 0 && "getLocation() requires a non-empty PathDiagnostic.");
return rbegin()->getLocation();
}
- void push_front(PathDiagnosticPiece* piece) {
+ void push_front(PathDiagnosticPiece *piece) {
assert(piece);
path.push_front(piece);
++Size;
}
- void push_back(PathDiagnosticPiece* piece) {
+ void push_back(PathDiagnosticPiece *piece) {
assert(piece);
path.push_back(piece);
++Size;
}
- PathDiagnosticPiece* back() {
+ PathDiagnosticPiece *back() {
return path.back();
}
- const PathDiagnosticPiece* back() const {
+ const PathDiagnosticPiece *back() const {
return path.back();
}
@@ -433,14 +536,14 @@ public:
public:
iterator(const ImplTy& i) : I(i) {}
- bool operator==(const iterator& X) const { return I == X.I; }
- bool operator!=(const iterator& X) const { return I != X.I; }
+ bool operator==(const iterator &X) const { return I == X.I; }
+ bool operator!=(const iterator &X) const { return I != X.I; }
PathDiagnosticPiece& operator*() const { return **I; }
- PathDiagnosticPiece* operator->() const { return *I; }
+ PathDiagnosticPiece *operator->() const { return *I; }
- iterator& operator++() { ++I; return *this; }
- iterator& operator--() { --I; return *this; }
+ iterator &operator++() { ++I; return *this; }
+ iterator &operator--() { --I; return *this; }
};
class const_iterator {
@@ -459,14 +562,14 @@ public:
public:
const_iterator(const ImplTy& i) : I(i) {}
- bool operator==(const const_iterator& X) const { return I == X.I; }
- bool operator!=(const const_iterator& X) const { return I != X.I; }
+ bool operator==(const const_iterator &X) const { return I == X.I; }
+ bool operator!=(const const_iterator &X) const { return I != X.I; }
reference operator*() const { return **I; }
pointer operator->() const { return *I; }
- const_iterator& operator++() { ++I; return *this; }
- const_iterator& operator--() { --I; return *this; }
+ const_iterator &operator++() { ++I; return *this; }
+ const_iterator &operator--() { --I; return *this; }
};
typedef std::reverse_iterator<iterator> reverse_iterator;
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h
index eb38bd8951e9..1e4edeb0c7ae 100644
--- a/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_SA_CORE_CHECKER
#define LLVM_CLANG_SA_CORE_CHECKER
+#include "clang/Analysis/ProgramPoint.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/Support/Casting.h"
@@ -151,9 +152,10 @@ public:
class Location {
template <typename CHECKER>
- static void _checkLocation(void *checker, const SVal &location, bool isLoad,
+ static void _checkLocation(void *checker,
+ const SVal &location, bool isLoad, const Stmt *S,
CheckerContext &C) {
- ((const CHECKER *)checker)->checkLocation(location, isLoad, C);
+ ((const CHECKER *)checker)->checkLocation(location, isLoad, S, C);
}
public:
@@ -166,9 +168,10 @@ public:
class Bind {
template <typename CHECKER>
- static void _checkBind(void *checker, const SVal &location, const SVal &val,
+ static void _checkBind(void *checker,
+ const SVal &location, const SVal &val, const Stmt *S,
CheckerContext &C) {
- ((const CHECKER *)checker)->checkBind(location, val, C);
+ ((const CHECKER *)checker)->checkBind(location, val, S, C);
}
public:
@@ -227,7 +230,7 @@ public:
class LiveSymbols {
template <typename CHECKER>
- static void _checkLiveSymbols(void *checker, const GRState *state,
+ static void _checkLiveSymbols(void *checker, const ProgramState *state,
SymbolReaper &SR) {
((const CHECKER *)checker)->checkLiveSymbols(state, SR);
}
@@ -257,15 +260,18 @@ public:
class RegionChanges {
template <typename CHECKER>
- static const GRState *_checkRegionChanges(void *checker, const GRState *state,
- const StoreManager::InvalidatedSymbols *invalidated,
- const MemRegion * const *Begin,
- const MemRegion * const *End) {
+ static const ProgramState *
+ _checkRegionChanges(void *checker,
+ const ProgramState *state,
+ const StoreManager::InvalidatedSymbols *invalidated,
+ ArrayRef<const MemRegion *> Explicits,
+ ArrayRef<const MemRegion *> Regions) {
return ((const CHECKER *)checker)->checkRegionChanges(state, invalidated,
- Begin, End);
+ Explicits, Regions);
}
template <typename CHECKER>
- static bool _wantsRegionChangeUpdate(void *checker, const GRState *state) {
+ static bool _wantsRegionChangeUpdate(void *checker,
+ const ProgramState *state) {
return ((const CHECKER *)checker)->wantsRegionChangeUpdate(state);
}
@@ -300,8 +306,10 @@ namespace eval {
class Assume {
template <typename CHECKER>
- static const GRState *_evalAssume(void *checker, const GRState *state,
- const SVal &cond, bool assumption) {
+ static const ProgramState *_evalAssume(void *checker,
+ const ProgramState *state,
+ const SVal &cond,
+ bool assumption) {
return ((const CHECKER *)checker)->evalAssume(state, cond, assumption);
}
@@ -327,38 +335,73 @@ public:
}
};
+class InlineCall {
+ template <typename CHECKER>
+ static bool _inlineCall(void *checker, const CallExpr *CE,
+ ExprEngine &Eng,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ return ((const CHECKER *)checker)->inlineCall(CE, Eng, Pred, Dst);
+ }
+
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerForInlineCall(
+ CheckerManager::InlineCallFunc(checker, _inlineCall<CHECKER>));
+ }
+};
+
} // end eval namespace
+class CheckerBase : public ProgramPointTag {
+public:
+ StringRef getTagDescription() const;
+
+ /// See CheckerManager::runCheckersForPrintState.
+ virtual void printState(raw_ostream &Out, const ProgramState *State,
+ const char *NL, const char *Sep) const { }
+};
+
template <typename CHECK1, typename CHECK2=check::_VoidCheck,
typename CHECK3=check::_VoidCheck, typename CHECK4=check::_VoidCheck,
typename CHECK5=check::_VoidCheck, typename CHECK6=check::_VoidCheck,
typename CHECK7=check::_VoidCheck, typename CHECK8=check::_VoidCheck,
typename CHECK9=check::_VoidCheck, typename CHECK10=check::_VoidCheck,
- typename CHECK11=check::_VoidCheck,typename CHECK12=check::_VoidCheck>
+ typename CHECK11=check::_VoidCheck,typename CHECK12=check::_VoidCheck,
+ typename CHECK13=check::_VoidCheck,typename CHECK14=check::_VoidCheck,
+ typename CHECK15=check::_VoidCheck,typename CHECK16=check::_VoidCheck>
class Checker;
template <>
class Checker<check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
- check::_VoidCheck, check::_VoidCheck, check::_VoidCheck> {
+ check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
+ check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
+ check::_VoidCheck>
+ : public CheckerBase
+{
public:
static void _register(void *checker, CheckerManager &mgr) { }
};
template <typename CHECK1, typename CHECK2, typename CHECK3, typename CHECK4,
typename CHECK5, typename CHECK6, typename CHECK7, typename CHECK8,
- typename CHECK9, typename CHECK10,typename CHECK11,typename CHECK12>
+ typename CHECK9, typename CHECK10,typename CHECK11,typename CHECK12,
+ typename CHECK13,typename CHECK14,typename CHECK15,typename CHECK16>
class Checker
: public CHECK1,
public Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8,
- CHECK9, CHECK10, CHECK11, CHECK12> {
+ CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,CHECK14,CHECK15,
+ CHECK16> {
public:
template <typename CHECKER>
static void _register(CHECKER *checker, CheckerManager &mgr) {
CHECK1::_register(checker, mgr);
- Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8, CHECK9,
- CHECK10, CHECK11,CHECK12>::_register(checker, mgr);
+ Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8,
+ CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,CHECK14,CHECK15,
+ CHECK16>::_register(checker, mgr);
}
};
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index 45d38fba0495..e3e4c49f71e1 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -27,6 +27,7 @@ namespace clang {
class CallExpr;
namespace ento {
+ class CheckerBase;
class ExprEngine;
class AnalysisManager;
class BugReporter;
@@ -36,7 +37,7 @@ namespace ento {
class ExplodedNode;
class ExplodedNodeSet;
class ExplodedGraph;
- class GRState;
+ class ProgramState;
class EndOfFunctionNodeBuilder;
class BranchNodeBuilder;
class MemRegion;
@@ -55,8 +56,8 @@ class CheckerFn<RET(P1, P2, P3, P4)> {
typedef RET (*Func)(void *, P1, P2, P3, P4);
Func Fn;
public:
- void *Checker;
- CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+ CheckerBase *Checker;
+ CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { }
RET operator()(P1 p1, P2 p2, P3 p3, P4 p4) const {
return Fn(Checker, p1, p2, p3, p4);
}
@@ -67,8 +68,8 @@ class CheckerFn<RET(P1, P2, P3)> {
typedef RET (*Func)(void *, P1, P2, P3);
Func Fn;
public:
- void *Checker;
- CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+ CheckerBase *Checker;
+ CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { }
RET operator()(P1 p1, P2 p2, P3 p3) const { return Fn(Checker, p1, p2, p3); }
};
@@ -77,8 +78,8 @@ class CheckerFn<RET(P1, P2)> {
typedef RET (*Func)(void *, P1, P2);
Func Fn;
public:
- void *Checker;
- CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+ CheckerBase *Checker;
+ CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { }
RET operator()(P1 p1, P2 p2) const { return Fn(Checker, p1, p2); }
};
@@ -87,8 +88,8 @@ class CheckerFn<RET(P1)> {
typedef RET (*Func)(void *, P1);
Func Fn;
public:
- void *Checker;
- CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+ CheckerBase *Checker;
+ CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { }
RET operator()(P1 p1) const { return Fn(Checker, p1); }
};
@@ -97,8 +98,8 @@ class CheckerFn<RET()> {
typedef RET (*Func)(void *);
Func Fn;
public:
- void *Checker;
- CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+ CheckerBase *Checker;
+ CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { }
RET operator()() const { return Fn(Checker); }
};
@@ -115,8 +116,8 @@ public:
const LangOptions &getLangOptions() const { return LangOpts; }
- typedef void *CheckerRef;
- typedef void *CheckerTag;
+ typedef CheckerBase *CheckerRef;
+ typedef const void *CheckerTag;
typedef CheckerFn<void ()> CheckerDtor;
//===----------------------------------------------------------------------===//
@@ -157,6 +158,11 @@ public:
//===----------------------------------------------------------------------===//
/// \brief Run checkers for pre-visiting Stmts.
+ ///
+ /// The notification is performed for every explored CFGElement, which does
+ /// not include the control flow statements such as IfStmt.
+ ///
+ /// \sa runCheckersForBranchCondition, runCheckersForPostStmt
void runCheckersForPreStmt(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const Stmt *S,
@@ -165,6 +171,11 @@ public:
}
/// \brief Run checkers for post-visiting Stmts.
+ ///
+ /// The notification is performed for every explored CFGElement, which does
+ /// not include the control flow statements such as IfStmt.
+ ///
+ /// \sa runCheckersForBranchCondition, runCheckersForPreStmt
void runCheckersForPostStmt(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const Stmt *S,
@@ -224,27 +235,43 @@ public:
BranchNodeBuilder &B, ExprEngine &Eng);
/// \brief Run checkers for live symbols.
- void runCheckersForLiveSymbols(const GRState *state,
+ ///
+ /// Allows modifying SymbolReaper object. For example, checkers can explicitly
+ /// register symbols of interest as live. These symbols will not be marked
+ /// dead and removed.
+ void runCheckersForLiveSymbols(const ProgramState *state,
SymbolReaper &SymReaper);
/// \brief Run checkers for dead symbols.
+ ///
+ /// Notifies checkers when symbols become dead. For example, this allows
+ /// checkers to aggressively clean up/reduce the checker state and produce
+ /// precise diagnostics.
void runCheckersForDeadSymbols(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
SymbolReaper &SymReaper, const Stmt *S,
ExprEngine &Eng);
/// \brief True if at least one checker wants to check region changes.
- bool wantsRegionChangeUpdate(const GRState *state);
+ bool wantsRegionChangeUpdate(const ProgramState *state);
/// \brief Run checkers for region changes.
- const GRState *
- runCheckersForRegionChanges(const GRState *state,
+ ///
+ /// This corresponds to the check::RegionChanges callback.
+ /// \param state The current program state.
+ /// \param invalidated A set of all symbols potentially touched by the change.
+ /// \param ExplicitRegions The regions explicitly requested for invalidation.
+ /// For example, in the case of a function call, these would be arguments.
+ /// \param Regions The transitive closure of accessible regions,
+ /// i.e. all regions that may have been touched by this change.
+ const ProgramState *
+ runCheckersForRegionChanges(const ProgramState *state,
const StoreManager::InvalidatedSymbols *invalidated,
- const MemRegion * const *Begin,
- const MemRegion * const *End);
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions);
/// \brief Run checkers for handling assumptions on symbolic values.
- const GRState *runCheckersForEvalAssume(const GRState *state,
+ const ProgramState *runCheckersForEvalAssume(const ProgramState *state,
SVal Cond, bool Assumption);
/// \brief Run checkers for evaluating a call.
@@ -254,10 +281,21 @@ public:
GraphExpander *defaultEval = 0);
/// \brief Run checkers for the entire Translation Unit.
- void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl* TU,
+ void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl *TU,
AnalysisManager &mgr,
BugReporter &BR);
+ /// \brief Run checkers for debug-printing a ProgramState.
+ ///
+ /// Unlike most other callbacks, any checker can simply implement the virtual
+ /// method CheckerBase::printState if it has custom data to print.
+ /// \param Out The output stream
+ /// \param State The state being printed
+ /// \param NL The preferred representation of a newline.
+ /// \param Sep The preferred separator between different kinds of data.
+ void runCheckersForPrintState(raw_ostream &Out, const ProgramState *State,
+ const char *NL, const char *Sep);
+
//===----------------------------------------------------------------------===//
// Internal registration functions for AST traversing.
//===----------------------------------------------------------------------===//
@@ -282,11 +320,13 @@ public:
typedef CheckerFn<void (const ObjCMessage &, CheckerContext &)>
CheckObjCMessageFunc;
- typedef CheckerFn<void (const SVal &location, bool isLoad, CheckerContext &)>
+ typedef CheckerFn<void (const SVal &location, bool isLoad, const Stmt *S,
+ CheckerContext &)>
CheckLocationFunc;
- typedef CheckerFn<void (const SVal &location, const SVal &val,
- CheckerContext &)> CheckBindFunc;
+ typedef CheckerFn<void (const SVal &location, const SVal &val,
+ const Stmt *S, CheckerContext &)>
+ CheckBindFunc;
typedef CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)>
CheckEndAnalysisFunc;
@@ -300,23 +340,28 @@ public:
typedef CheckerFn<void (SymbolReaper &, CheckerContext &)>
CheckDeadSymbolsFunc;
- typedef CheckerFn<void (const GRState *,SymbolReaper &)> CheckLiveSymbolsFunc;
+ typedef CheckerFn<void (const ProgramState *,SymbolReaper &)> CheckLiveSymbolsFunc;
- typedef CheckerFn<const GRState * (const GRState *,
+ typedef CheckerFn<const ProgramState * (const ProgramState *,
const StoreManager::InvalidatedSymbols *symbols,
- const MemRegion * const *begin,
- const MemRegion * const *end)>
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions)>
CheckRegionChangesFunc;
- typedef CheckerFn<bool (const GRState *)> WantsRegionChangeUpdateFunc;
+ typedef CheckerFn<bool (const ProgramState *)> WantsRegionChangeUpdateFunc;
- typedef CheckerFn<const GRState * (const GRState *,
- const SVal &cond, bool assumption)>
+ typedef CheckerFn<const ProgramState * (const ProgramState *,
+ const SVal &cond, bool assumption)>
EvalAssumeFunc;
typedef CheckerFn<bool (const CallExpr *, CheckerContext &)>
EvalCallFunc;
+ typedef CheckerFn<bool (const CallExpr *, ExprEngine &Eng,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst)>
+ InlineCallFunc;
+
typedef CheckerFn<void (const TranslationUnitDecl *,
AnalysisManager&, BugReporter &)>
CheckEndOfTranslationUnit;
@@ -351,6 +396,8 @@ public:
void _registerForEvalCall(EvalCallFunc checkfn);
+ void _registerForInlineCall(InlineCallFunc checkfn);
+
void _registerForEndOfTranslationUnit(CheckEndOfTranslationUnit checkfn);
//===----------------------------------------------------------------------===//
@@ -405,7 +452,7 @@ private:
std::vector<CheckDeclFunc> BodyCheckers;
- typedef llvm::SmallVector<CheckDeclFunc, 4> CachedDeclCheckers;
+ typedef SmallVector<CheckDeclFunc, 4> CachedDeclCheckers;
typedef llvm::DenseMap<unsigned, CachedDeclCheckers> CachedDeclCheckersMapTy;
CachedDeclCheckersMapTy CachedDeclCheckersMap;
@@ -439,7 +486,7 @@ private:
};
friend struct llvm::DenseMapInfo<CachedStmtCheckersKey>;
- typedef llvm::SmallVector<CheckStmtFunc, 4> CachedStmtCheckers;
+ typedef SmallVector<CheckStmtFunc, 4> CachedStmtCheckers;
typedef llvm::DenseMap<CachedStmtCheckersKey, CachedStmtCheckers>
CachedStmtCheckersMapTy;
CachedStmtCheckersMapTy CachedStmtCheckersMap;
@@ -473,10 +520,12 @@ private:
std::vector<EvalCallFunc> EvalCallCheckers;
+ std::vector<InlineCallFunc> InlineCallCheckers;
+
std::vector<CheckEndOfTranslationUnit> EndOfTranslationUnitCheckers;
struct EventInfo {
- llvm::SmallVector<CheckEventFunc, 4> Checkers;
+ SmallVector<CheckEventFunc, 4> Checkers;
bool HasDispatcher;
EventInfo() : HasDispatcher(false) { }
};
diff --git a/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h b/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h
new file mode 100644
index 000000000000..6ce5b3c5095e
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h
@@ -0,0 +1,43 @@
+//===--- CheckerOptInfo.h - Specifies which checkers to use -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H
+#define LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H
+
+#include "clang/Basic/LLVM.h"
+
+namespace clang {
+namespace ento {
+
+/// Represents a request to include or exclude a checker or package from a
+/// specific analysis run.
+///
+/// \sa CheckerRegistry::initializeManager
+class CheckerOptInfo {
+ StringRef Name;
+ bool Enable;
+ bool Claimed;
+
+public:
+ CheckerOptInfo(StringRef name, bool enable)
+ : Name(name), Enable(enable), Claimed(false) { }
+
+ StringRef getName() const { return Name; }
+ bool isEnabled() const { return Enable; }
+ bool isDisabled() const { return !isEnabled(); }
+
+ bool isClaimed() const { return Claimed; }
+ bool isUnclaimed() const { return !isClaimed(); }
+ void claim() { Claimed = true; }
+};
+
+} // end namespace ento
+} // end namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/CheckerProvider.h b/include/clang/StaticAnalyzer/Core/CheckerProvider.h
deleted file mode 100644
index b8aaaa1a04c0..000000000000
--- a/include/clang/StaticAnalyzer/Core/CheckerProvider.h
+++ /dev/null
@@ -1,58 +0,0 @@
-//===--- CheckerProvider.h - Static Analyzer Checkers Provider --*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Defines the Static Analyzer Checker Provider.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_SA_CORE_CHECKERPROVIDER_H
-#define LLVM_CLANG_SA_CORE_CHECKERPROVIDER_H
-
-#include "llvm/ADT/StringRef.h"
-
-namespace llvm {
- class raw_ostream;
-}
-
-namespace clang {
-
-namespace ento {
- class CheckerManager;
-
-class CheckerOptInfo {
- const char *Name;
- bool Enable;
- bool Claimed;
-
-public:
- CheckerOptInfo(const char *name, bool enable)
- : Name(name), Enable(enable), Claimed(false) { }
-
- const char *getName() const { return Name; }
- bool isEnabled() const { return Enable; }
- bool isDisabled() const { return !isEnabled(); }
-
- bool isClaimed() const { return Claimed; }
- bool isUnclaimed() const { return !isClaimed(); }
- void claim() { Claimed = true; }
-};
-
-class CheckerProvider {
-public:
- virtual ~CheckerProvider();
- virtual void registerCheckers(CheckerManager &checkerMgr,
- CheckerOptInfo *checkOpts, unsigned numCheckOpts) = 0;
- virtual void printHelp(llvm::raw_ostream &OS) = 0;
-};
-
-} // end ento namespace
-
-} // end clang namespace
-
-#endif
diff --git a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
new file mode 100644
index 000000000000..b59c14d32f91
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
@@ -0,0 +1,132 @@
+//===--- CheckerRegistry.h - Maintains all available checkers ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H
+#define LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H
+
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/Basic/LLVM.h"
+#include <vector>
+
+// FIXME: move this information to an HTML file in docs/.
+// At the very least, a checker plugin is a dynamic library that exports
+// clang_analyzerAPIVersionString. This should be defined as follows:
+//
+// extern "C"
+// const char clang_analyzerAPIVersionString[] =
+// CLANG_ANALYZER_API_VERSION_STRING;
+//
+// This is used to check whether the current version of the analyzer is known to
+// be incompatible with a plugin. Plugins with incompatible version strings,
+// or without a version string at all, will not be loaded.
+//
+// To add a custom checker to the analyzer, the plugin must also define the
+// function clang_registerCheckers. For example:
+//
+// extern "C"
+// void clang_registerCheckers (CheckerRegistry &registry) {
+// registry.addChecker<MainCallChecker>("example.MainCallChecker",
+// "Disallows calls to functions called main");
+// }
+//
+// The first method argument is the full name of the checker, including its
+// enclosing package. By convention, the registered name of a checker is the
+// name of the associated class (the template argument).
+// The second method argument is a short human-readable description of the
+// checker.
+//
+// The clang_registerCheckers function may add any number of checkers to the
+// registry. If any checkers require additional initialization, use the three-
+// argument form of CheckerRegistry::addChecker.
+//
+// To load a checker plugin, specify the full path to the dynamic library as
+// the argument to the -load option in the cc1 frontend. You can then enable
+// your custom checker using the -analyzer-checker:
+//
+// clang -cc1 -load </path/to/plugin.dylib> -analyze
+// -analyzer-checker=<example.MainCallChecker>
+//
+// For a complete working example, see examples/analyzer-plugin.
+
+
+namespace clang {
+namespace ento {
+
+#ifndef CLANG_ANALYZER_API_VERSION_STRING
+// FIXME: The Clang version string is not particularly granular;
+// the analyzer infrastructure can change a lot between releases.
+// Unfortunately, this string has to be statically embedded in each plugin,
+// so we can't just use the functions defined in Version.h.
+#include "clang/Basic/Version.h"
+#define CLANG_ANALYZER_API_VERSION_STRING CLANG_VERSION_STRING
+#endif
+
+class CheckerOptInfo;
+
+/// Manages a set of available checkers for running a static analysis.
+/// The checkers are organized into packages by full name, where including
+/// a package will recursively include all subpackages and checkers within it.
+/// For example, the checker "core.builtin.NoReturnFunctionChecker" will be
+/// included if initializeManager() is called with an option of "core",
+/// "core.builtin", or the full name "core.builtin.NoReturnFunctionChecker".
+class CheckerRegistry {
+public:
+ /// Initialization functions perform any necessary setup for a checker.
+ /// They should include a call to CheckerManager::registerChecker.
+ typedef void (*InitializationFunction)(CheckerManager &);
+ struct CheckerInfo {
+ InitializationFunction Initialize;
+ StringRef FullName;
+ StringRef Desc;
+
+ CheckerInfo(InitializationFunction fn, StringRef name, StringRef desc)
+ : Initialize(fn), FullName(name), Desc(desc) {}
+ };
+
+ typedef std::vector<CheckerInfo> CheckerInfoList;
+
+private:
+ template <typename T>
+ static void initializeManager(CheckerManager &mgr) {
+ mgr.registerChecker<T>();
+ }
+
+public:
+ /// Adds a checker to the registry. Use this non-templated overload when your
+ /// checker requires custom initialization.
+ void addChecker(InitializationFunction fn, StringRef fullName,
+ StringRef desc);
+
+ /// Adds a checker to the registry. Use this templated overload when your
+ /// checker does not require any custom initialization.
+ template <class T>
+ void addChecker(StringRef fullName, StringRef desc) {
+ addChecker(&initializeManager<T>, fullName, desc);
+ }
+
+ /// Initializes a CheckerManager by calling the initialization functions for
+ /// all checkers specified by the given CheckerOptInfo list. The order of this
+ /// list is significant; later options can be used to reverse earlier ones.
+ /// This can be used to exclude certain checkers in an included package.
+ void initializeManager(CheckerManager &mgr,
+ SmallVectorImpl<CheckerOptInfo> &opts) const;
+
+ /// Prints the name and description of all checkers in this registry.
+ /// This output is not intended to be machine-parseable.
+ void printHelp(raw_ostream &out, size_t maxNameChars = 30) const ;
+
+private:
+ mutable CheckerInfoList Checkers;
+ mutable llvm::StringMap<size_t> Packages;
+};
+
+} // end namespace ento
+} // end namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathDiagnosticClients.h b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
index d02228fa30dd..d1f5a7da5599 100644
--- a/include/clang/StaticAnalyzer/Core/PathDiagnosticClients.h
+++ b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
@@ -22,18 +22,18 @@ class Preprocessor;
namespace ento {
-class PathDiagnosticClient;
+class PathDiagnosticConsumer;
-PathDiagnosticClient*
-createHTMLDiagnosticClient(const std::string& prefix, const Preprocessor &PP);
+PathDiagnosticConsumer*
+createHTMLDiagnosticConsumer(const std::string& prefix, const Preprocessor &PP);
-PathDiagnosticClient*
-createPlistDiagnosticClient(const std::string& prefix, const Preprocessor &PP,
- PathDiagnosticClient *SubPD = 0);
+PathDiagnosticConsumer*
+createPlistDiagnosticConsumer(const std::string& prefix, const Preprocessor &PP,
+ PathDiagnosticConsumer *SubPD = 0);
-PathDiagnosticClient*
-createTextPathDiagnosticClient(const std::string& prefix,
- const Preprocessor &PP);
+PathDiagnosticConsumer*
+createTextPathDiagnosticConsumer(const std::string& prefix,
+ const Preprocessor &PP);
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
index 1ba038e6da2d..6c93f59d2094 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_GR_ANALYSISMANAGER_H
#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Frontend/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
@@ -34,10 +35,10 @@ class AnalysisManager : public BugReporterData {
LocationContextManager LocCtxMgr;
ASTContext &Ctx;
- Diagnostic &Diags;
+ DiagnosticsEngine &Diags;
const LangOptions &LangInfo;
- llvm::OwningPtr<PathDiagnosticClient> PD;
+ llvm::OwningPtr<PathDiagnosticConsumer> PD;
// Configurable components creators.
StoreManagerCreator CreateStoreMgr;
@@ -60,7 +61,7 @@ class AnalysisManager : public BugReporterData {
bool VisualizeEGDot;
bool VisualizeEGUbi;
- bool PurgeDead;
+ AnalysisPurgeMode PurgeDead;
/// EargerlyAssume - A flag indicating how the engine should handle
// expressions such as: 'x = (y != 0)'. When this flag is true then
@@ -75,27 +76,24 @@ class AnalysisManager : public BugReporterData {
bool EagerlyTrimEGraph;
public:
- AnalysisManager(ASTContext &ctx, Diagnostic &diags,
- const LangOptions &lang, PathDiagnosticClient *pd,
+ AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
+ const LangOptions &lang, PathDiagnosticConsumer *pd,
StoreManagerCreator storemgr,
ConstraintManagerCreator constraintmgr,
CheckerManager *checkerMgr,
idx::Indexer *idxer,
unsigned maxnodes, unsigned maxvisit,
- bool vizdot, bool vizubi, bool purge, bool eager, bool trim,
+ bool vizdot, bool vizubi, AnalysisPurgeMode purge,
+ bool eager, bool trim,
bool inlinecall, bool useUnoptimizedCFG,
bool addImplicitDtors, bool addInitializers,
- bool eagerlyTrimEGraph)
-
- : AnaCtxMgr(useUnoptimizedCFG, addImplicitDtors, addInitializers),
- Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd),
- CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),
- CheckerMgr(checkerMgr), Idxer(idxer),
- AScope(ScopeDecl), MaxNodes(maxnodes), MaxVisit(maxvisit),
- VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge),
- EagerlyAssume(eager), TrimGraph(trim), InlineCall(inlinecall),
- EagerlyTrimEGraph(eagerlyTrimEGraph) {}
-
+ bool eagerlyTrimEGraph);
+
+ /// Construct a clone of the given AnalysisManager with the given ASTContext
+ /// and DiagnosticsEngine.
+ AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
+ AnalysisManager &ParentAM);
+
~AnalysisManager() { FlushDiagnostics(); }
void ClearContexts() {
@@ -127,7 +125,7 @@ public:
return getASTContext().getSourceManager();
}
- virtual Diagnostic &getDiagnostic() {
+ virtual DiagnosticsEngine &getDiagnostic() {
return Diags;
}
@@ -135,7 +133,7 @@ public:
return LangInfo;
}
- virtual PathDiagnosticClient *getPathDiagnosticClient() {
+ virtual PathDiagnosticConsumer *getPathDiagnosticConsumer() {
return PD.get();
}
@@ -160,7 +158,7 @@ public:
bool shouldTrimGraph() const { return TrimGraph; }
- bool shouldPurgeDead() const { return PurgeDead; }
+ AnalysisPurgeMode getPurgeMode() const { return PurgeDead; }
bool shouldEagerlyAssume() const { return EagerlyAssume; }
@@ -174,8 +172,9 @@ public:
return AnaCtxMgr.getContext(D)->getCFG();
}
- LiveVariables *getLiveVariables(Decl const *D) {
- return AnaCtxMgr.getContext(D)->getLiveVariables();
+ template <typename T>
+ T *getAnalysis(Decl const *D) {
+ return AnaCtxMgr.getContext(D)->getAnalysis<T>();
}
ParentMap &getParentMap(Decl const *D) {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index 69495be400a3..42a15370a427 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -27,7 +27,7 @@ namespace clang {
namespace ento {
- class GRState;
+class ProgramState;
class CompoundValData : public llvm::FoldingSetNode {
QualType T;
@@ -49,17 +49,17 @@ public:
class LazyCompoundValData : public llvm::FoldingSetNode {
StoreRef store;
- const TypedRegion *region;
+ const TypedValueRegion *region;
public:
- LazyCompoundValData(const StoreRef &st, const TypedRegion *r)
+ LazyCompoundValData(const StoreRef &st, const TypedValueRegion *r)
: store(st), region(r) {}
const void *getStore() const { return store.getStore(); }
- const TypedRegion *getRegion() const { return region; }
+ const TypedValueRegion *getRegion() const { return region; }
static void Profile(llvm::FoldingSetNodeID& ID,
const StoreRef &store,
- const TypedRegion *region);
+ const TypedValueRegion *region);
void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, store, region); }
};
@@ -68,25 +68,25 @@ class BasicValueFactory {
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> >
APSIntSetTy;
- ASTContext& Ctx;
+ ASTContext &Ctx;
llvm::BumpPtrAllocator& BPAlloc;
APSIntSetTy APSIntSet;
- void* PersistentSVals;
- void* PersistentSValPairs;
+ void * PersistentSVals;
+ void * PersistentSValPairs;
llvm::ImmutableList<SVal>::Factory SValListFactory;
llvm::FoldingSet<CompoundValData> CompoundValDataSet;
llvm::FoldingSet<LazyCompoundValData> LazyCompoundValDataSet;
public:
- BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc)
+ BasicValueFactory(ASTContext &ctx, llvm::BumpPtrAllocator& Alloc)
: Ctx(ctx), BPAlloc(Alloc), PersistentSVals(0), PersistentSValPairs(0),
SValListFactory(Alloc) {}
~BasicValueFactory();
- ASTContext& getContext() const { return Ctx; }
+ ASTContext &getContext() const { return Ctx; }
const llvm::APSInt& getValue(const llvm::APSInt& X);
const llvm::APSInt& getValue(const llvm::APInt& X, bool isUnsigned);
@@ -176,7 +176,7 @@ public:
llvm::ImmutableList<SVal> Vals);
const LazyCompoundValData *getLazyCompoundValData(const StoreRef &store,
- const TypedRegion *region);
+ const TypedValueRegion *region);
llvm::ImmutableList<SVal> getEmptySValList() {
return SValListFactory.getEmptyList();
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h
index 7d0fdfb5f11f..2483a79455b2 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h
@@ -26,10 +26,13 @@ class StackFrameContext;
namespace ento {
+/// \class BlockCounter
+/// \brief An abstract data type used to count the number of times a given
+/// block has been visited along a path analyzed by CoreEngine.
class BlockCounter {
- void* Data;
+ void *Data;
- BlockCounter(void* D) : Data(D) {}
+ BlockCounter(void *D) : Data(D) {}
public:
BlockCounter() : Data(0) {}
@@ -38,7 +41,7 @@ public:
unsigned BlockID) const;
class Factory {
- void* F;
+ void *F;
public:
Factory(llvm::BumpPtrAllocator& Alloc);
~Factory();
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index 4429c6b2a7ad..1f1478713260 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -28,26 +28,29 @@ class CheckerContext {
ExprEngine &Eng;
ExplodedNode *Pred;
SaveAndRestore<bool> OldSink;
- const void *checkerTag;
- SaveAndRestore<ProgramPoint::Kind> OldPointKind;
SaveOr OldHasGen;
- const GRState *ST;
- const Stmt *statement;
+ const ProgramPoint Location;
+ const ProgramState *ST;
const unsigned size;
public:
bool *respondsToCallback;
public:
- CheckerContext(ExplodedNodeSet &dst, StmtNodeBuilder &builder,
- ExprEngine &eng, ExplodedNode *pred,
- const void *tag, ProgramPoint::Kind K,
+ CheckerContext(ExplodedNodeSet &dst,
+ StmtNodeBuilder &builder,
+ ExprEngine &eng,
+ ExplodedNode *pred,
+ const ProgramPoint &loc,
bool *respondsToCB = 0,
- const Stmt *stmt = 0, const GRState *st = 0)
- : Dst(dst), B(builder), Eng(eng), Pred(pred),
+ const ProgramState *st = 0)
+ : Dst(dst),
+ B(builder),
+ Eng(eng),
+ Pred(pred),
OldSink(B.BuildSinks),
- checkerTag(tag),
- OldPointKind(B.PointKind, K),
OldHasGen(B.hasGeneratedNode),
- ST(st), statement(stmt), size(Dst.size()),
+ Location(loc),
+ ST(st),
+ size(Dst.size()),
respondsToCallback(respondsToCB) {}
~CheckerContext();
@@ -69,10 +72,12 @@ public:
}
ExplodedNodeSet &getNodeSet() { return Dst; }
- StmtNodeBuilder &getNodeBuilder() { return B; }
ExplodedNode *&getPredecessor() { return Pred; }
- const GRState *getState() { return ST ? ST : B.GetState(Pred); }
- const Stmt *getStmt() const { return statement; }
+ const ProgramState *getState() { return ST ? ST : Pred->getState(); }
+
+ /// \brief Returns the number of times the current block has been visited
+ /// along the analyzed path.
+ unsigned getCurrentBlockCount() {return B.getCurrentBlockCount();}
ASTContext &getASTContext() {
return Eng.getContext();
@@ -90,64 +95,58 @@ public:
return Eng.getSValBuilder();
}
- ExplodedNode *generateNode(bool autoTransition = true) {
- assert(statement && "Only transitions with statements currently supported");
- ExplodedNode *N = generateNodeImpl(statement, getState(), false,
- checkerTag);
- if (N && autoTransition)
- Dst.Add(N);
- return N;
+ SymbolManager &getSymbolManager() {
+ return getSValBuilder().getSymbolManager();
}
-
- ExplodedNode *generateNode(const Stmt *stmt, const GRState *state,
- bool autoTransition = true, const void *tag = 0) {
- assert(state);
- ExplodedNode *N = generateNodeImpl(stmt, state, false,
- tag ? tag : checkerTag);
- if (N && autoTransition)
- addTransition(N);
- return N;
+
+ bool isObjCGCEnabled() {
+ return Eng.isObjCGCEnabled();
}
- ExplodedNode *generateNode(const GRState *state, ExplodedNode *pred,
+ /// \brief Generate a default checker node (containing checker tag but no
+ /// checker state changes).
+ ExplodedNode *generateNode(bool autoTransition = true) {
+ return generateNode(getState(), autoTransition);
+ }
+
+ /// \brief Generate a new checker node with the given predecessor.
+ /// Allows checkers to generate a chain of nodes.
+ ExplodedNode *generateNode(const ProgramState *state,
+ ExplodedNode *pred,
+ const ProgramPointTag *tag = 0,
bool autoTransition = true) {
- assert(statement && "Only transitions with statements currently supported");
- ExplodedNode *N = generateNodeImpl(statement, state, pred, false);
+ ExplodedNode *N = generateNodeImpl(state, false, pred, tag);
if (N && autoTransition)
addTransition(N);
return N;
}
- ExplodedNode *generateNode(const GRState *state, bool autoTransition = true,
- const void *tag = 0) {
- assert(statement && "Only transitions with statements currently supported");
- ExplodedNode *N = generateNodeImpl(statement, state, false,
- tag ? tag : checkerTag);
+ /// \brief Generate a new checker node.
+ ExplodedNode *generateNode(const ProgramState *state,
+ bool autoTransition = true,
+ const ProgramPointTag *tag = 0) {
+ ExplodedNode *N = generateNodeImpl(state, false, 0, tag);
if (N && autoTransition)
addTransition(N);
return N;
}
- ExplodedNode *generateSink(const Stmt *stmt, const GRState *state = 0) {
- return generateNodeImpl(stmt, state ? state : getState(), true,
- checkerTag);
- }
-
- ExplodedNode *generateSink(const GRState *state = 0) {
- assert(statement && "Only transitions with statements currently supported");
- return generateNodeImpl(statement, state ? state : getState(), true,
- checkerTag);
+ /// \brief Generate a sink node. Generating sink stops exploration of the
+ /// given path.
+ ExplodedNode *generateSink(const ProgramState *state = 0) {
+ return generateNodeImpl(state ? state : getState(), true);
}
void addTransition(ExplodedNode *node) {
Dst.Add(node);
}
- void addTransition(const GRState *state, const void *tag = 0) {
+ void addTransition(const ProgramState *state,
+ const ProgramPointTag *tag = 0) {
assert(state);
// If the 'state' is not new, we need to check if the cached state 'ST'
// is new.
- if (state != getState() || (ST && ST != B.GetState(Pred)))
+ if (state != getState() || (ST && ST != Pred->getState()))
// state is new or equals to ST.
generateNode(state, true, tag);
else
@@ -163,17 +162,14 @@ public:
}
private:
- ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state,
- bool markAsSink, const void *tag) {
- ExplodedNode *node = B.generateNode(stmt, state, Pred, tag);
- if (markAsSink && node)
- node->markAsSink();
- return node;
- }
-
- ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state,
- ExplodedNode *pred, bool markAsSink) {
- ExplodedNode *node = B.generateNode(stmt, state, pred, checkerTag);
+ ExplodedNode *generateNodeImpl(const ProgramState *state,
+ bool markAsSink,
+ ExplodedNode *pred = 0,
+ const ProgramPointTag *tag = 0) {
+
+ ExplodedNode *node = B.generateNode(tag ? Location.withTag(tag) : Location,
+ state,
+ pred ? pred : Pred);
if (markAsSink && node)
node->markAsSink();
return node;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
index 199b41afefae..3f6dddead8e9 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
-// FIXME: Typedef LiveSymbolsTy/DeadSymbolsTy at a more appropriate place.
-#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
namespace llvm {
class APSInt;
@@ -25,36 +25,40 @@ namespace clang {
namespace ento {
-class GRState;
-class GRStateManager;
+class ProgramState;
+class ProgramStateManager;
class SubEngine;
-class SVal;
class ConstraintManager {
public:
virtual ~ConstraintManager();
- virtual const GRState *assume(const GRState *state, DefinedSVal Cond,
- bool Assumption) = 0;
+ virtual const ProgramState *assume(const ProgramState *state,
+ DefinedSVal Cond,
+ bool Assumption) = 0;
- std::pair<const GRState*, const GRState*> assumeDual(const GRState *state,
- DefinedSVal Cond) {
+ std::pair<const ProgramState*, const ProgramState*>
+ assumeDual(const ProgramState *state, DefinedSVal Cond)
+ {
return std::make_pair(assume(state, Cond, true),
assume(state, Cond, false));
}
- virtual const llvm::APSInt* getSymVal(const GRState *state,
+ virtual const llvm::APSInt* getSymVal(const ProgramState *state,
SymbolRef sym) const = 0;
- virtual bool isEqual(const GRState *state, SymbolRef sym,
+ virtual bool isEqual(const ProgramState *state,
+ SymbolRef sym,
const llvm::APSInt& V) const = 0;
- virtual const GRState *removeDeadBindings(const GRState *state,
- SymbolReaper& SymReaper) = 0;
+ virtual const ProgramState *removeDeadBindings(const ProgramState *state,
+ SymbolReaper& SymReaper) = 0;
- virtual void print(const GRState *state, llvm::raw_ostream& Out,
- const char* nl, const char *sep) = 0;
+ virtual void print(const ProgramState *state,
+ raw_ostream &Out,
+ const char* nl,
+ const char *sep) = 0;
- virtual void EndPath(const GRState *state) {}
+ virtual void EndPath(const ProgramState *state) {}
/// canReasonAbout - Not all ConstraintManagers can accurately reason about
/// all SVal values. This method returns true if the ConstraintManager can
@@ -64,9 +68,9 @@ public:
virtual bool canReasonAbout(SVal X) const = 0;
};
-ConstraintManager* CreateBasicConstraintManager(GRStateManager& statemgr,
+ConstraintManager* CreateBasicConstraintManager(ProgramStateManager& statemgr,
SubEngine &subengine);
-ConstraintManager* CreateRangeConstraintManager(GRStateManager& statemgr,
+ConstraintManager* CreateRangeConstraintManager(ProgramStateManager& statemgr,
SubEngine &subengine);
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index 2c1d07c59b68..131d39e75528 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -19,11 +19,12 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
#include "llvm/ADT/OwningPtr.h"
namespace clang {
+class ProgramPointTag;
+
namespace ento {
//===----------------------------------------------------------------------===//
@@ -77,16 +78,17 @@ private:
/// usually because it could not reason about something.
BlocksAborted blocksAborted;
- void generateNode(const ProgramPoint& Loc, const GRState* State,
- ExplodedNode* Pred);
+ void generateNode(const ProgramPoint &Loc,
+ const ProgramState *State,
+ ExplodedNode *Pred);
- void HandleBlockEdge(const BlockEdge& E, ExplodedNode* Pred);
- void HandleBlockEntrance(const BlockEntrance& E, ExplodedNode* Pred);
- void HandleBlockExit(const CFGBlock* B, ExplodedNode* Pred);
- void HandlePostStmt(const CFGBlock* B, unsigned StmtIdx, ExplodedNode *Pred);
+ void HandleBlockEdge(const BlockEdge &E, ExplodedNode *Pred);
+ void HandleBlockEntrance(const BlockEntrance &E, ExplodedNode *Pred);
+ void HandleBlockExit(const CFGBlock *B, ExplodedNode *Pred);
+ void HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, ExplodedNode *Pred);
- void HandleBranch(const Stmt* Cond, const Stmt* Term, const CFGBlock* B,
- ExplodedNode* Pred);
+ void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B,
+ ExplodedNode *Pred);
void HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
unsigned Index, ExplodedNode *Pred);
void HandleCallExit(const CallExit &L, ExplodedNode *Pred);
@@ -124,9 +126,10 @@ public:
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of
/// steps. Returns true if there is still simulation state on the worklist.
bool ExecuteWorkList(const LocationContext *L, unsigned Steps,
- const GRState *InitState);
- void ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
- const GRState *InitState,
+ const ProgramState *InitState);
+ void ExecuteWorkListWithInitialState(const LocationContext *L,
+ unsigned Steps,
+ const ProgramState *InitState,
ExplodedNodeSet &Dst);
// Functions for external checking of whether we have unfinished work
@@ -160,41 +163,36 @@ public:
class StmtNodeBuilder {
CoreEngine& Eng;
- const CFGBlock& B;
+ const CFGBlock &B;
const unsigned Idx;
- ExplodedNode* Pred;
- GRStateManager& Mgr;
+ ExplodedNode *Pred;
+
public:
bool PurgingDeadSymbols;
bool BuildSinks;
bool hasGeneratedNode;
ProgramPoint::Kind PointKind;
- const void *Tag;
-
- const GRState* CleanedState;
-
+ const ProgramPointTag *Tag;
typedef llvm::SmallPtrSet<ExplodedNode*,5> DeferredTy;
DeferredTy Deferred;
- void GenerateAutoTransition(ExplodedNode* N);
+ void GenerateAutoTransition(ExplodedNode *N);
public:
- StmtNodeBuilder(const CFGBlock* b, unsigned idx, ExplodedNode* N,
- CoreEngine* e, GRStateManager &mgr);
+ StmtNodeBuilder(const CFGBlock *b,
+ unsigned idx,
+ ExplodedNode *N,
+ CoreEngine* e);
~StmtNodeBuilder();
- ExplodedNode* getPredecessor() const { return Pred; }
+ ExplodedNode *getPredecessor() const { return Pred; }
// FIXME: This should not be exposed.
WorkList *getWorkList() { return Eng.WList; }
- void SetCleanedState(const GRState* St) {
- CleanedState = St;
- }
-
BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
unsigned getCurrentBlockCount() const {
@@ -203,14 +201,11 @@ public:
B.getBlockID());
}
- ExplodedNode* generateNode(PostStmt PP,const GRState* St,ExplodedNode* Pred) {
- hasGeneratedNode = true;
- return generateNodeInternal(PP, St, Pred);
- }
-
- ExplodedNode* generateNode(const Stmt *S, const GRState *St,
- ExplodedNode *Pred, ProgramPoint::Kind K,
- const void *tag = 0) {
+ ExplodedNode *generateNode(const Stmt *S,
+ const ProgramState *St,
+ ExplodedNode *Pred,
+ ProgramPoint::Kind K,
+ const ProgramPointTag *tag = 0) {
hasGeneratedNode = true;
if (PurgingDeadSymbols)
@@ -219,59 +214,65 @@ public:
return generateNodeInternal(S, St, Pred, K, tag ? tag : Tag);
}
- ExplodedNode* generateNode(const Stmt *S, const GRState *St,
- ExplodedNode *Pred, const void *tag = 0) {
+ ExplodedNode *generateNode(const Stmt *S,
+ const ProgramState *St,
+ ExplodedNode *Pred,
+ const ProgramPointTag *tag = 0) {
return generateNode(S, St, Pred, PointKind, tag);
}
- ExplodedNode *generateNode(const ProgramPoint &PP, const GRState* State,
- ExplodedNode* Pred) {
+ ExplodedNode *generateNode(const ProgramPoint &PP,
+ const ProgramState *State,
+ ExplodedNode *Pred) {
hasGeneratedNode = true;
return generateNodeInternal(PP, State, Pred);
}
ExplodedNode*
- generateNodeInternal(const ProgramPoint &PP, const GRState* State,
- ExplodedNode* Pred);
+ generateNodeInternal(const ProgramPoint &PP,
+ const ProgramState *State,
+ ExplodedNode *Pred);
ExplodedNode*
- generateNodeInternal(const Stmt* S, const GRState* State, ExplodedNode* Pred,
- ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
- const void *tag = 0);
+ generateNodeInternal(const Stmt *S,
+ const ProgramState *State,
+ ExplodedNode *Pred,
+ ProgramPoint::Kind K,
+ const ProgramPointTag *tag = 0);
/// getStmt - Return the current block-level expression associated with
/// this builder.
- const Stmt* getStmt() const {
+ const Stmt *getStmt() const {
const CFGStmt *CS = B[Idx].getAs<CFGStmt>();
return CS ? CS->getStmt() : 0;
}
/// getBlock - Return the CFGBlock associated with the block-level expression
/// of this builder.
- const CFGBlock* getBlock() const { return &B; }
+ const CFGBlock *getBlock() const { return &B; }
unsigned getIndex() const { return Idx; }
- const GRState* GetState(ExplodedNode* Pred) const {
- if (Pred == getPredecessor())
- return CleanedState;
- else
- return Pred->getState();
- }
-
- ExplodedNode* MakeNode(ExplodedNodeSet& Dst, const Stmt* S,
- ExplodedNode* Pred, const GRState* St) {
+ ExplodedNode *MakeNode(ExplodedNodeSet &Dst,
+ const Stmt *S,
+ ExplodedNode *Pred,
+ const ProgramState *St) {
return MakeNode(Dst, S, Pred, St, PointKind);
}
- ExplodedNode* MakeNode(ExplodedNodeSet& Dst, const Stmt* S,ExplodedNode* Pred,
- const GRState* St, ProgramPoint::Kind K);
+ ExplodedNode *MakeNode(ExplodedNodeSet &Dst,
+ const Stmt *S,
+ ExplodedNode *Pred,
+ const ProgramState *St,
+ ProgramPoint::Kind K);
- ExplodedNode* MakeSinkNode(ExplodedNodeSet& Dst, const Stmt* S,
- ExplodedNode* Pred, const GRState* St) {
+ ExplodedNode *MakeSinkNode(ExplodedNodeSet &Dst,
+ const Stmt *S,
+ ExplodedNode *Pred,
+ const ProgramState *St) {
bool Tmp = BuildSinks;
BuildSinks = true;
- ExplodedNode* N = MakeNode(Dst, S, Pred, St);
+ ExplodedNode *N = MakeNode(Dst, S, Pred, St);
BuildSinks = Tmp;
return N;
}
@@ -279,12 +280,12 @@ public:
class BranchNodeBuilder {
CoreEngine& Eng;
- const CFGBlock* Src;
- const CFGBlock* DstT;
- const CFGBlock* DstF;
- ExplodedNode* Pred;
+ const CFGBlock *Src;
+ const CFGBlock *DstT;
+ const CFGBlock *DstF;
+ ExplodedNode *Pred;
- typedef llvm::SmallVector<ExplodedNode*,3> DeferredTy;
+ typedef SmallVector<ExplodedNode*,3> DeferredTy;
DeferredTy Deferred;
bool GeneratedTrue;
@@ -293,25 +294,27 @@ class BranchNodeBuilder {
bool InFeasibleFalse;
public:
- BranchNodeBuilder(const CFGBlock* src, const CFGBlock* dstT,
- const CFGBlock* dstF, ExplodedNode* pred, CoreEngine* e)
+ BranchNodeBuilder(const CFGBlock *src, const CFGBlock *dstT,
+ const CFGBlock *dstF, ExplodedNode *pred, CoreEngine* e)
: Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred),
GeneratedTrue(false), GeneratedFalse(false),
InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {}
~BranchNodeBuilder();
- ExplodedNode* getPredecessor() const { return Pred; }
+ ExplodedNode *getPredecessor() const { return Pred; }
const ExplodedGraph& getGraph() const { return *Eng.G; }
BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
- ExplodedNode* generateNode(const Stmt *Condition, const GRState* State);
+ /// This function generates a new ExplodedNode but not a new
+ /// branch(block edge).
+ ExplodedNode *generateNode(const Stmt *Condition, const ProgramState *State);
- ExplodedNode* generateNode(const GRState* State, bool branch);
+ ExplodedNode *generateNode(const ProgramState *State, bool branch);
- const CFGBlock* getTargetBlock(bool branch) const {
+ const CFGBlock *getTargetBlock(bool branch) const {
return branch ? DstT : DstF;
}
@@ -326,21 +329,21 @@ public:
return branch ? !InFeasibleTrue : !InFeasibleFalse;
}
- const GRState* getState() const {
+ const ProgramState *getState() const {
return getPredecessor()->getState();
}
};
class IndirectGotoNodeBuilder {
CoreEngine& Eng;
- const CFGBlock* Src;
- const CFGBlock& DispatchBlock;
- const Expr* E;
- ExplodedNode* Pred;
+ const CFGBlock *Src;
+ const CFGBlock &DispatchBlock;
+ const Expr *E;
+ ExplodedNode *Pred;
public:
- IndirectGotoNodeBuilder(ExplodedNode* pred, const CFGBlock* src,
- const Expr* e, const CFGBlock* dispatch, CoreEngine* eng)
+ IndirectGotoNodeBuilder(ExplodedNode *pred, const CFGBlock *src,
+ const Expr *e, const CFGBlock *dispatch, CoreEngine* eng)
: Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
class iterator {
@@ -350,8 +353,8 @@ public:
iterator(CFGBlock::const_succ_iterator i) : I(i) {}
public:
- iterator& operator++() { ++I; return *this; }
- bool operator!=(const iterator& X) const { return I != X.I; }
+ iterator &operator++() { ++I; return *this; }
+ bool operator!=(const iterator &X) const { return I != X.I; }
const LabelDecl *getLabel() const {
return llvm::cast<LabelStmt>((*I)->getLabel())->getDecl();
@@ -365,23 +368,24 @@ public:
iterator begin() { return iterator(DispatchBlock.succ_begin()); }
iterator end() { return iterator(DispatchBlock.succ_end()); }
- ExplodedNode* generateNode(const iterator& I, const GRState* State,
+ ExplodedNode *generateNode(const iterator &I,
+ const ProgramState *State,
bool isSink = false);
- const Expr* getTarget() const { return E; }
+ const Expr *getTarget() const { return E; }
- const GRState* getState() const { return Pred->State; }
+ const ProgramState *getState() const { return Pred->State; }
};
class SwitchNodeBuilder {
CoreEngine& Eng;
- const CFGBlock* Src;
- const Expr* Condition;
- ExplodedNode* Pred;
+ const CFGBlock *Src;
+ const Expr *Condition;
+ ExplodedNode *Pred;
public:
- SwitchNodeBuilder(ExplodedNode* pred, const CFGBlock* src,
- const Expr* condition, CoreEngine* eng)
+ SwitchNodeBuilder(ExplodedNode *pred, const CFGBlock *src,
+ const Expr *condition, CoreEngine* eng)
: Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
class iterator {
@@ -391,15 +395,15 @@ public:
iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {}
public:
- iterator& operator++() { ++I; return *this; }
+ iterator &operator++() { ++I; return *this; }
bool operator!=(const iterator &X) const { return I != X.I; }
bool operator==(const iterator &X) const { return I == X.I; }
- const CaseStmt* getCase() const {
+ const CaseStmt *getCase() const {
return llvm::cast<CaseStmt>((*I)->getLabel());
}
- const CFGBlock* getBlock() const {
+ const CFGBlock *getBlock() const {
return *I;
}
};
@@ -411,14 +415,15 @@ public:
return llvm::cast<SwitchStmt>(Src->getTerminator());
}
- ExplodedNode* generateCaseStmtNode(const iterator& I, const GRState* State);
+ ExplodedNode *generateCaseStmtNode(const iterator &I,
+ const ProgramState *State);
- ExplodedNode* generateDefaultCaseNode(const GRState* State,
+ ExplodedNode *generateDefaultCaseNode(const ProgramState *State,
bool isSink = false);
- const Expr* getCondition() const { return Condition; }
+ const Expr *getCondition() const { return Condition; }
- const GRState* getState() const { return Pred->State; }
+ const ProgramState *getState() const { return Pred->State; }
};
class GenericNodeBuilderImpl {
@@ -426,10 +431,12 @@ protected:
CoreEngine &engine;
ExplodedNode *pred;
ProgramPoint pp;
- llvm::SmallVector<ExplodedNode*, 2> sinksGenerated;
+ SmallVector<ExplodedNode*, 2> sinksGenerated;
- ExplodedNode *generateNodeImpl(const GRState *state, ExplodedNode *pred,
- ProgramPoint programPoint, bool asSink);
+ ExplodedNode *generateNodeImpl(const ProgramState *state,
+ ExplodedNode *pred,
+ ProgramPoint programPoint,
+ bool asSink);
GenericNodeBuilderImpl(CoreEngine &eng, ExplodedNode *pr, ProgramPoint p)
: engine(eng), pred(pr), pp(p), hasGeneratedNode(false) {}
@@ -439,13 +446,13 @@ public:
WorkList &getWorkList() { return *engine.WList; }
- ExplodedNode* getPredecessor() const { return pred; }
+ ExplodedNode *getPredecessor() const { return pred; }
BlockCounter getBlockCounter() const {
return engine.WList->getBlockCounter();
}
- const llvm::SmallVectorImpl<ExplodedNode*> &sinks() const {
+ const SmallVectorImpl<ExplodedNode*> &sinks() const {
return sinksGenerated;
}
};
@@ -456,8 +463,8 @@ public:
GenericNodeBuilder(CoreEngine &eng, ExplodedNode *pr, const PP_T &p)
: GenericNodeBuilderImpl(eng, pr, p) {}
- ExplodedNode *generateNode(const GRState *state, ExplodedNode *pred,
- const void *tag, bool asSink) {
+ ExplodedNode *generateNode(const ProgramState *state, ExplodedNode *pred,
+ const ProgramPointTag *tag, bool asSink) {
return generateNodeImpl(state, pred, cast<PP_T>(pp).withTag(tag),
asSink);
}
@@ -467,27 +474,27 @@ public:
class EndOfFunctionNodeBuilder {
CoreEngine &Eng;
- const CFGBlock& B;
- ExplodedNode* Pred;
- void *Tag;
+ const CFGBlock &B;
+ ExplodedNode *Pred;
+ const ProgramPointTag *Tag;
public:
bool hasGeneratedNode;
public:
- EndOfFunctionNodeBuilder(const CFGBlock* b, ExplodedNode* N, CoreEngine* e,
- void *checkerTag = 0)
- : Eng(*e), B(*b), Pred(N), Tag(checkerTag), hasGeneratedNode(false) {}
+ EndOfFunctionNodeBuilder(const CFGBlock *b, ExplodedNode *N, CoreEngine* e,
+ const ProgramPointTag *tag = 0)
+ : Eng(*e), B(*b), Pred(N), Tag(tag), hasGeneratedNode(false) {}
~EndOfFunctionNodeBuilder();
- EndOfFunctionNodeBuilder withCheckerTag(void *tag) {
+ EndOfFunctionNodeBuilder withCheckerTag(const ProgramPointTag *tag) {
return EndOfFunctionNodeBuilder(&B, Pred, &Eng, tag);
}
WorkList &getWorkList() { return *Eng.WList; }
- ExplodedNode* getPredecessor() const { return Pred; }
+ ExplodedNode *getPredecessor() const { return Pred; }
BlockCounter getBlockCounter() const {
return Eng.WList->getBlockCounter();
@@ -499,14 +506,15 @@ public:
B.getBlockID());
}
- ExplodedNode* generateNode(const GRState* State, ExplodedNode *P = 0,
- const void *tag = 0);
+ ExplodedNode *generateNode(const ProgramState *State,
+ ExplodedNode *P = 0,
+ const ProgramPointTag *tag = 0);
- void GenerateCallExitNode(const GRState *state);
+ void GenerateCallExitNode(const ProgramState *state);
- const CFGBlock* getBlock() const { return &B; }
+ const CFGBlock *getBlock() const { return &B; }
- const GRState* getState() const {
+ const ProgramState *getState() const {
return getPredecessor()->getState();
}
};
@@ -535,7 +543,7 @@ public:
const CFGBlock *blk, unsigned idx)
: Eng(eng), Pred(pred), CE(s), CalleeCtx(callee), Block(blk), Index(idx) {}
- const GRState *getState() const { return Pred->getState(); }
+ const ProgramState *getState() const { return Pred->getState(); }
const LocationContext *getLocationContext() const {
return Pred->getLocationContext();
@@ -549,7 +557,7 @@ public:
unsigned getIndex() const { return Index; }
- void generateNode(const GRState *state);
+ void generateNode(const ProgramState *state);
};
class CallExitNodeBuilder {
@@ -562,9 +570,9 @@ public:
const ExplodedNode *getPredecessor() const { return Pred; }
- const GRState *getState() const { return Pred->getState(); }
+ const ProgramState *getState() const { return Pred->getState(); }
- void generateNode(const GRState *state);
+ void generateNode(const ProgramState *state);
};
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
index 193056e6b030..2463e23f5f79 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
@@ -14,7 +14,6 @@
#ifndef LLVM_CLANG_GR_ENVIRONMENT_H
#define LLVM_CLANG_GR_ENVIRONMENT_H
-#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/ImmutableMap.h"
@@ -43,7 +42,7 @@ private:
Environment(BindingsTy eb)
: ExprBindings(eb) {}
- SVal lookupExpr(const Stmt* E) const;
+ SVal lookupExpr(const Stmt *E) const;
public:
typedef BindingsTy::iterator iterator;
@@ -53,7 +52,7 @@ public:
/// getSVal - Fetches the current binding of the expression in the
/// Environment.
- SVal getSVal(const Stmt* Ex, SValBuilder& svalBuilder,
+ SVal getSVal(const Stmt *Ex, SValBuilder& svalBuilder,
bool useOnlyDirectBindings = false) const;
/// Profile - Profile the contents of an Environment object for use
@@ -96,8 +95,7 @@ public:
SVal V);
Environment removeDeadBindings(Environment Env,
- SymbolReaper &SymReaper, const GRState *ST,
- llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
+ SymbolReaper &SymReaper, const ProgramState *ST);
};
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
index e5d6876fa6b2..fdfed3da5403 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -31,7 +31,7 @@
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/Support/Casting.h"
#include "clang/Analysis/Support/BumpVector.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
namespace clang {
@@ -67,7 +67,7 @@ class ExplodedNode : public llvm::FoldingSetNode {
return P & 0x1;
}
- void* getPtr() const {
+ void *getPtr() const {
assert (!getFlag());
return reinterpret_cast<void*>(P & ~Mask);
}
@@ -87,7 +87,7 @@ class ExplodedNode : public llvm::FoldingSetNode {
bool empty() const { return (P & ~Mask) == 0; }
- void addNode(ExplodedNode* N, ExplodedGraph &G);
+ void addNode(ExplodedNode *N, ExplodedGraph &G);
void replaceNode(ExplodedNode *node);
@@ -106,7 +106,7 @@ class ExplodedNode : public llvm::FoldingSetNode {
const ProgramPoint Location;
/// State - The state associated with this node.
- const GRState* State;
+ const ProgramState *State;
/// Preds - The predecessors of this node.
NodeGroup Preds;
@@ -116,13 +116,13 @@ class ExplodedNode : public llvm::FoldingSetNode {
public:
- explicit ExplodedNode(const ProgramPoint& loc, const GRState* state)
+ explicit ExplodedNode(const ProgramPoint &loc, const ProgramState *state)
: Location(loc), State(state) {
- const_cast<GRState*>(State)->incrementReferenceCount();
+ const_cast<ProgramState*>(State)->incrementReferenceCount();
}
~ExplodedNode() {
- const_cast<GRState*>(State)->decrementReferenceCount();
+ const_cast<ProgramState*>(State)->decrementReferenceCount();
}
/// getLocation - Returns the edge associated with the given node.
@@ -138,17 +138,18 @@ public:
ParentMap &getParentMap() const {return getLocationContext()->getParentMap();}
- LiveVariables &getLiveVariables() const {
- return *getLocationContext()->getLiveVariables();
+ template <typename T>
+ T &getAnalysis() const {
+ return *getLocationContext()->getAnalysis<T>();
}
- const GRState* getState() const { return State; }
+ const ProgramState *getState() const { return State; }
template <typename T>
const T* getLocationAs() const { return llvm::dyn_cast<T>(&Location); }
static void Profile(llvm::FoldingSetNodeID &ID,
- const ProgramPoint& Loc, const GRState* state) {
+ const ProgramPoint &Loc, const ProgramState *state) {
ID.Add(Loc);
ID.AddPointer(state);
}
@@ -159,7 +160,7 @@ public:
/// addPredeccessor - Adds a predecessor to the current node, and
/// in tandem add this node as a successor of the other node.
- void addPredecessor(ExplodedNode* V, ExplodedGraph &G);
+ void addPredecessor(ExplodedNode *V, ExplodedGraph &G);
unsigned succ_size() const { return Succs.size(); }
unsigned pred_size() const { return Preds.size(); }
@@ -169,11 +170,11 @@ public:
bool isSink() const { return Succs.getFlag(); }
void markAsSink() { Succs.setFlag(); }
- ExplodedNode* getFirstPred() {
+ ExplodedNode *getFirstPred() {
return pred_empty() ? NULL : *(pred_begin());
}
- const ExplodedNode* getFirstPred() const {
+ const ExplodedNode *getFirstPred() const {
return const_cast<ExplodedNode*>(this)->getFirstPred();
}
@@ -210,7 +211,7 @@ public:
class Auditor {
public:
virtual ~Auditor();
- virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst) = 0;
+ virtual void AddEdge(ExplodedNode *Src, ExplodedNode *Dst) = 0;
};
static void SetAuditor(Auditor* A);
@@ -226,7 +227,7 @@ class InterExplodedGraphMap {
friend class ExplodedGraph;
public:
- ExplodedNode* getMappedNode(const ExplodedNode* N) const;
+ ExplodedNode *getMappedNode(const ExplodedNode *N) const;
InterExplodedGraphMap() {}
virtual ~InterExplodedGraphMap() {}
@@ -237,8 +238,8 @@ protected:
friend class CoreEngine;
// Type definitions.
- typedef llvm::SmallVector<ExplodedNode*,2> RootsTy;
- typedef llvm::SmallVector<ExplodedNode*,10> EndNodesTy;
+ typedef SmallVector<ExplodedNode*,2> RootsTy;
+ typedef SmallVector<ExplodedNode*,10> EndNodesTy;
/// Roots - The roots of the simulation graph. Usually there will be only
/// one, but clients are free to establish multiple subgraphs within a single
@@ -275,7 +276,7 @@ public:
/// this pair exists, it is created. IsNew is set to true if
/// the node was freshly created.
- ExplodedNode* getNode(const ProgramPoint& L, const GRState *State,
+ ExplodedNode *getNode(const ProgramPoint &L, const ProgramState *State,
bool* IsNew = 0);
ExplodedGraph* MakeEmptyGraph() const {
@@ -283,13 +284,13 @@ public:
}
/// addRoot - Add an untyped node to the set of roots.
- ExplodedNode* addRoot(ExplodedNode* V) {
+ ExplodedNode *addRoot(ExplodedNode *V) {
Roots.push_back(V);
return V;
}
/// addEndOfPath - Add an untyped node to the set of EOP nodes.
- ExplodedNode* addEndOfPath(ExplodedNode* V) {
+ ExplodedNode *addEndOfPath(ExplodedNode *V) {
EndNodes.push_back(V);
return V;
}
@@ -368,18 +369,18 @@ class ExplodedNodeSet {
ImplTy Impl;
public:
- ExplodedNodeSet(ExplodedNode* N) {
+ ExplodedNodeSet(ExplodedNode *N) {
assert (N && !static_cast<ExplodedNode*>(N)->isSink());
Impl.insert(N);
}
ExplodedNodeSet() {}
- inline void Add(ExplodedNode* N) {
+ inline void Add(ExplodedNode *N) {
if (N && !static_cast<ExplodedNode*>(N)->isSink()) Impl.insert(N);
}
- ExplodedNodeSet& operator=(const ExplodedNodeSet &X) {
+ ExplodedNodeSet &operator=(const ExplodedNodeSet &X) {
Impl = X.Impl;
return *this;
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index d24036c0ec28..9bc470fdde60 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -19,9 +19,7 @@
#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/GRState.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/AST/Type.h"
#include "clang/AST/ExprObjC.h"
@@ -35,6 +33,8 @@ class ObjCForCollectionStmt;
namespace ento {
class AnalysisManager;
+class CallOrObjCMessage;
+class ObjCMessage;
class ExprEngine : public SubEngine {
AnalysisManager &AMgr;
@@ -49,7 +49,7 @@ class ExprEngine : public SubEngine {
StmtNodeBuilder* Builder;
/// StateMgr - Object that manages the data for all created states.
- GRStateManager StateMgr;
+ ProgramStateManager StateMgr;
/// SymMgr - Object that manages the symbol information.
SymbolManager& SymMgr;
@@ -58,31 +58,32 @@ class ExprEngine : public SubEngine {
SValBuilder &svalBuilder;
/// EntryNode - The immediate predecessor node.
- ExplodedNode* EntryNode;
+ ExplodedNode *EntryNode;
/// CleanedState - The state for EntryNode "cleaned" of all dead
/// variables and symbols (as determined by a liveness analysis).
- const GRState* CleanedState;
+ const ProgramState *CleanedState;
/// currentStmt - The current block-level statement.
- const Stmt* currentStmt;
+ const Stmt *currentStmt;
- // Obj-C Class Identifiers.
+ /// Obj-C Class Identifiers.
IdentifierInfo* NSExceptionII;
- // Obj-C Selectors.
+ /// Obj-C Selectors.
Selector* NSExceptionInstanceRaiseSelectors;
Selector RaiseSel;
+
+ /// Whether or not GC is enabled in this analysis.
+ bool ObjCGCEnabled;
/// The BugReporter associated with this engine. It is important that
/// this object be placed at the very end of member variables so that its
/// destructor is called before the rest of the ExprEngine is destroyed.
GRBugReporter BR;
-
- llvm::OwningPtr<TransferFuncs> TF;
public:
- ExprEngine(AnalysisManager &mgr, TransferFuncs *tf);
+ ExprEngine(AnalysisManager &mgr, bool gcEnabled);
~ExprEngine();
@@ -94,13 +95,13 @@ public:
/// of the function are added into the Dst set, which represent the exit
/// state of the function call.
void ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
- const GRState *InitState,
+ const ProgramState *InitState,
ExplodedNodeSet &Dst) {
Engine.ExecuteWorkListWithInitialState(L, Steps, InitState, Dst);
}
/// getContext - Return the ASTContext associated with this analysis.
- ASTContext& getContext() const { return AMgr.getASTContext(); }
+ ASTContext &getContext() const { return AMgr.getASTContext(); }
virtual AnalysisManager &getAnalysisManager() { return AMgr; }
@@ -110,14 +111,11 @@ public:
SValBuilder &getSValBuilder() { return svalBuilder; }
- TransferFuncs& getTF() { return *TF; }
-
BugReporter& getBugReporter() { return BR; }
StmtNodeBuilder &getBuilder() { assert(Builder); return *Builder; }
- // FIXME: Remove once TransferFuncs is no longer referenced.
- void setTransferFunction(TransferFuncs* tf);
+ bool isObjCGCEnabled() { return ObjCGCEnabled; }
/// ViewGraph - Visualize the ExplodedGraph created by executing the
/// simulation.
@@ -127,7 +125,7 @@ public:
/// getInitialState - Return the initial state used for the root vertex
/// in the ExplodedGraph.
- const GRState* getInitialState(const LocationContext *InitLoc);
+ const ProgramState *getInitialState(const LocationContext *InitLoc);
ExplodedGraph& getGraph() { return G; }
const ExplodedGraph& getGraph() const { return G; }
@@ -155,7 +153,7 @@ public:
/// ProcessBranch - Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a branch condition.
- void processBranch(const Stmt* Condition, const Stmt* Term,
+ void processBranch(const Stmt *Condition, const Stmt *Term,
BranchNodeBuilder& builder);
/// processIndirectGoto - Called by CoreEngine. Used to generate successor
@@ -181,21 +179,25 @@ public:
/// evalAssume - Callback function invoked by the ConstraintManager when
/// making assumptions about state values.
- const GRState *processAssume(const GRState *state, SVal cond,bool assumption);
+ const ProgramState *processAssume(const ProgramState *state, SVal cond,bool assumption);
- /// wantsRegionChangeUpdate - Called by GRStateManager to determine if a
+ /// wantsRegionChangeUpdate - Called by ProgramStateManager to determine if a
/// region change should trigger a processRegionChanges update.
- bool wantsRegionChangeUpdate(const GRState* state);
+ bool wantsRegionChangeUpdate(const ProgramState *state);
- /// processRegionChanges - Called by GRStateManager whenever a change is made
+ /// processRegionChanges - Called by ProgramStateManager whenever a change is made
/// to the store. Used to update checkers that track region values.
- const GRState *
- processRegionChanges(const GRState *state,
+ const ProgramState *
+ processRegionChanges(const ProgramState *state,
const StoreManager::InvalidatedSymbols *invalidated,
- const MemRegion * const *Begin,
- const MemRegion * const *End);
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions);
- virtual GRStateManager& getStateManager() { return StateMgr; }
+ /// printState - Called by ProgramStateManager to print checker-specific data.
+ void printState(raw_ostream &Out, const ProgramState *State,
+ const char *NL, const char *Sep);
+
+ virtual ProgramStateManager& getStateManager() { return StateMgr; }
StoreManager& getStoreManager() { return StateMgr.getStoreManager(); }
@@ -222,124 +224,109 @@ public:
const CoreEngine &getCoreEngine() const { return Engine; }
-protected:
- const GRState* GetState(ExplodedNode* N) {
- return N == EntryNode ? CleanedState : N->getState();
- }
-
public:
- ExplodedNode* MakeNode(ExplodedNodeSet& Dst, const Stmt* S,
- ExplodedNode* Pred, const GRState* St,
+ ExplodedNode *MakeNode(ExplodedNodeSet &Dst, const Stmt *S,
+ ExplodedNode *Pred, const ProgramState *St,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
- const void *tag = 0);
+ const ProgramPointTag *tag = 0);
/// Visit - Transfer function logic for all statements. Dispatches to
/// other functions that handle specific kinds of statements.
- void Visit(const Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst);
+ void Visit(const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst);
/// VisitArraySubscriptExpr - Transfer function for array accesses.
- void VisitLvalArraySubscriptExpr(const ArraySubscriptExpr* Ex,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *Ex,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitAsmStmt - Transfer function logic for inline asm.
- void VisitAsmStmt(const AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst);
+ void VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred, ExplodedNodeSet &Dst);
- void VisitAsmStmtHelperOutputs(const AsmStmt* A,
+ void VisitAsmStmtHelperOutputs(const AsmStmt *A,
AsmStmt::const_outputs_iterator I,
AsmStmt::const_outputs_iterator E,
- ExplodedNode* Pred, ExplodedNodeSet& Dst);
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
- void VisitAsmStmtHelperInputs(const AsmStmt* A,
+ void VisitAsmStmtHelperInputs(const AsmStmt *A,
AsmStmt::const_inputs_iterator I,
AsmStmt::const_inputs_iterator E,
- ExplodedNode* Pred, ExplodedNodeSet& Dst);
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
/// VisitBlockExpr - Transfer function logic for BlockExprs.
void VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
/// VisitBinaryOperator - Transfer function logic for binary operators.
- void VisitBinaryOperator(const BinaryOperator* B, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitBinaryOperator(const BinaryOperator* B, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitCall - Transfer function for function calls.
- void VisitCallExpr(const CallExpr* CE, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitCast - Transfer function logic for all casts (implicit and explicit).
void VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
/// VisitCompoundLiteralExpr - Transfer function logic for compound literals.
- void VisitCompoundLiteralExpr(const CompoundLiteralExpr* CL,
- ExplodedNode* Pred, ExplodedNodeSet& Dst);
+ void VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
/// Transfer function logic for DeclRefExprs and BlockDeclRefExprs.
- void VisitCommonDeclRefExpr(const Expr* DR, const NamedDecl *D,
- ExplodedNode* Pred, ExplodedNodeSet& Dst);
+ void VisitCommonDeclRefExpr(const Expr *DR, const NamedDecl *D,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
/// VisitDeclStmt - Transfer function logic for DeclStmts.
- void VisitDeclStmt(const DeclStmt* DS, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose
- void VisitGuardedExpr(const Expr* Ex, const Expr* L, const Expr* R,
- ExplodedNode* Pred, ExplodedNodeSet& Dst);
+ void VisitGuardedExpr(const Expr *Ex, const Expr *L, const Expr *R,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
- void VisitInitListExpr(const InitListExpr* E, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitInitListExpr(const InitListExpr *E, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitLogicalExpr - Transfer function logic for '&&', '||'
- void VisitLogicalExpr(const BinaryOperator* B, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitMemberExpr - Transfer function for member expressions.
- void VisitMemberExpr(const MemberExpr* M, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// Transfer function logic for ObjCAtSynchronizedStmts.
void VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
ExplodedNode *Pred, ExplodedNodeSet &Dst);
- void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *E,
- ExplodedNode *Pred, ExplodedNodeSet &Dst);
-
/// Transfer function logic for computing the lvalue of an Objective-C ivar.
- void VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr* DR, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *DR, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitObjCForCollectionStmt - Transfer function logic for
/// ObjCForCollectionStmt.
- void VisitObjCForCollectionStmt(const ObjCForCollectionStmt* S,
- ExplodedNode* Pred, ExplodedNodeSet& Dst);
+ void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
- void VisitObjCForCollectionStmtAux(const ObjCForCollectionStmt* S,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst, SVal ElementV);
-
- /// VisitObjCMessageExpr - Transfer function for ObjC message expressions.
- void VisitObjCMessageExpr(const ObjCMessageExpr* ME, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
- void VisitObjCMessage(const ObjCMessage &msg, ExplodedNodeSet &Src,
- ExplodedNodeSet& Dst);
+ void VisitObjCMessage(const ObjCMessage &msg, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitReturnStmt - Transfer function logic for return statements.
- void VisitReturnStmt(const ReturnStmt* R, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitReturnStmt(const ReturnStmt *R, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitOffsetOfExpr - Transfer function for offsetof.
- void VisitOffsetOfExpr(const OffsetOfExpr* Ex, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitOffsetOfExpr(const OffsetOfExpr *Ex, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitUnaryExprOrTypeTraitExpr - Transfer function for sizeof.
- void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr* Ex,
- ExplodedNode* Pred, ExplodedNodeSet& Dst);
+ void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
/// VisitUnaryOperator - Transfer function logic for unary operators.
- void VisitUnaryOperator(const UnaryOperator* B, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitUnaryOperator(const UnaryOperator* B, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
void VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet & Dst);
@@ -366,7 +353,8 @@ public:
ExplodedNodeSet &Dst);
/// Create a C++ temporary object for an rvalue.
- void CreateCXXTemporaryObject(const Expr *Ex, ExplodedNode *Pred,
+ void CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
+ ExplodedNode *Pred,
ExplodedNodeSet &Dst);
/// Synthesize CXXThisRegion.
@@ -389,8 +377,11 @@ public:
/// evalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic
/// expressions of the form 'x != 0' and generate new nodes (stored in Dst)
/// with those assumptions.
- void evalEagerlyAssume(ExplodedNodeSet& Dst, ExplodedNodeSet& Src,
+ void evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
const Expr *Ex);
+
+ std::pair<const ProgramPointTag *, const ProgramPointTag*>
+ getEagerlyAssumeTags();
SVal evalMinus(SVal X) {
return X.isValid() ? svalBuilder.evalMinus(cast<NonLoc>(X)) : X;
@@ -402,36 +393,36 @@ public:
public:
- SVal evalBinOp(const GRState *state, BinaryOperator::Opcode op,
+ SVal evalBinOp(const ProgramState *state, BinaryOperator::Opcode op,
NonLoc L, NonLoc R, QualType T) {
return svalBuilder.evalBinOpNN(state, op, L, R, T);
}
- SVal evalBinOp(const GRState *state, BinaryOperator::Opcode op,
+ SVal evalBinOp(const ProgramState *state, BinaryOperator::Opcode op,
NonLoc L, SVal R, QualType T) {
return R.isValid() ? svalBuilder.evalBinOpNN(state,op,L, cast<NonLoc>(R), T) : R;
}
- SVal evalBinOp(const GRState *ST, BinaryOperator::Opcode Op,
+ SVal evalBinOp(const ProgramState *ST, BinaryOperator::Opcode Op,
SVal LHS, SVal RHS, QualType T) {
return svalBuilder.evalBinOp(ST, Op, LHS, RHS, T);
}
protected:
- void evalObjCMessage(ExplodedNodeSet& Dst, const ObjCMessage &msg,
- ExplodedNode* Pred, const GRState *state) {
- assert (Builder && "StmtNodeBuilder must be defined.");
- getTF().evalObjCMessage(Dst, *this, *Builder, msg, Pred, state);
- }
+ void evalObjCMessage(ExplodedNodeSet &Dst, const ObjCMessage &msg,
+ ExplodedNode *Pred, const ProgramState *state);
+
+ const ProgramState *invalidateArguments(const ProgramState *State,
+ const CallOrObjCMessage &Call,
+ const LocationContext *LC);
- const GRState* MarkBranch(const GRState* St, const Stmt* Terminator,
+ const ProgramState *MarkBranch(const ProgramState *St, const Stmt *Terminator,
bool branchTaken);
/// evalBind - Handle the semantics of binding a value to a specific location.
/// This method is used by evalStore, VisitDeclStmt, and others.
- void evalBind(ExplodedNodeSet& Dst, const Stmt* StoreE, ExplodedNode* Pred,
- const GRState* St, SVal location, SVal Val,
- bool atDeclInit = false);
+ void evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, ExplodedNode *Pred,
+ SVal location, SVal Val, bool atDeclInit = false);
public:
// FIXME: 'tag' should be removed, and a LocationContext should be used
@@ -440,25 +431,25 @@ public:
// be the same as Pred->state, and when 'location' may not be the
// same as state->getLValue(Ex).
/// Simulate a read of the result of Ex.
- void evalLoad(ExplodedNodeSet& Dst, const Expr* Ex, ExplodedNode* Pred,
- const GRState* St, SVal location, const void *tag = 0,
+ void evalLoad(ExplodedNodeSet &Dst, const Expr *Ex, ExplodedNode *Pred,
+ const ProgramState *St, SVal location, const ProgramPointTag *tag = 0,
QualType LoadTy = QualType());
// FIXME: 'tag' should be removed, and a LocationContext should be used
// instead.
- void evalStore(ExplodedNodeSet& Dst, const Expr* AssignE, const Expr* StoreE,
- ExplodedNode* Pred, const GRState* St, SVal TargetLV, SVal Val,
- const void *tag = 0);
+ void evalStore(ExplodedNodeSet &Dst, const Expr *AssignE, const Expr *StoreE,
+ ExplodedNode *Pred, const ProgramState *St, SVal TargetLV, SVal Val,
+ const ProgramPointTag *tag = 0);
private:
- void evalLoadCommon(ExplodedNodeSet& Dst, const Expr* Ex, ExplodedNode* Pred,
- const GRState* St, SVal location, const void *tag,
+ void evalLoadCommon(ExplodedNodeSet &Dst, const Expr *Ex, ExplodedNode *Pred,
+ const ProgramState *St, SVal location, const ProgramPointTag *tag,
QualType LoadTy);
// FIXME: 'tag' should be removed, and a LocationContext should be used
// instead.
- void evalLocation(ExplodedNodeSet &Dst, const Stmt *S, ExplodedNode* Pred,
- const GRState* St, SVal location,
- const void *tag, bool isLoad);
+ void evalLocation(ExplodedNodeSet &Dst, const Stmt *S, ExplodedNode *Pred,
+ const ProgramState *St, SVal location,
+ const ProgramPointTag *tag, bool isLoad);
bool InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExplodedNode *Pred);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h
index 18e39d999bb4..89b47dc6ec26 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h
@@ -25,9 +25,9 @@ class StmtNodeBuilderRef {
ExplodedNodeSet &Dst;
StmtNodeBuilder &B;
ExprEngine& Eng;
- ExplodedNode* Pred;
- const GRState* state;
- const Stmt* stmt;
+ ExplodedNode *Pred;
+ const ProgramState *state;
+ const Stmt *stmt;
const unsigned OldSize;
const bool AutoCreateNode;
SaveAndRestore<bool> OldSink;
@@ -42,9 +42,9 @@ private:
StmtNodeBuilderRef(ExplodedNodeSet &dst,
StmtNodeBuilder &builder,
ExprEngine& eng,
- ExplodedNode* pred,
- const GRState *st,
- const Stmt* s, bool auto_create_node)
+ ExplodedNode *pred,
+ const ProgramState *st,
+ const Stmt *s, bool auto_create_node)
: Dst(dst), B(builder), Eng(eng), Pred(pred),
state(st), stmt(s), OldSize(Dst.size()), AutoCreateNode(auto_create_node),
OldSink(B.BuildSinks), OldHasGen(B.hasGeneratedNode) {}
@@ -62,13 +62,13 @@ public:
}
}
- const GRState *getState() { return state; }
+ const ProgramState *getState() { return state; }
- GRStateManager& getStateManager() {
+ ProgramStateManager& getStateManager() {
return Eng.getStateManager();
}
- ExplodedNode* MakeNode(const GRState* state) {
+ ExplodedNode *MakeNode(const ProgramState *state) {
return B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state);
}
};
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index db7a930b556e..c9941fe90c24 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -19,15 +19,14 @@
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/ADT/FoldingSet.h"
#include <string>
namespace llvm {
class BumpPtrAllocator;
-class raw_ostream;
}
namespace clang {
@@ -83,12 +82,13 @@ public:
// Untyped regions.
SymbolicRegionKind,
AllocaRegionKind,
+ BlockDataRegionKind,
// Typed regions.
BEG_TYPED_REGIONS,
FunctionTextRegionKind = BEG_TYPED_REGIONS,
BlockTextRegionKind,
- BlockDataRegionKind,
- CompoundLiteralRegionKind,
+ BEG_TYPED_VALUE_REGIONS,
+ CompoundLiteralRegionKind = BEG_TYPED_VALUE_REGIONS,
CXXThisRegionKind,
StringRegionKind,
ElementRegionKind,
@@ -100,6 +100,7 @@ public:
END_DECL_REGIONS = ObjCIvarRegionKind,
CXXTempObjectRegionKind,
CXXBaseObjectRegionKind,
+ END_TYPED_VALUE_REGIONS = CXXBaseObjectRegionKind,
END_TYPED_REGIONS = CXXBaseObjectRegionKind
};
@@ -136,7 +137,7 @@ public:
/// Compute the offset within the top level memory object.
RegionOffset getAsOffset() const;
- virtual void dumpToStream(llvm::raw_ostream& os) const;
+ virtual void dumpToStream(raw_ostream &os) const;
void dump() const;
@@ -197,7 +198,7 @@ class StaticGlobalSpaceRegion : public GlobalsSpaceRegion {
public:
void Profile(llvm::FoldingSetNodeID &ID) const;
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
const CodeTextRegion *getCodeRegion() const { return CR; }
@@ -214,7 +215,7 @@ class NonStaticGlobalSpaceRegion : public GlobalsSpaceRegion {
public:
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
static bool classof(const MemRegion *R) {
return R->getKind() == NonStaticGlobalSpaceRegionKind;
@@ -323,14 +324,14 @@ class AllocaRegion : public SubRegion {
protected:
unsigned Cnt; // Block counter. Used to distinguish different pieces of
// memory allocated by alloca at the same call site.
- const Expr* Ex;
+ const Expr *Ex;
- AllocaRegion(const Expr* ex, unsigned cnt, const MemRegion *superRegion)
+ AllocaRegion(const Expr *ex, unsigned cnt, const MemRegion *superRegion)
: SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {}
public:
- const Expr* getExpr() const { return Ex; }
+ const Expr *getExpr() const { return Ex; }
bool isBoundable() const { return true; }
@@ -338,10 +339,10 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) const;
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr* Ex,
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr *Ex,
unsigned Cnt, const MemRegion *superRegion);
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
static bool classof(const MemRegion* R) {
return R->getKind() == AllocaRegionKind;
@@ -354,6 +355,26 @@ protected:
TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {}
public:
+ virtual QualType getLocationType() const = 0;
+
+ QualType getDesugaredLocationType(ASTContext &Context) const {
+ return getLocationType().getDesugaredType(Context);
+ }
+
+ bool isBoundable() const { return true; }
+
+ static bool classof(const MemRegion* R) {
+ unsigned k = R->getKind();
+ return k >= BEG_TYPED_REGIONS && k <= END_TYPED_REGIONS;
+ }
+};
+
+/// TypedValueRegion - An abstract class representing regions having a typed value.
+class TypedValueRegion : public TypedRegion {
+protected:
+ TypedValueRegion(const MemRegion* sReg, Kind k) : TypedRegion(sReg, k) {}
+
+public:
virtual QualType getValueType() const = 0;
virtual QualType getLocationType() const {
@@ -370,15 +391,9 @@ public:
return T.getTypePtrOrNull() ? T.getDesugaredType(Context) : T;
}
- QualType getDesugaredLocationType(ASTContext &Context) const {
- return getLocationType().getDesugaredType(Context);
- }
-
- bool isBoundable() const { return true; }
-
static bool classof(const MemRegion* R) {
unsigned k = R->getKind();
- return k >= BEG_TYPED_REGIONS && k <= END_TYPED_REGIONS;
+ return k >= BEG_TYPED_VALUE_REGIONS && k <= END_TYPED_VALUE_REGIONS;
}
};
@@ -387,11 +402,6 @@ class CodeTextRegion : public TypedRegion {
protected:
CodeTextRegion(const MemRegion *sreg, Kind k) : TypedRegion(sreg, k) {}
public:
- QualType getValueType() const {
- assert(0 && "Do not get the object type of a CodeTextRegion.");
- return QualType();
- }
-
bool isBoundable() const { return false; }
static bool classof(const MemRegion* R) {
@@ -404,7 +414,7 @@ public:
class FunctionTextRegion : public CodeTextRegion {
const FunctionDecl *FD;
public:
- FunctionTextRegion(const FunctionDecl* fd, const MemRegion* sreg)
+ FunctionTextRegion(const FunctionDecl *fd, const MemRegion* sreg)
: CodeTextRegion(sreg, FunctionTextRegionKind), FD(fd) {}
QualType getLocationType() const {
@@ -415,7 +425,7 @@ public:
return FD;
}
- virtual void dumpToStream(llvm::raw_ostream& os) const;
+ virtual void dumpToStream(raw_ostream &os) const;
void Profile(llvm::FoldingSetNodeID& ID) const;
@@ -456,7 +466,7 @@ public:
AnalysisContext *getAnalysisContext() const { return AC; }
- virtual void dumpToStream(llvm::raw_ostream& os) const;
+ virtual void dumpToStream(raw_ostream &os) const;
void Profile(llvm::FoldingSetNodeID& ID) const;
@@ -509,7 +519,7 @@ public:
bool operator!=(const referenced_vars_iterator &I) const {
return I.R != R;
}
- referenced_vars_iterator& operator++() {
+ referenced_vars_iterator &operator++() {
++R;
return *this;
}
@@ -518,7 +528,7 @@ public:
referenced_vars_iterator referenced_vars_begin() const;
referenced_vars_iterator referenced_vars_end() const;
- virtual void dumpToStream(llvm::raw_ostream& os) const;
+ virtual void dumpToStream(raw_ostream &os) const;
void Profile(llvm::FoldingSetNodeID& ID) const;
@@ -559,7 +569,7 @@ public:
SymbolRef sym,
const MemRegion* superRegion);
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
static bool classof(const MemRegion* R) {
return R->getKind() == SymbolicRegionKind;
@@ -567,13 +577,13 @@ public:
};
/// StringRegion - Region associated with a StringLiteral.
-class StringRegion : public TypedRegion {
+class StringRegion : public TypedValueRegion {
friend class MemRegionManager;
const StringLiteral* Str;
protected:
StringRegion(const StringLiteral* str, const MemRegion* sreg)
- : TypedRegion(sreg, StringRegionKind), Str(str) {}
+ : TypedValueRegion(sreg, StringRegionKind), Str(str) {}
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
const StringLiteral* Str,
@@ -595,7 +605,7 @@ public:
ProfileRegion(ID, Str, superRegion);
}
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
static bool classof(const MemRegion* R) {
return R->getKind() == StringRegionKind;
@@ -605,16 +615,16 @@ public:
/// CompoundLiteralRegion - A memory region representing a compound literal.
/// Compound literals are essentially temporaries that are stack allocated
/// or in the global constant pool.
-class CompoundLiteralRegion : public TypedRegion {
+class CompoundLiteralRegion : public TypedValueRegion {
private:
friend class MemRegionManager;
- const CompoundLiteralExpr* CL;
+ const CompoundLiteralExpr *CL;
- CompoundLiteralRegion(const CompoundLiteralExpr* cl, const MemRegion* sReg)
- : TypedRegion(sReg, CompoundLiteralRegionKind), CL(cl) {}
+ CompoundLiteralRegion(const CompoundLiteralExpr *cl, const MemRegion* sReg)
+ : TypedValueRegion(sReg, CompoundLiteralRegionKind), CL(cl) {}
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
- const CompoundLiteralExpr* CL,
+ const CompoundLiteralExpr *CL,
const MemRegion* superRegion);
public:
QualType getValueType() const {
@@ -625,27 +635,27 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) const;
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
- const CompoundLiteralExpr* getLiteralExpr() const { return CL; }
+ const CompoundLiteralExpr *getLiteralExpr() const { return CL; }
static bool classof(const MemRegion* R) {
return R->getKind() == CompoundLiteralRegionKind;
}
};
-class DeclRegion : public TypedRegion {
+class DeclRegion : public TypedValueRegion {
protected:
- const Decl* D;
+ const Decl *D;
- DeclRegion(const Decl* d, const MemRegion* sReg, Kind k)
- : TypedRegion(sReg, k), D(d) {}
+ DeclRegion(const Decl *d, const MemRegion* sReg, Kind k)
+ : TypedValueRegion(sReg, k), D(d) {}
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D,
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D,
const MemRegion* superRegion, Kind k);
public:
- const Decl* getDecl() const { return D; }
+ const Decl *getDecl() const { return D; }
void Profile(llvm::FoldingSetNodeID& ID) const;
DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const;
@@ -660,10 +670,10 @@ class VarRegion : public DeclRegion {
friend class MemRegionManager;
// Constructors and private methods.
- VarRegion(const VarDecl* vd, const MemRegion* sReg)
+ VarRegion(const VarDecl *vd, const MemRegion* sReg)
: DeclRegion(vd, sReg, VarRegionKind) {}
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl* VD,
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl *VD,
const MemRegion *superRegion) {
DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind);
}
@@ -680,7 +690,7 @@ public:
return getDecl()->getType();
}
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
static bool classof(const MemRegion* R) {
return R->getKind() == VarRegionKind;
@@ -690,11 +700,11 @@ public:
/// CXXThisRegion - Represents the region for the implicit 'this' parameter
/// in a call to a C++ method. This region doesn't represent the object
/// referred to by 'this', but rather 'this' itself.
-class CXXThisRegion : public TypedRegion {
+class CXXThisRegion : public TypedValueRegion {
friend class MemRegionManager;
CXXThisRegion(const PointerType *thisPointerTy,
const MemRegion *sReg)
- : TypedRegion(sReg, CXXThisRegionKind), ThisPointerTy(thisPointerTy) {}
+ : TypedValueRegion(sReg, CXXThisRegionKind), ThisPointerTy(thisPointerTy) {}
static void ProfileRegion(llvm::FoldingSetNodeID &ID,
const PointerType *PT,
@@ -707,7 +717,7 @@ public:
return QualType(ThisPointerTy, 0);
}
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
static bool classof(const MemRegion* R) {
return R->getKind() == CXXThisRegionKind;
@@ -720,14 +730,14 @@ private:
class FieldRegion : public DeclRegion {
friend class MemRegionManager;
- FieldRegion(const FieldDecl* fd, const MemRegion* sReg)
+ FieldRegion(const FieldDecl *fd, const MemRegion* sReg)
: DeclRegion(fd, sReg, FieldRegionKind) {}
public:
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
- const FieldDecl* getDecl() const { return cast<FieldDecl>(D); }
+ const FieldDecl *getDecl() const { return cast<FieldDecl>(D); }
QualType getValueType() const {
// FIXME: We can cache this if needed.
@@ -736,7 +746,7 @@ public:
DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const;
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl* FD,
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD,
const MemRegion* superRegion) {
DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind);
}
@@ -750,19 +760,19 @@ class ObjCIvarRegion : public DeclRegion {
friend class MemRegionManager;
- ObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* sReg)
+ ObjCIvarRegion(const ObjCIvarDecl *ivd, const MemRegion* sReg)
: DeclRegion(ivd, sReg, ObjCIvarRegionKind) {}
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl* ivd,
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl *ivd,
const MemRegion* superRegion) {
DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCIvarRegionKind);
}
public:
- const ObjCIvarDecl* getDecl() const { return cast<ObjCIvarDecl>(D); }
+ const ObjCIvarDecl *getDecl() const { return cast<ObjCIvarDecl>(D); }
QualType getValueType() const { return getDecl()->getType(); }
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
static bool classof(const MemRegion* R) {
return R->getKind() == ObjCIvarRegionKind;
@@ -789,18 +799,18 @@ public:
CharUnits getOffset() const { return Offset; }
const MemRegion *getRegion() const { return Region; }
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
void dump() const;
};
-class ElementRegion : public TypedRegion {
+class ElementRegion : public TypedValueRegion {
friend class MemRegionManager;
QualType ElementType;
NonLoc Index;
ElementRegion(QualType elementType, NonLoc Idx, const MemRegion* sReg)
- : TypedRegion(sReg, ElementRegionKind),
+ : TypedValueRegion(sReg, ElementRegionKind),
ElementType(elementType), Index(Idx) {
assert((!isa<nonloc::ConcreteInt>(&Idx) ||
cast<nonloc::ConcreteInt>(&Idx)->getValue().isSigned()) &&
@@ -824,7 +834,7 @@ public:
/// Compute the offset within the array. The array might also be a subobject.
RegionRawOffset getAsArrayOffset() const;
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
void Profile(llvm::FoldingSetNodeID& ID) const;
@@ -834,23 +844,25 @@ public:
};
// C++ temporary object associated with an expression.
-class CXXTempObjectRegion : public TypedRegion {
+class CXXTempObjectRegion : public TypedValueRegion {
friend class MemRegionManager;
Expr const *Ex;
CXXTempObjectRegion(Expr const *E, MemRegion const *sReg)
- : TypedRegion(sReg, CXXTempObjectRegionKind), Ex(E) {}
+ : TypedValueRegion(sReg, CXXTempObjectRegionKind), Ex(E) {}
static void ProfileRegion(llvm::FoldingSetNodeID &ID,
Expr const *E, const MemRegion *sReg);
public:
+ const Expr *getExpr() const { return Ex; }
+
QualType getValueType() const {
return Ex->getType();
}
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
void Profile(llvm::FoldingSetNodeID &ID) const;
@@ -861,13 +873,13 @@ public:
// CXXBaseObjectRegion represents a base object within a C++ object. It is
// identified by the base class declaration and the region of its parent object.
-class CXXBaseObjectRegion : public TypedRegion {
+class CXXBaseObjectRegion : public TypedValueRegion {
friend class MemRegionManager;
const CXXRecordDecl *decl;
CXXBaseObjectRegion(const CXXRecordDecl *d, const MemRegion *sReg)
- : TypedRegion(sReg, CXXBaseObjectRegionKind), decl(d) {}
+ : TypedValueRegion(sReg, CXXBaseObjectRegionKind), decl(d) {}
static void ProfileRegion(llvm::FoldingSetNodeID &ID,
const CXXRecordDecl *decl, const MemRegion *sReg);
@@ -877,7 +889,7 @@ public:
QualType getValueType() const;
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
void Profile(llvm::FoldingSetNodeID &ID) const;
@@ -951,13 +963,13 @@ public:
const MemSpaceRegion *getCodeRegion();
/// getAllocaRegion - Retrieve a region associated with a call to alloca().
- const AllocaRegion *getAllocaRegion(const Expr* Ex, unsigned Cnt,
+ const AllocaRegion *getAllocaRegion(const Expr *Ex, unsigned Cnt,
const LocationContext *LC);
/// getCompoundLiteralRegion - Retrieve the region associated with a
/// given CompoundLiteral.
const CompoundLiteralRegion*
- getCompoundLiteralRegion(const CompoundLiteralExpr* CL,
+ getCompoundLiteralRegion(const CompoundLiteralExpr *CL,
const LocationContext *LC);
/// getCXXThisRegion - Retrieve the [artificial] region associated with the
@@ -994,7 +1006,7 @@ public:
/// a specified FieldDecl. 'superRegion' corresponds to the containing
/// memory region (which typically represents the memory representing
/// a structure or class).
- const FieldRegion *getFieldRegion(const FieldDecl* fd,
+ const FieldRegion *getFieldRegion(const FieldDecl *fd,
const MemRegion* superRegion);
const FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR,
@@ -1006,7 +1018,7 @@ public:
/// a specified Objective-c instance variable. 'superRegion' corresponds
/// to the containing region (which typically represents the Objective-C
/// object).
- const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl* ivd,
+ const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl *ivd,
const MemRegion* superRegion);
const CXXTempObjectRegion *getCXXTempObjectRegion(Expr const *Ex,
@@ -1069,7 +1081,7 @@ private:
// Out-of-line member definitions.
//===----------------------------------------------------------------------===//
-inline ASTContext& MemRegion::getContext() const {
+inline ASTContext &MemRegion::getContext() const {
return getMemRegionManager()->getContext();
}
@@ -1082,7 +1094,7 @@ inline ASTContext& MemRegion::getContext() const {
//===----------------------------------------------------------------------===//
namespace llvm {
-static inline raw_ostream& operator<<(raw_ostream& os,
+static inline raw_ostream &operator<<(raw_ostream &os,
const clang::ento::MemRegion* R) {
R->dumpToStream(os);
return os;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
index 734024c2cba4..add3479804bd 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
@@ -16,8 +16,10 @@
#define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/ExprCXX.h"
+#include "llvm/ADT/PointerUnion.h"
namespace clang {
namespace ento {
@@ -86,6 +88,21 @@ public:
return 0;
}
+ SVal getInstanceReceiverSVal(const ProgramState *State,
+ const LocationContext *LC) const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ if (!isInstanceMessage())
+ return UndefinedVal();
+ if (const Expr *Ex = getInstanceReceiver())
+ return State->getSValAsScalarOrLoc(Ex);
+
+ // An instance message with no expression means we are sending to super.
+ // In this case the object reference is the same as 'self'.
+ const ImplicitParamDecl *SelfDecl = LC->getSelfDecl();
+ assert(SelfDecl && "No message receiver Expr, but not in an ObjC method");
+ return State->getSVal(State->getRegion(SelfDecl, LC));
+ }
+
bool isInstanceMessage() const {
assert(isValid() && "This ObjCMessage is uninitialized!");
if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
@@ -96,7 +113,7 @@ public:
}
const ObjCMethodDecl *getMethodDecl() const;
-
+
const ObjCInterfaceDecl *getReceiverInterface() const;
SourceLocation getSuperLoc() const {
@@ -106,45 +123,63 @@ public:
return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getReceiverLocation();
}
- SourceRange getSourceRange() const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
+ const Expr *getMsgOrPropExpr() const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ return MsgOrPropE;
+ }
+
+ SourceRange getSourceRange() const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
return MsgOrPropE->getSourceRange();
}
- unsigned getNumArgs() const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getNumArgs();
- return isPropertySetter() ? 1 : 0;
- }
-
- SVal getArgSVal(unsigned i, const GRState *state) const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- assert(i < getNumArgs() && "Invalid index for argument");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return state->getSVal(msgE->getArg(i));
- assert(isPropertySetter());
- return SetterArgV;
- }
-
- QualType getArgType(unsigned i) const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- assert(i < getNumArgs() && "Invalid index for argument");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getArg(i)->getType();
- assert(isPropertySetter());
- return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getType();
- }
-
- const Expr *getArgExpr(unsigned i) const;
-
- SourceRange getArgSourceRange(unsigned i) const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- assert(i < getNumArgs() && "Invalid index for argument");
- if (const Expr *argE = getArgExpr(i))
- return argE->getSourceRange();
- return OriginE->getSourceRange();
- }
+ unsigned getNumArgs() const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+ return msgE->getNumArgs();
+ return isPropertySetter() ? 1 : 0;
+ }
+
+ SVal getArgSVal(unsigned i, const ProgramState *state) const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ assert(i < getNumArgs() && "Invalid index for argument");
+ if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+ return state->getSVal(msgE->getArg(i));
+ assert(isPropertySetter());
+ return SetterArgV;
+ }
+
+ QualType getArgType(unsigned i) const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ assert(i < getNumArgs() && "Invalid index for argument");
+ if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+ return msgE->getArg(i)->getType();
+ assert(isPropertySetter());
+ return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getType();
+ }
+
+ const Expr *getArgExpr(unsigned i) const;
+
+ SourceRange getArgSourceRange(unsigned i) const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ assert(i < getNumArgs() && "Invalid index for argument");
+ if (const Expr *argE = getArgExpr(i))
+ return argE->getSourceRange();
+ return OriginE->getSourceRange();
+ }
+
+ SourceRange getReceiverSourceRange() const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+ return msgE->getReceiverRange();
+
+ const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
+ if (propE->isObjectReceiver())
+ return propE->getBase()->getSourceRange();
+
+ // FIXME: This isn't a range.
+ return propE->getReceiverLocation();
+ }
};
class ObjCPropertyGetter : public ObjCMessage {
@@ -165,58 +200,89 @@ public:
}
};
-/// \brief Common wrapper for a call expression or an ObjC message, mainly to
-/// provide a common interface for handling their arguments.
+/// \brief Common wrapper for a call expression, ObjC message, or C++
+/// constructor, mainly to provide a common interface for their arguments.
class CallOrObjCMessage {
- const CallExpr *CallE;
+ llvm::PointerUnion<const CallExpr *, const CXXConstructExpr *> CallE;
ObjCMessage Msg;
- const GRState *State;
+ const ProgramState *State;
public:
- CallOrObjCMessage(const CallExpr *callE, const GRState *state)
+ CallOrObjCMessage(const CallExpr *callE, const ProgramState *state)
: CallE(callE), State(state) {}
- CallOrObjCMessage(const ObjCMessage &msg, const GRState *state)
- : CallE(0), Msg(msg), State(state) {}
+ CallOrObjCMessage(const CXXConstructExpr *consE, const ProgramState *state)
+ : CallE(consE), State(state) {}
+ CallOrObjCMessage(const ObjCMessage &msg, const ProgramState *state)
+ : CallE((CallExpr *)0), Msg(msg), State(state) {}
QualType getResultType(ASTContext &ctx) const;
bool isFunctionCall() const {
- return (bool) CallE;
+ return CallE && CallE.is<const CallExpr *>();
}
-
+
+ bool isCXXConstructExpr() const {
+ return CallE && CallE.is<const CXXConstructExpr *>();
+ }
+
+ bool isObjCMessage() const {
+ return !CallE;
+ }
+
bool isCXXCall() const {
- return CallE && isa<CXXMemberCallExpr>(CallE);
+ const CallExpr *ActualCallE = CallE.dyn_cast<const CallExpr *>();
+ return ActualCallE && isa<CXXMemberCallExpr>(ActualCallE);
+ }
+
+ const Expr *getOriginExpr() const {
+ if (!CallE)
+ return Msg.getOriginExpr();
+ if (const CXXConstructExpr *Ctor =
+ CallE.dyn_cast<const CXXConstructExpr *>())
+ return Ctor;
+ return CallE.get<const CallExpr *>();
}
SVal getFunctionCallee() const;
SVal getCXXCallee() const;
+ SVal getInstanceMessageReceiver(const LocationContext *LC) const;
unsigned getNumArgs() const {
- if (CallE) return CallE->getNumArgs();
- return Msg.getNumArgs();
+ if (!CallE)
+ return Msg.getNumArgs();
+ if (const CXXConstructExpr *Ctor =
+ CallE.dyn_cast<const CXXConstructExpr *>())
+ return Ctor->getNumArgs();
+ return CallE.get<const CallExpr *>()->getNumArgs();
}
SVal getArgSVal(unsigned i) const {
assert(i < getNumArgs());
- if (CallE)
- return State->getSVal(CallE->getArg(i));
- return Msg.getArgSVal(i, State);
+ if (!CallE)
+ return Msg.getArgSVal(i, State);
+ return State->getSVal(getArg(i));
}
- SVal getArgSValAsScalarOrLoc(unsigned i) const;
-
const Expr *getArg(unsigned i) const {
assert(i < getNumArgs());
- if (CallE)
- return CallE->getArg(i);
- return Msg.getArgExpr(i);
+ if (!CallE)
+ return Msg.getArgExpr(i);
+ if (const CXXConstructExpr *Ctor =
+ CallE.dyn_cast<const CXXConstructExpr *>())
+ return Ctor->getArg(i);
+ return CallE.get<const CallExpr *>()->getArg(i);
}
SourceRange getArgSourceRange(unsigned i) const {
assert(i < getNumArgs());
if (CallE)
- return CallE->getArg(i)->getSourceRange();
+ return getArg(i)->getSourceRange();
return Msg.getArgSourceRange(i);
}
+
+ SourceRange getReceiverSourceRange() const {
+ assert(isObjCMessage());
+ return Msg.getReceiverSourceRange();
+ }
};
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index 0d61d0e620eb..edae06e68c34 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -1,4 +1,4 @@
-//== GRState.h - Path-sensitive "State" for tracking values -----*- C++ -*--==//
+//== ProgramState.h - Path-sensitive "State" for tracking values -*- C++ -*--=//
//
// The LLVM Compiler Infrastructure
//
@@ -7,13 +7,14 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines SymbolRef, ExprBindKey, and GRState*.
+// This file defines SymbolRef, ExprBindKey, and ProgramState*.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_VALUESTATE_H
#define LLVM_CLANG_GR_VALUESTATE_H
+#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/Environment.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
@@ -21,12 +22,10 @@
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
-#include "llvm/Support/Casting.h"
namespace llvm {
class APSInt;
class BumpPtrAllocator;
-class raw_ostream;
}
namespace clang {
@@ -34,30 +33,31 @@ class ASTContext;
namespace ento {
-class GRStateManager;
+class ProgramStateManager;
-typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&,
+typedef ConstraintManager* (*ConstraintManagerCreator)(ProgramStateManager&,
SubEngine&);
-typedef StoreManager* (*StoreManagerCreator)(GRStateManager&);
+typedef StoreManager* (*StoreManagerCreator)(ProgramStateManager&);
//===----------------------------------------------------------------------===//
-// GRStateTrait - Traits used by the Generic Data Map of a GRState.
+// ProgramStateTrait - Traits used by the Generic Data Map of a ProgramState.
//===----------------------------------------------------------------------===//
-template <typename T> struct GRStatePartialTrait;
+template <typename T> struct ProgramStatePartialTrait;
-template <typename T> struct GRStateTrait {
+template <typename T> struct ProgramStateTrait {
typedef typename T::data_type data_type;
- static inline void* GDMIndex() { return &T::TagInt; }
- static inline void* MakeVoidPtr(data_type D) { return (void*) D; }
- static inline data_type MakeData(void* const* P) {
+ static inline void *GDMIndex() { return &T::TagInt; }
+ static inline void *MakeVoidPtr(data_type D) { return (void*) D; }
+ static inline data_type MakeData(void *const* P) {
return P ? (data_type) *P : (data_type) 0;
}
};
-class GRStateManager;
+class ProgramStateManager;
-/// GRState - This class encapsulates:
+/// \class ProgramState
+/// ProgramState - This class encapsulates:
///
/// 1. A mapping from expressions to values (Environment)
/// 2. A mapping from locations to values (Store)
@@ -65,47 +65,47 @@ class GRStateManager;
///
/// Together these represent the "abstract state" of a program.
///
-/// GRState is intended to be used as a functional object; that is,
+/// ProgramState is intended to be used as a functional object; that is,
/// once it is created and made "persistent" in a FoldingSet, its
/// values will never change.
-class GRState : public llvm::FoldingSetNode {
+class ProgramState : public llvm::FoldingSetNode {
public:
typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy;
typedef llvm::ImmutableMap<void*, void*> GenericDataMap;
private:
- void operator=(const GRState& R) const; // Do not implement.
+ void operator=(const ProgramState& R) const; // Do not implement.
- friend class GRStateManager;
+ friend class ProgramStateManager;
friend class ExplodedGraph;
friend class ExplodedNode;
- GRStateManager *stateMgr;
+ ProgramStateManager *stateMgr;
Environment Env; // Maps a Stmt to its current SVal.
Store store; // Maps a location to its current value.
GenericDataMap GDM; // Custom data stored by a client of this class.
unsigned refCount;
- /// makeWithStore - Return a GRState with the same values as the current
+ /// makeWithStore - Return a ProgramState with the same values as the current
/// state with the exception of using the specified Store.
- const GRState *makeWithStore(const StoreRef &store) const;
+ const ProgramState *makeWithStore(const StoreRef &store) const;
void setStore(const StoreRef &storeRef);
public:
- /// This ctor is used when creating the first GRState object.
- GRState(GRStateManager *mgr, const Environment& env,
+ /// This ctor is used when creating the first ProgramState object.
+ ProgramState(ProgramStateManager *mgr, const Environment& env,
StoreRef st, GenericDataMap gdm);
/// Copy ctor - We must explicitly define this or else the "Next" ptr
/// in FoldingSetNode will also get copied.
- GRState(const GRState& RHS);
+ ProgramState(const ProgramState &RHS);
- ~GRState();
+ ~ProgramState();
- /// Return the GRStateManager associated with this state.
- GRStateManager &getStateManager() const { return *stateMgr; }
+ /// Return the ProgramStateManager associated with this state.
+ ProgramStateManager &getStateManager() const { return *stateMgr; }
/// Return true if this state is referenced by a persistent ExplodedNode.
bool referencedByExplodedNode() const { return refCount > 0; }
@@ -124,10 +124,10 @@ public:
void setGDM(GenericDataMap gdm) { GDM = gdm; }
- /// Profile - Profile the contents of a GRState object for use in a
- /// FoldingSet. Two GRState objects are considered equal if they
+ /// Profile - Profile the contents of a ProgramState object for use in a
+ /// FoldingSet. Two ProgramState objects are considered equal if they
/// have the same Environment, Store, and GenericDataMap.
- static void Profile(llvm::FoldingSetNodeID& ID, const GRState* V) {
+ static void Profile(llvm::FoldingSetNodeID& ID, const ProgramState *V) {
V->Env.Profile(ID);
ID.AddPointer(V->store);
V->GDM.Profile(ID);
@@ -146,44 +146,41 @@ public:
// Constraints on values.
//==---------------------------------------------------------------------==//
//
- // Each GRState records constraints on symbolic values. These constraints
- // are managed using the ConstraintManager associated with a GRStateManager.
+ // Each ProgramState records constraints on symbolic values. These constraints
+ // are managed using the ConstraintManager associated with a ProgramStateManager.
// As constraints gradually accrue on symbolic values, added constraints
// may conflict and indicate that a state is infeasible (as no real values
// could satisfy all the constraints). This is the principal mechanism
- // for modeling path-sensitivity in ExprEngine/GRState.
+ // for modeling path-sensitivity in ExprEngine/ProgramState.
//
// Various "assume" methods form the interface for adding constraints to
// symbolic values. A call to 'assume' indicates an assumption being placed
// on one or symbolic values. 'assume' methods take the following inputs:
//
- // (1) A GRState object representing the current state.
+ // (1) A ProgramState object representing the current state.
//
// (2) The assumed constraint (which is specific to a given "assume" method).
//
// (3) A binary value "Assumption" that indicates whether the constraint is
// assumed to be true or false.
//
- // The output of "assume*" is a new GRState object with the added constraints.
+ // The output of "assume*" is a new ProgramState object with the added constraints.
// If no new state is feasible, NULL is returned.
//
- const GRState *assume(DefinedOrUnknownSVal cond, bool assumption) const;
+ const ProgramState *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<const GRState*, const GRState*>
+ std::pair<const ProgramState*, const ProgramState*>
assume(DefinedOrUnknownSVal cond) const;
- const GRState *assumeInBound(DefinedOrUnknownSVal idx,
+ const ProgramState *assumeInBound(DefinedOrUnknownSVal idx,
DefinedOrUnknownSVal upperBound,
bool assumption) const;
- //==---------------------------------------------------------------------==//
- // Utility methods for getting regions.
- //==---------------------------------------------------------------------==//
-
+ /// Utility method for getting regions.
const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const;
//==---------------------------------------------------------------------==//
@@ -192,52 +189,42 @@ public:
/// BindCompoundLiteral - Return the state that has the bindings currently
/// in this state plus the bindings for the CompoundLiteral.
- const GRState *bindCompoundLiteral(const CompoundLiteralExpr* CL,
+ const ProgramState *bindCompoundLiteral(const CompoundLiteralExpr *CL,
const LocationContext *LC,
SVal V) const;
/// Create a new state by binding the value 'V' to the statement 'S' in the
/// state's environment.
- const GRState *BindExpr(const Stmt *S, SVal V, bool Invalidate = true) const;
+ const ProgramState *BindExpr(const Stmt *S, 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.
- const GRState *bindExprAndLocation(const Stmt *S, SVal location, SVal V)
+ const ProgramState *bindExprAndLocation(const Stmt *S, SVal location, SVal V)
const;
- const GRState *bindDecl(const VarRegion *VR, SVal V) const;
+ const ProgramState *bindDecl(const VarRegion *VR, SVal V) const;
- const GRState *bindDeclWithNoInit(const VarRegion *VR) const;
+ const ProgramState *bindDeclWithNoInit(const VarRegion *VR) const;
- const GRState *bindLoc(Loc location, SVal V) const;
+ const ProgramState *bindLoc(Loc location, SVal V) const;
- const GRState *bindLoc(SVal location, SVal V) const;
+ const ProgramState *bindLoc(SVal location, SVal V) const;
- const GRState *bindDefault(SVal loc, SVal V) const;
+ const ProgramState *bindDefault(SVal loc, SVal V) const;
- const GRState *unbindLoc(Loc LV) const;
-
- /// invalidateRegion - Returns the state with bindings for the given region
- /// cleared from the store. See invalidateRegions.
- const GRState *invalidateRegion(const MemRegion *R,
- const Expr *E, unsigned BlockCount,
- StoreManager::InvalidatedSymbols *IS = NULL)
- const {
- return invalidateRegions(&R, &R+1, E, BlockCount, IS, false);
- }
+ const ProgramState *unbindLoc(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.
- const GRState *invalidateRegions(const MemRegion * const *Begin,
- const MemRegion * const *End,
+ const ProgramState *invalidateRegions(ArrayRef<const MemRegion *> Regions,
const Expr *E, unsigned BlockCount,
- StoreManager::InvalidatedSymbols *IS,
- bool invalidateGlobals) const;
+ StoreManager::InvalidatedSymbols *IS = 0,
+ bool invalidateGlobals = false) const;
/// enterStackFrame - Returns the state for entry to the given stack frame,
/// preserving the current state.
- const GRState *enterStackFrame(const StackFrameContext *frame) const;
+ const ProgramState *enterStackFrame(const StackFrameContext *frame) const;
/// Get the lvalue for a variable reference.
Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
@@ -260,7 +247,7 @@ public:
const llvm::APSInt *getSymVal(SymbolRef sym) const;
/// Returns the SVal bound to the statement 'S' in the state's environment.
- SVal getSVal(const Stmt* S, bool useOnlyDirectBindings = false) const;
+ SVal getSVal(const Stmt *S, bool useOnlyDirectBindings = false) const;
SVal getSValAsScalarOrLoc(const Stmt *Ex) const;
@@ -273,11 +260,22 @@ public:
SVal getSValAsScalarOrLoc(const MemRegion *R) const;
+ /// \brief Visits the symbols reachable from the given SVal using the provided
+ /// SymbolVisitor.
+ ///
+ /// This is a convenience API. Consider using ScanReachableSymbols class
+ /// directly when making multiple scans on the same state with the same
+ /// visitor to avoid repeated initialization cost.
+ /// \sa ScanReachableSymbols
bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const;
+ /// \brief Visits the symbols reachable from the SVals in the given range
+ /// using the provided SymbolVisitor.
bool scanReachableSymbols(const SVal *I, const SVal *E,
SymbolVisitor &visitor) const;
+ /// \brief Visits the symbols reachable from the regions in the given
+ /// MemRegions range using the provided SymbolVisitor.
bool scanReachableSymbols(const MemRegion * const *I,
const MemRegion * const *E,
SymbolVisitor &visitor) const;
@@ -294,70 +292,62 @@ public:
// Accessing the Generic Data Map (GDM).
//==---------------------------------------------------------------------==//
- void* const* FindGDM(void* K) const;
+ void *const* FindGDM(void *K) const;
template<typename T>
- const GRState *add(typename GRStateTrait<T>::key_type K) const;
+ const ProgramState *add(typename ProgramStateTrait<T>::key_type K) const;
template <typename T>
- typename GRStateTrait<T>::data_type
+ typename ProgramStateTrait<T>::data_type
get() const {
- return GRStateTrait<T>::MakeData(FindGDM(GRStateTrait<T>::GDMIndex()));
+ return ProgramStateTrait<T>::MakeData(FindGDM(ProgramStateTrait<T>::GDMIndex()));
}
template<typename T>
- typename GRStateTrait<T>::lookup_type
- get(typename GRStateTrait<T>::key_type key) const {
- void* const* d = FindGDM(GRStateTrait<T>::GDMIndex());
- return GRStateTrait<T>::Lookup(GRStateTrait<T>::MakeData(d), key);
+ typename ProgramStateTrait<T>::lookup_type
+ get(typename ProgramStateTrait<T>::key_type key) const {
+ void *const* d = FindGDM(ProgramStateTrait<T>::GDMIndex());
+ return ProgramStateTrait<T>::Lookup(ProgramStateTrait<T>::MakeData(d), key);
}
template <typename T>
- typename GRStateTrait<T>::context_type get_context() const;
+ typename ProgramStateTrait<T>::context_type get_context() const;
template<typename T>
- const GRState *remove(typename GRStateTrait<T>::key_type K) const;
+ const ProgramState *remove(typename ProgramStateTrait<T>::key_type K) const;
template<typename T>
- const GRState *remove(typename GRStateTrait<T>::key_type K,
- typename GRStateTrait<T>::context_type C) const;
+ const ProgramState *remove(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::context_type C) const;
template <typename T>
- const GRState *remove() const;
+ const ProgramState *remove() const;
template<typename T>
- const GRState *set(typename GRStateTrait<T>::data_type D) const;
+ const ProgramState *set(typename ProgramStateTrait<T>::data_type D) const;
template<typename T>
- const GRState *set(typename GRStateTrait<T>::key_type K,
- typename GRStateTrait<T>::value_type E) const;
+ const ProgramState *set(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::value_type E) const;
template<typename T>
- const GRState *set(typename GRStateTrait<T>::key_type K,
- typename GRStateTrait<T>::value_type E,
- typename GRStateTrait<T>::context_type C) const;
+ const ProgramState *set(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::value_type E,
+ typename ProgramStateTrait<T>::context_type C) const;
template<typename T>
- bool contains(typename GRStateTrait<T>::key_type key) const {
- void* const* d = FindGDM(GRStateTrait<T>::GDMIndex());
- return GRStateTrait<T>::Contains(GRStateTrait<T>::MakeData(d), key);
+ bool contains(typename ProgramStateTrait<T>::key_type key) const {
+ void *const* d = FindGDM(ProgramStateTrait<T>::GDMIndex());
+ return ProgramStateTrait<T>::Contains(ProgramStateTrait<T>::MakeData(d), key);
}
- // State pretty-printing.
- class Printer {
- public:
- virtual ~Printer() {}
- virtual void Print(llvm::raw_ostream& Out, const GRState* state,
- const char* nl, const char* sep) = 0;
- };
-
// Pretty-printing.
- void print(llvm::raw_ostream& Out, CFG &C, const char *nl = "\n",
+ void print(raw_ostream &Out, CFG &C, const char *nl = "\n",
const char *sep = "") const;
void printStdErr(CFG &C) const;
- void printDOT(llvm::raw_ostream& Out, CFG &C) const;
+ void printDOT(raw_ostream &Out, CFG &C) const;
private:
/// Increments the number of times this state is referenced by ExplodeNodes.
@@ -369,20 +359,20 @@ private:
--refCount;
}
- const GRState *invalidateRegionsImpl(const MemRegion * const *Begin,
- const MemRegion * const *End,
- const Expr *E, unsigned BlockCount,
- StoreManager::InvalidatedSymbols &IS,
- bool invalidateGlobals) const;
+ const ProgramState *
+ invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions,
+ const Expr *E, unsigned BlockCount,
+ StoreManager::InvalidatedSymbols &IS,
+ bool invalidateGlobals) const;
};
-class GRStateSet {
- typedef llvm::SmallPtrSet<const GRState*,5> ImplTy;
+class ProgramStateSet {
+ typedef llvm::SmallPtrSet<const ProgramState*,5> ImplTy;
ImplTy Impl;
public:
- GRStateSet() {}
+ ProgramStateSet() {}
- inline void Add(const GRState* St) {
+ inline void Add(const ProgramState *St) {
Impl.insert(St);
}
@@ -395,11 +385,11 @@ public:
inline iterator end() const { return Impl.end(); }
class AutoPopulate {
- GRStateSet& S;
+ ProgramStateSet &S;
unsigned StartSize;
- const GRState* St;
+ const ProgramState *St;
public:
- AutoPopulate(GRStateSet& s, const GRState* st)
+ AutoPopulate(ProgramStateSet &s, const ProgramState *st)
: S(s), StartSize(S.size()), St(st) {}
~AutoPopulate() {
@@ -410,12 +400,11 @@ public:
};
//===----------------------------------------------------------------------===//
-// GRStateManager - Factory object for GRStates.
+// ProgramStateManager - Factory object for ProgramStates.
//===----------------------------------------------------------------------===//
-class GRStateManager {
- friend class GRState;
- friend class ExprEngine; // FIXME: Remove.
+class ProgramStateManager {
+ friend class ProgramState;
private:
/// Eng - The SubEngine that owns this state manager.
SubEngine *Eng; /* Can be null. */
@@ -424,18 +413,14 @@ private:
llvm::OwningPtr<StoreManager> StoreMgr;
llvm::OwningPtr<ConstraintManager> ConstraintMgr;
- GRState::GenericDataMap::Factory GDMFactory;
+ ProgramState::GenericDataMap::Factory GDMFactory;
typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy;
GDMContextsTy GDMContexts;
- /// Printers - A set of printer objects used for pretty-printing a GRState.
- /// GRStateManager owns these objects.
- std::vector<GRState::Printer*> Printers;
-
/// StateSet - FoldingSet containing all the states created for analyzing
/// a particular function. This is used to unique states.
- llvm::FoldingSet<GRState> StateSet;
+ llvm::FoldingSet<ProgramState> StateSet;
/// Object that manages the data for all created SVals.
llvm::OwningPtr<SValBuilder> svalBuilder;
@@ -443,15 +428,15 @@ private:
/// A BumpPtrAllocator to allocate states.
llvm::BumpPtrAllocator &Alloc;
- /// A vector of recently allocated GRStates that can potentially be
+ /// A vector of recently allocated ProgramStates that can potentially be
/// reused.
- std::vector<GRState *> recentlyAllocatedStates;
+ std::vector<ProgramState *> recentlyAllocatedStates;
- /// A vector of GRStates that we can reuse.
- std::vector<GRState *> freeStates;
+ /// A vector of ProgramStates that we can reuse.
+ std::vector<ProgramState *> freeStates;
public:
- GRStateManager(ASTContext& Ctx,
+ ProgramStateManager(ASTContext &Ctx,
StoreManagerCreator CreateStoreManager,
ConstraintManagerCreator CreateConstraintManager,
llvm::BumpPtrAllocator& alloc,
@@ -465,7 +450,7 @@ public:
ConstraintMgr.reset((*CreateConstraintManager)(*this, subeng));
}
- GRStateManager(ASTContext& Ctx,
+ ProgramStateManager(ASTContext &Ctx,
StoreManagerCreator CreateStoreManager,
ConstraintManager* ConstraintManagerPtr,
llvm::BumpPtrAllocator& alloc)
@@ -478,9 +463,9 @@ public:
ConstraintMgr.reset(ConstraintManagerPtr);
}
- ~GRStateManager();
+ ~ProgramStateManager();
- const GRState *getInitialState(const LocationContext *InitLoc);
+ const ProgramState *getInitialState(const LocationContext *InitLoc);
ASTContext &getContext() { return svalBuilder->getContext(); }
const ASTContext &getContext() const { return svalBuilder->getContext(); }
@@ -516,13 +501,13 @@ public:
ConstraintManager& getConstraintManager() { return *ConstraintMgr; }
SubEngine* getOwningEngine() { return Eng; }
- const GRState* removeDeadBindings(const GRState* St,
+ const ProgramState *removeDeadBindings(const ProgramState *St,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper);
/// Marshal a new state for the callee in another translation unit.
/// 'state' is owned by the caller's engine.
- const GRState *MarshalState(const GRState *state, const StackFrameContext *L);
+ const ProgramState *MarshalState(const ProgramState *state, const StackFrameContext *L);
public:
@@ -531,18 +516,28 @@ public:
}
// Methods that manipulate the GDM.
- const GRState* addGDM(const GRState* St, void* Key, void* Data);
- const GRState *removeGDM(const GRState *state, void *Key);
+ const ProgramState *addGDM(const ProgramState *St, void *Key, void *Data);
+ const ProgramState *removeGDM(const ProgramState *state, void *Key);
// Methods that query & manipulate the Store.
- void iterBindings(const GRState* state, StoreManager::BindingsHandler& F) {
+ void iterBindings(const ProgramState *state, StoreManager::BindingsHandler& F) {
StoreMgr->iterBindings(state->getStore(), F);
}
- const GRState* getPersistentState(GRState& Impl);
-
- /// Periodically called by ExprEngine to recycle GRStates that were
+ const ProgramState *getPersistentState(ProgramState &Impl);
+ const ProgramState *getPersistentStateWithGDM(const ProgramState *FromState,
+ const ProgramState *GDMState);
+
+ bool haveEqualEnvironments(const ProgramState * S1, const ProgramState * S2) {
+ return S1->Env == S2->Env;
+ }
+
+ bool haveEqualStores(const ProgramState * S1, const ProgramState * S2) {
+ return S1->store == S2->store;
+ }
+
+ /// Periodically called by ExprEngine to recycle ProgramStates that were
/// created but never used for creating an ExplodedNode.
void recycleUnusedStates();
@@ -550,9 +545,9 @@ public:
// Generic Data Map methods.
//==---------------------------------------------------------------------==//
//
- // GRStateManager and GRState support a "generic data map" that allows
- // different clients of GRState objects to embed arbitrary data within a
- // GRState object. The generic data map is essentially an immutable map
+ // ProgramStateManager and ProgramState support a "generic data map" that allows
+ // different clients of ProgramState objects to embed arbitrary data within a
+ // ProgramState object. The generic data map is essentially an immutable map
// from a "tag" (that acts as the "key" for a client) and opaque values.
// Tags/keys and values are simply void* values. The typical way that clients
// generate unique tags are by taking the address of a static variable.
@@ -560,82 +555,82 @@ public:
// the data pointer are immutable (and thus are essentially purely functional
// data).
//
- // The templated methods below use the GRStateTrait<T> class
+ // The templated methods below use the ProgramStateTrait<T> class
// to resolve keys into the GDM and to return data values to clients.
//
// Trait based GDM dispatch.
template <typename T>
- const GRState* set(const GRState* st, typename GRStateTrait<T>::data_type D) {
- return addGDM(st, GRStateTrait<T>::GDMIndex(),
- GRStateTrait<T>::MakeVoidPtr(D));
+ const ProgramState *set(const ProgramState *st, typename ProgramStateTrait<T>::data_type D) {
+ return addGDM(st, ProgramStateTrait<T>::GDMIndex(),
+ ProgramStateTrait<T>::MakeVoidPtr(D));
}
template<typename T>
- const GRState* set(const GRState* st,
- typename GRStateTrait<T>::key_type K,
- typename GRStateTrait<T>::value_type V,
- typename GRStateTrait<T>::context_type C) {
+ const ProgramState *set(const ProgramState *st,
+ typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::value_type V,
+ typename ProgramStateTrait<T>::context_type C) {
- return addGDM(st, GRStateTrait<T>::GDMIndex(),
- GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Set(st->get<T>(), K, V, C)));
+ return addGDM(st, ProgramStateTrait<T>::GDMIndex(),
+ ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Set(st->get<T>(), K, V, C)));
}
template <typename T>
- const GRState* add(const GRState* st,
- typename GRStateTrait<T>::key_type K,
- typename GRStateTrait<T>::context_type C) {
- return addGDM(st, GRStateTrait<T>::GDMIndex(),
- GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Add(st->get<T>(), K, C)));
+ const ProgramState *add(const ProgramState *st,
+ typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::context_type C) {
+ return addGDM(st, ProgramStateTrait<T>::GDMIndex(),
+ ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Add(st->get<T>(), K, C)));
}
template <typename T>
- const GRState* remove(const GRState* st,
- typename GRStateTrait<T>::key_type K,
- typename GRStateTrait<T>::context_type C) {
+ const ProgramState *remove(const ProgramState *st,
+ typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::context_type C) {
- return addGDM(st, GRStateTrait<T>::GDMIndex(),
- GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Remove(st->get<T>(), K, C)));
+ return addGDM(st, ProgramStateTrait<T>::GDMIndex(),
+ ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Remove(st->get<T>(), K, C)));
}
template <typename T>
- const GRState *remove(const GRState *st) {
- return removeGDM(st, GRStateTrait<T>::GDMIndex());
+ const ProgramState *remove(const ProgramState *st) {
+ return removeGDM(st, ProgramStateTrait<T>::GDMIndex());
}
- void* FindGDMContext(void* index,
- void* (*CreateContext)(llvm::BumpPtrAllocator&),
+ void *FindGDMContext(void *index,
+ void *(*CreateContext)(llvm::BumpPtrAllocator&),
void (*DeleteContext)(void*));
template <typename T>
- typename GRStateTrait<T>::context_type get_context() {
- void* p = FindGDMContext(GRStateTrait<T>::GDMIndex(),
- GRStateTrait<T>::CreateContext,
- GRStateTrait<T>::DeleteContext);
+ typename ProgramStateTrait<T>::context_type get_context() {
+ void *p = FindGDMContext(ProgramStateTrait<T>::GDMIndex(),
+ ProgramStateTrait<T>::CreateContext,
+ ProgramStateTrait<T>::DeleteContext);
- return GRStateTrait<T>::MakeContext(p);
+ return ProgramStateTrait<T>::MakeContext(p);
}
- const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) {
+ const llvm::APSInt* getSymVal(const ProgramState *St, SymbolRef sym) {
return ConstraintMgr->getSymVal(St, sym);
}
- void EndPath(const GRState* St) {
+ void EndPath(const ProgramState *St) {
ConstraintMgr->EndPath(St);
}
};
//===----------------------------------------------------------------------===//
-// Out-of-line method definitions for GRState.
+// Out-of-line method definitions for ProgramState.
//===----------------------------------------------------------------------===//
-inline const VarRegion* GRState::getRegion(const VarDecl *D,
+inline const VarRegion* ProgramState::getRegion(const VarDecl *D,
const LocationContext *LC) const {
return getStateManager().getRegionManager().getVarRegion(D, LC);
}
-inline const GRState *GRState::assume(DefinedOrUnknownSVal Cond,
+inline const ProgramState *ProgramState::assume(DefinedOrUnknownSVal Cond,
bool Assumption) const {
if (Cond.isUnknown())
return this;
@@ -644,8 +639,8 @@ inline const GRState *GRState::assume(DefinedOrUnknownSVal Cond,
Assumption);
}
-inline std::pair<const GRState*, const GRState*>
-GRState::assume(DefinedOrUnknownSVal Cond) const {
+inline std::pair<const ProgramState*, const ProgramState*>
+ProgramState::assume(DefinedOrUnknownSVal Cond) const {
if (Cond.isUnknown())
return std::make_pair(this, this);
@@ -653,48 +648,48 @@ GRState::assume(DefinedOrUnknownSVal Cond) const {
cast<DefinedSVal>(Cond));
}
-inline const GRState *GRState::bindLoc(SVal LV, SVal V) const {
+inline const ProgramState *ProgramState::bindLoc(SVal LV, SVal V) const {
return !isa<Loc>(LV) ? this : bindLoc(cast<Loc>(LV), V);
}
-inline Loc GRState::getLValue(const VarDecl* VD,
+inline Loc ProgramState::getLValue(const VarDecl *VD,
const LocationContext *LC) const {
return getStateManager().StoreMgr->getLValueVar(VD, LC);
}
-inline Loc GRState::getLValue(const StringLiteral *literal) const {
+inline Loc ProgramState::getLValue(const StringLiteral *literal) const {
return getStateManager().StoreMgr->getLValueString(literal);
}
-inline Loc GRState::getLValue(const CompoundLiteralExpr *literal,
+inline Loc ProgramState::getLValue(const CompoundLiteralExpr *literal,
const LocationContext *LC) const {
return getStateManager().StoreMgr->getLValueCompoundLiteral(literal, LC);
}
-inline SVal GRState::getLValue(const ObjCIvarDecl *D, SVal Base) const {
+inline SVal ProgramState::getLValue(const ObjCIvarDecl *D, SVal Base) const {
return getStateManager().StoreMgr->getLValueIvar(D, Base);
}
-inline SVal GRState::getLValue(const FieldDecl* D, SVal Base) const {
+inline SVal ProgramState::getLValue(const FieldDecl *D, SVal Base) const {
return getStateManager().StoreMgr->getLValueField(D, Base);
}
-inline SVal GRState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{
+inline SVal ProgramState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{
if (NonLoc *N = dyn_cast<NonLoc>(&Idx))
return getStateManager().StoreMgr->getLValueElement(ElementType, *N, Base);
return UnknownVal();
}
-inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) const {
+inline const llvm::APSInt *ProgramState::getSymVal(SymbolRef sym) const {
return getStateManager().getSymVal(this, sym);
}
-inline SVal GRState::getSVal(const Stmt* Ex, bool useOnlyDirectBindings) const{
+inline SVal ProgramState::getSVal(const Stmt *Ex, bool useOnlyDirectBindings) const{
return Env.getSVal(Ex, *getStateManager().svalBuilder,
- useOnlyDirectBindings);
+ useOnlyDirectBindings);
}
-inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const {
+inline SVal ProgramState::getSValAsScalarOrLoc(const Stmt *S) const {
if (const Expr *Ex = dyn_cast<Expr>(S)) {
QualType T = Ex->getType();
if (Ex->isLValue() || Loc::isLocType(T) || T->isIntegerType())
@@ -704,88 +699,114 @@ inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const {
return UnknownVal();
}
-inline SVal GRState::getRawSVal(Loc LV, QualType T) const {
+inline SVal ProgramState::getRawSVal(Loc LV, QualType T) const {
return getStateManager().StoreMgr->Retrieve(getStore(), LV, T);
}
-inline SVal GRState::getSVal(const MemRegion* R) const {
+inline SVal ProgramState::getSVal(const MemRegion* R) const {
return getStateManager().StoreMgr->Retrieve(getStore(), loc::MemRegionVal(R));
}
-inline BasicValueFactory &GRState::getBasicVals() const {
+inline BasicValueFactory &ProgramState::getBasicVals() const {
return getStateManager().getBasicVals();
}
-inline SymbolManager &GRState::getSymbolManager() const {
+inline SymbolManager &ProgramState::getSymbolManager() const {
return getStateManager().getSymbolManager();
}
template<typename T>
-const GRState *GRState::add(typename GRStateTrait<T>::key_type K) const {
+const ProgramState *ProgramState::add(typename ProgramStateTrait<T>::key_type K) const {
return getStateManager().add<T>(this, K, get_context<T>());
}
template <typename T>
-typename GRStateTrait<T>::context_type GRState::get_context() const {
+typename ProgramStateTrait<T>::context_type ProgramState::get_context() const {
return getStateManager().get_context<T>();
}
template<typename T>
-const GRState *GRState::remove(typename GRStateTrait<T>::key_type K) const {
+const ProgramState *ProgramState::remove(typename ProgramStateTrait<T>::key_type K) const {
return getStateManager().remove<T>(this, K, get_context<T>());
}
template<typename T>
-const GRState *GRState::remove(typename GRStateTrait<T>::key_type K,
- typename GRStateTrait<T>::context_type C) const {
+const ProgramState *ProgramState::remove(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::context_type C) const {
return getStateManager().remove<T>(this, K, C);
}
template <typename T>
-const GRState *GRState::remove() const {
+const ProgramState *ProgramState::remove() const {
return getStateManager().remove<T>(this);
}
template<typename T>
-const GRState *GRState::set(typename GRStateTrait<T>::data_type D) const {
+const ProgramState *ProgramState::set(typename ProgramStateTrait<T>::data_type D) const {
return getStateManager().set<T>(this, D);
}
template<typename T>
-const GRState *GRState::set(typename GRStateTrait<T>::key_type K,
- typename GRStateTrait<T>::value_type E) const {
+const ProgramState *ProgramState::set(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::value_type E) const {
return getStateManager().set<T>(this, K, E, get_context<T>());
}
template<typename T>
-const GRState *GRState::set(typename GRStateTrait<T>::key_type K,
- typename GRStateTrait<T>::value_type E,
- typename GRStateTrait<T>::context_type C) const {
+const ProgramState *ProgramState::set(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::value_type E,
+ typename ProgramStateTrait<T>::context_type C) const {
return getStateManager().set<T>(this, K, E, C);
}
template <typename CB>
-CB GRState::scanReachableSymbols(SVal val) const {
+CB ProgramState::scanReachableSymbols(SVal val) const {
CB cb(this);
scanReachableSymbols(val, cb);
return cb;
}
template <typename CB>
-CB GRState::scanReachableSymbols(const SVal *beg, const SVal *end) const {
+CB ProgramState::scanReachableSymbols(const SVal *beg, const SVal *end) const {
CB cb(this);
scanReachableSymbols(beg, end, cb);
return cb;
}
template <typename CB>
-CB GRState::scanReachableSymbols(const MemRegion * const *beg,
+CB ProgramState::scanReachableSymbols(const MemRegion * const *beg,
const MemRegion * const *end) const {
CB cb(this);
scanReachableSymbols(beg, end, cb);
return cb;
}
+/// \class ScanReachableSymbols
+/// A Utility class that allows to visit the reachable symbols using a custom
+/// SymbolVisitor.
+class ScanReachableSymbols : public SubRegionMap::Visitor {
+ typedef llvm::DenseMap<const void*, unsigned> VisitedItems;
+
+ VisitedItems visited;
+ const ProgramState *state;
+ SymbolVisitor &visitor;
+ llvm::OwningPtr<SubRegionMap> SRM;
+public:
+
+ ScanReachableSymbols(const ProgramState *st, SymbolVisitor& v)
+ : state(st), visitor(v) {}
+
+ bool scan(nonloc::CompoundVal val);
+ bool scan(SVal val);
+ bool scan(const MemRegion *R);
+ bool scan(const SymExpr *sym);
+
+ // From SubRegionMap::Visitor.
+ bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) {
+ return scan(SubRegion);
+ }
+};
+
} // end GR namespace
} // end clang namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
index de7b8684066f..b80d494b88cb 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
@@ -1,4 +1,4 @@
-//==- GRStateTrait.h - Partial implementations of GRStateTrait -----*- C++ -*-//
+//ProgramStateTrait.h - Partial implementations of ProgramStateTrait -*- C++ -*-
//
// The LLVM Compiler Infrastructure
//
@@ -8,14 +8,15 @@
//===----------------------------------------------------------------------===//
//
// This file defines partial implementations of template specializations of
-// the class GRStateTrait<>. GRStateTrait<> is used by GRState to implement
-// set/get methods for mapulating a GRState's generic data map.
+// the class ProgramStateTrait<>. ProgramStateTrait<> is used by ProgramState
+// to implement set/get methods for mapulating a ProgramState's
+// generic data map.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_GRSTATETRAIT_H
-#define LLVM_CLANG_GR_GRSTATETRAIT_H
+#ifndef LLVM_CLANG_GR_PROGRAMSTATETRAIT_H
+#define LLVM_CLANG_GR_PROGRAMSTATETRAIT_H
namespace llvm {
class BumpPtrAllocator;
@@ -28,22 +29,22 @@ namespace llvm {
namespace clang {
namespace ento {
- template <typename T> struct GRStatePartialTrait;
+ template <typename T> struct ProgramStatePartialTrait;
// Partial-specialization for ImmutableMap.
template <typename Key, typename Data, typename Info>
- struct GRStatePartialTrait< llvm::ImmutableMap<Key,Data,Info> > {
+ struct ProgramStatePartialTrait< llvm::ImmutableMap<Key,Data,Info> > {
typedef llvm::ImmutableMap<Key,Data,Info> data_type;
typedef typename data_type::Factory& context_type;
typedef Key key_type;
typedef Data value_type;
typedef const value_type* lookup_type;
- static inline data_type MakeData(void* const* p) {
+ static inline data_type MakeData(void *const* p) {
return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0);
}
- static inline void* MakeVoidPtr(data_type B) {
+ static inline void *MakeVoidPtr(data_type B) {
return B.getRoot();
}
static lookup_type Lookup(data_type B, key_type K) {
@@ -57,15 +58,15 @@ namespace ento {
return F.remove(B, K);
}
- static inline context_type MakeContext(void* p) {
+ static inline context_type MakeContext(void *p) {
return *((typename data_type::Factory*) p);
}
- static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
+ static void *CreateContext(llvm::BumpPtrAllocator& Alloc) {
return new typename data_type::Factory(Alloc);
}
- static void DeleteContext(void* Ctx) {
+ static void DeleteContext(void *Ctx) {
delete (typename data_type::Factory*) Ctx;
}
};
@@ -74,16 +75,16 @@ namespace ento {
// Partial-specialization for ImmutableSet.
template <typename Key, typename Info>
- struct GRStatePartialTrait< llvm::ImmutableSet<Key,Info> > {
+ struct ProgramStatePartialTrait< llvm::ImmutableSet<Key,Info> > {
typedef llvm::ImmutableSet<Key,Info> data_type;
typedef typename data_type::Factory& context_type;
typedef Key key_type;
- static inline data_type MakeData(void* const* p) {
+ static inline data_type MakeData(void *const* p) {
return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0);
}
- static inline void* MakeVoidPtr(data_type B) {
+ static inline void *MakeVoidPtr(data_type B) {
return B.getRoot();
}
@@ -99,15 +100,15 @@ namespace ento {
return B.contains(K);
}
- static inline context_type MakeContext(void* p) {
+ static inline context_type MakeContext(void *p) {
return *((typename data_type::Factory*) p);
}
- static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
+ static void *CreateContext(llvm::BumpPtrAllocator& Alloc) {
return new typename data_type::Factory(Alloc);
}
- static void DeleteContext(void* Ctx) {
+ static void DeleteContext(void *Ctx) {
delete (typename data_type::Factory*) Ctx;
}
};
@@ -115,7 +116,7 @@ namespace ento {
// Partial-specialization for ImmutableList.
template <typename T>
- struct GRStatePartialTrait< llvm::ImmutableList<T> > {
+ struct ProgramStatePartialTrait< llvm::ImmutableList<T> > {
typedef llvm::ImmutableList<T> data_type;
typedef T key_type;
typedef typename data_type::Factory& context_type;
@@ -128,33 +129,33 @@ namespace ento {
return L.contains(K);
}
- static inline data_type MakeData(void* const* p) {
+ static inline data_type MakeData(void *const* p) {
return p ? data_type((const llvm::ImmutableListImpl<T>*) *p)
: data_type(0);
}
- static inline void* MakeVoidPtr(data_type D) {
+ static inline void *MakeVoidPtr(data_type D) {
return (void*) D.getInternalPointer();
}
- static inline context_type MakeContext(void* p) {
+ static inline context_type MakeContext(void *p) {
return *((typename data_type::Factory*) p);
}
- static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
+ static void *CreateContext(llvm::BumpPtrAllocator& Alloc) {
return new typename data_type::Factory(Alloc);
}
- static void DeleteContext(void* Ctx) {
+ static void DeleteContext(void *Ctx) {
delete (typename data_type::Factory*) Ctx;
}
};
// Partial specialization for bool.
- template <> struct GRStatePartialTrait<bool> {
+ template <> struct ProgramStatePartialTrait<bool> {
typedef bool data_type;
- static inline data_type MakeData(void* const* p) {
+ static inline data_type MakeData(void *const* p) {
return p ? (data_type) (uintptr_t) *p
: data_type();
}
@@ -164,10 +165,10 @@ namespace ento {
};
// Partial specialization for unsigned.
- template <> struct GRStatePartialTrait<unsigned> {
+ template <> struct ProgramStatePartialTrait<unsigned> {
typedef unsigned data_type;
- static inline data_type MakeData(void* const* p) {
+ static inline data_type MakeData(void *const* p) {
return p ? (data_type) (uintptr_t) *p
: data_type();
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 65eabea24077..17233e194e6d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -25,7 +25,7 @@ namespace clang {
namespace ento {
-class GRState;
+class ProgramState;
class SValBuilder {
protected:
@@ -40,7 +40,7 @@ protected:
/// Manages the creation of memory regions.
MemRegionManager MemMgr;
- GRStateManager &StateMgr;
+ ProgramStateManager &StateMgr;
/// The scalar type to use for array indices.
const QualType ArrayIndexTy;
@@ -56,7 +56,7 @@ public:
public:
SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
- GRStateManager &stateMgr)
+ ProgramStateManager &stateMgr)
: Context(context), BasicVals(context, alloc),
SymMgr(context, BasicVals, alloc),
MemMgr(context, alloc),
@@ -72,29 +72,29 @@ public:
virtual SVal evalComplement(NonLoc val) = 0;
- virtual SVal evalBinOpNN(const GRState *state, BinaryOperator::Opcode op,
+ virtual SVal evalBinOpNN(const ProgramState *state, BinaryOperator::Opcode op,
NonLoc lhs, NonLoc rhs, QualType resultTy) = 0;
- virtual SVal evalBinOpLL(const GRState *state, BinaryOperator::Opcode op,
+ virtual SVal evalBinOpLL(const ProgramState *state, BinaryOperator::Opcode op,
Loc lhs, Loc rhs, QualType resultTy) = 0;
- virtual SVal evalBinOpLN(const GRState *state, BinaryOperator::Opcode op,
+ virtual SVal evalBinOpLN(const ProgramState *state, BinaryOperator::Opcode op,
Loc lhs, NonLoc rhs, QualType resultTy) = 0;
/// getKnownValue - evaluates a given SVal. If the SVal has only one possible
/// (integer) value, that value is returned. Otherwise, returns NULL.
- virtual const llvm::APSInt *getKnownValue(const GRState *state, SVal val) = 0;
+ virtual const llvm::APSInt *getKnownValue(const ProgramState *state, SVal val) = 0;
- SVal evalBinOp(const GRState *state, BinaryOperator::Opcode op,
+ SVal evalBinOp(const ProgramState *state, BinaryOperator::Opcode op,
SVal lhs, SVal rhs, QualType type);
- DefinedOrUnknownSVal evalEQ(const GRState *state, DefinedOrUnknownSVal lhs,
+ DefinedOrUnknownSVal evalEQ(const ProgramState *state, DefinedOrUnknownSVal lhs,
DefinedOrUnknownSVal rhs);
ASTContext &getContext() { return Context; }
const ASTContext &getContext() const { return Context; }
- GRStateManager &getStateManager() { return StateMgr; }
+ ProgramStateManager &getStateManager() { return StateMgr; }
QualType getConditionType() const {
return getContext().IntTy;
@@ -115,14 +115,14 @@ public:
// Forwarding methods to SymbolManager.
- const SymbolConjured* getConjuredSymbol(const Stmt* stmt, QualType type,
+ const SymbolConjured* getConjuredSymbol(const Stmt *stmt, QualType type,
unsigned visitCount,
- const void* symbolTag = 0) {
+ const void *symbolTag = 0) {
return SymMgr.getConjuredSymbol(stmt, type, visitCount, symbolTag);
}
- const SymbolConjured* getConjuredSymbol(const Expr* expr, unsigned visitCount,
- const void* symbolTag = 0) {
+ const SymbolConjured* getConjuredSymbol(const Expr *expr, unsigned visitCount,
+ const void *symbolTag = 0) {
return SymMgr.getConjuredSymbol(expr, visitCount, symbolTag);
}
@@ -130,7 +130,7 @@ public:
DefinedOrUnknownSVal makeZeroVal(QualType type);
/// getRegionValueSymbolVal - make a unique symbol for value of region.
- DefinedOrUnknownSVal getRegionValueSymbolVal(const TypedRegion *region);
+ DefinedOrUnknownSVal getRegionValueSymbolVal(const TypedValueRegion *region);
DefinedOrUnknownSVal getConjuredSymbolVal(const void *symbolTag,
const Expr *expr, unsigned count);
@@ -139,7 +139,7 @@ public:
unsigned count);
DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(
- SymbolRef parentSymbol, const TypedRegion *region);
+ SymbolRef parentSymbol, const TypedValueRegion *region);
DefinedSVal getMetadataSymbolVal(
const void *symbolTag, const MemRegion *region,
@@ -154,7 +154,8 @@ public:
return nonloc::CompoundVal(BasicVals.getCompoundValData(type, vals));
}
- NonLoc makeLazyCompoundVal(const StoreRef &store, const TypedRegion *region) {
+ NonLoc makeLazyCompoundVal(const StoreRef &store,
+ const TypedValueRegion *region) {
return nonloc::LazyCompoundVal(
BasicVals.getLazyCompoundValData(store, region));
}
@@ -254,7 +255,7 @@ public:
SValBuilder* createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
ASTContext &context,
- GRStateManager &stateMgr);
+ ProgramStateManager &stateMgr);
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index 0d430794e76c..5827b0042a5d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -15,14 +15,10 @@
#ifndef LLVM_CLANG_GR_RVALUE_H
#define LLVM_CLANG_GR_RVALUE_H
+#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
-#include "llvm/Support/Casting.h"
#include "llvm/ADT/ImmutableList.h"
-namespace llvm {
- class raw_ostream;
-}
-
//==------------------------------------------------------------------------==//
// Base SVal types.
//==------------------------------------------------------------------------==//
@@ -33,12 +29,12 @@ namespace ento {
class CompoundValData;
class LazyCompoundValData;
-class GRState;
+class ProgramState;
class BasicValueFactory;
class MemRegion;
class TypedRegion;
class MemRegionManager;
-class GRStateManager;
+class ProgramStateManager;
class SValBuilder;
/// SVal - This represents a symbolic expression, which can be either
@@ -57,16 +53,16 @@ public:
enum { BaseBits = 2, BaseMask = 0x3 };
protected:
- const void* Data;
+ const void *Data;
/// The lowest 2 bits are a BaseKind (0 -- 3).
/// The higher bits are an unsigned "kind" value.
unsigned Kind;
- explicit SVal(const void* d, bool isLoc, unsigned ValKind)
+ explicit SVal(const void *d, bool isLoc, unsigned ValKind)
: Data(d), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {}
- explicit SVal(BaseKind k, const void* D = NULL)
+ explicit SVal(BaseKind k, const void *D = NULL)
: Data(D), Kind(k) {}
public:
@@ -74,7 +70,7 @@ public:
~SVal() {}
/// BufferTy - A temporary buffer to hold a set of SVals.
- typedef llvm::SmallVector<SVal,5> BufferTy;
+ typedef SmallVector<SVal,5> BufferTy;
inline unsigned getRawKind() const { return Kind; }
inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
@@ -123,7 +119,7 @@ public:
/// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a
/// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl.
/// Otherwise return 0.
- const FunctionDecl* getAsFunctionDecl() const;
+ const FunctionDecl *getAsFunctionDecl() const;
/// getAsLocSymbol - If this SVal is a location (subclasses Loc) and
/// wraps a symbol, return that SymbolRef. Otherwise return NULL.
@@ -142,22 +138,22 @@ public:
const MemRegion *getAsRegion() const;
- void dumpToStream(llvm::raw_ostream& OS) const;
+ void dumpToStream(raw_ostream &OS) const;
void dump() const;
// Iterators.
class symbol_iterator {
- llvm::SmallVector<const SymExpr*, 5> itr;
+ SmallVector<const SymExpr*, 5> itr;
void expand();
public:
symbol_iterator() {}
- symbol_iterator(const SymExpr* SE);
+ symbol_iterator(const SymExpr *SE);
- symbol_iterator& operator++();
+ symbol_iterator &operator++();
SymbolRef operator*();
- bool operator==(const symbol_iterator& X) const;
- bool operator!=(const symbol_iterator& X) const;
+ bool operator==(const symbol_iterator &X) const;
+ bool operator!=(const symbol_iterator &X) const;
};
symbol_iterator symbol_begin() const {
@@ -178,13 +174,13 @@ public:
class UndefinedVal : public SVal {
public:
UndefinedVal() : SVal(UndefinedKind) {}
- UndefinedVal(const void* D) : SVal(UndefinedKind, D) {}
+ UndefinedVal(const void *D) : SVal(UndefinedKind, D) {}
static inline bool classof(const SVal* V) {
return V->getBaseKind() == UndefinedKind;
}
- const void* getData() const { return Data; }
+ const void *getData() const { return Data; }
};
class DefinedOrUnknownSVal : public SVal {
@@ -195,7 +191,7 @@ private:
bool isValid() const;
protected:
- explicit DefinedOrUnknownSVal(const void* d, bool isLoc, unsigned ValKind)
+ explicit DefinedOrUnknownSVal(const void *d, bool isLoc, unsigned ValKind)
: SVal(d, isLoc, ValKind) {}
explicit DefinedOrUnknownSVal(BaseKind k, void *D = NULL)
@@ -225,7 +221,7 @@ private:
bool isUnknownOrUndef() const;
bool isValid() const;
protected:
- explicit DefinedSVal(const void* d, bool isLoc, unsigned ValKind)
+ explicit DefinedSVal(const void *d, bool isLoc, unsigned ValKind)
: DefinedOrUnknownSVal(d, isLoc, ValKind) {}
public:
// Implement isa<T> support.
@@ -236,11 +232,11 @@ public:
class NonLoc : public DefinedSVal {
protected:
- explicit NonLoc(unsigned SubKind, const void* d)
+ explicit NonLoc(unsigned SubKind, const void *d)
: DefinedSVal(d, false, SubKind) {}
public:
- void dumpToStream(llvm::raw_ostream& Out) const;
+ void dumpToStream(raw_ostream &Out) const;
// Implement isa<T> support.
static inline bool classof(const SVal* V) {
@@ -250,11 +246,11 @@ public:
class Loc : public DefinedSVal {
protected:
- explicit Loc(unsigned SubKind, const void* D)
+ explicit Loc(unsigned SubKind, const void *D)
: DefinedSVal(const_cast<void*>(D), true, SubKind) {}
public:
- void dumpToStream(llvm::raw_ostream& Out) const;
+ void dumpToStream(raw_ostream &Out) const;
Loc(const Loc& X) : DefinedSVal(X.Data, true, X.getSubKind()) {}
@@ -533,7 +529,7 @@ public:
} // end clang namespace
namespace llvm {
-static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os,
+static inline raw_ostream &operator<<(raw_ostream &os,
clang::ento::SVal V) {
V.dumpToStream(os);
return os;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index cdbdf64515b4..a688d7f21979 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -29,20 +29,20 @@ class StackFrameContext;
namespace ento {
-class GRState;
-class GRStateManager;
+class ProgramState;
+class ProgramStateManager;
class SubRegionMap;
class StoreManager {
protected:
SValBuilder &svalBuilder;
- GRStateManager &StateMgr;
+ ProgramStateManager &StateMgr;
/// MRMgr - Manages region objects associated with this StoreManager.
MemRegionManager &MRMgr;
ASTContext &Ctx;
- StoreManager(GRStateManager &stateMgr);
+ StoreManager(ProgramStateManager &stateMgr);
public:
virtual ~StoreManager() {}
@@ -60,7 +60,7 @@ public:
/// \param[in] state The analysis state.
/// \param[in] loc The symbolic memory location.
/// \param[in] val The value to bind to location \c loc.
- /// \return A pointer to a GRState object that contains the same bindings as
+ /// \return A pointer to a ProgramState object that contains the same bindings as
/// \c state with the addition of having the value specified by \c val bound
/// to the location given for \c loc.
virtual StoreRef Bind(Store store, Loc loc, SVal val) = 0;
@@ -73,7 +73,7 @@ public:
/// for the compound literal and 'BegInit' and 'EndInit' represent an
/// array of initializer values.
virtual StoreRef BindCompoundLiteral(Store store,
- const CompoundLiteralExpr* cl,
+ const CompoundLiteralExpr *cl,
const LocationContext *LC, SVal v) = 0;
/// getInitialStore - Returns the initial "empty" store representing the
@@ -97,16 +97,16 @@ public:
return svalBuilder.makeLoc(MRMgr.getStringRegion(S));
}
- Loc getLValueCompoundLiteral(const CompoundLiteralExpr* CL,
+ Loc getLValueCompoundLiteral(const CompoundLiteralExpr *CL,
const LocationContext *LC) {
return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC));
}
- virtual SVal getLValueIvar(const ObjCIvarDecl* decl, SVal base) {
+ virtual SVal getLValueIvar(const ObjCIvarDecl *decl, SVal base) {
return getLValueFieldOrIvar(decl, base);
}
- virtual SVal getLValueField(const FieldDecl* D, SVal Base) {
+ virtual SVal getLValueField(const FieldDecl *D, SVal Base) {
return getLValueFieldOrIvar(D, Base);
}
@@ -114,7 +114,7 @@ public:
// FIXME: This should soon be eliminated altogether; clients should deal with
// region extents directly.
- virtual DefinedOrUnknownSVal getSizeInElements(const GRState *state,
+ virtual DefinedOrUnknownSVal getSizeInElements(const ProgramState *state,
const MemRegion *region,
QualType EleTy) {
return UnknownVal();
@@ -130,12 +130,12 @@ public:
}
class CastResult {
- const GRState *state;
+ const ProgramState *state;
const MemRegion *region;
public:
- const GRState *getState() const { return state; }
+ const ProgramState *getState() const { return state; }
const MemRegion* getRegion() const { return region; }
- CastResult(const GRState *s, const MemRegion* r = 0) : state(s), region(r){}
+ CastResult(const ProgramState *s, const MemRegion* r = 0) : state(s), region(r){}
};
const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T);
@@ -146,13 +146,15 @@ public:
const MemRegion *castRegion(const MemRegion *region, QualType CastToTy);
virtual StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx,
- SymbolReaper& SymReaper,
- llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0;
+ SymbolReaper& SymReaper) = 0;
virtual StoreRef BindDecl(Store store, const VarRegion *VR, SVal initVal) = 0;
virtual StoreRef BindDeclWithNoInit(Store store, const VarRegion *VR) = 0;
+ virtual bool includedInBindings(Store store,
+ const MemRegion *region) const = 0;
+
/// If the StoreManager supports it, increment the reference count of
/// the specified Store object.
virtual void incrementReferenceCount(Store store) {}
@@ -163,7 +165,7 @@ public:
virtual void decrementReferenceCount(Store store) {}
typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols;
- typedef llvm::SmallVector<const MemRegion *, 8> InvalidatedRegions;
+ typedef SmallVector<const MemRegion *, 8> InvalidatedRegions;
/// invalidateRegions - Clears out the specified regions from the store,
/// marking their values as unknown. Depending on the store, this may also
@@ -185,19 +187,18 @@ public:
/// even if they do not currently have bindings. Pass \c NULL if this
/// information will not be used.
virtual StoreRef invalidateRegions(Store store,
- const MemRegion * const *Begin,
- const MemRegion * const *End,
+ ArrayRef<const MemRegion *> Regions,
const Expr *E, unsigned Count,
InvalidatedSymbols &IS,
bool invalidateGlobals,
- InvalidatedRegions *Regions) = 0;
+ InvalidatedRegions *Invalidated) = 0;
/// enterStackFrame - Let the StoreManager to do something when execution
/// engine is about to execute into a callee.
- virtual StoreRef enterStackFrame(const GRState *state,
+ virtual StoreRef enterStackFrame(const ProgramState *state,
const StackFrameContext *frame);
- virtual void print(Store store, llvm::raw_ostream& Out,
+ virtual void print(Store store, raw_ostream &Out,
const char* nl, const char *sep) = 0;
class BindingsHandler {
@@ -217,11 +218,11 @@ protected:
/// CastRetrievedVal - Used by subclasses of StoreManager to implement
/// implicit casts that arise from loads from regions that are reinterpreted
/// as another region.
- SVal CastRetrievedVal(SVal val, const TypedRegion *region, QualType castTy,
- bool performTestOnly = true);
+ SVal CastRetrievedVal(SVal val, const TypedValueRegion *region,
+ QualType castTy, bool performTestOnly = true);
private:
- SVal getLValueFieldOrIvar(const Decl* decl, SVal base);
+ SVal getLValueFieldOrIvar(const Decl *decl, SVal base);
};
@@ -269,11 +270,9 @@ public:
virtual bool iterSubRegions(const MemRegion *region, Visitor& V) const = 0;
};
-// FIXME: Do we need to pass GRStateManager anymore?
-StoreManager *CreateBasicStoreManager(GRStateManager& StMgr);
-StoreManager *CreateRegionStoreManager(GRStateManager& StMgr);
-StoreManager *CreateFieldsOnlyRegionStoreManager(GRStateManager& StMgr);
-StoreManager *CreateFlatStoreManager(GRStateManager &StMgr);
+// FIXME: Do we need to pass ProgramStateManager anymore?
+StoreManager *CreateRegionStoreManager(ProgramStateManager& StMgr);
+StoreManager *CreateFieldsOnlyRegionStoreManager(ProgramStateManager& StMgr);
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h b/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h
index 0662eadc93c3..d5ba003a6915 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h
@@ -23,7 +23,7 @@ namespace ento {
/// locations to values. At a high-level, it represents the symbolic
/// memory model. Different subclasses of StoreManager may choose
/// different types to represent the locations and values.
-typedef const void* Store;
+typedef const void *Store;
class StoreManager;
@@ -44,6 +44,7 @@ public:
~StoreRef();
Store getStore() const { return store; }
+ const StoreManager &getStoreManager() const { return mgr; }
};
}}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
index 1f6ea3d8c732..ae212bcf5ddf 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
@@ -30,8 +30,8 @@ template <typename PP> class GenericNodeBuilder;
class AnalysisManager;
class ExplodedNodeSet;
class ExplodedNode;
-class GRState;
-class GRStateManager;
+class ProgramState;
+class ProgramStateManager;
class BlockCounter;
class StmtNodeBuilder;
class BranchNodeBuilder;
@@ -46,11 +46,11 @@ class SubEngine {
public:
virtual ~SubEngine() {}
- virtual const GRState* getInitialState(const LocationContext *InitLoc) = 0;
+ virtual const ProgramState *getInitialState(const LocationContext *InitLoc) = 0;
virtual AnalysisManager &getAnalysisManager() = 0;
- virtual GRStateManager &getStateManager() = 0;
+ virtual ProgramStateManager &getStateManager() = 0;
/// Called by CoreEngine. Used to generate new successor
/// nodes by processing the 'effects' of a block-level statement.
@@ -64,7 +64,7 @@ public:
/// Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a branch condition.
- virtual void processBranch(const Stmt* Condition, const Stmt* Term,
+ virtual void processBranch(const Stmt *Condition, const Stmt *Term,
BranchNodeBuilder& builder) = 0;
/// Called by CoreEngine. Used to generate successor
@@ -87,28 +87,32 @@ public:
/// Called by ConstraintManager. Used to call checker-specific
/// logic for handling assumptions on symbolic values.
- virtual const GRState* processAssume(const GRState *state,
+ virtual const ProgramState *processAssume(const ProgramState *state,
SVal cond, bool assumption) = 0;
- /// wantsRegionChangeUpdate - Called by GRStateManager to determine if a
+ /// wantsRegionChangeUpdate - Called by ProgramStateManager to determine if a
/// region change should trigger a processRegionChanges update.
- virtual bool wantsRegionChangeUpdate(const GRState* state) = 0;
+ virtual bool wantsRegionChangeUpdate(const ProgramState *state) = 0;
- /// processRegionChanges - Called by GRStateManager whenever a change is made
+ /// processRegionChanges - Called by ProgramStateManager whenever a change is made
/// to the store. Used to update checkers that track region values.
- virtual const GRState *
- processRegionChanges(const GRState *state,
+ virtual const ProgramState *
+ processRegionChanges(const ProgramState *state,
const StoreManager::InvalidatedSymbols *invalidated,
- const MemRegion* const *Begin,
- const MemRegion* const *End) = 0;
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions) = 0;
- inline const GRState *
- processRegionChange(const GRState* state,
+ inline const ProgramState *
+ processRegionChange(const ProgramState *state,
const MemRegion* MR) {
- return processRegionChanges(state, 0, &MR, &MR+1);
+ return processRegionChanges(state, 0, MR, MR);
}
+ /// printState - Called by ProgramStateManager to print checker-specific data.
+ virtual void printState(raw_ostream &Out, const ProgramState *State,
+ const char *NL, const char *Sep) = 0;
+
/// Called by CoreEngine when the analysis worklist is either empty or the
// maximum number of analysis steps have been reached.
virtual void processEndWorklist(bool hasWorkRemaining) = 0;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index ad173bb43536..0d6e18eb3cc8 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -18,13 +18,15 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#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"
namespace llvm {
class BumpPtrAllocator;
-class raw_ostream;
}
namespace clang {
@@ -35,15 +37,15 @@ namespace ento {
class BasicValueFactory;
class MemRegion;
class SubRegion;
- class TypedRegion;
+ class TypedValueRegion;
class VarRegion;
class SymExpr : public llvm::FoldingSetNode {
public:
- enum Kind { BEGIN_SYMBOLS,
- RegionValueKind, ConjuredKind, DerivedKind, ExtentKind,
+ enum Kind { RegionValueKind, ConjuredKind, DerivedKind, ExtentKind,
MetadataKind,
- END_SYMBOLS,
+ BEGIN_SYMBOLS = RegionValueKind,
+ END_SYMBOLS = MetadataKind,
SymIntKind, SymSymKind };
private:
Kind K;
@@ -58,7 +60,7 @@ public:
void dump() const;
- virtual void dumpToStream(llvm::raw_ostream &os) const = 0;
+ virtual void dumpToStream(raw_ostream &os) const = 0;
virtual QualType getType(ASTContext&) const = 0;
virtual void Profile(llvm::FoldingSetNodeID& profile) = 0;
@@ -82,25 +84,26 @@ public:
SymbolID getSymbolID() const { return Sym; }
// Implement isa<T> support.
- static inline bool classof(const SymExpr* SE) {
+ static inline bool classof(const SymExpr *SE) {
Kind k = SE->getKind();
- return k > BEGIN_SYMBOLS && k < END_SYMBOLS;
+ return k >= BEGIN_SYMBOLS && k <= END_SYMBOLS;
}
};
typedef const SymbolData* SymbolRef;
+typedef llvm::SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy;
-// A symbol representing the value of a MemRegion.
+/// A symbol representing the value of a MemRegion.
class SymbolRegionValue : public SymbolData {
- const TypedRegion *R;
+ const TypedValueRegion *R;
public:
- SymbolRegionValue(SymbolID sym, const TypedRegion *r)
+ SymbolRegionValue(SymbolID sym, const TypedValueRegion *r)
: SymbolData(RegionValueKind, sym), R(r) {}
- const TypedRegion* getRegion() const { return R; }
+ const TypedValueRegion* getRegion() const { return R; }
- static void Profile(llvm::FoldingSetNodeID& profile, const TypedRegion* R) {
+ static void Profile(llvm::FoldingSetNodeID& profile, const TypedValueRegion* R) {
profile.AddInteger((unsigned) RegionValueKind);
profile.AddPointer(R);
}
@@ -109,39 +112,39 @@ public:
Profile(profile, R);
}
- void dumpToStream(llvm::raw_ostream &os) const;
+ void dumpToStream(raw_ostream &os) const;
QualType getType(ASTContext&) const;
// Implement isa<T> support.
- static inline bool classof(const SymExpr* SE) {
+ static inline bool classof(const SymExpr *SE) {
return SE->getKind() == RegionValueKind;
}
};
-// A symbol representing the result of an expression.
+/// A symbol representing the result of an expression.
class SymbolConjured : public SymbolData {
- const Stmt* S;
+ const Stmt *S;
QualType T;
unsigned Count;
- const void* SymbolTag;
+ const void *SymbolTag;
public:
- SymbolConjured(SymbolID sym, const Stmt* s, QualType t, unsigned count,
- const void* symbolTag)
+ SymbolConjured(SymbolID sym, const Stmt *s, QualType t, unsigned count,
+ const void *symbolTag)
: SymbolData(ConjuredKind, sym), S(s), T(t), Count(count),
SymbolTag(symbolTag) {}
- const Stmt* getStmt() const { return S; }
+ const Stmt *getStmt() const { return S; }
unsigned getCount() const { return Count; }
- const void* getTag() const { return SymbolTag; }
+ const void *getTag() const { return SymbolTag; }
QualType getType(ASTContext&) const;
- void dumpToStream(llvm::raw_ostream &os) const;
+ void dumpToStream(raw_ostream &os) const;
- static void Profile(llvm::FoldingSetNodeID& profile, const Stmt* S,
- QualType T, unsigned Count, const void* SymbolTag) {
+ static void Profile(llvm::FoldingSetNodeID& profile, const Stmt *S,
+ QualType T, unsigned Count, const void *SymbolTag) {
profile.AddInteger((unsigned) ConjuredKind);
profile.AddPointer(S);
profile.Add(T);
@@ -154,30 +157,30 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr* SE) {
+ static inline bool classof(const SymExpr *SE) {
return SE->getKind() == ConjuredKind;
}
};
-// A symbol representing the value of a MemRegion whose parent region has
-// symbolic value.
+/// A symbol representing the value of a MemRegion whose parent region has
+/// symbolic value.
class SymbolDerived : public SymbolData {
SymbolRef parentSymbol;
- const TypedRegion *R;
+ const TypedValueRegion *R;
public:
- SymbolDerived(SymbolID sym, SymbolRef parent, const TypedRegion *r)
+ SymbolDerived(SymbolID sym, SymbolRef parent, const TypedValueRegion *r)
: SymbolData(DerivedKind, sym), parentSymbol(parent), R(r) {}
SymbolRef getParentSymbol() const { return parentSymbol; }
- const TypedRegion *getRegion() const { return R; }
+ const TypedValueRegion *getRegion() const { return R; }
QualType getType(ASTContext&) const;
- void dumpToStream(llvm::raw_ostream &os) const;
+ void dumpToStream(raw_ostream &os) const;
static void Profile(llvm::FoldingSetNodeID& profile, SymbolRef parent,
- const TypedRegion *r) {
+ const TypedValueRegion *r) {
profile.AddInteger((unsigned) DerivedKind);
profile.AddPointer(r);
profile.AddPointer(parent);
@@ -188,7 +191,7 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr* SE) {
+ static inline bool classof(const SymExpr *SE) {
return SE->getKind() == DerivedKind;
}
};
@@ -207,7 +210,7 @@ public:
QualType getType(ASTContext&) const;
- void dumpToStream(llvm::raw_ostream &os) const;
+ void dumpToStream(raw_ostream &os) const;
static void Profile(llvm::FoldingSetNodeID& profile, const SubRegion *R) {
profile.AddInteger((unsigned) ExtentKind);
@@ -219,7 +222,7 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr* SE) {
+ static inline bool classof(const SymExpr *SE) {
return SE->getKind() == ExtentKind;
}
};
@@ -230,23 +233,23 @@ public:
/// Intended for use by checkers.
class SymbolMetadata : public SymbolData {
const MemRegion* R;
- const Stmt* S;
+ const Stmt *S;
QualType T;
unsigned Count;
- const void* Tag;
+ const void *Tag;
public:
- SymbolMetadata(SymbolID sym, const MemRegion* r, const Stmt* s, QualType t,
- unsigned count, const void* tag)
+ SymbolMetadata(SymbolID sym, const MemRegion* r, const Stmt *s, QualType t,
+ unsigned count, const void *tag)
: SymbolData(MetadataKind, sym), R(r), S(s), T(t), Count(count), Tag(tag) {}
const MemRegion *getRegion() const { return R; }
- const Stmt* getStmt() const { return S; }
+ const Stmt *getStmt() const { return S; }
unsigned getCount() const { return Count; }
- const void* getTag() const { return Tag; }
+ const void *getTag() const { return Tag; }
QualType getType(ASTContext&) const;
- void dumpToStream(llvm::raw_ostream &os) const;
+ void dumpToStream(raw_ostream &os) const;
static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion *R,
const Stmt *S, QualType T, unsigned Count,
@@ -264,12 +267,12 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr* SE) {
+ static inline bool classof(const SymExpr *SE) {
return SE->getKind() == MetadataKind;
}
};
-// SymIntExpr - Represents symbolic expression like 'x' + 3.
+/// SymIntExpr - Represents symbolic expression like 'x' + 3.
class SymIntExpr : public SymExpr {
const SymExpr *LHS;
BinaryOperator::Opcode Op;
@@ -283,11 +286,11 @@ public:
// FIXME: We probably need to make this out-of-line to avoid redundant
// generation of virtual functions.
- QualType getType(ASTContext& C) const { return T; }
+ QualType getType(ASTContext &C) const { return T; }
BinaryOperator::Opcode getOpcode() const { return Op; }
- void dumpToStream(llvm::raw_ostream &os) const;
+ void dumpToStream(raw_ostream &os) const;
const SymExpr *getLHS() const { return LHS; }
const llvm::APSInt &getRHS() const { return RHS; }
@@ -307,12 +310,12 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr* SE) {
+ static inline bool classof(const SymExpr *SE) {
return SE->getKind() == SymIntKind;
}
};
-// SymSymExpr - Represents symbolic expression like 'x' + 'y'.
+/// SymSymExpr - Represents symbolic expression like 'x' + 'y'.
class SymSymExpr : public SymExpr {
const SymExpr *LHS;
BinaryOperator::Opcode Op;
@@ -330,9 +333,9 @@ public:
// FIXME: We probably need to make this out-of-line to avoid redundant
// generation of virtual functions.
- QualType getType(ASTContext& C) const { return T; }
+ QualType getType(ASTContext &C) const { return T; }
- void dumpToStream(llvm::raw_ostream &os) const;
+ void dumpToStream(raw_ostream &os) const;
static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) {
@@ -348,48 +351,58 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr* SE) {
+ static inline bool classof(const SymExpr *SE) {
return SE->getKind() == SymSymKind;
}
};
class SymbolManager {
typedef llvm::FoldingSet<SymExpr> DataSetTy;
+ typedef llvm::DenseMap<SymbolRef, SymbolRefSmallVectorTy*> SymbolDependTy;
+
DataSetTy DataSet;
+ /// Stores the extra dependencies between symbols: the data should be kept
+ /// alive as long as the key is live.
+ SymbolDependTy SymbolDependencies;
unsigned SymbolCounter;
llvm::BumpPtrAllocator& BPAlloc;
BasicValueFactory &BV;
- ASTContext& Ctx;
+ ASTContext &Ctx;
public:
- SymbolManager(ASTContext& ctx, BasicValueFactory &bv,
+ SymbolManager(ASTContext &ctx, BasicValueFactory &bv,
llvm::BumpPtrAllocator& bpalloc)
- : SymbolCounter(0), BPAlloc(bpalloc), BV(bv), Ctx(ctx) {}
+ : SymbolDependencies(16), SymbolCounter(0),
+ BPAlloc(bpalloc), BV(bv), Ctx(ctx) {}
~SymbolManager();
static bool canSymbolicate(QualType T);
- /// Make a unique symbol for MemRegion R according to its kind.
- const SymbolRegionValue* getRegionValueSymbol(const TypedRegion* R);
+ /// \brief Make a unique symbol for MemRegion R according to its kind.
+ const SymbolRegionValue* getRegionValueSymbol(const TypedValueRegion* R);
- const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T,
+ const SymbolConjured* getConjuredSymbol(const Stmt *E, QualType T,
unsigned VisitCount,
- const void* SymbolTag = 0);
+ const void *SymbolTag = 0);
- const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount,
- const void* SymbolTag = 0) {
+ const SymbolConjured* getConjuredSymbol(const Expr *E, unsigned VisitCount,
+ const void *SymbolTag = 0) {
return getConjuredSymbol(E, E->getType(), VisitCount, SymbolTag);
}
const SymbolDerived *getDerivedSymbol(SymbolRef parentSymbol,
- const TypedRegion *R);
+ const TypedValueRegion *R);
const SymbolExtent *getExtentSymbol(const SubRegion *R);
- const SymbolMetadata* getMetadataSymbol(const MemRegion* R, const Stmt* S,
+ /// \brief Creates a metadata symbol associated with a specific region.
+ ///
+ /// VisitCount can be used to differentiate regions corresponding to
+ /// different loop iterations, thus, making the symbol path-dependent.
+ const SymbolMetadata* getMetadataSymbol(const MemRegion* R, const Stmt *S,
QualType T, unsigned VisitCount,
- const void* SymbolTag = 0);
+ const void *SymbolTag = 0);
const SymIntExpr *getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
const llvm::APSInt& rhs, QualType t);
@@ -406,23 +419,43 @@ public:
return SE->getType(Ctx);
}
+ /// \brief Add artificial symbol dependency.
+ ///
+ /// The dependent symbol should stay alive as long as the primary is alive.
+ void addSymbolDependency(const SymbolRef Primary, const SymbolRef Dependent);
+
+ const SymbolRefSmallVectorTy *getDependentSymbols(const SymbolRef Primary);
+
ASTContext &getContext() { return Ctx; }
BasicValueFactory &getBasicVals() { return BV; }
};
class SymbolReaper {
- typedef llvm::DenseSet<SymbolRef> SetTy;
+ enum SymbolStatus {
+ NotProcessed,
+ HaveMarkedDependents
+ };
- SetTy TheLiving;
- SetTy MetadataInUse;
- SetTy TheDead;
+ typedef llvm::DenseSet<SymbolRef> SymbolSetTy;
+ typedef llvm::DenseMap<SymbolRef, SymbolStatus> SymbolMapTy;
+ typedef llvm::DenseSet<const MemRegion *> RegionSetTy;
+
+ SymbolMapTy TheLiving;
+ SymbolSetTy MetadataInUse;
+ SymbolSetTy TheDead;
+
+ RegionSetTy RegionRoots;
+
const LocationContext *LCtx;
const Stmt *Loc;
SymbolManager& SymMgr;
+ StoreRef reapedStore;
+ llvm::DenseMap<const MemRegion *, unsigned> includedRegionCache;
public:
- SymbolReaper(const LocationContext *ctx, const Stmt *s, SymbolManager& symmgr)
- : LCtx(ctx), Loc(s), SymMgr(symmgr) {}
+ SymbolReaper(const LocationContext *ctx, const Stmt *s, SymbolManager& symmgr,
+ StoreManager &storeMgr)
+ : LCtx(ctx), Loc(s), SymMgr(symmgr), reapedStore(0, storeMgr) {}
~SymbolReaper() {}
@@ -430,48 +463,71 @@ public:
const Stmt *getCurrentStatement() const { return Loc; }
bool isLive(SymbolRef sym);
+ bool isLiveRegion(const MemRegion *region);
bool isLive(const Stmt *ExprVal) const;
- bool isLive(const VarRegion *VR) const;
+ bool isLive(const VarRegion *VR, bool includeStoreBindings = false) const;
- // markLive - Unconditionally marks a symbol as live. This should never be
- // used by checkers, only by the state infrastructure such as the store and
- // environment. Checkers should instead use metadata symbols and markInUse.
+ /// \brief Unconditionally marks a symbol as live.
+ ///
+ /// This should never be
+ /// used by checkers, only by the state infrastructure such as the store and
+ /// environment. Checkers should instead use metadata symbols and markInUse.
void markLive(SymbolRef sym);
- // markInUse - Marks a symbol as important to a checker. For metadata symbols,
- // this will keep the symbol alive as long as its associated region is also
- // live. For other symbols, this has no effect; checkers are not permitted
- // to influence the life of other symbols. This should be used before any
- // symbol marking has occurred, i.e. in the MarkLiveSymbols callback.
+ /// \brief Marks a symbol as important to a checker.
+ ///
+ /// For metadata symbols,
+ /// this will keep the symbol alive as long as its associated region is also
+ /// live. For other symbols, this has no effect; checkers are not permitted
+ /// to influence the life of other symbols. This should be used before any
+ /// symbol marking has occurred, i.e. in the MarkLiveSymbols callback.
void markInUse(SymbolRef sym);
- // maybeDead - If a symbol is known to be live, marks the symbol as live.
- // Otherwise, if the symbol cannot be proven live, it is marked as dead.
- // Returns true if the symbol is dead, false if live.
+ /// \brief If a symbol is known to be live, marks the symbol as live.
+ ///
+ /// Otherwise, if the symbol cannot be proven live, it is marked as dead.
+ /// Returns true if the symbol is dead, false if live.
bool maybeDead(SymbolRef sym);
- typedef SetTy::const_iterator dead_iterator;
+ typedef SymbolSetTy::const_iterator dead_iterator;
dead_iterator dead_begin() const { return TheDead.begin(); }
dead_iterator dead_end() const { return TheDead.end(); }
bool hasDeadSymbols() const {
return !TheDead.empty();
}
-
- /// isDead - Returns whether or not a symbol has been confirmed dead. This
- /// should only be called once all marking of dead symbols has completed.
- /// (For checkers, this means only in the evalDeadSymbols callback.)
+
+ typedef RegionSetTy::const_iterator region_iterator;
+ region_iterator region_begin() const { return RegionRoots.begin(); }
+ region_iterator region_end() const { return RegionRoots.end(); }
+
+ /// \brief Returns whether or not a symbol has been confirmed dead.
+ ///
+ /// This should only be called once all marking of dead symbols has completed.
+ /// (For checkers, this means only in the evalDeadSymbols callback.)
bool isDead(SymbolRef sym) const {
return TheDead.count(sym);
}
+
+ void markLive(const MemRegion *region);
+
+ /// \brief Set to the value of the symbolic store after
+ /// StoreManager::removeDeadBindings has been called.
+ void setReapedStore(StoreRef st) { reapedStore = st; }
+
+private:
+ /// Mark the symbols dependent on the input symbol as live.
+ void markDependentsLive(SymbolRef sym);
};
class SymbolVisitor {
public:
- // VisitSymbol - A visitor method invoked by
- // GRStateManager::scanReachableSymbols. The method returns \c true if
- // symbols should continue be scanned and \c false otherwise.
+ /// \brief A visitor method invoked by ProgramStateManager::scanReachableSymbols.
+ ///
+ /// The method returns \c true if symbols should continue be scanned and \c
+ /// false otherwise.
virtual bool VisitSymbol(SymbolRef sym) = 0;
+ virtual bool VisitMemRegion(const MemRegion *region) { return true; }
virtual ~SymbolVisitor();
};
@@ -480,7 +536,7 @@ public:
} // end clang namespace
namespace llvm {
-static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os,
+static inline raw_ostream &operator<<(raw_ostream &os,
const clang::ento::SymExpr *SE) {
SE->dumpToStream(os);
return os;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h
deleted file mode 100644
index 23ed2be8c7a4..000000000000
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h
+++ /dev/null
@@ -1,93 +0,0 @@
-//== TransferFuncs.h - Path-Sens. Transfer Functions 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 TransferFuncs, which provides a base-class that
-// defines an interface for transfer functions used by ExprEngine.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_GR_TRANSFERFUNCS
-#define LLVM_CLANG_GR_TRANSFERFUNCS
-
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
-#include <vector>
-
-namespace clang {
-class ObjCMessageExpr;
-
-namespace ento {
-class ExplodedNode;
-class ExplodedNodeSet;
-class EndOfFunctionNodeBuilder;
-class ExprEngine;
-class StmtNodeBuilder;
-class StmtNodeBuilderRef;
-
-class TransferFuncs {
-public:
- TransferFuncs() {}
- virtual ~TransferFuncs() {}
-
- virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {}
- virtual void RegisterChecks(ExprEngine& Eng) {}
-
-
- // Calls.
-
- virtual void evalCall(ExplodedNodeSet& Dst,
- ExprEngine& Engine,
- StmtNodeBuilder& Builder,
- const CallExpr* CE, SVal L,
- ExplodedNode* Pred) {}
-
- virtual void evalObjCMessage(ExplodedNodeSet& Dst,
- ExprEngine& Engine,
- StmtNodeBuilder& Builder,
- ObjCMessage msg,
- ExplodedNode* Pred,
- const GRState *state) {}
-
- // Stores.
-
- virtual void evalBind(StmtNodeBuilderRef& B, SVal location, SVal val) {}
-
- // End-of-path and dead symbol notification.
-
- virtual void evalEndPath(ExprEngine& Engine,
- EndOfFunctionNodeBuilder& Builder) {}
-
-
- virtual void evalDeadSymbols(ExplodedNodeSet& Dst,
- ExprEngine& Engine,
- StmtNodeBuilder& Builder,
- ExplodedNode* Pred,
- const GRState* state,
- SymbolReaper& SymReaper) {}
-
- // Return statements.
- virtual void evalReturn(ExplodedNodeSet& Dst,
- ExprEngine& Engine,
- StmtNodeBuilder& Builder,
- const ReturnStmt* S,
- ExplodedNode* Pred) {}
-
- // Assumptions.
- virtual const GRState* evalAssume(const GRState *state,
- SVal Cond, bool Assumption) {
- return state;
- }
-};
-
-} // end GR namespace
-
-} // end clang namespace
-
-#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
index 6bc9fe56f8d6..fa340753e5b7 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
@@ -28,20 +28,20 @@ class ExplodedNode;
class ExplodedNodeImpl;
class WorkListUnit {
- ExplodedNode* node;
+ ExplodedNode *node;
BlockCounter counter;
- const CFGBlock* block;
+ const CFGBlock *block;
unsigned blockIdx; // This is the index of the next statement.
public:
- WorkListUnit(ExplodedNode* N, BlockCounter C,
- const CFGBlock* B, unsigned idx)
+ WorkListUnit(ExplodedNode *N, BlockCounter C,
+ const CFGBlock *B, unsigned idx)
: node(N),
counter(C),
block(B),
blockIdx(idx) {}
- explicit WorkListUnit(ExplodedNode* N, BlockCounter C)
+ explicit WorkListUnit(ExplodedNode *N, BlockCounter C)
: node(N),
counter(C),
block(NULL),
diff --git a/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h b/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h
index 9d6298f36e3b..492edd4ccb41 100644
--- a/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h
+++ b/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h
@@ -1,4 +1,4 @@
-//===-- CheckerRegistration.h - Checker Registration Function-------*- C++ -*-===//
+//===-- CheckerRegistration.h - Checker Registration Function ---*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -10,17 +10,21 @@
#ifndef LLVM_CLANG_SA_FRONTEND_CHECKERREGISTRATION_H
#define LLVM_CLANG_SA_FRONTEND_CHECKERREGISTRATION_H
+#include "clang/Basic/LLVM.h"
+#include <string>
+
namespace clang {
class AnalyzerOptions;
class LangOptions;
- class Diagnostic;
+ class DiagnosticsEngine;
namespace ento {
class CheckerManager;
-CheckerManager *registerCheckers(const AnalyzerOptions &opts,
- const LangOptions &langOpts,
- Diagnostic &diags);
+CheckerManager *createCheckerManager(const AnalyzerOptions &opts,
+ const LangOptions &langOpts,
+ ArrayRef<std::string> plugins,
+ DiagnosticsEngine &diags);
} // end ento namespace
diff --git a/include/clang/StaticAnalyzer/Frontend/FrontendActions.h b/include/clang/StaticAnalyzer/Frontend/FrontendActions.h
index f01418175281..838ac925533f 100644
--- a/include/clang/StaticAnalyzer/Frontend/FrontendActions.h
+++ b/include/clang/StaticAnalyzer/Frontend/FrontendActions.h
@@ -23,10 +23,10 @@ namespace ento {
class AnalysisAction : public ASTFrontendAction {
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile);
+ StringRef InFile);
};
-void printCheckerHelp(llvm::raw_ostream &OS);
+void printCheckerHelp(raw_ostream &OS, ArrayRef<std::string> plugins);
} // end GR namespace
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp
index f1d947da677e..6e1b0e535bbb 100644
--- a/lib/ARCMigrate/ARCMT.cpp
+++ b/lib/ARCMigrate/ARCMT.cpp
@@ -10,6 +10,7 @@
#include "Internals.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/Rewrite/Rewriter.h"
@@ -18,12 +19,10 @@
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/ADT/Triple.h"
-
using namespace clang;
using namespace arcmt;
-using llvm::StringRef;
-bool CapturedDiagList::clearDiagnostic(llvm::ArrayRef<unsigned> IDs,
+bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs,
SourceRange range) {
if (range.isInvalid())
return false;
@@ -39,7 +38,7 @@ bool CapturedDiagList::clearDiagnostic(llvm::ArrayRef<unsigned> IDs,
diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) {
cleared = true;
ListTy::iterator eraseS = I++;
- while (I != List.end() && I->getLevel() == Diagnostic::Note)
+ while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note)
++I;
// Clear the diagnostic and any notes following it.
List.erase(eraseS, I);
@@ -52,7 +51,7 @@ bool CapturedDiagList::clearDiagnostic(llvm::ArrayRef<unsigned> IDs,
return cleared;
}
-bool CapturedDiagList::hasDiagnostic(llvm::ArrayRef<unsigned> IDs,
+bool CapturedDiagList::hasDiagnostic(ArrayRef<unsigned> IDs,
SourceRange range) const {
if (range.isInvalid())
return false;
@@ -74,14 +73,14 @@ bool CapturedDiagList::hasDiagnostic(llvm::ArrayRef<unsigned> IDs,
return false;
}
-void CapturedDiagList::reportDiagnostics(Diagnostic &Diags) const {
+void CapturedDiagList::reportDiagnostics(DiagnosticsEngine &Diags) const {
for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I)
Diags.Report(*I);
}
bool CapturedDiagList::hasErrors() const {
for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I)
- if (I->getLevel() >= Diagnostic::Error)
+ if (I->getLevel() >= DiagnosticsEngine::Error)
return true;
return false;
@@ -89,18 +88,18 @@ bool CapturedDiagList::hasErrors() const {
namespace {
-class CaptureDiagnosticClient : public DiagnosticClient {
- Diagnostic &Diags;
+class CaptureDiagnosticConsumer : public DiagnosticConsumer {
+ DiagnosticsEngine &Diags;
CapturedDiagList &CapturedDiags;
public:
- CaptureDiagnosticClient(Diagnostic &diags,
- CapturedDiagList &capturedDiags)
+ CaptureDiagnosticConsumer(DiagnosticsEngine &diags,
+ CapturedDiagList &capturedDiags)
: Diags(diags), CapturedDiags(capturedDiags) { }
- virtual void HandleDiagnostic(Diagnostic::Level level,
- const DiagnosticInfo &Info) {
+ virtual void HandleDiagnostic(DiagnosticsEngine::Level level,
+ const Diagnostic &Info) {
if (arcmt::isARCDiagnostic(Info.getID(), Diags) ||
- level >= Diagnostic::Error || level == Diagnostic::Note) {
+ level >= DiagnosticsEngine::Error || level == DiagnosticsEngine::Note) {
CapturedDiags.push_back(StoredDiagnostic(level, Info));
return;
}
@@ -108,11 +107,17 @@ public:
// Non-ARC warnings are ignored.
Diags.setLastDiagnosticIgnored();
}
+
+ DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
+ // Just drop any diagnostics that come from cloned consumers; they'll
+ // have different source managers anyway.
+ return new IgnoringDiagConsumer();
+ }
};
} // end anonymous namespace
-static inline llvm::StringRef SimulatorVersionDefineName() {
+static inline StringRef SimulatorVersionDefineName() {
return "__IPHONE_OS_VERSION_MIN_REQUIRED=";
}
@@ -121,11 +126,11 @@ static inline llvm::StringRef SimulatorVersionDefineName() {
// and return the grouped values as integers, e.g:
// __IPHONE_OS_VERSION_MIN_REQUIRED=40201
// will return Major=4, Minor=2, Micro=1.
-static bool GetVersionFromSimulatorDefine(llvm::StringRef define,
+static bool GetVersionFromSimulatorDefine(StringRef define,
unsigned &Major, unsigned &Minor,
unsigned &Micro) {
assert(define.startswith(SimulatorVersionDefineName()));
- llvm::StringRef name, version;
+ StringRef name, version;
llvm::tie(name, version) = define.split('=');
if (version.empty())
return false;
@@ -154,7 +159,7 @@ static bool HasARCRuntime(CompilerInvocation &origCI) {
continue;
if (!define.startswith(SimulatorVersionDefineName()))
continue;
- unsigned Major, Minor, Micro;
+ unsigned Major = 0, Minor = 0, Micro = 0;
if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) &&
Major < 10 && Minor < 100 && Micro < 100)
return Major >= 5;
@@ -177,7 +182,8 @@ static bool HasARCRuntime(CompilerInvocation &origCI) {
return false;
}
-CompilerInvocation *createInvocationForMigration(CompilerInvocation &origCI) {
+static CompilerInvocation *
+createInvocationForMigration(CompilerInvocation &origCI) {
llvm::OwningPtr<CompilerInvocation> CInvok;
CInvok.reset(new CompilerInvocation(origCI));
CInvok->getPreprocessorOpts().ImplicitPCHInclude = std::string();
@@ -194,13 +200,29 @@ CompilerInvocation *createInvocationForMigration(CompilerInvocation &origCI) {
return CInvok.take();
}
+static void emitPremigrationErrors(const CapturedDiagList &arcDiags,
+ const DiagnosticOptions &diagOpts,
+ Preprocessor &PP) {
+ TextDiagnosticPrinter printer(llvm::errs(), diagOpts);
+ llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, &printer, /*ShouldOwnClient=*/false));
+ Diags->setSourceManager(&PP.getSourceManager());
+
+ printer.BeginSourceFile(PP.getLangOptions(), &PP);
+ arcDiags.reportDiagnostics(*Diags);
+ printer.EndSourceFile();
+}
+
//===----------------------------------------------------------------------===//
// checkForManualIssues.
//===----------------------------------------------------------------------===//
bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
- llvm::StringRef Filename, InputKind Kind,
- DiagnosticClient *DiagClient) {
+ StringRef Filename, InputKind Kind,
+ DiagnosticConsumer *DiagClient,
+ bool emitPremigrationARCErrors,
+ StringRef plistOut) {
if (!origCI.getLangOpts().ObjC1)
return false;
@@ -216,11 +238,11 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
assert(DiagClient);
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags(
- new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
// Filter of all diagnostics.
- CaptureDiagnosticClient errRec(*Diags, capturedDiags);
+ CaptureDiagnosticConsumer errRec(*Diags, capturedDiags);
Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
llvm::OwningPtr<ASTUnit> Unit(
@@ -241,9 +263,21 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
return true;
}
+ if (emitPremigrationARCErrors)
+ emitPremigrationErrors(capturedDiags, origCI.getDiagnosticOpts(),
+ Unit->getPreprocessor());
+ if (!plistOut.empty()) {
+ SmallVector<StoredDiagnostic, 8> arcDiags;
+ for (CapturedDiagList::iterator
+ I = capturedDiags.begin(), E = capturedDiags.end(); I != E; ++I)
+ arcDiags.push_back(*I);
+ writeARCDiagsToPlist(plistOut, arcDiags,
+ Ctx.getSourceManager(), Ctx.getLangOptions());
+ }
+
// After parsing of source files ended, we want to reuse the
// diagnostics objects to emit further diagnostics.
- // We call BeginSourceFile because DiagnosticClient requires that
+ // We call BeginSourceFile because DiagnosticConsumer requires that
// diagnostics with source range information are emitted only in between
// BeginSourceFile() and EndSourceFile().
DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor());
@@ -266,7 +300,7 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
// to remove it so that we don't get errors from normal compilation.
origCI.getLangOpts().ObjCAutoRefCount = false;
- return capturedDiags.hasErrors();
+ return capturedDiags.hasErrors() || testAct.hasReportedErrors();
}
//===----------------------------------------------------------------------===//
@@ -274,15 +308,18 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
//===----------------------------------------------------------------------===//
static bool applyTransforms(CompilerInvocation &origCI,
- llvm::StringRef Filename, InputKind Kind,
- DiagnosticClient *DiagClient,
- llvm::StringRef outputDir) {
+ StringRef Filename, InputKind Kind,
+ DiagnosticConsumer *DiagClient,
+ StringRef outputDir,
+ bool emitPremigrationARCErrors,
+ StringRef plistOut) {
if (!origCI.getLangOpts().ObjC1)
return false;
// Make sure checking is successful first.
CompilerInvocation CInvokForCheck(origCI);
- if (arcmt::checkForManualIssues(CInvokForCheck, Filename, Kind, DiagClient))
+ if (arcmt::checkForManualIssues(CInvokForCheck, Filename, Kind, DiagClient,
+ emitPremigrationARCErrors, plistOut))
return true;
CompilerInvocation CInvok(origCI);
@@ -300,8 +337,8 @@ static bool applyTransforms(CompilerInvocation &origCI,
}
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags(
- new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
if (outputDir.empty()) {
origCI.getLangOpts().ObjCAutoRefCount = true;
@@ -315,28 +352,32 @@ static bool applyTransforms(CompilerInvocation &origCI,
}
bool arcmt::applyTransformations(CompilerInvocation &origCI,
- llvm::StringRef Filename, InputKind Kind,
- DiagnosticClient *DiagClient) {
- return applyTransforms(origCI, Filename, Kind, DiagClient, llvm::StringRef());
+ StringRef Filename, InputKind Kind,
+ DiagnosticConsumer *DiagClient) {
+ return applyTransforms(origCI, Filename, Kind, DiagClient,
+ StringRef(), false, StringRef());
}
bool arcmt::migrateWithTemporaryFiles(CompilerInvocation &origCI,
- llvm::StringRef Filename, InputKind Kind,
- DiagnosticClient *DiagClient,
- llvm::StringRef outputDir) {
+ StringRef Filename, InputKind Kind,
+ DiagnosticConsumer *DiagClient,
+ StringRef outputDir,
+ bool emitPremigrationARCErrors,
+ StringRef plistOut) {
assert(!outputDir.empty() && "Expected output directory path");
- return applyTransforms(origCI, Filename, Kind, DiagClient, outputDir);
+ return applyTransforms(origCI, Filename, Kind, DiagClient,
+ outputDir, emitPremigrationARCErrors, plistOut);
}
bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > &
remap,
- llvm::StringRef outputDir,
- DiagnosticClient *DiagClient) {
+ StringRef outputDir,
+ DiagnosticConsumer *DiagClient) {
assert(!outputDir.empty());
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags(
- new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
FileRemapper remapper;
bool err = remapper.initFromDisk(outputDir, *Diags,
@@ -364,7 +405,8 @@ public:
ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs)
: ARCMTMacroLocs(ARCMTMacroLocs) { }
- virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo *MI) {
+ virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo *MI,
+ SourceRange Range) {
if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName())
ARCMTMacroLocs.push_back(MacroNameTok.getLocation());
}
@@ -378,7 +420,7 @@ public:
: ARCMTMacroLocs(ARCMTMacroLocs) { }
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
+ StringRef InFile) {
CI.getPreprocessor().addPPCallbacks(
new ARCMTMacroTrackerPPCallbacks(ARCMTMacroLocs));
return new ASTConsumer();
@@ -402,7 +444,7 @@ public:
Listener->finish();
}
- virtual void insert(SourceLocation loc, llvm::StringRef text) {
+ virtual void insert(SourceLocation loc, StringRef text) {
bool err = rewriter.InsertText(loc, text, /*InsertAfter=*/true,
/*indentNewLines=*/true);
if (!err && Listener)
@@ -432,13 +474,13 @@ public:
MigrationProcess::RewriteListener::~RewriteListener() { }
MigrationProcess::MigrationProcess(const CompilerInvocation &CI,
- DiagnosticClient *diagClient,
- llvm::StringRef outputDir)
+ DiagnosticConsumer *diagClient,
+ StringRef outputDir)
: OrigCI(CI), DiagClient(diagClient) {
if (!outputDir.empty()) {
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags(
- new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true);
}
}
@@ -456,11 +498,11 @@ bool MigrationProcess::applyTransform(TransformFn trans,
assert(DiagClient);
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags(
- new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
// Filter of all diagnostics.
- CaptureDiagnosticClient errRec(*Diags, capturedDiags);
+ CaptureDiagnosticConsumer errRec(*Diags, capturedDiags);
Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
llvm::OwningPtr<ARCMTMacroTrackerAction> ASTAction;
@@ -488,7 +530,7 @@ bool MigrationProcess::applyTransform(TransformFn trans,
// After parsing of source files ended, we want to reuse the
// diagnostics objects to emit further diagnostics.
- // We call BeginSourceFile because DiagnosticClient requires that
+ // We call BeginSourceFile because DiagnosticConsumer requires that
// diagnostics with source range information are emitted only in between
// BeginSourceFile() and EndSourceFile().
DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor());
@@ -522,7 +564,7 @@ bool MigrationProcess::applyTransform(TransformFn trans,
buf.write(vecOS);
vecOS.flush();
llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy(
- llvm::StringRef(newText.data(), newText.size()), newFname);
+ StringRef(newText.data(), newText.size()), newFname);
llvm::SmallString<64> filePath(file->getName());
Unit->getFileManager().FixupRelativePath(filePath);
Remapper.remap(filePath.str(), memBuf);
@@ -535,7 +577,7 @@ bool MigrationProcess::applyTransform(TransformFn trans,
// isARCDiagnostic.
//===----------------------------------------------------------------------===//
-bool arcmt::isARCDiagnostic(unsigned diagID, Diagnostic &Diag) {
+bool arcmt::isARCDiagnostic(unsigned diagID, DiagnosticsEngine &Diag) {
return Diag.getDiagnosticIDs()->getCategoryNumberForDiag(diagID) ==
diag::DiagCat_Automatic_Reference_Counting_Issue;
}
diff --git a/lib/ARCMigrate/ARCMTActions.cpp b/lib/ARCMigrate/ARCMTActions.cpp
index 345c7452420e..dea867af659d 100644
--- a/lib/ARCMigrate/ARCMTActions.cpp
+++ b/lib/ARCMigrate/ARCMTActions.cpp
@@ -38,16 +38,26 @@ ModifyAction::ModifyAction(FrontendAction *WrappedAction)
: WrapperFrontendAction(WrappedAction) {}
bool MigrateAction::BeginInvocation(CompilerInstance &CI) {
- return !arcmt::migrateWithTemporaryFiles(CI.getInvocation(),
+ if (arcmt::migrateWithTemporaryFiles(CI.getInvocation(),
getCurrentFile(),
getCurrentFileKind(),
CI.getDiagnostics().getClient(),
- MigrateDir);
+ MigrateDir,
+ EmitPremigrationARCErros,
+ PlistOut))
+ return false; // errors, stop the action.
+
+ // We only want to see diagnostics emitted by migrateWithTemporaryFiles.
+ CI.getDiagnostics().setIgnoreAllWarnings(true);
+ return true;
}
MigrateAction::MigrateAction(FrontendAction *WrappedAction,
- llvm::StringRef migrateDir)
- : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir) {
+ StringRef migrateDir,
+ StringRef plistOut,
+ bool emitPremigrationARCErrors)
+ : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir),
+ PlistOut(plistOut), EmitPremigrationARCErros(emitPremigrationARCErrors) {
if (MigrateDir.empty())
MigrateDir = "."; // user current directory if none is given.
}
diff --git a/lib/ARCMigrate/CMakeLists.txt b/lib/ARCMigrate/CMakeLists.txt
index 5f2711e36f26..f6d404ee1354 100644
--- a/lib/ARCMigrate/CMakeLists.txt
+++ b/lib/ARCMigrate/CMakeLists.txt
@@ -4,6 +4,8 @@ add_clang_library(clangARCMigrate
ARCMT.cpp
ARCMTActions.cpp
FileRemapper.cpp
+ PlistReporter.cpp
+ TransAPIUses.cpp
TransARCAssign.cpp
TransAutoreleasePool.cpp
TransBlockObjCVariable.cpp
diff --git a/lib/ARCMigrate/FileRemapper.cpp b/lib/ARCMigrate/FileRemapper.cpp
index db26c29a3dda..c6e6ce46d173 100644
--- a/lib/ARCMigrate/FileRemapper.cpp
+++ b/lib/ARCMigrate/FileRemapper.cpp
@@ -27,7 +27,7 @@ FileRemapper::~FileRemapper() {
clear();
}
-void FileRemapper::clear(llvm::StringRef outputDir) {
+void FileRemapper::clear(StringRef outputDir) {
for (MappingsTy::iterator
I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I)
resetTarget(I->second);
@@ -40,7 +40,7 @@ void FileRemapper::clear(llvm::StringRef outputDir) {
}
}
-std::string FileRemapper::getRemapInfoFile(llvm::StringRef outputDir) {
+std::string FileRemapper::getRemapInfoFile(StringRef outputDir) {
assert(!outputDir.empty());
llvm::sys::Path dir(outputDir);
llvm::sys::Path infoFile = dir;
@@ -48,7 +48,7 @@ std::string FileRemapper::getRemapInfoFile(llvm::StringRef outputDir) {
return infoFile.str();
}
-bool FileRemapper::initFromDisk(llvm::StringRef outputDir, Diagnostic &Diag,
+bool FileRemapper::initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag,
bool ignoreIfFilesChanged) {
assert(FromToMappings.empty() &&
"initFromDisk should be called before any remap calls");
@@ -59,38 +59,38 @@ bool FileRemapper::initFromDisk(llvm::StringRef outputDir, Diagnostic &Diag,
return false;
std::vector<std::pair<const FileEntry *, const FileEntry *> > pairs;
-
- std::ifstream fin(infoFile.c_str());
- if (!fin.good())
- return report(std::string("Error opening file: ") + infoFile, Diag);
-
- while (true) {
- std::string fromFilename, toFilename;
- uint64_t timeModified;
-
- fin >> fromFilename >> timeModified >> toFilename;
- if (fin.eof())
- break;
- if (!fin.good())
- return report(std::string("Error in format of file: ") + infoFile, Diag);
-
+
+ llvm::OwningPtr<llvm::MemoryBuffer> fileBuf;
+ if (llvm::error_code ec = llvm::MemoryBuffer::getFile(infoFile.c_str(),
+ fileBuf))
+ return report("Error opening file: " + infoFile, Diag);
+
+ SmallVector<StringRef, 64> lines;
+ fileBuf->getBuffer().split(lines, "\n");
+
+ for (unsigned idx = 0; idx+3 <= lines.size(); idx += 3) {
+ StringRef fromFilename = lines[idx];
+ unsigned long long timeModified;
+ lines[idx+1].getAsInteger(10, timeModified);
+ StringRef toFilename = lines[idx+2];
+
const FileEntry *origFE = FileMgr->getFile(fromFilename);
if (!origFE) {
if (ignoreIfFilesChanged)
continue;
- return report(std::string("File does not exist: ") + fromFilename, Diag);
+ return report("File does not exist: " + fromFilename, Diag);
}
const FileEntry *newFE = FileMgr->getFile(toFilename);
if (!newFE) {
if (ignoreIfFilesChanged)
continue;
- return report(std::string("File does not exist: ") + toFilename, Diag);
+ return report("File does not exist: " + toFilename, Diag);
}
if ((uint64_t)origFE->getModificationTime() != timeModified) {
if (ignoreIfFilesChanged)
continue;
- return report(std::string("File was modified: ") + fromFilename, Diag);
+ return report("File was modified: " + fromFilename, Diag);
}
pairs.push_back(std::make_pair(origFE, newFE));
@@ -102,13 +102,12 @@ bool FileRemapper::initFromDisk(llvm::StringRef outputDir, Diagnostic &Diag,
return false;
}
-bool FileRemapper::flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag) {
+bool FileRemapper::flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag) {
using namespace llvm::sys;
bool existed;
if (fs::create_directory(outputDir, existed) != llvm::errc::success)
- return report(std::string("Could not create directory: ") + outputDir.str(),
- Diag);
+ return report("Could not create directory: " + outputDir, Diag);
std::string errMsg;
std::string infoFile = getRemapInfoFile(outputDir);
@@ -121,13 +120,13 @@ bool FileRemapper::flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag) {
I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) {
const FileEntry *origFE = I->first;
- llvm::SmallString<200> origPath = llvm::StringRef(origFE->getName());
+ llvm::SmallString<200> origPath = StringRef(origFE->getName());
fs::make_absolute(origPath);
infoOut << origPath << '\n';
infoOut << (uint64_t)origFE->getModificationTime() << '\n';
if (const FileEntry *FE = I->second.dyn_cast<const FileEntry *>()) {
- llvm::SmallString<200> newPath = llvm::StringRef(FE->getName());
+ llvm::SmallString<200> newPath = StringRef(FE->getName());
fs::make_absolute(newPath);
infoOut << newPath << '\n';
} else {
@@ -138,8 +137,7 @@ bool FileRemapper::flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag) {
tempPath += path::extension(origFE->getName());
int fd;
if (fs::unique_file(tempPath.str(), fd, tempPath) != llvm::errc::success)
- return report(std::string("Could not create file: ") + tempPath.c_str(),
- Diag);
+ return report("Could not create file: " + tempPath.str(), Diag);
llvm::raw_fd_ostream newOut(fd, /*shouldClose=*/true);
llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>();
@@ -156,8 +154,8 @@ bool FileRemapper::flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag) {
return false;
}
-bool FileRemapper::overwriteOriginal(Diagnostic &Diag,
- llvm::StringRef outputDir) {
+bool FileRemapper::overwriteOriginal(DiagnosticsEngine &Diag,
+ StringRef outputDir) {
using namespace llvm::sys;
for (MappingsTy::iterator
@@ -165,20 +163,15 @@ bool FileRemapper::overwriteOriginal(Diagnostic &Diag,
const FileEntry *origFE = I->first;
if (const FileEntry *newFE = I->second.dyn_cast<const FileEntry *>()) {
if (fs::copy_file(newFE->getName(), origFE->getName(),
- fs::copy_option::overwrite_if_exists) != llvm::errc::success) {
- std::string err = "Could not copy file '";
- llvm::raw_string_ostream os(err);
- os << "Could not copy file '" << newFE->getName() << "' to file '"
- << origFE->getName() << "'";
- os.flush();
- return report(err, Diag);
- }
+ fs::copy_option::overwrite_if_exists) != llvm::errc::success)
+ return report(StringRef("Could not copy file '") + newFE->getName() +
+ "' to file '" + origFE->getName() + "'", Diag);
} else {
bool fileExists = false;
fs::exists(origFE->getName(), fileExists);
if (!fileExists)
- return report(std::string("File does not exist: ") + origFE->getName(),
+ return report(StringRef("File does not exist: ") + origFE->getName(),
Diag);
std::string errMsg;
@@ -229,11 +222,11 @@ void FileRemapper::transferMappingsAndClear(CompilerInvocation &CI) {
clear();
}
-void FileRemapper::remap(llvm::StringRef filePath, llvm::MemoryBuffer *memBuf) {
+void FileRemapper::remap(StringRef filePath, llvm::MemoryBuffer *memBuf) {
remap(getOriginalFile(filePath), memBuf);
}
-void FileRemapper::remap(llvm::StringRef filePath, llvm::StringRef newPath) {
+void FileRemapper::remap(StringRef filePath, StringRef newPath) {
const FileEntry *file = getOriginalFile(filePath);
const FileEntry *newfile = FileMgr->getFile(newPath);
remap(file, newfile);
@@ -254,7 +247,7 @@ void FileRemapper::remap(const FileEntry *file, const FileEntry *newfile) {
ToFromMappings[newfile] = file;
}
-const FileEntry *FileRemapper::getOriginalFile(llvm::StringRef filePath) {
+const FileEntry *FileRemapper::getOriginalFile(StringRef filePath) {
const FileEntry *file = FileMgr->getFile(filePath);
// If we are updating a file that overriden an original file,
// actually update the original file.
@@ -283,9 +276,10 @@ void FileRemapper::resetTarget(Target &targ) {
}
}
-bool FileRemapper::report(const std::string &err, Diagnostic &Diag) {
+bool FileRemapper::report(const Twine &err, DiagnosticsEngine &Diag) {
+ llvm::SmallString<128> buf;
unsigned ID = Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Error,
- err);
+ err.toStringRef(buf));
Diag.Report(ID);
return true;
}
diff --git a/lib/ARCMigrate/Internals.h b/lib/ARCMigrate/Internals.h
index 4f9b138a06ce..46f3bb626f2f 100644
--- a/lib/ARCMigrate/Internals.h
+++ b/lib/ARCMigrate/Internals.h
@@ -26,21 +26,30 @@ class CapturedDiagList {
public:
void push_back(const StoredDiagnostic &diag) { List.push_back(diag); }
- bool clearDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range);
- bool hasDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range) const;
+ bool clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range);
+ bool hasDiagnostic(ArrayRef<unsigned> IDs, SourceRange range) const;
- void reportDiagnostics(Diagnostic &diags) const;
+ void reportDiagnostics(DiagnosticsEngine &diags) const;
bool hasErrors() const;
+
+ typedef ListTy::const_iterator iterator;
+ iterator begin() const { return List.begin(); }
+ iterator end() const { return List.end(); }
};
+void writeARCDiagsToPlist(const std::string &outPath,
+ ArrayRef<StoredDiagnostic> diags,
+ SourceManager &SM, const LangOptions &LangOpts);
+
class TransformActions {
- Diagnostic &Diags;
+ DiagnosticsEngine &Diags;
CapturedDiagList &CapturedDiags;
+ bool ReportedErrors;
void *Impl; // TransformActionsImpl.
public:
- TransformActions(Diagnostic &diag, CapturedDiagList &capturedDiags,
+ TransformActions(DiagnosticsEngine &diag, CapturedDiagList &capturedDiags,
ASTContext &ctx, Preprocessor &PP);
~TransformActions();
@@ -48,21 +57,21 @@ public:
bool commitTransaction();
void abortTransaction();
- void insert(SourceLocation loc, llvm::StringRef text);
- void insertAfterToken(SourceLocation loc, llvm::StringRef text);
+ void insert(SourceLocation loc, StringRef text);
+ void insertAfterToken(SourceLocation loc, StringRef text);
void remove(SourceRange range);
void removeStmt(Stmt *S);
- void replace(SourceRange range, llvm::StringRef text);
+ void replace(SourceRange range, StringRef text);
void replace(SourceRange range, SourceRange replacementRange);
- void replaceStmt(Stmt *S, llvm::StringRef text);
- void replaceText(SourceLocation loc, llvm::StringRef text,
- llvm::StringRef replacementText);
+ void replaceStmt(Stmt *S, StringRef text);
+ void replaceText(SourceLocation loc, StringRef text,
+ StringRef replacementText);
void increaseIndentation(SourceRange range,
SourceLocation parentIndent);
- bool clearDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range);
+ bool clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range);
bool clearAllDiagnostics(SourceRange range) {
- return clearDiagnostic(llvm::ArrayRef<unsigned>(), range);
+ return clearDiagnostic(ArrayRef<unsigned>(), range);
}
bool clearDiagnostic(unsigned ID1, unsigned ID2, SourceRange range) {
unsigned IDs[] = { ID1, ID2 };
@@ -83,16 +92,18 @@ public:
return CapturedDiags.hasDiagnostic(IDs, range);
}
- void reportError(llvm::StringRef error, SourceLocation loc,
+ void reportError(StringRef error, SourceLocation loc,
SourceRange range = SourceRange());
- void reportNote(llvm::StringRef note, SourceLocation loc,
+ void reportNote(StringRef note, SourceLocation loc,
SourceRange range = SourceRange());
+ bool hasReportedErrors() const { return ReportedErrors; }
+
class RewriteReceiver {
public:
virtual ~RewriteReceiver();
- virtual void insert(SourceLocation loc, llvm::StringRef text) = 0;
+ virtual void insert(SourceLocation loc, StringRef text) = 0;
virtual void remove(CharSourceRange range) = 0;
virtual void increaseIndentation(CharSourceRange range,
SourceLocation parentIndent) = 0;
@@ -135,9 +146,9 @@ public:
: Ctx(Ctx), SemaRef(sema), TA(TA), ARCMTMacroLocs(ARCMTMacroLocs) { }
};
-bool isARCDiagnostic(unsigned diagID, Diagnostic &Diag);
+bool isARCDiagnostic(unsigned diagID, DiagnosticsEngine &Diag);
-static inline llvm::StringRef getARCMTMacroName() {
+static inline StringRef getARCMTMacroName() {
return "__IMPL_ARCMT_REMOVED_EXPR__";
}
diff --git a/lib/ARCMigrate/PlistReporter.cpp b/lib/ARCMigrate/PlistReporter.cpp
new file mode 100644
index 000000000000..d1bc90fdbe16
--- /dev/null
+++ b/lib/ARCMigrate/PlistReporter.cpp
@@ -0,0 +1,195 @@
+//===--- PlistReporter.cpp - ARC Migrate Tool Plist Reporter ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Internals.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+using namespace clang;
+using namespace arcmt;
+
+// FIXME: This duplicates significant functionality from PlistDiagnostics.cpp,
+// it would be jolly good if there was a reusable PlistWriter or something.
+
+typedef llvm::DenseMap<FileID, unsigned> FIDMap;
+
+static void AddFID(FIDMap &FIDs, SmallVectorImpl<FileID> &V,
+ const SourceManager &SM, SourceLocation L) {
+
+ FileID FID = SM.getFileID(SM.getExpansionLoc(L));
+ FIDMap::iterator I = FIDs.find(FID);
+ if (I != FIDs.end()) return;
+ FIDs[FID] = V.size();
+ V.push_back(FID);
+}
+
+static unsigned GetFID(const FIDMap& FIDs, const SourceManager &SM,
+ SourceLocation L) {
+ FileID FID = SM.getFileID(SM.getExpansionLoc(L));
+ FIDMap::const_iterator I = FIDs.find(FID);
+ assert(I != FIDs.end());
+ return I->second;
+}
+
+static raw_ostream& Indent(raw_ostream& o, const unsigned indent) {
+ for (unsigned i = 0; i < indent; ++i) o << ' ';
+ return o;
+}
+
+static void EmitLocation(raw_ostream& o, const SourceManager &SM,
+ const LangOptions &LangOpts,
+ SourceLocation L, const FIDMap &FM,
+ unsigned indent, bool extend = false) {
+
+ FullSourceLoc Loc(SM.getExpansionLoc(L), const_cast<SourceManager&>(SM));
+
+ // Add in the length of the token, so that we cover multi-char tokens.
+ unsigned offset =
+ extend ? Lexer::MeasureTokenLength(Loc, SM, LangOpts) - 1 : 0;
+
+ Indent(o, indent) << "<dict>\n";
+ Indent(o, indent) << " <key>line</key><integer>"
+ << Loc.getExpansionLineNumber() << "</integer>\n";
+ Indent(o, indent) << " <key>col</key><integer>"
+ << Loc.getExpansionColumnNumber() + offset << "</integer>\n";
+ Indent(o, indent) << " <key>file</key><integer>"
+ << GetFID(FM, SM, Loc) << "</integer>\n";
+ Indent(o, indent) << "</dict>\n";
+}
+
+static void EmitRange(raw_ostream& o, const SourceManager &SM,
+ const LangOptions &LangOpts,
+ CharSourceRange R, const FIDMap &FM,
+ unsigned indent) {
+ Indent(o, indent) << "<array>\n";
+ EmitLocation(o, SM, LangOpts, R.getBegin(), FM, indent+1);
+ EmitLocation(o, SM, LangOpts, R.getEnd(), FM, indent+1, R.isTokenRange());
+ Indent(o, indent) << "</array>\n";
+}
+
+static raw_ostream& EmitString(raw_ostream& o,
+ StringRef s) {
+ o << "<string>";
+ for (StringRef::const_iterator I=s.begin(), E=s.end(); I!=E; ++I) {
+ char c = *I;
+ switch (c) {
+ default: o << c; break;
+ case '&': o << "&amp;"; break;
+ case '<': o << "&lt;"; break;
+ case '>': o << "&gt;"; break;
+ case '\'': o << "&apos;"; break;
+ case '\"': o << "&quot;"; break;
+ }
+ }
+ o << "</string>";
+ return o;
+}
+
+void arcmt::writeARCDiagsToPlist(const std::string &outPath,
+ ArrayRef<StoredDiagnostic> diags,
+ SourceManager &SM,
+ const LangOptions &LangOpts) {
+ DiagnosticIDs DiagIDs;
+
+ // Build up a set of FIDs that we use by scanning the locations and
+ // ranges of the diagnostics.
+ FIDMap FM;
+ SmallVector<FileID, 10> Fids;
+
+ for (ArrayRef<StoredDiagnostic>::iterator
+ I = diags.begin(), E = diags.end(); I != E; ++I) {
+ const StoredDiagnostic &D = *I;
+
+ AddFID(FM, Fids, SM, D.getLocation());
+
+ for (StoredDiagnostic::range_iterator
+ RI = D.range_begin(), RE = D.range_end(); RI != RE; ++RI) {
+ AddFID(FM, Fids, SM, RI->getBegin());
+ AddFID(FM, Fids, SM, RI->getEnd());
+ }
+ }
+
+ std::string errMsg;
+ llvm::raw_fd_ostream o(outPath.c_str(), errMsg);
+ if (!errMsg.empty()) {
+ llvm::errs() << "error: could not create file: " << outPath << '\n';
+ return;
+ }
+
+ // Write the plist header.
+ o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
+ "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
+ "<plist version=\"1.0\">\n";
+
+ // Write the root object: a <dict> containing...
+ // - "files", an <array> mapping from FIDs to file names
+ // - "diagnostics", an <array> containing the diagnostics
+ o << "<dict>\n"
+ " <key>files</key>\n"
+ " <array>\n";
+
+ for (SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end();
+ I!=E; ++I) {
+ o << " ";
+ EmitString(o, SM.getFileEntryForID(*I)->getName()) << '\n';
+ }
+
+ o << " </array>\n"
+ " <key>diagnostics</key>\n"
+ " <array>\n";
+
+ for (ArrayRef<StoredDiagnostic>::iterator
+ DI = diags.begin(), DE = diags.end(); DI != DE; ++DI) {
+
+ const StoredDiagnostic &D = *DI;
+
+ if (D.getLevel() == DiagnosticsEngine::Ignored)
+ continue;
+
+ o << " <dict>\n";
+
+ // Output the diagnostic.
+ o << " <key>description</key>";
+ EmitString(o, D.getMessage()) << '\n';
+ o << " <key>category</key>";
+ EmitString(o, DiagIDs.getCategoryNameFromID(
+ DiagIDs.getCategoryNumberForDiag(D.getID()))) << '\n';
+ o << " <key>type</key>";
+ if (D.getLevel() >= DiagnosticsEngine::Error)
+ EmitString(o, "error") << '\n';
+ else if (D.getLevel() == DiagnosticsEngine::Warning)
+ EmitString(o, "warning") << '\n';
+ else
+ EmitString(o, "note") << '\n';
+
+ // Output the location of the bug.
+ o << " <key>location</key>\n";
+ EmitLocation(o, SM, LangOpts, D.getLocation(), FM, 2);
+
+ // Output the ranges (if any).
+ StoredDiagnostic::range_iterator RI = D.range_begin(), RE = D.range_end();
+
+ if (RI != RE) {
+ o << " <key>ranges</key>\n";
+ o << " <array>\n";
+ for (; RI != RE; ++RI)
+ EmitRange(o, SM, LangOpts, *RI, FM, 4);
+ o << " </array>\n";
+ }
+
+ // Close up the entry.
+ o << " </dict>\n";
+ }
+
+ o << " </array>\n";
+
+ // Finish.
+ o << "</dict>\n</plist>";
+}
diff --git a/lib/ARCMigrate/TransAPIUses.cpp b/lib/ARCMigrate/TransAPIUses.cpp
new file mode 100644
index 000000000000..aaa82d8dfb7a
--- /dev/null
+++ b/lib/ARCMigrate/TransAPIUses.cpp
@@ -0,0 +1,109 @@
+//===--- TransAPIUses.cpp - Tranformations to ARC mode --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// checkAPIUses:
+//
+// Emits error/fix with some API uses that are obsolete or not safe in ARC mode:
+//
+// - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe
+// with __unsafe_unretained objects.
+// - Calling -zone gets replaced with 'nil'.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Transforms.h"
+#include "Internals.h"
+#include "clang/Sema/SemaDiagnostic.h"
+
+using namespace clang;
+using namespace arcmt;
+using namespace trans;
+
+namespace {
+
+class APIChecker : public RecursiveASTVisitor<APIChecker> {
+ MigrationPass &Pass;
+
+ Selector getReturnValueSel, setReturnValueSel;
+ Selector getArgumentSel, setArgumentSel;
+
+ Selector zoneSel;
+public:
+ APIChecker(MigrationPass &pass) : Pass(pass) {
+ SelectorTable &sels = Pass.Ctx.Selectors;
+ IdentifierTable &ids = Pass.Ctx.Idents;
+ getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue"));
+ setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue"));
+
+ IdentifierInfo *selIds[2];
+ selIds[0] = &ids.get("getArgument");
+ selIds[1] = &ids.get("atIndex");
+ getArgumentSel = sels.getSelector(2, selIds);
+ selIds[0] = &ids.get("setArgument");
+ setArgumentSel = sels.getSelector(2, selIds);
+
+ zoneSel = sels.getNullarySelector(&ids.get("zone"));
+ }
+
+ bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ // NSInvocation.
+ if (E->isInstanceMessage() &&
+ E->getReceiverInterface() &&
+ E->getReceiverInterface()->getName() == "NSInvocation") {
+ StringRef selName;
+ if (E->getSelector() == getReturnValueSel)
+ selName = "getReturnValue";
+ else if (E->getSelector() == setReturnValueSel)
+ selName = "setReturnValue";
+ else if (E->getSelector() == getArgumentSel)
+ selName = "getArgument";
+ else if (E->getSelector() == setArgumentSel)
+ selName = "setArgument";
+
+ if (selName.empty())
+ return true;
+
+ Expr *parm = E->getArg(0)->IgnoreParenCasts();
+ QualType pointee = parm->getType()->getPointeeType();
+ if (pointee.isNull())
+ return true;
+
+ if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone) {
+ std::string err = "NSInvocation's ";
+ err += selName;
+ err += " is not safe to be used with an object with ownership other "
+ "than __unsafe_unretained";
+ Pass.TA.reportError(err, parm->getLocStart(), parm->getSourceRange());
+ }
+ return true;
+ }
+
+ // -zone.
+ if (E->isInstanceMessage() &&
+ E->getInstanceReceiver() &&
+ E->getSelector() == zoneSel &&
+ Pass.TA.hasDiagnostic(diag::err_unavailable,
+ diag::err_unavailable_message,
+ E->getInstanceReceiver()->getExprLoc())) {
+ // Calling -zone is meaningless in ARC, change it to nil.
+ Transaction Trans(Pass.TA);
+ Pass.TA.clearDiagnostic(diag::err_unavailable,
+ diag::err_unavailable_message,
+ E->getInstanceReceiver()->getExprLoc());
+ Pass.TA.replace(E->getSourceRange(), getNilString(Pass.Ctx));
+ }
+ return true;
+ }
+};
+
+} // anonymous namespace
+
+void trans::checkAPIUses(MigrationPass &pass) {
+ APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
+}
diff --git a/lib/ARCMigrate/TransARCAssign.cpp b/lib/ARCMigrate/TransARCAssign.cpp
index 8c00df5daa03..1f10196f9daa 100644
--- a/lib/ARCMigrate/TransARCAssign.cpp
+++ b/lib/ARCMigrate/TransARCAssign.cpp
@@ -28,7 +28,6 @@
using namespace clang;
using namespace arcmt;
using namespace trans;
-using llvm::StringRef;
namespace {
diff --git a/lib/ARCMigrate/TransAutoreleasePool.cpp b/lib/ARCMigrate/TransAutoreleasePool.cpp
index 5b8485432c52..08561f97f962 100644
--- a/lib/ARCMigrate/TransAutoreleasePool.cpp
+++ b/lib/ARCMigrate/TransAutoreleasePool.cpp
@@ -36,16 +36,15 @@
using namespace clang;
using namespace arcmt;
using namespace trans;
-using llvm::StringRef;
namespace {
class ReleaseCollector : public RecursiveASTVisitor<ReleaseCollector> {
Decl *Dcl;
- llvm::SmallVectorImpl<ObjCMessageExpr *> &Releases;
+ SmallVectorImpl<ObjCMessageExpr *> &Releases;
public:
- ReleaseCollector(Decl *D, llvm::SmallVectorImpl<ObjCMessageExpr *> &releases)
+ ReleaseCollector(Decl *D, SmallVectorImpl<ObjCMessageExpr *> &releases)
: Dcl(D), Releases(releases) { }
bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
@@ -82,7 +81,7 @@ public:
}
~AutoreleasePoolRewriter() {
- llvm::SmallVector<VarDecl *, 8> VarsToHandle;
+ SmallVector<VarDecl *, 8> VarsToHandle;
for (std::map<VarDecl *, PoolVarInfo>::iterator
I = PoolVars.begin(), E = PoolVars.end(); I != E; ++I) {
@@ -92,7 +91,7 @@ public:
// Check that we can handle/rewrite all references of the pool.
clearRefsIn(info.Dcl, info.Refs);
- for (llvm::SmallVectorImpl<PoolScope>::iterator
+ for (SmallVectorImpl<PoolScope>::iterator
scpI = info.Scopes.begin(),
scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
PoolScope &scope = *scpI;
@@ -116,7 +115,7 @@ public:
Pass.TA.removeStmt(info.Dcl);
// Add "@autoreleasepool { }"
- for (llvm::SmallVectorImpl<PoolScope>::iterator
+ for (SmallVectorImpl<PoolScope>::iterator
scpI = info.Scopes.begin(),
scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
PoolScope &scope = *scpI;
@@ -147,11 +146,11 @@ public:
}
// Remove rest of pool var references.
- for (llvm::SmallVectorImpl<PoolScope>::iterator
+ for (SmallVectorImpl<PoolScope>::iterator
scpI = info.Scopes.begin(),
scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
PoolScope &scope = *scpI;
- for (llvm::SmallVectorImpl<ObjCMessageExpr *>::iterator
+ for (SmallVectorImpl<ObjCMessageExpr *>::iterator
relI = scope.Releases.begin(),
relE = scope.Releases.end(); relI != relE; ++relI) {
clearUnavailableDiags(*relI);
@@ -162,7 +161,7 @@ public:
}
bool VisitCompoundStmt(CompoundStmt *S) {
- llvm::SmallVector<PoolScope, 4> Scopes;
+ SmallVector<PoolScope, 4> Scopes;
for (Stmt::child_iterator
I = S->body_begin(), E = S->body_end(); I != E; ++I) {
@@ -228,7 +227,7 @@ private:
Stmt::child_iterator Begin;
Stmt::child_iterator End;
bool IsFollowedBySimpleReturnStmt;
- llvm::SmallVector<ObjCMessageExpr *, 4> Releases;
+ SmallVector<ObjCMessageExpr *, 4> Releases;
PoolScope() : PoolVar(0), CompoundParent(0), Begin(), End(),
IsFollowedBySimpleReturnStmt(false) { }
@@ -287,6 +286,9 @@ private:
}
bool isInScope(SourceLocation loc) {
+ if (loc.isInvalid())
+ return false;
+
SourceManager &SM = Ctx.getSourceManager();
if (SM.isBeforeInTranslationUnit(loc, ScopeRange.getBegin()))
return false;
@@ -420,7 +422,7 @@ private:
struct PoolVarInfo {
DeclStmt *Dcl;
ExprSet Refs;
- llvm::SmallVector<PoolScope, 2> Scopes;
+ SmallVector<PoolScope, 2> Scopes;
PoolVarInfo() : Dcl(0) { }
};
diff --git a/lib/ARCMigrate/TransBlockObjCVariable.cpp b/lib/ARCMigrate/TransBlockObjCVariable.cpp
index 0e342b7a8f8c..48c0ca9cefe5 100644
--- a/lib/ARCMigrate/TransBlockObjCVariable.cpp
+++ b/lib/ARCMigrate/TransBlockObjCVariable.cpp
@@ -32,7 +32,6 @@
using namespace clang;
using namespace arcmt;
using namespace trans;
-using llvm::StringRef;
namespace {
@@ -75,7 +74,7 @@ public:
RootBlockObjCVarRewriter(MigrationPass &pass) : Pass(pass) { }
bool VisitBlockDecl(BlockDecl *block) {
- llvm::SmallVector<VarDecl *, 4> BlockVars;
+ SmallVector<VarDecl *, 4> BlockVars;
for (BlockDecl::capture_iterator
I = block->capture_begin(), E = block->capture_end(); I != E; ++I) {
@@ -101,7 +100,7 @@ public:
bool useWeak = canApplyWeak(Pass.Ctx, var->getType());
SourceManager &SM = Pass.Ctx.getSourceManager();
Transaction Trans(Pass.TA);
- Pass.TA.replaceText(SM.getInstantiationLoc(attr->getLocation()),
+ Pass.TA.replaceText(SM.getExpansionLoc(attr->getLocation()),
"__block",
useWeak ? "__weak" : "__unsafe_unretained");
}
diff --git a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
index d0bc332ff160..3ad05e683c78 100644
--- a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
+++ b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
@@ -22,11 +22,53 @@
#include "Transforms.h"
#include "Internals.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/SourceManager.h"
using namespace clang;
using namespace arcmt;
using namespace trans;
-using llvm::StringRef;
+
+static bool isEmptyARCMTMacroStatement(NullStmt *S,
+ std::vector<SourceLocation> &MacroLocs,
+ ASTContext &Ctx) {
+ if (!S->hasLeadingEmptyMacro())
+ return false;
+
+ SourceLocation SemiLoc = S->getSemiLoc();
+ if (SemiLoc.isInvalid() || SemiLoc.isMacroID())
+ return false;
+
+ if (MacroLocs.empty())
+ return false;
+
+ SourceManager &SM = Ctx.getSourceManager();
+ std::vector<SourceLocation>::iterator
+ I = std::upper_bound(MacroLocs.begin(), MacroLocs.end(), SemiLoc,
+ SourceManager::LocBeforeThanCompare(SM));
+ --I;
+ SourceLocation
+ AfterMacroLoc = I->getLocWithOffset(getARCMTMacroName().size());
+ assert(AfterMacroLoc.isFileID());
+
+ if (AfterMacroLoc == SemiLoc)
+ return true;
+
+ int RelOffs = 0;
+ if (!SM.isInSameSLocAddrSpace(AfterMacroLoc, SemiLoc, &RelOffs))
+ return false;
+ if (RelOffs < 0)
+ return false;
+
+ // We make the reasonable assumption that a semicolon after 100 characters
+ // means that it is not the next token after our macro. If this assumption
+ // fails it is not critical, we will just fail to clear out, e.g., an empty
+ // 'if'.
+ if (RelOffs - getARCMTMacroName().size() > 100)
+ return false;
+
+ SourceLocation AfterMacroSemiLoc = findSemiAfterLocation(AfterMacroLoc, Ctx);
+ return AfterMacroSemiLoc == SemiLoc;
+}
namespace {
@@ -34,14 +76,14 @@ namespace {
/// transformations.
class EmptyChecker : public StmtVisitor<EmptyChecker, bool> {
ASTContext &Ctx;
- llvm::DenseSet<unsigned> &MacroLocs;
+ std::vector<SourceLocation> &MacroLocs;
public:
- EmptyChecker(ASTContext &ctx, llvm::DenseSet<unsigned> &macroLocs)
+ EmptyChecker(ASTContext &ctx, std::vector<SourceLocation> &macroLocs)
: Ctx(ctx), MacroLocs(macroLocs) { }
bool VisitNullStmt(NullStmt *S) {
- return isMacroLoc(S->getLeadingEmptyMacroLoc());
+ return isEmptyARCMTMacroStatement(S, MacroLocs, Ctx);
}
bool VisitCompoundStmt(CompoundStmt *S) {
if (S->body_empty())
@@ -103,23 +145,14 @@ public:
return false;
return Visit(S->getSubStmt());
}
-
-private:
- bool isMacroLoc(SourceLocation loc) {
- if (loc.isInvalid()) return false;
- return MacroLocs.count(loc.getRawEncoding());
- }
};
class EmptyStatementsRemover :
public RecursiveASTVisitor<EmptyStatementsRemover> {
MigrationPass &Pass;
- llvm::DenseSet<unsigned> &MacroLocs;
public:
- EmptyStatementsRemover(MigrationPass &pass,
- llvm::DenseSet<unsigned> &macroLocs)
- : Pass(pass), MacroLocs(macroLocs) { }
+ EmptyStatementsRemover(MigrationPass &pass) : Pass(pass) { }
bool TraverseStmtExpr(StmtExpr *E) {
CompoundStmt *S = E->getSubStmt();
@@ -139,17 +172,12 @@ public:
return true;
}
- bool isMacroLoc(SourceLocation loc) {
- if (loc.isInvalid()) return false;
- return MacroLocs.count(loc.getRawEncoding());
- }
-
ASTContext &getContext() { return Pass.Ctx; }
private:
void check(Stmt *S) {
if (!S) return;
- if (EmptyChecker(Pass.Ctx, MacroLocs).Visit(S)) {
+ if (EmptyChecker(Pass.Ctx, Pass.ARCMTMacroLocs).Visit(S)) {
Transaction Trans(Pass.TA);
Pass.TA.removeStmt(S);
}
@@ -158,8 +186,8 @@ private:
} // anonymous namespace
-static bool isBodyEmpty(CompoundStmt *body,
- ASTContext &Ctx, llvm::DenseSet<unsigned> &MacroLocs) {
+static bool isBodyEmpty(CompoundStmt *body, ASTContext &Ctx,
+ std::vector<SourceLocation> &MacroLocs) {
for (CompoundStmt::body_iterator
I = body->body_begin(), E = body->body_end(); I != E; ++I)
if (!EmptyChecker(Ctx, MacroLocs).Visit(*I))
@@ -168,8 +196,7 @@ static bool isBodyEmpty(CompoundStmt *body,
return true;
}
-static void removeDeallocMethod(MigrationPass &pass,
- llvm::DenseSet<unsigned> &MacroLocs) {
+static void removeDeallocMethod(MigrationPass &pass) {
ASTContext &Ctx = pass.Ctx;
TransformActions &TA = pass.TA;
DeclContext *DC = Ctx.getTranslationUnitDecl();
@@ -184,7 +211,7 @@ static void removeDeallocMethod(MigrationPass &pass,
ObjCMethodDecl *MD = *MI;
if (MD->getMethodFamily() == OMF_dealloc) {
if (MD->hasBody() &&
- isBodyEmpty(MD->getCompoundBody(), Ctx, MacroLocs)) {
+ isBodyEmpty(MD->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) {
Transaction Trans(TA);
TA.remove(MD->getSourceRange());
}
@@ -195,14 +222,9 @@ static void removeDeallocMethod(MigrationPass &pass,
}
void trans::removeEmptyStatementsAndDealloc(MigrationPass &pass) {
- llvm::DenseSet<unsigned> MacroLocs;
- for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i)
- MacroLocs.insert(pass.ARCMTMacroLocs[i].getRawEncoding());
-
- EmptyStatementsRemover(pass, MacroLocs)
- .TraverseDecl(pass.Ctx.getTranslationUnitDecl());
+ EmptyStatementsRemover(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
- removeDeallocMethod(pass, MacroLocs);
+ removeDeallocMethod(pass);
for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) {
Transaction Trans(pass.TA);
diff --git a/lib/ARCMigrate/TransProperties.cpp b/lib/ARCMigrate/TransProperties.cpp
index 872c95e1a444..ca845b6b330d 100644
--- a/lib/ARCMigrate/TransProperties.cpp
+++ b/lib/ARCMigrate/TransProperties.cpp
@@ -40,12 +40,12 @@
using namespace clang;
using namespace arcmt;
using namespace trans;
-using llvm::StringRef;
namespace {
class PropertiesRewriter {
MigrationPass &Pass;
+ ObjCImplementationDecl *CurImplD;
struct PropData {
ObjCPropertyDecl *PropD;
@@ -55,7 +55,7 @@ class PropertiesRewriter {
PropData(ObjCPropertyDecl *propD) : PropD(propD), IvarD(0), ImplD(0) { }
};
- typedef llvm::SmallVector<PropData, 2> PropsTy;
+ typedef SmallVector<PropData, 2> PropsTy;
typedef std::map<unsigned, PropsTy> AtPropDeclsTy;
AtPropDeclsTy AtProps;
@@ -63,6 +63,7 @@ public:
PropertiesRewriter(MigrationPass &pass) : Pass(pass) { }
void doTransform(ObjCImplementationDecl *D) {
+ CurImplD = D;
ObjCInterfaceDecl *iface = D->getClassInterface();
if (!iface)
return;
@@ -135,8 +136,16 @@ private:
return;
}
- if (propAttrs & ObjCPropertyDecl::OBJC_PR_assign)
+ if (propAttrs & ObjCPropertyDecl::OBJC_PR_assign) {
+ if (hasIvarAssignedAPlusOneObject(props)) {
+ rewriteAttribute("assign", "strong", atLoc);
+ return;
+ }
return rewriteAssign(props, atLoc);
+ }
+
+ if (hasIvarAssignedAPlusOneObject(props))
+ return maybeAddStrongAttr(props, atLoc);
return maybeAddWeakOrUnsafeUnretainedAttr(props, atLoc);
}
@@ -163,15 +172,15 @@ private:
void maybeAddWeakOrUnsafeUnretainedAttr(PropsTy &props,
SourceLocation atLoc) const {
ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
- if ((propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) &&
- hasNoBackingIvars(props))
- return;
bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props));
- bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained",
- atLoc);
- if (!addedAttr)
- canUseWeak = false;
+ if (!(propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) ||
+ !hasAllIvarsBacked(props)) {
+ bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained",
+ atLoc);
+ if (!addedAttr)
+ canUseWeak = false;
+ }
for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
if (isUserDeclared(I->IvarD))
@@ -187,7 +196,26 @@ private:
}
}
- bool rewriteAttribute(llvm::StringRef fromAttr, llvm::StringRef toAttr,
+ void maybeAddStrongAttr(PropsTy &props, SourceLocation atLoc) const {
+ ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
+
+ if (!(propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) ||
+ !hasAllIvarsBacked(props)) {
+ addAttribute("strong", atLoc);
+ }
+
+ 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_objc_property_default_assign_on_object,
+ I->ImplD->getLocation());
+ }
+ }
+ }
+
+ bool rewriteAttribute(StringRef fromAttr, StringRef toAttr,
SourceLocation atLoc) const {
if (atLoc.isMacroID())
return false;
@@ -199,7 +227,7 @@ private:
// 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 false;
@@ -214,7 +242,7 @@ private:
if (tok.isNot(tok::at)) return false;
lexer.LexFromRawLexer(tok);
if (tok.isNot(tok::raw_identifier)) return false;
- if (llvm::StringRef(tok.getRawIdentifierData(), tok.getLength())
+ if (StringRef(tok.getRawIdentifierData(), tok.getLength())
!= "property")
return false;
lexer.LexFromRawLexer(tok);
@@ -226,7 +254,7 @@ private:
while (1) {
if (tok.isNot(tok::raw_identifier)) return false;
- llvm::StringRef ident(tok.getRawIdentifierData(), tok.getLength());
+ StringRef ident(tok.getRawIdentifierData(), tok.getLength());
if (ident == fromAttr) {
Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr);
return true;
@@ -243,7 +271,7 @@ private:
return false;
}
- bool addAttribute(llvm::StringRef attr, SourceLocation atLoc) const {
+ bool addAttribute(StringRef attr, SourceLocation atLoc) const {
if (atLoc.isMacroID())
return false;
@@ -254,7 +282,7 @@ private:
// 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 false;
@@ -269,7 +297,7 @@ private:
if (tok.isNot(tok::at)) return false;
lexer.LexFromRawLexer(tok);
if (tok.isNot(tok::raw_identifier)) return false;
- if (llvm::StringRef(tok.getRawIdentifierData(), tok.getLength())
+ if (StringRef(tok.getRawIdentifierData(), tok.getLength())
!= "property")
return false;
lexer.LexFromRawLexer(tok);
@@ -291,6 +319,45 @@ private:
return true;
}
+ class PlusOneAssign : public RecursiveASTVisitor<PlusOneAssign> {
+ ObjCIvarDecl *Ivar;
+ public:
+ PlusOneAssign(ObjCIvarDecl *D) : Ivar(D) {}
+
+ bool VisitBinAssign(BinaryOperator *E) {
+ Expr *lhs = E->getLHS()->IgnoreParenImpCasts();
+ if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(lhs)) {
+ if (RE->getDecl() != Ivar)
+ return true;
+
+ if (ObjCMessageExpr *
+ ME = dyn_cast<ObjCMessageExpr>(E->getRHS()->IgnoreParenCasts()))
+ if (ME->getMethodFamily() == OMF_retain)
+ return false;
+
+ ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getRHS());
+ while (implCE && implCE->getCastKind() == CK_BitCast)
+ implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr());
+
+ if (implCE && implCE->getCastKind() == CK_ARCConsumeObject)
+ return false;
+ }
+
+ return true;
+ }
+ };
+
+ bool hasIvarAssignedAPlusOneObject(PropsTy &props) const {
+ for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
+ PlusOneAssign oneAssign(I->IvarD);
+ bool notFound = oneAssign.TraverseDecl(CurImplD);
+ if (!notFound)
+ return true;
+ }
+
+ return false;
+ }
+
bool hasIvarWithExplicitOwnership(PropsTy &props) const {
for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
if (isUserDeclared(I->IvarD)) {
@@ -305,9 +372,9 @@ private:
return false;
}
- bool hasNoBackingIvars(PropsTy &props) const {
+ bool hasAllIvarsBacked(PropsTy &props) const {
for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
- if (I->IvarD)
+ if (!isUserDeclared(I->IvarD))
return false;
return true;
diff --git a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
index ed6ed0adfdf2..394f8480e112 100644
--- a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
+++ b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
@@ -25,7 +25,6 @@
using namespace clang;
using namespace arcmt;
using namespace trans;
-using llvm::StringRef;
namespace {
@@ -130,10 +129,9 @@ public:
// Change the -release to "receiver = nil" in a finally to avoid a leak
// when an exception is thrown.
Pass.TA.replace(E->getSourceRange(), rec->getSourceRange());
- if (Pass.Ctx.Idents.get("nil").hasMacroDefinition())
- Pass.TA.insertAfterToken(rec->getLocEnd(), " = nil");
- else
- Pass.TA.insertAfterToken(rec->getLocEnd(), " = 0");
+ std::string str = " = ";
+ str += getNilString(Pass.Ctx);
+ Pass.TA.insertAfterToken(rec->getLocEnd(), str);
return true;
}
diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp
index 1cacd6d84e6d..69fb2e8949e4 100644
--- a/lib/ARCMigrate/TransUnbridgedCasts.cpp
+++ b/lib/ARCMigrate/TransUnbridgedCasts.cpp
@@ -36,25 +36,32 @@
#include "Internals.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/AST/ParentMap.h"
#include "clang/Basic/SourceManager.h"
using namespace clang;
using namespace arcmt;
using namespace trans;
-using llvm::StringRef;
namespace {
class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
MigrationPass &Pass;
IdentifierInfo *SelfII;
+ llvm::OwningPtr<ParentMap> StmtMap;
+
public:
UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass) {
SelfII = &Pass.Ctx.Idents.get("self");
}
+ void transformBody(Stmt *body) {
+ StmtMap.reset(new ParentMap(body));
+ TraverseStmt(body);
+ }
+
bool VisitCastExpr(CastExpr *E) {
- if (E->getCastKind() != CK_AnyPointerToObjCPointerCast
+ if (E->getCastKind() != CK_CPointerToObjCPointerCast
&& E->getCastKind() != CK_BitCast)
return true;
@@ -139,13 +146,21 @@ private:
}
void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
+ Transaction Trans(Pass.TA);
+ rewriteToBridgedCast(E, Kind, Trans);
+ }
+
+ void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind,
+ Transaction &Trans) {
TransformActions &TA = Pass.TA;
// We will remove the compiler diagnostic.
if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
diag::err_arc_cast_requires_bridge,
- E->getLocStart()))
+ E->getLocStart())) {
+ Trans.abort();
return;
+ }
StringRef bridge;
switch(Kind) {
@@ -157,7 +172,6 @@ private:
bridge = "__bridge_retained "; break;
}
- Transaction Trans(TA);
TA.clearDiagnostic(diag::err_arc_mismatched_cast,
diag::err_arc_cast_requires_bridge,
E->getLocStart());
@@ -168,7 +182,7 @@ private:
llvm::SmallString<128> newCast;
newCast += '(';
newCast += bridge;
- newCast += E->getType().getAsString(Pass.Ctx.PrintingPolicy);
+ newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
newCast += ')';
if (isa<ParenExpr>(E->getSubExpr())) {
@@ -181,16 +195,111 @@ private:
}
}
+ void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) {
+ Transaction Trans(Pass.TA);
+ Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange());
+ rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans);
+ }
+
void transformObjCToNonObjCCast(CastExpr *E) {
if (isSelf(E->getSubExpr()))
return rewriteToBridgedCast(E, OBC_Bridge);
+
+ CallExpr *callE;
+ if (isPassedToCFRetain(E, callE))
+ return rewriteCastForCFRetain(E, callE);
+
+ ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr());
+ if (family == OMF_retain)
+ return rewriteToBridgedCast(E, OBC_BridgeRetained);
+
+ if (family == OMF_autorelease || family == OMF_release) {
+ std::string err = "it is not safe to cast to '";
+ err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
+ err += "' the result of '";
+ err += family == OMF_autorelease ? "autorelease" : "release";
+ err += "' message; a __bridge cast may result in a pointer to a "
+ "destroyed object and a __bridge_retained may leak the object";
+ Pass.TA.reportError(err, E->getLocStart(),
+ E->getSubExpr()->getSourceRange());
+ Stmt *parent = E;
+ do {
+ parent = StmtMap->getParentIgnoreParenImpCasts(parent);
+ } while (parent && isa<ExprWithCleanups>(parent));
+
+ if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) {
+ std::string note = "remove the cast and change return type of function "
+ "to '";
+ note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy());
+ note += "' to have the object automatically autoreleased";
+ Pass.TA.reportNote(note, retS->getLocStart());
+ }
+ }
+
+ if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getSubExpr())){
+ if (implCE->getCastKind() == CK_ARCConsumeObject)
+ return rewriteToBridgedCast(E, OBC_BridgeRetained);
+ if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)
+ return rewriteToBridgedCast(E, OBC_Bridge);
+ }
+
+ bool isConsumed = false;
+ if (isPassedToCParamWithKnownOwnership(E, isConsumed))
+ return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained
+ : OBC_Bridge);
}
- bool isSelf(Expr *E) {
+ static ObjCMethodFamily getFamilyOfMessage(Expr *E) {
+ E = E->IgnoreParenCasts();
+ if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
+ return ME->getMethodFamily();
+
+ return OMF_None;
+ }
+
+ bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const {
+ if ((callE = dyn_cast_or_null<CallExpr>(
+ StmtMap->getParentIgnoreParenImpCasts(E))))
+ if (FunctionDecl *
+ FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
+ if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
+ FD->getParent()->isTranslationUnit() &&
+ FD->getLinkage() == ExternalLinkage)
+ return true;
+
+ return false;
+ }
+
+ bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const {
+ if (CallExpr *callE = dyn_cast_or_null<CallExpr>(
+ StmtMap->getParentIgnoreParenImpCasts(E)))
+ if (FunctionDecl *
+ FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) {
+ unsigned i = 0;
+ for (unsigned e = callE->getNumArgs(); i != e; ++i) {
+ Expr *arg = callE->getArg(i);
+ if (arg == E || arg->IgnoreParenImpCasts() == E)
+ break;
+ }
+ if (i < callE->getNumArgs()) {
+ ParmVarDecl *PD = FD->getParamDecl(i);
+ if (PD->getAttr<CFConsumedAttr>()) {
+ isConsumed = true;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ bool isSelf(Expr *E) const {
E = E->IgnoreParenLValueCasts();
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- if (DRE->getDecl()->getIdentifier() == SelfII)
- return true;
+ if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
+ if (IPD->getIdentifier() == SelfII)
+ return true;
+
return false;
}
};
@@ -198,6 +307,6 @@ private:
} // end anonymous namespace
void trans::rewriteUnbridgedCasts(MigrationPass &pass) {
- UnbridgedCastRewriter trans(pass);
+ BodyTransform<UnbridgedCastRewriter> trans(pass);
trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
}
diff --git a/lib/ARCMigrate/TransUnusedInitDelegate.cpp b/lib/ARCMigrate/TransUnusedInitDelegate.cpp
index 1019ab4ff1f6..e2aa6ff93cf3 100644
--- a/lib/ARCMigrate/TransUnusedInitDelegate.cpp
+++ b/lib/ARCMigrate/TransUnusedInitDelegate.cpp
@@ -27,7 +27,6 @@
using namespace clang;
using namespace arcmt;
using namespace trans;
-using llvm::StringRef;
namespace {
diff --git a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
index 07ccf70d4dfb..1dbe81114947 100644
--- a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
+++ b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
@@ -19,7 +19,6 @@
using namespace clang;
using namespace arcmt;
using namespace trans;
-using llvm::StringRef;
namespace {
diff --git a/lib/ARCMigrate/TransformActions.cpp b/lib/ARCMigrate/TransformActions.cpp
index c99940b494b9..ec676e909a3b 100644
--- a/lib/ARCMigrate/TransformActions.cpp
+++ b/lib/ARCMigrate/TransformActions.cpp
@@ -13,10 +13,8 @@
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/DenseSet.h"
#include <map>
-
using namespace clang;
using namespace arcmt;
-using llvm::StringRef;
namespace {
@@ -46,9 +44,9 @@ class TransformActionsImpl {
ActionKind Kind;
SourceLocation Loc;
SourceRange R1, R2;
- llvm::StringRef Text1, Text2;
+ StringRef Text1, Text2;
Stmt *S;
- llvm::SmallVector<unsigned, 2> DiagIDs;
+ SmallVector<unsigned, 2> DiagIDs;
};
std::vector<ActionData> CachedActions;
@@ -70,11 +68,11 @@ class TransformActionsImpl {
SourceLocation beginLoc = range.getBegin(), endLoc = range.getEnd();
assert(beginLoc.isValid() && endLoc.isValid());
if (range.isTokenRange()) {
- Begin = FullSourceLoc(srcMgr.getInstantiationLoc(beginLoc), srcMgr);
+ Begin = FullSourceLoc(srcMgr.getExpansionLoc(beginLoc), srcMgr);
End = FullSourceLoc(getLocForEndOfToken(endLoc, srcMgr, PP), srcMgr);
} else {
- Begin = FullSourceLoc(srcMgr.getInstantiationLoc(beginLoc), srcMgr);
- End = FullSourceLoc(srcMgr.getInstantiationLoc(endLoc), srcMgr);
+ Begin = FullSourceLoc(srcMgr.getExpansionLoc(beginLoc), srcMgr);
+ End = FullSourceLoc(srcMgr.getExpansionLoc(endLoc), srcMgr);
}
assert(Begin.isValid() && End.isValid());
}
@@ -104,7 +102,7 @@ class TransformActionsImpl {
}
};
- typedef llvm::SmallVector<StringRef, 2> TextsVec;
+ typedef SmallVector<StringRef, 2> TextsVec;
typedef std::map<FullSourceLoc, TextsVec, FullSourceLoc::BeforeThanCompare>
InsertsMap;
InsertsMap Inserts;
@@ -130,19 +128,19 @@ public:
bool isInTransaction() const { return IsInTransaction; }
- void insert(SourceLocation loc, llvm::StringRef text);
- void insertAfterToken(SourceLocation loc, llvm::StringRef text);
+ void insert(SourceLocation loc, StringRef text);
+ void insertAfterToken(SourceLocation loc, StringRef text);
void remove(SourceRange range);
void removeStmt(Stmt *S);
- void replace(SourceRange range, llvm::StringRef text);
+ void replace(SourceRange range, StringRef text);
void replace(SourceRange range, SourceRange replacementRange);
- void replaceStmt(Stmt *S, llvm::StringRef text);
- void replaceText(SourceLocation loc, llvm::StringRef text,
- llvm::StringRef replacementText);
+ void replaceStmt(Stmt *S, StringRef text);
+ void replaceText(SourceLocation loc, StringRef text,
+ StringRef replacementText);
void increaseIndentation(SourceRange range,
SourceLocation parentIndent);
- bool clearDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range);
+ bool clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range);
void applyRewrites(TransformActions::RewriteReceiver &receiver);
@@ -151,17 +149,17 @@ private:
bool canInsertAfterToken(SourceLocation loc);
bool canRemoveRange(SourceRange range);
bool canReplaceRange(SourceRange range, SourceRange replacementRange);
- bool canReplaceText(SourceLocation loc, llvm::StringRef text);
+ bool canReplaceText(SourceLocation loc, StringRef text);
void commitInsert(SourceLocation loc, StringRef text);
void commitInsertAfterToken(SourceLocation loc, StringRef text);
void commitRemove(SourceRange range);
void commitRemoveStmt(Stmt *S);
void commitReplace(SourceRange range, SourceRange replacementRange);
- void commitReplaceText(SourceLocation loc, llvm::StringRef text,
- llvm::StringRef replacementText);
+ void commitReplaceText(SourceLocation loc, StringRef text,
+ StringRef replacementText);
void commitIncreaseIndentation(SourceRange range,SourceLocation parentIndent);
- void commitClearDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range);
+ void commitClearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range);
void addRemoval(CharSourceRange range);
void addInsertion(SourceLocation loc, StringRef text);
@@ -364,7 +362,7 @@ void TransformActionsImpl::increaseIndentation(SourceRange range,
CachedActions.push_back(data);
}
-bool TransformActionsImpl::clearDiagnostic(llvm::ArrayRef<unsigned> IDs,
+bool TransformActionsImpl::clearDiagnostic(ArrayRef<unsigned> IDs,
SourceRange range) {
assert(IsInTransaction && "Actions only allowed during a transaction");
if (!CapturedDiags.hasDiagnostic(IDs, range))
@@ -383,7 +381,7 @@ bool TransformActionsImpl::canInsert(SourceLocation loc) {
return false;
SourceManager &SM = Ctx.getSourceManager();
- if (SM.isInSystemHeader(SM.getInstantiationLoc(loc)))
+ if (SM.isInSystemHeader(SM.getExpansionLoc(loc)))
return false;
if (loc.isFileID())
@@ -396,7 +394,7 @@ bool TransformActionsImpl::canInsertAfterToken(SourceLocation loc) {
return false;
SourceManager &SM = Ctx.getSourceManager();
- if (SM.isInSystemHeader(SM.getInstantiationLoc(loc)))
+ if (SM.isInSystemHeader(SM.getExpansionLoc(loc)))
return false;
if (loc.isFileID())
@@ -418,14 +416,14 @@ bool TransformActionsImpl::canReplaceText(SourceLocation loc, StringRef text) {
return false;
SourceManager &SM = Ctx.getSourceManager();
- loc = SM.getInstantiationLoc(loc);
+ loc = SM.getExpansionLoc(loc);
// Break down the source location.
std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(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 false;
@@ -479,9 +477,9 @@ void TransformActionsImpl::commitReplaceText(SourceLocation loc,
StringRef text,
StringRef replacementText) {
SourceManager &SM = Ctx.getSourceManager();
- loc = SM.getInstantiationLoc(loc);
+ loc = SM.getExpansionLoc(loc);
// canReplaceText already checked if loc points at text.
- SourceLocation afterText = loc.getFileLocWithOffset(text.size());
+ SourceLocation afterText = loc.getLocWithOffset(text.size());
addRemoval(CharSourceRange::getCharRange(loc, afterText));
commitInsert(loc, replacementText);
@@ -493,17 +491,17 @@ void TransformActionsImpl::commitIncreaseIndentation(SourceRange range,
IndentationRanges.push_back(
std::make_pair(CharRange(CharSourceRange::getTokenRange(range),
SM, PP),
- SM.getInstantiationLoc(parentIndent)));
+ SM.getExpansionLoc(parentIndent)));
}
-void TransformActionsImpl::commitClearDiagnostic(llvm::ArrayRef<unsigned> IDs,
+void TransformActionsImpl::commitClearDiagnostic(ArrayRef<unsigned> IDs,
SourceRange range) {
CapturedDiags.clearDiagnostic(IDs, range);
}
void TransformActionsImpl::addInsertion(SourceLocation loc, StringRef text) {
SourceManager &SM = Ctx.getSourceManager();
- loc = SM.getInstantiationLoc(loc);
+ loc = SM.getExpansionLoc(loc);
for (std::list<CharRange>::reverse_iterator
I = Removals.rbegin(), E = Removals.rend(); I != E; ++I) {
if (!SM.isBeforeInTranslationUnit(loc, I->End))
@@ -591,16 +589,16 @@ SourceLocation TransformActionsImpl::getLocForEndOfToken(SourceLocation loc,
SourceManager &SM,
Preprocessor &PP) {
if (loc.isMacroID())
- loc = SM.getInstantiationRange(loc).second;
+ loc = SM.getExpansionRange(loc).second;
return PP.getLocForEndOfToken(loc);
}
TransformActions::RewriteReceiver::~RewriteReceiver() { }
-TransformActions::TransformActions(Diagnostic &diag,
+TransformActions::TransformActions(DiagnosticsEngine &diag,
CapturedDiagList &capturedDiags,
ASTContext &ctx, Preprocessor &PP)
- : Diags(diag), CapturedDiags(capturedDiags) {
+ : Diags(diag), CapturedDiags(capturedDiags), ReportedErrors(false) {
Impl = new TransformActionsImpl(capturedDiags, ctx, PP);
}
@@ -621,12 +619,12 @@ void TransformActions::abortTransaction() {
}
-void TransformActions::insert(SourceLocation loc, llvm::StringRef text) {
+void TransformActions::insert(SourceLocation loc, StringRef text) {
static_cast<TransformActionsImpl*>(Impl)->insert(loc, text);
}
void TransformActions::insertAfterToken(SourceLocation loc,
- llvm::StringRef text) {
+ StringRef text) {
static_cast<TransformActionsImpl*>(Impl)->insertAfterToken(loc, text);
}
@@ -638,7 +636,7 @@ void TransformActions::removeStmt(Stmt *S) {
static_cast<TransformActionsImpl*>(Impl)->removeStmt(S);
}
-void TransformActions::replace(SourceRange range, llvm::StringRef text) {
+void TransformActions::replace(SourceRange range, StringRef text) {
static_cast<TransformActionsImpl*>(Impl)->replace(range, text);
}
@@ -647,12 +645,12 @@ void TransformActions::replace(SourceRange range,
static_cast<TransformActionsImpl*>(Impl)->replace(range, replacementRange);
}
-void TransformActions::replaceStmt(Stmt *S, llvm::StringRef text) {
+void TransformActions::replaceStmt(Stmt *S, StringRef text) {
static_cast<TransformActionsImpl*>(Impl)->replaceStmt(S, text);
}
-void TransformActions::replaceText(SourceLocation loc, llvm::StringRef text,
- llvm::StringRef replacementText) {
+void TransformActions::replaceText(SourceLocation loc, StringRef text,
+ StringRef replacementText) {
static_cast<TransformActionsImpl*>(Impl)->replaceText(loc, text,
replacementText);
}
@@ -663,7 +661,7 @@ void TransformActions::increaseIndentation(SourceRange range,
parentIndent);
}
-bool TransformActions::clearDiagnostic(llvm::ArrayRef<unsigned> IDs,
+bool TransformActions::clearDiagnostic(ArrayRef<unsigned> IDs,
SourceRange range) {
return static_cast<TransformActionsImpl*>(Impl)->clearDiagnostic(IDs, range);
}
@@ -672,7 +670,7 @@ void TransformActions::applyRewrites(RewriteReceiver &receiver) {
static_cast<TransformActionsImpl*>(Impl)->applyRewrites(receiver);
}
-void TransformActions::reportError(llvm::StringRef error, SourceLocation loc,
+void TransformActions::reportError(StringRef error, SourceLocation loc,
SourceRange range) {
assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() &&
"Errors should be emitted out of a transaction");
@@ -683,9 +681,10 @@ void TransformActions::reportError(llvm::StringRef error, SourceLocation loc,
= Diags.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Error,
rewriteErr);
Diags.Report(loc, diagID) << range;
+ ReportedErrors = true;
}
-void TransformActions::reportNote(llvm::StringRef note, SourceLocation loc,
+void TransformActions::reportNote(StringRef note, SourceLocation loc,
SourceRange range) {
assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() &&
"Errors should be emitted out of a transaction");
diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp
index 7bd95e54bc27..4244fafe07d4 100644
--- a/lib/ARCMigrate/Transforms.cpp
+++ b/lib/ARCMigrate/Transforms.cpp
@@ -23,7 +23,6 @@
using namespace clang;
using namespace arcmt;
using namespace trans;
-using llvm::StringRef;
//===----------------------------------------------------------------------===//
// Helpers.
@@ -92,11 +91,23 @@ bool trans::canApplyWeak(ASTContext &Ctx, QualType type) {
/// source location will be invalid.
SourceLocation trans::findLocationAfterSemi(SourceLocation loc,
ASTContext &Ctx) {
+ SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx);
+ if (SemiLoc.isInvalid())
+ return SourceLocation();
+ return SemiLoc.getLocWithOffset(1);
+}
+
+/// \brief \arg Loc is the end of a statement range. This returns the location
+/// of the semicolon following the statement.
+/// If no semicolon is found or the location is inside a macro, the returned
+/// source location will be invalid.
+SourceLocation trans::findSemiAfterLocation(SourceLocation loc,
+ ASTContext &Ctx) {
SourceManager &SM = Ctx.getSourceManager();
if (loc.isMacroID()) {
if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOptions()))
return SourceLocation();
- loc = SM.getInstantiationRange(loc).second;
+ loc = SM.getExpansionRange(loc).second;
}
loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOptions());
@@ -105,7 +116,7 @@ SourceLocation trans::findLocationAfterSemi(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();
@@ -120,7 +131,7 @@ SourceLocation trans::findLocationAfterSemi(SourceLocation loc,
if (tok.isNot(tok::semi))
return SourceLocation();
- return tok.getLocation().getFileLocWithOffset(1);
+ return tok.getLocation();
}
bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) {
@@ -155,7 +166,8 @@ bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) {
bool trans::isGlobalVar(Expr *E) {
E = E->IgnoreParenCasts();
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- return DRE->getDecl()->getDeclContext()->isFileContext();
+ return DRE->getDecl()->getDeclContext()->isFileContext() &&
+ DRE->getDecl()->getLinkage() == ExternalLinkage;
if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
return isGlobalVar(condOp->getTrueExpr()) &&
isGlobalVar(condOp->getFalseExpr());
@@ -163,6 +175,13 @@ bool trans::isGlobalVar(Expr *E) {
return false;
}
+StringRef trans::getNilString(ASTContext &Ctx) {
+ if (Ctx.Idents.get("nil").hasMacroDefinition())
+ return "nil";
+ else
+ return "0";
+}
+
namespace {
class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> {
@@ -283,6 +302,7 @@ static void independentTransforms(MigrationPass &pass) {
makeAssignARCSafe(pass);
rewriteUnbridgedCasts(pass);
rewriteBlockObjCVariable(pass);
+ checkAPIUses(pass);
}
std::vector<TransformFn> arcmt::getAllTransformations() {
diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h
index b47d6d8e9b8b..5e4db56dc894 100644
--- a/lib/ARCMigrate/Transforms.h
+++ b/lib/ARCMigrate/Transforms.h
@@ -37,6 +37,7 @@ void removeZeroOutPropsInDealloc(MigrationPass &pass);
void rewriteProperties(MigrationPass &pass);
void rewriteBlockObjCVariable(MigrationPass &pass);
void rewriteUnusedInitDelegate(MigrationPass &pass);
+void checkAPIUses(MigrationPass &pass);
void removeEmptyStatementsAndDealloc(MigrationPass &pass);
@@ -53,9 +54,16 @@ bool canApplyWeak(ASTContext &Ctx, QualType type);
/// source location will be invalid.
SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx);
+/// \brief \arg Loc is the end of a statement range. This returns the location
+/// of the semicolon following the statement.
+/// If no semicolon is found or the location is inside a macro, the returned
+/// source location will be invalid.
+SourceLocation findSemiAfterLocation(SourceLocation loc, ASTContext &Ctx);
+
bool hasSideEffects(Expr *E, ASTContext &Ctx);
bool isGlobalVar(Expr *E);
-
+/// \brief Returns "nil" or "0" if 'nil' macro is not actually defined.
+StringRef getNilString(ASTContext &Ctx);
template <typename BODY_TRANS>
class BodyTransform : public RecursiveASTVisitor<BodyTransform<BODY_TRANS> > {
@@ -65,7 +73,8 @@ public:
BodyTransform(MigrationPass &pass) : Pass(pass) { }
bool TraverseStmt(Stmt *rootS) {
- BODY_TRANS(Pass).transformBody(rootS);
+ if (rootS)
+ BODY_TRANS(Pass).transformBody(rootS);
return true;
}
};
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index ebe99b12cdab..6f63a32dd2ed 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -13,7 +13,10 @@
#include "clang/AST/APValue.h"
#include "clang/AST/CharUnits.h"
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
namespace {
@@ -89,9 +92,9 @@ static double GetApproxValue(const llvm::APFloat &F) {
return V.convertToDouble();
}
-void APValue::print(llvm::raw_ostream &OS) const {
+void APValue::print(raw_ostream &OS) const {
switch (getKind()) {
- default: assert(0 && "Unknown APValue kind!");
+ default: llvm_unreachable("Unknown APValue kind!");
case Uninitialized:
OS << "Uninitialized";
return;
@@ -118,6 +121,49 @@ void APValue::print(llvm::raw_ostream &OS) const {
}
}
+static void WriteShortAPValueToStream(raw_ostream& Out,
+ const APValue& V) {
+ switch (V.getKind()) {
+ default: llvm_unreachable("Unknown APValue kind!");
+ case APValue::Uninitialized:
+ Out << "Uninitialized";
+ break;
+ case APValue::Int:
+ Out << V.getInt();
+ break;
+ case APValue::Float:
+ Out << GetApproxValue(V.getFloat());
+ break;
+ case APValue::Vector:
+ Out << '[';
+ WriteShortAPValueToStream(Out, V.getVectorElt(0));
+ for (unsigned i = 1; i != V.getVectorLength(); ++i) {
+ Out << ", ";
+ WriteShortAPValueToStream(Out, V.getVectorElt(i));
+ }
+ Out << ']';
+ break;
+ case APValue::ComplexInt:
+ Out << V.getComplexIntReal() << "+" << V.getComplexIntImag() << "i";
+ break;
+ case APValue::ComplexFloat:
+ Out << GetApproxValue(V.getComplexFloatReal()) << "+"
+ << GetApproxValue(V.getComplexFloatImag()) << "i";
+ break;
+ case APValue::LValue:
+ Out << "LValue: <todo>";
+ break;
+ }
+}
+
+const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
+ const APValue &V) {
+ llvm::SmallString<64> Buffer;
+ llvm::raw_svector_ostream Out(Buffer);
+ WriteShortAPValueToStream(Out, V);
+ return DB << Out.str();
+}
+
const Expr* APValue::getLValueBase() const {
assert(isLValue() && "Invalid accessor");
return ((const LV*)(const void*)Data)->Base;
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 6eada6e22f4e..462428086ddd 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -30,6 +30,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Capacity.h"
#include "CXXABI.h"
#include <map>
@@ -49,7 +50,7 @@ unsigned ASTContext::NumImplicitDestructors;
unsigned ASTContext::NumImplicitDestructorsDeclared;
enum FloatingRank {
- FloatRank, DoubleRank, LongDoubleRank
+ HalfRank, FloatRank, DoubleRank, LongDoubleRank
};
void
@@ -104,7 +105,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
// Build a canonical template parameter list.
TemplateParameterList *Params = TTP->getTemplateParameters();
- llvm::SmallVector<NamedDecl *, 4> CanonParams;
+ SmallVector<NamedDecl *, 4> CanonParams;
CanonParams.reserve(Params->size());
for (TemplateParameterList::const_iterator P = Params->begin(),
PEnd = Params->end();
@@ -123,8 +124,8 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(T);
NonTypeTemplateParmDecl *Param;
if (NTTP->isExpandedParameterPack()) {
- llvm::SmallVector<QualType, 2> ExpandedTypes;
- llvm::SmallVector<TypeSourceInfo *, 2> ExpandedTInfos;
+ SmallVector<QualType, 2> ExpandedTypes;
+ SmallVector<TypeSourceInfo *, 2> ExpandedTInfos;
for (unsigned I = 0, N = NTTP->getNumExpansionTypes(); I != N; ++I) {
ExpandedTypes.push_back(getCanonicalType(NTTP->getExpansionType(I)));
ExpandedTInfos.push_back(
@@ -195,7 +196,7 @@ CXXABI *ASTContext::createCXXABI(const TargetInfo &T) {
return 0;
}
-static const LangAS::Map &getAddressSpaceMap(const TargetInfo &T,
+static const LangAS::Map *getAddressSpaceMap(const TargetInfo &T,
const LangOptions &LOpts) {
if (LOpts.FakeAddressSpaceMap) {
// The fake address space map must have a distinct entry for each
@@ -205,41 +206,46 @@ static const LangAS::Map &getAddressSpaceMap(const TargetInfo &T,
2, // opencl_local
3 // opencl_constant
};
- return FakeAddrSpaceMap;
+ return &FakeAddrSpaceMap;
} else {
- return T.getAddressSpaceMap();
+ return &T.getAddressSpaceMap();
}
}
-ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
- const TargetInfo &t,
+ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
+ const TargetInfo *t,
IdentifierTable &idents, SelectorTable &sels,
Builtin::Context &builtins,
- unsigned size_reserve) :
- FunctionProtoTypes(this_()),
- TemplateSpecializationTypes(this_()),
- DependentTemplateSpecializationTypes(this_()),
- SubstTemplateTemplateParmPacks(this_()),
- GlobalNestedNameSpecifier(0), IsInt128Installed(false),
- CFConstantStringTypeDecl(0), NSConstantStringTypeDecl(0),
- ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0),
- jmp_bufDecl(0), sigjmp_bufDecl(0), BlockDescriptorType(0),
- BlockDescriptorExtendedType(0), cudaConfigureCallDecl(0),
- NullTypeSourceInfo(QualType()),
- SourceMgr(SM), LangOpts(LOpts), ABI(createCXXABI(t)),
- AddrSpaceMap(getAddressSpaceMap(t, LOpts)), Target(t),
- Idents(idents), Selectors(sels),
- BuiltinInfo(builtins),
- DeclarationNames(*this),
- ExternalSource(0), Listener(0), PrintingPolicy(LOpts),
- LastSDM(0, 0),
- UniqueBlockByRefTypeID(0) {
- ObjCIdRedefinitionType = QualType();
- ObjCClassRedefinitionType = QualType();
- ObjCSelRedefinitionType = QualType();
+ unsigned size_reserve,
+ bool DelayInitialization)
+ : FunctionProtoTypes(this_()),
+ TemplateSpecializationTypes(this_()),
+ DependentTemplateSpecializationTypes(this_()),
+ SubstTemplateTemplateParmPacks(this_()),
+ GlobalNestedNameSpecifier(0),
+ Int128Decl(0), UInt128Decl(0),
+ ObjCIdDecl(0), ObjCSelDecl(0), ObjCClassDecl(0),
+ CFConstantStringTypeDecl(0), ObjCInstanceTypeDecl(0),
+ FILEDecl(0),
+ jmp_bufDecl(0), sigjmp_bufDecl(0), BlockDescriptorType(0),
+ BlockDescriptorExtendedType(0), cudaConfigureCallDecl(0),
+ NullTypeSourceInfo(QualType()),
+ SourceMgr(SM), LangOpts(LOpts),
+ AddrSpaceMap(0), Target(t), PrintingPolicy(LOpts),
+ Idents(idents), Selectors(sels),
+ BuiltinInfo(builtins),
+ DeclarationNames(*this),
+ ExternalSource(0), Listener(0),
+ LastSDM(0, 0),
+ UniqueBlockByRefTypeID(0)
+{
if (size_reserve > 0) Types.reserve(size_reserve);
TUDecl = TranslationUnitDecl::Create(*this);
- InitBuiltinTypes();
+
+ if (!DelayInitialization) {
+ assert(t && "No target supplied for ASTContext initialization");
+ InitBuiltinTypes(*t);
+ }
}
ASTContext::~ASTContext() {
@@ -347,6 +353,33 @@ void ASTContext::PrintStats() const {
BumpAlloc.PrintStats();
}
+TypedefDecl *ASTContext::getInt128Decl() const {
+ if (!Int128Decl) {
+ TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(Int128Ty);
+ Int128Decl = TypedefDecl::Create(const_cast<ASTContext &>(*this),
+ getTranslationUnitDecl(),
+ SourceLocation(),
+ SourceLocation(),
+ &Idents.get("__int128_t"),
+ TInfo);
+ }
+
+ return Int128Decl;
+}
+
+TypedefDecl *ASTContext::getUInt128Decl() const {
+ if (!UInt128Decl) {
+ TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(UnsignedInt128Ty);
+ UInt128Decl = TypedefDecl::Create(const_cast<ASTContext &>(*this),
+ getTranslationUnitDecl(),
+ SourceLocation(),
+ SourceLocation(),
+ &Idents.get("__uint128_t"),
+ TInfo);
+ }
+
+ return UInt128Decl;
+}
void ASTContext::InitBuiltinType(CanQualType &R, BuiltinType::Kind K) {
BuiltinType *Ty = new (*this, TypeAlignment) BuiltinType(K);
@@ -354,9 +387,16 @@ void ASTContext::InitBuiltinType(CanQualType &R, BuiltinType::Kind K) {
Types.push_back(Ty);
}
-void ASTContext::InitBuiltinTypes() {
+void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
+ assert((!this->Target || this->Target == &Target) &&
+ "Incorrect target reinitialization");
assert(VoidTy.isNull() && "Context reinitialized?");
+ this->Target = &Target;
+
+ ABI.reset(createCXXABI(Target));
+ AddrSpaceMap = getAddressSpaceMap(Target, LangOpts);
+
// C99 6.2.5p19.
InitBuiltinType(VoidTy, BuiltinType::Void);
@@ -431,11 +471,6 @@ void ASTContext::InitBuiltinTypes() {
BuiltinVaListType = QualType();
- // "Builtin" typedefs set by Sema::ActOnTranslationUnitScope().
- ObjCIdTypedefType = QualType();
- ObjCClassTypedefType = QualType();
- ObjCSelTypedefType = QualType();
-
// Builtin types for 'id', 'Class', and 'SEL'.
InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId);
InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass);
@@ -448,9 +483,12 @@ void ASTContext::InitBuiltinTypes() {
// nullptr type (C++0x 2.14.7)
InitBuiltinType(NullPtrTy, BuiltinType::NullPtr);
+
+ // half type (OpenCL 6.1.1.1) / ARM NEON __fp16
+ InitBuiltinType(HalfTy, BuiltinType::Half);
}
-Diagnostic &ASTContext::getDiagnostics() const {
+DiagnosticsEngine &ASTContext::getDiagnostics() const {
return SourceMgr.getDiagnostics();
}
@@ -496,6 +534,24 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
= new (*this) MemberSpecializationInfo(Tmpl, TSK, PointOfInstantiation);
}
+FunctionDecl *ASTContext::getClassScopeSpecializationPattern(
+ const FunctionDecl *FD){
+ assert(FD && "Specialization is 0");
+ llvm::DenseMap<const FunctionDecl*, FunctionDecl *>::const_iterator Pos
+ = ClassScopeSpecializationPattern.find(FD);
+ if (Pos == ClassScopeSpecializationPattern.end())
+ return 0;
+
+ return Pos->second;
+}
+
+void ASTContext::setClassScopeSpecializationPattern(FunctionDecl *FD,
+ FunctionDecl *Pattern) {
+ assert(FD && "Specialization is 0");
+ assert(Pattern && "Class scope specialization pattern is 0");
+ ClassScopeSpecializationPattern[FD] = Pattern;
+}
+
NamedDecl *
ASTContext::getInstantiatedFromUsingDecl(UsingDecl *UUD) {
llvm::DenseMap<UsingDecl *, NamedDecl *>::const_iterator Pos
@@ -555,35 +611,33 @@ void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst,
bool ASTContext::ZeroBitfieldFollowsNonBitfield(const FieldDecl *FD,
const FieldDecl *LastFD) const {
return (FD->isBitField() && LastFD && !LastFD->isBitField() &&
- FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() == 0);
-
+ FD->getBitWidthValue(*this) == 0);
}
bool ASTContext::ZeroBitfieldFollowsBitfield(const FieldDecl *FD,
const FieldDecl *LastFD) const {
return (FD->isBitField() && LastFD && LastFD->isBitField() &&
- FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() == 0 &&
- LastFD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() != 0);
-
+ FD->getBitWidthValue(*this) == 0 &&
+ LastFD->getBitWidthValue(*this) != 0);
}
bool ASTContext::BitfieldFollowsBitfield(const FieldDecl *FD,
const FieldDecl *LastFD) const {
return (FD->isBitField() && LastFD && LastFD->isBitField() &&
- FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() &&
- LastFD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue());
+ FD->getBitWidthValue(*this) &&
+ LastFD->getBitWidthValue(*this));
}
-bool ASTContext::NoneBitfieldFollowsBitfield(const FieldDecl *FD,
+bool ASTContext::NonBitfieldFollowsBitfield(const FieldDecl *FD,
const FieldDecl *LastFD) const {
return (!FD->isBitField() && LastFD && LastFD->isBitField() &&
- LastFD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue());
+ LastFD->getBitWidthValue(*this));
}
-bool ASTContext::BitfieldFollowsNoneBitfield(const FieldDecl *FD,
+bool ASTContext::BitfieldFollowsNonBitfield(const FieldDecl *FD,
const FieldDecl *LastFD) const {
return (FD->isBitField() && LastFD && !LastFD->isBitField() &&
- FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue());
+ FD->getBitWidthValue(*this));
}
ASTContext::overridden_cxx_method_iterator
@@ -631,10 +685,11 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
const BuiltinType *BT = T->getAs<BuiltinType>();
assert(BT && "Not a floating point type!");
switch (BT->getKind()) {
- default: assert(0 && "Not a floating point type!");
- case BuiltinType::Float: return Target.getFloatFormat();
- case BuiltinType::Double: return Target.getDoubleFormat();
- case BuiltinType::LongDouble: return Target.getLongDoubleFormat();
+ default: llvm_unreachable("Not a floating point type!");
+ case BuiltinType::Half: return Target->getHalfFormat();
+ case BuiltinType::Float: return Target->getFloatFormat();
+ case BuiltinType::Double: return Target->getDoubleFormat();
+ case BuiltinType::LongDouble: return Target->getLongDoubleFormat();
}
}
@@ -644,7 +699,7 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
/// If @p RefAsPointee, references are treated like their underlying type
/// (for alignof), else they're treated like pointers (for CodeGen).
CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
- unsigned Align = Target.getCharWidth();
+ unsigned Align = Target->getCharWidth();
bool UseAlignAttrOnly = false;
if (unsigned AlignFromAttr = D->getMaxAlignment()) {
@@ -654,7 +709,7 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
// *except* on a struct or struct member, where it only increases
// alignment unless 'packed' is also specified.
//
- // It is an error for [[align]] to decrease alignment, so we can
+ // It is an error for alignas to decrease alignment, so we can
// ignore that possibility; Sema should diagnose it.
if (isa<FieldDecl>(D)) {
UseAlignAttrOnly = D->hasAttr<PackedAttr>() ||
@@ -684,14 +739,14 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
if (!T->isIncompleteType() && !T->isFunctionType()) {
// Adjust alignments of declarations with array type by the
// large-array alignment on the target.
- unsigned MinWidth = Target.getLargeArrayMinWidth();
+ unsigned MinWidth = Target->getLargeArrayMinWidth();
const ArrayType *arrayType;
if (MinWidth && (arrayType = getAsArrayType(T))) {
if (isa<VariableArrayType>(arrayType))
- Align = std::max(Align, Target.getLargeArrayAlign());
+ Align = std::max(Align, Target->getLargeArrayAlign());
else if (isa<ConstantArrayType>(arrayType) &&
MinWidth <= getTypeSize(cast<ConstantArrayType>(arrayType)))
- Align = std::max(Align, Target.getLargeArrayAlign());
+ Align = std::max(Align, Target->getLargeArrayAlign());
// Walk through any array types while we're at it.
T = getBaseElementType(arrayType);
@@ -798,7 +853,7 @@ ASTContext::getTypeInfo(const Type *T) const {
case Type::Builtin:
switch (cast<BuiltinType>(T)->getKind()) {
- default: assert(0 && "Unknown builtin type!");
+ default: llvm_unreachable("Unknown builtin type!");
case BuiltinType::Void:
// GCC extension: alignof(void) = 8 bits.
Width = 0;
@@ -806,87 +861,91 @@ ASTContext::getTypeInfo(const Type *T) const {
break;
case BuiltinType::Bool:
- Width = Target.getBoolWidth();
- Align = Target.getBoolAlign();
+ Width = Target->getBoolWidth();
+ Align = Target->getBoolAlign();
break;
case BuiltinType::Char_S:
case BuiltinType::Char_U:
case BuiltinType::UChar:
case BuiltinType::SChar:
- Width = Target.getCharWidth();
- Align = Target.getCharAlign();
+ Width = Target->getCharWidth();
+ Align = Target->getCharAlign();
break;
case BuiltinType::WChar_S:
case BuiltinType::WChar_U:
- Width = Target.getWCharWidth();
- Align = Target.getWCharAlign();
+ Width = Target->getWCharWidth();
+ Align = Target->getWCharAlign();
break;
case BuiltinType::Char16:
- Width = Target.getChar16Width();
- Align = Target.getChar16Align();
+ Width = Target->getChar16Width();
+ Align = Target->getChar16Align();
break;
case BuiltinType::Char32:
- Width = Target.getChar32Width();
- Align = Target.getChar32Align();
+ Width = Target->getChar32Width();
+ Align = Target->getChar32Align();
break;
case BuiltinType::UShort:
case BuiltinType::Short:
- Width = Target.getShortWidth();
- Align = Target.getShortAlign();
+ Width = Target->getShortWidth();
+ Align = Target->getShortAlign();
break;
case BuiltinType::UInt:
case BuiltinType::Int:
- Width = Target.getIntWidth();
- Align = Target.getIntAlign();
+ Width = Target->getIntWidth();
+ Align = Target->getIntAlign();
break;
case BuiltinType::ULong:
case BuiltinType::Long:
- Width = Target.getLongWidth();
- Align = Target.getLongAlign();
+ Width = Target->getLongWidth();
+ Align = Target->getLongAlign();
break;
case BuiltinType::ULongLong:
case BuiltinType::LongLong:
- Width = Target.getLongLongWidth();
- Align = Target.getLongLongAlign();
+ Width = Target->getLongLongWidth();
+ Align = Target->getLongLongAlign();
break;
case BuiltinType::Int128:
case BuiltinType::UInt128:
Width = 128;
Align = 128; // int128_t is 128-bit aligned on all targets.
break;
+ case BuiltinType::Half:
+ Width = Target->getHalfWidth();
+ Align = Target->getHalfAlign();
+ break;
case BuiltinType::Float:
- Width = Target.getFloatWidth();
- Align = Target.getFloatAlign();
+ Width = Target->getFloatWidth();
+ Align = Target->getFloatAlign();
break;
case BuiltinType::Double:
- Width = Target.getDoubleWidth();
- Align = Target.getDoubleAlign();
+ Width = Target->getDoubleWidth();
+ Align = Target->getDoubleAlign();
break;
case BuiltinType::LongDouble:
- Width = Target.getLongDoubleWidth();
- Align = Target.getLongDoubleAlign();
+ Width = Target->getLongDoubleWidth();
+ Align = Target->getLongDoubleAlign();
break;
case BuiltinType::NullPtr:
- Width = Target.getPointerWidth(0); // C++ 3.9.1p11: sizeof(nullptr_t)
- Align = Target.getPointerAlign(0); // == sizeof(void*)
+ Width = Target->getPointerWidth(0); // C++ 3.9.1p11: sizeof(nullptr_t)
+ Align = Target->getPointerAlign(0); // == sizeof(void*)
break;
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
- Width = Target.getPointerWidth(0);
- Align = Target.getPointerAlign(0);
+ Width = Target->getPointerWidth(0);
+ Align = Target->getPointerAlign(0);
break;
}
break;
case Type::ObjCObjectPointer:
- Width = Target.getPointerWidth(0);
- Align = Target.getPointerAlign(0);
+ Width = Target->getPointerWidth(0);
+ Align = Target->getPointerAlign(0);
break;
case Type::BlockPointer: {
unsigned AS = getTargetAddressSpace(
cast<BlockPointerType>(T)->getPointeeType());
- Width = Target.getPointerWidth(AS);
- Align = Target.getPointerAlign(AS);
+ Width = Target->getPointerWidth(AS);
+ Align = Target->getPointerAlign(AS);
break;
}
case Type::LValueReference:
@@ -895,14 +954,14 @@ ASTContext::getTypeInfo(const Type *T) const {
// the pointer route.
unsigned AS = getTargetAddressSpace(
cast<ReferenceType>(T)->getPointeeType());
- Width = Target.getPointerWidth(AS);
- Align = Target.getPointerAlign(AS);
+ Width = Target->getPointerWidth(AS);
+ Align = Target->getPointerAlign(AS);
break;
}
case Type::Pointer: {
unsigned AS = getTargetAddressSpace(cast<PointerType>(T)->getPointeeType());
- Width = Target.getPointerWidth(AS);
- Align = Target.getPointerAlign(AS);
+ Width = Target->getPointerWidth(AS);
+ Align = Target->getPointerAlign(AS);
break;
}
case Type::MemberPointer: {
@@ -1012,9 +1071,26 @@ ASTContext::getTypeInfo(const Type *T) const {
return getTypeInfo(getCanonicalType(T));
}
+ case Type::Atomic: {
+ 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.)
+ Align = static_cast<unsigned>(Width);
+ }
+ }
+
}
- assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2");
+ assert(llvm::isPowerOf2_32(Align) && "Alignment must be power of 2");
return std::make_pair(Width, Align);
}
@@ -1063,19 +1139,6 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const {
return ABIAlign;
}
-/// ShallowCollectObjCIvars -
-/// Collect all ivars, including those synthesized, in the current class.
-///
-void ASTContext::ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI,
- llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) const {
- // FIXME. This need be removed but there are two many places which
- // assume const-ness of ObjCInterfaceDecl
- ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl *>(OI);
- for (ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv;
- Iv= Iv->getNextIvar())
- Ivars.push_back(Iv);
-}
-
/// DeepCollectObjCIvars -
/// This routine first collects all declared, but not synthesized, ivars in
/// super class and then collects all ivars, including those synthesized for
@@ -1084,17 +1147,16 @@ void ASTContext::ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI,
///
void ASTContext::DeepCollectObjCIvars(const ObjCInterfaceDecl *OI,
bool leafClass,
- llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) const {
+ SmallVectorImpl<const ObjCIvarDecl*> &Ivars) const {
if (const ObjCInterfaceDecl *SuperClass = OI->getSuperClass())
DeepCollectObjCIvars(SuperClass, false, Ivars);
if (!leafClass) {
for (ObjCInterfaceDecl::ivar_iterator I = OI->ivar_begin(),
E = OI->ivar_end(); I != E; ++I)
Ivars.push_back(*I);
- }
- else {
+ } else {
ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl *>(OI);
- for (ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv;
+ for (const ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv;
Iv= Iv->getNextIvar())
Ivars.push_back(Iv);
}
@@ -1562,7 +1624,7 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
// the target.
llvm::APInt ArySize(ArySizeIn);
ArySize =
- ArySize.zextOrTrunc(Target.getPointerWidth(getTargetAddressSpace(EltTy)));
+ ArySize.zextOrTrunc(Target->getPointerWidth(getTargetAddressSpace(EltTy)));
llvm::FoldingSetNodeID ID;
ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, IndexTypeQuals);
@@ -1670,6 +1732,12 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
break;
}
+ case Type::Atomic: {
+ const AtomicType *at = cast<AtomicType>(ty);
+ result = getAtomicType(getVariableArrayDecayedType(at->getValueType()));
+ break;
+ }
+
case Type::ConstantArray: {
const ConstantArrayType *cat = cast<ConstantArrayType>(ty);
result = getConstantArrayType(
@@ -2026,7 +2094,7 @@ ASTContext::getFunctionType(QualType ResultTy,
// The exception spec is not part of the canonical type.
QualType Canonical;
if (!isCanonical || getCanonicalCallConv(CallConv) != CallConv) {
- llvm::SmallVector<QualType, 16> CanonicalArgs;
+ SmallVector<QualType, 16> CanonicalArgs;
CanonicalArgs.reserve(NumArgs);
for (unsigned i = 0; i != NumArgs; ++i)
CanonicalArgs.push_back(getCanonicalParamType(ArgArray[i]));
@@ -2322,7 +2390,7 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
unsigned NumArgs = Args.size();
- llvm::SmallVector<TemplateArgument, 4> ArgVec;
+ SmallVector<TemplateArgument, 4> ArgVec;
ArgVec.reserve(NumArgs);
for (unsigned i = 0; i != NumArgs; ++i)
ArgVec.push_back(Args[i].getArgument());
@@ -2389,7 +2457,7 @@ ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template,
// Build the canonical template specialization type.
TemplateName CanonTemplate = getCanonicalTemplateName(Template);
- llvm::SmallVector<TemplateArgument, 4> CanonArgs;
+ SmallVector<TemplateArgument, 4> CanonArgs;
CanonArgs.reserve(NumArgs);
for (unsigned I = 0; I != NumArgs; ++I)
CanonArgs.push_back(getCanonicalTemplateArgument(Args[I]));
@@ -2509,7 +2577,7 @@ ASTContext::getDependentTemplateSpecializationType(
const IdentifierInfo *Name,
const TemplateArgumentListInfo &Args) const {
// TODO: avoid this copy
- llvm::SmallVector<TemplateArgument, 16> ArgCopy;
+ SmallVector<TemplateArgument, 16> ArgCopy;
for (unsigned I = 0, E = Args.size(); I != E; ++I)
ArgCopy.push_back(Args[I].getArgument());
return getDependentTemplateSpecializationType(Keyword, NNS, Name,
@@ -2543,7 +2611,7 @@ ASTContext::getDependentTemplateSpecializationType(
if (Keyword == ETK_None) CanonKeyword = ETK_Typename;
bool AnyNonCanonArgs = false;
- llvm::SmallVector<TemplateArgument, 16> CanonArgs(NumArgs);
+ SmallVector<TemplateArgument, 16> CanonArgs(NumArgs);
for (unsigned I = 0; I != NumArgs; ++I) {
CanonArgs[I] = getCanonicalTemplateArgument(Args[I]);
if (!CanonArgs[I].structurallyEquals(Args[I]))
@@ -2647,7 +2715,7 @@ QualType ASTContext::getObjCObjectType(QualType BaseType,
bool ProtocolsSorted = areSortedAndUniqued(Protocols, NumProtocols);
if (!ProtocolsSorted || !BaseType.isCanonical()) {
if (!ProtocolsSorted) {
- llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols,
+ SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols,
Protocols + NumProtocols);
unsigned UniqueCount = NumProtocols;
@@ -2737,8 +2805,7 @@ QualType ASTContext::getTypeOfExprType(Expr *tofExpr) const {
// typeof(expr) type. Use that as our canonical type.
toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr,
QualType((TypeOfExprType*)Canon, 0));
- }
- else {
+ } else {
// Build a new, canonical typeof(expr) type.
Canon
= new (*this, TypeAlignment) DependentTypeOfExprType(*this, tofExpr);
@@ -2821,8 +2888,7 @@ QualType ASTContext::getDecltypeType(Expr *e) const {
// decltype type. Use that as our canonical type.
dt = new (*this, TypeAlignment) DecltypeType(e, DependentTy,
QualType((DecltypeType*)Canon, 0));
- }
- else {
+ } else {
// Build a new, canonical typeof(expr) type.
Canon = new (*this, TypeAlignment) DependentDecltypeType(*this, e);
DependentDecltypeTypes.InsertNode(Canon, InsertPos);
@@ -2869,6 +2935,34 @@ QualType ASTContext::getAutoType(QualType DeducedType) const {
return QualType(AT, 0);
}
+/// getAtomicType - Return the uniqued reference to the atomic type for
+/// the given value type.
+QualType ASTContext::getAtomicType(QualType T) const {
+ // Unique pointers, to guarantee there is only one pointer of a particular
+ // structure.
+ llvm::FoldingSetNodeID ID;
+ AtomicType::Profile(ID, T);
+
+ void *InsertPos = 0;
+ if (AtomicType *AT = AtomicTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(AT, 0);
+
+ // If the atomic value type isn't canonical, this won't be a canonical type
+ // either, so fill in the canonical type field.
+ QualType Canonical;
+ if (!T.isCanonical()) {
+ Canonical = getAtomicType(getCanonicalType(T));
+
+ // Get the new insert position for the node we care about.
+ AtomicType *NewIP = AtomicTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
+ }
+ AtomicType *New = new (*this, TypeAlignment) AtomicType(T, Canonical);
+ Types.push_back(New);
+ AtomicTypes.InsertNode(New, InsertPos);
+ return QualType(New, 0);
+}
+
/// getAutoDeductType - Get type pattern for deducing against 'auto'.
QualType ASTContext::getAutoDeductType() const {
if (AutoDeductTy.isNull())
@@ -2898,7 +2992,7 @@ QualType ASTContext::getTagDeclType(const TagDecl *Decl) const {
/// of the sizeof operator (C99 6.5.3.4p4). The value is target dependent and
/// needs to agree with the definition in <stddef.h>.
CanQualType ASTContext::getSizeType() const {
- return getFromTargetType(Target.getSizeType());
+ return getFromTargetType(Target->getSizeType());
}
/// getSignedWCharType - Return the type of "signed wchar_t".
@@ -2918,7 +3012,7 @@ QualType ASTContext::getUnsignedWCharType() const {
/// getPointerDiffType - Return the unique type for "ptrdiff_t" (ref?)
/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
QualType ASTContext::getPointerDiffType() const {
- return getFromTargetType(Target.getPtrDiffType(0));
+ return getFromTargetType(Target->getPtrDiffType(0));
}
//===----------------------------------------------------------------------===//
@@ -3183,8 +3277,7 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
}
// Silence GCC warning
- assert(false && "Unhandled template argument kind");
- return TemplateArgument();
+ llvm_unreachable("Unhandled template argument kind");
}
NestedNameSpecifier *
@@ -3397,7 +3490,8 @@ static FloatingRank getFloatingRank(QualType T) {
assert(T->getAs<BuiltinType>() && "getFloatingRank(): not a floating type");
switch (T->getAs<BuiltinType>()->getKind()) {
- default: assert(0 && "getFloatingRank(): not a floating type");
+ default: llvm_unreachable("getFloatingRank(): not a floating type");
+ case BuiltinType::Half: return HalfRank;
case BuiltinType::Float: return FloatRank;
case BuiltinType::Double: return DoubleRank;
case BuiltinType::LongDouble: return LongDoubleRank;
@@ -3413,7 +3507,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size,
FloatingRank EltRank = getFloatingRank(Size);
if (Domain->isComplexType()) {
switch (EltRank) {
- default: assert(0 && "getFloatingRank(): illegal value for rank");
+ default: llvm_unreachable("getFloatingRank(): illegal value for rank");
case FloatRank: return FloatComplexTy;
case DoubleRank: return DoubleComplexTy;
case LongDoubleRank: return LongDoubleComplexTy;
@@ -3422,7 +3516,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size,
assert(Domain->isRealFloatingType() && "Unknown domain!");
switch (EltRank) {
- default: assert(0 && "getFloatingRank(): illegal value for rank");
+ default: llvm_unreachable("getFloatingRank(): illegal value for rank");
case FloatRank: return FloatTy;
case DoubleRank: return DoubleTy;
case LongDoubleRank: return LongDoubleTy;
@@ -3454,16 +3548,16 @@ unsigned ASTContext::getIntegerRank(const Type *T) const {
if (T->isSpecificBuiltinType(BuiltinType::WChar_S) ||
T->isSpecificBuiltinType(BuiltinType::WChar_U))
- T = getFromTargetType(Target.getWCharType()).getTypePtr();
+ T = getFromTargetType(Target->getWCharType()).getTypePtr();
if (T->isSpecificBuiltinType(BuiltinType::Char16))
- T = getFromTargetType(Target.getChar16Type()).getTypePtr();
+ T = getFromTargetType(Target->getChar16Type()).getTypePtr();
if (T->isSpecificBuiltinType(BuiltinType::Char32))
- T = getFromTargetType(Target.getChar32Type()).getTypePtr();
+ T = getFromTargetType(Target->getChar32Type()).getTypePtr();
switch (cast<BuiltinType>(T)->getKind()) {
- default: assert(0 && "getIntegerRank(): not a built-in integer");
+ default: llvm_unreachable("getIntegerRank(): not a built-in integer");
case BuiltinType::Bool:
return 1 + (getIntWidth(BoolTy) << 3);
case BuiltinType::Char_S:
@@ -3504,8 +3598,7 @@ QualType ASTContext::isPromotableBitField(Expr *E) const {
QualType FT = Field->getType();
- llvm::APSInt BitWidthAP = Field->getBitWidth()->EvaluateAsInt(*this);
- uint64_t BitWidth = BitWidthAP.getZExtValue();
+ uint64_t BitWidth = Field->getBitWidthValue(*this);
uint64_t IntSize = getTypeSize(IntTy);
// GCC extension compatibility: if the bit-field size is less than or equal
// to the size of int, it gets promoted no matter what its type is.
@@ -3653,82 +3746,6 @@ void ASTContext::setCFConstantStringType(QualType T) {
CFConstantStringTypeDecl = Rec->getDecl();
}
-// getNSConstantStringType - Return the type used for constant NSStrings.
-QualType ASTContext::getNSConstantStringType() const {
- if (!NSConstantStringTypeDecl) {
- NSConstantStringTypeDecl =
- CreateRecordDecl(*this, TTK_Struct, TUDecl,
- &Idents.get("__builtin_NSString"));
- NSConstantStringTypeDecl->startDefinition();
-
- QualType FieldTypes[3];
-
- // const int *isa;
- FieldTypes[0] = getPointerType(IntTy.withConst());
- // const char *str;
- FieldTypes[1] = getPointerType(CharTy.withConst());
- // unsigned int length;
- FieldTypes[2] = UnsignedIntTy;
-
- // Create fields
- for (unsigned i = 0; i < 3; ++i) {
- FieldDecl *Field = FieldDecl::Create(*this, NSConstantStringTypeDecl,
- SourceLocation(),
- SourceLocation(), 0,
- FieldTypes[i], /*TInfo=*/0,
- /*BitWidth=*/0,
- /*Mutable=*/false,
- /*HasInit=*/false);
- Field->setAccess(AS_public);
- NSConstantStringTypeDecl->addDecl(Field);
- }
-
- NSConstantStringTypeDecl->completeDefinition();
- }
-
- return getTagDeclType(NSConstantStringTypeDecl);
-}
-
-void ASTContext::setNSConstantStringType(QualType T) {
- const RecordType *Rec = T->getAs<RecordType>();
- assert(Rec && "Invalid NSConstantStringType");
- NSConstantStringTypeDecl = Rec->getDecl();
-}
-
-QualType ASTContext::getObjCFastEnumerationStateType() const {
- if (!ObjCFastEnumerationStateTypeDecl) {
- ObjCFastEnumerationStateTypeDecl =
- CreateRecordDecl(*this, TTK_Struct, TUDecl,
- &Idents.get("__objcFastEnumerationState"));
- ObjCFastEnumerationStateTypeDecl->startDefinition();
-
- QualType FieldTypes[] = {
- UnsignedLongTy,
- getPointerType(ObjCIdTypedefType),
- getPointerType(UnsignedLongTy),
- getConstantArrayType(UnsignedLongTy,
- llvm::APInt(32, 5), ArrayType::Normal, 0)
- };
-
- for (size_t i = 0; i < 4; ++i) {
- FieldDecl *Field = FieldDecl::Create(*this,
- ObjCFastEnumerationStateTypeDecl,
- SourceLocation(),
- SourceLocation(), 0,
- FieldTypes[i], /*TInfo=*/0,
- /*BitWidth=*/0,
- /*Mutable=*/false,
- /*HasInit=*/false);
- Field->setAccess(AS_public);
- ObjCFastEnumerationStateTypeDecl->addDecl(Field);
- }
-
- ObjCFastEnumerationStateTypeDecl->completeDefinition();
- }
-
- return getTagDeclType(ObjCFastEnumerationStateTypeDecl);
-}
-
QualType ASTContext::getBlockDescriptorType() const {
if (BlockDescriptorType)
return getTagDeclType(BlockDescriptorType);
@@ -3768,12 +3785,6 @@ QualType ASTContext::getBlockDescriptorType() const {
return getTagDeclType(BlockDescriptorType);
}
-void ASTContext::setBlockDescriptorType(QualType T) {
- const RecordType *Rec = T->getAs<RecordType>();
- assert(Rec && "Invalid BlockDescriptorType");
- BlockDescriptorType = Rec->getDecl();
-}
-
QualType ASTContext::getBlockDescriptorExtendedType() const {
if (BlockDescriptorExtendedType)
return getTagDeclType(BlockDescriptorExtendedType);
@@ -3817,12 +3828,6 @@ QualType ASTContext::getBlockDescriptorExtendedType() const {
return getTagDeclType(BlockDescriptorExtendedType);
}
-void ASTContext::setBlockDescriptorExtendedType(QualType T) {
- const RecordType *Rec = T->getAs<RecordType>();
- assert(Rec && "Invalid BlockDescriptorType");
- BlockDescriptorExtendedType = Rec->getDecl();
-}
-
bool ASTContext::BlockRequiresCopying(QualType Ty) const {
if (Ty->isObjCRetainableType())
return true;
@@ -3837,7 +3842,7 @@ bool ASTContext::BlockRequiresCopying(QualType Ty) const {
}
QualType
-ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const {
+ASTContext::BuildByRefType(StringRef DeclName, QualType Ty) const {
// type = struct __Block_byref_1_X {
// void *__isa;
// struct __Block_byref_1_X *__forwarding;
@@ -3869,7 +3874,7 @@ ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const {
Ty
};
- llvm::StringRef FieldNames[] = {
+ StringRef FieldNames[] = {
"__isa",
"__forwarding",
"__flags",
@@ -3897,10 +3902,15 @@ ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const {
return getPointerType(getTagDeclType(T));
}
-void ASTContext::setObjCFastEnumerationStateType(QualType T) {
- const RecordType *Rec = T->getAs<RecordType>();
- assert(Rec && "Invalid ObjCFAstEnumerationStateType");
- ObjCFastEnumerationStateTypeDecl = Rec->getDecl();
+TypedefDecl *ASTContext::getObjCInstanceTypeDecl() {
+ if (!ObjCInstanceTypeDecl)
+ ObjCInstanceTypeDecl = TypedefDecl::Create(*this,
+ getTranslationUnitDecl(),
+ SourceLocation(),
+ SourceLocation(),
+ &Idents.get("instancetype"),
+ getTrivialTypeSourceInfo(getObjCIdType()));
+ return ObjCInstanceTypeDecl;
}
// This returns true if a type has been typedefed to BOOL:
@@ -3962,7 +3972,6 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
S += charUnitsToString(ParmOffset);
// Block pointer and offset.
S += "@?0";
- ParmOffset = PtrSize;
// Argument types.
ParmOffset = PtrSize;
@@ -4044,7 +4053,7 @@ bool ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
// The first two arguments (self and _cmd) are pointers; account for
// their size.
CharUnits ParmOffset = 2 * PtrSize;
- for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
+ for (ObjCMethodDecl::param_const_iterator PI = Decl->param_begin(),
E = Decl->sel_param_end(); PI != E; ++PI) {
QualType PType = (*PI)->getType();
CharUnits sz = getObjCEncodingTypeSize(PType);
@@ -4061,9 +4070,9 @@ bool ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
// Argument types.
ParmOffset = 2 * PtrSize;
- for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
+ for (ObjCMethodDecl::param_const_iterator PI = Decl->param_begin(),
E = Decl->sel_param_end(); PI != E; ++PI) {
- ParmVarDecl *PVDecl = *PI;
+ const ParmVarDecl *PVDecl = *PI;
QualType PType = PVDecl->getOriginalType();
if (const ArrayType *AT =
dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) {
@@ -4166,6 +4175,7 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
case ObjCPropertyDecl::Assign: break;
case ObjCPropertyDecl::Copy: S += ",C"; break;
case ObjCPropertyDecl::Retain: S += ",&"; break;
+ case ObjCPropertyDecl::Weak: S += ",W"; break;
}
}
@@ -4225,7 +4235,7 @@ void ASTContext::getObjCEncodingForType(QualType T, std::string& S,
static char ObjCEncodingForPrimitiveKind(const ASTContext *C, QualType T) {
switch (T->getAs<BuiltinType>()->getKind()) {
- default: assert(0 && "Unhandled builtin type kind");
+ default: llvm_unreachable("Unhandled builtin type kind");
case BuiltinType::Void: return 'v';
case BuiltinType::Bool: return 'B';
case BuiltinType::Char_U:
@@ -4252,10 +4262,20 @@ static char ObjCEncodingForPrimitiveKind(const ASTContext *C, QualType T) {
}
}
+static char ObjCEncodingForEnumType(const ASTContext *C, const EnumType *ET) {
+ EnumDecl *Enum = ET->getDecl();
+
+ // The encoding of an non-fixed enum type is always 'i', regardless of size.
+ if (!Enum->isFixed())
+ return 'i';
+
+ // The encoding of a fixed enum type matches its fixed underlying type.
+ return ObjCEncodingForPrimitiveKind(C, Enum->getIntegerType());
+}
+
static void EncodeBitField(const ASTContext *Ctx, std::string& S,
QualType T, const FieldDecl *FD) {
- const Expr *E = FD->getBitWidth();
- assert(E && "bitfield width not there - getObjCEncodingForTypeImpl");
+ assert(FD->isBitField() && "not a bitfield - getObjCEncodingForTypeImpl");
S += 'b';
// The NeXT runtime encodes bit fields as b followed by the number of bits.
// The GNU runtime requires more information; bitfields are encoded as b,
@@ -4276,13 +4296,12 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S,
const RecordDecl *RD = FD->getParent();
const ASTRecordLayout &RL = Ctx->getASTRecordLayout(RD);
S += llvm::utostr(RL.getFieldOffset(FD->getFieldIndex()));
- if (T->isEnumeralType())
- S += 'i';
+ if (const EnumType *ET = T->getAs<EnumType>())
+ S += ObjCEncodingForEnumType(Ctx, ET);
else
S += ObjCEncodingForPrimitiveKind(Ctx, T);
}
- unsigned N = E->EvaluateAsInt(*Ctx).getZExtValue();
- S += llvm::utostr(N);
+ S += llvm::utostr(FD->getBitWidthValue(*Ctx));
}
// FIXME: Use SmallString for accumulating string.
@@ -4342,7 +4361,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
// Another legacy compatibility encoding. Some ObjC qualifier and type
// combinations need to be rearranged.
// Rewrite "in const" from "nr" to "rn"
- if (llvm::StringRef(S).endswith("nr"))
+ if (StringRef(S).endswith("nr"))
S.replace(S.end()-2, S.end(), "rn");
}
@@ -4423,7 +4442,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
= TemplateSpecializationType::PrintTemplateArgumentList(
TemplateArgs.data(),
TemplateArgs.size(),
- (*this).PrintingPolicy);
+ (*this).getPrintingPolicy());
S += TemplateArgsStr;
}
@@ -4463,11 +4482,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
return;
}
- if (T->isEnumeralType()) {
+ if (const EnumType *ET = T->getAs<EnumType>()) {
if (FD && FD->isBitField())
EncodeBitField(this, S, T, FD);
else
- S += 'i';
+ S += ObjCEncodingForEnumType(this, ET);
return;
}
@@ -4487,10 +4506,10 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
const IdentifierInfo *II = OI->getIdentifier();
S += II->getName();
S += '=';
- llvm::SmallVector<ObjCIvarDecl*, 32> Ivars;
+ SmallVector<const ObjCIvarDecl*, 32> Ivars;
DeepCollectObjCIvars(OI, true, Ivars);
for (unsigned i = 0, e = Ivars.size(); i != e; ++i) {
- FieldDecl *Field = cast<FieldDecl>(Ivars[i]);
+ const FieldDecl *Field = cast<FieldDecl>(Ivars[i]);
if (Field->isBitField())
getObjCEncodingForTypeImpl(Field->getType(), S, false, true, Field);
else
@@ -4573,7 +4592,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
return;
}
- assert(0 && "@encode for type not implemented!");
+ llvm_unreachable("@encode for type not implemented!");
}
void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
@@ -4621,8 +4640,9 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
if (base->isEmpty())
continue;
uint64_t offs = layout.getVBaseClassOffsetInBits(base);
- FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs),
- std::make_pair(offs, base));
+ if (FieldOrBaseOffsets.find(offs) == FieldOrBaseOffsets.end())
+ FieldOrBaseOffsets.insert(FieldOrBaseOffsets.end(),
+ std::make_pair(offs, base));
}
}
@@ -4637,7 +4657,9 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
std::multimap<uint64_t, NamedDecl *>::iterator
CurLayObj = FieldOrBaseOffsets.begin();
- if (CurLayObj != FieldOrBaseOffsets.end() && CurLayObj->first != 0) {
+ if ((CurLayObj != FieldOrBaseOffsets.end() && CurLayObj->first != 0) ||
+ (CurLayObj == FieldOrBaseOffsets.end() &&
+ CXXRec && CXXRec->isDynamicClass())) {
assert(CXXRec && CXXRec->isDynamicClass() &&
"Offset 0 was empty but no VTable ?");
if (FD) {
@@ -4695,7 +4717,7 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
if (field->isBitField()) {
EncodeBitField(this, S, field->getType(), field);
- CurOffs += field->getBitWidth()->EvaluateAsInt(*this).getZExtValue();
+ CurOffs += field->getBitWidthValue(*this);
} else {
QualType qt = field->getType();
getLegacyIntegralTypeEncoding(qt);
@@ -4731,20 +4753,48 @@ void ASTContext::setBuiltinVaListType(QualType T) {
BuiltinVaListType = T;
}
-void ASTContext::setObjCIdType(QualType T) {
- ObjCIdTypedefType = T;
+TypedefDecl *ASTContext::getObjCIdDecl() const {
+ if (!ObjCIdDecl) {
+ QualType T = getObjCObjectType(ObjCBuiltinIdTy, 0, 0);
+ T = getObjCObjectPointerType(T);
+ TypeSourceInfo *IdInfo = getTrivialTypeSourceInfo(T);
+ ObjCIdDecl = TypedefDecl::Create(const_cast<ASTContext &>(*this),
+ getTranslationUnitDecl(),
+ SourceLocation(), SourceLocation(),
+ &Idents.get("id"), IdInfo);
+ }
+
+ return ObjCIdDecl;
}
-void ASTContext::setObjCSelType(QualType T) {
- ObjCSelTypedefType = T;
+TypedefDecl *ASTContext::getObjCSelDecl() const {
+ if (!ObjCSelDecl) {
+ QualType SelT = getPointerType(ObjCBuiltinSelTy);
+ TypeSourceInfo *SelInfo = getTrivialTypeSourceInfo(SelT);
+ ObjCSelDecl = TypedefDecl::Create(const_cast<ASTContext &>(*this),
+ getTranslationUnitDecl(),
+ SourceLocation(), SourceLocation(),
+ &Idents.get("SEL"), SelInfo);
+ }
+ return ObjCSelDecl;
}
void ASTContext::setObjCProtoType(QualType QT) {
ObjCProtoType = QT;
}
-void ASTContext::setObjCClassType(QualType T) {
- ObjCClassTypedefType = T;
+TypedefDecl *ASTContext::getObjCClassDecl() const {
+ if (!ObjCClassDecl) {
+ QualType T = getObjCObjectType(ObjCBuiltinClassTy, 0, 0);
+ T = getObjCObjectPointerType(T);
+ TypeSourceInfo *ClassInfo = getTrivialTypeSourceInfo(T);
+ ObjCClassDecl = TypedefDecl::Create(const_cast<ASTContext &>(*this),
+ getTranslationUnitDecl(),
+ SourceLocation(), SourceLocation(),
+ &Idents.get("Class"), ClassInfo);
+ }
+
+ return ObjCClassDecl;
}
void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) {
@@ -4925,8 +4975,7 @@ CanQualType ASTContext::getFromTargetType(unsigned Type) const {
case TargetInfo::UnsignedLongLong: return UnsignedLongLongTy;
}
- assert(false && "Unhandled TargetInfo::IntType value");
- return CanQualType();
+ llvm_unreachable("Unhandled TargetInfo::IntType value");
}
//===----------------------------------------------------------------------===//
@@ -4937,7 +4986,7 @@ CanQualType ASTContext::getFromTargetType(unsigned Type) const {
/// garbage collection attribute.
///
Qualifiers::GC ASTContext::getObjCGCAttrKind(QualType Ty) const {
- if (getLangOptions().getGCMode() == LangOptions::NonGC)
+ if (getLangOptions().getGC() == LangOptions::NonGC)
return Qualifiers::GCNone;
assert(getLangOptions().ObjC1);
@@ -5261,7 +5310,7 @@ static
void getIntersectionOfProtocols(ASTContext &Context,
const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT,
- llvm::SmallVectorImpl<ObjCProtocolDecl *> &IntersectionOfProtocols) {
+ SmallVectorImpl<ObjCProtocolDecl *> &IntersectionOfProtocols) {
const ObjCObjectType* LHS = LHSOPT->getObjectType();
const ObjCObjectType* RHS = RHSOPT->getObjectType();
@@ -5287,8 +5336,7 @@ void getIntersectionOfProtocols(ASTContext &Context,
for (unsigned i = 0; i < RHSNumProtocols; ++i)
if (InheritedProtocolSet.count(RHSProtocols[i]))
IntersectionOfProtocols.push_back(RHSProtocols[i]);
- }
- else {
+ } else {
llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSInheritedProtocols;
Context.CollectInheritedProtocols(RHS->getInterface(),
RHSInheritedProtocols);
@@ -5317,7 +5365,7 @@ QualType ASTContext::areCommonBaseCompatible(
do {
LHS = cast<ObjCInterfaceType>(getObjCInterfaceType(LDecl));
if (canAssignObjCInterfaces(LHS, RHS)) {
- llvm::SmallVector<ObjCProtocolDecl *, 8> Protocols;
+ SmallVector<ObjCProtocolDecl *, 8> Protocols;
getIntersectionOfProtocols(*this, Lptr, Rptr, Protocols);
QualType Result = QualType(LHS, 0);
@@ -5552,13 +5600,13 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (lbaseInfo.getProducesResult() != rbaseInfo.getProducesResult())
return QualType();
- // It's noreturn if either type is.
- // FIXME: some uses, e.g. conditional exprs, really want this to be 'both'.
- bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn();
- if (NoReturn != lbaseInfo.getNoReturn())
+ // functypes which return are preferred over those that do not.
+ if (lbaseInfo.getNoReturn() && !rbaseInfo.getNoReturn())
allLTypes = false;
- if (NoReturn != rbaseInfo.getNoReturn())
+ 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();
FunctionType::ExtInfo einfo = lbaseInfo.withNoReturn(NoReturn);
@@ -5579,8 +5627,12 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (lproto->getTypeQuals() != rproto->getTypeQuals())
return QualType();
+ if (LangOpts.ObjCAutoRefCount &&
+ !FunctionTypesMatchOnNSConsumedAttrs(rproto, lproto))
+ return QualType();
+
// Check argument compatibility
- llvm::SmallVector<QualType, 10> types;
+ SmallVector<QualType, 10> types;
for (unsigned i = 0; i < lproto_nargs; i++) {
QualType largtype = lproto->getArgType(i).getUnqualifiedType();
QualType rargtype = rproto->getArgType(i).getUnqualifiedType();
@@ -5603,6 +5655,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (getCanonicalType(argtype) != getCanonicalType(rargtype))
allRTypes = false;
}
+
if (allLTypes) return lhs;
if (allRTypes) return rhs;
@@ -5756,22 +5809,19 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
#include "clang/AST/TypeNodes.def"
- assert(false && "Non-canonical and dependent types shouldn't get here");
- return QualType();
+ llvm_unreachable("Non-canonical and dependent types shouldn't get here");
case Type::LValueReference:
case Type::RValueReference:
case Type::MemberPointer:
- assert(false && "C++ should never be in mergeTypes");
- return QualType();
+ llvm_unreachable("C++ should never be in mergeTypes");
case Type::ObjCInterface:
case Type::IncompleteArray:
case Type::VariableArray:
case Type::FunctionProto:
case Type::ExtVector:
- assert(false && "Types are eliminated above");
- return QualType();
+ llvm_unreachable("Types are eliminated above");
case Type::Pointer:
{
@@ -5809,6 +5859,24 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
return RHS;
return getBlockPointerType(ResultType);
}
+ case Type::Atomic:
+ {
+ // Merge two pointer types, while trying to preserve typedef info
+ QualType LHSValue = LHS->getAs<AtomicType>()->getValueType();
+ QualType RHSValue = RHS->getAs<AtomicType>()->getValueType();
+ if (Unqualified) {
+ LHSValue = LHSValue.getUnqualifiedType();
+ RHSValue = RHSValue.getUnqualifiedType();
+ }
+ QualType ResultType = mergeTypes(LHSValue, RHSValue, false,
+ Unqualified);
+ if (ResultType.isNull()) return QualType();
+ if (getCanonicalType(LHSValue) == getCanonicalType(ResultType))
+ return LHS;
+ if (getCanonicalType(RHSValue) == getCanonicalType(ResultType))
+ return RHS;
+ return getAtomicType(ResultType);
+ }
case Type::ConstantArray:
{
const ConstantArrayType* LCAT = getAsConstantArrayType(LHS);
@@ -5904,6 +5972,26 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
return QualType();
}
+bool ASTContext::FunctionTypesMatchOnNSConsumedAttrs(
+ const FunctionProtoType *FromFunctionType,
+ const FunctionProtoType *ToFunctionType) {
+ if (FromFunctionType->hasAnyConsumedArgs() !=
+ ToFunctionType->hasAnyConsumedArgs())
+ return false;
+ FunctionProtoType::ExtProtoInfo FromEPI =
+ FromFunctionType->getExtProtoInfo();
+ FunctionProtoType::ExtProtoInfo ToEPI =
+ ToFunctionType->getExtProtoInfo();
+ if (FromEPI.ConsumedArguments && ToEPI.ConsumedArguments)
+ for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumArgs();
+ ArgIdx != NumArgs; ++ArgIdx) {
+ if (FromEPI.ConsumedArguments[ArgIdx] !=
+ ToEPI.ConsumedArguments[ArgIdx])
+ return false;
+ }
+ return true;
+}
+
/// mergeObjCGCQualifiers - This routine merges ObjC's GC attribute of 'LHS' and
/// 'RHS' attributes and returns the merged version; including for function
/// return types.
@@ -6022,8 +6110,7 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) {
case BuiltinType::Int128:
return UnsignedInt128Ty;
default:
- assert(0 && "Unexpected signed integer type");
- return QualType();
+ llvm_unreachable("Unexpected signed integer type");
}
}
@@ -6080,7 +6167,7 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
// Read the base type.
switch (*Str++) {
- default: assert(0 && "Unknown builtin type letter!");
+ default: llvm_unreachable("Unknown builtin type letter!");
case 'v':
assert(HowLong == 0 && !Signed && !Unsigned &&
"Bad modifiers used with 'v'!");
@@ -6183,7 +6270,11 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
assert(!RequiresICE && "Can't require complex ICE");
Type = Context.getComplexType(ElementType);
break;
- }
+ }
+ case 'Y' : {
+ Type = Context.getPointerDiffType();
+ break;
+ }
case 'P':
Type = Context.getFILEType();
if (Type.isNull()) {
@@ -6247,7 +6338,7 @@ QualType ASTContext::GetBuiltinType(unsigned Id,
unsigned *IntegerConstantArgs) const {
const char *TypeStr = BuiltinInfo.GetTypeString(Id);
- llvm::SmallVector<QualType, 8> ArgTypes;
+ SmallVector<QualType, 8> ArgTypes;
bool RequiresICE = false;
Error = GE_None;
@@ -6405,7 +6496,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// Forward declarations aren't required.
if (!FD->doesThisDeclarationHaveABody())
- return false;
+ return FD->doesDeclarationForceExternallyVisibleDefinition();
// Constructors and destructors are required.
if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>())
@@ -6431,7 +6522,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
return false;
return true;
}
-
+
const VarDecl *VD = cast<VarDecl>(D);
assert(VD->isFileVarDecl() && "Expected file scoped var");
@@ -6472,30 +6563,42 @@ bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const {
}
MangleContext *ASTContext::createMangleContext() {
- switch (Target.getCXXABI()) {
+ switch (Target->getCXXABI()) {
case CXXABI_ARM:
case CXXABI_Itanium:
return createItaniumMangleContext(*this, getDiagnostics());
case CXXABI_Microsoft:
return createMicrosoftMangleContext(*this, getDiagnostics());
}
- assert(0 && "Unsupported ABI");
- return 0;
+ llvm_unreachable("Unsupported ABI");
}
CXXABI::~CXXABI() {}
size_t ASTContext::getSideTableAllocatedMemory() const {
- size_t bytes = 0;
- bytes += ASTRecordLayouts.getMemorySize();
- bytes += ObjCLayouts.getMemorySize();
- bytes += KeyFunctions.getMemorySize();
- bytes += ObjCImpls.getMemorySize();
- bytes += BlockVarCopyInits.getMemorySize();
- bytes += DeclAttrs.getMemorySize();
- bytes += InstantiatedFromStaticDataMember.getMemorySize();
- bytes += InstantiatedFromUsingDecl.getMemorySize();
- bytes += InstantiatedFromUsingShadowDecl.getMemorySize();
- bytes += InstantiatedFromUnnamedFieldDecl.getMemorySize();
- return bytes;
+ return ASTRecordLayouts.getMemorySize()
+ + llvm::capacity_in_bytes(ObjCLayouts)
+ + llvm::capacity_in_bytes(KeyFunctions)
+ + llvm::capacity_in_bytes(ObjCImpls)
+ + llvm::capacity_in_bytes(BlockVarCopyInits)
+ + llvm::capacity_in_bytes(DeclAttrs)
+ + llvm::capacity_in_bytes(InstantiatedFromStaticDataMember)
+ + llvm::capacity_in_bytes(InstantiatedFromUsingDecl)
+ + llvm::capacity_in_bytes(InstantiatedFromUsingShadowDecl)
+ + llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl)
+ + llvm::capacity_in_bytes(OverriddenMethods)
+ + llvm::capacity_in_bytes(Types)
+ + llvm::capacity_in_bytes(VariableArrayTypes)
+ + llvm::capacity_in_bytes(ClassScopeSpecializationPattern);
+}
+
+void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) {
+ ParamIndices[D] = index;
+}
+
+unsigned ASTContext::getParameterIndex(const ParmVarDecl *D) const {
+ ParameterIndexTable::const_iterator I = ParamIndices.find(D);
+ assert(I != ParamIndices.end() &&
+ "ParmIndices lacks entry set by ParmVarDecl");
+ return I->second;
}
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 7c91b5cb7a00..07820dc3cc56 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -152,16 +152,16 @@ break; \
/// diagnostic message
static std::string
ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
- const Diagnostic::ArgumentValue *PrevArgs,
+ const DiagnosticsEngine::ArgumentValue *PrevArgs,
unsigned NumPrevArgs,
- llvm::SmallVectorImpl<intptr_t> &QualTypeVals) {
+ SmallVectorImpl<intptr_t> &QualTypeVals) {
// FIXME: Playing with std::string is really slow.
bool ForceAKA = false;
QualType CanTy = Ty.getCanonicalType();
- std::string S = Ty.getAsString(Context.PrintingPolicy);
- std::string CanS = CanTy.getAsString(Context.PrintingPolicy);
+ std::string S = Ty.getAsString(Context.getPrintingPolicy());
+ std::string CanS = CanTy.getAsString(Context.getPrintingPolicy());
- for (llvm::SmallVectorImpl<intptr_t>::iterator I = QualTypeVals.begin(),
+ for (SmallVectorImpl<intptr_t>::iterator I = QualTypeVals.begin(),
E = QualTypeVals.end(); I != E; ++I) {
QualType CompareTy =
QualType::getFromOpaquePtr(reinterpret_cast<void*>(*I));
@@ -170,10 +170,10 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
QualType CompareCanTy = CompareTy.getCanonicalType();
if (CompareCanTy == CanTy)
continue; // Same canonical types
- std::string CompareS = CompareTy.getAsString(Context.PrintingPolicy);
+ std::string CompareS = CompareTy.getAsString(Context.getPrintingPolicy());
if (CompareS != S)
continue; // Original strings are different
- std::string CompareCanS = CompareCanTy.getAsString(Context.PrintingPolicy);
+ std::string CompareCanS = CompareCanTy.getAsString(Context.getPrintingPolicy());
if (CompareCanS == CanS)
continue; // No new info from canonical type
@@ -186,7 +186,7 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
bool Repeated = false;
for (unsigned i = 0; i != NumPrevArgs; ++i) {
// TODO: Handle ak_declcontext case.
- if (PrevArgs[i].first == Diagnostic::ak_qualtype) {
+ if (PrevArgs[i].first == DiagnosticsEngine::ak_qualtype) {
void *Ptr = (void*)PrevArgs[i].second;
QualType PrevTy(QualType::getFromOpaquePtr(Ptr));
if (PrevTy == Ty) {
@@ -205,7 +205,7 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
if (DesugaredTy == Ty) {
DesugaredTy = Ty.getCanonicalType();
}
- std::string akaStr = DesugaredTy.getAsString(Context.PrintingPolicy);
+ std::string akaStr = DesugaredTy.getAsString(Context.getPrintingPolicy());
if (akaStr != S) {
S = "'" + S + "' (aka '" + akaStr + "')";
return S;
@@ -218,25 +218,25 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
}
void clang::FormatASTNodeDiagnosticArgument(
- Diagnostic::ArgumentKind Kind,
+ DiagnosticsEngine::ArgumentKind Kind,
intptr_t Val,
const char *Modifier,
unsigned ModLen,
const char *Argument,
unsigned ArgLen,
- const Diagnostic::ArgumentValue *PrevArgs,
+ const DiagnosticsEngine::ArgumentValue *PrevArgs,
unsigned NumPrevArgs,
- llvm::SmallVectorImpl<char> &Output,
+ SmallVectorImpl<char> &Output,
void *Cookie,
- llvm::SmallVectorImpl<intptr_t> &QualTypeVals) {
+ SmallVectorImpl<intptr_t> &QualTypeVals) {
ASTContext &Context = *static_cast<ASTContext*>(Cookie);
std::string S;
bool NeedQuotes = true;
switch (Kind) {
- default: assert(0 && "unknown ArgumentKind");
- case Diagnostic::ak_qualtype: {
+ default: llvm_unreachable("unknown ArgumentKind");
+ case DiagnosticsEngine::ak_qualtype: {
assert(ModLen == 0 && ArgLen == 0 &&
"Invalid modifier for QualType argument");
@@ -246,7 +246,7 @@ void clang::FormatASTNodeDiagnosticArgument(
NeedQuotes = false;
break;
}
- case Diagnostic::ak_declarationname: {
+ case DiagnosticsEngine::ak_declarationname: {
DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
S = N.getAsString();
@@ -260,7 +260,7 @@ void clang::FormatASTNodeDiagnosticArgument(
"Invalid modifier for DeclarationName argument");
break;
}
- case Diagnostic::ak_nameddecl: {
+ case DiagnosticsEngine::ak_nameddecl: {
bool Qualified;
if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
Qualified = true;
@@ -269,18 +269,18 @@ void clang::FormatASTNodeDiagnosticArgument(
"Invalid modifier for NamedDecl* argument");
Qualified = false;
}
- reinterpret_cast<NamedDecl*>(Val)->
- getNameForDiagnostic(S, Context.PrintingPolicy, Qualified);
+ const NamedDecl *ND = reinterpret_cast<const NamedDecl*>(Val);
+ ND->getNameForDiagnostic(S, Context.getPrintingPolicy(), Qualified);
break;
}
- case Diagnostic::ak_nestednamespec: {
+ case DiagnosticsEngine::ak_nestednamespec: {
llvm::raw_string_ostream OS(S);
reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS,
- Context.PrintingPolicy);
+ Context.getPrintingPolicy());
NeedQuotes = false;
break;
}
- case Diagnostic::ak_declcontext: {
+ case DiagnosticsEngine::ak_declcontext: {
DeclContext *DC = reinterpret_cast<DeclContext *> (Val);
assert(DC && "Should never have a null declaration context");
@@ -305,7 +305,7 @@ void clang::FormatASTNodeDiagnosticArgument(
S += "function ";
S += "'";
- ND->getNameForDiagnostic(S, Context.PrintingPolicy, true);
+ ND->getNameForDiagnostic(S, Context.getPrintingPolicy(), true);
S += "'";
}
NeedQuotes = false;
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index f5e392f88d0b..af66b04c3ad7 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -59,6 +59,7 @@ namespace {
QualType VisitFunctionNoProtoType(const FunctionNoProtoType *T);
QualType VisitFunctionProtoType(const FunctionProtoType *T);
// FIXME: UnresolvedUsingType
+ QualType VisitParenType(const ParenType *T);
QualType VisitTypedefType(const TypedefType *T);
QualType VisitTypeOfExprType(const TypeOfExprType *T);
// FIXME: DependentTypeOfExprType
@@ -83,16 +84,20 @@ namespace {
bool ImportDeclParts(NamedDecl *D, DeclContext *&DC,
DeclContext *&LexicalDC, DeclarationName &Name,
SourceLocation &Loc);
+ void ImportDefinitionIfNeeded(Decl *FromD, Decl *ToD = 0);
void ImportDeclarationNameLoc(const DeclarationNameInfo &From,
DeclarationNameInfo& To);
void ImportDeclContext(DeclContext *FromDC, bool ForceImport = false);
- bool ImportDefinition(RecordDecl *From, RecordDecl *To);
+ bool ImportDefinition(RecordDecl *From, RecordDecl *To,
+ bool ForceImport = false);
+ bool ImportDefinition(EnumDecl *From, EnumDecl *To,
+ bool ForceImport = false);
TemplateParameterList *ImportTemplateParameterList(
TemplateParameterList *Params);
TemplateArgument ImportTemplateArgument(const TemplateArgument &From);
bool ImportTemplateArguments(const TemplateArgument *FromArgs,
unsigned NumFromArgs,
- llvm::SmallVectorImpl<TemplateArgument> &ToArgs);
+ SmallVectorImpl<TemplateArgument> &ToArgs);
bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord);
bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord);
bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To);
@@ -805,12 +810,74 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
break;
}
-
+
+ case Type::Atomic: {
+ if (!IsStructurallyEquivalent(Context,
+ cast<AtomicType>(T1)->getValueType(),
+ cast<AtomicType>(T2)->getValueType()))
+ return false;
+ break;
+ }
+
} // end switch
return true;
}
+/// \brief Determine structural equivalence of two fields.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ FieldDecl *Field1, FieldDecl *Field2) {
+ RecordDecl *Owner2 = cast<RecordDecl>(Field2->getDeclContext());
+
+ if (!IsStructurallyEquivalent(Context,
+ Field1->getType(), Field2->getType())) {
+ Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(Owner2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_field)
+ << Field2->getDeclName() << Field2->getType();
+ Context.Diag1(Field1->getLocation(), diag::note_odr_field)
+ << Field1->getDeclName() << Field1->getType();
+ return false;
+ }
+
+ if (Field1->isBitField() != Field2->isBitField()) {
+ Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(Owner2);
+ if (Field1->isBitField()) {
+ Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
+ << Field1->getDeclName() << Field1->getType()
+ << Field1->getBitWidthValue(Context.C1);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field)
+ << Field2->getDeclName();
+ } else {
+ Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
+ << Field2->getDeclName() << Field2->getType()
+ << Field2->getBitWidthValue(Context.C2);
+ Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field)
+ << Field1->getDeclName();
+ }
+ return false;
+ }
+
+ if (Field1->isBitField()) {
+ // Make sure that the bit-fields are the same length.
+ unsigned Bits1 = Field1->getBitWidthValue(Context.C1);
+ unsigned Bits2 = Field2->getBitWidthValue(Context.C2);
+
+ if (Bits1 != Bits2) {
+ Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(Owner2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
+ << Field2->getDeclName() << Field2->getType() << Bits2;
+ Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
+ << Field1->getDeclName() << Field1->getType() << Bits1;
+ return false;
+ }
+ }
+
+ return true;
+}
+
/// \brief Determine structural equivalence of two records.
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
RecordDecl *D1, RecordDecl *D2) {
@@ -928,61 +995,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
}
- if (!IsStructurallyEquivalent(Context,
- Field1->getType(), Field2->getType())) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(Field2->getLocation(), diag::note_odr_field)
- << Field2->getDeclName() << Field2->getType();
- Context.Diag1(Field1->getLocation(), diag::note_odr_field)
- << Field1->getDeclName() << Field1->getType();
- return false;
- }
-
- if (Field1->isBitField() != Field2->isBitField()) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- if (Field1->isBitField()) {
- llvm::APSInt Bits;
- Field1->getBitWidth()->isIntegerConstantExpr(Bits, Context.C1);
- Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
- << Field1->getDeclName() << Field1->getType()
- << Bits.toString(10, false);
- Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field)
- << Field2->getDeclName();
- } else {
- llvm::APSInt Bits;
- Field2->getBitWidth()->isIntegerConstantExpr(Bits, Context.C2);
- Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
- << Field2->getDeclName() << Field2->getType()
- << Bits.toString(10, false);
- Context.Diag1(Field1->getLocation(),
- diag::note_odr_not_bit_field)
- << Field1->getDeclName();
- }
- return false;
- }
-
- if (Field1->isBitField()) {
- // Make sure that the bit-fields are the same length.
- llvm::APSInt Bits1, Bits2;
- if (!Field1->getBitWidth()->isIntegerConstantExpr(Bits1, Context.C1))
- return false;
- if (!Field2->getBitWidth()->isIntegerConstantExpr(Bits2, Context.C2))
- return false;
-
- if (!IsSameValue(Bits1, Bits2)) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
- << Field2->getDeclName() << Field2->getType()
- << Bits2.toString(10, false);
- Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
- << Field1->getDeclName() << Field1->getType()
- << Bits1.toString(10, false);
- return false;
- }
- }
+ if (!IsStructurallyEquivalent(Context, *Field1, *Field2))
+ return false;
}
if (Field2 != Field2End) {
@@ -1360,6 +1374,7 @@ QualType ASTNodeImporter::VisitBuiltinType(const BuiltinType *T) {
case BuiltinType::Long : return Importer.getToContext().LongTy;
case BuiltinType::LongLong : return Importer.getToContext().LongLongTy;
case BuiltinType::Int128 : return Importer.getToContext().Int128Ty;
+ case BuiltinType::Half: return Importer.getToContext().HalfTy;
case BuiltinType::Float: return Importer.getToContext().FloatTy;
case BuiltinType::Double: return Importer.getToContext().DoubleTy;
case BuiltinType::LongDouble: return Importer.getToContext().LongDoubleTy;
@@ -1518,7 +1533,7 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) {
return QualType();
// Import argument types
- llvm::SmallVector<QualType, 4> ArgTypes;
+ SmallVector<QualType, 4> ArgTypes;
for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(),
AEnd = T->arg_type_end();
A != AEnd; ++A) {
@@ -1529,7 +1544,7 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) {
}
// Import exception types
- llvm::SmallVector<QualType, 4> ExceptionTypes;
+ SmallVector<QualType, 4> ExceptionTypes;
for (FunctionProtoType::exception_iterator E = T->exception_begin(),
EEnd = T->exception_end();
E != EEnd; ++E) {
@@ -1546,6 +1561,14 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) {
ArgTypes.size(), EPI);
}
+QualType ASTNodeImporter::VisitParenType(const ParenType *T) {
+ QualType ToInnerType = Importer.Import(T->getInnerType());
+ if (ToInnerType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getParenType(ToInnerType);
+}
+
QualType ASTNodeImporter::VisitTypedefType(const TypedefType *T) {
TypedefNameDecl *ToDecl
= dyn_cast_or_null<TypedefNameDecl>(Importer.Import(T->getDecl()));
@@ -1628,7 +1651,7 @@ QualType ASTNodeImporter::VisitTemplateSpecializationType(
if (ToTemplate.isNull())
return QualType();
- llvm::SmallVector<TemplateArgument, 2> ToTemplateArgs;
+ SmallVector<TemplateArgument, 2> ToTemplateArgs;
if (ImportTemplateArguments(T->getArgs(), T->getNumArgs(), ToTemplateArgs))
return QualType();
@@ -1677,7 +1700,7 @@ QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) {
if (ToBaseType.isNull())
return QualType();
- llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols;
+ SmallVector<ObjCProtocolDecl *, 4> Protocols;
for (ObjCObjectType::qual_iterator P = T->qual_begin(),
PEnd = T->qual_end();
P != PEnd; ++P) {
@@ -1731,6 +1754,35 @@ bool ASTNodeImporter::ImportDeclParts(NamedDecl *D, DeclContext *&DC,
return false;
}
+void ASTNodeImporter::ImportDefinitionIfNeeded(Decl *FromD, Decl *ToD) {
+ if (!FromD)
+ return;
+
+ if (!ToD) {
+ ToD = Importer.Import(FromD);
+ if (!ToD)
+ return;
+ }
+
+ if (RecordDecl *FromRecord = dyn_cast<RecordDecl>(FromD)) {
+ if (RecordDecl *ToRecord = cast_or_null<RecordDecl>(ToD)) {
+ if (FromRecord->getDefinition() && !ToRecord->getDefinition()) {
+ ImportDefinition(FromRecord, ToRecord);
+ }
+ }
+ return;
+ }
+
+ if (EnumDecl *FromEnum = dyn_cast<EnumDecl>(FromD)) {
+ if (EnumDecl *ToEnum = cast_or_null<EnumDecl>(ToD)) {
+ if (FromEnum->getDefinition() && !ToEnum->getDefinition()) {
+ ImportDefinition(FromEnum, ToEnum);
+ }
+ }
+ return;
+ }
+}
+
void
ASTNodeImporter::ImportDeclarationNameLoc(const DeclarationNameInfo &From,
DeclarationNameInfo& To) {
@@ -1761,16 +1813,13 @@ ASTNodeImporter::ImportDeclarationNameLoc(const DeclarationNameInfo &From,
To.setNamedTypeInfo(Importer.Import(FromTInfo));
return;
}
- assert(0 && "Unknown name kind.");
+ llvm_unreachable("Unknown name kind.");
}
}
void ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
if (Importer.isMinimalImport() && !ForceImport) {
- if (DeclContext *ToDC = Importer.ImportContext(FromDC)) {
- ToDC->setHasExternalLexicalStorage();
- ToDC->setHasExternalVisibleStorage();
- }
+ Importer.ImportContext(FromDC);
return;
}
@@ -1781,8 +1830,9 @@ void ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
Importer.Import(*From);
}
-bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To) {
- if (To->getDefinition())
+bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
+ bool ForceImport) {
+ if (To->getDefinition() || To->isBeingDefined())
return false;
To->startDefinition();
@@ -1791,7 +1841,7 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To) {
if (CXXRecordDecl *ToCXX = dyn_cast<CXXRecordDecl>(To)) {
CXXRecordDecl *FromCXX = cast<CXXRecordDecl>(From);
- llvm::SmallVector<CXXBaseSpecifier *, 4> Bases;
+ SmallVector<CXXBaseSpecifier *, 4> Bases;
for (CXXRecordDecl::base_class_iterator
Base1 = FromCXX->bases_begin(),
FromBaseEnd = FromCXX->bases_end();
@@ -1804,7 +1854,10 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To) {
SourceLocation EllipsisLoc;
if (Base1->isPackExpansion())
EllipsisLoc = Importer.Import(Base1->getEllipsisLoc());
-
+
+ // Ensure that we have a definition for the base.
+ ImportDefinitionIfNeeded(Base1->getType()->getAsCXXRecordDecl());
+
Bases.push_back(
new (Importer.getToContext())
CXXBaseSpecifier(Importer.Import(Base1->getSourceRange()),
@@ -1818,14 +1871,39 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To) {
ToCXX->setBases(Bases.data(), Bases.size());
}
- ImportDeclContext(From);
+ ImportDeclContext(From, ForceImport);
To->completeDefinition();
return false;
}
+bool ASTNodeImporter::ImportDefinition(EnumDecl *From, EnumDecl *To,
+ bool ForceImport) {
+ if (To->getDefinition() || To->isBeingDefined())
+ return false;
+
+ To->startDefinition();
+
+ QualType T = Importer.Import(Importer.getFromContext().getTypeDeclType(From));
+ if (T.isNull())
+ return true;
+
+ QualType ToPromotionType = Importer.Import(From->getPromotionType());
+ if (ToPromotionType.isNull())
+ return true;
+
+ ImportDeclContext(From, ForceImport);
+
+ // FIXME: we might need to merge the number of positive or negative bits
+ // if the enumerator lists don't match.
+ To->completeDefinition(T, ToPromotionType,
+ From->getNumPositiveBits(),
+ From->getNumNegativeBits());
+ return false;
+}
+
TemplateParameterList *ASTNodeImporter::ImportTemplateParameterList(
TemplateParameterList *Params) {
- llvm::SmallVector<NamedDecl *, 4> ToParams;
+ SmallVector<NamedDecl *, 4> ToParams;
ToParams.reserve(Params->size());
for (TemplateParameterList::iterator P = Params->begin(),
PEnd = Params->end();
@@ -1892,7 +1970,7 @@ ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) {
return TemplateArgument();
case TemplateArgument::Pack: {
- llvm::SmallVector<TemplateArgument, 2> ToPack;
+ SmallVector<TemplateArgument, 2> ToPack;
ToPack.reserve(From.pack_size());
if (ImportTemplateArguments(From.pack_begin(), From.pack_size(), ToPack))
return TemplateArgument();
@@ -1910,7 +1988,7 @@ ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) {
bool ASTNodeImporter::ImportTemplateArguments(const TemplateArgument *FromArgs,
unsigned NumFromArgs,
- llvm::SmallVectorImpl<TemplateArgument> &ToArgs) {
+ SmallVectorImpl<TemplateArgument> &ToArgs) {
for (unsigned I = 0; I != NumFromArgs; ++I) {
TemplateArgument To = ImportTemplateArgument(FromArgs[I]);
if (To.isNull() && !FromArgs[I].isNull())
@@ -1969,20 +2047,20 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
else
MergeWithNamespace = cast<NamespaceDecl>(DC)->getAnonymousNamespace();
} else {
- llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
- for (DeclContext::lookup_result Lookup = DC->lookup(Name);
- Lookup.first != Lookup.second;
- ++Lookup.first) {
- if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Namespace))
+ SmallVector<NamedDecl *, 4> ConflictingDecls;
+ llvm::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))
continue;
- if (NamespaceDecl *FoundNS = dyn_cast<NamespaceDecl>(*Lookup.first)) {
+ if (NamespaceDecl *FoundNS = dyn_cast<NamespaceDecl>(FoundDecls[I])) {
MergeWithNamespace = FoundNS;
ConflictingDecls.clear();
break;
}
- ConflictingDecls.push_back(*Lookup.first);
+ ConflictingDecls.push_back(FoundDecls[I]);
}
if (!ConflictingDecls.empty()) {
@@ -2029,21 +2107,21 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
// seen a typedef with the same name (that we can merge with) or any
// other entity by that name (which name lookup could conflict with).
if (!DC->isFunctionOrMethod()) {
- llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
+ SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
- for (DeclContext::lookup_result Lookup = DC->lookup(Name);
- Lookup.first != Lookup.second;
- ++Lookup.first) {
- if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ llvm::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 (TypedefNameDecl *FoundTypedef =
- dyn_cast<TypedefNameDecl>(*Lookup.first)) {
+ dyn_cast<TypedefNameDecl>(FoundDecls[I])) {
if (Importer.IsStructurallyEquivalent(D->getUnderlyingType(),
FoundTypedef->getUnderlyingType()))
return Importer.Imported(D, FoundTypedef);
}
- ConflictingDecls.push_back(*Lookup.first);
+ ConflictingDecls.push_back(FoundDecls[I]);
}
if (!ConflictingDecls.empty()) {
@@ -2065,15 +2143,16 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
SourceLocation StartL = Importer.Import(D->getLocStart());
TypedefNameDecl *ToTypedef;
if (IsAlias)
+ ToTypedef = TypeAliasDecl::Create(Importer.getToContext(), DC,
+ StartL, Loc,
+ Name.getAsIdentifierInfo(),
+ TInfo);
+ else
ToTypedef = TypedefDecl::Create(Importer.getToContext(), DC,
StartL, Loc,
Name.getAsIdentifierInfo(),
TInfo);
- else
- ToTypedef = TypeAliasDecl::Create(Importer.getToContext(), DC,
- StartL, Loc,
- Name.getAsIdentifierInfo(),
- TInfo);
+
ToTypedef->setAccess(D->getAccess());
ToTypedef->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToTypedef);
@@ -2109,14 +2188,14 @@ 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) {
- llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
- for (DeclContext::lookup_result Lookup = DC->lookup(Name);
- Lookup.first != Lookup.second;
- ++Lookup.first) {
- if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ SmallVector<NamedDecl *, 4> ConflictingDecls;
+ llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ DC->localUncachedLookup(SearchName, FoundDecls);
+ for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
+ if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
- Decl *Found = *Lookup.first;
+ Decl *Found = FoundDecls[I];
if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Found)) {
if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>())
Found = Tag->getDecl();
@@ -2127,7 +2206,7 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
return Importer.Imported(D, FoundEnum);
}
- ConflictingDecls.push_back(*Lookup.first);
+ ConflictingDecls.push_back(FoundDecls[I]);
}
if (!ConflictingDecls.empty()) {
@@ -2157,25 +2236,9 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
D2->setIntegerType(ToIntegerType);
// Import the definition
- if (D->isDefinition()) {
- QualType T = Importer.Import(Importer.getFromContext().getTypeDeclType(D));
- if (T.isNull())
- return 0;
+ if (D->isCompleteDefinition() && ImportDefinition(D, D2))
+ return 0;
- QualType ToPromotionType = Importer.Import(D->getPromotionType());
- if (ToPromotionType.isNull())
- return 0;
-
- D2->startDefinition();
- ImportDeclContext(D);
-
- // FIXME: we might need to merge the number of positive or negative bits
- // if the enumerator lists don't match.
- D2->completeDefinition(T, ToPromotionType,
- D->getNumPositiveBits(),
- D->getNumNegativeBits());
- }
-
return D2;
}
@@ -2211,14 +2274,14 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
// We may already have a record of the same name; try to find and match it.
RecordDecl *AdoptDecl = 0;
if (!DC->isFunctionOrMethod() && SearchName) {
- llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
- for (DeclContext::lookup_result Lookup = DC->lookup(Name);
- Lookup.first != Lookup.second;
- ++Lookup.first) {
- if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ SmallVector<NamedDecl *, 4> ConflictingDecls;
+ llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ DC->localUncachedLookup(SearchName, FoundDecls);
+ for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
+ if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
- Decl *Found = *Lookup.first;
+ Decl *Found = FoundDecls[I];
if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Found)) {
if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>())
Found = Tag->getDecl();
@@ -2226,7 +2289,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
if (RecordDecl *FoundRecord = dyn_cast<RecordDecl>(Found)) {
if (RecordDecl *FoundDef = FoundRecord->getDefinition()) {
- if (!D->isDefinition() || IsStructuralMatch(D, FoundDef)) {
+ if (!D->isCompleteDefinition() || IsStructuralMatch(D, FoundDef)) {
// The record types structurally match, or the "from" translation
// unit only had a forward declaration anyway; call it the same
// function.
@@ -2241,7 +2304,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
}
}
- ConflictingDecls.push_back(*Lookup.first);
+ ConflictingDecls.push_back(FoundDecls[I]);
}
if (!ConflictingDecls.empty()) {
@@ -2274,7 +2337,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
Importer.Imported(D, D2);
- if (D->isDefinition() && ImportDefinition(D, D2))
+ if (D->isCompleteDefinition() && ImportDefinition(D, D2))
return 0;
return D2;
@@ -2295,15 +2358,15 @@ Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) {
// Determine whether there are any other declarations with the same name and
// in the same context.
if (!LexicalDC->isFunctionOrMethod()) {
- llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
+ SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
- for (DeclContext::lookup_result Lookup = DC->lookup(Name);
- Lookup.first != Lookup.second;
- ++Lookup.first) {
- if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ DC->localUncachedLookup(Name, FoundDecls);
+ for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
+ if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
- ConflictingDecls.push_back(*Lookup.first);
+ ConflictingDecls.push_back(FoundDecls[I]);
}
if (!ConflictingDecls.empty()) {
@@ -2341,15 +2404,15 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// Try to find a function in our own ("to") context with the same name, same
// type, and in the same context as the function we're importing.
if (!LexicalDC->isFunctionOrMethod()) {
- llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
+ SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
- for (DeclContext::lookup_result Lookup = DC->lookup(Name);
- Lookup.first != Lookup.second;
- ++Lookup.first) {
- if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ llvm::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 (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(*Lookup.first)) {
+ if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(FoundDecls[I])) {
if (isExternalLinkage(FoundFunction->getLinkage()) &&
isExternalLinkage(D->getLinkage())) {
if (Importer.IsStructurallyEquivalent(D->getType(),
@@ -2374,7 +2437,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
}
}
- ConflictingDecls.push_back(*Lookup.first);
+ ConflictingDecls.push_back(FoundDecls[I]);
}
if (!ConflictingDecls.empty()) {
@@ -2396,7 +2459,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
return 0;
// Import the function parameters.
- llvm::SmallVector<ParmVarDecl *, 8> Parameters;
+ SmallVector<ParmVarDecl *, 8> Parameters;
for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
P != PEnd; ++P) {
ParmVarDecl *ToP = cast_or_null<ParmVarDecl>(Importer.Import(*P));
@@ -2416,7 +2479,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
NameInfo, T, TInfo,
FromConstructor->isExplicit(),
D->isInlineSpecified(),
- D->isImplicit());
+ D->isImplicit(),
+ D->isConstexpr());
} else if (isa<CXXDestructorDecl>(D)) {
ToFunction = CXXDestructorDecl::Create(Importer.getToContext(),
cast<CXXRecordDecl>(DC),
@@ -2432,6 +2496,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
NameInfo, T, TInfo,
D->isInlineSpecified(),
FromConversion->isExplicit(),
+ D->isConstexpr(),
Importer.Import(D->getLocEnd()));
} else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
ToFunction = CXXMethodDecl::Create(Importer.getToContext(),
@@ -2441,6 +2506,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
Method->isStatic(),
Method->getStorageClassAsWritten(),
Method->isInlineSpecified(),
+ D->isConstexpr(),
Importer.Import(D->getLocEnd()));
} else {
ToFunction = FunctionDecl::Create(Importer.getToContext(), DC,
@@ -2448,7 +2514,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
NameInfo, T, TInfo, D->getStorageClass(),
D->getStorageClassAsWritten(),
D->isInlineSpecified(),
- D->hasWrittenPrototype());
+ D->hasWrittenPrototype(),
+ D->isConstexpr());
}
// Import the qualifier, if any.
@@ -2465,7 +2532,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
Parameters[I]->setOwningFunction(ToFunction);
ToFunction->addDecl(Parameters[I]);
}
- ToFunction->setParams(Parameters.data(), Parameters.size());
+ ToFunction->setParams(Parameters);
// FIXME: Other bits to merge?
@@ -2499,6 +2566,25 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
return 0;
+ // Determine whether we've already imported this field.
+ llvm::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])) {
+ if (Importer.IsStructurallyEquivalent(D->getType(),
+ FoundField->getType())) {
+ Importer.Imported(D, FoundField);
+ return FoundField;
+ }
+
+ Importer.ToDiag(Loc, diag::err_odr_field_type_inconsistent)
+ << Name << D->getType() << FoundField->getType();
+ Importer.ToDiag(FoundField->getLocation(), diag::note_odr_value_here)
+ << FoundField->getType();
+ return 0;
+ }
+ }
+
// Import the type.
QualType T = Importer.Import(D->getType());
if (T.isNull())
@@ -2531,6 +2617,26 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
return 0;
+ // Determine whether we've already imported this field.
+ llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ DC->localUncachedLookup(Name, FoundDecls);
+ for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
+ if (IndirectFieldDecl *FoundField
+ = dyn_cast<IndirectFieldDecl>(FoundDecls[I])) {
+ if (Importer.IsStructurallyEquivalent(D->getType(),
+ FoundField->getType())) {
+ Importer.Imported(D, FoundField);
+ return FoundField;
+ }
+
+ Importer.ToDiag(Loc, diag::err_odr_field_type_inconsistent)
+ << Name << D->getType() << FoundField->getType();
+ Importer.ToDiag(FoundField->getLocation(), diag::note_odr_value_here)
+ << FoundField->getType();
+ return 0;
+ }
+ }
+
// Import the type.
QualType T = Importer.Import(D->getType());
if (T.isNull())
@@ -2568,10 +2674,10 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
return 0;
// Determine whether we've already imported this ivar
- for (DeclContext::lookup_result Lookup = DC->lookup(Name);
- Lookup.first != Lookup.second;
- ++Lookup.first) {
- if (ObjCIvarDecl *FoundIvar = dyn_cast<ObjCIvarDecl>(*Lookup.first)) {
+ llvm::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])) {
if (Importer.IsStructurallyEquivalent(D->getType(),
FoundIvar->getType())) {
Importer.Imported(D, FoundIvar);
@@ -2621,15 +2727,15 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
// in the same context as the variable we're importing.
if (D->isFileVarDecl()) {
VarDecl *MergeWithVar = 0;
- llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
+ SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
- for (DeclContext::lookup_result Lookup = DC->lookup(Name);
- Lookup.first != Lookup.second;
- ++Lookup.first) {
- if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ llvm::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 (VarDecl *FoundVar = dyn_cast<VarDecl>(*Lookup.first)) {
+ if (VarDecl *FoundVar = dyn_cast<VarDecl>(FoundDecls[I])) {
// We have found a variable that we may need to merge with. Check it.
if (isExternalLinkage(FoundVar->getLinkage()) &&
isExternalLinkage(D->getLinkage())) {
@@ -2668,7 +2774,7 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
}
}
- ConflictingDecls.push_back(*Lookup.first);
+ ConflictingDecls.push_back(FoundDecls[I]);
}
if (MergeWithVar) {
@@ -2794,10 +2900,10 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
return 0;
- for (DeclContext::lookup_result Lookup = DC->lookup(Name);
- Lookup.first != Lookup.second;
- ++Lookup.first) {
- if (ObjCMethodDecl *FoundMethod = dyn_cast<ObjCMethodDecl>(*Lookup.first)) {
+ llvm::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])) {
if (FoundMethod->isInstanceMethod() != D->isInstanceMethod())
continue;
@@ -2872,6 +2978,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
D->isInstanceMethod(),
D->isVariadic(),
D->isSynthesized(),
+ D->isImplicit(),
D->isDefined(),
D->getImplementationControl(),
D->hasRelatedResultType());
@@ -2880,7 +2987,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
// deal with implicit parameters.
// Import the parameters
- llvm::SmallVector<ParmVarDecl *, 5> ToParams;
+ SmallVector<ParmVarDecl *, 5> ToParams;
for (ObjCMethodDecl::param_iterator FromP = D->param_begin(),
FromPEnd = D->param_end();
FromP != FromPEnd;
@@ -2897,9 +3004,9 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
ToParams[I]->setOwningFunction(ToMethod);
ToMethod->addDecl(ToParams[I]);
}
- ToMethod->setMethodParams(Importer.getToContext(),
- ToParams.data(), ToParams.size(),
- ToParams.size());
+ SmallVector<SourceLocation, 12> SelLocs;
+ D->getSelectorLocs(SelLocs);
+ ToMethod->setMethodParams(Importer.getToContext(), ToParams, SelLocs);
ToMethod->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToMethod);
@@ -2926,21 +3033,18 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
ObjCCategoryDecl *ToCategory = MergeWithCategory;
if (!ToCategory) {
ToCategory = ObjCCategoryDecl::Create(Importer.getToContext(), DC,
- Importer.Import(D->getAtLoc()),
+ Importer.Import(D->getAtStartLoc()),
Loc,
Importer.Import(D->getCategoryNameLoc()),
- Name.getAsIdentifierInfo());
+ Name.getAsIdentifierInfo(),
+ ToInterface);
ToCategory->setLexicalDeclContext(LexicalDC);
LexicalDC->addDecl(ToCategory);
Importer.Imported(D, ToCategory);
- // Link this category into its class's category list.
- ToCategory->setClassInterface(ToInterface);
- ToCategory->insertNextClassCategory();
-
// Import protocols
- llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols;
- llvm::SmallVector<SourceLocation, 4> ProtocolLocs;
+ SmallVector<ObjCProtocolDecl *, 4> Protocols;
+ SmallVector<SourceLocation, 4> ProtocolLocs;
ObjCCategoryDecl::protocol_loc_iterator FromProtoLoc
= D->protocol_loc_begin();
for (ObjCCategoryDecl::protocol_iterator FromProto = D->protocol_begin(),
@@ -2989,21 +3093,22 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
return 0;
ObjCProtocolDecl *MergeWithProtocol = 0;
- for (DeclContext::lookup_result Lookup = DC->lookup(Name);
- Lookup.first != Lookup.second;
- ++Lookup.first) {
- if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_ObjCProtocol))
+ llvm::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))
continue;
- if ((MergeWithProtocol = dyn_cast<ObjCProtocolDecl>(*Lookup.first)))
+ if ((MergeWithProtocol = dyn_cast<ObjCProtocolDecl>(FoundDecls[I])))
break;
}
ObjCProtocolDecl *ToProto = MergeWithProtocol;
if (!ToProto || ToProto->isForwardDecl()) {
if (!ToProto) {
- ToProto = ObjCProtocolDecl::Create(Importer.getToContext(), DC, Loc,
- Name.getAsIdentifierInfo());
+ ToProto = ObjCProtocolDecl::Create(Importer.getToContext(), DC,
+ Name.getAsIdentifierInfo(), Loc,
+ Importer.Import(D->getAtStartLoc()));
ToProto->setForwardDecl(D->isForwardDecl());
ToProto->setLexicalDeclContext(LexicalDC);
LexicalDC->addDecl(ToProto);
@@ -3011,8 +3116,8 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
Importer.Imported(D, ToProto);
// Import protocols
- llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols;
- llvm::SmallVector<SourceLocation, 4> ProtocolLocs;
+ SmallVector<ObjCProtocolDecl *, 4> Protocols;
+ SmallVector<SourceLocation, 4> ProtocolLocs;
ObjCProtocolDecl::protocol_loc_iterator
FromProtoLoc = D->protocol_loc_begin();
for (ObjCProtocolDecl::protocol_iterator FromProto = D->protocol_begin(),
@@ -3049,23 +3154,22 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
return 0;
ObjCInterfaceDecl *MergeWithIface = 0;
- for (DeclContext::lookup_result Lookup = DC->lookup(Name);
- Lookup.first != Lookup.second;
- ++Lookup.first) {
- if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary))
+ llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ DC->localUncachedLookup(Name, FoundDecls);
+ for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
+ if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary))
continue;
- if ((MergeWithIface = dyn_cast<ObjCInterfaceDecl>(*Lookup.first)))
+ if ((MergeWithIface = dyn_cast<ObjCInterfaceDecl>(FoundDecls[I])))
break;
}
ObjCInterfaceDecl *ToIface = MergeWithIface;
if (!ToIface || ToIface->isForwardDecl()) {
if (!ToIface) {
- ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(),
- DC, Loc,
- Name.getAsIdentifierInfo(),
- Importer.Import(D->getClassLoc()),
+ ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC,
+ Importer.Import(D->getAtStartLoc()),
+ Name.getAsIdentifierInfo(), Loc,
D->isForwardDecl(),
D->isImplicitInterfaceDecl());
ToIface->setForwardDecl(D->isForwardDecl());
@@ -3085,8 +3189,8 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
}
// Import protocols
- llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols;
- llvm::SmallVector<SourceLocation, 4> ProtocolLocs;
+ SmallVector<ObjCProtocolDecl *, 4> Protocols;
+ SmallVector<SourceLocation, 4> ProtocolLocs;
ObjCInterfaceDecl::protocol_loc_iterator
FromProtoLoc = D->protocol_loc_begin();
@@ -3175,9 +3279,10 @@ Decl *ASTNodeImporter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
return 0;
ToImpl = ObjCCategoryImplDecl::Create(Importer.getToContext(), DC,
- Importer.Import(D->getLocation()),
Importer.Import(D->getIdentifier()),
- Category->getClassInterface());
+ Category->getClassInterface(),
+ Importer.Import(D->getLocation()),
+ Importer.Import(D->getAtStartLoc()));
DeclContext *LexicalDC = DC;
if (D->getDeclContext() != D->getLexicalDeclContext()) {
@@ -3219,8 +3324,9 @@ Decl *ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
// now.
Impl = ObjCImplementationDecl::Create(Importer.getToContext(),
Importer.ImportContext(D->getDeclContext()),
+ Iface, Super,
Importer.Import(D->getLocation()),
- Iface, Super);
+ Importer.Import(D->getAtStartLoc()));
if (D->getDeclContext() != D->getLexicalDeclContext()) {
DeclContext *LexicalDC
@@ -3279,11 +3385,11 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
return 0;
// Check whether we have already imported this property.
- for (DeclContext::lookup_result Lookup = DC->lookup(Name);
- Lookup.first != Lookup.second;
- ++Lookup.first) {
+ llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ DC->localUncachedLookup(Name, FoundDecls);
+ for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (ObjCPropertyDecl *FoundProp
- = dyn_cast<ObjCPropertyDecl>(*Lookup.first)) {
+ = dyn_cast<ObjCPropertyDecl>(FoundDecls[I])) {
// Check property types.
if (!Importer.IsStructurallyEquivalent(D->getType(),
FoundProp->getType())) {
@@ -3430,8 +3536,8 @@ ASTNodeImporter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
// Import the location of this declaration.
SourceLocation Loc = Importer.Import(D->getLocation());
- llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols;
- llvm::SmallVector<SourceLocation, 4> Locations;
+ SmallVector<ObjCProtocolDecl *, 4> Protocols;
+ SmallVector<SourceLocation, 4> Locations;
ObjCForwardProtocolDecl::protocol_loc_iterator FromProtoLoc
= D->protocol_loc_begin();
for (ObjCForwardProtocolDecl::protocol_iterator FromProto
@@ -3472,25 +3578,14 @@ Decl *ASTNodeImporter::VisitObjCClassDecl(ObjCClassDecl *D) {
// Import the location of this declaration.
SourceLocation Loc = Importer.Import(D->getLocation());
-
- llvm::SmallVector<ObjCInterfaceDecl *, 4> Interfaces;
- llvm::SmallVector<SourceLocation, 4> Locations;
- for (ObjCClassDecl::iterator From = D->begin(), FromEnd = D->end();
- From != FromEnd; ++From) {
- ObjCInterfaceDecl *ToIface
- = cast_or_null<ObjCInterfaceDecl>(Importer.Import(From->getInterface()));
- if (!ToIface)
- continue;
-
- Interfaces.push_back(ToIface);
- Locations.push_back(Importer.Import(From->getLocation()));
- }
-
+ ObjCClassDecl::ObjCClassRef *From = D->getForwardDecl();
+ ObjCInterfaceDecl *ToIface
+ = cast_or_null<ObjCInterfaceDecl>(Importer.Import(From->getInterface()));
ObjCClassDecl *ToClass = ObjCClassDecl::Create(Importer.getToContext(), DC,
- Loc,
- Interfaces.data(),
- Locations.data(),
- Interfaces.size());
+ Loc,
+ ToIface,
+ Importer.Import(From->getLocation()));
+
ToClass->setLexicalDeclContext(LexicalDC);
LexicalDC->addDecl(ToClass);
Importer.Imported(D, ToClass);
@@ -3594,14 +3689,14 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// We may already have a template of the same name; try to find and match it.
if (!DC->isFunctionOrMethod()) {
- llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
- for (DeclContext::lookup_result Lookup = DC->lookup(Name);
- Lookup.first != Lookup.second;
- ++Lookup.first) {
- if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary))
+ SmallVector<NamedDecl *, 4> ConflictingDecls;
+ llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ DC->localUncachedLookup(Name, FoundDecls);
+ for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
+ if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary))
continue;
- Decl *Found = *Lookup.first;
+ Decl *Found = FoundDecls[I];
if (ClassTemplateDecl *FoundTemplate
= dyn_cast<ClassTemplateDecl>(Found)) {
if (IsStructuralMatch(D, FoundTemplate)) {
@@ -3614,7 +3709,7 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
}
}
- ConflictingDecls.push_back(*Lookup.first);
+ ConflictingDecls.push_back(FoundDecls[I]);
}
if (!ConflictingDecls.empty()) {
@@ -3660,7 +3755,8 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
Importer.Imported(D, D2);
Importer.Imported(DTemplated, D2Templated);
- if (DTemplated->isDefinition() && !D2Templated->isDefinition()) {
+ if (DTemplated->isCompleteDefinition() &&
+ !D2Templated->isCompleteDefinition()) {
// FIXME: Import definition!
}
@@ -3704,7 +3800,7 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
SourceLocation IdLoc = Importer.Import(D->getLocation());
// Import template arguments.
- llvm::SmallVector<TemplateArgument, 2> TemplateArgs;
+ SmallVector<TemplateArgument, 2> TemplateArgs;
if (ImportTemplateArguments(D->getTemplateArgs().data(),
D->getTemplateArgs().size(),
TemplateArgs))
@@ -3722,7 +3818,7 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
// FIXME: Check for specialization vs. instantiation errors.
if (RecordDecl *FoundDef = D2->getDefinition()) {
- if (!D->isDefinition() || IsStructuralMatch(D, FoundDef)) {
+ if (!D->isCompleteDefinition() || IsStructuralMatch(D, FoundDef)) {
// The record types structurally match, or the "from" translation
// unit only had a forward declaration anyway; call it the same
// function.
@@ -3752,7 +3848,7 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
}
Importer.Imported(D, D2);
- if (D->isDefinition() && ImportDefinition(D, D2))
+ if (D->isCompleteDefinition() && ImportDefinition(D, D2))
return 0;
return D2;
@@ -3792,14 +3888,17 @@ Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
QualType T = Importer.Import(E->getType());
if (T.isNull())
return 0;
-
- return DeclRefExpr::Create(Importer.getToContext(),
- Importer.Import(E->getQualifierLoc()),
- ToD,
- Importer.Import(E->getLocation()),
- T, E->getValueKind(),
- FoundD,
- /*FIXME:TemplateArgs=*/0);
+
+ DeclRefExpr *DRE = DeclRefExpr::Create(Importer.getToContext(),
+ Importer.Import(E->getQualifierLoc()),
+ ToD,
+ Importer.Import(E->getLocation()),
+ T, E->getValueKind(),
+ FoundD,
+ /*FIXME:TemplateArgs=*/0);
+ if (E->hadMultipleCandidates())
+ DRE->setHadMultipleCandidates(true);
+ return DRE;
}
Expr *ASTNodeImporter::VisitIntegerLiteral(IntegerLiteral *E) {
@@ -3817,8 +3916,8 @@ Expr *ASTNodeImporter::VisitCharacterLiteral(CharacterLiteral *E) {
if (T.isNull())
return 0;
- return new (Importer.getToContext()) CharacterLiteral(E->getValue(),
- E->isWide(), T,
+ return new (Importer.getToContext()) CharacterLiteral(E->getValue(),
+ E->getKind(), T,
Importer.Import(E->getLocation()));
}
@@ -4024,13 +4123,17 @@ Decl *ASTImporter::Import(Decl *FromD) {
if (!FromD)
return 0;
+ ASTNodeImporter Importer(*this);
+
// Check whether we've already imported this declaration.
llvm::DenseMap<Decl *, Decl *>::iterator Pos = ImportedDecls.find(FromD);
- if (Pos != ImportedDecls.end())
- return Pos->second;
+ if (Pos != ImportedDecls.end()) {
+ Decl *ToD = Pos->second;
+ Importer.ImportDefinitionIfNeeded(FromD, ToD);
+ return ToD;
+ }
// Import the type
- ASTNodeImporter Importer(*this);
Decl *ToD = Importer.Visit(FromD);
if (!ToD)
return 0;
@@ -4045,7 +4148,7 @@ Decl *ASTImporter::Import(Decl *FromD) {
} else if (TypedefNameDecl *FromTypedef = dyn_cast<TypedefNameDecl>(FromD)) {
// When we've finished transforming a typedef, see whether it was the
// typedef for an anonymous tag.
- for (llvm::SmallVector<TagDecl *, 4>::iterator
+ for (SmallVector<TagDecl *, 4>::iterator
FromTag = AnonTagsWithPendingTypedefs.begin(),
FromTagEnd = AnonTagsWithPendingTypedefs.end();
FromTag != FromTagEnd; ++FromTag) {
@@ -4252,7 +4355,7 @@ SourceLocation ASTImporter::Import(SourceLocation FromLoc) {
std::pair<FileID, unsigned> Decomposed = FromSM.getDecomposedLoc(FromLoc);
SourceManager &ToSM = ToContext.getSourceManager();
return ToSM.getLocForStartOfFile(Import(Decomposed.first))
- .getFileLocWithOffset(Decomposed.second);
+ .getLocWithOffset(Decomposed.second);
}
SourceRange ASTImporter::Import(SourceRange FromRange) {
@@ -4306,6 +4409,23 @@ void ASTImporter::ImportDefinition(Decl *From) {
if (DeclContext *FromDC = cast<DeclContext>(From)) {
ASTNodeImporter Importer(*this);
+
+ if (RecordDecl *ToRecord = dyn_cast<RecordDecl>(To)) {
+ if (!ToRecord->getDefinition()) {
+ Importer.ImportDefinition(cast<RecordDecl>(FromDC), ToRecord,
+ /*ForceImport=*/true);
+ return;
+ }
+ }
+
+ if (EnumDecl *ToEnum = dyn_cast<EnumDecl>(To)) {
+ if (!ToEnum->getDefinition()) {
+ Importer.ImportDefinition(cast<EnumDecl>(FromDC), ToEnum,
+ /*ForceImport=*/true);
+ return;
+ }
+ }
+
Importer.ImportDeclContext(FromDC, true);
}
}
@@ -4378,7 +4498,7 @@ Selector ASTImporter::Import(Selector FromSel) {
if (FromSel.isNull())
return Selector();
- llvm::SmallVector<IdentifierInfo *, 4> Idents;
+ SmallVector<IdentifierInfo *, 4> Idents;
Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(0)));
for (unsigned I = 1, N = FromSel.getNumArgs(); I < N; ++I)
Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(I)));
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 63583a02bfd1..1f0100a580a3 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -1,6 +1,6 @@
set(LLVM_LINK_COMPONENTS support)
-set(LLVM_USED_LIBS clangBasic)
+set(LLVM_USED_LIBS clangBasic clangLex)
add_clang_library(clangAST
APValue.cpp
@@ -35,6 +35,7 @@ add_clang_library(clangAST
ParentMap.cpp
RecordLayout.cpp
RecordLayoutBuilder.cpp
+ SelectorLocationsKind.cpp
Stmt.cpp
StmtDumper.cpp
StmtIterator.cpp
@@ -46,6 +47,8 @@ add_clang_library(clangAST
Type.cpp
TypeLoc.cpp
TypePrinter.cpp
+ VTableBuilder.cpp
+ VTTBuilder.cpp
)
add_dependencies(clangAST ClangARMNeon ClangAttrClasses ClangAttrList
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index 9ffe1f865689..f29bfd13192d 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -119,7 +119,7 @@ bool CXXRecordDecl::isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const {
bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
void *OpaqueData,
bool AllowShortCircuit) const {
- llvm::SmallVector<const CXXRecordDecl*, 8> Queue;
+ SmallVector<const CXXRecordDecl*, 8> Queue;
const CXXRecordDecl *Record = this;
bool AllMatches = true;
@@ -425,7 +425,7 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
void OverridingMethods::add(unsigned OverriddenSubobject,
UniqueVirtualMethod Overriding) {
- llvm::SmallVector<UniqueVirtualMethod, 4> &SubobjectOverrides
+ SmallVector<UniqueVirtualMethod, 4> &SubobjectOverrides
= Overrides[OverriddenSubobject];
if (std::find(SubobjectOverrides.begin(), SubobjectOverrides.end(),
Overriding) == SubobjectOverrides.end())
@@ -556,7 +556,7 @@ void FinalOverriderCollector::Collect(const CXXRecordDecl *RD,
// overrides.
typedef std::pair<CXXMethodDecl::method_iterator,
CXXMethodDecl::method_iterator> OverriddenMethods;
- llvm::SmallVector<OverriddenMethods, 4> Stack;
+ SmallVector<OverriddenMethods, 4> Stack;
Stack.push_back(std::make_pair(CanonM->begin_overridden_methods(),
CanonM->end_overridden_methods()));
while (!Stack.empty()) {
@@ -623,11 +623,11 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const {
SOEnd = OM->second.end();
SO != SOEnd;
++SO) {
- llvm::SmallVector<UniqueVirtualMethod, 4> &Overriding = SO->second;
+ SmallVector<UniqueVirtualMethod, 4> &Overriding = SO->second;
if (Overriding.size() < 2)
continue;
- for (llvm::SmallVector<UniqueVirtualMethod, 4>::iterator
+ for (SmallVector<UniqueVirtualMethod, 4>::iterator
Pos = Overriding.begin(), PosEnd = Overriding.end();
Pos != PosEnd;
/* increment in loop */) {
@@ -642,7 +642,7 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const {
// in a base class subobject that hides the virtual base class
// subobject.
bool Hidden = false;
- for (llvm::SmallVector<UniqueVirtualMethod, 4>::iterator
+ for (SmallVector<UniqueVirtualMethod, 4>::iterator
OP = Overriding.begin(), OPEnd = Overriding.end();
OP != OPEnd && !Hidden;
++OP) {
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 4c323da7eee3..95d52cb0fa1b 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -28,6 +28,8 @@
#include "clang/Basic/TargetInfo.h"
#include "llvm/Support/ErrorHandling.h"
+#include <algorithm>
+
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -51,7 +53,7 @@ static llvm::Optional<Visibility> getVisibilityOf(const Decl *D) {
// If we're on Mac OS X, an 'availability' for Mac OS X attribute
// implies visibility(default).
- if (D->getASTContext().Target.getTriple().isOSDarwin()) {
+ if (D->getASTContext().getTargetInfo().getTriple().isOSDarwin()) {
for (specific_attr_iterator<AvailabilityAttr>
A = D->specific_attr_begin<AvailabilityAttr>(),
AEnd = D->specific_attr_end<AvailabilityAttr>();
@@ -818,7 +820,7 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
if (Ctx->isFunctionOrMethod())
return getNameAsString();
- typedef llvm::SmallVector<const DeclContext *, 8> ContextsTy;
+ typedef SmallVector<const DeclContext *, 8> ContextsTy;
ContextsTy Contexts;
// Collect contexts.
@@ -845,18 +847,18 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
if (ND->isAnonymousNamespace())
OS << "<anonymous namespace>";
else
- OS << ND;
+ OS << *ND;
} else if (const RecordDecl *RD = dyn_cast<RecordDecl>(*I)) {
if (!RD->getIdentifier())
OS << "<anonymous " << RD->getKindName() << '>';
else
- OS << RD;
+ OS << *RD;
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
const FunctionProtoType *FT = 0;
if (FD->hasWrittenPrototype())
FT = dyn_cast<FunctionProtoType>(FD->getType()->getAs<FunctionType>());
- OS << FD << '(';
+ OS << *FD << '(';
if (FT) {
unsigned NumParams = FD->getNumParams();
for (unsigned i = 0; i < NumParams; ++i) {
@@ -875,13 +877,13 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
}
OS << ')';
} else {
- OS << cast<NamedDecl>(*I);
+ OS << *cast<NamedDecl>(*I);
}
OS << "::";
}
if (getDeclName())
- OS << this;
+ OS << *this;
else
OS << "<anonymous>";
@@ -1003,8 +1005,7 @@ void DeclaratorDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
}
// Set qualifier info.
getExtInfo()->QualifierLoc = QualifierLoc;
- }
- else {
+ } else {
// Here Qualifier == 0, i.e., we are removing the qualifier (if any).
if (hasExtInfo()) {
if (getExtInfo()->NumTemplParamLists == 0) {
@@ -1120,15 +1121,16 @@ QualifierInfo::setTemplateParameterListsInfo(ASTContext &Context,
const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
switch (SC) {
- case SC_None: break;
- case SC_Auto: return "auto"; break;
- case SC_Extern: return "extern"; break;
- case SC_PrivateExtern: return "__private_extern__"; break;
- case SC_Register: return "register"; break;
- case SC_Static: return "static"; break;
+ case SC_None: break;
+ case SC_Auto: return "auto";
+ case SC_Extern: return "extern";
+ case SC_OpenCLWorkGroupLocal: return "<<work-group-local>>";
+ case SC_PrivateExtern: return "__private_extern__";
+ case SC_Register: return "register";
+ case SC_Static: return "static";
}
- assert(0 && "Invalid storage class");
+ llvm_unreachable("Invalid storage class");
return 0;
}
@@ -1388,6 +1390,16 @@ ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
S, SCAsWritten, DefArg);
}
+SourceRange ParmVarDecl::getSourceRange() const {
+ if (!hasInheritedDefaultArg()) {
+ SourceRange ArgRange = getDefaultArgRange();
+ if (ArgRange.isValid())
+ return SourceRange(getOuterLocStart(), ArgRange.getEnd());
+ }
+
+ return DeclaratorDecl::getSourceRange();
+}
+
Expr *ParmVarDecl::getDefaultArg() {
assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!");
assert(!hasUninstantiatedDefaultArg() &&
@@ -1429,6 +1441,15 @@ bool ParmVarDecl::isParameterPack() const {
return isa<PackExpansionType>(getType());
}
+void ParmVarDecl::setParameterIndexLarge(unsigned parameterIndex) {
+ getASTContext().setParameterIndex(this, parameterIndex);
+ ParmVarDeclBits.ParameterIndex = ParameterIndexSentinel;
+}
+
+unsigned ParmVarDecl::getParameterIndexLarge() const {
+ return getASTContext().getParameterIndex(this);
+}
+
//===----------------------------------------------------------------------===//
// FunctionDecl Implementation
//===----------------------------------------------------------------------===//
@@ -1678,20 +1699,14 @@ unsigned FunctionDecl::getNumParams() const {
}
void FunctionDecl::setParams(ASTContext &C,
- ParmVarDecl **NewParamInfo, unsigned NumParams) {
+ llvm::ArrayRef<ParmVarDecl *> NewParamInfo) {
assert(ParamInfo == 0 && "Already has param info!");
- assert(NumParams == getNumParams() && "Parameter count mismatch!");
+ assert(NewParamInfo.size() == getNumParams() && "Parameter count mismatch!");
// Zero params -> null pointer.
- if (NumParams) {
- void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams);
- ParamInfo = new (Mem) ParmVarDecl*[NumParams];
- memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams);
-
- // Update source range. The check below allows us to set EndRangeLoc before
- // setting the parameters.
- if (EndRangeLoc.isInvalid() || EndRangeLoc == getLocation())
- EndRangeLoc = NewParamInfo[NumParams-1]->getLocEnd();
+ if (!NewParamInfo.empty()) {
+ ParamInfo = new (C) ParmVarDecl*[NewParamInfo.size()];
+ std::copy(NewParamInfo.begin(), NewParamInfo.end(), ParamInfo);
}
}
@@ -1762,6 +1777,33 @@ bool FunctionDecl::isInlined() const {
return false;
}
+/// \brief For a function declaration in C or C++, determine whether this
+/// declaration causes the definition to be externally visible.
+///
+/// Determines whether this is the first non-inline redeclaration of an inline
+/// function in a language where "inline" does not normally require an
+/// externally visible definition.
+bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
+ assert(!doesThisDeclarationHaveABody() &&
+ "Must have a declaration without a body.");
+
+ ASTContext &Context = getASTContext();
+
+ // In C99 mode, a function may have an inline definition (causing it to
+ // be deferred) then redeclared later. As a special case, "extern inline"
+ // is not required to produce an external symbol.
+ if (Context.getLangOptions().GNUInline || !Context.getLangOptions().C99 ||
+ Context.getLangOptions().CPlusPlus)
+ return false;
+ if (getLinkage() != ExternalLinkage || isInlineSpecified())
+ return false;
+ const FunctionDecl *Definition = 0;
+ if (hasBody(Definition))
+ return Definition->isInlined() &&
+ Definition->isInlineDefinitionExternallyVisible();
+ return false;
+}
+
/// \brief For an inline function definition in C or C++, determine whether the
/// definition will be externally visible.
///
@@ -1814,7 +1856,12 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
// Only consider file-scope declarations in this test.
if (!Redecl->getLexicalDeclContext()->isTranslationUnit())
continue;
-
+
+ // Only consider explicit declarations; the presence of a builtin for a
+ // libcall shouldn't affect whether a definition is externally visible.
+ if (Redecl->isImplicit())
+ continue;
+
if (!Redecl->isInlineSpecified() || Redecl->getStorageClass() == SC_Extern)
return true; // Not an inline definition
}
@@ -1857,8 +1904,7 @@ FunctionDecl::TemplatedKind FunctionDecl::getTemplatedKind() const {
<DependentFunctionTemplateSpecializationInfo*>())
return TK_DependentFunctionTemplateSpecialization;
- assert(false && "Did we miss a TemplateOrSpecialization type?");
- return TK_NonTemplate;
+ llvm_unreachable("Did we miss a TemplateOrSpecialization type?");
}
FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const {
@@ -1890,13 +1936,17 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
switch (getTemplateSpecializationKind()) {
case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
case TSK_ExplicitInstantiationDefinition:
return false;
case TSK_ImplicitInstantiation:
return true;
+ // It is possible to instantiate TSK_ExplicitSpecialization kind
+ // if the FunctionDecl has a class scope specialization pattern.
+ case TSK_ExplicitSpecialization:
+ return getClassScopeSpecializationPattern() != 0;
+
case TSK_ExplicitInstantiationDeclaration:
// Handled below.
break;
@@ -1919,6 +1969,10 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
}
FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
+ // Handle class scope explicit specialization special case.
+ if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ return getClassScopeSpecializationPattern();
+
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
while (Primary->getInstantiatedFromMemberTemplate()) {
// If we have hit a point where the user provided a specialization of
@@ -1944,6 +1998,10 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
return 0;
}
+FunctionDecl *FunctionDecl::getClassScopeSpecializationPattern() const {
+ return getASTContext().getClassScopeSpecializationPattern(this);
+}
+
const TemplateArgumentList *
FunctionDecl::getTemplateSpecializationArgs() const {
if (FunctionTemplateSpecializationInfo *Info
@@ -1954,7 +2012,7 @@ FunctionDecl::getTemplateSpecializationArgs() const {
return 0;
}
-const TemplateArgumentListInfo *
+const ASTTemplateArgumentListInfo *
FunctionDecl::getTemplateSpecializationArgsAsWritten() const {
if (FunctionTemplateSpecializationInfo *Info
= TemplateOrSpecialization
@@ -2069,7 +2127,7 @@ FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
MSInfo->getPointOfInstantiation().isInvalid())
MSInfo->setPointOfInstantiation(PointOfInstantiation);
} else
- assert(false && "Function cannot have a template specialization kind");
+ llvm_unreachable("Function cannot have a template specialization kind");
}
SourceLocation FunctionDecl::getPointOfInstantiation() const {
@@ -2134,6 +2192,12 @@ bool FieldDecl::isAnonymousStructOrUnion() const {
return false;
}
+unsigned FieldDecl::getBitWidthValue(const ASTContext &Ctx) const {
+ assert(isBitField() && "not a bitfield");
+ Expr *BitWidth = InitializerOrBitWidth.getPointer();
+ return BitWidth->EvaluateKnownConstInt(Ctx).getZExtValue();
+}
+
unsigned FieldDecl::getFieldIndex() const {
if (CachedFieldIndex) return CachedFieldIndex - 1;
@@ -2165,8 +2229,8 @@ unsigned FieldDecl::getFieldIndex() const {
}
SourceRange FieldDecl::getSourceRange() const {
- if (isBitField())
- return SourceRange(getInnerLocStart(), getBitWidth()->getLocEnd());
+ if (const Expr *E = InitializerOrBitWidth.getPointer())
+ return SourceRange(getInnerLocStart(), E->getLocEnd());
return DeclaratorDecl::getSourceRange();
}
@@ -2218,22 +2282,22 @@ void TagDecl::completeDefinition() {
cast<CXXRecordDecl>(this)->hasDefinition()) &&
"definition completed but not started");
- IsDefinition = true;
+ IsCompleteDefinition = true;
IsBeingDefined = false;
if (ASTMutationListener *L = getASTMutationListener())
L->CompletedTagDefinition(this);
}
-TagDecl* TagDecl::getDefinition() const {
- if (isDefinition())
+TagDecl *TagDecl::getDefinition() const {
+ if (isCompleteDefinition())
return const_cast<TagDecl *>(this);
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(this))
return CXXRD->getDefinition();
for (redecl_iterator R = redecls_begin(), REnd = redecls_end();
R != REnd; ++R)
- if (R->isDefinition())
+ if (R->isCompleteDefinition())
return *R;
return 0;
@@ -2246,8 +2310,7 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo;
// Set qualifier info.
getExtInfo()->QualifierLoc = QualifierLoc;
- }
- else {
+ } else {
// Here Qualifier == 0, i.e., we are removing the qualifier (if any).
if (hasExtInfo()) {
if (getExtInfo()->NumTemplParamLists == 0) {
@@ -2296,7 +2359,7 @@ void EnumDecl::completeDefinition(QualType NewType,
QualType NewPromotionType,
unsigned NumPositiveBits,
unsigned NumNegativeBits) {
- assert(!isDefinition() && "Cannot redefine enums!");
+ assert(!isCompleteDefinition() && "Cannot redefine enums!");
if (!IntegerType)
IntegerType = NewType.getTypePtr();
PromotionType = NewPromotionType;
@@ -2349,7 +2412,7 @@ RecordDecl::field_iterator RecordDecl::field_begin() const {
/// completeDefinition - Notes that the definition of this type is now
/// complete.
void RecordDecl::completeDefinition() {
- assert(!isDefinition() && "Cannot redefine record!");
+ assert(!isCompleteDefinition() && "Cannot redefine record!");
TagDecl::completeDefinition();
}
@@ -2360,7 +2423,7 @@ void RecordDecl::LoadFieldsFromExternalStorage() const {
// Notify that we have a RecordDecl doing some initialization.
ExternalASTSource::Deserializing TheFields(Source);
- llvm::SmallVector<Decl*, 64> Decls;
+ SmallVector<Decl*, 64> Decls;
LoadedFieldsFromExternalStorage = true;
switch (Source->FindExternalLexicalDeclsBy<FieldDecl>(this, Decls)) {
case ELR_Success:
@@ -2380,23 +2443,22 @@ void RecordDecl::LoadFieldsFromExternalStorage() const {
if (Decls.empty())
return;
- llvm::tie(FirstDecl, LastDecl) = BuildDeclChain(Decls);
+ llvm::tie(FirstDecl, LastDecl) = BuildDeclChain(Decls,
+ /*FieldsAlreadyLoaded=*/false);
}
//===----------------------------------------------------------------------===//
// BlockDecl Implementation
//===----------------------------------------------------------------------===//
-void BlockDecl::setParams(ParmVarDecl **NewParamInfo,
- unsigned NParms) {
+void BlockDecl::setParams(llvm::ArrayRef<ParmVarDecl *> NewParamInfo) {
assert(ParamInfo == 0 && "Already has param info!");
// Zero params -> null pointer.
- if (NParms) {
- NumParams = NParms;
- void *Mem = getASTContext().Allocate(sizeof(ParmVarDecl*)*NumParams);
- ParamInfo = new (Mem) ParmVarDecl*[NumParams];
- memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams);
+ if (!NewParamInfo.empty()) {
+ NumParams = NewParamInfo.size();
+ ParamInfo = new (getASTContext()) ParmVarDecl*[NewParamInfo.size()];
+ std::copy(NewParamInfo.begin(), NewParamInfo.end(), ParamInfo);
}
}
@@ -2481,10 +2543,12 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
QualType T, TypeSourceInfo *TInfo,
StorageClass SC, StorageClass SCAsWritten,
bool isInlineSpecified,
- bool hasWrittenPrototype) {
+ bool hasWrittenPrototype,
+ bool isConstexprSpecified) {
FunctionDecl *New = new (C) FunctionDecl(Function, DC, StartLoc, NameInfo,
T, TInfo, SC, SCAsWritten,
- isInlineSpecified);
+ isInlineSpecified,
+ isConstexprSpecified);
New->HasWrittenPrototype = hasWrittenPrototype;
return New;
}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index b2806f092cbd..321e40b43899 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -43,7 +43,7 @@ static bool StatSwitch = false;
const char *Decl::getDeclKindName() const {
switch (DeclKind) {
- default: assert(0 && "Declaration not in DeclNodes.inc!");
+ default: llvm_unreachable("Declaration not in DeclNodes.inc!");
#define DECL(DERIVED, BASE) case DERIVED: return #DERIVED;
#define ABSTRACT_DECL(DECL)
#include "clang/AST/DeclNodes.inc"
@@ -62,7 +62,7 @@ void Decl::setInvalidDecl(bool Invalid) {
const char *DeclContext::getDeclKindName() const {
switch (DeclKind) {
- default: assert(0 && "Declaration context not in DeclNodes.inc!");
+ default: llvm_unreachable("Declaration context not in DeclNodes.inc!");
#define DECL(DERIVED, BASE) case Decl::DERIVED: return #DERIVED;
#define ABSTRACT_DECL(DECL)
#include "clang/AST/DeclNodes.inc"
@@ -100,7 +100,7 @@ void Decl::PrintStats() {
void Decl::add(Kind k) {
switch (k) {
- default: assert(0 && "Declaration not in DeclNodes.inc!");
+ default: llvm_unreachable("Declaration not in DeclNodes.inc!");
#define DECL(DERIVED, BASE) case DERIVED: ++n##DERIVED##s; break;
#define ABSTRACT_DECL(DECL)
#include "clang/AST/DeclNodes.inc"
@@ -133,14 +133,18 @@ bool Decl::isFunctionOrFunctionTemplate() const {
return isa<FunctionDecl>(this) || isa<FunctionTemplateDecl>(this);
}
-bool Decl::isDefinedOutsideFunctionOrMethod() const {
- for (const DeclContext *DC = getDeclContext();
- DC && !DC->isTranslationUnit();
+bool Decl::isTemplateDecl() const {
+ return isa<TemplateDecl>(this);
+}
+
+const DeclContext *Decl::getParentFunctionOrMethod() const {
+ for (const DeclContext *DC = getDeclContext();
+ DC && !DC->isTranslationUnit() && !DC->isNamespace();
DC = DC->getParent())
if (DC->isFunctionOrMethod())
- return false;
+ return DC;
- return true;
+ return 0;
}
@@ -148,7 +152,7 @@ bool Decl::isDefinedOutsideFunctionOrMethod() const {
// PrettyStackTraceDecl Implementation
//===----------------------------------------------------------------------===//
-void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const {
+void PrettyStackTraceDecl::print(raw_ostream &OS) const {
SourceLocation TheLoc = Loc;
if (TheLoc.isInvalid() && TheDecl)
TheLoc = TheDecl->getLocation();
@@ -265,13 +269,13 @@ bool Decl::isReferenced() const {
static AvailabilityResult CheckAvailability(ASTContext &Context,
const AvailabilityAttr *A,
std::string *Message) {
- llvm::StringRef TargetPlatform = Context.Target.getPlatformName();
- llvm::StringRef PrettyPlatformName
+ StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
+ StringRef PrettyPlatformName
= AvailabilityAttr::getPrettyPlatformName(TargetPlatform);
if (PrettyPlatformName.empty())
PrettyPlatformName = TargetPlatform;
- VersionTuple TargetMinVersion = Context.Target.getPlatformMinVersion();
+ VersionTuple TargetMinVersion = Context.getTargetInfo().getPlatformMinVersion();
if (TargetMinVersion.empty())
return AR_Available;
@@ -493,6 +497,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case UsingDirective:
case ClassTemplateSpecialization:
case ClassTemplatePartialSpecialization:
+ case ClassScopeFunctionSpecialization:
case ObjCImplementation:
case ObjCCategory:
case ObjCCategoryImpl:
@@ -566,8 +571,7 @@ Decl *Decl::castFromDeclContext (const DeclContext *D) {
if (DK >= first##NAME && DK <= last##NAME) \
return static_cast<NAME##Decl*>(const_cast<DeclContext*>(D));
#include "clang/AST/DeclNodes.inc"
- assert(false && "a decl that inherits DeclContext isn't handled");
- return 0;
+ llvm_unreachable("a decl that inherits DeclContext isn't handled");
}
}
@@ -586,8 +590,7 @@ DeclContext *Decl::castToDeclContext(const Decl *D) {
if (DK >= first##NAME && DK <= last##NAME) \
return static_cast<NAME##Decl*>(const_cast<Decl*>(D));
#include "clang/AST/DeclNodes.inc"
- assert(false && "a decl that inherits DeclContext isn't handled");
- return 0;
+ llvm_unreachable("a decl that inherits DeclContext isn't handled");
}
}
@@ -627,7 +630,8 @@ void Decl::CheckAccessDeclContext() const {
isa<ParmVarDecl>(this) ||
// FIXME: a ClassTemplateSpecialization or CXXRecordDecl can have
// AS_none as access specifier.
- isa<CXXRecordDecl>(this))
+ isa<CXXRecordDecl>(this) ||
+ isa<ClassScopeFunctionSpecializationDecl>(this))
return;
assert(Access != AS_none &&
@@ -812,11 +816,15 @@ DeclContext *DeclContext::getNextContext() {
}
std::pair<Decl *, Decl *>
-DeclContext::BuildDeclChain(const llvm::SmallVectorImpl<Decl*> &Decls) {
+DeclContext::BuildDeclChain(const SmallVectorImpl<Decl*> &Decls,
+ bool FieldsAlreadyLoaded) {
// Build up a chain of declarations via the Decl::NextDeclInContext field.
Decl *FirstNewDecl = 0;
Decl *PrevDecl = 0;
for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
+ if (FieldsAlreadyLoaded && isa<FieldDecl>(Decls[I]))
+ continue;
+
Decl *D = Decls[I];
if (PrevDecl)
PrevDecl->NextDeclInContext = D;
@@ -838,9 +846,9 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const {
// Notify that we have a DeclContext that is initializing.
ExternalASTSource::Deserializing ADeclContext(Source);
-
+
// Load the external declarations, if any.
- llvm::SmallVector<Decl*, 64> Decls;
+ SmallVector<Decl*, 64> Decls;
ExternalLexicalStorage = false;
switch (Source->FindExternalLexicalDecls(this, Decls)) {
case ELR_Success:
@@ -855,17 +863,16 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const {
return;
// We may have already loaded just the fields of this record, in which case
- // don't add the decls, just replace the FirstDecl/LastDecl chain.
+ // we need to ignore them.
+ bool FieldsAlreadyLoaded = false;
if (const RecordDecl *RD = dyn_cast<RecordDecl>(this))
- if (RD->LoadedFieldsFromExternalStorage) {
- llvm::tie(FirstDecl, LastDecl) = BuildDeclChain(Decls);
- return;
- }
-
+ FieldsAlreadyLoaded = RD->LoadedFieldsFromExternalStorage;
+
// Splice the newly-read declarations into the beginning of the list
// of declarations.
Decl *ExternalFirst, *ExternalLast;
- llvm::tie(ExternalFirst, ExternalLast) = BuildDeclChain(Decls);
+ llvm::tie(ExternalFirst, ExternalLast) = BuildDeclChain(Decls,
+ FieldsAlreadyLoaded);
ExternalLast->NextDeclInContext = FirstDecl;
FirstDecl = ExternalFirst;
if (!LastDecl)
@@ -890,7 +897,7 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC,
DeclContext::lookup_result
ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
DeclarationName Name,
- llvm::SmallVectorImpl<NamedDecl*> &Decls) {
+ ArrayRef<NamedDecl*> Decls) {
ASTContext &Context = DC->getParentASTContext();;
StoredDeclsMap *Map;
@@ -898,35 +905,17 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
Map = DC->CreateStoredDeclsMap(Context);
StoredDeclsList &List = (*Map)[Name];
- for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
+ for (ArrayRef<NamedDecl*>::iterator
+ I = Decls.begin(), E = Decls.end(); I != E; ++I) {
if (List.isNull())
- List.setOnlyValue(Decls[I]);
+ List.setOnlyValue(*I);
else
- List.AddSubsequentDecl(Decls[I]);
+ List.AddSubsequentDecl(*I);
}
return List.getLookupResult();
}
-void ExternalASTSource::MaterializeVisibleDeclsForName(const DeclContext *DC,
- DeclarationName Name,
- llvm::SmallVectorImpl<NamedDecl*> &Decls) {
- assert(DC->LookupPtr);
- StoredDeclsMap &Map = *DC->LookupPtr;
-
- // If there's an entry in the table the visible decls for this name have
- // already been deserialized.
- if (Map.find(Name) == Map.end()) {
- StoredDeclsList &List = Map[Name];
- for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
- if (List.isNull())
- List.setOnlyValue(Decls[I]);
- else
- List.AddSubsequentDecl(Decls[I]);
- }
- }
-}
-
DeclContext::decl_iterator DeclContext::noload_decls_begin() const {
return decl_iterator(FirstDecl);
}
@@ -939,8 +928,6 @@ DeclContext::decl_iterator DeclContext::decls_begin() const {
if (hasExternalLexicalStorage())
LoadLexicalDeclsFromExternalStorage();
- // FIXME: Check whether we need to load some declarations from
- // external storage.
return decl_iterator(FirstDecl);
}
@@ -988,6 +975,9 @@ void DeclContext::removeDecl(Decl *D) {
if (isa<NamedDecl>(D)) {
NamedDecl *ND = cast<NamedDecl>(D);
+ // Remove only decls that have a name
+ if (!ND->getDeclName()) return;
+
StoredDeclsMap *Map = getPrimaryContext()->LookupPtr;
if (!Map) return;
@@ -1038,12 +1028,10 @@ void DeclContext::buildLookup(DeclContext *DCtx) {
if (D->getDeclContext() == DCtx)
makeDeclVisibleInContextImpl(ND);
- // Insert any forward-declared Objective-C interfaces into the lookup
+ // Insert any forward-declared Objective-C interface into the lookup
// data structure.
if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(*D))
- for (ObjCClassDecl::iterator I = Class->begin(), IEnd = Class->end();
- I != IEnd; ++I)
- makeDeclVisibleInContextImpl(I->getInterface());
+ makeDeclVisibleInContextImpl(Class->getForwardInterfaceDecl());
// If this declaration is itself a transparent declaration context or
// inline namespace, add its members (recursively).
@@ -1093,6 +1081,38 @@ DeclContext::lookup(DeclarationName Name) const {
return const_cast<DeclContext*>(this)->lookup(Name);
}
+void DeclContext::localUncachedLookup(DeclarationName Name,
+ llvm::SmallVectorImpl<NamedDecl *> &Results) {
+ Results.clear();
+
+ // If there's no external storage, just perform a normal lookup and copy
+ // the results.
+ if (!hasExternalVisibleStorage() && !hasExternalLexicalStorage()) {
+ lookup_result LookupResults = lookup(Name);
+ Results.insert(Results.end(), LookupResults.first, LookupResults.second);
+ return;
+ }
+
+ // If we have a lookup table, check there first. Maybe we'll get lucky.
+ if (LookupPtr) {
+ StoredDeclsMap::iterator Pos = LookupPtr->find(Name);
+ if (Pos != LookupPtr->end()) {
+ Results.insert(Results.end(),
+ Pos->second.getLookupResult().first,
+ Pos->second.getLookupResult().second);
+ return;
+ }
+ }
+
+ // Slow case: grovel through the declarations in our chain looking for
+ // matches.
+ for (Decl *D = FirstDecl; D; D = D->getNextDeclInContext()) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ if (ND->getDeclName() == Name)
+ Results.push_back(ND);
+ }
+}
+
DeclContext *DeclContext::getRedeclContext() {
DeclContext *Ctx = this;
// Skip through transparent contexts.
@@ -1205,15 +1225,6 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
DeclNameEntries.AddSubsequentDecl(D);
}
-void DeclContext::MaterializeVisibleDeclsFromExternalStorage() {
- ExternalASTSource *Source = getParentASTContext().getExternalSource();
- assert(hasExternalVisibleStorage() && Source && "No external storage?");
-
- if (!LookupPtr)
- CreateStoredDeclsMap(getParentASTContext());
- Source->MaterializeVisibleDecls(this);
-}
-
/// Returns iterator range [First, Last) of UsingDirectiveDecls stored within
/// this context.
DeclContext::udir_iterator_range
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 4b59bf37d74b..f3da67c4ff81 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -35,15 +35,16 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
HasMutableFields(false), HasTrivialDefaultConstructor(true),
- HasConstExprNonCopyMoveConstructor(false), HasTrivialCopyConstructor(true),
+ HasConstexprNonCopyMoveConstructor(false), HasTrivialCopyConstructor(true),
HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true),
HasTrivialMoveAssignment(true), HasTrivialDestructor(true),
HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
UserProvidedDefaultConstructor(false), DeclaredDefaultConstructor(false),
DeclaredCopyConstructor(false), DeclaredMoveConstructor(false),
DeclaredCopyAssignment(false), DeclaredMoveAssignment(false),
- DeclaredDestructor(false), NumBases(0), NumVBases(0), Bases(), VBases(),
- Definition(D), FirstFriend(0) {
+ DeclaredDestructor(false), FailedImplicitMoveConstructor(false),
+ FailedImplicitMoveAssignment(false), NumBases(0), NumVBases(0), Bases(),
+ VBases(), Definition(D), FirstFriend(0) {
}
CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
@@ -89,7 +90,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
llvm::SmallPtrSet<CanQualType, 8> SeenVBaseTypes;
// The virtual bases of this class.
- llvm::SmallVector<const CXXBaseSpecifier *, 8> VBases;
+ SmallVector<const CXXBaseSpecifier *, 8> VBases;
data().Bases = new(C) CXXBaseSpecifier [NumBases];
data().NumBases = NumBases;
@@ -287,7 +288,7 @@ bool CXXRecordDecl::isTriviallyCopyable() const {
/// (if there is one).
static CXXMethodDecl *
GetBestOverloadCandidateSimple(
- const llvm::SmallVectorImpl<std::pair<CXXMethodDecl *, Qualifiers> > &Cands) {
+ const SmallVectorImpl<std::pair<CXXMethodDecl *, Qualifiers> > &Cands) {
if (Cands.empty())
return 0;
if (Cands.size() == 1)
@@ -313,7 +314,7 @@ CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(unsigned TypeQuals) const{
= Context.DeclarationNames.getCXXConstructorName(
Context.getCanonicalType(ClassType));
unsigned FoundTQs;
- llvm::SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found;
+ SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found;
DeclContext::lookup_const_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd) = this->lookup(ConstructorName);
Con != ConEnd; ++Con) {
@@ -349,7 +350,7 @@ CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const {
QualType Class = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this));
DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
- llvm::SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found;
+ 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:
@@ -502,18 +503,18 @@ NotASpecialMember:;
// Note that we have a user-declared constructor.
data().UserDeclaredConstructor = true;
- // FIXME: Under C++0x, /only/ special member functions may be user-provided.
- // This is probably a defect.
- bool UserProvided = false;
+ // Technically, "user-provided" is only defined for special member
+ // functions, but the intent of the standard is clearly that it should apply
+ // to all functions.
+ bool UserProvided = Constructor->isUserProvided();
// C++0x [class.ctor]p5:
// A default constructor is trivial if it is not user-provided [...]
if (Constructor->isDefaultConstructor()) {
data().DeclaredDefaultConstructor = true;
- if (Constructor->isUserProvided()) {
+ if (UserProvided) {
data().HasTrivialDefaultConstructor = false;
data().UserProvidedDefaultConstructor = true;
- UserProvided = true;
}
}
@@ -527,10 +528,8 @@ NotASpecialMember:;
// C++0x [class.copy]p13:
// A copy/move constructor for class X is trivial if it is not
// user-provided [...]
- if (Constructor->isUserProvided()) {
+ if (UserProvided)
data().HasTrivialCopyConstructor = false;
- UserProvided = true;
- }
} else if (Constructor->isMoveConstructor()) {
data().UserDeclaredMoveConstructor = true;
data().DeclaredMoveConstructor = true;
@@ -538,17 +537,14 @@ NotASpecialMember:;
// C++0x [class.copy]p13:
// A copy/move constructor for class X is trivial if it is not
// user-provided [...]
- if (Constructor->isUserProvided()) {
+ if (UserProvided)
data().HasTrivialMoveConstructor = false;
- UserProvided = true;
- }
}
}
- if (Constructor->isConstExpr() &&
- !Constructor->isCopyOrMoveConstructor()) {
- // Record if we see any constexpr constructors which are niether copy
+ if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor()) {
+ // Record if we see any constexpr constructors which are neither copy
// nor move constructors.
- data().HasConstExprNonCopyMoveConstructor = true;
+ data().HasConstexprNonCopyMoveConstructor = true;
}
// C++ [dcl.init.aggr]p1:
@@ -657,6 +653,13 @@ NotASpecialMember:;
// Handle non-static data members.
if (FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
+ // C++ [class.bit]p2:
+ // A declaration for a bit-field that omits the identifier declares an
+ // unnamed bit-field. Unnamed bit-fields are not members and cannot be
+ // initialized.
+ if (Field->isUnnamedBitfield())
+ return;
+
// C++ [dcl.init.aggr]p1:
// An aggregate is an array or a class (clause 9) with [...] no
// private or protected non-static data members (clause 11).
@@ -675,7 +678,7 @@ NotASpecialMember:;
case AS_private: data().HasPrivateFields = true; break;
case AS_protected: data().HasProtectedFields = true; break;
case AS_public: data().HasPublicFields = true; break;
- case AS_none: assert(0 && "Invalid access specifier");
+ case AS_none: llvm_unreachable("Invalid access specifier");
};
if ((data().HasPrivateFields + data().HasProtectedFields +
data().HasPublicFields) > 1)
@@ -716,7 +719,11 @@ NotASpecialMember:;
}
// Record if this field is the first non-literal field or base.
- if (!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType())
+ // As a slight variation on the standard, we regard mutable members as being
+ // non-literal, since mutating a constexpr variable would break C++11
+ // constant expression semantics.
+ if ((!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType()) ||
+ Field->isMutable())
data().HasNonLiteralTypeFieldsOrBases = true;
if (Field->hasInClassInitializer()) {
@@ -827,15 +834,11 @@ NotASpecialMember:;
// If this is not a zero-length bit-field, then the class is not empty.
if (data().Empty) {
- if (!Field->getBitWidth())
+ if (!Field->isBitField() ||
+ (!Field->getBitWidth()->isTypeDependent() &&
+ !Field->getBitWidth()->isValueDependent() &&
+ Field->getBitWidthValue(Context) != 0))
data().Empty = false;
- else if (!Field->getBitWidth()->isTypeDependent() &&
- !Field->getBitWidth()->isValueDependent()) {
- llvm::APSInt Bits;
- if (Field->getBitWidth()->isIntegerConstantExpr(Bits, Context))
- if (!!Bits)
- data().Empty = false;
- }
}
}
@@ -1057,7 +1060,7 @@ CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
return;
}
- assert(false && "Not a class template or member class specialization");
+ llvm_unreachable("Not a class template or member class specialization");
}
CXXDestructorDecl *CXXRecordDecl::getDestructor() const {
@@ -1160,9 +1163,10 @@ CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
bool isStatic, StorageClass SCAsWritten, bool isInline,
- SourceLocation EndLocation) {
+ bool isConstexpr, SourceLocation EndLocation) {
return new (C) CXXMethodDecl(CXXMethod, RD, StartLoc, NameInfo, T, TInfo,
- isStatic, SCAsWritten, isInline, EndLocation);
+ isStatic, SCAsWritten, isInline, isConstexpr,
+ EndLocation);
}
bool CXXMethodDecl::isUsualDeallocationFunction() const {
@@ -1402,7 +1406,7 @@ SourceRange CXXCtorInitializer::getSourceRange() const {
CXXConstructorDecl *
CXXConstructorDecl::Create(ASTContext &C, EmptyShell Empty) {
return new (C) CXXConstructorDecl(0, SourceLocation(), DeclarationNameInfo(),
- QualType(), 0, false, false, false);
+ QualType(), 0, false, false, false, false);
}
CXXConstructorDecl *
@@ -1410,14 +1414,14 @@ CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- bool isExplicit,
- bool isInline,
- bool isImplicitlyDeclared) {
+ bool isExplicit, bool isInline,
+ bool isImplicitlyDeclared, bool isConstexpr) {
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXConstructorName &&
"Name must refer to a constructor");
return new (C) CXXConstructorDecl(RD, StartLoc, NameInfo, T, TInfo,
- isExplicit, isInline, isImplicitlyDeclared);
+ isExplicit, isInline, isImplicitlyDeclared,
+ isConstexpr);
}
bool CXXConstructorDecl::isDefaultConstructor() const {
@@ -1545,8 +1549,7 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- bool isInline,
- bool isImplicitlyDeclared) {
+ bool isInline, bool isImplicitlyDeclared) {
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXDestructorName &&
"Name must refer to a destructor");
@@ -1557,7 +1560,7 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
CXXConversionDecl *
CXXConversionDecl::Create(ASTContext &C, EmptyShell Empty) {
return new (C) CXXConversionDecl(0, SourceLocation(), DeclarationNameInfo(),
- QualType(), 0, false, false,
+ QualType(), 0, false, false, false,
SourceLocation());
}
@@ -1567,12 +1570,13 @@ CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
bool isInline, bool isExplicit,
- SourceLocation EndLocation) {
+ bool isConstexpr, SourceLocation EndLocation) {
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXConversionFunctionName &&
"Name must refer to a conversion function");
return new (C) CXXConversionDecl(RD, StartLoc, NameInfo, T, TInfo,
- isInline, isExplicit, EndLocation);
+ isInline, isExplicit, isConstexpr,
+ EndLocation);
}
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
@@ -1696,8 +1700,7 @@ static const char *getAccessName(AccessSpecifier AS) {
switch (AS) {
default:
case AS_none:
- assert("Invalid access specifier!");
- return 0;
+ llvm_unreachable("Invalid access specifier!");
case AS_public:
return "public";
case AS_private:
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 557b681d2fa6..a589b7f9d3e9 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Stmt.h"
+#include "clang/AST/ASTMutationListener.h"
#include "llvm/ADT/STLExtras.h"
using namespace clang;
@@ -185,7 +186,7 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
// Check for duplicate protocol in class's protocol list.
// This is O(n*m). But it is extremely rare and number of protocols in
// class or its extension are very few.
- llvm::SmallVector<ObjCProtocolDecl*, 8> ProtocolRefs;
+ SmallVector<ObjCProtocolDecl*, 8> ProtocolRefs;
for (unsigned i = 0; i < ExtNum; i++) {
bool protocolExists = false;
ObjCProtocolDecl *ProtoInExtension = ExtList[i];
@@ -337,17 +338,60 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C,
bool isInstance,
bool isVariadic,
bool isSynthesized,
+ bool isImplicitlyDeclared,
bool isDefined,
ImplementationControl impControl,
- bool HasRelatedResultType,
- unsigned numSelectorArgs) {
+ bool HasRelatedResultType) {
return new (C) ObjCMethodDecl(beginLoc, endLoc,
SelInfo, T, ResultTInfo, contextDecl,
isInstance,
- isVariadic, isSynthesized, isDefined,
+ isVariadic, isSynthesized, isImplicitlyDeclared,
+ isDefined,
impControl,
- HasRelatedResultType,
- numSelectorArgs);
+ HasRelatedResultType);
+}
+
+void ObjCMethodDecl::setAsRedeclaration(const ObjCMethodDecl *PrevMethod) {
+ assert(PrevMethod);
+ getASTContext().setObjCMethodRedeclaration(PrevMethod, this);
+ IsRedeclaration = true;
+ PrevMethod->HasRedeclaration = true;
+}
+
+void ObjCMethodDecl::setParamsAndSelLocs(ASTContext &C,
+ ArrayRef<ParmVarDecl*> Params,
+ ArrayRef<SourceLocation> SelLocs) {
+ ParamsAndSelLocs = 0;
+ NumParams = Params.size();
+ if (Params.empty() && SelLocs.empty())
+ return;
+
+ unsigned Size = sizeof(ParmVarDecl *) * NumParams +
+ sizeof(SourceLocation) * SelLocs.size();
+ ParamsAndSelLocs = C.Allocate(Size);
+ std::copy(Params.begin(), Params.end(), getParams());
+ std::copy(SelLocs.begin(), SelLocs.end(), getStoredSelLocs());
+}
+
+void ObjCMethodDecl::getSelectorLocs(
+ SmallVectorImpl<SourceLocation> &SelLocs) const {
+ for (unsigned i = 0, e = getNumSelectorLocs(); i != e; ++i)
+ SelLocs.push_back(getSelectorLoc(i));
+}
+
+void ObjCMethodDecl::setMethodParams(ASTContext &C,
+ ArrayRef<ParmVarDecl*> Params,
+ ArrayRef<SourceLocation> SelLocs) {
+ assert((!SelLocs.empty() || isImplicit()) &&
+ "No selector locs for non-implicit method");
+ if (isImplicit())
+ return setParamsAndSelLocs(C, Params, ArrayRef<SourceLocation>());
+
+ SelLocsKind = hasStandardSelectorLocs(getSelector(), SelLocs, Params, EndLoc);
+ if (SelLocsKind != SelLoc_NonStandard)
+ return setParamsAndSelLocs(C, Params, ArrayRef<SourceLocation>());
+
+ setParamsAndSelLocs(C, Params, SelLocs);
}
/// \brief A definition will return its interface declaration.
@@ -356,6 +400,11 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C,
ObjCMethodDecl *ObjCMethodDecl::getNextRedeclaration() {
ASTContext &Ctx = getASTContext();
ObjCMethodDecl *Redecl = 0;
+ if (HasRedeclaration)
+ Redecl = const_cast<ObjCMethodDecl*>(Ctx.getObjCMethodRedeclaration(this));
+ if (Redecl)
+ return Redecl;
+
Decl *CtxD = cast<Decl>(getDeclContext());
if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) {
@@ -377,6 +426,12 @@ ObjCMethodDecl *ObjCMethodDecl::getNextRedeclaration() {
Redecl = CatD->getMethod(getSelector(), isInstanceMethod());
}
+ if (!Redecl && isRedeclaration()) {
+ // This is the last redeclaration, go back to the first method.
+ return cast<ObjCContainerDecl>(CtxD)->getMethod(getSelector(),
+ isInstanceMethod());
+ }
+
return Redecl ? Redecl : this;
}
@@ -444,6 +499,7 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const {
// These selectors have a conventional meaning only for instance methods.
case OMF_dealloc:
+ case OMF_finalize:
case OMF_retain:
case OMF_release:
case OMF_autorelease:
@@ -545,8 +601,7 @@ ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() {
return IMD->getClassInterface();
assert(!isa<ObjCProtocolDecl>(getDeclContext()) && "It's a protocol method");
- assert(false && "unknown method context");
- return 0;
+ llvm_unreachable("unknown method context");
}
//===----------------------------------------------------------------------===//
@@ -566,11 +621,10 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(ASTContext &C,
ObjCInterfaceDecl::
ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
SourceLocation CLoc, bool FD, bool isInternal)
- : ObjCContainerDecl(ObjCInterface, DC, atLoc, Id),
+ : ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, atLoc),
TypeForDecl(0), SuperClass(0),
CategoryList(0), IvarList(0),
- ForwardDecl(FD), InternalInterface(isInternal), ExternallyCompleted(false),
- ClassLoc(CLoc) {
+ ForwardDecl(FD), InternalInterface(isInternal), ExternallyCompleted(false) {
}
void ObjCInterfaceDecl::LoadExternalDefinition() const {
@@ -756,8 +810,7 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC,
ID = IM->getClassInterface();
if (BW)
IM->setHasSynthBitfield(true);
- }
- else {
+ } else {
ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(DC);
ID = CD->getClassInterface();
if (BW)
@@ -778,8 +831,7 @@ const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const {
default:
case ObjCCategoryImpl:
case ObjCProtocol:
- assert(0 && "invalid ivar container!");
- return 0;
+ llvm_unreachable("invalid ivar container!");
// Ivars can only appear in class extension categories.
case ObjCCategory: {
@@ -812,9 +864,10 @@ ObjCAtDefsFieldDecl
//===----------------------------------------------------------------------===//
ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
- IdentifierInfo *Id) {
- return new (C) ObjCProtocolDecl(DC, L, Id);
+ IdentifierInfo *Id,
+ SourceLocation nameLoc,
+ SourceLocation atStartLoc) {
+ return new (C) ObjCProtocolDecl(DC, Id, nameLoc, atStartLoc);
}
ObjCProtocolDecl *ObjCProtocolDecl::lookupProtocolNamed(IdentifierInfo *Name) {
@@ -850,36 +903,31 @@ ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel,
//===----------------------------------------------------------------------===//
ObjCClassDecl::ObjCClassDecl(DeclContext *DC, SourceLocation L,
- ObjCInterfaceDecl *const *Elts,
- const SourceLocation *Locs,
- unsigned nElts,
+ ObjCInterfaceDecl *const Elt,
+ const SourceLocation Loc,
ASTContext &C)
: Decl(ObjCClass, DC, L) {
- setClassList(C, Elts, Locs, nElts);
-}
-
-void ObjCClassDecl::setClassList(ASTContext &C, ObjCInterfaceDecl*const*List,
- const SourceLocation *Locs, unsigned Num) {
- ForwardDecls = (ObjCClassRef*) C.Allocate(sizeof(ObjCClassRef)*Num,
- llvm::alignOf<ObjCClassRef>());
- for (unsigned i = 0; i < Num; ++i)
- new (&ForwardDecls[i]) ObjCClassRef(List[i], Locs[i]);
-
- NumDecls = Num;
+ setClass(C, Elt, Loc);
}
ObjCClassDecl *ObjCClassDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
- ObjCInterfaceDecl *const *Elts,
- const SourceLocation *Locs,
- unsigned nElts) {
- return new (C) ObjCClassDecl(DC, L, Elts, Locs, nElts, C);
+ ObjCInterfaceDecl *const Elt,
+ const SourceLocation Loc) {
+ return new (C) ObjCClassDecl(DC, L, Elt, Loc, C);
}
+void ObjCClassDecl::setClass(ASTContext &C, ObjCInterfaceDecl*const Cls,
+ const SourceLocation Loc) {
+
+ ForwardDecl = (ObjCClassRef*) C.Allocate(sizeof(ObjCClassRef),
+ llvm::alignOf<ObjCClassRef>());
+ new (ForwardDecl) ObjCClassRef(Cls, Loc);
+}
+
SourceRange ObjCClassDecl::getSourceRange() const {
// FIXME: We should include the semicolon
- assert(NumDecls);
- return SourceRange(getLocation(), ForwardDecls[NumDecls-1].getLocation());
+ return SourceRange(getLocation(), ForwardDecl->getLocation());
}
//===----------------------------------------------------------------------===//
@@ -912,8 +960,25 @@ ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation AtLoc,
SourceLocation ClassNameLoc,
SourceLocation CategoryNameLoc,
- IdentifierInfo *Id) {
- return new (C) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id);
+ IdentifierInfo *Id,
+ ObjCInterfaceDecl *IDecl) {
+ ObjCCategoryDecl *CatDecl = new (C) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc,
+ CategoryNameLoc, Id,
+ IDecl);
+ if (IDecl) {
+ // Link this category into its class's category list.
+ CatDecl->NextClassCategory = IDecl->getCategoryList();
+ IDecl->setCategoryList(CatDecl);
+ if (ASTMutationListener *L = C.getASTMutationListener())
+ L->AddedObjCCategoryToInterface(CatDecl, IDecl);
+ }
+
+ return CatDecl;
+}
+
+ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, EmptyShell Empty) {
+ return new (C) ObjCCategoryDecl(0, SourceLocation(), SourceLocation(),
+ SourceLocation(), 0, 0);
}
ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const {
@@ -932,9 +997,12 @@ void ObjCCategoryDecl::setImplementation(ObjCCategoryImplDecl *ImplD) {
ObjCCategoryImplDecl *
ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,IdentifierInfo *Id,
- ObjCInterfaceDecl *ClassInterface) {
- return new (C) ObjCCategoryImplDecl(DC, L, Id, ClassInterface);
+ IdentifierInfo *Id,
+ ObjCInterfaceDecl *ClassInterface,
+ SourceLocation nameLoc,
+ SourceLocation atStartLoc) {
+ return new (C) ObjCCategoryImplDecl(DC, Id, ClassInterface,
+ nameLoc, atStartLoc);
}
ObjCCategoryDecl *ObjCCategoryImplDecl::getCategoryDecl() const {
@@ -997,7 +1065,7 @@ FindPropertyImplDecl(IdentifierInfo *Id) const {
return 0;
}
-llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,
+raw_ostream &clang::operator<<(raw_ostream &OS,
const ObjCCategoryImplDecl *CID) {
OS << CID->getName();
return OS;
@@ -1009,13 +1077,28 @@ llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,
ObjCImplementationDecl *
ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
ObjCInterfaceDecl *ClassInterface,
- ObjCInterfaceDecl *SuperDecl) {
- return new (C) ObjCImplementationDecl(DC, L, ClassInterface, SuperDecl);
+ ObjCInterfaceDecl *SuperDecl,
+ SourceLocation nameLoc,
+ SourceLocation atStartLoc) {
+ return new (C) ObjCImplementationDecl(DC, ClassInterface, SuperDecl,
+ nameLoc, atStartLoc);
+}
+
+void ObjCImplementationDecl::setIvarInitializers(ASTContext &C,
+ CXXCtorInitializer ** initializers,
+ unsigned numInitializers) {
+ if (numInitializers > 0) {
+ NumIvarInitializers = numInitializers;
+ CXXCtorInitializer **ivarInitializers =
+ new (C) CXXCtorInitializer*[NumIvarInitializers];
+ memcpy(ivarInitializers, initializers,
+ numInitializers * sizeof(CXXCtorInitializer*));
+ IvarInitializers = ivarInitializers;
+ }
}
-llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,
+raw_ostream &clang::operator<<(raw_ostream &OS,
const ObjCImplementationDecl *ID) {
OS << ID->getName();
return OS;
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 19554a3baaea..08a1ab5723cd 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -24,22 +24,25 @@ using namespace clang;
namespace {
class DeclPrinter : public DeclVisitor<DeclPrinter> {
- llvm::raw_ostream &Out;
+ raw_ostream &Out;
ASTContext &Context;
PrintingPolicy Policy;
unsigned Indentation;
+ bool PrintInstantiation;
- llvm::raw_ostream& Indent() { return Indent(Indentation); }
- llvm::raw_ostream& Indent(unsigned Indentation);
- void ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls);
+ raw_ostream& Indent() { return Indent(Indentation); }
+ raw_ostream& Indent(unsigned Indentation);
+ void ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls);
void Print(AccessSpecifier AS);
public:
- DeclPrinter(llvm::raw_ostream &Out, ASTContext &Context,
+ DeclPrinter(raw_ostream &Out, ASTContext &Context,
const PrintingPolicy &Policy,
- unsigned Indentation = 0)
- : Out(Out), Context(Context), Policy(Policy), Indentation(Indentation) { }
+ unsigned Indentation = 0,
+ bool PrintInstantiation = false)
+ : Out(Out), Context(Context), Policy(Policy), Indentation(Indentation),
+ PrintInstantiation(PrintInstantiation) { }
void VisitDeclContext(DeclContext *DC, bool Indent = true);
@@ -62,6 +65,8 @@ namespace {
void VisitCXXRecordDecl(CXXRecordDecl *D);
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
void VisitTemplateDecl(const TemplateDecl *D);
+ void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
+ void VisitClassTemplateDecl(ClassTemplateDecl *D);
void VisitObjCMethodDecl(ObjCMethodDecl *D);
void VisitObjCClassDecl(ObjCClassDecl *D);
void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
@@ -77,16 +82,20 @@ namespace {
void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
void VisitUsingDecl(UsingDecl *D);
void VisitUsingShadowDecl(UsingShadowDecl *D);
+
+ void PrintTemplateParameters(const TemplateParameterList *Params,
+ const TemplateArgumentList *Args);
};
}
-void Decl::print(llvm::raw_ostream &Out, unsigned Indentation) const {
- print(Out, getASTContext().PrintingPolicy, Indentation);
+void Decl::print(raw_ostream &Out, unsigned Indentation,
+ bool PrintInstantiation) const {
+ print(Out, getASTContext().getPrintingPolicy(), Indentation, PrintInstantiation);
}
-void Decl::print(llvm::raw_ostream &Out, const PrintingPolicy &Policy,
- unsigned Indentation) const {
- DeclPrinter Printer(Out, getASTContext(), Policy, Indentation);
+void Decl::print(raw_ostream &Out, const PrintingPolicy &Policy,
+ unsigned Indentation, bool PrintInstantiation) const {
+ DeclPrinter Printer(Out, getASTContext(), Policy, Indentation, PrintInstantiation);
Printer.Visit(const_cast<Decl*>(this));
}
@@ -105,7 +114,7 @@ static QualType GetBaseType(QualType T) {
else if (const VectorType *VTy = BaseType->getAs<VectorType>())
BaseType = VTy->getElementType();
else
- assert(0 && "Unknown declarator!");
+ llvm_unreachable("Unknown declarator!");
}
return BaseType;
}
@@ -119,7 +128,7 @@ static QualType getDeclType(Decl* D) {
}
void Decl::printGroup(Decl** Begin, unsigned NumDecls,
- llvm::raw_ostream &Out, const PrintingPolicy &Policy,
+ raw_ostream &Out, const PrintingPolicy &Policy,
unsigned Indentation) {
if (NumDecls == 1) {
(*Begin)->print(Out, Policy, Indentation);
@@ -132,7 +141,7 @@ void Decl::printGroup(Decl** Begin, unsigned NumDecls,
++Begin;
PrintingPolicy SubPolicy(Policy);
- if (TD && TD->isDefinition()) {
+ if (TD && TD->isCompleteDefinition()) {
TD->print(Out, Policy, Indentation);
Out << " ";
SubPolicy.SuppressTag = true;
@@ -159,7 +168,7 @@ void DeclContext::dumpDeclContext() const {
DC = DC->getParent();
ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
- DeclPrinter Printer(llvm::errs(), Ctx, Ctx.PrintingPolicy, 0);
+ DeclPrinter Printer(llvm::errs(), Ctx, Ctx.getPrintingPolicy(), 0);
Printer.VisitDeclContext(const_cast<DeclContext *>(this), /*Indent=*/false);
}
@@ -167,13 +176,13 @@ void Decl::dump() const {
print(llvm::errs());
}
-llvm::raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
+raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
for (unsigned i = 0; i != Indentation; ++i)
Out << " ";
return Out;
}
-void DeclPrinter::ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls) {
+void DeclPrinter::ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls) {
this->Indent();
Decl::printGroup(Decls.data(), Decls.size(), Out, Policy, Indentation);
Out << ";\n";
@@ -183,7 +192,7 @@ void DeclPrinter::ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls) {
void DeclPrinter::Print(AccessSpecifier AS) {
switch(AS) {
- case AS_none: assert(0 && "No access specifier!"); break;
+ case AS_none: llvm_unreachable("No access specifier!");
case AS_public: Out << "public"; break;
case AS_protected: Out << "protected"; break;
case AS_private: Out << "private"; break;
@@ -198,7 +207,7 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
if (Indent)
Indentation += Policy.Indentation;
- llvm::SmallVector<Decl*, 2> Decls;
+ SmallVector<Decl*, 2> Decls;
for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end();
D != DEnd; ++D) {
@@ -304,8 +313,12 @@ void DeclPrinter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) {
std::string S = D->getNameAsString();
D->getUnderlyingType().getAsStringInternal(S, Policy);
- if (!Policy.SuppressSpecifiers)
+ if (!Policy.SuppressSpecifiers) {
Out << "typedef ";
+
+ if (D->isModulePrivate())
+ Out << "__module_private__ ";
+ }
Out << S;
}
@@ -315,6 +328,8 @@ void DeclPrinter::VisitTypeAliasDecl(TypeAliasDecl *D) {
}
void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
+ if (!Policy.SuppressSpecifiers && D->isModulePrivate())
+ Out << "__module_private__ ";
Out << "enum ";
if (D->isScoped()) {
if (D->isScopedUsingClassTag())
@@ -322,7 +337,7 @@ void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
else
Out << "struct ";
}
- Out << D;
+ Out << *D;
if (D->isFixed()) {
std::string Underlying;
@@ -330,7 +345,7 @@ void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
Out << " : " << Underlying;
}
- if (D->isDefinition()) {
+ if (D->isCompleteDefinition()) {
Out << " {\n";
VisitDeclContext(D);
Indent() << "}";
@@ -338,11 +353,13 @@ void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
}
void DeclPrinter::VisitRecordDecl(RecordDecl *D) {
+ if (!Policy.SuppressSpecifiers && D->isModulePrivate())
+ Out << "__module_private__ ";
Out << D->getKindName();
if (D->getIdentifier())
- Out << ' ' << D;
+ Out << ' ' << *D;
- if (D->isDefinition()) {
+ if (D->isCompleteDefinition()) {
Out << " {\n";
VisitDeclContext(D);
Indent() << "}";
@@ -350,7 +367,7 @@ void DeclPrinter::VisitRecordDecl(RecordDecl *D) {
}
void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) {
- Out << D;
+ Out << *D;
if (Expr *Init = D->getInitExpr()) {
Out << " = ";
Init->printPretty(Out, Context, 0, Policy, Indentation);
@@ -364,11 +381,13 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
case SC_Extern: Out << "extern "; break;
case SC_Static: Out << "static "; break;
case SC_PrivateExtern: Out << "__private_extern__ "; break;
- case SC_Auto: case SC_Register: llvm_unreachable("invalid for functions");
+ case SC_Auto: case SC_Register: case SC_OpenCLWorkGroupLocal:
+ llvm_unreachable("invalid for functions");
}
- if (D->isInlineSpecified()) Out << "inline ";
+ if (D->isInlineSpecified()) Out << "inline ";
if (D->isVirtualAsWritten()) Out << "virtual ";
+ if (D->isModulePrivate()) Out << "__module_private__ ";
}
PrintingPolicy SubPolicy(Policy);
@@ -449,6 +468,10 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (D->hasAttr<NoReturnAttr>())
Proto += " __attribute((noreturn))";
+
+ if (D->hasAttr<ReturnsTwiceAttr>())
+ Proto += " __attribute((returns_twice))";
+
if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) {
bool HasInitializerList = false;
for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
@@ -468,10 +491,9 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (BMInitializer->isAnyMemberInitializer()) {
FieldDecl *FD = BMInitializer->getAnyMember();
- Out << FD;
+ Out << *FD;
} else {
- Out << QualType(BMInitializer->getBaseClass(),
- 0).getAsString(Policy);
+ Out << QualType(BMInitializer->getBaseClass(), 0).getAsString(Policy);
}
Out << "(";
@@ -549,6 +571,8 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
if (!Policy.SuppressSpecifiers && D->isMutable())
Out << "mutable ";
+ if (!Policy.SuppressSpecifiers && D->isModulePrivate())
+ Out << "__module_private__ ";
std::string Name = D->getNameAsString();
D->getType().getAsStringInternal(Name, Policy);
@@ -577,6 +601,8 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
if (!Policy.SuppressSpecifiers && D->isThreadSpecified())
Out << "__thread ";
+ if (!Policy.SuppressSpecifiers && D->isModulePrivate())
+ Out << "__module_private__ ";
std::string Name = D->getNameAsString();
QualType T = D->getType();
@@ -621,7 +647,7 @@ void DeclPrinter::VisitStaticAssertDecl(StaticAssertDecl *D) {
// C++ declarations
//----------------------------------------------------------------------------
void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) {
- Out << "namespace " << D << " {\n";
+ Out << "namespace " << *D << " {\n";
VisitDeclContext(D);
Indent() << "}";
}
@@ -630,22 +656,24 @@ void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
Out << "using namespace ";
if (D->getQualifier())
D->getQualifier()->print(Out, Policy);
- Out << D->getNominatedNamespaceAsWritten();
+ Out << *D->getNominatedNamespaceAsWritten();
}
void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
- Out << "namespace " << D << " = ";
+ Out << "namespace " << *D << " = ";
if (D->getQualifier())
D->getQualifier()->print(Out, Policy);
- Out << D->getAliasedNamespace();
+ Out << *D->getAliasedNamespace();
}
void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
+ if (!Policy.SuppressSpecifiers && D->isModulePrivate())
+ Out << "__module_private__ ";
Out << D->getKindName();
if (D->getIdentifier())
- Out << ' ' << D;
+ Out << ' ' << *D;
- if (D->isDefinition()) {
+ if (D->isCompleteDefinition()) {
// Print the base classes
if (D->getNumBases()) {
Out << " : ";
@@ -694,10 +722,13 @@ void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
Visit(*D->decls_begin());
}
-void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
+void DeclPrinter::PrintTemplateParameters(
+ const TemplateParameterList *Params, const TemplateArgumentList *Args = 0) {
+ assert(Params);
+ assert(!Args || Params->size() == Args->size());
+
Out << "template <";
- TemplateParameterList *Params = D->getTemplateParameters();
for (unsigned i = 0, e = Params->size(); i != e; ++i) {
if (i != 0)
Out << ", ";
@@ -716,7 +747,10 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
Out << TTP->getNameAsString();
- if (TTP->hasDefaultArgument()) {
+ if (Args) {
+ Out << " = ";
+ Args->get(i).print(Policy, Out);
+ } else if (TTP->hasDefaultArgument()) {
Out << " = ";
Out << TTP->getDefaultArgument().getAsString(Policy);
};
@@ -732,7 +766,10 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
Out << Name->getName();
}
- if (NTTP->hasDefaultArgument()) {
+ if (Args) {
+ Out << " = ";
+ Args->get(i).print(Policy, Out);
+ } else if (NTTP->hasDefaultArgument()) {
Out << " = ";
NTTP->getDefaultArgument()->printPretty(Out, Context, 0, Policy,
Indentation);
@@ -745,6 +782,10 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
}
Out << "> ";
+}
+
+void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
+ PrintTemplateParameters(D->getTemplateParameters());
if (const TemplateTemplateParmDecl *TTP =
dyn_cast<TemplateTemplateParmDecl>(D)) {
@@ -757,17 +798,39 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
}
}
+void DeclPrinter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
+ if (PrintInstantiation) {
+ TemplateParameterList *Params = D->getTemplateParameters();
+ for (FunctionTemplateDecl::spec_iterator I = D->spec_begin(), E = D->spec_end();
+ I != E; ++I) {
+ PrintTemplateParameters(Params, (*I)->getTemplateSpecializationArgs());
+ Visit(*I);
+ }
+ }
+
+ return VisitRedeclarableTemplateDecl(D);
+}
+
+void DeclPrinter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+ if (PrintInstantiation) {
+ TemplateParameterList *Params = D->getTemplateParameters();
+ for (ClassTemplateDecl::spec_iterator I = D->spec_begin(), E = D->spec_end();
+ I != E; ++I) {
+ PrintTemplateParameters(Params, &(*I)->getTemplateArgs());
+ Visit(*I);
+ Out << '\n';
+ }
+ }
+
+ return VisitRedeclarableTemplateDecl(D);
+}
+
//----------------------------------------------------------------------------
// Objective-C declarations
//----------------------------------------------------------------------------
void DeclPrinter::VisitObjCClassDecl(ObjCClassDecl *D) {
- Out << "@class ";
- for (ObjCClassDecl::iterator I = D->begin(), E = D->end();
- I != E; ++I) {
- if (I != D->begin()) Out << ", ";
- Out << I->getInterface();
- }
+ Out << "@class " << *D->getForwardInterfaceDecl();
}
void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
@@ -783,9 +846,9 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(),
E = OMD->param_end(); PI != E; ++PI) {
// FIXME: selector is missing here!
- pos = name.find_first_of(":", lastPos);
+ pos = name.find_first_of(':', lastPos);
Out << " " << name.substr(lastPos, pos - lastPos);
- Out << ":(" << (*PI)->getType().getAsString(Policy) << ')' << *PI;
+ Out << ":(" << (*PI)->getType().getAsString(Policy) << ')' << **PI;
lastPos = pos + 1;
}
@@ -807,7 +870,7 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) {
ObjCInterfaceDecl *SID = OID->getSuperClass();
if (SID)
- Out << "@implementation " << I << " : " << SID;
+ Out << "@implementation " << I << " : " << *SID;
else
Out << "@implementation " << I;
Out << "\n";
@@ -820,7 +883,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
ObjCInterfaceDecl *SID = OID->getSuperClass();
if (SID)
- Out << "@interface " << I << " : " << SID;
+ Out << "@interface " << I << " : " << *SID;
else
Out << "@interface " << I;
@@ -829,7 +892,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
if (!Protocols.empty()) {
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
E = Protocols.end(); I != E; ++I)
- Out << (I == Protocols.begin() ? '<' : ',') << *I;
+ Out << (I == Protocols.begin() ? '<' : ',') << **I;
}
if (!Protocols.empty())
@@ -840,7 +903,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
Indentation += Policy.Indentation;
for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(),
E = OID->ivar_end(); I != E; ++I) {
- Indent() << (*I)->getType().getAsString(Policy) << ' ' << *I << ";\n";
+ Indent() << (*I)->getType().getAsString(Policy) << ' ' << **I << ";\n";
}
Indentation -= Policy.Indentation;
Out << "}\n";
@@ -857,18 +920,18 @@ void DeclPrinter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
E = D->protocol_end();
I != E; ++I) {
if (I != D->protocol_begin()) Out << ", ";
- Out << *I;
+ Out << **I;
}
}
void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
- Out << "@protocol " << PID << '\n';
+ Out << "@protocol " << *PID << '\n';
VisitDeclContext(PID, false);
Out << "@end";
}
void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
- Out << "@implementation " << PID->getClassInterface() << '(' << PID << ")\n";
+ Out << "@implementation " << *PID->getClassInterface() << '(' << *PID <<")\n";
VisitDeclContext(PID, false);
Out << "@end";
@@ -876,7 +939,7 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
}
void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
- Out << "@interface " << PID->getClassInterface() << '(' << PID << ")\n";
+ Out << "@interface " << *PID->getClassInterface() << '(' << *PID << ")\n";
VisitDeclContext(PID, false);
Out << "@end";
@@ -884,8 +947,8 @@ void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
}
void DeclPrinter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) {
- Out << "@compatibility_alias " << AID
- << ' ' << AID->getClassInterface() << ";\n";
+ Out << "@compatibility_alias " << *AID
+ << ' ' << *AID->getClassInterface() << ";\n";
}
/// PrintObjCPropertyDecl - print a property declaration.
@@ -904,58 +967,60 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
ObjCPropertyDecl::OBJC_PR_readonly) {
Out << (first ? ' ' : ',') << "readonly";
first = false;
- }
+ }
- if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) {
- Out << (first ? ' ' : ',') << "getter = "
- << PDecl->getGetterName().getAsString();
- first = false;
- }
- if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) {
- Out << (first ? ' ' : ',') << "setter = "
- << PDecl->getSetterName().getAsString();
- first = false;
- }
+ if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) {
+ Out << (first ? ' ' : ',') << "getter = "
+ << PDecl->getGetterName().getAsString();
+ first = false;
+ }
+ if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) {
+ Out << (first ? ' ' : ',') << "setter = "
+ << PDecl->getSetterName().getAsString();
+ first = false;
+ }
- if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_assign) {
- Out << (first ? ' ' : ',') << "assign";
- first = false;
- }
+ if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_assign) {
+ Out << (first ? ' ' : ',') << "assign";
+ first = false;
+ }
- if (PDecl->getPropertyAttributes() &
- ObjCPropertyDecl::OBJC_PR_readwrite) {
- Out << (first ? ' ' : ',') << "readwrite";
- first = false;
- }
+ if (PDecl->getPropertyAttributes() &
+ ObjCPropertyDecl::OBJC_PR_readwrite) {
+ Out << (first ? ' ' : ',') << "readwrite";
+ first = false;
+ }
- if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain) {
- Out << (first ? ' ' : ',') << "retain";
- first = false;
- }
+ if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain) {
+ Out << (first ? ' ' : ',') << "retain";
+ first = false;
+ }
- if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_strong) {
- Out << (first ? ' ' : ',') << "strong";
- first = false;
- }
+ if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_strong) {
+ Out << (first ? ' ' : ',') << "strong";
+ first = false;
+ }
- if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) {
- Out << (first ? ' ' : ',') << "copy";
- first = false;
- }
+ if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) {
+ Out << (first ? ' ' : ',') << "copy";
+ first = false;
+ }
- if (PDecl->getPropertyAttributes() &
- ObjCPropertyDecl::OBJC_PR_nonatomic) {
- Out << (first ? ' ' : ',') << "nonatomic";
- first = false;
- }
- if (PDecl->getPropertyAttributes() &
- ObjCPropertyDecl::OBJC_PR_atomic) {
- Out << (first ? ' ' : ',') << "atomic";
- first = false;
- }
- Out << " )";
+ if (PDecl->getPropertyAttributes() &
+ ObjCPropertyDecl::OBJC_PR_nonatomic) {
+ Out << (first ? ' ' : ',') << "nonatomic";
+ first = false;
+ }
+ if (PDecl->getPropertyAttributes() &
+ ObjCPropertyDecl::OBJC_PR_atomic) {
+ Out << (first ? ' ' : ',') << "atomic";
+ first = false;
+ }
+
+ (void) first; // Silence dead store warning due to idiomatic code.
+ Out << " )";
}
- Out << ' ' << PDecl->getType().getAsString(Policy) << ' ' << PDecl;
+ Out << ' ' << PDecl->getType().getAsString(Policy) << ' ' << *PDecl;
}
void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
@@ -963,15 +1028,15 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
Out << "@synthesize ";
else
Out << "@dynamic ";
- Out << PID->getPropertyDecl();
+ Out << *PID->getPropertyDecl();
if (PID->getPropertyIvarDecl())
- Out << '=' << PID->getPropertyIvarDecl();
+ Out << '=' << *PID->getPropertyIvarDecl();
}
void DeclPrinter::VisitUsingDecl(UsingDecl *D) {
Out << "using ";
D->getQualifier()->print(Out, Policy);
- Out << D;
+ Out << *D;
}
void
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index bc375d0ad2d3..558a4ccac96b 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -348,7 +348,7 @@ void ClassTemplateDecl::AddPartialSpecialization(
}
void ClassTemplateDecl::getPartialSpecializations(
- llvm::SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS) {
+ SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS) {
llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> &PartialSpecs
= getPartialSpecializations();
PS.clear();
@@ -406,7 +406,7 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
// pack.
ASTContext &Context = getASTContext();
TemplateParameterList *Params = getTemplateParameters();
- llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
+ SmallVector<TemplateArgument, 16> TemplateArgs;
TemplateArgs.resize(Params->size());
GenerateInjectedTemplateArgs(getASTContext(), Params, TemplateArgs.data());
CommonPtr->InjectedClassNameType
@@ -563,6 +563,24 @@ TemplateArgumentList::CreateCopy(ASTContext &Context,
return new (Mem) TemplateArgumentList(StoredArgs, NumArgs, true);
}
+FunctionTemplateSpecializationInfo *
+FunctionTemplateSpecializationInfo::Create(ASTContext &C, FunctionDecl *FD,
+ FunctionTemplateDecl *Template,
+ TemplateSpecializationKind TSK,
+ const TemplateArgumentList *TemplateArgs,
+ const TemplateArgumentListInfo *TemplateArgsAsWritten,
+ SourceLocation POI) {
+ const ASTTemplateArgumentListInfo *ArgsAsWritten = 0;
+ if (TemplateArgsAsWritten)
+ ArgsAsWritten = ASTTemplateArgumentListInfo::Create(C,
+ *TemplateArgsAsWritten);
+
+ return new (C) FunctionTemplateSpecializationInfo(FD, Template, TSK,
+ TemplateArgs,
+ ArgsAsWritten,
+ POI);
+}
+
//===----------------------------------------------------------------------===//
// ClassTemplateSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
@@ -638,15 +656,27 @@ ClassTemplateSpecializationDecl::getSpecializedTemplate() const {
SourceRange
ClassTemplateSpecializationDecl::getSourceRange() const {
- if (!ExplicitInfo)
- return SourceRange();
- SourceLocation Begin = getExternLoc();
- if (Begin.isInvalid())
- Begin = getTemplateKeywordLoc();
- SourceLocation End = getRBraceLoc();
- if (End.isInvalid())
- End = getTypeAsWritten()->getTypeLoc().getEndLoc();
- return SourceRange(Begin, End);
+ if (ExplicitInfo) {
+ SourceLocation Begin = getExternLoc();
+ if (Begin.isInvalid())
+ Begin = getTemplateKeywordLoc();
+ SourceLocation End = getRBraceLoc();
+ if (End.isInvalid())
+ End = getTypeAsWritten()->getTypeLoc().getEndLoc();
+ return SourceRange(Begin, End);
+ }
+ else {
+ // No explicit info available.
+ llvm::PointerUnion<ClassTemplateDecl *,
+ ClassTemplatePartialSpecializationDecl *>
+ inst_from = getInstantiatedFrom();
+ if (inst_from.isNull())
+ return getSpecializedTemplate()->getSourceRange();
+ if (ClassTemplateDecl *ctd = inst_from.dyn_cast<ClassTemplateDecl*>())
+ return ctd->getSourceRange();
+ return inst_from.get<ClassTemplatePartialSpecializationDecl*>()
+ ->getSourceRange();
+ }
}
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index 72c0e9da7f1d..bf647ed7ac35 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -193,8 +193,7 @@ DeclarationName::NameKind DeclarationName::getNameKind() const {
}
// Can't actually get here.
- assert(0 && "This should be unreachable!");
- return Identifier;
+ llvm_unreachable("This should be unreachable!");
}
bool DeclarationName::isDependentName() const {
@@ -209,7 +208,7 @@ std::string DeclarationName::getAsString() const {
return OS.str();
}
-void DeclarationName::printName(llvm::raw_ostream &OS) const {
+void DeclarationName::printName(raw_ostream &OS) const {
switch (getNameKind()) {
case Identifier:
if (const IdentifierInfo *II = getAsIdentifierInfo())
@@ -225,7 +224,7 @@ void DeclarationName::printName(llvm::raw_ostream &OS) const {
case CXXConstructorName: {
QualType ClassType = getCXXNameType();
if (const RecordType *ClassRec = ClassType->getAs<RecordType>())
- OS << ClassRec->getDecl();
+ OS << *ClassRec->getDecl();
else
OS << ClassType.getAsString();
return;
@@ -235,7 +234,7 @@ void DeclarationName::printName(llvm::raw_ostream &OS) const {
OS << '~';
QualType Type = getCXXNameType();
if (const RecordType *Rec = Type->getAs<RecordType>())
- OS << Rec->getDecl();
+ OS << *Rec->getDecl();
else
OS << Type.getAsString();
return;
@@ -266,7 +265,7 @@ void DeclarationName::printName(llvm::raw_ostream &OS) const {
OS << "operator ";
QualType Type = getCXXNameType();
if (const RecordType *Rec = Type->getAs<RecordType>())
- OS << Rec->getDecl();
+ OS << *Rec->getDecl();
else
OS << Type.getAsString();
return;
@@ -276,7 +275,7 @@ void DeclarationName::printName(llvm::raw_ostream &OS) const {
return;
}
- assert(false && "Unexpected declaration name kind");
+ llvm_unreachable("Unexpected declaration name kind");
}
QualType DeclarationName::getCXXNameType() const {
@@ -338,9 +337,8 @@ void *DeclarationName::getFETokenInfoAsVoid() const {
return getCXXLiteralIdentifier()->getFETokenInfo<void>();
default:
- assert(false && "Declaration name has no FETokenInfo");
+ llvm_unreachable("Declaration name has no FETokenInfo");
}
- return 0;
}
void DeclarationName::setFETokenInfo(void *T) {
@@ -364,7 +362,7 @@ void DeclarationName::setFETokenInfo(void *T) {
break;
default:
- assert(false && "Declaration name has no FETokenInfo");
+ llvm_unreachable("Declaration name has no FETokenInfo");
}
}
@@ -562,7 +560,7 @@ std::string DeclarationNameInfo::getAsString() const {
return OS.str();
}
-void DeclarationNameInfo::printName(llvm::raw_ostream &OS) const {
+void DeclarationNameInfo::printName(raw_ostream &OS) const {
switch (Name.getNameKind()) {
case DeclarationName::Identifier:
case DeclarationName::ObjCZeroArgSelector:
@@ -588,7 +586,7 @@ void DeclarationNameInfo::printName(llvm::raw_ostream &OS) const {
Name.printName(OS);
return;
}
- assert(false && "Unexpected declaration name kind");
+ llvm_unreachable("Unexpected declaration name kind");
}
SourceLocation DeclarationNameInfo::getEndLoc() const {
@@ -621,6 +619,5 @@ SourceLocation DeclarationNameInfo::getEndLoc() const {
case DeclarationName::CXXUsingDirective:
return NameLoc;
}
- assert(false && "Unexpected declaration name kind");
- return SourceLocation();
+ llvm_unreachable("Unexpected declaration name kind");
}
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
index dfe0119f597d..2568adaa5a44 100644
--- a/lib/AST/DumpXML.cpp
+++ b/lib/AST/DumpXML.cpp
@@ -53,9 +53,9 @@ enum NodeState {
};
struct Node {
- llvm::StringRef Name;
+ StringRef Name;
NodeState State;
- Node(llvm::StringRef name) : Name(name), State(NS_Attrs) {}
+ Node(StringRef name) : Name(name), State(NS_Attrs) {}
bool isDoneWithAttrs() const { return State != NS_Attrs; }
};
@@ -159,7 +159,7 @@ template <class Impl> struct XMLTypeVisitor {
#undef DISPATCH
};
-static llvm::StringRef getTypeKindName(Type *T) {
+static StringRef getTypeKindName(Type *T) {
switch (T->getTypeClass()) {
#define TYPE(DERIVED, BASE) case Type::DERIVED: return #DERIVED "Type";
#define ABSTRACT_TYPE(DERIVED, BASE)
@@ -172,11 +172,11 @@ static llvm::StringRef getTypeKindName(Type *T) {
struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
public XMLTypeVisitor<XMLDumper> {
- llvm::raw_ostream &out;
+ raw_ostream &out;
ASTContext &Context;
- llvm::SmallVector<Node, 16> Stack;
+ SmallVector<Node, 16> Stack;
unsigned Indent;
- explicit XMLDumper(llvm::raw_ostream &OS, ASTContext &context)
+ explicit XMLDumper(raw_ostream &OS, ASTContext &context)
: out(OS), Context(context), Indent(0) {}
void indent() {
@@ -185,7 +185,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
}
/// Push a new node on the stack.
- void push(llvm::StringRef name) {
+ void push(StringRef name) {
if (!Stack.empty()) {
assert(Stack.back().isDoneWithAttrs());
if (Stack.back().State == NS_LazyChildren) {
@@ -200,7 +200,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
}
/// Set the given attribute to the given value.
- void set(llvm::StringRef attr, llvm::StringRef value) {
+ void set(StringRef attr, StringRef value) {
assert(!Stack.empty() && !Stack.back().isDoneWithAttrs());
out << ' ' << attr << '=' << '"' << value << '"'; // TODO: quotation
}
@@ -226,7 +226,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
//---- General utilities -------------------------------------------//
- void setPointer(llvm::StringRef prop, const void *p) {
+ void setPointer(StringRef prop, const void *p) {
llvm::SmallString<10> buffer;
llvm::raw_svector_ostream os(buffer);
os << p;
@@ -238,11 +238,11 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
setPointer("ptr", p);
}
- void setInteger(llvm::StringRef prop, const llvm::APSInt &v) {
+ void setInteger(StringRef prop, const llvm::APSInt &v) {
set(prop, v.toString(10));
}
- void setInteger(llvm::StringRef prop, unsigned n) {
+ void setInteger(StringRef prop, unsigned n) {
llvm::SmallString<10> buffer;
llvm::raw_svector_ostream os(buffer);
os << n;
@@ -250,7 +250,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
set(prop, buffer);
}
- void setFlag(llvm::StringRef prop, bool flag) {
+ void setFlag(StringRef prop, bool flag) {
if (flag) set(prop, "true");
}
@@ -268,7 +268,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
class TemporaryContainer {
XMLDumper &Dumper;
public:
- TemporaryContainer(XMLDumper &dumper, llvm::StringRef name)
+ TemporaryContainer(XMLDumper &dumper, StringRef name)
: Dumper(dumper) {
Dumper.push(name);
Dumper.completeAttrs();
@@ -303,7 +303,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
completeAttrs();
pop();
}
- void visitDeclRef(llvm::StringRef Name, Decl *D) {
+ void visitDeclRef(StringRef Name, Decl *D) {
TemporaryContainer C(*this, Name);
if (D) visitDeclRef(D);
}
@@ -423,7 +423,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
// LinkageSpecDecl
void visitLinkageSpecDeclAttrs(LinkageSpecDecl *D) {
- llvm::StringRef lang = "";
+ StringRef lang = "";
switch (D->getLanguage()) {
case LinkageSpecDecl::lang_c: lang = "C"; break;
case LinkageSpecDecl::lang_cxx: lang = "C++"; break;
@@ -742,8 +742,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
// ObjCClassDecl
void visitObjCClassDeclChildren(ObjCClassDecl *D) {
- for (ObjCClassDecl::iterator I = D->begin(), E = D->end(); I != E; ++I)
- visitDeclRef(I->getInterface());
+ visitDeclRef(D->getForwardInterfaceDecl());
}
// ObjCInterfaceDecl
@@ -860,7 +859,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
}
// ObjCIvarDecl
- void setAccessControl(llvm::StringRef prop, ObjCIvarDecl::AccessControl AC) {
+ void setAccessControl(StringRef prop, ObjCIvarDecl::AccessControl AC) {
switch (AC) {
case ObjCIvarDecl::None: return set(prop, "none");
case ObjCIvarDecl::Private: return set(prop, "private");
@@ -1031,13 +1030,13 @@ void Decl::dumpXML() const {
dumpXML(llvm::errs());
}
-void Decl::dumpXML(llvm::raw_ostream &out) const {
+void Decl::dumpXML(raw_ostream &out) const {
XMLDumper(out, getASTContext()).dispatch(const_cast<Decl*>(this));
}
#else /* ifndef NDEBUG */
void Decl::dumpXML() const {}
-void Decl::dumpXML(llvm::raw_ostream &out) const {}
+void Decl::dumpXML(raw_ostream &out) const {}
#endif
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 4611ae369969..b0bcfe09f6dc 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -130,57 +130,6 @@ SourceLocation Expr::getExprLoc() const {
// Primary Expressions.
//===----------------------------------------------------------------------===//
-void ExplicitTemplateArgumentList::initializeFrom(
- const TemplateArgumentListInfo &Info) {
- LAngleLoc = Info.getLAngleLoc();
- RAngleLoc = Info.getRAngleLoc();
- NumTemplateArgs = Info.size();
-
- TemplateArgumentLoc *ArgBuffer = getTemplateArgs();
- for (unsigned i = 0; i != NumTemplateArgs; ++i)
- new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]);
-}
-
-void ExplicitTemplateArgumentList::initializeFrom(
- const TemplateArgumentListInfo &Info,
- bool &Dependent,
- bool &InstantiationDependent,
- bool &ContainsUnexpandedParameterPack) {
- LAngleLoc = Info.getLAngleLoc();
- RAngleLoc = Info.getRAngleLoc();
- NumTemplateArgs = Info.size();
-
- TemplateArgumentLoc *ArgBuffer = getTemplateArgs();
- for (unsigned i = 0; i != NumTemplateArgs; ++i) {
- Dependent = Dependent || Info[i].getArgument().isDependent();
- InstantiationDependent = InstantiationDependent ||
- Info[i].getArgument().isInstantiationDependent();
- ContainsUnexpandedParameterPack
- = ContainsUnexpandedParameterPack ||
- Info[i].getArgument().containsUnexpandedParameterPack();
-
- new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]);
- }
-}
-
-void ExplicitTemplateArgumentList::copyInto(
- TemplateArgumentListInfo &Info) const {
- Info.setLAngleLoc(LAngleLoc);
- Info.setRAngleLoc(RAngleLoc);
- for (unsigned I = 0; I != NumTemplateArgs; ++I)
- Info.addArgument(getTemplateArgs()[I]);
-}
-
-std::size_t ExplicitTemplateArgumentList::sizeFor(unsigned NumTemplateArgs) {
- return sizeof(ExplicitTemplateArgumentList) +
- sizeof(TemplateArgumentLoc) * NumTemplateArgs;
-}
-
-std::size_t ExplicitTemplateArgumentList::sizeFor(
- const TemplateArgumentListInfo &Info) {
- return sizeFor(Info.size());
-}
-
/// \brief Compute the type-, value-, and instantiation-dependence of a
/// declaration reference
/// based on the declaration being referenced.
@@ -325,7 +274,8 @@ DeclRefExpr::DeclRefExpr(NestedNameSpecifierLoc QualifierLoc,
if (InstantiationDependent)
setInstantiationDependent(true);
}
-
+ DeclRefExprBits.HadMultipleCandidates = 0;
+
computeDependence();
}
@@ -360,7 +310,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
if (FoundD)
Size += sizeof(NamedDecl *);
if (TemplateArgs)
- Size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs);
+ Size += ASTTemplateArgumentListInfo::sizeFor(*TemplateArgs);
void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>());
return new (Mem) DeclRefExpr(QualifierLoc, D, NameInfo, FoundD, TemplateArgs,
@@ -378,7 +328,7 @@ DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context,
if (HasFoundDecl)
Size += sizeof(NamedDecl *);
if (HasExplicitTemplateArgs)
- Size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs);
+ Size += ASTTemplateArgumentListInfo::sizeFor(NumTemplateArgs);
void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>());
return new (Mem) DeclRefExpr(EmptyShell());
@@ -463,7 +413,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
// For incorrect code, there might not be an ObjCInterfaceDecl. Do
// a null check to avoid a crash.
if (const ObjCInterfaceDecl *ID = MD->getClassInterface())
- Out << ID;
+ Out << *ID;
if (const ObjCCategoryImplDecl *CID =
dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext()))
@@ -532,9 +482,8 @@ double FloatingLiteral::getValueAsApproximateDouble() const {
return V.convertToDouble();
}
-StringLiteral *StringLiteral::Create(ASTContext &C, llvm::StringRef Str,
- bool Wide,
- bool Pascal, QualType Ty,
+StringLiteral *StringLiteral::Create(ASTContext &C, StringRef Str,
+ StringKind Kind, bool Pascal, QualType Ty,
const SourceLocation *Loc,
unsigned NumStrs) {
// Allocate enough space for the StringLiteral plus an array of locations for
@@ -549,7 +498,7 @@ StringLiteral *StringLiteral::Create(ASTContext &C, llvm::StringRef Str,
memcpy(AStrData, Str.data(), Str.size());
SL->StrData = AStrData;
SL->ByteLength = Str.size();
- SL->IsWide = Wide;
+ SL->Kind = Kind;
SL->IsPascal = Pascal;
SL->TokLocs[0] = Loc[0];
SL->NumConcatenated = NumStrs;
@@ -570,7 +519,7 @@ StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) {
return SL;
}
-void StringLiteral::setString(ASTContext &C, llvm::StringRef Str) {
+void StringLiteral::setString(ASTContext &C, StringRef Str) {
char *AStrData = new (C, 1) char[Str.size()];
memcpy(AStrData, Str.data(), Str.size());
StrData = AStrData;
@@ -587,8 +536,8 @@ void StringLiteral::setString(ASTContext &C, llvm::StringRef Str) {
SourceLocation StringLiteral::
getLocationOfByte(unsigned ByteNo, const SourceManager &SM,
const LangOptions &Features, const TargetInfo &Target) const {
- assert(!isWide() && "This doesn't work for wide strings yet");
-
+ assert(Kind == StringLiteral::Ascii && "This only works for ASCII strings");
+
// Loop over all of the tokens in this string until we find the one that
// contains the byte we're looking for.
unsigned TokNo = 0;
@@ -604,7 +553,7 @@ getLocationOfByte(unsigned ByteNo, const SourceManager &SM,
// Re-lex the token to get its length and original spelling.
std::pair<FileID, unsigned> LocInfo =SM.getDecomposedLoc(StrTokSpellingLoc);
bool Invalid = false;
- llvm::StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
+ StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
if (Invalid)
return StrTokSpellingLoc;
@@ -647,7 +596,7 @@ getLocationOfByte(unsigned ByteNo, const SourceManager &SM,
/// corresponds to, e.g. "sizeof" or "[pre]++".
const char *UnaryOperator::getOpcodeStr(Opcode Op) {
switch (Op) {
- default: assert(0 && "Unknown unary operator");
+ default: llvm_unreachable("Unknown unary operator");
case UO_PostInc: return "++";
case UO_PostDec: return "--";
case UO_PreInc: return "++";
@@ -667,7 +616,7 @@ const char *UnaryOperator::getOpcodeStr(Opcode Op) {
UnaryOperatorKind
UnaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix) {
switch (OO) {
- default: assert(false && "No unary operator for overloaded function");
+ default: llvm_unreachable("No unary operator for overloaded function");
case OO_PlusPlus: return Postfix ? UO_PostInc : UO_PreInc;
case OO_MinusMinus: return Postfix ? UO_PostDec : UO_PreDec;
case OO_Amp: return UO_AddrOf;
@@ -771,7 +720,13 @@ CallExpr::CallExpr(ASTContext &C, StmtClass SC, unsigned NumPreArgs,
}
Decl *CallExpr::getCalleeDecl() {
- Expr *CEE = getCallee()->IgnoreParenCasts();
+ Expr *CEE = getCallee()->IgnoreParenImpCasts();
+
+ while (SubstNonTypeTemplateParmExpr *NTTP
+ = dyn_cast<SubstNonTypeTemplateParmExpr>(CEE)) {
+ CEE = NTTP->getReplacement()->IgnoreParenCasts();
+ }
+
// If we're calling a dereference, look at the pointer instead.
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(CEE)) {
if (BO->isPtrMemOp())
@@ -947,7 +902,7 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
Size += sizeof(MemberNameQualifier);
if (targs)
- Size += ExplicitTemplateArgumentList::sizeFor(*targs);
+ Size += ASTTemplateArgumentListInfo::sizeFor(*targs);
void *Mem = C.Allocate(Size, llvm::alignOf<MemberExpr>());
MemberExpr *E = new (Mem) MemberExpr(base, isarrow, memberdecl, nameinfo,
@@ -1008,6 +963,94 @@ SourceRange MemberExpr::getSourceRange() const {
return SourceRange(StartLoc, EndLoc);
}
+void CastExpr::CheckCastConsistency() const {
+ switch (getCastKind()) {
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase:
+ case CK_DerivedToBaseMemberPointer:
+ case CK_BaseToDerived:
+ case CK_BaseToDerivedMemberPointer:
+ assert(!path_empty() && "Cast kind should have a base path!");
+ break;
+
+ case CK_CPointerToObjCPointerCast:
+ assert(getType()->isObjCObjectPointerType());
+ assert(getSubExpr()->getType()->isPointerType());
+ goto CheckNoBasePath;
+
+ case CK_BlockPointerToObjCPointerCast:
+ assert(getType()->isObjCObjectPointerType());
+ assert(getSubExpr()->getType()->isBlockPointerType());
+ goto CheckNoBasePath;
+
+ case CK_BitCast:
+ // Arbitrary casts to C pointer types count as bitcasts.
+ // Otherwise, we should only have block and ObjC pointer casts
+ // here if they stay within the type kind.
+ if (!getType()->isPointerType()) {
+ assert(getType()->isObjCObjectPointerType() ==
+ getSubExpr()->getType()->isObjCObjectPointerType());
+ assert(getType()->isBlockPointerType() ==
+ getSubExpr()->getType()->isBlockPointerType());
+ }
+ goto CheckNoBasePath;
+
+ case CK_AnyPointerToBlockPointerCast:
+ assert(getType()->isBlockPointerType());
+ assert(getSubExpr()->getType()->isAnyPointerType() &&
+ !getSubExpr()->getType()->isBlockPointerType());
+ goto CheckNoBasePath;
+
+ // These should not have an inheritance path.
+ case CK_Dynamic:
+ case CK_ToUnion:
+ case CK_ArrayToPointerDecay:
+ case CK_FunctionToPointerDecay:
+ case CK_NullToMemberPointer:
+ case CK_NullToPointer:
+ case CK_ConstructorConversion:
+ case CK_IntegralToPointer:
+ case CK_PointerToIntegral:
+ case CK_ToVoid:
+ case CK_VectorSplat:
+ case CK_IntegralCast:
+ case CK_IntegralToFloating:
+ case CK_FloatingToIntegral:
+ case CK_FloatingCast:
+ case CK_ObjCObjectLValueCast:
+ case CK_FloatingRealToComplex:
+ case CK_FloatingComplexToReal:
+ case CK_FloatingComplexCast:
+ case CK_FloatingComplexToIntegralComplex:
+ case CK_IntegralRealToComplex:
+ case CK_IntegralComplexToReal:
+ case CK_IntegralComplexCast:
+ case CK_IntegralComplexToFloatingComplex:
+ case CK_ARCProduceObject:
+ case CK_ARCConsumeObject:
+ case CK_ARCReclaimReturnedObject:
+ case CK_ARCExtendBlockObject:
+ assert(!getType()->isBooleanType() && "unheralded conversion to bool");
+ goto CheckNoBasePath;
+
+ case CK_Dependent:
+ case CK_LValueToRValue:
+ case CK_GetObjCProperty:
+ case CK_NoOp:
+ case CK_PointerToBoolean:
+ case CK_IntegralToBoolean:
+ case CK_FloatingToBoolean:
+ case CK_MemberPointerToBoolean:
+ case CK_FloatingComplexToBoolean:
+ case CK_IntegralComplexToBoolean:
+ case CK_LValueBitCast: // -> bool&
+ case CK_UserDefinedConversion: // operator bool()
+ CheckNoBasePath:
+ assert(path_empty() && "Cast kind should not have a base path!");
+ break;
+ }
+}
+
const char *CastExpr::getCastKindName() const {
switch (getCastKind()) {
case CK_Dependent:
@@ -1072,8 +1115,10 @@ const char *CastExpr::getCastKindName() const {
return "FloatingToBoolean";
case CK_MemberPointerToBoolean:
return "MemberPointerToBoolean";
- case CK_AnyPointerToObjCPointerCast:
- return "AnyPointerToObjCPointerCast";
+ case CK_CPointerToObjCPointerCast:
+ return "CPointerToObjCPointerCast";
+ case CK_BlockPointerToObjCPointerCast:
+ return "BlockPointerToObjCPointerCast";
case CK_AnyPointerToBlockPointerCast:
return "AnyPointerToBlockPointerCast";
case CK_ObjCObjectLValueCast:
@@ -1098,12 +1143,14 @@ const char *CastExpr::getCastKindName() const {
return "IntegralComplexCast";
case CK_IntegralComplexToFloatingComplex:
return "IntegralComplexToFloatingComplex";
- case CK_ObjCConsumeObject:
- return "ObjCConsumeObject";
- case CK_ObjCProduceObject:
- return "ObjCProduceObject";
- case CK_ObjCReclaimReturnedObject:
- return "ObjCReclaimReturnedObject";
+ case CK_ARCConsumeObject:
+ return "ARCConsumeObject";
+ case CK_ARCProduceObject:
+ return "ARCProduceObject";
+ case CK_ARCReclaimReturnedObject:
+ return "ARCReclaimReturnedObject";
+ case CK_ARCExtendBlockObject:
+ return "ARCCExtendBlockObject";
}
llvm_unreachable("Unhandled cast kind!");
@@ -1243,7 +1290,7 @@ const char *BinaryOperator::getOpcodeStr(Opcode Op) {
BinaryOperatorKind
BinaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO) {
switch (OO) {
- default: assert(false && "Not an overloadable binary operator");
+ default: llvm_unreachable("Not an overloadable binary operator");
case OO_Plus: return BO_Add;
case OO_Minus: return BO_Sub;
case OO_Star: return BO_Mul;
@@ -1491,6 +1538,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
}
case CompoundAssignOperatorClass:
case VAArgExprClass:
+ case AtomicExprClass:
return false;
case ConditionalOperatorClass: {
@@ -1525,8 +1573,24 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
R2 = cast<ArraySubscriptExpr>(this)->getRHS()->getSourceRange();
return true;
+ case CXXOperatorCallExprClass: {
+ // We warn about operator== and operator!= even when user-defined operator
+ // overloads as there is no reasonable way to define these such that they
+ // have non-trivial, desirable side-effects. See the -Wunused-comparison
+ // warning: these operators are commonly typo'ed, and so warning on them
+ // provides additional value as well. If this list is updated,
+ // DiagnoseUnusedComparison should be as well.
+ const CXXOperatorCallExpr *Op = cast<CXXOperatorCallExpr>(this);
+ if (Op->getOperator() == OO_EqualEqual ||
+ Op->getOperator() == OO_ExclaimEqual) {
+ Loc = Op->getOperatorLoc();
+ R1 = Op->getSourceRange();
+ return true;
+ }
+
+ // Fallthrough for generic call handling.
+ }
case CallExprClass:
- case CXXOperatorCallExprClass:
case CXXMemberCallExprClass: {
// If this is a direct call, get the callee.
const CallExpr *CE = cast<CallExpr>(this);
@@ -1666,8 +1730,15 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const {
->isOBJCGCCandidate(Ctx);
case CStyleCastExprClass:
return cast<CStyleCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
+ case BlockDeclRefExprClass:
case DeclRefExprClass: {
- const Decl *D = cast<DeclRefExpr>(E)->getDecl();
+
+ const Decl *D;
+ if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E))
+ D = BDRE->getDecl();
+ else
+ D = cast<DeclRefExpr>(E)->getDecl();
+
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (VD->hasGlobalStorage())
return true;
@@ -2024,7 +2095,11 @@ Expr *Expr::IgnoreParenCasts() {
E = Materialize->GetTemporaryExpr();
continue;
}
-
+ if (SubstNonTypeTemplateParmExpr *NTTP
+ = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) {
+ E = NTTP->getReplacement();
+ continue;
+ }
return E;
}
}
@@ -2058,6 +2133,10 @@ Expr *Expr::IgnoreParenLValueCasts() {
= dyn_cast<MaterializeTemporaryExpr>(E)) {
E = Materialize->GetTemporaryExpr();
continue;
+ } else if (SubstNonTypeTemplateParmExpr *NTTP
+ = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) {
+ E = NTTP->getReplacement();
+ continue;
}
break;
}
@@ -2092,6 +2171,11 @@ Expr *Expr::IgnoreParenImpCasts() {
E = Materialize->GetTemporaryExpr();
continue;
}
+ if (SubstNonTypeTemplateParmExpr *NTTP
+ = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) {
+ E = NTTP->getReplacement();
+ continue;
+ }
return E;
}
}
@@ -2149,6 +2233,12 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
}
}
+ if (SubstNonTypeTemplateParmExpr *NTTP
+ = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) {
+ E = NTTP->getReplacement();
+ continue;
+ }
+
return E;
}
}
@@ -2397,7 +2487,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
break;
case MaterializeTemporaryExprClass:
- return llvm::cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr()
+ return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr()
->isConstantInitializer(Ctx, false);
}
return isEvaluatable(Ctx);
@@ -2414,9 +2504,7 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
if (isValueDependent()) {
switch (NPC) {
case NPC_NeverValueDependent:
- assert(false && "Unexpected value dependent expression!");
- // If the unthinkable happens, fall through to the safest alternative.
-
+ llvm_unreachable("Unexpected value dependent expression!");
case NPC_ValueDependentIsNull:
if (isTypeDependent() || getType()->isIntegralType(Ctx))
return NPCK_ZeroInteger;
@@ -2576,7 +2664,7 @@ unsigned ExtVectorElementExpr::getNumElements() const {
bool ExtVectorElementExpr::containsDuplicateElements() const {
// FIXME: Refactor this code to an accessor on the AST node which returns the
// "type" of component access, and share with code below and in Sema.
- llvm::StringRef Comp = Accessor->getName();
+ StringRef Comp = Accessor->getName();
// Halving swizzles do not contain duplicate elements.
if (Comp == "hi" || Comp == "lo" || Comp == "even" || Comp == "odd")
@@ -2587,7 +2675,7 @@ bool ExtVectorElementExpr::containsDuplicateElements() const {
Comp = Comp.substr(1);
for (unsigned i = 0, e = Comp.size(); i != e; ++i)
- if (Comp.substr(i + 1).find(Comp[i]) != llvm::StringRef::npos)
+ if (Comp.substr(i + 1).find(Comp[i]) != StringRef::npos)
return true;
return false;
@@ -2595,8 +2683,8 @@ bool ExtVectorElementExpr::containsDuplicateElements() const {
/// getEncodedElementAccess - We encode the fields as a llvm ConstantArray.
void ExtVectorElementExpr::getEncodedElementAccess(
- llvm::SmallVectorImpl<unsigned> &Elts) const {
- llvm::StringRef Comp = Accessor->getName();
+ SmallVectorImpl<unsigned> &Elts) const {
+ StringRef Comp = Accessor->getName();
if (Comp[0] == 's' || Comp[0] == 'S')
Comp = Comp.substr(1);
@@ -2630,23 +2718,23 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
bool IsInstanceSuper,
QualType SuperType,
Selector Sel,
- SourceLocation SelLoc,
+ ArrayRef<SourceLocation> SelLocs,
+ SelectorLocationsKind SelLocsK,
ObjCMethodDecl *Method,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr *> Args,
SourceLocation RBracLoc)
: Expr(ObjCMessageExprClass, T, VK, OK_Ordinary,
/*TypeDependent=*/false, /*ValueDependent=*/false,
/*InstantiationDependent=*/false,
/*ContainsUnexpandedParameterPack=*/false),
- NumArgs(NumArgs), Kind(IsInstanceSuper? SuperInstance : SuperClass),
- HasMethod(Method != 0), IsDelegateInitCall(false), SuperLoc(SuperLoc),
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
: Sel.getAsOpaquePtr())),
- SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc)
+ Kind(IsInstanceSuper? SuperInstance : SuperClass),
+ HasMethod(Method != 0), IsDelegateInitCall(false), SuperLoc(SuperLoc),
+ LBracLoc(LBracLoc), RBracLoc(RBracLoc)
{
+ initArgsAndSelLocs(Args, SelLocs, SelLocsK);
setReceiverPointer(SuperType.getAsOpaquePtr());
- if (NumArgs)
- memcpy(getArgs(), Args, NumArgs * sizeof(Expr *));
}
ObjCMessageExpr::ObjCMessageExpr(QualType T,
@@ -2654,33 +2742,22 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
SourceLocation LBracLoc,
TypeSourceInfo *Receiver,
Selector Sel,
- SourceLocation SelLoc,
+ ArrayRef<SourceLocation> SelLocs,
+ SelectorLocationsKind SelLocsK,
ObjCMethodDecl *Method,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr *> Args,
SourceLocation RBracLoc)
: Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, T->isDependentType(),
T->isDependentType(), T->isInstantiationDependentType(),
T->containsUnexpandedParameterPack()),
- NumArgs(NumArgs), Kind(Class),
- HasMethod(Method != 0), IsDelegateInitCall(false),
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
: Sel.getAsOpaquePtr())),
- SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc)
+ Kind(Class),
+ HasMethod(Method != 0), IsDelegateInitCall(false),
+ LBracLoc(LBracLoc), RBracLoc(RBracLoc)
{
+ initArgsAndSelLocs(Args, SelLocs, SelLocsK);
setReceiverPointer(Receiver);
- Expr **MyArgs = getArgs();
- for (unsigned I = 0; I != NumArgs; ++I) {
- if (Args[I]->isTypeDependent())
- ExprBits.TypeDependent = true;
- if (Args[I]->isValueDependent())
- ExprBits.ValueDependent = true;
- if (Args[I]->isInstantiationDependent())
- ExprBits.InstantiationDependent = true;
- if (Args[I]->containsUnexpandedParameterPack())
- ExprBits.ContainsUnexpandedParameterPack = true;
-
- MyArgs[I] = Args[I];
- }
}
ObjCMessageExpr::ObjCMessageExpr(QualType T,
@@ -2688,23 +2765,31 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
SourceLocation LBracLoc,
Expr *Receiver,
Selector Sel,
- SourceLocation SelLoc,
+ ArrayRef<SourceLocation> SelLocs,
+ SelectorLocationsKind SelLocsK,
ObjCMethodDecl *Method,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr *> Args,
SourceLocation RBracLoc)
: Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, Receiver->isTypeDependent(),
Receiver->isTypeDependent(),
Receiver->isInstantiationDependent(),
Receiver->containsUnexpandedParameterPack()),
- NumArgs(NumArgs), Kind(Instance),
- HasMethod(Method != 0), IsDelegateInitCall(false),
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
: Sel.getAsOpaquePtr())),
- SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc)
+ Kind(Instance),
+ HasMethod(Method != 0), IsDelegateInitCall(false),
+ LBracLoc(LBracLoc), RBracLoc(RBracLoc)
{
+ initArgsAndSelLocs(Args, SelLocs, SelLocsK);
setReceiverPointer(Receiver);
+}
+
+void ObjCMessageExpr::initArgsAndSelLocs(ArrayRef<Expr *> Args,
+ ArrayRef<SourceLocation> SelLocs,
+ SelectorLocationsKind SelLocsK) {
+ setNumArgs(Args.size());
Expr **MyArgs = getArgs();
- for (unsigned I = 0; I != NumArgs; ++I) {
+ for (unsigned I = 0; I != Args.size(); ++I) {
if (Args[I]->isTypeDependent())
ExprBits.TypeDependent = true;
if (Args[I]->isValueDependent())
@@ -2716,6 +2801,10 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
MyArgs[I] = Args[I];
}
+
+ SelLocsKind = SelLocsK;
+ if (SelLocsK == SelLoc_NonStandard)
+ std::copy(SelLocs.begin(), SelLocs.end(), getStoredSelLocs());
}
ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
@@ -2725,16 +2814,15 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
bool IsInstanceSuper,
QualType SuperType,
Selector Sel,
- SourceLocation SelLoc,
+ ArrayRef<SourceLocation> SelLocs,
ObjCMethodDecl *Method,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr *> Args,
SourceLocation RBracLoc) {
- unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
- NumArgs * sizeof(Expr *);
- void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
+ SelectorLocationsKind SelLocsK;
+ ObjCMessageExpr *Mem = alloc(Context, Args, RBracLoc, SelLocs, Sel, SelLocsK);
return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, SuperLoc, IsInstanceSuper,
- SuperType, Sel, SelLoc, Method, Args,NumArgs,
- RBracLoc);
+ SuperType, Sel, SelLocs, SelLocsK,
+ Method, Args, RBracLoc);
}
ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
@@ -2742,15 +2830,14 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
SourceLocation LBracLoc,
TypeSourceInfo *Receiver,
Selector Sel,
- SourceLocation SelLoc,
+ ArrayRef<SourceLocation> SelLocs,
ObjCMethodDecl *Method,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr *> Args,
SourceLocation RBracLoc) {
- unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
- NumArgs * sizeof(Expr *);
- void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
- return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, Receiver, Sel, SelLoc,
- Method, Args, NumArgs, RBracLoc);
+ SelectorLocationsKind SelLocsK;
+ ObjCMessageExpr *Mem = alloc(Context, Args, RBracLoc, SelLocs, Sel, SelLocsK);
+ return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, Receiver, Sel,
+ SelLocs, SelLocsK, Method, Args, RBracLoc);
}
ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
@@ -2758,25 +2845,50 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
SourceLocation LBracLoc,
Expr *Receiver,
Selector Sel,
- SourceLocation SelLoc,
+ ArrayRef<SourceLocation> SelLocs,
ObjCMethodDecl *Method,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr *> Args,
SourceLocation RBracLoc) {
- unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
- NumArgs * sizeof(Expr *);
- void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
- return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, Receiver, Sel, SelLoc,
- Method, Args, NumArgs, RBracLoc);
+ SelectorLocationsKind SelLocsK;
+ ObjCMessageExpr *Mem = alloc(Context, Args, RBracLoc, SelLocs, Sel, SelLocsK);
+ return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, Receiver, Sel,
+ SelLocs, SelLocsK, Method, Args, RBracLoc);
}
ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(ASTContext &Context,
- unsigned NumArgs) {
- unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
- NumArgs * sizeof(Expr *);
- void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
+ unsigned NumArgs,
+ unsigned NumStoredSelLocs) {
+ ObjCMessageExpr *Mem = alloc(Context, NumArgs, NumStoredSelLocs);
return new (Mem) ObjCMessageExpr(EmptyShell(), NumArgs);
}
+ObjCMessageExpr *ObjCMessageExpr::alloc(ASTContext &C,
+ ArrayRef<Expr *> Args,
+ SourceLocation RBraceLoc,
+ ArrayRef<SourceLocation> SelLocs,
+ Selector Sel,
+ SelectorLocationsKind &SelLocsK) {
+ SelLocsK = hasStandardSelectorLocs(Sel, SelLocs, Args, RBraceLoc);
+ unsigned NumStoredSelLocs = (SelLocsK == SelLoc_NonStandard) ? SelLocs.size()
+ : 0;
+ return alloc(C, Args.size(), NumStoredSelLocs);
+}
+
+ObjCMessageExpr *ObjCMessageExpr::alloc(ASTContext &C,
+ unsigned NumArgs,
+ unsigned NumStoredSelLocs) {
+ unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
+ NumArgs * sizeof(Expr *) + NumStoredSelLocs * sizeof(SourceLocation);
+ return (ObjCMessageExpr *)C.Allocate(Size,
+ llvm::AlignOf<ObjCMessageExpr>::Alignment);
+}
+
+void ObjCMessageExpr::getSelectorLocs(
+ SmallVectorImpl<SourceLocation> &SelLocs) const {
+ for (unsigned i = 0, e = getNumSelectorLocs(); i != e; ++i)
+ SelLocs.push_back(getSelectorLoc(i));
+}
+
SourceRange ObjCMessageExpr::getReceiverRange() const {
switch (getReceiverKind()) {
case Instance:
@@ -2830,7 +2942,7 @@ ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const {
return 0;
}
-llvm::StringRef ObjCBridgedCastExpr::getBridgeKindName() const {
+StringRef ObjCBridgedCastExpr::getBridgeKindName() const {
switch (getBridgeKind()) {
case OBC_Bridge:
return "__bridge";
@@ -2844,7 +2956,7 @@ llvm::StringRef ObjCBridgedCastExpr::getBridgeKindName() const {
}
bool ChooseExpr::isConditionTrue(const ASTContext &C) const {
- return getCond()->EvaluateAsInt(C) != 0;
+ return getCond()->EvaluateKnownConstInt(C) != 0;
}
ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, Expr **args, unsigned nexpr,
@@ -3203,3 +3315,24 @@ BlockDeclRefExpr::BlockDeclRefExpr(VarDecl *d, QualType t, ExprValueKind VK,
ExprBits.ValueDependent = ValueDependent;
ExprBits.InstantiationDependent = InstantiationDependent;
}
+
+
+AtomicExpr::AtomicExpr(SourceLocation BLoc, Expr **args, unsigned nexpr,
+ QualType t, AtomicOp op, SourceLocation RP)
+ : Expr(AtomicExprClass, t, VK_RValue, OK_Ordinary,
+ false, false, false, false),
+ NumSubExprs(nexpr), BuiltinLoc(BLoc), RParenLoc(RP), Op(op)
+{
+ for (unsigned i = 0; i < nexpr; i++) {
+ if (args[i]->isTypeDependent())
+ ExprBits.TypeDependent = true;
+ if (args[i]->isValueDependent())
+ ExprBits.ValueDependent = true;
+ if (args[i]->isInstantiationDependent())
+ ExprBits.InstantiationDependent = true;
+ if (args[i]->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
+
+ SubExprs[i] = args[i];
+ }
+}
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index f92afffb5851..ad5ec8b8331a 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -49,6 +49,7 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
SourceRange TypeIdParens, Expr *arraySize,
CXXConstructorDecl *constructor, bool initializer,
Expr **constructorArgs, unsigned numConsArgs,
+ bool HadMultipleCandidates,
FunctionDecl *operatorDelete,
bool usualArrayDeleteWantsSize, QualType ty,
TypeSourceInfo *AllocatedTypeInfo,
@@ -61,6 +62,7 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
ty->containsUnexpandedParameterPack()),
GlobalNew(globalNew), Initializer(initializer),
UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize),
+ HadMultipleCandidates(HadMultipleCandidates),
SubExprs(0), OperatorNew(operatorNew),
OperatorDelete(operatorDelete), Constructor(constructor),
AllocatedTypeInfo(AllocatedTypeInfo), TypeIdParens(TypeIdParens),
@@ -202,7 +204,7 @@ UnresolvedLookupExpr::Create(ASTContext &C,
UnresolvedSetIterator End)
{
void *Mem = C.Allocate(sizeof(UnresolvedLookupExpr) +
- ExplicitTemplateArgumentList::sizeFor(Args));
+ ASTTemplateArgumentListInfo::sizeFor(Args));
return new (Mem) UnresolvedLookupExpr(C, NamingClass, QualifierLoc, NameInfo,
ADL, /*Overload*/ true, &Args,
Begin, End, /*StdIsAssociated=*/false);
@@ -213,7 +215,7 @@ UnresolvedLookupExpr::CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs,
unsigned NumTemplateArgs) {
std::size_t size = sizeof(UnresolvedLookupExpr);
if (HasExplicitTemplateArgs)
- size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs);
+ size += ASTTemplateArgumentListInfo::sizeFor(NumTemplateArgs);
void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedLookupExpr>());
UnresolvedLookupExpr *E = new (Mem) UnresolvedLookupExpr(EmptyShell());
@@ -332,7 +334,7 @@ DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(QualType T,
bool ContainsUnexpandedParameterPack
= ExprBits.ContainsUnexpandedParameterPack;
- reinterpret_cast<ExplicitTemplateArgumentList*>(this+1)
+ reinterpret_cast<ASTTemplateArgumentListInfo*>(this+1)
->initializeFrom(*Args, Dependent, InstantiationDependent,
ContainsUnexpandedParameterPack);
@@ -347,7 +349,7 @@ DependentScopeDeclRefExpr::Create(ASTContext &C,
const TemplateArgumentListInfo *Args) {
std::size_t size = sizeof(DependentScopeDeclRefExpr);
if (Args)
- size += ExplicitTemplateArgumentList::sizeFor(*Args);
+ size += ASTTemplateArgumentListInfo::sizeFor(*Args);
void *Mem = C.Allocate(size);
return new (Mem) DependentScopeDeclRefExpr(C.DependentTy, QualifierLoc,
NameInfo, Args);
@@ -359,7 +361,7 @@ DependentScopeDeclRefExpr::CreateEmpty(ASTContext &C,
unsigned NumTemplateArgs) {
std::size_t size = sizeof(DependentScopeDeclRefExpr);
if (HasExplicitTemplateArgs)
- size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs);
+ size += ASTTemplateArgumentListInfo::sizeFor(NumTemplateArgs);
void *Mem = C.Allocate(size);
DependentScopeDeclRefExpr *E
= new (Mem) DependentScopeDeclRefExpr(QualType(), NestedNameSpecifierLoc(),
@@ -628,11 +630,13 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
Expr **Args,
unsigned NumArgs,
SourceRange parenRange,
+ bool HadMultipleCandidates,
bool ZeroInitialization)
: CXXConstructExpr(C, CXXTemporaryObjectExprClass,
Type->getType().getNonReferenceType(),
Type->getTypeLoc().getBeginLoc(),
- Cons, false, Args, NumArgs, ZeroInitialization,
+ Cons, false, Args, NumArgs,
+ HadMultipleCandidates, ZeroInitialization,
CXXConstructExpr::CK_Complete, parenRange),
Type(Type) {
}
@@ -646,11 +650,13 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool Elidable,
Expr **Args, unsigned NumArgs,
+ bool HadMultipleCandidates,
bool ZeroInitialization,
ConstructionKind ConstructKind,
SourceRange ParenRange) {
return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D,
- Elidable, Args, NumArgs, ZeroInitialization,
+ Elidable, Args, NumArgs,
+ HadMultipleCandidates, ZeroInitialization,
ConstructKind, ParenRange);
}
@@ -658,16 +664,18 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool elidable,
Expr **args, unsigned numargs,
- bool ZeroInitialization,
+ bool HadMultipleCandidates,
+ bool ZeroInitialization,
ConstructionKind ConstructKind,
SourceRange ParenRange)
: Expr(SC, T, VK_RValue, OK_Ordinary,
T->isDependentType(), T->isDependentType(),
T->isInstantiationDependentType(),
T->containsUnexpandedParameterPack()),
- Constructor(D), Loc(Loc), ParenRange(ParenRange), Elidable(elidable),
- ZeroInitialization(ZeroInitialization), ConstructKind(ConstructKind),
- Args(0), NumArgs(numargs)
+ Constructor(D), Loc(Loc), ParenRange(ParenRange), NumArgs(numargs),
+ Elidable(elidable), HadMultipleCandidates(HadMultipleCandidates),
+ ZeroInitialization(ZeroInitialization),
+ ConstructKind(ConstructKind), Args(0)
{
if (NumArgs) {
Args = new (C) Stmt*[NumArgs];
@@ -838,7 +846,7 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C,
std::size_t size = sizeof(CXXDependentScopeMemberExpr);
if (TemplateArgs)
- size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs);
+ size += ASTTemplateArgumentListInfo::sizeFor(*TemplateArgs);
void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>());
return new (Mem) CXXDependentScopeMemberExpr(C, Base, BaseType,
@@ -859,7 +867,7 @@ CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C,
DeclarationNameInfo());
std::size_t size = sizeof(CXXDependentScopeMemberExpr) +
- ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs);
+ ASTTemplateArgumentListInfo::sizeFor(NumTemplateArgs);
void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>());
CXXDependentScopeMemberExpr *E
= new (Mem) CXXDependentScopeMemberExpr(C, 0, QualType(),
@@ -947,7 +955,7 @@ UnresolvedMemberExpr::Create(ASTContext &C,
UnresolvedSetIterator End) {
std::size_t size = sizeof(UnresolvedMemberExpr);
if (TemplateArgs)
- size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs);
+ size += ASTTemplateArgumentListInfo::sizeFor(*TemplateArgs);
void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedMemberExpr>());
return new (Mem) UnresolvedMemberExpr(C,
@@ -961,7 +969,7 @@ UnresolvedMemberExpr::CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs,
unsigned NumTemplateArgs) {
std::size_t size = sizeof(UnresolvedMemberExpr);
if (HasExplicitTemplateArgs)
- size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs);
+ size += ASTTemplateArgumentListInfo::sizeFor(NumTemplateArgs);
void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedMemberExpr>());
UnresolvedMemberExpr *E = new (Mem) UnresolvedMemberExpr(EmptyShell());
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index e7888a6aa7b3..49c68213aa43 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -162,6 +162,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::SubstNonTypeTemplateParmPackExprClass:
case Expr::AsTypeExprClass:
case Expr::ObjCIndirectCopyRestoreExprClass:
+ case Expr::AtomicExprClass:
return Cl::CL_PRValue;
// Next come the complicated cases.
@@ -393,7 +394,7 @@ static Cl::Kinds ClassifyUnnamed(ASTContext &Ctx, QualType T) {
// C++ [expr.call]p10: A function call is an lvalue if the result type is an
// lvalue reference type or an rvalue reference to function type, an xvalue
- // if the result type is an rvalue refernence to object type, and a prvalue
+ // if the result type is an rvalue reference to object type, and a prvalue
// otherwise.
if (T->isLValueReferenceType())
return Cl::CL_LValue;
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 786155af281d..df75bc8a735f 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -59,6 +59,8 @@ namespace {
EvalInfo(const ASTContext &ctx, Expr::EvalResult &evalresult)
: Ctx(ctx), EvalResult(evalresult) {}
+
+ const LangOptions &getLangOpts() { return Ctx.getLangOptions(); }
};
struct ComplexValue {
@@ -378,18 +380,22 @@ private:
RetTy DerivedError(const Expr *E) {
return static_cast<Derived*>(this)->Error(E);
}
+ RetTy DerivedValueInitialization(const Expr *E) {
+ return static_cast<Derived*>(this)->ValueInitialization(E);
+ }
protected:
EvalInfo &Info;
typedef ConstStmtVisitor<Derived, RetTy> StmtVisitorTy;
typedef ExprEvaluatorBase ExprEvaluatorBaseTy;
+ RetTy ValueInitialization(const Expr *E) { return DerivedError(E); }
+
public:
ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {}
RetTy VisitStmt(const Stmt *) {
- assert(0 && "Expression evaluator should not be called on stmts");
- return DerivedError(0);
+ llvm_unreachable("Expression evaluator should not be called on stmts");
}
RetTy VisitExpr(const Expr *E) {
return DerivedError(E);
@@ -436,6 +442,23 @@ public:
: DerivedError(E));
return DerivedSuccess(*value, E);
}
+
+ RetTy VisitInitListExpr(const InitListExpr *E) {
+ if (Info.getLangOpts().CPlusPlus0x) {
+ if (E->getNumInits() == 0)
+ return DerivedValueInitialization(E);
+ if (E->getNumInits() == 1)
+ return StmtVisitorTy::Visit(E->getInit(0));
+ }
+ return DerivedError(E);
+ }
+ RetTy VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
+ return DerivedValueInitialization(E);
+ }
+ RetTy VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) {
+ return DerivedValueInitialization(E);
+ }
+
};
}
@@ -447,6 +470,7 @@ namespace {
class LValueExprEvaluator
: public ExprEvaluatorBase<LValueExprEvaluator, bool> {
LValue &Result;
+ const Decl *PrevDecl;
bool Success(const Expr *E) {
Result.Base = E;
@@ -456,7 +480,7 @@ class LValueExprEvaluator
public:
LValueExprEvaluator(EvalInfo &info, LValue &Result) :
- ExprEvaluatorBaseTy(info), Result(Result) {}
+ ExprEvaluatorBaseTy(info), Result(Result), PrevDecl(0) {}
bool Success(const APValue &V, const Expr *E) {
Result.setFrom(V);
@@ -481,9 +505,13 @@ public:
return false;
case CK_NoOp:
+ case CK_LValueBitCast:
return Visit(E->getSubExpr());
+
+ // FIXME: Support CK_DerivedToBase and friends.
}
}
+
// FIXME: Missing: __real__, __imag__
};
@@ -501,10 +529,16 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
return Success(E);
// Reference parameters can refer to anything even if they have an
// "initializer" in the form of a default argument.
- if (!isa<ParmVarDecl>(VD))
+ if (!isa<ParmVarDecl>(VD)) {
// FIXME: Check whether VD might be overridden!
+
+ // Check for recursive initializers of references.
+ if (PrevDecl == VD)
+ return Error(E);
+ PrevDecl = VD;
if (const Expr *Init = VD->getAnyInitializer())
return Visit(Init);
+ }
}
return ExprEvaluatorBaseTy::VisitDeclRefExpr(E);
@@ -585,6 +619,9 @@ public:
bool Error(const Stmt *S) {
return false;
}
+ bool ValueInitialization(const Expr *E) {
+ return Success((Expr*)0);
+ }
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitCastExpr(const CastExpr* E);
@@ -599,10 +636,8 @@ public:
return Success(E);
return false;
}
- bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E)
- { return Success((Expr*)0); }
bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E)
- { return Success((Expr*)0); }
+ { return ValueInitialization(E); }
// FIXME: Missing: @protocol, @selector
};
@@ -667,7 +702,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
case CK_NoOp:
case CK_BitCast:
- case CK_AnyPointerToObjCPointerCast:
+ case CK_CPointerToObjCPointerCast:
+ case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
return Visit(SubExpr);
@@ -761,11 +797,11 @@ namespace {
APValue Success(const APValue &V, const Expr *E) { return V; }
APValue Error(const Expr *E) { return APValue(); }
+ APValue ValueInitialization(const Expr *E)
+ { return GetZeroVector(E->getType()); }
APValue VisitUnaryReal(const UnaryOperator *E)
{ return Visit(E->getSubExpr()); }
- APValue VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E)
- { return GetZeroVector(E->getType()); }
APValue VisitCastExpr(const CastExpr* E);
APValue VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
APValue VisitInitListExpr(const InitListExpr *E);
@@ -812,7 +848,7 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
}
// Splat and create vector APValue.
- llvm::SmallVector<APValue, 4> Elts(NElts, Result);
+ SmallVector<APValue, 4> Elts(NElts, Result);
return APValue(&Elts[0], Elts.size());
}
case CK_BitCast: {
@@ -829,7 +865,7 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
assert((EltTy->isIntegerType() || EltTy->isRealFloatingType()) &&
"Vectors must be composed of ints or floats");
- llvm::SmallVector<APValue, 4> Elts;
+ SmallVector<APValue, 4> Elts;
for (unsigned i = 0; i != NElts; ++i) {
APSInt Tmp = Init.extOrTrunc(EltWidth);
@@ -862,7 +898,7 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
unsigned NumElements = VT->getNumElements();
QualType EltTy = VT->getElementType();
- llvm::SmallVector<APValue, 4> Elements;
+ SmallVector<APValue, 4> Elements;
// If a vector is initialized with a single element, that value
// becomes every element of the vector, not just the first.
@@ -926,7 +962,7 @@ VectorExprEvaluator::GetZeroVector(QualType T) {
ZeroElement =
APValue(APFloat::getZero(Info.Ctx.getFloatTypeSemantics(EltTy)));
- llvm::SmallVector<APValue, 4> Elements(VT->getNumElements(), ZeroElement);
+ SmallVector<APValue, 4> Elements(VT->getNumElements(), ZeroElement);
return APValue(&Elements[0], Elements.size());
}
@@ -999,6 +1035,8 @@ public:
return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
}
+ bool ValueInitialization(const Expr *E) { return Success(0, E); }
+
//===--------------------------------------------------------------------===//
// Visitor Methods
//===--------------------------------------------------------------------===//
@@ -1039,16 +1077,9 @@ public:
return Success(E->getValue(), E);
}
+ // Note, GNU defines __null as an integer, not a pointer.
bool VisitGNUNullExpr(const GNUNullExpr *E) {
- return Success(0, E);
- }
-
- bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) {
- return Success(0, E);
- }
-
- bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
- return Success(0, E);
+ return ValueInitialization(E);
}
bool VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) {
@@ -1072,7 +1103,7 @@ public:
bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E);
bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
-
+
private:
CharUnits GetAlignOfExpr(const Expr *E);
CharUnits GetAlignOfType(QualType T);
@@ -1210,7 +1241,7 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) {
else if (ArgTy->isUnionType())
return union_type_class;
else // FIXME: offset_type_class, method_type_class, & lang_type_class?
- assert(0 && "CallExpr::isBuiltinClassifyType(): unimplemented type");
+ llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type");
return -1;
}
@@ -1267,7 +1298,7 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
// If evaluating the argument has side-effects we can't determine
// the size of the object and lower it to unknown now.
if (E->getArg(0)->HasSideEffects(Info.Ctx)) {
- if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() <= 1)
+ if (E->getArg(1)->EvaluateKnownConstInt(Info.Ctx).getZExtValue() <= 1)
return Success(-1ULL, E);
return Success(0, E);
}
@@ -1284,8 +1315,8 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
return Success(E->getArg(0)->isEvaluatable(Info.Ctx), E);
case Builtin::BI__builtin_eh_return_data_regno: {
- int Operand = E->getArg(0)->EvaluateAsInt(Info.Ctx).getZExtValue();
- Operand = Info.Ctx.Target.getEHDataRegisterNumber(Operand);
+ int Operand = E->getArg(0)->EvaluateKnownConstInt(Info.Ctx).getZExtValue();
+ Operand = Info.Ctx.getTargetInfo().getEHDataRegisterNumber(Operand);
return Success(Operand, E);
}
@@ -1300,9 +1331,9 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
= dyn_cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts())) {
// The string literal may have embedded null characters. Find the first
// one and truncate there.
- llvm::StringRef Str = S->getString();
- llvm::StringRef::size_type Pos = Str.find(0);
- if (Pos != llvm::StringRef::npos)
+ StringRef Str = S->getString();
+ StringRef::size_type Pos = Str.find(0);
+ if (Pos != StringRef::npos)
Str = Str.substr(0, Pos);
return Success(Str.size(), E);
@@ -1419,7 +1450,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
switch (E->getOpcode()) {
default:
- assert(0 && "Invalid binary operator!");
+ llvm_unreachable("Invalid binary operator!");
case BO_LT:
return Success(CR == APFloat::cmpLessThan, E);
case BO_GT:
@@ -1801,7 +1832,8 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_VectorSplat:
case CK_IntegralToFloating:
case CK_FloatingCast:
- case CK_AnyPointerToObjCPointerCast:
+ case CK_CPointerToObjCPointerCast:
+ case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
case CK_ObjCObjectLValueCast:
case CK_FloatingRealToComplex:
@@ -1818,9 +1850,10 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_GetObjCProperty:
case CK_LValueBitCast:
case CK_UserDefinedConversion:
- case CK_ObjCProduceObject:
- case CK_ObjCConsumeObject:
- case CK_ObjCReclaimReturnedObject:
+ case CK_ARCProduceObject:
+ case CK_ARCConsumeObject:
+ case CK_ARCReclaimReturnedObject:
+ case CK_ARCExtendBlockObject:
return false;
case CK_LValueToRValue:
@@ -1943,13 +1976,17 @@ public:
return false;
}
+ bool ValueInitialization(const Expr *E) {
+ Result = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(E->getType()));
+ return true;
+ }
+
bool VisitCallExpr(const CallExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitFloatingLiteral(const FloatingLiteral *E);
bool VisitCastExpr(const CastExpr *E);
- bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E);
bool VisitUnaryReal(const UnaryOperator *E);
bool VisitUnaryImag(const UnaryOperator *E);
@@ -2219,11 +2256,6 @@ bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
return false;
}
-bool FloatExprEvaluator::VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) {
- Result = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(E->getType()));
- return true;
-}
-
//===----------------------------------------------------------------------===//
// Complex Evaluation (for float and integer)
//===----------------------------------------------------------------------===//
@@ -2255,7 +2287,7 @@ public:
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitUnaryOperator(const UnaryOperator *E);
- // FIXME Missing: ImplicitValueInitExpr
+ // FIXME Missing: ImplicitValueInitExpr, InitListExpr
};
} // end anonymous namespace
@@ -2318,16 +2350,18 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_FloatingToIntegral:
case CK_FloatingToBoolean:
case CK_FloatingCast:
- case CK_AnyPointerToObjCPointerCast:
+ case CK_CPointerToObjCPointerCast:
+ case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
case CK_ObjCObjectLValueCast:
case CK_FloatingComplexToReal:
case CK_FloatingComplexToBoolean:
case CK_IntegralComplexToReal:
case CK_IntegralComplexToBoolean:
- case CK_ObjCProduceObject:
- case CK_ObjCConsumeObject:
- case CK_ObjCReclaimReturnedObject:
+ case CK_ARCProduceObject:
+ case CK_ARCConsumeObject:
+ case CK_ARCReclaimReturnedObject:
+ case CK_ARCExtendBlockObject:
llvm_unreachable("invalid cast kind for complex value");
case CK_LValueToRValue:
@@ -2633,6 +2667,13 @@ bool Expr::EvaluateAsBooleanCondition(bool &Result,
return HandleConversionToBool(this, Result, Info);
}
+bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx) const {
+ EvalResult Scratch;
+ EvalInfo Info(Ctx, Scratch);
+
+ return EvaluateInteger(this, Result, Info) && !Scratch.HasSideEffects;
+}
+
bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const {
EvalInfo Info(Ctx, Result);
@@ -2671,7 +2712,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
return HasSideEffect(Info).Visit(this);
}
-APSInt Expr::EvaluateAsInt(const ASTContext &Ctx) const {
+APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx) const {
EvalResult EvalResult;
bool Result = Evaluate(EvalResult, Ctx);
(void)Result;
@@ -2755,7 +2796,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::CompoundAssignOperatorClass:
case Expr::CompoundLiteralExprClass:
case Expr::ExtVectorElementExprClass:
- case Expr::InitListExprClass:
case Expr::DesignatedInitExprClass:
case Expr::ImplicitValueInitExprClass:
case Expr::ParenListExprClass:
@@ -2800,6 +2840,18 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::AsTypeExprClass:
case Expr::ObjCIndirectCopyRestoreExprClass:
case Expr::MaterializeTemporaryExprClass:
+ case Expr::AtomicExprClass:
+ return ICEDiag(2, E->getLocStart());
+
+ case Expr::InitListExprClass:
+ if (Ctx.getLangOptions().CPlusPlus0x) {
+ const InitListExpr *ILE = cast<InitListExpr>(E);
+ if (ILE->getNumInits() == 0)
+ return NoDiag();
+ if (ILE->getNumInits() == 1)
+ return CheckICE(ILE->getInit(0), Ctx);
+ // Fall through for more than 1 expression.
+ }
return ICEDiag(2, E->getLocStart());
case Expr::SizeOfPackExprClass:
@@ -2963,11 +3015,11 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// Evaluate gives an error for undefined Div/Rem, so make sure
// we don't evaluate one.
if (LHSResult.Val == 0 && RHSResult.Val == 0) {
- llvm::APSInt REval = Exp->getRHS()->EvaluateAsInt(Ctx);
+ llvm::APSInt REval = Exp->getRHS()->EvaluateKnownConstInt(Ctx);
if (REval == 0)
return ICEDiag(1, E->getLocStart());
if (REval.isSigned() && REval.isAllOnesValue()) {
- llvm::APSInt LEval = Exp->getLHS()->EvaluateAsInt(Ctx);
+ llvm::APSInt LEval = Exp->getLHS()->EvaluateKnownConstInt(Ctx);
if (LEval.isMinSignedValue())
return ICEDiag(1, E->getLocStart());
}
@@ -2998,11 +3050,11 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// evaluated are not considered.
if (Ctx.getLangOptions().CPlusPlus0x && LHSResult.Val == 0) {
if (Exp->getOpcode() == BO_LAnd &&
- Exp->getLHS()->EvaluateAsInt(Ctx) == 0)
+ Exp->getLHS()->EvaluateKnownConstInt(Ctx) == 0)
return LHSResult;
if (Exp->getOpcode() == BO_LOr &&
- Exp->getLHS()->EvaluateAsInt(Ctx) != 0)
+ Exp->getLHS()->EvaluateKnownConstInt(Ctx) != 0)
return LHSResult;
}
@@ -3012,7 +3064,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// to actually check the condition to see whether the side
// with the comma is evaluated.
if ((Exp->getOpcode() == BO_LAnd) !=
- (Exp->getLHS()->EvaluateAsInt(Ctx) == 0))
+ (Exp->getLHS()->EvaluateKnownConstInt(Ctx) == 0))
return RHSResult;
return NoDiag();
}
@@ -3031,11 +3083,17 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::CXXConstCastExprClass:
case Expr::ObjCBridgedCastExprClass: {
const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr();
- if (SubExpr->getType()->isIntegralOrEnumerationType())
+ switch (cast<CastExpr>(E)->getCastKind()) {
+ case CK_LValueToRValue:
+ case CK_NoOp:
+ case CK_IntegralToBoolean:
+ case CK_IntegralCast:
return CheckICE(SubExpr, Ctx);
- if (isa<FloatingLiteral>(SubExpr->IgnoreParens()))
- return NoDiag();
- return ICEDiag(2, E->getLocStart());
+ default:
+ if (isa<FloatingLiteral>(SubExpr->IgnoreParens()))
+ return NoDiag();
+ return ICEDiag(2, E->getLocStart());
+ }
}
case Expr::BinaryConditionalOperatorClass: {
const BinaryConditionalOperator *Exp = cast<BinaryConditionalOperator>(E);
@@ -3045,7 +3103,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
if (FalseResult.Val == 2) return FalseResult;
if (CommonResult.Val == 1) return CommonResult;
if (FalseResult.Val == 1 &&
- Exp->getCommon()->EvaluateAsInt(Ctx) == 0) return NoDiag();
+ Exp->getCommon()->EvaluateKnownConstInt(Ctx) == 0) return NoDiag();
return FalseResult;
}
case Expr::ConditionalOperatorClass: {
@@ -3072,7 +3130,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// subexpressions of [...] conditional (5.16) operations that
// are not evaluated are not considered
bool TrueBranch = Ctx.getLangOptions().CPlusPlus0x
- ? Exp->getCond()->EvaluateAsInt(Ctx) != 0
+ ? Exp->getCond()->EvaluateKnownConstInt(Ctx) != 0
: false;
ICEDiag TrueResult = NoDiag();
if (!Ctx.getLangOptions().CPlusPlus0x || TrueBranch)
@@ -3092,7 +3150,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// 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()->EvaluateAsInt(Ctx) == 0) {
+ if (Exp->getCond()->EvaluateKnownConstInt(Ctx) == 0) {
return FalseResult;
}
return TrueResult;
diff --git a/lib/AST/ExternalASTSource.cpp b/lib/AST/ExternalASTSource.cpp
index b96d65a729ca..fd616dbc9d2f 100644
--- a/lib/AST/ExternalASTSource.cpp
+++ b/lib/AST/ExternalASTSource.cpp
@@ -49,12 +49,10 @@ ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
return DeclContext::lookup_result();
}
-void ExternalASTSource::MaterializeVisibleDecls(const DeclContext *DC) { }
-
ExternalLoadResult
ExternalASTSource::FindExternalLexicalDecls(const DeclContext *DC,
bool (*isKindWeWant)(Decl::Kind),
- llvm::SmallVectorImpl<Decl*> &Result) {
+ SmallVectorImpl<Decl*> &Result) {
return ELR_AlreadyLoaded;
}
diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp
index c47a9dadbadd..b70520f44dc5 100644
--- a/lib/AST/InheritViz.cpp
+++ b/lib/AST/InheritViz.cpp
@@ -33,12 +33,12 @@ namespace clang {
/// vs. non-virtual bases.
class InheritanceHierarchyWriter {
ASTContext& Context;
- llvm::raw_ostream &Out;
+ raw_ostream &Out;
std::map<QualType, int, QualTypeOrdering> DirectBaseCount;
std::set<QualType, QualTypeOrdering> KnownVirtualBases;
public:
- InheritanceHierarchyWriter(ASTContext& Context, llvm::raw_ostream& Out)
+ InheritanceHierarchyWriter(ASTContext& Context, raw_ostream& Out)
: Context(Context), Out(Out) { }
void WriteGraph(QualType Type) {
@@ -55,7 +55,7 @@ protected:
/// WriteNodeReference - Write out a reference to the given node,
/// using a unique identifier for each direct base and for the
/// (only) virtual base.
- llvm::raw_ostream& WriteNodeReference(QualType Type, bool FromVirtual);
+ raw_ostream& WriteNodeReference(QualType Type, bool FromVirtual);
};
void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) {
@@ -120,7 +120,7 @@ void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) {
/// WriteNodeReference - Write out a reference to the given node,
/// using a unique identifier for each direct base and for the
/// (only) virtual base.
-llvm::raw_ostream&
+raw_ostream&
InheritanceHierarchyWriter::WriteNodeReference(QualType Type,
bool FromVirtual) {
QualType CanonType = Context.getCanonicalType(Type);
diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp
index 30aece3ee73b..0027dbf1915b 100644
--- a/lib/AST/ItaniumCXXABI.cpp
+++ b/lib/AST/ItaniumCXXABI.cpp
@@ -53,7 +53,7 @@ public:
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
CharUnits PointerSize =
- Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0));
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
return Layout.getNonVirtualSize() == PointerSize;
}
};
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index ec9863b298e6..acedf70f29c5 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -73,7 +73,7 @@ class ItaniumMangleContext : public MangleContext {
public:
explicit ItaniumMangleContext(ASTContext &Context,
- Diagnostic &Diags)
+ DiagnosticsEngine &Diags)
: MangleContext(Context, Diags) { }
uint64_t getAnonymousStructId(const TagDecl *TD) {
@@ -92,30 +92,30 @@ public:
/// @{
bool shouldMangleDeclName(const NamedDecl *D);
- void mangleName(const NamedDecl *D, llvm::raw_ostream &);
+ void mangleName(const NamedDecl *D, raw_ostream &);
void mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk,
- llvm::raw_ostream &);
+ raw_ostream &);
void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
const ThisAdjustment &ThisAdjustment,
- llvm::raw_ostream &);
+ raw_ostream &);
void mangleReferenceTemporary(const VarDecl *D,
- llvm::raw_ostream &);
+ raw_ostream &);
void mangleCXXVTable(const CXXRecordDecl *RD,
- llvm::raw_ostream &);
+ raw_ostream &);
void mangleCXXVTT(const CXXRecordDecl *RD,
- llvm::raw_ostream &);
+ raw_ostream &);
void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
const CXXRecordDecl *Type,
- llvm::raw_ostream &);
- void mangleCXXRTTI(QualType T, llvm::raw_ostream &);
- void mangleCXXRTTIName(QualType T, llvm::raw_ostream &);
+ raw_ostream &);
+ void mangleCXXRTTI(QualType T, raw_ostream &);
+ void mangleCXXRTTIName(QualType T, raw_ostream &);
void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
- llvm::raw_ostream &);
+ raw_ostream &);
void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
- llvm::raw_ostream &);
+ raw_ostream &);
- void mangleItaniumGuardVariable(const VarDecl *D, llvm::raw_ostream &);
+ void mangleItaniumGuardVariable(const VarDecl *D, raw_ostream &);
void mangleInitDiscriminator() {
Discriminator = 0;
@@ -136,7 +136,7 @@ public:
/// CXXNameMangler - Manage the mangling of a single name.
class CXXNameMangler {
ItaniumMangleContext &Context;
- llvm::raw_ostream &Out;
+ raw_ostream &Out;
/// The "structor" is the top-level declaration being mangled, if
/// that's not a template specialization; otherwise it's the pattern
@@ -191,7 +191,7 @@ class CXXNameMangler {
ASTContext &getASTContext() const { return Context.getASTContext(); }
public:
- CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_,
+ CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_,
const NamedDecl *D = 0)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(0),
SeqID(0) {
@@ -199,11 +199,11 @@ public:
assert(!D || (!isa<CXXDestructorDecl>(D) &&
!isa<CXXConstructorDecl>(D)));
}
- CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_,
+ CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_,
const CXXConstructorDecl *D, CXXCtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
SeqID(0) { }
- CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_,
+ CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_,
const CXXDestructorDecl *D, CXXDtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
SeqID(0) { }
@@ -219,9 +219,9 @@ public:
free(result);
}
#endif
- llvm::raw_ostream &getStream() { return Out; }
+ raw_ostream &getStream() { return Out; }
- void mangle(const NamedDecl *D, llvm::StringRef Prefix = "_Z");
+ void mangle(const NamedDecl *D, StringRef Prefix = "_Z");
void mangleCallOffset(int64_t NonVirtual, int64_t Virtual);
void mangleNumber(const llvm::APSInt &I);
void mangleNumber(int64_t Number);
@@ -310,7 +310,7 @@ private:
void mangleCXXCtorType(CXXCtorType T);
void mangleCXXDtorType(CXXDtorType T);
- void mangleTemplateArgs(const ExplicitTemplateArgumentList &TemplateArgs);
+ void mangleTemplateArgs(const ASTTemplateArgumentListInfo &TemplateArgs);
void mangleTemplateArgs(TemplateName Template,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
@@ -385,7 +385,7 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
return true;
}
-void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) {
+void CXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) {
// Any decl can be declared with __asm("foo") on it, and this takes precedence
// over all other naming in the .o file.
if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
@@ -397,8 +397,8 @@ void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) {
// llvm mangler on ELF is a nop, so we can just avoid adding the \01
// marker. We also avoid adding the marker if this is an alias for an
// LLVM intrinsic.
- llvm::StringRef UserLabelPrefix =
- getASTContext().Target.getUserLabelPrefix();
+ StringRef UserLabelPrefix =
+ getASTContext().getTargetInfo().getUserLabelPrefix();
if (!UserLabelPrefix.empty() && !ALA->getLabel().startswith("llvm."))
Out << '\01'; // LLVM IR Marker for __asm("foo")
@@ -788,6 +788,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
case Type::ObjCObject:
case Type::ObjCInterface:
case Type::ObjCObjectPointer:
+ case Type::Atomic:
llvm_unreachable("type is illegal as a nested name specifier");
case Type::SubstTemplateTypeParmPack:
@@ -1069,8 +1070,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
- assert(false && "Can't mangle Objective-C selector names here!");
- break;
+ llvm_unreachable("Can't mangle Objective-C selector names here!");
case DeclarationName::CXXConstructorName:
if (ND == Structor)
@@ -1124,8 +1124,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
break;
case DeclarationName::CXXUsingDirective:
- assert(false && "Can't mangle a using directive name!");
- break;
+ llvm_unreachable("Can't mangle a using directive name!");
}
}
@@ -1512,8 +1511,7 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) {
case OO_None:
case NUM_OVERLOADED_OPERATORS:
- assert(false && "Not an overloaded operator");
- break;
+ llvm_unreachable("Not an overloaded operator");
}
}
@@ -1538,7 +1536,7 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
Out << 'U' << ASString.size() << ASString;
}
- llvm::StringRef LifetimeName;
+ StringRef LifetimeName;
switch (Quals.getObjCLifetime()) {
// Objective-C ARC Extension:
//
@@ -1706,7 +1704,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
// UNSUPPORTED: ::= Dd # IEEE 754r decimal floating point (64 bits)
// UNSUPPORTED: ::= De # IEEE 754r decimal floating point (128 bits)
// UNSUPPORTED: ::= Df # IEEE 754r decimal floating point (32 bits)
- // UNSUPPORTED: ::= Dh # IEEE 754r half-precision floating point (16 bits)
+ // ::= Dh # IEEE 754r half-precision floating point (16 bits)
// ::= Di # char32_t
// ::= Ds # char16_t
// ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
@@ -1731,6 +1729,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::Long: Out << 'l'; break;
case BuiltinType::LongLong: Out << 'x'; break;
case BuiltinType::Int128: Out << 'n'; break;
+ case BuiltinType::Half: Out << "Dh"; break;
case BuiltinType::Float: Out << 'f'; break;
case BuiltinType::Double: Out << 'd'; break;
case BuiltinType::LongDouble: Out << 'e'; break;
@@ -2114,6 +2113,13 @@ void CXXNameMangler::mangleType(const AutoType *T) {
mangleType(D);
}
+void CXXNameMangler::mangleType(const AtomicType *T) {
+ // <type> ::= U <source-name> <type> # vendor extended type qualifier
+ // (Until there's a standardized mangling...)
+ Out << "U7_Atomic";
+ mangleType(T->getValueType());
+}
+
void CXXNameMangler::mangleIntegerLiteral(QualType T,
const llvm::APSInt &Value) {
// <expr-primary> ::= L <type> <value number> E # integer literal
@@ -2250,10 +2256,11 @@ recurse:
case Expr::CXXNoexceptExprClass:
case Expr::CUDAKernelCallExprClass:
case Expr::AsTypeExprClass:
+ case Expr::AtomicExprClass:
{
// As bad as this diagnostic is, it's better than crashing.
- Diagnostic &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot yet mangle expression type %0");
Diags.Report(E->getExprLoc(), DiagID)
<< E->getStmtClassName() << E->getSourceRange();
@@ -2262,9 +2269,9 @@ recurse:
// Even gcc-4.5 doesn't mangle this.
case Expr::BinaryConditionalOperatorClass: {
- Diagnostic &Diags = Context.getDiags();
+ DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID =
- Diags.getCustomDiagID(Diagnostic::Error,
+ Diags.getCustomDiagID(DiagnosticsEngine::Error,
"?: operator with omitted middle operand cannot be mangled");
Diags.Report(E->getExprLoc(), DiagID)
<< E->getStmtClassName() << E->getSourceRange();
@@ -2411,7 +2418,8 @@ recurse:
QualType T = (ImplicitlyConvertedToType.isNull() ||
!ImplicitlyConvertedToType->isIntegerType())? SAE->getType()
: ImplicitlyConvertedToType;
- mangleIntegerLiteral(T, SAE->EvaluateAsInt(Context.getASTContext()));
+ llvm::APSInt V = SAE->EvaluateKnownConstInt(Context.getASTContext());
+ mangleIntegerLiteral(T, V);
break;
}
@@ -2423,8 +2431,8 @@ recurse:
Out << 'a';
break;
case UETT_VecStep:
- Diagnostic &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot yet mangle vec_step expression");
Diags.Report(DiagID);
return;
@@ -2526,7 +2534,7 @@ recurse:
case Expr::ObjCBridgedCastExprClass: {
// Mangle ownership casts as a vendor extended operator __bridge,
// __bridge_transfer, or __bridge_retain.
- llvm::StringRef Kind = cast<ObjCBridgedCastExpr>(E)->getBridgeKindName();
+ StringRef Kind = cast<ObjCBridgedCastExpr>(E)->getBridgeKindName();
Out << "v1U" << Kind.size() << Kind;
}
// Fall through to mangle the cast itself.
@@ -2817,7 +2825,7 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
}
void CXXNameMangler::mangleTemplateArgs(
- const ExplicitTemplateArgumentList &TemplateArgs) {
+ const ASTTemplateArgumentListInfo &TemplateArgs) {
// <template-args> ::= I <template-arg>+ E
Out << 'I';
for (unsigned i = 0, e = TemplateArgs.NumTemplateArgs; i != e; ++i)
@@ -3021,7 +3029,7 @@ bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) {
}
Out << 'S'
- << llvm::StringRef(BufferPtr, llvm::array_endof(Buffer)-BufferPtr)
+ << StringRef(BufferPtr, llvm::array_endof(Buffer)-BufferPtr)
<< '_';
}
@@ -3196,7 +3204,7 @@ void CXXNameMangler::addSubstitution(uintptr_t Ptr) {
/// emit the identifier of the declaration (\c D->getIdentifier()) as its
/// name.
void ItaniumMangleContext::mangleName(const NamedDecl *D,
- llvm::raw_ostream &Out) {
+ raw_ostream &Out) {
assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
"Invalid mangleName() call, argument is not a variable or function!");
assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) &&
@@ -3212,21 +3220,21 @@ void ItaniumMangleContext::mangleName(const NamedDecl *D,
void ItaniumMangleContext::mangleCXXCtor(const CXXConstructorDecl *D,
CXXCtorType Type,
- llvm::raw_ostream &Out) {
+ raw_ostream &Out) {
CXXNameMangler Mangler(*this, Out, D, Type);
Mangler.mangle(D);
}
void ItaniumMangleContext::mangleCXXDtor(const CXXDestructorDecl *D,
CXXDtorType Type,
- llvm::raw_ostream &Out) {
+ raw_ostream &Out) {
CXXNameMangler Mangler(*this, Out, D, Type);
Mangler.mangle(D);
}
void ItaniumMangleContext::mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk,
- llvm::raw_ostream &Out) {
+ raw_ostream &Out) {
// <special-name> ::= T <call-offset> <base encoding>
// # base is the nominal target function of thunk
// <special-name> ::= Tc <call-offset> <call-offset> <base encoding>
@@ -3256,7 +3264,7 @@ void
ItaniumMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
CXXDtorType Type,
const ThisAdjustment &ThisAdjustment,
- llvm::raw_ostream &Out) {
+ raw_ostream &Out) {
// <special-name> ::= T <call-offset> <base encoding>
// # base is the nominal target function of thunk
CXXNameMangler Mangler(*this, Out, DD, Type);
@@ -3272,7 +3280,7 @@ ItaniumMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
/// mangleGuardVariable - Returns the mangled name for a guard variable
/// for the passed in VarDecl.
void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D,
- llvm::raw_ostream &Out) {
+ raw_ostream &Out) {
// <special-name> ::= GV <object name> # Guard variable for one-time
// # initialization
CXXNameMangler Mangler(*this, Out);
@@ -3281,7 +3289,7 @@ void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D,
}
void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D,
- llvm::raw_ostream &Out) {
+ raw_ostream &Out) {
// We match the GCC mangling here.
// <special-name> ::= GR <object name>
CXXNameMangler Mangler(*this, Out);
@@ -3290,7 +3298,7 @@ void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D,
}
void ItaniumMangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
- llvm::raw_ostream &Out) {
+ raw_ostream &Out) {
// <special-name> ::= TV <type> # virtual table
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "_ZTV";
@@ -3298,7 +3306,7 @@ void ItaniumMangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
}
void ItaniumMangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
- llvm::raw_ostream &Out) {
+ raw_ostream &Out) {
// <special-name> ::= TT <type> # VTT structure
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "_ZTT";
@@ -3308,7 +3316,7 @@ void ItaniumMangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
void ItaniumMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD,
int64_t Offset,
const CXXRecordDecl *Type,
- llvm::raw_ostream &Out) {
+ raw_ostream &Out) {
// <special-name> ::= TC <type> <offset number> _ <base type>
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "_ZTC";
@@ -3319,7 +3327,7 @@ void ItaniumMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD,
}
void ItaniumMangleContext::mangleCXXRTTI(QualType Ty,
- llvm::raw_ostream &Out) {
+ raw_ostream &Out) {
// <special-name> ::= TI <type> # typeinfo structure
assert(!Ty.hasQualifiers() && "RTTI info cannot have top-level qualifiers");
CXXNameMangler Mangler(*this, Out);
@@ -3328,7 +3336,7 @@ void ItaniumMangleContext::mangleCXXRTTI(QualType Ty,
}
void ItaniumMangleContext::mangleCXXRTTIName(QualType Ty,
- llvm::raw_ostream &Out) {
+ raw_ostream &Out) {
// <special-name> ::= TS <type> # typeinfo name (null terminated byte string)
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "_ZTS";
@@ -3336,6 +3344,6 @@ void ItaniumMangleContext::mangleCXXRTTIName(QualType Ty,
}
MangleContext *clang::createItaniumMangleContext(ASTContext &Context,
- Diagnostic &Diags) {
+ DiagnosticsEngine &Diags) {
return new ItaniumMangleContext(Context, Diags);
}
diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp
index c3f3b11caccf..5cb8f47519ec 100644
--- a/lib/AST/Mangle.cpp
+++ b/lib/AST/Mangle.cpp
@@ -37,9 +37,9 @@ using namespace clang;
namespace {
static void mangleFunctionBlock(MangleContext &Context,
- llvm::StringRef Outer,
+ StringRef Outer,
const BlockDecl *BD,
- llvm::raw_ostream &Out) {
+ raw_ostream &Out) {
Out << "__" << Outer << "_block_invoke_" << Context.getBlockId(BD, true);
}
@@ -60,13 +60,13 @@ static void checkMangleDC(const DeclContext *DC, const BlockDecl *BD) {
}
void MangleContext::mangleGlobalBlock(const BlockDecl *BD,
- llvm::raw_ostream &Out) {
+ raw_ostream &Out) {
Out << "__block_global_" << getBlockId(BD, false);
}
void MangleContext::mangleCtorBlock(const CXXConstructorDecl *CD,
CXXCtorType CT, const BlockDecl *BD,
- llvm::raw_ostream &ResStream) {
+ raw_ostream &ResStream) {
checkMangleDC(CD, BD);
llvm::SmallString<64> Buffer;
llvm::raw_svector_ostream Out(Buffer);
@@ -77,7 +77,7 @@ void MangleContext::mangleCtorBlock(const CXXConstructorDecl *CD,
void MangleContext::mangleDtorBlock(const CXXDestructorDecl *DD,
CXXDtorType DT, const BlockDecl *BD,
- llvm::raw_ostream &ResStream) {
+ raw_ostream &ResStream) {
checkMangleDC(DD, BD);
llvm::SmallString<64> Buffer;
llvm::raw_svector_ostream Out(Buffer);
@@ -87,7 +87,7 @@ void MangleContext::mangleDtorBlock(const CXXDestructorDecl *DD,
}
void MangleContext::mangleBlock(const DeclContext *DC, const BlockDecl *BD,
- llvm::raw_ostream &Out) {
+ raw_ostream &Out) {
assert(!isa<CXXConstructorDecl>(DC) && !isa<CXXDestructorDecl>(DC));
checkMangleDC(DC, BD);
@@ -113,7 +113,7 @@ void MangleContext::mangleBlock(const DeclContext *DC, const BlockDecl *BD,
}
void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD,
- llvm::raw_ostream &Out) {
+ raw_ostream &Out) {
llvm::SmallString<64> Name;
llvm::raw_svector_ostream OS(Name);
@@ -129,7 +129,7 @@ void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD,
}
void MangleContext::mangleBlock(const BlockDecl *BD,
- llvm::raw_ostream &Out) {
+ raw_ostream &Out) {
const DeclContext *DC = BD->getDeclContext();
while (isa<BlockDecl>(DC) || isa<EnumDecl>(DC))
DC = DC->getParent();
diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp
index 206f6dd0c9eb..f33d6fe1f563 100644
--- a/lib/AST/MicrosoftCXXABI.cpp
+++ b/lib/AST/MicrosoftCXXABI.cpp
@@ -30,7 +30,7 @@ public:
unsigned getMemberPointerSize(const MemberPointerType *MPT) const;
CallingConv getDefaultMethodCallConv() const {
- if (Context.Target.getTriple().getArch() == llvm::Triple::x86)
+ if (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
return CC_X86ThisCall;
else
return CC_C;
@@ -45,7 +45,7 @@ public:
// In the Microsoft ABI, classes can have one or two vtable pointers.
CharUnits PointerSize =
- Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0));
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
return Layout.getNonVirtualSize() == PointerSize ||
Layout.getNonVirtualSize() == PointerSize * 2;
}
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 4f920f9aaca7..1515db49fe3c 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -29,15 +29,15 @@ namespace {
/// Microsoft Visual C++ ABI.
class MicrosoftCXXNameMangler {
MangleContext &Context;
- llvm::raw_ostream &Out;
+ raw_ostream &Out;
ASTContext &getASTContext() const { return Context.getASTContext(); }
public:
- MicrosoftCXXNameMangler(MangleContext &C, llvm::raw_ostream &Out_)
+ MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_)
: Context(C), Out(Out_) { }
- void mangle(const NamedDecl *D, llvm::StringRef Prefix = "?");
+ void mangle(const NamedDecl *D, StringRef Prefix = "?");
void mangleName(const NamedDecl *ND);
void mangleFunctionEncoding(const FunctionDecl *FD);
void mangleVariableEncoding(const VarDecl *VD);
@@ -78,30 +78,30 @@ private:
class MicrosoftMangleContext : public MangleContext {
public:
MicrosoftMangleContext(ASTContext &Context,
- Diagnostic &Diags) : MangleContext(Context, Diags) { }
+ DiagnosticsEngine &Diags) : MangleContext(Context, Diags) { }
virtual bool shouldMangleDeclName(const NamedDecl *D);
- virtual void mangleName(const NamedDecl *D, llvm::raw_ostream &Out);
+ virtual void mangleName(const NamedDecl *D, raw_ostream &Out);
virtual void mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk,
- llvm::raw_ostream &);
+ raw_ostream &);
virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
const ThisAdjustment &ThisAdjustment,
- llvm::raw_ostream &);
+ raw_ostream &);
virtual void mangleCXXVTable(const CXXRecordDecl *RD,
- llvm::raw_ostream &);
+ raw_ostream &);
virtual void mangleCXXVTT(const CXXRecordDecl *RD,
- llvm::raw_ostream &);
+ raw_ostream &);
virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
const CXXRecordDecl *Type,
- llvm::raw_ostream &);
- virtual void mangleCXXRTTI(QualType T, llvm::raw_ostream &);
- virtual void mangleCXXRTTIName(QualType T, llvm::raw_ostream &);
+ raw_ostream &);
+ virtual void mangleCXXRTTI(QualType T, raw_ostream &);
+ virtual void mangleCXXRTTIName(QualType T, raw_ostream &);
virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
- llvm::raw_ostream &);
+ raw_ostream &);
virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
- llvm::raw_ostream &);
+ raw_ostream &);
virtual void mangleReferenceTemporary(const clang::VarDecl *,
- llvm::raw_ostream &);
+ raw_ostream &);
};
}
@@ -154,7 +154,7 @@ bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) {
}
void MicrosoftCXXNameMangler::mangle(const NamedDecl *D,
- llvm::StringRef Prefix) {
+ StringRef Prefix) {
// MSVC doesn't mangle C++ names the same way it mangles extern "C" names.
// Therefore it's really important that we don't decorate the
// name with leading underscores or leading/trailing at signs. So, emit a
@@ -332,16 +332,13 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
- assert(false && "Can't mangle Objective-C selector names here!");
- break;
+ llvm_unreachable("Can't mangle Objective-C selector names here!");
case DeclarationName::CXXConstructorName:
- assert(false && "Can't mangle constructors yet!");
- break;
+ llvm_unreachable("Can't mangle constructors yet!");
case DeclarationName::CXXDestructorName:
- assert(false && "Can't mangle destructors yet!");
- break;
+ llvm_unreachable("Can't mangle destructors yet!");
case DeclarationName::CXXConversionFunctionName:
// <operator-name> ::= ?B # (cast)
@@ -355,12 +352,10 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
case DeclarationName::CXXLiteralOperatorName:
// FIXME: Was this added in VS2010? Does MS even know how to mangle this?
- assert(false && "Don't know how to mangle literal operators yet!");
- break;
+ llvm_unreachable("Don't know how to mangle literal operators yet!");
case DeclarationName::CXXUsingDirective:
- assert(false && "Can't mangle a using directive name!");
- break;
+ llvm_unreachable("Can't mangle a using directive name!");
}
}
@@ -513,13 +508,11 @@ void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO) {
case OO_Array_Delete: Out << "?_V"; break;
case OO_Conditional:
- assert(false && "Don't know how to mangle ?:");
- break;
+ llvm_unreachable("Don't know how to mangle ?:");
case OO_None:
case NUM_OVERLOADED_OPERATORS:
- assert(false && "Not an overloaded operator");
- break;
+ llvm_unreachable("Not an overloaded operator");
}
}
@@ -712,18 +705,17 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::Dependent:
case BuiltinType::UnknownAny:
case BuiltinType::BoundMember:
- assert(false &&
+ llvm_unreachable(
"Overloaded and dependent types shouldn't get to name mangling");
- break;
case BuiltinType::ObjCId: Out << "PAUobjc_object@@"; break;
case BuiltinType::ObjCClass: Out << "PAUobjc_class@@"; break;
case BuiltinType::ObjCSel: Out << "PAUobjc_selector@@"; break;
case BuiltinType::Char16:
case BuiltinType::Char32:
+ case BuiltinType::Half:
case BuiltinType::NullPtr:
- assert(false && "Don't know how to mangle this type");
- break;
+ llvm_unreachable("Don't know how to mangle this type");
}
}
@@ -869,7 +861,7 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T,
CC = IsInstMethod ? getASTContext().getDefaultMethodCallConv() : CC_C;
switch (CC) {
default:
- assert(0 && "Unsupported CC for mangling");
+ llvm_unreachable("Unsupported CC for mangling");
case CC_Default:
case CC_C: Out << 'A'; break;
case CC_X86Pascal: Out << 'C'; break;
@@ -890,7 +882,7 @@ void MicrosoftCXXNameMangler::mangleThrowSpecification(
}
void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T) {
- assert(false && "Don't know how to mangle UnresolvedUsingTypes yet!");
+ llvm_unreachable("Don't know how to mangle UnresolvedUsingTypes yet!");
}
// <type> ::= <union-type> | <struct-type> | <class-type> | <enum-type>
@@ -954,7 +946,7 @@ void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T) {
mangleType(static_cast<const ArrayType *>(T), false);
}
void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) {
- llvm::SmallVector<llvm::APInt, 3> Dimensions;
+ SmallVector<llvm::APInt, 3> Dimensions;
for (;;) {
if (ElementTy->isConstantArrayType()) {
const ConstantArrayType *CAT =
@@ -962,10 +954,10 @@ void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) {
Dimensions.push_back(CAT->getSize());
ElementTy = CAT->getElementType();
} else if (ElementTy->isVariableArrayType()) {
- assert(false && "Don't know how to mangle VLAs!");
+ llvm_unreachable("Don't know how to mangle VLAs!");
} else if (ElementTy->isDependentSizedArrayType()) {
// The dependent expression has to be folded into a constant (TODO).
- assert(false && "Don't know how to mangle dependent-sized arrays!");
+ llvm_unreachable("Don't know how to mangle dependent-sized arrays!");
} else if (ElementTy->isIncompleteArrayType()) continue;
else break;
}
@@ -999,12 +991,12 @@ void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T) {
}
void MicrosoftCXXNameMangler::mangleType(const TemplateTypeParmType *T) {
- assert(false && "Don't know how to mangle TemplateTypeParmTypes yet!");
+ llvm_unreachable("Don't know how to mangle TemplateTypeParmTypes yet!");
}
void MicrosoftCXXNameMangler::mangleType(
const SubstTemplateTypeParmPackType *T) {
- assert(false &&
+ llvm_unreachable(
"Don't know how to mangle SubstTemplateTypeParmPackTypes yet!");
}
@@ -1045,21 +1037,22 @@ void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T) {
}
void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T) {
- assert(false && "Don't know how to mangle RValueReferenceTypes yet!");
+ llvm_unreachable("Don't know how to mangle RValueReferenceTypes yet!");
}
void MicrosoftCXXNameMangler::mangleType(const ComplexType *T) {
- assert(false && "Don't know how to mangle ComplexTypes yet!");
+ llvm_unreachable("Don't know how to mangle ComplexTypes yet!");
}
void MicrosoftCXXNameMangler::mangleType(const VectorType *T) {
- assert(false && "Don't know how to mangle VectorTypes yet!");
+ llvm_unreachable("Don't know how to mangle VectorTypes yet!");
}
void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T) {
- assert(false && "Don't know how to mangle ExtVectorTypes yet!");
+ llvm_unreachable("Don't know how to mangle ExtVectorTypes yet!");
}
void MicrosoftCXXNameMangler::mangleType(const DependentSizedExtVectorType *T) {
- assert(false && "Don't know how to mangle DependentSizedExtVectorTypes yet!");
+ llvm_unreachable(
+ "Don't know how to mangle DependentSizedExtVectorTypes yet!");
}
void MicrosoftCXXNameMangler::mangleType(const ObjCInterfaceType *T) {
@@ -1080,49 +1073,53 @@ void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T) {
}
void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T) {
- assert(false && "Don't know how to mangle InjectedClassNameTypes yet!");
+ llvm_unreachable("Don't know how to mangle InjectedClassNameTypes yet!");
}
void MicrosoftCXXNameMangler::mangleType(const TemplateSpecializationType *T) {
- assert(false && "Don't know how to mangle TemplateSpecializationTypes yet!");
+ llvm_unreachable("Don't know how to mangle TemplateSpecializationTypes yet!");
}
void MicrosoftCXXNameMangler::mangleType(const DependentNameType *T) {
- assert(false && "Don't know how to mangle DependentNameTypes yet!");
+ llvm_unreachable("Don't know how to mangle DependentNameTypes yet!");
}
void MicrosoftCXXNameMangler::mangleType(
const DependentTemplateSpecializationType *T) {
- assert(false &&
+ llvm_unreachable(
"Don't know how to mangle DependentTemplateSpecializationTypes yet!");
}
void MicrosoftCXXNameMangler::mangleType(const PackExpansionType *T) {
- assert(false && "Don't know how to mangle PackExpansionTypes yet!");
+ llvm_unreachable("Don't know how to mangle PackExpansionTypes yet!");
}
void MicrosoftCXXNameMangler::mangleType(const TypeOfType *T) {
- assert(false && "Don't know how to mangle TypeOfTypes yet!");
+ llvm_unreachable("Don't know how to mangle TypeOfTypes yet!");
}
void MicrosoftCXXNameMangler::mangleType(const TypeOfExprType *T) {
- assert(false && "Don't know how to mangle TypeOfExprTypes yet!");
+ llvm_unreachable("Don't know how to mangle TypeOfExprTypes yet!");
}
void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T) {
- assert(false && "Don't know how to mangle DecltypeTypes yet!");
+ llvm_unreachable("Don't know how to mangle DecltypeTypes yet!");
}
void MicrosoftCXXNameMangler::mangleType(const UnaryTransformType *T) {
- assert(false && "Don't know how to mangle UnaryTransformationTypes yet!");
+ llvm_unreachable("Don't know how to mangle UnaryTransformationTypes yet!");
}
void MicrosoftCXXNameMangler::mangleType(const AutoType *T) {
- assert(false && "Don't know how to mangle AutoTypes yet!");
+ llvm_unreachable("Don't know how to mangle AutoTypes yet!");
+}
+
+void MicrosoftCXXNameMangler::mangleType(const AtomicType *T) {
+ llvm_unreachable("Don't know how to mangle AtomicTypes yet!");
}
void MicrosoftMangleContext::mangleName(const NamedDecl *D,
- llvm::raw_ostream &Out) {
+ raw_ostream &Out) {
assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
"Invalid mangleName() call, argument is not a variable or function!");
assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) &&
@@ -1137,53 +1134,53 @@ void MicrosoftMangleContext::mangleName(const NamedDecl *D,
}
void MicrosoftMangleContext::mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk,
- llvm::raw_ostream &) {
- assert(false && "Can't yet mangle thunks!");
+ raw_ostream &) {
+ llvm_unreachable("Can't yet mangle thunks!");
}
void MicrosoftMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
CXXDtorType Type,
const ThisAdjustment &,
- llvm::raw_ostream &) {
- assert(false && "Can't yet mangle destructor thunks!");
+ raw_ostream &) {
+ llvm_unreachable("Can't yet mangle destructor thunks!");
}
void MicrosoftMangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
- llvm::raw_ostream &) {
- assert(false && "Can't yet mangle virtual tables!");
+ raw_ostream &) {
+ llvm_unreachable("Can't yet mangle virtual tables!");
}
void MicrosoftMangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
- llvm::raw_ostream &) {
+ raw_ostream &) {
llvm_unreachable("The MS C++ ABI does not have virtual table tables!");
}
void MicrosoftMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD,
int64_t Offset,
const CXXRecordDecl *Type,
- llvm::raw_ostream &) {
+ raw_ostream &) {
llvm_unreachable("The MS C++ ABI does not have constructor vtables!");
}
void MicrosoftMangleContext::mangleCXXRTTI(QualType T,
- llvm::raw_ostream &) {
- assert(false && "Can't yet mangle RTTI!");
+ raw_ostream &) {
+ llvm_unreachable("Can't yet mangle RTTI!");
}
void MicrosoftMangleContext::mangleCXXRTTIName(QualType T,
- llvm::raw_ostream &) {
- assert(false && "Can't yet mangle RTTI names!");
+ raw_ostream &) {
+ llvm_unreachable("Can't yet mangle RTTI names!");
}
void MicrosoftMangleContext::mangleCXXCtor(const CXXConstructorDecl *D,
CXXCtorType Type,
- llvm::raw_ostream &) {
- assert(false && "Can't yet mangle constructors!");
+ raw_ostream &) {
+ llvm_unreachable("Can't yet mangle constructors!");
}
void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D,
CXXDtorType Type,
- llvm::raw_ostream &) {
- assert(false && "Can't yet mangle destructors!");
+ raw_ostream &) {
+ llvm_unreachable("Can't yet mangle destructors!");
}
void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *,
- llvm::raw_ostream &) {
- assert(false && "Can't yet mangle reference temporaries!");
+ raw_ostream &) {
+ llvm_unreachable("Can't yet mangle reference temporaries!");
}
MangleContext *clang::createMicrosoftMangleContext(ASTContext &Context,
- Diagnostic &Diags) {
+ DiagnosticsEngine &Diags) {
return new MicrosoftMangleContext(Context, Diags);
}
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index f6d4f2513ce4..1ff2e7177b3b 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -218,7 +218,7 @@ bool NestedNameSpecifier::containsUnexpandedParameterPack() const {
/// \brief Print this nested name specifier to the given output
/// stream.
void
-NestedNameSpecifier::print(llvm::raw_ostream &OS,
+NestedNameSpecifier::print(raw_ostream &OS,
const PrintingPolicy &Policy) const {
if (getPrefix())
getPrefix()->print(OS, Policy);
@@ -569,7 +569,7 @@ void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context,
// Construct bogus (but well-formed) source information for the
// nested-name-specifier.
BufferSize = 0;
- llvm::SmallVector<NestedNameSpecifier *, 4> Stack;
+ SmallVector<NestedNameSpecifier *, 4> Stack;
for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix())
Stack.push_back(NNS);
while (!Stack.empty()) {
diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp
index b7b2005e9f84..5eef83a81a8b 100644
--- a/lib/AST/ParentMap.cpp
+++ b/lib/AST/ParentMap.cpp
@@ -66,6 +66,14 @@ Stmt *ParentMap::getParentIgnoreParenCasts(Stmt *S) const {
return S;
}
+Stmt *ParentMap::getParentIgnoreParenImpCasts(Stmt *S) const {
+ do {
+ S = getParent(S);
+ } while (S && isa<Expr>(S) && cast<Expr>(S)->IgnoreParenImpCasts() != S);
+
+ return S;
+}
+
Stmt *ParentMap::getOuterParenParent(Stmt *S) const {
Stmt *Paren = 0;
while (isa<ParenExpr>(S)) {
diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp
index 035c48fd0827..ccc591a28f32 100644
--- a/lib/AST/RecordLayout.cpp
+++ b/lib/AST/RecordLayout.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecordLayout.h"
+#include "clang/Basic/TargetInfo.h"
using namespace clang;
@@ -42,7 +43,7 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size,
// Constructor for C++ records.
ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
CharUnits size, CharUnits alignment,
- CharUnits datasize,
+ CharUnits vbptroffset, CharUnits datasize,
const uint64_t *fieldoffsets,
unsigned fieldcount,
CharUnits nonvirtualsize,
@@ -67,15 +68,20 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
CXXInfo->SizeOfLargestEmptySubobject = SizeOfLargestEmptySubobject;
CXXInfo->BaseOffsets = BaseOffsets;
CXXInfo->VBaseOffsets = VBaseOffsets;
+ CXXInfo->VBPtrOffset = vbptroffset;
#ifndef NDEBUG
if (const CXXRecordDecl *PrimaryBase = getPrimaryBase()) {
- if (isPrimaryBaseVirtual())
+ 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!");
- else
+ }
+ } else {
assert(getBaseClassOffsetInBits(PrimaryBase) == 0 &&
"Primary base must be at offset 0!");
+ }
}
#endif
}
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 5636a6f0f64a..bbd3fc016017 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -44,7 +44,7 @@ struct BaseSubobjectInfo {
bool IsVirtual;
/// Bases - Information about the base subobjects.
- llvm::SmallVector<BaseSubobjectInfo*, 4> Bases;
+ SmallVector<BaseSubobjectInfo*, 4> Bases;
/// PrimaryVirtualBaseInfo - Holds the base info for the primary virtual base
/// of this base info (if one exists).
@@ -64,7 +64,7 @@ class EmptySubobjectMap {
const CXXRecordDecl *Class;
/// EmptyClassOffsets - A map from offsets to empty record decls.
- typedef llvm::SmallVector<const CXXRecordDecl *, 1> ClassVectorTy;
+ typedef SmallVector<const CXXRecordDecl *, 1> ClassVectorTy;
typedef llvm::DenseMap<CharUnits, ClassVectorTy> EmptyClassOffsetsMapTy;
EmptyClassOffsetsMapTy EmptyClassOffsets;
@@ -556,7 +556,7 @@ protected:
/// \brief The alignment if attribute packed is not used.
CharUnits UnpackedAlignment;
- llvm::SmallVector<uint64_t, 16> FieldOffsets;
+ SmallVector<uint64_t, 16> FieldOffsets;
/// Packed - Whether the record is packed or not.
unsigned Packed : 1;
@@ -592,6 +592,9 @@ protected:
/// out is virtual.
bool PrimaryBaseIsVirtual;
+ /// VBPtrOffset - Virtual base table offset. Only for MS layout.
+ CharUnits VBPtrOffset;
+
typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
/// Bases - base classes and their offsets in the record.
@@ -613,16 +616,17 @@ protected:
llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
RecordLayoutBuilder(const ASTContext &Context, EmptySubobjectMap
- *EmptySubobjects)
+ *EmptySubobjects, CharUnits Alignment)
: Context(Context), EmptySubobjects(EmptySubobjects), Size(0),
- Alignment(CharUnits::One()), UnpackedAlignment(Alignment),
+ Alignment(Alignment), UnpackedAlignment(Alignment),
Packed(false), IsUnion(false),
IsMac68kAlign(false), IsMsStruct(false),
UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()),
DataSize(0), NonVirtualSize(CharUnits::Zero()),
NonVirtualAlignment(CharUnits::One()),
ZeroLengthBitfield(0), PrimaryBase(0),
- PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { }
+ PrimaryBaseIsVirtual(false), VBPtrOffset(CharUnits::fromQuantity(-1)),
+ FirstNearlyEmptyVBase(0) { }
void Layout(const RecordDecl *D);
void Layout(const CXXRecordDecl *D);
@@ -633,6 +637,8 @@ protected:
void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize,
bool FieldPacked, const FieldDecl *D);
void LayoutBitField(const FieldDecl *D);
+ void MSLayoutVirtualBases(const CXXRecordDecl *RD);
+ void MSLayout(const CXXRecordDecl *RD);
/// BaseSubobjectInfoAllocator - Allocator for BaseSubobjectInfo objects.
llvm::SpecificBumpPtrAllocator<BaseSubobjectInfo> BaseSubobjectInfoAllocator;
@@ -663,7 +669,7 @@ protected:
void SelectPrimaryVBase(const CXXRecordDecl *RD);
- virtual CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const;
+ CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const;
/// LayoutNonVirtualBases - Determines the primary base class (if any) and
/// lays it out. Will then proceed to lay out all non-virtual base clasess.
@@ -713,6 +719,8 @@ protected:
void setSize(CharUnits NewSize) { Size = Context.toBits(NewSize); }
void setSize(uint64_t NewSize) { Size = NewSize; }
+ CharUnits getAligment() const { return Alignment; }
+
CharUnits getDataSize() const {
assert(DataSize % Context.getCharWidth() == 0);
return Context.toCharUnitsFromBits(DataSize);
@@ -722,6 +730,11 @@ protected:
void setDataSize(CharUnits NewSize) { DataSize = Context.toBits(NewSize); }
void setDataSize(uint64_t NewSize) { DataSize = NewSize; }
+ bool HasVBPtr(const CXXRecordDecl *RD) const;
+ bool HasNewVirtualFunction(const CXXRecordDecl *RD) const;
+
+ /// Add vbptr or vfptr to layout.
+ void AddVPointer();
RecordLayoutBuilder(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
@@ -729,6 +742,8 @@ public:
static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD);
virtual ~RecordLayoutBuilder() { }
+
+ CharUnits GetVBPtrOffset() const { return VBPtrOffset; }
};
} // end anonymous namespace
@@ -765,7 +780,7 @@ RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
CharUnits
RecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const {
- return Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0));
+ return Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
}
/// DeterminePrimaryBase - Determine the primary base of the given class.
@@ -825,7 +840,7 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
setDataSize(getSize());
CharUnits UnpackedBaseAlign =
- Context.toCharUnitsFromBits(Context.Target.getPointerAlign(0));
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0));
CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign;
// The maximum field alignment overrides base align.
@@ -1046,6 +1061,45 @@ RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
}
}
+void RecordLayoutBuilder::AddVPointer() {
+ CharUnits PtrWidth =
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
+ setSize(getSize() + PtrWidth);
+ setDataSize(getSize());
+
+ if (Alignment > PtrWidth) {
+ setSize(getSize() + (Alignment - PtrWidth));
+ setDataSize(getSize());
+ }
+}
+
+bool
+RecordLayoutBuilder::HasNewVirtualFunction(const CXXRecordDecl *RD) const {
+ for (CXXRecordDecl::method_iterator method = RD->method_begin();
+ method != RD->method_end();
+ ++method) {
+ if (method->isVirtual() &&
+ !method->size_overridden_methods()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+RecordLayoutBuilder::HasVBPtr(const CXXRecordDecl *RD) const {
+ if (!RD->getNumBases())
+ return false;
+
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ if (!I->isVirtual()) {
+ return false;
+ }
+ }
+ return true;
+}
+
void
RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
const CXXRecordDecl *MostDerivedClass) {
@@ -1157,6 +1211,11 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
IsMsStruct = D->hasAttr<MsStructAttr>();
+ // Honor the default struct packing maximum alignment flag.
+ if (unsigned DefaultMaxFieldAlignment = Context.getLangOptions().PackStruct) {
+ MaxFieldAlignment = CharUnits::fromQuantity(DefaultMaxFieldAlignment);
+ }
+
// mac68k alignment supersedes maximum field alignment and attribute aligned,
// and forces all structures to have 2-byte alignment. The IBM docs on it
// allude to additional (more complicated) semantics, especially with regard
@@ -1184,6 +1243,11 @@ void RecordLayoutBuilder::Layout(const RecordDecl *D) {
}
void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
+ if (Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft) {
+ MSLayout(RD);
+ return ;
+ }
+
InitializeLayout(RD);
// Lay out the vtable and the non-virtual bases.
@@ -1193,7 +1257,7 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
NonVirtualSize = Context.toCharUnitsFromBits(
llvm::RoundUpToAlignment(getSizeInBits(),
- Context.Target.getCharAlign()));
+ Context.getTargetInfo().getCharAlign()));
NonVirtualAlignment = Alignment;
// Lay out the virtual bases and add the primary virtual base offsets.
@@ -1242,10 +1306,9 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
}
InitializeLayout(D);
- ObjCInterfaceDecl *OI = const_cast<ObjCInterfaceDecl*>(D);
// Layout each ivar sequentially.
- for (ObjCIvarDecl *IVD = OI->all_declared_ivar_begin();
- IVD; IVD = IVD->getNextIvar())
+ for (const ObjCIvarDecl *IVD = D->all_declared_ivar_begin(); IVD;
+ IVD = IVD->getNextIvar())
LayoutField(IVD);
// Finally, round the size of the total struct up to the alignment of the
@@ -1271,8 +1334,8 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
continue;
// FIXME. streamline these conditions into a simple one.
else if (Context.BitfieldFollowsBitfield(FD, LastFD) ||
- Context.BitfieldFollowsNoneBitfield(FD, LastFD) ||
- Context.NoneBitfieldFollowsBitfield(FD, LastFD)) {
+ Context.BitfieldFollowsNonBitfield(FD, LastFD) ||
+ Context.NonBitfieldFollowsBitfield(FD, LastFD)) {
// 1) Adjacent bit fields are packed into the same 1-, 2-, or
// 4-byte allocation unit if the integral types are the same
// size and if the next bit field fits into the current
@@ -1299,14 +1362,14 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
if (TypeSizeLastFD != TypeSize) {
if (RemainingInAlignment &&
LastFD && LastFD->isBitField() &&
- LastFD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) {
+ LastFD->getBitWidthValue(Context)) {
// If previous field was a bitfield with some remaining unfilled
// bits, pad the field so current field starts on its type boundary.
uint64_t FieldOffset =
getDataSizeInBits() - UnfilledBitsInLastByte;
uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset;
setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
- Context.Target.getCharAlign()));
+ Context.getTargetInfo().getCharAlign()));
setSize(std::max(getSizeInBits(), getDataSizeInBits()));
RemainingInAlignment = 0;
}
@@ -1325,13 +1388,12 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
uint64_t NewSizeInBits =
llvm::RoundUpToAlignment(UnpaddedFieldOffset, FieldAlign);
setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
- Context.Target.getCharAlign()));
+ Context.getTargetInfo().getCharAlign()));
UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
setSize(std::max(getSizeInBits(), getDataSizeInBits()));
}
if (FD->isBitField()) {
- uint64_t FieldSize =
- FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
+ uint64_t FieldSize = FD->getBitWidthValue(Context);
assert (FieldSize > 0 && "LayoutFields - ms_struct layout");
if (RemainingInAlignment < FieldSize)
RemainingInAlignment = TypeSize - FieldSize;
@@ -1340,8 +1402,7 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
}
}
else if (FD->isBitField()) {
- uint64_t FieldSize =
- FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
+ uint64_t FieldSize = FD->getBitWidthValue(Context);
std::pair<uint64_t, unsigned> FieldInfo =
Context.getTypeInfo(FD->getType());
uint64_t TypeSize = FieldInfo.first;
@@ -1349,18 +1410,23 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
}
LastFD = FD;
}
+ else if (!Context.getTargetInfo().useBitFieldTypeAlignment() &&
+ Context.getTargetInfo().useZeroLengthBitfieldAlignment()) {
+ FieldDecl *FD = (*Field);
+ if (FD->isBitField() && FD->getBitWidthValue(Context) == 0)
+ ZeroLengthBitfield = FD;
+ }
LayoutField(*Field);
}
if (IsMsStruct && RemainingInAlignment &&
- LastFD && LastFD->isBitField() &&
- LastFD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) {
+ LastFD && LastFD->isBitField() && LastFD->getBitWidthValue(Context)) {
// If we ended a bitfield before the full length of the type then
// pad the struct out to the full length of the last type.
uint64_t FieldOffset =
getDataSizeInBits() - UnfilledBitsInLastByte;
uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset;
setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
- Context.Target.getCharAlign()));
+ Context.getTargetInfo().getCharAlign()));
setSize(std::max(getSizeInBits(), getDataSizeInBits()));
}
}
@@ -1405,15 +1471,15 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
setDataSize(std::max(getDataSizeInBits(), FieldSize));
FieldOffset = 0;
} else {
- // The bitfield is allocated starting at the next offset aligned appropriately
- // for T', with length n bits.
+ // The bitfield is allocated starting at the next offset aligned
+ // appropriately for T', with length n bits.
FieldOffset = llvm::RoundUpToAlignment(getDataSizeInBits(),
Context.toBits(TypeAlign));
uint64_t NewSizeInBits = FieldOffset + FieldSize;
setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
- Context.Target.getCharAlign()));
+ Context.getTargetInfo().getCharAlign()));
UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
}
@@ -1434,7 +1500,7 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte;
uint64_t FieldOffset = IsUnion ? 0 : UnpaddedFieldOffset;
- uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
+ uint64_t FieldSize = D->getBitWidthValue(Context);
std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType());
uint64_t TypeSize = FieldInfo.first;
@@ -1443,21 +1509,32 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
// This check is needed for 'long long' in -m32 mode.
if (IsMsStruct && (TypeSize > FieldAlign))
FieldAlign = TypeSize;
-
+
if (ZeroLengthBitfield) {
- // If a zero-length bitfield is inserted after a bitfield,
- // and the alignment of the zero-length bitfield is
- // greater than the member that follows it, `bar', `bar'
- // will be aligned as the type of the zero-length bitfield.
- if (ZeroLengthBitfield != D) {
- std::pair<uint64_t, unsigned> FieldInfo =
- Context.getTypeInfo(ZeroLengthBitfield->getType());
- unsigned ZeroLengthBitfieldAlignment = FieldInfo.second;
- // Ignore alignment of subsequent zero-length bitfields.
- if ((ZeroLengthBitfieldAlignment > FieldAlign) || (FieldSize == 0))
- FieldAlign = ZeroLengthBitfieldAlignment;
- if (FieldSize)
- ZeroLengthBitfield = 0;
+ std::pair<uint64_t, unsigned> FieldInfo;
+ unsigned ZeroLengthBitfieldAlignment;
+ if (IsMsStruct) {
+ // If a zero-length bitfield is inserted after a bitfield,
+ // and the alignment of the zero-length bitfield is
+ // greater than the member that follows it, `bar', `bar'
+ // will be aligned as the type of the zero-length bitfield.
+ if (ZeroLengthBitfield != D) {
+ FieldInfo = Context.getTypeInfo(ZeroLengthBitfield->getType());
+ ZeroLengthBitfieldAlignment = FieldInfo.second;
+ // Ignore alignment of subsequent zero-length bitfields.
+ if ((ZeroLengthBitfieldAlignment > FieldAlign) || (FieldSize == 0))
+ FieldAlign = ZeroLengthBitfieldAlignment;
+ if (FieldSize)
+ ZeroLengthBitfield = 0;
+ }
+ } else {
+ // The alignment of a zero-length bitfield affects the alignment
+ // of the next member. The alignment is the max of the zero
+ // length bitfield's alignment and a target specific fixed value.
+ unsigned ZeroLengthBitfieldBoundary =
+ Context.getTargetInfo().getZeroLengthBitfieldBoundary();
+ if (ZeroLengthBitfieldBoundary > FieldAlign)
+ FieldAlign = ZeroLengthBitfieldBoundary;
}
}
@@ -1470,10 +1547,11 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
// was unnecessary (-Wpacked).
unsigned UnpackedFieldAlign = FieldAlign;
uint64_t UnpackedFieldOffset = FieldOffset;
- if (!Context.Target.useBitFieldTypeAlignment())
+ if (!Context.getTargetInfo().useBitFieldTypeAlignment() && !ZeroLengthBitfield)
UnpackedFieldAlign = 1;
- if (FieldPacked || !Context.Target.useBitFieldTypeAlignment())
+ if (FieldPacked ||
+ (!Context.getTargetInfo().useBitFieldTypeAlignment() && !ZeroLengthBitfield))
FieldAlign = 1;
FieldAlign = std::max(FieldAlign, D->getMaxAlignment());
UnpackedFieldAlign = std::max(UnpackedFieldAlign, D->getMaxAlignment());
@@ -1494,10 +1572,14 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
UnpackedFieldAlign);
- // Padding members don't affect overall alignment.
- if (!D->getIdentifier())
+ // Padding members don't affect overall alignment, unless zero length bitfield
+ // alignment is enabled.
+ if (!D->getIdentifier() && !Context.getTargetInfo().useZeroLengthBitfieldAlignment())
FieldAlign = UnpackedFieldAlign = 1;
+ if (!IsMsStruct)
+ ZeroLengthBitfield = 0;
+
// Place this field at the current location.
FieldOffsets.push_back(FieldOffset);
@@ -1512,7 +1594,7 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
uint64_t NewSizeInBits = FieldOffset + FieldSize;
setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
- Context.Target.getCharAlign()));
+ Context.getTargetInfo().getCharAlign()));
UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
}
@@ -1552,25 +1634,36 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
} else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
unsigned AS = RT->getPointeeType().getAddressSpace();
FieldSize =
- Context.toCharUnitsFromBits(Context.Target.getPointerWidth(AS));
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(AS));
FieldAlign =
- Context.toCharUnitsFromBits(Context.Target.getPointerAlign(AS));
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(AS));
} else {
std::pair<CharUnits, CharUnits> FieldInfo =
Context.getTypeInfoInChars(D->getType());
FieldSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
-
+
if (ZeroLengthBitfield) {
- // If a zero-length bitfield is inserted after a bitfield,
- // and the alignment of the zero-length bitfield is
- // greater than the member that follows it, `bar', `bar'
- // will be aligned as the type of the zero-length bitfield.
- std::pair<CharUnits, CharUnits> FieldInfo =
- Context.getTypeInfoInChars(ZeroLengthBitfield->getType());
- CharUnits ZeroLengthBitfieldAlignment = FieldInfo.second;
- if (ZeroLengthBitfieldAlignment > FieldAlign)
- FieldAlign = ZeroLengthBitfieldAlignment;
+ CharUnits ZeroLengthBitfieldBoundary =
+ Context.toCharUnitsFromBits(
+ Context.getTargetInfo().getZeroLengthBitfieldBoundary());
+ if (ZeroLengthBitfieldBoundary == CharUnits::Zero()) {
+ // If a zero-length bitfield is inserted after a bitfield,
+ // and the alignment of the zero-length bitfield is
+ // greater than the member that follows it, `bar', `bar'
+ // will be aligned as the type of the zero-length bitfield.
+ std::pair<CharUnits, CharUnits> FieldInfo =
+ Context.getTypeInfoInChars(ZeroLengthBitfield->getType());
+ CharUnits ZeroLengthBitfieldAlignment = FieldInfo.second;
+ if (ZeroLengthBitfieldAlignment > FieldAlign)
+ FieldAlign = ZeroLengthBitfieldAlignment;
+ } else if (ZeroLengthBitfieldBoundary > FieldAlign) {
+ // Align 'bar' based on a fixed alignment specified by the target.
+ assert(Context.getTargetInfo().useZeroLengthBitfieldAlignment() &&
+ "ZeroLengthBitfieldBoundary should only be used in conjunction"
+ " with useZeroLengthBitfieldAlignment.");
+ FieldAlign = ZeroLengthBitfieldBoundary;
+ }
ZeroLengthBitfield = 0;
}
@@ -1641,6 +1734,104 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
UpdateAlignment(FieldAlign, UnpackedFieldAlign);
}
+void RecordLayoutBuilder::MSLayoutVirtualBases(const CXXRecordDecl *RD) {
+
+ if (!RD->getNumVBases())
+ return;
+
+ for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+ E = RD->vbases_end(); I != E; ++I) {
+
+ const CXXRecordDecl* BaseDecl = I->getType()->getAsCXXRecordDecl();
+ const BaseSubobjectInfo* BaseInfo = VirtualBaseInfo.lookup(BaseDecl);
+
+ assert(BaseInfo && "Did not find virtual base info!");
+
+ LayoutVirtualBase(BaseInfo);
+ }
+}
+
+void RecordLayoutBuilder::MSLayout(const CXXRecordDecl *RD) {
+
+ bool IsVBPtrAddedToLayout = false;
+
+ InitializeLayout(RD);
+
+ if (HasVBPtr(RD)) {
+ // If all bases are virtual and the class declares a new virtual function,
+ // MSVC builds a vfptr.
+ if (HasNewVirtualFunction(RD)) {
+ AddVPointer();
+ }
+
+ VBPtrOffset = getSize();
+ AddVPointer();
+ IsVBPtrAddedToLayout = true;
+
+ ComputeBaseSubobjectInfo(RD);
+ } else {
+ LayoutNonVirtualBases(RD);
+ }
+
+ if (RD->getNumVBases() &&
+ !IsVBPtrAddedToLayout) {
+ // Add vbptr.
+ VBPtrOffset = getSize();
+ AddVPointer();
+ }
+
+ LayoutFields(RD);
+
+ NonVirtualSize = Context.toCharUnitsFromBits(
+ llvm::RoundUpToAlignment(getSizeInBits(),
+ Context.getTargetInfo().getCharAlign()));
+ NonVirtualAlignment = Alignment;
+
+ if (NonVirtualSize != NonVirtualSize.RoundUpToAlignment(Alignment)) {
+ CharUnits AlignMember =
+ NonVirtualSize.RoundUpToAlignment(Alignment) - NonVirtualSize;
+
+ setSize(getSize() + AlignMember);
+ setDataSize(getSize());
+
+ NonVirtualSize = Context.toCharUnitsFromBits(
+ llvm::RoundUpToAlignment(getSizeInBits(),
+ Context.getTargetInfo().getCharAlign()));
+ }
+
+ MSLayoutVirtualBases(RD);
+
+ VisitedVirtualBases.clear();
+
+ // Finally, round the size of the total struct up to the alignment of the
+ // struct itself.
+ if (!RD->getNumVBases())
+ FinishLayout(RD);
+
+#ifndef NDEBUG
+ // Check that we have base offsets for all bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ if (I->isVirtual())
+ continue;
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ assert(Bases.count(BaseDecl) && "Did not find base offset!");
+ }
+
+ // And all virtual bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+ E = RD->vbases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ assert(VBases.count(BaseDecl) && "Did not find base offset!");
+ }
+#endif
+}
+
void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
// In C++, records cannot be of size 0.
if (Context.getLangOptions().CPlusPlus && getSizeInBits() == 0) {
@@ -1663,7 +1854,7 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits);
setSize(llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment)));
- unsigned CharBitNum = Context.Target.getCharWidth();
+ unsigned CharBitNum = Context.getTargetInfo().getCharWidth();
if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
// Warn if padding was introduced to the struct/class/union.
if (getSizeInBits() > UnpaddedSize) {
@@ -1718,7 +1909,12 @@ void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset,
if (isa<ObjCIvarDecl>(D))
return;
- unsigned CharBitNum = Context.Target.getCharWidth();
+ // Don't warn about structs created without a SourceLocation. This can
+ // be done by clients of the AST, such as codegen.
+ if (D->getLocation().isInvalid())
+ return;
+
+ unsigned CharBitNum = Context.getTargetInfo().getCharWidth();
// Warn if padding was introduced to the struct/class.
if (!IsUnion && Offset > UnpaddedOffset) {
@@ -1802,36 +1998,18 @@ RecordLayoutBuilder::Diag(SourceLocation Loc, unsigned DiagID) {
return Context.getDiagnostics().Report(Loc, DiagID);
}
-namespace {
- // This class implements layout specific to the Microsoft ABI.
- class MSRecordLayoutBuilder : public RecordLayoutBuilder {
- public:
- MSRecordLayoutBuilder(const ASTContext& Ctx,
- EmptySubobjectMap *EmptySubobjects) :
- RecordLayoutBuilder(Ctx, EmptySubobjects) {}
-
- virtual CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const;
- };
-}
-
-CharUnits
-MSRecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const {
- // We should reserve space for two pointers if the class has both
- // virtual functions and virtual bases.
- CharUnits PointerWidth =
- Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0));
- if (RD->isPolymorphic() && RD->getNumVBases() > 0)
- return 2 * PointerWidth;
- return PointerWidth;
-}
-
/// getASTRecordLayout - Get or compute information about the layout of the
/// specified record (struct/union/class), which indicates its size and field
/// position information.
const ASTRecordLayout &
ASTContext::getASTRecordLayout(const RecordDecl *D) const {
+ // These asserts test different things. A record has a definition
+ // as soon as we begin to parse the definition. That definition is
+ // not a complete definition (which is what isDefinition() tests)
+ // until we *finish* parsing the definition.
D = D->getDefinition();
assert(D && "Cannot get layout of forward declarations!");
+ assert(D->isCompleteDefinition() && "Cannot layout type before complete!");
// Look up this layout, if already laid out, return what we have.
// Note that we can't save a reference to the entry because this function
@@ -1844,25 +2022,44 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
EmptySubobjectMap EmptySubobjects(*this, RD);
- // When compiling for Microsoft, use the special MS builder.
llvm::OwningPtr<RecordLayoutBuilder> Builder;
- switch (Target.getCXXABI()) {
- default:
- Builder.reset(new RecordLayoutBuilder(*this, &EmptySubobjects));
- break;
- case CXXABI_Microsoft:
- Builder.reset(new MSRecordLayoutBuilder(*this, &EmptySubobjects));
- }
+ CharUnits TargetAlign = CharUnits::One();
+
+ Builder.reset(new RecordLayoutBuilder(*this,
+ &EmptySubobjects,
+ TargetAlign));
+
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<RecordLayoutBuilder>
RecordBuilderCleanup(Builder.get());
Builder->Layout(RD);
+ TargetAlign = Builder->getAligment();
+
+ if (getTargetInfo().getCXXABI() == CXXABI_Microsoft &&
+ TargetAlign.getQuantity() > 4) {
+ // MSVC rounds the vtable pointer to the struct alignment in what must
+ // be a multi-pass operation. For now, let the builder figure out the
+ // alignment and recalculate the layout once its known.
+ Builder.reset(new RecordLayoutBuilder(*this,
+ &EmptySubobjects,
+ TargetAlign));
+
+ Builder->Layout(RD);
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<RecordLayoutBuilder>
+ RecordBuilderCleanup(Builder.get());
+ }
+
// 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.
- bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD();
+ // This does not affect the calculations of MSVC layouts
+ bool IsPODForThePurposeOfLayout =
+ (getTargetInfo().getCXXABI() == CXXABI_Microsoft) ||
+ cast<CXXRecordDecl>(D)->isPOD();
// FIXME: This should be done in FinalizeLayout.
CharUnits DataSize =
@@ -1873,6 +2070,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
NewEntry =
new (*this) ASTRecordLayout(*this, Builder->getSize(),
Builder->Alignment,
+ Builder->GetVBPtrOffset(),
DataSize,
Builder->FieldOffsets.data(),
Builder->FieldOffsets.size(),
@@ -1883,7 +2081,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
Builder->PrimaryBaseIsVirtual,
Builder->Bases, Builder->VBases);
} else {
- RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
+ RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0, CharUnits::One());
Builder.Layout(D);
NewEntry =
@@ -1915,8 +2113,8 @@ const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) {
return Entry;
}
-/// getInterfaceLayoutImpl - Get or compute information about the
-/// layout of the given interface.
+/// getObjCLayout - Get or compute information about the layout of the
+/// given interface.
///
/// \param Impl - If given, also include the layout of the interface's
/// implementation. This may differ by including synthesized ivars.
@@ -1942,7 +2140,7 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
return getObjCLayout(D, 0);
}
- RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
+ RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0, CharUnits::One());
Builder.Layout(D);
const ASTRecordLayout *NewEntry =
@@ -1957,13 +2155,13 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
return *NewEntry;
}
-static void PrintOffset(llvm::raw_ostream &OS,
+static void PrintOffset(raw_ostream &OS,
CharUnits Offset, unsigned IndentLevel) {
OS << llvm::format("%4d | ", Offset.getQuantity());
OS.indent(IndentLevel * 2);
}
-static void DumpCXXRecordLayout(llvm::raw_ostream &OS,
+static void DumpCXXRecordLayout(raw_ostream &OS,
const CXXRecordDecl *RD, const ASTContext &C,
CharUnits Offset,
unsigned IndentLevel,
@@ -1982,12 +2180,22 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS,
IndentLevel++;
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+ bool HasVbptr = Layout.getVBPtrOffset() != CharUnits::fromQuantity(-1);
// Vtable pointer.
if (RD->isDynamicClass() && !PrimaryBase) {
PrintOffset(OS, Offset, IndentLevel);
- OS << '(' << RD << " vtable pointer)\n";
+ OS << '(' << *RD << " vtable pointer)\n";
+ }
+
+ if (HasVbptr && !PrimaryBase) {
+ PrintOffset(OS, Offset + Layout.getVBPtrOffset(), IndentLevel);
+ OS << '(' << *RD << " vbtable pointer)\n";
+
+ // one vbtable per class
+ HasVbptr = false;
}
+
// Dump (non-virtual) bases
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
@@ -2005,6 +2213,11 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS,
Base == PrimaryBase ? "(primary base)" : "(base)",
/*IncludeVirtualBases=*/false);
}
+ // vbptr
+ if (HasVbptr) {
+ PrintOffset(OS, Offset + Layout.getVBPtrOffset(), IndentLevel);
+ OS << '(' << *RD << " vbtable pointer)\n";
+ }
// Dump fields.
uint64_t FieldNo = 0;
@@ -2024,7 +2237,7 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS,
}
PrintOffset(OS, FieldOffset, IndentLevel);
- OS << Field->getType().getAsString() << ' ' << Field << '\n';
+ OS << Field->getType().getAsString() << ' ' << *Field << '\n';
}
if (!IncludeVirtualBases)
@@ -2053,7 +2266,7 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS,
}
void ASTContext::DumpRecordLayout(const RecordDecl *RD,
- llvm::raw_ostream &OS) const {
+ raw_ostream &OS) const {
const ASTRecordLayout &Info = getASTRecordLayout(RD);
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
diff --git a/lib/AST/SelectorLocationsKind.cpp b/lib/AST/SelectorLocationsKind.cpp
new file mode 100644
index 000000000000..671207a7f2d9
--- /dev/null
+++ b/lib/AST/SelectorLocationsKind.cpp
@@ -0,0 +1,128 @@
+//===--- SelectorLocationsKind.cpp - Kind of selector locations -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Describes whether the identifier locations for a selector are "standard"
+// or not.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/SelectorLocationsKind.h"
+#include "clang/AST/Expr.h"
+
+using namespace clang;
+
+static SourceLocation getStandardSelLoc(unsigned Index,
+ Selector Sel,
+ bool WithArgSpace,
+ SourceLocation ArgLoc,
+ SourceLocation EndLoc) {
+ unsigned NumSelArgs = Sel.getNumArgs();
+ if (NumSelArgs == 0) {
+ assert(Index == 0);
+ if (EndLoc.isInvalid())
+ return SourceLocation();
+ IdentifierInfo *II = Sel.getIdentifierInfoForSlot(0);
+ unsigned Len = II ? II->getLength() : 0;
+ return EndLoc.getLocWithOffset(-Len);
+ }
+
+ assert(Index < NumSelArgs);
+ if (ArgLoc.isInvalid())
+ return SourceLocation();
+ IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Index);
+ unsigned Len = /* selector id */ (II ? II->getLength() : 0) + /* ':' */ 1;
+ if (WithArgSpace)
+ ++Len;
+ return ArgLoc.getLocWithOffset(-Len);
+}
+
+namespace {
+
+template <typename T>
+SourceLocation getArgLoc(T* Arg);
+
+template <>
+SourceLocation getArgLoc<Expr>(Expr *Arg) {
+ return Arg->getLocStart();
+}
+
+template <>
+SourceLocation getArgLoc<ParmVarDecl>(ParmVarDecl *Arg) {
+ SourceLocation Loc = Arg->getLocStart();
+ if (Loc.isInvalid())
+ return Loc;
+ // -1 to point to left paren of the method parameter's type.
+ return Loc.getLocWithOffset(-1);
+}
+
+template <typename T>
+SourceLocation getArgLoc(unsigned Index, ArrayRef<T*> Args) {
+ return Index < Args.size() ? getArgLoc(Args[Index]) : SourceLocation();
+}
+
+template <typename T>
+SelectorLocationsKind hasStandardSelLocs(Selector Sel,
+ ArrayRef<SourceLocation> SelLocs,
+ ArrayRef<T *> Args,
+ SourceLocation EndLoc) {
+ // Are selector locations in standard position with no space between args ?
+ unsigned i;
+ for (i = 0; i != SelLocs.size(); ++i) {
+ if (SelLocs[i] != getStandardSelectorLoc(i, Sel, /*WithArgSpace=*/false,
+ Args, EndLoc))
+ break;
+ }
+ if (i == SelLocs.size())
+ return SelLoc_StandardNoSpace;
+
+ // Are selector locations in standard position with space between args ?
+ for (i = 0; i != SelLocs.size(); ++i) {
+ if (SelLocs[i] != getStandardSelectorLoc(i, Sel, /*WithArgSpace=*/true,
+ Args, EndLoc))
+ return SelLoc_NonStandard;
+ }
+
+ return SelLoc_StandardWithSpace;
+}
+
+} // anonymous namespace
+
+SelectorLocationsKind
+clang::hasStandardSelectorLocs(Selector Sel,
+ ArrayRef<SourceLocation> SelLocs,
+ ArrayRef<Expr *> Args,
+ SourceLocation EndLoc) {
+ return hasStandardSelLocs(Sel, SelLocs, Args, EndLoc);
+}
+
+SourceLocation clang::getStandardSelectorLoc(unsigned Index,
+ Selector Sel,
+ bool WithArgSpace,
+ ArrayRef<Expr *> Args,
+ SourceLocation EndLoc) {
+ return getStandardSelLoc(Index, Sel, WithArgSpace,
+ getArgLoc(Index, Args), EndLoc);
+}
+
+SelectorLocationsKind
+clang::hasStandardSelectorLocs(Selector Sel,
+ ArrayRef<SourceLocation> SelLocs,
+ ArrayRef<ParmVarDecl *> Args,
+ SourceLocation EndLoc) {
+ return hasStandardSelLocs(Sel, SelLocs, Args, EndLoc);
+}
+
+SourceLocation clang::getStandardSelectorLoc(unsigned Index,
+ Selector Sel,
+ bool WithArgSpace,
+ ArrayRef<ParmVarDecl *> Args,
+ SourceLocation EndLoc) {
+ return getStandardSelLoc(Index, Sel, WithArgSpace,
+ getArgLoc(Index, Args), EndLoc);
+}
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index fd6f21d43b59..e7b87e4db679 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -97,6 +97,22 @@ Stmt *Stmt::IgnoreImplicit() {
return s;
}
+/// \brief Strip off all label-like statements.
+///
+/// This will strip off label statements, case statements, and default
+/// statements recursively.
+const Stmt *Stmt::stripLabelLikeStatements() const {
+ const Stmt *S = this;
+ while (true) {
+ if (const LabelStmt *LS = dyn_cast<LabelStmt>(S))
+ S = LS->getSubStmt();
+ else if (const SwitchCase *SC = dyn_cast<SwitchCase>(S))
+ S = SC->getSubStmt();
+ else
+ return S;
+ }
+}
+
namespace {
struct good {};
struct bad {};
@@ -214,7 +230,7 @@ Expr *AsmStmt::getOutputExpr(unsigned i) {
/// getOutputConstraint - Return the constraint string for the specified
/// output operand. All output constraints are known to be non-empty (either
/// '=' or '+').
-llvm::StringRef AsmStmt::getOutputConstraint(unsigned i) const {
+StringRef AsmStmt::getOutputConstraint(unsigned i) const {
return getOutputConstraintLiteral(i)->getString();
}
@@ -238,7 +254,7 @@ void AsmStmt::setInputExpr(unsigned i, Expr *E) {
/// getInputConstraint - Return the specified input constraint. Unlike output
/// constraints, these can be empty.
-llvm::StringRef AsmStmt::getInputConstraint(unsigned i) const {
+StringRef AsmStmt::getInputConstraint(unsigned i) const {
return getInputConstraintLiteral(i)->getString();
}
@@ -277,7 +293,7 @@ void AsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C,
/// getNamedOperand - Given a symbolic operand reference like %[foo],
/// translate this into a numeric value needed to reference the same operand.
/// This returns -1 if the operand name is invalid.
-int AsmStmt::getNamedOperand(llvm::StringRef SymbolicName) const {
+int AsmStmt::getNamedOperand(StringRef SymbolicName) const {
unsigned NumPlusOperands = 0;
// Check if this is an output operand.
@@ -297,9 +313,9 @@ int AsmStmt::getNamedOperand(llvm::StringRef SymbolicName) const {
/// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing
/// it into pieces. If the asm string is erroneous, emit errors and return
/// true, otherwise return false.
-unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
+unsigned AsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
ASTContext &C, unsigned &DiagOffs) const {
- llvm::StringRef Str = getAsmString()->getString();
+ StringRef Str = getAsmString()->getString();
const char *StrStart = Str.begin();
const char *StrEnd = Str.end();
const char *CurPtr = StrStart;
@@ -326,7 +342,7 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
// asm string.
std::string CurStringPiece;
- bool HasVariants = !C.Target.hasNoAsmVariants();
+ bool HasVariants = !C.getTargetInfo().hasNoAsmVariants();
while (1) {
// Done with the string?
@@ -416,7 +432,7 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
if (NameEnd == CurPtr)
return diag::err_asm_empty_symbolic_operand_name;
- llvm::StringRef SymbolicName(CurPtr, NameEnd - CurPtr);
+ StringRef SymbolicName(CurPtr, NameEnd - CurPtr);
int N = getNamedOperand(SymbolicName);
if (N == -1) {
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index fb024f33ab30..2968739c227a 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -27,7 +27,7 @@ using namespace clang;
namespace {
class StmtDumper : public StmtVisitor<StmtDumper> {
SourceManager *SM;
- llvm::raw_ostream &OS;
+ raw_ostream &OS;
unsigned IndentLevel;
/// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump
@@ -41,7 +41,7 @@ namespace {
unsigned LastLocLine;
public:
- StmtDumper(SourceManager *sm, llvm::raw_ostream &os, unsigned maxDepth)
+ StmtDumper(SourceManager *sm, raw_ostream &os, unsigned maxDepth)
: SM(sm), OS(os), IndentLevel(0-1), MaxDepth(maxDepth) {
LastLocFilename = "";
LastLocLine = ~0U;
@@ -235,9 +235,9 @@ void StmtDumper::DumpDeclarator(Decl *D) {
// nodes are where they need to be.
if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) {
OS << "\"typedef " << localType->getUnderlyingType().getAsString()
- << ' ' << localType << '"';
+ << ' ' << *localType << '"';
} else if (TypeAliasDecl *localType = dyn_cast<TypeAliasDecl>(D)) {
- OS << "\"using " << localType << " = "
+ OS << "\"using " << *localType << " = "
<< localType->getUnderlyingType().getAsString() << '"';
} else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
OS << "\"";
@@ -294,7 +294,7 @@ void StmtDumper::DumpDeclarator(Decl *D) {
DumpSubTree(SAD->getMessage());
OS << ");\"";
} else {
- assert(0 && "Unexpected decl");
+ llvm_unreachable("Unexpected decl");
}
}
@@ -333,7 +333,7 @@ void StmtDumper::VisitExpr(Expr *Node) {
DumpExpr(Node);
}
-static void DumpBasePath(llvm::raw_ostream &OS, CastExpr *Node) {
+static void DumpBasePath(raw_ostream &OS, CastExpr *Node) {
if (Node->path_empty())
return;
@@ -407,7 +407,7 @@ void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
DumpExpr(Node);
OS << " " << Node->getDecl()->getDeclKindName()
- << "Decl='" << Node->getDecl()
+ << "Decl='" << *Node->getDecl()
<< "' " << (void*)Node->getDecl();
if (Node->isFreeIvar())
OS << " isFreeIvar";
@@ -416,7 +416,7 @@ void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
void StmtDumper::VisitPredefinedExpr(PredefinedExpr *Node) {
DumpExpr(Node);
switch (Node->getIdentType()) {
- default: assert(0 && "unknown case");
+ default: llvm_unreachable("unknown case");
case PredefinedExpr::Func: OS << " __func__"; break;
case PredefinedExpr::Function: OS << " __FUNCTION__"; break;
case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break;
@@ -443,8 +443,13 @@ void StmtDumper::VisitStringLiteral(StringLiteral *Str) {
DumpExpr(Str);
// FIXME: this doesn't print wstrings right.
OS << " ";
- if (Str->isWide())
- OS << "L";
+ switch (Str->getKind()) {
+ case StringLiteral::Ascii: break; // No prefix
+ case StringLiteral::Wide: OS << 'L'; break;
+ case StringLiteral::UTF8: OS << "u8"; break;
+ case StringLiteral::UTF16: OS << 'u'; break;
+ case StringLiteral::UTF32: OS << 'U'; break;
+ }
OS << '"';
OS.write_escaped(Str->getString());
OS << '"';
@@ -475,7 +480,7 @@ void StmtDumper::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) {
void StmtDumper::VisitMemberExpr(MemberExpr *Node) {
DumpExpr(Node);
OS << " " << (Node->isArrow() ? "->" : ".")
- << Node->getMemberDecl() << ' '
+ << *Node->getMemberDecl() << ' '
<< (void*)Node->getMemberDecl();
}
void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
@@ -552,7 +557,8 @@ void StmtDumper::VisitCXXThisExpr(CXXThisExpr *Node) {
void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
DumpExpr(Node);
- OS << " functional cast to " << Node->getTypeAsWritten().getAsString();
+ OS << " functional cast to " << Node->getTypeAsWritten().getAsString()
+ << " <" << Node->getCastKindName() << ">";
}
void StmtDumper::VisitCXXConstructExpr(CXXConstructExpr *Node) {
@@ -637,7 +643,7 @@ void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
DumpExpr(Node);
- OS << ' ' << Node->getProtocol();
+ OS << ' ' <<* Node->getProtocol();
}
void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
@@ -656,7 +662,7 @@ void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
OS << "(null)";
OS << "\"";
} else {
- OS << " Kind=PropertyRef Property=\"" << Node->getExplicitProperty() << '"';
+ OS << " Kind=PropertyRef Property=\"" << *Node->getExplicitProperty() <<'"';
}
if (Node->isSuperReceiver())
@@ -674,7 +680,7 @@ void Stmt::dump(SourceManager &SM) const {
dump(llvm::errs(), SM);
}
-void Stmt::dump(llvm::raw_ostream &OS, SourceManager &SM) const {
+void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
StmtDumper P(&SM, OS, 4);
P.DumpSubTree(const_cast<Stmt*>(this));
OS << "\n";
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index f705a84c7cf4..daaa354ac342 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -28,14 +28,14 @@ using namespace clang;
namespace {
class StmtPrinter : public StmtVisitor<StmtPrinter> {
- llvm::raw_ostream &OS;
+ raw_ostream &OS;
ASTContext &Context;
unsigned IndentLevel;
clang::PrinterHelper* Helper;
PrintingPolicy Policy;
public:
- StmtPrinter(llvm::raw_ostream &os, ASTContext &C, PrinterHelper* helper,
+ StmtPrinter(raw_ostream &os, ASTContext &C, PrinterHelper* helper,
const PrintingPolicy &Policy,
unsigned Indentation = 0)
: OS(os), Context(C), IndentLevel(Indentation), Helper(helper),
@@ -76,7 +76,7 @@ namespace {
OS << "<null expr>";
}
- llvm::raw_ostream &Indent(int Delta = 0) {
+ raw_ostream &Indent(int Delta = 0) {
for (int i = 0, e = IndentLevel+Delta; i < e; ++i)
OS << " ";
return OS;
@@ -124,7 +124,7 @@ void StmtPrinter::PrintRawDecl(Decl *D) {
void StmtPrinter::PrintRawDeclStmt(DeclStmt *S) {
DeclStmt::decl_iterator Begin = S->decl_begin(), End = S->decl_end();
- llvm::SmallVector<Decl*, 2> Decls;
+ SmallVector<Decl*, 2> Decls;
for ( ; Begin != End; ++Begin)
Decls.push_back(*Begin);
@@ -564,7 +564,7 @@ void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
PrintExpr(Node->getBase());
OS << (Node->isArrow() ? "->" : ".");
}
- OS << Node->getDecl();
+ OS << *Node->getDecl();
}
void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
@@ -584,7 +584,7 @@ void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) {
switch (Node->getIdentType()) {
default:
- assert(0 && "unknown case");
+ llvm_unreachable("unknown case");
case PredefinedExpr::Func:
OS << "__func__";
break;
@@ -599,8 +599,14 @@ void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) {
void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) {
unsigned value = Node->getValue();
- if (Node->isWide())
- OS << "L";
+
+ switch (Node->getKind()) {
+ case CharacterLiteral::Ascii: break; // no prefix.
+ case CharacterLiteral::Wide: OS << 'L'; break;
+ case CharacterLiteral::UTF16: OS << 'u'; break;
+ case CharacterLiteral::UTF32: OS << 'U'; break;
+ }
+
switch (value) {
case '\\':
OS << "'\\\\'";
@@ -652,7 +658,7 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
// Emit suffixes. Integer literals are always a builtin integer type.
switch (Node->getType()->getAs<BuiltinType>()->getKind()) {
- default: assert(0 && "Unexpected type for integer literal!");
+ default: llvm_unreachable("Unexpected type for integer literal!");
case BuiltinType::Int: break; // no suffix.
case BuiltinType::UInt: OS << 'U'; break;
case BuiltinType::Long: OS << 'L'; break;
@@ -662,8 +668,9 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
}
}
void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) {
- // FIXME: print value more precisely.
- OS << Node->getValueAsApproximateDouble();
+ llvm::SmallString<16> Str;
+ Node->getValue().toString(Str);
+ OS << Str;
}
void StmtPrinter::VisitImaginaryLiteral(ImaginaryLiteral *Node) {
@@ -672,12 +679,18 @@ void StmtPrinter::VisitImaginaryLiteral(ImaginaryLiteral *Node) {
}
void StmtPrinter::VisitStringLiteral(StringLiteral *Str) {
- if (Str->isWide()) OS << 'L';
+ switch (Str->getKind()) {
+ case StringLiteral::Ascii: break; // no prefix.
+ case StringLiteral::Wide: OS << 'L'; break;
+ case StringLiteral::UTF8: OS << "u8"; break;
+ case StringLiteral::UTF16: OS << 'u'; break;
+ case StringLiteral::UTF32: OS << 'U'; break;
+ }
OS << '"';
// FIXME: this doesn't print wstrings right.
- llvm::StringRef StrData = Str->getString();
- for (llvm::StringRef::iterator I = StrData.begin(), E = StrData.end();
+ StringRef StrData = Str->getString();
+ for (StringRef::iterator I = StrData.begin(), E = StrData.end();
I != E; ++I) {
unsigned char Char = *I;
@@ -998,6 +1011,59 @@ void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
OS << ")";
}
+void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) {
+ const char *Name = 0;
+ switch (Node->getOp()) {
+ case AtomicExpr::Load:
+ Name = "__atomic_load(";
+ break;
+ case AtomicExpr::Store:
+ Name = "__atomic_store(";
+ break;
+ case AtomicExpr::CmpXchgStrong:
+ Name = "__atomic_compare_exchange_strong(";
+ break;
+ case AtomicExpr::CmpXchgWeak:
+ Name = "__atomic_compare_exchange_weak(";
+ break;
+ case AtomicExpr::Xchg:
+ Name = "__atomic_exchange(";
+ break;
+ case AtomicExpr::Add:
+ Name = "__atomic_fetch_add(";
+ break;
+ case AtomicExpr::Sub:
+ Name = "__atomic_fetch_sub(";
+ break;
+ case AtomicExpr::And:
+ Name = "__atomic_fetch_and(";
+ break;
+ case AtomicExpr::Or:
+ Name = "__atomic_fetch_or(";
+ break;
+ case AtomicExpr::Xor:
+ Name = "__atomic_fetch_xor(";
+ break;
+ }
+ OS << Name;
+ PrintExpr(Node->getPtr());
+ OS << ", ";
+ if (Node->getOp() != AtomicExpr::Load) {
+ PrintExpr(Node->getVal1());
+ OS << ", ";
+ }
+ if (Node->isCmpXChg()) {
+ PrintExpr(Node->getVal2());
+ OS << ", ";
+ }
+ PrintExpr(Node->getOrder());
+ if (Node->isCmpXChg()) {
+ OS << ", ";
+ PrintExpr(Node->getOrderFail());
+ }
+ OS << ")";
+}
+
// C++
void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) {
const char *OpStrings[NUM_OVERLOADED_OPERATORS] = {
@@ -1039,7 +1105,7 @@ void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) {
OS << ' ' << OpStrings[Kind] << ' ';
PrintExpr(Node->getArg(1));
} else {
- assert(false && "unknown overloaded operator");
+ llvm_unreachable("unknown overloaded operator");
}
}
@@ -1438,7 +1504,7 @@ void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
}
void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
- OS << "@protocol(" << Node->getProtocol() << ')';
+ OS << "@protocol(" << *Node->getProtocol() << ')';
}
void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
@@ -1520,7 +1586,7 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
}
void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) {
- OS << Node->getDecl();
+ OS << *Node->getDecl();
}
void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {}
@@ -1541,7 +1607,7 @@ void Stmt::dumpPretty(ASTContext& Context) const {
PrintingPolicy(Context.getLangOptions()));
}
-void Stmt::printPretty(llvm::raw_ostream &OS, ASTContext& Context,
+void Stmt::printPretty(raw_ostream &OS, ASTContext& Context,
PrinterHelper* Helper,
const PrintingPolicy &Policy,
unsigned Indentation) const {
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 120c9e50a92a..214378a974a6 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -252,7 +252,7 @@ void StmtProfiler::VisitIntegerLiteral(const IntegerLiteral *S) {
void StmtProfiler::VisitCharacterLiteral(const CharacterLiteral *S) {
VisitExpr(S);
- ID.AddBoolean(S->isWide());
+ ID.AddInteger(S->getKind());
ID.AddInteger(S->getValue());
}
@@ -269,7 +269,7 @@ void StmtProfiler::VisitImaginaryLiteral(const ImaginaryLiteral *S) {
void StmtProfiler::VisitStringLiteral(const StringLiteral *S) {
VisitExpr(S);
ID.AddString(S->getString());
- ID.AddBoolean(S->isWide());
+ ID.AddInteger(S->getKind());
}
void StmtProfiler::VisitParenExpr(const ParenExpr *S) {
@@ -468,6 +468,11 @@ void StmtProfiler::VisitGenericSelectionExpr(const GenericSelectionExpr *S) {
}
}
+void StmtProfiler::VisitAtomicExpr(const AtomicExpr *S) {
+ VisitExpr(S);
+ ID.AddInteger(S->getOp());
+}
+
static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S,
UnaryOperatorKind &UnaryOp,
BinaryOperatorKind &BinaryOp) {
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index 56c6e7bc47c1..0c011a8ef090 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -33,7 +33,7 @@ using namespace clang;
///
/// \param Out the raw_ostream instance to use for printing.
static void printIntegral(const TemplateArgument &TemplArg,
- llvm::raw_ostream &Out) {
+ raw_ostream &Out) {
const ::clang::Type *T = TemplArg.getIntegralType().getTypePtr();
const llvm::APSInt *Val = TemplArg.getAsIntegral();
@@ -68,8 +68,7 @@ TemplateArgument TemplateArgument::CreatePackCopy(ASTContext &Context,
bool TemplateArgument::isDependent() const {
switch (getKind()) {
case Null:
- assert(false && "Should not have a NULL template argument");
- return false;
+ llvm_unreachable("Should not have a NULL template argument");
case Type:
return getAsType()->isDependentType();
@@ -107,8 +106,7 @@ bool TemplateArgument::isDependent() const {
bool TemplateArgument::isInstantiationDependent() const {
switch (getKind()) {
case Null:
- assert(false && "Should not have a NULL template argument");
- return false;
+ llvm_unreachable("Should not have a NULL template argument");
case Type:
return getAsType()->isInstantiationDependentType();
@@ -309,7 +307,7 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const {
}
void TemplateArgument::print(const PrintingPolicy &Policy,
- llvm::raw_ostream &Out) const {
+ raw_ostream &Out) const {
switch (getKind()) {
case Null:
Out << "<no value>";
@@ -530,3 +528,65 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
return DB;
}
+
+const ASTTemplateArgumentListInfo *
+ASTTemplateArgumentListInfo::Create(ASTContext &C,
+ const TemplateArgumentListInfo &List) {
+ std::size_t size = sizeof(CXXDependentScopeMemberExpr) +
+ ASTTemplateArgumentListInfo::sizeFor(List);
+ void *Mem = C.Allocate(size, llvm::alignOf<ASTTemplateArgumentListInfo>());
+ ASTTemplateArgumentListInfo *TAI = new (Mem) ASTTemplateArgumentListInfo();
+ TAI->initializeFrom(List);
+ return TAI;
+}
+
+void ASTTemplateArgumentListInfo::initializeFrom(
+ const TemplateArgumentListInfo &Info) {
+ LAngleLoc = Info.getLAngleLoc();
+ RAngleLoc = Info.getRAngleLoc();
+ NumTemplateArgs = Info.size();
+
+ TemplateArgumentLoc *ArgBuffer = getTemplateArgs();
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
+ new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]);
+}
+
+void ASTTemplateArgumentListInfo::initializeFrom(
+ const TemplateArgumentListInfo &Info,
+ bool &Dependent,
+ bool &InstantiationDependent,
+ bool &ContainsUnexpandedParameterPack) {
+ LAngleLoc = Info.getLAngleLoc();
+ RAngleLoc = Info.getRAngleLoc();
+ NumTemplateArgs = Info.size();
+
+ TemplateArgumentLoc *ArgBuffer = getTemplateArgs();
+ for (unsigned i = 0; i != NumTemplateArgs; ++i) {
+ Dependent = Dependent || Info[i].getArgument().isDependent();
+ InstantiationDependent = InstantiationDependent ||
+ Info[i].getArgument().isInstantiationDependent();
+ ContainsUnexpandedParameterPack
+ = ContainsUnexpandedParameterPack ||
+ Info[i].getArgument().containsUnexpandedParameterPack();
+
+ new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]);
+ }
+}
+
+void ASTTemplateArgumentListInfo::copyInto(
+ TemplateArgumentListInfo &Info) const {
+ Info.setLAngleLoc(LAngleLoc);
+ Info.setRAngleLoc(RAngleLoc);
+ for (unsigned I = 0; I != NumTemplateArgs; ++I)
+ Info.addArgument(getTemplateArgs()[I]);
+}
+
+std::size_t ASTTemplateArgumentListInfo::sizeFor(unsigned NumTemplateArgs) {
+ return sizeof(ASTTemplateArgumentListInfo) +
+ sizeof(TemplateArgumentLoc) * NumTemplateArgs;
+}
+
+std::size_t ASTTemplateArgumentListInfo::sizeFor(
+ const TemplateArgumentListInfo &Info) {
+ return sizeFor(Info.size());
+}
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index 1f7b19aae471..a0487ba0593b 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -125,16 +125,16 @@ bool TemplateName::containsUnexpandedParameterPack() const {
}
void
-TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
+TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
bool SuppressNNS) const {
if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
- OS << Template;
+ OS << *Template;
else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
if (!SuppressNNS)
QTN->getQualifier()->print(OS, Policy);
if (QTN->hasTemplateKeyword())
OS << "template ";
- OS << QTN->getDecl();
+ OS << *QTN->getDecl();
} else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
if (!SuppressNNS && DTN->getQualifier())
DTN->getQualifier()->print(OS, Policy);
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 08971eb03421..44eeec004f57 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -42,6 +42,26 @@ bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const {
(hasObjCLifetime() && !Other.hasObjCLifetime()));
}
+const IdentifierInfo* QualType::getBaseTypeIdentifier() const {
+ const Type* ty = getTypePtr();
+ NamedDecl *ND = NULL;
+ if (ty->isPointerType() || ty->isReferenceType())
+ return ty->getPointeeType().getBaseTypeIdentifier();
+ else if (ty->isRecordType())
+ ND = ty->getAs<RecordType>()->getDecl();
+ else if (ty->isEnumeralType())
+ ND = ty->getAs<EnumType>()->getDecl();
+ else if (ty->getTypeClass() == Type::Typedef)
+ ND = ty->getAs<TypedefType>()->getDecl();
+ else if (ty->isArrayType())
+ return ty->castAsArrayTypeUnsafe()->
+ getElementType().getBaseTypeIdentifier();
+
+ if (ND)
+ return ND->getIdentifier();
+ return NULL;
+}
+
bool QualType::isConstant(QualType T, ASTContext &Ctx) {
if (T.isConstQualified())
return true;
@@ -635,6 +655,18 @@ bool Type::isWideCharType() const {
return false;
}
+bool Type::isChar16Type() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() == BuiltinType::Char16;
+ return false;
+}
+
+bool Type::isChar32Type() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() == BuiltinType::Char32;
+ return false;
+}
+
/// \brief Determine whether this type is any of the built-in character
/// types.
bool Type::isAnyCharacterType() const {
@@ -734,9 +766,16 @@ bool Type::hasUnsignedIntegerRepresentation() const {
return isUnsignedIntegerType();
}
+bool Type::isHalfType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() == BuiltinType::Half;
+ // FIXME: Should we allow complex __fp16? Probably not.
+ return false;
+}
+
bool Type::isFloatingType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
- return BT->getKind() >= BuiltinType::Float &&
+ return BT->getKind() >= BuiltinType::Half &&
BT->getKind() <= BuiltinType::LongDouble;
if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType))
return CT->getElementType()->isFloatingType();
@@ -801,14 +840,16 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const {
const Type *T = CanonicalType.getTypePtr();
if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) {
if (BT->getKind() == BuiltinType::Bool) return STK_Bool;
- if (BT->getKind() == BuiltinType::NullPtr) return STK_Pointer;
+ if (BT->getKind() == BuiltinType::NullPtr) return STK_CPointer;
if (BT->isInteger()) return STK_Integral;
if (BT->isFloatingPoint()) return STK_Floating;
llvm_unreachable("unknown scalar builtin type");
- } else if (isa<PointerType>(T) ||
- isa<BlockPointerType>(T) ||
- isa<ObjCObjectPointerType>(T)) {
- return STK_Pointer;
+ } else if (isa<PointerType>(T)) {
+ return STK_CPointer;
+ } else if (isa<BlockPointerType>(T)) {
+ return STK_BlockPointer;
+ } else if (isa<ObjCObjectPointerType>(T)) {
+ return STK_ObjCObjectPointer;
} else if (isa<MemberPointerType>(T)) {
return STK_MemberPointer;
} else if (isa<EnumType>(T)) {
@@ -821,7 +862,6 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const {
}
llvm_unreachable("unknown scalar type");
- return STK_Pointer;
}
/// \brief Determines whether the type is a C++ aggregate type or C
@@ -872,7 +912,7 @@ bool Type::isIncompleteType() const {
case Record:
// A tagged type (struct/union/enum/class) is incomplete if the decl is a
// forward declaration, but not a full definition (C99 6.2.5p22).
- return !cast<TagType>(CanonicalType)->getDecl()->isDefinition();
+ return !cast<TagType>(CanonicalType)->getDecl()->isCompleteDefinition();
case ConstantArray:
// An array is incomplete if its element type is incomplete
// (C++ [dcl.array]p1).
@@ -1073,7 +1113,7 @@ bool Type::isLiteralType() const {
// C++0x [basic.types]p10:
// A type is a literal type if it is:
// [...]
- // -- an array of literal type
+ // -- an array of literal type.
// Extension: variable arrays cannot be literal types, since they're
// runtime-sized.
if (isVariableArrayType())
@@ -1093,33 +1133,31 @@ bool Type::isLiteralType() const {
// C++0x [basic.types]p10:
// A type is a literal type if it is:
// -- a scalar type; or
- // As an extension, Clang treats vector types as Scalar types.
- if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true;
+ // As an extension, Clang treats vector types as literal types.
+ if (BaseTy->isScalarType() || BaseTy->isVectorType())
+ return true;
// -- a reference type; or
- if (BaseTy->isReferenceType()) return true;
+ if (BaseTy->isReferenceType())
+ return true;
// -- a class type that has all of the following properties:
if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
+ // -- a trivial destructor,
+ // -- every constructor call and full-expression in the
+ // brace-or-equal-initializers for non-static data members (if any)
+ // is a constant expression,
+ // -- it is an aggregate type or has at least one constexpr
+ // constructor or constructor template that is not a copy or move
+ // constructor, and
+ // -- all non-static data members and base classes of literal types
+ //
+ // We resolve DR1361 by ignoring the second bullet.
if (const CXXRecordDecl *ClassDecl =
- dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- // -- a trivial destructor,
- if (!ClassDecl->hasTrivialDestructor()) return false;
- // -- every constructor call and full-expression in the
- // brace-or-equal-initializers for non-static data members (if any)
- // is a constant expression,
- // FIXME: C++0x: Clang doesn't yet support non-static data member
- // declarations with initializers, or constexprs.
- // -- it is an aggregate type or has at least one constexpr
- // constructor or constructor template that is not a copy or move
- // constructor, and
- if (!ClassDecl->isAggregate() &&
- !ClassDecl->hasConstExprNonCopyMoveConstructor())
- return false;
- // -- all non-static data members and base classes of literal types
- if (ClassDecl->hasNonLiteralTypeFieldsOrBases()) return false;
- }
+ dyn_cast<CXXRecordDecl>(RT->getDecl()))
+ return ClassDecl->isLiteral();
return true;
}
+
return false;
}
@@ -1158,7 +1196,7 @@ bool Type::isStandardLayoutType() const {
}
// This is effectively the intersection of isTrivialType and
-// isStandardLayoutType. We implement it dircetly to avoid redundant
+// isStandardLayoutType. We implement it directly to avoid redundant
// conversions from a type to a CXXRecordDecl.
bool QualType::isCXX11PODType(ASTContext &Context) const {
const Type *ty = getTypePtr();
@@ -1426,10 +1464,10 @@ const char *Type::getTypeClassName() const {
return 0;
}
-const char *BuiltinType::getName(const LangOptions &LO) const {
+const char *BuiltinType::getName(const PrintingPolicy &Policy) const {
switch (getKind()) {
case Void: return "void";
- case Bool: return LO.Bool ? "bool" : "_Bool";
+ case Bool: return Policy.Bool ? "bool" : "_Bool";
case Char_S: return "char";
case Char_U: return "char";
case SChar: return "signed char";
@@ -1444,6 +1482,7 @@ const char *BuiltinType::getName(const LangOptions &LO) const {
case ULong: return "unsigned long";
case ULongLong: return "unsigned long long";
case UInt128: return "__uint128_t";
+ case Half: return "half";
case Float: return "float";
case Double: return "double";
case LongDouble: return "long double";
@@ -1481,7 +1520,7 @@ QualType QualType::getNonLValueExprType(ASTContext &Context) const {
return *this;
}
-llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) {
+StringRef FunctionType::getNameForCallConv(CallingConv CC) {
switch (CC) {
case CC_Default:
llvm_unreachable("no name for default cc");
@@ -1716,7 +1755,7 @@ static TagDecl *getInterestingTagDecl(TagDecl *decl) {
for (TagDecl::redecl_iterator I = decl->redecls_begin(),
E = decl->redecls_end();
I != E; ++I) {
- if (I->isDefinition() || I->isBeingDefined())
+ if (I->isCompleteDefinition() || I->isBeingDefined())
return *I;
}
// If there's no definition (not even in progress), return what we have.
@@ -2082,6 +2121,8 @@ static CachedProperties computeCachedProperties(const Type *T) {
return Cache::get(cast<ObjCObjectType>(T)->getBaseType());
case Type::ObjCObjectPointer:
return Cache::get(cast<ObjCObjectPointerType>(T)->getPointeeType());
+ case Type::Atomic:
+ return Cache::get(cast<AtomicType>(T)->getValueType());
}
llvm_unreachable("unhandled type class");
@@ -2227,13 +2268,13 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) {
/// with non-trivial destructors.
const CXXRecordDecl *record =
type->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
- if (record && !record->hasTrivialDestructor())
+ if (record && record->hasDefinition() && !record->hasTrivialDestructor())
return DK_cxx_destructor;
return DK_none;
}
-bool QualType::hasTrivialCopyAssignment(ASTContext &Context) const {
+bool QualType::hasTrivialAssignment(ASTContext &Context, bool Copying) const {
switch (getObjCLifetime()) {
case Qualifiers::OCL_None:
break;
@@ -2249,7 +2290,8 @@ bool QualType::hasTrivialCopyAssignment(ASTContext &Context) const {
if (const CXXRecordDecl *Record
= getTypePtr()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl())
- return Record->hasTrivialCopyAssignment();
+ return Copying ? Record->hasTrivialCopyAssignment() :
+ Record->hasTrivialMoveAssignment();
return true;
}
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 34e7693e3075..8e8b227e1f09 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -206,7 +206,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
case BuiltinType::Char_S:
return TST_char;
case BuiltinType::Char16:
- return TST_char16;
+ return TST_char16;
case BuiltinType::Char32:
return TST_char32;
case BuiltinType::WChar_S:
@@ -225,6 +225,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
case BuiltinType::Long:
case BuiltinType::LongLong:
case BuiltinType::Int128:
+ case BuiltinType::Half:
case BuiltinType::Float:
case BuiltinType::Double:
case BuiltinType::LongDouble:
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index b89d2aa31676..fb7b918ca2fe 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -123,6 +123,7 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
case Type::DependentTemplateSpecialization:
case Type::ObjCObject:
case Type::ObjCInterface:
+ case Type::Atomic:
CanPrefixQualifiers = true;
break;
@@ -205,11 +206,11 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
void TypePrinter::printBuiltin(const BuiltinType *T, std::string &S) {
if (S.empty()) {
- S = T->getName(Policy.LangOpts);
+ S = T->getName(Policy);
} else {
// Prefix the basic type, e.g. 'int X'.
S = ' ' + S;
- S = T->getName(Policy.LangOpts) + S;
+ S = T->getName(Policy) + S;
}
}
@@ -581,6 +582,16 @@ void TypePrinter::printAuto(const AutoType *T, std::string &S) {
}
}
+void TypePrinter::printAtomic(const AtomicType *T, std::string &S) {
+ if (!S.empty())
+ S = ' ' + S;
+ std::string Str;
+ IncludeStrongLifetimeRAII Strong(Policy);
+ print(T->getValueType(), Str);
+
+ S = "_Atomic(" + Str + ")" + S;
+}
+
/// Appends the given scope to the end of a string.
void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) {
if (DC->isTranslationUnit()) return;
diff --git a/lib/AST/VTTBuilder.cpp b/lib/AST/VTTBuilder.cpp
new file mode 100644
index 000000000000..f5ff624cf069
--- /dev/null
+++ b/lib/AST/VTTBuilder.cpp
@@ -0,0 +1,212 @@
+//===--- VTTBuilder.cpp - C++ VTT layout builder --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code dealing with generation of the layout of virtual table
+// tables (VTT).
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/VTTBuilder.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/Support/Format.h"
+#include <algorithm>
+#include <cstdio>
+
+using namespace clang;
+
+#define DUMP_OVERRIDERS 0
+
+VTTBuilder::VTTBuilder(ASTContext &Ctx,
+ const CXXRecordDecl *MostDerivedClass,
+ bool GenerateDefinition)
+ : Ctx(Ctx), MostDerivedClass(MostDerivedClass),
+ MostDerivedClassLayout(Ctx.getASTRecordLayout(MostDerivedClass)),
+ GenerateDefinition(GenerateDefinition) {
+ // Lay out this VTT.
+ LayoutVTT(BaseSubobject(MostDerivedClass, CharUnits::Zero()),
+ /*BaseIsVirtual=*/false);
+}
+
+void VTTBuilder::AddVTablePointer(BaseSubobject Base, uint64_t VTableIndex,
+ const CXXRecordDecl *VTableClass) {
+ // Store the vtable pointer index if we're generating the primary VTT.
+ if (VTableClass == MostDerivedClass) {
+ assert(!SecondaryVirtualPointerIndices.count(Base) &&
+ "A virtual pointer index already exists for this base subobject!");
+ SecondaryVirtualPointerIndices[Base] = VTTComponents.size();
+ }
+
+ if (!GenerateDefinition) {
+ VTTComponents.push_back(VTTComponent());
+ return;
+ }
+
+ VTTComponents.push_back(VTTComponent(VTableIndex, Base));
+}
+
+void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) {
+ const CXXRecordDecl *RD = Base.getBase();
+
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+
+ // Don't layout virtual bases.
+ if (I->isVirtual())
+ continue;
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
+ CharUnits BaseOffset = Base.getBaseOffset() +
+ Layout.getBaseClassOffset(BaseDecl);
+
+ // Layout the VTT for this base.
+ LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false);
+ }
+}
+
+void
+VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
+ bool BaseIsMorallyVirtual,
+ uint64_t VTableIndex,
+ const CXXRecordDecl *VTableClass,
+ VisitedVirtualBasesSetTy &VBases) {
+ const CXXRecordDecl *RD = Base.getBase();
+
+ // We're not interested in bases that don't have virtual bases, and not
+ // morally virtual bases.
+ if (!RD->getNumVBases() && !BaseIsMorallyVirtual)
+ return;
+
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Itanium C++ ABI 2.6.2:
+ // Secondary virtual pointers are present for all bases with either
+ // virtual bases or virtual function declarations overridden along a
+ // virtual path.
+ //
+ // If the base class is not dynamic, we don't want to add it, nor any
+ // of its base classes.
+ if (!BaseDecl->isDynamicClass())
+ continue;
+
+ bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual;
+ bool BaseDeclIsNonVirtualPrimaryBase = false;
+ CharUnits BaseOffset;
+ if (I->isVirtual()) {
+ // Ignore virtual bases that we've already visited.
+ if (!VBases.insert(BaseDecl))
+ continue;
+
+ BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
+ BaseDeclIsMorallyVirtual = true;
+ } else {
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
+
+ BaseOffset = Base.getBaseOffset() +
+ Layout.getBaseClassOffset(BaseDecl);
+
+ if (!Layout.isPrimaryBaseVirtual() &&
+ Layout.getPrimaryBase() == BaseDecl)
+ BaseDeclIsNonVirtualPrimaryBase = true;
+ }
+
+ // Itanium C++ ABI 2.6.2:
+ // Secondary virtual pointers: for each base class X which (a) has virtual
+ // bases or is reachable along a virtual path from D, and (b) is not a
+ // non-virtual primary base, the address of the virtual table for X-in-D
+ // or an appropriate construction virtual table.
+ if (!BaseDeclIsNonVirtualPrimaryBase &&
+ (BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) {
+ // Add the vtable pointer.
+ AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTableIndex,
+ VTableClass);
+ }
+
+ // And lay out the secondary virtual pointers for the base class.
+ LayoutSecondaryVirtualPointers(BaseSubobject(BaseDecl, BaseOffset),
+ BaseDeclIsMorallyVirtual, VTableIndex,
+ VTableClass, VBases);
+ }
+}
+
+void
+VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
+ uint64_t VTableIndex) {
+ VisitedVirtualBasesSetTy VBases;
+ LayoutSecondaryVirtualPointers(Base, /*BaseIsMorallyVirtual=*/false,
+ VTableIndex, Base.getBase(), VBases);
+}
+
+void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD,
+ VisitedVirtualBasesSetTy &VBases) {
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Check if this is a virtual base.
+ if (I->isVirtual()) {
+ // Check if we've seen this base before.
+ if (!VBases.insert(BaseDecl))
+ continue;
+
+ CharUnits BaseOffset =
+ MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
+
+ LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/true);
+ }
+
+ // We only need to layout virtual VTTs for this base if it actually has
+ // virtual bases.
+ if (BaseDecl->getNumVBases())
+ LayoutVirtualVTTs(BaseDecl, VBases);
+ }
+}
+
+void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) {
+ const CXXRecordDecl *RD = Base.getBase();
+
+ // Itanium C++ ABI 2.6.2:
+ // An array of virtual table addresses, called the VTT, is declared for
+ // each class type that has indirect or direct virtual base classes.
+ if (RD->getNumVBases() == 0)
+ return;
+
+ bool IsPrimaryVTT = Base.getBase() == MostDerivedClass;
+
+ if (!IsPrimaryVTT) {
+ // Remember the sub-VTT index.
+ SubVTTIndicies[Base] = VTTComponents.size();
+ }
+
+ uint64_t VTableIndex = VTTVTables.size();
+ VTTVTables.push_back(VTTVTable(Base, BaseIsVirtual));
+
+ // Add the primary vtable pointer.
+ AddVTablePointer(Base, VTableIndex, RD);
+
+ // Add the secondary VTTs.
+ LayoutSecondaryVTTs(Base);
+
+ // Add the secondary virtual pointers.
+ LayoutSecondaryVirtualPointers(Base, VTableIndex);
+
+ // If this is the primary VTT, we want to lay out virtual VTTs as well.
+ if (IsPrimaryVTT) {
+ VisitedVirtualBasesSetTy VBases;
+ LayoutVirtualVTTs(Base.getBase(), VBases);
+ }
+}
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
new file mode 100644
index 000000000000..7765817759a4
--- /dev/null
+++ b/lib/AST/VTableBuilder.cpp
@@ -0,0 +1,2404 @@
+//===--- VTableBuilder.cpp - C++ vtable layout builder --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code dealing with generation of the layout of virtual tables.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/VTableBuilder.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/Support/Format.h"
+#include <algorithm>
+#include <cstdio>
+
+using namespace clang;
+
+#define DUMP_OVERRIDERS 0
+
+namespace {
+
+/// BaseOffset - Represents an offset from a derived class to a direct or
+/// indirect base class.
+struct BaseOffset {
+ /// DerivedClass - The derived class.
+ const CXXRecordDecl *DerivedClass;
+
+ /// VirtualBase - If the path from the derived class to the base class
+ /// involves a virtual base class, this holds its declaration.
+ const CXXRecordDecl *VirtualBase;
+
+ /// NonVirtualOffset - The offset from the derived class to the base class.
+ /// (Or the offset from the virtual base class to the base class, if the
+ /// path from the derived class to the base class involves a virtual base
+ /// class.
+ CharUnits NonVirtualOffset;
+
+ BaseOffset() : DerivedClass(0), VirtualBase(0),
+ NonVirtualOffset(CharUnits::Zero()) { }
+ BaseOffset(const CXXRecordDecl *DerivedClass,
+ const CXXRecordDecl *VirtualBase, CharUnits NonVirtualOffset)
+ : DerivedClass(DerivedClass), VirtualBase(VirtualBase),
+ NonVirtualOffset(NonVirtualOffset) { }
+
+ bool isEmpty() const { return NonVirtualOffset.isZero() && !VirtualBase; }
+};
+
+/// FinalOverriders - Contains the final overrider member functions for all
+/// member functions in the base subobjects of a class.
+class FinalOverriders {
+public:
+ /// OverriderInfo - Information about a final overrider.
+ struct OverriderInfo {
+ /// Method - The method decl of the overrider.
+ const CXXMethodDecl *Method;
+
+ /// Offset - the base offset of the overrider in the layout class.
+ CharUnits Offset;
+
+ OverriderInfo() : Method(0), Offset(CharUnits::Zero()) { }
+ };
+
+private:
+ /// MostDerivedClass - The most derived class for which the final overriders
+ /// are stored.
+ const CXXRecordDecl *MostDerivedClass;
+
+ /// MostDerivedClassOffset - If we're building final overriders for a
+ /// construction vtable, this holds the offset from the layout class to the
+ /// most derived class.
+ const CharUnits MostDerivedClassOffset;
+
+ /// LayoutClass - The class we're using for layout information. Will be
+ /// different than the most derived class if the final overriders are for a
+ /// construction vtable.
+ const CXXRecordDecl *LayoutClass;
+
+ ASTContext &Context;
+
+ /// MostDerivedClassLayout - the AST record layout of the most derived class.
+ const ASTRecordLayout &MostDerivedClassLayout;
+
+ /// MethodBaseOffsetPairTy - Uniquely identifies a member function
+ /// in a base subobject.
+ typedef std::pair<const CXXMethodDecl *, CharUnits> MethodBaseOffsetPairTy;
+
+ typedef llvm::DenseMap<MethodBaseOffsetPairTy,
+ OverriderInfo> OverridersMapTy;
+
+ /// OverridersMap - The final overriders for all virtual member functions of
+ /// all the base subobjects of the most derived class.
+ OverridersMapTy OverridersMap;
+
+ /// SubobjectsToOffsetsMapTy - A mapping from a base subobject (represented
+ /// as a record decl and a subobject number) and its offsets in the most
+ /// derived class as well as the layout class.
+ typedef llvm::DenseMap<std::pair<const CXXRecordDecl *, unsigned>,
+ CharUnits> SubobjectOffsetMapTy;
+
+ typedef llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCountMapTy;
+
+ /// ComputeBaseOffsets - Compute the offsets for all base subobjects of the
+ /// given base.
+ void ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual,
+ CharUnits OffsetInLayoutClass,
+ SubobjectOffsetMapTy &SubobjectOffsets,
+ SubobjectOffsetMapTy &SubobjectLayoutClassOffsets,
+ SubobjectCountMapTy &SubobjectCounts);
+
+ typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
+
+ /// dump - dump the final overriders for a base subobject, and all its direct
+ /// and indirect base subobjects.
+ void dump(raw_ostream &Out, BaseSubobject Base,
+ VisitedVirtualBasesSetTy& VisitedVirtualBases);
+
+public:
+ FinalOverriders(const CXXRecordDecl *MostDerivedClass,
+ CharUnits MostDerivedClassOffset,
+ const CXXRecordDecl *LayoutClass);
+
+ /// getOverrider - Get the final overrider for the given method declaration in
+ /// the subobject with the given base offset.
+ OverriderInfo getOverrider(const CXXMethodDecl *MD,
+ CharUnits BaseOffset) const {
+ assert(OverridersMap.count(std::make_pair(MD, BaseOffset)) &&
+ "Did not find overrider!");
+
+ return OverridersMap.lookup(std::make_pair(MD, BaseOffset));
+ }
+
+ /// dump - dump the final overriders.
+ void dump() {
+ VisitedVirtualBasesSetTy VisitedVirtualBases;
+ dump(llvm::errs(), BaseSubobject(MostDerivedClass, CharUnits::Zero()),
+ VisitedVirtualBases);
+ }
+
+};
+
+#define DUMP_OVERRIDERS 0
+
+FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass,
+ CharUnits MostDerivedClassOffset,
+ const CXXRecordDecl *LayoutClass)
+ : MostDerivedClass(MostDerivedClass),
+ MostDerivedClassOffset(MostDerivedClassOffset), LayoutClass(LayoutClass),
+ Context(MostDerivedClass->getASTContext()),
+ MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)) {
+
+ // Compute base offsets.
+ SubobjectOffsetMapTy SubobjectOffsets;
+ SubobjectOffsetMapTy SubobjectLayoutClassOffsets;
+ SubobjectCountMapTy SubobjectCounts;
+ ComputeBaseOffsets(BaseSubobject(MostDerivedClass, CharUnits::Zero()),
+ /*IsVirtual=*/false,
+ MostDerivedClassOffset,
+ SubobjectOffsets, SubobjectLayoutClassOffsets,
+ SubobjectCounts);
+
+ // Get the the final overriders.
+ CXXFinalOverriderMap FinalOverriders;
+ MostDerivedClass->getFinalOverriders(FinalOverriders);
+
+ for (CXXFinalOverriderMap::const_iterator I = FinalOverriders.begin(),
+ E = FinalOverriders.end(); I != E; ++I) {
+ const CXXMethodDecl *MD = I->first;
+ const OverridingMethods& Methods = I->second;
+
+ for (OverridingMethods::const_iterator I = Methods.begin(),
+ E = Methods.end(); I != E; ++I) {
+ unsigned SubobjectNumber = I->first;
+ assert(SubobjectOffsets.count(std::make_pair(MD->getParent(),
+ SubobjectNumber)) &&
+ "Did not find subobject offset!");
+
+ CharUnits BaseOffset = SubobjectOffsets[std::make_pair(MD->getParent(),
+ SubobjectNumber)];
+
+ assert(I->second.size() == 1 && "Final overrider is not unique!");
+ const UniqueVirtualMethod &Method = I->second.front();
+
+ const CXXRecordDecl *OverriderRD = Method.Method->getParent();
+ assert(SubobjectLayoutClassOffsets.count(
+ std::make_pair(OverriderRD, Method.Subobject))
+ && "Did not find subobject offset!");
+ CharUnits OverriderOffset =
+ SubobjectLayoutClassOffsets[std::make_pair(OverriderRD,
+ Method.Subobject)];
+
+ OverriderInfo& Overrider = OverridersMap[std::make_pair(MD, BaseOffset)];
+ assert(!Overrider.Method && "Overrider should not exist yet!");
+
+ Overrider.Offset = OverriderOffset;
+ Overrider.Method = Method.Method;
+ }
+ }
+
+#if DUMP_OVERRIDERS
+ // And dump them (for now).
+ dump();
+#endif
+}
+
+static BaseOffset ComputeBaseOffset(ASTContext &Context,
+ const CXXRecordDecl *DerivedRD,
+ const CXXBasePath &Path) {
+ CharUnits NonVirtualOffset = CharUnits::Zero();
+
+ unsigned NonVirtualStart = 0;
+ const CXXRecordDecl *VirtualBase = 0;
+
+ // First, look for the virtual base class.
+ for (unsigned I = 0, E = Path.size(); I != E; ++I) {
+ const CXXBasePathElement &Element = Path[I];
+
+ if (Element.Base->isVirtual()) {
+ // FIXME: Can we break when we find the first virtual base?
+ // (If we can't, can't we just iterate over the path in reverse order?)
+ NonVirtualStart = I + 1;
+ QualType VBaseType = Element.Base->getType();
+ VirtualBase =
+ cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
+ }
+ }
+
+ // Now compute the non-virtual offset.
+ for (unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I) {
+ const CXXBasePathElement &Element = Path[I];
+
+ // Check the base class offset.
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class);
+
+ const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>();
+ const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl());
+
+ NonVirtualOffset += Layout.getBaseClassOffset(Base);
+ }
+
+ // FIXME: This should probably use CharUnits or something. Maybe we should
+ // even change the base offsets in ASTRecordLayout to be specified in
+ // CharUnits.
+ return BaseOffset(DerivedRD, VirtualBase, NonVirtualOffset);
+
+}
+
+static BaseOffset ComputeBaseOffset(ASTContext &Context,
+ const CXXRecordDecl *BaseRD,
+ const CXXRecordDecl *DerivedRD) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/false,
+ /*RecordPaths=*/true, /*DetectVirtual=*/false);
+
+ if (!const_cast<CXXRecordDecl *>(DerivedRD)->
+ isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) {
+ llvm_unreachable("Class must be derived from the passed in base class!");
+ }
+
+ return ComputeBaseOffset(Context, DerivedRD, Paths.front());
+}
+
+static BaseOffset
+ComputeReturnAdjustmentBaseOffset(ASTContext &Context,
+ const CXXMethodDecl *DerivedMD,
+ const CXXMethodDecl *BaseMD) {
+ const FunctionType *BaseFT = BaseMD->getType()->getAs<FunctionType>();
+ const FunctionType *DerivedFT = DerivedMD->getType()->getAs<FunctionType>();
+
+ // Canonicalize the return types.
+ CanQualType CanDerivedReturnType =
+ Context.getCanonicalType(DerivedFT->getResultType());
+ CanQualType CanBaseReturnType =
+ Context.getCanonicalType(BaseFT->getResultType());
+
+ assert(CanDerivedReturnType->getTypeClass() ==
+ CanBaseReturnType->getTypeClass() &&
+ "Types must have same type class!");
+
+ if (CanDerivedReturnType == CanBaseReturnType) {
+ // No adjustment needed.
+ return BaseOffset();
+ }
+
+ if (isa<ReferenceType>(CanDerivedReturnType)) {
+ CanDerivedReturnType =
+ CanDerivedReturnType->getAs<ReferenceType>()->getPointeeType();
+ CanBaseReturnType =
+ CanBaseReturnType->getAs<ReferenceType>()->getPointeeType();
+ } else if (isa<PointerType>(CanDerivedReturnType)) {
+ CanDerivedReturnType =
+ CanDerivedReturnType->getAs<PointerType>()->getPointeeType();
+ CanBaseReturnType =
+ CanBaseReturnType->getAs<PointerType>()->getPointeeType();
+ } else {
+ llvm_unreachable("Unexpected return type!");
+ }
+
+ // We need to compare unqualified types here; consider
+ // const T *Base::foo();
+ // T *Derived::foo();
+ if (CanDerivedReturnType.getUnqualifiedType() ==
+ CanBaseReturnType.getUnqualifiedType()) {
+ // No adjustment needed.
+ return BaseOffset();
+ }
+
+ const CXXRecordDecl *DerivedRD =
+ cast<CXXRecordDecl>(cast<RecordType>(CanDerivedReturnType)->getDecl());
+
+ const CXXRecordDecl *BaseRD =
+ cast<CXXRecordDecl>(cast<RecordType>(CanBaseReturnType)->getDecl());
+
+ return ComputeBaseOffset(Context, BaseRD, DerivedRD);
+}
+
+void
+FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual,
+ CharUnits OffsetInLayoutClass,
+ SubobjectOffsetMapTy &SubobjectOffsets,
+ SubobjectOffsetMapTy &SubobjectLayoutClassOffsets,
+ SubobjectCountMapTy &SubobjectCounts) {
+ const CXXRecordDecl *RD = Base.getBase();
+
+ unsigned SubobjectNumber = 0;
+ if (!IsVirtual)
+ SubobjectNumber = ++SubobjectCounts[RD];
+
+ // Set up the subobject to offset mapping.
+ assert(!SubobjectOffsets.count(std::make_pair(RD, SubobjectNumber))
+ && "Subobject offset already exists!");
+ assert(!SubobjectLayoutClassOffsets.count(std::make_pair(RD, SubobjectNumber))
+ && "Subobject offset already exists!");
+
+ SubobjectOffsets[std::make_pair(RD, SubobjectNumber)] = Base.getBaseOffset();
+ SubobjectLayoutClassOffsets[std::make_pair(RD, SubobjectNumber)] =
+ OffsetInLayoutClass;
+
+ // Traverse our bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ CharUnits BaseOffset;
+ CharUnits BaseOffsetInLayoutClass;
+ if (I->isVirtual()) {
+ // Check if we've visited this virtual base before.
+ if (SubobjectOffsets.count(std::make_pair(BaseDecl, 0)))
+ continue;
+
+ const ASTRecordLayout &LayoutClassLayout =
+ Context.getASTRecordLayout(LayoutClass);
+
+ BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
+ BaseOffsetInLayoutClass =
+ LayoutClassLayout.getVBaseClassOffset(BaseDecl);
+ } else {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ CharUnits Offset = Layout.getBaseClassOffset(BaseDecl);
+
+ BaseOffset = Base.getBaseOffset() + Offset;
+ BaseOffsetInLayoutClass = OffsetInLayoutClass + Offset;
+ }
+
+ ComputeBaseOffsets(BaseSubobject(BaseDecl, BaseOffset),
+ I->isVirtual(), BaseOffsetInLayoutClass,
+ SubobjectOffsets, SubobjectLayoutClassOffsets,
+ SubobjectCounts);
+ }
+}
+
+void FinalOverriders::dump(raw_ostream &Out, BaseSubobject Base,
+ VisitedVirtualBasesSetTy &VisitedVirtualBases) {
+ const CXXRecordDecl *RD = Base.getBase();
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore bases that don't have any virtual member functions.
+ if (!BaseDecl->isPolymorphic())
+ continue;
+
+ CharUnits BaseOffset;
+ if (I->isVirtual()) {
+ if (!VisitedVirtualBases.insert(BaseDecl)) {
+ // We've visited this base before.
+ continue;
+ }
+
+ BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
+ } else {
+ BaseOffset = Layout.getBaseClassOffset(BaseDecl) + Base.getBaseOffset();
+ }
+
+ dump(Out, BaseSubobject(BaseDecl, BaseOffset), VisitedVirtualBases);
+ }
+
+ Out << "Final overriders for (" << RD->getQualifiedNameAsString() << ", ";
+ Out << Base.getBaseOffset().getQuantity() << ")\n";
+
+ // Now dump the overriders for this base subobject.
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
+ const CXXMethodDecl *MD = *I;
+
+ if (!MD->isVirtual())
+ continue;
+
+ OverriderInfo Overrider = getOverrider(MD, Base.getBaseOffset());
+
+ Out << " " << MD->getQualifiedNameAsString() << " - (";
+ Out << Overrider.Method->getQualifiedNameAsString();
+ Out << ", " << ", " << Overrider.Offset.getQuantity() << ')';
+
+ BaseOffset Offset;
+ if (!Overrider.Method->isPure())
+ Offset = ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD);
+
+ if (!Offset.isEmpty()) {
+ Out << " [ret-adj: ";
+ if (Offset.VirtualBase)
+ Out << Offset.VirtualBase->getQualifiedNameAsString() << " vbase, ";
+
+ Out << Offset.NonVirtualOffset.getQuantity() << " nv]";
+ }
+
+ Out << "\n";
+ }
+}
+
+/// VCallOffsetMap - Keeps track of vcall offsets when building a vtable.
+struct VCallOffsetMap {
+
+ typedef std::pair<const CXXMethodDecl *, CharUnits> MethodAndOffsetPairTy;
+
+ /// Offsets - Keeps track of methods and their offsets.
+ // FIXME: This should be a real map and not a vector.
+ SmallVector<MethodAndOffsetPairTy, 16> Offsets;
+
+ /// MethodsCanShareVCallOffset - Returns whether two virtual member functions
+ /// can share the same vcall offset.
+ static bool MethodsCanShareVCallOffset(const CXXMethodDecl *LHS,
+ const CXXMethodDecl *RHS);
+
+public:
+ /// AddVCallOffset - Adds a vcall offset to the map. Returns true if the
+ /// add was successful, or false if there was already a member function with
+ /// the same signature in the map.
+ bool AddVCallOffset(const CXXMethodDecl *MD, CharUnits OffsetOffset);
+
+ /// getVCallOffsetOffset - Returns the vcall offset offset (relative to the
+ /// vtable address point) for the given virtual member function.
+ CharUnits getVCallOffsetOffset(const CXXMethodDecl *MD);
+
+ // empty - Return whether the offset map is empty or not.
+ bool empty() const { return Offsets.empty(); }
+};
+
+static bool HasSameVirtualSignature(const CXXMethodDecl *LHS,
+ const CXXMethodDecl *RHS) {
+ ASTContext &C = LHS->getASTContext(); // TODO: thread this down
+ CanQual<FunctionProtoType>
+ LT = C.getCanonicalType(LHS->getType()).getAs<FunctionProtoType>(),
+ RT = C.getCanonicalType(RHS->getType()).getAs<FunctionProtoType>();
+
+ // Fast-path matches in the canonical types.
+ if (LT == RT) return true;
+
+ // Force the signatures to match. We can't rely on the overrides
+ // list here because there isn't necessarily an inheritance
+ // relationship between the two methods.
+ if (LT.getQualifiers() != RT.getQualifiers() ||
+ LT->getNumArgs() != RT->getNumArgs())
+ return false;
+ for (unsigned I = 0, E = LT->getNumArgs(); I != E; ++I)
+ if (LT->getArgType(I) != RT->getArgType(I))
+ return false;
+ return true;
+}
+
+bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS,
+ const CXXMethodDecl *RHS) {
+ assert(LHS->isVirtual() && "LHS must be virtual!");
+ assert(RHS->isVirtual() && "LHS must be virtual!");
+
+ // A destructor can share a vcall offset with another destructor.
+ if (isa<CXXDestructorDecl>(LHS))
+ return isa<CXXDestructorDecl>(RHS);
+
+ // FIXME: We need to check more things here.
+
+ // The methods must have the same name.
+ DeclarationName LHSName = LHS->getDeclName();
+ DeclarationName RHSName = RHS->getDeclName();
+ if (LHSName != RHSName)
+ return false;
+
+ // And the same signatures.
+ return HasSameVirtualSignature(LHS, RHS);
+}
+
+bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD,
+ CharUnits OffsetOffset) {
+ // Check if we can reuse an offset.
+ for (unsigned I = 0, E = Offsets.size(); I != E; ++I) {
+ if (MethodsCanShareVCallOffset(Offsets[I].first, MD))
+ return false;
+ }
+
+ // Add the offset.
+ Offsets.push_back(MethodAndOffsetPairTy(MD, OffsetOffset));
+ return true;
+}
+
+CharUnits VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) {
+ // Look for an offset.
+ for (unsigned I = 0, E = Offsets.size(); I != E; ++I) {
+ if (MethodsCanShareVCallOffset(Offsets[I].first, MD))
+ return Offsets[I].second;
+ }
+
+ llvm_unreachable("Should always find a vcall offset offset!");
+}
+
+/// VCallAndVBaseOffsetBuilder - Class for building vcall and vbase offsets.
+class VCallAndVBaseOffsetBuilder {
+public:
+ typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits>
+ VBaseOffsetOffsetsMapTy;
+
+private:
+ /// MostDerivedClass - The most derived class for which we're building vcall
+ /// and vbase offsets.
+ const CXXRecordDecl *MostDerivedClass;
+
+ /// LayoutClass - The class we're using for layout information. Will be
+ /// different than the most derived class if we're building a construction
+ /// vtable.
+ const CXXRecordDecl *LayoutClass;
+
+ /// Context - The ASTContext which we will use for layout information.
+ ASTContext &Context;
+
+ /// Components - vcall and vbase offset components
+ typedef SmallVector<VTableComponent, 64> VTableComponentVectorTy;
+ VTableComponentVectorTy Components;
+
+ /// VisitedVirtualBases - Visited virtual bases.
+ llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
+
+ /// VCallOffsets - Keeps track of vcall offsets.
+ VCallOffsetMap VCallOffsets;
+
+
+ /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets,
+ /// relative to the address point.
+ VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
+
+ /// FinalOverriders - The final overriders of the most derived class.
+ /// (Can be null when we're not building a vtable of the most derived class).
+ const FinalOverriders *Overriders;
+
+ /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the
+ /// given base subobject.
+ void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual,
+ CharUnits RealBaseOffset);
+
+ /// AddVCallOffsets - Add vcall offsets for the given base subobject.
+ void AddVCallOffsets(BaseSubobject Base, CharUnits VBaseOffset);
+
+ /// AddVBaseOffsets - Add vbase offsets for the given class.
+ void AddVBaseOffsets(const CXXRecordDecl *Base,
+ CharUnits OffsetInLayoutClass);
+
+ /// getCurrentOffsetOffset - Get the current vcall or vbase offset offset in
+ /// chars, relative to the vtable address point.
+ CharUnits getCurrentOffsetOffset() const;
+
+public:
+ VCallAndVBaseOffsetBuilder(const CXXRecordDecl *MostDerivedClass,
+ const CXXRecordDecl *LayoutClass,
+ const FinalOverriders *Overriders,
+ BaseSubobject Base, bool BaseIsVirtual,
+ CharUnits OffsetInLayoutClass)
+ : MostDerivedClass(MostDerivedClass), LayoutClass(LayoutClass),
+ Context(MostDerivedClass->getASTContext()), Overriders(Overriders) {
+
+ // Add vcall and vbase offsets.
+ AddVCallAndVBaseOffsets(Base, BaseIsVirtual, OffsetInLayoutClass);
+ }
+
+ /// Methods for iterating over the components.
+ typedef VTableComponentVectorTy::const_reverse_iterator const_iterator;
+ const_iterator components_begin() const { return Components.rbegin(); }
+ const_iterator components_end() const { return Components.rend(); }
+
+ const VCallOffsetMap &getVCallOffsets() const { return VCallOffsets; }
+ const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const {
+ return VBaseOffsetOffsets;
+ }
+};
+
+void
+VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base,
+ bool BaseIsVirtual,
+ CharUnits RealBaseOffset) {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase());
+
+ // Itanium C++ ABI 2.5.2:
+ // ..in classes sharing a virtual table with a primary base class, the vcall
+ // and vbase offsets added by the derived class all come before the vcall
+ // and vbase offsets required by the base class, so that the latter may be
+ // laid out as required by the base class without regard to additions from
+ // the derived class(es).
+
+ // (Since we're emitting the vcall and vbase offsets in reverse order, we'll
+ // emit them for the primary base first).
+ if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
+ bool PrimaryBaseIsVirtual = Layout.isPrimaryBaseVirtual();
+
+ CharUnits PrimaryBaseOffset;
+
+ // Get the base offset of the primary base.
+ if (PrimaryBaseIsVirtual) {
+ assert(Layout.getVBaseClassOffsetInBits(PrimaryBase) == 0 &&
+ "Primary vbase should have a zero offset!");
+
+ const ASTRecordLayout &MostDerivedClassLayout =
+ Context.getASTRecordLayout(MostDerivedClass);
+
+ PrimaryBaseOffset =
+ MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase);
+ } else {
+ assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 &&
+ "Primary base should have a zero offset!");
+
+ PrimaryBaseOffset = Base.getBaseOffset();
+ }
+
+ AddVCallAndVBaseOffsets(
+ BaseSubobject(PrimaryBase,PrimaryBaseOffset),
+ PrimaryBaseIsVirtual, RealBaseOffset);
+ }
+
+ AddVBaseOffsets(Base.getBase(), RealBaseOffset);
+
+ // We only want to add vcall offsets for virtual bases.
+ if (BaseIsVirtual)
+ AddVCallOffsets(Base, RealBaseOffset);
+}
+
+CharUnits VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const {
+ // OffsetIndex is the index of this vcall or vbase offset, relative to the
+ // vtable address point. (We subtract 3 to account for the information just
+ // above the address point, the RTTI info, the offset to top, and the
+ // vcall offset itself).
+ int64_t OffsetIndex = -(int64_t)(3 + Components.size());
+
+ CharUnits PointerWidth =
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
+ CharUnits OffsetOffset = PointerWidth * OffsetIndex;
+ return OffsetOffset;
+}
+
+void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
+ CharUnits VBaseOffset) {
+ const CXXRecordDecl *RD = Base.getBase();
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
+ // Handle the primary base first.
+ // We only want to add vcall offsets if the base is non-virtual; a virtual
+ // primary base will have its vcall and vbase offsets emitted already.
+ if (PrimaryBase && !Layout.isPrimaryBaseVirtual()) {
+ // Get the base offset of the primary base.
+ assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 &&
+ "Primary base should have a zero offset!");
+
+ AddVCallOffsets(BaseSubobject(PrimaryBase, Base.getBaseOffset()),
+ VBaseOffset);
+ }
+
+ // Add the vcall offsets.
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
+ const CXXMethodDecl *MD = *I;
+
+ if (!MD->isVirtual())
+ continue;
+
+ CharUnits OffsetOffset = getCurrentOffsetOffset();
+
+ // Don't add a vcall offset if we already have one for this member function
+ // signature.
+ if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset))
+ continue;
+
+ CharUnits Offset = CharUnits::Zero();
+
+ if (Overriders) {
+ // Get the final overrider.
+ FinalOverriders::OverriderInfo Overrider =
+ Overriders->getOverrider(MD, Base.getBaseOffset());
+
+ /// The vcall offset is the offset from the virtual base to the object
+ /// where the function was overridden.
+ Offset = Overrider.Offset - VBaseOffset;
+ }
+
+ Components.push_back(
+ VTableComponent::MakeVCallOffset(Offset));
+ }
+
+ // And iterate over all non-virtual bases (ignoring the primary base).
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+
+ if (I->isVirtual())
+ continue;
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ if (BaseDecl == PrimaryBase)
+ continue;
+
+ // Get the base offset of this base.
+ CharUnits BaseOffset = Base.getBaseOffset() +
+ Layout.getBaseClassOffset(BaseDecl);
+
+ AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset),
+ VBaseOffset);
+ }
+}
+
+void
+VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
+ CharUnits OffsetInLayoutClass) {
+ const ASTRecordLayout &LayoutClassLayout =
+ Context.getASTRecordLayout(LayoutClass);
+
+ // Add vbase offsets.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Check if this is a virtual base that we haven't visited before.
+ if (I->isVirtual() && VisitedVirtualBases.insert(BaseDecl)) {
+ CharUnits Offset =
+ LayoutClassLayout.getVBaseClassOffset(BaseDecl) - OffsetInLayoutClass;
+
+ // Add the vbase offset offset.
+ assert(!VBaseOffsetOffsets.count(BaseDecl) &&
+ "vbase offset offset already exists!");
+
+ CharUnits VBaseOffsetOffset = getCurrentOffsetOffset();
+ VBaseOffsetOffsets.insert(
+ std::make_pair(BaseDecl, VBaseOffsetOffset));
+
+ Components.push_back(
+ VTableComponent::MakeVBaseOffset(Offset));
+ }
+
+ // Check the base class looking for more vbase offsets.
+ AddVBaseOffsets(BaseDecl, OffsetInLayoutClass);
+ }
+}
+
+/// VTableBuilder - Class for building vtable layout information.
+class VTableBuilder {
+public:
+ /// PrimaryBasesSetVectorTy - A set vector of direct and indirect
+ /// primary bases.
+ typedef llvm::SmallSetVector<const CXXRecordDecl *, 8>
+ PrimaryBasesSetVectorTy;
+
+ typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits>
+ VBaseOffsetOffsetsMapTy;
+
+ typedef llvm::DenseMap<BaseSubobject, uint64_t>
+ AddressPointsMapTy;
+
+private:
+ /// VTables - Global vtable information.
+ VTableContext &VTables;
+
+ /// MostDerivedClass - The most derived class for which we're building this
+ /// vtable.
+ const CXXRecordDecl *MostDerivedClass;
+
+ /// MostDerivedClassOffset - If we're building a construction vtable, this
+ /// holds the offset from the layout class to the most derived class.
+ const CharUnits MostDerivedClassOffset;
+
+ /// MostDerivedClassIsVirtual - Whether the most derived class is a virtual
+ /// base. (This only makes sense when building a construction vtable).
+ bool MostDerivedClassIsVirtual;
+
+ /// LayoutClass - The class we're using for layout information. Will be
+ /// different than the most derived class if we're building a construction
+ /// vtable.
+ const CXXRecordDecl *LayoutClass;
+
+ /// Context - The ASTContext which we will use for layout information.
+ ASTContext &Context;
+
+ /// FinalOverriders - The final overriders of the most derived class.
+ const FinalOverriders Overriders;
+
+ /// VCallOffsetsForVBases - Keeps track of vcall offsets for the virtual
+ /// bases in this vtable.
+ llvm::DenseMap<const CXXRecordDecl *, VCallOffsetMap> VCallOffsetsForVBases;
+
+ /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets for
+ /// the most derived class.
+ VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
+
+ /// Components - The components of the vtable being built.
+ SmallVector<VTableComponent, 64> Components;
+
+ /// AddressPoints - Address points for the vtable being built.
+ AddressPointsMapTy AddressPoints;
+
+ /// MethodInfo - Contains information about a method in a vtable.
+ /// (Used for computing 'this' pointer adjustment thunks.
+ struct MethodInfo {
+ /// BaseOffset - The base offset of this method.
+ const CharUnits BaseOffset;
+
+ /// BaseOffsetInLayoutClass - The base offset in the layout class of this
+ /// method.
+ const CharUnits BaseOffsetInLayoutClass;
+
+ /// VTableIndex - The index in the vtable that this method has.
+ /// (For destructors, this is the index of the complete destructor).
+ const uint64_t VTableIndex;
+
+ MethodInfo(CharUnits BaseOffset, CharUnits BaseOffsetInLayoutClass,
+ uint64_t VTableIndex)
+ : BaseOffset(BaseOffset),
+ BaseOffsetInLayoutClass(BaseOffsetInLayoutClass),
+ VTableIndex(VTableIndex) { }
+
+ MethodInfo()
+ : BaseOffset(CharUnits::Zero()),
+ BaseOffsetInLayoutClass(CharUnits::Zero()),
+ VTableIndex(0) { }
+ };
+
+ typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
+
+ /// MethodInfoMap - The information for all methods in the vtable we're
+ /// currently building.
+ MethodInfoMapTy MethodInfoMap;
+
+ typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy;
+
+ /// VTableThunks - The thunks by vtable index in the vtable currently being
+ /// built.
+ VTableThunksMapTy VTableThunks;
+
+ typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
+ typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
+
+ /// Thunks - A map that contains all the thunks needed for all methods in the
+ /// most derived class for which the vtable is currently being built.
+ ThunksMapTy Thunks;
+
+ /// AddThunk - Add a thunk for the given method.
+ void AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk);
+
+ /// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the
+ /// part of the vtable we're currently building.
+ void ComputeThisAdjustments();
+
+ typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
+
+ /// PrimaryVirtualBases - All known virtual bases who are a primary base of
+ /// some other base.
+ VisitedVirtualBasesSetTy PrimaryVirtualBases;
+
+ /// ComputeReturnAdjustment - Compute the return adjustment given a return
+ /// adjustment base offset.
+ ReturnAdjustment ComputeReturnAdjustment(BaseOffset Offset);
+
+ /// ComputeThisAdjustmentBaseOffset - Compute the base offset for adjusting
+ /// the 'this' pointer from the base subobject to the derived subobject.
+ BaseOffset ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
+ BaseSubobject Derived) const;
+
+ /// ComputeThisAdjustment - Compute the 'this' pointer adjustment for the
+ /// given virtual member function, its offset in the layout class and its
+ /// final overrider.
+ ThisAdjustment
+ ComputeThisAdjustment(const CXXMethodDecl *MD,
+ CharUnits BaseOffsetInLayoutClass,
+ FinalOverriders::OverriderInfo Overrider);
+
+ /// AddMethod - Add a single virtual member function to the vtable
+ /// components vector.
+ void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment);
+
+ /// IsOverriderUsed - Returns whether the overrider will ever be used in this
+ /// part of the vtable.
+ ///
+ /// Itanium C++ ABI 2.5.2:
+ ///
+ /// struct A { virtual void f(); };
+ /// struct B : virtual public A { int i; };
+ /// struct C : virtual public A { int j; };
+ /// struct D : public B, public C {};
+ ///
+ /// When B and C are declared, A is a primary base in each case, so although
+ /// vcall offsets are allocated in the A-in-B and A-in-C vtables, no this
+ /// adjustment is required and no thunk is generated. However, inside D
+ /// objects, A is no longer a primary base of C, so if we allowed calls to
+ /// C::f() to use the copy of A's vtable in the C subobject, we would need
+ /// to adjust this from C* to B::A*, which would require a third-party
+ /// thunk. Since we require that a call to C::f() first convert to A*,
+ /// C-in-D's copy of A's vtable is never referenced, so this is not
+ /// necessary.
+ bool IsOverriderUsed(const CXXMethodDecl *Overrider,
+ CharUnits BaseOffsetInLayoutClass,
+ const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
+ CharUnits FirstBaseOffsetInLayoutClass) const;
+
+
+ /// AddMethods - Add the methods of this base subobject and all its
+ /// primary bases to the vtable components vector.
+ void AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
+ const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
+ CharUnits FirstBaseOffsetInLayoutClass,
+ PrimaryBasesSetVectorTy &PrimaryBases);
+
+ // LayoutVTable - Layout the vtable for the given base class, including its
+ // secondary vtables and any vtables for virtual bases.
+ void LayoutVTable();
+
+ /// LayoutPrimaryAndSecondaryVTables - Layout the primary vtable for the
+ /// given base subobject, as well as all its secondary vtables.
+ ///
+ /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base
+ /// or a direct or indirect base of a virtual base.
+ ///
+ /// \param BaseIsVirtualInLayoutClass - Whether the base subobject is virtual
+ /// in the layout class.
+ void LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
+ bool BaseIsMorallyVirtual,
+ bool BaseIsVirtualInLayoutClass,
+ CharUnits OffsetInLayoutClass);
+
+ /// LayoutSecondaryVTables - Layout the secondary vtables for the given base
+ /// subobject.
+ ///
+ /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base
+ /// or a direct or indirect base of a virtual base.
+ void LayoutSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual,
+ CharUnits OffsetInLayoutClass);
+
+ /// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this
+ /// class hierarchy.
+ void DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
+ CharUnits OffsetInLayoutClass,
+ VisitedVirtualBasesSetTy &VBases);
+
+ /// LayoutVTablesForVirtualBases - Layout vtables for all virtual bases of the
+ /// given base (excluding any primary bases).
+ void LayoutVTablesForVirtualBases(const CXXRecordDecl *RD,
+ VisitedVirtualBasesSetTy &VBases);
+
+ /// isBuildingConstructionVTable - Return whether this vtable builder is
+ /// building a construction vtable.
+ bool isBuildingConstructorVTable() const {
+ return MostDerivedClass != LayoutClass;
+ }
+
+public:
+ VTableBuilder(VTableContext &VTables, const CXXRecordDecl *MostDerivedClass,
+ CharUnits MostDerivedClassOffset,
+ bool MostDerivedClassIsVirtual, const
+ CXXRecordDecl *LayoutClass)
+ : VTables(VTables), MostDerivedClass(MostDerivedClass),
+ MostDerivedClassOffset(MostDerivedClassOffset),
+ MostDerivedClassIsVirtual(MostDerivedClassIsVirtual),
+ LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()),
+ Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) {
+
+ LayoutVTable();
+
+ if (Context.getLangOptions().DumpVTableLayouts)
+ dumpLayout(llvm::errs());
+ }
+
+ uint64_t getNumThunks() const {
+ return Thunks.size();
+ }
+
+ ThunksMapTy::const_iterator thunks_begin() const {
+ return Thunks.begin();
+ }
+
+ ThunksMapTy::const_iterator thunks_end() const {
+ return Thunks.end();
+ }
+
+ const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const {
+ return VBaseOffsetOffsets;
+ }
+
+ const AddressPointsMapTy &getAddressPoints() const {
+ return AddressPoints;
+ }
+
+ /// getNumVTableComponents - Return the number of components in the vtable
+ /// currently built.
+ uint64_t getNumVTableComponents() const {
+ return Components.size();
+ }
+
+ const VTableComponent *vtable_component_begin() const {
+ return Components.begin();
+ }
+
+ const VTableComponent *vtable_component_end() const {
+ return Components.end();
+ }
+
+ AddressPointsMapTy::const_iterator address_points_begin() const {
+ return AddressPoints.begin();
+ }
+
+ AddressPointsMapTy::const_iterator address_points_end() const {
+ return AddressPoints.end();
+ }
+
+ VTableThunksMapTy::const_iterator vtable_thunks_begin() const {
+ return VTableThunks.begin();
+ }
+
+ VTableThunksMapTy::const_iterator vtable_thunks_end() const {
+ return VTableThunks.end();
+ }
+
+ /// dumpLayout - Dump the vtable layout.
+ void dumpLayout(raw_ostream&);
+};
+
+void VTableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) {
+ assert(!isBuildingConstructorVTable() &&
+ "Can't add thunks for construction vtable");
+
+ SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD];
+
+ // Check if we have this thunk already.
+ if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) !=
+ ThunksVector.end())
+ return;
+
+ ThunksVector.push_back(Thunk);
+}
+
+typedef llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverriddenMethodsSetTy;
+
+/// ComputeAllOverriddenMethods - Given a method decl, will return a set of all
+/// the overridden methods that the function decl overrides.
+static void
+ComputeAllOverriddenMethods(const CXXMethodDecl *MD,
+ OverriddenMethodsSetTy& OverriddenMethods) {
+ assert(MD->isVirtual() && "Method is not virtual!");
+
+ for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
+ E = MD->end_overridden_methods(); I != E; ++I) {
+ const CXXMethodDecl *OverriddenMD = *I;
+
+ OverriddenMethods.insert(OverriddenMD);
+
+ ComputeAllOverriddenMethods(OverriddenMD, OverriddenMethods);
+ }
+}
+
+void VTableBuilder::ComputeThisAdjustments() {
+ // Now go through the method info map and see if any of the methods need
+ // 'this' pointer adjustments.
+ for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(),
+ E = MethodInfoMap.end(); I != E; ++I) {
+ const CXXMethodDecl *MD = I->first;
+ const MethodInfo &MethodInfo = I->second;
+
+ // Ignore adjustments for unused function pointers.
+ uint64_t VTableIndex = MethodInfo.VTableIndex;
+ if (Components[VTableIndex].getKind() ==
+ VTableComponent::CK_UnusedFunctionPointer)
+ continue;
+
+ // Get the final overrider for this method.
+ FinalOverriders::OverriderInfo Overrider =
+ Overriders.getOverrider(MD, MethodInfo.BaseOffset);
+
+ // Check if we need an adjustment at all.
+ if (MethodInfo.BaseOffsetInLayoutClass == Overrider.Offset) {
+ // When a return thunk is needed by a derived class that overrides a
+ // virtual base, gcc uses a virtual 'this' adjustment as well.
+ // While the thunk itself might be needed by vtables in subclasses or
+ // in construction vtables, there doesn't seem to be a reason for using
+ // the thunk in this vtable. Still, we do so to match gcc.
+ if (VTableThunks.lookup(VTableIndex).Return.isEmpty())
+ continue;
+ }
+
+ ThisAdjustment ThisAdjustment =
+ ComputeThisAdjustment(MD, MethodInfo.BaseOffsetInLayoutClass, Overrider);
+
+ if (ThisAdjustment.isEmpty())
+ continue;
+
+ // Add it.
+ VTableThunks[VTableIndex].This = ThisAdjustment;
+
+ if (isa<CXXDestructorDecl>(MD)) {
+ // Add an adjustment for the deleting destructor as well.
+ VTableThunks[VTableIndex + 1].This = ThisAdjustment;
+ }
+ }
+
+ /// Clear the method info map.
+ MethodInfoMap.clear();
+
+ if (isBuildingConstructorVTable()) {
+ // We don't need to store thunk information for construction vtables.
+ return;
+ }
+
+ for (VTableThunksMapTy::const_iterator I = VTableThunks.begin(),
+ E = VTableThunks.end(); I != E; ++I) {
+ const VTableComponent &Component = Components[I->first];
+ const ThunkInfo &Thunk = I->second;
+ const CXXMethodDecl *MD;
+
+ switch (Component.getKind()) {
+ default:
+ llvm_unreachable("Unexpected vtable component kind!");
+ case VTableComponent::CK_FunctionPointer:
+ MD = Component.getFunctionDecl();
+ break;
+ case VTableComponent::CK_CompleteDtorPointer:
+ MD = Component.getDestructorDecl();
+ break;
+ case VTableComponent::CK_DeletingDtorPointer:
+ // We've already added the thunk when we saw the complete dtor pointer.
+ continue;
+ }
+
+ if (MD->getParent() == MostDerivedClass)
+ AddThunk(MD, Thunk);
+ }
+}
+
+ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
+ ReturnAdjustment Adjustment;
+
+ if (!Offset.isEmpty()) {
+ if (Offset.VirtualBase) {
+ // Get the virtual base offset offset.
+ if (Offset.DerivedClass == MostDerivedClass) {
+ // We can get the offset offset directly from our map.
+ Adjustment.VBaseOffsetOffset =
+ VBaseOffsetOffsets.lookup(Offset.VirtualBase).getQuantity();
+ } else {
+ Adjustment.VBaseOffsetOffset =
+ VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass,
+ Offset.VirtualBase).getQuantity();
+ }
+ }
+
+ Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity();
+ }
+
+ return Adjustment;
+}
+
+BaseOffset
+VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
+ BaseSubobject Derived) const {
+ const CXXRecordDecl *BaseRD = Base.getBase();
+ const CXXRecordDecl *DerivedRD = Derived.getBase();
+
+ CXXBasePaths Paths(/*FindAmbiguities=*/true,
+ /*RecordPaths=*/true, /*DetectVirtual=*/true);
+
+ if (!const_cast<CXXRecordDecl *>(DerivedRD)->
+ isDerivedFrom(const_cast<CXXRecordDecl *>(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.
+ for (CXXBasePaths::const_paths_iterator I = Paths.begin(), E = Paths.end();
+ I != E; ++I) {
+ BaseOffset Offset = ComputeBaseOffset(Context, DerivedRD, *I);
+
+ CharUnits OffsetToBaseSubobject = Offset.NonVirtualOffset;
+
+ if (Offset.VirtualBase) {
+ // If we have a virtual base class, the non-virtual offset is relative
+ // to the virtual base class offset.
+ const ASTRecordLayout &LayoutClassLayout =
+ Context.getASTRecordLayout(LayoutClass);
+
+ /// Get the virtual base offset, relative to the most derived class
+ /// layout.
+ OffsetToBaseSubobject +=
+ LayoutClassLayout.getVBaseClassOffset(Offset.VirtualBase);
+ } else {
+ // Otherwise, the non-virtual offset is relative to the derived class
+ // offset.
+ OffsetToBaseSubobject += Derived.getBaseOffset();
+ }
+
+ // Check if this path gives us the right base subobject.
+ if (OffsetToBaseSubobject == Base.getBaseOffset()) {
+ // Since we're going from the base class _to_ the derived class, we'll
+ // invert the non-virtual offset here.
+ Offset.NonVirtualOffset = -Offset.NonVirtualOffset;
+ return Offset;
+ }
+ }
+
+ return BaseOffset();
+}
+
+ThisAdjustment
+VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
+ CharUnits BaseOffsetInLayoutClass,
+ FinalOverriders::OverriderInfo Overrider) {
+ // Ignore adjustments for pure virtual member functions.
+ if (Overrider.Method->isPure())
+ return ThisAdjustment();
+
+ BaseSubobject OverriddenBaseSubobject(MD->getParent(),
+ BaseOffsetInLayoutClass);
+
+ BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(),
+ Overrider.Offset);
+
+ // Compute the adjustment offset.
+ BaseOffset Offset = ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject,
+ OverriderBaseSubobject);
+ if (Offset.isEmpty())
+ return ThisAdjustment();
+
+ ThisAdjustment Adjustment;
+
+ if (Offset.VirtualBase) {
+ // Get the vcall offset map for this virtual base.
+ VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase];
+
+ if (VCallOffsets.empty()) {
+ // We don't have vcall offsets for this virtual base, go ahead and
+ // build them.
+ VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, MostDerivedClass,
+ /*FinalOverriders=*/0,
+ BaseSubobject(Offset.VirtualBase,
+ CharUnits::Zero()),
+ /*BaseIsVirtual=*/true,
+ /*OffsetInLayoutClass=*/
+ CharUnits::Zero());
+
+ VCallOffsets = Builder.getVCallOffsets();
+ }
+
+ Adjustment.VCallOffsetOffset =
+ VCallOffsets.getVCallOffsetOffset(MD).getQuantity();
+ }
+
+ // Set the non-virtual part of the adjustment.
+ Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity();
+
+ return Adjustment;
+}
+
+void
+VTableBuilder::AddMethod(const CXXMethodDecl *MD,
+ ReturnAdjustment ReturnAdjustment) {
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(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));
+ } else {
+ // Add the return adjustment if necessary.
+ if (!ReturnAdjustment.isEmpty())
+ VTableThunks[Components.size()].Return = ReturnAdjustment;
+
+ // Add the function.
+ Components.push_back(VTableComponent::MakeFunction(MD));
+ }
+}
+
+/// OverridesIndirectMethodInBase - Return whether the given member function
+/// overrides any methods in the set of given bases.
+/// Unlike OverridesMethodInBase, this checks "overriders of overriders".
+/// For example, if we have:
+///
+/// struct A { virtual void f(); }
+/// struct B : A { virtual void f(); }
+/// struct C : B { virtual void f(); }
+///
+/// OverridesIndirectMethodInBase will return true if given C::f as the method
+/// and { A } as the set of bases.
+static bool
+OverridesIndirectMethodInBases(const CXXMethodDecl *MD,
+ VTableBuilder::PrimaryBasesSetVectorTy &Bases) {
+ if (Bases.count(MD->getParent()))
+ return true;
+
+ for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
+ E = MD->end_overridden_methods(); I != E; ++I) {
+ const CXXMethodDecl *OverriddenMD = *I;
+
+ // Check "indirect overriders".
+ if (OverridesIndirectMethodInBases(OverriddenMD, Bases))
+ return true;
+ }
+
+ return false;
+}
+
+bool
+VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider,
+ CharUnits BaseOffsetInLayoutClass,
+ const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
+ CharUnits FirstBaseOffsetInLayoutClass) const {
+ // If the base and the first base in the primary base chain have the same
+ // offsets, then this overrider will be used.
+ if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass)
+ return true;
+
+ // We know now that Base (or a direct or indirect base of it) is a primary
+ // base in part of the class hierarchy, but not a primary base in the most
+ // derived class.
+
+ // If the overrider is the first base in the primary base chain, we know
+ // that the overrider will be used.
+ if (Overrider->getParent() == FirstBaseInPrimaryBaseChain)
+ return true;
+
+ VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
+
+ const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain;
+ PrimaryBases.insert(RD);
+
+ // Now traverse the base chain, starting with the first base, until we find
+ // the base that is no longer a primary base.
+ while (true) {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
+ if (!PrimaryBase)
+ break;
+
+ if (Layout.isPrimaryBaseVirtual()) {
+ assert(Layout.getVBaseClassOffsetInBits(PrimaryBase) == 0 &&
+ "Primary base should always be at offset 0!");
+
+ const ASTRecordLayout &LayoutClassLayout =
+ Context.getASTRecordLayout(LayoutClass);
+
+ // Now check if this is the primary base that is not a primary base in the
+ // most derived class.
+ if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) !=
+ FirstBaseOffsetInLayoutClass) {
+ // We found it, stop walking the chain.
+ break;
+ }
+ } else {
+ assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 &&
+ "Primary base should always be at offset 0!");
+ }
+
+ if (!PrimaryBases.insert(PrimaryBase))
+ llvm_unreachable("Found a duplicate primary base!");
+
+ RD = PrimaryBase;
+ }
+
+ // If the final overrider is an override of one of the primary bases,
+ // then we know that it will be used.
+ return OverridesIndirectMethodInBases(Overrider, PrimaryBases);
+}
+
+/// FindNearestOverriddenMethod - Given a method, returns the overridden method
+/// from the nearest base. Returns null if no method was found.
+static const CXXMethodDecl *
+FindNearestOverriddenMethod(const CXXMethodDecl *MD,
+ VTableBuilder::PrimaryBasesSetVectorTy &Bases) {
+ OverriddenMethodsSetTy OverriddenMethods;
+ ComputeAllOverriddenMethods(MD, OverriddenMethods);
+
+ for (int I = Bases.size(), E = 0; I != E; --I) {
+ const CXXRecordDecl *PrimaryBase = Bases[I - 1];
+
+ // Now check the overriden methods.
+ for (OverriddenMethodsSetTy::const_iterator I = OverriddenMethods.begin(),
+ E = OverriddenMethods.end(); I != E; ++I) {
+ const CXXMethodDecl *OverriddenMD = *I;
+
+ // We found our overridden method.
+ if (OverriddenMD->getParent() == PrimaryBase)
+ return OverriddenMD;
+ }
+ }
+
+ return 0;
+}
+
+void
+VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
+ const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
+ CharUnits FirstBaseOffsetInLayoutClass,
+ PrimaryBasesSetVectorTy &PrimaryBases) {
+ const CXXRecordDecl *RD = Base.getBase();
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
+ CharUnits PrimaryBaseOffset;
+ CharUnits PrimaryBaseOffsetInLayoutClass;
+ if (Layout.isPrimaryBaseVirtual()) {
+ assert(Layout.getVBaseClassOffsetInBits(PrimaryBase) == 0 &&
+ "Primary vbase should have a zero offset!");
+
+ const ASTRecordLayout &MostDerivedClassLayout =
+ Context.getASTRecordLayout(MostDerivedClass);
+
+ PrimaryBaseOffset =
+ MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase);
+
+ const ASTRecordLayout &LayoutClassLayout =
+ Context.getASTRecordLayout(LayoutClass);
+
+ PrimaryBaseOffsetInLayoutClass =
+ LayoutClassLayout.getVBaseClassOffset(PrimaryBase);
+ } else {
+ assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 &&
+ "Primary base should have a zero offset!");
+
+ PrimaryBaseOffset = Base.getBaseOffset();
+ PrimaryBaseOffsetInLayoutClass = BaseOffsetInLayoutClass;
+ }
+
+ AddMethods(BaseSubobject(PrimaryBase, PrimaryBaseOffset),
+ PrimaryBaseOffsetInLayoutClass, FirstBaseInPrimaryBaseChain,
+ FirstBaseOffsetInLayoutClass, PrimaryBases);
+
+ if (!PrimaryBases.insert(PrimaryBase))
+ llvm_unreachable("Found a duplicate primary base!");
+ }
+
+ // Now go through all virtual member functions and add them.
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
+ const CXXMethodDecl *MD = *I;
+
+ if (!MD->isVirtual())
+ continue;
+
+ // Get the final overrider.
+ FinalOverriders::OverriderInfo Overrider =
+ Overriders.getOverrider(MD, Base.getBaseOffset());
+
+ // Check if this virtual member function overrides a method in a primary
+ // base. If this is the case, and the return type doesn't require adjustment
+ // then we can just use the member function from the primary base.
+ if (const CXXMethodDecl *OverriddenMD =
+ FindNearestOverriddenMethod(MD, PrimaryBases)) {
+ if (ComputeReturnAdjustmentBaseOffset(Context, MD,
+ OverriddenMD).isEmpty()) {
+ // Replace the method info of the overridden method with our own
+ // method.
+ assert(MethodInfoMap.count(OverriddenMD) &&
+ "Did not find the overridden method!");
+ MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD];
+
+ MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass,
+ OverriddenMethodInfo.VTableIndex);
+
+ assert(!MethodInfoMap.count(MD) &&
+ "Should not have method info for this method yet!");
+
+ MethodInfoMap.insert(std::make_pair(MD, MethodInfo));
+ MethodInfoMap.erase(OverriddenMD);
+
+ // If the overridden method exists in a virtual base class or a direct
+ // or indirect base class of a virtual base class, we need to emit a
+ // thunk if we ever have a class hierarchy where the base class is not
+ // a primary base in the complete object.
+ if (!isBuildingConstructorVTable() && OverriddenMD != MD) {
+ // Compute the this adjustment.
+ ThisAdjustment ThisAdjustment =
+ ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass,
+ Overrider);
+
+ if (ThisAdjustment.VCallOffsetOffset &&
+ Overrider.Method->getParent() == MostDerivedClass) {
+
+ // There's no return adjustment from OverriddenMD and MD,
+ // but that doesn't mean there isn't one between MD and
+ // the final overrider.
+ BaseOffset ReturnAdjustmentOffset =
+ ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD);
+ ReturnAdjustment ReturnAdjustment =
+ ComputeReturnAdjustment(ReturnAdjustmentOffset);
+
+ // This is a virtual thunk for the most derived class, add it.
+ AddThunk(Overrider.Method,
+ ThunkInfo(ThisAdjustment, ReturnAdjustment));
+ }
+ }
+
+ continue;
+ }
+ }
+
+ // Insert the method info for this method.
+ MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass,
+ Components.size());
+
+ assert(!MethodInfoMap.count(MD) &&
+ "Should not have method info for this method yet!");
+ MethodInfoMap.insert(std::make_pair(MD, MethodInfo));
+
+ // Check if this overrider is going to be used.
+ const CXXMethodDecl *OverriderMD = Overrider.Method;
+ if (!IsOverriderUsed(OverriderMD, BaseOffsetInLayoutClass,
+ FirstBaseInPrimaryBaseChain,
+ FirstBaseOffsetInLayoutClass)) {
+ Components.push_back(VTableComponent::MakeUnusedFunction(OverriderMD));
+ continue;
+ }
+
+ // Check if this overrider needs a return adjustment.
+ // We don't want to do this for pure virtual member functions.
+ BaseOffset ReturnAdjustmentOffset;
+ if (!OverriderMD->isPure()) {
+ ReturnAdjustmentOffset =
+ ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD);
+ }
+
+ ReturnAdjustment ReturnAdjustment =
+ ComputeReturnAdjustment(ReturnAdjustmentOffset);
+
+ AddMethod(Overrider.Method, ReturnAdjustment);
+ }
+}
+
+void VTableBuilder::LayoutVTable() {
+ LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass,
+ CharUnits::Zero()),
+ /*BaseIsMorallyVirtual=*/false,
+ MostDerivedClassIsVirtual,
+ MostDerivedClassOffset);
+
+ VisitedVirtualBasesSetTy VBases;
+
+ // Determine the primary virtual bases.
+ DeterminePrimaryVirtualBases(MostDerivedClass, MostDerivedClassOffset,
+ VBases);
+ VBases.clear();
+
+ LayoutVTablesForVirtualBases(MostDerivedClass, VBases);
+
+ // -fapple-kext adds an extra entry at end of vtbl.
+ bool IsAppleKext = Context.getLangOptions().AppleKext;
+ if (IsAppleKext)
+ Components.push_back(VTableComponent::MakeVCallOffset(CharUnits::Zero()));
+}
+
+void
+VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
+ bool BaseIsMorallyVirtual,
+ bool BaseIsVirtualInLayoutClass,
+ CharUnits OffsetInLayoutClass) {
+ assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!");
+
+ // Add vcall and vbase offsets for this vtable.
+ VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, LayoutClass, &Overriders,
+ Base, BaseIsVirtualInLayoutClass,
+ OffsetInLayoutClass);
+ Components.append(Builder.components_begin(), Builder.components_end());
+
+ // Check if we need to add these vcall offsets.
+ if (BaseIsVirtualInLayoutClass && !Builder.getVCallOffsets().empty()) {
+ VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Base.getBase()];
+
+ if (VCallOffsets.empty())
+ VCallOffsets = Builder.getVCallOffsets();
+ }
+
+ // If we're laying out the most derived class we want to keep track of the
+ // virtual base class offset offsets.
+ 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));
+
+ uint64_t AddressPoint = Components.size();
+
+ // Now go through all virtual member functions and add them.
+ PrimaryBasesSetVectorTy PrimaryBases;
+ AddMethods(Base, OffsetInLayoutClass,
+ Base.getBase(), OffsetInLayoutClass,
+ PrimaryBases);
+
+ // Compute 'this' pointer adjustments.
+ ComputeThisAdjustments();
+
+ // Add all address points.
+ const CXXRecordDecl *RD = Base.getBase();
+ while (true) {
+ AddressPoints.insert(std::make_pair(
+ BaseSubobject(RD, OffsetInLayoutClass),
+ AddressPoint));
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
+ if (!PrimaryBase)
+ break;
+
+ if (Layout.isPrimaryBaseVirtual()) {
+ // Check if this virtual primary base is a primary base in the layout
+ // class. If it's not, we don't want to add it.
+ const ASTRecordLayout &LayoutClassLayout =
+ Context.getASTRecordLayout(LayoutClass);
+
+ if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) !=
+ OffsetInLayoutClass) {
+ // We don't want to add this class (or any of its primary bases).
+ break;
+ }
+ }
+
+ RD = PrimaryBase;
+ }
+
+ // Layout secondary vtables.
+ LayoutSecondaryVTables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass);
+}
+
+void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base,
+ bool BaseIsMorallyVirtual,
+ CharUnits OffsetInLayoutClass) {
+ // Itanium C++ ABI 2.5.2:
+ // Following the primary virtual table of a derived class are secondary
+ // virtual tables for each of its proper base classes, except any primary
+ // base(s) with which it shares its primary virtual table.
+
+ const CXXRecordDecl *RD = Base.getBase();
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ // Ignore virtual bases, we'll emit them later.
+ if (I->isVirtual())
+ continue;
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore bases that don't have a vtable.
+ if (!BaseDecl->isDynamicClass())
+ continue;
+
+ if (isBuildingConstructorVTable()) {
+ // Itanium C++ ABI 2.6.4:
+ // Some of the base class subobjects may not need construction virtual
+ // tables, which will therefore not be present in the construction
+ // virtual table group, even though the subobject virtual tables are
+ // present in the main virtual table group for the complete object.
+ if (!BaseIsMorallyVirtual && !BaseDecl->getNumVBases())
+ continue;
+ }
+
+ // Get the base offset of this base.
+ CharUnits RelativeBaseOffset = Layout.getBaseClassOffset(BaseDecl);
+ CharUnits BaseOffset = Base.getBaseOffset() + RelativeBaseOffset;
+
+ CharUnits BaseOffsetInLayoutClass =
+ OffsetInLayoutClass + RelativeBaseOffset;
+
+ // Don't emit a secondary vtable for a primary base. We might however want
+ // to emit secondary vtables for other bases of this base.
+ if (BaseDecl == PrimaryBase) {
+ LayoutSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset),
+ BaseIsMorallyVirtual, BaseOffsetInLayoutClass);
+ continue;
+ }
+
+ // Layout the primary vtable (and any secondary vtables) for this base.
+ LayoutPrimaryAndSecondaryVTables(
+ BaseSubobject(BaseDecl, BaseOffset),
+ BaseIsMorallyVirtual,
+ /*BaseIsVirtualInLayoutClass=*/false,
+ BaseOffsetInLayoutClass);
+ }
+}
+
+void
+VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
+ CharUnits OffsetInLayoutClass,
+ VisitedVirtualBasesSetTy &VBases) {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ // Check if this base has a primary base.
+ if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
+
+ // Check if it's virtual.
+ if (Layout.isPrimaryBaseVirtual()) {
+ bool IsPrimaryVirtualBase = true;
+
+ if (isBuildingConstructorVTable()) {
+ // Check if the base is actually a primary base in the class we use for
+ // layout.
+ const ASTRecordLayout &LayoutClassLayout =
+ Context.getASTRecordLayout(LayoutClass);
+
+ CharUnits PrimaryBaseOffsetInLayoutClass =
+ LayoutClassLayout.getVBaseClassOffset(PrimaryBase);
+
+ // We know that the base is not a primary base in the layout class if
+ // the base offsets are different.
+ if (PrimaryBaseOffsetInLayoutClass != OffsetInLayoutClass)
+ IsPrimaryVirtualBase = false;
+ }
+
+ if (IsPrimaryVirtualBase)
+ PrimaryVirtualBases.insert(PrimaryBase);
+ }
+ }
+
+ // Traverse bases, looking for more primary virtual bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ CharUnits BaseOffsetInLayoutClass;
+
+ if (I->isVirtual()) {
+ if (!VBases.insert(BaseDecl))
+ continue;
+
+ const ASTRecordLayout &LayoutClassLayout =
+ Context.getASTRecordLayout(LayoutClass);
+
+ BaseOffsetInLayoutClass =
+ LayoutClassLayout.getVBaseClassOffset(BaseDecl);
+ } else {
+ BaseOffsetInLayoutClass =
+ OffsetInLayoutClass + Layout.getBaseClassOffset(BaseDecl);
+ }
+
+ DeterminePrimaryVirtualBases(BaseDecl, BaseOffsetInLayoutClass, VBases);
+ }
+}
+
+void
+VTableBuilder::LayoutVTablesForVirtualBases(const CXXRecordDecl *RD,
+ VisitedVirtualBasesSetTy &VBases) {
+ // Itanium C++ ABI 2.5.2:
+ // Then come the virtual base virtual tables, also in inheritance graph
+ // order, and again excluding primary bases (which share virtual tables with
+ // the classes for which they are primary).
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Check if this base needs a vtable. (If it's virtual, not a primary base
+ // of some other class, and we haven't visited it before).
+ if (I->isVirtual() && BaseDecl->isDynamicClass() &&
+ !PrimaryVirtualBases.count(BaseDecl) && VBases.insert(BaseDecl)) {
+ const ASTRecordLayout &MostDerivedClassLayout =
+ Context.getASTRecordLayout(MostDerivedClass);
+ CharUnits BaseOffset =
+ MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
+
+ const ASTRecordLayout &LayoutClassLayout =
+ Context.getASTRecordLayout(LayoutClass);
+ CharUnits BaseOffsetInLayoutClass =
+ LayoutClassLayout.getVBaseClassOffset(BaseDecl);
+
+ LayoutPrimaryAndSecondaryVTables(
+ BaseSubobject(BaseDecl, BaseOffset),
+ /*BaseIsMorallyVirtual=*/true,
+ /*BaseIsVirtualInLayoutClass=*/true,
+ BaseOffsetInLayoutClass);
+ }
+
+ // We only need to check the base for virtual base vtables if it actually
+ // has virtual bases.
+ if (BaseDecl->getNumVBases())
+ LayoutVTablesForVirtualBases(BaseDecl, VBases);
+ }
+}
+
+/// dumpLayout - Dump the vtable layout.
+void VTableBuilder::dumpLayout(raw_ostream& Out) {
+
+ if (isBuildingConstructorVTable()) {
+ Out << "Construction vtable for ('";
+ Out << MostDerivedClass->getQualifiedNameAsString() << "', ";
+ Out << MostDerivedClassOffset.getQuantity() << ") in '";
+ Out << LayoutClass->getQualifiedNameAsString();
+ } else {
+ Out << "Vtable for '";
+ Out << MostDerivedClass->getQualifiedNameAsString();
+ }
+ Out << "' (" << Components.size() << " entries).\n";
+
+ // Iterate through the address points and insert them into a new map where
+ // they are keyed by the index and not the base object.
+ // Since an address point can be shared by multiple subobjects, we use an
+ // STL multimap.
+ std::multimap<uint64_t, BaseSubobject> AddressPointsByIndex;
+ for (AddressPointsMapTy::const_iterator I = AddressPoints.begin(),
+ E = AddressPoints.end(); I != E; ++I) {
+ const BaseSubobject& Base = I->first;
+ uint64_t Index = I->second;
+
+ AddressPointsByIndex.insert(std::make_pair(Index, Base));
+ }
+
+ for (unsigned I = 0, E = Components.size(); I != E; ++I) {
+ uint64_t Index = I;
+
+ Out << llvm::format("%4d | ", I);
+
+ const VTableComponent &Component = Components[I];
+
+ // Dump the component.
+ switch (Component.getKind()) {
+
+ case VTableComponent::CK_VCallOffset:
+ Out << "vcall_offset ("
+ << Component.getVCallOffset().getQuantity()
+ << ")";
+ break;
+
+ case VTableComponent::CK_VBaseOffset:
+ Out << "vbase_offset ("
+ << Component.getVBaseOffset().getQuantity()
+ << ")";
+ break;
+
+ case VTableComponent::CK_OffsetToTop:
+ Out << "offset_to_top ("
+ << Component.getOffsetToTop().getQuantity()
+ << ")";
+ break;
+
+ case VTableComponent::CK_RTTI:
+ Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI";
+ break;
+
+ case VTableComponent::CK_FunctionPointer: {
+ const CXXMethodDecl *MD = Component.getFunctionDecl();
+
+ std::string Str =
+ PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual,
+ MD);
+ Out << Str;
+ if (MD->isPure())
+ Out << " [pure]";
+
+ ThunkInfo Thunk = VTableThunks.lookup(I);
+ if (!Thunk.isEmpty()) {
+ // If this function pointer has a return adjustment, dump it.
+ if (!Thunk.Return.isEmpty()) {
+ Out << "\n [return adjustment: ";
+ Out << Thunk.Return.NonVirtual << " non-virtual";
+
+ if (Thunk.Return.VBaseOffsetOffset) {
+ Out << ", " << Thunk.Return.VBaseOffsetOffset;
+ Out << " vbase offset offset";
+ }
+
+ Out << ']';
+ }
+
+ // If this function pointer has a 'this' pointer adjustment, dump it.
+ if (!Thunk.This.isEmpty()) {
+ Out << "\n [this adjustment: ";
+ Out << Thunk.This.NonVirtual << " non-virtual";
+
+ if (Thunk.This.VCallOffsetOffset) {
+ Out << ", " << Thunk.This.VCallOffsetOffset;
+ Out << " vcall offset offset";
+ }
+
+ Out << ']';
+ }
+ }
+
+ break;
+ }
+
+ case VTableComponent::CK_CompleteDtorPointer:
+ case VTableComponent::CK_DeletingDtorPointer: {
+ bool IsComplete =
+ Component.getKind() == VTableComponent::CK_CompleteDtorPointer;
+
+ const CXXDestructorDecl *DD = Component.getDestructorDecl();
+
+ Out << DD->getQualifiedNameAsString();
+ if (IsComplete)
+ Out << "() [complete]";
+ else
+ Out << "() [deleting]";
+
+ if (DD->isPure())
+ Out << " [pure]";
+
+ ThunkInfo Thunk = VTableThunks.lookup(I);
+ if (!Thunk.isEmpty()) {
+ // If this destructor has a 'this' pointer adjustment, dump it.
+ if (!Thunk.This.isEmpty()) {
+ Out << "\n [this adjustment: ";
+ Out << Thunk.This.NonVirtual << " non-virtual";
+
+ if (Thunk.This.VCallOffsetOffset) {
+ Out << ", " << Thunk.This.VCallOffsetOffset;
+ Out << " vcall offset offset";
+ }
+
+ Out << ']';
+ }
+ }
+
+ break;
+ }
+
+ case VTableComponent::CK_UnusedFunctionPointer: {
+ const CXXMethodDecl *MD = Component.getUnusedFunctionDecl();
+
+ std::string Str =
+ PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual,
+ MD);
+ Out << "[unused] " << Str;
+ if (MD->isPure())
+ Out << " [pure]";
+ }
+
+ }
+
+ Out << '\n';
+
+ // Dump the next address point.
+ uint64_t NextIndex = Index + 1;
+ if (AddressPointsByIndex.count(NextIndex)) {
+ if (AddressPointsByIndex.count(NextIndex) == 1) {
+ const BaseSubobject &Base =
+ AddressPointsByIndex.find(NextIndex)->second;
+
+ Out << " -- (" << Base.getBase()->getQualifiedNameAsString();
+ Out << ", " << Base.getBaseOffset().getQuantity();
+ Out << ") vtable address --\n";
+ } else {
+ CharUnits BaseOffset =
+ AddressPointsByIndex.lower_bound(NextIndex)->second.getBaseOffset();
+
+ // We store the class names in a set to get a stable order.
+ std::set<std::string> ClassNames;
+ for (std::multimap<uint64_t, BaseSubobject>::const_iterator I =
+ AddressPointsByIndex.lower_bound(NextIndex), E =
+ AddressPointsByIndex.upper_bound(NextIndex); I != E; ++I) {
+ assert(I->second.getBaseOffset() == BaseOffset &&
+ "Invalid base offset!");
+ const CXXRecordDecl *RD = I->second.getBase();
+ ClassNames.insert(RD->getQualifiedNameAsString());
+ }
+
+ for (std::set<std::string>::const_iterator I = ClassNames.begin(),
+ E = ClassNames.end(); I != E; ++I) {
+ Out << " -- (" << *I;
+ Out << ", " << BaseOffset.getQuantity() << ") vtable address --\n";
+ }
+ }
+ }
+ }
+
+ Out << '\n';
+
+ if (isBuildingConstructorVTable())
+ return;
+
+ if (MostDerivedClass->getNumVBases()) {
+ // We store the virtual base class names and their offsets in a map to get
+ // a stable order.
+
+ std::map<std::string, CharUnits> ClassNamesAndOffsets;
+ for (VBaseOffsetOffsetsMapTy::const_iterator I = VBaseOffsetOffsets.begin(),
+ E = VBaseOffsetOffsets.end(); I != E; ++I) {
+ std::string ClassName = I->first->getQualifiedNameAsString();
+ CharUnits OffsetOffset = I->second;
+ ClassNamesAndOffsets.insert(
+ std::make_pair(ClassName, OffsetOffset));
+ }
+
+ Out << "Virtual base offset offsets for '";
+ Out << MostDerivedClass->getQualifiedNameAsString() << "' (";
+ Out << ClassNamesAndOffsets.size();
+ Out << (ClassNamesAndOffsets.size() == 1 ? " entry" : " entries") << ").\n";
+
+ for (std::map<std::string, CharUnits>::const_iterator I =
+ ClassNamesAndOffsets.begin(), E = ClassNamesAndOffsets.end();
+ I != E; ++I)
+ Out << " " << I->first << " | " << I->second.getQuantity() << '\n';
+
+ Out << "\n";
+ }
+
+ if (!Thunks.empty()) {
+ // We store the method names in a map to get a stable order.
+ std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls;
+
+ for (ThunksMapTy::const_iterator I = Thunks.begin(), E = Thunks.end();
+ I != E; ++I) {
+ const CXXMethodDecl *MD = I->first;
+ std::string MethodName =
+ PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual,
+ MD);
+
+ MethodNamesAndDecls.insert(std::make_pair(MethodName, MD));
+ }
+
+ for (std::map<std::string, const CXXMethodDecl *>::const_iterator I =
+ MethodNamesAndDecls.begin(), E = MethodNamesAndDecls.end();
+ I != E; ++I) {
+ const std::string &MethodName = I->first;
+ const CXXMethodDecl *MD = I->second;
+
+ ThunkInfoVectorTy ThunksVector = Thunks[MD];
+ std::sort(ThunksVector.begin(), ThunksVector.end());
+
+ Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
+ Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
+
+ for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) {
+ const ThunkInfo &Thunk = ThunksVector[I];
+
+ Out << llvm::format("%4d | ", I);
+
+ // If this function pointer has a return pointer adjustment, dump it.
+ if (!Thunk.Return.isEmpty()) {
+ Out << "return adjustment: " << Thunk.This.NonVirtual;
+ Out << " non-virtual";
+ if (Thunk.Return.VBaseOffsetOffset) {
+ Out << ", " << Thunk.Return.VBaseOffsetOffset;
+ Out << " vbase offset offset";
+ }
+
+ if (!Thunk.This.isEmpty())
+ Out << "\n ";
+ }
+
+ // If this function pointer has a 'this' pointer adjustment, dump it.
+ if (!Thunk.This.isEmpty()) {
+ Out << "this adjustment: ";
+ Out << Thunk.This.NonVirtual << " non-virtual";
+
+ if (Thunk.This.VCallOffsetOffset) {
+ Out << ", " << Thunk.This.VCallOffsetOffset;
+ Out << " vcall offset offset";
+ }
+ }
+
+ Out << '\n';
+ }
+
+ Out << '\n';
+ }
+ }
+
+ // Compute the vtable indices for all the member functions.
+ // Store them in a map keyed by the index so we'll get a sorted table.
+ std::map<uint64_t, std::string> IndicesMap;
+
+ for (CXXRecordDecl::method_iterator i = MostDerivedClass->method_begin(),
+ e = MostDerivedClass->method_end(); i != e; ++i) {
+ const CXXMethodDecl *MD = *i;
+
+ // We only want virtual member functions.
+ if (!MD->isVirtual())
+ continue;
+
+ std::string MethodName =
+ PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual,
+ 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]";
+ } else {
+ IndicesMap[VTables.getMethodVTableIndex(MD)] = MethodName;
+ }
+ }
+
+ // Print the vtable indices for all the member functions.
+ if (!IndicesMap.empty()) {
+ Out << "VTable indices for '";
+ Out << MostDerivedClass->getQualifiedNameAsString();
+ Out << "' (" << IndicesMap.size() << " entries).\n";
+
+ for (std::map<uint64_t, std::string>::const_iterator I = IndicesMap.begin(),
+ E = IndicesMap.end(); I != E; ++I) {
+ uint64_t VTableIndex = I->first;
+ const std::string &MethodName = I->second;
+
+ Out << llvm::format(" %4u | ", VTableIndex) << MethodName << '\n';
+ }
+ }
+
+ Out << '\n';
+}
+
+}
+
+VTableLayout::VTableLayout(uint64_t NumVTableComponents,
+ const VTableComponent *VTableComponents,
+ uint64_t NumVTableThunks,
+ const VTableThunkTy *VTableThunks,
+ const AddressPointsMapTy &AddressPoints)
+ : NumVTableComponents(NumVTableComponents),
+ VTableComponents(new VTableComponent[NumVTableComponents]),
+ NumVTableThunks(NumVTableThunks),
+ VTableThunks(new VTableThunkTy[NumVTableThunks]),
+ AddressPoints(AddressPoints) {
+ std::copy(VTableComponents, VTableComponents+NumVTableComponents,
+ this->VTableComponents);
+ std::copy(VTableThunks, VTableThunks+NumVTableThunks, this->VTableThunks);
+}
+
+VTableLayout::~VTableLayout() {
+ delete[] VTableComponents;
+}
+
+VTableContext::~VTableContext() {
+ llvm::DeleteContainerSeconds(VTableLayouts);
+}
+
+static void
+CollectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context,
+ VTableBuilder::PrimaryBasesSetVectorTy &PrimaryBases) {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
+ if (!PrimaryBase)
+ return;
+
+ CollectPrimaryBases(PrimaryBase, Context, PrimaryBases);
+
+ if (!PrimaryBases.insert(PrimaryBase))
+ llvm_unreachable("Found a duplicate primary base!");
+}
+
+void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
+
+ // Itanium C++ ABI 2.5.2:
+ // The order of the virtual function pointers in a virtual table is the
+ // order of declaration of the corresponding member functions in the class.
+ //
+ // There is an entry for any virtual function declared in a class,
+ // whether it is a new function or overrides a base class function,
+ // unless it overrides a function from the primary base, and conversion
+ // between their return types does not require an adjustment.
+
+ int64_t CurrentIndex = 0;
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
+ if (PrimaryBase) {
+ assert(PrimaryBase->isCompleteDefinition() &&
+ "Should have the definition decl of the primary base!");
+
+ // Since the record decl shares its vtable pointer with the primary base
+ // we need to start counting at the end of the primary base's vtable.
+ CurrentIndex = getNumVirtualFunctionPointers(PrimaryBase);
+ }
+
+ // Collect all the primary bases, so we can check whether methods override
+ // a method from the base.
+ VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
+ CollectPrimaryBases(RD, Context, PrimaryBases);
+
+ const CXXDestructorDecl *ImplicitVirtualDtor = 0;
+
+ for (CXXRecordDecl::method_iterator i = RD->method_begin(),
+ e = RD->method_end(); i != e; ++i) {
+ const CXXMethodDecl *MD = *i;
+
+ // We only want virtual methods.
+ if (!MD->isVirtual())
+ continue;
+
+ // Check if this method overrides a method in the primary base.
+ if (const CXXMethodDecl *OverriddenMD =
+ FindNearestOverriddenMethod(MD, PrimaryBases)) {
+ // Check if converting from the return type of the method to the
+ // return type of the overridden method requires conversion.
+ if (ComputeReturnAdjustmentBaseOffset(Context, MD,
+ OverriddenMD).isEmpty()) {
+ // This index is shared between the index in the vtable of the primary
+ // base class.
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ const CXXDestructorDecl *OverriddenDD =
+ cast<CXXDestructorDecl>(OverriddenMD);
+
+ // 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 {
+ MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD);
+ }
+
+ // We don't need to add an entry for this method.
+ continue;
+ }
+ }
+
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ if (MD->isImplicit()) {
+ assert(!ImplicitVirtualDtor &&
+ "Did already see an implicit virtual dtor!");
+ ImplicitVirtualDtor = DD;
+ continue;
+ }
+
+ // Add the complete dtor.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
+
+ // Add the deleting dtor.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
+ } else {
+ // Add the entry.
+ MethodVTableIndices[MD] = CurrentIndex++;
+ }
+ }
+
+ if (ImplicitVirtualDtor) {
+ // Itanium C++ ABI 2.5.2:
+ // If a class has an implicitly-defined virtual destructor,
+ // its entries come after the declared virtual function pointers.
+
+ // Add the complete dtor.
+ MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] =
+ CurrentIndex++;
+
+ // Add the deleting dtor.
+ MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] =
+ CurrentIndex++;
+ }
+
+ NumVirtualFunctionPointers[RD] = CurrentIndex;
+}
+
+uint64_t VTableContext::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) {
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
+ NumVirtualFunctionPointers.find(RD);
+ if (I != NumVirtualFunctionPointers.end())
+ return I->second;
+
+ ComputeMethodVTableIndices(RD);
+
+ I = NumVirtualFunctionPointers.find(RD);
+ assert(I != NumVirtualFunctionPointers.end() && "Did not find entry!");
+ return I->second;
+}
+
+uint64_t VTableContext::getMethodVTableIndex(GlobalDecl GD) {
+ MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD);
+ if (I != MethodVTableIndices.end())
+ return I->second;
+
+ const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent();
+
+ ComputeMethodVTableIndices(RD);
+
+ I = MethodVTableIndices.find(GD);
+ assert(I != MethodVTableIndices.end() && "Did not find index!");
+ return I->second;
+}
+
+CharUnits
+VTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
+ const CXXRecordDecl *VBase) {
+ ClassPairTy ClassPair(RD, VBase);
+
+ VirtualBaseClassOffsetOffsetsMapTy::iterator I =
+ VirtualBaseClassOffsetOffsets.find(ClassPair);
+ if (I != VirtualBaseClassOffsetOffsets.end())
+ return I->second;
+
+ VCallAndVBaseOffsetBuilder Builder(RD, RD, /*FinalOverriders=*/0,
+ BaseSubobject(RD, CharUnits::Zero()),
+ /*BaseIsVirtual=*/false,
+ /*OffsetInLayoutClass=*/CharUnits::Zero());
+
+ for (VCallAndVBaseOffsetBuilder::VBaseOffsetOffsetsMapTy::const_iterator I =
+ Builder.getVBaseOffsetOffsets().begin(),
+ E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) {
+ // Insert all types.
+ ClassPairTy ClassPair(RD, I->first);
+
+ VirtualBaseClassOffsetOffsets.insert(
+ std::make_pair(ClassPair, I->second));
+ }
+
+ I = VirtualBaseClassOffsetOffsets.find(ClassPair);
+ assert(I != VirtualBaseClassOffsetOffsets.end() && "Did not find index!");
+
+ return I->second;
+}
+
+static VTableLayout *CreateVTableLayout(const VTableBuilder &Builder) {
+ SmallVector<VTableLayout::VTableThunkTy, 1>
+ VTableThunks(Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
+ std::sort(VTableThunks.begin(), VTableThunks.end());
+
+ return new VTableLayout(Builder.getNumVTableComponents(),
+ Builder.vtable_component_begin(),
+ VTableThunks.size(),
+ VTableThunks.data(),
+ Builder.getAddressPoints());
+}
+
+void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
+ const VTableLayout *&Entry = VTableLayouts[RD];
+
+ // Check if we've computed this information before.
+ if (Entry)
+ return;
+
+ VTableBuilder Builder(*this, RD, CharUnits::Zero(),
+ /*MostDerivedClassIsVirtual=*/0, RD);
+ Entry = CreateVTableLayout(Builder);
+
+ // Add the known thunks.
+ Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
+
+ // If we don't have the vbase information for this class, insert it.
+ // getVirtualBaseOffsetOffset will compute it separately without computing
+ // the rest of the vtable related information.
+ if (!RD->getNumVBases())
+ return;
+
+ const RecordType *VBaseRT =
+ RD->vbases_begin()->getType()->getAs<RecordType>();
+ const CXXRecordDecl *VBase = cast<CXXRecordDecl>(VBaseRT->getDecl());
+
+ if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase)))
+ return;
+
+ for (VTableBuilder::VBaseOffsetOffsetsMapTy::const_iterator I =
+ Builder.getVBaseOffsetOffsets().begin(),
+ E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) {
+ // Insert all types.
+ ClassPairTy ClassPair(RD, I->first);
+
+ VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I->second));
+ }
+}
+
+VTableLayout *VTableContext::createConstructionVTableLayout(
+ const CXXRecordDecl *MostDerivedClass,
+ CharUnits MostDerivedClassOffset,
+ bool MostDerivedClassIsVirtual,
+ const CXXRecordDecl *LayoutClass) {
+ VTableBuilder Builder(*this, MostDerivedClass, MostDerivedClassOffset,
+ MostDerivedClassIsVirtual, LayoutClass);
+ return CreateVTableLayout(Builder);
+}
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index 678f02fd71fb..3dd194b8e80a 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -24,25 +24,44 @@
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/Support/BumpVector.h"
+#include "clang/Analysis/Support/SaveAndRestore.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
+typedef llvm::DenseMap<const void *, ManagedAnalysis *> ManagedAnalysisMap;
+
AnalysisContext::AnalysisContext(const Decl *d,
idx::TranslationUnit *tu,
- bool useUnoptimizedCFG,
- bool addehedges,
- bool addImplicitDtors,
- bool addInitializers)
+ const CFG::BuildOptions &buildOptions)
: D(d), TU(tu),
+ cfgBuildOptions(buildOptions),
forcedBlkExprs(0),
- builtCFG(false), builtCompleteCFG(false),
- useUnoptimizedCFG(useUnoptimizedCFG),
- ReferencedBlockVars(0)
-{
+ builtCFG(false),
+ builtCompleteCFG(false),
+ ReferencedBlockVars(0),
+ ManagedAnalyses(0)
+{
+ cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs;
+}
+
+AnalysisContext::AnalysisContext(const Decl *d,
+ idx::TranslationUnit *tu)
+: D(d), TU(tu),
+ forcedBlkExprs(0),
+ builtCFG(false),
+ builtCompleteCFG(false),
+ ReferencedBlockVars(0),
+ ManagedAnalyses(0)
+{
cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs;
- cfgBuildOptions.AddEHEdges = addehedges;
+}
+
+AnalysisContextManager::AnalysisContextManager(bool useUnoptimizedCFG,
+ bool addImplicitDtors,
+ bool addInitializers) {
+ cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
cfgBuildOptions.AddImplicitDtors = addImplicitDtors;
cfgBuildOptions.AddInitializers = addInitializers;
}
@@ -53,7 +72,7 @@ void AnalysisContextManager::clear() {
Contexts.clear();
}
-Stmt *AnalysisContext::getBody() {
+Stmt *AnalysisContext::getBody() const {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
return FD->getBody();
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
@@ -95,7 +114,7 @@ AnalysisContext::getBlockForRegisteredExpression(const Stmt *stmt) {
}
CFG *AnalysisContext::getCFG() {
- if (useUnoptimizedCFG)
+ if (!cfgBuildOptions.PruneTriviallyFalseEdges)
return getUnoptimizedCFG();
if (!builtCFG) {
@@ -110,9 +129,10 @@ CFG *AnalysisContext::getCFG() {
CFG *AnalysisContext::getUnoptimizedCFG() {
if (!builtCompleteCFG) {
- CFG::BuildOptions B = cfgBuildOptions;
- B.PruneTriviallyFalseEdges = false;
- completeCFG.reset(CFG::buildCFG(D, getBody(), &D->getASTContext(), B));
+ SaveAndRestore<bool> NotPrune(cfgBuildOptions.PruneTriviallyFalseEdges,
+ false);
+ completeCFG.reset(CFG::buildCFG(D, getBody(), &D->getASTContext(),
+ cfgBuildOptions));
// Even when the cfg is not successfully built, we don't
// want to try building it again.
builtCompleteCFG = true;
@@ -160,36 +180,11 @@ PseudoConstantAnalysis *AnalysisContext::getPseudoConstantAnalysis() {
return PCA.get();
}
-LiveVariables *AnalysisContext::getLiveVariables() {
- if (!liveness) {
- if (CFG *c = getCFG()) {
- liveness.reset(new LiveVariables(*this));
- liveness->runOnCFG(*c);
- liveness->runOnAllBlocks(*c, 0, true);
- }
- }
-
- return liveness.get();
-}
-
-LiveVariables *AnalysisContext::getRelaxedLiveVariables() {
- if (!relaxedLiveness)
- if (CFG *c = getCFG()) {
- relaxedLiveness.reset(new LiveVariables(*this, false));
- relaxedLiveness->runOnCFG(*c);
- relaxedLiveness->runOnAllBlocks(*c, 0, true);
- }
-
- return relaxedLiveness.get();
-}
-
AnalysisContext *AnalysisContextManager::getContext(const Decl *D,
idx::TranslationUnit *TU) {
AnalysisContext *&AC = Contexts[D];
if (!AC)
- AC = new AnalysisContext(D, TU, UseUnoptimizedCFG, false,
- AddImplicitDtors, AddInitializers);
-
+ AC = new AnalysisContext(D, TU, cfgBuildOptions);
return AC;
}
@@ -201,7 +196,7 @@ void LocationContext::ProfileCommon(llvm::FoldingSetNodeID &ID,
ContextKind ck,
AnalysisContext *ctx,
const LocationContext *parent,
- const void* data) {
+ const void *data) {
ID.AddInteger(ck);
ID.AddPointer(ctx);
ID.AddPointer(parent);
@@ -392,13 +387,29 @@ AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) {
return std::make_pair(V->begin(), V->end());
}
+ManagedAnalysis *&AnalysisContext::getAnalysisImpl(const void *tag) {
+ if (!ManagedAnalyses)
+ ManagedAnalyses = new ManagedAnalysisMap();
+ ManagedAnalysisMap *M = (ManagedAnalysisMap*) ManagedAnalyses;
+ return (*M)[tag];
+}
+
//===----------------------------------------------------------------------===//
// Cleanup.
//===----------------------------------------------------------------------===//
+ManagedAnalysis::~ManagedAnalysis() {}
+
AnalysisContext::~AnalysisContext() {
delete forcedBlkExprs;
delete ReferencedBlockVars;
+ // Release the managed analyses.
+ if (ManagedAnalyses) {
+ ManagedAnalysisMap *M = (ManagedAnalysisMap*) ManagedAnalyses;
+ for (ManagedAnalysisMap::iterator I = M->begin(), E = M->end(); I!=E; ++I)
+ delete I->second;
+ delete M;
+ }
}
AnalysisContextManager::~AnalysisContextManager() {
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index f231c147f11e..83c7384db0f4 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -29,9 +29,9 @@ using namespace clang;
namespace {
-static SourceLocation GetEndLoc(Decl* D) {
- if (VarDecl* VD = dyn_cast<VarDecl>(D))
- if (Expr* Ex = VD->getInit())
+static SourceLocation GetEndLoc(Decl *D) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(D))
+ if (Expr *Ex = VD->getInit())
return Ex->getSourceRange().getEnd();
return D->getLocation();
}
@@ -121,16 +121,16 @@ public:
*this = Scope->Prev;
}
- VarDecl* const* operator->() const {
+ VarDecl *const* operator->() const {
assert (Scope && "Dereferencing invalid iterator is not allowed");
assert (VarIter != 0 && "Iterator has invalid value of VarIter member");
return &Scope->Vars[VarIter - 1];
}
- VarDecl* operator*() const {
+ VarDecl *operator*() const {
return *this->operator->();
}
- const_iterator& operator++() {
+ const_iterator &operator++() {
if (!Scope)
return *this;
@@ -146,10 +146,10 @@ public:
return P;
}
- bool operator==(const const_iterator& rhs) const {
+ bool operator==(const const_iterator &rhs) const {
return Scope == rhs.Scope && VarIter == rhs.VarIter;
}
- bool operator!=(const const_iterator& rhs) const {
+ bool operator!=(const const_iterator &rhs) const {
return !(*this == rhs);
}
@@ -179,7 +179,7 @@ public:
/// Begin of scope in direction of CFG building (backwards).
const_iterator begin() const { return const_iterator(*this, Vars.size()); }
- void addVar(VarDecl* VD) {
+ void addVar(VarDecl *VD) {
Vars.push_back(VD, ctx);
}
};
@@ -205,7 +205,7 @@ int LocalScope::const_iterator::distance(LocalScope::const_iterator L) {
/// and LocalScope::const_iterator that specifies position in LocalScope graph.
struct BlockScopePosPair {
BlockScopePosPair() : block(0) {}
- BlockScopePosPair(CFGBlock* b, LocalScope::const_iterator scopePos)
+ BlockScopePosPair(CFGBlock *b, LocalScope::const_iterator scopePos)
: block(b), scopePosition(scopePos) {}
CFGBlock *block;
@@ -252,13 +252,13 @@ class CFGBuilder {
ASTContext *Context;
llvm::OwningPtr<CFG> cfg;
- CFGBlock* Block;
- CFGBlock* Succ;
+ CFGBlock *Block;
+ CFGBlock *Succ;
JumpTarget ContinueJumpTarget;
JumpTarget BreakJumpTarget;
- CFGBlock* SwitchTerminatedBlock;
- CFGBlock* DefaultCaseBlock;
- CFGBlock* TryTerminatedBlock;
+ CFGBlock *SwitchTerminatedBlock;
+ CFGBlock *DefaultCaseBlock;
+ CFGBlock *TryTerminatedBlock;
// Current position in local scope.
LocalScope::const_iterator ScopePos;
@@ -305,7 +305,7 @@ private:
// Visitors to walk an AST and construct the CFG.
CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc);
CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc);
- CFGBlock *VisitBlockExpr(BlockExpr* E, AddStmtChoice asc);
+ CFGBlock *VisitBlockExpr(BlockExpr *E, AddStmtChoice asc);
CFGBlock *VisitBreakStmt(BreakStmt *B);
CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S);
CFGBlock *VisitExprWithCleanups(ExprWithCleanups *E,
@@ -328,11 +328,11 @@ private:
AddStmtChoice asc);
CFGBlock *VisitContinueStmt(ContinueStmt *C);
CFGBlock *VisitDeclStmt(DeclStmt *DS);
- CFGBlock *VisitDeclSubExpr(DeclStmt* DS);
+ CFGBlock *VisitDeclSubExpr(DeclStmt *DS);
CFGBlock *VisitDefaultStmt(DefaultStmt *D);
CFGBlock *VisitDoStmt(DoStmt *D);
CFGBlock *VisitForStmt(ForStmt *F);
- CFGBlock *VisitGotoStmt(GotoStmt* G);
+ CFGBlock *VisitGotoStmt(GotoStmt *G);
CFGBlock *VisitIfStmt(IfStmt *I);
CFGBlock *VisitImplicitCastExpr(ImplicitCastExpr *E, AddStmtChoice asc);
CFGBlock *VisitIndirectGotoStmt(IndirectGotoStmt *I);
@@ -343,7 +343,7 @@ private:
CFGBlock *VisitObjCAtThrowStmt(ObjCAtThrowStmt *S);
CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S);
CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S);
- CFGBlock *VisitReturnStmt(ReturnStmt* R);
+ CFGBlock *VisitReturnStmt(ReturnStmt *R);
CFGBlock *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
AddStmtChoice asc);
CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc);
@@ -353,7 +353,7 @@ private:
CFGBlock *Visit(Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd);
CFGBlock *VisitStmt(Stmt *S, AddStmtChoice asc);
- CFGBlock *VisitChildren(Stmt* S);
+ CFGBlock *VisitChildren(Stmt *S);
// Visitors to walk an AST and generate destructors of temporaries in
// full expression.
@@ -367,34 +367,35 @@ private:
bool BindToTemporary);
// NYS == Not Yet Supported
- CFGBlock* NYS() {
+ CFGBlock *NYS() {
badCFG = true;
return Block;
}
void autoCreateBlock() { if (!Block) Block = createBlock(); }
CFGBlock *createBlock(bool add_successor = true);
+ CFGBlock *createNoReturnBlock();
CFGBlock *addStmt(Stmt *S) {
return Visit(S, AddStmtChoice::AlwaysAdd);
}
CFGBlock *addInitializer(CXXCtorInitializer *I);
void addAutomaticObjDtors(LocalScope::const_iterator B,
- LocalScope::const_iterator E, Stmt* S);
+ LocalScope::const_iterator E, Stmt *S);
void addImplicitDtorsForDestructor(const CXXDestructorDecl *DD);
// Local scopes creation.
LocalScope* createOrReuseLocalScope(LocalScope* Scope);
- void addLocalScopeForStmt(Stmt* S);
- LocalScope* addLocalScopeForDeclStmt(DeclStmt* DS, LocalScope* Scope = NULL);
- LocalScope* addLocalScopeForVarDecl(VarDecl* VD, LocalScope* Scope = NULL);
+ void addLocalScopeForStmt(Stmt *S);
+ LocalScope* addLocalScopeForDeclStmt(DeclStmt *DS, LocalScope* Scope = NULL);
+ LocalScope* addLocalScopeForVarDecl(VarDecl *VD, LocalScope* Scope = NULL);
- void addLocalScopeAndDtors(Stmt* S);
+ void addLocalScopeAndDtors(Stmt *S);
// Interface to CFGBlock - adding CFGElements.
void appendStmt(CFGBlock *B, const Stmt *S) {
- if (alwaysAdd(S))
+ if (alwaysAdd(S) && cachedEntry)
cachedEntry->second = B;
// All block-level expressions should have already been IgnoreParens()ed.
@@ -413,12 +414,11 @@ private:
void appendTemporaryDtor(CFGBlock *B, CXXBindTemporaryExpr *E) {
B->appendTemporaryDtor(E, cfg->getBumpVectorContext());
}
+ void appendAutomaticObjDtor(CFGBlock *B, VarDecl *VD, Stmt *S) {
+ B->appendAutomaticObjDtor(VD, S, cfg->getBumpVectorContext());
+ }
- void insertAutomaticObjDtors(CFGBlock* Blk, CFGBlock::iterator I,
- LocalScope::const_iterator B, LocalScope::const_iterator E, Stmt* S);
- void appendAutomaticObjDtors(CFGBlock* Blk, LocalScope::const_iterator B,
- LocalScope::const_iterator E, Stmt* S);
- void prependAutomaticObjDtorsWithTerminator(CFGBlock* Blk,
+ void prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk,
LocalScope::const_iterator B, LocalScope::const_iterator E);
void addSuccessor(CFGBlock *B, CFGBlock *S) {
@@ -437,20 +437,12 @@ private:
/// tryEvaluateBool - Try and evaluate the Stmt and return 0 or 1
/// if we can evaluate to a known value, otherwise return -1.
TryResult tryEvaluateBool(Expr *S) {
- Expr::EvalResult Result;
- if (!tryEvaluate(S, Result))
+ bool Result;
+ if (!BuildOpts.PruneTriviallyFalseEdges ||
+ S->isTypeDependent() || S->isValueDependent() ||
+ !S->EvaluateAsBooleanCondition(Result, *Context))
return TryResult();
-
- if (Result.Val.isInt())
- return Result.Val.getInt().getBoolValue();
-
- if (Result.Val.isLValue()) {
- const Expr *e = Result.Val.getLValueBase();
- const CharUnits &c = Result.Val.getLValueOffset();
- if (!e && c.isZero())
- return false;
- }
- return TryResult();
+ return Result;
}
};
@@ -461,15 +453,17 @@ inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder,
}
bool CFGBuilder::alwaysAdd(const Stmt *stmt) {
+ bool shouldAdd = BuildOpts.alwaysAdd(stmt);
+
if (!BuildOpts.forcedBlkExprs)
- return false;
+ return shouldAdd;
if (lastLookup == stmt) {
if (cachedEntry) {
assert(cachedEntry->first == stmt);
return true;
}
- return false;
+ return shouldAdd;
}
lastLookup = stmt;
@@ -480,13 +474,13 @@ bool CFGBuilder::alwaysAdd(const Stmt *stmt) {
if (!fb) {
// No need to update 'cachedEntry', since it will always be null.
assert(cachedEntry == 0);
- return false;
+ return shouldAdd;
}
CFG::BuildOptions::ForcedBlkExprs::iterator itr = fb->find(stmt);
if (itr == fb->end()) {
cachedEntry = 0;
- return false;
+ return shouldAdd;
}
cachedEntry = &*itr;
@@ -512,7 +506,7 @@ static const VariableArrayType *FindVA(const Type *t) {
/// body (compound statement). The ownership of the returned CFG is
/// transferred to the caller. If CFG construction fails, this method returns
/// NULL.
-CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement) {
+CFG* CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
assert(cfg.get());
if (!Statement)
return NULL;
@@ -552,8 +546,8 @@ CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement) {
for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(),
E = BackpatchBlocks.end(); I != E; ++I ) {
- CFGBlock* B = I->block;
- GotoStmt* G = cast<GotoStmt>(B->getTerminator());
+ CFGBlock *B = I->block;
+ 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
@@ -567,7 +561,7 @@ CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement) {
}
// Add successors to the Indirect Goto Dispatch block (if we have one).
- if (CFGBlock* B = cfg->getIndirectGotoBlock())
+ if (CFGBlock *B = cfg->getIndirectGotoBlock())
for (LabelSetTy::iterator I = AddressTakenLabels.begin(),
E = AddressTakenLabels.end(); I != E; ++I ) {
@@ -589,13 +583,23 @@ CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement) {
/// createBlock - Used to lazily create blocks that are connected
/// to the current (global) succcessor.
-CFGBlock* CFGBuilder::createBlock(bool add_successor) {
- CFGBlock* B = cfg->createBlock();
+CFGBlock *CFGBuilder::createBlock(bool add_successor) {
+ CFGBlock *B = cfg->createBlock();
if (add_successor && Succ)
addSuccessor(B, Succ);
return B;
}
+/// createNoReturnBlock - Used to create a block is a 'noreturn' point in the
+/// CFG. It is *not* connected to the current (global) successor, and instead
+/// directly tied to the exit block in order to be reachable.
+CFGBlock *CFGBuilder::createNoReturnBlock() {
+ CFGBlock *B = createBlock(false);
+ B->setHasNoReturnElement();
+ addSuccessor(B, &cfg->getExit());
+ return B;
+}
+
/// addInitializer - Add C++ base or member initializer element to CFG.
CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
if (!BuildOpts.AddInitializers)
@@ -638,15 +642,41 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
/// for objects in range of local scope positions. Use S as trigger statement
/// for destructors.
void CFGBuilder::addAutomaticObjDtors(LocalScope::const_iterator B,
- LocalScope::const_iterator E, Stmt* S) {
+ LocalScope::const_iterator E, Stmt *S) {
if (!BuildOpts.AddImplicitDtors)
return;
if (B == E)
return;
- autoCreateBlock();
- appendAutomaticObjDtors(Block, B, E, S);
+ CFGBlock::iterator InsertPos;
+
+ // We need to append the destructors in reverse order, but any one of them
+ // may be a no-return destructor which changes the CFG. As a result, buffer
+ // this sequence up and replay them in reverse order when appending onto the
+ // CFGBlock(s).
+ SmallVector<VarDecl*, 10> Decls;
+ Decls.reserve(B.distance(E));
+ for (LocalScope::const_iterator I = B; I != E; ++I)
+ Decls.push_back(*I);
+
+ for (SmallVectorImpl<VarDecl*>::reverse_iterator I = Decls.rbegin(),
+ E = Decls.rend();
+ I != E; ++I) {
+ // If this destructor is marked as a no-return destructor, we need to
+ // create 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.
+ QualType Ty = (*I)->getType().getNonReferenceType();
+ if (const ArrayType *AT = Context->getAsArrayType(Ty))
+ Ty = AT->getElementType();
+ const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor();
+ if (cast<FunctionType>(Dtor->getType())->getNoReturnAttr())
+ Block = createNoReturnBlock();
+ else
+ autoCreateBlock();
+
+ appendAutomaticObjDtor(Block, *I, S);
+ }
}
/// addImplicitDtorsForDestructor - Add implicit destructors generated for
@@ -711,7 +741,7 @@ LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope* Scope) {
/// addLocalScopeForStmt - Add LocalScope to local scopes tree for statement
/// that should create implicit scope (e.g. if/else substatements).
-void CFGBuilder::addLocalScopeForStmt(Stmt* S) {
+void CFGBuilder::addLocalScopeForStmt(Stmt *S) {
if (!BuildOpts.AddImplicitDtors)
return;
@@ -721,9 +751,7 @@ void CFGBuilder::addLocalScopeForStmt(Stmt* S) {
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) {
for (CompoundStmt::body_iterator BI = CS->body_begin(), BE = CS->body_end()
; BI != BE; ++BI) {
- Stmt *SI = *BI;
- if (LabelStmt *LS = dyn_cast<LabelStmt>(SI))
- SI = LS->getSubStmt();
+ Stmt *SI = (*BI)->stripLabelLikeStatements();
if (DeclStmt *DS = dyn_cast<DeclStmt>(SI))
Scope = addLocalScopeForDeclStmt(DS, Scope);
}
@@ -732,22 +760,20 @@ void CFGBuilder::addLocalScopeForStmt(Stmt* S) {
// For any other statement scope will be implicit and as such will be
// interesting only for DeclStmt.
- if (LabelStmt *LS = dyn_cast<LabelStmt>(S))
- S = LS->getSubStmt();
- if (DeclStmt *DS = dyn_cast<DeclStmt>(S))
+ if (DeclStmt *DS = dyn_cast<DeclStmt>(S->stripLabelLikeStatements()))
addLocalScopeForDeclStmt(DS);
}
/// addLocalScopeForDeclStmt - Add LocalScope for declaration statement. Will
/// reuse Scope if not NULL.
-LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt* DS,
+LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS,
LocalScope* Scope) {
if (!BuildOpts.AddImplicitDtors)
return Scope;
for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end()
; DI != DE; ++DI) {
- if (VarDecl* VD = dyn_cast<VarDecl>(*DI))
+ if (VarDecl *VD = dyn_cast<VarDecl>(*DI))
Scope = addLocalScopeForVarDecl(VD, Scope);
}
return Scope;
@@ -756,7 +782,7 @@ LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt* DS,
/// addLocalScopeForVarDecl - Add LocalScope for variable declaration. It will
/// create add scope for automatic objects and temporary objects bound to
/// const reference. Will reuse Scope if not NULL.
-LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl* VD,
+LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
LocalScope* Scope) {
if (!BuildOpts.AddImplicitDtors)
return Scope;
@@ -788,7 +814,7 @@ LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl* VD,
}
// Check if type is a C++ class with non-trivial destructor.
- if (const CXXRecordDecl* CD = QT->getAsCXXRecordDecl())
+ if (const CXXRecordDecl *CD = QT->getAsCXXRecordDecl())
if (!CD->hasTrivialDestructor()) {
// Add the variable to scope
Scope = createOrReuseLocalScope(Scope);
@@ -800,7 +826,7 @@ LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl* VD,
/// addLocalScopeAndDtors - For given statement add local scope for it and
/// add destructors that will cleanup the scope. Will reuse Scope if not NULL.
-void CFGBuilder::addLocalScopeAndDtors(Stmt* S) {
+void CFGBuilder::addLocalScopeAndDtors(Stmt *S) {
if (!BuildOpts.AddImplicitDtors)
return;
@@ -809,40 +835,27 @@ void CFGBuilder::addLocalScopeAndDtors(Stmt* S) {
addAutomaticObjDtors(ScopePos, scopeBeginPos, S);
}
-/// insertAutomaticObjDtors - Insert destructor CFGElements for variables with
-/// automatic storage duration to CFGBlock's elements vector. Insertion will be
-/// performed in place specified with iterator.
-void CFGBuilder::insertAutomaticObjDtors(CFGBlock* Blk, CFGBlock::iterator I,
- LocalScope::const_iterator B, LocalScope::const_iterator E, Stmt* S) {
- BumpVectorContext& C = cfg->getBumpVectorContext();
- I = Blk->beginAutomaticObjDtorsInsert(I, B.distance(E), C);
- while (B != E)
- I = Blk->insertAutomaticObjDtor(I, *B++, S);
-}
-
-/// appendAutomaticObjDtors - Append destructor CFGElements for variables with
-/// automatic storage duration to CFGBlock's elements vector. Elements will be
-/// appended to physical end of the vector which happens to be logical
-/// beginning.
-void CFGBuilder::appendAutomaticObjDtors(CFGBlock* Blk,
- LocalScope::const_iterator B, LocalScope::const_iterator E, Stmt* S) {
- insertAutomaticObjDtors(Blk, Blk->begin(), B, E, S);
-}
-
/// prependAutomaticObjDtorsWithTerminator - Prepend destructor CFGElements for
/// variables with automatic storage duration to CFGBlock's elements vector.
/// Elements will be prepended to physical beginning of the vector which
/// happens to be logical end. Use blocks terminator as statement that specifies
/// destructors call site.
-void CFGBuilder::prependAutomaticObjDtorsWithTerminator(CFGBlock* Blk,
+/// FIXME: This mechanism for adding automatic destructors doesn't handle
+/// no-return destructors properly.
+void CFGBuilder::prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk,
LocalScope::const_iterator B, LocalScope::const_iterator E) {
- insertAutomaticObjDtors(Blk, Blk->end(), B, E, Blk->getTerminator());
+ BumpVectorContext &C = cfg->getBumpVectorContext();
+ CFGBlock::iterator InsertPos
+ = Blk->beginAutomaticObjDtorsInsert(Blk->end(), B.distance(E), C);
+ for (LocalScope::const_iterator I = B; I != E; ++I)
+ InsertPos = Blk->insertAutomaticObjDtor(InsertPos, *I,
+ Blk->getTerminator());
}
/// Visit - Walk the subtree of a statement and add extra
/// blocks for ternary operators, &&, and ||. We also process "," and
/// DeclStmts (which may contain nested control-flow).
-CFGBlock* CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
+CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
if (!S) {
badCFG = true;
return 0;
@@ -996,7 +1009,7 @@ CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) {
}
/// VisitChildren - Visit the children of a Stmt.
-CFGBlock *CFGBuilder::VisitChildren(Stmt* Terminator) {
+CFGBlock *CFGBuilder::VisitChildren(Stmt *Terminator) {
CFGBlock *lastBlock = Block;
for (Stmt::child_range I = Terminator->children(); I; ++I)
if (Stmt *child = *I)
@@ -1031,20 +1044,20 @@ CFGBlock *CFGBuilder::VisitUnaryOperator(UnaryOperator *U,
CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
AddStmtChoice asc) {
if (B->isLogicalOp()) { // && or ||
- CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
+ CFGBlock *ConfluenceBlock = Block ? Block : createBlock();
appendStmt(ConfluenceBlock, B);
if (badCFG)
return 0;
// create the block evaluating the LHS
- CFGBlock* LHSBlock = createBlock(false);
+ CFGBlock *LHSBlock = createBlock(false);
LHSBlock->setTerminator(B);
// create the block evaluating the RHS
Succ = ConfluenceBlock;
Block = NULL;
- CFGBlock* RHSBlock = addStmt(B->getRHS());
+ CFGBlock *RHSBlock = addStmt(B->getRHS());
if (RHSBlock) {
if (badCFG)
@@ -1191,13 +1204,13 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
return 0;
}
- Block = createBlock(!NoReturn);
+ if (NoReturn)
+ Block = createNoReturnBlock();
+ else
+ Block = createBlock();
+
appendStmt(Block, C);
- if (NoReturn) {
- // Wire this to the exit block directly.
- addSuccessor(Block, &cfg->getExit());
- }
if (AddEHEdge) {
// Add exceptional edges.
if (TryTerminatedBlock)
@@ -1211,7 +1224,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C,
AddStmtChoice asc) {
- CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
+ CFGBlock *ConfluenceBlock = Block ? Block : createBlock();
appendStmt(ConfluenceBlock, C);
if (badCFG)
return 0;
@@ -1219,13 +1232,13 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C,
AddStmtChoice alwaysAdd = asc.withAlwaysAdd(true);
Succ = ConfluenceBlock;
Block = NULL;
- CFGBlock* LHSBlock = Visit(C->getLHS(), alwaysAdd);
+ CFGBlock *LHSBlock = Visit(C->getLHS(), alwaysAdd);
if (badCFG)
return 0;
Succ = ConfluenceBlock;
Block = NULL;
- CFGBlock* RHSBlock = Visit(C->getRHS(), alwaysAdd);
+ CFGBlock *RHSBlock = Visit(C->getRHS(), alwaysAdd);
if (badCFG)
return 0;
@@ -1239,9 +1252,9 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C,
}
-CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) {
+CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C) {
addLocalScopeAndDtors(C);
- CFGBlock* LastBlock = Block;
+ CFGBlock *LastBlock = Block;
for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend();
I != E; ++I ) {
@@ -1264,7 +1277,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C,
// Create the confluence block that will "merge" the results of the ternary
// expression.
- CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
+ CFGBlock *ConfluenceBlock = Block ? Block : createBlock();
appendStmt(ConfluenceBlock, C);
if (badCFG)
return 0;
@@ -1277,7 +1290,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C,
// e.g: x ?: y is shorthand for: x ? x : y;
Succ = ConfluenceBlock;
Block = NULL;
- CFGBlock* LHSBlock = 0;
+ CFGBlock *LHSBlock = 0;
const Expr *trueExpr = C->getTrueExpr();
if (trueExpr != opaqueValue) {
LHSBlock = Visit(C->getTrueExpr(), alwaysAdd);
@@ -1290,7 +1303,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C,
// Create the block for the RHS expression.
Succ = ConfluenceBlock;
- CFGBlock* RHSBlock = Visit(C->getFalseExpr(), alwaysAdd);
+ CFGBlock *RHSBlock = Visit(C->getFalseExpr(), alwaysAdd);
if (badCFG)
return 0;
@@ -1331,7 +1344,7 @@ CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
CFGBlock *B = 0;
// FIXME: Add a reverse iterator for DeclStmt to avoid this extra copy.
- typedef llvm::SmallVector<Decl*,10> BufTy;
+ typedef SmallVector<Decl*,10> BufTy;
BufTy Buf(DS->decl_begin(), DS->decl_end());
for (BufTy::reverse_iterator I = Buf.rbegin(), E = Buf.rend(); I != E; ++I) {
@@ -1355,7 +1368,7 @@ CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
/// VisitDeclSubExpr - Utility method to add block-level expressions for
/// DeclStmts and initializers in them.
-CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt* DS) {
+CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
assert(DS->isSingleDecl() && "Can handle single declarations only.");
Decl *D = DS->getSingleDecl();
@@ -1414,7 +1427,7 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt* DS) {
return Block;
}
-CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) {
+CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
// We may see an if statement in the middle of a basic block, or it may be the
// first statement we are processing. In either case, we create a new basic
// block. First, we create the blocks for the then...else statements, and
@@ -1428,7 +1441,7 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) {
// Create local scope for possible condition variable.
// Store scope position. Add implicit destructor.
- if (VarDecl* VD = I->getConditionVariable()) {
+ if (VarDecl *VD = I->getConditionVariable()) {
LocalScope::const_iterator BeginScopePos = ScopePos;
addLocalScopeForVarDecl(VD);
addAutomaticObjDtors(ScopePos, BeginScopePos, I);
@@ -1443,9 +1456,9 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) {
}
// Process the false branch.
- CFGBlock* ElseBlock = Succ;
+ CFGBlock *ElseBlock = Succ;
- if (Stmt* Else = I->getElse()) {
+ if (Stmt *Else = I->getElse()) {
SaveAndRestore<CFGBlock*> sv(Succ);
// NULL out Block so that the recursive call to Visit will
@@ -1468,9 +1481,9 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) {
}
// Process the true branch.
- CFGBlock* ThenBlock;
+ CFGBlock *ThenBlock;
{
- Stmt* Then = I->getThen();
+ Stmt *Then = I->getThen();
assert(Then);
SaveAndRestore<CFGBlock*> sv(Succ);
Block = NULL;
@@ -1526,7 +1539,7 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) {
}
-CFGBlock* CFGBuilder::VisitReturnStmt(ReturnStmt* R) {
+CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) {
// If we were in the middle of a block we stop processing that block.
//
// NOTE: If a "return" appears in the middle of a block, this means that the
@@ -1546,7 +1559,7 @@ CFGBlock* CFGBuilder::VisitReturnStmt(ReturnStmt* R) {
return VisitStmt(R, AddStmtChoice::AlwaysAdd);
}
-CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt *L) {
+CFGBlock *CFGBuilder::VisitLabelStmt(LabelStmt *L) {
// Get the block of the labeled statement. Add it to our map.
addStmt(L->getSubStmt());
CFGBlock *LabelBlock = Block;
@@ -1575,7 +1588,7 @@ CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt *L) {
return LabelBlock;
}
-CFGBlock* CFGBuilder::VisitGotoStmt(GotoStmt* G) {
+CFGBlock *CFGBuilder::VisitGotoStmt(GotoStmt *G) {
// Goto is a control-flow statement. Thus we stop processing the current
// block and create a new one.
@@ -1597,8 +1610,8 @@ CFGBlock* CFGBuilder::VisitGotoStmt(GotoStmt* G) {
return Block;
}
-CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
- CFGBlock* LoopSuccessor = NULL;
+CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
+ CFGBlock *LoopSuccessor = NULL;
// Save local scope position because in case of condition variable ScopePos
// won't be restored when traversing AST.
@@ -1607,11 +1620,11 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
// Create local scope for init statement and possible condition variable.
// Add destructor for init statement and condition variable.
// Store scope position for continue statement.
- if (Stmt* Init = F->getInit())
+ if (Stmt *Init = F->getInit())
addLocalScopeForStmt(Init);
LocalScope::const_iterator LoopBeginScopePos = ScopePos;
- if (VarDecl* VD = F->getConditionVariable())
+ if (VarDecl *VD = F->getConditionVariable())
addLocalScopeForVarDecl(VD);
LocalScope::const_iterator ContinueScopePos = ScopePos;
@@ -1634,15 +1647,15 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
// Because of short-circuit evaluation, the condition of the loop can span
// multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that
// evaluate the condition.
- CFGBlock* ExitConditionBlock = createBlock(false);
- CFGBlock* EntryConditionBlock = ExitConditionBlock;
+ CFGBlock *ExitConditionBlock = createBlock(false);
+ CFGBlock *EntryConditionBlock = ExitConditionBlock;
// Set the terminator for the "exit" condition block.
ExitConditionBlock->setTerminator(F);
// Now add the actual condition to the condition block. Because the condition
// itself may contain control-flow, new blocks may be created.
- if (Stmt* C = F->getCond()) {
+ if (Stmt *C = F->getCond()) {
Block = ExitConditionBlock;
EntryConditionBlock = addStmt(C);
if (badCFG)
@@ -1691,7 +1704,7 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
// Loop body should end with destructor of Condition variable (if any).
addAutomaticObjDtors(ScopePos, LoopBeginScopePos, F);
- if (Stmt* I = F->getInc()) {
+ if (Stmt *I = F->getInc()) {
// Generate increment code in its own basic block. This is the target of
// continue statements.
Succ = addStmt(I);
@@ -1723,7 +1736,7 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
// Now populate the body block, and in the process create new blocks as we
// walk the body of the loop.
- CFGBlock* BodyBlock = addStmt(F->getBody());
+ CFGBlock *BodyBlock = addStmt(F->getBody());
if (!BodyBlock)
BodyBlock = ContinueJumpTarget.block;//can happen for "for (...;...;...);"
@@ -1740,7 +1753,7 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
// If the loop contains initialization, create a new block for those
// statements. This block can also contain statements that precede the loop.
- if (Stmt* I = F->getInit()) {
+ if (Stmt *I = F->getInit()) {
Block = createBlock();
return addStmt(I);
}
@@ -1760,7 +1773,7 @@ CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) {
return Visit(M->getBase());
}
-CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
+CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
// Objective-C fast enumeration 'for' statements:
// http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC
//
@@ -1793,7 +1806,7 @@ CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
// a DeclStmt and the other returns a DeclRefExpr.
//
- CFGBlock* LoopSuccessor = 0;
+ CFGBlock *LoopSuccessor = 0;
if (Block) {
if (badCFG)
@@ -1804,8 +1817,7 @@ CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
LoopSuccessor = Succ;
// Build the condition blocks.
- CFGBlock* ExitConditionBlock = createBlock(false);
- CFGBlock* EntryConditionBlock = ExitConditionBlock;
+ CFGBlock *ExitConditionBlock = createBlock(false);
// Set the terminator for the "exit" condition block.
ExitConditionBlock->setTerminator(S);
@@ -1819,7 +1831,8 @@ CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
// Walk the 'element' expression to see if there are any side-effects. We
// generate new blocks as necessary. We DON'T add the statement by default to
// the CFG unless it contains control-flow.
- EntryConditionBlock = Visit(S->getElement(), AddStmtChoice::NotAlwaysAdd);
+ CFGBlock *EntryConditionBlock = Visit(S->getElement(),
+ AddStmtChoice::NotAlwaysAdd);
if (Block) {
if (badCFG)
return 0;
@@ -1840,7 +1853,7 @@ CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
ContinueJumpTarget = JumpTarget(EntryConditionBlock, ScopePos);
- CFGBlock* BodyBlock = addStmt(S->getBody());
+ CFGBlock *BodyBlock = addStmt(S->getBody());
if (!BodyBlock)
BodyBlock = EntryConditionBlock; // can happen for "for (X in Y) ;"
@@ -1862,7 +1875,7 @@ CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
return addStmt(S->getCollection());
}
-CFGBlock* CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S) {
+CFGBlock *CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
// FIXME: Add locking 'primitives' to CFG for @synchronized.
// Inline the body.
@@ -1886,13 +1899,13 @@ CFGBlock* CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S) {
return addStmt(S->getSynchExpr());
}
-CFGBlock* CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt* S) {
+CFGBlock *CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
// FIXME
return NYS();
}
-CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
- CFGBlock* LoopSuccessor = NULL;
+CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
+ CFGBlock *LoopSuccessor = NULL;
// Save local scope position because in case of condition variable ScopePos
// won't be restored when traversing AST.
@@ -1901,7 +1914,7 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
// Create local scope for possible condition variable.
// Store scope position for continue statement.
LocalScope::const_iterator LoopBeginScopePos = ScopePos;
- if (VarDecl* VD = W->getConditionVariable()) {
+ if (VarDecl *VD = W->getConditionVariable()) {
addLocalScopeForVarDecl(VD);
addAutomaticObjDtors(ScopePos, LoopBeginScopePos, W);
}
@@ -1919,8 +1932,8 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
// Because of short-circuit evaluation, the condition of the loop can span
// multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that
// evaluate the condition.
- CFGBlock* ExitConditionBlock = createBlock(false);
- CFGBlock* EntryConditionBlock = ExitConditionBlock;
+ CFGBlock *ExitConditionBlock = createBlock(false);
+ CFGBlock *EntryConditionBlock = ExitConditionBlock;
// Set the terminator for the "exit" condition block.
ExitConditionBlock->setTerminator(W);
@@ -1928,7 +1941,7 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
// Now add the actual condition to the condition block. Because the condition
// itself may contain control-flow, new blocks may be created. Thus we update
// "Succ" after adding the condition.
- if (Stmt* C = W->getCond()) {
+ if (Stmt *C = W->getCond()) {
Block = ExitConditionBlock;
EntryConditionBlock = addStmt(C);
// The condition might finish the current 'Block'.
@@ -1990,7 +2003,7 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
addLocalScopeAndDtors(W->getBody());
// Create the body. The returned block is the entry to the loop body.
- CFGBlock* BodyBlock = addStmt(W->getBody());
+ CFGBlock *BodyBlock = addStmt(W->getBody());
if (!BodyBlock)
BodyBlock = ContinueJumpTarget.block; // can happen for "while(...) ;"
@@ -2017,13 +2030,13 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
}
-CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt* S) {
+CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
// FIXME: For now we pretend that @catch and the code it contains does not
// exit.
return Block;
}
-CFGBlock* CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt* S) {
+CFGBlock *CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
// FIXME: This isn't complete. We basically treat @throw like a return
// statement.
@@ -2042,7 +2055,7 @@ CFGBlock* CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt* S) {
return VisitStmt(S, AddStmtChoice::AlwaysAdd);
}
-CFGBlock* CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr* T) {
+CFGBlock *CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr *T) {
// If we were in the middle of a block we stop processing that block.
if (badCFG)
return 0;
@@ -2062,8 +2075,8 @@ CFGBlock* CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr* T) {
return VisitStmt(T, AddStmtChoice::AlwaysAdd);
}
-CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) {
- CFGBlock* LoopSuccessor = NULL;
+CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
+ CFGBlock *LoopSuccessor = NULL;
// "do...while" is a control-flow statement. Thus we stop processing the
// current block.
@@ -2077,15 +2090,15 @@ CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) {
// Because of short-circuit evaluation, the condition of the loop can span
// multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that
// evaluate the condition.
- CFGBlock* ExitConditionBlock = createBlock(false);
- CFGBlock* EntryConditionBlock = ExitConditionBlock;
+ CFGBlock *ExitConditionBlock = createBlock(false);
+ CFGBlock *EntryConditionBlock = ExitConditionBlock;
// Set the terminator for the "exit" condition block.
ExitConditionBlock->setTerminator(D);
// Now add the actual condition to the condition block. Because the condition
// itself may contain control-flow, new blocks may be created.
- if (Stmt* C = D->getCond()) {
+ if (Stmt *C = D->getCond()) {
Block = ExitConditionBlock;
EntryConditionBlock = addStmt(C);
if (Block) {
@@ -2101,7 +2114,7 @@ CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) {
const TryResult &KnownVal = tryEvaluateBool(D->getCond());
// Process the loop body.
- CFGBlock* BodyBlock = NULL;
+ CFGBlock *BodyBlock = NULL;
{
assert(D->getBody());
@@ -2165,7 +2178,7 @@ CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) {
return BodyBlock;
}
-CFGBlock* CFGBuilder::VisitContinueStmt(ContinueStmt* C) {
+CFGBlock *CFGBuilder::VisitContinueStmt(ContinueStmt *C) {
// "continue" is a control-flow statement. Thus we stop processing the
// current block.
if (badCFG)
@@ -2202,13 +2215,12 @@ CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
VA != 0; VA = FindVA(VA->getElementType().getTypePtr()))
lastBlock = addStmt(VA->getSizeExpr());
}
-
return lastBlock;
}
/// VisitStmtExpr - Utility method to handle (nested) statement
/// expressions (a GCC extension).
-CFGBlock* CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) {
+CFGBlock *CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) {
if (asc.alwaysAdd(*this, SE)) {
autoCreateBlock();
appendStmt(Block, SE);
@@ -2216,10 +2228,10 @@ CFGBlock* CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) {
return VisitCompoundStmt(SE->getSubStmt());
}
-CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) {
+CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
// "switch" is a control-flow statement. Thus we stop processing the current
// block.
- CFGBlock* SwitchSuccessor = NULL;
+ CFGBlock *SwitchSuccessor = NULL;
// Save local scope position because in case of condition variable ScopePos
// won't be restored when traversing AST.
@@ -2227,7 +2239,7 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) {
// Create local scope for possible condition variable.
// Store scope position. Add implicit destructor.
- if (VarDecl* VD = Terminator->getConditionVariable()) {
+ if (VarDecl *VD = Terminator->getConditionVariable()) {
LocalScope::const_iterator SwitchBeginScopePos = ScopePos;
addLocalScopeForVarDecl(VD);
addAutomaticObjDtors(ScopePos, SwitchBeginScopePos, Terminator);
@@ -2323,11 +2335,8 @@ static bool shouldAddCase(bool &switchExclusivelyCovered,
if (!switchExclusivelyCovered) {
if (switchCond->Val.isInt()) {
// Evaluate the LHS of the case value.
- Expr::EvalResult V1;
- CS->getLHS()->Evaluate(V1, Ctx);
- assert(V1.Val.isInt());
+ const llvm::APSInt &lhsInt = CS->getLHS()->EvaluateKnownConstInt(Ctx);
const llvm::APSInt &condInt = switchCond->Val.getInt();
- const llvm::APSInt &lhsInt = V1.Val.getInt();
if (condInt == lhsInt) {
addCase = true;
@@ -2336,10 +2345,8 @@ static bool shouldAddCase(bool &switchExclusivelyCovered,
else if (condInt < lhsInt) {
if (const Expr *RHS = CS->getRHS()) {
// Evaluate the RHS of the case value.
- Expr::EvalResult V2;
- RHS->Evaluate(V2, Ctx);
- assert(V2.Val.isInt());
- if (V2.Val.getInt() <= condInt) {
+ const llvm::APSInt &V2 = RHS->EvaluateKnownConstInt(Ctx);
+ if (V2 <= condInt) {
addCase = true;
switchExclusivelyCovered = true;
}
@@ -2352,7 +2359,7 @@ static bool shouldAddCase(bool &switchExclusivelyCovered,
return addCase;
}
-CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) {
+CFGBlock *CFGBuilder::VisitCaseStmt(CaseStmt *CS) {
// CaseStmts are essentially labels, so they are the first statement in a
// block.
CFGBlock *TopBlock = 0, *LastBlock = 0;
@@ -2383,7 +2390,7 @@ CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) {
addStmt(Sub);
}
- CFGBlock* CaseBlock = Block;
+ CFGBlock *CaseBlock = Block;
if (!CaseBlock)
CaseBlock = createBlock();
@@ -2416,7 +2423,7 @@ CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) {
return Succ;
}
-CFGBlock* CFGBuilder::VisitDefaultStmt(DefaultStmt* Terminator) {
+CFGBlock *CFGBuilder::VisitDefaultStmt(DefaultStmt *Terminator) {
if (Terminator->getSubStmt())
addStmt(Terminator->getSubStmt());
@@ -2450,7 +2457,7 @@ CFGBlock* CFGBuilder::VisitDefaultStmt(DefaultStmt* Terminator) {
CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {
// "try"/"catch" is a control-flow statement. Thus we stop processing the
// current block.
- CFGBlock* TrySuccessor = NULL;
+ CFGBlock *TrySuccessor = NULL;
if (Block) {
if (badCFG)
@@ -2492,8 +2499,8 @@ CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {
Succ = TrySuccessor;
// Save the current "try" context.
- SaveAndRestore<CFGBlock*> save_try(TryTerminatedBlock);
- TryTerminatedBlock = NewTryTerminatedBlock;
+ SaveAndRestore<CFGBlock*> save_try(TryTerminatedBlock, NewTryTerminatedBlock);
+ cfg->addTryDispatchBlock(TryTerminatedBlock);
assert(Terminator->getTryBlock() && "try must contain a non-NULL body");
Block = NULL;
@@ -2501,7 +2508,7 @@ CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {
return Block;
}
-CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) {
+CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) {
// CXXCatchStmt are treated like labels, so they are the first statement in a
// block.
@@ -2511,7 +2518,7 @@ CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) {
// Create local scope for possible exception variable.
// Store scope position. Add implicit destructor.
- if (VarDecl* VD = CS->getExceptionDecl()) {
+ if (VarDecl *VD = CS->getExceptionDecl()) {
LocalScope::const_iterator BeginScopePos = ScopePos;
addLocalScopeForVarDecl(VD);
addAutomaticObjDtors(ScopePos, BeginScopePos, CS);
@@ -2520,7 +2527,7 @@ CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) {
if (CS->getHandlerBlock())
addStmt(CS->getHandlerBlock());
- CFGBlock* CatchBlock = Block;
+ CFGBlock *CatchBlock = Block;
if (!CatchBlock)
CatchBlock = createBlock();
@@ -2535,7 +2542,7 @@ CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) {
return CatchBlock;
}
-CFGBlock* CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt* S) {
+CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
// C++0x for-range statements are specified as [stmt.ranged]:
//
// {
@@ -2563,7 +2570,7 @@ CFGBlock* CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt* S) {
// "for" is a control-flow statement. Thus we stop processing the current
// block.
- CFGBlock* LoopSuccessor = NULL;
+ CFGBlock *LoopSuccessor = NULL;
if (Block) {
if (badCFG)
return 0;
@@ -2577,7 +2584,7 @@ CFGBlock* CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt* S) {
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
// The block for the __begin != __end expression.
- CFGBlock* ConditionBlock = createBlock(false);
+ CFGBlock *ConditionBlock = createBlock(false);
ConditionBlock->setTerminator(S);
// Now add the actual condition to the condition block.
@@ -2713,9 +2720,9 @@ CFGBlock *CFGBuilder::VisitImplicitCastExpr(ImplicitCastExpr *E,
return Visit(E->getSubExpr(), AddStmtChoice());
}
-CFGBlock* CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt* I) {
+CFGBlock *CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt *I) {
// Lazily create the indirect-goto dispatch block if there isn't one already.
- CFGBlock* IBlock = cfg->getIndirectGotoBlock();
+ CFGBlock *IBlock = cfg->getIndirectGotoBlock();
if (!IBlock) {
IBlock = createBlock(false);
@@ -2774,7 +2781,7 @@ 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 llvm::SmallVector<Stmt *, 4> ChildrenVect;
+ typedef SmallVector<Stmt *, 4> ChildrenVect;
ChildrenVect ChildrenRev;
for (Stmt::child_range I = E->children(); I; ++I) {
if (*I) ChildrenRev.push_back(*I);
@@ -2864,7 +2871,16 @@ CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors(
if (!BindToTemporary) {
// If lifetime of temporary is not prolonged (by assigning to constant
// reference) add destructor for it.
- autoCreateBlock();
+
+ // If the destructor is marked as a no-return destructor, we need to create
+ // 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())
+ Block = createNoReturnBlock();
+ else
+ autoCreateBlock();
+
appendTemporaryDtor(Block, E);
B = Block;
}
@@ -2937,7 +2953,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
/// createBlock - Constructs and adds a new CFGBlock to the CFG. The block has
/// no successors or predecessors. If this is the first block created in the
/// CFG, it is automatically set to be the Entry and Exit of the CFG.
-CFGBlock* CFG::createBlock() {
+CFGBlock *CFG::createBlock() {
bool first_block = begin() == end();
// Create the block.
@@ -2955,7 +2971,7 @@ CFGBlock* CFG::createBlock() {
/// buildCFG - Constructs a CFG from an AST. Ownership of the returned
/// CFG is returned to the caller.
-CFG* CFG::buildCFG(const Decl *D, Stmt* Statement, ASTContext *C,
+CFG* CFG::buildCFG(const Decl *D, Stmt *Statement, ASTContext *C,
const BuildOptions &BO) {
CFGBuilder Builder(C, BO);
return Builder.buildCFG(D, Statement);
@@ -3013,17 +3029,17 @@ namespace {
typedef llvm::DenseMap<const Stmt*,unsigned> BlkExprMapTy;
}
-static void FindSubExprAssignments(Stmt *S,
- llvm::SmallPtrSet<Expr*,50>& Set) {
+static void FindSubExprAssignments(const Stmt *S,
+ llvm::SmallPtrSet<const Expr*,50>& Set) {
if (!S)
return;
- for (Stmt::child_range I = S->children(); I; ++I) {
- Stmt *child = *I;
+ for (Stmt::const_child_range I = S->children(); I; ++I) {
+ const Stmt *child = *I;
if (!child)
continue;
- if (BinaryOperator* B = dyn_cast<BinaryOperator>(child))
+ if (const BinaryOperator* B = dyn_cast<BinaryOperator>(child))
if (B->isAssignmentOp()) Set.insert(B);
FindSubExprAssignments(child, Set);
@@ -3037,7 +3053,7 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
// assignments that we want to *possibly* register as a block-level
// expression. Basically, if an assignment occurs both in a subexpression and
// at the block-level, it is a block-level expression.
- llvm::SmallPtrSet<Expr*,50> SubExprAssignments;
+ llvm::SmallPtrSet<const Expr*,50> SubExprAssignments;
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I)
for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI)
@@ -3053,19 +3069,19 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
const CFGStmt *CS = BI->getAs<CFGStmt>();
if (!CS)
continue;
- if (Expr* Exp = dyn_cast<Expr>(CS->getStmt())) {
+ if (const Expr *Exp = dyn_cast<Expr>(CS->getStmt())) {
assert((Exp->IgnoreParens() == Exp) && "No parens on block-level exps");
- if (BinaryOperator* B = dyn_cast<BinaryOperator>(Exp)) {
+ if (const BinaryOperator* B = dyn_cast<BinaryOperator>(Exp)) {
// Assignment expressions that are not nested within another
// expression are really "statements" whose value is never used by
// another expression.
if (B->isAssignmentOp() && !SubExprAssignments.count(Exp))
continue;
- } else if (const StmtExpr* SE = dyn_cast<StmtExpr>(Exp)) {
+ } else if (const StmtExpr *SE = dyn_cast<StmtExpr>(Exp)) {
// Special handling for statement expressions. The last statement in
// the statement expression is also a block-level expr.
- const CompoundStmt* C = SE->getSubStmt();
+ const CompoundStmt *C = SE->getSubStmt();
if (!C->body_empty()) {
const Stmt *Last = C->body_back();
if (const Expr *LastEx = dyn_cast<Expr>(Last))
@@ -3082,7 +3098,7 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
// Look at terminators. The condition is a block-level expression.
- Stmt* S = (*I)->getTerminatorCondition();
+ Stmt *S = (*I)->getTerminatorCondition();
if (S && M->find(S) == M->end()) {
unsigned x = M->size();
@@ -3093,7 +3109,7 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
return M;
}
-CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt* S) {
+CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt *S) {
assert(S != NULL);
if (!BlkExprMap) { BlkExprMap = (void*) PopulateBlkExprMap(*this); }
@@ -3223,7 +3239,7 @@ public:
void setBlockID(signed i) { currentBlock = i; }
void setStmtID(unsigned i) { currentStmt = i; }
- virtual bool handledStmt(Stmt* S, llvm::raw_ostream& OS) {
+ virtual bool handledStmt(Stmt *S, raw_ostream &OS) {
StmtMapTy::iterator I = StmtMap.find(S);
if (I == StmtMap.end())
@@ -3238,7 +3254,7 @@ public:
return true;
}
- bool handleDecl(const Decl* D, llvm::raw_ostream& OS) {
+ bool handleDecl(const Decl *D, raw_ostream &OS) {
DeclMapTy::iterator I = DeclMap.find(D);
if (I == DeclMap.end())
@@ -3260,30 +3276,30 @@ namespace {
class CFGBlockTerminatorPrint
: public StmtVisitor<CFGBlockTerminatorPrint,void> {
- llvm::raw_ostream& OS;
+ raw_ostream &OS;
StmtPrinterHelper* Helper;
PrintingPolicy Policy;
public:
- CFGBlockTerminatorPrint(llvm::raw_ostream& os, StmtPrinterHelper* helper,
+ CFGBlockTerminatorPrint(raw_ostream &os, StmtPrinterHelper* helper,
const PrintingPolicy &Policy)
: OS(os), Helper(helper), Policy(Policy) {}
- void VisitIfStmt(IfStmt* I) {
+ void VisitIfStmt(IfStmt *I) {
OS << "if ";
I->getCond()->printPretty(OS,Helper,Policy);
}
// Default case.
- void VisitStmt(Stmt* Terminator) {
+ void VisitStmt(Stmt *Terminator) {
Terminator->printPretty(OS, Helper, Policy);
}
- void VisitForStmt(ForStmt* F) {
+ void VisitForStmt(ForStmt *F) {
OS << "for (" ;
if (F->getInit())
OS << "...";
OS << "; ";
- if (Stmt* C = F->getCond())
+ if (Stmt *C = F->getCond())
C->printPretty(OS, Helper, Policy);
OS << "; ";
if (F->getInc())
@@ -3291,24 +3307,24 @@ public:
OS << ")";
}
- void VisitWhileStmt(WhileStmt* W) {
+ void VisitWhileStmt(WhileStmt *W) {
OS << "while " ;
- if (Stmt* C = W->getCond())
+ if (Stmt *C = W->getCond())
C->printPretty(OS, Helper, Policy);
}
- void VisitDoStmt(DoStmt* D) {
+ void VisitDoStmt(DoStmt *D) {
OS << "do ... while ";
- if (Stmt* C = D->getCond())
+ if (Stmt *C = D->getCond())
C->printPretty(OS, Helper, Policy);
}
- void VisitSwitchStmt(SwitchStmt* Terminator) {
+ void VisitSwitchStmt(SwitchStmt *Terminator) {
OS << "switch ";
Terminator->getCond()->printPretty(OS, Helper, Policy);
}
- void VisitCXXTryStmt(CXXTryStmt* CS) {
+ void VisitCXXTryStmt(CXXTryStmt *CS) {
OS << "try ...";
}
@@ -3317,13 +3333,13 @@ public:
OS << " ? ... : ...";
}
- void VisitChooseExpr(ChooseExpr* C) {
+ void VisitChooseExpr(ChooseExpr *C) {
OS << "__builtin_choose_expr( ";
C->getCond()->printPretty(OS, Helper, Policy);
OS << " )";
}
- void VisitIndirectGotoStmt(IndirectGotoStmt* I) {
+ void VisitIndirectGotoStmt(IndirectGotoStmt *I) {
OS << "goto *";
I->getTarget()->printPretty(OS, Helper, Policy);
}
@@ -3344,26 +3360,26 @@ public:
OS << " && ...";
return;
default:
- assert(false && "Invalid logical operator.");
+ llvm_unreachable("Invalid logical operator.");
}
}
- void VisitExpr(Expr* E) {
+ void VisitExpr(Expr *E) {
E->printPretty(OS, Helper, Policy);
}
};
} // end anonymous namespace
-static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper,
+static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper,
const CFGElement &E) {
if (const CFGStmt *CS = E.getAs<CFGStmt>()) {
- Stmt *S = CS->getStmt();
+ const Stmt *S = CS->getStmt();
if (Helper) {
// special printing for statement-expressions.
- if (StmtExpr* SE = dyn_cast<StmtExpr>(S)) {
- CompoundStmt* Sub = SE->getSubStmt();
+ if (const StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
+ const CompoundStmt *Sub = SE->getSubStmt();
if (Sub->children()) {
OS << "({ ... ; ";
@@ -3373,7 +3389,7 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper,
}
}
// special printing for comma expressions.
- if (BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
+ if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
if (B->getOpcode() == BO_Comma) {
OS << "... , ";
Helper->handledStmt(B->getRHS(),OS);
@@ -3401,7 +3417,7 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper,
else OS << I->getAnyMember()->getName();
OS << "(";
- if (Expr* IE = I->getInit())
+ if (Expr *IE = I->getInit())
IE->printPretty(OS, Helper, PrintingPolicy(Helper->getLangOpts()));
OS << ")";
@@ -3410,7 +3426,7 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper,
else OS << " (Member initializer)\n";
} else if (const CFGAutomaticObjDtor *DE = E.getAs<CFGAutomaticObjDtor>()){
- const VarDecl* VD = DE->getVarDecl();
+ const VarDecl *VD = DE->getVarDecl();
Helper->handleDecl(VD, OS);
const Type* T = VD->getType().getTypePtr();
@@ -3445,8 +3461,8 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper,
}
}
-static void print_block(llvm::raw_ostream& OS, const CFG* cfg,
- const CFGBlock& B,
+static void print_block(raw_ostream &OS, const CFG* cfg,
+ const CFGBlock &B,
StmtPrinterHelper* Helper, bool print_edges) {
if (Helper) Helper->setBlockID(B.getBlockID());
@@ -3464,14 +3480,14 @@ static void print_block(llvm::raw_ostream& OS, const CFG* cfg,
OS << " ]\n";
// Print the label of this block.
- if (Stmt* Label = const_cast<Stmt*>(B.getLabel())) {
+ if (Stmt *Label = const_cast<Stmt*>(B.getLabel())) {
if (print_edges)
OS << " ";
- if (LabelStmt* L = dyn_cast<LabelStmt>(Label))
+ if (LabelStmt *L = dyn_cast<LabelStmt>(Label))
OS << L->getName();
- else if (CaseStmt* C = dyn_cast<CaseStmt>(Label)) {
+ else if (CaseStmt *C = dyn_cast<CaseStmt>(Label)) {
OS << "case ";
C->getLHS()->printPretty(OS, Helper,
PrintingPolicy(Helper->getLangOpts()));
@@ -3492,7 +3508,7 @@ static void print_block(llvm::raw_ostream& OS, const CFG* cfg,
OS << ")";
} else
- assert(false && "Invalid label statement in CFGBlock.");
+ llvm_unreachable("Invalid label statement in CFGBlock.");
OS << ":\n";
}
@@ -3571,7 +3587,7 @@ static void print_block(llvm::raw_ostream& OS, const CFG* cfg,
void CFG::dump(const LangOptions &LO) const { print(llvm::errs(), LO); }
/// print - A simple pretty printer of a CFG that outputs to an ostream.
-void CFG::print(llvm::raw_ostream &OS, const LangOptions &LO) const {
+void CFG::print(raw_ostream &OS, const LangOptions &LO) const {
StmtPrinterHelper Helper(this, LO);
// Print the entry block.
@@ -3598,25 +3614,25 @@ void CFGBlock::dump(const CFG* cfg, const LangOptions &LO) const {
/// print - A simple pretty printer of a CFGBlock that outputs to an ostream.
/// Generally this will only be called from CFG::print.
-void CFGBlock::print(llvm::raw_ostream& OS, const CFG* cfg,
+void CFGBlock::print(raw_ostream &OS, const CFG* cfg,
const LangOptions &LO) const {
StmtPrinterHelper Helper(cfg, LO);
print_block(OS, cfg, *this, &Helper, true);
}
/// printTerminator - A simple pretty printer of the terminator of a CFGBlock.
-void CFGBlock::printTerminator(llvm::raw_ostream &OS,
+void CFGBlock::printTerminator(raw_ostream &OS,
const LangOptions &LO) const {
CFGBlockTerminatorPrint TPrinter(OS, NULL, PrintingPolicy(LO));
TPrinter.Visit(const_cast<Stmt*>(getTerminator().getStmt()));
}
-Stmt* CFGBlock::getTerminatorCondition() {
+Stmt *CFGBlock::getTerminatorCondition() {
Stmt *Terminator = this->Terminator;
if (!Terminator)
return NULL;
- Expr* E = NULL;
+ Expr *E = NULL;
switch (Terminator->getStmtClass()) {
default:
@@ -3693,7 +3709,7 @@ struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits {
DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
- static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph) {
+ static std::string getNodeLabel(const CFGBlock *Node, const CFG* Graph) {
#ifndef NDEBUG
std::string OutSStr;
diff --git a/lib/Analysis/CFGReachabilityAnalysis.cpp b/lib/Analysis/CFGReachabilityAnalysis.cpp
index 65cd0898573c..e77e72fa9fb1 100644
--- a/lib/Analysis/CFGReachabilityAnalysis.cpp
+++ b/lib/Analysis/CFGReachabilityAnalysis.cpp
@@ -40,7 +40,7 @@ bool CFGReverseBlockReachabilityAnalysis::isReachable(const CFGBlock *Src,
// Maps reachability to a common node by walking the predecessors of the
// destination node.
void CFGReverseBlockReachabilityAnalysis::mapReachability(const CFGBlock *Dst) {
- llvm::SmallVector<const CFGBlock *, 11> worklist;
+ SmallVector<const CFGBlock *, 11> worklist;
llvm::BitVector visited(analyzed.size());
ReachableSet &DstReachability = reachable[Dst->getBlockID()];
diff --git a/lib/Analysis/CFGStmtMap.cpp b/lib/Analysis/CFGStmtMap.cpp
index 1fd5eedfeb86..16df67678df5 100644
--- a/lib/Analysis/CFGStmtMap.cpp
+++ b/lib/Analysis/CFGStmtMap.cpp
@@ -19,7 +19,7 @@
using namespace clang;
-typedef llvm::DenseMap<Stmt*,CFGBlock*> SMap;
+typedef llvm::DenseMap<const Stmt*, CFGBlock*> SMap;
static SMap *AsMap(void *m) { return (SMap*) m; }
CFGStmtMap::~CFGStmtMap() { delete AsMap(M); }
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index 967fc2930f42..e446d1e0605d 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -9,9 +9,11 @@ add_clang_library(clangAnalysis
FormatString.cpp
LiveVariables.cpp
PrintfFormatString.cpp
+ ProgramPoint.cpp
PseudoConstantAnalysis.cpp
ReachableCode.cpp
ScanfFormatString.cpp
+ ThreadSafety.cpp
UninitializedValues.cpp
)
diff --git a/lib/Analysis/CocoaConventions.cpp b/lib/Analysis/CocoaConventions.cpp
index 90f7092f90ee..8acd1892f9c7 100644
--- a/lib/Analysis/CocoaConventions.cpp
+++ b/lib/Analysis/CocoaConventions.cpp
@@ -17,12 +17,9 @@
#include "clang/AST/DeclObjC.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
-
using namespace clang;
using namespace ento;
-using llvm::StringRef;
-
// The "fundamental rule" for naming conventions of methods:
// (url broken into two lines)
// http://developer.apple.com/documentation/Cocoa/Conceptual/
@@ -43,6 +40,7 @@ cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S,
case OMF_None:
case OMF_autorelease:
case OMF_dealloc:
+ case OMF_finalize:
case OMF_release:
case OMF_retain:
case OMF_retainCount:
@@ -63,11 +61,11 @@ cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S,
return NoConvention;
}
-bool cocoa::isRefType(QualType RetTy, llvm::StringRef Prefix,
- llvm::StringRef Name) {
+bool cocoa::isRefType(QualType RetTy, StringRef Prefix,
+ StringRef Name) {
// Recursively walk the typedef stack, allowing typedefs of reference types.
while (const TypedefType *TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) {
- llvm::StringRef TDName = TD->getDecl()->getIdentifier()->getName();
+ StringRef TDName = TD->getDecl()->getIdentifier()->getName();
if (TDName.startswith(Prefix) && TDName.endswith("Ref"))
return true;
@@ -127,10 +125,16 @@ bool cocoa::isCocoaObjectRef(QualType Ty) {
return false;
}
-bool coreFoundation::followsCreateRule(llvm::StringRef functionName) {
- llvm::StringRef::iterator it = functionName.begin();
- llvm::StringRef::iterator start = it;
- llvm::StringRef::iterator endI = functionName.end();
+bool coreFoundation::followsCreateRule(const FunctionDecl *fn) {
+ // For now, *just* base this on the function name, not on anything else.
+
+ const IdentifierInfo *ident = fn->getIdentifier();
+ if (!ident) return false;
+ StringRef functionName = ident->getName();
+
+ StringRef::iterator it = functionName.begin();
+ StringRef::iterator start = it;
+ StringRef::iterator endI = functionName.end();
while (true) {
// Scan for the start of 'create' or 'copy'.
@@ -138,6 +142,10 @@ bool coreFoundation::followsCreateRule(llvm::StringRef functionName) {
// Search for the first character. It can either be 'C' or 'c'.
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)))
+ continue;
+
++it;
break;
}
@@ -149,14 +157,13 @@ bool coreFoundation::followsCreateRule(llvm::StringRef functionName) {
// Scan for *lowercase* 'reate' or 'opy', followed by no lowercase
// character.
- llvm::StringRef suffix = functionName.substr(it - start);
+ StringRef suffix = functionName.substr(it - start);
if (suffix.startswith("reate")) {
it += 5;
}
else if (suffix.startswith("opy")) {
it += 3;
- }
- else {
+ } else {
// Keep scanning.
continue;
}
diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp
index 5f3cd4c61549..0f807e21e7fc 100644
--- a/lib/Analysis/FormatString.cpp
+++ b/lib/Analysis/FormatString.cpp
@@ -209,8 +209,7 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
switch (K) {
case InvalidTy:
- assert(false && "ArgTypeResult must be valid");
- return true;
+ llvm_unreachable("ArgTypeResult must be valid");
case UnknownTy:
return true;
@@ -312,8 +311,7 @@ bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const {
switch (K) {
case InvalidTy:
- assert(false && "No representative type for Invalid ArgTypeResult");
- // Fall-through.
+ llvm_unreachable("No representative type for Invalid ArgTypeResult");
case UnknownTy:
return QualType();
case SpecificTy:
@@ -379,7 +377,7 @@ analyze_format_string::LengthModifier::toString() const {
// Methods on OptionalAmount.
//===----------------------------------------------------------------------===//
-void OptionalAmount::toString(llvm::raw_ostream &os) const {
+void OptionalAmount::toString(raw_ostream &os) const {
switch (hs) {
case Invalid:
case NotSpecified:
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index 7b36f85ab62c..62c5455e0f22 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -1,392 +1,674 @@
-//=- LiveVariables.cpp - Live Variable Analysis for Source CFGs -*- 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 Live Variables analysis for source-level CFGs.
-//
-//===----------------------------------------------------------------------===//
-
#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Expr.h"
+#include "clang/AST/Stmt.h"
#include "clang/Analysis/CFG.h"
-#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
-#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
-#include "clang/Analysis/Support/SaveAndRestore.h"
#include "clang/Analysis/AnalysisContext.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/Support/raw_ostream.h"
+#include "clang/AST/StmtVisitor.h"
-using namespace clang;
-
-//===----------------------------------------------------------------------===//
-// Useful constants.
-//===----------------------------------------------------------------------===//
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/DenseMap.h"
-static const bool Alive = true;
-static const bool Dead = false;
+#include <deque>
+#include <algorithm>
+#include <vector>
-//===----------------------------------------------------------------------===//
-// Dataflow initialization logic.
-//===----------------------------------------------------------------------===//
+using namespace clang;
namespace {
-class RegisterDecls
- : public CFGRecStmtDeclVisitor<RegisterDecls> {
-
- LiveVariables::AnalysisDataTy& AD;
- typedef llvm::SmallVector<VarDecl*, 20> AlwaysLiveTy;
- AlwaysLiveTy AlwaysLive;
+// FIXME: This is copy-pasted from ThreadSafety.c. I wanted a patch that
+// contained working code before refactoring the implementation of both
+// files.
+class CFGBlockSet {
+ llvm::BitVector VisitedBlockIDs;
+
+public:
+ // po_iterator requires this iterator, but the only interface needed is the
+ // value_type typedef.
+ struct iterator {
+ typedef const CFGBlock *value_type;
+ };
+
+ CFGBlockSet() {}
+ CFGBlockSet(const CFG *G) : VisitedBlockIDs(G->getNumBlockIDs(), false) {}
+
+ /// \brief Set the bit associated with a particular CFGBlock.
+ /// This is the important method for the SetType template parameter.
+ bool insert(const CFGBlock *Block) {
+ // Note that insert() is called by po_iterator, which doesn't check to make
+ // sure that Block is non-null. Moreover, the CFGBlock iterator will
+ // occasionally hand out null pointers for pruned edges, so we catch those
+ // here.
+ if (Block == 0)
+ return false; // if an edge is trivially false.
+ if (VisitedBlockIDs.test(Block->getBlockID()))
+ return false;
+ VisitedBlockIDs.set(Block->getBlockID());
+ return true;
+ }
+
+ /// \brief Check if the bit for a CFGBlock has been already set.
+ /// This method is for tracking visited blocks in the main threadsafety loop.
+ /// Block must not be null.
+ bool alreadySet(const CFGBlock *Block) {
+ return VisitedBlockIDs.test(Block->getBlockID());
+ }
+};
+/// \brief We create a helper class which we use to iterate through CFGBlocks in
+/// the topological order.
+class TopologicallySortedCFG {
+ typedef llvm::po_iterator<const CFG*, CFGBlockSet, true> po_iterator;
+
+ std::vector<const CFGBlock*> Blocks;
+
+ typedef llvm::DenseMap<const CFGBlock *, unsigned> BlockOrderTy;
+ BlockOrderTy BlockOrder;
+
+
+public:
+ typedef std::vector<const CFGBlock*>::reverse_iterator iterator;
+
+ TopologicallySortedCFG(const CFG *CFGraph) {
+ Blocks.reserve(CFGraph->getNumBlockIDs());
+ CFGBlockSet BSet(CFGraph);
+
+ for (po_iterator I = po_iterator::begin(CFGraph, BSet),
+ E = po_iterator::end(CFGraph, BSet); I != E; ++I) {
+ BlockOrder[*I] = Blocks.size() + 1;
+ Blocks.push_back(*I);
+ }
+ }
+
+ iterator begin() {
+ return Blocks.rbegin();
+ }
+
+ iterator end() {
+ return Blocks.rend();
+ }
+
+ bool empty() {
+ return begin() == end();
+ }
+
+ struct BlockOrderCompare;
+ friend struct BlockOrderCompare;
+
+ struct BlockOrderCompare {
+ const TopologicallySortedCFG &TSC;
+ public:
+ BlockOrderCompare(const TopologicallySortedCFG &tsc) : TSC(tsc) {}
+
+ bool operator()(const CFGBlock *b1, const CFGBlock *b2) const {
+ TopologicallySortedCFG::BlockOrderTy::const_iterator b1It = TSC.BlockOrder.find(b1);
+ TopologicallySortedCFG::BlockOrderTy::const_iterator b2It = TSC.BlockOrder.find(b2);
+
+ unsigned b1V = (b1It == TSC.BlockOrder.end()) ? 0 : b1It->second;
+ unsigned b2V = (b2It == TSC.BlockOrder.end()) ? 0 : b2It->second;
+ return b1V > b2V;
+ }
+ };
+
+ BlockOrderCompare getComparator() const {
+ return BlockOrderCompare(*this);
+ }
+};
+class DataflowWorklist {
+ SmallVector<const CFGBlock *, 20> worklist;
+ llvm::BitVector enqueuedBlocks;
+ TopologicallySortedCFG TSC;
public:
- RegisterDecls(LiveVariables::AnalysisDataTy& ad) : AD(ad) {}
+ DataflowWorklist(const CFG &cfg)
+ : enqueuedBlocks(cfg.getNumBlockIDs()),
+ TSC(&cfg) {}
+
+ void enqueueBlock(const CFGBlock *block);
+ void enqueueSuccessors(const CFGBlock *block);
+ void enqueuePredecessors(const CFGBlock *block);
- ~RegisterDecls() {
+ const CFGBlock *dequeue();
- AD.AlwaysLive.resetValues(AD);
+ void sortWorklist();
+};
- for (AlwaysLiveTy::iterator I = AlwaysLive.begin(), E = AlwaysLive.end();
- I != E; ++ I)
- AD.AlwaysLive(*I, AD) = Alive;
- }
+}
- void VisitImplicitParamDecl(ImplicitParamDecl* IPD) {
- // Register the VarDecl for tracking.
- AD.Register(IPD);
+void DataflowWorklist::enqueueBlock(const clang::CFGBlock *block) {
+ if (block && !enqueuedBlocks[block->getBlockID()]) {
+ enqueuedBlocks[block->getBlockID()] = true;
+ worklist.push_back(block);
+ }
+}
+
+void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
+ const unsigned OldWorklistSize = worklist.size();
+ for (CFGBlock::const_succ_iterator I = block->succ_begin(),
+ E = block->succ_end(); I != E; ++I) {
+ enqueueBlock(*I);
}
- void VisitVarDecl(VarDecl* VD) {
- // Register the VarDecl for tracking.
- AD.Register(VD);
+ if (OldWorklistSize == 0 || OldWorklistSize == worklist.size())
+ return;
- // Does the variable have global storage? If so, it is always live.
- if (VD->hasGlobalStorage())
- AlwaysLive.push_back(VD);
+ sortWorklist();
+}
+
+void DataflowWorklist::enqueuePredecessors(const clang::CFGBlock *block) {
+ const unsigned OldWorklistSize = worklist.size();
+ for (CFGBlock::const_pred_iterator I = block->pred_begin(),
+ E = block->pred_end(); I != E; ++I) {
+ enqueueBlock(*I);
}
+
+ if (OldWorklistSize == 0 || OldWorklistSize == worklist.size())
+ return;
- CFG& getCFG() { return AD.getCFG(); }
-};
-} // end anonymous namespace
+ sortWorklist();
+}
+
+void DataflowWorklist::sortWorklist() {
+ std::sort(worklist.begin(), worklist.end(), TSC.getComparator());
+}
-LiveVariables::LiveVariables(AnalysisContext &AC, bool killAtAssign) {
- // Register all referenced VarDecls.
- CFG &cfg = *AC.getCFG();
- getAnalysisData().setCFG(cfg);
- getAnalysisData().setContext(AC.getASTContext());
- getAnalysisData().AC = &AC;
- getAnalysisData().killAtAssign = killAtAssign;
- RegisterDecls R(getAnalysisData());
- cfg.VisitBlockStmts(R);
+const CFGBlock *DataflowWorklist::dequeue() {
+ if (worklist.empty())
+ return 0;
+ const CFGBlock *b = worklist.back();
+ worklist.pop_back();
+ enqueuedBlocks[b->getBlockID()] = false;
+ return b;
+}
- // Register all parameters even if they didn't occur in the function body.
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(AC.getDecl()))
- for (FunctionDecl::param_const_iterator PI = FD->param_begin(),
- PE = FD->param_end(); PI != PE; ++PI)
- getAnalysisData().Register(*PI);
+namespace {
+class LiveVariablesImpl {
+public:
+ AnalysisContext &analysisContext;
+ std::vector<LiveVariables::LivenessValues> cfgBlockValues;
+ llvm::ImmutableSet<const Stmt *>::Factory SSetFact;
+ llvm::ImmutableSet<const VarDecl *>::Factory DSetFact;
+ llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksEndToLiveness;
+ llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksBeginToLiveness;
+ llvm::DenseMap<const Stmt *, LiveVariables::LivenessValues> stmtsToLiveness;
+ llvm::DenseMap<const DeclRefExpr *, unsigned> inAssignment;
+ const bool killAtAssign;
+
+ LiveVariables::LivenessValues
+ merge(LiveVariables::LivenessValues valsA,
+ LiveVariables::LivenessValues valsB);
+
+ LiveVariables::LivenessValues runOnBlock(const CFGBlock *block,
+ LiveVariables::LivenessValues val,
+ LiveVariables::Observer *obs = 0);
+
+ void dumpBlockLiveness(const SourceManager& M);
+
+ LiveVariablesImpl(AnalysisContext &ac, bool KillAtAssign)
+ : analysisContext(ac),
+ SSetFact(false), // Do not canonicalize ImmutableSets by default.
+ DSetFact(false), // This is a *major* performance win.
+ killAtAssign(KillAtAssign) {}
+};
+}
+
+static LiveVariablesImpl &getImpl(void *x) {
+ return *((LiveVariablesImpl *) x);
}
//===----------------------------------------------------------------------===//
-// Transfer functions.
+// Operations and queries on LivenessValues.
//===----------------------------------------------------------------------===//
+bool LiveVariables::LivenessValues::isLive(const Stmt *S) const {
+ return liveStmts.contains(S);
+}
+
+bool LiveVariables::LivenessValues::isLive(const VarDecl *D) const {
+ return liveDecls.contains(D);
+}
+
namespace {
+ template <typename SET>
+ SET mergeSets(SET A, SET B) {
+ if (A.isEmpty())
+ return B;
+
+ for (typename SET::iterator it = B.begin(), ei = B.end(); it != ei; ++it) {
+ A = A.add(*it);
+ }
+ return A;
+ }
+}
-class TransferFuncs : public CFGRecStmtVisitor<TransferFuncs>{
- LiveVariables::AnalysisDataTy& AD;
- LiveVariables::ValTy LiveState;
- const CFGBlock *currentBlock;
-public:
- TransferFuncs(LiveVariables::AnalysisDataTy& ad) : AD(ad), currentBlock(0) {}
-
- LiveVariables::ValTy& getVal() { return LiveState; }
- CFG& getCFG() { return AD.getCFG(); }
-
- void VisitDeclRefExpr(DeclRefExpr* DR);
- void VisitBinaryOperator(BinaryOperator* B);
- void VisitBlockExpr(BlockExpr *B);
- void VisitAssign(BinaryOperator* B);
- void VisitDeclStmt(DeclStmt* DS);
- void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S);
- void VisitUnaryOperator(UnaryOperator* U);
- void Visit(Stmt *S);
- void VisitTerminator(CFGBlock* B);
+LiveVariables::LivenessValues
+LiveVariablesImpl::merge(LiveVariables::LivenessValues valsA,
+ LiveVariables::LivenessValues valsB) {
+
+ llvm::ImmutableSetRef<const Stmt *>
+ SSetRefA(valsA.liveStmts.getRootWithoutRetain(), SSetFact.getTreeFactory()),
+ SSetRefB(valsB.liveStmts.getRootWithoutRetain(), SSetFact.getTreeFactory());
+
+
+ llvm::ImmutableSetRef<const VarDecl *>
+ DSetRefA(valsA.liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory()),
+ DSetRefB(valsB.liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory());
- /// VisitConditionVariableInit - Handle the initialization of condition
- /// variables at branches. Valid statements include IfStmt, ForStmt,
- /// WhileStmt, and SwitchStmt.
- void VisitConditionVariableInit(Stmt *S);
- void SetTopValue(LiveVariables::ValTy& V) {
- V = AD.AlwaysLive;
- }
+ SSetRefA = mergeSets(SSetRefA, SSetRefB);
+ DSetRefA = mergeSets(DSetRefA, DSetRefB);
- void setCurrentBlock(const CFGBlock *block) {
- currentBlock = block;
- }
-};
+ // asImmutableSet() canonicalizes the tree, allowing us to do an easy
+ // comparison afterwards.
+ return LiveVariables::LivenessValues(SSetRefA.asImmutableSet(),
+ DSetRefA.asImmutableSet());
+}
-void TransferFuncs::Visit(Stmt *S) {
+bool LiveVariables::LivenessValues::equals(const LivenessValues &V) const {
+ return liveStmts == V.liveStmts && liveDecls == V.liveDecls;
+}
- if (S == getCurrentBlkStmt()) {
+//===----------------------------------------------------------------------===//
+// Query methods.
+//===----------------------------------------------------------------------===//
- if (AD.Observer)
- AD.Observer->ObserveStmt(S, currentBlock, AD, LiveState);
+static bool isAlwaysAlive(const VarDecl *D) {
+ return D->hasGlobalStorage();
+}
- if (getCFG().isBlkExpr(S))
- LiveState(S, AD) = Dead;
+bool LiveVariables::isLive(const CFGBlock *B, const VarDecl *D) {
+ return isAlwaysAlive(D) || getImpl(impl).blocksEndToLiveness[B].isLive(D);
+}
- StmtVisitor<TransferFuncs,void>::Visit(S);
- }
- else if (!getCFG().isBlkExpr(S)) {
+bool LiveVariables::isLive(const Stmt *S, const VarDecl *D) {
+ return isAlwaysAlive(D) || getImpl(impl).stmtsToLiveness[S].isLive(D);
+}
- if (AD.Observer)
- AD.Observer->ObserveStmt(S, currentBlock, AD, LiveState);
+bool LiveVariables::isLive(const Stmt *Loc, const Stmt *S) {
+ return getImpl(impl).stmtsToLiveness[Loc].isLive(S);
+}
- StmtVisitor<TransferFuncs,void>::Visit(S);
+//===----------------------------------------------------------------------===//
+// Dataflow computation.
+//===----------------------------------------------------------------------===//
- }
- else {
- // For block-level expressions, mark that they are live.
- LiveState(S, AD) = Alive;
- }
+namespace {
+class TransferFunctions : public StmtVisitor<TransferFunctions> {
+ LiveVariablesImpl &LV;
+ LiveVariables::LivenessValues &val;
+ LiveVariables::Observer *observer;
+ const CFGBlock *currentBlock;
+public:
+ TransferFunctions(LiveVariablesImpl &im,
+ LiveVariables::LivenessValues &Val,
+ LiveVariables::Observer *Observer,
+ const CFGBlock *CurrentBlock)
+ : LV(im), val(Val), observer(Observer), currentBlock(CurrentBlock) {}
+
+ void VisitBinaryOperator(BinaryOperator *BO);
+ void VisitBlockExpr(BlockExpr *BE);
+ void VisitDeclRefExpr(DeclRefExpr *DR);
+ void VisitDeclStmt(DeclStmt *DS);
+ void VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS);
+ void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE);
+ void VisitUnaryOperator(UnaryOperator *UO);
+ void Visit(Stmt *S);
+};
}
+
+static const VariableArrayType *FindVA(QualType Ty) {
+ const Type *ty = Ty.getTypePtr();
+ while (const ArrayType *VT = dyn_cast<ArrayType>(ty)) {
+ if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(VT))
+ if (VAT->getSizeExpr())
+ return VAT;
+
+ ty = VT->getElementType().getTypePtr();
+ }
-void TransferFuncs::VisitConditionVariableInit(Stmt *S) {
- assert(!getCFG().isBlkExpr(S));
- CFGRecStmtVisitor<TransferFuncs>::VisitConditionVariableInit(S);
+ return 0;
}
-void TransferFuncs::VisitTerminator(CFGBlock* B) {
-
- const Stmt* E = B->getTerminatorCondition();
-
- if (!E)
- return;
+void TransferFunctions::Visit(Stmt *S) {
+ if (observer)
+ observer->observeStmt(S, currentBlock, val);
+
+ StmtVisitor<TransferFunctions>::Visit(S);
+
+ if (isa<Expr>(S)) {
+ val.liveStmts = LV.SSetFact.remove(val.liveStmts, S);
+ }
- assert (getCFG().isBlkExpr(E));
- LiveState(E, AD) = Alive;
+ // Mark all children expressions live.
+
+ switch (S->getStmtClass()) {
+ default:
+ break;
+ case Stmt::StmtExprClass: {
+ // For statement expressions, look through the compound statement.
+ S = cast<StmtExpr>(S)->getSubStmt();
+ break;
+ }
+ case Stmt::CXXMemberCallExprClass: {
+ // Include the implicit "this" pointer as being live.
+ CXXMemberCallExpr *CE = cast<CXXMemberCallExpr>(S);
+ if (Expr *ImplicitObj = CE->getImplicitObjectArgument()) {
+ ImplicitObj = ImplicitObj->IgnoreParens();
+ val.liveStmts = LV.SSetFact.add(val.liveStmts, ImplicitObj);
+ }
+ break;
+ }
+ case Stmt::DeclStmtClass: {
+ const DeclStmt *DS = cast<DeclStmt>(S);
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl())) {
+ for (const VariableArrayType* VA = FindVA(VD->getType());
+ VA != 0; VA = FindVA(VA->getElementType())) {
+ val.liveStmts = LV.SSetFact.add(val.liveStmts,
+ VA->getSizeExpr()->IgnoreParens());
+ }
+ }
+ break;
+ }
+ // FIXME: These cases eventually shouldn't be needed.
+ case Stmt::ExprWithCleanupsClass: {
+ S = cast<ExprWithCleanups>(S)->getSubExpr();
+ break;
+ }
+ case Stmt::CXXBindTemporaryExprClass: {
+ S = cast<CXXBindTemporaryExpr>(S)->getSubExpr();
+ break;
+ }
+ case Stmt::UnaryExprOrTypeTraitExprClass: {
+ // No need to unconditionally visit subexpressions.
+ return;
+ }
+ }
+
+ for (Stmt::child_iterator it = S->child_begin(), ei = S->child_end();
+ it != ei; ++it) {
+ if (Stmt *child = *it) {
+ if (Expr *Ex = dyn_cast<Expr>(child))
+ child = Ex->IgnoreParens();
+
+ val.liveStmts = LV.SSetFact.add(val.liveStmts, child);
+ }
+ }
}
-void TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
- if (VarDecl* V = dyn_cast<VarDecl>(DR->getDecl()))
- LiveState(V, AD) = Alive;
+void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) {
+ if (B->isAssignmentOp()) {
+ if (!LV.killAtAssign)
+ return;
+
+ // Assigning to a variable?
+ Expr *LHS = B->getLHS()->IgnoreParens();
+
+ if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS))
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ // Assignments to references don't kill the ref's address
+ if (VD->getType()->isReferenceType())
+ return;
+
+ if (!isAlwaysAlive(VD)) {
+ // The variable is now dead.
+ val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
+ }
+
+ if (observer)
+ observer->observerKill(DR);
+ }
+ }
}
-
-void TransferFuncs::VisitBlockExpr(BlockExpr *BE) {
+
+void TransferFunctions::VisitBlockExpr(BlockExpr *BE) {
AnalysisContext::referenced_decls_iterator I, E;
- llvm::tie(I, E) = AD.AC->getReferencedBlockVars(BE->getBlockDecl());
+ llvm::tie(I, E) =
+ LV.analysisContext.getReferencedBlockVars(BE->getBlockDecl());
for ( ; I != E ; ++I) {
- DeclBitVector_Types::Idx i = AD.getIdx(*I);
- if (i.isValid())
- LiveState.getBit(i) = Alive;
+ const VarDecl *VD = *I;
+ if (isAlwaysAlive(VD))
+ continue;
+ val.liveDecls = LV.DSetFact.add(val.liveDecls, VD);
}
}
-void TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {
- if (B->isAssignmentOp()) VisitAssign(B);
- else VisitStmt(B);
+void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *DR) {
+ if (const VarDecl *D = dyn_cast<VarDecl>(DR->getDecl()))
+ if (!isAlwaysAlive(D) && LV.inAssignment.find(DR) == LV.inAssignment.end())
+ val.liveDecls = LV.DSetFact.add(val.liveDecls, D);
}
-void
-TransferFuncs::BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
-
- // This is a block-level expression. Its value is 'dead' before this point.
- LiveState(S, AD) = Dead;
-
- // This represents a 'use' of the collection.
- Visit(S->getCollection());
+void TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
+ for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE = DS->decl_end();
+ DI != DE; ++DI)
+ if (VarDecl *VD = dyn_cast<VarDecl>(*DI)) {
+ if (!isAlwaysAlive(VD))
+ val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
+ }
+}
- // This represents a 'kill' for the variable.
- Stmt* Element = S->getElement();
- DeclRefExpr* DR = 0;
- VarDecl* VD = 0;
+void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS) {
+ // Kill the iteration variable.
+ DeclRefExpr *DR = 0;
+ const VarDecl *VD = 0;
- if (DeclStmt* DS = dyn_cast<DeclStmt>(Element))
+ Stmt *element = OS->getElement();
+ if (DeclStmt *DS = dyn_cast<DeclStmt>(element)) {
VD = cast<VarDecl>(DS->getSingleDecl());
- else {
- Expr* ElemExpr = cast<Expr>(Element)->IgnoreParens();
- if ((DR = dyn_cast<DeclRefExpr>(ElemExpr)))
- VD = cast<VarDecl>(DR->getDecl());
- else {
- Visit(ElemExpr);
- return;
- }
}
-
+ else if ((DR = dyn_cast<DeclRefExpr>(cast<Expr>(element)->IgnoreParens()))) {
+ VD = cast<VarDecl>(DR->getDecl());
+ }
+
if (VD) {
- LiveState(VD, AD) = Dead;
- if (AD.Observer && DR) { AD.Observer->ObserverKill(DR); }
+ val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
+ if (observer && DR)
+ observer->observerKill(DR);
}
}
+void TransferFunctions::
+VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE)
+{
+ // While sizeof(var) doesn't technically extend the liveness of 'var', it
+ // does extent the liveness of metadata if 'var' is a VariableArrayType.
+ // We handle that special case here.
+ if (UE->getKind() != UETT_SizeOf || UE->isArgumentType())
+ return;
-void TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
- Expr *E = U->getSubExpr();
+ const Expr *subEx = UE->getArgumentExpr();
+ if (subEx->getType()->isVariableArrayType()) {
+ assert(subEx->isLValue());
+ val.liveStmts = LV.SSetFact.add(val.liveStmts, subEx->IgnoreParens());
+ }
+}
- switch (U->getOpcode()) {
+void TransferFunctions::VisitUnaryOperator(UnaryOperator *UO) {
+ // Treat ++/-- as a kill.
+ // Note we don't actually have to do anything if we don't have an observer,
+ // since a ++/-- acts as both a kill and a "use".
+ if (!observer)
+ return;
+
+ switch (UO->getOpcode()) {
+ default:
+ return;
case UO_PostInc:
- case UO_PostDec:
+ case UO_PostDec:
case UO_PreInc:
case UO_PreDec:
- // Walk through the subexpressions, blasting through ParenExprs
- // until we either find a DeclRefExpr or some non-DeclRefExpr
- // expression.
- if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E->IgnoreParens()))
- if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) {
- // Treat the --/++ operator as a kill.
- if (AD.Observer) { AD.Observer->ObserverKill(DR); }
- LiveState(VD, AD) = Alive;
- return VisitDeclRefExpr(DR);
- }
-
- // Fall-through.
-
- default:
- return Visit(E);
+ break;
}
+
+ if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(UO->getSubExpr()->IgnoreParens()))
+ if (isa<VarDecl>(DR->getDecl())) {
+ // Treat ++/-- as a kill.
+ observer->observerKill(DR);
+ }
}
-void TransferFuncs::VisitAssign(BinaryOperator* B) {
- Expr* LHS = B->getLHS();
+LiveVariables::LivenessValues
+LiveVariablesImpl::runOnBlock(const CFGBlock *block,
+ LiveVariables::LivenessValues val,
+ LiveVariables::Observer *obs) {
- // Assigning to a variable?
- if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(LHS->IgnoreParens())) {
- // Assignments to references don't kill the ref's address
- if (DR->getDecl()->getType()->isReferenceType()) {
- VisitDeclRefExpr(DR);
- } else {
- if (AD.killAtAssign) {
- // Update liveness inforamtion.
- unsigned bit = AD.getIdx(DR->getDecl());
- LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit);
-
- if (AD.Observer) { AD.Observer->ObserverKill(DR); }
- }
- // Handle things like +=, etc., which also generate "uses"
- // of a variable. Do this just by visiting the subexpression.
- if (B->getOpcode() != BO_Assign)
- VisitDeclRefExpr(DR);
- }
+ TransferFunctions TF(*this, val, obs, block);
+
+ // Visit the terminator (if any).
+ if (const Stmt *term = block->getTerminator())
+ TF.Visit(const_cast<Stmt*>(term));
+
+ // Apply the transfer function for all Stmts in the block.
+ for (CFGBlock::const_reverse_iterator it = block->rbegin(),
+ ei = block->rend(); it != ei; ++it) {
+ const CFGElement &elem = *it;
+ if (!isa<CFGStmt>(elem))
+ continue;
+
+ const Stmt *S = cast<CFGStmt>(elem).getStmt();
+ TF.Visit(const_cast<Stmt*>(S));
+ stmtsToLiveness[S] = val;
}
- else // Not assigning to a variable. Process LHS as usual.
- Visit(LHS);
-
- Visit(B->getRHS());
+ return val;
}
-void TransferFuncs::VisitDeclStmt(DeclStmt* DS) {
- // Declarations effectively "kill" a variable since they cannot
- // possibly be live before they are declared.
- for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE = DS->decl_end();
- DI != DE; ++DI)
- if (VarDecl* VD = dyn_cast<VarDecl>(*DI)) {
- // Update liveness information by killing the VarDecl.
- unsigned bit = AD.getIdx(VD);
- LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit);
-
- // The initializer is evaluated after the variable comes into scope, but
- // before the DeclStmt (which binds the value to the variable).
- // Since this is a reverse dataflow analysis, we must evaluate the
- // transfer function for this expression after the DeclStmt. If the
- // initializer references the variable (which is bad) then we extend
- // its liveness.
- if (Expr* Init = VD->getInit())
- Visit(Init);
-
- if (const VariableArrayType* VT =
- AD.getContext().getAsVariableArrayType(VD->getType())) {
- StmtIterator I(const_cast<VariableArrayType*>(VT));
- StmtIterator E;
- for (; I != E; ++I) Visit(*I);
- }
- }
+void LiveVariables::runOnAllBlocks(LiveVariables::Observer &obs) {
+ const CFG *cfg = getImpl(impl).analysisContext.getCFG();
+ for (CFG::const_iterator it = cfg->begin(), ei = cfg->end(); it != ei; ++it)
+ getImpl(impl).runOnBlock(*it, getImpl(impl).blocksEndToLiveness[*it], &obs);
}
-} // end anonymous namespace
+LiveVariables::LiveVariables(void *im) : impl(im) {}
-//===----------------------------------------------------------------------===//
-// Merge operator: if something is live on any successor block, it is live
-// in the current block (a set union).
-//===----------------------------------------------------------------------===//
-
-namespace {
- typedef StmtDeclBitVector_Types::Union Merge;
- typedef DataflowSolver<LiveVariables, TransferFuncs, Merge> Solver;
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
-// External interface to run Liveness analysis.
-//===----------------------------------------------------------------------===//
-
-void LiveVariables::runOnCFG(CFG& cfg) {
- Solver S(*this);
- S.runOnCFG(cfg);
-}
-
-void LiveVariables::runOnAllBlocks(const CFG& cfg,
- LiveVariables::ObserverTy* Obs,
- bool recordStmtValues) {
- Solver S(*this);
- SaveAndRestore<LiveVariables::ObserverTy*> SRObs(getAnalysisData().Observer,
- Obs);
- S.runOnAllBlocks(cfg, recordStmtValues);
+LiveVariables::~LiveVariables() {
+ delete (LiveVariablesImpl*) impl;
}
-//===----------------------------------------------------------------------===//
-// liveness queries
-//
-
-bool LiveVariables::isLive(const CFGBlock* B, const VarDecl* D) const {
- DeclBitVector_Types::Idx i = getAnalysisData().getIdx(D);
- return i.isValid() ? getBlockData(B).getBit(i) : false;
+LiveVariables *
+LiveVariables::computeLiveness(AnalysisContext &AC,
+ bool killAtAssign) {
+
+ // No CFG? Bail out.
+ CFG *cfg = AC.getCFG();
+ if (!cfg)
+ return 0;
+
+ LiveVariablesImpl *LV = new LiveVariablesImpl(AC, killAtAssign);
+
+ // Construct the dataflow worklist. Enqueue the exit block as the
+ // start of the analysis.
+ DataflowWorklist worklist(*cfg);
+ llvm::BitVector everAnalyzedBlock(cfg->getNumBlockIDs());
+
+ // FIXME: we should enqueue using post order.
+ for (CFG::const_iterator it = cfg->begin(), ei = cfg->end(); it != ei; ++it) {
+ const CFGBlock *block = *it;
+ worklist.enqueueBlock(block);
+
+ // FIXME: Scan for DeclRefExprs using in the LHS of an assignment.
+ // We need to do this because we lack context in the reverse analysis
+ // to determine if a DeclRefExpr appears in such a context, and thus
+ // doesn't constitute a "use".
+ 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 (BO->getOpcode() == BO_Assign) {
+ if (const DeclRefExpr *DR =
+ dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParens())) {
+ LV->inAssignment[DR] = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ worklist.sortWorklist();
+
+ while (const CFGBlock *block = worklist.dequeue()) {
+ // Determine if the block's end value has changed. If not, we
+ // have nothing left to do for this block.
+ LivenessValues &prevVal = LV->blocksEndToLiveness[block];
+
+ // Merge the values of all successor blocks.
+ LivenessValues val;
+ for (CFGBlock::const_succ_iterator it = block->succ_begin(),
+ ei = block->succ_end(); it != ei; ++it) {
+ if (const CFGBlock *succ = *it) {
+ val = LV->merge(val, LV->blocksBeginToLiveness[succ]);
+ }
+ }
+
+ if (!everAnalyzedBlock[block->getBlockID()])
+ everAnalyzedBlock[block->getBlockID()] = true;
+ else if (prevVal.equals(val))
+ continue;
+
+ prevVal = val;
+
+ // Update the dataflow value for the start of this block.
+ LV->blocksBeginToLiveness[block] = LV->runOnBlock(block, val);
+
+ // Enqueue the value to the predecessors.
+ worklist.enqueuePredecessors(block);
+ }
+
+ return new LiveVariables(LV);
}
-bool LiveVariables::isLive(const ValTy& Live, const VarDecl* D) const {
- DeclBitVector_Types::Idx i = getAnalysisData().getIdx(D);
- return i.isValid() ? Live.getBit(i) : false;
+static bool compare_entries(const CFGBlock *A, const CFGBlock *B) {
+ return A->getBlockID() < B->getBlockID();
}
-bool LiveVariables::isLive(const Stmt* Loc, const Stmt* StmtVal) const {
- return getStmtData(Loc)(StmtVal,getAnalysisData());
+static bool compare_vd_entries(const Decl *A, const Decl *B) {
+ SourceLocation ALoc = A->getLocStart();
+ SourceLocation BLoc = B->getLocStart();
+ return ALoc.getRawEncoding() < BLoc.getRawEncoding();
}
-bool LiveVariables::isLive(const Stmt* Loc, const VarDecl* D) const {
- return getStmtData(Loc)(D,getAnalysisData());
+void LiveVariables::dumpBlockLiveness(const SourceManager &M) {
+ getImpl(impl).dumpBlockLiveness(M);
}
-//===----------------------------------------------------------------------===//
-// printing liveness state for debugging
-//
+void LiveVariablesImpl::dumpBlockLiveness(const SourceManager &M) {
+ std::vector<const CFGBlock *> vec;
+ for (llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues>::iterator
+ it = blocksEndToLiveness.begin(), ei = blocksEndToLiveness.end();
+ it != ei; ++it) {
+ vec.push_back(it->first);
+ }
+ std::sort(vec.begin(), vec.end(), compare_entries);
-void LiveVariables::dumpLiveness(const ValTy& V, const SourceManager& SM) const {
- const AnalysisDataTy& AD = getAnalysisData();
+ std::vector<const VarDecl*> declVec;
- for (AnalysisDataTy::decl_iterator I = AD.begin_decl(),
- E = AD.end_decl(); I!=E; ++I)
- if (V.getDeclBit(I->second)) {
- llvm::errs() << " " << I->first->getIdentifier()->getName() << " <";
- I->first->getLocation().dump(SM);
+ for (std::vector<const CFGBlock *>::iterator
+ it = vec.begin(), ei = vec.end(); it != ei; ++it) {
+ llvm::errs() << "\n[ B" << (*it)->getBlockID()
+ << " (live variables at block exit) ]\n";
+
+ LiveVariables::LivenessValues vals = blocksEndToLiveness[*it];
+ declVec.clear();
+
+ for (llvm::ImmutableSet<const VarDecl *>::iterator si =
+ vals.liveDecls.begin(),
+ se = vals.liveDecls.end(); si != se; ++si) {
+ declVec.push_back(*si);
+ }
+
+ std::sort(declVec.begin(), declVec.end(), compare_vd_entries);
+
+ for (std::vector<const VarDecl*>::iterator di = declVec.begin(),
+ de = declVec.end(); di != de; ++di) {
+ llvm::errs() << " " << (*di)->getDeclName().getAsString()
+ << " <";
+ (*di)->getLocation().dump(M);
llvm::errs() << ">\n";
}
-}
-
-void LiveVariables::dumpBlockLiveness(const SourceManager& M) const {
- for (BlockDataMapTy::const_iterator I = getBlockDataMap().begin(),
- E = getBlockDataMap().end(); I!=E; ++I) {
- llvm::errs() << "\n[ B" << I->first->getBlockID()
- << " (live variables at block exit) ]\n";
- dumpLiveness(I->second,M);
}
-
- llvm::errs() << "\n";
+ llvm::errs() << "\n";
}
+
+const void *LiveVariables::getTag() { static int x; return &x; }
+const void *RelaxedLiveVariables::getTag() { static int x; return &x; }
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index 00b0b279e4a0..46ece65a42e7 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -38,8 +38,7 @@ static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
unsigned *argIndex) {
if (argIndex) {
FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
- }
- else {
+ } else {
const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
analyze_format_string::PrecisionPos);
if (Amt.isInvalid())
@@ -388,6 +387,7 @@ bool PrintfSpecifier::fixType(QualType QT) {
case BuiltinType::Char32:
case BuiltinType::UInt128:
case BuiltinType::Int128:
+ case BuiltinType::Half:
// Integral types which are non-trivial to correct.
return false;
@@ -461,15 +461,14 @@ bool PrintfSpecifier::fixType(QualType QT) {
CS.setKind(ConversionSpecifier::uArg);
HasAlternativeForm = 0;
HasPlusPrefix = 0;
- }
- else {
- assert(0 && "Unexpected type");
+ } else {
+ llvm_unreachable("Unexpected type");
}
return true;
}
-void PrintfSpecifier::toString(llvm::raw_ostream &os) const {
+void PrintfSpecifier::toString(raw_ostream &os) const {
// Whilst some features have no defined order, we are using the order
// appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
os << "%";
diff --git a/lib/Analysis/ProgramPoint.cpp b/lib/Analysis/ProgramPoint.cpp
new file mode 100644
index 000000000000..3a0bbd5640d9
--- /dev/null
+++ b/lib/Analysis/ProgramPoint.cpp
@@ -0,0 +1,51 @@
+//==- ProgramPoint.cpp - Program Points for Path-Sensitive Analysis -*- C++ -*-/
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the interface ProgramPoint, which identifies a
+// distinct location in a function.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/ProgramPoint.h"
+
+using namespace clang;
+
+ProgramPointTag::~ProgramPointTag() {}
+
+ProgramPoint ProgramPoint::getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
+ const LocationContext *LC,
+ const ProgramPointTag *tag){
+ switch (K) {
+ default:
+ llvm_unreachable("Unhandled ProgramPoint kind");
+ case ProgramPoint::PreStmtKind:
+ return PreStmt(S, LC, tag);
+ case ProgramPoint::PostStmtKind:
+ return PostStmt(S, LC, tag);
+ case ProgramPoint::PreLoadKind:
+ return PreLoad(S, LC, tag);
+ case ProgramPoint::PostLoadKind:
+ return PostLoad(S, LC, tag);
+ case ProgramPoint::PreStoreKind:
+ return PreStore(S, LC, tag);
+ case ProgramPoint::PostStoreKind:
+ return PostStore(S, LC, tag);
+ case ProgramPoint::PostLValueKind:
+ return PostLValue(S, LC, tag);
+ case ProgramPoint::PostPurgeDeadSymbolsKind:
+ return PostPurgeDeadSymbols(S, LC, tag);
+ }
+}
+
+SimpleProgramPointTag::SimpleProgramPointTag(StringRef description)
+ : desc(description) {}
+
+StringRef SimpleProgramPointTag::getTagDescription() const {
+ return desc;
+}
diff --git a/lib/Analysis/PseudoConstantAnalysis.cpp b/lib/Analysis/PseudoConstantAnalysis.cpp
index ff96eb4a0a73..8f24c432b157 100644
--- a/lib/Analysis/PseudoConstantAnalysis.cpp
+++ b/lib/Analysis/PseudoConstantAnalysis.cpp
@@ -83,7 +83,7 @@ void PseudoConstantAnalysis::RunAnalysis() {
WorkList.push_back(DeclBody);
while (!WorkList.empty()) {
- const Stmt* Head = WorkList.front();
+ const Stmt *Head = WorkList.front();
WorkList.pop_front();
if (const Expr *Ex = dyn_cast<Expr>(Head))
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index c5b17fc77bb2..49317718c381 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -25,22 +25,163 @@
using namespace clang;
-static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1,
- SourceRange &R2) {
- const Stmt *S = 0;
- unsigned sn = 0;
- R1 = R2 = SourceRange();
+namespace {
+class DeadCodeScan {
+ llvm::BitVector Visited;
+ llvm::BitVector &Reachable;
+ llvm::SmallVector<const CFGBlock *, 10> WorkList;
+
+ typedef llvm::SmallVector<std::pair<const CFGBlock *, const Stmt *>, 12>
+ DeferredLocsTy;
+
+ DeferredLocsTy DeferredLocs;
+
+public:
+ DeadCodeScan(llvm::BitVector &reachable)
+ : Visited(reachable.size()),
+ Reachable(reachable) {}
+
+ void enqueue(const CFGBlock *block);
+ unsigned scanBackwards(const CFGBlock *Start,
+ clang::reachable_code::Callback &CB);
+
+ bool isDeadCodeRoot(const CFGBlock *Block);
+
+ const Stmt *findDeadCode(const CFGBlock *Block);
+
+ void reportDeadCode(const Stmt *S,
+ clang::reachable_code::Callback &CB);
+};
+}
+
+void DeadCodeScan::enqueue(const CFGBlock *block) {
+ unsigned blockID = block->getBlockID();
+ if (Reachable[blockID] || Visited[blockID])
+ return;
+ Visited[blockID] = true;
+ WorkList.push_back(block);
+}
+
+bool DeadCodeScan::isDeadCodeRoot(const clang::CFGBlock *Block) {
+ bool isDeadRoot = true;
+
+ for (CFGBlock::const_pred_iterator I = Block->pred_begin(),
+ E = Block->pred_end(); I != E; ++I) {
+ if (const CFGBlock *PredBlock = *I) {
+ unsigned blockID = PredBlock->getBlockID();
+ if (Visited[blockID]) {
+ isDeadRoot = false;
+ continue;
+ }
+ if (!Reachable[blockID]) {
+ isDeadRoot = false;
+ Visited[blockID] = true;
+ WorkList.push_back(PredBlock);
+ continue;
+ }
+ }
+ }
+
+ return isDeadRoot;
+}
+
+static bool isValidDeadStmt(const Stmt *S) {
+ if (S->getLocStart().isInvalid())
+ return false;
+ if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S))
+ return BO->getOpcode() != BO_Comma;
+ return true;
+}
+
+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>()) {
+ const Stmt *S = CS->getStmt();
+ if (isValidDeadStmt(S))
+ return S;
+ }
+
+ if (CFGTerminator T = Block->getTerminator()) {
+ const Stmt *S = T.getStmt();
+ if (isValidDeadStmt(S))
+ return S;
+ }
+
+ return 0;
+}
+
+static int SrcCmp(const void *p1, const void *p2) {
+ return
+ ((std::pair<const CFGBlock *, const Stmt *>*) p2)->second->getLocStart() <
+ ((std::pair<const CFGBlock *, const Stmt *>*) p1)->second->getLocStart();
+}
+
+unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start,
+ clang::reachable_code::Callback &CB) {
+
+ unsigned count = 0;
+ enqueue(Start);
+
+ while (!WorkList.empty()) {
+ const CFGBlock *Block = WorkList.pop_back_val();
+
+ // It is possible that this block has been marked reachable after
+ // it was enqueued.
+ if (Reachable[Block->getBlockID()])
+ continue;
+
+ // Look for any dead code within the block.
+ const Stmt *S = findDeadCode(Block);
+
+ if (!S) {
+ // No dead code. Possibly an empty block. Look at dead predecessors.
+ for (CFGBlock::const_pred_iterator I = Block->pred_begin(),
+ E = Block->pred_end(); I != E; ++I) {
+ if (const CFGBlock *predBlock = *I)
+ enqueue(predBlock);
+ }
+ continue;
+ }
+
+ // Specially handle macro-expanded code.
+ if (S->getLocStart().isMacroID()) {
+ count += clang::reachable_code::ScanReachableFromBlock(Block, Reachable);
+ continue;
+ }
+
+ if (isDeadCodeRoot(Block)) {
+ reportDeadCode(S, CB);
+ count += clang::reachable_code::ScanReachableFromBlock(Block, Reachable);
+ }
+ else {
+ // Record this statement as the possibly best location in a
+ // strongly-connected component of dead code for emitting a
+ // warning.
+ DeferredLocs.push_back(std::make_pair(Block, S));
+ }
+ }
- if (sn < b.size()) {
- const CFGStmt *CS = b[sn].getAs<CFGStmt>();
- if (!CS)
- return SourceLocation();
+ // If we didn't find a dead root, then report the dead code with the
+ // earliest location.
+ if (!DeferredLocs.empty()) {
+ llvm::array_pod_sort(DeferredLocs.begin(), DeferredLocs.end(), SrcCmp);
+ for (DeferredLocsTy::iterator I = DeferredLocs.begin(),
+ E = DeferredLocs.end(); I != E; ++I) {
+ const CFGBlock *block = I->first;
+ if (Reachable[block->getBlockID()])
+ continue;
+ reportDeadCode(I->second, CB);
+ count += clang::reachable_code::ScanReachableFromBlock(block, Reachable);
+ }
+ }
+
+ return count;
+}
- S = CS->getStmt();
- } else if (b.getTerminator())
- S = b.getTerminator();
- else
- return SourceLocation();
+static SourceLocation GetUnreachableLoc(const Stmt *S,
+ SourceRange &R1,
+ SourceRange &R2) {
+ R1 = R2 = SourceRange();
if (const Expr *Ex = dyn_cast<Expr>(S))
S = Ex->IgnoreParenImpCasts();
@@ -48,24 +189,6 @@ static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1,
switch (S->getStmtClass()) {
case Expr::BinaryOperatorClass: {
const BinaryOperator *BO = cast<BinaryOperator>(S);
- if (BO->getOpcode() == BO_Comma) {
- if (sn+1 < b.size())
- return b[sn+1].getAs<CFGStmt>()->getStmt()->getLocStart();
- const CFGBlock *n = &b;
- while (1) {
- if (n->getTerminator())
- return n->getTerminator()->getLocStart();
- if (n->succ_size() != 1)
- return SourceLocation();
- n = n[0].succ_begin()[0];
- if (n->pred_size() != 1)
- return SourceLocation();
- if (!n->empty())
- return n[0][0].getAs<CFGStmt>()->getStmt()->getLocStart();
- }
- }
- R1 = BO->getLHS()->getSourceRange();
- R2 = BO->getRHS()->getSourceRange();
return BO->getOperatorLoc();
}
case Expr::UnaryOperatorClass: {
@@ -120,177 +243,87 @@ static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1,
return S->getLocStart();
}
-static SourceLocation MarkLiveTop(const CFGBlock *Start,
- llvm::BitVector &reachable,
- SourceManager &SM) {
-
- // Prep work worklist.
- llvm::SmallVector<const CFGBlock*, 32> WL;
- WL.push_back(Start);
-
+void DeadCodeScan::reportDeadCode(const Stmt *S,
+ clang::reachable_code::Callback &CB) {
SourceRange R1, R2;
- SourceLocation top = GetUnreachableLoc(*Start, R1, R2);
-
- bool FromMainFile = false;
- bool FromSystemHeader = false;
- bool TopValid = false;
-
- if (top.isValid()) {
- FromMainFile = SM.isFromMainFile(top);
- FromSystemHeader = SM.isInSystemHeader(top);
- TopValid = true;
- }
-
- // Solve
- CFGBlock::FilterOptions FO;
- FO.IgnoreDefaultsWithCoveredEnums = 1;
-
- while (!WL.empty()) {
- const CFGBlock *item = WL.back();
- WL.pop_back();
-
- SourceLocation c = GetUnreachableLoc(*item, R1, R2);
- if (c.isValid()
- && (!TopValid
- || (SM.isFromMainFile(c) && !FromMainFile)
- || (FromSystemHeader && !SM.isInSystemHeader(c))
- || SM.isBeforeInTranslationUnit(c, top))) {
- top = c;
- FromMainFile = SM.isFromMainFile(top);
- FromSystemHeader = SM.isInSystemHeader(top);
- }
-
- reachable.set(item->getBlockID());
- for (CFGBlock::filtered_succ_iterator I =
- item->filtered_succ_start_end(FO); I.hasMore(); ++I)
- if (const CFGBlock *B = *I) {
- unsigned blockID = B->getBlockID();
- if (!reachable[blockID]) {
- reachable.set(blockID);
- WL.push_back(B);
- }
- }
- }
-
- return top;
+ SourceLocation Loc = GetUnreachableLoc(S, R1, R2);
+ CB.HandleUnreachable(Loc, R1, R2);
}
-static int LineCmp(const void *p1, const void *p2) {
- SourceLocation *Line1 = (SourceLocation *)p1;
- SourceLocation *Line2 = (SourceLocation *)p2;
- return !(*Line1 < *Line2);
-}
-
-namespace {
-struct ErrLoc {
- SourceLocation Loc;
- SourceRange R1;
- SourceRange R2;
- ErrLoc(SourceLocation l, SourceRange r1, SourceRange r2)
- : Loc(l), R1(r1), R2(r2) { }
-};
-}
namespace clang { namespace reachable_code {
-
-/// ScanReachableFromBlock - Mark all blocks reachable from Start.
-/// Returns the total number of blocks that were marked reachable.
-unsigned ScanReachableFromBlock(const CFGBlock &Start,
+
+unsigned ScanReachableFromBlock(const CFGBlock *Start,
llvm::BitVector &Reachable) {
unsigned count = 0;
- llvm::SmallVector<const CFGBlock*, 32> WL;
-
+
// Prep work queue
- Reachable.set(Start.getBlockID());
- ++count;
- WL.push_back(&Start);
-
+ SmallVector<const CFGBlock*, 32> WL;
+
+ // The entry block may have already been marked reachable
+ // by the caller.
+ if (!Reachable[Start->getBlockID()]) {
+ ++count;
+ Reachable[Start->getBlockID()] = true;
+ }
+
+ WL.push_back(Start);
+
// Find the reachable blocks from 'Start'.
- CFGBlock::FilterOptions FO;
- FO.IgnoreDefaultsWithCoveredEnums = 1;
-
while (!WL.empty()) {
- const CFGBlock *item = WL.back();
- WL.pop_back();
-
- // Look at the successors and mark then reachable.
- for (CFGBlock::filtered_succ_iterator I= item->filtered_succ_start_end(FO);
- I.hasMore(); ++I)
+ const CFGBlock *item = WL.pop_back_val();
+
+ // Look at the successors and mark then reachable.
+ for (CFGBlock::const_succ_iterator I = item->succ_begin(),
+ E = item->succ_end(); I != E; ++I)
if (const CFGBlock *B = *I) {
unsigned blockID = B->getBlockID();
if (!Reachable[blockID]) {
Reachable.set(blockID);
- ++count;
WL.push_back(B);
+ ++count;
}
}
}
return count;
}
-
+
void FindUnreachableCode(AnalysisContext &AC, Callback &CB) {
CFG *cfg = AC.getCFG();
if (!cfg)
return;
- // Scan for reachable blocks.
+ // Scan for reachable blocks from the entrance of the CFG.
+ // If there are no unreachable blocks, we're done.
llvm::BitVector reachable(cfg->getNumBlockIDs());
- unsigned numReachable = ScanReachableFromBlock(cfg->getEntry(), reachable);
-
- // If there are no unreachable blocks, we're done.
+ unsigned numReachable = ScanReachableFromBlock(&cfg->getEntry(), reachable);
if (numReachable == cfg->getNumBlockIDs())
return;
-
- SourceRange R1, R2;
-
- llvm::SmallVector<ErrLoc, 24> lines;
- bool AddEHEdges = AC.getAddEHEdges();
-
- // First, give warnings for blocks with no predecessors, as they
- // can't be part of a loop.
- for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
- CFGBlock &b = **I;
- if (!reachable[b.getBlockID()]) {
- if (b.pred_empty()) {
- if (!AddEHEdges
- && dyn_cast_or_null<CXXTryStmt>(b.getTerminator().getStmt())) {
- // When not adding EH edges from calls, catch clauses
- // can otherwise seem dead. Avoid noting them as dead.
- numReachable += ScanReachableFromBlock(b, reachable);
- continue;
- }
- SourceLocation c = GetUnreachableLoc(b, R1, R2);
- if (!c.isValid()) {
- // Blocks without a location can't produce a warning, so don't mark
- // reachable blocks from here as live.
- reachable.set(b.getBlockID());
- ++numReachable;
- continue;
- }
- lines.push_back(ErrLoc(c, R1, R2));
- // Avoid excessive errors by marking everything reachable from here
- numReachable += ScanReachableFromBlock(b, reachable);
- }
+
+ // If there aren't explicit EH edges, we should include the 'try' dispatch
+ // blocks as roots.
+ if (!AC.getCFGBuildOptions().AddEHEdges) {
+ for (CFG::try_block_iterator I = cfg->try_blocks_begin(),
+ E = cfg->try_blocks_end() ; I != E; ++I) {
+ numReachable += ScanReachableFromBlock(*I, reachable);
}
+ if (numReachable == cfg->getNumBlockIDs())
+ return;
}
- if (numReachable < cfg->getNumBlockIDs()) {
- // And then give warnings for the tops of loops.
- for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
- CFGBlock &b = **I;
- if (!reachable[b.getBlockID()])
- // Avoid excessive errors by marking everything reachable from here
- lines.push_back(ErrLoc(MarkLiveTop(&b, reachable,
- AC.getASTContext().getSourceManager()),
- SourceRange(), SourceRange()));
- }
+ // There are some unreachable blocks. We need to find the root blocks that
+ // contain code that should be considered unreachable.
+ for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
+ const CFGBlock *block = *I;
+ // A block may have been marked reachable during this loop.
+ if (reachable[block->getBlockID()])
+ continue;
+
+ DeadCodeScan DS(reachable);
+ numReachable += DS.scanBackwards(block, CB);
+
+ if (numReachable == cfg->getNumBlockIDs())
+ return;
}
-
- llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp);
-
- for (llvm::SmallVectorImpl<ErrLoc>::iterator I=lines.begin(), E=lines.end();
- I != E; ++I)
- if (I->Loc.isValid())
- CB.HandleUnreachable(I->Loc, I->R1, I->R2);
}
}} // end namespace clang::reachable_code
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
new file mode 100644
index 000000000000..5a12913c1c94
--- /dev/null
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -0,0 +1,799 @@
+//===- ThreadSafety.cpp ----------------------------------------*- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A intra-procedural analysis for thread safety (e.g. deadlocks and race
+// conditions), based off of an annotation system.
+//
+// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety for more
+// information.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Analyses/ThreadSafety.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/CFGStmtMap.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 "llvm/ADT/BitVector.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include <algorithm>
+#include <vector>
+
+using namespace clang;
+using namespace thread_safety;
+
+// Key method definition
+ThreadSafetyHandler::~ThreadSafetyHandler() {}
+
+// Helper function
+static Expr *getParent(Expr *Exp) {
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(Exp))
+ return ME->getBase();
+ if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(Exp))
+ return CE->getImplicitObjectArgument();
+ return 0;
+}
+
+namespace {
+/// \brief Implements a set of CFGBlocks using a BitVector.
+///
+/// This class contains a minimal interface, primarily dictated by the SetType
+/// template parameter of the llvm::po_iterator template, as used with external
+/// storage. We also use this set to keep track of which CFGBlocks we visit
+/// during the analysis.
+class CFGBlockSet {
+ llvm::BitVector VisitedBlockIDs;
+
+public:
+ // po_iterator requires this iterator, but the only interface needed is the
+ // value_type typedef.
+ struct iterator {
+ typedef const CFGBlock *value_type;
+ };
+
+ CFGBlockSet() {}
+ CFGBlockSet(const CFG *G) : VisitedBlockIDs(G->getNumBlockIDs(), false) {}
+
+ /// \brief Set the bit associated with a particular CFGBlock.
+ /// This is the important method for the SetType template parameter.
+ bool insert(const CFGBlock *Block) {
+ // Note that insert() is called by po_iterator, which doesn't check to make
+ // sure that Block is non-null. Moreover, the CFGBlock iterator will
+ // occasionally hand out null pointers for pruned edges, so we catch those
+ // here.
+ if (Block == 0)
+ return false; // if an edge is trivially false.
+ if (VisitedBlockIDs.test(Block->getBlockID()))
+ return false;
+ VisitedBlockIDs.set(Block->getBlockID());
+ return true;
+ }
+
+ /// \brief Check if the bit for a CFGBlock has been already set.
+ /// This method is for tracking visited blocks in the main threadsafety loop.
+ /// Block must not be null.
+ bool alreadySet(const CFGBlock *Block) {
+ return VisitedBlockIDs.test(Block->getBlockID());
+ }
+};
+
+/// \brief We create a helper class which we use to iterate through CFGBlocks in
+/// the topological order.
+class TopologicallySortedCFG {
+ typedef llvm::po_iterator<const CFG*, CFGBlockSet, true> po_iterator;
+
+ std::vector<const CFGBlock*> Blocks;
+
+public:
+ typedef std::vector<const CFGBlock*>::reverse_iterator iterator;
+
+ TopologicallySortedCFG(const CFG *CFGraph) {
+ Blocks.reserve(CFGraph->getNumBlockIDs());
+ CFGBlockSet BSet(CFGraph);
+
+ for (po_iterator I = po_iterator::begin(CFGraph, BSet),
+ E = po_iterator::end(CFGraph, BSet); I != E; ++I) {
+ Blocks.push_back(*I);
+ }
+ }
+
+ iterator begin() {
+ return Blocks.rbegin();
+ }
+
+ iterator end() {
+ return Blocks.rend();
+ }
+
+ bool empty() {
+ return begin() == end();
+ }
+};
+
+/// \brief A MutexID object uniquely identifies a particular mutex, and
+/// is built from an Expr* (i.e. calling a lock function).
+///
+/// Thread-safety analysis works by comparing lock expressions. Within the
+/// body of a function, an expression such as "x->foo->bar.mu" will resolve to
+/// a particular mutex object at run-time. Subsequent occurrences of the same
+/// expression (where "same" means syntactic equality) will refer to the same
+/// run-time object if three conditions hold:
+/// (1) Local variables in the expression, such as "x" have not changed.
+/// (2) Values on the heap that affect the expression have not changed.
+/// (3) The expression involves only pure function calls.
+/// The current implementation assumes, but does not verify, that multiple uses
+/// of the same lock expression satisfies these criteria.
+///
+/// Clang introduces an additional wrinkle, which is that it is difficult to
+/// derive canonical expressions, or compare expressions directly for equality.
+/// Thus, we identify a mutex not by an Expr, but by the set of named
+/// declarations that are referenced by the Expr. In other words,
+/// x->foo->bar.mu will be a four element vector with the Decls for
+/// mu, bar, and foo, and x. The vector will uniquely identify the expression
+/// for all practical purposes.
+///
+/// Note we will need to perform substitution on "this" and function parameter
+/// names when constructing a lock expression.
+///
+/// For example:
+/// class C { Mutex Mu; void lock() EXCLUSIVE_LOCK_FUNCTION(this->Mu); };
+/// void myFunc(C *X) { ... X->lock() ... }
+/// The original expression for the mutex acquired by myFunc is "this->Mu", but
+/// "X" is substituted for "this" so we get X->Mu();
+///
+/// For another example:
+/// foo(MyList *L) EXCLUSIVE_LOCKS_REQUIRED(L->Mu) { ... }
+/// MyList *MyL;
+/// foo(MyL); // requires lock MyL->Mu to be held
+class MutexID {
+ SmallVector<NamedDecl*, 2> DeclSeq;
+
+ /// Build a Decl sequence representing the lock from the given expression.
+ /// Recursive function that bottoms out when the final DeclRefExpr is reached.
+ // FIXME: Lock expressions that involve array indices or function calls.
+ // FIXME: Deal with LockReturned attribute.
+ void buildMutexID(Expr *Exp, Expr *Parent) {
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp)) {
+ NamedDecl *ND = cast<NamedDecl>(DRE->getDecl()->getCanonicalDecl());
+ DeclSeq.push_back(ND);
+ } else if (MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
+ NamedDecl *ND = ME->getMemberDecl();
+ DeclSeq.push_back(ND);
+ buildMutexID(ME->getBase(), Parent);
+ } else if (isa<CXXThisExpr>(Exp)) {
+ if (Parent)
+ buildMutexID(Parent, 0);
+ else
+ return; // mutexID is still valid in this case
+ } else if (CastExpr *CE = dyn_cast<CastExpr>(Exp))
+ buildMutexID(CE->getSubExpr(), Parent);
+ else
+ DeclSeq.clear(); // invalid lock expression
+ }
+
+public:
+ MutexID(Expr *LExpr, Expr *ParentExpr) {
+ buildMutexID(LExpr, ParentExpr);
+ }
+
+ /// If we encounter part of a lock expression we cannot parse
+ bool isValid() const {
+ return !DeclSeq.empty();
+ }
+
+ bool operator==(const MutexID &other) const {
+ return DeclSeq == other.DeclSeq;
+ }
+
+ bool operator!=(const MutexID &other) const {
+ return !(*this == other);
+ }
+
+ // SmallVector overloads Operator< to do lexicographic ordering. Note that
+ // we use pointer equality (and <) to compare NamedDecls. This means the order
+ // of MutexIDs in a lockset is nondeterministic. In order to output
+ // diagnostics in a deterministic ordering, we must order all diagnostics to
+ // output by SourceLocation when iterating through this lockset.
+ bool operator<(const MutexID &other) const {
+ return DeclSeq < other.DeclSeq;
+ }
+
+ /// \brief Returns the name of the first Decl in the list for a given MutexID;
+ /// e.g. the lock expression foo.bar() has name "bar".
+ /// The caret will point unambiguously to the lock expression, so using this
+ /// name in diagnostics is a way to get simple, and consistent, mutex names.
+ /// We do not want to output the entire expression text for security reasons.
+ StringRef getName() const {
+ assert(isValid());
+ return DeclSeq.front()->getName();
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ for (SmallVectorImpl<NamedDecl*>::const_iterator I = DeclSeq.begin(),
+ E = DeclSeq.end(); I != E; ++I) {
+ ID.AddPointer(*I);
+ }
+ }
+};
+
+/// \brief This is a helper class that stores info about the most recent
+/// accquire of a Lock.
+///
+/// The main body of the analysis maps MutexIDs to LockDatas.
+struct LockData {
+ SourceLocation AcquireLoc;
+
+ /// \brief LKind stores whether a lock is held shared or exclusively.
+ /// Note that this analysis does not currently support either re-entrant
+ /// locking or lock "upgrading" and "downgrading" between exclusive and
+ /// shared.
+ ///
+ /// FIXME: add support for re-entrant locking and lock up/downgrading
+ LockKind LKind;
+
+ LockData(SourceLocation AcquireLoc, LockKind LKind)
+ : AcquireLoc(AcquireLoc), LKind(LKind) {}
+
+ bool operator==(const LockData &other) const {
+ return AcquireLoc == other.AcquireLoc && LKind == other.LKind;
+ }
+
+ bool operator!=(const LockData &other) const {
+ return !(*this == other);
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(AcquireLoc.getRawEncoding());
+ ID.AddInteger(LKind);
+ }
+};
+
+/// A Lockset maps each MutexID (defined above) to information about how it has
+/// been locked.
+typedef llvm::ImmutableMap<MutexID, LockData> Lockset;
+
+/// \brief We use this class to visit different types of expressions in
+/// CFGBlocks, and build up the lockset.
+/// An expression may cause us to add or remove locks from the lockset, or else
+/// output error messages related to missing locks.
+/// FIXME: In future, we may be able to not inherit from a visitor.
+class BuildLockset : public StmtVisitor<BuildLockset> {
+ ThreadSafetyHandler &Handler;
+ Lockset LSet;
+ Lockset::Factory &LocksetFactory;
+
+ // Helper functions
+ void removeLock(SourceLocation UnlockLoc, Expr *LockExp, Expr *Parent);
+ void addLock(SourceLocation LockLoc, Expr *LockExp, Expr *Parent,
+ LockKind LK);
+ const ValueDecl *getValueDecl(Expr *Exp);
+ void warnIfMutexNotHeld (const NamedDecl *D, Expr *Exp, AccessKind AK,
+ Expr *MutexExp, ProtectedOperationKind POK);
+ void checkAccess(Expr *Exp, AccessKind AK);
+ void checkDereference(Expr *Exp, AccessKind AK);
+
+ template <class AttrType>
+ void addLocksToSet(LockKind LK, Attr *Attr, CXXMemberCallExpr *Exp);
+
+ /// \brief Returns true if the lockset contains a lock, regardless of whether
+ /// the lock is held exclusively or shared.
+ bool locksetContains(MutexID Lock) const {
+ return LSet.lookup(Lock);
+ }
+
+ /// \brief Returns true if the lockset contains a lock with the passed in
+ /// locktype.
+ bool locksetContains(MutexID Lock, LockKind KindRequested) const {
+ const LockData *LockHeld = LSet.lookup(Lock);
+ return (LockHeld && KindRequested == LockHeld->LKind);
+ }
+
+ /// \brief Returns true if the lockset contains a lock with at least the
+ /// passed in locktype. So for example, if we pass in LK_Shared, this function
+ /// returns true if the lock is held LK_Shared or LK_Exclusive. If we pass in
+ /// LK_Exclusive, this function returns true if the lock is held LK_Exclusive.
+ bool locksetContainsAtLeast(MutexID Lock, LockKind KindRequested) const {
+ switch (KindRequested) {
+ case LK_Shared:
+ return locksetContains(Lock);
+ case LK_Exclusive:
+ return locksetContains(Lock, KindRequested);
+ }
+ llvm_unreachable("Unknown LockKind");
+ }
+
+public:
+ BuildLockset(ThreadSafetyHandler &Handler, Lockset LS, Lockset::Factory &F)
+ : StmtVisitor<BuildLockset>(), Handler(Handler), LSet(LS),
+ LocksetFactory(F) {}
+
+ Lockset getLockset() {
+ return LSet;
+ }
+
+ void VisitUnaryOperator(UnaryOperator *UO);
+ void VisitBinaryOperator(BinaryOperator *BO);
+ void VisitCastExpr(CastExpr *CE);
+ void VisitCXXMemberCallExpr(CXXMemberCallExpr *Exp);
+};
+
+/// \brief Add a new lock to the lockset, warning if the lock is already there.
+/// \param LockLoc The source location of the acquire
+/// \param LockExp The lock expression corresponding to the lock to be added
+void BuildLockset::addLock(SourceLocation LockLoc, Expr *LockExp, Expr *Parent,
+ LockKind LK) {
+ // FIXME: deal with acquired before/after annotations. We can write a first
+ // pass that does the transitive lookup lazily, and refine afterwards.
+ MutexID Mutex(LockExp, Parent);
+ if (!Mutex.isValid()) {
+ Handler.handleInvalidLockExp(LockExp->getExprLoc());
+ return;
+ }
+
+ LockData NewLock(LockLoc, LK);
+
+ // FIXME: Don't always warn when we have support for reentrant locks.
+ if (locksetContains(Mutex))
+ Handler.handleDoubleLock(Mutex.getName(), LockLoc);
+ LSet = LocksetFactory.add(LSet, Mutex, NewLock);
+}
+
+/// \brief Remove a lock from the lockset, warning if the lock is not there.
+/// \param LockExp The lock expression corresponding to the lock to be removed
+/// \param UnlockLoc The source location of the unlock (only used in error msg)
+void BuildLockset::removeLock(SourceLocation UnlockLoc, Expr *LockExp,
+ Expr *Parent) {
+ MutexID Mutex(LockExp, Parent);
+ if (!Mutex.isValid()) {
+ Handler.handleInvalidLockExp(LockExp->getExprLoc());
+ return;
+ }
+
+ Lockset NewLSet = LocksetFactory.remove(LSet, Mutex);
+ if(NewLSet == LSet)
+ Handler.handleUnmatchedUnlock(Mutex.getName(), UnlockLoc);
+
+ LSet = NewLSet;
+}
+
+/// \brief Gets the value decl pointer from DeclRefExprs or MemberExprs
+const ValueDecl *BuildLockset::getValueDecl(Expr *Exp) {
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Exp))
+ return DR->getDecl();
+
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp))
+ return ME->getMemberDecl();
+
+ return 0;
+}
+
+/// \brief Warn if the LSet does not contain a lock sufficient to protect access
+/// of at least the passed in AccessType.
+void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp,
+ AccessKind AK, Expr *MutexExp,
+ ProtectedOperationKind POK) {
+ LockKind LK = getLockKindFromAccessKind(AK);
+ Expr *Parent = getParent(Exp);
+ MutexID Mutex(MutexExp, Parent);
+ if (!Mutex.isValid())
+ Handler.handleInvalidLockExp(MutexExp->getExprLoc());
+ else if (!locksetContainsAtLeast(Mutex, LK))
+ Handler.handleMutexNotHeld(D, POK, Mutex.getName(), LK, Exp->getExprLoc());
+}
+
+
+/// \brief This method identifies variable dereferences and checks pt_guarded_by
+/// and pt_guarded_var annotations. Note that we only check these annotations
+/// at the time a pointer is dereferenced.
+/// 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)
+ return;
+ Exp = UO->getSubExpr()->IgnoreParenCasts();
+
+ const ValueDecl *D = getValueDecl(Exp);
+ if(!D || !D->hasAttrs())
+ return;
+
+ if (D->getAttr<PtGuardedVarAttr>() && LSet.isEmpty())
+ Handler.handleNoMutexHeld(D, POK_VarDereference, 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);
+}
+
+/// \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) {
+ const ValueDecl *D = getValueDecl(Exp);
+ if(!D || !D->hasAttrs())
+ return;
+
+ if (D->getAttr<GuardedVarAttr>() && LSet.isEmpty())
+ Handler.handleNoMutexHeld(D, POK_VarAccess, 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);
+}
+
+/// \brief For unary operations which read and write a variable, we need to
+/// check whether we hold any required mutexes. Reads are checked in
+/// VisitCastExpr.
+void BuildLockset::VisitUnaryOperator(UnaryOperator *UO) {
+ switch (UO->getOpcode()) {
+ case clang::UO_PostDec:
+ 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);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+/// For binary operations which assign to a variable (writes), we need to check
+/// whether we hold any required mutexes.
+/// FIXME: Deal with non-primitive types.
+void BuildLockset::VisitBinaryOperator(BinaryOperator *BO) {
+ if (!BO->isAssignmentOp())
+ return;
+ Expr *LHSExp = BO->getLHS()->IgnoreParenCasts();
+ checkAccess(LHSExp, AK_Written);
+ checkDereference(LHSExp, AK_Written);
+}
+
+/// Whenever we do an LValue to Rvalue cast, we are reading a variable and
+/// need to ensure we hold any required mutexes.
+/// FIXME: Deal with non-primitive types.
+void BuildLockset::VisitCastExpr(CastExpr *CE) {
+ if (CE->getCastKind() != CK_LValueToRValue)
+ return;
+ Expr *SubExp = CE->getSubExpr()->IgnoreParenCasts();
+ checkAccess(SubExp, AK_Read);
+ checkDereference(SubExp, AK_Read);
+}
+
+/// \brief This function, parameterized by an attribute type, is used to add a
+/// set of locks specified as attribute arguments to the lockset.
+template <typename AttrType>
+void BuildLockset::addLocksToSet(LockKind LK, Attr *Attr,
+ CXXMemberCallExpr *Exp) {
+ typedef typename AttrType::args_iterator iterator_type;
+ SourceLocation ExpLocation = Exp->getExprLoc();
+ Expr *Parent = Exp->getImplicitObjectArgument();
+ AttrType *SpecificAttr = cast<AttrType>(Attr);
+
+ if (SpecificAttr->args_size() == 0) {
+ // The mutex held is the "this" object.
+ addLock(ExpLocation, Parent, 0, LK);
+ return;
+ }
+
+ for (iterator_type I = SpecificAttr->args_begin(),
+ E = SpecificAttr->args_end(); I != E; ++I)
+ addLock(ExpLocation, *I, Parent, LK);
+}
+
+/// \brief When visiting CXXMemberCallExprs we need to examine the attributes on
+/// the method that is being called and add, remove or check locks in the
+/// lockset accordingly.
+///
+/// FIXME: For classes annotated with one of the guarded annotations, we need
+/// to treat const method calls as reads and non-const method calls as writes,
+/// and check that the appropriate locks are held. Non-const method calls with
+/// the same signature as const method calls can be also treated as reads.
+///
+/// FIXME: We need to also visit CallExprs to catch/check global functions.
+///
+/// FIXME: Do not flag an error for member variables accessed in constructors/
+/// destructors
+void BuildLockset::VisitCXXMemberCallExpr(CXXMemberCallExpr *Exp) {
+ NamedDecl *D = dyn_cast_or_null<NamedDecl>(Exp->getCalleeDecl());
+
+ SourceLocation ExpLocation = Exp->getExprLoc();
+ Expr *Parent = Exp->getImplicitObjectArgument();
+
+ if(!D || !D->hasAttrs())
+ return;
+
+ AttrVec &ArgAttrs = D->getAttrs();
+ for(unsigned i = 0; i < ArgAttrs.size(); ++i) {
+ Attr *Attr = ArgAttrs[i];
+ switch (Attr->getKind()) {
+ // When we encounter an exclusive lock function, we need to add the lock
+ // to our lockset with kind exclusive.
+ case attr::ExclusiveLockFunction:
+ addLocksToSet<ExclusiveLockFunctionAttr>(LK_Exclusive, Attr, Exp);
+ break;
+
+ // When we encounter a shared lock function, we need to add the lock
+ // to our lockset with kind shared.
+ case attr::SharedLockFunction:
+ addLocksToSet<SharedLockFunctionAttr>(LK_Shared, Attr, Exp);
+ break;
+
+ // When we encounter an unlock function, we need to remove unlocked
+ // mutexes from the lockset, and flag a warning if they are not there.
+ case attr::UnlockFunction: {
+ UnlockFunctionAttr *UFAttr = cast<UnlockFunctionAttr>(Attr);
+
+ if (UFAttr->args_size() == 0) { // The lock held is the "this" object.
+ removeLock(ExpLocation, Parent, 0);
+ break;
+ }
+
+ for (UnlockFunctionAttr::args_iterator I = UFAttr->args_begin(),
+ E = UFAttr->args_end(); I != E; ++I)
+ removeLock(ExpLocation, *I, Parent);
+ break;
+ }
+
+ case attr::ExclusiveLocksRequired: {
+ ExclusiveLocksRequiredAttr *ELRAttr =
+ cast<ExclusiveLocksRequiredAttr>(Attr);
+
+ for (ExclusiveLocksRequiredAttr::args_iterator
+ I = ELRAttr->args_begin(), E = ELRAttr->args_end(); I != E; ++I)
+ warnIfMutexNotHeld(D, Exp, AK_Written, *I, POK_FunctionCall);
+ break;
+ }
+
+ case attr::SharedLocksRequired: {
+ SharedLocksRequiredAttr *SLRAttr = cast<SharedLocksRequiredAttr>(Attr);
+
+ for (SharedLocksRequiredAttr::args_iterator I = SLRAttr->args_begin(),
+ E = SLRAttr->args_end(); I != E; ++I)
+ warnIfMutexNotHeld(D, Exp, AK_Read, *I, POK_FunctionCall);
+ break;
+ }
+
+ case attr::LocksExcluded: {
+ LocksExcludedAttr *LEAttr = cast<LocksExcludedAttr>(Attr);
+ for (LocksExcludedAttr::args_iterator I = LEAttr->args_begin(),
+ E = LEAttr->args_end(); I != E; ++I) {
+ MutexID Mutex(*I, Parent);
+ if (!Mutex.isValid())
+ Handler.handleInvalidLockExp((*I)->getExprLoc());
+ else if (locksetContains(Mutex))
+ Handler.handleFunExcludesLock(D->getName(), Mutex.getName(),
+ ExpLocation);
+ }
+ break;
+ }
+
+ // Ignore other (non thread-safety) attributes
+ default:
+ break;
+ }
+ }
+}
+
+} // end anonymous namespace
+
+/// \brief Compute the intersection of two locksets and issue warnings for any
+/// locks in the symmetric difference.
+///
+/// This function is used at a merge point in the CFG when comparing the lockset
+/// of each branch being merged. For example, given the following sequence:
+/// A; if () then B; else C; D; we need to check that the lockset after B and C
+/// are the same. In the event of a difference, we use the intersection of these
+/// two locksets at the start of D.
+static Lockset intersectAndWarn(ThreadSafetyHandler &Handler,
+ const Lockset LSet1, const Lockset LSet2,
+ Lockset::Factory &Fact, LockErrorKind LEK) {
+ Lockset Intersection = LSet1;
+ for (Lockset::iterator I = LSet2.begin(), E = LSet2.end(); I != E; ++I) {
+ const MutexID &LSet2Mutex = I.getKey();
+ const LockData &LSet2LockData = I.getData();
+ if (const LockData *LD = LSet1.lookup(LSet2Mutex)) {
+ if (LD->LKind != LSet2LockData.LKind) {
+ Handler.handleExclusiveAndShared(LSet2Mutex.getName(),
+ LSet2LockData.AcquireLoc,
+ LD->AcquireLoc);
+ if (LD->LKind != LK_Exclusive)
+ Intersection = Fact.add(Intersection, LSet2Mutex, LSet2LockData);
+ }
+ } else {
+ Handler.handleMutexHeldEndOfScope(LSet2Mutex.getName(),
+ LSet2LockData.AcquireLoc, LEK);
+ }
+ }
+
+ for (Lockset::iterator I = LSet1.begin(), E = LSet1.end(); I != E; ++I) {
+ if (!LSet2.contains(I.getKey())) {
+ const MutexID &Mutex = I.getKey();
+ const LockData &MissingLock = I.getData();
+ Handler.handleMutexHeldEndOfScope(Mutex.getName(),
+ MissingLock.AcquireLoc, LEK);
+ Intersection = Fact.remove(Intersection, Mutex);
+ }
+ }
+ return Intersection;
+}
+
+static Lockset addLock(ThreadSafetyHandler &Handler,
+ Lockset::Factory &LocksetFactory,
+ Lockset &LSet, Expr *LockExp, LockKind LK,
+ SourceLocation Loc) {
+ MutexID Mutex(LockExp, 0);
+ if (!Mutex.isValid()) {
+ Handler.handleInvalidLockExp(LockExp->getExprLoc());
+ return LSet;
+ }
+ LockData NewLock(Loc, LK);
+ return LocksetFactory.add(LSet, Mutex, NewLock);
+}
+
+namespace clang {
+namespace thread_safety {
+/// \brief Check a function's CFG for thread-safety violations.
+///
+/// We traverse the blocks in the CFG, compute the set of mutexes that are held
+/// at the end of each block, and issue warnings for thread safety violations.
+/// Each block in the CFG is traversed exactly once.
+void runThreadSafetyAnalysis(AnalysisContext &AC,
+ ThreadSafetyHandler &Handler) {
+ CFG *CFGraph = AC.getCFG();
+ if (!CFGraph) return;
+ const Decl *D = AC.getDecl();
+ if (D && D->getAttr<NoThreadSafetyAnalysisAttr>()) return;
+
+ Lockset::Factory LocksetFactory;
+
+ // FIXME: Swith to SmallVector? Otherwise improve performance impact?
+ std::vector<Lockset> EntryLocksets(CFGraph->getNumBlockIDs(),
+ LocksetFactory.getEmptyMap());
+ std::vector<Lockset> ExitLocksets(CFGraph->getNumBlockIDs(),
+ LocksetFactory.getEmptyMap());
+
+ // We need to explore the CFG via a "topological" ordering.
+ // That way, we will be guaranteed to have information about required
+ // predecessor locksets when exploring a new block.
+ TopologicallySortedCFG SortedGraph(CFGraph);
+ CFGBlockSet VisitedBlocks(CFGraph);
+
+ if (!SortedGraph.empty() && D->hasAttrs()) {
+ const CFGBlock *FirstBlock = *SortedGraph.begin();
+ Lockset &InitialLockset = EntryLocksets[FirstBlock->getBlockID()];
+ const AttrVec &ArgAttrs = D->getAttrs();
+ for(unsigned i = 0; i < ArgAttrs.size(); ++i) {
+ Attr *Attr = ArgAttrs[i];
+ SourceLocation AttrLoc = Attr->getLocation();
+ if (SharedLocksRequiredAttr *SLRAttr
+ = dyn_cast<SharedLocksRequiredAttr>(Attr)) {
+ for (SharedLocksRequiredAttr::args_iterator
+ SLRIter = SLRAttr->args_begin(),
+ SLREnd = SLRAttr->args_end(); SLRIter != SLREnd; ++SLRIter)
+ InitialLockset = addLock(Handler, LocksetFactory, InitialLockset,
+ *SLRIter, LK_Shared,
+ AttrLoc);
+ } else if (ExclusiveLocksRequiredAttr *ELRAttr
+ = dyn_cast<ExclusiveLocksRequiredAttr>(Attr)) {
+ for (ExclusiveLocksRequiredAttr::args_iterator
+ ELRIter = ELRAttr->args_begin(),
+ ELREnd = ELRAttr->args_end(); ELRIter != ELREnd; ++ELRIter)
+ InitialLockset = addLock(Handler, LocksetFactory, InitialLockset,
+ *ELRIter, LK_Exclusive,
+ AttrLoc);
+ }
+ }
+ }
+
+ for (TopologicallySortedCFG::iterator I = SortedGraph.begin(),
+ E = SortedGraph.end(); I!= E; ++I) {
+ const CFGBlock *CurrBlock = *I;
+ int CurrBlockID = CurrBlock->getBlockID();
+
+ VisitedBlocks.insert(CurrBlock);
+
+ // Use the default initial lockset in case there are no predecessors.
+ Lockset &Entryset = EntryLocksets[CurrBlockID];
+ Lockset &Exitset = ExitLocksets[CurrBlockID];
+
+ // Iterate through the predecessor blocks and warn if the lockset for all
+ // predecessors is not the same. We take the entry lockset of the current
+ // block to be the intersection of all previous locksets.
+ // FIXME: By keeping the intersection, we may output more errors in future
+ // for a lock which is not in the intersection, but was in the union. We
+ // may want to also keep the union in future. As an example, let's say
+ // the intersection contains Mutex L, and the union contains L and M.
+ // Later we unlock M. At this point, we would output an error because we
+ // never locked M; although the real error is probably that we forgot to
+ // lock M on all code paths. Conversely, let's say that later we lock M.
+ // In this case, we should compare against the intersection instead of the
+ // union because the real error is probably that we forgot to unlock M on
+ // all code paths.
+ bool LocksetInitialized = false;
+ for (CFGBlock::const_pred_iterator PI = CurrBlock->pred_begin(),
+ PE = CurrBlock->pred_end(); PI != PE; ++PI) {
+
+ // if *PI -> CurrBlock is a back edge
+ if (*PI == 0 || !VisitedBlocks.alreadySet(*PI))
+ continue;
+
+ int PrevBlockID = (*PI)->getBlockID();
+ if (!LocksetInitialized) {
+ Entryset = ExitLocksets[PrevBlockID];
+ LocksetInitialized = true;
+ } else {
+ Entryset = intersectAndWarn(Handler, Entryset,
+ ExitLocksets[PrevBlockID], LocksetFactory,
+ LEK_LockedSomePredecessors);
+ }
+ }
+
+ BuildLockset LocksetBuilder(Handler, Entryset, LocksetFactory);
+ for (CFGBlock::const_iterator BI = CurrBlock->begin(),
+ BE = CurrBlock->end(); BI != BE; ++BI) {
+ if (const CFGStmt *CfgStmt = dyn_cast<CFGStmt>(&*BI))
+ LocksetBuilder.Visit(const_cast<Stmt*>(CfgStmt->getStmt()));
+ }
+ Exitset = LocksetBuilder.getLockset();
+
+ // For every back edge from CurrBlock (the end of the loop) to another block
+ // (FirstLoopBlock) we need to check that the Lockset of Block is equal to
+ // the one held at the beginning of FirstLoopBlock. We can look up the
+ // Lockset held at the beginning of FirstLoopBlock in the EntryLockSets map.
+ for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
+ SE = CurrBlock->succ_end(); SI != SE; ++SI) {
+
+ // if CurrBlock -> *SI is *not* a back edge
+ if (*SI == 0 || !VisitedBlocks.alreadySet(*SI))
+ continue;
+
+ CFGBlock *FirstLoopBlock = *SI;
+ Lockset PreLoop = EntryLocksets[FirstLoopBlock->getBlockID()];
+ Lockset LoopEnd = ExitLocksets[CurrBlockID];
+ intersectAndWarn(Handler, LoopEnd, PreLoop, LocksetFactory,
+ LEK_LockedSomeLoopIterations);
+ }
+ }
+
+ Lockset InitialLockset = EntryLocksets[CFGraph->getEntry().getBlockID()];
+ Lockset FinalLockset = ExitLocksets[CFGraph->getExit().getBlockID()];
+
+ // FIXME: Should we call this function for all blocks which exit the function?
+ intersectAndWarn(Handler, InitialLockset, FinalLockset, LocksetFactory,
+ LEK_LockedAtEndOfFunction);
+}
+
+/// \brief Helper function that returns a LockKind required for the given level
+/// of access.
+LockKind getLockKindFromAccessKind(AccessKind AK) {
+ switch (AK) {
+ case AK_Read :
+ return LK_Shared;
+ case AK_Written :
+ return LK_Exclusive;
+ }
+ llvm_unreachable("Unknown AccessKind");
+}
+}} // end namespace clang::thread_safety
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index 1d6959d81b16..9e98560b655d 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -123,13 +123,7 @@ public:
bool hasNoDeclarations() const {
return declToIndex.size() == 0;
}
-
- bool hasEntry(const VarDecl *vd) const {
- return declToIndex.getValueIndex(vd).hasValue();
- }
-
- bool hasValues(const CFGBlock *block);
-
+
void resetScratch();
ValueVector &getScratch() { return scratch; }
@@ -170,7 +164,7 @@ ValueVector &CFGBlockValues::lazyCreate(ValueVector *&bv) {
/// This function pattern matches for a '&&' or '||' that appears at
/// the beginning of a CFGBlock that also (1) has a terminator and
/// (2) has no other elements. If such an expression is found, it is returned.
-static BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) {
+static const BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) {
if (block->empty())
return 0;
@@ -178,7 +172,7 @@ static BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) {
if (!cstmt)
return 0;
- BinaryOperator *b = llvm::dyn_cast_or_null<BinaryOperator>(cstmt->getStmt());
+ const BinaryOperator *b = dyn_cast_or_null<BinaryOperator>(cstmt->getStmt());
if (!b || !b->isLogicalOp())
return 0;
@@ -209,11 +203,6 @@ ValueVector &CFGBlockValues::getValueVector(const CFGBlock *block,
return lazyCreate(vals[idx].first);
}
-bool CFGBlockValues::hasValues(const CFGBlock *block) {
- unsigned idx = block->getBlockID();
- return vals[idx].second != 0;
-}
-
BVPair &CFGBlockValues::getValueVectors(const clang::CFGBlock *block,
bool shouldLazyCreate) {
unsigned idx = block->getBlockID();
@@ -223,13 +212,6 @@ BVPair &CFGBlockValues::getValueVectors(const clang::CFGBlock *block,
return vals[idx];
}
-void CFGBlockValues::mergeIntoScratch(ValueVector const &source,
- bool isFirst) {
- if (isFirst)
- scratch = source;
- else
- scratch |= source;
-}
#if 0
static void printVector(const CFGBlock *block, ValueVector &bv,
unsigned num) {
@@ -240,8 +222,24 @@ static void printVector(const CFGBlock *block, ValueVector &bv,
}
llvm::errs() << " : " << num << '\n';
}
+
+static void printVector(const char *name, ValueVector const &bv) {
+ llvm::errs() << name << " : ";
+ for (unsigned i = 0; i < bv.size(); ++i) {
+ llvm::errs() << ' ' << bv[i];
+ }
+ llvm::errs() << "\n";
+}
#endif
+void CFGBlockValues::mergeIntoScratch(ValueVector const &source,
+ bool isFirst) {
+ if (isFirst)
+ scratch = source;
+ else
+ scratch |= source;
+}
+
bool CFGBlockValues::updateValueVectorWithScratch(const CFGBlock *block) {
ValueVector &dst = getValueVector(block, 0);
bool changed = (dst != scratch);
@@ -283,7 +281,7 @@ ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
namespace {
class DataflowWorklist {
- llvm::SmallVector<const CFGBlock *, 20> worklist;
+ SmallVector<const CFGBlock *, 20> worklist;
llvm::BitVector enqueuedBlocks;
public:
DataflowWorklist(const CFG &cfg) : enqueuedBlocks(cfg.getNumBlockIDs()) {}
@@ -336,23 +334,34 @@ public:
const VarDecl *getDecl() const { return vd; }
};
-class TransferFunctions : public CFGRecStmtVisitor<TransferFunctions> {
+class TransferFunctions : public StmtVisitor<TransferFunctions> {
CFGBlockValues &vals;
const CFG &cfg;
AnalysisContext &ac;
UninitVariablesHandler *handler;
- const DeclRefExpr *currentDR;
- const Expr *currentVoidCast;
- const bool flagBlockUses;
+
+ /// The last DeclRefExpr seen when analyzing a block. Used to
+ /// cheat when detecting cases when the address of a variable is taken.
+ DeclRefExpr *lastDR;
+
+ /// The last lvalue-to-rvalue conversion of a variable whose value
+ /// was uninitialized. Normally this results in a warning, but it is
+ /// possible to either silence the warning in some cases, or we
+ /// propagate the uninitialized value.
+ CastExpr *lastLoad;
+
+ /// For some expressions, we want to ignore any post-processing after
+ /// visitation.
+ bool skipProcessUses;
+
public:
TransferFunctions(CFGBlockValues &vals, const CFG &cfg,
AnalysisContext &ac,
- UninitVariablesHandler *handler,
- bool flagBlockUses)
- : vals(vals), cfg(cfg), ac(ac), handler(handler), currentDR(0),
- currentVoidCast(0), flagBlockUses(flagBlockUses) {}
+ UninitVariablesHandler *handler)
+ : vals(vals), cfg(cfg), ac(ac), handler(handler),
+ lastDR(0), lastLoad(0),
+ skipProcessUses(false) {}
- const CFG &getCFG() { return cfg; }
void reportUninit(const DeclRefExpr *ex, const VarDecl *vd,
bool isAlwaysUninit);
@@ -362,53 +371,59 @@ public:
void VisitUnaryOperator(UnaryOperator *uo);
void VisitBinaryOperator(BinaryOperator *bo);
void VisitCastExpr(CastExpr *ce);
- void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *se);
- void VisitCXXTypeidExpr(CXXTypeidExpr *E);
- void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs);
+ void VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs);
+ void Visit(Stmt *s);
bool isTrackedVar(const VarDecl *vd) {
return ::isTrackedVar(vd, cast<DeclContext>(ac.getDecl()));
}
FindVarResult findBlockVarDecl(Expr *ex);
+
+ void ProcessUses(Stmt *s = 0);
};
}
+static const Expr *stripCasts(ASTContext &C, const Expr *Ex) {
+ while (Ex) {
+ Ex = Ex->IgnoreParenNoopCasts(C);
+ if (const CastExpr *CE = dyn_cast<CastExpr>(Ex)) {
+ if (CE->getCastKind() == CK_LValueBitCast) {
+ Ex = CE->getSubExpr();
+ continue;
+ }
+ }
+ break;
+ }
+ return Ex;
+}
+
void TransferFunctions::reportUninit(const DeclRefExpr *ex,
const VarDecl *vd, bool isAlwaysUnit) {
if (handler) handler->handleUseOfUninitVariable(ex, vd, isAlwaysUnit);
}
-FindVarResult TransferFunctions::findBlockVarDecl(Expr* ex) {
- if (DeclRefExpr* dr = dyn_cast<DeclRefExpr>(ex->IgnoreParenCasts()))
+FindVarResult TransferFunctions::findBlockVarDecl(Expr *ex) {
+ if (DeclRefExpr *dr = dyn_cast<DeclRefExpr>(ex->IgnoreParenCasts()))
if (VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl()))
if (isTrackedVar(vd))
return FindVarResult(vd, dr);
return FindVarResult(0, 0);
}
-void TransferFunctions::BlockStmt_VisitObjCForCollectionStmt(
- ObjCForCollectionStmt *fs) {
-
- Visit(fs->getCollection());
-
+void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs) {
// This represents an initialization of the 'element' value.
Stmt *element = fs->getElement();
- const VarDecl* vd = 0;
+ const VarDecl *vd = 0;
- if (DeclStmt* ds = dyn_cast<DeclStmt>(element)) {
+ if (DeclStmt *ds = dyn_cast<DeclStmt>(element)) {
vd = cast<VarDecl>(ds->getSingleDecl());
if (!isTrackedVar(vd))
vd = 0;
- }
- else {
+ } else {
// Initialize the value of the reference variable.
const FindVarResult &res = findBlockVarDecl(cast<Expr>(element));
vd = res.getDecl();
- if (!vd) {
- Visit(element);
- return;
- }
}
if (vd)
@@ -416,14 +431,10 @@ void TransferFunctions::BlockStmt_VisitObjCForCollectionStmt(
}
void TransferFunctions::VisitBlockExpr(BlockExpr *be) {
- if (!flagBlockUses || !handler)
- return;
const BlockDecl *bd = be->getBlockDecl();
for (BlockDecl::capture_const_iterator i = bd->capture_begin(),
e = bd->capture_end() ; i != e; ++i) {
const VarDecl *vd = i->getVariable();
- if (!vd->hasLocalStorage())
- continue;
if (!isTrackedVar(vd))
continue;
if (i->isByRef()) {
@@ -431,19 +442,27 @@ void TransferFunctions::VisitBlockExpr(BlockExpr *be) {
continue;
}
Value v = vals[vd];
- if (isUninitialized(v))
+ if (handler && isUninitialized(v))
handler->handleUseOfUninitVariable(be, vd, isAlwaysUninit(v));
}
}
+void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
+ // Record the last DeclRefExpr seen. This is an lvalue computation.
+ // We use this value to later detect if a variable "escapes" the analysis.
+ if (const VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl()))
+ if (isTrackedVar(vd)) {
+ ProcessUses();
+ lastDR = dr;
+ }
+}
+
void TransferFunctions::VisitDeclStmt(DeclStmt *ds) {
for (DeclStmt::decl_iterator DI = ds->decl_begin(), DE = ds->decl_end();
DI != DE; ++DI) {
if (VarDecl *vd = dyn_cast<VarDecl>(*DI)) {
if (isTrackedVar(vd)) {
if (Expr *init = vd->getInit()) {
- Visit(init);
-
// If the initializer consists solely of a reference to itself, we
// explicitly mark the variable as uninitialized. This allows code
// like the following:
@@ -454,56 +473,48 @@ void TransferFunctions::VisitDeclStmt(DeclStmt *ds) {
// clients can detect this pattern and adjust their reporting
// appropriately, but we need to continue to analyze subsequent uses
// of the variable.
- DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(init->IgnoreParenImpCasts());
- vals[vd] = (DRE && DRE->getDecl() == vd) ? Uninitialized
- : Initialized;
+ if (init == lastLoad) {
+ const DeclRefExpr *DR
+ = cast<DeclRefExpr>(stripCasts(ac.getASTContext(),
+ lastLoad->getSubExpr()));
+ if (DR->getDecl() == vd) {
+ // int x = x;
+ // Propagate uninitialized value, but don't immediately report
+ // a problem.
+ vals[vd] = Uninitialized;
+ lastLoad = 0;
+ lastDR = 0;
+ if (handler)
+ handler->handleSelfInit(vd);
+ return;
+ }
+ }
+
+ // All other cases: treat the new variable as initialized.
+ // This is a minor optimization to reduce the propagation
+ // of the analysis, since we will have already reported
+ // the use of the uninitialized value (which visiting the
+ // initializer).
+ vals[vd] = Initialized;
}
- } else if (Stmt *init = vd->getInit()) {
- Visit(init);
}
}
}
}
-void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
- // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast
- // cannot be block-level expressions. Therefore, we determine if
- // a DeclRefExpr is involved in a "load" by comparing it to the current
- // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
- // If a DeclRefExpr is not involved in a load, we are essentially computing
- // its address, either for assignment to a reference or via the '&' operator.
- // In such cases, treat the variable as being initialized, since this
- // analysis isn't powerful enough to do alias tracking.
- if (dr != currentDR)
- if (const VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl()))
- if (isTrackedVar(vd))
- vals[vd] = Initialized;
-}
-
void TransferFunctions::VisitBinaryOperator(clang::BinaryOperator *bo) {
if (bo->isAssignmentOp()) {
const FindVarResult &res = findBlockVarDecl(bo->getLHS());
- if (const VarDecl* vd = res.getDecl()) {
- // We assume that DeclRefExprs wrapped in a BinaryOperator "assignment"
- // cannot be block-level expressions. Therefore, we determine if
- // a DeclRefExpr is involved in a "load" by comparing it to the current
- // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
- SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
- res.getDeclRefExpr());
- Visit(bo->getRHS());
- Visit(bo->getLHS());
-
+ if (const VarDecl *vd = res.getDecl()) {
ValueVector::reference val = vals[vd];
if (isUninitialized(val)) {
if (bo->getOpcode() != BO_Assign)
reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val));
- val = Initialized;
+ else
+ val = Initialized;
}
- return;
}
}
- Visit(bo->getRHS());
- Visit(bo->getLHS());
}
void TransferFunctions::VisitUnaryOperator(clang::UnaryOperator *uo) {
@@ -514,86 +525,88 @@ void TransferFunctions::VisitUnaryOperator(clang::UnaryOperator *uo) {
case clang::UO_PreInc: {
const FindVarResult &res = findBlockVarDecl(uo->getSubExpr());
if (const VarDecl *vd = res.getDecl()) {
- // We assume that DeclRefExprs wrapped in a unary operator ++/--
- // cannot be block-level expressions. Therefore, we determine if
- // a DeclRefExpr is involved in a "load" by comparing it to the current
- // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
- SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
- res.getDeclRefExpr());
- Visit(uo->getSubExpr());
+ assert(res.getDeclRefExpr() == lastDR);
+ // We null out lastDR to indicate we have fully processed it
+ // and we don't want the auto-value setting in Visit().
+ lastDR = 0;
ValueVector::reference val = vals[vd];
- if (isUninitialized(val)) {
+ if (isUninitialized(val))
reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val));
- // Don't cascade warnings.
- val = Initialized;
- }
- return;
}
break;
}
default:
break;
}
- Visit(uo->getSubExpr());
}
void TransferFunctions::VisitCastExpr(clang::CastExpr *ce) {
if (ce->getCastKind() == CK_LValueToRValue) {
const FindVarResult &res = findBlockVarDecl(ce->getSubExpr());
- if (const VarDecl *vd = res.getDecl()) {
- // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast
- // cannot be block-level expressions. Therefore, we determine if
- // a DeclRefExpr is involved in a "load" by comparing it to the current
- // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
- // Here we update 'currentDR' to be the one associated with this
- // lvalue-to-rvalue cast. Then, when we analyze the DeclRefExpr, we
- // will know that we are not computing its lvalue for other purposes
- // than to perform a load.
- SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
- res.getDeclRefExpr());
- Visit(ce->getSubExpr());
- if (currentVoidCast != ce) {
- Value val = vals[vd];
- if (isUninitialized(val)) {
- reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val));
- // Don't cascade warnings.
- vals[vd] = Initialized;
- }
- }
- return;
+ if (res.getDecl()) {
+ assert(res.getDeclRefExpr() == lastDR);
+ lastLoad = ce;
}
}
+ else if (ce->getCastKind() == CK_NoOp ||
+ ce->getCastKind() == CK_LValueBitCast) {
+ skipProcessUses = true;
+ }
else if (CStyleCastExpr *cse = dyn_cast<CStyleCastExpr>(ce)) {
if (cse->getType()->isVoidType()) {
// e.g. (void) x;
- SaveAndRestore<const Expr *>
- lastVoidCast(currentVoidCast, cse->getSubExpr()->IgnoreParens());
- Visit(cse->getSubExpr());
- return;
+ if (lastLoad == cse->getSubExpr()) {
+ // Squelch any detected load of an uninitialized value if
+ // we cast it to void.
+ lastLoad = 0;
+ lastDR = 0;
+ }
}
}
- Visit(ce->getSubExpr());
}
-void TransferFunctions::VisitUnaryExprOrTypeTraitExpr(
- UnaryExprOrTypeTraitExpr *se) {
- if (se->getKind() == UETT_SizeOf) {
- if (se->getType()->isConstantSizeType())
+void TransferFunctions::Visit(clang::Stmt *s) {
+ skipProcessUses = false;
+ StmtVisitor<TransferFunctions>::Visit(s);
+ if (!skipProcessUses)
+ ProcessUses(s);
+}
+
+void TransferFunctions::ProcessUses(Stmt *s) {
+ // This method is typically called after visiting a CFGElement statement
+ // in the CFG. We delay processing of reporting many loads of uninitialized
+ // values until here.
+ if (lastLoad) {
+ // If we just visited the lvalue-to-rvalue cast, there is nothing
+ // left to do.
+ if (lastLoad == s)
+ return;
+
+ const DeclRefExpr *DR =
+ cast<DeclRefExpr>(stripCasts(ac.getASTContext(),
+ lastLoad->getSubExpr()));
+ const VarDecl *VD = cast<VarDecl>(DR->getDecl());
+
+ // If we reach here, we may have seen a load of an uninitialized value
+ // and it hasn't been casted to void or otherwise handled. In this
+ // situation, report the incident.
+ if (isUninitialized(vals[VD]))
+ reportUninit(DR, VD, isAlwaysUninit(vals[VD]));
+
+ lastLoad = 0;
+
+ if (DR == lastDR) {
+ lastDR = 0;
return;
- // Handle VLAs.
- Visit(se->getArgumentExpr());
+ }
}
-}
-void TransferFunctions::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(ac.getASTContext()).isGLValue()) {
- QualType SubExprTy = E->getExprOperand()->getType();
- if (const RecordType *Record = SubExprTy->getAs<RecordType>())
- if (cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic())
- Visit(E->getExprOperand());
+ // Any other uses of 'lastDR' involve taking an lvalue of variable.
+ // In this case, it "escapes" the analysis.
+ if (lastDR && lastDR != s) {
+ vals[cast<VarDecl>(lastDR->getDecl())] = Initialized;
+ lastDR = 0;
}
}
@@ -604,8 +617,7 @@ void TransferFunctions::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
AnalysisContext &ac, CFGBlockValues &vals,
llvm::BitVector &wasAnalyzed,
- UninitVariablesHandler *handler = 0,
- bool flagBlockUses = false) {
+ UninitVariablesHandler *handler = 0) {
wasAnalyzed[block->getBlockID()] = true;
@@ -623,8 +635,7 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
vals.mergeIntoScratch(*(vB.second ? vB.second : vB.first), false);
valsAB.first = vA.first;
valsAB.second = &vals.getScratch();
- }
- else {
+ } else {
// Merge the 'T' bits from the first and second.
assert(b->getOpcode() == BO_LOr);
vals.mergeIntoScratch(*vA.first, true);
@@ -640,17 +651,21 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
bool isFirst = true;
for (CFGBlock::const_pred_iterator I = block->pred_begin(),
E = block->pred_end(); I != E; ++I) {
- vals.mergeIntoScratch(vals.getValueVector(*I, block), isFirst);
- isFirst = false;
+ const CFGBlock *pred = *I;
+ if (wasAnalyzed[pred->getBlockID()]) {
+ vals.mergeIntoScratch(vals.getValueVector(pred, block), isFirst);
+ isFirst = false;
+ }
}
// Apply the transfer function.
- TransferFunctions tf(vals, cfg, ac, handler, flagBlockUses);
+ TransferFunctions tf(vals, cfg, ac, handler);
for (CFGBlock::const_iterator I = block->begin(), E = block->end();
I != E; ++I) {
if (const CFGStmt *cs = dyn_cast<CFGStmt>(&*I)) {
- tf.BlockStmt_Visit(cs->getStmt());
+ tf.Visit(const_cast<Stmt*>(cs->getStmt()));
}
}
+ tf.ProcessUses();
return vals.updateValueVectorWithScratch(block);
}
@@ -685,6 +700,7 @@ void clang::runUninitializedVariablesAnalysis(
llvm::BitVector previouslyVisited(cfg.getNumBlockIDs());
worklist.enqueueSuccessors(&cfg.getEntry());
llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false);
+ wasAnalyzed[cfg.getEntry().getBlockID()] = true;
while (const CFGBlock *block = worklist.dequeue()) {
// Did the block change?
@@ -697,9 +713,9 @@ void clang::runUninitializedVariablesAnalysis(
// Run through the blocks one more time, and report uninitialized variabes.
for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
- if (wasAnalyzed[(*BI)->getBlockID()]) {
- runOnBlock(*BI, cfg, ac, vals, wasAnalyzed, &handler,
- /* flagBlockUses */ true);
+ const CFGBlock *block = *BI;
+ if (wasAnalyzed[block->getBlockID()]) {
+ runOnBlock(block, cfg, ac, vals, wasAnalyzed, &handler);
++stats.NumBlockVisits;
}
}
diff --git a/lib/Basic/Builtins.cpp b/lib/Basic/Builtins.cpp
index 7df24a03b03a..7bdcdc688552 100644
--- a/lib/Basic/Builtins.cpp
+++ b/lib/Basic/Builtins.cpp
@@ -32,11 +32,15 @@ const Builtin::Info &Builtin::Context::GetRecord(unsigned ID) const {
return TSRecords[ID - Builtin::FirstTSBuiltin];
}
-Builtin::Context::Context(const TargetInfo &Target) {
+Builtin::Context::Context() {
// Get the target specific builtins from the target.
TSRecords = 0;
NumTSRecords = 0;
- Target.getTargetBuiltins(TSRecords, NumTSRecords);
+}
+
+void Builtin::Context::InitializeTarget(const TargetInfo &Target) {
+ assert(NumTSRecords == 0 && "Already initialized target?");
+ Target.getTargetBuiltins(TSRecords, NumTSRecords);
}
/// InitializeBuiltins - Mark the identifiers for all the builtins with their
@@ -59,7 +63,7 @@ void Builtin::Context::InitializeBuiltins(IdentifierTable &Table,
}
void
-Builtin::Context::GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names,
+Builtin::Context::GetBuiltinNames(SmallVectorImpl<const char *> &Names,
bool NoBuiltins) {
// Final all target-independent names
for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i)
diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt
index c1e7cf6bf971..ff348896e39a 100644
--- a/lib/Basic/CMakeLists.txt
+++ b/lib/Basic/CMakeLists.txt
@@ -8,6 +8,7 @@ add_clang_library(clangBasic
FileManager.cpp
FileSystemStatCache.cpp
IdentifierTable.cpp
+ LangOptions.cpp
SourceLocation.cpp
SourceManager.cpp
TargetInfo.cpp
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index ae363a0df0d0..e5f390196d80 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -20,21 +20,22 @@
using namespace clang;
-static void DummyArgToStringFn(Diagnostic::ArgumentKind AK, intptr_t QT,
+static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT,
const char *Modifier, unsigned ML,
const char *Argument, unsigned ArgLen,
- const Diagnostic::ArgumentValue *PrevArgs,
+ const DiagnosticsEngine::ArgumentValue *PrevArgs,
unsigned NumPrevArgs,
- llvm::SmallVectorImpl<char> &Output,
+ SmallVectorImpl<char> &Output,
void *Cookie,
- llvm::SmallVectorImpl<intptr_t> &QualTypeVals) {
+ SmallVectorImpl<intptr_t> &QualTypeVals) {
const char *Str = "<can't format argument>";
Output.append(Str, Str+strlen(Str));
}
-Diagnostic::Diagnostic(const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &diags,
- DiagnosticClient *client, bool ShouldOwnClient)
+DiagnosticsEngine::DiagnosticsEngine(
+ const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &diags,
+ DiagnosticConsumer *client, bool ShouldOwnClient)
: Diags(diags), Client(client), OwnsDiagClient(ShouldOwnClient),
SourceMgr(0) {
ArgToStringFn = DummyArgToStringFn;
@@ -43,6 +44,7 @@ Diagnostic::Diagnostic(const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &diags,
AllExtensionsSilenced = 0;
IgnoreAllWarnings = false;
WarningsAsErrors = false;
+ EnableAllWarnings = false;
ErrorsAsFatal = false;
SuppressSystemWarnings = false;
SuppressAllDiagnostics = false;
@@ -55,12 +57,13 @@ Diagnostic::Diagnostic(const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &diags,
Reset();
}
-Diagnostic::~Diagnostic() {
+DiagnosticsEngine::~DiagnosticsEngine() {
if (OwnsDiagClient)
delete Client;
}
-void Diagnostic::setClient(DiagnosticClient *client, bool ShouldOwnClient) {
+void DiagnosticsEngine::setClient(DiagnosticConsumer *client,
+ bool ShouldOwnClient) {
if (OwnsDiagClient && Client)
delete Client;
@@ -68,11 +71,11 @@ void Diagnostic::setClient(DiagnosticClient *client, bool ShouldOwnClient) {
OwnsDiagClient = ShouldOwnClient;
}
-void Diagnostic::pushMappings(SourceLocation Loc) {
+void DiagnosticsEngine::pushMappings(SourceLocation Loc) {
DiagStateOnPushStack.push_back(GetCurDiagState());
}
-bool Diagnostic::popMappings(SourceLocation Loc) {
+bool DiagnosticsEngine::popMappings(SourceLocation Loc) {
if (DiagStateOnPushStack.empty())
return false;
@@ -84,7 +87,7 @@ bool Diagnostic::popMappings(SourceLocation Loc) {
return true;
}
-void Diagnostic::Reset() {
+void DiagnosticsEngine::Reset() {
ErrorOccurred = false;
FatalErrorOccurred = false;
UnrecoverableErrorOccurred = false;
@@ -92,11 +95,13 @@ void Diagnostic::Reset() {
NumWarnings = 0;
NumErrors = 0;
NumErrorsSuppressed = 0;
+ TrapNumErrorsOccurred = 0;
+ TrapNumUnrecoverableErrorsOccurred = 0;
CurDiagID = ~0U;
// Set LastDiagLevel to an "unset" state. If we set it to 'Ignored', notes
- // using a Diagnostic associated to a translation unit that follow
- // diagnostics from a Diagnostic associated to anoter t.u. will not be
+ // 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;
DelayedDiagID = 0;
@@ -112,8 +117,8 @@ void Diagnostic::Reset() {
PushDiagStatePoint(&DiagStates.back(), SourceLocation());
}
-void Diagnostic::SetDelayedDiagnostic(unsigned DiagID, llvm::StringRef Arg1,
- llvm::StringRef Arg2) {
+void DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1,
+ StringRef Arg2) {
if (DelayedDiagID)
return;
@@ -122,15 +127,15 @@ void Diagnostic::SetDelayedDiagnostic(unsigned DiagID, llvm::StringRef Arg1,
DelayedDiagArg2 = Arg2.str();
}
-void Diagnostic::ReportDelayed() {
+void DiagnosticsEngine::ReportDelayed() {
Report(DelayedDiagID) << DelayedDiagArg1 << DelayedDiagArg2;
DelayedDiagID = 0;
DelayedDiagArg1.clear();
DelayedDiagArg2.clear();
}
-Diagnostic::DiagStatePointsTy::iterator
-Diagnostic::GetDiagStatePointForLoc(SourceLocation L) const {
+DiagnosticsEngine::DiagStatePointsTy::iterator
+DiagnosticsEngine::GetDiagStatePointForLoc(SourceLocation L) const {
assert(!DiagStatePoints.empty());
assert(DiagStatePoints.front().Loc.isInvalid() &&
"Should have created a DiagStatePoint for command-line");
@@ -155,7 +160,7 @@ Diagnostic::GetDiagStatePointForLoc(SourceLocation L) const {
///
/// \param The source location that this change of diagnostic state should
/// take affect. It can be null if we are setting the latest state.
-void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
+void DiagnosticsEngine::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
SourceLocation L) {
assert(Diag < diag::DIAG_UPPER_LIMIT &&
"Can only map builtin diagnostics");
@@ -167,10 +172,19 @@ void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
bool isPragma = L.isValid();
FullSourceLoc Loc(L, *SourceMgr);
FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
+ DiagnosticMappingInfo MappingInfo = DiagnosticMappingInfo::Make(
+ Map, /*IsUser=*/true, isPragma);
+
+ // If this is a pragma mapping, then set the diagnostic mapping flags so that
+ // we override command line options.
+ if (isPragma) {
+ MappingInfo.setNoWarningAsError(true);
+ MappingInfo.setNoErrorAsFatal(true);
+ }
// Common case; setting all the diagnostics of a group in one place.
if (Loc.isInvalid() || Loc == LastStateChangePos) {
- setDiagnosticMappingInternal(Diag, Map, GetCurDiagState(), true, isPragma);
+ GetCurDiagState()->setMappingInfo(Diag, MappingInfo);
return;
}
@@ -183,7 +197,7 @@ void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
// the new state became active.
DiagStates.push_back(*GetCurDiagState());
PushDiagStatePoint(&DiagStates.back(), Loc);
- setDiagnosticMappingInternal(Diag, Map, GetCurDiagState(), true, isPragma);
+ GetCurDiagState()->setMappingInfo(Diag, MappingInfo);
return;
}
@@ -196,12 +210,12 @@ void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
// Update all diagnostic states that are active after the given location.
for (DiagStatePointsTy::iterator
I = Pos+1, E = DiagStatePoints.end(); I != E; ++I) {
- setDiagnosticMappingInternal(Diag, Map, I->State, true, isPragma);
+ GetCurDiagState()->setMappingInfo(Diag, MappingInfo);
}
// If the location corresponds to an existing point, just update its state.
if (Pos->Loc == Loc) {
- setDiagnosticMappingInternal(Diag, Map, Pos->State, true, isPragma);
+ GetCurDiagState()->setMappingInfo(Diag, MappingInfo);
return;
}
@@ -210,12 +224,86 @@ void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
Pos->Loc.isBeforeInTranslationUnitThan(Loc);
DiagStates.push_back(*Pos->State);
DiagState *NewState = &DiagStates.back();
- setDiagnosticMappingInternal(Diag, Map, NewState, true, isPragma);
+ GetCurDiagState()->setMappingInfo(Diag, MappingInfo);
DiagStatePoints.insert(Pos+1, DiagStatePoint(NewState,
FullSourceLoc(Loc, *SourceMgr)));
}
-void Diagnostic::Report(const StoredDiagnostic &storedDiag) {
+bool DiagnosticsEngine::setDiagnosticGroupMapping(
+ StringRef Group, diag::Mapping Map, SourceLocation Loc)
+{
+ // Get the diagnostics in this group.
+ llvm::SmallVector<diag::kind, 8> GroupDiags;
+ if (Diags->getDiagnosticsInGroup(Group, GroupDiags))
+ return true;
+
+ // Set the mapping.
+ for (unsigned i = 0, e = GroupDiags.size(); i != e; ++i)
+ setDiagnosticMapping(GroupDiags[i], Map, Loc);
+
+ return false;
+}
+
+bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group,
+ bool Enabled) {
+ // If we are enabling this feature, just set the diagnostic mappings to map to
+ // errors.
+ if (Enabled)
+ return setDiagnosticGroupMapping(Group, diag::MAP_ERROR);
+
+ // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
+ // potentially downgrade anything already mapped to be a warning.
+
+ // Get the diagnostics in this group.
+ llvm::SmallVector<diag::kind, 8> GroupDiags;
+ if (Diags->getDiagnosticsInGroup(Group, GroupDiags))
+ return true;
+
+ // Perform the mapping change.
+ for (unsigned i = 0, e = GroupDiags.size(); i != e; ++i) {
+ DiagnosticMappingInfo &Info = GetCurDiagState()->getOrAddMappingInfo(
+ GroupDiags[i]);
+
+ if (Info.getMapping() == diag::MAP_ERROR ||
+ Info.getMapping() == diag::MAP_FATAL)
+ Info.setMapping(diag::MAP_WARNING);
+
+ Info.setNoWarningAsError(true);
+ }
+
+ return false;
+}
+
+bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
+ bool Enabled) {
+ // If we are enabling this feature, just set the diagnostic mappings to map to
+ // fatal errors.
+ if (Enabled)
+ return setDiagnosticGroupMapping(Group, diag::MAP_FATAL);
+
+ // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
+ // potentially downgrade anything already mapped to be an error.
+
+ // Get the diagnostics in this group.
+ llvm::SmallVector<diag::kind, 8> GroupDiags;
+ if (Diags->getDiagnosticsInGroup(Group, GroupDiags))
+ return true;
+
+ // Perform the mapping change.
+ for (unsigned i = 0, e = GroupDiags.size(); i != e; ++i) {
+ DiagnosticMappingInfo &Info = GetCurDiagState()->getOrAddMappingInfo(
+ GroupDiags[i]);
+
+ if (Info.getMapping() == diag::MAP_FATAL)
+ Info.setMapping(diag::MAP_ERROR);
+
+ Info.setNoErrorAsFatal(true);
+ }
+
+ return false;
+}
+
+void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) {
assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!");
CurDiagLoc = storedDiag.getLocation();
@@ -232,19 +320,20 @@ void Diagnostic::Report(const StoredDiagnostic &storedDiag) {
DiagRanges[i++] = *RI;
NumFixItHints = storedDiag.fixit_size();
- assert(NumFixItHints < Diagnostic::MaxFixItHints && "Too many fix-it hints!");
+ assert(NumFixItHints < DiagnosticsEngine::MaxFixItHints &&
+ "Too many fix-it hints!");
i = 0;
for (StoredDiagnostic::fixit_iterator
FI = storedDiag.fixit_begin(),
FE = storedDiag.fixit_end(); FI != FE; ++FI)
FixItHints[i++] = *FI;
- assert(Client && "DiagnosticClient not set!");
+ assert(Client && "DiagnosticConsumer not set!");
Level DiagLevel = storedDiag.getLevel();
- DiagnosticInfo Info(this, storedDiag.getMessage());
+ Diagnostic Info(this, storedDiag.getMessage());
Client->HandleDiagnostic(DiagLevel, Info);
if (Client->IncludeInDiagnosticCounts()) {
- if (DiagLevel == Diagnostic::Warning)
+ if (DiagLevel == DiagnosticsEngine::Warning)
++NumWarnings;
}
@@ -263,11 +352,11 @@ bool DiagnosticBuilder::Emit() {
if (DiagObj == 0) return false;
// When emitting diagnostics, we set the final argument count into
- // the Diagnostic object.
+ // the DiagnosticsEngine object.
FlushCounts();
// Process the diagnostic, sending the accumulated information to the
- // DiagnosticClient.
+ // DiagnosticConsumer.
bool Emitted = DiagObj->ProcessDiag();
// Clear out the current diagnostic object.
@@ -285,16 +374,16 @@ bool DiagnosticBuilder::Emit() {
}
-DiagnosticClient::~DiagnosticClient() {}
+DiagnosticConsumer::~DiagnosticConsumer() {}
-void DiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
- const DiagnosticInfo &Info) {
+void DiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) {
if (!IncludeInDiagnosticCounts())
return;
- if (DiagLevel == Diagnostic::Warning)
+ if (DiagLevel == DiagnosticsEngine::Warning)
++NumWarnings;
- else if (DiagLevel >= Diagnostic::Error)
+ else if (DiagLevel >= DiagnosticsEngine::Error)
++NumErrors;
}
@@ -337,9 +426,9 @@ static const char *ScanFormat(const char *I, const char *E, char Target) {
/// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'.
/// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'.
/// This is very useful for certain classes of variant diagnostics.
-static void HandleSelectModifier(const DiagnosticInfo &DInfo, unsigned ValNo,
+static void HandleSelectModifier(const Diagnostic &DInfo, unsigned ValNo,
const char *Argument, unsigned ArgumentLen,
- llvm::SmallVectorImpl<char> &OutStr) {
+ SmallVectorImpl<char> &OutStr) {
const char *ArgumentEnd = Argument+ArgumentLen;
// Skip over 'ValNo' |'s.
@@ -362,7 +451,7 @@ static void HandleSelectModifier(const DiagnosticInfo &DInfo, unsigned ValNo,
/// letter 's' to the string if the value is not 1. This is used in cases like
/// this: "you idiot, you have %4 parameter%s4!".
static void HandleIntegerSModifier(unsigned ValNo,
- llvm::SmallVectorImpl<char> &OutStr) {
+ SmallVectorImpl<char> &OutStr) {
if (ValNo != 1)
OutStr.push_back('s');
}
@@ -372,7 +461,7 @@ static void HandleIntegerSModifier(unsigned ValNo,
/// to the first ordinal. Currently this is hard-coded to use the
/// English form.
static void HandleOrdinalModifier(unsigned ValNo,
- llvm::SmallVectorImpl<char> &OutStr) {
+ SmallVectorImpl<char> &OutStr) {
assert(ValNo != 0 && "ValNo must be strictly positive!");
llvm::raw_svector_ostream Out(OutStr);
@@ -495,9 +584,9 @@ static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) {
/// {1:form0|[2,4]:form1|:form2}
/// Polish (requires repeated form):
/// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2}
-static void HandlePluralModifier(const DiagnosticInfo &DInfo, unsigned ValNo,
+static void HandlePluralModifier(const Diagnostic &DInfo, unsigned ValNo,
const char *Argument, unsigned ArgumentLen,
- llvm::SmallVectorImpl<char> &OutStr) {
+ SmallVectorImpl<char> &OutStr) {
const char *ArgumentEnd = Argument + ArgumentLen;
while (1) {
assert(Argument < ArgumentEnd && "Plural expression didn't match.");
@@ -523,34 +612,34 @@ static void HandlePluralModifier(const DiagnosticInfo &DInfo, unsigned ValNo,
/// FormatDiagnostic - Format this diagnostic into a string, substituting the
/// formal arguments into the %0 slots. The result is appended onto the Str
/// array.
-void DiagnosticInfo::
-FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
+void Diagnostic::
+FormatDiagnostic(SmallVectorImpl<char> &OutStr) const {
if (!StoredDiagMessage.empty()) {
OutStr.append(StoredDiagMessage.begin(), StoredDiagMessage.end());
return;
}
- llvm::StringRef Diag =
+ StringRef Diag =
getDiags()->getDiagnosticIDs()->getDescription(getID());
FormatDiagnostic(Diag.begin(), Diag.end(), OutStr);
}
-void DiagnosticInfo::
+void Diagnostic::
FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
- llvm::SmallVectorImpl<char> &OutStr) const {
+ SmallVectorImpl<char> &OutStr) const {
/// FormattedArgs - Keep track of all of the arguments formatted by
/// ConvertArgToString and pass them into subsequent calls to
/// ConvertArgToString, allowing the implementation to avoid redundancies in
/// obvious cases.
- llvm::SmallVector<Diagnostic::ArgumentValue, 8> FormattedArgs;
+ SmallVector<DiagnosticsEngine::ArgumentValue, 8> FormattedArgs;
/// QualTypeVals - Pass a vector of arrays so that QualType names can be
/// compared to see if more information is needed to be printed.
- llvm::SmallVector<intptr_t, 2> QualTypeVals;
+ SmallVector<intptr_t, 2> QualTypeVals;
for (unsigned i = 0, e = getNumArgs(); i < e; ++i)
- if (getArgKind(i) == Diagnostic::ak_qualtype)
+ if (getArgKind(i) == DiagnosticsEngine::ak_qualtype)
QualTypeVals.push_back(getRawArg(i));
while (DiagStr != DiagEnd) {
@@ -600,17 +689,17 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
assert(isdigit(*DiagStr) && "Invalid format for argument in diagnostic");
unsigned ArgNo = *DiagStr++ - '0';
- Diagnostic::ArgumentKind Kind = getArgKind(ArgNo);
+ DiagnosticsEngine::ArgumentKind Kind = getArgKind(ArgNo);
switch (Kind) {
// ---- STRINGS ----
- case Diagnostic::ak_std_string: {
+ case DiagnosticsEngine::ak_std_string: {
const std::string &S = getArgStdStr(ArgNo);
assert(ModifierLen == 0 && "No modifiers for strings yet");
OutStr.append(S.begin(), S.end());
break;
}
- case Diagnostic::ak_c_string: {
+ case DiagnosticsEngine::ak_c_string: {
const char *S = getArgCStr(ArgNo);
assert(ModifierLen == 0 && "No modifiers for strings yet");
@@ -622,7 +711,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
break;
}
// ---- INTEGERS ----
- case Diagnostic::ak_sint: {
+ case DiagnosticsEngine::ak_sint: {
int Val = getArgSInt(ArgNo);
if (ModifierIs(Modifier, ModifierLen, "select")) {
@@ -641,7 +730,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
}
break;
}
- case Diagnostic::ak_uint: {
+ case DiagnosticsEngine::ak_uint: {
unsigned Val = getArgUInt(ArgNo);
if (ModifierIs(Modifier, ModifierLen, "select")) {
@@ -660,7 +749,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
break;
}
// ---- NAMES and TYPES ----
- case Diagnostic::ak_identifierinfo: {
+ case DiagnosticsEngine::ak_identifierinfo: {
const IdentifierInfo *II = getArgIdentifier(ArgNo);
assert(ModifierLen == 0 && "No modifiers for strings yet");
@@ -674,11 +763,11 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\'';
break;
}
- case Diagnostic::ak_qualtype:
- case Diagnostic::ak_declarationname:
- case Diagnostic::ak_nameddecl:
- case Diagnostic::ak_nestednamespec:
- case Diagnostic::ak_declcontext:
+ case DiagnosticsEngine::ak_qualtype:
+ case DiagnosticsEngine::ak_declarationname:
+ case DiagnosticsEngine::ak_nameddecl:
+ case DiagnosticsEngine::ak_nestednamespec:
+ case DiagnosticsEngine::ak_declcontext:
getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo),
Modifier, ModifierLen,
Argument, ArgumentLen,
@@ -690,10 +779,10 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
// Remember this argument info for subsequent formatting operations. Turn
// std::strings into a null terminated string to make it be the same case as
// all the other ones.
- if (Kind != Diagnostic::ak_std_string)
+ if (Kind != DiagnosticsEngine::ak_std_string)
FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo)));
else
- FormattedArgs.push_back(std::make_pair(Diagnostic::ak_c_string,
+ FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_c_string,
(intptr_t)getArgStdStr(ArgNo).c_str()));
}
@@ -701,12 +790,12 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
StoredDiagnostic::StoredDiagnostic() { }
-StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level, unsigned ID,
- llvm::StringRef Message)
+StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
+ StringRef Message)
: ID(ID), Level(Level), Loc(), Message(Message) { }
-StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level,
- const DiagnosticInfo &Info)
+StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level,
+ const Diagnostic &Info)
: ID(Info.getID()), Level(Level)
{
assert((Info.getLocation().isInvalid() || Info.hasSourceManager()) &&
@@ -726,13 +815,23 @@ StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level,
FixIts.push_back(Info.getFixItHint(I));
}
+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)
+{
+ this->Ranges.assign(Ranges.begin(), Ranges.end());
+ this->FixIts.assign(FixIts.begin(), FixIts.end());
+}
+
StoredDiagnostic::~StoredDiagnostic() { }
/// IncludeInDiagnosticCounts - This method (whose default implementation
/// returns true) indicates whether the diagnostics handled by this
-/// DiagnosticClient should be included in the number of diagnostics
-/// reported by Diagnostic.
-bool DiagnosticClient::IncludeInDiagnosticCounts() const { return true; }
+/// DiagnosticConsumer should be included in the number of diagnostics
+/// reported by DiagnosticsEngine.
+bool DiagnosticConsumer::IncludeInDiagnosticCounts() const { return true; }
PartialDiagnostic::StorageAllocator::StorageAllocator() {
for (unsigned I = 0; I != NumCached; ++I)
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index 147ba7e99e74..9481287c08cf 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -21,6 +21,8 @@
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/SemaDiagnostic.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/ErrorHandling.h"
#include <map>
using namespace clang;
@@ -45,6 +47,8 @@ struct StaticDiagInfoRec {
unsigned Class : 3;
unsigned SFINAE : 1;
unsigned AccessControl : 1;
+ unsigned WarnNoWerror : 1;
+ unsigned WarnShowInSystemHeader : 1;
unsigned Category : 5;
uint8_t NameLen;
@@ -61,21 +65,21 @@ struct StaticDiagInfoRec {
const char *BriefExplanationStr;
const char *FullExplanationStr;
- llvm::StringRef getName() const {
- return llvm::StringRef(NameStr, NameLen);
+ StringRef getName() const {
+ return StringRef(NameStr, NameLen);
}
- llvm::StringRef getOptionGroup() const {
- return llvm::StringRef(OptionGroupStr, OptionGroupLen);
+ StringRef getOptionGroup() const {
+ return StringRef(OptionGroupStr, OptionGroupLen);
}
- llvm::StringRef getDescription() const {
- return llvm::StringRef(DescriptionStr, DescriptionLen);
+ StringRef getDescription() const {
+ return StringRef(DescriptionStr, DescriptionLen);
}
- llvm::StringRef getBriefExplanation() const {
- return llvm::StringRef(BriefExplanationStr, BriefExplanationLen);
+ StringRef getBriefExplanation() const {
+ return StringRef(BriefExplanationStr, BriefExplanationLen);
}
- llvm::StringRef getFullExplanation() const {
- return llvm::StringRef(FullExplanationStr, FullExplanationLen);
+ StringRef getFullExplanation() const {
+ return StringRef(FullExplanationStr, FullExplanationLen);
}
bool operator<(const StaticDiagInfoRec &RHS) const {
@@ -88,8 +92,8 @@ struct StaticDiagNameIndexRec {
unsigned short DiagID;
uint8_t NameLen;
- llvm::StringRef getName() const {
- return llvm::StringRef(NameStr, NameLen);
+ StringRef getName() const {
+ return StringRef(NameStr, NameLen);
}
bool operator<(const StaticDiagNameIndexRec &RHS) const {
@@ -114,8 +118,10 @@ public:
static const StaticDiagInfoRec StaticDiagInfo[] = {
#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \
- SFINAE,ACCESS,CATEGORY,BRIEF,FULL) \
- { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS, CATEGORY, \
+ SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER, \
+ CATEGORY,BRIEF,FULL) \
+ { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS, \
+ NOWERROR, SHOWINSYSHEADER, CATEGORY, \
STR_SIZE(#ENUM, uint8_t), STR_SIZE(GROUP, uint8_t), \
STR_SIZE(DESC, uint16_t), STR_SIZE(BRIEF, uint16_t), \
STR_SIZE(FULL, uint16_t), \
@@ -129,7 +135,7 @@ static const StaticDiagInfoRec StaticDiagInfo[] = {
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#undef DIAG
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};
static const unsigned StaticDiagInfoSize =
@@ -166,7 +172,8 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
#endif
// Search the diagnostic table with a binary search.
- StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0 };
+ StaticDiagInfoRec Find = { static_cast<unsigned short>(DiagID),
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
const StaticDiagInfoRec *Found =
std::lower_bound(StaticDiagInfo, StaticDiagInfo + StaticDiagInfoSize, Find);
@@ -177,19 +184,36 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
return Found;
}
-static unsigned GetDefaultDiagMapping(unsigned DiagID) {
- if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->Mapping;
- return diag::MAP_FATAL;
+static DiagnosticMappingInfo GetDefaultDiagMappingInfo(unsigned DiagID) {
+ DiagnosticMappingInfo Info = DiagnosticMappingInfo::Make(
+ diag::MAP_FATAL, /*IsUser=*/false, /*IsPragma=*/false);
+
+ if (const StaticDiagInfoRec *StaticInfo = GetDiagInfo(DiagID)) {
+ Info.setMapping((diag::Mapping) StaticInfo->Mapping);
+
+ if (StaticInfo->WarnNoWerror) {
+ assert(Info.getMapping() == diag::MAP_WARNING &&
+ "Unexpected mapping with no-Werror bit!");
+ Info.setNoWarningAsError(true);
+ }
+
+ if (StaticInfo->WarnShowInSystemHeader) {
+ assert(Info.getMapping() == diag::MAP_WARNING &&
+ "Unexpected mapping with show-in-system-header bit!");
+ Info.setShowInSystemHeader(true);
+ }
+ }
+
+ return Info;
}
/// getWarningOptionForDiag - Return the lowest-level warning option that
/// enables the specified diagnostic. If there is no -Wfoo flag that controls
/// the diagnostic, this returns null.
-llvm::StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
+StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
return Info->getOptionGroup();
- return llvm::StringRef();
+ return StringRef();
}
/// getCategoryNumberForDiag - Return the category number that a specified
@@ -206,12 +230,28 @@ namespace {
const char *NameStr;
uint8_t NameLen;
- llvm::StringRef getName() const {
- return llvm::StringRef(NameStr, NameLen);
+ StringRef getName() const {
+ return StringRef(NameStr, NameLen);
}
};
}
+// Unfortunately, the split between DiagnosticIDs and Diagnostic is not
+// particularly clean, but for now we just implement this method here so we can
+// access GetDefaultDiagMapping.
+DiagnosticMappingInfo &DiagnosticsEngine::DiagState::getOrAddMappingInfo(
+ diag::kind Diag)
+{
+ std::pair<iterator, bool> Result = DiagMap.insert(
+ std::make_pair(Diag, DiagnosticMappingInfo()));
+
+ // Initialize the entry if we added it.
+ if (Result.second)
+ Result.first->second = GetDefaultDiagMappingInfo(Diag);
+
+ return Result.first->second;
+}
+
static const StaticDiagCategoryRec CategoryNameTable[] = {
#define GET_CATEGORY_TABLE
#define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) },
@@ -228,9 +268,9 @@ unsigned DiagnosticIDs::getNumberOfCategories() {
/// getCategoryNameFromID - Given a category ID, return the name of the
/// category, an empty string if CategoryID is zero, or null if CategoryID is
/// invalid.
-llvm::StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
+StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
if (CategoryID >= getNumberOfCategories())
- return llvm::StringRef();
+ return StringRef();
return CategoryNameTable[CategoryID].getName();
}
@@ -256,20 +296,23 @@ DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) {
}
/// getName - Given a diagnostic ID, return its name
-llvm::StringRef DiagnosticIDs::getName(unsigned DiagID) {
+StringRef DiagnosticIDs::getName(unsigned DiagID) {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
return Info->getName();
- return llvm::StringRef();
+ return StringRef();
}
/// getIdFromName - Given a diagnostic name, return its ID, or 0
-unsigned DiagnosticIDs::getIdFromName(llvm::StringRef Name) {
+unsigned DiagnosticIDs::getIdFromName(StringRef Name) {
const StaticDiagNameIndexRec *StaticDiagNameIndexEnd =
StaticDiagNameIndex + StaticDiagNameIndexSize;
if (Name.empty()) { return diag::DIAG_UPPER_LIMIT; }
- StaticDiagNameIndexRec Find = { Name.data(), 0, Name.size() };
+ assert(Name.size() == static_cast<uint8_t>(Name.size()) &&
+ "Name is too long");
+ StaticDiagNameIndexRec Find = { Name.data(), 0,
+ static_cast<uint8_t>(Name.size()) };
const StaticDiagNameIndexRec *Found =
std::lower_bound( StaticDiagNameIndex, StaticDiagNameIndexEnd, Find);
@@ -282,18 +325,18 @@ unsigned DiagnosticIDs::getIdFromName(llvm::StringRef Name) {
/// getBriefExplanation - Given a diagnostic ID, return a brief explanation
/// of the issue
-llvm::StringRef DiagnosticIDs::getBriefExplanation(unsigned DiagID) {
+StringRef DiagnosticIDs::getBriefExplanation(unsigned DiagID) {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
return Info->getBriefExplanation();
- return llvm::StringRef();
+ return StringRef();
}
/// getFullExplanation - Given a diagnostic ID, return a full explanation
/// of the issue
-llvm::StringRef DiagnosticIDs::getFullExplanation(unsigned DiagID) {
+StringRef DiagnosticIDs::getFullExplanation(unsigned DiagID) {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
return Info->getFullExplanation();
- return llvm::StringRef();
+ return StringRef();
}
/// getBuiltinDiagClass - Return the class field of the diagnostic.
@@ -305,6 +348,35 @@ static unsigned getBuiltinDiagClass(unsigned DiagID) {
}
//===----------------------------------------------------------------------===//
+// diag_iterator
+//===----------------------------------------------------------------------===//
+
+llvm::StringRef DiagnosticIDs::diag_iterator::getDiagName() const {
+ return static_cast<const StaticDiagNameIndexRec*>(impl)->getName();
+}
+
+unsigned DiagnosticIDs::diag_iterator::getDiagID() const {
+ return static_cast<const StaticDiagNameIndexRec*>(impl)->DiagID;
+}
+
+DiagnosticIDs::diag_iterator &DiagnosticIDs::diag_iterator::operator++() {
+ const StaticDiagNameIndexRec* ptr =
+ static_cast<const StaticDiagNameIndexRec*>(impl);;
+ ++ptr;
+ impl = ptr;
+ return *this;
+}
+
+DiagnosticIDs::diag_iterator DiagnosticIDs::diags_begin() {
+ return DiagnosticIDs::diag_iterator(StaticDiagNameIndex);
+}
+
+DiagnosticIDs::diag_iterator DiagnosticIDs::diags_end() {
+ return DiagnosticIDs::diag_iterator(StaticDiagNameIndex +
+ StaticDiagNameIndexSize);
+}
+
+//===----------------------------------------------------------------------===//
// Custom Diagnostic information
//===----------------------------------------------------------------------===//
@@ -318,7 +390,7 @@ namespace clang {
/// getDescription - Return the description of the specified custom
/// diagnostic.
- llvm::StringRef getDescription(unsigned DiagID) const {
+ StringRef getDescription(unsigned DiagID) const {
assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
"Invalid diagnosic ID");
return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second;
@@ -331,7 +403,7 @@ namespace clang {
return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
}
- unsigned getOrCreateDiagID(DiagnosticIDs::Level L, llvm::StringRef Message,
+ unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message,
DiagnosticIDs &Diags) {
DiagDesc D(L, Message);
// Check to see if it already exists.
@@ -366,7 +438,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
/// registered and created, otherwise the existing ID is returned.
-unsigned DiagnosticIDs::getCustomDiagID(Level L, llvm::StringRef Message) {
+unsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef Message) {
if (CustomDiagInfo == 0)
CustomDiagInfo = new diag::CustomDiagInfo();
return CustomDiagInfo->getOrCreateDiagID(L, Message, *this);
@@ -400,32 +472,39 @@ bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,
getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
return false;
- EnabledByDefault = GetDefaultDiagMapping(DiagID) != diag::MAP_IGNORE;
+ EnabledByDefault =
+ GetDefaultDiagMappingInfo(DiagID).getMapping() != diag::MAP_IGNORE;
return true;
}
+bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) {
+ if (DiagID >= diag::DIAG_UPPER_LIMIT)
+ return false;
+
+ return GetDefaultDiagMappingInfo(DiagID).getMapping() == diag::MAP_ERROR;
+}
+
/// getDescription - Given a diagnostic ID, return a description of the
/// issue.
-llvm::StringRef DiagnosticIDs::getDescription(unsigned DiagID) const {
+StringRef DiagnosticIDs::getDescription(unsigned DiagID) const {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
return Info->getDescription();
return CustomDiagInfo->getDescription(DiagID);
}
-/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
-/// object, classify the specified diagnostic ID into a Level, consumable by
-/// the DiagnosticClient.
+/// getDiagnosticLevel - Based on the way the client configured the
+/// DiagnosticsEngine object, classify the specified diagnostic ID into a Level,
+/// by consumable the DiagnosticClient.
DiagnosticIDs::Level
DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
- const Diagnostic &Diag,
- diag::Mapping *mapping) const {
+ const DiagnosticsEngine &Diag) const {
// Handle custom diagnostics, which cannot be mapped.
if (DiagID >= diag::DIAG_UPPER_LIMIT)
return CustomDiagInfo->getLevel(DiagID);
unsigned DiagClass = getBuiltinDiagClass(DiagID);
assert(DiagClass != CLASS_NOTE && "Cannot get diagnostic level of a note!");
- return getDiagnosticLevel(DiagID, DiagClass, Loc, Diag, mapping);
+ return getDiagnosticLevel(DiagID, DiagClass, Loc, Diag);
}
/// \brief Based on the way the client configured the Diagnostic
@@ -437,130 +516,119 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
DiagnosticIDs::Level
DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
SourceLocation Loc,
- const Diagnostic &Diag,
- diag::Mapping *mapping) const {
+ const DiagnosticsEngine &Diag) const {
// Specific non-error diagnostics may be mapped to various levels from ignored
// to error. Errors can only be mapped to fatal.
DiagnosticIDs::Level Result = DiagnosticIDs::Fatal;
- Diagnostic::DiagStatePointsTy::iterator
+ DiagnosticsEngine::DiagStatePointsTy::iterator
Pos = Diag.GetDiagStatePointForLoc(Loc);
- Diagnostic::DiagState *State = Pos->State;
-
- // Get the mapping information, if unset, compute it lazily.
- unsigned MappingInfo = Diag.getDiagnosticMappingInfo((diag::kind)DiagID,
- State);
- if (MappingInfo == 0) {
- MappingInfo = GetDefaultDiagMapping(DiagID);
- Diag.setDiagnosticMappingInternal(DiagID, MappingInfo, State, false, false);
- }
-
- if (mapping)
- *mapping = (diag::Mapping) (MappingInfo & 7);
+ DiagnosticsEngine::DiagState *State = Pos->State;
- bool ShouldEmitInSystemHeader = false;
+ // Get the mapping information, or compute it lazily.
+ DiagnosticMappingInfo &MappingInfo = State->getOrAddMappingInfo(
+ (diag::kind)DiagID);
- switch (MappingInfo & 7) {
- default: assert(0 && "Unknown mapping!");
+ switch (MappingInfo.getMapping()) {
+ default: llvm_unreachable("Unknown mapping!");
case diag::MAP_IGNORE:
- // Ignore this, unless this is an extension diagnostic and we're mapping
- // them onto warnings or errors.
- if (!isBuiltinExtensionDiag(DiagID) || // Not an extension
- Diag.ExtBehavior == Diagnostic::Ext_Ignore || // Ext ignored
- (MappingInfo & 8) != 0) // User explicitly mapped it.
- return DiagnosticIDs::Ignored;
+ Result = DiagnosticIDs::Ignored;
+ break;
+ case diag::MAP_WARNING:
Result = DiagnosticIDs::Warning;
- if (Diag.ExtBehavior == Diagnostic::Ext_Error) Result = DiagnosticIDs::Error;
- if (Result == DiagnosticIDs::Error && Diag.ErrorsAsFatal)
- Result = DiagnosticIDs::Fatal;
break;
case diag::MAP_ERROR:
Result = DiagnosticIDs::Error;
- if (Diag.ErrorsAsFatal)
- Result = DiagnosticIDs::Fatal;
break;
case diag::MAP_FATAL:
Result = DiagnosticIDs::Fatal;
break;
- case diag::MAP_WARNING_SHOW_IN_SYSTEM_HEADER:
- ShouldEmitInSystemHeader = true;
- // continue as MAP_WARNING.
- case diag::MAP_WARNING:
- // If warnings are globally mapped to ignore or error, do it.
- if (Diag.IgnoreAllWarnings)
- return DiagnosticIDs::Ignored;
+ }
+ // Upgrade ignored diagnostics if -Weverything is enabled.
+ if (Diag.EnableAllWarnings && Result == DiagnosticIDs::Ignored &&
+ !MappingInfo.isUser())
Result = DiagnosticIDs::Warning;
- // If this is an extension diagnostic and we're in -pedantic-error mode, and
- // if the user didn't explicitly map it, upgrade to an error.
- if (Diag.ExtBehavior == Diagnostic::Ext_Error &&
- (MappingInfo & 8) == 0 &&
- isBuiltinExtensionDiag(DiagID))
- Result = DiagnosticIDs::Error;
-
- if (Diag.WarningsAsErrors)
- Result = DiagnosticIDs::Error;
- if (Result == DiagnosticIDs::Error && Diag.ErrorsAsFatal)
- Result = DiagnosticIDs::Fatal;
- break;
+ // Ignore -pedantic diagnostics inside __extension__ blocks.
+ // (The diagnostics controlled by -pedantic are the extension diagnostics
+ // that are not enabled by default.)
+ bool EnabledByDefault;
+ bool IsExtensionDiag = isBuiltinExtensionDiag(DiagID, EnabledByDefault);
+ if (Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault)
+ return DiagnosticIDs::Ignored;
- case diag::MAP_WARNING_NO_WERROR:
- // Diagnostics specified with -Wno-error=foo should be set to warnings, but
- // not be adjusted by -Werror or -pedantic-errors.
- Result = DiagnosticIDs::Warning;
+ // For extension diagnostics that haven't been explicitly mapped, check if we
+ // should upgrade the diagnostic.
+ if (IsExtensionDiag && !MappingInfo.isUser()) {
+ switch (Diag.ExtBehavior) {
+ case DiagnosticsEngine::Ext_Ignore:
+ break;
+ case DiagnosticsEngine::Ext_Warn:
+ // Upgrade ignored diagnostics to warnings.
+ if (Result == DiagnosticIDs::Ignored)
+ Result = DiagnosticIDs::Warning;
+ break;
+ case DiagnosticsEngine::Ext_Error:
+ // Upgrade ignored or warning diagnostics to errors.
+ if (Result == DiagnosticIDs::Ignored || Result == DiagnosticIDs::Warning)
+ Result = DiagnosticIDs::Error;
+ break;
+ }
+ }
- // If warnings are globally mapped to ignore or error, do it.
- if (Diag.IgnoreAllWarnings)
- return DiagnosticIDs::Ignored;
+ // At this point, ignored errors can no longer be upgraded.
+ if (Result == DiagnosticIDs::Ignored)
+ return Result;
- break;
+ // Honor -w, which is lower in priority than pedantic-errors, but higher than
+ // -Werror.
+ if (Result == DiagnosticIDs::Warning && Diag.IgnoreAllWarnings)
+ return DiagnosticIDs::Ignored;
- case diag::MAP_ERROR_NO_WFATAL:
- // Diagnostics specified as -Wno-fatal-error=foo should be errors, but
- // unaffected by -Wfatal-errors.
- Result = DiagnosticIDs::Error;
- break;
+ // If -Werror is enabled, map warnings to errors unless explicitly disabled.
+ if (Result == DiagnosticIDs::Warning) {
+ if (Diag.WarningsAsErrors && !MappingInfo.hasNoWarningAsError())
+ Result = DiagnosticIDs::Error;
}
- // Okay, we're about to return this as a "diagnostic to emit" one last check:
- // if this is any sort of extension warning, and if we're in an __extension__
- // block, silence it.
- if (Diag.AllExtensionsSilenced && isBuiltinExtensionDiag(DiagID))
- return DiagnosticIDs::Ignored;
+ // If -Wfatal-errors is enabled, map errors to fatal unless explicity
+ // disabled.
+ if (Result == DiagnosticIDs::Error) {
+ if (Diag.ErrorsAsFatal && !MappingInfo.hasNoErrorAsFatal())
+ Result = DiagnosticIDs::Fatal;
+ }
- // If we are in a system header, we ignore it.
- // We also want to ignore extensions and warnings in -Werror and
+ // If we are in a system header, we ignore it. We look at the diagnostic class
+ // because we also want to ignore extensions and warnings in -Werror and
// -pedantic-errors modes, which *map* warnings/extensions to errors.
if (Result >= DiagnosticIDs::Warning &&
DiagClass != CLASS_ERROR &&
// Custom diagnostics always are emitted in system headers.
DiagID < diag::DIAG_UPPER_LIMIT &&
- !ShouldEmitInSystemHeader &&
+ !MappingInfo.hasShowInSystemHeader() &&
Diag.SuppressSystemWarnings &&
Loc.isValid() &&
Diag.getSourceManager().isInSystemHeader(
- Diag.getSourceManager().getInstantiationLoc(Loc)))
+ Diag.getSourceManager().getExpansionLoc(Loc)))
return DiagnosticIDs::Ignored;
return Result;
}
-namespace {
- struct WarningOption {
- // Be safe with the size of 'NameLen' because we don't statically check if
- // the size will fit in the field; the struct size won't decrease with a
- // shorter type anyway.
- size_t NameLen;
- const char *NameStr;
- const short *Members;
- const short *SubGroups;
+struct clang::WarningOption {
+ // Be safe with the size of 'NameLen' because we don't statically check if
+ // the size will fit in the field; the struct size won't decrease with a
+ // shorter type anyway.
+ size_t NameLen;
+ const char *NameStr;
+ const short *Members;
+ const short *SubGroups;
- llvm::StringRef getName() const {
- return llvm::StringRef(NameStr, NameLen);
- }
- };
-}
+ StringRef getName() const {
+ return StringRef(NameStr, NameLen);
+ }
+};
#define GET_DIAG_ARRAYS
#include "clang/Basic/DiagnosticGroups.inc"
@@ -580,54 +648,43 @@ static bool WarningOptionCompare(const WarningOption &LHS,
return LHS.getName() < RHS.getName();
}
-static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping,
- SourceLocation Loc, Diagnostic &Diag) {
- // Option exists, poke all the members of its diagnostic set.
+void DiagnosticIDs::getDiagnosticsInGroup(
+ const WarningOption *Group,
+ llvm::SmallVectorImpl<diag::kind> &Diags) const
+{
+ // Add the members of the option diagnostic set.
if (const short *Member = Group->Members) {
for (; *Member != -1; ++Member)
- Diag.setDiagnosticMapping(*Member, Mapping, Loc);
+ Diags.push_back(*Member);
}
- // Enable/disable all subgroups along with this one.
+ // Add the members of the subgroups.
if (const short *SubGroups = Group->SubGroups) {
for (; *SubGroups != (short)-1; ++SubGroups)
- MapGroupMembers(&OptionTable[(short)*SubGroups], Mapping, Loc, Diag);
+ getDiagnosticsInGroup(&OptionTable[(short)*SubGroups], Diags);
}
}
-/// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g.
-/// "unknown-pragmas" to have the specified mapping. This returns true and
-/// ignores the request if "Group" was unknown, false otherwise.
-bool DiagnosticIDs::setDiagnosticGroupMapping(llvm::StringRef Group,
- diag::Mapping Map,
- SourceLocation Loc,
- Diagnostic &Diag) const {
- assert((Loc.isValid() ||
- Diag.DiagStatePoints.empty() ||
- Diag.DiagStatePoints.back().Loc.isInvalid()) &&
- "Loc should be invalid only when the mapping comes from command-line");
- assert((Loc.isInvalid() || Diag.DiagStatePoints.empty() ||
- Diag.DiagStatePoints.back().Loc.isInvalid() ||
- !Diag.SourceMgr->isBeforeInTranslationUnit(Loc,
- Diag.DiagStatePoints.back().Loc)) &&
- "Source location of new mapping is before the previous one!");
-
+bool DiagnosticIDs::getDiagnosticsInGroup(
+ StringRef Group,
+ llvm::SmallVectorImpl<diag::kind> &Diags) const
+{
WarningOption Key = { Group.size(), Group.data(), 0, 0 };
const WarningOption *Found =
std::lower_bound(OptionTable, OptionTable + OptionTableSize, Key,
WarningOptionCompare);
if (Found == OptionTable + OptionTableSize ||
Found->getName() != Group)
- return true; // Option not found.
+ return true; // Option not found.
- MapGroupMembers(Found, Map, Loc, Diag);
+ getDiagnosticsInGroup(Found, Diags);
return false;
}
/// ProcessDiag - This is the method used to report a diagnostic that is
/// finally fully formed.
-bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const {
- DiagnosticInfo Info(&Diag);
+bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
+ Diagnostic Info(&Diag);
if (Diag.SuppressAllDiagnostics)
return false;
@@ -665,6 +722,13 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const {
Diag.LastDiagLevel = DiagLevel;
}
+ // Update counts for DiagnosticErrorTrap even if a fatal error occurred.
+ if (DiagLevel >= DiagnosticIDs::Error) {
+ ++Diag.TrapNumErrorsOccurred;
+ if (isUnrecoverable(DiagID))
+ ++Diag.TrapNumUnrecoverableErrorsOccurred;
+ }
+
// If a fatal error has already been emitted, silence all subsequent
// diagnostics.
if (Diag.FatalErrorOccurred) {
@@ -685,27 +749,26 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const {
return false;
if (DiagLevel >= DiagnosticIDs::Error) {
- Diag.TrapErrorOccurred = true;
- if (isUnrecoverable(DiagID)) {
- Diag.TrapUnrecoverableErrorOccurred = true;
+ if (isUnrecoverable(DiagID))
Diag.UnrecoverableErrorOccurred = true;
- }
if (Diag.Client->IncludeInDiagnosticCounts()) {
Diag.ErrorOccurred = true;
++Diag.NumErrors;
}
- // If we've emitted a lot of errors, emit a fatal error after it to stop a
- // flood of bogus errors.
- if (Diag.ErrorLimit && Diag.NumErrors >= Diag.ErrorLimit &&
- DiagLevel == DiagnosticIDs::Error)
+ // If we've emitted a lot of errors, emit a fatal error instead of it to
+ // stop a flood of bogus errors.
+ if (Diag.ErrorLimit && Diag.NumErrors > Diag.ErrorLimit &&
+ DiagLevel == DiagnosticIDs::Error) {
Diag.SetDelayedDiagnostic(diag::fatal_too_many_errors);
+ return false;
+ }
}
// If we have any Fix-Its, make sure that all of the Fix-Its point into
- // source locations that aren't macro instantiations. If any point into
- // macro instantiations, remove all of the Fix-Its.
+ // source locations that aren't macro expansions. If any point into macro
+ // expansions, remove all of the Fix-Its.
for (unsigned I = 0, N = Diag.NumFixItHints; I != N; ++I) {
const FixItHint &FixIt = Diag.FixItHints[I];
if (FixIt.RemoveRange.isInvalid() ||
@@ -717,7 +780,7 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const {
}
// Finally, report it.
- Diag.Client->HandleDiagnostic((Diagnostic::Level)DiagLevel, Info);
+ Diag.Client->HandleDiagnostic((DiagnosticsEngine::Level)DiagLevel, Info);
if (Diag.Client->IncludeInDiagnosticCounts()) {
if (DiagLevel == DiagnosticIDs::Warning)
++Diag.NumWarnings;
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index f747c534c0ed..c1f715ed0592 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -217,25 +217,26 @@ void FileManager::removeStatCache(FileSystemStatCache *statCache) {
/// \brief Retrieve the directory that the given file name resides in.
/// Filename can point to either a real file or a virtual file.
static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
- llvm::StringRef Filename) {
+ StringRef Filename,
+ bool CacheFailure) {
if (Filename.empty())
return NULL;
if (llvm::sys::path::is_separator(Filename[Filename.size() - 1]))
return NULL; // If Filename is a directory.
- llvm::StringRef DirName = llvm::sys::path::parent_path(Filename);
+ StringRef DirName = llvm::sys::path::parent_path(Filename);
// Use the current directory if file has no path component.
if (DirName.empty())
DirName = ".";
- return FileMgr.getDirectory(DirName);
+ return FileMgr.getDirectory(DirName, CacheFailure);
}
/// Add all ancestors of the given path (pointing to either a file or
/// a directory) as virtual directories.
-void FileManager::addAncestorsAsVirtualDirs(llvm::StringRef Path) {
- llvm::StringRef DirName = llvm::sys::path::parent_path(Path);
+void FileManager::addAncestorsAsVirtualDirs(StringRef Path) {
+ StringRef DirName = llvm::sys::path::parent_path(Path);
if (DirName.empty())
return;
@@ -263,7 +264,8 @@ void FileManager::addAncestorsAsVirtualDirs(llvm::StringRef Path) {
/// (real or virtual). This returns NULL if the directory doesn't
/// exist.
///
-const DirectoryEntry *FileManager::getDirectory(llvm::StringRef DirName) {
+const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
+ bool CacheFailure) {
++NumDirLookups;
llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
SeenDirEntries.GetOrCreateValue(DirName);
@@ -287,6 +289,8 @@ const DirectoryEntry *FileManager::getDirectory(llvm::StringRef DirName) {
struct stat StatBuf;
if (getStatValue(InterndDirName, StatBuf, 0/*directory lookup*/)) {
// There's no real directory at the given path.
+ if (!CacheFailure)
+ SeenDirEntries.erase(DirName);
return 0;
}
@@ -309,7 +313,8 @@ const DirectoryEntry *FileManager::getDirectory(llvm::StringRef DirName) {
/// getFile - Lookup, cache, and verify the specified file (real or
/// virtual). This returns NULL if the file doesn't exist.
///
-const FileEntry *FileManager::getFile(llvm::StringRef Filename, bool openFile) {
+const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
+ bool CacheFailure) {
++NumFileLookups;
// See if there is already an entry in the map.
@@ -335,10 +340,15 @@ const FileEntry *FileManager::getFile(llvm::StringRef Filename, bool openFile) {
// subdirectory. This will let us avoid having to waste time on known-to-fail
// searches when we go to find sys/bar.h, because all the search directories
// without a 'sys' subdir will get a cached failure result.
- const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename);
- if (DirInfo == 0) // Directory doesn't exist, file can't exist.
+ const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename,
+ CacheFailure);
+ if (DirInfo == 0) { // Directory doesn't exist, file can't exist.
+ if (!CacheFailure)
+ SeenFileEntries.erase(Filename);
+
return 0;
-
+ }
+
// FIXME: Use the directory info to prune this, before doing the stat syscall.
// FIXME: This will reduce the # syscalls.
@@ -347,6 +357,9 @@ const FileEntry *FileManager::getFile(llvm::StringRef Filename, bool openFile) {
struct stat StatBuf;
if (getStatValue(InterndFileName, StatBuf, &FileDescriptor)) {
// There's no real file at the given path.
+ if (!CacheFailure)
+ SeenFileEntries.erase(Filename);
+
return 0;
}
@@ -381,7 +394,7 @@ const FileEntry *FileManager::getFile(llvm::StringRef Filename, bool openFile) {
}
const FileEntry *
-FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
+FileManager::getVirtualFile(StringRef Filename, off_t Size,
time_t ModificationTime) {
++NumFileLookups;
@@ -404,7 +417,8 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
// Now that all ancestors of Filename are in the cache, the
// following call is guaranteed to find the DirectoryEntry from the
// cache.
- const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename);
+ const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename,
+ /*CacheFailure=*/true);
assert(DirInfo &&
"The directory of a virtual file should already be in the cache.");
@@ -451,8 +465,8 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
return UFE;
}
-void FileManager::FixupRelativePath(llvm::SmallVectorImpl<char> &path) const {
- llvm::StringRef pathRef(path.data(), path.size());
+void FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const {
+ StringRef pathRef(path.data(), path.size());
if (FileSystemOpts.WorkingDir.empty()
|| llvm::sys::path::is_absolute(pathRef))
@@ -499,7 +513,7 @@ getBufferForFile(const FileEntry *Entry, std::string *ErrorStr) {
}
llvm::MemoryBuffer *FileManager::
-getBufferForFile(llvm::StringRef Filename, std::string *ErrorStr) {
+getBufferForFile(StringRef Filename, std::string *ErrorStr) {
llvm::OwningPtr<llvm::MemoryBuffer> Result;
llvm::error_code ec;
if (FileSystemOpts.WorkingDir.empty()) {
@@ -537,7 +551,7 @@ bool FileManager::getStatValue(const char *Path, struct stat &StatBuf,
StatCache.get());
}
-bool FileManager::getNoncachedStatValue(llvm::StringRef Path,
+bool FileManager::getNoncachedStatValue(StringRef Path,
struct stat &StatBuf) {
llvm::SmallString<128> FilePath(Path);
FixupRelativePath(FilePath);
@@ -546,7 +560,7 @@ bool FileManager::getNoncachedStatValue(llvm::StringRef Path,
}
void FileManager::GetUniqueIDMapping(
- llvm::SmallVectorImpl<const FileEntry *> &UIDToFiles) const {
+ SmallVectorImpl<const FileEntry *> &UIDToFiles) const {
UIDToFiles.clear();
UIDToFiles.resize(NextFileUID);
@@ -558,7 +572,7 @@ void FileManager::GetUniqueIDMapping(
UIDToFiles[FE->getValue()->getUID()] = FE->getValue();
// Map virtual file entries
- for (llvm::SmallVector<FileEntry*, 4>::const_iterator
+ for (SmallVector<FileEntry*, 4>::const_iterator
VFE = VirtualFileEntries.begin(), VFEEnd = VirtualFileEntries.end();
VFE != VFEEnd; ++VFE)
if (*VFE && *VFE != NON_EXISTENT_FILE)
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 188e2d46f587..38f09a08af3c 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -32,6 +32,7 @@ IdentifierInfo::IdentifierInfo() {
ObjCOrBuiltinID = 0;
HasMacro = false;
IsExtension = false;
+ IsCXX11CompatKeyword = false;
IsPoisoned = false;
IsCPPOperatorKeyword = false;
NeedsHandleIdentifier = false;
@@ -55,7 +56,7 @@ namespace {
class EmptyLookupIterator : public IdentifierIterator
{
public:
- virtual llvm::StringRef Next() { return llvm::StringRef(); }
+ virtual StringRef Next() { return StringRef(); }
};
}
@@ -102,11 +103,11 @@ namespace {
/// identifiers because they are language keywords. This causes the lexer to
/// automatically map matching identifiers to specialized token codes.
///
-/// The C90/C99/CPP/CPP0x flags are set to 2 if the token should be
-/// enabled in the specified langauge, set to 1 if it is an extension
-/// in the specified language, and set to 0 if disabled in the
-/// specified language.
-static void AddKeyword(llvm::StringRef Keyword,
+/// The C90/C99/CPP/CPP0x flags are set to 3 if the token is a keyword in a
+/// future language standard, set to 2 if the token should be enabled in the
+/// specified langauge, set to 1 if it is an extension in the specified
+/// language, and set to 0 if disabled in the specified language.
+static void AddKeyword(StringRef Keyword,
tok::TokenKind TokenCode, unsigned Flags,
const LangOptions &LangOpts, IdentifierTable &Table) {
unsigned AddResult = 0;
@@ -115,7 +116,7 @@ static void AddKeyword(llvm::StringRef Keyword,
else if (LangOpts.CPlusPlus0x && (Flags & KEYCXX0X)) AddResult = 2;
else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2;
else if (LangOpts.GNUKeywords && (Flags & KEYGNU)) AddResult = 1;
- else if (LangOpts.Microsoft && (Flags & KEYMS)) AddResult = 1;
+ else if (LangOpts.MicrosoftExt && (Flags & KEYMS)) AddResult = 1;
else if (LangOpts.Borland && (Flags & KEYBORLAND)) AddResult = 1;
else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2;
else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2;
@@ -123,17 +124,20 @@ static void AddKeyword(llvm::StringRef Keyword,
else if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) AddResult = 2;
else if (LangOpts.C1X && (Flags & KEYC1X)) AddResult = 2;
else if (LangOpts.ObjCAutoRefCount && (Flags & KEYARC)) AddResult = 2;
-
+ else if (LangOpts.CPlusPlus && (Flags & KEYCXX0X)) AddResult = 3;
+
// Don't add this keyword if disabled in this language.
if (AddResult == 0) return;
- IdentifierInfo &Info = Table.get(Keyword, TokenCode);
+ IdentifierInfo &Info =
+ Table.get(Keyword, AddResult == 3 ? tok::identifier : TokenCode);
Info.setIsExtensionToken(AddResult == 1);
+ Info.setIsCXX11CompatKeyword(AddResult == 3);
}
/// AddCXXOperatorKeyword - Register a C++ operator keyword alternative
/// representations.
-static void AddCXXOperatorKeyword(llvm::StringRef Keyword,
+static void AddCXXOperatorKeyword(StringRef Keyword,
tok::TokenKind TokenCode,
IdentifierTable &Table) {
IdentifierInfo &Info = Table.get(Keyword, TokenCode);
@@ -142,7 +146,7 @@ static void AddCXXOperatorKeyword(llvm::StringRef Keyword,
/// AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or
/// "property".
-static void AddObjCKeyword(llvm::StringRef Name,
+static void AddObjCKeyword(StringRef Name,
tok::ObjCKeywordKind ObjCID,
IdentifierTable &Table) {
Table.get(Name).setObjCKeywordID(ObjCID);
@@ -153,20 +157,20 @@ static void AddObjCKeyword(llvm::StringRef Name,
void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
// Add keywords and tokens for the current language.
#define KEYWORD(NAME, FLAGS) \
- AddKeyword(llvm::StringRef(#NAME), tok::kw_ ## NAME, \
+ AddKeyword(StringRef(#NAME), tok::kw_ ## NAME, \
FLAGS, LangOpts, *this);
#define ALIAS(NAME, TOK, FLAGS) \
- AddKeyword(llvm::StringRef(NAME), tok::kw_ ## TOK, \
+ AddKeyword(StringRef(NAME), tok::kw_ ## TOK, \
FLAGS, LangOpts, *this);
#define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \
if (LangOpts.CXXOperatorNames) \
- AddCXXOperatorKeyword(llvm::StringRef(#NAME), tok::ALIAS, *this);
+ AddCXXOperatorKeyword(StringRef(#NAME), tok::ALIAS, *this);
#define OBJC1_AT_KEYWORD(NAME) \
if (LangOpts.ObjC1) \
- AddObjCKeyword(llvm::StringRef(#NAME), tok::objc_##NAME, *this);
+ AddObjCKeyword(StringRef(#NAME), tok::objc_##NAME, *this);
#define OBJC2_AT_KEYWORD(NAME) \
if (LangOpts.ObjC2) \
- AddObjCKeyword(llvm::StringRef(#NAME), tok::objc_##NAME, *this);
+ AddObjCKeyword(StringRef(#NAME), tok::objc_##NAME, *this);
#define TESTING_KEYWORD(NAME, FLAGS)
#include "clang/Basic/TokenKinds.def"
@@ -217,6 +221,7 @@ tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
CASE(12, 'i', 'c', include_next);
CASE(16, '_', 'i', __include_macros);
+ CASE(16, '_', 'e', __export_macro__);
#undef CASE
#undef HASH
}
@@ -336,9 +341,9 @@ IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const {
return SI->getIdentifierInfoForSlot(argIndex);
}
-llvm::StringRef Selector::getNameForSlot(unsigned int argIndex) const {
+StringRef Selector::getNameForSlot(unsigned int argIndex) const {
IdentifierInfo *II = getIdentifierInfoForSlot(argIndex);
- return II? II->getName() : llvm::StringRef();
+ return II? II->getName() : StringRef();
}
std::string MultiKeywordSelector::getName() const {
@@ -377,7 +382,7 @@ std::string Selector::getAsString() const {
/// Interpreting the given string using the normal CamelCase
/// conventions, determine whether the given string starts with the
/// given "word", which is assumed to end in a lowercase letter.
-static bool startsWithWord(llvm::StringRef name, llvm::StringRef word) {
+static bool startsWithWord(StringRef name, StringRef word) {
if (name.size() < word.size()) return false;
return ((name.size() == word.size() ||
!islower(name[word.size()]))
@@ -388,10 +393,11 @@ ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
if (!first) return OMF_None;
- llvm::StringRef name = first->getName();
+ StringRef name = first->getName();
if (sel.isUnarySelector()) {
if (name == "autorelease") return OMF_autorelease;
if (name == "dealloc") return OMF_dealloc;
+ if (name == "finalize") return OMF_finalize;
if (name == "release") return OMF_release;
if (name == "retain") return OMF_retain;
if (name == "retainCount") return OMF_retainCount;
@@ -491,4 +497,3 @@ const char *clang::getOperatorSpelling(OverloadedOperatorKind Operator) {
return 0;
}
-
diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp
new file mode 100644
index 000000000000..5f479dbb771c
--- /dev/null
+++ b/lib/Basic/LangOptions.cpp
@@ -0,0 +1,30 @@
+//===--- LangOptions.cpp - C Language Family Language Options ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the LangOptions class.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Basic/LangOptions.h"
+
+using namespace clang;
+
+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"
+}
+
+void LangOptions::resetNonModularOptions() {
+#define LANGOPT(Name, Bits, Default, Description)
+#define BENIGN_LANGOPT(Name, Bits, Default, Description) Name = Default;
+#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ Name = Default;
+#include "clang/Basic/LangOptions.def"
+}
+
diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp
index 5062d43f58f2..6e4f3e6ad7a4 100644
--- a/lib/Basic/SourceLocation.cpp
+++ b/lib/Basic/SourceLocation.cpp
@@ -23,7 +23,7 @@ using namespace clang;
// PrettyStackTraceLoc
//===----------------------------------------------------------------------===//
-void PrettyStackTraceLoc::print(llvm::raw_ostream &OS) const {
+void PrettyStackTraceLoc::print(raw_ostream &OS) const {
if (Loc.isValid()) {
Loc.print(OS, SM);
OS << ": ";
@@ -35,7 +35,7 @@ void PrettyStackTraceLoc::print(llvm::raw_ostream &OS) const {
// SourceLocation
//===----------------------------------------------------------------------===//
-void SourceLocation::print(llvm::raw_ostream &OS, const SourceManager &SM)const{
+void SourceLocation::print(raw_ostream &OS, const SourceManager &SM)const{
if (!isValid()) {
OS << "<invalid loc>";
return;
@@ -48,13 +48,13 @@ void SourceLocation::print(llvm::raw_ostream &OS, const SourceManager &SM)const{
OS << "<invalid>";
return;
}
- // The instantiation and spelling pos is identical for file locs.
+ // The macro expansion and spelling pos is identical for file locs.
OS << PLoc.getFilename() << ':' << PLoc.getLine()
<< ':' << PLoc.getColumn();
return;
}
- SM.getInstantiationLoc(*this).print(OS, SM);
+ SM.getExpansionLoc(*this).print(OS, SM);
OS << " <Spelling=";
SM.getSpellingLoc(*this).print(OS, SM);
@@ -75,9 +75,9 @@ FileID FullSourceLoc::getFileID() const {
}
-FullSourceLoc FullSourceLoc::getInstantiationLoc() const {
+FullSourceLoc FullSourceLoc::getExpansionLoc() const {
assert(isValid());
- return FullSourceLoc(SrcMgr->getInstantiationLoc(*this), *SrcMgr);
+ return FullSourceLoc(SrcMgr->getExpansionLoc(*this), *SrcMgr);
}
FullSourceLoc FullSourceLoc::getSpellingLoc() const {
@@ -85,14 +85,14 @@ FullSourceLoc FullSourceLoc::getSpellingLoc() const {
return FullSourceLoc(SrcMgr->getSpellingLoc(*this), *SrcMgr);
}
-unsigned FullSourceLoc::getInstantiationLineNumber(bool *Invalid) const {
+unsigned FullSourceLoc::getExpansionLineNumber(bool *Invalid) const {
assert(isValid());
- return SrcMgr->getInstantiationLineNumber(*this, Invalid);
+ return SrcMgr->getExpansionLineNumber(*this, Invalid);
}
-unsigned FullSourceLoc::getInstantiationColumnNumber(bool *Invalid) const {
+unsigned FullSourceLoc::getExpansionColumnNumber(bool *Invalid) const {
assert(isValid());
- return SrcMgr->getInstantiationColumnNumber(*this, Invalid);
+ return SrcMgr->getExpansionColumnNumber(*this, Invalid);
}
unsigned FullSourceLoc::getSpellingLineNumber(bool *Invalid) const {
@@ -125,7 +125,7 @@ const llvm::MemoryBuffer* FullSourceLoc::getBuffer(bool *Invalid) const {
return SrcMgr->getBuffer(SrcMgr->getFileID(*this), Invalid);
}
-llvm::StringRef FullSourceLoc::getBufferData(bool *Invalid) const {
+StringRef FullSourceLoc::getBufferData(bool *Invalid) const {
return getBuffer(Invalid)->getBuffer();
}
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 45922c15527f..364663ee3265 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -17,10 +17,12 @@
#include "clang/Basic/FileManager.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.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 <algorithm>
#include <string>
#include <cstring>
@@ -39,9 +41,8 @@ ContentCache::~ContentCache() {
delete Buffer.getPointer();
}
-/// getSizeBytesMapped - Returns the number of bytes actually mapped for
-/// this ContentCache. This can be 0 if the MemBuffer was not actually
-/// instantiated.
+/// getSizeBytesMapped - Returns the number of bytes actually mapped for this
+/// ContentCache. This can be 0 if the MemBuffer was not actually expanded.
unsigned ContentCache::getSizeBytesMapped() const {
return Buffer.getPointer() ? Buffer.getPointer()->getBufferSize() : 0;
}
@@ -78,7 +79,7 @@ void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B,
Buffer.setInt(DoNotFree? DoNotFreeFlag : 0);
}
-const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
+const llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag,
const SourceManager &SM,
SourceLocation Loc,
bool *Invalid) const {
@@ -105,7 +106,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
// that we are in an inconsistent situation and error out as quickly as
// possible.
if (!Buffer.getPointer()) {
- const llvm::StringRef FillStr("<<<MISSING SOURCE FILE>>>\n");
+ const StringRef FillStr("<<<MISSING SOURCE FILE>>>\n");
Buffer.setPointer(MemoryBuffer::getNewMemBuffer(ContentsEntry->getSize(),
"<invalid>"));
char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart());
@@ -143,7 +144,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
// If the buffer is valid, check to see if it has a UTF Byte Order Mark
// (BOM). We only support UTF-8 with and without a BOM right now. See
// http://en.wikipedia.org/wiki/Byte_order_mark for more information.
- llvm::StringRef BufStr = Buffer.getPointer()->getBuffer();
+ StringRef BufStr = Buffer.getPointer()->getBuffer();
const char *InvalidBOM = llvm::StringSwitch<const char *>(BufStr)
.StartsWith("\xFE\xFF", "UTF-16 (BE)")
.StartsWith("\xFF\xFE", "UTF-16 (LE)")
@@ -169,7 +170,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
return Buffer.getPointer();
}
-unsigned LineTableInfo::getLineTableFilenameID(llvm::StringRef Name) {
+unsigned LineTableInfo::getLineTableFilenameID(StringRef Name) {
// Look up the filename in the string table, returning the pre-existing value
// if it exists.
llvm::StringMapEntry<unsigned> &Entry =
@@ -186,7 +187,7 @@ unsigned LineTableInfo::getLineTableFilenameID(llvm::StringRef Name) {
/// AddLineNote - Add a line note to the line table that indicates that there
/// is a #line at the specified FID/Offset location which changes the presumed
/// location to LineNo/FilenameID.
-void LineTableInfo::AddLineNote(unsigned FID, unsigned Offset,
+void LineTableInfo::AddLineNote(int FID, unsigned Offset,
unsigned LineNo, int FilenameID) {
std::vector<LineEntry> &Entries = LineEntries[FID];
@@ -217,7 +218,7 @@ void LineTableInfo::AddLineNote(unsigned FID, unsigned Offset,
/// presumed #include stack. If it is 1, this is a file entry, if it is 2 then
/// this is a file exit. FileKind specifies whether this is a system header or
/// extern C system header.
-void LineTableInfo::AddLineNote(unsigned FID, unsigned Offset,
+void LineTableInfo::AddLineNote(int FID, unsigned Offset,
unsigned LineNo, int FilenameID,
unsigned EntryExit,
SrcMgr::CharacteristicKind FileKind) {
@@ -251,7 +252,7 @@ void LineTableInfo::AddLineNote(unsigned FID, unsigned Offset,
/// FindNearestLineEntry - Find the line entry nearest to FID that is before
/// it. If there is no line entry before Offset in FID, return null.
-const LineEntry *LineTableInfo::FindNearestLineEntry(unsigned FID,
+const LineEntry *LineTableInfo::FindNearestLineEntry(int FID,
unsigned Offset) {
const std::vector<LineEntry> &Entries = LineEntries[FID];
assert(!Entries.empty() && "No #line entries for this FID after all!");
@@ -270,14 +271,14 @@ const LineEntry *LineTableInfo::FindNearestLineEntry(unsigned FID,
/// \brief Add a new line entry that has already been encoded into
/// the internal representation of the line table.
-void LineTableInfo::AddEntry(unsigned FID,
+void LineTableInfo::AddEntry(int FID,
const std::vector<LineEntry> &Entries) {
LineEntries[FID] = Entries;
}
/// getLineTableFilenameID - Return the uniqued ID for the specified filename.
///
-unsigned SourceManager::getLineTableFilenameID(llvm::StringRef Name) {
+unsigned SourceManager::getLineTableFilenameID(StringRef Name) {
if (LineTable == 0)
LineTable = new LineTableInfo();
return LineTable->getLineTableFilenameID(Name);
@@ -289,7 +290,7 @@ unsigned SourceManager::getLineTableFilenameID(llvm::StringRef Name) {
/// unspecified.
void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
int FilenameID) {
- std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
+ std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
bool Invalid = false;
const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
@@ -319,7 +320,7 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
return AddLineNote(Loc, LineNo, FilenameID);
}
- std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
+ std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
bool Invalid = false;
const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
@@ -362,7 +363,7 @@ LineTableInfo &SourceManager::getLineTable() {
// Private 'Create' methods.
//===----------------------------------------------------------------------===//
-SourceManager::SourceManager(Diagnostic &Diag, FileManager &FileMgr)
+SourceManager::SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr)
: Diag(Diag), FileMgr(FileMgr), OverridenFilesKeepOriginalName(true),
ExternalSLocEntries(0), LineTable(0), NumLinearScans(0),
NumBinaryProbes(0), FakeBufferForRecovery(0) {
@@ -387,11 +388,18 @@ SourceManager::~SourceManager() {
}
delete FakeBufferForRecovery;
+
+ for (llvm::DenseMap<FileID, MacroArgsMap *>::iterator
+ I = MacroArgsCacheMap.begin(),E = MacroArgsCacheMap.end(); I!=E; ++I) {
+ delete I->second;
+ }
}
void SourceManager::clearIDTables() {
MainFileID = FileID();
- SLocEntryTable.clear();
+ LocalSLocEntryTable.clear();
+ LoadedSLocEntryTable.clear();
+ SLocEntryLoaded.clear();
LastLineNoFileIDQuery = FileID();
LastLineNoContentCache = 0;
LastFileIDLookup = FileID();
@@ -399,9 +407,10 @@ void SourceManager::clearIDTables() {
if (LineTable)
LineTable->clear();
- // Use up FileID #0 as an invalid instantiation.
- NextOffset = 0;
- createInstantiationLoc(SourceLocation(),SourceLocation(),SourceLocation(), 1);
+ // Use up FileID #0 as an invalid expansion.
+ NextLocalOffset = 0;
+ CurrentLoadedOffset = MaxLoadedOffset;
+ createExpansionLoc(SourceLocation(),SourceLocation(),SourceLocation(), 1);
}
/// getOrCreateContentCache - Create or return a cached ContentCache for the
@@ -452,33 +461,16 @@ SourceManager::createMemBufferContentCache(const MemoryBuffer *Buffer) {
return Entry;
}
-void SourceManager::PreallocateSLocEntries(ExternalSLocEntrySource *Source,
- unsigned NumSLocEntries,
- unsigned NextOffset) {
- ExternalSLocEntries = Source;
- this->NextOffset = NextOffset;
- unsigned CurPrealloc = SLocEntryLoaded.size();
- // If we've ever preallocated, we must not count the dummy entry.
- if (CurPrealloc) --CurPrealloc;
- SLocEntryLoaded.resize(NumSLocEntries + 1);
- SLocEntryLoaded[0] = true;
- SLocEntryTable.resize(SLocEntryTable.size() + NumSLocEntries - CurPrealloc);
-}
-
-void SourceManager::ClearPreallocatedSLocEntries() {
- unsigned I = 0;
- for (unsigned N = SLocEntryLoaded.size(); I != N; ++I)
- if (!SLocEntryLoaded[I])
- break;
-
- // We've already loaded all preallocated source location entries.
- if (I == SLocEntryLoaded.size())
- return;
-
- // Remove everything from location I onward.
- SLocEntryTable.resize(I);
- SLocEntryLoaded.clear();
- ExternalSLocEntries = 0;
+std::pair<int, unsigned>
+SourceManager::AllocateLoadedSLocEntries(unsigned NumSLocEntries,
+ unsigned TotalSize) {
+ assert(ExternalSLocEntries && "Don't have an external sloc source");
+ LoadedSLocEntryTable.resize(LoadedSLocEntryTable.size() + NumSLocEntries);
+ SLocEntryLoaded.resize(LoadedSLocEntryTable.size());
+ CurrentLoadedOffset -= TotalSize;
+ assert(CurrentLoadedOffset >= NextLocalOffset && "Out of source locations");
+ int ID = LoadedSLocEntryTable.size();
+ return std::make_pair(-ID - 1, CurrentLoadedOffset);
}
/// \brief As part of recovering from missing or changed content, produce a
@@ -492,7 +484,7 @@ const llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const {
}
//===----------------------------------------------------------------------===//
-// Methods to create new FileID's and instantiations.
+// Methods to create new FileID's and macro expansions.
//===----------------------------------------------------------------------===//
/// createFileID - Create a new FileID for the specified ContentCache and
@@ -501,77 +493,76 @@ const llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const {
FileID SourceManager::createFileID(const ContentCache *File,
SourceLocation IncludePos,
SrcMgr::CharacteristicKind FileCharacter,
- unsigned PreallocatedID,
- unsigned Offset) {
- if (PreallocatedID) {
- // If we're filling in a preallocated ID, just load in the file
- // entry and return.
- assert(PreallocatedID < SLocEntryLoaded.size() &&
- "Preallocate ID out-of-range");
- assert(!SLocEntryLoaded[PreallocatedID] &&
- "Source location entry already loaded");
- assert(Offset && "Preallocate source location cannot have zero offset");
- SLocEntryTable[PreallocatedID]
- = SLocEntry::get(Offset, FileInfo::get(IncludePos, File, FileCharacter));
- SLocEntryLoaded[PreallocatedID] = true;
- FileID FID = FileID::get(PreallocatedID);
- return FID;
+ int LoadedID, unsigned LoadedOffset) {
+ if (LoadedID < 0) {
+ assert(LoadedID != -1 && "Loading sentinel FileID");
+ unsigned Index = unsigned(-LoadedID) - 2;
+ assert(Index < LoadedSLocEntryTable.size() && "FileID out of range");
+ assert(!SLocEntryLoaded[Index] && "FileID already loaded");
+ LoadedSLocEntryTable[Index] = SLocEntry::get(LoadedOffset,
+ FileInfo::get(IncludePos, File, FileCharacter));
+ SLocEntryLoaded[Index] = true;
+ return FileID::get(LoadedID);
}
-
- SLocEntryTable.push_back(SLocEntry::get(NextOffset,
- FileInfo::get(IncludePos, File,
- FileCharacter)));
+ LocalSLocEntryTable.push_back(SLocEntry::get(NextLocalOffset,
+ FileInfo::get(IncludePos, File,
+ FileCharacter)));
unsigned FileSize = File->getSize();
- assert(NextOffset+FileSize+1 > NextOffset && "Ran out of source locations!");
- NextOffset += FileSize+1;
+ assert(NextLocalOffset + FileSize + 1 > NextLocalOffset &&
+ NextLocalOffset + FileSize + 1 <= CurrentLoadedOffset &&
+ "Ran out of source locations!");
+ // We do a +1 here because we want a SourceLocation that means "the end of the
+ // file", e.g. for the "no newline at the end of the file" diagnostic.
+ NextLocalOffset += FileSize + 1;
// Set LastFileIDLookup to the newly created file. The next getFileID call is
// almost guaranteed to be from that file.
- FileID FID = FileID::get(SLocEntryTable.size()-1);
+ FileID FID = FileID::get(LocalSLocEntryTable.size()-1);
return LastFileIDLookup = FID;
}
SourceLocation
-SourceManager::createMacroArgInstantiationLoc(SourceLocation SpellingLoc,
- SourceLocation ILoc,
- unsigned TokLength) {
- InstantiationInfo II =
- InstantiationInfo::createForMacroArg(SpellingLoc, ILoc);
- return createInstantiationLocImpl(II, TokLength);
-}
-
-SourceLocation SourceManager::createInstantiationLoc(SourceLocation SpellingLoc,
- SourceLocation ILocStart,
- SourceLocation ILocEnd,
- unsigned TokLength,
- unsigned PreallocatedID,
- unsigned Offset) {
- InstantiationInfo II =
- InstantiationInfo::create(SpellingLoc, ILocStart, ILocEnd);
- return createInstantiationLocImpl(II, TokLength, PreallocatedID, Offset);
+SourceManager::createMacroArgExpansionLoc(SourceLocation SpellingLoc,
+ SourceLocation ExpansionLoc,
+ unsigned TokLength) {
+ ExpansionInfo Info = ExpansionInfo::createForMacroArg(SpellingLoc,
+ ExpansionLoc);
+ return createExpansionLocImpl(Info, TokLength);
}
SourceLocation
-SourceManager::createInstantiationLocImpl(const InstantiationInfo &II,
- unsigned TokLength,
- unsigned PreallocatedID,
- unsigned Offset) {
- if (PreallocatedID) {
- // If we're filling in a preallocated ID, just load in the
- // instantiation entry and return.
- assert(PreallocatedID < SLocEntryLoaded.size() &&
- "Preallocate ID out-of-range");
- assert(!SLocEntryLoaded[PreallocatedID] &&
- "Source location entry already loaded");
- assert(Offset && "Preallocate source location cannot have zero offset");
- SLocEntryTable[PreallocatedID] = SLocEntry::get(Offset, II);
- SLocEntryLoaded[PreallocatedID] = true;
- return SourceLocation::getMacroLoc(Offset);
+SourceManager::createExpansionLoc(SourceLocation SpellingLoc,
+ SourceLocation ExpansionLocStart,
+ SourceLocation ExpansionLocEnd,
+ unsigned TokLength,
+ int LoadedID,
+ unsigned LoadedOffset) {
+ ExpansionInfo Info = ExpansionInfo::create(SpellingLoc, ExpansionLocStart,
+ ExpansionLocEnd);
+ return createExpansionLocImpl(Info, TokLength, LoadedID, LoadedOffset);
+}
+
+SourceLocation
+SourceManager::createExpansionLocImpl(const ExpansionInfo &Info,
+ unsigned TokLength,
+ int LoadedID,
+ unsigned LoadedOffset) {
+ if (LoadedID < 0) {
+ assert(LoadedID != -1 && "Loading sentinel FileID");
+ unsigned Index = unsigned(-LoadedID) - 2;
+ assert(Index < LoadedSLocEntryTable.size() && "FileID out of range");
+ assert(!SLocEntryLoaded[Index] && "FileID already loaded");
+ LoadedSLocEntryTable[Index] = SLocEntry::get(LoadedOffset, Info);
+ SLocEntryLoaded[Index] = true;
+ return SourceLocation::getMacroLoc(LoadedOffset);
}
- SLocEntryTable.push_back(SLocEntry::get(NextOffset, II));
- assert(NextOffset+TokLength+1 > NextOffset && "Ran out of source locations!");
- NextOffset += TokLength+1;
- return SourceLocation::getMacroLoc(NextOffset-(TokLength+1));
+ LocalSLocEntryTable.push_back(SLocEntry::get(NextLocalOffset, Info));
+ assert(NextLocalOffset + TokLength + 1 > NextLocalOffset &&
+ NextLocalOffset + TokLength + 1 <= CurrentLoadedOffset &&
+ "Ran out of source locations!");
+ // See createFileID for that +1.
+ NextLocalOffset += TokLength + 1;
+ return SourceLocation::getMacroLoc(NextLocalOffset - (TokLength + 1));
}
const llvm::MemoryBuffer *
@@ -602,9 +593,9 @@ void SourceManager::overrideFileContents(const FileEntry *SourceFile,
OverriddenFiles[SourceFile] = NewFile;
}
-llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
+StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
bool MyInvalid = false;
- const SLocEntry &SLoc = getSLocEntry(FID.ID, &MyInvalid);
+ const SLocEntry &SLoc = getSLocEntry(FID, &MyInvalid);
if (!SLoc.isFile() || MyInvalid) {
if (Invalid)
*Invalid = true;
@@ -627,18 +618,32 @@ llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
// SourceLocation manipulation methods.
//===----------------------------------------------------------------------===//
-/// getFileIDSlow - Return the FileID for a SourceLocation. This is a very hot
-/// method that is used for all SourceManager queries that start with a
-/// SourceLocation object. It is responsible for finding the entry in
-/// SLocEntryTable which contains the specified location.
+/// \brief Return the FileID for a SourceLocation.
///
+/// This is the cache-miss path of getFileID. Not as hot as that function, but
+/// still very important. It is responsible for finding the entry in the
+/// SLocEntry tables that contains the specified location.
FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
if (!SLocOffset)
return FileID::get(0);
+ // Now it is time to search for the correct file. See where the SLocOffset
+ // sits in the global view and consult local or loaded buffers for it.
+ if (SLocOffset < NextLocalOffset)
+ return getFileIDLocal(SLocOffset);
+ return getFileIDLoaded(SLocOffset);
+}
+
+/// \brief Return the FileID for a SourceLocation with a low offset.
+///
+/// This function knows that the SourceLocation is in a local buffer, not a
+/// loaded one.
+FileID SourceManager::getFileIDLocal(unsigned SLocOffset) const {
+ assert(SLocOffset < NextLocalOffset && "Bad function choice");
+
// After the first and second level caches, I see two common sorts of
- // behavior: 1) a lot of searched FileID's are "near" the cached file location
- // or are "near" the cached instantiation location. 2) others are just
+ // behavior: 1) a lot of searched FileID's are "near" the cached file
+ // location or are "near" the cached expansion location. 2) others are just
// completely random and may be a very long way away.
//
// To handle this, we do a linear search for up to 8 steps to catch #1 quickly
@@ -649,12 +654,13 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
// most newly created FileID.
std::vector<SrcMgr::SLocEntry>::const_iterator I;
- if (SLocEntryTable[LastFileIDLookup.ID].getOffset() < SLocOffset) {
+ if (LastFileIDLookup.ID < 0 ||
+ LocalSLocEntryTable[LastFileIDLookup.ID].getOffset() < SLocOffset) {
// Neither loc prunes our search.
- I = SLocEntryTable.end();
+ I = LocalSLocEntryTable.end();
} else {
// Perhaps it is near the file point.
- I = SLocEntryTable.begin()+LastFileIDLookup.ID;
+ I = LocalSLocEntryTable.begin()+LastFileIDLookup.ID;
}
// Find the FileID that contains this. "I" is an iterator that points to a
@@ -662,25 +668,12 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
unsigned NumProbes = 0;
while (1) {
--I;
- if (ExternalSLocEntries) {
- bool Invalid = false;
- getSLocEntry(FileID::get(I - SLocEntryTable.begin()), &Invalid);
- if (Invalid)
- return FileID::get(0);
- }
-
if (I->getOffset() <= SLocOffset) {
-#if 0
- printf("lin %d -> %d [%s] %d %d\n", SLocOffset,
- I-SLocEntryTable.begin(),
- I->isInstantiation() ? "inst" : "file",
- LastFileIDLookup.ID, int(SLocEntryTable.end()-I));
-#endif
- FileID Res = FileID::get(I-SLocEntryTable.begin());
-
- // If this isn't an instantiation, remember it. We have good locality
- // across FileID lookups.
- if (!I->isInstantiation())
+ FileID Res = FileID::get(int(I - LocalSLocEntryTable.begin()));
+
+ // If this isn't an expansion, remember it. We have good locality across
+ // FileID lookups.
+ if (!I->isExpansion())
LastFileIDLookup = Res;
NumLinearScans += NumProbes+1;
return Res;
@@ -691,7 +684,7 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
// Convert "I" back into an index. We know that it is an entry whose index is
// larger than the offset we are looking for.
- unsigned GreaterIndex = I-SLocEntryTable.begin();
+ unsigned GreaterIndex = I - LocalSLocEntryTable.begin();
// LessIndex - This is the lower bound of the range that we're searching.
// We know that the offset corresponding to the FileID is is less than
// SLocOffset.
@@ -700,8 +693,7 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
while (1) {
bool Invalid = false;
unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex;
- unsigned MidOffset = getSLocEntry(FileID::get(MiddleIndex), &Invalid)
- .getOffset();
+ unsigned MidOffset = getLocalSLocEntry(MiddleIndex, &Invalid).getOffset();
if (Invalid)
return FileID::get(0);
@@ -715,18 +707,14 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
}
// If the middle index contains the value, succeed and return.
+ // FIXME: This could be made faster by using a function that's aware of
+ // being in the local area.
if (isOffsetInFileID(FileID::get(MiddleIndex), SLocOffset)) {
-#if 0
- printf("bin %d -> %d [%s] %d %d\n", SLocOffset,
- I-SLocEntryTable.begin(),
- I->isInstantiation() ? "inst" : "file",
- LastFileIDLookup.ID, int(SLocEntryTable.end()-I));
-#endif
FileID Res = FileID::get(MiddleIndex);
- // If this isn't an instantiation, remember it. We have good locality
+ // If this isn't a macro expansion, remember it. We have good locality
// across FileID lookups.
- if (!I->isInstantiation())
+ if (!LocalSLocEntryTable[MiddleIndex].isExpansion())
LastFileIDLookup = Res;
NumBinaryProbes += NumProbes;
return Res;
@@ -737,17 +725,82 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
}
}
+/// \brief Return the FileID for a SourceLocation with a high offset.
+///
+/// This function knows that the SourceLocation is in a loaded buffer, not a
+/// local one.
+FileID SourceManager::getFileIDLoaded(unsigned SLocOffset) const {
+ assert(SLocOffset >= CurrentLoadedOffset && "Bad function choice");
+
+ // Sanity checking, otherwise a bug may lead to hanging in release build.
+ if (SLocOffset < CurrentLoadedOffset)
+ return FileID();
+
+ // Essentially the same as the local case, but the loaded array is sorted
+ // in the other direction.
+
+ // First do a linear scan from the last lookup position, if possible.
+ unsigned I;
+ int LastID = LastFileIDLookup.ID;
+ if (LastID >= 0 || getLoadedSLocEntryByID(LastID).getOffset() < SLocOffset)
+ I = 0;
+ else
+ I = (-LastID - 2) + 1;
+
+ unsigned NumProbes;
+ for (NumProbes = 0; NumProbes < 8; ++NumProbes, ++I) {
+ // Make sure the entry is loaded!
+ const SrcMgr::SLocEntry &E = getLoadedSLocEntry(I);
+ if (E.getOffset() <= SLocOffset) {
+ FileID Res = FileID::get(-int(I) - 2);
+
+ if (!E.isExpansion())
+ LastFileIDLookup = Res;
+ NumLinearScans += NumProbes + 1;
+ return Res;
+ }
+ }
+
+ // Linear scan failed. Do the binary search. Note the reverse sorting of the
+ // table: GreaterIndex is the one where the offset is greater, which is
+ // actually a lower index!
+ unsigned GreaterIndex = I;
+ unsigned LessIndex = LoadedSLocEntryTable.size();
+ NumProbes = 0;
+ while (1) {
+ ++NumProbes;
+ unsigned MiddleIndex = (LessIndex - GreaterIndex) / 2 + GreaterIndex;
+ const SrcMgr::SLocEntry &E = getLoadedSLocEntry(MiddleIndex);
+
+ ++NumProbes;
+
+ if (E.getOffset() > SLocOffset) {
+ GreaterIndex = MiddleIndex;
+ continue;
+ }
+
+ if (isOffsetInFileID(FileID::get(-int(MiddleIndex) - 2), SLocOffset)) {
+ FileID Res = FileID::get(-int(MiddleIndex) - 2);
+ if (!E.isExpansion())
+ LastFileIDLookup = Res;
+ NumBinaryProbes += NumProbes;
+ return Res;
+ }
+
+ LessIndex = MiddleIndex;
+ }
+}
+
SourceLocation SourceManager::
-getInstantiationLocSlowCase(SourceLocation Loc) const {
+getExpansionLocSlowCase(SourceLocation Loc) const {
do {
// Note: If Loc indicates an offset into a token that came from a macro
// expansion (e.g. the 5th character of the token) we do not want to add
- // this offset when going to the instantiation location. The instatiation
+ // this offset when going to the expansion location. The expansion
// location is the macro invocation, which the offset has nothing to do
// with. This is unlike when we get the spelling loc, because the offset
// directly correspond to the token whose spelling we're inspecting.
- Loc = getSLocEntry(getFileID(Loc)).getInstantiation()
- .getInstantiationLocStart();
+ Loc = getSLocEntry(getFileID(Loc)).getExpansion().getExpansionLocStart();
} while (!Loc.isFileID());
return Loc;
@@ -756,23 +809,32 @@ getInstantiationLocSlowCase(SourceLocation Loc) const {
SourceLocation SourceManager::getSpellingLocSlowCase(SourceLocation Loc) const {
do {
std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(Loc);
- Loc = getSLocEntry(LocInfo.first).getInstantiation().getSpellingLoc();
- Loc = Loc.getFileLocWithOffset(LocInfo.second);
+ Loc = getSLocEntry(LocInfo.first).getExpansion().getSpellingLoc();
+ Loc = Loc.getLocWithOffset(LocInfo.second);
+ } while (!Loc.isFileID());
+ return Loc;
+}
+
+SourceLocation SourceManager::getFileLocSlowCase(SourceLocation Loc) const {
+ do {
+ if (isMacroArgExpansion(Loc))
+ Loc = getImmediateSpellingLoc(Loc);
+ else
+ Loc = getImmediateExpansionRange(Loc).first;
} while (!Loc.isFileID());
return Loc;
}
std::pair<FileID, unsigned>
-SourceManager::getDecomposedInstantiationLocSlowCase(
+SourceManager::getDecomposedExpansionLocSlowCase(
const SrcMgr::SLocEntry *E) const {
- // If this is an instantiation record, walk through all the instantiation
- // points.
+ // If this is an expansion record, walk through all the expansion points.
FileID FID;
SourceLocation Loc;
unsigned Offset;
do {
- Loc = E->getInstantiation().getInstantiationLocStart();
+ Loc = E->getExpansion().getExpansionLocStart();
FID = getFileID(Loc);
E = &getSLocEntry(FID);
@@ -785,16 +847,16 @@ SourceManager::getDecomposedInstantiationLocSlowCase(
std::pair<FileID, unsigned>
SourceManager::getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E,
unsigned Offset) const {
- // If this is an instantiation record, walk through all the instantiation
- // points.
+ // If this is an expansion record, walk through all the expansion points.
FileID FID;
SourceLocation Loc;
do {
- Loc = E->getInstantiation().getSpellingLoc();
+ Loc = E->getExpansion().getSpellingLoc();
+ Loc = Loc.getLocWithOffset(Offset);
FID = getFileID(Loc);
E = &getSLocEntry(FID);
- Offset += Loc.getOffset()-E->getOffset();
+ Offset = Loc.getOffset()-E->getOffset();
} while (!Loc.isFileID());
return std::make_pair(FID, Offset);
@@ -807,45 +869,45 @@ SourceManager::getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E,
SourceLocation SourceManager::getImmediateSpellingLoc(SourceLocation Loc) const{
if (Loc.isFileID()) return Loc;
std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(Loc);
- Loc = getSLocEntry(LocInfo.first).getInstantiation().getSpellingLoc();
- return Loc.getFileLocWithOffset(LocInfo.second);
+ Loc = getSLocEntry(LocInfo.first).getExpansion().getSpellingLoc();
+ return Loc.getLocWithOffset(LocInfo.second);
}
-/// getImmediateInstantiationRange - Loc is required to be an instantiation
-/// location. Return the start/end of the instantiation information.
+/// getImmediateExpansionRange - Loc is required to be an expansion location.
+/// Return the start/end of the expansion information.
std::pair<SourceLocation,SourceLocation>
-SourceManager::getImmediateInstantiationRange(SourceLocation Loc) const {
- assert(Loc.isMacroID() && "Not an instantiation loc!");
- const InstantiationInfo &II = getSLocEntry(getFileID(Loc)).getInstantiation();
- return II.getInstantiationLocRange();
+SourceManager::getImmediateExpansionRange(SourceLocation Loc) const {
+ assert(Loc.isMacroID() && "Not a macro expansion loc!");
+ const ExpansionInfo &Expansion = getSLocEntry(getFileID(Loc)).getExpansion();
+ return Expansion.getExpansionLocRange();
}
-/// getInstantiationRange - Given a SourceLocation object, return the
-/// range of tokens covered by the instantiation in the ultimate file.
+/// getExpansionRange - Given a SourceLocation object, return the range of
+/// tokens covered by the expansion in the ultimate file.
std::pair<SourceLocation,SourceLocation>
-SourceManager::getInstantiationRange(SourceLocation Loc) const {
+SourceManager::getExpansionRange(SourceLocation Loc) const {
if (Loc.isFileID()) return std::make_pair(Loc, Loc);
std::pair<SourceLocation,SourceLocation> Res =
- getImmediateInstantiationRange(Loc);
+ getImmediateExpansionRange(Loc);
- // Fully resolve the start and end locations to their ultimate instantiation
+ // Fully resolve the start and end locations to their ultimate expansion
// points.
while (!Res.first.isFileID())
- Res.first = getImmediateInstantiationRange(Res.first).first;
+ Res.first = getImmediateExpansionRange(Res.first).first;
while (!Res.second.isFileID())
- Res.second = getImmediateInstantiationRange(Res.second).second;
+ Res.second = getImmediateExpansionRange(Res.second).second;
return Res;
}
-bool SourceManager::isMacroArgInstantiation(SourceLocation Loc) const {
+bool SourceManager::isMacroArgExpansion(SourceLocation Loc) const {
if (!Loc.isMacroID()) return false;
FileID FID = getFileID(Loc);
const SrcMgr::SLocEntry *E = &getSLocEntry(FID);
- const SrcMgr::InstantiationInfo &II = E->getInstantiation();
- return II.isMacroArgInstantiation();
+ const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
+ return Expansion.isMacroArgExpansion();
}
@@ -913,10 +975,10 @@ unsigned SourceManager::getSpellingColumnNumber(SourceLocation Loc,
return getColumnNumber(LocInfo.first, LocInfo.second, Invalid);
}
-unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc,
- bool *Invalid) const {
+unsigned SourceManager::getExpansionColumnNumber(SourceLocation Loc,
+ bool *Invalid) const {
if (isInvalid(Loc, Invalid)) return 0;
- std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
+ std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
return getColumnNumber(LocInfo.first, LocInfo.second, Invalid);
}
@@ -927,10 +989,10 @@ unsigned SourceManager::getPresumedColumnNumber(SourceLocation Loc,
}
static LLVM_ATTRIBUTE_NOINLINE void
-ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI,
+ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI,
llvm::BumpPtrAllocator &Alloc,
const SourceManager &SM, bool &Invalid);
-static void ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI,
+static void ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI,
llvm::BumpPtrAllocator &Alloc,
const SourceManager &SM, bool &Invalid) {
// Note that calling 'getBuffer()' may lazily page in the file.
@@ -941,7 +1003,7 @@ static void ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI,
// Find the file offsets of all of the *physical* source lines. This does
// not look at trigraphs, escaped newlines, or anything else tricky.
- llvm::SmallVector<unsigned, 256> LineOffsets;
+ SmallVector<unsigned, 256> LineOffsets;
// Line #1 starts at char 0.
LineOffsets.push_back(0);
@@ -1108,10 +1170,10 @@ unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc,
std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc);
return getLineNumber(LocInfo.first, LocInfo.second);
}
-unsigned SourceManager::getInstantiationLineNumber(SourceLocation Loc,
- bool *Invalid) const {
+unsigned SourceManager::getExpansionLineNumber(SourceLocation Loc,
+ bool *Invalid) const {
if (isInvalid(Loc, Invalid)) return 0;
- std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
+ std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
return getLineNumber(LocInfo.first, LocInfo.second);
}
unsigned SourceManager::getPresumedLineNumber(SourceLocation Loc,
@@ -1131,7 +1193,7 @@ unsigned SourceManager::getPresumedLineNumber(SourceLocation Loc,
SrcMgr::CharacteristicKind
SourceManager::getFileCharacteristic(SourceLocation Loc) const {
assert(!Loc.isInvalid() && "Can't get file characteristic of invalid loc!");
- std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
+ std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
bool Invalid = false;
const SLocEntry &SEntry = getSLocEntry(LocInfo.first, &Invalid);
if (Invalid || !SEntry.isFile())
@@ -1172,13 +1234,13 @@ const char *SourceManager::getBufferName(SourceLocation Loc,
/// or GNU line marker directives. This provides a view on the data that a
/// user should see in diagnostics, for example.
///
-/// Note that a presumed location is always given as the instantiation point
-/// of an instantiation location, not at the spelling location.
+/// 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 {
if (Loc.isInvalid()) return PresumedLoc();
- // Presumed locations are always for instantiation points.
- std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
+ // Presumed locations are always for expansion points.
+ std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
bool Invalid = false;
const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
@@ -1229,7 +1291,7 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
// Handle virtual #include manipulation.
if (Entry->IncludeOffset) {
IncludeLoc = getLocForStartOfFile(LocInfo.first);
- IncludeLoc = IncludeLoc.getFileLocWithOffset(Entry->IncludeOffset);
+ IncludeLoc = IncludeLoc.getLocWithOffset(Entry->IncludeOffset);
}
}
}
@@ -1237,6 +1299,25 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
return PresumedLoc(Filename, LineNo, ColNo, IncludeLoc);
}
+/// \brief The size of the SLocEnty that \arg FID represents.
+unsigned SourceManager::getFileIDSize(FileID FID) const {
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
+ if (Invalid)
+ return 0;
+
+ int ID = FID.ID;
+ unsigned NextOffset;
+ if ((ID > 0 && unsigned(ID+1) == local_sloc_entry_size()))
+ NextOffset = getNextLocalOffset();
+ else if (ID+1 == -1)
+ NextOffset = MaxLoadedOffset;
+ else
+ NextOffset = getSLocEntry(FileID::get(ID+1)).getOffset();
+
+ return NextOffset - Entry.getOffset() - 1;
+}
+
//===----------------------------------------------------------------------===//
// Other miscellaneous methods.
//===----------------------------------------------------------------------===//
@@ -1259,24 +1340,36 @@ static llvm::Optional<ino_t> getActualFileInode(const FileEntry *File) {
/// \brief Get the source location for the given file:line:col triplet.
///
/// If the source file is included multiple times, the source location will
-/// be based upon the first inclusion.
-SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
- unsigned Line, unsigned Col) {
+/// be based upon an arbitrary inclusion.
+SourceLocation SourceManager::translateFileLineCol(const FileEntry *SourceFile,
+ unsigned Line,
+ unsigned Col) const {
assert(SourceFile && "Null source file!");
assert(Line && Col && "Line and column should start from 1!");
+ FileID FirstFID = translateFile(SourceFile);
+ return translateLineCol(FirstFID, Line, Col);
+}
+
+/// \brief Get the FileID for the given file.
+///
+/// If the source file is included multiple times, the FileID will be the
+/// first inclusion.
+FileID SourceManager::translateFile(const FileEntry *SourceFile) const {
+ assert(SourceFile && "Null source file!");
+
// Find the first file ID that corresponds to the given file.
FileID FirstFID;
// 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<llvm::StringRef> SourceFileName;
+ llvm::Optional<StringRef> SourceFileName;
if (!MainFileID.isInvalid()) {
bool Invalid = false;
const SLocEntry &MainSLoc = getSLocEntry(MainFileID, &Invalid);
if (Invalid)
- return SourceLocation();
+ return FileID();
if (MainSLoc.isFile()) {
const ContentCache *MainContentCache
@@ -1308,12 +1401,12 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
if (FirstFID.isInvalid()) {
// The location we're looking for isn't in the main file; look
- // through all of the source locations.
- for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) {
+ // through all of the local source locations.
+ for (unsigned I = 0, N = local_sloc_entry_size(); I != N; ++I) {
bool Invalid = false;
- const SLocEntry &SLoc = getSLocEntry(I, &Invalid);
+ const SLocEntry &SLoc = getLocalSLocEntry(I, &Invalid);
if (Invalid)
- return SourceLocation();
+ return FileID();
if (SLoc.isFile() &&
SLoc.getFile().getContentCache() &&
@@ -1322,6 +1415,18 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
break;
}
}
+ // If that still didn't help, try the modules.
+ if (FirstFID.isInvalid()) {
+ for (unsigned I = 0, N = loaded_sloc_entry_size(); I != N; ++I) {
+ const SLocEntry &SLoc = getLoadedSLocEntry(I);
+ if (SLoc.isFile() &&
+ SLoc.getFile().getContentCache() &&
+ SLoc.getFile().getContentCache()->OrigEntry == SourceFile) {
+ FirstFID = FileID::get(-int(I) - 2);
+ break;
+ }
+ }
+ }
}
// If we haven't found what we want yet, try again, but this time stat()
@@ -1333,10 +1438,12 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
(SourceFileInode ||
(SourceFileInode = getActualFileInode(SourceFile)))) {
bool Invalid = false;
- for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) {
- const SLocEntry &SLoc = getSLocEntry(I, &Invalid);
+ for (unsigned I = 0, N = local_sloc_entry_size(); I != N; ++I) {
+ FileID IFileID;
+ IFileID.ID = I;
+ const SLocEntry &SLoc = getSLocEntry(IFileID, &Invalid);
if (Invalid)
- return SourceLocation();
+ return FileID();
if (SLoc.isFile()) {
const ContentCache *FileContentCache
@@ -1355,20 +1462,38 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
}
}
}
-
- if (FirstFID.isInvalid())
+
+ return FirstFID;
+}
+
+/// \brief Get the source location in \arg FID for the given line:col.
+/// Returns null location if \arg FID is not a file SLocEntry.
+SourceLocation SourceManager::translateLineCol(FileID FID,
+ unsigned Line,
+ unsigned Col) const {
+ if (FID.isInvalid())
+ return SourceLocation();
+
+ bool Invalid = false;
+ const SLocEntry &Entry = getSLocEntry(FID, &Invalid);
+ if (Invalid)
+ return SourceLocation();
+
+ if (!Entry.isFile())
return SourceLocation();
+ SourceLocation FileLoc = SourceLocation::getFileLoc(Entry.getOffset());
+
if (Line == 1 && Col == 1)
- return getLocForStartOfFile(FirstFID);
+ return FileLoc;
ContentCache *Content
- = const_cast<ContentCache *>(getOrCreateContentCache(SourceFile));
+ = const_cast<ContentCache *>(Entry.getFile().getContentCache());
if (!Content)
return SourceLocation();
// If this is the first use of line information for this buffer, compute the
- /// SourceLineCache for it on demand.
+ // SourceLineCache for it on demand.
if (Content->SourceLineCache == 0) {
bool MyInvalid = false;
ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid);
@@ -1380,33 +1505,150 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
unsigned Size = Content->getBuffer(Diag, *this)->getBufferSize();
if (Size > 0)
--Size;
- return getLocForStartOfFile(FirstFID).getFileLocWithOffset(Size);
+ return FileLoc.getLocWithOffset(Size);
}
unsigned FilePos = Content->SourceLineCache[Line - 1];
const char *Buf = Content->getBuffer(Diag, *this)->getBufferStart() + FilePos;
unsigned BufLength = Content->getBuffer(Diag, *this)->getBufferEnd() - Buf;
+ if (BufLength == 0)
+ return FileLoc.getLocWithOffset(FilePos);
+
unsigned i = 0;
// Check that the given column is valid.
while (i < BufLength-1 && i < Col-1 && Buf[i] != '\n' && Buf[i] != '\r')
++i;
if (i < Col-1)
- return getLocForStartOfFile(FirstFID).getFileLocWithOffset(FilePos + i);
+ return FileLoc.getLocWithOffset(FilePos + i);
- return getLocForStartOfFile(FirstFID).getFileLocWithOffset(FilePos + Col - 1);
+ return FileLoc.getLocWithOffset(FilePos + Col - 1);
}
-/// Given a decomposed source location, move it up the include/instantiation
-/// stack to the parent source location. If this is possible, return the
-/// decomposed version of the parent in Loc and return false. If Loc is the
-/// top-level entry, return true and don't modify it.
+/// \brief Compute a map of macro argument chunks to their expanded source
+/// location. Chunks that are not part of a macro argument will map to an
+/// invalid source location. e.g. if a file contains one macro argument at
+/// offset 100 with length 10, this is how the map will be formed:
+/// 0 -> SourceLocation()
+/// 100 -> Expanded macro arg location
+/// 110 -> SourceLocation()
+void SourceManager::computeMacroArgsCache(MacroArgsMap *&CachePtr,
+ FileID FID) const {
+ assert(!FID.isInvalid());
+ assert(!CachePtr);
+
+ CachePtr = new MacroArgsMap();
+ MacroArgsMap &MacroArgsCache = *CachePtr;
+ // Initially no macro argument chunk is present.
+ MacroArgsCache.insert(std::make_pair(0, SourceLocation()));
+
+ int ID = FID.ID;
+ while (1) {
+ ++ID;
+ // Stop if there are no more FileIDs to check.
+ if (ID > 0) {
+ if (unsigned(ID) >= local_sloc_entry_size())
+ return;
+ } else if (ID == -1) {
+ return;
+ }
+
+ const SrcMgr::SLocEntry &Entry = getSLocEntryByID(ID);
+ if (Entry.isFile()) {
+ SourceLocation IncludeLoc = Entry.getFile().getIncludeLoc();
+ if (IncludeLoc.isInvalid())
+ continue;
+ if (!isInFileID(IncludeLoc, FID))
+ return; // No more files/macros that may be "contained" in this file.
+
+ // Skip the files/macros of the #include'd file, we only care about macros
+ // that lexed macro arguments from our file.
+ if (Entry.getFile().NumCreatedFIDs)
+ ID += Entry.getFile().NumCreatedFIDs - 1/*because of next ++ID*/;
+ continue;
+ }
+
+ if (!Entry.getExpansion().isMacroArgExpansion())
+ continue;
+
+ SourceLocation SpellLoc =
+ getSpellingLoc(Entry.getExpansion().getSpellingLoc());
+ unsigned BeginOffs;
+ if (!isInFileID(SpellLoc, FID, &BeginOffs))
+ return; // No more files/macros that may be "contained" in this file.
+ unsigned EndOffs = BeginOffs + getFileIDSize(FileID::get(ID));
+
+ // Add a new chunk for this macro argument. A previous macro argument chunk
+ // may have been lexed again, so e.g. if the map is
+ // 0 -> SourceLocation()
+ // 100 -> Expanded loc #1
+ // 110 -> SourceLocation()
+ // and we found a new macro FileID that lexed from offet 105 with length 3,
+ // the new map will be:
+ // 0 -> SourceLocation()
+ // 100 -> Expanded loc #1
+ // 105 -> Expanded loc #2
+ // 108 -> Expanded loc #1
+ // 110 -> SourceLocation()
+ //
+ // Since re-lexed macro chunks will always be the same size or less of
+ // previous chunks, we only need to find where the ending of the new macro
+ // chunk is mapped to and update the map with new begin/end mappings.
+
+ MacroArgsMap::iterator I = MacroArgsCache.upper_bound(EndOffs);
+ --I;
+ SourceLocation EndOffsMappedLoc = I->second;
+ MacroArgsCache[BeginOffs] = SourceLocation::getMacroLoc(Entry.getOffset());
+ MacroArgsCache[EndOffs] = EndOffsMappedLoc;
+ }
+}
+
+/// \brief If \arg Loc points inside a function macro argument, the returned
+/// location will be the macro location in which the argument was expanded.
+/// If a macro argument is used multiple times, the expanded location will
+/// be at the first expansion of the argument.
+/// e.g.
+/// MY_MACRO(foo);
+/// ^
+/// Passing a file location pointing at 'foo', will yield a macro location
+/// where 'foo' was expanded into.
+SourceLocation
+SourceManager::getMacroArgExpandedLocation(SourceLocation Loc) const {
+ if (Loc.isInvalid() || !Loc.isFileID())
+ return Loc;
+
+ FileID FID;
+ unsigned Offset;
+ llvm::tie(FID, Offset) = getDecomposedLoc(Loc);
+ if (FID.isInvalid())
+ return Loc;
+
+ MacroArgsMap *&MacroArgsCache = MacroArgsCacheMap[FID];
+ if (!MacroArgsCache)
+ computeMacroArgsCache(MacroArgsCache, FID);
+
+ assert(!MacroArgsCache->empty());
+ MacroArgsMap::iterator I = MacroArgsCache->upper_bound(Offset);
+ --I;
+
+ unsigned MacroArgBeginOffs = I->first;
+ SourceLocation MacroArgExpandedLoc = I->second;
+ if (MacroArgExpandedLoc.isValid())
+ return MacroArgExpandedLoc.getLocWithOffset(Offset - MacroArgBeginOffs);
+
+ return Loc;
+}
+
+/// Given a decomposed source location, move it up the include/expansion stack
+/// to the parent source location. If this is possible, return the decomposed
+/// version of the parent in Loc and return false. If Loc is the top-level
+/// entry, return true and don't modify it.
static bool MoveUpIncludeHierarchy(std::pair<FileID, unsigned> &Loc,
const SourceManager &SM) {
SourceLocation UpperLoc;
const SrcMgr::SLocEntry &Entry = SM.getSLocEntry(Loc.first);
- if (Entry.isInstantiation())
- UpperLoc = Entry.getInstantiation().getInstantiationLocStart();
+ if (Entry.isExpansion())
+ UpperLoc = Entry.getExpansion().getExpansionLocEnd();
else
UpperLoc = Entry.getFile().getIncludeLoc();
@@ -1427,11 +1669,6 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
if (LHS == RHS)
return false;
- // If both locations are macro instantiations, the order of their offsets
- // reflect the order that the tokens, pointed to by these locations, were
- // instantiated (during parsing each token that is instantiated by a macro,
- // expands the SLocEntries).
-
std::pair<FileID, unsigned> LOffs = getDecomposedLoc(LHS);
std::pair<FileID, unsigned> ROffs = getDecomposedLoc(RHS);
@@ -1445,41 +1682,28 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second);
// Okay, we missed in the cache, start updating the cache for this query.
- IsBeforeInTUCache.setQueryFIDs(LOffs.first, ROffs.first);
-
- // "Traverse" the include/instantiation stacks of both locations and try to
- // find a common "ancestor". FileIDs build a tree-like structure that
- // reflects the #include hierarchy, and this algorithm needs to find the
- // nearest common ancestor between the two locations. For example, if you
- // have a.c that includes b.h and c.h, and are comparing a location in b.h to
- // a location in c.h, we need to find that their nearest common ancestor is
- // a.c, and compare the locations of the two #includes to find their relative
- // ordering.
- //
- // SourceManager assigns FileIDs in order of parsing. This means that an
- // includee always has a larger FileID than an includer. While you might
- // think that we could just compare the FileID's here, that doesn't work to
- // compare a point at the end of a.c with a point within c.h. Though c.h has
- // a larger FileID, we have to compare the include point of c.h to the
- // location in a.c.
- //
- // Despite not being able to directly compare FileID's, we can tell that a
- // larger FileID is necessarily more deeply nested than a lower one and use
- // this information to walk up the tree to the nearest common ancestor.
+ IsBeforeInTUCache.setQueryFIDs(LOffs.first, ROffs.first,
+ /*isLFIDBeforeRFID=*/LOffs.first.ID < ROffs.first.ID);
+
+ // We need to find the common ancestor. The only way of doing this is to
+ // build the complete include chain for one and then walking up the chain
+ // of the other looking for a match.
+ // We use a map from FileID to Offset to store the chain. Easier than writing
+ // a custom set hash info that only depends on the first part of a pair.
+ typedef llvm::DenseMap<FileID, unsigned> LocSet;
+ LocSet LChain;
do {
- // If LOffs is larger than ROffs, then LOffs must be more deeply nested than
- // ROffs, walk up the #include chain.
- if (LOffs.first.ID > ROffs.first.ID) {
- if (MoveUpIncludeHierarchy(LOffs, *this))
- break; // We reached the top.
-
- } else {
- // Otherwise, ROffs is larger than LOffs, so ROffs must be more deeply
- // nested than LOffs, walk up the #include chain.
- if (MoveUpIncludeHierarchy(ROffs, *this))
- break; // We reached the top.
- }
- } while (LOffs.first != ROffs.first);
+ LChain.insert(LOffs);
+ // We catch the case where LOffs is in a file included by ROffs and
+ // quit early. The other way round unfortunately remains suboptimal.
+ } while (LOffs.first != ROffs.first && !MoveUpIncludeHierarchy(LOffs, *this));
+ LocSet::iterator I;
+ while((I = LChain.find(ROffs.first)) == LChain.end()) {
+ if (MoveUpIncludeHierarchy(ROffs, *this))
+ break; // Met at topmost file.
+ }
+ if (I != LChain.end())
+ LOffs = *I;
// If we exited because we found a nearest common ancestor, compare the
// locations within the common file and cache them.
@@ -1488,26 +1712,21 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second);
}
- // There is no common ancestor, most probably because one location is in the
- // predefines buffer or an AST file.
- // FIXME: We should rearrange the external interface so this simply never
- // happens; it can't conceptually happen. Also see PR5662.
- IsBeforeInTUCache.setQueryFIDs(FileID(), FileID()); // Don't try caching.
-
- // Zip both entries up to the top level record.
- while (!MoveUpIncludeHierarchy(LOffs, *this)) /*empty*/;
- while (!MoveUpIncludeHierarchy(ROffs, *this)) /*empty*/;
-
- // If exactly one location is a memory buffer, assume it precedes the other.
-
- // Strip off macro instantation locations, going up to the top-level File
- // SLocEntry.
- bool LIsMB = getFileEntryForID(LOffs.first) == 0;
- bool RIsMB = getFileEntryForID(ROffs.first) == 0;
- if (LIsMB != RIsMB)
- return LIsMB;
-
- // Otherwise, just assume FileIDs were created in order.
+ // This can happen if a location is in a built-ins buffer.
+ // But see PR5662.
+ // Clear the lookup cache, it depends on a common location.
+ IsBeforeInTUCache.clear();
+ bool LIsBuiltins = strcmp("<built-in>",
+ getBuffer(LOffs.first)->getBufferIdentifier()) == 0;
+ bool RIsBuiltins = strcmp("<built-in>",
+ getBuffer(ROffs.first)->getBufferIdentifier()) == 0;
+ // built-in is before non-built-in
+ if (LIsBuiltins != RIsBuiltins)
+ return LIsBuiltins;
+ assert(LIsBuiltins && RIsBuiltins &&
+ "Non-built-in locations must be rooted in the main file");
+ // Both are in built-in buffers, but from different files. We just claim that
+ // lower IDs come first.
return LOffs.first < ROffs.first;
}
@@ -1517,20 +1736,26 @@ void SourceManager::PrintStats() const {
llvm::errs() << "\n*** Source Manager Stats:\n";
llvm::errs() << FileInfos.size() << " files mapped, " << MemBufferInfos.size()
<< " mem buffers mapped.\n";
- llvm::errs() << SLocEntryTable.size() << " SLocEntry's allocated ("
- << SLocEntryTable.capacity()*sizeof(SrcMgr::SLocEntry)
+ llvm::errs() << LocalSLocEntryTable.size() << " local SLocEntry's allocated ("
+ << llvm::capacity_in_bytes(LocalSLocEntryTable)
<< " bytes of capacity), "
- << NextOffset << "B of Sloc address space used.\n";
-
+ << NextLocalOffset << "B of Sloc address space used.\n";
+ llvm::errs() << LoadedSLocEntryTable.size()
+ << " loaded SLocEntries allocated, "
+ << MaxLoadedOffset - CurrentLoadedOffset
+ << "B of Sloc address space used.\n";
+
unsigned NumLineNumsComputed = 0;
unsigned NumFileBytesMapped = 0;
for (fileinfo_iterator I = fileinfo_begin(), E = fileinfo_end(); I != E; ++I){
NumLineNumsComputed += I->second->SourceLineCache != 0;
NumFileBytesMapped += I->second->getSizeBytesMapped();
}
+ unsigned NumMacroArgsComputed = MacroArgsCacheMap.size();
llvm::errs() << NumFileBytesMapped << " bytes of files mapped, "
- << NumLineNumsComputed << " files with line #'s computed.\n";
+ << NumLineNumsComputed << " files with line #'s computed, "
+ << NumMacroArgsComputed << " files with macro args computed.\n";
llvm::errs() << "FileID scans: " << NumLinearScans << " linear, "
<< NumBinaryProbes << " binary.\n";
}
@@ -1557,3 +1782,11 @@ SourceManager::MemoryBufferSizes SourceManager::getMemoryBufferSizes() const {
return MemoryBufferSizes(malloc_bytes, mmap_bytes);
}
+size_t SourceManager::getDataStructureSizes() const {
+ return llvm::capacity_in_bytes(MemBufferInfos)
+ + llvm::capacity_in_bytes(LocalSLocEntryTable)
+ + llvm::capacity_in_bytes(LoadedSLocEntryTable)
+ + llvm::capacity_in_bytes(SLocEntryLoaded)
+ + llvm::capacity_in_bytes(FileInfos)
+ + llvm::capacity_in_bytes(OverriddenFiles);
+}
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index 30a9bdb31774..593db2b901c7 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -16,6 +16,7 @@
#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;
@@ -33,6 +34,8 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
IntWidth = IntAlign = 32;
LongWidth = LongAlign = 32;
LongLongWidth = LongLongAlign = 64;
+ HalfWidth = 16;
+ HalfAlign = 16;
FloatWidth = 32;
FloatAlign = 32;
DoubleWidth = 64;
@@ -41,6 +44,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
LongDoubleAlign = 64;
LargeArrayMinWidth = 0;
LargeArrayAlign = 0;
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 0;
SizeType = UnsignedLong;
PtrDiffType = SignedLong;
IntMaxType = SignedLongLong;
@@ -53,6 +57,9 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
Int64Type = SignedLongLong;
SigAtomicType = SignedInt;
UseBitFieldTypeAlignment = true;
+ UseZeroLengthBitfieldAlignment = false;
+ ZeroLengthBitfieldBoundary = 0;
+ HalfFormat = &llvm::APFloat::IEEEhalf;
FloatFormat = &llvm::APFloat::IEEEsingle;
DoubleFormat = &llvm::APFloat::IEEEdouble;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
@@ -60,6 +67,8 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
"i64:64:64-f32:32:32-f64:64:64-n32";
UserLabelPrefix = "_";
MCountName = "mcount";
+ RegParmMax = 0;
+ SSERegParmMax = 0;
HasAlignMac68kSupport = false;
// Default to no types using fpret.
@@ -83,7 +92,7 @@ TargetInfo::~TargetInfo() {}
/// For example, SignedShort -> "short".
const char *TargetInfo::getTypeName(IntType T) {
switch (T) {
- default: assert(0 && "not an integer!");
+ default: llvm_unreachable("not an integer!");
case SignedShort: return "short";
case UnsignedShort: return "unsigned short";
case SignedInt: return "int";
@@ -99,7 +108,7 @@ const char *TargetInfo::getTypeName(IntType T) {
/// integer type enum. For example, SignedLong -> "L".
const char *TargetInfo::getTypeConstantSuffix(IntType T) {
switch (T) {
- default: assert(0 && "not an integer!");
+ default: llvm_unreachable("not an integer!");
case SignedShort:
case SignedInt: return "";
case SignedLong: return "L";
@@ -115,7 +124,7 @@ const char *TargetInfo::getTypeConstantSuffix(IntType T) {
/// enum. For example, SignedInt -> getIntWidth().
unsigned TargetInfo::getTypeWidth(IntType T) const {
switch (T) {
- default: assert(0 && "not an integer!");
+ default: llvm_unreachable("not an integer!");
case SignedShort:
case UnsignedShort: return getShortWidth();
case SignedInt:
@@ -131,7 +140,7 @@ unsigned TargetInfo::getTypeWidth(IntType T) const {
/// enum. For example, SignedInt -> getIntAlign().
unsigned TargetInfo::getTypeAlign(IntType T) const {
switch (T) {
- default: assert(0 && "not an integer!");
+ default: llvm_unreachable("not an integer!");
case SignedShort:
case UnsignedShort: return getShortAlign();
case SignedInt:
@@ -147,7 +156,7 @@ unsigned TargetInfo::getTypeAlign(IntType T) const {
/// the type is signed; false otherwise.
bool TargetInfo::isTypeSigned(IntType T) {
switch (T) {
- default: assert(0 && "not an integer!");
+ default: llvm_unreachable("not an integer!");
case SignedShort:
case SignedInt:
case SignedLong:
@@ -174,7 +183,7 @@ void TargetInfo::setForcedLangOptions(LangOptions &Opts) {
//===----------------------------------------------------------------------===//
-static llvm::StringRef removeGCCRegisterPrefix(llvm::StringRef Name) {
+static StringRef removeGCCRegisterPrefix(StringRef Name) {
if (Name[0] == '%' || Name[0] == '#')
Name = Name.substr(1);
@@ -184,7 +193,7 @@ static llvm::StringRef removeGCCRegisterPrefix(llvm::StringRef Name) {
/// isValidClobber - Returns whether the passed in string is
/// a valid clobber in an inline asm statement. This is used by
/// Sema.
-bool TargetInfo::isValidClobber(llvm::StringRef Name) const {
+bool TargetInfo::isValidClobber(StringRef Name) const {
return (isValidGCCRegisterName(Name) ||
Name == "memory" || Name == "cc");
}
@@ -192,7 +201,7 @@ bool TargetInfo::isValidClobber(llvm::StringRef Name) const {
/// isValidGCCRegisterName - Returns whether the passed in string
/// is a valid register name according to GCC. This is used by Sema for
/// inline asm statements.
-bool TargetInfo::isValidGCCRegisterName(llvm::StringRef Name) const {
+bool TargetInfo::isValidGCCRegisterName(StringRef Name) const {
if (Name.empty())
return false;
@@ -248,8 +257,8 @@ bool TargetInfo::isValidGCCRegisterName(llvm::StringRef Name) const {
return false;
}
-llvm::StringRef
-TargetInfo::getNormalizedGCCRegisterName(llvm::StringRef Name) const {
+StringRef
+TargetInfo::getNormalizedGCCRegisterName(StringRef Name) const {
assert(isValidGCCRegisterName(Name) && "Invalid register passed in");
// Get rid of any register prefix.
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 3518ea6f7986..b89ea0c05326 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -26,6 +26,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/MC/MCSectionMachO.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Type.h"
#include <algorithm>
using namespace clang;
@@ -37,7 +38,7 @@ using namespace clang;
/// DefineStd - Define a macro name and standard variants. For example if
/// MacroName is "unix", then this will define "__unix", "__unix__", and "unix"
/// when in GNU mode.
-static void DefineStd(MacroBuilder &Builder, llvm::StringRef MacroName,
+static void DefineStd(MacroBuilder &Builder, StringRef MacroName,
const LangOptions &Opts) {
assert(MacroName[0] != '_' && "Identifier should be in the user's namespace");
@@ -77,7 +78,7 @@ public:
static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
const llvm::Triple &Triple,
- llvm::StringRef &PlatformName,
+ StringRef &PlatformName,
VersionTuple &PlatformMinVersion) {
Builder.defineMacro("__APPLE_CC__", "5621");
Builder.defineMacro("__APPLE__");
@@ -89,7 +90,7 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))");
// Darwin defines __strong even in C mode (just to nothing).
- if (Opts.getGCMode() != LangOptions::NonGC)
+ if (Opts.getGC() != LangOptions::NonGC)
Builder.defineMacro("__strong", "__attribute__((objc_gc(strong)))");
else
Builder.defineMacro("__strong", "");
@@ -146,6 +147,14 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
}
}
+ // If -ccc-host-triple arch-pc-win32-macho option specified, we're
+ // generating code for Win32 ABI. No need to emit
+ // __ENVIRONMENT_XX_OS_VERSION_MIN_REQUIRED__.
+ if (PlatformName == "win32") {
+ PlatformMinVersion = VersionTuple(Maj, Min, Rev);
+ return;
+ }
+
// Set the appropriate OS version define.
if (PlatformName == "ios") {
assert(Maj < 10 && Min < 100 && Rev < 100 && "Invalid version!");
@@ -194,9 +203,9 @@ public:
this->MCountName = "\01mcount";
}
- virtual std::string isValidSectionSpecifier(llvm::StringRef SR) const {
+ virtual std::string isValidSectionSpecifier(StringRef SR) const {
// Let MCSectionMachO validate this.
- llvm::StringRef Segment, Section;
+ StringRef Segment, Section;
unsigned TAA, StubSize;
bool HasTAA;
return llvm::MCSectionMachO::ParseSectionSpecifier(SR, Segment, Section,
@@ -238,11 +247,12 @@ protected:
MacroBuilder &Builder) const {
// FreeBSD defines; list based off of gcc output
- // FIXME: Move version number handling to llvm::Triple.
- llvm::StringRef Release = Triple.getOSName().substr(strlen("freebsd"), 1);
+ unsigned Release = Triple.getOSMajorVersion();
+ if (Release == 0U)
+ Release = 8;
- Builder.defineMacro("__FreeBSD__", Release);
- Builder.defineMacro("__FreeBSD_cc_version", Release + "00001");
+ Builder.defineMacro("__FreeBSD__", Twine(Release));
+ Builder.defineMacro("__FreeBSD_cc_version", Twine(Release * 100000U + 1U));
Builder.defineMacro("__KPRINTF_ATTRIBUTE__");
DefineStd(Builder, "unix", Opts);
Builder.defineMacro("__ELF__");
@@ -495,9 +505,9 @@ protected:
Builder.defineMacro("_MT");
if (Opts.MSCVersion != 0)
- Builder.defineMacro("_MSC_VER", llvm::Twine(Opts.MSCVersion));
+ Builder.defineMacro("_MSC_VER", Twine(Opts.MSCVersion));
- if (Opts.Microsoft) {
+ if (Opts.MicrosoftExt) {
Builder.defineMacro("_MSC_EXTENSIONS");
if (Opts.CPlusPlus0x) {
@@ -869,13 +879,41 @@ public:
} // end anonymous namespace.
namespace {
+ static const unsigned PTXAddrSpaceMap[] = {
+ 0, // opencl_global
+ 4, // opencl_local
+ 1 // opencl_constant
+ };
class PTXTargetInfo : public TargetInfo {
static const char * const GCCRegNames[];
static const Builtin::Info BuiltinInfo[];
+ std::vector<llvm::StringRef> AvailableFeatures;
public:
PTXTargetInfo(const std::string& triple) : TargetInfo(triple) {
TLSSupported = false;
LongWidth = LongAlign = 64;
+ AddrSpaceMap = &PTXAddrSpaceMap;
+ // Define available target features
+ // These must be defined in sorted order!
+ AvailableFeatures.push_back("compute10");
+ AvailableFeatures.push_back("compute11");
+ AvailableFeatures.push_back("compute12");
+ AvailableFeatures.push_back("compute13");
+ AvailableFeatures.push_back("compute20");
+ AvailableFeatures.push_back("double");
+ AvailableFeatures.push_back("no-fma");
+ AvailableFeatures.push_back("ptx20");
+ AvailableFeatures.push_back("ptx21");
+ AvailableFeatures.push_back("ptx22");
+ AvailableFeatures.push_back("ptx23");
+ AvailableFeatures.push_back("sm10");
+ AvailableFeatures.push_back("sm11");
+ AvailableFeatures.push_back("sm12");
+ AvailableFeatures.push_back("sm13");
+ AvailableFeatures.push_back("sm20");
+ AvailableFeatures.push_back("sm21");
+ AvailableFeatures.push_back("sm22");
+ AvailableFeatures.push_back("sm23");
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -908,6 +946,10 @@ namespace {
// FIXME: implement
return "typedef char* __builtin_va_list;";
}
+
+ virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
+ const std::string &Name,
+ bool Enabled) const;
};
const Builtin::Info PTXTargetInfo::BuiltinInfo[] = {
@@ -927,6 +969,17 @@ namespace {
NumNames = llvm::array_lengthof(GCCRegNames);
}
+ bool PTXTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
+ const std::string &Name,
+ bool Enabled) const {
+ if(std::binary_search(AvailableFeatures.begin(), AvailableFeatures.end(),
+ Name)) {
+ Features[Name] = Enabled;
+ return true;
+ } else {
+ return false;
+ }
+ }
class PTX32TargetInfo : public PTXTargetInfo {
public:
@@ -1119,10 +1172,134 @@ class X86TargetInfo : public TargetInfo {
bool HasAES;
bool HasAVX;
+ /// \brief Enumeration of all of the X86 CPUs supported by Clang.
+ ///
+ /// Each enumeration represents a particular CPU supported by Clang. These
+ /// loosely correspond to the options passed to '-march' or '-mtune' flags.
+ enum CPUKind {
+ CK_Generic,
+
+ /// \name i386
+ /// i386-generation processors.
+ //@{
+ CK_i386,
+ //@}
+
+ /// \name i486
+ /// i486-generation processors.
+ //@{
+ CK_i486,
+ CK_WinChipC6,
+ CK_WinChip2,
+ CK_C3,
+ //@}
+
+ /// \name i586
+ /// i586-generation processors, P5 microarchitecture based.
+ //@{
+ CK_i586,
+ CK_Pentium,
+ CK_PentiumMMX,
+ //@}
+
+ /// \name i686
+ /// i686-generation processors, P6 / Pentium M microarchitecture based.
+ //@{
+ CK_i686,
+ CK_PentiumPro,
+ CK_Pentium2,
+ CK_Pentium3,
+ CK_Pentium3M,
+ CK_PentiumM,
+ CK_C3_2,
+
+ /// This enumerator is a bit odd, as GCC no longer accepts -march=yonah.
+ /// Clang however has some logic to suport this.
+ // FIXME: Warn, deprecate, and potentially remove this.
+ CK_Yonah,
+ //@}
+
+ /// \name Netburst
+ /// Netburst microarchitecture based processors.
+ //@{
+ CK_Pentium4,
+ CK_Pentium4M,
+ CK_Prescott,
+ CK_Nocona,
+ //@}
+
+ /// \name Core
+ /// Core microarchitecture based processors.
+ //@{
+ CK_Core2,
+
+ /// This enumerator, like \see CK_Yonah, is a bit odd. It is another
+ /// codename which GCC no longer accepts as an option to -march, but Clang
+ /// has some logic for recognizing it.
+ // FIXME: Warn, deprecate, and potentially remove this.
+ CK_Penryn,
+ //@}
+
+ /// \name Atom
+ /// Atom processors
+ //@{
+ CK_Atom,
+ //@}
+
+ /// \name Nehalem
+ /// Nehalem microarchitecture based processors.
+ //@{
+ CK_Corei7,
+ CK_Corei7AVX,
+ CK_CoreAVXi,
+ //@}
+
+ /// \name K6
+ /// K6 architecture processors.
+ //@{
+ CK_K6,
+ CK_K6_2,
+ CK_K6_3,
+ //@}
+
+ /// \name K7
+ /// K7 architecture processors.
+ //@{
+ CK_Athlon,
+ CK_AthlonThunderbird,
+ CK_Athlon4,
+ CK_AthlonXP,
+ CK_AthlonMP,
+ //@}
+
+ /// \name K8
+ /// K8 architecture processors.
+ //@{
+ CK_Athlon64,
+ CK_Athlon64SSE3,
+ CK_AthlonFX,
+ CK_K8,
+ CK_K8SSE3,
+ CK_Opteron,
+ CK_OpteronSSE3,
+
+ /// This specification is deprecated and will be removed in the future.
+ /// Users should prefer \see CK_K8.
+ // FIXME: Warn on this when the CPU is set to it.
+ CK_x86_64,
+ //@}
+
+ /// \name Geode
+ /// Geode processors.
+ //@{
+ CK_Geode
+ //@}
+ } CPU;
+
public:
X86TargetInfo(const std::string& triple)
: TargetInfo(triple), SSELevel(NoSSE), MMX3DNowLevel(NoMMX3DNow),
- HasAES(false), HasAVX(false) {
+ HasAES(false), HasAVX(false), CPU(CK_Generic) {
LongDoubleFormat = &llvm::APFloat::x87DoubleExtended;
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
@@ -1156,16 +1333,122 @@ public:
virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
const std::string &Name,
bool Enabled) const;
- virtual void getDefaultFeatures(const std::string &CPU,
- llvm::StringMap<bool> &Features) const;
+ virtual void getDefaultFeatures(llvm::StringMap<bool> &Features) const;
virtual void HandleTargetFeatures(std::vector<std::string> &Features);
virtual const char* getABI() const {
return MMX3DNowLevel == NoMMX3DNow ? "no-mmx" : "";
}
+ virtual bool setCPU(const std::string &Name) {
+ CPU = llvm::StringSwitch<CPUKind>(Name)
+ .Case("i386", CK_i386)
+ .Case("i486", CK_i486)
+ .Case("winchip-c6", CK_WinChipC6)
+ .Case("winchip2", CK_WinChip2)
+ .Case("c3", CK_C3)
+ .Case("i586", CK_i586)
+ .Case("pentium", CK_Pentium)
+ .Case("pentium-mmx", CK_PentiumMMX)
+ .Case("i686", CK_i686)
+ .Case("pentiumpro", CK_PentiumPro)
+ .Case("pentium2", CK_Pentium2)
+ .Case("pentium3", CK_Pentium3)
+ .Case("pentium3m", CK_Pentium3M)
+ .Case("pentium-m", CK_PentiumM)
+ .Case("c3-2", CK_C3_2)
+ .Case("yonah", CK_Yonah)
+ .Case("pentium4", CK_Pentium4)
+ .Case("pentium4m", CK_Pentium4M)
+ .Case("prescott", CK_Prescott)
+ .Case("nocona", CK_Nocona)
+ .Case("core2", CK_Core2)
+ .Case("penryn", CK_Penryn)
+ .Case("atom", CK_Atom)
+ .Case("corei7", CK_Corei7)
+ .Case("corei7-avx", CK_Corei7AVX)
+ .Case("core-avx-i", CK_CoreAVXi)
+ .Case("k6", CK_K6)
+ .Case("k6-2", CK_K6_2)
+ .Case("k6-3", CK_K6_3)
+ .Case("athlon", CK_Athlon)
+ .Case("athlon-tbird", CK_AthlonThunderbird)
+ .Case("athlon-4", CK_Athlon4)
+ .Case("athlon-xp", CK_AthlonXP)
+ .Case("athlon-mp", CK_AthlonMP)
+ .Case("athlon64", CK_Athlon64)
+ .Case("athlon64-sse3", CK_Athlon64SSE3)
+ .Case("athlon-fx", CK_AthlonFX)
+ .Case("k8", CK_K8)
+ .Case("k8-sse3", CK_K8SSE3)
+ .Case("opteron", CK_Opteron)
+ .Case("opteron-sse3", CK_OpteronSSE3)
+ .Case("x86-64", CK_x86_64)
+ .Case("geode", CK_Geode)
+ .Default(CK_Generic);
+
+ // Perform any per-CPU checks necessary to determine if this CPU is
+ // acceptable.
+ // FIXME: This results in terrible diagnostics. Clang just says the CPU is
+ // invalid without explaining *why*.
+ switch (CPU) {
+ case CK_Generic:
+ // No processor selected!
+ return false;
+
+ case CK_i386:
+ case CK_i486:
+ case CK_WinChipC6:
+ case CK_WinChip2:
+ case CK_C3:
+ case CK_i586:
+ case CK_Pentium:
+ case CK_PentiumMMX:
+ case CK_i686:
+ case CK_PentiumPro:
+ case CK_Pentium2:
+ case CK_Pentium3:
+ case CK_Pentium3M:
+ case CK_PentiumM:
+ case CK_Yonah:
+ case CK_C3_2:
+ case CK_Pentium4:
+ case CK_Pentium4M:
+ case CK_Prescott:
+ case CK_K6:
+ case CK_K6_2:
+ case CK_K6_3:
+ case CK_Athlon:
+ case CK_AthlonThunderbird:
+ case CK_Athlon4:
+ case CK_AthlonXP:
+ case CK_AthlonMP:
+ case CK_Geode:
+ // Only accept certain architectures when compiling in 32-bit mode.
+ if (PointerWidth != 32)
+ return false;
+
+ // Fallthrough
+ case CK_Nocona:
+ case CK_Core2:
+ case CK_Penryn:
+ case CK_Atom:
+ case CK_Corei7:
+ case CK_Corei7AVX:
+ case CK_CoreAVXi:
+ case CK_Athlon64:
+ case CK_Athlon64SSE3:
+ case CK_AthlonFX:
+ case CK_K8:
+ case CK_K8SSE3:
+ case CK_Opteron:
+ case CK_OpteronSSE3:
+ case CK_x86_64:
+ return true;
+ }
+ llvm_unreachable("Unhandled CPU kind");
+ }
};
-void X86TargetInfo::getDefaultFeatures(const std::string &CPU,
- llvm::StringMap<bool> &Features) const {
+void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
// FIXME: This should not be here.
Features["3dnow"] = false;
Features["3dnowa"] = false;
@@ -1188,57 +1471,100 @@ void X86TargetInfo::getDefaultFeatures(const std::string &CPU,
if (PointerWidth == 64)
Features["sse2"] = Features["sse"] = Features["mmx"] = true;
- if (CPU == "generic" || CPU == "i386" || CPU == "i486" || CPU == "i586" ||
- CPU == "pentium" || CPU == "i686" || CPU == "pentiumpro")
- ;
- else if (CPU == "pentium-mmx" || CPU == "pentium2")
+ switch (CPU) {
+ case CK_Generic:
+ case CK_i386:
+ case CK_i486:
+ case CK_i586:
+ case CK_Pentium:
+ case CK_i686:
+ case CK_PentiumPro:
+ break;
+ case CK_PentiumMMX:
+ case CK_Pentium2:
setFeatureEnabled(Features, "mmx", true);
- else if (CPU == "pentium3") {
+ break;
+ case CK_Pentium3:
+ case CK_Pentium3M:
setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse", true);
- } else if (CPU == "pentium-m" || CPU == "pentium4" || CPU == "x86-64") {
+ break;
+ case CK_PentiumM:
+ case CK_Pentium4:
+ case CK_Pentium4M:
+ case CK_x86_64:
setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse2", true);
- } else if (CPU == "yonah" || CPU == "prescott" || CPU == "nocona") {
+ break;
+ case CK_Yonah:
+ case CK_Prescott:
+ case CK_Nocona:
setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse3", true);
- } else if (CPU == "core2") {
+ break;
+ case CK_Core2:
setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "ssse3", true);
- } else if (CPU == "penryn") {
+ break;
+ case CK_Penryn:
setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse4", true);
Features["sse42"] = false;
- } else if (CPU == "atom") {
+ break;
+ case CK_Atom:
setFeatureEnabled(Features, "mmx", true);
- setFeatureEnabled(Features, "sse3", true);
- } else if (CPU == "corei7") {
+ setFeatureEnabled(Features, "ssse3", true);
+ break;
+ case CK_Corei7:
setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse4", true);
setFeatureEnabled(Features, "aes", true);
- } else if (CPU == "corei7-avx") {
+ break;
+ case CK_Corei7AVX:
+ case CK_CoreAVXi:
setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse4", true);
setFeatureEnabled(Features, "aes", true);
//setFeatureEnabled(Features, "avx", true);
- } else if (CPU == "k6" || CPU == "winchip-c6")
+ break;
+ case CK_K6:
+ case CK_WinChipC6:
setFeatureEnabled(Features, "mmx", true);
- else if (CPU == "k6-2" || CPU == "k6-3" || CPU == "athlon" ||
- CPU == "athlon-tbird" || CPU == "winchip2" || CPU == "c3") {
+ break;
+ case CK_K6_2:
+ case CK_K6_3:
+ case CK_WinChip2:
+ case CK_C3:
setFeatureEnabled(Features, "3dnow", true);
- } else if (CPU == "athlon-4" || CPU == "athlon-xp" || CPU == "athlon-mp") {
+ break;
+ case CK_Athlon:
+ case CK_AthlonThunderbird:
+ case CK_Geode:
+ setFeatureEnabled(Features, "3dnowa", true);
+ break;
+ case CK_Athlon4:
+ case CK_AthlonXP:
+ case CK_AthlonMP:
setFeatureEnabled(Features, "sse", true);
setFeatureEnabled(Features, "3dnowa", true);
- } else if (CPU == "k8" || CPU == "opteron" || CPU == "athlon64" ||
- CPU == "athlon-fx") {
+ break;
+ case CK_K8:
+ case CK_Opteron:
+ case CK_Athlon64:
+ case CK_AthlonFX:
setFeatureEnabled(Features, "sse2", true);
setFeatureEnabled(Features, "3dnowa", true);
- } else if (CPU == "k8-sse3") {
+ break;
+ case CK_K8SSE3:
+ case CK_OpteronSSE3:
+ case CK_Athlon64SSE3:
setFeatureEnabled(Features, "sse3", true);
setFeatureEnabled(Features, "3dnowa", true);
- } else if (CPU == "c3-2") {
+ break;
+ case CK_C3_2:
setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse", true);
+ break;
}
}
@@ -1276,7 +1602,8 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
else if (Name == "aes")
Features["aes"] = true;
else if (Name == "avx")
- Features["avx"] = true;
+ Features["avx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["ssse3"] = Features["sse41"] = Features["sse42"] = true;
} else {
if (Name == "mmx")
Features["mmx"] = Features["3dnow"] = Features["3dnowa"] = false;
@@ -1358,8 +1685,8 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
Features.erase(it);
}
-/// X86TargetInfo::getTargetDefines - Return a set of the X86-specific #defines
-/// that are not tied to a specific subtarget.
+/// X86TargetInfo::getTargetDefines - Return the set of the X86-specific macro
+/// definitions for this particular subtarget.
void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
// Target identification.
@@ -1374,19 +1701,140 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
DefineStd(Builder, "i386", Opts);
}
- if (HasAES)
- Builder.defineMacro("__AES__");
-
- if (HasAVX)
- Builder.defineMacro("__AVX__");
+ // Subtarget options.
+ // FIXME: We are hard-coding the tune parameters based on the CPU, but they
+ // truly should be based on -mtune options.
+ switch (CPU) {
+ case CK_Generic:
+ break;
+ case CK_i386:
+ // The rest are coming from the i386 define above.
+ Builder.defineMacro("__tune_i386__");
+ break;
+ case CK_i486:
+ case CK_WinChipC6:
+ case CK_WinChip2:
+ case CK_C3:
+ Builder.defineMacro("__i486");
+ Builder.defineMacro("__i486__");
+ Builder.defineMacro("__tune_i486__");
+ break;
+ case CK_PentiumMMX:
+ Builder.defineMacro("__pentium_mmx__");
+ Builder.defineMacro("__tune_pentium_mmx__");
+ // Fallthrough
+ case CK_i586:
+ case CK_Pentium:
+ Builder.defineMacro("__i586");
+ Builder.defineMacro("__i586__");
+ Builder.defineMacro("__tune_i586__");
+ Builder.defineMacro("__pentium");
+ Builder.defineMacro("__pentium__");
+ Builder.defineMacro("__tune_pentium__");
+ break;
+ case CK_Pentium3:
+ case CK_Pentium3M:
+ case CK_PentiumM:
+ Builder.defineMacro("__tune_pentium3__");
+ // Fallthrough
+ case CK_Pentium2:
+ case CK_C3_2:
+ Builder.defineMacro("__tune_pentium2__");
+ // Fallthrough
+ case CK_PentiumPro:
+ Builder.defineMacro("__tune_i686__");
+ Builder.defineMacro("__tune_pentiumpro__");
+ // Fallthrough
+ case CK_i686:
+ Builder.defineMacro("__i686");
+ Builder.defineMacro("__i686__");
+ // Strangely, __tune_i686__ isn't defined by GCC when CPU == i686.
+ Builder.defineMacro("__pentiumpro");
+ Builder.defineMacro("__pentiumpro__");
+ break;
+ case CK_Pentium4:
+ case CK_Pentium4M:
+ Builder.defineMacro("__pentium4");
+ Builder.defineMacro("__pentium4__");
+ Builder.defineMacro("__tune_pentium4__");
+ break;
+ case CK_Yonah:
+ case CK_Prescott:
+ case CK_Nocona:
+ Builder.defineMacro("__nocona");
+ Builder.defineMacro("__nocona__");
+ Builder.defineMacro("__tune_nocona__");
+ break;
+ case CK_Core2:
+ case CK_Penryn:
+ Builder.defineMacro("__core2");
+ Builder.defineMacro("__core2__");
+ Builder.defineMacro("__tune_core2__");
+ break;
+ case CK_Atom:
+ Builder.defineMacro("__atom");
+ Builder.defineMacro("__atom__");
+ Builder.defineMacro("__tune_atom__");
+ break;
+ case CK_Corei7:
+ case CK_Corei7AVX:
+ case CK_CoreAVXi:
+ Builder.defineMacro("__corei7");
+ Builder.defineMacro("__corei7__");
+ Builder.defineMacro("__tune_corei7__");
+ break;
+ case CK_K6_2:
+ Builder.defineMacro("__k6_2__");
+ Builder.defineMacro("__tune_k6_2__");
+ // Fallthrough
+ case CK_K6_3:
+ if (CPU != CK_K6_2) { // In case of fallthrough
+ // FIXME: GCC may be enabling these in cases where some other k6
+ // architecture is specified but -m3dnow is explicitly provided. The
+ // exact semantics need to be determined and emulated here.
+ Builder.defineMacro("__k6_3__");
+ Builder.defineMacro("__tune_k6_3__");
+ }
+ // Fallthrough
+ case CK_K6:
+ Builder.defineMacro("__k6");
+ Builder.defineMacro("__k6__");
+ Builder.defineMacro("__tune_k6__");
+ break;
+ case CK_Athlon:
+ case CK_AthlonThunderbird:
+ case CK_Athlon4:
+ case CK_AthlonXP:
+ case CK_AthlonMP:
+ Builder.defineMacro("__athlon");
+ Builder.defineMacro("__athlon__");
+ Builder.defineMacro("__tune_athlon__");
+ if (SSELevel != NoSSE) {
+ Builder.defineMacro("__athlon_sse__");
+ Builder.defineMacro("__tune_athlon_sse__");
+ }
+ break;
+ case CK_K8:
+ case CK_K8SSE3:
+ case CK_x86_64:
+ case CK_Opteron:
+ case CK_OpteronSSE3:
+ case CK_Athlon64:
+ case CK_Athlon64SSE3:
+ case CK_AthlonFX:
+ Builder.defineMacro("__k8");
+ Builder.defineMacro("__k8__");
+ Builder.defineMacro("__tune_k8__");
+ break;
+ case CK_Geode:
+ Builder.defineMacro("__geode");
+ Builder.defineMacro("__geode__");
+ Builder.defineMacro("__tune_geode__");
+ break;
+ }
// Target properties.
Builder.defineMacro("__LITTLE_ENDIAN__");
-
- // Subtarget options.
- Builder.defineMacro("__nocona");
- Builder.defineMacro("__nocona__");
- Builder.defineMacro("__tune_nocona__");
Builder.defineMacro("__REGISTER_PREFIX__", "");
// Define __NO_MATH_INLINES on linux/x86 so that we don't get inline
@@ -1394,6 +1842,12 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
// backend can't deal with (PR879).
Builder.defineMacro("__NO_MATH_INLINES");
+ if (HasAES)
+ Builder.defineMacro("__AES__");
+
+ if (HasAVX)
+ Builder.defineMacro("__AVX__");
+
// Each case falls through to the previous one here.
switch (SSELevel) {
case SSE42:
@@ -1414,20 +1868,20 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
break;
}
- if (Opts.Microsoft && PointerWidth == 32) {
+ if (Opts.MicrosoftExt && PointerWidth == 32) {
switch (SSELevel) {
case SSE42:
case SSE41:
case SSSE3:
case SSE3:
case SSE2:
- Builder.defineMacro("_M_IX86_FP", llvm::Twine(2));
+ Builder.defineMacro("_M_IX86_FP", Twine(2));
break;
case SSE1:
- Builder.defineMacro("_M_IX86_FP", llvm::Twine(1));
+ Builder.defineMacro("_M_IX86_FP", Twine(1));
break;
default:
- Builder.defineMacro("_M_IX86_FP", llvm::Twine(0));
+ Builder.defineMacro("_M_IX86_FP", Twine(0));
}
}
@@ -1521,7 +1975,7 @@ public:
LongDoubleAlign = 32;
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-"
- "a0:0:64-f80:32:32-n8:16:32";
+ "a0:0:64-f80:32:32-n8:16:32-S128";
SizeType = UnsignedInt;
PtrDiffType = SignedInt;
IntPtrType = SignedInt;
@@ -1531,6 +1985,11 @@ public:
RealTypeUsesObjCFPRet = ((1 << TargetInfo::Float) |
(1 << TargetInfo::Double) |
(1 << TargetInfo::LongDouble));
+
+ // x86-32 has atomics up to 8 bytes
+ // FIXME: Check that we actually have cmpxchg8b before setting
+ // MaxAtomicInlineWidth. (cmpxchg8b is an i586 instruction.)
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
}
virtual const char *getVAListDeclaration() const {
return "typedef char* __builtin_va_list;";
@@ -1567,7 +2026,7 @@ public:
IntPtrType = SignedLong;
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-"
- "a0:0:64-f80:128:128-n8:16:32";
+ "a0:0:64-f80:128:128-n8:16:32-S128";
HasAlignMac68kSupport = true;
}
@@ -1585,7 +2044,7 @@ public:
DoubleAlign = LongLongAlign = 64;
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:128:128-v64:64:64-"
- "v128:128:128-a0:0:64-f80:32:32-n8:16:32";
+ "v128:128:128-a0:0:64-f80:32:32-n8:16:32-S32";
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -1634,7 +2093,7 @@ public:
// mingw32-gcc provides __declspec(a) as alias of __attribute__((a)).
// In contrast, clang-cc1 provides __declspec(a) with -fms-extensions.
- if (Opts.Microsoft)
+ if (Opts.MicrosoftExt)
// Provide "as-is" __declspec.
Builder.defineMacro("__declspec", "__declspec");
else
@@ -1655,7 +2114,7 @@ public:
DoubleAlign = LongLongAlign = 64;
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"
- "a0:0:64-f80:32:32-n8:16:32";
+ "a0:0:64-f80:32:32-n8:16:32-S32";
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -1697,9 +2156,6 @@ protected:
MacroBuilder &Builder) const {
// RTEMS defines; list based off of gcc output
- // FIXME: Move version number handling to llvm::Triple.
- llvm::StringRef Release = Triple.getOSName().substr(strlen("rtems"), 1);
-
Builder.defineMacro("__rtems__");
Builder.defineMacro("__ELF__");
}
@@ -1765,10 +2221,16 @@ public:
DescriptionString = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"
- "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64";
+ "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128";
// Use fpret only for long double.
RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble);
+
+ // x86-64 has atomics up to 16 bytes.
+ // FIXME: Once the backend is fixed, increase MaxAtomicInlineWidth to 128
+ // on CPUs with cmpxchg16b
+ MaxAtomicPromoteWidth = 128;
+ MaxAtomicInlineWidth = 64;
}
virtual const char *getVAListDeclaration() const {
return "typedef struct __va_list_tag {"
@@ -1853,7 +2315,7 @@ public:
// mingw32-gcc provides __declspec(a) as alias of __attribute__((a)).
// In contrast, clang-cc1 provides __declspec(a) with -fms-extensions.
- if (Opts.Microsoft)
+ if (Opts.MicrosoftExt)
// Provide "as-is" __declspec.
Builder.defineMacro("__declspec", "__declspec");
else
@@ -1932,15 +2394,19 @@ public:
// so set preferred for small types to 32.
DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-"
- "v64:64:64-v128:64:128-a0:0:32-n32");
+ "v64:64:64-v128:64:128-a0:0:32-n32-S64");
} else {
DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-"
- "v64:64:64-v128:64:128-a0:0:64-n32");
+ "v64:64:64-v128:64:128-a0:0:64-n32-S64");
}
// ARM targets default to using the ARM C++ ABI.
CXXABI = CXXABI_ARM;
+
+ // ARM has atomics up to 8 bytes
+ // FIXME: Set MaxAtomicInlineWidth if we have the feature v6e
+ MaxAtomicPromoteWidth = 64;
}
virtual const char *getABI() const { return ABI.c_str(); }
virtual bool setABI(const std::string &Name) {
@@ -1958,16 +2424,27 @@ public:
// structures. This corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc.
UseBitFieldTypeAlignment = false;
+ /// Do force alignment of members that follow zero length bitfields. If
+ /// the alignment of the zero-length bitfield is greater than the member
+ /// that follows it, `bar', `bar' will be aligned as the type of the
+ /// zero length bitfield.
+ UseZeroLengthBitfieldAlignment = true;
+
+ /// gcc forces the alignment to 4 bytes, regardless of the type of the
+ /// zero length bitfield. This corresponds to EMPTY_FIELD_BOUNDARY in
+ /// gcc.
+ ZeroLengthBitfieldBoundary = 32;
+
if (IsThumb) {
// Thumb1 add sp, #imm requires the immediate value be multiple of 4,
// so set preferred for small types to 32.
DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-"
"i64:32:64-f32:32:32-f64:32:64-"
- "v64:32:64-v128:32:128-a0:0:32-n32");
+ "v64:32:64-v128:32:128-a0:0:32-n32-S32");
} else {
DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:32:64-f32:32:32-f64:32:64-"
- "v64:32:64-v128:32:128-a0:0:32-n32");
+ "v64:32:64-v128:32:128-a0:0:32-n32-S32");
}
// FIXME: Override "preferred align" for double and long long.
@@ -1981,8 +2458,7 @@ public:
return true;
}
- void getDefaultFeatures(const std::string &CPU,
- llvm::StringMap<bool> &Features) const {
+ void getDefaultFeatures(llvm::StringMap<bool> &Features) const {
if (CPU == "arm1136jf-s" || CPU == "arm1176jzf-s" || CPU == "mpcore")
Features["vfp2"] = true;
else if (CPU == "cortex-a8" || CPU == "cortex-a9")
@@ -2027,7 +2503,7 @@ public:
Features.erase(it);
}
- static const char *getCPUDefineSuffix(llvm::StringRef Name) {
+ static const char *getCPUDefineSuffix(StringRef Name) {
return llvm::StringSwitch<const char*>(Name)
.Cases("arm8", "arm810", "4")
.Cases("strongarm", "strongarm110", "strongarm1100", "strongarm1110", "4")
@@ -2066,7 +2542,7 @@ public:
Builder.defineMacro("__LITTLE_ENDIAN__");
Builder.defineMacro("__REGISTER_PREFIX__", "");
- llvm::StringRef CPUArch = getCPUDefineSuffix(CPU);
+ StringRef CPUArch = getCPUDefineSuffix(CPU);
Builder.defineMacro("__ARM_ARCH_" + CPUArch + "__");
// Subtarget options.
@@ -2129,6 +2605,9 @@ public:
case 'P': // VFP Floating point register double precision
Info.setAllowsRegister();
return true;
+ case 'Q': // A memory address that is a single base register.
+ Info.setAllowsMemory();
+ return true;
case 'U': // a memory reference...
switch (Name[1]) {
case 'q': // ...ARMV4 ldrsb
@@ -2245,6 +2724,9 @@ public:
DarwinARMTargetInfo(const std::string& triple)
: DarwinTargetInfo<ARMTargetInfo>(triple) {
HasAlignMac68kSupport = true;
+ // iOS always has 64-bit atomic instructions.
+ // FIXME: This should be based off of the target features in ARMTargetInfo.
+ MaxAtomicInlineWidth = 64;
}
};
} // end anonymous namespace.
@@ -2590,6 +3072,12 @@ namespace {
// target processor and program binary. TCE co-design environment is
// publicly available in http://tce.cs.tut.fi
+ static const unsigned TCEOpenCLAddrSpaceMap[] = {
+ 3, // opencl_global
+ 4, // opencl_local
+ 5 // opencl_constant
+ };
+
class TCETargetInfo : public TargetInfo{
public:
TCETargetInfo(const std::string& triple) : TargetInfo(triple) {
@@ -2618,6 +3106,7 @@ namespace {
"i16:16:32-i32:32:32-i64:32:32-"
"f32:32:32-f64:32:32-v64:32:32-"
"v128:32:32-a0:0:32-n32";
+ AddrSpaceMap = &TCEOpenCLAddrSpaceMap;
}
virtual void getTargetDefines(const LangOptions &Opts,
@@ -2646,51 +3135,30 @@ namespace {
}
namespace {
-class MipsTargetInfo : public TargetInfo {
- std::string ABI, CPU;
- static const TargetInfo::GCCRegAlias GCCRegAliases[];
- static const char * const GCCRegNames[];
+class MipsTargetInfoBase : public TargetInfo {
+ std::string CPU;
+protected:
+ std::string ABI;
public:
- MipsTargetInfo(const std::string& triple) : TargetInfo(triple), ABI("o32") {
- 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";
+ MipsTargetInfoBase(const std::string& triple, const std::string& ABIStr)
+ : TargetInfo(triple), ABI(ABIStr) {
SizeType = UnsignedInt;
PtrDiffType = SignedInt;
}
virtual const char *getABI() const { return ABI.c_str(); }
- virtual bool setABI(const std::string &Name) {
-
- if ((Name == "o32") || (Name == "eabi")) {
- ABI = Name;
- return true;
- } else
- return false;
- }
+ virtual bool setABI(const std::string &Name) = 0;
virtual bool setCPU(const std::string &Name) {
CPU = Name;
return true;
}
- void getDefaultFeatures(const std::string &CPU,
- llvm::StringMap<bool> &Features) const {
+ void getDefaultFeatures(llvm::StringMap<bool> &Features) const {
Features[ABI] = true;
Features[CPU] = true;
}
virtual void getArchDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- if (ABI == "o32")
- Builder.defineMacro("__mips_o32");
- else if (ABI == "eabi")
- Builder.defineMacro("__mips_eabi");
- }
+ MacroBuilder &Builder) const = 0;
virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- DefineStd(Builder, "mips", Opts);
- Builder.defineMacro("_mips");
- DefineStd(Builder, "MIPSEB", Opts);
- Builder.defineMacro("_MIPSEB");
- Builder.defineMacro("__REGISTER_PREFIX__", "");
- getArchDefines(Opts, Builder);
- }
+ MacroBuilder &Builder) const = 0;
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
// FIXME: Implement!
@@ -2699,9 +3167,24 @@ public:
return "typedef void* __builtin_va_list;";
}
virtual void getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const;
+ unsigned &NumNames) const {
+ static const char * const GCCRegNames[] = {
+ "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
+ "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
+ "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
+ "$24", "$25", "$26", "$27", "$28", "$sp", "$fp", "$31",
+ "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
+ "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
+ "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
+ "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
+ "hi", "lo", "", "$fcc0","$fcc1","$fcc2","$fcc3","$fcc4",
+ "$fcc5","$fcc6","$fcc7"
+ };
+ Names = GCCRegNames;
+ NumNames = llvm::array_lengthof(GCCRegNames);
+ }
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const;
+ unsigned &NumAliases) const = 0;
virtual bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &Info) const {
switch (*Name) {
@@ -2722,89 +3205,296 @@ public:
}
};
-const char * const MipsTargetInfo::GCCRegNames[] = {
- "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
- "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
- "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
- "$24", "$25", "$26", "$27", "$28", "$sp", "$fp", "$31",
- "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
- "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
- "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
- "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
- "hi", "lo", "", "$fcc0","$fcc1","$fcc2","$fcc3","$fcc4",
- "$fcc5","$fcc6","$fcc7"
+class Mips32TargetInfoBase : public MipsTargetInfoBase {
+public:
+ Mips32TargetInfoBase(const std::string& triple) :
+ MipsTargetInfoBase(triple, "o32") {}
+ virtual bool setABI(const std::string &Name) {
+ if ((Name == "o32") || (Name == "eabi")) {
+ ABI = Name;
+ return true;
+ } else
+ return false;
+ }
+ virtual void getArchDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ if (ABI == "o32") {
+ Builder.defineMacro("__mips_o32");
+ Builder.defineMacro("_ABIO32", "1");
+ Builder.defineMacro("_MIPS_SIM", "_ABIO32");
+ }
+ else if (ABI == "eabi")
+ Builder.defineMacro("__mips_eabi");
+ else
+ llvm_unreachable("Invalid ABI for Mips32.");
+ }
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ static const TargetInfo::GCCRegAlias GCCRegAliases[] = {
+ { { "at" }, "$1" },
+ { { "v0" }, "$2" },
+ { { "v1" }, "$3" },
+ { { "a0" }, "$4" },
+ { { "a1" }, "$5" },
+ { { "a2" }, "$6" },
+ { { "a3" }, "$7" },
+ { { "t0" }, "$8" },
+ { { "t1" }, "$9" },
+ { { "t2" }, "$10" },
+ { { "t3" }, "$11" },
+ { { "t4" }, "$12" },
+ { { "t5" }, "$13" },
+ { { "t6" }, "$14" },
+ { { "t7" }, "$15" },
+ { { "s0" }, "$16" },
+ { { "s1" }, "$17" },
+ { { "s2" }, "$18" },
+ { { "s3" }, "$19" },
+ { { "s4" }, "$20" },
+ { { "s5" }, "$21" },
+ { { "s6" }, "$22" },
+ { { "s7" }, "$23" },
+ { { "t8" }, "$24" },
+ { { "t9" }, "$25" },
+ { { "k0" }, "$26" },
+ { { "k1" }, "$27" },
+ { { "gp" }, "$28" },
+ { { "sp" }, "$29" },
+ { { "fp" }, "$30" },
+ { { "ra" }, "$31" }
+ };
+ Aliases = GCCRegAliases;
+ NumAliases = llvm::array_lengthof(GCCRegAliases);
+ }
};
-void MipsTargetInfo::getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const {
- Names = GCCRegNames;
- NumNames = llvm::array_lengthof(GCCRegNames);
-}
+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";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "mips", Opts);
+ Builder.defineMacro("_mips");
+ DefineStd(Builder, "MIPSEB", Opts);
+ Builder.defineMacro("_MIPSEB");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
+ getArchDefines(Opts, Builder);
+ }
+};
-const TargetInfo::GCCRegAlias MipsTargetInfo::GCCRegAliases[] = {
- { { "at" }, "$1" },
- { { "v0" }, "$2" },
- { { "v1" }, "$3" },
- { { "a0" }, "$4" },
- { { "a1" }, "$5" },
- { { "a2" }, "$6" },
- { { "a3" }, "$7" },
- { { "t0" }, "$8" },
- { { "t1" }, "$9" },
- { { "t2" }, "$10" },
- { { "t3" }, "$11" },
- { { "t4" }, "$12" },
- { { "t5" }, "$13" },
- { { "t6" }, "$14" },
- { { "t7" }, "$15" },
- { { "s0" }, "$16" },
- { { "s1" }, "$17" },
- { { "s2" }, "$18" },
- { { "s3" }, "$19" },
- { { "s4" }, "$20" },
- { { "s5" }, "$21" },
- { { "s6" }, "$22" },
- { { "s7" }, "$23" },
- { { "t8" }, "$24" },
- { { "t9" }, "$25" },
- { { "k0" }, "$26" },
- { { "k1" }, "$27" },
- { { "gp" }, "$28" },
- { { "sp" }, "$29" },
- { { "fp" }, "$30" },
- { { "ra" }, "$31" }
+class Mips32ELTargetInfo : public Mips32TargetInfoBase {
+public:
+ Mips32ELTargetInfo(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";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "mips", Opts);
+ Builder.defineMacro("_mips");
+ DefineStd(Builder, "MIPSEL", Opts);
+ Builder.defineMacro("_MIPSEL");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
+ getArchDefines(Opts, Builder);
+ }
};
-void MipsTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const {
- Aliases = GCCRegAliases;
- NumAliases = llvm::array_lengthof(GCCRegAliases);
-}
+class Mips64TargetInfoBase : public MipsTargetInfoBase {
+ virtual void SetDescriptionString(const std::string &Name) = 0;
+public:
+ Mips64TargetInfoBase(const std::string& triple) :
+ MipsTargetInfoBase(triple, "n64") {}
+ virtual bool setABI(const std::string &Name) {
+ SetDescriptionString(Name);
+ if ((Name == "n32") || (Name == "n64")) {
+ ABI = Name;
+ return true;
+ } else
+ return false;
+ }
+ virtual void getArchDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ if (ABI == "n32") {
+ Builder.defineMacro("__mips_n32");
+ Builder.defineMacro("_ABIN32", "2");
+ Builder.defineMacro("_MIPS_SIM", "_ABIN32");
+ }
+ else if (ABI == "n64") {
+ Builder.defineMacro("__mips_n64");
+ Builder.defineMacro("_ABI64", "3");
+ Builder.defineMacro("_MIPS_SIM", "_ABI64");
+ }
+ else
+ llvm_unreachable("Invalid ABI for Mips64.");
+ }
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ static const TargetInfo::GCCRegAlias GCCRegAliases[] = {
+ { { "at" }, "$1" },
+ { { "v0" }, "$2" },
+ { { "v1" }, "$3" },
+ { { "a0" }, "$4" },
+ { { "a1" }, "$5" },
+ { { "a2" }, "$6" },
+ { { "a3" }, "$7" },
+ { { "a4" }, "$8" },
+ { { "a5" }, "$9" },
+ { { "a6" }, "$10" },
+ { { "a7" }, "$11" },
+ { { "t0" }, "$12" },
+ { { "t1" }, "$13" },
+ { { "t2" }, "$14" },
+ { { "t3" }, "$15" },
+ { { "s0" }, "$16" },
+ { { "s1" }, "$17" },
+ { { "s2" }, "$18" },
+ { { "s3" }, "$19" },
+ { { "s4" }, "$20" },
+ { { "s5" }, "$21" },
+ { { "s6" }, "$22" },
+ { { "s7" }, "$23" },
+ { { "t8" }, "$24" },
+ { { "t9" }, "$25" },
+ { { "k0" }, "$26" },
+ { { "k1" }, "$27" },
+ { { "gp" }, "$28" },
+ { { "sp" }, "$29" },
+ { { "fp" }, "$30" },
+ { { "ra" }, "$31" }
+ };
+ Aliases = GCCRegAliases;
+ NumAliases = llvm::array_lengthof(GCCRegAliases);
+ }
+};
+
+class Mips64EBTargetInfo : public Mips64TargetInfoBase {
+ virtual void SetDescriptionString(const std::string &Name) {
+ // Change DescriptionString only if ABI is n32.
+ 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-v64:64:64-n32";
+ }
+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-v64:64:64-n32";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "mips", Opts);
+ Builder.defineMacro("_mips");
+ DefineStd(Builder, "MIPSEB", Opts);
+ Builder.defineMacro("_MIPSEB");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
+ getArchDefines(Opts, Builder);
+ }
+};
+
+class Mips64ELTargetInfo : public Mips64TargetInfoBase {
+ virtual void SetDescriptionString(const std::string &Name) {
+ // Change DescriptionString only if ABI is n32.
+ 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-v64:64:64-n32";
+ }
+public:
+ Mips64ELTargetInfo(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-v64:64:64-n32";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "mips", Opts);
+ Builder.defineMacro("_mips");
+ DefineStd(Builder, "MIPSEL", Opts);
+ Builder.defineMacro("_MIPSEL");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
+ getArchDefines(Opts, Builder);
+ }
+};
} // end anonymous namespace.
namespace {
-class MipselTargetInfo : public MipsTargetInfo {
+class PNaClTargetInfo : public TargetInfo {
public:
- MipselTargetInfo(const std::string& triple) : MipsTargetInfo(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";
+ PNaClTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ this->UserLabelPrefix = "";
+ this->LongAlign = 32;
+ this->LongWidth = 32;
+ this->PointerAlign = 32;
+ this->PointerWidth = 32;
+ this->IntMaxType = TargetInfo::SignedLongLong;
+ this->UIntMaxType = TargetInfo::UnsignedLongLong;
+ this->Int64Type = TargetInfo::SignedLongLong;
+ this->DoubleAlign = 64;
+ this->LongDoubleWidth = 64;
+ this->LongDoubleAlign = 64;
+ this->SizeType = TargetInfo::UnsignedInt;
+ this->PtrDiffType = TargetInfo::SignedInt;
+ this->IntPtrType = TargetInfo::SignedInt;
+ this->RegParmMax = 2;
+ DescriptionString = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"
+ "f32:32:32-f64:64:64-p:32:32:32-v128:32:32";
}
+ void getDefaultFeatures(llvm::StringMap<bool> &Features) const {
+ }
+ virtual void getArchDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__le32__");
+ Builder.defineMacro("__pnacl__");
+ }
virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const;
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "unix", Opts);
+ Builder.defineMacro("__ELF__");
+ if (Opts.POSIXThreads)
+ Builder.defineMacro("_REENTRANT");
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("_GNU_SOURCE");
+
+ Builder.defineMacro("__native_client__");
+ getArchDefines(Opts, Builder);
+ }
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ }
+ virtual const char *getVAListDeclaration() const {
+ return "typedef int __builtin_va_list[4];";
+ }
+ virtual void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const;
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const;
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const {
+ return false;
+ }
+
+ virtual const char *getClobbers() const {
+ return "";
+ }
};
-void MipselTargetInfo::getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- DefineStd(Builder, "mips", Opts);
- Builder.defineMacro("_mips");
- DefineStd(Builder, "MIPSEL", Opts);
- Builder.defineMacro("_MIPSEL");
- Builder.defineMacro("__REGISTER_PREFIX__", "");
- getArchDefines(Opts, Builder);
+void PNaClTargetInfo::getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {
+ Names = NULL;
+ NumNames = 0;
+}
+
+void PNaClTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ Aliases = NULL;
+ NumAliases = 0;
}
} // end anonymous namespace.
+
//===----------------------------------------------------------------------===//
// Driver code
//===----------------------------------------------------------------------===//
@@ -2845,40 +3535,74 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::mips:
switch (os) {
- case llvm::Triple::Psp:
- return new PSPTargetInfo<MipsTargetInfo>(T);
case llvm::Triple::Linux:
- return new LinuxTargetInfo<MipsTargetInfo>(T);
+ return new LinuxTargetInfo<Mips32EBTargetInfo>(T);
case llvm::Triple::RTEMS:
- return new RTEMSTargetInfo<MipsTargetInfo>(T);
+ return new RTEMSTargetInfo<Mips32EBTargetInfo>(T);
case llvm::Triple::FreeBSD:
- return new FreeBSDTargetInfo<MipsTargetInfo>(T);
+ return new FreeBSDTargetInfo<Mips32EBTargetInfo>(T);
case llvm::Triple::NetBSD:
- return new NetBSDTargetInfo<MipsTargetInfo>(T);
+ return new NetBSDTargetInfo<Mips32EBTargetInfo>(T);
default:
- return new MipsTargetInfo(T);
+ return new Mips32EBTargetInfo(T);
}
case llvm::Triple::mipsel:
switch (os) {
- case llvm::Triple::Psp:
- return new PSPTargetInfo<MipselTargetInfo>(T);
case llvm::Triple::Linux:
- return new LinuxTargetInfo<MipselTargetInfo>(T);
+ return new LinuxTargetInfo<Mips32ELTargetInfo>(T);
case llvm::Triple::RTEMS:
- return new RTEMSTargetInfo<MipselTargetInfo>(T);
+ return new RTEMSTargetInfo<Mips32ELTargetInfo>(T);
case llvm::Triple::FreeBSD:
- return new FreeBSDTargetInfo<MipselTargetInfo>(T);
+ return new FreeBSDTargetInfo<Mips32ELTargetInfo>(T);
case llvm::Triple::NetBSD:
- return new NetBSDTargetInfo<MipselTargetInfo>(T);
+ return new NetBSDTargetInfo<Mips32ELTargetInfo>(T);
default:
- return new MipsTargetInfo(T);
+ return new Mips32ELTargetInfo(T);
+ }
+
+ case llvm::Triple::mips64:
+ switch (os) {
+ case llvm::Triple::Linux:
+ return new LinuxTargetInfo<Mips64EBTargetInfo>(T);
+ case llvm::Triple::RTEMS:
+ return new RTEMSTargetInfo<Mips64EBTargetInfo>(T);
+ case llvm::Triple::FreeBSD:
+ return new FreeBSDTargetInfo<Mips64EBTargetInfo>(T);
+ case llvm::Triple::NetBSD:
+ return new NetBSDTargetInfo<Mips64EBTargetInfo>(T);
+ default:
+ return new Mips64EBTargetInfo(T);
+ }
+
+ case llvm::Triple::mips64el:
+ switch (os) {
+ case llvm::Triple::Linux:
+ return new LinuxTargetInfo<Mips64ELTargetInfo>(T);
+ case llvm::Triple::RTEMS:
+ return new RTEMSTargetInfo<Mips64ELTargetInfo>(T);
+ case llvm::Triple::FreeBSD:
+ return new FreeBSDTargetInfo<Mips64ELTargetInfo>(T);
+ case llvm::Triple::NetBSD:
+ return new NetBSDTargetInfo<Mips64ELTargetInfo>(T);
+ default:
+ return new Mips64ELTargetInfo(T);
+ }
+
+ case llvm::Triple::le32:
+ switch (os) {
+ case llvm::Triple::NativeClient:
+ return new PNaClTargetInfo(T);
+ default:
+ return NULL;
}
case llvm::Triple::ppc:
if (Triple.isOSDarwin())
return new DarwinPPC32TargetInfo(T);
switch (os) {
+ case llvm::Triple::Linux:
+ return new LinuxTargetInfo<PPC32TargetInfo>(T);
case llvm::Triple::FreeBSD:
return new FreeBSDTargetInfo<PPC32TargetInfo>(T);
case llvm::Triple::NetBSD:
@@ -2893,6 +3617,8 @@ static TargetInfo *AllocateTarget(const std::string &T) {
if (Triple.isOSDarwin())
return new DarwinPPC64TargetInfo(T);
switch (os) {
+ case llvm::Triple::Linux:
+ return new LinuxTargetInfo<PPC64TargetInfo>(T);
case llvm::Triple::Lv2:
return new PS3PPUTargetInfo<PPC64TargetInfo>(T);
case llvm::Triple::FreeBSD:
@@ -2913,6 +3639,8 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::sparc:
switch (os) {
+ case llvm::Triple::Linux:
+ return new LinuxTargetInfo<SparcV8TargetInfo>(T);
case llvm::Triple::AuroraUX:
return new AuroraUXSparcV8TargetInfo(T);
case llvm::Triple::Solaris:
@@ -3001,7 +3729,7 @@ static TargetInfo *AllocateTarget(const std::string &T) {
/// CreateTargetInfo - Return the target info object for the specified target
/// triple.
-TargetInfo *TargetInfo::CreateTargetInfo(Diagnostic &Diags,
+TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
TargetOptions &Opts) {
llvm::Triple Triple(Opts.Triple);
@@ -3033,7 +3761,7 @@ TargetInfo *TargetInfo::CreateTargetInfo(Diagnostic &Diags,
// Compute the default target features, we need the target to handle this
// because features may have dependencies on one another.
llvm::StringMap<bool> Features;
- Target->getDefaultFeatures(Opts.CPU, Features);
+ Target->getDefaultFeatures(Features);
// Apply the user specified deltas.
for (std::vector<std::string>::const_iterator it = Opts.Features.begin(),
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index 8f713524629c..4705eda02e28 100644
--- a/lib/Basic/Version.cpp
+++ b/lib/Basic/Version.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/Version.h"
+#include "clang/Basic/LLVM.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Config/config.h"
#include <cstring>
@@ -24,14 +25,14 @@ std::string getClangRepositoryPath() {
return CLANG_REPOSITORY_STRING;
#else
#ifdef SVN_REPOSITORY
- llvm::StringRef URL(SVN_REPOSITORY);
+ StringRef URL(SVN_REPOSITORY);
#else
- llvm::StringRef URL("");
+ StringRef URL("");
#endif
// 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 llvm::StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $");
+ static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/branches/release_30/lib/Basic/Version.cpp $");
if (URL.empty()) {
URL = SVNRepository.slice(SVNRepository.find(':'),
SVNRepository.find("/lib/Basic"));
@@ -42,7 +43,7 @@ std::string getClangRepositoryPath() {
// Trim path prefix off, assuming path came from standard cfe path.
size_t Start = URL.find("cfe/");
- if (Start != llvm::StringRef::npos)
+ if (Start != StringRef::npos)
URL = URL.substr(Start + 4);
return URL;
diff --git a/lib/Basic/VersionTuple.cpp b/lib/Basic/VersionTuple.cpp
index d5cf126ff487..77aad39cbf2c 100644
--- a/lib/Basic/VersionTuple.cpp
+++ b/lib/Basic/VersionTuple.cpp
@@ -25,7 +25,7 @@ std::string VersionTuple::getAsString() const {
return Result;
}
-llvm::raw_ostream& clang::operator<<(llvm::raw_ostream &Out,
+raw_ostream& clang::operator<<(raw_ostream &Out,
const VersionTuple &V) {
Out << V.getMajor();
if (llvm::Optional<unsigned> Minor = V.getMinor())
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index 85f42db81f59..b9e3ed9edd19 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -15,6 +15,7 @@
#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"
@@ -23,21 +24,24 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/PassManagerBuilder.h"
+#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetData.h"
+#include "llvm/Target/TargetLibraryInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
-#include "llvm/Target/TargetRegistry.h"
#include "llvm/Transforms/Instrumentation.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Scalar.h"
using namespace clang;
using namespace llvm;
namespace {
class EmitAssemblyHelper {
- Diagnostic &Diags;
+ DiagnosticsEngine &Diags;
const CodeGenOptions &CodeGenOpts;
const TargetOptions &TargetOpts;
const LangOptions &LangOpts;
@@ -82,7 +86,7 @@ private:
bool AddEmitPasses(BackendAction Action, formatted_raw_ostream &OS);
public:
- EmitAssemblyHelper(Diagnostic &_Diags,
+ EmitAssemblyHelper(DiagnosticsEngine &_Diags,
const CodeGenOptions &CGOpts, const TargetOptions &TOpts,
const LangOptions &LOpts,
Module *M)
@@ -237,27 +241,18 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
TargetMachine::setDataSections (CodeGenOpts.DataSections);
// FIXME: Parse this earlier.
- if (CodeGenOpts.RelocationModel == "static") {
- TargetMachine::setRelocationModel(llvm::Reloc::Static);
- } else if (CodeGenOpts.RelocationModel == "pic") {
- TargetMachine::setRelocationModel(llvm::Reloc::PIC_);
- } else {
- assert(CodeGenOpts.RelocationModel == "dynamic-no-pic" &&
- "Invalid PIC model!");
- TargetMachine::setRelocationModel(llvm::Reloc::DynamicNoPIC);
- }
- // FIXME: Parse this earlier.
+ llvm::CodeModel::Model CM;
if (CodeGenOpts.CodeModel == "small") {
- TargetMachine::setCodeModel(llvm::CodeModel::Small);
+ CM = llvm::CodeModel::Small;
} else if (CodeGenOpts.CodeModel == "kernel") {
- TargetMachine::setCodeModel(llvm::CodeModel::Kernel);
+ CM = llvm::CodeModel::Kernel;
} else if (CodeGenOpts.CodeModel == "medium") {
- TargetMachine::setCodeModel(llvm::CodeModel::Medium);
+ CM = llvm::CodeModel::Medium;
} else if (CodeGenOpts.CodeModel == "large") {
- TargetMachine::setCodeModel(llvm::CodeModel::Large);
+ CM = llvm::CodeModel::Large;
} else {
assert(CodeGenOpts.CodeModel.empty() && "Invalid code model!");
- TargetMachine::setCodeModel(llvm::CodeModel::Default);
+ CM = llvm::CodeModel::Default;
}
std::vector<const char *> BackendArgs;
@@ -274,6 +269,8 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
BackendArgs.push_back("-time-passes");
for (unsigned i = 0, e = CodeGenOpts.BackendOptions.size(); i != e; ++i)
BackendArgs.push_back(CodeGenOpts.BackendOptions[i].c_str());
+ if (CodeGenOpts.NoGlobalMerge)
+ BackendArgs.push_back("-global-merge=false");
BackendArgs.push_back(0);
llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1,
const_cast<char **>(&BackendArgs[0]));
@@ -287,8 +284,20 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
Features.AddFeature(*it);
FeaturesStr = Features.getString();
}
+
+ llvm::Reloc::Model RM = llvm::Reloc::Default;
+ if (CodeGenOpts.RelocationModel == "static") {
+ RM = llvm::Reloc::Static;
+ } else if (CodeGenOpts.RelocationModel == "pic") {
+ RM = llvm::Reloc::PIC_;
+ } else {
+ assert(CodeGenOpts.RelocationModel == "dynamic-no-pic" &&
+ "Invalid PIC model!");
+ RM = llvm::Reloc::DynamicNoPIC;
+ }
+
TargetMachine *TM = TheTarget->createTargetMachine(Triple, TargetOpts.CPU,
- FeaturesStr);
+ FeaturesStr, RM, CM);
if (CodeGenOpts.RelaxAll)
TM->setMCRelaxAll(true);
@@ -386,7 +395,8 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) {
}
}
-void clang::EmitBackendOutput(Diagnostic &Diags, const CodeGenOptions &CGOpts,
+void clang::EmitBackendOutput(DiagnosticsEngine &Diags,
+ const CodeGenOptions &CGOpts,
const TargetOptions &TOpts,
const LangOptions &LOpts,
Module *M,
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 9815d1d4ef4d..969495376642 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -59,10 +59,10 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM,
const CGBlockInfo &blockInfo) {
ASTContext &C = CGM.getContext();
- const llvm::Type *ulong = CGM.getTypes().ConvertType(C.UnsignedLongTy);
- const llvm::Type *i8p = CGM.getTypes().ConvertType(C.VoidPtrTy);
+ llvm::Type *ulong = CGM.getTypes().ConvertType(C.UnsignedLongTy);
+ llvm::Type *i8p = CGM.getTypes().ConvertType(C.VoidPtrTy);
- llvm::SmallVector<llvm::Constant*, 6> elements;
+ SmallVector<llvm::Constant*, 6> elements;
// reserved
elements.push_back(llvm::ConstantInt::get(ulong, 0));
@@ -243,7 +243,7 @@ static CharUnits getLowBit(CharUnits v) {
}
static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info,
- llvm::SmallVectorImpl<llvm::Type*> &elementTypes) {
+ SmallVectorImpl<llvm::Type*> &elementTypes) {
ASTContext &C = CGM.getContext();
// The header is basically a 'struct { void *; int; int; void *; void *; }'.
@@ -280,7 +280,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
ASTContext &C = CGM.getContext();
const BlockDecl *block = info.getBlockDecl();
- llvm::SmallVector<llvm::Type*, 8> elementTypes;
+ SmallVector<llvm::Type*, 8> elementTypes;
initializeForBlockHeader(CGM, info, elementTypes);
if (!block->hasCaptures()) {
@@ -291,7 +291,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
}
// Collect the layout chunks.
- llvm::SmallVector<BlockLayoutChunk, 16> layout;
+ SmallVector<BlockLayoutChunk, 16> layout;
layout.reserve(block->capturesCXXThis() +
(block->capture_end() - block->capture_begin()));
@@ -422,7 +422,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
// which has 7 bytes of padding, as opposed to the naive solution
// which might have less (?).
if (endAlign < maxFieldAlign) {
- llvm::SmallVectorImpl<BlockLayoutChunk>::iterator
+ SmallVectorImpl<BlockLayoutChunk>::iterator
li = layout.begin() + 1, le = layout.end();
// Look for something that the header end is already
@@ -433,7 +433,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
// If we found something that's naturally aligned for the end of
// the header, keep adding things...
if (li != le) {
- llvm::SmallVectorImpl<BlockLayoutChunk>::iterator first = li;
+ SmallVectorImpl<BlockLayoutChunk>::iterator first = li;
for (; li != le; ++li) {
assert(endAlign >= li->Alignment);
@@ -468,7 +468,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
// Slam everything else on now. This works because they have
// strictly decreasing alignment and we expect that size is always a
// multiple of alignment.
- for (llvm::SmallVectorImpl<BlockLayoutChunk>::iterator
+ for (SmallVectorImpl<BlockLayoutChunk>::iterator
li = layout.begin(), le = layout.end(); li != le; ++li) {
assert(endAlign >= li->Alignment);
li->setIndex(info, elementTypes.size());
@@ -507,7 +507,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
// Build the block descriptor.
llvm::Constant *descriptor = buildBlockDescriptor(CGM, blockInfo);
- const llvm::Type *intTy = ConvertType(getContext().IntTy);
+ llvm::Type *intTy = ConvertType(getContext().IntTy);
llvm::AllocaInst *blockAddr =
CreateTempAlloca(blockInfo.StructureType, "block");
@@ -617,10 +617,9 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
ImplicitCastExpr l2r(ImplicitCastExpr::OnStack, type, CK_LValueToRValue,
declRef, VK_RValue);
EmitExprAsInit(&l2r, &blockFieldPseudoVar,
- LValue::MakeAddr(blockField, type,
- getContext().getDeclAlign(variable)
- .getQuantity(),
- getContext()),
+ MakeAddrLValue(blockField, type,
+ getContext().getDeclAlign(variable)
+ .getQuantity()),
/*captured by init*/ false);
}
@@ -681,8 +680,8 @@ llvm::Type *CodeGenModule::getBlockDescriptorType() {
// const char *layout; // reserved
// };
BlockDescriptorType =
- llvm::StructType::createNamed("struct.__block_descriptor",
- UnsignedLongTy, UnsignedLongTy, NULL);
+ llvm::StructType::create("struct.__block_descriptor",
+ UnsignedLongTy, UnsignedLongTy, NULL);
// Now form a pointer to that.
BlockDescriptorType = llvm::PointerType::getUnqual(BlockDescriptorType);
@@ -703,13 +702,9 @@ llvm::Type *CodeGenModule::getGenericBlockLiteralType() {
// struct __block_descriptor *__descriptor;
// };
GenericBlockLiteralType =
- llvm::StructType::createNamed("struct.__block_literal_generic",
- VoidPtrTy,
- IntTy,
- IntTy,
- VoidPtrTy,
- BlockDescPtrTy,
- NULL);
+ llvm::StructType::create("struct.__block_literal_generic",
+ VoidPtrTy, IntTy, IntTy, VoidPtrTy,
+ BlockDescPtrTy, NULL);
return GenericBlockLiteralType;
}
@@ -723,7 +718,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
llvm::Value *Callee = EmitScalarExpr(E->getCallee());
// Get a pointer to the generic block literal.
- const llvm::Type *BlockLiteralTy =
+ llvm::Type *BlockLiteralTy =
llvm::PointerType::getUnqual(CGM.getGenericBlockLiteralType());
// Bitcast the callee to a block literal.
@@ -731,9 +726,9 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
Builder.CreateBitCast(Callee, BlockLiteralTy, "block.literal");
// Get the function pointer from the literal.
- llvm::Value *FuncPtr = Builder.CreateStructGEP(BlockLiteral, 3, "tmp");
+ llvm::Value *FuncPtr = Builder.CreateStructGEP(BlockLiteral, 3);
- BlockLiteral = Builder.CreateBitCast(BlockLiteral, VoidPtrTy, "tmp");
+ BlockLiteral = Builder.CreateBitCast(BlockLiteral, VoidPtrTy);
// Add the block literal.
CallArgList Args;
@@ -746,20 +741,16 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
E->arg_begin(), E->arg_end());
// Load the function.
- llvm::Value *Func = Builder.CreateLoad(FuncPtr, "tmp");
+ llvm::Value *Func = Builder.CreateLoad(FuncPtr);
const FunctionType *FuncTy = FnType->castAs<FunctionType>();
- QualType ResultType = FuncTy->getResultType();
-
- const CGFunctionInfo &FnInfo =
- CGM.getTypes().getFunctionInfo(ResultType, Args,
- FuncTy->getExtInfo());
+ const CGFunctionInfo &FnInfo = CGM.getTypes().getFunctionInfo(Args, FuncTy);
// Cast the function pointer to the right type.
- const llvm::Type *BlockFTy =
+ llvm::Type *BlockFTy =
CGM.getTypes().GetFunctionType(FnInfo, false);
- const llvm::Type *BlockFTyPtr = llvm::PointerType::getUnqual(BlockFTy);
+ llvm::Type *BlockFTyPtr = llvm::PointerType::getUnqual(BlockFTy);
Func = Builder.CreateBitCast(Func, BlockFTyPtr);
// And call the block.
@@ -783,7 +774,7 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const VarDecl *variable,
// to byref*.
addr = Builder.CreateLoad(addr);
- const llvm::PointerType *byrefPointerType
+ llvm::PointerType *byrefPointerType
= llvm::PointerType::get(BuildByRefType(variable), 0);
addr = Builder.CreateBitCast(addr, byrefPointerType,
"byref.addr");
@@ -863,7 +854,7 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
literal->setAlignment(blockInfo.BlockAlign.getQuantity());
// Return a constant of the appropriately-casted type.
- const llvm::Type *requiredType =
+ llvm::Type *requiredType =
CGM.getTypes().ConvertType(blockInfo.getBlockExpr()->getType());
return llvm::ConstantExpr::getBitCast(literal, requiredType);
}
@@ -918,7 +909,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
if (CGM.ReturnTypeUsesSRet(fnInfo))
blockInfo.UsesStret = true;
- const llvm::FunctionType *fnLLVMType =
+ llvm::FunctionType *fnLLVMType =
CGM.getTypes().GetFunctionType(fnInfo, fnType->isVariadic());
MangleBuffer name;
@@ -1005,7 +996,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(),
ce = blockDecl->capture_end(); ci != ce; ++ci) {
const VarDecl *variable = ci->getVariable();
- DI->setLocation(variable->getLocation());
+ DI->EmitLocation(Builder, variable->getLocation());
const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
if (capture.isConstant()) {
@@ -1065,7 +1056,7 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
// FIXME: it would be nice if these were mergeable with things with
// identical semantics.
- const llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI, false);
+ llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI, false);
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
@@ -1088,7 +1079,7 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
true);
StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
- const llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
+ llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
llvm::Value *src = GetAddrOfLocalVar(&srcDecl);
src = Builder.CreateLoad(src);
@@ -1180,7 +1171,7 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
- const llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI, false);
+ llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI, false);
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
@@ -1201,7 +1192,7 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
false, true);
StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
- const llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
+ llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
llvm::Value *src = GetAddrOfLocalVar(&srcDecl);
src = Builder.CreateLoad(src);
@@ -1399,7 +1390,7 @@ public:
static llvm::Constant *
generateByrefCopyHelper(CodeGenFunction &CGF,
- const llvm::StructType &byrefType,
+ llvm::StructType &byrefType,
CodeGenModule::ByrefHelpers &byrefInfo) {
ASTContext &Context = CGF.getContext();
@@ -1416,7 +1407,7 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
CGF.CGM.getTypes().getFunctionInfo(R, args, FunctionType::ExtInfo());
CodeGenTypes &Types = CGF.CGM.getTypes();
- const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
+ llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
@@ -1438,7 +1429,7 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
if (byrefInfo.needsCopy()) {
- const llvm::Type *byrefPtrType = byrefType.getPointerTo(0);
+ llvm::Type *byrefPtrType = byrefType.getPointerTo(0);
// dst->x
llvm::Value *destField = CGF.GetAddrOfLocalVar(&dst);
@@ -1462,7 +1453,7 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
/// Build the copy helper for a __block variable.
static llvm::Constant *buildByrefCopyHelper(CodeGenModule &CGM,
- const llvm::StructType &byrefType,
+ llvm::StructType &byrefType,
CodeGenModule::ByrefHelpers &info) {
CodeGenFunction CGF(CGM);
return generateByrefCopyHelper(CGF, byrefType, info);
@@ -1471,7 +1462,7 @@ static llvm::Constant *buildByrefCopyHelper(CodeGenModule &CGM,
/// Generate code for a __block variable's dispose helper.
static llvm::Constant *
generateByrefDisposeHelper(CodeGenFunction &CGF,
- const llvm::StructType &byrefType,
+ llvm::StructType &byrefType,
CodeGenModule::ByrefHelpers &byrefInfo) {
ASTContext &Context = CGF.getContext();
QualType R = Context.VoidTy;
@@ -1484,7 +1475,7 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
CGF.CGM.getTypes().getFunctionInfo(R, args, FunctionType::ExtInfo());
CodeGenTypes &Types = CGF.CGM.getTypes();
- const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
+ llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
@@ -1521,7 +1512,7 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
/// Build the dispose helper for a __block variable.
static llvm::Constant *buildByrefDisposeHelper(CodeGenModule &CGM,
- const llvm::StructType &byrefType,
+ llvm::StructType &byrefType,
CodeGenModule::ByrefHelpers &info) {
CodeGenFunction CGF(CGM);
return generateByrefDisposeHelper(CGF, byrefType, info);
@@ -1529,7 +1520,7 @@ static llvm::Constant *buildByrefDisposeHelper(CodeGenModule &CGM,
///
template <class T> static T *buildByrefHelpers(CodeGenModule &CGM,
- const llvm::StructType &byrefTy,
+ llvm::StructType &byrefTy,
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.
@@ -1553,7 +1544,7 @@ template <class T> static T *buildByrefHelpers(CodeGenModule &CGM,
}
CodeGenModule::ByrefHelpers *
-CodeGenFunction::buildByrefHelpers(const llvm::StructType &byrefType,
+CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
const AutoVarEmission &emission) {
const VarDecl &var = *emission.Variable;
QualType type = var.getType();
@@ -1658,18 +1649,18 @@ llvm::Value *CodeGenFunction::BuildBlockByrefAddress(llvm::Value *BaseAddr,
/// T x;
/// } x
///
-const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
- std::pair<const llvm::Type *, unsigned> &Info = ByRefValueInfo[D];
+llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
+ std::pair<llvm::Type *, unsigned> &Info = ByRefValueInfo[D];
if (Info.first)
return Info.first;
QualType Ty = D->getType();
- llvm::SmallVector<llvm::Type *, 8> types;
+ SmallVector<llvm::Type *, 8> types;
llvm::StructType *ByRefType =
- llvm::StructType::createNamed(getLLVMContext(),
- "struct.__block_byref_" + D->getNameAsString());
+ llvm::StructType::create(getLLVMContext(),
+ "struct.__block_byref_" + D->getNameAsString());
// void *__isa;
types.push_back(Int8PtrTy);
@@ -1742,7 +1733,7 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) {
llvm::Value *addr = emission.Address;
// That's an alloca of the byref structure type.
- const llvm::StructType *byrefType = cast<llvm::StructType>(
+ llvm::StructType *byrefType = cast<llvm::StructType>(
cast<llvm::PointerType>(addr->getType())->getElementType());
// Build the byref helpers if necessary. This is null if we don't need any.
@@ -1812,8 +1803,63 @@ namespace {
/// to be done externally.
void CodeGenFunction::enterByrefCleanup(const AutoVarEmission &emission) {
// We don't enter this cleanup if we're in pure-GC mode.
- if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly)
+ if (CGM.getLangOptions().getGC() == LangOptions::GCOnly)
return;
EHStack.pushCleanup<CallBlockRelease>(NormalAndEHCleanup, emission.Address);
}
+
+/// Adjust the declaration of something from the blocks API.
+static void configureBlocksRuntimeObject(CodeGenModule &CGM,
+ llvm::Constant *C) {
+ if (!CGM.getLangOptions().BlocksRuntimeOptional) return;
+
+ llvm::GlobalValue *GV = cast<llvm::GlobalValue>(C->stripPointerCasts());
+ if (GV->isDeclaration() &&
+ GV->getLinkage() == llvm::GlobalValue::ExternalLinkage)
+ GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
+}
+
+llvm::Constant *CodeGenModule::getBlockObjectDispose() {
+ if (BlockObjectDispose)
+ return BlockObjectDispose;
+
+ llvm::Type *args[] = { Int8PtrTy, Int32Ty };
+ llvm::FunctionType *fty
+ = llvm::FunctionType::get(VoidTy, args, false);
+ BlockObjectDispose = CreateRuntimeFunction(fty, "_Block_object_dispose");
+ configureBlocksRuntimeObject(*this, BlockObjectDispose);
+ return BlockObjectDispose;
+}
+
+llvm::Constant *CodeGenModule::getBlockObjectAssign() {
+ if (BlockObjectAssign)
+ return BlockObjectAssign;
+
+ llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, Int32Ty };
+ llvm::FunctionType *fty
+ = llvm::FunctionType::get(VoidTy, args, false);
+ BlockObjectAssign = CreateRuntimeFunction(fty, "_Block_object_assign");
+ configureBlocksRuntimeObject(*this, BlockObjectAssign);
+ return BlockObjectAssign;
+}
+
+llvm::Constant *CodeGenModule::getNSConcreteGlobalBlock() {
+ if (NSConcreteGlobalBlock)
+ return NSConcreteGlobalBlock;
+
+ NSConcreteGlobalBlock = GetOrCreateLLVMGlobal("_NSConcreteGlobalBlock",
+ Int8PtrTy->getPointerTo(), 0);
+ configureBlocksRuntimeObject(*this, NSConcreteGlobalBlock);
+ return NSConcreteGlobalBlock;
+}
+
+llvm::Constant *CodeGenModule::getNSConcreteStackBlock() {
+ if (NSConcreteStackBlock)
+ return NSConcreteStackBlock;
+
+ NSConcreteStackBlock = GetOrCreateLLVMGlobal("_NSConcreteStackBlock",
+ Int8PtrTy->getPointerTo(), 0);
+ configureBlocksRuntimeObject(*this, NSConcreteStackBlock);
+ return NSConcreteStackBlock;
+}
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index 4d8dead2be8c..6e71c1fdc041 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -176,7 +176,7 @@ public:
/// because it gets set later in the block-creation process.
mutable bool UsesStret : 1;
- const llvm::StructType *StructureType;
+ llvm::StructType *StructureType;
const BlockExpr *Block;
CharUnits BlockSize;
CharUnits BlockAlign;
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 1566bd9e6697..ec0ca424220e 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -27,24 +27,34 @@ using namespace clang;
using namespace CodeGen;
using namespace llvm;
-static void EmitMemoryBarrier(CodeGenFunction &CGF,
- bool LoadLoad, bool LoadStore,
- bool StoreLoad, bool StoreStore,
- bool Device) {
- Value *True = CGF.Builder.getTrue();
- Value *False = CGF.Builder.getFalse();
- Value *C[5] = { LoadLoad ? True : False,
- LoadStore ? True : False,
- StoreLoad ? True : False,
- StoreStore ? True : False,
- Device ? True : False };
- CGF.Builder.CreateCall(CGF.CGM.getIntrinsic(Intrinsic::memory_barrier), C);
+/// getBuiltinLibFunction - Given a builtin id for a function like
+/// "__builtin_fabsf", return a Function* for "fabsf".
+llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD,
+ unsigned BuiltinID) {
+ assert(Context.BuiltinInfo.isLibFunction(BuiltinID));
+
+ // Get the name, skip over the __builtin_ prefix (if necessary).
+ StringRef Name;
+ GlobalDecl D(FD);
+
+ // If the builtin has been declared explicitly with an assembler label,
+ // use the mangled name. This differs from the plain label on platforms
+ // that prefix labels.
+ if (FD->hasAttr<AsmLabelAttr>())
+ Name = getMangledName(D);
+ else
+ Name = Context.BuiltinInfo.GetName(BuiltinID) + 10;
+
+ llvm::FunctionType *Ty =
+ cast<llvm::FunctionType>(getTypes().ConvertType(FD->getType()));
+
+ return GetOrCreateLLVMFunction(Name, Ty, D, /*ForVTable=*/false);
}
/// Emit the conversions required to turn the given value into an
/// integer of the given size.
static Value *EmitToInt(CodeGenFunction &CGF, llvm::Value *V,
- QualType T, const llvm::IntegerType *IntType) {
+ QualType T, llvm::IntegerType *IntType) {
V = CGF.EmitToMemory(V, T);
if (V->getType()->isPointerTy())
@@ -55,7 +65,7 @@ static Value *EmitToInt(CodeGenFunction &CGF, llvm::Value *V,
}
static Value *EmitFromInt(CodeGenFunction &CGF, llvm::Value *V,
- QualType T, const llvm::Type *ResultType) {
+ QualType T, llvm::Type *ResultType) {
V = CGF.EmitFromMemory(V, T);
if (ResultType->isPointerTy())
@@ -65,25 +75,11 @@ static Value *EmitFromInt(CodeGenFunction &CGF, llvm::Value *V,
return V;
}
-// The atomic builtins are also full memory barriers. This is a utility for
-// wrapping a call to the builtins with memory barriers.
-static Value *EmitCallWithBarrier(CodeGenFunction &CGF, Value *Fn,
- ArrayRef<Value *> Args) {
- // FIXME: We need a target hook for whether this applies to device memory or
- // not.
- bool Device = true;
-
- // Create barriers both before and after the call.
- EmitMemoryBarrier(CGF, true, true, true, true, Device);
- Value *Result = CGF.Builder.CreateCall(Fn, Args);
- EmitMemoryBarrier(CGF, true, true, true, true, Device);
- return Result;
-}
-
/// Utility to insert an atomic instruction based on Instrinsic::ID
/// and the expression node.
static RValue EmitBinaryAtomic(CodeGenFunction &CGF,
- Intrinsic::ID Id, const CallExpr *E) {
+ llvm::AtomicRMWInst::BinOp Kind,
+ const CallExpr *E) {
QualType T = E->getType();
assert(E->getArg(0)->getType()->isPointerType());
assert(CGF.getContext().hasSameUnqualifiedType(T,
@@ -99,16 +95,15 @@ static RValue EmitBinaryAtomic(CodeGenFunction &CGF,
CGF.getContext().getTypeSize(T));
llvm::Type *IntPtrType = IntType->getPointerTo(AddrSpace);
- llvm::Type *IntrinsicTypes[2] = { IntType, IntPtrType };
- llvm::Value *AtomF = CGF.CGM.getIntrinsic(Id, IntrinsicTypes);
-
llvm::Value *Args[2];
Args[0] = CGF.Builder.CreateBitCast(DestPtr, IntPtrType);
Args[1] = CGF.EmitScalarExpr(E->getArg(1));
- const llvm::Type *ValueType = Args[1]->getType();
+ llvm::Type *ValueType = Args[1]->getType();
Args[1] = EmitToInt(CGF, Args[1], T, IntType);
- llvm::Value *Result = EmitCallWithBarrier(CGF, AtomF, Args);
+ llvm::Value *Result =
+ CGF.Builder.CreateAtomicRMW(Kind, Args[0], Args[1],
+ llvm::SequentiallyConsistent);
Result = EmitFromInt(CGF, Result, T, ValueType);
return RValue::get(Result);
}
@@ -117,7 +112,8 @@ static RValue EmitBinaryAtomic(CodeGenFunction &CGF,
/// the expression node, where the return value is the result of the
/// operation.
static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF,
- Intrinsic::ID Id, const CallExpr *E,
+ llvm::AtomicRMWInst::BinOp Kind,
+ const CallExpr *E,
Instruction::BinaryOps Op) {
QualType T = E->getType();
assert(E->getArg(0)->getType()->isPointerType());
@@ -134,16 +130,15 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF,
CGF.getContext().getTypeSize(T));
llvm::Type *IntPtrType = IntType->getPointerTo(AddrSpace);
- llvm::Type *IntrinsicTypes[2] = { IntType, IntPtrType };
- llvm::Value *AtomF = CGF.CGM.getIntrinsic(Id, IntrinsicTypes);
-
llvm::Value *Args[2];
Args[1] = CGF.EmitScalarExpr(E->getArg(1));
- const llvm::Type *ValueType = Args[1]->getType();
+ llvm::Type *ValueType = Args[1]->getType();
Args[1] = EmitToInt(CGF, Args[1], T, IntType);
Args[0] = CGF.Builder.CreateBitCast(DestPtr, IntPtrType);
- llvm::Value *Result = EmitCallWithBarrier(CGF, AtomF, Args);
+ llvm::Value *Result =
+ CGF.Builder.CreateAtomicRMW(Kind, Args[0], Args[1],
+ llvm::SequentiallyConsistent);
Result = CGF.Builder.CreateBinOp(Op, Result, Args[1]);
Result = EmitFromInt(CGF, Result, T, ValueType);
return RValue::get(Result);
@@ -157,21 +152,26 @@ static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) {
StringRef FnName;
switch (ValTyP->getKind()) {
- default: assert(0 && "Isn't a scalar fp type!");
+ default: llvm_unreachable("Isn't a scalar fp type!");
case BuiltinType::Float: FnName = "fabsf"; break;
case BuiltinType::Double: FnName = "fabs"; break;
case BuiltinType::LongDouble: FnName = "fabsl"; break;
}
// The prototype is something that takes and returns whatever V's type is.
- llvm::Type *ArgTys[] = { V->getType() };
- llvm::FunctionType *FT = llvm::FunctionType::get(V->getType(), ArgTys,
+ llvm::FunctionType *FT = llvm::FunctionType::get(V->getType(), V->getType(),
false);
llvm::Value *Fn = CGF.CGM.CreateRuntimeFunction(FT, FnName);
return CGF.Builder.CreateCall(Fn, V, "abs");
}
+static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *Fn,
+ const CallExpr *E, llvm::Value *calleeValue) {
+ return CGF.EmitCall(E->getCallee()->getType(), calleeValue,
+ ReturnValueSlot(), E->arg_begin(), E->arg_end(), Fn);
+}
+
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.
@@ -195,7 +195,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__builtin_va_start:
case Builtin::BI__builtin_va_end: {
Value *ArgValue = EmitVAListRef(E->getArg(0));
- const llvm::Type *DestType = Int8PtrTy;
+ llvm::Type *DestType = Int8PtrTy;
if (ArgValue->getType() != DestType)
ArgValue = Builder.CreateBitCast(ArgValue, DestType,
ArgValue->getName().data());
@@ -208,7 +208,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *DstPtr = EmitVAListRef(E->getArg(0));
Value *SrcPtr = EmitVAListRef(E->getArg(1));
- const llvm::Type *Type = Int8PtrTy;
+ llvm::Type *Type = Int8PtrTy;
DstPtr = Builder.CreateBitCast(DstPtr, Type);
SrcPtr = Builder.CreateBitCast(SrcPtr, Type);
@@ -236,8 +236,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::Type *ArgType = ArgValue->getType();
Value *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
- const llvm::Type *ResultType = ConvertType(E->getType());
- Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Value *Result = Builder.CreateCall(F, ArgValue);
if (Result->getType() != ResultType)
Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
"cast");
@@ -251,8 +251,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::Type *ArgType = ArgValue->getType();
Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
- const llvm::Type *ResultType = ConvertType(E->getType());
- Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Value *Result = Builder.CreateCall(F, ArgValue);
if (Result->getType() != ResultType)
Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
"cast");
@@ -267,9 +267,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::Type *ArgType = ArgValue->getType();
Value *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
- const llvm::Type *ResultType = ConvertType(E->getType());
- Value *Tmp = Builder.CreateAdd(Builder.CreateCall(F, ArgValue, "tmp"),
- llvm::ConstantInt::get(ArgType, 1), "tmp");
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Value *Tmp = Builder.CreateAdd(Builder.CreateCall(F, ArgValue),
+ llvm::ConstantInt::get(ArgType, 1));
Value *Zero = llvm::Constant::getNullValue(ArgType);
Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero, "iszero");
Value *Result = Builder.CreateSelect(IsZero, Zero, Tmp, "ffs");
@@ -287,10 +287,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::Type *ArgType = ArgValue->getType();
Value *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType);
- const llvm::Type *ResultType = ConvertType(E->getType());
- Value *Tmp = Builder.CreateCall(F, ArgValue, "tmp");
- Value *Result = Builder.CreateAnd(Tmp, llvm::ConstantInt::get(ArgType, 1),
- "tmp");
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Value *Tmp = Builder.CreateCall(F, ArgValue);
+ Value *Result = Builder.CreateAnd(Tmp, llvm::ConstantInt::get(ArgType, 1));
if (Result->getType() != ResultType)
Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
"cast");
@@ -304,8 +303,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::Type *ArgType = ArgValue->getType();
Value *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType);
- const llvm::Type *ResultType = ConvertType(E->getType());
- Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Value *Result = Builder.CreateCall(F, ArgValue);
if (Result->getType() != ResultType)
Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
"cast");
@@ -327,7 +326,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *ArgValue = EmitScalarExpr(E->getArg(0));
llvm::Type *ArgType = ArgValue->getType();
Value *F = CGM.getIntrinsic(Intrinsic::bswap, ArgType);
- return RValue::get(Builder.CreateCall(F, ArgValue, "tmp"));
+ return RValue::get(Builder.CreateCall(F, ArgValue));
}
case Builtin::BI__builtin_object_size: {
// We pass this builtin onto the optimizer so that it can
@@ -381,7 +380,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *Exponent = EmitScalarExpr(E->getArg(1));
llvm::Type *ArgType = Base->getType();
Value *F = CGM.getIntrinsic(Intrinsic::powi, ArgType);
- return RValue::get(Builder.CreateCall2(F, Base, Exponent, "tmp"));
+ return RValue::get(Builder.CreateCall2(F, Base, Exponent));
}
case Builtin::BI__builtin_isgreater:
@@ -396,7 +395,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *RHS = EmitScalarExpr(E->getArg(1));
switch (BuiltinID) {
- default: assert(0 && "Unknown ordered comparison");
+ default: llvm_unreachable("Unknown ordered comparison");
case Builtin::BI__builtin_isgreater:
LHS = Builder.CreateFCmpOGT(LHS, RHS, "cmp");
break;
@@ -417,13 +416,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
break;
}
// ZExt bool to int type.
- return RValue::get(Builder.CreateZExt(LHS, ConvertType(E->getType()),
- "tmp"));
+ return RValue::get(Builder.CreateZExt(LHS, ConvertType(E->getType())));
}
case Builtin::BI__builtin_isnan: {
Value *V = EmitScalarExpr(E->getArg(0));
V = Builder.CreateFCmpUNO(V, V, "cmp");
- return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()), "tmp"));
+ return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType())));
}
case Builtin::BI__builtin_isinf: {
@@ -432,7 +430,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
V = EmitFAbs(*this, V, E->getArg(0)->getType());
V = Builder.CreateFCmpOEQ(V, ConstantFP::getInfinity(V->getType()),"isinf");
- return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()), "tmp"));
+ return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType())));
}
// TODO: BI__builtin_isinf_sign
@@ -457,7 +455,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
}
case Builtin::BI__builtin_isfinite: {
- // isfinite(x) --> x == x && fabs(x) != infinity; }
+ // isfinite(x) --> x == x && fabs(x) != infinity;
Value *V = EmitScalarExpr(E->getArg(0));
Value *Eq = Builder.CreateFCmpOEQ(V, V, "iseq");
@@ -471,7 +469,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__builtin_fpclassify: {
Value *V = EmitScalarExpr(E->getArg(5));
- const llvm::Type *Ty = ConvertType(E->getArg(5)->getType());
+ llvm::Type *Ty = ConvertType(E->getArg(5)->getType());
// Create Result
BasicBlock *Begin = Builder.GetInsertBlock();
@@ -530,7 +528,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BIalloca:
case Builtin::BI__builtin_alloca: {
Value *Size = EmitScalarExpr(E->getArg(0));
- return RValue::get(Builder.CreateAlloca(Builder.getInt8Ty(), Size, "tmp"));
+ return RValue::get(Builder.CreateAlloca(Builder.getInt8Ty(), Size));
}
case Builtin::BIbzero:
case Builtin::BI__builtin_bzero: {
@@ -550,11 +548,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__builtin___memcpy_chk: {
// fold __builtin_memcpy_chk(x, y, cst1, cst2) to memset iff cst1<=cst2.
- if (!E->getArg(2)->isEvaluatable(CGM.getContext()) ||
- !E->getArg(3)->isEvaluatable(CGM.getContext()))
+ llvm::APSInt Size, DstSize;
+ if (!E->getArg(2)->EvaluateAsInt(Size, CGM.getContext()) ||
+ !E->getArg(3)->EvaluateAsInt(DstSize, CGM.getContext()))
break;
- llvm::APSInt Size = E->getArg(2)->EvaluateAsInt(CGM.getContext());
- llvm::APSInt DstSize = E->getArg(3)->EvaluateAsInt(CGM.getContext());
if (Size.ugt(DstSize))
break;
Value *Dest = EmitScalarExpr(E->getArg(0));
@@ -575,11 +572,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__builtin___memmove_chk: {
// fold __builtin_memmove_chk(x, y, cst1, cst2) to memset iff cst1<=cst2.
- if (!E->getArg(2)->isEvaluatable(CGM.getContext()) ||
- !E->getArg(3)->isEvaluatable(CGM.getContext()))
+ llvm::APSInt Size, DstSize;
+ if (!E->getArg(2)->EvaluateAsInt(Size, CGM.getContext()) ||
+ !E->getArg(3)->EvaluateAsInt(DstSize, CGM.getContext()))
break;
- llvm::APSInt Size = E->getArg(2)->EvaluateAsInt(CGM.getContext());
- llvm::APSInt DstSize = E->getArg(3)->EvaluateAsInt(CGM.getContext());
if (Size.ugt(DstSize))
break;
Value *Dest = EmitScalarExpr(E->getArg(0));
@@ -608,11 +604,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
}
case Builtin::BI__builtin___memset_chk: {
// fold __builtin_memset_chk(x, y, cst1, cst2) to memset iff cst1<=cst2.
- if (!E->getArg(2)->isEvaluatable(CGM.getContext()) ||
- !E->getArg(3)->isEvaluatable(CGM.getContext()))
+ llvm::APSInt Size, DstSize;
+ if (!E->getArg(2)->EvaluateAsInt(Size, CGM.getContext()) ||
+ !E->getArg(3)->EvaluateAsInt(DstSize, CGM.getContext()))
break;
- llvm::APSInt Size = E->getArg(2)->EvaluateAsInt(CGM.getContext());
- llvm::APSInt DstSize = E->getArg(3)->EvaluateAsInt(CGM.getContext());
if (Size.ugt(DstSize))
break;
Value *Address = EmitScalarExpr(E->getArg(0));
@@ -640,13 +635,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
}
case Builtin::BI__builtin_return_address: {
Value *Depth = EmitScalarExpr(E->getArg(0));
- Depth = Builder.CreateIntCast(Depth, Int32Ty, false, "tmp");
+ Depth = Builder.CreateIntCast(Depth, Int32Ty, false);
Value *F = CGM.getIntrinsic(Intrinsic::returnaddress);
return RValue::get(Builder.CreateCall(F, Depth));
}
case Builtin::BI__builtin_frame_address: {
Value *Depth = EmitScalarExpr(E->getArg(0));
- Depth = Builder.CreateIntCast(Depth, Int32Ty, false, "tmp");
+ Depth = Builder.CreateIntCast(Depth, Int32Ty, false);
Value *F = CGM.getIntrinsic(Intrinsic::frameaddress);
return RValue::get(Builder.CreateCall(F, Depth));
}
@@ -661,7 +656,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Result);
}
case Builtin::BI__builtin_dwarf_sp_column: {
- const llvm::IntegerType *Ty
+ llvm::IntegerType *Ty
= cast<llvm::IntegerType>(ConvertType(E->getType()));
int Column = getTargetHooks().getDwarfEHStackPointer(CGM);
if (Column == -1) {
@@ -680,7 +675,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *Int = EmitScalarExpr(E->getArg(0));
Value *Ptr = EmitScalarExpr(E->getArg(1));
- const llvm::IntegerType *IntTy = cast<llvm::IntegerType>(Int->getType());
+ llvm::IntegerType *IntTy = cast<llvm::IntegerType>(Int->getType());
assert((IntTy->getBitWidth() == 32 || IntTy->getBitWidth() == 64) &&
"LLVM's __builtin_eh_return only supports 32- and 64-bit variants");
Value *F = CGM.getIntrinsic(IntTy->getBitWidth() == 32
@@ -775,82 +770,82 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_lock_test_and_set:
case Builtin::BI__sync_lock_release:
case Builtin::BI__sync_swap:
- assert(0 && "Shouldn't make it through sema");
+ llvm_unreachable("Shouldn't make it through sema");
case Builtin::BI__sync_fetch_and_add_1:
case Builtin::BI__sync_fetch_and_add_2:
case Builtin::BI__sync_fetch_and_add_4:
case Builtin::BI__sync_fetch_and_add_8:
case Builtin::BI__sync_fetch_and_add_16:
- return EmitBinaryAtomic(*this, Intrinsic::atomic_load_add, E);
+ return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Add, E);
case Builtin::BI__sync_fetch_and_sub_1:
case Builtin::BI__sync_fetch_and_sub_2:
case Builtin::BI__sync_fetch_and_sub_4:
case Builtin::BI__sync_fetch_and_sub_8:
case Builtin::BI__sync_fetch_and_sub_16:
- return EmitBinaryAtomic(*this, Intrinsic::atomic_load_sub, E);
+ return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Sub, E);
case Builtin::BI__sync_fetch_and_or_1:
case Builtin::BI__sync_fetch_and_or_2:
case Builtin::BI__sync_fetch_and_or_4:
case Builtin::BI__sync_fetch_and_or_8:
case Builtin::BI__sync_fetch_and_or_16:
- return EmitBinaryAtomic(*this, Intrinsic::atomic_load_or, E);
+ return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Or, E);
case Builtin::BI__sync_fetch_and_and_1:
case Builtin::BI__sync_fetch_and_and_2:
case Builtin::BI__sync_fetch_and_and_4:
case Builtin::BI__sync_fetch_and_and_8:
case Builtin::BI__sync_fetch_and_and_16:
- return EmitBinaryAtomic(*this, Intrinsic::atomic_load_and, E);
+ return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::And, E);
case Builtin::BI__sync_fetch_and_xor_1:
case Builtin::BI__sync_fetch_and_xor_2:
case Builtin::BI__sync_fetch_and_xor_4:
case Builtin::BI__sync_fetch_and_xor_8:
case Builtin::BI__sync_fetch_and_xor_16:
- return EmitBinaryAtomic(*this, Intrinsic::atomic_load_xor, E);
+ return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Xor, E);
// Clang extensions: not overloaded yet.
case Builtin::BI__sync_fetch_and_min:
- return EmitBinaryAtomic(*this, Intrinsic::atomic_load_min, E);
+ return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Min, E);
case Builtin::BI__sync_fetch_and_max:
- return EmitBinaryAtomic(*this, Intrinsic::atomic_load_max, E);
+ return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Max, E);
case Builtin::BI__sync_fetch_and_umin:
- return EmitBinaryAtomic(*this, Intrinsic::atomic_load_umin, E);
+ return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::UMin, E);
case Builtin::BI__sync_fetch_and_umax:
- return EmitBinaryAtomic(*this, Intrinsic::atomic_load_umax, E);
+ return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::UMax, E);
case Builtin::BI__sync_add_and_fetch_1:
case Builtin::BI__sync_add_and_fetch_2:
case Builtin::BI__sync_add_and_fetch_4:
case Builtin::BI__sync_add_and_fetch_8:
case Builtin::BI__sync_add_and_fetch_16:
- return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_add, E,
+ return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::Add, E,
llvm::Instruction::Add);
case Builtin::BI__sync_sub_and_fetch_1:
case Builtin::BI__sync_sub_and_fetch_2:
case Builtin::BI__sync_sub_and_fetch_4:
case Builtin::BI__sync_sub_and_fetch_8:
case Builtin::BI__sync_sub_and_fetch_16:
- return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_sub, E,
+ return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::Sub, E,
llvm::Instruction::Sub);
case Builtin::BI__sync_and_and_fetch_1:
case Builtin::BI__sync_and_and_fetch_2:
case Builtin::BI__sync_and_and_fetch_4:
case Builtin::BI__sync_and_and_fetch_8:
case Builtin::BI__sync_and_and_fetch_16:
- return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_and, E,
+ return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::And, E,
llvm::Instruction::And);
case Builtin::BI__sync_or_and_fetch_1:
case Builtin::BI__sync_or_and_fetch_2:
case Builtin::BI__sync_or_and_fetch_4:
case Builtin::BI__sync_or_and_fetch_8:
case Builtin::BI__sync_or_and_fetch_16:
- return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_or, E,
+ return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::Or, E,
llvm::Instruction::Or);
case Builtin::BI__sync_xor_and_fetch_1:
case Builtin::BI__sync_xor_and_fetch_2:
case Builtin::BI__sync_xor_and_fetch_4:
case Builtin::BI__sync_xor_and_fetch_8:
case Builtin::BI__sync_xor_and_fetch_16:
- return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_xor, E,
+ return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::Xor, E,
llvm::Instruction::Xor);
case Builtin::BI__sync_val_compare_and_swap_1:
@@ -867,18 +862,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::IntegerType::get(getLLVMContext(),
getContext().getTypeSize(T));
llvm::Type *IntPtrType = IntType->getPointerTo(AddrSpace);
- llvm::Type *IntrinsicTypes[2] = { IntType, IntPtrType };
- Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap,
- IntrinsicTypes);
Value *Args[3];
Args[0] = Builder.CreateBitCast(DestPtr, IntPtrType);
Args[1] = EmitScalarExpr(E->getArg(1));
- const llvm::Type *ValueType = Args[1]->getType();
+ llvm::Type *ValueType = Args[1]->getType();
Args[1] = EmitToInt(*this, Args[1], T, IntType);
Args[2] = EmitToInt(*this, EmitScalarExpr(E->getArg(2)), T, IntType);
- Value *Result = EmitCallWithBarrier(*this, AtomF, Args);
+ Value *Result = Builder.CreateAtomicCmpXchg(Args[0], Args[1], Args[2],
+ llvm::SequentiallyConsistent);
Result = EmitFromInt(*this, Result, T, ValueType);
return RValue::get(Result);
}
@@ -897,9 +890,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::IntegerType::get(getLLVMContext(),
getContext().getTypeSize(T));
llvm::Type *IntPtrType = IntType->getPointerTo(AddrSpace);
- llvm::Type *IntrinsicTypes[2] = { IntType, IntPtrType };
- Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap,
- IntrinsicTypes);
Value *Args[3];
Args[0] = Builder.CreateBitCast(DestPtr, IntPtrType);
@@ -907,7 +897,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Args[2] = EmitToInt(*this, EmitScalarExpr(E->getArg(2)), T, IntType);
Value *OldVal = Args[1];
- Value *PrevVal = EmitCallWithBarrier(*this, AtomF, Args);
+ Value *PrevVal = Builder.CreateAtomicCmpXchg(Args[0], Args[1], Args[2],
+ llvm::SequentiallyConsistent);
Value *Result = Builder.CreateICmpEQ(PrevVal, OldVal);
// zext bool to int.
Result = Builder.CreateZExt(Result, ConvertType(E->getType()));
@@ -919,14 +910,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_swap_4:
case Builtin::BI__sync_swap_8:
case Builtin::BI__sync_swap_16:
- return EmitBinaryAtomic(*this, Intrinsic::atomic_swap, E);
+ return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Xchg, E);
case Builtin::BI__sync_lock_test_and_set_1:
case Builtin::BI__sync_lock_test_and_set_2:
case Builtin::BI__sync_lock_test_and_set_4:
case Builtin::BI__sync_lock_test_and_set_8:
case Builtin::BI__sync_lock_test_and_set_16:
- return EmitBinaryAtomic(*this, Intrinsic::atomic_swap, E);
+ return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Xchg, E);
case Builtin::BI__sync_lock_release_1:
case Builtin::BI__sync_lock_release_2:
@@ -934,32 +925,95 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_lock_release_8:
case Builtin::BI__sync_lock_release_16: {
Value *Ptr = EmitScalarExpr(E->getArg(0));
- const llvm::Type *ElTy =
+ llvm::Type *ElLLVMTy =
cast<llvm::PointerType>(Ptr->getType())->getElementType();
llvm::StoreInst *Store =
- Builder.CreateStore(llvm::Constant::getNullValue(ElTy), Ptr);
- Store->setVolatile(true);
+ Builder.CreateStore(llvm::Constant::getNullValue(ElLLVMTy), Ptr);
+ QualType ElTy = E->getArg(0)->getType()->getPointeeType();
+ CharUnits StoreSize = getContext().getTypeSizeInChars(ElTy);
+ Store->setAlignment(StoreSize.getQuantity());
+ Store->setAtomic(llvm::Release);
return RValue::get(0);
}
case Builtin::BI__sync_synchronize: {
- // We assume like gcc appears to, that this only applies to cached memory.
- EmitMemoryBarrier(*this, true, true, true, true, false);
+ // We assume this is supposed to correspond to a C++0x-style
+ // sequentially-consistent fence (i.e. this is only usable for
+ // synchonization, not device I/O or anything like that). This intrinsic
+ // is really badly designed in the sense that in theory, there isn't
+ // any way to safely use it... but in practice, it mostly works
+ // to use it with non-atomic loads and stores to get acquire/release
+ // semantics.
+ Builder.CreateFence(llvm::SequentiallyConsistent);
return RValue::get(0);
}
- case Builtin::BI__builtin_llvm_memory_barrier: {
- Value *C[5] = {
- EmitScalarExpr(E->getArg(0)),
- EmitScalarExpr(E->getArg(1)),
- EmitScalarExpr(E->getArg(2)),
- EmitScalarExpr(E->getArg(3)),
- EmitScalarExpr(E->getArg(4))
- };
- Builder.CreateCall(CGM.getIntrinsic(Intrinsic::memory_barrier), C);
+ case Builtin::BI__atomic_thread_fence:
+ case Builtin::BI__atomic_signal_fence: {
+ llvm::SynchronizationScope Scope;
+ if (BuiltinID == Builtin::BI__atomic_signal_fence)
+ Scope = llvm::SingleThread;
+ else
+ Scope = llvm::CrossThread;
+ Value *Order = EmitScalarExpr(E->getArg(0));
+ if (isa<llvm::ConstantInt>(Order)) {
+ int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
+ switch (ord) {
+ case 0: // memory_order_relaxed
+ default: // invalid order
+ break;
+ case 1: // memory_order_consume
+ case 2: // memory_order_acquire
+ Builder.CreateFence(llvm::Acquire, Scope);
+ break;
+ case 3: // memory_order_release
+ Builder.CreateFence(llvm::Release, Scope);
+ break;
+ case 4: // memory_order_acq_rel
+ Builder.CreateFence(llvm::AcquireRelease, Scope);
+ break;
+ case 5: // memory_order_seq_cst
+ Builder.CreateFence(llvm::SequentiallyConsistent, Scope);
+ break;
+ }
+ return RValue::get(0);
+ }
+
+ llvm::BasicBlock *AcquireBB, *ReleaseBB, *AcqRelBB, *SeqCstBB;
+ AcquireBB = createBasicBlock("acquire", CurFn);
+ ReleaseBB = createBasicBlock("release", CurFn);
+ AcqRelBB = createBasicBlock("acqrel", CurFn);
+ SeqCstBB = createBasicBlock("seqcst", CurFn);
+ llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn);
+
+ Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false);
+ llvm::SwitchInst *SI = Builder.CreateSwitch(Order, ContBB);
+
+ Builder.SetInsertPoint(AcquireBB);
+ Builder.CreateFence(llvm::Acquire, Scope);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(1), AcquireBB);
+ SI->addCase(Builder.getInt32(2), AcquireBB);
+
+ Builder.SetInsertPoint(ReleaseBB);
+ Builder.CreateFence(llvm::Release, Scope);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(3), ReleaseBB);
+
+ Builder.SetInsertPoint(AcqRelBB);
+ Builder.CreateFence(llvm::AcquireRelease, Scope);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(4), AcqRelBB);
+
+ Builder.SetInsertPoint(SeqCstBB);
+ Builder.CreateFence(llvm::SequentiallyConsistent, Scope);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(5), SeqCstBB);
+
+ Builder.SetInsertPoint(ContBB);
return RValue::get(0);
}
-
+
// Library functions with special handling.
case Builtin::BIsqrt:
case Builtin::BIsqrtf:
@@ -982,7 +1036,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *Exponent = EmitScalarExpr(E->getArg(1));
llvm::Type *ArgType = Base->getType();
Value *F = CGM.getIntrinsic(Intrinsic::pow, ArgType);
- return RValue::get(Builder.CreateCall2(F, Base, Exponent, "tmp"));
+ return RValue::get(Builder.CreateCall2(F, Base, Exponent));
}
case Builtin::BIfma:
@@ -997,8 +1051,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *F = CGM.getIntrinsic(Intrinsic::fma, ArgType);
return RValue::get(Builder.CreateCall3(F, FirstArg,
EmitScalarExpr(E->getArg(1)),
- EmitScalarExpr(E->getArg(2)),
- "tmp"));
+ EmitScalarExpr(E->getArg(2))));
}
case Builtin::BI__builtin_signbit:
@@ -1007,25 +1060,40 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
LLVMContext &C = CGM.getLLVMContext();
Value *Arg = EmitScalarExpr(E->getArg(0));
- const llvm::Type *ArgTy = Arg->getType();
+ llvm::Type *ArgTy = Arg->getType();
if (ArgTy->isPPC_FP128Ty())
break; // FIXME: I'm not sure what the right implementation is here.
int ArgWidth = ArgTy->getPrimitiveSizeInBits();
- const llvm::Type *ArgIntTy = llvm::IntegerType::get(C, ArgWidth);
+ llvm::Type *ArgIntTy = llvm::IntegerType::get(C, ArgWidth);
Value *BCArg = Builder.CreateBitCast(Arg, ArgIntTy);
Value *ZeroCmp = llvm::Constant::getNullValue(ArgIntTy);
Value *Result = Builder.CreateICmpSLT(BCArg, ZeroCmp);
return RValue::get(Builder.CreateZExt(Result, ConvertType(E->getType())));
}
+ case Builtin::BI__builtin_annotation: {
+ llvm::Value *AnnVal = EmitScalarExpr(E->getArg(0));
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::annotation,
+ AnnVal->getType());
+
+ // 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();
+ return RValue::get(EmitAnnotationCall(F, AnnVal, Str, E->getExprLoc()));
+ }
}
- // If this is an alias for a libm function (e.g. __builtin_sin) turn it into
- // that function.
- if (getContext().BuiltinInfo.isLibFunction(BuiltinID) ||
- getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID))
- return EmitCall(E->getCallee()->getType(),
- CGM.getBuiltinLibFunction(FD, BuiltinID),
- ReturnValueSlot(), E->arg_begin(), E->arg_end(), FD);
+ // If this is an alias for a lib function (e.g. __builtin_sin), emit
+ // the call using the normal call path, but using the unmangled
+ // version of the function name.
+ if (getContext().BuiltinInfo.isLibFunction(BuiltinID))
+ return emitLibraryCall(*this, FD, E,
+ CGM.getBuiltinLibFunction(FD, BuiltinID));
+
+ // If this is a predefined lib function (e.g. malloc), emit the call
+ // using exactly the normal call path.
+ if (getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID))
+ return emitLibraryCall(*this, FD, E, EmitScalarExpr(E->getCallee()));
// See if we have a target specific intrinsic.
const char *Name = getContext().BuiltinInfo.GetName(BuiltinID);
@@ -1045,7 +1113,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
assert(Error == ASTContext::GE_None && "Should not codegen an error");
Function *F = CGM.getIntrinsic(IntrinsicID);
- const llvm::FunctionType *FTy = F->getFunctionType();
+ llvm::FunctionType *FTy = F->getFunctionType();
for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
Value *ArgValue;
@@ -1064,7 +1132,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// If the intrinsic arg type is different from the builtin arg type
// we need to do a bit cast.
- const llvm::Type *PTy = FTy->getParamType(i);
+ llvm::Type *PTy = FTy->getParamType(i);
if (PTy != ArgValue->getType()) {
assert(PTy->canLosslesslyBitCastTo(FTy->getParamType(i)) &&
"Must be able to losslessly bit cast to param");
@@ -1077,7 +1145,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *V = Builder.CreateCall(F, Args);
QualType BuiltinRetType = E->getType();
- const llvm::Type *RetTy = llvm::Type::getVoidTy(getLLVMContext());
+ llvm::Type *RetTy = llvm::Type::getVoidTy(getLLVMContext());
if (!BuiltinRetType->isVoidType()) RetTy = ConvertType(BuiltinRetType);
if (RetTy != V->getType()) {
@@ -1154,12 +1222,12 @@ Value *CodeGenFunction::EmitNeonCall(Function *F, SmallVectorImpl<Value*> &Ops,
return Builder.CreateCall(F, Ops, name);
}
-Value *CodeGenFunction::EmitNeonShiftVector(Value *V, const llvm::Type *Ty,
+Value *CodeGenFunction::EmitNeonShiftVector(Value *V, llvm::Type *Ty,
bool neg) {
ConstantInt *CI = cast<ConstantInt>(V);
int SV = CI->getSExtValue();
- const llvm::VectorType *VTy = cast<llvm::VectorType>(Ty);
+ llvm::VectorType *VTy = cast<llvm::VectorType>(Ty);
llvm::Constant *C = ConstantInt::get(VTy->getElementType(), neg ? -SV : SV);
SmallVector<llvm::Constant*, 16> CV(VTy->getNumElements(), C);
return llvm::ConstantVector::get(CV);
@@ -1193,12 +1261,12 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
const FunctionDecl *FD = E->getDirectCallee();
// Oddly people write this call without args on occasion and gcc accepts
// it - it's also marked as varargs in the description file.
- llvm::SmallVector<Value*, 2> Ops;
+ SmallVector<Value*, 2> Ops;
for (unsigned i = 0; i < E->getNumArgs(); i++)
Ops.push_back(EmitScalarExpr(E->getArg(i)));
- const llvm::Type *Ty = CGM.getTypes().ConvertType(FD->getType());
- const llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
- llvm::StringRef Name = FD->getName();
+ 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);
}
@@ -1223,7 +1291,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, NULL);
Value *One = llvm::ConstantInt::get(Int32Ty, 1);
- Value *Tmp = Builder.CreateAlloca(Int64Ty, One, "tmp");
+ Value *Tmp = Builder.CreateAlloca(Int64Ty, One);
Value *Val = EmitScalarExpr(E->getArg(0));
Builder.CreateStore(Val, Tmp);
@@ -1236,10 +1304,41 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall3(F, Arg0, Arg1, StPtr, "strexd");
}
- llvm::SmallVector<Value*, 4> Ops;
+ SmallVector<Value*, 4> Ops;
for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++)
Ops.push_back(EmitScalarExpr(E->getArg(i)));
+ // vget_lane and vset_lane are not overloaded and do not have an extra
+ // argument that specifies the vector type.
+ switch (BuiltinID) {
+ default: break;
+ case ARM::BI__builtin_neon_vget_lane_i8:
+ case ARM::BI__builtin_neon_vget_lane_i16:
+ case ARM::BI__builtin_neon_vget_lane_i32:
+ case ARM::BI__builtin_neon_vget_lane_i64:
+ case ARM::BI__builtin_neon_vget_lane_f32:
+ case ARM::BI__builtin_neon_vgetq_lane_i8:
+ case ARM::BI__builtin_neon_vgetq_lane_i16:
+ case ARM::BI__builtin_neon_vgetq_lane_i32:
+ case ARM::BI__builtin_neon_vgetq_lane_i64:
+ case ARM::BI__builtin_neon_vgetq_lane_f32:
+ return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
+ "vget_lane");
+ case ARM::BI__builtin_neon_vset_lane_i8:
+ case ARM::BI__builtin_neon_vset_lane_i16:
+ case ARM::BI__builtin_neon_vset_lane_i32:
+ case ARM::BI__builtin_neon_vset_lane_i64:
+ case ARM::BI__builtin_neon_vset_lane_f32:
+ case ARM::BI__builtin_neon_vsetq_lane_i8:
+ case ARM::BI__builtin_neon_vsetq_lane_i16:
+ case ARM::BI__builtin_neon_vsetq_lane_i32:
+ case ARM::BI__builtin_neon_vsetq_lane_i64:
+ case ARM::BI__builtin_neon_vsetq_lane_f32:
+ Ops.push_back(EmitScalarExpr(E->getArg(2)));
+ return Builder.CreateInsertElement(Ops[1], Ops[0], Ops[2], "vset_lane");
+ }
+
+ // Get the last argument, which specifies the vector type.
llvm::APSInt Result;
const Expr *Arg = E->getArg(E->getNumArgs()-1);
if (!Arg->isIntegerConstantExpr(Result, getContext()))
@@ -1382,18 +1481,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Value *SV = llvm::ConstantVector::get(Indices);
return Builder.CreateShuffleVector(Ops[0], Ops[1], SV, "vext");
}
- case ARM::BI__builtin_neon_vget_lane_i8:
- case ARM::BI__builtin_neon_vget_lane_i16:
- case ARM::BI__builtin_neon_vget_lane_i32:
- case ARM::BI__builtin_neon_vget_lane_i64:
- case ARM::BI__builtin_neon_vget_lane_f32:
- case ARM::BI__builtin_neon_vgetq_lane_i8:
- case ARM::BI__builtin_neon_vgetq_lane_i16:
- case ARM::BI__builtin_neon_vgetq_lane_i32:
- case ARM::BI__builtin_neon_vgetq_lane_i64:
- case ARM::BI__builtin_neon_vgetq_lane_f32:
- return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
- "vget_lane");
case ARM::BI__builtin_neon_vhadd_v:
case ARM::BI__builtin_neon_vhaddq_v:
Int = usgn ? Intrinsic::arm_neon_vhaddu : Intrinsic::arm_neon_vhadds;
@@ -1457,9 +1544,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
Ops.push_back(GetPointeeAlignment(*this, E->getArg(1)));
- Ops[1] = Builder.CreateCall(F,
- ArrayRef<Value *>(Ops.begin() + 1, Ops.end()),
- "vld2_lane");
+ Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld2_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
return Builder.CreateStore(Ops[1], Ops[0]);
@@ -1471,9 +1556,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
Ops[4] = Builder.CreateBitCast(Ops[4], Ty);
Ops.push_back(GetPointeeAlignment(*this, E->getArg(1)));
- Ops[1] = Builder.CreateCall(F,
- ArrayRef<Value *>(Ops.begin() + 1, Ops.end()),
- "vld3_lane");
+ Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld3_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
return Builder.CreateStore(Ops[1], Ops[0]);
@@ -1486,9 +1569,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[4] = Builder.CreateBitCast(Ops[4], Ty);
Ops[5] = Builder.CreateBitCast(Ops[5], Ty);
Ops.push_back(GetPointeeAlignment(*this, E->getArg(1)));
- Ops[1] = Builder.CreateCall(F,
- ArrayRef<Value *>(Ops.begin() + 1, Ops.end()),
- "vld3_lane");
+ Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld3_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
return Builder.CreateStore(Ops[1], Ops[0]);
@@ -1508,7 +1589,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vld4_dup_v:
Int = Intrinsic::arm_neon_vld2;
break;
- default: assert(0 && "unknown vld_dup intrinsic?");
+ default: llvm_unreachable("unknown vld_dup intrinsic?");
}
Function *F = CGM.getIntrinsic(Int, Ty);
Value *Align = GetPointeeAlignment(*this, E->getArg(1));
@@ -1527,10 +1608,10 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vld4_dup_v:
Int = Intrinsic::arm_neon_vld2lane;
break;
- default: assert(0 && "unknown vld_dup intrinsic?");
+ default: llvm_unreachable("unknown vld_dup intrinsic?");
}
Function *F = CGM.getIntrinsic(Int, Ty);
- const llvm::StructType *STy = cast<llvm::StructType>(F->getReturnType());
+ llvm::StructType *STy = cast<llvm::StructType>(F->getReturnType());
SmallVector<Value*, 6> Args;
Args.push_back(Ops[1]);
@@ -1562,14 +1643,14 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Int = usgn ? Intrinsic::arm_neon_vminu : Intrinsic::arm_neon_vmins;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmin");
case ARM::BI__builtin_neon_vmovl_v: {
- const llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy);
+ llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy);
Ops[0] = Builder.CreateBitCast(Ops[0], DTy);
if (usgn)
return Builder.CreateZExt(Ops[0], Ty, "vmovl");
return Builder.CreateSExt(Ops[0], Ty, "vmovl");
}
case ARM::BI__builtin_neon_vmovn_v: {
- const llvm::Type *QTy = llvm::VectorType::getExtendedElementVectorType(VTy);
+ llvm::Type *QTy = llvm::VectorType::getExtendedElementVectorType(VTy);
Ops[0] = Builder.CreateBitCast(Ops[0], QTy);
return Builder.CreateTrunc(Ops[0], Ty, "vmovn");
}
@@ -1587,7 +1668,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Int = usgn ? Intrinsic::arm_neon_vpadalu : Intrinsic::arm_neon_vpadals;
// The source operand type has twice as many elements of half the size.
unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits();
- const llvm::Type *EltTy =
+ llvm::Type *EltTy =
llvm::IntegerType::get(getLLVMContext(), EltBits / 2);
llvm::Type *NarrowTy =
llvm::VectorType::get(EltTy, VTy->getNumElements() * 2);
@@ -1602,7 +1683,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Int = usgn ? Intrinsic::arm_neon_vpaddlu : Intrinsic::arm_neon_vpaddls;
// The source operand type has twice as many elements of half the size.
unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits();
- const llvm::Type *EltTy = llvm::IntegerType::get(getLLVMContext(), EltBits / 2);
+ llvm::Type *EltTy = llvm::IntegerType::get(getLLVMContext(), EltBits / 2);
llvm::Type *NarrowTy =
llvm::VectorType::get(EltTy, VTy->getNumElements() * 2);
llvm::Type *Tys[2] = { Ty, NarrowTy };
@@ -1729,18 +1810,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vrsubhn_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrsubhn, Ty),
Ops, "vrsubhn");
- case ARM::BI__builtin_neon_vset_lane_i8:
- case ARM::BI__builtin_neon_vset_lane_i16:
- case ARM::BI__builtin_neon_vset_lane_i32:
- case ARM::BI__builtin_neon_vset_lane_i64:
- case ARM::BI__builtin_neon_vset_lane_f32:
- case ARM::BI__builtin_neon_vsetq_lane_i8:
- case ARM::BI__builtin_neon_vsetq_lane_i16:
- case ARM::BI__builtin_neon_vsetq_lane_i32:
- case ARM::BI__builtin_neon_vsetq_lane_i64:
- case ARM::BI__builtin_neon_vsetq_lane_f32:
- Ops.push_back(EmitScalarExpr(E->getArg(2)));
- return Builder.CreateInsertElement(Ops[1], Ops[0], Ops[2], "vset_lane");
case ARM::BI__builtin_neon_vshl_v:
case ARM::BI__builtin_neon_vshlq_v:
Int = usgn ? Intrinsic::arm_neon_vshiftu : Intrinsic::arm_neon_vshifts;
@@ -1921,7 +1990,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
llvm::Value *CodeGenFunction::
-BuildVector(const llvm::SmallVectorImpl<llvm::Value*> &Ops) {
+BuildVector(const SmallVectorImpl<llvm::Value*> &Ops) {
assert((Ops.size() & (Ops.size() - 1)) == 0 &&
"Not a power-of-two sized vector!");
bool AllConstants = true;
@@ -1949,7 +2018,7 @@ BuildVector(const llvm::SmallVectorImpl<llvm::Value*> &Ops) {
Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
- llvm::SmallVector<Value*, 4> Ops;
+ SmallVector<Value*, 4> Ops;
// Find out if any arguments are required to be integer constant expressions.
unsigned ICEArguments = 0;
@@ -1983,7 +2052,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_psrlqi128:
case X86::BI__builtin_ia32_psrlwi128: {
Ops[1] = Builder.CreateZExt(Ops[1], Int64Ty, "zext");
- const llvm::Type *Ty = llvm::VectorType::get(Int64Ty, 2);
+ llvm::Type *Ty = llvm::VectorType::get(Int64Ty, 2);
llvm::Value *Zero = llvm::ConstantInt::get(Int32Ty, 0);
Ops[1] = Builder.CreateInsertElement(llvm::UndefValue::get(Ty),
Ops[1], Zero, "insert");
@@ -1992,7 +2061,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
Intrinsic::ID ID = Intrinsic::not_intrinsic;
switch (BuiltinID) {
- default: assert(0 && "Unsupported shift intrinsic!");
+ default: llvm_unreachable("Unsupported shift intrinsic!");
case X86::BI__builtin_ia32_pslldi128:
name = "pslldi";
ID = Intrinsic::x86_sse2_psll_d;
@@ -2046,13 +2115,13 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_psrlqi:
case X86::BI__builtin_ia32_psrlwi: {
Ops[1] = Builder.CreateZExt(Ops[1], Int64Ty, "zext");
- const llvm::Type *Ty = llvm::VectorType::get(Int64Ty, 1);
+ llvm::Type *Ty = llvm::VectorType::get(Int64Ty, 1);
Ops[1] = Builder.CreateBitCast(Ops[1], Ty, "bitcast");
const char *name = 0;
Intrinsic::ID ID = Intrinsic::not_intrinsic;
switch (BuiltinID) {
- default: assert(0 && "Unsupported shift intrinsic!");
+ default: llvm_unreachable("Unsupported shift intrinsic!");
case X86::BI__builtin_ia32_pslldi:
name = "pslldi";
ID = Intrinsic::x86_mmx_psll_d;
@@ -2098,19 +2167,19 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall(F, Ops, "cmpss");
}
case X86::BI__builtin_ia32_ldmxcsr: {
- const llvm::Type *PtrTy = Int8PtrTy;
+ llvm::Type *PtrTy = Int8PtrTy;
Value *One = llvm::ConstantInt::get(Int32Ty, 1);
- Value *Tmp = Builder.CreateAlloca(Int32Ty, One, "tmp");
+ Value *Tmp = Builder.CreateAlloca(Int32Ty, One);
Builder.CreateStore(Ops[0], Tmp);
return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_ldmxcsr),
Builder.CreateBitCast(Tmp, PtrTy));
}
case X86::BI__builtin_ia32_stmxcsr: {
- const llvm::Type *PtrTy = Int8PtrTy;
+ llvm::Type *PtrTy = Int8PtrTy;
Value *One = llvm::ConstantInt::get(Int32Ty, 1);
- Value *Tmp = Builder.CreateAlloca(Int32Ty, One, "tmp");
- One = Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_stmxcsr),
- Builder.CreateBitCast(Tmp, PtrTy));
+ Value *Tmp = Builder.CreateAlloca(Int32Ty, One);
+ Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_stmxcsr),
+ Builder.CreateBitCast(Tmp, PtrTy));
return Builder.CreateLoad(Tmp, "stmxcsr");
}
case X86::BI__builtin_ia32_cmppd: {
@@ -2144,7 +2213,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// If palignr is shifting the pair of input vectors less than 9 bytes,
// emit a shuffle instruction.
if (shiftVal <= 8) {
- llvm::SmallVector<llvm::Constant*, 8> Indices;
+ SmallVector<llvm::Constant*, 8> Indices;
for (unsigned i = 0; i != 8; ++i)
Indices.push_back(llvm::ConstantInt::get(Int32Ty, shiftVal + i));
@@ -2156,17 +2225,17 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// than 16 bytes, emit a logical right shift of the destination.
if (shiftVal < 16) {
// MMX has these as 1 x i64 vectors for some odd optimization reasons.
- const llvm::Type *VecTy = llvm::VectorType::get(Int64Ty, 1);
+ llvm::Type *VecTy = llvm::VectorType::get(Int64Ty, 1);
Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast");
Ops[1] = llvm::ConstantInt::get(VecTy, (shiftVal-8) * 8);
// create i32 constant
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_mmx_psrl_q);
- return Builder.CreateCall(F, ArrayRef<Value *>(&Ops[0], 2), "palignr");
+ return Builder.CreateCall(F, makeArrayRef(&Ops[0], 2), "palignr");
}
- // If palignr is shifting the pair of vectors more than 32 bytes, emit zero.
+ // If palignr is shifting the pair of vectors more than 16 bytes, emit zero.
return llvm::Constant::getNullValue(ConvertType(E->getType()));
}
case X86::BI__builtin_ia32_palignr128: {
@@ -2175,7 +2244,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// If palignr is shifting the pair of input vectors less than 17 bytes,
// emit a shuffle instruction.
if (shiftVal <= 16) {
- llvm::SmallVector<llvm::Constant*, 16> Indices;
+ SmallVector<llvm::Constant*, 16> Indices;
for (unsigned i = 0; i != 16; ++i)
Indices.push_back(llvm::ConstantInt::get(Int32Ty, shiftVal + i));
@@ -2186,14 +2255,14 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// If palignr is shifting the pair of input vectors more than 16 but less
// than 32 bytes, emit a logical right shift of the destination.
if (shiftVal < 32) {
- const llvm::Type *VecTy = llvm::VectorType::get(Int64Ty, 2);
+ llvm::Type *VecTy = llvm::VectorType::get(Int64Ty, 2);
Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast");
Ops[1] = llvm::ConstantInt::get(Int32Ty, (shiftVal-16) * 8);
// create i32 constant
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_psrl_dq);
- return Builder.CreateCall(F, ArrayRef<Value *>(&Ops[0], 2), "palignr");
+ return Builder.CreateCall(F, makeArrayRef(&Ops[0], 2), "palignr");
}
// If palignr is shifting the pair of vectors more than 32 bytes, emit zero.
@@ -2352,7 +2421,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
- llvm::SmallVector<Value*, 4> Ops;
+ SmallVector<Value*, 4> Ops;
for (unsigned i = 0, e = E->getNumArgs(); i != e; i++)
Ops.push_back(EmitScalarExpr(E->getArg(i)));
@@ -2373,11 +2442,11 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
{
Ops[1] = Builder.CreateBitCast(Ops[1], Int8PtrTy);
- Ops[0] = Builder.CreateGEP(Ops[1], Ops[0], "tmp");
+ Ops[0] = Builder.CreateGEP(Ops[1], Ops[0]);
Ops.pop_back();
switch (BuiltinID) {
- default: assert(0 && "Unsupported ld/lvsl/lvsr intrinsic!");
+ default: llvm_unreachable("Unsupported ld/lvsl/lvsr intrinsic!");
case PPC::BI__builtin_altivec_lvx:
ID = Intrinsic::ppc_altivec_lvx;
break;
@@ -2412,11 +2481,11 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
case PPC::BI__builtin_altivec_stvewx:
{
Ops[2] = Builder.CreateBitCast(Ops[2], Int8PtrTy);
- Ops[1] = Builder.CreateGEP(Ops[2], Ops[1], "tmp");
+ Ops[1] = Builder.CreateGEP(Ops[2], Ops[1]);
Ops.pop_back();
switch (BuiltinID) {
- default: assert(0 && "Unsupported st intrinsic!");
+ default: llvm_unreachable("Unsupported st intrinsic!");
case PPC::BI__builtin_altivec_stvx:
ID = Intrinsic::ppc_altivec_stvx;
break;
diff --git a/lib/CodeGen/CGCUDANV.cpp b/lib/CodeGen/CGCUDANV.cpp
new file mode 100644
index 000000000000..88a0bdc821d7
--- /dev/null
+++ b/lib/CodeGen/CGCUDANV.cpp
@@ -0,0 +1,126 @@
+//===----- CGCUDANV.cpp - Interface to NVIDIA CUDA Runtime ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides a class for CUDA code generation targeting the NVIDIA CUDA
+// runtime library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGCUDARuntime.h"
+#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/Support/CallSite.h"
+
+#include <vector>
+
+using namespace clang;
+using namespace CodeGen;
+
+namespace {
+
+class CGNVCUDARuntime : public CGCUDARuntime {
+
+private:
+ llvm::Type *IntTy, *SizeTy;
+ llvm::PointerType *CharPtrTy, *VoidPtrTy;
+
+ llvm::Constant *getSetupArgumentFn() const;
+ llvm::Constant *getLaunchFn() const;
+
+public:
+ CGNVCUDARuntime(CodeGenModule &CGM);
+
+ void EmitDeviceStubBody(CodeGenFunction &CGF, FunctionArgList &Args);
+};
+
+}
+
+CGNVCUDARuntime::CGNVCUDARuntime(CodeGenModule &CGM) : CGCUDARuntime(CGM) {
+ CodeGen::CodeGenTypes &Types = CGM.getTypes();
+ ASTContext &Ctx = CGM.getContext();
+
+ IntTy = Types.ConvertType(Ctx.IntTy);
+ SizeTy = Types.ConvertType(Ctx.getSizeType());
+
+ CharPtrTy = llvm::PointerType::getUnqual(Types.ConvertType(Ctx.CharTy));
+ VoidPtrTy = cast<llvm::PointerType>(Types.ConvertType(Ctx.VoidPtrTy));
+}
+
+llvm::Constant *CGNVCUDARuntime::getSetupArgumentFn() const {
+ // cudaError_t cudaSetupArgument(void *, size_t, size_t)
+ std::vector<llvm::Type*> Params;
+ Params.push_back(VoidPtrTy);
+ Params.push_back(SizeTy);
+ Params.push_back(SizeTy);
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(IntTy,
+ Params, false),
+ "cudaSetupArgument");
+}
+
+llvm::Constant *CGNVCUDARuntime::getLaunchFn() const {
+ // cudaError_t cudaLaunch(char *)
+ std::vector<llvm::Type*> Params;
+ Params.push_back(CharPtrTy);
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(IntTy,
+ Params, false),
+ "cudaLaunch");
+}
+
+void CGNVCUDARuntime::EmitDeviceStubBody(CodeGenFunction &CGF,
+ FunctionArgList &Args) {
+ // Build the argument value list and the argument stack struct type.
+ llvm::SmallVector<llvm::Value *, 16> ArgValues;
+ std::vector<llvm::Type *> ArgTypes;
+ for (FunctionArgList::const_iterator I = Args.begin(), E = Args.end();
+ I != E; ++I) {
+ llvm::Value *V = CGF.GetAddrOfLocalVar(*I);
+ ArgValues.push_back(V);
+ assert(isa<llvm::PointerType>(V->getType()) && "Arg type not PointerType");
+ ArgTypes.push_back(cast<llvm::PointerType>(V->getType())->getElementType());
+ }
+ llvm::StructType *ArgStackTy = llvm::StructType::get(
+ CGF.getLLVMContext(), ArgTypes);
+
+ llvm::BasicBlock *EndBlock = CGF.createBasicBlock("setup.end");
+
+ // Emit the calls to cudaSetupArgument
+ llvm::Constant *cudaSetupArgFn = getSetupArgumentFn();
+ for (unsigned I = 0, E = Args.size(); I != E; ++I) {
+ llvm::Value *Args[3];
+ llvm::BasicBlock *NextBlock = CGF.createBasicBlock("setup.next");
+ Args[0] = CGF.Builder.CreatePointerCast(ArgValues[I], VoidPtrTy);
+ Args[1] = CGF.Builder.CreateIntCast(
+ llvm::ConstantExpr::getSizeOf(ArgTypes[I]),
+ SizeTy, false);
+ Args[2] = CGF.Builder.CreateIntCast(
+ llvm::ConstantExpr::getOffsetOf(ArgStackTy, I),
+ SizeTy, false);
+ llvm::CallSite CS = CGF.EmitCallOrInvoke(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);
+ CGF.EmitBlock(NextBlock);
+ }
+
+ // Emit the call to cudaLaunch
+ llvm::Constant *cudaLaunchFn = getLaunchFn();
+ llvm::Value *Arg = CGF.Builder.CreatePointerCast(CGF.CurFn, CharPtrTy);
+ CGF.EmitCallOrInvoke(cudaLaunchFn, Arg);
+ CGF.EmitBranch(EndBlock);
+
+ CGF.EmitBlock(EndBlock);
+}
+
+CGCUDARuntime *CodeGen::CreateNVCUDARuntime(CodeGenModule &CGM) {
+ return new CGNVCUDARuntime(CGM);
+}
diff --git a/lib/CodeGen/CGCUDARuntime.cpp b/lib/CodeGen/CGCUDARuntime.cpp
new file mode 100644
index 000000000000..77dc248d69e6
--- /dev/null
+++ b/lib/CodeGen/CGCUDARuntime.cpp
@@ -0,0 +1,55 @@
+//===----- CGCUDARuntime.cpp - Interface to CUDA Runtimes -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides an abstract class for CUDA code generation. Concrete
+// subclasses of this implement code generation for specific CUDA
+// runtime libraries.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGCUDARuntime.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/ExprCXX.h"
+#include "CGCall.h"
+#include "CodeGenFunction.h"
+
+using namespace clang;
+using namespace CodeGen;
+
+CGCUDARuntime::~CGCUDARuntime() {}
+
+RValue CGCUDARuntime::EmitCUDAKernelCallExpr(CodeGenFunction &CGF,
+ const CUDAKernelCallExpr *E,
+ ReturnValueSlot ReturnValue) {
+ llvm::BasicBlock *ConfigOKBlock = CGF.createBasicBlock("kcall.configok");
+ llvm::BasicBlock *ContBlock = CGF.createBasicBlock("kcall.end");
+
+ CodeGenFunction::ConditionalEvaluation eval(CGF);
+ CGF.EmitBranchOnBoolExpr(E->getConfig(), ContBlock, ConfigOKBlock);
+
+ eval.begin(CGF);
+ CGF.EmitBlock(ConfigOKBlock);
+
+ const Decl *TargetDecl = 0;
+ if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E->getCallee())) {
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) {
+ TargetDecl = DRE->getDecl();
+ }
+ }
+
+ llvm::Value *Callee = CGF.EmitScalarExpr(E->getCallee());
+ CGF.EmitCall(E->getCallee()->getType(), Callee, ReturnValue,
+ E->arg_begin(), E->arg_end(), TargetDecl);
+ CGF.EmitBranch(ContBlock);
+
+ CGF.EmitBlock(ContBlock);
+ eval.end(CGF);
+
+ return RValue::get(0);
+}
diff --git a/lib/CodeGen/CGCUDARuntime.h b/lib/CodeGen/CGCUDARuntime.h
new file mode 100644
index 000000000000..a99a67ae1ae7
--- /dev/null
+++ b/lib/CodeGen/CGCUDARuntime.h
@@ -0,0 +1,54 @@
+//===----- CGCUDARuntime.h - Interface to CUDA Runtimes ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides an abstract class for CUDA code generation. Concrete
+// subclasses of this implement code generation for specific CUDA
+// runtime libraries.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_CUDARUNTIME_H
+#define CLANG_CODEGEN_CUDARUNTIME_H
+
+namespace clang {
+
+class CUDAKernelCallExpr;
+
+namespace CodeGen {
+
+class CodeGenFunction;
+class CodeGenModule;
+class FunctionArgList;
+class ReturnValueSlot;
+class RValue;
+
+class CGCUDARuntime {
+protected:
+ CodeGenModule &CGM;
+
+public:
+ CGCUDARuntime(CodeGenModule &CGM) : CGM(CGM) {}
+ virtual ~CGCUDARuntime();
+
+ virtual RValue EmitCUDAKernelCallExpr(CodeGenFunction &CGF,
+ const CUDAKernelCallExpr *E,
+ ReturnValueSlot ReturnValue);
+
+ virtual void EmitDeviceStubBody(CodeGenFunction &CGF,
+ FunctionArgList &Args) = 0;
+
+};
+
+/// Creates an instance of a CUDA runtime class.
+CGCUDARuntime *CreateNVCUDARuntime(CodeGenModule &CGM);
+
+}
+}
+
+#endif
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index f6fc202eaae2..b5e6e0d7d993 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -138,7 +138,7 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
return true;
// Derive the type for the alias.
- const llvm::PointerType *AliasType
+ llvm::PointerType *AliasType
= getTypes().GetFunctionType(AliasDecl)->getPointerTo();
// Find the referrent. Some aliases might require a bitcast, in
@@ -154,7 +154,7 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
new llvm::GlobalAlias(AliasType, Linkage, "", Aliasee, &getModule());
// Switch any previous uses to the alias.
- llvm::StringRef MangledName = getMangledName(AliasDecl);
+ StringRef MangledName = getMangledName(AliasDecl);
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
assert(Entry->isDeclaration() && "definition already exists for alias");
@@ -214,14 +214,14 @@ CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor,
const CGFunctionInfo *fnInfo) {
GlobalDecl GD(ctor, ctorType);
- llvm::StringRef name = getMangledName(GD);
+ StringRef name = getMangledName(GD);
if (llvm::GlobalValue *existing = GetGlobalValue(name))
return existing;
if (!fnInfo) fnInfo = &getTypes().getFunctionInfo(ctor, ctorType);
const FunctionProtoType *proto = ctor->getType()->castAs<FunctionProtoType>();
- const llvm::FunctionType *fnType =
+ llvm::FunctionType *fnType =
getTypes().GetFunctionType(*fnInfo, proto->isVariadic());
return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD,
/*ForVTable=*/false));
@@ -236,11 +236,7 @@ void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) {
// The destructor used for destructing this as a most-derived class;
// call the base destructor and then destructs any virtual bases.
- if (!D->getParent()->isAbstract() || D->isVirtual()) {
- // We don't need to emit the complete ctor if the class is abstract,
- // unless the destructor is virtual and needs to be in the vtable.
- EmitGlobal(GlobalDecl(D, Dtor_Complete));
- }
+ EmitGlobal(GlobalDecl(D, Dtor_Complete));
// The destructor used for destructing this as a base class; ignores
// virtual bases.
@@ -282,13 +278,13 @@ CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor,
const CGFunctionInfo *fnInfo) {
GlobalDecl GD(dtor, dtorType);
- llvm::StringRef name = getMangledName(GD);
+ StringRef name = getMangledName(GD);
if (llvm::GlobalValue *existing = GetGlobalValue(name))
return existing;
if (!fnInfo) fnInfo = &getTypes().getFunctionInfo(dtor, dtorType);
- const llvm::FunctionType *fnType =
+ llvm::FunctionType *fnType =
getTypes().GetFunctionType(*fnInfo, false);
return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD,
@@ -296,7 +292,7 @@ CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor,
}
static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VTableIndex,
- llvm::Value *This, const llvm::Type *Ty) {
+ llvm::Value *This, llvm::Type *Ty) {
Ty = Ty->getPointerTo()->getPointerTo();
llvm::Value *VTable = CGF.GetVTablePtr(This, Ty);
@@ -307,9 +303,9 @@ static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VTableIndex,
llvm::Value *
CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
- const llvm::Type *Ty) {
+ llvm::Type *Ty) {
MD = MD->getCanonicalDecl();
- uint64_t VTableIndex = CGM.getVTables().getMethodVTableIndex(MD);
+ uint64_t VTableIndex = CGM.getVTableContext().getMethodVTableIndex(MD);
return ::BuildVirtualCall(*this, VTableIndex, This, Ty);
}
@@ -320,7 +316,7 @@ CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
llvm::Value *
CodeGenFunction::BuildAppleKextVirtualCall(const CXXMethodDecl *MD,
NestedNameSpecifier *Qual,
- const llvm::Type *Ty) {
+ llvm::Type *Ty) {
llvm::Value *VTable = 0;
assert((Qual->getKind() == NestedNameSpecifier::TypeSpec) &&
"BuildAppleKextVirtualCall - bad Qual kind");
@@ -339,9 +335,10 @@ CodeGenFunction::BuildAppleKextVirtualCall(const CXXMethodDecl *MD,
VTable = Builder.CreateBitCast(VTable, Ty);
assert(VTable && "BuildVirtualCall = kext vtbl pointer is null");
MD = MD->getCanonicalDecl();
- uint64_t VTableIndex = CGM.getVTables().getMethodVTableIndex(MD);
+ uint64_t VTableIndex = CGM.getVTableContext().getMethodVTableIndex(MD);
uint64_t AddressPoint =
- CGM.getVTables().getAddressPoint(BaseSubobject(RD, CharUnits::Zero()), RD);
+ CGM.getVTableContext().getVTableLayout(RD)
+ .getAddressPoint(BaseSubobject(RD, CharUnits::Zero()));
VTableIndex += AddressPoint;
llvm::Value *VFuncPtr =
Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfnkxt");
@@ -366,7 +363,7 @@ CodeGenFunction::BuildAppleKextVirtualDestructorCall(
&CGM.getTypes().getFunctionInfo(cast<CXXDestructorDecl>(MD),
Dtor_Complete);
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::Type *Ty
+ llvm::Type *Ty
= CGM.getTypes().GetFunctionType(*FInfo, FPT->isVariadic());
llvm::Value *VTable = CGM.getVTables().GetAddrOfVTable(RD);
@@ -374,9 +371,10 @@ CodeGenFunction::BuildAppleKextVirtualDestructorCall(
VTable = Builder.CreateBitCast(VTable, Ty);
DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl());
uint64_t VTableIndex =
- CGM.getVTables().getMethodVTableIndex(GlobalDecl(DD, Type));
+ CGM.getVTableContext().getMethodVTableIndex(GlobalDecl(DD, Type));
uint64_t AddressPoint =
- CGM.getVTables().getAddressPoint(BaseSubobject(RD, CharUnits::Zero()), RD);
+ CGM.getVTableContext().getVTableLayout(RD)
+ .getAddressPoint(BaseSubobject(RD, CharUnits::Zero()));
VTableIndex += AddressPoint;
llvm::Value *VFuncPtr =
Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfnkxt");
@@ -387,10 +385,10 @@ CodeGenFunction::BuildAppleKextVirtualDestructorCall(
llvm::Value *
CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
- llvm::Value *This, const llvm::Type *Ty) {
+ llvm::Value *This, llvm::Type *Ty) {
DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl());
uint64_t VTableIndex =
- CGM.getVTables().getMethodVTableIndex(GlobalDecl(DD, Type));
+ CGM.getVTableContext().getMethodVTableIndex(GlobalDecl(DD, Type));
return ::BuildVirtualCall(*this, VTableIndex, This, Ty);
}
diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp
index dcc28b45cfc3..248448ccdc2e 100644
--- a/lib/CodeGen/CGCXXABI.cpp
+++ b/lib/CodeGen/CGCXXABI.cpp
@@ -20,9 +20,9 @@ using namespace CodeGen;
CGCXXABI::~CGCXXABI() { }
static void ErrorUnsupportedABI(CodeGenFunction &CGF,
- llvm::StringRef S) {
- Diagnostic &Diags = CGF.CGM.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
+ StringRef S) {
+ DiagnosticsEngine &Diags = CGF.CGM.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot yet compile %1 in this ABI");
Diags.Report(CGF.getContext().getFullLoc(CGF.CurCodeDecl->getLocation()),
DiagID)
@@ -49,7 +49,7 @@ llvm::Value *CGCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
MPT->getPointeeType()->getAs<FunctionProtoType>();
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
- const llvm::FunctionType *FTy =
+ llvm::FunctionType *FTy =
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
FPT->isVariadic());
return llvm::Constant::getNullValue(FTy->getPointerTo());
@@ -60,7 +60,7 @@ llvm::Value *CGCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF,
llvm::Value *MemPtr,
const MemberPointerType *MPT) {
ErrorUnsupportedABI(CGF, "loads of member pointers");
- const llvm::Type *Ty = CGF.ConvertType(MPT->getPointeeType())->getPointerTo();
+ llvm::Type *Ty = CGF.ConvertType(MPT->getPointeeType())->getPointerTo();
return llvm::Constant::getNullValue(Ty);
}
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index 29f299a43e37..c2abf358329c 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -15,14 +15,14 @@
#ifndef CLANG_CODEGEN_CXXABI_H
#define CLANG_CODEGEN_CXXABI_H
+#include "clang/Basic/LLVM.h"
+
#include "CodeGenFunction.h"
namespace llvm {
class Constant;
class Type;
class Value;
-
- template <class T> class SmallVectorImpl;
}
namespace clang {
@@ -151,7 +151,7 @@ public:
virtual void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
CXXCtorType T,
CanQualType &ResTy,
- llvm::SmallVectorImpl<CanQualType> &ArgTys) = 0;
+ SmallVectorImpl<CanQualType> &ArgTys) = 0;
/// Build the signature of the given destructor variant by adding
/// any required parameters. For convenience, ResTy has been
@@ -160,7 +160,7 @@ public:
virtual void BuildDestructorSignature(const CXXDestructorDecl *Dtor,
CXXDtorType T,
CanQualType &ResTy,
- llvm::SmallVectorImpl<CanQualType> &ArgTys) = 0;
+ SmallVectorImpl<CanQualType> &ArgTys) = 0;
/// Build the ABI-specific portion of the parameter list for a
/// function. This generally involves a 'this' parameter and
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index f8783ad08d00..6ae2d0c96775 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -69,14 +69,14 @@ static CanQualType GetReturnType(QualType RetTy) {
const CGFunctionInfo &
CodeGenTypes::getFunctionInfo(CanQual<FunctionNoProtoType> FTNP) {
return getFunctionInfo(FTNP->getResultType().getUnqualifiedType(),
- llvm::SmallVector<CanQualType, 16>(),
+ SmallVector<CanQualType, 16>(),
FTNP->getExtInfo());
}
/// \param Args - contains any initial parameters besides those
/// in the formal type
static const CGFunctionInfo &getFunctionInfo(CodeGenTypes &CGT,
- llvm::SmallVectorImpl<CanQualType> &ArgTys,
+ SmallVectorImpl<CanQualType> &ArgTys,
CanQual<FunctionProtoType> FTP) {
// FIXME: Kill copy.
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
@@ -87,7 +87,7 @@ static const CGFunctionInfo &getFunctionInfo(CodeGenTypes &CGT,
const CGFunctionInfo &
CodeGenTypes::getFunctionInfo(CanQual<FunctionProtoType> FTP) {
- llvm::SmallVector<CanQualType, 16> ArgTys;
+ SmallVector<CanQualType, 16> ArgTys;
return ::getFunctionInfo(*this, ArgTys, FTP);
}
@@ -113,7 +113,7 @@ static CallingConv getCallingConventionForDecl(const Decl *D) {
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD,
const FunctionProtoType *FTP) {
- llvm::SmallVector<CanQualType, 16> ArgTys;
+ SmallVector<CanQualType, 16> ArgTys;
// Add the 'this' pointer.
ArgTys.push_back(GetThisType(Context, RD));
@@ -123,7 +123,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD,
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) {
- llvm::SmallVector<CanQualType, 16> ArgTys;
+ SmallVector<CanQualType, 16> ArgTys;
assert(!isa<CXXConstructorDecl>(MD) && "wrong method for contructors!");
assert(!isa<CXXDestructorDecl>(MD) && "wrong method for destructors!");
@@ -137,7 +137,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) {
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D,
CXXCtorType Type) {
- llvm::SmallVector<CanQualType, 16> ArgTys;
+ SmallVector<CanQualType, 16> ArgTys;
ArgTys.push_back(GetThisType(Context, D->getParent()));
CanQualType ResTy = Context.VoidTy;
@@ -154,7 +154,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D,
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D,
CXXDtorType Type) {
- llvm::SmallVector<CanQualType, 2> ArgTys;
+ SmallVector<CanQualType, 2> ArgTys;
ArgTys.push_back(GetThisType(Context, D->getParent()));
CanQualType ResTy = Context.VoidTy;
@@ -180,11 +180,11 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) {
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) {
- llvm::SmallVector<CanQualType, 16> ArgTys;
+ SmallVector<CanQualType, 16> ArgTys;
ArgTys.push_back(Context.getCanonicalParamType(MD->getSelfDecl()->getType()));
ArgTys.push_back(Context.getCanonicalParamType(Context.getObjCSelType()));
// FIXME: Kill copy?
- for (ObjCMethodDecl::param_iterator i = MD->param_begin(),
+ for (ObjCMethodDecl::param_const_iterator i = MD->param_begin(),
e = MD->param_end(); i != e; ++i) {
ArgTys.push_back(Context.getCanonicalParamType((*i)->getType()));
}
@@ -216,7 +216,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
const CallArgList &Args,
const FunctionType::ExtInfo &Info) {
// FIXME: Kill copy.
- llvm::SmallVector<CanQualType, 16> ArgTys;
+ SmallVector<CanQualType, 16> ArgTys;
for (CallArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i)
ArgTys.push_back(Context.getCanonicalParamType(i->Ty));
@@ -227,7 +227,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
const FunctionArgList &Args,
const FunctionType::ExtInfo &Info) {
// FIXME: Kill copy.
- llvm::SmallVector<CanQualType, 16> ArgTys;
+ SmallVector<CanQualType, 16> ArgTys;
for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i)
ArgTys.push_back(Context.getCanonicalParamType((*i)->getType()));
@@ -235,15 +235,15 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
}
const CGFunctionInfo &CodeGenTypes::getNullaryFunctionInfo() {
- llvm::SmallVector<CanQualType, 1> args;
+ SmallVector<CanQualType, 1> args;
return getFunctionInfo(getContext().VoidTy, args, FunctionType::ExtInfo());
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
- const llvm::SmallVectorImpl<CanQualType> &ArgTys,
+ const SmallVectorImpl<CanQualType> &ArgTys,
const FunctionType::ExtInfo &Info) {
#ifndef NDEBUG
- for (llvm::SmallVectorImpl<CanQualType>::const_iterator
+ for (SmallVectorImpl<CanQualType>::const_iterator
I = ArgTys.begin(), E = ArgTys.end(); I != E; ++I)
assert(I->isCanonicalAsParam());
#endif
@@ -312,50 +312,65 @@ CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention,
/***/
void CodeGenTypes::GetExpandedTypes(QualType type,
- llvm::SmallVectorImpl<llvm::Type*> &expandedTypes) {
- const RecordType *RT = type->getAsStructureType();
- assert(RT && "Can only expand structure types.");
- const RecordDecl *RD = RT->getDecl();
- assert(!RD->hasFlexibleArrayMember() &&
- "Cannot expand structure with flexible array.");
-
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
+ SmallVectorImpl<llvm::Type*> &expandedTypes) {
+ if (const ConstantArrayType *AT = Context.getAsConstantArrayType(type)) {
+ uint64_t NumElts = AT->getSize().getZExtValue();
+ for (uint64_t Elt = 0; Elt < NumElts; ++Elt)
+ GetExpandedTypes(AT->getElementType(), expandedTypes);
+ } else if (const RecordType *RT = type->getAsStructureType()) {
+ const RecordDecl *RD = RT->getDecl();
+ assert(!RD->hasFlexibleArrayMember() &&
+ "Cannot expand structure with flexible array.");
+ for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
i != e; ++i) {
- const FieldDecl *FD = *i;
- assert(!FD->isBitField() &&
- "Cannot expand structure with bit-field members.");
-
- QualType fieldType = FD->getType();
- if (fieldType->isRecordType())
- GetExpandedTypes(fieldType, expandedTypes);
- else
- expandedTypes.push_back(ConvertType(fieldType));
- }
+ const FieldDecl *FD = *i;
+ assert(!FD->isBitField() &&
+ "Cannot expand structure with bit-field members.");
+ GetExpandedTypes(FD->getType(), expandedTypes);
+ }
+ } else if (const ComplexType *CT = type->getAs<ComplexType>()) {
+ llvm::Type *EltTy = ConvertType(CT->getElementType());
+ expandedTypes.push_back(EltTy);
+ expandedTypes.push_back(EltTy);
+ } else
+ expandedTypes.push_back(ConvertType(type));
}
llvm::Function::arg_iterator
CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV,
llvm::Function::arg_iterator AI) {
- const RecordType *RT = Ty->getAsStructureType();
- assert(RT && "Can only expand structure types.");
-
- RecordDecl *RD = RT->getDecl();
assert(LV.isSimple() &&
"Unexpected non-simple lvalue during struct expansion.");
llvm::Value *Addr = LV.getAddress();
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
+
+ if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) {
+ unsigned NumElts = AT->getSize().getZExtValue();
+ QualType EltTy = AT->getElementType();
+ for (unsigned Elt = 0; Elt < NumElts; ++Elt) {
+ llvm::Value *EltAddr = Builder.CreateConstGEP2_32(Addr, 0, Elt);
+ LValue LV = MakeAddrLValue(EltAddr, EltTy);
+ AI = ExpandTypeFromArgs(EltTy, LV, AI);
+ }
+ } else if (const RecordType *RT = Ty->getAsStructureType()) {
+ RecordDecl *RD = RT->getDecl();
+ for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
i != e; ++i) {
- FieldDecl *FD = *i;
- QualType FT = FD->getType();
+ FieldDecl *FD = *i;
+ QualType FT = FD->getType();
- // FIXME: What are the right qualifiers here?
- LValue LV = EmitLValueForField(Addr, FD, 0);
- if (CodeGenFunction::hasAggregateLLVMType(FT)) {
+ // FIXME: What are the right qualifiers here?
+ LValue LV = EmitLValueForField(Addr, FD, 0);
AI = ExpandTypeFromArgs(FT, LV, AI);
- } else {
- EmitStoreThroughLValue(RValue::get(AI), LV);
- ++AI;
}
+ } else if (const ComplexType *CT = Ty->getAs<ComplexType>()) {
+ QualType EltTy = CT->getElementType();
+ llvm::Value *RealAddr = Builder.CreateStructGEP(Addr, 0, "real");
+ EmitStoreThroughLValue(RValue::get(AI++), MakeAddrLValue(RealAddr, EltTy));
+ llvm::Value *ImagAddr = Builder.CreateStructGEP(Addr, 0, "imag");
+ EmitStoreThroughLValue(RValue::get(AI++), MakeAddrLValue(ImagAddr, EltTy));
+ } else {
+ EmitStoreThroughLValue(RValue::get(AI), LV);
+ ++AI;
}
return AI;
@@ -367,12 +382,12 @@ CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV,
/// with an in-memory size smaller than DstSize.
static llvm::Value *
EnterStructPointerForCoercedAccess(llvm::Value *SrcPtr,
- const llvm::StructType *SrcSTy,
+ llvm::StructType *SrcSTy,
uint64_t DstSize, CodeGenFunction &CGF) {
// We can't dive into a zero-element struct.
if (SrcSTy->getNumElements() == 0) return SrcPtr;
- const llvm::Type *FirstElt = SrcSTy->getElementType(0);
+ llvm::Type *FirstElt = SrcSTy->getElementType(0);
// If the first elt is at least as large as what we're looking for, or if the
// first element is the same size as the whole struct, we can enter it.
@@ -386,9 +401,9 @@ EnterStructPointerForCoercedAccess(llvm::Value *SrcPtr,
SrcPtr = CGF.Builder.CreateConstGEP2_32(SrcPtr, 0, 0, "coerce.dive");
// If the first element is a struct, recurse.
- const llvm::Type *SrcTy =
+ llvm::Type *SrcTy =
cast<llvm::PointerType>(SrcPtr->getType())->getElementType();
- if (const llvm::StructType *SrcSTy = dyn_cast<llvm::StructType>(SrcTy))
+ if (llvm::StructType *SrcSTy = dyn_cast<llvm::StructType>(SrcTy))
return EnterStructPointerForCoercedAccess(SrcPtr, SrcSTy, DstSize, CGF);
return SrcPtr;
@@ -398,7 +413,7 @@ EnterStructPointerForCoercedAccess(llvm::Value *SrcPtr,
/// are either integers or pointers. This does a truncation of the value if it
/// is too large or a zero extension if it is too small.
static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val,
- const llvm::Type *Ty,
+ llvm::Type *Ty,
CodeGenFunction &CGF) {
if (Val->getType() == Ty)
return Val;
@@ -412,7 +427,7 @@ static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val,
Val = CGF.Builder.CreatePtrToInt(Val, CGF.IntPtrTy, "coerce.val.pi");
}
- const llvm::Type *DestIntTy = Ty;
+ llvm::Type *DestIntTy = Ty;
if (isa<llvm::PointerType>(DestIntTy))
DestIntTy = CGF.IntPtrTy;
@@ -433,9 +448,9 @@ static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val,
/// destination type; in this situation the values of bits which not
/// present in the src are undefined.
static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr,
- const llvm::Type *Ty,
+ llvm::Type *Ty,
CodeGenFunction &CGF) {
- const llvm::Type *SrcTy =
+ llvm::Type *SrcTy =
cast<llvm::PointerType>(SrcPtr->getType())->getElementType();
// If SrcTy and Ty are the same, just do a load.
@@ -444,7 +459,7 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr,
uint64_t DstSize = CGF.CGM.getTargetData().getTypeAllocSize(Ty);
- if (const llvm::StructType *SrcSTy = dyn_cast<llvm::StructType>(SrcTy)) {
+ if (llvm::StructType *SrcSTy = dyn_cast<llvm::StructType>(SrcTy)) {
SrcPtr = EnterStructPointerForCoercedAccess(SrcPtr, SrcSTy, DstSize, CGF);
SrcTy = cast<llvm::PointerType>(SrcPtr->getType())->getElementType();
}
@@ -495,7 +510,7 @@ static void BuildAggStore(CodeGenFunction &CGF, llvm::Value *Val,
llvm::Value *DestPtr, bool DestIsVolatile,
bool LowAlignment) {
// Prefer scalar stores to first-class aggregate stores.
- if (const llvm::StructType *STy =
+ if (llvm::StructType *STy =
dyn_cast<llvm::StructType>(Val->getType())) {
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
llvm::Value *EltPtr = CGF.Builder.CreateConstGEP2_32(DestPtr, 0, i);
@@ -519,8 +534,8 @@ static void CreateCoercedStore(llvm::Value *Src,
llvm::Value *DstPtr,
bool DstIsVolatile,
CodeGenFunction &CGF) {
- const llvm::Type *SrcTy = Src->getType();
- const llvm::Type *DstTy =
+ llvm::Type *SrcTy = Src->getType();
+ llvm::Type *DstTy =
cast<llvm::PointerType>(DstPtr->getType())->getElementType();
if (SrcTy == DstTy) {
CGF.Builder.CreateStore(Src, DstPtr, DstIsVolatile);
@@ -529,7 +544,7 @@ static void CreateCoercedStore(llvm::Value *Src,
uint64_t SrcSize = CGF.CGM.getTargetData().getTypeAllocSize(SrcTy);
- if (const llvm::StructType *DstSTy = dyn_cast<llvm::StructType>(DstTy)) {
+ if (llvm::StructType *DstSTy = dyn_cast<llvm::StructType>(DstTy)) {
DstPtr = EnterStructPointerForCoercedAccess(DstPtr, DstSTy, SrcSize, CGF);
DstTy = cast<llvm::PointerType>(DstPtr->getType())->getElementType();
}
@@ -584,11 +599,11 @@ bool CodeGenModule::ReturnTypeUsesFPRet(QualType ResultType) {
default:
return false;
case BuiltinType::Float:
- return getContext().Target.useObjCFPRetForRealType(TargetInfo::Float);
+ return getContext().getTargetInfo().useObjCFPRetForRealType(TargetInfo::Float);
case BuiltinType::Double:
- return getContext().Target.useObjCFPRetForRealType(TargetInfo::Double);
+ return getContext().getTargetInfo().useObjCFPRetForRealType(TargetInfo::Double);
case BuiltinType::LongDouble:
- return getContext().Target.useObjCFPRetForRealType(
+ return getContext().getTargetInfo().useObjCFPRetForRealType(
TargetInfo::LongDouble);
}
}
@@ -614,8 +629,8 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) {
bool Inserted = FunctionsBeingProcessed.insert(&FI); (void)Inserted;
assert(Inserted && "Recursively being processed?");
- llvm::SmallVector<llvm::Type*, 8> argTypes;
- const llvm::Type *resultType = 0;
+ SmallVector<llvm::Type*, 8> argTypes;
+ llvm::Type *resultType = 0;
const ABIArgInfo &retAI = FI.getReturnInfo();
switch (retAI.getKind()) {
@@ -632,7 +647,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) {
resultType = llvm::Type::getVoidTy(getLLVMContext());
QualType ret = FI.getReturnType();
- const llvm::Type *ty = ConvertType(ret);
+ llvm::Type *ty = ConvertType(ret);
unsigned addressSpace = Context.getTargetAddressSpace(ret);
argTypes.push_back(llvm::PointerType::get(ty, addressSpace));
break;
@@ -653,7 +668,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) {
case ABIArgInfo::Indirect: {
// indirect arguments are always on the stack, which is addr space #0.
- const llvm::Type *LTy = ConvertTypeForMem(it->type);
+ llvm::Type *LTy = ConvertTypeForMem(it->type);
argTypes.push_back(LTy->getPointerTo());
break;
}
@@ -664,7 +679,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) {
// way is semantically identical, but fast-isel and the optimizer
// generally likes scalar values better than FCAs.
llvm::Type *argType = argAI.getCoerceToType();
- if (const llvm::StructType *st = dyn_cast<llvm::StructType>(argType)) {
+ if (llvm::StructType *st = dyn_cast<llvm::StructType>(argType)) {
for (unsigned i = 0, e = st->getNumElements(); i != e; ++i)
argTypes.push_back(st->getElementType(i));
} else {
@@ -685,7 +700,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) {
return llvm::FunctionType::get(resultType, argTypes, isVariadic);
}
-const llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) {
+llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
@@ -714,6 +729,8 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
// FIXME: handle sseregparm someday...
if (TargetDecl) {
+ if (TargetDecl->hasAttr<ReturnsTwiceAttr>())
+ FuncAttrs |= llvm::Attribute::ReturnsTwice;
if (TargetDecl->hasAttr<NoThrowAttr>())
FuncAttrs |= llvm::Attribute::NoUnwind;
else if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
@@ -724,10 +741,18 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
if (TargetDecl->hasAttr<NoReturnAttr>())
FuncAttrs |= llvm::Attribute::NoReturn;
- if (TargetDecl->hasAttr<ConstAttr>())
+
+ if (TargetDecl->hasAttr<ReturnsTwiceAttr>())
+ FuncAttrs |= llvm::Attribute::ReturnsTwice;
+
+ // 'const' and 'pure' attribute functions are also nounwind.
+ if (TargetDecl->hasAttr<ConstAttr>()) {
FuncAttrs |= llvm::Attribute::ReadNone;
- else if (TargetDecl->hasAttr<PureAttr>())
+ FuncAttrs |= llvm::Attribute::NoUnwind;
+ } else if (TargetDecl->hasAttr<PureAttr>()) {
FuncAttrs |= llvm::Attribute::ReadOnly;
+ FuncAttrs |= llvm::Attribute::NoUnwind;
+ }
if (TargetDecl->hasAttr<MallocAttr>())
RetAttrs |= llvm::Attribute::NoAlias;
}
@@ -763,7 +788,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
break;
case ABIArgInfo::Expand:
- assert(0 && "Invalid ABI kind for return argument");
+ llvm_unreachable("Invalid ABI kind for return argument");
}
if (RetAttrs)
@@ -776,7 +801,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
else
RegParm = CodeGenOpts.NumRegisterParameters;
- unsigned PointerWidth = getContext().Target.getPointerWidth(0);
+ unsigned PointerWidth = getContext().getTargetInfo().getPointerWidth(0);
for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
ie = FI.arg_end(); it != ie; ++it) {
QualType ParamType = it->type;
@@ -803,7 +828,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
}
// FIXME: handle sseregparm someday...
- if (const llvm::StructType *STy =
+ if (llvm::StructType *STy =
dyn_cast<llvm::StructType>(AI.getCoerceToType()))
Index += STy->getNumElements()-1; // 1 will be added below.
break;
@@ -824,7 +849,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
continue;
case ABIArgInfo::Expand: {
- llvm::SmallVector<llvm::Type*, 8> types;
+ SmallVector<llvm::Type*, 8> types;
// FIXME: This is rather inefficient. Do we ever actually need to do
// anything here? The result should be just reconstructed on the other
// side, so extension should be a non-issue.
@@ -847,7 +872,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
static llvm::Value *emitArgumentDemotion(CodeGenFunction &CGF,
const VarDecl *var,
llvm::Value *value) {
- const llvm::Type *varType = CGF.ConvertType(var->getType());
+ llvm::Type *varType = CGF.ConvertType(var->getType());
// This can happen with promotions that actually don't change the
// underlying type, like the enum promotions.
@@ -872,7 +897,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl)) {
if (FD->hasImplicitReturnZero()) {
QualType RetTy = FD->getResultType().getUnqualifiedType();
- const llvm::Type* LLVMTy = CGM.getTypes().ConvertType(RetTy);
+ llvm::Type* LLVMTy = CGM.getTypes().ConvertType(RetTy);
llvm::Constant* Zero = llvm::Constant::getNullValue(LLVMTy);
Builder.CreateStore(Zero, ReturnValue);
}
@@ -887,6 +912,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// Name the struct return argument.
if (CGM.ReturnTypeUsesSRet(FI)) {
AI->setName("agg.result");
+ AI->addAttr(llvm::Attribute::NoAlias);
++AI;
}
@@ -918,7 +944,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
//
// FIXME: We should have a common utility for generating an aggregate
// copy.
- const llvm::Type *I8PtrTy = Builder.getInt8PtrTy();
+ llvm::Type *I8PtrTy = Builder.getInt8PtrTy();
CharUnits Size = getContext().getTypeSizeInChars(Ty);
llvm::Value *Dst = Builder.CreateBitCast(AlignedTemp, I8PtrTy);
llvm::Value *Src = Builder.CreateBitCast(V, I8PtrTy);
@@ -954,9 +980,13 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
if (Arg->getType().isRestrictQualified())
AI->addAttr(llvm::Attribute::NoAlias);
+ // Ensure the argument is the correct type.
+ if (V->getType() != ArgI.getCoerceToType())
+ V = Builder.CreateBitCast(V, ArgI.getCoerceToType());
+
if (isPromoted)
V = emitArgumentDemotion(*this, Arg, V);
-
+
EmitParmDecl(*Arg, V, ArgNo);
break;
}
@@ -985,13 +1015,13 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// If the coerce-to type is a first class aggregate, we flatten it and
// pass the elements. Either way is semantically identical, but fast-isel
// and the optimizer generally likes scalar values better than FCAs.
- if (const llvm::StructType *STy =
+ if (llvm::StructType *STy =
dyn_cast<llvm::StructType>(ArgI.getCoerceToType())) {
Ptr = Builder.CreateBitCast(Ptr, llvm::PointerType::getUnqual(STy));
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
assert(AI != Fn->arg_end() && "Argument mismatch!");
- AI->setName(Arg->getName() + ".coerce" + llvm::Twine(i));
+ AI->setName(Arg->getName() + ".coerce" + Twine(i));
llvm::Value *EltPtr = Builder.CreateConstGEP2_32(Ptr, 0, i);
Builder.CreateStore(AI++, EltPtr);
}
@@ -1025,7 +1055,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// Name the arguments used in expansion and increment AI.
unsigned Index = 0;
for (; AI != End; ++AI, ++Index)
- AI->setName(Arg->getName() + "." + llvm::Twine(Index));
+ AI->setName(Arg->getName() + "." + Twine(Index));
continue;
}
@@ -1054,12 +1084,12 @@ static llvm::Value *tryEmitFusedAutoreleaseOfResult(CodeGenFunction &CGF,
if (BB->empty()) return 0;
if (&BB->back() != result) return 0;
- const llvm::Type *resultType = result->getType();
+ llvm::Type *resultType = result->getType();
// result is in a BasicBlock and is therefore an Instruction.
llvm::Instruction *generator = cast<llvm::Instruction>(result);
- llvm::SmallVector<llvm::Instruction*,4> insnsToKill;
+ SmallVector<llvm::Instruction*,4> insnsToKill;
// Look for:
// %generator = bitcast %type1* %generator2 to %type2*
@@ -1112,7 +1142,7 @@ static llvm::Value *tryEmitFusedAutoreleaseOfResult(CodeGenFunction &CGF,
}
// Delete all the unnecessary instructions, from latest to earliest.
- for (llvm::SmallVectorImpl<llvm::Instruction*>::iterator
+ for (SmallVectorImpl<llvm::Instruction*>::iterator
i = insnsToKill.begin(), e = insnsToKill.end(); i != e; ++i)
(*i)->eraseFromParent();
@@ -1218,7 +1248,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
break;
case ABIArgInfo::Expand:
- assert(0 && "Invalid ABI kind for return argument");
+ llvm_unreachable("Invalid ABI kind for return argument");
}
llvm::Instruction *Ret = RV ? Builder.CreateRet(RV) : Builder.CreateRetVoid();
@@ -1324,7 +1354,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
// The dest and src types don't necessarily match in LLVM terms
// because of the crazy ObjC compatibility rules.
- const llvm::PointerType *destType =
+ llvm::PointerType *destType =
cast<llvm::PointerType>(CGF.ConvertType(CRE->getType()));
// If the address is a constant null, just pass the appropriate null.
@@ -1406,9 +1436,14 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
return emitWritebackArg(*this, args, CRE);
}
- if (type->isReferenceType())
+ assert(type->isReferenceType() == E->isGLValue() &&
+ "reference binding to unmaterialized r-value!");
+
+ if (E->isGLValue()) {
+ assert(E->getObjectKind() == OK_Ordinary);
return args.add(EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0),
type);
+ }
if (hasAggregateLLVMType(type) && !E->getType()->isAnyComplexType() &&
isa<ImplicitCastExpr>(E) &&
@@ -1427,8 +1462,8 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
/// on the current state of the EH stack.
llvm::CallSite
CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
- llvm::ArrayRef<llvm::Value *> Args,
- const llvm::Twine &Name) {
+ ArrayRef<llvm::Value *> Args,
+ const Twine &Name) {
llvm::BasicBlock *InvokeDest = getInvokeDest();
if (!InvokeDest)
return Builder.CreateCall(Callee, Args, Name);
@@ -1442,8 +1477,8 @@ CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
llvm::CallSite
CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
- const llvm::Twine &Name) {
- return EmitCallOrInvoke(Callee, llvm::ArrayRef<llvm::Value *>(), Name);
+ const Twine &Name) {
+ return EmitCallOrInvoke(Callee, ArrayRef<llvm::Value *>(), Name);
}
static void checkArgMatches(llvm::Value *Elt, unsigned &ArgNo,
@@ -1456,28 +1491,45 @@ static void checkArgMatches(llvm::Value *Elt, unsigned &ArgNo,
}
void CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
- llvm::SmallVector<llvm::Value*,16> &Args,
+ SmallVector<llvm::Value*,16> &Args,
llvm::FunctionType *IRFuncTy) {
- const RecordType *RT = Ty->getAsStructureType();
- assert(RT && "Can only expand structure types.");
-
- RecordDecl *RD = RT->getDecl();
- assert(RV.isAggregate() && "Unexpected rvalue during struct expansion");
- llvm::Value *Addr = RV.getAggregateAddr();
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i) {
- FieldDecl *FD = *i;
- QualType FT = FD->getType();
-
- // FIXME: What are the right qualifiers here?
- LValue LV = EmitLValueForField(Addr, FD, 0);
- if (CodeGenFunction::hasAggregateLLVMType(FT)) {
- ExpandTypeToArgs(FT, RValue::getAggregate(LV.getAddress()),
- Args, IRFuncTy);
- continue;
+ if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) {
+ unsigned NumElts = AT->getSize().getZExtValue();
+ QualType EltTy = AT->getElementType();
+ 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 (CodeGenFunction::hasAggregateLLVMType(EltTy))
+ EltRV = RValue::getAggregate(LV.getAddress());
+ else
+ EltRV = EmitLoadOfLValue(LV);
+ ExpandTypeToArgs(EltTy, EltRV, Args, IRFuncTy);
}
+ } else if (const RecordType *RT = Ty->getAsStructureType()) {
+ RecordDecl *RD = RT->getDecl();
+ assert(RV.isAggregate() && "Unexpected rvalue during struct expansion");
+ llvm::Value *Addr = RV.getAggregateAddr();
+ for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
+ i != e; ++i) {
+ FieldDecl *FD = *i;
+ QualType FT = FD->getType();
- RValue RV = EmitLoadOfLValue(LV);
+ // FIXME: What are the right qualifiers here?
+ LValue LV = EmitLValueForField(Addr, FD, 0);
+ RValue FldRV;
+ if (CodeGenFunction::hasAggregateLLVMType(FT))
+ FldRV = RValue::getAggregate(LV.getAddress());
+ else
+ FldRV = EmitLoadOfLValue(LV);
+ ExpandTypeToArgs(FT, FldRV, Args, IRFuncTy);
+ }
+ } else if (isa<ComplexType>(Ty)) {
+ ComplexPairTy CV = RV.getComplexVal();
+ Args.push_back(CV.first);
+ Args.push_back(CV.second);
+ } else {
assert(RV.isScalar() &&
"Unexpected non-scalar rvalue during struct expansion.");
@@ -1499,7 +1551,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
const Decl *TargetDecl,
llvm::Instruction **callOrInvoke) {
// FIXME: We no longer need the types from CallArgs; lift up and simplify.
- llvm::SmallVector<llvm::Value*, 16> Args;
+ SmallVector<llvm::Value*, 16> Args;
// Handle struct-return functions by passing a pointer to the
// location that we would like to return into.
@@ -1630,7 +1682,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// If the coerce-to type is a first class aggregate, we flatten it and
// pass the elements. Either way is semantically identical, but fast-isel
// and the optimizer generally likes scalar values better than FCAs.
- if (const llvm::StructType *STy =
+ if (llvm::StructType *STy =
dyn_cast<llvm::StructType>(ArgInfo.getCoerceToType())) {
SrcPtr = Builder.CreateBitCast(SrcPtr,
llvm::PointerType::getUnqual(STy));
@@ -1668,10 +1720,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// with unprototyped functions.
if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(Callee))
if (llvm::Function *CalleeF = dyn_cast<llvm::Function>(CE->getOperand(0))) {
- const llvm::PointerType *CurPT=cast<llvm::PointerType>(Callee->getType());
- const llvm::FunctionType *CurFT =
+ llvm::PointerType *CurPT=cast<llvm::PointerType>(Callee->getType());
+ llvm::FunctionType *CurFT =
cast<llvm::FunctionType>(CurPT->getElementType());
- const llvm::FunctionType *ActualFT = CalleeF->getFunctionType();
+ llvm::FunctionType *ActualFT = CalleeF->getFunctionType();
if (CE->getOpcode() == llvm::Instruction::BitCast &&
ActualFT->getReturnType() == CurFT->getReturnType() &&
@@ -1813,11 +1865,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
}
case ABIArgInfo::Expand:
- assert(0 && "Invalid ABI kind for return argument");
+ llvm_unreachable("Invalid ABI kind for return argument");
}
- assert(0 && "Unhandled ABIArgInfo::Kind");
- return RValue::get(0);
+ llvm_unreachable("Unhandled ABIArgInfo::Kind");
}
/* VarArg handling */
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index 343b944bf6c9..24ed366dd860 100644
--- a/lib/CodeGen/CGCall.h
+++ b/lib/CodeGen/CGCall.h
@@ -42,7 +42,7 @@ namespace clang {
class VarDecl;
namespace CodeGen {
- typedef llvm::SmallVector<llvm::AttributeWithIndex, 8> AttributeListType;
+ typedef SmallVector<llvm::AttributeWithIndex, 8> AttributeListType;
struct CallArg {
RValue RV;
@@ -56,7 +56,7 @@ namespace CodeGen {
/// CallArgList - Type for representing both the value and type of
/// arguments in a call.
class CallArgList :
- public llvm::SmallVector<CallArg, 16> {
+ public SmallVector<CallArg, 16> {
public:
struct Writeback {
/// The original argument.
@@ -90,18 +90,18 @@ namespace CodeGen {
bool hasWritebacks() const { return !Writebacks.empty(); }
- typedef llvm::SmallVectorImpl<Writeback>::const_iterator writeback_iterator;
+ typedef SmallVectorImpl<Writeback>::const_iterator writeback_iterator;
writeback_iterator writeback_begin() const { return Writebacks.begin(); }
writeback_iterator writeback_end() const { return Writebacks.end(); }
private:
- llvm::SmallVector<Writeback, 1> Writebacks;
+ SmallVector<Writeback, 1> Writebacks;
};
/// FunctionArgList - Type for representing both the decl and type
/// of parameters to a function. The decl must be either a
/// ParmVarDecl or ImplicitParamDecl.
- class FunctionArgList : public llvm::SmallVector<const VarDecl*, 16> {
+ class FunctionArgList : public SmallVector<const VarDecl*, 16> {
};
/// CGFunctionInfo - Class to encapsulate the information about a
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 7dbaaf85299f..c28ecc05ded6 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -62,7 +62,7 @@ CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl,
if (Offset.isZero())
return 0;
- const llvm::Type *PtrDiffTy =
+ llvm::Type *PtrDiffTy =
Types.ConvertType(getContext().getPointerDiffType());
return llvm::ConstantInt::get(PtrDiffTy, Offset.getQuantity());
@@ -95,7 +95,7 @@ CodeGenFunction::GetAddressOfDirectBaseInCompleteClass(llvm::Value *This,
// TODO: for complete types, this should be possible with a GEP.
llvm::Value *V = This;
if (Offset.isPositive()) {
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
+ llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
V = Builder.CreateBitCast(V, Int8PtrTy);
V = Builder.CreateConstInBoundsGEP1_64(V, Offset.getQuantity());
}
@@ -107,7 +107,7 @@ CodeGenFunction::GetAddressOfDirectBaseInCompleteClass(llvm::Value *This,
static llvm::Value *
ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ThisPtr,
CharUnits NonVirtual, llvm::Value *Virtual) {
- const llvm::Type *PtrDiffTy =
+ llvm::Type *PtrDiffTy =
CGF.ConvertType(CGF.getContext().getPointerDiffType());
llvm::Value *NonVirtualOffset = 0;
@@ -125,7 +125,7 @@ ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ThisPtr,
BaseOffset = NonVirtualOffset;
// Apply the base offset.
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
ThisPtr = CGF.Builder.CreateBitCast(ThisPtr, Int8PtrTy);
ThisPtr = CGF.Builder.CreateGEP(ThisPtr, BaseOffset, "add.ptr");
@@ -155,7 +155,7 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
Start, PathEnd);
// Get the base pointer type.
- const llvm::Type *BasePtrTy =
+ llvm::Type *BasePtrTy =
ConvertType((PathEnd[-1])->getType())->getPointerTo();
if (NonVirtualOffset.isZero() && !VBase) {
@@ -225,7 +225,7 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
QualType DerivedTy =
getContext().getCanonicalType(getContext().getTagDeclType(Derived));
- const llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo();
+ llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo();
llvm::Value *NonVirtualOffset =
CGM.GetNonVirtualBaseClassOffset(Derived, PathBegin, PathEnd);
@@ -398,8 +398,11 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
BaseClassDecl,
isBaseVirtual);
- AggValueSlot AggSlot = AggValueSlot::forAddr(V, Qualifiers(),
- /*Lifetime*/ true);
+ AggValueSlot AggSlot =
+ AggValueSlot::forAddr(V, Qualifiers(),
+ AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased);
CGF.EmitAggExpr(BaseInit->getInit(), AggSlot);
@@ -436,8 +439,11 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
CGF.EmitComplexExprIntoAddr(MemberInit->getInit(), Dest,
LHS.isVolatileQualified());
} else {
- AggValueSlot Slot = AggValueSlot::forAddr(Dest, LHS.getQuals(),
- /*Lifetime*/ true);
+ AggValueSlot Slot =
+ AggValueSlot::forAddr(Dest, LHS.getQuals(),
+ AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased);
CGF.EmitAggExpr(MemberInit->getInit(), Slot);
}
@@ -521,6 +527,12 @@ namespace {
}
};
}
+
+static bool hasTrivialCopyOrMoveConstructor(const CXXRecordDecl *Record,
+ bool Moving) {
+ return Moving ? Record->hasTrivialMoveConstructor() :
+ Record->hasTrivialCopyConstructor();
+}
static void EmitMemberInitializer(CodeGenFunction &CGF,
const CXXRecordDecl *ClassDecl,
@@ -547,11 +559,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
LHS = CGF.EmitLValueForFieldInitialization(ThisPtr, Field, 0);
}
- // FIXME: If there's no initializer and the CXXCtorInitializer
- // was implicitly generated, we shouldn't be zeroing memory.
- if (FieldType->isArrayType() && !MemberInit->getInit()) {
- CGF.EmitNullInitialization(LHS.getAddress(), Field->getType());
- } else if (!CGF.hasAggregateLLVMType(Field->getType())) {
+ if (!CGF.hasAggregateLLVMType(Field->getType())) {
if (LHS.isSimple()) {
CGF.EmitExprAsInit(MemberInit->getInit(), Field, LHS, false);
} else {
@@ -565,15 +573,15 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
llvm::Value *ArrayIndexVar = 0;
const ConstantArrayType *Array
= CGF.getContext().getAsConstantArrayType(FieldType);
- if (Array && Constructor->isImplicit() &&
- Constructor->isCopyConstructor()) {
- const llvm::Type *SizeTy
+ if (Array && Constructor->isImplicitlyDefined() &&
+ Constructor->isCopyOrMoveConstructor()) {
+ llvm::Type *SizeTy
= CGF.ConvertType(CGF.getContext().getSizeType());
// The LHS is a pointer to the first object we'll be constructing, as
// a flat array.
QualType BaseElementTy = CGF.getContext().getBaseElementType(Array);
- const llvm::Type *BasePtr = CGF.ConvertType(BaseElementTy);
+ llvm::Type *BasePtr = CGF.ConvertType(BaseElementTy);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
llvm::Value *BaseAddrPtr = CGF.Builder.CreateBitCast(LHS.getAddress(),
BasePtr);
@@ -589,7 +597,8 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
// constructors, perform a single aggregate copy.
const CXXRecordDecl *Record = BaseElementTy->getAsCXXRecordDecl();
if (BaseElementTy.isPODType(CGF.getContext()) ||
- (Record && Record->hasTrivialCopyConstructor())) {
+ (Record && hasTrivialCopyOrMoveConstructor(Record,
+ Constructor->isMoveConstructor()))) {
// Find the source pointer. We knows it's the last argument because
// we know we're in a copy constructor.
unsigned SrcArgIndex = Args.size() - 1;
@@ -684,7 +693,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
// delegation optimization.
if (CtorType == Ctor_Complete && IsConstructorDelegationValid(Ctor)) {
if (CGDebugInfo *DI = getDebugInfo())
- DI->EmitStopPoint(Builder);
+ DI->EmitLocation(Builder, Ctor->getLocEnd());
EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args);
return;
}
@@ -729,7 +738,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
const CXXRecordDecl *ClassDecl = CD->getParent();
- llvm::SmallVector<CXXCtorInitializer *, 8> MemberInitializers;
+ SmallVector<CXXCtorInitializer *, 8> MemberInitializers;
for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(),
E = CD->init_end();
@@ -971,6 +980,10 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
const CXXRecordDecl *ClassDecl = DD->getParent();
+ // Unions have no bases and do not call field destructors.
+ if (ClassDecl->isUnion())
+ return;
+
// The complete-destructor phase just destructs all the virtual bases.
if (DtorType == Dtor_Complete) {
@@ -1018,7 +1031,7 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
}
// Destroy direct fields.
- llvm::SmallVector<const FieldDecl *, 16> FieldDecls;
+ SmallVector<const FieldDecl *, 16> FieldDecls;
for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
E = ClassDecl->field_end(); I != E; ++I) {
const FieldDecl *field = *I;
@@ -1195,7 +1208,8 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
}
assert(ArgBeg + 1 == ArgEnd && "unexpected argcount for trivial ctor");
- assert(D->isCopyConstructor() && "trivial 1-arg ctor not a copy ctor");
+ assert(D->isCopyOrMoveConstructor() &&
+ "trivial 1-arg ctor not a copy/move ctor");
const Expr *E = (*ArgBeg);
QualType Ty = E->getType();
@@ -1217,7 +1231,8 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
CallExpr::const_arg_iterator ArgEnd) {
if (D->isTrivial()) {
assert(ArgBeg + 1 == ArgEnd && "unexpected argcount for trivial ctor");
- assert(D->isCopyConstructor() && "trivial 1-arg ctor not a copy ctor");
+ assert(D->isCopyOrMoveConstructor() &&
+ "trivial 1-arg ctor not a copy/move ctor");
EmitAggregateCopy(This, Src, (*ArgBeg)->getType());
return;
}
@@ -1236,7 +1251,7 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
// Push the src ptr.
QualType QT = *(FPT->arg_type_begin());
- const llvm::Type *t = CGM.getTypes().ConvertType(QT);
+ llvm::Type *t = CGM.getTypes().ConvertType(QT);
Src = Builder.CreateBitCast(Src, t);
Args.add(RValue::get(Src), QT);
@@ -1258,10 +1273,8 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
EmitCallArg(Args, *Arg, ArgType);
}
- QualType ResultType = FPT->getResultType();
- EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args,
- FPT->getExtInfo()),
- Callee, ReturnValueSlot(), Args, D);
+ EmitCall(CGM.getTypes().getFunctionInfo(Args, FPT), Callee,
+ ReturnValueSlot(), Args, D);
}
void
@@ -1326,7 +1339,10 @@ CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor
llvm::Value *ThisPtr = LoadCXXThis();
AggValueSlot AggSlot =
- AggValueSlot::forAddr(ThisPtr, Qualifiers(), /*Lifetime*/ true);
+ AggValueSlot::forAddr(ThisPtr, Qualifiers(),
+ AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased);
EmitAggExpr(Ctor->init_begin()[0]->getInit(), AggSlot);
@@ -1394,12 +1410,12 @@ CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This,
const CXXRecordDecl *BaseClassDecl) {
llvm::Value *VTablePtr = GetVTablePtr(This, Int8PtrTy);
CharUnits VBaseOffsetOffset =
- CGM.getVTables().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl);
+ CGM.getVTableContext().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl);
llvm::Value *VBaseOffsetPtr =
Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetOffset.getQuantity(),
"vbase.offset.ptr");
- const llvm::Type *PtrDiffTy =
+ llvm::Type *PtrDiffTy =
ConvertType(getContext().getPointerDiffType());
VBaseOffsetPtr = Builder.CreateBitCast(VBaseOffsetPtr,
@@ -1436,7 +1452,8 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
// And load the address point from the VTT.
VTableAddressPoint = Builder.CreateLoad(VTT);
} else {
- uint64_t AddressPoint = CGM.getVTables().getAddressPoint(Base, VTableClass);
+ uint64_t AddressPoint =
+ CGM.getVTableContext().getVTableLayout(VTableClass).getAddressPoint(Base);
VTableAddressPoint =
Builder.CreateConstInBoundsGEP2_64(VTable, 0, AddressPoint);
}
@@ -1465,7 +1482,7 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
VirtualOffset);
// Finally, store the address point.
- const llvm::Type *AddressPointPtrTy =
+ llvm::Type *AddressPointPtrTy =
VTableAddressPoint->getType()->getPointerTo();
VTableField = Builder.CreateBitCast(VTableField, AddressPointPtrTy);
Builder.CreateStore(VTableAddressPoint, VTableField);
@@ -1549,7 +1566,7 @@ void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) {
}
llvm::Value *CodeGenFunction::GetVTablePtr(llvm::Value *This,
- const llvm::Type *Ty) {
+ llvm::Type *Ty) {
llvm::Value *VTablePtrSrc = Builder.CreateBitCast(This, Ty->getPointerTo());
return Builder.CreateLoad(VTablePtrSrc, "vtable");
}
@@ -1605,7 +1622,6 @@ static const Expr *skipNoOpCastsAndParens(const Expr *E) {
/// canDevirtualizeMemberFunctionCall - Checks whether the given virtual member
/// function call on the given expr can be devirtualized.
-/// expr can be devirtualized.
static bool canDevirtualizeMemberFunctionCall(const Expr *Base,
const CXXMethodDecl *MD) {
// If the most derived class is marked final, we know that no subclass can
@@ -1677,7 +1693,7 @@ CodeGenFunction::EmitCXXOperatorMemberCallee(const CXXOperatorCallExpr *E,
const CXXMethodDecl *MD,
llvm::Value *This) {
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
- const llvm::Type *Ty =
+ llvm::Type *Ty =
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
FPT->isVariadic());
diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp
index 9c5dd1f23721..b2d0786cb6cd 100644
--- a/lib/CodeGen/CGCleanup.cpp
+++ b/lib/CodeGen/CGCleanup.cpp
@@ -48,7 +48,7 @@ DominatingValue<RValue>::saved_type::save(CodeGenFunction &CGF, RValue rv) {
if (rv.isComplex()) {
CodeGenFunction::ComplexPairTy V = rv.getComplexVal();
- const llvm::Type *ComplexTy =
+ llvm::Type *ComplexTy =
llvm::StructType::get(V.first->getType(), V.second->getType(),
(void*) 0);
llvm::Value *addr = CGF.CreateTempAlloca(ComplexTy, "saved-complex");
@@ -119,16 +119,30 @@ char *EHScopeStack::allocate(size_t Size) {
}
EHScopeStack::stable_iterator
-EHScopeStack::getEnclosingEHCleanup(iterator it) const {
- assert(it != end());
- do {
- if (isa<EHCleanupScope>(*it)) {
- if (cast<EHCleanupScope>(*it).isEHCleanup())
- return stabilize(it);
- return cast<EHCleanupScope>(*it).getEnclosingEHCleanup();
+EHScopeStack::getInnermostActiveNormalCleanup() const {
+ for (stable_iterator si = getInnermostNormalCleanup(), se = stable_end();
+ si != se; ) {
+ EHCleanupScope &cleanup = cast<EHCleanupScope>(*find(si));
+ if (cleanup.isActive()) return si;
+ si = cleanup.getEnclosingNormalCleanup();
+ }
+ return stable_end();
+}
+
+EHScopeStack::stable_iterator EHScopeStack::getInnermostActiveEHScope() const {
+ for (stable_iterator si = getInnermostEHScope(), se = stable_end();
+ si != se; ) {
+ // Skip over inactive cleanups.
+ EHCleanupScope *cleanup = dyn_cast<EHCleanupScope>(&*find(si));
+ if (cleanup && !cleanup->isActive()) {
+ si = cleanup->getEnclosingEHScope();
+ continue;
}
- ++it;
- } while (it != end());
+
+ // All other scopes are always active.
+ return si;
+ }
+
return stable_end();
}
@@ -146,11 +160,11 @@ void *EHScopeStack::pushCleanup(CleanupKind Kind, size_t Size) {
Size,
BranchFixups.size(),
InnermostNormalCleanup,
- InnermostEHCleanup);
+ InnermostEHScope);
if (IsNormalCleanup)
InnermostNormalCleanup = stable_begin();
if (IsEHCleanup)
- InnermostEHCleanup = stable_begin();
+ InnermostEHScope = stable_begin();
return Scope->getCleanupBuffer();
}
@@ -161,11 +175,9 @@ void EHScopeStack::popCleanup() {
assert(isa<EHCleanupScope>(*begin()));
EHCleanupScope &Cleanup = cast<EHCleanupScope>(*begin());
InnermostNormalCleanup = Cleanup.getEnclosingNormalCleanup();
- InnermostEHCleanup = Cleanup.getEnclosingEHCleanup();
+ InnermostEHScope = Cleanup.getEnclosingEHScope();
StartOfData += Cleanup.getAllocatedSize();
- if (empty()) NextEHDestIndex = FirstEHDestIndex;
-
// Destroy the cleanup.
Cleanup.~EHCleanupScope();
@@ -182,37 +194,35 @@ void EHScopeStack::popCleanup() {
}
}
-EHFilterScope *EHScopeStack::pushFilter(unsigned NumFilters) {
- char *Buffer = allocate(EHFilterScope::getSizeForNumFilters(NumFilters));
- CatchDepth++;
- return new (Buffer) EHFilterScope(NumFilters);
+EHFilterScope *EHScopeStack::pushFilter(unsigned numFilters) {
+ assert(getInnermostEHScope() == stable_end());
+ char *buffer = allocate(EHFilterScope::getSizeForNumFilters(numFilters));
+ EHFilterScope *filter = new (buffer) EHFilterScope(numFilters);
+ InnermostEHScope = stable_begin();
+ return filter;
}
void EHScopeStack::popFilter() {
assert(!empty() && "popping exception stack when not empty");
- EHFilterScope &Filter = cast<EHFilterScope>(*begin());
- StartOfData += EHFilterScope::getSizeForNumFilters(Filter.getNumFilters());
+ EHFilterScope &filter = cast<EHFilterScope>(*begin());
+ StartOfData += EHFilterScope::getSizeForNumFilters(filter.getNumFilters());
- if (empty()) NextEHDestIndex = FirstEHDestIndex;
-
- assert(CatchDepth > 0 && "mismatched filter push/pop");
- CatchDepth--;
+ InnermostEHScope = filter.getEnclosingEHScope();
}
-EHCatchScope *EHScopeStack::pushCatch(unsigned NumHandlers) {
- char *Buffer = allocate(EHCatchScope::getSizeForNumHandlers(NumHandlers));
- CatchDepth++;
- EHCatchScope *Scope = new (Buffer) EHCatchScope(NumHandlers);
- for (unsigned I = 0; I != NumHandlers; ++I)
- Scope->getHandlers()[I].Index = getNextEHDestIndex();
- return Scope;
+EHCatchScope *EHScopeStack::pushCatch(unsigned numHandlers) {
+ char *buffer = allocate(EHCatchScope::getSizeForNumHandlers(numHandlers));
+ EHCatchScope *scope =
+ new (buffer) EHCatchScope(numHandlers, InnermostEHScope);
+ InnermostEHScope = stable_begin();
+ return scope;
}
void EHScopeStack::pushTerminate() {
char *Buffer = allocate(EHTerminateScope::getSize());
- CatchDepth++;
- new (Buffer) EHTerminateScope(getNextEHDestIndex());
+ new (Buffer) EHTerminateScope(InnermostEHScope);
+ InnermostEHScope = stable_begin();
}
/// Remove any 'null' fixups on the stack. However, we can't pop more
@@ -384,17 +394,6 @@ static llvm::BasicBlock *CreateNormalEntry(CodeGenFunction &CGF,
return Entry;
}
-static llvm::BasicBlock *CreateEHEntry(CodeGenFunction &CGF,
- EHCleanupScope &Scope) {
- assert(Scope.isEHCleanup());
- llvm::BasicBlock *Entry = Scope.getEHBlock();
- if (!Entry) {
- Entry = CGF.createBasicBlock("eh.cleanup");
- Scope.setEHBlock(Entry);
- }
- return Entry;
-}
-
/// Attempts to reduce a cleanup's entry block to a fallthrough. This
/// is basically llvm::MergeBlockIntoPredecessor, except
/// simplified/optimized for the tighter constraints on cleanup blocks.
@@ -483,6 +482,49 @@ static void ForwardPrebranchedFallthrough(llvm::BasicBlock *Exit,
}
}
+/// We don't need a normal entry block for the given cleanup.
+/// Optimistic fixup branches can cause these blocks to come into
+/// existence anyway; if so, destroy it.
+///
+/// The validity of this transformation is very much specific to the
+/// exact ways in which we form branches to cleanup entries.
+static void destroyOptimisticNormalEntry(CodeGenFunction &CGF,
+ EHCleanupScope &scope) {
+ llvm::BasicBlock *entry = scope.getNormalBlock();
+ if (!entry) return;
+
+ // Replace all the uses with unreachable.
+ llvm::BasicBlock *unreachableBB = CGF.getUnreachableBlock();
+ for (llvm::BasicBlock::use_iterator
+ i = entry->use_begin(), e = entry->use_end(); i != e; ) {
+ llvm::Use &use = i.getUse();
+ ++i;
+
+ use.set(unreachableBB);
+
+ // The only uses should be fixup switches.
+ llvm::SwitchInst *si = cast<llvm::SwitchInst>(use.getUser());
+ if (si->getNumCases() == 2 && si->getDefaultDest() == unreachableBB) {
+ // Replace the switch with a branch.
+ llvm::BranchInst::Create(si->getSuccessor(1), si);
+
+ // The switch operand is a load from the cleanup-dest alloca.
+ llvm::LoadInst *condition = cast<llvm::LoadInst>(si->getCondition());
+
+ // Destroy the switch.
+ si->eraseFromParent();
+
+ // Destroy the load.
+ assert(condition->getOperand(0) == CGF.NormalCleanupDest);
+ assert(condition->use_empty());
+ condition->eraseFromParent();
+ }
+ }
+
+ assert(entry->use_empty());
+ delete entry;
+}
+
/// Pops a cleanup block. If the block includes a normal cleanup, the
/// current insertion point is threaded through the cleanup, as are
/// any branch fixups on the cleanup.
@@ -501,7 +543,10 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
// Check whether we need an EH cleanup. This is only true if we've
// generated a lazy EH cleanup block.
- bool RequiresEHCleanup = Scope.hasEHBranches();
+ llvm::BasicBlock *EHEntry = Scope.getCachedEHDispatchBlock();
+ assert(Scope.hasEHBranches() == (EHEntry != 0));
+ bool RequiresEHCleanup = (EHEntry != 0);
+ EHScopeStack::stable_iterator EHParent = Scope.getEnclosingEHScope();
// Check the three conditions which might require a normal cleanup:
@@ -537,43 +582,37 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
RequiresNormalCleanup = true;
}
- EHScopeStack::Cleanup::Flags cleanupFlags;
- if (Scope.isNormalCleanup())
- cleanupFlags.setIsNormalCleanupKind();
- if (Scope.isEHCleanup())
- cleanupFlags.setIsEHCleanupKind();
-
- // Even if we don't need the normal cleanup, we might still have
- // prebranched fallthrough to worry about.
- if (Scope.isNormalCleanup() && !RequiresNormalCleanup &&
- HasPrebranchedFallthrough) {
- assert(!IsActive);
-
- llvm::BasicBlock *NormalEntry = Scope.getNormalBlock();
-
- // If we're branching through this cleanup, just forward the
- // prebranched fallthrough to the next cleanup, leaving the insert
- // point in the old block.
+ // If we have a prebranched fallthrough into an inactive normal
+ // cleanup, rewrite it so that it leads to the appropriate place.
+ if (Scope.isNormalCleanup() && HasPrebranchedFallthrough && !IsActive) {
+ llvm::BasicBlock *prebranchDest;
+
+ // If the prebranch is semantically branching through the next
+ // cleanup, just forward it to the next block, leaving the
+ // insertion point in the prebranched block.
if (FallthroughIsBranchThrough) {
- EHScope &S = *EHStack.find(Scope.getEnclosingNormalCleanup());
- llvm::BasicBlock *EnclosingEntry =
- CreateNormalEntry(*this, cast<EHCleanupScope>(S));
-
- ForwardPrebranchedFallthrough(FallthroughSource,
- NormalEntry, EnclosingEntry);
- assert(NormalEntry->use_empty() &&
- "uses of entry remain after forwarding?");
- delete NormalEntry;
+ EHScope &enclosing = *EHStack.find(Scope.getEnclosingNormalCleanup());
+ prebranchDest = CreateNormalEntry(*this, cast<EHCleanupScope>(enclosing));
- // Otherwise, we're branching out; just emit the next block.
+ // Otherwise, we need to make a new block. If the normal cleanup
+ // isn't being used at all, we could actually reuse the normal
+ // entry block, but this is simpler, and it avoids conflicts with
+ // dead optimistic fixup branches.
} else {
- EmitBlock(NormalEntry);
- SimplifyCleanupEntry(*this, NormalEntry);
+ prebranchDest = createBasicBlock("forwarded-prebranch");
+ EmitBlock(prebranchDest);
}
+
+ llvm::BasicBlock *normalEntry = Scope.getNormalBlock();
+ assert(normalEntry && !normalEntry->use_empty());
+
+ ForwardPrebranchedFallthrough(FallthroughSource,
+ normalEntry, prebranchDest);
}
// If we don't need the cleanup at all, we're done.
if (!RequiresNormalCleanup && !RequiresEHCleanup) {
+ destroyOptimisticNormalEntry(*this, Scope);
EHStack.popCleanup(); // safe because there are no fixups
assert(EHStack.getNumBranchFixups() == 0 ||
EHStack.hasNormalCleanups());
@@ -583,7 +622,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
// Copy the cleanup emission data out. Note that SmallVector
// guarantees maximal alignment for its buffer regardless of its
// type parameter.
- llvm::SmallVector<char, 8*sizeof(void*)> CleanupBuffer;
+ SmallVector<char, 8*sizeof(void*)> CleanupBuffer;
CleanupBuffer.reserve(Scope.getCleanupSize());
memcpy(CleanupBuffer.data(),
Scope.getCleanupBuffer(), Scope.getCleanupSize());
@@ -591,63 +630,14 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
EHScopeStack::Cleanup *Fn =
reinterpret_cast<EHScopeStack::Cleanup*>(CleanupBuffer.data());
- // We want to emit the EH cleanup after the normal cleanup, but go
- // ahead and do the setup for the EH cleanup while the scope is still
- // alive.
- llvm::BasicBlock *EHEntry = 0;
- llvm::SmallVector<llvm::Instruction*, 2> EHInstsToAppend;
- if (RequiresEHCleanup) {
- EHEntry = CreateEHEntry(*this, Scope);
-
- // Figure out the branch-through dest if necessary.
- llvm::BasicBlock *EHBranchThroughDest = 0;
- if (Scope.hasEHBranchThroughs()) {
- assert(Scope.getEnclosingEHCleanup() != EHStack.stable_end());
- EHScope &S = *EHStack.find(Scope.getEnclosingEHCleanup());
- EHBranchThroughDest = CreateEHEntry(*this, cast<EHCleanupScope>(S));
- }
-
- // If we have exactly one branch-after and no branch-throughs, we
- // can dispatch it without a switch.
- if (!Scope.hasEHBranchThroughs() &&
- Scope.getNumEHBranchAfters() == 1) {
- assert(!EHBranchThroughDest);
-
- // TODO: remove the spurious eh.cleanup.dest stores if this edge
- // never went through any switches.
- llvm::BasicBlock *BranchAfterDest = Scope.getEHBranchAfterBlock(0);
- EHInstsToAppend.push_back(llvm::BranchInst::Create(BranchAfterDest));
-
- // Otherwise, if we have any branch-afters, we need a switch.
- } else if (Scope.getNumEHBranchAfters()) {
- // The default of the switch belongs to the branch-throughs if
- // they exist.
- llvm::BasicBlock *Default =
- (EHBranchThroughDest ? EHBranchThroughDest : getUnreachableBlock());
-
- const unsigned SwitchCapacity = Scope.getNumEHBranchAfters();
-
- llvm::LoadInst *Load =
- new llvm::LoadInst(getEHCleanupDestSlot(), "cleanup.dest");
- llvm::SwitchInst *Switch =
- llvm::SwitchInst::Create(Load, Default, SwitchCapacity);
-
- EHInstsToAppend.push_back(Load);
- EHInstsToAppend.push_back(Switch);
-
- for (unsigned I = 0, E = Scope.getNumEHBranchAfters(); I != E; ++I)
- Switch->addCase(Scope.getEHBranchAfterIndex(I),
- Scope.getEHBranchAfterBlock(I));
-
- // Otherwise, we have only branch-throughs; jump to the next EH
- // cleanup.
- } else {
- assert(EHBranchThroughDest);
- EHInstsToAppend.push_back(llvm::BranchInst::Create(EHBranchThroughDest));
- }
- }
+ EHScopeStack::Cleanup::Flags cleanupFlags;
+ if (Scope.isNormalCleanup())
+ cleanupFlags.setIsNormalCleanupKind();
+ if (Scope.isEHCleanup())
+ cleanupFlags.setIsEHCleanupKind();
if (!RequiresNormalCleanup) {
+ destroyOptimisticNormalEntry(*this, Scope);
EHStack.popCleanup();
} else {
// If we have a fallthrough and no other need for the cleanup,
@@ -655,15 +645,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
if (HasFallthrough && !HasPrebranchedFallthrough &&
!HasFixups && !HasExistingBranches) {
- // Fixups can cause us to optimistically create a normal block,
- // only to later have no real uses for it. Just delete it in
- // this case.
- // TODO: we can potentially simplify all the uses after this.
- if (Scope.getNormalBlock()) {
- Scope.getNormalBlock()->replaceAllUsesWith(getUnreachableBlock());
- delete Scope.getNormalBlock();
- }
-
+ destroyOptimisticNormalEntry(*this, Scope);
EHStack.popCleanup();
EmitCleanup(*this, Fn, cleanupFlags, NormalActiveFlag);
@@ -676,18 +658,19 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
// I. Set up the fallthrough edge in.
+ CGBuilderTy::InsertPoint savedInactiveFallthroughIP;
+
// If there's a fallthrough, we need to store the cleanup
// destination index. For fall-throughs this is always zero.
if (HasFallthrough) {
if (!HasPrebranchedFallthrough)
Builder.CreateStore(Builder.getInt32(0), getNormalCleanupDestSlot());
- // Otherwise, clear the IP if we don't have fallthrough because
- // the cleanup is inactive. We don't need to save it because
- // it's still just FallthroughSource.
+ // Otherwise, save and clear the IP if we don't have fallthrough
+ // because the cleanup is inactive.
} else if (FallthroughSource) {
assert(!IsActive && "source without fallthrough for active cleanup");
- Builder.ClearInsertionPoint();
+ savedInactiveFallthroughIP = Builder.saveAndClearIP();
}
// II. Emit the entry block. This implicitly branches to it if
@@ -716,7 +699,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
}
llvm::BasicBlock *FallthroughDest = 0;
- llvm::SmallVector<llvm::Instruction*, 2> InstsToAppend;
+ SmallVector<llvm::Instruction*, 2> InstsToAppend;
// If there's exactly one branch-after and no other threads,
// we can route it without a switch.
@@ -800,25 +783,14 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
// V. Set up the fallthrough edge out.
- // Case 1: a fallthrough source exists but shouldn't branch to
- // the cleanup because the cleanup is inactive.
+ // Case 1: a fallthrough source exists but doesn't branch to the
+ // cleanup because the cleanup is inactive.
if (!HasFallthrough && FallthroughSource) {
+ // Prebranched fallthrough was forwarded earlier.
+ // Non-prebranched fallthrough doesn't need to be forwarded.
+ // Either way, all we need to do is restore the IP we cleared before.
assert(!IsActive);
-
- // If we have a prebranched fallthrough, that needs to be
- // forwarded to the right block.
- if (HasPrebranchedFallthrough) {
- llvm::BasicBlock *Next;
- if (FallthroughIsBranchThrough) {
- Next = BranchThroughDest;
- assert(!FallthroughDest);
- } else {
- Next = FallthroughDest;
- }
-
- ForwardPrebranchedFallthrough(FallthroughSource, NormalEntry, Next);
- }
- Builder.SetInsertPoint(FallthroughSource);
+ Builder.restoreIP(savedInactiveFallthroughIP);
// Case 2: a fallthrough source exists and should branch to the
// cleanup, but we're not supposed to branch through to the next
@@ -864,10 +836,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
cleanupFlags.setIsForEHCleanup();
EmitCleanup(*this, Fn, cleanupFlags, EHActiveFlag);
- // Append the prepared cleanup prologue from above.
- llvm::BasicBlock *EHExit = Builder.GetInsertBlock();
- for (unsigned I = 0, E = EHInstsToAppend.size(); I != E; ++I)
- EHExit->getInstList().push_back(EHInstsToAppend[I]);
+ Builder.CreateBr(getEHDispatchBlock(EHParent));
Builder.restoreIP(SavedIP);
@@ -979,64 +948,6 @@ void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) {
Builder.ClearInsertionPoint();
}
-void CodeGenFunction::EmitBranchThroughEHCleanup(UnwindDest Dest) {
- // We should never get invalid scope depths for an UnwindDest; that
- // implies that the destination wasn't set up correctly.
- assert(Dest.getScopeDepth().isValid() && "invalid scope depth on EH dest?");
-
- if (!HaveInsertPoint())
- return;
-
- // Create the branch.
- llvm::BranchInst *BI = Builder.CreateBr(Dest.getBlock());
-
- // Calculate the innermost active cleanup.
- EHScopeStack::stable_iterator
- InnermostCleanup = EHStack.getInnermostActiveEHCleanup();
-
- // If the destination is in the same EH cleanup scope as us, we
- // don't need to thread through anything.
- if (InnermostCleanup.encloses(Dest.getScopeDepth())) {
- Builder.ClearInsertionPoint();
- return;
- }
- assert(InnermostCleanup != EHStack.stable_end());
-
- // Store the index at the start.
- llvm::ConstantInt *Index = Builder.getInt32(Dest.getDestIndex());
- new llvm::StoreInst(Index, getEHCleanupDestSlot(), BI);
-
- // Adjust BI to point to the first cleanup block.
- {
- EHCleanupScope &Scope =
- cast<EHCleanupScope>(*EHStack.find(InnermostCleanup));
- BI->setSuccessor(0, CreateEHEntry(*this, Scope));
- }
-
- // Add this destination to all the scopes involved.
- for (EHScopeStack::stable_iterator
- I = InnermostCleanup, E = Dest.getScopeDepth(); ; ) {
- assert(E.strictlyEncloses(I));
- EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.find(I));
- assert(Scope.isEHCleanup());
- I = Scope.getEnclosingEHCleanup();
-
- // If this is the last cleanup we're propagating through, add this
- // as a branch-after.
- if (I == E) {
- Scope.addEHBranchAfter(Index, Dest.getBlock());
- break;
- }
-
- // Otherwise, add it as a branch-through. If this isn't new
- // information, all the rest of the work has been done before.
- if (!Scope.addEHBranchThrough(Dest.getBlock()))
- break;
- }
-
- Builder.ClearInsertionPoint();
-}
-
static bool IsUsedAsNormalCleanup(EHScopeStack &EHStack,
EHScopeStack::stable_iterator C) {
// If we needed a normal block for any reason, that counts.
@@ -1057,18 +968,21 @@ static bool IsUsedAsNormalCleanup(EHScopeStack &EHStack,
}
static bool IsUsedAsEHCleanup(EHScopeStack &EHStack,
- EHScopeStack::stable_iterator C) {
+ EHScopeStack::stable_iterator cleanup) {
// If we needed an EH block for any reason, that counts.
- if (cast<EHCleanupScope>(*EHStack.find(C)).getEHBlock())
+ if (EHStack.find(cleanup)->hasEHBranches())
return true;
// Check whether any enclosed cleanups were needed.
for (EHScopeStack::stable_iterator
- I = EHStack.getInnermostEHCleanup(); I != C; ) {
- assert(C.strictlyEncloses(I));
- EHCleanupScope &S = cast<EHCleanupScope>(*EHStack.find(I));
- if (S.getEHBlock()) return true;
- I = S.getEnclosingEHCleanup();
+ i = EHStack.getInnermostEHScope(); i != cleanup; ) {
+ assert(cleanup.strictlyEncloses(i));
+
+ EHScope &scope = *EHStack.find(i);
+ if (scope.hasEHBranches())
+ return true;
+
+ i = scope.getEnclosingEHScope();
}
return false;
@@ -1163,10 +1077,3 @@ llvm::Value *CodeGenFunction::getNormalCleanupDestSlot() {
CreateTempAlloca(Builder.getInt32Ty(), "cleanup.dest.slot");
return NormalCleanupDest;
}
-
-llvm::Value *CodeGenFunction::getEHCleanupDestSlot() {
- if (!EHCleanupDest)
- EHCleanupDest =
- CreateTempAlloca(Builder.getInt32Ty(), "eh.cleanup.dest.slot");
- return EHCleanupDest;
-}
diff --git a/lib/CodeGen/CGCleanup.h b/lib/CodeGen/CGCleanup.h
index c93ec5bb76a9..7726e442c025 100644
--- a/lib/CodeGen/CGCleanup.h
+++ b/lib/CodeGen/CGCleanup.h
@@ -29,25 +29,102 @@ namespace CodeGen {
/// A protected scope for zero-cost EH handling.
class EHScope {
llvm::BasicBlock *CachedLandingPad;
+ llvm::BasicBlock *CachedEHDispatchBlock;
- unsigned K : 2;
+ EHScopeStack::stable_iterator EnclosingEHScope;
+
+ class CommonBitFields {
+ friend class EHScope;
+ unsigned Kind : 2;
+ };
+ enum { NumCommonBits = 2 };
protected:
- enum { BitsRemaining = 30 };
+ class CatchBitFields {
+ friend class EHCatchScope;
+ unsigned : NumCommonBits;
+
+ unsigned NumHandlers : 32 - NumCommonBits;
+ };
+
+ class CleanupBitFields {
+ friend class EHCleanupScope;
+ unsigned : NumCommonBits;
+
+ /// Whether this cleanup needs to be run along normal edges.
+ unsigned IsNormalCleanup : 1;
+
+ /// Whether this cleanup needs to be run along exception edges.
+ unsigned IsEHCleanup : 1;
+
+ /// Whether this cleanup is currently active.
+ unsigned IsActive : 1;
+
+ /// Whether the normal cleanup should test the activation flag.
+ unsigned TestFlagInNormalCleanup : 1;
+
+ /// Whether the EH cleanup should test the activation flag.
+ unsigned TestFlagInEHCleanup : 1;
+
+ /// The amount of extra storage needed by the Cleanup.
+ /// Always a multiple of the scope-stack alignment.
+ unsigned CleanupSize : 12;
+
+ /// The number of fixups required by enclosing scopes (not including
+ /// this one). If this is the top cleanup scope, all the fixups
+ /// from this index onwards belong to this scope.
+ unsigned FixupDepth : 32 - 17 - NumCommonBits; // currently 13
+ };
+
+ class FilterBitFields {
+ friend class EHFilterScope;
+ unsigned : NumCommonBits;
+
+ unsigned NumFilters : 32 - NumCommonBits;
+ };
+
+ union {
+ CommonBitFields CommonBits;
+ CatchBitFields CatchBits;
+ CleanupBitFields CleanupBits;
+ FilterBitFields FilterBits;
+ };
public:
enum Kind { Cleanup, Catch, Terminate, Filter };
- EHScope(Kind K) : CachedLandingPad(0), K(K) {}
+ EHScope(Kind kind, EHScopeStack::stable_iterator enclosingEHScope)
+ : CachedLandingPad(0), CachedEHDispatchBlock(0),
+ EnclosingEHScope(enclosingEHScope) {
+ CommonBits.Kind = kind;
+ }
- Kind getKind() const { return static_cast<Kind>(K); }
+ Kind getKind() const { return static_cast<Kind>(CommonBits.Kind); }
llvm::BasicBlock *getCachedLandingPad() const {
return CachedLandingPad;
}
- void setCachedLandingPad(llvm::BasicBlock *Block) {
- CachedLandingPad = Block;
+ void setCachedLandingPad(llvm::BasicBlock *block) {
+ CachedLandingPad = block;
+ }
+
+ llvm::BasicBlock *getCachedEHDispatchBlock() const {
+ return CachedEHDispatchBlock;
+ }
+
+ void setCachedEHDispatchBlock(llvm::BasicBlock *block) {
+ CachedEHDispatchBlock = block;
+ }
+
+ bool hasEHBranches() const {
+ if (llvm::BasicBlock *block = getCachedEHDispatchBlock())
+ return !block->use_empty();
+ return false;
+ }
+
+ EHScopeStack::stable_iterator getEnclosingEHScope() const {
+ return EnclosingEHScope;
}
};
@@ -57,8 +134,6 @@ public:
/// Objective C @finally blocks are represented using a cleanup scope
/// after the catch scope.
class EHCatchScope : public EHScope {
- unsigned NumHandlers : BitsRemaining;
-
// In effect, we have a flexible array member
// Handler Handlers[0];
// But that's only standard in C99, not C++, so we have to do
@@ -73,8 +148,7 @@ public:
/// The catch handler for this type.
llvm::BasicBlock *Block;
- /// The unwind destination index for this handler.
- unsigned Index;
+ bool isCatchAll() const { return Type == 0; }
};
private:
@@ -93,12 +167,14 @@ public:
return sizeof(EHCatchScope) + N * sizeof(Handler);
}
- EHCatchScope(unsigned NumHandlers)
- : EHScope(Catch), NumHandlers(NumHandlers) {
+ EHCatchScope(unsigned numHandlers,
+ EHScopeStack::stable_iterator enclosingEHScope)
+ : EHScope(Catch, enclosingEHScope) {
+ CatchBits.NumHandlers = numHandlers;
}
unsigned getNumHandlers() const {
- return NumHandlers;
+ return CatchBits.NumHandlers;
}
void setCatchAllHandler(unsigned I, llvm::BasicBlock *Block) {
@@ -127,44 +203,16 @@ public:
/// A cleanup scope which generates the cleanup blocks lazily.
class EHCleanupScope : public EHScope {
- /// Whether this cleanup needs to be run along normal edges.
- bool IsNormalCleanup : 1;
-
- /// Whether this cleanup needs to be run along exception edges.
- bool IsEHCleanup : 1;
-
- /// Whether this cleanup is currently active.
- bool IsActive : 1;
-
- /// Whether the normal cleanup should test the activation flag.
- bool TestFlagInNormalCleanup : 1;
-
- /// Whether the EH cleanup should test the activation flag.
- bool TestFlagInEHCleanup : 1;
-
- /// The amount of extra storage needed by the Cleanup.
- /// Always a multiple of the scope-stack alignment.
- unsigned CleanupSize : 12;
-
- /// The number of fixups required by enclosing scopes (not including
- /// this one). If this is the top cleanup scope, all the fixups
- /// from this index onwards belong to this scope.
- unsigned FixupDepth : BitsRemaining - 17; // currently 13
-
/// The nearest normal cleanup scope enclosing this one.
EHScopeStack::stable_iterator EnclosingNormal;
- /// The nearest EH cleanup scope enclosing this one.
+ /// The nearest EH scope enclosing this one.
EHScopeStack::stable_iterator EnclosingEH;
/// The dual entry/exit block along the normal edge. This is lazily
/// created if needed before the cleanup is popped.
llvm::BasicBlock *NormalBlock;
- /// The dual entry/exit block along the EH edge. This is lazily
- /// created if needed before the cleanup is popped.
- llvm::BasicBlock *EHBlock;
-
/// An optional i1 variable indicating whether this cleanup has been
/// activated yet.
llvm::AllocaInst *ActiveFlag;
@@ -178,17 +226,8 @@ class EHCleanupScope : public EHScope {
llvm::SmallPtrSet<llvm::BasicBlock*, 4> Branches;
/// Normal branch-afters.
- llvm::SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4>
+ SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4>
BranchAfters;
-
- /// The destinations of EH branch-afters and branch-throughs.
- /// TODO: optimize for the extremely common case of a single
- /// branch-through.
- llvm::SmallPtrSet<llvm::BasicBlock*, 4> EHBranches;
-
- /// EH branch-afters.
- llvm::SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4>
- EHBranchAfters;
};
mutable struct ExtInfo *ExtInfo;
@@ -210,56 +249,64 @@ public:
}
size_t getAllocatedSize() const {
- return sizeof(EHCleanupScope) + CleanupSize;
+ return sizeof(EHCleanupScope) + CleanupBits.CleanupSize;
}
- EHCleanupScope(bool IsNormal, bool IsEH, bool IsActive,
- unsigned CleanupSize, unsigned FixupDepth,
- EHScopeStack::stable_iterator EnclosingNormal,
- EHScopeStack::stable_iterator EnclosingEH)
- : EHScope(EHScope::Cleanup),
- IsNormalCleanup(IsNormal), IsEHCleanup(IsEH), IsActive(IsActive),
- TestFlagInNormalCleanup(false), TestFlagInEHCleanup(false),
- CleanupSize(CleanupSize), FixupDepth(FixupDepth),
- EnclosingNormal(EnclosingNormal), EnclosingEH(EnclosingEH),
- NormalBlock(0), EHBlock(0), ActiveFlag(0), ExtInfo(0)
- {
- assert(this->CleanupSize == CleanupSize && "cleanup size overflow");
+ EHCleanupScope(bool isNormal, bool isEH, bool isActive,
+ unsigned cleanupSize, unsigned fixupDepth,
+ EHScopeStack::stable_iterator enclosingNormal,
+ EHScopeStack::stable_iterator enclosingEH)
+ : EHScope(EHScope::Cleanup, enclosingEH), EnclosingNormal(enclosingNormal),
+ NormalBlock(0), ActiveFlag(0), ExtInfo(0) {
+ CleanupBits.IsNormalCleanup = isNormal;
+ CleanupBits.IsEHCleanup = isEH;
+ CleanupBits.IsActive = isActive;
+ CleanupBits.TestFlagInNormalCleanup = false;
+ CleanupBits.TestFlagInEHCleanup = false;
+ CleanupBits.CleanupSize = cleanupSize;
+ CleanupBits.FixupDepth = fixupDepth;
+
+ assert(CleanupBits.CleanupSize == cleanupSize && "cleanup size overflow");
}
~EHCleanupScope() {
delete ExtInfo;
}
- bool isNormalCleanup() const { return IsNormalCleanup; }
+ bool isNormalCleanup() const { return CleanupBits.IsNormalCleanup; }
llvm::BasicBlock *getNormalBlock() const { return NormalBlock; }
void setNormalBlock(llvm::BasicBlock *BB) { NormalBlock = BB; }
- bool isEHCleanup() const { return IsEHCleanup; }
- llvm::BasicBlock *getEHBlock() const { return EHBlock; }
- void setEHBlock(llvm::BasicBlock *BB) { EHBlock = BB; }
+ bool isEHCleanup() const { return CleanupBits.IsEHCleanup; }
+ llvm::BasicBlock *getEHBlock() const { return getCachedEHDispatchBlock(); }
+ void setEHBlock(llvm::BasicBlock *BB) { setCachedEHDispatchBlock(BB); }
- bool isActive() const { return IsActive; }
- void setActive(bool A) { IsActive = A; }
+ bool isActive() const { return CleanupBits.IsActive; }
+ void setActive(bool A) { CleanupBits.IsActive = A; }
llvm::AllocaInst *getActiveFlag() const { return ActiveFlag; }
void setActiveFlag(llvm::AllocaInst *Var) { ActiveFlag = Var; }
- void setTestFlagInNormalCleanup() { TestFlagInNormalCleanup = true; }
- bool shouldTestFlagInNormalCleanup() const { return TestFlagInNormalCleanup; }
+ void setTestFlagInNormalCleanup() {
+ CleanupBits.TestFlagInNormalCleanup = true;
+ }
+ bool shouldTestFlagInNormalCleanup() const {
+ return CleanupBits.TestFlagInNormalCleanup;
+ }
- void setTestFlagInEHCleanup() { TestFlagInEHCleanup = true; }
- bool shouldTestFlagInEHCleanup() const { return TestFlagInEHCleanup; }
+ void setTestFlagInEHCleanup() {
+ CleanupBits.TestFlagInEHCleanup = true;
+ }
+ bool shouldTestFlagInEHCleanup() const {
+ return CleanupBits.TestFlagInEHCleanup;
+ }
- unsigned getFixupDepth() const { return FixupDepth; }
+ unsigned getFixupDepth() const { return CleanupBits.FixupDepth; }
EHScopeStack::stable_iterator getEnclosingNormalCleanup() const {
return EnclosingNormal;
}
- EHScopeStack::stable_iterator getEnclosingEHCleanup() const {
- return EnclosingEH;
- }
- size_t getCleanupSize() const { return CleanupSize; }
+ size_t getCleanupSize() const { return CleanupBits.CleanupSize; }
void *getCleanupBuffer() { return this + 1; }
EHScopeStack::Cleanup *getCleanup() {
@@ -327,41 +374,6 @@ public:
return (ExtInfo->BranchAfters.size() != ExtInfo->Branches.size());
}
- // Same stuff, only for EH branches instead of normal branches.
- // It's quite possible that we could find a better representation
- // for this.
-
- bool hasEHBranches() const { return ExtInfo && !ExtInfo->EHBranches.empty(); }
- void addEHBranchAfter(llvm::ConstantInt *Index,
- llvm::BasicBlock *Block) {
- struct ExtInfo &ExtInfo = getExtInfo();
- if (ExtInfo.EHBranches.insert(Block))
- ExtInfo.EHBranchAfters.push_back(std::make_pair(Block, Index));
- }
-
- unsigned getNumEHBranchAfters() const {
- return ExtInfo ? ExtInfo->EHBranchAfters.size() : 0;
- }
-
- llvm::BasicBlock *getEHBranchAfterBlock(unsigned I) const {
- assert(I < getNumEHBranchAfters());
- return ExtInfo->EHBranchAfters[I].first;
- }
-
- llvm::ConstantInt *getEHBranchAfterIndex(unsigned I) const {
- assert(I < getNumEHBranchAfters());
- return ExtInfo->EHBranchAfters[I].second;
- }
-
- bool addEHBranchThrough(llvm::BasicBlock *Block) {
- return getExtInfo().EHBranches.insert(Block);
- }
-
- bool hasEHBranchThroughs() const {
- if (!ExtInfo) return false;
- return (ExtInfo->EHBranchAfters.size() != ExtInfo->EHBranches.size());
- }
-
static bool classof(const EHScope *Scope) {
return (Scope->getKind() == Cleanup);
}
@@ -373,8 +385,6 @@ public:
///
/// This is used to implement C++ exception specifications.
class EHFilterScope : public EHScope {
- unsigned NumFilters : BitsRemaining;
-
// Essentially ends in a flexible array member:
// llvm::Value *FilterTypes[0];
@@ -387,42 +397,42 @@ class EHFilterScope : public EHScope {
}
public:
- EHFilterScope(unsigned NumFilters) :
- EHScope(Filter), NumFilters(NumFilters) {}
+ EHFilterScope(unsigned numFilters)
+ : EHScope(Filter, EHScopeStack::stable_end()) {
+ FilterBits.NumFilters = numFilters;
+ }
- static size_t getSizeForNumFilters(unsigned NumFilters) {
- return sizeof(EHFilterScope) + NumFilters * sizeof(llvm::Value*);
+ static size_t getSizeForNumFilters(unsigned numFilters) {
+ return sizeof(EHFilterScope) + numFilters * sizeof(llvm::Value*);
}
- unsigned getNumFilters() const { return NumFilters; }
+ unsigned getNumFilters() const { return FilterBits.NumFilters; }
- void setFilter(unsigned I, llvm::Value *FilterValue) {
- assert(I < getNumFilters());
- getFilters()[I] = FilterValue;
+ void setFilter(unsigned i, llvm::Value *filterValue) {
+ assert(i < getNumFilters());
+ getFilters()[i] = filterValue;
}
- llvm::Value *getFilter(unsigned I) const {
- assert(I < getNumFilters());
- return getFilters()[I];
+ llvm::Value *getFilter(unsigned i) const {
+ assert(i < getNumFilters());
+ return getFilters()[i];
}
- static bool classof(const EHScope *Scope) {
- return Scope->getKind() == Filter;
+ static bool classof(const EHScope *scope) {
+ return scope->getKind() == Filter;
}
};
/// An exceptions scope which calls std::terminate if any exception
/// reaches it.
class EHTerminateScope : public EHScope {
- unsigned DestIndex : BitsRemaining;
public:
- EHTerminateScope(unsigned Index) : EHScope(Terminate), DestIndex(Index) {}
+ EHTerminateScope(EHScopeStack::stable_iterator enclosingEHScope)
+ : EHScope(Terminate, enclosingEHScope) {}
static size_t getSize() { return sizeof(EHTerminateScope); }
- unsigned getDestIndex() const { return DestIndex; }
-
- static bool classof(const EHScope *Scope) {
- return Scope->getKind() == Terminate;
+ static bool classof(const EHScope *scope) {
+ return scope->getKind() == Terminate;
}
};
@@ -498,26 +508,17 @@ inline EHScopeStack::iterator EHScopeStack::end() const {
inline void EHScopeStack::popCatch() {
assert(!empty() && "popping exception stack when not empty");
- assert(isa<EHCatchScope>(*begin()));
- StartOfData += EHCatchScope::getSizeForNumHandlers(
- cast<EHCatchScope>(*begin()).getNumHandlers());
-
- if (empty()) NextEHDestIndex = FirstEHDestIndex;
-
- assert(CatchDepth > 0 && "mismatched catch/terminate push/pop");
- CatchDepth--;
+ EHCatchScope &scope = cast<EHCatchScope>(*begin());
+ InnermostEHScope = scope.getEnclosingEHScope();
+ StartOfData += EHCatchScope::getSizeForNumHandlers(scope.getNumHandlers());
}
inline void EHScopeStack::popTerminate() {
assert(!empty() && "popping exception stack when not empty");
- assert(isa<EHTerminateScope>(*begin()));
+ EHTerminateScope &scope = cast<EHTerminateScope>(*begin());
+ InnermostEHScope = scope.getEnclosingEHScope();
StartOfData += EHTerminateScope::getSize();
-
- if (empty()) NextEHDestIndex = FirstEHDestIndex;
-
- assert(CatchDepth > 0 && "mismatched catch/terminate push/pop");
- CatchDepth--;
}
inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const {
@@ -532,28 +533,6 @@ EHScopeStack::stabilize(iterator ir) const {
return stable_iterator(EndOfBuffer - ir.Ptr);
}
-inline EHScopeStack::stable_iterator
-EHScopeStack::getInnermostActiveNormalCleanup() const {
- for (EHScopeStack::stable_iterator
- I = getInnermostNormalCleanup(), E = stable_end(); I != E; ) {
- EHCleanupScope &S = cast<EHCleanupScope>(*find(I));
- if (S.isActive()) return I;
- I = S.getEnclosingNormalCleanup();
- }
- return stable_end();
-}
-
-inline EHScopeStack::stable_iterator
-EHScopeStack::getInnermostActiveEHCleanup() const {
- for (EHScopeStack::stable_iterator
- I = getInnermostEHCleanup(), E = stable_end(); I != E; ) {
- EHCleanupScope &S = cast<EHCleanupScope>(*find(I));
- if (S.isActive()) return I;
- I = S.getEnclosingEHCleanup();
- }
- return stable_end();
-}
-
}
}
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 4c1244591743..c7a9b407d264 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -33,7 +33,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Dwarf.h"
-#include "llvm/Support/Path.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
using namespace clang;
@@ -46,12 +46,46 @@ CGDebugInfo::CGDebugInfo(CodeGenModule &CGM)
}
CGDebugInfo::~CGDebugInfo() {
- assert(RegionStack.empty() && "Region stack mismatch, stack not empty!");
+ assert(LexicalBlockStack.empty() &&
+ "Region stack mismatch, stack not empty!");
}
void CGDebugInfo::setLocation(SourceLocation Loc) {
- if (Loc.isValid())
- CurLoc = CGM.getContext().getSourceManager().getInstantiationLoc(Loc);
+ // If the new location isn't valid return.
+ if (!Loc.isValid()) return;
+
+ CurLoc = CGM.getContext().getSourceManager().getExpansionLoc(Loc);
+
+ // If we've changed files in the middle of a lexical scope go ahead
+ // and create a new lexical scope with file node if it's different
+ // from the one in the scope.
+ if (LexicalBlockStack.empty()) return;
+
+ SourceManager &SM = CGM.getContext().getSourceManager();
+ PresumedLoc PCLoc = SM.getPresumedLoc(CurLoc);
+ PresumedLoc PPLoc = SM.getPresumedLoc(PrevLoc);
+
+ if (PCLoc.isInvalid() || PPLoc.isInvalid() ||
+ !strcmp(PPLoc.getFilename(), PCLoc.getFilename()))
+ return;
+
+ llvm::MDNode *LB = LexicalBlockStack.back();
+ llvm::DIScope Scope = llvm::DIScope(LB);
+ if (Scope.isLexicalBlockFile()) {
+ llvm::DILexicalBlockFile LBF = llvm::DILexicalBlockFile(LB);
+ llvm::DIDescriptor D
+ = DBuilder.createLexicalBlockFile(LBF.getScope(),
+ getOrCreateFile(CurLoc));
+ llvm::MDNode *N = D;
+ LexicalBlockStack.pop_back();
+ LexicalBlockStack.push_back(N);
+ } else if (Scope.isLexicalBlock()) {
+ llvm::DIDescriptor D
+ = DBuilder.createLexicalBlockFile(Scope, getOrCreateFile(CurLoc));
+ llvm::MDNode *N = D;
+ LexicalBlockStack.pop_back();
+ LexicalBlockStack.push_back(N);
+ }
}
/// getContextDescriptor - Get context info for the decl.
@@ -81,7 +115,7 @@ llvm::DIDescriptor CGDebugInfo::getContextDescriptor(const Decl *Context) {
/// getFunctionName - Get function name for the given FunctionDecl. If the
/// name is constructred on demand (e.g. C++ destructor) then the name
/// is stored on the side.
-llvm::StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
+StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
assert (FD && "Invalid FunctionDecl!");
IdentifierInfo *FII = FD->getIdentifier();
if (FII)
@@ -93,10 +127,10 @@ llvm::StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
// Copy this name on the side and use its reference.
char *StrPtr = DebugInfoNames.Allocate<char>(NS.length());
memcpy(StrPtr, NS.data(), NS.length());
- return llvm::StringRef(StrPtr, NS.length());
+ return StringRef(StrPtr, NS.length());
}
-llvm::StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
+StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
llvm::SmallString<256> MethodName;
llvm::raw_svector_ostream OS(MethodName);
OS << (OMD->isInstanceMethod() ? '-' : '+') << '[';
@@ -116,22 +150,20 @@ llvm::StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
char *StrPtr = DebugInfoNames.Allocate<char>(OS.tell());
memcpy(StrPtr, MethodName.begin(), OS.tell());
- return llvm::StringRef(StrPtr, OS.tell());
+ return StringRef(StrPtr, OS.tell());
}
/// getSelectorName - Return selector name. This is used for debugging
/// info.
-llvm::StringRef CGDebugInfo::getSelectorName(Selector S) {
- llvm::SmallString<256> SName;
- llvm::raw_svector_ostream OS(SName);
- OS << S.getAsString();
- char *StrPtr = DebugInfoNames.Allocate<char>(OS.tell());
- memcpy(StrPtr, SName.begin(), OS.tell());
- return llvm::StringRef(StrPtr, OS.tell());
+StringRef CGDebugInfo::getSelectorName(Selector S) {
+ const std::string &SName = S.getAsString();
+ char *StrPtr = DebugInfoNames.Allocate<char>(SName.size());
+ memcpy(StrPtr, SName.data(), SName.size());
+ return StringRef(StrPtr, SName.size());
}
/// getClassName - Get class name including template argument list.
-llvm::StringRef
+StringRef
CGDebugInfo::getClassName(RecordDecl *RD) {
ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(RD);
@@ -160,7 +192,7 @@ CGDebugInfo::getClassName(RecordDecl *RD) {
// Copy this name on the side and use its reference.
char *StrPtr = DebugInfoNames.Allocate<char>(Buffer.length());
memcpy(StrPtr, Buffer.data(), Buffer.length());
- return llvm::StringRef(StrPtr, Buffer.length());
+ return StringRef(StrPtr, Buffer.length());
}
/// getOrCreateFile - Get the file debug info descriptor for the input location.
@@ -172,7 +204,7 @@ llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
- if (PLoc.isInvalid() || llvm::StringRef(PLoc.getFilename()).empty())
+ if (PLoc.isInvalid() || StringRef(PLoc.getFilename()).empty())
// If the location is not valid then use main input file.
return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory());
@@ -202,7 +234,7 @@ llvm::DIFile CGDebugInfo::getOrCreateMainFile() {
/// getLineNumber - Get line number for the location. If location is invalid
/// then use current location.
unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) {
- assert (CurLoc.isValid() && "Invalid current location!");
+ assert((Loc.isValid() || CurLoc.isValid()) && "Invalid current location!");
SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc);
return PLoc.isValid()? PLoc.getLine() : 0;
@@ -211,20 +243,20 @@ unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) {
/// getColumnNumber - Get column number for the location. If location is
/// invalid then use current location.
unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc) {
- assert (CurLoc.isValid() && "Invalid current location!");
+ assert((Loc.isValid() || CurLoc.isValid()) && "Invalid current location!");
SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc);
return PLoc.isValid()? PLoc.getColumn() : 0;
}
-llvm::StringRef CGDebugInfo::getCurrentDirname() {
+StringRef CGDebugInfo::getCurrentDirname() {
if (!CWDName.empty())
return CWDName;
- char *CompDirnamePtr = NULL;
- llvm::sys::Path CWD = llvm::sys::Path::GetCurrentDirectory();
- CompDirnamePtr = DebugInfoNames.Allocate<char>(CWD.size());
- memcpy(CompDirnamePtr, CWD.c_str(), CWD.size());
- return CWDName = llvm::StringRef(CompDirnamePtr, CWD.size());
+ llvm::SmallString<256> CWD;
+ llvm::sys::fs::current_path(CWD);
+ char *CompDirnamePtr = DebugInfoNames.Allocate<char>(CWD.size());
+ memcpy(CompDirnamePtr, CWD.data(), CWD.size());
+ return CWDName = StringRef(CompDirnamePtr, CWD.size());
}
/// CreateCompileUnit - Create new compile unit.
@@ -250,7 +282,7 @@ void CGDebugInfo::CreateCompileUnit() {
// Save filename string.
char *FilenamePtr = DebugInfoNames.Allocate<char>(MainFileName.length());
memcpy(FilenamePtr, MainFileName.c_str(), MainFileName.length());
- llvm::StringRef Filename(FilenamePtr, MainFileName.length());
+ StringRef Filename(FilenamePtr, MainFileName.length());
unsigned LangTag;
const LangOptions &LO = CGM.getLangOptions();
@@ -289,7 +321,17 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
unsigned Encoding = 0;
const char *BTName = NULL;
switch (BT->getKind()) {
- default:
+ case BuiltinType::Dependent:
+ llvm_unreachable("Unexpected builtin type Dependent");
+ case BuiltinType::Overload:
+ llvm_unreachable("Unexpected builtin type Overload");
+ case BuiltinType::BoundMember:
+ llvm_unreachable("Unexpected builtin type BoundMember");
+ case BuiltinType::UnknownAny:
+ llvm_unreachable("Unexpected builtin type UnknownAny");
+ case BuiltinType::NullPtr:
+ return DBuilder.
+ createNullPtrType(BT->getName(CGM.getContext().getLangOptions()));
case BuiltinType::Void:
return llvm::DIType();
case BuiltinType::ObjCClass:
@@ -312,7 +354,7 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
llvm::DIType ISATy = DBuilder.createPointerType(OCTy, Size);
- llvm::SmallVector<llvm::Value *, 16> EltTys;
+ SmallVector<llvm::Value *, 16> EltTys;
llvm::DIType FieldTy =
DBuilder.createMemberType(getOrCreateMainFile(), "isa",
getOrCreateMainFile(), 0, Size,
@@ -334,17 +376,22 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
case BuiltinType::Char_U: Encoding = llvm::dwarf::DW_ATE_unsigned_char; break;
case BuiltinType::Char_S:
case BuiltinType::SChar: Encoding = llvm::dwarf::DW_ATE_signed_char; break;
+ case BuiltinType::Char16:
+ case BuiltinType::Char32: Encoding = llvm::dwarf::DW_ATE_UTF; break;
case BuiltinType::UShort:
case BuiltinType::UInt:
case BuiltinType::UInt128:
case BuiltinType::ULong:
+ case BuiltinType::WChar_U:
case BuiltinType::ULongLong: Encoding = llvm::dwarf::DW_ATE_unsigned; break;
case BuiltinType::Short:
case BuiltinType::Int:
case BuiltinType::Int128:
case BuiltinType::Long:
+ case BuiltinType::WChar_S:
case BuiltinType::LongLong: Encoding = llvm::dwarf::DW_ATE_signed; break;
case BuiltinType::Bool: Encoding = llvm::dwarf::DW_ATE_boolean; break;
+ case BuiltinType::Half:
case BuiltinType::Float:
case BuiltinType::LongDouble:
case BuiltinType::Double: Encoding = llvm::dwarf::DW_ATE_float; break;
@@ -432,7 +479,7 @@ llvm::DIType CGDebugInfo::CreateType(const PointerType *Ty,
Ty->getPointeeType(), Unit);
}
-/// CreatePointeeType - Create PointTee type. If Pointee is a record
+/// CreatePointeeType - Create Pointee type. If Pointee is a record
/// then emit record's fwd if debug info size reduction is enabled.
llvm::DIType CGDebugInfo::CreatePointeeType(QualType PointeeTy,
llvm::DIFile Unit) {
@@ -477,7 +524,7 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
// Size is always the size of a pointer. We can't use getTypeSize here
// because that does not return the correct value for references.
unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy);
- uint64_t Size = CGM.getContext().Target.getPointerWidth(AS);
+ uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
return
@@ -489,7 +536,7 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
if (BlockLiteralGenericSet)
return BlockLiteralGeneric;
- llvm::SmallVector<llvm::Value *, 8> EltTys;
+ SmallVector<llvm::Value *, 8> EltTys;
llvm::DIType FieldTy;
QualType FType;
uint64_t FieldSize, FieldOffset;
@@ -567,7 +614,7 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty,
llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
llvm::DIFile Unit) {
- llvm::SmallVector<llvm::Value *, 16> EltTys;
+ SmallVector<llvm::Value *, 16> EltTys;
// Add the result type at least.
EltTys.push_back(getOrCreateType(Ty->getResultType(), Unit));
@@ -587,9 +634,9 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
return DbgTy;
}
-llvm::DIType CGDebugInfo::createFieldType(llvm::StringRef name,
+llvm::DIType CGDebugInfo::createFieldType(StringRef name,
QualType type,
- Expr *bitWidth,
+ uint64_t sizeInBitsOverride,
SourceLocation loc,
AccessSpecifier AS,
uint64_t offsetInBits,
@@ -606,8 +653,8 @@ llvm::DIType CGDebugInfo::createFieldType(llvm::StringRef name,
if (!type->isIncompleteArrayType()) {
llvm::tie(sizeInBits, alignInBits) = CGM.getContext().getTypeInfo(type);
- if (bitWidth)
- sizeInBits = bitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue();
+ if (sizeInBitsOverride)
+ sizeInBits = sizeInBitsOverride;
}
unsigned flags = 0;
@@ -624,7 +671,7 @@ llvm::DIType CGDebugInfo::createFieldType(llvm::StringRef name,
/// record fields. This is used while creating debug info entry for a Record.
void CGDebugInfo::
CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
- llvm::SmallVectorImpl<llvm::Value *> &elements,
+ SmallVectorImpl<llvm::Value *> &elements,
llvm::DIType RecordTy) {
unsigned fieldNo = 0;
const FieldDecl *LastFD = 0;
@@ -644,7 +691,7 @@ CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
LastFD = field;
}
- llvm::StringRef name = field->getName();
+ StringRef name = field->getName();
QualType type = field->getType();
// Ignore unnamed fields unless they're anonymous structs/unions.
@@ -653,8 +700,14 @@ CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
continue;
}
+ 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, field->getBitWidth(),
+ = createFieldType(name, type, SizeInBitsOverride,
field->getLocation(), field->getAccess(),
layout.getFieldOffset(fieldNo), tunit, RecordTy);
@@ -674,25 +727,23 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
Unit);
// Add "this" pointer.
-
llvm::DIArray Args = llvm::DICompositeType(FnTy).getTypeArray();
assert (Args.getNumElements() && "Invalid number of arguments!");
- llvm::SmallVector<llvm::Value *, 16> Elts;
+ SmallVector<llvm::Value *, 16> Elts;
// 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());
- llvm::DIType ThisPtrType =
- DBuilder.createArtificialType(getOrCreateType(ThisPtr, Unit));
-
- TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
- Elts.push_back(ThisPtrType);
- }
+ if (!Method->isStatic()) {
+ // "this" pointer is always first argument.
+ QualType ThisPtr = Method->getThisType(CGM.getContext());
+ llvm::DIType ThisPtrType =
+ DBuilder.createArtificialType(getOrCreateType(ThisPtr, Unit));
+
+ TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
+ Elts.push_back(ThisPtrType);
+ }
// Copy rest of the arguments.
for (unsigned i = 1, e = Args.getNumElements(); i != e; ++i)
@@ -723,12 +774,12 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
bool IsCtorOrDtor =
isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
- llvm::StringRef MethodName = getFunctionName(Method);
+ StringRef MethodName = getFunctionName(Method);
llvm::DIType MethodTy = getOrCreateMethodType(Method, Unit);
// Since a single ctor/dtor corresponds to multiple functions, it doesn't
// make sense to give a single ctor/dtor a linkage name.
- llvm::StringRef MethodLinkageName;
+ StringRef MethodLinkageName;
if (!IsCtorOrDtor && !isFunctionLocalClass(Method->getParent()))
MethodLinkageName = CGM.getMangledName(Method);
@@ -750,7 +801,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
// It doesn't make sense to give a virtual destructor a vtable index,
// since a single destructor has two entries in the vtable.
if (!isa<CXXDestructorDecl>(Method))
- VIndex = CGM.getVTables().getMethodVTableIndex(Method);
+ VIndex = CGM.getVTableContext().getMethodVTableIndex(Method);
ContainingType = RecordTy;
}
@@ -774,7 +825,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
Flags |= llvm::DIDescriptor::FlagPrototyped;
llvm::DISubprogram SP =
- DBuilder.createMethod(RecordTy , MethodName, MethodLinkageName,
+ DBuilder.createMethod(RecordTy, MethodName, MethodLinkageName,
MethodDefUnit, MethodLine,
MethodTy, /*isLocalToUnit=*/false,
/* isDefinition=*/ false,
@@ -791,7 +842,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
/// a Record.
void CGDebugInfo::
CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DIFile Unit,
- llvm::SmallVectorImpl<llvm::Value *> &EltTys,
+ SmallVectorImpl<llvm::Value *> &EltTys,
llvm::DIType RecordTy) {
for(CXXRecordDecl::method_iterator I = RD->method_begin(),
E = RD->method_end(); I != E; ++I) {
@@ -809,11 +860,12 @@ CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DIFile Unit,
/// a Record.
void CGDebugInfo::
CollectCXXFriends(const CXXRecordDecl *RD, llvm::DIFile Unit,
- llvm::SmallVectorImpl<llvm::Value *> &EltTys,
+ SmallVectorImpl<llvm::Value *> &EltTys,
llvm::DIType RecordTy) {
-
for (CXXRecordDecl::friend_iterator BI = RD->friend_begin(),
BE = RD->friend_end(); BI != BE; ++BI) {
+ if ((*BI)->isUnsupportedFriend())
+ continue;
if (TypeSourceInfo *TInfo = (*BI)->getFriendType())
EltTys.push_back(DBuilder.createFriend(RecordTy,
getOrCreateType(TInfo->getType(),
@@ -826,7 +878,7 @@ CollectCXXFriends(const CXXRecordDecl *RD, llvm::DIFile Unit,
/// a Record.
void CGDebugInfo::
CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit,
- llvm::SmallVectorImpl<llvm::Value *> &EltTys,
+ SmallVectorImpl<llvm::Value *> &EltTys,
llvm::DIType RecordTy) {
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
@@ -842,7 +894,8 @@ CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit,
// virtual base offset offset is -ve. The code generator emits dwarf
// expression where it expects +ve number.
BaseOffset =
- 0 - CGM.getVTables().getVirtualBaseOffsetOffset(RD, Base).getQuantity();
+ 0 - CGM.getVTableContext()
+ .getVirtualBaseOffsetOffset(RD, Base).getQuantity();
BFlags = llvm::DIDescriptor::FlagVirtual;
} else
BaseOffset = RL.getBaseClassOffsetInBits(Base);
@@ -868,7 +921,7 @@ llvm::DIArray CGDebugInfo::
CollectTemplateParams(const TemplateParameterList *TPList,
const TemplateArgumentList &TAList,
llvm::DIFile Unit) {
- llvm::SmallVector<llvm::Value *, 16> TemplateParams;
+ SmallVector<llvm::Value *, 16> TemplateParams;
for (unsigned i = 0, e = TAList.size(); i != e; ++i) {
const TemplateArgument &TA = TAList[i];
const NamedDecl *ND = TPList->getParam(i);
@@ -892,9 +945,11 @@ CollectTemplateParams(const TemplateParameterList *TPList,
/// info for function template parameters.
llvm::DIArray CGDebugInfo::
CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit) {
- if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplateSpecialization){
+ if (FD->getTemplatedKind() ==
+ FunctionDecl::TK_FunctionTemplateSpecialization) {
const TemplateParameterList *TList =
- FD->getTemplateSpecializationInfo()->getTemplate()->getTemplateParameters();
+ FD->getTemplateSpecializationInfo()->getTemplate()
+ ->getTemplateParameters();
return
CollectTemplateParams(TList, *FD->getTemplateSpecializationArgs(), Unit);
}
@@ -936,14 +991,14 @@ llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) {
}
/// getVTableName - Get vtable name for the given Class.
-llvm::StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) {
+StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) {
// Otherwise construct gdb compatible name name.
std::string Name = "_vptr$" + RD->getNameAsString();
// Copy this name on the side and use its reference.
char *StrPtr = DebugInfoNames.Allocate<char>(Name.length());
memcpy(StrPtr, Name.data(), Name.length());
- return llvm::StringRef(StrPtr, Name.length());
+ return StringRef(StrPtr, Name.length());
}
@@ -951,7 +1006,7 @@ llvm::StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) {
/// debug info entry in EltTys vector.
void CGDebugInfo::
CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
- llvm::SmallVectorImpl<llvm::Value *> &EltTys) {
+ SmallVectorImpl<llvm::Value *> &EltTys) {
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
// If there is a primary base then it will hold vtable info.
@@ -1016,11 +1071,11 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
// it.
TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
// Push the struct on region stack.
- RegionStack.push_back(FwdDeclNode);
+ LexicalBlockStack.push_back(FwdDeclNode);
RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
// Convert all the elements.
- llvm::SmallVector<llvm::Value *, 16> EltTys;
+ SmallVector<llvm::Value *, 16> EltTys;
const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
if (CXXDecl) {
@@ -1040,7 +1095,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
// Create the descriptor for static variable.
llvm::DIFile VUnit = getOrCreateFile(V->getLocation());
- llvm::StringRef VName = V->getName();
+ 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) {
@@ -1062,7 +1117,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
TParamsArray = CollectCXXTemplateParams(TSpecial, Unit);
}
- RegionStack.pop_back();
+ LexicalBlockStack.pop_back();
llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator RI =
RegionMap.find(Ty->getDecl());
if (RI != RegionMap.end())
@@ -1070,7 +1125,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
llvm::DIDescriptor RDContext =
getContextDescriptor(cast<Decl>(RD->getDeclContext()));
- llvm::StringRef RDName = RD->getName();
+ StringRef RDName = RD->getName();
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
@@ -1134,8 +1189,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
unsigned Line = getLineNumber(ID->getLocation());
unsigned RuntimeLang = TheCU.getLanguage();
- // If this is just a forward declaration, return a special forward-declaration
- // debug type.
+ // If this is just a forward declaration return a special forward-declaration
+ // debug type since we won't be able to lay out the entire type.
if (ID->isForwardDecl()) {
llvm::DIType FwdDecl =
DBuilder.createStructType(Unit, ID->getName(),
@@ -1144,12 +1199,12 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
return FwdDecl;
}
- // To handle recursive interface, we
- // first generate a debug descriptor for the struct as a forward declaration.
- // Then (if it is a definition) we go through and get debug info for all of
- // its members. Finally, we create a descriptor for the complete type (which
- // may refer to the forward decl if the struct is recursive) and replace all
- // uses of the forward declaration with the final definition.
+ // To handle a recursive interface, we first generate a debug descriptor
+ // for the struct as a forward declaration. Then (if it is a definition)
+ // we go through and get debug info for all of its members. Finally, we
+ // create a descriptor for the complete type (which 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 = DBuilder.createTemporaryType(DefUnit);
llvm::MDNode *MN = FwdDecl;
@@ -1158,11 +1213,11 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// it.
TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
// Push the struct on region stack.
- RegionStack.push_back(FwdDeclNode);
+ LexicalBlockStack.push_back(FwdDeclNode);
RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
// Convert all the elements.
- llvm::SmallVector<llvm::Value *, 16> EltTys;
+ SmallVector<llvm::Value *, 16> EltTys;
ObjCInterfaceDecl *SClass = ID->getSuperClass();
if (SClass) {
@@ -1177,7 +1232,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
}
const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(ID);
-
+ ObjCImplementationDecl *ImpD = ID->getImplementation();
unsigned FieldNo = 0;
for (ObjCIvarDecl *Field = ID->all_declared_ivar_begin(); Field;
Field = Field->getNextIvar(), ++FieldNo) {
@@ -1185,7 +1240,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
if (!FieldTy.isValid())
return llvm::DIType();
- llvm::StringRef FieldName = Field->getName();
+ StringRef FieldName = Field->getName();
// Ignore unnamed fields.
if (FieldName.empty())
@@ -1201,15 +1256,18 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
if (!FType->isIncompleteArrayType()) {
// Bit size, align and offset of the type.
- FieldSize = CGM.getContext().getTypeSize(FType);
- Expr *BitWidth = Field->getBitWidth();
- if (BitWidth)
- FieldSize = BitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue();
-
- FieldAlign = CGM.getContext().getTypeAlign(FType);
+ FieldSize = Field->isBitField()
+ ? Field->getBitWidthValue(CGM.getContext())
+ : CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
}
- uint64_t FieldOffset = RL.getFieldOffset(FieldNo);
+ // We can't know the offset of our ivar in the structure if we're using
+ // the non-fragile abi and the debugger should ignore the value anyways.
+ // Call it the FieldNo+1 due to how debuggers use the information,
+ // e.g. negating the value when it needs a lookup in the dynamic table.
+ uint64_t FieldOffset = CGM.getLangOptions().ObjCNonFragileABI ? FieldNo+1
+ : RL.getFieldOffset(FieldNo);
unsigned Flags = 0;
if (Field->getAccessControl() == ObjCIvarDecl::Protected)
@@ -1217,17 +1275,21 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
else if (Field->getAccessControl() == ObjCIvarDecl::Private)
Flags = llvm::DIDescriptor::FlagPrivate;
- llvm::StringRef PropertyName;
- llvm::StringRef PropertyGetter;
- llvm::StringRef PropertySetter;
+ StringRef PropertyName;
+ StringRef PropertyGetter;
+ StringRef PropertySetter;
unsigned PropertyAttributes = 0;
- if (ObjCPropertyDecl *PD =
- ID->FindPropertyVisibleInPrimaryClass(Field->getIdentifier())) {
+ ObjCPropertyDecl *PD = NULL;
+ if (ImpD)
+ if (ObjCPropertyImplDecl *PImpD =
+ ImpD->FindPropertyImplIvarDecl(Field->getIdentifier()))
+ PD = PImpD->getPropertyDecl();
+ if (PD) {
PropertyName = PD->getName();
PropertyGetter = getSelectorName(PD->getGetterName());
PropertySetter = getSelectorName(PD->getSetterName());
PropertyAttributes = PD->getPropertyAttributes();
- }
+ }
FieldTy = DBuilder.createObjCIVar(FieldName, FieldDefUnit,
FieldLine, FieldSize, FieldAlign,
FieldOffset, Flags, FieldTy,
@@ -1238,7 +1300,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
- RegionStack.pop_back();
+ LexicalBlockStack.pop_back();
llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator RI =
RegionMap.find(Ty->getDecl());
if (RI != RegionMap.end())
@@ -1322,7 +1384,7 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
// Add the dimensions of the array. FIXME: This loses CV qualifiers from
// interior arrays, do we care? Why aren't nested arrays represented the
// obvious/recursive way?
- llvm::SmallVector<llvm::Value *, 8> Subscripts;
+ SmallVector<llvm::Value *, 8> Subscripts;
QualType EltTy(Ty, 0);
if (Ty->isIncompleteArrayType())
EltTy = Ty->getElementType();
@@ -1339,7 +1401,8 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
LowerBound = 1;
// FIXME: Verify this is right for VLAs.
- Subscripts.push_back(DBuilder.getOrCreateSubrange(LowerBound, UpperBound));
+ Subscripts.push_back(DBuilder.getOrCreateSubrange(LowerBound,
+ UpperBound));
EltTy = Ty->getElementType();
}
}
@@ -1395,15 +1458,22 @@ llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty,
llvm::DIArray Elements = DBuilder.getOrCreateArray(ElementTypes);
- return DBuilder.createStructType(U, llvm::StringRef("test"),
+ return DBuilder.createStructType(U, StringRef("test"),
U, 0, FieldOffset,
0, 0, Elements);
}
+llvm::DIType CGDebugInfo::CreateType(const AtomicType *Ty,
+ llvm::DIFile U) {
+ // Ignore the atomic wrapping
+ // FIXME: What is the correct representation?
+ return getOrCreateType(Ty->getValueType(), U);
+}
+
/// CreateEnumType - get enumeration type.
llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) {
llvm::DIFile Unit = getOrCreateFile(ED->getLocation());
- llvm::SmallVector<llvm::Value *, 16> Enumerators;
+ SmallVector<llvm::Value *, 16> Enumerators;
// Create DIEnumerator elements for each enumerator.
for (EnumDecl::enumerator_iterator
@@ -1522,7 +1592,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
#define NON_CANONICAL_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
#include "clang/AST/TypeNodes.def"
- assert(false && "Dependent types cannot show up in debug information");
+ llvm_unreachable("Dependent types cannot show up in debug information");
case Type::ExtVector:
case Type::Vector:
@@ -1558,6 +1628,9 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
case Type::MemberPointer:
return CreateType(cast<MemberPointerType>(Ty), Unit);
+ case Type::Atomic:
+ return CreateType(cast<AtomicType>(Ty), Unit);
+
case Type::Attributed:
case Type::TemplateSpecialization:
case Type::Elaborated:
@@ -1573,7 +1646,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
}
assert(Diag && "Fall through without a diagnostic?");
- unsigned DiagID = CGM.getDiags().getCustomDiagID(Diagnostic::Error,
+ unsigned DiagID = CGM.getDiags().getCustomDiagID(DiagnosticsEngine::Error,
"debug information for %0 is not yet supported");
CGM.getDiags().Report(DiagID)
<< Diag;
@@ -1582,7 +1655,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
/// CreateMemberType - Create new member and increase Offset by FType's size.
llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType,
- llvm::StringRef Name,
+ StringRef Name,
uint64_t *Offset) {
llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
uint64_t FieldSize = CGM.getContext().getTypeSize(FType);
@@ -1627,13 +1700,14 @@ llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) {
// getOrCreateFunctionType - Construct DIType. If it is a c++ method, include
// implicit parameter "this".
-llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl * D, QualType FnType,
+llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl * D,
+ QualType FnType,
llvm::DIFile F) {
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
return getOrCreateMethodType(Method, F);
else if (const ObjCMethodDecl *OMethod = dyn_cast<ObjCMethodDecl>(D)) {
// Add "self" and "_cmd"
- llvm::SmallVector<llvm::Value *, 16> Elts;
+ SmallVector<llvm::Value *, 16> Elts;
// First element is always return type. For 'void' functions it is NULL.
Elts.push_back(getOrCreateType(OMethod->getResultType(), F));
@@ -1642,7 +1716,7 @@ llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl * D, QualType FnTyp
// "cmd" pointer is always second argument.
Elts.push_back(getOrCreateType(OMethod->getCmdDecl()->getType(), F));
// Get rest of the arguments.
- for (ObjCMethodDecl::param_iterator PI = OMethod->param_begin(),
+ for (ObjCMethodDecl::param_const_iterator PI = OMethod->param_begin(),
PE = OMethod->param_end(); PI != PE; ++PI)
Elts.push_back(getOrCreateType((*PI)->getType(), F));
@@ -1658,13 +1732,13 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
llvm::Function *Fn,
CGBuilderTy &Builder) {
- llvm::StringRef Name;
- llvm::StringRef LinkageName;
+ StringRef Name;
+ StringRef LinkageName;
- FnBeginRegionCount.push_back(RegionStack.size());
+ FnBeginRegionCount.push_back(LexicalBlockStack.size());
const Decl *D = GD.getDecl();
-
+
unsigned Flags = 0;
llvm::DIFile Unit = getOrCreateFile(CurLoc);
llvm::DIDescriptor FDContext(Unit);
@@ -1677,7 +1751,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
llvm::DIDescriptor SP(dyn_cast_or_null<llvm::MDNode>(&*FI->second));
if (SP.isSubprogram() && llvm::DISubprogram(SP).isDefinition()) {
llvm::MDNode *SPN = SP;
- RegionStack.push_back(SPN);
+ LexicalBlockStack.push_back(SPN);
RegionMap[D] = llvm::WeakVH(SP);
return;
}
@@ -1687,7 +1761,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
if (!Fn->hasInternalLinkage())
LinkageName = CGM.getMangledName(GD);
if (LinkageName == Name)
- LinkageName = llvm::StringRef();
+ LinkageName = StringRef();
if (FD->hasPrototype())
Flags |= llvm::DIDescriptor::FlagPrototyped;
if (const NamespaceDecl *NSDecl =
@@ -1726,121 +1800,85 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
// Push function on region stack.
llvm::MDNode *SPN = SP;
- RegionStack.push_back(SPN);
+ LexicalBlockStack.push_back(SPN);
RegionMap[D] = llvm::WeakVH(SP);
-
- // Clear stack used to keep track of #line directives.
- LineDirectiveFiles.clear();
}
+/// EmitLocation - Emit metadata to indicate a change in line/column
+/// information in the source file.
+void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) {
+
+ // Update our current location
+ setLocation(Loc);
-void CGDebugInfo::EmitStopPoint(CGBuilderTy &Builder) {
if (CurLoc.isInvalid() || CurLoc.isMacroID()) return;
// Don't bother if things are the same as last time.
SourceManager &SM = CGM.getContext().getSourceManager();
- if (CurLoc == PrevLoc
- || (SM.getInstantiationLineNumber(CurLoc) ==
- SM.getInstantiationLineNumber(PrevLoc)
- && SM.isFromSameFile(CurLoc, PrevLoc)))
+ if (CurLoc == PrevLoc ||
+ SM.getExpansionLoc(CurLoc) == SM.getExpansionLoc(PrevLoc))
// New Builder may not be in sync with CGDebugInfo.
if (!Builder.getCurrentDebugLocation().isUnknown())
return;
-
+
// Update last state.
PrevLoc = CurLoc;
- llvm::MDNode *Scope = RegionStack.back();
+ llvm::MDNode *Scope = LexicalBlockStack.back();
Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(getLineNumber(CurLoc),
getColumnNumber(CurLoc),
Scope));
}
-/// UpdateLineDirectiveRegion - Update region stack only if #line directive
-/// has introduced scope change.
-void CGDebugInfo::UpdateLineDirectiveRegion(CGBuilderTy &Builder) {
- if (CurLoc.isInvalid() || CurLoc.isMacroID() ||
- PrevLoc.isInvalid() || PrevLoc.isMacroID())
- return;
- SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PCLoc = SM.getPresumedLoc(CurLoc);
- PresumedLoc PPLoc = SM.getPresumedLoc(PrevLoc);
-
- if (PCLoc.isInvalid() || PPLoc.isInvalid() ||
- !strcmp(PPLoc.getFilename(), PCLoc.getFilename()))
- return;
-
- // If #line directive stack is empty then we are entering a new scope.
- if (LineDirectiveFiles.empty()) {
- EmitRegionStart(Builder);
- LineDirectiveFiles.push_back(PCLoc.getFilename());
- return;
- }
-
- assert (RegionStack.size() >= LineDirectiveFiles.size()
- && "error handling #line regions!");
-
- bool SeenThisFile = false;
- // Chek if current file is already seen earlier.
- for(std::vector<const char *>::iterator I = LineDirectiveFiles.begin(),
- E = LineDirectiveFiles.end(); I != E; ++I)
- if (!strcmp(PCLoc.getFilename(), *I)) {
- SeenThisFile = true;
- break;
- }
+/// CreateLexicalBlock - Creates a new lexical block node and pushes it on
+/// the stack.
+void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) {
+ llvm::DIDescriptor D =
+ DBuilder.createLexicalBlock(LexicalBlockStack.empty() ?
+ llvm::DIDescriptor() :
+ llvm::DIDescriptor(LexicalBlockStack.back()),
+ getOrCreateFile(CurLoc),
+ getLineNumber(CurLoc),
+ getColumnNumber(CurLoc));
+ llvm::MDNode *DN = D;
+ LexicalBlockStack.push_back(DN);
+}
- // If #line for this file is seen earlier then pop out #line regions.
- if (SeenThisFile) {
- while (!LineDirectiveFiles.empty()) {
- const char *LastFile = LineDirectiveFiles.back();
- RegionStack.pop_back();
- LineDirectiveFiles.pop_back();
- if (!strcmp(PPLoc.getFilename(), LastFile))
- break;
- }
- return;
- }
+/// EmitLexicalBlockStart - Constructs the debug code for entering a declarative
+/// region - beginning of a DW_TAG_lexical_block.
+void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc) {
+ // Set our current location.
+ setLocation(Loc);
- // .. otherwise insert new #line region.
- EmitRegionStart(Builder);
- LineDirectiveFiles.push_back(PCLoc.getFilename());
+ // Create a new lexical block and push it on the stack.
+ CreateLexicalBlock(Loc);
- return;
-}
-/// EmitRegionStart- Constructs the debug code for entering a declarative
-/// region - "llvm.dbg.region.start.".
-void CGDebugInfo::EmitRegionStart(CGBuilderTy &Builder) {
- llvm::DIDescriptor D =
- DBuilder.createLexicalBlock(RegionStack.empty() ?
- llvm::DIDescriptor() :
- llvm::DIDescriptor(RegionStack.back()),
- getOrCreateFile(CurLoc),
- getLineNumber(CurLoc),
- getColumnNumber(CurLoc));
- llvm::MDNode *DN = D;
- RegionStack.push_back(DN);
+ // Emit a line table change for the current location inside the new scope.
+ Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(getLineNumber(Loc),
+ getColumnNumber(Loc),
+ LexicalBlockStack.back()));
}
-/// EmitRegionEnd - Constructs the debug code for exiting a declarative
-/// region - "llvm.dbg.region.end."
-void CGDebugInfo::EmitRegionEnd(CGBuilderTy &Builder) {
- assert(!RegionStack.empty() && "Region stack mismatch, stack empty!");
+/// EmitLexicalBlockEnd - Constructs the debug code for exiting a declarative
+/// region - end of a DW_TAG_lexical_block.
+void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc) {
+ assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
- // Provide an region stop point.
- EmitStopPoint(Builder);
+ // Provide an entry in the line table for the end of the block.
+ EmitLocation(Builder, Loc);
- RegionStack.pop_back();
+ LexicalBlockStack.pop_back();
}
/// EmitFunctionEnd - Constructs the debug code for exiting a function.
void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) {
- assert(!RegionStack.empty() && "Region stack mismatch, stack empty!");
+ assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
unsigned RCount = FnBeginRegionCount.back();
- assert(RCount <= RegionStack.size() && "Region stack mismatch");
+ assert(RCount <= LexicalBlockStack.size() && "Region stack mismatch");
// Pop all regions for this function.
- while (RegionStack.size() != RCount)
- EmitRegionEnd(Builder);
+ while (LexicalBlockStack.size() != RCount)
+ EmitLexicalBlockEnd(Builder, CurLoc);
FnBeginRegionCount.pop_back();
}
@@ -1849,7 +1887,7 @@ void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) {
llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
uint64_t *XOffset) {
- llvm::SmallVector<llvm::Value *, 5> EltTys;
+ SmallVector<llvm::Value *, 5> EltTys;
QualType FType;
uint64_t FieldSize, FieldOffset;
unsigned FieldAlign;
@@ -1876,7 +1914,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
CharUnits Align = CGM.getContext().getDeclAlign(VD);
if (Align > CGM.getContext().toCharUnitsFromBits(
- CGM.getContext().Target.getPointerAlign(0))) {
+ CGM.getContext().getTargetInfo().getPointerAlign(0))) {
CharUnits FieldOffsetInBytes
= CGM.getContext().toCharUnitsFromBits(FieldOffset);
CharUnits AlignedOffsetInBytes
@@ -1916,7 +1954,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
llvm::Value *Storage,
unsigned ArgNo, CGBuilderTy &Builder) {
- assert(!RegionStack.empty() && "Region stack mismatch, stack empty!");
+ assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
llvm::DIType Ty;
@@ -1940,7 +1978,8 @@ 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() || !Record->hasTrivialDestructor())
+ if (!Record->hasTrivialCopyConstructor() ||
+ !Record->hasTrivialDestructor())
Ty = DBuilder.createReferenceType(Ty);
}
}
@@ -1951,18 +1990,18 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
unsigned Flags = 0;
if (VD->isImplicit())
Flags |= llvm::DIDescriptor::FlagArtificial;
- llvm::MDNode *Scope = RegionStack.back();
+ llvm::MDNode *Scope = LexicalBlockStack.back();
- llvm::StringRef Name = VD->getName();
+ StringRef Name = VD->getName();
if (!Name.empty()) {
if (VD->hasAttr<BlocksAttr>()) {
CharUnits offset = CharUnits::fromQuantity(32);
- llvm::SmallVector<llvm::Value *, 9> addr;
- const llvm::Type *Int64Ty = llvm::Type::getInt64Ty(CGM.getLLVMContext());
+ SmallVector<llvm::Value *, 9> addr;
+ llvm::Type *Int64Ty = llvm::Type::getInt64Ty(CGM.getLLVMContext());
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
// offset of __forwarding field
offset = CGM.getContext().toCharUnitsFromBits(
- CGM.getContext().Target.getPointerWidth(0));
+ CGM.getContext().getTargetInfo().getPointerWidth(0));
addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
@@ -1973,14 +2012,14 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
// Create the descriptor for the variable.
llvm::DIVariable D =
DBuilder.createComplexVariable(Tag,
- llvm::DIDescriptor(RegionStack.back()),
+ llvm::DIDescriptor(Scope),
VD->getName(), Unit, Line, Ty,
addr, ArgNo);
// Insert an llvm.dbg.declare into the current block.
+ // 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;
}
@@ -1993,7 +2032,6 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
// 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;
}
@@ -2008,7 +2046,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
I != E; ++I) {
FieldDecl *Field = *I;
llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
- llvm::StringRef FieldName = Field->getName();
+ StringRef FieldName = Field->getName();
// Ignore unnamed fields. Do not ignore unnamed records.
if (FieldName.empty() && !isa<RecordType>(Field->getType()))
@@ -2024,7 +2062,6 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
// 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));
}
}
@@ -2040,7 +2077,7 @@ void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder,
const CGBlockInfo &blockInfo) {
- assert(!RegionStack.empty() && "Region stack mismatch, stack empty!");
+ assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
if (Builder.GetInsertBlock() == 0)
return;
@@ -2065,15 +2102,16 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
target.getStructLayout(blockInfo.StructureType)
->getElementOffset(blockInfo.getCapture(VD).getIndex()));
- llvm::SmallVector<llvm::Value *, 9> addr;
- const llvm::Type *Int64Ty = llvm::Type::getInt64Ty(CGM.getLLVMContext());
+ SmallVector<llvm::Value *, 9> addr;
+ llvm::Type *Int64Ty = llvm::Type::getInt64Ty(CGM.getLLVMContext());
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
if (isByRef) {
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
// offset of __forwarding field
- offset = CGM.getContext().toCharUnitsFromBits(target.getPointerSizeInBits());
+ offset = CGM.getContext()
+ .toCharUnitsFromBits(target.getPointerSizeInBits());
addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
@@ -2085,14 +2123,13 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
// Create the descriptor for the variable.
llvm::DIVariable D =
DBuilder.createComplexVariable(llvm::dwarf::DW_TAG_auto_variable,
- llvm::DIDescriptor(RegionStack.back()),
+ llvm::DIDescriptor(LexicalBlockStack.back()),
VD->getName(), Unit, Line, Ty, addr);
// Insert an llvm.dbg.declare into the current block.
- llvm::Instruction *Call =
+ llvm::Instruction *Call =
DBuilder.insertDeclare(Storage, D, Builder.GetInsertPoint());
-
- llvm::MDNode *Scope = RegionStack.back();
- Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
+ Call->setDebugLoc(llvm::DebugLoc::get(Line, Column,
+ LexicalBlockStack.back()));
}
/// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument
@@ -2131,7 +2168,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
const llvm::StructLayout *blockLayout =
CGM.getTargetData().getStructLayout(block.StructureType);
- llvm::SmallVector<llvm::Value*, 16> fields;
+ SmallVector<llvm::Value*, 16> fields;
fields.push_back(createFieldType("__isa", C.VoidPtrTy, 0, loc, AS_public,
blockLayout->getElementOffsetInBits(0),
tunit, tunit));
@@ -2154,7 +2191,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
// We want to sort the captures by offset, not because DWARF
// requires this, but because we're paranoid about debuggers.
- llvm::SmallVector<BlockLayoutChunk, 8> chunks;
+ SmallVector<BlockLayoutChunk, 8> chunks;
// 'this' capture.
if (blockDecl->capturesCXXThis()) {
@@ -2187,7 +2224,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
// Sort by offset.
llvm::array_pod_sort(chunks.begin(), chunks.end());
- for (llvm::SmallVectorImpl<BlockLayoutChunk>::iterator
+ for (SmallVectorImpl<BlockLayoutChunk>::iterator
i = chunks.begin(), e = chunks.end(); i != e; ++i) {
uint64_t offsetInBits = i->OffsetInBits;
const BlockDecl::Capture *capture = i->Capture;
@@ -2204,7 +2241,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
}
const VarDecl *variable = capture->getVariable();
- llvm::StringRef name = variable->getName();
+ StringRef name = variable->getName();
llvm::DIType fieldType;
if (capture->isByRef()) {
@@ -2239,8 +2276,8 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
// Get overall information about the block.
unsigned flags = llvm::DIDescriptor::FlagArtificial;
- llvm::MDNode *scope = RegionStack.back();
- llvm::StringRef name = ".block_descriptor";
+ llvm::MDNode *scope = LexicalBlockStack.back();
+ StringRef name = ".block_descriptor";
// Create the descriptor for the parameter.
llvm::DIVariable debugVar =
@@ -2265,6 +2302,8 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
llvm::DIFile Unit = getOrCreateFile(D->getLocation());
unsigned LineNo = getLineNumber(D->getLocation());
+ setLocation(D->getLocation());
+
QualType T = D->getType();
if (T->isIncompleteArrayType()) {
@@ -2277,13 +2316,13 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
T = CGM.getContext().getConstantArrayType(ET, ConstVal,
ArrayType::Normal, 0);
}
- llvm::StringRef DeclName = D->getName();
- llvm::StringRef LinkageName;
+ StringRef DeclName = D->getName();
+ StringRef LinkageName;
if (D->getDeclContext() && !isa<FunctionDecl>(D->getDeclContext())
&& !isa<ObjCMethodDecl>(D->getDeclContext()))
LinkageName = Var->getName();
if (LinkageName == DeclName)
- LinkageName = llvm::StringRef();
+ LinkageName = StringRef();
llvm::DIDescriptor DContext =
getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()));
DBuilder.createStaticVariable(DContext, DeclName, LinkageName,
@@ -2298,7 +2337,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
llvm::DIFile Unit = getOrCreateFile(ID->getLocation());
unsigned LineNo = getLineNumber(ID->getLocation());
- llvm::StringRef Name = ID->getName();
+ StringRef Name = ID->getName();
QualType T = CGM.getContext().getObjCInterfaceType(ID);
if (T->isIncompleteArrayType()) {
@@ -2323,7 +2362,7 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD,
llvm::Constant *Init) {
// Create the descriptor for the variable.
llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
- llvm::StringRef Name = VD->getName();
+ StringRef Name = VD->getName();
llvm::DIType Ty = getOrCreateType(VD->getType(), Unit);
if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(VD)) {
if (const EnumDecl *ED = dyn_cast<EnumDecl>(ECD->getDeclContext()))
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index f87d0072e323..a4533a83d579 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -56,21 +56,18 @@ class CGDebugInfo {
bool BlockLiteralGenericSet;
llvm::DIType BlockLiteralGeneric;
- std::vector<llvm::TrackingVH<llvm::MDNode> > RegionStack;
+ // LexicalBlockStack - Keep track of our current nested lexical block.
+ std::vector<llvm::TrackingVH<llvm::MDNode> > LexicalBlockStack;
llvm::DenseMap<const Decl *, llvm::WeakVH> RegionMap;
- // FnBeginRegionCount - Keep track of RegionStack counter at the beginning
- // of a function. This is used to pop unbalanced regions at the end of a
- // function.
+ // FnBeginRegionCount - Keep track of LexicalBlockStack counter at the
+ // beginning of a function. This is used to pop unbalanced regions at
+ // the end of a function.
std::vector<unsigned> FnBeginRegionCount;
- /// LineDirectiveFiles - This stack is used to keep track of
- /// scopes introduced by #line directives.
- std::vector<const char *> LineDirectiveFiles;
-
/// DebugInfoNames - This is a storage for names that are
/// constructed on demand. For example, C++ destructors, C++ operators etc..
llvm::BumpPtrAllocator DebugInfoNames;
- llvm::StringRef CWDName;
+ StringRef CWDName;
llvm::DenseMap<const char *, llvm::WeakVH> DIFileCache;
llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache;
@@ -95,6 +92,7 @@ class CGDebugInfo {
llvm::DIType CreateType(const LValueReferenceType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const RValueReferenceType *Ty, llvm::DIFile Unit);
llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DIFile F);
+ llvm::DIType CreateType(const AtomicType *Ty, llvm::DIFile F);
llvm::DIType CreateEnumType(const EnumDecl *ED);
llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method,
llvm::DIFile F);
@@ -113,17 +111,17 @@ class CGDebugInfo {
void CollectCXXMemberFunctions(const CXXRecordDecl *Decl,
llvm::DIFile F,
- llvm::SmallVectorImpl<llvm::Value *> &E,
+ SmallVectorImpl<llvm::Value *> &E,
llvm::DIType T);
void CollectCXXFriends(const CXXRecordDecl *Decl,
llvm::DIFile F,
- llvm::SmallVectorImpl<llvm::Value *> &EltTys,
+ SmallVectorImpl<llvm::Value *> &EltTys,
llvm::DIType RecordTy);
void CollectCXXBases(const CXXRecordDecl *Decl,
llvm::DIFile F,
- llvm::SmallVectorImpl<llvm::Value *> &EltTys,
+ SmallVectorImpl<llvm::Value *> &EltTys,
llvm::DIType RecordTy);
llvm::DIArray
@@ -136,30 +134,35 @@ class CGDebugInfo {
CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TS,
llvm::DIFile F);
- llvm::DIType createFieldType(llvm::StringRef name, QualType type,
- Expr *bitWidth, SourceLocation loc,
+ llvm::DIType createFieldType(StringRef name, QualType type,
+ uint64_t sizeInBitsOverride, SourceLocation loc,
AccessSpecifier AS, uint64_t offsetInBits,
llvm::DIFile tunit,
llvm::DIDescriptor scope);
void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F,
- llvm::SmallVectorImpl<llvm::Value *> &E,
+ SmallVectorImpl<llvm::Value *> &E,
llvm::DIType RecordTy);
void CollectVTableInfo(const CXXRecordDecl *Decl,
llvm::DIFile F,
- llvm::SmallVectorImpl<llvm::Value *> &EltTys);
+ SmallVectorImpl<llvm::Value *> &EltTys);
+ // CreateLexicalBlock - Create a new lexical block node and push it on
+ // the stack.
+ void CreateLexicalBlock(SourceLocation Loc);
+
public:
CGDebugInfo(CodeGenModule &CGM);
~CGDebugInfo();
+ void finalize() { DBuilder.finalize(); }
/// setLocation - Update the current source location. If \arg loc is
/// invalid it is ignored.
void setLocation(SourceLocation Loc);
- /// EmitStopPoint - Emit a call to llvm.dbg.stoppoint to indicate a change of
- /// source line.
- void EmitStopPoint(CGBuilderTy &Builder);
+ /// EmitLocation - Emit metadata to indicate a change in line/column
+ /// information in the source file.
+ void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc);
/// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate
/// start of a new function.
@@ -169,21 +172,17 @@ public:
/// EmitFunctionEnd - Constructs the debug code for exiting a function.
void EmitFunctionEnd(CGBuilderTy &Builder);
- /// UpdateLineDirectiveRegion - Update region stack only if #line directive
- /// has introduced scope change.
- void UpdateLineDirectiveRegion(CGBuilderTy &Builder);
-
/// UpdateCompletedType - Update type cache because the type is now
/// translated.
void UpdateCompletedType(const TagDecl *TD);
- /// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start
- /// of a new block.
- void EmitRegionStart(CGBuilderTy &Builder);
+ /// EmitLexicalBlockStart - Emit metadata to indicate the beginning of a
+ /// new lexical block and push the block onto the stack.
+ void EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc);
- /// EmitRegionEnd - Emit call to llvm.dbg.region.end to indicate end of a
- /// block.
- void EmitRegionEnd(CGBuilderTy &Builder);
+ /// EmitLexicalBlockEnd - Emit metadata to indicate the end of a new lexical
+ /// block and pop the current block.
+ void EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc);
/// EmitDeclareOfAutoVariable - Emit call to llvm.dbg.declare for an automatic
/// variable declaration.
@@ -234,7 +233,7 @@ private:
llvm::DIDescriptor getContextDescriptor(const Decl *Decl);
/// getCurrentDirname - Return current directory name.
- llvm::StringRef getCurrentDirname();
+ StringRef getCurrentDirname();
/// CreateCompileUnit - Create new compile unit.
void CreateCompileUnit();
@@ -255,7 +254,7 @@ private:
/// CreateMemberType - Create new member and increase Offset by FType's size.
llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType,
- llvm::StringRef Name, uint64_t *Offset);
+ StringRef Name, uint64_t *Offset);
/// getFunctionDeclaration - Return debug info descriptor to describe method
/// declaration for the given method definition.
@@ -264,21 +263,21 @@ private:
/// 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.
- llvm::StringRef getFunctionName(const FunctionDecl *FD);
+ StringRef getFunctionName(const FunctionDecl *FD);
/// getObjCMethodName - Returns the unmangled name of an Objective-C method.
/// This is the display name for the debugging info.
- llvm::StringRef getObjCMethodName(const ObjCMethodDecl *FD);
+ StringRef getObjCMethodName(const ObjCMethodDecl *FD);
/// getSelectorName - Return selector name. This is used for debugging
/// info.
- llvm::StringRef getSelectorName(Selector S);
+ StringRef getSelectorName(Selector S);
/// getClassName - Get class name including template argument list.
- llvm::StringRef getClassName(RecordDecl *RD);
+ StringRef getClassName(RecordDecl *RD);
/// getVTableName - Get vtable name for the given Class.
- llvm::StringRef getVTableName(const CXXRecordDecl *Decl);
+ StringRef getVTableName(const CXXRecordDecl *Decl);
/// getLineNumber - Get line number for the location. If location is invalid
/// then use current location.
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 62c3a9791d0f..a6147ea7658b 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -14,6 +14,7 @@
#include "CGDebugInfo.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
+#include "CGOpenCLRuntime.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
@@ -46,7 +47,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::Field:
case Decl::IndirectField:
case Decl::ObjCIvar:
- case Decl::ObjCAtDefsField:
+ case Decl::ObjCAtDefsField:
case Decl::ParmVar:
case Decl::ImplicitParam:
case Decl::ClassTemplate:
@@ -70,7 +71,8 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::Friend:
case Decl::FriendTemplate:
case Decl::Block:
- assert(0 && "Declaration should not be in declstmts!");
+ case Decl::ClassScopeFunctionSpecialization:
+ llvm_unreachable("Declaration should not be in declstmts!");
case Decl::Function: // void X();
case Decl::Record: // struct/union/class X;
case Decl::Enum: // enum X;
@@ -112,7 +114,7 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) {
case SC_Register:
return EmitAutoVarDecl(D);
case SC_Static: {
- llvm::GlobalValue::LinkageTypes Linkage =
+ llvm::GlobalValue::LinkageTypes Linkage =
llvm::GlobalValue::InternalLinkage;
// If the function definition has some sort of weak linkage, its
@@ -123,26 +125,28 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) {
if (getContext().getLangOptions().CPlusPlus)
if (llvm::GlobalValue::isWeakForLinker(CurFn->getLinkage()))
Linkage = CurFn->getLinkage();
-
+
return EmitStaticVarDecl(D, Linkage);
}
case SC_Extern:
case SC_PrivateExtern:
// Don't emit it now, allow it to be emitted lazily on its first use.
return;
+ case SC_OpenCLWorkGroupLocal:
+ return CGM.getOpenCLRuntime().EmitWorkGroupLocalVarDecl(*this, D);
}
- assert(0 && "Unknown storage class");
+ llvm_unreachable("Unknown storage class");
}
static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D,
const char *Separator) {
CodeGenModule &CGM = CGF.CGM;
if (CGF.getContext().getLangOptions().CPlusPlus) {
- llvm::StringRef Name = CGM.getMangledName(&D);
+ StringRef Name = CGM.getMangledName(&D);
return Name.str();
}
-
+
std::string ContextName;
if (!CGF.CurFuncDecl) {
// Better be in a block declared in global scope.
@@ -154,15 +158,15 @@ static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D,
ContextName = Name.getString();
}
else
- assert(0 && "Unknown context for block static var decl");
+ llvm_unreachable("Unknown context for block static var decl");
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CGF.CurFuncDecl)) {
- llvm::StringRef Name = CGM.getMangledName(FD);
+ StringRef Name = CGM.getMangledName(FD);
ContextName = Name.str();
} else if (isa<ObjCMethodDecl>(CGF.CurFuncDecl))
ContextName = CGF.CurFn->getName();
else
- assert(0 && "Unknown context for static var decl");
-
+ llvm_unreachable("Unknown context for static var decl");
+
return ContextName + Separator + D.getNameAsString();
}
@@ -175,7 +179,7 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
std::string Name = GetStaticDeclName(*this, D, Separator);
- const llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty);
+ llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty);
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), LTy,
Ty.isConstant(getContext()), Linkage,
@@ -203,7 +207,7 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
if (!getContext().getLangOptions().CPlusPlus)
CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
else if (Builder.GetInsertBlock()) {
- // Since we have a static initializer, this global variable can't
+ // Since we have a static initializer, this global variable can't
// be constant.
GV->setConstant(false);
@@ -218,7 +222,7 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
// in the LLVM type system.)
if (GV->getType()->getElementType() != Init->getType()) {
llvm::GlobalVariable *OldGV = GV;
-
+
GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(),
OldGV->isConstant(),
OldGV->getLinkage(), Init, "",
@@ -226,19 +230,19 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
D.isThreadSpecified(),
CGM.getContext().getTargetAddressSpace(D.getType()));
GV->setVisibility(OldGV->getVisibility());
-
+
// Steal the name of the old global
GV->takeName(OldGV);
-
+
// Replace all uses of the old global with the new global
llvm::Constant *NewPtrForOldDecl =
llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
OldGV->replaceAllUsesWith(NewPtrForOldDecl);
-
+
// Erase the old global, since it is no longer used.
OldGV->eraseFromParent();
}
-
+
GV->setInitializer(Init);
return GV;
}
@@ -259,7 +263,7 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
// Make sure to evaluate VLA bounds now so that we have them for later.
if (D.getType()->isVariablyModifiedType())
EmitVariablyModifiedType(D.getType());
-
+
// Local static block variables must be treated as globals as they may be
// referenced in their RHS initializer block-literal expresion.
CGM.setStaticLocalDeclAddress(&D, GV);
@@ -270,14 +274,8 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
- // FIXME: Merge attribute handling.
- if (const AnnotateAttr *AA = D.getAttr<AnnotateAttr>()) {
- SourceManager &SM = CGM.getContext().getSourceManager();
- llvm::Constant *Ann =
- CGM.EmitAnnotateAttr(GV, AA,
- SM.getInstantiationLineNumber(D.getLocation()));
- CGM.AddAnnotation(Ann);
- }
+ if (D.hasAttr<AnnotateAttr>())
+ CGM.AddGlobalAnnotations(&D, GV);
if (const SectionAttr *SA = D.getAttr<SectionAttr>())
GV->setSection(SA->getName());
@@ -290,8 +288,8 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
//
// FIXME: It is really dangerous to store this in the map; if anyone
// RAUW's the GV uses of this constant will be invalid.
- const llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(D.getType());
- const llvm::Type *LPtrTy =
+ llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(D.getType());
+ llvm::Type *LPtrTy =
LTy->getPointerTo(CGM.getContext().getTargetAddressSpace(D.getType()));
DMEntry = llvm::ConstantExpr::getBitCast(GV, LPtrTy);
@@ -348,7 +346,7 @@ namespace {
CGF.Builder.CreateCondBr(DidNRVO, SkipDtorBB, RunDtorBB);
CGF.EmitBlock(RunDtorBB);
}
-
+
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
/*ForVirtualBase=*/false, Loc);
@@ -360,7 +358,7 @@ namespace {
llvm::Value *Stack;
CallStackRestore(llvm::Value *Stack) : Stack(Stack) {}
void Emit(CodeGenFunction &CGF, Flags flags) {
- llvm::Value *V = CGF.Builder.CreateLoad(Stack, "tmp");
+ llvm::Value *V = CGF.Builder.CreateLoad(Stack);
llvm::Value *F = CGF.CGM.getIntrinsic(llvm::Intrinsic::stackrestore);
CGF.Builder.CreateCall(F, V);
}
@@ -384,7 +382,7 @@ namespace {
llvm::Constant *CleanupFn;
const CGFunctionInfo &FnInfo;
const VarDecl &Var;
-
+
CallCleanupFunction(llvm::Constant *CleanupFn, const CGFunctionInfo *Info,
const VarDecl *Var)
: CleanupFn(CleanupFn), FnInfo(*Info), Var(*Var) {}
@@ -441,7 +439,7 @@ static void EmitAutoVarWithLifetime(CodeGenFunction &CGF, const VarDecl &var,
case Qualifiers::OCL_Autoreleasing:
// nothing to do
break;
-
+
case Qualifiers::OCL_Weak:
// __weak objects always get EH cleanups; otherwise, exceptions
// could cause really nasty crashes instead of mere leaks.
@@ -508,7 +506,7 @@ void CodeGenFunction::EmitScalarInit(const Expr *init,
// actually perform the initialization with an assign.
bool accessedByInit = false;
if (lifetime != Qualifiers::OCL_ExplicitNone)
- accessedByInit = isAccessedBy(D, init);
+ accessedByInit = (capturedByInit || isAccessedBy(D, init));
if (accessedByInit) {
LValue tempLV = lvalue;
// Drill down to the __block object if necessary.
@@ -519,12 +517,12 @@ void CodeGenFunction::EmitScalarInit(const Expr *init,
getByRefValueLLVMField(cast<VarDecl>(D))));
}
- const llvm::PointerType *ty
+ llvm::PointerType *ty
= cast<llvm::PointerType>(tempLV.getAddress()->getType());
ty = cast<llvm::PointerType>(ty->getElementType());
llvm::Value *zero = llvm::ConstantPointerNull::get(ty);
-
+
// If __weak, we want to use a barrier under certain conditions.
if (lifetime == Qualifiers::OCL_Weak)
EmitARCInitWeak(tempLV.getAddress(), zero);
@@ -613,7 +611,7 @@ void CodeGenFunction::EmitScalarInit(llvm::Value *init, LValue lvalue) {
break;
}
- EmitStoreOfScalar(init, lvalue);
+ EmitStoreOfScalar(init, lvalue);
}
/// canEmitInitWithFewStoresAfterMemset - Decide whether we can emit the
@@ -640,7 +638,7 @@ static bool canEmitInitWithFewStoresAfterMemset(llvm::Constant *Init,
}
return true;
}
-
+
// Anything else is hard and scary.
return false;
}
@@ -655,7 +653,7 @@ static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc,
isa<llvm::ConstantPointerNull>(Init) ||
isa<llvm::UndefValue>(Init))
return;
-
+
if (isa<llvm::ConstantInt>(Init) || isa<llvm::ConstantFP>(Init) ||
isa<llvm::ConstantVector>(Init) || isa<llvm::BlockAddress>(Init) ||
isa<llvm::ConstantExpr>(Init)) {
@@ -663,14 +661,14 @@ static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc,
Builder.CreateStore(Init, Loc, isVolatile);
return;
}
-
+
assert((isa<llvm::ConstantStruct>(Init) || isa<llvm::ConstantArray>(Init)) &&
"Unknown value type!");
-
+
for (unsigned i = 0, e = Init->getNumOperands(); i != e; ++i) {
llvm::Constant *Elt = cast<llvm::Constant>(Init->getOperand(i));
if (Elt->isNullValue()) continue;
-
+
// Otherwise, get a pointer to the element and emit it.
emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i),
isVolatile, Builder);
@@ -694,8 +692,8 @@ static bool shouldUseMemSetPlusStoresToInitialize(llvm::Constant *Init,
// plopping in more stores.
unsigned StoreBudget = 6;
uint64_t SizeLimit = 32;
-
- return GlobalSize > SizeLimit &&
+
+ return GlobalSize > SizeLimit &&
canEmitInitWithFewStoresAfterMemset(Init, StoreBudget);
}
@@ -730,7 +728,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
llvm::Value *DeclPtr;
if (Ty->isConstantSizeType()) {
if (!Target.useGlobalsForAutomaticVariables()) {
- bool NRVO = getContext().getLangOptions().ElideConstructors &&
+ bool NRVO = getContext().getLangOptions().ElideConstructors &&
D.isNRVOVariable();
// If this value is a POD array or struct with a statically
@@ -740,7 +738,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
// arrays as long as the initialization is trivial (e.g. if they
// have a non-trivial destructor, but not a non-trivial constructor).
if (D.getInit() &&
- (Ty->isArrayType() || Ty->isRecordType()) &&
+ (Ty->isArrayType() || Ty->isRecordType()) &&
(Ty.isPODType(getContext()) ||
getContext().getBaseElementType(Ty)->isObjCObjectPointerType()) &&
D.getInit()->isConstantInitializer(getContext(), false)) {
@@ -759,27 +757,27 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
// Otherwise, tell the initialization code that we're in this case.
emission.IsConstantAggregate = true;
}
-
+
// A normal fixed sized variable becomes an alloca in the entry block,
// unless it's an NRVO variable.
- const llvm::Type *LTy = ConvertTypeForMem(Ty);
-
+ 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
+ // 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;
@@ -788,13 +786,13 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
} else {
if (isByRef)
LTy = BuildByRefType(&D);
-
+
llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
Alloc->setName(D.getNameAsString());
CharUnits allocaAlignment = alignment;
if (isByRef)
- allocaAlignment = std::max(allocaAlignment,
+ allocaAlignment = std::max(allocaAlignment,
getContext().toCharUnitsFromBits(Target.getPointerAlign(0)));
Alloc->setAlignment(allocaAlignment.getQuantity());
DeclPtr = Alloc;
@@ -829,7 +827,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
QualType elementType;
llvm::tie(elementCount, elementType) = getVLASize(Ty);
- const llvm::Type *llvmTy = ConvertTypeForMem(elementType);
+ llvm::Type *llvmTy = ConvertTypeForMem(elementType);
// Allocate memory for the array.
llvm::AllocaInst *vla = Builder.CreateAlloca(llvmTy, elementCount, "vla");
@@ -853,6 +851,9 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder);
}
+ if (D.hasAttr<AnnotateAttr>())
+ EmitVarAnnotations(&D, emission.Address);
+
return emission;
}
@@ -875,6 +876,32 @@ static bool isCapturedBy(const VarDecl &var, const Expr *e) {
return false;
}
+ if (const StmtExpr *SE = dyn_cast<StmtExpr>(e)) {
+ const CompoundStmt *CS = SE->getSubStmt();
+ for (CompoundStmt::const_body_iterator BI = CS->body_begin(),
+ BE = CS->body_end(); BI != BE; ++BI)
+ if (Expr *E = dyn_cast<Expr>((*BI))) {
+ if (isCapturedBy(var, E))
+ return true;
+ }
+ else if (DeclStmt *DS = dyn_cast<DeclStmt>((*BI))) {
+ // special case declarations
+ for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
+ I != E; ++I) {
+ if (VarDecl *VD = dyn_cast<VarDecl>((*I))) {
+ Expr *Init = VD->getInit();
+ if (Init && isCapturedBy(var, Init))
+ return true;
+ }
+ }
+ }
+ else
+ // FIXME. Make safe assumption assuming arbitrary statements cause capturing.
+ // Later, provide code to poke into statements for capture analysis.
+ return true;
+ return false;
+ }
+
for (Stmt::const_child_range children = e->children(); children; ++children)
if (isCapturedBy(var, cast<Expr>(*children)))
return true;
@@ -887,14 +914,14 @@ static bool isCapturedBy(const VarDecl &var, const Expr *e) {
static bool isTrivialInitializer(const Expr *Init) {
if (!Init)
return true;
-
+
if (const CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init))
if (CXXConstructorDecl *Constructor = Construct->getConstructor())
if (Constructor->isTrivial() &&
Constructor->isDefaultConstructor() &&
!Construct->requiresZeroInitialization())
return true;
-
+
return false;
}
void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
@@ -922,7 +949,6 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
if (isTrivialInitializer(Init))
return;
-
CharUnits alignment = emission.Alignment;
@@ -950,16 +976,16 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
assert(constant != 0 && "Wasn't a simple constant init?");
llvm::Value *SizeVal =
- llvm::ConstantInt::get(IntPtrTy,
+ llvm::ConstantInt::get(IntPtrTy,
getContext().getTypeSizeInChars(type).getQuantity());
- const llvm::Type *BP = Int8PtrTy;
+ llvm::Type *BP = Int8PtrTy;
if (Loc->getType() != BP)
- Loc = Builder.CreateBitCast(Loc, BP, "tmp");
+ Loc = Builder.CreateBitCast(Loc, BP);
// If the initializer is all or mostly zeros, codegen with memset then do
// a few stores afterward.
- if (shouldUseMemSetPlusStoresToInitialize(constant,
+ if (shouldUseMemSetPlusStoresToInitialize(constant,
CGM.getTargetData().getTypeAllocSize(constant->getType()))) {
Builder.CreateMemSet(Loc, llvm::ConstantInt::get(Int8Ty, 0), SizeVal,
alignment.getQuantity(), isVolatile);
@@ -968,19 +994,19 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
emitStoresForInitAfterMemset(constant, Loc, isVolatile, Builder);
}
} else {
- // Otherwise, create a temporary global with the initializer then
+ // Otherwise, create a temporary global with the initializer then
// memcpy from the global to the alloca.
std::string Name = GetStaticDeclName(*this, D, ".");
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), constant->getType(), true,
- llvm::GlobalValue::InternalLinkage,
+ llvm::GlobalValue::PrivateLinkage,
constant, Name, 0, false, 0);
GV->setAlignment(alignment.getQuantity());
GV->setUnnamedAddr(true);
-
+
llvm::Value *SrcPtr = GV;
if (SrcPtr->getType() != BP)
- SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp");
+ SrcPtr = Builder.CreateBitCast(SrcPtr, BP);
Builder.CreateMemCpy(Loc, SrcPtr, SizeVal, alignment.getQuantity(),
isVolatile);
@@ -1007,7 +1033,7 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init,
if (type->isReferenceType()) {
RValue rvalue = EmitReferenceBindingToExpr(init, D);
- if (capturedByInit)
+ if (capturedByInit)
drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
EmitStoreThroughLValue(rvalue, lvalue);
} else if (!hasAggregateLLVMType(type)) {
@@ -1019,7 +1045,10 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init,
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, true, false));
+ EmitAggExpr(init, AggValueSlot::forLValue(lvalue,
+ AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased));
}
}
@@ -1058,7 +1087,7 @@ void CodeGenFunction::emitAutoVarTypeCleanup(
case QualType::DK_objc_strong_lifetime:
// Suppress cleanups for pseudo-strong variables.
if (var->isARCPseudoStrong()) return;
-
+
// Otherwise, consider whether to use an EH cleanup or not.
cleanupKind = getARCCleanupKind();
@@ -1094,7 +1123,7 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
emitAutoVarTypeCleanup(emission, dtorKind);
// In GC mode, honor objc_precise_lifetime.
- if (getLangOptions().getGCMode() != LangOptions::NonGC &&
+ if (getLangOptions().getGC() != LangOptions::NonGC &&
D.hasAttr<ObjCPreciseLifetimeAttr>()) {
EHStack.pushCleanup<ExtendGCLifetime>(NormalCleanup, &D);
}
@@ -1267,11 +1296,9 @@ static void emitPartialArrayDestroy(CodeGenFunction &CGF,
if (arrayDepth) {
llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, arrayDepth+1);
- llvm::SmallVector<llvm::Value*,4> gepIndices(arrayDepth, zero);
- begin = CGF.Builder.CreateInBoundsGEP(begin, gepIndices.begin(),
- gepIndices.end(), "pad.arraybegin");
- end = CGF.Builder.CreateInBoundsGEP(end, gepIndices.begin(),
- gepIndices.end(), "pad.arrayend");
+ SmallVector<llvm::Value*,4> gepIndices(arrayDepth, zero);
+ begin = CGF.Builder.CreateInBoundsGEP(begin, gepIndices, "pad.arraybegin");
+ end = CGF.Builder.CreateInBoundsGEP(end, gepIndices, "pad.arrayend");
}
// Destroy the array. We don't ever need an EH cleanup because we
@@ -1330,7 +1357,7 @@ namespace {
/// pushIrregularPartialArrayCleanup - Push an EH cleanup to destroy
/// already-constructed elements of the given array. The cleanup
/// may be popped with DeactivateCleanupBlock or PopCleanupBlock.
-///
+///
/// \param elementType - the immediate element type of the array;
/// possibly still an array type
/// \param array - a value of type elementType*
@@ -1349,7 +1376,7 @@ void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
/// pushRegularPartialArrayCleanup - Push an EH cleanup to destroy
/// already-constructed elements of the given array. The cleanup
/// may be popped with DeactivateCleanupBlock or PopCleanupBlock.
-///
+///
/// \param elementType - the immediate element type of the array;
/// possibly still an array type
/// \param array - a value of type elementType*
@@ -1476,4 +1503,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
// Emit debug info for param declaration.
if (CGDebugInfo *DI = getDebugInfo())
DI->EmitDeclareOfArgVariable(&D, DeclPtr, ArgNo, Builder);
+
+ if (D.hasAttr<AnnotateAttr>())
+ EmitVarAnnotations(&D, DeclPtr);
}
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 0ae6a3d2ee90..3b8f830278b2 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -46,7 +46,9 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
} else if (type->isAnyComplexType()) {
CGF.EmitComplexExprIntoAddr(Init, DeclPtr, lv.isVolatile());
} else {
- CGF.EmitAggExpr(Init, AggValueSlot::forLValue(lv, true));
+ CGF.EmitAggExpr(Init, AggValueSlot::forLValue(lv,AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased));
}
}
@@ -126,17 +128,16 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
}
// Get the destructor function type
- llvm::Type *ArgTys[] = { Int8PtrTy };
llvm::Type *DtorFnTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()),
- ArgTys, false);
+ Int8PtrTy, false);
DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy);
llvm::Type *Params[] = { DtorFnTy, Int8PtrTy, Int8PtrTy };
// Get the __cxa_atexit function type
// extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d );
- const llvm::FunctionType *AtExitFnTy =
+ llvm::FunctionType *AtExitFnTy =
llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false);
llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy,
@@ -167,15 +168,15 @@ void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
static llvm::Function *
CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
- const llvm::FunctionType *FTy,
- llvm::StringRef Name) {
+ llvm::FunctionType *FTy,
+ StringRef Name) {
llvm::Function *Fn =
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
Name, &CGM.getModule());
if (!CGM.getContext().getLangOptions().AppleKext) {
// Set the section if needed.
if (const char *Section =
- CGM.getContext().Target.getStaticInitSectionSpecifier())
+ CGM.getContext().getTargetInfo().getStaticInitSectionSpecifier())
Fn->setSection(Section);
}
@@ -188,7 +189,7 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
void
CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
llvm::GlobalVariable *Addr) {
- const llvm::FunctionType *FTy
+ llvm::FunctionType *FTy
= llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
false);
@@ -225,7 +226,7 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
if (CXXGlobalInits.empty() && PrioritizedCXXGlobalInits.empty())
return;
- const llvm::FunctionType *FTy
+ llvm::FunctionType *FTy
= llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
false);
@@ -234,7 +235,7 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
CreateGlobalInitOrDestructFunction(*this, FTy, "_GLOBAL__I_a");
if (!PrioritizedCXXGlobalInits.empty()) {
- llvm::SmallVector<llvm::Constant*, 8> LocalCXXGlobalInits;
+ SmallVector<llvm::Constant*, 8> LocalCXXGlobalInits;
llvm::array_pod_sort(PrioritizedCXXGlobalInits.begin(),
PrioritizedCXXGlobalInits.end());
for (unsigned i = 0; i < PrioritizedCXXGlobalInits.size(); i++) {
@@ -259,7 +260,7 @@ void CodeGenModule::EmitCXXGlobalDtorFunc() {
if (CXXGlobalDtors.empty())
return;
- const llvm::FunctionType *FTy
+ llvm::FunctionType *FTy
= llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
false);
@@ -351,7 +352,7 @@ CodeGenFunction::generateDestroyHelper(llvm::Constant *addr,
const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(getContext().VoidTy, args,
FunctionType::ExtInfo());
- const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
+ llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
llvm::Function *fn =
CreateGlobalInitOrDestructFunction(CGM, FTy, "__cxx_global_array_dtor");
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 418bea6ee402..5e4fb9881937 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -29,9 +29,8 @@ using namespace CodeGen;
static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) {
// void *__cxa_allocate_exception(size_t thrown_size);
- llvm::Type *ArgTys[] = { CGF.SizeTy };
- const llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.Int8PtrTy, ArgTys, /*IsVarArgs=*/false);
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGF.Int8PtrTy, CGF.SizeTy, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception");
}
@@ -39,9 +38,8 @@ static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) {
static llvm::Constant *getFreeExceptionFn(CodeGenFunction &CGF) {
// void __cxa_free_exception(void *thrown_exception);
- llvm::Type *ArgTys[] = { CGF.Int8PtrTy };
- const llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.VoidTy, ArgTys, /*IsVarArgs=*/false);
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGF.VoidTy, CGF.Int8PtrTy, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception");
}
@@ -51,7 +49,7 @@ static llvm::Constant *getThrowFn(CodeGenFunction &CGF) {
// void (*dest) (void *));
llvm::Type *Args[3] = { CGF.Int8PtrTy, CGF.Int8PtrTy, CGF.Int8PtrTy };
- const llvm::FunctionType *FTy =
+ llvm::FunctionType *FTy =
llvm::FunctionType::get(CGF.VoidTy, Args, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw");
@@ -60,7 +58,7 @@ static llvm::Constant *getThrowFn(CodeGenFunction &CGF) {
static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) {
// void __cxa_rethrow();
- const llvm::FunctionType *FTy =
+ llvm::FunctionType *FTy =
llvm::FunctionType::get(CGF.VoidTy, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow");
@@ -69,9 +67,8 @@ static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) {
static llvm::Constant *getGetExceptionPtrFn(CodeGenFunction &CGF) {
// void *__cxa_get_exception_ptr(void*);
- llvm::Type *ArgTys[] = { CGF.Int8PtrTy };
- const llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.Int8PtrTy, ArgTys, /*IsVarArgs=*/false);
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrTy, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_get_exception_ptr");
}
@@ -79,9 +76,8 @@ static llvm::Constant *getGetExceptionPtrFn(CodeGenFunction &CGF) {
static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) {
// void *__cxa_begin_catch(void*);
- llvm::Type *ArgTys[] = { CGF.Int8PtrTy };
- const llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.Int8PtrTy, ArgTys, /*IsVarArgs=*/false);
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrTy, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");
}
@@ -89,7 +85,7 @@ static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) {
static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) {
// void __cxa_end_catch();
- const llvm::FunctionType *FTy =
+ llvm::FunctionType *FTy =
llvm::FunctionType::get(CGF.VoidTy, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
@@ -98,17 +94,15 @@ static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) {
static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) {
// void __cxa_call_unexepcted(void *thrown_exception);
- llvm::Type *ArgTys[] = { CGF.Int8PtrTy };
- const llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.VoidTy, ArgTys, /*IsVarArgs=*/false);
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGF.VoidTy, CGF.Int8PtrTy, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
}
llvm::Constant *CodeGenFunction::getUnwindResumeFn() {
- llvm::Type *ArgTys[] = { Int8PtrTy };
- const llvm::FunctionType *FTy =
- llvm::FunctionType::get(VoidTy, ArgTys, /*IsVarArgs=*/false);
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(VoidTy, Int8PtrTy, /*IsVarArgs=*/false);
if (CGM.getLangOptions().SjLjExceptions)
return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
@@ -116,9 +110,8 @@ llvm::Constant *CodeGenFunction::getUnwindResumeFn() {
}
llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() {
- llvm::Type *ArgTys[] = { Int8PtrTy };
- const llvm::FunctionType *FTy =
- llvm::FunctionType::get(VoidTy, ArgTys, /*IsVarArgs=*/false);
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(VoidTy, Int8PtrTy, /*IsVarArgs=*/false);
if (CGM.getLangOptions().SjLjExceptions)
return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume_or_Rethrow");
@@ -128,10 +121,10 @@ llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() {
static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
// void __terminate();
- const llvm::FunctionType *FTy =
+ llvm::FunctionType *FTy =
llvm::FunctionType::get(CGF.VoidTy, /*IsVarArgs=*/false);
- llvm::StringRef name;
+ StringRef name;
// In C++, use std::terminate().
if (CGF.getLangOptions().CPlusPlus)
@@ -145,10 +138,9 @@ static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
}
static llvm::Constant *getCatchallRethrowFn(CodeGenFunction &CGF,
- llvm::StringRef Name) {
- llvm::Type *ArgTys[] = { CGF.Int8PtrTy };
- const llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.VoidTy, ArgTys, /*IsVarArgs=*/false);
+ StringRef Name) {
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGF.VoidTy, CGF.Int8PtrTy, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, Name);
}
@@ -247,21 +239,34 @@ static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) {
continue;
}
- // Otherwise, it has to be a selector call.
- if (!isa<llvm::EHSelectorInst>(User)) return false;
+ // Otherwise, it has to be a landingpad instruction.
+ llvm::LandingPadInst *LPI = dyn_cast<llvm::LandingPadInst>(User);
+ if (!LPI) return false;
- llvm::EHSelectorInst *Selector = cast<llvm::EHSelectorInst>(User);
- for (unsigned I = 2, E = Selector->getNumArgOperands(); I != E; ++I) {
+ for (unsigned I = 0, E = LPI->getNumClauses(); I != E; ++I) {
// Look for something that would've been returned by the ObjC
// runtime's GetEHType() method.
- llvm::GlobalVariable *GV
- = dyn_cast<llvm::GlobalVariable>(Selector->getArgOperand(I));
- if (!GV) continue;
-
- // ObjC EH selector entries are always global variables with
- // names starting like this.
- if (GV->getName().startswith("OBJC_EHTYPE"))
- return false;
+ llvm::Value *Val = LPI->getClause(I)->stripPointerCasts();
+ if (LPI->isCatch(I)) {
+ // Check if the catch value has the ObjC prefix.
+ if (llvm::GlobalVariable *GV = dyn_cast<llvm::GlobalVariable>(Val))
+ // ObjC EH selector entries are always global variables with
+ // names starting like this.
+ if (GV->getName().startswith("OBJC_EHTYPE"))
+ return false;
+ } else {
+ // Check if any of the filter values have the ObjC prefix.
+ llvm::Constant *CVal = cast<llvm::Constant>(Val);
+ for (llvm::User::op_iterator
+ II = CVal->op_begin(), IE = CVal->op_end(); II != IE; ++II) {
+ if (llvm::GlobalVariable *GV =
+ cast<llvm::GlobalVariable>((*II)->stripPointerCasts()))
+ // ObjC EH selector entries are always global variables with
+ // names starting like this.
+ if (GV->getName().startswith("OBJC_EHTYPE"))
+ return false;
+ }
+ }
}
}
@@ -274,7 +279,7 @@ static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) {
/// when it really needs it.
void CodeGenModule::SimplifyPersonality() {
// For now, this is really a Darwin-specific operation.
- if (!Context.Target.getTriple().isOSDarwin())
+ if (!Context.getTargetInfo().getTriple().isOSDarwin())
return;
// If we're not in ObjC++ -fexceptions, there's nothing to do.
@@ -314,12 +319,6 @@ static llvm::Constant *getCatchAllValue(CodeGenFunction &CGF) {
return llvm::ConstantPointerNull::get(CGF.Int8PtrTy);
}
-/// Returns the value to inject into a selector to indicate the
-/// presence of a cleanup.
-static llvm::Constant *getCleanupValue(CodeGenFunction &CGF) {
- return llvm::ConstantInt::get(CGF.Builder.getInt32Ty(), 0);
-}
-
namespace {
/// A cleanup to free the exception object if its initialization
/// throws.
@@ -346,7 +345,7 @@ static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *e,
// __cxa_allocate_exception returns a void*; we need to cast this
// to the appropriate type for the object.
- const llvm::Type *ty = CGF.ConvertTypeForMem(e->getType())->getPointerTo();
+ llvm::Type *ty = CGF.ConvertTypeForMem(e->getType())->getPointerTo();
llvm::Value *typedAddr = CGF.Builder.CreateBitCast(addr, ty);
// FIXME: this isn't quite right! If there's a final unelided call
@@ -375,6 +374,14 @@ llvm::Value *CodeGenFunction::getEHSelectorSlot() {
return EHSelectorSlot;
}
+llvm::Value *CodeGenFunction::getExceptionFromSlot() {
+ return Builder.CreateLoad(getExceptionSlot(), "exn");
+}
+
+llvm::Value *CodeGenFunction::getSelectorFromSlot() {
+ return Builder.CreateLoad(getEHSelectorSlot(), "sel");
+}
+
void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
if (!E->getSubExpr()) {
if (getInvokeDest()) {
@@ -397,7 +404,7 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
QualType ThrowType = E->getSubExpr()->getType();
// Now allocate the exception object.
- const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
+ llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
uint64_t TypeSize = getContext().getTypeSizeInChars(ThrowType).getQuantity();
llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this);
@@ -475,6 +482,43 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
}
}
+/// Emit the dispatch block for a filter scope if necessary.
+static void emitFilterDispatchBlock(CodeGenFunction &CGF,
+ EHFilterScope &filterScope) {
+ llvm::BasicBlock *dispatchBlock = filterScope.getCachedEHDispatchBlock();
+ if (!dispatchBlock) return;
+ if (dispatchBlock->use_empty()) {
+ delete dispatchBlock;
+ return;
+ }
+
+ CGF.EmitBlockAfterUses(dispatchBlock);
+
+ // If this isn't a catch-all filter, we need to check whether we got
+ // here because the filter triggered.
+ if (filterScope.getNumFilters()) {
+ // Load the selector value.
+ llvm::Value *selector = CGF.getSelectorFromSlot();
+ llvm::BasicBlock *unexpectedBB = CGF.createBasicBlock("ehspec.unexpected");
+
+ llvm::Value *zero = CGF.Builder.getInt32(0);
+ llvm::Value *failsFilter =
+ CGF.Builder.CreateICmpSLT(selector, zero, "ehspec.fails");
+ CGF.Builder.CreateCondBr(failsFilter, unexpectedBB, CGF.getEHResumeBlock());
+
+ CGF.EmitBlock(unexpectedBB);
+ }
+
+ // Call __cxa_call_unexpected. This doesn't need to be an invoke
+ // because __cxa_call_unexpected magically filters exceptions
+ // according to the last landing pad the exception was thrown
+ // into. Seriously.
+ llvm::Value *exn = CGF.getExceptionFromSlot();
+ CGF.Builder.CreateCall(getUnexpectedFn(CGF), exn)
+ ->setDoesNotReturn();
+ CGF.Builder.CreateUnreachable();
+}
+
void CodeGenFunction::EmitEndEHSpec(const Decl *D) {
if (!CGM.getLangOptions().CXXExceptions)
return;
@@ -492,6 +536,8 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) {
EHStack.popTerminate();
}
} else if (EST == EST_Dynamic || EST == EST_DynamicNone) {
+ EHFilterScope &filterScope = cast<EHFilterScope>(*EHStack.begin());
+ emitFilterDispatchBlock(*this, filterScope);
EHStack.popFilter();
}
}
@@ -533,6 +579,50 @@ void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
}
}
+llvm::BasicBlock *
+CodeGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator si) {
+ // The dispatch block for the end of the scope chain is a block that
+ // just resumes unwinding.
+ if (si == EHStack.stable_end())
+ return getEHResumeBlock();
+
+ // Otherwise, we should look at the actual scope.
+ EHScope &scope = *EHStack.find(si);
+
+ llvm::BasicBlock *dispatchBlock = scope.getCachedEHDispatchBlock();
+ if (!dispatchBlock) {
+ switch (scope.getKind()) {
+ case EHScope::Catch: {
+ // Apply a special case to a single catch-all.
+ EHCatchScope &catchScope = cast<EHCatchScope>(scope);
+ if (catchScope.getNumHandlers() == 1 &&
+ catchScope.getHandler(0).isCatchAll()) {
+ dispatchBlock = catchScope.getHandler(0).Block;
+
+ // Otherwise, make a dispatch block.
+ } else {
+ dispatchBlock = createBasicBlock("catch.dispatch");
+ }
+ break;
+ }
+
+ case EHScope::Cleanup:
+ dispatchBlock = createBasicBlock("ehcleanup");
+ break;
+
+ case EHScope::Filter:
+ dispatchBlock = createBasicBlock("filter.dispatch");
+ break;
+
+ case EHScope::Terminate:
+ dispatchBlock = getTerminateHandler();
+ break;
+ }
+ scope.setCachedEHDispatchBlock(dispatchBlock);
+ }
+ return dispatchBlock;
+}
+
/// Check whether this is a non-EH scope, i.e. a scope which doesn't
/// affect exception handling. Currently, the only non-EH scopes are
/// normal-only cleanup scopes.
@@ -629,280 +719,143 @@ const CleanupHackLevel_t CleanupHackLevel = CHL_MandatoryCleanup;
llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
assert(EHStack.requiresLandingPad());
- for (EHScopeStack::iterator ir = EHStack.begin(); ; ) {
- assert(ir != EHStack.end() &&
- "stack requiring landing pad is nothing but non-EH scopes?");
-
- // If this is a terminate scope, just use the singleton terminate
- // landing pad.
- if (isa<EHTerminateScope>(*ir))
- return getTerminateLandingPad();
-
- // If this isn't an EH scope, iterate; otherwise break out.
- if (!isNonEHScope(*ir)) break;
- ++ir;
+ EHScope &innermostEHScope = *EHStack.find(EHStack.getInnermostEHScope());
+ switch (innermostEHScope.getKind()) {
+ case EHScope::Terminate:
+ return getTerminateLandingPad();
- // We haven't checked this scope for a cached landing pad yet.
- if (llvm::BasicBlock *LP = ir->getCachedLandingPad())
- return LP;
+ case EHScope::Catch:
+ case EHScope::Cleanup:
+ case EHScope::Filter:
+ if (llvm::BasicBlock *lpad = innermostEHScope.getCachedLandingPad())
+ return lpad;
}
// Save the current IR generation state.
- CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
+ CGBuilderTy::InsertPoint savedIP = Builder.saveAndClearIP();
- const EHPersonality &Personality = EHPersonality::get(getLangOptions());
+ const EHPersonality &personality = EHPersonality::get(getLangOptions());
// Create and configure the landing pad.
- llvm::BasicBlock *LP = createBasicBlock("lpad");
- EmitBlock(LP);
+ llvm::BasicBlock *lpad = createBasicBlock("lpad");
+ EmitBlock(lpad);
+
+ llvm::LandingPadInst *LPadInst =
+ Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty, NULL),
+ getOpaquePersonalityFn(CGM, personality), 0);
+
+ llvm::Value *LPadExn = Builder.CreateExtractValue(LPadInst, 0);
+ Builder.CreateStore(LPadExn, getExceptionSlot());
+ llvm::Value *LPadSel = Builder.CreateExtractValue(LPadInst, 1);
+ Builder.CreateStore(LPadSel, getEHSelectorSlot());
// Save the exception pointer. It's safe to use a single exception
// pointer per function because EH cleanups can never have nested
// try/catches.
- llvm::CallInst *Exn =
- Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_exception), "exn");
- Exn->setDoesNotThrow();
- Builder.CreateStore(Exn, getExceptionSlot());
-
- // Build the selector arguments.
- llvm::SmallVector<llvm::Value*, 8> EHSelector;
- EHSelector.push_back(Exn);
- EHSelector.push_back(getOpaquePersonalityFn(CGM, Personality));
+ // Build the landingpad instruction.
// Accumulate all the handlers in scope.
- llvm::DenseMap<llvm::Value*, UnwindDest> EHHandlers;
- UnwindDest CatchAll;
- bool HasEHCleanup = false;
- bool HasEHFilter = false;
- llvm::SmallVector<llvm::Value*, 8> EHFilters;
+ bool hasCatchAll = false;
+ bool hasCleanup = false;
+ bool hasFilter = false;
+ SmallVector<llvm::Value*, 4> filterTypes;
+ llvm::SmallPtrSet<llvm::Value*, 4> catchTypes;
for (EHScopeStack::iterator I = EHStack.begin(), E = EHStack.end();
I != E; ++I) {
switch (I->getKind()) {
case EHScope::Cleanup:
- if (!HasEHCleanup)
- HasEHCleanup = cast<EHCleanupScope>(*I).isEHCleanup();
- // We otherwise don't care about cleanups.
+ // If we have a cleanup, remember that.
+ hasCleanup = (hasCleanup || cast<EHCleanupScope>(*I).isEHCleanup());
continue;
case EHScope::Filter: {
assert(I.next() == EHStack.end() && "EH filter is not end of EH stack");
- assert(!CatchAll.isValid() && "EH filter reached after catch-all");
-
- // Filter scopes get added to the selector in weird ways.
- EHFilterScope &Filter = cast<EHFilterScope>(*I);
- HasEHFilter = true;
-
- // Add all the filter values which we aren't already explicitly
- // catching.
- for (unsigned I = 0, E = Filter.getNumFilters(); I != E; ++I) {
- llvm::Value *FV = Filter.getFilter(I);
- if (!EHHandlers.count(FV))
- EHFilters.push_back(FV);
- }
+ assert(!hasCatchAll && "EH filter reached after catch-all");
+
+ // Filter scopes get added to the landingpad in weird ways.
+ EHFilterScope &filter = cast<EHFilterScope>(*I);
+ hasFilter = true;
+
+ // Add all the filter values.
+ for (unsigned i = 0, e = filter.getNumFilters(); i != e; ++i)
+ filterTypes.push_back(filter.getFilter(i));
goto done;
}
case EHScope::Terminate:
// Terminate scopes are basically catch-alls.
- assert(!CatchAll.isValid());
- CatchAll = UnwindDest(getTerminateHandler(),
- EHStack.getEnclosingEHCleanup(I),
- cast<EHTerminateScope>(*I).getDestIndex());
+ assert(!hasCatchAll);
+ hasCatchAll = true;
goto done;
case EHScope::Catch:
break;
}
- EHCatchScope &Catch = cast<EHCatchScope>(*I);
- for (unsigned HI = 0, HE = Catch.getNumHandlers(); HI != HE; ++HI) {
- EHCatchScope::Handler Handler = Catch.getHandler(HI);
-
- // Catch-all. We should only have one of these per catch.
- if (!Handler.Type) {
- assert(!CatchAll.isValid());
- CatchAll = UnwindDest(Handler.Block,
- EHStack.getEnclosingEHCleanup(I),
- Handler.Index);
- continue;
+ EHCatchScope &catchScope = cast<EHCatchScope>(*I);
+ for (unsigned hi = 0, he = catchScope.getNumHandlers(); hi != he; ++hi) {
+ EHCatchScope::Handler handler = catchScope.getHandler(hi);
+
+ // If this is a catch-all, register that and abort.
+ if (!handler.Type) {
+ assert(!hasCatchAll);
+ hasCatchAll = true;
+ goto done;
}
// Check whether we already have a handler for this type.
- UnwindDest &Dest = EHHandlers[Handler.Type];
- if (Dest.isValid()) continue;
-
- EHSelector.push_back(Handler.Type);
- Dest = UnwindDest(Handler.Block,
- EHStack.getEnclosingEHCleanup(I),
- Handler.Index);
+ if (catchTypes.insert(handler.Type))
+ // If not, add it directly to the landingpad.
+ LPadInst->addClause(handler.Type);
}
-
- // Stop if we found a catch-all.
- if (CatchAll.isValid()) break;
}
done:
- unsigned LastToEmitInLoop = EHSelector.size();
-
- // If we have a catch-all, add null to the selector.
- if (CatchAll.isValid()) {
- EHSelector.push_back(getCatchAllValue(*this));
+ // If we have a catch-all, add null to the landingpad.
+ assert(!(hasCatchAll && hasFilter));
+ if (hasCatchAll) {
+ LPadInst->addClause(getCatchAllValue(*this));
// If we have an EH filter, we need to add those handlers in the
- // right place in the selector, which is to say, at the end.
- } else if (HasEHFilter) {
- // Create a filter expression: an integer constant saying how many
- // filters there are (+1 to avoid ambiguity with 0 for cleanup),
- // followed by the filter types. The personality routine only
- // lands here if the filter doesn't match.
- EHSelector.push_back(llvm::ConstantInt::get(Builder.getInt32Ty(),
- EHFilters.size() + 1));
- EHSelector.append(EHFilters.begin(), EHFilters.end());
+ // right place in the landingpad, which is to say, at the end.
+ } else if (hasFilter) {
+ // 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;
+ llvm::ArrayType *AType =
+ llvm::ArrayType::get(!filterTypes.empty() ?
+ filterTypes[0]->getType() : Int8PtrTy,
+ filterTypes.size());
+
+ for (unsigned i = 0, e = filterTypes.size(); i != e; ++i)
+ Filters.push_back(cast<llvm::Constant>(filterTypes[i]));
+ llvm::Constant *FilterArray = llvm::ConstantArray::get(AType, Filters);
+ LPadInst->addClause(FilterArray);
// Also check whether we need a cleanup.
- if (CleanupHackLevel == CHL_MandatoryCatchall || HasEHCleanup)
- EHSelector.push_back(CleanupHackLevel == CHL_MandatoryCatchall
- ? getCatchAllValue(*this)
- : getCleanupValue(*this));
+ if (hasCleanup)
+ LPadInst->setCleanup(true);
// Otherwise, signal that we at least have cleanups.
- } else if (CleanupHackLevel == CHL_MandatoryCatchall || HasEHCleanup) {
- EHSelector.push_back(CleanupHackLevel == CHL_MandatoryCatchall
- ? getCatchAllValue(*this)
- : getCleanupValue(*this));
-
- // At the MandatoryCleanup hack level, we don't need to actually
- // spuriously tell the unwinder that we have cleanups, but we do
- // need to always be prepared to handle cleanups.
- } else if (CleanupHackLevel == CHL_MandatoryCleanup) {
- // Just don't decrement LastToEmitInLoop.
-
- } else {
- assert(LastToEmitInLoop > 2);
- LastToEmitInLoop--;
+ } else if (CleanupHackLevel == CHL_MandatoryCatchall || hasCleanup) {
+ if (CleanupHackLevel == CHL_MandatoryCatchall)
+ LPadInst->addClause(getCatchAllValue(*this));
+ else
+ LPadInst->setCleanup(true);
}
- assert(EHSelector.size() >= 3 && "selector call has only two arguments!");
+ assert((LPadInst->getNumClauses() > 0 || LPadInst->isCleanup()) &&
+ "landingpad instruction has no clauses!");
// Tell the backend how to generate the landing pad.
- llvm::CallInst *Selection =
- Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_selector),
- EHSelector, "eh.selector");
- Selection->setDoesNotThrow();
-
- // Save the selector value in mandatory-cleanup mode.
- if (CleanupHackLevel == CHL_MandatoryCleanup)
- Builder.CreateStore(Selection, getEHSelectorSlot());
-
- // Select the right handler.
- llvm::Value *llvm_eh_typeid_for =
- CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for);
-
- // The results of llvm_eh_typeid_for aren't reliable --- at least
- // not locally --- so we basically have to do this as an 'if' chain.
- // We walk through the first N-1 catch clauses, testing and chaining,
- // and then fall into the final clause (which is either a cleanup, a
- // filter (possibly with a cleanup), a catch-all, or another catch).
- for (unsigned I = 2; I != LastToEmitInLoop; ++I) {
- llvm::Value *Type = EHSelector[I];
- UnwindDest Dest = EHHandlers[Type];
- assert(Dest.isValid() && "no handler entry for value in selector?");
-
- // Figure out where to branch on a match. As a debug code-size
- // optimization, if the scope depth matches the innermost cleanup,
- // we branch directly to the catch handler.
- llvm::BasicBlock *Match = Dest.getBlock();
- bool MatchNeedsCleanup =
- Dest.getScopeDepth() != EHStack.getInnermostEHCleanup();
- if (MatchNeedsCleanup)
- Match = createBasicBlock("eh.match");
-
- llvm::BasicBlock *Next = createBasicBlock("eh.next");
-
- // Check whether the exception matches.
- llvm::CallInst *Id
- = Builder.CreateCall(llvm_eh_typeid_for,
- Builder.CreateBitCast(Type, Int8PtrTy));
- Id->setDoesNotThrow();
- Builder.CreateCondBr(Builder.CreateICmpEQ(Selection, Id),
- Match, Next);
-
- // Emit match code if necessary.
- if (MatchNeedsCleanup) {
- EmitBlock(Match);
- EmitBranchThroughEHCleanup(Dest);
- }
-
- // Continue to the next match.
- EmitBlock(Next);
- }
-
- // Emit the final case in the selector.
- // This might be a catch-all....
- if (CatchAll.isValid()) {
- assert(isa<llvm::ConstantPointerNull>(EHSelector.back()));
- EmitBranchThroughEHCleanup(CatchAll);
-
- // ...or an EH filter...
- } else if (HasEHFilter) {
- llvm::Value *SavedSelection = Selection;
-
- // First, unwind out to the outermost scope if necessary.
- if (EHStack.hasEHCleanups()) {
- // The end here might not dominate the beginning, so we might need to
- // save the selector if we need it.
- llvm::AllocaInst *SelectorVar = 0;
- if (HasEHCleanup) {
- SelectorVar = CreateTempAlloca(Builder.getInt32Ty(), "selector.var");
- Builder.CreateStore(Selection, SelectorVar);
- }
-
- llvm::BasicBlock *CleanupContBB = createBasicBlock("ehspec.cleanup.cont");
- EmitBranchThroughEHCleanup(UnwindDest(CleanupContBB, EHStack.stable_end(),
- EHStack.getNextEHDestIndex()));
- EmitBlock(CleanupContBB);
-
- if (HasEHCleanup)
- SavedSelection = Builder.CreateLoad(SelectorVar, "ehspec.saved-selector");
- }
-
- // If there was a cleanup, we'll need to actually check whether we
- // landed here because the filter triggered.
- if (CleanupHackLevel != CHL_Ideal || HasEHCleanup) {
- llvm::BasicBlock *UnexpectedBB = createBasicBlock("ehspec.unexpected");
-
- llvm::Constant *Zero = llvm::ConstantInt::get(Int32Ty, 0);
- llvm::Value *FailsFilter =
- Builder.CreateICmpSLT(SavedSelection, Zero, "ehspec.fails");
- Builder.CreateCondBr(FailsFilter, UnexpectedBB, getRethrowDest().getBlock());
-
- EmitBlock(UnexpectedBB);
- }
-
- // Call __cxa_call_unexpected. This doesn't need to be an invoke
- // because __cxa_call_unexpected magically filters exceptions
- // according to the last landing pad the exception was thrown
- // into. Seriously.
- Builder.CreateCall(getUnexpectedFn(*this),
- Builder.CreateLoad(getExceptionSlot()))
- ->setDoesNotReturn();
- Builder.CreateUnreachable();
-
- // ...or a normal catch handler...
- } else if (CleanupHackLevel == CHL_Ideal && !HasEHCleanup) {
- llvm::Value *Type = EHSelector.back();
- EmitBranchThroughEHCleanup(EHHandlers[Type]);
-
- // ...or a cleanup.
- } else {
- EmitBranchThroughEHCleanup(getRethrowDest());
- }
+ Builder.CreateBr(getEHDispatchBlock(EHStack.getInnermostEHScope()));
// Restore the old IR generation state.
- Builder.restoreIP(SavedIP);
+ Builder.restoreIP(savedIP);
- return LP;
+ return lpad;
}
namespace {
@@ -954,11 +907,11 @@ static void InitCatchParam(CodeGenFunction &CGF,
const VarDecl &CatchParam,
llvm::Value *ParamAddr) {
// Load the exception from where the landing pad saved it.
- llvm::Value *Exn = CGF.Builder.CreateLoad(CGF.getExceptionSlot(), "exn");
+ llvm::Value *Exn = CGF.getExceptionFromSlot();
CanQualType CatchType =
CGF.CGM.getContext().getCanonicalType(CatchParam.getType());
- const llvm::Type *LLVMCatchTy = CGF.ConvertTypeForMem(CatchType);
+ llvm::Type *LLVMCatchTy = CGF.ConvertTypeForMem(CatchType);
// If we're catching by reference, we can just cast the object
// pointer to the appropriate pointer.
@@ -1001,7 +954,7 @@ static void InitCatchParam(CodeGenFunction &CGF,
// pad. The best solution is to fix the personality function.
} else {
// Pull the pointer for the reference type off.
- const llvm::Type *PtrTy =
+ llvm::Type *PtrTy =
cast<llvm::PointerType>(LLVMCatchTy)->getElementType();
// Create the temporary and write the adjusted pointer into it.
@@ -1037,7 +990,7 @@ static void InitCatchParam(CodeGenFunction &CGF,
// Otherwise, it returns a pointer into the exception object.
- const llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
+ llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
if (IsComplex) {
@@ -1055,7 +1008,7 @@ static void InitCatchParam(CodeGenFunction &CGF,
assert(isa<RecordType>(CatchType) && "unexpected catch type!");
- const llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
+ llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
// Check for a copy expression. If we don't have a copy expression,
// that means a trivial copy is okay.
@@ -1086,8 +1039,10 @@ static void InitCatchParam(CodeGenFunction &CGF,
CGF.EHStack.pushTerminate();
// Perform the copy construction.
- CGF.EmitAggExpr(copyExpr, AggValueSlot::forAddr(ParamAddr, Qualifiers(),
- false));
+ CGF.EmitAggExpr(copyExpr, AggValueSlot::forAddr(ParamAddr, Qualifiers(),
+ AggValueSlot::IsNotDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased));
// Leave the terminate scope.
CGF.EHStack.popTerminate();
@@ -1127,7 +1082,7 @@ static void BeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *S) {
VarDecl *CatchParam = S->getExceptionDecl();
if (!CatchParam) {
- llvm::Value *Exn = CGF.Builder.CreateLoad(CGF.getExceptionSlot(), "exn");
+ llvm::Value *Exn = CGF.getExceptionFromSlot();
CallBeginCatch(CGF, Exn, true);
return;
}
@@ -1146,16 +1101,112 @@ namespace {
};
}
+/// Emit the structure of the dispatch block for the given catch scope.
+/// It is an invariant that the dispatch block already exists.
+static void emitCatchDispatchBlock(CodeGenFunction &CGF,
+ EHCatchScope &catchScope) {
+ llvm::BasicBlock *dispatchBlock = catchScope.getCachedEHDispatchBlock();
+ assert(dispatchBlock);
+
+ // If there's only a single catch-all, getEHDispatchBlock returned
+ // that catch-all as the dispatch block.
+ if (catchScope.getNumHandlers() == 1 &&
+ catchScope.getHandler(0).isCatchAll()) {
+ assert(dispatchBlock == catchScope.getHandler(0).Block);
+ return;
+ }
+
+ CGBuilderTy::InsertPoint savedIP = CGF.Builder.saveIP();
+ CGF.EmitBlockAfterUses(dispatchBlock);
+
+ // Select the right handler.
+ llvm::Value *llvm_eh_typeid_for =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for);
+
+ // Load the selector value.
+ llvm::Value *selector = CGF.getSelectorFromSlot();
+
+ // Test against each of the exception types we claim to catch.
+ for (unsigned i = 0, e = catchScope.getNumHandlers(); ; ++i) {
+ assert(i < e && "ran off end of handlers!");
+ const EHCatchScope::Handler &handler = catchScope.getHandler(i);
+
+ llvm::Value *typeValue = handler.Type;
+ assert(typeValue && "fell into catch-all case!");
+ typeValue = CGF.Builder.CreateBitCast(typeValue, CGF.Int8PtrTy);
+
+ // Figure out the next block.
+ bool nextIsEnd;
+ llvm::BasicBlock *nextBlock;
+
+ // If this is the last handler, we're at the end, and the next
+ // block is the block for the enclosing EH scope.
+ if (i + 1 == e) {
+ nextBlock = CGF.getEHDispatchBlock(catchScope.getEnclosingEHScope());
+ nextIsEnd = true;
+
+ // If the next handler is a catch-all, we're at the end, and the
+ // next block is that handler.
+ } else if (catchScope.getHandler(i+1).isCatchAll()) {
+ nextBlock = catchScope.getHandler(i+1).Block;
+ nextIsEnd = true;
+
+ // Otherwise, we're not at the end and we need a new block.
+ } else {
+ nextBlock = CGF.createBasicBlock("catch.fallthrough");
+ nextIsEnd = false;
+ }
+
+ // Figure out the catch type's index in the LSDA's type table.
+ llvm::CallInst *typeIndex =
+ CGF.Builder.CreateCall(llvm_eh_typeid_for, typeValue);
+ typeIndex->setDoesNotThrow();
+
+ llvm::Value *matchesTypeIndex =
+ CGF.Builder.CreateICmpEQ(selector, typeIndex, "matches");
+ CGF.Builder.CreateCondBr(matchesTypeIndex, handler.Block, nextBlock);
+
+ // If the next handler is a catch-all, we're completely done.
+ if (nextIsEnd) {
+ CGF.Builder.restoreIP(savedIP);
+ return;
+
+ // Otherwise we need to emit and continue at that block.
+ } else {
+ CGF.EmitBlock(nextBlock);
+ }
+ }
+
+ llvm_unreachable("fell out of loop!");
+}
+
+void CodeGenFunction::popCatchScope() {
+ EHCatchScope &catchScope = cast<EHCatchScope>(*EHStack.begin());
+ if (catchScope.hasEHBranches())
+ emitCatchDispatchBlock(*this, catchScope);
+ EHStack.popCatch();
+}
+
void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
unsigned NumHandlers = S.getNumHandlers();
EHCatchScope &CatchScope = cast<EHCatchScope>(*EHStack.begin());
assert(CatchScope.getNumHandlers() == NumHandlers);
+ // If the catch was not required, bail out now.
+ if (!CatchScope.hasEHBranches()) {
+ EHStack.popCatch();
+ return;
+ }
+
+ // Emit the structure of the EH dispatch for this catch.
+ emitCatchDispatchBlock(*this, CatchScope);
+
// Copy the handler blocks off before we pop the EH stack. Emitting
// the handlers might scribble on this memory.
- llvm::SmallVector<EHCatchScope::Handler, 8> Handlers(NumHandlers);
+ SmallVector<EHCatchScope::Handler, 8> Handlers(NumHandlers);
memcpy(Handlers.data(), CatchScope.begin(),
NumHandlers * sizeof(EHCatchScope::Handler));
+
EHStack.popCatch();
// The fall-through block.
@@ -1171,12 +1222,19 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
ImplicitRethrow = isa<CXXDestructorDecl>(CurCodeDecl) ||
isa<CXXConstructorDecl>(CurCodeDecl);
- for (unsigned I = 0; I != NumHandlers; ++I) {
- llvm::BasicBlock *CatchBlock = Handlers[I].Block;
- EmitBlock(CatchBlock);
+ // Perversely, we emit the handlers backwards precisely because we
+ // want them to appear in source order. In all of these cases, the
+ // catch block will have exactly one predecessor, which will be a
+ // particular block in the catch dispatch. However, in the case of
+ // a catch-all, one of the dispatch blocks will branch to two
+ // different handlers, and EmitBlockAfterUses will cause the second
+ // handler to be moved before the first.
+ for (unsigned I = NumHandlers; I != 0; --I) {
+ llvm::BasicBlock *CatchBlock = Handlers[I-1].Block;
+ EmitBlockAfterUses(CatchBlock);
// Catch the exception if this isn't a catch-all.
- const CXXCatchStmt *C = S.getHandler(I);
+ const CXXCatchStmt *C = S.getHandler(I-1);
// Enter a cleanup scope, including the catch variable and the
// end-catch.
@@ -1315,7 +1373,7 @@ void CodeGenFunction::FinallyInfo::enter(CodeGenFunction &CGF,
// In the latter case we need to pass it the exception object.
// But we can't use the exception slot because the @finally might
// have a landing pad (which would overwrite the exception slot).
- const llvm::FunctionType *rethrowFnTy =
+ llvm::FunctionType *rethrowFnTy =
cast<llvm::FunctionType>(
cast<llvm::PointerType>(rethrowFn->getType())->getElementType());
SavedExnVar = 0;
@@ -1358,7 +1416,8 @@ void CodeGenFunction::FinallyInfo::exit(CodeGenFunction &CGF) {
// Leave the finally catch-all.
EHCatchScope &catchScope = cast<EHCatchScope>(*CGF.EHStack.begin());
llvm::BasicBlock *catchBB = catchScope.getHandler(0).Block;
- CGF.EHStack.popCatch();
+
+ CGF.popCatchScope();
// If there are any references to the catch-all block, emit it.
if (catchBB->use_empty()) {
@@ -1371,13 +1430,13 @@ void CodeGenFunction::FinallyInfo::exit(CodeGenFunction &CGF) {
// If there's a begin-catch function, call it.
if (BeginCatchFn) {
- exn = CGF.Builder.CreateLoad(CGF.getExceptionSlot());
+ exn = CGF.getExceptionFromSlot();
CGF.Builder.CreateCall(BeginCatchFn, exn)->setDoesNotThrow();
}
// If we need to remember the exception pointer to rethrow later, do so.
if (SavedExnVar) {
- if (!exn) exn = CGF.Builder.CreateLoad(CGF.getExceptionSlot());
+ if (!exn) exn = CGF.getExceptionFromSlot();
CGF.Builder.CreateStore(exn, SavedExnVar);
}
@@ -1405,19 +1464,11 @@ llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {
Builder.SetInsertPoint(TerminateLandingPad);
// Tell the backend that this is a landing pad.
- llvm::CallInst *Exn =
- Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_exception), "exn");
- Exn->setDoesNotThrow();
-
const EHPersonality &Personality = EHPersonality::get(CGM.getLangOptions());
-
- // Tell the backend what the exception table should be:
- // nothing but a catch-all.
- llvm::Value *Args[3] = { Exn, getOpaquePersonalityFn(CGM, Personality),
- getCatchAllValue(*this) };
- Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_selector),
- Args, "eh.selector")
- ->setDoesNotThrow();
+ llvm::LandingPadInst *LPadInst =
+ Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty, NULL),
+ getOpaquePersonalityFn(CGM, Personality), 0);
+ LPadInst->addClause(getCatchAllValue(*this));
llvm::CallInst *TerminateCall = Builder.CreateCall(getTerminateFn(*this));
TerminateCall->setDoesNotReturn();
@@ -1451,26 +1502,26 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
return TerminateHandler;
}
-CodeGenFunction::UnwindDest CodeGenFunction::getRethrowDest() {
- if (RethrowBlock.isValid()) return RethrowBlock;
+llvm::BasicBlock *CodeGenFunction::getEHResumeBlock() {
+ if (EHResumeBlock) return EHResumeBlock;
CGBuilderTy::InsertPoint SavedIP = Builder.saveIP();
// We emit a jump to a notional label at the outermost unwind state.
- llvm::BasicBlock *Unwind = createBasicBlock("eh.resume");
- Builder.SetInsertPoint(Unwind);
+ EHResumeBlock = createBasicBlock("eh.resume");
+ Builder.SetInsertPoint(EHResumeBlock);
const EHPersonality &Personality = EHPersonality::get(CGM.getLangOptions());
// This can always be a call because we necessarily didn't find
// anything on the EH stack which needs our help.
- llvm::StringRef RethrowName = Personality.getCatchallRethrowFnName();
+ StringRef RethrowName = Personality.getCatchallRethrowFnName();
if (!RethrowName.empty()) {
Builder.CreateCall(getCatchallRethrowFn(*this, RethrowName),
- Builder.CreateLoad(getExceptionSlot()))
+ getExceptionFromSlot())
->setDoesNotReturn();
} else {
- llvm::Value *Exn = Builder.CreateLoad(getExceptionSlot());
+ llvm::Value *Exn = getExceptionFromSlot();
switch (CleanupHackLevel) {
case CHL_MandatoryCatchall:
@@ -1481,12 +1532,21 @@ CodeGenFunction::UnwindDest CodeGenFunction::getRethrowDest() {
->setDoesNotReturn();
break;
case CHL_MandatoryCleanup: {
- // In mandatory-cleanup mode, we should use llvm.eh.resume.
- llvm::Value *Selector = Builder.CreateLoad(getEHSelectorSlot());
- Builder.CreateCall2(CGM.getIntrinsic(llvm::Intrinsic::eh_resume),
- Exn, Selector)
- ->setDoesNotReturn();
- break;
+ // In mandatory-cleanup mode, we should use 'resume'.
+
+ // Recreate the landingpad's return value for the 'resume' instruction.
+ llvm::Value *Exn = getExceptionFromSlot();
+ llvm::Value *Sel = getSelectorFromSlot();
+
+ llvm::Type *LPadType = llvm::StructType::get(Exn->getType(),
+ Sel->getType(), NULL);
+ llvm::Value *LPadVal = llvm::UndefValue::get(LPadType);
+ LPadVal = Builder.CreateInsertValue(LPadVal, Exn, 0, "lpad.val");
+ LPadVal = Builder.CreateInsertValue(LPadVal, Sel, 1, "lpad.val");
+
+ Builder.CreateResume(LPadVal);
+ Builder.restoreIP(SavedIP);
+ return EHResumeBlock;
}
case CHL_Ideal:
// In an idealized mode where we don't have to worry about the
@@ -1502,7 +1562,5 @@ CodeGenFunction::UnwindDest CodeGenFunction::getRethrowDest() {
Builder.restoreIP(SavedIP);
- RethrowBlock = UnwindDest(Unwind, EHStack.stable_end(), 0);
- return RethrowBlock;
+ return EHResumeBlock;
}
-
diff --git a/lib/CodeGen/CGException.h b/lib/CodeGen/CGException.h
index 5a743b51f66f..d0216160d50f 100644
--- a/lib/CodeGen/CGException.h
+++ b/lib/CodeGen/CGException.h
@@ -24,15 +24,15 @@ namespace CodeGen {
/// The exceptions personality for a function. When
class EHPersonality {
- llvm::StringRef PersonalityFn;
+ StringRef PersonalityFn;
// If this is non-null, this personality requires a non-standard
// function for rethrowing an exception after a catchall cleanup.
// This function must have prototype void(void*).
- llvm::StringRef CatchallRethrowFn;
+ StringRef CatchallRethrowFn;
- EHPersonality(llvm::StringRef PersonalityFn,
- llvm::StringRef CatchallRethrowFn = llvm::StringRef())
+ EHPersonality(StringRef PersonalityFn,
+ StringRef CatchallRethrowFn = StringRef())
: PersonalityFn(PersonalityFn),
CatchallRethrowFn(CatchallRethrowFn) {}
@@ -46,8 +46,8 @@ public:
static const EHPersonality GNU_CPlusPlus;
static const EHPersonality GNU_CPlusPlus_SJLJ;
- llvm::StringRef getPersonalityFnName() const { return PersonalityFn; }
- llvm::StringRef getCatchallRethrowFnName() const { return CatchallRethrowFn; }
+ StringRef getPersonalityFnName() const { return PersonalityFn; }
+ StringRef getCatchallRethrowFnName() const { return CatchallRethrowFn; }
};
}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index a7e8003eaab5..bd4e553991b3 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -18,6 +18,7 @@
#include "CGDebugInfo.h"
#include "CGRecordLayout.h"
#include "CGObjCRuntime.h"
+#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Frontend/CodeGenOptions.h"
@@ -34,7 +35,7 @@ llvm::Value *CodeGenFunction::EmitCastToVoidPtr(llvm::Value *value) {
unsigned addressSpace =
cast<llvm::PointerType>(value->getType())->getAddressSpace();
- const llvm::PointerType *destType = Int8PtrTy;
+ llvm::PointerType *destType = Int8PtrTy;
if (addressSpace)
destType = llvm::Type::getInt8PtrTy(getLLVMContext(), addressSpace);
@@ -44,8 +45,8 @@ llvm::Value *CodeGenFunction::EmitCastToVoidPtr(llvm::Value *value) {
/// CreateTempAlloca - This creates a alloca and inserts it into the entry
/// block.
-llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty,
- const llvm::Twine &Name) {
+llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(llvm::Type *Ty,
+ const Twine &Name) {
if (!Builder.isNamePreserving())
return new llvm::AllocaInst(Ty, 0, "", AllocaInsertPt);
return new llvm::AllocaInst(Ty, 0, Name, AllocaInsertPt);
@@ -59,7 +60,7 @@ void CodeGenFunction::InitTempAlloca(llvm::AllocaInst *Var,
}
llvm::AllocaInst *CodeGenFunction::CreateIRTemp(QualType Ty,
- const llvm::Twine &Name) {
+ const Twine &Name) {
llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertType(Ty), Name);
// FIXME: Should we prefer the preferred type alignment here?
CharUnits Align = getContext().getTypeAlignInChars(Ty);
@@ -68,7 +69,7 @@ llvm::AllocaInst *CodeGenFunction::CreateIRTemp(QualType Ty,
}
llvm::AllocaInst *CodeGenFunction::CreateMemTemp(QualType Ty,
- const llvm::Twine &Name) {
+ const Twine &Name) {
llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty), Name);
// FIXME: Should we prefer the preferred type alignment here?
CharUnits Align = getContext().getTypeAlignInChars(Ty);
@@ -136,7 +137,10 @@ void CodeGenFunction::EmitAnyExprToMem(const Expr *E,
if (E->getType()->isAnyComplexType())
EmitComplexExprIntoAddr(E, Location, Quals.hasVolatile());
else if (hasAggregateLLVMType(E->getType()))
- EmitAggExpr(E, AggValueSlot::forAddr(Location, Quals, IsInit));
+ EmitAggExpr(E, AggValueSlot::forAddr(Location, Quals,
+ AggValueSlot::IsDestructed_t(IsInit),
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsAliased_t(!IsInit)));
else {
RValue RV = RValue::get(EmitScalarExpr(E, /*Ignore*/ false));
LValue LV = MakeAddrLValue(Location, E->getType());
@@ -174,7 +178,7 @@ namespace {
}
static llvm::Value *
-CreateReferenceTemporary(CodeGenFunction& CGF, QualType Type,
+CreateReferenceTemporary(CodeGenFunction &CGF, QualType Type,
const NamedDecl *InitializedDecl) {
if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl)) {
if (VD->hasGlobalStorage()) {
@@ -183,7 +187,7 @@ CreateReferenceTemporary(CodeGenFunction& CGF, QualType Type,
CGF.CGM.getCXXABI().getMangleContext().mangleReferenceTemporary(VD, Out);
Out.flush();
- const llvm::Type *RefTempTy = CGF.ConvertTypeForMem(Type);
+ llvm::Type *RefTempTy = CGF.ConvertTypeForMem(Type);
// Create the reference temporary.
llvm::GlobalValue *RefTemp =
@@ -310,7 +314,7 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
return ReferenceTemporary;
}
- llvm::SmallVector<SubobjectAdjustment, 2> Adjustments;
+ SmallVector<SubobjectAdjustment, 2> Adjustments;
while (true) {
E = E->IgnoreParens();
@@ -354,8 +358,12 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
!E->getType()->isAnyComplexType()) {
ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(),
InitializedDecl);
+ AggValueSlot::IsDestructed_t isDestructed
+ = AggValueSlot::IsDestructed_t(InitializedDecl != 0);
AggSlot = AggValueSlot::forAddr(ReferenceTemporary, Qualifiers(),
- InitializedDecl != 0);
+ isDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased);
}
if (InitializedDecl) {
@@ -466,7 +474,8 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,
else {
switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) {
case Qualifiers::OCL_None:
- assert(0 && "Not a reference temporary that needs to be deallocated");
+ llvm_unreachable(
+ "Not a reference temporary that needs to be deallocated");
case Qualifiers::OCL_ExplicitNone:
case Qualifiers::OCL_Autoreleasing:
// Nothing to do.
@@ -578,7 +587,7 @@ RValue CodeGenFunction::GetUndefRValue(QualType Ty) {
return RValue::get(0);
if (const ComplexType *CTy = Ty->getAs<ComplexType>()) {
- const llvm::Type *EltTy = ConvertType(CTy->getElementType());
+ llvm::Type *EltTy = ConvertType(CTy->getElementType());
llvm::Value *U = llvm::UndefValue::get(EltTy);
return RValue::getComplex(std::make_pair(U, U));
}
@@ -652,7 +661,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
return EmitVAArgExprLValue(cast<VAArgExpr>(E));
case Expr::DeclRefExprClass:
return EmitDeclRefLValue(cast<DeclRefExpr>(E));
- case Expr::ParenExprClass:return EmitLValue(cast<ParenExpr>(E)->getSubExpr());
+ case Expr::ParenExprClass:
+ return EmitLValue(cast<ParenExpr>(E)->getSubExpr());
case Expr::GenericSelectionExprClass:
return EmitLValue(cast<GenericSelectionExpr>(E)->getResultExpr());
case Expr::PredefinedExprClass:
@@ -731,7 +741,7 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue) {
llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
unsigned Alignment, QualType Ty,
llvm::MDNode *TBAAInfo) {
- llvm::LoadInst *Load = Builder.CreateLoad(Addr, "tmp");
+ llvm::LoadInst *Load = Builder.CreateLoad(Addr);
if (Volatile)
Load->setVolatile(true);
if (Alignment)
@@ -812,7 +822,7 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV) {
if (LV.isVectorElt()) {
llvm::Value *Vec = Builder.CreateLoad(LV.getVectorAddr(),
- LV.isVolatileQualified(), "tmp");
+ LV.isVolatileQualified());
return RValue::get(Builder.CreateExtractElement(Vec, LV.getVectorIdx(),
"vecext"));
}
@@ -833,7 +843,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) {
const CGBitFieldInfo &Info = LV.getBitFieldInfo();
// Get the output type.
- const llvm::Type *ResLTy = ConvertType(LV.getType());
+ llvm::Type *ResLTy = ConvertType(LV.getType());
unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy);
// Compute the result as an OR of all of the individual component accesses.
@@ -857,7 +867,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) {
}
// Cast to the access type.
- const llvm::Type *PTy = llvm::Type::getIntNPtrTy(getLLVMContext(),
+ llvm::Type *PTy = llvm::Type::getIntNPtrTy(getLLVMContext(),
AI.AccessWidth,
CGM.getContext().getTargetAddressSpace(LV.getType()));
Ptr = Builder.CreateBitCast(Ptr, PTy);
@@ -905,7 +915,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) {
// appropriate shufflevector.
RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) {
llvm::Value *Vec = Builder.CreateLoad(LV.getExtVectorAddr(),
- LV.isVolatileQualified(), "tmp");
+ LV.isVolatileQualified());
const llvm::Constant *Elts = LV.getExtVectorElts();
@@ -915,13 +925,13 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) {
if (!ExprVT) {
unsigned InIdx = getAccessedFieldNo(0, Elts);
llvm::Value *Elt = llvm::ConstantInt::get(Int32Ty, InIdx);
- return RValue::get(Builder.CreateExtractElement(Vec, Elt, "tmp"));
+ return RValue::get(Builder.CreateExtractElement(Vec, Elt));
}
// Always use shuffle vector to try to retain the original program structure
unsigned NumResultElts = ExprVT->getNumElements();
- llvm::SmallVector<llvm::Constant*, 4> Mask;
+ SmallVector<llvm::Constant*, 4> Mask;
for (unsigned i = 0; i != NumResultElts; ++i) {
unsigned InIdx = getAccessedFieldNo(i, Elts);
Mask.push_back(llvm::ConstantInt::get(Int32Ty, InIdx));
@@ -929,7 +939,7 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) {
llvm::Value *MaskV = llvm::ConstantVector::get(Mask);
Vec = Builder.CreateShuffleVector(Vec, llvm::UndefValue::get(Vec->getType()),
- MaskV, "tmp");
+ MaskV);
return RValue::get(Vec);
}
@@ -943,7 +953,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst) {
if (Dst.isVectorElt()) {
// Read/modify/write the vector, inserting the new element.
llvm::Value *Vec = Builder.CreateLoad(Dst.getVectorAddr(),
- Dst.isVolatileQualified(), "tmp");
+ Dst.isVolatileQualified());
Vec = Builder.CreateInsertElement(Vec, Src.getScalarVal(),
Dst.getVectorIdx(), "vecins");
Builder.CreateStore(Vec, Dst.getVectorAddr(),Dst.isVolatileQualified());
@@ -1002,7 +1012,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst) {
llvm::Value *src = Src.getScalarVal();
if (Dst.isObjCIvar()) {
assert(Dst.getBaseIvarExp() && "BaseIvarExp is NULL");
- const llvm::Type *ResultType = ConvertType(getContext().LongTy);
+ llvm::Type *ResultType = ConvertType(getContext().LongTy);
llvm::Value *RHS = EmitScalarExpr(Dst.getBaseIvarExp());
llvm::Value *dst = RHS;
RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast");
@@ -1029,7 +1039,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
const CGBitFieldInfo &Info = Dst.getBitFieldInfo();
// Get the output type.
- const llvm::Type *ResLTy = ConvertTypeForMem(Dst.getType());
+ llvm::Type *ResLTy = ConvertTypeForMem(Dst.getType());
unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy);
// Get the source value, truncated to the width of the bit-field.
@@ -1045,7 +1055,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
// Return the new value of the bit-field, if requested.
if (Result) {
// Cast back to the proper type for result.
- const llvm::Type *SrcTy = Src.getScalarVal()->getType();
+ llvm::Type *SrcTy = Src.getScalarVal()->getType();
llvm::Value *ReloadVal = Builder.CreateIntCast(SrcVal, SrcTy, false,
"bf.reload.val");
@@ -1082,10 +1092,10 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
}
// Cast to the access type.
- const llvm::Type *AccessLTy =
+ llvm::Type *AccessLTy =
llvm::Type::getIntNTy(getLLVMContext(), AI.AccessWidth);
- const llvm::Type *PTy = AccessLTy->getPointerTo(addressSpace);
+ 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
@@ -1134,7 +1144,7 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
// This access turns into a read/modify/write of the vector. Load the input
// value now.
llvm::Value *Vec = Builder.CreateLoad(Dst.getExtVectorAddr(),
- Dst.isVolatileQualified(), "tmp");
+ Dst.isVolatileQualified());
const llvm::Constant *Elts = Dst.getExtVectorElts();
llvm::Value *SrcVal = Src.getScalarVal();
@@ -1147,7 +1157,7 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
// Use shuffle vector is the src and destination are the same number of
// elements and restore the vector mask since it is on the side it will be
// stored.
- llvm::SmallVector<llvm::Constant*, 4> Mask(NumDstElts);
+ SmallVector<llvm::Constant*, 4> Mask(NumDstElts);
for (unsigned i = 0; i != NumSrcElts; ++i) {
unsigned InIdx = getAccessedFieldNo(i, Elts);
Mask[InIdx] = llvm::ConstantInt::get(Int32Ty, i);
@@ -1156,13 +1166,13 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
llvm::Value *MaskV = llvm::ConstantVector::get(Mask);
Vec = Builder.CreateShuffleVector(SrcVal,
llvm::UndefValue::get(Vec->getType()),
- MaskV, "tmp");
+ MaskV);
} else if (NumDstElts > NumSrcElts) {
// Extended the source vector to the same length and then shuffle it
// into the destination.
// FIXME: since we're shuffling with undef, can we just use the indices
// into that? This could be simpler.
- llvm::SmallVector<llvm::Constant*, 4> ExtMask;
+ SmallVector<llvm::Constant*, 4> ExtMask;
unsigned i;
for (i = 0; i != NumSrcElts; ++i)
ExtMask.push_back(llvm::ConstantInt::get(Int32Ty, i));
@@ -1172,9 +1182,9 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
llvm::Value *ExtSrcVal =
Builder.CreateShuffleVector(SrcVal,
llvm::UndefValue::get(SrcVal->getType()),
- ExtMaskV, "tmp");
+ ExtMaskV);
// build identity
- llvm::SmallVector<llvm::Constant*, 4> Mask;
+ SmallVector<llvm::Constant*, 4> Mask;
for (unsigned i = 0; i != NumDstElts; ++i)
Mask.push_back(llvm::ConstantInt::get(Int32Ty, i));
@@ -1184,16 +1194,16 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
Mask[Idx] = llvm::ConstantInt::get(Int32Ty, i+NumDstElts);
}
llvm::Value *MaskV = llvm::ConstantVector::get(Mask);
- Vec = Builder.CreateShuffleVector(Vec, ExtSrcVal, MaskV, "tmp");
+ Vec = Builder.CreateShuffleVector(Vec, ExtSrcVal, MaskV);
} else {
// We should never shorten the vector
- assert(0 && "unexpected shorten vector length");
+ llvm_unreachable("unexpected shorten vector length");
}
} else {
// If the Src is a scalar (not a vector) it must be updating one element.
unsigned InIdx = getAccessedFieldNo(0, Elts);
llvm::Value *Elt = llvm::ConstantInt::get(Int32Ty, InIdx);
- Vec = Builder.CreateInsertElement(Vec, SrcVal, Elt, "tmp");
+ Vec = Builder.CreateInsertElement(Vec, SrcVal, Elt);
}
Builder.CreateStore(Vec, Dst.getExtVectorAddr(), Dst.isVolatileQualified());
@@ -1203,11 +1213,23 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
// generating write-barries API. It is currently a global, ivar,
// or neither.
static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
- LValue &LV) {
- if (Ctx.getLangOptions().getGCMode() == LangOptions::NonGC)
+ LValue &LV,
+ bool IsMemberAccess=false) {
+ if (Ctx.getLangOptions().getGC() == LangOptions::NonGC)
return;
if (isa<ObjCIvarRefExpr>(E)) {
+ QualType ExpTy = E->getType();
+ if (IsMemberAccess && ExpTy->isPointerType()) {
+ // If ivar is a structure pointer, assigning to field of
+ // this struct follows gcc's behavior and makes it a non-ivar
+ // writer-barrier conservatively.
+ ExpTy = ExpTy->getAs<PointerType>()->getPointeeType();
+ if (ExpTy->isRecordType()) {
+ LV.setObjCIvar(false);
+ return;
+ }
+ }
LV.setObjCIvar(true);
ObjCIvarRefExpr *Exp = cast<ObjCIvarRefExpr>(const_cast<Expr*>(E));
LV.setBaseIvarExp(Exp->getBase());
@@ -1227,12 +1249,12 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
}
if (const UnaryOperator *Exp = dyn_cast<UnaryOperator>(E)) {
- setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
+ setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess);
return;
}
if (const ParenExpr *Exp = dyn_cast<ParenExpr>(E)) {
- setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
+ setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess);
if (LV.isObjCIvar()) {
// If cast is to a structure pointer, follow gcc's behavior and make it
// a non-ivar write-barrier.
@@ -1251,17 +1273,17 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
}
if (const ImplicitCastExpr *Exp = dyn_cast<ImplicitCastExpr>(E)) {
- setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
+ setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess);
return;
}
if (const CStyleCastExpr *Exp = dyn_cast<CStyleCastExpr>(E)) {
- setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
+ setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess);
return;
}
if (const ObjCBridgedCastExpr *Exp = dyn_cast<ObjCBridgedCastExpr>(E)) {
- setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
+ setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess);
return;
}
@@ -1277,9 +1299,9 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
LV.setGlobalObjCRef(false);
return;
}
-
+
if (const MemberExpr *Exp = dyn_cast<MemberExpr>(E)) {
- setObjCGCLValueClass(Ctx, Exp->getBase(), LV);
+ setObjCGCLValueClass(Ctx, Exp->getBase(), LV, true);
// We don't know if member is an 'ivar', but this flag is looked at
// only in the context of LV.isObjCIvar().
LV.setObjCArray(E->getType()->isArrayType());
@@ -1290,7 +1312,7 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
static llvm::Value *
EmitBitCastOfLValueToProperType(CodeGenFunction &CGF,
llvm::Value *V, llvm::Type *IRType,
- llvm::StringRef Name = llvm::StringRef()) {
+ StringRef Name = StringRef()) {
unsigned AS = cast<llvm::PointerType>(V->getType())->getAddressSpace();
return CGF.Builder.CreateBitCast(V, IRType->getPointerTo(AS), Name);
}
@@ -1302,7 +1324,7 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD);
if (VD->getType()->isReferenceType())
- V = CGF.Builder.CreateLoad(V, "tmp");
+ V = CGF.Builder.CreateLoad(V);
V = EmitBitCastOfLValueToProperType(CGF, V,
CGF.getTypes().ConvertTypeForMem(E->getType()));
@@ -1325,7 +1347,7 @@ static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF,
QualType NoProtoType =
CGF.getContext().getFunctionNoProtoType(Proto->getResultType());
NoProtoType = CGF.getContext().getPointerType(NoProtoType);
- V = CGF.Builder.CreateBitCast(V, CGF.ConvertType(NoProtoType), "tmp");
+ V = CGF.Builder.CreateBitCast(V, CGF.ConvertType(NoProtoType));
}
}
unsigned Alignment = CGF.getContext().getDeclAlign(FD).getQuantity();
@@ -1361,7 +1383,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
V = BuildBlockByrefAddress(V, VD);
if (VD->getType()->isReferenceType())
- V = Builder.CreateLoad(V, "tmp");
+ V = Builder.CreateLoad(V);
V = EmitBitCastOfLValueToProperType(*this, V,
getTypes().ConvertTypeForMem(E->getType()));
@@ -1378,7 +1400,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(ND))
return EmitFunctionDeclLValue(*this, E, fn);
- assert(false && "Unhandled DeclRefExpr");
+ llvm_unreachable("Unhandled DeclRefExpr");
// an invalid LValue, but the assert will
// ensure that this point is never reached.
@@ -1398,7 +1420,7 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
QualType ExprTy = getContext().getCanonicalType(E->getSubExpr()->getType());
switch (E->getOpcode()) {
- default: assert(0 && "Unknown unary operator lvalue!");
+ default: llvm_unreachable("Unknown unary operator lvalue!");
case UO_Deref: {
QualType T = E->getSubExpr()->getType()->getPointeeType();
assert(!T.isNull() && "CodeGenFunction::EmitUnaryOpLValue: Illegal type");
@@ -1411,7 +1433,7 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
// But, we continue to generate __strong write barrier on indirect write
// into a pointer to object.
if (getContext().getLangOptions().ObjC1 &&
- getContext().getLangOptions().getGCMode() != LangOptions::NonGC &&
+ getContext().getLangOptions().getGC() != LangOptions::NonGC &&
LV.isObjCWeak())
LV.setNonGC(!E->isOBJCGCCandidate(getContext()));
return LV;
@@ -1474,7 +1496,7 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
std::string GlobalVarName;
switch (Type) {
- default: assert(0 && "Invalid type");
+ default: llvm_unreachable("Invalid type");
case PredefinedExpr::Func:
GlobalVarName = "__func__.";
break;
@@ -1486,7 +1508,7 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
break;
}
- llvm::StringRef FnName = CurFn->getName();
+ StringRef FnName = CurFn->getName();
if (FnName.startswith("\01"))
FnName = FnName.substr(1);
GlobalVarName += FnName;
@@ -1646,9 +1668,9 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
ArrayAlignment = ArrayLV.getAlignment();
if (getContext().getLangOptions().isSignedOverflowDefined())
- Address = Builder.CreateGEP(ArrayPtr, Args, Args+2, "arrayidx");
+ Address = Builder.CreateGEP(ArrayPtr, Args, "arrayidx");
else
- Address = Builder.CreateInBoundsGEP(ArrayPtr, Args, Args+2, "arrayidx");
+ Address = Builder.CreateInBoundsGEP(ArrayPtr, Args, "arrayidx");
} else {
// The base must be a pointer, which is not an aggregate. Emit it.
llvm::Value *Base = EmitScalarExpr(E->getBase());
@@ -1672,7 +1694,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
LV.getQuals().setAddressSpace(E->getBase()->getType().getAddressSpace());
if (getContext().getLangOptions().ObjC1 &&
- getContext().getLangOptions().getGCMode() != LangOptions::NonGC) {
+ getContext().getLangOptions().getGC() != LangOptions::NonGC) {
LV.setNonGC(!E->isOBJCGCCandidate(getContext()));
setObjCGCLValueClass(getContext(), E, LV);
}
@@ -1681,10 +1703,10 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
static
llvm::Constant *GenerateConstantVector(llvm::LLVMContext &VMContext,
- llvm::SmallVector<unsigned, 4> &Elts) {
- llvm::SmallVector<llvm::Constant*, 4> CElts;
+ SmallVector<unsigned, 4> &Elts) {
+ SmallVector<llvm::Constant*, 4> CElts;
- const llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext);
+ llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext);
for (unsigned i = 0, e = Elts.size(); i != e; ++i)
CElts.push_back(llvm::ConstantInt::get(Int32Ty, Elts[i]));
@@ -1725,7 +1747,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
E->getType().withCVRQualifiers(Base.getQuals().getCVRQualifiers());
// Encode the element access list into a vector of unsigned indices.
- llvm::SmallVector<unsigned, 4> Indices;
+ SmallVector<unsigned, 4> Indices;
E->getEncodedElementAccess(Indices);
if (Base.isSimple()) {
@@ -1735,7 +1757,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
assert(Base.isExtVectorElt() && "Can only subscript lvalue vec elts here!");
llvm::Constant *BaseElts = Base.getExtVectorElts();
- llvm::SmallVector<llvm::Constant *, 4> CElts;
+ SmallVector<llvm::Constant *, 4> CElts;
for (unsigned i = 0, e = Indices.size(); i != e; ++i) {
if (isa<llvm::ConstantAggregateZero>(BaseElts))
@@ -1784,8 +1806,7 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
return EmitFunctionDeclLValue(*this, E, FD);
- assert(false && "Unhandled member declaration!");
- return LValue();
+ llvm_unreachable("Unhandled member declaration!");
}
LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value *BaseValue,
@@ -1867,6 +1888,9 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value *baseAddr,
CGM.getTypes().ConvertTypeForMem(type),
field->getName());
+ if (field->hasAttr<AnnotateAttr>())
+ addr = EmitFieldAnnotations(field, addr);
+
unsigned alignment = getContext().getDeclAlign(field).getQuantity();
LValue LV = MakeAddrLValue(addr, type, alignment);
LV.getQuals().addCVRQualifiers(cvr);
@@ -1896,7 +1920,7 @@ CodeGenFunction::EmitLValueForFieldInitialization(llvm::Value *BaseValue,
const CGRecordLayout &RL =
CGM.getTypes().getCGRecordLayout(Field->getParent());
unsigned idx = RL.getLLVMFieldNo(Field);
- llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx, "tmp");
+ llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx);
assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs");
@@ -1904,7 +1928,7 @@ CodeGenFunction::EmitLValueForFieldInitialization(llvm::Value *BaseValue,
// for both unions and structs. A union needs a bitcast, a struct element
// will need a bitcast if the LLVM type laid out doesn't match the desired
// type.
- const llvm::Type *llvmType = ConvertTypeForMem(FieldType);
+ llvm::Type *llvmType = ConvertTypeForMem(FieldType);
unsigned AS = cast<llvm::PointerType>(V->getType())->getAddressSpace();
V = Builder.CreateBitCast(V, llvmType->getPointerTo(AS));
@@ -2048,9 +2072,10 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_BaseToDerivedMemberPointer:
case CK_MemberPointerToBoolean:
case CK_AnyPointerToBlockPointerCast:
- case CK_ObjCProduceObject:
- case CK_ObjCConsumeObject:
- case CK_ObjCReclaimReturnedObject: {
+ case CK_ARCProduceObject:
+ case CK_ARCConsumeObject:
+ case CK_ARCReclaimReturnedObject:
+ case CK_ARCExtendBlockObject: {
// These casts only produce lvalues when we're binding a reference to a
// temporary realized from a (converted) pure rvalue. Emit the expression
// as a value, copy it into a temporary, and return an lvalue referring to
@@ -2069,7 +2094,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_ConstructorConversion:
case CK_UserDefinedConversion:
- case CK_AnyPointerToObjCPointerCast:
+ case CK_CPointerToObjCPointerCast:
+ case CK_BlockPointerToObjCPointerCast:
return EmitLValue(E->getSubExpr());
case CK_UncheckedDerivedToBase:
@@ -2143,8 +2169,7 @@ LValue CodeGenFunction::EmitOpaqueValueLValue(const OpaqueValueExpr *e) {
LValue CodeGenFunction::EmitMaterializeTemporaryExpr(
const MaterializeTemporaryExpr *E) {
- RValue RV = EmitReferenceBindingToExpr(E->GetTemporaryExpr(),
- /*InitializedDecl=*/0);
+ RValue RV = EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0);
return MakeAddrLValue(RV.getScalarVal(), E->getType());
}
@@ -2155,11 +2180,8 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr(
RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
ReturnValueSlot ReturnValue) {
- if (CGDebugInfo *DI = getDebugInfo()) {
- DI->setLocation(E->getLocStart());
- DI->UpdateLineDirectiveRegion(Builder);
- DI->EmitStopPoint(Builder);
- }
+ if (CGDebugInfo *DI = getDebugInfo())
+ DI->EmitLocation(Builder, E->getLocStart());
// Builtins never have block type.
if (E->getCallee()->getType()->isBlockPointerType())
@@ -2168,14 +2190,13 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
if (const CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(E))
return EmitCXXMemberCallExpr(CE, ReturnValue);
- const Decl *TargetDecl = 0;
- if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E->getCallee())) {
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) {
- TargetDecl = DRE->getDecl();
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(TargetDecl))
- if (unsigned builtinID = FD->getBuiltinID())
- return EmitBuiltinExpr(FD, builtinID, E);
- }
+ if (const CUDAKernelCallExpr *CE = dyn_cast<CUDAKernelCallExpr>(E))
+ return EmitCUDAKernelCallExpr(CE, ReturnValue);
+
+ const Decl *TargetDecl = E->getCalleeDecl();
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl)) {
+ if (unsigned builtinID = FD->getBuiltinID())
+ return EmitBuiltinExpr(FD, builtinID, E);
}
if (const CXXOperatorCallExpr *CE = dyn_cast<CXXOperatorCallExpr>(E))
@@ -2306,7 +2327,7 @@ LValue CodeGenFunction::EmitVAArgExprLValue(const VAArgExpr *E) {
LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) {
assert(E->getType()->getAsCXXRecordDecl()->hasTrivialDestructor()
&& "binding l-value to type which needs a temporary");
- AggValueSlot Slot = CreateAggTemp(E->getType(), "tmp");
+ AggValueSlot Slot = CreateAggTemp(E->getType());
EmitCXXConstructExpr(E, Slot);
return MakeAddrLValue(Slot.getAddr(), E->getType());
}
@@ -2319,7 +2340,7 @@ CodeGenFunction::EmitCXXTypeidLValue(const CXXTypeidExpr *E) {
LValue
CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) {
AggValueSlot Slot = CreateAggTemp(E->getType(), "temp.lvalue");
- Slot.setLifetimeExternallyManaged();
+ Slot.setExternallyDestructed();
EmitAggExpr(E->getSubExpr(), Slot);
EmitCXXTemporary(E->getTemporary(), Slot.getAddr());
return MakeAddrLValue(Slot.getAddr(), E->getType());
@@ -2406,8 +2427,35 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
CallArgList Args;
EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), ArgBeg, ArgEnd);
- return EmitCall(CGM.getTypes().getFunctionInfo(Args, FnType),
- Callee, ReturnValue, Args, TargetDecl);
+ const CGFunctionInfo &FnInfo = CGM.getTypes().getFunctionInfo(Args, FnType);
+
+ // C99 6.5.2.2p6:
+ // If the expression that denotes the called function has a type
+ // that does not include a prototype, [the default argument
+ // promotions are performed]. If the number of arguments does not
+ // equal the number of parameters, the behavior is undefined. If
+ // the function is defined with a type that includes a prototype,
+ // and either the prototype ends with an ellipsis (, ...) or the
+ // types of the arguments after promotion are not compatible with
+ // the types of the parameters, the behavior is undefined. If the
+ // function is defined with a type that does not include a
+ // prototype, and the types of the arguments after promotion are
+ // not compatible with those of the parameters after promotion,
+ // the behavior is undefined [except in some trivial cases].
+ // That is, in the general case, we should assume that a call
+ // 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) &&
+ !getTargetHooks().isNoProtoCallVariadic(FnType->getCallConv())) {
+ assert(cast<llvm::FunctionType>(Callee->getType()->getContainedType(0))
+ ->isVarArg());
+ llvm::Type *CalleeTy = getTypes().GetFunctionType(FnInfo, false);
+ CalleeTy = CalleeTy->getPointerTo();
+ Callee = Builder.CreateBitCast(Callee, CalleeTy, "callee.knr.cast");
+ }
+
+ return EmitCall(FnInfo, Callee, ReturnValue, Args, TargetDecl);
}
LValue CodeGenFunction::
@@ -2428,3 +2476,279 @@ 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) {
+ if (E->isCmpXChg()) {
+ // 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;
+ }
+
+ if (E->getOp() == AtomicExpr::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;
+ }
+
+ if (E->getOp() == AtomicExpr::Store) {
+ 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;
+ }
+
+ llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add;
+ switch (E->getOp()) {
+ case AtomicExpr::CmpXchgWeak:
+ case AtomicExpr::CmpXchgStrong:
+ case AtomicExpr::Store:
+ case AtomicExpr::Load: assert(0 && "Already handled!");
+ case AtomicExpr::Add: Op = llvm::AtomicRMWInst::Add; break;
+ case AtomicExpr::Sub: Op = llvm::AtomicRMWInst::Sub; break;
+ case AtomicExpr::And: Op = llvm::AtomicRMWInst::And; break;
+ case AtomicExpr::Or: Op = llvm::AtomicRMWInst::Or; break;
+ case AtomicExpr::Xor: Op = llvm::AtomicRMWInst::Xor; break;
+ case AtomicExpr::Xchg: Op = llvm::AtomicRMWInst::Xchg; 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());
+ llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(RMWI, 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->getAs<AtomicType>()->getValueType();
+ CharUnits sizeChars = getContext().getTypeSizeInChars(AtomicTy);
+ uint64_t Size = sizeChars.getQuantity();
+ CharUnits alignChars = getContext().getTypeAlignInChars(AtomicTy);
+ unsigned Align = alignChars.getQuantity();
+ unsigned MaxInlineWidth =
+ getContext().getTargetInfo().getMaxAtomicInlineWidth();
+ bool UseLibcall = (Size != Align || Size > MaxInlineWidth);
+
+ llvm::Value *Ptr, *Order, *OrderFail = 0, *Val1 = 0, *Val2 = 0;
+ Ptr = EmitScalarExpr(E->getPtr());
+ Order = EmitScalarExpr(E->getOrder());
+ if (E->isCmpXChg()) {
+ Val1 = EmitScalarExpr(E->getVal1());
+ Val2 = EmitValToTemp(*this, E->getVal2());
+ OrderFail = EmitScalarExpr(E->getOrderFail());
+ (void)OrderFail; // OrderFail is unused at the moment
+ } else if ((E->getOp() == AtomicExpr::Add || E->getOp() == AtomicExpr::Sub) &&
+ MemTy->isPointerType()) {
+ // For pointers, 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.
+ 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));
+ } else if (E->getOp() != AtomicExpr::Load) {
+ Val1 = EmitValToTemp(*this, E->getVal1());
+ }
+
+ if (E->getOp() != AtomicExpr::Store && !Dest)
+ Dest = CreateMemTemp(E->getType(), ".atomicdst");
+
+ if (UseLibcall) {
+ // FIXME: Finalize what the libcalls are actually supposed to look like.
+ // See also http://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary .
+ return EmitUnsupportedRValue(E, "atomic library call");
+ }
+#if 0
+ if (UseLibcall) {
+ const char* LibCallName;
+ switch (E->getOp()) {
+ case AtomicExpr::CmpXchgWeak:
+ LibCallName = "__atomic_compare_exchange_generic"; break;
+ case AtomicExpr::CmpXchgStrong:
+ LibCallName = "__atomic_compare_exchange_generic"; break;
+ 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;
+ case AtomicExpr::Xchg: LibCallName = "__atomic_exchange_generic"; break;
+ case AtomicExpr::Store: LibCallName = "__atomic_store_generic"; break;
+ case AtomicExpr::Load: LibCallName = "__atomic_load_generic"; break;
+ }
+ llvm::SmallVector<QualType, 4> Params;
+ CallArgList Args;
+ QualType RetTy = getContext().VoidTy;
+ if (E->getOp() != AtomicExpr::Store && !E->isCmpXChg())
+ Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
+ getContext().VoidPtrTy);
+ Args.add(RValue::get(EmitCastToVoidPtr(Ptr)),
+ getContext().VoidPtrTy);
+ if (E->getOp() != AtomicExpr::Load)
+ Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
+ getContext().VoidPtrTy);
+ if (E->isCmpXChg()) {
+ Args.add(RValue::get(EmitCastToVoidPtr(Val2)),
+ getContext().VoidPtrTy);
+ RetTy = getContext().IntTy;
+ }
+ Args.add(RValue::get(llvm::ConstantInt::get(SizeTy, Size)),
+ getContext().getSizeType());
+ const CGFunctionInfo &FuncInfo =
+ CGM.getTypes().getFunctionInfo(RetTy, Args, FunctionType::ExtInfo());
+ llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FuncInfo, false);
+ llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, LibCallName);
+ RValue Res = EmitCall(FuncInfo, Func, ReturnValueSlot(), Args);
+ if (E->isCmpXChg())
+ return Res;
+ if (E->getOp() == AtomicExpr::Store)
+ return RValue::get(0);
+ return ConvertTempToRValue(*this, E->getType(), Dest);
+ }
+#endif
+ 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
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Acquire);
+ break;
+ case 3: // memory_order_release
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Release);
+ break;
+ case 4: // memory_order_acq_rel
+ 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->getOp() == AtomicExpr::Store)
+ 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 (E->getOp() != AtomicExpr::Store)
+ AcquireBB = createBasicBlock("acquire", CurFn);
+ if (E->getOp() != AtomicExpr::Load)
+ ReleaseBB = createBasicBlock("release", CurFn);
+ if (E->getOp() != AtomicExpr::Load && E->getOp() != AtomicExpr::Store)
+ 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 (E->getOp() != AtomicExpr::Store) {
+ 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 (E->getOp() != AtomicExpr::Load) {
+ Builder.SetInsertPoint(ReleaseBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Release);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(3), ReleaseBB);
+ }
+ if (E->getOp() != AtomicExpr::Load && E->getOp() != AtomicExpr::Store) {
+ 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->getOp() == AtomicExpr::Store)
+ return RValue::get(0);
+ return ConvertTempToRValue(*this, E->getType(), OrigDest);
+}
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 915ffd6034e2..97754d5c0ba6 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -35,11 +35,18 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
AggValueSlot Dest;
bool IgnoreResult;
+ /// We want to use 'dest' as the return slot except under two
+ /// conditions:
+ /// - The destination slot requires garbage collection, so we
+ /// need to use the GC API.
+ /// - The destination slot is potentially aliased.
+ bool shouldUseDestForReturnSlot() const {
+ return !(Dest.requiresGCollection() || Dest.isPotentiallyAliased());
+ }
+
ReturnValueSlot getReturnValueSlot() const {
- // If the destination slot requires garbage collection, we can't
- // use the real return value slot, because we have to use the GC
- // API.
- if (Dest.requiresGCollection()) return ReturnValueSlot();
+ if (!shouldUseDestForReturnSlot())
+ return ReturnValueSlot();
return ReturnValueSlot(Dest.getAddr(), Dest.isVolatile());
}
@@ -69,7 +76,13 @@ public:
void EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore = false);
void EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore = false);
- void EmitGCMove(const Expr *E, RValue Src);
+ void EmitMoveFromReturnSlot(const Expr *E, RValue Src);
+
+ AggValueSlot::NeedsGCBarriers_t needsGC(QualType T) {
+ if (CGF.getLangOptions().getGC() && TypeRequiresGCollection(T))
+ return AggValueSlot::NeedsGCBarriers;
+ return AggValueSlot::DoesNotNeedGCBarriers;
+ }
bool TypeRequiresGCollection(QualType T);
@@ -141,6 +154,9 @@ public:
void EmitNullInitializationToLValue(LValue Address);
// case Expr::ChooseExprClass:
void VisitCXXThrowExpr(const CXXThrowExpr *E) { CGF.EmitCXXThrowExpr(E); }
+ void VisitAtomicExpr(AtomicExpr *E) {
+ CGF.EmitAtomicExpr(E, EnsureSlot(E->getType()).getAddr());
+ }
};
} // end anonymous namespace.
@@ -173,23 +189,27 @@ bool AggExprEmitter::TypeRequiresGCollection(QualType T) {
return Record->hasObjectMember();
}
-/// \brief Perform the final move to DestPtr if RequiresGCollection is set.
+/// \brief Perform the final move to DestPtr if for some reason
+/// getReturnValueSlot() didn't use it directly.
///
/// The idea is that you do something like this:
/// RValue Result = EmitSomething(..., getReturnValueSlot());
-/// EmitGCMove(E, Result);
-/// If GC doesn't interfere, this will cause the result to be emitted
-/// directly into the return value slot. If GC does interfere, a final
-/// move will be performed.
-void AggExprEmitter::EmitGCMove(const Expr *E, RValue Src) {
- if (Dest.requiresGCollection()) {
- CharUnits size = CGF.getContext().getTypeSizeInChars(E->getType());
- const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
- llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size.getQuantity());
- CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, Dest.getAddr(),
- Src.getAggregateAddr(),
- SizeVal);
+/// EmitMoveFromReturnSlot(E, Result);
+///
+/// If nothing interferes, this will cause the result to be emitted
+/// directly into the return value slot. Otherwise, a final move
+/// will be performed.
+void AggExprEmitter::EmitMoveFromReturnSlot(const Expr *E, RValue Src) {
+ if (shouldUseDestForReturnSlot()) {
+ // Logically, Dest.getAddr() should equal Src.getAggregateAddr().
+ // The possibility of undef rvalues complicates that a lot,
+ // though, so we can't really assert.
+ return;
}
+
+ // Otherwise, do a final copy,
+ assert(Dest.getAddr() != Src.getAggregateAddr());
+ EmitFinalDestCopy(E, Src, /*Ignore*/ true);
}
/// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
@@ -215,7 +235,7 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) {
if (Dest.requiresGCollection()) {
CharUnits size = CGF.getContext().getTypeSizeInChars(E->getType());
- const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
+ llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size.getQuantity());
CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF,
Dest.getAddr(),
@@ -301,16 +321,15 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_DerivedToBase:
case CK_BaseToDerived:
case CK_UncheckedDerivedToBase: {
- assert(0 && "cannot perform hierarchy conversion in EmitAggExpr: "
+ llvm_unreachable("cannot perform hierarchy conversion in EmitAggExpr: "
"should have been unpacked before we got here");
- break;
}
case CK_GetObjCProperty: {
LValue LV = CGF.EmitLValue(E->getSubExpr());
assert(LV.isPropertyRef());
RValue RV = CGF.EmitLoadOfPropertyRefLValue(LV, getReturnValueSlot());
- EmitGCMove(E, RV);
+ EmitMoveFromReturnSlot(E, RV);
break;
}
@@ -348,7 +367,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_FloatingToIntegral:
case CK_FloatingToBoolean:
case CK_FloatingCast:
- case CK_AnyPointerToObjCPointerCast:
+ case CK_CPointerToObjCPointerCast:
+ case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
case CK_ObjCObjectLValueCast:
case CK_FloatingRealToComplex:
@@ -361,9 +381,10 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_IntegralComplexToBoolean:
case CK_IntegralComplexCast:
case CK_IntegralComplexToFloatingComplex:
- case CK_ObjCProduceObject:
- case CK_ObjCConsumeObject:
- case CK_ObjCReclaimReturnedObject:
+ case CK_ARCProduceObject:
+ case CK_ARCConsumeObject:
+ case CK_ARCReclaimReturnedObject:
+ case CK_ARCExtendBlockObject:
llvm_unreachable("cast kind invalid for aggregate types");
}
}
@@ -375,12 +396,12 @@ void AggExprEmitter::VisitCallExpr(const CallExpr *E) {
}
RValue RV = CGF.EmitCallExpr(E, getReturnValueSlot());
- EmitGCMove(E, RV);
+ EmitMoveFromReturnSlot(E, RV);
}
void AggExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
RValue RV = CGF.EmitObjCMessageExpr(E, getReturnValueSlot());
- EmitGCMove(E, RV);
+ EmitMoveFromReturnSlot(E, RV);
}
void AggExprEmitter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
@@ -426,10 +447,9 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
// as it may change the 'forwarding' field via call to Block_copy.
LValue RHS = CGF.EmitLValue(E->getRHS());
LValue LHS = CGF.EmitLValue(E->getLHS());
- bool GCollection = false;
- if (CGF.getContext().getLangOptions().getGCMode())
- GCollection = TypeRequiresGCollection(E->getLHS()->getType());
- Dest = AggValueSlot::forLValue(LHS, true, GCollection);
+ Dest = AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
+ needsGC(E->getLHS()->getType()),
+ AggValueSlot::IsAliased);
EmitFinalDestCopy(E, RHS, true);
return;
}
@@ -451,13 +471,11 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
}
CGF.EmitStoreThroughPropertyRefLValue(Src, LHS);
} else {
- bool GCollection = false;
- if (CGF.getContext().getLangOptions().getGCMode())
- GCollection = TypeRequiresGCollection(E->getLHS()->getType());
-
// Codegen the RHS so that it stores directly into the LHS.
- AggValueSlot LHSSlot = AggValueSlot::forLValue(LHS, true,
- GCollection);
+ AggValueSlot LHSSlot =
+ AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
+ needsGC(E->getLHS()->getType()),
+ AggValueSlot::IsAliased);
CGF.EmitAggExpr(E->getRHS(), LHSSlot, false);
EmitFinalDestCopy(E, LHS, true);
}
@@ -476,7 +494,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
// Save whether the destination's lifetime is externally managed.
- bool DestLifetimeManaged = Dest.isLifetimeExternallyManaged();
+ bool isExternallyDestructed = Dest.isExternallyDestructed();
eval.begin(CGF);
CGF.EmitBlock(LHSBlock);
@@ -489,8 +507,8 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
// If the result of an agg expression is unused, then the emission
// of the LHS might need to create a destination slot. That's fine
// with us, and we can safely emit the RHS into the same slot, but
- // we shouldn't claim that its lifetime is externally managed.
- Dest.setLifetimeExternallyManaged(DestLifetimeManaged);
+ // we shouldn't claim that it's already being destructed.
+ Dest.setExternallyDestructed(isExternallyDestructed);
eval.begin(CGF);
CGF.EmitBlock(RHSBlock);
@@ -518,16 +536,17 @@ void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
void AggExprEmitter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
// Ensure that we have a slot, but if we already do, remember
- // whether its lifetime was externally managed.
- bool WasManaged = Dest.isLifetimeExternallyManaged();
+ // whether it was externally destructed.
+ bool wasExternallyDestructed = Dest.isExternallyDestructed();
Dest = EnsureSlot(E->getType());
- Dest.setLifetimeExternallyManaged();
+
+ // We're going to push a destructor if there isn't already one.
+ Dest.setExternallyDestructed();
Visit(E->getSubExpr());
- // Set up the temporary's destructor if its lifetime wasn't already
- // being managed.
- if (!WasManaged)
+ // Push that destructor we promised.
+ if (!wasExternallyDestructed)
CGF.EmitCXXTemporary(E->getTemporary(), Dest.getAddr());
}
@@ -596,7 +615,10 @@ AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) {
} else if (type->isAnyComplexType()) {
CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false);
} else if (CGF.hasAggregateLLVMType(type)) {
- CGF.EmitAggExpr(E, AggValueSlot::forLValue(LV, true, false,
+ 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);
@@ -647,9 +669,9 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
// Handle initialization of an array.
if (E->getType()->isArrayType()) {
- const llvm::PointerType *APType =
+ llvm::PointerType *APType =
cast<llvm::PointerType>(DestPtr->getType());
- const llvm::ArrayType *AType =
+ llvm::ArrayType *AType =
cast<llvm::ArrayType>(APType->getElementType());
uint64_t NumInitElements = E->getNumInits();
@@ -676,7 +698,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0);
llvm::Value *indices[] = { zero, zero };
llvm::Value *begin =
- Builder.CreateInBoundsGEP(DestPtr, indices, indices+2, "arrayinit.begin");
+ Builder.CreateInBoundsGEP(DestPtr, indices, "arrayinit.begin");
// Exception safety requires us to destroy all the
// already-constructed members if an initializer throws.
@@ -839,7 +861,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
// We'll need to enter cleanup scopes in case any of the member
// initializers throw an exception.
- llvm::SmallVector<EHScopeStack::stable_iterator, 16> cleanups;
+ SmallVector<EHScopeStack::stable_iterator, 16> cleanups;
// Here we iterate over the fields; this makes it simpler to both
// default-initialize fields and skip over unnamed fields.
@@ -948,7 +970,7 @@ static CharUnits GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
// Reference values are always non-null and have the width of a pointer.
if (Field->getType()->isReferenceType())
NumNonZeroBytes += CGF.getContext().toCharUnitsFromBits(
- CGF.getContext().Target.getPointerWidth(0));
+ CGF.getContext().getTargetInfo().getPointerWidth(0));
else
NumNonZeroBytes += GetNumNonZeroBytesInInit(E, CGF);
}
@@ -999,7 +1021,7 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
CharUnits Align = TypeInfo.second;
llvm::Value *Loc = Slot.getAddr();
- const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
Loc = CGF.Builder.CreateBitCast(Loc, BP);
CGF.Builder.CreateMemSet(Loc, CGF.Builder.getInt8(0), SizeVal,
@@ -1036,7 +1058,9 @@ LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) {
assert(hasAggregateLLVMType(E->getType()) && "Invalid argument!");
llvm::Value *Temp = CreateMemTemp(E->getType());
LValue LV = MakeAddrLValue(Temp, E->getType());
- EmitAggExpr(E, AggValueSlot::forLValue(LV, false));
+ EmitAggExpr(E, AggValueSlot::forLValue(LV, AggValueSlot::IsNotDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased));
return LV;
}
@@ -1049,7 +1073,9 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
if (const RecordType *RT = Ty->getAs<RecordType>()) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl());
assert((Record->hasTrivialCopyConstructor() ||
- Record->hasTrivialCopyAssignment()) &&
+ Record->hasTrivialCopyAssignment() ||
+ Record->hasTrivialMoveConstructor() ||
+ Record->hasTrivialMoveAssignment()) &&
"Trying to aggregate-copy a type without a trivial copy "
"constructor or assignment operator");
// Ignore empty classes in C++.
@@ -1088,24 +1114,24 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
// we need to use a different call here. We use isVolatile to indicate when
// either the source or the destination is volatile.
- const llvm::PointerType *DPT = cast<llvm::PointerType>(DestPtr->getType());
- const llvm::Type *DBP =
+ llvm::PointerType *DPT = cast<llvm::PointerType>(DestPtr->getType());
+ llvm::Type *DBP =
llvm::Type::getInt8PtrTy(getLLVMContext(), DPT->getAddressSpace());
- DestPtr = Builder.CreateBitCast(DestPtr, DBP, "tmp");
+ DestPtr = Builder.CreateBitCast(DestPtr, DBP);
- const llvm::PointerType *SPT = cast<llvm::PointerType>(SrcPtr->getType());
- const llvm::Type *SBP =
+ llvm::PointerType *SPT = cast<llvm::PointerType>(SrcPtr->getType());
+ llvm::Type *SBP =
llvm::Type::getInt8PtrTy(getLLVMContext(), SPT->getAddressSpace());
- SrcPtr = Builder.CreateBitCast(SrcPtr, SBP, "tmp");
+ SrcPtr = Builder.CreateBitCast(SrcPtr, SBP);
// Don't do any of the memmove_collectable tests if GC isn't set.
- if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC) {
+ if (CGM.getLangOptions().getGC() == LangOptions::NonGC) {
// fall through
} else if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
RecordDecl *Record = RecordTy->getDecl();
if (Record->hasObjectMember()) {
CharUnits size = TypeInfo.first;
- const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
+ llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size.getQuantity());
CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr,
SizeVal);
@@ -1116,7 +1142,7 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) {
if (RecordTy->getDecl()->hasObjectMember()) {
CharUnits size = TypeInfo.first;
- const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
+ llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
llvm::Value *SizeVal =
llvm::ConstantInt::get(SizeTy, size.getQuantity());
CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr,
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 4396f567f2f9..78db5903de54 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -13,6 +13,7 @@
#include "clang/Frontend/CodeGenOptions.h"
#include "CodeGenFunction.h"
+#include "CGCUDARuntime.h"
#include "CGCXXABI.h"
#include "CGObjCRuntime.h"
#include "CGDebugInfo.h"
@@ -206,16 +207,17 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
cast<CXXConstructorDecl>(MD)->isDefaultConstructor())
return RValue::get(0);
- if (MD->isCopyAssignmentOperator()) {
- // We don't like to generate the trivial copy assignment operator when
- // it isn't necessary; just produce the proper effect here.
+ if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) {
+ // We don't like to generate the trivial copy/move assignment operator
+ // when it isn't necessary; just produce the proper effect here.
llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress();
EmitAggregateCopy(This, RHS, CE->getType());
return RValue::get(This);
}
if (isa<CXXConstructorDecl>(MD) &&
- cast<CXXConstructorDecl>(MD)->isCopyConstructor()) {
+ cast<CXXConstructorDecl>(MD)->isCopyOrMoveConstructor()) {
+ // Trivial move and copy ctor are the same.
llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress();
EmitSynthesizedCXXCopyCtorCall(cast<CXXConstructorDecl>(MD), This, RHS,
CE->arg_begin(), CE->arg_end());
@@ -236,7 +238,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
FInfo = &CGM.getTypes().getFunctionInfo(MD);
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::Type *Ty
+ llvm::Type *Ty
= CGM.getTypes().GetFunctionType(*FInfo, FPT->isVariadic());
// C++ [class.virtual]p12:
@@ -333,16 +335,12 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
LValue LV = EmitLValue(E->getArg(0));
llvm::Value *This = LV.getAddress();
- if (MD->isCopyAssignmentOperator()) {
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(MD->getDeclContext());
- if (ClassDecl->hasTrivialCopyAssignment()) {
- assert(!ClassDecl->hasUserDeclaredCopyAssignment() &&
- "EmitCXXOperatorMemberCallExpr - user declared copy assignment");
- llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress();
- QualType Ty = E->getType();
- EmitAggregateCopy(This, Src, Ty);
- return RValue::get(This);
- }
+ if ((MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) &&
+ MD->isTrivial()) {
+ llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress();
+ QualType Ty = E->getType();
+ EmitAggregateCopy(This, Src, Ty);
+ return RValue::get(This);
}
llvm::Value *Callee = EmitCXXOperatorMemberCallee(E, MD, This);
@@ -350,6 +348,54 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
E->arg_begin() + 1, E->arg_end());
}
+RValue CodeGenFunction::EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E,
+ ReturnValueSlot ReturnValue) {
+ return CGM.getCUDARuntime().EmitCUDAKernelCallExpr(*this, E, ReturnValue);
+}
+
+static void EmitNullBaseClassInitialization(CodeGenFunction &CGF,
+ llvm::Value *DestPtr,
+ const CXXRecordDecl *Base) {
+ if (Base->isEmpty())
+ return;
+
+ DestPtr = CGF.EmitCastToVoidPtr(DestPtr);
+
+ const ASTRecordLayout &Layout = CGF.getContext().getASTRecordLayout(Base);
+ CharUnits Size = Layout.getNonVirtualSize();
+ CharUnits Align = Layout.getNonVirtualAlign();
+
+ llvm::Value *SizeVal = CGF.CGM.getSize(Size);
+
+ // If the type contains a pointer to data member we can't memset it to zero.
+ // Instead, create a null constant and copy it to the destination.
+ // TODO: there are other patterns besides zero that we can usefully memset,
+ // like -1, which happens to be the pattern used by member-pointers.
+ // TODO: isZeroInitializable can be over-conservative in the case where a
+ // virtual base contains a member pointer.
+ if (!CGF.CGM.getTypes().isZeroInitializable(Base)) {
+ llvm::Constant *NullConstant = CGF.CGM.EmitNullConstantForBase(Base);
+
+ llvm::GlobalVariable *NullVariable =
+ new llvm::GlobalVariable(CGF.CGM.getModule(), NullConstant->getType(),
+ /*isConstant=*/true,
+ llvm::GlobalVariable::PrivateLinkage,
+ NullConstant, Twine());
+ NullVariable->setAlignment(Align.getQuantity());
+ llvm::Value *SrcPtr = CGF.EmitCastToVoidPtr(NullVariable);
+
+ // Get and call the appropriate llvm.memcpy overload.
+ CGF.Builder.CreateMemCpy(DestPtr, SrcPtr, SizeVal, Align.getQuantity());
+ 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.
+ CGF.Builder.CreateMemSet(DestPtr, CGF.Builder.getInt8(0), SizeVal,
+ Align.getQuantity());
+}
+
void
CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
AggValueSlot Dest) {
@@ -360,8 +406,19 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
// constructor, as can be the case with a non-user-provided default
// constructor, emit the zero initialization now, unless destination is
// already zeroed.
- if (E->requiresZeroInitialization() && !Dest.isZeroed())
- EmitNullInitialization(Dest.getAddr(), E->getType());
+ if (E->requiresZeroInitialization() && !Dest.isZeroed()) {
+ switch (E->getConstructionKind()) {
+ case CXXConstructExpr::CK_Delegating:
+ assert(0 && "Delegating constructor should not need zeroing");
+ case CXXConstructExpr::CK_Complete:
+ EmitNullInitialization(Dest.getAddr(), E->getType());
+ break;
+ case CXXConstructExpr::CK_VirtualBase:
+ case CXXConstructExpr::CK_NonVirtualBase:
+ EmitNullBaseClassInitialization(*this, Dest.getAddr(), CD->getParent());
+ break;
+ }
+ }
// If this is a call to a trivial default constructor, do nothing.
if (CD->isTrivial() && CD->isDefaultConstructor())
@@ -483,7 +540,7 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
// the cookie size would bring the total size >= 0.
bool isSigned
= e->getArraySize()->getType()->isSignedIntegerOrEnumerationType();
- const llvm::IntegerType *numElementsType
+ llvm::IntegerType *numElementsType
= cast<llvm::IntegerType>(numElements->getType());
unsigned numElementsWidth = numElementsType->getBitWidth();
@@ -703,63 +760,85 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const CXXNewExpr *E,
AllocType.isVolatileQualified());
else {
AggValueSlot Slot
- = AggValueSlot::forAddr(NewPtr, AllocType.getQualifiers(), true);
+ = AggValueSlot::forAddr(NewPtr, AllocType.getQualifiers(),
+ AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased);
CGF.EmitAggExpr(Init, Slot);
}
}
void
CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E,
- llvm::Value *NewPtr,
- llvm::Value *NumElements) {
+ QualType elementType,
+ llvm::Value *beginPtr,
+ llvm::Value *numElements) {
// We have a POD type.
if (E->getNumConstructorArgs() == 0)
return;
-
- const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
-
- // Create a temporary for the loop index and initialize it with 0.
- llvm::Value *IndexPtr = CreateTempAlloca(SizeTy, "loop.index");
- llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy);
- Builder.CreateStore(Zero, IndexPtr);
-
- // Start the loop with a block that tests the condition.
- llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
- llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
-
- EmitBlock(CondBlock);
-
- llvm::BasicBlock *ForBody = createBasicBlock("for.body");
-
- // Generate: if (loop-index < number-of-elements fall to the loop body,
- // otherwise, go to the block after the for-loop.
- llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
- llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElements, "isless");
- // If the condition is true, execute the body.
- Builder.CreateCondBr(IsLess, ForBody, AfterFor);
-
- EmitBlock(ForBody);
-
- llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
- // Inside the loop body, emit the constructor call on the array element.
- Counter = Builder.CreateLoad(IndexPtr);
- llvm::Value *Address = Builder.CreateInBoundsGEP(NewPtr, Counter,
- "arrayidx");
- StoreAnyExprIntoOneUnit(*this, E, Address);
-
- EmitBlock(ContinueBlock);
-
- // Emit the increment of the loop counter.
- llvm::Value *NextVal = llvm::ConstantInt::get(SizeTy, 1);
- Counter = Builder.CreateLoad(IndexPtr);
- NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
- Builder.CreateStore(NextVal, IndexPtr);
-
- // Finally, branch back up to the condition for the next iteration.
- EmitBranch(CondBlock);
-
- // Emit the fall-through block.
- EmitBlock(AfterFor, true);
+
+ // Check if the number of elements is constant.
+ bool checkZero = true;
+ if (llvm::ConstantInt *constNum = dyn_cast<llvm::ConstantInt>(numElements)) {
+ // If it's constant zero, skip the whole loop.
+ if (constNum->isZero()) return;
+
+ checkZero = false;
+ }
+
+ // Find the end of the array, hoisted out of the loop.
+ llvm::Value *endPtr =
+ Builder.CreateInBoundsGEP(beginPtr, numElements, "array.end");
+
+ // Create the continuation block.
+ llvm::BasicBlock *contBB = createBasicBlock("new.loop.end");
+
+ // If we need to check for zero, do so now.
+ if (checkZero) {
+ llvm::BasicBlock *nonEmptyBB = createBasicBlock("new.loop.nonempty");
+ llvm::Value *isEmpty = Builder.CreateICmpEQ(beginPtr, endPtr,
+ "array.isempty");
+ Builder.CreateCondBr(isEmpty, contBB, nonEmptyBB);
+ EmitBlock(nonEmptyBB);
+ }
+
+ // Enter the loop.
+ llvm::BasicBlock *entryBB = Builder.GetInsertBlock();
+ llvm::BasicBlock *loopBB = createBasicBlock("new.loop");
+
+ EmitBlock(loopBB);
+
+ // Set up the current-element phi.
+ llvm::PHINode *curPtr =
+ Builder.CreatePHI(beginPtr->getType(), 2, "array.cur");
+ curPtr->addIncoming(beginPtr, entryBB);
+
+ // Enter a partial-destruction cleanup if necessary.
+ QualType::DestructionKind dtorKind = elementType.isDestructedType();
+ EHScopeStack::stable_iterator cleanup;
+ if (needsEHCleanup(dtorKind)) {
+ pushRegularPartialArrayCleanup(beginPtr, curPtr, elementType,
+ getDestroyer(dtorKind));
+ cleanup = EHStack.stable_begin();
+ }
+
+ // Emit the initializer into this element.
+ StoreAnyExprIntoOneUnit(*this, E, curPtr);
+
+ // Leave the cleanup if we entered one.
+ if (cleanup != EHStack.stable_end())
+ DeactivateCleanupBlock(cleanup);
+
+ // Advance to the next element.
+ llvm::Value *nextPtr = Builder.CreateConstGEP1_32(curPtr, 1, "array.next");
+
+ // Check whether we've gotten to the end of the array and, if so,
+ // exit the loop.
+ llvm::Value *isEnd = Builder.CreateICmpEQ(nextPtr, endPtr, "array.atend");
+ Builder.CreateCondBr(isEnd, contBB, loopBB);
+ curPtr->addIncoming(nextPtr, Builder.GetInsertBlock());
+
+ EmitBlock(contBB);
}
static void EmitZeroMemSet(CodeGenFunction &CGF, QualType T,
@@ -771,6 +850,7 @@ static void EmitZeroMemSet(CodeGenFunction &CGF, QualType T,
}
static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
+ QualType ElementType,
llvm::Value *NewPtr,
llvm::Value *NumElements,
llvm::Value *AllocSizeWithoutCookie) {
@@ -783,11 +863,10 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
if (!E->hasInitializer() || Ctor->getParent()->isEmpty())
return;
- if (CGF.CGM.getTypes().isZeroInitializable(E->getAllocatedType())) {
+ if (CGF.CGM.getTypes().isZeroInitializable(ElementType)) {
// Optimization: since zero initialization will just set the memory
// to all zeroes, generate a single memset to do it in one shot.
- EmitZeroMemSet(CGF, E->getAllocatedType(), NewPtr,
- AllocSizeWithoutCookie);
+ EmitZeroMemSet(CGF, ElementType, NewPtr, AllocSizeWithoutCookie);
return;
}
@@ -803,11 +882,10 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
isa<ImplicitValueInitExpr>(E->getConstructorArg(0))) {
// Optimization: since zero initialization will just set the memory
// to all zeroes, generate a single memset to do it in one shot.
- EmitZeroMemSet(CGF, E->getAllocatedType(), NewPtr,
- AllocSizeWithoutCookie);
- return;
+ EmitZeroMemSet(CGF, ElementType, NewPtr, AllocSizeWithoutCookie);
+ return;
} else {
- CGF.EmitNewArrayInitializer(E, NewPtr, NumElements);
+ CGF.EmitNewArrayInitializer(E, ElementType, NewPtr, NumElements);
return;
}
}
@@ -819,7 +897,7 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
if (E->hasInitializer() &&
!Ctor->getParent()->hasUserDeclaredConstructor() &&
!Ctor->getParent()->isEmpty())
- CGF.EmitNullInitialization(NewPtr, E->getAllocatedType());
+ CGF.EmitNullInitialization(NewPtr, ElementType);
CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, /*ForVirtualBase=*/false,
NewPtr, E->constructor_arg_begin(),
@@ -1086,15 +1164,6 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
Builder.CreateCondBr(isNull, contBB, notNullBB);
EmitBlock(notNullBB);
}
-
- assert((allocSize == allocSizeWithoutCookie) ==
- CalculateCookiePadding(*this, E).isZero());
- if (allocSize != allocSizeWithoutCookie) {
- assert(E->isArray());
- allocation = CGM.getCXXABI().InitializeArrayCookie(*this, allocation,
- numElements,
- E, allocType);
- }
// If there's an operator delete, enter a cleanup to call it if an
// exception is thrown.
@@ -1105,21 +1174,28 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
operatorDeleteCleanup = EHStack.stable_begin();
}
- const llvm::Type *elementPtrTy
+ assert((allocSize == allocSizeWithoutCookie) ==
+ CalculateCookiePadding(*this, E).isZero());
+ if (allocSize != allocSizeWithoutCookie) {
+ assert(E->isArray());
+ allocation = CGM.getCXXABI().InitializeArrayCookie(*this, allocation,
+ numElements,
+ E, allocType);
+ }
+
+ llvm::Type *elementPtrTy
= ConvertTypeForMem(allocType)->getPointerTo(AS);
llvm::Value *result = Builder.CreateBitCast(allocation, elementPtrTy);
+ EmitNewInitializer(*this, E, allocType, result, numElements,
+ allocSizeWithoutCookie);
if (E->isArray()) {
- EmitNewInitializer(*this, E, result, numElements, allocSizeWithoutCookie);
-
// NewPtr is a pointer to the base element type. If we're
// allocating an array of arrays, we'll need to cast back to the
// array pointer type.
- const llvm::Type *resultType = ConvertTypeForMem(E->getType());
+ llvm::Type *resultType = ConvertTypeForMem(E->getType());
if (result->getType() != resultType)
result = Builder.CreateBitCast(result, resultType);
- } else {
- EmitNewInitializer(*this, E, result, numElements, allocSizeWithoutCookie);
}
// Deactivate the 'operator delete' cleanup if we finished
@@ -1206,7 +1282,7 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
const CXXDestructorDecl *Dtor = 0;
if (const RecordType *RT = ElementType->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (!RD->hasTrivialDestructor()) {
+ if (RD->hasDefinition() && !RD->hasTrivialDestructor()) {
Dtor = RD->getDestructor();
if (Dtor->isVirtual()) {
@@ -1218,7 +1294,7 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
ElementType);
}
- const llvm::Type *Ty =
+ llvm::Type *Ty =
CGF.getTypes().GetFunctionType(CGF.getTypes().getFunctionInfo(Dtor,
Dtor_Complete),
/*isVariadic=*/false);
@@ -1307,7 +1383,7 @@ namespace {
// Pass the original requested size as the second argument.
if (DeleteFTy->getNumArgs() == 2) {
QualType size_t = DeleteFTy->getArgType(1);
- const llvm::IntegerType *SizeTy
+ llvm::IntegerType *SizeTy
= cast<llvm::IntegerType>(CGF.ConvertType(size_t));
CharUnits ElementTypeSize =
@@ -1406,7 +1482,7 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
QualType DeleteTy = Arg->getType()->getAs<PointerType>()->getPointeeType();
if (DeleteTy->isConstantArrayType()) {
llvm::Value *Zero = Builder.getInt32(0);
- llvm::SmallVector<llvm::Value*,8> GEP;
+ SmallVector<llvm::Value*,8> GEP;
GEP.push_back(Zero); // point at the outermost array
@@ -1420,7 +1496,7 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
GEP.push_back(Zero);
}
- Ptr = Builder.CreateInBoundsGEP(Ptr, GEP.begin(), GEP.end(), "del.first");
+ Ptr = Builder.CreateInBoundsGEP(Ptr, GEP, "del.first");
}
assert(ConvertTypeForMem(DeleteTy) ==
@@ -1439,8 +1515,8 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
static llvm::Constant *getBadTypeidFn(CodeGenFunction &CGF) {
// void __cxa_bad_typeid();
- const llvm::Type *VoidTy = llvm::Type::getVoidTy(CGF.getLLVMContext());
- const llvm::FunctionType *FTy =
+ llvm::Type *VoidTy = llvm::Type::getVoidTy(CGF.getLLVMContext());
+ llvm::FunctionType *FTy =
llvm::FunctionType::get(VoidTy, false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid");
@@ -1454,7 +1530,7 @@ static void EmitBadTypeidCall(CodeGenFunction &CGF) {
static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF,
const Expr *E,
- const llvm::Type *StdTypeInfoPtrTy) {
+ llvm::Type *StdTypeInfoPtrTy) {
// Get the vtable pointer.
llvm::Value *ThisPtr = CGF.EmitLValue(E).getAddress();
@@ -1487,7 +1563,7 @@ static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF,
}
llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
- const llvm::Type *StdTypeInfoPtrTy =
+ llvm::Type *StdTypeInfoPtrTy =
ConvertType(E->getType())->getPointerTo();
if (E->isTypeOperand()) {
@@ -1528,7 +1604,7 @@ static llvm::Constant *getDynamicCastFn(CodeGenFunction &CGF) {
llvm::Type *Args[4] = { Int8PtrTy, Int8PtrTy, Int8PtrTy, PtrDiffTy };
- const llvm::FunctionType *FTy =
+ llvm::FunctionType *FTy =
llvm::FunctionType::get(Int8PtrTy, Args, false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__dynamic_cast");
@@ -1537,8 +1613,8 @@ static llvm::Constant *getDynamicCastFn(CodeGenFunction &CGF) {
static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) {
// void __cxa_bad_cast();
- const llvm::Type *VoidTy = llvm::Type::getVoidTy(CGF.getLLVMContext());
- const llvm::FunctionType *FTy =
+ llvm::Type *VoidTy = llvm::Type::getVoidTy(CGF.getLLVMContext());
+ llvm::FunctionType *FTy =
llvm::FunctionType::get(VoidTy, false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_cast");
@@ -1554,9 +1630,9 @@ static llvm::Value *
EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
QualType SrcTy, QualType DestTy,
llvm::BasicBlock *CastEnd) {
- const llvm::Type *PtrDiffLTy =
+ llvm::Type *PtrDiffLTy =
CGF.ConvertType(CGF.getContext().getPointerDiffType());
- const llvm::Type *DestLTy = CGF.ConvertType(DestTy);
+ llvm::Type *DestLTy = CGF.ConvertType(DestTy);
if (const PointerType *PTy = DestTy->getAs<PointerType>()) {
if (PTy->getPointeeType()->isVoidType()) {
@@ -1626,7 +1702,7 @@ EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
static llvm::Value *EmitDynamicCastToNull(CodeGenFunction &CGF,
QualType DestTy) {
- const llvm::Type *DestLTy = CGF.ConvertType(DestTy);
+ llvm::Type *DestLTy = CGF.ConvertType(DestTy);
if (DestTy->isPointerType())
return llvm::Constant::getNullValue(DestLTy);
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 35cff1d72714..4a31bcfbe9e0 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -103,8 +103,7 @@ public:
ComplexPairTy VisitStmt(Stmt *S) {
S->dump(CGF.getContext().getSourceManager());
- assert(0 && "Stmt can't have complex result type!");
- return ComplexPairTy();
+ llvm_unreachable("Stmt can't have complex result type!");
}
ComplexPairTy VisitExpr(Expr *S);
ComplexPairTy VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr());}
@@ -119,6 +118,7 @@ public:
// l-values.
ComplexPairTy VisitDeclRefExpr(const Expr *E) { return EmitLoadOfLValue(E); }
+ ComplexPairTy VisitBlockDeclRefExpr(const Expr *E) { return EmitLoadOfLValue(E); }
ComplexPairTy VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
return EmitLoadOfLValue(E);
}
@@ -266,6 +266,10 @@ public:
ComplexPairTy VisitInitListExpr(InitListExpr *E);
ComplexPairTy VisitVAArgExpr(VAArgExpr *E);
+
+ ComplexPairTy VisitAtomicExpr(AtomicExpr *E) {
+ return CGF.EmitAtomicExpr(E).getComplexVal();
+ }
};
} // end anonymous namespace.
@@ -312,8 +316,8 @@ void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *Ptr,
ComplexPairTy ComplexExprEmitter::VisitExpr(Expr *E) {
CGF.ErrorUnsupported(E, "complex expression");
- const llvm::Type *EltTy =
- CGF.ConvertType(E->getType()->getAs<ComplexType>()->getElementType());
+ llvm::Type *EltTy =
+ CGF.ConvertType(E->getType()->getAs<ComplexType>()->getElementType());
llvm::Value *U = llvm::UndefValue::get(EltTy);
return ComplexPairTy(U, U);
}
@@ -402,16 +406,18 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
case CK_FloatingToIntegral:
case CK_FloatingToBoolean:
case CK_FloatingCast:
- case CK_AnyPointerToObjCPointerCast:
+ case CK_CPointerToObjCPointerCast:
+ case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
case CK_ObjCObjectLValueCast:
case CK_FloatingComplexToReal:
case CK_FloatingComplexToBoolean:
case CK_IntegralComplexToReal:
case CK_IntegralComplexToBoolean:
- case CK_ObjCProduceObject:
- case CK_ObjCConsumeObject:
- case CK_ObjCReclaimReturnedObject:
+ case CK_ARCProduceObject:
+ case CK_ARCConsumeObject:
+ case CK_ARCReclaimReturnedObject:
+ case CK_ARCExtendBlockObject:
llvm_unreachable("invalid cast kind for complex value");
case CK_FloatingRealToComplex:
@@ -524,40 +530,40 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
llvm::Value *DSTr, *DSTi;
if (Op.LHS.first->getType()->isFloatingPointTy()) {
// (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
- llvm::Value *Tmp1 = Builder.CreateFMul(LHSr, RHSr, "tmp"); // a*c
- llvm::Value *Tmp2 = Builder.CreateFMul(LHSi, RHSi, "tmp"); // b*d
- llvm::Value *Tmp3 = Builder.CreateFAdd(Tmp1, Tmp2, "tmp"); // ac+bd
+ llvm::Value *Tmp1 = Builder.CreateFMul(LHSr, RHSr); // a*c
+ llvm::Value *Tmp2 = Builder.CreateFMul(LHSi, RHSi); // b*d
+ llvm::Value *Tmp3 = Builder.CreateFAdd(Tmp1, Tmp2); // ac+bd
- llvm::Value *Tmp4 = Builder.CreateFMul(RHSr, RHSr, "tmp"); // c*c
- llvm::Value *Tmp5 = Builder.CreateFMul(RHSi, RHSi, "tmp"); // d*d
- llvm::Value *Tmp6 = Builder.CreateFAdd(Tmp4, Tmp5, "tmp"); // cc+dd
+ llvm::Value *Tmp4 = Builder.CreateFMul(RHSr, RHSr); // c*c
+ llvm::Value *Tmp5 = Builder.CreateFMul(RHSi, RHSi); // d*d
+ llvm::Value *Tmp6 = Builder.CreateFAdd(Tmp4, Tmp5); // cc+dd
- llvm::Value *Tmp7 = Builder.CreateFMul(LHSi, RHSr, "tmp"); // b*c
- llvm::Value *Tmp8 = Builder.CreateFMul(LHSr, RHSi, "tmp"); // a*d
- llvm::Value *Tmp9 = Builder.CreateFSub(Tmp7, Tmp8, "tmp"); // bc-ad
+ llvm::Value *Tmp7 = Builder.CreateFMul(LHSi, RHSr); // b*c
+ llvm::Value *Tmp8 = Builder.CreateFMul(LHSr, RHSi); // a*d
+ llvm::Value *Tmp9 = Builder.CreateFSub(Tmp7, Tmp8); // bc-ad
- DSTr = Builder.CreateFDiv(Tmp3, Tmp6, "tmp");
- DSTi = Builder.CreateFDiv(Tmp9, Tmp6, "tmp");
+ DSTr = Builder.CreateFDiv(Tmp3, Tmp6);
+ DSTi = Builder.CreateFDiv(Tmp9, Tmp6);
} else {
// (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
- llvm::Value *Tmp1 = Builder.CreateMul(LHSr, RHSr, "tmp"); // a*c
- llvm::Value *Tmp2 = Builder.CreateMul(LHSi, RHSi, "tmp"); // b*d
- llvm::Value *Tmp3 = Builder.CreateAdd(Tmp1, Tmp2, "tmp"); // ac+bd
+ llvm::Value *Tmp1 = Builder.CreateMul(LHSr, RHSr); // a*c
+ llvm::Value *Tmp2 = Builder.CreateMul(LHSi, RHSi); // b*d
+ llvm::Value *Tmp3 = Builder.CreateAdd(Tmp1, Tmp2); // ac+bd
- llvm::Value *Tmp4 = Builder.CreateMul(RHSr, RHSr, "tmp"); // c*c
- llvm::Value *Tmp5 = Builder.CreateMul(RHSi, RHSi, "tmp"); // d*d
- llvm::Value *Tmp6 = Builder.CreateAdd(Tmp4, Tmp5, "tmp"); // cc+dd
+ llvm::Value *Tmp4 = Builder.CreateMul(RHSr, RHSr); // c*c
+ llvm::Value *Tmp5 = Builder.CreateMul(RHSi, RHSi); // d*d
+ llvm::Value *Tmp6 = Builder.CreateAdd(Tmp4, Tmp5); // cc+dd
- llvm::Value *Tmp7 = Builder.CreateMul(LHSi, RHSr, "tmp"); // b*c
- llvm::Value *Tmp8 = Builder.CreateMul(LHSr, RHSi, "tmp"); // a*d
- llvm::Value *Tmp9 = Builder.CreateSub(Tmp7, Tmp8, "tmp"); // bc-ad
+ llvm::Value *Tmp7 = Builder.CreateMul(LHSi, RHSr); // b*c
+ 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()) {
- DSTr = Builder.CreateUDiv(Tmp3, Tmp6, "tmp");
- DSTi = Builder.CreateUDiv(Tmp9, Tmp6, "tmp");
+ DSTr = Builder.CreateUDiv(Tmp3, Tmp6);
+ DSTi = Builder.CreateUDiv(Tmp9, Tmp6);
} else {
- DSTr = Builder.CreateSDiv(Tmp3, Tmp6, "tmp");
- DSTi = Builder.CreateSDiv(Tmp9, Tmp6, "tmp");
+ DSTr = Builder.CreateSDiv(Tmp3, Tmp6);
+ DSTi = Builder.CreateSDiv(Tmp9, Tmp6);
}
}
@@ -735,12 +741,19 @@ ComplexPairTy ComplexExprEmitter::VisitInitListExpr(InitListExpr *E) {
Ignore = TestAndClearIgnoreImag();
(void)Ignore;
assert (Ignore == false && "init list ignored");
- if (E->getNumInits())
+
+ if (E->getNumInits() == 2) {
+ llvm::Value *Real = CGF.EmitScalarExpr(E->getInit(0));
+ llvm::Value *Imag = CGF.EmitScalarExpr(E->getInit(1));
+ return ComplexPairTy(Real, Imag);
+ } else if (E->getNumInits() == 1) {
return Visit(E->getInit(0));
+ }
// Empty init list intializes to null
+ assert(E->getNumInits() == 0 && "Unexpected number of inits");
QualType Ty = E->getType()->getAs<ComplexType>()->getElementType();
- const llvm::Type* LTy = CGF.ConvertType(Ty);
+ llvm::Type* LTy = CGF.ConvertType(Ty);
llvm::Value* zeroConstant = llvm::Constant::getNullValue(LTy);
return ComplexPairTy(zeroConstant, zeroConstant);
}
@@ -751,7 +764,7 @@ ComplexPairTy ComplexExprEmitter::VisitVAArgExpr(VAArgExpr *E) {
if (!ArgPtr) {
CGF.ErrorUnsupported(E, "complex va_arg expression");
- const llvm::Type *EltTy =
+ llvm::Type *EltTy =
CGF.ConvertType(E->getType()->getAs<ComplexType>()->getElementType());
llvm::Value *U = llvm::UndefValue::get(EltTy);
return ComplexPairTy(U, U);
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 45e44dda0f58..3997866ea68e 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -138,13 +138,12 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
// We need to add padding.
CharUnits PadSize = Context.toCharUnitsFromBits(
llvm::RoundUpToAlignment(FieldOffset - NextFieldOffsetInBits,
- Context.Target.getCharAlign()));
+ Context.getTargetInfo().getCharAlign()));
AppendPadding(PadSize);
}
- uint64_t FieldSize =
- Field->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
+ uint64_t FieldSize = Field->getBitWidthValue(Context);
llvm::APInt FieldValue = CI->getValue();
@@ -213,7 +212,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
// padding and then an hole for our i8 to get plopped into.
assert(isa<llvm::ArrayType>(LastElt->getType()) &&
"Expected array padding of undefs");
- const llvm::ArrayType *AT = cast<llvm::ArrayType>(LastElt->getType());
+ llvm::ArrayType *AT = cast<llvm::ArrayType>(LastElt->getType());
assert(AT->getElementType()->isIntegerTy(CharWidth) &&
AT->getNumElements() != 0 &&
"Expected non-empty array padding of undefs");
@@ -281,7 +280,7 @@ void ConstStructBuilder::AppendPadding(CharUnits PadSize) {
if (PadSize.isZero())
return;
- const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
+ llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
if (PadSize > CharUnits::One())
Ty = llvm::ArrayType::get(Ty, PadSize.getQuantity());
@@ -317,7 +316,7 @@ void ConstStructBuilder::ConvertStructToPacked() {
CharUnits NumChars =
AlignedElementOffsetInChars - ElementOffsetInChars;
- const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
+ llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
if (NumChars > CharUnits::One())
Ty = llvm::ArrayType::get(Ty, NumChars.getQuantity());
@@ -364,7 +363,7 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) {
continue;
// Don't emit anonymous bitfields, they just affect layout.
- if (Field->isBitField() && !Field->getIdentifier()) {
+ if (Field->isUnnamedBitfield()) {
LastFD = (*Field);
continue;
}
@@ -435,11 +434,11 @@ llvm::Constant *ConstStructBuilder::
// Pick the type to use. If the type is layout identical to the ConvertType
// type then use it, otherwise use whatever the builder produced for us.
- const llvm::StructType *STy =
+ llvm::StructType *STy =
llvm::ConstantStruct::getTypeForElements(CGM.getLLVMContext(),
Builder.Elements,Builder.Packed);
- const llvm::Type *ILETy = CGM.getTypes().ConvertType(ILE->getType());
- if (const llvm::StructType *ILESTy = dyn_cast<llvm::StructType>(ILETy)) {
+ llvm::Type *ILETy = CGM.getTypes().ConvertType(ILE->getType());
+ if (llvm::StructType *ILESTy = dyn_cast<llvm::StructType>(ILETy)) {
if (ILESTy->isLayoutIdentical(STy))
STy = ILESTy;
}
@@ -513,7 +512,7 @@ public:
llvm::Constant *RHS = CGM.EmitConstantExpr(E->getRHS(),
E->getRHS()->getType(), CGF);
- const llvm::Type *ResultType = ConvertType(E->getType());
+ llvm::Type *ResultType = ConvertType(E->getType());
LHS = llvm::ConstantExpr::getPtrToInt(LHS, ResultType);
RHS = llvm::ConstantExpr::getPtrToInt(RHS, ResultType);
@@ -527,7 +526,7 @@ public:
llvm::Constant *C = CGM.EmitConstantExpr(subExpr, subExpr->getType(), CGF);
if (!C) return 0;
- const llvm::Type *destType = ConvertType(E->getType());
+ llvm::Type *destType = ConvertType(E->getType());
switch (E->getCastKind()) {
case CK_ToUnion: {
@@ -571,7 +570,8 @@ public:
case CK_NoOp:
return C;
- case CK_AnyPointerToObjCPointerCast:
+ case CK_CPointerToObjCPointerCast:
+ case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
case CK_LValueBitCast:
case CK_BitCast:
@@ -585,9 +585,10 @@ public:
case CK_GetObjCProperty:
case CK_ToVoid:
case CK_Dynamic:
- case CK_ObjCProduceObject:
- case CK_ObjCConsumeObject:
- case CK_ObjCReclaimReturnedObject:
+ case CK_ARCProduceObject:
+ case CK_ARCConsumeObject:
+ case CK_ARCReclaimReturnedObject:
+ case CK_ARCExtendBlockObject:
return 0;
// These might need to be supported for constexpr.
@@ -680,9 +681,9 @@ public:
return Visit(ILE->getInit(0));
std::vector<llvm::Constant*> Elts;
- const llvm::ArrayType *AType =
+ llvm::ArrayType *AType =
cast<llvm::ArrayType>(ConvertType(ILE->getType()));
- const llvm::Type *ElemTy = AType->getElementType();
+ llvm::Type *ElemTy = AType->getElementType();
unsigned NumElements = AType->getNumElements();
// Initialising an array requires us to automatically
@@ -719,7 +720,7 @@ public:
std::vector<llvm::Type*> Types;
for (unsigned i = 0; i < Elts.size(); ++i)
Types.push_back(Elts[i]->getType());
- const llvm::StructType *SType = llvm::StructType::get(AType->getContext(),
+ llvm::StructType *SType = llvm::StructType::get(AType->getContext(),
Types, true);
return llvm::ConstantStruct::get(SType, Elts);
}
@@ -740,6 +741,22 @@ public:
}
llvm::Constant *VisitInitListExpr(InitListExpr *ILE) {
+ if (ILE->getType()->isAnyComplexType() && ILE->getNumInits() == 2) {
+ // Complex type with element initializers
+ Expr *Real = ILE->getInit(0);
+ Expr *Imag = ILE->getInit(1);
+ llvm::Constant *Complex[2];
+ Complex[0] = CGM.EmitConstantExpr(Real, Real->getType(), CGF);
+ if (!Complex[0])
+ return 0;
+ Complex[1] = CGM.EmitConstantExpr(Imag, Imag->getType(), CGF);
+ if (!Complex[1])
+ return 0;
+ llvm::StructType *STy =
+ cast<llvm::StructType>(ConvertType(ILE->getType()));
+ return llvm::ConstantStruct::get(STy, Complex);
+ }
+
if (ILE->getType()->isScalarType()) {
// We have a scalar in braces. Just use the first element.
if (ILE->getNumInits() > 0) {
@@ -762,10 +779,7 @@ public:
if (ILE->getType()->isVectorType())
return 0;
- assert(0 && "Unable to handle InitListExpr");
- // Get rid of control reaches end of void function warning.
- // Not reached.
- return 0;
+ llvm_unreachable("Unable to handle InitListExpr");
}
llvm::Constant *VisitCXXConstructExpr(CXXConstructExpr *E) {
@@ -789,8 +803,8 @@ public:
if (E->getNumArgs()) {
assert(E->getNumArgs() == 1 && "trivial ctor with > 1 argument");
- assert(E->getConstructor()->isCopyConstructor() &&
- "trivial ctor has argument but isn't a copy ctor");
+ assert(E->getConstructor()->isCopyOrMoveConstructor() &&
+ "trivial ctor has argument but isn't a copy/move ctor");
Expr *Arg = E->getArg(0);
assert(CGM.getContext().hasSameUnqualifiedType(Ty, Arg->getType()) &&
@@ -831,7 +845,7 @@ public:
}
// Utility methods
- const llvm::Type *ConvertType(QualType T) {
+ llvm::Type *ConvertType(QualType T) {
return CGM.getTypes().ConvertType(T);
}
@@ -948,10 +962,9 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
if (Success && !Result.HasSideEffects) {
switch (Result.Val.getKind()) {
case APValue::Uninitialized:
- assert(0 && "Constant expressions should be initialized.");
- return 0;
+ llvm_unreachable("Constant expressions should be initialized.");
case APValue::LValue: {
- const llvm::Type *DestTy = getTypes().ConvertTypeForMem(DestType);
+ llvm::Type *DestTy = getTypes().ConvertTypeForMem(DestType);
llvm::Constant *Offset =
llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
Result.Val.getLValueOffset().getQuantity());
@@ -962,9 +975,9 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
// Apply offset if necessary.
if (!Offset->isNullValue()) {
- const llvm::Type *Type = llvm::Type::getInt8PtrTy(VMContext);
+ llvm::Type *Type = llvm::Type::getInt8PtrTy(VMContext);
llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(C, Type);
- Casted = llvm::ConstantExpr::getGetElementPtr(Casted, &Offset, 1);
+ Casted = llvm::ConstantExpr::getGetElementPtr(Casted, Offset);
C = llvm::ConstantExpr::getBitCast(Casted, C->getType());
}
@@ -994,7 +1007,7 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
Result.Val.getInt());
if (C->getType()->isIntegerTy(1)) {
- const llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
+ llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
C = llvm::ConstantExpr::getZExt(C, BoolTy);
}
return C;
@@ -1013,8 +1026,13 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
NULL);
return llvm::ConstantStruct::get(STy, Complex);
}
- case APValue::Float:
- return llvm::ConstantFP::get(VMContext, Result.Val.getFloat());
+ case APValue::Float: {
+ const llvm::APFloat &Init = Result.Val.getFloat();
+ if (&Init.getSemantics() == &llvm::APFloat::IEEEhalf)
+ return llvm::ConstantInt::get(VMContext, Init.bitcastToAPInt());
+ else
+ return llvm::ConstantFP::get(VMContext, Init);
+ }
case APValue::ComplexFloat: {
llvm::Constant *Complex[2];
@@ -1030,7 +1048,7 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
return llvm::ConstantStruct::get(STy, Complex);
}
case APValue::Vector: {
- llvm::SmallVector<llvm::Constant *, 4> Inits;
+ SmallVector<llvm::Constant *, 4> Inits;
unsigned NumElts = Result.Val.getVectorLength();
if (Context.getLangOptions().AltiVec &&
@@ -1064,7 +1082,7 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
llvm::Constant* C = ConstExprEmitter(*this, CGF).Visit(const_cast<Expr*>(E));
if (C && C->getType()->isIntegerTy(1)) {
- const llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
+ llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
C = llvm::ConstantExpr::getZExt(C, BoolTy);
}
return C;
@@ -1181,14 +1199,14 @@ FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T,
}
static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM,
- const llvm::Type *baseType,
+ llvm::Type *baseType,
const CXXRecordDecl *base);
static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
const CXXRecordDecl *record,
bool asCompleteObject) {
const CGRecordLayout &layout = CGM.getTypes().getCGRecordLayout(record);
- const llvm::StructType *structure =
+ llvm::StructType *structure =
(asCompleteObject ? layout.getLLVMType()
: layout.getBaseSubobjectLLVMType());
@@ -1212,7 +1230,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
continue;
unsigned fieldIndex = layout.getNonVirtualBaseLLVMFieldNo(base);
- const llvm::Type *baseType = structure->getElementType(fieldIndex);
+ llvm::Type *baseType = structure->getElementType(fieldIndex);
elements[fieldIndex] = EmitNullConstantForBase(CGM, baseType, base);
}
@@ -1245,7 +1263,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
// We might have already laid this field out.
if (elements[fieldIndex]) continue;
- const llvm::Type *baseType = structure->getElementType(fieldIndex);
+ llvm::Type *baseType = structure->getElementType(fieldIndex);
elements[fieldIndex] = EmitNullConstantForBase(CGM, baseType, base);
}
}
@@ -1261,7 +1279,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
/// Emit the null constant for a base subobject.
static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM,
- const llvm::Type *baseType,
+ llvm::Type *baseType,
const CXXRecordDecl *base) {
const CGRecordLayout &baseLayout = CGM.getTypes().getCGRecordLayout(base);
@@ -1277,7 +1295,7 @@ static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM,
// Otherwise, some bases are represented as arrays of i8 if the size
// of the base is smaller than its corresponding LLVM type. Figure
// out how many elements this base array has.
- const llvm::ArrayType *baseArrayType = cast<llvm::ArrayType>(baseType);
+ llvm::ArrayType *baseArrayType = cast<llvm::ArrayType>(baseType);
unsigned numBaseElements = baseArrayType->getNumElements();
// Fill in null data member pointers.
@@ -1287,7 +1305,7 @@ static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM,
// Now go through all other elements and zero them out.
if (numBaseElements) {
- const llvm::Type *i8 = llvm::Type::getInt8Ty(CGM.getLLVMContext());
+ llvm::Type *i8 = llvm::Type::getInt8Ty(CGM.getLLVMContext());
llvm::Constant *i8_zero = llvm::Constant::getNullValue(i8);
for (unsigned i = 0; i != numBaseElements; ++i) {
if (!baseElements[i])
@@ -1312,7 +1330,7 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
for (unsigned i = 0; i != NumElements; ++i)
Array[i] = Element;
- const llvm::ArrayType *ATy =
+ llvm::ArrayType *ATy =
cast<llvm::ArrayType>(getTypes().ConvertTypeForMem(T));
return llvm::ConstantArray::get(ATy, Array);
}
@@ -1330,3 +1348,8 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
// A NULL pointer is represented as -1.
return getCXXABI().EmitNullMemberPointer(T->castAs<MemberPointerType>());
}
+
+llvm::Constant *
+CodeGenModule::EmitNullConstantForBase(const CXXRecordDecl *Record) {
+ return ::EmitNullConstant(*this, Record, false);
+}
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index a73e667e780e..3a9fbeed9d69 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -78,7 +78,7 @@ public:
return I;
}
- const llvm::Type *ConvertType(QualType T) { return CGF.ConvertType(T); }
+ llvm::Type *ConvertType(QualType T) { return CGF.ConvertType(T); }
LValue EmitLValue(const Expr *E) { return CGF.EmitLValue(E); }
LValue EmitCheckedLValue(const Expr *E) { return CGF.EmitCheckedLValue(E); }
@@ -153,8 +153,7 @@ public:
Value *VisitStmt(Stmt *S) {
S->dump(CGF.getContext().getSourceManager());
- assert(0 && "Stmt can't have complex result type!");
- return 0;
+ llvm_unreachable("Stmt can't have complex result type!");
}
Value *VisitExpr(Expr *S);
@@ -343,6 +342,10 @@ public:
}
// C++
+ Value *VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E) {
+ return EmitLoadOfLValue(E);
+ }
+
Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
return Visit(DAE->getExpr());
}
@@ -510,6 +513,7 @@ public:
return CGF.EmitObjCStringLiteral(E);
}
Value *VisitAsTypeExpr(AsTypeExpr *CE);
+ Value *VisitAtomicExpr(AtomicExpr *AE);
};
} // end anonymous namespace.
@@ -548,14 +552,24 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
if (DstType->isVoidType()) return 0;
+ 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()) {
+ Src = Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16), Src);
+ SrcType = CGF.getContext().FloatTy;
+ SrcTy = llvm::Type::getFloatTy(VMContext);
+ }
+
// Handle conversions to bool first, they are special: comparisons against 0.
if (DstType->isBooleanType())
return EmitConversionToBool(Src, SrcType);
- const llvm::Type *DstTy = ConvertType(DstType);
+ llvm::Type *DstTy = ConvertType(DstType);
// Ignore conversions like int -> uint.
- if (Src->getType() == DstTy)
+ if (SrcTy == DstTy)
return Src;
// Handle pointer conversions next: pointers can only be converted to/from
@@ -563,13 +577,13 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
// some native types (like Obj-C id) may map to a pointer type.
if (isa<llvm::PointerType>(DstTy)) {
// The source value may be an integer, or a pointer.
- if (isa<llvm::PointerType>(Src->getType()))
+ if (isa<llvm::PointerType>(SrcTy))
return Builder.CreateBitCast(Src, DstTy, "conv");
assert(SrcType->isIntegerType() && "Not ptr->ptr or int->ptr conversion?");
// First, convert to the correct width so that we control the kind of
// extension.
- const llvm::Type *MiddleTy = CGF.IntPtrTy;
+ llvm::Type *MiddleTy = CGF.IntPtrTy;
bool InputSigned = SrcType->isSignedIntegerOrEnumerationType();
llvm::Value* IntResult =
Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv");
@@ -577,7 +591,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
return Builder.CreateIntToPtr(IntResult, DstTy, "conv");
}
- if (isa<llvm::PointerType>(Src->getType())) {
+ if (isa<llvm::PointerType>(SrcTy)) {
// Must be an ptr to int cast.
assert(isa<llvm::IntegerType>(DstTy) && "not ptr->int?");
return Builder.CreatePtrToInt(Src, DstTy, "conv");
@@ -592,10 +606,10 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
// 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, "tmp");
+ UnV = Builder.CreateInsertElement(UnV, Elt, Idx);
// Splat the element across to all elements
- llvm::SmallVector<llvm::Constant*, 16> Args;
+ SmallVector<llvm::Constant*, 16> Args;
unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
for (unsigned i = 0; i != NumElements; ++i)
Args.push_back(Builder.getInt32(0));
@@ -606,34 +620,47 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
}
// Allow bitcast from vector to integer/fp of the same size.
- if (isa<llvm::VectorType>(Src->getType()) ||
+ if (isa<llvm::VectorType>(SrcTy) ||
isa<llvm::VectorType>(DstTy))
return Builder.CreateBitCast(Src, DstTy, "conv");
// Finally, we have the arithmetic types: real int/float.
- if (isa<llvm::IntegerType>(Src->getType())) {
+ Value *Res = NULL;
+ llvm::Type *ResTy = DstTy;
+
+ // Cast to half via float
+ if (DstType->isHalfType())
+ DstTy = llvm::Type::getFloatTy(VMContext);
+
+ if (isa<llvm::IntegerType>(SrcTy)) {
bool InputSigned = SrcType->isSignedIntegerOrEnumerationType();
if (isa<llvm::IntegerType>(DstTy))
- return Builder.CreateIntCast(Src, DstTy, InputSigned, "conv");
+ Res = Builder.CreateIntCast(Src, DstTy, InputSigned, "conv");
else if (InputSigned)
- return Builder.CreateSIToFP(Src, DstTy, "conv");
+ Res = Builder.CreateSIToFP(Src, DstTy, "conv");
else
- return Builder.CreateUIToFP(Src, DstTy, "conv");
- }
-
- assert(Src->getType()->isFloatingPointTy() && "Unknown real conversion");
- if (isa<llvm::IntegerType>(DstTy)) {
+ Res = Builder.CreateUIToFP(Src, DstTy, "conv");
+ } else if (isa<llvm::IntegerType>(DstTy)) {
+ assert(SrcTy->isFloatingPointTy() && "Unknown real conversion");
if (DstType->isSignedIntegerOrEnumerationType())
- return Builder.CreateFPToSI(Src, DstTy, "conv");
+ Res = Builder.CreateFPToSI(Src, DstTy, "conv");
else
- return Builder.CreateFPToUI(Src, DstTy, "conv");
+ Res = Builder.CreateFPToUI(Src, DstTy, "conv");
+ } else {
+ assert(SrcTy->isFloatingPointTy() && DstTy->isFloatingPointTy() &&
+ "Unknown real conversion");
+ if (DstTy->getTypeID() < SrcTy->getTypeID())
+ Res = Builder.CreateFPTrunc(Src, DstTy, "conv");
+ else
+ Res = Builder.CreateFPExt(Src, DstTy, "conv");
}
- assert(DstTy->isFloatingPointTy() && "Unknown real conversion");
- if (DstTy->getTypeID() < Src->getType()->getTypeID())
- return Builder.CreateFPTrunc(Src, DstTy, "conv");
- else
- return Builder.CreateFPExt(Src, DstTy, "conv");
+ if (DstTy != ResTy) {
+ assert(ResTy->isIntegerTy(16) && "Only half FP requires extra conversion");
+ Res = Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16), Res);
+ }
+
+ return Res;
}
/// EmitComplexToScalarConversion - Emit a conversion from the specified complex
@@ -686,14 +713,14 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
Value *RHS = CGF.EmitScalarExpr(E->getExpr(1));
Value *Mask;
- const llvm::VectorType *LTy = cast<llvm::VectorType>(LHS->getType());
+ llvm::VectorType *LTy = cast<llvm::VectorType>(LHS->getType());
unsigned LHSElts = LTy->getNumElements();
if (E->getNumSubExprs() == 3) {
Mask = CGF.EmitScalarExpr(E->getExpr(2));
// Shuffle LHS & RHS into one input vector.
- llvm::SmallVector<llvm::Constant*, 32> concat;
+ SmallVector<llvm::Constant*, 32> concat;
for (unsigned i = 0; i != LHSElts; ++i) {
concat.push_back(Builder.getInt32(2*i));
concat.push_back(Builder.getInt32(2*i+1));
@@ -706,7 +733,7 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
Mask = RHS;
}
- const llvm::VectorType *MTy = cast<llvm::VectorType>(Mask->getType());
+ llvm::VectorType *MTy = cast<llvm::VectorType>(Mask->getType());
llvm::Constant* EltMask;
// Treat vec3 like vec4.
@@ -721,7 +748,7 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
(1 << llvm::Log2_32(LHSElts))-1);
// Mask off the high bits of each shuffle index.
- llvm::SmallVector<llvm::Constant *, 32> MaskV;
+ SmallVector<llvm::Constant *, 32> MaskV;
for (unsigned i = 0, e = MTy->getNumElements(); i != e; ++i)
MaskV.push_back(EltMask);
@@ -734,7 +761,7 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
// n = extract mask i
// x = extract val n
// newv = insert newv, x, i
- const llvm::VectorType *RTy = llvm::VectorType::get(LTy->getElementType(),
+ llvm::VectorType *RTy = llvm::VectorType::get(LTy->getElementType(),
MTy->getNumElements());
Value* NewV = llvm::UndefValue::get(RTy);
for (unsigned i = 0, e = MTy->getNumElements(); i != e; ++i) {
@@ -760,8 +787,8 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
Value* V2 = CGF.EmitScalarExpr(E->getExpr(1));
// Handle vec3 special since the index will be off by one for the RHS.
- const llvm::VectorType *VTy = cast<llvm::VectorType>(V1->getType());
- llvm::SmallVector<llvm::Constant*, 32> indices;
+ llvm::VectorType *VTy = cast<llvm::VectorType>(V1->getType());
+ SmallVector<llvm::Constant*, 32> indices;
for (unsigned i = 2; i < E->getNumSubExprs(); i++) {
unsigned Idx = E->getShuffleMaskIdx(CGF.getContext(), i-2);
if (VTy->getNumElements() == 3 && Idx > 3)
@@ -815,7 +842,7 @@ Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
}
static llvm::Constant *getMaskElt(llvm::ShuffleVectorInst *SVI, unsigned Idx,
- unsigned Off, const llvm::Type *I32Ty) {
+ unsigned Off, llvm::Type *I32Ty) {
int MV = SVI->getMaskValue(Idx);
if (MV == -1)
return llvm::UndefValue::get(I32Ty);
@@ -831,12 +858,17 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
if (E->hadArrayRangeDesignator())
CGF.ErrorUnsupported(E, "GNU array range designator extension");
- const llvm::VectorType *VType =
+ llvm::VectorType *VType =
dyn_cast<llvm::VectorType>(ConvertType(E->getType()));
- // We have a scalar in braces. Just use the first element.
- if (!VType)
+ if (!VType) {
+ if (NumInitElements == 0) {
+ // C++11 value-initialization for the scalar.
+ return EmitNullValue(E->getType());
+ }
+ // We have a scalar in braces. Just use the first element.
return Visit(E->getInit(0));
+ }
unsigned ResElts = VType->getNumElements();
@@ -851,9 +883,9 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
for (unsigned i = 0; i != NumInitElements; ++i) {
Expr *IE = E->getInit(i);
Value *Init = Visit(IE);
- llvm::SmallVector<llvm::Constant*, 16> Args;
+ SmallVector<llvm::Constant*, 16> Args;
- const llvm::VectorType *VVT = dyn_cast<llvm::VectorType>(Init->getType());
+ llvm::VectorType *VVT = dyn_cast<llvm::VectorType>(Init->getType());
// Handle scalar elements. If the scalar initializer is actually one
// element of a different vector of the same width, use shuffle instead of
@@ -911,7 +943,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
if (isa<ExtVectorElementExpr>(IE)) {
llvm::ShuffleVectorInst *SVI = cast<llvm::ShuffleVectorInst>(Init);
Value *SVOp = SVI->getOperand(0);
- const llvm::VectorType *OpTy = cast<llvm::VectorType>(SVOp->getType());
+ llvm::VectorType *OpTy = cast<llvm::VectorType>(SVOp->getType());
if (OpTy->getNumElements() == ResElts) {
for (unsigned j = 0; j != CurIdx; ++j) {
@@ -968,7 +1000,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
// FIXME: evaluate codegen vs. shuffling against constant null vector.
// Emit remaining default initializers.
- const llvm::Type *EltTy = VType->getElementType();
+ llvm::Type *EltTy = VType->getElementType();
// Emit remaining default initializers
for (/* Do not initialize i*/; CurIdx < ResElts; ++CurIdx) {
@@ -1023,8 +1055,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
ConvertType(CGF.getContext().getPointerType(DestTy)));
return EmitLoadOfLValue(CGF.MakeAddrLValue(V, DestTy));
}
-
- case CK_AnyPointerToObjCPointerCast:
+
+ case CK_CPointerToObjCPointerCast:
+ case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
case CK_BitCast: {
Value *Src = Visit(const_cast<Expr*>(E));
@@ -1075,7 +1108,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
V = Builder.CreateStructGEP(V, 0, "arraydecay");
}
- return V;
+ // Make sure the array decay ends up being the right type. This matters if
+ // the array type was of an incomplete type.
+ return CGF.Builder.CreateBitCast(V, ConvertType(CE->getType()));
}
case CK_FunctionToPointerDecay:
return EmitLValue(E).getAddress();
@@ -1108,15 +1143,17 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
return CGF.CGM.getCXXABI().EmitMemberPointerConversion(CGF, CE, Src);
}
- case CK_ObjCProduceObject:
+ case CK_ARCProduceObject:
return CGF.EmitARCRetainScalarExpr(E);
- case CK_ObjCConsumeObject:
+ case CK_ARCConsumeObject:
return CGF.EmitObjCConsumeObject(E->getType(), Visit(E));
- case CK_ObjCReclaimReturnedObject: {
+ case CK_ARCReclaimReturnedObject: {
llvm::Value *value = Visit(E);
value = CGF.EmitARCRetainAutoreleasedReturnValue(value);
return CGF.EmitObjCConsumeObject(E->getType(), value);
}
+ case CK_ARCExtendBlockObject:
+ return CGF.EmitARCExtendBlockObject(E);
case CK_FloatingRealToComplex:
case CK_FloatingComplexCast:
@@ -1147,7 +1184,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
// First, convert to the correct width so that we control the kind of
// extension.
- const llvm::Type *MiddleTy = CGF.IntPtrTy;
+ llvm::Type *MiddleTy = CGF.IntPtrTy;
bool InputSigned = E->getType()->isSignedIntegerOrEnumerationType();
llvm::Value* IntResult =
Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv");
@@ -1163,16 +1200,16 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
return 0;
}
case CK_VectorSplat: {
- const llvm::Type *DstTy = ConvertType(DestTy);
+ llvm::Type *DstTy = ConvertType(DestTy);
Value *Elt = Visit(const_cast<Expr*>(E));
// 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, "tmp");
+ UnV = Builder.CreateInsertElement(UnV, Elt, Idx);
// Splat the element across to all elements
- llvm::SmallVector<llvm::Constant*, 16> Args;
+ SmallVector<llvm::Constant*, 16> Args;
unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
llvm::Constant *Zero = Builder.getInt32(0);
for (unsigned i = 0; i < NumElements; i++)
@@ -1188,7 +1225,6 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_FloatingToIntegral:
case CK_FloatingCast:
return EmitScalarConversion(Visit(E), E->getType(), DestTy);
-
case CK_IntegralToBoolean:
return EmitIntToBoolConversion(Visit(E));
case CK_PointerToBoolean:
@@ -1253,10 +1289,8 @@ EmitAddConsiderOverflowBehavior(const UnaryOperator *E,
BinOp.Opcode = BO_Add;
BinOp.E = E;
return EmitOverflowCheckedBinOp(BinOp);
- break;
}
- assert(false && "Unknown SignedOverflowBehaviorTy");
- return 0;
+ llvm_unreachable("Unknown SignedOverflowBehaviorTy");
}
llvm::Value *
@@ -1344,6 +1378,14 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
} else if (type->isRealFloatingType()) {
// Add the inc/dec to the real part.
llvm::Value *amt;
+
+ if (type->isHalfType()) {
+ // Another special case: half FP increment should be done via float
+ value =
+ Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16),
+ input);
+ }
+
if (value->getType()->isFloatTy())
amt = llvm::ConstantFP::get(VMContext,
llvm::APFloat(static_cast<float>(amount)));
@@ -1359,6 +1401,11 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
}
value = Builder.CreateFAdd(value, amt, isInc ? "inc" : "dec");
+ if (type->isHalfType())
+ value =
+ Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16),
+ value);
+
// Objective-C pointer types.
} else {
const ObjCObjectPointerType *OPT = type->castAs<ObjCObjectPointerType>();
@@ -1375,13 +1422,13 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
value = Builder.CreateInBoundsGEP(value, sizeValue, "incdec.objptr");
value = Builder.CreateBitCast(value, input->getType());
}
-
+
// Store the updated result through the lvalue.
if (LV.isBitField())
CGF.EmitStoreThroughBitfieldLValue(RValue::get(value), LV, &value);
else
CGF.EmitStoreThroughLValue(RValue::get(value), LV);
-
+
// If this is a postinc, return the value read from memory, otherwise use the
// updated value.
return isPre ? value : input;
@@ -1432,7 +1479,7 @@ Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) {
// Loop over the components of the offsetof to compute the value.
unsigned n = E->getNumComponents();
- const llvm::Type* ResultType = ConvertType(E->getType());
+ llvm::Type* ResultType = ConvertType(E->getType());
llvm::Value* Result = llvm::Constant::getNullValue(ResultType);
QualType CurrentType = E->getTypeSourceInfo()->getType();
for (unsigned i = 0; i != n; ++i) {
@@ -1686,7 +1733,7 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
llvm::next(insertPt));
llvm::BasicBlock *overflowBB = CGF.createBasicBlock("overflow", CGF.CurFn);
- const llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType());
+ llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType());
if (Ops.Ty->hasSignedIntegerRepresentation()) {
llvm::Value *IntMin =
@@ -1769,7 +1816,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
IID = llvm::Intrinsic::smul_with_overflow;
break;
default:
- assert(false && "Unsupported operation for overflow detection");
+ llvm_unreachable("Unsupported operation for overflow detection");
IID = 0;
}
OpID <<= 1;
@@ -2065,7 +2112,7 @@ enum IntrinsicType { VCMPEQ, VCMPGT };
static llvm::Intrinsic::ID GetIntrinsic(IntrinsicType IT,
BuiltinType::Kind ElemKind) {
switch (ElemKind) {
- default: assert(0 && "unexpected element type");
+ default: llvm_unreachable("unexpected element type");
case BuiltinType::Char_U:
case BuiltinType::UChar:
return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequb_p :
@@ -2135,7 +2182,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
BuiltinType::Kind ElementKind = BTy->getKind();
switch(E->getOpcode()) {
- default: assert(0 && "is not a comparison operation");
+ default: llvm_unreachable("is not a comparison operation");
case BO_EQ:
CR6 = CR6_LT;
ID = GetIntrinsic(VCMPEQ, ElementKind);
@@ -2294,7 +2341,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
}
Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
- const llvm::Type *ResTy = ConvertType(E->getType());
+ llvm::Type *ResTy = ConvertType(E->getType());
// If we have 0 && RHS, see if we can elide RHS, if so, just return 0.
// If we have 1 && X, just emit X without inserting the control flow.
@@ -2349,7 +2396,7 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
}
Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
- const llvm::Type *ResTy = ConvertType(E->getType());
+ llvm::Type *ResTy = ConvertType(E->getType());
// If we have 1 || RHS, see if we can elide RHS, if so, just return 1.
// If we have 0 || X, just emit X without inserting the control flow.
@@ -2471,11 +2518,11 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
llvm::Value *LHS = Visit(lhsExpr);
llvm::Value *RHS = Visit(rhsExpr);
- const llvm::Type *condType = ConvertType(condExpr->getType());
- const llvm::VectorType *vecTy = cast<llvm::VectorType>(condType);
+ llvm::Type *condType = ConvertType(condExpr->getType());
+ llvm::VectorType *vecTy = cast<llvm::VectorType>(condType);
unsigned numElem = vecTy->getNumElements();
- const llvm::Type *elemType = vecTy->getElementType();
+ llvm::Type *elemType = vecTy->getElementType();
std::vector<llvm::Constant*> Zvals;
for (unsigned i = 0; i < numElem; ++i)
@@ -2493,7 +2540,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
llvm::Value *RHSTmp = RHS;
llvm::Value *LHSTmp = LHS;
bool wasCast = false;
- const llvm::VectorType *rhsVTy = cast<llvm::VectorType>(RHS->getType());
+ llvm::VectorType *rhsVTy = cast<llvm::VectorType>(RHS->getType());
if (rhsVTy->getElementType()->isFloatTy()) {
RHSTmp = Builder.CreateBitCast(RHS, tmp2->getType());
LHSTmp = Builder.CreateBitCast(LHS, tmp->getType());
@@ -2578,11 +2625,11 @@ Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *block) {
Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) {
Value *Src = CGF.EmitScalarExpr(E->getSrcExpr());
- const llvm::Type *DstTy = ConvertType(E->getType());
+ llvm::Type *DstTy = ConvertType(E->getType());
// Going from vec4->vec3 or vec3->vec4 is a special case and requires
// a shuffle vector instead of a bitcast.
- const llvm::Type *SrcTy = Src->getType();
+ llvm::Type *SrcTy = Src->getType();
if (isa<llvm::VectorType>(DstTy) && isa<llvm::VectorType>(SrcTy)) {
unsigned numElementsDst = cast<llvm::VectorType>(DstTy)->getNumElements();
unsigned numElementsSrc = cast<llvm::VectorType>(SrcTy)->getNumElements();
@@ -2592,15 +2639,15 @@ Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) {
// In the case of going from int4->float3, a bitcast is needed before
// doing a shuffle.
- const llvm::Type *srcElemTy =
+ llvm::Type *srcElemTy =
cast<llvm::VectorType>(SrcTy)->getElementType();
- const llvm::Type *dstElemTy =
+ llvm::Type *dstElemTy =
cast<llvm::VectorType>(DstTy)->getElementType();
if ((srcElemTy->isIntegerTy() && dstElemTy->isFloatTy())
|| (srcElemTy->isFloatTy() && dstElemTy->isIntegerTy())) {
// Create a float type of the same size as the source or destination.
- const llvm::VectorType *newSrcTy = llvm::VectorType::get(dstElemTy,
+ llvm::VectorType *newSrcTy = llvm::VectorType::get(dstElemTy,
numElementsSrc);
Src = Builder.CreateBitCast(Src, newSrcTy, "astypeCast");
@@ -2608,7 +2655,7 @@ Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) {
llvm::Value *UnV = llvm::UndefValue::get(Src->getType());
- llvm::SmallVector<llvm::Constant*, 3> Args;
+ SmallVector<llvm::Constant*, 3> Args;
Args.push_back(Builder.getInt32(0));
Args.push_back(Builder.getInt32(1));
Args.push_back(Builder.getInt32(2));
@@ -2626,6 +2673,10 @@ Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) {
return Builder.CreateBitCast(Src, DstTy, "astype");
}
+Value *ScalarExprEmitter::VisitAtomicExpr(AtomicExpr *E) {
+ return CGF.EmitAtomicExpr(E).getScalarVal();
+}
+
//===----------------------------------------------------------------------===//
// Entry Point into this File
//===----------------------------------------------------------------------===//
@@ -2678,7 +2729,7 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) {
// object->isa or (*object).isa
// Generate code as for: *(Class*)object
// build Class* type
- const llvm::Type *ClassPtrTy = ConvertType(E->getType());
+ llvm::Type *ClassPtrTy = ConvertType(E->getType());
Expr *BaseExpr = E->getBase();
if (BaseExpr->isRValue()) {
@@ -2744,8 +2795,7 @@ LValue CodeGenFunction::EmitCompoundAssignmentLValue(
case BO_LOr:
case BO_Assign:
case BO_Comma:
- assert(false && "Not valid compound assignment operators");
- break;
+ llvm_unreachable("Not valid compound assignment operators");
}
llvm_unreachable("Unhandled compound assignment operator");
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 426cca00140c..51f20534d116 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -33,7 +33,7 @@ tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e);
/// Given the address of a variable of pointer type, find the correct
/// null to store into it.
static llvm::Constant *getNullForVariable(llvm::Value *addr) {
- const llvm::Type *type =
+ llvm::Type *type =
cast<llvm::PointerType>(addr->getType())->getElementType();
return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(type));
}
@@ -80,6 +80,53 @@ static RValue AdjustRelatedResultType(CodeGenFunction &CGF,
CGF.ConvertType(E->getType())));
}
+/// Decide whether to extend the lifetime of the receiver of a
+/// returns-inner-pointer message.
+static bool
+shouldExtendReceiverForInnerPointerMessage(const ObjCMessageExpr *message) {
+ switch (message->getReceiverKind()) {
+
+ // For a normal instance message, we should extend unless the
+ // receiver is loaded from a variable with precise lifetime.
+ case ObjCMessageExpr::Instance: {
+ const Expr *receiver = message->getInstanceReceiver();
+ const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(receiver);
+ if (!ice || ice->getCastKind() != CK_LValueToRValue) return true;
+ receiver = ice->getSubExpr()->IgnoreParens();
+
+ // Only __strong variables.
+ if (receiver->getType().getObjCLifetime() != Qualifiers::OCL_Strong)
+ return true;
+
+ // All ivars and fields have precise lifetime.
+ if (isa<MemberExpr>(receiver) || isa<ObjCIvarRefExpr>(receiver))
+ return false;
+
+ // Otherwise, check for variables.
+ const DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(ice->getSubExpr());
+ if (!declRef) return true;
+ const VarDecl *var = dyn_cast<VarDecl>(declRef->getDecl());
+ if (!var) return true;
+
+ // All variables have precise lifetime except local variables with
+ // automatic storage duration that aren't specially marked.
+ return (var->hasLocalStorage() &&
+ !var->hasAttr<ObjCPreciseLifetimeAttr>());
+ }
+
+ case ObjCMessageExpr::Class:
+ case ObjCMessageExpr::SuperClass:
+ // It's never necessary for class objects.
+ return false;
+
+ case ObjCMessageExpr::SuperInstance:
+ // We generally assume that 'self' lives throughout a method call.
+ return false;
+ }
+
+ llvm_unreachable("invalid receiver kind");
+}
+
RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
ReturnValueSlot Return) {
// Only the lookup mechanism and first two arguments of the method
@@ -88,6 +135,8 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
bool isDelegateInit = E->isDelegateInitCall();
+ const ObjCMethodDecl *method = E->getMethodDecl();
+
// We don't retain the receiver in delegate init calls, and this is
// safe because the receiver value is always loaded from 'self',
// which we zero out. We don't want to Block_copy block receivers,
@@ -95,8 +144,8 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
bool retainSelf =
(!isDelegateInit &&
CGM.getLangOptions().ObjCAutoRefCount &&
- E->getMethodDecl() &&
- E->getMethodDecl()->hasAttr<NSConsumesSelfAttr>());
+ method &&
+ method->hasAttr<NSConsumesSelfAttr>());
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
bool isSuperMessage = false;
@@ -112,8 +161,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
TryEmitResult ter = tryEmitARCRetainScalarExpr(*this,
E->getInstanceReceiver());
Receiver = ter.getPointer();
- if (!ter.getInt())
- Receiver = EmitARCRetainNonBlock(Receiver);
+ if (ter.getInt()) retainSelf = false;
} else
Receiver = EmitScalarExpr(E->getInstanceReceiver());
break;
@@ -126,9 +174,6 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
assert(OID && "Invalid Objective-C class message send");
Receiver = Runtime.GetClass(Builder, OID);
isClassMessage = true;
-
- if (retainSelf)
- Receiver = EmitARCRetainNonBlock(Receiver);
break;
}
@@ -136,9 +181,6 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
ReceiverType = E->getSuperType();
Receiver = LoadObjCSelf();
isSuperMessage = true;
-
- if (retainSelf)
- Receiver = EmitARCRetainNonBlock(Receiver);
break;
case ObjCMessageExpr::SuperClass:
@@ -146,17 +188,25 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
Receiver = LoadObjCSelf();
isSuperMessage = true;
isClassMessage = true;
-
- if (retainSelf)
- Receiver = EmitARCRetainNonBlock(Receiver);
break;
}
+ if (retainSelf)
+ Receiver = EmitARCRetainNonBlock(Receiver);
+
+ // In ARC, we sometimes want to "extend the lifetime"
+ // (i.e. retain+autorelease) of receivers of returns-inner-pointer
+ // messages.
+ if (getLangOptions().ObjCAutoRefCount && method &&
+ method->hasAttr<ObjCReturnsInnerPointerAttr>() &&
+ shouldExtendReceiverForInnerPointerMessage(E))
+ Receiver = EmitARCRetainAutorelease(ReceiverType, Receiver);
+
QualType ResultType =
- E->getMethodDecl() ? E->getMethodDecl()->getResultType() : E->getType();
+ method ? method->getResultType() : E->getType();
CallArgList Args;
- EmitCallArgs(Args, E->getMethodDecl(), E->arg_begin(), E->arg_end());
+ EmitCallArgs(Args, method, E->arg_begin(), E->arg_end());
// For delegate init calls in ARC, do an unsafe store of null into
// self. This represents the call taking direct ownership of that
@@ -189,12 +239,12 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
Receiver,
isClassMessage,
Args,
- E->getMethodDecl());
+ method);
} else {
result = Runtime.GenerateMessageSend(*this, Return, ResultType,
E->getSelector(),
Receiver, Args, OID,
- E->getMethodDecl());
+ method);
}
// For delegate init calls in ARC, implicitly store the result of
@@ -206,14 +256,14 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
// The delegate return type isn't necessarily a matching type; in
// fact, it's quite likely to be 'id'.
- const llvm::Type *selfTy =
+ llvm::Type *selfTy =
cast<llvm::PointerType>(selfAddr->getType())->getElementType();
newSelf = Builder.CreateBitCast(newSelf, selfTy);
Builder.CreateStore(newSelf, selfAddr);
}
- return AdjustRelatedResultType(*this, E, E->getMethodDecl(), result);
+ return AdjustRelatedResultType(*this, E, method, result);
}
namespace {
@@ -263,7 +313,7 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
args.push_back(OMD->getSelfDecl());
args.push_back(OMD->getCmdDecl());
- for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(),
+ for (ObjCMethodDecl::param_const_iterator PI = OMD->param_begin(),
E = OMD->param_end(); PI != E; ++PI)
args.push_back(*PI);
@@ -285,39 +335,6 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
static llvm::Value *emitARCRetainLoadOfScalar(CodeGenFunction &CGF,
LValue lvalue, QualType type);
-void CodeGenFunction::GenerateObjCGetterBody(ObjCIvarDecl *Ivar,
- bool IsAtomic, bool IsStrong) {
- LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(),
- Ivar, 0);
- llvm::Value *GetCopyStructFn =
- CGM.getObjCRuntime().GetGetStructFunction();
- CodeGenTypes &Types = CGM.getTypes();
- // objc_copyStruct (ReturnValue, &structIvar,
- // sizeof (Type of Ivar), isAtomic, false);
- CallArgList Args;
- RValue RV = RValue::get(Builder.CreateBitCast(ReturnValue, VoidPtrTy));
- Args.add(RV, getContext().VoidPtrTy);
- RV = RValue::get(Builder.CreateBitCast(LV.getAddress(), VoidPtrTy));
- Args.add(RV, getContext().VoidPtrTy);
- // sizeof (Type of Ivar)
- CharUnits Size = getContext().getTypeSizeInChars(Ivar->getType());
- llvm::Value *SizeVal =
- llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy),
- Size.getQuantity());
- Args.add(RValue::get(SizeVal), getContext().LongTy);
- llvm::Value *isAtomic =
- llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy),
- IsAtomic ? 1 : 0);
- Args.add(RValue::get(isAtomic), getContext().BoolTy);
- llvm::Value *hasStrong =
- llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy),
- IsStrong ? 1 : 0);
- Args.add(RValue::get(hasStrong), getContext().BoolTy);
- EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args,
- FunctionType::ExtInfo()),
- GetCopyStructFn, ReturnValueSlot(), Args);
-}
-
/// Generate an Objective-C method. An Objective-C method is a C function with
/// its pointer, name, and types registered in the class struture.
void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) {
@@ -326,218 +343,599 @@ void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) {
FinishFunction(OMD->getBodyRBrace());
}
-// FIXME: I wasn't sure about the synthesis approach. If we end up generating an
-// AST for the whole body we can just fall back to having a GenerateFunction
-// which takes the body Stmt.
+/// emitStructGetterCall - Call the runtime function to load a property
+/// into the return value slot.
+static void emitStructGetterCall(CodeGenFunction &CGF, ObjCIvarDecl *ivar,
+ bool isAtomic, bool hasStrong) {
+ ASTContext &Context = CGF.getContext();
+
+ llvm::Value *src =
+ CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), CGF.LoadObjCSelf(),
+ ivar, 0).getAddress();
+
+ // objc_copyStruct (ReturnValue, &structIvar,
+ // sizeof (Type of Ivar), isAtomic, false);
+ CallArgList args;
+
+ llvm::Value *dest = CGF.Builder.CreateBitCast(CGF.ReturnValue, CGF.VoidPtrTy);
+ args.add(RValue::get(dest), Context.VoidPtrTy);
+
+ src = CGF.Builder.CreateBitCast(src, CGF.VoidPtrTy);
+ args.add(RValue::get(src), Context.VoidPtrTy);
+
+ CharUnits size = CGF.getContext().getTypeSizeInChars(ivar->getType());
+ args.add(RValue::get(CGF.CGM.getSize(size)), Context.getSizeType());
+ args.add(RValue::get(CGF.Builder.getInt1(isAtomic)), Context.BoolTy);
+ args.add(RValue::get(CGF.Builder.getInt1(hasStrong)), Context.BoolTy);
+
+ llvm::Value *fn = CGF.CGM.getObjCRuntime().GetGetStructFunction();
+ CGF.EmitCall(CGF.getTypes().getFunctionInfo(Context.VoidTy, args,
+ FunctionType::ExtInfo()),
+ fn, ReturnValueSlot(), args);
+}
+
+/// Determine whether the given architecture supports unaligned atomic
+/// accesses. They don't have to be fast, just faster than a function
+/// call and a mutex.
+static bool hasUnalignedAtomics(llvm::Triple::ArchType arch) {
+ // FIXME: Allow unaligned atomic load/store on x86. (It is not
+ // currently supported by the backend.)
+ return 0;
+}
+
+/// Return the maximum size that permits atomic accesses for the given
+/// architecture.
+static CharUnits getMaxAtomicAccessSize(CodeGenModule &CGM,
+ llvm::Triple::ArchType arch) {
+ // ARM has 8-byte atomic accesses, but it's not clear whether we
+ // want to rely on them here.
+
+ // In the default case, just assume that any size up to a pointer is
+ // fine given adequate alignment.
+ return CharUnits::fromQuantity(CGM.PointerSizeInBytes);
+}
+
+namespace {
+ class PropertyImplStrategy {
+ public:
+ enum StrategyKind {
+ /// The 'native' strategy is to use the architecture's provided
+ /// reads and writes.
+ Native,
+
+ /// Use objc_setProperty and objc_getProperty.
+ GetSetProperty,
+
+ /// Use objc_setProperty for the setter, but use expression
+ /// evaluation for the getter.
+ SetPropertyAndExpressionGet,
+
+ /// Use objc_copyStruct.
+ CopyStruct,
+
+ /// The 'expression' strategy is to emit normal assignment or
+ /// lvalue-to-rvalue expressions.
+ Expression
+ };
+
+ StrategyKind getKind() const { return StrategyKind(Kind); }
+
+ bool hasStrongMember() const { return HasStrong; }
+ bool isAtomic() const { return IsAtomic; }
+ bool isCopy() const { return IsCopy; }
+
+ CharUnits getIvarSize() const { return IvarSize; }
+ CharUnits getIvarAlignment() const { return IvarAlignment; }
+
+ PropertyImplStrategy(CodeGenModule &CGM,
+ const ObjCPropertyImplDecl *propImpl);
+
+ private:
+ unsigned Kind : 8;
+ unsigned IsAtomic : 1;
+ unsigned IsCopy : 1;
+ unsigned HasStrong : 1;
+
+ CharUnits IvarSize;
+ CharUnits IvarAlignment;
+ };
+}
+
+/// Pick an implementation strategy for the the given property synthesis.
+PropertyImplStrategy::PropertyImplStrategy(CodeGenModule &CGM,
+ const ObjCPropertyImplDecl *propImpl) {
+ const ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
+ ObjCPropertyDecl::SetterKind setterKind = prop->getSetterKind();
+
+ IsCopy = (setterKind == ObjCPropertyDecl::Copy);
+ IsAtomic = prop->isAtomic();
+ HasStrong = false; // doesn't matter here.
+
+ // Evaluate the ivar's size and alignment.
+ ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
+ QualType ivarType = ivar->getType();
+ llvm::tie(IvarSize, IvarAlignment)
+ = CGM.getContext().getTypeInfoInChars(ivarType);
+
+ // If we have a copy property, we always have to use getProperty/setProperty.
+ // TODO: we could actually use setProperty and an expression for non-atomics.
+ if (IsCopy) {
+ Kind = GetSetProperty;
+ return;
+ }
+
+ // Handle retain.
+ if (setterKind == ObjCPropertyDecl::Retain) {
+ // In GC-only, there's nothing special that needs to be done.
+ if (CGM.getLangOptions().getGC() == LangOptions::GCOnly) {
+ // fallthrough
+
+ // In ARC, if the property is non-atomic, use expression emission,
+ // which translates to objc_storeStrong. This isn't required, but
+ // it's slightly nicer.
+ } else if (CGM.getLangOptions().ObjCAutoRefCount && !IsAtomic) {
+ Kind = Expression;
+ return;
+
+ // Otherwise, we need to at least use setProperty. However, if
+ // the property isn't atomic, we can use normal expression
+ // emission for the getter.
+ } else if (!IsAtomic) {
+ Kind = SetPropertyAndExpressionGet;
+ return;
+
+ // Otherwise, we have to use both setProperty and getProperty.
+ } else {
+ Kind = GetSetProperty;
+ return;
+ }
+ }
+
+ // If we're not atomic, just use expression accesses.
+ if (!IsAtomic) {
+ Kind = Expression;
+ return;
+ }
+
+ // Properties on bitfield ivars need to be emitted using expression
+ // accesses even if they're nominally atomic.
+ if (ivar->isBitField()) {
+ Kind = Expression;
+ return;
+ }
+
+ // GC-qualified or ARC-qualified ivars need to be emitted as
+ // expressions. This actually works out to being atomic anyway,
+ // except for ARC __strong, but that should trigger the above code.
+ if (ivarType.hasNonTrivialObjCLifetime() ||
+ (CGM.getLangOptions().getGC() &&
+ CGM.getContext().getObjCGCAttrKind(ivarType))) {
+ Kind = Expression;
+ return;
+ }
+
+ // Compute whether the ivar has strong members.
+ if (CGM.getLangOptions().getGC())
+ if (const RecordType *recordType = ivarType->getAs<RecordType>())
+ HasStrong = recordType->getDecl()->hasObjectMember();
+
+ // We can never access structs with object members with a native
+ // access, because we need to use write barriers. This is what
+ // objc_copyStruct is for.
+ if (HasStrong) {
+ Kind = CopyStruct;
+ return;
+ }
+
+ // Otherwise, this is target-dependent and based on the size and
+ // alignment of the ivar.
+
+ // If the size of the ivar is not a power of two, give up. We don't
+ // want to get into the business of doing compare-and-swaps.
+ if (!IvarSize.isPowerOfTwo()) {
+ Kind = CopyStruct;
+ return;
+ }
+
+ llvm::Triple::ArchType arch =
+ CGM.getContext().getTargetInfo().getTriple().getArch();
+
+ // Most architectures require memory to fit within a single cache
+ // line, so the alignment has to be at least the size of the access.
+ // Otherwise we have to grab a lock.
+ if (IvarAlignment < IvarSize && !hasUnalignedAtomics(arch)) {
+ Kind = CopyStruct;
+ return;
+ }
+
+ // If the ivar's size exceeds the architecture's maximum atomic
+ // access size, we have to use CopyStruct.
+ if (IvarSize > getMaxAtomicAccessSize(CGM, arch)) {
+ Kind = CopyStruct;
+ return;
+ }
+
+ // Otherwise, we can use native loads and stores.
+ Kind = Native;
+}
/// GenerateObjCGetter - Generate an Objective-C property getter
/// function. The given Decl must be an ObjCImplementationDecl. @synthesize
/// is illegal within a category.
void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID) {
- ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl();
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
- bool IsAtomic =
- !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic);
ObjCMethodDecl *OMD = PD->getGetterMethodDecl();
assert(OMD && "Invalid call to generate getter (empty method)");
StartObjCMethod(OMD, IMP->getClassInterface(), PID->getLocStart());
-
- // Determine if we should use an objc_getProperty call for
- // this. Non-atomic properties are directly evaluated.
- // atomic 'copy' and 'retain' properties are also directly
- // evaluated in gc-only mode.
- if (CGM.getLangOptions().getGCMode() != LangOptions::GCOnly &&
- IsAtomic &&
- (PD->getSetterKind() == ObjCPropertyDecl::Copy ||
- PD->getSetterKind() == ObjCPropertyDecl::Retain)) {
- llvm::Value *GetPropertyFn =
- CGM.getObjCRuntime().GetPropertyGetFunction();
- if (!GetPropertyFn) {
- CGM.ErrorUnsupported(PID, "Obj-C getter requiring atomic copy");
- FinishFunction();
+ generateObjCGetterBody(IMP, PID);
+
+ FinishFunction();
+}
+
+static bool hasTrivialGetExpr(const ObjCPropertyImplDecl *propImpl) {
+ const Expr *getter = propImpl->getGetterCXXConstructor();
+ if (!getter) return true;
+
+ // Sema only makes only of these when the ivar has a C++ class type,
+ // so the form is pretty constrained.
+
+ // If the property has a reference type, we might just be binding a
+ // reference, in which case the result will be a gl-value. We should
+ // treat this as a non-trivial operation.
+ if (getter->isGLValue())
+ return false;
+
+ // If we selected a trivial copy-constructor, we're okay.
+ if (const CXXConstructExpr *construct = dyn_cast<CXXConstructExpr>(getter))
+ return (construct->getConstructor()->isTrivial());
+
+ // The constructor might require cleanups (in which case it's never
+ // trivial).
+ assert(isa<ExprWithCleanups>(getter));
+ return false;
+}
+
+void
+CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
+ const ObjCPropertyImplDecl *propImpl) {
+ // If there's a non-trivial 'get' expression, we just have to emit that.
+ if (!hasTrivialGetExpr(propImpl)) {
+ ReturnStmt ret(SourceLocation(), propImpl->getGetterCXXConstructor(),
+ /*nrvo*/ 0);
+ EmitReturnStmt(ret);
+ return;
+ }
+
+ const ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
+ QualType propType = prop->getType();
+ ObjCMethodDecl *getterMethod = prop->getGetterMethodDecl();
+
+ ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
+
+ // Pick an implementation strategy.
+ PropertyImplStrategy strategy(CGM, propImpl);
+ switch (strategy.getKind()) {
+ case PropertyImplStrategy::Native: {
+ LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0);
+
+ // Currently, all atomic accesses have to be through integer
+ // types, so there's no point in trying to pick a prettier type.
+ llvm::Type *bitcastType =
+ llvm::Type::getIntNTy(getLLVMContext(),
+ getContext().toBits(strategy.getIvarSize()));
+ bitcastType = bitcastType->getPointerTo(); // addrspace 0 okay
+
+ // Perform an atomic load. This does not impose ordering constraints.
+ llvm::Value *ivarAddr = LV.getAddress();
+ ivarAddr = Builder.CreateBitCast(ivarAddr, bitcastType);
+ llvm::LoadInst *load = Builder.CreateLoad(ivarAddr, "load");
+ load->setAlignment(strategy.getIvarAlignment().getQuantity());
+ load->setAtomic(llvm::Unordered);
+
+ // Store that value into the return address. Doing this with a
+ // bitcast is likely to produce some pretty ugly IR, but it's not
+ // the *most* terrible thing in the world.
+ Builder.CreateStore(load, Builder.CreateBitCast(ReturnValue, bitcastType));
+
+ // Make sure we don't do an autorelease.
+ AutoreleaseResult = false;
+ return;
+ }
+
+ case PropertyImplStrategy::GetSetProperty: {
+ llvm::Value *getPropertyFn =
+ CGM.getObjCRuntime().GetPropertyGetFunction();
+ if (!getPropertyFn) {
+ CGM.ErrorUnsupported(propImpl, "Obj-C getter requiring atomic copy");
return;
}
// Return (ivar-type) objc_getProperty((id) self, _cmd, offset, true).
// FIXME: Can't this be simpler? This might even be worse than the
// corresponding gcc code.
- CodeGenTypes &Types = CGM.getTypes();
- ValueDecl *Cmd = OMD->getCmdDecl();
- llvm::Value *CmdVal = Builder.CreateLoad(LocalDeclMap[Cmd], "cmd");
- QualType IdTy = getContext().getObjCIdType();
- llvm::Value *SelfAsId =
- Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy));
- llvm::Value *Offset = EmitIvarOffset(IMP->getClassInterface(), Ivar);
- llvm::Value *True =
- llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1);
- CallArgList Args;
- Args.add(RValue::get(SelfAsId), IdTy);
- Args.add(RValue::get(CmdVal), Cmd->getType());
- Args.add(RValue::get(Offset), getContext().getPointerDiffType());
- Args.add(RValue::get(True), getContext().BoolTy);
+ llvm::Value *cmd =
+ Builder.CreateLoad(LocalDeclMap[getterMethod->getCmdDecl()], "cmd");
+ llvm::Value *self = Builder.CreateBitCast(LoadObjCSelf(), VoidPtrTy);
+ llvm::Value *ivarOffset =
+ EmitIvarOffset(classImpl->getClassInterface(), ivar);
+
+ CallArgList args;
+ args.add(RValue::get(self), getContext().getObjCIdType());
+ args.add(RValue::get(cmd), getContext().getObjCSelType());
+ args.add(RValue::get(ivarOffset), getContext().getPointerDiffType());
+ args.add(RValue::get(Builder.getInt1(strategy.isAtomic())),
+ getContext().BoolTy);
+
// FIXME: We shouldn't need to get the function info here, the
// runtime already should have computed it to build the function.
- RValue RV = EmitCall(Types.getFunctionInfo(PD->getType(), Args,
- FunctionType::ExtInfo()),
- GetPropertyFn, ReturnValueSlot(), Args);
+ RValue RV = EmitCall(getTypes().getFunctionInfo(propType, args,
+ FunctionType::ExtInfo()),
+ getPropertyFn, ReturnValueSlot(), args);
+
// We need to fix the type here. Ivars with copy & retain are
// always objects so we don't need to worry about complex or
// aggregates.
RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(),
- Types.ConvertType(PD->getType())));
- EmitReturnOfRValue(RV, PD->getType());
+ getTypes().ConvertType(propType)));
+
+ EmitReturnOfRValue(RV, propType);
// objc_getProperty does an autorelease, so we should suppress ours.
AutoreleaseResult = false;
- } else {
- const llvm::Triple &Triple = getContext().Target.getTriple();
- QualType IVART = Ivar->getType();
- if (IsAtomic &&
- IVART->isScalarType() &&
- (Triple.getArch() == llvm::Triple::arm ||
- Triple.getArch() == llvm::Triple::thumb) &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(4)) &&
- CGM.getObjCRuntime().GetGetStructFunction()) {
- GenerateObjCGetterBody(Ivar, true, false);
- }
- else if (IsAtomic &&
- (IVART->isScalarType() && !IVART->isRealFloatingType()) &&
- Triple.getArch() == llvm::Triple::x86 &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(4)) &&
- CGM.getObjCRuntime().GetGetStructFunction()) {
- GenerateObjCGetterBody(Ivar, true, false);
- }
- else if (IsAtomic &&
- (IVART->isScalarType() && !IVART->isRealFloatingType()) &&
- Triple.getArch() == llvm::Triple::x86_64 &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(8)) &&
- CGM.getObjCRuntime().GetGetStructFunction()) {
- GenerateObjCGetterBody(Ivar, true, false);
- }
- else if (IVART->isAnyComplexType()) {
- LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(),
- Ivar, 0);
- ComplexPairTy Pair = LoadComplexFromAddr(LV.getAddress(),
+
+ return;
+ }
+
+ case PropertyImplStrategy::CopyStruct:
+ emitStructGetterCall(*this, ivar, strategy.isAtomic(),
+ strategy.hasStrongMember());
+ return;
+
+ case PropertyImplStrategy::Expression:
+ case PropertyImplStrategy::SetPropertyAndExpressionGet: {
+ 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(IVART)) {
- bool IsStrong = false;
- if ((IsStrong = IvarTypeWithAggrGCObjects(IVART))
- && CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect
- && CGM.getObjCRuntime().GetGetStructFunction()) {
- GenerateObjCGetterBody(Ivar, IsAtomic, IsStrong);
- }
- else {
- const CXXRecordDecl *classDecl = IVART->getAsCXXRecordDecl();
-
- if (PID->getGetterCXXConstructor() &&
- classDecl && !classDecl->hasTrivialDefaultConstructor()) {
- ReturnStmt *Stmt =
- new (getContext()) ReturnStmt(SourceLocation(),
- PID->getGetterCXXConstructor(),
- 0);
- EmitReturnStmt(*Stmt);
- } else if (IsAtomic &&
- !IVART->isAnyComplexType() &&
- Triple.getArch() == llvm::Triple::x86 &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(4)) &&
- CGM.getObjCRuntime().GetGetStructFunction()) {
- GenerateObjCGetterBody(Ivar, true, false);
- }
- else if (IsAtomic &&
- !IVART->isAnyComplexType() &&
- Triple.getArch() == llvm::Triple::x86_64 &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(8)) &&
- CGM.getObjCRuntime().GetGetStructFunction()) {
- GenerateObjCGetterBody(Ivar, true, false);
- }
- else {
- LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(),
- Ivar, 0);
- EmitAggregateCopy(ReturnValue, LV.getAddress(), IVART);
- }
- }
- }
- else {
- LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(),
- Ivar, 0);
- QualType propType = PD->getType();
-
- llvm::Value *value;
- if (propType->isReferenceType()) {
- value = LV.getAddress();
+ StoreComplexToAddr(pair, ReturnValue, LV.isVolatileQualified());
+ } else if (hasAggregateLLVMType(ivarType)) {
+ // 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 {
+ llvm::Value *value;
+ if (propType->isReferenceType()) {
+ value = LV.getAddress();
+ } else {
+ // We want to load and autoreleaseReturnValue ARC __weak ivars.
+ if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak) {
+ value = emitARCRetainLoadOfScalar(*this, LV, ivarType);
+
+ // Otherwise we want to do a simple load, suppressing the
+ // final autorelease.
} else {
- // In ARC, we want to emit this retained.
- if (getLangOptions().ObjCAutoRefCount &&
- PD->getType()->isObjCRetainableType())
- value = emitARCRetainLoadOfScalar(*this, LV, IVART);
- else
- value = EmitLoadOfLValue(LV).getScalarVal();
-
- value = Builder.CreateBitCast(value, ConvertType(propType));
+ value = EmitLoadOfLValue(LV).getScalarVal();
+ AutoreleaseResult = false;
}
- EmitReturnOfRValue(RValue::get(value), propType);
+ value = Builder.CreateBitCast(value, ConvertType(propType));
+ }
+
+ EmitReturnOfRValue(RValue::get(value), propType);
}
+ return;
}
- FinishFunction();
+ }
+ llvm_unreachable("bad @property implementation strategy!");
}
-void CodeGenFunction::GenerateObjCAtomicSetterBody(ObjCMethodDecl *OMD,
- ObjCIvarDecl *Ivar) {
+/// emitStructSetterCall - Call the runtime function to store the value
+/// from the first formal parameter into the given ivar.
+static void emitStructSetterCall(CodeGenFunction &CGF, ObjCMethodDecl *OMD,
+ ObjCIvarDecl *ivar) {
// objc_copyStruct (&structIvar, &Arg,
// sizeof (struct something), true, false);
- llvm::Value *GetCopyStructFn =
- CGM.getObjCRuntime().GetSetStructFunction();
- CodeGenTypes &Types = CGM.getTypes();
- CallArgList Args;
- LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0);
- RValue RV =
- RValue::get(Builder.CreateBitCast(LV.getAddress(),
- Types.ConvertType(getContext().VoidPtrTy)));
- Args.add(RV, getContext().VoidPtrTy);
- llvm::Value *Arg = LocalDeclMap[*OMD->param_begin()];
- llvm::Value *ArgAsPtrTy =
- Builder.CreateBitCast(Arg,
- Types.ConvertType(getContext().VoidPtrTy));
- RV = RValue::get(ArgAsPtrTy);
- Args.add(RV, getContext().VoidPtrTy);
- // sizeof (Type of Ivar)
- CharUnits Size = getContext().getTypeSizeInChars(Ivar->getType());
- llvm::Value *SizeVal =
- llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy),
- Size.getQuantity());
- Args.add(RValue::get(SizeVal), getContext().LongTy);
- llvm::Value *True =
- llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1);
- Args.add(RValue::get(True), getContext().BoolTy);
- llvm::Value *False =
- llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 0);
- Args.add(RValue::get(False), getContext().BoolTy);
- EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args,
- FunctionType::ExtInfo()),
- GetCopyStructFn, ReturnValueSlot(), Args);
+ CallArgList args;
+
+ // The first argument is the address of the ivar.
+ llvm::Value *ivarAddr = CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(),
+ CGF.LoadObjCSelf(), ivar, 0)
+ .getAddress();
+ ivarAddr = CGF.Builder.CreateBitCast(ivarAddr, CGF.Int8PtrTy);
+ args.add(RValue::get(ivarAddr), CGF.getContext().VoidPtrTy);
+
+ // The second argument is the address of the parameter variable.
+ ParmVarDecl *argVar = *OMD->param_begin();
+ DeclRefExpr argRef(argVar, argVar->getType(), VK_LValue, SourceLocation());
+ llvm::Value *argAddr = CGF.EmitLValue(&argRef).getAddress();
+ argAddr = CGF.Builder.CreateBitCast(argAddr, CGF.Int8PtrTy);
+ args.add(RValue::get(argAddr), CGF.getContext().VoidPtrTy);
+
+ // The third argument is the sizeof the type.
+ llvm::Value *size =
+ CGF.CGM.getSize(CGF.getContext().getTypeSizeInChars(ivar->getType()));
+ args.add(RValue::get(size), CGF.getContext().getSizeType());
+
+ // The fourth argument is the 'isAtomic' flag.
+ args.add(RValue::get(CGF.Builder.getTrue()), CGF.getContext().BoolTy);
+
+ // The fifth argument is the 'hasStrong' flag.
+ // FIXME: should this really always be false?
+ args.add(RValue::get(CGF.Builder.getFalse()), CGF.getContext().BoolTy);
+
+ llvm::Value *copyStructFn = CGF.CGM.getObjCRuntime().GetSetStructFunction();
+ CGF.EmitCall(CGF.getTypes().getFunctionInfo(CGF.getContext().VoidTy, args,
+ FunctionType::ExtInfo()),
+ copyStructFn, ReturnValueSlot(), args);
+}
+
+static bool hasTrivialSetExpr(const ObjCPropertyImplDecl *PID) {
+ Expr *setter = PID->getSetterCXXAssignment();
+ if (!setter) return true;
+
+ // Sema only makes only of these when the ivar has a C++ class type,
+ // so the form is pretty constrained.
+
+ // An operator call is trivial if the function it calls is trivial.
+ // This also implies that there's nothing non-trivial going on with
+ // the arguments, because operator= can only be trivial if it's a
+ // synthesized assignment operator and therefore both parameters are
+ // references.
+ if (CallExpr *call = dyn_cast<CallExpr>(setter)) {
+ if (const FunctionDecl *callee
+ = dyn_cast_or_null<FunctionDecl>(call->getCalleeDecl()))
+ if (callee->isTrivial())
+ return true;
+ return false;
+ }
+
+ assert(isa<ExprWithCleanups>(setter));
+ return false;
}
-static bool
-IvarAssignHasTrvialAssignment(const ObjCPropertyImplDecl *PID,
- QualType IvarT) {
- bool HasTrvialAssignment = true;
- if (PID->getSetterCXXAssignment()) {
- const CXXRecordDecl *classDecl = IvarT->getAsCXXRecordDecl();
- HasTrvialAssignment =
- (!classDecl || classDecl->hasTrivialCopyAssignment());
+void
+CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
+ const ObjCPropertyImplDecl *propImpl) {
+ // Just use the setter expression if Sema gave us one and it's
+ // non-trivial. There's no way to do this atomically.
+ if (!hasTrivialSetExpr(propImpl)) {
+ EmitStmt(propImpl->getSetterCXXAssignment());
+ return;
+ }
+
+ const ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
+ ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
+ ObjCMethodDecl *setterMethod = prop->getSetterMethodDecl();
+
+ PropertyImplStrategy strategy(CGM, propImpl);
+ switch (strategy.getKind()) {
+ case PropertyImplStrategy::Native: {
+ llvm::Value *argAddr = LocalDeclMap[*setterMethod->param_begin()];
+
+ LValue ivarLValue =
+ EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, /*quals*/ 0);
+ llvm::Value *ivarAddr = ivarLValue.getAddress();
+
+ // Currently, all atomic accesses have to be through integer
+ // types, so there's no point in trying to pick a prettier type.
+ llvm::Type *bitcastType =
+ llvm::Type::getIntNTy(getLLVMContext(),
+ getContext().toBits(strategy.getIvarSize()));
+ bitcastType = bitcastType->getPointerTo(); // addrspace 0 okay
+
+ // Cast both arguments to the chosen operation type.
+ argAddr = Builder.CreateBitCast(argAddr, bitcastType);
+ ivarAddr = Builder.CreateBitCast(ivarAddr, bitcastType);
+
+ // This bitcast load is likely to cause some nasty IR.
+ llvm::Value *load = Builder.CreateLoad(argAddr);
+
+ // Perform an atomic store. There are no memory ordering requirements.
+ llvm::StoreInst *store = Builder.CreateStore(load, ivarAddr);
+ store->setAlignment(strategy.getIvarAlignment().getQuantity());
+ store->setAtomic(llvm::Unordered);
+ return;
+ }
+
+ case PropertyImplStrategy::GetSetProperty:
+ case PropertyImplStrategy::SetPropertyAndExpressionGet: {
+ llvm::Value *setPropertyFn =
+ CGM.getObjCRuntime().GetPropertySetFunction();
+ if (!setPropertyFn) {
+ CGM.ErrorUnsupported(propImpl, "Obj-C setter requiring atomic copy");
+ return;
+ }
+
+ // Emit objc_setProperty((id) self, _cmd, offset, arg,
+ // <is-atomic>, <is-copy>).
+ llvm::Value *cmd =
+ Builder.CreateLoad(LocalDeclMap[setterMethod->getCmdDecl()]);
+ llvm::Value *self =
+ Builder.CreateBitCast(LoadObjCSelf(), VoidPtrTy);
+ llvm::Value *ivarOffset =
+ EmitIvarOffset(classImpl->getClassInterface(), ivar);
+ llvm::Value *arg = LocalDeclMap[*setterMethod->param_begin()];
+ arg = Builder.CreateBitCast(Builder.CreateLoad(arg, "arg"), VoidPtrTy);
+
+ CallArgList args;
+ args.add(RValue::get(self), getContext().getObjCIdType());
+ args.add(RValue::get(cmd), getContext().getObjCSelType());
+ args.add(RValue::get(ivarOffset), getContext().getPointerDiffType());
+ args.add(RValue::get(arg), getContext().getObjCIdType());
+ args.add(RValue::get(Builder.getInt1(strategy.isAtomic())),
+ getContext().BoolTy);
+ args.add(RValue::get(Builder.getInt1(strategy.isCopy())),
+ getContext().BoolTy);
+ // FIXME: We shouldn't need to get the function info here, the runtime
+ // already should have computed it to build the function.
+ EmitCall(getTypes().getFunctionInfo(getContext().VoidTy, args,
+ FunctionType::ExtInfo()),
+ setPropertyFn, ReturnValueSlot(), args);
+ return;
+ }
+
+ case PropertyImplStrategy::CopyStruct:
+ emitStructSetterCall(*this, setterMethod, ivar);
+ return;
+
+ case PropertyImplStrategy::Expression:
+ break;
+ }
+
+ // Otherwise, fake up some ASTs and emit a normal assignment.
+ ValueDecl *selfDecl = setterMethod->getSelfDecl();
+ DeclRefExpr self(selfDecl, selfDecl->getType(), VK_LValue, SourceLocation());
+ ImplicitCastExpr selfLoad(ImplicitCastExpr::OnStack,
+ selfDecl->getType(), CK_LValueToRValue, &self,
+ VK_RValue);
+ ObjCIvarRefExpr ivarRef(ivar, ivar->getType().getNonReferenceType(),
+ SourceLocation(), &selfLoad, true, true);
+
+ ParmVarDecl *argDecl = *setterMethod->param_begin();
+ QualType argType = argDecl->getType().getNonReferenceType();
+ DeclRefExpr arg(argDecl, argType, VK_LValue, SourceLocation());
+ ImplicitCastExpr argLoad(ImplicitCastExpr::OnStack,
+ argType.getUnqualifiedType(), CK_LValueToRValue,
+ &arg, VK_RValue);
+
+ // The property type can differ from the ivar type in some situations with
+ // Objective-C pointer types, we can always bit cast the RHS in these cases.
+ // The following absurdity is just to ensure well-formed IR.
+ CastKind argCK = CK_NoOp;
+ if (ivarRef.getType()->isObjCObjectPointerType()) {
+ if (argLoad.getType()->isObjCObjectPointerType())
+ argCK = CK_BitCast;
+ else if (argLoad.getType()->isBlockPointerType())
+ argCK = CK_BlockPointerToObjCPointerCast;
+ else
+ argCK = CK_CPointerToObjCPointerCast;
+ } else if (ivarRef.getType()->isBlockPointerType()) {
+ if (argLoad.getType()->isBlockPointerType())
+ argCK = CK_BitCast;
+ else
+ argCK = CK_AnyPointerToBlockPointerCast;
+ } else if (ivarRef.getType()->isPointerType()) {
+ argCK = CK_BitCast;
}
- return HasTrvialAssignment;
+ ImplicitCastExpr argCast(ImplicitCastExpr::OnStack,
+ ivarRef.getType(), argCK, &argLoad,
+ VK_RValue);
+ Expr *finalArg = &argLoad;
+ if (!getContext().hasSameUnqualifiedType(ivarRef.getType(),
+ argLoad.getType()))
+ finalArg = &argCast;
+
+
+ BinaryOperator assign(&ivarRef, finalArg, BO_Assign,
+ ivarRef.getType(), VK_RValue, OK_Ordinary,
+ SourceLocation());
+ EmitStmt(&assign);
}
/// GenerateObjCSetter - Generate an Objective-C property setter
@@ -545,136 +943,12 @@ IvarAssignHasTrvialAssignment(const ObjCPropertyImplDecl *PID,
/// is illegal within a category.
void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID) {
- ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl();
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
ObjCMethodDecl *OMD = PD->getSetterMethodDecl();
assert(OMD && "Invalid call to generate setter (empty method)");
StartObjCMethod(OMD, IMP->getClassInterface(), PID->getLocStart());
- const llvm::Triple &Triple = getContext().Target.getTriple();
- QualType IVART = Ivar->getType();
- bool IsCopy = PD->getSetterKind() == ObjCPropertyDecl::Copy;
- bool IsAtomic =
- !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic);
-
- // Determine if we should use an objc_setProperty call for
- // this. Properties with 'copy' semantics always use it, as do
- // non-atomic properties with 'release' semantics as long as we are
- // not in gc-only mode.
- if (IsCopy ||
- (CGM.getLangOptions().getGCMode() != LangOptions::GCOnly &&
- PD->getSetterKind() == ObjCPropertyDecl::Retain)) {
- llvm::Value *SetPropertyFn =
- CGM.getObjCRuntime().GetPropertySetFunction();
-
- if (!SetPropertyFn) {
- CGM.ErrorUnsupported(PID, "Obj-C getter requiring atomic copy");
- FinishFunction();
- return;
- }
- // Emit objc_setProperty((id) self, _cmd, offset, arg,
- // <is-atomic>, <is-copy>).
- // FIXME: Can't this be simpler? This might even be worse than the
- // corresponding gcc code.
- CodeGenTypes &Types = CGM.getTypes();
- ValueDecl *Cmd = OMD->getCmdDecl();
- llvm::Value *CmdVal = Builder.CreateLoad(LocalDeclMap[Cmd], "cmd");
- QualType IdTy = getContext().getObjCIdType();
- llvm::Value *SelfAsId =
- Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy));
- llvm::Value *Offset = EmitIvarOffset(IMP->getClassInterface(), Ivar);
- llvm::Value *Arg = LocalDeclMap[*OMD->param_begin()];
- llvm::Value *ArgAsId =
- Builder.CreateBitCast(Builder.CreateLoad(Arg, "arg"),
- Types.ConvertType(IdTy));
- llvm::Value *True =
- llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1);
- llvm::Value *False =
- llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 0);
- CallArgList Args;
- Args.add(RValue::get(SelfAsId), IdTy);
- Args.add(RValue::get(CmdVal), Cmd->getType());
- Args.add(RValue::get(Offset), getContext().getPointerDiffType());
- Args.add(RValue::get(ArgAsId), IdTy);
- Args.add(RValue::get(IsAtomic ? True : False), getContext().BoolTy);
- Args.add(RValue::get(IsCopy ? True : False), getContext().BoolTy);
- // FIXME: We shouldn't need to get the function info here, the runtime
- // already should have computed it to build the function.
- EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args,
- FunctionType::ExtInfo()),
- SetPropertyFn,
- ReturnValueSlot(), Args);
- } else if (IsAtomic && hasAggregateLLVMType(IVART) &&
- !IVART->isAnyComplexType() &&
- IvarAssignHasTrvialAssignment(PID, IVART) &&
- ((Triple.getArch() == llvm::Triple::x86 &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(4))) ||
- (Triple.getArch() == llvm::Triple::x86_64 &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(8))))
- && CGM.getObjCRuntime().GetSetStructFunction()) {
- // objc_copyStruct (&structIvar, &Arg,
- // sizeof (struct something), true, false);
- GenerateObjCAtomicSetterBody(OMD, Ivar);
- } else if (PID->getSetterCXXAssignment()) {
- EmitIgnoredExpr(PID->getSetterCXXAssignment());
- } else {
- if (IsAtomic &&
- IVART->isScalarType() &&
- (Triple.getArch() == llvm::Triple::arm ||
- Triple.getArch() == llvm::Triple::thumb) &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(4)) &&
- CGM.getObjCRuntime().GetGetStructFunction()) {
- GenerateObjCAtomicSetterBody(OMD, Ivar);
- }
- else if (IsAtomic &&
- (IVART->isScalarType() && !IVART->isRealFloatingType()) &&
- Triple.getArch() == llvm::Triple::x86 &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(4)) &&
- CGM.getObjCRuntime().GetGetStructFunction()) {
- GenerateObjCAtomicSetterBody(OMD, Ivar);
- }
- else if (IsAtomic &&
- (IVART->isScalarType() && !IVART->isRealFloatingType()) &&
- Triple.getArch() == llvm::Triple::x86_64 &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(8)) &&
- CGM.getObjCRuntime().GetGetStructFunction()) {
- GenerateObjCAtomicSetterBody(OMD, Ivar);
- }
- else {
- // FIXME: Find a clean way to avoid AST node creation.
- SourceLocation Loc = PID->getLocStart();
- ValueDecl *Self = OMD->getSelfDecl();
- ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl();
- DeclRefExpr Base(Self, Self->getType(), VK_RValue, Loc);
- ParmVarDecl *ArgDecl = *OMD->param_begin();
- QualType T = ArgDecl->getType();
- if (T->isReferenceType())
- T = cast<ReferenceType>(T)->getPointeeType();
- DeclRefExpr Arg(ArgDecl, T, VK_LValue, Loc);
- ObjCIvarRefExpr IvarRef(Ivar, Ivar->getType(), Loc, &Base, true, true);
-
- // The property type can differ from the ivar type in some situations with
- // Objective-C pointer types, we can always bit cast the RHS in these cases.
- if (getContext().getCanonicalType(Ivar->getType()) !=
- getContext().getCanonicalType(ArgDecl->getType())) {
- ImplicitCastExpr ArgCasted(ImplicitCastExpr::OnStack,
- Ivar->getType(), CK_BitCast, &Arg,
- VK_RValue);
- BinaryOperator Assign(&IvarRef, &ArgCasted, BO_Assign,
- Ivar->getType(), VK_RValue, OK_Ordinary, Loc);
- EmitStmt(&Assign);
- } else {
- BinaryOperator Assign(&IvarRef, &Arg, BO_Assign,
- Ivar->getType(), VK_RValue, OK_Ordinary, Loc);
- EmitStmt(&Assign);
- }
- }
- }
+ generateObjCSetterBody(IMP, PID);
FinishFunction();
}
@@ -716,9 +990,8 @@ static void emitCXXDestructMethod(CodeGenFunction &CGF,
llvm::Value *self = CGF.LoadObjCSelf();
- ObjCInterfaceDecl *iface
- = const_cast<ObjCInterfaceDecl*>(impl->getClassInterface());
- for (ObjCIvarDecl *ivar = iface->all_declared_ivar_begin();
+ const ObjCInterfaceDecl *iface = impl->getClassInterface();
+ for (const ObjCIvarDecl *ivar = iface->all_declared_ivar_begin();
ivar; ivar = ivar->getNextIvar()) {
QualType type = ivar->getType();
@@ -758,7 +1031,7 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
// Suppress the final autorelease in ARC.
AutoreleaseResult = false;
- llvm::SmallVector<CXXCtorInitializer *, 8> IvarInitializers;
+ SmallVector<CXXCtorInitializer *, 8> IvarInitializers;
for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(),
E = IMP->init_end(); B != E; ++B) {
CXXCtorInitializer *IvarInit = (*B);
@@ -766,7 +1039,10 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field);
LValue LV = EmitLValueForIvar(TypeOfSelfObject(),
LoadObjCSelf(), Ivar, 0);
- EmitAggExpr(IvarInit->getInit(), AggValueSlot::forLValue(LV, true));
+ EmitAggExpr(IvarInit->getInit(),
+ AggValueSlot::forLValue(LV, AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased));
}
// constructor returns 'self'.
CodeGenTypes &Types = CGM.getTypes();
@@ -791,7 +1067,7 @@ bool CodeGenFunction::IndirectObjCSetterArg(const CGFunctionInfo &FI) {
}
bool CodeGenFunction::IvarTypeWithAggrGCObjects(QualType Ty) {
- if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC)
+ if (CGM.getLangOptions().getGC() == LangOptions::NonGC)
return false;
if (const RecordType *FDTTy = Ty.getTypePtr()->getAs<RecordType>())
return FDTTy->getDecl()->hasObjectMember();
@@ -896,7 +1172,7 @@ void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src,
if (Src.isScalar()) {
llvm::Value *SrcVal = Src.getScalarVal();
QualType DstType = getContext().getCanonicalType(ArgType);
- const llvm::Type *DstTy = ConvertType(DstType);
+ llvm::Type *DstTy = ConvertType(DstType);
if (SrcVal->getType() != DstTy)
Src =
RValue::get(EmitScalarConversion(SrcVal, E->getType(), DstType));
@@ -932,10 +1208,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
}
CGDebugInfo *DI = getDebugInfo();
- if (DI) {
- DI->setLocation(S.getSourceRange().getBegin());
- DI->EmitRegionStart(Builder);
- }
+ if (DI)
+ DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin());
// The local variable comes into scope immediately.
AutoVarEmission variable = AutoVarEmission::invalid();
@@ -943,10 +1217,9 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
variable = EmitAutoVarAlloca(*cast<VarDecl>(SD->getSingleDecl()));
JumpDest LoopEnd = getJumpDestInCurrentScope("forcoll.end");
- JumpDest AfterBody = getJumpDestInCurrentScope("forcoll.next");
// Fast enumeration state.
- QualType StateTy = getContext().getObjCFastEnumerationStateType();
+ QualType StateTy = CGM.getObjCFastEnumerationStateType();
llvm::Value *StatePtr = CreateMemTemp(StateTy, "state.ptr");
EmitNullInitialization(StatePtr, StateTy);
@@ -968,8 +1241,20 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
ArrayType::Normal, 0);
llvm::Value *ItemsPtr = CreateMemTemp(ItemsTy, "items.ptr");
- // Emit the collection pointer.
- llvm::Value *Collection = EmitScalarExpr(S.getCollection());
+ // Emit the collection pointer. In ARC, we do a retain.
+ llvm::Value *Collection;
+ if (getLangOptions().ObjCAutoRefCount) {
+ Collection = EmitARCRetainScalarExpr(S.getCollection());
+
+ // Enter a cleanup to do the release.
+ EmitObjCConsumeObject(S.getCollection()->getType(), Collection);
+ } else {
+ Collection = EmitScalarExpr(S.getCollection());
+ }
+
+ // The 'continue' label needs to appear within the cleanup for the
+ // collection object.
+ JumpDest AfterBody = getJumpDestInCurrentScope("forcoll.next");
// Send it our message:
CallArgList Args;
@@ -985,7 +1270,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
Args.add(RValue::get(ItemsPtr), getContext().getPointerType(ItemsTy));
// The third argument is the capacity of that temporary array.
- const llvm::Type *UnsignedLongLTy = ConvertType(getContext().UnsignedLongTy);
+ llvm::Type *UnsignedLongLTy = ConvertType(getContext().UnsignedLongTy);
llvm::Constant *Count = llvm::ConstantInt::get(UnsignedLongLTy, NumItems);
Args.add(RValue::get(Count), getContext().UnsignedLongTy);
@@ -1053,8 +1338,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
EmitBlock(WasMutatedBB);
llvm::Value *V =
Builder.CreateBitCast(Collection,
- ConvertType(getContext().getObjCIdType()),
- "tmp");
+ ConvertType(getContext().getObjCIdType()));
CallArgList Args2;
Args2.add(RValue::get(V), getContext().getObjCIdType());
// FIXME: We shouldn't need to get the function info here, the runtime already
@@ -1089,7 +1373,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
elementType = cast<Expr>(S.getElement())->getType();
elementIsVariable = false;
}
- const llvm::Type *convertedElementType = ConvertType(elementType);
+ llvm::Type *convertedElementType = ConvertType(elementType);
// Fetch the buffer out of the enumeration state.
// TODO: this pointer should actually be invariant between
@@ -1179,10 +1463,12 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
EmitStoreThroughLValue(RValue::get(null), elementLValue);
}
- if (DI) {
- DI->setLocation(S.getSourceRange().getEnd());
- DI->EmitRegionEnd(Builder);
- }
+ if (DI)
+ DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd());
+
+ // Leave the cleanup we entered in ARC.
+ if (getLangOptions().ObjCAutoRefCount)
+ PopCleanupBlock();
EmitBlock(LoopEnd.getBlock());
}
@@ -1200,7 +1486,7 @@ void CodeGenFunction::EmitObjCAtSynchronizedStmt(
CGM.getObjCRuntime().EmitSynchronizedStmt(*this, S);
}
-/// Produce the code for a CK_ObjCProduceObject. Just does a
+/// Produce the code for a CK_ARCProduceObject. Just does a
/// primitive retain.
llvm::Value *CodeGenFunction::EmitObjCProduceObject(QualType type,
llvm::Value *value) {
@@ -1209,63 +1495,22 @@ llvm::Value *CodeGenFunction::EmitObjCProduceObject(QualType type,
namespace {
struct CallObjCRelease : EHScopeStack::Cleanup {
- CallObjCRelease(QualType type, llvm::Value *ptr, llvm::Value *condition)
- : type(type), ptr(ptr), condition(condition) {}
- QualType type;
- llvm::Value *ptr;
- llvm::Value *condition;
+ CallObjCRelease(llvm::Value *object) : object(object) {}
+ llvm::Value *object;
void Emit(CodeGenFunction &CGF, Flags flags) {
- llvm::Value *object;
-
- // If we're in a conditional branch, we had to stash away in an
- // alloca the pointer to be released.
- llvm::BasicBlock *cont = 0;
- if (condition) {
- llvm::BasicBlock *release = CGF.createBasicBlock("release.yes");
- cont = CGF.createBasicBlock("release.cont");
-
- llvm::Value *cond = CGF.Builder.CreateLoad(condition);
- CGF.Builder.CreateCondBr(cond, release, cont);
- CGF.EmitBlock(release);
- object = CGF.Builder.CreateLoad(ptr);
- } else {
- object = ptr;
- }
-
CGF.EmitARCRelease(object, /*precise*/ true);
-
- if (cont) CGF.EmitBlock(cont);
}
};
}
-/// Produce the code for a CK_ObjCConsumeObject. Does a primitive
+/// Produce the code for a CK_ARCConsumeObject. Does a primitive
/// release at the end of the full-expression.
llvm::Value *CodeGenFunction::EmitObjCConsumeObject(QualType type,
llvm::Value *object) {
// If we're in a conditional branch, we need to make the cleanup
- // conditional. FIXME: this really needs to be supported by the
- // environment.
- llvm::AllocaInst *cond;
- llvm::Value *ptr;
- if (isInConditionalBranch()) {
- cond = CreateTempAlloca(Builder.getInt1Ty(), "release.cond");
- ptr = CreateTempAlloca(object->getType(), "release.value");
-
- // The alloca is false until we get here.
- // FIXME: er. doesn't this need to be set at the start of the condition?
- InitTempAlloca(cond, Builder.getFalse());
-
- // Then it turns true.
- Builder.CreateStore(Builder.getTrue(), cond);
- Builder.CreateStore(object, ptr);
- } else {
- cond = 0;
- ptr = object;
- }
-
- EHStack.pushCleanup<CallObjCRelease>(getARCCleanupKind(), type, ptr, cond);
+ // conditional.
+ pushFullExprCleanup<CallObjCRelease>(getARCCleanupKind(), object);
return object;
}
@@ -1276,8 +1521,8 @@ llvm::Value *CodeGenFunction::EmitObjCExtendObjectLifetime(QualType type,
static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM,
- const llvm::FunctionType *type,
- llvm::StringRef fnName) {
+ llvm::FunctionType *type,
+ StringRef fnName) {
llvm::Constant *fn = CGM.CreateRuntimeFunction(type, fnName);
// In -fobjc-no-arc-runtime, emit weak references to the runtime
@@ -1295,18 +1540,18 @@ static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM,
static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF,
llvm::Value *value,
llvm::Constant *&fn,
- llvm::StringRef fnName) {
+ StringRef fnName) {
if (isa<llvm::ConstantPointerNull>(value)) return value;
if (!fn) {
std::vector<llvm::Type*> args(1, CGF.Int8PtrTy);
- const llvm::FunctionType *fnType =
+ llvm::FunctionType *fnType =
llvm::FunctionType::get(CGF.Int8PtrTy, args, false);
fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
}
// Cast the argument to 'id'.
- const llvm::Type *origType = value->getType();
+ llvm::Type *origType = value->getType();
value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
// Call the function.
@@ -1322,16 +1567,16 @@ static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF,
static llvm::Value *emitARCLoadOperation(CodeGenFunction &CGF,
llvm::Value *addr,
llvm::Constant *&fn,
- llvm::StringRef fnName) {
+ StringRef fnName) {
if (!fn) {
std::vector<llvm::Type*> args(1, CGF.Int8PtrPtrTy);
- const llvm::FunctionType *fnType =
+ llvm::FunctionType *fnType =
llvm::FunctionType::get(CGF.Int8PtrTy, args, false);
fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
}
// Cast the argument to 'id*'.
- const llvm::Type *origType = addr->getType();
+ llvm::Type *origType = addr->getType();
addr = CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy);
// Call the function.
@@ -1353,7 +1598,7 @@ static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF,
llvm::Value *addr,
llvm::Value *value,
llvm::Constant *&fn,
- llvm::StringRef fnName,
+ StringRef fnName,
bool ignored) {
assert(cast<llvm::PointerType>(addr->getType())->getElementType()
== value->getType());
@@ -1363,12 +1608,12 @@ static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF,
argTypes[0] = CGF.Int8PtrPtrTy;
argTypes[1] = CGF.Int8PtrTy;
- const llvm::FunctionType *fnType
+ llvm::FunctionType *fnType
= llvm::FunctionType::get(CGF.Int8PtrTy, argTypes, false);
fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
}
- const llvm::Type *origType = value->getType();
+ llvm::Type *origType = value->getType();
addr = CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy);
value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
@@ -1387,12 +1632,12 @@ static void emitARCCopyOperation(CodeGenFunction &CGF,
llvm::Value *dst,
llvm::Value *src,
llvm::Constant *&fn,
- llvm::StringRef fnName) {
+ StringRef fnName) {
assert(dst->getType() == src->getType());
if (!fn) {
std::vector<llvm::Type*> argTypes(2, CGF.Int8PtrPtrTy);
- const llvm::FunctionType *fnType
+ llvm::FunctionType *fnType
= llvm::FunctionType::get(CGF.Builder.getVoidTy(), argTypes, false);
fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
}
@@ -1409,7 +1654,7 @@ static void emitARCCopyOperation(CodeGenFunction &CGF,
/// call i8* @objc_retainBlock(i8* %value)
llvm::Value *CodeGenFunction::EmitARCRetain(QualType type, llvm::Value *value) {
if (type->isBlockPointerType())
- return EmitARCRetainBlock(value);
+ return EmitARCRetainBlock(value, /*mandatory*/ false);
else
return EmitARCRetainNonBlock(value);
}
@@ -1424,10 +1669,32 @@ llvm::Value *CodeGenFunction::EmitARCRetainNonBlock(llvm::Value *value) {
/// Retain the given block, with _Block_copy semantics.
/// call i8* @objc_retainBlock(i8* %value)
-llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value) {
- return emitARCValueOperation(*this, value,
- CGM.getARCEntrypoints().objc_retainBlock,
- "objc_retainBlock");
+///
+/// \param mandatory - If false, emit the call with metadata
+/// indicating that it's okay for the optimizer to eliminate this call
+/// if it can prove that the block never escapes except down the stack.
+llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value,
+ bool mandatory) {
+ llvm::Value *result
+ = emitARCValueOperation(*this, value,
+ CGM.getARCEntrypoints().objc_retainBlock,
+ "objc_retainBlock");
+
+ // If the copy isn't mandatory, add !clang.arc.copy_on_escape to
+ // tell the optimizer that it doesn't need to do this copy if the
+ // block doesn't escape, where being passed as an argument doesn't
+ // count as escaping.
+ if (!mandatory && isa<llvm::Instruction>(result)) {
+ llvm::CallInst *call
+ = cast<llvm::CallInst>(result->stripPointerCasts());
+ assert(call->getCalledValue() == CGM.getARCEntrypoints().objc_retainBlock);
+
+ SmallVector<llvm::Value*,1> args;
+ call->setMetadata("clang.arc.copy_on_escape",
+ llvm::MDNode::get(Builder.getContext(), args));
+ }
+
+ return result;
}
/// Retain the given object which is the result of a function call.
@@ -1442,7 +1709,7 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
llvm::InlineAsm *&marker
= CGM.getARCEntrypoints().retainAutoreleasedReturnValueMarker;
if (!marker) {
- llvm::StringRef assembly
+ StringRef assembly
= CGM.getTargetCodeGenInfo()
.getARCRetainAutoreleasedReturnValueMarker();
@@ -1468,8 +1735,7 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
assert(metadata->getNumOperands() <= 1);
if (metadata->getNumOperands() == 0) {
llvm::Value *string = llvm::MDString::get(getLLVMContext(), assembly);
- llvm::Value *args[] = { string };
- metadata->addOperand(llvm::MDNode::get(getLLVMContext(), args));
+ metadata->addOperand(llvm::MDNode::get(getLLVMContext(), string));
}
}
}
@@ -1490,7 +1756,7 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
llvm::Constant *&fn = CGM.getARCEntrypoints().objc_release;
if (!fn) {
std::vector<llvm::Type*> args(1, Int8PtrTy);
- const llvm::FunctionType *fnType =
+ llvm::FunctionType *fnType =
llvm::FunctionType::get(Builder.getVoidTy(), args, false);
fn = createARCRuntimeFunction(CGM, fnType, "objc_release");
}
@@ -1503,7 +1769,7 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
call->setDoesNotThrow();
if (!precise) {
- llvm::SmallVector<llvm::Value*,1> args;
+ SmallVector<llvm::Value*,1> args;
call->setMetadata("clang.imprecise_release",
llvm::MDNode::get(Builder.getContext(), args));
}
@@ -1520,7 +1786,7 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(llvm::Value *addr,
llvm::Constant *&fn = CGM.getARCEntrypoints().objc_storeStrong;
if (!fn) {
llvm::Type *argTypes[] = { Int8PtrPtrTy, Int8PtrTy };
- const llvm::FunctionType *fnType
+ llvm::FunctionType *fnType
= llvm::FunctionType::get(Builder.getVoidTy(), argTypes, false);
fn = createARCRuntimeFunction(CGM, fnType, "objc_storeStrong");
}
@@ -1607,9 +1873,9 @@ llvm::Value *CodeGenFunction::EmitARCRetainAutorelease(QualType type,
if (isa<llvm::ConstantPointerNull>(value)) return value;
- const llvm::Type *origType = value->getType();
+ llvm::Type *origType = value->getType();
value = Builder.CreateBitCast(value, Int8PtrTy);
- value = EmitARCRetainBlock(value);
+ value = EmitARCRetainBlock(value, /*mandatory*/ true);
value = EmitARCAutorelease(value);
return Builder.CreateBitCast(value, origType);
}
@@ -1674,7 +1940,7 @@ void CodeGenFunction::EmitARCDestroyWeak(llvm::Value *addr) {
llvm::Constant *&fn = CGM.getARCEntrypoints().objc_destroyWeak;
if (!fn) {
std::vector<llvm::Type*> args(1, Int8PtrPtrTy);
- const llvm::FunctionType *fnType =
+ llvm::FunctionType *fnType =
llvm::FunctionType::get(Builder.getVoidTy(), args, false);
fn = createARCRuntimeFunction(CGM, fnType, "objc_destroyWeak");
}
@@ -1709,7 +1975,7 @@ void CodeGenFunction::EmitARCCopyWeak(llvm::Value *dst, llvm::Value *src) {
llvm::Value *CodeGenFunction::EmitObjCAutoreleasePoolPush() {
llvm::Constant *&fn = CGM.getRREntrypoints().objc_autoreleasePoolPush;
if (!fn) {
- const llvm::FunctionType *fnType =
+ llvm::FunctionType *fnType =
llvm::FunctionType::get(Int8PtrTy, false);
fn = createARCRuntimeFunction(CGM, fnType, "objc_autoreleasePoolPush");
}
@@ -1728,7 +1994,7 @@ void CodeGenFunction::EmitObjCAutoreleasePoolPop(llvm::Value *value) {
llvm::Constant *&fn = CGM.getRREntrypoints().objc_autoreleasePoolPop;
if (!fn) {
std::vector<llvm::Type*> args(1, Int8PtrTy);
- const llvm::FunctionType *fnType =
+ llvm::FunctionType *fnType =
llvm::FunctionType::get(Builder.getVoidTy(), args, false);
// We don't want to use a weak import here; instead we should not
@@ -1851,6 +2117,24 @@ static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
e = e->IgnoreParens();
QualType type = e->getType();
+ // If we're loading retained from a __strong xvalue, we can avoid
+ // an extra retain/release pair by zeroing out the source of this
+ // "move" operation.
+ if (e->isXValue() &&
+ !type.isConstQualified() &&
+ type.getObjCLifetime() == Qualifiers::OCL_Strong) {
+ // Emit the lvalue.
+ LValue lv = CGF.EmitLValue(e);
+
+ // Load the object pointer.
+ llvm::Value *result = CGF.EmitLoadOfLValue(lv).getScalarVal();
+
+ // Set the source pointer to NULL.
+ CGF.EmitStoreOfScalar(getNullForVariable(lv.getAddress()), lv);
+
+ return TryEmitResult(result, true);
+ }
+
// As a very special optimization, in ARC++, if the l-value is the
// result of a non-volatile assignment, do a simple retain of the
// result of the call to objc_storeWeak instead of reloading.
@@ -1913,35 +2197,53 @@ static llvm::Value *emitARCRetainAfterCall(CodeGenFunction &CGF,
}
}
+/// Determine whether it might be important to emit a separate
+/// objc_retain_block on the result of the given expression, or
+/// whether it's okay to just emit it in a +1 context.
+static bool shouldEmitSeparateBlockRetain(const Expr *e) {
+ assert(e->getType()->isBlockPointerType());
+ e = e->IgnoreParens();
+
+ // For future goodness, emit block expressions directly in +1
+ // contexts if we can.
+ if (isa<BlockExpr>(e))
+ return false;
+
+ if (const CastExpr *cast = dyn_cast<CastExpr>(e)) {
+ switch (cast->getCastKind()) {
+ // Emitting these operations in +1 contexts is goodness.
+ case CK_LValueToRValue:
+ case CK_ARCReclaimReturnedObject:
+ case CK_ARCConsumeObject:
+ case CK_ARCProduceObject:
+ return false;
+
+ // These operations preserve a block type.
+ case CK_NoOp:
+ case CK_BitCast:
+ return shouldEmitSeparateBlockRetain(cast->getSubExpr());
+
+ // These operations are known to be bad (or haven't been considered).
+ case CK_AnyPointerToBlockPointerCast:
+ default:
+ return true;
+ }
+ }
+
+ return true;
+}
+
static TryEmitResult
tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
+ // Look through cleanups.
+ if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) {
+ CodeGenFunction::RunCleanupsScope scope(CGF);
+ return tryEmitARCRetainScalarExpr(CGF, cleanups->getSubExpr());
+ }
+
// The desired result type, if it differs from the type of the
// ultimate opaque expression.
- const llvm::Type *resultType = 0;
-
- // If we're loading retained from a __strong xvalue, we can avoid
- // an extra retain/release pair by zeroing out the source of this
- // "move" operation.
- if (e->isXValue() && !e->getType().isConstQualified() &&
- e->getType().getObjCLifetime() == Qualifiers::OCL_Strong) {
- // Emit the lvalue
- LValue lv = CGF.EmitLValue(e);
-
- // Load the object pointer and cast it to the appropriate type.
- QualType exprType = e->getType();
- llvm::Value *result = CGF.EmitLoadOfLValue(lv).getScalarVal();
-
- if (resultType)
- result = CGF.Builder.CreateBitCast(result, resultType);
-
- // Set the source pointer to NULL.
- llvm::Value *null
- = llvm::ConstantPointerNull::get(
- cast<llvm::PointerType>(CGF.ConvertType(exprType)));
- CGF.EmitStoreOfScalar(null, lv);
-
- return TryEmitResult(result, true);
- }
+ llvm::Type *resultType = 0;
while (true) {
e = e->IgnoreParens();
@@ -1969,7 +2271,8 @@ tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
// These casts can change the type, so remember that and
// soldier on. We only need to remember the outermost such
// cast, though.
- case CK_AnyPointerToObjCPointerCast:
+ case CK_CPointerToObjCPointerCast:
+ case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
case CK_BitCast:
if (!resultType)
@@ -1980,15 +2283,49 @@ tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
// For consumptions, just emit the subexpression and thus elide
// the retain/release pair.
- case CK_ObjCConsumeObject: {
+ case CK_ARCConsumeObject: {
llvm::Value *result = CGF.EmitScalarExpr(ce->getSubExpr());
if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
return TryEmitResult(result, true);
}
+ // Block extends are net +0. Naively, we could just recurse on
+ // the subexpression, but actually we need to ensure that the
+ // value is copied as a block, so there's a little filter here.
+ case CK_ARCExtendBlockObject: {
+ llvm::Value *result; // will be a +0 value
+
+ // If we can't safely assume the sub-expression will produce a
+ // block-copied value, emit the sub-expression at +0.
+ if (shouldEmitSeparateBlockRetain(ce->getSubExpr())) {
+ result = CGF.EmitScalarExpr(ce->getSubExpr());
+
+ // Otherwise, try to emit the sub-expression at +1 recursively.
+ } else {
+ TryEmitResult subresult
+ = tryEmitARCRetainScalarExpr(CGF, ce->getSubExpr());
+ result = subresult.getPointer();
+
+ // If that produced a retained value, just use that,
+ // possibly casting down.
+ if (subresult.getInt()) {
+ if (resultType)
+ result = CGF.Builder.CreateBitCast(result, resultType);
+ return TryEmitResult(result, true);
+ }
+
+ // Otherwise it's +0.
+ }
+
+ // Retain the object as a block, then cast down.
+ result = CGF.EmitARCRetainBlock(result, /*mandatory*/ true);
+ if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
+ return TryEmitResult(result, true);
+ }
+
// For reclaims, emit the subexpression as a retained call and
// skip the consumption.
- case CK_ObjCReclaimReturnedObject: {
+ case CK_ARCReclaimReturnedObject: {
llvm::Value *result = emitARCRetainCall(CGF, ce->getSubExpr());
if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
return TryEmitResult(result, true);
@@ -2067,6 +2404,48 @@ CodeGenFunction::EmitARCRetainAutoreleaseScalarExpr(const Expr *e) {
return value;
}
+llvm::Value *CodeGenFunction::EmitARCExtendBlockObject(const Expr *e) {
+ llvm::Value *result;
+ bool doRetain;
+
+ if (shouldEmitSeparateBlockRetain(e)) {
+ result = EmitScalarExpr(e);
+ doRetain = true;
+ } else {
+ TryEmitResult subresult = tryEmitARCRetainScalarExpr(*this, e);
+ result = subresult.getPointer();
+ doRetain = !subresult.getInt();
+ }
+
+ if (doRetain)
+ result = EmitARCRetainBlock(result, /*mandatory*/ true);
+ return EmitObjCConsumeObject(e->getType(), result);
+}
+
+llvm::Value *CodeGenFunction::EmitObjCThrowOperand(const Expr *expr) {
+ // In ARC, retain and autorelease the expression.
+ if (getLangOptions().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.
+ CodeGenFunction::RunCleanupsScope cleanups(*this);
+ if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(expr))
+ expr = ewc->getSubExpr();
+
+ return EmitARCRetainAutoreleaseScalarExpr(expr);
+ }
+
+ // Otherwise, use the normal scalar-expression emission. The
+ // exception machinery doesn't do anything special with the
+ // exception like retaining it, so there's no safety associated with
+ // only running cleanups after the throw has started, and when it
+ // matters it tends to be substantially inferior code.
+ return EmitScalarExpr(expr);
+}
+
std::pair<LValue,llvm::Value*>
CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e,
bool ignored) {
@@ -2074,10 +2453,20 @@ CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e,
TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e->getRHS());
llvm::Value *value = result.getPointer();
+ bool hasImmediateRetain = result.getInt();
+
+ // If we didn't emit a retained object, and the l-value is of block
+ // type, then we need to emit the block-retain immediately in case
+ // it invalidates the l-value.
+ if (!hasImmediateRetain && e->getType()->isBlockPointerType()) {
+ value = EmitARCRetainBlock(value, /*mandatory*/ false);
+ hasImmediateRetain = true;
+ }
+
LValue lvalue = EmitLValue(e->getLHS());
// If the RHS was emitted retained, expand this.
- if (result.getInt()) {
+ if (hasImmediateRetain) {
llvm::Value *oldValue =
EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatileQualified(),
lvalue.getAlignment(), e->getType(),
@@ -2111,10 +2500,8 @@ void CodeGenFunction::EmitObjCAutoreleasePoolStmt(
const CompoundStmt &S = cast<CompoundStmt>(*subStmt);
CGDebugInfo *DI = getDebugInfo();
- if (DI) {
- DI->setLocation(S.getLBracLoc());
- DI->EmitRegionStart(Builder);
- }
+ if (DI)
+ DI->EmitLexicalBlockStart(Builder, S.getLBracLoc());
// Keep track of the current cleanup stack depth.
RunCleanupsScope Scope(*this);
@@ -2130,19 +2517,16 @@ void CodeGenFunction::EmitObjCAutoreleasePoolStmt(
E = S.body_end(); I != E; ++I)
EmitStmt(*I);
- if (DI) {
- DI->setLocation(S.getRBracLoc());
- DI->EmitRegionEnd(Builder);
- }
+ if (DI)
+ DI->EmitLexicalBlockEnd(Builder, S.getRBracLoc());
}
/// EmitExtendGCLifetime - Given a pointer to an Objective-C object,
/// make sure it survives garbage collection until this point.
void CodeGenFunction::EmitExtendGCLifetime(llvm::Value *object) {
// We just use an inline assembly.
- llvm::Type *paramTypes[] = { VoidPtrTy };
llvm::FunctionType *extenderType
- = llvm::FunctionType::get(VoidTy, paramTypes, /*variadic*/ false);
+ = llvm::FunctionType::get(VoidTy, VoidPtrTy, /*variadic*/ false);
llvm::Value *extender
= llvm::InlineAsm::get(extenderType,
/* assembly */ "",
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 61027feb5cb9..d3da649fbbf3 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -36,12 +36,11 @@
#include "llvm/Support/Compiler.h"
#include "llvm/Target/TargetData.h"
-#include <stdarg.h>
+#include <cstdarg>
using namespace clang;
using namespace CodeGen;
-using llvm::dyn_cast;
namespace {
@@ -82,7 +81,7 @@ class LazyRuntimeFunction {
if (!Function) {
if (0 == FunctionName) return 0;
// We put the return type on the end of the vector, so pop it back off
- const llvm::Type *RetTy = ArgTys.back();
+ llvm::Type *RetTy = ArgTys.back();
ArgTys.pop_back();
llvm::FunctionType *FTy = llvm::FunctionType::get(RetTy, ArgTys, false);
Function =
@@ -111,17 +110,17 @@ protected:
llvm::Module &TheModule;
/// strut objc_super. Used for sending messages to super. This structure
/// contains the receiver (object) and the expected class.
- const llvm::StructType *ObjCSuperTy;
+ llvm::StructType *ObjCSuperTy;
/// struct objc_super*. The type of the argument to the superclass message
/// lookup functions.
- const llvm::PointerType *PtrToObjCSuperTy;
+ llvm::PointerType *PtrToObjCSuperTy;
/// LLVM type for selectors. Opaque pointer (i8*) unless a header declaring
/// SEL is included in a header somewhere, in which case it will be whatever
/// type is declared in that header, most likely {i8*, i8*}.
llvm::PointerType *SelectorTy;
/// LLVM i8 type. Cached here to avoid repeatedly getting it in all of the
/// places where it's used
- const llvm::IntegerType *Int8Ty;
+ llvm::IntegerType *Int8Ty;
/// Pointer to i8 - LLVM type of char*, for all of the places where the
/// runtime needs to deal with C strings.
llvm::PointerType *PtrToInt8Ty;
@@ -138,7 +137,7 @@ protected:
llvm::PointerType *IdTy;
/// Pointer to a pointer to an Objective-C object. Used in the new ABI
/// message lookup function and some GC-related functions.
- const llvm::PointerType *PtrToIdTy;
+ llvm::PointerType *PtrToIdTy;
/// The clang type of id. Used when using the clang CGCall infrastructure to
/// call Objective-C methods.
CanQualType ASTIdTy;
@@ -153,14 +152,20 @@ protected:
/// compatibility with GCC...
llvm::IntegerType *LongTy;
/// LLVM type for C size_t. Used in various runtime data structures.
- const llvm::IntegerType *SizeTy;
+ llvm::IntegerType *SizeTy;
+ /// LLVM type for C intptr_t.
+ llvm::IntegerType *IntPtrTy;
/// LLVM type for C ptrdiff_t. Mainly used in property accessor functions.
- const llvm::IntegerType *PtrDiffTy;
+ llvm::IntegerType *PtrDiffTy;
/// LLVM type for C int*. Used for GCC-ABI-compatible non-fragile instance
/// variables.
- const llvm::PointerType *PtrToIntTy;
+ llvm::PointerType *PtrToIntTy;
/// LLVM type for Objective-C BOOL type.
- const llvm::Type *BoolTy;
+ llvm::Type *BoolTy;
+ /// 32-bit integer type, to save us needing to look it up every time it's used.
+ llvm::IntegerType *Int32Ty;
+ /// 64-bit integer type, to save us needing to look it up every time it's used.
+ llvm::IntegerType *Int64Ty;
/// Metadata kind used to tie method lookups to message sends. The GNUstep
/// runtime provides some LLVM passes that can use this to do things like
/// automatic IMP caching and speculative inlining.
@@ -171,7 +176,7 @@ protected:
llvm::Constant *MakeConstantString(const std::string &Str,
const std::string &Name="") {
llvm::Constant *ConstStr = CGM.GetAddrOfConstantCString(Str, Name.c_str());
- return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2);
+ return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros);
}
/// Emits a linkonce_odr string, whose name is the prefix followed by the
/// string value. This allows the linker to combine the strings between
@@ -186,14 +191,14 @@ protected:
ConstStr = new llvm::GlobalVariable(TheModule, value->getType(), true,
llvm::GlobalValue::LinkOnceODRLinkage, value, prefix + Str);
}
- return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2);
+ return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros);
}
/// Generates a global structure, initialized by the elements in the vector.
/// The element types must match the types of the structure elements in the
/// first argument.
- llvm::GlobalVariable *MakeGlobal(const llvm::StructType *Ty,
- std::vector<llvm::Constant*> &V,
- llvm::StringRef Name="",
+ llvm::GlobalVariable *MakeGlobal(llvm::StructType *Ty,
+ llvm::ArrayRef<llvm::Constant*> V,
+ StringRef Name="",
llvm::GlobalValue::LinkageTypes linkage
=llvm::GlobalValue::InternalLinkage) {
llvm::Constant *C = llvm::ConstantStruct::get(Ty, V);
@@ -203,9 +208,9 @@ protected:
/// Generates a global array. The vector must contain the same number of
/// elements that the array type declares, of the type specified as the array
/// element type.
- llvm::GlobalVariable *MakeGlobal(const llvm::ArrayType *Ty,
- std::vector<llvm::Constant*> &V,
- llvm::StringRef Name="",
+ llvm::GlobalVariable *MakeGlobal(llvm::ArrayType *Ty,
+ llvm::ArrayRef<llvm::Constant*> V,
+ StringRef Name="",
llvm::GlobalValue::LinkageTypes linkage
=llvm::GlobalValue::InternalLinkage) {
llvm::Constant *C = llvm::ConstantArray::get(Ty, V);
@@ -214,9 +219,9 @@ protected:
}
/// Generates a global array, inferring the array type from the specified
/// element type and the size of the initialiser.
- llvm::GlobalVariable *MakeGlobalArray(const llvm::Type *Ty,
- std::vector<llvm::Constant*> &V,
- llvm::StringRef Name="",
+ llvm::GlobalVariable *MakeGlobalArray(llvm::Type *Ty,
+ llvm::ArrayRef<llvm::Constant*> V,
+ StringRef Name="",
llvm::GlobalValue::LinkageTypes linkage
=llvm::GlobalValue::InternalLinkage) {
llvm::ArrayType *ArrayTy = llvm::ArrayType::get(Ty, V.size());
@@ -225,7 +230,7 @@ protected:
/// 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, const 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);
}
@@ -268,7 +273,7 @@ private:
/// Type of the selector map. This is roughly equivalent to the structure
/// used in the GNUstep runtime, which maintains a list of all of the valid
/// types for a selector in a table.
- typedef llvm::DenseMap<Selector, llvm::SmallVector<TypedSelector, 2> >
+ typedef llvm::DenseMap<Selector, SmallVector<TypedSelector, 2> >
SelectorMap;
/// A map from selectors to selector types. This allows us to emit all
/// selectors of the same name and type together.
@@ -332,18 +337,18 @@ private:
/// metadata. This is used purely for introspection in the fragile ABI. In
/// the non-fragile ABI, it's used for instance variable fixup.
llvm::Constant *GenerateIvarList(
- const llvm::SmallVectorImpl<llvm::Constant *> &IvarNames,
- const llvm::SmallVectorImpl<llvm::Constant *> &IvarTypes,
- const llvm::SmallVectorImpl<llvm::Constant *> &IvarOffsets);
+ const SmallVectorImpl<llvm::Constant *> &IvarNames,
+ const SmallVectorImpl<llvm::Constant *> &IvarTypes,
+ const SmallVectorImpl<llvm::Constant *> &IvarOffsets);
/// Generates a method list structure. This is a structure containing a size
/// and an array of structures containing method metadata.
///
/// This structure is used by both classes and categories, and contains a next
/// pointer allowing them to be chained together in a linked list.
- llvm::Constant *GenerateMethodList(const llvm::StringRef &ClassName,
- const llvm::StringRef &CategoryName,
- const llvm::SmallVectorImpl<Selector> &MethodSels,
- const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes,
+ llvm::Constant *GenerateMethodList(const StringRef &ClassName,
+ const StringRef &CategoryName,
+ const SmallVectorImpl<Selector> &MethodSels,
+ const SmallVectorImpl<llvm::Constant *> &MethodTypes,
bool isClassMethodList);
/// Emits an empty protocol. This is used for @protocol() where no protocol
/// is found. The runtime will (hopefully) fix up the pointer to refer to the
@@ -352,12 +357,12 @@ private:
/// Generates a list of property metadata structures. This follows the same
/// pattern as method and instance variable metadata lists.
llvm::Constant *GeneratePropertyList(const ObjCImplementationDecl *OID,
- llvm::SmallVectorImpl<Selector> &InstanceMethodSels,
- llvm::SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes);
+ SmallVectorImpl<Selector> &InstanceMethodSels,
+ SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes);
/// Generates a list of referenced protocols. Classes, categories, and
/// protocols all use this structure.
llvm::Constant *GenerateProtocolList(
- const llvm::SmallVectorImpl<std::string> &Protocols);
+ const SmallVectorImpl<std::string> &Protocols);
/// To ensure that all protocols are seen by the runtime, we add a category on
/// 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
@@ -376,12 +381,14 @@ private:
llvm::Constant *Protocols,
llvm::Constant *IvarOffsets,
llvm::Constant *Properties,
+ llvm::Constant *StrongIvarBitmap,
+ llvm::Constant *WeakIvarBitmap,
bool isMeta=false);
/// Generates a method list. This is used by protocols to define the required
/// and optional methods.
llvm::Constant *GenerateProtocolMethodList(
- const llvm::SmallVectorImpl<llvm::Constant *> &MethodNames,
- const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes);
+ const SmallVectorImpl<llvm::Constant *> &MethodNames,
+ const SmallVectorImpl<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,
@@ -403,12 +410,24 @@ protected:
llvm::Value *&Receiver,
llvm::Value *cmd,
llvm::MDNode *node) = 0;
- /// Looks up the method for sending a message to a superclass. This mechanism
- /// differs between the GCC and GNU runtimes, so this method must be
- /// overridden in subclasses.
+ /// Looks up the method for sending a message to a superclass. This
+ /// mechanism differs between the GCC and GNU runtimes, so this method must
+ /// be overridden in subclasses.
virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF,
llvm::Value *ObjCSuper,
llvm::Value *cmd) = 0;
+ /// Libobjc2 uses a bitfield representation where small(ish) bitfields are
+ /// stored in a 64-bit value with the low bit set to 1 and the remaining 63
+ /// bits set to their values, LSB first, while larger ones are stored in a
+ /// structure of this / form:
+ ///
+ /// struct { int32_t length; int32_t values[length]; };
+ ///
+ /// The values in the array are stored in host-endian format, with the least
+ /// significant bit being assumed to come first in the bitfield. Therefore,
+ /// a bitfield with the 64th bit set will be (int64_t)&{ 2, [0, 1<<31] },
+ /// while a bitfield / with the 63rd bit set will be 1<<64.
+ llvm::Constant *MakeBitField(llvm::SmallVectorImpl<bool> &bits);
public:
CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
unsigned protocolClassVersion);
@@ -622,7 +641,7 @@ class CGObjCGNUstep : public CGObjCGNU {
// void *__cxa_begin_catch(void *e)
EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy, NULL);
// void __cxa_end_catch(void)
- EnterCatchFn.init(&CGM, "__cxa_end_catch", VoidTy, NULL);
+ ExitCatchFn.init(&CGM, "__cxa_end_catch", VoidTy, NULL);
// void _Unwind_Resume_or_Rethrow(void*)
ExceptionReThrowFn.init(&CGM, "_Unwind_Resume_or_Rethrow", VoidTy, PtrTy, NULL);
}
@@ -650,13 +669,13 @@ void CGObjCGNU::EmitClassRef(const std::string &className) {
llvm::GlobalValue::WeakAnyLinkage, ClassSymbol, symbolRef);
}
-static std::string SymbolNameForMethod(const llvm::StringRef &ClassName,
- const llvm::StringRef &CategoryName, const Selector MethodName,
+static std::string SymbolNameForMethod(const StringRef &ClassName,
+ const StringRef &CategoryName, const Selector MethodName,
bool isClassMethod) {
std::string MethodNameColonStripped = MethodName.getAsString();
std::replace(MethodNameColonStripped.begin(), MethodNameColonStripped.end(),
':', '_');
- return (llvm::Twine(isClassMethod ? "_c_" : "_i_") + ClassName + "_" +
+ return (Twine(isClassMethod ? "_c_" : "_i_") + ClassName + "_" +
CategoryName + "_" + MethodNameColonStripped).str();
}
@@ -697,6 +716,12 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
PtrToIntTy = llvm::PointerType::getUnqual(IntTy);
PtrTy = PtrToInt8Ty;
+ Int32Ty = llvm::Type::getInt32Ty(VMContext);
+ Int64Ty = llvm::Type::getInt64Ty(VMContext);
+
+ IntPtrTy =
+ TheModule.getPointerSize() == llvm::Module::Pointer32 ? Int32Ty : Int64Ty;
+
// Object type
QualType UnqualIdTy = CGM.getContext().getObjCIdType();
ASTIdTy = CanQualType();
@@ -744,11 +769,11 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
true));
const LangOptions &Opts = CGM.getLangOptions();
- if ((Opts.getGCMode() != LangOptions::NonGC) || Opts.ObjCAutoRefCount)
+ if ((Opts.getGC() != LangOptions::NonGC) || Opts.ObjCAutoRefCount)
RuntimeVersion = 10;
// Don't bother initialising the GC stuff unless we're compiling in GC mode
- if (Opts.getGCMode() != LangOptions::NonGC) {
+ if (Opts.getGC() != LangOptions::NonGC) {
// This is a bit of an hack. We should sort this out by having a proper
// CGObjCGNUstep subclass for GC, but we may want to really support the old
// ABI and GC added in ObjectiveC2.framework, so we fudge it a bit for now
@@ -793,9 +818,8 @@ llvm::Value *CGObjCGNU::GetClassNamed(CGBuilderTy &Builder,
EmitClassRef(Name);
ClassName = Builder.CreateStructGEP(ClassName, 0);
- llvm::Type *ArgTys[] = { PtrToInt8Ty };
llvm::Constant *ClassLookupFn =
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, ArgTys, true),
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, PtrToInt8Ty, true),
"objc_lookup_class");
return Builder.CreateCall(ClassLookupFn, ClassName);
}
@@ -813,11 +837,11 @@ llvm::Value *CGObjCGNU::EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) {
llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel,
const std::string &TypeEncoding, bool lval) {
- llvm::SmallVector<TypedSelector, 2> &Types = SelectorTable[Sel];
+ SmallVector<TypedSelector, 2> &Types = SelectorTable[Sel];
llvm::GlobalAlias *SelValue = 0;
- for (llvm::SmallVectorImpl<TypedSelector>::iterator i = Types.begin(),
+ for (SmallVectorImpl<TypedSelector>::iterator i = Types.begin(),
e = Types.end() ; i!=e ; i++) {
if (i->first == TypeEncoding) {
SelValue = i->second;
@@ -918,7 +942,7 @@ llvm::Constant *CGObjCGNU::GetEHType(QualType T) {
llvm::GlobalValue::ExternalLinkage, 0, vtableName);
}
llvm::Constant *Two = llvm::ConstantInt::get(IntTy, 2);
- Vtable = llvm::ConstantExpr::getGetElementPtr(Vtable, &Two, 1);
+ Vtable = llvm::ConstantExpr::getGetElementPtr(Vtable, Two);
Vtable = llvm::ConstantExpr::getBitCast(Vtable, PtrToInt8Ty);
llvm::Constant *typeName =
@@ -972,7 +996,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method) {
CGBuilderTy &Builder = CGF.Builder;
- if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly) {
+ if (CGM.getLangOptions().getGC() == LangOptions::GCOnly) {
if (Sel == RetainSel || Sel == AutoreleaseSel) {
return RValue::get(EnforceType(Builder, Receiver,
CGM.getTypes().ConvertType(ResultType)));
@@ -999,13 +1023,11 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
if (isCategoryImpl) {
llvm::Constant *classLookupFunction = 0;
if (IsClassMessage) {
- llvm::Type *ArgTys[] = { PtrTy };
classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
- IdTy, ArgTys, true), "objc_get_meta_class");
+ IdTy, PtrTy, true), "objc_get_meta_class");
} else {
- llvm::Type *ArgTys[] = { PtrTy };
classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
- IdTy, ArgTys, true), "objc_get_class");
+ IdTy, PtrTy, true), "objc_get_class");
}
ReceiverClass = Builder.CreateCall(classLookupFunction,
MakeConstantString(Class->getNameAsString()));
@@ -1048,7 +1070,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
Builder.CreateStore(ReceiverClass, Builder.CreateStructGEP(ObjCSuper, 1));
ObjCSuper = EnforceType(Builder, ObjCSuper, PtrToObjCSuperTy);
- const llvm::FunctionType *impType =
+ llvm::FunctionType *impType =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
// Get the IMP
@@ -1082,7 +1104,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
CGBuilderTy &Builder = CGF.Builder;
// Strip out message sends to retain / release in GC mode
- if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly) {
+ if (CGM.getLangOptions().getGC() == LangOptions::GCOnly) {
if (Sel == RetainSel || Sel == AutoreleaseSel) {
return RValue::get(EnforceType(Builder, Receiver,
CGM.getTypes().ConvertType(ResultType)));
@@ -1148,7 +1170,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
FunctionType::ExtInfo());
- const llvm::FunctionType *impType =
+ llvm::FunctionType *impType =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
imp = EnforceType(Builder, imp, llvm::PointerType::getUnqual(impType));
@@ -1175,7 +1197,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
} else if (msgRet.isAggregate()) {
llvm::Value *v = msgRet.getAggregateAddr();
llvm::PHINode *phi = Builder.CreatePHI(v->getType(), 2);
- const llvm::PointerType *RetTy = cast<llvm::PointerType>(v->getType());
+ llvm::PointerType *RetTy = cast<llvm::PointerType>(v->getType());
llvm::AllocaInst *NullVal =
CGF.CreateTempAlloca(RetTy->getElementType(), "null");
CGF.InitTempAlloca(NullVal,
@@ -1201,10 +1223,10 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
/// Generates a MethodList. Used in construction of a objc_class and
/// objc_category structures.
-llvm::Constant *CGObjCGNU::GenerateMethodList(const llvm::StringRef &ClassName,
- const llvm::StringRef &CategoryName,
- const llvm::SmallVectorImpl<Selector> &MethodSels,
- const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes,
+llvm::Constant *CGObjCGNU::GenerateMethodList(const StringRef &ClassName,
+ const StringRef &CategoryName,
+ const SmallVectorImpl<Selector> &MethodSels,
+ const SmallVectorImpl<llvm::Constant *> &MethodTypes,
bool isClassMethodList) {
if (MethodSels.empty())
return NULLPtr;
@@ -1239,8 +1261,7 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const llvm::StringRef &ClassName,
Methods);
// Structure containing list pointer, array and array count
- llvm::StructType *ObjCMethodListTy =
- llvm::StructType::createNamed(VMContext, "");
+ llvm::StructType *ObjCMethodListTy = llvm::StructType::create(VMContext);
llvm::Type *NextPtrTy = llvm::PointerType::getUnqual(ObjCMethodListTy);
ObjCMethodListTy->setBody(
NextPtrTy,
@@ -1251,8 +1272,7 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const llvm::StringRef &ClassName,
Methods.clear();
Methods.push_back(llvm::ConstantPointerNull::get(
llvm::PointerType::getUnqual(ObjCMethodListTy)));
- Methods.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
- MethodTypes.size()));
+ Methods.push_back(llvm::ConstantInt::get(Int32Ty, MethodTypes.size()));
Methods.push_back(MethodArray);
// Create an instance of the structure
@@ -1261,9 +1281,9 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const llvm::StringRef &ClassName,
/// Generates an IvarList. Used in construction of a objc_class.
llvm::Constant *CGObjCGNU::GenerateIvarList(
- const llvm::SmallVectorImpl<llvm::Constant *> &IvarNames,
- const llvm::SmallVectorImpl<llvm::Constant *> &IvarTypes,
- const llvm::SmallVectorImpl<llvm::Constant *> &IvarOffsets) {
+ const SmallVectorImpl<llvm::Constant *> &IvarNames,
+ const SmallVectorImpl<llvm::Constant *> &IvarTypes,
+ const SmallVectorImpl<llvm::Constant *> &IvarOffsets) {
if (IvarNames.size() == 0)
return NULLPtr;
// Get the method structure type.
@@ -1312,6 +1332,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
llvm::Constant *Protocols,
llvm::Constant *IvarOffsets,
llvm::Constant *Properties,
+ llvm::Constant *StrongIvarBitmap,
+ llvm::Constant *WeakIvarBitmap,
bool isMeta) {
// Set up the class structure
// Note: Several of these are char*s when they should be ids. This is
@@ -1339,6 +1361,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
LongTy, // abi_version
IvarOffsets->getType(), // ivar_offsets
Properties->getType(), // properties
+ Int64Ty, // strong_pointers
+ Int64Ty, // weak_pointers
NULL);
llvm::Constant *Zero = llvm::ConstantInt::get(LongTy, 0);
// Fill in the structure
@@ -1363,9 +1387,11 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
Elements.push_back(NULLPtr);
Elements.push_back(llvm::ConstantExpr::getBitCast(Protocols, PtrTy));
Elements.push_back(NULLPtr);
- Elements.push_back(Zero);
+ Elements.push_back(llvm::ConstantInt::get(LongTy, 1));
Elements.push_back(IvarOffsets);
Elements.push_back(Properties);
+ Elements.push_back(StrongIvarBitmap);
+ Elements.push_back(WeakIvarBitmap);
// Create an instance of the structure
// This is now an externally visible symbol, so that we can speed up class
// messages in the next ABI.
@@ -1374,8 +1400,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
}
llvm::Constant *CGObjCGNU::GenerateProtocolMethodList(
- const llvm::SmallVectorImpl<llvm::Constant *> &MethodNames,
- const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes) {
+ const SmallVectorImpl<llvm::Constant *> &MethodNames,
+ const SmallVectorImpl<llvm::Constant *> &MethodTypes) {
// Get the method structure type.
llvm::StructType *ObjCMethodDescTy = llvm::StructType::get(
PtrToInt8Ty, // Really a selector, but the runtime does the casting for us.
@@ -1403,7 +1429,7 @@ llvm::Constant *CGObjCGNU::GenerateProtocolMethodList(
// Create the protocol list structure used in classes, categories and so on
llvm::Constant *CGObjCGNU::GenerateProtocolList(
- const llvm::SmallVectorImpl<std::string> &Protocols) {
+ const SmallVectorImpl<std::string> &Protocols) {
llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(PtrToInt8Ty,
Protocols.size());
llvm::StructType *ProtocolListTy = llvm::StructType::get(
@@ -1438,15 +1464,15 @@ llvm::Constant *CGObjCGNU::GenerateProtocolList(
llvm::Value *CGObjCGNU::GenerateProtocolRef(CGBuilderTy &Builder,
const ObjCProtocolDecl *PD) {
llvm::Value *protocol = ExistingProtocols[PD->getNameAsString()];
- const llvm::Type *T =
+ llvm::Type *T =
CGM.getTypes().ConvertType(CGM.getContext().getObjCProtoType());
return Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T));
}
llvm::Constant *CGObjCGNU::GenerateEmptyProtocol(
const std::string &ProtocolName) {
- llvm::SmallVector<std::string, 0> EmptyStringVector;
- llvm::SmallVector<llvm::Constant*, 0> EmptyConstantVector;
+ SmallVector<std::string, 0> EmptyStringVector;
+ SmallVector<llvm::Constant*, 0> EmptyConstantVector;
llvm::Constant *ProtocolList = GenerateProtocolList(EmptyStringVector);
llvm::Constant *MethodList =
@@ -1465,8 +1491,7 @@ llvm::Constant *CGObjCGNU::GenerateEmptyProtocol(
// The isa pointer must be set to a magic number so the runtime knows it's
// the correct layout.
Elements.push_back(llvm::ConstantExpr::getIntToPtr(
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
- ProtocolVersion), IdTy));
+ llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy));
Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name"));
Elements.push_back(ProtocolList);
Elements.push_back(MethodList);
@@ -1479,14 +1504,14 @@ llvm::Constant *CGObjCGNU::GenerateEmptyProtocol(
void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
ASTContext &Context = CGM.getContext();
std::string ProtocolName = PD->getNameAsString();
- llvm::SmallVector<std::string, 16> Protocols;
+ SmallVector<std::string, 16> Protocols;
for (ObjCProtocolDecl::protocol_iterator PI = PD->protocol_begin(),
E = PD->protocol_end(); PI != E; ++PI)
Protocols.push_back((*PI)->getNameAsString());
- llvm::SmallVector<llvm::Constant*, 16> InstanceMethodNames;
- llvm::SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
- llvm::SmallVector<llvm::Constant*, 16> OptionalInstanceMethodNames;
- llvm::SmallVector<llvm::Constant*, 16> OptionalInstanceMethodTypes;
+ SmallVector<llvm::Constant*, 16> InstanceMethodNames;
+ SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
+ SmallVector<llvm::Constant*, 16> OptionalInstanceMethodNames;
+ SmallVector<llvm::Constant*, 16> OptionalInstanceMethodTypes;
for (ObjCProtocolDecl::instmeth_iterator iter = PD->instmeth_begin(),
E = PD->instmeth_end(); iter != E; iter++) {
std::string TypeStr;
@@ -1502,10 +1527,10 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
}
}
// Collect information about class methods:
- llvm::SmallVector<llvm::Constant*, 16> ClassMethodNames;
- llvm::SmallVector<llvm::Constant*, 16> ClassMethodTypes;
- llvm::SmallVector<llvm::Constant*, 16> OptionalClassMethodNames;
- llvm::SmallVector<llvm::Constant*, 16> OptionalClassMethodTypes;
+ SmallVector<llvm::Constant*, 16> ClassMethodNames;
+ SmallVector<llvm::Constant*, 16> ClassMethodTypes;
+ SmallVector<llvm::Constant*, 16> OptionalClassMethodNames;
+ SmallVector<llvm::Constant*, 16> OptionalClassMethodTypes;
for (ObjCProtocolDecl::classmeth_iterator
iter = PD->classmeth_begin(), endIter = PD->classmeth_end();
iter != endIter ; iter++) {
@@ -1626,8 +1651,7 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
// The isa pointer must be set to a magic number so the runtime knows it's
// the correct layout.
Elements.push_back(llvm::ConstantExpr::getIntToPtr(
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
- ProtocolVersion), IdTy));
+ llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy));
Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name"));
Elements.push_back(ProtocolList);
Elements.push_back(InstanceMethodList);
@@ -1642,8 +1666,8 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
}
void CGObjCGNU::GenerateProtocolHolderCategory(void) {
// Collect information about instance methods
- llvm::SmallVector<Selector, 1> MethodSels;
- llvm::SmallVector<llvm::Constant*, 1> MethodTypes;
+ SmallVector<Selector, 1> MethodSels;
+ SmallVector<llvm::Constant*, 1> MethodTypes;
std::vector<llvm::Constant*> Elements;
const std::string ClassName = "__ObjC_Protocol_Holder_Ugly_Hack";
@@ -1686,12 +1710,55 @@ void CGObjCGNU::GenerateProtocolHolderCategory(void) {
PtrTy, PtrTy, PtrTy, NULL), Elements), PtrTy));
}
+/// Libobjc2 uses a bitfield representation where small(ish) bitfields are
+/// stored in a 64-bit value with the low bit set to 1 and the remaining 63
+/// bits set to their values, LSB first, while larger ones are stored in a
+/// structure of this / form:
+///
+/// struct { int32_t length; int32_t values[length]; };
+///
+/// The values in the array are stored in host-endian format, with the least
+/// significant bit being assumed to come first in the bitfield. Therefore, a
+/// bitfield with the 64th bit set will be (int64_t)&{ 2, [0, 1<<31] }, while a
+/// bitfield / with the 63rd bit set will be 1<<64.
+llvm::Constant *CGObjCGNU::MakeBitField(llvm::SmallVectorImpl<bool> &bits) {
+ int bitCount = bits.size();
+ if (bitCount < 64) {
+ uint64_t val = 1;
+ for (int i=0 ; i<bitCount ; ++i) {
+ if (bits[i]) val |= 1ULL<<(i+1);
+ }
+ return llvm::ConstantInt::get(Int64Ty, val);
+ }
+ llvm::SmallVector<llvm::Constant*, 8> values;
+ int v=0;
+ while (v < bitCount) {
+ int32_t word = 0;
+ for (int i=0 ; (i<32) && (v<bitCount) ; ++i) {
+ if (bits[v]) word |= 1<<i;
+ v++;
+ }
+ values.push_back(llvm::ConstantInt::get(Int32Ty, word));
+ }
+ llvm::ArrayType *arrayTy = llvm::ArrayType::get(Int32Ty, values.size());
+ llvm::Constant *array = llvm::ConstantArray::get(arrayTy, values);
+ llvm::Constant *fields[2] = {
+ llvm::ConstantInt::get(Int32Ty, values.size()),
+ array };
+ llvm::Constant *GS = MakeGlobal(llvm::StructType::get(Int32Ty, arrayTy,
+ NULL), fields);
+ llvm::Constant *ptr = llvm::ConstantExpr::getPtrToInt(GS, IntPtrTy);
+ if (IntPtrTy != Int64Ty)
+ ptr = llvm::ConstantExpr::getZExt(ptr, Int64Ty);
+ return ptr;
+}
+
void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
std::string ClassName = OCD->getClassInterface()->getNameAsString();
std::string CategoryName = OCD->getNameAsString();
// Collect information about instance methods
- llvm::SmallVector<Selector, 16> InstanceMethodSels;
- llvm::SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
+ SmallVector<Selector, 16> InstanceMethodSels;
+ SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
for (ObjCCategoryImplDecl::instmeth_iterator
iter = OCD->instmeth_begin(), endIter = OCD->instmeth_end();
iter != endIter ; iter++) {
@@ -1702,8 +1769,8 @@ void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
}
// Collect information about class methods
- llvm::SmallVector<Selector, 16> ClassMethodSels;
- llvm::SmallVector<llvm::Constant*, 16> ClassMethodTypes;
+ SmallVector<Selector, 16> ClassMethodSels;
+ SmallVector<llvm::Constant*, 16> ClassMethodTypes;
for (ObjCCategoryImplDecl::classmeth_iterator
iter = OCD->classmeth_begin(), endIter = OCD->classmeth_end();
iter != endIter ; iter++) {
@@ -1714,7 +1781,7 @@ void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
}
// Collect the names of referenced protocols
- llvm::SmallVector<std::string, 16> Protocols;
+ SmallVector<std::string, 16> Protocols;
const ObjCCategoryDecl *CatDecl = OCD->getCategoryDecl();
const ObjCList<ObjCProtocolDecl> &Protos = CatDecl->getReferencedProtocols();
for (ObjCList<ObjCProtocolDecl>::iterator I = Protos.begin(),
@@ -1741,8 +1808,8 @@ void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
}
llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OID,
- llvm::SmallVectorImpl<Selector> &InstanceMethodSels,
- llvm::SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes) {
+ SmallVectorImpl<Selector> &InstanceMethodSels,
+ SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes) {
ASTContext &Context = CGM.getContext();
//
// Property metadata: name, attributes, isSynthesized, setter name, setter
@@ -1845,11 +1912,13 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
Context.getASTObjCImplementationLayout(OID).getSize().getQuantity();
// Collect information about instance variables.
- llvm::SmallVector<llvm::Constant*, 16> IvarNames;
- llvm::SmallVector<llvm::Constant*, 16> IvarTypes;
- llvm::SmallVector<llvm::Constant*, 16> IvarOffsets;
+ SmallVector<llvm::Constant*, 16> IvarNames;
+ SmallVector<llvm::Constant*, 16> IvarTypes;
+ SmallVector<llvm::Constant*, 16> IvarOffsets;
std::vector<llvm::Constant*> IvarOffsetValues;
+ SmallVector<bool, 16> WeakIvars;
+ SmallVector<bool, 16> StrongIvars;
int superInstanceSize = !SuperClassDecl ? 0 :
Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize().getQuantity();
@@ -1859,12 +1928,8 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
instanceSize = 0 - (instanceSize - superInstanceSize);
}
- // Collect declared and synthesized ivars.
- llvm::SmallVector<ObjCIvarDecl*, 16> OIvars;
- CGM.getContext().ShallowCollectObjCIvars(ClassDecl, OIvars);
-
- for (unsigned i = 0, e = OIvars.size(); i != e; ++i) {
- ObjCIvarDecl *IVD = OIvars[i];
+ for (const ObjCIvarDecl *IVD = ClassDecl->all_declared_ivar_begin(); IVD;
+ IVD = IVD->getNextIvar()) {
// Store the name
IvarNames.push_back(MakeConstantString(IVD->getNameAsString()));
// Get the type encoding for this ivar
@@ -1896,14 +1961,30 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
IVD->getNameAsString());
IvarOffsets.push_back(OffsetValue);
IvarOffsetValues.push_back(OffsetVar);
+ Qualifiers::ObjCLifetime lt = IVD->getType().getQualifiers().getObjCLifetime();
+ switch (lt) {
+ case Qualifiers::OCL_Strong:
+ StrongIvars.push_back(true);
+ WeakIvars.push_back(false);
+ break;
+ case Qualifiers::OCL_Weak:
+ StrongIvars.push_back(false);
+ WeakIvars.push_back(true);
+ break;
+ default:
+ StrongIvars.push_back(false);
+ WeakIvars.push_back(false);
+ }
}
+ llvm::Constant *StrongIvarBitmap = MakeBitField(StrongIvars);
+ llvm::Constant *WeakIvarBitmap = MakeBitField(WeakIvars);
llvm::GlobalVariable *IvarOffsetArray =
MakeGlobalArray(PtrToIntTy, IvarOffsetValues, ".ivar.offsets");
// Collect information about instance methods
- llvm::SmallVector<Selector, 16> InstanceMethodSels;
- llvm::SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
+ SmallVector<Selector, 16> InstanceMethodSels;
+ SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
for (ObjCImplementationDecl::instmeth_iterator
iter = OID->instmeth_begin(), endIter = OID->instmeth_end();
iter != endIter ; iter++) {
@@ -1918,8 +1999,8 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
// Collect information about class methods
- llvm::SmallVector<Selector, 16> ClassMethodSels;
- llvm::SmallVector<llvm::Constant*, 16> ClassMethodTypes;
+ SmallVector<Selector, 16> ClassMethodSels;
+ SmallVector<llvm::Constant*, 16> ClassMethodTypes;
for (ObjCImplementationDecl::classmeth_iterator
iter = OID->classmeth_begin(), endIter = OID->classmeth_end();
iter != endIter ; iter++) {
@@ -1929,7 +2010,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
ClassMethodTypes.push_back(MakeConstantString(TypeStr));
}
// Collect the names of referenced protocols
- llvm::SmallVector<std::string, 16> Protocols;
+ SmallVector<std::string, 16> Protocols;
const ObjCList<ObjCProtocolDecl> &Protos =ClassDecl->getReferencedProtocols();
for (ObjCList<ObjCProtocolDecl>::iterator I = Protos.begin(),
E = Protos.end(); I != E; ++I)
@@ -1945,7 +2026,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
SuperClass = llvm::ConstantPointerNull::get(PtrToInt8Ty);
}
// Empty vector used to construct empty method lists
- llvm::SmallVector<llvm::Constant*, 1> empty;
+ SmallVector<llvm::Constant*, 1> empty;
// Generate the method and instance variable lists
llvm::Constant *MethodList = GenerateMethodList(ClassName, "",
InstanceMethodSels, InstanceMethodTypes, false);
@@ -1963,20 +2044,20 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
// setting up the alias. These are: The base address for the global, the
// ivar array (second field), the ivar in this list (set for each ivar), and
// the offset (third field in ivar structure)
- const llvm::Type *IndexTy = llvm::Type::getInt32Ty(VMContext);
+ llvm::Type *IndexTy = Int32Ty;
llvm::Constant *offsetPointerIndexes[] = {Zeros[0],
llvm::ConstantInt::get(IndexTy, 1), 0,
llvm::ConstantInt::get(IndexTy, 2) };
-
- for (unsigned i = 0, e = OIvars.size(); i != e; ++i) {
- ObjCIvarDecl *IVD = OIvars[i];
+ unsigned ivarIndex = 0;
+ for (const ObjCIvarDecl *IVD = ClassDecl->all_declared_ivar_begin(); IVD;
+ IVD = IVD->getNextIvar()) {
const std::string Name = "__objc_ivar_offset_" + ClassName + '.'
+ IVD->getNameAsString();
- offsetPointerIndexes[2] = llvm::ConstantInt::get(IndexTy, i);
+ offsetPointerIndexes[2] = llvm::ConstantInt::get(IndexTy, ivarIndex);
// Get the correct ivar field
llvm::Constant *offsetValue = llvm::ConstantExpr::getGetElementPtr(
- IvarList, offsetPointerIndexes, 4);
+ IvarList, offsetPointerIndexes);
// Get the existing variable, if one exists.
llvm::GlobalVariable *offset = TheModule.getNamedGlobal(Name);
if (offset) {
@@ -1990,11 +2071,14 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
offset = new llvm::GlobalVariable(TheModule, offsetValue->getType(),
false, llvm::GlobalValue::ExternalLinkage, offsetValue, Name);
}
+ ++ivarIndex;
}
+ llvm::Constant *Zero64 = llvm::ConstantInt::get(Int64Ty, 0);
//Generate metaclass for class methods
llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr,
NULLPtr, 0x12L, ClassName.c_str(), 0, Zeros[0], GenerateIvarList(
- empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr, true);
+ empty, empty, empty), ClassMethodList, NULLPtr,
+ NULLPtr, NULLPtr, Zero64, Zero64, true);
// Generate the class structure
llvm::Constant *ClassStruct =
@@ -2002,7 +2086,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
ClassName.c_str(), 0,
llvm::ConstantInt::get(LongTy, instanceSize), IvarList,
MethodList, GenerateProtocolList(Protocols), IvarOffsetArray,
- Properties);
+ Properties, StrongIvarBitmap, WeakIvarBitmap);
// Resolve the class aliases, if they exist.
if (ClassPtrAlias) {
@@ -2033,7 +2117,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
// Add all referenced protocols to a category.
GenerateProtocolHolderCategory();
- const llvm::StructType *SelStructTy = dyn_cast<llvm::StructType>(
+ llvm::StructType *SelStructTy = dyn_cast<llvm::StructType>(
SelectorTy->getElementType());
llvm::Type *SelStructPtrTy = SelectorTy;
if (SelStructTy == 0) {
@@ -2049,7 +2133,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
ConstantStrings.size() + 1);
ConstantStrings.push_back(NULLPtr);
- llvm::StringRef StringClass = CGM.getLangOptions().ObjCConstantStringClass;
+ StringRef StringClass = CGM.getLangOptions().ObjCConstantStringClass;
if (StringClass.empty()) StringClass = "NXConstantString";
@@ -2088,8 +2172,8 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
std::string SelNameStr = iter->first.getAsString();
llvm::Constant *SelName = ExportUniqueString(SelNameStr, ".objc_sel_name");
- llvm::SmallVectorImpl<TypedSelector> &Types = iter->second;
- for (llvm::SmallVectorImpl<TypedSelector>::iterator i = Types.begin(),
+ SmallVectorImpl<TypedSelector> &Types = iter->second;
+ for (SmallVectorImpl<TypedSelector>::iterator i = Types.begin(),
e = Types.end() ; i!=e ; i++) {
llvm::Constant *SelectorTypeEncoding = NULLPtr;
@@ -2126,10 +2210,10 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
for (unsigned int i=0 ; i<SelectorCount ; i++) {
llvm::Constant *Idxs[] = {Zeros[0],
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), i), Zeros[0]};
+ llvm::ConstantInt::get(Int32Ty, i), Zeros[0]};
// FIXME: We're generating redundant loads and stores here!
llvm::Constant *SelPtr = llvm::ConstantExpr::getGetElementPtr(SelectorList,
- Idxs, 2);
+ makeArrayRef(Idxs, 2));
// If selectors are defined as an opaque type, cast the pointer to this
// type.
SelPtr = llvm::ConstantExpr::getBitCast(SelPtr, SelectorTy);
@@ -2177,7 +2261,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
Elements.push_back(SymTab);
if (RuntimeVersion >= 10)
- switch (CGM.getLangOptions().getGCMode()) {
+ switch (CGM.getLangOptions().getGC()) {
case LangOptions::GCOnly:
Elements.push_back(llvm::ConstantInt::get(IntTy, 2));
break;
@@ -2205,9 +2289,9 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
CGBuilderTy Builder(VMContext);
Builder.SetInsertPoint(EntryBB);
- llvm::Type *ArgTys[] = { llvm::PointerType::getUnqual(ModuleTy) };
llvm::FunctionType *FT =
- llvm::FunctionType::get(Builder.getVoidTy(), ArgTys, true);
+ llvm::FunctionType::get(Builder.getVoidTy(),
+ llvm::PointerType::getUnqual(ModuleTy), true);
llvm::Value *Register = CGM.CreateRuntimeFunction(FT, "__objc_exec_class");
Builder.CreateCall(Register, Module);
Builder.CreateRetVoid();
@@ -2219,13 +2303,13 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD) {
const ObjCCategoryImplDecl *OCD =
dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext());
- llvm::StringRef CategoryName = OCD ? OCD->getName() : "";
- llvm::StringRef ClassName = CD->getName();
+ StringRef CategoryName = OCD ? OCD->getName() : "";
+ StringRef ClassName = CD->getName();
Selector MethodName = OMD->getSelector();
bool isClassMethod = !OMD->isInstanceMethod();
CodeGenTypes &Types = CGM.getTypes();
- const llvm::FunctionType *MethodTy =
+ llvm::FunctionType *MethodTy =
Types.GetFunctionType(Types.getFunctionInfo(OMD), OMD->isVariadic());
std::string FunctionName = SymbolNameForMethod(ClassName, CategoryName,
MethodName, isClassMethod);
@@ -2285,15 +2369,14 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
llvm::Value *ExceptionAsObject;
if (const Expr *ThrowExpr = S.getThrowExpr()) {
- llvm::Value *Exception = CGF.EmitScalarExpr(ThrowExpr);
+ llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr);
ExceptionAsObject = Exception;
} else {
assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) &&
"Unexpected rethrow outside @catch block.");
ExceptionAsObject = CGF.ObjCEHValueStack.back();
}
- ExceptionAsObject =
- CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy, "tmp");
+ ExceptionAsObject = CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy);
// Note: This may have to be an invoke, if we want to support constructs like:
// @try {
@@ -2341,7 +2424,7 @@ void CGObjCGNU::EmitObjCGlobalAssign(CodeGenFunction &CGF,
B.CreateCall2(GlobalAssignFn, src, dst);
else
// FIXME. Add threadloca assign API
- assert(false && "EmitObjCGlobalAssign - Threal Local API NYI");
+ llvm_unreachable("EmitObjCGlobalAssign - Threal Local API NYI");
}
void CGObjCGNU::EmitObjCIvarAssign(CodeGenFunction &CGF,
@@ -2396,15 +2479,15 @@ llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(
const_cast<ObjCInterfaceDecl *>(ID)))
Offset = ComputeIvarBaseOffset(CGM, ID, Ivar);
- llvm::ConstantInt *OffsetGuess =
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Offset, "ivar");
+ llvm::ConstantInt *OffsetGuess = llvm::ConstantInt::get(Int32Ty, Offset,
+ /*isSigned*/true);
// Don't emit the guess in non-PIC code because the linker will not be able
// to replace it with the real version for a library. In non-PIC code you
// must compile with the fragile ABI if you want to use ivars from a
// GCC-compiled class.
if (CGM.getLangOptions().PICLevel) {
llvm::GlobalVariable *IvarOffsetGV = new llvm::GlobalVariable(TheModule,
- llvm::Type::getInt32Ty(VMContext), false,
+ Int32Ty, false,
llvm::GlobalValue::PrivateLinkage, OffsetGuess, Name+".guess");
IvarOffsetPointer = new llvm::GlobalVariable(TheModule,
IvarOffsetGV->getType(), false, llvm::GlobalValue::LinkOnceAnyLinkage,
@@ -2432,10 +2515,9 @@ LValue CGObjCGNU::EmitObjCValueForIvar(CodeGenFunction &CGF,
static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context,
const ObjCInterfaceDecl *OID,
const ObjCIvarDecl *OIVD) {
- llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
- Context.ShallowCollectObjCIvars(OID, Ivars);
- for (unsigned k = 0, e = Ivars.size(); k != e; ++k) {
- if (OIVD == Ivars[k])
+ for (const ObjCIvarDecl *next = OID->all_declared_ivar_begin(); next;
+ next = next->getNextIvar()) {
+ if (OIVD == next)
return OID;
}
@@ -2461,12 +2543,12 @@ llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGenFunction &CGF,
llvm::Value *Offset = TheModule.getGlobalVariable(name);
if (!Offset)
Offset = new llvm::GlobalVariable(TheModule, IntTy,
- false, llvm::GlobalValue::CommonLinkage,
- 0, name);
+ false, llvm::GlobalValue::LinkOnceAnyLinkage,
+ llvm::Constant::getNullValue(IntTy), name);
return CGF.Builder.CreateLoad(Offset);
}
uint64_t Offset = ComputeIvarBaseOffset(CGF.CGM, Interface, Ivar);
- return llvm::ConstantInt::get(PtrDiffTy, Offset, "ivar");
+ return llvm::ConstantInt::get(PtrDiffTy, Offset, /*isSigned*/true);
}
CGObjCRuntime *
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 010b9e174e46..308e0c7d3786 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -205,14 +205,14 @@ public:
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
// id objc_getProperty (id, SEL, ptrdiff_t, bool)
- llvm::SmallVector<CanQualType,4> Params;
+ SmallVector<CanQualType,4> Params;
CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType());
CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType());
Params.push_back(IdType);
Params.push_back(SelType);
Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified());
Params.push_back(Ctx.BoolTy);
- const llvm::FunctionType *FTy =
+ llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(IdType, Params,
FunctionType::ExtInfo()),
false);
@@ -223,7 +223,7 @@ public:
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
// void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool)
- llvm::SmallVector<CanQualType,6> Params;
+ SmallVector<CanQualType,6> Params;
CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType());
CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType());
Params.push_back(IdType);
@@ -232,7 +232,7 @@ public:
Params.push_back(IdType);
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
- const llvm::FunctionType *FTy =
+ llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
FunctionType::ExtInfo()),
false);
@@ -244,13 +244,13 @@ public:
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
// void objc_copyStruct (void *, const void *, size_t, bool, bool)
- llvm::SmallVector<CanQualType,5> Params;
+ SmallVector<CanQualType,5> Params;
Params.push_back(Ctx.VoidPtrTy);
Params.push_back(Ctx.VoidPtrTy);
Params.push_back(Ctx.LongTy);
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
- const llvm::FunctionType *FTy =
+ llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
FunctionType::ExtInfo()),
false);
@@ -261,9 +261,9 @@ public:
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
// void objc_enumerationMutation (id)
- llvm::SmallVector<CanQualType,1> Params;
+ SmallVector<CanQualType,1> Params;
Params.push_back(Ctx.getCanonicalParamType(Ctx.getObjCIdType()));
- const llvm::FunctionType *FTy =
+ llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
FunctionType::ExtInfo()),
false);
@@ -669,8 +669,8 @@ protected:
unsigned ObjCABI;
// gc ivar layout bitmap calculation helper caches.
- llvm::SmallVector<GC_IVAR, 16> SkipIvars;
- llvm::SmallVector<GC_IVAR, 16> IvarsInfo;
+ SmallVector<GC_IVAR, 16> SkipIvars;
+ SmallVector<GC_IVAR, 16> IvarsInfo;
/// LazySymbols - Symbols to generate a lazy reference for. See
/// DefinedSymbols and FinishModule().
@@ -733,7 +733,7 @@ protected:
/// \param[out] NameOut - The return value.
void GetNameForMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD,
- llvm::SmallVectorImpl<char> &NameOut);
+ SmallVectorImpl<char> &NameOut);
/// GetMethodVarName - Return a unique constant for the given
/// selector's name. The return value has type char *.
@@ -775,7 +775,7 @@ protected:
void BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
const llvm::StructLayout *Layout,
const RecordDecl *RD,
- const llvm::SmallVectorImpl<FieldDecl*> &RecFields,
+ const SmallVectorImpl<const FieldDecl*> &RecFields,
unsigned int BytePos, bool ForStrongLayout,
bool &HasUnion);
@@ -786,7 +786,7 @@ protected:
/// EmitPropertyList - Emit the given property list. The return
/// value has type PropertyListPtrTy.
- llvm::Constant *EmitPropertyList(llvm::Twine Name,
+ llvm::Constant *EmitPropertyList(Twine Name,
const Decl *Container,
const ObjCContainerDecl *OCD,
const ObjCCommonTypesHelper &ObjCTypes);
@@ -817,7 +817,7 @@ protected:
/// \param Align - The alignment for the variable, or 0.
/// \param AddToUsed - Whether the variable should be added to
/// "llvm.used".
- llvm::GlobalVariable *CreateMetadataVar(llvm::Twine Name,
+ llvm::GlobalVariable *CreateMetadataVar(Twine Name,
llvm::Constant *Init,
const char *Section,
unsigned Align,
@@ -923,7 +923,7 @@ private:
/// EmitMethodList - Emit the method list for the given
/// implementation. The return value has type MethodListPtrTy.
- llvm::Constant *EmitMethodList(llvm::Twine Name,
+ llvm::Constant *EmitMethodList(Twine Name,
const char *Section,
const ConstantVector &Methods);
@@ -938,7 +938,7 @@ private:
/// - begin, end: The method list to output.
///
/// The return value has type MethodDescriptionListPtrTy.
- llvm::Constant *EmitMethodDescList(llvm::Twine Name,
+ llvm::Constant *EmitMethodDescList(Twine Name,
const char *Section,
const ConstantVector &Methods);
@@ -964,7 +964,7 @@ private:
/// EmitProtocolList - Generate the list of referenced
/// protocols. The return value has type ProtocolListPtrTy.
- llvm::Constant *EmitProtocolList(llvm::Twine Name,
+ llvm::Constant *EmitProtocolList(Twine Name,
ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end);
@@ -1060,8 +1060,7 @@ public:
/// GetClassGlobal - Return the global variable for the Objective-C
/// class of the given name.
virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) {
- assert(false && "CGObjCMac::GetClassGlobal");
- return 0;
+ llvm_unreachable("CGObjCMac::GetClassGlobal");
}
};
@@ -1117,7 +1116,7 @@ private:
/// EmitMethodList - Emit the method list for the given
/// implementation. The return value has type MethodListnfABITy.
- llvm::Constant *EmitMethodList(llvm::Twine Name,
+ llvm::Constant *EmitMethodList(Twine Name,
const char *Section,
const ConstantVector &Methods);
/// EmitIvarList - Emit the ivar list for the given
@@ -1144,7 +1143,7 @@ private:
/// EmitProtocolList - Generate the list of referenced
/// protocols. The return value has type ProtocolListPtrTy.
- llvm::Constant *EmitProtocolList(llvm::Twine Name,
+ llvm::Constant *EmitProtocolList(Twine Name,
ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end);
@@ -1375,7 +1374,7 @@ static llvm::Constant *getConstantGEP(llvm::LLVMContext &VMContext,
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), idx0),
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), idx1)
};
- return llvm::ConstantExpr::getGetElementPtr(C, Idxs, 2);
+ return llvm::ConstantExpr::getGetElementPtr(C, Idxs);
}
/// hasObjCExceptionAttribute - Return true if this class or any super
@@ -1418,12 +1417,12 @@ llvm::Constant *CGObjCMac::GetEHType(QualType T) {
if (T->isObjCIdType() ||
T->isObjCQualifiedIdType()) {
return CGM.GetAddrOfRTTIDescriptor(
- CGM.getContext().ObjCIdRedefinitionType, /*ForEH=*/true);
+ CGM.getContext().getObjCIdRedefinitionType(), /*ForEH=*/true);
}
if (T->isObjCClassType() ||
T->isObjCQualifiedClassType()) {
return CGM.GetAddrOfRTTIDescriptor(
- CGM.getContext().ObjCClassRedefinitionType, /*ForEH=*/true);
+ CGM.getContext().getObjCClassRedefinitionType(), /*ForEH=*/true);
}
if (T->isObjCObjectPointerType())
return CGM.GetAddrOfRTTIDescriptor(T, /*ForEH=*/true);
@@ -1510,7 +1509,7 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
}
// FIXME: We shouldn't need to do this cast, rectify the ASTContext and
// ObjCTypes types.
- const llvm::Type *ClassTy =
+ llvm::Type *ClassTy =
CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
Target = CGF.Builder.CreateBitCast(Target, ClassTy);
CGF.Builder.CreateStore(Target,
@@ -1549,7 +1548,7 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
const ObjCCommonTypesHelper &ObjCTypes) {
CallArgList ActualArgs;
if (!IsSuper)
- Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp");
+ Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy);
ActualArgs.add(RValue::get(Arg0), Arg0Ty);
ActualArgs.add(RValue::get(Sel), CGF.getContext().getObjCSelType());
ActualArgs.addFrom(CallArgs);
@@ -1557,7 +1556,7 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
FunctionType::ExtInfo());
- const llvm::FunctionType *FTy =
+ llvm::FunctionType *FTy =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
if (Method)
@@ -1605,15 +1604,15 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
llvm::Constant *nullPtr =
llvm::Constant::getNullValue(llvm::Type::getInt8PtrTy(VMContext));
- if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC &&
+ if (CGM.getLangOptions().getGC() == LangOptions::NonGC &&
!CGM.getLangOptions().ObjCAutoRefCount)
return nullPtr;
bool hasUnion = false;
SkipIvars.clear();
IvarsInfo.clear();
- unsigned WordSizeInBits = CGM.getContext().Target.getPointerWidth(0);
- unsigned ByteSizeInBits = CGM.getContext().Target.getCharWidth();
+ unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0);
+ unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth();
// __isa is the first field in block descriptor and must assume by runtime's
// convention that it is GC'able.
@@ -1878,7 +1877,7 @@ CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD,
};
*/
llvm::Constant *
-CGObjCMac::EmitProtocolList(llvm::Twine Name,
+CGObjCMac::EmitProtocolList(Twine Name,
ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end) {
std::vector<llvm::Constant*> ProtocolRefs;
@@ -1942,7 +1941,7 @@ void CGObjCCommonMac::PushProtocolProperties(llvm::SmallPtrSet<const IdentifierI
struct _objc_property[prop_count];
};
*/
-llvm::Constant *CGObjCCommonMac::EmitPropertyList(llvm::Twine Name,
+llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
const Decl *Container,
const ObjCContainerDecl *OCD,
const ObjCCommonTypesHelper &ObjCTypes) {
@@ -2014,7 +2013,7 @@ CGObjCMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) {
Desc);
}
-llvm::Constant *CGObjCMac::EmitMethodDescList(llvm::Twine Name,
+llvm::Constant *CGObjCMac::EmitMethodDescList(Twine Name,
const char *Section,
const ConstantVector &Methods) {
// Return null for empty list.
@@ -2407,10 +2406,9 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID,
if (ForClass)
return llvm::Constant::getNullValue(ObjCTypes.IvarListPtrTy);
- ObjCInterfaceDecl *OID =
- const_cast<ObjCInterfaceDecl*>(ID->getClassInterface());
+ const ObjCInterfaceDecl *OID = ID->getClassInterface();
- for (ObjCIvarDecl *IVD = OID->all_declared_ivar_begin();
+ for (const ObjCIvarDecl *IVD = OID->all_declared_ivar_begin();
IVD; IVD = IVD->getNextIvar()) {
// Ignore unnamed bit-fields.
if (!IVD->getDeclName())
@@ -2476,7 +2474,7 @@ llvm::Constant *CGObjCMac::GetMethodConstant(const ObjCMethodDecl *MD) {
return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Method);
}
-llvm::Constant *CGObjCMac::EmitMethodList(llvm::Twine Name,
+llvm::Constant *CGObjCMac::EmitMethodList(Twine Name,
const char *Section,
const ConstantVector &Methods) {
// Return null for empty list.
@@ -2501,7 +2499,7 @@ llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
GetNameForMethod(OMD, CD, Name);
CodeGenTypes &Types = CGM.getTypes();
- const llvm::FunctionType *MethodTy =
+ llvm::FunctionType *MethodTy =
Types.GetFunctionType(Types.getFunctionInfo(OMD), OMD->isVariadic());
llvm::Function *Method =
llvm::Function::Create(MethodTy,
@@ -2514,12 +2512,12 @@ llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
}
llvm::GlobalVariable *
-CGObjCCommonMac::CreateMetadataVar(llvm::Twine Name,
+CGObjCCommonMac::CreateMetadataVar(Twine Name,
llvm::Constant *Init,
const char *Section,
unsigned Align,
bool AddToUsed) {
- const llvm::Type *Ty = Init->getType();
+ llvm::Type *Ty = Init->getType();
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Ty, false,
llvm::GlobalValue::InternalLinkage, Init, Name);
@@ -2627,7 +2625,7 @@ namespace {
class FragileHazards {
CodeGenFunction &CGF;
- llvm::SmallVector<llvm::Value*, 20> Locals;
+ SmallVector<llvm::Value*, 20> Locals;
llvm::DenseSet<llvm::BasicBlock*> BlocksBeforeTry;
llvm::InlineAsm *ReadHazard;
@@ -2754,7 +2752,6 @@ void FragileHazards::collectLocals() {
llvm::DenseSet<llvm::Value*> AllocasToIgnore;
addIfPresent(AllocasToIgnore, CGF.ReturnValue);
addIfPresent(AllocasToIgnore, CGF.NormalCleanupDest);
- addIfPresent(AllocasToIgnore, CGF.EHCleanupDest);
// Collect all the allocas currently in the function. This is
// probably way too aggressive.
@@ -2766,7 +2763,7 @@ void FragileHazards::collectLocals() {
}
llvm::FunctionType *FragileHazards::GetAsmFnType() {
- llvm::SmallVector<llvm::Type *, 16> tys(Locals.size());
+ SmallVector<llvm::Type *, 16> tys(Locals.size());
for (unsigned i = 0, e = Locals.size(); i != e; ++i)
tys[i] = Locals[i]->getType();
return llvm::FunctionType::get(CGF.VoidTy, tys, false);
@@ -2958,7 +2955,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
llvm::Constant *Zero = llvm::ConstantInt::get(CGF.Builder.getInt32Ty(), 0);
llvm::Value *GEPIndexes[] = { Zero, Zero, Zero };
llvm::Value *SetJmpBuffer =
- CGF.Builder.CreateGEP(ExceptionData, GEPIndexes, GEPIndexes+3, "setjmp_buffer");
+ CGF.Builder.CreateGEP(ExceptionData, GEPIndexes, "setjmp_buffer");
llvm::CallInst *SetJmpResult =
CGF.Builder.CreateCall(ObjCTypes.getSetJmpFn(), SetJmpBuffer, "setjmp_result");
SetJmpResult->setDoesNotThrow();
@@ -3119,8 +3116,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// Initialize the catch variable.
llvm::Value *Tmp =
CGF.Builder.CreateBitCast(Caught,
- CGF.ConvertType(CatchParam->getType()),
- "tmp");
+ CGF.ConvertType(CatchParam->getType()));
CGF.Builder.CreateStore(Tmp, CGF.GetAddrOfLocalVar(CatchParam));
CGF.EmitStmt(CatchStmt->getCatchBody());
@@ -3208,9 +3204,9 @@ void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
llvm::Value *ExceptionAsObject;
if (const Expr *ThrowExpr = S.getThrowExpr()) {
- llvm::Value *Exception = CGF.EmitScalarExpr(ThrowExpr);
+ llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr);
ExceptionAsObject =
- CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy, "tmp");
+ CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy);
} else {
assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) &&
"Unexpected rethrow outside @catch block.");
@@ -3230,7 +3226,7 @@ void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
///
llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
llvm::Value *AddrWeakObj) {
- const llvm::Type* DestTy =
+ llvm::Type* DestTy =
cast<llvm::PointerType>(AddrWeakObj->getType())->getElementType();
AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj,
ObjCTypes.PtrObjectPtrTy);
@@ -3245,7 +3241,7 @@ llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
///
void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
- const llvm::Type * SrcTy = src->getType();
+ llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
@@ -3266,7 +3262,7 @@ void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst,
bool threadlocal) {
- const llvm::Type * SrcTy = src->getType();
+ llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
@@ -3292,7 +3288,7 @@ void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst,
llvm::Value *ivarOffset) {
assert(ivarOffset && "EmitObjCIvarAssign - ivarOffset is NULL");
- const llvm::Type * SrcTy = src->getType();
+ llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
@@ -3312,7 +3308,7 @@ void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
///
void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
- const llvm::Type * SrcTy = src->getType();
+ llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
@@ -3386,15 +3382,15 @@ void CGObjCCommonMac::EmitImageInfo() {
unsigned flags = 0;
// FIXME: Fix and continue?
- if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC)
+ if (CGM.getLangOptions().getGC() != LangOptions::NonGC)
flags |= eImageInfo_GarbageCollected;
- if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly)
+ if (CGM.getLangOptions().getGC() == LangOptions::GCOnly)
flags |= eImageInfo_GCOnly;
// We never allow @synthesize of a superclass property.
flags |= eImageInfo_CorrectedSynthesize;
- const llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext);
+ llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext);
// Emitted as int[2];
llvm::Constant *values[2] = {
@@ -3498,7 +3494,7 @@ llvm::Value *CGObjCMac::EmitClassRefFromId(CGBuilderTy &Builder,
4, true);
}
- return Builder.CreateLoad(Entry, "tmp");
+ return Builder.CreateLoad(Entry);
}
llvm::Value *CGObjCMac::EmitClassRef(CGBuilderTy &Builder,
@@ -3527,7 +3523,7 @@ llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel,
if (lvalue)
return Entry;
- return Builder.CreateLoad(Entry, "tmp");
+ return Builder.CreateLoad(Entry);
}
llvm::Constant *CGObjCCommonMac::GetClassName(IdentifierInfo *Ident) {
@@ -3551,13 +3547,6 @@ llvm::Function *CGObjCCommonMac::GetMethodDefinition(const ObjCMethodDecl *MD) {
if (I != MethodDefinitions.end())
return I->second;
- if (MD->hasBody() && MD->getPCHLevel() > 0) {
- // MD isn't emitted yet because it comes from PCH.
- CGM.EmitTopLevelDecl(const_cast<ObjCMethodDecl*>(MD));
- assert(MethodDefinitions[MD] && "EmitTopLevelDecl didn't emit the method!");
- return MethodDefinitions[MD];
- }
-
return NULL;
}
@@ -3574,8 +3563,8 @@ void CGObjCCommonMac::BuildAggrIvarRecordLayout(const RecordType *RT,
bool &HasUnion) {
const RecordDecl *RD = RT->getDecl();
// FIXME - Use iterator.
- llvm::SmallVector<FieldDecl*, 16> Fields(RD->field_begin(), RD->field_end());
- const llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0));
+ SmallVector<const FieldDecl*, 16> Fields(RD->field_begin(), RD->field_end());
+ llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0));
const llvm::StructLayout *RecLayout =
CGM.getTargetData().getStructLayout(cast<llvm::StructType>(Ty));
@@ -3586,15 +3575,15 @@ void CGObjCCommonMac::BuildAggrIvarRecordLayout(const RecordType *RT,
void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
const llvm::StructLayout *Layout,
const RecordDecl *RD,
- const llvm::SmallVectorImpl<FieldDecl*> &RecFields,
+ const SmallVectorImpl<const FieldDecl*> &RecFields,
unsigned int BytePos, bool ForStrongLayout,
bool &HasUnion) {
bool IsUnion = (RD && RD->isUnion());
uint64_t MaxUnionIvarSize = 0;
uint64_t MaxSkippedUnionIvarSize = 0;
- FieldDecl *MaxField = 0;
- FieldDecl *MaxSkippedField = 0;
- FieldDecl *LastFieldBitfieldOrUnnamed = 0;
+ const FieldDecl *MaxField = 0;
+ const FieldDecl *MaxSkippedField = 0;
+ const FieldDecl *LastFieldBitfieldOrUnnamed = 0;
uint64_t MaxFieldOffset = 0;
uint64_t MaxSkippedFieldOffset = 0;
uint64_t LastBitfieldOrUnnamedOffset = 0;
@@ -3602,16 +3591,16 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
if (RecFields.empty())
return;
- unsigned WordSizeInBits = CGM.getContext().Target.getPointerWidth(0);
- unsigned ByteSizeInBits = CGM.getContext().Target.getCharWidth();
+ unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0);
+ unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth();
if (!RD && CGM.getLangOptions().ObjCAutoRefCount) {
- FieldDecl *FirstField = RecFields[0];
+ const FieldDecl *FirstField = RecFields[0];
FirstFieldDelta =
ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(FirstField));
}
for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
- FieldDecl *Field = RecFields[i];
+ const FieldDecl *Field = RecFields[i];
uint64_t FieldOffset;
if (RD) {
// Note that 'i' here is actually the field index inside RD of Field,
@@ -3721,9 +3710,8 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
if (LastFieldBitfieldOrUnnamed) {
if (LastFieldBitfieldOrUnnamed->isBitField()) {
// Last field was a bitfield. Must update skip info.
- Expr *BitWidth = LastFieldBitfieldOrUnnamed->getBitWidth();
- uint64_t BitFieldSize =
- BitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue();
+ uint64_t BitFieldSize
+ = LastFieldBitfieldOrUnnamed->getBitWidthValue(CGM.getContext());
GC_IVAR skivar;
skivar.ivar_bytepos = BytePos + LastBitfieldOrUnnamedOffset;
skivar.ivar_size = (BitFieldSize / ByteSizeInBits)
@@ -3754,10 +3742,10 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
/// filled already by the caller.
llvm::Constant *CGObjCCommonMac::BuildIvarLayoutBitmap(std::string& BitMap) {
unsigned int WordsToScan, WordsToSkip;
- const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+ llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext);
// Build the string of skip/scan nibbles
- llvm::SmallVector<SKIP_SCAN, 32> SkipScanIvars;
+ SmallVector<SKIP_SCAN, 32> SkipScanIvars;
unsigned int WordSize =
CGM.getTypes().getTargetData().getTypeAllocSize(PtrTy);
if (IvarsInfo[0].ivar_bytepos == 0) {
@@ -3898,25 +3886,24 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
bool ForStrongLayout) {
bool hasUnion = false;
- const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext);
- if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC &&
+ llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+ if (CGM.getLangOptions().getGC() == LangOptions::NonGC &&
!CGM.getLangOptions().ObjCAutoRefCount)
return llvm::Constant::getNullValue(PtrTy);
- ObjCInterfaceDecl *OI =
- const_cast<ObjCInterfaceDecl*>(OMD->getClassInterface());
- llvm::SmallVector<FieldDecl*, 32> RecFields;
+ const ObjCInterfaceDecl *OI = OMD->getClassInterface();
+ SmallVector<const FieldDecl*, 32> RecFields;
if (CGM.getLangOptions().ObjCAutoRefCount) {
- for (ObjCIvarDecl *IVD = OI->all_declared_ivar_begin();
+ for (const ObjCIvarDecl *IVD = OI->all_declared_ivar_begin();
IVD; IVD = IVD->getNextIvar())
RecFields.push_back(cast<FieldDecl>(IVD));
}
else {
- llvm::SmallVector<ObjCIvarDecl*, 32> Ivars;
+ SmallVector<const ObjCIvarDecl*, 32> Ivars;
CGM.getContext().DeepCollectObjCIvars(OI, true, Ivars);
- for (unsigned k = 0, e = Ivars.size(); k != e; ++k)
- RecFields.push_back(cast<FieldDecl>(Ivars[k]));
+ // FIXME: This is not ideal; we shouldn't have to do this copy.
+ RecFields.append(Ivars.begin(), Ivars.end());
}
if (RecFields.empty())
@@ -4036,7 +4023,7 @@ CGObjCCommonMac::GetPropertyTypeString(const ObjCPropertyDecl *PD,
void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D,
const ObjCContainerDecl *CD,
- llvm::SmallVectorImpl<char> &Name) {
+ SmallVectorImpl<char> &Name) {
llvm::raw_svector_ostream OS(Name);
assert (CD && "Missing container decl in GetNameForMethod");
OS << '\01' << (D->isInstanceMethod() ? '-' : '+')
@@ -4125,7 +4112,7 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
// FIXME: It would be nice to unify this with the opaque type, so that the IR
// comes out a bit cleaner.
- const llvm::Type *T = Types.ConvertType(Ctx.getObjCProtoType());
+ llvm::Type *T = Types.ConvertType(Ctx.getObjCProtoType());
ExternalProtocolPtrTy = llvm::PointerType::getUnqual(T);
// I'm not sure I like this. The implicit coordination is a bit
@@ -4160,8 +4147,8 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
// char *name;
// char *attributes;
// }
- PropertyTy = llvm::StructType::createNamed("struct._prop_t",
- Int8PtrTy, Int8PtrTy, NULL);
+ PropertyTy = llvm::StructType::create("struct._prop_t",
+ Int8PtrTy, Int8PtrTy, NULL);
// struct _prop_list_t {
// uint32_t entsize; // sizeof(struct _prop_t)
@@ -4169,10 +4156,8 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
// struct _prop_t prop_list[count_of_properties];
// }
PropertyListTy =
- llvm::StructType::createNamed("struct._prop_list_t",
- IntTy, IntTy,
- llvm::ArrayType::get(PropertyTy, 0),
- NULL);
+ llvm::StructType::create("struct._prop_list_t", IntTy, IntTy,
+ llvm::ArrayType::get(PropertyTy, 0), NULL);
// struct _prop_list_t *
PropertyListPtrTy = llvm::PointerType::getUnqual(PropertyListTy);
@@ -4181,12 +4166,12 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
// char *method_type;
// char *_imp;
// }
- MethodTy = llvm::StructType::createNamed("struct._objc_method",
- SelectorPtrTy, Int8PtrTy, Int8PtrTy,
- NULL);
+ MethodTy = llvm::StructType::create("struct._objc_method",
+ SelectorPtrTy, Int8PtrTy, Int8PtrTy,
+ NULL);
// struct _objc_cache *
- CacheTy = llvm::StructType::createNamed(VMContext, "struct._objc_cache");
+ CacheTy = llvm::StructType::create(VMContext, "struct._objc_cache");
CachePtrTy = llvm::PointerType::getUnqual(CacheTy);
}
@@ -4198,18 +4183,17 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// char *types;
// }
MethodDescriptionTy =
- llvm::StructType::createNamed("struct._objc_method_description",
- SelectorPtrTy, Int8PtrTy, NULL);
+ llvm::StructType::create("struct._objc_method_description",
+ SelectorPtrTy, Int8PtrTy, NULL);
// struct _objc_method_description_list {
// int count;
// struct _objc_method_description[1];
// }
MethodDescriptionListTy =
- llvm::StructType::createNamed("struct._objc_method_description_list",
- IntTy,
- llvm::ArrayType::get(MethodDescriptionTy, 0),
- NULL);
+ llvm::StructType::create("struct._objc_method_description_list",
+ IntTy,
+ llvm::ArrayType::get(MethodDescriptionTy, 0),NULL);
// struct _objc_method_description_list *
MethodDescriptionListPtrTy =
@@ -4224,12 +4208,10 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// struct _objc_property_list *instance_properties;
// }
ProtocolExtensionTy =
- llvm::StructType::createNamed("struct._objc_protocol_extension",
- IntTy,
- MethodDescriptionListPtrTy,
- MethodDescriptionListPtrTy,
- PropertyListPtrTy,
- NULL);
+ llvm::StructType::create("struct._objc_protocol_extension",
+ IntTy, MethodDescriptionListPtrTy,
+ MethodDescriptionListPtrTy, PropertyListPtrTy,
+ NULL);
// struct _objc_protocol_extension *
ProtocolExtensionPtrTy = llvm::PointerType::getUnqual(ProtocolExtensionTy);
@@ -4237,10 +4219,10 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// Handle recursive construction of Protocol and ProtocolList types
ProtocolTy =
- llvm::StructType::createNamed(VMContext, "struct._objc_protocol");
+ llvm::StructType::create(VMContext, "struct._objc_protocol");
ProtocolListTy =
- llvm::StructType::createNamed(VMContext, "struct._objc_protocol_list");
+ llvm::StructType::create(VMContext, "struct._objc_protocol_list");
ProtocolListTy->setBody(llvm::PointerType::getUnqual(ProtocolListTy),
LongTy,
llvm::ArrayType::get(ProtocolTy, 0),
@@ -4271,26 +4253,26 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// char *ivar_type;
// int ivar_offset;
// }
- IvarTy = llvm::StructType::createNamed("struct._objc_ivar",
- Int8PtrTy, Int8PtrTy, IntTy, NULL);
+ IvarTy = llvm::StructType::create("struct._objc_ivar",
+ Int8PtrTy, Int8PtrTy, IntTy, NULL);
// struct _objc_ivar_list *
IvarListTy =
- llvm::StructType::createNamed(VMContext, "struct._objc_ivar_list");
+ llvm::StructType::create(VMContext, "struct._objc_ivar_list");
IvarListPtrTy = llvm::PointerType::getUnqual(IvarListTy);
// struct _objc_method_list *
MethodListTy =
- llvm::StructType::createNamed(VMContext, "struct._objc_method_list");
+ llvm::StructType::create(VMContext, "struct._objc_method_list");
MethodListPtrTy = llvm::PointerType::getUnqual(MethodListTy);
// struct _objc_class_extension *
ClassExtensionTy =
- llvm::StructType::createNamed("struct._objc_class_extension",
- IntTy, Int8PtrTy, PropertyListPtrTy, NULL);
+ llvm::StructType::create("struct._objc_class_extension",
+ IntTy, Int8PtrTy, PropertyListPtrTy, NULL);
ClassExtensionPtrTy = llvm::PointerType::getUnqual(ClassExtensionTy);
- ClassTy = llvm::StructType::createNamed(VMContext, "struct._objc_class");
+ ClassTy = llvm::StructType::create(VMContext, "struct._objc_class");
// struct _objc_class {
// Class isa;
@@ -4331,10 +4313,10 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// struct _objc_property_list *instance_properties;// category's @property
// }
CategoryTy =
- llvm::StructType::createNamed("struct._objc_category",
- Int8PtrTy, Int8PtrTy, MethodListPtrTy,
- MethodListPtrTy, ProtocolListPtrTy,
- IntTy, PropertyListPtrTy, NULL);
+ llvm::StructType::create("struct._objc_category",
+ Int8PtrTy, Int8PtrTy, MethodListPtrTy,
+ MethodListPtrTy, ProtocolListPtrTy,
+ IntTy, PropertyListPtrTy, NULL);
// Global metadata structures
@@ -4346,9 +4328,9 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// char *defs[cls_def_cnt + cat_def_cnt];
// }
SymtabTy =
- llvm::StructType::createNamed("struct._objc_symtab",
- LongTy, SelectorPtrTy, ShortTy, ShortTy,
- llvm::ArrayType::get(Int8PtrTy, 0), NULL);
+ llvm::StructType::create("struct._objc_symtab",
+ LongTy, SelectorPtrTy, ShortTy, ShortTy,
+ llvm::ArrayType::get(Int8PtrTy, 0), NULL);
SymtabPtrTy = llvm::PointerType::getUnqual(SymtabTy);
// struct _objc_module {
@@ -4358,8 +4340,8 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// struct _objc_symtab* symtab;
// }
ModuleTy =
- llvm::StructType::createNamed("struct._objc_module",
- LongTy, LongTy, Int8PtrTy, SymtabPtrTy, NULL);
+ llvm::StructType::create("struct._objc_module",
+ LongTy, LongTy, Int8PtrTy, SymtabPtrTy, NULL);
// FIXME: This is the size of the setjmp buffer and should be target
@@ -4371,7 +4353,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
llvm::Type::getInt8PtrTy(VMContext), 4);
ExceptionDataTy =
- llvm::StructType::createNamed("struct._objc_exception_data",
+ llvm::StructType::create("struct._objc_exception_data",
llvm::ArrayType::get(llvm::Type::getInt32Ty(VMContext),
SetJmpBufferSize),
StackPtrTy, NULL);
@@ -4386,10 +4368,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// struct _objc_method method_list[method_count];
// }
MethodListnfABITy =
- llvm::StructType::createNamed("struct.__method_list_t",
- IntTy, IntTy,
- llvm::ArrayType::get(MethodTy, 0),
- NULL);
+ llvm::StructType::create("struct.__method_list_t", IntTy, IntTy,
+ llvm::ArrayType::get(MethodTy, 0), NULL);
// struct method_list_t *
MethodListnfABIPtrTy = llvm::PointerType::getUnqual(MethodListnfABITy);
@@ -4408,20 +4388,14 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// Holder for struct _protocol_list_t *
ProtocolListnfABITy =
- llvm::StructType::createNamed(VMContext, "struct._objc_protocol_list");
+ llvm::StructType::create(VMContext, "struct._objc_protocol_list");
ProtocolnfABITy =
- llvm::StructType::createNamed("struct._protocol_t",
- ObjectPtrTy, Int8PtrTy,
- llvm::PointerType::getUnqual(ProtocolListnfABITy),
- MethodListnfABIPtrTy,
- MethodListnfABIPtrTy,
- MethodListnfABIPtrTy,
- MethodListnfABIPtrTy,
- PropertyListPtrTy,
- IntTy,
- IntTy,
- NULL);
+ llvm::StructType::create("struct._protocol_t", ObjectPtrTy, Int8PtrTy,
+ llvm::PointerType::getUnqual(ProtocolListnfABITy),
+ MethodListnfABIPtrTy, MethodListnfABIPtrTy,
+ MethodListnfABIPtrTy, MethodListnfABIPtrTy,
+ PropertyListPtrTy, IntTy, IntTy, NULL);
// struct _protocol_t*
ProtocolnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolnfABITy);
@@ -4445,13 +4419,9 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// uint32_t size;
// }
IvarnfABITy =
- llvm::StructType::createNamed("struct._ivar_t",
- llvm::PointerType::getUnqual(LongTy),
- Int8PtrTy,
- Int8PtrTy,
- IntTy,
- IntTy,
- NULL);
+ llvm::StructType::create("struct._ivar_t",
+ llvm::PointerType::getUnqual(LongTy),
+ Int8PtrTy, Int8PtrTy, IntTy, IntTy, NULL);
// struct _ivar_list_t {
// uint32 entsize; // sizeof(struct _ivar_t)
@@ -4459,10 +4429,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// struct _iver_t list[count];
// }
IvarListnfABITy =
- llvm::StructType::createNamed("struct._ivar_list_t",
- IntTy, IntTy,
- llvm::ArrayType::get(IvarnfABITy, 0),
- NULL);
+ llvm::StructType::create("struct._ivar_list_t", IntTy, IntTy,
+ llvm::ArrayType::get(IvarnfABITy, 0), NULL);
IvarListnfABIPtrTy = llvm::PointerType::getUnqual(IvarListnfABITy);
@@ -4481,18 +4449,12 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// }
// FIXME. Add 'reserved' field in 64bit abi mode!
- ClassRonfABITy = llvm::StructType::createNamed("struct._class_ro_t",
- IntTy,
- IntTy,
- IntTy,
- Int8PtrTy,
- Int8PtrTy,
- MethodListnfABIPtrTy,
- ProtocolListnfABIPtrTy,
- IvarListnfABIPtrTy,
- Int8PtrTy,
- PropertyListPtrTy,
- NULL);
+ ClassRonfABITy = llvm::StructType::create("struct._class_ro_t",
+ IntTy, IntTy, IntTy, Int8PtrTy,
+ Int8PtrTy, MethodListnfABIPtrTy,
+ ProtocolListnfABIPtrTy,
+ IvarListnfABIPtrTy,
+ Int8PtrTy, PropertyListPtrTy, NULL);
// ImpnfABITy - LLVM for id (*)(id, SEL, ...)
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
@@ -4507,7 +4469,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// struct class_ro_t *ro;
// }
- ClassnfABITy = llvm::StructType::createNamed(VMContext, "struct._class_t");
+ ClassnfABITy = llvm::StructType::create(VMContext, "struct._class_t");
ClassnfABITy->setBody(llvm::PointerType::getUnqual(ClassnfABITy),
llvm::PointerType::getUnqual(ClassnfABITy),
CachePtrTy,
@@ -4526,14 +4488,13 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// const struct _protocol_list_t * const protocols;
// const struct _prop_list_t * const properties;
// }
- CategorynfABITy = llvm::StructType::createNamed("struct._category_t",
- Int8PtrTy,
- ClassnfABIPtrTy,
- MethodListnfABIPtrTy,
- MethodListnfABIPtrTy,
- ProtocolListnfABIPtrTy,
- PropertyListPtrTy,
- NULL);
+ CategorynfABITy = llvm::StructType::create("struct._category_t",
+ Int8PtrTy, ClassnfABIPtrTy,
+ MethodListnfABIPtrTy,
+ MethodListnfABIPtrTy,
+ ProtocolListnfABIPtrTy,
+ PropertyListPtrTy,
+ NULL);
// New types for nonfragile abi messaging.
CodeGen::CodeGenTypes &Types = CGM.getTypes();
@@ -4569,8 +4530,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// SEL name;
// };
SuperMessageRefTy =
- llvm::StructType::createNamed("struct._super_message_ref_t",
- ImpnfABITy, SelectorPtrTy, NULL);
+ llvm::StructType::create("struct._super_message_ref_t",
+ ImpnfABITy, SelectorPtrTy, NULL);
// SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t*
SuperMessageRefPtrTy = llvm::PointerType::getUnqual(SuperMessageRefTy);
@@ -4582,11 +4543,9 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// Class cls;
// };
EHTypeTy =
- llvm::StructType::createNamed("struct._objc_typeinfo",
- llvm::PointerType::getUnqual(Int8PtrTy),
- Int8PtrTy,
- ClassnfABIPtrTy,
- NULL);
+ llvm::StructType::create("struct._objc_typeinfo",
+ llvm::PointerType::getUnqual(Int8PtrTy),
+ Int8PtrTy, ClassnfABIPtrTy, NULL);
EHTypePtrTy = llvm::PointerType::getUnqual(EHTypeTy);
}
@@ -4694,7 +4653,7 @@ bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) {
// These are vtable-based if GC is disabled.
// Optimistically use vtable dispatch for hybrid compiles.
- if (CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) {
+ if (CGM.getLangOptions().getGC() != LangOptions::GCOnly) {
VTableDispatchMethods.insert(GetNullarySelector("retain"));
VTableDispatchMethods.insert(GetNullarySelector("release"));
VTableDispatchMethods.insert(GetNullarySelector("autorelease"));
@@ -4710,7 +4669,7 @@ bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) {
// These are vtable-based if GC is enabled.
// Optimistically use vtable dispatch for hybrid compiles.
- if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
+ if (CGM.getLangOptions().getGC() != LangOptions::NonGC) {
VTableDispatchMethods.insert(GetNullarySelector("hash"));
VTableDispatchMethods.insert(GetUnarySelector("addObject"));
@@ -5035,7 +4994,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName);
if (PTGV)
- return Builder.CreateLoad(PTGV, "tmp");
+ return Builder.CreateLoad(PTGV);
PTGV = new llvm::GlobalVariable(
CGM.getModule(),
Init->getType(), false,
@@ -5045,7 +5004,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, "tmp");
+ return Builder.CreateLoad(PTGV);
}
/// GenerateCategory - Build metadata for a category implementation.
@@ -5167,7 +5126,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetMethodConstant(
/// struct _objc_method method_list[method_count];
/// }
///
-llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList(llvm::Twine Name,
+llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList(Twine Name,
const char *Section,
const ConstantVector &Methods) {
// Return null for empty list.
@@ -5258,13 +5217,12 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
std::vector<llvm::Constant*> Ivars, Ivar(5);
- ObjCInterfaceDecl *OID =
- const_cast<ObjCInterfaceDecl*>(ID->getClassInterface());
+ const ObjCInterfaceDecl *OID = ID->getClassInterface();
assert(OID && "CGObjCNonFragileABIMac::EmitIvarList - null interface");
// FIXME. Consolidate this with similar code in GenerateClass.
- for (ObjCIvarDecl *IVD = OID->all_declared_ivar_begin();
+ for (const ObjCIvarDecl *IVD = OID->all_declared_ivar_begin();
IVD; IVD = IVD->getNextIvar()) {
// Ignore unnamed bit-fields.
if (!IVD->getDeclName())
@@ -5273,7 +5231,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
ComputeIvarBaseOffset(CGM, ID, IVD));
Ivar[1] = GetMethodVarName(IVD->getIdentifier());
Ivar[2] = GetMethodVarType(IVD);
- const llvm::Type *FieldTy =
+ llvm::Type *FieldTy =
CGM.getTypes().ConvertTypeForMem(IVD->getType());
unsigned Size = CGM.getTargetData().getTypeAllocSize(FieldTy);
unsigned Align = CGM.getContext().getPreferredTypeAlign(
@@ -5461,7 +5419,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
/// @endcode
///
llvm::Constant *
-CGObjCNonFragileABIMac::EmitProtocolList(llvm::Twine Name,
+CGObjCNonFragileABIMac::EmitProtocolList(Twine Name,
ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end) {
std::vector<llvm::Constant*> ProtocolRefs;
@@ -5669,7 +5627,7 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
callee = CGF.Builder.CreateLoad(callee, "msgSend_fn");
bool variadic = method ? method->isVariadic() : false;
- const llvm::FunctionType *fnType =
+ llvm::FunctionType *fnType =
CGF.getTypes().GetFunctionType(fnInfo, variadic);
callee = CGF.Builder.CreateBitCast(callee,
llvm::PointerType::getUnqual(fnType));
@@ -5730,7 +5688,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CGBuilderTy &Builder,
CGM.AddUsedGlobal(Entry);
}
- return Builder.CreateLoad(Entry, "tmp");
+ return Builder.CreateLoad(Entry);
}
llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder,
@@ -5764,7 +5722,7 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
CGM.AddUsedGlobal(Entry);
}
- return Builder.CreateLoad(Entry, "tmp");
+ return Builder.CreateLoad(Entry);
}
/// EmitMetaClassRef - Return a Value * of the address of _class_t
@@ -5774,7 +5732,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID) {
llvm::GlobalVariable * &Entry = MetaClassReferences[ID->getIdentifier()];
if (Entry)
- return Builder.CreateLoad(Entry, "tmp");
+ return Builder.CreateLoad(Entry);
std::string MetaClassName(getMetaclassSymbolPrefix() + ID->getNameAsString());
llvm::GlobalVariable *MetaClassGV = GetClassGlobal(MetaClassName);
@@ -5790,7 +5748,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
- return Builder.CreateLoad(Entry, "tmp");
+ return Builder.CreateLoad(Entry);
}
/// GetClass - Return a reference to the class for the given interface
@@ -5847,7 +5805,7 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
// FIXME: We shouldn't need to do this cast, rectify the ASTContext and
// ObjCTypes types.
- const llvm::Type *ClassTy =
+ llvm::Type *ClassTy =
CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
Target = CGF.Builder.CreateBitCast(Target, ClassTy);
CGF.Builder.CreateStore(Target,
@@ -5881,7 +5839,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder,
if (lval)
return Entry;
- return Builder.CreateLoad(Entry, "tmp");
+ return Builder.CreateLoad(Entry);
}
/// EmitObjCIvarAssign - Code gen for assigning to a __strong object.
/// objc_assign_ivar (id src, id *dst, ptrdiff_t)
@@ -5890,7 +5848,7 @@ void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src,
llvm::Value *dst,
llvm::Value *ivarOffset) {
- const llvm::Type * SrcTy = src->getType();
+ llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
@@ -5911,7 +5869,7 @@ void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign(
CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
- const llvm::Type * SrcTy = src->getType();
+ llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
@@ -5944,7 +5902,7 @@ void CGObjCNonFragileABIMac::EmitGCMemmoveCollectable(
llvm::Value * CGObjCNonFragileABIMac::EmitObjCWeakRead(
CodeGen::CodeGenFunction &CGF,
llvm::Value *AddrWeakObj) {
- const llvm::Type* DestTy =
+ 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(),
@@ -5958,7 +5916,7 @@ llvm::Value * CGObjCNonFragileABIMac::EmitObjCWeakRead(
///
void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
- const llvm::Type * SrcTy = src->getType();
+ llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
@@ -5979,7 +5937,7 @@ void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst,
bool threadlocal) {
- const llvm::Type * SrcTy = src->getType();
+ llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
@@ -6043,9 +6001,8 @@ void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtThrowStmt &S) {
if (const Expr *ThrowExpr = S.getThrowExpr()) {
- llvm::Value *Exception = CGF.EmitScalarExpr(ThrowExpr);
- Exception = CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy,
- "tmp");
+ llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr);
+ Exception = CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy);
CGF.EmitCallOrInvoke(ObjCTypes.getExceptionThrowFn(), Exception)
.setDoesNotReturn();
} else {
@@ -6096,7 +6053,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 2);
std::vector<llvm::Constant*> Values(3);
- Values[0] = llvm::ConstantExpr::getGetElementPtr(VTableGV, &VTableIdx, 1);
+ Values[0] = llvm::ConstantExpr::getGetElementPtr(VTableGV, VTableIdx);
Values[1] = GetClassName(ID->getIdentifier());
Values[2] = GetClassGlobal(ClassName);
llvm::Constant *Init =
diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp
index 09c8d0b28f9c..ef426ce6ed9b 100644
--- a/lib/CodeGen/CGObjCRuntime.cpp
+++ b/lib/CodeGen/CGObjCRuntime.cpp
@@ -52,9 +52,8 @@ static uint64_t LookupFieldBitOffset(CodeGen::CodeGenModule &CGM,
// implemented. This should be fixed to get the information from the layout
// directly.
unsigned Index = 0;
- ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl*>(Container);
- for (ObjCIvarDecl *IVD = IDecl->all_declared_ivar_begin();
+ for (const ObjCIvarDecl *IVD = Container->all_declared_ivar_begin();
IVD; IVD = IVD->getNextIvar()) {
if (Ivar == IVD)
break;
@@ -86,9 +85,9 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
unsigned CVRQualifiers,
llvm::Value *Offset) {
// Compute (type*) ( (char *) BaseValue + Offset)
- const llvm::Type *I8Ptr = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ llvm::Type *I8Ptr = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
QualType IvarTy = Ivar->getType();
- const llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy);
+ llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy);
llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, I8Ptr);
V = CGF.Builder.CreateInBoundsGEP(V, Offset, "add.ptr");
V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy));
@@ -118,10 +117,9 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
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().Target.getCharAlign();
+ uint64_t ContainingTypeAlign = CGF.CGM.getContext().getTargetInfo().getCharAlign();
uint64_t ContainingTypeSize = TypeSizeInBits - (FieldBitOffset - BitOffset);
- uint64_t BitFieldSize =
- Ivar->getBitWidth()->EvaluateAsInt(CGF.getContext()).getZExtValue();
+ uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext());
// Allocate a new CGBitFieldInfo object to describe this access.
//
@@ -178,7 +176,7 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
FinallyInfo.enter(CGF, Finally->getFinallyBody(),
beginCatchFn, endCatchFn, exceptionRethrowFn);
- llvm::SmallVector<CatchHandler, 8> Handlers;
+ SmallVector<CatchHandler, 8> Handlers;
// Enter the catch, if there is one.
if (S.getNumCatchStmts()) {
@@ -212,7 +210,7 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
// Leave the try.
if (S.getNumCatchStmts())
- CGF.EHStack.popCatch();
+ CGF.popCatchScope();
// Remember where we were.
CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP();
@@ -222,7 +220,7 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
CatchHandler &Handler = Handlers[I];
CGF.EmitBlock(Handler.Block);
- llvm::Value *RawExn = CGF.Builder.CreateLoad(CGF.getExceptionSlot());
+ llvm::Value *RawExn = CGF.getExceptionFromSlot();
// Enter the catch.
llvm::Value *Exn = RawExn;
@@ -244,7 +242,7 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
// Bind the catch parameter if it exists.
if (const VarDecl *CatchParam = Handler.Variable) {
- const llvm::Type *CatchType = CGF.ConvertType(CatchParam->getType());
+ llvm::Type *CatchType = CGF.ConvertType(CatchParam->getType());
llvm::Value *CastExn = CGF.Builder.CreateBitCast(Exn, CatchType);
CGF.EmitAutoVarDecl(*CatchParam);
@@ -289,21 +287,26 @@ void CGObjCRuntime::EmitAtSynchronizedStmt(CodeGenFunction &CGF,
const ObjCAtSynchronizedStmt &S,
llvm::Function *syncEnterFn,
llvm::Function *syncExitFn) {
- // Evaluate the lock operand. This should dominate the cleanup.
- llvm::Value *SyncArg =
- CGF.EmitScalarExpr(S.getSynchExpr());
+ CodeGenFunction::RunCleanupsScope cleanups(CGF);
+
+ // Evaluate the lock operand. This is guaranteed to dominate the
+ // ARC release and lock-release cleanups.
+ const Expr *lockExpr = S.getSynchExpr();
+ llvm::Value *lock;
+ if (CGF.getLangOptions().ObjCAutoRefCount) {
+ lock = CGF.EmitARCRetainScalarExpr(lockExpr);
+ lock = CGF.EmitObjCConsumeObject(lockExpr->getType(), lock);
+ } else {
+ lock = CGF.EmitScalarExpr(lockExpr);
+ }
+ lock = CGF.Builder.CreateBitCast(lock, CGF.VoidPtrTy);
// Acquire the lock.
- SyncArg = CGF.Builder.CreateBitCast(SyncArg, syncEnterFn->getFunctionType()->getParamType(0));
- CGF.Builder.CreateCall(syncEnterFn, SyncArg);
+ CGF.Builder.CreateCall(syncEnterFn, lock)->setDoesNotThrow();
// Register an all-paths cleanup to release the lock.
- CGF.EHStack.pushCleanup<CallSyncExit>(NormalAndEHCleanup, syncExitFn,
- SyncArg);
+ CGF.EHStack.pushCleanup<CallSyncExit>(NormalAndEHCleanup, syncExitFn, lock);
// Emit the body of the statement.
CGF.EmitStmt(S.getSynchBody());
-
- // Pop the lock-release cleanup.
- CGF.PopCleanupBlock();
}
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index 7accc70c9623..4fa47a740aaf 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -208,8 +208,7 @@ public:
virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) {
- assert(false &&"autoreleasepool unsupported in this ABI");
- return 0;
+ llvm_unreachable("autoreleasepool unsupported in this ABI");
}
/// EnumerationMutationFunction - Return the function that's called by the
diff --git a/lib/CodeGen/CGOpenCLRuntime.cpp b/lib/CodeGen/CGOpenCLRuntime.cpp
new file mode 100644
index 000000000000..3a0e116e5ab1
--- /dev/null
+++ b/lib/CodeGen/CGOpenCLRuntime.cpp
@@ -0,0 +1,28 @@
+//===----- CGOpenCLRuntime.cpp - Interface to OpenCL Runtimes -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides an abstract class for OpenCL code generation. Concrete
+// subclasses of this implement code generation for specific OpenCL
+// runtime libraries.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGOpenCLRuntime.h"
+#include "CodeGenFunction.h"
+#include "llvm/GlobalValue.h"
+
+using namespace clang;
+using namespace CodeGen;
+
+CGOpenCLRuntime::~CGOpenCLRuntime() {}
+
+void CGOpenCLRuntime::EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
+ const VarDecl &D) {
+ return CGF.EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
+}
diff --git a/lib/CodeGen/CGOpenCLRuntime.h b/lib/CodeGen/CGOpenCLRuntime.h
new file mode 100644
index 000000000000..9a8430fb7500
--- /dev/null
+++ b/lib/CodeGen/CGOpenCLRuntime.h
@@ -0,0 +1,46 @@
+//===----- CGOpenCLRuntime.h - Interface to OpenCL Runtimes -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides an abstract class for OpenCL code generation. Concrete
+// subclasses of this implement code generation for specific OpenCL
+// runtime libraries.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_OPENCLRUNTIME_H
+#define CLANG_CODEGEN_OPENCLRUNTIME_H
+
+namespace clang {
+
+class VarDecl;
+
+namespace CodeGen {
+
+class CodeGenFunction;
+class CodeGenModule;
+
+class CGOpenCLRuntime {
+protected:
+ CodeGenModule &CGM;
+
+public:
+ CGOpenCLRuntime(CodeGenModule &CGM) : CGM(CGM) {}
+ virtual ~CGOpenCLRuntime();
+
+ /// Emit the IR required for a work-group-local variable declaration, and add
+ /// an entry to CGF's LocalDeclMap for D. The base class does this using
+ /// CodeGenFunction::EmitStaticVarDecl to emit an internal global for D.
+ virtual void EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
+ const VarDecl &D);
+};
+
+}
+}
+
+#endif
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index e564c7070525..fbdb2984830b 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -26,10 +26,10 @@ class RTTIBuilder {
CodeGenModule &CGM; // Per-module state.
llvm::LLVMContext &VMContext;
- const llvm::Type *Int8PtrTy;
+ llvm::Type *Int8PtrTy;
/// Fields - The fields of the RTTI descriptor currently being built.
- llvm::SmallVector<llvm::Constant *, 16> Fields;
+ SmallVector<llvm::Constant *, 16> Fields;
/// GetAddrOfTypeName - Returns the mangled type name of the given type.
llvm::GlobalVariable *
@@ -120,7 +120,7 @@ RTTIBuilder::GetAddrOfTypeName(QualType Ty,
llvm::raw_svector_ostream Out(OutName);
CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, Out);
Out.flush();
- llvm::StringRef Name = OutName.str();
+ StringRef Name = OutName.str();
// We know that the mangled name of the type starts at index 4 of the
// mangled name of the typename, so we can just index into it in order to
@@ -141,7 +141,7 @@ llvm::Constant *RTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
llvm::raw_svector_ostream Out(OutName);
CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out);
Out.flush();
- llvm::StringRef Name = OutName.str();
+ StringRef Name = OutName.str();
// Look for an existing global.
llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(Name);
@@ -185,6 +185,7 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
case BuiltinType::ULong:
case BuiltinType::LongLong:
case BuiltinType::ULongLong:
+ case BuiltinType::Half:
case BuiltinType::Float:
case BuiltinType::Double:
case BuiltinType::LongDouble:
@@ -203,7 +204,7 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
- assert(false && "FIXME: Objective-C types are unsupported!");
+ llvm_unreachable("FIXME: Objective-C types are unsupported!");
}
// Silent gcc.
@@ -267,7 +268,7 @@ static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM, QualType Ty) {
/// IsIncompleteClassType - Returns whether the given record type is incomplete.
static bool IsIncompleteClassType(const RecordType *RecordTy) {
- return !RecordTy->getDecl()->isDefinition();
+ return !RecordTy->getDecl()->isCompleteDefinition();
}
/// ContainsIncompleteClassType - Returns whether the given type contains an
@@ -393,17 +394,18 @@ void RTTIBuilder::BuildVTablePointer(const Type *Ty) {
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
#include "clang/AST/TypeNodes.def"
- assert(false && "Non-canonical and dependent types shouldn't get here");
+ llvm_unreachable("Non-canonical and dependent types shouldn't get here");
case Type::LValueReference:
case Type::RValueReference:
- assert(false && "References shouldn't get here");
+ llvm_unreachable("References shouldn't get here");
case Type::Builtin:
// GCC treats vector and complex types as fundamental types.
case Type::Vector:
case Type::ExtVector:
case Type::Complex:
+ case Type::Atomic:
// FIXME: GCC treats block pointers as fundamental types?!
case Type::BlockPointer:
// abi::__fundamental_type_info.
@@ -479,12 +481,12 @@ void RTTIBuilder::BuildVTablePointer(const Type *Ty) {
llvm::Constant *VTable =
CGM.getModule().getOrInsertGlobal(VTableName, Int8PtrTy);
- const llvm::Type *PtrDiffTy =
+ llvm::Type *PtrDiffTy =
CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
// The vtable address point is 2.
llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2);
- VTable = llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, &Two, 1);
+ VTable = llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Two);
VTable = llvm::ConstantExpr::getBitCast(VTable, Int8PtrTy);
Fields.push_back(VTable);
@@ -533,7 +535,7 @@ maybeUpdateRTTILinkage(CodeGenModule &CGM, llvm::GlobalVariable *GV,
llvm::raw_svector_ostream Out(OutName);
CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, Out);
Out.flush();
- llvm::StringRef Name = OutName.str();
+ StringRef Name = OutName.str();
llvm::GlobalVariable *TypeNameGV = CGM.getModule().getNamedGlobal(Name);
@@ -553,7 +555,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
llvm::raw_svector_ostream Out(OutName);
CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out);
Out.flush();
- llvm::StringRef Name = OutName.str();
+ StringRef Name = OutName.str();
llvm::GlobalVariable *OldGV = CGM.getModule().getNamedGlobal(Name);
if (OldGV && !OldGV->isDeclaration()) {
@@ -580,7 +582,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
// And the name.
llvm::GlobalVariable *TypeName = GetAddrOfTypeName(Ty, Linkage);
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+ llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
Fields.push_back(llvm::ConstantExpr::getBitCast(TypeName, Int8PtrTy));
switch (Ty->getTypeClass()) {
@@ -590,7 +592,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
#include "clang/AST/TypeNodes.def"
- assert(false && "Non-canonical and dependent types shouldn't get here");
+ llvm_unreachable("Non-canonical and dependent types shouldn't get here");
// GCC treats vector types as fundamental types.
case Type::Builtin:
@@ -604,7 +606,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
case Type::LValueReference:
case Type::RValueReference:
- assert(false && "References shouldn't get here");
+ llvm_unreachable("References shouldn't get here");
case Type::ConstantArray:
case Type::IncompleteArray:
@@ -656,6 +658,10 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
case Type::MemberPointer:
BuildPointerToMemberTypeInfo(cast<MemberPointerType>(Ty));
break;
+
+ case Type::Atomic:
+ // No fields, at least for the moment.
+ break;
}
llvm::Constant *Init = llvm::ConstantStruct::getAnon(Fields);
@@ -822,7 +828,7 @@ static unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *RD) {
/// classes with bases that do not satisfy the abi::__si_class_type_info
/// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
- const llvm::Type *UnsignedIntLTy =
+ llvm::Type *UnsignedIntLTy =
CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
// Itanium C++ ABI 2.9.5p6c:
@@ -840,7 +846,7 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
if (!RD->getNumBases())
return;
- const llvm::Type *LongLTy =
+ llvm::Type *LongLTy =
CGM.getTypes().ConvertType(CGM.getContext().LongTy);
// Now add the base class descriptions.
@@ -879,7 +885,7 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
CharUnits Offset;
if (Base->isVirtual())
Offset =
- CGM.getVTables().getVirtualBaseOffsetOffset(RD, BaseDecl);
+ CGM.getVTableContext().getVirtualBaseOffsetOffset(RD, BaseDecl);
else {
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
Offset = Layout.getBaseClassOffset(BaseDecl);
@@ -916,7 +922,7 @@ void RTTIBuilder::BuildPointerTypeInfo(QualType PointeeTy) {
if (ContainsIncompleteClassType(UnqualifiedPointeeTy))
Flags |= PTI_Incomplete;
- const llvm::Type *UnsignedIntLTy =
+ llvm::Type *UnsignedIntLTy =
CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
@@ -953,7 +959,7 @@ void RTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) {
if (IsIncompleteClassType(ClassType))
Flags |= PTI_ContainingClassIncomplete;
- const llvm::Type *UnsignedIntLTy =
+ llvm::Type *UnsignedIntLTy =
CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
@@ -977,12 +983,12 @@ llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
// FIXME: should we even be calling this method if RTTI is disabled
// and it's not for EH?
if (!ForEH && !getContext().getLangOptions().RTTI) {
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+ llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
return llvm::Constant::getNullValue(Int8PtrTy);
}
if (ForEH && Ty->isObjCObjectPointerType() && !Features.NeXTRuntime) {
- return Runtime->GetEHType(Ty);
+ return ObjCRuntime->GetEHType(Ty);
}
return RTTIBuilder(*this).BuildTypeInfo(Ty);
diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h
index 8a450298f70a..25a0a508f188 100644
--- a/lib/CodeGen/CGRecordLayout.h
+++ b/lib/CodeGen/CGRecordLayout.h
@@ -10,12 +10,13 @@
#ifndef CLANG_CODEGEN_CGRECORDLAYOUT_H
#define CLANG_CODEGEN_CGRECORDLAYOUT_H
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/DerivedTypes.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/DerivedTypes.h"
+
namespace llvm {
- class raw_ostream;
class StructType;
}
@@ -144,7 +145,7 @@ public:
/// @}
- void print(llvm::raw_ostream &OS) const;
+ void print(raw_ostream &OS) const;
void dump() const;
/// \brief Given a bit-field decl, build an appropriate helper object for
@@ -270,7 +271,7 @@ public:
return it->second;
}
- void print(llvm::raw_ostream &OS) const;
+ void print(raw_ostream &OS) const;
void dump() const;
};
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 2b07bafa0096..6475ccac0389 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -35,7 +35,7 @@ class CGRecordLayoutBuilder {
public:
/// FieldTypes - Holds the LLVM types that the struct is created from.
///
- llvm::SmallVector<llvm::Type *, 16> FieldTypes;
+ SmallVector<llvm::Type *, 16> FieldTypes;
/// BaseSubobjectType - Holds the LLVM type for the non-virtual part
/// of the struct. For example, consider:
@@ -174,7 +174,7 @@ private:
/// the passed size.
void AppendTailPadding(CharUnits RecordSize);
- CharUnits getTypeAlignment(const llvm::Type *Ty) const;
+ CharUnits getTypeAlignment(llvm::Type *Ty) const;
/// getAlignmentAsLLVMStruct - Returns the maximum alignment of all the
/// LLVM element types.
@@ -230,7 +230,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
uint64_t FieldSize,
uint64_t ContainingTypeSizeInBits,
unsigned ContainingTypeAlign) {
- const llvm::Type *Ty = Types.ConvertTypeForMem(FD->getType());
+ llvm::Type *Ty = Types.ConvertTypeForMem(FD->getType());
CharUnits TypeSizeInBytes =
CharUnits::fromQuantity(Types.getTargetData().getTypeAllocSize(Ty));
uint64_t TypeSizeInBits = Types.getContext().toBits(TypeSizeInBytes);
@@ -363,15 +363,14 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D,
uint64_t fieldOffset) {
- uint64_t fieldSize =
- D->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue();
+ uint64_t fieldSize = D->getBitWidthValue(Types.getContext());
if (fieldSize == 0)
return;
uint64_t nextFieldOffsetInBits = Types.getContext().toBits(NextFieldOffset);
CharUnits numBytesToAppend;
- unsigned charAlign = Types.getContext().Target.getCharAlign();
+ unsigned charAlign = Types.getContext().getTargetInfo().getCharAlign();
if (fieldOffset < nextFieldOffsetInBits && !BitsAvailableInLastField) {
assert(fieldOffset % charAlign == 0 &&
@@ -492,8 +491,7 @@ llvm::Type *
CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field,
const ASTRecordLayout &Layout) {
if (Field->isBitField()) {
- uint64_t FieldSize =
- Field->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue();
+ uint64_t FieldSize = Field->getBitWidthValue(Types.getContext());
// Ignore zero sized bit fields.
if (FieldSize == 0)
@@ -502,7 +500,7 @@ CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field,
llvm::Type *FieldTy = llvm::Type::getInt8Ty(Types.getLLVMContext());
CharUnits NumBytesToAppend = Types.getContext().toCharUnitsFromBits(
llvm::RoundUpToAlignment(FieldSize,
- Types.getContext().Target.getCharAlign()));
+ Types.getContext().getTargetInfo().getCharAlign()));
if (NumBytesToAppend > CharUnits::One())
FieldTy = llvm::ArrayType::get(FieldTy, NumBytesToAppend.getQuantity());
@@ -672,10 +670,10 @@ CGRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD,
// Check if we need to add a vtable pointer.
if (RD->isDynamicClass()) {
if (!PrimaryBase) {
- const llvm::Type *FunctionType =
+ llvm::Type *FunctionType =
llvm::FunctionType::get(llvm::Type::getInt32Ty(Types.getLLVMContext()),
/*isVarArg=*/true);
- const llvm::Type *VTableTy = FunctionType->getPointerTo();
+ llvm::Type *VTableTy = FunctionType->getPointerTo();
assert(NextFieldOffset.isZero() &&
"VTable pointer must come first!");
@@ -735,8 +733,8 @@ CGRecordLayoutBuilder::ComputeNonVirtualBaseType(const CXXRecordDecl *RD) {
}
- BaseSubobjectType = llvm::StructType::createNamed(Types.getLLVMContext(), "",
- FieldTypes, Packed);
+ BaseSubobjectType = llvm::StructType::create(Types.getLLVMContext(),
+ FieldTypes, "", Packed);
Types.addRecordTypeName(RD, BaseSubobjectType, ".base");
// Pull the padding back off.
@@ -882,7 +880,7 @@ void CGRecordLayoutBuilder::AppendBytes(CharUnits numBytes) {
AppendField(NextFieldOffset, getByteArrayType(numBytes));
}
-CharUnits CGRecordLayoutBuilder::getTypeAlignment(const llvm::Type *Ty) const {
+CharUnits CGRecordLayoutBuilder::getTypeAlignment(llvm::Type *Ty) const {
if (Packed)
return CharUnits::One();
@@ -983,7 +981,7 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
}
// Verify that the LLVM and AST field offsets agree.
- const llvm::StructType *ST =
+ llvm::StructType *ST =
dyn_cast<llvm::StructType>(RL->getLLVMType());
const llvm::StructLayout *SL = getTargetData().getStructLayout(ST);
@@ -1037,7 +1035,7 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
return RL;
}
-void CGRecordLayout::print(llvm::raw_ostream &OS) const {
+void CGRecordLayout::print(raw_ostream &OS) const {
OS << "<CGRecordLayout\n";
OS << " LLVMType:" << *CompleteObjectType << "\n";
if (BaseSubobjectType)
@@ -1071,7 +1069,7 @@ void CGRecordLayout::dump() const {
print(llvm::errs());
}
-void CGBitFieldInfo::print(llvm::raw_ostream &OS) const {
+void CGBitFieldInfo::print(raw_ostream &OS) const {
OS << "<CGBitFieldInfo";
OS << " Size:" << Size;
OS << " IsSigned:" << IsSigned << "\n";
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 07bddb797265..c56931bbc6fa 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -31,20 +31,19 @@ using namespace CodeGen;
void CodeGenFunction::EmitStopPoint(const Stmt *S) {
if (CGDebugInfo *DI = getDebugInfo()) {
+ SourceLocation Loc;
if (isa<DeclStmt>(S))
- DI->setLocation(S->getLocEnd());
+ Loc = S->getLocEnd();
else
- DI->setLocation(S->getLocStart());
- DI->UpdateLineDirectiveRegion(Builder);
- DI->EmitStopPoint(Builder);
+ Loc = S->getLocStart();
+ DI->EmitLocation(Builder, Loc);
}
}
void CodeGenFunction::EmitStmt(const Stmt *S) {
assert(S && "Null statement?");
- // Check if we can handle this without bothering to generate an
- // insert point or debug info.
+ // These statements have their own debug info handling.
if (EmitSimpleStmt(S))
return;
@@ -137,11 +136,11 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
EmitObjCAtTryStmt(cast<ObjCAtTryStmt>(*S));
break;
case Stmt::ObjCAtCatchStmtClass:
- assert(0 && "@catch statements should be handled by EmitObjCAtTryStmt");
- break;
+ llvm_unreachable(
+ "@catch statements should be handled by EmitObjCAtTryStmt");
case Stmt::ObjCAtFinallyStmtClass:
- assert(0 && "@finally statements should be handled by EmitObjCAtTryStmt");
- break;
+ llvm_unreachable(
+ "@finally statements should be handled by EmitObjCAtTryStmt");
case Stmt::ObjCAtThrowStmtClass:
EmitObjCAtThrowStmt(cast<ObjCAtThrowStmt>(*S));
break;
@@ -192,10 +191,8 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
"LLVM IR generation of compound statement ('{}')");
CGDebugInfo *DI = getDebugInfo();
- if (DI) {
- DI->setLocation(S.getLBracLoc());
- DI->EmitRegionStart(Builder);
- }
+ if (DI)
+ DI->EmitLexicalBlockStart(Builder, S.getLBracLoc());
// Keep track of the current cleanup stack depth.
RunCleanupsScope Scope(*this);
@@ -204,10 +201,8 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
E = S.body_end()-GetLast; I != E; ++I)
EmitStmt(*I);
- if (DI) {
- DI->setLocation(S.getRBracLoc());
- DI->EmitRegionEnd(Builder);
- }
+ if (DI)
+ DI->EmitLexicalBlockEnd(Builder, S.getRBracLoc());
RValue RV;
if (!GetLast)
@@ -286,6 +281,23 @@ void CodeGenFunction::EmitBranch(llvm::BasicBlock *Target) {
Builder.ClearInsertionPoint();
}
+void CodeGenFunction::EmitBlockAfterUses(llvm::BasicBlock *block) {
+ bool inserted = false;
+ for (llvm::BasicBlock::use_iterator
+ i = block->use_begin(), e = block->use_end(); i != e; ++i) {
+ if (llvm::Instruction *insn = dyn_cast<llvm::Instruction>(*i)) {
+ CurFn->getBasicBlockList().insertAfter(insn->getParent(), block);
+ inserted = true;
+ break;
+ }
+ }
+
+ if (!inserted)
+ CurFn->getBasicBlockList().push_back(block);
+
+ Builder.SetInsertPoint(block);
+}
+
CodeGenFunction::JumpDest
CodeGenFunction::getJumpDestForLabel(const LabelDecl *D) {
JumpDest &Dest = LabelMap[D];
@@ -555,10 +567,8 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
RunCleanupsScope ForScope(*this);
CGDebugInfo *DI = getDebugInfo();
- if (DI) {
- DI->setLocation(S.getSourceRange().getBegin());
- DI->EmitRegionStart(Builder);
- }
+ if (DI)
+ DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin());
// Evaluate the first part before the loop.
if (S.getInit())
@@ -637,10 +647,8 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
ForScope.ForceCleanup();
- if (DI) {
- DI->setLocation(S.getSourceRange().getEnd());
- DI->EmitRegionEnd(Builder);
- }
+ if (DI)
+ DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd());
// Emit the fall-through block.
EmitBlock(LoopExit.getBlock(), true);
@@ -652,10 +660,8 @@ void CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S) {
RunCleanupsScope ForScope(*this);
CGDebugInfo *DI = getDebugInfo();
- if (DI) {
- DI->setLocation(S.getSourceRange().getBegin());
- DI->EmitRegionStart(Builder);
- }
+ if (DI)
+ DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin());
// Evaluate the first pieces before the loop.
EmitStmt(S.getRangeStmt());
@@ -711,10 +717,8 @@ void CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S) {
ForScope.ForceCleanup();
- if (DI) {
- DI->setLocation(S.getSourceRange().getEnd());
- DI->EmitRegionEnd(Builder);
- }
+ if (DI)
+ DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd());
// Emit the fall-through block.
EmitBlock(LoopExit.getBlock(), true);
@@ -767,7 +771,10 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
} else if (RV->getType()->isAnyComplexType()) {
EmitComplexExprIntoAddr(RV, ReturnValue, false);
} else {
- EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, Qualifiers(), true));
+ EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, Qualifiers(),
+ AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased));
}
EmitBranchThroughCleanup(ReturnBlock);
@@ -816,8 +823,8 @@ void CodeGenFunction::EmitContinueStmt(const ContinueStmt &S) {
void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) {
assert(S.getRHS() && "Expected RHS value in CaseStmt");
- llvm::APSInt LHS = S.getLHS()->EvaluateAsInt(getContext());
- llvm::APSInt RHS = S.getRHS()->EvaluateAsInt(getContext());
+ llvm::APSInt LHS = S.getLHS()->EvaluateKnownConstInt(getContext());
+ llvm::APSInt RHS = S.getRHS()->EvaluateKnownConstInt(getContext());
// Emit the code for this case. We do this first to make sure it is
// properly chained from our predecessor before generating the
@@ -856,7 +863,7 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) {
// Emit range check.
llvm::Value *Diff =
- Builder.CreateSub(SwitchInsn->getCondition(), Builder.getInt(LHS), "tmp");
+ Builder.CreateSub(SwitchInsn->getCondition(), Builder.getInt(LHS));
llvm::Value *Cond =
Builder.CreateICmpULE(Diff, Builder.getInt(Range), "inbounds");
Builder.CreateCondBr(Cond, CaseDest, FalseDest);
@@ -876,7 +883,7 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
}
llvm::ConstantInt *CaseVal =
- Builder.getInt(S.getLHS()->EvaluateAsInt(getContext()));
+ Builder.getInt(S.getLHS()->EvaluateKnownConstInt(getContext()));
// If the body of the case is just a 'break', and if there was no fallthrough,
// try to not emit an empty block.
@@ -917,7 +924,7 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
while (NextCase && NextCase->getRHS() == 0) {
CurCase = NextCase;
llvm::ConstantInt *CaseVal =
- Builder.getInt(CurCase->getLHS()->EvaluateAsInt(getContext()));
+ Builder.getInt(CurCase->getLHS()->EvaluateKnownConstInt(getContext()));
SwitchInsn->addCase(CaseVal, CaseDest);
NextCase = dyn_cast<CaseStmt>(CurCase->getSubStmt());
}
@@ -961,7 +968,7 @@ enum CSFC_Result { CSFC_Failure, CSFC_FallThrough, CSFC_Success };
static CSFC_Result CollectStatementsForCase(const Stmt *S,
const SwitchCase *Case,
bool &FoundCase,
- llvm::SmallVectorImpl<const Stmt*> &ResultStmts) {
+ SmallVectorImpl<const Stmt*> &ResultStmts) {
// If this is a null statement, just succeed.
if (S == 0)
return Case ? CSFC_Success : CSFC_FallThrough;
@@ -1086,7 +1093,7 @@ static CSFC_Result CollectStatementsForCase(const Stmt *S,
/// for more details.
static bool FindCaseStatementsForValue(const SwitchStmt &S,
const llvm::APInt &ConstantCondValue,
- llvm::SmallVectorImpl<const Stmt*> &ResultStmts,
+ SmallVectorImpl<const Stmt*> &ResultStmts,
ASTContext &C) {
// First step, find the switch case that is being branched to. We can do this
// efficiently by scanning the SwitchCase list.
@@ -1107,7 +1114,7 @@ static bool FindCaseStatementsForValue(const SwitchStmt &S,
if (CS->getRHS()) return false;
// If we found our case, remember it as 'case'.
- if (CS->getLHS()->EvaluateAsInt(C) == ConstantCondValue)
+ if (CS->getLHS()->EvaluateKnownConstInt(C) == ConstantCondValue)
break;
}
@@ -1147,7 +1154,7 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
// emit the live case statement (if any) of the switch.
llvm::APInt ConstantCondValue;
if (ConstantFoldsToSimpleInteger(S.getCond(), ConstantCondValue)) {
- llvm::SmallVector<const Stmt*, 4> CaseStmts;
+ SmallVector<const Stmt*, 4> CaseStmts;
if (FindCaseStatementsForValue(S, ConstantCondValue, CaseStmts,
getContext())) {
RunCleanupsScope ExecutedScope(*this);
@@ -1219,7 +1226,7 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
static std::string
SimplifyConstraint(const char *Constraint, const TargetInfo &Target,
- llvm::SmallVectorImpl<TargetInfo::ConstraintInfo> *OutCons=0) {
+ SmallVectorImpl<TargetInfo::ConstraintInfo> *OutCons=0) {
std::string Result;
while (*Constraint) {
@@ -1276,7 +1283,7 @@ AddVariableConstraints(const std::string &Constraint, const Expr &AsmExpr,
AsmLabelAttr *Attr = Variable->getAttr<AsmLabelAttr>();
if (!Attr)
return Constraint;
- llvm::StringRef Register = Attr->getLabel();
+ StringRef Register = Attr->getLabel();
assert(Target.isValidGCCRegisterName(Register));
// We're using validateOutputConstraint here because we only care if
// this is a register constraint.
@@ -1301,7 +1308,7 @@ CodeGenFunction::EmitAsmInputLValue(const AsmStmt &S,
if (!CodeGenFunction::hasAggregateLLVMType(InputType)) {
Arg = EmitLoadOfLValue(InputValue).getScalarVal();
} else {
- const llvm::Type *Ty = ConvertType(InputType);
+ llvm::Type *Ty = ConvertType(InputType);
uint64_t Size = CGM.getTargetData().getTypeSizeInBits(Ty);
if (Size <= 64 && llvm::isPowerOf2_64(Size)) {
Ty = llvm::IntegerType::get(getLLVMContext(), Size);
@@ -1341,11 +1348,11 @@ llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S,
/// asm.
static llvm::MDNode *getAsmSrcLocInfo(const StringLiteral *Str,
CodeGenFunction &CGF) {
- llvm::SmallVector<llvm::Value *, 8> Locs;
+ SmallVector<llvm::Value *, 8> Locs;
// Add the location of the first line to the MDNode.
Locs.push_back(llvm::ConstantInt::get(CGF.Int32Ty,
Str->getLocStart().getRawEncoding()));
- llvm::StringRef StrVal = Str->getString();
+ StringRef StrVal = Str->getString();
if (!StrVal.empty()) {
const SourceManager &SM = CGF.CGM.getContext().getSourceManager();
const LangOptions &LangOpts = CGF.CGM.getLangOptions();
@@ -1367,7 +1374,7 @@ static llvm::MDNode *getAsmSrcLocInfo(const StringLiteral *Str,
void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// Analyze the asm string to decompose it into its pieces. We know that Sema
// has already done this, so it is guaranteed to be successful.
- llvm::SmallVector<AsmStmt::AsmStringPiece, 4> Pieces;
+ SmallVector<AsmStmt::AsmStringPiece, 4> Pieces;
unsigned DiagOffs;
S.AnalyzeAsmString(Pieces, getContext(), DiagOffs);
@@ -1384,8 +1391,8 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
}
// Get all the output and input constraints together.
- llvm::SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
- llvm::SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
+ SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
+ SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) {
TargetInfo::ConstraintInfo Info(S.getOutputConstraint(i),
@@ -1530,14 +1537,18 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// Use ptrtoint as appropriate so that we can do our extension.
if (isa<llvm::PointerType>(Arg->getType()))
Arg = Builder.CreatePtrToInt(Arg, IntPtrTy);
- const llvm::Type *OutputTy = ConvertType(OutputType);
+ llvm::Type *OutputTy = ConvertType(OutputType);
if (isa<llvm::IntegerType>(OutputTy))
Arg = Builder.CreateZExt(Arg, OutputTy);
- else
+ else if (isa<llvm::PointerType>(OutputTy))
+ Arg = Builder.CreateZExt(Arg, IntPtrTy);
+ else {
+ assert(OutputTy->isFloatingPointTy() && "Unexpected output type");
Arg = Builder.CreateFPExt(Arg, OutputTy);
+ }
}
}
- if (const llvm::Type* AdjTy =
+ if (llvm::Type* AdjTy =
getTargetHooks().adjustInlineAsmType(*this, InputConstraint,
Arg->getType()))
Arg = Builder.CreateBitCast(Arg, AdjTy);
@@ -1556,7 +1567,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// Clobbers
for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) {
- llvm::StringRef Clobber = S.getClobber(i)->getString();
+ StringRef Clobber = S.getClobber(i)->getString();
if (Clobber != "memory" && Clobber != "cc")
Clobber = Target.getNormalizedGCCRegisterName(Clobber);
@@ -1577,7 +1588,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
Constraints += MachineClobbers;
}
- const llvm::Type *ResultType;
+ llvm::Type *ResultType;
if (ResultRegTypes.empty())
ResultType = llvm::Type::getVoidTy(getLLVMContext());
else if (ResultRegTypes.size() == 1)
@@ -1585,7 +1596,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
else
ResultType = llvm::StructType::get(getLLVMContext(), ResultRegTypes);
- const llvm::FunctionType *FTy =
+ llvm::FunctionType *FTy =
llvm::FunctionType::get(ResultType, ArgTypes, false);
llvm::InlineAsm *IA =
@@ -1615,7 +1626,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// If the result type of the LLVM IR asm doesn't match the result type of
// the expression, do the conversion.
if (ResultRegTypes[i] != ResultTruncRegTypes[i]) {
- const llvm::Type *TruncTy = ResultTruncRegTypes[i];
+ llvm::Type *TruncTy = ResultTruncRegTypes[i];
// Truncate the integer result to the right size, note that TruncTy can be
// a pointer.
diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp
index cec02cdfc235..ea7b8cb49794 100644
--- a/lib/CodeGen/CGVTT.cpp
+++ b/lib/CodeGen/CGVTT.cpp
@@ -14,383 +14,81 @@
#include "CodeGenModule.h"
#include "CGCXXABI.h"
#include "clang/AST/RecordLayout.h"
+#include "clang/AST/VTTBuilder.h"
using namespace clang;
using namespace CodeGen;
#define D1(x)
-namespace {
-
-/// VTT builder - Class for building VTT layout information.
-class VTTBuilder {
-
- CodeGenModule &CGM;
-
- /// MostDerivedClass - The most derived class for which we're building this
- /// vtable.
- const CXXRecordDecl *MostDerivedClass;
-
- typedef llvm::SmallVector<llvm::Constant *, 64> VTTComponentsVectorTy;
-
- /// VTTComponents - The VTT components.
- VTTComponentsVectorTy VTTComponents;
-
- /// MostDerivedClassLayout - the AST record layout of the most derived class.
- const ASTRecordLayout &MostDerivedClassLayout;
-
- typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
-
- typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy;
-
- /// SubVTTIndicies - The sub-VTT indices for the bases of the most derived
- /// class.
- llvm::DenseMap<BaseSubobject, uint64_t> SubVTTIndicies;
-
- /// SecondaryVirtualPointerIndices - The secondary virtual pointer indices of
- /// all subobjects of the most derived class.
- llvm::DenseMap<BaseSubobject, uint64_t> SecondaryVirtualPointerIndices;
-
- /// GenerateDefinition - Whether the VTT builder should generate LLVM IR for
- /// the VTT.
- bool GenerateDefinition;
-
- /// The linkage to use for any construction vtables required by this VTT.
- /// Only required if we're building a definition.
- llvm::GlobalVariable::LinkageTypes LinkageForConstructionVTables;
-
- /// GetAddrOfVTable - Returns the address of the vtable for the base class in
- /// the given vtable class.
- ///
- /// \param AddressPoints - If the returned vtable is a construction vtable,
- /// this will hold the address points for it.
- llvm::Constant *GetAddrOfVTable(BaseSubobject Base, bool BaseIsVirtual,
- AddressPointsMapTy& AddressPoints);
-
- /// 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, llvm::Constant *VTable,
- const CXXRecordDecl *VTableClass,
- const AddressPointsMapTy& AddressPoints);
-
- /// LayoutSecondaryVTTs - Lay out the secondary VTTs of the given base
- /// subobject.
- void LayoutSecondaryVTTs(BaseSubobject Base);
-
- /// LayoutSecondaryVirtualPointers - Lay out the secondary virtual pointers
- /// for the given base subobject.
- ///
- /// \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,
- llvm::Constant *VTable,
- const CXXRecordDecl *VTableClass,
- const AddressPointsMapTy& AddressPoints,
- VisitedVirtualBasesSetTy &VBases);
-
- /// 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,
- llvm::Constant *VTable,
- const AddressPointsMapTy& AddressPoints);
-
- /// LayoutVirtualVTTs - Lay out the VTTs for the virtual base classes of the
- /// given record decl.
- void LayoutVirtualVTTs(const CXXRecordDecl *RD,
- VisitedVirtualBasesSetTy &VBases);
-
- /// LayoutVTT - Will lay out the VTT for the given subobject, including any
- /// secondary VTTs, secondary virtual pointers and virtual VTTs.
- void LayoutVTT(BaseSubobject Base, bool BaseIsVirtual);
-
-public:
- VTTBuilder(CodeGenModule &CGM, const CXXRecordDecl *MostDerivedClass,
- bool GenerateDefinition,
- llvm::GlobalVariable::LinkageTypes LinkageForConstructionVTables
- = (llvm::GlobalVariable::LinkageTypes) -1);
-
- // getVTTComponents - Returns a reference to the VTT components.
- const VTTComponentsVectorTy &getVTTComponents() const {
- return VTTComponents;
- }
-
- /// getSubVTTIndicies - Returns a reference to the sub-VTT indices.
- const llvm::DenseMap<BaseSubobject, uint64_t> &getSubVTTIndicies() const {
- return SubVTTIndicies;
- }
-
- /// getSecondaryVirtualPointerIndices - Returns a reference to the secondary
- /// virtual pointer indices.
- const llvm::DenseMap<BaseSubobject, uint64_t> &
- getSecondaryVirtualPointerIndices() const {
- return SecondaryVirtualPointerIndices;
- }
-
-};
-
-VTTBuilder::VTTBuilder(CodeGenModule &CGM,
- const CXXRecordDecl *MostDerivedClass,
- bool GenerateDefinition,
- llvm::GlobalVariable::LinkageTypes LinkageForConstructionVTables)
- : CGM(CGM), MostDerivedClass(MostDerivedClass),
- MostDerivedClassLayout(CGM.getContext().getASTRecordLayout(MostDerivedClass)),
- GenerateDefinition(GenerateDefinition),
- LinkageForConstructionVTables(LinkageForConstructionVTables) {
- assert(!GenerateDefinition ||
- LinkageForConstructionVTables
- != (llvm::GlobalVariable::LinkageTypes) -1);
-
- // Lay out this VTT.
- LayoutVTT(BaseSubobject(MostDerivedClass, CharUnits::Zero()),
- /*BaseIsVirtual=*/false);
-}
-
-llvm::Constant *
-VTTBuilder::GetAddrOfVTable(BaseSubobject Base, bool BaseIsVirtual,
- AddressPointsMapTy& AddressPoints) {
- if (!GenerateDefinition)
- return 0;
-
- if (Base.getBase() == MostDerivedClass) {
- assert(Base.getBaseOffset().isZero() &&
+llvm::Constant *GetAddrOfVTTVTable(CodeGenVTables &CGVT,
+ const CXXRecordDecl *MostDerivedClass,
+ const VTTVTable &VTable,
+ llvm::GlobalVariable::LinkageTypes Linkage,
+ llvm::DenseMap<BaseSubobject, uint64_t> &AddressPoints) {
+ if (VTable.getBase() == MostDerivedClass) {
+ assert(VTable.getBaseOffset().isZero() &&
"Most derived class vtable must have a zero offset!");
// This is a regular vtable.
- return CGM.getVTables().GetAddrOfVTable(MostDerivedClass);
+ return CGVT.GetAddrOfVTable(MostDerivedClass);
}
- return CGM.getVTables().GenerateConstructionVTable(MostDerivedClass,
- Base, BaseIsVirtual,
- LinkageForConstructionVTables,
- AddressPoints);
+ return CGVT.GenerateConstructionVTable(MostDerivedClass,
+ VTable.getBaseSubobject(),
+ VTable.isVirtual(),
+ Linkage,
+ AddressPoints);
}
-void VTTBuilder::AddVTablePointer(BaseSubobject Base, llvm::Constant *VTable,
- const CXXRecordDecl *VTableClass,
- const AddressPointsMapTy& AddressPoints) {
- // Store the vtable pointer index if we're generating the primary VTT.
- if (VTableClass == MostDerivedClass) {
- assert(!SecondaryVirtualPointerIndices.count(Base) &&
- "A virtual pointer index already exists for this base subobject!");
- SecondaryVirtualPointerIndices[Base] = VTTComponents.size();
- }
-
- if (!GenerateDefinition) {
- VTTComponents.push_back(0);
- return;
- }
-
- uint64_t AddressPoint;
- if (VTableClass != MostDerivedClass) {
- // The vtable is a construction vtable, look in the construction vtable
- // address points.
- AddressPoint = AddressPoints.lookup(Base);
- assert(AddressPoint != 0 && "Did not find ctor vtable address point!");
- } else {
- // Just get the address point for the regular vtable.
- AddressPoint = CGM.getVTables().getAddressPoint(Base, VTableClass);
- assert(AddressPoint != 0 && "Did not find vtable address point!");
- }
+void
+CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT,
+ llvm::GlobalVariable::LinkageTypes Linkage,
+ const CXXRecordDecl *RD) {
+ VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/true);
- if (!AddressPoint) AddressPoint = 0;
-
- llvm::Value *Idxs[] = {
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(CGM.getLLVMContext()), 0),
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(CGM.getLLVMContext()),
- AddressPoint)
- };
-
- llvm::Constant *Init =
- llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Idxs, 2);
-
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy);
+ llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()),
+ *Int64Ty = llvm::Type::getInt64Ty(CGM.getLLVMContext());
+ llvm::ArrayType *ArrayType =
+ llvm::ArrayType::get(Int8PtrTy, Builder.getVTTComponents().size());
- VTTComponents.push_back(Init);
-}
-
-void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) {
- const CXXRecordDecl *RD = Base.getBase();
-
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
-
- // Don't layout virtual bases.
- if (I->isVirtual())
- continue;
-
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- CharUnits BaseOffset = Base.getBaseOffset() +
- Layout.getBaseClassOffset(BaseDecl);
-
- // Layout the VTT for this base.
- LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false);
+ SmallVector<llvm::Constant *, 8> VTables;
+ SmallVector<VTableAddressPointsMapTy, 8> VTableAddressPoints;
+ for (const VTTVTable *i = Builder.getVTTVTables().begin(),
+ *e = Builder.getVTTVTables().end(); i != e; ++i) {
+ VTableAddressPoints.push_back(VTableAddressPointsMapTy());
+ VTables.push_back(GetAddrOfVTTVTable(*this, RD, *i, Linkage,
+ VTableAddressPoints.back()));
}
-}
-
-void
-VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
- bool BaseIsMorallyVirtual,
- llvm::Constant *VTable,
- const CXXRecordDecl *VTableClass,
- const AddressPointsMapTy& AddressPoints,
- VisitedVirtualBasesSetTy &VBases) {
- const CXXRecordDecl *RD = Base.getBase();
-
- // We're not interested in bases that don't have virtual bases, and not
- // morally virtual bases.
- if (!RD->getNumVBases() && !BaseIsMorallyVirtual)
- return;
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
- // Itanium C++ ABI 2.6.2:
- // Secondary virtual pointers are present for all bases with either
- // virtual bases or virtual function declarations overridden along a
- // virtual path.
- //
- // If the base class is not dynamic, we don't want to add it, nor any
- // of its base classes.
- if (!BaseDecl->isDynamicClass())
- continue;
-
- bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual;
- bool BaseDeclIsNonVirtualPrimaryBase = false;
- CharUnits BaseOffset;
- if (I->isVirtual()) {
- // Ignore virtual bases that we've already visited.
- if (!VBases.insert(BaseDecl))
- continue;
-
- BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
- BaseDeclIsMorallyVirtual = true;
+ SmallVector<llvm::Constant *, 8> VTTComponents;
+ for (const VTTComponent *i = Builder.getVTTComponents().begin(),
+ *e = Builder.getVTTComponents().end(); i != e; ++i) {
+ const VTTVTable &VTTVT = Builder.getVTTVTables()[i->VTableIndex];
+ llvm::Constant *VTable = VTables[i->VTableIndex];
+ uint64_t AddressPoint;
+ if (VTTVT.getBase() == RD) {
+ // Just get the address point for the regular vtable.
+ AddressPoint = VTContext.getVTableLayout(RD)
+ .getAddressPoint(i->VTableBase);
+ assert(AddressPoint != 0 && "Did not find vtable address point!");
} else {
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
-
- BaseOffset = Base.getBaseOffset() +
- Layout.getBaseClassOffset(BaseDecl);
-
- if (!Layout.isPrimaryBaseVirtual() &&
- Layout.getPrimaryBase() == BaseDecl)
- BaseDeclIsNonVirtualPrimaryBase = true;
+ AddressPoint = VTableAddressPoints[i->VTableIndex].lookup(i->VTableBase);
+ assert(AddressPoint != 0 && "Did not find ctor vtable address point!");
}
- // Itanium C++ ABI 2.6.2:
- // Secondary virtual pointers: for each base class X which (a) has virtual
- // bases or is reachable along a virtual path from D, and (b) is not a
- // non-virtual primary base, the address of the virtual table for X-in-D
- // or an appropriate construction virtual table.
- if (!BaseDeclIsNonVirtualPrimaryBase &&
- (BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) {
- // Add the vtable pointer.
- AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTable,
- VTableClass, AddressPoints);
- }
+ llvm::Value *Idxs[] = {
+ llvm::ConstantInt::get(Int64Ty, 0),
+ llvm::ConstantInt::get(Int64Ty, AddressPoint)
+ };
- // And lay out the secondary virtual pointers for the base class.
- LayoutSecondaryVirtualPointers(BaseSubobject(BaseDecl, BaseOffset),
- BaseDeclIsMorallyVirtual, VTable,
- VTableClass, AddressPoints, VBases);
- }
-}
+ llvm::Constant *Init =
+ llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Idxs);
-void
-VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
- llvm::Constant *VTable,
- const AddressPointsMapTy& AddressPoints) {
- VisitedVirtualBasesSetTy VBases;
- LayoutSecondaryVirtualPointers(Base, /*BaseIsMorallyVirtual=*/false,
- VTable, Base.getBase(), AddressPoints, VBases);
-}
+ Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy);
-void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD,
- VisitedVirtualBasesSetTy &VBases) {
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
- // Check if this is a virtual base.
- if (I->isVirtual()) {
- // Check if we've seen this base before.
- if (!VBases.insert(BaseDecl))
- continue;
-
- CharUnits BaseOffset =
- MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
-
- LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/true);
- }
-
- // We only need to layout virtual VTTs for this base if it actually has
- // virtual bases.
- if (BaseDecl->getNumVBases())
- LayoutVirtualVTTs(BaseDecl, VBases);
+ VTTComponents.push_back(Init);
}
-}
-void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) {
- const CXXRecordDecl *RD = Base.getBase();
-
- // Itanium C++ ABI 2.6.2:
- // An array of virtual table addresses, called the VTT, is declared for
- // each class type that has indirect or direct virtual base classes.
- if (RD->getNumVBases() == 0)
- return;
-
- bool IsPrimaryVTT = Base.getBase() == MostDerivedClass;
-
- if (!IsPrimaryVTT) {
- // Remember the sub-VTT index.
- SubVTTIndicies[Base] = VTTComponents.size();
- }
-
- AddressPointsMapTy AddressPoints;
- llvm::Constant *VTable = GetAddrOfVTable(Base, BaseIsVirtual, AddressPoints);
-
- // Add the primary vtable pointer.
- AddVTablePointer(Base, VTable, RD, AddressPoints);
-
- // Add the secondary VTTs.
- LayoutSecondaryVTTs(Base);
-
- // Add the secondary virtual pointers.
- LayoutSecondaryVirtualPointers(Base, VTable, AddressPoints);
-
- // If this is the primary VTT, we want to lay out virtual VTTs as well.
- if (IsPrimaryVTT) {
- VisitedVirtualBasesSetTy VBases;
- LayoutVirtualVTTs(Base.getBase(), VBases);
- }
-}
-
-}
-
-void
-CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT,
- llvm::GlobalVariable::LinkageTypes Linkage,
- const CXXRecordDecl *RD) {
- VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/true, Linkage);
-
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- const llvm::ArrayType *ArrayType =
- llvm::ArrayType::get(Int8PtrTy, Builder.getVTTComponents().size());
-
- llvm::Constant *Init =
- llvm::ConstantArray::get(ArrayType, Builder.getVTTComponents());
+ llvm::Constant *Init = llvm::ConstantArray::get(ArrayType, VTTComponents);
VTT->setInitializer(Init);
@@ -408,15 +106,16 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) {
llvm::raw_svector_ostream Out(OutName);
CGM.getCXXABI().getMangleContext().mangleCXXVTT(RD, Out);
Out.flush();
- llvm::StringRef Name = OutName.str();
+ StringRef Name = OutName.str();
- ComputeVTableRelatedInformation(RD, /*VTableRequired=*/true);
+ // This will also defer the definition of the VTT.
+ (void) GetAddrOfVTable(RD);
- VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false);
+ VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false);
- const llvm::Type *Int8PtrTy =
+ llvm::Type *Int8PtrTy =
llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- const llvm::ArrayType *ArrayType =
+ llvm::ArrayType *ArrayType =
llvm::ArrayType::get(Int8PtrTy, Builder.getVTTComponents().size());
llvm::GlobalVariable *GV =
@@ -452,7 +151,7 @@ uint64_t CodeGenVTables::getSubVTTIndex(const CXXRecordDecl *RD,
if (I != SubVTTIndicies.end())
return I->second;
- VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false);
+ VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false);
for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator I =
Builder.getSubVTTIndicies().begin(),
@@ -478,7 +177,7 @@ CodeGenVTables::getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD,
if (I != SecondaryVirtualPointerIndices.end())
return I->second;
- VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false);
+ VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false);
// Insert all secondary vpointer indices.
for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator I =
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index c161b79fd3a0..a306c857e5aa 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -28,2399 +28,8 @@
using namespace clang;
using namespace CodeGen;
-namespace {
-
-/// BaseOffset - Represents an offset from a derived class to a direct or
-/// indirect base class.
-struct BaseOffset {
- /// DerivedClass - The derived class.
- const CXXRecordDecl *DerivedClass;
-
- /// VirtualBase - If the path from the derived class to the base class
- /// involves a virtual base class, this holds its declaration.
- const CXXRecordDecl *VirtualBase;
-
- /// NonVirtualOffset - The offset from the derived class to the base class.
- /// (Or the offset from the virtual base class to the base class, if the
- /// path from the derived class to the base class involves a virtual base
- /// class.
- CharUnits NonVirtualOffset;
-
- BaseOffset() : DerivedClass(0), VirtualBase(0),
- NonVirtualOffset(CharUnits::Zero()) { }
- BaseOffset(const CXXRecordDecl *DerivedClass,
- const CXXRecordDecl *VirtualBase, CharUnits NonVirtualOffset)
- : DerivedClass(DerivedClass), VirtualBase(VirtualBase),
- NonVirtualOffset(NonVirtualOffset) { }
-
- bool isEmpty() const { return NonVirtualOffset.isZero() && !VirtualBase; }
-};
-
-/// FinalOverriders - Contains the final overrider member functions for all
-/// member functions in the base subobjects of a class.
-class FinalOverriders {
-public:
- /// OverriderInfo - Information about a final overrider.
- struct OverriderInfo {
- /// Method - The method decl of the overrider.
- const CXXMethodDecl *Method;
-
- /// Offset - the base offset of the overrider in the layout class.
- CharUnits Offset;
-
- OverriderInfo() : Method(0), Offset(CharUnits::Zero()) { }
- };
-
-private:
- /// MostDerivedClass - The most derived class for which the final overriders
- /// are stored.
- const CXXRecordDecl *MostDerivedClass;
-
- /// MostDerivedClassOffset - If we're building final overriders for a
- /// construction vtable, this holds the offset from the layout class to the
- /// most derived class.
- const CharUnits MostDerivedClassOffset;
-
- /// LayoutClass - The class we're using for layout information. Will be
- /// different than the most derived class if the final overriders are for a
- /// construction vtable.
- const CXXRecordDecl *LayoutClass;
-
- ASTContext &Context;
-
- /// MostDerivedClassLayout - the AST record layout of the most derived class.
- const ASTRecordLayout &MostDerivedClassLayout;
-
- /// MethodBaseOffsetPairTy - Uniquely identifies a member function
- /// in a base subobject.
- typedef std::pair<const CXXMethodDecl *, CharUnits> MethodBaseOffsetPairTy;
-
- typedef llvm::DenseMap<MethodBaseOffsetPairTy,
- OverriderInfo> OverridersMapTy;
-
- /// OverridersMap - The final overriders for all virtual member functions of
- /// all the base subobjects of the most derived class.
- OverridersMapTy OverridersMap;
-
- /// SubobjectsToOffsetsMapTy - A mapping from a base subobject (represented
- /// as a record decl and a subobject number) and its offsets in the most
- /// derived class as well as the layout class.
- typedef llvm::DenseMap<std::pair<const CXXRecordDecl *, unsigned>,
- CharUnits> SubobjectOffsetMapTy;
-
- typedef llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCountMapTy;
-
- /// ComputeBaseOffsets - Compute the offsets for all base subobjects of the
- /// given base.
- void ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual,
- CharUnits OffsetInLayoutClass,
- SubobjectOffsetMapTy &SubobjectOffsets,
- SubobjectOffsetMapTy &SubobjectLayoutClassOffsets,
- SubobjectCountMapTy &SubobjectCounts);
-
- typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
-
- /// dump - dump the final overriders for a base subobject, and all its direct
- /// and indirect base subobjects.
- void dump(llvm::raw_ostream &Out, BaseSubobject Base,
- VisitedVirtualBasesSetTy& VisitedVirtualBases);
-
-public:
- FinalOverriders(const CXXRecordDecl *MostDerivedClass,
- CharUnits MostDerivedClassOffset,
- const CXXRecordDecl *LayoutClass);
-
- /// getOverrider - Get the final overrider for the given method declaration in
- /// the subobject with the given base offset.
- OverriderInfo getOverrider(const CXXMethodDecl *MD,
- CharUnits BaseOffset) const {
- assert(OverridersMap.count(std::make_pair(MD, BaseOffset)) &&
- "Did not find overrider!");
-
- return OverridersMap.lookup(std::make_pair(MD, BaseOffset));
- }
-
- /// dump - dump the final overriders.
- void dump() {
- VisitedVirtualBasesSetTy VisitedVirtualBases;
- dump(llvm::errs(), BaseSubobject(MostDerivedClass, CharUnits::Zero()),
- VisitedVirtualBases);
- }
-
-};
-
-#define DUMP_OVERRIDERS 0
-
-FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass,
- CharUnits MostDerivedClassOffset,
- const CXXRecordDecl *LayoutClass)
- : MostDerivedClass(MostDerivedClass),
- MostDerivedClassOffset(MostDerivedClassOffset), LayoutClass(LayoutClass),
- Context(MostDerivedClass->getASTContext()),
- MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)) {
-
- // Compute base offsets.
- SubobjectOffsetMapTy SubobjectOffsets;
- SubobjectOffsetMapTy SubobjectLayoutClassOffsets;
- SubobjectCountMapTy SubobjectCounts;
- ComputeBaseOffsets(BaseSubobject(MostDerivedClass, CharUnits::Zero()),
- /*IsVirtual=*/false,
- MostDerivedClassOffset,
- SubobjectOffsets, SubobjectLayoutClassOffsets,
- SubobjectCounts);
-
- // Get the the final overriders.
- CXXFinalOverriderMap FinalOverriders;
- MostDerivedClass->getFinalOverriders(FinalOverriders);
-
- for (CXXFinalOverriderMap::const_iterator I = FinalOverriders.begin(),
- E = FinalOverriders.end(); I != E; ++I) {
- const CXXMethodDecl *MD = I->first;
- const OverridingMethods& Methods = I->second;
-
- for (OverridingMethods::const_iterator I = Methods.begin(),
- E = Methods.end(); I != E; ++I) {
- unsigned SubobjectNumber = I->first;
- assert(SubobjectOffsets.count(std::make_pair(MD->getParent(),
- SubobjectNumber)) &&
- "Did not find subobject offset!");
-
- CharUnits BaseOffset = SubobjectOffsets[std::make_pair(MD->getParent(),
- SubobjectNumber)];
-
- assert(I->second.size() == 1 && "Final overrider is not unique!");
- const UniqueVirtualMethod &Method = I->second.front();
-
- const CXXRecordDecl *OverriderRD = Method.Method->getParent();
- assert(SubobjectLayoutClassOffsets.count(
- std::make_pair(OverriderRD, Method.Subobject))
- && "Did not find subobject offset!");
- CharUnits OverriderOffset =
- SubobjectLayoutClassOffsets[std::make_pair(OverriderRD,
- Method.Subobject)];
-
- OverriderInfo& Overrider = OverridersMap[std::make_pair(MD, BaseOffset)];
- assert(!Overrider.Method && "Overrider should not exist yet!");
-
- Overrider.Offset = OverriderOffset;
- Overrider.Method = Method.Method;
- }
- }
-
-#if DUMP_OVERRIDERS
- // And dump them (for now).
- dump();
-#endif
-}
-
-static BaseOffset ComputeBaseOffset(ASTContext &Context,
- const CXXRecordDecl *DerivedRD,
- const CXXBasePath &Path) {
- CharUnits NonVirtualOffset = CharUnits::Zero();
-
- unsigned NonVirtualStart = 0;
- const CXXRecordDecl *VirtualBase = 0;
-
- // First, look for the virtual base class.
- for (unsigned I = 0, E = Path.size(); I != E; ++I) {
- const CXXBasePathElement &Element = Path[I];
-
- if (Element.Base->isVirtual()) {
- // FIXME: Can we break when we find the first virtual base?
- // (If we can't, can't we just iterate over the path in reverse order?)
- NonVirtualStart = I + 1;
- QualType VBaseType = Element.Base->getType();
- VirtualBase =
- cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
- }
- }
-
- // Now compute the non-virtual offset.
- for (unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I) {
- const CXXBasePathElement &Element = Path[I];
-
- // Check the base class offset.
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class);
-
- const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>();
- const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl());
-
- NonVirtualOffset += Layout.getBaseClassOffset(Base);
- }
-
- // FIXME: This should probably use CharUnits or something. Maybe we should
- // even change the base offsets in ASTRecordLayout to be specified in
- // CharUnits.
- return BaseOffset(DerivedRD, VirtualBase, NonVirtualOffset);
-
-}
-
-static BaseOffset ComputeBaseOffset(ASTContext &Context,
- const CXXRecordDecl *BaseRD,
- const CXXRecordDecl *DerivedRD) {
- CXXBasePaths Paths(/*FindAmbiguities=*/false,
- /*RecordPaths=*/true, /*DetectVirtual=*/false);
-
- if (!const_cast<CXXRecordDecl *>(DerivedRD)->
- isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) {
- assert(false && "Class must be derived from the passed in base class!");
- return BaseOffset();
- }
-
- return ComputeBaseOffset(Context, DerivedRD, Paths.front());
-}
-
-static BaseOffset
-ComputeReturnAdjustmentBaseOffset(ASTContext &Context,
- const CXXMethodDecl *DerivedMD,
- const CXXMethodDecl *BaseMD) {
- const FunctionType *BaseFT = BaseMD->getType()->getAs<FunctionType>();
- const FunctionType *DerivedFT = DerivedMD->getType()->getAs<FunctionType>();
-
- // Canonicalize the return types.
- CanQualType CanDerivedReturnType =
- Context.getCanonicalType(DerivedFT->getResultType());
- CanQualType CanBaseReturnType =
- Context.getCanonicalType(BaseFT->getResultType());
-
- assert(CanDerivedReturnType->getTypeClass() ==
- CanBaseReturnType->getTypeClass() &&
- "Types must have same type class!");
-
- if (CanDerivedReturnType == CanBaseReturnType) {
- // No adjustment needed.
- return BaseOffset();
- }
-
- if (isa<ReferenceType>(CanDerivedReturnType)) {
- CanDerivedReturnType =
- CanDerivedReturnType->getAs<ReferenceType>()->getPointeeType();
- CanBaseReturnType =
- CanBaseReturnType->getAs<ReferenceType>()->getPointeeType();
- } else if (isa<PointerType>(CanDerivedReturnType)) {
- CanDerivedReturnType =
- CanDerivedReturnType->getAs<PointerType>()->getPointeeType();
- CanBaseReturnType =
- CanBaseReturnType->getAs<PointerType>()->getPointeeType();
- } else {
- assert(false && "Unexpected return type!");
- }
-
- // We need to compare unqualified types here; consider
- // const T *Base::foo();
- // T *Derived::foo();
- if (CanDerivedReturnType.getUnqualifiedType() ==
- CanBaseReturnType.getUnqualifiedType()) {
- // No adjustment needed.
- return BaseOffset();
- }
-
- const CXXRecordDecl *DerivedRD =
- cast<CXXRecordDecl>(cast<RecordType>(CanDerivedReturnType)->getDecl());
-
- const CXXRecordDecl *BaseRD =
- cast<CXXRecordDecl>(cast<RecordType>(CanBaseReturnType)->getDecl());
-
- return ComputeBaseOffset(Context, BaseRD, DerivedRD);
-}
-
-void
-FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual,
- CharUnits OffsetInLayoutClass,
- SubobjectOffsetMapTy &SubobjectOffsets,
- SubobjectOffsetMapTy &SubobjectLayoutClassOffsets,
- SubobjectCountMapTy &SubobjectCounts) {
- const CXXRecordDecl *RD = Base.getBase();
-
- unsigned SubobjectNumber = 0;
- if (!IsVirtual)
- SubobjectNumber = ++SubobjectCounts[RD];
-
- // Set up the subobject to offset mapping.
- assert(!SubobjectOffsets.count(std::make_pair(RD, SubobjectNumber))
- && "Subobject offset already exists!");
- assert(!SubobjectLayoutClassOffsets.count(std::make_pair(RD, SubobjectNumber))
- && "Subobject offset already exists!");
-
- SubobjectOffsets[std::make_pair(RD, SubobjectNumber)] = Base.getBaseOffset();
- SubobjectLayoutClassOffsets[std::make_pair(RD, SubobjectNumber)] =
- OffsetInLayoutClass;
-
- // Traverse our bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
- CharUnits BaseOffset;
- CharUnits BaseOffsetInLayoutClass;
- if (I->isVirtual()) {
- // Check if we've visited this virtual base before.
- if (SubobjectOffsets.count(std::make_pair(BaseDecl, 0)))
- continue;
-
- const ASTRecordLayout &LayoutClassLayout =
- Context.getASTRecordLayout(LayoutClass);
-
- BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
- BaseOffsetInLayoutClass =
- LayoutClassLayout.getVBaseClassOffset(BaseDecl);
- } else {
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- CharUnits Offset = Layout.getBaseClassOffset(BaseDecl);
-
- BaseOffset = Base.getBaseOffset() + Offset;
- BaseOffsetInLayoutClass = OffsetInLayoutClass + Offset;
- }
-
- ComputeBaseOffsets(BaseSubobject(BaseDecl, BaseOffset),
- I->isVirtual(), BaseOffsetInLayoutClass,
- SubobjectOffsets, SubobjectLayoutClassOffsets,
- SubobjectCounts);
- }
-}
-
-void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base,
- VisitedVirtualBasesSetTy &VisitedVirtualBases) {
- const CXXRecordDecl *RD = Base.getBase();
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
-
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
- // Ignore bases that don't have any virtual member functions.
- if (!BaseDecl->isPolymorphic())
- continue;
-
- CharUnits BaseOffset;
- if (I->isVirtual()) {
- if (!VisitedVirtualBases.insert(BaseDecl)) {
- // We've visited this base before.
- continue;
- }
-
- BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
- } else {
- BaseOffset = Layout.getBaseClassOffset(BaseDecl) + Base.getBaseOffset();
- }
-
- dump(Out, BaseSubobject(BaseDecl, BaseOffset), VisitedVirtualBases);
- }
-
- Out << "Final overriders for (" << RD->getQualifiedNameAsString() << ", ";
- Out << Base.getBaseOffset().getQuantity() << ")\n";
-
- // Now dump the overriders for this base subobject.
- for (CXXRecordDecl::method_iterator I = RD->method_begin(),
- E = RD->method_end(); I != E; ++I) {
- const CXXMethodDecl *MD = *I;
-
- if (!MD->isVirtual())
- continue;
-
- OverriderInfo Overrider = getOverrider(MD, Base.getBaseOffset());
-
- Out << " " << MD->getQualifiedNameAsString() << " - (";
- Out << Overrider.Method->getQualifiedNameAsString();
- Out << ", " << ", " << Overrider.Offset.getQuantity() << ')';
-
- BaseOffset Offset;
- if (!Overrider.Method->isPure())
- Offset = ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD);
-
- if (!Offset.isEmpty()) {
- Out << " [ret-adj: ";
- if (Offset.VirtualBase)
- Out << Offset.VirtualBase->getQualifiedNameAsString() << " vbase, ";
-
- Out << Offset.NonVirtualOffset.getQuantity() << " nv]";
- }
-
- Out << "\n";
- }
-}
-
-/// VTableComponent - Represents a single component in a vtable.
-class VTableComponent {
-public:
- enum Kind {
- CK_VCallOffset,
- CK_VBaseOffset,
- CK_OffsetToTop,
- CK_RTTI,
- CK_FunctionPointer,
-
- /// CK_CompleteDtorPointer - A pointer to the complete destructor.
- CK_CompleteDtorPointer,
-
- /// CK_DeletingDtorPointer - A pointer to the deleting destructor.
- CK_DeletingDtorPointer,
-
- /// CK_UnusedFunctionPointer - In some cases, a vtable function pointer
- /// will end up never being called. Such vtable function pointers are
- /// represented as a CK_UnusedFunctionPointer.
- CK_UnusedFunctionPointer
- };
-
- static VTableComponent MakeVCallOffset(CharUnits Offset) {
- return VTableComponent(CK_VCallOffset, Offset);
- }
-
- static VTableComponent MakeVBaseOffset(CharUnits Offset) {
- return VTableComponent(CK_VBaseOffset, Offset);
- }
-
- static VTableComponent MakeOffsetToTop(CharUnits Offset) {
- return VTableComponent(CK_OffsetToTop, Offset);
- }
-
- static VTableComponent MakeRTTI(const CXXRecordDecl *RD) {
- return VTableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD));
- }
-
- static VTableComponent MakeFunction(const CXXMethodDecl *MD) {
- assert(!isa<CXXDestructorDecl>(MD) &&
- "Don't use MakeFunction with destructors!");
-
- return VTableComponent(CK_FunctionPointer,
- reinterpret_cast<uintptr_t>(MD));
- }
-
- static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) {
- return VTableComponent(CK_CompleteDtorPointer,
- reinterpret_cast<uintptr_t>(DD));
- }
-
- static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) {
- return VTableComponent(CK_DeletingDtorPointer,
- reinterpret_cast<uintptr_t>(DD));
- }
-
- static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) {
- assert(!isa<CXXDestructorDecl>(MD) &&
- "Don't use MakeUnusedFunction with destructors!");
- return VTableComponent(CK_UnusedFunctionPointer,
- reinterpret_cast<uintptr_t>(MD));
- }
-
- static VTableComponent getFromOpaqueInteger(uint64_t I) {
- return VTableComponent(I);
- }
-
- /// getKind - Get the kind of this vtable component.
- Kind getKind() const {
- return (Kind)(Value & 0x7);
- }
-
- CharUnits getVCallOffset() const {
- assert(getKind() == CK_VCallOffset && "Invalid component kind!");
-
- return getOffset();
- }
-
- CharUnits getVBaseOffset() const {
- assert(getKind() == CK_VBaseOffset && "Invalid component kind!");
-
- return getOffset();
- }
-
- CharUnits getOffsetToTop() const {
- assert(getKind() == CK_OffsetToTop && "Invalid component kind!");
-
- return getOffset();
- }
-
- const CXXRecordDecl *getRTTIDecl() const {
- assert(getKind() == CK_RTTI && "Invalid component kind!");
-
- return reinterpret_cast<CXXRecordDecl *>(getPointer());
- }
-
- const CXXMethodDecl *getFunctionDecl() const {
- assert(getKind() == CK_FunctionPointer);
-
- return reinterpret_cast<CXXMethodDecl *>(getPointer());
- }
-
- const CXXDestructorDecl *getDestructorDecl() const {
- assert((getKind() == CK_CompleteDtorPointer ||
- getKind() == CK_DeletingDtorPointer) && "Invalid component kind!");
-
- return reinterpret_cast<CXXDestructorDecl *>(getPointer());
- }
-
- const CXXMethodDecl *getUnusedFunctionDecl() const {
- assert(getKind() == CK_UnusedFunctionPointer);
-
- return reinterpret_cast<CXXMethodDecl *>(getPointer());
- }
-
-private:
- VTableComponent(Kind ComponentKind, CharUnits Offset) {
- assert((ComponentKind == CK_VCallOffset ||
- ComponentKind == CK_VBaseOffset ||
- ComponentKind == CK_OffsetToTop) && "Invalid component kind!");
- assert(Offset.getQuantity() <= ((1LL << 56) - 1) && "Offset is too big!");
-
- Value = ((Offset.getQuantity() << 3) | ComponentKind);
- }
-
- VTableComponent(Kind ComponentKind, uintptr_t Ptr) {
- assert((ComponentKind == CK_RTTI ||
- ComponentKind == CK_FunctionPointer ||
- ComponentKind == CK_CompleteDtorPointer ||
- ComponentKind == CK_DeletingDtorPointer ||
- ComponentKind == CK_UnusedFunctionPointer) &&
- "Invalid component kind!");
-
- assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!");
-
- Value = Ptr | ComponentKind;
- }
-
- CharUnits getOffset() const {
- assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset ||
- getKind() == CK_OffsetToTop) && "Invalid component kind!");
-
- return CharUnits::fromQuantity(Value >> 3);
- }
-
- uintptr_t getPointer() const {
- assert((getKind() == CK_RTTI ||
- getKind() == CK_FunctionPointer ||
- getKind() == CK_CompleteDtorPointer ||
- getKind() == CK_DeletingDtorPointer ||
- getKind() == CK_UnusedFunctionPointer) &&
- "Invalid component kind!");
-
- return static_cast<uintptr_t>(Value & ~7ULL);
- }
-
- explicit VTableComponent(uint64_t Value)
- : Value(Value) { }
-
- /// The kind is stored in the lower 3 bits of the value. For offsets, we
- /// make use of the facts that classes can't be larger than 2^55 bytes,
- /// so we store the offset in the lower part of the 61 bytes that remain.
- /// (The reason that we're not simply using a PointerIntPair here is that we
- /// need the offsets to be 64-bit, even when on a 32-bit machine).
- int64_t Value;
-};
-
-/// VCallOffsetMap - Keeps track of vcall offsets when building a vtable.
-struct VCallOffsetMap {
-
- typedef std::pair<const CXXMethodDecl *, CharUnits> MethodAndOffsetPairTy;
-
- /// Offsets - Keeps track of methods and their offsets.
- // FIXME: This should be a real map and not a vector.
- llvm::SmallVector<MethodAndOffsetPairTy, 16> Offsets;
-
- /// MethodsCanShareVCallOffset - Returns whether two virtual member functions
- /// can share the same vcall offset.
- static bool MethodsCanShareVCallOffset(const CXXMethodDecl *LHS,
- const CXXMethodDecl *RHS);
-
-public:
- /// AddVCallOffset - Adds a vcall offset to the map. Returns true if the
- /// add was successful, or false if there was already a member function with
- /// the same signature in the map.
- bool AddVCallOffset(const CXXMethodDecl *MD, CharUnits OffsetOffset);
-
- /// getVCallOffsetOffset - Returns the vcall offset offset (relative to the
- /// vtable address point) for the given virtual member function.
- CharUnits getVCallOffsetOffset(const CXXMethodDecl *MD);
-
- // empty - Return whether the offset map is empty or not.
- bool empty() const { return Offsets.empty(); }
-};
-
-static bool HasSameVirtualSignature(const CXXMethodDecl *LHS,
- const CXXMethodDecl *RHS) {
- ASTContext &C = LHS->getASTContext(); // TODO: thread this down
- CanQual<FunctionProtoType>
- LT = C.getCanonicalType(LHS->getType()).getAs<FunctionProtoType>(),
- RT = C.getCanonicalType(RHS->getType()).getAs<FunctionProtoType>();
-
- // Fast-path matches in the canonical types.
- if (LT == RT) return true;
-
- // Force the signatures to match. We can't rely on the overrides
- // list here because there isn't necessarily an inheritance
- // relationship between the two methods.
- if (LT.getQualifiers() != RT.getQualifiers() ||
- LT->getNumArgs() != RT->getNumArgs())
- return false;
- for (unsigned I = 0, E = LT->getNumArgs(); I != E; ++I)
- if (LT->getArgType(I) != RT->getArgType(I))
- return false;
- return true;
-}
-
-bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS,
- const CXXMethodDecl *RHS) {
- assert(LHS->isVirtual() && "LHS must be virtual!");
- assert(RHS->isVirtual() && "LHS must be virtual!");
-
- // A destructor can share a vcall offset with another destructor.
- if (isa<CXXDestructorDecl>(LHS))
- return isa<CXXDestructorDecl>(RHS);
-
- // FIXME: We need to check more things here.
-
- // The methods must have the same name.
- DeclarationName LHSName = LHS->getDeclName();
- DeclarationName RHSName = RHS->getDeclName();
- if (LHSName != RHSName)
- return false;
-
- // And the same signatures.
- return HasSameVirtualSignature(LHS, RHS);
-}
-
-bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD,
- CharUnits OffsetOffset) {
- // Check if we can reuse an offset.
- for (unsigned I = 0, E = Offsets.size(); I != E; ++I) {
- if (MethodsCanShareVCallOffset(Offsets[I].first, MD))
- return false;
- }
-
- // Add the offset.
- Offsets.push_back(MethodAndOffsetPairTy(MD, OffsetOffset));
- return true;
-}
-
-CharUnits VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) {
- // Look for an offset.
- for (unsigned I = 0, E = Offsets.size(); I != E; ++I) {
- if (MethodsCanShareVCallOffset(Offsets[I].first, MD))
- return Offsets[I].second;
- }
-
- assert(false && "Should always find a vcall offset offset!");
- return CharUnits::Zero();
-}
-
-/// VCallAndVBaseOffsetBuilder - Class for building vcall and vbase offsets.
-class VCallAndVBaseOffsetBuilder {
-public:
- typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits>
- VBaseOffsetOffsetsMapTy;
-
-private:
- /// MostDerivedClass - The most derived class for which we're building vcall
- /// and vbase offsets.
- const CXXRecordDecl *MostDerivedClass;
-
- /// LayoutClass - The class we're using for layout information. Will be
- /// different than the most derived class if we're building a construction
- /// vtable.
- const CXXRecordDecl *LayoutClass;
-
- /// Context - The ASTContext which we will use for layout information.
- ASTContext &Context;
-
- /// Components - vcall and vbase offset components
- typedef llvm::SmallVector<VTableComponent, 64> VTableComponentVectorTy;
- VTableComponentVectorTy Components;
-
- /// VisitedVirtualBases - Visited virtual bases.
- llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
-
- /// VCallOffsets - Keeps track of vcall offsets.
- VCallOffsetMap VCallOffsets;
-
-
- /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets,
- /// relative to the address point.
- VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
-
- /// FinalOverriders - The final overriders of the most derived class.
- /// (Can be null when we're not building a vtable of the most derived class).
- const FinalOverriders *Overriders;
-
- /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the
- /// given base subobject.
- void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual,
- CharUnits RealBaseOffset);
-
- /// AddVCallOffsets - Add vcall offsets for the given base subobject.
- void AddVCallOffsets(BaseSubobject Base, CharUnits VBaseOffset);
-
- /// AddVBaseOffsets - Add vbase offsets for the given class.
- void AddVBaseOffsets(const CXXRecordDecl *Base,
- CharUnits OffsetInLayoutClass);
-
- /// getCurrentOffsetOffset - Get the current vcall or vbase offset offset in
- /// chars, relative to the vtable address point.
- CharUnits getCurrentOffsetOffset() const;
-
-public:
- VCallAndVBaseOffsetBuilder(const CXXRecordDecl *MostDerivedClass,
- const CXXRecordDecl *LayoutClass,
- const FinalOverriders *Overriders,
- BaseSubobject Base, bool BaseIsVirtual,
- CharUnits OffsetInLayoutClass)
- : MostDerivedClass(MostDerivedClass), LayoutClass(LayoutClass),
- Context(MostDerivedClass->getASTContext()), Overriders(Overriders) {
-
- // Add vcall and vbase offsets.
- AddVCallAndVBaseOffsets(Base, BaseIsVirtual, OffsetInLayoutClass);
- }
-
- /// Methods for iterating over the components.
- typedef VTableComponentVectorTy::const_reverse_iterator const_iterator;
- const_iterator components_begin() const { return Components.rbegin(); }
- const_iterator components_end() const { return Components.rend(); }
-
- const VCallOffsetMap &getVCallOffsets() const { return VCallOffsets; }
- const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const {
- return VBaseOffsetOffsets;
- }
-};
-
-void
-VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base,
- bool BaseIsVirtual,
- CharUnits RealBaseOffset) {
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase());
-
- // Itanium C++ ABI 2.5.2:
- // ..in classes sharing a virtual table with a primary base class, the vcall
- // and vbase offsets added by the derived class all come before the vcall
- // and vbase offsets required by the base class, so that the latter may be
- // laid out as required by the base class without regard to additions from
- // the derived class(es).
-
- // (Since we're emitting the vcall and vbase offsets in reverse order, we'll
- // emit them for the primary base first).
- if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
- bool PrimaryBaseIsVirtual = Layout.isPrimaryBaseVirtual();
-
- CharUnits PrimaryBaseOffset;
-
- // Get the base offset of the primary base.
- if (PrimaryBaseIsVirtual) {
- assert(Layout.getVBaseClassOffsetInBits(PrimaryBase) == 0 &&
- "Primary vbase should have a zero offset!");
-
- const ASTRecordLayout &MostDerivedClassLayout =
- Context.getASTRecordLayout(MostDerivedClass);
-
- PrimaryBaseOffset =
- MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase);
- } else {
- assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 &&
- "Primary base should have a zero offset!");
-
- PrimaryBaseOffset = Base.getBaseOffset();
- }
-
- AddVCallAndVBaseOffsets(
- BaseSubobject(PrimaryBase,PrimaryBaseOffset),
- PrimaryBaseIsVirtual, RealBaseOffset);
- }
-
- AddVBaseOffsets(Base.getBase(), RealBaseOffset);
-
- // We only want to add vcall offsets for virtual bases.
- if (BaseIsVirtual)
- AddVCallOffsets(Base, RealBaseOffset);
-}
-
-CharUnits VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const {
- // OffsetIndex is the index of this vcall or vbase offset, relative to the
- // vtable address point. (We subtract 3 to account for the information just
- // above the address point, the RTTI info, the offset to top, and the
- // vcall offset itself).
- int64_t OffsetIndex = -(int64_t)(3 + Components.size());
-
- CharUnits PointerWidth =
- Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0));
- CharUnits OffsetOffset = PointerWidth * OffsetIndex;
- return OffsetOffset;
-}
-
-void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
- CharUnits VBaseOffset) {
- const CXXRecordDecl *RD = Base.getBase();
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
-
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
-
- // Handle the primary base first.
- // We only want to add vcall offsets if the base is non-virtual; a virtual
- // primary base will have its vcall and vbase offsets emitted already.
- if (PrimaryBase && !Layout.isPrimaryBaseVirtual()) {
- // Get the base offset of the primary base.
- assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 &&
- "Primary base should have a zero offset!");
-
- AddVCallOffsets(BaseSubobject(PrimaryBase, Base.getBaseOffset()),
- VBaseOffset);
- }
-
- // Add the vcall offsets.
- for (CXXRecordDecl::method_iterator I = RD->method_begin(),
- E = RD->method_end(); I != E; ++I) {
- const CXXMethodDecl *MD = *I;
-
- if (!MD->isVirtual())
- continue;
-
- CharUnits OffsetOffset = getCurrentOffsetOffset();
-
- // Don't add a vcall offset if we already have one for this member function
- // signature.
- if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset))
- continue;
-
- CharUnits Offset = CharUnits::Zero();
-
- if (Overriders) {
- // Get the final overrider.
- FinalOverriders::OverriderInfo Overrider =
- Overriders->getOverrider(MD, Base.getBaseOffset());
-
- /// The vcall offset is the offset from the virtual base to the object
- /// where the function was overridden.
- Offset = Overrider.Offset - VBaseOffset;
- }
-
- Components.push_back(
- VTableComponent::MakeVCallOffset(Offset));
- }
-
- // And iterate over all non-virtual bases (ignoring the primary base).
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
-
- if (I->isVirtual())
- continue;
-
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- if (BaseDecl == PrimaryBase)
- continue;
-
- // Get the base offset of this base.
- CharUnits BaseOffset = Base.getBaseOffset() +
- Layout.getBaseClassOffset(BaseDecl);
-
- AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset),
- VBaseOffset);
- }
-}
-
-void
-VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
- CharUnits OffsetInLayoutClass) {
- const ASTRecordLayout &LayoutClassLayout =
- Context.getASTRecordLayout(LayoutClass);
-
- // Add vbase offsets.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
- // Check if this is a virtual base that we haven't visited before.
- if (I->isVirtual() && VisitedVirtualBases.insert(BaseDecl)) {
- CharUnits Offset =
- LayoutClassLayout.getVBaseClassOffset(BaseDecl) - OffsetInLayoutClass;
-
- // Add the vbase offset offset.
- assert(!VBaseOffsetOffsets.count(BaseDecl) &&
- "vbase offset offset already exists!");
-
- CharUnits VBaseOffsetOffset = getCurrentOffsetOffset();
- VBaseOffsetOffsets.insert(
- std::make_pair(BaseDecl, VBaseOffsetOffset));
-
- Components.push_back(
- VTableComponent::MakeVBaseOffset(Offset));
- }
-
- // Check the base class looking for more vbase offsets.
- AddVBaseOffsets(BaseDecl, OffsetInLayoutClass);
- }
-}
-
-/// VTableBuilder - Class for building vtable layout information.
-class VTableBuilder {
-public:
- /// PrimaryBasesSetVectorTy - A set vector of direct and indirect
- /// primary bases.
- typedef llvm::SmallSetVector<const CXXRecordDecl *, 8>
- PrimaryBasesSetVectorTy;
-
- typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits>
- VBaseOffsetOffsetsMapTy;
-
- typedef llvm::DenseMap<BaseSubobject, uint64_t>
- AddressPointsMapTy;
-
-private:
- /// VTables - Global vtable information.
- CodeGenVTables &VTables;
-
- /// MostDerivedClass - The most derived class for which we're building this
- /// vtable.
- const CXXRecordDecl *MostDerivedClass;
-
- /// MostDerivedClassOffset - If we're building a construction vtable, this
- /// holds the offset from the layout class to the most derived class.
- const CharUnits MostDerivedClassOffset;
-
- /// MostDerivedClassIsVirtual - Whether the most derived class is a virtual
- /// base. (This only makes sense when building a construction vtable).
- bool MostDerivedClassIsVirtual;
-
- /// LayoutClass - The class we're using for layout information. Will be
- /// different than the most derived class if we're building a construction
- /// vtable.
- const CXXRecordDecl *LayoutClass;
-
- /// Context - The ASTContext which we will use for layout information.
- ASTContext &Context;
-
- /// FinalOverriders - The final overriders of the most derived class.
- const FinalOverriders Overriders;
-
- /// VCallOffsetsForVBases - Keeps track of vcall offsets for the virtual
- /// bases in this vtable.
- llvm::DenseMap<const CXXRecordDecl *, VCallOffsetMap> VCallOffsetsForVBases;
-
- /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets for
- /// the most derived class.
- VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
-
- /// Components - The components of the vtable being built.
- llvm::SmallVector<VTableComponent, 64> Components;
-
- /// AddressPoints - Address points for the vtable being built.
- AddressPointsMapTy AddressPoints;
-
- /// MethodInfo - Contains information about a method in a vtable.
- /// (Used for computing 'this' pointer adjustment thunks.
- struct MethodInfo {
- /// BaseOffset - The base offset of this method.
- const CharUnits BaseOffset;
-
- /// BaseOffsetInLayoutClass - The base offset in the layout class of this
- /// method.
- const CharUnits BaseOffsetInLayoutClass;
-
- /// VTableIndex - The index in the vtable that this method has.
- /// (For destructors, this is the index of the complete destructor).
- const uint64_t VTableIndex;
-
- MethodInfo(CharUnits BaseOffset, CharUnits BaseOffsetInLayoutClass,
- uint64_t VTableIndex)
- : BaseOffset(BaseOffset),
- BaseOffsetInLayoutClass(BaseOffsetInLayoutClass),
- VTableIndex(VTableIndex) { }
-
- MethodInfo()
- : BaseOffset(CharUnits::Zero()),
- BaseOffsetInLayoutClass(CharUnits::Zero()),
- VTableIndex(0) { }
- };
-
- typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
-
- /// MethodInfoMap - The information for all methods in the vtable we're
- /// currently building.
- MethodInfoMapTy MethodInfoMap;
-
- typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy;
-
- /// VTableThunks - The thunks by vtable index in the vtable currently being
- /// built.
- VTableThunksMapTy VTableThunks;
-
- typedef llvm::SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
- typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
-
- /// Thunks - A map that contains all the thunks needed for all methods in the
- /// most derived class for which the vtable is currently being built.
- ThunksMapTy Thunks;
-
- /// AddThunk - Add a thunk for the given method.
- void AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk);
-
- /// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the
- /// part of the vtable we're currently building.
- void ComputeThisAdjustments();
-
- typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
-
- /// PrimaryVirtualBases - All known virtual bases who are a primary base of
- /// some other base.
- VisitedVirtualBasesSetTy PrimaryVirtualBases;
-
- /// ComputeReturnAdjustment - Compute the return adjustment given a return
- /// adjustment base offset.
- ReturnAdjustment ComputeReturnAdjustment(BaseOffset Offset);
-
- /// ComputeThisAdjustmentBaseOffset - Compute the base offset for adjusting
- /// the 'this' pointer from the base subobject to the derived subobject.
- BaseOffset ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
- BaseSubobject Derived) const;
-
- /// ComputeThisAdjustment - Compute the 'this' pointer adjustment for the
- /// given virtual member function, its offset in the layout class and its
- /// final overrider.
- ThisAdjustment
- ComputeThisAdjustment(const CXXMethodDecl *MD,
- CharUnits BaseOffsetInLayoutClass,
- FinalOverriders::OverriderInfo Overrider);
-
- /// AddMethod - Add a single virtual member function to the vtable
- /// components vector.
- void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment);
-
- /// IsOverriderUsed - Returns whether the overrider will ever be used in this
- /// part of the vtable.
- ///
- /// Itanium C++ ABI 2.5.2:
- ///
- /// struct A { virtual void f(); };
- /// struct B : virtual public A { int i; };
- /// struct C : virtual public A { int j; };
- /// struct D : public B, public C {};
- ///
- /// When B and C are declared, A is a primary base in each case, so although
- /// vcall offsets are allocated in the A-in-B and A-in-C vtables, no this
- /// adjustment is required and no thunk is generated. However, inside D
- /// objects, A is no longer a primary base of C, so if we allowed calls to
- /// C::f() to use the copy of A's vtable in the C subobject, we would need
- /// to adjust this from C* to B::A*, which would require a third-party
- /// thunk. Since we require that a call to C::f() first convert to A*,
- /// C-in-D's copy of A's vtable is never referenced, so this is not
- /// necessary.
- bool IsOverriderUsed(const CXXMethodDecl *Overrider,
- CharUnits BaseOffsetInLayoutClass,
- const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
- CharUnits FirstBaseOffsetInLayoutClass) const;
-
-
- /// AddMethods - Add the methods of this base subobject and all its
- /// primary bases to the vtable components vector.
- void AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
- const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
- CharUnits FirstBaseOffsetInLayoutClass,
- PrimaryBasesSetVectorTy &PrimaryBases);
-
- // LayoutVTable - Layout the vtable for the given base class, including its
- // secondary vtables and any vtables for virtual bases.
- void LayoutVTable();
-
- /// LayoutPrimaryAndSecondaryVTables - Layout the primary vtable for the
- /// given base subobject, as well as all its secondary vtables.
- ///
- /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base
- /// or a direct or indirect base of a virtual base.
- ///
- /// \param BaseIsVirtualInLayoutClass - Whether the base subobject is virtual
- /// in the layout class.
- void LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
- bool BaseIsMorallyVirtual,
- bool BaseIsVirtualInLayoutClass,
- CharUnits OffsetInLayoutClass);
-
- /// LayoutSecondaryVTables - Layout the secondary vtables for the given base
- /// subobject.
- ///
- /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base
- /// or a direct or indirect base of a virtual base.
- void LayoutSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual,
- CharUnits OffsetInLayoutClass);
-
- /// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this
- /// class hierarchy.
- void DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
- CharUnits OffsetInLayoutClass,
- VisitedVirtualBasesSetTy &VBases);
-
- /// LayoutVTablesForVirtualBases - Layout vtables for all virtual bases of the
- /// given base (excluding any primary bases).
- void LayoutVTablesForVirtualBases(const CXXRecordDecl *RD,
- VisitedVirtualBasesSetTy &VBases);
-
- /// isBuildingConstructionVTable - Return whether this vtable builder is
- /// building a construction vtable.
- bool isBuildingConstructorVTable() const {
- return MostDerivedClass != LayoutClass;
- }
-
-public:
- VTableBuilder(CodeGenVTables &VTables, const CXXRecordDecl *MostDerivedClass,
- CharUnits MostDerivedClassOffset,
- bool MostDerivedClassIsVirtual, const
- CXXRecordDecl *LayoutClass)
- : VTables(VTables), MostDerivedClass(MostDerivedClass),
- MostDerivedClassOffset(MostDerivedClassOffset),
- MostDerivedClassIsVirtual(MostDerivedClassIsVirtual),
- LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()),
- Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) {
-
- LayoutVTable();
- }
-
- ThunksMapTy::const_iterator thunks_begin() const {
- return Thunks.begin();
- }
-
- ThunksMapTy::const_iterator thunks_end() const {
- return Thunks.end();
- }
-
- const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const {
- return VBaseOffsetOffsets;
- }
-
- /// getNumVTableComponents - Return the number of components in the vtable
- /// currently built.
- uint64_t getNumVTableComponents() const {
- return Components.size();
- }
-
- const uint64_t *vtable_components_data_begin() const {
- return reinterpret_cast<const uint64_t *>(Components.begin());
- }
-
- const uint64_t *vtable_components_data_end() const {
- return reinterpret_cast<const uint64_t *>(Components.end());
- }
-
- AddressPointsMapTy::const_iterator address_points_begin() const {
- return AddressPoints.begin();
- }
-
- AddressPointsMapTy::const_iterator address_points_end() const {
- return AddressPoints.end();
- }
-
- VTableThunksMapTy::const_iterator vtable_thunks_begin() const {
- return VTableThunks.begin();
- }
-
- VTableThunksMapTy::const_iterator vtable_thunks_end() const {
- return VTableThunks.end();
- }
-
- /// dumpLayout - Dump the vtable layout.
- void dumpLayout(llvm::raw_ostream&);
-};
-
-void VTableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) {
- assert(!isBuildingConstructorVTable() &&
- "Can't add thunks for construction vtable");
-
- llvm::SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD];
-
- // Check if we have this thunk already.
- if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) !=
- ThunksVector.end())
- return;
-
- ThunksVector.push_back(Thunk);
-}
-
-typedef llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverriddenMethodsSetTy;
-
-/// ComputeAllOverriddenMethods - Given a method decl, will return a set of all
-/// the overridden methods that the function decl overrides.
-static void
-ComputeAllOverriddenMethods(const CXXMethodDecl *MD,
- OverriddenMethodsSetTy& OverriddenMethods) {
- assert(MD->isVirtual() && "Method is not virtual!");
-
- for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
- E = MD->end_overridden_methods(); I != E; ++I) {
- const CXXMethodDecl *OverriddenMD = *I;
-
- OverriddenMethods.insert(OverriddenMD);
-
- ComputeAllOverriddenMethods(OverriddenMD, OverriddenMethods);
- }
-}
-
-void VTableBuilder::ComputeThisAdjustments() {
- // Now go through the method info map and see if any of the methods need
- // 'this' pointer adjustments.
- for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(),
- E = MethodInfoMap.end(); I != E; ++I) {
- const CXXMethodDecl *MD = I->first;
- const MethodInfo &MethodInfo = I->second;
-
- // Ignore adjustments for unused function pointers.
- uint64_t VTableIndex = MethodInfo.VTableIndex;
- if (Components[VTableIndex].getKind() ==
- VTableComponent::CK_UnusedFunctionPointer)
- continue;
-
- // Get the final overrider for this method.
- FinalOverriders::OverriderInfo Overrider =
- Overriders.getOverrider(MD, MethodInfo.BaseOffset);
-
- // Check if we need an adjustment at all.
- if (MethodInfo.BaseOffsetInLayoutClass == Overrider.Offset) {
- // When a return thunk is needed by a derived class that overrides a
- // virtual base, gcc uses a virtual 'this' adjustment as well.
- // While the thunk itself might be needed by vtables in subclasses or
- // in construction vtables, there doesn't seem to be a reason for using
- // the thunk in this vtable. Still, we do so to match gcc.
- if (VTableThunks.lookup(VTableIndex).Return.isEmpty())
- continue;
- }
-
- ThisAdjustment ThisAdjustment =
- ComputeThisAdjustment(MD, MethodInfo.BaseOffsetInLayoutClass, Overrider);
-
- if (ThisAdjustment.isEmpty())
- continue;
-
- // Add it.
- VTableThunks[VTableIndex].This = ThisAdjustment;
-
- if (isa<CXXDestructorDecl>(MD)) {
- // Add an adjustment for the deleting destructor as well.
- VTableThunks[VTableIndex + 1].This = ThisAdjustment;
- }
- }
-
- /// Clear the method info map.
- MethodInfoMap.clear();
-
- if (isBuildingConstructorVTable()) {
- // We don't need to store thunk information for construction vtables.
- return;
- }
-
- for (VTableThunksMapTy::const_iterator I = VTableThunks.begin(),
- E = VTableThunks.end(); I != E; ++I) {
- const VTableComponent &Component = Components[I->first];
- const ThunkInfo &Thunk = I->second;
- const CXXMethodDecl *MD;
-
- switch (Component.getKind()) {
- default:
- llvm_unreachable("Unexpected vtable component kind!");
- case VTableComponent::CK_FunctionPointer:
- MD = Component.getFunctionDecl();
- break;
- case VTableComponent::CK_CompleteDtorPointer:
- MD = Component.getDestructorDecl();
- break;
- case VTableComponent::CK_DeletingDtorPointer:
- // We've already added the thunk when we saw the complete dtor pointer.
- continue;
- }
-
- if (MD->getParent() == MostDerivedClass)
- AddThunk(MD, Thunk);
- }
-}
-
-ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
- ReturnAdjustment Adjustment;
-
- if (!Offset.isEmpty()) {
- if (Offset.VirtualBase) {
- // Get the virtual base offset offset.
- if (Offset.DerivedClass == MostDerivedClass) {
- // We can get the offset offset directly from our map.
- Adjustment.VBaseOffsetOffset =
- VBaseOffsetOffsets.lookup(Offset.VirtualBase).getQuantity();
- } else {
- Adjustment.VBaseOffsetOffset =
- VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass,
- Offset.VirtualBase).getQuantity();
- }
- }
-
- Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity();
- }
-
- return Adjustment;
-}
-
-BaseOffset
-VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
- BaseSubobject Derived) const {
- const CXXRecordDecl *BaseRD = Base.getBase();
- const CXXRecordDecl *DerivedRD = Derived.getBase();
-
- CXXBasePaths Paths(/*FindAmbiguities=*/true,
- /*RecordPaths=*/true, /*DetectVirtual=*/true);
-
- if (!const_cast<CXXRecordDecl *>(DerivedRD)->
- isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) {
- assert(false && "Class must be derived from the passed in base class!");
- return BaseOffset();
- }
-
- // We have to go through all the paths, and see which one leads us to the
- // right base subobject.
- for (CXXBasePaths::const_paths_iterator I = Paths.begin(), E = Paths.end();
- I != E; ++I) {
- BaseOffset Offset = ComputeBaseOffset(Context, DerivedRD, *I);
-
- CharUnits OffsetToBaseSubobject = Offset.NonVirtualOffset;
-
- if (Offset.VirtualBase) {
- // If we have a virtual base class, the non-virtual offset is relative
- // to the virtual base class offset.
- const ASTRecordLayout &LayoutClassLayout =
- Context.getASTRecordLayout(LayoutClass);
-
- /// Get the virtual base offset, relative to the most derived class
- /// layout.
- OffsetToBaseSubobject +=
- LayoutClassLayout.getVBaseClassOffset(Offset.VirtualBase);
- } else {
- // Otherwise, the non-virtual offset is relative to the derived class
- // offset.
- OffsetToBaseSubobject += Derived.getBaseOffset();
- }
-
- // Check if this path gives us the right base subobject.
- if (OffsetToBaseSubobject == Base.getBaseOffset()) {
- // Since we're going from the base class _to_ the derived class, we'll
- // invert the non-virtual offset here.
- Offset.NonVirtualOffset = -Offset.NonVirtualOffset;
- return Offset;
- }
- }
-
- return BaseOffset();
-}
-
-ThisAdjustment
-VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
- CharUnits BaseOffsetInLayoutClass,
- FinalOverriders::OverriderInfo Overrider) {
- // Ignore adjustments for pure virtual member functions.
- if (Overrider.Method->isPure())
- return ThisAdjustment();
-
- BaseSubobject OverriddenBaseSubobject(MD->getParent(),
- BaseOffsetInLayoutClass);
-
- BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(),
- Overrider.Offset);
-
- // Compute the adjustment offset.
- BaseOffset Offset = ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject,
- OverriderBaseSubobject);
- if (Offset.isEmpty())
- return ThisAdjustment();
-
- ThisAdjustment Adjustment;
-
- if (Offset.VirtualBase) {
- // Get the vcall offset map for this virtual base.
- VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase];
-
- if (VCallOffsets.empty()) {
- // We don't have vcall offsets for this virtual base, go ahead and
- // build them.
- VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, MostDerivedClass,
- /*FinalOverriders=*/0,
- BaseSubobject(Offset.VirtualBase,
- CharUnits::Zero()),
- /*BaseIsVirtual=*/true,
- /*OffsetInLayoutClass=*/
- CharUnits::Zero());
-
- VCallOffsets = Builder.getVCallOffsets();
- }
-
- Adjustment.VCallOffsetOffset =
- VCallOffsets.getVCallOffsetOffset(MD).getQuantity();
- }
-
- // Set the non-virtual part of the adjustment.
- Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity();
-
- return Adjustment;
-}
-
-void
-VTableBuilder::AddMethod(const CXXMethodDecl *MD,
- ReturnAdjustment ReturnAdjustment) {
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(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));
- } else {
- // Add the return adjustment if necessary.
- if (!ReturnAdjustment.isEmpty())
- VTableThunks[Components.size()].Return = ReturnAdjustment;
-
- // Add the function.
- Components.push_back(VTableComponent::MakeFunction(MD));
- }
-}
-
-/// OverridesIndirectMethodInBase - Return whether the given member function
-/// overrides any methods in the set of given bases.
-/// Unlike OverridesMethodInBase, this checks "overriders of overriders".
-/// For example, if we have:
-///
-/// struct A { virtual void f(); }
-/// struct B : A { virtual void f(); }
-/// struct C : B { virtual void f(); }
-///
-/// OverridesIndirectMethodInBase will return true if given C::f as the method
-/// and { A } as the set of bases.
-static bool
-OverridesIndirectMethodInBases(const CXXMethodDecl *MD,
- VTableBuilder::PrimaryBasesSetVectorTy &Bases) {
- if (Bases.count(MD->getParent()))
- return true;
-
- for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
- E = MD->end_overridden_methods(); I != E; ++I) {
- const CXXMethodDecl *OverriddenMD = *I;
-
- // Check "indirect overriders".
- if (OverridesIndirectMethodInBases(OverriddenMD, Bases))
- return true;
- }
-
- return false;
-}
-
-bool
-VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider,
- CharUnits BaseOffsetInLayoutClass,
- const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
- CharUnits FirstBaseOffsetInLayoutClass) const {
- // If the base and the first base in the primary base chain have the same
- // offsets, then this overrider will be used.
- if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass)
- return true;
-
- // We know now that Base (or a direct or indirect base of it) is a primary
- // base in part of the class hierarchy, but not a primary base in the most
- // derived class.
-
- // If the overrider is the first base in the primary base chain, we know
- // that the overrider will be used.
- if (Overrider->getParent() == FirstBaseInPrimaryBaseChain)
- return true;
-
- VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
-
- const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain;
- PrimaryBases.insert(RD);
-
- // Now traverse the base chain, starting with the first base, until we find
- // the base that is no longer a primary base.
- while (true) {
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
-
- if (!PrimaryBase)
- break;
-
- if (Layout.isPrimaryBaseVirtual()) {
- assert(Layout.getVBaseClassOffsetInBits(PrimaryBase) == 0 &&
- "Primary base should always be at offset 0!");
-
- const ASTRecordLayout &LayoutClassLayout =
- Context.getASTRecordLayout(LayoutClass);
-
- // Now check if this is the primary base that is not a primary base in the
- // most derived class.
- if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) !=
- FirstBaseOffsetInLayoutClass) {
- // We found it, stop walking the chain.
- break;
- }
- } else {
- assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 &&
- "Primary base should always be at offset 0!");
- }
-
- if (!PrimaryBases.insert(PrimaryBase))
- assert(false && "Found a duplicate primary base!");
-
- RD = PrimaryBase;
- }
-
- // If the final overrider is an override of one of the primary bases,
- // then we know that it will be used.
- return OverridesIndirectMethodInBases(Overrider, PrimaryBases);
-}
-
-/// FindNearestOverriddenMethod - Given a method, returns the overridden method
-/// from the nearest base. Returns null if no method was found.
-static const CXXMethodDecl *
-FindNearestOverriddenMethod(const CXXMethodDecl *MD,
- VTableBuilder::PrimaryBasesSetVectorTy &Bases) {
- OverriddenMethodsSetTy OverriddenMethods;
- ComputeAllOverriddenMethods(MD, OverriddenMethods);
-
- for (int I = Bases.size(), E = 0; I != E; --I) {
- const CXXRecordDecl *PrimaryBase = Bases[I - 1];
-
- // Now check the overriden methods.
- for (OverriddenMethodsSetTy::const_iterator I = OverriddenMethods.begin(),
- E = OverriddenMethods.end(); I != E; ++I) {
- const CXXMethodDecl *OverriddenMD = *I;
-
- // We found our overridden method.
- if (OverriddenMD->getParent() == PrimaryBase)
- return OverriddenMD;
- }
- }
-
- return 0;
-}
-
-void
-VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
- const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
- CharUnits FirstBaseOffsetInLayoutClass,
- PrimaryBasesSetVectorTy &PrimaryBases) {
- const CXXRecordDecl *RD = Base.getBase();
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
-
- if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
- CharUnits PrimaryBaseOffset;
- CharUnits PrimaryBaseOffsetInLayoutClass;
- if (Layout.isPrimaryBaseVirtual()) {
- assert(Layout.getVBaseClassOffsetInBits(PrimaryBase) == 0 &&
- "Primary vbase should have a zero offset!");
-
- const ASTRecordLayout &MostDerivedClassLayout =
- Context.getASTRecordLayout(MostDerivedClass);
-
- PrimaryBaseOffset =
- MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase);
-
- const ASTRecordLayout &LayoutClassLayout =
- Context.getASTRecordLayout(LayoutClass);
-
- PrimaryBaseOffsetInLayoutClass =
- LayoutClassLayout.getVBaseClassOffset(PrimaryBase);
- } else {
- assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 &&
- "Primary base should have a zero offset!");
-
- PrimaryBaseOffset = Base.getBaseOffset();
- PrimaryBaseOffsetInLayoutClass = BaseOffsetInLayoutClass;
- }
-
- AddMethods(BaseSubobject(PrimaryBase, PrimaryBaseOffset),
- PrimaryBaseOffsetInLayoutClass, FirstBaseInPrimaryBaseChain,
- FirstBaseOffsetInLayoutClass, PrimaryBases);
-
- if (!PrimaryBases.insert(PrimaryBase))
- assert(false && "Found a duplicate primary base!");
- }
-
- // Now go through all virtual member functions and add them.
- for (CXXRecordDecl::method_iterator I = RD->method_begin(),
- E = RD->method_end(); I != E; ++I) {
- const CXXMethodDecl *MD = *I;
-
- if (!MD->isVirtual())
- continue;
-
- // Get the final overrider.
- FinalOverriders::OverriderInfo Overrider =
- Overriders.getOverrider(MD, Base.getBaseOffset());
-
- // Check if this virtual member function overrides a method in a primary
- // base. If this is the case, and the return type doesn't require adjustment
- // then we can just use the member function from the primary base.
- if (const CXXMethodDecl *OverriddenMD =
- FindNearestOverriddenMethod(MD, PrimaryBases)) {
- if (ComputeReturnAdjustmentBaseOffset(Context, MD,
- OverriddenMD).isEmpty()) {
- // Replace the method info of the overridden method with our own
- // method.
- assert(MethodInfoMap.count(OverriddenMD) &&
- "Did not find the overridden method!");
- MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD];
-
- MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass,
- OverriddenMethodInfo.VTableIndex);
-
- assert(!MethodInfoMap.count(MD) &&
- "Should not have method info for this method yet!");
-
- MethodInfoMap.insert(std::make_pair(MD, MethodInfo));
- MethodInfoMap.erase(OverriddenMD);
-
- // If the overridden method exists in a virtual base class or a direct
- // or indirect base class of a virtual base class, we need to emit a
- // thunk if we ever have a class hierarchy where the base class is not
- // a primary base in the complete object.
- if (!isBuildingConstructorVTable() && OverriddenMD != MD) {
- // Compute the this adjustment.
- ThisAdjustment ThisAdjustment =
- ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass,
- Overrider);
-
- if (ThisAdjustment.VCallOffsetOffset &&
- Overrider.Method->getParent() == MostDerivedClass) {
-
- // There's no return adjustment from OverriddenMD and MD,
- // but that doesn't mean there isn't one between MD and
- // the final overrider.
- BaseOffset ReturnAdjustmentOffset =
- ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD);
- ReturnAdjustment ReturnAdjustment =
- ComputeReturnAdjustment(ReturnAdjustmentOffset);
-
- // This is a virtual thunk for the most derived class, add it.
- AddThunk(Overrider.Method,
- ThunkInfo(ThisAdjustment, ReturnAdjustment));
- }
- }
-
- continue;
- }
- }
-
- // Insert the method info for this method.
- MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass,
- Components.size());
-
- assert(!MethodInfoMap.count(MD) &&
- "Should not have method info for this method yet!");
- MethodInfoMap.insert(std::make_pair(MD, MethodInfo));
-
- // Check if this overrider is going to be used.
- const CXXMethodDecl *OverriderMD = Overrider.Method;
- if (!IsOverriderUsed(OverriderMD, BaseOffsetInLayoutClass,
- FirstBaseInPrimaryBaseChain,
- FirstBaseOffsetInLayoutClass)) {
- Components.push_back(VTableComponent::MakeUnusedFunction(OverriderMD));
- continue;
- }
-
- // Check if this overrider needs a return adjustment.
- // We don't want to do this for pure virtual member functions.
- BaseOffset ReturnAdjustmentOffset;
- if (!OverriderMD->isPure()) {
- ReturnAdjustmentOffset =
- ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD);
- }
-
- ReturnAdjustment ReturnAdjustment =
- ComputeReturnAdjustment(ReturnAdjustmentOffset);
-
- AddMethod(Overrider.Method, ReturnAdjustment);
- }
-}
-
-void VTableBuilder::LayoutVTable() {
- LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass,
- CharUnits::Zero()),
- /*BaseIsMorallyVirtual=*/false,
- MostDerivedClassIsVirtual,
- MostDerivedClassOffset);
-
- VisitedVirtualBasesSetTy VBases;
-
- // Determine the primary virtual bases.
- DeterminePrimaryVirtualBases(MostDerivedClass, MostDerivedClassOffset,
- VBases);
- VBases.clear();
-
- LayoutVTablesForVirtualBases(MostDerivedClass, VBases);
-}
-
-void
-VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
- bool BaseIsMorallyVirtual,
- bool BaseIsVirtualInLayoutClass,
- CharUnits OffsetInLayoutClass) {
- assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!");
-
- // Add vcall and vbase offsets for this vtable.
- VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, LayoutClass, &Overriders,
- Base, BaseIsVirtualInLayoutClass,
- OffsetInLayoutClass);
- Components.append(Builder.components_begin(), Builder.components_end());
-
- // Check if we need to add these vcall offsets.
- if (BaseIsVirtualInLayoutClass && !Builder.getVCallOffsets().empty()) {
- VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Base.getBase()];
-
- if (VCallOffsets.empty())
- VCallOffsets = Builder.getVCallOffsets();
- }
-
- // If we're laying out the most derived class we want to keep track of the
- // virtual base class offset offsets.
- 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));
-
- uint64_t AddressPoint = Components.size();
-
- // Now go through all virtual member functions and add them.
- PrimaryBasesSetVectorTy PrimaryBases;
- AddMethods(Base, OffsetInLayoutClass,
- Base.getBase(), OffsetInLayoutClass,
- PrimaryBases);
-
- // Compute 'this' pointer adjustments.
- ComputeThisAdjustments();
-
- // Add all address points.
- const CXXRecordDecl *RD = Base.getBase();
- while (true) {
- AddressPoints.insert(std::make_pair(
- BaseSubobject(RD, OffsetInLayoutClass),
- AddressPoint));
-
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
-
- if (!PrimaryBase)
- break;
-
- if (Layout.isPrimaryBaseVirtual()) {
- // Check if this virtual primary base is a primary base in the layout
- // class. If it's not, we don't want to add it.
- const ASTRecordLayout &LayoutClassLayout =
- Context.getASTRecordLayout(LayoutClass);
-
- if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) !=
- OffsetInLayoutClass) {
- // We don't want to add this class (or any of its primary bases).
- break;
- }
- }
-
- RD = PrimaryBase;
- }
-
- // Layout secondary vtables.
- LayoutSecondaryVTables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass);
-}
-
-void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base,
- bool BaseIsMorallyVirtual,
- CharUnits OffsetInLayoutClass) {
- // Itanium C++ ABI 2.5.2:
- // Following the primary virtual table of a derived class are secondary
- // virtual tables for each of its proper base classes, except any primary
- // base(s) with which it shares its primary virtual table.
-
- const CXXRecordDecl *RD = Base.getBase();
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
-
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- // Ignore virtual bases, we'll emit them later.
- if (I->isVirtual())
- continue;
-
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
- // Ignore bases that don't have a vtable.
- if (!BaseDecl->isDynamicClass())
- continue;
-
- if (isBuildingConstructorVTable()) {
- // Itanium C++ ABI 2.6.4:
- // Some of the base class subobjects may not need construction virtual
- // tables, which will therefore not be present in the construction
- // virtual table group, even though the subobject virtual tables are
- // present in the main virtual table group for the complete object.
- if (!BaseIsMorallyVirtual && !BaseDecl->getNumVBases())
- continue;
- }
-
- // Get the base offset of this base.
- CharUnits RelativeBaseOffset = Layout.getBaseClassOffset(BaseDecl);
- CharUnits BaseOffset = Base.getBaseOffset() + RelativeBaseOffset;
-
- CharUnits BaseOffsetInLayoutClass =
- OffsetInLayoutClass + RelativeBaseOffset;
-
- // Don't emit a secondary vtable for a primary base. We might however want
- // to emit secondary vtables for other bases of this base.
- if (BaseDecl == PrimaryBase) {
- LayoutSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset),
- BaseIsMorallyVirtual, BaseOffsetInLayoutClass);
- continue;
- }
-
- // Layout the primary vtable (and any secondary vtables) for this base.
- LayoutPrimaryAndSecondaryVTables(
- BaseSubobject(BaseDecl, BaseOffset),
- BaseIsMorallyVirtual,
- /*BaseIsVirtualInLayoutClass=*/false,
- BaseOffsetInLayoutClass);
- }
-}
-
-void
-VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
- CharUnits OffsetInLayoutClass,
- VisitedVirtualBasesSetTy &VBases) {
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
-
- // Check if this base has a primary base.
- if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
-
- // Check if it's virtual.
- if (Layout.isPrimaryBaseVirtual()) {
- bool IsPrimaryVirtualBase = true;
-
- if (isBuildingConstructorVTable()) {
- // Check if the base is actually a primary base in the class we use for
- // layout.
- const ASTRecordLayout &LayoutClassLayout =
- Context.getASTRecordLayout(LayoutClass);
-
- CharUnits PrimaryBaseOffsetInLayoutClass =
- LayoutClassLayout.getVBaseClassOffset(PrimaryBase);
-
- // We know that the base is not a primary base in the layout class if
- // the base offsets are different.
- if (PrimaryBaseOffsetInLayoutClass != OffsetInLayoutClass)
- IsPrimaryVirtualBase = false;
- }
-
- if (IsPrimaryVirtualBase)
- PrimaryVirtualBases.insert(PrimaryBase);
- }
- }
-
- // Traverse bases, looking for more primary virtual bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
- CharUnits BaseOffsetInLayoutClass;
-
- if (I->isVirtual()) {
- if (!VBases.insert(BaseDecl))
- continue;
-
- const ASTRecordLayout &LayoutClassLayout =
- Context.getASTRecordLayout(LayoutClass);
-
- BaseOffsetInLayoutClass =
- LayoutClassLayout.getVBaseClassOffset(BaseDecl);
- } else {
- BaseOffsetInLayoutClass =
- OffsetInLayoutClass + Layout.getBaseClassOffset(BaseDecl);
- }
-
- DeterminePrimaryVirtualBases(BaseDecl, BaseOffsetInLayoutClass, VBases);
- }
-}
-
-void
-VTableBuilder::LayoutVTablesForVirtualBases(const CXXRecordDecl *RD,
- VisitedVirtualBasesSetTy &VBases) {
- // Itanium C++ ABI 2.5.2:
- // Then come the virtual base virtual tables, also in inheritance graph
- // order, and again excluding primary bases (which share virtual tables with
- // the classes for which they are primary).
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
- // Check if this base needs a vtable. (If it's virtual, not a primary base
- // of some other class, and we haven't visited it before).
- if (I->isVirtual() && BaseDecl->isDynamicClass() &&
- !PrimaryVirtualBases.count(BaseDecl) && VBases.insert(BaseDecl)) {
- const ASTRecordLayout &MostDerivedClassLayout =
- Context.getASTRecordLayout(MostDerivedClass);
- CharUnits BaseOffset =
- MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
-
- const ASTRecordLayout &LayoutClassLayout =
- Context.getASTRecordLayout(LayoutClass);
- CharUnits BaseOffsetInLayoutClass =
- LayoutClassLayout.getVBaseClassOffset(BaseDecl);
-
- LayoutPrimaryAndSecondaryVTables(
- BaseSubobject(BaseDecl, BaseOffset),
- /*BaseIsMorallyVirtual=*/true,
- /*BaseIsVirtualInLayoutClass=*/true,
- BaseOffsetInLayoutClass);
- }
-
- // We only need to check the base for virtual base vtables if it actually
- // has virtual bases.
- if (BaseDecl->getNumVBases())
- LayoutVTablesForVirtualBases(BaseDecl, VBases);
- }
-}
-
-/// dumpLayout - Dump the vtable layout.
-void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) {
-
- if (isBuildingConstructorVTable()) {
- Out << "Construction vtable for ('";
- Out << MostDerivedClass->getQualifiedNameAsString() << "', ";
- Out << MostDerivedClassOffset.getQuantity() << ") in '";
- Out << LayoutClass->getQualifiedNameAsString();
- } else {
- Out << "Vtable for '";
- Out << MostDerivedClass->getQualifiedNameAsString();
- }
- Out << "' (" << Components.size() << " entries).\n";
-
- // Iterate through the address points and insert them into a new map where
- // they are keyed by the index and not the base object.
- // Since an address point can be shared by multiple subobjects, we use an
- // STL multimap.
- std::multimap<uint64_t, BaseSubobject> AddressPointsByIndex;
- for (AddressPointsMapTy::const_iterator I = AddressPoints.begin(),
- E = AddressPoints.end(); I != E; ++I) {
- const BaseSubobject& Base = I->first;
- uint64_t Index = I->second;
-
- AddressPointsByIndex.insert(std::make_pair(Index, Base));
- }
-
- for (unsigned I = 0, E = Components.size(); I != E; ++I) {
- uint64_t Index = I;
-
- Out << llvm::format("%4d | ", I);
-
- const VTableComponent &Component = Components[I];
-
- // Dump the component.
- switch (Component.getKind()) {
-
- case VTableComponent::CK_VCallOffset:
- Out << "vcall_offset ("
- << Component.getVCallOffset().getQuantity()
- << ")";
- break;
-
- case VTableComponent::CK_VBaseOffset:
- Out << "vbase_offset ("
- << Component.getVBaseOffset().getQuantity()
- << ")";
- break;
-
- case VTableComponent::CK_OffsetToTop:
- Out << "offset_to_top ("
- << Component.getOffsetToTop().getQuantity()
- << ")";
- break;
-
- case VTableComponent::CK_RTTI:
- Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI";
- break;
-
- case VTableComponent::CK_FunctionPointer: {
- const CXXMethodDecl *MD = Component.getFunctionDecl();
-
- std::string Str =
- PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual,
- MD);
- Out << Str;
- if (MD->isPure())
- Out << " [pure]";
-
- ThunkInfo Thunk = VTableThunks.lookup(I);
- if (!Thunk.isEmpty()) {
- // If this function pointer has a return adjustment, dump it.
- if (!Thunk.Return.isEmpty()) {
- Out << "\n [return adjustment: ";
- Out << Thunk.Return.NonVirtual << " non-virtual";
-
- if (Thunk.Return.VBaseOffsetOffset) {
- Out << ", " << Thunk.Return.VBaseOffsetOffset;
- Out << " vbase offset offset";
- }
-
- Out << ']';
- }
-
- // If this function pointer has a 'this' pointer adjustment, dump it.
- if (!Thunk.This.isEmpty()) {
- Out << "\n [this adjustment: ";
- Out << Thunk.This.NonVirtual << " non-virtual";
-
- if (Thunk.This.VCallOffsetOffset) {
- Out << ", " << Thunk.This.VCallOffsetOffset;
- Out << " vcall offset offset";
- }
-
- Out << ']';
- }
- }
-
- break;
- }
-
- case VTableComponent::CK_CompleteDtorPointer:
- case VTableComponent::CK_DeletingDtorPointer: {
- bool IsComplete =
- Component.getKind() == VTableComponent::CK_CompleteDtorPointer;
-
- const CXXDestructorDecl *DD = Component.getDestructorDecl();
-
- Out << DD->getQualifiedNameAsString();
- if (IsComplete)
- Out << "() [complete]";
- else
- Out << "() [deleting]";
-
- if (DD->isPure())
- Out << " [pure]";
-
- ThunkInfo Thunk = VTableThunks.lookup(I);
- if (!Thunk.isEmpty()) {
- // If this destructor has a 'this' pointer adjustment, dump it.
- if (!Thunk.This.isEmpty()) {
- Out << "\n [this adjustment: ";
- Out << Thunk.This.NonVirtual << " non-virtual";
-
- if (Thunk.This.VCallOffsetOffset) {
- Out << ", " << Thunk.This.VCallOffsetOffset;
- Out << " vcall offset offset";
- }
-
- Out << ']';
- }
- }
-
- break;
- }
-
- case VTableComponent::CK_UnusedFunctionPointer: {
- const CXXMethodDecl *MD = Component.getUnusedFunctionDecl();
-
- std::string Str =
- PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual,
- MD);
- Out << "[unused] " << Str;
- if (MD->isPure())
- Out << " [pure]";
- }
-
- }
-
- Out << '\n';
-
- // Dump the next address point.
- uint64_t NextIndex = Index + 1;
- if (AddressPointsByIndex.count(NextIndex)) {
- if (AddressPointsByIndex.count(NextIndex) == 1) {
- const BaseSubobject &Base =
- AddressPointsByIndex.find(NextIndex)->second;
-
- Out << " -- (" << Base.getBase()->getQualifiedNameAsString();
- Out << ", " << Base.getBaseOffset().getQuantity();
- Out << ") vtable address --\n";
- } else {
- CharUnits BaseOffset =
- AddressPointsByIndex.lower_bound(NextIndex)->second.getBaseOffset();
-
- // We store the class names in a set to get a stable order.
- std::set<std::string> ClassNames;
- for (std::multimap<uint64_t, BaseSubobject>::const_iterator I =
- AddressPointsByIndex.lower_bound(NextIndex), E =
- AddressPointsByIndex.upper_bound(NextIndex); I != E; ++I) {
- assert(I->second.getBaseOffset() == BaseOffset &&
- "Invalid base offset!");
- const CXXRecordDecl *RD = I->second.getBase();
- ClassNames.insert(RD->getQualifiedNameAsString());
- }
-
- for (std::set<std::string>::const_iterator I = ClassNames.begin(),
- E = ClassNames.end(); I != E; ++I) {
- Out << " -- (" << *I;
- Out << ", " << BaseOffset.getQuantity() << ") vtable address --\n";
- }
- }
- }
- }
-
- Out << '\n';
-
- if (isBuildingConstructorVTable())
- return;
-
- if (MostDerivedClass->getNumVBases()) {
- // We store the virtual base class names and their offsets in a map to get
- // a stable order.
-
- std::map<std::string, CharUnits> ClassNamesAndOffsets;
- for (VBaseOffsetOffsetsMapTy::const_iterator I = VBaseOffsetOffsets.begin(),
- E = VBaseOffsetOffsets.end(); I != E; ++I) {
- std::string ClassName = I->first->getQualifiedNameAsString();
- CharUnits OffsetOffset = I->second;
- ClassNamesAndOffsets.insert(
- std::make_pair(ClassName, OffsetOffset));
- }
-
- Out << "Virtual base offset offsets for '";
- Out << MostDerivedClass->getQualifiedNameAsString() << "' (";
- Out << ClassNamesAndOffsets.size();
- Out << (ClassNamesAndOffsets.size() == 1 ? " entry" : " entries") << ").\n";
-
- for (std::map<std::string, CharUnits>::const_iterator I =
- ClassNamesAndOffsets.begin(), E = ClassNamesAndOffsets.end();
- I != E; ++I)
- Out << " " << I->first << " | " << I->second.getQuantity() << '\n';
-
- Out << "\n";
- }
-
- if (!Thunks.empty()) {
- // We store the method names in a map to get a stable order.
- std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls;
-
- for (ThunksMapTy::const_iterator I = Thunks.begin(), E = Thunks.end();
- I != E; ++I) {
- const CXXMethodDecl *MD = I->first;
- std::string MethodName =
- PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual,
- MD);
-
- MethodNamesAndDecls.insert(std::make_pair(MethodName, MD));
- }
-
- for (std::map<std::string, const CXXMethodDecl *>::const_iterator I =
- MethodNamesAndDecls.begin(), E = MethodNamesAndDecls.end();
- I != E; ++I) {
- const std::string &MethodName = I->first;
- const CXXMethodDecl *MD = I->second;
-
- ThunkInfoVectorTy ThunksVector = Thunks[MD];
- std::sort(ThunksVector.begin(), ThunksVector.end());
-
- Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
- Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
-
- for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) {
- const ThunkInfo &Thunk = ThunksVector[I];
-
- Out << llvm::format("%4d | ", I);
-
- // If this function pointer has a return pointer adjustment, dump it.
- if (!Thunk.Return.isEmpty()) {
- Out << "return adjustment: " << Thunk.This.NonVirtual;
- Out << " non-virtual";
- if (Thunk.Return.VBaseOffsetOffset) {
- Out << ", " << Thunk.Return.VBaseOffsetOffset;
- Out << " vbase offset offset";
- }
-
- if (!Thunk.This.isEmpty())
- Out << "\n ";
- }
-
- // If this function pointer has a 'this' pointer adjustment, dump it.
- if (!Thunk.This.isEmpty()) {
- Out << "this adjustment: ";
- Out << Thunk.This.NonVirtual << " non-virtual";
-
- if (Thunk.This.VCallOffsetOffset) {
- Out << ", " << Thunk.This.VCallOffsetOffset;
- Out << " vcall offset offset";
- }
- }
-
- Out << '\n';
- }
-
- Out << '\n';
- }
- }
-
- // Compute the vtable indices for all the member functions.
- // Store them in a map keyed by the index so we'll get a sorted table.
- std::map<uint64_t, std::string> IndicesMap;
-
- for (CXXRecordDecl::method_iterator i = MostDerivedClass->method_begin(),
- e = MostDerivedClass->method_end(); i != e; ++i) {
- const CXXMethodDecl *MD = *i;
-
- // We only want virtual member functions.
- if (!MD->isVirtual())
- continue;
-
- std::string MethodName =
- PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual,
- 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]";
- } else {
- IndicesMap[VTables.getMethodVTableIndex(MD)] = MethodName;
- }
- }
-
- // Print the vtable indices for all the member functions.
- if (!IndicesMap.empty()) {
- Out << "VTable indices for '";
- Out << MostDerivedClass->getQualifiedNameAsString();
- Out << "' (" << IndicesMap.size() << " entries).\n";
-
- for (std::map<uint64_t, std::string>::const_iterator I = IndicesMap.begin(),
- E = IndicesMap.end(); I != E; ++I) {
- uint64_t VTableIndex = I->first;
- const std::string &MethodName = I->second;
-
- Out << llvm::format(" %4u | ", VTableIndex) << MethodName << '\n';
- }
- }
-
- Out << '\n';
-}
-
-}
-
-static void
-CollectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context,
- VTableBuilder::PrimaryBasesSetVectorTy &PrimaryBases) {
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
-
- if (!PrimaryBase)
- return;
-
- CollectPrimaryBases(PrimaryBase, Context, PrimaryBases);
-
- if (!PrimaryBases.insert(PrimaryBase))
- assert(false && "Found a duplicate primary base!");
-}
-
-void CodeGenVTables::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
-
- // Itanium C++ ABI 2.5.2:
- // The order of the virtual function pointers in a virtual table is the
- // order of declaration of the corresponding member functions in the class.
- //
- // There is an entry for any virtual function declared in a class,
- // whether it is a new function or overrides a base class function,
- // unless it overrides a function from the primary base, and conversion
- // between their return types does not require an adjustment.
-
- int64_t CurrentIndex = 0;
-
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
-
- if (PrimaryBase) {
- assert(PrimaryBase->isDefinition() &&
- "Should have the definition decl of the primary base!");
-
- // Since the record decl shares its vtable pointer with the primary base
- // we need to start counting at the end of the primary base's vtable.
- CurrentIndex = getNumVirtualFunctionPointers(PrimaryBase);
- }
-
- // Collect all the primary bases, so we can check whether methods override
- // a method from the base.
- VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
- CollectPrimaryBases(RD, CGM.getContext(), PrimaryBases);
-
- const CXXDestructorDecl *ImplicitVirtualDtor = 0;
-
- for (CXXRecordDecl::method_iterator i = RD->method_begin(),
- e = RD->method_end(); i != e; ++i) {
- const CXXMethodDecl *MD = *i;
-
- // We only want virtual methods.
- if (!MD->isVirtual())
- continue;
-
- // Check if this method overrides a method in the primary base.
- if (const CXXMethodDecl *OverriddenMD =
- FindNearestOverriddenMethod(MD, PrimaryBases)) {
- // Check if converting from the return type of the method to the
- // return type of the overridden method requires conversion.
- if (ComputeReturnAdjustmentBaseOffset(CGM.getContext(), MD,
- OverriddenMD).isEmpty()) {
- // This index is shared between the index in the vtable of the primary
- // base class.
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- const CXXDestructorDecl *OverriddenDD =
- cast<CXXDestructorDecl>(OverriddenMD);
-
- // 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 {
- MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD);
- }
-
- // We don't need to add an entry for this method.
- continue;
- }
- }
-
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- if (MD->isImplicit()) {
- assert(!ImplicitVirtualDtor &&
- "Did already see an implicit virtual dtor!");
- ImplicitVirtualDtor = DD;
- continue;
- }
-
- // Add the complete dtor.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
-
- // Add the deleting dtor.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
- } else {
- // Add the entry.
- MethodVTableIndices[MD] = CurrentIndex++;
- }
- }
-
- if (ImplicitVirtualDtor) {
- // Itanium C++ ABI 2.5.2:
- // If a class has an implicitly-defined virtual destructor,
- // its entries come after the declared virtual function pointers.
-
- // Add the complete dtor.
- MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] =
- CurrentIndex++;
-
- // Add the deleting dtor.
- MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] =
- CurrentIndex++;
- }
-
- NumVirtualFunctionPointers[RD] = CurrentIndex;
-}
+CodeGenVTables::CodeGenVTables(CodeGenModule &CGM)
+ : CGM(CGM), VTContext(CGM.getContext()) { }
bool CodeGenVTables::ShouldEmitVTableInThisTU(const CXXRecordDecl *RD) {
assert(RD->isDynamicClass() && "Non dynamic classes have no VTable.");
@@ -2449,75 +58,6 @@ bool CodeGenVTables::ShouldEmitVTableInThisTU(const CXXRecordDecl *RD) {
return KeyFunction->hasBody();
}
-uint64_t CodeGenVTables::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) {
- llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
- NumVirtualFunctionPointers.find(RD);
- if (I != NumVirtualFunctionPointers.end())
- return I->second;
-
- ComputeMethodVTableIndices(RD);
-
- I = NumVirtualFunctionPointers.find(RD);
- assert(I != NumVirtualFunctionPointers.end() && "Did not find entry!");
- return I->second;
-}
-
-uint64_t CodeGenVTables::getMethodVTableIndex(GlobalDecl GD) {
- MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD);
- if (I != MethodVTableIndices.end())
- return I->second;
-
- const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent();
-
- ComputeMethodVTableIndices(RD);
-
- I = MethodVTableIndices.find(GD);
- assert(I != MethodVTableIndices.end() && "Did not find index!");
- return I->second;
-}
-
-CharUnits
-CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
- const CXXRecordDecl *VBase) {
- ClassPairTy ClassPair(RD, VBase);
-
- VirtualBaseClassOffsetOffsetsMapTy::iterator I =
- VirtualBaseClassOffsetOffsets.find(ClassPair);
- if (I != VirtualBaseClassOffsetOffsets.end())
- return I->second;
-
- VCallAndVBaseOffsetBuilder Builder(RD, RD, /*FinalOverriders=*/0,
- BaseSubobject(RD, CharUnits::Zero()),
- /*BaseIsVirtual=*/false,
- /*OffsetInLayoutClass=*/CharUnits::Zero());
-
- for (VCallAndVBaseOffsetBuilder::VBaseOffsetOffsetsMapTy::const_iterator I =
- Builder.getVBaseOffsetOffsets().begin(),
- E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) {
- // Insert all types.
- ClassPairTy ClassPair(RD, I->first);
-
- VirtualBaseClassOffsetOffsets.insert(
- std::make_pair(ClassPair, I->second));
- }
-
- I = VirtualBaseClassOffsetOffsets.find(ClassPair);
- assert(I != VirtualBaseClassOffsetOffsets.end() && "Did not find index!");
-
- return I->second;
-}
-
-uint64_t
-CodeGenVTables::getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD) {
- assert(AddressPoints.count(std::make_pair(RD, Base)) &&
- "Did not find address point!");
-
- uint64_t AddressPoint = AddressPoints.lookup(std::make_pair(RD, Base));
- assert(AddressPoint && "Address point must not be zero!");
-
- return AddressPoint;
-}
-
llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
const ThunkInfo &Thunk) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
@@ -2532,7 +72,7 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
getCXXABI().getMangleContext().mangleThunk(MD, Thunk, Out);
Out.flush();
- const llvm::Type *Ty = getTypes().GetFunctionTypeForVTable(GD);
+ llvm::Type *Ty = getTypes().GetFunctionTypeForVTable(GD);
return GetOrCreateLLVMFunction(Name, Ty, GD, /*ForVTable=*/true);
}
@@ -2543,7 +83,7 @@ static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF,
if (!NonVirtualAdjustment && !VirtualAdjustment)
return Ptr;
- const llvm::Type *Int8PtrTy =
+ llvm::Type *Int8PtrTy =
llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
llvm::Value *V = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy);
@@ -2554,7 +94,7 @@ static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF,
}
if (VirtualAdjustment) {
- const llvm::Type *PtrDiffTy =
+ llvm::Type *PtrDiffTy =
CGF.ConvertType(CGF.getContext().getPointerDiffType());
// Do the virtual adjustment.
@@ -2704,7 +244,7 @@ void CodeGenFunction::GenerateVarArgsThunk(
QualType ResultType = FPT->getResultType();
// Get the original function
- const llvm::Type *Ty =
+ llvm::Type *Ty =
CGM.getTypes().GetFunctionType(FnInfo, /*IsVariadic*/true);
llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
llvm::Function *BaseFn = cast<llvm::Function>(Callee);
@@ -2811,7 +351,7 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
}
// Get our callee.
- const llvm::Type *Ty =
+ llvm::Type *Ty =
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(GD),
FPT->isVariadic());
llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
@@ -2881,7 +421,7 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
"Shouldn't replace non-declaration");
// Remove the name from the old thunk function and get a new thunk.
- OldThunkFn->setName(llvm::StringRef());
+ OldThunkFn->setName(StringRef());
Entry = CGM.GetAddrOfThunk(GD, Thunk);
// If needed, replace the old thunk with a bitcast.
@@ -2953,122 +493,27 @@ void CodeGenVTables::EmitThunks(GlobalDecl GD)
if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
return;
- const CXXRecordDecl *RD = MD->getParent();
-
- // Compute VTable related info for this class.
- ComputeVTableRelatedInformation(RD, false);
-
- ThunksMapTy::const_iterator I = Thunks.find(MD);
- if (I == Thunks.end()) {
- // We did not find a thunk for this method.
+ const VTableContext::ThunkInfoVectorTy *ThunkInfoVector =
+ VTContext.getThunkInfo(MD);
+ if (!ThunkInfoVector)
return;
- }
- const ThunkInfoVectorTy &ThunkInfoVector = I->second;
- for (unsigned I = 0, E = ThunkInfoVector.size(); I != E; ++I)
- EmitThunk(GD, ThunkInfoVector[I], /*UseAvailableExternallyLinkage=*/false);
-}
-
-void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD,
- bool RequireVTable) {
- VTableLayoutData &Entry = VTableLayoutMap[RD];
-
- // We may need to generate a definition for this vtable.
- if (RequireVTable && !Entry.getInt()) {
- if (ShouldEmitVTableInThisTU(RD))
- CGM.DeferredVTables.push_back(RD);
-
- Entry.setInt(true);
- }
-
- // Check if we've computed this information before.
- if (Entry.getPointer())
- return;
-
- VTableBuilder Builder(*this, RD, CharUnits::Zero(),
- /*MostDerivedClassIsVirtual=*/0, RD);
-
- // Add the VTable layout.
- uint64_t NumVTableComponents = Builder.getNumVTableComponents();
- // -fapple-kext adds an extra entry at end of vtbl.
- bool IsAppleKext = CGM.getContext().getLangOptions().AppleKext;
- if (IsAppleKext)
- NumVTableComponents += 1;
-
- uint64_t *LayoutData = new uint64_t[NumVTableComponents + 1];
- if (IsAppleKext)
- LayoutData[NumVTableComponents] = 0;
- Entry.setPointer(LayoutData);
-
- // Store the number of components.
- LayoutData[0] = NumVTableComponents;
-
- // Store the components.
- std::copy(Builder.vtable_components_data_begin(),
- Builder.vtable_components_data_end(),
- &LayoutData[1]);
-
- // Add the known thunks.
- Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
-
- // Add the thunks needed in this vtable.
- assert(!VTableThunksMap.count(RD) &&
- "Thunks already exists for this vtable!");
-
- VTableThunksTy &VTableThunks = VTableThunksMap[RD];
- VTableThunks.append(Builder.vtable_thunks_begin(),
- Builder.vtable_thunks_end());
-
- // Sort them.
- std::sort(VTableThunks.begin(), VTableThunks.end());
-
- // Add the address points.
- for (VTableBuilder::AddressPointsMapTy::const_iterator I =
- Builder.address_points_begin(), E = Builder.address_points_end();
- I != E; ++I) {
-
- uint64_t &AddressPoint = AddressPoints[std::make_pair(RD, I->first)];
-
- // Check if we already have the address points for this base.
- assert(!AddressPoint && "Address point already exists for this base!");
-
- AddressPoint = I->second;
- }
-
- // If we don't have the vbase information for this class, insert it.
- // getVirtualBaseOffsetOffset will compute it separately without computing
- // the rest of the vtable related information.
- if (!RD->getNumVBases())
- return;
-
- const RecordType *VBaseRT =
- RD->vbases_begin()->getType()->getAs<RecordType>();
- const CXXRecordDecl *VBase = cast<CXXRecordDecl>(VBaseRT->getDecl());
-
- if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase)))
- return;
-
- for (VTableBuilder::VBaseOffsetOffsetsMapTy::const_iterator I =
- Builder.getVBaseOffsetOffsets().begin(),
- E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) {
- // Insert all types.
- ClassPairTy ClassPair(RD, I->first);
-
- VirtualBaseClassOffsetOffsets.insert(
- std::make_pair(ClassPair, I->second));
- }
+ for (unsigned I = 0, E = ThunkInfoVector->size(); I != E; ++I)
+ EmitThunk(GD, (*ThunkInfoVector)[I],
+ /*UseAvailableExternallyLinkage=*/false);
}
llvm::Constant *
CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
- const uint64_t *Components,
+ const VTableComponent *Components,
unsigned NumComponents,
- const VTableThunksTy &VTableThunks) {
- llvm::SmallVector<llvm::Constant *, 64> Inits;
+ const VTableLayout::VTableThunkTy *VTableThunks,
+ unsigned NumVTableThunks) {
+ SmallVector<llvm::Constant *, 64> Inits;
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+ llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- const llvm::Type *PtrDiffTy =
+ llvm::Type *PtrDiffTy =
CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
QualType ClassType = CGM.getContext().getTagDeclType(RD);
@@ -3079,8 +524,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
llvm::Constant* PureVirtualFn = 0;
for (unsigned I = 0; I != NumComponents; ++I) {
- VTableComponent Component =
- VTableComponent::getFromOpaqueInteger(Components[I]);
+ VTableComponent Component = Components[I];
llvm::Constant *Init = 0;
@@ -3126,7 +570,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
if (cast<CXXMethodDecl>(GD.getDecl())->isPure()) {
// We have a pure virtual member function.
if (!PureVirtualFn) {
- const llvm::FunctionType *Ty =
+ llvm::FunctionType *Ty =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()),
/*isVarArg=*/false);
PureVirtualFn =
@@ -3138,7 +582,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
Init = PureVirtualFn;
} else {
// Check if we should use a thunk.
- if (NextVTableThunkIndex < VTableThunks.size() &&
+ if (NextVTableThunkIndex < NumVTableThunks &&
VTableThunks[NextVTableThunkIndex].first == I) {
const ThunkInfo &Thunk = VTableThunks[NextVTableThunkIndex].second;
@@ -3147,7 +591,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
NextVTableThunkIndex++;
} else {
- const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVTable(GD);
+ llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVTable(GD);
Init = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
}
@@ -3170,46 +614,45 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
}
llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) {
+ llvm::GlobalVariable *&VTable = VTables[RD];
+ if (VTable)
+ return VTable;
+
+ // We may need to generate a definition for this vtable.
+ if (ShouldEmitVTableInThisTU(RD))
+ CGM.DeferredVTables.push_back(RD);
+
llvm::SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
CGM.getCXXABI().getMangleContext().mangleCXXVTable(RD, Out);
Out.flush();
- llvm::StringRef Name = OutName.str();
+ StringRef Name = OutName.str();
- ComputeVTableRelatedInformation(RD, /*VTableRequired=*/true);
-
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+ llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
llvm::ArrayType *ArrayType =
- llvm::ArrayType::get(Int8PtrTy, getNumVTableComponents(RD));
+ llvm::ArrayType::get(Int8PtrTy,
+ VTContext.getVTableLayout(RD).getNumVTableComponents());
- llvm::GlobalVariable *GV =
+ VTable =
CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType,
llvm::GlobalValue::ExternalLinkage);
- GV->setUnnamedAddr(true);
- return GV;
+ VTable->setUnnamedAddr(true);
+ return VTable;
}
void
CodeGenVTables::EmitVTableDefinition(llvm::GlobalVariable *VTable,
llvm::GlobalVariable::LinkageTypes Linkage,
const CXXRecordDecl *RD) {
- // Dump the vtable layout if necessary.
- if (CGM.getLangOptions().DumpVTableLayouts) {
- VTableBuilder Builder(*this, RD, CharUnits::Zero(),
- /*MostDerivedClassIsVirtual=*/0, RD);
-
- Builder.dumpLayout(llvm::errs());
- }
+ const VTableLayout &VTLayout = VTContext.getVTableLayout(RD);
- assert(VTableThunksMap.count(RD) &&
- "No thunk status for this record decl!");
-
- const VTableThunksTy& Thunks = VTableThunksMap[RD];
-
// Create and set the initializer.
llvm::Constant *Init =
- CreateVTableInitializer(RD, getVTableComponentsData(RD),
- getNumVTableComponents(RD), Thunks);
+ CreateVTableInitializer(RD,
+ VTLayout.vtable_component_begin(),
+ VTLayout.getNumVTableComponents(),
+ VTLayout.vtable_thunk_begin(),
+ VTLayout.getNumVTableThunks());
VTable->setInitializer(Init);
// Set the correct linkage.
@@ -3225,17 +668,13 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
bool BaseIsVirtual,
llvm::GlobalVariable::LinkageTypes Linkage,
VTableAddressPointsMapTy& AddressPoints) {
- VTableBuilder Builder(*this, Base.getBase(),
- Base.getBaseOffset(),
- /*MostDerivedClassIsVirtual=*/BaseIsVirtual, RD);
-
- // Dump the vtable layout if necessary.
- if (CGM.getLangOptions().DumpVTableLayouts)
- Builder.dumpLayout(llvm::errs());
+ llvm::OwningPtr<VTableLayout> VTLayout(
+ VTContext.createConstructionVTableLayout(Base.getBase(),
+ Base.getBaseOffset(),
+ BaseIsVirtual, RD));
// Add the address points.
- AddressPoints.insert(Builder.address_points_begin(),
- Builder.address_points_end());
+ AddressPoints = VTLayout->getAddressPoints();
// Get the mangled construction vtable name.
llvm::SmallString<256> OutName;
@@ -3244,11 +683,11 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
mangleCXXCtorVTable(RD, Base.getBaseOffset().getQuantity(), Base.getBase(),
Out);
Out.flush();
- llvm::StringRef Name = OutName.str();
+ StringRef Name = OutName.str();
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+ llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
llvm::ArrayType *ArrayType =
- llvm::ArrayType::get(Int8PtrTy, Builder.getNumVTableComponents());
+ llvm::ArrayType::get(Int8PtrTy, VTLayout->getNumVTableComponents());
// Create the variable that will hold the construction vtable.
llvm::GlobalVariable *VTable =
@@ -3258,19 +697,13 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
// V-tables are always unnamed_addr.
VTable->setUnnamedAddr(true);
- // Add the thunks.
- VTableThunksTy VTableThunks;
- VTableThunks.append(Builder.vtable_thunks_begin(),
- Builder.vtable_thunks_end());
-
- // Sort them.
- std::sort(VTableThunks.begin(), VTableThunks.end());
-
// Create and set the initializer.
llvm::Constant *Init =
CreateVTableInitializer(Base.getBase(),
- Builder.vtable_components_data_begin(),
- Builder.getNumVTableComponents(), VTableThunks);
+ VTLayout->vtable_component_begin(),
+ VTLayout->getNumVTableComponents(),
+ VTLayout->vtable_thunk_begin(),
+ VTLayout->getNumVTableThunks());
VTable->setInitializer(Init);
return VTable;
@@ -3279,13 +712,10 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
void
CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
const CXXRecordDecl *RD) {
- llvm::GlobalVariable *&VTable = VTables[RD];
- if (VTable) {
- assert(VTable->getInitializer() && "VTable doesn't have a definition!");
+ llvm::GlobalVariable *VTable = GetAddrOfVTable(RD);
+ if (VTable->hasInitializer())
return;
- }
- VTable = GetAddrOfVTable(RD);
EmitVTableDefinition(VTable, Linkage, RD);
if (RD->getNumVBases()) {
diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h
index eff6e56c1f80..828330e5e3c4 100644
--- a/lib/CodeGen/CGVTables.h
+++ b/lib/CodeGen/CGVTables.h
@@ -17,8 +17,10 @@
#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"
namespace clang {
class CXXRecordDecl;
@@ -26,145 +28,18 @@ namespace clang {
namespace CodeGen {
class CodeGenModule;
-// BaseSubobject - Uniquely identifies a direct or indirect base class.
-// Stores both the base class decl and the offset from the most derived class to
-// the base class.
-class BaseSubobject {
- /// Base - The base class declaration.
- const CXXRecordDecl *Base;
-
- /// BaseOffset - The offset from the most derived class to the base class.
- CharUnits BaseOffset;
-
-public:
- BaseSubobject(const CXXRecordDecl *Base, CharUnits BaseOffset)
- : Base(Base), BaseOffset(BaseOffset) { }
-
- /// getBase - Returns the base class declaration.
- const CXXRecordDecl *getBase() const { return Base; }
-
- /// getBaseOffset - Returns the base class offset.
- CharUnits getBaseOffset() const { return BaseOffset; }
-
- friend bool operator==(const BaseSubobject &LHS, const BaseSubobject &RHS) {
- return LHS.Base == RHS.Base && LHS.BaseOffset == RHS.BaseOffset;
- }
-};
-
-} // end namespace CodeGen
-} // end namespace clang
-
-namespace llvm {
-
-template<> struct DenseMapInfo<clang::CodeGen::BaseSubobject> {
- static clang::CodeGen::BaseSubobject getEmptyKey() {
- return clang::CodeGen::BaseSubobject(
- DenseMapInfo<const clang::CXXRecordDecl *>::getEmptyKey(),
- clang::CharUnits::fromQuantity(DenseMapInfo<int64_t>::getEmptyKey()));
- }
-
- static clang::CodeGen::BaseSubobject getTombstoneKey() {
- return clang::CodeGen::BaseSubobject(
- DenseMapInfo<const clang::CXXRecordDecl *>::getTombstoneKey(),
- clang::CharUnits::fromQuantity(DenseMapInfo<int64_t>::getTombstoneKey()));
- }
-
- static unsigned getHashValue(const clang::CodeGen::BaseSubobject &Base) {
- return
- DenseMapInfo<const clang::CXXRecordDecl *>::getHashValue(Base.getBase()) ^
- DenseMapInfo<int64_t>::getHashValue(Base.getBaseOffset().getQuantity());
- }
-
- static bool isEqual(const clang::CodeGen::BaseSubobject &LHS,
- const clang::CodeGen::BaseSubobject &RHS) {
- return LHS == RHS;
- }
-};
-
-// It's OK to treat BaseSubobject as a POD type.
-template <> struct isPodLike<clang::CodeGen::BaseSubobject> {
- static const bool value = true;
-};
-
-}
-
-namespace clang {
-namespace CodeGen {
-
class CodeGenVTables {
CodeGenModule &CGM;
- /// 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;
- MethodVTableIndicesTy MethodVTableIndices;
-
- typedef std::pair<const CXXRecordDecl *,
- const CXXRecordDecl *> ClassPairTy;
-
- /// VirtualBaseClassOffsetOffsets - Contains the vtable offset (relative to
- /// the address point) in chars where the offsets for virtual bases of a class
- /// are stored.
- typedef llvm::DenseMap<ClassPairTy, CharUnits>
- VirtualBaseClassOffsetOffsetsMapTy;
- VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets;
+ VTableContext VTContext;
/// VTables - All the vtables which have been defined.
llvm::DenseMap<const CXXRecordDecl *, llvm::GlobalVariable *> VTables;
- /// NumVirtualFunctionPointers - Contains the number of virtual function
- /// pointers in the vtable for a given record decl.
- llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers;
-
- typedef llvm::SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
- typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
-
- /// Thunks - Contains all thunks that a given method decl will need.
- ThunksMapTy Thunks;
-
- // The layout entry and a bool indicating whether we've actually emitted
- // the vtable.
- typedef llvm::PointerIntPair<uint64_t *, 1, bool> VTableLayoutData;
- typedef llvm::DenseMap<const CXXRecordDecl *, VTableLayoutData>
- VTableLayoutMapTy;
-
- /// VTableLayoutMap - Stores the vtable layout for all record decls.
- /// The layout is stored as an array of 64-bit integers, where the first
- /// integer is the number of vtable entries in the layout, and the subsequent
- /// integers are the vtable components.
- VTableLayoutMapTy VTableLayoutMap;
-
- typedef std::pair<const CXXRecordDecl *, BaseSubobject> BaseSubobjectPairTy;
- typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t> AddressPointsMapTy;
-
- /// Address points - Address points for all vtables.
- AddressPointsMapTy AddressPoints;
-
/// VTableAddressPointsMapTy - Address points for a single vtable.
typedef llvm::DenseMap<BaseSubobject, uint64_t> VTableAddressPointsMapTy;
- typedef llvm::SmallVector<std::pair<uint64_t, ThunkInfo>, 1>
- VTableThunksTy;
-
- typedef llvm::DenseMap<const CXXRecordDecl *, VTableThunksTy>
- VTableThunksMapTy;
-
- /// VTableThunksMap - Contains thunks needed by vtables.
- VTableThunksMapTy VTableThunksMap;
-
- uint64_t getNumVTableComponents(const CXXRecordDecl *RD) const {
- assert(VTableLayoutMap.count(RD) && "No vtable layout for this class!");
-
- return VTableLayoutMap.lookup(RD).getPointer()[0];
- }
-
- const uint64_t *getVTableComponentsData(const CXXRecordDecl *RD) const {
- assert(VTableLayoutMap.count(RD) && "No vtable layout for this class!");
-
- uint64_t *Components = VTableLayoutMap.lookup(RD).getPointer();
- return &Components[1];
- }
-
+ typedef std::pair<const CXXRecordDecl *, BaseSubobject> BaseSubobjectPairTy;
typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t> SubVTTIndiciesMapTy;
/// SubVTTIndicies - Contains indices into the various sub-VTTs.
@@ -177,12 +52,6 @@ class CodeGenVTables {
/// indices.
SecondaryVirtualPointerIndicesMapTy SecondaryVirtualPointerIndices;
- /// getNumVirtualFunctionPointers - Return the number of virtual function
- /// pointers in the vtable for a given record decl.
- uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD);
-
- void ComputeMethodVTableIndices(const CXXRecordDecl *RD);
-
/// EmitThunk - Emit a single thunk.
void EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
bool UseAvailableExternallyLinkage);
@@ -193,24 +62,20 @@ class CodeGenVTables {
/// doesn't contain any incomplete types.
void MaybeEmitThunkAvailableExternally(GlobalDecl GD, const ThunkInfo &Thunk);
- /// ComputeVTableRelatedInformation - Compute and store all vtable related
- /// information (vtable layout, vbase offset offsets, thunks etc) for the
- /// given record decl.
- void ComputeVTableRelatedInformation(const CXXRecordDecl *RD,
- bool VTableRequired);
-
/// CreateVTableInitializer - Create a vtable initializer for the given record
/// decl.
/// \param Components - The vtable components; this is really an array of
/// VTableComponents.
llvm::Constant *CreateVTableInitializer(const CXXRecordDecl *RD,
- const uint64_t *Components,
+ const VTableComponent *Components,
unsigned NumComponents,
- const VTableThunksTy &VTableThunks);
+ const VTableLayout::VTableThunkTy *VTableThunks,
+ unsigned NumVTableThunks);
public:
- CodeGenVTables(CodeGenModule &CGM)
- : CGM(CGM) { }
+ CodeGenVTables(CodeGenModule &CGM);
+
+ VTableContext &getVTableContext() { return VTContext; }
/// \brief True if the VTable of this record must be emitted in the
/// translation unit.
@@ -230,19 +95,6 @@ public:
uint64_t getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD,
BaseSubobject Base);
- /// getMethodVTableIndex - Return the index (relative to the vtable address
- /// point) where the function pointer for the given virtual function is
- /// stored.
- uint64_t getMethodVTableIndex(GlobalDecl GD);
-
- /// getVirtualBaseOffsetOffset - Return the offset in chars (relative to the
- /// vtable address point) where the offset of the virtual base that contains
- /// the given base is stored, otherwise, if no virtual base contains the given
- /// class, return 0. Base must be a virtual base class or an unambigious
- /// base.
- CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
- const CXXRecordDecl *VBase);
-
/// getAddressPoint - Get the address point of the given subobject in the
/// class decl.
uint64_t getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD);
diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h
index 4d0b8410e451..489e600b3ddf 100644
--- a/lib/CodeGen/CGValue.h
+++ b/lib/CodeGen/CGValue.h
@@ -337,65 +337,90 @@ class AggValueSlot {
// Qualifiers
Qualifiers Quals;
+
+ /// DestructedFlag - This is set to true if some external code is
+ /// responsible for setting up a destructor for the slot. Otherwise
+ /// the code which constructs it should push the appropriate cleanup.
+ bool DestructedFlag : 1;
+
+ /// ObjCGCFlag - This is set to true if writing to the memory in the
+ /// slot might require calling an appropriate Objective-C GC
+ /// barrier. The exact interaction here is unnecessarily mysterious.
+ bool ObjCGCFlag : 1;
- // Associated flags.
- bool LifetimeFlag : 1;
- bool RequiresGCollection : 1;
-
- /// IsZeroed - This is set to true if the destination is known to be zero
- /// before the assignment into it. This means that zero fields don't need to
- /// be set.
- bool IsZeroed : 1;
+ /// ZeroedFlag - This is set to true if the memory in the slot is
+ /// known to be zero before the assignment into it. This means that
+ /// zero fields don't need to be set.
+ bool ZeroedFlag : 1;
+
+ /// AliasedFlag - This is set to true if the slot might be aliased
+ /// and it's not undefined behavior to access it through such an
+ /// alias. Note that it's always undefined behavior to access a C++
+ /// object that's under construction through an alias derived from
+ /// outside the construction process.
+ ///
+ /// This flag controls whether calls that produce the aggregate
+ /// value may be evaluated directly into the slot, or whether they
+ /// must be evaluated into an unaliased temporary and then memcpy'ed
+ /// over. Since it's invalid in general to memcpy a non-POD C++
+ /// object, it's important that this flag never be set when
+ /// evaluating an expression which constructs such an object.
+ bool AliasedFlag : 1;
public:
+ enum IsAliased_t { IsNotAliased, IsAliased };
+ enum IsDestructed_t { IsNotDestructed, IsDestructed };
+ enum IsZeroed_t { IsNotZeroed, IsZeroed };
+ enum NeedsGCBarriers_t { DoesNotNeedGCBarriers, NeedsGCBarriers };
+
/// ignored - Returns an aggregate value slot indicating that the
/// aggregate value is being ignored.
static AggValueSlot ignored() {
AggValueSlot AV;
AV.Addr = 0;
AV.Quals = Qualifiers();
- AV.LifetimeFlag = AV.RequiresGCollection = AV.IsZeroed =0;
+ AV.DestructedFlag = AV.ObjCGCFlag = AV.ZeroedFlag = AV.AliasedFlag = false;
return AV;
}
/// forAddr - Make a slot for an aggregate value.
///
- /// \param Volatile - true if the slot should be volatile-initialized
- ///
- /// \param Qualifiers - The qualifiers that dictate how the slot
- /// should be initialied. Only 'volatile' and the Objective-C
- /// lifetime qualifiers matter.
+ /// \param quals - The qualifiers that dictate how the slot should
+ /// be initialied. Only 'volatile' and the Objective-C lifetime
+ /// qualifiers matter.
///
- /// \param LifetimeExternallyManaged - true if the slot's lifetime
- /// is being externally managed; false if a destructor should be
- /// registered for any temporaries evaluated into the slot
- /// \param RequiresGCollection - true if the slot is located
+ /// \param isDestructed - true if something else is responsible
+ /// for calling destructors on this object
+ /// \param needsGC - true if the slot is potentially located
/// somewhere that ObjC GC calls should be emitted for
- static AggValueSlot forAddr(llvm::Value *Addr, Qualifiers Quals,
- bool LifetimeExternallyManaged,
- bool RequiresGCollection = false,
- bool IsZeroed = false) {
+ static AggValueSlot forAddr(llvm::Value *addr, Qualifiers quals,
+ IsDestructed_t isDestructed,
+ NeedsGCBarriers_t needsGC,
+ IsAliased_t isAliased,
+ IsZeroed_t isZeroed = IsNotZeroed) {
AggValueSlot AV;
- AV.Addr = Addr;
- AV.Quals = Quals;
- AV.LifetimeFlag = LifetimeExternallyManaged;
- AV.RequiresGCollection = RequiresGCollection;
- AV.IsZeroed = IsZeroed;
+ AV.Addr = addr;
+ AV.Quals = quals;
+ AV.DestructedFlag = isDestructed;
+ AV.ObjCGCFlag = needsGC;
+ AV.ZeroedFlag = isZeroed;
+ AV.AliasedFlag = isAliased;
return AV;
}
- static AggValueSlot forLValue(LValue LV, bool LifetimeExternallyManaged,
- bool RequiresGCollection = false,
- bool IsZeroed = false) {
+ static AggValueSlot forLValue(LValue LV, IsDestructed_t isDestructed,
+ NeedsGCBarriers_t needsGC,
+ IsAliased_t isAliased,
+ IsZeroed_t isZeroed = IsNotZeroed) {
return forAddr(LV.getAddress(), LV.getQuals(),
- LifetimeExternallyManaged, RequiresGCollection, IsZeroed);
+ isDestructed, needsGC, isAliased, isZeroed);
}
- bool isLifetimeExternallyManaged() const {
- return LifetimeFlag;
+ IsDestructed_t isExternallyDestructed() const {
+ return IsDestructed_t(DestructedFlag);
}
- void setLifetimeExternallyManaged(bool Managed = true) {
- LifetimeFlag = Managed;
+ void setExternallyDestructed(bool destructed = true) {
+ DestructedFlag = destructed;
}
Qualifiers getQualifiers() const { return Quals; }
@@ -408,8 +433,8 @@ public:
return Quals.getObjCLifetime();
}
- bool requiresGCollection() const {
- return RequiresGCollection;
+ NeedsGCBarriers_t requiresGCollection() const {
+ return NeedsGCBarriers_t(ObjCGCFlag);
}
llvm::Value *getAddr() const {
@@ -420,13 +445,17 @@ public:
return Addr == 0;
}
+ IsAliased_t isPotentiallyAliased() const {
+ return IsAliased_t(AliasedFlag);
+ }
+
RValue asRValue() const {
return RValue::getAggregate(getAddr(), isVolatile());
}
- void setZeroed(bool V = true) { IsZeroed = V; }
- bool isZeroed() const {
- return IsZeroed;
+ void setZeroed(bool V = true) { ZeroedFlag = V; }
+ IsZeroed_t isZeroed() const {
+ return IsZeroed_t(ZeroedFlag);
}
};
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index 80e46d2be704..5e674a8d0110 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -14,6 +14,8 @@ add_clang_library(clangCodeGen
CGBuiltin.cpp
CGCall.cpp
CGClass.cpp
+ CGCUDANV.cpp
+ CGCUDARuntime.cpp
CGCXX.cpp
CGCXXABI.cpp
CGCleanup.cpp
@@ -31,6 +33,7 @@ add_clang_library(clangCodeGen
CGObjCGNU.cpp
CGObjCMac.cpp
CGObjCRuntime.cpp
+ CGOpenCLRuntime.cpp
CGRecordLayoutBuilder.cpp
CGRTTI.cpp
CGStmt.cpp
diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp
index 263e01e4f18a..68dd5c94dc01 100644
--- a/lib/CodeGen/CodeGenAction.cpp
+++ b/lib/CodeGen/CodeGenAction.cpp
@@ -30,12 +30,12 @@ using namespace llvm;
namespace clang {
class BackendConsumer : public ASTConsumer {
- Diagnostic &Diags;
+ DiagnosticsEngine &Diags;
BackendAction Action;
const CodeGenOptions &CodeGenOpts;
const TargetOptions &TargetOpts;
const LangOptions &LangOpts;
- llvm::raw_ostream *AsmOutStream;
+ raw_ostream *AsmOutStream;
ASTContext *Context;
Timer LLVMIRGeneration;
@@ -45,12 +45,12 @@ namespace clang {
llvm::OwningPtr<llvm::Module> TheModule;
public:
- BackendConsumer(BackendAction action, Diagnostic &_Diags,
+ BackendConsumer(BackendAction action, DiagnosticsEngine &_Diags,
const CodeGenOptions &compopts,
const TargetOptions &targetopts,
const LangOptions &langopts,
bool TimePasses,
- const std::string &infile, llvm::raw_ostream *OS,
+ const std::string &infile, raw_ostream *OS,
LLVMContext &C) :
Diags(_Diags),
Action(action),
@@ -185,7 +185,7 @@ static FullSourceLoc ConvertBackendLocation(const llvm::SMDiagnostic &D,
// Translate the offset into the file.
unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();
SourceLocation NewLoc =
- CSM.getLocForStartOfFile(FID).getFileLocWithOffset(Offset);
+ CSM.getLocForStartOfFile(FID).getLocWithOffset(Offset);
return FullSourceLoc(NewLoc, CSM);
}
@@ -199,7 +199,7 @@ void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D,
// we re-format the SMDiagnostic in terms of a clang diagnostic.
// Strip "error: " off the start of the message string.
- llvm::StringRef Message = D.getMessage();
+ StringRef Message = D.getMessage();
if (Message.startswith("error: "))
Message = Message.substr(7);
@@ -259,7 +259,7 @@ llvm::LLVMContext *CodeGenAction::takeLLVMContext() {
}
static raw_ostream *GetOutputStream(CompilerInstance &CI,
- llvm::StringRef InFile,
+ StringRef InFile,
BackendAction Action) {
switch (Action) {
case Backend_EmitAssembly:
@@ -275,14 +275,13 @@ static raw_ostream *GetOutputStream(CompilerInstance &CI,
return CI.createDefaultOutputFile(true, InFile, "o");
}
- assert(0 && "Invalid action!");
- return 0;
+ llvm_unreachable("Invalid action!");
}
ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
+ StringRef InFile) {
BackendAction BA = static_cast<BackendAction>(Act);
- llvm::OwningPtr<llvm::raw_ostream> OS(GetOutputStream(CI, InFile, BA));
+ llvm::OwningPtr<raw_ostream> OS(GetOutputStream(CI, InFile, BA));
if (BA != Backend_EmitNothing && !OS)
return 0;
@@ -320,17 +319,17 @@ void CodeGenAction::ExecuteAction() {
TheModule.reset(ParseIR(MainFileCopy, Err, *VMContext));
if (!TheModule) {
// Translate from the diagnostic info to the SourceManager location.
- SourceLocation Loc = SM.getLocation(
+ SourceLocation Loc = SM.translateFileLineCol(
SM.getFileEntryForID(SM.getMainFileID()), Err.getLineNo(),
Err.getColumnNo() + 1);
// Get a custom diagnostic for the error. We strip off a leading
// diagnostic code if there is one.
- llvm::StringRef Msg = Err.getMessage();
+ StringRef Msg = Err.getMessage();
if (Msg.startswith("error: "))
Msg = Msg.substr(7);
- unsigned DiagID = CI.getDiagnostics().getCustomDiagID(Diagnostic::Error,
- Msg);
+ unsigned DiagID = CI.getDiagnostics().getCustomDiagID(
+ DiagnosticsEngine::Error, Msg);
CI.getDiagnostics().Report(Loc, DiagID);
return;
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 702897a7c448..8191f021da4a 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -13,6 +13,7 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
+#include "CGCUDARuntime.h"
#include "CGCXXABI.h"
#include "CGDebugInfo.h"
#include "CGException.h"
@@ -30,10 +31,10 @@ using namespace CodeGen;
CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
: CodeGenTypeCache(cgm), CGM(cgm),
- Target(CGM.getContext().Target), Builder(cgm.getModule().getContext()),
+ Target(CGM.getContext().getTargetInfo()), Builder(cgm.getModule().getContext()),
AutoreleaseResult(false), BlockInfo(0), BlockPointer(0),
- NormalCleanupDest(0), EHCleanupDest(0), NextCleanupDestIndex(1),
- ExceptionSlot(0), EHSelectorSlot(0),
+ NormalCleanupDest(0), NextCleanupDestIndex(1),
+ EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0),
DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false),
IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0),
CXXThisDecl(0), CXXThisValue(0), CXXVTTDecl(0), CXXVTTValue(0),
@@ -86,6 +87,10 @@ bool CodeGenFunction::hasAggregateLLVMType(QualType type) {
case Type::ObjCObject:
case Type::ObjCInterface:
return true;
+
+ // In IRGen, atomic types are just the underlying type
+ case Type::Atomic:
+ return hasAggregateLLVMType(type->getAs<AtomicType>()->getValueType());
}
llvm_unreachable("unknown type kind!");
}
@@ -116,7 +121,8 @@ void CodeGenFunction::EmitReturnBlock() {
dyn_cast<llvm::BranchInst>(*ReturnBlock.getBlock()->use_begin());
if (BI && BI->isUnconditional() &&
BI->getSuccessor(0) == ReturnBlock.getBlock()) {
- // Reset insertion point and delete the branch.
+ // Reset insertion point, including debug location, and delete the branch.
+ Builder.SetCurrentDebugLocation(BI->getDebugLoc());
Builder.SetInsertPoint(BI->getParent());
BI->eraseFromParent();
delete ReturnBlock.getBlock();
@@ -189,7 +195,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
}
}
- EmitIfUsed(*this, RethrowBlock.getBlock());
+ EmitIfUsed(*this, EHResumeBlock);
EmitIfUsed(*this, TerminateLandingPad);
EmitIfUsed(*this, TerminateHandler);
EmitIfUsed(*this, UnreachableBlock);
@@ -215,7 +221,7 @@ void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn) {
// void __cyg_profile_func_{enter,exit} (void *this_fn, void *call_site);
llvm::PointerType *PointerTy = Int8PtrTy;
llvm::Type *ProfileFuncArgs[] = { PointerTy, PointerTy };
- const llvm::FunctionType *FunctionTy =
+ llvm::FunctionType *FunctionTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()),
ProfileFuncArgs, false);
@@ -345,6 +351,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
if (Ty->isVariablyModifiedType())
EmitVariablyModifiedType(Ty);
}
+ // Emit a location at the end of the prologue.
+ if (CGDebugInfo *DI = getDebugInfo())
+ DI->EmitLocation(Builder, StartLoc);
}
void CodeGenFunction::EmitFunctionBody(FunctionArgList &Args) {
@@ -364,9 +373,12 @@ static void TryMarkNoThrow(llvm::Function *F) {
for (llvm::Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI)
for (llvm::BasicBlock::iterator
BI = FI->begin(), BE = FI->end(); BI != BE; ++BI)
- if (llvm::CallInst *Call = dyn_cast<llvm::CallInst>(&*BI))
+ if (llvm::CallInst *Call = dyn_cast<llvm::CallInst>(&*BI)) {
if (!Call->doesNotThrow())
return;
+ } else if (isa<llvm::ResumeInst>(&*BI)) {
+ return;
+ }
F->setDoesNotThrow(true);
}
@@ -400,6 +412,10 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
EmitDestructorBody(Args);
else if (isa<CXXConstructorDecl>(FD))
EmitConstructorBody(Args);
+ else if (getContext().getLangOptions().CUDA &&
+ !CGM.getCodeGenOpts().CUDAIsDevice &&
+ FD->hasAttr<CUDAGlobalAttr>())
+ CGM.getCUDARuntime().EmitDeviceStubBody(*this, Args);
else
EmitFunctionBody(Args);
@@ -645,7 +661,7 @@ static void emitNonZeroVLAInit(CodeGenFunction &CGF, QualType baseType,
llvm::Value *baseSizeInChars
= llvm::ConstantInt::get(CGF.IntPtrTy, baseSizeAndAlign.first.getQuantity());
- const llvm::Type *i8p = Builder.getInt8PtrTy();
+ llvm::Type *i8p = Builder.getInt8PtrTy();
llvm::Value *begin = Builder.CreateBitCast(dest, i8p, "vla.begin");
llvm::Value *end = Builder.CreateInBoundsGEP(dest, sizeInChars, "vla.end");
@@ -690,9 +706,9 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
// Cast the dest ptr to the appropriate i8 pointer type.
unsigned DestAS =
cast<llvm::PointerType>(DestPtr->getType())->getAddressSpace();
- const llvm::Type *BP = Builder.getInt8PtrTy(DestAS);
+ llvm::Type *BP = Builder.getInt8PtrTy(DestAS);
if (DestPtr->getType() != BP)
- DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp");
+ DestPtr = Builder.CreateBitCast(DestPtr, BP);
// Get size and alignment info for this aggregate.
std::pair<CharUnits, CharUnits> TypeInfo =
@@ -740,7 +756,7 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
new llvm::GlobalVariable(CGM.getModule(), NullConstant->getType(),
/*isConstant=*/true,
llvm::GlobalVariable::PrivateLinkage,
- NullConstant, llvm::Twine());
+ NullConstant, Twine());
llvm::Value *SrcPtr =
Builder.CreateBitCast(NullVariable, Builder.getInt8PtrTy());
@@ -818,7 +834,7 @@ llvm::Value *CodeGenFunction::emitArrayLength(const ArrayType *origArrayType,
// We have some number of constant-length arrays, so addr should
// have LLVM type [M x [N x [...]]]*. Build a GEP that walks
// down to the first element of addr.
- llvm::SmallVector<llvm::Value*, 8> gepIndices;
+ SmallVector<llvm::Value*, 8> gepIndices;
// GEP down to the array type.
llvm::ConstantInt *zero = Builder.getInt32(0);
@@ -828,7 +844,7 @@ llvm::Value *CodeGenFunction::emitArrayLength(const ArrayType *origArrayType,
// constant-length arrays than to re-evaluate the array bounds.
uint64_t countFromCLAs = 1;
- const llvm::ArrayType *llvmArrayType =
+ llvm::ArrayType *llvmArrayType =
cast<llvm::ArrayType>(
cast<llvm::PointerType>(addr->getType())->getElementType());
while (true) {
@@ -850,8 +866,7 @@ llvm::Value *CodeGenFunction::emitArrayLength(const ArrayType *origArrayType,
baseType = arrayType->getElementType();
// Create the actual GEP.
- addr = Builder.CreateInBoundsGEP(addr, gepIndices.begin(),
- gepIndices.end(), "array.begin");
+ addr = Builder.CreateInBoundsGEP(addr, gepIndices, "array.begin");
llvm::Value *numElements
= llvm::ConstantInt::get(SizeTy, countFromCLAs);
@@ -975,6 +990,10 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
case Type::FunctionNoProto:
type = cast<FunctionType>(ty)->getResultType();
break;
+
+ case Type::Atomic:
+ type = cast<AtomicType>(ty)->getValueType();
+ break;
}
} while (type->isVariablyModifiedType());
}
@@ -1018,3 +1037,50 @@ void CodeGenFunction::unprotectFromPeepholes(PeepholeProtection protection) {
// In theory, we could try to duplicate the peepholes now, but whatever.
protection.Inst->eraseFromParent();
}
+
+llvm::Value *CodeGenFunction::EmitAnnotationCall(llvm::Value *AnnotationFn,
+ llvm::Value *AnnotatedVal,
+ llvm::StringRef AnnotationStr,
+ SourceLocation Location) {
+ llvm::Value *Args[4] = {
+ AnnotatedVal,
+ Builder.CreateBitCast(CGM.EmitAnnotationString(AnnotationStr), Int8PtrTy),
+ Builder.CreateBitCast(CGM.EmitAnnotationUnit(Location), Int8PtrTy),
+ CGM.EmitAnnotationLineNo(Location)
+ };
+ return Builder.CreateCall(AnnotationFn, Args);
+}
+
+void CodeGenFunction::EmitVarAnnotations(const VarDecl *D, llvm::Value *V) {
+ assert(D->hasAttr<AnnotateAttr>() && "no annotate attribute");
+ // FIXME We create a new bitcast for every annotation because that's what
+ // llvm-gcc was doing.
+ for (specific_attr_iterator<AnnotateAttr>
+ ai = D->specific_attr_begin<AnnotateAttr>(),
+ ae = D->specific_attr_end<AnnotateAttr>(); ai != ae; ++ai)
+ EmitAnnotationCall(CGM.getIntrinsic(llvm::Intrinsic::var_annotation),
+ Builder.CreateBitCast(V, CGM.Int8PtrTy, V->getName()),
+ (*ai)->getAnnotation(), D->getLocation());
+}
+
+llvm::Value *CodeGenFunction::EmitFieldAnnotations(const FieldDecl *D,
+ llvm::Value *V) {
+ assert(D->hasAttr<AnnotateAttr>() && "no annotate attribute");
+ llvm::Type *VTy = V->getType();
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::ptr_annotation,
+ CGM.Int8PtrTy);
+
+ for (specific_attr_iterator<AnnotateAttr>
+ ai = D->specific_attr_begin<AnnotateAttr>(),
+ ae = D->specific_attr_end<AnnotateAttr>(); ai != ae; ++ai) {
+ // FIXME Always emit the cast inst so we can differentiate between
+ // annotation on the first field of a struct and annotation on the struct
+ // itself.
+ if (VTy != CGM.Int8PtrTy)
+ V = Builder.Insert(new llvm::BitCastInst(V, CGM.Int8PtrTy));
+ V = EmitAnnotationCall(F, V, (*ai)->getAnnotation(), D->getLocation());
+ V = Builder.CreateBitCast(V, VTy);
+ }
+
+ return V;
+}
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index f27ed947b8d8..157623da8fdd 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -325,16 +325,8 @@ private:
/// The innermost normal cleanup on the stack.
stable_iterator InnermostNormalCleanup;
- /// The innermost EH cleanup on the stack.
- stable_iterator InnermostEHCleanup;
-
- /// The number of catches on the stack.
- unsigned CatchDepth;
-
- /// The current EH destination index. Reset to FirstCatchIndex
- /// whenever the last EH cleanup is popped.
- unsigned NextEHDestIndex;
- enum { FirstEHDestIndex = 1 };
+ /// The innermost EH scope on the stack.
+ stable_iterator InnermostEHScope;
/// The current set of branch fixups. A branch fixup is a jump to
/// an as-yet unemitted label, i.e. a label for which we don't yet
@@ -353,7 +345,7 @@ private:
/// A a;
/// foo:
/// bar();
- llvm::SmallVector<BranchFixup, 8> BranchFixups;
+ SmallVector<BranchFixup, 8> BranchFixups;
char *allocate(size_t Size);
@@ -362,8 +354,7 @@ private:
public:
EHScopeStack() : StartOfBuffer(0), EndOfBuffer(0), StartOfData(0),
InnermostNormalCleanup(stable_end()),
- InnermostEHCleanup(stable_end()),
- CatchDepth(0), NextEHDestIndex(FirstEHDestIndex) {}
+ InnermostEHScope(stable_end()) {}
~EHScopeStack() { delete[] StartOfBuffer; }
// Variadic templates would make this not terrible.
@@ -435,8 +426,7 @@ public:
return new (Buffer) T(N, a0, a1, a2);
}
- /// Pops a cleanup scope off the stack. This should only be called
- /// by CodeGenFunction::PopCleanupBlock.
+ /// Pops a cleanup scope off the stack. This is private to CGCleanup.cpp.
void popCleanup();
/// Push a set of catch handlers on the stack. The catch is
@@ -444,7 +434,7 @@ public:
/// set on it.
class EHCatchScope *pushCatch(unsigned NumHandlers);
- /// Pops a catch scope off the stack.
+ /// Pops a catch scope off the stack. This is private to CGException.cpp.
void popCatch();
/// Push an exceptions filter on the stack.
@@ -463,7 +453,7 @@ public:
bool empty() const { return StartOfData == EndOfBuffer; }
bool requiresLandingPad() const {
- return (CatchDepth || hasEHCleanups());
+ return InnermostEHScope != stable_end();
}
/// Determines whether there are any normal cleanups on the stack.
@@ -476,19 +466,13 @@ public:
stable_iterator getInnermostNormalCleanup() const {
return InnermostNormalCleanup;
}
- stable_iterator getInnermostActiveNormalCleanup() const; // CGException.h
+ stable_iterator getInnermostActiveNormalCleanup() const;
- /// Determines whether there are any EH cleanups on the stack.
- bool hasEHCleanups() const {
- return InnermostEHCleanup != stable_end();
+ stable_iterator getInnermostEHScope() const {
+ return InnermostEHScope;
}
- /// Returns the innermost EH cleanup on the stack, or stable_end()
- /// if there are no EH cleanups.
- stable_iterator getInnermostEHCleanup() const {
- return InnermostEHCleanup;
- }
- stable_iterator getInnermostActiveEHCleanup() const; // CGException.h
+ stable_iterator getInnermostActiveEHScope() const;
/// An unstable reference to a scope-stack depth. Invalidated by
/// pushes but not pops.
@@ -515,10 +499,6 @@ public:
/// Translates an iterator into a stable_iterator.
stable_iterator stabilize(iterator it) const;
- /// Finds the nearest cleanup enclosing the given iterator.
- /// Returns stable_iterator::invalid() if there are no such cleanups.
- stable_iterator getEnclosingEHCleanup(iterator it) const;
-
/// Turn a stable reference to a scope depth into a unstable pointer
/// to the EH stack.
iterator find(stable_iterator save) const;
@@ -547,9 +527,6 @@ public:
/// Clears the branch-fixups list. This should only be called by
/// ResolveAllBranchFixups.
void clearFixups() { BranchFixups.clear(); }
-
- /// Gets the next EH destination index.
- unsigned getNextEHDestIndex() { return NextEHDestIndex++; }
};
/// CodeGenFunction - This class organizes the per-function state that is used
@@ -580,26 +557,6 @@ public:
unsigned Index;
};
- /// An unwind destination is an abstract label, branching to which
- /// may require a jump out through EH cleanups.
- struct UnwindDest {
- UnwindDest() : Block(0), ScopeDepth(), Index(0) {}
- UnwindDest(llvm::BasicBlock *Block,
- EHScopeStack::stable_iterator Depth,
- unsigned Index)
- : Block(Block), ScopeDepth(Depth), Index(Index) {}
-
- bool isValid() const { return Block != 0; }
- llvm::BasicBlock *getBlock() const { return Block; }
- EHScopeStack::stable_iterator getScopeDepth() const { return ScopeDepth; }
- unsigned getDestIndex() const { return Index; }
-
- private:
- llvm::BasicBlock *Block;
- EHScopeStack::stable_iterator ScopeDepth;
- unsigned Index;
- };
-
CodeGenModule &CGM; // Per-module state.
const TargetInfo &Target;
@@ -629,9 +586,6 @@ public:
/// iff the function has no return value.
llvm::Value *ReturnValue;
- /// RethrowBlock - Unified rethrow block.
- UnwindDest RethrowBlock;
-
/// AllocaInsertPoint - This is an instruction in the entry block before which
/// we prefer to insert allocas.
llvm::AssertingVH<llvm::Instruction> AllocaInsertPt;
@@ -652,16 +606,18 @@ public:
/// i32s containing the indexes of the cleanup destinations.
llvm::AllocaInst *NormalCleanupDest;
- llvm::AllocaInst *EHCleanupDest;
unsigned NextCleanupDestIndex;
- /// The exception slot. All landing pads write the current
- /// exception pointer into this alloca.
+ /// EHResumeBlock - Unified block containing a call to llvm.eh.resume.
+ llvm::BasicBlock *EHResumeBlock;
+
+ /// The exception slot. All landing pads write the current exception pointer
+ /// into this alloca.
llvm::Value *ExceptionSlot;
- /// The selector slot. Under the MandatoryCleanup model, all
- /// landing pads write the current selector value into this alloca.
+ /// The selector slot. Under the MandatoryCleanup model, all landing pads
+ /// write the current selector value into this alloca.
llvm::AllocaInst *EHSelectorSlot;
/// Emits a landing pad for the current EH stack.
@@ -681,7 +637,7 @@ public:
public:
/// ObjCEHValueStack - Stack of Objective-C exception values, used for
/// rethrows.
- llvm::SmallVector<llvm::Value*, 8> ObjCEHValueStack;
+ SmallVector<llvm::Value*, 8> ObjCEHValueStack;
/// A class controlling the emission of a finally block.
class FinallyInfo {
@@ -872,7 +828,7 @@ public:
/// The given basic block lies in the current EH scope, but may be a
/// target of a potentially scope-crossing jump; get a stable handle
/// to which we can perform this jump later.
- JumpDest getJumpDestInCurrentScope(llvm::StringRef Name = llvm::StringRef()) {
+ JumpDest getJumpDestInCurrentScope(StringRef Name = StringRef()) {
return getJumpDestInCurrentScope(createBasicBlock(Name));
}
@@ -886,14 +842,13 @@ public:
/// a conservatively correct answer for this method.
bool isObviouslyBranchWithoutCleanups(JumpDest Dest) const;
- /// EmitBranchThroughEHCleanup - Emit a branch from the current
- /// insert block through the EH cleanup handling code (if any) and
- /// then on to \arg Dest.
- void EmitBranchThroughEHCleanup(UnwindDest Dest);
+ /// popCatchScope - Pops the catch scope at the top of the EHScope
+ /// stack, emitting any required code (other than the catch handlers
+ /// themselves).
+ void popCatchScope();
- /// getRethrowDest - Returns the unified outermost-scope rethrow
- /// destination.
- UnwindDest getRethrowDest();
+ llvm::BasicBlock *getEHResumeBlock();
+ llvm::BasicBlock *getEHDispatchBlock(EHScopeStack::stable_iterator scope);
/// An object to manage conditionally-evaluated expressions.
class ConditionalEvaluation {
@@ -1089,7 +1044,7 @@ private:
JumpDest BreakBlock;
JumpDest ContinueBlock;
};
- llvm::SmallVector<BreakContinue, 8> BreakContinueStack;
+ SmallVector<BreakContinue, 8> BreakContinueStack;
/// SwitchInsn - This is nearest current switch instruction. It is null if if
/// current context is not in a switch.
@@ -1135,7 +1090,7 @@ private:
/// ByrefValueInfoMap - For each __block variable, contains a pair of the LLVM
/// type as well as the field number that contains the actual data.
- llvm::DenseMap<const ValueDecl *, std::pair<const llvm::Type *,
+ llvm::DenseMap<const ValueDecl *, std::pair<llvm::Type *,
unsigned> > ByRefValueInfo;
llvm::BasicBlock *TerminateLandingPad;
@@ -1161,13 +1116,17 @@ public:
const LangOptions &getLangOptions() const { return CGM.getLangOptions(); }
- /// Returns a pointer to the function's exception object slot, which
- /// is assigned in every landing pad.
+ /// Returns a pointer to the function's exception object and selector slot,
+ /// which is assigned in every landing pad.
llvm::Value *getExceptionSlot();
llvm::Value *getEHSelectorSlot();
+ /// Returns the contents of the function's exception object and selector
+ /// slots.
+ llvm::Value *getExceptionFromSlot();
+ llvm::Value *getSelectorFromSlot();
+
llvm::Value *getNormalCleanupDestSlot();
- llvm::Value *getEHCleanupDestSlot();
llvm::BasicBlock *getUnreachableBlock() {
if (!UnreachableBlock) {
@@ -1248,9 +1207,8 @@ public:
/// GenerateObjCGetter - Synthesize an Objective-C property getter function.
void GenerateObjCGetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID);
- void GenerateObjCGetterBody(ObjCIvarDecl *Ivar, bool IsAtomic, bool IsStrong);
- void GenerateObjCAtomicSetterBody(ObjCMethodDecl *OMD,
- ObjCIvarDecl *Ivar);
+ void generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
+ const ObjCPropertyImplDecl *propImpl);
void GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
ObjCMethodDecl *MD, bool ctor);
@@ -1259,6 +1217,8 @@ public:
/// for the given property.
void GenerateObjCSetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID);
+ void generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
+ const ObjCPropertyImplDecl *propImpl);
bool IndirectObjCSetterArg(const CGFunctionInfo &FI);
bool IvarTypeWithAggrGCObjects(QualType Ty);
@@ -1269,7 +1229,7 @@ public:
llvm::Value *EmitBlockLiteral(const BlockExpr *);
llvm::Constant *BuildDescriptorBlockDecl(const BlockExpr *,
const CGBlockInfo &Info,
- const llvm::StructType *,
+ llvm::StructType *,
llvm::Constant *BlockVarLayout);
llvm::Function *GenerateBlockFunction(GlobalDecl GD,
@@ -1298,7 +1258,7 @@ public:
return GetAddrOfBlockDecl(E->getDecl(), E->isByRef());
}
llvm::Value *GetAddrOfBlockDecl(const VarDecl *var, bool ByRef);
- const llvm::Type *BuildByRefType(const VarDecl *var);
+ llvm::Type *BuildByRefType(const VarDecl *var);
void GenerateCode(GlobalDecl GD, llvm::Function *Fn,
const CGFunctionInfo &FnInfo);
@@ -1352,7 +1312,7 @@ public:
/// GetVTablePtr - Return the Value of the vtable pointer member pointed
/// to by This.
- llvm::Value *GetVTablePtr(llvm::Value *This, const llvm::Type *Ty);
+ llvm::Value *GetVTablePtr(llvm::Value *This, llvm::Type *Ty);
/// EnterDtorCleanups - Enter the cleanups necessary to complete the
/// given phase of destruction for a destructor. The end result
@@ -1415,7 +1375,7 @@ public:
static bool hasAggregateLLVMType(QualType T);
/// createBasicBlock - Create an LLVM basic block.
- llvm::BasicBlock *createBasicBlock(llvm::StringRef name = "",
+ llvm::BasicBlock *createBasicBlock(StringRef name = "",
llvm::Function *parent = 0,
llvm::BasicBlock *before = 0) {
#ifdef NDEBUG
@@ -1444,6 +1404,10 @@ public:
/// means the block can be ignored if it is unreachable.
void EmitBlock(llvm::BasicBlock *BB, bool IsFinished=false);
+ /// EmitBlockAfterUses - Emit the given block somewhere hopefully
+ /// near its uses, and leave the insertion point in it.
+ void EmitBlockAfterUses(llvm::BasicBlock *BB);
+
/// EmitBranch - Emit a branch to the specified basic block from the current
/// insert block, taking care to avoid creation of branches from dummy
/// blocks. It is legal to call this function even if there is no current
@@ -1486,8 +1450,8 @@ public:
/// CreateTempAlloca - This creates a alloca and inserts it into the entry
/// block. The caller is responsible for setting an appropriate alignment on
/// the alloca.
- llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty,
- const llvm::Twine &Name = "tmp");
+ llvm::AllocaInst *CreateTempAlloca(llvm::Type *Ty,
+ const Twine &Name = "tmp");
/// InitTempAlloca - Provide an initial value for the given alloca.
void InitTempAlloca(llvm::AllocaInst *Alloca, llvm::Value *Value);
@@ -1497,17 +1461,19 @@ public:
/// value needs to be stored into an alloca (for example, to avoid explicit
/// PHI construction), but the type is the IR type, not the type appropriate
/// for storing in memory.
- llvm::AllocaInst *CreateIRTemp(QualType T, const llvm::Twine &Name = "tmp");
+ llvm::AllocaInst *CreateIRTemp(QualType T, const Twine &Name = "tmp");
/// CreateMemTemp - Create a temporary memory object of the given type, with
/// appropriate alignment.
- llvm::AllocaInst *CreateMemTemp(QualType T, const llvm::Twine &Name = "tmp");
+ llvm::AllocaInst *CreateMemTemp(QualType T, const Twine &Name = "tmp");
/// CreateAggTemp - Create a temporary memory object for the given
/// aggregate type.
- AggValueSlot CreateAggTemp(QualType T, const llvm::Twine &Name = "tmp") {
+ AggValueSlot CreateAggTemp(QualType T, const Twine &Name = "tmp") {
return AggValueSlot::forAddr(CreateMemTemp(T, Name), T.getQualifiers(),
- false);
+ AggValueSlot::IsNotDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased);
}
/// Emit a cast to void* in the appropriate address space.
@@ -1708,8 +1674,8 @@ public:
void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type,
bool ForVirtualBase, llvm::Value *This);
- void EmitNewArrayInitializer(const CXXNewExpr *E, llvm::Value *NewPtr,
- llvm::Value *NumElements);
+ void EmitNewArrayInitializer(const CXXNewExpr *E, QualType elementType,
+ llvm::Value *NewPtr, llvm::Value *NumElements);
void EmitCXXTemporary(const CXXTemporary *Temporary, llvm::Value *Ptr);
@@ -2074,18 +2040,18 @@ public:
ReturnValueSlot ReturnValue = ReturnValueSlot());
llvm::CallSite EmitCallOrInvoke(llvm::Value *Callee,
- llvm::ArrayRef<llvm::Value *> Args,
- const llvm::Twine &Name = "");
+ ArrayRef<llvm::Value *> Args,
+ const Twine &Name = "");
llvm::CallSite EmitCallOrInvoke(llvm::Value *Callee,
- const llvm::Twine &Name = "");
+ const Twine &Name = "");
llvm::Value *BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
- const llvm::Type *Ty);
+ llvm::Type *Ty);
llvm::Value *BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
- llvm::Value *This, const llvm::Type *Ty);
+ llvm::Value *This, llvm::Type *Ty);
llvm::Value *BuildAppleKextVirtualCall(const CXXMethodDecl *MD,
NestedNameSpecifier *Qual,
- const llvm::Type *Ty);
+ llvm::Type *Ty);
llvm::Value *BuildAppleKextVirtualDestructorCall(const CXXDestructorDecl *DD,
CXXDtorType Type,
@@ -2110,6 +2076,9 @@ public:
const CXXMethodDecl *MD,
ReturnValueSlot ReturnValue);
+ RValue EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E,
+ ReturnValueSlot ReturnValue);
+
RValue EmitBuiltinExpr(const FunctionDecl *FD,
unsigned BuiltinID, const CallExpr *E);
@@ -2122,14 +2091,14 @@ public:
llvm::Value *EmitARMBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitNeonCall(llvm::Function *F,
- llvm::SmallVectorImpl<llvm::Value*> &O,
+ SmallVectorImpl<llvm::Value*> &O,
const char *name,
unsigned shift = 0, bool rightshift = false);
llvm::Value *EmitNeonSplat(llvm::Value *V, llvm::Constant *Idx);
- llvm::Value *EmitNeonShiftVector(llvm::Value *V, const llvm::Type *Ty,
+ llvm::Value *EmitNeonShiftVector(llvm::Value *V, llvm::Type *Ty,
bool negateForRightShift);
- llvm::Value *BuildVector(const llvm::SmallVectorImpl<llvm::Value*> &Ops);
+ llvm::Value *BuildVector(const SmallVectorImpl<llvm::Value*> &Ops);
llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
@@ -2163,7 +2132,7 @@ public:
bool ignored);
llvm::Value *EmitARCRetain(QualType type, llvm::Value *value);
llvm::Value *EmitARCRetainNonBlock(llvm::Value *value);
- llvm::Value *EmitARCRetainBlock(llvm::Value *value);
+ llvm::Value *EmitARCRetainBlock(llvm::Value *value, bool mandatory);
void EmitARCRelease(llvm::Value *value, bool precise);
llvm::Value *EmitARCAutorelease(llvm::Value *value);
llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value);
@@ -2175,10 +2144,13 @@ public:
std::pair<LValue,llvm::Value*>
EmitARCStoreStrong(const BinaryOperator *e, bool ignored);
+ llvm::Value *EmitObjCThrowOperand(const Expr *expr);
+
llvm::Value *EmitObjCProduceObject(QualType T, llvm::Value *Ptr);
llvm::Value *EmitObjCConsumeObject(QualType T, llvm::Value *Ptr);
llvm::Value *EmitObjCExtendObjectLifetime(QualType T, llvm::Value *Ptr);
+ llvm::Value *EmitARCExtendBlockObject(const Expr *expr);
llvm::Value *EmitARCRetainScalarExpr(const Expr *expr);
llvm::Value *EmitARCRetainAutoreleaseScalarExpr(const Expr *expr);
@@ -2311,6 +2283,25 @@ public:
void EmitCXXThrowExpr(const CXXThrowExpr *E);
+ RValue EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest = 0);
+
+ //===--------------------------------------------------------------------===//
+ // Annotations Emission
+ //===--------------------------------------------------------------------===//
+
+ /// Emit an annotation call (intrinsic or builtin).
+ llvm::Value *EmitAnnotationCall(llvm::Value *AnnotationFn,
+ llvm::Value *AnnotatedVal,
+ llvm::StringRef AnnotationStr,
+ SourceLocation Location);
+
+ /// Emit local annotations for the local variable V, declared by D.
+ void EmitVarAnnotations(const VarDecl *D, llvm::Value *V);
+
+ /// Emit field annotations for the given field & value. Returns the
+ /// annotation result.
+ llvm::Value *EmitFieldAnnotations(const FieldDecl *D, llvm::Value *V);
+
//===--------------------------------------------------------------------===//
// Internal Helpers
//===--------------------------------------------------------------------===//
@@ -2370,7 +2361,7 @@ private:
/// Ty, into individual arguments on the provided vector \arg Args. See
/// ABIArgInfo::Expand.
void ExpandTypeToArgs(QualType Ty, RValue Src,
- llvm::SmallVector<llvm::Value*, 16> &Args,
+ SmallVector<llvm::Value*, 16> &Args,
llvm::FunctionType *IRFuncTy);
llvm::Value* EmitAsmInput(const AsmStmt &S,
@@ -2439,7 +2430,7 @@ private:
void EmitDeclMetadata();
CodeGenModule::ByrefHelpers *
- buildByrefHelpers(const llvm::StructType &byrefType,
+ buildByrefHelpers(llvm::StructType &byrefType,
const AutoVarEmission &emission);
};
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 0668039a892c..924ec8448e86 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -16,8 +16,10 @@
#include "CodeGenFunction.h"
#include "CodeGenTBAA.h"
#include "CGCall.h"
+#include "CGCUDARuntime.h"
#include "CGCXXABI.h"
#include "CGObjCRuntime.h"
+#include "CGOpenCLRuntime.h"
#include "TargetInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "clang/AST/ASTContext.h"
@@ -27,7 +29,6 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/RecordLayout.h"
-#include "clang/Basic/Builtins.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -44,8 +45,10 @@
using namespace clang;
using namespace CodeGen;
+static const char AnnotationSection[] = "llvm.metadata";
+
static CGCXXABI &createCXXABI(CodeGenModule &CGM) {
- switch (CGM.getContext().Target.getCXXABI()) {
+ switch (CGM.getContext().getTargetInfo().getCXXABI()) {
case CXXABI_ARM: return *CreateARMCXXABI(CGM);
case CXXABI_Itanium: return *CreateItaniumCXXABI(CGM);
case CXXABI_Microsoft: return *CreateMicrosoftCXXABI(CGM);
@@ -58,22 +61,25 @@ static CGCXXABI &createCXXABI(CodeGenModule &CGM) {
CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
llvm::Module &M, const llvm::TargetData &TD,
- Diagnostic &diags)
+ DiagnosticsEngine &diags)
: Context(C), Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M),
TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags),
ABI(createCXXABI(*this)),
Types(C, M, TD, getTargetCodeGenInfo().getABIInfo(), ABI, CGO),
TBAA(0),
- VTables(*this), Runtime(0), DebugInfo(0), ARCData(0), RRData(0),
- CFConstantStringClassRef(0), ConstantStringClassRef(0),
+ VTables(*this), ObjCRuntime(0), OpenCLRuntime(0), CUDARuntime(0),
+ DebugInfo(0), ARCData(0), RRData(0), CFConstantStringClassRef(0),
+ ConstantStringClassRef(0), NSConstantStringType(0),
VMContext(M.getContext()),
- NSConcreteGlobalBlockDecl(0), NSConcreteStackBlockDecl(0),
NSConcreteGlobalBlock(0), NSConcreteStackBlock(0),
- BlockObjectAssignDecl(0), BlockObjectDisposeDecl(0),
BlockObjectAssign(0), BlockObjectDispose(0),
BlockDescriptorType(0), GenericBlockLiteralType(0) {
if (Features.ObjC1)
- createObjCRuntime();
+ createObjCRuntime();
+ if (Features.OpenCL)
+ createOpenCLRuntime();
+ if (Features.CUDA)
+ createCUDARuntime();
// Enable TBAA unless it's suppressed.
if (!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0)
@@ -98,17 +104,20 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
Int8Ty = llvm::Type::getInt8Ty(LLVMContext);
Int32Ty = llvm::Type::getInt32Ty(LLVMContext);
Int64Ty = llvm::Type::getInt64Ty(LLVMContext);
- PointerWidthInBits = C.Target.getPointerWidth(0);
+ PointerWidthInBits = C.getTargetInfo().getPointerWidth(0);
PointerAlignInBytes =
- C.toCharUnitsFromBits(C.Target.getPointerAlign(0)).getQuantity();
- IntTy = llvm::IntegerType::get(LLVMContext, C.Target.getIntWidth());
+ C.toCharUnitsFromBits(C.getTargetInfo().getPointerAlign(0)).getQuantity();
+ IntTy = llvm::IntegerType::get(LLVMContext, C.getTargetInfo().getIntWidth());
IntPtrTy = llvm::IntegerType::get(LLVMContext, PointerWidthInBits);
Int8PtrTy = Int8Ty->getPointerTo(0);
Int8PtrPtrTy = Int8PtrTy->getPointerTo(0);
}
CodeGenModule::~CodeGenModule() {
- delete Runtime;
+ delete ObjCRuntime;
+ delete OpenCLRuntime;
+ delete CUDARuntime;
+ delete TheTargetCodeGenInfo;
delete &ABI;
delete TBAA;
delete DebugInfo;
@@ -118,21 +127,29 @@ CodeGenModule::~CodeGenModule() {
void CodeGenModule::createObjCRuntime() {
if (!Features.NeXTRuntime)
- Runtime = CreateGNUObjCRuntime(*this);
+ ObjCRuntime = CreateGNUObjCRuntime(*this);
else
- Runtime = CreateMacObjCRuntime(*this);
+ ObjCRuntime = CreateMacObjCRuntime(*this);
+}
+
+void CodeGenModule::createOpenCLRuntime() {
+ OpenCLRuntime = new CGOpenCLRuntime(*this);
+}
+
+void CodeGenModule::createCUDARuntime() {
+ CUDARuntime = CreateNVCUDARuntime(*this);
}
void CodeGenModule::Release() {
EmitDeferred();
EmitCXXGlobalInitFunc();
EmitCXXGlobalDtorFunc();
- if (Runtime)
- if (llvm::Function *ObjCInitFunction = Runtime->ModuleInitFunction())
+ if (ObjCRuntime)
+ if (llvm::Function *ObjCInitFunction = ObjCRuntime->ModuleInitFunction())
AddGlobalCtor(ObjCInitFunction);
EmitCtorList(GlobalCtors, "llvm.global_ctors");
EmitCtorList(GlobalDtors, "llvm.global_dtors");
- EmitAnnotations();
+ EmitGlobalAnnotations();
EmitLLVMUsed();
SimplifyPersonality();
@@ -142,6 +159,9 @@ void CodeGenModule::Release() {
if (getCodeGenOpts().EmitGcovArcs || getCodeGenOpts().EmitGcovNotes)
EmitCoverageFile();
+
+ if (DebugInfo)
+ DebugInfo->finalize();
}
void CodeGenModule::UpdateCompletedType(const TagDecl *TD) {
@@ -163,11 +183,11 @@ void CodeGenModule::DecorateInstruction(llvm::Instruction *Inst,
}
bool CodeGenModule::isTargetDarwin() const {
- return getContext().Target.getTriple().isOSDarwin();
+ return getContext().getTargetInfo().getTriple().isOSDarwin();
}
-void CodeGenModule::Error(SourceLocation loc, llvm::StringRef error) {
- unsigned diagID = getDiags().getCustomDiagID(Diagnostic::Error, error);
+void CodeGenModule::Error(SourceLocation loc, StringRef error) {
+ unsigned diagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, error);
getDiags().Report(Context.getFullLoc(loc), diagID);
}
@@ -177,7 +197,7 @@ void CodeGenModule::ErrorUnsupported(const Stmt *S, const char *Type,
bool OmitOnError) {
if (OmitOnError && getDiags().hasErrorOccurred())
return;
- unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Error,
+ unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
"cannot compile this %0 yet");
std::string Msg = Type;
getDiags().Report(Context.getFullLoc(S->getLocStart()), DiagID)
@@ -190,7 +210,7 @@ void CodeGenModule::ErrorUnsupported(const Decl *D, const char *Type,
bool OmitOnError) {
if (OmitOnError && getDiags().hasErrorOccurred())
return;
- unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Error,
+ unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
"cannot compile this %0 yet");
std::string Msg = Type;
getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID) << Msg;
@@ -281,10 +301,10 @@ void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV,
GV->setUnnamedAddr(true);
}
-llvm::StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
+StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
const NamedDecl *ND = cast<NamedDecl>(GD.getDecl());
- llvm::StringRef &Str = MangledDeclNames[GD.getCanonicalDecl()];
+ StringRef &Str = MangledDeclNames[GD.getCanonicalDecl()];
if (!Str.empty())
return Str;
@@ -313,7 +333,7 @@ llvm::StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
char *Name = MangledNamesAllocator.Allocate<char>(Length);
std::copy(Buffer.begin(), Buffer.end(), Name);
- Str = llvm::StringRef(Name, Length);
+ Str = StringRef(Name, Length);
return Str;
}
@@ -333,7 +353,7 @@ void CodeGenModule::getBlockMangledName(GlobalDecl GD, MangleBuffer &Buffer,
MangleCtx.mangleBlock(cast<DeclContext>(D), BD, Out);
}
-llvm::GlobalValue *CodeGenModule::GetGlobalValue(llvm::StringRef Name) {
+llvm::GlobalValue *CodeGenModule::GetGlobalValue(StringRef Name) {
return getModule().getNamedValue(Name);
}
@@ -380,22 +400,6 @@ void CodeGenModule::EmitCtorList(const CtorList &Fns, const char *GlobalName) {
}
}
-void CodeGenModule::EmitAnnotations() {
- if (Annotations.empty())
- return;
-
- // Create a new global variable for the ConstantStruct in the Module.
- llvm::Constant *Array =
- llvm::ConstantArray::get(llvm::ArrayType::get(Annotations[0]->getType(),
- Annotations.size()),
- Annotations);
- llvm::GlobalValue *gv =
- new llvm::GlobalVariable(TheModule, Array->getType(), false,
- llvm::GlobalValue::AppendingLinkage, Array,
- "llvm.global.annotations");
- gv->setSection("llvm.metadata");
-}
-
llvm::GlobalValue::LinkageTypes
CodeGenModule::getFunctionLinkage(const FunctionDecl *D) {
GVALinkage Linkage = getContext().GetGVALinkageForFunction(D);
@@ -413,7 +417,12 @@ CodeGenModule::getFunctionLinkage(const FunctionDecl *D) {
// definition somewhere else, so we can use available_externally linkage.
if (Linkage == GVA_C99Inline)
return llvm::Function::AvailableExternallyLinkage;
-
+
+ // Note that Apple's kernel linker doesn't support symbol
+ // coalescing, so we need to avoid linkonce and weak linkages there.
+ // Normally, this means we just map to internal, but for explicit
+ // instantiations we'll map to external.
+
// In C++, the compiler has to emit a definition in every translation unit
// that references the function. We should use linkonce_odr because
// a) if all references in this translation unit are optimized away, we
@@ -432,7 +441,7 @@ CodeGenModule::getFunctionLinkage(const FunctionDecl *D) {
if (Linkage == GVA_ExplicitTemplateInstantiation)
return !Context.getLangOptions().AppleKext
? llvm::Function::WeakODRLinkage
- : llvm::Function::InternalLinkage;
+ : llvm::Function::ExternalLinkage;
// Otherwise, we have strong external linkage.
assert(Linkage == GVA_StrongExternal);
@@ -460,29 +469,54 @@ void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D,
F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
}
+/// Determines whether the language options require us to model
+/// unwind exceptions. We treat -fexceptions as mandating this
+/// except under the fragile ObjC ABI with only ObjC exceptions
+/// enabled. This means, for example, that C with -fexceptions
+/// enables this.
+static bool hasUnwindExceptions(const LangOptions &Features) {
+ // If exceptions are completely disabled, obviously this is false.
+ if (!Features.Exceptions) return false;
+
+ // If C++ exceptions are enabled, this is true.
+ if (Features.CXXExceptions) return true;
+
+ // If ObjC exceptions are enabled, this depends on the ABI.
+ if (Features.ObjCExceptions) {
+ if (!Features.ObjCNonFragileABI) return false;
+ }
+
+ return true;
+}
+
void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
llvm::Function *F) {
if (CodeGenOpts.UnwindTables)
F->setHasUWTable();
- if (!Features.Exceptions && !Features.ObjCNonFragileABI)
+ if (!hasUnwindExceptions(Features))
F->addFnAttr(llvm::Attribute::NoUnwind);
- if (D->hasAttr<AlwaysInlineAttr>())
- F->addFnAttr(llvm::Attribute::AlwaysInline);
-
- if (D->hasAttr<NakedAttr>())
+ if (D->hasAttr<NakedAttr>()) {
+ // Naked implies noinline: we should not be inlining such functions.
F->addFnAttr(llvm::Attribute::Naked);
+ F->addFnAttr(llvm::Attribute::NoInline);
+ }
if (D->hasAttr<NoInlineAttr>())
F->addFnAttr(llvm::Attribute::NoInline);
+ // (noinline wins over always_inline, and we can't specify both in IR)
+ if (D->hasAttr<AlwaysInlineAttr>() &&
+ !F->hasFnAttr(llvm::Attribute::NoInline))
+ F->addFnAttr(llvm::Attribute::AlwaysInline);
+
if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D))
F->setUnnamedAddr(true);
- if (Features.getStackProtectorMode() == LangOptions::SSPOn)
+ if (Features.getStackProtector() == LangOptions::SSPOn)
F->addFnAttr(llvm::Attribute::StackProtect);
- else if (Features.getStackProtectorMode() == LangOptions::SSPReq)
+ else if (Features.getStackProtector() == LangOptions::SSPReq)
F->addFnAttr(llvm::Attribute::StackProtectReq);
unsigned alignment = D->getMaxAlignment() / Context.getCharWidth();
@@ -570,7 +604,7 @@ void CodeGenModule::EmitLLVMUsed() {
if (LLVMUsed.empty())
return;
- const llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext);
+ llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext);
// Convert LLVMUsed to what ConstantArray needs.
std::vector<llvm::Constant*> UsedArray;
@@ -597,7 +631,7 @@ void CodeGenModule::EmitLLVMUsed() {
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.
+ // for a static function, iterate until no changes are made.
while (!DeferredDeclsToEmit.empty() || !DeferredVTables.empty()) {
if (!DeferredVTables.empty()) {
@@ -618,7 +652,7 @@ void CodeGenModule::EmitDeferred() {
// ignore these cases.
//
// TODO: That said, looking this up multiple times is very wasteful.
- llvm::StringRef Name = getMangledName(D);
+ StringRef Name = getMangledName(D);
llvm::GlobalValue *CGRef = GetGlobalValue(Name);
assert(CGRef && "Deferred decl wasn't referenced?");
@@ -635,54 +669,78 @@ void CodeGenModule::EmitDeferred() {
}
}
-/// EmitAnnotateAttr - Generate the llvm::ConstantStruct which contains the
-/// annotation information for a given GlobalValue. The annotation struct is
-/// {i8 *, i8 *, i8 *, i32}. The first field is a constant expression, the
-/// GlobalValue being annotated. The second field is the constant string
-/// created from the AnnotateAttr's annotation. The third field is a constant
-/// string containing the name of the translation unit. The fourth field is
-/// the line number in the file of the annotated value declaration.
-///
-/// FIXME: this does not unique the annotation string constants, as llvm-gcc
-/// appears to.
-///
+void CodeGenModule::EmitGlobalAnnotations() {
+ if (Annotations.empty())
+ return;
+
+ // Create a new global variable for the ConstantStruct in the Module.
+ llvm::Constant *Array = llvm::ConstantArray::get(llvm::ArrayType::get(
+ Annotations[0]->getType(), Annotations.size()), Annotations);
+ llvm::GlobalValue *gv = new llvm::GlobalVariable(getModule(),
+ Array->getType(), false, llvm::GlobalValue::AppendingLinkage, Array,
+ "llvm.global.annotations");
+ gv->setSection(AnnotationSection);
+}
+
+llvm::Constant *CodeGenModule::EmitAnnotationString(llvm::StringRef Str) {
+ llvm::StringMap<llvm::Constant*>::iterator i = AnnotationStrings.find(Str);
+ if (i != AnnotationStrings.end())
+ return i->second;
+
+ // Not found yet, create a new global.
+ llvm::Constant *s = llvm::ConstantArray::get(getLLVMContext(), Str, true);
+ llvm::GlobalValue *gv = new llvm::GlobalVariable(getModule(), s->getType(),
+ true, llvm::GlobalValue::PrivateLinkage, s, ".str");
+ gv->setSection(AnnotationSection);
+ gv->setUnnamedAddr(true);
+ AnnotationStrings[Str] = gv;
+ return gv;
+}
+
+llvm::Constant *CodeGenModule::EmitAnnotationUnit(SourceLocation Loc) {
+ SourceManager &SM = getContext().getSourceManager();
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+ if (PLoc.isValid())
+ return EmitAnnotationString(PLoc.getFilename());
+ return EmitAnnotationString(SM.getBufferName(Loc));
+}
+
+llvm::Constant *CodeGenModule::EmitAnnotationLineNo(SourceLocation L) {
+ SourceManager &SM = getContext().getSourceManager();
+ PresumedLoc PLoc = SM.getPresumedLoc(L);
+ unsigned LineNo = PLoc.isValid() ? PLoc.getLine() :
+ SM.getExpansionLineNumber(L);
+ return llvm::ConstantInt::get(Int32Ty, LineNo);
+}
+
llvm::Constant *CodeGenModule::EmitAnnotateAttr(llvm::GlobalValue *GV,
const AnnotateAttr *AA,
- unsigned LineNo) {
- llvm::Module *M = &getModule();
-
- // get [N x i8] constants for the annotation string, and the filename string
- // which are the 2nd and 3rd elements of the global annotation structure.
- const llvm::Type *SBP = llvm::Type::getInt8PtrTy(VMContext);
- llvm::Constant *anno = llvm::ConstantArray::get(VMContext,
- AA->getAnnotation(), true);
- llvm::Constant *unit = llvm::ConstantArray::get(VMContext,
- M->getModuleIdentifier(),
- true);
-
- // Get the two global values corresponding to the ConstantArrays we just
- // created to hold the bytes of the strings.
- llvm::GlobalValue *annoGV =
- new llvm::GlobalVariable(*M, anno->getType(), false,
- llvm::GlobalValue::PrivateLinkage, anno,
- GV->getName());
- // translation unit name string, emitted into the llvm.metadata section.
- llvm::GlobalValue *unitGV =
- new llvm::GlobalVariable(*M, unit->getType(), false,
- llvm::GlobalValue::PrivateLinkage, unit,
- ".str");
- unitGV->setUnnamedAddr(true);
+ SourceLocation L) {
+ // Get the globals for file name, annotation, and the line number.
+ llvm::Constant *AnnoGV = EmitAnnotationString(AA->getAnnotation()),
+ *UnitGV = EmitAnnotationUnit(L),
+ *LineNoCst = EmitAnnotationLineNo(L);
// Create the ConstantStruct for the global annotation.
llvm::Constant *Fields[4] = {
- llvm::ConstantExpr::getBitCast(GV, SBP),
- llvm::ConstantExpr::getBitCast(annoGV, SBP),
- llvm::ConstantExpr::getBitCast(unitGV, SBP),
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), LineNo)
+ llvm::ConstantExpr::getBitCast(GV, Int8PtrTy),
+ llvm::ConstantExpr::getBitCast(AnnoGV, Int8PtrTy),
+ llvm::ConstantExpr::getBitCast(UnitGV, Int8PtrTy),
+ LineNoCst
};
return llvm::ConstantStruct::getAnon(Fields);
}
+void CodeGenModule::AddGlobalAnnotations(const ValueDecl *D,
+ llvm::GlobalValue *GV) {
+ assert(D->hasAttr<AnnotateAttr>() && "no annotate attribute");
+ // Get the struct elements for these annotations.
+ for (specific_attr_iterator<AnnotateAttr>
+ ai = D->specific_attr_begin<AnnotateAttr>(),
+ ae = D->specific_attr_end<AnnotateAttr>(); ai != ae; ++ai)
+ Annotations.push_back(EmitAnnotateAttr(GV, *ai, D->getLocation()));
+}
+
bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
// Never defer when EmitAllDecls is specified.
if (Features.EmitAllDecls)
@@ -695,7 +753,7 @@ llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) {
const AliasAttr *AA = VD->getAttr<AliasAttr>();
assert(AA && "No alias?");
- const llvm::Type *DeclTy = getTypes().ConvertTypeForMem(VD->getType());
+ llvm::Type *DeclTy = getTypes().ConvertTypeForMem(VD->getType());
// See if there is already something with the target's name in the module.
llvm::GlobalValue *Entry = GetGlobalValue(AA->getAliasee());
@@ -728,34 +786,45 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
if (Global->hasAttr<AliasAttr>())
return EmitAliasDefinition(GD);
- // Ignore declarations, they will be emitted on their first use.
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Global)) {
- if (FD->getIdentifier()) {
- llvm::StringRef Name = FD->getName();
- if (Name == "_Block_object_assign") {
- BlockObjectAssignDecl = FD;
- } else if (Name == "_Block_object_dispose") {
- BlockObjectDisposeDecl = FD;
- }
+ // If this is CUDA, be selective about which declarations we emit.
+ if (Features.CUDA) {
+ if (CodeGenOpts.CUDAIsDevice) {
+ if (!Global->hasAttr<CUDADeviceAttr>() &&
+ !Global->hasAttr<CUDAGlobalAttr>() &&
+ !Global->hasAttr<CUDAConstantAttr>() &&
+ !Global->hasAttr<CUDASharedAttr>())
+ return;
+ } else {
+ if (!Global->hasAttr<CUDAHostAttr>() && (
+ Global->hasAttr<CUDADeviceAttr>() ||
+ Global->hasAttr<CUDAConstantAttr>() ||
+ Global->hasAttr<CUDASharedAttr>()))
+ return;
}
+ }
+ // Ignore declarations, they will be emitted on their first use.
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Global)) {
// Forward declarations are emitted lazily on first use.
- if (!FD->doesThisDeclarationHaveABody())
+ if (!FD->doesThisDeclarationHaveABody()) {
+ if (!FD->doesDeclarationForceExternallyVisibleDefinition())
+ return;
+
+ const FunctionDecl *InlineDefinition = 0;
+ FD->getBody(InlineDefinition);
+
+ StringRef MangledName = getMangledName(GD);
+ llvm::StringMap<GlobalDecl>::iterator DDI =
+ DeferredDecls.find(MangledName);
+ if (DDI != DeferredDecls.end())
+ DeferredDecls.erase(DDI);
+ EmitGlobalDefinition(InlineDefinition);
return;
+ }
} else {
const VarDecl *VD = cast<VarDecl>(Global);
assert(VD->isFileVarDecl() && "Cannot emit local var decl as global.");
- if (VD->getIdentifier()) {
- llvm::StringRef Name = VD->getName();
- if (Name == "_NSConcreteGlobalBlock") {
- NSConcreteGlobalBlockDecl = VD;
- } else if (Name == "_NSConcreteStackBlock") {
- NSConcreteStackBlockDecl = VD;
- }
- }
-
-
if (VD->isThisDeclarationADefinition() != VarDecl::Definition)
return;
}
@@ -778,7 +847,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
// If the value has already been used, add it directly to the
// DeferredDeclsToEmit list.
- llvm::StringRef MangledName = getMangledName(GD);
+ StringRef MangledName = getMangledName(GD);
if (GetGlobalValue(MangledName))
DeferredDeclsToEmit.push_back(GD);
else {
@@ -827,7 +896,7 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
return EmitGlobalVarDefinition(VD);
- assert(0 && "Invalid argument to EmitGlobalDefinition()");
+ llvm_unreachable("Invalid argument to EmitGlobalDefinition()");
}
/// GetOrCreateLLVMFunction - If the specified mangled name is not in the
@@ -838,8 +907,8 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
/// If D is non-null, it specifies a decl that correspond to this. This is used
/// to set the attributes on the function when it is first created.
llvm::Constant *
-CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
- const llvm::Type *Ty,
+CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
+ llvm::Type *Ty,
GlobalDecl D, bool ForVTable,
llvm::Attributes ExtraAttrs) {
// Lookup the entry, lazily creating it if necessary.
@@ -865,7 +934,7 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
// sure not to try to set attributes.
bool IsIncompleteFunction = false;
- const llvm::FunctionType *FTy;
+ llvm::FunctionType *FTy;
if (isa<llvm::FunctionType>(Ty)) {
FTy = cast<llvm::FunctionType>(Ty);
} else {
@@ -935,21 +1004,21 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
/// non-null, then this function will use the specified type if it has to
/// create it (this occurs when we see a definition of the function).
llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD,
- const llvm::Type *Ty,
+ llvm::Type *Ty,
bool ForVTable) {
// If there was no specific requested type, just convert it now.
if (!Ty)
Ty = getTypes().ConvertType(cast<ValueDecl>(GD.getDecl())->getType());
- llvm::StringRef MangledName = getMangledName(GD);
+ StringRef MangledName = getMangledName(GD);
return GetOrCreateLLVMFunction(MangledName, Ty, GD, ForVTable);
}
/// CreateRuntimeFunction - Create a new runtime function with the specified
/// type and name.
llvm::Constant *
-CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy,
- llvm::StringRef Name,
+CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy,
+ StringRef Name,
llvm::Attributes ExtraAttrs) {
return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false,
ExtraAttrs);
@@ -979,8 +1048,8 @@ static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D,
/// If D is non-null, it specifies a decl that correspond to this. This is used
/// to set the attributes on the global when it is first created.
llvm::Constant *
-CodeGenModule::GetOrCreateLLVMGlobal(llvm::StringRef MangledName,
- const llvm::PointerType *Ty,
+CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
+ llvm::PointerType *Ty,
const VarDecl *D,
bool UnnamedAddr) {
// Lookup the entry, lazily creating it if necessary.
@@ -1049,8 +1118,8 @@ CodeGenModule::GetOrCreateLLVMGlobal(llvm::StringRef MangledName,
llvm::GlobalVariable *
-CodeGenModule::CreateOrReplaceCXXRuntimeVariable(llvm::StringRef Name,
- const llvm::Type *Ty,
+CodeGenModule::CreateOrReplaceCXXRuntimeVariable(StringRef Name,
+ llvm::Type *Ty,
llvm::GlobalValue::LinkageTypes Linkage) {
llvm::GlobalVariable *GV = getModule().getNamedGlobal(Name);
llvm::GlobalVariable *OldGV = 0;
@@ -1092,24 +1161,24 @@ CodeGenModule::CreateOrReplaceCXXRuntimeVariable(llvm::StringRef Name,
/// then it will be greated with the specified type instead of whatever the
/// normal requested type would be.
llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D,
- const llvm::Type *Ty) {
+ llvm::Type *Ty) {
assert(D->hasGlobalStorage() && "Not a global variable");
QualType ASTTy = D->getType();
if (Ty == 0)
Ty = getTypes().ConvertTypeForMem(ASTTy);
- const llvm::PointerType *PTy =
+ llvm::PointerType *PTy =
llvm::PointerType::get(Ty, getContext().getTargetAddressSpace(ASTTy));
- llvm::StringRef MangledName = getMangledName(D);
+ StringRef MangledName = getMangledName(D);
return GetOrCreateLLVMGlobal(MangledName, PTy, D);
}
/// CreateRuntimeVariable - Create a new runtime global variable with the
/// specified type and name.
llvm::Constant *
-CodeGenModule::CreateRuntimeVariable(const llvm::Type *Ty,
- llvm::StringRef Name) {
+CodeGenModule::CreateRuntimeVariable(llvm::Type *Ty,
+ StringRef Name) {
return GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), 0,
true);
}
@@ -1121,7 +1190,7 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
// If we have not seen a reference to this variable yet, place it
// into the deferred declarations table to be emitted if needed
// later.
- llvm::StringRef MangledName = getMangledName(D);
+ StringRef MangledName = getMangledName(D);
if (!GetGlobalValue(MangledName)) {
DeferredDecls[MangledName] = D;
return;
@@ -1207,7 +1276,7 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
return llvm::GlobalVariable::LinkOnceODRLinkage;
}
-CharUnits CodeGenModule::GetTargetTypeStoreSize(const llvm::Type *Ty) const {
+CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const {
return Context.toCharUnitsFromBits(
TheTargetData.getTypeStoreSizeInBits(Ty));
}
@@ -1253,7 +1322,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
}
}
- const llvm::Type* InitType = Init->getType();
+ llvm::Type* InitType = Init->getType();
llvm::Constant *Entry = GetAddrOfGlobalVar(D, InitType);
// Strip off a bitcast if we got one back.
@@ -1282,7 +1351,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
getContext().getTargetAddressSpace(ASTTy)) {
// Move the old entry aside so that we'll create a new one.
- Entry->setName(llvm::StringRef());
+ Entry->setName(StringRef());
// Make a new global with the correct type, this is now guaranteed to work.
GV = cast<llvm::GlobalVariable>(GetAddrOfGlobalVar(D, InitType));
@@ -1296,11 +1365,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
cast<llvm::GlobalValue>(Entry)->eraseFromParent();
}
- if (const AnnotateAttr *AA = D->getAttr<AnnotateAttr>()) {
- SourceManager &SM = Context.getSourceManager();
- AddAnnotation(EmitAnnotateAttr(GV, AA,
- SM.getInstantiationLineNumber(D->getLocation())));
- }
+ if (D->hasAttr<AnnotateAttr>())
+ AddGlobalAnnotations(D, GV);
GV->setInitializer(Init);
@@ -1326,10 +1392,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
EmitCXXGlobalVarDeclInitFunc(D, GV);
// Emit global variable debug information.
- if (CGDebugInfo *DI = getModuleDebugInfo()) {
- DI->setLocation(D->getLocation());
+ if (CGDebugInfo *DI = getModuleDebugInfo())
DI->EmitGlobalVariable(GV, D);
- }
}
llvm::GlobalValue::LinkageTypes
@@ -1377,8 +1441,8 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
llvm::Function *OldFn = dyn_cast<llvm::Function>(Old);
if (OldFn == 0) return;
- const llvm::Type *NewRetTy = NewFn->getReturnType();
- llvm::SmallVector<llvm::Value*, 4> ArgList;
+ 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; ) {
@@ -1394,6 +1458,17 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
if (CI->getType() != NewRetTy && !CI->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)
+ AttrVec.push_back(llvm::AttributeWithIndex::get(0, 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.
@@ -1406,10 +1481,17 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
DontTransform = true;
break;
}
+
+ // Add any parameter attributes.
+ if (llvm::Attributes PAttrs = AttrList.getParamAttributes(ArgNo + 1))
+ AttrVec.push_back(llvm::AttributeWithIndex::get(ArgNo + 1, PAttrs));
}
if (DontTransform)
continue;
+ if (llvm::Attributes FnAttrs = AttrList.getFnAttributes())
+ AttrVec.push_back(llvm::AttributeWithIndex::get(~0, FnAttrs));
+
// 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);
@@ -1417,7 +1499,8 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
ArgList.clear();
if (!NewCall->getType()->isVoidTy())
NewCall->takeName(CI);
- NewCall->setAttributes(CI->getAttributes());
+ NewCall->setAttributes(llvm::AttrListPtr::get(AttrVec.begin(),
+ AttrVec.end()));
NewCall->setCallingConv(CI->getCallingConv());
// Finally, remove the old call, replacing any uses with the new one.
@@ -1440,7 +1523,7 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
bool variadic = false;
if (const FunctionProtoType *fpt = D->getType()->getAs<FunctionProtoType>())
variadic = fpt->isVariadic();
- const llvm::FunctionType *Ty = getTypes().GetFunctionType(FI, variadic);
+ llvm::FunctionType *Ty = getTypes().GetFunctionType(FI, variadic);
// Get or create the prototype for the function.
llvm::Constant *Entry = GetAddrOfFunction(GD, Ty);
@@ -1467,7 +1550,7 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
// (e.g. "int f()") and then a definition of a different type
// (e.g. "int f(int x)"). Move the old function aside so that it
// doesn't interfere with GetAddrOfFunction.
- OldFn->setName(llvm::StringRef());
+ 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
@@ -1510,6 +1593,8 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
AddGlobalCtor(Fn, CA->getPriority());
if (const DestructorAttr *DA = D->getAttr<DestructorAttr>())
AddGlobalDtor(Fn, DA->getPriority());
+ if (D->hasAttr<AnnotateAttr>())
+ AddGlobalAnnotations(D, Fn);
}
void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
@@ -1517,7 +1602,7 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
const AliasAttr *AA = D->getAttr<AliasAttr>();
assert(AA && "Not an alias?");
- llvm::StringRef MangledName = getMangledName(GD);
+ StringRef MangledName = getMangledName(GD);
// If there is a definition in the module, then it wins over the alias.
// This is dubious, but allow it to be safe. Just ignore the alias.
@@ -1525,7 +1610,7 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
if (Entry && !Entry->isDeclaration())
return;
- const llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType());
+ llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType());
// Create a reference to the named value. This ensures that it is emitted
// if a deferred decl.
@@ -1582,37 +1667,8 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
SetCommonAttributes(D, GA);
}
-/// getBuiltinLibFunction - Given a builtin id for a function like
-/// "__builtin_fabsf", return a Function* for "fabsf".
-llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD,
- unsigned BuiltinID) {
- assert((Context.BuiltinInfo.isLibFunction(BuiltinID) ||
- Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) &&
- "isn't a lib fn");
-
- // Get the name, skip over the __builtin_ prefix (if necessary).
- llvm::StringRef Name;
- GlobalDecl D(FD);
-
- // If the builtin has been declared explicitly with an assembler label,
- // use the mangled name. This differs from the plain label on platforms
- // that prefix labels.
- if (FD->hasAttr<AsmLabelAttr>())
- Name = getMangledName(D);
- else if (Context.BuiltinInfo.isLibFunction(BuiltinID))
- Name = Context.BuiltinInfo.GetName(BuiltinID) + 10;
- else
- Name = Context.BuiltinInfo.GetName(BuiltinID);
-
-
- const llvm::FunctionType *Ty =
- cast<llvm::FunctionType>(getTypes().ConvertType(FD->getType()));
-
- return GetOrCreateLLVMFunction(Name, Ty, D, /*ForVTable=*/false);
-}
-
llvm::Function *CodeGenModule::getIntrinsic(unsigned IID,
- llvm::ArrayRef<llvm::Type*> Tys) {
+ ArrayRef<llvm::Type*> Tys) {
return llvm::Intrinsic::getDeclaration(&getModule(), (llvm::Intrinsic::ID)IID,
Tys);
}
@@ -1623,7 +1679,7 @@ GetConstantCFStringEntry(llvm::StringMap<llvm::Constant*> &Map,
bool TargetIsLSB,
bool &IsUTF16,
unsigned &StringLength) {
- llvm::StringRef String = Literal->getString();
+ StringRef String = Literal->getString();
unsigned NumBytes = String.size();
// Check for simple case.
@@ -1633,7 +1689,7 @@ GetConstantCFStringEntry(llvm::StringMap<llvm::Constant*> &Map,
}
// Otherwise, convert the UTF8 literals into a byte string.
- llvm::SmallVector<UTF16, 128> ToBuf(NumBytes);
+ SmallVector<UTF16, 128> ToBuf(NumBytes);
const UTF8 *FromPtr = (UTF8 *)String.data();
UTF16 *ToPtr = &ToBuf[0];
@@ -1665,7 +1721,7 @@ GetConstantCFStringEntry(llvm::StringMap<llvm::Constant*> &Map,
AsBytes.push_back(0);
IsUTF16 = true;
- return Map.GetOrCreateValue(llvm::StringRef(AsBytes.data(), AsBytes.size()));
+ return Map.GetOrCreateValue(StringRef(AsBytes.data(), AsBytes.size()));
}
static llvm::StringMapEntry<llvm::Constant*> &
@@ -1673,7 +1729,7 @@ GetConstantStringEntry(llvm::StringMap<llvm::Constant*> &Map,
const StringLiteral *Literal,
unsigned &StringLength)
{
- llvm::StringRef String = Literal->getString();
+ StringRef String = Literal->getString();
StringLength = String.size();
return Map.GetOrCreateValue(String);
}
@@ -1696,18 +1752,18 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
// If we don't already have it, get __CFConstantStringClassReference.
if (!CFConstantStringClassRef) {
- const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy);
+ llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy);
Ty = llvm::ArrayType::get(Ty, 0);
llvm::Constant *GV = CreateRuntimeVariable(Ty,
"__CFConstantStringClassReference");
// Decay array -> ptr
CFConstantStringClassRef =
- llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
+ llvm::ConstantExpr::getGetElementPtr(GV, Zeros);
}
QualType CFTy = getContext().getCFConstantStringType();
- const llvm::StructType *STy =
+ llvm::StructType *STy =
cast<llvm::StructType>(getTypes().ConvertType(CFTy));
std::vector<llvm::Constant*> Fields(4);
@@ -1716,7 +1772,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
Fields[0] = CFConstantStringClassRef;
// Flags.
- const llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy);
+ llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy);
Fields[1] = isUTF16 ? llvm::ConstantInt::get(Ty, 0x07d0) :
llvm::ConstantInt::get(Ty, 0x07C8);
@@ -1750,7 +1806,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy);
GV->setAlignment(Align.getQuantity());
}
- Fields[2] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
+ Fields[2] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros);
// String length.
Ty = getTypes().ConvertType(getContext().LongTy);
@@ -1761,13 +1817,23 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
GV = new llvm::GlobalVariable(getModule(), C->getType(), true,
llvm::GlobalVariable::PrivateLinkage, C,
"_unnamed_cfstring_");
- if (const char *Sect = getContext().Target.getCFStringSection())
+ if (const char *Sect = getContext().getTargetInfo().getCFStringSection())
GV->setSection(Sect);
Entry.setValue(GV);
return GV;
}
+static RecordDecl *
+CreateRecordDecl(const ASTContext &Ctx, RecordDecl::TagKind TK,
+ DeclContext *DC, IdentifierInfo *Id) {
+ SourceLocation Loc;
+ if (Ctx.getLangOptions().CPlusPlus)
+ return CXXRecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id);
+ else
+ return RecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id);
+}
+
llvm::Constant *
CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
unsigned StringLength = 0;
@@ -1784,7 +1850,7 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
// If we don't already have it, get _NSConstantStringClassReference.
if (!ConstantStringClassRef) {
std::string StringClass(getLangOptions().ObjCConstantStringClass);
- const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy);
+ llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy);
llvm::Constant *GV;
if (Features.ObjCNonFragileABI) {
std::string str =
@@ -1792,25 +1858,54 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
: "OBJC_CLASS_$_" + StringClass;
GV = getObjCRuntime().GetClassGlobal(str);
// Make sure the result is of the correct type.
- const llvm::Type *PTy = llvm::PointerType::getUnqual(Ty);
+ llvm::Type *PTy = llvm::PointerType::getUnqual(Ty);
ConstantStringClassRef =
llvm::ConstantExpr::getBitCast(GV, PTy);
} else {
std::string str =
StringClass.empty() ? "_NSConstantStringClassReference"
: "_" + StringClass + "ClassReference";
- const llvm::Type *PTy = llvm::ArrayType::get(Ty, 0);
+ llvm::Type *PTy = llvm::ArrayType::get(Ty, 0);
GV = CreateRuntimeVariable(PTy, str);
// Decay array -> ptr
ConstantStringClassRef =
- llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
+ llvm::ConstantExpr::getGetElementPtr(GV, Zeros);
}
}
-
- QualType NSTy = getContext().getNSConstantStringType();
-
- const llvm::StructType *STy =
- cast<llvm::StructType>(getTypes().ConvertType(NSTy));
+
+ if (!NSConstantStringType) {
+ // Construct the type for a constant NSString.
+ RecordDecl *D = CreateRecordDecl(Context, TTK_Struct,
+ Context.getTranslationUnitDecl(),
+ &Context.Idents.get("__builtin_NSString"));
+ D->startDefinition();
+
+ QualType FieldTypes[3];
+
+ // const int *isa;
+ FieldTypes[0] = Context.getPointerType(Context.IntTy.withConst());
+ // const char *str;
+ FieldTypes[1] = Context.getPointerType(Context.CharTy.withConst());
+ // unsigned int length;
+ FieldTypes[2] = Context.UnsignedIntTy;
+
+ // Create fields
+ for (unsigned i = 0; i < 3; ++i) {
+ FieldDecl *Field = FieldDecl::Create(Context, D,
+ SourceLocation(),
+ SourceLocation(), 0,
+ FieldTypes[i], /*TInfo=*/0,
+ /*BitWidth=*/0,
+ /*Mutable=*/false,
+ /*HasInit=*/false);
+ Field->setAccess(AS_public);
+ D->addDecl(Field);
+ }
+
+ D->completeDefinition();
+ QualType NSTy = Context.getTagDeclType(D);
+ NSConstantStringType = cast<llvm::StructType>(getTypes().ConvertType(NSTy));
+ }
std::vector<llvm::Constant*> Fields(3);
@@ -1831,28 +1926,63 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
GV->setUnnamedAddr(true);
CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy);
GV->setAlignment(Align.getQuantity());
- Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
+ Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros);
// String length.
- const llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy);
+ llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy);
Fields[2] = llvm::ConstantInt::get(Ty, StringLength);
// The struct.
- C = llvm::ConstantStruct::get(STy, Fields);
+ C = llvm::ConstantStruct::get(NSConstantStringType, Fields);
GV = new llvm::GlobalVariable(getModule(), C->getType(), true,
llvm::GlobalVariable::PrivateLinkage, C,
"_unnamed_nsstring_");
// FIXME. Fix section.
if (const char *Sect =
Features.ObjCNonFragileABI
- ? getContext().Target.getNSStringNonFragileABISection()
- : getContext().Target.getNSStringSection())
+ ? getContext().getTargetInfo().getNSStringNonFragileABISection()
+ : getContext().getTargetInfo().getNSStringSection())
GV->setSection(Sect);
Entry.setValue(GV);
return GV;
}
+QualType CodeGenModule::getObjCFastEnumerationStateType() {
+ if (ObjCFastEnumerationStateType.isNull()) {
+ RecordDecl *D = CreateRecordDecl(Context, TTK_Struct,
+ Context.getTranslationUnitDecl(),
+ &Context.Idents.get("__objcFastEnumerationState"));
+ D->startDefinition();
+
+ QualType FieldTypes[] = {
+ Context.UnsignedLongTy,
+ Context.getPointerType(Context.getObjCIdType()),
+ Context.getPointerType(Context.UnsignedLongTy),
+ Context.getConstantArrayType(Context.UnsignedLongTy,
+ llvm::APInt(32, 5), ArrayType::Normal, 0)
+ };
+
+ for (size_t i = 0; i < 4; ++i) {
+ FieldDecl *Field = FieldDecl::Create(Context,
+ D,
+ SourceLocation(),
+ SourceLocation(), 0,
+ FieldTypes[i], /*TInfo=*/0,
+ /*BitWidth=*/0,
+ /*Mutable=*/false,
+ /*HasInit=*/false);
+ Field->setAccess(AS_public);
+ D->addDecl(Field);
+ }
+
+ D->completeDefinition();
+ ObjCFastEnumerationStateType = Context.getTagDeclType(D);
+ }
+
+ return ObjCFastEnumerationStateType;
+}
+
/// GetStringForStringLiteral - Return the appropriate bytes for a
/// string literal, properly padded to match the literal type.
std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) {
@@ -1864,8 +1994,20 @@ std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) {
// Resize the string to the right size.
uint64_t RealLen = CAT->getSize().getZExtValue();
- if (E->isWide())
- RealLen *= Context.Target.getWCharWidth() / Context.getCharWidth();
+ switch (E->getKind()) {
+ case StringLiteral::Ascii:
+ case StringLiteral::UTF8:
+ break;
+ case StringLiteral::Wide:
+ RealLen *= Context.getTargetInfo().getWCharWidth() / Context.getCharWidth();
+ break;
+ case StringLiteral::UTF16:
+ RealLen *= Context.getTargetInfo().getChar16Width() / Context.getCharWidth();
+ break;
+ case StringLiteral::UTF32:
+ RealLen *= Context.getTargetInfo().getChar32Width() / Context.getCharWidth();
+ break;
+ }
std::string Str = E->getString().str();
Str.resize(RealLen, '\0');
@@ -1879,8 +2021,11 @@ llvm::Constant *
CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) {
// FIXME: This can be more efficient.
// FIXME: We shouldn't need to bitcast the constant in the wide string case.
- llvm::Constant *C = GetAddrOfConstantString(GetStringForStringLiteral(S));
- if (S->isWide()) {
+ CharUnits Align = getContext().getTypeAlignInChars(S->getType());
+ llvm::Constant *C = GetAddrOfConstantString(GetStringForStringLiteral(S),
+ /* GlobalName */ 0,
+ Align.getQuantity());
+ if (S->isWide() || S->isUTF16() || S->isUTF32()) {
llvm::Type *DestTy =
llvm::PointerType::getUnqual(getTypes().ConvertType(S->getType()));
C = llvm::ConstantExpr::getBitCast(C, DestTy);
@@ -1900,10 +2045,11 @@ CodeGenModule::GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *E) {
/// GenerateWritableString -- Creates storage for a string literal.
-static llvm::Constant *GenerateStringLiteral(llvm::StringRef str,
+static llvm::GlobalVariable *GenerateStringLiteral(StringRef str,
bool constant,
CodeGenModule &CGM,
- const char *GlobalName) {
+ const char *GlobalName,
+ unsigned Alignment) {
// Create Constant for this string literal. Don't add a '\0'.
llvm::Constant *C =
llvm::ConstantArray::get(CGM.getLLVMContext(), str, false);
@@ -1913,7 +2059,7 @@ static llvm::Constant *GenerateStringLiteral(llvm::StringRef str,
new llvm::GlobalVariable(CGM.getModule(), C->getType(), constant,
llvm::GlobalValue::PrivateLinkage,
C, GlobalName);
- GV->setAlignment(1);
+ GV->setAlignment(Alignment);
GV->setUnnamedAddr(true);
return GV;
}
@@ -1926,8 +2072,9 @@ static llvm::Constant *GenerateStringLiteral(llvm::StringRef str,
/// Feature.WriteableStrings.
///
/// The result has pointer to array type.
-llvm::Constant *CodeGenModule::GetAddrOfConstantString(llvm::StringRef Str,
- const char *GlobalName) {
+llvm::Constant *CodeGenModule::GetAddrOfConstantString(StringRef Str,
+ const char *GlobalName,
+ unsigned Alignment) {
bool IsConstant = !Features.WritableStrings;
// Get the default prefix if a name wasn't specified.
@@ -1936,27 +2083,32 @@ llvm::Constant *CodeGenModule::GetAddrOfConstantString(llvm::StringRef Str,
// Don't share any string literals if strings aren't constant.
if (!IsConstant)
- return GenerateStringLiteral(Str, false, *this, GlobalName);
+ return GenerateStringLiteral(Str, false, *this, GlobalName, Alignment);
- llvm::StringMapEntry<llvm::Constant *> &Entry =
+ llvm::StringMapEntry<llvm::GlobalVariable *> &Entry =
ConstantStringMap.GetOrCreateValue(Str);
- if (Entry.getValue())
- return Entry.getValue();
+ if (llvm::GlobalVariable *GV = Entry.getValue()) {
+ if (Alignment > GV->getAlignment()) {
+ GV->setAlignment(Alignment);
+ }
+ return GV;
+ }
// Create a global variable for this.
- llvm::Constant *C = GenerateStringLiteral(Str, true, *this, GlobalName);
- Entry.setValue(C);
- return C;
+ llvm::GlobalVariable *GV = GenerateStringLiteral(Str, true, *this, GlobalName, Alignment);
+ Entry.setValue(GV);
+ return GV;
}
/// GetAddrOfConstantCString - Returns a pointer to a character
/// array containing the literal and a terminating '\0'
/// character. The result has pointer to array type.
llvm::Constant *CodeGenModule::GetAddrOfConstantCString(const std::string &Str,
- const char *GlobalName){
- llvm::StringRef StrWithNull(Str.c_str(), Str.size() + 1);
- return GetAddrOfConstantString(StrWithNull, GlobalName);
+ const char *GlobalName,
+ unsigned Alignment) {
+ StringRef StrWithNull(Str.c_str(), Str.size() + 1);
+ return GetAddrOfConstantString(StrWithNull, GlobalName, Alignment);
}
/// EmitObjCPropertyImplementations - Emit information for synthesized
@@ -1988,9 +2140,8 @@ void CodeGenModule::EmitObjCPropertyImplementations(const
}
static bool needsDestructMethod(ObjCImplementationDecl *impl) {
- ObjCInterfaceDecl *iface
- = const_cast<ObjCInterfaceDecl*>(impl->getClassInterface());
- for (ObjCIvarDecl *ivar = iface->all_declared_ivar_begin();
+ const ObjCInterfaceDecl *iface = impl->getClassInterface();
+ for (const ObjCIvarDecl *ivar = iface->all_declared_ivar_begin();
ivar; ivar = ivar->getNextIvar())
if (ivar->getType().isDestructedType())
return true;
@@ -2007,8 +2158,10 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
ObjCMethodDecl *DTORMethod =
ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(),
- cxxSelector, getContext().VoidTy, 0, D, true,
- false, true, false, ObjCMethodDecl::Required);
+ cxxSelector, getContext().VoidTy, 0, D,
+ /*isInstance=*/true, /*isVariadic=*/false,
+ /*isSynthesized=*/true, /*isImplicitlyDeclared=*/true,
+ /*isDefined=*/false, ObjCMethodDecl::Required);
D->addInstanceMethod(DTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false);
D->setHasCXXStructors(true);
@@ -2024,9 +2177,14 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
// The constructor returns 'self'.
ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(),
D->getLocation(),
- D->getLocation(), cxxSelector,
+ D->getLocation(),
+ cxxSelector,
getContext().getObjCIdType(), 0,
- D, true, false, true, false,
+ D, /*isInstance=*/true,
+ /*isVariadic=*/false,
+ /*isSynthesized=*/true,
+ /*isImplicitlyDeclared=*/true,
+ /*isDefined=*/false,
ObjCMethodDecl::Required);
D->addInstanceMethod(CTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
@@ -2134,13 +2292,13 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
}
case Decl::ObjCProtocol:
- Runtime->GenerateProtocol(cast<ObjCProtocolDecl>(D));
+ ObjCRuntime->GenerateProtocol(cast<ObjCProtocolDecl>(D));
break;
case Decl::ObjCCategoryImpl:
// Categories have properties but don't support synthesize so we
// can ignore them here.
- Runtime->GenerateCategory(cast<ObjCCategoryImplDecl>(D));
+ ObjCRuntime->GenerateCategory(cast<ObjCCategoryImplDecl>(D));
break;
case Decl::ObjCImplementation: {
@@ -2149,7 +2307,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
Context.ResetObjCLayout(OMD->getClassInterface());
EmitObjCPropertyImplementations(OMD);
EmitObjCIvarInitializations(OMD);
- Runtime->GenerateClass(OMD);
+ ObjCRuntime->GenerateClass(OMD);
break;
}
case Decl::ObjCMethod: {
@@ -2169,11 +2327,13 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::FileScopeAsm: {
FileScopeAsmDecl *AD = cast<FileScopeAsmDecl>(D);
- llvm::StringRef AsmString = AD->getAsmString()->getString();
+ StringRef AsmString = AD->getAsmString()->getString();
const std::string &S = getModule().getModuleInlineAsm();
if (S.empty())
getModule().setModuleInlineAsm(AsmString);
+ else if (*--S.end() == '\n')
+ getModule().setModuleInlineAsm(S + AsmString.str());
else
getModule().setModuleInlineAsm(S + '\n' + AsmString.str());
break;
@@ -2191,7 +2351,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
static llvm::Constant *GetPointerConstant(llvm::LLVMContext &Context,
const void *Ptr) {
uintptr_t PtrInt = reinterpret_cast<uintptr_t>(Ptr);
- const llvm::Type *i64 = llvm::Type::getInt64Ty(Context);
+ llvm::Type *i64 = llvm::Type::getInt64Ty(Context);
return llvm::ConstantInt::get(i64, PtrInt);
}
@@ -2222,7 +2382,7 @@ void CodeGenModule::EmitDeclMetadata() {
llvm::NamedMDNode *GlobalMetadata = 0;
// StaticLocalDeclMap
- for (llvm::DenseMap<GlobalDecl,llvm::StringRef>::iterator
+ for (llvm::DenseMap<GlobalDecl,StringRef>::iterator
I = MangledDeclNames.begin(), E = MangledDeclNames.end();
I != E; ++I) {
llvm::GlobalValue *Addr = getModule().getNamedValue(I->second);
@@ -2273,81 +2433,3 @@ void CodeGenModule::EmitCoverageFile() {
}
}
}
-
-///@name Custom Runtime Function Interfaces
-///@{
-//
-// FIXME: These can be eliminated once we can have clients just get the required
-// AST nodes from the builtin tables.
-
-llvm::Constant *CodeGenModule::getBlockObjectDispose() {
- if (BlockObjectDispose)
- return BlockObjectDispose;
-
- // If we saw an explicit decl, use that.
- if (BlockObjectDisposeDecl) {
- return BlockObjectDispose = GetAddrOfFunction(
- BlockObjectDisposeDecl,
- getTypes().GetFunctionType(BlockObjectDisposeDecl));
- }
-
- // Otherwise construct the function by hand.
- llvm::Type *args[] = { Int8PtrTy, Int32Ty };
- const llvm::FunctionType *fty
- = llvm::FunctionType::get(VoidTy, args, false);
- return BlockObjectDispose =
- CreateRuntimeFunction(fty, "_Block_object_dispose");
-}
-
-llvm::Constant *CodeGenModule::getBlockObjectAssign() {
- if (BlockObjectAssign)
- return BlockObjectAssign;
-
- // If we saw an explicit decl, use that.
- if (BlockObjectAssignDecl) {
- return BlockObjectAssign = GetAddrOfFunction(
- BlockObjectAssignDecl,
- getTypes().GetFunctionType(BlockObjectAssignDecl));
- }
-
- // Otherwise construct the function by hand.
- llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, Int32Ty };
- const llvm::FunctionType *fty
- = llvm::FunctionType::get(VoidTy, args, false);
- return BlockObjectAssign =
- CreateRuntimeFunction(fty, "_Block_object_assign");
-}
-
-llvm::Constant *CodeGenModule::getNSConcreteGlobalBlock() {
- if (NSConcreteGlobalBlock)
- return NSConcreteGlobalBlock;
-
- // If we saw an explicit decl, use that.
- if (NSConcreteGlobalBlockDecl) {
- return NSConcreteGlobalBlock = GetAddrOfGlobalVar(
- NSConcreteGlobalBlockDecl,
- getTypes().ConvertType(NSConcreteGlobalBlockDecl->getType()));
- }
-
- // Otherwise construct the variable by hand.
- return NSConcreteGlobalBlock =
- CreateRuntimeVariable(Int8PtrTy, "_NSConcreteGlobalBlock");
-}
-
-llvm::Constant *CodeGenModule::getNSConcreteStackBlock() {
- if (NSConcreteStackBlock)
- return NSConcreteStackBlock;
-
- // If we saw an explicit decl, use that.
- if (NSConcreteStackBlockDecl) {
- return NSConcreteStackBlock = GetAddrOfGlobalVar(
- NSConcreteStackBlockDecl,
- getTypes().ConvertType(NSConcreteStackBlockDecl->getType()));
- }
-
- // Otherwise construct the variable by hand.
- return NSConcreteStackBlock =
- CreateRuntimeVariable(Int8PtrTy, "_NSConcreteStackBlock");
-}
-
-///@}
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 86fb6d4d030e..8e38a8999013 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -62,7 +62,7 @@ namespace clang {
class VarDecl;
class LangOptions;
class CodeGenOptions;
- class Diagnostic;
+ class DiagnosticsEngine;
class AnnotateAttr;
class CXXDestructorDecl;
class MangleBuffer;
@@ -75,6 +75,8 @@ namespace CodeGen {
class CGCXXABI;
class CGDebugInfo;
class CGObjCRuntime;
+ class CGOpenCLRuntime;
+ class CGCUDARuntime;
class BlockFieldFlags;
class FunctionArgList;
@@ -129,8 +131,12 @@ namespace CodeGen {
/// The width of a pointer into the generic address space.
unsigned char PointerWidthInBits;
- /// The alignment of a pointer into the generic address space.
- unsigned char PointerAlignInBytes;
+ /// The size and alignment of a pointer into the generic address
+ /// space.
+ union {
+ unsigned char PointerAlignInBytes;
+ unsigned char PointerSizeInBytes;
+ };
};
struct RREntrypoints {
@@ -212,7 +218,7 @@ class CodeGenModule : public CodeGenTypeCache {
llvm::Module &TheModule;
const llvm::TargetData &TheTargetData;
mutable const TargetCodeGenInfo *TheTargetCodeGenInfo;
- Diagnostic &Diags;
+ DiagnosticsEngine &Diags;
CGCXXABI &ABI;
CodeGenTypes Types;
CodeGenTBAA *TBAA;
@@ -221,7 +227,9 @@ class CodeGenModule : public CodeGenTypeCache {
CodeGenVTables VTables;
friend class CodeGenVTables;
- CGObjCRuntime* Runtime;
+ CGObjCRuntime* ObjCRuntime;
+ CGOpenCLRuntime* OpenCLRuntime;
+ CGCUDARuntime* CUDARuntime;
CGDebugInfo* DebugInfo;
ARCEntrypoints *ARCData;
RREntrypoints *RRData;
@@ -257,13 +265,17 @@ class CodeGenModule : public CodeGenTypeCache {
CtorList GlobalDtors;
/// MangledDeclNames - A map of canonical GlobalDecls to their mangled names.
- llvm::DenseMap<GlobalDecl, llvm::StringRef> MangledDeclNames;
+ llvm::DenseMap<GlobalDecl, StringRef> MangledDeclNames;
llvm::BumpPtrAllocator MangledNamesAllocator;
+ /// Global annotations.
std::vector<llvm::Constant*> Annotations;
+ /// Map used to get unique annotation strings.
+ llvm::StringMap<llvm::Constant*> AnnotationStrings;
+
llvm::StringMap<llvm::Constant*> CFConstantStringMap;
- llvm::StringMap<llvm::Constant*> ConstantStringMap;
+ llvm::StringMap<llvm::GlobalVariable*> ConstantStringMap;
llvm::DenseMap<const Decl*, llvm::Value*> StaticLocalDeclMap;
/// CXXGlobalInits - Global variables with initializers that need to run
@@ -279,13 +291,16 @@ class CodeGenModule : public CodeGenTypeCache {
/// - Global variables with initializers whose order of initialization
/// is set by init_priority attribute.
- llvm::SmallVector<std::pair<OrderGlobalInits, llvm::Function*>, 8>
+ SmallVector<std::pair<OrderGlobalInits, llvm::Function*>, 8>
PrioritizedCXXGlobalInits;
/// CXXGlobalDtors - Global destructor functions and arguments that need to
/// run on termination.
std::vector<std::pair<llvm::WeakVH,llvm::Constant*> > CXXGlobalDtors;
+ /// @name Cache for Objective-C runtime types
+ /// @{
+
/// CFConstantStringClassRef - Cached reference to the class for constant
/// strings. This value has type int * but is actually an Obj-C class pointer.
llvm::Constant *CFConstantStringClassRef;
@@ -294,21 +309,29 @@ class CodeGenModule : public CodeGenTypeCache {
/// strings. This value has type int * but is actually an Obj-C class pointer.
llvm::Constant *ConstantStringClassRef;
+ /// \brief The LLVM type corresponding to NSConstantString.
+ llvm::StructType *NSConstantStringType;
+
+ /// \brief The type used to describe the state of a fast enumeration in
+ /// Objective-C's for..in loop.
+ QualType ObjCFastEnumerationStateType;
+
+ /// @}
+
/// Lazily create the Objective-C runtime
void createObjCRuntime();
+ void createOpenCLRuntime();
+ void createCUDARuntime();
+
llvm::LLVMContext &VMContext;
/// @name Cache for Blocks Runtime Globals
/// @{
- const VarDecl *NSConcreteGlobalBlockDecl;
- const VarDecl *NSConcreteStackBlockDecl;
llvm::Constant *NSConcreteGlobalBlock;
llvm::Constant *NSConcreteStackBlock;
- const FunctionDecl *BlockObjectAssignDecl;
- const FunctionDecl *BlockObjectDisposeDecl;
llvm::Constant *BlockObjectAssign;
llvm::Constant *BlockObjectDispose;
@@ -322,7 +345,8 @@ class CodeGenModule : public CodeGenTypeCache {
/// @}
public:
CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts,
- llvm::Module &M, const llvm::TargetData &TD, Diagnostic &Diags);
+ llvm::Module &M, const llvm::TargetData &TD,
+ DiagnosticsEngine &Diags);
~CodeGenModule();
@@ -332,13 +356,25 @@ public:
/// getObjCRuntime() - Return a reference to the configured
/// Objective-C runtime.
CGObjCRuntime &getObjCRuntime() {
- if (!Runtime) createObjCRuntime();
- return *Runtime;
+ if (!ObjCRuntime) createObjCRuntime();
+ return *ObjCRuntime;
}
/// hasObjCRuntime() - Return true iff an Objective-C runtime has
/// been configured.
- bool hasObjCRuntime() { return !!Runtime; }
+ bool hasObjCRuntime() { return !!ObjCRuntime; }
+
+ /// getOpenCLRuntime() - Return a reference to the configured OpenCL runtime.
+ CGOpenCLRuntime &getOpenCLRuntime() {
+ assert(OpenCLRuntime != 0);
+ return *OpenCLRuntime;
+ }
+
+ /// getCUDARuntime() - Return a reference to the configured CUDA runtime.
+ CGCUDARuntime &getCUDARuntime() {
+ assert(CUDARuntime != 0);
+ return *CUDARuntime;
+ }
/// getCXXABI() - Return a reference to the configured C++ ABI.
CGCXXABI &getCXXABI() { return ABI; }
@@ -369,9 +405,10 @@ public:
llvm::Module &getModule() const { return TheModule; }
CodeGenTypes &getTypes() { return Types; }
CodeGenVTables &getVTables() { return VTables; }
- Diagnostic &getDiags() const { return Diags; }
+ VTableContext &getVTableContext() { return VTables.getVTableContext(); }
+ DiagnosticsEngine &getDiags() const { return Diags; }
const llvm::TargetData &getTargetData() const { return TheTargetData; }
- const TargetInfo &getTarget() const { return Context.Target; }
+ const TargetInfo &getTarget() const { return Context.getTargetInfo(); }
llvm::LLVMContext &getLLVMContext() { return VMContext; }
const TargetCodeGenInfo &getTargetCodeGenInfo();
bool isTargetDarwin() const;
@@ -433,7 +470,7 @@ public:
/// variable with the right type will be created and all uses of the old
/// variable will be replaced with a bitcast to the new variable.
llvm::GlobalVariable *
- CreateOrReplaceCXXRuntimeVariable(llvm::StringRef Name, const llvm::Type *Ty,
+ CreateOrReplaceCXXRuntimeVariable(StringRef Name, llvm::Type *Ty,
llvm::GlobalValue::LinkageTypes Linkage);
/// GetAddrOfGlobalVar - Return the llvm::Constant for the address of the
@@ -441,14 +478,14 @@ public:
/// then it will be greated with the specified type instead of whatever the
/// normal requested type would be.
llvm::Constant *GetAddrOfGlobalVar(const VarDecl *D,
- const llvm::Type *Ty = 0);
+ llvm::Type *Ty = 0);
/// GetAddrOfFunction - Return the address of the given function. If Ty is
/// non-null, then this function will use the specified type if it has to
/// create it.
llvm::Constant *GetAddrOfFunction(GlobalDecl GD,
- const llvm::Type *Ty = 0,
+ llvm::Type *Ty = 0,
bool ForVTable = false);
/// GetAddrOfRTTIDescriptor - Get the address of the RTTI descriptor
@@ -544,8 +581,9 @@ public:
///
/// \param GlobalName If provided, the name to use for the global
/// (if one is created).
- llvm::Constant *GetAddrOfConstantString(llvm::StringRef Str,
- const char *GlobalName=0);
+ llvm::Constant *GetAddrOfConstantString(StringRef Str,
+ const char *GlobalName=0,
+ unsigned Alignment=1);
/// GetAddrOfConstantCString - Returns a pointer to a character array
/// containing the literal and a terminating '\0' character. The result has
@@ -554,7 +592,12 @@ public:
/// \param GlobalName If provided, the name to use for the global (if one is
/// created).
llvm::Constant *GetAddrOfConstantCString(const std::string &str,
- const char *GlobalName=0);
+ const char *GlobalName=0,
+ unsigned Alignment=1);
+
+ /// \brief Retrieve the record type that describes the state of an
+ /// Objective-C fast enumeration loop (for..in).
+ QualType getObjCFastEnumerationStateType();
/// GetAddrOfCXXConstructor - Return the address of the constructor of the
/// given type.
@@ -573,8 +616,8 @@ public:
llvm::Value *getBuiltinLibFunction(const FunctionDecl *FD,
unsigned BuiltinID);
- llvm::Function *getIntrinsic(unsigned IID, llvm::ArrayRef<llvm::Type*> Tys =
- llvm::ArrayRef<llvm::Type*>());
+ llvm::Function *getIntrinsic(unsigned IID, ArrayRef<llvm::Type*> Tys =
+ ArrayRef<llvm::Type*>());
/// EmitTopLevelDecl - Emit code for a single top level declaration.
void EmitTopLevelDecl(Decl *D);
@@ -584,8 +627,6 @@ public:
/// metadata global.
void AddUsedGlobal(llvm::GlobalValue *GV);
- void AddAnnotation(llvm::Constant *C) { Annotations.push_back(C); }
-
/// AddCXXDtorEntry - Add a destructor and object to add to the C++ global
/// destructor function.
void AddCXXDtorEntry(llvm::Constant *DtorFn, llvm::Constant *Object) {
@@ -594,14 +635,14 @@ public:
/// CreateRuntimeFunction - Create a new runtime function with the specified
/// type and name.
- llvm::Constant *CreateRuntimeFunction(const llvm::FunctionType *Ty,
- llvm::StringRef Name,
+ llvm::Constant *CreateRuntimeFunction(llvm::FunctionType *Ty,
+ StringRef Name,
llvm::Attributes ExtraAttrs =
llvm::Attribute::None);
/// CreateRuntimeVariable - Create a new runtime global variable with the
/// specified type and name.
- llvm::Constant *CreateRuntimeVariable(const llvm::Type *Ty,
- llvm::StringRef Name);
+ llvm::Constant *CreateRuntimeVariable(llvm::Type *Ty,
+ StringRef Name);
///@name Custom Blocks Runtime Interfaces
///@{
@@ -629,11 +670,13 @@ public:
/// but not always, an LLVM null constant.
llvm::Constant *EmitNullConstant(QualType T);
- llvm::Constant *EmitAnnotateAttr(llvm::GlobalValue *GV,
- const AnnotateAttr *AA, unsigned LineNo);
+ /// EmitNullConstantForBase - Return a null constant appropriate for
+ /// zero-initializing a base class with the given type. This is usually,
+ /// but not always, an LLVM null constant.
+ llvm::Constant *EmitNullConstantForBase(const CXXRecordDecl *Record);
/// Error - Emit a general error that something can't be done.
- void Error(SourceLocation loc, llvm::StringRef error);
+ void Error(SourceLocation loc, StringRef error);
/// ErrorUnsupported - Print out an error that codegen doesn't support the
/// specified stmt yet.
@@ -688,7 +731,7 @@ public:
AttributeListType &PAL,
unsigned &CallingConv);
- llvm::StringRef getMangledName(GlobalDecl GD);
+ StringRef getMangledName(GlobalDecl GD);
void getBlockMangledName(GlobalDecl GD, MangleBuffer &Buffer,
const BlockDecl *BD);
@@ -709,7 +752,7 @@ public:
/// GetTargetTypeStoreSize - Return the store size, in character units, of
/// the given LLVM type.
- CharUnits GetTargetTypeStoreSize(const llvm::Type *Ty) const;
+ CharUnits GetTargetTypeStoreSize(llvm::Type *Ty) const;
/// GetLLVMLinkageVarDefinition - Returns LLVM linkage for a global
/// variable.
@@ -719,17 +762,44 @@ public:
std::vector<const CXXRecordDecl*> DeferredVTables;
+ /// Emit all the global annotations.
+ void EmitGlobalAnnotations();
+
+ /// Emit an annotation string.
+ llvm::Constant *EmitAnnotationString(llvm::StringRef Str);
+
+ /// Emit the annotation's translation unit.
+ llvm::Constant *EmitAnnotationUnit(SourceLocation Loc);
+
+ /// Emit the annotation line number.
+ llvm::Constant *EmitAnnotationLineNo(SourceLocation L);
+
+ /// EmitAnnotateAttr - Generate the llvm::ConstantStruct which contains the
+ /// annotation information for a given GlobalValue. The annotation struct is
+ /// {i8 *, i8 *, i8 *, i32}. The first field is a constant expression, the
+ /// GlobalValue being annotated. The second field is the constant string
+ /// created from the AnnotateAttr's annotation. The third field is a constant
+ /// string containing the name of the translation unit. The fourth field is
+ /// the line number in the file of the annotated value declaration.
+ llvm::Constant *EmitAnnotateAttr(llvm::GlobalValue *GV,
+ const AnnotateAttr *AA,
+ SourceLocation L);
+
+ /// Add global annotations that are set on D, for the global GV. Those
+ /// annotations are emitted during finalization of the LLVM code.
+ void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV);
+
private:
- llvm::GlobalValue *GetGlobalValue(llvm::StringRef Ref);
+ llvm::GlobalValue *GetGlobalValue(StringRef Ref);
- llvm::Constant *GetOrCreateLLVMFunction(llvm::StringRef MangledName,
- const llvm::Type *Ty,
+ llvm::Constant *GetOrCreateLLVMFunction(StringRef MangledName,
+ llvm::Type *Ty,
GlobalDecl D,
bool ForVTable,
llvm::Attributes ExtraAttrs =
llvm::Attribute::None);
- llvm::Constant *GetOrCreateLLVMGlobal(llvm::StringRef MangledName,
- const llvm::PointerType *PTy,
+ llvm::Constant *GetOrCreateLLVMGlobal(StringRef MangledName,
+ llvm::PointerType *PTy,
const VarDecl *D,
bool UnnamedAddr = false);
@@ -804,8 +874,6 @@ private:
/// suitable for use as a LLVM constructor or destructor array.
void EmitCtorList(const CtorList &Fns, const char *GlobalName);
- void EmitAnnotations(void);
-
/// EmitFundamentalRTTIDescriptor - Emit the RTTI descriptors for the
/// given type.
void EmitFundamentalRTTIDescriptor(QualType Type);
diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp
index 53e40b2238b3..887c1eabb0c6 100644
--- a/lib/CodeGen/CodeGenTBAA.cpp
+++ b/lib/CodeGen/CodeGenTBAA.cpp
@@ -58,7 +58,7 @@ llvm::MDNode *CodeGenTBAA::getChar() {
/// getTBAAInfoForNamedType - Create a TBAA tree node with the given string
/// as its identifier, and the given Parent node as its tree parent.
-llvm::MDNode *CodeGenTBAA::getTBAAInfoForNamedType(llvm::StringRef NameStr,
+llvm::MDNode *CodeGenTBAA::getTBAAInfoForNamedType(StringRef NameStr,
llvm::MDNode *Parent,
bool Readonly) {
// Currently there is only one flag defined - the readonly flag.
@@ -75,7 +75,7 @@ llvm::MDNode *CodeGenTBAA::getTBAAInfoForNamedType(llvm::StringRef NameStr,
// Create the mdnode.
unsigned Len = llvm::array_lengthof(Ops) - !Flags;
- return llvm::MDNode::get(VMContext, llvm::ArrayRef<llvm::Value*>(Ops, Len));
+ return llvm::MDNode::get(VMContext, llvm::makeArrayRef(Ops, Len));
}
static bool TypeHasMayAlias(QualType QTy) {
diff --git a/lib/CodeGen/CodeGenTBAA.h b/lib/CodeGen/CodeGenTBAA.h
index c4583473a0e0..9fe51fb33141 100644
--- a/lib/CodeGen/CodeGenTBAA.h
+++ b/lib/CodeGen/CodeGenTBAA.h
@@ -15,7 +15,7 @@
#ifndef CLANG_CODEGEN_CODEGENTBAA_H
#define CLANG_CODEGEN_CODEGENTBAA_H
-#include "llvm/LLVMContext.h"
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
namespace llvm {
@@ -55,7 +55,7 @@ class CodeGenTBAA {
/// considered to be equivalent to it.
llvm::MDNode *getChar();
- llvm::MDNode *getTBAAInfoForNamedType(llvm::StringRef NameStr,
+ llvm::MDNode *getTBAAInfoForNamedType(StringRef NameStr,
llvm::MDNode *Parent,
bool Readonly = false);
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 764688fcb12e..e0d921896580 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -29,7 +29,7 @@ using namespace CodeGen;
CodeGenTypes::CodeGenTypes(ASTContext &Ctx, llvm::Module& M,
const llvm::TargetData &TD, const ABIInfo &Info,
CGCXXABI &CXXABI, const CodeGenOptions &CGO)
- : Context(Ctx), Target(Ctx.Target), TheModule(M), TheTargetData(TD),
+ : Context(Ctx), Target(Ctx.getTargetInfo()), TheModule(M), TheTargetData(TD),
TheABIInfo(Info), TheCXXABI(CXXABI), CodeGenOpts(CGO) {
SkippedLayout = false;
}
@@ -47,7 +47,7 @@ CodeGenTypes::~CodeGenTypes() {
void CodeGenTypes::addRecordTypeName(const RecordDecl *RD,
llvm::StructType *Ty,
- llvm::StringRef suffix) {
+ StringRef suffix) {
llvm::SmallString<256> TypeName;
llvm::raw_svector_ostream OS(TypeName);
OS << RD->getKindName() << '.';
@@ -263,6 +263,8 @@ 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);
if (&format == &llvm::APFloat::IEEEsingle)
return llvm::Type::getFloatTy(VMContext);
if (&format == &llvm::APFloat::IEEEdouble)
@@ -273,8 +275,7 @@ static llvm::Type *getTypeForFormat(llvm::LLVMContext &VMContext,
return llvm::Type::getPPC_FP128Ty(VMContext);
if (&format == &llvm::APFloat::x87DoubleExtended)
return llvm::Type::getX86_FP80Ty(VMContext);
- assert(0 && "Unknown float format!");
- return 0;
+ llvm_unreachable("Unknown float format!");
}
/// ConvertType - Convert the specified type to its LLVM form.
@@ -342,6 +343,14 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
static_cast<unsigned>(Context.getTypeSize(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());
+ break;
case BuiltinType::Float:
case BuiltinType::Double:
case BuiltinType::LongDouble:
@@ -418,7 +427,15 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
}
case Type::ConstantArray: {
const ConstantArrayType *A = cast<ConstantArrayType>(Ty);
- const llvm::Type *EltTy = ConvertTypeForMem(A->getElementType());
+ llvm::Type *EltTy = ConvertTypeForMem(A->getElementType());
+
+ // Lower arrays of undefined struct type to arrays of i8 just to have a
+ // concrete type.
+ if (!EltTy->isSized()) {
+ SkippedLayout = true;
+ EltTy = llvm::Type::getInt8Ty(getLLVMContext());
+ }
+
ResultType = llvm::ArrayType::get(EltTy, A->getSize().getZExtValue());
break;
}
@@ -502,7 +519,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
// these.
llvm::Type *&T = InterfaceTypes[cast<ObjCInterfaceType>(Ty)];
if (!T)
- T = llvm::StructType::createNamed(getLLVMContext(), "");
+ T = llvm::StructType::create(getLLVMContext());
ResultType = T;
break;
}
@@ -511,15 +528,15 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
// Protocol qualifications do not influence the LLVM type, we just return a
// pointer to the underlying interface type. We don't need to worry about
// recursive conversion.
- const llvm::Type *T =
- ConvertType(cast<ObjCObjectPointerType>(Ty)->getPointeeType());
+ llvm::Type *T =
+ ConvertTypeForMem(cast<ObjCObjectPointerType>(Ty)->getPointeeType());
ResultType = T->getPointerTo();
break;
}
case Type::Enum: {
const EnumDecl *ED = cast<EnumType>(Ty)->getDecl();
- if (ED->isDefinition() || ED->isFixed())
+ if (ED->isCompleteDefinition() || ED->isFixed())
return ConvertType(ED->getIntegerType());
// Return a placeholder 'i32' type. This can be changed later when the
// type is defined (see UpdateCompletedType), but is likely to be the
@@ -541,6 +558,11 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
getCXXABI().ConvertMemberPointerType(cast<MemberPointerType>(Ty));
break;
}
+
+ case Type::Atomic: {
+ ResultType = ConvertTypeForMem(cast<AtomicType>(Ty)->getValueType());
+ break;
+ }
}
assert(ResultType && "Didn't convert a type?");
@@ -559,7 +581,7 @@ llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) {
// If we don't have a StructType at all yet, create the forward declaration.
if (Entry == 0) {
- Entry = llvm::StructType::createNamed(getLLVMContext(), "");
+ Entry = llvm::StructType::create(getLLVMContext());
addRecordTypeName(RD, Entry, "");
}
llvm::StructType *Ty = Entry;
@@ -567,7 +589,7 @@ llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) {
// If this is still a forward declaration, or the LLVM type is already
// complete, there's nothing more to do.
RD = RD->getDefinition();
- if (RD == 0 || !Ty->isOpaque())
+ if (RD == 0 || !RD->isCompleteDefinition() || !Ty->isOpaque())
return Ty;
// If converting this type would cause us to infinitely loop, don't do it!
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 7c0fb8164373..7f0f8ac5f0c5 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -93,7 +93,7 @@ class CodeGenTypes {
/// a recursive struct conversion, set this to true.
bool SkippedLayout;
- llvm::SmallVector<const RecordDecl *, 8> DeferredRecords;
+ SmallVector<const RecordDecl *, 8> DeferredRecords;
private:
/// TypeCache - This map keeps cache of llvm::Types
@@ -138,7 +138,7 @@ public:
/// GetFunctionTypeForVTable - Get the LLVM function type for use in a vtable,
/// given a CXXMethodDecl. If the method to has an incomplete return type,
/// and/or incomplete argument types, this will return the opaque type.
- const llvm::Type *GetFunctionTypeForVTable(GlobalDecl GD);
+ llvm::Type *GetFunctionTypeForVTable(GlobalDecl GD);
const CGRecordLayout &getCGRecordLayout(const RecordDecl*);
@@ -190,7 +190,7 @@ public:
///
/// \param ArgTys - must all actually be canonical as params
const CGFunctionInfo &getFunctionInfo(CanQualType RetTy,
- const llvm::SmallVectorImpl<CanQualType> &ArgTys,
+ const SmallVectorImpl<CanQualType> &ArgTys,
const FunctionType::ExtInfo &Info);
/// \brief Compute a new LLVM record layout object for the given record.
@@ -200,7 +200,7 @@ public:
/// addRecordTypeName - Compute a name from the given record decl with an
/// optional suffix and name the given LLVM type using it.
void addRecordTypeName(const RecordDecl *RD, llvm::StructType *Ty,
- llvm::StringRef suffix);
+ StringRef suffix);
public: // These are internal details of CGT that shouldn't be used externally.
@@ -211,7 +211,7 @@ public: // These are internal details of CGT that shouldn't be used externally.
/// argument types it would be passed as on the provided vector \arg
/// ArgTys. See ABIArgInfo::Expand.
void GetExpandedTypes(QualType type,
- llvm::SmallVectorImpl<llvm::Type*> &expanded);
+ SmallVectorImpl<llvm::Type*> &expanded);
/// IsZeroInitializable - Return whether a type can be
/// zero-initialized (in the C++ sense) with an LLVM zeroinitializer.
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 0c86080fa80e..c3f635aed642 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -96,12 +96,12 @@ public:
void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
CXXCtorType T,
CanQualType &ResTy,
- llvm::SmallVectorImpl<CanQualType> &ArgTys);
+ SmallVectorImpl<CanQualType> &ArgTys);
void BuildDestructorSignature(const CXXDestructorDecl *Dtor,
CXXDtorType T,
CanQualType &ResTy,
- llvm::SmallVectorImpl<CanQualType> &ArgTys);
+ SmallVectorImpl<CanQualType> &ArgTys);
void BuildInstanceFunctionParams(CodeGenFunction &CGF,
QualType &ResTy,
@@ -131,12 +131,12 @@ public:
void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
CXXCtorType T,
CanQualType &ResTy,
- llvm::SmallVectorImpl<CanQualType> &ArgTys);
+ SmallVectorImpl<CanQualType> &ArgTys);
void BuildDestructorSignature(const CXXDestructorDecl *Dtor,
CXXDtorType T,
CanQualType &ResTy,
- llvm::SmallVectorImpl<CanQualType> &ArgTys);
+ SmallVectorImpl<CanQualType> &ArgTys);
void BuildInstanceFunctionParams(CodeGenFunction &CGF,
QualType &ResTy,
@@ -215,11 +215,11 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
- const llvm::FunctionType *FTy =
+ llvm::FunctionType *FTy =
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
FPT->isVariadic());
- const llvm::IntegerType *ptrdiff = getPtrDiffTy();
+ llvm::IntegerType *ptrdiff = getPtrDiffTy();
llvm::Constant *ptrdiff_1 = llvm::ConstantInt::get(ptrdiff, 1);
llvm::BasicBlock *FnVirtual = CGF.createBasicBlock("memptr.virtual");
@@ -259,7 +259,7 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
CGF.EmitBlock(FnVirtual);
// Cast the adjusted this to a pointer to vtable pointer and load.
- const llvm::Type *VTableTy = Builder.getInt8PtrTy();
+ llvm::Type *VTableTy = Builder.getInt8PtrTy();
llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy->getPointerTo());
VTable = Builder.CreateLoad(VTable, "memptr.vtable");
@@ -307,7 +307,7 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF,
// Cast the address to the appropriate pointer type, adopting the
// address space of the base pointer.
- const llvm::Type *PType
+ llvm::Type *PType
= CGF.ConvertTypeForMem(MPT->getPointeeType())->getPointerTo(AS);
return Builder.CreateBitCast(Addr, PType);
}
@@ -478,7 +478,7 @@ ItaniumCXXABI::EmitMemberPointerConversion(llvm::Constant *C,
llvm::Constant *
ItaniumCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
- const llvm::Type *ptrdiff_t = getPtrDiffTy();
+ llvm::Type *ptrdiff_t = getPtrDiffTy();
// Itanium C++ ABI 2.3:
// A NULL pointer is represented as -1.
@@ -504,16 +504,16 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
MD = MD->getCanonicalDecl();
CodeGenTypes &Types = CGM.getTypes();
- const llvm::Type *ptrdiff_t = getPtrDiffTy();
+ llvm::Type *ptrdiff_t = getPtrDiffTy();
// Get the function pointer (or index if this is a virtual function).
llvm::Constant *MemPtr[2];
if (MD->isVirtual()) {
- uint64_t Index = CGM.getVTables().getMethodVTableIndex(MD);
+ uint64_t Index = CGM.getVTableContext().getMethodVTableIndex(MD);
const ASTContext &Context = getContext();
CharUnits PointerWidth =
- Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0));
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
uint64_t VTableOffset = (Index * PointerWidth.getQuantity());
if (IsARM) {
@@ -535,7 +535,7 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
}
} else {
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
- const llvm::Type *Ty;
+ llvm::Type *Ty;
// Check whether the function has a computable LLVM signature.
if (Types.isFuncTypeConvertible(FPT)) {
// The function has a computable LLVM signature; use the correct type.
@@ -678,7 +678,7 @@ bool ItaniumCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
void ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
CXXCtorType Type,
CanQualType &ResTy,
- llvm::SmallVectorImpl<CanQualType> &ArgTys) {
+ SmallVectorImpl<CanQualType> &ArgTys) {
ASTContext &Context = getContext();
// 'this' is already there.
@@ -692,7 +692,7 @@ void ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
void ARMCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
CXXCtorType Type,
CanQualType &ResTy,
- llvm::SmallVectorImpl<CanQualType> &ArgTys) {
+ SmallVectorImpl<CanQualType> &ArgTys) {
ItaniumCXXABI::BuildConstructorSignature(Ctor, Type, ResTy, ArgTys);
ResTy = ArgTys[0];
}
@@ -702,7 +702,7 @@ void ARMCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
CXXDtorType Type,
CanQualType &ResTy,
- llvm::SmallVectorImpl<CanQualType> &ArgTys) {
+ SmallVectorImpl<CanQualType> &ArgTys) {
ASTContext &Context = getContext();
// 'this' is already there.
@@ -717,7 +717,7 @@ void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
void ARMCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
CXXDtorType Type,
CanQualType &ResTy,
- llvm::SmallVectorImpl<CanQualType> &ArgTys) {
+ SmallVectorImpl<CanQualType> &ArgTys) {
ItaniumCXXABI::BuildDestructorSignature(Dtor, Type, ResTy, ArgTys);
if (Type != Dtor_Deleting)
@@ -784,7 +784,7 @@ void ARMCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF,
return ItaniumCXXABI::EmitReturnFromThunk(CGF, RV, ResultType);
// Destructor thunks in the ARM ABI have indeterminate results.
- const llvm::Type *T =
+ llvm::Type *T =
cast<llvm::PointerType>(CGF.ReturnValue->getType())->getElementType();
RValue Undef = RValue::get(llvm::UndefValue::get(T));
return ItaniumCXXABI::EmitReturnFromThunk(CGF, Undef, ResultType);
@@ -829,27 +829,7 @@ bool ItaniumCXXABI::NeedsArrayCookie(const CXXDeleteExpr *expr,
if (expr->doesUsualArrayDeleteWantSize())
return true;
- // Automatic Reference Counting:
- // We need an array cookie for pointers with strong or weak lifetime.
- if (getContext().getLangOptions().ObjCAutoRefCount &&
- elementType->isObjCLifetimeType()) {
- switch (elementType.getObjCLifetime()) {
- case Qualifiers::OCL_None:
- case Qualifiers::OCL_ExplicitNone:
- case Qualifiers::OCL_Autoreleasing:
- return false;
-
- case Qualifiers::OCL_Strong:
- case Qualifiers::OCL_Weak:
- return true;
- }
- }
-
- // Otherwise, if the class has a non-trivial destructor, it always
- // needs a cookie.
- const CXXRecordDecl *record =
- elementType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
- return (record && !record->hasTrivialDestructor());
+ return elementType.isDestructedType();
}
CharUnits ItaniumCXXABI::GetArrayCookieSize(const CXXNewExpr *expr) {
@@ -907,7 +887,7 @@ void ItaniumCXXABI::ReadArrayCookie(CodeGenFunction &CGF,
CharUnits &CookieSize) {
// Derive a char* in the same address space as the pointer.
unsigned AS = cast<llvm::PointerType>(Ptr->getType())->getAddressSpace();
- const llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS);
+ llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS);
// If we don't need an array cookie, bail out early.
if (!NeedsArrayCookie(expr, ElementType)) {
@@ -919,7 +899,7 @@ void ItaniumCXXABI::ReadArrayCookie(CodeGenFunction &CGF,
QualType SizeTy = getContext().getSizeType();
CharUnits SizeSize = getContext().getTypeSizeInChars(SizeTy);
- const llvm::Type *SizeLTy = CGF.ConvertType(SizeTy);
+ llvm::Type *SizeLTy = CGF.ConvertType(SizeTy);
CookieSize
= std::max(SizeSize, getContext().getTypeAlignInChars(ElementType));
@@ -968,7 +948,7 @@ llvm::Value *ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
ASTContext &Ctx = getContext();
CharUnits SizeSize = Ctx.getTypeSizeInChars(Ctx.getSizeType());
- const llvm::IntegerType *SizeTy =
+ llvm::IntegerType *SizeTy =
cast<llvm::IntegerType>(CGF.ConvertType(Ctx.getSizeType()));
// The cookie is always at the start of the buffer.
@@ -1000,7 +980,7 @@ void ARMCXXABI::ReadArrayCookie(CodeGenFunction &CGF,
CharUnits &CookieSize) {
// Derive a char* in the same address space as the pointer.
unsigned AS = cast<llvm::PointerType>(Ptr->getType())->getAddressSpace();
- const llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS);
+ llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS);
// If we don't need an array cookie, bail out early.
if (!NeedsArrayCookie(expr, ElementType)) {
@@ -1012,7 +992,7 @@ void ARMCXXABI::ReadArrayCookie(CodeGenFunction &CGF,
QualType SizeTy = getContext().getSizeType();
CharUnits SizeSize = getContext().getTypeSizeInChars(SizeTy);
- const llvm::Type *SizeLTy = CGF.ConvertType(SizeTy);
+ llvm::Type *SizeLTy = CGF.ConvertType(SizeTy);
// The cookie size is always 2 * sizeof(size_t).
CookieSize = 2 * SizeSize;
@@ -1036,10 +1016,9 @@ void ARMCXXABI::ReadArrayCookie(CodeGenFunction &CGF,
static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM,
llvm::PointerType *GuardPtrTy) {
// int __cxa_guard_acquire(__guard *guard_object);
- llvm::Type *ArgTys[] = { GuardPtrTy };
- const llvm::FunctionType *FTy =
+ llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.getTypes().ConvertType(CGM.getContext().IntTy),
- ArgTys, /*isVarArg=*/false);
+ GuardPtrTy, /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire");
}
@@ -1047,10 +1026,9 @@ static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM,
static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
llvm::PointerType *GuardPtrTy) {
// void __cxa_guard_release(__guard *guard_object);
- llvm::Type *ArgTys[] = { GuardPtrTy };
- const llvm::FunctionType *FTy =
+ llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()),
- ArgTys, /*isVarArg=*/false);
+ GuardPtrTy, /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release");
}
@@ -1058,10 +1036,9 @@ static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM,
llvm::PointerType *GuardPtrTy) {
// void __cxa_guard_abort(__guard *guard_object);
- llvm::Type *ArgTys[] = { GuardPtrTy };
- const llvm::FunctionType *FTy =
+ llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()),
- ArgTys, /*isVarArg=*/false);
+ GuardPtrTy, /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort");
}
@@ -1090,7 +1067,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
bool threadsafe =
(getContext().getLangOptions().ThreadsafeStatics && D.isLocalVarDecl());
- const llvm::IntegerType *GuardTy;
+ llvm::IntegerType *GuardTy;
// If we have a global variable with internal linkage and thread-safe statics
// are disabled, we can just let the guard variable be of type i8.
@@ -1152,21 +1129,28 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
// }
} else {
// Load the first byte of the guard variable.
- const llvm::Type *PtrTy = Builder.getInt8PtrTy();
- llvm::Value *V =
- Builder.CreateLoad(Builder.CreateBitCast(GuardVariable, PtrTy), "tmp");
-
- IsInitialized = Builder.CreateIsNull(V, "guard.uninitialized");
+ llvm::Type *PtrTy = Builder.getInt8PtrTy();
+ llvm::LoadInst *LI =
+ Builder.CreateLoad(Builder.CreateBitCast(GuardVariable, PtrTy));
+ LI->setAlignment(1);
+
+ // Itanium ABI:
+ // An implementation supporting thread-safety on multiprocessor
+ // systems must also guarantee that references to the initialized
+ // object do not occur before the load of the initialization flag.
+ //
+ // In LLVM, we do this by marking the load Acquire.
+ if (threadsafe)
+ LI->setAtomic(llvm::Acquire);
+
+ IsInitialized = Builder.CreateIsNull(LI, "guard.uninitialized");
}
llvm::BasicBlock *InitCheckBlock = CGF.createBasicBlock("init.check");
llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end");
- llvm::BasicBlock *NoCheckBlock = EndBlock;
- if (threadsafe) NoCheckBlock = CGF.createBasicBlock("init.barrier");
-
// Check if the first byte of the guard variable is zero.
- Builder.CreateCondBr(IsInitialized, InitCheckBlock, NoCheckBlock);
+ Builder.CreateCondBr(IsInitialized, InitCheckBlock, EndBlock);
CGF.EmitBlock(InitCheckBlock);
@@ -1200,23 +1184,5 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
Builder.CreateStore(llvm::ConstantInt::get(GuardTy, 1), GuardVariable);
}
- // Emit an acquire memory barrier if using thread-safe statics:
- // Itanium ABI:
- // An implementation supporting thread-safety on multiprocessor
- // systems must also guarantee that references to the initialized
- // object do not occur before the load of the initialization flag.
- if (threadsafe) {
- Builder.CreateBr(EndBlock);
- CGF.EmitBlock(NoCheckBlock);
-
- llvm::Value *_false = Builder.getFalse();
- llvm::Value *_true = Builder.getTrue();
-
- Builder.CreateCall5(CGM.getIntrinsic(llvm::Intrinsic::memory_barrier),
- /* load-load, load-store */ _true, _true,
- /* store-load, store-store */ _false, _false,
- /* device or I/O */ _false);
- }
-
CGF.EmitBlock(EndBlock);
}
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 747e5e3222c2..e200e7961701 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -31,7 +31,7 @@ public:
void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
CXXCtorType Type,
CanQualType &ResTy,
- llvm::SmallVectorImpl<CanQualType> &ArgTys) {
+ SmallVectorImpl<CanQualType> &ArgTys) {
// 'this' is already in place
// TODO: 'for base' flag
}
@@ -39,7 +39,7 @@ public:
void BuildDestructorSignature(const CXXDestructorDecl *Ctor,
CXXDtorType Type,
CanQualType &ResTy,
- llvm::SmallVectorImpl<CanQualType> &ArgTys) {
+ SmallVectorImpl<CanQualType> &ArgTys) {
// 'this' is already in place
// TODO: 'for base' flag
}
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 4a2c4abbeb03..793ee9192e6b 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -27,7 +27,7 @@ using namespace clang;
namespace {
class CodeGeneratorImpl : public CodeGenerator {
- Diagnostic &Diags;
+ DiagnosticsEngine &Diags;
llvm::OwningPtr<const llvm::TargetData> TD;
ASTContext *Ctx;
const CodeGenOptions CodeGenOpts; // Intentionally copied in.
@@ -35,7 +35,7 @@ namespace {
llvm::OwningPtr<llvm::Module> M;
llvm::OwningPtr<CodeGen::CodeGenModule> Builder;
public:
- CodeGeneratorImpl(Diagnostic &diags, const std::string& ModuleName,
+ CodeGeneratorImpl(DiagnosticsEngine &diags, const std::string& ModuleName,
const CodeGenOptions &CGO, llvm::LLVMContext& C)
: Diags(diags), CodeGenOpts(CGO), M(new llvm::Module(ModuleName, C)) {}
@@ -52,9 +52,9 @@ namespace {
virtual void Initialize(ASTContext &Context) {
Ctx = &Context;
- M->setTargetTriple(Ctx->Target.getTriple().getTriple());
- M->setDataLayout(Ctx->Target.getTargetDescription());
- TD.reset(new llvm::TargetData(Ctx->Target.getTargetDescription()));
+ M->setTargetTriple(Ctx->getTargetInfo().getTriple().getTriple());
+ M->setDataLayout(Ctx->getTargetInfo().getTargetDescription());
+ TD.reset(new llvm::TargetData(Ctx->getTargetInfo().getTargetDescription()));
Builder.reset(new CodeGen::CodeGenModule(Context, CodeGenOpts,
*M, *TD, Diags));
}
@@ -112,7 +112,7 @@ namespace {
};
}
-CodeGenerator *clang::CreateLLVMCodeGen(Diagnostic &Diags,
+CodeGenerator *clang::CreateLLVMCodeGen(DiagnosticsEngine &Diags,
const std::string& ModuleName,
const CodeGenOptions &CGO,
llvm::LLVMContext& C) {
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index df2c1bd98cca..e1dc8f7ffdbd 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -57,12 +57,12 @@ const llvm::TargetData &ABIInfo::getTargetData() const {
void ABIArgInfo::dump() const {
- llvm::raw_ostream &OS = llvm::errs();
+ raw_ostream &OS = llvm::errs();
OS << "(ABIArgInfo Kind=";
switch (TheKind) {
case Direct:
OS << "Direct Type=";
- if (const llvm::Type *Ty = getCoerceToType())
+ if (llvm::Type *Ty = getCoerceToType())
Ty->print(OS);
else
OS << "null";
@@ -87,6 +87,25 @@ void ABIArgInfo::dump() const {
TargetCodeGenInfo::~TargetCodeGenInfo() { delete Info; }
+// If someone can figure out a general rule for this, that would be great.
+// It's probably just doomed to be platform-dependent, though.
+unsigned TargetCodeGenInfo::getSizeOfUnwindException() const {
+ // Verified for:
+ // x86-64 FreeBSD, Linux, Darwin
+ // x86-32 FreeBSD, Linux, Darwin
+ // PowerPC Linux, Darwin
+ // ARM Darwin (*not* EABI)
+ return 32;
+}
+
+bool TargetCodeGenInfo::isNoProtoCallVariadic(CallingConv CC) const {
+ // The following conventions are known to require this to be false:
+ // x86_stdcall
+ // MIPS
+ // For everything else, we just prefer false unless we opt out.
+ return false;
+}
+
static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays);
/// isEmptyField - Return true iff a the field is "empty", that is it
@@ -348,7 +367,7 @@ ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const {
/// UseX86_MMXType - Return true if this is an MMX type that should use the special
/// x86_mmx type.
-bool UseX86_MMXType(const llvm::Type *IRType) {
+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.
return IRType->isVectorTy() && IRType->getPrimitiveSizeInBits() == 64 &&
@@ -357,7 +376,7 @@ bool UseX86_MMXType(const llvm::Type *IRType) {
}
static llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
- llvm::StringRef Constraint,
+ StringRef Constraint,
llvm::Type* Ty) {
if ((Constraint == "y" || Constraint == "&y") && Ty->isVectorTy())
return llvm::Type::getX86_MMXTy(CGF.getLLVMContext());
@@ -428,7 +447,7 @@ public:
llvm::Value *Address) const;
llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
- llvm::StringRef Constraint,
+ StringRef Constraint,
llvm::Type* Ty) const {
return X86AdjustInlineAsmType(CGF, Constraint, Ty);
}
@@ -724,8 +743,8 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const {
llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
- const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- const llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
+ llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP,
@@ -765,7 +784,7 @@ bool X86_32TargetCodeGenInfo::initDwarfEHRegSizeTable(
CodeGen::CGBuilderTy &Builder = CGF.Builder;
llvm::LLVMContext &Context = CGF.getLLVMContext();
- const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
+ llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4);
// 0-7 are the eight integer registers; the order is different
@@ -892,7 +911,7 @@ class X86_64ABIInfo : public ABIInfo {
/// required strict binary compatibility with older versions of GCC
/// may need to exempt themselves.
bool honorsRevision0_98() const {
- return !getContext().Target.getTriple().isOSDarwin();
+ return !getContext().getTargetInfo().getTriple().isOSDarwin();
}
public:
@@ -932,7 +951,7 @@ public:
CodeGen::CGBuilderTy &Builder = CGF.Builder;
llvm::LLVMContext &Context = CGF.getLLVMContext();
- const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
+ llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8);
// 0-15 are the 16 integer registers.
@@ -943,11 +962,20 @@ public:
}
llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
- llvm::StringRef Constraint,
+ StringRef Constraint,
llvm::Type* Ty) const {
return X86AdjustInlineAsmType(CGF, Constraint, Ty);
}
+ bool isNoProtoCallVariadic(CallingConv CC) const {
+ // The default CC on x86-64 sets %al to the number of SSA
+ // registers used, and GCC sets this when calling an unprototyped
+ // function, so we override the default behavior.
+ if (CC == CC_Default || CC == CC_C) return true;
+
+ return TargetCodeGenInfo::isNoProtoCallVariadic(CC);
+ }
+
};
class WinX86_64TargetCodeGenInfo : public TargetCodeGenInfo {
@@ -964,7 +992,7 @@ public:
CodeGen::CGBuilderTy &Builder = CGF.Builder;
llvm::LLVMContext &Context = CGF.getLLVMContext();
- const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
+ llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8);
// 0-15 are the 16 integer registers.
@@ -1309,8 +1337,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
continue;
uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx);
- uint64_t Size =
- i->getBitWidth()->EvaluateAsInt(getContext()).getZExtValue();
+ uint64_t Size = i->getBitWidthValue(getContext());
uint64_t EB_Lo = Offset / 64;
uint64_t EB_Hi = (Offset + Size - 1) / 64;
@@ -1489,14 +1516,14 @@ static bool BitsContainNoUserData(QualType Ty, unsigned StartBit,
/// float member at the specified offset. For example, {int,{float}} has a
/// float at offset 4. It is conservatively correct for this routine to return
/// false.
-static bool ContainsFloatAtOffset(const llvm::Type *IRType, unsigned IROffset,
+static bool ContainsFloatAtOffset(llvm::Type *IRType, unsigned IROffset,
const llvm::TargetData &TD) {
// Base case if we find a float.
if (IROffset == 0 && IRType->isFloatTy())
return true;
// If this is a struct, recurse into the field at the specified offset.
- if (const llvm::StructType *STy = dyn_cast<llvm::StructType>(IRType)) {
+ if (llvm::StructType *STy = dyn_cast<llvm::StructType>(IRType)) {
const llvm::StructLayout *SL = TD.getStructLayout(STy);
unsigned Elt = SL->getElementContainingOffset(IROffset);
IROffset -= SL->getElementOffset(Elt);
@@ -1504,8 +1531,8 @@ static bool ContainsFloatAtOffset(const llvm::Type *IRType, unsigned IROffset,
}
// If this is an array, recurse into the field at the specified offset.
- if (const llvm::ArrayType *ATy = dyn_cast<llvm::ArrayType>(IRType)) {
- const llvm::Type *EltTy = ATy->getElementType();
+ if (llvm::ArrayType *ATy = dyn_cast<llvm::ArrayType>(IRType)) {
+ llvm::Type *EltTy = ATy->getElementType();
unsigned EltSize = TD.getTypeAllocSize(EltTy);
IROffset -= IROffset/EltSize*EltSize;
return ContainsFloatAtOffset(EltTy, IROffset, TD);
@@ -1578,7 +1605,7 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
}
}
- if (const llvm::StructType *STy = dyn_cast<llvm::StructType>(IRType)) {
+ if (llvm::StructType *STy = dyn_cast<llvm::StructType>(IRType)) {
// If this is a struct, recurse into the field at the specified offset.
const llvm::StructLayout *SL = getTargetData().getStructLayout(STy);
if (IROffset < SL->getSizeInBytes()) {
@@ -1590,7 +1617,7 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
}
}
- if (const llvm::ArrayType *ATy = dyn_cast<llvm::ArrayType>(IRType)) {
+ if (llvm::ArrayType *ATy = dyn_cast<llvm::ArrayType>(IRType)) {
llvm::Type *EltTy = ATy->getElementType();
unsigned EltSize = getTargetData().getTypeAllocSize(EltTy);
unsigned EltOffset = IROffset/EltSize*EltSize;
@@ -1678,7 +1705,7 @@ classifyReturnType(QualType RetTy) const {
case SSEUp:
case X87Up:
- assert(0 && "Invalid classification for lo word.");
+ llvm_unreachable("Invalid classification for lo word.");
// AMD64-ABI 3.2.3p4: Rule 2. Types of class memory are returned via
// hidden argument.
@@ -1732,7 +1759,7 @@ classifyReturnType(QualType RetTy) const {
// never occur as a hi class.
case Memory:
case X87:
- assert(0 && "Invalid classification for hi word.");
+ llvm_unreachable("Invalid classification for hi word.");
case ComplexX87: // Previously handled.
case NoClass:
@@ -1820,7 +1847,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned &neededInt,
case SSEUp:
case X87Up:
- assert(0 && "Invalid classification for lo word.");
+ llvm_unreachable("Invalid classification for lo word.");
// AMD64-ABI 3.2.3p3: Rule 2. If the class is INTEGER, the next
// available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8
@@ -1864,8 +1891,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned &neededInt,
case Memory:
case X87:
case ComplexX87:
- assert(0 && "Invalid classification for hi word.");
- break;
+ llvm_unreachable("Invalid classification for hi word.");
case NoClass: break;
@@ -1970,7 +1996,7 @@ static llvm::Value *EmitVAArgFromMemory(llvm::Value *VAListAddr,
}
// AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area.
- const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty);
+ llvm::Type *LTy = CGF.ConvertTypeForMem(Ty);
llvm::Value *Res =
CGF.Builder.CreateBitCast(overflow_arg_area,
llvm::PointerType::getUnqual(LTy));
@@ -2061,22 +2087,22 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
// collect arguments from different places; often what should result in a
// simple assembling of a structure from scattered addresses has many more
// loads than necessary. Can we clean this up?
- const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty);
+ llvm::Type *LTy = CGF.ConvertTypeForMem(Ty);
llvm::Value *RegAddr =
CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(VAListAddr, 3),
"reg_save_area");
if (neededInt && neededSSE) {
// FIXME: Cleanup.
assert(AI.isDirect() && "Unexpected ABI info for mixed regs");
- const llvm::StructType *ST = cast<llvm::StructType>(AI.getCoerceToType());
+ llvm::StructType *ST = cast<llvm::StructType>(AI.getCoerceToType());
llvm::Value *Tmp = CGF.CreateTempAlloca(ST);
assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs");
- const llvm::Type *TyLo = ST->getElementType(0);
- const llvm::Type *TyHi = ST->getElementType(1);
+ llvm::Type *TyLo = ST->getElementType(0);
+ llvm::Type *TyHi = ST->getElementType(1);
assert((TyLo->isFPOrFPVectorTy() ^ TyHi->isFPOrFPVectorTy()) &&
"Unexpected ABI info for mixed regs");
- const llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo);
- const llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi);
+ llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo);
+ llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi);
llvm::Value *GPAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset);
llvm::Value *FPAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset);
llvm::Value *RegLoAddr = TyLo->isFloatingPointTy() ? FPAddr : GPAddr;
@@ -2104,9 +2130,9 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
llvm::Value *RegAddrLo = CGF.Builder.CreateGEP(RegAddr, fp_offset);
llvm::Value *RegAddrHi = CGF.Builder.CreateConstGEP1_32(RegAddrLo, 16);
llvm::Type *DoubleTy = llvm::Type::getDoubleTy(VMContext);
- const llvm::Type *DblPtrTy =
+ llvm::Type *DblPtrTy =
llvm::PointerType::getUnqual(DoubleTy);
- const llvm::StructType *ST = llvm::StructType::get(DoubleTy,
+ llvm::StructType *ST = llvm::StructType::get(DoubleTy,
DoubleTy, NULL);
llvm::Value *V, *Tmp = CGF.CreateTempAlloca(ST);
V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrLo,
@@ -2166,7 +2192,7 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty) const {
// FIXME: mingw-w64-gcc emits 128-bit struct as i128
if (Size == 128 &&
- getContext().Target.getTriple().getOS() == llvm::Triple::MinGW32)
+ getContext().getTargetInfo().getTriple().getOS() == llvm::Triple::MinGW32)
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
Size));
@@ -2198,8 +2224,8 @@ void WinX86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
llvm::Value *WinX86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
- const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- const llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
+ llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP,
@@ -2246,7 +2272,7 @@ PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
CodeGen::CGBuilderTy &Builder = CGF.Builder;
llvm::LLVMContext &Context = CGF.getLLVMContext();
- const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
+ llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4);
llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8);
llvm::Value *Sixteen8 = llvm::ConstantInt::get(i8, 16);
@@ -2300,6 +2326,11 @@ private:
public:
ARMABIInfo(CodeGenTypes &CGT, ABIKind _Kind) : ABIInfo(CGT), Kind(_Kind) {}
+ bool isEABI() const {
+ StringRef Env = getContext().getTargetInfo().getTriple().getEnvironmentName();
+ return (Env == "gnueabi" || Env == "eabi");
+ }
+
private:
ABIKind getABIKind() const { return Kind; }
@@ -2317,11 +2348,15 @@ public:
ARMTargetCodeGenInfo(CodeGenTypes &CGT, ARMABIInfo::ABIKind K)
:TargetCodeGenInfo(new ARMABIInfo(CGT, K)) {}
+ const ARMABIInfo &getABIInfo() const {
+ return static_cast<const ARMABIInfo&>(TargetCodeGenInfo::getABIInfo());
+ }
+
int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const {
return 13;
}
- llvm::StringRef getARCRetainAutoreleasedReturnValueMarker() const {
+ StringRef getARCRetainAutoreleasedReturnValueMarker() const {
return "mov\tr7, r7\t\t@ marker for objc_retainAutoreleaseReturnValue";
}
@@ -2330,7 +2365,7 @@ public:
CodeGen::CGBuilderTy &Builder = CGF.Builder;
llvm::LLVMContext &Context = CGF.getLLVMContext();
- const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
+ llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4);
// 0-15 are the 16 integer registers.
@@ -2338,6 +2373,11 @@ public:
return false;
}
+
+ unsigned getSizeOfUnwindException() const {
+ if (getABIInfo().isEABI()) return 88;
+ return TargetCodeGenInfo::getSizeOfUnwindException();
+ }
};
}
@@ -2354,8 +2394,7 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
// Calling convention as default by an ABI.
llvm::CallingConv::ID DefaultCC;
- llvm::StringRef Env = getContext().Target.getTriple().getEnvironmentName();
- if (Env == "gnueabi" || Env == "eabi")
+ if (isEABI())
DefaultCC = llvm::CallingConv::ARM_AAPCS;
else
DefaultCC = llvm::CallingConv::ARM_APCS;
@@ -2379,6 +2418,73 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
}
}
+/// isHomogeneousAggregate - Return true if a type is an AAPCS-VFP homogeneous
+/// aggregate. If HAMembers is non-null, the number of base elements
+/// contained in the type is returned through it; this is used for the
+/// recursive calls that check aggregate component types.
+static bool isHomogeneousAggregate(QualType Ty, const Type *&Base,
+ ASTContext &Context,
+ uint64_t *HAMembers = 0) {
+ uint64_t Members;
+ if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) {
+ if (!isHomogeneousAggregate(AT->getElementType(), Base, Context, &Members))
+ return false;
+ Members *= AT->getSize().getZExtValue();
+ } else if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ const RecordDecl *RD = RT->getDecl();
+ if (RD->isUnion() || RD->hasFlexibleArrayMember())
+ return false;
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ if (!CXXRD->isAggregate())
+ return false;
+ }
+ Members = 0;
+ for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
+ i != e; ++i) {
+ const FieldDecl *FD = *i;
+ uint64_t FldMembers;
+ if (!isHomogeneousAggregate(FD->getType(), Base, Context, &FldMembers))
+ return false;
+ Members += FldMembers;
+ }
+ } else {
+ Members = 1;
+ if (const ComplexType *CT = Ty->getAs<ComplexType>()) {
+ Members = 2;
+ Ty = CT->getElementType();
+ }
+
+ // Homogeneous aggregates for AAPCS-VFP must have base types of float,
+ // double, or 64-bit or 128-bit vectors.
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
+ if (BT->getKind() != BuiltinType::Float &&
+ BT->getKind() != BuiltinType::Double)
+ return false;
+ } else if (const VectorType *VT = Ty->getAs<VectorType>()) {
+ unsigned VecSize = Context.getTypeSize(VT);
+ if (VecSize != 64 && VecSize != 128)
+ return false;
+ } else {
+ return false;
+ }
+
+ // The base type must be the same for all members. Vector types of the
+ // same total size are treated as being equivalent here.
+ const Type *TyPtr = Ty.getTypePtr();
+ if (!Base)
+ Base = TyPtr;
+ if (Base != TyPtr &&
+ (!Base->isVectorType() || !TyPtr->isVectorType() ||
+ Context.getTypeSize(Base) != Context.getTypeSize(TyPtr)))
+ return false;
+ }
+
+ // Homogeneous Aggregates can have at most 4 members of the base type.
+ if (HAMembers)
+ *HAMembers = Members;
+ return (Members <= 4);
+}
+
ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const {
if (!isAggregateTypeForABI(Ty)) {
// Treat an enum type as its underlying type.
@@ -2398,23 +2504,26 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const {
if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+ if (getABIKind() == ARMABIInfo::AAPCS_VFP) {
+ // Homogeneous Aggregates need to be expanded.
+ const Type *Base = 0;
+ if (isHomogeneousAggregate(Ty, Base, getContext()))
+ return ABIArgInfo::getExpand();
+ }
+
// Otherwise, pass by coercing to a structure of the appropriate size.
//
+ // FIXME: This is kind of nasty... but there isn't much choice because the ARM
+ // backend doesn't support byval.
// FIXME: This doesn't handle alignment > 64 bits.
- const llvm::Type* ElemTy;
+ llvm::Type* ElemTy;
unsigned SizeRegs;
- if (getContext().getTypeSizeInChars(Ty) <= CharUnits::fromQuantity(64)) {
- ElemTy = llvm::Type::getInt32Ty(getVMContext());
- SizeRegs = (getContext().getTypeSize(Ty) + 31) / 32;
- } else if (getABIKind() == ARMABIInfo::APCS) {
- // Initial ARM ByVal support is APCS-only.
- return ABIArgInfo::getIndirect(0, /*ByVal=*/true);
- } else {
- // FIXME: This is kind of nasty... but there isn't much choice
- // because most of the ARM calling conventions don't yet support
- // byval.
+ if (getContext().getTypeAlign(Ty) > 32) {
ElemTy = llvm::Type::getInt64Ty(getVMContext());
SizeRegs = (getContext().getTypeSize(Ty) + 63) / 64;
+ } else {
+ ElemTy = llvm::Type::getInt32Ty(getVMContext());
+ SizeRegs = (getContext().getTypeSize(Ty) + 31) / 32;
}
llvm::Type *STy =
@@ -2579,14 +2688,23 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const {
llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
- // FIXME: Need to handle alignment
- const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- const llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
+ llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP,
"ap");
llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
+ // Handle address alignment for type alignment > 32 bits
+ uint64_t TyAlign = CGF.getContext().getTypeAlign(Ty) / 8;
+ if (TyAlign > 4) {
+ assert((TyAlign & (TyAlign - 1)) == 0 &&
+ "Alignment is not power of 2!");
+ llvm::Value *AddrAsInt = Builder.CreatePtrToInt(Addr, CGF.Int32Ty);
+ AddrAsInt = Builder.CreateAdd(AddrAsInt, Builder.getInt32(TyAlign - 1));
+ AddrAsInt = Builder.CreateAnd(AddrAsInt, Builder.getInt32(~(TyAlign - 1)));
+ Addr = Builder.CreateIntToPtr(AddrAsInt, BP);
+ }
llvm::Type *PTy =
llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy);
@@ -2623,6 +2741,9 @@ class PTXTargetCodeGenInfo : public TargetCodeGenInfo {
public:
PTXTargetCodeGenInfo(CodeGenTypes &CGT)
: TargetCodeGenInfo(new PTXABIInfo(CGT)) {}
+
+ virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const;
};
ABIArgInfo PTXABIInfo::classifyReturnType(QualType RetTy) const {
@@ -2652,13 +2773,21 @@ void PTXABIInfo::computeInfo(CGFunctionInfo &FI) const {
// Calling convention as default by an ABI.
llvm::CallingConv::ID DefaultCC;
- llvm::StringRef Env = getContext().Target.getTriple().getEnvironmentName();
- if (Env == "device")
+ const LangOptions &LangOpts = getContext().getLangOptions();
+ if (LangOpts.OpenCL || LangOpts.CUDA) {
+ // If we are in OpenCL or CUDA mode, then default to device functions
DefaultCC = llvm::CallingConv::PTX_Device;
- else
- DefaultCC = llvm::CallingConv::PTX_Kernel;
-
+ } 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);
+
}
llvm::Value *PTXABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
@@ -2667,6 +2796,36 @@ llvm::Value *PTXABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
return 0;
}
+void PTXTargetCodeGenInfo::SetTargetAttributes(const Decl *D,
+ llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const{
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ if (!FD) return;
+
+ llvm::Function *F = cast<llvm::Function>(GV);
+
+ // Perform special handling in OpenCL mode
+ if (M.getLangOptions().OpenCL) {
+ // Use OpenCL function attributes to set proper calling conventions
+ // 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);
+ // And kernel functions are not subject to inlining
+ F->addFnAttr(llvm::Attribute::NoInline);
+ }
+ }
+
+ // Perform special handling in CUDA mode.
+ if (M.getLangOptions().CUDA) {
+ // CUDA __global__ functions get a kernel calling convention. 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);
+ }
+}
+
}
//===----------------------------------------------------------------------===//
@@ -2891,7 +3050,7 @@ void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
// Step 3: Emit ISR vector alias.
unsigned Num = attr->getNumber() + 0xffe0;
new llvm::GlobalAlias(GV->getType(), llvm::Function::ExternalLinkage,
- "vector_" + llvm::Twine::utohexstr(Num),
+ "vector_" + Twine::utohexstr(Num),
GV, &M.getModule());
}
}
@@ -2904,6 +3063,7 @@ void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
namespace {
class MipsABIInfo : public ABIInfo {
+ static const unsigned MinABIStackAlignInBytes = 4;
public:
MipsABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
@@ -2914,10 +3074,13 @@ public:
CodeGenFunction &CGF) const;
};
+const unsigned MipsABIInfo::MinABIStackAlignInBytes;
+
class MIPSTargetCodeGenInfo : public TargetCodeGenInfo {
+ unsigned SizeOfUnwindException;
public:
- MIPSTargetCodeGenInfo(CodeGenTypes &CGT)
- : TargetCodeGenInfo(new MipsABIInfo(CGT)) {}
+ MIPSTargetCodeGenInfo(CodeGenTypes &CGT, unsigned SZ)
+ : TargetCodeGenInfo(new MipsABIInfo(CGT)), SizeOfUnwindException(SZ) {}
int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const {
return 29;
@@ -2925,6 +3088,10 @@ public:
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const;
+
+ unsigned getSizeOfUnwindException() const {
+ return SizeOfUnwindException;
+ }
};
}
@@ -2934,6 +3101,11 @@ ABIArgInfo MipsABIInfo::classifyArgumentType(QualType Ty) const {
if (getContext().getTypeSize(Ty) == 0)
return ABIArgInfo::getIgnore();
+ // Records with non trivial destructors/constructors should not be passed
+ // by value.
+ if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+
return ABIArgInfo::getIndirect(0);
}
@@ -2973,7 +3145,37 @@ void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const {
llvm::Value* MipsABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
- return 0;
+ llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
+
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, "ap");
+ llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
+ unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8;
+ llvm::Type *PTy = llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
+ llvm::Value *AddrTyped;
+
+ if (TypeAlign > MinABIStackAlignInBytes) {
+ llvm::Value *AddrAsInt32 = CGF.Builder.CreatePtrToInt(Addr, CGF.Int32Ty);
+ llvm::Value *Inc = llvm::ConstantInt::get(CGF.Int32Ty, TypeAlign - 1);
+ llvm::Value *Mask = llvm::ConstantInt::get(CGF.Int32Ty, -TypeAlign);
+ llvm::Value *Add = CGF.Builder.CreateAdd(AddrAsInt32, Inc);
+ llvm::Value *And = CGF.Builder.CreateAnd(Add, Mask);
+ AddrTyped = CGF.Builder.CreateIntToPtr(And, PTy);
+ }
+ else
+ AddrTyped = Builder.CreateBitCast(Addr, PTy);
+
+ llvm::Value *AlignedAddr = Builder.CreateBitCast(AddrTyped, BP);
+ TypeAlign = std::max(TypeAlign, MinABIStackAlignInBytes);
+ uint64_t Offset =
+ llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, TypeAlign);
+ llvm::Value *NextAddr =
+ Builder.CreateGEP(AlignedAddr, llvm::ConstantInt::get(CGF.Int32Ty, Offset),
+ "ap.next");
+ Builder.CreateStore(NextAddr, VAListAddrAsBPP);
+
+ return AddrTyped;
}
bool
@@ -2987,7 +3189,7 @@ MIPSTargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
// Everything on MIPS is 4 bytes. Double-precision FP registers
// are aliased to pairs of single-precision FP registers.
- const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
+ llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4);
// 0-31 are the general purpose registers, $0 - $31.
@@ -3009,29 +3211,98 @@ MIPSTargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
return false;
}
+//===----------------------------------------------------------------------===//
+// TCE ABI Implementation (see http://tce.cs.tut.fi). Uses mostly the defaults.
+// Currently subclassed only to implement custom OpenCL C function attribute
+// handling.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class TCETargetCodeGenInfo : public DefaultTargetCodeGenInfo {
+public:
+ TCETargetCodeGenInfo(CodeGenTypes &CGT)
+ : DefaultTargetCodeGenInfo(CGT) {}
+
+ virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const;
+};
+
+void TCETargetCodeGenInfo::SetTargetAttributes(const Decl *D,
+ llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const {
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ if (!FD) return;
+
+ llvm::Function *F = cast<llvm::Function>(GV);
+
+ if (M.getLangOptions().OpenCL) {
+ if (FD->hasAttr<OpenCLKernelAttr>()) {
+ // OpenCL C Kernel functions are not subject to inlining
+ F->addFnAttr(llvm::Attribute::NoInline);
+
+ if (FD->hasAttr<ReqdWorkGroupSizeAttr>()) {
+
+ // Convert the reqd_work_group_size() attributes to metadata.
+ llvm::LLVMContext &Context = F->getContext();
+ llvm::NamedMDNode *OpenCLMetadata =
+ M.getModule().getOrInsertNamedMetadata("opencl.kernel_wg_size_info");
+
+ SmallVector<llvm::Value*, 5> Operands;
+ Operands.push_back(F);
+
+ Operands.push_back(llvm::Constant::getIntegerValue(
+ llvm::Type::getInt32Ty(Context),
+ llvm::APInt(
+ 32,
+ FD->getAttr<ReqdWorkGroupSizeAttr>()->getXDim())));
+ Operands.push_back(llvm::Constant::getIntegerValue(
+ llvm::Type::getInt32Ty(Context),
+ llvm::APInt(
+ 32,
+ FD->getAttr<ReqdWorkGroupSizeAttr>()->getYDim())));
+ Operands.push_back(llvm::Constant::getIntegerValue(
+ llvm::Type::getInt32Ty(Context),
+ llvm::APInt(
+ 32,
+ FD->getAttr<ReqdWorkGroupSizeAttr>()->getZDim())));
+
+ // Add a boolean constant operand for "required" (true) or "hint" (false)
+ // for implementing the work_group_size_hint attr later. Currently
+ // always true as the hint is not yet implemented.
+ Operands.push_back(llvm::ConstantInt::getTrue(llvm::Type::getInt1Ty(Context)));
+
+ OpenCLMetadata->addOperand(llvm::MDNode::get(Context, Operands));
+ }
+ }
+ }
+}
+
+}
const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
if (TheTargetCodeGenInfo)
return *TheTargetCodeGenInfo;
- // For now we just cache the TargetCodeGenInfo in CodeGenModule and don't
- // free it.
-
- const llvm::Triple &Triple = getContext().Target.getTriple();
+ const llvm::Triple &Triple = getContext().getTargetInfo().getTriple();
switch (Triple.getArch()) {
default:
return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo(Types));
case llvm::Triple::mips:
case llvm::Triple::mipsel:
- return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types));
+ return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, 24));
+
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, 32));
case llvm::Triple::arm:
case llvm::Triple::thumb:
{
ARMABIInfo::ABIKind Kind = ARMABIInfo::AAPCS;
- if (strcmp(getContext().Target.getABI(), "apcs-gnu") == 0)
+ if (strcmp(getContext().getTargetInfo().getABI(), "apcs-gnu") == 0)
Kind = ARMABIInfo::APCS;
else if (CodeGenOpts.FloatABI == "hard")
Kind = ARMABIInfo::AAPCS_VFP;
@@ -3055,8 +3326,11 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::msp430:
return *(TheTargetCodeGenInfo = new MSP430TargetCodeGenInfo(Types));
+ case llvm::Triple::tce:
+ return *(TheTargetCodeGenInfo = new TCETargetCodeGenInfo(Types));
+
case llvm::Triple::x86: {
- bool DisableMMX = strcmp(getContext().Target.getABI(), "no-mmx") == 0;
+ bool DisableMMX = strcmp(getContext().getTargetInfo().getABI(), "no-mmx") == 0;
if (Triple.isOSDarwin())
return *(TheTargetCodeGenInfo =
diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h
index d5e8884cdffe..8f90c7bdd92d 100644
--- a/lib/CodeGen/TargetInfo.h
+++ b/lib/CodeGen/TargetInfo.h
@@ -15,6 +15,8 @@
#ifndef CLANG_CODEGEN_TARGETINFO_H
#define CLANG_CODEGEN_TARGETINFO_H
+#include "clang/Basic/LLVM.h"
+#include "clang/AST/Type.h"
#include "llvm/ADT/StringRef.h"
namespace llvm {
@@ -58,7 +60,7 @@ namespace clang {
/// uint64 private_1;
/// uint64 private_2;
/// };
- unsigned getSizeOfUnwindException() const { return 32; }
+ virtual unsigned getSizeOfUnwindException() const;
/// Controls whether __builtin_extend_pointer should sign-extend
/// pointers to uint64_t or zero-extend them (the default). Has
@@ -107,7 +109,7 @@ namespace clang {
}
virtual llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
- llvm::StringRef Constraint,
+ StringRef Constraint,
llvm::Type* Ty) const {
return Ty;
}
@@ -122,9 +124,43 @@ namespace clang {
/// a particular instruction sequence. This functions returns
/// that instruction sequence in inline assembly, which will be
/// empty if none is required.
- virtual llvm::StringRef getARCRetainAutoreleasedReturnValueMarker() const {
+ virtual StringRef getARCRetainAutoreleasedReturnValueMarker() const {
return "";
}
+
+ /// Determine whether a call to an unprototyped functions under
+ /// the given calling convention should use the variadic
+ /// convention or the non-variadic convention.
+ ///
+ /// There's a good reason to make a platform's variadic calling
+ /// convention be different from its non-variadic calling
+ /// convention: the non-variadic arguments can be passed in
+ /// registers (better for performance), and the variadic arguments
+ /// can be passed on the stack (also better for performance). If
+ /// this is done, however, unprototyped functions *must* use the
+ /// non-variadic convention, because C99 states that a call
+ /// through an unprototyped function type must succeed if the
+ /// function was defined with a non-variadic prototype with
+ /// compatible parameters. Therefore, splitting the conventions
+ /// makes it impossible to call a variadic function through an
+ /// unprototyped type. Since function prototypes came out in the
+ /// late 1970s, this is probably an acceptable trade-off.
+ /// Nonetheless, not all platforms are willing to make it, and in
+ /// particularly x86-64 bends over backwards to make the
+ /// conventions compatible.
+ ///
+ /// The default is false. This is correct whenever:
+ /// - the conventions are exactly the same, because it does not
+ /// matter and the resulting IR will be somewhat prettier in
+ /// certain cases; or
+ /// - 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.
+ virtual bool isNoProtoCallVariadic(CallingConv CC) const;
};
}
diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp
index 549ce0a7f41b..52c0dbb5f173 100644
--- a/lib/Driver/Action.cpp
+++ b/lib/Driver/Action.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Action.h"
+#include "llvm/Support/ErrorHandling.h"
#include <cassert>
using namespace clang::driver;
@@ -31,10 +32,10 @@ const char *Action::getClassName(ActionClass AC) {
case LinkJobClass: return "linker";
case LipoJobClass: return "lipo";
case DsymutilJobClass: return "dsymutil";
+ case VerifyJobClass: return "verify";
}
- assert(0 && "invalid class");
- return 0;
+ llvm_unreachable("invalid class");
}
InputAction::InputAction(const Arg &_Input, types::ID _Type)
@@ -84,3 +85,7 @@ LipoJobAction::LipoJobAction(ActionList &Inputs, types::ID Type)
DsymutilJobAction::DsymutilJobAction(ActionList &Inputs, types::ID Type)
: JobAction(DsymutilJobClass, Inputs, Type) {
}
+
+VerifyJobAction::VerifyJobAction(ActionList &Inputs, types::ID Type)
+ : JobAction(VerifyJobClass, Inputs, Type) {
+}
diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp
index b8af9cc47e09..ca9b944950e1 100644
--- a/lib/Driver/ArgList.cpp
+++ b/lib/Driver/ArgList.cpp
@@ -46,6 +46,17 @@ void ArgList::append(Arg *A) {
Args.push_back(A);
}
+void ArgList::eraseArg(OptSpecifier Id) {
+ for (iterator it = begin(), ie = end(); it != ie; ) {
+ if ((*it)->getOption().matches(Id)) {
+ it = Args.erase(it);
+ ie = end();
+ } else {
+ ++it;
+ }
+ }
+}
+
Arg *ArgList::getLastArgNoClaim(OptSpecifier Id) const {
// FIXME: Make search efficient?
for (const_reverse_iterator it = rbegin(), ie = rend(); it != ie; ++it)
@@ -117,19 +128,19 @@ bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default) const {
return Default;
}
-llvm::StringRef ArgList::getLastArgValue(OptSpecifier Id,
- llvm::StringRef Default) const {
+StringRef ArgList::getLastArgValue(OptSpecifier Id,
+ StringRef Default) const {
if (Arg *A = getLastArg(Id))
return A->getValue(*this);
return Default;
}
int ArgList::getLastArgIntValue(OptSpecifier Id, int Default,
- clang::Diagnostic &Diags) const {
+ clang::DiagnosticsEngine &Diags) const {
int Res = Default;
if (Arg *A = getLastArg(Id)) {
- if (llvm::StringRef(A->getValue(*this)).getAsInteger(10, Res))
+ if (StringRef(A->getValue(*this)).getAsInteger(10, Res))
Diags.Report(diag::err_drv_invalid_int_value)
<< A->getAsString(*this) << A->getValue(*this);
}
@@ -138,7 +149,7 @@ int ArgList::getLastArgIntValue(OptSpecifier Id, int Default,
}
std::vector<std::string> ArgList::getAllArgValues(OptSpecifier Id) const {
- llvm::SmallVector<const char *, 16> Values;
+ SmallVector<const char *, 16> Values;
AddAllArgValues(Values, Id);
return std::vector<std::string>(Values.begin(), Values.end());
}
@@ -177,7 +188,7 @@ void ArgList::AddAllArgsTranslated(ArgStringList &Output, OptSpecifier Id0,
(*it)->claim();
if (Joined) {
- Output.push_back(MakeArgString(llvm::StringRef(Translation) +
+ Output.push_back(MakeArgString(StringRef(Translation) +
(*it)->getValue(*this, 0)));
} else {
Output.push_back(Translation);
@@ -192,16 +203,22 @@ void ArgList::ClaimAllArgs(OptSpecifier Id0) const {
(*it)->claim();
}
-const char *ArgList::MakeArgString(const llvm::Twine &T) const {
+void ArgList::ClaimAllArgs() const {
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it)
+ if (!(*it)->isClaimed())
+ (*it)->claim();
+}
+
+const char *ArgList::MakeArgString(const Twine &T) const {
llvm::SmallString<256> Str;
T.toVector(Str);
return MakeArgString(Str.str());
}
const char *ArgList::GetOrMakeJoinedArgString(unsigned Index,
- llvm::StringRef LHS,
- llvm::StringRef RHS) const {
- llvm::StringRef Cur = getArgString(Index);
+ StringRef LHS,
+ StringRef RHS) const {
+ StringRef Cur = getArgString(Index);
if (Cur.size() == LHS.size() + RHS.size() &&
Cur.startswith(LHS) && Cur.endswith(RHS))
return Cur.data();
@@ -223,7 +240,7 @@ InputArgList::~InputArgList() {
delete *it;
}
-unsigned InputArgList::MakeIndex(llvm::StringRef String0) const {
+unsigned InputArgList::MakeIndex(StringRef String0) const {
unsigned Index = ArgStrings.size();
// Tuck away so we have a reliable const char *.
@@ -233,8 +250,8 @@ unsigned InputArgList::MakeIndex(llvm::StringRef String0) const {
return Index;
}
-unsigned InputArgList::MakeIndex(llvm::StringRef String0,
- llvm::StringRef String1) const {
+unsigned InputArgList::MakeIndex(StringRef String0,
+ StringRef String1) const {
unsigned Index0 = MakeIndex(String0);
unsigned Index1 = MakeIndex(String1);
assert(Index0 + 1 == Index1 && "Unexpected non-consecutive indices!");
@@ -242,7 +259,7 @@ unsigned InputArgList::MakeIndex(llvm::StringRef String0,
return Index0;
}
-const char *InputArgList::MakeArgString(llvm::StringRef Str) const {
+const char *InputArgList::MakeArgString(StringRef Str) const {
return getArgString(MakeIndex(Str));
}
@@ -259,7 +276,7 @@ DerivedArgList::~DerivedArgList() {
delete *it;
}
-const char *DerivedArgList::MakeArgString(llvm::StringRef Str) const {
+const char *DerivedArgList::MakeArgString(StringRef Str) const {
return BaseArgs.MakeArgString(Str);
}
@@ -270,7 +287,7 @@ Arg *DerivedArgList::MakeFlagArg(const Arg *BaseArg, const Option *Opt) const {
}
Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option *Opt,
- llvm::StringRef Value) const {
+ StringRef Value) const {
unsigned Index = BaseArgs.MakeIndex(Value);
Arg *A = new Arg(Opt, Index, BaseArgs.getArgString(Index), BaseArg);
SynthesizedArgs.push_back(A);
@@ -278,7 +295,7 @@ Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option *Opt,
}
Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option *Opt,
- llvm::StringRef Value) const {
+ StringRef Value) const {
unsigned Index = BaseArgs.MakeIndex(Opt->getName(), Value);
Arg *A = new Arg(Opt, Index, BaseArgs.getArgString(Index + 1), BaseArg);
SynthesizedArgs.push_back(A);
@@ -286,7 +303,7 @@ Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option *Opt,
}
Arg *DerivedArgList::MakeJoinedArg(const Arg *BaseArg, const Option *Opt,
- llvm::StringRef Value) const {
+ StringRef Value) const {
unsigned Index = BaseArgs.MakeIndex(Opt->getName().str() + Value.str());
Arg *A = new Arg(Opt, Index,
BaseArgs.getArgString(Index) + Opt->getName().size(),
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index 2657faa0d3a7..d02da9588a63 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -16,16 +16,19 @@
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Program.h"
#include <sys/stat.h>
#include <errno.h>
+
using namespace clang::driver;
+using namespace clang;
Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain,
InputArgList *_Args, DerivedArgList *_TranslatedArgs)
: TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args),
- TranslatedArgs(_TranslatedArgs) {
+ TranslatedArgs(_TranslatedArgs), Redirects(0) {
}
Compilation::~Compilation() {
@@ -43,6 +46,13 @@ Compilation::~Compilation() {
for (ActionList::iterator it = Actions.begin(), ie = Actions.end();
it != ie; ++it)
delete *it;
+
+ // Free redirections of stdout/stderr.
+ if (Redirects) {
+ delete Redirects[1];
+ delete Redirects[2];
+ delete [] Redirects;
+ }
}
const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC,
@@ -60,14 +70,14 @@ const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC,
return *Entry;
}
-void Compilation::PrintJob(llvm::raw_ostream &OS, const Job &J,
+void Compilation::PrintJob(raw_ostream &OS, const Job &J,
const char *Terminator, bool Quote) const {
if (const Command *C = dyn_cast<Command>(&J)) {
OS << " \"" << C->getExecutable() << '"';
for (ArgStringList::const_iterator it = C->getArguments().begin(),
ie = C->getArguments().end(); it != ie; ++it) {
OS << ' ';
- if (!Quote) {
+ if (!Quote && !std::strpbrk(*it, " \"\\$")) {
OS << *it;
continue;
}
@@ -135,9 +145,9 @@ int Compilation::ExecuteCommand(const Command &C,
std::copy(C.getArguments().begin(), C.getArguments().end(), Argv+1);
Argv[C.getArguments().size() + 1] = 0;
- if (getDriver().CCCEcho || getDriver().CCPrintOptions ||
- getArgs().hasArg(options::OPT_v)) {
- llvm::raw_ostream *OS = &llvm::errs();
+ if ((getDriver().CCCEcho || getDriver().CCPrintOptions ||
+ getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) {
+ raw_ostream *OS = &llvm::errs();
// Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the
// output stream.
@@ -167,7 +177,7 @@ int Compilation::ExecuteCommand(const Command &C,
std::string Error;
int Res =
llvm::sys::Program::ExecuteAndWait(Prog, Argv,
- /*env*/0, /*redirects*/0,
+ /*env*/0, Redirects,
/*secondsToWait*/0, /*memoryLimit*/0,
&Error);
if (!Error.empty()) {
@@ -195,3 +205,24 @@ int Compilation::ExecuteJob(const Job &J,
return 0;
}
}
+
+void Compilation::initCompilationForDiagnostics(void) {
+ // Free actions and jobs.
+ DeleteContainerPointers(Actions);
+ Jobs.clear();
+
+ // Clear temporary/results file lists.
+ TempFiles.clear();
+ ResultFiles.clear();
+
+ // Remove any user specified output. Claim any unclaimed arguments, so as
+ // to avoid emitting warnings about unused args.
+ if (TranslatedArgs->hasArg(options::OPT_o))
+ TranslatedArgs->eraseArg(options::OPT_o);
+ TranslatedArgs->ClaimAllArgs();
+
+ // Redirect stdout/stderr to /dev/null.
+ Redirects = new const llvm::sys::Path*[3]();
+ Redirects[1] = new const llvm::sys::Path();
+ Redirects[2] = new const llvm::sys::Path();
+}
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 789f6f7ae9ce..75300b5307e0 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -25,7 +25,6 @@
#include "clang/Driver/Options.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
-#include "clang/Driver/Types.h"
#include "clang/Basic/Version.h"
@@ -33,6 +32,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/FileSystem.h"
@@ -46,11 +46,11 @@
using namespace clang::driver;
using namespace clang;
-Driver::Driver(llvm::StringRef ClangExecutable,
- llvm::StringRef DefaultHostTriple,
- llvm::StringRef DefaultImageName,
- bool IsProduction, bool CXXIsProduction,
- Diagnostic &Diags)
+Driver::Driver(StringRef ClangExecutable,
+ StringRef DefaultHostTriple,
+ StringRef DefaultImageName,
+ bool IsProduction,
+ DiagnosticsEngine &Diags)
: Opts(createDriverOptTable()), Diags(Diags),
ClangExecutable(ClangExecutable), UseStdLib(true),
DefaultHostTriple(DefaultHostTriple), DefaultImageName(DefaultImageName),
@@ -60,9 +60,9 @@ Driver::Driver(llvm::StringRef ClangExecutable,
CCLogDiagnosticsFilename(0), CCCIsCXX(false),
CCCIsCPP(false),CCCEcho(false), CCCPrintBindings(false),
CCPrintOptions(false), CCPrintHeaders(false), CCLogDiagnostics(false),
- CCCGenericGCCName(""), CheckInputsExist(true), CCCUseClang(true),
- CCCUseClangCXX(true), CCCUseClangCPP(true), CCCUsePCH(true),
- SuppressMissingInputWarning(false) {
+ CCGenDiagnostics(false), CCCGenericGCCName(""), CheckInputsExist(true),
+ CCCUseClang(true), CCCUseClangCXX(true), CCCUseClangCPP(true),
+ CCCUsePCH(true), SuppressMissingInputWarning(false) {
if (IsProduction) {
// In a "production" build, only use clang on architectures we expect to
// work, and don't use clang C++.
@@ -73,16 +73,13 @@ Driver::Driver(llvm::StringRef ClangExecutable,
CCCClangArchs.insert(llvm::Triple::x86);
CCCClangArchs.insert(llvm::Triple::x86_64);
CCCClangArchs.insert(llvm::Triple::arm);
-
- if (!CXXIsProduction)
- CCCUseClangCXX = false;
}
Name = llvm::sys::path::stem(ClangExecutable);
Dir = llvm::sys::path::parent_path(ClangExecutable);
// Compute the path to the resource directory.
- llvm::StringRef ClangResourceDir(CLANG_RESOURCE_DIR);
+ StringRef ClangResourceDir(CLANG_RESOURCE_DIR);
llvm::SmallString<128> P(Dir);
if (ClangResourceDir != "")
llvm::sys::path::append(P, ClangResourceDir);
@@ -96,7 +93,7 @@ Driver::~Driver() {
delete Host;
}
-InputArgList *Driver::ParseArgStrings(llvm::ArrayRef<const char *> ArgList) {
+InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) {
llvm::PrettyStackTraceString CrashInfo("Command line argument parsing");
unsigned MissingArgIndex, MissingArgCount;
InputArgList *Args = getOpts().ParseArgs(ArgList.begin(), ArgList.end(),
@@ -120,6 +117,43 @@ InputArgList *Driver::ParseArgStrings(llvm::ArrayRef<const char *> ArgList) {
return Args;
}
+// Determine which compilation mode we are in. We look for options which
+// affect the phase, starting with the earliest phases, and record which
+// option we used to determine the final phase.
+phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, Arg **FinalPhaseArg)
+const {
+ Arg *PhaseArg = 0;
+ phases::ID FinalPhase;
+
+ // -{E,M,MM} only run the preprocessor.
+ if (CCCIsCPP ||
+ (PhaseArg = DAL.getLastArg(options::OPT_E)) ||
+ (PhaseArg = DAL.getLastArg(options::OPT_M, options::OPT_MM))) {
+ FinalPhase = phases::Preprocess;
+
+ // -{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_rewrite_objc)) ||
+ (PhaseArg = DAL.getLastArg(options::OPT__analyze,
+ options::OPT__analyze_auto)) ||
+ (PhaseArg = DAL.getLastArg(options::OPT_emit_ast)) ||
+ (PhaseArg = DAL.getLastArg(options::OPT_S))) {
+ FinalPhase = phases::Compile;
+
+ // -c only runs up to the assembler.
+ } else if ((PhaseArg = DAL.getLastArg(options::OPT_c))) {
+ FinalPhase = phases::Assemble;
+
+ // Otherwise do everything.
+ } else
+ FinalPhase = phases::Link;
+
+ if (FinalPhaseArg)
+ *FinalPhaseArg = PhaseArg;
+
+ return FinalPhase;
+}
+
DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
DerivedArgList *DAL = new DerivedArgList(Args);
@@ -142,7 +176,7 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
// Add the remaining values as Xlinker arguments.
for (unsigned i = 0, e = A->getNumValues(); i != e; ++i)
- if (llvm::StringRef(A->getValue(Args, i)) != "--no-demangle")
+ if (StringRef(A->getValue(Args, i)) != "--no-demangle")
DAL->AddSeparateArg(A, Opts->getOption(options::OPT_Xlinker),
A->getValue(Args, i));
@@ -154,10 +188,10 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
// care to encourage this usage model.
if (A->getOption().matches(options::OPT_Wp_COMMA) &&
A->getNumValues() == 2 &&
- (A->getValue(Args, 0) == llvm::StringRef("-MD") ||
- A->getValue(Args, 0) == llvm::StringRef("-MMD"))) {
+ (A->getValue(Args, 0) == StringRef("-MD") ||
+ A->getValue(Args, 0) == StringRef("-MMD"))) {
// Rewrite to -MD/-MMD along with -MF.
- if (A->getValue(Args, 0) == llvm::StringRef("-MD"))
+ if (A->getValue(Args, 0) == StringRef("-MD"))
DAL->AddFlagArg(A, Opts->getOption(options::OPT_MD));
else
DAL->AddFlagArg(A, Opts->getOption(options::OPT_MMD));
@@ -168,7 +202,7 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
// Rewrite reserved library names.
if (A->getOption().matches(options::OPT_l)) {
- llvm::StringRef Value = A->getValue(Args);
+ StringRef Value = A->getValue(Args);
// Rewrite unless -nostdlib is present.
if (!HasNostdlib && Value == "stdc++") {
@@ -201,12 +235,20 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
return DAL;
}
-Compilation *Driver::BuildCompilation(llvm::ArrayRef<const char *> ArgList) {
+Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
llvm::PrettyStackTraceString CrashInfo("Compilation construction");
- // FIXME: Handle environment options which effect driver behavior, somewhere
- // (client?). GCC_EXEC_PREFIX, COMPILER_PATH, LIBRARY_PATH, LPATH,
- // CC_PRINT_OPTIONS.
+ // FIXME: Handle environment options which affect driver behavior, somewhere
+ // (client?). GCC_EXEC_PREFIX, LIBRARY_PATH, LPATH, CC_PRINT_OPTIONS.
+
+ if (char *env = ::getenv("COMPILER_PATH")) {
+ StringRef CompilerPath = env;
+ while (!CompilerPath.empty()) {
+ std::pair<StringRef, StringRef> Split = CompilerPath.split(':');
+ PrefixDirs.push_back(Split.first);
+ CompilerPath = Split.second;
+ }
+ }
// FIXME: What are we going to do with -V and -b?
@@ -242,11 +284,11 @@ Compilation *Driver::BuildCompilation(llvm::ArrayRef<const char *> ArgList) {
CCCUseClang = !Args->hasArg(options::OPT_ccc_no_clang);
CCCUseClangCPP = !Args->hasArg(options::OPT_ccc_no_clang_cpp);
if (const Arg *A = Args->getLastArg(options::OPT_ccc_clang_archs)) {
- llvm::StringRef Cur = A->getValue(*Args);
+ StringRef Cur = A->getValue(*Args);
CCCClangArchs.clear();
while (!Cur.empty()) {
- std::pair<llvm::StringRef, llvm::StringRef> Split = Cur.split(',');
+ std::pair<StringRef, StringRef> Split = Cur.split(',');
if (!Split.first.empty()) {
llvm::Triple::ArchType Arch =
@@ -296,12 +338,17 @@ Compilation *Driver::BuildCompilation(llvm::ArrayRef<const char *> ArgList) {
if (!HandleImmediateArgs(*C))
return C;
+ // Construct the list of inputs.
+ InputList Inputs;
+ BuildInputs(C->getDefaultToolChain(), C->getArgs(), Inputs);
+
// Construct the list of abstract actions to perform for this compilation.
if (Host->useDriverDriver())
BuildUniversalActions(C->getDefaultToolChain(), C->getArgs(),
- C->getActions());
+ Inputs, C->getActions());
else
- BuildActions(C->getDefaultToolChain(), C->getArgs(), C->getActions());
+ BuildActions(C->getDefaultToolChain(), C->getArgs(), Inputs,
+ C->getActions());
if (CCCPrintActions) {
PrintActions(*C);
@@ -313,7 +360,112 @@ Compilation *Driver::BuildCompilation(llvm::ArrayRef<const char *> ArgList) {
return C;
}
-int Driver::ExecuteCompilation(const Compilation &C) const {
+// When clang crashes, produce diagnostic information including the fully
+// preprocessed source file(s). Request that the developer attach the
+// diagnostic information to a bug report.
+void Driver::generateCompilationDiagnostics(Compilation &C,
+ const Command *FailingCommand) {
+ Diag(clang::diag::note_drv_command_failed_diag_msg)
+ << "Please submit a bug report to " BUG_REPORT_URL " and include command"
+ " line arguments and all diagnostic information.";
+
+ // Suppress driver output and emit preprocessor output to temp file.
+ CCCIsCPP = true;
+ CCGenDiagnostics = true;
+
+ // Clear stale state and suppress tool output.
+ C.initCompilationForDiagnostics();
+ Diags.Reset();
+
+ // Construct the list of inputs.
+ InputList Inputs;
+ BuildInputs(C.getDefaultToolChain(), C.getArgs(), Inputs);
+
+ for (InputList::iterator it = Inputs.begin(), ie = Inputs.end(); it != ie;) {
+ bool IgnoreInput = false;
+
+ // Ignore input from stdin or any inputs that cannot be preprocessed.
+ if (!strcmp(it->second->getValue(C.getArgs()), "-")) {
+ Diag(clang::diag::note_drv_command_failed_diag_msg)
+ << "Error generating preprocessed source(s) - ignoring input from stdin"
+ ".";
+ IgnoreInput = true;
+ } else if (types::getPreprocessedType(it->first) == types::TY_INVALID) {
+ IgnoreInput = true;
+ }
+
+ if (IgnoreInput) {
+ it = Inputs.erase(it);
+ ie = Inputs.end();
+ } else {
+ ++it;
+ }
+ }
+
+ // Don't attempt to generate preprocessed files if multiple -arch options are
+ // used.
+ int Archs = 0;
+ for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end();
+ it != ie; ++it) {
+ Arg *A = *it;
+ if (A->getOption().matches(options::OPT_arch)) {
+ Archs++;
+ if (Archs > 1) {
+ Diag(clang::diag::note_drv_command_failed_diag_msg)
+ << "Error generating preprocessed source(s) - cannot generate "
+ "preprocessed source with multiple -arch options.";
+ 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.
+ if (Host->useDriverDriver())
+ BuildUniversalActions(C.getDefaultToolChain(), C.getArgs(),
+ Inputs, C.getActions());
+ else
+ BuildActions(C.getDefaultToolChain(), C.getArgs(), Inputs,
+ C.getActions());
+
+ BuildJobs(C);
+
+ // If there were errors building the compilation, quit now.
+ if (Diags.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);
+
+ // If the command succeeded, we are done.
+ if (Res == 0) {
+ Diag(clang::diag::note_drv_command_failed_diag_msg)
+ << "Preprocessed source(s) are located at:";
+ ArgStringList Files = C.getTempFiles();
+ for (ArgStringList::const_iterator it = Files.begin(), ie = Files.end();
+ it != ie; ++it)
+ Diag(clang::diag::note_drv_command_failed_diag_msg) << *it;
+ } else {
+ // Failure, remove preprocessed files.
+ 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).";
+ }
+}
+
+int Driver::ExecuteCompilation(const Compilation &C,
+ const Command *&FailingCommand) const {
// Just print if -### was present.
if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) {
C.PrintJob(llvm::errs(), C.getJobs(), "\n", true);
@@ -321,10 +473,9 @@ int Driver::ExecuteCompilation(const Compilation &C) const {
}
// If there were errors building the compilation, quit now.
- if (getDiags().hasErrorOccurred())
+ if (Diags.hasErrorOccurred())
return 1;
- const Command *FailingCommand = 0;
int Res = C.ExecuteJob(C.getJobs(), FailingCommand);
// Remove temp files.
@@ -382,7 +533,7 @@ void Driver::PrintHelp(bool ShowHidden) const {
ShowHidden);
}
-void Driver::PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const {
+void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const {
// FIXME: The following handlers should use a callback mechanism, we don't
// know what the client would like to do.
OS << getClangFullVersion() << '\n';
@@ -397,7 +548,7 @@ void Driver::PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const {
/// PrintDiagnosticCategories - Implement the --print-diagnostic-categories
/// option.
-static void PrintDiagnosticCategories(llvm::raw_ostream &OS) {
+static void PrintDiagnosticCategories(raw_ostream &OS) {
// Skip the empty category.
for (unsigned i = 1, max = DiagnosticIDs::getNumberOfCategories();
i != max; ++i)
@@ -457,7 +608,7 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
llvm::outs() << *it;
}
llvm::outs() << "\n";
- llvm::outs() << "libraries: =";
+ llvm::outs() << "libraries: =" << ResourceDir;
std::string sysroot;
if (Arg *A = C.getArgs().getLastArg(options::OPT__sysroot_EQ))
@@ -465,8 +616,7 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
for (ToolChain::path_list::const_iterator it = TC.getFilePaths().begin(),
ie = TC.getFilePaths().end(); it != ie; ++it) {
- if (it != TC.getFilePaths().begin())
- llvm::outs() << ':';
+ llvm::outs() << ':';
const char *path = it->c_str();
if (path[0] == '=')
llvm::outs() << sysroot << path + 1;
@@ -594,12 +744,13 @@ static bool ContainsCompileOrAssembleAction(const Action *A) {
void Driver::BuildUniversalActions(const ToolChain &TC,
const DerivedArgList &Args,
+ const InputList &BAInputs,
ActionList &Actions) const {
llvm::PrettyStackTraceString CrashInfo("Building universal build actions");
// Collect the list of architectures. Duplicates are allowed, but should only
// be handled once (in the order seen).
llvm::StringSet<> ArchNames;
- llvm::SmallVector<const char *, 4> Archs;
+ SmallVector<const char *, 4> Archs;
for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
it != ie; ++it) {
Arg *A = *it;
@@ -638,7 +789,7 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
}
ActionList SingleActions;
- BuildActions(TC, Args, SingleActions);
+ BuildActions(TC, Args, BAInputs, SingleActions);
// Add in arch bindings for every top level action, as well as lipo and
// dsymutil steps if needed.
@@ -683,23 +834,33 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
Actions.pop_back();
Actions.push_back(new DsymutilJobAction(Inputs, types::TY_dSYM));
+
+ // Verify the debug output if we're in assert mode.
+ // TODO: The verifier is noisy by default so put this under an
+ // option for now.
+ #ifndef NDEBUG
+ if (Args.hasArg(options::OPT_verify)) {
+ ActionList VerifyInputs;
+ VerifyInputs.push_back(Actions.back());
+ Actions.pop_back();
+ Actions.push_back(new VerifyJobAction(VerifyInputs,
+ types::TY_Nothing));
+ }
+ #endif
}
}
}
}
-void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
- ActionList &Actions) const {
- llvm::PrettyStackTraceString CrashInfo("Building compilation actions");
- // Start by constructing the list of inputs and their types.
-
+// Construct a the list of inputs and their types.
+void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
+ InputList &Inputs) const {
// Track the current user specified (-x) input. We also explicitly track the
// argument used to set the type; we only want to claim the type when we
// actually use it, so we warn about unused -x arguments.
types::ID InputType = types::TY_Nothing;
Arg *InputTypeArg = 0;
- llvm::SmallVector<std::pair<types::ID, const Arg*>, 16> Inputs;
for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
it != ie; ++it) {
Arg *A = *it;
@@ -803,7 +964,6 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
}
}
}
-
if (CCCIsCPP && Inputs.empty()) {
// If called as standalone preprocessor, stdin is processed
// if no other input is present.
@@ -812,40 +972,19 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
A->claim();
Inputs.push_back(std::make_pair(types::TY_C, A));
}
+}
+
+void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
+ const InputList &Inputs, ActionList &Actions) const {
+ llvm::PrettyStackTraceString CrashInfo("Building compilation actions");
if (!SuppressMissingInputWarning && Inputs.empty()) {
Diag(clang::diag::err_drv_no_input_files);
return;
}
- // Determine which compilation mode we are in. We look for options which
- // affect the phase, starting with the earliest phases, and record which
- // option we used to determine the final phase.
- Arg *FinalPhaseArg = 0;
- phases::ID FinalPhase;
-
- // -{E,M,MM} only run the preprocessor.
- if (CCCIsCPP ||
- (FinalPhaseArg = Args.getLastArg(options::OPT_E)) ||
- (FinalPhaseArg = Args.getLastArg(options::OPT_M, options::OPT_MM))) {
- FinalPhase = phases::Preprocess;
-
- // -{fsyntax-only,-analyze,emit-ast,S} only run up to the compiler.
- } else if ((FinalPhaseArg = Args.getLastArg(options::OPT_fsyntax_only)) ||
- (FinalPhaseArg = Args.getLastArg(options::OPT_rewrite_objc)) ||
- (FinalPhaseArg = Args.getLastArg(options::OPT__analyze,
- options::OPT__analyze_auto)) ||
- (FinalPhaseArg = Args.getLastArg(options::OPT_emit_ast)) ||
- (FinalPhaseArg = Args.getLastArg(options::OPT_S))) {
- FinalPhase = phases::Compile;
-
- // -c only runs up to the assembler.
- } else if ((FinalPhaseArg = Args.getLastArg(options::OPT_c))) {
- FinalPhase = phases::Assemble;
-
- // Otherwise do everything.
- } else
- FinalPhase = phases::Link;
+ Arg *FinalPhaseArg;
+ phases::ID FinalPhase = getFinalPhase(Args, &FinalPhaseArg);
// Reject -Z* at the top level, these options should never have been exposed
// by gcc.
@@ -935,7 +1074,7 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
llvm::PrettyStackTraceString CrashInfo("Constructing phase actions");
// Build the appropriate action.
switch (Phase) {
- case phases::Link: assert(0 && "link action invalid here.");
+ case phases::Link: llvm_unreachable("link action invalid here.");
case phases::Preprocess: {
types::ID OutputTy;
// -{M, MM} alter the output type.
@@ -971,8 +1110,7 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
return new AssembleJobAction(Input, types::TY_Object);
}
- assert(0 && "invalid phase in ConstructPhaseAction");
- return 0;
+ llvm_unreachable("invalid phase in ConstructPhaseAction");
}
bool Driver::IsUsingLTO(const ArgList &Args) const {
@@ -1048,7 +1186,8 @@ void Driver::BuildJobs(Compilation &C) const {
Arg *A = *it;
// FIXME: It would be nice to be able to send the argument to the
- // Diagnostic, so that extra values, position, and so on could be printed.
+ // DiagnosticsEngine, so that extra values, position, and so on could be
+ // printed.
if (!A->isClaimed()) {
if (A->getOption().hasNoArgumentUnused())
continue;
@@ -1091,7 +1230,7 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC,
bool HasStatic = (C.getArgs().hasArg(options::OPT_mkernel) ||
C.getArgs().hasArg(options::OPT_static) ||
C.getArgs().hasArg(options::OPT_fapple_kext));
- bool IsDarwin = TC->getTriple().getOS() == llvm::Triple::Darwin;
+ bool IsDarwin = TC->getTriple().isOSDarwin();
bool IsIADefault = TC->IsIntegratedAssemblerDefault() &&
!(HasStatic && IsDarwin);
if (C.getArgs().hasFlag(options::OPT_integrated_as,
@@ -1176,6 +1315,11 @@ void Driver::BuildJobsForAction(Compilation &C,
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))
+ SubJobAtTopLevel = true;
+
InputInfo II;
BuildJobsForAction(C, *it, TC, BoundArch,
SubJobAtTopLevel, LinkingOutput, II);
@@ -1198,7 +1342,7 @@ void Driver::BuildJobsForAction(Compilation &C,
A->getType(), BaseInput);
}
- if (CCCPrintBindings) {
+ if (CCCPrintBindings && !CCGenDiagnostics) {
llvm::errs() << "# \"" << T.getToolChain().getTripleString() << '"'
<< " - \"" << T.getName() << "\", inputs: [";
for (unsigned i = 0, e = InputInfos.size(); i != e; ++i) {
@@ -1219,27 +1363,31 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
bool AtTopLevel) const {
llvm::PrettyStackTraceString CrashInfo("Computing output path");
// Output to a user requested destination?
- if (AtTopLevel && !isa<DsymutilJobAction>(JA)) {
+ if (AtTopLevel && !isa<DsymutilJobAction>(JA) &&
+ !isa<VerifyJobAction>(JA)) {
if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o))
return C.addResultFile(FinalOutput->getValue(C.getArgs()));
}
// Default to writing to stdout?
- if (AtTopLevel && isa<PreprocessJobAction>(JA))
+ if (AtTopLevel && isa<PreprocessJobAction>(JA) && !CCGenDiagnostics)
return "-";
// Output to a temporary file?
- if (!AtTopLevel && !C.getArgs().hasArg(options::OPT_save_temps)) {
+ if ((!AtTopLevel && !C.getArgs().hasArg(options::OPT_save_temps)) ||
+ CCGenDiagnostics) {
+ StringRef Name = llvm::sys::path::filename(BaseInput);
+ std::pair<StringRef, StringRef> Split = Name.split('.');
std::string TmpName =
- GetTemporaryPath(types::getTypeTempSuffix(JA.getType()));
+ GetTemporaryPath(Split.first, types::getTypeTempSuffix(JA.getType()));
return C.addTempFile(C.getArgs().MakeArgString(TmpName.c_str()));
}
llvm::SmallString<128> BasePath(BaseInput);
- llvm::StringRef BaseName;
+ StringRef BaseName;
// Dsymutil actions should use the full path.
- if (isa<DsymutilJobAction>(JA))
+ if (isa<DsymutilJobAction>(JA) || isa<VerifyJobAction>(JA))
BaseName = BasePath;
else
BaseName = llvm::sys::path::filename(BasePath);
@@ -1261,12 +1409,14 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
NamedOutput = C.getArgs().MakeArgString(Suffixed.c_str());
}
- // If we're saving temps and the temp filename conflicts with the input
+ // If we're saving temps and the temp filename conflicts with the input
// filename, then avoid overwriting input file.
if (!AtTopLevel && C.getArgs().hasArg(options::OPT_save_temps) &&
- NamedOutput == BaseName) {
+ NamedOutput == BaseName) {
+ StringRef Name = llvm::sys::path::filename(BaseInput);
+ std::pair<StringRef, StringRef> Split = Name.split('.');
std::string TmpName =
- GetTemporaryPath(types::getTypeTempSuffix(JA.getType()));
+ GetTemporaryPath(Split.first, types::getTypeTempSuffix(JA.getType()));
return C.addTempFile(C.getArgs().MakeArgString(TmpName.c_str()));
}
@@ -1300,6 +1450,12 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const {
return P.str();
}
+ llvm::sys::Path P(ResourceDir);
+ P.appendComponent(Name);
+ bool Exists;
+ if (!llvm::sys::fs::exists(P.str(), Exists) && Exists)
+ return P.str();
+
const ToolChain::path_list &List = TC.getFilePaths();
for (ToolChain::path_list::const_iterator
it = List.begin(), ie = List.end(); it != ie; ++it) {
@@ -1318,40 +1474,53 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const {
return Name;
}
+static bool isPathExecutable(llvm::sys::Path &P, bool WantFile) {
+ bool Exists;
+ return (WantFile ? !llvm::sys::fs::exists(P.str(), Exists) && Exists
+ : P.canExecute());
+}
+
std::string Driver::GetProgramPath(const char *Name, const ToolChain &TC,
bool WantFile) const {
+ std::string TargetSpecificExecutable(DefaultHostTriple + "-" + Name);
// Respect a limited subset of the '-Bprefix' functionality in GCC by
// attempting to use this prefix when lokup up program paths.
for (Driver::prefix_list::const_iterator it = PrefixDirs.begin(),
ie = PrefixDirs.end(); it != ie; ++it) {
llvm::sys::Path P(*it);
+ P.appendComponent(TargetSpecificExecutable);
+ if (isPathExecutable(P, WantFile)) return P.str();
+ P.eraseComponent();
P.appendComponent(Name);
- bool Exists;
- if (WantFile ? !llvm::sys::fs::exists(P.str(), Exists) && Exists
- : P.canExecute())
- return P.str();
+ if (isPathExecutable(P, WantFile)) return P.str();
}
const ToolChain::path_list &List = TC.getProgramPaths();
for (ToolChain::path_list::const_iterator
it = List.begin(), ie = List.end(); it != ie; ++it) {
llvm::sys::Path P(*it);
+ P.appendComponent(TargetSpecificExecutable);
+ if (isPathExecutable(P, WantFile)) return P.str();
+ P.eraseComponent();
P.appendComponent(Name);
- bool Exists;
- if (WantFile ? !llvm::sys::fs::exists(P.str(), Exists) && Exists
- : P.canExecute())
- return P.str();
+ if (isPathExecutable(P, WantFile)) return P.str();
}
// If all else failed, search the path.
- llvm::sys::Path P(llvm::sys::Program::FindProgramByName(Name));
+ llvm::sys::Path
+ P(llvm::sys::Program::FindProgramByName(TargetSpecificExecutable));
+ if (!P.empty())
+ return P.str();
+
+ P = llvm::sys::Path(llvm::sys::Program::FindProgramByName(Name));
if (!P.empty())
return P.str();
return Name;
}
-std::string Driver::GetTemporaryPath(const char *Suffix) const {
+std::string Driver::GetTemporaryPath(StringRef Prefix, const char *Suffix)
+ const {
// FIXME: This is lame; sys::Path should provide this function (in particular,
// it should know how to find the temporary files dir).
std::string Error;
@@ -1363,7 +1532,7 @@ std::string Driver::GetTemporaryPath(const char *Suffix) const {
if (!TmpDir)
TmpDir = "/tmp";
llvm::sys::Path P(TmpDir);
- P.appendComponent("cc");
+ P.appendComponent(Prefix);
if (P.makeUnique(false, &Error)) {
Diag(clang::diag::err_drv_unable_to_make_temp) << Error;
return "";
@@ -1388,6 +1557,8 @@ const HostInfo *Driver::GetHostInfo(const char *TripleStr) const {
case llvm::Triple::AuroraUX:
return createAuroraUXHostInfo(*this, Triple);
case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ case llvm::Triple::IOS:
return createDarwinHostInfo(*this, Triple);
case llvm::Triple::DragonFly:
return createDragonFlyHostInfo(*this, Triple);
diff --git a/lib/Driver/HostInfo.cpp b/lib/Driver/HostInfo.cpp
index 3b1c2c73fd74..292678bf8aa8 100644
--- a/lib/Driver/HostInfo.cpp
+++ b/lib/Driver/HostInfo.cpp
@@ -188,7 +188,7 @@ bool UnknownHostInfo::useDriverDriver() const {
ToolChain *UnknownHostInfo::CreateToolChain(const ArgList &Args,
const char *ArchName) const {
assert(!ArchName &&
- "Unexpected arch name on platform without driver driver support.");
+ "Unexpected arch name on platform without driver support.");
// Automatically handle some instances of -m32/-m64 we know about.
std::string Arch = getArchName();
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index 51055e93f558..5443d70e825c 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -9,6 +9,8 @@
#include "clang/Driver/Job.h"
+#include "llvm/ADT/STLExtras.h"
+
#include <cassert>
using namespace clang::driver;
@@ -28,6 +30,10 @@ JobList::~JobList() {
delete *it;
}
+void JobList::clear() {
+ DeleteContainerPointers(Jobs);
+}
+
void Job::addCommand(Command *C) {
cast<JobList>(this)->addJob(C);
}
diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp
index 0252b3e5cac5..4f5390b6e26b 100644
--- a/lib/Driver/OptTable.cpp
+++ b/lib/Driver/OptTable.cpp
@@ -12,11 +12,12 @@
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Option.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
-#include <cassert>
#include <map>
using namespace clang::driver;
using namespace clang::driver::options;
+using namespace clang;
// Ordering on Info. The ordering is *almost* lexicographic, with two
// exceptions. First, '\0' comes at the end of the alphabet instead of
@@ -116,7 +117,7 @@ OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos)
if (!(getInfo(i) < getInfo(i + 1))) {
getOption(i)->dump();
getOption(i + 1)->dump();
- assert(0 && "Options are not in order!");
+ llvm_unreachable("Options are not in order!");
}
}
#endif
@@ -268,10 +269,10 @@ static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) {
// Add metavar, if used.
switch (Opts.getOptionKind(Id)) {
case Option::GroupClass: case Option::InputClass: case Option::UnknownClass:
- assert(0 && "Invalid option with help text.");
+ llvm_unreachable("Invalid option with help text.");
case Option::MultiArgClass:
- assert(0 && "Cannot print metavar for this kind of option.");
+ llvm_unreachable("Cannot print metavar for this kind of option.");
case Option::FlagClass:
break;
@@ -291,7 +292,7 @@ static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) {
return Name;
}
-static void PrintHelpOptionList(llvm::raw_ostream &OS, llvm::StringRef Title,
+static void PrintHelpOptionList(raw_ostream &OS, StringRef Title,
std::vector<std::pair<std::string,
const char*> > &OptionHelp) {
OS << Title << ":\n";
@@ -342,7 +343,7 @@ static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) {
return getOptionHelpGroup(Opts, GroupID);
}
-void OptTable::PrintHelp(llvm::raw_ostream &OS, const char *Name,
+void OptTable::PrintHelp(raw_ostream &OS, const char *Name,
const char *Title, bool ShowHidden) const {
OS << "OVERVIEW: " << Title << "\n";
OS << '\n';
diff --git a/lib/Driver/Option.cpp b/lib/Driver/Option.cpp
index 90d21a3d0b17..ee1963fd331d 100644
--- a/lib/Driver/Option.cpp
+++ b/lib/Driver/Option.cpp
@@ -12,6 +12,7 @@
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/ErrorHandling.h"
#include <cassert>
#include <algorithm>
using namespace clang::driver;
@@ -61,7 +62,7 @@ void Option::dump() const {
llvm::errs() << "<";
switch (Kind) {
default:
- assert(0 && "Invalid kind");
+ llvm_unreachable("Invalid kind");
#define P(N) case N: llvm::errs() << #N; break
P(GroupClass);
P(InputClass);
@@ -114,8 +115,7 @@ OptionGroup::OptionGroup(OptSpecifier ID, const char *Name,
}
Arg *OptionGroup::accept(const ArgList &Args, unsigned &Index) const {
- assert(0 && "accept() should never be called on an OptionGroup");
- return 0;
+ llvm_unreachable("accept() should never be called on an OptionGroup");
}
InputOption::InputOption(OptSpecifier ID)
@@ -123,8 +123,7 @@ InputOption::InputOption(OptSpecifier ID)
}
Arg *InputOption::accept(const ArgList &Args, unsigned &Index) const {
- assert(0 && "accept() should never be called on an InputOption");
- return 0;
+ llvm_unreachable("accept() should never be called on an InputOption");
}
UnknownOption::UnknownOption(OptSpecifier ID)
@@ -132,8 +131,7 @@ UnknownOption::UnknownOption(OptSpecifier ID)
}
Arg *UnknownOption::accept(const ArgList &Args, unsigned &Index) const {
- assert(0 && "accept() should never be called on an UnknownOption");
- return 0;
+ llvm_unreachable("accept() should never be called on an UnknownOption");
}
FlagOption::FlagOption(OptSpecifier ID, const char *Name,
diff --git a/lib/Driver/Phases.cpp b/lib/Driver/Phases.cpp
index f36000214ab0..b885eeef9832 100644
--- a/lib/Driver/Phases.cpp
+++ b/lib/Driver/Phases.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Phases.h"
+#include "llvm/Support/ErrorHandling.h"
#include <cassert>
@@ -22,6 +23,5 @@ const char *phases::getPhaseName(ID Id) {
case Link: return "linker";
}
- assert(0 && "Invalid phase id.");
- return 0;
+ llvm_unreachable("Invalid phase id.");
}
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index 74b65918f34f..d09ab16814a0 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -18,11 +18,11 @@
#include "clang/Driver/ObjCRuntime.h"
#include "clang/Driver/Options.h"
#include "llvm/Support/ErrorHandling.h"
-
using namespace clang::driver;
+using namespace clang;
-ToolChain::ToolChain(const HostInfo &_Host, const llvm::Triple &_Triple)
- : Host(_Host), Triple(_Triple) {
+ToolChain::ToolChain(const HostInfo &H, const llvm::Triple &T)
+ : Host(H), Triple(T) {
}
ToolChain::~ToolChain() {
@@ -79,7 +79,7 @@ static const char *getARMTargetCPU(const ArgList &Args,
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
return A->getValue(Args);
- llvm::StringRef MArch;
+ StringRef MArch;
if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
// Otherwise, if we have -march= choose the base CPU for that arch.
MArch = A->getValue(Args);
@@ -134,7 +134,7 @@ static const char *getARMTargetCPU(const ArgList &Args,
//
// FIXME: This is redundant with -mcpu, why does LLVM use this.
// FIXME: tblgen this, or kill it!
-static const char *getLLVMArchSuffixForARM(llvm::StringRef CPU) {
+static const char *getLLVMArchSuffixForARM(StringRef CPU) {
if (CPU == "arm7tdmi" || CPU == "arm7tdmi-s" || CPU == "arm710t" ||
CPU == "arm720t" || CPU == "arm9" || CPU == "arm9tdmi" ||
CPU == "arm920" || CPU == "arm920t" || CPU == "arm922t" ||
@@ -169,7 +169,8 @@ static const char *getLLVMArchSuffixForARM(llvm::StringRef CPU) {
return "";
}
-std::string ToolChain::ComputeLLVMTriple(const ArgList &Args) const {
+std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
+ types::ID InputType) const {
switch (getTriple().getArch()) {
default:
return getTripleString();
@@ -182,12 +183,14 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args) const {
// Thumb2 is the default for V7 on Darwin.
//
// FIXME: Thumb should just be another -target-feaure, not in the triple.
- llvm::StringRef Suffix =
+ StringRef Suffix =
getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple));
- bool ThumbDefault =
- (Suffix == "v7" && getTriple().getOS() == llvm::Triple::Darwin);
+ bool ThumbDefault = (Suffix == "v7" && getTriple().isOSDarwin());
std::string ArchName = "arm";
- if (Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, ThumbDefault))
+
+ // Assembly files should start in ARM mode.
+ if (InputType != types::TY_PP_Asm &&
+ Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, ThumbDefault))
ArchName = "thumb";
Triple.setArchName(ArchName + Suffix.str());
@@ -196,25 +199,26 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args) const {
}
}
-std::string ToolChain::ComputeEffectiveClangTriple(const ArgList &Args) const {
+std::string ToolChain::ComputeEffectiveClangTriple(const ArgList &Args,
+ types::ID InputType) const {
// Diagnose use of Darwin OS deployment target arguments on non-Darwin.
if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ,
options::OPT_miphoneos_version_min_EQ,
options::OPT_mios_simulator_version_min_EQ))
- getDriver().Diag(clang::diag::err_drv_clang_unsupported)
+ getDriver().Diag(diag::err_drv_clang_unsupported)
<< A->getAsString(Args);
- return ComputeLLVMTriple(Args);
+ return ComputeLLVMTriple(Args, InputType);
}
ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{
if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
- llvm::StringRef Value = A->getValue(Args);
+ StringRef Value = A->getValue(Args);
if (Value == "libc++")
return ToolChain::CST_Libcxx;
if (Value == "libstdc++")
return ToolChain::CST_Libstdcxx;
- getDriver().Diag(clang::diag::err_drv_invalid_stdlib_name)
+ getDriver().Diag(diag::err_drv_invalid_stdlib_name)
<< A->getAsString(Args);
}
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 1619ef8f84a9..825a83d8b8d8 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -27,6 +27,7 @@
#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"
@@ -41,12 +42,14 @@
using namespace clang::driver;
using namespace clang::driver::toolchains;
+using namespace clang;
/// Darwin - Darwin tool chain for i386 and x86_64.
Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple)
: ToolChain(Host, Triple), TargetInitialized(false),
- ARCRuntimeForSimulator(ARCSimulator_None)
+ ARCRuntimeForSimulator(ARCSimulator_None),
+ LibCXXForSimulator(LibCXXSimulator_None)
{
// Compute the initial Darwin version based on the host.
bool HadExtra;
@@ -54,7 +57,7 @@ Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple)
if (!Driver::GetReleaseVersion(&OSName.c_str()[6],
DarwinVersion[0], DarwinVersion[1],
DarwinVersion[2], HadExtra))
- getDriver().Diag(clang::diag::err_drv_invalid_darwin_version) << OSName;
+ getDriver().Diag(diag::err_drv_invalid_darwin_version) << OSName;
llvm::raw_string_ostream(MacosxVersionMin)
<< "10." << std::max(0, (int)DarwinVersion[0] - 4) << '.'
@@ -108,52 +111,40 @@ void Darwin::configureObjCRuntime(ObjCRuntime &runtime) const {
runtime.HasTerminate = false;
}
-// FIXME: Can we tablegen this?
-static const char *GetArmArchForMArch(llvm::StringRef Value) {
- if (Value == "armv6k")
- return "armv6";
-
- if (Value == "armv5tej")
- return "armv5";
-
- if (Value == "xscale")
- return "xscale";
-
- if (Value == "armv4t")
- return "armv4t";
-
- if (Value == "armv7" || Value == "armv7-a" || Value == "armv7-r" ||
- Value == "armv7-m" || Value == "armv7a" || Value == "armv7r" ||
- Value == "armv7m")
- return "armv7";
-
- return 0;
-}
-
-// FIXME: Can we tablegen this?
-static const char *GetArmArchForMCpu(llvm::StringRef Value) {
- if (Value == "arm10tdmi" || Value == "arm1020t" || Value == "arm9e" ||
- Value == "arm946e-s" || Value == "arm966e-s" ||
- Value == "arm968e-s" || Value == "arm10e" ||
- Value == "arm1020e" || Value == "arm1022e" || Value == "arm926ej-s" ||
- Value == "arm1026ej-s")
- return "armv5";
-
- if (Value == "xscale")
- return "xscale";
-
- if (Value == "arm1136j-s" || Value == "arm1136jf-s" ||
- Value == "arm1176jz-s" || Value == "arm1176jzf-s" ||
- Value == "cortex-m0" )
- return "armv6";
-
- if (Value == "cortex-a8" || Value == "cortex-r4" || Value == "cortex-m3")
- return "armv7";
-
- return 0;
-}
-
-llvm::StringRef Darwin::getDarwinArchName(const ArgList &Args) const {
+/// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2.
+bool Darwin::hasBlocksRuntime() const {
+ if (isTargetIPhoneOS())
+ return !isIPhoneOSVersionLT(3, 2);
+ else
+ return !isMacosxVersionLT(10, 6);
+}
+
+static const char *GetArmArchForMArch(StringRef Value) {
+ return llvm::StringSwitch<const char*>(Value)
+ .Case("armv6k", "armv6")
+ .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")
+ .Default(0);
+}
+
+static const char *GetArmArchForMCpu(StringRef Value) {
+ return llvm::StringSwitch<const char *>(Value)
+ .Cases("arm9e", "arm946e-s", "arm966e-s", "arm968e-s", "arm926ej-s","armv5")
+ .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", "armv7")
+ .Default(0);
+}
+
+StringRef Darwin::getDarwinArchName(const ArgList &Args) const {
switch (getTriple().getArch()) {
default:
return getArchName();
@@ -180,8 +171,9 @@ Darwin::~Darwin() {
delete it->second;
}
-std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args) const {
- llvm::Triple Triple(ComputeLLVMTriple(Args));
+std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args,
+ types::ID InputType) const {
+ llvm::Triple Triple(ComputeLLVMTriple(Args, InputType));
// If the target isn't initialized (e.g., an unknown Darwin platform, return
// the default triple).
@@ -208,9 +200,10 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA,
// Fallback to llvm-gcc for i386 kext compiles, we don't support that ABI.
if (Inputs.size() == 1 &&
types::isCXX(Inputs[0]->getType()) &&
- getTriple().getOS() == llvm::Triple::Darwin &&
+ getTriple().isOSDarwin() &&
getTriple().getArch() == llvm::Triple::x86 &&
- C.getArgs().getLastArg(options::OPT_fapple_kext))
+ (C.getArgs().getLastArg(options::OPT_fapple_kext) ||
+ C.getArgs().getLastArg(options::OPT_mkernel)))
Key = JA.getKind();
else
Key = Action::AnalyzeJobClass;
@@ -232,7 +225,7 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA,
switch (Key) {
case Action::InputClass:
case Action::BindArchClass:
- assert(0 && "Invalid tool kind.");
+ llvm_unreachable("Invalid tool kind.");
case Action::PreprocessJobClass:
T = new tools::darwin::Preprocess(*this); break;
case Action::AnalyzeJobClass:
@@ -253,6 +246,8 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA,
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;
}
}
@@ -263,8 +258,6 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA,
DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple)
: Darwin(Host, Triple)
{
- std::string UsrPrefix = "llvm-gcc-4.2/";
-
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
@@ -277,16 +270,24 @@ DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple)
// For fallback, we need to know how to find the GCC cc1 executables, so we
// also add the GCC libexec paths. This is legacy code that can be removed
// once fallback is no longer useful.
+ AddGCCLibexecPath(DarwinVersion[0]);
+ AddGCCLibexecPath(DarwinVersion[0] - 2);
+ AddGCCLibexecPath(DarwinVersion[0] - 1);
+ AddGCCLibexecPath(DarwinVersion[0] + 1);
+ AddGCCLibexecPath(DarwinVersion[0] + 2);
+}
+
+void DarwinClang::AddGCCLibexecPath(unsigned darwinVersion) {
std::string ToolChainDir = "i686-apple-darwin";
- ToolChainDir += llvm::utostr(DarwinVersion[0]);
+ ToolChainDir += llvm::utostr(darwinVersion);
ToolChainDir += "/4.2.1";
std::string Path = getDriver().Dir;
- Path += "/../" + UsrPrefix + "libexec/gcc/";
+ Path += "/../llvm-gcc-4.2/libexec/gcc/";
Path += ToolChainDir;
getProgramPaths().push_back(Path);
- Path = "/usr/" + UsrPrefix + "libexec/gcc/";
+ Path = "/usr/llvm-gcc-4.2/libexec/gcc/";
Path += ToolChainDir;
getProgramPaths().push_back(Path);
}
@@ -304,7 +305,7 @@ void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args,
P.appendComponent("gcc");
switch (getTriple().getArch()) {
default:
- assert(0 && "Invalid Darwin arch!");
+ llvm_unreachable("Invalid Darwin arch!");
case llvm::Triple::x86:
case llvm::Triple::x86_64:
P.appendComponent("i686-apple-darwin10");
@@ -328,7 +329,7 @@ void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args,
case llvm::Triple::arm:
case llvm::Triple::thumb: {
std::string Triple = ComputeLLVMTriple(Args);
- llvm::StringRef TripleStr = Triple;
+ StringRef TripleStr = Triple;
if (TripleStr.startswith("armv5") || TripleStr.startswith("thumbv5"))
ArchSpecificDir = "v5";
else if (TripleStr.startswith("armv6") || TripleStr.startswith("thumbv6"))
@@ -360,8 +361,8 @@ void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args,
void DarwinClang::AddLinkARCArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
-
- CmdArgs.push_back("-force_load");
+
+ CmdArgs.push_back("-force_load");
llvm::sys::Path P(getDriver().ClangExecutable);
P.eraseComponent(); // 'clang'
P.eraseComponent(); // 'bin'
@@ -383,13 +384,13 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args,
}
void DarwinClang::AddLinkRuntimeLib(const ArgList &Args,
- ArgStringList &CmdArgs,
+ ArgStringList &CmdArgs,
const char *DarwinStaticLib) 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.
bool Exists;
@@ -408,7 +409,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
// cares. This is useful in situations where someone wants to statically link
// something like libstdc++, and needs its runtime support routines.
if (const Arg *A = Args.getLastArg(options::OPT_static_libgcc)) {
- getDriver().Diag(clang::diag::err_drv_unsupported_opt)
+ getDriver().Diag(diag::err_drv_unsupported_opt)
<< A->getAsString(Args);
return;
}
@@ -421,8 +422,9 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
if (isTargetIPhoneOS()) {
// If we are compiling as iOS / simulator, don't attempt to link libgcc_s.1,
// it never went into the SDK.
- if (!isTargetIOSSimulator())
- CmdArgs.push_back("-lgcc_s.1");
+ // Linking against libgcc_s.1 isn't needed for iOS 5.0+
+ if (isIPhoneOSVersionLT(5, 0) && !isTargetIOSSimulator())
+ CmdArgs.push_back("-lgcc_s.1");
// We currently always need a static runtime library for iOS.
AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.ios.a");
@@ -452,7 +454,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
}
}
-static inline llvm::StringRef SimulatorVersionDefineName() {
+static inline StringRef SimulatorVersionDefineName() {
return "__IPHONE_OS_VERSION_MIN_REQUIRED";
}
@@ -461,11 +463,11 @@ static inline llvm::StringRef SimulatorVersionDefineName() {
// and return the grouped values as integers, e.g:
// __IPHONE_OS_VERSION_MIN_REQUIRED=40201
// will return Major=4, Minor=2, Micro=1.
-static bool GetVersionFromSimulatorDefine(llvm::StringRef define,
+static bool GetVersionFromSimulatorDefine(StringRef define,
unsigned &Major, unsigned &Minor,
unsigned &Micro) {
assert(define.startswith(SimulatorVersionDefineName()));
- llvm::StringRef name, version;
+ StringRef name, version;
llvm::tie(name, version) = define.split('=');
if (version.empty())
return false;
@@ -496,13 +498,15 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
if (!iOSVersion) {
for (arg_iterator it = Args.filtered_begin(options::OPT_D),
ie = Args.filtered_end(); it != ie; ++it) {
- llvm::StringRef define = (*it)->getValue(Args);
+ StringRef define = (*it)->getValue(Args);
if (define.startswith(SimulatorVersionDefineName())) {
- unsigned Major, Minor, Micro;
+ unsigned Major = 0, Minor = 0, Micro = 0;
if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) &&
Major < 10 && Minor < 100 && Micro < 100) {
ARCRuntimeForSimulator = Major < 5 ? ARCSimulator_NoARCRuntime
: ARCSimulator_HasARCRuntime;
+ LibCXXForSimulator = Major < 5 ? LibCXXSimulator_NotAvailable
+ : LibCXXSimulator_Available;
}
break;
}
@@ -510,61 +514,78 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
}
if (OSXVersion && (iOSVersion || iOSSimVersion)) {
- getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with)
+ getDriver().Diag(diag::err_drv_argument_not_allowed_with)
<< OSXVersion->getAsString(Args)
<< (iOSVersion ? iOSVersion : iOSSimVersion)->getAsString(Args);
iOSVersion = iOSSimVersion = 0;
} else if (iOSVersion && iOSSimVersion) {
- getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with)
+ getDriver().Diag(diag::err_drv_argument_not_allowed_with)
<< iOSVersion->getAsString(Args)
<< iOSSimVersion->getAsString(Args);
iOSSimVersion = 0;
} else if (!OSXVersion && !iOSVersion && !iOSSimVersion) {
- // If not deployment target was specified on the command line, check for
+ // If no deployment target was specified on the command line, check for
// environment defines.
- const char *OSXTarget = ::getenv("MACOSX_DEPLOYMENT_TARGET");
- const char *iOSTarget = ::getenv("IPHONEOS_DEPLOYMENT_TARGET");
- const char *iOSSimTarget = ::getenv("IOS_SIMULATOR_DEPLOYMENT_TARGET");
-
- // Ignore empty strings.
- if (OSXTarget && OSXTarget[0] == '\0')
- OSXTarget = 0;
- if (iOSTarget && iOSTarget[0] == '\0')
- iOSTarget = 0;
- if (iOSSimTarget && iOSSimTarget[0] == '\0')
- iOSSimTarget = 0;
+ StringRef OSXTarget;
+ StringRef iOSTarget;
+ StringRef iOSSimTarget;
+ if (char *env = ::getenv("MACOSX_DEPLOYMENT_TARGET"))
+ OSXTarget = env;
+ if (char *env = ::getenv("IPHONEOS_DEPLOYMENT_TARGET"))
+ iOSTarget = env;
+ if (char *env = ::getenv("IOS_SIMULATOR_DEPLOYMENT_TARGET"))
+ iOSSimTarget = env;
+
+ // If no '-miphoneos-version-min' specified on the command line and
+ // IPHONEOS_DEPLOYMENT_TARGET is not defined, see if we can set the default
+ // based on isysroot.
+ if (iOSTarget.empty()) {
+ if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
+ StringRef first, second;
+ StringRef isysroot = A->getValue(Args);
+ llvm::tie(first, second) = isysroot.split(StringRef("SDKs/iPhoneOS"));
+ if (second != "")
+ iOSTarget = second.substr(0,3);
+ }
+ }
+
+ // If no OSX or iOS target has been specified and we're compiling for armv7,
+ // go ahead as assume we're targeting iOS.
+ if (OSXTarget.empty() && iOSTarget.empty())
+ if (getDarwinArchName(Args) == "armv7")
+ iOSTarget = "0.0";
// Handle conflicting deployment targets
//
// FIXME: Don't hardcode default here.
// Do not allow conflicts with the iOS simulator target.
- if (iOSSimTarget && (OSXTarget || iOSTarget)) {
- getDriver().Diag(clang::diag::err_drv_conflicting_deployment_targets)
+ if (!iOSSimTarget.empty() && (!OSXTarget.empty() || !iOSTarget.empty())) {
+ getDriver().Diag(diag::err_drv_conflicting_deployment_targets)
<< "IOS_SIMULATOR_DEPLOYMENT_TARGET"
- << (OSXTarget ? "MACOSX_DEPLOYMENT_TARGET" :
+ << (!OSXTarget.empty() ? "MACOSX_DEPLOYMENT_TARGET" :
"IPHONEOS_DEPLOYMENT_TARGET");
}
// Allow conflicts among OSX and iOS for historical reasons, but choose the
// default platform.
- if (OSXTarget && iOSTarget) {
+ if (!OSXTarget.empty() && !iOSTarget.empty()) {
if (getTriple().getArch() == llvm::Triple::arm ||
getTriple().getArch() == llvm::Triple::thumb)
- OSXTarget = 0;
+ OSXTarget = "";
else
- iOSTarget = 0;
+ iOSTarget = "";
}
- if (OSXTarget) {
+ if (!OSXTarget.empty()) {
const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
OSXVersion = Args.MakeJoinedArg(0, O, OSXTarget);
Args.append(OSXVersion);
- } else if (iOSTarget) {
+ } else if (!iOSTarget.empty()) {
const Option *O = Opts.getOption(options::OPT_miphoneos_version_min_EQ);
iOSVersion = Args.MakeJoinedArg(0, O, iOSTarget);
Args.append(iOSVersion);
- } else if (iOSSimTarget) {
+ } else if (!iOSSimTarget.empty()) {
const Option *O = Opts.getOption(
options::OPT_mios_simulator_version_min_EQ);
iOSSimVersion = Args.MakeJoinedArg(0, O, iOSSimTarget);
@@ -580,7 +601,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
// Reject invalid architecture combinations.
if (iOSSimVersion && (getTriple().getArch() != llvm::Triple::x86 &&
getTriple().getArch() != llvm::Triple::x86_64)) {
- getDriver().Diag(clang::diag::err_drv_invalid_arch_for_deployment_target)
+ getDriver().Diag(diag::err_drv_invalid_arch_for_deployment_target)
<< getTriple().getArchName() << iOSSimVersion->getAsString(Args);
}
@@ -592,7 +613,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
if (!Driver::GetReleaseVersion(OSXVersion->getValue(Args), Major, Minor,
Micro, HadExtra) || HadExtra ||
Major != 10 || Minor >= 100 || Micro >= 100)
- getDriver().Diag(clang::diag::err_drv_invalid_version_number)
+ getDriver().Diag(diag::err_drv_invalid_version_number)
<< OSXVersion->getAsString(Args);
} else {
const Arg *Version = iOSVersion ? iOSVersion : iOSSimVersion;
@@ -600,7 +621,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
if (!Driver::GetReleaseVersion(Version->getValue(Args), Major, Minor,
Micro, HadExtra) || HadExtra ||
Major >= 10 || Minor >= 100 || Micro >= 100)
- getDriver().Diag(clang::diag::err_drv_invalid_version_number)
+ getDriver().Diag(diag::err_drv_invalid_version_number)
<< Version->getAsString(Args);
}
@@ -704,7 +725,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
// triple arch, or the arch being bound.
//
// FIXME: Canonicalize name.
- llvm::StringRef XarchArch = A->getValue(Args, 0);
+ StringRef XarchArch = A->getValue(Args, 0);
if (!(XarchArch == getArchName() ||
(BoundArch && XarchArch == BoundArch)))
continue;
@@ -723,11 +744,11 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
// use isDriverOption() as an approximation, although things
// like -O4 are going to slip through.
if (!XarchArg || Index > Prev + 1) {
- getDriver().Diag(clang::diag::err_drv_invalid_Xarch_argument_with_args)
+ getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args)
<< A->getAsString(Args);
continue;
} else if (XarchArg->getOption().isDriverOption()) {
- getDriver().Diag(clang::diag::err_drv_invalid_Xarch_argument_isdriver)
+ getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver)
<< A->getAsString(Args);
continue;
}
@@ -764,7 +785,6 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
case options::OPT_fapple_kext:
DAL->append(A);
DAL->AddFlagArg(A, Opts.getOption(options::OPT_static));
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_static));
break;
case options::OPT_dependency_file:
@@ -784,12 +804,6 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
Opts.getOption(options::OPT_feliminate_unused_debug_symbols));
break;
- case options::OPT_fterminated_vtables:
- case options::OPT_findirect_virtual_calls:
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_fapple_kext));
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_static));
- break;
-
case options::OPT_shared:
DAL->AddFlagArg(A, Opts.getOption(options::OPT_dynamiclib));
break;
@@ -830,7 +844,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
// Add the arch options based on the particular spelling of -arch, to match
// how the driver driver works.
if (BoundArch) {
- llvm::StringRef Name = BoundArch;
+ StringRef Name = BoundArch;
const Option *MCpu = Opts.getOption(options::OPT_mcpu_EQ);
const Option *MArch = Opts.getOption(options::OPT_march_EQ);
@@ -900,6 +914,28 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
// argument.
AddDeploymentTarget(*DAL);
+ // Validate the C++ standard library choice.
+ CXXStdlibType Type = GetCXXStdlibType(*DAL);
+ if (Type == ToolChain::CST_Libcxx) {
+ switch (LibCXXForSimulator) {
+ case LibCXXSimulator_None:
+ // Handle non-simulator cases.
+ if (isTargetIPhoneOS()) {
+ if (isIPhoneOSVersionLT(5, 0)) {
+ getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment)
+ << "iOS 5.0";
+ }
+ }
+ break;
+ case LibCXXSimulator_NotAvailable:
+ getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment)
+ << "iOS 5.0";
+ break;
+ case LibCXXSimulator_Available:
+ break;
+ }
+ }
+
return DAL;
}
@@ -942,8 +978,9 @@ bool Darwin::SupportsObjCGC() const {
}
std::string
-Darwin_Generic_GCC::ComputeEffectiveClangTriple(const ArgList &Args) const {
- return ComputeLLVMTriple(Args);
+Darwin_Generic_GCC::ComputeEffectiveClangTriple(const ArgList &Args,
+ types::ID InputType) const {
+ return ComputeLLVMTriple(Args, InputType);
}
/// Generic_GCC - A tool chain using the 'gcc' command to perform
@@ -978,7 +1015,7 @@ Tool &Generic_GCC::SelectTool(const Compilation &C,
switch (Key) {
case Action::InputClass:
case Action::BindArchClass:
- assert(0 && "Invalid tool kind.");
+ llvm_unreachable("Invalid tool kind.");
case Action::PreprocessJobClass:
T = new tools::gcc::Preprocess(*this); break;
case Action::PrecompileJobClass:
@@ -998,6 +1035,8 @@ Tool &Generic_GCC::SelectTool(const Compilation &C,
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;
}
}
@@ -1067,7 +1106,7 @@ Tool &TCEToolChain::SelectTool(const Compilation &C,
case Action::AnalyzeJobClass:
T = new tools::Clang(*this); break;
default:
- assert(false && "Unsupported action for TCE target.");
+ llvm_unreachable("Unsupported action for TCE target.");
}
}
return *T;
@@ -1346,32 +1385,24 @@ static bool IsUbuntu(enum LinuxDistro Distro) {
Distro == UbuntuNatty || Distro == UbuntuOneiric;
}
-static bool IsDebianBased(enum LinuxDistro Distro) {
- return IsDebian(Distro) || IsUbuntu(Distro);
-}
-
+// FIXME: This should be deleted. We should assume a multilib environment, and
+// fallback gracefully if any parts of it are absent.
static bool HasMultilib(llvm::Triple::ArchType Arch, enum LinuxDistro Distro) {
if (Arch == llvm::Triple::x86_64) {
bool Exists;
if (Distro == Exherbo &&
(llvm::sys::fs::exists("/usr/lib32/libc.so", Exists) || !Exists))
return false;
-
- return true;
}
- if (Arch == llvm::Triple::ppc64)
- return true;
- if ((Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc) &&
- IsDebianBased(Distro))
- return true;
- return false;
+
+ return true;
}
static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
llvm::OwningPtr<llvm::MemoryBuffer> File;
if (!llvm::MemoryBuffer::getFile("/etc/lsb-release", File)) {
- llvm::StringRef Data = File.get()->getBuffer();
- llvm::SmallVector<llvm::StringRef, 8> Lines;
+ StringRef Data = File.get()->getBuffer();
+ SmallVector<StringRef, 8> Lines;
Data.split(Lines, "\n");
for (unsigned int i = 0, s = Lines.size(); i < s; ++ i) {
if (Lines[i] == "DISTRIB_CODENAME=hardy")
@@ -1395,7 +1426,7 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
}
if (!llvm::MemoryBuffer::getFile("/etc/redhat-release", File)) {
- llvm::StringRef Data = File.get()->getBuffer();
+ StringRef Data = File.get()->getBuffer();
if (Data.startswith("Fedora release 15"))
return Fedora15;
else if (Data.startswith("Fedora release 14"))
@@ -1403,24 +1434,24 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
else if (Data.startswith("Fedora release 13"))
return Fedora13;
else if (Data.startswith("Fedora release") &&
- Data.find("Rawhide") != llvm::StringRef::npos)
+ Data.find("Rawhide") != StringRef::npos)
return FedoraRawhide;
else if (Data.startswith("Red Hat Enterprise Linux") &&
- Data.find("release 6") != llvm::StringRef::npos)
+ Data.find("release 6") != StringRef::npos)
return RHEL6;
else if ((Data.startswith("Red Hat Enterprise Linux") ||
Data.startswith("CentOS")) &&
- Data.find("release 5") != llvm::StringRef::npos)
+ Data.find("release 5") != StringRef::npos)
return RHEL5;
else if ((Data.startswith("Red Hat Enterprise Linux") ||
Data.startswith("CentOS")) &&
- Data.find("release 4") != llvm::StringRef::npos)
+ Data.find("release 4") != StringRef::npos)
return RHEL4;
return UnknownDistro;
}
if (!llvm::MemoryBuffer::getFile("/etc/debian_version", File)) {
- llvm::StringRef Data = File.get()->getBuffer();
+ StringRef Data = File.get()->getBuffer();
if (Data[0] == '5')
return DebianLenny;
else if (Data.startswith("squeeze/sid"))
@@ -1431,7 +1462,7 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
}
if (!llvm::MemoryBuffer::getFile("/etc/SuSE-release", File)) {
- llvm::StringRef Data = File.get()->getBuffer();
+ StringRef Data = File.get()->getBuffer();
if (Data.startswith("openSUSE 11.3"))
return OpenSuse11_3;
else if (Data.startswith("openSUSE 11.4"))
@@ -1451,164 +1482,282 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
return UnknownDistro;
}
-static std::string findGCCBaseLibDir(const std::string &GccTriple) {
- // FIXME: Using CXX_INCLUDE_ROOT is here is a bit of a hack, but
- // avoids adding yet another option to configure/cmake.
- // It would probably be cleaner to break it in two variables
- // CXX_GCC_ROOT with just /foo/bar
- // CXX_GCC_VER with 4.5.2
- // Then we would have
- // CXX_INCLUDE_ROOT = CXX_GCC_ROOT/include/c++/CXX_GCC_VER
- // and this function would return
- // CXX_GCC_ROOT/lib/gcc/CXX_INCLUDE_ARCH/CXX_GCC_VER
- llvm::SmallString<128> CxxIncludeRoot(CXX_INCLUDE_ROOT);
- if (CxxIncludeRoot != "") {
- // This is of the form /foo/bar/include/c++/4.5.2/
- if (CxxIncludeRoot.back() == '/')
- llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the /
- llvm::StringRef Version = llvm::sys::path::filename(CxxIncludeRoot);
- llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the version
- llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the c++
- llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the include
- std::string ret(CxxIncludeRoot.c_str());
- ret.append("/lib/gcc/");
- ret.append(CXX_INCLUDE_ARCH);
- ret.append("/");
- ret.append(Version);
- return ret;
- }
- static const char* GccVersions[] = {"4.6.1", "4.6.0", "4.6",
- "4.5.2", "4.5.1", "4.5",
- "4.4.5", "4.4.4", "4.4.3", "4.4",
- "4.3.4", "4.3.3", "4.3.2", "4.3",
- "4.2.4", "4.2.3", "4.2.2", "4.2.1",
- "4.2", "4.1.1"};
+/// \brief Trivial helper function to simplify code checking path existence.
+static bool PathExists(StringRef Path) {
bool Exists;
- for (unsigned i = 0; i < sizeof(GccVersions)/sizeof(char*); ++i) {
- std::string Suffix = GccTriple + "/" + GccVersions[i];
- std::string t1 = "/usr/lib/gcc/" + Suffix;
- if (!llvm::sys::fs::exists(t1 + "/crtbegin.o", Exists) && Exists)
- return t1;
- std::string t2 = "/usr/lib64/gcc/" + Suffix;
- if (!llvm::sys::fs::exists(t2 + "/crtbegin.o", Exists) && Exists)
- return t2;
- std::string t3 = "/usr/lib/" + GccTriple + "/gcc/" + Suffix;
- if (!llvm::sys::fs::exists(t3 + "/crtbegin.o", Exists) && Exists)
- return t3;
- }
- return "";
+ if (!llvm::sys::fs::exists(Path, Exists))
+ return Exists;
+ return false;
}
-Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
- : Generic_ELF(Host, Triple) {
- llvm::Triple::ArchType Arch =
- llvm::Triple(getDriver().DefaultHostTriple).getArch();
+namespace {
+/// \brief This is a class to find a viable GCC installation for Clang to use.
+///
+/// This class tries to find a GCC installation on the system, and report
+/// information about it. It starts from the host information provided to the
+/// Driver, and has logic for fuzzing that where appropriate.
+class GCCInstallationDetector {
+ /// \brief Struct to store and manipulate GCC versions.
+ ///
+ /// We rely on assumptions about the form and structure of GCC version
+ /// numbers: they consist of at most three '.'-separated components, and each
+ /// component is a non-negative integer.
+ struct GCCVersion {
+ unsigned Major, Minor, Patch;
+
+ static GCCVersion Parse(StringRef VersionText) {
+ const GCCVersion BadVersion = {0, 0, 0};
+ std::pair<StringRef, StringRef> First = VersionText.split('.');
+ std::pair<StringRef, StringRef> Second = First.second.split('.');
+
+ GCCVersion GoodVersion = {0, 0, 0};
+ if (First.first.getAsInteger(10, GoodVersion.Major))
+ return BadVersion;
+ if (Second.first.getAsInteger(10, GoodVersion.Minor))
+ return BadVersion;
+ // We accept a number, or a string for the patch version, in case there
+ // is a strang suffix, or other mangling: '4.1.x', '4.1.2-rc3'. When it
+ // isn't a number, we just use '0' as the number but accept it.
+ if (Second.first.getAsInteger(10, GoodVersion.Patch))
+ GoodVersion.Patch = 0;
+ return GoodVersion;
+ }
- std::string Suffix32 = "";
- if (Arch == llvm::Triple::x86_64)
- Suffix32 = "/32";
+ bool 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;
+ return Patch < RHS.Patch;
+ }
+ bool operator>(const GCCVersion &RHS) const { return RHS < *this; }
+ bool operator<=(const GCCVersion &RHS) const { return !(*this > RHS); }
+ bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); }
+ };
+
+ bool IsValid;
+ std::string GccTriple;
+
+ // FIXME: These might be better as path objects.
+ std::string GccInstallPath;
+ std::string GccParentLibPath;
+
+ llvm::SmallString<128> CxxIncludeRoot;
+
+public:
+ /// \brief Construct a GCCInstallationDetector from the driver.
+ ///
+ /// This performs all of the autodetection and sets up the various paths.
+ /// Once constructed, a GCCInstallation is esentially immutable.
+ GCCInstallationDetector(const Driver &D)
+ : IsValid(false),
+ GccTriple(D.DefaultHostTriple),
+ CxxIncludeRoot(CXX_INCLUDE_ROOT) {
+ // FIXME: Using CXX_INCLUDE_ROOT is here is a bit of a hack, but
+ // avoids adding yet another option to configure/cmake.
+ // It would probably be cleaner to break it in two variables
+ // CXX_GCC_ROOT with just /foo/bar
+ // CXX_GCC_VER with 4.5.2
+ // Then we would have
+ // CXX_INCLUDE_ROOT = CXX_GCC_ROOT/include/c++/CXX_GCC_VER
+ // and this function would return
+ // CXX_GCC_ROOT/lib/gcc/CXX_INCLUDE_ARCH/CXX_GCC_VER
+ if (CxxIncludeRoot != "") {
+ // This is of the form /foo/bar/include/c++/4.5.2/
+ if (CxxIncludeRoot.back() == '/')
+ llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the /
+ StringRef Version = llvm::sys::path::filename(CxxIncludeRoot);
+ llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the version
+ llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the c++
+ llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the include
+ GccInstallPath = CxxIncludeRoot.str();
+ GccInstallPath.append("/lib/gcc/");
+ GccInstallPath.append(CXX_INCLUDE_ARCH);
+ GccInstallPath.append("/");
+ GccInstallPath.append(Version);
+ GccParentLibPath = GccInstallPath + "/../../..";
+ IsValid = true;
+ return;
+ }
- std::string Suffix64 = "";
- if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc)
- Suffix64 = "/64";
+ llvm::Triple::ArchType HostArch = llvm::Triple(GccTriple).getArch();
+ // The library directories which may contain GCC installations.
+ SmallVector<StringRef, 4> CandidateLibDirs;
+ // The compatible GCC triples for this particular architecture.
+ SmallVector<StringRef, 10> CandidateTriples;
+ CollectLibDirsAndTriples(HostArch, CandidateLibDirs, CandidateTriples);
+
+ // Always include the default host triple as the final fallback if no
+ // specific triple is detected.
+ CandidateTriples.push_back(D.DefaultHostTriple);
+
+ // Compute the set of prefixes for our search.
+ SmallVector<std::string, 8> Prefixes(D.PrefixDirs.begin(),
+ D.PrefixDirs.end());
+ Prefixes.push_back(D.SysRoot);
+ Prefixes.push_back(D.SysRoot + "/usr");
+ Prefixes.push_back(D.InstalledDir + "/..");
+
+ // Loop over the various components which exist and select the best GCC
+ // installation available. GCC installs are ranked by version number.
+ GCCVersion BestVersion = {0, 0, 0};
+ for (unsigned i = 0, ie = Prefixes.size(); i < ie; ++i) {
+ if (!PathExists(Prefixes[i]))
+ continue;
+ for (unsigned j = 0, je = CandidateLibDirs.size(); j < je; ++j) {
+ const std::string LibDir = Prefixes[i] + CandidateLibDirs[j].str();
+ if (!PathExists(LibDir))
+ continue;
+ for (unsigned k = 0, ke = CandidateTriples.size(); k < ke; ++k)
+ ScanLibDirForGCCTriple(LibDir, CandidateTriples[k], BestVersion);
+ }
+ }
+ }
- std::string Lib32 = "lib";
+ /// \brief Check whether we detected a valid GCC install.
+ bool isValid() const { return IsValid; }
+
+ /// \brief Get the GCC triple for the detected install.
+ const std::string &getTriple() const { return GccTriple; }
+
+ /// \brief Get the detected GCC installation path.
+ const std::string &getInstallPath() const { return GccInstallPath; }
+
+ /// \brief Get the detected GCC parent lib path.
+ const std::string &getParentLibPath() const { return GccParentLibPath; }
+
+private:
+ static void CollectLibDirsAndTriples(llvm::Triple::ArchType HostArch,
+ SmallVectorImpl<StringRef> &LibDirs,
+ SmallVectorImpl<StringRef> &Triples) {
+ if (HostArch == llvm::Triple::arm || HostArch == llvm::Triple::thumb) {
+ static const char *const ARMLibDirs[] = { "/lib" };
+ static const char *const ARMTriples[] = { "arm-linux-gnueabi" };
+ LibDirs.append(ARMLibDirs, ARMLibDirs + llvm::array_lengthof(ARMLibDirs));
+ Triples.append(ARMTriples, ARMTriples + llvm::array_lengthof(ARMTriples));
+ } else if (HostArch == llvm::Triple::x86_64) {
+ static const char *const X86_64LibDirs[] = { "/lib64", "/lib" };
+ static const char *const X86_64Triples[] = {
+ "x86_64-linux-gnu",
+ "x86_64-unknown-linux-gnu",
+ "x86_64-pc-linux-gnu",
+ "x86_64-redhat-linux6E",
+ "x86_64-redhat-linux",
+ "x86_64-suse-linux",
+ "x86_64-manbo-linux-gnu",
+ "x86_64-linux-gnu",
+ "x86_64-slackware-linux"
+ };
+ LibDirs.append(X86_64LibDirs,
+ X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs));
+ Triples.append(X86_64Triples,
+ X86_64Triples + llvm::array_lengthof(X86_64Triples));
+ } else if (HostArch == llvm::Triple::x86) {
+ static const char *const X86LibDirs[] = { "/lib32", "/lib" };
+ static const char *const X86Triples[] = {
+ "i686-linux-gnu",
+ "i386-linux-gnu",
+ "i686-pc-linux-gnu",
+ "i486-linux-gnu",
+ "i686-redhat-linux",
+ "i386-redhat-linux",
+ "i586-suse-linux",
+ "i486-slackware-linux"
+ };
+ LibDirs.append(X86LibDirs, X86LibDirs + llvm::array_lengthof(X86LibDirs));
+ Triples.append(X86Triples, X86Triples + llvm::array_lengthof(X86Triples));
+ } else if (HostArch == llvm::Triple::ppc) {
+ static const char *const PPCLibDirs[] = { "/lib32", "/lib" };
+ static const char *const PPCTriples[] = {
+ "powerpc-linux-gnu",
+ "powerpc-unknown-linux-gnu"
+ };
+ LibDirs.append(PPCLibDirs, PPCLibDirs + llvm::array_lengthof(PPCLibDirs));
+ Triples.append(PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples));
+ } else if (HostArch == llvm::Triple::ppc64) {
+ static const char *const PPC64LibDirs[] = { "/lib64", "/lib" };
+ static const char *const PPC64Triples[] = {
+ "powerpc64-unknown-linux-gnu"
+ };
+ LibDirs.append(PPC64LibDirs,
+ PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs));
+ Triples.append(PPC64Triples,
+ PPC64Triples + llvm::array_lengthof(PPC64Triples));
+ }
+ }
- bool Exists;
- if (!llvm::sys::fs::exists("/lib32", Exists) && Exists)
- Lib32 = "lib32";
-
- std::string Lib64 = "lib";
- bool Symlink;
- if (!llvm::sys::fs::exists("/lib64", Exists) && Exists &&
- (llvm::sys::fs::is_symlink("/lib64", Symlink) || !Symlink))
- Lib64 = "lib64";
-
- std::string GccTriple = "";
- if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) {
- if (!llvm::sys::fs::exists("/usr/lib/gcc/arm-linux-gnueabi", Exists) &&
- Exists)
- GccTriple = "arm-linux-gnueabi";
- } else if (Arch == llvm::Triple::x86_64) {
- if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-linux-gnu", Exists) &&
- Exists)
- GccTriple = "x86_64-linux-gnu";
- else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-unknown-linux-gnu",
- Exists) && Exists)
- GccTriple = "x86_64-unknown-linux-gnu";
- else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-pc-linux-gnu",
- Exists) && Exists)
- GccTriple = "x86_64-pc-linux-gnu";
- else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-redhat-linux6E",
- Exists) && Exists)
- GccTriple = "x86_64-redhat-linux6E";
- else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-redhat-linux",
- Exists) && Exists)
- GccTriple = "x86_64-redhat-linux";
- else if (!llvm::sys::fs::exists("/usr/lib64/gcc/x86_64-suse-linux",
- Exists) && Exists)
- GccTriple = "x86_64-suse-linux";
- else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-manbo-linux-gnu",
- Exists) && Exists)
- GccTriple = "x86_64-manbo-linux-gnu";
- else if (!llvm::sys::fs::exists("/usr/lib/x86_64-linux-gnu/gcc",
- Exists) && Exists)
- GccTriple = "x86_64-linux-gnu";
- } else if (Arch == llvm::Triple::x86) {
- if (!llvm::sys::fs::exists("/usr/lib/gcc/i686-linux-gnu", Exists) && Exists)
- GccTriple = "i686-linux-gnu";
- else if (!llvm::sys::fs::exists("/usr/lib/gcc/i686-pc-linux-gnu", Exists) &&
- Exists)
- GccTriple = "i686-pc-linux-gnu";
- else if (!llvm::sys::fs::exists("/usr/lib/gcc/i486-linux-gnu", Exists) &&
- Exists)
- GccTriple = "i486-linux-gnu";
- else if (!llvm::sys::fs::exists("/usr/lib/gcc/i686-redhat-linux", Exists) &&
- Exists)
- GccTriple = "i686-redhat-linux";
- else if (!llvm::sys::fs::exists("/usr/lib/gcc/i586-suse-linux", Exists) &&
- Exists)
- GccTriple = "i586-suse-linux";
- else if (!llvm::sys::fs::exists("/usr/lib/gcc/i486-slackware-linux", Exists)
- && Exists)
- GccTriple = "i486-slackware-linux";
- } else if (Arch == llvm::Triple::ppc) {
- if (!llvm::sys::fs::exists("/usr/lib/powerpc-linux-gnu", Exists) && Exists)
- GccTriple = "powerpc-linux-gnu";
- else if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc-unknown-linux-gnu",
- Exists) && Exists)
- GccTriple = "powerpc-unknown-linux-gnu";
- } else if (Arch == llvm::Triple::ppc64) {
- if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc64-unknown-linux-gnu",
- Exists) && Exists)
- GccTriple = "powerpc64-unknown-linux-gnu";
- else if (!llvm::sys::fs::exists("/usr/lib64/gcc/"
- "powerpc64-unknown-linux-gnu", Exists) &&
- Exists)
- GccTriple = "powerpc64-unknown-linux-gnu";
+ void ScanLibDirForGCCTriple(const std::string &LibDir,
+ StringRef CandidateTriple,
+ GCCVersion &BestVersion) {
+ // There are various different suffixes involving the triple we
+ // check for. We also record what is necessary to walk from each back
+ // up to the lib directory.
+ const std::string Suffixes[] = {
+ "/gcc/" + CandidateTriple.str(),
+ "/" + CandidateTriple.str() + "/gcc/" + CandidateTriple.str(),
+
+ // Ubuntu has a strange mis-matched pair of triples that this happens to
+ // match.
+ // FIXME: It may be worthwhile to generalize this and look for a second
+ // triple.
+ "/" + CandidateTriple.str() + "/gcc/i686-linux-gnu"
+ };
+ const std::string InstallSuffixes[] = {
+ "/../../..",
+ "/../../../..",
+ "/../../../.."
+ };
+ // Only look at the final, weird Ubuntu suffix for i386-linux-gnu.
+ const unsigned NumSuffixes = (llvm::array_lengthof(Suffixes) -
+ (CandidateTriple != "i386-linux-gnu"));
+ for (unsigned i = 0; i < NumSuffixes; ++i) {
+ StringRef Suffix = Suffixes[i];
+ llvm::error_code EC;
+ for (llvm::sys::fs::directory_iterator LI(LibDir + Suffix, EC), LE;
+ !EC && LI != LE; LI = LI.increment(EC)) {
+ StringRef VersionText = llvm::sys::path::filename(LI->path());
+ GCCVersion CandidateVersion = GCCVersion::Parse(VersionText);
+ static const GCCVersion MinVersion = { 4, 1, 1 };
+ if (CandidateVersion < MinVersion)
+ continue;
+ if (CandidateVersion <= BestVersion)
+ continue;
+ if (!PathExists(LI->path() + "/crtbegin.o"))
+ continue;
+
+ BestVersion = CandidateVersion;
+ GccTriple = CandidateTriple.str();
+ // FIXME: We hack together the directory name here instead of
+ // using LI to ensure stable path separators across Windows and
+ // Linux.
+ GccInstallPath = LibDir + Suffixes[i] + "/" + VersionText.str();
+ GccParentLibPath = GccInstallPath + InstallSuffixes[i];
+ IsValid = true;
+ }
+ }
}
+};
+}
- std::string Base = findGCCBaseLibDir(GccTriple);
- path_list &Paths = getFilePaths();
- bool Is32Bits = (getArch() == llvm::Triple::x86 ||
- getArch() == llvm::Triple::ppc);
+static void addPathIfExists(const std::string &Path,
+ ToolChain::path_list &Paths) {
+ if (PathExists(Path)) Paths.push_back(Path);
+}
- std::string Suffix;
- std::string Lib;
+Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
+ : Generic_ELF(Host, Triple) {
+ llvm::Triple::ArchType Arch =
+ llvm::Triple(getDriver().DefaultHostTriple).getArch();
+ const std::string &SysRoot = getDriver().SysRoot;
+ GCCInstallationDetector GCCInstallation(getDriver());
- if (Is32Bits) {
- Suffix = Suffix32;
- Lib = Lib32;
- } else {
- Suffix = Suffix64;
- Lib = Lib64;
- }
+ // OpenSuse stores the linker with the compiler, add that to the search
+ // path.
+ ToolChain::path_list &PPaths = getProgramPaths();
+ PPaths.push_back(GCCInstallation.getParentLibPath() + "/../" +
+ GCCInstallation.getTriple() + "/bin");
- llvm::sys::Path LinkerPath(Base + "/../../../../" + GccTriple + "/bin/ld");
- if (!llvm::sys::fs::exists(LinkerPath.str(), Exists) && Exists)
- Linker = LinkerPath.str();
- else
- Linker = GetProgramPath("ld");
+ Linker = GetProgramPath("ld");
LinuxDistro Distro = DetectLinuxDistro(Arch);
@@ -1642,29 +1791,63 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
if (IsOpenSuse(Distro))
ExtraOpts.push_back("--enable-new-dtags");
- if (Distro == ArchLinux)
- Lib = "lib";
+ // The selection of paths to try here is designed to match the patterns which
+ // the GCC driver itself uses, as this is part of the GCC-compatible driver.
+ // This was determined by running GCC in a fake filesystem, creating all
+ // possible permutations of these directories, and seeing which ones it added
+ // to the link paths.
+ path_list &Paths = getFilePaths();
+ const bool Is32Bits = (getArch() == llvm::Triple::x86 ||
+ getArch() == llvm::Triple::ppc);
+
+ const std::string Suffix32 = Arch == llvm::Triple::x86_64 ? "/32" : "";
+ const std::string Suffix64 = Arch == llvm::Triple::x86_64 ? "" : "/64";
+ const std::string Suffix = Is32Bits ? Suffix32 : Suffix64;
+ const std::string Multilib = Is32Bits ? "lib32" : "lib64";
- Paths.push_back(Base + Suffix);
+ // FIXME: Because we add paths only when they exist on the system, I think we
+ // should remove the concept of 'HasMultilib'. It's more likely to break the
+ // behavior than to preserve any useful invariant on the system.
if (HasMultilib(Arch, Distro)) {
- if (IsOpenSuse(Distro) && Is32Bits)
- Paths.push_back(Base + "/../../../../" + GccTriple + "/lib/../lib");
- Paths.push_back(Base + "/../../../../" + Lib);
+ // Add the multilib suffixed paths.
+ if (GCCInstallation.isValid()) {
+ const std::string &LibPath = GCCInstallation.getParentLibPath();
+ const std::string &GccTriple = GCCInstallation.getTriple();
+ // FIXME: This OpenSuse-specific path shouldn't be needed any more, but
+ // I don't want to remove it without finding someone to test.
+ if (IsOpenSuse(Distro) && Is32Bits)
+ Paths.push_back(LibPath + "/../" + GccTriple + "/lib/../lib");
+
+ addPathIfExists(GCCInstallation.getInstallPath() + Suffix, Paths);
+ addPathIfExists(LibPath + "/../" + GccTriple + "/lib/../" + Multilib,
+ Paths);
+ addPathIfExists(LibPath + "/../" + Multilib, Paths);
+ }
+ addPathIfExists(SysRoot + "/lib/../" + Multilib, Paths);
+ addPathIfExists(SysRoot + "/usr/lib/../" + Multilib, Paths);
+
+ // Try walking via the GCC triple path in case of multiarch GCC
+ // installations with strange symlinks.
+ if (GCCInstallation.isValid())
+ addPathIfExists(SysRoot + "/usr/lib/" + GCCInstallation.getTriple() +
+ "/../../" + Multilib, Paths);
}
- // FIXME: This is in here to find crt1.o. It is provided by libc, and
- // libc (like gcc), can be installed in any directory. Once we are
- // fetching this from a config file, we should have a libc prefix.
- Paths.push_back("/lib/../" + Lib);
- Paths.push_back("/usr/lib/../" + Lib);
+ // Add the non-multilib suffixed paths (if potentially different).
+ if (GCCInstallation.isValid()) {
+ const std::string &LibPath = GCCInstallation.getParentLibPath();
+ const std::string &GccTriple = GCCInstallation.getTriple();
+ if (!Suffix.empty() || !HasMultilib(Arch, Distro))
+ addPathIfExists(GCCInstallation.getInstallPath(), Paths);
+ addPathIfExists(LibPath + "/../" + GccTriple + "/lib", Paths);
+ addPathIfExists(LibPath, Paths);
+ }
+ addPathIfExists(SysRoot + "/lib", Paths);
+ addPathIfExists(SysRoot + "/usr/lib", Paths);
- if (!Suffix.empty())
- Paths.push_back(Base);
- if (IsOpenSuse(Distro))
- Paths.push_back(Base + "/../../../../" + GccTriple + "/lib");
- Paths.push_back(Base + "/../../..");
- if (Arch == getArch() && IsUbuntu(Distro))
- Paths.push_back("/usr/lib/" + GccTriple);
+ // Add a multiarch lib directory whenever it exists and is plausible.
+ if (GCCInstallation.isValid() && Arch == getArch())
+ addPathIfExists(SysRoot + "/usr/lib/" + GCCInstallation.getTriple(), Paths);
}
bool Linux::HasNativeLLVMSupport() const {
@@ -1752,6 +1935,10 @@ Tool &Windows::SelectTool(const Compilation &C, const JobAction &JA,
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) {
@@ -1759,14 +1946,19 @@ Tool &Windows::SelectTool(const Compilation &C, const JobAction &JA,
case Action::BindArchClass:
case Action::LipoJobClass:
case Action::DsymutilJobClass:
- assert(0 && "Invalid tool kind.");
+ case Action::VerifyJobClass:
+ llvm_unreachable("Invalid tool kind.");
case Action::PreprocessJobClass:
case Action::PrecompileJobClass:
case Action::AnalyzeJobClass:
case Action::CompileJobClass:
T = new tools::Clang(*this); break;
case Action::AssembleJobClass:
- T = new tools::ClangAs(*this); break;
+ 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;
}
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index d68016b3a240..dfcb253acd88 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -66,6 +66,12 @@ private:
ARCSimulator_NoARCRuntime
} ARCRuntimeForSimulator;
+ mutable enum {
+ LibCXXSimulator_None,
+ LibCXXSimulator_NotAvailable,
+ LibCXXSimulator_Available
+ } LibCXXForSimulator;
+
private:
/// Whether we are targeting iPhoneOS target.
mutable bool TargetIsIPhoneOS;
@@ -89,7 +95,8 @@ public:
Darwin(const HostInfo &Host, const llvm::Triple& Triple);
~Darwin();
- std::string ComputeEffectiveClangTriple(const ArgList &Args) const;
+ std::string ComputeEffectiveClangTriple(const ArgList &Args,
+ types::ID InputType) const;
/// @name Darwin Specific Toolchain API
/// {
@@ -139,7 +146,7 @@ public:
/// getDarwinArchName - Get the "Darwin" arch name for a particular compiler
/// invocation. For example, Darwin treats different ARM variations as
/// distinct architectures.
- llvm::StringRef getDarwinArchName(const ArgList &Args) const;
+ StringRef getDarwinArchName(const ArgList &Args) const;
static bool isVersionLT(unsigned (&A)[3], unsigned (&B)[3]) {
for (unsigned i=0; i < 3; ++i) {
@@ -187,6 +194,7 @@ public:
virtual bool HasNativeLLVMSupport() const;
virtual void configureObjCRuntime(ObjCRuntime &runtime) const;
+ virtual bool hasBlocksRuntime() const;
virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args,
const char *BoundArch) const;
@@ -237,9 +245,12 @@ public:
return !(!isTargetIPhoneOS() && isMacosxVersionLT(10, 6));
}
virtual bool IsUnwindTablesDefault() const;
- virtual unsigned GetDefaultStackProtectorLevel() const {
- // Stack protectors default to on for 10.6 and beyond.
- return !isTargetIPhoneOS() && !isMacosxVersionLT(10, 6);
+ virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const {
+ // Stack protectors default to on for user code on 10.5,
+ // and for everything in 10.6 and beyond
+ return !isTargetIPhoneOS() &&
+ (!isMacosxVersionLT(10, 6) ||
+ (!isMacosxVersionLT(10, 5) && !KernelOrKext));
}
virtual const char *GetDefaultRelocationModel() const;
virtual const char *GetForcedPicModel() const;
@@ -257,6 +268,9 @@ public:
/// DarwinClang - The Darwin toolchain used by Clang.
class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin {
+private:
+ void AddGCCLibexecPath(unsigned darwinVersion);
+
public:
DarwinClang(const HostInfo &Host, const llvm::Triple& Triple);
@@ -288,7 +302,8 @@ public:
Darwin_Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple)
: Generic_GCC(Host, Triple) {}
- std::string ComputeEffectiveClangTriple(const ArgList &Args) const;
+ std::string ComputeEffectiveClangTriple(const ArgList &Args,
+ types::ID InputType) const;
virtual const char *GetDefaultRelocationModel() const { return "pic"; }
};
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index eb17609d6c34..4b4ff25e281f 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -45,25 +45,14 @@
using namespace clang::driver;
using namespace clang::driver::tools;
-
-/// FindTargetProgramPath - Return path of the target specific version of
-/// ProgName. If it doesn't exist, return path of ProgName itself.
-static std::string FindTargetProgramPath(const ToolChain &TheToolChain,
- const std::string TripleString,
- const char *ProgName) {
- std::string Executable(TripleString + "-" + ProgName);
- std::string Path(TheToolChain.GetProgramPath(Executable.c_str()));
- if (Path != Executable)
- return Path;
- return TheToolChain.GetProgramPath(ProgName);
-}
+using namespace clang;
/// CheckPreprocessingOptions - Perform some validation of preprocessing
/// arguments that is shared with gcc.
static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) {
if (Arg *A = Args.getLastArg(options::OPT_C, options::OPT_CC))
if (!Args.hasArg(options::OPT_E) && !D.CCCIsCPP)
- D.Diag(clang::diag::err_drv_argument_only_allowed_with)
+ D.Diag(diag::err_drv_argument_only_allowed_with)
<< A->getAsString(Args) << "-E";
}
@@ -74,14 +63,14 @@ static void CheckCodeGenerationOptions(const Driver &D, const ArgList &Args) {
if (Args.hasArg(options::OPT_static))
if (const Arg *A = Args.getLastArg(options::OPT_dynamic,
options::OPT_mdynamic_no_pic))
- D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
<< A->getAsString(Args) << "-static";
}
// Quote target names for inclusion in GNU Make dependency files.
// Only the characters '$', '#', ' ', '\t' are quoted.
-static void QuoteTarget(llvm::StringRef Target,
- llvm::SmallVectorImpl<char> &Res) {
+static void QuoteTarget(StringRef Target,
+ SmallVectorImpl<char> &Res) {
for (unsigned i = 0, e = Target.size(); i != e; ++i) {
switch (Target[i]) {
case ' ':
@@ -126,7 +115,7 @@ static void AddLinkerInputs(const ToolChain &TC,
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)
+ D.Diag(diag::err_drv_no_linker_llvm_support)
<< TC.getTripleString();
}
@@ -168,20 +157,52 @@ static void addProfileRT(const ToolChain &TC, const ArgList &Args,
// the link line. We cannot do the same thing because unlike gcov there is a
// libprofile_rt.so. We used to use the -l:libprofile_rt.a syntax, but that is
// not supported by old linkers.
- llvm::Twine ProfileRT =
- llvm::Twine(TC.getDriver().Dir) + "/../lib/" + "libprofile_rt.a";
+ Twine ProfileRT =
+ Twine(TC.getDriver().Dir) + "/../lib/" + "libprofile_rt.a";
- if (Triple.getOS() == llvm::Triple::Darwin) {
+ if (Triple.isOSDarwin()) {
// On Darwin, if the static library doesn't exist try the dylib.
bool Exists;
if (llvm::sys::fs::exists(ProfileRT.str(), Exists) || !Exists)
ProfileRT =
- llvm::Twine(TC.getDriver().Dir) + "/../lib/" + "libprofile_rt.dylib";
+ Twine(TC.getDriver().Dir) + "/../lib/" + "libprofile_rt.dylib";
}
CmdArgs.push_back(Args.MakeArgString(ProfileRT));
}
+static void AddIncludeDirectoryList(const ArgList &Args,
+ ArgStringList &CmdArgs,
+ const char *ArgName,
+ const char *DirList) {
+ if (!DirList)
+ return; // Nothing to do.
+
+ StringRef Dirs(DirList);
+ if (Dirs.empty()) // Empty string should not add '.'.
+ return;
+
+ StringRef::size_type Delim;
+ while ((Delim = Dirs.find(llvm::sys::PathSeparator)) != StringRef::npos) {
+ if (Delim == 0) { // Leading colon.
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(".");
+ } else {
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(Args.MakeArgString(Dirs.substr(0, Delim)));
+ }
+ Dirs = Dirs.substr(Delim + 1);
+ }
+
+ if (Dirs.empty()) { // Trailing colon.
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(".");
+ } else { // Add the last path.
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(Args.MakeArgString(Dirs));
+ }
+}
+
void Clang::AddPreprocessingOptions(const Driver &D,
const ArgList &Args,
ArgStringList &CmdArgs,
@@ -245,7 +266,7 @@ void Clang::AddPreprocessingOptions(const Driver &D,
if (Args.hasArg(options::OPT_MG)) {
if (!A || A->getOption().matches(options::OPT_MD) ||
A->getOption().matches(options::OPT_MMD))
- D.Diag(clang::diag::err_drv_mg_requires_m_or_mm);
+ D.Diag(diag::err_drv_mg_requires_m_or_mm);
CmdArgs.push_back("-MG");
}
@@ -328,7 +349,7 @@ void Clang::AddPreprocessingOptions(const Driver &D,
continue;
} else {
// Ignore the PCH if not first on command line and emit warning.
- D.Diag(clang::diag::warn_drv_pch_not_first_include)
+ D.Diag(diag::warn_drv_pch_not_first_include)
<< P.str() << A->getAsString(Args);
}
}
@@ -340,14 +361,15 @@ void Clang::AddPreprocessingOptions(const Driver &D,
}
Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U);
- Args.AddAllArgs(CmdArgs, options::OPT_I_Group, options::OPT_F);
+ Args.AddAllArgs(CmdArgs, options::OPT_I_Group, options::OPT_F,
+ options::OPT_index_header_map);
// Add C++ include arguments, if needed.
types::ID InputType = Inputs[0].getType();
if (types::isCXX(InputType)) {
bool ObjCXXAutoRefCount
= types::isObjC(InputType) && isObjCAutoRefCount(Args);
- getToolChain().AddClangCXXStdlibIncludeArgs(Args, CmdArgs,
+ getToolChain().AddClangCXXStdlibIncludeArgs(Args, CmdArgs,
ObjCXXAutoRefCount);
Args.AddAllArgs(CmdArgs, options::OPT_stdlib_EQ);
}
@@ -363,7 +385,7 @@ void Clang::AddPreprocessingOptions(const Driver &D,
// -I- is a deprecated GCC feature, reject it.
if (Arg *A = Args.getLastArg(options::OPT_I_))
- D.Diag(clang::diag::err_drv_I_dash_not_supported) << A->getAsString(Args);
+ D.Diag(diag::err_drv_I_dash_not_supported) << A->getAsString(Args);
// If we have a --sysroot, and don't have an explicit -isysroot flag, add an
// -isysroot to the CC1 invocation.
@@ -373,6 +395,39 @@ void Clang::AddPreprocessingOptions(const Driver &D,
CmdArgs.push_back(A->getValue(Args));
}
}
+
+ // 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 {
+ llvm::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));
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_fauto_module_import);
+
+ // Parse additional include paths from environment variables.
+ // CPATH - included following the user specified includes (but prior to
+ // builtin and standard includes).
+ AddIncludeDirectoryList(Args, CmdArgs, "-I", ::getenv("CPATH"));
+ // C_INCLUDE_PATH - system includes enabled when compiling C.
+ AddIncludeDirectoryList(Args, CmdArgs, "-c-isystem",
+ ::getenv("C_INCLUDE_PATH"));
+ // CPLUS_INCLUDE_PATH - system includes enabled when compiling C++.
+ AddIncludeDirectoryList(Args, CmdArgs, "-cxx-isystem",
+ ::getenv("CPLUS_INCLUDE_PATH"));
+ // OBJC_INCLUDE_PATH - system includes enabled when compiling ObjC.
+ AddIncludeDirectoryList(Args, CmdArgs, "-objc-isystem",
+ ::getenv("OBJC_INCLUDE_PATH"));
+ // OBJCPLUS_INCLUDE_PATH - system includes enabled when compiling ObjC++.
+ AddIncludeDirectoryList(Args, CmdArgs, "-objcxx-isystem",
+ ::getenv("OBJCPLUS_INCLUDE_PATH"));
}
/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting.
@@ -386,7 +441,7 @@ static const char *getARMTargetCPU(const ArgList &Args,
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
return A->getValue(Args);
- llvm::StringRef MArch;
+ StringRef MArch;
if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
// Otherwise, if we have -march= choose the base CPU for that arch.
MArch = A->getValue(Args);
@@ -395,45 +450,27 @@ static const char *getARMTargetCPU(const ArgList &Args,
MArch = Triple.getArchName();
}
- if (MArch == "armv2" || MArch == "armv2a")
- return "arm2";
- if (MArch == "armv3")
- return "arm6";
- if (MArch == "armv3m")
- return "arm7m";
- if (MArch == "armv4" || MArch == "armv4t")
- return "arm7tdmi";
- if (MArch == "armv5" || MArch == "armv5t")
- return "arm10tdmi";
- if (MArch == "armv5e" || MArch == "armv5te")
- return "arm1026ejs";
- if (MArch == "armv5tej")
- return "arm926ej-s";
- if (MArch == "armv6" || MArch == "armv6k")
- return "arm1136jf-s";
- if (MArch == "armv6j")
- return "arm1136j-s";
- if (MArch == "armv6z" || MArch == "armv6zk")
- return "arm1176jzf-s";
- if (MArch == "armv6t2")
- return "arm1156t2-s";
- if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a")
- return "cortex-a8";
- if (MArch == "armv7r" || MArch == "armv7-r")
- return "cortex-r4";
- if (MArch == "armv7m" || MArch == "armv7-m")
- return "cortex-m3";
- if (MArch == "ep9312")
- return "ep9312";
- if (MArch == "iwmmxt")
- return "iwmmxt";
- if (MArch == "xscale")
- return "xscale";
- if (MArch == "armv6m" || MArch == "armv6-m")
- return "cortex-m0";
-
- // If all else failed, return the most base CPU LLVM supports.
- return "arm7tdmi";
+ return llvm::StringSwitch<const char *>(MArch)
+ .Cases("armv2", "armv2a","arm2")
+ .Case("armv3", "arm6")
+ .Case("armv3m", "arm7m")
+ .Cases("armv4", "armv4t", "arm7tdmi")
+ .Cases("armv5", "armv5t", "arm10tdmi")
+ .Cases("armv5e", "armv5te", "arm1026ejs")
+ .Case("armv5tej", "arm926ej-s")
+ .Cases("armv6", "armv6k", "arm1136jf-s")
+ .Case("armv6j", "arm1136j-s")
+ .Cases("armv6z", "armv6zk", "arm1176jzf-s")
+ .Case("armv6t2", "arm1156t2-s")
+ .Cases("armv7", "armv7a", "armv7-a", "cortex-a8")
+ .Cases("armv7r", "armv7-r", "cortex-r4")
+ .Cases("armv7m", "armv7-m", "cortex-m3")
+ .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");
}
/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular
@@ -441,33 +478,21 @@ static const char *getARMTargetCPU(const ArgList &Args,
//
// FIXME: This is redundant with -mcpu, why does LLVM use this.
// FIXME: tblgen this, or kill it!
-static const char *getLLVMArchSuffixForARM(llvm::StringRef CPU) {
- if (CPU == "arm7tdmi" || CPU == "arm7tdmi-s" || CPU == "arm710t" ||
- CPU == "arm720t" || CPU == "arm9" || CPU == "arm9tdmi" ||
- CPU == "arm920" || CPU == "arm920t" || CPU == "arm922t" ||
- CPU == "arm940t" || CPU == "ep9312")
- return "v4t";
-
- if (CPU == "arm10tdmi" || CPU == "arm1020t")
- return "v5";
-
- if (CPU == "arm9e" || CPU == "arm926ej-s" || CPU == "arm946e-s" ||
- CPU == "arm966e-s" || CPU == "arm968e-s" || CPU == "arm10e" ||
- CPU == "arm1020e" || CPU == "arm1022e" || CPU == "xscale" ||
- CPU == "iwmmxt")
- return "v5e";
-
- if (CPU == "arm1136j-s" || CPU == "arm1136jf-s" || CPU == "arm1176jz-s" ||
- CPU == "arm1176jzf-s" || CPU == "mpcorenovfp" || CPU == "mpcore")
- return "v6";
-
- if (CPU == "arm1156t2-s" || CPU == "arm1156t2f-s")
- return "v6t2";
-
- if (CPU == "cortex-a8" || CPU == "cortex-a9")
- return "v7";
-
- return "";
+static const char *getLLVMArchSuffixForARM(StringRef CPU) {
+ return llvm::StringSwitch<const char *>(CPU)
+ .Cases("arm7tdmi", "arm7tdmi-s", "arm710t", "v4t")
+ .Cases("arm720t", "arm9", "arm9tdmi", "v4t")
+ .Cases("arm920", "arm920t", "arm922t", "v4t")
+ .Cases("arm940t", "ep9312","v4t")
+ .Cases("arm10tdmi", "arm1020t", "v5")
+ .Cases("arm9e", "arm926ej-s", "arm946e-s", "v5e")
+ .Cases("arm966e-s", "arm968e-s", "arm10e", "v5e")
+ .Cases("arm1020e", "arm1022e", "xscale", "iwmmxt", "v5e")
+ .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6")
+ .Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6")
+ .Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
+ .Cases("cortex-a8", "cortex-a9", "v7")
+ .Default("");
}
// FIXME: Move to target hook.
@@ -479,7 +504,7 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) {
case llvm::Triple::arm:
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
- if (Triple.getOS() == llvm::Triple::Darwin)
+ if (Triple.isOSDarwin())
return true;
return false;
@@ -494,12 +519,6 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
const Driver &D = getToolChain().getDriver();
llvm::Triple Triple = getToolChain().getTriple();
- // Disable movt generation, if requested.
-#ifdef DISABLE_ARM_DARWIN_USE_MOVT
- CmdArgs.push_back("-backend-option");
- CmdArgs.push_back("-arm-darwin-use-movt=0");
-#endif
-
// Select the ABI to use.
//
// FIXME: Support -meabi.
@@ -528,7 +547,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
// Select the float ABI as determined by -msoft-float, -mhard-float, and
// -mfloat-abi=.
- llvm::StringRef FloatABI;
+ StringRef FloatABI;
if (Arg *A = Args.getLastArg(options::OPT_msoft_float,
options::OPT_mhard_float,
options::OPT_mfloat_abi_EQ)) {
@@ -539,7 +558,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
else {
FloatABI = A->getValue(Args);
if (FloatABI != "soft" && FloatABI != "softfp" && FloatABI != "hard") {
- D.Diag(clang::diag::err_drv_invalid_mfloat_abi)
+ D.Diag(diag::err_drv_invalid_mfloat_abi)
<< A->getAsString(Args);
FloatABI = "soft";
}
@@ -550,11 +569,13 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
if (FloatABI.empty()) {
const llvm::Triple &Triple = getToolChain().getTriple();
switch (Triple.getOS()) {
- case llvm::Triple::Darwin: {
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ case llvm::Triple::IOS: {
// Darwin defaults to "softfp" for v6 and v7.
//
// FIXME: Factor out an ARM class so we can cache the arch somewhere.
- llvm::StringRef ArchName =
+ StringRef ArchName =
getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple));
if (ArchName.startswith("v6") || ArchName.startswith("v7"))
FloatABI = "softfp";
@@ -583,7 +604,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
default:
// Assume "soft", but warn the user we are guessing.
FloatABI = "soft";
- D.Diag(clang::diag::warn_drv_assuming_mfloat_abi_is) << "soft";
+ D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft";
break;
}
}
@@ -630,7 +651,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
// FIXME: Centralize feature selection, defaulting shouldn't be also in the
// frontend target.
if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {
- llvm::StringRef FPU = A->getValue(Args);
+ StringRef FPU = A->getValue(Args);
// Set the target features based on the FPU.
if (FPU == "fpa" || FPU == "fpe2" || FPU == "fpe3" || FPU == "maverick") {
@@ -651,7 +672,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+neon");
} else
- D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+ D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
}
// Setting -msoft-float effectively disables NEON because of the GCC
@@ -670,42 +691,84 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
CmdArgs.push_back("-arm-strict-align");
// The kext linker doesn't know how to deal with movw/movt.
-#ifndef DISABLE_ARM_DARWIN_USE_MOVT
CmdArgs.push_back("-backend-option");
CmdArgs.push_back("-arm-darwin-use-movt=0");
-#endif
+ }
+
+ // Setting -mno-global-merge disables the codegen global merge pass. Setting
+ // -mglobal-merge has no effect as the pass is enabled by default.
+ if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge,
+ options::OPT_mno_global_merge)) {
+ if (A->getOption().matches(options::OPT_mno_global_merge))
+ CmdArgs.push_back("-mno-global-merge");
}
}
+// Get default architecture.
+static const char* getMipsArchFromCPU(StringRef CPUName) {
+ if (CPUName == "mips32r1" || CPUName == "4ke")
+ return "mips";
+
+ assert((CPUName == "mips64r1" || CPUName == "mips64r2") &&
+ "Unexpected cpu name.");
+
+ return "mips64";
+}
+
+// Get default target cpu.
+static const char* getMipsCPUFromArch(StringRef ArchName, const Driver &D) {
+ if (ArchName == "mips" || ArchName == "mipsel")
+ return "mips32r1";
+ else if (ArchName == "mips64" || ArchName == "mips64el")
+ return "mips64r1";
+ else
+ D.Diag(diag::err_drv_invalid_arch_name) << ArchName;
+
+ return 0;
+}
+
+// Get default ABI.
+static const char* getMipsABIFromArch(StringRef ArchName) {
+ if (ArchName == "mips" || ArchName == "mipsel")
+ return "o32";
+
+ assert((ArchName == "mips64" || ArchName == "mips64el") &&
+ "Unexpected arch name.");
+ return "n64";
+}
+
void Clang::AddMIPSTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
const Driver &D = getToolChain().getDriver();
+ StringRef ArchName;
+ const char *CPUName;
+
+ // Set target cpu and architecture.
+ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
+ CPUName = A->getValue(Args);
+ ArchName = getMipsArchFromCPU(CPUName);
+ }
+ else {
+ ArchName = Args.MakeArgString(getToolChain().getArchName());
+ CPUName = getMipsCPUFromArch(ArchName, D);
+ }
+
+ CmdArgs.push_back("-target-cpu");
+ CmdArgs.push_back(CPUName);
+
// Select the ABI to use.
const char *ABIName = 0;
- if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
+ if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
ABIName = A->getValue(Args);
- } else {
- ABIName = "o32";
- }
+ else
+ ABIName = getMipsABIFromArch(ArchName);
CmdArgs.push_back("-target-abi");
CmdArgs.push_back(ABIName);
- if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- llvm::StringRef MArch = A->getValue(Args);
- CmdArgs.push_back("-target-cpu");
-
- if ((MArch == "r2000") || (MArch == "r3000"))
- CmdArgs.push_back("mips1");
- else if (MArch == "r6000")
- CmdArgs.push_back("mips2");
- else
- CmdArgs.push_back(Args.MakeArgString(MArch));
- }
-
// Select the float ABI as determined by -msoft-float, -mhard-float, and
- llvm::StringRef FloatABI;
+ StringRef FloatABI;
if (Arg *A = Args.getLastArg(options::OPT_msoft_float,
options::OPT_mhard_float)) {
if (A->getOption().matches(options::OPT_msoft_float))
@@ -718,7 +781,7 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
if (FloatABI.empty()) {
// Assume "soft", but warn the user we are guessing.
FloatABI = "soft";
- D.Diag(clang::diag::warn_drv_assuming_mfloat_abi_is) << "soft";
+ D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft";
}
if (FloatABI == "soft") {
@@ -737,13 +800,13 @@ void Clang::AddSparcTargetArgs(const ArgList &Args,
const Driver &D = getToolChain().getDriver();
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- llvm::StringRef MArch = A->getValue(Args);
+ StringRef MArch = A->getValue(Args);
CmdArgs.push_back("-target-cpu");
CmdArgs.push_back(MArch.str().c_str());
}
// Select the float ABI as determined by -msoft-float, -mhard-float, and
- llvm::StringRef FloatABI;
+ StringRef FloatABI;
if (Arg *A = Args.getLastArg(options::OPT_msoft_float,
options::OPT_mhard_float)) {
if (A->getOption().matches(options::OPT_msoft_float))
@@ -758,7 +821,7 @@ void Clang::AddSparcTargetArgs(const ArgList &Args,
default:
// Assume "soft", but warn the user we are guessing.
FloatABI = "soft";
- D.Diag(clang::diag::warn_drv_assuming_mfloat_abi_is) << "soft";
+ D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft";
break;
}
}
@@ -792,7 +855,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
const char *CPUName = 0;
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- if (llvm::StringRef(A->getValue(Args)) == "native") {
+ if (StringRef(A->getValue(Args)) == "native") {
// FIXME: Reject attempts to use -march=native unless the target matches
// the host.
//
@@ -808,7 +871,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
// Select the default CPU if none was given (or detection failed).
if (!CPUName) {
// FIXME: Need target hooks.
- if (getToolChain().getOS().startswith("darwin")) {
+ if (getToolChain().getTriple().isOSDarwin()) {
if (getToolChain().getArch() == llvm::Triple::x86_64)
CPUName = "core2";
else if (getToolChain().getArch() == llvm::Triple::x86)
@@ -856,7 +919,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
std::vector<const char*> Features;
for (arg_iterator it = Args.filtered_begin(options::OPT_m_x86_Features_Group),
ie = Args.filtered_end(); it != ie; ++it) {
- llvm::StringRef Name = (*it)->getOption().getName();
+ StringRef Name = (*it)->getOption().getName();
(*it)->claim();
// Skip over "-m".
@@ -881,7 +944,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
}
}
-static bool
+static bool
shouldUseExceptionTablesForObjCExceptions(unsigned objcABIVersion,
const llvm::Triple &Triple) {
// We use the zero-cost exception tables for Objective-C if the non-fragile
@@ -891,12 +954,12 @@ shouldUseExceptionTablesForObjCExceptions(unsigned objcABIVersion,
if (objcABIVersion >= 2)
return true;
- if (Triple.getOS() != llvm::Triple::Darwin)
+ if (!Triple.isOSDarwin())
return false;
return (!Triple.isMacOSXVersionLT(10,5) &&
(Triple.getArch() == llvm::Triple::x86_64 ||
- Triple.getArch() == llvm::Triple::arm));
+ Triple.getArch() == llvm::Triple::arm));
}
/// addExceptionArgs - Adds exception related arguments to the driver command
@@ -922,7 +985,7 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType,
options::OPT_fno_exceptions)) {
if (A->getOption().matches(options::OPT_fexceptions))
ExceptionsEnabled = true;
- else
+ else
ExceptionsEnabled = false;
DidHaveExplicitExceptionFlag = true;
@@ -938,20 +1001,20 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType,
// Obj-C exceptions are enabled by default, regardless of -fexceptions. This
// is not necessarily sensible, but follows GCC.
if (types::isObjC(InputType) &&
- Args.hasFlag(options::OPT_fobjc_exceptions,
+ Args.hasFlag(options::OPT_fobjc_exceptions,
options::OPT_fno_objc_exceptions,
true)) {
CmdArgs.push_back("-fobjc-exceptions");
- ShouldUseExceptionTables |=
+ ShouldUseExceptionTables |=
shouldUseExceptionTablesForObjCExceptions(objcABIVersion, Triple);
}
if (types::isCXX(InputType)) {
bool CXXExceptionsEnabled = ExceptionsEnabled;
- if (Arg *A = Args.getLastArg(options::OPT_fcxx_exceptions,
- options::OPT_fno_cxx_exceptions,
+ if (Arg *A = Args.getLastArg(options::OPT_fcxx_exceptions,
+ options::OPT_fno_cxx_exceptions,
options::OPT_fexceptions,
options::OPT_fno_exceptions)) {
if (A->getOption().matches(options::OPT_fcxx_exceptions))
@@ -973,7 +1036,7 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType,
static bool ShouldDisableCFI(const ArgList &Args,
const ToolChain &TC) {
- if (TC.getTriple().getOS() == llvm::Triple::Darwin) {
+ 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.
@@ -1079,7 +1142,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
A->claim();
for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) {
- llvm::StringRef Value = A->getValue(Args, i);
+ StringRef Value = A->getValue(Args, i);
if (Value == "-force_cpusubtype_ALL") {
// Do nothing, this is the default and we don't support anything else.
@@ -1091,7 +1154,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
} else if (Value == "--noexecstack") {
CmdArgs.push_back("-mnoexecstack");
} else {
- D.Diag(clang::diag::err_drv_unsupported_option_argument)
+ D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Value;
}
}
@@ -1217,7 +1280,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
else
Model = getToolChain().GetDefaultRelocationModel();
}
- if (llvm::StringRef(Model) != "pic") {
+ if (StringRef(Model) != "pic") {
CmdArgs.push_back("-mrelocation-model");
CmdArgs.push_back(Model);
}
@@ -1275,13 +1338,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Enable -mconstructor-aliases except on darwin, where we have to
// work around a linker bug; see <rdar://problem/7651567>.
- if (getToolChain().getTriple().getOS() != llvm::Triple::Darwin)
+ if (!getToolChain().getTriple().isOSDarwin())
CmdArgs.push_back("-mconstructor-aliases");
// Darwin's kernel doesn't support guard variables; just die if we
// try to use them.
- if (KernelOrKext &&
- getToolChain().getTriple().getOS() == llvm::Triple::Darwin)
+ if (KernelOrKext && getToolChain().getTriple().isOSDarwin())
CmdArgs.push_back("-fforbid-guard-variables");
if (Args.hasArg(options::OPT_mms_bitfields)) {
@@ -1325,6 +1387,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
case llvm::Triple::mips:
case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
AddMIPSTargetArgs(Args, CmdArgs);
break;
@@ -1347,7 +1411,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -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().getOS() != llvm::Triple::Darwin))
+ !getToolChain().getTriple().isOSDarwin()))
CmdArgs.push_back("-momit-leaf-frame-pointer");
// -fno-math-errno is default.
@@ -1362,21 +1426,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_fallow_unsupported)) {
Arg *Unsupported;
if ((Unsupported = Args.getLastArg(options::OPT_iframework)))
- D.Diag(clang::diag::err_drv_clang_unsupported)
+ D.Diag(diag::err_drv_clang_unsupported)
<< Unsupported->getOption().getName();
if (types::isCXX(InputType) &&
- getToolChain().getTriple().getOS() == llvm::Triple::Darwin &&
+ getToolChain().getTriple().isOSDarwin() &&
getToolChain().getTriple().getArch() == llvm::Triple::x86) {
- if ((Unsupported = Args.getLastArg(options::OPT_fapple_kext)))
- D.Diag(clang::diag::err_drv_clang_unsupported_opt_cxx_darwin_i386)
+ if ((Unsupported = Args.getLastArg(options::OPT_fapple_kext)) ||
+ (Unsupported = Args.getLastArg(options::OPT_mkernel)))
+ D.Diag(diag::err_drv_clang_unsupported_opt_cxx_darwin_i386)
<< Unsupported->getOption().getName();
}
}
Args.AddAllArgs(CmdArgs, options::OPT_v);
Args.AddLastArg(CmdArgs, options::OPT_H);
- if (D.CCPrintHeaders) {
+ if (D.CCPrintHeaders && !D.CCGenDiagnostics) {
CmdArgs.push_back("-header-include-file");
CmdArgs.push_back(D.CCPrintHeadersFilename ?
D.CCPrintHeadersFilename : "-");
@@ -1384,7 +1449,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_P);
Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout);
- if (D.CCLogDiagnostics) {
+ if (D.CCLogDiagnostics && !D.CCGenDiagnostics) {
CmdArgs.push_back("-diagnostic-log-file");
CmdArgs.push_back(D.CCLogDiagnosticsFilename ?
D.CCLogDiagnosticsFilename : "-");
@@ -1417,9 +1482,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- Args.AddLastArg(CmdArgs, options::OPT_nostdinc);
- Args.AddLastArg(CmdArgs, options::OPT_nostdincxx);
- Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc);
+ // Pass options for controlling the default header search paths.
+ if (Args.hasArg(options::OPT_nostdinc)) {
+ CmdArgs.push_back("-nostdsysteminc");
+ CmdArgs.push_back("-nobuiltininc");
+ } else {
+ if (Args.hasArg(options::OPT_nostdlibinc))
+ CmdArgs.push_back("-nostdsysteminc");
+ Args.AddLastArg(CmdArgs, options::OPT_nostdincxx);
+ Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc);
+ }
// Pass the path to compiler resource files.
CmdArgs.push_back("-resource-dir");
@@ -1444,11 +1516,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-arcmt-migrate");
CmdArgs.push_back("-arcmt-migrate-directory");
CmdArgs.push_back(A->getValue(Args));
+
+ Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_report_output);
+ Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_emit_arc_errors);
break;
}
}
}
-
+
// Add preprocessing options like -I, -D, etc. if we are using the
// preprocessor.
//
@@ -1456,6 +1531,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (types::getPreprocessedType(InputType) != types::TY_INVALID)
AddPreprocessingOptions(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".
+ // When building with ccache, it will pass -D options to clang even on
+ // preprocessed inputs and configure concludes that -fPIC is not supported.
+ Args.ClaimAllArgs(options::OPT_D);
+
// Manually translate -O to -O2 and -O4 to -O3; let clang reject
// others.
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
@@ -1584,7 +1665,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// If -fmessage-length=N was not specified, determine whether this is a
// terminal and, if so, implicitly define -fmessage-length appropriately.
unsigned N = llvm::sys::Process::StandardErrColumns();
- CmdArgs.push_back(Args.MakeArgString(llvm::Twine(N)));
+ CmdArgs.push_back(Args.MakeArgString(Twine(N)));
}
if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ)) {
@@ -1629,7 +1710,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Forward -ftrap_function= options to the backend.
if (Arg *A = Args.getLastArg(options::OPT_ftrap_function_EQ)) {
- llvm::StringRef FuncName = A->getValue(Args);
+ StringRef FuncName = A->getValue(Args);
CmdArgs.push_back("-backend-option");
CmdArgs.push_back(Args.MakeArgString("-trap-func=" + FuncName));
}
@@ -1659,11 +1740,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
StackProtectorLevel = 1;
else if (A->getOption().matches(options::OPT_fstack_protector_all))
StackProtectorLevel = 2;
- } else
- StackProtectorLevel = getToolChain().GetDefaultStackProtectorLevel();
+ } else {
+ StackProtectorLevel =
+ getToolChain().GetDefaultStackProtectorLevel(KernelOrKext);
+ }
if (StackProtectorLevel) {
CmdArgs.push_back("-stack-protector");
- CmdArgs.push_back(Args.MakeArgString(llvm::Twine(StackProtectorLevel)));
+ CmdArgs.push_back(Args.MakeArgString(Twine(StackProtectorLevel)));
}
// Translate -mstackrealign
@@ -1671,7 +1754,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-backend-option");
CmdArgs.push_back("-force-align-stack");
}
-
+
// Forward -f options with positive and negative forms; we translate
// these by hand.
@@ -1696,6 +1779,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.hasArg(options::OPT_fobjc_nonfragile_abi) &&
!Args.hasArg(options::OPT_fno_blocks))) {
CmdArgs.push_back("-fblocks");
+
+ if (!Args.hasArg(options::OPT_fgnu_runtime) &&
+ !getToolChain().hasBlocksRuntime())
+ CmdArgs.push_back("-fblocks-runtime-optional");
}
// -faccess-control is default.
@@ -1743,11 +1830,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().getTriple().getOS() == llvm::Triple::Win32))
CmdArgs.push_back("-fms-extensions");
+ // -fms-compatibility=0 is default.
+ if (Args.hasFlag(options::OPT_fms_compatibility, options::OPT_fno_ms_compatibility,
+ getToolChain().getTriple().getOS() == llvm::Triple::Win32))
+ CmdArgs.push_back("-fms-compatibility");
+
// -fmsc-version=1300 is default.
if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
getToolChain().getTriple().getOS() == llvm::Triple::Win32) ||
Args.hasArg(options::OPT_fmsc_version)) {
- llvm::StringRef msc_ver = Args.getLastArgValue(options::OPT_fmsc_version);
+ StringRef msc_ver = Args.getLastArgValue(options::OPT_fmsc_version);
if (msc_ver.empty())
CmdArgs.push_back("-fmsc-version=1300");
else
@@ -1760,10 +1852,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_borland_extensions, false))
CmdArgs.push_back("-fborland-extensions");
- // -fno-delayed-template-parsing is default.
+ // -fno-delayed-template-parsing is default, except for Windows where MSVC STL
+ // needs it.
if (Args.hasFlag(options::OPT_fdelayed_template_parsing,
options::OPT_fno_delayed_template_parsing,
- false))
+ getToolChain().getTriple().getOS() == llvm::Triple::Win32))
CmdArgs.push_back("-fdelayed-template-parsing");
// -fgnu-keywords default varies depending on language; only pass if
@@ -1780,96 +1873,90 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fobjc-nonfragile-abi=0 is default.
ObjCRuntime objCRuntime;
unsigned objcABIVersion = 0;
- if (types::isObjC(InputType)) {
- bool NeXTRuntimeIsDefault
- = (IsRewriter || getToolChain().getTriple().isOSDarwin());
- if (Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime,
- NeXTRuntimeIsDefault)) {
- objCRuntime.setKind(ObjCRuntime::NeXT);
- } else {
- CmdArgs.push_back("-fgnu-runtime");
- objCRuntime.setKind(ObjCRuntime::GNU);
- }
- getToolChain().configureObjCRuntime(objCRuntime);
- if (objCRuntime.HasARC)
- CmdArgs.push_back("-fobjc-runtime-has-arc");
- if (objCRuntime.HasWeak)
- CmdArgs.push_back("-fobjc-runtime-has-weak");
- if (objCRuntime.HasTerminate)
- CmdArgs.push_back("-fobjc-runtime-has-terminate");
-
- // Compute the Objective-C ABI "version" to use. Version numbers are
- // slightly confusing for historical reasons:
- // 1 - Traditional "fragile" ABI
- // 2 - Non-fragile ABI, version 1
- // 3 - Non-fragile ABI, version 2
- objcABIVersion = 1;
- // If -fobjc-abi-version= is present, use that to set the version.
- if (Arg *A = Args.getLastArg(options::OPT_fobjc_abi_version_EQ)) {
- if (llvm::StringRef(A->getValue(Args)) == "1")
- objcABIVersion = 1;
- else if (llvm::StringRef(A->getValue(Args)) == "2")
- objcABIVersion = 2;
- else if (llvm::StringRef(A->getValue(Args)) == "3")
- objcABIVersion = 3;
- else
- D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
- } else {
- // Otherwise, determine if we are using the non-fragile ABI.
- if (Args.hasFlag(options::OPT_fobjc_nonfragile_abi,
- options::OPT_fno_objc_nonfragile_abi,
- getToolChain().IsObjCNonFragileABIDefault())) {
- // Determine the non-fragile ABI version to use.
+ bool NeXTRuntimeIsDefault
+ = (IsRewriter || getToolChain().getTriple().isOSDarwin());
+ if (Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime,
+ NeXTRuntimeIsDefault)) {
+ objCRuntime.setKind(ObjCRuntime::NeXT);
+ } else {
+ CmdArgs.push_back("-fgnu-runtime");
+ objCRuntime.setKind(ObjCRuntime::GNU);
+ }
+ getToolChain().configureObjCRuntime(objCRuntime);
+ if (objCRuntime.HasARC)
+ CmdArgs.push_back("-fobjc-runtime-has-arc");
+ if (objCRuntime.HasWeak)
+ CmdArgs.push_back("-fobjc-runtime-has-weak");
+ if (objCRuntime.HasTerminate)
+ CmdArgs.push_back("-fobjc-runtime-has-terminate");
+
+ // Compute the Objective-C ABI "version" to use. Version numbers are
+ // slightly confusing for historical reasons:
+ // 1 - Traditional "fragile" ABI
+ // 2 - Non-fragile ABI, version 1
+ // 3 - Non-fragile ABI, version 2
+ objcABIVersion = 1;
+ // If -fobjc-abi-version= is present, use that to set the version.
+ if (Arg *A = Args.getLastArg(options::OPT_fobjc_abi_version_EQ)) {
+ if (StringRef(A->getValue(Args)) == "1")
+ objcABIVersion = 1;
+ else if (StringRef(A->getValue(Args)) == "2")
+ objcABIVersion = 2;
+ else if (StringRef(A->getValue(Args)) == "3")
+ objcABIVersion = 3;
+ else
+ D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
+ } else {
+ // Otherwise, determine if we are using the non-fragile ABI.
+ bool NonFragileABIIsDefault
+ = (!IsRewriter && getToolChain().IsObjCNonFragileABIDefault());
+ if (Args.hasFlag(options::OPT_fobjc_nonfragile_abi,
+ options::OPT_fno_objc_nonfragile_abi,
+ NonFragileABIIsDefault)) {
+ // Determine the non-fragile ABI version to use.
#ifdef DISABLE_DEFAULT_NONFRAGILEABI_TWO
- unsigned NonFragileABIVersion = 1;
+ unsigned NonFragileABIVersion = 1;
#else
- unsigned NonFragileABIVersion = 2;
+ unsigned NonFragileABIVersion = 2;
#endif
- if (Arg *A = Args.getLastArg(
- options::OPT_fobjc_nonfragile_abi_version_EQ)) {
- if (llvm::StringRef(A->getValue(Args)) == "1")
- NonFragileABIVersion = 1;
- else if (llvm::StringRef(A->getValue(Args)) == "2")
- NonFragileABIVersion = 2;
- else
- D.Diag(clang::diag::err_drv_clang_unsupported)
- << A->getAsString(Args);
- }
-
- objcABIVersion = 1 + NonFragileABIVersion;
- } else {
- objcABIVersion = 1;
- }
- }
-
- if (objcABIVersion == 2 || objcABIVersion == 3) {
- CmdArgs.push_back("-fobjc-nonfragile-abi");
-
- // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and
- // legacy is the default.
- if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch,
- options::OPT_fno_objc_legacy_dispatch,
- getToolChain().IsObjCLegacyDispatchDefault())) {
- if (getToolChain().UseObjCMixedDispatch())
- CmdArgs.push_back("-fobjc-dispatch-method=mixed");
+ if (Arg *A = Args.getLastArg(
+ options::OPT_fobjc_nonfragile_abi_version_EQ)) {
+ if (StringRef(A->getValue(Args)) == "1")
+ NonFragileABIVersion = 1;
+ else if (StringRef(A->getValue(Args)) == "2")
+ NonFragileABIVersion = 2;
else
- CmdArgs.push_back("-fobjc-dispatch-method=non-legacy");
+ D.Diag(diag::err_drv_clang_unsupported)
+ << A->getAsString(Args);
}
+
+ objcABIVersion = 1 + NonFragileABIVersion;
+ } else {
+ objcABIVersion = 1;
}
+ }
- // FIXME: Don't expose -fobjc-default-synthesize-properties as a top-level
- // driver flag yet. This feature is still under active development
- // and shouldn't be exposed as a user visible feature (which may change).
- // Clang still supports this as a -cc1 option for development and testing.
-#if 0
- // -fobjc-default-synthesize-properties=0 is default.
- if (Args.hasFlag(options::OPT_fobjc_default_synthesize_properties,
- options::OPT_fno_objc_default_synthesize_properties,
- getToolChain().IsObjCDefaultSynthPropertiesDefault())) {
- CmdArgs.push_back("-fobjc-default-synthesize-properties");
+ if (objcABIVersion == 1) {
+ CmdArgs.push_back("-fobjc-fragile-abi");
+ } else {
+ // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and
+ // legacy is the default.
+ if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch,
+ options::OPT_fno_objc_legacy_dispatch,
+ getToolChain().IsObjCLegacyDispatchDefault())) {
+ if (getToolChain().UseObjCMixedDispatch())
+ CmdArgs.push_back("-fobjc-dispatch-method=mixed");
+ else
+ CmdArgs.push_back("-fobjc-dispatch-method=non-legacy");
}
-#endif
+ }
+
+ // -fobjc-default-synthesize-properties=0 is default.
+ if (Args.hasFlag(options::OPT_fobjc_default_synthesize_properties,
+ options::OPT_fno_objc_default_synthesize_properties,
+ getToolChain().IsObjCDefaultSynthPropertiesDefault())) {
+ CmdArgs.push_back("-fobjc-default-synthesize-properties");
}
// Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc.
@@ -1890,7 +1977,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// rewriter.
if (IsRewriter)
CmdArgs.push_back("-fno-objc-infer-related-result-type");
-
+
// Handle -fobjc-gc and -fobjc-gc-only. They are exclusive, and -fobjc-gc-only
// takes precedence.
const Arg *GCArg = Args.getLastArg(options::OPT_fobjc_gc_only);
@@ -1898,13 +1985,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
GCArg = Args.getLastArg(options::OPT_fobjc_gc);
if (GCArg) {
if (ARC) {
- D.Diag(clang::diag::err_drv_objc_gc_arr)
+ D.Diag(diag::err_drv_objc_gc_arr)
<< GCArg->getAsString(Args);
} else if (getToolChain().SupportsObjCGC()) {
GCArg->render(Args, CmdArgs);
} else {
// FIXME: We should move this to a hard error.
- D.Diag(clang::diag::warn_drv_objc_gc_unsupported)
+ D.Diag(diag::warn_drv_objc_gc_unsupported)
<< GCArg->getAsString(Args);
}
}
@@ -1947,11 +2034,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
false))
CmdArgs.push_back("-fpascal-strings");
+ // Honor -fpack-struct= and -fpack-struct, if given. Note that
+ // -fno-pack-struct doesn't apply to -fpack-struct=.
+ if (Arg *A = Args.getLastArg(options::OPT_fpack_struct_EQ)) {
+ CmdArgs.push_back("-fpack-struct");
+ CmdArgs.push_back(A->getValue(Args));
+ } else if (Args.hasFlag(options::OPT_fpack_struct,
+ options::OPT_fno_pack_struct, false)) {
+ CmdArgs.push_back("-fpack-struct");
+ CmdArgs.push_back("1");
+ }
+
if (Args.hasArg(options::OPT_mkernel) ||
Args.hasArg(options::OPT_fapple_kext)) {
if (!Args.hasArg(options::OPT_fcommon))
CmdArgs.push_back("-fno-common");
}
+
// -fcommon is default, only pass non-default.
else if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common))
CmdArgs.push_back("-fno-common");
@@ -1960,13 +2059,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -funsigned-bitfields.
if (!Args.hasFlag(options::OPT_fsigned_bitfields,
options::OPT_funsigned_bitfields))
- D.Diag(clang::diag::warn_drv_clang_unsupported)
+ D.Diag(diag::warn_drv_clang_unsupported)
<< Args.getLastArg(options::OPT_funsigned_bitfields)->getAsString(Args);
// -fsigned-bitfields is default, and clang doesn't support -fno-for-scope.
if (!Args.hasFlag(options::OPT_ffor_scope,
options::OPT_fno_for_scope))
- D.Diag(clang::diag::err_drv_clang_unsupported)
+ D.Diag(diag::err_drv_clang_unsupported)
<< Args.getLastArg(options::OPT_fno_for_scope)->getAsString(Args);
// -fcaret-diagnostics is default.
@@ -1978,7 +2077,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info,
options::OPT_fno_diagnostics_fixit_info))
CmdArgs.push_back("-fno-diagnostics-fixit-info");
-
+
// Enable -fdiagnostics-show-name by default.
if (Args.hasFlag(options::OPT_fdiagnostics_show_name,
options::OPT_fno_diagnostics_show_name, false))
@@ -2054,14 +2153,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_funit_at_a_time,
options::OPT_fno_unit_at_a_time)) {
if (A->getOption().matches(options::OPT_fno_unit_at_a_time))
- D.Diag(clang::diag::warn_drv_clang_unsupported) << A->getAsString(Args);
+ D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args);
}
// Default to -fno-builtin-str{cat,cpy} on Darwin for ARM.
//
// FIXME: This is disabled until clang -cc1 supports -fno-builtin-foo. PR4941.
#if 0
- if (getToolChain().getTriple().getOS() == llvm::Triple::Darwin &&
+ if (getToolChain().getTriple().isOSDarwin() &&
(getToolChain().getTriple().getArch() == llvm::Triple::arm ||
getToolChain().getTriple().getArch() == llvm::Triple::thumb)) {
if (!Args.hasArg(options::OPT_fbuiltin_strcat))
@@ -2076,8 +2175,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_traditional_cpp)) {
if (isa<PreprocessJobAction>(JA))
CmdArgs.push_back("-traditional-cpp");
- else
- D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+ else
+ D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
}
Args.AddLastArg(CmdArgs, options::OPT_dM);
@@ -2092,7 +2191,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// We translate this by hand to the -cc1 argument, since nightly test uses
// it and developers have been trained to spell it with -mllvm.
- if (llvm::StringRef((*it)->getValue(Args, 0)) == "-disable-llvm-optzns")
+ if (StringRef((*it)->getValue(Args, 0)) == "-disable-llvm-optzns")
CmdArgs.push_back("-disable-llvm-optzns");
else
(*it)->render(Args, CmdArgs);
@@ -2144,7 +2243,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_pg))
if (Args.hasArg(options::OPT_fomit_frame_pointer))
- D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
<< "-fomit-frame-pointer" << A->getAsString(Args);
// Claim some arguments which clang supports automatically.
@@ -2188,7 +2287,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
// Add the "effective" target triple.
CmdArgs.push_back("-triple");
- std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args);
+ std::string TripleStr =
+ getToolChain().ComputeEffectiveClangTriple(Args, Input.getType());
CmdArgs.push_back(Args.MakeArgString(TripleStr));
// Set the output mode, we currently only expect to be used as a real
@@ -2251,7 +2351,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
// If using a driver driver, force the arch.
const std::string &Arch = getToolChain().getArchName();
- if (getToolChain().getTriple().getOS() == llvm::Triple::Darwin) {
+ if (getToolChain().getTriple().isOSDarwin()) {
CmdArgs.push_back("-arch");
// FIXME: Remove these special cases.
@@ -2297,10 +2397,10 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
// 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)
+ D.Diag(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)
+ D.Diag(diag::err_drv_no_ast_support)
<< getToolChain().getTripleString();
if (types::canTypeBeUserSpecified(II.getType())) {
@@ -2363,7 +2463,7 @@ void gcc::Compile::RenderExtraToolArgs(const JobAction &JA,
CmdArgs.push_back("-c");
else {
if (JA.getType() != types::TY_PP_Asm)
- D.Diag(clang::diag::err_drv_invalid_gcc_output_type)
+ D.Diag(diag::err_drv_invalid_gcc_output_type)
<< getTypeName(JA.getType());
CmdArgs.push_back("-S");
@@ -2383,19 +2483,21 @@ void gcc::Link::RenderExtraToolArgs(const JobAction &JA,
const char *darwin::CC1::getCC1Name(types::ID Type) const {
switch (Type) {
default:
- assert(0 && "Unexpected type for Darwin CC1 tool.");
+ 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_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_ObjCXXHeader:
+ case types::TY_PP_ObjCXX: case types::TY_PP_ObjCXX_Alias:
+ case types::TY_PP_ObjCXXHeader:
return "cc1objplus";
}
}
@@ -2424,14 +2526,145 @@ darwin::CC1::getDependencyFileName(const ArgList &Args,
if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) {
std::string Str(OutputOpt->getValue(Args));
-
Res = Str.substr(0, Str.rfind('.'));
- } else
+ } else {
Res = darwin::CC1::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;
+
+ // Remove -faltivec
+ if (Option.equals("-faltivec")) {
+ it = CmdArgs.erase(it);
+ ie = CmdArgs.end();
+ continue;
+ }
+
+ // 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("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("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("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();
@@ -2469,7 +2702,7 @@ void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
if (Arg *A = Args.getLastArg(options::OPT_pg))
if (Args.hasArg(options::OPT_fomit_frame_pointer))
- D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
<< A->getAsString(Args) << "-fomit-frame-pointer";
AddCC1Args(Args, CmdArgs);
@@ -2741,6 +2974,8 @@ void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_d_Group);
+ RemoveCC1UnsupportedArgs(CmdArgs);
+
const char *CC1Name = getCC1Name(Inputs[0].getType());
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(CC1Name));
@@ -2760,7 +2995,7 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA,
types::ID InputType = Inputs[0].getType();
const Arg *A;
if ((A = Args.getLastArg(options::OPT_traditional)))
- D.Diag(clang::diag::err_drv_argument_only_allowed_with)
+ D.Diag(diag::err_drv_argument_only_allowed_with)
<< A->getAsString(Args) << "-E";
if (JA.getType() == types::TY_LLVM_IR ||
@@ -2770,11 +3005,11 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA,
JA.getType() == types::TY_LTO_BC)
CmdArgs.push_back("-emit-llvm-bc");
else if (Output.getType() == types::TY_AST)
- D.Diag(clang::diag::err_drv_no_ast_support)
+ 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(clang::diag::err_drv_invalid_gcc_output_type)
+ D.Diag(diag::err_drv_invalid_gcc_output_type)
<< getTypeName(JA.getType());
ArgStringList OutputArgs;
@@ -2808,7 +3043,7 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA,
// Reject AST inputs.
if (II.getType() == types::TY_AST) {
- D.Diag(clang::diag::err_drv_no_ast_support)
+ D.Diag(diag::err_drv_no_ast_support)
<< getToolChain().getTripleString();
return;
}
@@ -2830,12 +3065,23 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-o");
// NOTE: gcc uses a temp .s file for this, but there doesn't seem
// to be a good reason.
- CmdArgs.push_back("/dev/null");
+ const char *TmpPath = C.getArgs().MakeArgString(
+ D.GetTemporaryPath("cc", "s"));
+ C.addTempFile(TmpPath);
+ CmdArgs.push_back(TmpPath);
- CmdArgs.push_back("--output-pch=");
- CmdArgs.push_back(Output.getFilename());
+ // 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));
@@ -2860,7 +3106,7 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
}
// Forward -g, assuming we are dealing with an actual assembly file.
- if (SourceAction->getType() == types::TY_Asm ||
+ if (SourceAction->getType() == types::TY_Asm ||
SourceAction->getType() == types::TY_PP_Asm) {
if (Args.hasArg(options::OPT_gstabs))
CmdArgs.push_back("--gstabs");
@@ -2902,7 +3148,7 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
void darwin::DarwinTool::AddDarwinArch(const ArgList &Args,
ArgStringList &CmdArgs) const {
- llvm::StringRef ArchName = getDarwinToolChain().getDarwinArchName(Args);
+ StringRef ArchName = getDarwinToolChain().getDarwinArchName(Args);
// Derived from darwin_arch spec.
CmdArgs.push_back("-arch");
@@ -2925,7 +3171,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
if (!Driver::GetReleaseVersion(A->getValue(Args), Version[0],
Version[1], Version[2], HadExtra) ||
HadExtra)
- D.Diag(clang::diag::err_drv_invalid_version_number)
+ D.Diag(diag::err_drv_invalid_version_number)
<< A->getAsString(Args);
}
@@ -2949,7 +3195,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
ie = Args.filtered_end(); it != ie; ++it) {
const Arg *A = *it;
for (unsigned i = 0, e = A->getNumValues(); i != e; ++i)
- if (llvm::StringRef(A->getValue(Args, i)) == "-kext")
+ if (StringRef(A->getValue(Args, i)) == "-kext")
UsesLdClassic = true;
}
}
@@ -2962,7 +3208,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
// dsymutil step.
if (Version[0] >= 116 && D.IsUsingLTO(Args)) {
const char *TmpPath = C.getArgs().MakeArgString(
- D.GetTemporaryPath(types::getTypeTempSuffix(types::TY_Object)));
+ D.GetTemporaryPath("cc", types::getTypeTempSuffix(types::TY_Object)));
C.addTempFile(TmpPath);
CmdArgs.push_back("-object_path_lto");
CmdArgs.push_back(TmpPath);
@@ -2990,7 +3236,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
if ((A = Args.getLastArg(options::OPT_compatibility__version)) ||
(A = Args.getLastArg(options::OPT_current__version)) ||
(A = Args.getLastArg(options::OPT_install__name)))
- D.Diag(clang::diag::err_drv_argument_only_allowed_with)
+ D.Diag(diag::err_drv_argument_only_allowed_with)
<< A->getAsString(Args) << "-dynamiclib";
Args.AddLastArg(CmdArgs, options::OPT_force__flat__namespace);
@@ -3006,7 +3252,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
(A = Args.getLastArg(options::OPT_force__flat__namespace)) ||
(A = Args.getLastArg(options::OPT_keep__private__externs)) ||
(A = Args.getLastArg(options::OPT_private__bundle)))
- D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
<< A->getAsString(Args) << "-dynamiclib";
Args.AddAllArgsTranslated(CmdArgs, options::OPT_compatibility__version,
@@ -3053,9 +3299,9 @@ void darwin::Link::AddLinkArgs(Compilation &C,
CmdArgs.push_back("-iphoneos_version_min");
else
CmdArgs.push_back("-macosx_version_min");
- CmdArgs.push_back(Args.MakeArgString(llvm::Twine(TargetVersion[0]) + "." +
- llvm::Twine(TargetVersion[1]) + "." +
- llvm::Twine(TargetVersion[2])));
+ CmdArgs.push_back(Args.MakeArgString(Twine(TargetVersion[0]) + "." +
+ Twine(TargetVersion[1]) + "." +
+ Twine(TargetVersion[2])));
Args.AddLastArg(CmdArgs, options::OPT_nomultidefs);
Args.AddLastArg(CmdArgs, options::OPT_multi__module);
@@ -3138,6 +3384,18 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
// more information.
ArgStringList CmdArgs;
+ /// Hack(tm) to ignore linking errors when we are doing ARC migration.
+ if (Args.hasArg(options::OPT_ccc_arcmt_check,
+ options::OPT_ccc_arcmt_migrate)) {
+ for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I)
+ (*I)->claim();
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath("touch"));
+ CmdArgs.push_back(Output.getFilename());
+ C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ return;
+ }
+
// I'm not sure why this particular decomposition exists in gcc, but
// we follow suite for ease of comparison.
AddLinkArgs(C, Args, CmdArgs);
@@ -3345,6 +3603,26 @@ void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA,
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
+void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+ CmdArgs.push_back("--verify");
+
+ assert(Inputs.size() == 1 && "Unable to handle multiple inputs.");
+ const InputInfo &Input = Inputs[0];
+ assert(Input.isFilename() && "Unexpected verify input");
+
+ // Grabbing the output of the earlier dsymutil run.
+ CmdArgs.push_back(Input.getFilename());
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath("dwarfdump"));
+ C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+}
+
void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -3663,9 +3941,11 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back(Args.MakeArgString(
getToolChain().GetFilePath("gcrt1.o")));
- else
+ else {
+ const char *crt = Args.hasArg(options::OPT_pie) ? "Scrt1.o" : "crt1.o";
CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath("crt1.o")));
+ getToolChain().GetFilePath(crt)));
+ }
CmdArgs.push_back(Args.MakeArgString(
getToolChain().GetFilePath("crti.o")));
CmdArgs.push_back(Args.MakeArgString(
@@ -3682,7 +3962,7 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
const ToolChain::path_list Paths = getToolChain().getFilePaths();
for (ToolChain::path_list::const_iterator i = Paths.begin(), e = Paths.end();
i != e; ++i)
- CmdArgs.push_back(Args.MakeArgString(llvm::StringRef("-L") + *i));
+ CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + *i));
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
Args.AddAllArgs(CmdArgs, options::OPT_e);
Args.AddAllArgs(CmdArgs, options::OPT_s);
@@ -3797,9 +4077,7 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
}
- const char *Exec = Args.MakeArgString(FindTargetProgramPath(getToolChain(),
- ToolTriple.getTriple(),
- "as"));
+ const char *Exec = Args.MakeArgString((getToolChain().GetProgramPath("as")));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -3915,9 +4193,7 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
- const char *Exec = Args.MakeArgString(FindTargetProgramPath(getToolChain(),
- ToolTriple.getTriple(),
- "ld"));
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -3935,7 +4211,7 @@ void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
} else if (getToolChain().getArch() == llvm::Triple::x86_64) {
CmdArgs.push_back("--64");
} else if (getToolChain().getArch() == llvm::Triple::arm) {
- llvm::StringRef MArch = getToolChain().getArchName();
+ StringRef MArch = getToolChain().getArchName();
if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a")
CmdArgs.push_back("-mfpu=neon");
}
@@ -3999,7 +4275,7 @@ 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::arm
+ else if (ToolChain.getArch() == llvm::Triple::arm
|| ToolChain.getArch() == llvm::Triple::thumb)
CmdArgs.push_back("armelf_linux_eabi");
else if (ToolChain.getArch() == llvm::Triple::ppc)
@@ -4070,7 +4346,7 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
for (ToolChain::path_list::const_iterator i = Paths.begin(), e = Paths.end();
i != e; ++i)
- CmdArgs.push_back(Args.MakeArgString(llvm::StringRef("-L") + *i));
+ CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + *i));
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 1741d051ce9f..a4f732e1c213 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -178,6 +178,7 @@ namespace darwin {
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;
@@ -276,6 +277,21 @@ namespace darwin {
const ArgList &TCArgs,
const char *LinkingOutput) const;
};
+
+ class LLVM_LIBRARY_VISIBILITY VerifyDebug : public DarwinTool {
+ public:
+ VerifyDebug(const ToolChain &TC) : DarwinTool("darwin::VerifyDebug",
+ "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;
+ };
+
}
/// openbsd -- Directly call GNU Binutils assembler and linker
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index 4a4312b77fc9..d61ab68c90ad 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -79,10 +79,11 @@ bool types::isAcceptedByClang(ID Id) {
case TY_C: case TY_PP_C:
case TY_CL:
case TY_CUDA:
- case TY_ObjC: case TY_PP_ObjC:
+ case TY_ObjC: case TY_PP_ObjC: case TY_PP_ObjC_Alias:
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_CHeader: case TY_PP_CHeader:
+ case TY_CLHeader:
case TY_ObjCHeader: case TY_PP_ObjCHeader:
case TY_CXXHeader: case TY_PP_CXXHeader:
case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader:
@@ -110,10 +111,10 @@ bool types::isObjC(ID Id) {
default:
return false;
- case TY_ObjC: case TY_PP_ObjC:
+ case TY_ObjC: case TY_PP_ObjC: case TY_PP_ObjC_Alias:
case TY_ObjCXX: case TY_PP_ObjCXX:
case TY_ObjCHeader: case TY_PP_ObjCHeader:
- case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader:
+ case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: case TY_PP_ObjCXX_Alias:
return true;
}
}
@@ -144,6 +145,7 @@ types::ID types::lookupTypeForExtension(const char *Ext) {
.Case("F", TY_Fortran)
.Case("s", TY_PP_Asm)
.Case("S", TY_Asm)
+ .Case("o", TY_Object)
.Case("ii", TY_PP_CXX)
.Case("mi", TY_PP_ObjC)
.Case("mm", TY_ObjCXX)
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 28d312a2219b..54bb28272868 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -31,22 +31,23 @@ using namespace clang;
namespace {
class ASTPrinter : public ASTConsumer {
- llvm::raw_ostream &Out;
+ raw_ostream &Out;
bool Dump;
public:
- ASTPrinter(llvm::raw_ostream* o = NULL, bool Dump = false)
+ ASTPrinter(raw_ostream* o = NULL, bool Dump = false)
: Out(o? *o : llvm::outs()), Dump(Dump) { }
virtual void HandleTranslationUnit(ASTContext &Context) {
- PrintingPolicy Policy = Context.PrintingPolicy;
+ PrintingPolicy Policy = Context.getPrintingPolicy();
Policy.Dump = Dump;
- Context.getTranslationUnitDecl()->print(Out, Policy);
+ Context.getTranslationUnitDecl()->print(Out, Policy, /*Indentation=*/0,
+ /*PrintInstantiation=*/true);
}
};
} // end anonymous namespace
-ASTConsumer *clang::CreateASTPrinter(llvm::raw_ostream* out) {
+ASTConsumer *clang::CreateASTPrinter(raw_ostream* out) {
return new ASTPrinter(out);
}
@@ -95,7 +96,7 @@ ASTConsumer *clang::CreateASTViewer() { return new ASTViewer(); }
namespace {
class DeclContextPrinter : public ASTConsumer {
- llvm::raw_ostream& Out;
+ raw_ostream& Out;
public:
DeclContextPrinter() : Out(llvm::errs()) {}
@@ -117,34 +118,34 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
case Decl::Namespace: {
Out << "[namespace] ";
const NamespaceDecl* ND = cast<NamespaceDecl>(DC);
- Out << ND;
+ Out << *ND;
break;
}
case Decl::Enum: {
const EnumDecl* ED = cast<EnumDecl>(DC);
- if (ED->isDefinition())
+ if (ED->isCompleteDefinition())
Out << "[enum] ";
else
Out << "<enum> ";
- Out << ED;
+ Out << *ED;
break;
}
case Decl::Record: {
const RecordDecl* RD = cast<RecordDecl>(DC);
- if (RD->isDefinition())
+ if (RD->isCompleteDefinition())
Out << "[struct] ";
else
Out << "<struct> ";
- Out << RD;
+ Out << *RD;
break;
}
case Decl::CXXRecord: {
const CXXRecordDecl* RD = cast<CXXRecordDecl>(DC);
- if (RD->isDefinition())
+ if (RD->isCompleteDefinition())
Out << "[class] ";
else
Out << "<class> ";
- Out << RD << ' ' << DC;
+ Out << *RD << ' ' << DC;
break;
}
case Decl::ObjCMethod:
@@ -177,7 +178,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "[function] ";
else
Out << "<function> ";
- Out << FD;
+ Out << *FD;
// Print the parameters.
Out << "(";
bool PrintComma = false;
@@ -187,7 +188,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << ", ";
else
PrintComma = true;
- Out << *I;
+ Out << **I;
}
Out << ")";
break;
@@ -200,7 +201,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "(c++ method) ";
else
Out << "<c++ method> ";
- Out << D;
+ Out << *D;
// Print the parameters.
Out << "(";
bool PrintComma = false;
@@ -210,7 +211,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << ", ";
else
PrintComma = true;
- Out << *I;
+ Out << **I;
}
Out << ")";
@@ -230,7 +231,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "(c++ ctor) ";
else
Out << "<c++ ctor> ";
- Out << D;
+ Out << *D;
// Print the parameters.
Out << "(";
bool PrintComma = false;
@@ -240,7 +241,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << ", ";
else
PrintComma = true;
- Out << *I;
+ Out << **I;
}
Out << ")";
@@ -259,7 +260,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "(c++ dtor) ";
else
Out << "<c++ dtor> ";
- Out << D;
+ Out << *D;
// Check the semantic DC.
const DeclContext* SemaDC = D->getDeclContext();
const DeclContext* LexicalDC = D->getLexicalDeclContext();
@@ -275,7 +276,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "(c++ conversion) ";
else
Out << "<c++ conversion> ";
- Out << D;
+ Out << *D;
// Check the semantic DC.
const DeclContext* SemaDC = D->getDeclContext();
const DeclContext* LexicalDC = D->getLexicalDeclContext();
@@ -285,7 +286,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
}
default:
- assert(0 && "a decl that inherits DeclContext isn't handled");
+ llvm_unreachable("a decl that inherits DeclContext isn't handled");
}
Out << "\n";
@@ -322,53 +323,53 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
}
case Decl::IndirectField: {
IndirectFieldDecl* IFD = cast<IndirectFieldDecl>(*I);
- Out << "<IndirectField> " << IFD << '\n';
+ Out << "<IndirectField> " << *IFD << '\n';
break;
}
case Decl::Label: {
LabelDecl *LD = cast<LabelDecl>(*I);
- Out << "<Label> " << LD << '\n';
+ Out << "<Label> " << *LD << '\n';
break;
}
case Decl::Field: {
FieldDecl *FD = cast<FieldDecl>(*I);
- Out << "<field> " << FD << '\n';
+ Out << "<field> " << *FD << '\n';
break;
}
case Decl::Typedef:
case Decl::TypeAlias: {
TypedefNameDecl* TD = cast<TypedefNameDecl>(*I);
- Out << "<typedef> " << TD << '\n';
+ Out << "<typedef> " << *TD << '\n';
break;
}
case Decl::EnumConstant: {
EnumConstantDecl* ECD = cast<EnumConstantDecl>(*I);
- Out << "<enum constant> " << ECD << '\n';
+ Out << "<enum constant> " << *ECD << '\n';
break;
}
case Decl::Var: {
VarDecl* VD = cast<VarDecl>(*I);
- Out << "<var> " << VD << '\n';
+ Out << "<var> " << *VD << '\n';
break;
}
case Decl::ImplicitParam: {
ImplicitParamDecl* IPD = cast<ImplicitParamDecl>(*I);
- Out << "<implicit parameter> " << IPD << '\n';
+ Out << "<implicit parameter> " << *IPD << '\n';
break;
}
case Decl::ParmVar: {
ParmVarDecl* PVD = cast<ParmVarDecl>(*I);
- Out << "<parameter> " << PVD << '\n';
+ Out << "<parameter> " << *PVD << '\n';
break;
}
case Decl::ObjCProperty: {
ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(*I);
- Out << "<objc property> " << OPD << '\n';
+ Out << "<objc property> " << *OPD << '\n';
break;
}
case Decl::FunctionTemplate: {
FunctionTemplateDecl* FTD = cast<FunctionTemplateDecl>(*I);
- Out << "<function template> " << FTD << '\n';
+ Out << "<function template> " << *FTD << '\n';
break;
}
case Decl::FileScopeAsm: {
@@ -381,17 +382,17 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
}
case Decl::NamespaceAlias: {
NamespaceAliasDecl* NAD = cast<NamespaceAliasDecl>(*I);
- Out << "<namespace alias> " << NAD << '\n';
+ Out << "<namespace alias> " << *NAD << '\n';
break;
}
case Decl::ClassTemplate: {
ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(*I);
- Out << "<class template> " << CTD << '\n';
+ Out << "<class template> " << *CTD << '\n';
break;
}
default:
Out << "DeclKind: " << DK << '"' << *I << "\"\n";
- assert(0 && "decl unhandled");
+ llvm_unreachable("decl unhandled");
}
}
}
@@ -404,10 +405,10 @@ ASTConsumer *clang::CreateDeclContextPrinter() {
namespace {
class ASTDumpXML : public ASTConsumer {
- llvm::raw_ostream &OS;
+ raw_ostream &OS;
public:
- ASTDumpXML(llvm::raw_ostream &OS) : OS(OS) {}
+ ASTDumpXML(raw_ostream &OS) : OS(OS) {}
void HandleTranslationUnit(ASTContext &C) {
C.getTranslationUnitDecl()->dumpXML(OS);
@@ -415,6 +416,6 @@ public:
};
}
-ASTConsumer *clang::CreateASTDumperXML(llvm::raw_ostream &OS) {
+ASTConsumer *clang::CreateASTDumperXML(raw_ostream &OS) {
return new ASTDumpXML(OS);
}
diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp
index 3905b99b02a4..cb195d11fbca 100644
--- a/lib/Frontend/ASTMerge.cpp
+++ b/lib/Frontend/ASTMerge.cpp
@@ -17,12 +17,12 @@
using namespace clang;
ASTConsumer *ASTMergeAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
+ StringRef InFile) {
return AdaptedAction->CreateASTConsumer(CI, InFile);
}
bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI,
- llvm::StringRef Filename) {
+ StringRef Filename) {
// FIXME: This is a hack. We need a better way to communicate the
// AST file, compiler instance, and file name than member variables
// of FrontendAction.
@@ -41,8 +41,8 @@ void ASTMergeAction::ExecuteAction() {
llvm::IntrusiveRefCntPtr<DiagnosticIDs>
DiagIDs(CI.getDiagnostics().getDiagnosticIDs());
for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) {
- llvm::IntrusiveRefCntPtr<Diagnostic>
- Diags(new Diagnostic(DiagIDs, CI.getDiagnostics().getClient(),
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine>
+ Diags(new DiagnosticsEngine(DiagIDs, CI.getDiagnostics().getClient(),
/*ShouldOwnClient=*/false));
ASTUnit *Unit = ASTUnit::LoadFromASTFile(ASTFiles[I], Diags,
CI.getFileSystemOpts(), false);
@@ -93,8 +93,8 @@ bool ASTMergeAction::usesPreprocessorOnly() const {
return AdaptedAction->usesPreprocessorOnly();
}
-bool ASTMergeAction::usesCompleteTranslationUnit() {
- return AdaptedAction->usesCompleteTranslationUnit();
+TranslationUnitKind ASTMergeAction::getTranslationUnitKind() {
+ return AdaptedAction->getTranslationUnitKind();
}
bool ASTMergeAction::hasPCHSupport() const {
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 5b0a52c65b84..032adf3876a4 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -29,7 +29,6 @@
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Frontend/Utils.h"
#include "clang/Serialization/ASTReader.h"
-#include "clang/Serialization/ASTSerializationListener.h"
#include "clang/Serialization/ASTWriter.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
@@ -45,6 +44,8 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Timer.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Mutex.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include <cstdlib>
#include <cstdio>
@@ -65,7 +66,7 @@ namespace {
Start = TimeRecord::getCurrentTime();
}
- void setOutput(const llvm::Twine &Output) {
+ void setOutput(const Twine &Output) {
if (WantTiming)
this->Output = Output.str();
}
@@ -96,10 +97,9 @@ static llvm::sys::cas_flag ActiveASTUnitObjects;
ASTUnit::ASTUnit(bool _MainFileIsAST)
: OnlyLocalDecls(false), CaptureDiagnostics(false),
MainFileIsAST(_MainFileIsAST),
- CompleteTranslationUnit(true), WantTiming(getenv("LIBCLANG_TIMING")),
+ TUKind(TU_Complete), WantTiming(getenv("LIBCLANG_TIMING")),
OwnsRemappedFileBuffers(true),
NumStoredDiagnosticsFromDriver(0),
- ConcurrencyCheckValue(CheckUnlocked),
PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0),
ShouldCacheCodeCompletionResults(false),
NestedMacroExpansions(true),
@@ -114,7 +114,6 @@ ASTUnit::ASTUnit(bool _MainFileIsAST)
}
ASTUnit::~ASTUnit() {
- ConcurrencyCheckValue = CheckLocked;
CleanTemporaryFiles();
if (!PreambleFile.empty())
llvm::sys::Path(PreambleFile).eraseFromDisk();
@@ -185,7 +184,7 @@ static unsigned getDeclShowContexts(NamedDecl *ND,
// In Objective-C, you can only be a subclass of another Objective-C class
if (isa<ObjCInterfaceDecl>(ND))
- Contexts |= (1 << (CodeCompletionContext::CCC_ObjCSuperclass - 1));
+ Contexts |= (1 << (CodeCompletionContext::CCC_ObjCInterfaceName - 1));
// Deal with tag names.
if (isa<EnumDecl>(ND)) {
@@ -236,7 +235,7 @@ void ASTUnit::CacheCodeCompletionResults() {
// Gather the set of global code completions.
typedef CodeCompletionResult Result;
- llvm::SmallVector<Result, 8> Results;
+ SmallVector<Result, 8> Results;
CachedCompletionAllocator = new GlobalCodeCompletionAllocator;
TheSema->GatherGlobalCodeCompletions(*CachedCompletionAllocator, Results);
@@ -375,33 +374,61 @@ namespace {
/// \brief Gathers information from ASTReader that will be used to initialize
/// a Preprocessor.
class ASTInfoCollector : public ASTReaderListener {
+ Preprocessor &PP;
+ ASTContext &Context;
LangOptions &LangOpt;
HeaderSearch &HSI;
- std::string &TargetTriple;
+ llvm::IntrusiveRefCntPtr<TargetInfo> &Target;
std::string &Predefines;
unsigned &Counter;
unsigned NumHeaderInfos;
+ bool InitializedLanguage;
public:
- ASTInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI,
- std::string &TargetTriple, std::string &Predefines,
+ ASTInfoCollector(Preprocessor &PP, ASTContext &Context, LangOptions &LangOpt,
+ HeaderSearch &HSI,
+ llvm::IntrusiveRefCntPtr<TargetInfo> &Target,
+ std::string &Predefines,
unsigned &Counter)
- : LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple),
- Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {}
+ : PP(PP), Context(Context), LangOpt(LangOpt), HSI(HSI), Target(Target),
+ Predefines(Predefines), Counter(Counter), NumHeaderInfos(0),
+ InitializedLanguage(false) {}
virtual bool ReadLanguageOptions(const LangOptions &LangOpts) {
+ if (InitializedLanguage)
+ return false;
+
LangOpt = LangOpts;
+
+ // Initialize the preprocessor.
+ PP.Initialize(*Target);
+
+ // Initialize the ASTContext
+ Context.InitBuiltinTypes(*Target);
+
+ InitializedLanguage = true;
return false;
}
- virtual bool ReadTargetTriple(llvm::StringRef Triple) {
- TargetTriple = Triple;
+ virtual bool ReadTargetTriple(StringRef Triple) {
+ // If we've already initialized the target, don't do it again.
+ if (Target)
+ return false;
+
+ // FIXME: This is broken, we should store the TargetOptions in the AST file.
+ TargetOptions TargetOpts;
+ TargetOpts.ABI = "";
+ TargetOpts.CXXABI = "";
+ TargetOpts.CPU = "";
+ TargetOpts.Features.clear();
+ TargetOpts.Triple = Triple;
+ Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(), TargetOpts);
return false;
}
virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
- llvm::StringRef OriginalFileName,
+ StringRef OriginalFileName,
std::string &SuggestedPredefines,
FileManager &FileMgr) {
Predefines = Buffers[0].Data;
@@ -420,28 +447,34 @@ public:
}
};
-class StoredDiagnosticClient : public DiagnosticClient {
- llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags;
+class StoredDiagnosticConsumer : public DiagnosticConsumer {
+ SmallVectorImpl<StoredDiagnostic> &StoredDiags;
public:
- explicit StoredDiagnosticClient(
- llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
+ explicit StoredDiagnosticConsumer(
+ SmallVectorImpl<StoredDiagnostic> &StoredDiags)
: StoredDiags(StoredDiags) { }
- virtual void HandleDiagnostic(Diagnostic::Level Level,
- const DiagnosticInfo &Info);
+ virtual void HandleDiagnostic(DiagnosticsEngine::Level Level,
+ const Diagnostic &Info);
+
+ DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
+ // Just drop any diagnostics that come from cloned consumers; they'll
+ // have different source managers anyway.
+ return new IgnoringDiagConsumer();
+ }
};
/// \brief RAII object that optionally captures diagnostics, if
/// there is no diagnostic client to capture them already.
class CaptureDroppedDiagnostics {
- Diagnostic &Diags;
- StoredDiagnosticClient Client;
- DiagnosticClient *PreviousClient;
+ DiagnosticsEngine &Diags;
+ StoredDiagnosticConsumer Client;
+ DiagnosticConsumer *PreviousClient;
public:
- CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags,
- llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
+ CaptureDroppedDiagnostics(bool RequestCapture, DiagnosticsEngine &Diags,
+ SmallVectorImpl<StoredDiagnostic> &StoredDiags)
: Diags(Diags), Client(StoredDiags), PreviousClient(0)
{
if (RequestCapture || Diags.getClient() == 0) {
@@ -460,10 +493,10 @@ public:
} // anonymous namespace
-void StoredDiagnosticClient::HandleDiagnostic(Diagnostic::Level Level,
- const DiagnosticInfo &Info) {
+void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level,
+ const Diagnostic &Info) {
// Default implementation (Warnings/errors count).
- DiagnosticClient::HandleDiagnostic(Level, Info);
+ DiagnosticConsumer::HandleDiagnostic(Level, Info);
StoredDiags.push_back(StoredDiagnostic(Level, Info));
}
@@ -472,37 +505,32 @@ const std::string &ASTUnit::getOriginalSourceFileName() {
return OriginalSourceFile;
}
-const std::string &ASTUnit::getASTFileName() {
- assert(isMainFileAST() && "Not an ASTUnit from an AST file!");
- return static_cast<ASTReader *>(Ctx->getExternalSource())->getFileName();
-}
-
-llvm::MemoryBuffer *ASTUnit::getBufferForFile(llvm::StringRef Filename,
+llvm::MemoryBuffer *ASTUnit::getBufferForFile(StringRef Filename,
std::string *ErrorStr) {
assert(FileMgr);
return FileMgr->getBufferForFile(Filename, ErrorStr);
}
/// \brief Configure the diagnostics object for use with ASTUnit.
-void ASTUnit::ConfigureDiags(llvm::IntrusiveRefCntPtr<Diagnostic> &Diags,
+void ASTUnit::ConfigureDiags(llvm::IntrusiveRefCntPtr<DiagnosticsEngine> &Diags,
const char **ArgBegin, const char **ArgEnd,
ASTUnit &AST, bool CaptureDiagnostics) {
if (!Diags.getPtr()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
DiagnosticOptions DiagOpts;
- DiagnosticClient *Client = 0;
+ DiagnosticConsumer *Client = 0;
if (CaptureDiagnostics)
- Client = new StoredDiagnosticClient(AST.StoredDiagnostics);
+ Client = new StoredDiagnosticConsumer(AST.StoredDiagnostics);
Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd- ArgBegin,
ArgBegin, Client);
} else if (CaptureDiagnostics) {
- Diags->setClient(new StoredDiagnosticClient(AST.StoredDiagnostics));
+ Diags->setClient(new StoredDiagnosticConsumer(AST.StoredDiagnostics));
}
}
ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
const FileSystemOptions &FileSystemOpts,
bool OnlyLocalDecls,
RemappedFile *RemappedFiles,
@@ -513,8 +541,8 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
ASTUnitCleanup(AST.get());
- llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic,
- llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> >
+ llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
+ llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
DiagCleanup(Diags.getPtr());
ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics);
@@ -576,25 +604,41 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
// Gather Info for preprocessor construction later on.
- LangOptions LangInfo;
HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
- std::string TargetTriple;
std::string Predefines;
unsigned Counter;
llvm::OwningPtr<ASTReader> Reader;
- Reader.reset(new ASTReader(AST->getSourceManager(), AST->getFileManager(),
- AST->getDiagnostics()));
+ AST->PP = new Preprocessor(AST->getDiagnostics(), AST->ASTFileLangOpts,
+ /*Target=*/0, AST->getSourceManager(), HeaderInfo,
+ *AST,
+ /*IILookup=*/0,
+ /*OwnsHeaderSearch=*/false,
+ /*DelayInitialization=*/true);
+ Preprocessor &PP = *AST->PP;
+
+ AST->Ctx = new ASTContext(AST->ASTFileLangOpts,
+ AST->getSourceManager(),
+ /*Target=*/0,
+ PP.getIdentifierTable(),
+ PP.getSelectorTable(),
+ PP.getBuiltinInfo(),
+ /* size_reserve = */0,
+ /*DelayInitialization=*/true);
+ ASTContext &Context = *AST->Ctx;
+
+ Reader.reset(new ASTReader(PP, Context));
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTReader>
ReaderCleanup(Reader.get());
- Reader->setListener(new ASTInfoCollector(LangInfo, HeaderInfo, TargetTriple,
- Predefines, Counter));
+ Reader->setListener(new ASTInfoCollector(*AST->PP, Context,
+ AST->ASTFileLangOpts, HeaderInfo,
+ AST->Target, Predefines, Counter));
- switch (Reader->ReadAST(Filename, ASTReader::MainFile)) {
+ switch (Reader->ReadAST(Filename, serialization::MK_MainFile)) {
case ASTReader::Success:
break;
@@ -606,39 +650,8 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
AST->OriginalSourceFile = Reader->getOriginalSourceFile();
- // AST file loaded successfully. Now create the preprocessor.
-
- // Get information about the target being compiled for.
- //
- // FIXME: This is broken, we should store the TargetOptions in the AST file.
- TargetOptions TargetOpts;
- TargetOpts.ABI = "";
- TargetOpts.CXXABI = "";
- TargetOpts.CPU = "";
- TargetOpts.Features.clear();
- TargetOpts.Triple = TargetTriple;
- AST->Target = TargetInfo::CreateTargetInfo(AST->getDiagnostics(),
- TargetOpts);
- AST->PP = new Preprocessor(AST->getDiagnostics(), LangInfo, *AST->Target,
- AST->getSourceManager(), HeaderInfo);
- Preprocessor &PP = *AST->PP;
-
PP.setPredefines(Reader->getSuggestedPredefines());
PP.setCounterValue(Counter);
- Reader->setPreprocessor(PP);
-
- // Create and initialize the ASTContext.
-
- AST->Ctx = new ASTContext(LangInfo,
- AST->getSourceManager(),
- *AST->Target,
- PP.getIdentifierTable(),
- PP.getSelectorTable(),
- PP.getBuiltinInfo(),
- /* size_reserve = */0);
- ASTContext &Context = *AST->Ctx;
-
- Reader->InitializeContext(Context);
// Attach the AST reader to the AST context as an external AST
// source, so that declarations will be deserialized from the
@@ -710,10 +723,8 @@ void AddTopLevelDeclarationToHash(Decl *D, unsigned &Hash) {
return;
}
- if (ObjCClassDecl *Class = llvm::dyn_cast<ObjCClassDecl>(D)) {
- for (ObjCClassDecl::iterator I = Class->begin(), IEnd = Class->end();
- I != IEnd; ++I)
- AddTopLevelDeclarationToHash(I->getInterface(), Hash);
+ if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(D)) {
+ AddTopLevelDeclarationToHash(Class->getForwardInterfaceDecl(), Hash);
return;
}
}
@@ -752,7 +763,7 @@ public:
ASTUnit &Unit;
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
+ StringRef InFile) {
CI.getPreprocessor().addPPCallbacks(
new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue()));
return new TopLevelDeclTrackerConsumer(Unit,
@@ -763,22 +774,20 @@ public:
TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
virtual bool hasCodeCompletionSupport() const { return false; }
- virtual bool usesCompleteTranslationUnit() {
- return Unit.isCompleteTranslationUnit();
+ virtual TranslationUnitKind getTranslationUnitKind() {
+ return Unit.getTranslationUnitKind();
}
};
-class PrecompilePreambleConsumer : public PCHGenerator,
- public ASTSerializationListener {
+class PrecompilePreambleConsumer : public PCHGenerator {
ASTUnit &Unit;
unsigned &Hash;
std::vector<Decl *> TopLevelDecls;
public:
- PrecompilePreambleConsumer(ASTUnit &Unit,
- const Preprocessor &PP, bool Chaining,
- const char *isysroot, llvm::raw_ostream *Out)
- : PCHGenerator(PP, "", Chaining, isysroot, Out), Unit(Unit),
+ PrecompilePreambleConsumer(ASTUnit &Unit, const Preprocessor &PP,
+ StringRef isysroot, raw_ostream *Out)
+ : PCHGenerator(PP, "", /*IsModule=*/false, isysroot, Out), Unit(Unit),
Hash(Unit.getCurrentTopLevelHashValue()) {
Hash = 0;
}
@@ -809,15 +818,6 @@ public:
getWriter().getDeclID(TopLevelDecls[I]));
}
}
-
- virtual void SerializedPreprocessedEntity(PreprocessedEntity *Entity,
- uint64_t Offset) {
- Unit.addPreprocessedEntityFromPreamble(Offset);
- }
-
- virtual ASTSerializationListener *GetASTSerializationListener() {
- return this;
- }
};
class PrecompilePreambleAction : public ASTFrontendAction {
@@ -827,27 +827,27 @@ public:
explicit PrecompilePreambleAction(ASTUnit &Unit) : Unit(Unit) {}
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
+ StringRef InFile) {
std::string Sysroot;
std::string OutputFile;
- llvm::raw_ostream *OS = 0;
- bool Chaining;
+ raw_ostream *OS = 0;
if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
OutputFile,
- OS, Chaining))
+ OS))
return 0;
- const char *isysroot = CI.getFrontendOpts().RelocatablePCH ?
- Sysroot.c_str() : 0;
+ if (!CI.getFrontendOpts().RelocatablePCH)
+ Sysroot.clear();
+
CI.getPreprocessor().addPPCallbacks(
new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue()));
- return new PrecompilePreambleConsumer(Unit, CI.getPreprocessor(), Chaining,
- isysroot, OS);
+ return new PrecompilePreambleConsumer(Unit, CI.getPreprocessor(), Sysroot,
+ OS);
}
virtual bool hasCodeCompletionSupport() const { return false; }
virtual bool hasASTFileSupport() const { return false; }
- virtual bool usesCompleteTranslationUnit() { return false; }
+ virtual TranslationUnitKind getTranslationUnitKind() { return TU_Prefix; }
};
}
@@ -873,7 +873,10 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
CICleanup(Clang.get());
- Clang->setInvocation(&*Invocation);
+ llvm::IntrusiveRefCntPtr<CompilerInvocation>
+ CCInvocation(new CompilerInvocation(*Invocation));
+
+ Clang->setInvocation(CCInvocation.getPtr());
OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].second;
// Set up diagnostics, capturing any diagnostics that would
@@ -913,16 +916,13 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
// Clear out old caches and data.
TopLevelDecls.clear();
- PreprocessedEntities.clear();
CleanTemporaryFiles();
- PreprocessedEntitiesByFile.clear();
if (!OverrideMainBuffer) {
StoredDiagnostics.erase(
StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver,
StoredDiagnostics.end());
TopLevelDeclsInPreamble.clear();
- PreprocessedEntitiesInPreamble.clear();
}
// Create a file manager object to provide access to and cache the filesystem.
@@ -936,13 +936,11 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts();
PreprocessorOpts.DetailedRecordIncludesNestedMacroExpansions
= NestedMacroExpansions;
- std::string PriorImplicitPCHInclude;
if (OverrideMainBuffer) {
PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
PreprocessorOpts.PrecompiledPreambleBytes.second
= PreambleEndsAtStartOfLine;
- PriorImplicitPCHInclude = PreprocessorOpts.ImplicitPCHInclude;
PreprocessorOpts.ImplicitPCHInclude = PreambleFile;
PreprocessorOpts.DisablePCHValidation = true;
@@ -961,9 +959,6 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
// Keep track of the override buffer;
SavedMainFileBuffer = OverrideMainBuffer;
- } else {
- PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
- PreprocessorOpts.PrecompiledPreambleBytes.second = false;
}
llvm::OwningPtr<TopLevelDeclTrackerAction> Act(
@@ -976,7 +971,14 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second,
Clang->getFrontendOpts().Inputs[0].first))
goto error;
-
+
+ if (OverrideMainBuffer) {
+ std::string ModName = PreambleFile;
+ TranslateStoredDiagnostics(Clang->getModuleManager(), ModName,
+ getSourceManager(), PreambleDiagnostics,
+ StoredDiagnostics);
+ }
+
Act->Execute();
// Steal the created target, context, and preprocessor.
@@ -990,21 +992,11 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
Act->EndSourceFile();
- // Remove the overridden buffer we used for the preamble.
- if (OverrideMainBuffer) {
- PreprocessorOpts.eraseRemappedFile(
- PreprocessorOpts.remapped_file_buffer_end() - 1);
- PreprocessorOpts.ImplicitPCHInclude = PriorImplicitPCHInclude;
- }
-
return false;
error:
// Remove the overridden buffer we used for the preamble.
if (OverrideMainBuffer) {
- PreprocessorOpts.eraseRemappedFile(
- PreprocessorOpts.remapped_file_buffer_end() - 1);
- PreprocessorOpts.ImplicitPCHInclude = PriorImplicitPCHInclude;
delete OverrideMainBuffer;
SavedMainFileBuffer = 0;
}
@@ -1041,7 +1033,7 @@ static std::string GetPreamblePCHPath() {
P.createDirectoryOnDisk(true);
P.appendComponent("preamble");
P.appendSuffix("pch");
- if (P.createTemporaryFileOnDisk())
+ if (P.makeUnique(/*reuse_current=*/false, /*ErrMsg*/0))
return std::string();
return P.str();
@@ -1118,12 +1110,14 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
CreatedBuffer = true;
}
- return std::make_pair(Buffer, Lexer::ComputePreamble(Buffer, MaxLines));
+ return std::make_pair(Buffer, Lexer::ComputePreamble(Buffer,
+ Invocation.getLangOpts(),
+ MaxLines));
}
static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old,
unsigned NewSize,
- llvm::StringRef NewName) {
+ StringRef NewName) {
llvm::MemoryBuffer *Result
= llvm::MemoryBuffer::getNewUninitMemBuffer(NewSize, NewName);
memcpy(const_cast<char*>(Result->getBufferStart()),
@@ -1170,7 +1164,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> > NewPreamble
= ComputePreamble(*PreambleInvocation, MaxLines, CreatedPreambleBuffer);
- // If ComputePreamble() Take ownership of the
+ // If ComputePreamble() Take ownership of the preamble buffer.
llvm::OwningPtr<llvm::MemoryBuffer> OwnedPreambleBuffer;
if (CreatedPreambleBuffer)
OwnedPreambleBuffer.reset(NewPreamble.first);
@@ -1197,7 +1191,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
if (Preamble.size() == NewPreamble.second.first &&
PreambleEndsAtStartOfLine == NewPreamble.second.second &&
NewPreamble.first->getBufferSize() < PreambleReservedSize-2 &&
- memcmp(&Preamble[0], NewPreamble.first->getBufferStart(),
+ memcmp(Preamble.getBufferStart(), NewPreamble.first->getBufferStart(),
NewPreamble.second.first) == 0) {
// The preamble has not changed. We may be able to re-use the precompiled
// preamble.
@@ -1271,10 +1265,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
ProcessWarningOptions(getDiagnostics(),
PreambleInvocation->getDiagnosticOpts());
getDiagnostics().setNumWarnings(NumWarningsInPreamble);
- if (StoredDiagnostics.size() > NumStoredDiagnosticsInPreamble)
- StoredDiagnostics.erase(
- StoredDiagnostics.begin() + NumStoredDiagnosticsInPreamble,
- StoredDiagnostics.end());
// Create a version of the main file buffer that is padded to
// buffer size we reserved when creating the preamble.
@@ -1291,6 +1281,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// We can't reuse the previously-computed preamble. Build a new one.
Preamble.clear();
+ PreambleDiagnostics.clear();
llvm::sys::Path(PreambleFile).eraseFromDisk();
PreambleRebuildCounter = 1;
} else if (!AllowRebuild) {
@@ -1332,7 +1323,9 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// Save the preamble text for later; we'll need to compare against it for
// subsequent reparses.
- Preamble.assign(NewPreamble.first->getBufferStart(),
+ StringRef MainFilename = PreambleInvocation->getFrontendOpts().Inputs[0].second;
+ Preamble.assign(FileMgr->getFile(MainFilename),
+ NewPreamble.first->getBufferStart(),
NewPreamble.first->getBufferStart()
+ NewPreamble.second.first);
PreambleEndsAtStartOfLine = NewPreamble.second.second;
@@ -1353,7 +1346,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// Tell the compiler invocation to generate a temporary precompiled header.
FrontendOpts.ProgramAction = frontend::GeneratePCH;
- FrontendOpts.ChainedPCH = true;
// FIXME: Generate the precompiled header into memory?
FrontendOpts.OutputFile = PreamblePCHPath;
PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
@@ -1406,8 +1398,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
StoredDiagnostics.end());
TopLevelDecls.clear();
TopLevelDeclsInPreamble.clear();
- PreprocessedEntities.clear();
- PreprocessedEntitiesInPreamble.clear();
// Create a file manager object to provide access to and cache the filesystem.
Clang->setFileManager(new FileManager(Clang->getFileSystemOpts()));
@@ -1438,17 +1428,24 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
Preamble.clear();
TopLevelDeclsInPreamble.clear();
- PreprocessedEntities.clear();
- PreprocessedEntitiesInPreamble.clear();
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
PreprocessorOpts.eraseRemappedFile(
PreprocessorOpts.remapped_file_buffer_end() - 1);
return 0;
}
+ // Transfer any diagnostics generated when parsing the preamble into the set
+ // of preamble diagnostics.
+ PreambleDiagnostics.clear();
+ PreambleDiagnostics.insert(PreambleDiagnostics.end(),
+ StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver,
+ StoredDiagnostics.end());
+ StoredDiagnostics.erase(
+ StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver,
+ StoredDiagnostics.end());
+
// Keep track of the preamble we precompiled.
PreambleFile = FrontendOpts.OutputFile;
- NumStoredDiagnosticsInPreamble = StoredDiagnostics.size();
NumWarningsInPreamble = getDiagnostics().getNumWarnings();
// Keep track of all of the files that the source manager knows about,
@@ -1501,69 +1498,12 @@ void ASTUnit::RealizeTopLevelDeclsFromPreamble() {
TopLevelDecls.insert(TopLevelDecls.begin(), Resolved.begin(), Resolved.end());
}
-void ASTUnit::RealizePreprocessedEntitiesFromPreamble() {
- if (!PP)
- return;
-
- PreprocessingRecord *PPRec = PP->getPreprocessingRecord();
- if (!PPRec)
- return;
-
- ExternalPreprocessingRecordSource *External = PPRec->getExternalSource();
- if (!External)
- return;
-
- for (unsigned I = 0, N = PreprocessedEntitiesInPreamble.size(); I != N; ++I) {
- if (PreprocessedEntity *PE
- = External->ReadPreprocessedEntityAtOffset(
- PreprocessedEntitiesInPreamble[I]))
- PreprocessedEntities.push_back(PE);
- }
-
- if (PreprocessedEntities.empty())
- return;
-
- PreprocessedEntities.insert(PreprocessedEntities.end(),
- PPRec->begin(true), PPRec->end(true));
-}
-
-ASTUnit::pp_entity_iterator ASTUnit::pp_entity_begin() {
- if (!PreprocessedEntitiesInPreamble.empty() &&
- PreprocessedEntities.empty())
- RealizePreprocessedEntitiesFromPreamble();
-
- if (PreprocessedEntities.empty())
- if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord())
- return PPRec->begin(true);
-
- return PreprocessedEntities.begin();
-}
-
-ASTUnit::pp_entity_iterator ASTUnit::pp_entity_end() {
- if (!PreprocessedEntitiesInPreamble.empty() &&
- PreprocessedEntities.empty())
- RealizePreprocessedEntitiesFromPreamble();
-
- if (PreprocessedEntities.empty())
- if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord())
- return PPRec->end(true);
-
- return PreprocessedEntities.end();
-}
-
-unsigned ASTUnit::getMaxPCHLevel() const {
- if (!getOnlyLocalDecls())
- return Decl::MaxPCHLevel;
-
- return 0;
-}
-
-llvm::StringRef ASTUnit::getMainFileName() const {
+StringRef ASTUnit::getMainFileName() const {
return Invocation->getFrontendOpts().Inputs[0].second;
}
ASTUnit *ASTUnit::create(CompilerInvocation *CI,
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags) {
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags) {
llvm::OwningPtr<ASTUnit> AST;
AST.reset(new ASTUnit(false));
ConfigureDiags(Diags, 0, 0, *AST, /*CaptureDiagnostics=*/false);
@@ -1571,33 +1511,35 @@ ASTUnit *ASTUnit::create(CompilerInvocation *CI,
AST->Invocation = CI;
AST->FileSystemOpts = CI->getFileSystemOpts();
AST->FileMgr = new FileManager(AST->FileSystemOpts);
- AST->SourceMgr = new SourceManager(*Diags, *AST->FileMgr);
+ AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr);
return AST.take();
}
ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
- ASTFrontendAction *Action) {
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ ASTFrontendAction *Action,
+ ASTUnit *Unit) {
assert(CI && "A CompilerInvocation is required");
- // Create the AST unit.
- llvm::OwningPtr<ASTUnit> AST;
- AST.reset(new ASTUnit(false));
- ConfigureDiags(Diags, 0, 0, *AST, /*CaptureDiagnostics*/false);
- AST->Diagnostics = Diags;
+ llvm::OwningPtr<ASTUnit> OwnAST;
+ ASTUnit *AST = Unit;
+ if (!AST) {
+ // Create the AST unit.
+ OwnAST.reset(create(CI, Diags));
+ AST = OwnAST.get();
+ }
+
AST->OnlyLocalDecls = false;
AST->CaptureDiagnostics = false;
- AST->CompleteTranslationUnit = Action ? Action->usesCompleteTranslationUnit()
- : true;
+ AST->TUKind = Action ? Action->getTranslationUnitKind() : TU_Complete;
AST->ShouldCacheCodeCompletionResults = false;
- AST->Invocation = CI;
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
- ASTUnitCleanup(AST.get());
- llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic,
- llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> >
+ ASTUnitCleanup(OwnAST.get());
+ llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
+ llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
DiagCleanup(Diags.getPtr());
// We'll manage file buffers ourselves.
@@ -1643,9 +1585,6 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
"IR inputs not supported here!");
// Configure the various subsystems.
- AST->FileSystemOpts = Clang->getFileSystemOpts();
- AST->FileMgr = new FileManager(AST->FileSystemOpts);
- AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr);
AST->TheSema.reset();
AST->Ctx = 0;
AST->PP = 0;
@@ -1686,7 +1625,10 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
Act->EndSourceFile();
- return AST.take();
+ if (OwnAST)
+ return OwnAST.take();
+ else
+ return AST;
}
bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) {
@@ -1719,11 +1661,11 @@ bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) {
}
ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
bool OnlyLocalDecls,
bool CaptureDiagnostics,
bool PrecompilePreamble,
- bool CompleteTranslationUnit,
+ TranslationUnitKind TUKind,
bool CacheCodeCompletionResults,
bool NestedMacroExpansions) {
// Create the AST unit.
@@ -1733,7 +1675,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
AST->Diagnostics = Diags;
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
- AST->CompleteTranslationUnit = CompleteTranslationUnit;
+ AST->TUKind = TUKind;
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
AST->Invocation = CI;
AST->NestedMacroExpansions = NestedMacroExpansions;
@@ -1741,8 +1683,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
ASTUnitCleanup(AST.get());
- llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic,
- llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> >
+ llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
+ llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
DiagCleanup(Diags.getPtr());
return AST->LoadFromCompilerInvocation(PrecompilePreamble)? 0 : AST.take();
@@ -1750,18 +1692,16 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
const char **ArgEnd,
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
- llvm::StringRef ResourceFilesPath,
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ StringRef ResourceFilesPath,
bool OnlyLocalDecls,
bool CaptureDiagnostics,
RemappedFile *RemappedFiles,
unsigned NumRemappedFiles,
bool RemappedFilesKeepOriginalName,
bool PrecompilePreamble,
- bool CompleteTranslationUnit,
+ TranslationUnitKind TUKind,
bool CacheCodeCompletionResults,
- bool CXXPrecompilePreamble,
- bool CXXChainedPCH,
bool NestedMacroExpansions) {
if (!Diags.getPtr()) {
// No diagnostics engine was provided, so create our own diagnostics object
@@ -1771,17 +1711,18 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
ArgBegin);
}
- llvm::SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
+ SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
llvm::IntrusiveRefCntPtr<CompilerInvocation> CI;
{
+
CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags,
StoredDiagnostics);
CI = clang::createInvocationFromCommandLine(
- llvm::ArrayRef<const char *>(ArgBegin, ArgEnd-ArgBegin),
- Diags);
+ llvm::makeArrayRef(ArgBegin, ArgEnd),
+ Diags);
if (!CI)
return 0;
}
@@ -1803,16 +1744,6 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
// Override the resources path.
CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
- // Check whether we should precompile the preamble and/or use chained PCH.
- // FIXME: This is a temporary hack while we debug C++ chained PCH.
- if (CI->getLangOpts().CPlusPlus) {
- PrecompilePreamble = PrecompilePreamble && CXXPrecompilePreamble;
-
- if (PrecompilePreamble && !CXXChainedPCH &&
- !CI->getPreprocessorOpts().ImplicitPCHInclude.empty())
- PrecompilePreamble = false;
- }
-
// Create the AST unit.
llvm::OwningPtr<ASTUnit> AST;
AST.reset(new ASTUnit(false));
@@ -1823,10 +1754,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
AST->FileMgr = new FileManager(AST->FileSystemOpts);
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
- AST->CompleteTranslationUnit = CompleteTranslationUnit;
+ AST->TUKind = TUKind;
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size();
- AST->NumStoredDiagnosticsInPreamble = StoredDiagnostics.size();
AST->StoredDiagnostics.swap(StoredDiagnostics);
AST->Invocation = CI;
AST->NestedMacroExpansions = NestedMacroExpansions;
@@ -1837,8 +1767,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInvocation,
llvm::CrashRecoveryContextReleaseRefCleanup<CompilerInvocation> >
CICleanup(CI.getPtr());
- llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic,
- llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> >
+ llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
+ llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
DiagCleanup(Diags.getPtr());
return AST->LoadFromCompilerInvocation(PrecompilePreamble) ? 0 : AST.take();
@@ -1896,6 +1826,10 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
CurrentTopLevelHashValue != CompletionCacheTopLevelHashValue)
CacheCodeCompletionResults();
+ // We now need to clear out the completion allocator for
+ // clang_getCursorCompletionString; it'll be recreated if necessary.
+ CursorCompletionAllocator = 0;
+
return Result;
}
@@ -1985,7 +1919,7 @@ static void CalculateHiddenNames(const CodeCompletionContext &Context,
case CodeCompletionContext::CCC_Name:
case CodeCompletionContext::CCC_PotentiallyQualifiedName:
case CodeCompletionContext::CCC_ParenthesizedExpression:
- case CodeCompletionContext::CCC_ObjCSuperclass:
+ case CodeCompletionContext::CCC_ObjCInterfaceName:
break;
case CodeCompletionContext::CCC_EnumTag:
@@ -2052,12 +1986,11 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
bool AddedResult = false;
unsigned InContexts
= (Context.getKind() == CodeCompletionContext::CCC_Recovery? NormalContexts
- : (1 << (Context.getKind() - 1)));
-
+ : (1ULL << (Context.getKind() - 1)));
// Contains the set of names that are hidden by "local" completion results.
llvm::StringSet<llvm::BumpPtrAllocator> HiddenNames;
typedef CodeCompletionResult Result;
- llvm::SmallVector<Result, 8> AllResults;
+ SmallVector<Result, 8> AllResults;
for (ASTUnit::cached_completion_iterator
C = AST.cached_completion_begin(),
CEnd = AST.cached_completion_end();
@@ -2139,22 +2072,22 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
-void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
+void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
RemappedFile *RemappedFiles,
unsigned NumRemappedFiles,
bool IncludeMacros,
bool IncludeCodePatterns,
CodeCompleteConsumer &Consumer,
- Diagnostic &Diag, LangOptions &LangOpts,
+ DiagnosticsEngine &Diag, LangOptions &LangOpts,
SourceManager &SourceMgr, FileManager &FileMgr,
- llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics,
- llvm::SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers) {
+ SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics,
+ SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers) {
if (!Invocation)
return;
SimpleTimer CompletionTimer(WantTiming);
CompletionTimer.setOutput("Code completion @ " + File + ":" +
- llvm::Twine(Line) + ":" + llvm::Twine(Column));
+ Twine(Line) + ":" + Twine(Column));
llvm::IntrusiveRefCntPtr<CompilerInvocation>
CCInvocation(new CompilerInvocation(*Invocation));
@@ -2252,7 +2185,8 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
llvm::sys::PathWithStatus MainPath(OriginalSourceFile);
if (const FileStatus *CompleteFileStatus = CompleteFilePath.getFileStatus())
if (const FileStatus *MainStatus = MainPath.getFileStatus())
- if (CompleteFileStatus->getUniqueID() == MainStatus->getUniqueID())
+ if (CompleteFileStatus->getUniqueID() == MainStatus->getUniqueID() &&
+ Line > 1)
OverrideMainBuffer
= getMainBufferWithPrecompiledPreamble(*CCInvocation, false,
Line - 1);
@@ -2272,17 +2206,6 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
PreprocessorOpts.ImplicitPCHInclude = PreambleFile;
PreprocessorOpts.DisablePCHValidation = true;
- // The stored diagnostics have the old source manager. Copy them
- // to our output set of stored diagnostics, updating the source
- // manager to the one we were given.
- for (unsigned I = NumStoredDiagnosticsFromDriver,
- N = this->StoredDiagnostics.size();
- I < N; ++I) {
- StoredDiagnostics.push_back(this->StoredDiagnostics[I]);
- FullSourceLoc Loc(StoredDiagnostics[I].getLocation(), SourceMgr);
- StoredDiagnostics[I].setLocation(Loc);
- }
-
OwnedBuffers.push_back(OverrideMainBuffer);
} else {
PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
@@ -2296,36 +2219,58 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
Act.reset(new SyntaxOnlyAction);
if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second,
Clang->getFrontendOpts().Inputs[0].first)) {
+ if (OverrideMainBuffer) {
+ std::string ModName = PreambleFile;
+ TranslateStoredDiagnostics(Clang->getModuleManager(), ModName,
+ getSourceManager(), PreambleDiagnostics,
+ StoredDiagnostics);
+ }
Act->Execute();
Act->EndSourceFile();
}
}
-CXSaveError ASTUnit::Save(llvm::StringRef File) {
+CXSaveError ASTUnit::Save(StringRef File) {
if (getDiagnostics().hasUnrecoverableErrorOccurred())
return CXSaveError_TranslationErrors;
-
+
+ // Write to a temporary file and later rename it to the actual file, to avoid
+ // possible race conditions.
+ llvm::SmallString<128> TempPath;
+ TempPath = File;
+ TempPath += "-%%%%%%%%";
+ int fd;
+ if (llvm::sys::fs::unique_file(TempPath.str(), fd, TempPath,
+ /*makeAbsolute=*/false))
+ return CXSaveError_Unknown;
+
// FIXME: Can we somehow regenerate the stat cache here, or do we need to
// unconditionally create a stat cache when we parse the file?
- std::string ErrorInfo;
- llvm::raw_fd_ostream Out(File.str().c_str(), ErrorInfo,
- llvm::raw_fd_ostream::F_Binary);
- if (!ErrorInfo.empty() || Out.has_error())
- return CXSaveError_Unknown;
+ llvm::raw_fd_ostream Out(fd, /*shouldClose=*/true);
serialize(Out);
Out.close();
- return Out.has_error()? CXSaveError_Unknown : CXSaveError_None;
+ if (Out.has_error())
+ return CXSaveError_Unknown;
+
+ if (llvm::error_code ec = llvm::sys::fs::rename(TempPath.str(), File)) {
+ bool exists;
+ llvm::sys::fs::remove(TempPath.str(), exists);
+ return CXSaveError_Unknown;
+ }
+
+ return CXSaveError_None;
}
-bool ASTUnit::serialize(llvm::raw_ostream &OS) {
+bool ASTUnit::serialize(raw_ostream &OS) {
if (getDiagnostics().hasErrorOccurred())
return true;
std::vector<unsigned char> Buffer;
llvm::BitstreamWriter Stream(Buffer);
ASTWriter Writer(Stream);
- Writer.WriteAST(getSema(), 0, std::string(), 0);
+ // FIXME: Handle modules
+ Writer.WriteAST(getSema(), 0, std::string(), /*IsModule=*/false, "");
// Write the generated bitstream to "Out".
if (!Buffer.empty())
@@ -2333,3 +2278,168 @@ bool ASTUnit::serialize(llvm::raw_ostream &OS) {
return false;
}
+
+typedef ContinuousRangeMap<unsigned, int, 2> SLocRemap;
+
+static void TranslateSLoc(SourceLocation &L, SLocRemap &Remap) {
+ unsigned Raw = L.getRawEncoding();
+ const unsigned MacroBit = 1U << 31;
+ L = SourceLocation::getFromRawEncoding((Raw & MacroBit) |
+ ((Raw & ~MacroBit) + Remap.find(Raw & ~MacroBit)->second));
+}
+
+void ASTUnit::TranslateStoredDiagnostics(
+ ASTReader *MMan,
+ StringRef ModName,
+ SourceManager &SrcMgr,
+ const SmallVectorImpl<StoredDiagnostic> &Diags,
+ SmallVectorImpl<StoredDiagnostic> &Out) {
+ // The stored diagnostic has the old source manager in it; update
+ // the locations to refer into the new source manager. We also need to remap
+ // all the locations to the new view. This includes the diag location, any
+ // associated source ranges, and the source ranges of associated fix-its.
+ // FIXME: There should be a cleaner way to do this.
+
+ SmallVector<StoredDiagnostic, 4> Result;
+ Result.reserve(Diags.size());
+ assert(MMan && "Don't have a module manager");
+ serialization::Module *Mod = MMan->ModuleMgr.lookup(ModName);
+ assert(Mod && "Don't have preamble module");
+ SLocRemap &Remap = Mod->SLocRemap;
+ for (unsigned I = 0, N = Diags.size(); I != N; ++I) {
+ // Rebuild the StoredDiagnostic.
+ const StoredDiagnostic &SD = Diags[I];
+ SourceLocation L = SD.getLocation();
+ TranslateSLoc(L, Remap);
+ FullSourceLoc Loc(L, SrcMgr);
+
+ SmallVector<CharSourceRange, 4> Ranges;
+ Ranges.reserve(SD.range_size());
+ for (StoredDiagnostic::range_iterator I = SD.range_begin(),
+ E = SD.range_end();
+ I != E; ++I) {
+ SourceLocation BL = I->getBegin();
+ TranslateSLoc(BL, Remap);
+ SourceLocation EL = I->getEnd();
+ TranslateSLoc(EL, Remap);
+ Ranges.push_back(CharSourceRange(SourceRange(BL, EL), I->isTokenRange()));
+ }
+
+ SmallVector<FixItHint, 2> FixIts;
+ FixIts.reserve(SD.fixit_size());
+ for (StoredDiagnostic::fixit_iterator I = SD.fixit_begin(),
+ E = SD.fixit_end();
+ I != E; ++I) {
+ FixIts.push_back(FixItHint());
+ FixItHint &FH = FixIts.back();
+ FH.CodeToInsert = I->CodeToInsert;
+ SourceLocation BL = I->RemoveRange.getBegin();
+ TranslateSLoc(BL, Remap);
+ SourceLocation EL = I->RemoveRange.getEnd();
+ TranslateSLoc(EL, Remap);
+ FH.RemoveRange = CharSourceRange(SourceRange(BL, EL),
+ I->RemoveRange.isTokenRange());
+ }
+
+ Result.push_back(StoredDiagnostic(SD.getLevel(), SD.getID(),
+ SD.getMessage(), Loc, Ranges, FixIts));
+ }
+ Result.swap(Out);
+}
+
+SourceLocation ASTUnit::getLocation(const FileEntry *File,
+ unsigned Line, unsigned Col) const {
+ const SourceManager &SM = getSourceManager();
+ SourceLocation Loc = SM.translateFileLineCol(File, Line, Col);
+ return SM.getMacroArgExpandedLocation(Loc);
+}
+
+SourceLocation ASTUnit::getLocation(const FileEntry *File,
+ unsigned Offset) const {
+ const SourceManager &SM = getSourceManager();
+ SourceLocation FileLoc = SM.translateFileLineCol(File, 1, 1);
+ return SM.getMacroArgExpandedLocation(FileLoc.getLocWithOffset(Offset));
+}
+
+/// \brief If \arg Loc is a loaded location from the preamble, returns
+/// the corresponding local location of the main file, otherwise it returns
+/// \arg Loc.
+SourceLocation ASTUnit::mapLocationFromPreamble(SourceLocation Loc) {
+ FileID PreambleID;
+ if (SourceMgr)
+ PreambleID = SourceMgr->getPreambleFileID();
+
+ if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid())
+ return Loc;
+
+ unsigned Offs;
+ if (SourceMgr->isInFileID(Loc, PreambleID, &Offs) && Offs < Preamble.size()) {
+ SourceLocation FileLoc
+ = SourceMgr->getLocForStartOfFile(SourceMgr->getMainFileID());
+ return FileLoc.getLocWithOffset(Offs);
+ }
+
+ return Loc;
+}
+
+/// \brief If \arg Loc is a local location of the main file but inside the
+/// preamble chunk, returns the corresponding loaded location from the
+/// preamble, otherwise it returns \arg Loc.
+SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) {
+ FileID PreambleID;
+ if (SourceMgr)
+ PreambleID = SourceMgr->getPreambleFileID();
+
+ if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid())
+ return Loc;
+
+ unsigned Offs;
+ if (SourceMgr->isInFileID(Loc, SourceMgr->getMainFileID(), &Offs) &&
+ Offs < Preamble.size()) {
+ SourceLocation FileLoc = SourceMgr->getLocForStartOfFile(PreambleID);
+ return FileLoc.getLocWithOffset(Offs);
+ }
+
+ return Loc;
+}
+
+void ASTUnit::PreambleData::countLines() const {
+ NumLines = 0;
+ if (empty())
+ return;
+
+ for (std::vector<char>::const_iterator
+ I = Buffer.begin(), E = Buffer.end(); I != E; ++I) {
+ if (*I == '\n')
+ ++NumLines;
+ }
+ if (Buffer.back() != '\n')
+ ++NumLines;
+}
+
+#ifndef NDEBUG
+ASTUnit::ConcurrencyState::ConcurrencyState() {
+ Mutex = new llvm::sys::MutexImpl(/*recursive=*/true);
+}
+
+ASTUnit::ConcurrencyState::~ConcurrencyState() {
+ delete static_cast<llvm::sys::MutexImpl *>(Mutex);
+}
+
+void ASTUnit::ConcurrencyState::start() {
+ bool acquired = static_cast<llvm::sys::MutexImpl *>(Mutex)->tryacquire();
+ assert(acquired && "Concurrent access to ASTUnit!");
+}
+
+void ASTUnit::ConcurrencyState::finish() {
+ static_cast<llvm::sys::MutexImpl *>(Mutex)->release();
+}
+
+#else // NDEBUG
+
+ASTUnit::ConcurrencyState::ConcurrencyState() {}
+ASTUnit::ConcurrencyState::~ConcurrencyState() {}
+void ASTUnit::ConcurrencyState::start() {}
+void ASTUnit::ConcurrencyState::finish() {}
+
+#endif
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index 556b1333c19b..39128fba3885 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -29,7 +29,7 @@ add_clang_library(clangFrontend
PrintPreprocessedOutput.cpp
TextDiagnosticBuffer.cpp
TextDiagnosticPrinter.cpp
- VerifyDiagnosticsClient.cpp
+ VerifyDiagnosticConsumer.cpp
Warnings.cpp
)
@@ -48,5 +48,6 @@ add_dependencies(clangFrontend
ClangDiagnosticFrontend
ClangDiagnosticLex
ClangDiagnosticSema
+ ClangDriverOptions
ClangDeclNodes
ClangStmtNodes)
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index 20b51893fcc2..8195445fe0e4 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -71,13 +71,13 @@ public:
bool isFile() const { return Kind == IsFE; }
- llvm::StringRef getString() const {
+ StringRef getString() const {
return Kind == IsFE ? FE->getName() : Path;
}
unsigned getKind() const { return (unsigned) Kind; }
- void EmitData(llvm::raw_ostream& Out) {
+ void EmitData(raw_ostream& Out) {
switch (Kind) {
case IsFE:
// Emit stat information.
@@ -119,7 +119,7 @@ public:
}
static std::pair<unsigned,unsigned>
- EmitKeyDataLength(llvm::raw_ostream& Out, PTHEntryKeyVariant V,
+ EmitKeyDataLength(raw_ostream& Out, PTHEntryKeyVariant V,
const PTHEntry& E) {
unsigned n = V.getString().size() + 1 + 1;
@@ -131,14 +131,14 @@ public:
return std::make_pair(n, m);
}
- static void EmitKey(llvm::raw_ostream& Out, PTHEntryKeyVariant V, unsigned n){
+ static void EmitKey(raw_ostream& Out, PTHEntryKeyVariant V, unsigned n){
// Emit the entry kind.
::Emit8(Out, (unsigned) V.getKind());
// Emit the string.
Out.write(V.getString().data(), n - 1);
}
- static void EmitData(llvm::raw_ostream& Out, PTHEntryKeyVariant V,
+ static void EmitData(raw_ostream& Out, PTHEntryKeyVariant V,
const PTHEntry& E, unsigned) {
@@ -197,7 +197,7 @@ class PTHWriter {
Out.write(Ptr, NumBytes);
}
- void EmitString(llvm::StringRef V) {
+ void EmitString(StringRef V) {
::Emit16(Out, V.size());
EmitBuf(V.data(), V.size());
}
@@ -247,7 +247,7 @@ void PTHWriter::EmitToken(const Token& T) {
} else {
// We cache *un-cleaned* spellings. This gives us 100% fidelity with the
// source code.
- llvm::StringRef s(T.getLiteralData(), T.getLength());
+ StringRef s(T.getLiteralData(), T.getLength());
// Get the string entry.
llvm::StringMapEntry<OffsetOpt> *E = &CachedStrs.GetOrCreateValue(s);
@@ -584,20 +584,20 @@ public:
}
static std::pair<unsigned,unsigned>
- EmitKeyDataLength(llvm::raw_ostream& Out, const PTHIdKey* key, uint32_t) {
+ EmitKeyDataLength(raw_ostream& Out, const PTHIdKey* key, uint32_t) {
unsigned n = key->II->getLength() + 1;
::Emit16(Out, n);
return std::make_pair(n, sizeof(uint32_t));
}
- static void EmitKey(llvm::raw_ostream& Out, PTHIdKey* key, unsigned n) {
+ static void EmitKey(raw_ostream& Out, PTHIdKey* key, unsigned n) {
// Record the location of the key data. This is used when generating
// the mapping from persistent IDs to strings.
key->FileOffset = Out.tell();
Out.write(key->II->getNameStart(), n);
}
- static void EmitData(llvm::raw_ostream& Out, PTHIdKey*, uint32_t pID,
+ static void EmitData(raw_ostream& Out, PTHIdKey*, uint32_t pID,
unsigned) {
::Emit32(Out, pID);
}
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index c58e3af5089b..55264870b8b5 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -19,12 +19,13 @@
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PTHManager.h"
-#include "clang/Frontend/ChainedDiagnosticClient.h"
+#include "clang/Frontend/ChainedDiagnosticConsumer.h"
#include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/LogDiagnosticPrinter.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "clang/Frontend/VerifyDiagnosticsClient.h"
+#include "clang/Frontend/VerifyDiagnosticConsumer.h"
#include "clang/Frontend/Utils.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Sema/CodeCompleteConsumer.h"
@@ -38,11 +39,25 @@
#include "llvm/Support/Program.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/system_error.h"
+#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Config/config.h"
+
+// Support for FileLockManager
+#include <fstream>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if LLVM_ON_WIN32
+#include <windows.h>
+#endif
+#if LLVM_ON_UNIX
+#include <unistd.h>
+#endif
+
using namespace clang;
CompilerInstance::CompilerInstance()
- : Invocation(new CompilerInvocation()) {
+ : Invocation(new CompilerInvocation()), ModuleManager(0) {
}
CompilerInstance::~CompilerInstance() {
@@ -52,7 +67,7 @@ void CompilerInstance::setInvocation(CompilerInvocation *Value) {
Invocation = Value;
}
-void CompilerInstance::setDiagnostics(Diagnostic *Value) {
+void CompilerInstance::setDiagnostics(DiagnosticsEngine *Value) {
Diagnostics = Value;
}
@@ -64,7 +79,7 @@ void CompilerInstance::setFileManager(FileManager *Value) {
FileMgr = Value;
}
-void CompilerInstance::setSourceManager(SourceManager *Value) {
+void CompilerInstance::setSourceManager(SourceManager *Value) {
SourceMgr = Value;
}
@@ -87,9 +102,9 @@ void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
// Diagnostics
static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
unsigned argc, const char* const *argv,
- Diagnostic &Diags) {
+ DiagnosticsEngine &Diags) {
std::string ErrorInfo;
- llvm::OwningPtr<llvm::raw_ostream> OS(
+ llvm::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)
@@ -103,17 +118,17 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
(*OS) << '\n';
// Chain in a diagnostic client which will log the diagnostics.
- DiagnosticClient *Logger =
+ DiagnosticConsumer *Logger =
new TextDiagnosticPrinter(*OS.take(), DiagOpts, /*OwnsOutputStream=*/true);
- Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger));
+ Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), Logger));
}
static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts,
const CodeGenOptions *CodeGenOpts,
- Diagnostic &Diags) {
+ DiagnosticsEngine &Diags) {
std::string ErrorInfo;
bool OwnsStream = false;
- llvm::raw_ostream *OS = &llvm::errs();
+ raw_ostream *OS = &llvm::errs();
if (DiagOpts.DiagnosticLogFile != "-") {
// Create the output stream.
llvm::raw_fd_ostream *FileOS(
@@ -135,38 +150,47 @@ static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts,
OwnsStream);
if (CodeGenOpts)
Logger->setDwarfDebugFlags(CodeGenOpts->DwarfDebugFlags);
- Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger));
+ Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), Logger));
}
void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv,
- DiagnosticClient *Client) {
+ DiagnosticConsumer *Client,
+ bool ShouldOwnClient,
+ bool ShouldCloneClient) {
Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv, Client,
+ ShouldOwnClient, ShouldCloneClient,
&getCodeGenOpts());
}
-llvm::IntrusiveRefCntPtr<Diagnostic>
+llvm::IntrusiveRefCntPtr<DiagnosticsEngine>
CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
int Argc, const char* const *Argv,
- DiagnosticClient *Client,
+ DiagnosticConsumer *Client,
+ bool ShouldOwnClient,
+ bool ShouldCloneClient,
const CodeGenOptions *CodeGenOpts) {
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic(DiagID));
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine>
+ Diags(new DiagnosticsEngine(DiagID));
// Create the diagnostic client for reporting errors or for
// implementing -verify.
- if (Client)
- Diags->setClient(Client);
- else
+ if (Client) {
+ if (ShouldCloneClient)
+ Diags->setClient(Client->clone(*Diags), ShouldOwnClient);
+ else
+ Diags->setClient(Client, ShouldOwnClient);
+ } else
Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts));
// Chain in -verify checker, if requested.
if (Opts.VerifyDiagnostics)
- Diags->setClient(new VerifyDiagnosticsClient(*Diags, Diags->takeClient()));
+ Diags->setClient(new VerifyDiagnosticConsumer(*Diags));
// Chain in -diagnostic-log-file dumper, if requested.
if (!Opts.DiagnosticLogFile.empty())
SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags);
-
+
if (!Opts.DumpBuildInformation.empty())
SetUpBuildDumpLog(Opts, Argc, Argv, *Diags);
@@ -191,49 +215,47 @@ void CompilerInstance::createSourceManager(FileManager &FileMgr) {
// Preprocessor
void CompilerInstance::createPreprocessor() {
- PP = createPreprocessor(getDiagnostics(), getLangOpts(),
- getPreprocessorOpts(), getHeaderSearchOpts(),
- getDependencyOutputOpts(), getTarget(),
- getFrontendOpts(), getSourceManager(),
- getFileManager());
-}
-
-Preprocessor *
-CompilerInstance::createPreprocessor(Diagnostic &Diags,
- const LangOptions &LangInfo,
- const PreprocessorOptions &PPOpts,
- const HeaderSearchOptions &HSOpts,
- const DependencyOutputOptions &DepOpts,
- const TargetInfo &Target,
- const FrontendOptions &FEOpts,
- SourceManager &SourceMgr,
- FileManager &FileMgr) {
+ const PreprocessorOptions &PPOpts = getPreprocessorOpts();
+
// Create a PTH manager if we are using some form of a token cache.
PTHManager *PTHMgr = 0;
if (!PPOpts.TokenCache.empty())
- PTHMgr = PTHManager::Create(PPOpts.TokenCache, Diags);
+ PTHMgr = PTHManager::Create(PPOpts.TokenCache, getDiagnostics());
// Create the Preprocessor.
- HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr);
- Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target,
- SourceMgr, *HeaderInfo, PTHMgr,
- /*OwnsHeaderSearch=*/true);
+ HeaderSearch *HeaderInfo = new HeaderSearch(getFileManager());
+ PP = new Preprocessor(getDiagnostics(), getLangOpts(), &getTarget(),
+ getSourceManager(), *HeaderInfo, *this, PTHMgr,
+ /*OwnsHeaderSearch=*/true);
// Note that this is different then passing PTHMgr to Preprocessor's ctor.
// That argument is used as the IdentifierInfoLookup argument to
// IdentifierTable's ctor.
if (PTHMgr) {
- PTHMgr->setPreprocessor(PP);
+ PTHMgr->setPreprocessor(&*PP);
PP->setPTHManager(PTHMgr);
}
if (PPOpts.DetailedRecord)
PP->createPreprocessingRecord(
- PPOpts.DetailedRecordIncludesNestedMacroExpansions);
-
- InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts);
+ PPOpts.DetailedRecordIncludesNestedMacroExpansions);
+
+ InitializePreprocessor(*PP, PPOpts, getHeaderSearchOpts(), getFrontendOpts());
+
+ // Set up the module path, including the hash for the
+ // module-creation options.
+ llvm::SmallString<256> SpecificModuleCache(
+ getHeaderSearchOpts().ModuleCachePath);
+ if (!getHeaderSearchOpts().DisableModuleHash)
+ llvm::sys::path::append(SpecificModuleCache,
+ getInvocation().getModuleHash());
+ PP->getHeaderSearchInfo().configureModules(SpecificModuleCache,
+ getPreprocessorOpts().ModuleBuildPath.empty()
+ ? std::string()
+ : getPreprocessorOpts().ModuleBuildPath.back());
// Handle generating dependencies, if requested.
+ const DependencyOutputOptions &DepOpts = getDependencyOutputOpts();
if (!DepOpts.OutputFile.empty())
AttachDependencyFileGen(*PP, DepOpts);
@@ -241,14 +263,12 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
if (DepOpts.ShowHeaderIncludes)
AttachHeaderIncludeGen(*PP);
if (!DepOpts.HeaderIncludeOutputFile.empty()) {
- llvm::StringRef OutputPath = DepOpts.HeaderIncludeOutputFile;
+ StringRef OutputPath = DepOpts.HeaderIncludeOutputFile;
if (OutputPath == "-")
OutputPath = "";
AttachHeaderIncludeGen(*PP, /*ShowAllHeaders=*/true, OutputPath,
/*ShowDepth=*/false);
}
-
- return PP;
}
// ASTContext
@@ -256,30 +276,31 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
void CompilerInstance::createASTContext() {
Preprocessor &PP = getPreprocessor();
Context = new ASTContext(getLangOpts(), PP.getSourceManager(),
- getTarget(), PP.getIdentifierTable(),
+ &getTarget(), PP.getIdentifierTable(),
PP.getSelectorTable(), PP.getBuiltinInfo(),
/*size_reserve=*/ 0);
}
// ExternalASTSource
-void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path,
+void CompilerInstance::createPCHExternalASTSource(StringRef Path,
bool DisablePCHValidation,
bool DisableStatCache,
void *DeserializationListener){
llvm::OwningPtr<ExternalASTSource> Source;
bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;
Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot,
- DisablePCHValidation,
+ DisablePCHValidation,
DisableStatCache,
getPreprocessor(), getASTContext(),
DeserializationListener,
Preamble));
+ ModuleManager = static_cast<ASTReader*>(Source.get());
getASTContext().setExternalSource(Source);
}
ExternalASTSource *
-CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path,
+CompilerInstance::createPCHExternalASTSource(StringRef Path,
const std::string &Sysroot,
bool DisablePCHValidation,
bool DisableStatCache,
@@ -288,14 +309,15 @@ CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path,
void *DeserializationListener,
bool Preamble) {
llvm::OwningPtr<ASTReader> Reader;
- Reader.reset(new ASTReader(PP, &Context,
- Sysroot.empty() ? 0 : Sysroot.c_str(),
+ Reader.reset(new ASTReader(PP, Context,
+ Sysroot.empty() ? "" : Sysroot.c_str(),
DisablePCHValidation, DisableStatCache));
Reader->setDeserializationListener(
static_cast<ASTDeserializationListener *>(DeserializationListener));
switch (Reader->ReadAST(Path,
- Preamble ? ASTReader::Preamble : ASTReader::PCH)) {
+ Preamble ? serialization::MK_Preamble
+ : serialization::MK_PCH)) {
case ASTReader::Success:
// Set the predefines buffer as suggested by the PCH reader. Typically, the
// predefines buffer will be empty.
@@ -316,7 +338,7 @@ CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path,
// Code Completion
-static bool EnableCodeCompletion(Preprocessor &PP,
+static bool EnableCodeCompletion(Preprocessor &PP,
const std::string &Filename,
unsigned Line,
unsigned Column) {
@@ -371,19 +393,19 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP,
bool ShowMacros,
bool ShowCodePatterns,
bool ShowGlobals,
- llvm::raw_ostream &OS) {
+ raw_ostream &OS) {
if (EnableCodeCompletion(PP, Filename, Line, Column))
return 0;
// Set up the creation routine for code-completion.
- return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns,
+ return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns,
ShowGlobals, OS);
}
-void CompilerInstance::createSema(bool CompleteTranslationUnit,
+void CompilerInstance::createSema(TranslationUnitKind TUKind,
CodeCompleteConsumer *CompletionConsumer) {
TheSema.reset(new Sema(getPreprocessor(), getASTContext(), getASTConsumer(),
- CompleteTranslationUnit, CompletionConsumer));
+ TUKind, CompletionConsumer));
}
// Output Files
@@ -418,28 +440,30 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) {
}
} else if (!it->Filename.empty() && EraseFiles)
llvm::sys::Path(it->Filename).eraseFromDisk();
-
+
}
OutputFiles.clear();
}
llvm::raw_fd_ostream *
CompilerInstance::createDefaultOutputFile(bool Binary,
- llvm::StringRef InFile,
- llvm::StringRef Extension) {
+ StringRef InFile,
+ StringRef Extension) {
return createOutputFile(getFrontendOpts().OutputFile, Binary,
/*RemoveFileOnSignal=*/true, InFile, Extension);
}
llvm::raw_fd_ostream *
-CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
+CompilerInstance::createOutputFile(StringRef OutputPath,
bool Binary, bool RemoveFileOnSignal,
- llvm::StringRef InFile,
- llvm::StringRef Extension) {
+ StringRef InFile,
+ StringRef Extension,
+ bool UseTemporary) {
std::string Error, OutputPathName, TempPathName;
llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary,
RemoveFileOnSignal,
InFile, Extension,
+ UseTemporary,
&OutputPathName,
&TempPathName);
if (!OS) {
@@ -457,12 +481,13 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
}
llvm::raw_fd_ostream *
-CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
+CompilerInstance::createOutputFile(StringRef OutputPath,
std::string &Error,
bool Binary,
bool RemoveFileOnSignal,
- llvm::StringRef InFile,
- llvm::StringRef Extension,
+ StringRef InFile,
+ StringRef Extension,
+ bool UseTemporary,
std::string *ResultPathName,
std::string *TempPathName) {
std::string OutFile, TempFile;
@@ -478,8 +503,11 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
} else {
OutFile = "-";
}
-
- if (OutFile != "-") {
+
+ llvm::OwningPtr<llvm::raw_fd_ostream> OS;
+ std::string OSFile;
+
+ if (UseTemporary && OutFile != "-") {
llvm::sys::Path OutPath(OutFile);
// Only create the temporary if we can actually write to OutPath, otherwise
// we want to fail early.
@@ -487,21 +515,26 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
if ((llvm::sys::fs::exists(OutPath.str(), Exists) || !Exists) ||
(OutPath.isRegularFile() && OutPath.canWrite())) {
// Create a temporary file.
- llvm::sys::Path TempPath(OutFile);
- if (!TempPath.createTemporaryFileOnDisk())
- TempFile = TempPath.str();
+ llvm::SmallString<128> TempPath;
+ TempPath = OutFile;
+ TempPath += "-%%%%%%%%";
+ int fd;
+ if (llvm::sys::fs::unique_file(TempPath.str(), fd, TempPath,
+ /*makeAbsolute=*/false) == llvm::errc::success) {
+ OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true));
+ OSFile = TempFile = TempPath.str();
+ }
}
}
- std::string OSFile = OutFile;
- if (!TempFile.empty())
- OSFile = TempFile;
-
- llvm::OwningPtr<llvm::raw_fd_ostream> OS(
- new llvm::raw_fd_ostream(OSFile.c_str(), Error,
- (Binary ? llvm::raw_fd_ostream::F_Binary : 0)));
- if (!Error.empty())
- return 0;
+ if (!OS) {
+ OSFile = OutFile;
+ OS.reset(
+ new llvm::raw_fd_ostream(OSFile.c_str(), Error,
+ (Binary ? llvm::raw_fd_ostream::F_Binary : 0)));
+ if (!Error.empty())
+ return 0;
+ }
// Make sure the out stream file gets removed if we crash.
if (RemoveFileOnSignal)
@@ -517,21 +550,18 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
// Initialization Utilities
-bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile) {
+bool CompilerInstance::InitializeSourceManager(StringRef InputFile) {
return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(),
getSourceManager(), getFrontendOpts());
}
-bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile,
- Diagnostic &Diags,
+bool CompilerInstance::InitializeSourceManager(StringRef InputFile,
+ DiagnosticsEngine &Diags,
FileManager &FileMgr,
SourceManager &SourceMgr,
const FrontendOptions &Opts) {
- // Figure out where to get and map in the main file, unless it's already
- // been created (e.g., by a precompiled preamble).
- if (!SourceMgr.getMainFileID().isInvalid()) {
- // Do nothing: the main file has already been set.
- } else if (InputFile != "-") {
+ // Figure out where to get and map in the main file.
+ if (InputFile != "-") {
const FileEntry *File = FileMgr.getFile(InputFile);
if (!File) {
Diags.Report(diag::err_fe_error_reading) << InputFile;
@@ -565,7 +595,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
// FIXME: Take this as an argument, once all the APIs we used have moved to
// taking it as an input instead of hard-coding llvm::errs.
- llvm::raw_ostream &OS = llvm::errs();
+ raw_ostream &OS = llvm::errs();
// Create the target instance.
setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts()));
@@ -589,7 +619,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
if (getFrontendOpts().ShowStats)
llvm::EnableStatistics();
-
+
for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) {
const std::string &InFile = getFrontendOpts().Inputs[i].second;
@@ -608,7 +638,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
// Get the total number of warnings/errors from the client.
unsigned NumWarnings = getDiagnostics().getClient()->getNumWarnings();
unsigned NumErrors = getDiagnostics().getClient()->getNumErrors();
-
+
if (NumWarnings)
OS << NumWarnings << " warning" << (NumWarnings == 1 ? "" : "s");
if (NumWarnings && NumErrors)
@@ -627,4 +657,456 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
return !getDiagnostics().getClient()->getNumErrors();
}
+/// \brief Determine the appropriate source input kind based on language
+/// options.
+static InputKind getSourceInputKindFromOptions(const LangOptions &LangOpts) {
+ if (LangOpts.OpenCL)
+ return IK_OpenCL;
+ if (LangOpts.CUDA)
+ return IK_CUDA;
+ if (LangOpts.ObjC1)
+ return LangOpts.CPlusPlus? IK_ObjCXX : IK_ObjC;
+ return LangOpts.CPlusPlus? IK_CXX : IK_C;
+}
+
+namespace {
+ struct CompileModuleData {
+ CompilerInstance &Instance;
+ GeneratePCHAction &CreateModuleAction;
+ };
+}
+
+/// \brief Helper function that executes the module-generating action under
+/// a crash recovery context.
+static void doCompileModule(void *UserData) {
+ CompileModuleData &Data = *reinterpret_cast<CompileModuleData *>(UserData);
+ Data.Instance.ExecuteAction(Data.CreateModuleAction);
+}
+
+namespace {
+ /// \brief Class that manages the creation of a lock file to aid
+ /// implicit coordination between different processes.
+ ///
+ /// The implicit coordination works by creating a ".lock" file alongside
+ /// the file that we're coordinating for, using the atomicity of the file
+ /// system to ensure that only a single process can create that ".lock" file.
+ /// When the lock file is removed, the owning process has finished the
+ /// operation.
+ class LockFileManager {
+ public:
+ /// \brief Describes the state of a lock file.
+ enum LockFileState {
+ /// \brief The lock file has been created and is owned by this instance
+ /// of the object.
+ LFS_Owned,
+ /// \brief The lock file already exists and is owned by some other
+ /// instance.
+ LFS_Shared,
+ /// \brief An error occurred while trying to create or find the lock
+ /// file.
+ LFS_Error
+ };
+
+ private:
+ llvm::SmallString<128> LockFileName;
+ llvm::SmallString<128> UniqueLockFileName;
+
+ llvm::Optional<std::pair<std::string, int> > Owner;
+ llvm::Optional<llvm::error_code> Error;
+
+ LockFileManager(const LockFileManager &);
+ LockFileManager &operator=(const LockFileManager &);
+
+ static llvm::Optional<std::pair<std::string, int> >
+ readLockFile(StringRef LockFileName);
+
+ static bool processStillExecuting(StringRef Hostname, int PID);
+
+ public:
+
+ LockFileManager(StringRef FileName);
+ ~LockFileManager();
+
+ /// \brief Determine the state of the lock file.
+ LockFileState getState() const;
+
+ operator LockFileState() const { return getState(); }
+
+ /// \brief For a shared lock, wait until the owner releases the lock.
+ void waitForUnlock();
+ };
+}
+
+/// \brief Attempt to read the lock file with the given name, if it exists.
+///
+/// \param LockFileName The name of the lock file to read.
+///
+/// \returns The process ID of the process that owns this lock file
+llvm::Optional<std::pair<std::string, int> >
+LockFileManager::readLockFile(StringRef LockFileName) {
+ // Check whether the lock file exists. If not, clearly there's nothing
+ // to read, so we just return.
+ bool Exists = false;
+ if (llvm::sys::fs::exists(LockFileName, Exists) || !Exists)
+ return llvm::Optional<std::pair<std::string, int> >();
+
+ // Read the owning host and PID out of the lock file. If it appears that the
+ // owning process is dead, the lock file is invalid.
+ int PID = 0;
+ std::string Hostname;
+ std::ifstream Input(LockFileName.str().c_str());
+ if (Input >> Hostname >> PID && PID > 0 &&
+ processStillExecuting(Hostname, PID))
+ return std::make_pair(Hostname, PID);
+
+ // Delete the lock file. It's invalid anyway.
+ bool Existed;
+ llvm::sys::fs::remove(LockFileName, Existed);
+ return llvm::Optional<std::pair<std::string, int> >();
+}
+
+bool LockFileManager::processStillExecuting(StringRef Hostname, int PID) {
+#if LLVM_ON_UNIX
+ char MyHostname[256];
+ MyHostname[255] = 0;
+ MyHostname[0] = 0;
+ gethostname(MyHostname, 255);
+ // Check whether the process is dead. If so, we're done.
+ if (MyHostname == Hostname && getsid(PID) == -1 && errno == ESRCH)
+ return false;
+#endif
+
+ return true;
+}
+
+LockFileManager::LockFileManager(StringRef FileName)
+{
+ LockFileName = FileName;
+ LockFileName += ".lock";
+
+ // If the lock file already exists, don't bother to try to create our own
+ // lock file; it won't work anyway. Just figure out who owns this lock file.
+ if ((Owner = readLockFile(LockFileName)))
+ return;
+
+ // Create a lock file that is unique to this instance.
+ UniqueLockFileName = LockFileName;
+ UniqueLockFileName += "-%%%%%%%%";
+ int UniqueLockFileID;
+ if (llvm::error_code EC
+ = llvm::sys::fs::unique_file(UniqueLockFileName.str(),
+ UniqueLockFileID,
+ UniqueLockFileName,
+ /*makeAbsolute=*/false)) {
+ Error = EC;
+ return;
+ }
+
+ // Write our process ID to our unique lock file.
+ {
+ llvm::raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true);
+
+#if LLVM_ON_UNIX
+ // FIXME: move getpid() call into LLVM
+ char hostname[256];
+ hostname[255] = 0;
+ hostname[0] = 0;
+ gethostname(hostname, 255);
+ Out << hostname << ' ' << getpid();
+#else
+ Out << "localhost 1";
+#endif
+ Out.close();
+
+ if (Out.has_error()) {
+ // We failed to write out PID, so make up an excuse, remove the
+ // unique lock file, and fail.
+ Error = llvm::make_error_code(llvm::errc::no_space_on_device);
+ bool Existed;
+ llvm::sys::fs::remove(UniqueLockFileName.c_str(), Existed);
+ return;
+ }
+ }
+
+ // Create a hard link from the lock file name. If this succeeds, we're done.
+ llvm::error_code EC
+ = llvm::sys::fs::create_hard_link(UniqueLockFileName.str(),
+ LockFileName.str());
+ if (EC == llvm::errc::success)
+ return;
+
+ // Creating the hard link failed.
+
+#ifdef LLVM_ON_UNIX
+ // The creation of the hard link may appear to fail, but if stat'ing the
+ // unique file returns a link count of 2, then we can still declare success.
+ struct stat StatBuf;
+ if (stat(UniqueLockFileName.c_str(), &StatBuf) == 0 &&
+ StatBuf.st_nlink == 2)
+ return;
+#endif
+
+ // Someone else managed to create the lock file first. Wipe out our unique
+ // lock file (it's useless now) and read the process ID from the lock file.
+ bool Existed;
+ llvm::sys::fs::remove(UniqueLockFileName.str(), Existed);
+ if ((Owner = readLockFile(LockFileName)))
+ return;
+
+ // There is a lock file that nobody owns; try to clean it up and report
+ // an error.
+ llvm::sys::fs::remove(LockFileName.str(), Existed);
+ Error = EC;
+}
+
+LockFileManager::LockFileState LockFileManager::getState() const {
+ if (Owner)
+ return LFS_Shared;
+
+ if (Error)
+ return LFS_Error;
+
+ return LFS_Owned;
+}
+
+LockFileManager::~LockFileManager() {
+ if (getState() != LFS_Owned)
+ return;
+
+ // Since we own the lock, remove the lock file and our own unique lock file.
+ bool Existed;
+ llvm::sys::fs::remove(LockFileName.str(), Existed);
+ llvm::sys::fs::remove(UniqueLockFileName.str(), Existed);
+}
+
+void LockFileManager::waitForUnlock() {
+ if (getState() != LFS_Shared)
+ return;
+
+#if LLVM_ON_WIN32
+ unsigned long Interval = 1;
+#else
+ struct timespec Interval;
+ Interval.tv_sec = 0;
+ Interval.tv_nsec = 1000000;
+#endif
+ // Don't wait more than an hour for the file to appear.
+ const unsigned MaxSeconds = 3600;
+ do {
+ // Sleep for the designated interval, to allow the owning process time to
+ // finish up and
+ // FIXME: Should we hook in to system APIs to get a notification when the
+ // lock file is deleted?
+#if LLVM_ON_WIN32
+ Sleep(Interval);
+#else
+ nanosleep(&Interval, NULL);
+#endif
+ // If the file no longer exists, we're done.
+ bool Exists = false;
+ if (!llvm::sys::fs::exists(LockFileName.str(), Exists) && !Exists)
+ return;
+
+ if (!processStillExecuting((*Owner).first, (*Owner).second))
+ return;
+
+ // Exponentially increase the time we wait for the lock to be removed.
+#if LLVM_ON_WIN32
+ Interval *= 2;
+#else
+ Interval.tv_sec *= 2;
+ Interval.tv_nsec *= 2;
+ if (Interval.tv_nsec >= 1000000000) {
+ ++Interval.tv_sec;
+ Interval.tv_nsec -= 1000000000;
+ }
+#endif
+ } while (
+#if LLVM_ON_WIN32
+ Interval < MaxSeconds * 1000
+#else
+ Interval.tv_sec < (time_t)MaxSeconds
+#endif
+ );
+
+ // Give up.
+}
+
+/// \brief Compile a module file for the given module name with the given
+/// umbrella header, using the options provided by the importing compiler
+/// instance.
+static void compileModule(CompilerInstance &ImportingInstance,
+ StringRef ModuleName,
+ StringRef ModuleFileName,
+ StringRef UmbrellaHeader) {
+ LockFileManager Locked(ModuleFileName);
+ switch (Locked) {
+ case LockFileManager::LFS_Error:
+ return;
+
+ case LockFileManager::LFS_Owned:
+ // We're responsible for building the module ourselves. Do so below.
+ break;
+
+ case LockFileManager::LFS_Shared:
+ // Someone else is responsible for building the module. Wait for them to
+ // finish.
+ Locked.waitForUnlock();
+ break;
+ }
+
+ // Construct a compiler invocation for creating this module.
+ llvm::IntrusiveRefCntPtr<CompilerInvocation> Invocation
+ (new CompilerInvocation(ImportingInstance.getInvocation()));
+
+ // For any options that aren't intended to affect how a module is built,
+ // reset them to their default values.
+ Invocation->getLangOpts().resetNonModularOptions();
+ Invocation->getPreprocessorOpts().resetNonModularOptions();
+
+ // Note that this module is part of the module build path, so that we
+ // can detect cycles in the module graph.
+ Invocation->getPreprocessorOpts().ModuleBuildPath.push_back(ModuleName);
+
+ // Set up the inputs/outputs so that we build the module from its umbrella
+ // header.
+ FrontendOptions &FrontendOpts = Invocation->getFrontendOpts();
+ FrontendOpts.OutputFile = ModuleFileName.str();
+ FrontendOpts.DisableFree = false;
+ FrontendOpts.Inputs.clear();
+ FrontendOpts.Inputs.push_back(
+ std::make_pair(getSourceInputKindFromOptions(Invocation->getLangOpts()),
+ UmbrellaHeader));
+
+ Invocation->getDiagnosticOpts().VerifyDiagnostics = 0;
+
+
+ assert(ImportingInstance.getInvocation().getModuleHash() ==
+ Invocation->getModuleHash() && "Module hash mismatch!");
+
+ // Construct a compiler instance that will be used to actually create the
+ // module.
+ CompilerInstance Instance;
+ Instance.setInvocation(&*Invocation);
+ Instance.createDiagnostics(/*argc=*/0, /*argv=*/0,
+ &ImportingInstance.getDiagnosticClient(),
+ /*ShouldOwnClient=*/true,
+ /*ShouldCloneClient=*/true);
+
+ // Construct a module-generating action.
+ GeneratePCHAction CreateModuleAction(true);
+
+ // Execute the action to actually build the module in-place. Use a separate
+ // thread so that we get a stack large enough.
+ const unsigned ThreadStackSize = 8 << 20;
+ llvm::CrashRecoveryContext CRC;
+ CompileModuleData Data = { Instance, CreateModuleAction };
+ CRC.RunSafelyOnThread(&doCompileModule, &Data, ThreadStackSize);
+}
+
+ModuleKey CompilerInstance::loadModule(SourceLocation ImportLoc,
+ IdentifierInfo &ModuleName,
+ SourceLocation ModuleNameLoc) {
+ // Determine what file we're searching from.
+ SourceManager &SourceMgr = getSourceManager();
+ SourceLocation ExpandedImportLoc = SourceMgr.getExpansionLoc(ImportLoc);
+ const FileEntry *CurFile
+ = SourceMgr.getFileEntryForID(SourceMgr.getFileID(ExpandedImportLoc));
+ if (!CurFile)
+ CurFile = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
+
+ // Search for a module with the given name.
+ std::string UmbrellaHeader;
+ std::string ModuleFileName;
+ const FileEntry *ModuleFile
+ = PP->getHeaderSearchInfo().lookupModule(ModuleName.getName(),
+ &ModuleFileName,
+ &UmbrellaHeader);
+
+ bool BuildingModule = false;
+ if (!ModuleFile && !UmbrellaHeader.empty()) {
+ // We didn't find the module, but there is an umbrella header that
+ // can be used to create the module file. Create a separate compilation
+ // module to do so.
+
+ // 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.getName());
+ if (Pos != ModuleBuildPath.end()) {
+ llvm::SmallString<256> CyclePath;
+ for (; Pos != ModuleBuildPath.end(); ++Pos) {
+ CyclePath += *Pos;
+ CyclePath += " -> ";
+ }
+ CyclePath += ModuleName.getName();
+
+ getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle)
+ << ModuleName.getName() << CyclePath;
+ return 0;
+ }
+
+ getDiagnostics().Report(ModuleNameLoc, diag::warn_module_build)
+ << ModuleName.getName();
+ BuildingModule = true;
+ compileModule(*this, ModuleName.getName(), ModuleFileName, UmbrellaHeader);
+ ModuleFile = PP->getHeaderSearchInfo().lookupModule(ModuleName.getName());
+ }
+
+ if (!ModuleFile) {
+ getDiagnostics().Report(ModuleNameLoc,
+ BuildingModule? diag::err_module_not_built
+ : diag::err_module_not_found)
+ << ModuleName.getName()
+ << SourceRange(ImportLoc, ModuleNameLoc);
+ return 0;
+ }
+
+ // If we don't already have an ASTReader, create one now.
+ if (!ModuleManager) {
+ if (!hasASTContext())
+ createASTContext();
+
+ std::string Sysroot = getHeaderSearchOpts().Sysroot;
+ const PreprocessorOptions &PPOpts = getPreprocessorOpts();
+ ModuleManager = new ASTReader(getPreprocessor(), *Context,
+ Sysroot.empty() ? "" : Sysroot.c_str(),
+ PPOpts.DisablePCHValidation,
+ PPOpts.DisableStatCache);
+ if (hasASTConsumer()) {
+ ModuleManager->setDeserializationListener(
+ getASTConsumer().GetASTDeserializationListener());
+ getASTContext().setASTMutationListener(
+ getASTConsumer().GetASTMutationListener());
+ }
+ llvm::OwningPtr<ExternalASTSource> Source;
+ Source.reset(ModuleManager);
+ getASTContext().setExternalSource(Source);
+ if (hasSema())
+ ModuleManager->InitializeSema(getSema());
+ if (hasASTConsumer())
+ ModuleManager->StartTranslationUnit(&getASTConsumer());
+ }
+
+ // Try to load the module we found.
+ switch (ModuleManager->ReadAST(ModuleFile->getName(),
+ serialization::MK_Module)) {
+ case ASTReader::Success:
+ break;
+
+ case ASTReader::IgnorePCH:
+ // FIXME: The ASTReader will already have complained, but can we showhorn
+ // that diagnostic information into a more useful form?
+ return 0;
+
+ case ASTReader::Failure:
+ // Already complained.
+ return 0;
+ }
+
+ // FIXME: The module file's FileEntry makes a poor key indeed!
+ return (ModuleKey)ModuleFile;
+}
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 06b72602fd18..1debf3b35318 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -60,6 +60,16 @@ static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) {
}
}
+static const char *getAnalysisPurgeModeName(AnalysisPurgeMode Kind) {
+ switch (Kind) {
+ default:
+ llvm_unreachable("Unknown analysis client!");
+#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \
+ case NAME: return CMDFLAG;
+#include "clang/Frontend/Analyses.def"
+ }
+}
+
//===----------------------------------------------------------------------===//
// Serialization (to args)
//===----------------------------------------------------------------------===//
@@ -68,7 +78,7 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
std::vector<std::string> &Res) {
if (Opts.ShowCheckerHelp)
Res.push_back("-analyzer-checker-help");
- if (Opts.AnalysisStoreOpt != BasicStoreModel) {
+ if (Opts.AnalysisStoreOpt != RegionStoreModel) {
Res.push_back("-analyzer-store");
Res.push_back(getAnalysisStoreName(Opts.AnalysisStoreOpt));
}
@@ -80,6 +90,10 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
Res.push_back("-analyzer-output");
Res.push_back(getAnalysisDiagClientName(Opts.AnalysisDiagOpt));
}
+ if (Opts.AnalysisPurgeOpt != PurgeStmt) {
+ Res.push_back("-analyzer-purge");
+ Res.push_back(getAnalysisPurgeModeName(Opts.AnalysisPurgeOpt));
+ }
if (!Opts.AnalyzeSpecificFunction.empty()) {
Res.push_back("-analyze-function");
Res.push_back(Opts.AnalyzeSpecificFunction);
@@ -92,8 +106,6 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
Res.push_back("-analyzer-opt-analyze-nested-blocks");
if (Opts.EagerlyAssume)
Res.push_back("-analyzer-eagerly-assume");
- if (!Opts.PurgeDead)
- Res.push_back("-analyzer-no-purge-dead");
if (Opts.TrimGraph)
Res.push_back("-trim-egraph");
if (Opts.VisualizeEGDot)
@@ -171,6 +183,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-mcode-model");
Res.push_back(Opts.CodeModel);
}
+ if (Opts.CUDAIsDevice)
+ Res.push_back("-fcuda-is-device");
if (!Opts.CXAAtExit)
Res.push_back("-fno-use-cxa-atexit");
if (Opts.CXXCtorDtorAliases)
@@ -207,6 +221,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-mregparm");
Res.push_back(llvm::utostr(Opts.NumRegisterParameters));
}
+ if (Opts.NoGlobalMerge)
+ Res.push_back("-mno-global-merge");
if (Opts.NoExecStack)
Res.push_back("-mnoexecstack");
if (Opts.RelaxAll)
@@ -361,7 +377,6 @@ static const char *getActionName(frontend::ActionKind Kind) {
case frontend::ASTDumpXML: return "-ast-dump-xml";
case frontend::ASTPrint: return "-ast-print";
case frontend::ASTView: return "-ast-view";
- case frontend::CreateModule: return "-create-module";
case frontend::DumpRawTokens: return "-dump-raw-tokens";
case frontend::DumpTokens: return "-dump-tokens";
case frontend::EmitAssembly: return "-S";
@@ -372,6 +387,7 @@ static const char *getActionName(frontend::ActionKind Kind) {
case frontend::EmitCodeGenOnly: return "-emit-codegen-only";
case frontend::EmitObj: return "-emit-obj";
case frontend::FixIt: return "-fixit";
+ case frontend::GenerateModule: return "-emit-module";
case frontend::GeneratePCH: return "-emit-pch";
case frontend::GeneratePTH: return "-emit-pth";
case frontend::InitOnly: return "-init-only";
@@ -404,8 +420,6 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-disable-free");
if (Opts.RelocatablePCH)
Res.push_back("-relocatable-pch");
- if (Opts.ChainedPCH)
- Res.push_back("-chained-pch");
if (Opts.ShowHelp)
Res.push_back("-help");
if (Opts.ShowMacrosInCodeCompletion)
@@ -439,6 +453,12 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-arcmt-migrate-directory");
Res.push_back(Opts.ARCMTMigrateDir);
}
+ if (!Opts.ARCMTMigrateReportOut.empty()) {
+ Res.push_back("-arcmt-migrate-report-output");
+ Res.push_back(Opts.ARCMTMigrateReportOut);
+ }
+ if (Opts.ARCMTMigrateEmitARCErrors)
+ Res.push_back("-arcmt-migrate-emit-errors");
bool NeedLang = false;
for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i)
@@ -491,10 +511,6 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-ast-merge");
Res.push_back(Opts.ASTMergeFiles[i]);
}
- for (unsigned i = 0, e = Opts.Modules.size(); i != e; ++i) {
- Res.push_back("-import-module");
- Res.push_back(Opts.Modules[i]);
- }
for (unsigned i = 0, e = Opts.LLVMArgs.size(); i != e; ++i) {
Res.push_back("-mllvm");
Res.push_back(Opts.LLVMArgs[i]);
@@ -514,17 +530,43 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
if (E.IsFramework && (E.Group != frontend::Angled || !E.IsUserSupplied))
llvm::report_fatal_error("Invalid option set!");
if (E.IsUserSupplied) {
- if (E.Group == frontend::After) {
+ switch (E.Group) {
+ case frontend::After:
Res.push_back("-idirafter");
- } else if (E.Group == frontend::Quoted) {
+ break;
+
+ case frontend::Quoted:
Res.push_back("-iquote");
- } else if (E.Group == frontend::System) {
+ break;
+
+ case frontend::System:
Res.push_back("-isystem");
- } else if (E.Group == frontend::CXXSystem) {
+ break;
+
+ case frontend::IndexHeaderMap:
+ Res.push_back("-index-header-map");
+ Res.push_back(E.IsFramework? "-F" : "-I");
+ break;
+
+ case frontend::CSystem:
+ Res.push_back("-c-isystem");
+ break;
+
+ case frontend::CXXSystem:
Res.push_back("-cxx-isystem");
- } else {
- assert(E.Group == frontend::Angled && "Invalid group!");
+ break;
+
+ case frontend::ObjCSystem:
+ Res.push_back("-objc-isystem");
+ break;
+
+ case frontend::ObjCXXSystem:
+ Res.push_back("-objcxx-isystem");
+ break;
+
+ case frontend::Angled:
Res.push_back(E.IsFramework ? "-F" : "-I");
+ break;
}
} else {
if (E.Group != frontend::Angled && E.Group != frontend::System)
@@ -535,32 +577,16 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
Res.push_back(E.Path);
}
- if (!Opts.EnvIncPath.empty()) {
- // FIXME: Provide an option for this, and move env detection to driver.
- llvm::report_fatal_error("Not yet implemented!");
- }
- if (!Opts.CEnvIncPath.empty()) {
- // FIXME: Provide an option for this, and move env detection to driver.
- llvm::report_fatal_error("Not yet implemented!");
- }
- if (!Opts.ObjCEnvIncPath.empty()) {
- // FIXME: Provide an option for this, and move env detection to driver.
- llvm::report_fatal_error("Not yet implemented!");
- }
- if (!Opts.CXXEnvIncPath.empty()) {
- // FIXME: Provide an option for this, and move env detection to driver.
- llvm::report_fatal_error("Not yet implemented!");
- }
- if (!Opts.ObjCXXEnvIncPath.empty()) {
- // FIXME: Provide an option for this, and move env detection to driver.
- llvm::report_fatal_error("Not yet implemented!");
- }
if (!Opts.ResourceDir.empty()) {
Res.push_back("-resource-dir");
Res.push_back(Opts.ResourceDir);
}
- if (!Opts.UseStandardIncludes)
- Res.push_back("-nostdinc");
+ if (!Opts.ModuleCachePath.empty()) {
+ Res.push_back("-fmodule-cache-path");
+ Res.push_back(Opts.ModuleCachePath);
+ }
+ if (!Opts.UseStandardSystemIncludes)
+ Res.push_back("-nostdsysteminc");
if (!Opts.UseStandardCXXIncludes)
Res.push_back("-nostdinc++");
if (Opts.UseLibcxx)
@@ -593,16 +619,14 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fno-gnu-keywords");
if (!Opts.GNUMode && Opts.GNUKeywords)
Res.push_back("-fgnu-keywords");
- if (Opts.Microsoft)
+ if (Opts.MicrosoftExt)
Res.push_back("-fms-extensions");
if (Opts.MSCVersion != 0)
Res.push_back("-fmsc-version=" + llvm::utostr(Opts.MSCVersion));
if (Opts.Borland)
Res.push_back("-fborland-extensions");
- if (Opts.ObjCNonFragileABI)
- Res.push_back("-fobjc-nonfragile-abi");
- if (Opts.ObjCNonFragileABI2)
- Res.push_back("-fobjc-nonfragile-abi");
+ if (!Opts.ObjCNonFragileABI)
+ Res.push_back("-fobjc-fragile-abi");
if (Opts.ObjCDefaultSynthProperties)
Res.push_back("-fobjc-default-synthesize-properties");
// NoInline is implicit.
@@ -648,6 +672,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-pthread");
if (Opts.Blocks)
Res.push_back("-fblocks");
+ if (Opts.BlocksRuntimeOptional)
+ Res.push_back("-fblocks-runtime-optional");
if (Opts.EmitAllDecls)
Res.push_back("-femit-all-decls");
if (Opts.MathErrno)
@@ -690,11 +716,11 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fshort-wchar");
if (!Opts.ElideConstructors)
Res.push_back("-fno-elide-constructors");
- if (Opts.getGCMode() != LangOptions::NonGC) {
- if (Opts.getGCMode() == LangOptions::HybridGC) {
+ if (Opts.getGC() != LangOptions::NonGC) {
+ if (Opts.getGC() == LangOptions::HybridGC) {
Res.push_back("-fobjc-gc");
} else {
- assert(Opts.getGCMode() == LangOptions::GCOnly && "Invalid GC mode!");
+ assert(Opts.getGC() == LangOptions::GCOnly && "Invalid GC mode!");
Res.push_back("-fobjc-gc-only");
}
}
@@ -721,9 +747,9 @@ static void LangOptsToArgs(const LangOptions &Opts,
if (Opts.InlineVisibilityHidden)
Res.push_back("-fvisibility-inlines-hidden");
- if (Opts.getStackProtectorMode() != 0) {
+ if (Opts.getStackProtector() != 0) {
Res.push_back("-stack-protector");
- Res.push_back(llvm::utostr(Opts.getStackProtectorMode()));
+ Res.push_back(llvm::utostr(Opts.getStackProtector()));
}
if (Opts.InstantiationDepth != DefaultLangOpts.InstantiationDepth) {
Res.push_back("-ftemplate-depth");
@@ -858,7 +884,7 @@ using namespace clang::driver::cc1options;
//
static unsigned getOptimizationLevel(ArgList &Args, InputKind IK,
- Diagnostic &Diags) {
+ DiagnosticsEngine &Diags) {
unsigned DefaultOpt = 0;
if (IK == IK_OpenCL && !Args.hasArg(OPT_cl_opt_disable))
DefaultOpt = 2;
@@ -868,11 +894,11 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK,
}
static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
- Diagnostic &Diags) {
+ DiagnosticsEngine &Diags) {
using namespace cc1options;
if (Arg *A = Args.getLastArg(OPT_analyzer_store)) {
- llvm::StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue(Args);
AnalysisStores Value = llvm::StringSwitch<AnalysisStores>(Name)
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \
.Case(CMDFLAG, NAME##Model)
@@ -887,7 +913,7 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
}
if (Arg *A = Args.getLastArg(OPT_analyzer_constraints)) {
- llvm::StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue(Args);
AnalysisConstraints Value = llvm::StringSwitch<AnalysisConstraints>(Name)
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \
.Case(CMDFLAG, NAME##Model)
@@ -902,7 +928,7 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
}
if (Arg *A = Args.getLastArg(OPT_analyzer_output)) {
- llvm::StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue(Args);
AnalysisDiagClients Value = llvm::StringSwitch<AnalysisDiagClients>(Name)
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) \
.Case(CMDFLAG, PD_##NAME)
@@ -916,6 +942,21 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
Opts.AnalysisDiagOpt = Value;
}
+ if (Arg *A = Args.getLastArg(OPT_analyzer_purge)) {
+ StringRef Name = A->getValue(Args);
+ AnalysisPurgeMode Value = llvm::StringSwitch<AnalysisPurgeMode>(Name)
+#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \
+ .Case(CMDFLAG, NAME)
+#include "clang/Frontend/Analyses.def"
+ .Default(NumPurgeModes);
+ // FIXME: Error handling.
+ if (Value == NumPurgeModes)
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << Name;
+ else
+ Opts.AnalysisPurgeOpt = Value;
+ }
+
Opts.ShowCheckerHelp = Args.hasArg(OPT_analyzer_checker_help);
Opts.VisualizeEGDot = Args.hasArg(OPT_analyzer_viz_egraph_graphviz);
Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph);
@@ -923,7 +964,6 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress);
Opts.AnalyzeNestedBlocks =
Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks);
- Opts.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead);
Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume);
Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function);
Opts.UnoptimizedCFG = Args.hasArg(OPT_analysis_UnoptimizedCFG);
@@ -944,8 +984,8 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
bool enable = (A->getOption().getID() == OPT_analyzer_checker);
// We can have a list of comma separated checker names, e.g:
// '-analyzer-checker=cocoa,unix'
- llvm::StringRef checkerList = A->getValue(Args);
- llvm::SmallVector<llvm::StringRef, 4> checkers;
+ StringRef checkerList = A->getValue(Args);
+ SmallVector<StringRef, 4> checkers;
checkerList.split(checkers, ",");
for (unsigned i = 0, e = checkers.size(); i != e; ++i)
Opts.CheckersControlList.push_back(std::make_pair(checkers[i], enable));
@@ -953,7 +993,7 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
}
static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
- Diagnostic &Diags) {
+ DiagnosticsEngine &Diags) {
using namespace cc1options;
Opts.OptimizationLevel = getOptimizationLevel(Args, IK, Diags);
@@ -990,6 +1030,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions);
Opts.ObjCRuntimeHasARC = Args.hasArg(OPT_fobjc_runtime_has_arc);
Opts.ObjCRuntimeHasTerminate = Args.hasArg(OPT_fobjc_runtime_has_terminate);
+ Opts.CUDAIsDevice = Args.hasArg(OPT_fcuda_is_device);
Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit);
Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases);
Opts.CodeModel = Args.getLastArgValue(OPT_mcode_model);
@@ -1004,6 +1045,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss);
Opts.BackendOptions = Args.getAllArgValues(OPT_backend_option);
Opts.NumRegisterParameters = Args.getLastArgIntValue(OPT_mregparm, 0, Diags);
+ Opts.NoGlobalMerge = Args.hasArg(OPT_mno_global_merge);
Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer);
@@ -1028,7 +1070,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file);
if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) {
- llvm::StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue(Args);
unsigned Method = llvm::StringSwitch<unsigned>(Name)
.Case("legacy", CodeGenOptions::Legacy)
.Case("non-legacy", CodeGenOptions::NonLegacy)
@@ -1054,7 +1096,7 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
}
static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
- Diagnostic &Diags) {
+ DiagnosticsEngine &Diags) {
using namespace cc1options;
Opts.DiagnosticLogFile = Args.getLastArgValue(OPT_diagnostic_log_file);
Opts.IgnoreWarnings = Args.hasArg(OPT_w);
@@ -1078,18 +1120,18 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
if (A->getOption().matches(OPT_fdiagnostics_show_note_include_stack))
Opts.ShowNoteIncludeStack = true;
- llvm::StringRef ShowOverloads =
+ StringRef ShowOverloads =
Args.getLastArgValue(OPT_fshow_overloads_EQ, "all");
if (ShowOverloads == "best")
- Opts.ShowOverloads = Diagnostic::Ovl_Best;
+ Opts.ShowOverloads = DiagnosticsEngine::Ovl_Best;
else if (ShowOverloads == "all")
- Opts.ShowOverloads = Diagnostic::Ovl_All;
+ Opts.ShowOverloads = DiagnosticsEngine::Ovl_All;
else
Diags.Report(diag::err_drv_invalid_value)
<< Args.getLastArg(OPT_fshow_overloads_EQ)->getAsString(Args)
<< ShowOverloads;
- llvm::StringRef ShowCategory =
+ StringRef ShowCategory =
Args.getLastArgValue(OPT_fdiagnostics_show_category, "none");
if (ShowCategory == "none")
Opts.ShowCategories = 0;
@@ -1102,7 +1144,7 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
<< Args.getLastArg(OPT_fdiagnostics_show_category)->getAsString(Args)
<< ShowCategory;
- llvm::StringRef Format =
+ StringRef Format =
Args.getLastArgValue(OPT_fdiagnostics_format, "clang");
if (Format == "clang")
Opts.Format = DiagnosticOptions::Clang;
@@ -1143,13 +1185,13 @@ static void ParseFileSystemArgs(FileSystemOptions &Opts, ArgList &Args) {
}
static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
- Diagnostic &Diags) {
+ DiagnosticsEngine &Diags) {
using namespace cc1options;
Opts.ProgramAction = frontend::ParseSyntaxOnly;
if (const Arg *A = Args.getLastArg(OPT_Action_Group)) {
switch (A->getOption().getID()) {
default:
- assert(0 && "Invalid option in group!");
+ llvm_unreachable("Invalid option in group!");
case OPT_ast_dump:
Opts.ProgramAction = frontend::ASTDump; break;
case OPT_ast_dump_xml:
@@ -1181,6 +1223,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
// fall-through!
case OPT_fixit:
Opts.ProgramAction = frontend::FixIt; break;
+ case OPT_emit_module:
+ Opts.ProgramAction = frontend::GenerateModule; break;
case OPT_emit_pch:
Opts.ProgramAction = frontend::GeneratePCH; break;
case OPT_emit_pth:
@@ -1205,8 +1249,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ProgramAction = frontend::RunAnalysis; break;
case OPT_Eonly:
Opts.ProgramAction = frontend::RunPreprocessorOnly; break;
- case OPT_create_module:
- Opts.ProgramAction = frontend::CreateModule; break;
}
}
@@ -1244,7 +1286,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.OutputFile = Args.getLastArgValue(OPT_o);
Opts.Plugins = Args.getAllArgValues(OPT_load);
Opts.RelocatablePCH = Args.hasArg(OPT_relocatable_pch);
- Opts.ChainedPCH = Args.hasArg(OPT_chained_pch);
Opts.ShowHelp = Args.hasArg(OPT_help);
Opts.ShowMacrosInCodeCompletion = Args.hasArg(OPT_code_completion_macros);
Opts.ShowCodePatternsInCodeCompletion
@@ -1257,7 +1298,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ASTMergeFiles = Args.getAllArgValues(OPT_ast_merge);
Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm);
Opts.FixWhatYouCan = Args.hasArg(OPT_fix_what_you_can);
- Opts.Modules = Args.getAllArgValues(OPT_import_module);
Opts.ARCMTAction = FrontendOptions::ARCMT_None;
if (const Arg *A = Args.getLastArg(OPT_arcmt_check,
@@ -1278,6 +1318,10 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
}
}
Opts.ARCMTMigrateDir = Args.getLastArgValue(OPT_arcmt_migrate_directory);
+ Opts.ARCMTMigrateReportOut
+ = Args.getLastArgValue(OPT_arcmt_migrate_report_output);
+ Opts.ARCMTMigrateEmitARCErrors
+ = Args.hasArg(OPT_arcmt_migrate_emit_arc_errors);
InputKind DashX = IK_None;
if (const Arg *A = Args.getLastArg(OPT_x)) {
@@ -1294,7 +1338,9 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
.Case("objective-c-cpp-output", IK_PreprocessedObjC)
.Case("objc-cpp-output", IK_PreprocessedObjC)
.Case("objective-c++-cpp-output", IK_PreprocessedObjCXX)
+ .Case("objc++-cpp-output", IK_PreprocessedObjCXX)
.Case("c-header", IK_C)
+ .Case("cl-header", IK_OpenCL)
.Case("objective-c-header", IK_ObjC)
.Case("c++-header", IK_CXX)
.Case("objective-c++-header", IK_ObjCXX)
@@ -1315,7 +1361,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
InputKind IK = DashX;
if (IK == IK_None) {
IK = FrontendOptions::getInputKindForExtension(
- llvm::StringRef(Inputs[i]).rsplit('.').second);
+ StringRef(Inputs[i]).rsplit('.').second);
// FIXME: Remove this hack.
if (i == 0)
DashX = IK;
@@ -1348,20 +1394,35 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
Opts.Sysroot = Args.getLastArgValue(OPT_isysroot, "/");
Opts.Verbose = Args.hasArg(OPT_v);
Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc);
- Opts.UseStandardIncludes = !Args.hasArg(OPT_nostdinc);
+ Opts.UseStandardSystemIncludes = !Args.hasArg(OPT_nostdsysteminc);
Opts.UseStandardCXXIncludes = !Args.hasArg(OPT_nostdincxx);
if (const Arg *A = Args.getLastArg(OPT_stdlib_EQ))
Opts.UseLibcxx = (strcmp(A->getValue(Args), "libc++") == 0);
Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir);
-
- // Add -I... and -F... options in order.
- for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F),
- ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(Args), frontend::Angled, true,
+ Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodule_cache_path);
+ Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash);
+
+ // Add -I..., -F..., and -index-header-map options in order.
+ bool IsIndexHeaderMap = false;
+ for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F,
+ OPT_index_header_map),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ if ((*it)->getOption().matches(OPT_index_header_map)) {
+ // -index-header-map applies to the next -I or -F.
+ IsIndexHeaderMap = true;
+ continue;
+ }
+
+ frontend::IncludeDirGroup Group
+ = IsIndexHeaderMap? frontend::IndexHeaderMap : frontend::Angled;
+
+ Opts.AddPath((*it)->getValue(Args), Group, true,
/*IsFramework=*/ (*it)->getOption().matches(OPT_F), false);
+ IsIndexHeaderMap = false;
+ }
// Add -iprefix/-iwith-prefix/-iwithprefixbefore options.
- llvm::StringRef Prefix = ""; // FIXME: This isn't the correct default prefix.
+ StringRef Prefix = ""; // FIXME: This isn't the correct default prefix.
for (arg_iterator it = Args.filtered_begin(OPT_iprefix, OPT_iwithprefix,
OPT_iwithprefixbefore),
ie = Args.filtered_end(); it != ie; ++it) {
@@ -1382,14 +1443,25 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
for (arg_iterator it = Args.filtered_begin(OPT_iquote),
ie = Args.filtered_end(); it != ie; ++it)
Opts.AddPath((*it)->getValue(Args), frontend::Quoted, true, false, false);
- for (arg_iterator it = Args.filtered_begin(OPT_cxx_isystem, OPT_isystem,
+ for (arg_iterator it = Args.filtered_begin(OPT_isystem,
OPT_iwithsysroot), ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(Args),
- ((*it)->getOption().matches(OPT_cxx_isystem) ?
- frontend::CXXSystem : frontend::System),
- true, false, !(*it)->getOption().matches(OPT_iwithsysroot));
-
- // FIXME: Need options for the various environment variables!
+ Opts.AddPath((*it)->getValue(Args), frontend::System, true, false,
+ !(*it)->getOption().matches(OPT_iwithsysroot));
+
+ // Add the paths for the various language specific isystem flags.
+ for (arg_iterator it = Args.filtered_begin(OPT_c_isystem),
+ ie = Args.filtered_end(); it != ie; ++it)
+ Opts.AddPath((*it)->getValue(Args), frontend::CSystem, true, false, true);
+ for (arg_iterator it = Args.filtered_begin(OPT_cxx_isystem),
+ ie = Args.filtered_end(); it != ie; ++it)
+ Opts.AddPath((*it)->getValue(Args), frontend::CXXSystem, true, false, true);
+ for (arg_iterator it = Args.filtered_begin(OPT_objc_isystem),
+ ie = Args.filtered_end(); it != ie; ++it)
+ Opts.AddPath((*it)->getValue(Args), frontend::ObjCSystem, true, false,true);
+ for (arg_iterator it = Args.filtered_begin(OPT_objcxx_isystem),
+ ie = Args.filtered_end(); it != ie; ++it)
+ Opts.AddPath((*it)->getValue(Args), frontend::ObjCXXSystem, true, false,
+ true);
}
void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
@@ -1412,7 +1484,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
case IK_None:
case IK_AST:
case IK_LLVM_IR:
- assert(0 && "Invalid input kind!");
+ llvm_unreachable("Invalid input kind!");
case IK_OpenCL:
LangStd = LangStandard::lang_opencl;
break;
@@ -1450,9 +1522,9 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
// OpenCL has some additional defaults.
if (LangStd == LangStandard::lang_opencl) {
Opts.OpenCL = 1;
- Opts.AltiVec = 1;
+ Opts.AltiVec = 0;
Opts.CXXOperatorNames = 1;
- Opts.LaxVectorConversions = 1;
+ Opts.LaxVectorConversions = 0;
Opts.DefaultFPContract = 1;
}
@@ -1473,7 +1545,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
}
static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
- Diagnostic &Diags) {
+ DiagnosticsEngine &Diags) {
// FIXME: Cleanup per-file based stuff.
LangStandard::Kind LangStd = LangStandard::lang_unspecified;
if (const Arg *A = Args.getLastArg(OPT_std_EQ)) {
@@ -1543,12 +1615,12 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Opts.ObjC1) {
if (Args.hasArg(OPT_fobjc_gc_only))
- Opts.setGCMode(LangOptions::GCOnly);
+ Opts.setGC(LangOptions::GCOnly);
else if (Args.hasArg(OPT_fobjc_gc))
- Opts.setGCMode(LangOptions::HybridGC);
+ Opts.setGC(LangOptions::HybridGC);
else if (Args.hasArg(OPT_fobjc_arc)) {
Opts.ObjCAutoRefCount = 1;
- if (!Args.hasArg(OPT_fobjc_nonfragile_abi))
+ if (Args.hasArg(OPT_fobjc_fragile_abi))
Diags.Report(diag::err_arc_nonfragile_abi);
}
@@ -1583,7 +1655,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Args.hasArg(OPT_fdelayed_template_parsing))
Opts.DelayedTemplateParsing = 1;
- llvm::StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default");
+ StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default");
if (Vis == "default")
Opts.setVisibilityMode(DefaultVisibility);
else if (Vis == "hidden")
@@ -1613,7 +1685,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
OPT_fno_dollars_in_identifiers,
Opts.DollarIdents);
Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings);
- Opts.Microsoft = Args.hasArg(OPT_fms_extensions);
+ Opts.MicrosoftExt = Args.hasArg(OPT_fms_extensions);
+ Opts.MicrosoftMode = Args.hasArg(OPT_fms_compatibility);
Opts.MSCVersion = Args.getLastArgIntValue(OPT_fmsc_version, 0, Diags);
Opts.Borland = Args.hasArg(OPT_fborland_extensions);
Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
@@ -1631,6 +1704,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.RTTI = !Args.hasArg(OPT_fno_rtti);
Opts.Blocks = Args.hasArg(OPT_fblocks);
+ Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional);
Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char);
Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar);
Opts.ShortEnums = Args.hasArg(OPT_fshort_enums);
@@ -1650,13 +1724,14 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime);
Opts.ObjCConstantStringClass =
Args.getLastArgValue(OPT_fconstant_string_class);
- Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi);
+ Opts.ObjCNonFragileABI = !Args.hasArg(OPT_fobjc_fragile_abi);
if (Opts.ObjCNonFragileABI)
Opts.ObjCNonFragileABI2 = true;
Opts.ObjCDefaultSynthProperties =
Args.hasArg(OPT_fobjc_default_synthesize_properties);
Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior);
Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls);
+ Opts.PackStruct = Args.getLastArgIntValue(OPT_fpack_struct, 0, Diags);
Opts.PICLevel = Args.getLastArgIntValue(OPT_pic_level, 0, Diags);
Opts.Static = Args.hasArg(OPT_static_define);
Opts.DumpRecordLayouts = Args.hasArg(OPT_fdump_record_layouts);
@@ -1693,15 +1768,15 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Diags.Report(diag::err_drv_invalid_value)
<< Args.getLastArg(OPT_stack_protector)->getAsString(Args) << SSP;
break;
- case 0: Opts.setStackProtectorMode(LangOptions::SSPOff); break;
- case 1: Opts.setStackProtectorMode(LangOptions::SSPOn); break;
- case 2: Opts.setStackProtectorMode(LangOptions::SSPReq); break;
+ case 0: Opts.setStackProtector(LangOptions::SSPOff); break;
+ case 1: Opts.setStackProtector(LangOptions::SSPOn); break;
+ case 2: Opts.setStackProtector(LangOptions::SSPReq); break;
}
}
static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
FileManager &FileMgr,
- Diagnostic &Diags) {
+ DiagnosticsEngine &Diags) {
using namespace cc1options;
Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch);
Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth);
@@ -1711,6 +1786,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Opts.TokenCache = Opts.ImplicitPTHInclude;
Opts.UsePredefines = !Args.hasArg(OPT_undef);
Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record);
+ Opts.AutoModuleImport = Args.hasArg(OPT_fauto_module_import);
Opts.DisablePCHValidation = Args.hasArg(OPT_fno_validate_pch);
Opts.DumpDeserializedPCHDecls = Args.hasArg(OPT_dump_deserialized_pch_decls);
@@ -1721,12 +1797,12 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
}
if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) {
- llvm::StringRef Value(A->getValue(Args));
+ StringRef Value(A->getValue(Args));
size_t Comma = Value.find(',');
unsigned Bytes = 0;
unsigned EndOfLine = 0;
- if (Comma == llvm::StringRef::npos ||
+ if (Comma == StringRef::npos ||
Value.substr(0, Comma).getAsInteger(10, Bytes) ||
Value.substr(Comma + 1).getAsInteger(10, EndOfLine))
Diags.Report(diag::err_drv_preamble_format);
@@ -1777,8 +1853,8 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
for (arg_iterator it = Args.filtered_begin(OPT_remap_file),
ie = Args.filtered_end(); it != ie; ++it) {
const Arg *A = *it;
- std::pair<llvm::StringRef,llvm::StringRef> Split =
- llvm::StringRef(A->getValue(Args)).split(';');
+ std::pair<StringRef,StringRef> Split =
+ StringRef(A->getValue(Args)).split(';');
if (Split.second.empty()) {
Diags.Report(diag::err_drv_invalid_remap_file) << A->getAsString(Args);
@@ -1789,7 +1865,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
}
if (Arg *A = Args.getLastArg(OPT_fobjc_arc_cxxlib_EQ)) {
- llvm::StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue(Args);
unsigned Library = llvm::StringSwitch<unsigned>(Name)
.Case("libc++", ARCXX_libcxx)
.Case("libstdc++", ARCXX_libstdcxx)
@@ -1831,7 +1907,7 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) {
void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
const char *const *ArgBegin,
const char *const *ArgEnd,
- Diagnostic &Diags) {
+ DiagnosticsEngine &Diags) {
// Parse the arguments.
llvm::OwningPtr<OptTable> Opts(createCC1OptTable());
unsigned MissingArgIndex, MissingArgCount;
@@ -1870,3 +1946,105 @@ void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args);
ParseTargetArgs(Res.getTargetOpts(), *Args);
}
+
+namespace {
+
+ class ModuleSignature {
+ llvm::SmallVector<uint64_t, 16> Data;
+ unsigned CurBit;
+ uint64_t CurValue;
+
+ public:
+ ModuleSignature() : CurBit(0), CurValue(0) { }
+
+ void add(uint64_t Value, unsigned Bits);
+ void add(StringRef Value);
+ void flush();
+
+ llvm::APInt getAsInteger() const;
+ };
+}
+
+void ModuleSignature::add(uint64_t Value, unsigned int NumBits) {
+ CurValue |= Value << CurBit;
+ if (CurBit + NumBits < 64) {
+ CurBit += NumBits;
+ return;
+ }
+
+ // Add the current word.
+ Data.push_back(CurValue);
+
+ if (CurBit)
+ CurValue = Value >> (64-CurBit);
+ else
+ CurValue = 0;
+ CurBit = (CurBit+NumBits) & 63;
+}
+
+void ModuleSignature::flush() {
+ if (CurBit == 0)
+ return;
+
+ Data.push_back(CurValue);
+ CurBit = 0;
+ CurValue = 0;
+}
+
+void ModuleSignature::add(StringRef Value) {
+ for (StringRef::iterator I = Value.begin(), IEnd = Value.end(); I != IEnd;++I)
+ add(*I, 8);
+}
+
+llvm::APInt ModuleSignature::getAsInteger() const {
+ return llvm::APInt(Data.size() * 64, Data);
+}
+
+std::string CompilerInvocation::getModuleHash() const {
+ ModuleSignature Signature;
+
+ // Start the signature with the compiler version.
+ Signature.add(getClangFullRepositoryVersion());
+
+ // Extend the signature with the language options
+#define LANGOPT(Name, Bits, Default, Description) \
+ Signature.add(LangOpts.Name, Bits);
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ Signature.add(static_cast<unsigned>(LangOpts.get##Name()), Bits);
+#define BENIGN_LANGOPT(Name, Bits, Default, Description)
+#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
+#include "clang/Basic/LangOptions.def"
+
+ // Extend the signature with the target triple
+ llvm::Triple T(TargetOpts.Triple);
+ Signature.add((unsigned)T.getArch(), 5);
+ Signature.add((unsigned)T.getVendor(), 4);
+ Signature.add((unsigned)T.getOS(), 5);
+ Signature.add((unsigned)T.getEnvironment(), 4);
+
+ // Extend the signature with preprocessor options.
+ Signature.add(getPreprocessorOpts().UsePredefines, 1);
+ Signature.add(getPreprocessorOpts().DetailedRecord, 1);
+
+ // Hash the preprocessor defines.
+ // FIXME: This is terrible. Use an MD5 sum of the preprocessor defines.
+ std::vector<StringRef> MacroDefs;
+ for (std::vector<std::pair<std::string, bool/*isUndef*/> >::const_iterator
+ I = getPreprocessorOpts().Macros.begin(),
+ IEnd = getPreprocessorOpts().Macros.end();
+ I != IEnd; ++I) {
+ if (!I->second)
+ MacroDefs.push_back(I->first);
+ }
+ llvm::array_pod_sort(MacroDefs.begin(), MacroDefs.end());
+
+ unsigned PPHashResult = 0;
+ for (unsigned I = 0, N = MacroDefs.size(); I != N; ++I)
+ PPHashResult = llvm::HashString(MacroDefs[I], PPHashResult);
+ Signature.add(PPHashResult, 32);
+
+ // We've generated the signature. Treat it as one large APInt that we'll
+ // encode in base-36 and return.
+ Signature.flush();
+ return Signature.getAsInteger().toString(36, /*Signed=*/false);
+}
diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp
index 42b648aa6411..fc1508103c2e 100644
--- a/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -29,8 +29,8 @@ using namespace clang;
/// \return A CompilerInvocation, or 0 if none was built for the given
/// argument vector.
CompilerInvocation *
-clang::createInvocationFromCommandLine(llvm::ArrayRef<const char *> ArgList,
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags) {
+clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList,
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags) {
if (!Diags.getPtr()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
@@ -39,7 +39,7 @@ clang::createInvocationFromCommandLine(llvm::ArrayRef<const char *> ArgList,
ArgList.begin());
}
- llvm::SmallVector<const char *, 16> Args;
+ SmallVector<const char *, 16> Args;
Args.push_back("<clang>"); // FIXME: Remove dummy argument.
Args.insert(Args.end(), ArgList.begin(), ArgList.end());
@@ -49,7 +49,7 @@ clang::createInvocationFromCommandLine(llvm::ArrayRef<const char *> ArgList,
// FIXME: We shouldn't have to pass in the path info.
driver::Driver TheDriver("clang", llvm::sys::getHostTriple(),
- "a.out", false, false, *Diags);
+ "a.out", false, *Diags);
// Don't check that inputs exist, they may have been remapped.
TheDriver.setCheckInputsExist(false);
@@ -74,7 +74,7 @@ clang::createInvocationFromCommandLine(llvm::ArrayRef<const char *> ArgList,
}
const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
- if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
+ if (StringRef(Cmd->getCreator().getName()) != "clang") {
Diags->Report(diag::err_fe_expected_clang_command);
return 0;
}
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
index 1edd09b06c4c..ff3a12392c9f 100644
--- a/lib/Frontend/DependencyFile.cpp
+++ b/lib/Frontend/DependencyFile.cpp
@@ -32,19 +32,19 @@ class DependencyFileCallback : public PPCallbacks {
llvm::StringSet<> FilesSet;
const Preprocessor *PP;
std::vector<std::string> Targets;
- llvm::raw_ostream *OS;
+ raw_ostream *OS;
bool IncludeSystemHeaders;
bool PhonyTarget;
bool AddMissingHeaderDeps;
private:
bool FileMatchesDepCriteria(const char *Filename,
SrcMgr::CharacteristicKind FileType);
- void AddFilename(llvm::StringRef Filename);
+ void AddFilename(StringRef Filename);
void OutputDependencyFile();
public:
DependencyFileCallback(const Preprocessor *_PP,
- llvm::raw_ostream *_OS,
+ raw_ostream *_OS,
const DependencyOutputOptions &Opts)
: PP(_PP), Targets(Opts.Targets), OS(_OS),
IncludeSystemHeaders(Opts.IncludeSystemHeaders),
@@ -52,15 +52,16 @@ public:
AddMissingHeaderDeps(Opts.AddMissingHeaderDeps) {}
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
- SrcMgr::CharacteristicKind FileType);
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID);
virtual void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
- llvm::StringRef FileName,
+ StringRef FileName,
bool IsAngled,
const FileEntry *File,
SourceLocation EndLoc,
- llvm::StringRef SearchPath,
- llvm::StringRef RelativePath);
+ StringRef SearchPath,
+ StringRef RelativePath);
virtual void EndOfMainFile() {
OutputDependencyFile();
@@ -78,7 +79,7 @@ void clang::AttachDependencyFileGen(Preprocessor &PP,
}
std::string Err;
- llvm::raw_ostream *OS(new llvm::raw_fd_ostream(Opts.OutputFile.c_str(), Err));
+ raw_ostream *OS(new llvm::raw_fd_ostream(Opts.OutputFile.c_str(), Err));
if (!Err.empty()) {
PP.getDiagnostics().Report(diag::err_fe_error_opening)
<< Opts.OutputFile << Err;
@@ -86,14 +87,8 @@ void clang::AttachDependencyFileGen(Preprocessor &PP,
}
// Disable the "file not found" diagnostic if the -MG option was given.
- // FIXME: Ideally this would live in the driver, but we don't have the ability
- // to remap individual diagnostics there without creating a DiagGroup, in
- // which case we would need to prevent the group name from showing up in
- // diagnostics.
- if (Opts.AddMissingHeaderDeps) {
- PP.getDiagnostics().setDiagnosticMapping(diag::warn_pp_file_not_found,
- diag::MAP_IGNORE, SourceLocation());
- }
+ if (Opts.AddMissingHeaderDeps)
+ PP.SetSuppressIncludeNotFoundError(true);
PP.addPPCallbacks(new DependencyFileCallback(&PP, OS, Opts));
}
@@ -113,7 +108,8 @@ bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename,
void DependencyFileCallback::FileChanged(SourceLocation Loc,
FileChangeReason Reason,
- SrcMgr::CharacteristicKind FileType) {
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID) {
if (Reason != PPCallbacks::EnterFile)
return;
@@ -123,10 +119,10 @@ void DependencyFileCallback::FileChanged(SourceLocation Loc,
SourceManager &SM = PP->getSourceManager();
const FileEntry *FE =
- SM.getFileEntryForID(SM.getFileID(SM.getInstantiationLoc(Loc)));
+ SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc)));
if (FE == 0) return;
- llvm::StringRef Filename = FE->getName();
+ StringRef Filename = FE->getName();
if (!FileMatchesDepCriteria(Filename.data(), FileType))
return;
@@ -143,24 +139,24 @@ void DependencyFileCallback::FileChanged(SourceLocation Loc,
void DependencyFileCallback::InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
- llvm::StringRef FileName,
+ StringRef FileName,
bool IsAngled,
const FileEntry *File,
SourceLocation EndLoc,
- llvm::StringRef SearchPath,
- llvm::StringRef RelativePath) {
+ StringRef SearchPath,
+ StringRef RelativePath) {
if (AddMissingHeaderDeps && !File)
AddFilename(FileName);
}
-void DependencyFileCallback::AddFilename(llvm::StringRef Filename) {
+void DependencyFileCallback::AddFilename(StringRef Filename) {
if (FilesSet.insert(Filename))
Files.push_back(Filename);
}
/// PrintFilename - GCC escapes spaces, but apparently not ' or " or other
/// scary characters.
-static void PrintFilename(llvm::raw_ostream &OS, llvm::StringRef Filename) {
+static void PrintFilename(raw_ostream &OS, StringRef Filename) {
for (unsigned i = 0, e = Filename.size(); i != e; ++i) {
if (Filename[i] == ' ')
OS << '\\';
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index 0128d6ee0531..ba2d63b026d5 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -20,6 +20,7 @@
#include "clang/Frontend/MultiplexConsumer.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Serialization/ASTDeserializationListener.h"
+#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/ChainedIncludesSource.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Timer.h"
@@ -65,7 +66,7 @@ public:
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
if (NamesToCheck.find(ND->getNameAsString()) != NamesToCheck.end()) {
unsigned DiagID
- = Ctx.getDiagnostics().getCustomDiagID(Diagnostic::Error,
+ = Ctx.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error,
"%0 was deserialized");
Ctx.getDiagnostics().Report(Ctx.getFullLoc(D->getLocation()), DiagID)
<< ND->getNameAsString();
@@ -82,7 +83,7 @@ FrontendAction::FrontendAction() : Instance(0) {}
FrontendAction::~FrontendAction() {}
-void FrontendAction::setCurrentFile(llvm::StringRef Value, InputKind Kind,
+void FrontendAction::setCurrentFile(StringRef Value, InputKind Kind,
ASTUnit *AST) {
CurrentFile = Value;
CurrentFileKind = Kind;
@@ -90,7 +91,7 @@ void FrontendAction::setCurrentFile(llvm::StringRef Value, InputKind Kind,
}
ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
+ StringRef InFile) {
ASTConsumer* Consumer = CreateASTConsumer(CI, InFile);
if (!Consumer)
return 0;
@@ -123,7 +124,7 @@ ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
}
bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
- llvm::StringRef Filename,
+ StringRef Filename,
InputKind InputKind) {
assert(!Instance && "Already processing a source file!");
assert(!Filename.empty() && "Unexpected empty filename!");
@@ -141,7 +142,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
assert(hasASTFileSupport() &&
"This action does not have AST file support!");
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics());
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
std::string Error;
ASTUnit *AST = ASTUnit::LoadFromASTFile(Filename, Diags,
CI.getFileSystemOpts());
@@ -224,9 +225,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
} else if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
// Use PCH.
assert(hasPCHSupport() && "This action does not have PCH support!");
- ASTDeserializationListener *DeserialListener
- = CI.getInvocation().getFrontendOpts().ChainedPCH ?
- Consumer->GetASTDeserializationListener() : 0;
+ ASTDeserializationListener *DeserialListener =
+ Consumer->GetASTDeserializationListener();
if (CI.getPreprocessorOpts().DumpDeserializedPCHDecls)
DeserialListener = new DeserializedDeclsDumper(DeserialListener);
if (!CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn.empty())
@@ -247,7 +247,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
goto failure;
}
- // Initialize builtin info as long as we aren't using an external AST
+ // Initialize built-in info as long as we aren't using an external AST
// source.
if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
Preprocessor &PP = CI.getPreprocessor();
@@ -374,26 +374,26 @@ void ASTFrontendAction::ExecuteAction() {
CompletionConsumer = &CI.getCodeCompletionConsumer();
if (!CI.hasSema())
- CI.createSema(usesCompleteTranslationUnit(), CompletionConsumer);
+ CI.createSema(getTranslationUnitKind(), CompletionConsumer);
ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats);
}
ASTConsumer *
PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
+ StringRef InFile) {
llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
}
ASTConsumer *WrapperFrontendAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
+ StringRef InFile) {
return WrappedAction->CreateASTConsumer(CI, InFile);
}
bool WrapperFrontendAction::BeginInvocation(CompilerInstance &CI) {
return WrappedAction->BeginInvocation(CI);
}
bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI,
- llvm::StringRef Filename) {
+ StringRef Filename) {
WrappedAction->setCurrentFile(getCurrentFile(), getCurrentFileKind());
WrappedAction->setCompilerInstance(&CI);
return WrappedAction->BeginSourceFileAction(CI, Filename);
@@ -408,8 +408,8 @@ void WrapperFrontendAction::EndSourceFileAction() {
bool WrapperFrontendAction::usesPreprocessorOnly() const {
return WrappedAction->usesPreprocessorOnly();
}
-bool WrapperFrontendAction::usesCompleteTranslationUnit() {
- return WrappedAction->usesCompleteTranslationUnit();
+TranslationUnitKind WrapperFrontendAction::getTranslationUnitKind() {
+ return WrappedAction->getTranslationUnitKind();
}
bool WrapperFrontendAction::hasPCHSupport() const {
return WrappedAction->hasPCHSupport();
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 7b06c7e49acf..6f84da96300c 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -22,6 +22,8 @@
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
+
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -29,7 +31,7 @@ using namespace clang;
//===----------------------------------------------------------------------===//
ASTConsumer *InitOnlyAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
+ StringRef InFile) {
return new ASTConsumer();
}
@@ -41,20 +43,20 @@ void InitOnlyAction::ExecuteAction() {
//===----------------------------------------------------------------------===//
ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
- if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile))
+ StringRef InFile) {
+ if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile))
return CreateASTPrinter(OS);
return 0;
}
ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
+ StringRef InFile) {
return CreateASTDumper();
}
ASTConsumer *ASTDumpXMLAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
- llvm::raw_ostream *OS;
+ StringRef InFile) {
+ raw_ostream *OS;
if (CI.getFrontendOpts().OutputFile.empty())
OS = &llvm::outs();
else
@@ -64,35 +66,34 @@ ASTConsumer *ASTDumpXMLAction::CreateASTConsumer(CompilerInstance &CI,
}
ASTConsumer *ASTViewAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
+ StringRef InFile) {
return CreateASTViewer();
}
ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
+ StringRef InFile) {
return CreateDeclContextPrinter();
}
ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
+ StringRef InFile) {
std::string Sysroot;
std::string OutputFile;
- llvm::raw_ostream *OS = 0;
- bool Chaining;
- if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS, Chaining))
+ raw_ostream *OS = 0;
+ if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS))
return 0;
- const char *isysroot = CI.getFrontendOpts().RelocatablePCH ?
- Sysroot.c_str() : 0;
- return new PCHGenerator(CI.getPreprocessor(), OutputFile, Chaining, isysroot, OS);
+ if (!CI.getFrontendOpts().RelocatablePCH)
+ Sysroot.clear();
+ return new PCHGenerator(CI.getPreprocessor(), OutputFile, MakeModule,
+ Sysroot, OS);
}
bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
- llvm::StringRef InFile,
+ StringRef InFile,
std::string &Sysroot,
std::string &OutputFile,
- llvm::raw_ostream *&OS,
- bool &Chaining) {
+ raw_ostream *&OS) {
Sysroot = CI.getHeaderSearchOpts().Sysroot;
if (CI.getFrontendOpts().RelocatablePCH && Sysroot.empty()) {
CI.getDiagnostics().Report(diag::err_relocatable_without_isysroot);
@@ -101,19 +102,19 @@ bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
// We use createOutputFile here because this is exposed via libclang, and we
// must disable the RemoveFileOnSignal behavior.
+ // We use a temporary to avoid race conditions.
OS = CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true,
- /*RemoveFileOnSignal=*/false, InFile);
+ /*RemoveFileOnSignal=*/false, InFile,
+ /*Extension=*/"", /*useTemporary=*/true);
if (!OS)
return true;
OutputFile = CI.getFrontendOpts().OutputFile;
- Chaining = CI.getInvocation().getFrontendOpts().ChainedPCH &&
- !CI.getPreprocessorOpts().ImplicitPCHInclude.empty();
return false;
}
ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
+ StringRef InFile) {
return new ASTConsumer();
}
@@ -182,9 +183,48 @@ void PreprocessOnlyAction::ExecuteAction() {
void PrintPreprocessedAction::ExecuteAction() {
CompilerInstance &CI = getCompilerInstance();
- // Output file needs to be set to 'Binary', to avoid converting Unix style
+ // Output file may need to be set to 'Binary', to avoid converting Unix style
// line feeds (<LF>) to Microsoft style line feeds (<CR><LF>).
- llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
+ //
+ // Look to see what type of line endings the file uses. If there's a
+ // CRLF, then we won't open the file up in binary mode. If there is
+ // just an LF or CR, then we will open the file up in binary mode.
+ // In this fashion, the output format should match the input format, unless
+ // the input format has inconsistent line endings.
+ //
+ // This should be a relatively fast operation since most files won't have
+ // all of their source code on a single line. However, that is still a
+ // concern, so if we scan for too long, we'll just assume the file should
+ // be opened in binary mode.
+ bool BinaryMode = true;
+ bool InvalidFile = false;
+ const SourceManager& SM = CI.getSourceManager();
+ const llvm::MemoryBuffer *Buffer = SM.getBuffer(SM.getMainFileID(),
+ &InvalidFile);
+ if (!InvalidFile) {
+ const char *cur = Buffer->getBufferStart();
+ const char *end = Buffer->getBufferEnd();
+ const char *next = (cur != end) ? cur + 1 : end;
+
+ // Limit ourselves to only scanning 256 characters into the source
+ // file. This is mostly a sanity check in case the file has no
+ // newlines whatsoever.
+ if (end - cur > 256) end = cur + 256;
+
+ while (next < end) {
+ if (*cur == 0x0D) { // CR
+ if (*next == 0x0A) // CRLF
+ BinaryMode = false;
+
+ break;
+ } else if (*cur == 0x0A) // LF
+ break;
+
+ ++cur, ++next;
+ }
+ }
+
+ raw_ostream *OS = CI.createDefaultOutputFile(BinaryMode, getCurrentFile());
if (!OS) return;
DoPrintPreprocessedInput(CI.getPreprocessor(), OS,
@@ -217,7 +257,7 @@ void PrintPreambleAction::ExecuteAction() {
llvm::MemoryBuffer *Buffer
= CI.getFileManager().getBufferForFile(getCurrentFile());
if (Buffer) {
- unsigned Preamble = Lexer::ComputePreamble(Buffer).first;
+ unsigned Preamble = Lexer::ComputePreamble(Buffer, CI.getLangOpts()).first;
llvm::outs().write(Buffer->getBufferStart(), Preamble);
delete Buffer;
}
diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp
index 0a2005192a19..ea4005f7c960 100644
--- a/lib/Frontend/FrontendOptions.cpp
+++ b/lib/Frontend/FrontendOptions.cpp
@@ -11,7 +11,7 @@
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
-InputKind FrontendOptions::getInputKindForExtension(llvm::StringRef Extension) {
+InputKind FrontendOptions::getInputKindForExtension(StringRef Extension) {
return llvm::StringSwitch<InputKind>(Extension)
.Case("ast", IK_AST)
.Case("c", IK_C)
diff --git a/lib/Frontend/HeaderIncludeGen.cpp b/lib/Frontend/HeaderIncludeGen.cpp
index 51dec967cd6b..3b41d894ec50 100644
--- a/lib/Frontend/HeaderIncludeGen.cpp
+++ b/lib/Frontend/HeaderIncludeGen.cpp
@@ -17,7 +17,7 @@ using namespace clang;
namespace {
class HeaderIncludesCallback : public PPCallbacks {
SourceManager &SM;
- llvm::raw_ostream *OutputFile;
+ raw_ostream *OutputFile;
unsigned CurrentIncludeDepth;
bool HasProcessedPredefines;
bool OwnsOutputFile;
@@ -26,7 +26,7 @@ class HeaderIncludesCallback : public PPCallbacks {
public:
HeaderIncludesCallback(const Preprocessor *PP, bool ShowAllHeaders_,
- llvm::raw_ostream *OutputFile_, bool OwnsOutputFile_,
+ raw_ostream *OutputFile_, bool OwnsOutputFile_,
bool ShowDepth_)
: SM(PP->getSourceManager()), OutputFile(OutputFile_),
CurrentIncludeDepth(0), HasProcessedPredefines(false),
@@ -39,13 +39,14 @@ public:
}
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
- SrcMgr::CharacteristicKind FileType);
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID);
};
}
void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders,
- llvm::StringRef OutputPath, bool ShowDepth) {
- llvm::raw_ostream *OutputFile = &llvm::errs();
+ StringRef OutputPath, bool ShowDepth) {
+ raw_ostream *OutputFile = &llvm::errs();
bool OwnsOutputFile = false;
// Open the output file, if used.
@@ -72,7 +73,8 @@ void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders,
void HeaderIncludesCallback::FileChanged(SourceLocation Loc,
FileChangeReason Reason,
- SrcMgr::CharacteristicKind NewFileType) {
+ SrcMgr::CharacteristicKind NewFileType,
+ FileID PrevFID) {
// Unless we are exiting a #include, make sure to skip ahead to the line the
// #include directive was at.
PresumedLoc UserLoc = SM.getPresumedLoc(Loc);
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index e11a415db194..b066e71a9435 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -52,38 +52,34 @@ class InitHeaderSearch {
public:
- InitHeaderSearch(HeaderSearch &HS, bool verbose, llvm::StringRef sysroot)
+ InitHeaderSearch(HeaderSearch &HS, bool verbose, StringRef sysroot)
: Headers(HS), Verbose(verbose), IncludeSysroot(sysroot),
IsNotEmptyOrRoot(!(sysroot.empty() || sysroot == "/")) {
}
/// AddPath - Add the specified path to the specified group list.
- void AddPath(const llvm::Twine &Path, IncludeDirGroup Group,
+ void AddPath(const Twine &Path, IncludeDirGroup Group,
bool isCXXAware, bool isUserSupplied,
bool isFramework, bool IgnoreSysRoot = false);
/// AddGnuCPlusPlusIncludePaths - Add the necessary paths to support a gnu
/// libstdc++.
- void AddGnuCPlusPlusIncludePaths(llvm::StringRef Base,
- llvm::StringRef ArchDir,
- llvm::StringRef Dir32,
- llvm::StringRef Dir64,
+ void AddGnuCPlusPlusIncludePaths(StringRef Base,
+ StringRef ArchDir,
+ StringRef Dir32,
+ StringRef Dir64,
const llvm::Triple &triple);
/// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to support a MinGW
/// libstdc++.
- void AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base,
- llvm::StringRef Arch,
- llvm::StringRef Version);
+ void AddMinGWCPlusPlusIncludePaths(StringRef Base,
+ StringRef Arch,
+ StringRef Version);
/// AddMinGW64CXXPaths - Add the necessary paths to support
/// libstdc++ of x86_64-w64-mingw32 aka mingw-w64.
- void AddMinGW64CXXPaths(llvm::StringRef Base,
- llvm::StringRef Version);
-
- /// AddDelimitedPaths - Add a list of paths delimited by the system PATH
- /// separator. The processing follows that of the CPATH variable for gcc.
- void AddDelimitedPaths(llvm::StringRef String);
+ void AddMinGW64CXXPaths(StringRef Base,
+ StringRef Version);
// AddDefaultCIncludePaths - Add paths that should always be searched.
void AddDefaultCIncludePaths(const llvm::Triple &triple,
@@ -96,9 +92,9 @@ public:
/// AddDefaultSystemIncludePaths - Adds the default system include paths so
/// that e.g. stdio.h is found.
- void AddDefaultSystemIncludePaths(const LangOptions &Lang,
- const llvm::Triple &triple,
- const HeaderSearchOptions &HSOpts);
+ void AddDefaultIncludePaths(const LangOptions &Lang,
+ const llvm::Triple &triple,
+ const HeaderSearchOptions &HSOpts);
/// Realize - Merges all search path lists into one list and send it to
/// HeaderSearch.
@@ -107,7 +103,7 @@ public:
} // end anonymous namespace.
-void InitHeaderSearch::AddPath(const llvm::Twine &Path,
+void InitHeaderSearch::AddPath(const Twine &Path,
IncludeDirGroup Group, bool isCXXAware,
bool isUserSupplied, bool isFramework,
bool IgnoreSysRoot) {
@@ -116,7 +112,7 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path,
// Compute the actual path, taking into consideration -isysroot.
llvm::SmallString<256> MappedPathStorage;
- llvm::StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
+ StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
// Handle isysroot.
if ((Group == System || Group == CXXSystem) && !IgnoreSysRoot &&
@@ -134,7 +130,7 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path,
// Compute the DirectoryLookup type.
SrcMgr::CharacteristicKind Type;
- if (Group == Quoted || Group == Angled)
+ if (Group == Quoted || Group == Angled || Group == IndexHeaderMap)
Type = SrcMgr::C_User;
else if (isCXXAware)
Type = SrcMgr::C_System;
@@ -156,7 +152,7 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path,
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)));
+ isUserSupplied, Group == IndexHeaderMap)));
return;
}
}
@@ -167,30 +163,10 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path,
<< MappedPathStr << "\"\n";
}
-
-void InitHeaderSearch::AddDelimitedPaths(llvm::StringRef at) {
- if (at.empty()) // Empty string should not add '.' path.
- return;
-
- llvm::StringRef::size_type delim;
- while ((delim = at.find(llvm::sys::PathSeparator)) != llvm::StringRef::npos) {
- if (delim == 0)
- AddPath(".", Angled, false, true, false);
- else
- AddPath(at.substr(0, delim), Angled, false, true, false);
- at = at.substr(delim + 1);
- }
-
- if (at.empty())
- AddPath(".", Angled, false, true, false);
- else
- AddPath(at, Angled, false, true, false);
-}
-
-void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(llvm::StringRef Base,
- llvm::StringRef ArchDir,
- llvm::StringRef Dir32,
- llvm::StringRef Dir64,
+void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(StringRef Base,
+ StringRef ArchDir,
+ StringRef Dir32,
+ StringRef Dir64,
const llvm::Triple &triple) {
// Add the base dir
AddPath(Base, CXXSystem, true, false, false);
@@ -207,9 +183,9 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(llvm::StringRef Base,
AddPath(Base + "/backward", CXXSystem, true, false, false);
}
-void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base,
- llvm::StringRef Arch,
- llvm::StringRef Version) {
+void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(StringRef Base,
+ StringRef Arch,
+ StringRef Version) {
AddPath(Base + "/" + Arch + "/" + Version + "/include/c++",
CXXSystem, true, false, false);
AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/" + Arch,
@@ -218,8 +194,8 @@ void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base,
CXXSystem, true, false, false);
}
-void InitHeaderSearch::AddMinGW64CXXPaths(llvm::StringRef Base,
- llvm::StringRef Version) {
+void InitHeaderSearch::AddMinGW64CXXPaths(StringRef Base,
+ StringRef Version) {
// Assumes Base is HeaderSearchOpts' ResourceDir
AddPath(Base + "/../../../include/c++/" + Version,
CXXSystem, true, false, false);
@@ -448,14 +424,16 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
const HeaderSearchOptions &HSOpts) {
llvm::Triple::OSType os = triple.getOS();
- switch (os) {
- case llvm::Triple::FreeBSD:
- case llvm::Triple::NetBSD:
- break;
- default:
- // FIXME: temporary hack: hard-coded paths.
- AddPath("/usr/local/include", System, true, false, false);
- break;
+ if (HSOpts.UseStandardSystemIncludes) {
+ switch (os) {
+ case llvm::Triple::FreeBSD:
+ case llvm::Triple::NetBSD:
+ break;
+ default:
+ // FIXME: temporary hack: hard-coded paths.
+ AddPath("/usr/local/include", System, true, false, false);
+ break;
+ }
}
// Builtin includes use #include_next directives and should be positioned
@@ -468,12 +446,17 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
AddPath(P.str(), System, false, false, false, /*IgnoreSysRoot=*/ true);
}
+ // All remaining additions are for system include directories, early exit if
+ // we aren't using them.
+ if (!HSOpts.UseStandardSystemIncludes)
+ return;
+
// Add dirs specified via 'configure --with-c-include-dirs'.
- llvm::StringRef CIncludeDirs(C_INCLUDE_DIRS);
+ StringRef CIncludeDirs(C_INCLUDE_DIRS);
if (CIncludeDirs != "") {
- llvm::SmallVector<llvm::StringRef, 5> dirs;
+ SmallVector<StringRef, 5> dirs;
CIncludeDirs.split(dirs, ":");
- for (llvm::SmallVectorImpl<llvm::StringRef>::iterator i = dirs.begin();
+ for (SmallVectorImpl<StringRef>::iterator i = dirs.begin();
i != dirs.end();
++i)
AddPath(*i, System, false, false, false);
@@ -597,9 +580,9 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
void InitHeaderSearch::
AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOptions &HSOpts) {
llvm::Triple::OSType os = triple.getOS();
- llvm::StringRef CxxIncludeRoot(CXX_INCLUDE_ROOT);
+ StringRef CxxIncludeRoot(CXX_INCLUDE_ROOT);
if (CxxIncludeRoot != "") {
- llvm::StringRef CxxIncludeArch(CXX_INCLUDE_ARCH);
+ StringRef CxxIncludeArch(CXX_INCLUDE_ARCH);
if (CxxIncludeArch == "")
AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, triple.str().c_str(),
CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR,
@@ -737,7 +720,12 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp
//===------------------------------------------------------------------===//
// Redhat based distros.
//===------------------------------------------------------------------===//
- // Fedora 15
+ // Fedora 15 (GCC 4.6.1)
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.1",
+ "x86_64-redhat-linux", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.1",
+ "i686-redhat-linux", "", "", triple);
+ // Fedora 15 (GCC 4.6.0)
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0",
"x86_64-redhat-linux", "32", "", triple);
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0",
@@ -840,6 +828,17 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0",
"x86_64-unknown-linux-gnu", "", "", triple);
+ // Slackware gcc 4.5.2 (13.37)
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.2",
+ "i486-slackware-linux", "", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.2",
+ "x86_64-slackware-linux", "", "", triple);
+ // Slackware gcc 4.5.3 (-current)
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.3",
+ "i486-slackware-linux", "", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.3",
+ "x86_64-slackware-linux", "", "", triple);
+
// Gentoo x86 gcc 4.5.2
AddGnuCPlusPlusIncludePaths(
"/usr/lib/gcc/i686-pc-linux-gnu/4.5.2/include/g++-v4",
@@ -889,6 +888,10 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp
AddGnuCPlusPlusIncludePaths(
"/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.3/include/g++-v4",
"x86_64-pc-linux-gnu", "32", "", triple);
+ // Gentoo amd64 gcc 4.3.4
+ AddGnuCPlusPlusIncludePaths(
+ "/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.4/include/g++-v4",
+ "x86_64-pc-linux-gnu", "", "", triple);
// Gentoo amd64 gcc 4.3.2
AddGnuCPlusPlusIncludePaths(
"/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.2/include/g++-v4",
@@ -936,32 +939,53 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp
}
}
-void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang,
- const llvm::Triple &triple,
+void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang,
+ const llvm::Triple &triple,
const HeaderSearchOptions &HSOpts) {
- if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes) {
- if (HSOpts.UseLibcxx)
+ if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes &&
+ HSOpts.UseStandardSystemIncludes) {
+ if (HSOpts.UseLibcxx) {
+ if (triple.isOSDarwin()) {
+ // On Darwin, libc++ may be installed alongside the compiler in
+ // lib/c++/v1.
+ llvm::sys::Path P(HSOpts.ResourceDir);
+ if (!P.isEmpty()) {
+ P.eraseComponent(); // Remove version from foo/lib/clang/version
+ P.eraseComponent(); // Remove clang from foo/lib/clang
+
+ // Get foo/lib/c++/v1
+ P.appendComponent("c++");
+ P.appendComponent("v1");
+ AddPath(P.str(), CXXSystem, true, false, false, true);
+ }
+ }
+
AddPath("/usr/include/c++/v1", CXXSystem, true, false, false);
- else
+ } else {
AddDefaultCPlusPlusIncludePaths(triple, HSOpts);
+ }
}
AddDefaultCIncludePaths(triple, HSOpts);
// Add the default framework include paths on Darwin.
- if (triple.isOSDarwin()) {
- AddPath("/System/Library/Frameworks", System, true, false, true);
- AddPath("/Library/Frameworks", System, true, false, true);
+ if (HSOpts.UseStandardSystemIncludes) {
+ if (triple.isOSDarwin()) {
+ AddPath("/System/Library/Frameworks", System, true, false, true);
+ AddPath("/Library/Frameworks", System, true, false, true);
+ }
}
}
/// RemoveDuplicates - If there are duplicate directory entries in the specified
-/// search list, remove the later (dead) ones.
-static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
- unsigned First, bool Verbose) {
+/// search list, remove the later (dead) ones. Returns the number of non-system
+/// headers removed, which is used to update NumAngled.
+static unsigned RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
+ unsigned First, bool Verbose) {
llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenDirs;
llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenFrameworkDirs;
llvm::SmallPtrSet<const HeaderMap *, 8> SeenHeaderMaps;
+ unsigned NonSystemRemoved = 0;
for (unsigned i = First; i != SearchList.size(); ++i) {
unsigned DirToRemove = i;
@@ -1028,12 +1052,15 @@ static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
llvm::errs() << " as it is a non-system directory that duplicates "
<< "a system directory\n";
}
+ if (DirToRemove != i)
+ ++NonSystemRemoved;
// This is reached if the current entry is a duplicate. Remove the
// DirToRemove (usually the current dir).
SearchList.erase(SearchList.begin()+DirToRemove);
--i;
}
+ return NonSystemRemoved;
}
@@ -1054,7 +1081,7 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) {
for (path_iterator it = IncludePath.begin(), ie = IncludePath.end();
it != ie; ++it) {
- if (it->first == Angled)
+ if (it->first == Angled || it->first == IndexHeaderMap)
SearchList.push_back(it->second);
}
@@ -1063,7 +1090,11 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) {
for (path_iterator it = IncludePath.begin(), ie = IncludePath.end();
it != ie; ++it) {
- if (it->first == System || (Lang.CPlusPlus && it->first == CXXSystem))
+ if (it->first == System ||
+ (!Lang.ObjC1 && !Lang.CPlusPlus && it->first == CSystem) ||
+ (/*FIXME !Lang.ObjC1 && */Lang.CPlusPlus && it->first == CXXSystem) ||
+ (Lang.ObjC1 && !Lang.CPlusPlus && it->first == ObjCSystem) ||
+ (Lang.ObjC1 && Lang.CPlusPlus && it->first == ObjCXXSystem))
SearchList.push_back(it->second);
}
@@ -1076,7 +1107,8 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) {
// Remove duplicates across both the Angled and System directories. GCC does
// this and failing to remove duplicates across these two groups breaks
// #include_next.
- RemoveDuplicates(SearchList, NumQuoted, Verbose);
+ unsigned NonSystemRemoved = RemoveDuplicates(SearchList, NumQuoted, Verbose);
+ NumAngled -= NonSystemRemoved;
bool DontSearchCurDir = false; // TODO: set to true if -I- is set?
Headers.SetSearchPaths(SearchList, NumQuoted, NumAngled, DontSearchCurDir);
@@ -1116,19 +1148,7 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS,
E.IgnoreSysRoot);
}
- // Add entries from CPATH and friends.
- Init.AddDelimitedPaths(HSOpts.EnvIncPath);
- if (Lang.CPlusPlus && Lang.ObjC1)
- Init.AddDelimitedPaths(HSOpts.ObjCXXEnvIncPath);
- else if (Lang.CPlusPlus)
- Init.AddDelimitedPaths(HSOpts.CXXEnvIncPath);
- else if (Lang.ObjC1)
- Init.AddDelimitedPaths(HSOpts.ObjCEnvIncPath);
- else
- Init.AddDelimitedPaths(HSOpts.CEnvIncPath);
-
- if (HSOpts.UseStandardIncludes)
- Init.AddDefaultSystemIncludePaths(Lang, Triple, HSOpts);
+ Init.AddDefaultIncludePaths(Lang, Triple, HSOpts);
Init.Realize(Lang);
}
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 9428cd5de0f3..6f49ec474473 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -30,15 +30,15 @@ using namespace clang;
// Append a #define line to Buf for Macro. Macro should be of the form XXX,
// in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit
// "#define XXX Y z W". To get a #define with no value, use "XXX=".
-static void DefineBuiltinMacro(MacroBuilder &Builder, llvm::StringRef Macro,
- Diagnostic &Diags) {
- std::pair<llvm::StringRef, llvm::StringRef> MacroPair = Macro.split('=');
- llvm::StringRef MacroName = MacroPair.first;
- llvm::StringRef MacroBody = MacroPair.second;
+static void DefineBuiltinMacro(MacroBuilder &Builder, StringRef Macro,
+ DiagnosticsEngine &Diags) {
+ std::pair<StringRef, StringRef> MacroPair = Macro.split('=');
+ StringRef MacroName = MacroPair.first;
+ StringRef MacroBody = MacroPair.second;
if (MacroName.size() != Macro.size()) {
// Per GCC -D semantics, the macro ends at \n if it exists.
- llvm::StringRef::size_type End = MacroBody.find_first_of("\n\r");
- if (End != llvm::StringRef::npos)
+ StringRef::size_type End = MacroBody.find_first_of("\n\r");
+ if (End != StringRef::npos)
Diags.Report(diag::warn_fe_macro_contains_embedded_newline)
<< MacroName;
Builder.defineMacro(MacroName, MacroBody.substr(0, End));
@@ -48,7 +48,7 @@ static void DefineBuiltinMacro(MacroBuilder &Builder, llvm::StringRef Macro,
}
}
-std::string clang::NormalizeDashIncludePath(llvm::StringRef File,
+std::string clang::NormalizeDashIncludePath(StringRef File,
FileManager &FileMgr) {
// Implicit include paths should be resolved relative to the current
// working directory first, and then use the regular header search
@@ -70,17 +70,17 @@ std::string clang::NormalizeDashIncludePath(llvm::StringRef File,
/// AddImplicitInclude - Add an implicit #include of the specified file to the
/// predefines buffer.
-static void AddImplicitInclude(MacroBuilder &Builder, llvm::StringRef File,
+static void AddImplicitInclude(MacroBuilder &Builder, StringRef File,
FileManager &FileMgr) {
Builder.append("#include \"" +
- llvm::Twine(NormalizeDashIncludePath(File, FileMgr)) + "\"");
+ Twine(NormalizeDashIncludePath(File, FileMgr)) + "\"");
}
static void AddImplicitIncludeMacros(MacroBuilder &Builder,
- llvm::StringRef File,
+ StringRef File,
FileManager &FileMgr) {
Builder.append("#__include_macros \"" +
- llvm::Twine(NormalizeDashIncludePath(File, FileMgr)) + "\"");
+ Twine(NormalizeDashIncludePath(File, FileMgr)) + "\"");
// Marker token to stop the __include_macros fetch loop.
Builder.append("##"); // ##?
}
@@ -88,7 +88,7 @@ static void AddImplicitIncludeMacros(MacroBuilder &Builder,
/// AddImplicitIncludePTH - Add an implicit #include using the original file
/// used to generate a PTH cache.
static void AddImplicitIncludePTH(MacroBuilder &Builder, Preprocessor &PP,
- llvm::StringRef ImplicitIncludePTH) {
+ StringRef ImplicitIncludePTH) {
PTHManager *P = PP.getPTHManager();
// Null check 'P' in the corner case where it couldn't be created.
const char *OriginalFile = P ? P->getOriginalSourceFile() : 0;
@@ -120,7 +120,7 @@ static T PickFP(const llvm::fltSemantics *Sem, T IEEESingleVal,
return IEEEQuadVal;
}
-static void DefineFloatMacros(MacroBuilder &Builder, llvm::StringRef Prefix,
+static void DefineFloatMacros(MacroBuilder &Builder, StringRef Prefix,
const llvm::fltSemantics *Sem) {
const char *DenormMin, *Epsilon, *Max, *Min;
DenormMin = PickFP(Sem, "1.40129846e-45F", "4.9406564584124654e-324",
@@ -153,27 +153,27 @@ static void DefineFloatMacros(MacroBuilder &Builder, llvm::StringRef Prefix,
Builder.defineMacro(DefPrefix + "DENORM_MIN__", DenormMin);
Builder.defineMacro(DefPrefix + "HAS_DENORM__");
- Builder.defineMacro(DefPrefix + "DIG__", llvm::Twine(Digits));
- Builder.defineMacro(DefPrefix + "EPSILON__", llvm::Twine(Epsilon));
+ Builder.defineMacro(DefPrefix + "DIG__", Twine(Digits));
+ Builder.defineMacro(DefPrefix + "EPSILON__", Twine(Epsilon));
Builder.defineMacro(DefPrefix + "HAS_INFINITY__");
Builder.defineMacro(DefPrefix + "HAS_QUIET_NAN__");
- Builder.defineMacro(DefPrefix + "MANT_DIG__", llvm::Twine(MantissaDigits));
+ Builder.defineMacro(DefPrefix + "MANT_DIG__", Twine(MantissaDigits));
- Builder.defineMacro(DefPrefix + "MAX_10_EXP__", llvm::Twine(Max10Exp));
- Builder.defineMacro(DefPrefix + "MAX_EXP__", llvm::Twine(MaxExp));
- Builder.defineMacro(DefPrefix + "MAX__", llvm::Twine(Max));
+ Builder.defineMacro(DefPrefix + "MAX_10_EXP__", Twine(Max10Exp));
+ Builder.defineMacro(DefPrefix + "MAX_EXP__", Twine(MaxExp));
+ Builder.defineMacro(DefPrefix + "MAX__", Twine(Max));
- Builder.defineMacro(DefPrefix + "MIN_10_EXP__","("+llvm::Twine(Min10Exp)+")");
- Builder.defineMacro(DefPrefix + "MIN_EXP__", "("+llvm::Twine(MinExp)+")");
- Builder.defineMacro(DefPrefix + "MIN__", llvm::Twine(Min));
+ Builder.defineMacro(DefPrefix + "MIN_10_EXP__","("+Twine(Min10Exp)+")");
+ Builder.defineMacro(DefPrefix + "MIN_EXP__", "("+Twine(MinExp)+")");
+ Builder.defineMacro(DefPrefix + "MIN__", Twine(Min));
}
/// DefineTypeSize - Emit a macro to the predefines buffer that declares a macro
/// named MacroName with the max value for a type with width 'TypeWidth' a
/// signedness of 'isSigned' and with a value suffix of 'ValSuffix' (e.g. LL).
-static void DefineTypeSize(llvm::StringRef MacroName, unsigned TypeWidth,
- llvm::StringRef ValSuffix, bool isSigned,
+static void DefineTypeSize(StringRef MacroName, unsigned TypeWidth,
+ StringRef ValSuffix, bool isSigned,
MacroBuilder &Builder) {
llvm::APInt MaxVal = isSigned ? llvm::APInt::getSignedMaxValue(TypeWidth)
: llvm::APInt::getMaxValue(TypeWidth);
@@ -182,26 +182,26 @@ static void DefineTypeSize(llvm::StringRef MacroName, unsigned TypeWidth,
/// DefineTypeSize - An overloaded helper that uses TargetInfo to determine
/// the width, suffix, and signedness of the given type
-static void DefineTypeSize(llvm::StringRef MacroName, TargetInfo::IntType Ty,
+static void DefineTypeSize(StringRef MacroName, TargetInfo::IntType Ty,
const TargetInfo &TI, MacroBuilder &Builder) {
DefineTypeSize(MacroName, TI.getTypeWidth(Ty), TI.getTypeConstantSuffix(Ty),
TI.isTypeSigned(Ty), Builder);
}
-static void DefineType(const llvm::Twine &MacroName, TargetInfo::IntType Ty,
+static void DefineType(const Twine &MacroName, TargetInfo::IntType Ty,
MacroBuilder &Builder) {
Builder.defineMacro(MacroName, TargetInfo::getTypeName(Ty));
}
-static void DefineTypeWidth(llvm::StringRef MacroName, TargetInfo::IntType Ty,
+static void DefineTypeWidth(StringRef MacroName, TargetInfo::IntType Ty,
const TargetInfo &TI, MacroBuilder &Builder) {
- Builder.defineMacro(MacroName, llvm::Twine(TI.getTypeWidth(Ty)));
+ Builder.defineMacro(MacroName, Twine(TI.getTypeWidth(Ty)));
}
-static void DefineTypeSizeof(llvm::StringRef MacroName, unsigned BitWidth,
+static void DefineTypeSizeof(StringRef MacroName, unsigned BitWidth,
const TargetInfo &TI, MacroBuilder &Builder) {
Builder.defineMacro(MacroName,
- llvm::Twine(BitWidth / TI.getCharWidth()));
+ Twine(BitWidth / TI.getCharWidth()));
}
static void DefineExactWidthIntType(TargetInfo::IntType Ty,
@@ -213,81 +213,15 @@ static void DefineExactWidthIntType(TargetInfo::IntType Ty,
if (TypeWidth == 64)
Ty = TI.getInt64Type();
- DefineType("__INT" + llvm::Twine(TypeWidth) + "_TYPE__", Ty, Builder);
+ DefineType("__INT" + Twine(TypeWidth) + "_TYPE__", Ty, Builder);
- llvm::StringRef ConstSuffix(TargetInfo::getTypeConstantSuffix(Ty));
+ StringRef ConstSuffix(TargetInfo::getTypeConstantSuffix(Ty));
if (!ConstSuffix.empty())
- Builder.defineMacro("__INT" + llvm::Twine(TypeWidth) + "_C_SUFFIX__",
+ Builder.defineMacro("__INT" + Twine(TypeWidth) + "_C_SUFFIX__",
ConstSuffix);
}
/// \brief Add definitions required for a smooth interaction between
-/// Objective-C++ automatic reference counting and libc++.
-static void AddObjCXXARCLibcxxDefines(const LangOptions &LangOpts,
- MacroBuilder &Builder) {
- Builder.defineMacro("_LIBCPP_PREDEFINED_OBJC_ARC_ADDRESSOF");
-
- std::string Result;
- {
- // Provide overloads of the function std::__1::addressof() that accept
- // references to lifetime-qualified objects. libc++'s (more general)
- // std::__1::addressof() template fails to instantiate with such types,
- // because it attempts to convert the object to a char& before
- // dereferencing.
- llvm::raw_string_ostream Out(Result);
-
- Out << "#pragma clang diagnostic push\n"
- << "#pragma clang diagnostic ignored \"-Wc++0x-extensions\"\n"
- << "namespace std { inline namespace __1 {\n"
- << "\n";
-
- Out << "template <class _Tp>\n"
- << "inline __attribute__ ((__visibility__(\"hidden\"), "
- << "__always_inline__))\n"
- << "__attribute__((objc_ownership(strong))) _Tp*\n"
- << "addressof(__attribute__((objc_ownership(strong))) _Tp& __x) {\n"
- << " return &__x;\n"
- << "}\n"
- << "\n";
-
- if (LangOpts.ObjCRuntimeHasWeak) {
- Out << "template <class _Tp>\n"
- << "inline __attribute__ ((__visibility__(\"hidden\"),"
- << "__always_inline__))\n"
- << "__attribute__((objc_ownership(weak))) _Tp*\n"
- << "addressof(__attribute__((objc_ownership(weak))) _Tp& __x) {\n"
- << " return &__x;\n"
- << "};\n"
- << "\n";
- }
-
- Out << "template <class _Tp>\n"
- << "inline __attribute__ ((__visibility__(\"hidden\"),"
- << "__always_inline__))\n"
- << "__attribute__((objc_ownership(autoreleasing))) _Tp*\n"
- << "addressof(__attribute__((objc_ownership(autoreleasing))) _Tp& __x) "
- << "{\n"
- << " return &__x;\n"
- << "}\n"
- << "\n";
-
- Out << "template <class _Tp>\n"
- << "inline __attribute__ ((__visibility__(\"hidden\"), "
- << "__always_inline__))\n"
- << "__unsafe_unretained _Tp* addressof(__unsafe_unretained _Tp& __x)"
- << " {\n"
- << " return &__x;\n"
- << "}\n";
-
- Out << "\n"
- << "} }\n"
- << "#pragma clang diagnostic pop\n"
- << "\n";
- }
- Builder.append(Result);
-}
-
-/// \brief Add definitions required for a smooth interaction between
/// Objective-C++ automated reference counting and libstdc++ (4.2).
static void AddObjCXXARCLibstdcxxDefines(const LangOptions &LangOpts,
MacroBuilder &Builder) {
@@ -344,7 +278,7 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
const LangOptions &LangOpts,
const FrontendOptions &FEOpts,
MacroBuilder &Builder) {
- if (!LangOpts.Microsoft && !LangOpts.TraditionalCPP)
+ if (!LangOpts.MicrosoftExt && !LangOpts.TraditionalCPP)
Builder.defineMacro("__STDC__");
if (LangOpts.Freestanding)
Builder.defineMacro("__STDC_HOSTED__", "0");
@@ -412,7 +346,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// checks that it is necessary to report 4.2.1 (the base GCC version we claim
// compatibility with) first.
Builder.defineMacro("__VERSION__", "\"4.2.1 Compatible " +
- llvm::Twine(getClangFullCPPVersion()) + "\"");
+ Twine(getClangFullCPPVersion()) + "\"");
// Initialize language-specific preprocessor defines.
@@ -426,10 +360,12 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (LangOpts.ObjC1) {
if (LangOpts.ObjCNonFragileABI) {
Builder.defineMacro("__OBJC2__");
- Builder.defineMacro("OBJC_ZEROCOST_EXCEPTIONS");
+
+ if (LangOpts.ObjCExceptions)
+ Builder.defineMacro("OBJC_ZEROCOST_EXCEPTIONS");
}
- if (LangOpts.getGCMode() != LangOptions::NonGC)
+ if (LangOpts.getGC() != LangOptions::NonGC)
Builder.defineMacro("__OBJC_GC__");
if (LangOpts.NeXTRuntime)
@@ -452,7 +388,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__BLOCKS__");
}
- if (LangOpts.Exceptions)
+ if (LangOpts.CXXExceptions)
Builder.defineMacro("__EXCEPTIONS");
if (LangOpts.RTTI)
Builder.defineMacro("__GXX_RTTI");
@@ -468,7 +404,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__private_extern__", "extern");
}
- if (LangOpts.Microsoft) {
+ if (LangOpts.MicrosoftExt) {
// Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however
// VC++ appears to only like __FUNCTION__.
Builder.defineMacro("__PRETTY_FUNCTION__", "__FUNCTION__");
@@ -546,7 +482,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// Define a __POINTER_WIDTH__ macro for stdint.h.
Builder.defineMacro("__POINTER_WIDTH__",
- llvm::Twine((int)TI.getPointerWidth(0)));
+ Twine((int)TI.getPointerWidth(0)));
if (!LangOpts.CharIsSigned)
Builder.defineMacro("__CHAR_UNSIGNED__");
@@ -555,7 +491,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__WINT_UNSIGNED__");
// Define exact-width integer types for stdint.h
- Builder.defineMacro("__INT" + llvm::Twine(TI.getCharWidth()) + "_TYPE__",
+ Builder.defineMacro("__INT" + Twine(TI.getCharWidth()) + "_TYPE__",
"char");
if (TI.getShortWidth() > TI.getCharWidth())
@@ -589,19 +525,19 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__NO_INLINE__");
if (unsigned PICLevel = LangOpts.PICLevel) {
- Builder.defineMacro("__PIC__", llvm::Twine(PICLevel));
- Builder.defineMacro("__pic__", llvm::Twine(PICLevel));
+ Builder.defineMacro("__PIC__", Twine(PICLevel));
+ Builder.defineMacro("__pic__", Twine(PICLevel));
}
// Macros to control C99 numerics and <float.h>
Builder.defineMacro("__FLT_EVAL_METHOD__", "0");
Builder.defineMacro("__FLT_RADIX__", "2");
int Dig = PickFP(&TI.getLongDoubleFormat(), -1/*FIXME*/, 17, 21, 33, 36);
- Builder.defineMacro("__DECIMAL_DIG__", llvm::Twine(Dig));
+ Builder.defineMacro("__DECIMAL_DIG__", Twine(Dig));
- if (LangOpts.getStackProtectorMode() == LangOptions::SSPOn)
+ if (LangOpts.getStackProtector() == LangOptions::SSPOn)
Builder.defineMacro("__SSP__");
- else if (LangOpts.getStackProtectorMode() == LangOptions::SSPReq)
+ else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
Builder.defineMacro("__SSP_ALL__", "2");
if (FEOpts.ProgramAction == frontend::RewriteObjC)
@@ -629,7 +565,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// Initialize the remapping of files to alternative contents, e.g.,
// those specified through other files.
-static void InitializeFileRemapping(Diagnostic &Diags,
+static void InitializeFileRemapping(DiagnosticsEngine &Diags,
SourceManager &SourceMgr,
FileManager &FileMgr,
const PreprocessorOptions &InitOpts) {
@@ -705,6 +641,10 @@ void clang::InitializePreprocessor(Preprocessor &PP,
InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(),
PP.getFileManager(), InitOpts);
+ // Specify whether the preprocessor should replace #include/#import with
+ // module imports when plausible.
+ PP.setAutoModuleImport(InitOpts.AutoModuleImport);
+
// Emit line markers for various builtin sections of the file. We don't do
// this in asm preprocessor mode, because "# 4" is not a line marker directive
// in this mode.
@@ -720,10 +660,7 @@ void clang::InitializePreprocessor(Preprocessor &PP,
if (LangOpts.ObjC1 && LangOpts.CPlusPlus && LangOpts.ObjCAutoRefCount) {
switch (InitOpts.ObjCXXARCStandardLibrary) {
case ARCXX_nolib:
- break;
-
- case ARCXX_libcxx:
- AddObjCXXARCLibcxxDefines(LangOpts, Builder);
+ case ARCXX_libcxx:
break;
case ARCXX_libstdcxx:
@@ -778,7 +715,7 @@ void clang::InitializePreprocessor(Preprocessor &PP,
// Copy PredefinedBuffer into the Preprocessor.
PP.setPredefines(Predefines.str());
-
+
// Initialize the header search object.
ApplyHeaderSearchOptions(PP.getHeaderSearchInfo(), HSOpts,
PP.getLangOptions(),
diff --git a/lib/Frontend/LangStandards.cpp b/lib/Frontend/LangStandards.cpp
index af1721d0f9ec..abb521ba27f2 100644
--- a/lib/Frontend/LangStandards.cpp
+++ b/lib/Frontend/LangStandards.cpp
@@ -29,7 +29,7 @@ const LangStandard &LangStandard::getLangStandardForKind(Kind K) {
}
}
-const LangStandard *LangStandard::getLangStandardForName(llvm::StringRef Name) {
+const LangStandard *LangStandard::getLangStandardForName(StringRef Name) {
Kind K = llvm::StringSwitch<Kind>(Name)
#define LANGSTANDARD(id, name, desc, features) \
.Case(name, lang_##id)
diff --git a/lib/Frontend/LogDiagnosticPrinter.cpp b/lib/Frontend/LogDiagnosticPrinter.cpp
index 78eb1b212836..8b585be90ec4 100644
--- a/lib/Frontend/LogDiagnosticPrinter.cpp
+++ b/lib/Frontend/LogDiagnosticPrinter.cpp
@@ -14,7 +14,7 @@
#include "llvm/Support/raw_ostream.h"
using namespace clang;
-LogDiagnosticPrinter::LogDiagnosticPrinter(llvm::raw_ostream &os,
+LogDiagnosticPrinter::LogDiagnosticPrinter(raw_ostream &os,
const DiagnosticOptions &diags,
bool _OwnsOutputStream)
: OS(os), LangOpts(0), DiagOpts(&diags),
@@ -26,15 +26,30 @@ LogDiagnosticPrinter::~LogDiagnosticPrinter() {
delete &OS;
}
-static llvm::StringRef getLevelName(Diagnostic::Level Level) {
+static StringRef getLevelName(DiagnosticsEngine::Level Level) {
switch (Level) {
default:
return "<unknown>";
- case Diagnostic::Ignored: return "ignored";
- case Diagnostic::Note: return "note";
- case Diagnostic::Warning: return "warning";
- case Diagnostic::Error: return "error";
- case Diagnostic::Fatal: return "fatal error";
+ case DiagnosticsEngine::Ignored: return "ignored";
+ case DiagnosticsEngine::Note: return "note";
+ case DiagnosticsEngine::Warning: return "warning";
+ case DiagnosticsEngine::Error: return "error";
+ case DiagnosticsEngine::Fatal: return "fatal error";
+ }
+}
+
+// Escape XML characters inside the raw string.
+static void emitString(llvm::raw_svector_ostream &OS, const StringRef Raw) {
+ for (StringRef::iterator I = Raw.begin(), E = Raw.end(); I != E; ++I) {
+ char c = *I;
+ switch (c) {
+ default: OS << c; break;
+ case '&': OS << "&amp;"; break;
+ case '<': OS << "&lt;"; break;
+ case '>': OS << "&gt;"; break;
+ case '\'': OS << "&apos;"; break;
+ case '\"': OS << "&quot;"; break;
+ }
}
}
@@ -42,9 +57,9 @@ void LogDiagnosticPrinter::EndSourceFile() {
// We emit all the diagnostics in EndSourceFile. However, we don't emit any
// entry if no diagnostics were present.
//
- // Note that DiagnosticClient has no "end-of-compilation" callback, so we will
- // miss any diagnostics which are emitted after and outside the translation
- // unit processing.
+ // Note that DiagnosticConsumer has no "end-of-compilation" callback, so we
+ // will miss any diagnostics which are emitted after and outside the
+ // translation unit processing.
if (Entries.empty())
return;
@@ -55,11 +70,15 @@ void LogDiagnosticPrinter::EndSourceFile() {
OS << "<dict>\n";
if (!MainFilename.empty()) {
OS << " <key>main-file</key>\n"
- << " <string>" << MainFilename << "</string>\n";
+ << " <string>";
+ emitString(OS, MainFilename);
+ OS << "</string>\n";
}
if (!DwarfDebugFlags.empty()) {
OS << " <key>dwarf-debug-flags</key>\n"
- << " <string>" << DwarfDebugFlags << "</string>\n";
+ << " <string>";
+ emitString(OS, DwarfDebugFlags);
+ OS << "</string>\n";
}
OS << " <key>diagnostics</key>\n";
OS << " <array>\n";
@@ -68,10 +87,14 @@ void LogDiagnosticPrinter::EndSourceFile() {
OS << " <dict>\n";
OS << " <key>level</key>\n"
- << " <string>" << getLevelName(DE.DiagnosticLevel) << "</string>\n";
+ << " <string>";
+ emitString(OS, getLevelName(DE.DiagnosticLevel));
+ OS << "</string>\n";
if (!DE.Filename.empty()) {
OS << " <key>filename</key>\n"
- << " <string>" << DE.Filename << "</string>\n";
+ << " <string>";
+ emitString(OS, DE.Filename);
+ OS << "</string>\n";
}
if (DE.Line != 0) {
OS << " <key>line</key>\n"
@@ -83,7 +106,9 @@ void LogDiagnosticPrinter::EndSourceFile() {
}
if (!DE.Message.empty()) {
OS << " <key>message</key>\n"
- << " <string>" << DE.Message << "</string>\n";
+ << " <string>";
+ emitString(OS, DE.Message);
+ OS << "</string>\n";
}
OS << " </dict>\n";
}
@@ -93,10 +118,10 @@ void LogDiagnosticPrinter::EndSourceFile() {
this->OS << OS.str();
}
-void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
- const DiagnosticInfo &Info) {
+void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
+ const Diagnostic &Info) {
// Default implementation (Warnings/errors count).
- DiagnosticClient::HandleDiagnostic(Level, Info);
+ DiagnosticConsumer::HandleDiagnostic(Level, Info);
// Initialize the main file name, if we haven't already fetched it.
if (MainFilename.empty() && Info.hasSourceManager()) {
@@ -144,3 +169,9 @@ void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
// Record the diagnostic entry.
Entries.push_back(DE);
}
+
+DiagnosticConsumer *
+LogDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const {
+ return new LogDiagnosticPrinter(OS, *DiagOpts, /*OwnsOutputStream=*/false);
+}
+
diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp
index 5aa65d7a60aa..8e746f65a906 100644
--- a/lib/Frontend/MultiplexConsumer.cpp
+++ b/lib/Frontend/MultiplexConsumer.cpp
@@ -37,7 +37,7 @@ public:
virtual void TypeRead(serialization::TypeIdx Idx, QualType T);
virtual void DeclRead(serialization::DeclID ID, const Decl *D);
virtual void SelectorRead(serialization::SelectorID iD, Selector Sel);
- virtual void MacroDefinitionRead(serialization::MacroID,
+ virtual void MacroDefinitionRead(serialization::PreprocessedEntityID,
MacroDefinition *MD);
private:
std::vector<ASTDeserializationListener*> Listeners;
@@ -79,7 +79,7 @@ void MultiplexASTDeserializationListener::SelectorRead(
}
void MultiplexASTDeserializationListener::MacroDefinitionRead(
- serialization::MacroID ID, MacroDefinition *MD) {
+ serialization::PreprocessedEntityID ID, MacroDefinition *MD) {
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->MacroDefinitionRead(ID, MD);
}
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index c892960a18b9..8a61f968e67f 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -33,7 +33,7 @@ using namespace clang;
/// PrintMacroDefinition - Print a macro definition in a form that will be
/// properly accepted back as a definition.
static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI,
- Preprocessor &PP, llvm::raw_ostream &OS) {
+ Preprocessor &PP, raw_ostream &OS) {
OS << "#define " << II.getName();
if (MI.isFunctionLike()) {
@@ -83,7 +83,7 @@ class PrintPPOutputPPCallbacks : public PPCallbacks {
SourceManager &SM;
TokenConcatenation ConcatInfo;
public:
- llvm::raw_ostream &OS;
+ raw_ostream &OS;
private:
unsigned CurLine;
@@ -96,7 +96,7 @@ private:
bool DumpDefines;
bool UseLineDirective;
public:
- PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os,
+ PrintPPOutputPPCallbacks(Preprocessor &pp, raw_ostream &os,
bool lineMarkers, bool defines)
: PP(pp), SM(PP.getSourceManager()),
ConcatInfo(PP), OS(os), DisableLineMarkers(lineMarkers),
@@ -109,7 +109,7 @@ public:
Initialized = false;
// If we're in microsoft mode, use normal #line instead of line markers.
- UseLineDirective = PP.getLangOptions().Microsoft;
+ UseLineDirective = PP.getLangOptions().MicrosoftExt;
}
void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; }
@@ -118,17 +118,18 @@ public:
bool StartNewLineIfNeeded();
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
- SrcMgr::CharacteristicKind FileType);
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID);
virtual void Ident(SourceLocation Loc, const std::string &str);
virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
const std::string &Str);
- virtual void PragmaMessage(SourceLocation Loc, llvm::StringRef Str);
+ virtual void PragmaMessage(SourceLocation Loc, StringRef Str);
virtual void PragmaDiagnosticPush(SourceLocation Loc,
- llvm::StringRef Namespace);
+ StringRef Namespace);
virtual void PragmaDiagnosticPop(SourceLocation Loc,
- llvm::StringRef Namespace);
- virtual void PragmaDiagnostic(SourceLocation Loc, llvm::StringRef Namespace,
- diag::Mapping Map, llvm::StringRef Str);
+ StringRef Namespace);
+ virtual void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace,
+ diag::Mapping Map, StringRef Str);
bool HandleFirstTokOnLine(Token &Tok);
bool MoveToLine(SourceLocation Loc) {
@@ -235,7 +236,8 @@ bool PrintPPOutputPPCallbacks::StartNewLineIfNeeded() {
/// position.
void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
FileChangeReason Reason,
- SrcMgr::CharacteristicKind NewFileType) {
+ SrcMgr::CharacteristicKind NewFileType,
+ FileID PrevFID) {
// Unless we are exiting a #include, make sure to skip ahead to the line the
// #include directive was at.
SourceManager &SourceMgr = SM;
@@ -346,7 +348,7 @@ void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
}
void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc,
- llvm::StringRef Str) {
+ StringRef Str) {
MoveToLine(Loc);
OS << "#pragma message(";
@@ -369,22 +371,22 @@ void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc,
}
void PrintPPOutputPPCallbacks::
-PragmaDiagnosticPush(SourceLocation Loc, llvm::StringRef Namespace) {
+PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace) {
MoveToLine(Loc);
OS << "#pragma " << Namespace << " diagnostic push";
EmittedTokensOnThisLine = true;
}
void PrintPPOutputPPCallbacks::
-PragmaDiagnosticPop(SourceLocation Loc, llvm::StringRef Namespace) {
+PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) {
MoveToLine(Loc);
OS << "#pragma " << Namespace << " diagnostic pop";
EmittedTokensOnThisLine = true;
}
void PrintPPOutputPPCallbacks::
-PragmaDiagnostic(SourceLocation Loc, llvm::StringRef Namespace,
- diag::Mapping Map, llvm::StringRef Str) {
+PragmaDiagnostic(SourceLocation Loc, StringRef Namespace,
+ diag::Mapping Map, StringRef Str) {
MoveToLine(Loc);
OS << "#pragma " << Namespace << " diagnostic ";
switch (Map) {
@@ -419,7 +421,7 @@ bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) {
// Print out space characters so that the first token on a line is
// indented for easy reading.
- unsigned ColNo = SM.getInstantiationColumnNumber(Tok.getLocation());
+ unsigned ColNo = SM.getExpansionColumnNumber(Tok.getLocation());
// This hack prevents stuff like:
// #define HASH #
@@ -491,7 +493,7 @@ struct UnknownPragmaHandler : public PragmaHandler {
static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
PrintPPOutputPPCallbacks *Callbacks,
- llvm::raw_ostream &OS) {
+ raw_ostream &OS) {
char Buffer[256];
Token PrevPrevTok, PrevTok;
PrevPrevTok.startToken();
@@ -550,7 +552,7 @@ static int MacroIDCompare(const void* a, const void* b) {
return LHS->first->getName().compare(RHS->first->getName());
}
-static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) {
+static void DoPrintMacros(Preprocessor &PP, raw_ostream *OS) {
// Ignore unknown pragmas.
PP.AddPragmaHandler(new EmptyPragmaHandler());
@@ -562,7 +564,7 @@ static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) {
do PP.Lex(Tok);
while (Tok.isNot(tok::eof));
- llvm::SmallVector<id_macro_pair, 128>
+ SmallVector<id_macro_pair, 128>
MacrosByID(PP.macro_begin(), PP.macro_end());
llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(), MacroIDCompare);
@@ -578,7 +580,7 @@ static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) {
/// DoPrintPreprocessedInput - This implements -E mode.
///
-void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS,
+void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS,
const PreprocessorOutputOptions &Opts) {
// Show macros with no output is handled specially.
if (!Opts.ShowCPP) {
diff --git a/lib/Frontend/TextDiagnosticBuffer.cpp b/lib/Frontend/TextDiagnosticBuffer.cpp
index 069c86de137f..f8ea9f1361ab 100644
--- a/lib/Frontend/TextDiagnosticBuffer.cpp
+++ b/lib/Frontend/TextDiagnosticBuffer.cpp
@@ -13,39 +13,48 @@
#include "clang/Frontend/TextDiagnosticBuffer.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
/// HandleDiagnostic - Store the errors, warnings, and notes that are
/// reported.
///
-void TextDiagnosticBuffer::HandleDiagnostic(Diagnostic::Level Level,
- const DiagnosticInfo &Info) {
+void TextDiagnosticBuffer::HandleDiagnostic(DiagnosticsEngine::Level Level,
+ const Diagnostic &Info) {
// Default implementation (Warnings/errors count).
- DiagnosticClient::HandleDiagnostic(Level, Info);
+ DiagnosticConsumer::HandleDiagnostic(Level, Info);
llvm::SmallString<100> Buf;
Info.FormatDiagnostic(Buf);
switch (Level) {
- default: assert(0 && "Diagnostic not handled during diagnostic buffering!");
- case Diagnostic::Note:
+ default: llvm_unreachable(
+ "Diagnostic not handled during diagnostic buffering!");
+ case DiagnosticsEngine::Note:
Notes.push_back(std::make_pair(Info.getLocation(), Buf.str()));
break;
- case Diagnostic::Warning:
+ case DiagnosticsEngine::Warning:
Warnings.push_back(std::make_pair(Info.getLocation(), Buf.str()));
break;
- case Diagnostic::Error:
- case Diagnostic::Fatal:
+ case DiagnosticsEngine::Error:
+ case DiagnosticsEngine::Fatal:
Errors.push_back(std::make_pair(Info.getLocation(), Buf.str()));
break;
}
}
-void TextDiagnosticBuffer::FlushDiagnostics(Diagnostic &Diags) const {
+void TextDiagnosticBuffer::FlushDiagnostics(DiagnosticsEngine &Diags) const {
// FIXME: Flush the diagnostics in order.
for (const_iterator it = err_begin(), ie = err_end(); it != ie; ++it)
- Diags.Report(Diags.getCustomDiagID(Diagnostic::Error, it->second.c_str()));
+ Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ it->second.c_str()));
for (const_iterator it = warn_begin(), ie = warn_end(); it != ie; ++it)
- Diags.Report(Diags.getCustomDiagID(Diagnostic::Warning,it->second.c_str()));
+ Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Warning,
+ it->second.c_str()));
for (const_iterator it = note_begin(), ie = note_end(); it != ie; ++it)
- Diags.Report(Diags.getCustomDiagID(Diagnostic::Note, it->second.c_str()));
+ Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Note,
+ it->second.c_str()));
+}
+
+DiagnosticConsumer *TextDiagnosticBuffer::clone(DiagnosticsEngine &) const {
+ return new TextDiagnosticBuffer();
}
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index e49e19a17c8d..10e7238218cb 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -18,29 +18,29 @@
#include "clang/Lex/Lexer.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringExtras.h"
#include <algorithm>
using namespace clang;
-static const enum llvm::raw_ostream::Colors noteColor =
- llvm::raw_ostream::BLACK;
-static const enum llvm::raw_ostream::Colors fixitColor =
- llvm::raw_ostream::GREEN;
-static const enum llvm::raw_ostream::Colors caretColor =
- llvm::raw_ostream::GREEN;
-static const enum llvm::raw_ostream::Colors warningColor =
- llvm::raw_ostream::MAGENTA;
-static const enum llvm::raw_ostream::Colors errorColor = llvm::raw_ostream::RED;
-static const enum llvm::raw_ostream::Colors fatalColor = llvm::raw_ostream::RED;
+static const enum raw_ostream::Colors noteColor =
+ raw_ostream::BLACK;
+static const enum raw_ostream::Colors fixitColor =
+ raw_ostream::GREEN;
+static const enum raw_ostream::Colors caretColor =
+ raw_ostream::GREEN;
+static const enum raw_ostream::Colors warningColor =
+ raw_ostream::MAGENTA;
+static const enum raw_ostream::Colors errorColor = raw_ostream::RED;
+static const enum raw_ostream::Colors fatalColor = raw_ostream::RED;
// Used for changing only the bold attribute.
-static const enum llvm::raw_ostream::Colors savedColor =
- llvm::raw_ostream::SAVEDCOLOR;
+static const enum raw_ostream::Colors savedColor =
+ raw_ostream::SAVEDCOLOR;
/// \brief Number of spaces to indent when word-wrapping.
const unsigned WordWrapIndentation = 6;
-TextDiagnosticPrinter::TextDiagnosticPrinter(llvm::raw_ostream &os,
+TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &os,
const DiagnosticOptions &diags,
bool _OwnsOutputStream)
: OS(os), LangOpts(0), DiagOpts(&diags),
@@ -53,105 +53,52 @@ TextDiagnosticPrinter::~TextDiagnosticPrinter() {
delete &OS;
}
-void TextDiagnosticPrinter::PrintIncludeStack(Diagnostic::Level Level,
- SourceLocation Loc,
- const SourceManager &SM) {
- if (!DiagOpts->ShowNoteIncludeStack && Level == Diagnostic::Note) return;
-
- if (Loc.isInvalid()) return;
+/// \brief Helper to recursivly walk up the include stack and print each layer
+/// on the way back down.
+static void PrintIncludeStackRecursively(raw_ostream &OS,
+ const SourceManager &SM,
+ SourceLocation Loc,
+ bool ShowLocation) {
+ if (Loc.isInvalid())
+ return;
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
if (PLoc.isInvalid())
return;
-
+
// Print out the other include frames first.
- PrintIncludeStack(Level, PLoc.getIncludeLoc(), SM);
+ PrintIncludeStackRecursively(OS, SM, PLoc.getIncludeLoc(), ShowLocation);
- if (DiagOpts->ShowLocation)
+ if (ShowLocation)
OS << "In file included from " << PLoc.getFilename()
<< ':' << PLoc.getLine() << ":\n";
else
OS << "In included file:\n";
}
-/// HighlightRange - Given a SourceRange and a line number, highlight (with ~'s)
-/// any characters in LineNo that intersect the SourceRange.
-void TextDiagnosticPrinter::HighlightRange(const CharSourceRange &R,
- const SourceManager &SM,
- unsigned LineNo, FileID FID,
- std::string &CaretLine,
- const std::string &SourceLine) {
- assert(CaretLine.size() == SourceLine.size() &&
- "Expect a correspondence between source and caret line!");
- if (!R.isValid()) return;
-
- SourceLocation Begin = SM.getInstantiationLoc(R.getBegin());
- SourceLocation End = SM.getInstantiationLoc(R.getEnd());
-
- // If the End location and the start location are the same and are a macro
- // location, then the range was something that came from a macro expansion
- // or _Pragma. If this is an object-like macro, the best we can do is to
- // highlight the range. If this is a function-like macro, we'd also like to
- // highlight the arguments.
- if (Begin == End && R.getEnd().isMacroID())
- End = SM.getInstantiationRange(R.getEnd()).second;
-
- unsigned StartLineNo = SM.getInstantiationLineNumber(Begin);
- if (StartLineNo > LineNo || SM.getFileID(Begin) != FID)
- return; // No intersection.
-
- unsigned EndLineNo = SM.getInstantiationLineNumber(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.getInstantiationColumnNumber(Begin);
- if (StartColNo) --StartColNo; // Zero base the col #.
- }
-
- // Compute the column number of the end.
- unsigned EndColNo = CaretLine.size();
- if (EndLineNo == LineNo) {
- EndColNo = SM.getInstantiationColumnNumber(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();
- }
- }
+/// \brief Prints an include stack when appropriate for a particular diagnostic
+/// level and location.
+///
+/// This routine handles all the logic of suppressing particular include stacks
+/// (such as those for notes) and duplicate include stacks when repeated
+/// warnings occur within the same file. It also handles the logic of
+/// customizing the formatting and display of the include stack.
+///
+/// \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 TextDiagnosticPrinter::PrintIncludeStack(DiagnosticsEngine::Level Level,
+ SourceLocation Loc,
+ const SourceManager &SM) {
+ // Skip redundant include stacks altogether.
+ if (LastWarningLoc == Loc)
+ return;
+ LastWarningLoc = Loc;
- 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 < SourceLine.size() &&
- (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t'))
- ++StartColNo;
-
- // Pick the last non-whitespace column.
- if (EndColNo > SourceLine.size())
- EndColNo = SourceLine.size();
- while (EndColNo-1 &&
- (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t'))
- --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??");
- }
+ if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
+ return;
- // Fill the range with ~'s.
- for (unsigned i = StartColNo; i < EndColNo; ++i)
- CaretLine[i] = '~';
+ PrintIncludeStackRecursively(OS, SM, Loc, DiagOpts->ShowLocation);
}
/// \brief When the source code line we want to print is too long for
@@ -300,7 +247,7 @@ static SourceLocation skipToMacroArgExpansion(const SourceManager &SM,
SourceLocation StartLoc) {
for (SourceLocation L = StartLoc; L.isMacroID();
L = SM.getImmediateSpellingLoc(L)) {
- if (SM.isMacroArgInstantiation(L))
+ if (SM.isMacroArgExpansion(L))
return L;
}
@@ -317,12 +264,12 @@ static SourceLocation getImmediateMacroCallerLoc(const SourceManager &SM,
// When we have the location of (part of) an expanded parameter, its spelling
// location points to the argument as typed into the macro call, and
// therefore is used to locate the macro caller.
- if (SM.isMacroArgInstantiation(Loc))
+ if (SM.isMacroArgExpansion(Loc))
return SM.getImmediateSpellingLoc(Loc);
// Otherwise, the caller of the macro is located where this macro is
// expanded (while the spelling is part of the macro definition).
- return SM.getImmediateInstantiationRange(Loc).first;
+ return SM.getImmediateExpansionRange(Loc).first;
}
/// Gets the location of the immediate macro callee, one level down the stack
@@ -334,34 +281,82 @@ static SourceLocation getImmediateMacroCalleeLoc(const SourceManager &SM,
// When we have the location of (part of) an expanded parameter, its
// expansion location points to the unexpanded paramater reference within
// the macro definition (or callee).
- if (SM.isMacroArgInstantiation(Loc))
- return SM.getImmediateInstantiationRange(Loc).first;
+ if (SM.isMacroArgExpansion(Loc))
+ return SM.getImmediateExpansionRange(Loc).first;
// Otherwise, the callee of the macro is located where this location was
// spelled inside the macro definition.
return SM.getImmediateSpellingLoc(Loc);
}
-void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
- CharSourceRange *Ranges,
- unsigned NumRanges,
- const SourceManager &SM,
- const FixItHint *Hints,
- unsigned NumHints,
- unsigned Columns,
- unsigned OnMacroInst,
- unsigned MacroSkipStart,
- unsigned MacroSkipEnd) {
- assert(LangOpts && "Unexpected diagnostic outside source file processing");
- assert(!Loc.isInvalid() && "must have a valid source location here");
+namespace {
- // If this is a macro ID, first emit information about where this was
- // expanded (recursively) then emit information about where the token was
- // spelled from.
- if (!Loc.isFileID()) {
- // Whether to suppress printing this macro expansion.
- bool Suppressed
- = OnMacroInst >= MacroSkipStart && OnMacroInst < MacroSkipEnd;
+/// \brief Class to encapsulate the logic for formatting and printing a textual
+/// diagnostic message.
+///
+/// This class provides an interface for building and emitting a textual
+/// diagnostic, including all of the macro backtraces, caret diagnostics, FixIt
+/// Hints, and code snippets. In the presence of macros this involves
+/// a recursive process, synthesizing notes for each macro expansion.
+///
+/// The purpose of this class is to isolate the implementation of printing
+/// beautiful text diagnostics from any particular interfaces. The Clang
+/// DiagnosticClient is implemented through this class as is diagnostic
+/// printing coming out of libclang.
+///
+/// A brief worklist:
+/// FIXME: Sink the printing of the diagnostic message itself into this class.
+/// FIXME: Sink the printing of the include stack into this class.
+/// FIXME: Remove the TextDiagnosticPrinter as an input.
+/// FIXME: Sink the recursive printing of template instantiations into this
+/// class.
+class TextDiagnostic {
+ TextDiagnosticPrinter &Printer;
+ raw_ostream &OS;
+ const SourceManager &SM;
+ const LangOptions &LangOpts;
+ const DiagnosticOptions &DiagOpts;
+
+public:
+ TextDiagnostic(TextDiagnosticPrinter &Printer,
+ raw_ostream &OS,
+ const SourceManager &SM,
+ const LangOptions &LangOpts,
+ const DiagnosticOptions &DiagOpts)
+ : Printer(Printer), OS(OS), SM(SM), LangOpts(LangOpts), DiagOpts(DiagOpts) {
+ }
+
+ /// \brief Emit the caret and underlining text.
+ ///
+ /// Walks up the macro expansion stack printing the code snippet, caret,
+ /// underlines and FixItHint display as appropriate at each level. Walk is
+ /// accomplished by calling itself recursively.
+ ///
+ /// FIXME: Remove macro expansion from this routine, it shouldn't be tied to
+ /// caret diagnostics.
+ /// FIXME: Break up massive function into logical units.
+ ///
+ /// \param Loc The location for this caret.
+ /// \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 EmitCaret(SourceLocation Loc,
+ SmallVectorImpl<CharSourceRange>& Ranges,
+ ArrayRef<FixItHint> Hints,
+ unsigned &MacroDepth,
+ unsigned OnMacroInst = 0) {
+ 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()) {
+ assert(MacroDepth == 0 && "We shouldn't hit a leaf node twice!");
+ MacroDepth = OnMacroInst;
+ EmitSnippetAndCaret(Loc, Ranges, Hints);
+ 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.
@@ -370,21 +365,31 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
SourceLocation OneLevelUp = getImmediateMacroCallerLoc(SM, Loc);
// FIXME: Map ranges?
- EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM,
- Hints, NumHints, Columns,
- OnMacroInst + 1, MacroSkipStart, MacroSkipEnd);
+ EmitCaret(OneLevelUp, Ranges, Hints, MacroDepth, OnMacroInst + 1);
// Map the location.
Loc = getImmediateMacroCalleeLoc(SM, Loc);
+ unsigned MacroSkipStart = 0, MacroSkipEnd = 0;
+ if (MacroDepth > DiagOpts.MacroBacktraceLimit) {
+ MacroSkipStart = DiagOpts.MacroBacktraceLimit / 2 +
+ DiagOpts.MacroBacktraceLimit % 2;
+ MacroSkipEnd = MacroDepth - DiagOpts.MacroBacktraceLimit / 2;
+ }
+
+ // Whether to suppress printing this macro expansion.
+ bool Suppressed = (OnMacroInst >= MacroSkipStart &&
+ OnMacroInst < MacroSkipEnd);
+
// Map the ranges.
- for (unsigned i = 0; i != NumRanges; ++i) {
- CharSourceRange &R = Ranges[i];
- SourceLocation S = R.getBegin(), E = R.getEnd();
- if (S.isMacroID())
- R.setBegin(getImmediateMacroCalleeLoc(SM, S));
- if (E.isMacroID())
- R.setEnd(getImmediateMacroCalleeLoc(SM, E));
+ for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
+ E = Ranges.end();
+ I != E; ++I) {
+ SourceLocation Start = I->getBegin(), End = I->getEnd();
+ if (Start.isMacroID())
+ I->setBegin(getImmediateMacroCalleeLoc(SM, Start));
+ if (End.isMacroID())
+ I->setEnd(getImmediateMacroCalleeLoc(SM, End));
}
if (!Suppressed) {
@@ -398,139 +403,248 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
// If this diagnostic is not in the main file, print out the
// "included from" lines.
- if (LastWarningLoc != PLoc.getIncludeLoc()) {
- LastWarningLoc = PLoc.getIncludeLoc();
- PrintIncludeStack(Diagnostic::Note, LastWarningLoc, SM);
- }
+ Printer.PrintIncludeStack(DiagnosticsEngine::Note, PLoc.getIncludeLoc(),
+ SM);
- if (DiagOpts->ShowLocation) {
+ if (DiagOpts.ShowLocation) {
// Emit the file/line/column that this expansion came from.
OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':';
- if (DiagOpts->ShowColumn)
+ if (DiagOpts.ShowColumn)
OS << PLoc.getColumn() << ':';
OS << ' ';
}
OS << "note: expanded from:\n";
- EmitCaretDiagnostic(Loc, Ranges, NumRanges, SM, 0, 0,
- Columns, OnMacroInst + 1, MacroSkipStart,
- MacroSkipEnd);
+ EmitSnippetAndCaret(Loc, Ranges, ArrayRef<FixItHint>());
return;
}
-
+
if (OnMacroInst == MacroSkipStart) {
// Tell the user that we've skipped contexts.
OS << "note: (skipping " << (MacroSkipEnd - MacroSkipStart)
<< " expansions in backtrace; use -fmacro-backtrace-limit=0 to see "
"all)\n";
}
-
- return;
}
-
- // Decompose the location into a FID/Offset pair.
- std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
- FileID FID = LocInfo.first;
- unsigned FileOffset = LocInfo.second;
-
- // Get information about the buffer it points into.
- bool Invalid = false;
- const char *BufStart = SM.getBufferData(FID, &Invalid).data();
- if (Invalid)
- return;
- unsigned ColNo = SM.getColumnNumber(FID, FileOffset);
- unsigned CaretEndColNo
- = ColNo + Lexer::MeasureTokenLength(Loc, SM, *LangOpts);
+ /// \brief Emit a code snippet and caret line.
+ ///
+ /// This routine emits a single line's code snippet and caret line..
+ ///
+ /// \param Loc The location for the caret.
+ /// \param Ranges The underlined ranges for this code snippet.
+ /// \param Hints The FixIt hints active for this diagnostic.
+ void EmitSnippetAndCaret(SourceLocation Loc,
+ SmallVectorImpl<CharSourceRange>& Ranges,
+ ArrayRef<FixItHint> Hints) {
+ assert(!Loc.isInvalid() && "must have a valid source location here");
+ assert(Loc.isFileID() && "must have a file location here");
+
+ // Decompose the location into a FID/Offset pair.
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ FileID FID = LocInfo.first;
+ unsigned FileOffset = LocInfo.second;
+
+ // Get information about the buffer it points into.
+ bool Invalid = false;
+ const char *BufStart = SM.getBufferData(FID, &Invalid).data();
+ if (Invalid)
+ 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.
+ unsigned LineNo = SM.getLineNumber(FID, FileOffset);
+ unsigned ColNo = SM.getColumnNumber(FID, FileOffset);
+ unsigned CaretEndColNo
+ = ColNo + Lexer::MeasureTokenLength(Loc, SM, LangOpts);
+
+ // 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;
+
+ // FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past
+ // the source line length as currently being computed. See
+ // test/Misc/message-length.c.
+ CaretEndColNo = std::min(CaretEndColNo, unsigned(LineEnd - LineStart));
+
+ // Copy the line of code into an std::string for ease of manipulation.
+ std::string SourceLine(LineStart, LineEnd);
+
+ // Create a line for the caret that is filled with spaces that is the same
+ // length as the line of source code.
+ std::string CaretLine(LineEnd-LineStart, ' ');
+
+ // Highlight all of the characters covered by Ranges with ~ characters.
+ for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
+ E = Ranges.end();
+ I != E; ++I)
+ HighlightRange(*I, LineNo, FID, SourceLine, CaretLine);
+
+ // Next, insert the caret itself.
+ if (ColNo-1 < CaretLine.size())
+ CaretLine[ColNo-1] = '^';
+ else
+ CaretLine.push_back('^');
+
+ ExpandTabs(SourceLine, CaretLine);
+
+ // If we are in -fdiagnostics-print-source-range-info mode, we are trying
+ // to produce easily machine parsable output. Add a space before the
+ // source line and the caret to make it trivial to tell the main diagnostic
+ // line from what the user is intended to see.
+ if (DiagOpts.ShowSourceRanges) {
+ SourceLine = ' ' + SourceLine;
+ CaretLine = ' ' + CaretLine;
+ }
+ std::string FixItInsertionLine = BuildFixItInsertionLine(LineNo,
+ LineStart, LineEnd,
+ Hints);
- // 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;
+ // If the source line is too long for our terminal, select only the
+ // "interesting" source region within that line.
+ unsigned Columns = DiagOpts.MessageLength;
+ if (Columns && SourceLine.size() > Columns)
+ SelectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
+ CaretEndColNo, Columns);
- // FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past
- // the source line length as currently being computed. See
- // test/Misc/message-length.c.
- CaretEndColNo = std::min(CaretEndColNo, unsigned(LineEnd - LineStart));
+ // Finally, remove any blank spaces from the end of CaretLine.
+ while (CaretLine[CaretLine.size()-1] == ' ')
+ CaretLine.erase(CaretLine.end()-1);
- // Copy the line of code into an std::string for ease of manipulation.
- std::string SourceLine(LineStart, LineEnd);
+ // Emit what we have computed.
+ OS << SourceLine << '\n';
- // Create a line for the caret that is filled with spaces that is the same
- // length as the line of source code.
- std::string CaretLine(LineEnd-LineStart, ' ');
+ if (DiagOpts.ShowColors)
+ OS.changeColor(caretColor, true);
+ OS << CaretLine << '\n';
+ if (DiagOpts.ShowColors)
+ OS.resetColor();
- // Highlight all of the characters covered by Ranges with ~ characters.
- if (NumRanges) {
- unsigned LineNo = SM.getLineNumber(FID, FileOffset);
+ if (!FixItInsertionLine.empty()) {
+ if (DiagOpts.ShowColors)
+ // Print fixit line in color
+ OS.changeColor(fixitColor, false);
+ if (DiagOpts.ShowSourceRanges)
+ OS << ' ';
+ OS << FixItInsertionLine << '\n';
+ if (DiagOpts.ShowColors)
+ OS.resetColor();
+ }
- for (unsigned i = 0, e = NumRanges; i != e; ++i)
- HighlightRange(Ranges[i], SM, LineNo, FID, CaretLine, SourceLine);
+ // Print out any parseable fixit information requested by the options.
+ EmitParseableFixits(Hints);
}
- // Next, insert the caret itself.
- if (ColNo-1 < CaretLine.size())
- CaretLine[ColNo-1] = '^';
- else
- CaretLine.push_back('^');
-
- // Scan the source line, looking for tabs. If we find any, manually expand
- // them to spaces and update the CaretLine to match.
- for (unsigned i = 0; i != SourceLine.size(); ++i) {
- if (SourceLine[i] != '\t') continue;
-
- // Replace this tab with at least one space.
- SourceLine[i] = ' ';
-
- // Compute the number of spaces we need to insert.
- unsigned TabStop = DiagOpts->TabStop;
- assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop &&
- "Invalid -ftabstop value");
- unsigned NumSpaces = ((i+TabStop)/TabStop * TabStop) - (i+1);
- assert(NumSpaces < TabStop && "Invalid computation of space amt");
+private:
+ /// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo.
+ void HighlightRange(const CharSourceRange &R,
+ unsigned LineNo, FileID FID,
+ const std::string &SourceLine,
+ std::string &CaretLine) {
+ assert(CaretLine.size() == SourceLine.size() &&
+ "Expect a correspondence between source and caret line!");
+ if (!R.isValid()) return;
+
+ SourceLocation Begin = SM.getExpansionLoc(R.getBegin());
+ SourceLocation End = SM.getExpansionLoc(R.getEnd());
+
+ // If the End location and the start location are the same and are a macro
+ // location, then the range was something that came from a macro expansion
+ // or _Pragma. If this is an object-like macro, the best we can do is to
+ // highlight the range. If this is a function-like macro, we'd also like to
+ // highlight the arguments.
+ if (Begin == End && R.getEnd().isMacroID())
+ End = SM.getExpansionRange(R.getEnd()).second;
+
+ 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 #.
+ }
- // Insert spaces into the SourceLine.
- SourceLine.insert(i+1, NumSpaces, ' ');
+ // Compute the column number of the end.
+ unsigned EndColNo = CaretLine.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();
+ }
+ }
- // Insert spaces or ~'s into CaretLine.
- CaretLine.insert(i+1, NumSpaces, CaretLine[i] == '~' ? '~' : ' ');
- }
+ 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 < SourceLine.size() &&
+ (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t'))
+ ++StartColNo;
+
+ // Pick the last non-whitespace column.
+ if (EndColNo > SourceLine.size())
+ EndColNo = SourceLine.size();
+ while (EndColNo-1 &&
+ (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t'))
+ --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??");
+ }
- // If we are in -fdiagnostics-print-source-range-info mode, we are trying to
- // produce easily machine parsable output. Add a space before the source line
- // and the caret to make it trivial to tell the main diagnostic line from what
- // the user is intended to see.
- if (DiagOpts->ShowSourceRanges) {
- SourceLine = ' ' + SourceLine;
- CaretLine = ' ' + CaretLine;
+ // Fill the range with ~'s.
+ for (unsigned i = StartColNo; i < EndColNo; ++i)
+ CaretLine[i] = '~';
}
- std::string FixItInsertionLine;
- if (NumHints && DiagOpts->ShowFixits) {
- for (const FixItHint *Hint = Hints, *LastHint = Hints + NumHints;
- Hint != LastHint; ++Hint) {
- if (!Hint->CodeToInsert.empty()) {
+ std::string BuildFixItInsertionLine(unsigned LineNo,
+ const char *LineStart,
+ const char *LineEnd,
+ ArrayRef<FixItHint> Hints) {
+ std::string FixItInsertionLine;
+ if (Hints.empty() || !DiagOpts.ShowFixits)
+ return FixItInsertionLine;
+
+ 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 is on the same line as the caret.
std::pair<FileID, unsigned> HintLocInfo
- = SM.getDecomposedInstantiationLoc(Hint->RemoveRange.getBegin());
- if (SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) ==
- SM.getLineNumber(FID, FileOffset)) {
+ = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin());
+ if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second)) {
// Insert the new code into the line just below the code
// that the user wrote.
unsigned HintColNo
= SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second);
unsigned LastColumnModified
- = HintColNo - 1 + Hint->CodeToInsert.size();
+ = HintColNo - 1 + I->CodeToInsert.size();
if (LastColumnModified > FixItInsertionLine.size())
FixItInsertionLine.resize(LastColumnModified, ' ');
- std::copy(Hint->CodeToInsert.begin(), Hint->CodeToInsert.end(),
+ std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(),
FixItInsertionLine.begin() + HintColNo - 1);
} else {
FixItInsertionLine.clear();
@@ -538,119 +652,348 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
}
}
}
+
+ if (FixItInsertionLine.empty())
+ return FixItInsertionLine;
+
// Now that we have the entire fixit line, expand the tabs in it.
// Since we don't want to insert spaces in the middle of a word,
// find each word and the column it should line up with and insert
// spaces until they match.
- if (!FixItInsertionLine.empty()) {
- unsigned FixItPos = 0;
- unsigned LinePos = 0;
- unsigned TabExpandedCol = 0;
- unsigned LineLength = LineEnd - LineStart;
-
- while (FixItPos < FixItInsertionLine.size() && LinePos < LineLength) {
- // Find the next word in the FixIt line.
- while (FixItPos < FixItInsertionLine.size() &&
- FixItInsertionLine[FixItPos] == ' ')
- ++FixItPos;
- unsigned CharDistance = FixItPos - TabExpandedCol;
-
- // Walk forward in the source line, keeping track of
- // the tab-expanded column.
- for (unsigned I = 0; I < CharDistance; ++I, ++LinePos)
- if (LinePos >= LineLength || LineStart[LinePos] != '\t')
- ++TabExpandedCol;
- else
- TabExpandedCol =
- (TabExpandedCol/DiagOpts->TabStop + 1) * DiagOpts->TabStop;
-
- // Adjust the fixit line to match this column.
- FixItInsertionLine.insert(FixItPos, TabExpandedCol-FixItPos, ' ');
- FixItPos = TabExpandedCol;
-
- // Walk to the end of the word.
- while (FixItPos < FixItInsertionLine.size() &&
- FixItInsertionLine[FixItPos] != ' ')
- ++FixItPos;
- }
+ unsigned FixItPos = 0;
+ unsigned LinePos = 0;
+ unsigned TabExpandedCol = 0;
+ unsigned LineLength = LineEnd - LineStart;
+
+ while (FixItPos < FixItInsertionLine.size() && LinePos < LineLength) {
+ // Find the next word in the FixIt line.
+ while (FixItPos < FixItInsertionLine.size() &&
+ FixItInsertionLine[FixItPos] == ' ')
+ ++FixItPos;
+ unsigned CharDistance = FixItPos - TabExpandedCol;
+
+ // Walk forward in the source line, keeping track of
+ // the tab-expanded column.
+ for (unsigned I = 0; I < CharDistance; ++I, ++LinePos)
+ if (LinePos >= LineLength || LineStart[LinePos] != '\t')
+ ++TabExpandedCol;
+ else
+ TabExpandedCol =
+ (TabExpandedCol/DiagOpts.TabStop + 1) * DiagOpts.TabStop;
+
+ // Adjust the fixit line to match this column.
+ FixItInsertionLine.insert(FixItPos, TabExpandedCol-FixItPos, ' ');
+ FixItPos = TabExpandedCol;
+
+ // Walk to the end of the word.
+ while (FixItPos < FixItInsertionLine.size() &&
+ FixItInsertionLine[FixItPos] != ' ')
+ ++FixItPos;
}
+
+ return FixItInsertionLine;
}
- // If the source line is too long for our terminal, select only the
- // "interesting" source region within that line.
- if (Columns && SourceLine.size() > Columns)
- SelectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
- CaretEndColNo, Columns);
+ void ExpandTabs(std::string &SourceLine, std::string &CaretLine) {
+ // Scan the source line, looking for tabs. If we find any, manually expand
+ // them to spaces and update the CaretLine to match.
+ for (unsigned i = 0; i != SourceLine.size(); ++i) {
+ if (SourceLine[i] != '\t') continue;
- // Finally, remove any blank spaces from the end of CaretLine.
- while (CaretLine[CaretLine.size()-1] == ' ')
- CaretLine.erase(CaretLine.end()-1);
+ // Replace this tab with at least one space.
+ SourceLine[i] = ' ';
- // Emit what we have computed.
- OS << SourceLine << '\n';
+ // Compute the number of spaces we need to insert.
+ unsigned TabStop = DiagOpts.TabStop;
+ assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop &&
+ "Invalid -ftabstop value");
+ unsigned NumSpaces = ((i+TabStop)/TabStop * TabStop) - (i+1);
+ assert(NumSpaces < TabStop && "Invalid computation of space amt");
- if (DiagOpts->ShowColors)
- OS.changeColor(caretColor, true);
- OS << CaretLine << '\n';
- if (DiagOpts->ShowColors)
- OS.resetColor();
+ // Insert spaces into the SourceLine.
+ SourceLine.insert(i+1, NumSpaces, ' ');
- if (!FixItInsertionLine.empty()) {
- if (DiagOpts->ShowColors)
- // Print fixit line in color
- OS.changeColor(fixitColor, false);
- if (DiagOpts->ShowSourceRanges)
- OS << ' ';
- OS << FixItInsertionLine << '\n';
- if (DiagOpts->ShowColors)
- OS.resetColor();
+ // Insert spaces or ~'s into CaretLine.
+ CaretLine.insert(i+1, NumSpaces, CaretLine[i] == '~' ? '~' : ' ');
+ }
}
- if (DiagOpts->ShowParseableFixits) {
+ void EmitParseableFixits(ArrayRef<FixItHint> Hints) {
+ if (!DiagOpts.ShowParseableFixits)
+ return;
// We follow FixItRewriter's example in not (yet) handling
// fix-its in macros.
- bool BadApples = false;
- for (const FixItHint *Hint = Hints; Hint != Hints + NumHints; ++Hint) {
- if (Hint->RemoveRange.isInvalid() ||
- Hint->RemoveRange.getBegin().isMacroID() ||
- Hint->RemoveRange.getEnd().isMacroID()) {
- BadApples = true;
+ for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
+ I != E; ++I) {
+ if (I->RemoveRange.isInvalid() ||
+ I->RemoveRange.getBegin().isMacroID() ||
+ I->RemoveRange.getEnd().isMacroID())
+ return;
+ }
+
+ for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
+ I != E; ++I) {
+ SourceLocation BLoc = I->RemoveRange.getBegin();
+ SourceLocation ELoc = I->RemoveRange.getEnd();
+
+ std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(BLoc);
+ std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(ELoc);
+
+ // Adjust for token ranges.
+ if (I->RemoveRange.isTokenRange())
+ EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, LangOpts);
+
+ // We specifically do not do word-wrapping or tab-expansion here,
+ // because this is supposed to be easy to parse.
+ PresumedLoc PLoc = SM.getPresumedLoc(BLoc);
+ if (PLoc.isInvalid())
break;
+
+ OS << "fix-it:\"";
+ OS.write_escaped(PLoc.getFilename());
+ OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second)
+ << ':' << SM.getColumnNumber(BInfo.first, BInfo.second)
+ << '-' << SM.getLineNumber(EInfo.first, EInfo.second)
+ << ':' << SM.getColumnNumber(EInfo.first, EInfo.second)
+ << "}:\"";
+ OS.write_escaped(I->CodeToInsert);
+ OS << "\"\n";
+ }
+ }
+};
+
+} // end namespace
+
+/// Get the presumed location of a diagnostic message. This computes the
+/// presumed location for the top of any macro backtrace when present.
+static PresumedLoc getDiagnosticPresumedLoc(const SourceManager &SM,
+ SourceLocation Loc) {
+ // 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(SM, Loc);
+ Loc = getImmediateMacroCallerLoc(SM, Loc);
+ }
+
+ return SM.getPresumedLoc(Loc);
+}
+
+/// \brief Print out the file/line/column information and include trace.
+///
+/// This method handlen the emission of the diagnostic location information.
+/// This includes extracting as much location information as is present for the
+/// diagnostic and printing it, as well as any include stack or source ranges
+/// necessary.
+void TextDiagnosticPrinter::EmitDiagnosticLoc(DiagnosticsEngine::Level Level,
+ const Diagnostic &Info,
+ const SourceManager &SM,
+ PresumedLoc PLoc) {
+ if (PLoc.isInvalid()) {
+ // At least print the file name if available:
+ FileID FID = SM.getFileID(Info.getLocation());
+ if (!FID.isInvalid()) {
+ const FileEntry* FE = SM.getFileEntryForID(FID);
+ if (FE && FE->getName()) {
+ OS << FE->getName();
+ if (FE->getDevice() == 0 && FE->getInode() == 0
+ && FE->getFileMode() == 0) {
+ // in PCH is a guess, but a good one:
+ OS << " (in PCH)";
+ }
+ OS << ": ";
}
}
+ return;
+ }
+ unsigned LineNo = PLoc.getLine();
+
+ if (!DiagOpts->ShowLocation)
+ return;
+
+ if (DiagOpts->ShowColors)
+ OS.changeColor(savedColor, true);
- if (!BadApples) {
- for (const FixItHint *Hint = Hints; Hint != Hints + NumHints; ++Hint) {
+ OS << PLoc.getFilename();
+ switch (DiagOpts->Format) {
+ case DiagnosticOptions::Clang: OS << ':' << LineNo; break;
+ case DiagnosticOptions::Msvc: OS << '(' << LineNo; break;
+ case DiagnosticOptions::Vi: OS << " +" << LineNo; break;
+ }
- SourceLocation B = Hint->RemoveRange.getBegin();
- SourceLocation E = Hint->RemoveRange.getEnd();
+ if (DiagOpts->ShowColumn)
+ // Compute the column number.
+ if (unsigned ColNo = PLoc.getColumn()) {
+ if (DiagOpts->Format == DiagnosticOptions::Msvc) {
+ OS << ',';
+ ColNo--;
+ } else
+ OS << ':';
+ OS << ColNo;
+ }
+ switch (DiagOpts->Format) {
+ case DiagnosticOptions::Clang:
+ case DiagnosticOptions::Vi: OS << ':'; break;
+ case DiagnosticOptions::Msvc: OS << ") : "; break;
+ }
- std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
- std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
+ if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) {
+ FileID CaretFileID =
+ SM.getFileID(SM.getExpansionLoc(Info.getLocation()));
+ bool PrintedRange = false;
+
+ for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) {
+ // Ignore invalid ranges.
+ if (!Info.getRange(i).isValid()) continue;
+
+ SourceLocation B = Info.getRange(i).getBegin();
+ SourceLocation E = Info.getRange(i).getEnd();
+ B = SM.getExpansionLoc(B);
+ E = SM.getExpansionLoc(E);
+
+ // If the End location and the start location are the same and are a
+ // macro location, then the range was something that came from a
+ // macro expansion or _Pragma. If this is an object-like macro, the
+ // best we can do is to highlight the range. If this is a
+ // function-like macro, we'd also like to highlight the arguments.
+ if (B == E && Info.getRange(i).getEnd().isMacroID())
+ E = SM.getExpansionRange(Info.getRange(i).getEnd()).second;
+
+ std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
+ std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
+
+ // If the start or end of the range is in another file, just discard
+ // it.
+ if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
+ continue;
+
+ // Add in the length of the token, so that we cover multi-char
+ // tokens.
+ unsigned TokSize = 0;
+ if (Info.getRange(i).isTokenRange())
+ TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts);
+
+ OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':'
+ << SM.getColumnNumber(BInfo.first, BInfo.second) << '-'
+ << SM.getLineNumber(EInfo.first, EInfo.second) << ':'
+ << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize)
+ << '}';
+ PrintedRange = true;
+ }
+
+ if (PrintedRange)
+ OS << ':';
+ }
+ OS << ' ';
+}
- // Adjust for token ranges.
- if (Hint->RemoveRange.isTokenRange())
- EInfo.second += Lexer::MeasureTokenLength(E, SM, *LangOpts);
+/// \brief Print the diagonstic level to a raw_ostream.
+///
+/// Handles colorizing the level and formatting.
+static void printDiagnosticLevel(raw_ostream &OS,
+ DiagnosticsEngine::Level Level,
+ bool ShowColors) {
+ if (ShowColors) {
+ // Print diagnostic category in bold and color
+ switch (Level) {
+ case DiagnosticsEngine::Ignored:
+ llvm_unreachable("Invalid diagnostic type");
+ case DiagnosticsEngine::Note: OS.changeColor(noteColor, true); break;
+ case DiagnosticsEngine::Warning: OS.changeColor(warningColor, true); break;
+ case DiagnosticsEngine::Error: OS.changeColor(errorColor, true); break;
+ case DiagnosticsEngine::Fatal: OS.changeColor(fatalColor, true); break;
+ }
+ }
- // We specifically do not do word-wrapping or tab-expansion here,
- // because this is supposed to be easy to parse.
- PresumedLoc PLoc = SM.getPresumedLoc(B);
- if (PLoc.isInvalid())
- break;
-
- OS << "fix-it:\"";
- OS.write_escaped(SM.getPresumedLoc(B).getFilename());
- OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second)
- << ':' << SM.getColumnNumber(BInfo.first, BInfo.second)
- << '-' << SM.getLineNumber(EInfo.first, EInfo.second)
- << ':' << SM.getColumnNumber(EInfo.first, EInfo.second)
- << "}:\"";
- OS.write_escaped(Hint->CodeToInsert);
- OS << "\"\n";
+ switch (Level) {
+ case DiagnosticsEngine::Ignored: llvm_unreachable("Invalid diagnostic type");
+ case DiagnosticsEngine::Note: OS << "note: "; break;
+ case DiagnosticsEngine::Warning: OS << "warning: "; break;
+ case DiagnosticsEngine::Error: OS << "error: "; break;
+ case DiagnosticsEngine::Fatal: OS << "fatal error: "; break;
+ }
+
+ if (ShowColors)
+ OS.resetColor();
+}
+
+/// \brief Print the diagnostic name to a raw_ostream.
+///
+/// This prints the diagnostic name to a raw_ostream if it has one. It formats
+/// the name according to the expected diagnostic message formatting:
+/// " [diagnostic_name_here]"
+static void printDiagnosticName(raw_ostream &OS, const Diagnostic &Info) {
+ if (!DiagnosticIDs::isBuiltinNote(Info.getID()))
+ OS << " [" << DiagnosticIDs::getName(Info.getID()) << "]";
+}
+
+/// \brief Print any diagnostic option information to a raw_ostream.
+///
+/// This implements all of the logic for adding diagnostic options to a message
+/// (via OS). Each relevant option is comma separated and all are enclosed in
+/// the standard bracketing: " [...]".
+static void printDiagnosticOptions(raw_ostream &OS,
+ DiagnosticsEngine::Level Level,
+ const Diagnostic &Info,
+ const DiagnosticOptions &DiagOpts) {
+ bool Started = false;
+ if (DiagOpts.ShowOptionNames) {
+ // Handle special cases for non-warnings early.
+ if (Info.getID() == diag::fatal_too_many_errors) {
+ OS << " [-ferror-limit=]";
+ return;
+ }
+
+ // The code below is somewhat fragile because we are essentially trying to
+ // report to the user what happened by inferring what the diagnostic engine
+ // did. Eventually it might make more sense to have the diagnostic engine
+ // include some "why" information in the diagnostic.
+
+ // If this is a warning which has been mapped to an error by the user (as
+ // inferred by checking whether the default mapping is to an error) then
+ // flag it as such. Note that diagnostics could also have been mapped by a
+ // pragma, but we don't currently have a way to distinguish this.
+ if (Level == DiagnosticsEngine::Error &&
+ DiagnosticIDs::isBuiltinWarningOrExtension(Info.getID()) &&
+ !DiagnosticIDs::isDefaultMappingAsError(Info.getID())) {
+ OS << " [-Werror";
+ Started = true;
+ }
+
+ // If the diagnostic is an extension diagnostic and not enabled by default
+ // then it must have been turned on with -pedantic.
+ bool EnabledByDefault;
+ if (DiagnosticIDs::isBuiltinExtensionDiag(Info.getID(),
+ EnabledByDefault) &&
+ !EnabledByDefault) {
+ OS << (Started ? "," : " [") << "-pedantic";
+ Started = true;
+ }
+
+ StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID());
+ if (!Opt.empty()) {
+ OS << (Started ? "," : " [") << "-W" << Opt;
+ Started = true;
+ }
+ }
+
+ // If the user wants to see category information, include it too.
+ if (DiagOpts.ShowCategories) {
+ unsigned DiagCategory =
+ DiagnosticIDs::getCategoryNumberForDiag(Info.getID());
+ if (DiagCategory) {
+ OS << (Started ? "," : " [");
+ Started = true;
+ if (DiagOpts.ShowCategories == 1)
+ OS << DiagCategory;
+ else {
+ assert(DiagOpts.ShowCategories == 2 && "Invalid ShowCategories value");
+ OS << DiagnosticIDs::getCategoryNameFromID(DiagCategory);
}
}
}
+ if (Started)
+ OS << ']';
}
/// \brief Skip over whitespace in the string, starting at the given
@@ -659,9 +1002,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
/// \returns The index of the first non-whitespace character that is
/// greater than or equal to Idx or, if no such character exists,
/// returns the end of the string.
-static unsigned skipWhitespace(unsigned Idx,
- const llvm::SmallVectorImpl<char> &Str,
- unsigned Length) {
+static unsigned skipWhitespace(unsigned Idx, StringRef Str, unsigned Length) {
while (Idx < Length && isspace(Str[Idx]))
++Idx;
return Idx;
@@ -692,8 +1033,7 @@ static inline char findMatchingPunctuation(char c) {
///
/// \returns the index pointing one character past the end of the
/// word.
-static unsigned findEndOfWord(unsigned Start,
- const llvm::SmallVectorImpl<char> &Str,
+static unsigned findEndOfWord(unsigned Start, StringRef Str,
unsigned Length, unsigned Column,
unsigned Columns) {
assert(Start < Str.size() && "Invalid start position!");
@@ -748,38 +1088,22 @@ static unsigned findEndOfWord(unsigned Start,
/// \brief Print the given string to a stream, word-wrapping it to
/// some number of columns in the process.
///
-/// \brief OS the stream to which the word-wrapping string will be
+/// \param OS the stream to which the word-wrapping string will be
/// emitted.
-///
-/// \brief Str the string to word-wrap and output.
-///
-/// \brief Columns the number of columns to word-wrap to.
-///
-/// \brief Column the column number at which the first character of \p
+/// \param Str the string to word-wrap and output.
+/// \param Columns the number of columns to word-wrap to.
+/// \param Column the column number at which the first character of \p
/// Str will be printed. This will be non-zero when part of the first
/// line has already been printed.
-///
-/// \brief Indentation the number of spaces to indent any lines beyond
+/// \param Indentation the number of spaces to indent any lines beyond
/// the first line.
-///
/// \returns true if word-wrapping was required, or false if the
/// string fit on the first line.
-static bool PrintWordWrapped(llvm::raw_ostream &OS,
- const llvm::SmallVectorImpl<char> &Str,
+static bool printWordWrapped(raw_ostream &OS, StringRef Str,
unsigned Columns,
unsigned Column = 0,
unsigned Indentation = WordWrapIndentation) {
- unsigned Length = Str.size();
-
- // If there is a newline in this message somewhere, find that
- // newline and split the message into the part before the newline
- // (which will be word-wrapped) and the part from the newline one
- // (which will be emitted unchanged).
- for (unsigned I = 0; I != Length; ++I)
- if (Str[I] == '\n') {
- Length = I;
- break;
- }
+ const unsigned Length = std::min(Str.find('\n'), Str.size());
// The string used to indent each line.
llvm::SmallString<16> IndentStr;
@@ -803,7 +1127,7 @@ static bool PrintWordWrapped(llvm::raw_ostream &OS,
OS << ' ';
Column += 1;
}
- OS.write(&Str[WordStart], WordLength);
+ OS << Str.substr(WordStart, WordLength);
Column += WordLength;
continue;
}
@@ -812,38 +1136,57 @@ static bool PrintWordWrapped(llvm::raw_ostream &OS,
// line.
OS << '\n';
OS.write(&IndentStr[0], Indentation);
- OS.write(&Str[WordStart], WordLength);
+ OS << Str.substr(WordStart, WordLength);
Column = Indentation + WordLength;
Wrapped = true;
}
- if (Length == Str.size())
- return Wrapped; // We're done.
+ // Append any remaning text from the message with its existing formatting.
+ OS << Str.substr(Length);
- // There is a newline in the message, followed by something that
- // will not be word-wrapped. Print that.
- OS.write(&Str[Length], Str.size() - Length);
- return true;
+ return Wrapped;
}
-/// Get the presumed location of a diagnostic message. This computes the
-/// presumed location for the top of any macro backtrace when present.
-static PresumedLoc getDiagnosticPresumedLoc(const SourceManager &SM,
- SourceLocation Loc) {
- // 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(SM, Loc);
- Loc = getImmediateMacroCallerLoc(SM, Loc);
+static void printDiagnosticMessage(raw_ostream &OS,
+ DiagnosticsEngine::Level Level,
+ StringRef Message,
+ unsigned CurrentColumn, unsigned Columns,
+ bool ShowColors) {
+ if (ShowColors) {
+ // Print warnings, errors and fatal errors in bold, no color
+ switch (Level) {
+ case DiagnosticsEngine::Warning: OS.changeColor(savedColor, true); break;
+ case DiagnosticsEngine::Error: OS.changeColor(savedColor, true); break;
+ case DiagnosticsEngine::Fatal: OS.changeColor(savedColor, true); break;
+ default: break; //don't bold notes
+ }
}
- return SM.getPresumedLoc(Loc);
+ if (Columns)
+ printWordWrapped(OS, Message, Columns, CurrentColumn);
+ else
+ OS << Message;
+
+ if (ShowColors)
+ OS.resetColor();
+ OS << '\n';
}
-void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
- const DiagnosticInfo &Info) {
+void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
+ const Diagnostic &Info) {
// Default implementation (Warnings/errors count).
- DiagnosticClient::HandleDiagnostic(Level, Info);
+ DiagnosticConsumer::HandleDiagnostic(Level, Info);
+
+ // Render the diagnostic message into a temporary buffer eagerly. We'll use
+ // this later as we print out the diagnostic to the terminal.
+ llvm::SmallString<100> OutStr;
+ Info.FormatDiagnostic(OutStr);
+
+ llvm::raw_svector_ostream DiagMessageStream(OutStr);
+ if (DiagOpts->ShowNames)
+ printDiagnosticName(DiagMessageStream, Info);
+ printDiagnosticOptions(DiagMessageStream, Level, Info, *DiagOpts);
+
// Keeps track of the the starting position of the location
// information (e.g., "foo.c:10:4:") that precedes the error
@@ -854,289 +1197,82 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
if (!Prefix.empty())
OS << Prefix << ": ";
- // If the location is specified, print out a file/line/col and include trace
- // if enabled.
- if (Info.getLocation().isValid()) {
- const SourceManager &SM = Info.getSourceManager();
- PresumedLoc PLoc = getDiagnosticPresumedLoc(SM, Info.getLocation());
- if (PLoc.isInvalid()) {
- // At least print the file name if available:
- FileID FID = SM.getFileID(Info.getLocation());
- if (!FID.isInvalid()) {
- const FileEntry* FE = SM.getFileEntryForID(FID);
- if (FE && FE->getName()) {
- OS << FE->getName();
- if (FE->getDevice() == 0 && FE->getInode() == 0
- && FE->getFileMode() == 0) {
- // in PCH is a guess, but a good one:
- OS << " (in PCH)";
- }
- OS << ": ";
- }
- }
- } else {
- unsigned LineNo = PLoc.getLine();
-
- // First, if this diagnostic is not in the main file, print out the
- // "included from" lines.
- if (LastWarningLoc != PLoc.getIncludeLoc()) {
- LastWarningLoc = PLoc.getIncludeLoc();
- PrintIncludeStack(Level, LastWarningLoc, SM);
- StartOfLocationInfo = OS.tell();
- }
-
- // Compute the column number.
- if (DiagOpts->ShowLocation) {
- if (DiagOpts->ShowColors)
- OS.changeColor(savedColor, true);
-
- OS << PLoc.getFilename();
- switch (DiagOpts->Format) {
- case DiagnosticOptions::Clang: OS << ':' << LineNo; break;
- case DiagnosticOptions::Msvc: OS << '(' << LineNo; break;
- case DiagnosticOptions::Vi: OS << " +" << LineNo; break;
- }
- if (DiagOpts->ShowColumn)
- if (unsigned ColNo = PLoc.getColumn()) {
- if (DiagOpts->Format == DiagnosticOptions::Msvc) {
- OS << ',';
- ColNo--;
- } else
- OS << ':';
- OS << ColNo;
- }
- switch (DiagOpts->Format) {
- case DiagnosticOptions::Clang:
- case DiagnosticOptions::Vi: OS << ':'; break;
- case DiagnosticOptions::Msvc: OS << ") : "; break;
- }
-
-
- if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) {
- FileID CaretFileID =
- SM.getFileID(SM.getInstantiationLoc(Info.getLocation()));
- bool PrintedRange = false;
-
- for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) {
- // Ignore invalid ranges.
- if (!Info.getRange(i).isValid()) continue;
-
- SourceLocation B = Info.getRange(i).getBegin();
- SourceLocation E = Info.getRange(i).getEnd();
- B = SM.getInstantiationLoc(B);
- E = SM.getInstantiationLoc(E);
-
- // If the End location and the start location are the same and are a
- // macro location, then the range was something that came from a
- // macro expansion or _Pragma. If this is an object-like macro, the
- // best we can do is to highlight the range. If this is a
- // function-like macro, we'd also like to highlight the arguments.
- if (B == E && Info.getRange(i).getEnd().isMacroID())
- E = SM.getInstantiationRange(Info.getRange(i).getEnd()).second;
-
- std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
- std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
-
- // If the start or end of the range is in another file, just discard
- // it.
- if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
- continue;
-
- // Add in the length of the token, so that we cover multi-char
- // tokens.
- unsigned TokSize = 0;
- if (Info.getRange(i).isTokenRange())
- TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts);
-
- OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':'
- << SM.getColumnNumber(BInfo.first, BInfo.second) << '-'
- << SM.getLineNumber(EInfo.first, EInfo.second) << ':'
- << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize)
- << '}';
- PrintedRange = true;
- }
-
- if (PrintedRange)
- OS << ':';
- }
- }
- OS << ' ';
- if (DiagOpts->ShowColors)
- OS.resetColor();
- }
- }
-
- if (DiagOpts->ShowColors) {
- // Print diagnostic category in bold and color
- switch (Level) {
- case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type");
- case Diagnostic::Note: OS.changeColor(noteColor, true); break;
- case Diagnostic::Warning: OS.changeColor(warningColor, true); break;
- case Diagnostic::Error: OS.changeColor(errorColor, true); break;
- case Diagnostic::Fatal: OS.changeColor(fatalColor, true); break;
- }
- }
-
- switch (Level) {
- case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type");
- case Diagnostic::Note: OS << "note: "; break;
- case Diagnostic::Warning: OS << "warning: "; break;
- case Diagnostic::Error: OS << "error: "; break;
- case Diagnostic::Fatal: OS << "fatal error: "; break;
+ // Use a dedicated, simpler path for diagnostics without a valid location.
+ // This is important as if the location is missing, we may be emitting
+ // diagnostics in a context that lacks language options, a source manager, or
+ // other infrastructure necessary when emitting more rich diagnostics.
+ if (!Info.getLocation().isValid()) {
+ printDiagnosticLevel(OS, Level, DiagOpts->ShowColors);
+ printDiagnosticMessage(OS, Level, DiagMessageStream.str(),
+ OS.tell() - StartOfLocationInfo,
+ DiagOpts->MessageLength, DiagOpts->ShowColors);
+ OS.flush();
+ return;
}
- if (DiagOpts->ShowColors)
- OS.resetColor();
-
- llvm::SmallString<100> OutStr;
- Info.FormatDiagnostic(OutStr);
+ // Assert that the rest of our infrastructure is setup properly.
+ assert(LangOpts && "Unexpected diagnostic outside source file processing");
+ assert(DiagOpts && "Unexpected diagnostic without options set");
+ assert(Info.hasSourceManager() &&
+ "Unexpected diagnostic with no source manager");
+ const SourceManager &SM = Info.getSourceManager();
+ TextDiagnostic TextDiag(*this, OS, SM, *LangOpts, *DiagOpts);
- if (DiagOpts->ShowNames &&
- !DiagnosticIDs::isBuiltinNote(Info.getID())) {
- OutStr += " [";
- OutStr += DiagnosticIDs::getName(Info.getID());
- OutStr += "]";
- }
-
- std::string OptionName;
- if (DiagOpts->ShowOptionNames) {
- // Was this a warning mapped to an error using -Werror or pragma?
- if (Level == Diagnostic::Error &&
- DiagnosticIDs::isBuiltinWarningOrExtension(Info.getID())) {
- diag::Mapping mapping = diag::MAP_IGNORE;
- Info.getDiags()->getDiagnosticLevel(Info.getID(), Info.getLocation(),
- &mapping);
- if (mapping == diag::MAP_WARNING)
- OptionName += "-Werror";
- }
+ PresumedLoc PLoc = getDiagnosticPresumedLoc(SM, Info.getLocation());
- llvm::StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID());
- if (!Opt.empty()) {
- if (!OptionName.empty())
- OptionName += ',';
- OptionName += "-W";
- OptionName += Opt;
- } else if (Info.getID() == diag::fatal_too_many_errors) {
- OptionName = "-ferror-limit=";
- } else {
- // If the diagnostic is an extension diagnostic and not enabled by default
- // then it must have been turned on with -pedantic.
- bool EnabledByDefault;
- if (DiagnosticIDs::isBuiltinExtensionDiag(Info.getID(),
- EnabledByDefault) &&
- !EnabledByDefault)
- OptionName = "-pedantic";
- }
- }
-
- // If the user wants to see category information, include it too.
- unsigned DiagCategory = 0;
- if (DiagOpts->ShowCategories)
- DiagCategory = DiagnosticIDs::getCategoryNumberForDiag(Info.getID());
-
- // If there is any categorization information, include it.
- if (!OptionName.empty() || DiagCategory != 0) {
- bool NeedsComma = false;
- OutStr += " [";
-
- if (!OptionName.empty()) {
- OutStr += OptionName;
- NeedsComma = true;
- }
-
- if (DiagCategory) {
- if (NeedsComma) OutStr += ',';
- if (DiagOpts->ShowCategories == 1)
- OutStr += llvm::utostr(DiagCategory);
- else {
- assert(DiagOpts->ShowCategories == 2 && "Invalid ShowCategories value");
- OutStr += DiagnosticIDs::getCategoryNameFromID(DiagCategory);
- }
- }
-
- OutStr += "]";
- }
+ // First, if this diagnostic is not in the main file, print out the
+ // "included from" lines.
+ PrintIncludeStack(Level, PLoc.getIncludeLoc(), SM);
+ StartOfLocationInfo = OS.tell();
-
- if (DiagOpts->ShowColors) {
- // Print warnings, errors and fatal errors in bold, no color
- switch (Level) {
- case Diagnostic::Warning: OS.changeColor(savedColor, true); break;
- case Diagnostic::Error: OS.changeColor(savedColor, true); break;
- case Diagnostic::Fatal: OS.changeColor(savedColor, true); break;
- default: break; //don't bold notes
- }
- }
+ // Next emit the location of this particular diagnostic.
+ EmitDiagnosticLoc(Level, Info, SM, PLoc);
- if (DiagOpts->MessageLength) {
- // We will be word-wrapping the error message, so compute the
- // column number where we currently are (after printing the
- // location information).
- unsigned Column = OS.tell() - StartOfLocationInfo;
- PrintWordWrapped(OS, OutStr, DiagOpts->MessageLength, Column);
- } else {
- OS.write(OutStr.begin(), OutStr.size());
- }
- OS << '\n';
if (DiagOpts->ShowColors)
OS.resetColor();
+ printDiagnosticLevel(OS, Level, DiagOpts->ShowColors);
+ printDiagnosticMessage(OS, Level, DiagMessageStream.str(),
+ OS.tell() - StartOfLocationInfo,
+ DiagOpts->MessageLength, DiagOpts->ShowColors);
+
// If caret diagnostics are enabled and we have location, we want to
// emit the caret. However, we only do this if the location moved
// from the last diagnostic, if the last diagnostic was a note that
// was part of a different warning or error diagnostic, or if the
// diagnostic has ranges. We don't want to emit the same caret
// multiple times if one loc has multiple diagnostics.
- if (DiagOpts->ShowCarets && Info.getLocation().isValid() &&
+ if (DiagOpts->ShowCarets &&
((LastLoc != Info.getLocation()) || Info.getNumRanges() ||
- (LastCaretDiagnosticWasNote && Level != Diagnostic::Note) ||
+ (LastCaretDiagnosticWasNote && Level != DiagnosticsEngine::Note) ||
Info.getNumFixItHints())) {
// Cache the LastLoc, it allows us to omit duplicate source/caret spewage.
LastLoc = FullSourceLoc(Info.getLocation(), Info.getSourceManager());
- LastCaretDiagnosticWasNote = (Level == Diagnostic::Note);
+ LastCaretDiagnosticWasNote = (Level == DiagnosticsEngine::Note);
// Get the ranges into a local array we can hack on.
- CharSourceRange Ranges[20];
- unsigned NumRanges = Info.getNumRanges();
- assert(NumRanges < 20 && "Out of space");
- for (unsigned i = 0; i != NumRanges; ++i)
- Ranges[i] = Info.getRange(i);
-
- unsigned NumHints = Info.getNumFixItHints();
- for (unsigned i = 0; i != NumHints; ++i) {
+ SmallVector<CharSourceRange, 20> Ranges;
+ Ranges.reserve(Info.getNumRanges());
+ for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i)
+ Ranges.push_back(Info.getRange(i));
+
+ for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i) {
const FixItHint &Hint = Info.getFixItHint(i);
- if (Hint.RemoveRange.isValid()) {
- assert(NumRanges < 20 && "Out of space");
- Ranges[NumRanges++] = Hint.RemoveRange;
- }
+ if (Hint.RemoveRange.isValid())
+ Ranges.push_back(Hint.RemoveRange);
}
- const SourceManager &SM = LastLoc.getManager();
- unsigned MacroInstSkipStart = 0, MacroInstSkipEnd = 0;
- if (DiagOpts && DiagOpts->MacroBacktraceLimit && !LastLoc.isFileID()) {
- // Compute the length of the macro-expansion backtrace, so that we
- // can establish which steps in the macro backtrace we'll skip.
- SourceLocation Loc = LastLoc;
- unsigned Depth = 0;
- do {
- ++Depth;
- Loc = skipToMacroArgExpansion(SM, Loc);
- Loc = getImmediateMacroCallerLoc(SM, Loc);
- } while (!Loc.isFileID());
-
- if (Depth > DiagOpts->MacroBacktraceLimit) {
- MacroInstSkipStart = DiagOpts->MacroBacktraceLimit / 2 +
- DiagOpts->MacroBacktraceLimit % 2;
- MacroInstSkipEnd = Depth - DiagOpts->MacroBacktraceLimit / 2;
- }
- }
-
- EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(),
- Info.getFixItHints(),
- Info.getNumFixItHints(),
- DiagOpts->MessageLength,
- 0, MacroInstSkipStart, MacroInstSkipEnd);
+ unsigned MacroDepth = 0;
+ TextDiag.EmitCaret(LastLoc, Ranges,
+ llvm::makeArrayRef(Info.getFixItHints(),
+ Info.getNumFixItHints()),
+ MacroDepth);
}
OS.flush();
}
+
+DiagnosticConsumer *
+TextDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const {
+ return new TextDiagnosticPrinter(OS, *DiagOpts, /*OwnsOutputStream=*/false);
+}
diff --git a/lib/Frontend/VerifyDiagnosticsClient.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp
index fff417e20dcb..cf35c8edc310 100644
--- a/lib/Frontend/VerifyDiagnosticsClient.cpp
+++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -1,4 +1,4 @@
-//===--- VerifyDiagnosticsClient.cpp - Verifying Diagnostic Client --------===//
+//===---- VerifyDiagnosticConsumer.cpp - Verifying Diagnostic Client ------===//
//
// The LLVM Compiler Infrastructure
//
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/VerifyDiagnosticsClient.h"
+#include "clang/Frontend/VerifyDiagnosticConsumer.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticBuffer.h"
#include "clang/Lex/Preprocessor.h"
@@ -20,19 +20,24 @@
#include "llvm/Support/raw_ostream.h"
using namespace clang;
-VerifyDiagnosticsClient::VerifyDiagnosticsClient(Diagnostic &_Diags,
- DiagnosticClient *_Primary)
- : Diags(_Diags), PrimaryClient(_Primary),
- Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0) {
+VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &_Diags)
+ : Diags(_Diags), PrimaryClient(Diags.getClient()),
+ OwnsPrimaryClient(Diags.ownsClient()),
+ Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0)
+{
+ Diags.takeClient();
}
-VerifyDiagnosticsClient::~VerifyDiagnosticsClient() {
- CheckDiagnostics();
+VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
+ CheckDiagnostics();
+ Diags.takeClient();
+ if (OwnsPrimaryClient)
+ delete PrimaryClient;
}
-// DiagnosticClient interface.
+// DiagnosticConsumer interface.
-void VerifyDiagnosticsClient::BeginSourceFile(const LangOptions &LangOpts,
+void VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts,
const Preprocessor *PP) {
// FIXME: Const hack, we screw up the preprocessor but in practice its ok
// because it doesn't get reused. It would be better if we could make a copy
@@ -42,7 +47,7 @@ void VerifyDiagnosticsClient::BeginSourceFile(const LangOptions &LangOpts,
PrimaryClient->BeginSourceFile(LangOpts, PP);
}
-void VerifyDiagnosticsClient::EndSourceFile() {
+void VerifyDiagnosticConsumer::EndSourceFile() {
CheckDiagnostics();
PrimaryClient->EndSourceFile();
@@ -50,8 +55,12 @@ void VerifyDiagnosticsClient::EndSourceFile() {
CurrentPreprocessor = 0;
}
-void VerifyDiagnosticsClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
- const DiagnosticInfo &Info) {
+void VerifyDiagnosticConsumer::HandleDiagnostic(
+ DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
+ if (FirstErrorFID.isInvalid() && Info.hasSourceManager()) {
+ const SourceManager &SM = Info.getSourceManager();
+ FirstErrorFID = SM.getFileID(Info.getLocation());
+ }
// Send the diagnostic to the buffer, we will check it once we reach the end
// of the source file (or are destructed).
Buffer->HandleDiagnostic(DiagLevel, Info);
@@ -163,7 +172,7 @@ public:
: Begin(Begin), End(End), C(Begin), P(Begin), PEnd(NULL) { }
// Return true if string literal is next.
- bool Next(llvm::StringRef S) {
+ bool Next(StringRef S) {
P = C;
PEnd = C + S.size();
if (PEnd > End)
@@ -189,7 +198,7 @@ public:
// Return true if string literal is found.
// When true, P marks begin-position of S in content.
- bool Search(llvm::StringRef S) {
+ bool Search(StringRef S) {
P = std::search(C, End, S.begin(), S.end());
PEnd = P + S.size();
return P != End;
@@ -278,7 +287,7 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen,
// next token: {{
if (!PH.Next("{{")) {
- PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin),
+ PP.Diag(Pos.getLocWithOffset(PH.C-PH.Begin),
diag::err_verify_missing_start) << KindStr;
continue;
}
@@ -287,7 +296,7 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen,
// search for token: }}
if (!PH.Search("}}")) {
- PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin),
+ PP.Diag(Pos.getLocWithOffset(PH.C-PH.Begin),
diag::err_verify_missing_end) << KindStr;
continue;
}
@@ -296,11 +305,11 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen,
// build directive text; convert \n to newlines
std::string Text;
- llvm::StringRef NewlineStr = "\\n";
- llvm::StringRef Content(ContentBegin, ContentEnd-ContentBegin);
+ StringRef NewlineStr = "\\n";
+ StringRef Content(ContentBegin, ContentEnd-ContentBegin);
size_t CPos = 0;
size_t FPos;
- while ((FPos = Content.find(NewlineStr, CPos)) != llvm::StringRef::npos) {
+ while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) {
Text += Content.substr(CPos, FPos-CPos);
Text += '\n';
CPos = FPos + NewlineStr.size();
@@ -314,7 +323,7 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen,
if (D->isValid(Error))
DL->push_back(D);
else {
- PP.Diag(Pos.getFileLocWithOffset(ContentBegin-PH.Begin),
+ PP.Diag(Pos.getLocWithOffset(ContentBegin-PH.Begin),
diag::err_verify_invalid_content)
<< KindStr << Error;
}
@@ -323,14 +332,12 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen,
/// FindExpectedDiags - Lex the main source file to find all of the
// expected errors and warnings.
-static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED) {
- // Create a raw lexer to pull all the comments out of the main file. We don't
- // want to look in #include'd headers for expected-error strings.
- SourceManager &SM = PP.getSourceManager();
- FileID FID = SM.getMainFileID();
- if (SM.getMainFileID().isInvalid())
+static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED, FileID FID) {
+ // Create a raw lexer to pull all the comments out of FID.
+ if (FID.isInvalid())
return;
+ SourceManager& SM = PP.getSourceManager();
// Create a lexer to lex all the tokens of the main file in raw mode.
const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
Lexer RawLex(FID, FromFile, SM, PP.getLangOptions());
@@ -357,7 +364,7 @@ static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED) {
/// happened. Print the map out in a nice format and return "true". If the map
/// is empty and we're not going to print things, then return "false".
///
-static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr,
+static unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr,
const_diag_iterator diag_begin,
const_diag_iterator diag_end,
const char *Kind, bool Expected) {
@@ -378,7 +385,7 @@ static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr,
return std::distance(diag_begin, diag_end);
}
-static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr,
+static unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr,
DirectiveList &DL, const char *Kind,
bool Expected) {
if (DL.empty())
@@ -403,7 +410,7 @@ static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr,
/// CheckLists - Compare expected to seen diagnostic lists and return the
/// the difference between them.
///
-static unsigned CheckLists(Diagnostic &Diags, SourceManager &SourceMgr,
+static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
const char *Label,
DirectiveList &Left,
const_diag_iterator d2_begin,
@@ -446,7 +453,7 @@ static unsigned CheckLists(Diagnostic &Diags, SourceManager &SourceMgr,
/// were actually reported. It emits any discrepencies. Return "true" if there
/// were problems. Return "false" otherwise.
///
-static unsigned CheckResults(Diagnostic &Diags, SourceManager &SourceMgr,
+static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
const TextDiagnosticBuffer &Buffer,
ExpectedData &ED) {
// We want to capture the delta between what was expected and what was
@@ -471,21 +478,34 @@ static unsigned CheckResults(Diagnostic &Diags, SourceManager &SourceMgr,
return NumProblems;
}
-void VerifyDiagnosticsClient::CheckDiagnostics() {
+void VerifyDiagnosticConsumer::CheckDiagnostics() {
ExpectedData ED;
// Ensure any diagnostics go to the primary client.
- DiagnosticClient *CurClient = Diags.takeClient();
- Diags.setClient(PrimaryClient.get());
+ bool OwnsCurClient = Diags.ownsClient();
+ DiagnosticConsumer *CurClient = Diags.takeClient();
+ Diags.setClient(PrimaryClient, false);
// If we have a preprocessor, scan the source for expected diagnostic
// markers. If not then any diagnostics are unexpected.
if (CurrentPreprocessor) {
- FindExpectedDiags(*CurrentPreprocessor, ED);
+ SourceManager &SM = CurrentPreprocessor->getSourceManager();
+ // Extract expected-error strings from main file.
+ FindExpectedDiags(*CurrentPreprocessor, ED, SM.getMainFileID());
+ // Only check for expectations in other diagnostic locations
+ // if they are not the main file (via ID or FileEntry) - the main
+ // file has already been looked at, and its expectations must not
+ // be added twice.
+ if (!FirstErrorFID.isInvalid() && FirstErrorFID != SM.getMainFileID()
+ && (!SM.getFileEntryForID(FirstErrorFID)
+ || (SM.getFileEntryForID(FirstErrorFID) !=
+ SM.getFileEntryForID(SM.getMainFileID())))) {
+ FindExpectedDiags(*CurrentPreprocessor, ED, FirstErrorFID);
+ FirstErrorFID = FileID();
+ }
// Check that the expected diagnostics occurred.
- NumErrors += CheckResults(Diags, CurrentPreprocessor->getSourceManager(),
- *Buffer, ED);
+ NumErrors += CheckResults(Diags, SM, *Buffer, ED);
} else {
NumErrors += (PrintProblem(Diags, 0,
Buffer->err_begin(), Buffer->err_end(),
@@ -499,12 +519,20 @@ void VerifyDiagnosticsClient::CheckDiagnostics() {
}
Diags.takeClient();
- Diags.setClient(CurClient);
+ Diags.setClient(CurClient, OwnsCurClient);
// Reset the buffer, we have processed all the diagnostics in it.
Buffer.reset(new TextDiagnosticBuffer());
}
+DiagnosticConsumer *
+VerifyDiagnosticConsumer::clone(DiagnosticsEngine &Diags) const {
+ if (!Diags.getClient())
+ Diags.setClient(PrimaryClient->clone(Diags));
+
+ return new VerifyDiagnosticConsumer(Diags);
+}
+
Directive* Directive::Create(bool RegexKind, const SourceLocation &Location,
const std::string &Text, unsigned Count) {
if (RegexKind)
diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp
index f12b484c05e6..8fbcd4b44d79 100644
--- a/lib/Frontend/Warnings.cpp
+++ b/lib/Frontend/Warnings.cpp
@@ -31,12 +31,12 @@
#include <algorithm>
using namespace clang;
-void clang::ProcessWarningOptions(Diagnostic &Diags,
+void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
const DiagnosticOptions &Opts) {
Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers
Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings);
Diags.setShowOverloads(
- static_cast<Diagnostic::OverloadsShown>(Opts.ShowOverloads));
+ static_cast<DiagnosticsEngine::OverloadsShown>(Opts.ShowOverloads));
// Handle -ferror-limit
if (Opts.ErrorLimit)
@@ -48,14 +48,14 @@ void clang::ProcessWarningOptions(Diagnostic &Diags,
// extension diagnostics onto WARNING or ERROR unless the user has futz'd
// around with them explicitly.
if (Opts.PedanticErrors)
- Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Error);
+ Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Error);
else if (Opts.Pedantic)
- Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Warn);
+ Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Warn);
else
- Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Ignore);
+ Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Ignore);
for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) {
- llvm::StringRef Opt = Opts.Warnings[i];
+ StringRef Opt = Opts.Warnings[i];
// Check to see if this warning starts with "no-", if so, this is a negative
// form of the option.
@@ -75,11 +75,18 @@ void clang::ProcessWarningOptions(Diagnostic &Diags,
Diags.setSuppressSystemWarnings(!isPositive);
continue;
}
+
+ // -Weverything is a special case as well. It implicitly enables all
+ // warnings, including ones not explicitly in a warning group.
+ if (Opt == "everything") {
+ Diags.setEnableAllWarnings(true);
+ continue;
+ }
// -Werror/-Wno-error is a special case, not controlled by the option table.
// It also has the "specifier" form of -Werror=foo and -Werror-foo.
if (Opt.startswith("error")) {
- llvm::StringRef Specifier;
+ StringRef Specifier;
if (Opt.size() > 5) { // Specifier must be present.
if ((Opt[5] != '=' && Opt[5] != '-') || Opt.size() == 6) {
Diags.Report(diag::warn_unknown_warning_specifier)
@@ -94,14 +101,18 @@ void clang::ProcessWarningOptions(Diagnostic &Diags,
continue;
}
- // -Werror=foo maps foo to Error, -Wno-error=foo maps it to Warning.
- Mapping = isPositive ? diag::MAP_ERROR : diag::MAP_WARNING_NO_WERROR;
- Opt = Specifier;
+ // Set the warning as error flag for this specifier.
+ if (Diags.setDiagnosticGroupWarningAsError(Specifier, isPositive)) {
+ Diags.Report(isPositive ? diag::warn_unknown_warning_option :
+ diag::warn_unknown_negative_warning_option)
+ << ("-W" + Opt.str());
+ }
+ continue;
}
// -Wfatal-errors is yet another special case.
if (Opt.startswith("fatal-errors")) {
- llvm::StringRef Specifier;
+ StringRef Specifier;
if (Opt.size() != 12) {
if ((Opt[12] != '=' && Opt[12] != '-') || Opt.size() == 13) {
Diags.Report(diag::warn_unknown_warning_specifier)
@@ -116,15 +127,19 @@ void clang::ProcessWarningOptions(Diagnostic &Diags,
continue;
}
- // -Wfatal-errors=foo maps foo to Fatal, -Wno-fatal-errors=foo
- // maps it to Error.
- Mapping = isPositive ? diag::MAP_FATAL : diag::MAP_ERROR_NO_WFATAL;
- Opt = Specifier;
+ // Set the error as fatal flag for this specifier.
+ if (Diags.setDiagnosticGroupErrorAsFatal(Specifier, isPositive)) {
+ Diags.Report(isPositive ? diag::warn_unknown_warning_option :
+ diag::warn_unknown_negative_warning_option)
+ << ("-W" + Opt.str());
+ }
+ continue;
}
- if (Diags.setDiagnosticGroupMapping(Opt, Mapping))
+ if (Diags.setDiagnosticGroupMapping(Opt, Mapping)) {
Diags.Report(isPositive ? diag::warn_unknown_warning_option :
diag::warn_unknown_negative_warning_option)
<< ("-W" + Opt.str());
+ }
}
}
diff --git a/lib/FrontendTool/CMakeLists.txt b/lib/FrontendTool/CMakeLists.txt
index b8e4329c07f9..5270b1b03ed3 100644
--- a/lib/FrontendTool/CMakeLists.txt
+++ b/lib/FrontendTool/CMakeLists.txt
@@ -5,3 +5,7 @@ set(LLVM_USED_LIBS clangDriver clangFrontend clangRewrite clangCodeGen
add_clang_library(clangFrontendTool
ExecuteCompilerInvocation.cpp
)
+
+add_dependencies(clangFrontendTool
+ ClangCC1Options
+ ClangDiagnosticFrontend)
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index f2db3ae74191..c9af3cc3ff1e 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -39,7 +39,6 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
case ASTDumpXML: return new ASTDumpXMLAction();
case ASTPrint: return new ASTPrintAction();
case ASTView: return new ASTViewAction();
- case CreateModule: return 0;
case DumpRawTokens: return new DumpRawTokensAction();
case DumpTokens: return new DumpTokensAction();
case EmitAssembly: return new EmitAssemblyAction();
@@ -50,7 +49,8 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
case EmitCodeGenOnly: return new EmitCodeGenOnlyAction();
case EmitObj: return new EmitObjAction();
case FixIt: return new FixItAction();
- case GeneratePCH: return new GeneratePCHAction();
+ case GenerateModule: return new GeneratePCHAction(true);
+ case GeneratePCH: return new GeneratePCHAction(false);
case GeneratePTH: return new GeneratePTHAction();
case InitOnly: return new InitOnlyAction();
case ParseSyntaxOnly: return new SyntaxOnlyAction();
@@ -100,7 +100,10 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
Act = new arcmt::ModifyAction(Act);
break;
case FrontendOptions::ARCMT_Migrate:
- Act = new arcmt::MigrateAction(Act, CI.getFrontendOpts().ARCMTMigrateDir);
+ Act = new arcmt::MigrateAction(Act,
+ CI.getFrontendOpts().ARCMTMigrateDir,
+ CI.getFrontendOpts().ARCMTMigrateReportOut,
+ CI.getFrontendOpts().ARCMTMigrateEmitARCErrors);
break;
}
@@ -122,12 +125,6 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
return 0;
}
- // Honor -analyzer-checker-help.
- if (Clang->getAnalyzerOpts().ShowCheckerHelp) {
- ento::printCheckerHelp(llvm::outs());
- return 0;
- }
-
// Honor -version.
//
// FIXME: Use a better -version message?
@@ -136,9 +133,20 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
return 0;
}
+ // Load any requested plugins.
+ for (unsigned i = 0,
+ e = Clang->getFrontendOpts().Plugins.size(); i != e; ++i) {
+ const std::string &Path = Clang->getFrontendOpts().Plugins[i];
+ std::string Error;
+ if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Path.c_str(), &Error))
+ Clang->getDiagnostics().Report(diag::err_fe_unable_to_load_plugin)
+ << Path << Error;
+ }
+
// Honor -mllvm.
//
// FIXME: Remove this, one day.
+ // This should happen AFTER plugins have been loaded!
if (!Clang->getFrontendOpts().LLVMArgs.empty()) {
unsigned NumArgs = Clang->getFrontendOpts().LLVMArgs.size();
const char **Args = new const char*[NumArgs + 2];
@@ -149,14 +157,11 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
llvm::cl::ParseCommandLineOptions(NumArgs + 1, const_cast<char **>(Args));
}
- // Load any requested plugins.
- for (unsigned i = 0,
- e = Clang->getFrontendOpts().Plugins.size(); i != e; ++i) {
- const std::string &Path = Clang->getFrontendOpts().Plugins[i];
- std::string Error;
- if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Path.c_str(), &Error))
- Clang->getDiagnostics().Report(diag::err_fe_unable_to_load_plugin)
- << Path << Error;
+ // 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;
}
// If there were errors in processing arguments, don't do anything else.
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index 78fd6f19f67b..1faf92fd1978 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -12,6 +12,7 @@ set(files
nmmintrin.h
pmmintrin.h
smmintrin.h
+ stdalign.h
stdarg.h
stdbool.h
stddef.h
diff --git a/lib/Headers/Makefile b/lib/Headers/Makefile
index d75b1a2e7cae..91cc562bd355 100644
--- a/lib/Headers/Makefile
+++ b/lib/Headers/Makefile
@@ -49,6 +49,6 @@ $(INSTHEADERS): $(PROJ_headers)/%.h: $(HeaderDir)/%.h | $(PROJ_headers)
install-local:: $(INSTHEADERS)
-$(ObjDir)/arm_neon.h.inc.tmp : $(CLANG_LEVEL)/include/clang/Basic/arm_neon.td $(TBLGEN) $(ObjDir)/.dir
+$(ObjDir)/arm_neon.h.inc.tmp : $(CLANG_LEVEL)/include/clang/Basic/arm_neon.td $(CLANG_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang arm_neon.h.inc with tblgen"
- $(Verb) $(TableGen) -gen-arm-neon -o $(call SYSPATH, $@) $<
+ $(Verb) $(ClangTableGen) -gen-arm-neon -o $(call SYSPATH, $@) $<
diff --git a/lib/Headers/avxintrin.h b/lib/Headers/avxintrin.h
index 2eb2f8562256..0a0d2e45d965 100644
--- a/lib/Headers/avxintrin.h
+++ b/lib/Headers/avxintrin.h
@@ -341,7 +341,7 @@ _mm256_dp_ps(__m256 a, __m256 b, const int c)
(__builtin_shufflevector((__v8sf)(a), (__v8sf)(b), \
(mask) & 0x3, ((mask) & 0xc) >> 2, \
(((mask) & 0x30) >> 4) + 8, (((mask) & 0xc0) >> 6) + 8, \
- (mask) & 0x3 + 4, (((mask) & 0xc) >> 2) + 4, \
+ ((mask) & 0x3) + 4, (((mask) & 0xc) >> 2) + 4, \
(((mask) & 0x30) >> 4) + 12, (((mask) & 0xc0) >> 6) + 12))
#define _mm256_shuffle_pd(a, b, mask) \
diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h
index ee12d3caef9c..903cfde87224 100644
--- a/lib/Headers/emmintrin.h
+++ b/lib/Headers/emmintrin.h
@@ -321,6 +321,12 @@ _mm_comigt_sd(__m128d a, __m128d b)
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
+_mm_comige_sd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_comisdge(a, b);
+}
+
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_comineq_sd(__m128d a, __m128d b)
{
return __builtin_ia32_comisdneq(a, b);
@@ -351,6 +357,12 @@ _mm_ucomigt_sd(__m128d a, __m128d b)
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
+_mm_ucomige_sd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_ucomisdge(a, b);
+}
+
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_ucomineq_sd(__m128d a, __m128d b)
{
return __builtin_ia32_ucomisdneq(a, b);
@@ -452,7 +464,11 @@ _mm_load_pd(double const *dp)
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_load1_pd(double const *dp)
{
- return (__m128d){ dp[0], dp[0] };
+ struct __mm_load1_pd_struct {
+ double u;
+ } __attribute__((__packed__, __may_alias__));
+ double u = ((struct __mm_load1_pd_struct*)dp)->u;
+ return (__m128d){ u, u };
}
#define _mm_load_pd1(dp) _mm_load1_pd(dp)
@@ -460,7 +476,8 @@ _mm_load1_pd(double const *dp)
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_loadr_pd(double const *dp)
{
- return (__m128d){ dp[1], dp[0] };
+ __m128d u = *(__m128d*)dp;
+ return __builtin_shufflevector(u, u, 1, 0);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
@@ -475,19 +492,31 @@ _mm_loadu_pd(double const *dp)
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_load_sd(double const *dp)
{
- return (__m128d){ *dp, 0.0 };
+ struct __mm_load_sd_struct {
+ double u;
+ } __attribute__((__packed__, __may_alias__));
+ 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)
{
- return (__m128d){ a[0], *dp };
+ struct __mm_loadh_pd_struct {
+ double u;
+ } __attribute__((__packed__, __may_alias__));
+ 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)
{
- return (__m128d){ *dp, a[1] };
+ struct __mm_loadl_pd_struct {
+ double u;
+ } __attribute__((__packed__, __may_alias__));
+ double u = ((struct __mm_loadl_pd_struct*)dp)->u;
+ return (__m128d){ u, a[1] };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
@@ -529,14 +558,20 @@ _mm_move_sd(__m128d a, __m128d b)
static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_store_sd(double *dp, __m128d a)
{
- dp[0] = a[0];
+ struct __mm_store_sd_struct {
+ double u;
+ } __attribute__((__packed__, __may_alias__));
+ ((struct __mm_store_sd_struct*)dp)->u = a[0];
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_store1_pd(double *dp, __m128d a)
{
- dp[0] = a[0];
- dp[1] = a[0];
+ struct __mm_store1_pd_struct {
+ 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];
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
@@ -554,20 +589,26 @@ _mm_storeu_pd(double *dp, __m128d a)
static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_storer_pd(double *dp, __m128d a)
{
- dp[0] = a[1];
- dp[1] = a[0];
+ a = __builtin_shufflevector(a, a, 1, 0);
+ *(__m128d *)dp = a;
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_storeh_pd(double *dp, __m128d a)
{
- dp[0] = a[1];
+ struct __mm_storeh_pd_struct {
+ double u;
+ } __attribute__((__packed__, __may_alias__));
+ ((struct __mm_storeh_pd_struct*)dp)->u = a[1];
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_storel_pd(double *dp, __m128d a)
{
- dp[0] = a[0];
+ struct __mm_storeh_pd_struct {
+ double u;
+ } __attribute__((__packed__, __may_alias__));
+ ((struct __mm_storeh_pd_struct*)dp)->u = a[0];
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
@@ -1023,7 +1064,10 @@ _mm_loadu_si128(__m128i const *p)
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_loadl_epi64(__m128i const *p)
{
- return (__m128i) { *(long long*)p, 0};
+ struct __mm_loadl_epi64_struct {
+ long long u;
+ } __attribute__((__packed__, __may_alias__));
+ return (__m128i) { ((struct __mm_loadl_epi64_struct*)p)->u, 0};
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Headers/float.h b/lib/Headers/float.h
index 6eede0b6ba47..b7cb73ae59fe 100644
--- a/lib/Headers/float.h
+++ b/lib/Headers/float.h
@@ -24,7 +24,7 @@
#ifndef __FLOAT_H
#define __FLOAT_H
-/* If we're on MinGW, fall baack to the system's float.h, which might have
+/* If we're on MinGW, fall back to the system's float.h, which might have
* additional definitions provided for Windows.
* For more details see http://msdn.microsoft.com/en-us/library/y0ybw9fy.aspx
*/
diff --git a/lib/Headers/mm_malloc.h b/lib/Headers/mm_malloc.h
index ec9236204bb9..5fa176187227 100644
--- a/lib/Headers/mm_malloc.h
+++ b/lib/Headers/mm_malloc.h
@@ -53,7 +53,9 @@ _mm_malloc(size_t size, size_t align)
align = sizeof(void *);
void *mallocedMemory;
-#ifdef _WIN32
+#if defined(__MINGW32__)
+ mallocedMemory = __mingw_aligned_malloc(size, align);
+#elif defined(_WIN32)
mallocedMemory = _aligned_malloc(size, align);
#else
if (posix_memalign(&mallocedMemory, align, size))
diff --git a/lib/Headers/pmmintrin.h b/lib/Headers/pmmintrin.h
index 7ca386cee953..5f9b097ba65f 100644
--- a/lib/Headers/pmmintrin.h
+++ b/lib/Headers/pmmintrin.h
@@ -84,11 +84,7 @@ _mm_hsub_pd(__m128d a, __m128d b)
return __builtin_ia32_hsubpd(a, b);
}
-static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_loaddup_pd(double const *dp)
-{
- return (__m128d){ *dp, *dp };
-}
+#define _mm_loaddup_pd(dp) _mm_load1_pd(dp)
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_movedup_pd(__m128d a)
diff --git a/lib/Headers/stdalign.h b/lib/Headers/stdalign.h
new file mode 100644
index 000000000000..e7fbfa0499fd
--- /dev/null
+++ b/lib/Headers/stdalign.h
@@ -0,0 +1,30 @@
+/*===---- stdalign.h - Standard header for alignment ------------------------===
+ *
+ * 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 __STDALIGN_H
+#define __STDALIGN_H
+
+#define alignas _Alignas
+#define __alignas_is_defined 1
+
+#endif /* __STDALIGN_H */
diff --git a/lib/Headers/tgmath.h b/lib/Headers/tgmath.h
index e1a00236781a..1b0b9d24c1d5 100644
--- a/lib/Headers/tgmath.h
+++ b/lib/Headers/tgmath.h
@@ -1049,19 +1049,18 @@ static long double
static float
_TG_ATTRS
- __tg_nexttoward(float __x, float __y) {return nexttowardf(__x, __y);}
+ __tg_nexttoward(float __x, long double __y) {return nexttowardf(__x, __y);}
static double
_TG_ATTRS
- __tg_nexttoward(double __x, double __y) {return nexttoward(__x, __y);}
+ __tg_nexttoward(double __x, long double __y) {return nexttoward(__x, __y);}
static long double
_TG_ATTRS
__tg_nexttoward(long double __x, long double __y) {return nexttowardl(__x, __y);}
#undef nexttoward
-#define nexttoward(__x, __y) __tg_nexttoward(__tg_promote2((__x), (__y))(__x), \
- __tg_promote2((__x), (__y))(__y))
+#define nexttoward(__x, __y) __tg_nexttoward(__tg_promote1((__x))(__x), (__y))
// remainder
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index 50f275dce054..a0bc0bb09274 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -501,31 +501,45 @@ _mm_cvtss_f32(__m128 a)
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_loadh_pi(__m128 a, const __m64 *p)
{
- __m128 b;
- b[0] = *(float*)p;
- b[1] = *((float*)p+1);
- return __builtin_shufflevector(a, b, 0, 1, 4, 5);
+ typedef float __mm_loadh_pi_v2f32 __attribute__((__vector_size__(8)));
+ struct __mm_loadh_pi_struct {
+ __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);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_loadl_pi(__m128 a, const __m64 *p)
{
- __m128 b;
- b[0] = *(float*)p;
- b[1] = *((float*)p+1);
- return __builtin_shufflevector(a, b, 4, 5, 2, 3);
+ typedef float __mm_loadl_pi_v2f32 __attribute__((__vector_size__(8)));
+ struct __mm_loadl_pi_struct {
+ __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);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_load_ss(const float *p)
{
- return (__m128){ *p, 0, 0, 0 };
+ struct __mm_load_ss_struct {
+ float u;
+ } __attribute__((__packed__, __may_alias__));
+ 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)
{
- return (__m128){ *p, *p, *p, *p };
+ struct __mm_load1_ps_struct {
+ float u;
+ } __attribute__((__packed__, __may_alias__));
+ float u = ((struct __mm_load1_ps_struct*)p)->u;
+ return (__m128){ u, u, u, u };
}
#define _mm_load_ps1(p) _mm_load1_ps(p)
@@ -541,7 +555,7 @@ _mm_loadu_ps(const float *p)
{
struct __loadu_ps {
__m128 v;
- } __attribute__((packed, may_alias));
+ } __attribute__((__packed__, __may_alias__));
return ((struct __loadu_ps*)p)->v;
}
@@ -604,7 +618,10 @@ _mm_storel_pi(__m64 *p, __m128 a)
static __inline__ void __attribute__((__always_inline__))
_mm_store_ss(float *p, __m128 a)
{
- *p = a[0];
+ struct __mm_store_ss_struct {
+ float u;
+ } __attribute__((__packed__, __may_alias__));
+ ((struct __mm_store_ss_struct*)p)->u = a[0];
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Index/ASTLocation.cpp b/lib/Index/ASTLocation.cpp
index bd3b5ee8bf98..66b393eb6571 100644
--- a/lib/Index/ASTLocation.cpp
+++ b/lib/Index/ASTLocation.cpp
@@ -41,7 +41,7 @@ Decl *ASTLocation::getReferencedDecl() {
return 0;
switch (getKind()) {
- default: assert(0 && "Invalid Kind");
+ default: llvm_unreachable("Invalid Kind");
case N_Type:
return 0;
case N_Decl:
@@ -60,8 +60,7 @@ SourceRange ASTLocation::getSourceRange() const {
return SourceRange();
switch (getKind()) {
- default: assert(0 && "Invalid Kind");
- return SourceRange();
+ default: llvm_unreachable("Invalid Kind");
case N_Decl:
return D->getSourceRange();
case N_Stmt:
@@ -75,7 +74,7 @@ SourceRange ASTLocation::getSourceRange() const {
return SourceRange();
}
-void ASTLocation::print(llvm::raw_ostream &OS) const {
+void ASTLocation::print(raw_ostream &OS) const {
if (isInvalid()) {
OS << "<< Invalid ASTLocation >>\n";
return;
@@ -87,7 +86,7 @@ void ASTLocation::print(llvm::raw_ostream &OS) const {
case N_Decl:
OS << "[Decl: " << AsDecl()->getDeclKindName() << " ";
if (const NamedDecl *ND = dyn_cast<NamedDecl>(AsDecl()))
- OS << ND;
+ OS << *ND;
break;
case N_Stmt:
@@ -97,7 +96,7 @@ void ASTLocation::print(llvm::raw_ostream &OS) const {
case N_NamedRef:
OS << "[NamedRef: " << AsNamedRef().ND->getDeclKindName() << " ";
- OS << AsNamedRef().ND;
+ OS << *AsNamedRef().ND;
break;
case N_Type: {
diff --git a/lib/Index/CallGraph.cpp b/lib/Index/CallGraph.cpp
index 94790b8fbc17..741e78107f84 100644
--- a/lib/Index/CallGraph.cpp
+++ b/lib/Index/CallGraph.cpp
@@ -110,7 +110,7 @@ Decl *CallGraph::getDecl(CallGraphNode *Node) {
return Node->getDecl(*Ctx);
}
-void CallGraph::print(llvm::raw_ostream &os) {
+void CallGraph::print(raw_ostream &os) {
for (iterator I = begin(), E = end(); I != E; ++I) {
if (I->second->hasCallee()) {
os << "function: " << I->first.getPrintableName()
diff --git a/lib/Index/Entity.cpp b/lib/Index/Entity.cpp
index afac05c41377..fbab6d8684fd 100644
--- a/lib/Index/Entity.cpp
+++ b/lib/Index/Entity.cpp
@@ -47,7 +47,7 @@ public:
unsigned IdNS, bool isObjCInstanceMethod);
// Get an Entity associated with the name in the global namespace.
- Entity getGlobalEntity(llvm::StringRef Name);
+ Entity getGlobalEntity(StringRef Name);
Entity VisitNamedDecl(NamedDecl *D);
Entity VisitVarDecl(VarDecl *D);
@@ -77,7 +77,7 @@ Entity EntityGetter::getEntity(Entity Parent, DeclarationName Name,
return Entity(New);
}
-Entity EntityGetter::getGlobalEntity(llvm::StringRef Name) {
+Entity EntityGetter::getGlobalEntity(StringRef Name) {
IdentifierInfo *II = &ProgImpl.getIdents().get(Name);
DeclarationName GlobName(II);
unsigned IdNS = Decl::IDNS_Ordinary;
@@ -209,7 +209,7 @@ Entity EntityImpl::get(Decl *D, Program &Prog, ProgramImpl &ProgImpl) {
}
/// \brief Get an Entity associated with a global name.
-Entity EntityImpl::get(llvm::StringRef Name, Program &Prog,
+Entity EntityImpl::get(StringRef Name, Program &Prog,
ProgramImpl &ProgImpl) {
return EntityGetter(Prog, ProgImpl).getGlobalEntity(Name);
}
@@ -259,7 +259,7 @@ Entity Entity::get(Decl *D, Program &Prog) {
return EntityImpl::get(D, Prog, ProgImpl);
}
-Entity Entity::get(llvm::StringRef Name, Program &Prog) {
+Entity Entity::get(StringRef Name, Program &Prog) {
ProgramImpl &ProgImpl = *static_cast<ProgramImpl*>(Prog.Impl);
return EntityImpl::get(Name, Prog, ProgImpl);
}
diff --git a/lib/Index/EntityImpl.h b/lib/Index/EntityImpl.h
index da52ccfc099e..6d6a0c6d2b69 100644
--- a/lib/Index/EntityImpl.h
+++ b/lib/Index/EntityImpl.h
@@ -47,7 +47,7 @@ public:
/// \brief Get an Entity associated with the given Decl.
/// \returns Null if an Entity cannot refer to this Decl.
static Entity get(Decl *D, Program &Prog, ProgramImpl &ProgImpl);
- static Entity get(llvm::StringRef Name, Program &Prog, ProgramImpl &ProgImpl);
+ static Entity get(StringRef Name, Program &Prog, ProgramImpl &ProgImpl);
std::string getPrintableName();
diff --git a/lib/Index/GlobalSelector.cpp b/lib/Index/GlobalSelector.cpp
index 34679185b166..2fe6f95ec9be 100644
--- a/lib/Index/GlobalSelector.cpp
+++ b/lib/Index/GlobalSelector.cpp
@@ -25,7 +25,7 @@ Selector GlobalSelector::getSelector(ASTContext &AST) const {
Selector GlobSel = Selector(reinterpret_cast<uintptr_t>(Val));
- llvm::SmallVector<IdentifierInfo *, 8> Ids;
+ SmallVector<IdentifierInfo *, 8> Ids;
for (unsigned i = 0, e = GlobSel.isUnarySelector() ? 1 : GlobSel.getNumArgs();
i != e; ++i) {
IdentifierInfo *GlobII = GlobSel.getIdentifierInfoForSlot(i);
@@ -52,7 +52,7 @@ GlobalSelector GlobalSelector::get(Selector Sel, Program &Prog) {
ProgramImpl &ProgImpl = *static_cast<ProgramImpl*>(Prog.Impl);
- llvm::SmallVector<IdentifierInfo *, 8> Ids;
+ SmallVector<IdentifierInfo *, 8> Ids;
for (unsigned i = 0, e = Sel.isUnarySelector() ? 1 : Sel.getNumArgs();
i != e; ++i) {
IdentifierInfo *II = Sel.getIdentifierInfoForSlot(i);
diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp
index e102a6da608c..0cb564c222d5 100644
--- a/lib/Lex/HeaderMap.cpp
+++ b/lib/Lex/HeaderMap.cpp
@@ -57,7 +57,7 @@ struct HMapHeader {
/// HashHMapKey - This is the 'well known' hash function required by the file
/// format, used to look up keys in the hash table. The hash table uses simple
/// linear probing based on this function.
-static inline unsigned HashHMapKey(llvm::StringRef Str) {
+static inline unsigned HashHMapKey(StringRef Str) {
unsigned Result = 0;
const char *S = Str.begin(), *End = Str.end();
@@ -200,7 +200,7 @@ void HeaderMap::dump() const {
/// LookupFile - Check to see if the specified relative filename is located in
/// this HeaderMap. If so, open it and return its FileEntry.
const FileEntry *HeaderMap::LookupFile(
- llvm::StringRef Filename, FileManager &FM) const {
+ StringRef Filename, FileManager &FM) const {
const HMapHeader &Hdr = getHeader();
unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets);
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index 86ab9564a235..931145a8d655 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -18,6 +18,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Capacity.h"
#include <cstdio>
using namespace clang;
@@ -97,6 +98,60 @@ const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) {
return 0;
}
+const FileEntry *HeaderSearch::lookupModule(StringRef ModuleName,
+ std::string *ModuleFileName,
+ std::string *UmbrellaHeader) {
+ // If we don't have a module cache path, we can't do anything.
+ if (ModuleCachePath.empty()) {
+ if (ModuleFileName)
+ ModuleFileName->clear();
+ return 0;
+ }
+
+ // Try to find the module path.
+ llvm::SmallString<256> FileName(ModuleCachePath);
+ llvm::sys::path::append(FileName, ModuleName + ".pcm");
+ if (ModuleFileName)
+ *ModuleFileName = FileName.str();
+
+ if (const FileEntry *ModuleFile
+ = getFileMgr().getFile(FileName, /*OpenFile=*/false,
+ /*CacheFailure=*/false))
+ return ModuleFile;
+
+ // We didn't find the module. If we're not supposed to look for an
+ // umbrella header, this is the end of the road.
+ if (!UmbrellaHeader)
+ return 0;
+
+ // Look in each of the framework directories for an umbrella header with
+ // the same name as the module.
+ // FIXME: We need a way for non-frameworks to provide umbrella headers.
+ llvm::SmallString<128> UmbrellaHeaderName;
+ UmbrellaHeaderName = ModuleName;
+ UmbrellaHeaderName += '/';
+ UmbrellaHeaderName += ModuleName;
+ UmbrellaHeaderName += ".h";
+ for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
+ // Skip non-framework include paths
+ if (!SearchDirs[Idx].isFramework())
+ continue;
+
+ // Look for the umbrella header in this directory.
+ if (const FileEntry *HeaderFile
+ = SearchDirs[Idx].LookupFile(UmbrellaHeaderName, *this, 0, 0,
+ StringRef(), 0)) {
+ *UmbrellaHeader = HeaderFile->getName();
+ return 0;
+ }
+ }
+
+ // We did not find an umbrella header. Clear out the UmbrellaHeader pointee
+ // so our caller knows that we failed.
+ UmbrellaHeader->clear();
+ return 0;
+}
+
//===----------------------------------------------------------------------===//
// File lookup within a DirectoryLookup scope
//===----------------------------------------------------------------------===//
@@ -116,17 +171,19 @@ const char *DirectoryLookup::getName() const {
/// LookupFile - Lookup the specified file in this search path, returning it
/// if it exists or returning null if not.
const FileEntry *DirectoryLookup::LookupFile(
- llvm::StringRef Filename,
+ StringRef Filename,
HeaderSearch &HS,
- llvm::SmallVectorImpl<char> *SearchPath,
- llvm::SmallVectorImpl<char> *RelativePath) const {
+ SmallVectorImpl<char> *SearchPath,
+ SmallVectorImpl<char> *RelativePath,
+ StringRef BuildingModule,
+ StringRef *SuggestedModule) const {
llvm::SmallString<1024> TmpDir;
if (isNormalDir()) {
// Concatenate the requested file onto the directory.
TmpDir = getDir()->getName();
llvm::sys::path::append(TmpDir, Filename);
if (SearchPath != NULL) {
- llvm::StringRef SearchPathRef(getDir()->getName());
+ StringRef SearchPathRef(getDir()->getName());
SearchPath->clear();
SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
}
@@ -138,14 +195,15 @@ const FileEntry *DirectoryLookup::LookupFile(
}
if (isFramework())
- return DoFrameworkLookup(Filename, HS, SearchPath, RelativePath);
+ return DoFrameworkLookup(Filename, HS, SearchPath, RelativePath,
+ BuildingModule, SuggestedModule);
assert(isHeaderMap() && "Unknown directory lookup");
const FileEntry * const Result = getHeaderMap()->LookupFile(
Filename, HS.getFileMgr());
if (Result) {
if (SearchPath != NULL) {
- llvm::StringRef SearchPathRef(getName());
+ StringRef SearchPathRef(getName());
SearchPath->clear();
SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
}
@@ -161,15 +219,18 @@ const FileEntry *DirectoryLookup::LookupFile(
/// DoFrameworkLookup - Do a lookup of the specified file in the current
/// DirectoryLookup, which is a framework directory.
const FileEntry *DirectoryLookup::DoFrameworkLookup(
- llvm::StringRef Filename,
+ StringRef Filename,
HeaderSearch &HS,
- llvm::SmallVectorImpl<char> *SearchPath,
- llvm::SmallVectorImpl<char> *RelativePath) const {
+ SmallVectorImpl<char> *SearchPath,
+ SmallVectorImpl<char> *RelativePath,
+ StringRef BuildingModule,
+ StringRef *SuggestedModule) const
+{
FileManager &FileMgr = HS.getFileMgr();
// Framework names must have a '/' in the filename.
size_t SlashPos = Filename.find('/');
- if (SlashPos == llvm::StringRef::npos) return 0;
+ if (SlashPos == StringRef::npos) return 0;
// Find out if this is the home for the specified framework, by checking
// HeaderSearch. Possible answer are yes/no and unknown.
@@ -226,9 +287,16 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
SearchPath->append(FrameworkName.begin(), FrameworkName.end()-1);
}
+ /// Determine whether this is the module we're building or not.
+ bool AutomaticImport = SuggestedModule &&
+ (BuildingModule != StringRef(Filename.begin(), SlashPos)) &&
+ !Filename.substr(SlashPos + 1).startswith("..");
+
FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end());
if (const FileEntry *FE = FileMgr.getFile(FrameworkName.str(),
- /*openFile=*/true)) {
+ /*openFile=*/!AutomaticImport)) {
+ if (AutomaticImport)
+ *SuggestedModule = StringRef(Filename.begin(), SlashPos);
return FE;
}
@@ -240,7 +308,11 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
SearchPath->insert(SearchPath->begin()+OrigSize, Private,
Private+strlen(Private));
- return FileMgr.getFile(FrameworkName.str(), /*openFile=*/true);
+ const FileEntry *FE = FileMgr.getFile(FrameworkName.str(),
+ /*openFile=*/!AutomaticImport);
+ if (FE && AutomaticImport)
+ *SuggestedModule = StringRef(Filename.begin(), SlashPos);
+ return FE;
}
@@ -255,13 +327,18 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
/// non-null, indicates where the #including file is, in case a relative search
/// is needed.
const FileEntry *HeaderSearch::LookupFile(
- llvm::StringRef Filename,
+ StringRef Filename,
bool isAngled,
const DirectoryLookup *FromDir,
const DirectoryLookup *&CurDir,
const FileEntry *CurFileEnt,
- llvm::SmallVectorImpl<char> *SearchPath,
- llvm::SmallVectorImpl<char> *RelativePath) {
+ SmallVectorImpl<char> *SearchPath,
+ SmallVectorImpl<char> *RelativePath,
+ StringRef *SuggestedModule)
+{
+ if (SuggestedModule)
+ *SuggestedModule = StringRef();
+
// If 'Filename' is absolute, check to see if it exists and no searching.
if (llvm::sys::path::is_absolute(Filename)) {
CurDir = 0;
@@ -279,7 +356,7 @@ const FileEntry *HeaderSearch::LookupFile(
return FileMgr.getFile(Filename, /*openFile=*/true);
}
- // Step #0, unless disabled, check to see if the file is in the #includer's
+ // Unless disabled, check to see if the file is in the #includer's
// directory. This has to be based on CurFileEnt, not CurDir, because
// CurFileEnt could be a #include of a subdirectory (#include "foo/bar.h") and
// a subsequent include of "baz.h" should resolve to "whatever/foo/baz.h".
@@ -301,7 +378,7 @@ const FileEntry *HeaderSearch::LookupFile(
unsigned DirInfo = getFileInfo(CurFileEnt).DirInfo;
getFileInfo(FE).DirInfo = DirInfo;
if (SearchPath != NULL) {
- llvm::StringRef SearchPathRef(CurFileEnt->getDir()->getName());
+ StringRef SearchPathRef(CurFileEnt->getDir()->getName());
SearchPath->clear();
SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
}
@@ -346,19 +423,56 @@ const FileEntry *HeaderSearch::LookupFile(
// Check each directory in sequence to see if it contains this file.
for (; i != SearchDirs.size(); ++i) {
const FileEntry *FE =
- SearchDirs[i].LookupFile(Filename, *this, SearchPath, RelativePath);
+ SearchDirs[i].LookupFile(Filename, *this, SearchPath, RelativePath,
+ BuildingModule, SuggestedModule);
if (!FE) continue;
CurDir = &SearchDirs[i];
// This file is a system header or C++ unfriendly if the dir is.
- getFileInfo(FE).DirInfo = CurDir->getDirCharacteristic();
-
+ HeaderFileInfo &HFI = getFileInfo(FE);
+ HFI.DirInfo = CurDir->getDirCharacteristic();
+
+ // If this file is found in a header map and uses the framework style of
+ // includes, then this header is part of a framework we're building.
+ if (CurDir->isIndexHeaderMap()) {
+ size_t SlashPos = Filename.find('/');
+ if (SlashPos != StringRef::npos) {
+ HFI.IndexHeaderMapHeader = 1;
+ HFI.Framework = getUniqueFrameworkName(StringRef(Filename.begin(),
+ SlashPos));
+ }
+ }
+
// Remember this location for the next lookup we do.
CacheLookup.second = i;
return FE;
}
+ // If we are including a file with a quoted include "foo.h" from inside
+ // a header in a framework that is currently being built, and we couldn't
+ // resolve "foo.h" any other way, change the include to <Foo/foo.h>, where
+ // "Foo" is the name of the framework in which the including header was found.
+ if (CurFileEnt && !isAngled && Filename.find('/') == StringRef::npos) {
+ HeaderFileInfo &IncludingHFI = getFileInfo(CurFileEnt);
+ if (IncludingHFI.IndexHeaderMapHeader) {
+ llvm::SmallString<128> ScratchFilename;
+ ScratchFilename += IncludingHFI.Framework;
+ ScratchFilename += '/';
+ ScratchFilename += Filename;
+
+ const FileEntry *Result = LookupFile(ScratchFilename, /*isAngled=*/true,
+ FromDir, CurDir, CurFileEnt,
+ SearchPath, RelativePath,
+ SuggestedModule);
+ std::pair<unsigned, unsigned> &CacheLookup
+ = LookupFileCache.GetOrCreateValue(Filename).getValue();
+ CacheLookup.second
+ = LookupFileCache.GetOrCreateValue(ScratchFilename).getValue().second;
+ return Result;
+ }
+ }
+
// Otherwise, didn't find it. Remember we didn't find this.
CacheLookup.second = SearchDirs.size();
return 0;
@@ -370,15 +484,15 @@ const FileEntry *HeaderSearch::LookupFile(
/// is a subframework within Carbon.framework. If so, return the FileEntry
/// for the designated file, otherwise return null.
const FileEntry *HeaderSearch::
-LookupSubframeworkHeader(llvm::StringRef Filename,
+LookupSubframeworkHeader(StringRef Filename,
const FileEntry *ContextFileEnt,
- llvm::SmallVectorImpl<char> *SearchPath,
- llvm::SmallVectorImpl<char> *RelativePath) {
+ SmallVectorImpl<char> *SearchPath,
+ SmallVectorImpl<char> *RelativePath) {
assert(ContextFileEnt && "No context file?");
// Framework names must have a '/' in the filename. Find it.
size_t SlashPos = Filename.find('/');
- if (SlashPos == llvm::StringRef::npos) return 0;
+ if (SlashPos == StringRef::npos) return 0;
// Look up the base framework name of the ContextFileEnt.
const char *ContextName = ContextFileEnt->getName();
@@ -466,7 +580,31 @@ LookupSubframeworkHeader(llvm::StringRef Filename,
// File Info Management.
//===----------------------------------------------------------------------===//
+/// \brief Merge the header file info provided by \p OtherHFI into the current
+/// header file info (\p HFI)
+static void mergeHeaderFileInfo(HeaderFileInfo &HFI,
+ const HeaderFileInfo &OtherHFI) {
+ HFI.isImport |= OtherHFI.isImport;
+ HFI.isPragmaOnce |= OtherHFI.isPragmaOnce;
+ HFI.NumIncludes += OtherHFI.NumIncludes;
+
+ if (!HFI.ControllingMacro && !HFI.ControllingMacroID) {
+ HFI.ControllingMacro = OtherHFI.ControllingMacro;
+ HFI.ControllingMacroID = OtherHFI.ControllingMacroID;
+ }
+
+ if (OtherHFI.External) {
+ HFI.DirInfo = OtherHFI.DirInfo;
+ HFI.External = OtherHFI.External;
+ HFI.IndexHeaderMapHeader = OtherHFI.IndexHeaderMapHeader;
+ }
+ if (HFI.Framework.empty())
+ HFI.Framework = OtherHFI.Framework;
+
+ HFI.Resolved = true;
+}
+
/// getFileInfo - Return the HeaderFileInfo structure for the specified
/// FileEntry.
HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
@@ -474,10 +612,8 @@ HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
FileInfo.resize(FE->getUID()+1);
HeaderFileInfo &HFI = FileInfo[FE->getUID()];
- if (ExternalSource && !HFI.Resolved) {
- HFI = ExternalSource->GetHeaderFileInfo(FE);
- HFI.Resolved = true;
- }
+ if (ExternalSource && !HFI.Resolved)
+ mergeHeaderFileInfo(HFI, ExternalSource->GetHeaderFileInfo(FE));
return HFI;
}
@@ -488,10 +624,8 @@ bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) {
// Resolve header file info from the external source, if needed.
HeaderFileInfo &HFI = FileInfo[File->getUID()];
- if (ExternalSource && !HFI.Resolved) {
- HFI = ExternalSource->GetHeaderFileInfo(File);
- HFI.Resolved = true;
- }
+ if (ExternalSource && !HFI.Resolved)
+ mergeHeaderFileInfo(HFI, ExternalSource->GetHeaderFileInfo(File));
return HFI.isPragmaOnce || HFI.ControllingMacro || HFI.ControllingMacroID;
}
@@ -542,4 +676,14 @@ bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){
return true;
}
+size_t HeaderSearch::getTotalMemory() const {
+ return SearchDirs.capacity()
+ + llvm::capacity_in_bytes(FileInfo)
+ + llvm::capacity_in_bytes(HeaderMaps)
+ + LookupFileCache.getAllocator().getTotalMemory()
+ + FrameworkMap.getAllocator().getTotalMemory();
+}
+StringRef HeaderSearch::getUniqueFrameworkName(StringRef Framework) {
+ return FrameworkNames.GetOrCreateValue(Framework).getKey();
+}
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index a28b8f6e7b9f..a98d889dbc98 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -32,7 +32,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
-#include <cctype>
+#include <cstring>
using namespace clang;
static void InitCharacterInfo();
@@ -76,7 +76,7 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
// skip the UTF-8 BOM if it's present.
if (BufferStart == BufferPtr) {
// Determine the size of the BOM.
- llvm::StringRef Buf(BufferStart, BufferEnd - BufferStart);
+ StringRef Buf(BufferStart, BufferEnd - BufferStart);
size_t BOMLength = llvm::StringSwitch<size_t>(Buf)
.StartsWith("\xEF\xBB\xBF", 3) // UTF-8 BOM
.Default(0);
@@ -86,7 +86,7 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
}
Is_PragmaLexer = false;
- IsInConflictMarker = false;
+ CurrentConflictMarkerState = CMK_None;
// Start of the file is a start of line.
IsAtStartOfLine = true;
@@ -187,9 +187,9 @@ Lexer *Lexer::Create_PragmaLexer(SourceLocation SpellingLoc,
// Set the SourceLocation with the remapping information. This ensures that
// GetMappedTokenLoc will remap the tokens as they are lexed.
- L->FileLoc = SM.createInstantiationLoc(SM.getLocForStartOfFile(SpellingFID),
- ExpansionLocStart,
- ExpansionLocEnd, TokLen);
+ L->FileLoc = SM.createExpansionLoc(SM.getLocForStartOfFile(SpellingFID),
+ ExpansionLocStart,
+ ExpansionLocEnd, TokLen);
// Ensure that the lexer thinks it is inside a directive, so that end \n will
// return an EOD token.
@@ -217,7 +217,7 @@ std::string Lexer::Stringify(const std::string &Str, bool Charify) {
/// Stringify - Convert the specified string into a C string by escaping '\'
/// and " characters. This does not add surrounding ""'s to the string.
-void Lexer::Stringify(llvm::SmallVectorImpl<char> &Str) {
+void Lexer::Stringify(SmallVectorImpl<char> &Str) {
for (unsigned i = 0, e = Str.size(); i != e; ++i) {
if (Str[i] == '\\' || Str[i] == '"') {
Str.insert(Str.begin()+i, '\\');
@@ -235,8 +235,8 @@ void Lexer::Stringify(llvm::SmallVectorImpl<char> &Str) {
/// after trigraph expansion and escaped-newline folding. In particular, this
/// wants to get the true, uncanonicalized, spelling of things like digraphs
/// UCNs, etc.
-llvm::StringRef Lexer::getSpelling(SourceLocation loc,
- llvm::SmallVectorImpl<char> &buffer,
+StringRef Lexer::getSpelling(SourceLocation loc,
+ SmallVectorImpl<char> &buffer,
const SourceManager &SM,
const LangOptions &options,
bool *invalid) {
@@ -245,10 +245,10 @@ llvm::StringRef Lexer::getSpelling(SourceLocation loc,
// Try to the load the file buffer.
bool invalidTemp = false;
- llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
+ StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
if (invalidTemp) {
if (invalid) *invalid = true;
- return llvm::StringRef();
+ return StringRef();
}
const char *tokenBegin = file.data() + locInfo.second;
@@ -263,7 +263,7 @@ llvm::StringRef Lexer::getSpelling(SourceLocation loc,
// Common case: no need for cleaning.
if (!token.needsCleaning())
- return llvm::StringRef(tokenBegin, length);
+ return StringRef(tokenBegin, length);
// Hard case, we need to relex the characters into the string.
buffer.clear();
@@ -275,7 +275,7 @@ llvm::StringRef Lexer::getSpelling(SourceLocation loc,
ti += charSize;
}
- return llvm::StringRef(buffer.data(), buffer.size());
+ return StringRef(buffer.data(), buffer.size());
}
/// getSpelling() - Return the 'spelling' of this token. The spelling of a
@@ -394,10 +394,10 @@ unsigned Lexer::MeasureTokenLength(SourceLocation Loc,
// If this comes from a macro expansion, we really do want the macro name, not
// the token this macro expanded to.
- Loc = SM.getInstantiationLoc(Loc);
+ Loc = SM.getExpansionLoc(Loc);
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
bool Invalid = false;
- llvm::StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
+ StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
if (Invalid)
return 0;
@@ -415,15 +415,16 @@ unsigned Lexer::MeasureTokenLength(SourceLocation Loc,
return TheTok.getLength();
}
-SourceLocation Lexer::GetBeginningOfToken(SourceLocation Loc,
- const SourceManager &SM,
- const LangOptions &LangOpts) {
+static SourceLocation getBeginningOfFileToken(SourceLocation Loc,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ assert(Loc.isFileID());
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
if (LocInfo.first.isInvalid())
return Loc;
bool Invalid = false;
- llvm::StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
+ StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
if (Invalid)
return Loc;
@@ -448,7 +449,7 @@ SourceLocation Lexer::GetBeginningOfToken(SourceLocation Loc,
}
// Create a lexer starting at the beginning of this token.
- SourceLocation LexerStartLoc = Loc.getFileLocWithOffset(-LocInfo.second);
+ SourceLocation LexerStartLoc = Loc.getLocWithOffset(-LocInfo.second);
Lexer TheLexer(LexerStartLoc, LangOpts, BufStart, LexStart, Buffer.end());
TheLexer.SetCommentRetentionState(true);
@@ -474,6 +475,25 @@ SourceLocation Lexer::GetBeginningOfToken(SourceLocation Loc,
return Loc;
}
+SourceLocation Lexer::GetBeginningOfToken(SourceLocation Loc,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ if (Loc.isFileID())
+ return getBeginningOfFileToken(Loc, SM, LangOpts);
+
+ if (!SM.isMacroArgExpansion(Loc))
+ return Loc;
+
+ SourceLocation FileLoc = SM.getSpellingLoc(Loc);
+ SourceLocation BeginFileLoc = getBeginningOfFileToken(FileLoc, SM, LangOpts);
+ std::pair<FileID, unsigned> FileLocInfo = SM.getDecomposedLoc(FileLoc);
+ std::pair<FileID, unsigned> BeginFileLocInfo= SM.getDecomposedLoc(BeginFileLoc);
+ assert(FileLocInfo.first == BeginFileLocInfo.first &&
+ FileLocInfo.second >= BeginFileLocInfo.second);
+ return Loc.getLocWithOffset(SM.getDecomposedLoc(BeginFileLoc).second -
+ SM.getDecomposedLoc(FileLoc).second);
+}
+
namespace {
enum PreambleDirectiveKind {
PDK_Skipped,
@@ -484,21 +504,36 @@ namespace {
}
std::pair<unsigned, bool>
-Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer, unsigned MaxLines) {
+Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer,
+ const LangOptions &Features, unsigned MaxLines) {
// Create a lexer starting at the beginning of the file. Note that we use a
// "fake" file source location at offset 1 so that the lexer will track our
// position within the file.
const unsigned StartOffset = 1;
SourceLocation StartLoc = SourceLocation::getFromRawEncoding(StartOffset);
- LangOptions LangOpts;
- Lexer TheLexer(StartLoc, LangOpts, Buffer->getBufferStart(),
+ Lexer TheLexer(StartLoc, Features, Buffer->getBufferStart(),
Buffer->getBufferStart(), Buffer->getBufferEnd());
bool InPreprocessorDirective = false;
Token TheTok;
Token IfStartTok;
unsigned IfCount = 0;
- unsigned Line = 0;
+
+ unsigned MaxLineOffset = 0;
+ if (MaxLines) {
+ const char *CurPtr = Buffer->getBufferStart();
+ unsigned CurLine = 0;
+ while (CurPtr != Buffer->getBufferEnd()) {
+ char ch = *CurPtr++;
+ if (ch == '\n') {
+ ++CurLine;
+ if (CurLine == MaxLines)
+ break;
+ }
+ }
+ if (CurPtr != Buffer->getBufferEnd())
+ MaxLineOffset = CurPtr - Buffer->getBufferStart();
+ }
do {
TheLexer.LexFromRawLexer(TheTok);
@@ -522,11 +557,11 @@ Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer, unsigned MaxLines) {
// Keep track of the # of lines in the preamble.
if (TheTok.isAtStartOfLine()) {
- ++Line;
+ unsigned TokOffset = TheTok.getLocation().getRawEncoding() - StartOffset;
// If we were asked to limit the number of lines in the preamble,
// and we're about to exceed that limit, we're done.
- if (MaxLines && Line >= MaxLines)
+ if (MaxLineOffset && TokOffset >= MaxLineOffset)
break;
}
@@ -539,12 +574,12 @@ Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer, unsigned MaxLines) {
Token HashTok = TheTok;
InPreprocessorDirective = true;
- // Figure out which direective this is. Since we're lexing raw tokens,
+ // Figure out which directive this is. Since we're lexing raw tokens,
// we don't have an identifier table available. Instead, just look at
// the raw identifier to recognize and categorize preprocessor directives.
TheLexer.LexFromRawLexer(TheTok);
if (TheTok.getKind() == tok::raw_identifier && !TheTok.needsCleaning()) {
- llvm::StringRef Keyword(TheTok.getRawIdentifierData(),
+ StringRef Keyword(TheTok.getRawIdentifierData(),
TheTok.getLength());
PreambleDirectiveKind PDK
= llvm::StringSwitch<PreambleDirectiveKind>(Keyword)
@@ -638,7 +673,7 @@ SourceLocation Lexer::AdvanceToTokenCharacter(SourceLocation TokStart,
// chars, this method is extremely fast.
while (Lexer::isObviouslySimpleCharacter(*TokPtr)) {
if (CharNo == 0)
- return TokStart.getFileLocWithOffset(PhysOffset);
+ return TokStart.getLocWithOffset(PhysOffset);
++TokPtr, --CharNo, ++PhysOffset;
}
@@ -658,7 +693,7 @@ SourceLocation Lexer::AdvanceToTokenCharacter(SourceLocation TokStart,
if (!Lexer::isObviouslySimpleCharacter(*TokPtr))
PhysOffset += Lexer::SkipEscapedNewLines(TokPtr)-TokPtr;
- return TokStart.getFileLocWithOffset(PhysOffset);
+ return TokStart.getLocWithOffset(PhysOffset);
}
/// \brief Computes the source location just past the end of the
@@ -687,7 +722,7 @@ SourceLocation Lexer::getLocForEndOfToken(SourceLocation Loc, unsigned Offset,
return SourceLocation(); // Points inside the macro expansion.
// Continue and find the location just after the macro expansion.
- Loc = SM.getInstantiationRange(Loc).second;
+ Loc = SM.getExpansionRange(Loc).second;
}
unsigned Len = Lexer::MeasureTokenLength(Loc, SM, Features);
@@ -696,14 +731,14 @@ SourceLocation Lexer::getLocForEndOfToken(SourceLocation Loc, unsigned Offset,
else
return Loc;
- return Loc.getFileLocWithOffset(Len);
+ return Loc.getLocWithOffset(Len);
}
/// \brief Returns true if the given MacroID location points at the first
/// token of the macro expansion.
bool Lexer::isAtStartOfMacroExpansion(SourceLocation loc,
- const SourceManager &SM,
- const LangOptions &LangOpts) {
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
std::pair<FileID, unsigned> infoLoc = SM.getDecomposedLoc(loc);
@@ -713,8 +748,7 @@ bool Lexer::isAtStartOfMacroExpansion(SourceLocation loc,
return false; // Does not point at the start of token.
SourceLocation expansionLoc =
- SM.getSLocEntry(infoLoc.first)
- .getInstantiation().getInstantiationLocStart();
+ SM.getSLocEntry(infoLoc.first).getExpansion().getExpansionLocStart();
if (expansionLoc.isFileID())
return true; // No other macro expansions, this is the first.
@@ -734,17 +768,15 @@ bool Lexer::isAtEndOfMacroExpansion(SourceLocation loc,
return false;
FileID FID = SM.getFileID(loc);
- SourceLocation afterLoc = loc.getFileLocWithOffset(tokLen+1);
- if (!SM.isBeforeInSourceLocationOffset(afterLoc, SM.getNextOffset()))
- return true; // We got past the last FileID, this points to the last token.
+ SourceLocation afterLoc = loc.getLocWithOffset(tokLen+1);
+ if (SM.isInFileID(afterLoc, FID))
+ return false; // Still in the same FileID, does not point to the last token.
// FIXME: If the token comes from the macro token paste operator ('##')
// or the stringify operator ('#') this function will always return false;
- if (FID == SM.getFileID(afterLoc))
- return false; // Still in the same FileID, does not point to the last token.
-
+
SourceLocation expansionLoc =
- SM.getSLocEntry(FID).getInstantiation().getInstantiationLocEnd();
+ SM.getSLocEntry(FID).getExpansion().getExpansionLocEnd();
if (expansionLoc.isFileID())
return true; // No other macro expansions.
@@ -761,7 +793,8 @@ enum {
CHAR_LETTER = 0x04, // a-z,A-Z
CHAR_NUMBER = 0x08, // 0-9
CHAR_UNDER = 0x10, // _
- CHAR_PERIOD = 0x20 // .
+ CHAR_PERIOD = 0x20, // .
+ CHAR_RAWDEL = 0x40 // {}[]#<>%:;?*+-/^&|~!=,"'
};
// Statically initialize CharInfo table based on ASCII character set
@@ -786,20 +819,20 @@ static const unsigned char CharInfo[256] =
0 , 0 , 0 , 0 ,
//32 SP 33 ! 34 " 35 #
//36 $ 37 % 38 & 39 '
- CHAR_HORZ_WS, 0 , 0 , 0 ,
- 0 , 0 , 0 , 0 ,
+ 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 , 0 , 0 ,
- 0 , 0 , CHAR_PERIOD , 0 ,
+ 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 , 0 , 0 ,
- 0 , 0 , 0 , 0 ,
+ 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 ,
@@ -814,8 +847,8 @@ static const unsigned char CharInfo[256] =
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 , 0 ,
- 0 , 0 , 0 , CHAR_UNDER ,
+ 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 ,
@@ -829,9 +862,9 @@ static const unsigned char CharInfo[256] =
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 , 0 ,
- 0 , 0 , 0 , 0
+//124 | 125 } 126 ~ 127 DEL
+ CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_RAWDEL ,
+ CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , 0
};
static void InitCharacterInfo() {
@@ -869,6 +902,12 @@ 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'.
@@ -883,6 +922,14 @@ static inline bool isNumberBody(unsigned char c) {
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;
+}
+
//===----------------------------------------------------------------------===//
// Diagnostics forwarding code.
@@ -907,14 +954,14 @@ static SourceLocation GetMappedTokenLoc(Preprocessor &PP,
// Create a new SLoc which is expanded from Expansion(FileLoc) but whose
// characters come from spelling(FileLoc)+Offset.
SourceLocation SpellingLoc = SM.getSpellingLoc(FileLoc);
- SpellingLoc = SpellingLoc.getFileLocWithOffset(CharNo);
+ SpellingLoc = SpellingLoc.getLocWithOffset(CharNo);
// Figure out the expansion loc range, which is the range covered by the
// original _Pragma(...) sequence.
std::pair<SourceLocation,SourceLocation> II =
- SM.getImmediateInstantiationRange(FileLoc);
+ SM.getImmediateExpansionRange(FileLoc);
- return SM.createInstantiationLoc(SpellingLoc, II.first, II.second, TokLen);
+ return SM.createExpansionLoc(SpellingLoc, II.first, II.second, TokLen);
}
/// getSourceLocation - Return a source location identifier for the specified
@@ -928,7 +975,7 @@ SourceLocation Lexer::getSourceLocation(const char *Loc,
// the file id from FileLoc with the offset specified.
unsigned CharNo = Loc-BufferStart;
if (FileLoc.isFileID())
- return FileLoc.getFileLocWithOffset(CharNo);
+ return FileLoc.getLocWithOffset(CharNo);
// Otherwise, this is the _Pragma lexer case, which pretends that all of the
// tokens are lexed from where the _Pragma was defined.
@@ -978,7 +1025,7 @@ static char DecodeTrigraphChar(const char *CP, Lexer *L) {
}
if (!L->isLexingRawMode())
- L->Diag(CP-2, diag::trigraph_converted) << llvm::StringRef(&Res, 1);
+ L->Diag(CP-2, diag::trigraph_converted) << StringRef(&Res, 1);
return Res;
}
@@ -1028,6 +1075,59 @@ const char *Lexer::SkipEscapedNewLines(const char *P) {
}
}
+/// \brief Checks that the given token is the first token that occurs after the
+/// given location (this excludes comments and whitespace). Returns the location
+/// immediately after the specified token. If the token is not found or the
+/// location is inside a macro, the returned source location will be invalid.
+SourceLocation Lexer::findLocationAfterToken(SourceLocation Loc,
+ tok::TokenKind TKind,
+ const SourceManager &SM,
+ const LangOptions &LangOpts,
+ bool SkipTrailingWhitespaceAndNewLine) {
+ if (Loc.isMacroID()) {
+ if (!Lexer::isAtEndOfMacroExpansion(Loc, SM, LangOpts))
+ return SourceLocation();
+ Loc = SM.getExpansionRange(Loc).second;
+ }
+ Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts);
+
+ // Break down the source location.
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+
+ // Try to load the file buffer.
+ bool InvalidTemp = false;
+ llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
+ if (InvalidTemp)
+ return SourceLocation();
+
+ const char *TokenBegin = File.data() + LocInfo.second;
+
+ // Lex from the start of the given location.
+ Lexer lexer(SM.getLocForStartOfFile(LocInfo.first), LangOpts, File.begin(),
+ TokenBegin, File.end());
+ // Find the token.
+ Token Tok;
+ lexer.LexFromRawLexer(Tok);
+ if (Tok.isNot(TKind))
+ return SourceLocation();
+ SourceLocation TokenLoc = Tok.getLocation();
+
+ // Calculate how much whitespace needs to be skipped if any.
+ unsigned NumWhitespaceChars = 0;
+ if (SkipTrailingWhitespaceAndNewLine) {
+ const char *TokenEnd = SM.getCharacterData(TokenLoc) +
+ Tok.getLength();
+ unsigned char C = *TokenEnd;
+ while (isHorizontalWhitespace(C)) {
+ C = *(++TokenEnd);
+ NumWhitespaceChars++;
+ }
+ if (isVerticalWhitespace(C))
+ NumWhitespaceChars++;
+ }
+
+ return TokenLoc.getLocWithOffset(Tok.getLength() + NumWhitespaceChars);
+}
/// getCharAndSizeSlow - Peek a single 'character' from the specified buffer,
/// get its size, and return it. This is tricky in several cases:
@@ -1191,6 +1291,7 @@ FinishIdentifier:
// preprocessor, which may macro expand it or something.
if (II->isHandleIdentifierCase())
PP->HandleIdentifier(Result);
+
return;
}
@@ -1252,13 +1353,12 @@ void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
if ((C == '-' || C == '+') && (PrevCh == 'E' || PrevCh == 'e')) {
// If we are in Microsoft mode, don't continue if the constant is hex.
// For example, MSVC will accept the following as 3 tokens: 0x1234567e+1
- if (!Features.Microsoft || !isHexaLiteral(BufferPtr, Features))
+ if (!Features.MicrosoftExt || !isHexaLiteral(BufferPtr, Features))
return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result));
}
// If we have a hex FP constant, continue.
- if ((C == '-' || C == '+') && (PrevCh == 'P' || PrevCh == 'p') &&
- !Features.CPlusPlus0x)
+ if ((C == '-' || C == '+') && (PrevCh == 'P' || PrevCh == 'p'))
return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result));
// Update the location of token as well as BufferPtr.
@@ -1268,10 +1368,17 @@ void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
}
/// LexStringLiteral - Lex the remainder of a string literal, after having lexed
-/// either " or L".
-void Lexer::LexStringLiteral(Token &Result, const char *CurPtr, bool Wide) {
+/// either " or L" or u8" or u" or U".
+void Lexer::LexStringLiteral(Token &Result, const char *CurPtr,
+ tok::TokenKind Kind) {
const char *NulCharacter = 0; // Does this string contain the \0 character?
+ if (!isLexingRawMode() &&
+ (Kind == tok::utf8_string_literal ||
+ Kind == tok::utf16_string_literal ||
+ Kind == tok::utf32_string_literal))
+ Diag(BufferPtr, diag::warn_cxx98_compat_unicode_literal);
+
char C = getAndAdvanceChar(CurPtr, Result);
while (C != '"') {
// Skip escaped characters. Escaped newlines will already be processed by
@@ -1281,16 +1388,21 @@ void Lexer::LexStringLiteral(Token &Result, const char *CurPtr, bool Wide) {
if (C == '\n' || C == '\r' || // Newline.
(C == 0 && CurPtr-1 == BufferEnd)) { // End of file.
- if (C == 0 && PP && PP->isCodeCompletionFile(FileLoc))
- PP->CodeCompleteNaturalLanguage();
- else if (!isLexingRawMode() && !Features.AsmPreprocessor)
+ if (!isLexingRawMode() && !Features.AsmPreprocessor)
Diag(BufferPtr, diag::warn_unterminated_string);
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
return;
}
- if (C == 0)
+ if (C == 0) {
+ if (isCodeCompletionPoint(CurPtr-1)) {
+ PP->CodeCompleteNaturalLanguage();
+ FormTokenWithChars(Result, CurPtr-1, tok::unknown);
+ return cutOffLexing();
+ }
+
NulCharacter = CurPtr-1;
+ }
C = getAndAdvanceChar(CurPtr, Result);
}
@@ -1300,8 +1412,82 @@ void Lexer::LexStringLiteral(Token &Result, const char *CurPtr, bool Wide) {
// Update the location of the token as well as the BufferPtr instance var.
const char *TokStart = BufferPtr;
- FormTokenWithChars(Result, CurPtr,
- Wide ? tok::wide_string_literal : tok::string_literal);
+ FormTokenWithChars(Result, CurPtr, Kind);
+ Result.setLiteralData(TokStart);
+}
+
+/// LexRawStringLiteral - Lex the remainder of a raw string literal, after
+/// having lexed R", LR", u8R", uR", or UR".
+void Lexer::LexRawStringLiteral(Token &Result, const char *CurPtr,
+ tok::TokenKind Kind) {
+ // This function doesn't use getAndAdvanceChar because C++0x [lex.pptoken]p3:
+ // Between the initial and final double quote characters of the raw string,
+ // any transformations performed in phases 1 and 2 (trigraphs,
+ // universal-character-names, and line splicing) are reverted.
+
+ if (!isLexingRawMode())
+ Diag(BufferPtr, diag::warn_cxx98_compat_raw_string_literal);
+
+ unsigned PrefixLen = 0;
+
+ while (PrefixLen != 16 && isRawStringDelimBody(CurPtr[PrefixLen]))
+ ++PrefixLen;
+
+ // If the last character was not a '(', then we didn't lex a valid delimiter.
+ if (CurPtr[PrefixLen] != '(') {
+ if (!isLexingRawMode()) {
+ const char *PrefixEnd = &CurPtr[PrefixLen];
+ if (PrefixLen == 16) {
+ Diag(PrefixEnd, diag::err_raw_delim_too_long);
+ } else {
+ Diag(PrefixEnd, diag::err_invalid_char_raw_delim)
+ << StringRef(PrefixEnd, 1);
+ }
+ }
+
+ // Search for the next '"' in hopes of salvaging the lexer. Unfortunately,
+ // it's possible the '"' was intended to be part of the raw string, but
+ // there's not much we can do about that.
+ while (1) {
+ char C = *CurPtr++;
+
+ if (C == '"')
+ break;
+ if (C == 0 && CurPtr-1 == BufferEnd) {
+ --CurPtr;
+ break;
+ }
+ }
+
+ FormTokenWithChars(Result, CurPtr, tok::unknown);
+ return;
+ }
+
+ // Save prefix and move CurPtr past it
+ const char *Prefix = CurPtr;
+ CurPtr += PrefixLen + 1; // skip over prefix and '('
+
+ while (1) {
+ char C = *CurPtr++;
+
+ if (C == ')') {
+ // Check for prefix match and closing quote.
+ if (strncmp(CurPtr, Prefix, PrefixLen) == 0 && CurPtr[PrefixLen] == '"') {
+ CurPtr += PrefixLen + 1; // skip over prefix and '"'
+ break;
+ }
+ } else if (C == 0 && CurPtr-1 == BufferEnd) { // End of file.
+ if (!isLexingRawMode())
+ Diag(BufferPtr, diag::err_unterminated_raw_string)
+ << StringRef(Prefix, PrefixLen);
+ FormTokenWithChars(Result, CurPtr-1, tok::unknown);
+ return;
+ }
+ }
+
+ // Update the location of token as well as BufferPtr.
+ const char *TokStart = BufferPtr;
+ FormTokenWithChars(Result, CurPtr, Kind);
Result.setLiteralData(TokStart);
}
@@ -1317,7 +1503,8 @@ void Lexer::LexAngledStringLiteral(Token &Result, const char *CurPtr) {
// Skip the escaped character.
C = getAndAdvanceChar(CurPtr, Result);
} else if (C == '\n' || C == '\r' || // Newline.
- (C == 0 && CurPtr-1 == BufferEnd)) { // End of file.
+ (C == 0 && (CurPtr-1 == BufferEnd || // End of file.
+ isCodeCompletionPoint(CurPtr-1)))) {
// If the filename is unterminated, then it must just be a lone <
// character. Return this as such.
FormTokenWithChars(Result, AfterLessPos, tok::less);
@@ -1340,10 +1527,15 @@ void Lexer::LexAngledStringLiteral(Token &Result, const char *CurPtr) {
/// LexCharConstant - Lex the remainder of a character constant, after having
-/// lexed either ' or L'.
-void Lexer::LexCharConstant(Token &Result, const char *CurPtr) {
+/// lexed either ' or L' or u' or U'.
+void Lexer::LexCharConstant(Token &Result, const char *CurPtr,
+ tok::TokenKind Kind) {
const char *NulCharacter = 0; // Does this character contain the \0 character?
+ if (!isLexingRawMode() &&
+ (Kind == tok::utf16_char_constant || Kind == tok::utf32_char_constant))
+ Diag(BufferPtr, diag::warn_cxx98_compat_unicode_literal);
+
char C = getAndAdvanceChar(CurPtr, Result);
if (C == '\'') {
if (!isLexingRawMode() && !Features.AsmPreprocessor)
@@ -1360,13 +1552,17 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr) {
C = getAndAdvanceChar(CurPtr, Result);
} else if (C == '\n' || C == '\r' || // Newline.
(C == 0 && CurPtr-1 == BufferEnd)) { // End of file.
- if (C == 0 && PP && PP->isCodeCompletionFile(FileLoc))
- PP->CodeCompleteNaturalLanguage();
- else if (!isLexingRawMode() && !Features.AsmPreprocessor)
+ if (!isLexingRawMode() && !Features.AsmPreprocessor)
Diag(BufferPtr, diag::warn_unterminated_char);
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
return;
} else if (C == 0) {
+ if (isCodeCompletionPoint(CurPtr-1)) {
+ PP->CodeCompleteNaturalLanguage();
+ FormTokenWithChars(Result, CurPtr-1, tok::unknown);
+ return cutOffLexing();
+ }
+
NulCharacter = CurPtr-1;
}
C = getAndAdvanceChar(CurPtr, Result);
@@ -1378,7 +1574,7 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr) {
// Update the location of token as well as BufferPtr.
const char *TokStart = BufferPtr;
- FormTokenWithChars(Result, CurPtr, tok::char_constant);
+ FormTokenWithChars(Result, CurPtr, Kind);
Result.setLiteralData(TokStart);
}
@@ -1451,20 +1647,28 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
char C;
do {
C = *CurPtr;
- // FIXME: Speedup BCPL comment lexing. Just scan for a \n or \r character.
- // If we find a \n character, scan backwards, checking to see if it's an
- // escaped newline, like we do for block comments.
-
// Skip over characters in the fast loop.
while (C != 0 && // Potentially EOF.
- C != '\\' && // Potentially escaped newline.
- C != '?' && // Potentially trigraph.
C != '\n' && C != '\r') // Newline or DOS-style newline.
C = *++CurPtr;
- // If this is a newline, we're done.
- if (C == '\n' || C == '\r')
- break; // Found the newline? Break out!
+ const char *NextLine = CurPtr;
+ if (C != 0) {
+ // We found a newline, see if it's escaped.
+ const char *EscapePtr = CurPtr-1;
+ while (isHorizontalWhitespace(*EscapePtr)) // Skip whitespace.
+ --EscapePtr;
+
+ if (*EscapePtr == '\\') // Escaped newline.
+ CurPtr = EscapePtr;
+ else if (EscapePtr[0] == '/' && EscapePtr[-1] == '?' &&
+ EscapePtr[-2] == '?') // Trigraph-escaped newline.
+ CurPtr = EscapePtr-2;
+ else
+ break; // This is a newline, we're done.
+
+ C = *CurPtr;
+ }
// Otherwise, this is a hard case. Fall back on getAndAdvanceChar to
// properly decode the character. Read it in raw mode to avoid emitting
@@ -1476,6 +1680,13 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
C = getAndAdvanceChar(CurPtr, Result);
LexingRawMode = OldRawMode;
+ // If we only read only one character, then no special handling is needed.
+ // We're done and can skip forward to the newline.
+ if (C != 0 && CurPtr == OldPtr+1) {
+ CurPtr = NextLine;
+ break;
+ }
+
// If the char that we finally got was a \n, then we must have had something
// like \<newline><newline>. We don't want to have consumed the second
// newline, we want CurPtr, to end up pointing to it down below.
@@ -1492,9 +1703,9 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
if (OldPtr[0] == '\n' || OldPtr[0] == '\r') {
// Okay, we found a // comment that ends in a newline, if the next
// line is also a // comment, but has spaces, don't emit a diagnostic.
- if (isspace(C)) {
+ if (isWhitespace(C)) {
const char *ForwardPtr = CurPtr;
- while (isspace(*ForwardPtr)) // Skip whitespace.
+ while (isWhitespace(*ForwardPtr)) // Skip whitespace.
++ForwardPtr;
if (ForwardPtr[0] == '/' && ForwardPtr[1] == '/')
break;
@@ -1507,12 +1718,16 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
}
if (CurPtr == BufferEnd+1) {
- if (PP && PP->isCodeCompletionFile(FileLoc))
- PP->CodeCompleteNaturalLanguage();
-
--CurPtr;
break;
}
+
+ if (C == '\0' && isCodeCompletionPoint(CurPtr-1)) {
+ PP->CodeCompleteNaturalLanguage();
+ cutOffLexing();
+ return false;
+ }
+
} while (C != '\n' && C != '\r');
// Found but did not consume the newline. Notify comment handlers about the
@@ -1573,7 +1788,7 @@ bool Lexer::SaveBCPLComment(Token &Result, const char *CurPtr) {
Result.setKind(tok::comment);
PP->CreateString(&Spelling[0], Spelling.size(), Result,
- Result.getLocation());
+ Result.getLocation(), Result.getLocation());
return true;
}
@@ -1667,8 +1882,7 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
unsigned char C = getCharAndSize(CurPtr, CharSize);
CurPtr += CharSize;
if (C == 0 && CurPtr == BufferEnd+1) {
- if (!isLexingRawMode() &&
- !PP->isCodeCompletionFile(FileLoc))
+ if (!isLexingRawMode())
Diag(BufferPtr, diag::err_unterminated_block_comment);
--CurPtr;
@@ -1691,7 +1905,10 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
while (1) {
// Skip over all non-interesting characters until we find end of buffer or a
// (probably ending) '/' character.
- if (CurPtr + 24 < BufferEnd) {
+ if (CurPtr + 24 < BufferEnd &&
+ // If there is a code-completion point avoid the fast scan because it
+ // doesn't check for '\0'.
+ !(PP && PP->getCodeCompletionFileLoc() == FileLoc)) {
// While not aligned to a 16-byte boundary.
while (C != '/' && ((intptr_t)CurPtr & 0x0F) != 0)
C = *CurPtr++;
@@ -1751,9 +1968,7 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
Diag(CurPtr-1, diag::warn_nested_block_comment);
}
} else if (C == 0 && CurPtr == BufferEnd+1) {
- if (PP && PP->isCodeCompletionFile(FileLoc))
- PP->CodeCompleteNaturalLanguage();
- else if (!isLexingRawMode())
+ if (!isLexingRawMode())
Diag(BufferPtr, diag::err_unterminated_block_comment);
// Note: the user probably forgot a */. We could continue immediately
// after the /*, but this would involve lexing a lot of what really is the
@@ -1769,7 +1984,12 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
BufferPtr = CurPtr;
return false;
+ } else if (C == '\0' && isCodeCompletionPoint(CurPtr-1)) {
+ PP->CodeCompleteNaturalLanguage();
+ cutOffLexing();
+ return false;
}
+
C = *CurPtr++;
}
@@ -1826,6 +2046,12 @@ std::string Lexer::ReadToEndOfLine() {
case 0: // Null.
// Found end of file?
if (CurPtr-1 != BufferEnd) {
+ if (isCodeCompletionPoint(CurPtr-1)) {
+ PP->CodeCompleteNaturalLanguage();
+ cutOffLexing();
+ return Result;
+ }
+
// Nope, normal character, continue.
Result += Char;
break;
@@ -1840,8 +2066,8 @@ std::string Lexer::ReadToEndOfLine() {
// Next, lex the character, which should handle the EOD transition.
Lex(Tmp);
if (Tmp.is(tok::code_completion)) {
- if (PP && PP->getCodeCompletionHandler())
- PP->getCodeCompletionHandler()->CodeCompleteNaturalLanguage();
+ if (PP)
+ PP->CodeCompleteNaturalLanguage();
Lex(Tmp);
}
assert(Tmp.is(tok::eod) && "Unexpected token!");
@@ -1857,22 +2083,6 @@ std::string Lexer::ReadToEndOfLine() {
/// This returns true if Result contains a token, false if PP.Lex should be
/// called again.
bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
- // Check if we are performing code completion.
- if (PP && PP->isCodeCompletionFile(FileLoc)) {
- // We're at the end of the file, but we've been asked to consider the
- // end of the file to be a code-completion token. Return the
- // code-completion token.
- Result.startToken();
- FormTokenWithChars(Result, CurPtr, tok::code_completion);
-
- // Only do the eof -> code_completion translation once.
- PP->SetCodeCompletionPoint(0, 0, 0);
-
- // Silence any diagnostics that occur once we hit the code-completion point.
- PP->getDiagnostics().setSuppressAllDiagnostics(true);
- return true;
- }
-
// If we hit the end of the file while parsing a preprocessor directive,
// end the preprocessor directive first. The next token returned will
// then be the end of file.
@@ -1900,7 +2110,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
// If we are in a #if directive, emit an error.
while (!ConditionalStack.empty()) {
- if (!PP->isCodeCompletionFile(FileLoc))
+ if (PP->getCodeCompletionFileLoc() != FileLoc)
PP->Diag(ConditionalStack.back().IfLoc,
diag::err_pp_unterminated_conditional);
ConditionalStack.pop_back();
@@ -1951,15 +2161,18 @@ unsigned Lexer::isNextPPTokenLParen() {
}
/// FindConflictEnd - Find the end of a version control conflict marker.
-static const char *FindConflictEnd(const char *CurPtr, const char *BufferEnd) {
- llvm::StringRef RestOfBuffer(CurPtr+7, BufferEnd-CurPtr-7);
- size_t Pos = RestOfBuffer.find(">>>>>>>");
- while (Pos != llvm::StringRef::npos) {
+static const char *FindConflictEnd(const char *CurPtr, const char *BufferEnd,
+ ConflictMarkerKind CMK) {
+ const char *Terminator = CMK == CMK_Perforce ? "<<<<\n" : ">>>>>>>";
+ size_t TermLen = CMK == CMK_Perforce ? 5 : 7;
+ StringRef RestOfBuffer(CurPtr+TermLen, BufferEnd-CurPtr-TermLen);
+ size_t Pos = RestOfBuffer.find(Terminator);
+ while (Pos != StringRef::npos) {
// Must occur at start of line.
if (RestOfBuffer[Pos-1] != '\r' &&
RestOfBuffer[Pos-1] != '\n') {
- RestOfBuffer = RestOfBuffer.substr(Pos+7);
- Pos = RestOfBuffer.find(">>>>>>>");
+ RestOfBuffer = RestOfBuffer.substr(Pos+TermLen);
+ Pos = RestOfBuffer.find(Terminator);
continue;
}
return RestOfBuffer.data()+Pos;
@@ -1977,23 +2190,25 @@ bool Lexer::IsStartOfConflictMarker(const char *CurPtr) {
CurPtr[-1] != '\n' && CurPtr[-1] != '\r')
return false;
- // Check to see if we have <<<<<<<.
- if (BufferEnd-CurPtr < 8 ||
- llvm::StringRef(CurPtr, 7) != "<<<<<<<")
+ // Check to see if we have <<<<<<< or >>>>.
+ if ((BufferEnd-CurPtr < 8 || StringRef(CurPtr, 7) != "<<<<<<<") &&
+ (BufferEnd-CurPtr < 6 || StringRef(CurPtr, 5) != ">>>> "))
return false;
// If we have a situation where we don't care about conflict markers, ignore
// it.
- if (IsInConflictMarker || isLexingRawMode())
+ if (CurrentConflictMarkerState || isLexingRawMode())
return false;
- // Check to see if there is a >>>>>>> somewhere in the buffer at the start of
- // a line to terminate this conflict marker.
- if (FindConflictEnd(CurPtr, BufferEnd)) {
+ ConflictMarkerKind Kind = *CurPtr == '<' ? CMK_Normal : CMK_Perforce;
+
+ // Check to see if there is an ending marker somewhere in the buffer at the
+ // start of a line to terminate this conflict marker.
+ if (FindConflictEnd(CurPtr, BufferEnd, Kind)) {
// We found a match. We are really in a conflict marker.
// Diagnose this, and ignore to the end of line.
Diag(CurPtr, diag::err_conflict_marker);
- IsInConflictMarker = true;
+ CurrentConflictMarkerState = Kind;
// Skip ahead to the end of line. We know this exists because the
// end-of-conflict marker starts with \r or \n.
@@ -2010,10 +2225,10 @@ bool Lexer::IsStartOfConflictMarker(const char *CurPtr) {
}
-/// HandleEndOfConflictMarker - If this is a '=======' or '|||||||' or '>>>>>>>'
-/// marker, then it is the end of a conflict marker. Handle it by ignoring up
-/// until the end of the line. This returns true if it is a conflict marker and
-/// false if not.
+/// HandleEndOfConflictMarker - If this is a '====' or '||||' or '>>>>', or if
+/// it is '<<<<' and the conflict marker started with a '>>>>' marker, then it
+/// is the end of a conflict marker. Handle it by ignoring up until the end of
+/// the line. This returns true if it is a conflict marker and false if not.
bool Lexer::HandleEndOfConflictMarker(const char *CurPtr) {
// Only a conflict marker if it starts at the beginning of a line.
if (CurPtr != BufferStart &&
@@ -2022,18 +2237,19 @@ bool Lexer::HandleEndOfConflictMarker(const char *CurPtr) {
// If we have a situation where we don't care about conflict markers, ignore
// it.
- if (!IsInConflictMarker || isLexingRawMode())
+ if (!CurrentConflictMarkerState || isLexingRawMode())
return false;
- // Check to see if we have the marker (7 characters in a row).
- for (unsigned i = 1; i != 7; ++i)
+ // Check to see if we have the marker (4 characters in a row).
+ for (unsigned i = 1; i != 4; ++i)
if (CurPtr[i] != CurPtr[0])
return false;
// If we do have it, search for the end of the conflict marker. This could
// fail if it got skipped with a '#if 0' or something. Note that CurPtr might
// be the end of conflict marker.
- if (const char *End = FindConflictEnd(CurPtr, BufferEnd)) {
+ if (const char *End = FindConflictEnd(CurPtr, BufferEnd,
+ CurrentConflictMarkerState)) {
CurPtr = End;
// Skip ahead to the end of line.
@@ -2043,13 +2259,22 @@ bool Lexer::HandleEndOfConflictMarker(const char *CurPtr) {
BufferPtr = CurPtr;
// No longer in the conflict marker.
- IsInConflictMarker = false;
+ CurrentConflictMarkerState = CMK_None;
return true;
}
return false;
}
+bool Lexer::isCodeCompletionPoint(const char *CurPtr) const {
+ if (PP && PP->isCodeCompletionEnabled()) {
+ SourceLocation Loc = FileLoc.getLocWithOffset(CurPtr-BufferStart);
+ return Loc == PP->getCodeCompletionLoc();
+ }
+
+ return false;
+}
+
/// LexTokenInternal - This implements a simple C family lexer. It is an
/// extremely performance critical piece of code. This assumes that the buffer
@@ -2102,6 +2327,14 @@ LexNextToken:
return PPCache->Lex(Result);
}
+ // Check if we are performing code completion.
+ if (isCodeCompletionPoint(CurPtr-1)) {
+ // Return the code-completion token.
+ Result.startToken();
+ FormTokenWithChars(Result, CurPtr, tok::code_completion);
+ return;
+ }
+
if (!isLexingRawMode())
Diag(CurPtr-1, diag::null_in_file);
Result.setFlag(Token::LeadingSpace);
@@ -2112,7 +2345,7 @@ LexNextToken:
case 26: // DOS & CP/M EOF: "^Z".
// If we're in Microsoft extensions mode, treat this as end of file.
- if (Features.Microsoft) {
+ if (Features.MicrosoftExt) {
// Read the PP instance variable into an automatic variable, because
// LexEndOfFile will often delete 'this'.
Preprocessor *PPCache = PP;
@@ -2186,6 +2419,102 @@ LexNextToken:
MIOpt.ReadToken();
return LexNumericConstant(Result, CurPtr);
+ case 'u': // Identifier (uber) or C++0x UTF-8 or UTF-16 string literal
+ // Notify MIOpt that we read a non-whitespace/non-comment token.
+ MIOpt.ReadToken();
+
+ if (Features.CPlusPlus0x) {
+ Char = getCharAndSize(CurPtr, SizeTmp);
+
+ // UTF-16 string literal
+ if (Char == '"')
+ return LexStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result),
+ tok::utf16_string_literal);
+
+ // UTF-16 character constant
+ if (Char == '\'')
+ return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result),
+ tok::utf16_char_constant);
+
+ // UTF-16 raw string literal
+ if (Char == 'R' && getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
+ return LexRawStringLiteral(Result,
+ ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
+ SizeTmp2, Result),
+ tok::utf16_string_literal);
+
+ if (Char == '8') {
+ char Char2 = getCharAndSize(CurPtr + SizeTmp, SizeTmp2);
+
+ // UTF-8 string literal
+ if (Char2 == '"')
+ return LexStringLiteral(Result,
+ ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
+ SizeTmp2, Result),
+ tok::utf8_string_literal);
+
+ if (Char2 == 'R') {
+ unsigned SizeTmp3;
+ char Char3 = getCharAndSize(CurPtr + SizeTmp + SizeTmp2, SizeTmp3);
+ // UTF-8 raw string literal
+ if (Char3 == '"') {
+ return LexRawStringLiteral(Result,
+ ConsumeChar(ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
+ SizeTmp2, Result),
+ SizeTmp3, Result),
+ tok::utf8_string_literal);
+ }
+ }
+ }
+ }
+
+ // treat u like the start of an identifier.
+ return LexIdentifier(Result, CurPtr);
+
+ case 'U': // Identifier (Uber) or C++0x UTF-32 string literal
+ // Notify MIOpt that we read a non-whitespace/non-comment token.
+ MIOpt.ReadToken();
+
+ if (Features.CPlusPlus0x) {
+ Char = getCharAndSize(CurPtr, SizeTmp);
+
+ // UTF-32 string literal
+ if (Char == '"')
+ return LexStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result),
+ tok::utf32_string_literal);
+
+ // UTF-32 character constant
+ if (Char == '\'')
+ return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result),
+ tok::utf32_char_constant);
+
+ // UTF-32 raw string literal
+ if (Char == 'R' && getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
+ return LexRawStringLiteral(Result,
+ ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
+ SizeTmp2, Result),
+ tok::utf32_string_literal);
+ }
+
+ // treat U like the start of an identifier.
+ return LexIdentifier(Result, CurPtr);
+
+ case 'R': // Identifier or C++0x raw string literal
+ // Notify MIOpt that we read a non-whitespace/non-comment token.
+ MIOpt.ReadToken();
+
+ if (Features.CPlusPlus0x) {
+ Char = getCharAndSize(CurPtr, SizeTmp);
+
+ if (Char == '"')
+ return LexRawStringLiteral(Result,
+ ConsumeChar(CurPtr, SizeTmp, Result),
+ tok::string_literal);
+ }
+
+ // treat R like the start of an identifier.
+ return LexIdentifier(Result, CurPtr);
+
case 'L': // Identifier (Loony) or wide literal (L'x' or L"xyz").
// Notify MIOpt that we read a non-whitespace/non-comment token.
MIOpt.ReadToken();
@@ -2194,21 +2523,30 @@ LexNextToken:
// Wide string literal.
if (Char == '"')
return LexStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result),
- true);
+ tok::wide_string_literal);
+
+ // Wide raw string literal.
+ if (Features.CPlusPlus0x && Char == 'R' &&
+ getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
+ return LexRawStringLiteral(Result,
+ ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
+ SizeTmp2, Result),
+ tok::wide_string_literal);
// Wide character constant.
if (Char == '\'')
- return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result));
+ return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result),
+ tok::wide_char_constant);
// FALL THROUGH, treating L like the start of an identifier.
// C99 6.4.2: Identifiers.
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K': /*'L'*/case 'M': case 'N':
- case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
+ case 'O': case 'P': case 'Q': /*'R'*/case 'S': case 'T': /*'U'*/
case 'V': case 'W': case 'X': case 'Y': case 'Z':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
- case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
+ case 'o': case 'p': case 'q': case 'r': case 's': case 't': /*'u'*/
case 'v': case 'w': case 'x': case 'y': case 'z':
case '_':
// Notify MIOpt that we read a non-whitespace/non-comment token.
@@ -2231,13 +2569,13 @@ LexNextToken:
case '\'':
// Notify MIOpt that we read a non-whitespace/non-comment token.
MIOpt.ReadToken();
- return LexCharConstant(Result, CurPtr);
+ return LexCharConstant(Result, CurPtr, tok::char_constant);
// C99 6.4.5: String Literals.
case '"':
// Notify MIOpt that we read a non-whitespace/non-comment token.
MIOpt.ReadToken();
- return LexStringLiteral(Result, CurPtr, false);
+ return LexStringLiteral(Result, CurPtr, tok::string_literal);
// C99 6.4.6: Punctuators.
case '?':
@@ -2396,7 +2734,7 @@ LexNextToken:
Kind = tok::hashhash; // '%:%:' -> '##'
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
- } else if (Char == '@' && Features.Microsoft) { // %:@ -> #@ -> Charize
+ } else if (Char == '@' && Features.MicrosoftExt) {// %:@ -> #@ -> Charize
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
if (!isLexingRawMode())
Diag(BufferPtr, diag::charize_microsoft_ext);
@@ -2447,6 +2785,10 @@ LexNextToken:
// If this is actually a '<<<<<<<' version control conflict marker,
// recognize it as such and recover nicely.
goto LexNextToken;
+ } else if (After == '<' && HandleEndOfConflictMarker(CurPtr-1)) {
+ // If this is '<<<<' and we're in a Perforce-style conflict marker,
+ // ignore it.
+ goto LexNextToken;
} else if (Features.CUDA && After == '<') {
Kind = tok::lesslessless;
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
@@ -2470,6 +2812,8 @@ LexNextToken:
char After = getCharAndSize(CurPtr + SizeTmp + SizeTmp2, SizeTmp3);
if (After != ':' && After != '>') {
Kind = tok::less;
+ if (!isLexingRawMode())
+ Diag(BufferPtr, diag::warn_cxx98_compat_less_colon_colon);
break;
}
}
@@ -2494,6 +2838,10 @@ LexNextToken:
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
Kind = tok::greatergreaterequal;
+ } else if (After == '>' && IsStartOfConflictMarker(CurPtr-1)) {
+ // If this is actually a '>>>>' conflict marker, recognize it as such
+ // and recover nicely.
+ goto LexNextToken;
} else if (After == '>' && HandleEndOfConflictMarker(CurPtr-1)) {
// If this is '>>>>>>>' and we're in a conflict marker, ignore it.
goto LexNextToken;
@@ -2552,7 +2900,7 @@ LexNextToken:
case '=':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '=') {
- // If this is '=======' and we're in a conflict marker, ignore it.
+ // If this is '====' and we're in a conflict marker, ignore it.
if (CurPtr[1] == '=' && HandleEndOfConflictMarker(CurPtr-1))
goto LexNextToken;
@@ -2570,7 +2918,7 @@ LexNextToken:
if (Char == '#') {
Kind = tok::hashhash;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
- } else if (Char == '@' && Features.Microsoft) { // #@ -> Charize
+ } else if (Char == '@' && Features.MicrosoftExt) { // #@ -> Charize
Kind = tok::hashat;
if (!isLexingRawMode())
Diag(BufferPtr, diag::charize_microsoft_ext);
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 2c96c4d4ee24..70183fd1a0ea 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -16,8 +16,8 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
/// HexDigitValue - Return the value of the specified hex digit, or -1 if it's
@@ -29,12 +29,31 @@ static int HexDigitValue(char C) {
return -1;
}
+static unsigned getCharWidth(tok::TokenKind kind, const TargetInfo &Target) {
+ switch (kind) {
+ default: llvm_unreachable("Unknown token type!");
+ case tok::char_constant:
+ case tok::string_literal:
+ case tok::utf8_string_literal:
+ return Target.getCharWidth();
+ case tok::wide_char_constant:
+ case tok::wide_string_literal:
+ return Target.getWCharWidth();
+ case tok::utf16_char_constant:
+ case tok::utf16_string_literal:
+ return Target.getChar16Width();
+ case tok::utf32_char_constant:
+ case tok::utf32_string_literal:
+ return Target.getChar32Width();
+ }
+}
+
/// ProcessCharEscape - Parse a standard C escape sequence, which can occur in
/// either a character or a string literal.
static unsigned ProcessCharEscape(const char *&ThisTokBuf,
const char *ThisTokEnd, bool &HadError,
- FullSourceLoc Loc, bool IsWide,
- Diagnostic *Diags, const TargetInfo &Target) {
+ FullSourceLoc Loc, unsigned CharWidth,
+ DiagnosticsEngine *Diags) {
// Skip the '\' char.
++ThisTokBuf;
@@ -99,9 +118,6 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
}
// See if any bits will be truncated when evaluated as a character.
- unsigned CharWidth =
- IsWide ? Target.getWCharWidth() : Target.getCharWidth();
-
if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) {
Overflow = true;
ResultChar &= ~0U >> (32-CharWidth);
@@ -129,9 +145,6 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
ThisTokBuf[0] >= '0' && ThisTokBuf[0] <= '7');
// Check for overflow. Reject '\777', but not L'\777'.
- unsigned CharWidth =
- IsWide ? Target.getWCharWidth() : Target.getCharWidth();
-
if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) {
if (Diags)
Diags->Report(Loc, diag::warn_octal_escape_too_large);
@@ -167,7 +180,7 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
/// return the UTF32.
static bool ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
uint32_t &UcnVal, unsigned short &UcnLen,
- FullSourceLoc Loc, Diagnostic *Diags,
+ FullSourceLoc Loc, DiagnosticsEngine *Diags,
const LangOptions &Features) {
if (!Features.CPlusPlus && !Features.C99 && Diags)
Diags->Report(Loc, diag::warn_ucn_not_valid_in_c89);
@@ -220,7 +233,8 @@ static bool ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
/// we will likely rework our support for UCN's.
static void EncodeUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
char *&ResultBuf, bool &HadError,
- FullSourceLoc Loc, bool wide, Diagnostic *Diags,
+ FullSourceLoc Loc, unsigned CharByteWidth,
+ DiagnosticsEngine *Diags,
const LangOptions &Features) {
typedef uint32_t UTF32;
UTF32 UcnVal = 0;
@@ -231,19 +245,22 @@ static void EncodeUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
return;
}
- if (wide) {
- (void)UcnLen;
- assert((UcnLen== 4 || UcnLen== 8) && "only ucn length of 4 or 8 supported");
+ assert((CharByteWidth == 1 || CharByteWidth == 2 || CharByteWidth) &&
+ "only character widths of 1, 2, or 4 bytes supported");
- if (!Features.ShortWChar) {
- // Note: our internal rep of wide char tokens is always little-endian.
- *ResultBuf++ = (UcnVal & 0x000000FF);
- *ResultBuf++ = (UcnVal & 0x0000FF00) >> 8;
- *ResultBuf++ = (UcnVal & 0x00FF0000) >> 16;
- *ResultBuf++ = (UcnVal & 0xFF000000) >> 24;
- return;
- }
+ (void)UcnLen;
+ assert((UcnLen== 4 || UcnLen== 8) && "only ucn length of 4 or 8 supported");
+ if (CharByteWidth == 4) {
+ // Note: our internal rep of wide char tokens is always little-endian.
+ *ResultBuf++ = (UcnVal & 0x000000FF);
+ *ResultBuf++ = (UcnVal & 0x0000FF00) >> 8;
+ *ResultBuf++ = (UcnVal & 0x00FF0000) >> 16;
+ *ResultBuf++ = (UcnVal & 0xFF000000) >> 24;
+ return;
+ }
+
+ if (CharByteWidth == 2) {
// Convert to UTF16.
if (UcnVal < (UTF32)0xFFFF) {
*ResultBuf++ = (UcnVal & 0x000000FF);
@@ -262,6 +279,9 @@ static void EncodeUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
*ResultBuf++ = (surrogate2 & 0x0000FF00) >> 8;
return;
}
+
+ assert(CharByteWidth == 1 && "UTF-8 encoding is only for 1 byte characters");
+
// Now that we've parsed/checked the UCN, we convert from UTF32->UTF8.
// The conversion below was inspired by:
// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c
@@ -371,7 +391,7 @@ NumericLiteralParser(const char *begin, const char *end,
// Done.
} else if (isxdigit(*s) && !(*s == 'e' || *s == 'E')) {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin),
- diag::err_invalid_decimal_digit) << llvm::StringRef(s, 1);
+ diag::err_invalid_decimal_digit) << StringRef(s, 1);
hadError = true;
return;
} else if (*s == '.') {
@@ -434,7 +454,7 @@ NumericLiteralParser(const char *begin, const char *end,
continue; // Success.
case 'i':
case 'I':
- if (PP.getLangOptions().Microsoft) {
+ if (PP.getLangOptions().MicrosoftExt) {
if (isFPConstant || isLong || isLongLong) break;
// Allow i8, i16, i32, i64, and i128.
@@ -498,7 +518,7 @@ NumericLiteralParser(const char *begin, const char *end,
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin),
isFPConstant ? diag::err_invalid_suffix_float_constant :
diag::err_invalid_suffix_integer_constant)
- << llvm::StringRef(SuffixBegin, ThisTokEnd-SuffixBegin);
+ << StringRef(SuffixBegin, ThisTokEnd-SuffixBegin);
hadError = true;
return;
}
@@ -528,7 +548,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
}
// A binary exponent can appear with or with a '.'. If dotted, the
// binary exponent is required.
- if ((*s == 'p' || *s == 'P') && !PP.getLangOptions().CPlusPlus0x) {
+ if (*s == 'p' || *s == 'P') {
const char *Exponent = s;
s++;
saw_exponent = true;
@@ -542,12 +562,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
}
s = first_non_digit;
- // In C++0x, we cannot support hexadecmial floating literals because
- // they conflict with user-defined literals, so we warn in previous
- // versions of C++ by default.
- if (PP.getLangOptions().CPlusPlus)
- PP.Diag(TokLoc, diag::ext_hexconstant_cplusplus);
- else if (!PP.getLangOptions().HexFloats)
+ if (!PP.getLangOptions().HexFloats)
PP.Diag(TokLoc, diag::ext_hexconstant_invalid);
} else if (saw_period) {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin),
@@ -569,7 +584,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
// Done.
} else if (isxdigit(*s)) {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin),
- diag::err_invalid_binary_digit) << llvm::StringRef(s, 1);
+ diag::err_invalid_binary_digit) << StringRef(s, 1);
hadError = true;
}
// Other suffixes will be diagnosed by the caller.
@@ -599,7 +614,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
// the code is using an incorrect base.
if (isxdigit(*s) && *s != 'e' && *s != 'E') {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin),
- diag::err_invalid_octal_digit) << llvm::StringRef(s, 1);
+ diag::err_invalid_octal_digit) << StringRef(s, 1);
hadError = true;
return;
}
@@ -688,7 +703,6 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) {
llvm::APFloat::opStatus
NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) {
using llvm::APFloat;
- using llvm::StringRef;
unsigned n = std::min(SuffixBegin - ThisTokBegin, ThisTokEnd - ThisTokBegin);
return Result.convertFromString(StringRef(ThisTokBegin, n),
@@ -696,14 +710,51 @@ NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) {
}
+/// character-literal: [C++0x lex.ccon]
+/// ' c-char-sequence '
+/// u' c-char-sequence '
+/// U' c-char-sequence '
+/// L' c-char-sequence '
+/// c-char-sequence:
+/// c-char
+/// c-char-sequence c-char
+/// c-char:
+/// any member of the source character set except the single-quote ',
+/// backslash \, or new-line character
+/// escape-sequence
+/// universal-character-name
+/// escape-sequence: [C++0x lex.ccon]
+/// simple-escape-sequence
+/// octal-escape-sequence
+/// hexadecimal-escape-sequence
+/// simple-escape-sequence:
+/// one of \' \" \? \\ \a \b \f \n \r \t \v
+/// octal-escape-sequence:
+/// \ octal-digit
+/// \ octal-digit octal-digit
+/// \ octal-digit octal-digit octal-digit
+/// hexadecimal-escape-sequence:
+/// \x hexadecimal-digit
+/// hexadecimal-escape-sequence hexadecimal-digit
+/// universal-character-name:
+/// \u hex-quad
+/// \U hex-quad hex-quad
+/// hex-quad:
+/// hex-digit hex-digit hex-digit hex-digit
+///
CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
- SourceLocation Loc, Preprocessor &PP) {
+ SourceLocation Loc, Preprocessor &PP,
+ tok::TokenKind kind) {
// At this point we know that the character matches the regex "L?'.*'".
HadError = false;
- // Determine if this is a wide character.
- IsWide = begin[0] == 'L';
- if (IsWide) ++begin;
+ Kind = kind;
+
+ // Determine if this is a wide or UTF character.
+ if (Kind == tok::wide_char_constant || Kind == tok::utf16_char_constant ||
+ Kind == tok::utf32_char_constant) {
+ ++begin;
+ }
// Skip over the entry quote.
assert(begin[0] == '\'' && "Invalid token lexed");
@@ -730,8 +781,9 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
// Is this a Universal Character Name escape?
if (begin[0] != '\\') // If this is a normal character, consume it.
- ResultChar = *begin++;
+ ResultChar = (unsigned char)*begin++;
else { // Otherwise, this is an escape character.
+ unsigned CharWidth = getCharWidth(Kind, PP.getTargetInfo());
// Check for UCN.
if (begin[1] == 'u' || begin[1] == 'U') {
uint32_t utf32 = 0;
@@ -742,19 +794,22 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
HadError = 1;
}
ResultChar = utf32;
+ if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) {
+ PP.Diag(Loc, diag::warn_ucn_escape_too_large);
+ ResultChar &= ~0U >> (32-CharWidth);
+ }
} else {
// Otherwise, this is a non-UCN escape character. Process it.
ResultChar = ProcessCharEscape(begin, end, HadError,
FullSourceLoc(Loc,PP.getSourceManager()),
- IsWide,
- &PP.getDiagnostics(), PP.getTargetInfo());
+ CharWidth, &PP.getDiagnostics());
}
}
// If this is a multi-character constant (e.g. 'abc'), handle it. These are
// implementation defined (C99 6.4.4.4p10).
if (NumCharsSoFar) {
- if (IsWide) {
+ if (!isAscii()) {
// Emulate GCC's (unintentional?) behavior: L'ab' -> L'b'.
LitVal = 0;
} else {
@@ -776,8 +831,8 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
if (NumCharsSoFar > 1) {
// Warn about discarding the top bits for multi-char wide-character
// constants (L'abcd').
- if (IsWide)
- PP.Diag(Loc, diag::warn_extraneous_wide_char_constant);
+ if (!isAscii())
+ PP.Diag(Loc, diag::warn_extraneous_char_constant);
else if (NumCharsSoFar != 4)
PP.Diag(Loc, diag::ext_multichar_character_literal);
else
@@ -789,47 +844,62 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
// Transfer the value from APInt to uint64_t
Value = LitVal.getZExtValue();
- if (IsWide && PP.getLangOptions().ShortWChar && Value > 0xFFFF)
- PP.Diag(Loc, diag::warn_ucn_escape_too_large);
-
// If this is a single narrow character, sign extend it (e.g. '\xFF' is "-1")
// if 'char' is signed for this target (C99 6.4.4.4p10). Note that multiple
// character constants are not sign extended in the this implementation:
// '\xFF\xFF' = 65536 and '\x0\xFF' = 255, which matches GCC.
- if (!IsWide && NumCharsSoFar == 1 && (Value & 128) &&
+ if (isAscii() && NumCharsSoFar == 1 && (Value & 128) &&
PP.getLangOptions().CharIsSigned)
Value = (signed char)Value;
}
-/// string-literal: [C99 6.4.5]
-/// " [s-char-sequence] "
-/// L" [s-char-sequence] "
+/// string-literal: [C++0x lex.string]
+/// encoding-prefix " [s-char-sequence] "
+/// encoding-prefix R raw-string
+/// encoding-prefix:
+/// u8
+/// u
+/// U
+/// L
/// s-char-sequence:
/// s-char
/// s-char-sequence s-char
/// s-char:
-/// any source character except the double quote ",
-/// backslash \, or newline character
-/// escape-character
-/// universal-character-name
-/// escape-character: [C99 6.4.4.4]
-/// \ escape-code
+/// any member of the source character set except the double-quote ",
+/// backslash \, or new-line character
+/// escape-sequence
/// universal-character-name
-/// escape-code:
-/// character-escape-code
-/// octal-escape-code
-/// hex-escape-code
-/// character-escape-code: one of
-/// n t b r f v a
-/// \ ' " ?
-/// octal-escape-code:
-/// octal-digit
-/// octal-digit octal-digit
-/// octal-digit octal-digit octal-digit
-/// hex-escape-code:
-/// x hex-digit
-/// hex-escape-code hex-digit
+/// raw-string:
+/// " d-char-sequence ( r-char-sequence ) d-char-sequence "
+/// r-char-sequence:
+/// r-char
+/// r-char-sequence r-char
+/// r-char:
+/// any member of the source character set, except a right parenthesis )
+/// followed by the initial d-char-sequence (which may be empty)
+/// followed by a double quote ".
+/// d-char-sequence:
+/// d-char
+/// d-char-sequence d-char
+/// d-char:
+/// any member of the basic source character set except:
+/// space, the left parenthesis (, the right parenthesis ),
+/// the backslash \, and the control characters representing horizontal
+/// tab, vertical tab, form feed, and newline.
+/// escape-sequence: [C++0x lex.ccon]
+/// simple-escape-sequence
+/// octal-escape-sequence
+/// hexadecimal-escape-sequence
+/// simple-escape-sequence:
+/// one of \' \" \? \\ \a \b \f \n \r \t \v
+/// octal-escape-sequence:
+/// \ octal-digit
+/// \ octal-digit octal-digit
+/// \ octal-digit octal-digit octal-digit
+/// hexadecimal-escape-sequence:
+/// \x hexadecimal-digit
+/// hexadecimal-escape-sequence hexadecimal-digit
/// universal-character-name:
/// \u hex-quad
/// \U hex-quad hex-quad
@@ -841,8 +911,8 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
Preprocessor &PP, bool Complain)
: SM(PP.getSourceManager()), Features(PP.getLangOptions()),
Target(PP.getTargetInfo()), Diags(Complain ? &PP.getDiagnostics() : 0),
- MaxTokenLength(0), SizeBound(0), wchar_tByteWidth(0),
- ResultPtr(ResultBuf.data()), hadError(false), AnyWide(false), Pascal(false) {
+ MaxTokenLength(0), SizeBound(0), CharByteWidth(0), Kind(tok::unknown),
+ ResultPtr(ResultBuf.data()), hadError(false), Pascal(false) {
init(StringToks, NumStringToks);
}
@@ -862,7 +932,7 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
MaxTokenLength = StringToks[0].getLength();
assert(StringToks[0].getLength() >= 2 && "literal token is invalid!");
SizeBound = StringToks[0].getLength()-2; // -2 for "".
- AnyWide = StringToks[0].is(tok::wide_string_literal);
+ Kind = StringToks[0].getKind();
hadError = false;
@@ -883,8 +953,18 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
if (StringToks[i].getLength() > MaxTokenLength)
MaxTokenLength = StringToks[i].getLength();
- // Remember if we see any wide strings.
- AnyWide |= StringToks[i].is(tok::wide_string_literal);
+ // Remember if we see any wide or utf-8/16/32 strings.
+ // Also check for illegal concatenations.
+ if (StringToks[i].isNot(Kind) && StringToks[i].isNot(tok::string_literal)) {
+ if (isAscii()) {
+ Kind = StringToks[i].getKind();
+ } else {
+ if (Diags)
+ Diags->Report(FullSourceLoc(StringToks[i].getLocation(), SM),
+ diag::err_unsupported_string_concat);
+ hadError = true;
+ }
+ }
}
// Include space for the null terminator.
@@ -892,19 +972,14 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
// TODO: K&R warning: "traditional C rejects string constant concatenation"
- // Get the width in bytes of wchar_t. If no wchar_t strings are used, do not
- // query the target. As such, wchar_tByteWidth is only valid if AnyWide=true.
- wchar_tByteWidth = ~0U;
- if (AnyWide) {
- wchar_tByteWidth = Target.getWCharWidth();
- assert((wchar_tByteWidth & 7) == 0 && "Assumes wchar_t is byte multiple!");
- wchar_tByteWidth /= 8;
- }
+ // Get the width in bytes of char/wchar_t/char16_t/char32_t
+ CharByteWidth = getCharWidth(Kind, Target);
+ assert((CharByteWidth & 7) == 0 && "Assumes character size is byte multiple");
+ CharByteWidth /= 8;
// The output buffer size needs to be large enough to hold wide characters.
// This is a worst-case assumption which basically corresponds to L"" "long".
- if (AnyWide)
- SizeBound *= wchar_tByteWidth;
+ SizeBound *= CharByteWidth;
// Size the temporary buffer to hold the result string data.
ResultBuf.resize(SizeBound);
@@ -929,78 +1004,82 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
Lexer::getSpelling(StringToks[i], ThisTokBuf, SM, Features,
&StringInvalid);
if (StringInvalid) {
- hadError = 1;
+ hadError = true;
continue;
}
const char *ThisTokEnd = ThisTokBuf+ThisTokLen-1; // Skip end quote.
- bool wide = false;
// TODO: Input character set mapping support.
- // Skip L marker for wide strings.
- if (ThisTokBuf[0] == 'L') {
- wide = true;
+ // Skip marker for wide or unicode strings.
+ if (ThisTokBuf[0] == 'L' || ThisTokBuf[0] == 'u' || ThisTokBuf[0] == 'U') {
++ThisTokBuf;
+ // Skip 8 of u8 marker for utf8 strings.
+ if (ThisTokBuf[0] == '8')
+ ++ThisTokBuf;
}
- assert(ThisTokBuf[0] == '"' && "Expected quote, lexer broken?");
- ++ThisTokBuf;
-
- // Check if this is a pascal string
- if (Features.PascalStrings && ThisTokBuf + 1 != ThisTokEnd &&
- ThisTokBuf[0] == '\\' && ThisTokBuf[1] == 'p') {
+ // Check for raw string
+ if (ThisTokBuf[0] == 'R') {
+ ThisTokBuf += 2; // skip R"
- // If the \p sequence is found in the first token, we have a pascal string
- // Otherwise, if we already have a pascal string, ignore the first \p
- if (i == 0) {
+ const char *Prefix = ThisTokBuf;
+ while (ThisTokBuf[0] != '(')
++ThisTokBuf;
- Pascal = true;
- } else if (Pascal)
- ThisTokBuf += 2;
- }
+ ++ThisTokBuf; // skip '('
+
+ // remove same number of characters from the end
+ if (ThisTokEnd >= ThisTokBuf + (ThisTokBuf - Prefix))
+ ThisTokEnd -= (ThisTokBuf - Prefix);
+
+ // Copy the string over
+ CopyStringFragment(StringRef(ThisTokBuf, ThisTokEnd - ThisTokBuf));
+ } else {
+ assert(ThisTokBuf[0] == '"' && "Expected quote, lexer broken?");
+ ++ThisTokBuf; // skip "
+
+ // Check if this is a pascal string
+ if (Features.PascalStrings && ThisTokBuf + 1 != ThisTokEnd &&
+ ThisTokBuf[0] == '\\' && ThisTokBuf[1] == 'p') {
- while (ThisTokBuf != ThisTokEnd) {
- // Is this a span of non-escape characters?
- if (ThisTokBuf[0] != '\\') {
- const char *InStart = ThisTokBuf;
- do {
+ // If the \p sequence is found in the first token, we have a pascal string
+ // Otherwise, if we already have a pascal string, ignore the first \p
+ if (i == 0) {
++ThisTokBuf;
- } while (ThisTokBuf != ThisTokEnd && ThisTokBuf[0] != '\\');
-
- // Copy the character span over.
- unsigned Len = ThisTokBuf-InStart;
- if (!AnyWide) {
- memcpy(ResultPtr, InStart, Len);
- ResultPtr += Len;
- } else {
- // Note: our internal rep of wide char tokens is always little-endian.
- for (; Len; --Len, ++InStart) {
- *ResultPtr++ = InStart[0];
- // Add zeros at the end.
- for (unsigned i = 1, e = wchar_tByteWidth; i != e; ++i)
- *ResultPtr++ = 0;
- }
- }
- continue;
- }
- // Is this a Universal Character Name escape?
- if (ThisTokBuf[1] == 'u' || ThisTokBuf[1] == 'U') {
- EncodeUCNEscape(ThisTokBuf, ThisTokEnd, ResultPtr,
- hadError, FullSourceLoc(StringToks[i].getLocation(),SM),
- wide, Diags, Features);
- continue;
+ Pascal = true;
+ } else if (Pascal)
+ ThisTokBuf += 2;
}
- // Otherwise, this is a non-UCN escape character. Process it.
- unsigned ResultChar =
- ProcessCharEscape(ThisTokBuf, ThisTokEnd, hadError,
- FullSourceLoc(StringToks[i].getLocation(), SM),
- AnyWide, Diags, Target);
- // Note: our internal rep of wide char tokens is always little-endian.
- *ResultPtr++ = ResultChar & 0xFF;
+ while (ThisTokBuf != ThisTokEnd) {
+ // Is this a span of non-escape characters?
+ if (ThisTokBuf[0] != '\\') {
+ const char *InStart = ThisTokBuf;
+ do {
+ ++ThisTokBuf;
+ } while (ThisTokBuf != ThisTokEnd && ThisTokBuf[0] != '\\');
+
+ // Copy the character span over.
+ CopyStringFragment(StringRef(InStart, ThisTokBuf - InStart));
+ continue;
+ }
+ // Is this a Universal Character Name escape?
+ if (ThisTokBuf[1] == 'u' || ThisTokBuf[1] == 'U') {
+ EncodeUCNEscape(ThisTokBuf, ThisTokEnd, ResultPtr,
+ hadError, FullSourceLoc(StringToks[i].getLocation(),SM),
+ CharByteWidth, Diags, Features);
+ continue;
+ }
+ // Otherwise, this is a non-UCN escape character. Process it.
+ unsigned ResultChar =
+ ProcessCharEscape(ThisTokBuf, ThisTokEnd, hadError,
+ FullSourceLoc(StringToks[i].getLocation(), SM),
+ CharByteWidth*8, Diags);
+
+ // Note: our internal rep of wide char tokens is always little-endian.
+ *ResultPtr++ = ResultChar & 0xFF;
- if (AnyWide) {
- for (unsigned i = 1, e = wchar_tByteWidth; i != e; ++i)
+ for (unsigned i = 1, e = CharByteWidth; i != e; ++i)
*ResultPtr++ = ResultChar >> i*8;
}
}
@@ -1008,8 +1087,7 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
if (Pascal) {
ResultBuf[0] = ResultPtr-&ResultBuf[0]-1;
- if (AnyWide)
- ResultBuf[0] /= wchar_tByteWidth;
+ ResultBuf[0] /= CharByteWidth;
// Verify that pascal strings aren't too large.
if (GetStringLength() > 256) {
@@ -1018,7 +1096,7 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
diag::err_pascal_string_too_long)
<< SourceRange(StringToks[0].getLocation(),
StringToks[NumStringToks-1].getLocation());
- hadError = 1;
+ hadError = true;
return;
}
} else if (Diags) {
@@ -1036,6 +1114,25 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
}
+/// copyStringFragment - This function copies from Start to End into ResultPtr.
+/// Performs widening for multi-byte characters.
+void StringLiteralParser::CopyStringFragment(StringRef Fragment) {
+ // Copy the character span over.
+ if (CharByteWidth == 1) {
+ memcpy(ResultPtr, Fragment.data(), Fragment.size());
+ ResultPtr += Fragment.size();
+ } else {
+ // Note: our internal rep of wide char tokens is always little-endian.
+ for (StringRef::iterator I=Fragment.begin(), E=Fragment.end(); I!=E; ++I) {
+ *ResultPtr++ = *I;
+ // Add zeros at the end.
+ for (unsigned i = 1, e = CharByteWidth; i != e; ++i)
+ *ResultPtr++ = 0;
+ }
+ }
+}
+
+
/// getOffsetOfStringByte - This function returns the offset of the
/// specified byte of the string data represented by Token. This handles
/// advancing over escape sequences in the string.
@@ -1052,7 +1149,8 @@ unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok,
if (StringInvalid)
return 0;
- assert(SpellingPtr[0] != 'L' && "Doesn't handle wide strings yet");
+ assert(SpellingPtr[0] != 'L' && SpellingPtr[0] != 'u' &&
+ SpellingPtr[0] != 'U' && "Doesn't handle wide or utf strings yet");
const char *SpellingStart = SpellingPtr;
@@ -1077,7 +1175,7 @@ unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok,
bool HadError = false;
ProcessCharEscape(SpellingPtr, SpellingEnd, HadError,
FullSourceLoc(Tok.getLocation(), SM),
- false, Diags, Target);
+ CharByteWidth*8, Diags);
assert(!HadError && "This method isn't valid on erroneous strings");
--ByteNo;
}
diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp
index 968c15e3c27b..1846d1c05e30 100644
--- a/lib/Lex/MacroArgs.cpp
+++ b/lib/Lex/MacroArgs.cpp
@@ -15,13 +15,15 @@
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/LexDiagnostic.h"
+
+#include <algorithm>
+
using namespace clang;
/// MacroArgs ctor function - This destroys the vector passed in.
MacroArgs *MacroArgs::create(const MacroInfo *MI,
- const Token *UnexpArgTokens,
- unsigned NumToks, bool VarargsElided,
- Preprocessor &PP) {
+ llvm::ArrayRef<Token> UnexpArgTokens,
+ bool VarargsElided, Preprocessor &PP) {
assert(MI->isFunctionLike() &&
"Can't have args for an object-like macro!");
MacroArgs **ResultEnt = 0;
@@ -31,12 +33,12 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI,
// free list. If so, reuse it.
for (MacroArgs **Entry = &PP.MacroArgCache; *Entry;
Entry = &(*Entry)->ArgCache)
- if ((*Entry)->NumUnexpArgTokens >= NumToks &&
+ if ((*Entry)->NumUnexpArgTokens >= UnexpArgTokens.size() &&
(*Entry)->NumUnexpArgTokens < ClosestMatch) {
ResultEnt = Entry;
// If we have an exact match, use it.
- if ((*Entry)->NumUnexpArgTokens == NumToks)
+ if ((*Entry)->NumUnexpArgTokens == UnexpArgTokens.size())
break;
// Otherwise, use the best fit.
ClosestMatch = (*Entry)->NumUnexpArgTokens;
@@ -45,21 +47,22 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI,
MacroArgs *Result;
if (ResultEnt == 0) {
// Allocate memory for a MacroArgs object with the lexer tokens at the end.
- Result = (MacroArgs*)malloc(sizeof(MacroArgs) + NumToks*sizeof(Token));
+ Result = (MacroArgs*)malloc(sizeof(MacroArgs) +
+ UnexpArgTokens.size() * sizeof(Token));
// Construct the MacroArgs object.
- new (Result) MacroArgs(NumToks, VarargsElided);
+ new (Result) MacroArgs(UnexpArgTokens.size(), VarargsElided);
} else {
Result = *ResultEnt;
// Unlink this node from the preprocessors singly linked list.
*ResultEnt = Result->ArgCache;
- Result->NumUnexpArgTokens = NumToks;
+ Result->NumUnexpArgTokens = UnexpArgTokens.size();
Result->VarargsElided = VarargsElided;
}
// Copy the actual unexpanded tokens to immediately after the result ptr.
- if (NumToks)
- memcpy(const_cast<Token*>(Result->getUnexpArgument(0)),
- UnexpArgTokens, NumToks*sizeof(Token));
+ if (!UnexpArgTokens.empty())
+ std::copy(UnexpArgTokens.begin(), UnexpArgTokens.end(),
+ const_cast<Token*>(Result->getUnexpArgument(0)));
return Result;
}
@@ -186,7 +189,8 @@ MacroArgs::getPreExpArgument(unsigned Arg, const MacroInfo *MI,
///
Token MacroArgs::StringifyArgument(const Token *ArgToks,
Preprocessor &PP, bool Charify,
- SourceLocation hashInstLoc) {
+ SourceLocation ExpansionLocStart,
+ SourceLocation ExpansionLocEnd) {
Token Tok;
Tok.startToken();
Tok.setKind(Charify ? tok::char_constant : tok::string_literal);
@@ -208,13 +212,21 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
// by 6.10.3.2p2.
if (Tok.is(tok::string_literal) || // "foo"
Tok.is(tok::wide_string_literal) || // L"foo"
- Tok.is(tok::char_constant)) { // 'x' and L'x'.
+ 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'.
bool Invalid = false;
std::string TokStr = PP.getSpelling(Tok, &Invalid);
if (!Invalid) {
std::string Str = Lexer::Stringify(TokStr);
Result.append(Str.begin(), Str.end());
}
+ } else if (Tok.is(tok::code_completion)) {
+ PP.CodeCompleteNaturalLanguage();
} else {
// Otherwise, just append the token. Do some gymnastics to get the token
// in place and avoid copies where possible.
@@ -274,7 +286,8 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
}
}
- PP.CreateString(&Result[0], Result.size(), Tok, hashInstLoc);
+ PP.CreateString(&Result[0], Result.size(), Tok,
+ ExpansionLocStart, ExpansionLocEnd);
return Tok;
}
@@ -282,7 +295,8 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
/// that has been 'stringified' as required by the # operator.
const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo,
Preprocessor &PP,
- SourceLocation hashInstLoc) {
+ SourceLocation ExpansionLocStart,
+ SourceLocation ExpansionLocEnd) {
assert(ArgNo < NumUnexpArgTokens && "Invalid argument number!");
if (StringifiedArgs.empty()) {
StringifiedArgs.resize(getNumArguments());
@@ -291,6 +305,8 @@ const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo,
}
if (StringifiedArgs[ArgNo].isNot(tok::string_literal))
StringifiedArgs[ArgNo] = StringifyArgument(getUnexpArgument(ArgNo), PP,
- /*Charify=*/false, hashInstLoc);
+ /*Charify=*/false,
+ ExpansionLocStart,
+ ExpansionLocEnd);
return StringifiedArgs[ArgNo];
}
diff --git a/lib/Lex/MacroArgs.h b/lib/Lex/MacroArgs.h
index a962dacf7c93..cf86d710adb7 100644
--- a/lib/Lex/MacroArgs.h
+++ b/lib/Lex/MacroArgs.h
@@ -14,6 +14,8 @@
#ifndef LLVM_CLANG_MACROARGS_H
#define LLVM_CLANG_MACROARGS_H
+#include "llvm/ADT/ArrayRef.h"
+
#include <vector>
namespace clang {
@@ -58,9 +60,8 @@ public:
/// MacroArgs ctor function - Create a new MacroArgs object with the specified
/// macro and argument info.
static MacroArgs *create(const MacroInfo *MI,
- const Token *UnexpArgTokens,
- unsigned NumArgTokens, bool VarargsElided,
- Preprocessor &PP);
+ llvm::ArrayRef<Token> UnexpArgTokens,
+ bool VarargsElided, Preprocessor &PP);
/// destroy - Destroy and deallocate the memory for this object.
///
@@ -88,7 +89,8 @@ public:
/// getStringifiedArgument - Compute, cache, and return the specified argument
/// that has been 'stringified' as required by the # operator.
const Token &getStringifiedArgument(unsigned ArgNo, Preprocessor &PP,
- SourceLocation hashInstLoc);
+ SourceLocation ExpansionLocStart,
+ SourceLocation ExpansionLocEnd);
/// getNumArguments - Return the number of arguments passed into this macro
/// invocation.
@@ -109,7 +111,8 @@ public:
///
static Token StringifyArgument(const Token *ArgToks,
Preprocessor &PP, bool Charify,
- SourceLocation hashInstLoc);
+ SourceLocation ExpansionLocStart,
+ SourceLocation ExpansionLocEnd);
/// deallocate - This should only be called by the Preprocessor when managing
diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp
index 0a16a2567219..5a7af5639830 100644
--- a/lib/Lex/MacroInfo.cpp
+++ b/lib/Lex/MacroInfo.cpp
@@ -21,6 +21,7 @@ MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) {
IsGNUVarargs = false;
IsBuiltinMacro = false;
IsFromAST = false;
+ ChangedAfterLoad = false;
IsDisabled = false;
IsUsed = false;
IsAllowRedefinitionsWithoutWarning = false;
@@ -40,6 +41,7 @@ MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator) {
IsGNUVarargs = MI.IsGNUVarargs;
IsBuiltinMacro = MI.IsBuiltinMacro;
IsFromAST = MI.IsFromAST;
+ ChangedAfterLoad = MI.ChangedAfterLoad;
IsDisabled = MI.IsDisabled;
IsUsed = MI.IsUsed;
IsAllowRedefinitionsWithoutWarning = MI.IsAllowRedefinitionsWithoutWarning;
@@ -68,9 +70,9 @@ unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const {
assert((macroEnd.isFileID() || lastToken.is(tok::comment)) &&
"Macro defined in macro?");
std::pair<FileID, unsigned>
- startInfo = SM.getDecomposedInstantiationLoc(macroStart);
+ startInfo = SM.getDecomposedExpansionLoc(macroStart);
std::pair<FileID, unsigned>
- endInfo = SM.getDecomposedInstantiationLoc(macroEnd);
+ endInfo = SM.getDecomposedExpansionLoc(macroEnd);
assert(startInfo.first == endInfo.first &&
"Macro definition spanning multiple FileIDs ?");
assert(startInfo.second <= endInfo.second);
diff --git a/lib/Lex/PPCaching.cpp b/lib/Lex/PPCaching.cpp
index 33106591c3ba..986341b98668 100644
--- a/lib/Lex/PPCaching.cpp
+++ b/lib/Lex/PPCaching.cpp
@@ -74,6 +74,8 @@ void Preprocessor::EnterCachingLexMode() {
return;
PushIncludeMacroStack();
+ if (CurLexerKind != CLK_LexAfterModuleImport)
+ CurLexerKind = CLK_CachingLexer;
}
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 4af5fabe5c80..de50c750e4d6 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -17,6 +17,7 @@
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/CodeCompletionHandler.h"
+#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/Pragma.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
@@ -102,8 +103,8 @@ void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) {
if (MacroNameTok.is(tok::code_completion)) {
if (CodeComplete)
CodeComplete->CodeCompleteMacroName(isDefineUndef == 1);
+ setCodeCompletionReached();
LexUnexpandedToken(MacroNameTok);
- return;
}
// Missing macro name?
@@ -192,7 +193,8 @@ void Preprocessor::CheckEndOfDirective(const char *DirType, bool EnableMacros) {
/// the first valid token.
void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
bool FoundNonSkipPortion,
- bool FoundElse) {
+ bool FoundElse,
+ SourceLocation ElseLoc) {
++NumSkipped;
assert(CurTokenLexer == 0 && CurPPLexer && "Lexing a macro, not a file?");
@@ -214,6 +216,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
if (Tok.is(tok::code_completion)) {
if (CodeComplete)
CodeComplete->CodeCompleteInConditionalExclusion();
+ setCodeCompletionReached();
continue;
}
@@ -222,7 +225,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// Emit errors for each unterminated conditional on the stack, including
// the current one.
while (!CurPPLexer->ConditionalStack.empty()) {
- if (!isCodeCompletionFile(Tok.getLocation()))
+ if (CurLexer->getFileLoc() != CodeCompletionFileLoc)
Diag(CurPPLexer->ConditionalStack.back().IfLoc,
diag::err_pp_unterminated_conditional);
CurPPLexer->ConditionalStack.pop_back();
@@ -275,9 +278,9 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// that we can't use Tok.getIdentifierInfo() because its lookup is disabled
// when skipping.
char DirectiveBuf[20];
- llvm::StringRef Directive;
+ StringRef Directive;
if (!Tok.needsCleaning() && Tok.getLength() < 20) {
- Directive = llvm::StringRef(RawCharData, Tok.getLength());
+ Directive = StringRef(RawCharData, Tok.getLength());
} else {
std::string DirectiveStr = getSpelling(Tok);
unsigned IdLen = DirectiveStr.size();
@@ -288,11 +291,11 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
continue;
}
memcpy(DirectiveBuf, &DirectiveStr[0], IdLen);
- Directive = llvm::StringRef(DirectiveBuf, IdLen);
+ Directive = StringRef(DirectiveBuf, IdLen);
}
if (Directive.startswith("if")) {
- llvm::StringRef Sub = Directive.substr(2);
+ StringRef Sub = Directive.substr(2);
if (Sub.empty() || // "if"
Sub == "def" || // "ifdef"
Sub == "ndef") { // "ifndef"
@@ -307,7 +310,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
Callbacks->Endif();
}
} else if (Directive[0] == 'e') {
- llvm::StringRef Sub = Directive.substr(1);
+ StringRef Sub = Directive.substr(1);
if (Sub == "ndif") { // "endif"
CheckEndOfDirective("endif");
PPConditionalInfo CondInfo;
@@ -387,6 +390,11 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// of the file, just stop skipping and return to lexing whatever came after
// the #if block.
CurPPLexer->LexingRawMode = false;
+
+ if (Callbacks) {
+ SourceLocation BeginLoc = ElseLoc.isValid() ? ElseLoc : IfTokenLoc;
+ Callbacks->SourceRangeSkipped(SourceRange(BeginLoc, Tok.getLocation()));
+ }
}
void Preprocessor::PTHSkipExcludedConditionalBlock() {
@@ -472,12 +480,13 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() {
/// return null on failure. isAngled indicates whether the file reference is
/// for system #include's or not (i.e. using <> instead of "").
const FileEntry *Preprocessor::LookupFile(
- llvm::StringRef Filename,
+ StringRef Filename,
bool isAngled,
const DirectoryLookup *FromDir,
const DirectoryLookup *&CurDir,
- llvm::SmallVectorImpl<char> *SearchPath,
- llvm::SmallVectorImpl<char> *RelativePath) {
+ SmallVectorImpl<char> *SearchPath,
+ SmallVectorImpl<char> *RelativePath,
+ StringRef *SuggestedModule) {
// If the header lookup mechanism may be relative to the current file, pass in
// info about where the current file is.
const FileEntry *CurFileEnt = 0;
@@ -501,12 +510,13 @@ const FileEntry *Preprocessor::LookupFile(
CurDir = CurDirLookup;
const FileEntry *FE = HeaderInfo.LookupFile(
Filename, isAngled, FromDir, CurDir, CurFileEnt,
- SearchPath, RelativePath);
+ SearchPath, RelativePath, SuggestedModule);
if (FE) return FE;
// Otherwise, see if this is a subframework header. If so, this is relative
// to one of the headers on the #include stack. Walk the list of the current
// 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,
@@ -581,6 +591,7 @@ TryAgain:
if (CodeComplete)
CodeComplete->CodeCompleteDirective(
CurPPLexer->getConditionalStackDepth() > 0);
+ setCodeCompletionReached();
return;
case tok::numeric_constant: // # 7 GNU line marker directive.
if (getLangOptions().AsmPreprocessor)
@@ -652,6 +663,9 @@ TryAgain:
case tok::pp_unassert:
//isExtension = true; // FIXME: implement #unassert
break;
+
+ case tok::pp___export_macro__:
+ return HandleMacroExportDirective(Result);
}
break;
}
@@ -758,9 +772,13 @@ 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 = Features.C99 ? 2147483648U : 32768U;
+ unsigned LineLimit = 32768U;
+ if (Features.C99 || Features.CPlusPlus0x)
+ LineLimit = 2147483648U;
if (LineNo >= LineLimit)
Diag(DigitTok, diag::ext_pp_line_too_big) << LineLimit;
+ else if (Features.CPlusPlus0x && LineNo >= 32768U)
+ Diag(DigitTok, diag::warn_cxx98_compat_pp_line_too_big);
int FilenameID = -1;
Token StrTok;
@@ -777,7 +795,7 @@ void Preprocessor::HandleLineDirective(Token &Tok) {
} else {
// Parse and validate the string, converting it into a unique ID.
StringLiteralParser Literal(&StrTok, 1, *this);
- assert(!Literal.AnyWide && "Didn't allow wide strings in");
+ assert(Literal.isAscii() && "Didn't allow wide strings in");
if (Literal.hadError)
return DiscardUntilEndOfDirective();
if (Literal.Pascal) {
@@ -825,7 +843,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
// If we are leaving the current presumed file, check to make sure the
// presumed include stack isn't empty!
FileID CurFileID =
- SM.getDecomposedInstantiationLoc(FlagTok.getLocation()).first;
+ SM.getDecomposedExpansionLoc(FlagTok.getLocation()).first;
PresumedLoc PLoc = SM.getPresumedLoc(FlagTok.getLocation());
if (PLoc.isInvalid())
return true;
@@ -834,7 +852,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
// different physical file, then we aren't in a "1" line marker flag region.
SourceLocation IncLoc = PLoc.getIncludeLoc();
if (IncLoc.isInvalid() ||
- SM.getDecomposedInstantiationLoc(IncLoc).first != CurFileID) {
+ SM.getDecomposedExpansionLoc(IncLoc).first != CurFileID) {
PP.Diag(FlagTok, diag::err_pp_linemarker_invalid_pop);
PP.DiscardUntilEndOfDirective();
return true;
@@ -910,7 +928,7 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
} else {
// Parse and validate the string, converting it into a unique ID.
StringLiteralParser Literal(&StrTok, 1, *this);
- assert(!Literal.AnyWide && "Didn't allow wide strings in");
+ assert(Literal.isAscii() && "Didn't allow wide strings in");
if (Literal.hadError)
return DiscardUntilEndOfDirective();
if (Literal.Pascal) {
@@ -1000,6 +1018,37 @@ void Preprocessor::HandleIdentSCCSDirective(Token &Tok) {
}
}
+/// \brief Handle a #__export_macro__ directive.
+void Preprocessor::HandleMacroExportDirective(Token &Tok) {
+ Token MacroNameTok;
+ ReadMacroName(MacroNameTok, 2);
+
+ // Error reading macro name? If so, diagnostic already issued.
+ if (MacroNameTok.is(tok::eod))
+ return;
+
+ // Check to see if this is the last token on the #__export_macro__ line.
+ CheckEndOfDirective("__export_macro__");
+
+ // Okay, we finally have a valid identifier to undef.
+ MacroInfo *MI = getMacroInfo(MacroNameTok.getIdentifierInfo());
+
+ // If the macro is not defined, this is an error.
+ if (MI == 0) {
+ Diag(MacroNameTok, diag::err_pp_export_non_macro)
+ << MacroNameTok.getIdentifierInfo();
+ return;
+ }
+
+ // Note that this macro has now been exported.
+ MI->setExportLocation(MacroNameTok.getLocation());
+
+ // If this macro definition came from a PCH file, mark it
+ // as having changed since serialization.
+ if (MI->isFromAST())
+ MI->setChangedAfterLoad();
+}
+
//===----------------------------------------------------------------------===//
// Preprocessor Include Directive Handling.
//===----------------------------------------------------------------------===//
@@ -1011,7 +1060,7 @@ void Preprocessor::HandleIdentSCCSDirective(Token &Tok) {
/// spelling of the filename, but is also expected to handle the case when
/// this method decides to use a different buffer.
bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc,
- llvm::StringRef &Buffer) {
+ StringRef &Buffer) {
// Get the text form of the filename.
assert(!Buffer.empty() && "Can't have tokens with empty spellings!");
@@ -1020,27 +1069,27 @@ bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc,
if (Buffer[0] == '<') {
if (Buffer.back() != '>') {
Diag(Loc, diag::err_pp_expects_filename);
- Buffer = llvm::StringRef();
+ Buffer = StringRef();
return true;
}
isAngled = true;
} else if (Buffer[0] == '"') {
if (Buffer.back() != '"') {
Diag(Loc, diag::err_pp_expects_filename);
- Buffer = llvm::StringRef();
+ Buffer = StringRef();
return true;
}
isAngled = false;
} else {
Diag(Loc, diag::err_pp_expects_filename);
- Buffer = llvm::StringRef();
+ Buffer = StringRef();
return true;
}
// Diagnose #include "" as invalid.
if (Buffer.size() <= 2) {
Diag(Loc, diag::err_pp_empty_filename);
- Buffer = llvm::StringRef();
+ Buffer = StringRef();
return true;
}
@@ -1070,6 +1119,7 @@ bool Preprocessor::ConcatenateIncludeName(
// FIXME: Provide code completion for #includes.
if (CurTok.is(tok::code_completion)) {
+ setCodeCompletionReached();
Lex(CurTok);
continue;
}
@@ -1122,7 +1172,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
// Reserve a buffer to get the spelling.
llvm::SmallString<128> FilenameBuffer;
- llvm::StringRef Filename;
+ StringRef Filename;
SourceLocation End;
switch (FilenameTok.getKind()) {
@@ -1171,23 +1221,44 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
return;
}
+ // Complain about attempts to #include files in an audit pragma.
+ if (PragmaARCCFCodeAuditedLoc.isValid()) {
+ Diag(HashLoc, diag::err_pp_include_in_arc_cf_code_audited);
+ Diag(PragmaARCCFCodeAuditedLoc, diag::note_pragma_entered_here);
+
+ // Immediately leave the pragma.
+ PragmaARCCFCodeAuditedLoc = SourceLocation();
+ }
+
// Search include directories.
const DirectoryLookup *CurDir;
llvm::SmallString<1024> SearchPath;
llvm::SmallString<1024> RelativePath;
// We get the raw path only if we have 'Callbacks' to which we later pass
// the path.
+ StringRef SuggestedModule;
const FileEntry *File = LookupFile(
Filename, isAngled, LookupFrom, CurDir,
- Callbacks ? &SearchPath : NULL, Callbacks ? &RelativePath : NULL);
-
+ Callbacks ? &SearchPath : NULL, Callbacks ? &RelativePath : NULL,
+ AutoModuleImport? &SuggestedModule : 0);
+
+ // If we are supposed to import a module rather than including the header,
+ // do so now.
+ if (!SuggestedModule.empty()) {
+ TheModuleLoader.loadModule(IncludeTok.getLocation(),
+ Identifiers.get(SuggestedModule),
+ FilenameTok.getLocation());
+ return;
+ }
+
// Notify the callback object that we've seen an inclusion directive.
if (Callbacks)
Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled, File,
End, SearchPath, RelativePath);
if (File == 0) {
- Diag(FilenameTok, diag::warn_pp_file_not_found) << Filename;
+ if (!SuppressIncludeNotFoundError)
+ Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
return;
}
@@ -1284,7 +1355,7 @@ void Preprocessor::HandleIncludeMacrosDirective(SourceLocation HashLoc,
/// closing ), updating MI with what we learn. Return true if an error occurs
/// parsing the arg list.
bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI) {
- llvm::SmallVector<IdentifierInfo*, 32> Arguments;
+ SmallVector<IdentifierInfo*, 32> Arguments;
Token Tok;
while (1) {
@@ -1298,8 +1369,10 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI) {
Diag(Tok, diag::err_pp_expected_ident_in_arg_list);
return true;
case tok::ellipsis: // #define X(... -> C99 varargs
- // Warn if use of C99 feature in non-C99 mode.
- if (!Features.C99) Diag(Tok, diag::ext_variadic_macro);
+ if (!Features.C99)
+ Diag(Tok, Features.CPlusPlus0x ?
+ diag::warn_cxx98_compat_variadic_macro :
+ diag::ext_variadic_macro);
// Lex the token after the identifier.
LexUnexpandedToken(Tok);
@@ -1423,7 +1496,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
// Read the first token after the arg list for down below.
LexUnexpandedToken(Tok);
- } else if (Features.C99) {
+ } else if (Features.C99 || Features.CPlusPlus0x) {
// 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);
@@ -1564,7 +1637,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
// warn-because-unused-macro set. If it gets used it will be removed from set.
if (isInPrimaryFile() && // don't warn for include'd macros.
Diags->getDiagnosticLevel(diag::pp_macro_not_used,
- MI->getDefinitionLoc()) != Diagnostic::Ignored) {
+ MI->getDefinitionLoc()) != DiagnosticsEngine::Ignored) {
MI->setIsWarnIfUnused(true);
WarnUnusedMacroLocs.insert(MI->getDefinitionLoc());
}
@@ -1765,7 +1838,7 @@ void Preprocessor::HandleElseDirective(Token &Result) {
// Finally, skip the rest of the contents of this block.
SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
- /*FoundElse*/true);
+ /*FoundElse*/true, Result.getLocation());
if (Callbacks)
Callbacks->Else();
@@ -1798,7 +1871,8 @@ void Preprocessor::HandleElifDirective(Token &ElifToken) {
// Finally, skip the rest of the contents of this block.
SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
- /*FoundElse*/CI.FoundElse);
+ /*FoundElse*/CI.FoundElse,
+ ElifToken.getLocation());
if (Callbacks)
Callbacks->Elif(SourceRange(ConditionalBegin, ConditionalEnd));
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index 8fcfc70a7c67..20f624a0bb12 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -23,6 +23,7 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/LexDiagnostic.h"
#include "llvm/ADT/APSInt.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
namespace {
@@ -83,20 +84,21 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
Result.setBegin(PeekTok.getLocation());
// Get the next token, don't expand it.
- PP.LexUnexpandedToken(PeekTok);
+ PP.LexUnexpandedNonComment(PeekTok);
// Two options, it can either be a pp-identifier or a (.
SourceLocation LParenLoc;
if (PeekTok.is(tok::l_paren)) {
// Found a paren, remember we saw it and skip it.
LParenLoc = PeekTok.getLocation();
- PP.LexUnexpandedToken(PeekTok);
+ PP.LexUnexpandedNonComment(PeekTok);
}
if (PeekTok.is(tok::code_completion)) {
if (PP.getCodeCompletionHandler())
PP.getCodeCompletionHandler()->CodeCompleteMacroName(false);
- PP.LexUnexpandedToken(PeekTok);
+ PP.setCodeCompletionReached();
+ PP.LexUnexpandedNonComment(PeekTok);
}
// If we don't have a pp-identifier now, this is an error.
@@ -115,12 +117,16 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
PP.markMacroAsUsed(Macro);
}
- // Consume identifier.
- Result.setEnd(PeekTok.getLocation());
- PP.LexUnexpandedToken(PeekTok);
+ // Invoke the 'defined' callback.
+ if (PPCallbacks *Callbacks = PP.getPPCallbacks())
+ Callbacks->Defined(PeekTok);
// If we are in parens, ensure we have a trailing ).
if (LParenLoc.isValid()) {
+ // Consume identifier.
+ Result.setEnd(PeekTok.getLocation());
+ PP.LexUnexpandedNonComment(PeekTok);
+
if (PeekTok.isNot(tok::r_paren)) {
PP.Diag(PeekTok.getLocation(), diag::err_pp_missing_rparen) << "defined";
PP.Diag(LParenLoc, diag::note_matching) << "(";
@@ -129,6 +135,10 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
// Consume the ).
Result.setEnd(PeekTok.getLocation());
PP.LexNonComment(PeekTok);
+ } else {
+ // Consume identifier.
+ Result.setEnd(PeekTok.getLocation());
+ PP.LexNonComment(PeekTok);
}
// Success, remember that we saw defined(X).
@@ -152,7 +162,8 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
if (PeekTok.is(tok::code_completion)) {
if (PP.getCodeCompletionHandler())
PP.getCodeCompletionHandler()->CodeCompletePreprocessorExpression();
- PP.LexUnexpandedToken(PeekTok);
+ PP.setCodeCompletionReached();
+ PP.LexNonComment(PeekTok);
}
// If this token's spelling is a pp-identifier, check to see if it is
@@ -188,7 +199,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
case tok::numeric_constant: {
llvm::SmallString<64> IntegerBuffer;
bool NumberInvalid = false;
- llvm::StringRef Spelling = PP.getSpelling(PeekTok, IntegerBuffer,
+ StringRef Spelling = PP.getSpelling(PeekTok, IntegerBuffer,
&NumberInvalid);
if (NumberInvalid)
return true; // a diagnostic was already reported
@@ -205,9 +216,9 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
assert(Literal.isIntegerLiteral() && "Unknown ppnumber");
// long long is a C99 feature.
- if (!PP.getLangOptions().C99 && !PP.getLangOptions().CPlusPlus0x
- && Literal.isLongLong)
- PP.Diag(PeekTok, diag::ext_longlong);
+ if (!PP.getLangOptions().C99 && Literal.isLongLong)
+ PP.Diag(PeekTok, PP.getLangOptions().CPlusPlus0x ?
+ diag::warn_cxx98_compat_longlong : diag::ext_longlong);
// Parse the integer literal into Result.
if (Literal.GetIntegerValue(Result.Val)) {
@@ -236,15 +247,18 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
PP.LexNonComment(PeekTok);
return false;
}
- case tok::char_constant: { // 'x'
+ case tok::char_constant: // 'x'
+ case tok::wide_char_constant: { // L'x'
+ case tok::utf16_char_constant: // u'x'
+ case tok::utf32_char_constant: // U'x'
llvm::SmallString<32> CharBuffer;
bool CharInvalid = false;
- llvm::StringRef ThisTok = PP.getSpelling(PeekTok, CharBuffer, &CharInvalid);
+ StringRef ThisTok = PP.getSpelling(PeekTok, CharBuffer, &CharInvalid);
if (CharInvalid)
return true;
CharLiteralParser Literal(ThisTok.begin(), ThisTok.end(),
- PeekTok.getLocation(), PP);
+ PeekTok.getLocation(), PP, PeekTok.getKind());
if (Literal.hadError())
return true; // A diagnostic was already emitted.
@@ -255,6 +269,10 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
NumBits = TI.getIntWidth();
else if (Literal.isWide())
NumBits = TI.getWCharWidth();
+ else if (Literal.isUTF16())
+ NumBits = TI.getChar16Width();
+ else if (Literal.isUTF32())
+ NumBits = TI.getChar32Width();
else
NumBits = TI.getCharWidth();
@@ -262,8 +280,9 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
llvm::APSInt Val(NumBits);
// Set the value.
Val = Literal.getValue();
- // Set the signedness.
- Val.setIsUnsigned(!PP.getLangOptions().CharIsSigned);
+ // Set the signedness. UTF-16 and UTF-32 are always unsigned
+ if (!Literal.isUTF16() && !Literal.isUTF32())
+ Val.setIsUnsigned(!PP.getLangOptions().CharIsSigned);
if (Result.Val.getBitWidth() > Val.getBitWidth()) {
Result.Val = Val.extend(Result.Val.getBitWidth());
@@ -521,7 +540,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
bool Overflow = false;
switch (Operator) {
- default: assert(0 && "Unknown operator token!");
+ default: llvm_unreachable("Unknown operator token!");
case tok::percent:
if (RHS.Val != 0)
Res = LHS.Val % RHS.Val;
@@ -704,7 +723,7 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
// Peek ahead one token.
Token Tok;
- Lex(Tok);
+ LexNonComment(Tok);
// C99 6.10.1p3 - All expressions are evaluated as intmax_t or uintmax_t.
unsigned BitWidth = getTargetInfo().getIntMaxTWidth();
@@ -759,4 +778,3 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective;
return ResVal.Val != 0;
}
-
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index bf28199b888a..25a98ae47b6e 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -89,7 +89,14 @@ void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir,
<< std::string(SourceMgr.getBufferName(FileStart)) << "";
return;
}
-
+
+ if (isCodeCompletionEnabled() &&
+ SourceMgr.getFileEntryForID(FID) == CodeCompletionFile) {
+ CodeCompletionFileLoc = SourceMgr.getLocForStartOfFile(FID);
+ CodeCompletionLoc =
+ CodeCompletionFileLoc.getLocWithOffset(CodeCompletionOffset);
+ }
+
EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir);
return;
}
@@ -106,7 +113,9 @@ void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer,
CurLexer.reset(TheLexer);
CurPPLexer = TheLexer;
CurDirLookup = CurDir;
-
+ if (CurLexerKind != CLK_LexAfterModuleImport)
+ CurLexerKind = CLK_Lexer;
+
// Notify the client, if desired, that we are in a new source file.
if (Callbacks && !CurLexer->Is_PragmaLexer) {
SrcMgr::CharacteristicKind FileType =
@@ -128,7 +137,9 @@ void Preprocessor::EnterSourceFileWithPTH(PTHLexer *PL,
CurDirLookup = CurDir;
CurPTHLexer.reset(PL);
CurPPLexer = CurPTHLexer.get();
-
+ if (CurLexerKind != CLK_LexAfterModuleImport)
+ CurLexerKind = CLK_PTHLexer;
+
// Notify the client, if desired, that we are in a new source file.
if (Callbacks) {
FileID FID = CurPPLexer->getFileID();
@@ -152,6 +163,8 @@ void Preprocessor::EnterMacro(Token &Tok, SourceLocation ILEnd,
CurTokenLexer.reset(TokenLexerCache[--NumCachedTokenLexers]);
CurTokenLexer->Init(Tok, ILEnd, Args);
}
+ if (CurLexerKind != CLK_LexAfterModuleImport)
+ CurLexerKind = CLK_TokenLexer;
}
/// EnterTokenStream - Add a "macro" context to the top of the include stack,
@@ -181,6 +194,8 @@ void Preprocessor::EnterTokenStream(const Token *Toks, unsigned NumToks,
CurTokenLexer.reset(TokenLexerCache[--NumCachedTokenLexers]);
CurTokenLexer->Init(Toks, NumToks, DisableMacroExpansion, OwnsTokens);
}
+ if (CurLexerKind != CLK_LexAfterModuleImport)
+ CurLexerKind = CLK_TokenLexer;
}
/// HandleEndOfFile - This callback is invoked when the lexer hits the end of
@@ -201,9 +216,50 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
}
}
+ // Complain about reaching an EOF within arc_cf_code_audited.
+ if (PragmaARCCFCodeAuditedLoc.isValid()) {
+ Diag(PragmaARCCFCodeAuditedLoc, diag::err_pp_eof_in_arc_cf_code_audited);
+
+ // Recover by leaving immediately.
+ PragmaARCCFCodeAuditedLoc = SourceLocation();
+ }
+
// If this is a #include'd file, pop it off the include stack and continue
// lexing the #includer file.
if (!IncludeMacroStack.empty()) {
+
+ // If we lexed the code-completion file, act as if we reached EOF.
+ if (isCodeCompletionEnabled() && CurPPLexer &&
+ SourceMgr.getLocForStartOfFile(CurPPLexer->getFileID()) ==
+ CodeCompletionFileLoc) {
+ if (CurLexer) {
+ Result.startToken();
+ CurLexer->FormTokenWithChars(Result, CurLexer->BufferEnd, tok::eof);
+ CurLexer.reset();
+ } else {
+ assert(CurPTHLexer && "Got EOF but no current lexer set!");
+ CurPTHLexer->getEOF(Result);
+ CurPTHLexer.reset();
+ }
+
+ CurPPLexer = 0;
+ return true;
+ }
+
+ if (!isEndOfMacro && CurPPLexer &&
+ SourceMgr.getIncludeLoc(CurPPLexer->getFileID()).isValid()) {
+ // Notify SourceManager to record the number of FileIDs that were created
+ // during lexing of the #include'd file.
+ unsigned NumFIDs =
+ SourceMgr.local_sloc_entry_size() -
+ CurPPLexer->getInitialNumSLocEntries() + 1/*#include'd file*/;
+ SourceMgr.setNumCreatedFIDsForFileID(CurPPLexer->getFileID(), NumFIDs);
+ }
+
+ FileID ExitedFID;
+ if (Callbacks && !isEndOfMacro && CurPPLexer)
+ ExitedFID = CurPPLexer->getFileID();
+
// We're done with the #included file.
RemoveTopOfLexerStack();
@@ -212,7 +268,7 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
SrcMgr::CharacteristicKind FileType =
SourceMgr.getFileCharacteristic(CurPPLexer->getSourceLocation());
Callbacks->FileChanged(CurPPLexer->getSourceLocation(),
- PPCallbacks::ExitFile, FileType);
+ PPCallbacks::ExitFile, FileType, ExitedFID);
}
// Client should lex another token.
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index ecd4d4cfc68b..e10c95c75f25 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -21,10 +21,12 @@
#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 "llvm/ADT/STLExtras.h"
#include "llvm/Config/config.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/ErrorHandling.h"
#include <cstdio>
#include <ctime>
using namespace clang;
@@ -91,9 +93,10 @@ void Preprocessor::RegisterBuiltinMacros() {
Ident__has_attribute = RegisterBuiltinMacro(*this, "__has_attribute");
Ident__has_include = RegisterBuiltinMacro(*this, "__has_include");
Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next");
+ Ident__has_warning = RegisterBuiltinMacro(*this, "__has_warning");
// Microsoft Extensions.
- if (Features.Microsoft)
+ if (Features.MicrosoftExt)
Ident__pragma = RegisterBuiltinMacro(*this, "__pragma");
else
Ident__pragma = 0;
@@ -185,7 +188,8 @@ 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, MI,
+ Identifier.getLocation());
ExpandBuiltinMacro(Identifier);
return false;
}
@@ -226,13 +230,14 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// Notice that this macro has been used.
markMacroAsUsed(MI);
- if (Callbacks) Callbacks->MacroExpands(Identifier, MI);
-
- // If we started lexing a macro, enter the macro expansion body.
-
// Remember where the token is expanded.
SourceLocation ExpandLoc = Identifier.getLocation();
+ if (Callbacks) Callbacks->MacroExpands(Identifier, MI,
+ SourceRange(ExpandLoc, ExpansionEnd));
+
+ // If we started lexing a macro, enter the macro expansion body.
+
// If this macro expands to no tokens, don't bother to push it onto the
// expansion stack, only to take it right back off.
if (MI->getNumTokens() == 0) {
@@ -255,7 +260,6 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
if (HadLeadingSpace) Identifier.setFlag(Token::LeadingSpace);
}
Identifier.setFlag(Token::LeadingEmptyMacro);
- LastEmptyMacroExpansionLoc = ExpandLoc;
++NumFastMacroExpanded;
return false;
@@ -284,8 +288,8 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// Update the tokens location to include both its expansion and physical
// locations.
SourceLocation Loc =
- SourceMgr.createInstantiationLoc(Identifier.getLocation(), ExpandLoc,
- ExpansionEnd,Identifier.getLength());
+ SourceMgr.createExpansionLoc(Identifier.getLocation(), ExpandLoc,
+ ExpansionEnd,Identifier.getLength());
Identifier.setLocation(Loc);
// If this is a disabled macro or #define X X, we must mark the result as
@@ -333,7 +337,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// ArgTokens - Build up a list of tokens that make up each argument. Each
// argument is separated by an EOF token. Use a SmallVector so we can avoid
// heap allocations in the common case.
- llvm::SmallVector<Token, 64> ArgTokens;
+ SmallVector<Token, 64> ArgTokens;
unsigned NumActuals = 0;
while (Tok.isNot(tok::r_paren)) {
@@ -352,13 +356,6 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// an argument value in a macro could expand to ',' or '(' or ')'.
LexUnexpandedToken(Tok);
- if (Tok.is(tok::code_completion)) {
- if (CodeComplete)
- CodeComplete->CodeCompleteMacroArgument(MacroName.getIdentifierInfo(),
- MI, NumActuals);
- 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.
@@ -393,7 +390,15 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
if (MacroInfo *MI = getMacroInfo(Tok.getIdentifierInfo()))
if (!MI->isEnabled())
Tok.setFlag(Token::DisableExpand);
+ } else if (Tok.is(tok::code_completion)) {
+ if (CodeComplete)
+ CodeComplete->CodeCompleteMacroArgument(MacroName.getIdentifierInfo(),
+ MI, NumActuals);
+ // Don't mark that we reached the code-completion point because the
+ // parser is going to handle the token and there will be another
+ // code-completion callback.
}
+
ArgTokens.push_back(Tok);
}
@@ -416,8 +421,10 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// Empty arguments are standard in C99 and C++0x, and are supported as an extension in
// other modes.
- if (ArgTokens.size() == ArgTokenStart && !Features.C99 && !Features.CPlusPlus0x)
- Diag(Tok, diag::ext_empty_fnmacro_arg);
+ if (ArgTokens.size() == ArgTokenStart && !Features.C99)
+ Diag(Tok, Features.CPlusPlus0x ?
+ diag::warn_cxx98_compat_empty_fnmacro_arg :
+ diag::ext_empty_fnmacro_arg);
// Add a marker EOF token to the end of the token list for this argument.
Token EOFTok;
@@ -487,8 +494,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
return 0;
}
- return MacroArgs::create(MI, ArgTokens.data(), ArgTokens.size(),
- isVarargsElided, *this);
+ return MacroArgs::create(MI, ArgTokens, isVarargsElided, *this);
}
/// \brief Keeps macro expanded tokens for TokenLexers.
@@ -497,7 +503,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
/// going to lex in the cache and when it finishes the tokens are removed
/// from the end of the cache.
Token *Preprocessor::cacheMacroExpandedTokens(TokenLexer *tokLexer,
- llvm::ArrayRef<Token> tokens) {
+ ArrayRef<Token> tokens) {
assert(tokLexer);
if (tokens.empty())
return 0;
@@ -597,34 +603,48 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("objc_arc", LangOpts.ObjCAutoRefCount)
.Case("objc_arc_weak", LangOpts.ObjCAutoRefCount &&
LangOpts.ObjCRuntimeHasWeak)
+ .Case("objc_fixed_enum", LangOpts.ObjC2)
+ .Case("objc_instancetype", LangOpts.ObjC2)
.Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
.Case("objc_weak_class", LangOpts.ObjCNonFragileABI)
.Case("ownership_holds", true)
.Case("ownership_returns", true)
.Case("ownership_takes", true)
// C1X features
+ .Case("c_alignas", LangOpts.C1X)
.Case("c_generic_selections", LangOpts.C1X)
.Case("c_static_assert", LangOpts.C1X)
// C++0x features
.Case("cxx_access_control_sfinae", LangOpts.CPlusPlus0x)
.Case("cxx_alias_templates", LangOpts.CPlusPlus0x)
+ .Case("cxx_alignas", LangOpts.CPlusPlus0x)
.Case("cxx_attributes", LangOpts.CPlusPlus0x)
.Case("cxx_auto_type", LangOpts.CPlusPlus0x)
+ //.Case("cxx_constexpr", false);
.Case("cxx_decltype", LangOpts.CPlusPlus0x)
.Case("cxx_default_function_template_args", 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_inheriting_constructors", false)
.Case("cxx_inline_namespaces", LangOpts.CPlusPlus0x)
//.Case("cxx_lambdas", false)
+ .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", false)
.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", false)
+ //.Case("cxx_unrestricted_unions", false)
+ //.Case("cxx_user_literals", false)
.Case("cxx_variadic_templates", LangOpts.CPlusPlus0x)
// Type traits
.Case("has_nothrow_assign", LangOpts.CPlusPlus)
@@ -639,16 +659,31 @@ 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)
- .Case("is_empty", 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 &&
+ PP.getIdentifierInfo("__is_empty")->getTokenID()
+ != tok::identifier)
.Case("is_enum", LangOpts.CPlusPlus)
.Case("is_literal", LangOpts.CPlusPlus)
.Case("is_standard_layout", LangOpts.CPlusPlus)
- .Case("is_pod", LangOpts.CPlusPlus)
+ // __is_pod is available only if the horrible
+ // "struct __is_pod" parsing hack hasn't been needed in this
+ // translation unit. If it has, __is_pod reverts to a normal
+ // identifier and __has_feature(is_pod) evaluates false.
+ .Case("is_pod",
+ LangOpts.CPlusPlus &&
+ PP.getIdentifierInfo("__is_pod")->getTokenID()
+ != tok::identifier)
.Case("is_polymorphic", LangOpts.CPlusPlus)
.Case("is_trivial", LangOpts.CPlusPlus)
.Case("is_trivially_copyable", LangOpts.CPlusPlus)
.Case("is_union", LangOpts.CPlusPlus)
.Case("tls", PP.getTargetInfo().isTLSSupported())
+ .Case("underlying_type", LangOpts.CPlusPlus)
.Default(false);
}
@@ -661,7 +696,8 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) {
// If the use of an extension results in an error diagnostic, extensions are
// effectively unavailable, so just return false here.
- if (PP.getDiagnostics().getExtensionHandlingBehavior()==Diagnostic::Ext_Error)
+ if (PP.getDiagnostics().getExtensionHandlingBehavior() ==
+ DiagnosticsEngine::Ext_Error)
return false;
const LangOptions &LangOpts = PP.getLangOptions();
@@ -670,12 +706,16 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) {
// must be less restrictive than HasFeature's.
return llvm::StringSwitch<bool>(II->getName())
// C1X features supported by other languages as extensions.
+ .Case("c_alignas", true)
.Case("c_generic_selections", true)
.Case("c_static_assert", true)
// C++0x features supported by other languages as extensions.
.Case("cxx_deleted_functions", LangOpts.CPlusPlus)
+ .Case("cxx_explicit_conversions", LangOpts.CPlusPlus)
.Case("cxx_inline_namespaces", LangOpts.CPlusPlus)
+ .Case("cxx_nonstatic_member_init", LangOpts.CPlusPlus)
.Case("cxx_override_control", LangOpts.CPlusPlus)
+ .Case("cxx_range_for", LangOpts.CPlusPlus)
.Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus)
.Case("cxx_rvalue_references", LangOpts.CPlusPlus)
.Default(false);
@@ -714,7 +754,7 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
// Reserve a buffer to get the spelling.
llvm::SmallString<128> FilenameBuffer;
- llvm::StringRef Filename;
+ StringRef Filename;
SourceLocation EndLoc;
switch (Tok.getKind()) {
@@ -753,7 +793,7 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
// Search include directories.
const DirectoryLookup *CurDir;
const FileEntry *File =
- PP.LookupFile(Filename, isAngled, LookupFrom, CurDir, NULL, NULL);
+ PP.LookupFile(Filename, isAngled, LookupFrom, CurDir, NULL, NULL, NULL);
// Get the result value. Result = true means the file exists.
bool Result = File != 0;
@@ -837,7 +877,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
// can matter for a function-like macro that expands to contain __LINE__.
// Skip down through expansion points until we find a file loc for the
// end of the expansion history.
- Loc = SourceMgr.getInstantiationRange(Loc).second;
+ Loc = SourceMgr.getExpansionRange(Loc).second;
PresumedLoc PLoc = SourceMgr.getPresumedLoc(Loc);
// __LINE__ expands to a simple numeric value.
@@ -874,18 +914,18 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
ComputeDATE_TIME(DATELoc, TIMELoc, *this);
Tok.setKind(tok::string_literal);
Tok.setLength(strlen("\"Mmm dd yyyy\""));
- Tok.setLocation(SourceMgr.createInstantiationLoc(DATELoc, Tok.getLocation(),
- Tok.getLocation(),
- Tok.getLength()));
+ Tok.setLocation(SourceMgr.createExpansionLoc(DATELoc, Tok.getLocation(),
+ Tok.getLocation(),
+ Tok.getLength()));
return;
} else if (II == Ident__TIME__) {
if (!TIMELoc.isValid())
ComputeDATE_TIME(DATELoc, TIMELoc, *this);
Tok.setKind(tok::string_literal);
Tok.setLength(strlen("\"hh:mm:ss\""));
- Tok.setLocation(SourceMgr.createInstantiationLoc(TIMELoc, Tok.getLocation(),
- Tok.getLocation(),
- Tok.getLength()));
+ Tok.setLocation(SourceMgr.createExpansionLoc(TIMELoc, Tok.getLocation(),
+ Tok.getLocation(),
+ Tok.getLength()));
return;
} else if (II == Ident__INCLUDE_LEVEL__) {
// Compute the presumed include depth of this token. This can be affected
@@ -923,7 +963,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Result = "??? ??? ?? ??:??:?? ????\n";
}
// Surround the string with " and strip the trailing newline.
- OS << '"' << llvm::StringRef(Result, strlen(Result)-1) << '"';
+ OS << '"' << StringRef(Result, strlen(Result)-1) << '"';
Tok.setKind(tok::string_literal);
} else if (II == Ident__COUNTER__) {
// __COUNTER__ expands to a simple numeric value.
@@ -983,10 +1023,78 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Value = EvaluateHasIncludeNext(Tok, II, *this);
OS << (int)Value;
Tok.setKind(tok::numeric_constant);
+ } else if (II == Ident__has_warning) {
+ // The argument should be a parenthesized string literal.
+ // The argument to these builtins should be a parenthesized identifier.
+ SourceLocation StartLoc = Tok.getLocation();
+ bool IsValid = false;
+ bool Value = false;
+ // Read the '('.
+ Lex(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)) {
+ StrToks.push_back(Tok);
+ 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);
+ }
+ } while (false);
+
+ if (!IsValid)
+ Diag(StartLoc, diag::err_warning_check_malformed);
+
+ OS << (int)Value;
+ Tok.setKind(tok::numeric_constant);
} else {
- assert(0 && "Unknown identifier!");
+ llvm_unreachable("Unknown identifier!");
}
- CreateString(OS.str().data(), OS.str().size(), Tok, Tok.getLocation());
+ CreateString(OS.str().data(), OS.str().size(), Tok,
+ Tok.getLocation(), Tok.getLocation());
}
void Preprocessor::markMacroAsUsed(MacroInfo *MI) {
diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp
index e5ef0fdf20eb..e0c4cf0c16c8 100644
--- a/lib/Lex/PTHLexer.cpp
+++ b/lib/Lex/PTHLexer.cpp
@@ -73,7 +73,7 @@ LexNextToken:
Tok.setKind(TKind);
Tok.setFlag(TFlags);
assert(!LexingRawMode);
- Tok.setLocation(FileStartLoc.getFileLocWithOffset(FileOffset));
+ Tok.setLocation(FileStartLoc.getLocWithOffset(FileOffset));
Tok.setLength(Len);
// Handle identifiers.
@@ -147,7 +147,7 @@ bool PTHLexer::LexEndOfFile(Token &Result) {
// If we are in a #if directive, emit an error.
while (!ConditionalStack.empty()) {
- if (!PP->isCodeCompletionFile(FileStartLoc))
+ if (PP->getCodeCompletionFileLoc() != FileStartLoc)
PP->Diag(ConditionalStack.back().IfLoc,
diag::err_pp_unterminated_conditional);
ConditionalStack.pop_back();
@@ -297,7 +297,7 @@ SourceLocation PTHLexer::getSourceLocation() {
// NOTE: This is a virtual function; hence it is defined out-of-line.
const unsigned char *OffsetPtr = CurPtr + (DISK_TOKEN_SIZE - 4);
uint32_t Offset = ReadLE32(OffsetPtr);
- return FileStartLoc.getFileLocWithOffset(Offset);
+ return FileStartLoc.getLocWithOffset(Offset);
}
//===----------------------------------------------------------------------===//
@@ -380,7 +380,7 @@ public:
}
static unsigned ComputeHash(const internal_key_type& a) {
- return llvm::HashString(llvm::StringRef(a.first, a.second));
+ return llvm::HashString(StringRef(a.first, a.second));
}
// This hopefully will just get inlined and removed by the optimizer.
@@ -431,11 +431,12 @@ PTHManager::~PTHManager() {
free(PerIDCache);
}
-static void InvalidPTH(Diagnostic &Diags, const char *Msg) {
- Diags.Report(Diags.getCustomDiagID(Diagnostic::Error, Msg));
+static void InvalidPTH(DiagnosticsEngine &Diags, const char *Msg) {
+ Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, Msg));
}
-PTHManager *PTHManager::Create(const std::string &file, Diagnostic &Diags) {
+PTHManager *PTHManager::Create(const std::string &file,
+ DiagnosticsEngine &Diags) {
// Memory map the PTH file.
llvm::OwningPtr<llvm::MemoryBuffer> File;
@@ -572,10 +573,10 @@ IdentifierInfo* PTHManager::LazilyCreateIdentifierInfo(unsigned PersistentID) {
return II;
}
-IdentifierInfo* PTHManager::get(llvm::StringRef Name) {
+IdentifierInfo* PTHManager::get(StringRef Name) {
PTHStringIdLookup& SL = *((PTHStringIdLookup*)StringIdLookup);
// Double check our assumption that the last character isn't '\0'.
- assert(Name.empty() || Name.data()[Name.size()-1] != '\0');
+ assert(Name.empty() || Name.back() != '\0');
PTHStringIdLookup::iterator I = SL.find(std::make_pair(Name.data(),
Name.size()));
if (I == SL.end()) // No identifier found?
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index e6b28c13317b..f6532c2175a1 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -54,11 +54,11 @@ PragmaNamespace::~PragmaNamespace() {
/// specified name. If not, return the handler for the null identifier if it
/// exists, otherwise return null. If IgnoreNull is true (the default) then
/// the null handler isn't returned on failure to match.
-PragmaHandler *PragmaNamespace::FindHandler(llvm::StringRef Name,
+PragmaHandler *PragmaNamespace::FindHandler(StringRef Name,
bool IgnoreNull) const {
if (PragmaHandler *Handler = Handlers.lookup(Name))
return Handler;
- return IgnoreNull ? 0 : Handlers.lookup(llvm::StringRef());
+ return IgnoreNull ? 0 : Handlers.lookup(StringRef());
}
void PragmaNamespace::AddPragma(PragmaHandler *Handler) {
@@ -85,7 +85,7 @@ void PragmaNamespace::HandlePragma(Preprocessor &PP,
// Get the handler for this token. If there is no handler, ignore the pragma.
PragmaHandler *Handler
= FindHandler(Tok.getIdentifierInfo() ? Tok.getIdentifierInfo()->getName()
- : llvm::StringRef(),
+ : StringRef(),
/*IgnoreNull=*/false);
if (Handler == 0) {
PP.Diag(Tok, diag::warn_pragma_ignored);
@@ -210,7 +210,7 @@ void Preprocessor::HandleMicrosoft__pragma(Token &Tok) {
}
// Get the tokens enclosed within the __pragma(), as well as the final ')'.
- llvm::SmallVector<Token, 32> PragmaToks;
+ SmallVector<Token, 32> PragmaToks;
int NumParens = 0;
Lex(Tok);
while (Tok.isNot(tok::eof)) {
@@ -353,7 +353,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
// Reserve a buffer to get the spelling.
llvm::SmallString<128> FilenameBuffer;
bool Invalid = false;
- llvm::StringRef Filename = getSpelling(FilenameTok, FilenameBuffer, &Invalid);
+ StringRef Filename = getSpelling(FilenameTok, FilenameBuffer, &Invalid);
if (Invalid)
return;
@@ -366,9 +366,11 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
// Search include directories for this file.
const DirectoryLookup *CurDir;
- const FileEntry *File = LookupFile(Filename, isAngled, 0, CurDir, NULL, NULL);
+ const FileEntry *File = LookupFile(Filename, isAngled, 0, CurDir, NULL, NULL,
+ NULL);
if (File == 0) {
- Diag(FilenameTok, diag::warn_pp_file_not_found) << Filename;
+ if (!SuppressIncludeNotFoundError)
+ Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
return;
}
@@ -436,7 +438,7 @@ void Preprocessor::HandlePragmaComment(Token &Tok) {
// String concatenation allows multiple strings, which can even come from
// macro expansion.
// "foo " "bar" "Baz"
- llvm::SmallVector<Token, 4> StrToks;
+ SmallVector<Token, 4> StrToks;
while (Tok.is(tok::string_literal)) {
StrToks.push_back(Tok);
Lex(Tok);
@@ -444,7 +446,7 @@ void Preprocessor::HandlePragmaComment(Token &Tok) {
// Concatenate and parse the strings.
StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this);
- assert(!Literal.AnyWide && "Didn't allow wide strings in");
+ assert(Literal.isAscii() && "Didn't allow wide strings in");
if (Literal.hadError)
return;
if (Literal.Pascal) {
@@ -512,7 +514,7 @@ void Preprocessor::HandlePragmaMessage(Token &Tok) {
// String concatenation allows multiple strings, which can even come from
// macro expansion.
// "foo " "bar" "Baz"
- llvm::SmallVector<Token, 4> StrToks;
+ SmallVector<Token, 4> StrToks;
while (Tok.is(tok::string_literal)) {
StrToks.push_back(Tok);
Lex(Tok);
@@ -520,7 +522,7 @@ void Preprocessor::HandlePragmaMessage(Token &Tok) {
// Concatenate and parse the strings.
StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this);
- assert(!Literal.AnyWide && "Didn't allow wide strings in");
+ assert(Literal.isAscii() && "Didn't allow wide strings in");
if (Literal.hadError)
return;
if (Literal.Pascal) {
@@ -528,7 +530,7 @@ void Preprocessor::HandlePragmaMessage(Token &Tok) {
return;
}
- llvm::StringRef MessageString(Literal.GetString());
+ StringRef MessageString(Literal.GetString());
if (ExpectClosingParen) {
if (Tok.isNot(tok::r_paren)) {
@@ -662,7 +664,7 @@ void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) {
/// AddPragmaHandler - Add the specified pragma handler to the preprocessor.
/// If 'Namespace' is non-null, then it is a token required to exist on the
/// pragma line before the pragma string starts, e.g. "STDC" or "GCC".
-void Preprocessor::AddPragmaHandler(llvm::StringRef Namespace,
+void Preprocessor::AddPragmaHandler(StringRef Namespace,
PragmaHandler *Handler) {
PragmaNamespace *InsertNS = PragmaHandlers;
@@ -693,7 +695,7 @@ void Preprocessor::AddPragmaHandler(llvm::StringRef Namespace,
/// preprocessor. If \arg Namespace is non-null, then it should be the
/// namespace that \arg Handler was added to. It is an error to remove
/// a handler that has not been registered.
-void Preprocessor::RemovePragmaHandler(llvm::StringRef Namespace,
+void Preprocessor::RemovePragmaHandler(StringRef Namespace,
PragmaHandler *Handler) {
PragmaNamespace *NS = PragmaHandlers;
@@ -802,7 +804,7 @@ struct PragmaDebugHandler : public PragmaHandler {
IdentifierInfo *II = Tok.getIdentifierInfo();
if (II->isStr("assert")) {
- assert(0 && "This is an assertion!");
+ llvm_unreachable("This is an assertion!");
} else if (II->isStr("crash")) {
*(volatile int*) 0x11 = 0;
} else if (II->isStr("llvm_fatal_error")) {
@@ -889,7 +891,7 @@ public:
// String concatenation allows multiple strings, which can even come from
// macro expansion.
// "foo " "bar" "Baz"
- llvm::SmallVector<Token, 4> StrToks;
+ SmallVector<Token, 4> StrToks;
while (Tok.is(tok::string_literal)) {
StrToks.push_back(Tok);
PP.LexUnexpandedToken(Tok);
@@ -902,7 +904,7 @@ public:
// Concatenate and parse the strings.
StringLiteralParser Literal(&StrToks[0], StrToks.size(), PP);
- assert(!Literal.AnyWide && "Didn't allow wide strings in");
+ assert(Literal.isAscii() && "Didn't allow wide strings in");
if (Literal.hadError)
return;
if (Literal.Pascal) {
@@ -910,7 +912,7 @@ public:
return;
}
- llvm::StringRef WarningName(Literal.GetString());
+ StringRef WarningName(Literal.GetString());
if (WarningName.size() < 3 || WarningName[0] != '-' ||
WarningName[1] != 'W') {
@@ -1003,6 +1005,60 @@ struct PragmaSTDC_UnknownHandler : public PragmaHandler {
}
};
+/// PragmaARCCFCodeAuditedHandler -
+/// #pragma clang arc_cf_code_audited begin/end
+struct PragmaARCCFCodeAuditedHandler : public PragmaHandler {
+ PragmaARCCFCodeAuditedHandler() : PragmaHandler("arc_cf_code_audited") {}
+ virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &NameTok) {
+ SourceLocation Loc = NameTok.getLocation();
+ bool IsBegin;
+
+ Token Tok;
+
+ // Lex the 'begin' or 'end'.
+ PP.LexUnexpandedToken(Tok);
+ const IdentifierInfo *BeginEnd = Tok.getIdentifierInfo();
+ if (BeginEnd && BeginEnd->isStr("begin")) {
+ IsBegin = true;
+ } else if (BeginEnd && BeginEnd->isStr("end")) {
+ IsBegin = false;
+ } else {
+ PP.Diag(Tok.getLocation(), diag::err_pp_arc_cf_code_audited_syntax);
+ return;
+ }
+
+ // Verify that this is followed by EOD.
+ PP.LexUnexpandedToken(Tok);
+ if (Tok.isNot(tok::eod))
+ PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
+
+ // The start location of the active audit.
+ SourceLocation BeginLoc = PP.getPragmaARCCFCodeAuditedLoc();
+
+ // The start location we want after processing this.
+ SourceLocation NewLoc;
+
+ if (IsBegin) {
+ // Complain about attempts to re-enter an audit.
+ if (BeginLoc.isValid()) {
+ PP.Diag(Loc, diag::err_pp_double_begin_of_arc_cf_code_audited);
+ PP.Diag(BeginLoc, diag::note_pragma_entered_here);
+ }
+ NewLoc = Loc;
+ } else {
+ // Complain about attempts to leave an audit that doesn't exist.
+ if (!BeginLoc.isValid()) {
+ PP.Diag(Loc, diag::err_pp_unmatched_end_of_arc_cf_code_audited);
+ return;
+ }
+ NewLoc = SourceLocation();
+ }
+
+ PP.setPragmaARCCFCodeAuditedLoc(NewLoc);
+ }
+};
+
} // end anonymous namespace
@@ -1026,13 +1082,14 @@ void Preprocessor::RegisterBuiltinPragmas() {
AddPragmaHandler("clang", new PragmaDebugHandler());
AddPragmaHandler("clang", new PragmaDependencyHandler());
AddPragmaHandler("clang", new PragmaDiagnosticHandler("clang"));
+ AddPragmaHandler("clang", new PragmaARCCFCodeAuditedHandler());
AddPragmaHandler("STDC", new PragmaSTDC_FENV_ACCESSHandler());
AddPragmaHandler("STDC", new PragmaSTDC_CX_LIMITED_RANGEHandler());
AddPragmaHandler("STDC", new PragmaSTDC_UnknownHandler());
// MS extensions.
- if (Features.Microsoft) {
+ if (Features.MicrosoftExt) {
AddPragmaHandler(new PragmaCommentHandler());
}
}
diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp
index 9f93ab04502a..2816609d5f8f 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 "clang/Basic/IdentifierTable.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Capacity.h"
using namespace clang;
@@ -24,7 +24,7 @@ ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() { }
InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec,
InclusionKind Kind,
- llvm::StringRef FileName,
+ StringRef FileName,
bool InQuotes, const FileEntry *File,
SourceRange Range)
: PreprocessingDirective(InclusionDirectiveKind, Range),
@@ -34,116 +34,254 @@ InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec,
= (char*)PPRec.Allocate(FileName.size() + 1, llvm::alignOf<char>());
memcpy(Memory, FileName.data(), FileName.size());
Memory[FileName.size()] = 0;
- this->FileName = llvm::StringRef(Memory, FileName.size());
+ this->FileName = StringRef(Memory, FileName.size());
}
-void PreprocessingRecord::MaybeLoadPreallocatedEntities() const {
- if (!ExternalSource || LoadedPreallocatedEntities)
- return;
-
- LoadedPreallocatedEntities = true;
- ExternalSource->ReadPreprocessedEntities();
+PreprocessingRecord::PreprocessingRecord(SourceManager &SM,
+ bool IncludeNestedMacroExpansions)
+ : SourceMgr(SM), IncludeNestedMacroExpansions(IncludeNestedMacroExpansions),
+ ExternalSource(0)
+{
}
-PreprocessingRecord::PreprocessingRecord(bool IncludeNestedMacroExpansions)
- : IncludeNestedMacroExpansions(IncludeNestedMacroExpansions),
- ExternalSource(0), NumPreallocatedEntities(0),
- LoadedPreallocatedEntities(false)
-{
+/// \brief Returns a pair of [Begin, End) iterators of preprocessed entities
+/// that source range \arg R encompasses.
+std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+PreprocessingRecord::getPreprocessedEntitiesInRange(SourceRange Range) {
+ if (Range.isInvalid())
+ return std::make_pair(iterator(this, 0), iterator(this, 0));
+ assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin()));
+
+ std::pair<unsigned, unsigned>
+ Local = findLocalPreprocessedEntitiesInRange(Range);
+
+ // Check if range spans local entities.
+ if (!ExternalSource || SourceMgr.isLocalSourceLocation(Range.getBegin()))
+ return std::make_pair(iterator(this, Local.first),
+ iterator(this, Local.second));
+
+ std::pair<unsigned, unsigned>
+ Loaded = ExternalSource->findPreprocessedEntitiesInRange(Range);
+
+ // Check if range spans local entities.
+ if (Loaded.first == Loaded.second)
+ return std::make_pair(iterator(this, Local.first),
+ iterator(this, Local.second));
+
+ unsigned TotalLoaded = LoadedPreprocessedEntities.size();
+
+ // Check if range spans loaded entities.
+ if (Local.first == Local.second)
+ return std::make_pair(iterator(this, int(Loaded.first)-TotalLoaded),
+ iterator(this, int(Loaded.second)-TotalLoaded));
+
+ // Range spands loaded and local entities.
+ return std::make_pair(iterator(this, int(Loaded.first)-TotalLoaded),
+ iterator(this, Local.second));
}
-PreprocessingRecord::iterator
-PreprocessingRecord::begin(bool OnlyLocalEntities) {
- if (OnlyLocalEntities)
- return PreprocessedEntities.begin() + NumPreallocatedEntities;
-
- MaybeLoadPreallocatedEntities();
- return PreprocessedEntities.begin();
+std::pair<unsigned, unsigned>
+PreprocessingRecord::findLocalPreprocessedEntitiesInRange(
+ SourceRange Range) const {
+ if (Range.isInvalid())
+ return std::make_pair(0,0);
+ assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin()));
+
+ unsigned Begin = findBeginLocalPreprocessedEntity(Range.getBegin());
+ unsigned End = findEndLocalPreprocessedEntity(Range.getEnd());
+ return std::make_pair(Begin, End);
}
-PreprocessingRecord::iterator PreprocessingRecord::end(bool OnlyLocalEntities) {
- if (!OnlyLocalEntities)
- MaybeLoadPreallocatedEntities();
-
- return PreprocessedEntities.end();
+namespace {
+
+template <SourceLocation (SourceRange::*getRangeLoc)() const>
+struct PPEntityComp {
+ const SourceManager &SM;
+
+ explicit PPEntityComp(const SourceManager &SM) : SM(SM) { }
+
+ bool operator()(PreprocessedEntity *L, PreprocessedEntity *R) const {
+ SourceLocation LHS = getLoc(L);
+ SourceLocation RHS = getLoc(R);
+ return SM.isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ bool operator()(PreprocessedEntity *L, SourceLocation RHS) const {
+ SourceLocation LHS = getLoc(L);
+ return SM.isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ bool operator()(SourceLocation LHS, PreprocessedEntity *R) const {
+ SourceLocation RHS = getLoc(R);
+ return SM.isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ SourceLocation getLoc(PreprocessedEntity *PPE) const {
+ SourceRange Range = PPE->getSourceRange();
+ return (Range.*getRangeLoc)();
+ }
+};
+
}
-PreprocessingRecord::const_iterator
-PreprocessingRecord::begin(bool OnlyLocalEntities) const {
- if (OnlyLocalEntities)
- return PreprocessedEntities.begin() + NumPreallocatedEntities;
-
- MaybeLoadPreallocatedEntities();
- return PreprocessedEntities.begin();
+unsigned PreprocessingRecord::findBeginLocalPreprocessedEntity(
+ SourceLocation Loc) const {
+ if (SourceMgr.isLoadedSourceLocation(Loc))
+ return 0;
+
+ size_t Count = PreprocessedEntities.size();
+ size_t Half;
+ std::vector<PreprocessedEntity *>::const_iterator
+ First = PreprocessedEntities.begin();
+ std::vector<PreprocessedEntity *>::const_iterator I;
+
+ // Do a binary search manually instead of using std::lower_bound because
+ // The end locations of entities may be unordered (when a macro expansion
+ // is inside another macro argument), but for this case it is not important
+ // whether we get the first macro expansion or its containing macro.
+ while (Count > 0) {
+ Half = Count/2;
+ I = First;
+ std::advance(I, Half);
+ if (SourceMgr.isBeforeInTranslationUnit((*I)->getSourceRange().getEnd(),
+ Loc)){
+ First = I;
+ ++First;
+ Count = Count - Half - 1;
+ } else
+ Count = Half;
+ }
+
+ return First - PreprocessedEntities.begin();
}
-PreprocessingRecord::const_iterator
-PreprocessingRecord::end(bool OnlyLocalEntities) const {
- if (!OnlyLocalEntities)
- MaybeLoadPreallocatedEntities();
-
- return PreprocessedEntities.end();
+unsigned PreprocessingRecord::findEndLocalPreprocessedEntity(
+ SourceLocation Loc) const {
+ if (SourceMgr.isLoadedSourceLocation(Loc))
+ return 0;
+
+ std::vector<PreprocessedEntity *>::const_iterator
+ I = std::upper_bound(PreprocessedEntities.begin(),
+ PreprocessedEntities.end(),
+ Loc,
+ PPEntityComp<&SourceRange::getBegin>(SourceMgr));
+ return I - PreprocessedEntities.begin();
}
void PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) {
- PreprocessedEntities.push_back(Entity);
+ assert(Entity);
+ SourceLocation BeginLoc = Entity->getSourceRange().getBegin();
+
+ // Check normal case, this entity begin location is after the previous one.
+ if (PreprocessedEntities.empty() ||
+ !SourceMgr.isBeforeInTranslationUnit(BeginLoc,
+ PreprocessedEntities.back()->getSourceRange().getBegin())) {
+ PreprocessedEntities.push_back(Entity);
+ return;
+ }
+
+ // The entity's location is not after the previous one; this can happen rarely
+ // e.g. with "#include MACRO".
+ // Iterate the entities vector in reverse until we find the right place to
+ // insert the new entity.
+ for (std::vector<PreprocessedEntity *>::iterator
+ RI = PreprocessedEntities.end(), Begin = PreprocessedEntities.begin();
+ RI != Begin; --RI) {
+ std::vector<PreprocessedEntity *>::iterator I = RI;
+ --I;
+ if (!SourceMgr.isBeforeInTranslationUnit(BeginLoc,
+ (*I)->getSourceRange().getBegin())) {
+ PreprocessedEntities.insert(RI, Entity);
+ return;
+ }
+ }
}
void PreprocessingRecord::SetExternalSource(
- ExternalPreprocessingRecordSource &Source,
- unsigned NumPreallocatedEntities) {
+ ExternalPreprocessingRecordSource &Source) {
assert(!ExternalSource &&
"Preprocessing record already has an external source");
ExternalSource = &Source;
- this->NumPreallocatedEntities = NumPreallocatedEntities;
- PreprocessedEntities.insert(PreprocessedEntities.begin(),
- NumPreallocatedEntities, 0);
}
-void PreprocessingRecord::SetPreallocatedEntity(unsigned Index,
- PreprocessedEntity *Entity) {
- assert(Index < NumPreallocatedEntities &&"Out-of-bounds preallocated entity");
- PreprocessedEntities[Index] = Entity;
+unsigned PreprocessingRecord::allocateLoadedEntities(unsigned NumEntities) {
+ unsigned Result = LoadedPreprocessedEntities.size();
+ LoadedPreprocessedEntities.resize(LoadedPreprocessedEntities.size()
+ + NumEntities);
+ return Result;
+}
+
+void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro,
+ PPEntityID PPID) {
+ MacroDefinitions[Macro] = PPID;
+}
+
+/// \brief Retrieve the preprocessed entity at the given ID.
+PreprocessedEntity *PreprocessingRecord::getPreprocessedEntity(PPEntityID PPID){
+ if (PPID < 0) {
+ assert(unsigned(-PPID-1) < LoadedPreprocessedEntities.size() &&
+ "Out-of bounds loaded preprocessed entity");
+ return getLoadedPreprocessedEntity(LoadedPreprocessedEntities.size()+PPID);
+ }
+ assert(unsigned(PPID) < PreprocessedEntities.size() &&
+ "Out-of bounds local preprocessed entity");
+ return PreprocessedEntities[PPID];
}
-void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro,
- MacroDefinition *MD) {
- MacroDefinitions[Macro] = MD;
+/// \brief Retrieve the loaded preprocessed entity at the given index.
+PreprocessedEntity *
+PreprocessingRecord::getLoadedPreprocessedEntity(unsigned Index) {
+ assert(Index < LoadedPreprocessedEntities.size() &&
+ "Out-of bounds loaded preprocessed entity");
+ assert(ExternalSource && "No external source to load from");
+ PreprocessedEntity *&Entity = LoadedPreprocessedEntities[Index];
+ if (!Entity) {
+ Entity = ExternalSource->ReadPreprocessedEntity(Index);
+ if (!Entity) // Failed to load.
+ Entity = new (*this)
+ PreprocessedEntity(PreprocessedEntity::InvalidKind, SourceRange());
+ }
+ return Entity;
}
MacroDefinition *PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) {
- llvm::DenseMap<const MacroInfo *, MacroDefinition *>::iterator Pos
+ llvm::DenseMap<const MacroInfo *, PPEntityID>::iterator Pos
= MacroDefinitions.find(MI);
if (Pos == MacroDefinitions.end())
return 0;
- return Pos->second;
+ PreprocessedEntity *Entity = getPreprocessedEntity(Pos->second);
+ if (Entity->isInvalid())
+ return 0;
+ return cast<MacroDefinition>(Entity);
}
-void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI) {
+void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI,
+ SourceRange Range) {
if (!IncludeNestedMacroExpansions && Id.getLocation().isMacroID())
return;
- if (MacroDefinition *Def = findMacroDefinition(MI))
- PreprocessedEntities.push_back(
- new (*this) MacroExpansion(Id.getIdentifierInfo(),
- Id.getLocation(), Def));
+ if (MI->isBuiltinMacro())
+ addPreprocessedEntity(
+ new (*this) MacroExpansion(Id.getIdentifierInfo(),Range));
+ else if (MacroDefinition *Def = findMacroDefinition(MI))
+ addPreprocessedEntity(
+ new (*this) MacroExpansion(Def, Range));
}
void PreprocessingRecord::MacroDefined(const Token &Id,
const MacroInfo *MI) {
SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc());
MacroDefinition *Def
- = new (*this) MacroDefinition(Id.getIdentifierInfo(),
- MI->getDefinitionLoc(),
- R);
- MacroDefinitions[MI] = Def;
- PreprocessedEntities.push_back(Def);
+ = new (*this) MacroDefinition(Id.getIdentifierInfo(), R);
+ addPreprocessedEntity(Def);
+ MacroDefinitions[MI] = getPPEntityID(PreprocessedEntities.size()-1,
+ /*isLoaded=*/false);
}
void PreprocessingRecord::MacroUndefined(const Token &Id,
const MacroInfo *MI) {
- llvm::DenseMap<const MacroInfo *, MacroDefinition *>::iterator Pos
+ llvm::DenseMap<const MacroInfo *, PPEntityID>::iterator Pos
= MacroDefinitions.find(MI);
if (Pos != MacroDefinitions.end())
MacroDefinitions.erase(Pos);
@@ -152,12 +290,12 @@ void PreprocessingRecord::MacroUndefined(const Token &Id,
void PreprocessingRecord::InclusionDirective(
SourceLocation HashLoc,
const clang::Token &IncludeTok,
- llvm::StringRef FileName,
+ StringRef FileName,
bool IsAngled,
const FileEntry *File,
clang::SourceLocation EndLoc,
- llvm::StringRef SearchPath,
- llvm::StringRef RelativePath) {
+ StringRef SearchPath,
+ StringRef RelativePath) {
InclusionDirective::InclusionKind Kind = InclusionDirective::Include;
switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) {
@@ -185,5 +323,12 @@ void PreprocessingRecord::InclusionDirective(
clang::InclusionDirective *ID
= new (*this) clang::InclusionDirective(*this, Kind, FileName, !IsAngled,
File, SourceRange(HashLoc, EndLoc));
- PreprocessedEntities.push_back(ID);
+ addPreprocessedEntity(ID);
+}
+
+size_t PreprocessingRecord::getTotalMemory() const {
+ return BumpAlloc.getTotalMemory()
+ + llvm::capacity_in_bytes(MacroDefinitions)
+ + llvm::capacity_in_bytes(PreprocessedEntities)
+ + llvm::capacity_in_bytes(LoadedPreprocessedEntities);
}
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index e7aa286a16bf..31662ad0c116 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -35,6 +35,7 @@
#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"
@@ -42,27 +43,83 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Capacity.h"
using namespace clang;
//===----------------------------------------------------------------------===//
ExternalPreprocessorSource::~ExternalPreprocessorSource() { }
-Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
- const TargetInfo &target, SourceManager &SM,
- HeaderSearch &Headers,
+Preprocessor::Preprocessor(DiagnosticsEngine &diags, LangOptions &opts,
+ const TargetInfo *target, SourceManager &SM,
+ HeaderSearch &Headers, ModuleLoader &TheModuleLoader,
IdentifierInfoLookup* IILookup,
- bool OwnsHeaders)
+ bool OwnsHeaders,
+ bool DelayInitialization)
: Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()),
- SourceMgr(SM),
- HeaderInfo(Headers), ExternalSource(0),
- Identifiers(opts, IILookup), BuiltinInfo(Target), CodeComplete(0),
- CodeCompletionFile(0), SkipMainFilePreamble(0, true), CurPPLexer(0),
- CurDirLookup(0), Callbacks(0), MacroArgCache(0), Record(0), MIChainHead(0),
- MICache(0) {
- ScratchBuf = new ScratchBuffer(SourceMgr);
- CounterValue = 0; // __COUNTER__ starts at 0.
+ SourceMgr(SM), HeaderInfo(Headers), TheModuleLoader(TheModuleLoader),
+ ExternalSource(0),
+ Identifiers(opts, IILookup), 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;
+
+ if (!DelayInitialization) {
+ assert(Target && "Must provide target information for PP initialization");
+ Initialize(*Target);
+ }
+}
+
+Preprocessor::~Preprocessor() {
+ assert(BacktrackPositions.empty() && "EnableBacktrack/Backtrack imbalance!");
+ assert(((MacroExpandingLexersStack.empty() && MacroExpandedTokens.empty()) ||
+ isCodeCompletionReached()) &&
+ "Preprocessor::HandleEndOfTokenLexer should have cleared those");
+
+ while (!IncludeMacroStack.empty()) {
+ delete IncludeMacroStack.back().TheLexer;
+ delete IncludeMacroStack.back().TheTokenLexer;
+ IncludeMacroStack.pop_back();
+ }
+ // Free any macro definitions.
+ for (MacroInfoChain *I = MIChainHead ; I ; I = I->Next)
+ I->MI.Destroy();
+
+ // Free any cached macro expanders.
+ for (unsigned i = 0, e = NumCachedTokenLexers; i != e; ++i)
+ delete TokenLexerCache[i];
+
+ // Free any cached MacroArgs.
+ for (MacroArgs *ArgList = MacroArgCache; ArgList; )
+ ArgList = ArgList->deallocate();
+
+ // Release pragma information.
+ delete PragmaHandlers;
+
+ // Delete the scratch buffer info.
+ delete ScratchBuf;
+
+ // Delete the header search info, if we own it.
+ if (OwnsHeaderSearch)
+ delete &HeaderInfo;
+
+ delete Callbacks;
+}
+
+void Preprocessor::Initialize(const TargetInfo &Target) {
+ assert((!this->Target || this->Target == &Target) &&
+ "Invalid override of target information");
+ this->Target = &Target;
+
+ // Initialize information about built-ins.
+ BuiltinInfo.InitializeTarget(Target);
+
+ ScratchBuf = new ScratchBuffer(SourceMgr);
+ CounterValue = 0; // __COUNTER__ starts at 0.
+
// Clear stats.
NumDirectives = NumDefined = NumUndefined = NumPragma = 0;
NumIf = NumElse = NumEndif = 0;
@@ -71,33 +128,35 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
NumFastMacroExpanded = NumTokenPaste = NumFastTokenPaste = 0;
MaxIncludeStackDepth = 0;
NumSkipped = 0;
-
+
// Default to discarding comments.
KeepComments = false;
KeepMacroComments = false;
-
+ SuppressIncludeNotFoundError = false;
+ AutoModuleImport = false;
+
// Macro expansion is enabled.
DisableMacroExpansion = false;
InMacroArgs = false;
NumCachedTokenLexers = 0;
-
+
CachedLexPos = 0;
-
+
// We haven't read anything from the external source.
ReadMacrosFromExternalSource = false;
-
+
// "Poison" __VA_ARGS__, which can only appear in the expansion of a macro.
// This gets unpoisoned where it is allowed.
(Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned();
SetPoisonReason(Ident__VA_ARGS__,diag::ext_pp_bad_vaargs_use);
-
+
// Initialize the pragma handlers.
- PragmaHandlers = new PragmaNamespace(llvm::StringRef());
+ PragmaHandlers = new PragmaNamespace(StringRef());
RegisterBuiltinPragmas();
-
+
// Initialize builtin macros like __LINE__ and friends.
RegisterBuiltinMacros();
-
+
if(Features.Borland) {
Ident__exception_info = getIdentifierInfo("_exception_info");
Ident___exception_info = getIdentifierInfo("__exception_info");
@@ -112,44 +171,7 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
Ident__exception_info = Ident__exception_code = Ident__abnormal_termination = 0;
Ident___exception_info = Ident___exception_code = Ident___abnormal_termination = 0;
Ident_GetExceptionInfo = Ident_GetExceptionCode = Ident_AbnormalTermination = 0;
- }
-
-}
-
-Preprocessor::~Preprocessor() {
- assert(BacktrackPositions.empty() && "EnableBacktrack/Backtrack imbalance!");
- assert(MacroExpandingLexersStack.empty() && MacroExpandedTokens.empty() &&
- "Preprocessor::HandleEndOfTokenLexer should have cleared those");
-
- while (!IncludeMacroStack.empty()) {
- delete IncludeMacroStack.back().TheLexer;
- delete IncludeMacroStack.back().TheTokenLexer;
- IncludeMacroStack.pop_back();
- }
-
- // Free any macro definitions.
- for (MacroInfoChain *I = MIChainHead ; I ; I = I->Next)
- I->MI.Destroy();
-
- // Free any cached macro expanders.
- for (unsigned i = 0, e = NumCachedTokenLexers; i != e; ++i)
- delete TokenLexerCache[i];
-
- // Free any cached MacroArgs.
- for (MacroArgs *ArgList = MacroArgCache; ArgList; )
- ArgList = ArgList->deallocate();
-
- // Release pragma information.
- delete PragmaHandlers;
-
- // Delete the scratch buffer info.
- delete ScratchBuf;
-
- // Delete the header search info, if we own it.
- if (OwnsHeaderSearch)
- delete &HeaderInfo;
-
- delete Callbacks;
+ }
}
void Preprocessor::setPTHManager(PTHManager* pm) {
@@ -172,7 +194,7 @@ void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const {
llvm::errs() << " [ExpandDisabled]";
if (Tok.needsCleaning()) {
const char *Start = SourceMgr.getCharacterData(Tok.getLocation());
- llvm::errs() << " [UnClean='" << llvm::StringRef(Start, Tok.getLength())
+ llvm::errs() << " [UnClean='" << StringRef(Start, Tok.getLength())
<< "']";
}
@@ -228,7 +250,13 @@ Preprocessor::macro_begin(bool IncludeExternalMacros) const {
}
size_t Preprocessor::getTotalMemory() const {
- return BP.getTotalMemory() + MacroExpandedTokens.capacity()*sizeof(Token);
+ return BP.getTotalMemory()
+ + llvm::capacity_in_bytes(MacroExpandedTokens)
+ + Predefines.capacity() /* Predefines buffer. */
+ + llvm::capacity_in_bytes(Macros)
+ + llvm::capacity_in_bytes(PragmaPushMacroInfo)
+ + llvm::capacity_in_bytes(PoisonReasons)
+ + llvm::capacity_in_bytes(CommentHandlers);
}
Preprocessor::macro_iterator
@@ -243,15 +271,13 @@ Preprocessor::macro_end(bool IncludeExternalMacros) const {
}
bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File,
- unsigned TruncateAtLine,
- unsigned TruncateAtColumn) {
- using llvm::MemoryBuffer;
-
- CodeCompletionFile = File;
+ unsigned CompleteLine,
+ unsigned CompleteColumn) {
+ assert(File);
+ assert(CompleteLine && CompleteColumn && "Starts from 1:1");
+ assert(!CodeCompletionFile && "Already set");
- // Okay to clear out the code-completion point by passing NULL.
- if (!CodeCompletionFile)
- return false;
+ using llvm::MemoryBuffer;
// Load the actual file's contents.
bool Invalid = false;
@@ -261,7 +287,7 @@ bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File,
// Find the byte position of the truncation point.
const char *Position = Buffer->getBufferStart();
- for (unsigned Line = 1; Line < TruncateAtLine; ++Line) {
+ for (unsigned Line = 1; Line < CompleteLine; ++Line) {
for (; *Position; ++Position) {
if (*Position != '\r' && *Position != '\n')
continue;
@@ -275,38 +301,37 @@ bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File,
}
}
- Position += TruncateAtColumn - 1;
+ Position += CompleteColumn - 1;
- // Truncate the buffer.
+ // Insert '\0' at the code-completion point.
if (Position < Buffer->getBufferEnd()) {
- llvm::StringRef Data(Buffer->getBufferStart(),
- Position-Buffer->getBufferStart());
- MemoryBuffer *TruncatedBuffer
- = MemoryBuffer::getMemBufferCopy(Data, Buffer->getBufferIdentifier());
- SourceMgr.overrideFileContents(File, TruncatedBuffer);
+ CodeCompletionFile = File;
+ CodeCompletionOffset = Position - Buffer->getBufferStart();
+
+ MemoryBuffer *NewBuffer =
+ MemoryBuffer::getNewUninitMemBuffer(Buffer->getBufferSize() + 1,
+ Buffer->getBufferIdentifier());
+ char *NewBuf = const_cast<char*>(NewBuffer->getBufferStart());
+ char *NewPos = std::copy(Buffer->getBufferStart(), Position, NewBuf);
+ *NewPos = '\0';
+ std::copy(Position, Buffer->getBufferEnd(), NewPos+1);
+ SourceMgr.overrideFileContents(File, NewBuffer);
}
return false;
}
-bool Preprocessor::isCodeCompletionFile(SourceLocation FileLoc) const {
- return CodeCompletionFile && FileLoc.isFileID() &&
- SourceMgr.getFileEntryForID(SourceMgr.getFileID(FileLoc))
- == CodeCompletionFile;
-}
-
void Preprocessor::CodeCompleteNaturalLanguage() {
- SetCodeCompletionPoint(0, 0, 0);
- getDiagnostics().setSuppressAllDiagnostics(true);
if (CodeComplete)
CodeComplete->CodeCompleteNaturalLanguage();
+ setCodeCompletionReached();
}
/// getSpelling - This method is used to get the spelling of a token into a
/// SmallVector. Note that the returned StringRef may not point to the
/// supplied buffer if a copy can be avoided.
-llvm::StringRef Preprocessor::getSpelling(const Token &Tok,
- llvm::SmallVectorImpl<char> &Buffer,
+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)) {
@@ -321,22 +346,23 @@ llvm::StringRef Preprocessor::getSpelling(const Token &Tok,
const char *Ptr = Buffer.data();
unsigned Len = getSpelling(Tok, Ptr, Invalid);
- return llvm::StringRef(Ptr, Len);
+ return StringRef(Ptr, Len);
}
/// CreateString - Plop the specified string into a scratch buffer and return a
/// location for it. If specified, the source location provides a source
/// location for the token.
void Preprocessor::CreateString(const char *Buf, unsigned Len, Token &Tok,
- SourceLocation ExpansionLoc) {
+ SourceLocation ExpansionLocStart,
+ SourceLocation ExpansionLocEnd) {
Tok.setLength(Len);
const char *DestPtr;
SourceLocation Loc = ScratchBuf->getToken(Buf, Len, DestPtr);
- if (ExpansionLoc.isValid())
- Loc = SourceMgr.createInstantiationLoc(Loc, ExpansionLoc,
- ExpansionLoc, Len);
+ if (ExpansionLocStart.isValid())
+ Loc = SourceMgr.createExpansionLoc(Loc, ExpansionLocStart,
+ ExpansionLocEnd, Len);
Tok.setLocation(Loc);
// If this is a raw identifier or a literal token, set the pointer data.
@@ -407,12 +433,12 @@ IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier) const {
IdentifierInfo *II;
if (!Identifier.needsCleaning()) {
// No cleaning needed, just use the characters from the lexed buffer.
- II = getIdentifierInfo(llvm::StringRef(Identifier.getRawIdentifierData(),
+ II = getIdentifierInfo(StringRef(Identifier.getRawIdentifierData(),
Identifier.getLength()));
} else {
// Cleaning needed, alloca a buffer, clean into it, then use the buffer.
llvm::SmallString<64> IdentifierBuffer;
- llvm::StringRef CleanedStr = getSpelling(Identifier, IdentifierBuffer);
+ StringRef CleanedStr = getSpelling(Identifier, IdentifierBuffer);
II = getIdentifierInfo(CleanedStr);
}
@@ -487,6 +513,17 @@ void Preprocessor::HandleIdentifier(Token &Identifier) {
}
}
+ // If this identifier is a keyword in C++11, produce a warning. Don't warn if
+ // we're not considering macro expansion, since this identifier might be the
+ // name of a macro.
+ // FIXME: This warning is disabled in cases where it shouldn't be, like
+ // "#define constexpr constexpr", "int constexpr;"
+ if (II.isCXX11CompatKeyword() & !DisableMacroExpansion) {
+ Diag(Identifier, diag::warn_cxx11_keyword) << II.getName();
+ // Don't diagnose this keyword again in this translation unit.
+ II.setIsCXX11CompatKeyword(false);
+ }
+
// C++ 2.11p2: If this is an alternative representation of a C++ operator,
// then we act as if it is the actual operator and not the textual
// representation of it.
@@ -499,6 +536,44 @@ void Preprocessor::HandleIdentifier(Token &Identifier) {
// like "#define TY typeof", "TY(1) x".
if (II.isExtensionToken() && !DisableMacroExpansion)
Diag(Identifier, diag::ext_token_used);
+
+ // If this is the '__import_module__' keyword, note that the next token
+ // indicates a module name.
+ if (II.getTokenID() == tok::kw___import_module__ &&
+ !InMacroArgs && !DisableMacroExpansion) {
+ ModuleImportLoc = Identifier.getLocation();
+ CurLexerKind = CLK_LexAfterModuleImport;
+ }
+}
+
+/// \brief Lex a token following the __import_module__ keyword.
+void Preprocessor::LexAfterModuleImport(Token &Result) {
+ // Figure out what kind of lexer we actually have.
+ if (CurLexer)
+ CurLexerKind = CLK_Lexer;
+ else if (CurPTHLexer)
+ CurLexerKind = CLK_PTHLexer;
+ else if (CurTokenLexer)
+ CurLexerKind = CLK_TokenLexer;
+ else
+ CurLexerKind = CLK_CachingLexer;
+
+ // Lex the next token.
+ Lex(Result);
+
+ // The token sequence
+ //
+ // __import_module__ identifier
+ //
+ // indicates a module import directive. We already saw the __import_module__
+ // keyword, so now we're looking for the identifier.
+ if (Result.getKind() != tok::identifier)
+ return;
+
+ // Load the module.
+ (void)TheModuleLoader.loadModule(ModuleImportLoc,
+ *Result.getIdentifierInfo(),
+ Result.getLocation());
}
void Preprocessor::AddCommentHandler(CommentHandler *Handler) {
@@ -529,6 +604,8 @@ bool Preprocessor::HandleComment(Token &result, SourceRange Comment) {
return true;
}
+ModuleLoader::~ModuleLoader() { }
+
CommentHandler::~CommentHandler() { }
CodeCompletionHandler::~CodeCompletionHandler() { }
@@ -538,6 +615,7 @@ void Preprocessor::createPreprocessingRecord(
if (Record)
return;
- Record = new PreprocessingRecord(IncludeNestedMacroExpansions);
+ Record = new PreprocessingRecord(getSourceManager(),
+ IncludeNestedMacroExpansions);
addPPCallbacks(Record);
}
diff --git a/lib/Lex/PreprocessorLexer.cpp b/lib/Lex/PreprocessorLexer.cpp
index 808a81bd5e87..0da9ef5531e7 100644
--- a/lib/Lex/PreprocessorLexer.cpp
+++ b/lib/Lex/PreprocessorLexer.cpp
@@ -17,6 +17,14 @@
#include "clang/Basic/SourceManager.h"
using namespace clang;
+PreprocessorLexer::PreprocessorLexer(Preprocessor *pp, FileID fid)
+ : PP(pp), FID(fid), InitialNumSLocEntries(0),
+ ParsingPreprocessorDirective(false),
+ ParsingFilename(false), LexingRawMode(false) {
+ if (pp)
+ InitialNumSLocEntries = pp->getSourceManager().local_sloc_entry_size();
+}
+
/// LexIncludeFilename - After the preprocessor has parsed a #include, lex and
/// (potentially) macro expand the filename.
void PreprocessorLexer::LexIncludeFilename(Token &FilenameTok) {
diff --git a/lib/Lex/ScratchBuffer.cpp b/lib/Lex/ScratchBuffer.cpp
index 0e98c1751985..3d363fa4b472 100644
--- a/lib/Lex/ScratchBuffer.cpp
+++ b/lib/Lex/ScratchBuffer.cpp
@@ -53,7 +53,7 @@ SourceLocation ScratchBuffer::getToken(const char *Buf, unsigned Len,
// diagnostic points to one.
CurBuffer[BytesUsed-1] = '\0';
- return BufferStartLoc.getFileLocWithOffset(BytesUsed-Len-1);
+ return BufferStartLoc.getLocWithOffset(BytesUsed-Len-1);
}
void ScratchBuffer::AllocScratchBuffer(unsigned RequestLen) {
diff --git a/lib/Lex/TokenConcatenation.cpp b/lib/Lex/TokenConcatenation.cpp
index 3e9e8550313c..dc6d686d6cc1 100644
--- a/lib/Lex/TokenConcatenation.cpp
+++ b/lib/Lex/TokenConcatenation.cpp
@@ -17,42 +17,53 @@
using namespace clang;
-/// StartsWithL - Return true if the spelling of this token starts with 'L'.
-bool TokenConcatenation::StartsWithL(const Token &Tok) const {
- if (!Tok.needsCleaning()) {
- SourceManager &SM = PP.getSourceManager();
- return *SM.getCharacterData(SM.getSpellingLoc(Tok.getLocation())) == 'L';
- }
+/// IsStringPrefix - Return true if Str is a string prefix.
+/// 'L', 'u', 'U', or 'u8'. Including raw versions.
+static bool IsStringPrefix(StringRef Str, bool CPlusPlus0x) {
- if (Tok.getLength() < 256) {
- char Buffer[256];
- const char *TokPtr = Buffer;
- PP.getSpelling(Tok, TokPtr);
- return TokPtr[0] == 'L';
+ if (Str[0] == 'L' ||
+ (CPlusPlus0x && (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)
+ return true; // "LR", "uR", "UR"
+
+ // Check for "u8" and "u8R"
+ if (Str[0] == 'u' && Str[1] == '8') {
+ if (Str.size() == 2) return true; // "u8"
+ if (Str.size() == 3 && Str[2] == 'R') return true; // "u8R"
+ }
}
- return PP.getSpelling(Tok)[0] == 'L';
+ return false;
}
-/// IsIdentifierL - Return true if the spelling of this token is literally
-/// 'L'.
-bool TokenConcatenation::IsIdentifierL(const Token &Tok) const {
+/// IsIdentifierStringPrefix - Return true if the spelling of the token
+/// is literally 'L', 'u', 'U', or 'u8'. Including raw versions.
+bool TokenConcatenation::IsIdentifierStringPrefix(const Token &Tok) const {
+ const LangOptions &LangOpts = PP.getLangOptions();
+
if (!Tok.needsCleaning()) {
- if (Tok.getLength() != 1)
+ if (Tok.getLength() < 1 || Tok.getLength() > 3)
return false;
SourceManager &SM = PP.getSourceManager();
- return *SM.getCharacterData(SM.getSpellingLoc(Tok.getLocation())) == 'L';
+ const char *Ptr = SM.getCharacterData(SM.getSpellingLoc(Tok.getLocation()));
+ return IsStringPrefix(StringRef(Ptr, Tok.getLength()),
+ LangOpts.CPlusPlus0x);
}
if (Tok.getLength() < 256) {
char Buffer[256];
const char *TokPtr = Buffer;
- if (PP.getSpelling(Tok, TokPtr) != 1)
- return false;
- return TokPtr[0] == 'L';
+ unsigned length = PP.getSpelling(Tok, TokPtr);
+ return IsStringPrefix(StringRef(TokPtr, length), LangOpts.CPlusPlus0x);
}
- return PP.getSpelling(Tok) == "L";
+ return IsStringPrefix(StringRef(PP.getSpelling(Tok)), LangOpts.CPlusPlus0x);
}
TokenConcatenation::TokenConcatenation(Preprocessor &pp) : PP(pp) {
@@ -132,7 +143,7 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
// 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().getFileLocWithOffset(PrevTok.getLength()) ==
+ PrevTok.getLocation().getLocWithOffset(PrevTok.getLength()) ==
Tok.getLocation())
return false;
@@ -179,24 +190,19 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
if (Tok.is(tok::numeric_constant))
return GetFirstChar(PP, Tok) != '.';
- if (Tok.getIdentifierInfo() || Tok.is(tok::wide_string_literal) /* ||
- Tok.is(tok::wide_char_literal)*/)
+ if (Tok.getIdentifierInfo() || Tok.is(tok::wide_string_literal) ||
+ Tok.is(tok::utf8_string_literal) || Tok.is(tok::utf16_string_literal) ||
+ Tok.is(tok::utf32_string_literal) || Tok.is(tok::wide_char_constant) ||
+ Tok.is(tok::utf16_char_constant) || Tok.is(tok::utf32_char_constant))
return true;
// If this isn't identifier + string, we're done.
if (Tok.isNot(tok::char_constant) && Tok.isNot(tok::string_literal))
return false;
- // FIXME: need a wide_char_constant!
-
- // If the string was a wide string L"foo" or wide char L'f', it would
- // concat with the previous identifier into fooL"bar". Avoid this.
- if (StartsWithL(Tok))
- return true;
-
// Otherwise, this is a narrow character or string. If the *identifier*
- // is a literal 'L', avoid pasting L "foo" -> L"foo".
- return IsIdentifierL(PrevTok);
+ // is a literal 'L', 'u8', 'u' or 'U', avoid pasting L "foo" -> L"foo".
+ return IsIdentifierStringPrefix(PrevTok);
case tok::numeric_constant:
return isalnum(FirstChar) || Tok.is(tok::numeric_constant) ||
FirstChar == '+' || FirstChar == '-' || FirstChar == '.';
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index 8ff82f160033..a58054490fcd 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -43,7 +43,7 @@ void TokenLexer::Init(Token &Tok, SourceLocation ELEnd, MacroArgs *Actuals) {
MacroExpansionStart = SourceLocation();
SourceManager &SM = PP.getSourceManager();
- MacroStartSLocOffset = SM.getNextOffset();
+ MacroStartSLocOffset = SM.getNextLocalOffset();
if (NumTokens > 0) {
assert(Tokens[0].getLocation().isValid());
@@ -55,12 +55,12 @@ void TokenLexer::Init(Token &Tok, SourceLocation ELEnd, MacroArgs *Actuals) {
// definition. Tokens that get lexed directly from the definition will
// have their locations pointing inside this chunk. This is to avoid
// creating separate source location entries for each token.
- SourceLocation macroStart = SM.getInstantiationLoc(Tokens[0].getLocation());
- MacroDefStartInfo = SM.getDecomposedLoc(macroStart);
- MacroExpansionStart = SM.createInstantiationLoc(macroStart,
- ExpandLocStart,
- ExpandLocEnd,
- Macro->getDefinitionLength(SM));
+ MacroDefStart = SM.getExpansionLoc(Tokens[0].getLocation());
+ MacroDefLength = Macro->getDefinitionLength(SM);
+ MacroExpansionStart = SM.createExpansionLoc(MacroDefStart,
+ ExpandLocStart,
+ ExpandLocEnd,
+ MacroDefLength);
}
// If this is a function-like macro, expand the arguments and change
@@ -121,9 +121,8 @@ void TokenLexer::destroy() {
/// Expand the arguments of a function-like macro so that we can quickly
/// return preexpanded tokens from Tokens.
void TokenLexer::ExpandFunctionArguments() {
- SourceManager &SM = PP.getSourceManager();
- llvm::SmallVector<Token, 128> ResultToks;
+ SmallVector<Token, 128> ResultToks;
// Loop through 'Tokens', expanding them into ResultToks. Keep
// track of whether we change anything. If not, no need to keep them. If so,
@@ -144,19 +143,22 @@ void TokenLexer::ExpandFunctionArguments() {
int ArgNo = Macro->getArgumentNum(Tokens[i+1].getIdentifierInfo());
assert(ArgNo != -1 && "Token following # is not an argument?");
- SourceLocation hashInstLoc;
- if(ExpandLocStart.isValid()) {
- hashInstLoc = getMacroExpansionLocation(CurTok.getLocation());
- assert(hashInstLoc.isValid() && "Expected '#' to come from definition");
- }
+ SourceLocation ExpansionLocStart =
+ getExpansionLocForMacroDefLoc(CurTok.getLocation());
+ SourceLocation ExpansionLocEnd =
+ getExpansionLocForMacroDefLoc(Tokens[i+1].getLocation());
Token Res;
if (CurTok.is(tok::hash)) // Stringify
- Res = ActualArgs->getStringifiedArgument(ArgNo, PP, hashInstLoc);
+ Res = ActualArgs->getStringifiedArgument(ArgNo, PP,
+ ExpansionLocStart,
+ ExpansionLocEnd);
else {
// 'charify': don't bother caching these.
Res = MacroArgs::StringifyArgument(ActualArgs->getUnexpArgument(ArgNo),
- PP, true, hashInstLoc);
+ PP, true,
+ ExpansionLocStart,
+ ExpansionLocEnd);
}
// The stringified/charified string leading space flag gets set to match
@@ -225,16 +227,9 @@ void TokenLexer::ExpandFunctionArguments() {
}
if(ExpandLocStart.isValid()) {
- SourceLocation curInst =
- getMacroExpansionLocation(CurTok.getLocation());
- assert(curInst.isValid() &&
- "Expected arg identifier to come from definition");
- for (unsigned i = FirstResult, e = ResultToks.size(); i != e; ++i) {
- Token &Tok = ResultToks[i];
- Tok.setLocation(SM.createMacroArgInstantiationLoc(Tok.getLocation(),
- curInst,
- Tok.getLength()));
- }
+ updateLocForMacroArgTokens(CurTok.getLocation(),
+ ResultToks.begin()+FirstResult,
+ ResultToks.end());
}
// If any tokens were substituted from the argument, the whitespace
@@ -282,17 +277,8 @@ void TokenLexer::ExpandFunctionArguments() {
}
if (ExpandLocStart.isValid()) {
- SourceLocation curInst =
- getMacroExpansionLocation(CurTok.getLocation());
- assert(curInst.isValid() &&
- "Expected arg identifier to come from definition");
- for (unsigned i = ResultToks.size() - NumToks, e = ResultToks.size();
- i != e; ++i) {
- Token &Tok = ResultToks[i];
- Tok.setLocation(SM.createMacroArgInstantiationLoc(Tok.getLocation(),
- curInst,
- Tok.getLength()));
- }
+ updateLocForMacroArgTokens(CurTok.getLocation(),
+ ResultToks.end()-NumToks, ResultToks.end());
}
// If this token (the macro argument) was supposed to get leading
@@ -417,18 +403,15 @@ void TokenLexer::Lex(Token &Tok) {
// that captures all of this.
if (ExpandLocStart.isValid() && // Don't do this for token streams.
// Check that the token's location was not already set properly.
- SM.isBeforeInSourceLocationOffset(Tok.getLocation(),
- MacroStartSLocOffset)) {
+ SM.isBeforeInSLocAddrSpace(Tok.getLocation(), MacroStartSLocOffset)) {
SourceLocation instLoc;
if (Tok.is(tok::comment)) {
- instLoc = SM.createInstantiationLoc(Tok.getLocation(),
- ExpandLocStart,
- ExpandLocEnd,
- Tok.getLength());
+ instLoc = SM.createExpansionLoc(Tok.getLocation(),
+ ExpandLocStart,
+ ExpandLocEnd,
+ Tok.getLength());
} else {
- instLoc = getMacroExpansionLocation(Tok.getLocation());
- assert(instLoc.isValid() &&
- "Location for token not coming from definition was not set!");
+ instLoc = getExpansionLocForMacroDefLoc(Tok.getLocation());
}
Tok.setLocation(instLoc);
@@ -469,6 +452,7 @@ void TokenLexer::Lex(Token &Tok) {
bool TokenLexer::PasteTokens(Token &Tok) {
llvm::SmallString<128> Buffer;
const char *ResultTokStrPtr = 0;
+ SourceLocation StartLoc = Tok.getLocation();
SourceLocation PasteOpLoc;
do {
// Consume the ## operator.
@@ -562,7 +546,7 @@ bool TokenLexer::PasteTokens(Token &Tok) {
if (isInvalid) {
// Test for the Microsoft extension of /##/ turning into // here on the
// error path.
- if (PP.getLangOptions().Microsoft && Tok.is(tok::slash) &&
+ if (PP.getLangOptions().MicrosoftExt && Tok.is(tok::slash) &&
RHS.is(tok::slash)) {
HandleMicrosoftCommentPaste(Tok);
return true;
@@ -574,14 +558,13 @@ bool TokenLexer::PasteTokens(Token &Tok) {
// information so that the user knows where it came from.
SourceManager &SM = PP.getSourceManager();
SourceLocation Loc =
- SM.createInstantiationLoc(PasteOpLoc, ExpandLocStart,
- ExpandLocEnd, 2);
+ SM.createExpansionLoc(PasteOpLoc, ExpandLocStart, ExpandLocEnd, 2);
// If we're in microsoft extensions mode, downgrade this from a hard
// error to a warning that defaults to an error. This allows
// disabling it.
PP.Diag(Loc,
- PP.getLangOptions().Microsoft ? diag::err_pp_bad_paste_ms
- : diag::err_pp_bad_paste)
+ PP.getLangOptions().MicrosoftExt ? diag::err_pp_bad_paste_ms
+ : diag::err_pp_bad_paste)
<< Buffer.str();
}
@@ -604,23 +587,20 @@ bool TokenLexer::PasteTokens(Token &Tok) {
Tok = Result;
} while (!isAtEnd() && Tokens[CurToken].is(tok::hashhash));
+ SourceLocation EndLoc = Tokens[CurToken - 1].getLocation();
+
// The token's current location indicate where the token was lexed from. We
// need this information to compute the spelling of the token, but any
// diagnostics for the expanded token should appear as if the token was
- // expanded from the (##) operator. Pull this information together into
+ // expanded from the full ## expression. Pull this information together into
// a new SourceLocation that captures all of this.
- if (ExpandLocStart.isValid()) {
- SourceManager &SM = PP.getSourceManager();
- SourceLocation pasteLocInst =
- getMacroExpansionLocation(PasteOpLoc);
- assert(pasteLocInst.isValid() &&
- "Expected '##' to come from definition");
-
- Tok.setLocation(SM.createInstantiationLoc(Tok.getLocation(),
- pasteLocInst,
- pasteLocInst,
- Tok.getLength()));
- }
+ SourceManager &SM = PP.getSourceManager();
+ if (StartLoc.isFileID())
+ StartLoc = getExpansionLocForMacroDefLoc(StartLoc);
+ if (EndLoc.isFileID())
+ EndLoc = getExpansionLocForMacroDefLoc(EndLoc);
+ Tok.setLocation(SM.createExpansionLoc(Tok.getLocation(), StartLoc, EndLoc,
+ Tok.getLength()));
// Now that we got the result token, it will be subject to expansion. Since
// token pasting re-lexes the result token in raw mode, identifier information
@@ -666,22 +646,111 @@ void TokenLexer::HandleMicrosoftCommentPaste(Token &Tok) {
PP.HandleMicrosoftCommentPaste(Tok);
}
-/// \brief If \arg loc is a FileID and points inside the current macro
+/// \brief If \arg loc is a file ID and points inside the current macro
/// definition, returns the appropriate source location pointing at the
-/// macro expansion source location entry.
-SourceLocation TokenLexer::getMacroExpansionLocation(SourceLocation loc) const {
+/// macro expansion source location entry, otherwise it returns an invalid
+/// SourceLocation.
+SourceLocation
+TokenLexer::getExpansionLocForMacroDefLoc(SourceLocation loc) const {
assert(ExpandLocStart.isValid() && MacroExpansionStart.isValid() &&
"Not appropriate for token streams");
- assert(loc.isValid());
+ assert(loc.isValid() && loc.isFileID());
SourceManager &SM = PP.getSourceManager();
- unsigned relativeOffset;
- if (loc.isFileID() &&
- SM.isInFileID(loc,
- MacroDefStartInfo.first, MacroDefStartInfo.second,
- Macro->getDefinitionLength(SM), &relativeOffset)) {
- return MacroExpansionStart.getFileLocWithOffset(relativeOffset);
+ assert(SM.isInSLocAddrSpace(loc, MacroDefStart, MacroDefLength) &&
+ "Expected loc to come from the macro definition");
+
+ unsigned relativeOffset = 0;
+ SM.isInSLocAddrSpace(loc, MacroDefStart, MacroDefLength, &relativeOffset);
+ return MacroExpansionStart.getLocWithOffset(relativeOffset);
+}
+
+/// \brief Finds the tokens that are consecutive (from the same FileID)
+/// creates a single SLocEntry, and assigns SourceLocations to each token that
+/// point to that SLocEntry. e.g for
+/// assert(foo == bar);
+/// There will be a single SLocEntry for the "foo == bar" chunk and locations
+/// for the 'foo', '==', 'bar' tokens will point inside that chunk.
+///
+/// \arg begin_tokens will be updated to a position past all the found
+/// consecutive tokens.
+static void updateConsecutiveMacroArgTokens(SourceManager &SM,
+ SourceLocation InstLoc,
+ Token *&begin_tokens,
+ Token * end_tokens) {
+ assert(begin_tokens < end_tokens);
+
+ SourceLocation FirstLoc = begin_tokens->getLocation();
+ SourceLocation CurLoc = FirstLoc;
+
+ // Compare the source location offset of tokens and group together tokens that
+ // are close, even if their locations point to different FileIDs. e.g.
+ //
+ // |bar | foo | cake | (3 tokens from 3 consecutive FileIDs)
+ // ^ ^
+ // |bar foo cake| (one SLocEntry chunk for all tokens)
+ //
+ // we can perform this "merge" since the token's spelling location depends
+ // on the relative offset.
+
+ Token *NextTok = begin_tokens + 1;
+ for (; NextTok < end_tokens; ++NextTok) {
+ int RelOffs;
+ if (!SM.isInSameSLocAddrSpace(CurLoc, NextTok->getLocation(), &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();
}
- return SourceLocation();
+ // For the consecutive tokens, find the length of the SLocEntry to contain
+ // all of them.
+ Token &LastConsecutiveTok = *(NextTok-1);
+ int LastRelOffs = 0;
+ SM.isInSameSLocAddrSpace(FirstLoc, LastConsecutiveTok.getLocation(),
+ &LastRelOffs);
+ unsigned FullLength = LastRelOffs + LastConsecutiveTok.getLength();
+
+ // Create a macro expansion SLocEntry that will "contain" all of the tokens.
+ SourceLocation Expansion =
+ SM.createMacroArgExpansionLoc(FirstLoc, InstLoc,FullLength);
+
+ // Change the location of the tokens from the spelling location to the new
+ // expanded location.
+ for (; begin_tokens < NextTok; ++begin_tokens) {
+ Token &Tok = *begin_tokens;
+ int RelOffs = 0;
+ SM.isInSameSLocAddrSpace(FirstLoc, Tok.getLocation(), &RelOffs);
+ Tok.setLocation(Expansion.getLocWithOffset(RelOffs));
+ }
+}
+
+/// \brief Creates SLocEntries and updates the locations of macro argument
+/// tokens to their new expanded locations.
+///
+/// \param ArgIdDefLoc the location of the macro argument id inside the macro
+/// definition.
+/// \param Tokens the macro argument tokens to update.
+void TokenLexer::updateLocForMacroArgTokens(SourceLocation ArgIdSpellLoc,
+ Token *begin_tokens,
+ Token *end_tokens) {
+ SourceManager &SM = PP.getSourceManager();
+
+ SourceLocation InstLoc =
+ getExpansionLocForMacroDefLoc(ArgIdSpellLoc);
+
+ while (begin_tokens < end_tokens) {
+ // If there's only one token just create a SLocEntry for it.
+ if (end_tokens - begin_tokens == 1) {
+ Token &Tok = *begin_tokens;
+ Tok.setLocation(SM.createMacroArgExpansionLoc(Tok.getLocation(),
+ InstLoc,
+ Tok.getLength()));
+ return;
+ }
+
+ updateConsecutiveMacroArgTokens(SM, InstLoc, begin_tokens, end_tokens);
+ }
}
diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt
index 6bf5e64cc6f8..6c980ced7ee4 100644
--- a/lib/Parse/CMakeLists.txt
+++ b/lib/Parse/CMakeLists.txt
@@ -16,4 +16,4 @@ add_clang_library(clangParse
Parser.cpp
)
-add_dependencies(clangParse ClangAttrClasses ClangAttrList ClangDeclNodes ClangDiagnosticParse ClangStmtNodes)
+add_dependencies(clangParse ClangAttrClasses ClangAttrList ClangDeclNodes ClangDiagnosticParse ClangStmtNodes ClangAttrLateParsed)
diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp
index 56584c96180b..fdd7d0f151a6 100644
--- a/lib/Parse/ParseAST.cpp
+++ b/lib/Parse/ParseAST.cpp
@@ -37,11 +37,11 @@ using namespace clang;
///
void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
ASTContext &Ctx, bool PrintStats,
- bool CompleteTranslationUnit,
+ TranslationUnitKind TUKind,
CodeCompleteConsumer *CompletionConsumer) {
llvm::OwningPtr<Sema> S(new Sema(PP, Ctx, *Consumer,
- CompleteTranslationUnit,
+ TUKind,
CompletionConsumer));
// Recover resources if we crash before exiting this method.
@@ -93,7 +93,7 @@ void clang::ParseAST(Sema &S, bool PrintStats) {
Consumer->HandleTopLevelDecl(ADecl.get());
// Process any TopLevelDecls generated by #pragma weak.
- for (llvm::SmallVector<Decl*,2>::iterator
+ for (SmallVector<Decl*,2>::iterator
I = S.WeakTopLevelDecls().begin(),
E = S.WeakTopLevelDecls().end(); I != E; ++I)
Consumer->HandleTopLevelDecl(DeclGroupRef(*I));
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index f5c69981ca35..b387e9e551d4 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -21,7 +21,9 @@ using namespace clang;
/// 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, ParsingDeclarator &D,
+Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
+ AttributeList *AccessAttrs,
+ ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo,
const VirtSpecifiers& VS, ExprResult& Init) {
assert(D.isFunctionDeclarator() && "This isn't a function declarator!");
@@ -34,16 +36,25 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0);
Decl *FnD;
+ D.setFunctionDefinition(true);
if (D.getDeclSpec().isFriendSpecified())
- // FIXME: Friend templates
- FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D, true,
+ FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D,
move(TemplateParams));
- else { // FIXME: pass template information through
+ else {
FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D,
move(TemplateParams), 0,
- VS, Init.release(),
- /*HasInit=*/false,
- /*IsDefinition*/true);
+ VS, /*HasInit=*/false);
+ if (FnD) {
+ Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs,
+ false, true);
+ bool TypeSpecContainsAuto
+ = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto;
+ if (Init.get())
+ Actions.AddInitializerToDecl(FnD, Init.get(), false,
+ TypeSpecContainsAuto);
+ else
+ Actions.ActOnUninitializedDecl(FnD, TypeSpecContainsAuto);
+ }
}
HandleMemberFunctionDefaultArgs(D, FnD);
@@ -123,30 +134,24 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
CachedTokens &Toks = LM->Toks;
tok::TokenKind kind = Tok.getKind();
- // We may have a constructor initializer or function-try-block here.
- if (kind == tok::colon || kind == tok::kw_try) {
- // Consume everything up to (and including) the left brace.
- if (!ConsumeAndStoreUntil(tok::l_brace, Toks)) {
- // We didn't find the left-brace we expected after the
- // constructor initializer.
- if (Tok.is(tok::semi)) {
- // We found a semicolon; complain, consume the semicolon, and
- // don't try to parse this method later.
- Diag(Tok.getLocation(), diag::err_expected_lbrace);
- ConsumeAnyToken();
- delete getCurrentClass().LateParsedDeclarations.back();
- getCurrentClass().LateParsedDeclarations.pop_back();
- return FnD;
- }
+ // Consume everything up to (and including) the left brace of the
+ // function body.
+ if (ConsumeAndStoreFunctionPrologue(Toks)) {
+ // We didn't find the left-brace we expected after the
+ // constructor initializer.
+ if (Tok.is(tok::semi)) {
+ // We found a semicolon; complain, consume the semicolon, and
+ // don't try to parse this method later.
+ Diag(Tok.getLocation(), diag::err_expected_lbrace);
+ ConsumeAnyToken();
+ delete getCurrentClass().LateParsedDeclarations.back();
+ getCurrentClass().LateParsedDeclarations.pop_back();
+ return FnD;
}
-
} else {
- // Begin by storing the '{' token.
- Toks.push_back(Tok);
- ConsumeBrace();
+ // Consume everything up to (and including) the matching right brace.
+ ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
}
- // Consume everything up to (and including) the matching right brace.
- ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
// If we're in a function-try-block, we need to store all the catch blocks.
if (kind == tok::kw_try) {
@@ -398,6 +403,8 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
if (!Tok.is(tok::l_brace)) {
FnScope.Exit();
Actions.ActOnFinishFunctionBody(LM.D, 0);
+ while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof))
+ ConsumeAnyToken();
return;
}
} else
@@ -450,7 +457,7 @@ void Parser::ParseLexedMemberInitializers(ParsingClass &Class) {
}
void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) {
- if (MI.Field->isInvalidDecl())
+ if (!MI.Field || MI.Field->isInvalidDecl())
return;
// Append the current token at the end of the new token stream so that it
@@ -551,8 +558,16 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
ConsumeBrace();
break;
+ case tok::code_completion:
+ Toks.push_back(Tok);
+ ConsumeCodeCompletionToken();
+ break;
+
case tok::string_literal:
case tok::wide_string_literal:
+ case tok::utf8_string_literal:
+ case tok::utf16_string_literal:
+ case tok::utf32_string_literal:
Toks.push_back(Tok);
ConsumeStringToken();
break;
@@ -569,3 +584,70 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
isFirstTokenConsumed = false;
}
}
+
+/// \brief Consume tokens and store them in the passed token container until
+/// we've passed the try keyword and constructor initializers and have consumed
+/// the opening brace of the function body. The opening brace will be consumed
+/// if and only if there was no error.
+///
+/// \return True on error.
+bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) {
+ if (Tok.is(tok::kw_try)) {
+ Toks.push_back(Tok);
+ ConsumeToken();
+ }
+ if (Tok.is(tok::colon)) {
+ // Initializers can contain braces too.
+ Toks.push_back(Tok);
+ ConsumeToken();
+
+ while (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) {
+ if (Tok.is(tok::eof) || Tok.is(tok::semi))
+ return true;
+
+ // Grab the identifier.
+ if (!ConsumeAndStoreUntil(tok::l_paren, tok::l_brace, Toks,
+ /*StopAtSemi=*/true,
+ /*ConsumeFinalToken=*/false))
+ return true;
+
+ tok::TokenKind kind = Tok.getKind();
+ Toks.push_back(Tok);
+ if (kind == tok::l_paren)
+ ConsumeParen();
+ else {
+ assert(kind == tok::l_brace && "Must be left paren or brace here.");
+ ConsumeBrace();
+ // In C++03, this has to be the start of the function body, which
+ // means the initializer is malformed.
+ if (!getLang().CPlusPlus0x)
+ return false;
+ }
+
+ // Grab the initializer
+ if (!ConsumeAndStoreUntil(kind == tok::l_paren ? tok::r_paren :
+ tok::r_brace,
+ Toks, /*StopAtSemi=*/true))
+ return true;
+
+ // Grab the separating comma, if any.
+ if (Tok.is(tok::comma)) {
+ Toks.push_back(Tok);
+ ConsumeToken();
+ }
+ }
+ }
+
+ // Grab any remaining garbage to be diagnosed later. We stop when we reach a
+ // brace: an opening one is the function body, while a closing one probably
+ // means we've reached the end of the class.
+ if (!ConsumeAndStoreUntil(tok::l_brace, tok::r_brace, Toks,
+ /*StopAtSemi=*/true, /*ConsumeFinalToken=*/false))
+ return true;
+ if(Tok.isNot(tok::l_brace))
+ return true;
+
+ Toks.push_back(Tok);
+ ConsumeBrace();
+ return false;
+}
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 0e17295858b9..2aa178f5ebee 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -19,6 +19,7 @@
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "RAIIObjectsForParser.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringSwitch.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -32,12 +33,10 @@ using namespace clang;
/// Called type-id in C++.
TypeResult Parser::ParseTypeName(SourceRange *Range,
Declarator::TheContext Context,
- ObjCDeclSpec *objcQuals,
AccessSpecifier AS,
Decl **OwnedType) {
// Parse the common declaration-specifiers piece.
DeclSpec DS(AttrFactory);
- DS.setObjCQualifiers(objcQuals);
ParseSpecifierQualifierList(DS, AS);
if (OwnedType)
*OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0;
@@ -54,6 +53,16 @@ TypeResult Parser::ParseTypeName(SourceRange *Range,
return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
}
+
+/// isAttributeLateParsed - Return true if the attribute has arguments that
+/// require late parsing.
+static bool isAttributeLateParsed(const IdentifierInfo &II) {
+ return llvm::StringSwitch<bool>(II.getName())
+#include "clang/Parse/AttrLateParsed.inc"
+ .Default(false);
+}
+
+
/// ParseGNUAttributes - Parse a non-empty attributes list.
///
/// [GNU] attributes:
@@ -91,7 +100,8 @@ TypeResult Parser::ParseTypeName(SourceRange *Range,
/// a pressing need to implement the 2 token lookahead.
void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
- SourceLocation *endLoc) {
+ SourceLocation *endLoc,
+ LateParsedAttrList *LateAttrs) {
assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!");
while (Tok.is(tok::kw___attribute)) {
@@ -108,7 +118,6 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
// Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") ))
while (Tok.is(tok::identifier) || isDeclarationSpecifier() ||
Tok.is(tok::comma)) {
-
if (Tok.is(tok::comma)) {
// allows for empty/non-empty attributes. ((__vector_size__(16),,,,))
ConsumeToken();
@@ -118,112 +127,26 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
- // Availability attributes have their own grammar.
- if (AttrName->isStr("availability"))
- ParseAvailabilityAttribute(*AttrName, AttrNameLoc, attrs, endLoc);
- // check if we have a "parameterized" attribute
- else if (Tok.is(tok::l_paren)) {
- ConsumeParen(); // ignore the left paren loc for now
-
- if (Tok.is(tok::identifier)) {
- IdentifierInfo *ParmName = Tok.getIdentifierInfo();
- SourceLocation ParmLoc = ConsumeToken();
-
- if (Tok.is(tok::r_paren)) {
- // __attribute__(( mode(byte) ))
- ConsumeParen(); // ignore the right paren loc for now
- attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
- ParmName, ParmLoc, 0, 0);
- } else if (Tok.is(tok::comma)) {
- ConsumeToken();
- // __attribute__(( format(printf, 1, 2) ))
- ExprVector ArgExprs(Actions);
- bool ArgExprsOk = true;
-
- // now parse the non-empty comma separated list of expressions
- while (1) {
- ExprResult ArgExpr(ParseAssignmentExpression());
- if (ArgExpr.isInvalid()) {
- ArgExprsOk = false;
- SkipUntil(tok::r_paren);
- break;
- } else {
- ArgExprs.push_back(ArgExpr.release());
- }
- if (Tok.isNot(tok::comma))
- break;
- ConsumeToken(); // Eat the comma, move to the next argument
- }
- if (ArgExprsOk && Tok.is(tok::r_paren)) {
- ConsumeParen(); // ignore the right paren loc for now
- attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
- ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size());
- }
- }
- } else { // not an identifier
- switch (Tok.getKind()) {
- case tok::r_paren:
- // parse a possibly empty comma separated list of expressions
- // __attribute__(( nonnull() ))
- ConsumeParen(); // ignore the right paren loc for now
- attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
- 0, SourceLocation(), 0, 0);
- break;
- case tok::kw_char:
- case tok::kw_wchar_t:
- case tok::kw_char16_t:
- case tok::kw_char32_t:
- case tok::kw_bool:
- case tok::kw_short:
- case tok::kw_int:
- case tok::kw_long:
- case tok::kw___int64:
- case tok::kw_signed:
- case tok::kw_unsigned:
- case tok::kw_float:
- case tok::kw_double:
- case tok::kw_void:
- case tok::kw_typeof: {
- AttributeList *attr
- = attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
- 0, SourceLocation(), 0, 0);
- if (attr->getKind() == AttributeList::AT_IBOutletCollection)
- Diag(Tok, diag::err_iboutletcollection_builtintype);
- // If it's a builtin type name, eat it and expect a rparen
- // __attribute__(( vec_type_hint(char) ))
- ConsumeToken();
- if (Tok.is(tok::r_paren))
- ConsumeParen();
- break;
- }
- default:
- // __attribute__(( aligned(16) ))
- ExprVector ArgExprs(Actions);
- bool ArgExprsOk = true;
-
- // now parse the list of expressions
- while (1) {
- ExprResult ArgExpr(ParseAssignmentExpression());
- if (ArgExpr.isInvalid()) {
- ArgExprsOk = false;
- SkipUntil(tok::r_paren);
- break;
- } else {
- ArgExprs.push_back(ArgExpr.release());
- }
- if (Tok.isNot(tok::comma))
- break;
- ConsumeToken(); // Eat the comma, move to the next argument
- }
- // Match the ')'.
- if (ArgExprsOk && Tok.is(tok::r_paren)) {
- ConsumeParen(); // ignore the right paren loc for now
- attrs.addNew(AttrName, AttrNameLoc, 0,
- AttrNameLoc, 0, SourceLocation(),
- ArgExprs.take(), ArgExprs.size());
- }
- break;
- }
+ if (Tok.is(tok::l_paren)) {
+ // handle "parameterized" attributes
+ if (LateAttrs && !ClassStack.empty() &&
+ isAttributeLateParsed(*AttrName)) {
+ // Delayed parsing is only available for attributes that occur
+ // in certain locations within a class scope.
+ LateParsedAttribute *LA =
+ new LateParsedAttribute(this, *AttrName, AttrNameLoc);
+ LateAttrs->push_back(LA);
+ getCurrentClass().LateParsedDeclarations.push_back(LA);
+
+ // consume everything up to and including the matching right parens
+ ConsumeAndStoreUntil(tok::r_paren, LA->Toks, true, false);
+
+ Token Eof;
+ Eof.startToken();
+ Eof.setLocation(Tok.getLocation());
+ LA->Toks.push_back(Eof);
+ } else {
+ ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc);
}
} else {
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
@@ -241,6 +164,133 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
}
}
+
+/// Parse the arguments to a parameterized GNU attribute
+void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
+ SourceLocation AttrNameLoc,
+ ParsedAttributes &Attrs,
+ SourceLocation *EndLoc) {
+
+ assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
+
+ // Availability attributes have their own grammar.
+ if (AttrName->isStr("availability")) {
+ ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
+ return;
+ }
+ // Thread safety attributes fit into the FIXME case above, so we
+ // just parse the arguments as a list of expressions
+ if (IsThreadSafetyAttribute(AttrName->getName())) {
+ ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
+ return;
+ }
+
+ ConsumeParen(); // ignore the left paren loc for now
+
+ if (Tok.is(tok::identifier)) {
+ IdentifierInfo *ParmName = Tok.getIdentifierInfo();
+ SourceLocation ParmLoc = ConsumeToken();
+
+ if (Tok.is(tok::r_paren)) {
+ // __attribute__(( mode(byte) ))
+ SourceLocation RParen = ConsumeParen();
+ Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc,
+ ParmName, ParmLoc, 0, 0);
+ } else if (Tok.is(tok::comma)) {
+ ConsumeToken();
+ // __attribute__(( format(printf, 1, 2) ))
+ ExprVector ArgExprs(Actions);
+ bool ArgExprsOk = true;
+
+ // now parse the non-empty comma separated list of expressions
+ while (1) {
+ ExprResult ArgExpr(ParseAssignmentExpression());
+ if (ArgExpr.isInvalid()) {
+ ArgExprsOk = false;
+ SkipUntil(tok::r_paren);
+ break;
+ } else {
+ ArgExprs.push_back(ArgExpr.release());
+ }
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken(); // Eat the comma, move to the next argument
+ }
+ if (ArgExprsOk && Tok.is(tok::r_paren)) {
+ SourceLocation RParen = ConsumeParen();
+ Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc,
+ ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size());
+ }
+ }
+ } else { // not an identifier
+ switch (Tok.getKind()) {
+ case tok::r_paren: {
+ // parse a possibly empty comma separated list of expressions
+ // __attribute__(( nonnull() ))
+ SourceLocation RParen = ConsumeParen();
+ Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc,
+ 0, SourceLocation(), 0, 0);
+ break;
+ }
+ case tok::kw_char:
+ case tok::kw_wchar_t:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
+ case tok::kw_bool:
+ case tok::kw_short:
+ case tok::kw_int:
+ case tok::kw_long:
+ case tok::kw___int64:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_void:
+ case tok::kw_typeof: {
+ // If it's a builtin type name, eat it and expect a rparen
+ // __attribute__(( vec_type_hint(char) ))
+ SourceLocation EndLoc = ConsumeToken();
+ if (Tok.is(tok::r_paren))
+ EndLoc = ConsumeParen();
+ AttributeList *attr
+ = Attrs.addNew(AttrName, SourceRange(AttrNameLoc, EndLoc), 0,
+ AttrNameLoc, 0, SourceLocation(), 0, 0);
+ if (attr->getKind() == AttributeList::AT_IBOutletCollection)
+ Diag(Tok, diag::err_iboutletcollection_builtintype);
+ break;
+ }
+ default:
+ // __attribute__(( aligned(16) ))
+ ExprVector ArgExprs(Actions);
+ bool ArgExprsOk = true;
+
+ // now parse the list of expressions
+ while (1) {
+ ExprResult ArgExpr(ParseAssignmentExpression());
+ if (ArgExpr.isInvalid()) {
+ ArgExprsOk = false;
+ SkipUntil(tok::r_paren);
+ break;
+ } else {
+ ArgExprs.push_back(ArgExpr.release());
+ }
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken(); // Eat the comma, move to the next argument
+ }
+ // Match the ')'.
+ if (ArgExprsOk && Tok.is(tok::r_paren)) {
+ SourceLocation RParen = ConsumeParen();
+ Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0,
+ AttrNameLoc, 0, SourceLocation(),
+ ArgExprs.take(), ArgExprs.size());
+ }
+ break;
+ }
+ }
+}
+
+
/// ParseMicrosoftDeclSpec - Parse an __declspec construct
///
/// [MS] decl-specifier:
@@ -297,10 +347,13 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) {
// FIXME: Allow Sema to distinguish between these and real attributes!
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___ptr64) || Tok.is(tok::kw___w64) ||
+ Tok.is(tok::kw___ptr32) ||
+ Tok.is(tok::kw___unaligned)) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
- if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64))
+ if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) ||
+ Tok.is(tok::kw___ptr32))
// FIXME: Support these properly!
continue;
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
@@ -511,12 +564,11 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
AvailabilityChange Changes[Unknown];
// Opening '('.
- SourceLocation LParenLoc;
- if (!Tok.is(tok::l_paren)) {
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.consumeOpen()) {
Diag(Tok, diag::err_expected_lparen);
return;
}
- LParenLoc = ConsumeParen();
// Parse the platform name,
if (Tok.isNot(tok::identifier)) {
@@ -614,12 +666,11 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
} while (true);
// Closing ')'.
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
- if (RParenLoc.isInvalid())
+ if (T.consumeClose())
return;
if (endLoc)
- *endLoc = RParenLoc;
+ *endLoc = T.getCloseLocation();
// The 'unavailable' availability cannot be combined with any other
// availability changes. Make sure that hasn't happened.
@@ -641,7 +692,8 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
}
// Record this attribute
- attrs.addNew(&Availability, AvailabilityLoc,
+ attrs.addNew(&Availability,
+ SourceRange(AvailabilityLoc, T.getCloseLocation()),
0, SourceLocation(),
Platform, PlatformLoc,
Changes[Introduced],
@@ -650,6 +702,172 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
UnavailableLoc, false, false);
}
+
+// Late Parsed Attributes:
+// See other examples of late parsing in lib/Parse/ParseCXXInlineMethods
+
+void Parser::LateParsedDeclaration::ParseLexedAttributes() {}
+
+void Parser::LateParsedClass::ParseLexedAttributes() {
+ Self->ParseLexedAttributes(*Class);
+}
+
+void Parser::LateParsedAttribute::ParseLexedAttributes() {
+ Self->ParseLexedAttribute(*this);
+}
+
+/// Wrapper class which calls ParseLexedAttribute, after setting up the
+/// scope appropriately.
+void Parser::ParseLexedAttributes(ParsingClass &Class) {
+ // Deal with templates
+ // FIXME: Test cases to make sure this does the right thing for templates.
+ bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
+ ParseScope ClassTemplateScope(this, Scope::TemplateParamScope,
+ HasTemplateScope);
+ if (HasTemplateScope)
+ Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
+
+ // Set or update the scope flags to include Scope::ThisScope.
+ bool AlreadyHasClassScope = Class.TopLevelClass;
+ unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope|Scope::ThisScope;
+ ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope);
+ ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope);
+
+ for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i) {
+ Class.LateParsedDeclarations[i]->ParseLexedAttributes();
+ }
+}
+
+/// \brief Finish parsing an attribute for which parsing was delayed.
+/// This will be called at the end of parsing a class declaration
+/// for each LateParsedAttribute. We consume the saved tokens and
+/// create an attribute with the arguments filled in. We add this
+/// to the Attribute list for the decl.
+void Parser::ParseLexedAttribute(LateParsedAttribute &LA) {
+ // Save the current token position.
+ SourceLocation OrigLoc = Tok.getLocation();
+
+ // Append the current token at the end of the new token stream so that it
+ // doesn't get lost.
+ LA.Toks.push_back(Tok);
+ PP.EnterTokenStream(LA.Toks.data(), LA.Toks.size(), true, false);
+ // Consume the previously pushed token.
+ ConsumeAnyToken();
+
+ ParsedAttributes Attrs(AttrFactory);
+ SourceLocation endLoc;
+
+ // If the Decl is templatized, add template parameters to scope.
+ bool HasTemplateScope = LA.D && LA.D->isTemplateDecl();
+ ParseScope TempScope(this, Scope::TemplateParamScope, HasTemplateScope);
+ if (HasTemplateScope)
+ Actions.ActOnReenterTemplateScope(Actions.CurScope, LA.D);
+
+ // If the Decl is on a function, add function parameters to the scope.
+ bool HasFunctionScope = LA.D && LA.D->isFunctionOrFunctionTemplate();
+ ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope, HasFunctionScope);
+ if (HasFunctionScope)
+ Actions.ActOnReenterFunctionContext(Actions.CurScope, LA.D);
+
+ ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc);
+
+ if (HasFunctionScope) {
+ Actions.ActOnExitFunctionContext();
+ FnScope.Exit(); // Pop scope, and remove Decls from IdResolver
+ }
+ if (HasTemplateScope) {
+ TempScope.Exit();
+ }
+
+ // Late parsed attributes must be attached to Decls by hand. If the
+ // LA.D is not set, then this was not done properly.
+ assert(LA.D && "No decl attached to late parsed attribute");
+ Actions.ActOnFinishDelayedAttribute(getCurScope(), LA.D, Attrs);
+
+ if (Tok.getLocation() != OrigLoc) {
+ // Due to a parsing error, we either went over the cached tokens or
+ // there are still cached tokens left, so we skip the leftover tokens.
+ // Since this is an uncommon situation that should be avoided, use the
+ // expensive isBeforeInTranslationUnit call.
+ if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(),
+ OrigLoc))
+ while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof))
+ ConsumeAnyToken();
+ }
+}
+
+/// \brief Wrapper around a case statement checking if AttrName is
+/// one of the thread safety attributes
+bool Parser::IsThreadSafetyAttribute(llvm::StringRef AttrName){
+ return llvm::StringSwitch<bool>(AttrName)
+ .Case("guarded_by", true)
+ .Case("guarded_var", true)
+ .Case("pt_guarded_by", true)
+ .Case("pt_guarded_var", true)
+ .Case("lockable", true)
+ .Case("scoped_lockable", true)
+ .Case("no_thread_safety_analysis", true)
+ .Case("acquired_after", true)
+ .Case("acquired_before", true)
+ .Case("exclusive_lock_function", true)
+ .Case("shared_lock_function", true)
+ .Case("exclusive_trylock_function", true)
+ .Case("shared_trylock_function", true)
+ .Case("unlock_function", true)
+ .Case("lock_returned", true)
+ .Case("locks_excluded", true)
+ .Case("exclusive_locks_required", true)
+ .Case("shared_locks_required", true)
+ .Default(false);
+}
+
+/// \brief Parse the contents of thread safety attributes. These
+/// should always be parsed as an expression list.
+///
+/// We need to special case the parsing due to the fact that if the first token
+/// of the first argument is an identifier, the main parse loop will store
+/// that token as a "parameter" and the rest of
+/// the arguments will be added to a list of "arguments". However,
+/// subsequent tokens in the first argument are lost. We instead parse each
+/// argument as an expression and add all arguments to the list of "arguments".
+/// In future, we will take advantage of this special case to also
+/// deal with some argument scoping issues here (for example, referring to a
+/// function parameter in the attribute on that function).
+void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
+ SourceLocation AttrNameLoc,
+ ParsedAttributes &Attrs,
+ SourceLocation *EndLoc) {
+ assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
+
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
+
+ ExprVector ArgExprs(Actions);
+ bool ArgExprsOk = true;
+
+ // now parse the list of expressions
+ while (1) {
+ ExprResult ArgExpr(ParseAssignmentExpression());
+ if (ArgExpr.isInvalid()) {
+ ArgExprsOk = false;
+ T.consumeClose();
+ break;
+ } else {
+ ArgExprs.push_back(ArgExpr.release());
+ }
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken(); // Eat the comma, move to the next argument
+ }
+ // Match the ')'.
+ if (ArgExprsOk && !T.consumeClose()) {
+ Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(),
+ ArgExprs.take(), ArgExprs.size());
+ }
+ if (EndLoc)
+ *EndLoc = T.getCloseLocation();
+}
+
void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed)
<< attrs.Range;
@@ -676,6 +894,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
SourceLocation &DeclEnd,
ParsedAttributesWithRange &attrs) {
ParenBraceBracketBalancer BalancerRAIIObj(*this);
+ // Must temporarily exit the objective-c container scope for
+ // parsing c none objective-c decls.
+ ObjCDeclContextSwitch ObjCDC(*this);
Decl *SingleDecl = 0;
Decl *OwnedType = 0;
@@ -832,7 +1053,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, &ThisDecl, 1);
}
- llvm::SmallVector<Decl *, 8> DeclsInGroup;
+ SmallVector<Decl *, 8> DeclsInGroup;
Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(D);
D.complete(FirstDecl);
if (FirstDecl)
@@ -998,9 +1219,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteInitializer(getCurScope(), ThisDecl);
- ConsumeCodeCompletionToken();
- SkipUntil(tok::comma, true, true);
- return ThisDecl;
+ cutOffParsing();
+ return 0;
}
ExprResult Init(ParseInitializer());
@@ -1019,7 +1239,9 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
}
} else if (Tok.is(tok::l_paren)) {
// Parse C++ direct initializer: '(' expression-list ')'
- SourceLocation LParenLoc = ConsumeParen();
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
+
ExprVector Exprs(Actions);
CommaLocsTy CommaLocs;
@@ -1037,7 +1259,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
}
} else {
// Match the ')'.
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ T.consumeClose();
assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() &&
"Unexpected number of commas!");
@@ -1047,9 +1269,9 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
ExitScope();
}
- Actions.AddCXXDirectInitializerToDecl(ThisDecl, LParenLoc,
+ Actions.AddCXXDirectInitializerToDecl(ThisDecl, T.getOpenLocation(),
move_arg(Exprs),
- RParenLoc,
+ T.getCloseLocation(),
TypeContainsAuto);
}
} else if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) {
@@ -1090,6 +1312,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS) {
/// specifier-qualifier-list is a subset of declaration-specifiers. Just
/// parse declaration-specifiers and complain about extra stuff.
+ /// TODO: diagnose attribute-specifiers and alignment-specifiers.
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
// Validate declspec for type-name.
@@ -1273,12 +1496,70 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) {
return DSC_normal;
}
+/// ParseAlignArgument - Parse the argument to an alignment-specifier.
+///
+/// FIXME: Simply returns an alignof() expression if the argument is a
+/// type. Ideally, the type should be propagated directly into Sema.
+///
+/// [C1X/C++0x] type-id
+/// [C1X] constant-expression
+/// [C++0x] assignment-expression
+ExprResult Parser::ParseAlignArgument(SourceLocation Start) {
+ if (isTypeIdInParens()) {
+ EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
+ SourceLocation TypeLoc = Tok.getLocation();
+ ParsedType Ty = ParseTypeName().get();
+ SourceRange TypeRange(Start, Tok.getLocation());
+ return Actions.ActOnUnaryExprOrTypeTraitExpr(TypeLoc, UETT_AlignOf, true,
+ Ty.getAsOpaquePtr(), TypeRange);
+ } else
+ return ParseConstantExpression();
+}
+
+/// ParseAlignmentSpecifier - Parse an alignment-specifier, and add the
+/// attribute to Attrs.
+///
+/// alignment-specifier:
+/// [C1X] '_Alignas' '(' type-id ')'
+/// [C1X] '_Alignas' '(' constant-expression ')'
+/// [C++0x] 'alignas' '(' type-id ')'
+/// [C++0x] 'alignas' '(' assignment-expression ')'
+void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
+ SourceLocation *endLoc) {
+ assert((Tok.is(tok::kw_alignas) || Tok.is(tok::kw__Alignas)) &&
+ "Not an alignment-specifier!");
+
+ SourceLocation KWLoc = Tok.getLocation();
+ ConsumeToken();
+
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.expectAndConsume(diag::err_expected_lparen))
+ return;
+
+ ExprResult ArgExpr = ParseAlignArgument(T.getOpenLocation());
+ if (ArgExpr.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return;
+ }
+
+ T.consumeClose();
+ if (endLoc)
+ *endLoc = T.getCloseLocation();
+
+ ExprVector ArgExprs(Actions);
+ ArgExprs.push_back(ArgExpr.release());
+ Attrs.addNew(PP.getIdentifierInfo("aligned"), KWLoc, 0, KWLoc,
+ 0, T.getOpenLocation(), ArgExprs.take(), 1, false, true);
+}
+
/// ParseDeclarationSpecifiers
/// declaration-specifiers: [C99 6.7]
/// storage-class-specifier declaration-specifiers[opt]
/// type-specifier declaration-specifiers[opt]
/// [C99] function-specifier declaration-specifiers[opt]
+/// [C1X] alignment-specifier declaration-specifiers[opt]
/// [GNU] attributes declaration-specifiers[opt]
+/// [Clang] '__module_private__' declaration-specifiers[opt]
///
/// storage-class-specifier: [C99 6.7.1]
/// 'typedef'
@@ -1316,6 +1597,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
switch (Tok.getKind()) {
default:
DoneWithDeclSpec:
+ // [C++0x] decl-specifier-seq: decl-specifier attribute-specifier-seq[opt]
+ MaybeParseCXX0XAttributes(DS.getAttributes());
+
// If this is not a declaration specifier token, we're done reading decl
// specifiers. First verify that DeclSpec's are consistent.
DS.Finish(Diags, PP);
@@ -1337,8 +1621,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
Actions.CodeCompleteDeclSpec(getCurScope(), DS,
AllowNonIdentifiers,
AllowNestedNameSpecifiers);
- ConsumeCodeCompletionToken();
- return;
+ return cutOffParsing();
}
if (getCurScope()->getFnParent() || getCurScope()->getBlockParent())
@@ -1352,8 +1635,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
CCC = Sema::PCC_ObjCImplementation;
Actions.CodeCompleteOrdinaryName(getCurScope(), CCC);
- ConsumeCodeCompletionToken();
- return;
+ return cutOffParsing();
}
case tok::coloncolon: // ::foo::bar
@@ -1641,11 +1923,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
break;
case tok::kw___ptr64:
+ case tok::kw___ptr32:
case tok::kw___w64:
case tok::kw___cdecl:
case tok::kw___stdcall:
case tok::kw___fastcall:
case tok::kw___thiscall:
+ case tok::kw___unaligned:
ParseMicrosoftTypeAttributes(DS.getAttributes());
continue;
@@ -1661,49 +1945,47 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// storage-class-specifier
case tok::kw_typedef:
- isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec,
- DiagID, getLang());
+ isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_typedef, Loc,
+ PrevSpec, DiagID);
break;
case tok::kw_extern:
if (DS.isThreadSpecified())
Diag(Tok, diag::ext_thread_before) << "extern";
- isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_extern, Loc, PrevSpec,
- DiagID, getLang());
+ isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_extern, Loc,
+ PrevSpec, DiagID);
break;
case tok::kw___private_extern__:
- isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_private_extern, Loc,
- PrevSpec, DiagID, getLang());
+ isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_private_extern,
+ Loc, PrevSpec, DiagID);
break;
case tok::kw_static:
if (DS.isThreadSpecified())
Diag(Tok, diag::ext_thread_before) << "static";
- isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_static, Loc, PrevSpec,
- DiagID, getLang());
+ isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_static, Loc,
+ PrevSpec, DiagID);
break;
case tok::kw_auto:
if (getLang().CPlusPlus0x) {
if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) {
- isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec,
- DiagID, getLang());
+ isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
+ PrevSpec, DiagID);
if (!isInvalid)
- Diag(Tok, diag::auto_storage_class)
+ Diag(Tok, diag::ext_auto_storage_class)
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
- }
- else
+ } else
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec,
DiagID);
- }
- else
- isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec,
- DiagID, getLang());
+ } else
+ isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
+ PrevSpec, DiagID);
break;
case tok::kw_register:
- isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec,
- DiagID, getLang());
+ isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_register, Loc,
+ PrevSpec, DiagID);
break;
case tok::kw_mutable:
- isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_mutable, Loc, PrevSpec,
- DiagID, getLang());
+ isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_mutable, Loc,
+ PrevSpec, DiagID);
break;
case tok::kw___thread:
isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec, DiagID);
@@ -1720,6 +2002,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.SetFunctionSpecExplicit(Loc, PrevSpec, DiagID);
break;
+ // alignment-specifier
+ case tok::kw__Alignas:
+ if (!getLang().C1X)
+ Diag(Tok, diag::ext_c1x_alignas);
+ ParseAlignmentSpecifier(DS.getAttributes());
+ continue;
+
// friend
case tok::kw_friend:
if (DSContext == DSC_class)
@@ -1731,6 +2020,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
}
break;
+ // Modules
+ case tok::kw___module_private__:
+ isInvalid = DS.setModulePrivateSpec(Loc, PrevSpec, DiagID);
+ break;
+
// constexpr
case tok::kw_constexpr:
isInvalid = DS.SetConstexprSpec(Loc, PrevSpec, DiagID);
@@ -1781,6 +2075,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec,
DiagID);
break;
+ case tok::kw_half:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec,
+ DiagID);
+ break;
case tok::kw_float:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec,
DiagID);
@@ -1890,6 +2188,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw___underlying_type:
ParseUnderlyingTypeSpecifier(DS);
+ continue;
+
+ case tok::kw__Atomic:
+ ParseAtomicSpecifier(DS);
+ continue;
// OpenCL qualifiers:
case tok::kw_private:
@@ -2004,7 +2307,8 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
case tok::kw_typename: // typename foo::bar
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
- if (TryAnnotateTypeOrScopeToken())
+ if (TryAnnotateTypeOrScopeToken(/*EnteringContext=*/false,
+ /*NeedType=*/true))
return true;
if (Tok.is(tok::identifier))
return false;
@@ -2017,7 +2321,8 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
- if (TryAnnotateTypeOrScopeToken())
+ if (TryAnnotateTypeOrScopeToken(/*EnteringContext=*/false,
+ /*NeedType=*/true))
return true;
return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
TemplateInfo, SuppressDeclarations);
@@ -2082,6 +2387,9 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
case tok::kw_int:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID);
break;
+ case tok::kw_half:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID);
+ break;
case tok::kw_float:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID);
break;
@@ -2166,6 +2474,10 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
ParseUnderlyingTypeSpecifier(DS);
return true;
+ case tok::kw__Atomic:
+ ParseAtomicSpecifier(DS);
+ return true;
+
// OpenCL qualifiers:
case tok::kw_private:
if (!getLang().OpenCL)
@@ -2182,18 +2494,24 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
// C++0x auto support.
case tok::kw_auto:
- if (!getLang().CPlusPlus0x)
+ // This is only called in situations where a storage-class specifier is
+ // illegal, so we can assume an auto type specifier was intended even in
+ // C++98. In C++98 mode, DeclSpec::Finish will produce an appropriate
+ // extension diagnostic.
+ if (!getLang().CPlusPlus)
return false;
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID);
break;
case tok::kw___ptr64:
+ case tok::kw___ptr32:
case tok::kw___w64:
case tok::kw___cdecl:
case tok::kw___stdcall:
case tok::kw___fastcall:
case tok::kw___thiscall:
+ case tok::kw___unaligned:
ParseMicrosoftTypeAttributes(DS.getAttributes());
return true;
@@ -2236,6 +2554,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
///
void Parser::
ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) {
+
if (Tok.is(tok::kw___extension__)) {
// __extension__ silences extension warnings in the subexpression.
ExtensionRAIIObject O(Diags); // Use RAII to do this.
@@ -2314,7 +2633,9 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
PrettyDeclStackTraceEntry CrashInfo(Actions, TagDecl, RecordLoc,
"parsing struct/union body");
- SourceLocation LBraceLoc = ConsumeBrace();
+ BalancedDelimiterTracker T(*this, tok::l_brace);
+ if (T.consumeOpen())
+ return;
ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope);
Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
@@ -2325,7 +2646,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
Diag(Tok, diag::ext_empty_struct_union)
<< (TagType == TST_union);
- llvm::SmallVector<Decl *, 32> FieldDecls;
+ SmallVector<Decl *, 32> FieldDecls;
// While we still have something to read, read the declarations in the struct.
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
@@ -2347,10 +2668,10 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
struct CFieldCallback : FieldCallback {
Parser &P;
Decl *TagDecl;
- llvm::SmallVectorImpl<Decl *> &FieldDecls;
+ SmallVectorImpl<Decl *> &FieldDecls;
CFieldCallback(Parser &P, Decl *TagDecl,
- llvm::SmallVectorImpl<Decl *> &FieldDecls) :
+ SmallVectorImpl<Decl *> &FieldDecls) :
P(P), TagDecl(TagDecl), FieldDecls(FieldDecls) {}
virtual Decl *invoke(FieldDeclarator &FD) {
@@ -2378,7 +2699,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
SkipUntil(tok::semi, true);
continue;
}
- llvm::SmallVector<Decl *, 16> Fields;
+ SmallVector<Decl *, 16> Fields;
Actions.ActOnDefs(getCurScope(), TagDecl, Tok.getLocation(),
Tok.getIdentifierInfo(), Fields);
FieldDecls.insert(FieldDecls.end(), Fields.begin(), Fields.end());
@@ -2400,18 +2721,19 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
}
}
- SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
+ T.consumeClose();
ParsedAttributes attrs(AttrFactory);
// If attributes exist after struct contents, parse them.
MaybeParseGNUAttributes(attrs);
Actions.ActOnFields(getCurScope(),
- RecordLoc, TagDecl, FieldDecls.data(), FieldDecls.size(),
- LBraceLoc, RBraceLoc,
+ RecordLoc, TagDecl, FieldDecls,
+ T.getOpenLocation(), T.getCloseLocation(),
attrs.getList());
StructScope.Exit();
- Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, RBraceLoc);
+ Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl,
+ T.getCloseLocation());
}
/// ParseEnumSpecifier
@@ -2448,7 +2770,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (Tok.is(tok::code_completion)) {
// Code completion for an enum name.
Actions.CodeCompleteTag(getCurScope(), DeclSpec::TST_enum);
- ConsumeCodeCompletionToken();
+ return cutOffParsing();
}
bool IsScopedEnum = false;
@@ -2465,7 +2787,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
ParsedAttributes attrs(AttrFactory);
MaybeParseGNUAttributes(attrs);
- bool AllowFixedUnderlyingType = getLang().CPlusPlus0x || getLang().Microsoft;
+ bool AllowFixedUnderlyingType
+ = getLang().CPlusPlus0x || getLang().MicrosoftExt || getLang().ObjC2;
CXXScopeSpec &SS = DS.getTypeSpecScope();
if (getLang().CPlusPlus) {
@@ -2568,7 +2891,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
SourceRange Range;
BaseType = ParseTypeName(&Range);
- if (!getLang().CPlusPlus0x)
+ if (!getLang().CPlusPlus0x && !getLang().ObjC2)
Diag(StartLoc, diag::ext_ms_enum_fixed_underlying_type)
<< Range;
}
@@ -2615,7 +2938,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
unsigned DiagID;
Decl *TagDecl = Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK,
StartLoc, SS, Name, NameLoc, attrs.getList(),
- AS,
+ AS, DS.getModulePrivateSpecLoc(),
MultiTemplateParamsArg(Actions),
Owned, IsDependent, IsScopedEnum,
IsScopedUsingClassTag, BaseType);
@@ -2681,13 +3004,14 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
ParseScope EnumScope(this, Scope::DeclScope);
Actions.ActOnTagStartDefinition(getCurScope(), EnumDecl);
- SourceLocation LBraceLoc = ConsumeBrace();
+ BalancedDelimiterTracker T(*this, tok::l_brace);
+ T.consumeOpen();
// C does not allow an empty enumerator-list, C++ does [dcl.enum].
if (Tok.is(tok::r_brace) && !getLang().CPlusPlus)
Diag(Tok, diag::error_empty_enum);
- llvm::SmallVector<Decl *, 32> EnumConstantDecls;
+ SmallVector<Decl *, 32> EnumConstantDecls;
Decl *LastEnumConstDecl = 0;
@@ -2738,18 +3062,20 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
}
// Eat the }.
- SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
+ T.consumeClose();
// If attributes exist after the identifier list, parse them.
ParsedAttributes attrs(AttrFactory);
MaybeParseGNUAttributes(attrs);
- Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl,
- EnumConstantDecls.data(), EnumConstantDecls.size(),
- getCurScope(), attrs.getList());
+ Actions.ActOnEnumBody(StartLoc, T.getOpenLocation(), T.getCloseLocation(),
+ EnumDecl, EnumConstantDecls.data(),
+ EnumConstantDecls.size(), getCurScope(),
+ attrs.getList());
EnumScope.Exit();
- Actions.ActOnTagFinishDefinition(getCurScope(), EnumDecl, RBraceLoc);
+ Actions.ActOnTagFinishDefinition(getCurScope(), EnumDecl,
+ T.getCloseLocation());
}
/// isTypeSpecifierQualifier - Return true if the current token could be the
@@ -2797,6 +3123,7 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const {
case tok::kw_char16_t:
case tok::kw_char32_t:
case tok::kw_int:
+ case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
case tok::kw_bool:
@@ -2866,6 +3193,7 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw_char16_t:
case tok::kw_char32_t:
case tok::kw_int:
+ case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
case tok::kw_bool:
@@ -2901,7 +3229,9 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw___thiscall:
case tok::kw___w64:
case tok::kw___ptr64:
+ case tok::kw___ptr32:
case tok::kw___pascal:
+ case tok::kw___unaligned:
case tok::kw___private:
case tok::kw___local:
@@ -2915,6 +3245,10 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw_private:
return getLang().OpenCL;
+
+ // C1x _Atomic()
+ case tok::kw__Atomic:
+ return true;
}
}
@@ -2976,6 +3310,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw_register:
case tok::kw___thread:
+ // Modules
+ case tok::kw___module_private__:
+
// type-specifiers
case tok::kw_short:
case tok::kw_long:
@@ -2991,6 +3328,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw_char32_t:
case tok::kw_int:
+ case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
case tok::kw_bool:
@@ -3031,6 +3369,10 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw_decltype:
return true;
+ // C1x _Atomic()
+ case tok::kw__Atomic:
+ return true;
+
// GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'.
case tok::less:
return getLang().ObjC1;
@@ -3047,8 +3389,10 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw___thiscall:
case tok::kw___w64:
case tok::kw___ptr64:
+ case tok::kw___ptr32:
case tok::kw___forceinline:
case tok::kw___pascal:
+ case tok::kw___unaligned:
case tok::kw___private:
case tok::kw___local:
@@ -3148,8 +3492,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
switch (Tok.getKind()) {
case tok::code_completion:
Actions.CodeCompleteTypeQualifiers(DS);
- ConsumeCodeCompletionToken();
- break;
+ return cutOffParsing();
case tok::kw_const:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, DiagID,
@@ -3180,10 +3523,12 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
case tok::kw___w64:
case tok::kw___ptr64:
+ case tok::kw___ptr32:
case tok::kw___cdecl:
case tok::kw___stdcall:
case tok::kw___fastcall:
case tok::kw___thiscall:
+ case tok::kw___unaligned:
if (VendorAttributesAllowed) {
ParseMicrosoftTypeAttributes(DS.getAttributes());
continue;
@@ -3548,7 +3893,9 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
break;
}
ParsedAttributes attrs(AttrFactory);
- ParseFunctionDeclarator(ConsumeParen(), D, attrs);
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
+ ParseFunctionDeclarator(D, attrs, T);
} else if (Tok.is(tok::l_square)) {
ParseBracketDeclarator(D);
} else {
@@ -3571,7 +3918,9 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
/// parameter-type-list[opt] ')'
///
void Parser::ParseParenDeclarator(Declarator &D) {
- SourceLocation StartLoc = ConsumeParen();
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
+
assert(!D.isPastIdentifier() && "Should be called before passing identifier");
// Eat any attributes before we look at whether this is a grouping or function
@@ -3596,7 +3945,8 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// 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___w64) || Tok.is(tok::kw___ptr64) ||
+ Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned)) {
ParseMicrosoftTypeAttributes(attrs);
}
// Eat any Borland extensions.
@@ -3633,9 +3983,10 @@ void Parser::ParseParenDeclarator(Declarator &D) {
ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator);
// Match the ')'.
- SourceLocation EndLoc = MatchRHSPunctuation(tok::r_paren, StartLoc);
- D.AddTypeInfo(DeclaratorChunk::getParen(StartLoc, EndLoc),
- attrs, EndLoc);
+ T.consumeClose();
+ D.AddTypeInfo(DeclaratorChunk::getParen(T.getOpenLocation(),
+ T.getCloseLocation()),
+ attrs, T.getCloseLocation());
D.setGroupingParens(hadGroupingParens);
return;
@@ -3647,7 +3998,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// ParseFunctionDeclarator to handle of argument list.
D.SetIdentifier(0, Tok.getLocation());
- ParseFunctionDeclarator(StartLoc, D, attrs, RequiresArg);
+ ParseFunctionDeclarator(D, attrs, T, RequiresArg);
}
/// ParseFunctionDeclarator - We are after the identifier and have parsed the
@@ -3668,8 +4019,9 @@ void Parser::ParseParenDeclarator(Declarator &D) {
/// dynamic-exception-specification
/// noexcept-specification
///
-void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
+void Parser::ParseFunctionDeclarator(Declarator &D,
ParsedAttributes &attrs,
+ BalancedDelimiterTracker &Tracker,
bool RequiresArg) {
// lparen is already consumed!
assert(D.isPastIdentifier() && "Should not call before identifier!");
@@ -3678,7 +4030,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
// Otherwise, it is treated as a K&R-style function.
bool HasProto = false;
// Build up an array of information about the parsed arguments.
- llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
+ SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
// Remember where we see an ellipsis, if any.
SourceLocation EllipsisLoc;
@@ -3687,20 +4039,20 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
SourceLocation RefQualifierLoc;
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;
ParsedType TrailingReturnType;
SourceLocation EndLoc;
-
if (isFunctionDeclaratorIdentifierList()) {
if (RequiresArg)
Diag(Tok, diag::err_argument_required_after_attribute);
ParseFunctionDeclaratorIdentifierList(D, ParamInfo);
- EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ Tracker.consumeClose();
+ EndLoc = Tracker.getCloseLocation();
} else {
// Enter function-declaration scope, limiting any declarators to the
// function prototype scope, including parameter declarators.
@@ -3715,7 +4067,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
HasProto = ParamInfo.size() || getLang().CPlusPlus;
// If we have the closing ')', eat it.
- EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ Tracker.consumeClose();
+ EndLoc = Tracker.getCloseLocation();
if (getLang().CPlusPlus) {
MaybeParseCXX0XAttributes(attrs);
@@ -3745,7 +4098,10 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
// Parse trailing-return-type[opt].
if (getLang().CPlusPlus0x && Tok.is(tok::arrow)) {
- TrailingReturnType = ParseTrailingReturnType().get();
+ SourceRange Range;
+ TrailingReturnType = ParseTrailingReturnType(Range).get();
+ if (Range.getEnd().isValid())
+ EndLoc = Range.getEnd();
}
}
@@ -3768,7 +4124,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
DynamicExceptions.size(),
NoexceptExpr.isUsable() ?
NoexceptExpr.get() : 0,
- LParenLoc, EndLoc, D,
+ Tracker.getOpenLocation(),
+ EndLoc, D,
TrailingReturnType),
attrs, EndLoc);
}
@@ -3811,7 +4168,7 @@ bool Parser::isFunctionDeclaratorIdentifierList() {
///
void Parser::ParseFunctionDeclaratorIdentifierList(
Declarator &D,
- llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo) {
+ SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo) {
// If there was no identifier specified for the declarator, either we are in
// an abstract-declarator, or we are in a parameter declarator which was found
// to be abstract. In abstract-declarators, identifier lists are not valid:
@@ -3890,7 +4247,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(
void Parser::ParseParameterDeclarationClause(
Declarator &D,
ParsedAttributes &attrs,
- llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo,
+ SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo,
SourceLocation &EllipsisLoc) {
while (1) {
@@ -3902,9 +4259,9 @@ void Parser::ParseParameterDeclarationClause(
// Parse the declaration-specifiers.
// Just use the ParsingDeclaration "scope" of the declarator.
DeclSpec DS(AttrFactory);
-
+
// Skip any Microsoft attributes before a param.
- if (getLang().Microsoft && Tok.is(tok::l_square))
+ if (getLang().MicrosoftExt && Tok.is(tok::l_square))
ParseMicrosoftAttributes(DS.getAttributes());
SourceLocation DSStart = Tok.getLocation();
@@ -4036,20 +4393,22 @@ void Parser::ParseParameterDeclarationClause(
/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']'
/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']'
void Parser::ParseBracketDeclarator(Declarator &D) {
- SourceLocation StartLoc = ConsumeBracket();
+ BalancedDelimiterTracker T(*this, tok::l_square);
+ T.consumeOpen();
// C array syntax has many features, but by-far the most common is [] and [4].
// This code does a fast path to handle some of the most obvious cases.
if (Tok.getKind() == tok::r_square) {
- SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+ T.consumeClose();
ParsedAttributes attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
// Remember that we parsed the empty array type.
ExprResult NumElements;
D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0,
- StartLoc, EndLoc),
- attrs, EndLoc);
+ T.getOpenLocation(),
+ T.getCloseLocation()),
+ attrs, T.getCloseLocation());
return;
} else if (Tok.getKind() == tok::numeric_constant &&
GetLookAheadToken(1).is(tok::r_square)) {
@@ -4057,15 +4416,16 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
ExprResult ExprRes(Actions.ActOnNumericConstant(Tok));
ConsumeToken();
- SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+ T.consumeClose();
ParsedAttributes attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
// Remember that we parsed a array type, and remember its features.
D.AddTypeInfo(DeclaratorChunk::getArray(0, false, 0,
ExprRes.release(),
- StartLoc, EndLoc),
- attrs, EndLoc);
+ T.getOpenLocation(),
+ T.getCloseLocation()),
+ attrs, T.getCloseLocation());
return;
}
@@ -4122,7 +4482,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
return;
}
- SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+ T.consumeClose();
ParsedAttributes attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
@@ -4131,8 +4491,9 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(),
StaticLoc.isValid(), isStar,
NumElements.release(),
- StartLoc, EndLoc),
- attrs, EndLoc);
+ T.getOpenLocation(),
+ T.getCloseLocation()),
+ attrs, T.getCloseLocation());
}
/// [GNU] typeof-specifier:
@@ -4190,6 +4551,41 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
Diag(StartLoc, DiagID) << PrevSpec;
}
+/// [C1X] atomic-specifier:
+/// _Atomic ( type-name )
+///
+void Parser::ParseAtomicSpecifier(DeclSpec &DS) {
+ assert(Tok.is(tok::kw__Atomic) && "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);
+ return;
+ }
+
+ TypeResult Result = ParseTypeName();
+ if (Result.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return;
+ }
+
+ // Match the ')'
+ T.consumeClose();
+
+ if (T.getCloseLocation().isInvalid())
+ return;
+
+ DS.setTypeofParensRange(T.getRange());
+ DS.SetRangeEnd(T.getCloseLocation());
+
+ const char *PrevSpec = 0;
+ unsigned DiagID;
+ if (DS.SetTypeSpecType(DeclSpec::TST_atomic, StartLoc, PrevSpec,
+ DiagID, Result.release()))
+ Diag(StartLoc, DiagID) << PrevSpec;
+}
+
/// TryAltiVecVectorTokenOutOfLine - Out of line body that should only be called
/// from TryAltiVecVectorToken.
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 172049c34053..4339047f1f16 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -52,10 +52,12 @@ Decl *Parser::ParseNamespace(unsigned Context,
SourceLocation InlineLoc) {
assert(Tok.is(tok::kw_namespace) && "Not a namespace!");
SourceLocation NamespaceLoc = ConsumeToken(); // eat the 'namespace'.
-
+ ObjCDeclContextSwitch ObjCDC(*this);
+
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteNamespaceDecl(getCurScope());
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return 0;
}
SourceLocation IdentLoc;
@@ -89,12 +91,12 @@ Decl *Parser::ParseNamespace(unsigned Context,
if (InlineLoc.isValid())
Diag(InlineLoc, diag::err_inline_namespace_alias)
<< FixItHint::CreateRemoval(InlineLoc);
-
return ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd);
}
- if (Tok.isNot(tok::l_brace)) {
+ BalancedDelimiterTracker T(*this, tok::l_brace);
+ if (T.consumeOpen()) {
if (!ExtraIdent.empty()) {
Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
<< SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
@@ -104,8 +106,6 @@ Decl *Parser::ParseNamespace(unsigned Context,
return 0;
}
- SourceLocation LBrace = ConsumeBrace();
-
if (getCurScope()->isClassScope() || getCurScope()->isTemplateParamScope() ||
getCurScope()->isInObjcMethodScope() || getCurScope()->getBlockParent() ||
getCurScope()->getFnParent()) {
@@ -113,7 +113,7 @@ Decl *Parser::ParseNamespace(unsigned Context,
Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
<< SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
}
- Diag(LBrace, diag::err_namespace_nonnamespace_scope);
+ Diag(T.getOpenLocation(), diag::err_namespace_nonnamespace_scope);
SkipUntil(tok::r_brace, false);
return 0;
}
@@ -156,23 +156,23 @@ Decl *Parser::ParseNamespace(unsigned Context,
Decl *NamespcDecl =
Actions.ActOnStartNamespaceDef(getCurScope(), InlineLoc, NamespaceLoc,
- IdentLoc, Ident, LBrace, attrs.getList());
+ IdentLoc, Ident, T.getOpenLocation(),
+ attrs.getList());
PrettyDeclStackTraceEntry CrashInfo(Actions, NamespcDecl, NamespaceLoc,
"parsing namespace");
- SourceLocation RBraceLoc;
// Parse the contents of the namespace. This includes parsing recovery on
// any improperly nested namespaces.
ParseInnerNamespace(ExtraIdentLoc, ExtraIdent, ExtraNamespaceLoc, 0,
- InlineLoc, LBrace, attrs, RBraceLoc);
+ InlineLoc, attrs, T);
// Leave the namespace scope.
NamespaceScope.Exit();
- Actions.ActOnFinishNamespaceDef(NamespcDecl, RBraceLoc);
+ DeclEnd = T.getCloseLocation();
+ Actions.ActOnFinishNamespaceDef(NamespcDecl, DeclEnd);
- DeclEnd = RBraceLoc;
return NamespcDecl;
}
@@ -181,9 +181,8 @@ void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
std::vector<IdentifierInfo*>& Ident,
std::vector<SourceLocation>& NamespaceLoc,
unsigned int index, SourceLocation& InlineLoc,
- SourceLocation& LBrace,
ParsedAttributes& attrs,
- SourceLocation& RBraceLoc) {
+ BalancedDelimiterTracker &Tracker) {
if (index == Ident.size()) {
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
ParsedAttributesWithRange attrs(AttrFactory);
@@ -191,7 +190,10 @@ void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
MaybeParseMicrosoftAttributes(attrs);
ParseExternalDeclaration(attrs);
}
- RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBrace);
+
+ // The caller is what called check -- we are simply calling
+ // the close for it.
+ Tracker.consumeClose();
return;
}
@@ -201,14 +203,15 @@ void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
Decl *NamespcDecl =
Actions.ActOnStartNamespaceDef(getCurScope(), SourceLocation(),
NamespaceLoc[index], IdentLoc[index],
- Ident[index], LBrace, attrs.getList());
+ Ident[index], Tracker.getOpenLocation(),
+ attrs.getList());
ParseInnerNamespace(IdentLoc, Ident, NamespaceLoc, ++index, InlineLoc,
- LBrace, attrs, RBraceLoc);
+ attrs, Tracker);
NamespaceScope.Exit();
- Actions.ActOnFinishNamespaceDef(NamespcDecl, RBraceLoc);
+ Actions.ActOnFinishNamespaceDef(NamespcDecl, Tracker.getCloseLocation());
}
/// ParseNamespaceAlias - Parse the part after the '=' in a namespace
@@ -224,7 +227,8 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteNamespaceAliasDecl(getCurScope());
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return 0;
}
CXXScopeSpec SS;
@@ -262,7 +266,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
assert(Tok.is(tok::string_literal) && "Not a string literal!");
llvm::SmallString<8> LangBuffer;
bool Invalid = false;
- llvm::StringRef Lang = PP.getSpelling(Tok, LangBuffer, &Invalid);
+ StringRef Lang = PP.getSpelling(Tok, LangBuffer, &Invalid);
if (Invalid)
return 0;
@@ -296,7 +300,8 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
ProhibitAttributes(attrs);
- SourceLocation LBrace = ConsumeBrace();
+ BalancedDelimiterTracker T(*this, tok::l_brace);
+ T.consumeOpen();
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
@@ -304,9 +309,9 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
ParseExternalDeclaration(attrs);
}
- SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace);
+ T.consumeClose();
return Actions.ActOnFinishLinkageSpecification(getCurScope(), LinkageSpec,
- RBrace);
+ T.getCloseLocation());
}
/// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or
@@ -317,13 +322,15 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
ParsedAttributesWithRange &attrs,
Decl **OwnedType) {
assert(Tok.is(tok::kw_using) && "Not using token");
-
+ ObjCDeclContextSwitch ObjCDC(*this);
+
// Eat 'using'.
SourceLocation UsingLoc = ConsumeToken();
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteUsing(getCurScope());
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return 0;
}
// 'using namespace' means this is a using-directive.
@@ -344,7 +351,7 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
ProhibitAttributes(attrs);
return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd,
- AS_none, OwnedType);
+ AS_none, OwnedType);
}
/// ParseUsingDirective - Parse C++ using-directive, assumes
@@ -368,7 +375,8 @@ Decl *Parser::ParseUsingDirective(unsigned Context,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteUsingDirective(getCurScope());
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return 0;
}
CXXScopeSpec SS;
@@ -514,7 +522,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
TypeAlias = ParseTypeName(0, TemplateInfo.Kind ?
Declarator::AliasTemplateContext :
- Declarator::AliasDeclContext, 0, AS, OwnedType);
+ Declarator::AliasDeclContext, AS, OwnedType);
} else
// Parse (optional) attributes (most likely GNU strong-using extension).
MaybeParseGNUAttributes(attrs);
@@ -540,6 +548,15 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
return 0;
}
+ // "typename" keyword is allowed for identifiers only,
+ // because it may be a type definition.
+ if (IsTypeName && Name.getKind() != UnqualifiedId::IK_Identifier) {
+ Diag(Name.getSourceRange().getBegin(), diag::err_typename_identifiers_only)
+ << FixItHint::CreateRemoval(SourceRange(TypenameLoc));
+ // Proceed parsing, but reset the IsTypeName flag.
+ IsTypeName = false;
+ }
+
if (IsAliasDecl) {
TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
MultiTemplateParamsArg TemplateParamsArg(Actions,
@@ -571,13 +588,12 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
SourceLocation StaticAssertLoc = ConsumeToken();
- if (Tok.isNot(tok::l_paren)) {
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.consumeOpen()) {
Diag(Tok, diag::err_expected_lparen);
return 0;
}
- SourceLocation LParenLoc = ConsumeParen();
-
ExprResult AssertExpr(ParseConstantExpression());
if (AssertExpr.isInvalid()) {
SkipUntil(tok::semi);
@@ -597,7 +613,7 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
if (AssertMessage.isInvalid())
return 0;
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ T.consumeClose();
DeclEnd = Tok.getLocation();
ExpectAndConsumeSemi(diag::err_expected_semi_after_static_assert);
@@ -605,7 +621,7 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc,
AssertExpr.take(),
AssertMessage.take(),
- RParenLoc);
+ T.getCloseLocation());
}
/// ParseDecltypeSpecifier - Parse a C++0x decltype specifier.
@@ -616,11 +632,9 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
assert(Tok.is(tok::kw_decltype) && "Not a decltype specifier");
SourceLocation StartLoc = ConsumeToken();
- SourceLocation LParenLoc = Tok.getLocation();
-
- if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
- "decltype")) {
- SkipUntil(tok::r_paren);
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ "decltype", tok::r_paren)) {
return;
}
@@ -637,13 +651,8 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
}
// Match the ')'
- SourceLocation RParenLoc;
- if (Tok.is(tok::r_paren))
- RParenLoc = ConsumeParen();
- else
- MatchRHSPunctuation(tok::r_paren, LParenLoc);
-
- if (RParenLoc.isInvalid())
+ T.consumeClose();
+ if (T.getCloseLocation().isInvalid())
return;
const char *PrevSpec = 0;
@@ -659,11 +668,9 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
"Not an underlying type specifier");
SourceLocation StartLoc = ConsumeToken();
- SourceLocation LParenLoc = Tok.getLocation();
-
- if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
- "__underlying_type")) {
- SkipUntil(tok::r_paren);
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ "__underlying_type", tok::r_paren)) {
return;
}
@@ -674,13 +681,8 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
}
// Match the ')'
- SourceLocation RParenLoc;
- if (Tok.is(tok::r_paren))
- RParenLoc = ConsumeParen();
- else
- MatchRHSPunctuation(tok::r_paren, LParenLoc);
-
- if (RParenLoc.isInvalid())
+ T.consumeClose();
+ if (T.getCloseLocation().isInvalid())
return;
const char *PrevSpec = 0;
@@ -851,7 +853,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (Tok.is(tok::code_completion)) {
// Code completion for a struct, class, or union name.
Actions.CodeCompleteTag(getCurScope(), TagType);
- ConsumeCodeCompletionToken();
+ return cutOffParsing();
}
// C++03 [temp.explicit] 14.7.2/8:
@@ -901,7 +903,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
Tok.is(tok::kw___is_signed) ||
Tok.is(tok::kw___is_unsigned) ||
Tok.is(tok::kw___is_void))) {
- // GNU libstdc++ 4.2 and libc++ uaw certain intrinsic names as the
+ // GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the
// name of struct templates, but some are keywords in GCC >= 4.3
// and Clang. Therefore, when we see the token sequence "struct
// X", make X into a normal identifier rather than a keyword, to
@@ -1136,7 +1138,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Build the class template specialization.
TagOrTempResult
= Actions.ActOnClassTemplateSpecialization(getCurScope(), TagType, TUK,
- StartLoc, SS,
+ StartLoc, DS.getModulePrivateSpecLoc(), SS,
TemplateId->Template,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
@@ -1188,6 +1190,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Declaration or definition of a class type
TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc,
SS, Name, NameLoc, attrs.getList(), AS,
+ DS.getModulePrivateSpecLoc(),
TParams, Owned, IsDependent, false,
false, clang::TypeResult());
@@ -1264,7 +1267,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
case tok::kw_typedef: // struct foo {...} typedef x;
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_mutable: // struct foo {...} mutable 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,
// almost no one actually writes code like this. If we see one of these,
@@ -1321,7 +1325,7 @@ void Parser::ParseBaseClause(Decl *ClassDecl) {
ConsumeToken();
// Build up an array of parsed base specifiers.
- llvm::SmallVector<CXXBaseSpecifier *, 8> BaseInfo;
+ SmallVector<CXXBaseSpecifier *, 8> BaseInfo;
while (true) {
// Parse a base-specifier.
@@ -1565,7 +1569,6 @@ bool Parser::isCXX0XFinalKeyword() const {
/// virt-specifier:
/// override
/// final
-/// new
///
/// pure-specifier:
/// '= 0'
@@ -1574,6 +1577,7 @@ bool Parser::isCXX0XFinalKeyword() const {
/// '=' constant-expression
///
void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
+ AttributeList *AccessAttrs,
const ParsedTemplateInfo &TemplateInfo,
ParsingDeclRAIIObject *TemplateDiags) {
if (Tok.is(tok::at)) {
@@ -1640,7 +1644,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
"Nested template improperly parsed?");
SourceLocation DeclEnd;
ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd,
- AS);
+ AS, AccessAttrs);
return;
}
@@ -1649,7 +1653,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// __extension__ silences extension warnings in the subexpression.
ExtensionRAIIObject O(Diags); // Use RAII to do this.
ConsumeToken();
- return ParseCXXClassMemberDeclaration(AS, TemplateInfo, TemplateDiags);
+ return ParseCXXClassMemberDeclaration(AS, AccessAttrs,
+ TemplateInfo, TemplateDiags);
}
// Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it
@@ -1699,7 +1704,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext);
VirtSpecifiers VS;
- ExprResult Init;
+
+ // Hold late-parsed attributes so we can attach a Decl to them later.
+ LateParsedAttrList LateParsedAttrs;
if (Tok.isNot(tok::colon)) {
// Don't parse FOO:BAR as if it were a typo for FOO::BAR.
@@ -1719,11 +1726,12 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
ParseOptionalCXX0XVirtSpecifierSeq(VS);
// If attributes exist after the declarator, but before an '{', parse them.
- MaybeParseGNUAttributes(DeclaratorInfo);
+ MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
// MSVC permits pure specifier on inline functions declared at class scope.
// Hence check for =0 before checking for function definition.
- if (getLang().Microsoft && Tok.is(tok::equal) &&
+ ExprResult Init;
+ if (getLang().MicrosoftExt && Tok.is(tok::equal) &&
DeclaratorInfo.isFunctionDeclarator() &&
NextToken().is(tok::numeric_constant)) {
ConsumeToken();
@@ -1776,7 +1784,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return;
}
- ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS, Init);
+ Decl *FunDecl =
+ ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo, TemplateInfo,
+ VS, Init);
+
+ for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) {
+ LateParsedAttrs[i]->setDecl(FunDecl);
+ }
+ LateParsedAttrs.clear();
// Consume the ';' - it's optional unless we have a delete or default
if (Tok.is(tok::semi)) {
@@ -1791,7 +1806,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// member-declarator
// member-declarator-list ',' member-declarator
- llvm::SmallVector<Decl *, 8> DeclsInGroup;
+ SmallVector<Decl *, 8> DeclsInGroup;
ExprResult BitfieldSize;
while (1) {
@@ -1818,31 +1833,25 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
}
// If attributes exist after the declarator, parse them.
- MaybeParseGNUAttributes(DeclaratorInfo);
+ MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
// 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);
+ bool HasInitializer = false;
bool HasDeferredInitializer = false;
if (Tok.is(tok::equal) || Tok.is(tok::l_brace)) {
if (BitfieldSize.get()) {
Diag(Tok, diag::err_bitfield_member_init);
SkipUntil(tok::comma, true, true);
} else {
+ HasInitializer = true;
HasDeferredInitializer = !DeclaratorInfo.isDeclarationOfFunction() &&
DeclaratorInfo.getDeclSpec().getStorageClassSpec()
!= DeclSpec::SCS_static &&
DeclaratorInfo.getDeclSpec().getStorageClassSpec()
!= DeclSpec::SCS_typedef;
-
- if (!HasDeferredInitializer) {
- SourceLocation EqualLoc;
- Init = ParseCXXMemberInitializer(
- DeclaratorInfo.isDeclarationOfFunction(), EqualLoc);
- if (Init.isInvalid())
- SkipUntil(tok::comma, true, true);
- }
}
}
@@ -1854,32 +1863,30 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (DS.isFriendSpecified()) {
// TODO: handle initializers, bitfields, 'delete'
ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo,
- /*IsDefinition*/ false,
move(TemplateParams));
} else {
ThisDecl = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS,
DeclaratorInfo,
move(TemplateParams),
BitfieldSize.release(),
- VS, Init.release(),
- HasDeferredInitializer,
- /*IsDefinition*/ false);
+ VS, HasDeferredInitializer);
+ if (AccessAttrs)
+ Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs,
+ false, true);
}
- if (ThisDecl)
- DeclsInGroup.push_back(ThisDecl);
-
- if (DeclaratorInfo.isFunctionDeclarator() &&
- DeclaratorInfo.getDeclSpec().getStorageClassSpec()
- != DeclSpec::SCS_typedef) {
- HandleMemberFunctionDefaultArgs(DeclaratorInfo, ThisDecl);
+
+ // Set the Decl for any late parsed attributes
+ for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) {
+ LateParsedAttrs[i]->setDecl(ThisDecl);
}
+ LateParsedAttrs.clear();
- DeclaratorInfo.complete(ThisDecl);
-
+ // Handle the initializer.
if (HasDeferredInitializer) {
+ // The initializer was deferred; parse it and cache the tokens.
if (!getLang().CPlusPlus0x)
Diag(Tok, diag::warn_nonstatic_member_init_accepted_as_extension);
-
+
if (DeclaratorInfo.isArrayOfUnknownBound()) {
// C++0x [dcl.array]p3: An array bound may also be omitted when the
// declarator is followed by an initializer.
@@ -1892,8 +1899,36 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
ThisDecl->setInvalidDecl();
} else
ParseCXXNonStaticMemberInitializer(ThisDecl);
+ } else if (HasInitializer) {
+ // Normal initializer.
+ SourceLocation EqualLoc;
+ ExprResult Init
+ = ParseCXXMemberInitializer(DeclaratorInfo.isDeclarationOfFunction(),
+ EqualLoc);
+ if (Init.isInvalid())
+ SkipUntil(tok::comma, true, true);
+ else if (ThisDecl)
+ Actions.AddInitializerToDecl(ThisDecl, Init.get(), false,
+ DS.getTypeSpecType() == DeclSpec::TST_auto);
+ } else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static) {
+ // No initializer.
+ Actions.ActOnUninitializedDecl(ThisDecl,
+ DS.getTypeSpecType() == DeclSpec::TST_auto);
+ }
+
+ if (ThisDecl) {
+ Actions.FinalizeDeclaration(ThisDecl);
+ DeclsInGroup.push_back(ThisDecl);
+ }
+
+ if (DeclaratorInfo.isFunctionDeclarator() &&
+ DeclaratorInfo.getDeclSpec().getStorageClassSpec()
+ != DeclSpec::SCS_typedef) {
+ HandleMemberFunctionDefaultArgs(DeclaratorInfo, ThisDecl);
}
+ DeclaratorInfo.complete(ThisDecl);
+
// If we don't have a comma, it is either the end of the list (a ';')
// or an error, bail out.
if (Tok.isNot(tok::comma))
@@ -1905,8 +1940,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// Parse the next declarator.
DeclaratorInfo.clear();
VS.clear();
- BitfieldSize = 0;
- Init = 0;
+ BitfieldSize = true;
// Attributes are only allowed on the second declarator.
MaybeParseGNUAttributes(DeclaratorInfo);
@@ -1973,7 +2007,6 @@ ExprResult Parser::ParseCXXMemberInitializer(bool IsFunction,
return ExprResult();
}
} else if (Tok.is(tok::kw_default)) {
- Diag(ConsumeToken(), diag::err_default_special_members);
if (IsFunction)
Diag(Tok, diag::err_default_delete_in_multiple_declaration)
<< 0 /* default */;
@@ -2067,12 +2100,12 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
}
assert(Tok.is(tok::l_brace));
-
- SourceLocation LBraceLoc = ConsumeBrace();
+ BalancedDelimiterTracker T(*this, tok::l_brace);
+ T.consumeOpen();
if (TagDecl)
Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, FinalLoc,
- LBraceLoc);
+ T.getOpenLocation());
// C++ 11p3: Members of a class defined with the keyword class are private
// by default. Members of a class defined with the keywords struct or union
@@ -2082,14 +2115,14 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
CurAS = AS_private;
else
CurAS = AS_public;
+ ParsedAttributes AccessAttrs(AttrFactory);
- SourceLocation RBraceLoc;
if (TagDecl) {
// While we still have something to read, read the member-declarations.
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
// Each iteration of this loop reads one member-declaration.
- if (getLang().Microsoft && (Tok.is(tok::kw___if_exists) ||
+ if (getLang().MicrosoftExt && (Tok.is(tok::kw___if_exists) ||
Tok.is(tok::kw___if_not_exists))) {
ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS);
continue;
@@ -2109,22 +2142,41 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
// Current token is a C++ access specifier.
CurAS = AS;
SourceLocation ASLoc = Tok.getLocation();
+ unsigned TokLength = Tok.getLength();
ConsumeToken();
- if (Tok.is(tok::colon))
- Actions.ActOnAccessSpecifier(AS, ASLoc, Tok.getLocation());
- else
- Diag(Tok, diag::err_expected_colon);
- ConsumeToken();
+ AccessAttrs.clear();
+ MaybeParseGNUAttributes(AccessAttrs);
+
+ SourceLocation EndLoc;
+ if (Tok.is(tok::colon)) {
+ EndLoc = Tok.getLocation();
+ if (Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc,
+ AccessAttrs.getList())) {
+ // found another attribute than only annotations
+ AccessAttrs.clear();
+ }
+ ConsumeToken();
+ } else if (Tok.is(tok::semi)) {
+ EndLoc = Tok.getLocation();
+ ConsumeToken();
+ Diag(EndLoc, diag::err_expected_colon)
+ << FixItHint::CreateReplacement(EndLoc, ":");
+ } else {
+ EndLoc = ASLoc.getLocWithOffset(TokLength);
+ Diag(EndLoc, diag::err_expected_colon)
+ << FixItHint::CreateInsertion(EndLoc, ":");
+ }
+ Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc);
continue;
}
// FIXME: Make sure we don't have a template here.
// Parse all the comma separated declarators.
- ParseCXXClassMemberDeclaration(CurAS);
+ ParseCXXClassMemberDeclaration(CurAS, AccessAttrs.getList());
}
- RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
+ T.consumeClose();
} else {
SkipUntil(tok::r_brace, false, false);
}
@@ -2135,7 +2187,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
if (TagDecl)
Actions.ActOnFinishCXXMemberSpecification(getCurScope(), RecordLoc, TagDecl,
- LBraceLoc, RBraceLoc,
+ T.getOpenLocation(),
+ T.getCloseLocation(),
attrs.getList());
// C++0x [class.mem]p2: Within the class member-specification, the class is
@@ -2148,8 +2201,10 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
if (TagDecl && NonNestedClass) {
// We are not inside a nested class. This class and its nested classes
// are complete and we can parse the delayed portions of method
- // declarations and the lexed inline method definitions.
+ // declarations and the lexed inline method definitions, along with any
+ // delayed attributes.
SourceLocation SavedPrevTokLocation = PrevTokLocation;
+ ParseLexedAttributes(getCurrentClass());
ParseLexedMethodDeclarations(getCurrentClass());
ParseLexedMemberInitializers(getCurrentClass());
ParseLexedMethodDefs(getCurrentClass());
@@ -2157,7 +2212,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
}
if (TagDecl)
- Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, RBraceLoc);
+ Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl,
+ T.getCloseLocation());
// Leave the class scope.
ParsingDef.Pop();
@@ -2192,7 +2248,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true);
SourceLocation ColonLoc = ConsumeToken();
- llvm::SmallVector<CXXCtorInitializer*, 4> MemInitializers;
+ SmallVector<CXXCtorInitializer*, 4> MemInitializers;
bool AnyErrors = false;
do {
@@ -2200,7 +2256,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
Actions.CodeCompleteConstructorInitializer(ConstructorDecl,
MemInitializers.data(),
MemInitializers.size());
- ConsumeCodeCompletionToken();
+ return cutOffParsing();
} else {
MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);
if (!MemInit.isInvalid())
@@ -2270,11 +2326,20 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
// Parse the '('.
if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) {
- // FIXME: Do something with the braced-init-list.
- ParseBraceInitializer();
- return true;
+ ExprResult InitList = ParseBraceInitializer();
+ if (InitList.isInvalid())
+ return true;
+
+ SourceLocation EllipsisLoc;
+ if (Tok.is(tok::ellipsis))
+ EllipsisLoc = ConsumeToken();
+
+ return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
+ TemplateTypeTy, IdLoc, InitList.take(),
+ EllipsisLoc);
} else if(Tok.is(tok::l_paren)) {
- SourceLocation LParenLoc = ConsumeParen();
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
// Parse the optional expression-list.
ExprVector ArgExprs(Actions);
@@ -2284,7 +2349,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
return true;
}
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ T.consumeClose();
SourceLocation EllipsisLoc;
if (Tok.is(tok::ellipsis))
@@ -2292,8 +2357,8 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
TemplateTypeTy, IdLoc,
- LParenLoc, ArgExprs.take(),
- ArgExprs.size(), RParenLoc,
+ T.getOpenLocation(), ArgExprs.take(),
+ ArgExprs.size(), T.getCloseLocation(),
EllipsisLoc);
}
@@ -2313,8 +2378,8 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
/// 'noexcept' '(' constant-expression ')'
ExceptionSpecificationType
Parser::MaybeParseExceptionSpecification(SourceRange &SpecificationRange,
- llvm::SmallVectorImpl<ParsedType> &DynamicExceptions,
- llvm::SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
+ SmallVectorImpl<ParsedType> &DynamicExceptions,
+ SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
ExprResult &NoexceptExpr) {
ExceptionSpecificationType Result = EST_None;
@@ -2339,7 +2404,8 @@ Parser::MaybeParseExceptionSpecification(SourceRange &SpecificationRange,
SourceLocation KeywordLoc = ConsumeToken();
if (Tok.is(tok::l_paren)) {
// There is an argument.
- SourceLocation LParenLoc = ConsumeParen();
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
NoexceptType = EST_ComputedNoexcept;
NoexceptExpr = ParseConstantExpression();
// The argument must be contextually convertible to bool. We use
@@ -2347,8 +2413,8 @@ Parser::MaybeParseExceptionSpecification(SourceRange &SpecificationRange,
if (!NoexceptExpr.isInvalid())
NoexceptExpr = Actions.ActOnBooleanCondition(getCurScope(), KeywordLoc,
NoexceptExpr.get());
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
- NoexceptRange = SourceRange(KeywordLoc, RParenLoc);
+ T.consumeClose();
+ NoexceptRange = SourceRange(KeywordLoc, T.getCloseLocation());
} else {
// There is no argument.
NoexceptType = EST_BasicNoexcept;
@@ -2386,27 +2452,26 @@ Parser::MaybeParseExceptionSpecification(SourceRange &SpecificationRange,
///
ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification(
SourceRange &SpecificationRange,
- llvm::SmallVectorImpl<ParsedType> &Exceptions,
- llvm::SmallVectorImpl<SourceRange> &Ranges) {
+ SmallVectorImpl<ParsedType> &Exceptions,
+ SmallVectorImpl<SourceRange> &Ranges) {
assert(Tok.is(tok::kw_throw) && "expected throw");
SpecificationRange.setBegin(ConsumeToken());
-
- if (!Tok.is(tok::l_paren)) {
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.consumeOpen()) {
Diag(Tok, diag::err_expected_lparen_after) << "throw";
SpecificationRange.setEnd(SpecificationRange.getBegin());
return EST_DynamicNone;
}
- SourceLocation LParenLoc = ConsumeParen();
// Parse throw(...), a Microsoft extension that means "this function
// can throw anything".
if (Tok.is(tok::ellipsis)) {
SourceLocation EllipsisLoc = ConsumeToken();
- if (!getLang().Microsoft)
+ if (!getLang().MicrosoftExt)
Diag(EllipsisLoc, diag::ext_ellipsis_exception_spec);
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
- SpecificationRange.setEnd(RParenLoc);
+ T.consumeClose();
+ SpecificationRange.setEnd(T.getCloseLocation());
return EST_MSAny;
}
@@ -2436,13 +2501,14 @@ ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification(
break;
}
- SpecificationRange.setEnd(MatchRHSPunctuation(tok::r_paren, LParenLoc));
+ T.consumeClose();
+ SpecificationRange.setEnd(T.getCloseLocation());
return Exceptions.empty() ? EST_DynamicNone : EST_Dynamic;
}
/// ParseTrailingReturnType - Parse a trailing return type on a new-style
/// function declaration.
-TypeResult Parser::ParseTrailingReturnType() {
+TypeResult Parser::ParseTrailingReturnType(SourceRange &Range) {
assert(Tok.is(tok::arrow) && "expected arrow");
ConsumeToken();
@@ -2454,8 +2520,6 @@ TypeResult Parser::ParseTrailingReturnType() {
//
// struct X is parsed as class definition because of the trailing
// brace.
-
- SourceRange Range;
return ParseTypeName(&Range);
}
@@ -2519,11 +2583,12 @@ void Parser::PopParsingClass(Sema::ParsingClassState state) {
Victim->TemplateScope = getCurScope()->getParent()->isTemplateParamScope();
}
-/// ParseCXX0XAttributes - Parse a C++0x attribute-specifier. Currently only
-/// parses standard attributes.
+/// ParseCXX0XAttributeSpecifier - Parse a C++0x attribute-specifier. Currently
+/// only parses standard attributes.
///
/// [C++0x] attribute-specifier:
/// '[' '[' attribute-list ']' ']'
+/// alignment-specifier
///
/// [C++0x] attribute-list:
/// attribute[opt]
@@ -2554,12 +2619,18 @@ void Parser::PopParsingClass(Sema::ParsingClassState state) {
/// '[' balanced-token-seq ']'
/// '{' balanced-token-seq '}'
/// any token but '(', ')', '[', ']', '{', or '}'
-void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs,
- SourceLocation *endLoc) {
+void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs,
+ SourceLocation *endLoc) {
+ if (Tok.is(tok::kw_alignas)) {
+ Diag(Tok.getLocation(), diag::warn_cxx98_compat_alignas);
+ ParseAlignmentSpecifier(attrs, endLoc);
+ return;
+ }
+
assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square)
&& "Not a C++0x attribute list");
- SourceLocation StartLoc = Tok.getLocation(), Loc;
+ Diag(Tok.getLocation(), diag::warn_cxx98_compat_attribute);
ConsumeBracket();
ConsumeBracket();
@@ -2617,29 +2688,6 @@ void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs,
break;
}
- // One argument; must be a type-id or assignment-expression
- case AttributeList::AT_aligned: {
- if (Tok.isNot(tok::l_paren)) {
- Diag(Tok.getLocation(), diag::err_cxx0x_attribute_requires_arguments)
- << AttrName->getName();
- break;
- }
- SourceLocation ParamLoc = ConsumeParen();
-
- ExprResult ArgExpr = ParseCXX0XAlignArgument(ParamLoc);
-
- MatchRHSPunctuation(tok::r_paren, ParamLoc);
-
- ExprVector ArgExprs(Actions);
- ArgExprs.push_back(ArgExpr.release());
- attrs.addNew(AttrName, AttrLoc, 0, AttrLoc,
- 0, ParamLoc, ArgExprs.take(), 1,
- false, true);
-
- AttrParsed = true;
- break;
- }
-
// Silence warnings
default: break;
}
@@ -2655,31 +2703,27 @@ void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs,
if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare))
SkipUntil(tok::r_square, false);
- Loc = Tok.getLocation();
+ if (endLoc)
+ *endLoc = Tok.getLocation();
if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare))
SkipUntil(tok::r_square, false);
-
- attrs.Range = SourceRange(StartLoc, Loc);
}
-/// ParseCXX0XAlignArgument - Parse the argument to C++0x's [[align]]
-/// attribute.
-///
-/// FIXME: Simply returns an alignof() expression if the argument is a
-/// type. Ideally, the type should be propagated directly into Sema.
-///
-/// [C++0x] 'align' '(' type-id ')'
-/// [C++0x] 'align' '(' assignment-expression ')'
-ExprResult Parser::ParseCXX0XAlignArgument(SourceLocation Start) {
- if (isTypeIdInParens()) {
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
- SourceLocation TypeLoc = Tok.getLocation();
- ParsedType Ty = ParseTypeName().get();
- SourceRange TypeRange(Start, Tok.getLocation());
- return Actions.ActOnUnaryExprOrTypeTraitExpr(TypeLoc, UETT_AlignOf, true,
- Ty.getAsOpaquePtr(), TypeRange);
- } else
- return ParseConstantExpression();
+/// ParseCXX0XAttributes - Parse a C++0x attribute-specifier-seq.
+///
+/// attribute-specifier-seq:
+/// attribute-specifier-seq[opt] attribute-specifier
+void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs,
+ SourceLocation *endLoc) {
+ SourceLocation StartLoc = Tok.getLocation(), Loc;
+ if (!endLoc)
+ endLoc = &Loc;
+
+ do {
+ ParseCXX0XAttributeSpecifier(attrs, endLoc);
+ } while (isCXX0XAttributeSpecifier());
+
+ attrs.Range = SourceRange(StartLoc, *endLoc);
}
/// ParseMicrosoftAttributes - Parse a Microsoft attribute [Attr]
@@ -2753,7 +2797,7 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType,
}
// Parse all the comma separated declarators.
- ParseCXXClassMemberDeclaration(CurAS);
+ ParseCXXClassMemberDeclaration(CurAS, 0);
}
if (Tok.isNot(tok::r_brace)) {
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index fc64ae022654..bc8bbf564005 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -214,7 +214,8 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
ExprResult Parser::ParseAssignmentExpression() {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression);
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return ExprError();
}
if (Tok.is(tok::kw_throw))
@@ -303,23 +304,23 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
// Eat the colon.
ColonLoc = ConsumeToken();
} else {
- // Otherwise, we're missing a ':'. Assume that this was a typo that the
- // user forgot. If we're not in a macro instantiation, we can suggest a
- // fixit hint. If there were two spaces before the current token,
+ // Otherwise, we're missing a ':'. Assume that this was a typo that
+ // the user forgot. If we're not in a macro expansion, we can suggest
+ // a fixit hint. If there were two spaces before the current token,
// suggest inserting the colon in between them, otherwise insert ": ".
SourceLocation FILoc = Tok.getLocation();
const char *FIText = ": ";
const SourceManager &SM = PP.getSourceManager();
if (FILoc.isFileID() || PP.isAtStartOfMacroExpansion(FILoc)) {
- FILoc = SM.getInstantiationLoc(FILoc);
+ FILoc = SM.getExpansionLoc(FILoc);
bool IsInvalid = false;
const char *SourcePtr =
- SM.getCharacterData(FILoc.getFileLocWithOffset(-1), &IsInvalid);
+ SM.getCharacterData(FILoc.getLocWithOffset(-1), &IsInvalid);
if (!IsInvalid && *SourcePtr == ' ') {
SourcePtr =
- SM.getCharacterData(FILoc.getFileLocWithOffset(-2), &IsInvalid);
+ SM.getCharacterData(FILoc.getLocWithOffset(-2), &IsInvalid);
if (!IsInvalid && *SourcePtr == ' ') {
- FILoc = FILoc.getFileLocWithOffset(-1);
+ FILoc = FILoc.getLocWithOffset(-1);
FIText = ":";
}
}
@@ -336,7 +337,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
// goes through a special hook that takes the left-hand side into account.
if (Tok.is(tok::code_completion) && NextTokPrec == prec::Assignment) {
Actions.CodeCompleteAssignmentRHS(getCurScope(), LHS.get());
- ConsumeCodeCompletionToken();
+ cutOffParsing();
return ExprError();
}
@@ -769,6 +770,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
break;
}
case tok::char_constant: // constant: character-constant
+ case tok::wide_char_constant:
+ case tok::utf16_char_constant:
+ case tok::utf32_char_constant:
Res = Actions.ActOnCharacterConstant(Tok);
ConsumeToken();
break;
@@ -780,6 +784,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
break;
case tok::string_literal: // primary-expression: string-literal
case tok::wide_string_literal:
+ case tok::utf8_string_literal:
+ case tok::utf16_string_literal:
+ case tok::utf32_string_literal:
Res = ParseStringLiteralExpression();
break;
case tok::kw__Generic: // primary-expression: generic-selection [C1X 6.5.1]
@@ -913,6 +920,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___int64:
case tok::kw_signed:
case tok::kw_unsigned:
+ case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
case tok::kw_void:
@@ -1021,18 +1029,21 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw_noexcept: { // [C++0x] 'noexcept' '(' expression ')'
SourceLocation KeyLoc = ConsumeToken();
- SourceLocation LParen = Tok.getLocation();
- if (ExpectAndConsume(tok::l_paren,
- diag::err_expected_lparen_after, "noexcept"))
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+
+ if (T.expectAndConsume(diag::err_expected_lparen_after, "noexcept"))
return ExprError();
// C++ [expr.unary.noexcept]p1:
// The noexcept operator determines whether the evaluation of its operand,
// which is an unevaluated operand, can throw an exception.
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
ExprResult Result = ParseExpression();
- SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen);
+
+ T.consumeClose();
+
if (!Result.isInvalid())
- Result = Actions.ActOnNoexceptExpr(KeyLoc, LParen, Result.take(), RParen);
+ Result = Actions.ActOnNoexceptExpr(KeyLoc, T.getOpenLocation(),
+ Result.take(), T.getCloseLocation());
return move(Result);
}
@@ -1104,11 +1115,20 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
break;
case tok::code_completion: {
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression);
- ConsumeCodeCompletionToken();
- return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
- NotCastExpr, isTypeCast);
+ cutOffParsing();
+ return ExprError();
}
case tok::l_square:
+ if (getLang().CPlusPlus0x) {
+ if (getLang().ObjC1) {
+ Res = TryParseLambdaExpression();
+ if (Res.isInvalid())
+ Res = ParseObjCMessageExpression();
+ break;
+ }
+ Res = ParseLambdaExpression();
+ break;
+ }
if (getLang().ObjC1) {
Res = ParseObjCMessageExpression();
break;
@@ -1154,9 +1174,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
return move(LHS);
Actions.CodeCompletePostfixExpression(getCurScope(), LHS);
- ConsumeCodeCompletionToken();
- LHS = ExprError();
- break;
+ cutOffParsing();
+ return ExprError();
case tok::identifier:
// If we see identifier: after an expression, and we're not already in a
@@ -1183,8 +1202,10 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (getLang().ObjC1 && Tok.isAtStartOfLine() &&
isSimpleObjCMessageExpression())
return move(LHS);
-
- Loc = ConsumeBracket();
+
+ BalancedDelimiterTracker T(*this, tok::l_square);
+ T.consumeOpen();
+ Loc = T.getOpenLocation();
ExprResult Idx;
if (getLang().CPlusPlus0x && Tok.is(tok::l_brace))
Idx = ParseBraceInitializer();
@@ -1200,7 +1221,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
LHS = ExprError();
// Match the ']'.
- MatchRHSPunctuation(tok::r_square, Loc);
+ T.consumeClose();
break;
}
@@ -1212,12 +1233,13 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
Expr *ExecConfig = 0;
+ BalancedDelimiterTracker LLLT(*this, tok::lesslessless);
+ BalancedDelimiterTracker PT(*this, tok::l_paren);
+
if (OpKind == tok::lesslessless) {
ExprVector ExecConfigExprs(Actions);
CommaLocsTy ExecConfigCommaLocs;
- SourceLocation LLLLoc, GGGLoc;
-
- LLLLoc = ConsumeToken();
+ LLLT.consumeOpen();
if (ParseExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) {
LHS = ExprError();
@@ -1225,11 +1247,9 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (LHS.isInvalid()) {
SkipUntil(tok::greatergreatergreater);
- } else if (Tok.isNot(tok::greatergreatergreater)) {
- MatchRHSPunctuation(tok::greatergreatergreater, LLLLoc);
+ } else if (LLLT.consumeClose()) {
+ // There was an error closing the brackets
LHS = ExprError();
- } else {
- GGGLoc = ConsumeToken();
}
if (!LHS.isInvalid()) {
@@ -1241,14 +1261,17 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (!LHS.isInvalid()) {
ExprResult ECResult = Actions.ActOnCUDAExecConfigExpr(getCurScope(),
- LLLLoc, move_arg(ExecConfigExprs), GGGLoc);
+ LLLT.getOpenLocation(),
+ move_arg(ExecConfigExprs),
+ LLLT.getCloseLocation());
if (ECResult.isInvalid())
LHS = ExprError();
else
ExecConfig = ECResult.get();
}
} else {
- Loc = ConsumeParen();
+ PT.consumeOpen();
+ Loc = PT.getOpenLocation();
}
ExprVector ArgExprs(Actions);
@@ -1256,7 +1279,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteCall(getCurScope(), LHS.get(), 0, 0);
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return ExprError();
}
if (OpKind == tok::l_paren || !LHS.isInvalid()) {
@@ -1272,7 +1296,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (LHS.isInvalid()) {
SkipUntil(tok::r_paren);
} else if (Tok.isNot(tok::r_paren)) {
- MatchRHSPunctuation(tok::r_paren, Loc);
+ PT.consumeClose();
LHS = ExprError();
} else {
assert((ArgExprs.size() == 0 ||
@@ -1281,7 +1305,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
LHS = Actions.ActOnCallExpr(getCurScope(), LHS.take(), Loc,
move_arg(ArgExprs), Tok.getLocation(),
ExecConfig);
- ConsumeParen();
+ PT.consumeClose();
}
break;
@@ -1314,7 +1338,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
Actions.CodeCompleteMemberReferenceExpr(getCurScope(), LHS.get(),
OpLoc, OpKind == tok::arrow);
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return ExprError();
}
if (MayBePseudoDestructor && !LHS.isInvalid()) {
@@ -1334,7 +1359,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (ParseUnqualifiedId(SS,
/*EnteringContext=*/false,
/*AllowDestructorName=*/true,
- /*AllowConstructorName=*/ getLang().Microsoft,
+ /*AllowConstructorName=*/ getLang().MicrosoftExt,
ObjectType,
Name))
LHS = ExprError();
@@ -1473,11 +1498,14 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
IdentifierInfo *Name = 0;
SourceLocation NameLoc;
if (Tok.is(tok::l_paren)) {
- LParenLoc = ConsumeParen();
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
+ LParenLoc = T.getOpenLocation();
if (Tok.is(tok::identifier)) {
Name = Tok.getIdentifierInfo();
NameLoc = ConsumeToken();
- RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ T.consumeClose();
+ RParenLoc = T.getCloseLocation();
if (RParenLoc.isInvalid())
RParenLoc = PP.getLocForEndOfToken(NameLoc);
} else {
@@ -1564,11 +1592,13 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
return ExprError(Diag(Tok, diag::err_expected_lparen_after_id)
<< BuiltinII);
- SourceLocation LParenLoc = ConsumeParen();
+ BalancedDelimiterTracker PT(*this, tok::l_paren);
+ PT.consumeOpen();
+
// TODO: Build AST.
switch (T) {
- default: assert(0 && "Not a builtin primary expression!");
+ default: llvm_unreachable("Not a builtin primary expression!");
case tok::kw___builtin_va_arg: {
ExprResult Expr(ParseAssignmentExpression());
@@ -1607,7 +1637,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
}
// Keep track of the various subcomponents we see.
- llvm::SmallVector<Sema::OffsetOfComponent, 4> Comps;
+ SmallVector<Sema::OffsetOfComponent, 4> Comps;
Comps.push_back(Sema::OffsetOfComponent());
Comps.back().isBrackets = false;
@@ -1634,7 +1664,9 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
// offsetof-member-designator: offsetof-member-design '[' expression ']'
Comps.push_back(Sema::OffsetOfComponent());
Comps.back().isBrackets = true;
- Comps.back().LocStart = ConsumeBracket();
+ BalancedDelimiterTracker ST(*this, tok::l_square);
+ ST.consumeOpen();
+ Comps.back().LocStart = ST.getOpenLocation();
Res = ParseExpression();
if (Res.isInvalid()) {
SkipUntil(tok::r_paren);
@@ -1642,18 +1674,19 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
}
Comps.back().U.E = Res.release();
- Comps.back().LocEnd =
- MatchRHSPunctuation(tok::r_square, Comps.back().LocStart);
+ ST.consumeClose();
+ Comps.back().LocEnd = ST.getCloseLocation();
} else {
if (Tok.isNot(tok::r_paren)) {
- MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ PT.consumeClose();
Res = ExprError();
} else if (Ty.isInvalid()) {
Res = ExprError();
} else {
+ PT.consumeClose();
Res = Actions.ActOnBuiltinOffsetOf(getCurScope(), StartLoc, TypeLoc,
- Ty.get(), &Comps[0],
- Comps.size(), ConsumeParen());
+ Ty.get(), &Comps[0], Comps.size(),
+ PT.getCloseLocation());
}
break;
}
@@ -1753,7 +1786,11 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
SourceLocation &RParenLoc) {
assert(Tok.is(tok::l_paren) && "Not a paren expr!");
GreaterThanIsOperatorScope G(GreaterThanIsOperator, true);
- SourceLocation OpenLoc = ConsumeParen();
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.consumeOpen())
+ return ExprError();
+ SourceLocation OpenLoc = T.getOpenLocation();
+
ExprResult Result(true);
bool isAmbiguousTypeId;
CastTy = ParsedType();
@@ -1762,7 +1799,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
Actions.CodeCompleteOrdinaryName(getCurScope(),
ExprType >= CompoundLiteral? Sema::PCC_ParenthesizedExpression
: Sema::PCC_Expression);
- ConsumeCodeCompletionToken();
+ cutOffParsing();
return ExprError();
}
@@ -1806,7 +1843,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
}
TypeResult Ty = ParseTypeName();
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, OpenLoc);
+ T.consumeClose();
+ RParenLoc = T.getCloseLocation();
ExprResult SubExpr = ParseCastExpression(/*isUnaryExpression=*/false);
if (Ty.isInvalid() || SubExpr.isInvalid())
@@ -1825,9 +1863,11 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
// in which case we should treat it as type-id.
// if stopIfCastExpr is false, we need to determine the context past the
// parens, so we defer to ParseCXXAmbiguousParenExpression for that.
- if (isAmbiguousTypeId && !stopIfCastExpr)
- return ParseCXXAmbiguousParenExpression(ExprType, CastTy,
- OpenLoc, RParenLoc);
+ if (isAmbiguousTypeId && !stopIfCastExpr) {
+ ExprResult res = ParseCXXAmbiguousParenExpression(ExprType, CastTy, T);
+ RParenLoc = T.getCloseLocation();
+ return res;
+ }
// Parse the type declarator.
DeclSpec DS(AttrFactory);
@@ -1851,11 +1891,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
Ty.get(), 0);
} else {
// Match the ')'.
- if (Tok.is(tok::r_paren))
- RParenLoc = ConsumeParen();
- else
- MatchRHSPunctuation(tok::r_paren, OpenLoc);
-
+ T.consumeClose();
+ RParenLoc = T.getCloseLocation();
if (Tok.is(tok::l_brace)) {
ExprType = CompoundLiteral;
TypeResult Ty;
@@ -1939,11 +1976,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
return ExprError();
}
- if (Tok.is(tok::r_paren))
- RParenLoc = ConsumeParen();
- else
- MatchRHSPunctuation(tok::r_paren, OpenLoc);
-
+ T.consumeClose();
+ RParenLoc = T.getCloseLocation();
return move(Result);
}
@@ -1978,7 +2012,7 @@ ExprResult Parser::ParseStringLiteralExpression() {
// String concat. Note that keywords like __func__ and __FUNCTION__ are not
// considered to be strings for concatenation purposes.
- llvm::SmallVector<Token, 4> StringToks;
+ SmallVector<Token, 4> StringToks;
do {
StringToks.push_back(Tok);
@@ -2007,8 +2041,8 @@ ExprResult Parser::ParseGenericSelectionExpression() {
if (!getLang().C1X)
Diag(KeyLoc, diag::ext_c1x_generic_selection);
- SourceLocation LParenLoc = Tok.getLocation();
- if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen, ""))
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.expectAndConsume(diag::err_expected_lparen))
return ExprError();
ExprResult ControllingExpr;
@@ -2074,11 +2108,12 @@ ExprResult Parser::ParseGenericSelectionExpression() {
ConsumeToken();
}
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
- if (RParenLoc.isInvalid())
+ T.consumeClose();
+ if (T.getCloseLocation().isInvalid())
return ExprError();
- return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc,
+ return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc,
+ T.getCloseLocation(),
ControllingExpr.release(),
move_arg(Types), move_arg(Exprs));
}
@@ -2104,8 +2139,8 @@ ExprResult Parser::ParseGenericSelectionExpression() {
/// [C++0x] assignment-expression
/// [C++0x] braced-init-list
///
-bool Parser::ParseExpressionList(llvm::SmallVectorImpl<Expr*> &Exprs,
- llvm::SmallVectorImpl<SourceLocation> &CommaLocs,
+bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &Exprs,
+ SmallVectorImpl<SourceLocation> &CommaLocs,
void (Sema::*Completer)(Scope *S,
Expr *Data,
Expr **Args,
@@ -2117,7 +2152,8 @@ bool Parser::ParseExpressionList(llvm::SmallVectorImpl<Expr*> &Exprs,
(Actions.*Completer)(getCurScope(), Data, Exprs.data(), Exprs.size());
else
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression);
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return true;
}
ExprResult Expr;
@@ -2148,7 +2184,7 @@ bool Parser::ParseExpressionList(llvm::SmallVectorImpl<Expr*> &Exprs,
void Parser::ParseBlockId() {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type);
- ConsumeCodeCompletionToken();
+ return cutOffParsing();
}
// Parse the specifier-qualifier-list piece.
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index b32eeda24279..60166e880c04 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -15,6 +15,7 @@
#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Scope.h"
#include "clang/Sema/ParsedTemplate.h"
#include "llvm/Support/ErrorHandling.h"
@@ -28,8 +29,7 @@ static int SelectDigraphErrorMessage(tok::TokenKind Kind) {
case tok::kw_reinterpret_cast: return 3;
case tok::kw_static_cast: return 4;
default:
- assert(0 && "Unknown type for digraph error message.");
- return -1;
+ llvm_unreachable("Unknown type for digraph error message.");
}
}
@@ -37,7 +37,7 @@ static int SelectDigraphErrorMessage(tok::TokenKind Kind) {
static bool AreTokensAdjacent(Preprocessor &PP, Token &First, Token &Second) {
SourceManager &SM = PP.getSourceManager();
SourceLocation FirstLoc = SM.getSpellingLoc(First.getLocation());
- SourceLocation FirstEnd = FirstLoc.getFileLocWithOffset(First.getLength());
+ SourceLocation FirstEnd = FirstLoc.getLocWithOffset(First.getLength());
return FirstEnd == SM.getSpellingLoc(Second.getLocation());
}
@@ -58,7 +58,7 @@ static void FixDigraph(Parser &P, Preprocessor &PP, Token &DigraphToken,
// Update token information to reflect their change in token type.
ColonToken.setKind(tok::coloncolon);
- ColonToken.setLocation(ColonToken.getLocation().getFileLocWithOffset(-1));
+ ColonToken.setLocation(ColonToken.getLocation().getLocWithOffset(-1));
ColonToken.setLength(2);
DigraphToken.setKind(tok::less);
DigraphToken.setLength(1);
@@ -69,6 +69,31 @@ static void FixDigraph(Parser &P, Preprocessor &PP, Token &DigraphToken,
PP.EnterToken(DigraphToken);
}
+// Check for '<::' which should be '< ::' instead of '[:' when following
+// a template name.
+void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType,
+ bool EnteringContext,
+ IdentifierInfo &II, CXXScopeSpec &SS) {
+ if (!Next.is(tok::l_square) || Next.getLength() != 2)
+ return;
+
+ Token SecondToken = GetLookAheadToken(2);
+ if (!SecondToken.is(tok::colon) || !AreTokensAdjacent(PP, Next, SecondToken))
+ return;
+
+ TemplateTy Template;
+ UnqualifiedId TemplateName;
+ TemplateName.setIdentifier(&II, Tok.getLocation());
+ bool MemberOfUnknownSpecialization;
+ if (!Actions.isTemplateName(getCurScope(), SS, /*hasTemplateKeyword=*/false,
+ TemplateName, ObjectType, EnteringContext,
+ Template, MemberOfUnknownSpecialization))
+ return;
+
+ FixDigraph(*this, PP, Next, SecondToken, tok::kw_template,
+ /*AtDigraph*/false);
+}
+
/// \brief Parse global scope or nested-name-specifier if present.
///
/// Parses a C++ global scope specifier ('::') or nested-name-specifier (which
@@ -161,12 +186,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// Code completion for a nested-name-specifier, where the code
// code completion token follows the '::'.
Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext);
- SourceLocation ccLoc = ConsumeCodeCompletionToken();
// Include code completion token into the range of the scope otherwise
// when we try to annotate the scope tokens the dangling code completion
// token will cause assertion in
// Preprocessor::AnnotatePreviousCachedTokens.
- SS.setEndLoc(ccLoc);
+ SS.setEndLoc(Tok.getLocation());
+ cutOffParsing();
+ return true;
}
}
@@ -339,28 +365,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
continue;
}
- // Check for '<::' which should be '< ::' instead of '[:' when following
- // a template name.
- if (Next.is(tok::l_square) && Next.getLength() == 2) {
- Token SecondToken = GetLookAheadToken(2);
- if (SecondToken.is(tok::colon) &&
- AreTokensAdjacent(PP, Next, SecondToken)) {
- TemplateTy Template;
- UnqualifiedId TemplateName;
- TemplateName.setIdentifier(&II, Tok.getLocation());
- bool MemberOfUnknownSpecialization;
- if (Actions.isTemplateName(getCurScope(), SS,
- /*hasTemplateKeyword=*/false,
- TemplateName,
- ObjectType,
- EnteringContext,
- Template,
- MemberOfUnknownSpecialization)) {
- FixDigraph(*this, PP, Next, SecondToken, tok::kw_template,
- /*AtDigraph*/false);
- }
- }
- }
+ CheckForTemplateAndDigraph(Next, ObjectType, EnteringContext, II, SS);
// nested-name-specifier:
// type-name '<'
@@ -396,7 +401,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// parse correctly as a template, so suggest the keyword 'template'
// before 'getAs' and treat this as a dependent template name.
unsigned DiagID = diag::err_missing_dependent_template_keyword;
- if (getLang().Microsoft)
+ if (getLang().MicrosoftExt)
DiagID = diag::warn_missing_dependent_template_keyword;
Diag(Tok.getLocation(), DiagID)
@@ -504,6 +509,273 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
}
+/// ParseLambdaExpression - Parse a C++0x lambda expression.
+///
+/// lambda-expression:
+/// lambda-introducer lambda-declarator[opt] compound-statement
+///
+/// lambda-introducer:
+/// '[' lambda-capture[opt] ']'
+///
+/// lambda-capture:
+/// capture-default
+/// capture-list
+/// capture-default ',' capture-list
+///
+/// capture-default:
+/// '&'
+/// '='
+///
+/// capture-list:
+/// capture
+/// capture-list ',' capture
+///
+/// capture:
+/// identifier
+/// '&' identifier
+/// 'this'
+///
+/// lambda-declarator:
+/// '(' parameter-declaration-clause ')' attribute-specifier[opt]
+/// 'mutable'[opt] exception-specification[opt]
+/// trailing-return-type[opt]
+///
+ExprResult Parser::ParseLambdaExpression() {
+ // Parse lambda-introducer.
+ LambdaIntroducer Intro;
+
+ llvm::Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro));
+ if (DiagID) {
+ Diag(Tok, DiagID.getValue());
+ SkipUntil(tok::r_square);
+ }
+
+ return ParseLambdaExpressionAfterIntroducer(Intro);
+}
+
+/// TryParseLambdaExpression - Use lookahead and potentially tentative
+/// parsing to determine if we are looking at a C++0x lambda expression, and parse
+/// it if we are.
+///
+/// If we are not looking at a lambda expression, returns ExprError().
+ExprResult Parser::TryParseLambdaExpression() {
+ assert(getLang().CPlusPlus0x
+ && Tok.is(tok::l_square)
+ && "Not at the start of a possible lambda expression.");
+
+ const Token Next = NextToken(), After = GetLookAheadToken(2);
+
+ // If lookahead indicates this is a lambda...
+ if (Next.is(tok::r_square) || // []
+ Next.is(tok::equal) || // [=
+ (Next.is(tok::amp) && // [&] or [&,
+ (After.is(tok::r_square) ||
+ After.is(tok::comma))) ||
+ (Next.is(tok::identifier) && // [identifier]
+ After.is(tok::r_square))) {
+ return ParseLambdaExpression();
+ }
+
+ // If lookahead indicates this is an Objective-C message...
+ if (Next.is(tok::identifier) && After.is(tok::identifier)) {
+ return ExprError();
+ }
+
+ LambdaIntroducer Intro;
+ if (TryParseLambdaIntroducer(Intro))
+ return ExprError();
+ return ParseLambdaExpressionAfterIntroducer(Intro);
+}
+
+/// 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;
+
+ assert(Tok.is(tok::l_square) && "Lambda expressions begin with '['.");
+ BalancedDelimiterTracker T(*this, tok::l_square);
+ T.consumeOpen();
+
+ Intro.Range.setBegin(T.getOpenLocation());
+
+ bool first = true;
+
+ // Parse capture-default.
+ if (Tok.is(tok::amp) &&
+ (NextToken().is(tok::comma) || NextToken().is(tok::r_square))) {
+ Intro.Default = LCD_ByRef;
+ ConsumeToken();
+ first = false;
+ } else if (Tok.is(tok::equal)) {
+ Intro.Default = LCD_ByCopy;
+ ConsumeToken();
+ first = false;
+ }
+
+ while (Tok.isNot(tok::r_square)) {
+ if (!first) {
+ if (Tok.isNot(tok::comma))
+ return DiagResult(diag::err_expected_comma_or_rsquare);
+ ConsumeToken();
+ }
+
+ first = false;
+
+ // Parse capture.
+ LambdaCaptureKind Kind = LCK_ByCopy;
+ SourceLocation Loc;
+ IdentifierInfo* Id = 0;
+
+ if (Tok.is(tok::kw_this)) {
+ Kind = LCK_This;
+ Loc = ConsumeToken();
+ } else {
+ if (Tok.is(tok::amp)) {
+ Kind = LCK_ByRef;
+ ConsumeToken();
+ }
+
+ if (Tok.is(tok::identifier)) {
+ Id = Tok.getIdentifierInfo();
+ Loc = ConsumeToken();
+ } else if (Tok.is(tok::kw_this)) {
+ // FIXME: If we want to suggest a fixit here, will need to return more
+ // than just DiagnosticID. Perhaps full DiagnosticBuilder that can be
+ // Clear()ed to prevent emission in case of tentative parsing?
+ return DiagResult(diag::err_this_captured_by_reference);
+ } else {
+ return DiagResult(diag::err_expected_capture);
+ }
+ }
+
+ Intro.addCapture(Kind, Loc, Id);
+ }
+
+ T.consumeClose();
+ Intro.Range.setEnd(T.getCloseLocation());
+
+ return DiagResult();
+}
+
+/// TryParseLambdaExpression - Tentatively parse a lambda introducer.
+///
+/// Returns true if it hit something unexpected.
+bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) {
+ TentativeParsingAction PA(*this);
+
+ llvm::Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro));
+
+ if (DiagID) {
+ PA.Revert();
+ return true;
+ }
+
+ PA.Commit();
+ return false;
+}
+
+/// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda
+/// expression.
+ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
+ LambdaIntroducer &Intro) {
+ // Parse lambda-declarator[opt].
+ DeclSpec DS(AttrFactory);
+ Declarator D(DS, Declarator::PrototypeContext);
+
+ if (Tok.is(tok::l_paren)) {
+ ParseScope PrototypeScope(this,
+ Scope::FunctionPrototypeScope |
+ Scope::DeclScope);
+
+ SourceLocation DeclLoc, DeclEndLoc;
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
+ DeclLoc = T.getOpenLocation();
+
+ // Parse parameter-declaration-clause.
+ ParsedAttributes Attr(AttrFactory);
+ llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
+ SourceLocation EllipsisLoc;
+
+ if (Tok.isNot(tok::r_paren))
+ ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc);
+
+ T.consumeClose();
+ DeclEndLoc = T.getCloseLocation();
+
+ // Parse 'mutable'[opt].
+ SourceLocation MutableLoc;
+ if (Tok.is(tok::kw_mutable)) {
+ MutableLoc = ConsumeToken();
+ DeclEndLoc = MutableLoc;
+ }
+
+ // Parse exception-specification[opt].
+ ExceptionSpecificationType ESpecType = EST_None;
+ SourceRange ESpecRange;
+ llvm::SmallVector<ParsedType, 2> DynamicExceptions;
+ llvm::SmallVector<SourceRange, 2> DynamicExceptionRanges;
+ ExprResult NoexceptExpr;
+ ESpecType = MaybeParseExceptionSpecification(ESpecRange,
+ DynamicExceptions,
+ DynamicExceptionRanges,
+ NoexceptExpr);
+
+ if (ESpecType != EST_None)
+ DeclEndLoc = ESpecRange.getEnd();
+
+ // Parse attribute-specifier[opt].
+ MaybeParseCXX0XAttributes(Attr, &DeclEndLoc);
+
+ // Parse trailing-return-type[opt].
+ ParsedType TrailingReturnType;
+ if (Tok.is(tok::arrow)) {
+ SourceRange Range;
+ TrailingReturnType = ParseTrailingReturnType(Range).get();
+ if (Range.getEnd().isValid())
+ DeclEndLoc = Range.getEnd();
+ }
+
+ PrototypeScope.Exit();
+
+ D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true,
+ /*isVariadic=*/EllipsisLoc.isValid(),
+ EllipsisLoc,
+ ParamInfo.data(), ParamInfo.size(),
+ DS.getTypeQualifiers(),
+ /*RefQualifierIsLValueRef=*/true,
+ /*RefQualifierLoc=*/SourceLocation(),
+ MutableLoc,
+ ESpecType, ESpecRange.getBegin(),
+ DynamicExceptions.data(),
+ DynamicExceptionRanges.data(),
+ DynamicExceptions.size(),
+ NoexceptExpr.isUsable() ?
+ NoexceptExpr.get() : 0,
+ DeclLoc, DeclEndLoc, D,
+ TrailingReturnType),
+ Attr, DeclEndLoc);
+ }
+
+ // Parse compound-statement.
+ if (Tok.is(tok::l_brace)) {
+ // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
+ // it.
+ ParseScope BodyScope(this, Scope::BlockScope | Scope::FnScope |
+ Scope::BreakScope | Scope::ContinueScope |
+ Scope::DeclScope);
+
+ StmtResult Stmt(ParseCompoundStatementBody());
+
+ BodyScope.Exit();
+ } else {
+ Diag(Tok, diag::err_expected_lambda_body);
+ }
+
+ return ExprEmpty();
+}
+
/// ParseCXXCasts - This handles the various ways to cast expressions to another
/// type.
///
@@ -518,7 +790,7 @@ ExprResult Parser::ParseCXXCasts() {
const char *CastName = 0; // For error messages
switch (Kind) {
- default: assert(0 && "Unknown C++ cast!"); abort();
+ default: llvm_unreachable("Unknown C++ cast!");
case tok::kw_const_cast: CastName = "const_cast"; break;
case tok::kw_dynamic_cast: CastName = "dynamic_cast"; break;
case tok::kw_reinterpret_cast: CastName = "reinterpret_cast"; break;
@@ -551,21 +823,23 @@ ExprResult Parser::ParseCXXCasts() {
if (ExpectAndConsume(tok::greater, diag::err_expected_greater))
return ExprError(Diag(LAngleBracketLoc, diag::note_matching) << "<");
- SourceLocation LParenLoc = Tok.getLocation(), RParenLoc;
+ SourceLocation LParenLoc, RParenLoc;
+ BalancedDelimiterTracker T(*this, tok::l_paren);
- if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, CastName))
+ if (T.expectAndConsume(diag::err_expected_lparen_after, CastName))
return ExprError();
ExprResult Result = ParseExpression();
// Match the ')'.
- RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ T.consumeClose();
if (!Result.isInvalid() && !DeclaratorInfo.isInvalidType())
Result = Actions.ActOnCXXNamedCast(OpLoc, Kind,
LAngleBracketLoc, DeclaratorInfo,
RAngleBracketLoc,
- LParenLoc, Result.take(), RParenLoc);
+ T.getOpenLocation(), Result.take(),
+ T.getCloseLocation());
return move(Result);
}
@@ -580,13 +854,13 @@ ExprResult Parser::ParseCXXTypeid() {
assert(Tok.is(tok::kw_typeid) && "Not 'typeid'!");
SourceLocation OpLoc = ConsumeToken();
- SourceLocation LParenLoc = Tok.getLocation();
- SourceLocation RParenLoc;
+ SourceLocation LParenLoc, RParenLoc;
+ BalancedDelimiterTracker T(*this, tok::l_paren);
// typeid expressions are always parenthesized.
- if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
- "typeid"))
+ if (T.expectAndConsume(diag::err_expected_lparen_after, "typeid"))
return ExprError();
+ LParenLoc = T.getOpenLocation();
ExprResult Result;
@@ -594,8 +868,8 @@ ExprResult Parser::ParseCXXTypeid() {
TypeResult Ty = ParseTypeName();
// Match the ')'.
- RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
-
+ T.consumeClose();
+ RParenLoc = T.getCloseLocation();
if (Ty.isInvalid() || RParenLoc.isInvalid())
return ExprError();
@@ -618,18 +892,11 @@ ExprResult Parser::ParseCXXTypeid() {
if (Result.isInvalid())
SkipUntil(tok::r_paren);
else {
- RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ T.consumeClose();
+ RParenLoc = T.getCloseLocation();
if (RParenLoc.isInvalid())
return ExprError();
- // If we are a foo<int> that identifies a single function, resolve it now...
- Expr* e = Result.get();
- if (e->getType() == Actions.Context.OverloadTy) {
- ExprResult er =
- Actions.ResolveAndFixSingleFunctionTemplateSpecialization(e);
- if (er.isUsable())
- Result = er.release();
- }
Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/false,
Result.release(), RParenLoc);
}
@@ -647,12 +914,10 @@ ExprResult Parser::ParseCXXUuidof() {
assert(Tok.is(tok::kw___uuidof) && "Not '__uuidof'!");
SourceLocation OpLoc = ConsumeToken();
- SourceLocation LParenLoc = Tok.getLocation();
- SourceLocation RParenLoc;
+ BalancedDelimiterTracker T(*this, tok::l_paren);
// __uuidof expressions are always parenthesized.
- if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
- "__uuidof"))
+ if (T.expectAndConsume(diag::err_expected_lparen_after, "__uuidof"))
return ExprError();
ExprResult Result;
@@ -661,13 +926,14 @@ ExprResult Parser::ParseCXXUuidof() {
TypeResult Ty = ParseTypeName();
// Match the ')'.
- RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ T.consumeClose();
if (Ty.isInvalid())
return ExprError();
- Result = Actions.ActOnCXXUuidof(OpLoc, LParenLoc, /*isType=*/true,
- Ty.get().getAsOpaquePtr(), RParenLoc);
+ Result = Actions.ActOnCXXUuidof(OpLoc, T.getOpenLocation(), /*isType=*/true,
+ Ty.get().getAsOpaquePtr(),
+ T.getCloseLocation());
} else {
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
Result = ParseExpression();
@@ -676,10 +942,11 @@ ExprResult Parser::ParseCXXUuidof() {
if (Result.isInvalid())
SkipUntil(tok::r_paren);
else {
- RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ T.consumeClose();
- Result = Actions.ActOnCXXUuidof(OpLoc, LParenLoc, /*isType=*/false,
- Result.release(), RParenLoc);
+ Result = Actions.ActOnCXXUuidof(OpLoc, T.getOpenLocation(),
+ /*isType=*/false,
+ Result.release(), T.getCloseLocation());
}
}
@@ -836,7 +1103,8 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
} else {
GreaterThanIsOperatorScope G(GreaterThanIsOperator, true);
- SourceLocation LParenLoc = ConsumeParen();
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
ExprVector Exprs(Actions);
CommaLocsTy CommaLocs;
@@ -849,7 +1117,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
}
// Match the ')'.
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ T.consumeClose();
// TypeRep could be null, if it references an invalid typedef.
if (!TypeRep)
@@ -857,8 +1125,9 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&&
"Unexpected number of commas!");
- return Actions.ActOnCXXTypeConstructExpr(TypeRep, LParenLoc, move_arg(Exprs),
- RParenLoc);
+ return Actions.ActOnCXXTypeConstructExpr(TypeRep, T.getOpenLocation(),
+ move_arg(Exprs),
+ T.getCloseLocation());
}
}
@@ -889,7 +1158,8 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
bool ConvertToBoolean) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition);
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return true;
}
if (!isCXXConditionDeclaration()) {
@@ -969,6 +1239,7 @@ bool Parser::isCXXSimpleTypeSpecifier() const {
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:
@@ -1022,10 +1293,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
switch (Tok.getKind()) {
case tok::identifier: // foo::bar
case tok::coloncolon: // ::foo::bar
- assert(0 && "Annotation token should already be formed!");
+ llvm_unreachable("Annotation token should already be formed!");
default:
- assert(0 && "Not a simple-type-specifier token!");
- abort();
+ llvm_unreachable("Not a simple-type-specifier token!");
// type-name
case tok::annot_typename: {
@@ -1074,6 +1344,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
case tok::kw_int:
DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID);
break;
+ case tok::kw_half:
+ DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID);
+ break;
case tok::kw_float:
DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID);
break;
@@ -1394,16 +1667,15 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
// Consume the 'new' or 'delete'.
SymbolLocations[SymbolIdx++] = ConsumeToken();
if (Tok.is(tok::l_square)) {
- // Consume the '['.
- SourceLocation LBracketLoc = ConsumeBracket();
- // Consume the ']'.
- SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square,
- LBracketLoc);
- if (RBracketLoc.isInvalid())
+ // Consume the '[' and ']'.
+ BalancedDelimiterTracker T(*this, tok::l_square);
+ T.consumeOpen();
+ T.consumeClose();
+ if (T.getCloseLocation().isInvalid())
return true;
- SymbolLocations[SymbolIdx++] = LBracketLoc;
- SymbolLocations[SymbolIdx++] = RBracketLoc;
+ SymbolLocations[SymbolIdx++] = T.getOpenLocation();
+ SymbolLocations[SymbolIdx++] = T.getCloseLocation();
Op = isNew? OO_Array_New : OO_Array_Delete;
} else {
Op = isNew? OO_New : OO_Delete;
@@ -1420,31 +1692,29 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
#include "clang/Basic/OperatorKinds.def"
case tok::l_paren: {
- // Consume the '('.
- SourceLocation LParenLoc = ConsumeParen();
- // Consume the ')'.
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren,
- LParenLoc);
- if (RParenLoc.isInvalid())
+ // Consume the '(' and ')'.
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
+ T.consumeClose();
+ if (T.getCloseLocation().isInvalid())
return true;
- SymbolLocations[SymbolIdx++] = LParenLoc;
- SymbolLocations[SymbolIdx++] = RParenLoc;
+ SymbolLocations[SymbolIdx++] = T.getOpenLocation();
+ SymbolLocations[SymbolIdx++] = T.getCloseLocation();
Op = OO_Call;
break;
}
case tok::l_square: {
- // Consume the '['.
- SourceLocation LBracketLoc = ConsumeBracket();
- // Consume the ']'.
- SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square,
- LBracketLoc);
- if (RBracketLoc.isInvalid())
+ // Consume the '[' and ']'.
+ BalancedDelimiterTracker T(*this, tok::l_square);
+ T.consumeOpen();
+ T.consumeClose();
+ if (T.getCloseLocation().isInvalid())
return true;
- SymbolLocations[SymbolIdx++] = LBracketLoc;
- SymbolLocations[SymbolIdx++] = RBracketLoc;
+ SymbolLocations[SymbolIdx++] = T.getOpenLocation();
+ SymbolLocations[SymbolIdx++] = T.getCloseLocation();
Op = OO_Subscript;
break;
}
@@ -1452,10 +1722,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
case tok::code_completion: {
// Code completion for the operator name.
Actions.CodeCompleteOperatorName(getCurScope());
-
- // Consume the operator token.
- ConsumeCodeCompletionToken();
-
+ cutOffParsing();
// Don't try to parse any further.
return true;
}
@@ -1758,13 +2025,16 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
Declarator DeclaratorInfo(DS, Declarator::CXXNewContext);
if (Tok.is(tok::l_paren)) {
// If it turns out to be a placement, we change the type location.
- PlacementLParen = ConsumeParen();
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
+ PlacementLParen = T.getOpenLocation();
if (ParseExpressionListOrTypeId(PlacementArgs, DeclaratorInfo)) {
SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
return ExprError();
}
- PlacementRParen = MatchRHSPunctuation(tok::r_paren, PlacementLParen);
+ T.consumeClose();
+ PlacementRParen = T.getCloseLocation();
if (PlacementRParen.isInvalid()) {
SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
return ExprError();
@@ -1772,18 +2042,19 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
if (PlacementArgs.empty()) {
// Reset the placement locations. There was no placement.
- TypeIdParens = SourceRange(PlacementLParen, PlacementRParen);
+ TypeIdParens = T.getRange();
PlacementLParen = PlacementRParen = SourceLocation();
} else {
// We still need the type.
if (Tok.is(tok::l_paren)) {
- TypeIdParens.setBegin(ConsumeParen());
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
MaybeParseGNUAttributes(DeclaratorInfo);
ParseSpecifierQualifierList(DS);
DeclaratorInfo.SetSourceRange(DS.getSourceRange());
ParseDeclarator(DeclaratorInfo);
- TypeIdParens.setEnd(MatchRHSPunctuation(tok::r_paren,
- TypeIdParens.getBegin()));
+ T.consumeClose();
+ TypeIdParens = T.getRange();
} else {
MaybeParseGNUAttributes(DeclaratorInfo);
if (ParseCXXTypeSpecifierSeq(DS))
@@ -1816,7 +2087,9 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
SourceLocation ConstructorLParen, ConstructorRParen;
if (Tok.is(tok::l_paren)) {
- ConstructorLParen = ConsumeParen();
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
+ ConstructorLParen = T.getOpenLocation();
if (Tok.isNot(tok::r_paren)) {
CommaLocsTy CommaLocs;
if (ParseExpressionList(ConstructorArgs, CommaLocs)) {
@@ -1824,7 +2097,8 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
return ExprError();
}
}
- ConstructorRParen = MatchRHSPunctuation(tok::r_paren, ConstructorLParen);
+ T.consumeClose();
+ ConstructorRParen = T.getCloseLocation();
if (ConstructorRParen.isInvalid()) {
SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
return ExprError();
@@ -1851,7 +2125,9 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) {
// Parse the array dimensions.
bool first = true;
while (Tok.is(tok::l_square)) {
- SourceLocation LLoc = ConsumeBracket();
+ BalancedDelimiterTracker T(*this, tok::l_square);
+ T.consumeOpen();
+
ExprResult Size(first ? ParseExpression()
: ParseConstantExpression());
if (Size.isInvalid()) {
@@ -1861,15 +2137,17 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) {
}
first = false;
- SourceLocation RLoc = MatchRHSPunctuation(tok::r_square, LLoc);
+ T.consumeClose();
ParsedAttributes attrs(AttrFactory);
D.AddTypeInfo(DeclaratorChunk::getArray(0,
/*static=*/false, /*star=*/false,
- Size.release(), LLoc, RLoc),
- attrs, RLoc);
+ Size.release(),
+ T.getOpenLocation(),
+ T.getCloseLocation()),
+ attrs, T.getCloseLocation());
- if (RLoc.isInvalid())
+ if (T.getCloseLocation().isInvalid())
return;
}
}
@@ -1885,7 +2163,7 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) {
/// '(' expression-list ')'
///
bool Parser::ParseExpressionListOrTypeId(
- llvm::SmallVectorImpl<Expr*> &PlacementArgs,
+ SmallVectorImpl<Expr*> &PlacementArgs,
Declarator &D) {
// The '(' was already consumed.
if (isTypeIdInParens()) {
@@ -1921,9 +2199,11 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {
bool ArrayDelete = false;
if (Tok.is(tok::l_square)) {
ArrayDelete = true;
- SourceLocation LHS = ConsumeBracket();
- SourceLocation RHS = MatchRHSPunctuation(tok::r_square, LHS);
- if (RHS.isInvalid())
+ BalancedDelimiterTracker T(*this, tok::l_square);
+
+ T.consumeOpen();
+ T.consumeClose();
+ if (T.getCloseLocation().isInvalid())
return ExprError();
}
@@ -1936,7 +2216,7 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {
static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) {
switch(kind) {
- default: assert(false && "Not a known unary type trait.");
+ default: llvm_unreachable("Not a known unary type trait.");
case tok::kw___has_nothrow_assign: return UTT_HasNothrowAssign;
case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor;
case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy;
@@ -2004,7 +2284,7 @@ static ArrayTypeTrait ArrayTypeTraitFromTokKind(tok::TokenKind kind) {
static ExpressionTrait ExpressionTraitFromTokKind(tok::TokenKind kind) {
switch(kind) {
- default: assert(false && "Not a known unary expression trait.");
+ default: llvm_unreachable("Not a known unary expression trait.");
case tok::kw___is_lvalue_expr: return ET_IsLValueExpr;
case tok::kw___is_rvalue_expr: return ET_IsRValueExpr;
}
@@ -2021,8 +2301,8 @@ ExprResult Parser::ParseUnaryTypeTrait() {
UnaryTypeTrait UTT = UnaryTypeTraitFromTokKind(Tok.getKind());
SourceLocation Loc = ConsumeToken();
- SourceLocation LParen = Tok.getLocation();
- if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen))
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.expectAndConsume(diag::err_expected_lparen))
return ExprError();
// FIXME: Error reporting absolutely sucks! If the this fails to parse a type
@@ -2030,12 +2310,12 @@ ExprResult Parser::ParseUnaryTypeTrait() {
// specifiers.
TypeResult Ty = ParseTypeName();
- SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen);
+ T.consumeClose();
if (Ty.isInvalid())
return ExprError();
- return Actions.ActOnUnaryTypeTrait(UTT, Loc, Ty.get(), RParen);
+ return Actions.ActOnUnaryTypeTrait(UTT, Loc, Ty.get(), T.getCloseLocation());
}
/// ParseBinaryTypeTrait - Parse the built-in binary type-trait
@@ -2049,8 +2329,8 @@ ExprResult Parser::ParseBinaryTypeTrait() {
BinaryTypeTrait BTT = BinaryTypeTraitFromTokKind(Tok.getKind());
SourceLocation Loc = ConsumeToken();
- SourceLocation LParen = Tok.getLocation();
- if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen))
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.expectAndConsume(diag::err_expected_lparen))
return ExprError();
TypeResult LhsTy = ParseTypeName();
@@ -2070,9 +2350,10 @@ ExprResult Parser::ParseBinaryTypeTrait() {
return ExprError();
}
- SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen);
+ T.consumeClose();
- return Actions.ActOnBinaryTypeTrait(BTT, Loc, LhsTy.get(), RhsTy.get(), RParen);
+ return Actions.ActOnBinaryTypeTrait(BTT, Loc, LhsTy.get(), RhsTy.get(),
+ T.getCloseLocation());
}
/// ParseArrayTypeTrait - Parse the built-in array type-trait
@@ -2086,8 +2367,8 @@ ExprResult Parser::ParseArrayTypeTrait() {
ArrayTypeTrait ATT = ArrayTypeTraitFromTokKind(Tok.getKind());
SourceLocation Loc = ConsumeToken();
- SourceLocation LParen = Tok.getLocation();
- if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen))
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.expectAndConsume(diag::err_expected_lparen))
return ExprError();
TypeResult Ty = ParseTypeName();
@@ -2099,8 +2380,9 @@ ExprResult Parser::ParseArrayTypeTrait() {
switch (ATT) {
case ATT_ArrayRank: {
- SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen);
- return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), NULL, RParen);
+ T.consumeClose();
+ return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), NULL,
+ T.getCloseLocation());
}
case ATT_ArrayExtent: {
if (ExpectAndConsume(tok::comma, diag::err_expected_comma)) {
@@ -2109,9 +2391,10 @@ ExprResult Parser::ParseArrayTypeTrait() {
}
ExprResult DimExpr = ParseExpression();
- SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen);
+ T.consumeClose();
- return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), DimExpr.get(), RParen);
+ return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), DimExpr.get(),
+ T.getCloseLocation());
}
default:
break;
@@ -2129,15 +2412,16 @@ ExprResult Parser::ParseExpressionTrait() {
ExpressionTrait ET = ExpressionTraitFromTokKind(Tok.getKind());
SourceLocation Loc = ConsumeToken();
- SourceLocation LParen = Tok.getLocation();
- if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen))
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.expectAndConsume(diag::err_expected_lparen))
return ExprError();
ExprResult Expr = ParseExpression();
- SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen);
+ T.consumeClose();
- return Actions.ActOnExpressionTrait(ET, Loc, Expr.get(), RParen);
+ return Actions.ActOnExpressionTrait(ET, Loc, Expr.get(),
+ T.getCloseLocation());
}
@@ -2147,8 +2431,7 @@ ExprResult Parser::ParseExpressionTrait() {
ExprResult
Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
ParsedType &CastTy,
- SourceLocation LParenLoc,
- SourceLocation &RParenLoc) {
+ BalancedDelimiterTracker &Tracker) {
assert(getLang().CPlusPlus && "Should only be called for C++!");
assert(ExprType == CastExpr && "Compound literals are not ambiguous!");
assert(isTypeIdInParens() && "Not a type-id!");
@@ -2182,7 +2465,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
// the context that follows them.
if (!ConsumeAndStoreUntil(tok::r_paren, Toks)) {
// We didn't find the ')' we expected.
- MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ Tracker.consumeClose();
return ExprError();
}
@@ -2227,15 +2510,14 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
ParseDeclarator(DeclaratorInfo);
// Match the ')'.
- if (Tok.is(tok::r_paren))
- RParenLoc = ConsumeParen();
- else
- MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ Tracker.consumeClose();
if (ParseAs == CompoundLiteral) {
ExprType = CompoundLiteral;
TypeResult Ty = ParseTypeName();
- return ParseCompoundLiteralExpression(Ty.get(), LParenLoc, RParenLoc);
+ return ParseCompoundLiteralExpression(Ty.get(),
+ Tracker.getOpenLocation(),
+ Tracker.getCloseLocation());
}
// We parsed '(' type-id ')' and the thing after it wasn't a '{'.
@@ -2246,9 +2528,9 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
// Result is what ParseCastExpression returned earlier.
if (!Result.isInvalid())
- Result = Actions.ActOnCastExpr(getCurScope(), LParenLoc,
- DeclaratorInfo, CastTy,
- RParenLoc, Result.take());
+ Result = Actions.ActOnCastExpr(getCurScope(), Tracker.getOpenLocation(),
+ DeclaratorInfo, CastTy,
+ Tracker.getCloseLocation(), Result.take());
return move(Result);
}
@@ -2258,7 +2540,8 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
ExprType = SimpleExpr;
Result = ParseExpression();
if (!Result.isInvalid() && Tok.is(tok::r_paren))
- Result = Actions.ActOnParenExpr(LParenLoc, Tok.getLocation(), Result.take());
+ Result = Actions.ActOnParenExpr(Tracker.getOpenLocation(),
+ Tok.getLocation(), Result.take());
// Match the ')'.
if (Result.isInvalid()) {
@@ -2266,10 +2549,6 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
return ExprError();
}
- if (Tok.is(tok::r_paren))
- RParenLoc = ConsumeParen();
- else
- MatchRHSPunctuation(tok::r_paren, LParenLoc);
-
+ Tracker.consumeClose();
return move(Result);
}
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index 2c9278a90033..33abc932541d 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -90,7 +90,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
assert(Tok.is(tok::colon) && "MayBeDesignationStart not working properly!");
SourceLocation ColonLoc = ConsumeToken();
- Diag(Tok, diag::ext_gnu_old_style_field_designator)
+ Diag(NameLoc, diag::ext_gnu_old_style_field_designator)
<< FixItHint::CreateReplacement(SourceRange(NameLoc, ColonLoc),
NewSyntax.str());
@@ -139,7 +139,10 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
//
InMessageExpressionRAIIObject InMessage(*this, true);
- SourceLocation StartLoc = ConsumeBracket();
+ BalancedDelimiterTracker T(*this, tok::l_square);
+ T.consumeOpen();
+ SourceLocation StartLoc = T.getOpenLocation();
+
ExprResult Idx;
// If Objective-C is enabled and this is a typename (class message
@@ -266,8 +269,9 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
StartLoc, EllipsisLoc));
}
- SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
- Desig.getDesignator(Desig.getNumDesignators() - 1).setRBracketLoc(EndLoc);
+ T.consumeClose();
+ Desig.getDesignator(Desig.getNumDesignators() - 1).setRBracketLoc(
+ T.getCloseLocation());
}
// Okay, we're done with the designator sequence. We know that there must be
@@ -316,7 +320,9 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
ExprResult Parser::ParseBraceInitializer() {
InMessageExpressionRAIIObject InMessage(*this, false);
- SourceLocation LBraceLoc = ConsumeBrace();
+ BalancedDelimiterTracker T(*this, tok::l_brace);
+ T.consumeOpen();
+ SourceLocation LBraceLoc = T.getOpenLocation();
/// InitExprs - This is the actual list of expressions contained in the
/// initializer.
@@ -376,12 +382,13 @@ ExprResult Parser::ParseBraceInitializer() {
// Handle trailing comma.
if (Tok.is(tok::r_brace)) break;
}
- if (InitExprsOk && Tok.is(tok::r_brace))
+
+ bool closed = !T.consumeClose();
+
+ if (InitExprsOk && closed)
return Actions.ActOnInitList(LBraceLoc, move_arg(InitExprs),
- ConsumeBrace());
+ T.getCloseLocation());
- // Match the '}'.
- MatchRHSPunctuation(tok::r_brace, LBraceLoc);
return ExprError(); // an error occurred.
}
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 7641565d1cc3..88044d1bc9d8 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -29,57 +29,70 @@ using namespace clang;
/// [OBJC] objc-protocol-definition
/// [OBJC] objc-method-definition
/// [OBJC] '@' 'end'
-Decl *Parser::ParseObjCAtDirectives() {
+Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() {
SourceLocation AtLoc = ConsumeToken(); // the "@"
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCAtDirective(getCurScope(), ObjCImpDecl, false);
- ConsumeCodeCompletionToken();
+ Actions.CodeCompleteObjCAtDirective(getCurScope());
+ cutOffParsing();
+ return DeclGroupPtrTy();
}
-
+
+ Decl *SingleDecl = 0;
switch (Tok.getObjCKeywordID()) {
case tok::objc_class:
return ParseObjCAtClassDeclaration(AtLoc);
+ break;
case tok::objc_interface: {
ParsedAttributes attrs(AttrFactory);
- return ParseObjCAtInterfaceDeclaration(AtLoc, attrs);
+ SingleDecl = ParseObjCAtInterfaceDeclaration(AtLoc, attrs);
+ break;
}
case tok::objc_protocol: {
ParsedAttributes attrs(AttrFactory);
- return ParseObjCAtProtocolDeclaration(AtLoc, attrs);
+ SingleDecl = ParseObjCAtProtocolDeclaration(AtLoc, attrs);
+ break;
}
case tok::objc_implementation:
- return ParseObjCAtImplementationDeclaration(AtLoc);
+ SingleDecl = ParseObjCAtImplementationDeclaration(AtLoc);
+ break;
case tok::objc_end:
return ParseObjCAtEndDeclaration(AtLoc);
+ break;
case tok::objc_compatibility_alias:
- return ParseObjCAtAliasDeclaration(AtLoc);
+ SingleDecl = ParseObjCAtAliasDeclaration(AtLoc);
+ break;
case tok::objc_synthesize:
- return ParseObjCPropertySynthesize(AtLoc);
+ SingleDecl = ParseObjCPropertySynthesize(AtLoc);
+ break;
case tok::objc_dynamic:
- return ParseObjCPropertyDynamic(AtLoc);
+ SingleDecl = ParseObjCPropertyDynamic(AtLoc);
+ break;
default:
Diag(AtLoc, diag::err_unexpected_at);
SkipUntil(tok::semi);
- return 0;
+ SingleDecl = 0;
+ break;
}
+ return Actions.ConvertDeclToDeclGroup(SingleDecl);
}
///
/// objc-class-declaration:
/// '@' 'class' identifier-list ';'
///
-Decl *Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
+Parser::DeclGroupPtrTy
+Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
ConsumeToken(); // the identifier "class"
- llvm::SmallVector<IdentifierInfo *, 8> ClassNames;
- llvm::SmallVector<SourceLocation, 8> ClassLocs;
+ SmallVector<IdentifierInfo *, 8> ClassNames;
+ SmallVector<SourceLocation, 8> ClassLocs;
while (1) {
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
SkipUntil(tok::semi);
- return 0;
+ return Actions.ConvertDeclToDeclGroup(0);
}
ClassNames.push_back(Tok.getIdentifierInfo());
ClassLocs.push_back(Tok.getLocation());
@@ -93,7 +106,7 @@ Decl *Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
// Consume the ';'.
if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class"))
- return 0;
+ return Actions.ConvertDeclToDeclGroup(0);
return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(),
ClassLocs.data(),
@@ -137,7 +150,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
// Code completion after '@interface'.
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCInterfaceDecl(getCurScope());
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return 0;
}
if (Tok.isNot(tok::identifier)) {
@@ -150,14 +164,16 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
SourceLocation nameLoc = ConsumeToken();
if (Tok.is(tok::l_paren) &&
!isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category.
- // TODO(dgregor): Use the return value from the next line to provide better
- // recovery.
- ConsumeParen();
- SourceLocation categoryLoc, rparenLoc;
+
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
+
+ SourceLocation categoryLoc;
IdentifierInfo *categoryId = 0;
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCInterfaceCategory(getCurScope(), nameId, nameLoc);
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return 0;
}
// For ObjC2, the category name is optional (not an error).
@@ -169,24 +185,25 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
Diag(Tok, diag::err_expected_ident); // missing category name.
return 0;
}
- if (Tok.isNot(tok::r_paren)) {
- Diag(Tok, diag::err_expected_rparen);
- SkipUntil(tok::r_paren, false); // don't stop at ';'
+
+ T.consumeClose();
+ if (T.getCloseLocation().isInvalid())
return 0;
+
+ if (!attrs.empty()) { // categories don't support attributes.
+ Diag(nameLoc, diag::err_objc_no_attributes_on_category);
+ attrs.clear();
}
- rparenLoc = ConsumeParen();
+
// Next, we need to check for any protocol references.
SourceLocation LAngleLoc, EndProtoLoc;
- llvm::SmallVector<Decl *, 8> ProtocolRefs;
- llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
+ SmallVector<Decl *, 8> ProtocolRefs;
+ SmallVector<SourceLocation, 8> ProtocolLocs;
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true,
LAngleLoc, EndProtoLoc))
return 0;
- if (!attrs.empty()) // categories don't support attributes.
- Diag(Tok, diag::err_objc_no_attributes_on_category);
-
Decl *CategoryType =
Actions.ActOnStartCategoryInterface(atLoc,
nameId, nameLoc,
@@ -195,11 +212,11 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
ProtocolRefs.size(),
ProtocolLocs.data(),
EndProtoLoc);
- if (Tok.is(tok::l_brace))
- ParseObjCClassInstanceVariables(CategoryType, tok::objc_private,
- atLoc);
- ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword);
+ if (Tok.is(tok::l_brace))
+ ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, atLoc);
+
+ ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType);
return CategoryType;
}
// Parse a class interface.
@@ -212,7 +229,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
// Code completion of superclass names.
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCSuperclass(getCurScope(), nameId, nameLoc);
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return 0;
}
if (Tok.isNot(tok::identifier)) {
@@ -223,8 +241,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
superClassLoc = ConsumeToken();
}
// Next, we need to check for any protocol references.
- llvm::SmallVector<Decl *, 8> ProtocolRefs;
- llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
+ SmallVector<Decl *, 8> ProtocolRefs;
+ SmallVector<SourceLocation, 8> ProtocolLocs;
SourceLocation LAngleLoc, EndProtoLoc;
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true,
@@ -241,7 +259,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
if (Tok.is(tok::l_brace))
ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, atLoc);
- ParseObjCInterfaceDeclList(ClsType, tok::objc_interface);
+ ParseObjCInterfaceDeclList(tok::objc_interface, ClsType);
return ClsType;
}
@@ -249,17 +267,16 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
/// it's used, but instead it's been lifted to here to support VS2005.
struct Parser::ObjCPropertyCallback : FieldCallback {
Parser &P;
- Decl *IDecl;
- llvm::SmallVectorImpl<Decl *> &Props;
+ SmallVectorImpl<Decl *> &Props;
ObjCDeclSpec &OCDS;
SourceLocation AtLoc;
tok::ObjCKeywordKind MethodImplKind;
- ObjCPropertyCallback(Parser &P, Decl *IDecl,
- llvm::SmallVectorImpl<Decl *> &Props,
+ ObjCPropertyCallback(Parser &P,
+ SmallVectorImpl<Decl *> &Props,
ObjCDeclSpec &OCDS, SourceLocation AtLoc,
tok::ObjCKeywordKind MethodImplKind) :
- P(P), IDecl(IDecl), Props(Props), OCDS(OCDS), AtLoc(AtLoc),
+ P(P), Props(Props), OCDS(OCDS), AtLoc(AtLoc),
MethodImplKind(MethodImplKind) {
}
@@ -292,7 +309,7 @@ struct Parser::ObjCPropertyCallback : FieldCallback {
bool isOverridingProperty = false;
Decl *Property =
P.Actions.ActOnProperty(P.getCurScope(), AtLoc, FD, OCDS,
- GetterSel, SetterSel, IDecl,
+ GetterSel, SetterSel,
&isOverridingProperty,
MethodImplKind);
if (!isOverridingProperty)
@@ -314,20 +331,20 @@ struct Parser::ObjCPropertyCallback : FieldCallback {
/// @required
/// @optional
///
-void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl,
- tok::ObjCKeywordKind contextKey) {
- llvm::SmallVector<Decl *, 32> allMethods;
- llvm::SmallVector<Decl *, 16> allProperties;
- llvm::SmallVector<DeclGroupPtrTy, 8> allTUVariables;
+void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
+ Decl *CDecl) {
+ SmallVector<Decl *, 32> allMethods;
+ SmallVector<Decl *, 16> allProperties;
+ SmallVector<DeclGroupPtrTy, 8> allTUVariables;
tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;
SourceRange AtEnd;
-
+
while (1) {
// If this is a method prototype, parse it.
if (Tok.is(tok::minus) || Tok.is(tok::plus)) {
Decl *methodPrototype =
- ParseObjCMethodPrototype(interfaceDecl, MethodImplKind, false);
+ ParseObjCMethodPrototype(MethodImplKind, false);
allMethods.push_back(methodPrototype);
// Consume the ';' here, since ParseObjCMethodPrototype() is re-used for
// method definitions.
@@ -339,7 +356,6 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl,
Diag(Tok, diag::err_expected_minus_or_plus);
ParseObjCMethodDecl(Tok.getLocation(),
tok::minus,
- interfaceDecl,
MethodImplKind, false);
continue;
}
@@ -358,7 +374,7 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl,
Actions.CodeCompleteOrdinaryName(getCurScope(),
ObjCImpDecl? Sema::PCC_ObjCImplementation
: Sema::PCC_ObjCInterface);
- ConsumeCodeCompletionToken();
+ return cutOffParsing();
}
// If we don't have an @ directive, parse it as a function definition.
@@ -368,9 +384,6 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl,
// erroneous r_brace would cause an infinite loop if not handled here.
if (Tok.is(tok::r_brace))
break;
-
- // FIXME: as the name implies, this rule allows function definitions.
- // We could pass a flag or check for functions during semantic analysis.
ParsedAttributes attrs(AttrFactory);
allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(attrs));
continue;
@@ -379,8 +392,8 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl,
// Otherwise, we have an @ directive, eat the @.
SourceLocation AtLoc = ConsumeToken(); // the "@"
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCAtDirective(getCurScope(), ObjCImpDecl, true);
- ConsumeCodeCompletionToken();
+ Actions.CodeCompleteObjCAtDirective(getCurScope());
+ return cutOffParsing();
break;
}
@@ -433,9 +446,9 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl,
ObjCDeclSpec OCDS;
// Parse property attribute list, if any.
if (Tok.is(tok::l_paren))
- ParseObjCPropertyAttribute(OCDS, interfaceDecl);
+ ParseObjCPropertyAttribute(OCDS);
- ObjCPropertyCallback Callback(*this, interfaceDecl, allProperties,
+ ObjCPropertyCallback Callback(*this, allProperties,
OCDS, AtLoc, MethodImplKind);
// Parse all the comma separated declarators.
@@ -450,8 +463,8 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl,
// We break out of the big loop in two cases: when we see @end or when we see
// EOF. In the former case, eat the @end. In the later case, emit an error.
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCAtDirective(getCurScope(), ObjCImpDecl, true);
- ConsumeCodeCompletionToken();
+ Actions.CodeCompleteObjCAtDirective(getCurScope());
+ return cutOffParsing();
} else if (Tok.isObjCAtKeyword(tok::objc_end))
ConsumeToken(); // the "end" identifier
else
@@ -459,7 +472,7 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl,
// Insert collected methods declarations into the @interface object.
// This passes in an invalid SourceLocation for AtEndLoc when EOF is hit.
- Actions.ActOnAtEnd(getCurScope(), AtEnd, interfaceDecl,
+ Actions.ActOnAtEnd(getCurScope(), AtEnd,
allMethods.data(), allMethods.size(),
allProperties.data(), allProperties.size(),
allTUVariables.data(), allTUVariables.size());
@@ -485,20 +498,21 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl,
/// weak
/// unsafe_unretained
///
-void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl) {
+void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
assert(Tok.getKind() == tok::l_paren);
- SourceLocation LHSLoc = ConsumeParen(); // consume '('
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
while (1) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCPropertyFlags(getCurScope(), DS);
- ConsumeCodeCompletionToken();
+ return cutOffParsing();
}
const IdentifierInfo *II = Tok.getIdentifierInfo();
// If this is not an identifier at all, bail out early.
if (II == 0) {
- MatchRHSPunctuation(tok::r_paren, LHSLoc);
+ T.consumeClose();
return;
}
@@ -536,10 +550,10 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl) {
if (Tok.is(tok::code_completion)) {
if (IsSetter)
- Actions.CodeCompleteObjCPropertySetter(getCurScope(), ClassDecl);
+ Actions.CodeCompleteObjCPropertySetter(getCurScope());
else
- Actions.CodeCompleteObjCPropertyGetter(getCurScope(), ClassDecl);
- ConsumeCodeCompletionToken();
+ Actions.CodeCompleteObjCPropertyGetter(getCurScope());
+ return cutOffParsing();
}
@@ -577,7 +591,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl) {
ConsumeToken();
}
- MatchRHSPunctuation(tok::r_paren, LHSLoc);
+ T.consumeClose();
}
/// objc-method-proto:
@@ -590,14 +604,13 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl) {
/// objc-method-attributes: [OBJC2]
/// __attribute__((deprecated))
///
-Decl *Parser::ParseObjCMethodPrototype(Decl *IDecl,
- tok::ObjCKeywordKind MethodImplKind,
+Decl *Parser::ParseObjCMethodPrototype(tok::ObjCKeywordKind MethodImplKind,
bool MethodDefinition) {
assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-");
tok::TokenKind methodType = Tok.getKind();
SourceLocation mLoc = ConsumeToken();
- Decl *MDecl = ParseObjCMethodDecl(mLoc, methodType, IDecl,MethodImplKind,
+ Decl *MDecl = ParseObjCMethodDecl(mLoc, methodType, MethodImplKind,
MethodDefinition);
// Since this rule is used for both method declarations and definitions,
// the caller is (optionally) responsible for consuming the ';'.
@@ -732,12 +745,15 @@ bool Parser::isTokIdentifier_in() const {
/// objc-type-qualifiers objc-type-qualifier
///
void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
- ObjCTypeNameContext Context) {
+ Declarator::TheContext Context) {
+ assert(Context == Declarator::ObjCParameterContext ||
+ Context == Declarator::ObjCResultContext);
+
while (1) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCPassingType(getCurScope(), DS,
- Context == OTN_ParameterType);
- ConsumeCodeCompletionToken();
+ Context == Declarator::ObjCParameterContext);
+ return cutOffParsing();
}
if (Tok.isNot(tok::identifier))
@@ -750,7 +766,7 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
ObjCDeclSpec::ObjCDeclQualifier Qual;
switch (i) {
- default: assert(0 && "Unknown decl qualifier");
+ default: llvm_unreachable("Unknown decl qualifier");
case objc_in: Qual = ObjCDeclSpec::DQ_In; break;
case objc_out: Qual = ObjCDeclSpec::DQ_Out; break;
case objc_inout: Qual = ObjCDeclSpec::DQ_Inout; break;
@@ -769,30 +785,95 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
}
}
+/// Take all the decl attributes out of the given list and add
+/// them to the given attribute set.
+static void takeDeclAttributes(ParsedAttributes &attrs,
+ AttributeList *list) {
+ while (list) {
+ AttributeList *cur = list;
+ list = cur->getNext();
+
+ if (!cur->isUsedAsTypeAttr()) {
+ // Clear out the next pointer. We're really completely
+ // destroying the internal invariants of the declarator here,
+ // but it doesn't matter because we're done with it.
+ cur->setNext(0);
+ attrs.add(cur);
+ }
+ }
+}
+
+/// takeDeclAttributes - Take all the decl attributes from the given
+/// declarator and add them to the given list.
+static void takeDeclAttributes(ParsedAttributes &attrs,
+ Declarator &D) {
+ // First, take ownership of all attributes.
+ attrs.getPool().takeAllFrom(D.getAttributePool());
+ attrs.getPool().takeAllFrom(D.getDeclSpec().getAttributePool());
+
+ // Now actually move the attributes over.
+ takeDeclAttributes(attrs, D.getDeclSpec().getAttributes().getList());
+ takeDeclAttributes(attrs, D.getAttributes());
+ for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i)
+ takeDeclAttributes(attrs,
+ const_cast<AttributeList*>(D.getTypeObject(i).getAttrs()));
+}
+
/// objc-type-name:
/// '(' objc-type-qualifiers[opt] type-name ')'
/// '(' objc-type-qualifiers[opt] ')'
///
ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
- ObjCTypeNameContext Context) {
+ Declarator::TheContext context,
+ ParsedAttributes *paramAttrs) {
+ assert(context == Declarator::ObjCParameterContext ||
+ context == Declarator::ObjCResultContext);
+ assert((paramAttrs != 0) == (context == Declarator::ObjCParameterContext));
+
assert(Tok.is(tok::l_paren) && "expected (");
- SourceLocation LParenLoc = ConsumeParen();
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
+
SourceLocation TypeStartLoc = Tok.getLocation();
+ ObjCDeclContextSwitch ObjCDC(*this);
// Parse type qualifiers, in, inout, etc.
- ParseObjCTypeQualifierList(DS, Context);
+ ParseObjCTypeQualifierList(DS, context);
ParsedType Ty;
if (isTypeSpecifierQualifier()) {
- TypeResult TypeSpec =
- ParseTypeName(0, Declarator::ObjCPrototypeContext, &DS);
- if (!TypeSpec.isInvalid())
- Ty = TypeSpec.get();
+ // Parse an abstract declarator.
+ DeclSpec declSpec(AttrFactory);
+ declSpec.setObjCQualifiers(&DS);
+ ParseSpecifierQualifierList(declSpec);
+ Declarator declarator(declSpec, context);
+ ParseDeclarator(declarator);
+
+ // If that's not invalid, extract a type.
+ if (!declarator.isInvalidType()) {
+ TypeResult type = Actions.ActOnTypeName(getCurScope(), declarator);
+ if (!type.isInvalid())
+ Ty = type.get();
+
+ // If we're parsing a parameter, steal all the decl attributes
+ // and add them to the decl spec.
+ if (context == Declarator::ObjCParameterContext)
+ takeDeclAttributes(*paramAttrs, declarator);
+ }
+ } else if (context == Declarator::ObjCResultContext &&
+ Tok.is(tok::identifier)) {
+ if (!Ident_instancetype)
+ Ident_instancetype = PP.getIdentifierInfo("instancetype");
+
+ if (Tok.getIdentifierInfo() == Ident_instancetype) {
+ Ty = Actions.ActOnObjCInstanceType(Tok.getLocation());
+ ConsumeToken();
+ }
}
-
+
if (Tok.is(tok::r_paren))
- ConsumeParen();
+ T.consumeClose();
else if (Tok.getLocation() == TypeStartLoc) {
// If we didn't eat any tokens, then this isn't a type.
Diag(Tok, diag::err_expected_type);
@@ -800,7 +881,7 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
} else {
// Otherwise, we found *something*, but didn't get a ')' in the right
// place. Emit an error then return what we have as the type.
- MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ T.consumeClose();
}
return Ty;
}
@@ -835,22 +916,22 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
///
Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
tok::TokenKind mType,
- Decl *IDecl,
tok::ObjCKeywordKind MethodImplKind,
bool MethodDefinition) {
ParsingDeclRAIIObject PD(*this);
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
- /*ReturnType=*/ ParsedType(), IDecl);
- ConsumeCodeCompletionToken();
+ /*ReturnType=*/ ParsedType());
+ cutOffParsing();
+ return 0;
}
// Parse the return type if present.
ParsedType ReturnType;
ObjCDeclSpec DSRet;
if (Tok.is(tok::l_paren))
- ReturnType = ParseObjCTypeName(DSRet, OTN_ResultType);
+ ReturnType = ParseObjCTypeName(DSRet, Declarator::ObjCResultContext, 0);
// If attributes exist before the method, parse them.
ParsedAttributes methodAttrs(AttrFactory);
@@ -859,8 +940,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
- ReturnType, IDecl);
- ConsumeCodeCompletionToken();
+ ReturnType);
+ cutOffParsing();
+ return 0;
}
// Now parse the selector.
@@ -876,7 +958,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
return 0;
}
- llvm::SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo;
+ SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo;
if (Tok.isNot(tok::colon)) {
// If attributes exist after the method, parse them.
if (getLang().ObjC2)
@@ -885,7 +967,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
Decl *Result
= Actions.ActOnMethodDeclaration(getCurScope(), mLoc, Tok.getLocation(),
- mType, IDecl, DSRet, ReturnType,
+ mType, DSRet, ReturnType,
selLoc, Sel, 0,
CParamInfo.data(), CParamInfo.size(),
methodAttrs.getList(), MethodImplKind,
@@ -894,8 +976,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
return Result;
}
- llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
- llvm::SmallVector<Sema::ObjCArgInfo, 12> ArgInfos;
+ SmallVector<IdentifierInfo *, 12> KeyIdents;
+ SmallVector<SourceLocation, 12> KeyLocs;
+ SmallVector<Sema::ObjCArgInfo, 12> ArgInfos;
ParseScope PrototypeScope(this,
Scope::FunctionPrototypeScope|Scope::DeclScope);
@@ -914,9 +997,12 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
ArgInfo.Type = ParsedType();
if (Tok.is(tok::l_paren)) // Parse the argument type if present.
- ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec, OTN_ParameterType);
+ ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec,
+ Declarator::ObjCParameterContext,
+ &paramAttrs);
// If attributes exist before the argument name, parse them.
+ // Regardless, collect all the attributes we've parsed so far.
ArgInfo.ArgAttrs = 0;
if (getLang().ObjC2) {
MaybeParseGNUAttributes(paramAttrs);
@@ -925,7 +1011,6 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// Code completion for the next piece of the selector.
if (Tok.is(tok::code_completion)) {
- ConsumeCodeCompletionToken();
KeyIdents.push_back(SelIdent);
Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
mType == tok::minus,
@@ -933,8 +1018,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
ReturnType,
KeyIdents.data(),
KeyIdents.size());
- KeyIdents.pop_back();
- break;
+ cutOffParsing();
+ return 0;
}
if (Tok.isNot(tok::identifier)) {
@@ -948,25 +1033,25 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
ArgInfos.push_back(ArgInfo);
KeyIdents.push_back(SelIdent);
+ KeyLocs.push_back(selLoc);
// Make sure the attributes persist.
allParamAttrs.takeAllFrom(paramAttrs.getPool());
// Code completion for the next piece of the selector.
if (Tok.is(tok::code_completion)) {
- ConsumeCodeCompletionToken();
Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
mType == tok::minus,
/*AtParameterName=*/false,
ReturnType,
KeyIdents.data(),
KeyIdents.size());
- break;
+ cutOffParsing();
+ return 0;
}
// Check for another keyword selector.
- SourceLocation Loc;
- SelIdent = ParseObjCSelectorPiece(Loc);
+ SelIdent = ParseObjCSelectorPiece(selLoc);
if (!SelIdent && Tok.isNot(tok::colon))
break;
// We have a selector or a colon, continue parsing.
@@ -1001,23 +1086,18 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
if (getLang().ObjC2)
MaybeParseGNUAttributes(methodAttrs);
- if (KeyIdents.size() == 0) {
- // Leave prototype scope.
- PrototypeScope.Exit();
+ if (KeyIdents.size() == 0)
return 0;
- }
Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),
&KeyIdents[0]);
Decl *Result
= Actions.ActOnMethodDeclaration(getCurScope(), mLoc, Tok.getLocation(),
- mType, IDecl, DSRet, ReturnType,
- selLoc, Sel, &ArgInfos[0],
+ mType, DSRet, ReturnType,
+ KeyLocs, Sel, &ArgInfos[0],
CParamInfo.data(), CParamInfo.size(),
methodAttrs.getList(),
MethodImplKind, isVariadic, MethodDefinition);
- // Leave prototype scope.
- PrototypeScope.Exit();
PD.complete(Result);
return Result;
@@ -1027,21 +1107,22 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
/// '<' identifier-list '>'
///
bool Parser::
-ParseObjCProtocolReferences(llvm::SmallVectorImpl<Decl *> &Protocols,
- llvm::SmallVectorImpl<SourceLocation> &ProtocolLocs,
+ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
+ SmallVectorImpl<SourceLocation> &ProtocolLocs,
bool WarnOnDeclarations,
SourceLocation &LAngleLoc, SourceLocation &EndLoc) {
assert(Tok.is(tok::less) && "expected <");
LAngleLoc = ConsumeToken(); // the "<"
- llvm::SmallVector<IdentifierLocPair, 8> ProtocolIdents;
+ SmallVector<IdentifierLocPair, 8> ProtocolIdents;
while (1) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents.data(),
ProtocolIdents.size());
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return true;
}
if (Tok.isNot(tok::identifier)) {
@@ -1080,8 +1161,8 @@ bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) {
assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'");
assert(getLang().ObjC1 && "Protocol qualifiers only exist in Objective-C");
SourceLocation LAngleLoc, EndProtoLoc;
- llvm::SmallVector<Decl *, 8> ProtocolDecl;
- llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
+ SmallVector<Decl *, 8> ProtocolDecl;
+ SmallVector<SourceLocation, 8> ProtocolLocs;
bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false,
LAngleLoc, EndProtoLoc);
DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(),
@@ -1116,11 +1197,13 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
tok::ObjCKeywordKind visibility,
SourceLocation atLoc) {
assert(Tok.is(tok::l_brace) && "expected {");
- llvm::SmallVector<Decl *, 32> AllIvarDecls;
-
+ SmallVector<Decl *, 32> AllIvarDecls;
+
ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope);
+ ObjCDeclContextSwitch ObjCDC(*this);
- SourceLocation LBraceLoc = ConsumeBrace(); // the "{"
+ 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)) {
@@ -1140,7 +1223,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCAtVisibility(getCurScope());
- ConsumeCodeCompletionToken();
+ return cutOffParsing();
}
switch (Tok.getObjCKeywordID()) {
@@ -1160,26 +1243,28 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteOrdinaryName(getCurScope(),
Sema::PCC_ObjCInstanceVariableList);
- ConsumeCodeCompletionToken();
+ return cutOffParsing();
}
struct ObjCIvarCallback : FieldCallback {
Parser &P;
Decl *IDecl;
tok::ObjCKeywordKind visibility;
- llvm::SmallVectorImpl<Decl *> &AllIvarDecls;
+ SmallVectorImpl<Decl *> &AllIvarDecls;
ObjCIvarCallback(Parser &P, Decl *IDecl, tok::ObjCKeywordKind V,
- llvm::SmallVectorImpl<Decl *> &AllIvarDecls) :
+ SmallVectorImpl<Decl *> &AllIvarDecls) :
P(P), IDecl(IDecl), visibility(V), AllIvarDecls(AllIvarDecls) {
}
Decl *invoke(FieldDeclarator &FD) {
+ P.Actions.ActOnObjCContainerStartDefinition(IDecl);
// Install the declarator into the interface decl.
Decl *Field
= P.Actions.ActOnIvar(P.getCurScope(),
FD.D.getDeclSpec().getSourceRange().getBegin(),
- IDecl, FD.D, FD.BitfieldSize, visibility);
+ FD.D, FD.BitfieldSize, visibility);
+ P.Actions.ActOnObjCContainerFinishDefinition();
if (Field)
AllIvarDecls.push_back(Field);
return Field;
@@ -1198,13 +1283,16 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
SkipUntil(tok::r_brace, true, true);
}
}
- SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
- Actions.ActOnLastBitfield(RBraceLoc, interfaceDecl, AllIvarDecls);
+ 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.data(), AllIvarDecls.size(),
- LBraceLoc, RBraceLoc, 0);
+ AllIvarDecls,
+ T.getOpenLocation(), T.getCloseLocation(), 0);
return;
}
@@ -1232,7 +1320,8 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCProtocolDecl(getCurScope());
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return 0;
}
if (Tok.isNot(tok::identifier)) {
@@ -1251,7 +1340,7 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
}
if (Tok.is(tok::comma)) { // list of forward declarations.
- llvm::SmallVector<IdentifierLocPair, 8> ProtocolRefs;
+ SmallVector<IdentifierLocPair, 8> ProtocolRefs;
ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc));
// Parse the list of forward declarations.
@@ -1282,8 +1371,8 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
// Last, and definitely not least, parse a protocol declaration.
SourceLocation LAngleLoc, EndProtoLoc;
- llvm::SmallVector<Decl *, 8> ProtocolRefs;
- llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
+ SmallVector<Decl *, 8> ProtocolRefs;
+ SmallVector<SourceLocation, 8> ProtocolLocs;
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false,
LAngleLoc, EndProtoLoc))
@@ -1295,7 +1384,8 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
ProtocolRefs.size(),
ProtocolLocs.data(),
EndProtoLoc, attrs.getList());
- ParseObjCInterfaceDeclList(ProtoType, tok::objc_protocol);
+
+ ParseObjCInterfaceDeclList(tok::objc_protocol, ProtoType);
return ProtoType;
}
@@ -1318,7 +1408,8 @@ Decl *Parser::ParseObjCAtImplementationDeclaration(
// Code completion after '@implementation'.
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCImplementationDecl(getCurScope());
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return 0;
}
if (Tok.isNot(tok::identifier)) {
@@ -1337,7 +1428,8 @@ Decl *Parser::ParseObjCAtImplementationDeclaration(
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc);
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return 0;
}
if (Tok.is(tok::identifier)) {
@@ -1356,6 +1448,7 @@ Decl *Parser::ParseObjCAtImplementationDeclaration(
Decl *ImplCatType = Actions.ActOnStartCategoryImplementation(
atLoc, nameId, nameLoc, categoryId,
categoryLoc);
+
ObjCImpDecl = ImplCatType;
PendingObjCImpDecl.push_back(ObjCImpDecl);
return 0;
@@ -1378,29 +1471,38 @@ Decl *Parser::ParseObjCAtImplementationDeclaration(
superClassId, superClassLoc);
if (Tok.is(tok::l_brace)) // we have ivars
- ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/,
- tok::objc_private, atLoc);
+ ParseObjCClassInstanceVariables(ImplClsType, tok::objc_private, atLoc);
+
ObjCImpDecl = ImplClsType;
PendingObjCImpDecl.push_back(ObjCImpDecl);
-
return 0;
}
-Decl *Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
+Parser::DeclGroupPtrTy
+Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
assert(Tok.isObjCAtKeyword(tok::objc_end) &&
"ParseObjCAtEndDeclaration(): Expected @end");
- Decl *Result = ObjCImpDecl;
ConsumeToken(); // the "end" identifier
+ SmallVector<Decl *, 8> DeclsInGroup;
+ Actions.DefaultSynthesizeProperties(getCurScope(), ObjCImpDecl);
+ for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i) {
+ Decl *D = ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i]);
+ DeclsInGroup.push_back(D);
+ }
+ DeclsInGroup.push_back(ObjCImpDecl);
+
if (ObjCImpDecl) {
- Actions.ActOnAtEnd(getCurScope(), atEnd, ObjCImpDecl);
- ObjCImpDecl = 0;
+ Actions.ActOnAtEnd(getCurScope(), atEnd);
PendingObjCImpDecl.pop_back();
}
- else {
+ else
// missing @implementation
Diag(atEnd.getBegin(), diag::err_expected_implementation);
- }
- return Result;
+
+ LateParsedObjCMethods.clear();
+ ObjCImpDecl = 0;
+ return Actions.BuildDeclaratorGroup(
+ DeclsInGroup.data(), DeclsInGroup.size(), false);
}
Parser::DeclGroupPtrTy Parser::FinishPendingObjCActions() {
@@ -1408,7 +1510,7 @@ Parser::DeclGroupPtrTy Parser::FinishPendingObjCActions() {
if (PendingObjCImpDecl.empty())
return Actions.ConvertDeclToDeclGroup(0);
Decl *ImpDecl = PendingObjCImpDecl.pop_back_val();
- Actions.ActOnAtEnd(getCurScope(), SourceRange(), ImpDecl);
+ Actions.ActOnAtEnd(getCurScope(), SourceRange());
return Actions.ConvertDeclToDeclGroup(ImpDecl);
}
@@ -1455,8 +1557,9 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
while (true) {
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCPropertyDefinition(getCurScope(), ObjCImpDecl);
- ConsumeCodeCompletionToken();
+ Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
+ cutOffParsing();
+ return 0;
}
if (Tok.isNot(tok::identifier)) {
@@ -1474,9 +1577,9 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
ConsumeToken(); // consume '='
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCPropertySynthesizeIvar(getCurScope(), propertyId,
- ObjCImpDecl);
- ConsumeCodeCompletionToken();
+ Actions.CodeCompleteObjCPropertySynthesizeIvar(getCurScope(), propertyId);
+ cutOffParsing();
+ return 0;
}
if (Tok.isNot(tok::identifier)) {
@@ -1486,7 +1589,7 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
propertyIvar = Tok.getIdentifierInfo();
propertyIvarLoc = ConsumeToken(); // consume ivar-name
}
- Actions.ActOnPropertyImplDecl(getCurScope(), atLoc, propertyLoc, true, ObjCImpDecl,
+ Actions.ActOnPropertyImplDecl(getCurScope(), atLoc, propertyLoc, true,
propertyId, propertyIvar, propertyIvarLoc);
if (Tok.isNot(tok::comma))
break;
@@ -1509,8 +1612,9 @@ Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
ConsumeToken(); // consume dynamic
while (true) {
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCPropertyDefinition(getCurScope(), ObjCImpDecl);
- ConsumeCodeCompletionToken();
+ Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
+ cutOffParsing();
+ return 0;
}
if (Tok.isNot(tok::identifier)) {
@@ -1521,7 +1625,7 @@ Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
IdentifierInfo *propertyId = Tok.getIdentifierInfo();
SourceLocation propertyLoc = ConsumeToken(); // consume property name
- Actions.ActOnPropertyImplDecl(getCurScope(), atLoc, propertyLoc, false, ObjCImpDecl,
+ Actions.ActOnPropertyImplDecl(getCurScope(), atLoc, propertyLoc, false,
propertyId, 0, SourceLocation());
if (Tok.isNot(tok::comma))
@@ -1560,31 +1664,46 @@ Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
Diag(Tok, diag::err_expected_lparen_after) << "@synchronized";
return StmtError();
}
+
+ // The operand is surrounded with parentheses.
ConsumeParen(); // '('
- ExprResult Res(ParseExpression());
- if (Res.isInvalid()) {
- SkipUntil(tok::semi);
- return StmtError();
- }
- if (Tok.isNot(tok::r_paren)) {
- Diag(Tok, diag::err_expected_lbrace);
- return StmtError();
+ ExprResult operand(ParseExpression());
+
+ if (Tok.is(tok::r_paren)) {
+ ConsumeParen(); // ')'
+ } else {
+ if (!operand.isInvalid())
+ Diag(Tok, diag::err_expected_rparen);
+
+ // Skip forward until we see a left brace, but don't consume it.
+ SkipUntil(tok::l_brace, true, true);
}
- ConsumeParen(); // ')'
+
+ // Require a compound statement.
if (Tok.isNot(tok::l_brace)) {
- Diag(Tok, diag::err_expected_lbrace);
+ if (!operand.isInvalid())
+ Diag(Tok, diag::err_expected_lbrace);
return StmtError();
}
- // Enter a scope to hold everything within the compound stmt. Compound
- // statements can always hold declarations.
- ParseScope BodyScope(this, Scope::DeclScope);
- StmtResult SynchBody(ParseCompoundStatementBody());
+ // Check the @synchronized operand now.
+ if (!operand.isInvalid())
+ operand = Actions.ActOnObjCAtSynchronizedOperand(atLoc, operand.take());
- BodyScope.Exit();
- if (SynchBody.isInvalid())
- SynchBody = Actions.ActOnNullStmt(Tok.getLocation());
- return Actions.ActOnObjCAtSynchronizedStmt(atLoc, Res.take(), SynchBody.take());
+ // Parse the compound statement within a new scope.
+ ParseScope bodyScope(this, Scope::DeclScope);
+ StmtResult body(ParseCompoundStatementBody());
+ bodyScope.Exit();
+
+ // If there was a semantic or parse error earlier with the
+ // operand, fail now.
+ if (operand.isInvalid())
+ return StmtError();
+
+ if (body.isInvalid())
+ body = Actions.ActOnNullStmt(Tok.getLocation());
+
+ return Actions.ActOnObjCAtSynchronizedStmt(atLoc, operand.get(), body.get());
}
/// objc-try-catch-statement:
@@ -1724,7 +1843,7 @@ Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) {
/// objc-method-def: objc-method-proto ';'[opt] '{' body '}'
///
Decl *Parser::ParseObjCMethodDefinition() {
- Decl *MDecl = ParseObjCMethodPrototype(ObjCImpDecl);
+ Decl *MDecl = ParseObjCMethodPrototype();
PrettyDeclStackTraceEntry CrashInfo(Actions, MDecl, Tok.getLocation(),
"parsing Objective-C method");
@@ -1749,42 +1868,26 @@ Decl *Parser::ParseObjCMethodDefinition() {
if (Tok.isNot(tok::l_brace))
return 0;
}
- SourceLocation BraceLoc = Tok.getLocation();
-
- // Enter a scope for the method body.
- ParseScope BodyScope(this,
- Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope);
-
- // Tell the actions module that we have entered a method definition with the
- // specified Declarator for the method.
- Actions.ActOnStartOfObjCMethodDef(getCurScope(), MDecl);
-
- if (PP.isCodeCompletionEnabled()) {
- if (trySkippingFunctionBodyForCodeCompletion()) {
- BodyScope.Exit();
- return Actions.ActOnFinishFunctionBody(MDecl, 0);
- }
- }
-
- StmtResult FnBody(ParseCompoundStatementBody());
-
- // If the function body could not be parsed, make a bogus compoundstmt.
- if (FnBody.isInvalid())
- FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc,
- MultiStmtArg(Actions), false);
-
- // Leave the function body scope.
- BodyScope.Exit();
-
- // TODO: Pass argument information.
- Actions.ActOnFinishFunctionBody(MDecl, FnBody.take());
+ // Allow the rest of sema to find private method decl implementations.
+ if (MDecl)
+ Actions.AddAnyMethodToGlobalPool(MDecl);
+
+ // Consume the tokens and store them for later parsing.
+ LexedMethod* LM = new LexedMethod(this, MDecl);
+ LateParsedObjCMethods.push_back(LM);
+ CachedTokens &Toks = LM->Toks;
+ // Begin by storing the '{' token.
+ Toks.push_back(Tok);
+ ConsumeBrace();
+ // Consume everything up to (and including) the matching right brace.
+ ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
return MDecl;
}
StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCAtStatement(getCurScope());
- ConsumeCodeCompletionToken();
+ cutOffParsing();
return StmtError();
}
@@ -1818,7 +1921,7 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
switch (Tok.getKind()) {
case tok::code_completion:
Actions.CodeCompleteObjCAtExpression(getCurScope());
- ConsumeCodeCompletionToken();
+ cutOffParsing();
return ExprError();
case tok::string_literal: // primary-expression: string-literal
@@ -1984,8 +2087,7 @@ ExprResult Parser::ParseObjCMessageExpression() {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCMessageReceiver(getCurScope());
- ConsumeCodeCompletionToken();
- SkipUntil(tok::r_square);
+ cutOffParsing();
return ExprError();
}
@@ -2116,22 +2218,23 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
else
Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
0, 0, false);
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return ExprError();
}
// Parse objc-selector
SourceLocation Loc;
IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc);
- SourceLocation SelectorLoc = Loc;
-
- llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
+ SmallVector<IdentifierInfo *, 12> KeyIdents;
+ SmallVector<SourceLocation, 12> KeyLocs;
ExprVector KeyExprs(Actions);
if (Tok.is(tok::colon)) {
while (1) {
// Each iteration parses a single keyword argument.
KeyIdents.push_back(selIdent);
+ KeyLocs.push_back(Loc);
if (Tok.isNot(tok::colon)) {
Diag(Tok, diag::err_expected_colon);
@@ -2162,8 +2265,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
KeyIdents.size(),
/*AtArgumentEpression=*/true);
- ConsumeCodeCompletionToken();
- SkipUntil(tok::r_square);
+ cutOffParsing();
return ExprError();
}
@@ -2196,8 +2298,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
KeyIdents.data(),
KeyIdents.size(),
/*AtArgumentEpression=*/false);
- ConsumeCodeCompletionToken();
- SkipUntil(tok::r_square);
+ cutOffParsing();
return ExprError();
}
@@ -2248,24 +2349,26 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
SourceLocation RBracLoc = ConsumeBracket(); // consume ']'
unsigned nKeys = KeyIdents.size();
- if (nKeys == 0)
+ if (nKeys == 0) {
KeyIdents.push_back(selIdent);
+ KeyLocs.push_back(Loc);
+ }
Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]);
if (SuperLoc.isValid())
return Actions.ActOnSuperMessage(getCurScope(), SuperLoc, Sel,
- LBracLoc, SelectorLoc, RBracLoc,
+ LBracLoc, KeyLocs, RBracLoc,
MultiExprArg(Actions,
KeyExprs.take(),
KeyExprs.size()));
else if (ReceiverType)
return Actions.ActOnClassMessage(getCurScope(), ReceiverType, Sel,
- LBracLoc, SelectorLoc, RBracLoc,
+ LBracLoc, KeyLocs, RBracLoc,
MultiExprArg(Actions,
KeyExprs.take(),
KeyExprs.size()));
return Actions.ActOnInstanceMessage(getCurScope(), ReceiverExpr, Sel,
- LBracLoc, SelectorLoc, RBracLoc,
+ LBracLoc, KeyLocs, RBracLoc,
MultiExprArg(Actions,
KeyExprs.take(),
KeyExprs.size()));
@@ -2278,7 +2381,7 @@ ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
// @"foo" @"bar" is a valid concatenated string. Eat any subsequent string
// expressions. At this point, we know that the only valid thing that starts
// with '@' is an @"".
- llvm::SmallVector<SourceLocation, 4> AtLocs;
+ SmallVector<SourceLocation, 4> AtLocs;
ExprVector AtStrings(Actions);
AtLocs.push_back(AtLoc);
AtStrings.push_back(Res.release());
@@ -2312,17 +2415,19 @@ Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {
if (Tok.isNot(tok::l_paren))
return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@encode");
- SourceLocation LParenLoc = ConsumeParen();
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
TypeResult Ty = ParseTypeName();
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ T.consumeClose();
if (Ty.isInvalid())
return ExprError();
- return Owned(Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, LParenLoc,
- Ty.get(), RParenLoc));
+ return Owned(Actions.ParseObjCEncodeExpression(AtLoc, EncLoc,
+ T.getOpenLocation(), Ty.get(),
+ T.getCloseLocation()));
}
/// objc-protocol-expression
@@ -2334,7 +2439,8 @@ Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
if (Tok.isNot(tok::l_paren))
return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@protocol");
- SourceLocation LParenLoc = ConsumeParen();
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
if (Tok.isNot(tok::identifier))
return ExprError(Diag(Tok, diag::err_expected_ident));
@@ -2342,10 +2448,11 @@ Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
IdentifierInfo *protocolId = Tok.getIdentifierInfo();
ConsumeToken();
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ T.consumeClose();
return Owned(Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc,
- LParenLoc, RParenLoc));
+ T.getOpenLocation(),
+ T.getCloseLocation()));
}
/// objc-selector-expression
@@ -2356,15 +2463,16 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
if (Tok.isNot(tok::l_paren))
return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@selector");
- llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
- SourceLocation LParenLoc = ConsumeParen();
+ SmallVector<IdentifierInfo *, 12> KeyIdents;
SourceLocation sLoc;
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
+
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents.data(),
KeyIdents.size());
- ConsumeCodeCompletionToken();
- MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ cutOffParsing();
return ExprError();
}
@@ -2391,8 +2499,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents.data(),
KeyIdents.size());
- ConsumeCodeCompletionToken();
- MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ cutOffParsing();
return ExprError();
}
@@ -2404,8 +2511,52 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
break;
}
}
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ T.consumeClose();
Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]);
return Owned(Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc,
- LParenLoc, RParenLoc));
+ T.getOpenLocation(),
+ T.getCloseLocation()));
}
+
+Decl *Parser::ParseLexedObjCMethodDefs(LexedMethod &LM) {
+
+ assert(!LM.Toks.empty() && "ParseLexedObjCMethodDef - Empty body!");
+ // Append the current token at the end of the new token stream so that it
+ // doesn't get lost.
+ LM.Toks.push_back(Tok);
+ PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false);
+
+ // MDecl might be null due to error in method prototype, etc.
+ Decl *MDecl = LM.D;
+ // Consume the previously pushed token.
+ ConsumeAnyToken();
+
+ assert(Tok.is(tok::l_brace) && "Inline objective-c method not starting with '{'");
+ SourceLocation BraceLoc = Tok.getLocation();
+ // Enter a scope for the method body.
+ ParseScope BodyScope(this,
+ Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope);
+
+ // Tell the actions module that we have entered a method definition with the
+ // specified Declarator for the method.
+ Actions.ActOnStartOfObjCMethodDef(getCurScope(), MDecl);
+
+ if (PP.isCodeCompletionEnabled()) {
+ if (trySkippingFunctionBodyForCodeCompletion()) {
+ BodyScope.Exit();
+ return Actions.ActOnFinishFunctionBody(MDecl, 0);
+ }
+ }
+
+ StmtResult FnBody(ParseCompoundStatementBody());
+
+ // If the function body could not be parsed, make a bogus compoundstmt.
+ if (FnBody.isInvalid())
+ FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc,
+ MultiStmtArg(Actions), false);
+
+ // Leave the function body scope.
+ BodyScope.Exit();
+
+ return Actions.ActOnFinishFunctionBody(MDecl, FnBody.take());
+}
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index c30ab75b76e8..2ccb6ea88d0f 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -38,7 +38,7 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP,
SourceLocation VisLoc = VisTok.getLocation();
Token Tok;
- PP.Lex(Tok);
+ PP.LexUnexpandedToken(Tok);
const IdentifierInfo *PushPop = Tok.getIdentifierInfo();
@@ -49,20 +49,20 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP,
VisType = 0;
} else if (PushPop && PushPop->isStr("push")) {
IsPush = true;
- PP.Lex(Tok);
+ PP.LexUnexpandedToken(Tok);
if (Tok.isNot(tok::l_paren)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen)
<< "visibility";
return;
}
- PP.Lex(Tok);
+ PP.LexUnexpandedToken(Tok);
VisType = Tok.getIdentifierInfo();
if (!VisType) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
<< "visibility";
return;
}
- PP.Lex(Tok);
+ PP.LexUnexpandedToken(Tok);
if (Tok.isNot(tok::r_paren)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen)
<< "visibility";
@@ -73,7 +73,7 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP,
<< "visibility";
return;
}
- PP.Lex(Tok);
+ PP.LexUnexpandedToken(Tok);
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
<< "visibility";
@@ -297,7 +297,7 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP,
}
// Lex the declaration reference(s).
- llvm::SmallVector<Token, 5> Identifiers;
+ SmallVector<Token, 5> Identifiers;
SourceLocation RParenLoc;
bool LexID = true;
@@ -451,8 +451,11 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP,
}
OpenCLOptions &f = Actions.getOpenCLOptions();
- if (ename->isStr("all")) {
-#define OPENCLEXT(nm) f.nm = state;
+ // OpenCL 1.1 9.1: "The all variant sets the behavior for all extensions,
+ // overriding all previously issued extension directives, but only if the
+ // behavior is set to disable."
+ if (state == 0 && ename->isStr("all")) {
+#define OPENCLEXT(nm) f.nm = 0;
#include "clang/Basic/OpenCLExtensions.def"
}
#define OPENCLEXT(nm) else if (ename->isStr(#nm)) { f.nm = state; }
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index b91bca55a9dc..a2b7cdd81b87 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -79,7 +79,7 @@ StmtResult
Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) {
const char *SemiError = 0;
StmtResult Res;
-
+
ParenBraceBracketBalancer BalancerRAIIObj(*this);
ParsedAttributesWithRange attrs(AttrFactory);
@@ -100,20 +100,25 @@ Retry:
case tok::code_completion:
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement);
- ConsumeCodeCompletionToken();
- return ParseStatementOrDeclaration(Stmts, OnlyStatement);
-
+ cutOffParsing();
+ return StmtError();
+
case tok::identifier: {
Token Next = NextToken();
if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement
// identifier ':' statement
return ParseLabeledStatement(attrs);
}
-
+
if (Next.isNot(tok::coloncolon)) {
CXXScopeSpec SS;
IdentifierInfo *Name = Tok.getIdentifierInfo();
SourceLocation NameLoc = Tok.getLocation();
+
+ if (getLang().CPlusPlus)
+ CheckForTemplateAndDigraph(Next, ParsedType(),
+ /*EnteringContext=*/false, *Name, SS);
+
Sema::NameClassification Classification
= Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next);
switch (Classification.getKind()) {
@@ -125,11 +130,11 @@ Retry:
Tok.setKind(Name->getTokenID());
goto Retry;
}
-
+
// Fall through via the normal error path.
// FIXME: This seems like it could only happen for context-sensitive
// keywords.
-
+
case Sema::NC_Error:
// Handle errors here by skipping up to the next semicolon or '}', and
// eat the semicolon if that's what stopped us.
@@ -137,33 +142,33 @@ Retry:
if (Tok.is(tok::semi))
ConsumeToken();
return StmtError();
-
+
case Sema::NC_Unknown:
// Either we don't know anything about this identifier, or we know that
- // we're in a syntactic context we haven't handled yet.
- break;
-
+ // we're in a syntactic context we haven't handled yet.
+ break;
+
case Sema::NC_Type:
Tok.setKind(tok::annot_typename);
setTypeAnnotation(Tok, Classification.getType());
Tok.setAnnotationEndLoc(NameLoc);
PP.AnnotateCachedTokens(Tok);
break;
-
+
case Sema::NC_Expression:
Tok.setKind(tok::annot_primary_expr);
setExprAnnotation(Tok, Classification.getExpression());
Tok.setAnnotationEndLoc(NameLoc);
PP.AnnotateCachedTokens(Tok);
break;
-
+
case Sema::NC_TypeTemplate:
case Sema::NC_FunctionTemplate: {
ConsumeToken(); // the identifier
UnqualifiedId Id;
Id.setIdentifier(Name, NameLoc);
if (AnnotateTemplateIdToken(
- TemplateTy::make(Classification.getTemplateName()),
+ TemplateTy::make(Classification.getTemplateName()),
Classification.getTemplateNameKind(),
SS, Id, SourceLocation(),
/*AllowTypeAnnotation=*/false)) {
@@ -172,10 +177,10 @@ Retry:
SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true);
if (Tok.is(tok::semi))
ConsumeToken();
- return StmtError();
+ return StmtError();
}
-
- // If the next token is '::', jump right into parsing a
+
+ // If the next token is '::', jump right into parsing a
// nested-name-specifier. We don't want to leave the template-id
// hanging.
if (NextToken().is(tok::coloncolon) && TryAnnotateCXXScopeToken(false)){
@@ -184,22 +189,22 @@ Retry:
SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true);
if (Tok.is(tok::semi))
ConsumeToken();
- return StmtError();
+ return StmtError();
}
-
+
// We've annotated a template-id, so try again now.
goto Retry;
}
-
+
case Sema::NC_NestedNameSpecifier:
// FIXME: Implement this!
break;
}
}
-
+
// Fall through
}
-
+
default: {
if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
@@ -224,10 +229,8 @@ Retry:
case tok::l_brace: // C99 6.8.2: compound-statement
return ParseCompoundStatement(attrs);
case tok::semi: { // C99 6.8.3p3: expression[opt] ';'
- SourceLocation LeadingEmptyMacroLoc;
- if (Tok.hasLeadingEmptyMacro())
- LeadingEmptyMacroLoc = PP.getLastEmptyMacroExpansionLoc();
- return Actions.ActOnNullStmt(ConsumeToken(), LeadingEmptyMacroLoc);
+ bool HasLeadingEmptyMacro = Tok.hasLeadingEmptyMacro();
+ return Actions.ActOnNullStmt(ConsumeToken(), HasLeadingEmptyMacro);
}
case tok::kw_if: // C99 6.8.4.1: if-statement
@@ -297,7 +300,7 @@ Retry:
StmtResult Parser::ParseExprStatement(ParsedAttributes &Attrs) {
// If a case keyword is missing, this is where it should be inserted.
Token OldToken = Tok;
-
+
// FIXME: Use the attributes
// expression[opt] ';'
ExprResult Expr(ParseExpression());
@@ -310,18 +313,18 @@ StmtResult Parser::ParseExprStatement(ParsedAttributes &Attrs) {
ConsumeToken();
return StmtError();
}
-
+
if (Tok.is(tok::colon) && getCurScope()->isSwitchScope() &&
Actions.CheckCaseExpression(Expr.get())) {
// If a constant expression is followed by a colon inside a switch block,
// suggest a missing case keyword.
Diag(OldToken, diag::err_expected_case_before_expression)
<< FixItHint::CreateInsertion(OldToken.getLocation(), "case ");
-
+
// Recover parsing as a case statement.
return ParseCaseStatement(Attrs, /*MissingCase=*/true, Expr);
}
-
+
// Otherwise, eat the semicolon.
ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get()));
@@ -458,12 +461,12 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &attrs) {
// Broken substmt shouldn't prevent the label from being added to the AST.
if (SubStmt.isInvalid())
SubStmt = Actions.ActOnNullStmt(ColonLoc);
-
+
LabelDecl *LD = Actions.LookupOrCreateLabel(IdentTok.getIdentifierInfo(),
IdentTok.getLocation());
if (AttributeList *Attrs = attrs.getList())
Actions.ProcessDeclAttributeList(Actions.CurScope, LD, Attrs);
-
+
return Actions.ActOnLabelStmt(IdentTok.getLocation(), LD, ColonLoc,
SubStmt.get());
}
@@ -499,7 +502,7 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase,
// DeepestParsedCaseStmt - This is the deepest statement we have parsed, which
// gets updated each time a new case is parsed, and whose body is unset so
// far. When parsing 'case 4', this is the 'case 3' node.
- StmtTy *DeepestParsedCaseStmt = 0;
+ Stmt *DeepestParsedCaseStmt = 0;
// While we have case statements, eat and stack them.
SourceLocation ColonLoc;
@@ -509,14 +512,15 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteCase(getCurScope());
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return StmtError();
}
-
+
/// We don't want to treat 'case x : y' as a potential typo for 'case x::y'.
/// Disable this form of error recovery while we're parsing the case
/// expression.
ColonProtectionRAIIObject ColonProtection(*this);
-
+
ExprResult LHS(MissingCase ? Expr : ParseConstantExpression());
MissingCase = false;
if (LHS.isInvalid()) {
@@ -537,7 +541,7 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase,
return StmtError();
}
}
-
+
ColonProtection.restore();
if (Tok.is(tok::colon)) {
@@ -554,7 +558,7 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase,
<< FixItHint::CreateInsertion(ExpectedLoc, ":");
ColonLoc = ExpectedLoc;
}
-
+
StmtResult Case =
Actions.ActOnCaseStmt(CaseLoc, LHS.get(), DotDotDotLoc,
RHS.get(), ColonLoc);
@@ -631,7 +635,7 @@ StmtResult Parser::ParseDefaultStatement(ParsedAttributes &attrs) {
<< FixItHint::CreateInsertion(ExpectedLoc, ":");
ColonLoc = ExpectedLoc;
}
-
+
// Diagnose the common error "switch (X) {... default: }", which is not valid.
if (Tok.is(tok::r_brace)) {
SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
@@ -704,8 +708,9 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
Tok.getLocation(),
"in compound statement ('{}')");
InMessageExpressionRAIIObject InMessage(*this, false);
-
- SourceLocation LBraceLoc = ConsumeBrace(); // eat the '{'.
+ BalancedDelimiterTracker T(*this, tok::l_brace);
+ if (T.consumeOpen())
+ return StmtError();
StmtVector Stmts(Actions);
@@ -714,40 +719,40 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
while (Tok.is(tok::kw___label__)) {
SourceLocation LabelLoc = ConsumeToken();
Diag(LabelLoc, diag::ext_gnu_local_label);
-
- llvm::SmallVector<Decl *, 8> DeclsInGroup;
+
+ SmallVector<Decl *, 8> DeclsInGroup;
while (1) {
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
break;
}
-
+
IdentifierInfo *II = Tok.getIdentifierInfo();
SourceLocation IdLoc = ConsumeToken();
DeclsInGroup.push_back(Actions.LookupOrCreateLabel(II, IdLoc, LabelLoc));
-
+
if (!Tok.is(tok::comma))
break;
ConsumeToken();
}
-
+
DeclSpec DS(AttrFactory);
DeclGroupPtrTy Res = Actions.FinalizeDeclaratorGroup(getCurScope(), DS,
DeclsInGroup.data(), DeclsInGroup.size());
StmtResult R = Actions.ActOnDeclStmt(Res, LabelLoc, Tok.getLocation());
-
+
ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration);
if (R.isUsable())
Stmts.push_back(R.release());
}
-
+
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
if (Tok.is(tok::annot_pragma_unused)) {
HandlePragmaUnused();
continue;
}
- if (getLang().Microsoft && (Tok.is(tok::kw___if_exists) ||
+ if (getLang().MicrosoftExt && (Tok.is(tok::kw___if_exists) ||
Tok.is(tok::kw___if_not_exists))) {
ParseMicrosoftIfExistsStatement(Stmts);
continue;
@@ -803,13 +808,15 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
// 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(LBraceLoc, diag::note_matching) << "{";
+ Diag(T.getOpenLocation(), diag::note_matching) << "{";
return StmtError();
}
- SourceLocation RBraceLoc = ConsumeBrace();
- return Actions.ActOnCompoundStmt(LBraceLoc, RBraceLoc, move_arg(Stmts),
- isStmtExpr);
+ if (T.consumeClose())
+ return StmtError();
+
+ return Actions.ActOnCompoundStmt(T.getOpenLocation(), T.getCloseLocation(),
+ move_arg(Stmts), isStmtExpr);
}
/// ParseParenExprOrCondition:
@@ -827,13 +834,15 @@ bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult,
Decl *&DeclResult,
SourceLocation Loc,
bool ConvertToBoolean) {
- SourceLocation LParenLoc = ConsumeParen();
- if (getLang().CPlusPlus)
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
+
+ if (getLang().CPlusPlus)
ParseCXXCondition(ExprResult, DeclResult, Loc, ConvertToBoolean);
else {
ExprResult = ParseExpression();
DeclResult = 0;
-
+
// If required, convert to a boolean value.
if (!ExprResult.isInvalid() && ConvertToBoolean)
ExprResult
@@ -852,7 +861,7 @@ bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult,
}
// Otherwise the condition is valid or the rparen is present.
- MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ T.consumeClose();
return false;
}
@@ -950,9 +959,13 @@ StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs) {
C99orCXX && Tok.isNot(tok::l_brace));
ElseStmt = ParseStatement();
-
+
// Pop the 'else' scope if needed.
InnerScope.Exit();
+ } else if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteAfterIf(getCurScope());
+ cutOffParsing();
+ return StmtError();
}
IfScope.Exit();
@@ -1027,7 +1040,7 @@ StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) {
= Actions.ActOnStartOfSwitchStmt(SwitchLoc, Cond.get(), CondVar);
if (Switch.isInvalid()) {
- // Skip the switch body.
+ // Skip the switch body.
// FIXME: This is not optimal recovery, but parsing the body is more
// dangerous due to the presence of case and default statements, which
// will have no place to connect back with the switch.
@@ -1038,7 +1051,7 @@ StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) {
SkipUntil(tok::semi);
return move(Switch);
}
-
+
// C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if
// there is no compound stmt. C90 does not have this clause. We only do this
// if the body isn't a compound statement to avoid push/pop in common cases.
@@ -1063,7 +1076,7 @@ StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) {
if (Body.isInvalid())
// FIXME: Remove the case statement list from the Switch statement.
Body = Actions.ActOnNullStmt(Tok.getLocation());
-
+
return Actions.ActOnFinishSwitchStmt(SwitchLoc, Switch.get(), Body.get());
}
@@ -1196,16 +1209,17 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) {
}
// Parse the parenthesized condition.
- SourceLocation LPLoc = ConsumeParen();
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
ExprResult Cond = ParseExpression();
- SourceLocation RPLoc = MatchRHSPunctuation(tok::r_paren, LPLoc);
+ T.consumeClose();
DoScope.Exit();
if (Cond.isInvalid() || Body.isInvalid())
return StmtError();
- return Actions.ActOnDoStmt(DoLoc, Body.get(), WhileLoc, LPLoc,
- Cond.get(), RPLoc);
+ return Actions.ActOnDoStmt(DoLoc, Body.get(), WhileLoc, T.getOpenLocation(),
+ Cond.get(), T.getCloseLocation());
}
/// ParseForStatement
@@ -1265,7 +1279,9 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
ParseScope ForScope(this, ScopeFlags);
- SourceLocation LParenLoc = ConsumeParen();
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
+
ExprResult Value;
bool ForEach = false, ForRange = false;
@@ -1276,14 +1292,15 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
ForRangeInit ForRangeInit;
FullExprArg ThirdPart(Actions);
Decl *SecondVar = 0;
-
+
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteOrdinaryName(getCurScope(),
+ Actions.CodeCompleteOrdinaryName(getCurScope(),
C99orCXXorObjC? Sema::PCC_ForInit
: Sema::PCC_Expression);
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return StmtError();
}
-
+
// Parse the first part of the for specifier.
if (Tok.is(tok::semi)) { // for (;
// no first part, eat the ';'.
@@ -1302,13 +1319,16 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
StmtVector Stmts(Actions);
- DeclGroupPtrTy DG = ParseSimpleDeclaration(Stmts, Declarator::ForContext,
+ DeclGroupPtrTy DG = ParseSimpleDeclaration(Stmts, Declarator::ForContext,
DeclEnd, attrs, false,
MightBeForRangeStmt ?
&ForRangeInit : 0);
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
if (ForRangeInit.ParsedForRangeDecl()) {
+ if (!getLang().CPlusPlus0x)
+ Diag(ForRangeInit.ColonLoc, diag::ext_for_range);
+
ForRange = true;
} else if (Tok.is(tok::semi)) { // for (int x = 4;
ConsumeToken();
@@ -1316,10 +1336,11 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
Actions.ActOnForEachDeclStmt(DG);
// ObjC: for (id x in expr)
ConsumeToken(); // consume 'in'
-
+
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCForCollection(getCurScope(), DG);
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return StmtError();
}
Collection = ParseExpression();
} else {
@@ -1342,10 +1363,11 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
ConsumeToken();
} else if (ForEach) {
ConsumeToken(); // consume 'in'
-
+
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCForCollection(getCurScope(), DeclGroupPtrTy());
- ConsumeCodeCompletionToken();
+ cutOffParsing();
+ return StmtError();
}
Collection = ParseExpression();
} else {
@@ -1373,7 +1395,7 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
else {
Second = ParseExpression();
if (!Second.isInvalid())
- Second = Actions.ActOnBooleanCondition(getCurScope(), ForLoc,
+ Second = Actions.ActOnBooleanCondition(getCurScope(), ForLoc,
Second.get());
}
SecondPartIsInvalid = Second.isInvalid();
@@ -1399,18 +1421,27 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
}
}
// Match the ')'.
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ T.consumeClose();
// We need to perform most of the semantic analysis for a C++0x for-range
// statememt before parsing the body, in order to be able to deduce the type
// of an auto-typed loop variable.
StmtResult ForRangeStmt;
- if (ForRange)
- ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, LParenLoc,
+ if (ForRange) {
+ ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, T.getOpenLocation(),
FirstPart.take(),
ForRangeInit.ColonLoc,
ForRangeInit.RangeExpr.get(),
- RParenLoc);
+ T.getCloseLocation());
+
+
+ // Similarly, we need to do the semantic analysis for a for-range
+ // statement immediately in order to close over temporaries correctly.
+ } else if (ForEach) {
+ if (!Collection.isInvalid())
+ Collection =
+ Actions.ActOnObjCForCollectionOperand(ForLoc, Collection.take());
+ }
// C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if
// there is no compound stmt. C90 does not have this clause. We only do this
@@ -1439,18 +1470,18 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
return StmtError();
if (ForEach)
- // FIXME: It isn't clear how to communicate the late destruction of
- // C++ temporaries used to create the collection.
- return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc,
- FirstPart.take(),
- Collection.take(), RParenLoc,
- Body.take());
+ return Actions.ActOnObjCForCollectionStmt(ForLoc, T.getOpenLocation(),
+ FirstPart.take(),
+ Collection.take(),
+ T.getCloseLocation(),
+ Body.take());
if (ForRange)
return Actions.FinishCXXForRangeStmt(ForRangeStmt.take(), Body.take());
- return Actions.ActOnForStmt(ForLoc, LParenLoc, FirstPart.take(), SecondPart,
- SecondVar, ThirdPart, RParenLoc, Body.take());
+ return Actions.ActOnForStmt(ForLoc, T.getOpenLocation(), FirstPart.take(),
+ SecondPart, SecondVar, ThirdPart,
+ T.getCloseLocation(), Body.take());
}
/// ParseGotoStatement
@@ -1529,11 +1560,10 @@ StmtResult Parser::ParseReturnStatement(ParsedAttributes &attrs) {
if (Tok.isNot(tok::semi)) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteReturn(getCurScope());
- ConsumeCodeCompletionToken();
- SkipUntil(tok::semi, false, true);
+ cutOffParsing();
return StmtError();
}
-
+
// FIXME: This is a hack to allow something like C++0x's generalized
// initializer lists, but only enough of this feature to allow Clang to
// parse libstdc++ 4.5's headers.
@@ -1552,30 +1582,105 @@ StmtResult Parser::ParseReturnStatement(ParsedAttributes &attrs) {
return Actions.ActOnReturnStmt(ReturnLoc, R.take());
}
-/// FuzzyParseMicrosoftAsmStatement. When -fms-extensions is enabled, this
-/// routine is called to skip/ignore tokens that comprise the MS asm statement.
-StmtResult Parser::FuzzyParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
- SourceLocation EndLoc;
- if (Tok.is(tok::l_brace)) {
- unsigned short savedBraceCount = BraceCount;
- do {
- EndLoc = Tok.getLocation();
- ConsumeAnyToken();
- } while (BraceCount > savedBraceCount && Tok.isNot(tok::eof));
- } else {
- // From the MS website: If used without braces, the __asm keyword means
- // that the rest of the line is an assembly-language statement.
- SourceManager &SrcMgr = PP.getSourceManager();
+/// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled,
+/// this routine is called to collect the tokens for an MS asm statement.
+StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
+ SourceManager &SrcMgr = PP.getSourceManager();
+ SourceLocation EndLoc = AsmLoc;
+ do {
+ bool InBraces = false;
+ unsigned short savedBraceCount = 0;
+ bool InAsmComment = false;
+ FileID FID;
+ unsigned LineNo = 0;
+ unsigned NumTokensRead = 0;
+ SourceLocation LBraceLoc;
+
+ if (Tok.is(tok::l_brace)) {
+ // Braced inline asm: consume the opening brace.
+ InBraces = true;
+ savedBraceCount = BraceCount;
+ EndLoc = LBraceLoc = ConsumeBrace();
+ ++NumTokensRead;
+ } else {
+ // Single-line inline asm; compute which line it is on.
+ std::pair<FileID, unsigned> ExpAsmLoc =
+ SrcMgr.getDecomposedExpansionLoc(EndLoc);
+ FID = ExpAsmLoc.first;
+ LineNo = SrcMgr.getLineNumber(FID, ExpAsmLoc.second);
+ }
+
SourceLocation TokLoc = Tok.getLocation();
- unsigned LineNo = SrcMgr.getInstantiationLineNumber(TokLoc);
do {
+ // If we hit EOF, we're done, period.
+ if (Tok.is(tok::eof))
+ break;
+ // When we consume the closing brace, we're done.
+ if (InBraces && BraceCount == savedBraceCount)
+ break;
+
+ if (!InAsmComment && Tok.is(tok::semi)) {
+ // A semicolon in an asm is the start of a comment.
+ InAsmComment = true;
+ if (InBraces) {
+ // Compute which line the comment is on.
+ std::pair<FileID, unsigned> ExpSemiLoc =
+ SrcMgr.getDecomposedExpansionLoc(TokLoc);
+ FID = ExpSemiLoc.first;
+ LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second);
+ }
+ } else if (!InBraces || InAsmComment) {
+ // If end-of-line is significant, check whether this token is on a
+ // new line.
+ std::pair<FileID, unsigned> ExpLoc =
+ SrcMgr.getDecomposedExpansionLoc(TokLoc);
+ if (ExpLoc.first != FID ||
+ SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) {
+ // If this is a single-line __asm, we're done.
+ if (!InBraces)
+ break;
+ // We're no longer in a comment.
+ InAsmComment = false;
+ } else if (!InAsmComment && Tok.is(tok::r_brace)) {
+ // Single-line asm always ends when a closing brace is seen.
+ // FIXME: This is compatible with Apple gcc's -fasm-blocks; what
+ // does MSVC do here?
+ break;
+ }
+ }
+
+ // Consume the next token; make sure we don't modify the brace count etc.
+ // if we are in a comment.
EndLoc = TokLoc;
- ConsumeAnyToken();
+ if (InAsmComment)
+ PP.Lex(Tok);
+ else
+ ConsumeAnyToken();
TokLoc = Tok.getLocation();
- } while ((SrcMgr.getInstantiationLineNumber(TokLoc) == LineNo) &&
- Tok.isNot(tok::r_brace) && Tok.isNot(tok::semi) &&
- Tok.isNot(tok::eof));
- }
+ ++NumTokensRead;
+ } while (1);
+
+ if (InBraces && BraceCount != savedBraceCount) {
+ // __asm without closing brace (this can happen at EOF).
+ Diag(Tok, diag::err_expected_rbrace);
+ Diag(LBraceLoc, diag::note_matching) << "{";
+ return StmtError();
+ } else if (NumTokensRead == 0) {
+ // Empty __asm.
+ Diag(Tok, diag::err_expected_lbrace);
+ return StmtError();
+ }
+ // Multiple adjacent asm's form together into a single asm statement
+ // in the AST.
+ if (!Tok.is(tok::kw_asm))
+ break;
+ EndLoc = ConsumeToken();
+ } while (1);
+ // FIXME: Need to actually grab the data and pass it on to Sema. Ideally,
+ // what Sema wants is a string of the entire inline asm, with one instruction
+ // per line and all the __asm keywords stripped out, and a way of mapping
+ // from any character of that string to its location in the original source
+ // code. I'm not entirely sure how to go about that, though.
Token t;
t.setKind(tok::string_literal);
t.setLiteralData("\"/*FIXME: not done*/\"");
@@ -1611,20 +1716,24 @@ StmtResult Parser::FuzzyParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
/// asm-clobbers ',' asm-string-literal
///
/// [MS] ms-asm-statement:
-/// '__asm' assembly-instruction ';'[opt]
-/// '__asm' '{' assembly-instruction-list '}' ';'[opt]
+/// ms-asm-block
+/// ms-asm-block ms-asm-statement
+///
+/// [MS] ms-asm-block:
+/// '__asm' ms-asm-line '\n'
+/// '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt]
///
-/// [MS] assembly-instruction-list:
-/// assembly-instruction ';'[opt]
-/// assembly-instruction-list ';' assembly-instruction ';'[opt]
+/// [MS] ms-asm-instruction-block
+/// ms-asm-line
+/// ms-asm-line '\n' ms-asm-instruction-block
///
StmtResult Parser::ParseAsmStatement(bool &msAsm) {
assert(Tok.is(tok::kw_asm) && "Not an asm stmt");
SourceLocation AsmLoc = ConsumeToken();
- if (getLang().Microsoft && Tok.isNot(tok::l_paren) && !isTypeQualifier()) {
+ if (getLang().MicrosoftExt && Tok.isNot(tok::l_paren) && !isTypeQualifier()) {
msAsm = true;
- return FuzzyParseMicrosoftAsmStatement(AsmLoc);
+ return ParseMicrosoftAsmStatement(AsmLoc);
}
DeclSpec DS(AttrFactory);
SourceLocation Loc = Tok.getLocation();
@@ -1643,25 +1752,26 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
SkipUntil(tok::r_paren);
return StmtError();
}
- Loc = ConsumeParen();
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
ExprResult AsmString(ParseAsmStringLiteral());
if (AsmString.isInvalid())
return StmtError();
- llvm::SmallVector<IdentifierInfo *, 4> Names;
+ SmallVector<IdentifierInfo *, 4> Names;
ExprVector Constraints(Actions);
ExprVector Exprs(Actions);
ExprVector Clobbers(Actions);
if (Tok.is(tok::r_paren)) {
// We have a simple asm expression like 'asm("foo")'.
- SourceLocation RParenLoc = ConsumeParen();
+ T.consumeClose();
return Actions.ActOnAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile,
- /*NumOutputs*/ 0, /*NumInputs*/ 0, 0,
+ /*NumOutputs*/ 0, /*NumInputs*/ 0, 0,
move_arg(Constraints), move_arg(Exprs),
AsmString.take(), move_arg(Clobbers),
- RParenLoc);
+ T.getCloseLocation());
}
// Parse Outputs, if present.
@@ -1670,12 +1780,12 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
// In C++ mode, parse "::" like ": :".
AteExtraColon = Tok.is(tok::coloncolon);
ConsumeToken();
-
+
if (!AteExtraColon &&
ParseAsmOperandsOpt(Names, Constraints, Exprs))
return StmtError();
}
-
+
unsigned NumOutputs = Names.size();
// Parse Inputs, if present.
@@ -1688,7 +1798,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
AteExtraColon = Tok.is(tok::coloncolon);
ConsumeToken();
}
-
+
if (!AteExtraColon &&
ParseAsmOperandsOpt(Names, Constraints, Exprs))
return StmtError();
@@ -1721,12 +1831,12 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
}
}
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, Loc);
+ T.consumeClose();
return Actions.ActOnAsmStmt(AsmLoc, false, isVolatile,
NumOutputs, NumInputs, Names.data(),
move_arg(Constraints), move_arg(Exprs),
AsmString.take(), move_arg(Clobbers),
- RParenLoc);
+ T.getCloseLocation());
}
/// ParseAsmOperands - Parse the asm-operands production as used by
@@ -1742,9 +1852,9 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
///
//
// FIXME: Avoid unnecessary std::string trashing.
-bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
- llvm::SmallVectorImpl<ExprTy *> &Constraints,
- llvm::SmallVectorImpl<ExprTy *> &Exprs) {
+bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
+ SmallVectorImpl<Expr *> &Constraints,
+ SmallVectorImpl<Expr *> &Exprs) {
// 'asm-operands' isn't present?
if (!isTokenStringLiteral() && Tok.isNot(tok::l_square))
return false;
@@ -1752,7 +1862,8 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
while (1) {
// Read the [id] if present.
if (Tok.is(tok::l_square)) {
- SourceLocation Loc = ConsumeBracket();
+ BalancedDelimiterTracker T(*this, tok::l_square);
+ T.consumeOpen();
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
@@ -1764,7 +1875,7 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
ConsumeToken();
Names.push_back(II);
- MatchRHSPunctuation(tok::r_square, Loc);
+ T.consumeClose();
} else
Names.push_back(0);
@@ -1782,9 +1893,10 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
}
// Read the parenthesized expression.
- SourceLocation OpenLoc = ConsumeParen();
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
ExprResult Res(ParseExpression());
- MatchRHSPunctuation(tok::r_paren, OpenLoc);
+ T.consumeClose();
if (Res.isInvalid()) {
SkipUntil(tok::r_paren);
return true;
@@ -1808,7 +1920,7 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
return Actions.ActOnFinishFunctionBody(Decl, 0);
}
}
-
+
PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc,
"parsing function body");
@@ -1841,6 +1953,8 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) {
// Constructor initializer list?
if (Tok.is(tok::colon))
ParseConstructorInitializer(Decl);
+ else
+ Actions.ActOnDefaultCtorInitializers(Decl);
if (PP.isCodeCompletionEnabled()) {
if (trySkippingFunctionBodyForCodeCompletion()) {
@@ -1977,8 +2091,8 @@ StmtResult Parser::ParseCXXCatchBlock() {
SourceLocation CatchLoc = ConsumeToken();
- SourceLocation LParenLoc = Tok.getLocation();
- if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen))
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.expectAndConsume(diag::err_expected_lparen))
return StmtError();
// C++ 3.3.2p3:
@@ -1999,7 +2113,8 @@ StmtResult Parser::ParseCXXCatchBlock() {
} else
ConsumeToken();
- if (MatchRHSPunctuation(tok::r_paren, LParenLoc).isInvalid())
+ T.consumeClose();
+ if (T.getCloseLocation().isInvalid())
return StmtError();
if (Tok.isNot(tok::l_brace))
@@ -2018,7 +2133,7 @@ void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) {
bool Result;
if (ParseMicrosoftIfExistsCondition(Result))
return;
-
+
if (Tok.isNot(tok::l_brace)) {
Diag(Tok, diag::err_expected_lbrace);
return;
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 9eab40a3ecdf..3d68a4ab9db8 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -26,12 +26,16 @@ using namespace clang;
Decl *
Parser::ParseDeclarationStartingWithTemplate(unsigned Context,
SourceLocation &DeclEnd,
- AccessSpecifier AS) {
- if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less))
+ AccessSpecifier AS,
+ AttributeList *AccessAttrs) {
+ ObjCDeclContextSwitch ObjCDC(*this);
+
+ if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) {
return ParseExplicitInstantiation(SourceLocation(), ConsumeToken(),
- DeclEnd);
-
- return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS);
+ DeclEnd);
+ }
+ return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS,
+ AccessAttrs);
}
/// \brief RAII class that manages the template parameter depth.
@@ -75,7 +79,8 @@ namespace {
Decl *
Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
SourceLocation &DeclEnd,
- AccessSpecifier AS) {
+ AccessSpecifier AS,
+ AttributeList *AccessAttrs) {
assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) &&
"Token does not start a template declaration.");
@@ -129,7 +134,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
// Parse the '<' template-parameter-list '>'
SourceLocation LAngleLoc, RAngleLoc;
- llvm::SmallVector<Decl*, 4> TemplateParams;
+ SmallVector<Decl*, 4> TemplateParams;
if (ParseTemplateParameters(Depth, TemplateParams, LAngleLoc,
RAngleLoc)) {
// Skip until the semi-colon or a }.
@@ -159,7 +164,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
isSpecialization,
LastParamListWasEmpty),
ParsingTemplateParams,
- DeclEnd, AS);
+ DeclEnd, AS, AccessAttrs);
}
/// \brief Parse a single declaration that declares a template,
@@ -188,13 +193,15 @@ Parser::ParseSingleDeclarationAfterTemplate(
const ParsedTemplateInfo &TemplateInfo,
ParsingDeclRAIIObject &DiagsFromTParams,
SourceLocation &DeclEnd,
- AccessSpecifier AS) {
+ AccessSpecifier AS,
+ AttributeList *AccessAttrs) {
assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
"Template information required");
if (Context == Declarator::MemberContext) {
// We are parsing a member template.
- ParseCXXClassMemberDeclaration(AS, TemplateInfo, &DiagsFromTParams);
+ ParseCXXClassMemberDeclaration(AS, AccessAttrs, TemplateInfo,
+ &DiagsFromTParams);
return 0;
}
@@ -289,7 +296,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
///
/// \returns true if an error occurred, false otherwise.
bool Parser::ParseTemplateParameters(unsigned Depth,
- llvm::SmallVectorImpl<Decl*> &TemplateParams,
+ SmallVectorImpl<Decl*> &TemplateParams,
SourceLocation &LAngleLoc,
SourceLocation &RAngleLoc) {
// Get the template parameter list.
@@ -322,7 +329,7 @@ bool Parser::ParseTemplateParameters(unsigned Depth,
/// template-parameter-list ',' template-parameter
bool
Parser::ParseTemplateParameterList(unsigned Depth,
- llvm::SmallVectorImpl<Decl*> &TemplateParams) {
+ SmallVectorImpl<Decl*> &TemplateParams) {
while (1) {
if (Decl *TmpParam
= ParseTemplateParameter(Depth, TemplateParams.size())) {
@@ -468,8 +475,10 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
Ellipsis = true;
EllipsisLoc = ConsumeToken();
- if (!getLang().CPlusPlus0x)
- Diag(EllipsisLoc, diag::ext_variadic_templates);
+ Diag(EllipsisLoc,
+ getLang().CPlusPlus0x
+ ? diag::warn_cxx98_compat_variadic_templates
+ : diag::ext_variadic_templates);
}
// Grab the template parameter name (if given)
@@ -516,7 +525,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
// Handle the template <...> part.
SourceLocation TemplateLoc = ConsumeToken();
- llvm::SmallVector<Decl*,8> TemplateParams;
+ SmallVector<Decl*,8> TemplateParams;
SourceLocation LAngleLoc, RAngleLoc;
{
ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
@@ -540,8 +549,10 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
if (Tok.is(tok::ellipsis)) {
EllipsisLoc = ConsumeToken();
- if (!getLang().CPlusPlus0x)
- Diag(EllipsisLoc, diag::ext_variadic_templates);
+ Diag(EllipsisLoc,
+ getLang().CPlusPlus0x
+ ? diag::warn_cxx98_compat_variadic_templates
+ : diag::ext_variadic_templates);
}
// Get the identifier, if given.
@@ -558,7 +569,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
return 0;
}
- TemplateParamsTy *ParamList =
+ TemplateParameterList *ParamList =
Actions.ActOnTemplateParameterList(Depth, SourceLocation(),
TemplateLoc, LAngleLoc,
TemplateParams.data(),
@@ -1157,6 +1168,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
FD = cast<FunctionDecl>(LMT.D);
// Reinject the template parameters.
+ SmallVector<ParseScope*, 4> TemplateParamScopeStack;
DeclaratorDecl* Declarator = dyn_cast<DeclaratorDecl>(FD);
if (Declarator && Declarator->getNumTemplateParameterLists() != 0) {
Actions.ActOnReenterDeclaratorTemplateScope(getCurScope(), Declarator);
@@ -1164,17 +1176,31 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
} else {
Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D);
+ // Get the list of DeclContext to reenter.
+ SmallVector<DeclContext*, 4> DeclContextToReenter;
DeclContext *DD = FD->getLexicalParent();
while (DD && DD->isRecord()) {
- if (ClassTemplatePartialSpecializationDecl* MD =
- dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(DD))
- Actions.ActOnReenterTemplateScope(getCurScope(), MD);
- else if (CXXRecordDecl* MD = dyn_cast_or_null<CXXRecordDecl>(DD))
- Actions.ActOnReenterTemplateScope(getCurScope(),
- MD->getDescribedClassTemplate());
-
+ DeclContextToReenter.push_back(DD);
DD = DD->getLexicalParent();
}
+
+ // Reenter template scopes from outmost to innermost.
+ SmallVector<DeclContext*, 4>::reverse_iterator II =
+ DeclContextToReenter.rbegin();
+ for (; II != DeclContextToReenter.rend(); ++II) {
+ if (ClassTemplatePartialSpecializationDecl* MD =
+ dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(*II)) {
+ TemplateParamScopeStack.push_back(new ParseScope(this,
+ Scope::TemplateParamScope));
+ Actions.ActOnReenterTemplateScope(getCurScope(), MD);
+ } else if (CXXRecordDecl* MD = dyn_cast_or_null<CXXRecordDecl>(*II)) {
+ TemplateParamScopeStack.push_back(new ParseScope(this,
+ Scope::TemplateParamScope,
+ MD->getDescribedClassTemplate() != 0 ));
+ Actions.ActOnReenterTemplateScope(getCurScope(),
+ MD->getDescribedClassTemplate());
+ }
+ }
}
assert(!LMT.Toks.empty() && "Empty body!");
@@ -1205,21 +1231,25 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
if (Tok.is(tok::kw_try)) {
ParseFunctionTryBlock(LMT.D, FnScope);
- return;
- }
- if (Tok.is(tok::colon)) {
- ParseConstructorInitializer(LMT.D);
+ } else {
+ if (Tok.is(tok::colon))
+ ParseConstructorInitializer(LMT.D);
+ else
+ Actions.ActOnDefaultCtorInitializers(LMT.D);
- // Error recovery.
- if (!Tok.is(tok::l_brace)) {
+ if (Tok.is(tok::l_brace)) {
+ ParseFunctionStatementBody(LMT.D, FnScope);
+ Actions.MarkAsLateParsedTemplate(FD, false);
+ } else
Actions.ActOnFinishFunctionBody(LMT.D, 0);
- return;
- }
- } else
- Actions.ActOnDefaultCtorInitializers(LMT.D);
+ }
- ParseFunctionStatementBody(LMT.D, FnScope);
- Actions.MarkAsLateParsedTemplate(FD, false);
+ // Exit scopes.
+ FnScope.Exit();
+ SmallVector<ParseScope*, 4>::reverse_iterator I =
+ TemplateParamScopeStack.rbegin();
+ for (; I != TemplateParamScopeStack.rend(); ++I)
+ delete *I;
DeclGroupPtrTy grp = Actions.ConvertDeclToDeclGroup(LMT.D);
if (grp)
@@ -1229,15 +1259,10 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
/// \brief Lex a delayed template function for late parsing.
void Parser::LexTemplateFunctionForLateParsing(CachedTokens &Toks) {
tok::TokenKind kind = Tok.getKind();
- // We may have a constructor initializer or function-try-block here.
- if (kind == tok::colon || kind == tok::kw_try)
- ConsumeAndStoreUntil(tok::l_brace, Toks);
- else {
- Toks.push_back(Tok);
- ConsumeBrace();
+ if (!ConsumeAndStoreFunctionPrologue(Toks)) {
+ // Consume everything up to (and including) the matching right brace.
+ ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
}
- // Consume everything up to (and including) the matching right brace.
- ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
// If we're in a function-try-block, we need to store all the catch blocks.
if (kind == tok::kw_try) {
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 2ba0fc673f67..d53839f3cb01 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -377,6 +377,7 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
///
/// [C++0x] attribute-specifier:
/// '[' '[' attribute-list ']' ']'
+/// alignment-specifier
///
/// [C++0x] attribute-list:
/// attribute[opt]
@@ -409,6 +410,9 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
/// any token but '(', ')', '[', ']', '{', or '}'
bool Parser::isCXX0XAttributeSpecifier (bool CheckClosing,
tok::TokenKind *After) {
+ if (Tok.is(tok::kw_alignas))
+ return true;
+
if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square))
return false;
@@ -552,7 +556,8 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
Tok.is(tok::kw___cdecl) ||
Tok.is(tok::kw___stdcall) ||
Tok.is(tok::kw___fastcall) ||
- Tok.is(tok::kw___thiscall))
+ Tok.is(tok::kw___thiscall) ||
+ Tok.is(tok::kw___unaligned))
return TPResult::True(); // attributes indicate declaration
TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier);
if (TPR != TPResult::Ambiguous())
@@ -605,8 +610,14 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
// Obviously starts an expression.
case tok::numeric_constant:
case tok::char_constant:
+ case tok::wide_char_constant:
+ case tok::utf16_char_constant:
+ case tok::utf32_char_constant:
case tok::string_literal:
case tok::wide_string_literal:
+ case tok::utf8_string_literal:
+ case tok::utf16_string_literal:
+ case tok::utf32_string_literal:
case tok::l_square:
case tok::l_paren:
case tok::amp:
@@ -674,6 +685,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw_const:
case tok::kw_double:
case tok::kw_enum:
+ case tok::kw_half:
case tok::kw_float:
case tok::kw_int:
case tok::kw_long:
@@ -705,8 +717,10 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw___stdcall:
case tok::kw___fastcall:
case tok::kw___thiscall:
+ case tok::kw___unaligned:
case tok::kw___vector:
case tok::kw___pixel:
+ case tok::kw__Atomic:
return TPResult::False();
default:
@@ -863,6 +877,9 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw_virtual:
case tok::kw_explicit:
+ // Modules
+ case tok::kw___module_private__:
+
// type-specifier:
// simple-type-specifier
// class-specifier
@@ -896,7 +913,9 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw___thiscall:
case tok::kw___w64:
case tok::kw___ptr64:
+ case tok::kw___ptr32:
case tok::kw___forceinline:
+ case tok::kw___unaligned:
return TPResult::True();
// Borland
@@ -976,6 +995,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw___int64:
case tok::kw_signed:
case tok::kw_unsigned:
+ case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
case tok::kw_void:
@@ -1016,6 +1036,10 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw___underlying_type:
return TPResult::True();
+ // C1x _Atomic
+ case tok::kw__Atomic:
+ return TPResult::True();
+
default:
return TPResult::False();
}
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 5c502907bc15..c90964381f8d 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -72,7 +72,7 @@ Parser::Parser(Preprocessor &pp, Sema &actions)
/// If a crash happens while the parser is active, print out a line indicating
/// what the current token is.
-void PrettyStackTraceParserEntry::print(llvm::raw_ostream &OS) const {
+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";
@@ -122,34 +122,6 @@ void Parser::SuggestParentheses(SourceLocation Loc, unsigned DK,
<< FixItHint::CreateInsertion(EndLoc, ")");
}
-/// MatchRHSPunctuation - For punctuation with a LHS and RHS (e.g. '['/']'),
-/// this helper function matches and consumes the specified RHS token if
-/// present. If not present, it emits a corresponding diagnostic indicating
-/// that the parser failed to match the RHS of the token at LHSLoc.
-SourceLocation Parser::MatchRHSPunctuation(tok::TokenKind RHSTok,
- SourceLocation LHSLoc) {
-
- if (Tok.is(RHSTok))
- return ConsumeAnyToken();
-
- SourceLocation R = Tok.getLocation();
- const char *LHSName = "unknown";
- diag::kind DID = diag::err_parse_error;
- switch (RHSTok) {
- default: break;
- case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen; break;
- case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break;
- case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break;
- case tok::greater: LHSName = "<"; DID = diag::err_expected_greater; break;
- case tok::greatergreatergreater:
- LHSName = "<<<"; DID = diag::err_expected_ggg; break;
- }
- Diag(Tok, DID);
- Diag(LHSLoc, diag::note_matching) << LHSName;
- SkipUntil(RHSTok);
- return R;
-}
-
static bool IsCommonTypo(tok::TokenKind ExpectedTok, const Token &Tok) {
switch (ExpectedTok) {
case tok::semi: return Tok.is(tok::colon); // : for ;
@@ -298,6 +270,9 @@ bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks,
case tok::string_literal:
case tok::wide_string_literal:
+ case tok::utf8_string_literal:
+ case tok::utf16_string_literal:
+ case tok::utf32_string_literal:
ConsumeStringToken();
break;
@@ -440,6 +415,7 @@ void Parser::Initialize() {
ObjCTypeQuals[objc_byref] = &PP.getIdentifierTable().get("byref");
}
+ Ident_instancetype = 0;
Ident_final = 0;
Ident_override = 0;
@@ -550,7 +526,12 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
ParsingDeclSpec *DS) {
DelayedCleanupPoint CleanupRAII(TopLevelDeclCleanupPool);
ParenBraceBracketBalancer BalancerRAIIObj(*this);
-
+
+ if (PP.isCodeCompletionReached()) {
+ cutOffParsing();
+ return DeclGroupPtrTy();
+ }
+
Decl *SingleDecl = 0;
switch (Tok.getKind()) {
case tok::semi:
@@ -590,10 +571,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
break;
}
case tok::at:
- // @ is not a legal token unless objc is enabled, no need to check for ObjC.
- /// FIXME: ParseObjCAtDirectives should return a DeclGroup for things like
- /// @class foo, bar;
- SingleDecl = ParseObjCAtDirectives();
+ return ParseObjCAtDirectives();
break;
case tok::minus:
case tok::plus:
@@ -608,8 +586,8 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
Actions.CodeCompleteOrdinaryName(getCurScope(),
ObjCImpDecl? Sema::PCC_ObjCImplementation
: Sema::PCC_Namespace);
- ConsumeCodeCompletionToken();
- return ParseExternalDeclaration(attrs);
+ cutOffParsing();
+ return DeclGroupPtrTy();
case tok::kw_using:
case tok::kw_namespace:
case tok::kw_typedef:
@@ -676,6 +654,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
ParseMicrosoftIfExistsExternalDeclaration();
return DeclGroupPtrTy();
+ case tok::kw___import_module__:
+ return ParseModuleImport();
+
default:
dont_know:
// We can't tell whether this is a function-definition or declaration yet.
@@ -808,6 +789,11 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs,
AccessSpecifier AS) {
ParsingDeclSpec DS(*this);
DS.takeAttributesFrom(attrs);
+ // Must temporarily exit the objective-c container scope for
+ // parsing c constructs and re-enter objc container scope
+ // afterwards.
+ ObjCDeclContextSwitch ObjCDC(*this);
+
return ParseDeclarationOrFunctionDefinition(DS, AS);
}
@@ -877,9 +863,9 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
Scope *ParentScope = getCurScope()->getParent();
+ D.setFunctionDefinition(true);
Decl *DP = Actions.HandleDeclarator(ParentScope, D,
- move(TemplateParameterLists),
- /*IsFunctionDefinition=*/true);
+ move(TemplateParameterLists));
D.complete(DP);
D.getMutableDeclSpec().abort();
@@ -1133,13 +1119,12 @@ Parser::ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
ConsumeToken();
}
- if (Tok.isNot(tok::l_paren)) {
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.consumeOpen()) {
Diag(Tok, diag::err_expected_lparen_after) << "asm";
return ExprError();
}
- Loc = ConsumeParen();
-
ExprResult Result(ParseAsmStringLiteral());
if (Result.isInvalid()) {
@@ -1148,9 +1133,10 @@ Parser::ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
*EndLoc = Tok.getLocation();
ConsumeAnyToken();
} else {
- Loc = MatchRHSPunctuation(tok::r_paren, Loc);
+ // Close the paren and get the location of the end bracket
+ T.consumeClose();
if (EndLoc)
- *EndLoc = Loc;
+ *EndLoc = T.getCloseLocation();
}
return move(Result);
@@ -1190,7 +1176,7 @@ TemplateIdAnnotation *Parser::takeTemplateIdAnnotation(const Token &tok) {
///
/// Note that this routine emits an error if you call it with ::new or ::delete
/// as the current tokens, so only call it in contexts where these are invalid.
-bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
+bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon)
|| Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)) &&
"Cannot be a type or scope token!");
@@ -1208,7 +1194,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
0, /*IsTypename*/true))
return true;
if (!SS.isSet()) {
- if (getLang().Microsoft)
+ if (getLang().MicrosoftExt)
Diag(Tok.getLocation(), diag::warn_expected_qualified_after_typename);
else
Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename);
@@ -1264,13 +1250,18 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
return true;
if (Tok.is(tok::identifier)) {
+ IdentifierInfo *CorrectedII = 0;
// Determine whether the identifier is a type name.
if (ParsedType Ty = Actions.getTypeName(*Tok.getIdentifierInfo(),
Tok.getLocation(), getCurScope(),
&SS, false,
NextToken().is(tok::period),
ParsedType(),
- /*NonTrivialTypeSourceInfo*/true)) {
+ /*NonTrivialTypeSourceInfo*/true,
+ NeedType ? &CorrectedII : NULL)) {
+ // A FixIt was applied as a result of typo correction
+ if (CorrectedII)
+ Tok.setIdentifierInfo(CorrectedII);
// This is a typename. Replace the current token in-place with an
// annotation type token.
Tok.setKind(tok::annot_typename);
@@ -1405,20 +1396,27 @@ bool Parser::isTokenEqualOrMistypedEqualEqual(unsigned DiagID) {
return Tok.is(tok::equal);
}
-void Parser::CodeCompletionRecovery() {
+SourceLocation Parser::handleUnexpectedCodeCompletionToken() {
+ assert(Tok.is(tok::code_completion));
+ PrevTokLocation = Tok.getLocation();
+
for (Scope *S = getCurScope(); S; S = S->getParent()) {
if (S->getFlags() & Scope::FnScope) {
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_RecoveryInFunction);
- return;
+ cutOffParsing();
+ return PrevTokLocation;
}
if (S->getFlags() & Scope::ClassScope) {
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Class);
- return;
+ cutOffParsing();
+ return PrevTokLocation;
}
}
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Namespace);
+ cutOffParsing();
+ return PrevTokLocation;
}
// Anchor the Parser::FieldCallback vtable to this translation unit.
@@ -1463,13 +1461,12 @@ bool Parser::ParseMicrosoftIfExistsCondition(bool& Result) {
Token Condition = Tok;
SourceLocation IfExistsLoc = ConsumeToken();
- SourceLocation LParenLoc = Tok.getLocation();
- if (Tok.isNot(tok::l_paren)) {
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.consumeOpen()) {
Diag(Tok, diag::err_expected_lparen_after) << IfExistsLoc;
SkipUntil(tok::semi);
return true;
}
- ConsumeParen(); // eat the '('.
// Parse nested-name-specifier.
CXXScopeSpec SS;
@@ -1488,7 +1485,8 @@ bool Parser::ParseMicrosoftIfExistsCondition(bool& Result) {
return true;
}
- if (MatchRHSPunctuation(tok::r_paren, LParenLoc).isInvalid())
+ T.consumeClose();
+ if (T.getCloseLocation().isInvalid())
return true;
// Check if the symbol exists.
@@ -1533,3 +1531,86 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
}
ConsumeBrace();
}
+
+Parser::DeclGroupPtrTy Parser::ParseModuleImport() {
+ assert(Tok.is(tok::kw___import_module__) &&
+ "Improper start to module import");
+ SourceLocation ImportLoc = ConsumeToken();
+
+ // Parse the module name.
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok, diag::err_module_expected_ident);
+ SkipUntil(tok::semi);
+ return DeclGroupPtrTy();
+ }
+
+ IdentifierInfo &ModuleName = *Tok.getIdentifierInfo();
+ SourceLocation ModuleNameLoc = ConsumeToken();
+ DeclResult Import = Actions.ActOnModuleImport(ImportLoc, ModuleName, ModuleNameLoc);
+ ExpectAndConsumeSemi(diag::err_module_expected_semi);
+ if (Import.isInvalid())
+ return DeclGroupPtrTy();
+
+ return Actions.ConvertDeclToDeclGroup(Import.get());
+}
+
+bool Parser::BalancedDelimiterTracker::consumeOpen() {
+ // Try to consume the token we are holding
+ if (P.Tok.is(Kind)) {
+ P.QuantityTracker.push(Kind);
+ Cleanup = true;
+ if (P.QuantityTracker.getDepth(Kind) < MaxDepth) {
+ LOpen = P.ConsumeAnyToken();
+ return false;
+ } else {
+ P.Diag(P.Tok, diag::err_parser_impl_limit_overflow);
+ P.SkipUntil(tok::eof);
+ }
+ }
+ return true;
+}
+
+bool Parser::BalancedDelimiterTracker::expectAndConsume(unsigned DiagID,
+ const char *Msg,
+ tok::TokenKind SkipToToc ) {
+ LOpen = P.Tok.getLocation();
+ if (!P.ExpectAndConsume(Kind, DiagID, Msg, SkipToToc)) {
+ P.QuantityTracker.push(Kind);
+ Cleanup = true;
+ if (P.QuantityTracker.getDepth(Kind) < MaxDepth) {
+ return false;
+ } else {
+ P.Diag(P.Tok, diag::err_parser_impl_limit_overflow);
+ P.SkipUntil(tok::eof);
+ }
+ }
+ return true;
+}
+
+bool Parser::BalancedDelimiterTracker::consumeClose() {
+ if (P.Tok.is(Close)) {
+ LClose = P.ConsumeAnyToken();
+ if (Cleanup)
+ P.QuantityTracker.pop(Kind);
+
+ Cleanup = false;
+ return false;
+ } else {
+ const char *LHSName = "unknown";
+ diag::kind DID = diag::err_parse_error;
+ switch (Close) {
+ default: break;
+ case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen; break;
+ case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break;
+ case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break;
+ case tok::greater: LHSName = "<"; DID = diag::err_expected_greater; break;
+ case tok::greatergreatergreater:
+ LHSName = "<<<"; DID = diag::err_expected_ggg; break;
+ }
+ P.Diag(P.Tok, DID);
+ P.Diag(LOpen, diag::note_matching) << LHSName;
+ if (P.SkipUntil(Close))
+ LClose = P.Tok.getLocation();
+ }
+ return true;
+}
diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h
index 3765f92348ea..ef17aee3f512 100644
--- a/lib/Parse/RAIIObjectsForParser.h
+++ b/lib/Parse/RAIIObjectsForParser.h
@@ -30,9 +30,9 @@ namespace clang {
class ExtensionRAIIObject {
void operator=(const ExtensionRAIIObject &); // DO NOT IMPLEMENT
ExtensionRAIIObject(const ExtensionRAIIObject&); // DO NOT IMPLEMENT
- Diagnostic &Diags;
+ DiagnosticsEngine &Diags;
public:
- ExtensionRAIIObject(Diagnostic &diags) : Diags(diags) {
+ ExtensionRAIIObject(DiagnosticsEngine &diags) : Diags(diags) {
Diags.IncrementAllExtensionsSilenced();
}
diff --git a/lib/Rewrite/DeltaTree.cpp b/lib/Rewrite/DeltaTree.cpp
index 085dfd89ef15..4297dc8de62f 100644
--- a/lib/Rewrite/DeltaTree.cpp
+++ b/lib/Rewrite/DeltaTree.cpp
@@ -12,12 +12,10 @@
//===----------------------------------------------------------------------===//
#include "clang/Rewrite/DeltaTree.h"
-#include "llvm/Support/Casting.h"
+#include "clang/Basic/LLVM.h"
#include <cstring>
#include <cstdio>
using namespace clang;
-using llvm::cast;
-using llvm::dyn_cast;
/// The DeltaTree class is a multiway search tree (BTree) structure with some
/// fancy features. B-Trees are generally more memory and cache efficient
diff --git a/lib/Rewrite/FixItRewriter.cpp b/lib/Rewrite/FixItRewriter.cpp
index e50793e2775f..632c0de0742a 100644
--- a/lib/Rewrite/FixItRewriter.cpp
+++ b/lib/Rewrite/FixItRewriter.cpp
@@ -25,7 +25,7 @@
using namespace clang;
-FixItRewriter::FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr,
+FixItRewriter::FixItRewriter(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
const LangOptions &LangOpts,
FixItOptions *FixItOpts)
: Diags(Diags),
@@ -41,7 +41,7 @@ FixItRewriter::~FixItRewriter() {
Diags.setClient(Client);
}
-bool FixItRewriter::WriteFixedFile(FileID ID, llvm::raw_ostream &OS) {
+bool FixItRewriter::WriteFixedFile(FileID ID, raw_ostream &OS) {
const RewriteBuffer *RewriteBuf = Rewrite.getRewriteBufferFor(ID);
if (!RewriteBuf) return true;
RewriteBuf->write(OS);
@@ -78,15 +78,15 @@ bool FixItRewriter::IncludeInDiagnosticCounts() const {
return Client ? Client->IncludeInDiagnosticCounts() : true;
}
-void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
- const DiagnosticInfo &Info) {
+void FixItRewriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) {
// Default implementation (Warnings/errors count).
- DiagnosticClient::HandleDiagnostic(DiagLevel, Info);
+ DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
Client->HandleDiagnostic(DiagLevel, Info);
// Skip over any diagnostics that are ignored or notes.
- if (DiagLevel <= Diagnostic::Note)
+ if (DiagLevel <= DiagnosticsEngine::Note)
return;
// Make sure that we can perform all of the modifications we
@@ -107,7 +107,8 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
Diag(Info.getLocation(), diag::note_fixit_in_macro);
// If this was an error, refuse to perform any rewriting.
- if (DiagLevel == Diagnostic::Error || DiagLevel == Diagnostic::Fatal) {
+ if (DiagLevel == DiagnosticsEngine::Error ||
+ DiagLevel == DiagnosticsEngine::Fatal) {
if (++NumFailures == 1)
Diag(Info.getLocation(), diag::note_fixit_unfixed_error);
}
@@ -155,4 +156,9 @@ void FixItRewriter::Diag(SourceLocation Loc, unsigned DiagID) {
Diags.setClient(this);
}
+DiagnosticConsumer *FixItRewriter::clone(DiagnosticsEngine &Diags) const {
+ return new FixItRewriter(Diags, Diags.getSourceManager(),
+ Rewrite.getLangOpts(), FixItOpts);
+}
+
FixItOptions::~FixItOptions() {}
diff --git a/lib/Rewrite/FrontendActions.cpp b/lib/Rewrite/FrontendActions.cpp
index 33e79edaf93b..f00e7fd9c913 100644
--- a/lib/Rewrite/FrontendActions.cpp
+++ b/lib/Rewrite/FrontendActions.cpp
@@ -28,8 +28,8 @@ using namespace clang;
//===----------------------------------------------------------------------===//
ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
- if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile))
+ StringRef InFile) {
+ if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile))
return CreateHTMLPrinter(OS, CI.getPreprocessor());
return 0;
}
@@ -38,7 +38,7 @@ FixItAction::FixItAction() {}
FixItAction::~FixItAction() {}
ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
+ StringRef InFile) {
return new ASTConsumer();
}
@@ -67,7 +67,7 @@ public:
} // end anonymous namespace
bool FixItAction::BeginSourceFileAction(CompilerInstance &CI,
- llvm::StringRef Filename) {
+ StringRef Filename) {
const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
if (!FEOpts.FixItSuffix.empty()) {
FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix,
@@ -91,8 +91,8 @@ void FixItAction::EndSourceFileAction() {
//===----------------------------------------------------------------------===//
ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
- if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp"))
+ StringRef InFile) {
+ if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp"))
return CreateObjCRewriter(InFile, OS,
CI.getDiagnostics(), CI.getLangOpts(),
CI.getDiagnosticOpts().NoRewriteMacros);
@@ -101,7 +101,7 @@ ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI,
void RewriteMacrosAction::ExecuteAction() {
CompilerInstance &CI = getCompilerInstance();
- llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
+ raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
if (!OS) return;
RewriteMacrosInInput(CI.getPreprocessor(), OS);
@@ -109,7 +109,7 @@ void RewriteMacrosAction::ExecuteAction() {
void RewriteTestAction::ExecuteAction() {
CompilerInstance &CI = getCompilerInstance();
- llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
+ raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
if (!OS) return;
DoRewriteTest(CI.getPreprocessor(), OS);
diff --git a/lib/Rewrite/HTMLPrint.cpp b/lib/Rewrite/HTMLPrint.cpp
index f66bfcb2dfc4..6a89265ef2c2 100644
--- a/lib/Rewrite/HTMLPrint.cpp
+++ b/lib/Rewrite/HTMLPrint.cpp
@@ -32,12 +32,12 @@ using namespace clang;
namespace {
class HTMLPrinter : public ASTConsumer {
Rewriter R;
- llvm::raw_ostream *Out;
+ raw_ostream *Out;
Preprocessor &PP;
bool SyntaxHighlight, HighlightMacros;
public:
- HTMLPrinter(llvm::raw_ostream *OS, Preprocessor &pp,
+ HTMLPrinter(raw_ostream *OS, Preprocessor &pp,
bool _SyntaxHighlight, bool _HighlightMacros)
: Out(OS), PP(pp), SyntaxHighlight(_SyntaxHighlight),
HighlightMacros(_HighlightMacros) {}
@@ -47,7 +47,7 @@ namespace {
};
}
-ASTConsumer* clang::CreateHTMLPrinter(llvm::raw_ostream *OS,
+ASTConsumer* clang::CreateHTMLPrinter(raw_ostream *OS,
Preprocessor &PP,
bool SyntaxHighlight,
bool HighlightMacros) {
diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/HTMLRewrite.cpp
index 0b54755dc58c..ba39602d162b 100644
--- a/lib/Rewrite/HTMLRewrite.cpp
+++ b/lib/Rewrite/HTMLRewrite.cpp
@@ -33,8 +33,8 @@ using namespace clang;
void html::HighlightRange(Rewriter &R, SourceLocation B, SourceLocation E,
const char *StartTag, const char *EndTag) {
SourceManager &SM = R.getSourceMgr();
- B = SM.getInstantiationLoc(B);
- E = SM.getInstantiationLoc(E);
+ B = SM.getExpansionLoc(B);
+ E = SM.getExpansionLoc(E);
FileID FID = SM.getFileID(B);
assert(SM.getFileID(E) == FID && "B/E not in the same file!");
@@ -140,10 +140,10 @@ void html::EscapeText(Rewriter &R, FileID FID,
unsigned NumSpaces = 8-(ColNo&7);
if (EscapeSpaces)
RB.ReplaceText(FilePos, 1,
- llvm::StringRef("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
+ StringRef("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
"&nbsp;&nbsp;&nbsp;", 6*NumSpaces));
else
- RB.ReplaceText(FilePos, 1, llvm::StringRef(" ", NumSpaces));
+ RB.ReplaceText(FilePos, 1, StringRef(" ", NumSpaces));
ColNo += NumSpaces;
break;
}
@@ -277,7 +277,7 @@ void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, FileID FID,
const char* FileEnd = Buf->getBufferEnd();
SourceLocation StartLoc = R.getSourceMgr().getLocForStartOfFile(FID);
- SourceLocation EndLoc = StartLoc.getFileLocWithOffset(FileEnd-FileStart);
+ SourceLocation EndLoc = StartLoc.getLocWithOffset(FileEnd-FileStart);
std::string s;
llvm::raw_string_ostream os(s);
@@ -397,8 +397,15 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart,
"<span class='comment'>", "</span>");
break;
+ case tok::utf8_string_literal:
+ // Chop off the u part of u8 prefix
+ ++TokOffs;
+ --TokLen;
+ // FALL THROUGH to chop the 8
case tok::wide_string_literal:
- // Chop off the L prefix
+ case tok::utf16_string_literal:
+ case tok::utf32_string_literal:
+ // Chop off the L, u, U or 8 prefix
++TokOffs;
--TokLen;
// FALL THROUGH.
@@ -433,17 +440,6 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
}
}
-namespace {
-/// IgnoringDiagClient - This is a diagnostic client that just ignores all
-/// diags.
-class IgnoringDiagClient : public DiagnosticClient {
- void HandleDiagnostic(Diagnostic::Level DiagLevel,
- const DiagnosticInfo &Info) {
- // Just ignore it.
- }
-};
-}
-
/// HighlightMacros - This uses the macro table state from the end of the
/// file, to re-expand macros and insert (into the HTML) information about the
/// macro expansions. This won't be perfectly perfect, but it will be
@@ -486,14 +482,14 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) {
// Temporarily change the diagnostics object so that we ignore any generated
// diagnostics from this pass.
- Diagnostic TmpDiags(PP.getDiagnostics().getDiagnosticIDs(),
- new IgnoringDiagClient);
+ DiagnosticsEngine TmpDiags(PP.getDiagnostics().getDiagnosticIDs(),
+ new IgnoringDiagConsumer);
// FIXME: This is a huge hack; we reuse the input preprocessor because we want
// its state, but we aren't actually changing it (we hope). This should really
// construct a copy of the preprocessor.
Preprocessor &TmpPP = const_cast<Preprocessor&>(PP);
- Diagnostic *OldDiags = &TmpPP.getDiagnostics();
+ DiagnosticsEngine *OldDiags = &TmpPP.getDiagnostics();
TmpPP.setDiagnostics(TmpDiags);
// Inform the preprocessor that we don't want comments.
@@ -519,7 +515,7 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) {
// expansion by inserting a start tag before the macro expansion and
// end tag after it.
std::pair<SourceLocation, SourceLocation> LLoc =
- SM.getInstantiationRange(Tok.getLocation());
+ SM.getExpansionRange(Tok.getLocation());
// Ignore tokens whose instantiation location was not the main file.
if (SM.getFileID(LLoc.first) != FID) {
@@ -542,7 +538,7 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) {
// instantiation. It would be really nice to pop up a window with all the
// spelling of the tokens or something.
while (!Tok.is(tok::eof) &&
- SM.getInstantiationLoc(Tok.getLocation()) == LLoc.first) {
+ SM.getExpansionLoc(Tok.getLocation()) == LLoc.first) {
// Insert a newline if the macro expansion is getting large.
if (LineLen > 60) {
Expansion += "<br>";
diff --git a/lib/Rewrite/RewriteMacros.cpp b/lib/Rewrite/RewriteMacros.cpp
index 0453098a56d2..d56910037c6c 100644
--- a/lib/Rewrite/RewriteMacros.cpp
+++ b/lib/Rewrite/RewriteMacros.cpp
@@ -87,7 +87,7 @@ static void LexRawTokensFromMainFile(Preprocessor &PP,
/// RewriteMacrosInInput - Implement -rewrite-macros mode.
-void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) {
+void clang::RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS) {
SourceManager &SM = PP.getSourceManager();
Rewriter Rewrite;
@@ -112,7 +112,7 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) {
// that aren't in the preprocessed view, we have macros that expand to no
// tokens, or macro arguments etc.
while (RawTok.isNot(tok::eof) || PPTok.isNot(tok::eof)) {
- SourceLocation PPLoc = SM.getInstantiationLoc(PPTok.getLocation());
+ SourceLocation PPLoc = SM.getExpansionLoc(PPTok.getLocation());
// If PPTok is from a different source file, ignore it.
if (!SM.isFromMainFile(PPLoc)) {
@@ -197,7 +197,7 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) {
while (PPOffs < RawOffs) {
Expansion += ' ' + PP.getSpelling(PPTok);
PP.Lex(PPTok);
- PPLoc = SM.getInstantiationLoc(PPTok.getLocation());
+ PPLoc = SM.getExpansionLoc(PPTok.getLocation());
PPOffs = SM.getFileOffset(PPLoc);
}
Expansion += ' ';
diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp
index 8202164ebce5..6a392ea357f1 100644
--- a/lib/Rewrite/RewriteObjC.cpp
+++ b/lib/Rewrite/RewriteObjC.cpp
@@ -55,7 +55,7 @@ namespace {
};
Rewriter Rewrite;
- Diagnostic &Diags;
+ DiagnosticsEngine &Diags;
const LangOptions &LangOpts;
unsigned RewriteFailedDiag;
unsigned TryFinallyContainsReturnDiag;
@@ -67,14 +67,14 @@ namespace {
const char *MainFileStart, *MainFileEnd;
SourceLocation LastIncLoc;
- llvm::SmallVector<ObjCImplementationDecl *, 8> ClassImplementation;
- llvm::SmallVector<ObjCCategoryImplDecl *, 8> CategoryImplementation;
+ SmallVector<ObjCImplementationDecl *, 8> ClassImplementation;
+ SmallVector<ObjCCategoryImplDecl *, 8> CategoryImplementation;
llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCSynthesizedStructs;
llvm::SmallPtrSet<ObjCProtocolDecl*, 8> ObjCSynthesizedProtocols;
llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCForwardDecls;
llvm::DenseMap<ObjCMethodDecl*, std::string> MethodInternalNames;
- llvm::SmallVector<Stmt *, 32> Stmts;
- llvm::SmallVector<int, 8> ObjCBcLabelNo;
+ SmallVector<Stmt *, 32> Stmts;
+ SmallVector<int, 8> ObjCBcLabelNo;
// Remember all the @protocol(<expr>) expressions.
llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ProtocolExprDecls;
@@ -113,7 +113,7 @@ namespace {
bool IsHeader;
std::string InFileName;
- llvm::raw_ostream* OutFile;
+ raw_ostream* OutFile;
bool SilenceRewriteMacroWarning;
bool objc_impl_method;
@@ -121,16 +121,16 @@ namespace {
std::string Preamble;
// Block expressions.
- llvm::SmallVector<BlockExpr *, 32> Blocks;
- llvm::SmallVector<int, 32> InnerDeclRefsCount;
- llvm::SmallVector<BlockDeclRefExpr *, 32> InnerDeclRefs;
+ SmallVector<BlockExpr *, 32> Blocks;
+ SmallVector<int, 32> InnerDeclRefsCount;
+ SmallVector<BlockDeclRefExpr *, 32> InnerDeclRefs;
- llvm::SmallVector<BlockDeclRefExpr *, 32> BlockDeclRefs;
+ SmallVector<BlockDeclRefExpr *, 32> BlockDeclRefs;
// Block related declarations.
- llvm::SmallVector<ValueDecl *, 8> BlockByCopyDecls;
+ SmallVector<ValueDecl *, 8> BlockByCopyDecls;
llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDeclsPtrSet;
- llvm::SmallVector<ValueDecl *, 8> BlockByRefDecls;
+ SmallVector<ValueDecl *, 8> BlockByRefDecls;
llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDeclsPtrSet;
llvm::DenseMap<ValueDecl *, unsigned> BlockByRefDeclNo;
llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls;
@@ -161,13 +161,18 @@ namespace {
// Top Level Driver code.
virtual void HandleTopLevelDecl(DeclGroupRef D) {
- for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
+ for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {
+ if (isa<ObjCClassDecl>((*I))) {
+ RewriteForwardClassDecl(D);
+ break;
+ }
HandleTopLevelSingleDecl(*I);
+ }
}
void HandleTopLevelSingleDecl(Decl *D);
void HandleDeclInMainFile(Decl *D);
- RewriteObjC(std::string inFile, llvm::raw_ostream *OS,
- Diagnostic &D, const LangOptions &LOpts,
+ RewriteObjC(std::string inFile, raw_ostream *OS,
+ DiagnosticsEngine &D, const LangOptions &LOpts,
bool silenceMacroWarn);
~RewriteObjC() {}
@@ -219,7 +224,7 @@ namespace {
<< Old->getSourceRange();
}
- void InsertText(SourceLocation Loc, llvm::StringRef Str,
+ void InsertText(SourceLocation Loc, StringRef Str,
bool InsertAfter = true) {
// If insertion succeeded or warning disabled return with no warning.
if (!Rewrite.InsertText(Loc, Str, InsertAfter) ||
@@ -230,7 +235,7 @@ namespace {
}
void ReplaceText(SourceLocation Start, unsigned OrigLength,
- llvm::StringRef Str) {
+ StringRef Str) {
// If removal succeeded or warning disabled return with no warning.
if (!Rewrite.ReplaceText(Start, OrigLength, Str) ||
SilenceRewriteMacroWarning)
@@ -241,7 +246,11 @@ namespace {
// Syntactic Rewriting.
void RewriteInclude();
- void RewriteForwardClassDecl(ObjCClassDecl *Dcl);
+ void RewriteForwardClassDecl(DeclGroupRef D);
+ void RewriteForwardClassDecl(const llvm::SmallVector<Decl*, 8> &DG);
+ void RewriteForwardClassEpilogue(ObjCClassDecl *ClassDecl,
+ const std::string &typedefString);
+
void RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
ObjCImplementationDecl *IMD,
ObjCCategoryImplDecl *CID);
@@ -332,17 +341,17 @@ namespace {
void RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
MethodIterator MethodEnd,
bool IsInstanceMethod,
- llvm::StringRef prefix,
- llvm::StringRef ClassName,
+ StringRef prefix,
+ StringRef ClassName,
std::string &Result);
void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol,
- llvm::StringRef prefix,
- llvm::StringRef ClassName,
+ StringRef prefix,
+ StringRef ClassName,
std::string &Result);
void RewriteObjCProtocolListMetaData(const ObjCList<ObjCProtocolDecl> &Prots,
- llvm::StringRef prefix,
- llvm::StringRef ClassName,
+ StringRef prefix,
+ StringRef ClassName,
std::string &Result);
void SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
std::string &Result);
@@ -367,24 +376,24 @@ namespace {
void RewriteBlockPointerFunctionArgs(FunctionDecl *FD);
std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
- llvm::StringRef funcName, std::string Tag);
+ StringRef funcName, std::string Tag);
std::string SynthesizeBlockFunc(BlockExpr *CE, int i,
- llvm::StringRef funcName, std::string Tag);
+ StringRef funcName, std::string Tag);
std::string SynthesizeBlockImpl(BlockExpr *CE,
std::string Tag, std::string Desc);
std::string SynthesizeBlockDescriptor(std::string DescTag,
std::string ImplTag,
- int i, llvm::StringRef funcName,
+ int i, StringRef funcName,
unsigned hasCopy);
Stmt *SynthesizeBlockCall(CallExpr *Exp, const Expr* BlockExp);
void SynthesizeBlockLiterals(SourceLocation FunLocStart,
- llvm::StringRef FunName);
+ StringRef FunName);
void RewriteRecordBody(RecordDecl *RD);
void CollectBlockDeclRefInfo(BlockExpr *Exp);
void GetBlockDeclRefExprs(Stmt *S);
void GetInnerBlockDeclRefExprs(Stmt *S,
- llvm::SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs,
+ SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs,
llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts);
// We avoid calling Type::isBlockPointerType(), since it operates on the
@@ -411,8 +420,14 @@ namespace {
else if (T->isObjCQualifiedClassType())
T = Context->getObjCClassType();
else if (T->isObjCObjectPointerType() &&
- T->getPointeeType()->isObjCQualifiedInterfaceType())
- T = Context->getObjCIdType();
+ T->getPointeeType()->isObjCQualifiedInterfaceType()) {
+ if (const ObjCObjectPointerType * OBJPT =
+ T->getAsObjCInterfacePointerType()) {
+ const ObjCInterfaceType *IFaceT = OBJPT->getInterfaceType();
+ T = QualType(IFaceT, 0);
+ T = Context->getPointerType(T);
+ }
+ }
}
// FIXME: This predicate seems like it would be useful to add to ASTContext.
@@ -439,9 +454,9 @@ namespace {
const char *&RParen);
void RewriteCastExpr(CStyleCastExpr *CE);
- FunctionDecl *SynthBlockInitFunctionDecl(llvm::StringRef name);
+ FunctionDecl *SynthBlockInitFunctionDecl(StringRef name);
Stmt *SynthBlockInitExpr(BlockExpr *Exp,
- const llvm::SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs);
+ const SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs);
void QuoteDoublequotes(std::string &From, std::string &To) {
for (unsigned i = 0; i < From.length(); i++) {
@@ -456,6 +471,8 @@ namespace {
const QualType *args,
unsigned numArgs,
bool variadic = false) {
+ if (result == Context->getObjCInstanceType())
+ result = Context->getObjCIdType();
FunctionProtoType::ExtProtoInfo fpi;
fpi.Variadic = variadic;
return Context->getFunctionType(result, args, numArgs, fpi);
@@ -505,22 +522,23 @@ static bool IsHeaderFile(const std::string &Filename) {
return Ext == "h" || Ext == "hh" || Ext == "H";
}
-RewriteObjC::RewriteObjC(std::string inFile, llvm::raw_ostream* OS,
- Diagnostic &D, const LangOptions &LOpts,
+RewriteObjC::RewriteObjC(std::string inFile, raw_ostream* OS,
+ DiagnosticsEngine &D, const LangOptions &LOpts,
bool silenceMacroWarn)
: Diags(D), LangOpts(LOpts), InFileName(inFile), OutFile(OS),
SilenceRewriteMacroWarning(silenceMacroWarn) {
IsHeader = IsHeaderFile(inFile);
- RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
+ RewriteFailedDiag = Diags.getCustomDiagID(DiagnosticsEngine::Warning,
"rewriting sub-expression within a macro (may not be correct)");
- TryFinallyContainsReturnDiag = Diags.getCustomDiagID(Diagnostic::Warning,
+ TryFinallyContainsReturnDiag = Diags.getCustomDiagID(
+ DiagnosticsEngine::Warning,
"rewriter doesn't support user-specified control flow semantics "
"for @try/@finally (code may not execute properly)");
}
ASTConsumer *clang::CreateObjCRewriter(const std::string& InFile,
- llvm::raw_ostream* OS,
- Diagnostic &Diags,
+ raw_ostream* OS,
+ DiagnosticsEngine &Diags,
const LangOptions &LOpts,
bool SilenceRewriteMacroWarning) {
return new RewriteObjC(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning);
@@ -572,7 +590,7 @@ void RewriteObjC::Initialize(ASTContext &context) {
Preamble += "struct objc_selector; struct objc_class;\n";
Preamble += "struct __rw_objc_super { struct objc_object *object; ";
Preamble += "struct objc_object *superClass; ";
- if (LangOpts.Microsoft) {
+ if (LangOpts.MicrosoftExt) {
// Add a constructor for creating temporary objects.
Preamble += "__rw_objc_super(struct objc_object *o, struct objc_object *s) "
": ";
@@ -583,7 +601,7 @@ void RewriteObjC::Initialize(ASTContext &context) {
Preamble += "typedef struct objc_object Protocol;\n";
Preamble += "#define _REWRITER_typedef_Protocol\n";
Preamble += "#endif\n";
- if (LangOpts.Microsoft) {
+ if (LangOpts.MicrosoftExt) {
Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n";
Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n";
} else
@@ -592,9 +610,9 @@ void RewriteObjC::Initialize(ASTContext &context) {
Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper";
Preamble += "(struct objc_super *, struct objc_selector *, ...);\n";
- Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend_stret";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSend_stret";
Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
- Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper_stret";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSendSuper_stret";
Preamble += "(struct objc_super *, struct objc_selector *, ...);\n";
Preamble += "__OBJC_RW_DLLIMPORT double objc_msgSend_fpret";
Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
@@ -660,7 +678,7 @@ void RewriteObjC::Initialize(ASTContext &context) {
Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n";
Preamble += "#endif\n";
Preamble += "#endif\n";
- if (LangOpts.Microsoft) {
+ if (LangOpts.MicrosoftExt) {
Preamble += "#undef __OBJC_RW_DLLIMPORT\n";
Preamble += "#undef __OBJC_RW_STATICIMPORT\n";
Preamble += "#ifndef KEEP_ATTRIBUTES\n"; // We use this for clang tests.
@@ -690,7 +708,7 @@ void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {
// #included file. If the former, rewrite it now. If the later, check to see
// if we rewrote the #include/#import.
SourceLocation Loc = D->getLocation();
- Loc = SM->getInstantiationLoc(Loc);
+ Loc = SM->getExpansionLoc(Loc);
// If this is for a builtin, ignore it.
if (Loc.isInvalid()) return;
@@ -717,8 +735,23 @@ void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {
// Recurse into linkage specifications
for (DeclContext::decl_iterator DI = LSD->decls_begin(),
DIEnd = LSD->decls_end();
- DI != DIEnd; ++DI)
+ DI != DIEnd; ) {
+ if (isa<ObjCClassDecl>((*DI))) {
+ SmallVector<Decl *, 8> DG;
+ Decl *D = (*DI);
+ SourceLocation Loc = D->getLocation();
+ while (DI != DIEnd &&
+ isa<ObjCClassDecl>(D) && D->getLocation() == Loc) {
+ DG.push_back(D);
+ ++DI;
+ D = (*DI);
+ }
+ RewriteForwardClassDecl(DG);
+ continue;
+ }
HandleTopLevelSingleDecl(*DI);
+ ++DI;
+ }
}
// If we have a decl in the main file, see if we should rewrite it.
if (SM->isFromMainFile(Loc))
@@ -731,7 +764,7 @@ void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {
void RewriteObjC::RewriteInclude() {
SourceLocation LocStart = SM->getLocForStartOfFile(MainFileID);
- llvm::StringRef MainBuf = SM->getBufferData(MainFileID);
+ StringRef MainBuf = SM->getBufferData(MainFileID);
const char *MainBufStart = MainBuf.begin();
const char *MainBufEnd = MainBuf.end();
size_t ImportLen = strlen("import");
@@ -747,7 +780,7 @@ void RewriteObjC::RewriteInclude() {
if (!strncmp(BufPtr, "import", ImportLen)) {
// replace import with include
SourceLocation ImportLoc =
- LocStart.getFileLocWithOffset(BufPtr-MainBufStart);
+ LocStart.getLocWithOffset(BufPtr-MainBufStart);
ReplaceText(ImportLoc, ImportLen, "include");
BufPtr += ImportLen;
}
@@ -777,7 +810,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
const char *semiBuf = strchr(startBuf, ';');
assert((*semiBuf == ';') && "@synthesize: can't find ';'");
SourceLocation onePastSemiLoc =
- startLoc.getFileLocWithOffset(semiBuf-startBuf+1);
+ startLoc.getLocWithOffset(semiBuf-startBuf+1);
if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
return; // FIXME: is this correct?
@@ -821,7 +854,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) {
if (i) Getr += ", ";
std::string ParamStr = FT->getArgType(i).getAsString(
- Context->PrintingPolicy);
+ Context->getPrintingPolicy());
Getr += ParamStr;
}
if (FT->isVariadic()) {
@@ -886,55 +919,73 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
InsertText(onePastSemiLoc, Setr);
}
-void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) {
- // Get the start location and compute the semi location.
- SourceLocation startLoc = ClassDecl->getLocation();
- const char *startBuf = SM->getCharacterData(startLoc);
- const char *semiPtr = strchr(startBuf, ';');
+static void RewriteOneForwardClassDecl(ObjCInterfaceDecl *ForwardDecl,
+ std::string &typedefString) {
+ typedefString += "#ifndef _REWRITER_typedef_";
+ typedefString += ForwardDecl->getNameAsString();
+ typedefString += "\n";
+ typedefString += "#define _REWRITER_typedef_";
+ typedefString += ForwardDecl->getNameAsString();
+ typedefString += "\n";
+ typedefString += "typedef struct objc_object ";
+ typedefString += ForwardDecl->getNameAsString();
+ typedefString += ";\n#endif\n";
+}
+
+void RewriteObjC::RewriteForwardClassEpilogue(ObjCClassDecl *ClassDecl,
+ const std::string &typedefString) {
+ SourceLocation startLoc = ClassDecl->getLocation();
+ const char *startBuf = SM->getCharacterData(startLoc);
+ const char *semiPtr = strchr(startBuf, ';');
+ // Replace the @class with typedefs corresponding to the classes.
+ ReplaceText(startLoc, semiPtr-startBuf+1, typedefString);
+}
- // Translate to typedef's that forward reference structs with the same name
- // as the class. As a convenience, we include the original declaration
- // as a comment.
+void RewriteObjC::RewriteForwardClassDecl(DeclGroupRef D) {
std::string typedefString;
- typedefString += "// @class ";
- for (ObjCClassDecl::iterator I = ClassDecl->begin(), E = ClassDecl->end();
- I != E; ++I) {
- ObjCInterfaceDecl *ForwardDecl = I->getInterface();
- typedefString += ForwardDecl->getNameAsString();
- if (I+1 != E)
- typedefString += ", ";
- else
+ for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {
+ ObjCClassDecl *ClassDecl = cast<ObjCClassDecl>(*I);
+ ObjCInterfaceDecl *ForwardDecl = ClassDecl->getForwardInterfaceDecl();
+ if (I == D.begin()) {
+ // Translate to typedef's that forward reference structs with the same name
+ // as the class. As a convenience, we include the original declaration
+ // as a comment.
+ typedefString += "// @class ";
+ typedefString += ForwardDecl->getNameAsString();
typedefString += ";\n";
+ }
+ RewriteOneForwardClassDecl(ForwardDecl, typedefString);
}
-
- for (ObjCClassDecl::iterator I = ClassDecl->begin(), E = ClassDecl->end();
- I != E; ++I) {
- ObjCInterfaceDecl *ForwardDecl = I->getInterface();
- typedefString += "#ifndef _REWRITER_typedef_";
- typedefString += ForwardDecl->getNameAsString();
- typedefString += "\n";
- typedefString += "#define _REWRITER_typedef_";
- typedefString += ForwardDecl->getNameAsString();
- typedefString += "\n";
- typedefString += "typedef struct objc_object ";
- typedefString += ForwardDecl->getNameAsString();
- typedefString += ";\n#endif\n";
- }
-
- // Replace the @class with typedefs corresponding to the classes.
- ReplaceText(startLoc, semiPtr-startBuf+1, typedefString);
+ DeclGroupRef::iterator I = D.begin();
+ RewriteForwardClassEpilogue(cast<ObjCClassDecl>(*I), typedefString);
+}
+
+void RewriteObjC::RewriteForwardClassDecl(
+ const llvm::SmallVector<Decl*, 8> &D) {
+ std::string typedefString;
+ for (unsigned i = 0; i < D.size(); i++) {
+ ObjCClassDecl *ClassDecl = cast<ObjCClassDecl>(D[i]);
+ ObjCInterfaceDecl *ForwardDecl = ClassDecl->getForwardInterfaceDecl();
+ if (i == 0) {
+ typedefString += "// @class ";
+ typedefString += ForwardDecl->getNameAsString();
+ typedefString += ";\n";
+ }
+ RewriteOneForwardClassDecl(ForwardDecl, typedefString);
+ }
+ RewriteForwardClassEpilogue(cast<ObjCClassDecl>(D[0]), typedefString);
}
void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) {
// When method is a synthesized one, such as a getter/setter there is
// nothing to rewrite.
- if (Method->isSynthesized())
+ if (Method->isImplicit())
return;
SourceLocation LocStart = Method->getLocStart();
SourceLocation LocEnd = Method->getLocEnd();
- if (SM->getInstantiationLineNumber(LocEnd) >
- SM->getInstantiationLineNumber(LocStart)) {
+ if (SM->getExpansionLineNumber(LocEnd) >
+ SM->getExpansionLineNumber(LocStart)) {
InsertText(LocStart, "#if 0\n");
ReplaceText(LocEnd, 1, ";\n#endif\n");
} else {
@@ -1001,12 +1052,12 @@ void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
const char *endBuf = SM->getCharacterData(LocEnd);
for (const char *p = startBuf; p < endBuf; p++) {
if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) {
- SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
+ SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf);
ReplaceText(OptionalLoc, strlen("@optional"), "/* @optional */");
}
else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) {
- SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
+ SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf);
ReplaceText(OptionalLoc, strlen("@required"), "/* @required */");
}
@@ -1016,7 +1067,7 @@ void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
void RewriteObjC::RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *PDecl) {
SourceLocation LocStart = PDecl->getLocation();
if (LocStart.isInvalid())
- assert(false && "Invalid SourceLocation");
+ llvm_unreachable("Invalid SourceLocation");
// FIXME: handle forward protocol that are declared across multiple lines.
ReplaceText(LocStart, 0, "// ");
}
@@ -1037,11 +1088,11 @@ void RewriteObjC::RewriteTypeIntoString(QualType T, std::string &ResultStr,
PointeeTy = BPT->getPointeeType();
if ((FPRetType = PointeeTy->getAs<FunctionType>())) {
ResultStr += FPRetType->getResultType().getAsString(
- Context->PrintingPolicy);
+ Context->getPrintingPolicy());
ResultStr += "(*";
}
} else
- ResultStr += T.getAsString(Context->PrintingPolicy);
+ ResultStr += T.getAsString(Context->getPrintingPolicy());
}
void RewriteObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl,
@@ -1089,7 +1140,7 @@ void RewriteObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl,
if (OMD->isInstanceMethod()) {
QualType selfTy = Context->getObjCInterfaceType(IDecl);
selfTy = Context->getPointerType(selfTy);
- if (!LangOpts.Microsoft) {
+ if (!LangOpts.MicrosoftExt) {
if (ObjCSynthesizedStructs.count(const_cast<ObjCInterfaceDecl*>(IDecl)))
ResultStr += "struct ";
}
@@ -1099,10 +1150,10 @@ void RewriteObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl,
}
else
ResultStr += Context->getObjCClassType().getAsString(
- Context->PrintingPolicy);
+ Context->getPrintingPolicy());
ResultStr += " self, ";
- ResultStr += Context->getObjCSelType().getAsString(Context->PrintingPolicy);
+ ResultStr += Context->getObjCSelType().getAsString(Context->getPrintingPolicy());
ResultStr += " _cmd";
// Method arguments.
@@ -1118,9 +1169,9 @@ void RewriteObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl,
QualType QT = PDecl->getType();
// Make sure we convert "t (^)(...)" to "t (*)(...)".
if (convertBlockPointerToFunctionPointer(QT))
- QT.getAsStringInternal(Name, Context->PrintingPolicy);
+ QT.getAsStringInternal(Name, Context->getPrintingPolicy());
else
- PDecl->getType().getAsStringInternal(Name, Context->PrintingPolicy);
+ PDecl->getType().getAsStringInternal(Name, Context->getPrintingPolicy());
ResultStr += Name;
}
}
@@ -1137,7 +1188,7 @@ void RewriteObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl,
for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) {
if (i) ResultStr += ", ";
std::string ParamStr = FT->getArgType(i).getAsString(
- Context->PrintingPolicy);
+ Context->getPrintingPolicy());
ResultStr += ParamStr;
}
if (FT->isVariadic()) {
@@ -1265,8 +1316,6 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(BinaryOperator *BinOp, Expr *
}
assert(OMD && "RewritePropertyOrImplicitSetter - null OMD");
- llvm::SmallVector<Expr *, 1> ExprVec;
- ExprVec.push_back(newStmt);
ObjCMessageExpr *MsgExpr;
if (Super)
@@ -1278,7 +1327,7 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(BinaryOperator *BinOp, Expr *
/*IsInstanceSuper=*/true,
SuperTy,
Sel, SelectorLoc, OMD,
- &ExprVec[0], 1,
+ newStmt,
/*FIXME:*/SourceLocation());
else {
// FIXME. Refactor this into common code with that in
@@ -1295,7 +1344,7 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(BinaryOperator *BinOp, Expr *
/*FIXME: */SourceLocation(),
cast<Expr>(Receiver),
Sel, SelectorLoc, OMD,
- &ExprVec[0], 1,
+ newStmt,
/*FIXME:*/SourceLocation());
}
Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr);
@@ -1354,7 +1403,7 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(Expr *PropOrGetterRefExpr) {
/*IsInstanceSuper=*/true,
SuperTy,
Sel, SelectorLoc, OMD,
- 0, 0,
+ ArrayRef<Expr*>(),
PropOrGetterRefExpr->getLocEnd());
else {
assert (Receiver && "RewritePropertyOrImplicitGetter - Receiver is null");
@@ -1368,7 +1417,7 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(Expr *PropOrGetterRefExpr) {
PropOrGetterRefExpr->getLocStart(),
cast<Expr>(Receiver),
Sel, SelectorLoc, OMD,
- 0, 0,
+ ArrayRef<Expr*>(),
PropOrGetterRefExpr->getLocEnd());
}
@@ -1611,7 +1660,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
SourceLocation startLoc = S->getLocStart();
const char *startBuf = SM->getCharacterData(startLoc);
- llvm::StringRef elementName;
+ StringRef elementName;
std::string elementTypeAsString;
std::string buf;
buf = "\n{\n\t";
@@ -1624,7 +1673,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
// Simply use 'id' for all qualified types.
elementTypeAsString = "id";
else
- elementTypeAsString = ElementType.getAsString(Context->PrintingPolicy);
+ elementTypeAsString = ElementType.getAsString(Context->getPrintingPolicy());
buf += elementTypeAsString;
buf += " ";
elementName = D->getName();
@@ -1640,7 +1689,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
// Simply use 'id' for all qualified types.
elementTypeAsString = "id";
else
- elementTypeAsString = VD->getType().getAsString(Context->PrintingPolicy);
+ elementTypeAsString = VD->getType().getAsString(Context->getPrintingPolicy());
}
// struct __objcFastEnumerationState enumState = { 0 };
@@ -1667,7 +1716,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
// Replace ')' in for '(' type elem in collection ')' with ';'
SourceLocation rightParenLoc = S->getRParenLoc();
const char *rparenBuf = SM->getCharacterData(rightParenLoc);
- SourceLocation lparenLoc = startLoc.getFileLocWithOffset(rparenBuf-startBuf);
+ SourceLocation lparenLoc = startLoc.getLocWithOffset(rparenBuf-startBuf);
buf = ";\n\t";
// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState
@@ -1744,7 +1793,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
// Insert all these *after* the statement body.
// FIXME: If this should support Obj-C++, support CXXTryStmt
if (isa<CompoundStmt>(S->getBody())) {
- SourceLocation endBodyLoc = OrigEnd.getFileLocWithOffset(1);
+ SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(1);
InsertText(endBodyLoc, buf);
} else {
/* Need to treat single statements specially. For example:
@@ -1757,7 +1806,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
const char *stmtBuf = SM->getCharacterData(OrigEnd);
const char *semiBuf = strchr(stmtBuf, ';');
assert(semiBuf && "Can't find ';'");
- SourceLocation endBodyLoc = OrigEnd.getFileLocWithOffset(semiBuf-stmtBuf+1);
+ SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(semiBuf-stmtBuf+1);
InsertText(endBodyLoc, buf);
}
Stmts.pop_back();
@@ -1789,7 +1838,7 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
SourceLocation endLoc = S->getSynchBody()->getLocStart();
const char *endBuf = SM->getCharacterData(endLoc);
while (*endBuf != ')') endBuf--;
- SourceLocation rparenLoc = startLoc.getFileLocWithOffset(endBuf-startBuf);
+ SourceLocation rparenLoc = startLoc.getLocWithOffset(endBuf-startBuf);
buf = ");\n";
// declare a new scope with two variables, _stack and _rethrow.
buf += "/* @try scope begin */ \n{ struct _objc_exception_data {\n";
@@ -1812,9 +1861,15 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
std::string syncBuf;
syncBuf += " objc_sync_exit(";
- Expr *syncExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
- CK_BitCast,
- S->getSynchExpr());
+
+ Expr *syncExpr = S->getSynchExpr();
+ CastKind CK = syncExpr->getType()->isObjCObjectPointerType()
+ ? CK_BitCast :
+ syncExpr->getType()->isBlockPointerType()
+ ? CK_BlockPointerToObjCPointerCast
+ : CK_CPointerToObjCPointerCast;
+ syncExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CK, syncExpr);
std::string syncExprBufS;
llvm::raw_string_ostream syncExprBuf(syncExprBufS);
syncExpr->printPretty(syncExprBuf, *Context, 0,
@@ -1875,7 +1930,7 @@ void RewriteObjC::RewriteTryReturnStmts(Stmt *S) {
const char *semiBuf = strchr(startBuf, ';');
assert((*semiBuf == ';') && "RewriteTryReturnStmts: can't find ';'");
- SourceLocation onePastSemiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf+1);
+ SourceLocation onePastSemiLoc = startLoc.getLocWithOffset(semiBuf-startBuf+1);
std::string buf;
buf = "{ objc_exception_try_exit(&_stack); return";
@@ -1898,7 +1953,7 @@ void RewriteObjC::RewriteSyncReturnStmts(Stmt *S, std::string syncExitBuf) {
const char *semiBuf = strchr(startBuf, ';');
assert((*semiBuf == ';') && "RewriteSyncReturnStmts: can't find ';'");
- SourceLocation onePastSemiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf+1);
+ SourceLocation onePastSemiLoc = startLoc.getLocWithOffset(semiBuf-startBuf+1);
std::string buf;
buf = "{ objc_exception_try_exit(&_stack);";
@@ -1936,7 +1991,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
SourceLocation lastCurlyLoc = startLoc;
if (S->getNumCatchStmts()) {
- startLoc = startLoc.getFileLocWithOffset(1);
+ startLoc = startLoc.getLocWithOffset(1);
buf = " /* @catch begin */ else {\n";
buf += " id _caught = objc_exception_extract(&_stack);\n";
buf += " objc_exception_try_enter (&_stack);\n";
@@ -2007,7 +2062,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
// declares the @catch parameter).
ReplaceText(rParenLoc, bodyBuf-rParenBuf+1, " = _caught;");
} else {
- assert(false && "@catch rewrite bug");
+ llvm_unreachable("@catch rewrite bug");
}
}
// Complete the catch list...
@@ -2017,7 +2072,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
"bogus @catch body location");
// Insert the last (implicit) else clause *before* the right curly brace.
- bodyLoc = bodyLoc.getFileLocWithOffset(-1);
+ bodyLoc = bodyLoc.getLocWithOffset(-1);
buf = "} /* last catch end */\n";
buf += "else {\n";
buf += " _rethrow = _caught;\n";
@@ -2045,9 +2100,9 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
assert(*SM->getCharacterData(endLoc) == '}' &&
"bogus @finally body location");
- startLoc = startLoc.getFileLocWithOffset(1);
+ startLoc = startLoc.getLocWithOffset(1);
InsertText(startLoc, " if (!_rethrow) objc_exception_try_exit(&_stack);\n");
- endLoc = endLoc.getFileLocWithOffset(-1);
+ endLoc = endLoc.getLocWithOffset(-1);
InsertText(endLoc, " if (_rethrow) objc_exception_throw(_rethrow);\n");
// Set lastCurlyLoc
@@ -2071,7 +2126,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
RewriteTryReturnStmts(S->getTryBody());
}
// Now emit the final closing curly brace...
- lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1);
+ lastCurlyLoc = lastCurlyLoc.getLocWithOffset(1);
InsertText(lastCurlyLoc, " } /* @try scope end */\n");
return 0;
}
@@ -2100,7 +2155,7 @@ Stmt *RewriteObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) {
const char *semiBuf = strchr(startBuf, ';');
assert((*semiBuf == ';') && "@throw: can't find ';'");
- SourceLocation semiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf);
+ SourceLocation semiLoc = startLoc.getLocWithOffset(semiBuf-startBuf);
ReplaceText(semiLoc, 1, ");");
return 0;
}
@@ -2111,8 +2166,8 @@ Stmt *RewriteObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) {
std::string StrEncoding;
Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding);
Expr *Replacement = StringLiteral::Create(*Context, StrEncoding,
- false, false, StrType,
- SourceLocation());
+ StringLiteral::Ascii, false,
+ StrType, SourceLocation());
ReplaceStmt(Exp, Replacement);
// Replace this subexpr in the parent.
@@ -2125,12 +2180,12 @@ Stmt *RewriteObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) {
SynthSelGetUidFunctionDecl();
assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl");
// Create a call to sel_registerName("selName").
- llvm::SmallVector<Expr*, 8> SelExprs;
+ SmallVector<Expr*, 8> SelExprs;
QualType argType = Context->getPointerType(Context->CharTy);
SelExprs.push_back(StringLiteral::Create(*Context,
Exp->getSelector().getAsString(),
- false, false, argType,
- SourceLocation()));
+ StringLiteral::Ascii, false,
+ argType, SourceLocation()));
CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
&SelExprs[0], SelExprs.size());
ReplaceStmt(Exp, SelExp);
@@ -2231,8 +2286,8 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) {
const char *startRef = 0, *endRef = 0;
if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
// Get the locations of the startRef, endRef.
- SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-startBuf);
- SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-startBuf+1);
+ SourceLocation LessLoc = Loc.getLocWithOffset(startRef-startBuf);
+ SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-startBuf+1);
// Comment out the protocol references.
InsertText(LessLoc, "/*");
InsertText(GreaterLoc, "*/");
@@ -2276,8 +2331,8 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
const char *startRef = 0, *endRef = 0;
if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
// Get the locations of the startRef, endRef.
- SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-endBuf);
- SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-endBuf+1);
+ SourceLocation LessLoc = Loc.getLocWithOffset(startRef-endBuf);
+ SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-endBuf+1);
// Comment out the protocol references.
InsertText(LessLoc, "/*");
InsertText(GreaterLoc, "*/");
@@ -2299,9 +2354,9 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
// Get the locations of the startRef, endRef.
SourceLocation LessLoc =
- Loc.getFileLocWithOffset(startRef-startFuncBuf);
+ Loc.getLocWithOffset(startRef-startFuncBuf);
SourceLocation GreaterLoc =
- Loc.getFileLocWithOffset(endRef-startFuncBuf+1);
+ Loc.getLocWithOffset(endRef-startFuncBuf+1);
// Comment out the protocol references.
InsertText(LessLoc, "/*");
InsertText(GreaterLoc, "*/");
@@ -2330,7 +2385,7 @@ void RewriteObjC::RewriteTypeOfDecl(VarDecl *ND) {
}
// FIXME. This will not work for multiple declarators; as in:
// __typeof__(a) b,c,d;
- std::string TypeAsString(QT.getAsString(Context->PrintingPolicy));
+ std::string TypeAsString(QT.getAsString(Context->getPrintingPolicy()));
SourceLocation DeclLoc = ND->getTypeSpecStartLoc();
const char *startBuf = SM->getCharacterData(DeclLoc);
if (ND->getInit()) {
@@ -2342,13 +2397,13 @@ void RewriteObjC::RewriteTypeOfDecl(VarDecl *ND) {
startLoc = ECE->getLParenLoc();
else
startLoc = E->getLocStart();
- startLoc = SM->getInstantiationLoc(startLoc);
+ startLoc = SM->getExpansionLoc(startLoc);
const char *endBuf = SM->getCharacterData(startLoc);
ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString);
}
else {
SourceLocation X = ND->getLocEnd();
- X = SM->getInstantiationLoc(X);
+ X = SM->getExpansionLoc(X);
const char *endBuf = SM->getCharacterData(X);
ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString);
}
@@ -2357,7 +2412,7 @@ void RewriteObjC::RewriteTypeOfDecl(VarDecl *ND) {
// SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str);
void RewriteObjC::SynthSelGetUidFunctionDecl() {
IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName");
- llvm::SmallVector<QualType, 16> ArgTys;
+ SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getFuncType =
getSimpleFunctionType(Context->getObjCSelType(), &ArgTys[0], ArgTys.size());
@@ -2380,7 +2435,7 @@ void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) {
}
void RewriteObjC::RewriteBlockPointerType(std::string& Str, QualType Type) {
- std::string TypeString(Type.getAsString(Context->PrintingPolicy));
+ std::string TypeString(Type.getAsString(Context->getPrintingPolicy()));
const char *argPtr = TypeString.c_str();
if (!strchr(argPtr, '^')) {
Str += TypeString;
@@ -2396,7 +2451,7 @@ void RewriteObjC::RewriteBlockPointerType(std::string& Str, QualType Type) {
void RewriteObjC::RewriteBlockPointerTypeVariable(std::string& Str,
ValueDecl *VD) {
QualType Type = VD->getType();
- std::string TypeString(Type.getAsString(Context->PrintingPolicy));
+ std::string TypeString(Type.getAsString(Context->getPrintingPolicy()));
const char *argPtr = TypeString.c_str();
int paren = 0;
while (*argPtr) {
@@ -2430,7 +2485,7 @@ void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) {
if (!proto)
return;
QualType Type = proto->getResultType();
- std::string FdStr = Type.getAsString(Context->PrintingPolicy);
+ std::string FdStr = Type.getAsString(Context->getPrintingPolicy());
FdStr += " ";
FdStr += FD->getName();
FdStr += "(";
@@ -2451,7 +2506,7 @@ void RewriteObjC::SynthSuperContructorFunctionDecl() {
if (SuperContructorFunctionDecl)
return;
IdentifierInfo *msgSendIdent = &Context->Idents.get("__rw_objc_super");
- llvm::SmallVector<QualType, 16> ArgTys;
+ SmallVector<QualType, 16> ArgTys;
QualType argT = Context->getObjCIdType();
assert(!argT.isNull() && "Can't find 'id' type");
ArgTys.push_back(argT);
@@ -2469,7 +2524,7 @@ void RewriteObjC::SynthSuperContructorFunctionDecl() {
// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
void RewriteObjC::SynthMsgSendFunctionDecl() {
IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend");
- llvm::SmallVector<QualType, 16> ArgTys;
+ SmallVector<QualType, 16> ArgTys;
QualType argT = Context->getObjCIdType();
assert(!argT.isNull() && "Can't find 'id' type");
ArgTys.push_back(argT);
@@ -2490,7 +2545,7 @@ void RewriteObjC::SynthMsgSendFunctionDecl() {
// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...);
void RewriteObjC::SynthMsgSendSuperFunctionDecl() {
IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper");
- llvm::SmallVector<QualType, 16> ArgTys;
+ SmallVector<QualType, 16> ArgTys;
RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
SourceLocation(), SourceLocation(),
&Context->Idents.get("objc_super"));
@@ -2514,7 +2569,7 @@ void RewriteObjC::SynthMsgSendSuperFunctionDecl() {
// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...);
void RewriteObjC::SynthMsgSendStretFunctionDecl() {
IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_stret");
- llvm::SmallVector<QualType, 16> ArgTys;
+ SmallVector<QualType, 16> ArgTys;
QualType argT = Context->getObjCIdType();
assert(!argT.isNull() && "Can't find 'id' type");
ArgTys.push_back(argT);
@@ -2537,7 +2592,7 @@ void RewriteObjC::SynthMsgSendStretFunctionDecl() {
void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() {
IdentifierInfo *msgSendIdent =
&Context->Idents.get("objc_msgSendSuper_stret");
- llvm::SmallVector<QualType, 16> ArgTys;
+ SmallVector<QualType, 16> ArgTys;
RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
SourceLocation(), SourceLocation(),
&Context->Idents.get("objc_super"));
@@ -2561,7 +2616,7 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() {
// SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...);
void RewriteObjC::SynthMsgSendFpretFunctionDecl() {
IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_fpret");
- llvm::SmallVector<QualType, 16> ArgTys;
+ SmallVector<QualType, 16> ArgTys;
QualType argT = Context->getObjCIdType();
assert(!argT.isNull() && "Can't find 'id' type");
ArgTys.push_back(argT);
@@ -2582,7 +2637,7 @@ void RewriteObjC::SynthMsgSendFpretFunctionDecl() {
// SynthGetClassFunctionDecl - id objc_getClass(const char *name);
void RewriteObjC::SynthGetClassFunctionDecl() {
IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass");
- llvm::SmallVector<QualType, 16> ArgTys;
+ SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(),
&ArgTys[0], ArgTys.size());
@@ -2598,7 +2653,7 @@ void RewriteObjC::SynthGetClassFunctionDecl() {
void RewriteObjC::SynthGetSuperClassFunctionDecl() {
IdentifierInfo *getSuperClassIdent =
&Context->Idents.get("class_getSuperclass");
- llvm::SmallVector<QualType, 16> ArgTys;
+ SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getObjCClassType());
QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(),
&ArgTys[0], ArgTys.size());
@@ -2615,7 +2670,7 @@ void RewriteObjC::SynthGetSuperClassFunctionDecl() {
// SynthGetMetaClassFunctionDecl - id objc_getClass(const char *name);
void RewriteObjC::SynthGetMetaClassFunctionDecl() {
IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass");
- llvm::SmallVector<QualType, 16> ArgTys;
+ SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(),
&ArgTys[0], ArgTys.size());
@@ -2667,7 +2722,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
SourceLocation());
// cast to NSConstantString *
CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(),
- CK_BitCast, Unop);
+ CK_CPointerToObjCPointerCast, Unop);
ReplaceStmt(Exp, cast);
// delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.
return cast;
@@ -2770,7 +2825,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
}
// Synthesize a call to objc_msgSend().
- llvm::SmallVector<Expr*, 8> MsgExprs;
+ SmallVector<Expr*, 8> MsgExprs;
switch (Exp->getReceiverKind()) {
case ObjCMessageExpr::SuperClass: {
MsgSendFlavor = MsgSendSuperFunctionDecl;
@@ -2780,7 +2835,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();
- llvm::SmallVector<Expr*, 4> InitExprs;
+ SmallVector<Expr*, 4> InitExprs;
// set the receiver to self, the first argument to all methods.
InitExprs.push_back(
@@ -2793,11 +2848,12 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
); // set the 'receiver'.
// (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
- llvm::SmallVector<Expr*, 8> ClsExprs;
+ SmallVector<Expr*, 8> ClsExprs;
QualType argType = Context->getPointerType(Context->CharTy);
ClsExprs.push_back(StringLiteral::Create(*Context,
ClassDecl->getIdentifier()->getName(),
- false, false, argType, SourceLocation()));
+ StringLiteral::Ascii, false,
+ argType, SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
@@ -2806,7 +2862,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// (Class)objc_getClass("CurrentClass")
CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,
Context->getObjCClassType(),
- CK_BitCast, Cls);
+ CK_CPointerToObjCPointerCast, Cls);
ClsExprs.clear();
ClsExprs.push_back(ArgExpr);
Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl,
@@ -2823,7 +2879,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
QualType superType = getSuperStructType();
Expr *SuperRep;
- if (LangOpts.Microsoft) {
+ if (LangOpts.MicrosoftExt) {
SynthSuperContructorFunctionDecl();
// Simulate a contructor call...
DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
@@ -2868,14 +2924,14 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
}
case ObjCMessageExpr::Class: {
- llvm::SmallVector<Expr*, 8> ClsExprs;
+ SmallVector<Expr*, 8> ClsExprs;
QualType argType = Context->getPointerType(Context->CharTy);
ObjCInterfaceDecl *Class
= Exp->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
IdentifierInfo *clsName = Class->getIdentifier();
ClsExprs.push_back(StringLiteral::Create(*Context,
clsName->getName(),
- false, false,
+ StringLiteral::Ascii, false,
argType, SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
&ClsExprs[0],
@@ -2891,7 +2947,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();
- llvm::SmallVector<Expr*, 4> InitExprs;
+ SmallVector<Expr*, 4> InitExprs;
InitExprs.push_back(
NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
@@ -2902,11 +2958,12 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
); // set the 'receiver'.
// (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
- llvm::SmallVector<Expr*, 8> ClsExprs;
+ SmallVector<Expr*, 8> ClsExprs;
QualType argType = Context->getPointerType(Context->CharTy);
ClsExprs.push_back(StringLiteral::Create(*Context,
ClassDecl->getIdentifier()->getName(),
- false, false, argType, SourceLocation()));
+ StringLiteral::Ascii, false, argType,
+ SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
@@ -2931,7 +2988,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
QualType superType = getSuperStructType();
Expr *SuperRep;
- if (LangOpts.Microsoft) {
+ if (LangOpts.MicrosoftExt) {
SynthSuperContructorFunctionDecl();
// Simulate a contructor call...
DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
@@ -2975,19 +3032,25 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
Expr *recExpr = Exp->getInstanceReceiver();
while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr))
recExpr = CE->getSubExpr();
+ CastKind CK = recExpr->getType()->isObjCObjectPointerType()
+ ? CK_BitCast : recExpr->getType()->isBlockPointerType()
+ ? CK_BlockPointerToObjCPointerCast
+ : CK_CPointerToObjCPointerCast;
+
recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
- CK_BitCast, recExpr);
+ CK, recExpr);
MsgExprs.push_back(recExpr);
break;
}
}
// Create a call to sel_registerName("selName"), it will be the 2nd argument.
- llvm::SmallVector<Expr*, 8> SelExprs;
+ SmallVector<Expr*, 8> SelExprs;
QualType argType = Context->getPointerType(Context->CharTy);
SelExprs.push_back(StringLiteral::Create(*Context,
Exp->getSelector().getAsString(),
- false, false, argType, SourceLocation()));
+ StringLiteral::Ascii, false,
+ argType, SourceLocation()));
CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
&SelExprs[0], SelExprs.size(),
StartLoc,
@@ -3005,16 +3068,42 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
type = Context->getObjCIdType();
// Make sure we convert "type (^)(...)" to "type (*)(...)".
(void)convertBlockPointerToFunctionPointer(type);
- userExpr = NoTypeInfoCStyleCastExpr(Context, type, CK_BitCast,
- userExpr);
+ const Expr *SubExpr = ICE->IgnoreParenImpCasts();
+ CastKind CK;
+ if (SubExpr->getType()->isIntegralType(*Context) &&
+ type->isBooleanType()) {
+ CK = CK_IntegralToBoolean;
+ } else if (type->isObjCObjectPointerType()) {
+ if (SubExpr->getType()->isBlockPointerType()) {
+ CK = CK_BlockPointerToObjCPointerCast;
+ } else if (SubExpr->getType()->isPointerType()) {
+ CK = CK_CPointerToObjCPointerCast;
+ } else {
+ CK = CK_BitCast;
+ }
+ } else {
+ CK = CK_BitCast;
+ }
+
+ userExpr = NoTypeInfoCStyleCastExpr(Context, type, CK, userExpr);
}
// Make id<P...> cast into an 'id' cast.
else if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(userExpr)) {
if (CE->getType()->isObjCQualifiedIdType()) {
while ((CE = dyn_cast<CStyleCastExpr>(userExpr)))
userExpr = CE->getSubExpr();
+ CastKind CK;
+ if (userExpr->getType()->isIntegralType(*Context)) {
+ CK = CK_IntegralToPointer;
+ } else if (userExpr->getType()->isBlockPointerType()) {
+ CK = CK_BlockPointerToObjCPointerCast;
+ } else if (userExpr->getType()->isPointerType()) {
+ CK = CK_CPointerToObjCPointerCast;
+ } else {
+ CK = CK_BitCast;
+ }
userExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
- CK_BitCast, userExpr);
+ CK, userExpr);
}
}
MsgExprs.push_back(userExpr);
@@ -3025,7 +3114,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
}
// Generate the funky cast.
CastExpr *cast;
- llvm::SmallVector<QualType, 8> ArgTypes;
+ SmallVector<QualType, 8> ArgTypes;
QualType returnType;
// Push 'id' and 'SEL', the 2 implicit arguments.
@@ -3045,8 +3134,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
(void)convertBlockPointerToFunctionPointer(t);
ArgTypes.push_back(t);
}
- returnType = OMD->getResultType()->isObjCQualifiedIdType()
- ? Context->getObjCIdType() : OMD->getResultType();
+ returnType = Exp->getType();
+ convertToUnqualifiedObjCType(returnType);
(void)convertBlockPointerToFunctionPointer(returnType);
} else {
returnType = Context->getObjCIdType();
@@ -3251,7 +3340,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
// SynthesizeObjCInternalStruct is ever called recursively.
Result += "\nstruct ";
Result += CDecl->getNameAsString();
- if (LangOpts.Microsoft)
+ if (LangOpts.MicrosoftExt)
Result += "_IMPL";
if (NumIvars > 0) {
@@ -3275,7 +3364,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
// This clause is segregated to avoid breaking the common case.
if (BufferContainsPPDirectives(startBuf, cursor)) {
SourceLocation L = RCDecl ? CDecl->getSuperClassLoc() :
- CDecl->getClassLoc();
+ CDecl->getAtStartLoc();
const char *endHeader = SM->getCharacterData(L);
endHeader += Lexer::MeasureTokenLength(L, *SM, LangOpts);
@@ -3299,7 +3388,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
// insert the super class structure definition.
SourceLocation OnePastCurly =
- LocStart.getFileLocWithOffset(cursor-startBuf+1);
+ LocStart.getLocWithOffset(cursor-startBuf+1);
InsertText(OnePastCurly, Result);
}
cursor++; // past '{'
@@ -3307,7 +3396,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
// Now comment out any visibility specifiers.
while (cursor < endBuf) {
if (*cursor == '@') {
- SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
+ SourceLocation atLoc = LocStart.getLocWithOffset(cursor-startBuf);
// Skip whitespace.
for (++cursor; cursor[0] == ' ' || cursor[0] == '\t'; ++cursor)
/*scan*/;
@@ -3324,20 +3413,20 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
// of user code, then scan the ivar list and use needToScanForQualifiers
// for type checking.
else if (*cursor == '<') {
- SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
+ SourceLocation atLoc = LocStart.getLocWithOffset(cursor-startBuf);
InsertText(atLoc, "/* ");
cursor = strchr(cursor, '>');
cursor++;
- atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
+ atLoc = LocStart.getLocWithOffset(cursor-startBuf);
InsertText(atLoc, " */");
} else if (*cursor == '^') { // rewrite block specifier.
- SourceLocation caretLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
+ SourceLocation caretLoc = LocStart.getLocWithOffset(cursor-startBuf);
ReplaceText(caretLoc, 1, "*");
}
cursor++;
}
// Don't forget to add a ';'!!
- InsertText(LocEnd.getFileLocWithOffset(1), ";");
+ InsertText(LocEnd.getLocWithOffset(1), ";");
} else { // we don't have any instance variables - insert super struct.
endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts);
Result += " {\n struct ";
@@ -3349,7 +3438,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
}
// Mark this struct as having been generated.
if (!ObjCSynthesizedStructs.insert(CDecl))
- assert(false && "struct already synthesize- SynthesizeObjCInternalStruct");
+ llvm_unreachable("struct already synthesize- SynthesizeObjCInternalStruct");
}
// RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or
@@ -3358,8 +3447,8 @@ template<typename MethodIterator>
void RewriteObjC::RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
MethodIterator MethodEnd,
bool IsInstanceMethod,
- llvm::StringRef prefix,
- llvm::StringRef ClassName,
+ StringRef prefix,
+ StringRef ClassName,
std::string &Result) {
if (MethodBegin == MethodEnd) return;
@@ -3428,8 +3517,8 @@ void RewriteObjC::RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
/// RewriteObjCProtocolMetaData - Rewrite protocols meta-data.
void RewriteObjC::
-RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, llvm::StringRef prefix,
- llvm::StringRef ClassName, std::string &Result) {
+RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, StringRef prefix,
+ StringRef ClassName, std::string &Result) {
static bool objc_protocol_methods = false;
// Output struct protocol_methods holder of method selector and type.
@@ -3570,13 +3659,13 @@ RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, llvm::StringRef prefix,
// Mark this protocol as having been generated.
if (!ObjCSynthesizedProtocols.insert(PDecl))
- assert(false && "protocol already synthesized");
+ llvm_unreachable("protocol already synthesized");
}
void RewriteObjC::
RewriteObjCProtocolListMetaData(const ObjCList<ObjCProtocolDecl> &Protocols,
- llvm::StringRef prefix, llvm::StringRef ClassName,
+ StringRef prefix, StringRef ClassName,
std::string &Result) {
if (Protocols.empty()) return;
@@ -3634,7 +3723,7 @@ void RewriteObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
FullCategoryName += IDecl->getNameAsString();
// Build _objc_method_list for class's instance methods if needed
- llvm::SmallVector<ObjCMethodDecl *, 32>
+ SmallVector<ObjCMethodDecl *, 32>
InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end());
// If any of our property implementations have associated getters or
@@ -3742,7 +3831,7 @@ void RewriteObjC::SynthesizeIvarOffsetComputation(ObjCIvarDecl *ivar,
} else {
Result += "__OFFSETOFIVAR__(struct ";
Result += ivar->getContainingInterface()->getNameAsString();
- if (LangOpts.Microsoft)
+ if (LangOpts.MicrosoftExt)
Result += "_IMPL";
Result += ", ";
Result += ivar->getNameAsString();
@@ -3804,7 +3893,7 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
Result += "\n";
ObjCInterfaceDecl::ivar_iterator IVI, IVE;
- llvm::SmallVector<ObjCIvarDecl *, 8> IVars;
+ SmallVector<ObjCIvarDecl *, 8> IVars;
if (!IDecl->ivar_empty()) {
for (ObjCInterfaceDecl::ivar_iterator
IV = IDecl->ivar_begin(), IVEnd = IDecl->ivar_end();
@@ -3843,7 +3932,7 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
}
// Build _objc_method_list for class's instance methods if needed
- llvm::SmallVector<ObjCMethodDecl *, 32>
+ SmallVector<ObjCMethodDecl *, 32>
InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end());
// If any of our property implementations have associated getters or
@@ -3986,7 +4075,7 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
// class has size. Must synthesize its size.
Result += ",sizeof(struct ";
Result += CDecl->getNameAsString();
- if (LangOpts.Microsoft)
+ if (LangOpts.MicrosoftExt)
Result += "_IMPL";
Result += ")";
}
@@ -4104,7 +4193,7 @@ void RewriteObjC::SynthesizeMetaDataIntoBuffer(std::string &Result) {
", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n";
Result += "};\n\n";
- if (LangOpts.Microsoft) {
+ if (LangOpts.MicrosoftExt) {
if (ProtocolExprDecls.size()) {
Result += "#pragma section(\".objc_protocol$B\",long,read,write)\n";
Result += "#pragma data_seg(push, \".objc_protocol$B\")\n";
@@ -4144,12 +4233,12 @@ static bool HasLocalVariableExternalStorage(ValueDecl *VD) {
}
std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
- llvm::StringRef funcName,
+ StringRef funcName,
std::string Tag) {
const FunctionType *AFT = CE->getFunctionType();
QualType RT = AFT->getResultType();
std::string StructRef = "struct " + Tag;
- std::string S = "static " + RT.getAsString(Context->PrintingPolicy) + " __" +
+ std::string S = "static " + RT.getAsString(Context->getPrintingPolicy()) + " __" +
funcName.str() + "_" + "block_func_" + utostr(i);
BlockDecl *BD = CE->getBlockDecl();
@@ -4173,9 +4262,9 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
ParamStr = (*AI)->getNameAsString();
QualType QT = (*AI)->getType();
if (convertBlockPointerToFunctionPointer(QT))
- QT.getAsStringInternal(ParamStr, Context->PrintingPolicy);
+ QT.getAsStringInternal(ParamStr, Context->getPrintingPolicy());
else
- QT.getAsStringInternal(ParamStr, Context->PrintingPolicy);
+ QT.getAsStringInternal(ParamStr, Context->getPrintingPolicy());
S += ParamStr;
}
if (FT->isVariadic()) {
@@ -4188,7 +4277,7 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
// Create local declarations to avoid rewriting all closure decl ref exprs.
// First, emit a declaration for all "by ref" decls.
- for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
S += " ";
std::string Name = (*I)->getNameAsString();
@@ -4199,7 +4288,7 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";
}
// Next, emit a declaration for all "by copy" declarations.
- for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
S += " ";
// Handle nested closure invocation. For example:
@@ -4224,7 +4313,7 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
QualType QT = (*I)->getType();
if (HasLocalVariableExternalStorage(*I))
QT = Context->getPointerType(QT);
- QT.getAsStringInternal(Name, Context->PrintingPolicy);
+ QT.getAsStringInternal(Name, Context->getPrintingPolicy());
S += Name + " = __cself->" +
(*I)->getNameAsString() + "; // bound by copy\n";
}
@@ -4238,7 +4327,7 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
}
std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
- llvm::StringRef funcName,
+ StringRef funcName,
std::string Tag) {
std::string StructRef = "struct " + Tag;
std::string S = "static void __";
@@ -4250,12 +4339,15 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
S += "*src) {";
for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
E = ImportedBlockDecls.end(); I != E; ++I) {
+ ValueDecl *VD = (*I);
S += "_Block_object_assign((void*)&dst->";
S += (*I)->getNameAsString();
S += ", (void*)src->";
S += (*I)->getNameAsString();
if (BlockByRefDeclsPtrSet.count((*I)))
S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
+ else if (VD->getType()->isBlockPointerType())
+ S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);";
else
S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);";
}
@@ -4268,10 +4360,13 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
S += "*src) {";
for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
E = ImportedBlockDecls.end(); I != E; ++I) {
+ ValueDecl *VD = (*I);
S += "_Block_object_dispose((void*)src->";
S += (*I)->getNameAsString();
if (BlockByRefDeclsPtrSet.count((*I)))
S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
+ else if (VD->getType()->isBlockPointerType())
+ S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);";
else
S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);";
}
@@ -4294,7 +4389,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
if (BlockDeclRefs.size()) {
// Output all "by copy" declarations.
- for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
S += " ";
std::string FieldName = (*I)->getNameAsString();
@@ -4316,14 +4411,14 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
QualType QT = (*I)->getType();
if (HasLocalVariableExternalStorage(*I))
QT = Context->getPointerType(QT);
- QT.getAsStringInternal(FieldName, Context->PrintingPolicy);
- QT.getAsStringInternal(ArgName, Context->PrintingPolicy);
+ QT.getAsStringInternal(FieldName, Context->getPrintingPolicy());
+ QT.getAsStringInternal(ArgName, Context->getPrintingPolicy());
Constructor += ", " + ArgName;
}
S += FieldName + ";\n";
}
// Output all "by ref" declarations.
- for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
S += " ";
std::string FieldName = (*I)->getNameAsString();
@@ -4342,7 +4437,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
Constructor += ", int flags=0)";
// Initialize all "by copy" arguments.
bool firsTime = true;
- for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
std::string Name = (*I)->getNameAsString();
if (firsTime) {
@@ -4357,7 +4452,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
Constructor += Name + "(_" + Name + ")";
}
// Initialize all "by ref" arguments.
- for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
std::string Name = (*I)->getNameAsString();
if (firsTime) {
@@ -4396,7 +4491,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag,
std::string ImplTag, int i,
- llvm::StringRef FunName,
+ StringRef FunName,
unsigned hasCopy) {
std::string S = "\nstatic struct " + DescTag;
@@ -4423,7 +4518,7 @@ std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag,
}
void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
- llvm::StringRef FunName) {
+ StringRef FunName) {
// Insert declaration for the function in which block literal is used.
if (CurFunctionDeclToDeclareForBlock && !Blocks.empty())
RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock);
@@ -4512,7 +4607,7 @@ void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
void RewriteObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) {
SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
- llvm::StringRef FuncName = FD->getName();
+ StringRef FuncName = FD->getName();
SynthesizeBlockLiterals(FunLocStart, FuncName);
}
@@ -4564,7 +4659,7 @@ void RewriteObjC::GetBlockDeclRefExprs(Stmt *S) {
}
void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S,
- llvm::SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs,
+ SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs,
llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts) {
for (Stmt::child_range CI = S->children(); CI; ++CI)
if (*CI) {
@@ -4603,7 +4698,7 @@ QualType RewriteObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) {
const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);
// FTP will be null for closures that don't take arguments.
// Generate a funky cast.
- llvm::SmallVector<QualType, 8> ArgTypes;
+ SmallVector<QualType, 8> ArgTypes;
QualType Res = FT->getResultType();
bool HasBlockType = convertBlockPointerToFunctionPointer(Res);
@@ -4673,7 +4768,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
QualType PtrBlock = Context->getPointerType(Context->getTagDeclType(RD));
// Generate a funky cast.
- llvm::SmallVector<QualType, 8> ArgTypes;
+ SmallVector<QualType, 8> ArgTypes;
// Push the block argument type.
ArgTypes.push_back(PtrBlock);
@@ -4716,7 +4811,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
CK_BitCast, ME);
PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast);
- llvm::SmallVector<Expr*, 8> BlkExprs;
+ SmallVector<Expr*, 8> BlkExprs;
// Add the implicit argument.
BlkExprs.push_back(BlkCast);
// Add the user arguments.
@@ -4767,7 +4862,7 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) {
FD->getType(), VK_LValue,
OK_Ordinary);
- llvm::StringRef Name = VD->getName();
+ StringRef Name = VD->getName();
FD = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
&Context->Idents.get(Name),
Context->VoidPtrTy, 0,
@@ -4835,7 +4930,7 @@ void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) {
switch (*argPtr) {
case '^':
// Replace the '^' with '*'.
- LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf);
+ LocStart = LocStart.getLocWithOffset(argPtr-startBuf);
ReplaceText(LocStart, 1, "*");
break;
}
@@ -4855,7 +4950,7 @@ void RewriteObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) {
parenCount++;
// advance the location to startArgList.
- DeclLoc = DeclLoc.getFileLocWithOffset(startArgList-startBuf);
+ DeclLoc = DeclLoc.getLocWithOffset(startArgList-startBuf);
assert((DeclLoc.isValid()) && "Invalid DeclLoc");
const char *argPtr = startArgList;
@@ -4864,7 +4959,7 @@ void RewriteObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) {
switch (*argPtr) {
case '^':
// Replace the '^' with '*'.
- DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList);
+ DeclLoc = DeclLoc.getLocWithOffset(argPtr-startArgList);
ReplaceText(DeclLoc, 1, "*");
break;
case '(':
@@ -4957,14 +5052,14 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND))
DeclT = FD->getType();
else
- assert(0 && "RewriteBlockPointerDecl(): Decl type not yet handled");
+ llvm_unreachable("RewriteBlockPointerDecl(): Decl type not yet handled");
const char *startBuf = SM->getCharacterData(DeclLoc);
const char *endBuf = startBuf;
// scan backward (from the decl location) for the end of the previous decl.
while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart)
startBuf--;
- SourceLocation Start = DeclLoc.getFileLocWithOffset(startBuf-endBuf);
+ SourceLocation Start = DeclLoc.getLocWithOffset(startBuf-endBuf);
std::string buf;
unsigned OrigLength=0;
// *startBuf != '^' if we are dealing with a pointer to function that
@@ -5108,7 +5203,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
DeclLoc = ND->getLocation();
const char *startBuf = SM->getCharacterData(DeclLoc);
SourceLocation X = ND->getLocEnd();
- X = SM->getInstantiationLoc(X);
+ X = SM->getExpansionLoc(X);
const char *endBuf = SM->getCharacterData(X);
std::string Name(ND->getNameAsString());
std::string ByrefType;
@@ -5130,7 +5225,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
QualType T = Ty;
(void)convertBlockPointerToFunctionPointer(T);
- T.getAsStringInternal(Name, Context->PrintingPolicy);
+ T.getAsStringInternal(Name, Context->getPrintingPolicy());
ByrefType += " " + Name + ";\n";
ByrefType += "};\n";
@@ -5203,7 +5298,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
startLoc = ECE->getLParenLoc();
else
startLoc = E->getLocStart();
- startLoc = SM->getInstantiationLoc(startLoc);
+ startLoc = SM->getExpansionLoc(startLoc);
endBuf = SM->getCharacterData(startLoc);
ByrefType += " " + Name;
ByrefType += " = {(void*)";
@@ -5235,7 +5330,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
const char *semiBuf = strchr(startInitializerBuf, ';');
assert((*semiBuf == ';') && "RewriteByRefVar: can't find ';'");
SourceLocation semiLoc =
- startLoc.getFileLocWithOffset(semiBuf-startInitializerBuf);
+ startLoc.getLocWithOffset(semiBuf-startInitializerBuf);
InsertText(semiLoc, "}");
}
@@ -5271,7 +5366,7 @@ void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) {
}
}
-FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(llvm::StringRef name) {
+FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(StringRef name) {
IdentifierInfo *ID = &Context->Idents.get(name);
QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy);
return FunctionDecl::Create(*Context, TUDecl, SourceLocation(),
@@ -5280,7 +5375,7 @@ FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(llvm::StringRef name) {
}
Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
- const llvm::SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs) {
+ const SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs) {
const BlockDecl *block = Exp->getBlockDecl();
Blocks.push_back(Exp);
@@ -5343,7 +5438,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, FType, VK_RValue,
SourceLocation());
- llvm::SmallVector<Expr*, 4> InitExprs;
+ SmallVector<Expr*, 4> InitExprs;
// Initialize the block function.
FD = SynthBlockInitFunctionDecl(Func);
@@ -5376,7 +5471,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
if (BlockDeclRefs.size()) {
Expr *Exp;
// Output all "by copy" declarations.
- for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
if (isObjCType((*I)->getType())) {
// FIXME: Conform to ABI ([[obj retain] autorelease]).
@@ -5410,7 +5505,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
InitExprs.push_back(Exp);
}
// Output all "by ref" declarations.
- for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
ValueDecl *ND = (*I);
std::string Name(ND->getNameAsString());
@@ -5557,7 +5652,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
}
if (BlockExpr *BE = dyn_cast<BlockExpr>(S)) {
- llvm::SmallVector<BlockDeclRefExpr *, 8> InnerBlockDeclRefs;
+ SmallVector<BlockDeclRefExpr *, 8> InnerBlockDeclRefs;
llvm::SmallPtrSet<const DeclContext *, 8> InnerContexts;
InnerContexts.insert(BE->getBlockDecl());
ImportedLocalExternalDecls.clear();
@@ -5568,12 +5663,20 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
CurrentBody = BE->getBody();
CollectPropertySetters(CurrentBody);
PropParentMap = 0;
+ // block literal on rhs of a property-dot-sytax assignment
+ // must be replaced by its synthesize ast so getRewrittenText
+ // works as expected. In this case, what actually ends up on RHS
+ // is the blockTranscribed which is the helper function for the
+ // block literal; as in: self.c = ^() {[ace ARR];};
+ bool saveDisableReplaceStmt = DisableReplaceStmt;
+ DisableReplaceStmt = false;
RewriteFunctionBodyOrGlobalInitializer(BE->getBody());
+ DisableReplaceStmt = saveDisableReplaceStmt;
CurrentBody = SaveCurrentBody;
PropParentMap = 0;
ImportedLocalExternalDecls.clear();
// Now we snarf the rewritten text and stash it away for later use.
- std::string Str = Rewrite.ConvertToString(BE->getBody());
+ std::string Str = Rewrite.getRewrittenText(BE->getSourceRange());
RewrittenBlockExprs[BE] = Str;
Stmt *blockTranscribed = SynthBlockInitExpr(BE, InnerBlockDeclRefs);
@@ -5866,8 +5969,8 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
ClassImplementation.push_back(CI);
else if (ObjCCategoryImplDecl *CI = dyn_cast<ObjCCategoryImplDecl>(D))
CategoryImplementation.push_back(CI);
- else if (ObjCClassDecl *CD = dyn_cast<ObjCClassDecl>(D))
- RewriteForwardClassDecl(CD);
+ else if (isa<ObjCClassDecl>(D))
+ llvm_unreachable("RewriteObjC::HandleDeclInMainFile - ObjCClassDecl");
else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
RewriteObjCQualifiedInterfaceTypes(VD);
if (isTopLevelBlockPointerType(VD->getType()))
@@ -5881,7 +5984,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
}
} else if (VD->getType()->isRecordType()) {
RecordDecl *RD = VD->getType()->getAs<RecordType>()->getDecl();
- if (RD->isDefinition())
+ if (RD->isCompleteDefinition())
RewriteRecordBody(RD);
}
if (VD->getInit()) {
@@ -5913,7 +6016,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
return;
}
if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
- if (RD->isDefinition())
+ if (RD->isCompleteDefinition())
RewriteRecordBody(RD);
return;
}
diff --git a/lib/Rewrite/RewriteRope.cpp b/lib/Rewrite/RewriteRope.cpp
index cfedd4b41faf..6c211b28fd99 100644
--- a/lib/Rewrite/RewriteRope.cpp
+++ b/lib/Rewrite/RewriteRope.cpp
@@ -12,11 +12,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Rewrite/RewriteRope.h"
-#include "llvm/Support/Casting.h"
+#include "clang/Basic/LLVM.h"
#include <algorithm>
using namespace clang;
-using llvm::dyn_cast;
-using llvm::cast;
/// RewriteRope is a "strong" string class, designed to make insertions and
/// deletions in the middle of the string nearly constant time (really, they are
diff --git a/lib/Rewrite/RewriteTest.cpp b/lib/Rewrite/RewriteTest.cpp
index 36207000c905..c446324d3eb2 100644
--- a/lib/Rewrite/RewriteTest.cpp
+++ b/lib/Rewrite/RewriteTest.cpp
@@ -16,7 +16,7 @@
#include "clang/Rewrite/TokenRewriter.h"
#include "llvm/Support/raw_ostream.h"
-void clang::DoRewriteTest(Preprocessor &PP, llvm::raw_ostream* OS) {
+void clang::DoRewriteTest(Preprocessor &PP, raw_ostream* OS) {
SourceManager &SM = PP.getSourceManager();
const LangOptions &LangOpts = PP.getLangOptions();
diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp
index 92f516074ec9..464b299ccdb0 100644
--- a/lib/Rewrite/Rewriter.cpp
+++ b/lib/Rewrite/Rewriter.cpp
@@ -17,10 +17,9 @@
#include "clang/AST/Decl.h"
#include "clang/Lex/Lexer.h"
#include "clang/Basic/SourceManager.h"
-#include "llvm/Support/raw_ostream.h"
using namespace clang;
-llvm::raw_ostream &RewriteBuffer::write(llvm::raw_ostream &os) const {
+raw_ostream &RewriteBuffer::write(raw_ostream &os) const {
// FIXME: eliminate the copy by writing out each chunk at a time
os << std::string(begin(), end());
return os;
@@ -84,7 +83,7 @@ void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size,
}
}
-void RewriteBuffer::InsertText(unsigned OrigOffset, llvm::StringRef Str,
+void RewriteBuffer::InsertText(unsigned OrigOffset, StringRef Str,
bool InsertAfter) {
// Nothing to insert, exit early.
@@ -101,7 +100,7 @@ void RewriteBuffer::InsertText(unsigned OrigOffset, llvm::StringRef Str,
/// buffer with a new string. This is effectively a combined "remove+insert"
/// operation.
void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength,
- llvm::StringRef NewStr) {
+ StringRef NewStr) {
unsigned RealOffset = getMappedOffset(OrigOffset, true);
Buffer.erase(RealOffset, OrigLength);
Buffer.insert(RealOffset, NewStr.begin(), NewStr.end());
@@ -222,7 +221,7 @@ RewriteBuffer &Rewriter::getEditBuffer(FileID FID) {
return I->second;
I = RewriteBuffers.insert(I, std::make_pair(FID, RewriteBuffer()));
- llvm::StringRef MB = SourceMgr->getBufferData(FID);
+ StringRef MB = SourceMgr->getBufferData(FID);
I->second.Initialize(MB.begin(), MB.end());
return I->second;
@@ -230,10 +229,8 @@ RewriteBuffer &Rewriter::getEditBuffer(FileID FID) {
/// InsertText - Insert the specified string at the specified location in the
/// original buffer.
-bool Rewriter::InsertText(SourceLocation Loc, llvm::StringRef Str,
+bool Rewriter::InsertText(SourceLocation Loc, StringRef Str,
bool InsertAfter, bool indentNewLines) {
- using llvm::StringRef;
-
if (!isRewritable(Loc)) return true;
FileID FID;
unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
@@ -256,7 +253,7 @@ bool Rewriter::InsertText(SourceLocation Loc, llvm::StringRef Str,
indentSpace = MB.substr(lineOffs, i-lineOffs);
}
- llvm::SmallVector<StringRef, 4> lines;
+ SmallVector<StringRef, 4> lines;
Str.split(lines, "\n");
for (unsigned i = 0, e = lines.size(); i != e; ++i) {
@@ -273,7 +270,7 @@ bool Rewriter::InsertText(SourceLocation Loc, llvm::StringRef Str,
return false;
}
-bool Rewriter::InsertTextAfterToken(SourceLocation Loc, llvm::StringRef Str) {
+bool Rewriter::InsertTextAfterToken(SourceLocation Loc, StringRef Str) {
if (!isRewritable(Loc)) return true;
FileID FID;
unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
@@ -298,7 +295,7 @@ bool Rewriter::RemoveText(SourceLocation Start, unsigned Length,
/// buffer with a new string. This is effectively a combined "remove/insert"
/// operation.
bool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength,
- llvm::StringRef NewStr) {
+ StringRef NewStr) {
if (!isRewritable(Start)) return true;
FileID StartFileID;
unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID);
@@ -317,7 +314,7 @@ bool Rewriter::ReplaceText(SourceRange range, SourceRange replacementRange) {
FileID FID;
unsigned newOffs = getLocationOffsetAndFileID(replacementRange.getBegin(),
FID);
- llvm::StringRef MB = SourceMgr->getBufferData(FID);
+ StringRef MB = SourceMgr->getBufferData(FID);
return ReplaceText(start, origLength, MB.substr(newOffs, newLength));
}
@@ -349,8 +346,6 @@ std::string Rewriter::ConvertToString(Stmt *From) {
bool Rewriter::IncreaseIndentation(CharSourceRange range,
SourceLocation parentIndent) {
- using llvm::StringRef;
-
if (range.isInvalid()) return true;
if (!isRewritable(range.getBegin())) return true;
if (!isRewritable(range.getEnd())) return true;
@@ -400,7 +395,7 @@ bool Rewriter::IncreaseIndentation(CharSourceRange range,
if (!startSpace.startswith(parentSpace))
return true;
- llvm::StringRef indent = startSpace.substr(parentSpace.size());
+ StringRef indent = startSpace.substr(parentSpace.size());
// Indent the lines between start/end offsets.
RewriteBuffer &RB = getEditBuffer(FID);
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 7a14855e69cd..babb8af18b37 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -17,6 +17,7 @@
#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/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
@@ -25,14 +26,23 @@
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/EvaluatedExprVisitor.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/Analyses/ReachableCode.h"
#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
+#include "clang/Analysis/Analyses/ThreadSafety.h"
#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
+#include <algorithm>
+#include <vector>
using namespace clang;
@@ -86,7 +96,7 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
// The CFG leaves in dead things, and we don't want the dead code paths to
// confuse us, so we mark all live things first.
llvm::BitVector live(cfg->getNumBlockIDs());
- unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(),
+ unsigned count = reachable_code::ScanReachableFromBlock(&cfg->getEntry(),
live);
bool AddEHEdges = AC.getAddEHEdges();
@@ -101,7 +111,7 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator()))
// When not adding EH edges from calls, catch clauses
// can otherwise seem dead. Avoid noting them as dead.
- count += reachable_code::ScanReachableFromBlock(b, live);
+ count += reachable_code::ScanReachableFromBlock(&b, live);
continue;
}
}
@@ -126,31 +136,23 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
if (!live[B.getBlockID()])
continue;
+ // Skip blocks which contain an element marked as no-return. They don't
+ // represent actually viable edges into the exit block, so mark them as
+ // abnormal.
+ if (B.hasNoReturnElement()) {
+ HasAbnormalEdge = true;
+ continue;
+ }
+
// Destructors can appear after the 'return' in the CFG. This is
// normal. We need to look pass the destructors for the return
// statement (if it exists).
CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend();
- bool hasNoReturnDtor = false;
-
- for ( ; ri != re ; ++ri) {
- CFGElement CE = *ri;
-
- // FIXME: The right solution is to just sever the edges in the
- // CFG itself.
- if (const CFGImplicitDtor *iDtor = ri->getAs<CFGImplicitDtor>())
- if (iDtor->isNoReturn(AC.getASTContext())) {
- hasNoReturnDtor = true;
- HasFakeEdge = true;
- break;
- }
-
- if (isa<CFGStmt>(CE))
+
+ for ( ; ri != re ; ++ri)
+ if (isa<CFGStmt>(*ri))
break;
- }
-
- if (hasNoReturnDtor)
- continue;
-
+
// No more CFGElements in the block?
if (ri == re) {
if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) {
@@ -163,7 +165,7 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
}
CFGStmt CS = cast<CFGStmt>(*ri);
- Stmt *S = CS.getStmt();
+ const Stmt *S = CS.getStmt();
if (isa<ReturnStmt>(S)) {
HasLiveReturn = true;
continue;
@@ -187,34 +189,13 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
HasAbnormalEdge = true;
continue;
}
-
- bool NoReturnEdge = false;
- if (CallExpr *C = dyn_cast<CallExpr>(S)) {
- if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit())
- == B.succ_end()) {
- HasAbnormalEdge = true;
- continue;
- }
- Expr *CEE = C->getCallee()->IgnoreParenCasts();
- QualType calleeType = CEE->getType();
- if (calleeType == AC.getASTContext().BoundMemberTy) {
- calleeType = Expr::findBoundMemberType(CEE);
- assert(!calleeType.isNull() && "analyzing unresolved call?");
- }
- if (getFunctionExtInfo(calleeType).getNoReturn()) {
- NoReturnEdge = true;
- HasFakeEdge = true;
- } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
- ValueDecl *VD = DRE->getDecl();
- if (VD->hasAttr<NoReturnAttr>()) {
- NoReturnEdge = true;
- HasFakeEdge = true;
- }
- }
+ if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit())
+ == B.succ_end()) {
+ HasAbnormalEdge = true;
+ continue;
}
- // FIXME: Add noreturn message sends.
- if (NoReturnEdge == false)
- HasPlainEdge = true;
+
+ HasPlainEdge = true;
}
if (!HasPlainEdge) {
if (HasLiveReturn)
@@ -258,7 +239,23 @@ struct CheckFallThroughDiagnostics {
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Func))
isVirtualMethod = Method->isVirtual();
- if (!isVirtualMethod)
+ // Don't suggest that template instantiations be marked "noreturn"
+ bool isTemplateInstantiation = false;
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func)) {
+ switch (Function->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ break;
+
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ isTemplateInstantiation = true;
+ break;
+ }
+ }
+
+ if (!isVirtualMethod && !isTemplateInstantiation)
D.diag_NeverFallThroughOrReturn =
diag::warn_suggest_noreturn_function;
else
@@ -284,25 +281,25 @@ struct CheckFallThroughDiagnostics {
return D;
}
- bool checkDiagnostics(Diagnostic &D, bool ReturnsVoid,
+ bool checkDiagnostics(DiagnosticsEngine &D, bool ReturnsVoid,
bool HasNoReturn) const {
if (funMode) {
return (ReturnsVoid ||
D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function,
- FuncLoc) == Diagnostic::Ignored)
+ FuncLoc) == DiagnosticsEngine::Ignored)
&& (!HasNoReturn ||
D.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr,
- FuncLoc) == Diagnostic::Ignored)
+ FuncLoc) == DiagnosticsEngine::Ignored)
&& (!ReturnsVoid ||
D.getDiagnosticLevel(diag::warn_suggest_noreturn_block, FuncLoc)
- == Diagnostic::Ignored);
+ == DiagnosticsEngine::Ignored);
}
// For blocks.
return ReturnsVoid && !HasNoReturn
&& (!ReturnsVoid ||
D.getDiagnosticLevel(diag::warn_suggest_noreturn_block, FuncLoc)
- == Diagnostic::Ignored);
+ == DiagnosticsEngine::Ignored);
}
};
@@ -340,7 +337,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
}
}
- Diagnostic &Diags = S.getDiagnostics();
+ DiagnosticsEngine &Diags = S.getDiagnostics();
// Short circuit for compilation speed.
if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
@@ -369,9 +366,17 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
CD.diag_AlwaysFallThrough_ReturnsNonVoid);
break;
case NeverFallThroughOrReturn:
- if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn)
- S.Diag(Compound->getLBracLoc(),
- CD.diag_NeverFallThroughOrReturn);
+ if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn)
+ << 0 << FD;
+ } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn)
+ << 1 << MD;
+ } else {
+ S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn);
+ }
+ }
break;
case NeverFallThrough:
break;
@@ -415,13 +420,58 @@ public:
};
}
+static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
+ // Don't issue a fixit if there is already an initializer.
+ if (VD->getInit())
+ return false;
+
+ // Suggest possible initialization (if any).
+ const char *initialization = 0;
+ QualType VariableTy = VD->getType().getCanonicalType();
+
+ if (VariableTy->isObjCObjectPointerType() ||
+ VariableTy->isBlockPointerType()) {
+ // Check if 'nil' is defined.
+ if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil")))
+ initialization = " = nil";
+ else
+ initialization = " = 0";
+ }
+ else if (VariableTy->isRealFloatingType())
+ initialization = " = 0.0";
+ else if (VariableTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus)
+ initialization = " = false";
+ else if (VariableTy->isEnumeralType())
+ return false;
+ else if (VariableTy->isPointerType() || VariableTy->isMemberPointerType()) {
+ if (S.Context.getLangOptions().CPlusPlus0x)
+ initialization = " = nullptr";
+ // Check if 'NULL' is defined.
+ else if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("NULL")))
+ initialization = " = NULL";
+ else
+ initialization = " = 0";
+ }
+ else if (VariableTy->isScalarType())
+ initialization = " = 0";
+
+ if (initialization) {
+ SourceLocation loc = S.PP.getLocForEndOfToken(VD->getLocEnd());
+ S.Diag(loc, diag::note_var_fixit_add_initialization) << VD->getDeclName()
+ << FixItHint::CreateInsertion(loc, initialization);
+ return true;
+ }
+ return false;
+}
+
/// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an
/// uninitialized variable. This manages the different forms of diagnostic
/// emitted for particular types of uses. Returns true if the use was diagnosed
/// as a warning. If a pariticular use is one we omit warnings for, returns
/// false.
static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD,
- const Expr *E, bool isAlwaysUninit) {
+ const Expr *E, bool isAlwaysUninit,
+ bool alwaysReportSelfInit = false) {
bool isSelfInit = false;
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
@@ -441,7 +491,7 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD,
// TODO: Should we suppress maybe-uninitialized warnings for
// variables initialized in this way?
if (const Expr *Initializer = VD->getInit()) {
- if (DRE == Initializer->IgnoreParenImpCasts())
+ if (!alwaysReportSelfInit && DRE == Initializer->IgnoreParenImpCasts())
return false;
ContainsReference CR(S.Context, DRE);
@@ -469,54 +519,15 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD,
}
// Report where the variable was declared when the use wasn't within
- // the initializer of that declaration.
- if (!isSelfInit)
+ // the initializer of that declaration & we didn't already suggest
+ // an initialization fixit.
+ if (!isSelfInit && !SuggestInitializationFixit(S, VD))
S.Diag(VD->getLocStart(), diag::note_uninit_var_def)
<< VD->getDeclName();
return true;
}
-static void SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
- // Don't issue a fixit if there is already an initializer.
- if (VD->getInit())
- return;
-
- // Suggest possible initialization (if any).
- const char *initialization = 0;
- QualType VariableTy = VD->getType().getCanonicalType();
-
- if (VariableTy->isObjCObjectPointerType() ||
- VariableTy->isBlockPointerType()) {
- // Check if 'nil' is defined.
- if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil")))
- initialization = " = nil";
- else
- initialization = " = 0";
- }
- else if (VariableTy->isRealFloatingType())
- initialization = " = 0.0";
- else if (VariableTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus)
- initialization = " = false";
- else if (VariableTy->isEnumeralType())
- return;
- else if (VariableTy->isPointerType() || VariableTy->isMemberPointerType()) {
- // Check if 'NULL' is defined.
- if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("NULL")))
- initialization = " = NULL";
- else
- initialization = " = 0";
- }
- else if (VariableTy->isScalarType())
- initialization = " = 0";
-
- if (initialization) {
- SourceLocation loc = S.PP.getLocForEndOfToken(VD->getLocEnd());
- S.Diag(loc, diag::note_var_fixit_add_initialization)
- << FixItHint::CreateInsertion(loc, initialization);
- }
-}
-
typedef std::pair<const Expr*, bool> UninitUse;
namespace {
@@ -530,8 +541,8 @@ struct SLocSort {
class UninitValsDiagReporter : public UninitVariablesHandler {
Sema &S;
- typedef llvm::SmallVector<UninitUse, 2> UsesVec;
- typedef llvm::DenseMap<const VarDecl *, UsesVec*> UsesMap;
+ typedef SmallVector<UninitUse, 2> UsesVec;
+ typedef llvm::DenseMap<const VarDecl *, std::pair<UsesVec*, bool> > UsesMap;
UsesMap *uses;
public:
@@ -539,17 +550,26 @@ public:
~UninitValsDiagReporter() {
flushDiagnostics();
}
-
- void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd,
- bool isAlwaysUninit) {
+
+ std::pair<UsesVec*, bool> &getUses(const VarDecl *vd) {
if (!uses)
uses = new UsesMap();
-
- UsesVec *&vec = (*uses)[vd];
+
+ UsesMap::mapped_type &V = (*uses)[vd];
+ UsesVec *&vec = V.first;
if (!vec)
vec = new UsesVec();
- vec->push_back(std::make_pair(ex, isAlwaysUninit));
+ return V;
+ }
+
+ void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd,
+ bool isAlwaysUninit) {
+ getUses(vd).first->push_back(std::make_pair(ex, isAlwaysUninit));
+ }
+
+ void handleSelfInit(const VarDecl *vd) {
+ getUses(vd).second = true;
}
void flushDiagnostics() {
@@ -558,28 +578,34 @@ public:
for (UsesMap::iterator i = uses->begin(), e = uses->end(); i != e; ++i) {
const VarDecl *vd = i->first;
- UsesVec *vec = i->second;
-
- bool fixitIssued = false;
-
- // Sort the uses by their SourceLocations. While not strictly
- // guaranteed to produce them in line/column order, this will provide
- // a stable ordering.
- std::sort(vec->begin(), vec->end(), SLocSort());
-
- for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve;
- ++vi) {
- if (!DiagnoseUninitializedUse(S, vd, vi->first,
- /*isAlwaysUninit=*/vi->second))
- continue;
-
- // Suggest a fixit hint the first time we diagnose a use of a variable.
- if (!fixitIssued) {
- SuggestInitializationFixit(S, vd);
- fixitIssued = true;
+ const UsesMap::mapped_type &V = i->second;
+
+ UsesVec *vec = V.first;
+ bool hasSelfInit = V.second;
+
+ // Specially handle the case where we have uses of an uninitialized
+ // variable, but the root cause is an idiomatic self-init. We want
+ // to report the diagnostic at the self-init since that is the root cause.
+ if (!vec->empty() && hasSelfInit)
+ DiagnoseUninitializedUse(S, vd, vd->getInit()->IgnoreParenCasts(),
+ true, /* alwaysReportSelfInit */ true);
+ else {
+ // Sort the uses by their SourceLocations. While not strictly
+ // guaranteed to produce them in line/column order, this will provide
+ // a stable ordering.
+ std::sort(vec->begin(), vec->end(), SLocSort());
+
+ for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve;
+ ++vi) {
+ if (DiagnoseUninitializedUse(S, vd, vi->first,
+ /*isAlwaysUninit=*/vi->second))
+ // Skip further diagnostics for this variable. We try to warn only
+ // on the first point at which a variable is used uninitialized.
+ break;
}
}
-
+
+ // Release the uses vector.
delete vec;
}
delete uses;
@@ -587,6 +613,132 @@ public:
};
}
+
+//===----------------------------------------------------------------------===//
+// -Wthread-safety
+//===----------------------------------------------------------------------===//
+namespace clang {
+namespace thread_safety {
+typedef std::pair<SourceLocation, PartialDiagnostic> DelayedDiag;
+typedef llvm::SmallVector<DelayedDiag, 4> DiagList;
+
+struct SortDiagBySourceLocation {
+ Sema &S;
+ SortDiagBySourceLocation(Sema &S) : S(S) {}
+
+ bool operator()(const DelayedDiag &left, const DelayedDiag &right) {
+ // Although this call will be slow, this is only called when outputting
+ // multiple warnings.
+ return S.getSourceManager().isBeforeInTranslationUnit(left.first,
+ right.first);
+ }
+};
+
+class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
+ Sema &S;
+ DiagList Warnings;
+
+ // Helper functions
+ void warnLockMismatch(unsigned DiagID, Name LockName, SourceLocation Loc) {
+ PartialDiagnostic Warning = S.PDiag(DiagID) << LockName;
+ Warnings.push_back(DelayedDiag(Loc, Warning));
+ }
+
+ public:
+ ThreadSafetyReporter(Sema &S) : S(S) {}
+
+ /// \brief Emit all buffered diagnostics in order of sourcelocation.
+ /// We need to output diagnostics produced while iterating through
+ /// the lockset in deterministic order, so this function orders diagnostics
+ /// and outputs them.
+ void emitDiagnostics() {
+ SortDiagBySourceLocation SortDiagBySL(S);
+ sort(Warnings.begin(), Warnings.end(), SortDiagBySL);
+ for (DiagList::iterator I = Warnings.begin(), E = Warnings.end();
+ I != E; ++I)
+ S.Diag(I->first, I->second);
+ }
+
+ void handleInvalidLockExp(SourceLocation Loc) {
+ PartialDiagnostic Warning = S.PDiag(diag::warn_cannot_resolve_lock) << Loc;
+ Warnings.push_back(DelayedDiag(Loc, Warning));
+ }
+ void handleUnmatchedUnlock(Name LockName, SourceLocation Loc) {
+ warnLockMismatch(diag::warn_unlock_but_no_lock, LockName, Loc);
+ }
+
+ void handleDoubleLock(Name LockName, SourceLocation Loc) {
+ warnLockMismatch(diag::warn_double_lock, LockName, Loc);
+ }
+
+ void handleMutexHeldEndOfScope(Name LockName, SourceLocation Loc,
+ LockErrorKind LEK){
+ unsigned DiagID = 0;
+ switch (LEK) {
+ case LEK_LockedSomePredecessors:
+ DiagID = diag::warn_lock_at_end_of_scope;
+ break;
+ case LEK_LockedSomeLoopIterations:
+ DiagID = diag::warn_expecting_lock_held_on_loop;
+ break;
+ case LEK_LockedAtEndOfFunction:
+ DiagID = diag::warn_no_unlock;
+ break;
+ }
+ warnLockMismatch(DiagID, LockName, Loc);
+ }
+
+
+ void handleExclusiveAndShared(Name LockName, SourceLocation Loc1,
+ SourceLocation Loc2) {
+ PartialDiagnostic Warning =
+ S.PDiag(diag::warn_lock_exclusive_and_shared) << LockName;
+ PartialDiagnostic Note =
+ S.PDiag(diag::note_lock_exclusive_and_shared) << LockName;
+ Warnings.push_back(DelayedDiag(Loc1, Warning));
+ Warnings.push_back(DelayedDiag(Loc2, Note));
+ }
+
+ void handleNoMutexHeld(const NamedDecl *D, ProtectedOperationKind POK,
+ AccessKind AK, SourceLocation Loc) {
+ assert((POK == POK_VarAccess || POK == POK_VarDereference)
+ && "Only works for variables");
+ unsigned DiagID = POK == POK_VarAccess?
+ diag::warn_variable_requires_any_lock:
+ diag::warn_var_deref_requires_any_lock;
+ PartialDiagnostic Warning = S.PDiag(DiagID)
+ << D->getName() << getLockKindFromAccessKind(AK);
+ Warnings.push_back(DelayedDiag(Loc, Warning));
+ }
+
+ void handleMutexNotHeld(const NamedDecl *D, ProtectedOperationKind POK,
+ Name LockName, LockKind LK, SourceLocation Loc) {
+ unsigned DiagID = 0;
+ switch (POK) {
+ case POK_VarAccess:
+ DiagID = diag::warn_variable_requires_lock;
+ break;
+ case POK_VarDereference:
+ DiagID = diag::warn_var_deref_requires_lock;
+ break;
+ case POK_FunctionCall:
+ DiagID = diag::warn_fun_requires_lock;
+ break;
+ }
+ PartialDiagnostic Warning = S.PDiag(DiagID)
+ << D->getName() << LockName << LK;
+ Warnings.push_back(DelayedDiag(Loc, Warning));
+ }
+
+ void handleFunExcludesLock(Name FunName, Name LockName, SourceLocation Loc) {
+ PartialDiagnostic Warning =
+ S.PDiag(diag::warn_fun_excludes_mutex) << FunName << LockName;
+ Warnings.push_back(DelayedDiag(Loc, Warning));
+ }
+};
+}
+}
+
//===----------------------------------------------------------------------===//
// AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based
// warnings on a function, method, or block.
@@ -595,6 +747,7 @@ public:
clang::sema::AnalysisBasedWarnings::Policy::Policy() {
enableCheckFallThrough = 1;
enableCheckUnreachable = 0;
+ enableThreadSafetyAnalysis = 0;
}
clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
@@ -608,14 +761,18 @@ clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
MaxUninitAnalysisVariablesPerFunction(0),
NumUninitAnalysisBlockVisits(0),
MaxUninitAnalysisBlockVisitsPerFunction(0) {
- Diagnostic &D = S.getDiagnostics();
+ DiagnosticsEngine &D = S.getDiagnostics();
DefaultPolicy.enableCheckUnreachable = (unsigned)
(D.getDiagnosticLevel(diag::warn_unreachable, SourceLocation()) !=
- Diagnostic::Ignored);
+ DiagnosticsEngine::Ignored);
+ DefaultPolicy.enableThreadSafetyAnalysis = (unsigned)
+ (D.getDiagnosticLevel(diag::warn_double_lock, SourceLocation()) !=
+ DiagnosticsEngine::Ignored);
+
}
static void flushDiagnostics(Sema &S, sema::FunctionScopeInfo *fscope) {
- for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
+ for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
i = fscope->PossiblyUnreachableDiags.begin(),
e = fscope->PossiblyUnreachableDiags.end();
i != e; ++i) {
@@ -635,7 +792,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
// don't bother trying.
// (2) The code already has problems; running the analysis just takes more
// time.
- Diagnostic &Diags = S.getDiagnostics();
+ DiagnosticsEngine &Diags = S.getDiagnostics();
// Do not do any analysis for declarations in system headers if we are
// going to just ignore them.
@@ -656,17 +813,43 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
const Stmt *Body = D->getBody();
assert(Body);
+ AnalysisContext AC(D, 0);
+
// Don't generate EH edges for CallExprs as we'd like to avoid the n^2
// explosion for destrutors that can result and the compile time hit.
- AnalysisContext AC(D, 0, /*useUnoptimizedCFG=*/false, /*addehedges=*/false,
- /*addImplicitDtors=*/true, /*addInitializers=*/true);
+ AC.getCFGBuildOptions().PruneTriviallyFalseEdges = true;
+ AC.getCFGBuildOptions().AddEHEdges = false;
+ AC.getCFGBuildOptions().AddInitializers = true;
+ AC.getCFGBuildOptions().AddImplicitDtors = true;
+
+ // Force that certain expressions appear as CFGElements in the CFG. This
+ // is used to speed up various analyses.
+ // FIXME: This isn't the right factoring. This is here for initial
+ // prototyping, but we need a way for analyses to say what expressions they
+ // expect to always be CFGElements and then fill in the BuildOptions
+ // appropriately. This is essentially a layering violation.
+ if (P.enableCheckUnreachable) {
+ // Unreachable code analysis requires a linearized CFG.
+ AC.getCFGBuildOptions().setAllAlwaysAdd();
+ }
+ else {
+ AC.getCFGBuildOptions()
+ .setAlwaysAdd(Stmt::BinaryOperatorClass)
+ .setAlwaysAdd(Stmt::BlockExprClass)
+ .setAlwaysAdd(Stmt::CStyleCastExprClass)
+ .setAlwaysAdd(Stmt::DeclRefExprClass)
+ .setAlwaysAdd(Stmt::ImplicitCastExprClass)
+ .setAlwaysAdd(Stmt::UnaryOperatorClass);
+ }
+ // Construct the analysis context with the specified CFG build options.
+
// Emit delayed diagnostics.
if (!fscope->PossiblyUnreachableDiags.empty()) {
bool analyzed = false;
// Register the expressions with the CFGBuilder.
- for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
+ for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
i = fscope->PossiblyUnreachableDiags.begin(),
e = fscope->PossiblyUnreachableDiags.end();
i != e; ++i) {
@@ -676,7 +859,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
if (AC.getCFG()) {
analyzed = true;
- for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
+ for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
i = fscope->PossiblyUnreachableDiags.begin(),
e = fscope->PossiblyUnreachableDiags.end();
i != e; ++i)
@@ -716,11 +899,18 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
// Warning: check for unreachable code
if (P.enableCheckUnreachable)
CheckUnreachable(S, AC);
-
+
+ // Check for thread safety violations
+ if (P.enableThreadSafetyAnalysis) {
+ thread_safety::ThreadSafetyReporter Reporter(S);
+ thread_safety::runThreadSafetyAnalysis(AC, Reporter);
+ Reporter.emitDiagnostics();
+ }
+
if (Diags.getDiagnosticLevel(diag::warn_uninit_var, D->getLocStart())
- != Diagnostic::Ignored ||
+ != DiagnosticsEngine::Ignored ||
Diags.getDiagnosticLevel(diag::warn_maybe_uninit_var, D->getLocStart())
- != Diagnostic::Ignored) {
+ != DiagnosticsEngine::Ignored) {
if (CFG *cfg = AC.getCFG()) {
UninitValsDiagReporter reporter(S);
UninitVariablesAnalysisStats stats;
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index 5a8330bbfd77..13a0edec28d6 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -98,7 +98,7 @@ AttributePool::createIntegerAttribute(ASTContext &C, IdentifierInfo *Name,
}
AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
- llvm::StringRef AttrName = Name->getName();
+ StringRef AttrName = Name->getName();
// Normalize the attribute name, __foo__ becomes foo.
if (AttrName.startswith("__") && AttrName.endswith("__"))
@@ -159,10 +159,11 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("address_space", AT_address_space)
.Case("opencl_image_access", AT_opencl_image_access)
.Case("always_inline", AT_always_inline)
- .Case("returns_twice", IgnoredAttribute)
+ .Case("returns_twice", AT_returns_twice)
.Case("vec_type_hint", IgnoredAttribute)
.Case("objc_exception", AT_objc_exception)
.Case("objc_method_family", AT_objc_method_family)
+ .Case("objc_returns_inner_pointer", AT_objc_returns_inner_pointer)
.Case("ext_vector_type", AT_ext_vector_type)
.Case("neon_vector_type", AT_neon_vector_type)
.Case("neon_polyvector_type", AT_neon_polyvector_type)
@@ -170,15 +171,18 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("analyzer_noreturn", AT_analyzer_noreturn)
.Case("warn_unused_result", AT_warn_unused_result)
.Case("carries_dependency", AT_carries_dependency)
+ .Case("ns_bridged", AT_ns_bridged)
.Case("ns_consumed", AT_ns_consumed)
.Case("ns_consumes_self", AT_ns_consumes_self)
.Case("ns_returns_autoreleased", AT_ns_returns_autoreleased)
.Case("ns_returns_not_retained", AT_ns_returns_not_retained)
.Case("ns_returns_retained", AT_ns_returns_retained)
+ .Case("cf_audited_transfer", AT_cf_audited_transfer)
.Case("cf_consumed", AT_cf_consumed)
.Case("cf_returns_not_retained", AT_cf_returns_not_retained)
.Case("cf_returns_retained", AT_cf_returns_retained)
.Case("cf_returns_autoreleased", AT_cf_returns_autoreleased)
+ .Case("cf_unknown_transfer", AT_cf_unknown_transfer)
.Case("ns_consumes_self", AT_ns_consumes_self)
.Case("ns_consumed", AT_ns_consumed)
.Case("objc_ownership", AT_objc_ownership)
@@ -209,5 +213,23 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("uuid", AT_uuid)
.Case("pcs", AT_pcs)
.Case("ms_struct", AT_MsStruct)
+ .Case("guarded_var", AT_guarded_var)
+ .Case("pt_guarded_var", AT_pt_guarded_var)
+ .Case("scoped_lockable", AT_scoped_lockable)
+ .Case("lockable", AT_lockable)
+ .Case("no_thread_safety_analysis", AT_no_thread_safety_analysis)
+ .Case("guarded_by", AT_guarded_by)
+ .Case("pt_guarded_by", AT_pt_guarded_by)
+ .Case("acquired_after", AT_acquired_after)
+ .Case("acquired_before", AT_acquired_before)
+ .Case("exclusive_lock_function", AT_exclusive_lock_function)
+ .Case("exclusive_locks_required", AT_exclusive_locks_required)
+ .Case("exclusive_trylock_function", AT_exclusive_trylock_function)
+ .Case("lock_returned", AT_lock_returned)
+ .Case("locks_excluded", AT_locks_excluded)
+ .Case("shared_lock_function", AT_shared_lock_function)
+ .Case("shared_locks_required", AT_shared_locks_required)
+ .Case("shared_trylock_function", AT_shared_trylock_function)
+ .Case("unlock_function", AT_unlock_function)
.Default(UnknownAttribute);
}
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 652198189a4c..dbbb980de850 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -8,12 +8,13 @@ add_clang_library(clangSema
DelayedDiagnostic.cpp
IdentifierResolver.cpp
JumpDiagnostics.cpp
+ MultiInitializer.cpp
Scope.cpp
Sema.cpp
SemaAccess.cpp
SemaAttr.cpp
- SemaCXXCast.cpp
SemaCXXScopeSpec.cpp
+ SemaCast.cpp
SemaChecking.cpp
SemaCodeComplete.cpp
SemaDecl.cpp
@@ -25,6 +26,7 @@ add_clang_library(clangSema
SemaExprCXX.cpp
SemaExprMember.cpp
SemaExprObjC.cpp
+ SemaFixItUtils.cpp
SemaInit.cpp
SemaLookup.cpp
SemaObjCProperty.cpp
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index d7dc5b2538c6..da9860361bc3 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -26,7 +26,6 @@
#include <functional>
using namespace clang;
-using llvm::StringRef;
//===----------------------------------------------------------------------===//
// Code completion context implementation
@@ -68,7 +67,7 @@ bool CodeCompletionContext::wantConstructorResults() const {
case CCC_OtherWithMacros:
case CCC_ObjCInstanceMessage:
case CCC_ObjCClassMessage:
- case CCC_ObjCSuperclass:
+ case CCC_ObjCInterfaceName:
case CCC_ObjCCategoryName:
return false;
}
@@ -191,14 +190,36 @@ CodeCompletionString::Chunk::CreateCurrentParameter(
CodeCompletionString::CodeCompletionString(const Chunk *Chunks,
unsigned NumChunks,
unsigned Priority,
- CXAvailabilityKind Availability)
- : NumChunks(NumChunks), Priority(Priority), Availability(Availability)
+ CXAvailabilityKind Availability,
+ const char **Annotations,
+ unsigned NumAnnotations)
+ : NumChunks(NumChunks), NumAnnotations(NumAnnotations)
+ , Priority(Priority), Availability(Availability)
{
+ assert(NumChunks <= 0xffff);
+ assert(NumAnnotations <= 0xffff);
+
Chunk *StoredChunks = reinterpret_cast<Chunk *>(this + 1);
for (unsigned I = 0; I != NumChunks; ++I)
StoredChunks[I] = Chunks[I];
+
+ const char **StoredAnnotations = reinterpret_cast<const char **>(StoredChunks + NumChunks);
+ for (unsigned I = 0; I != NumAnnotations; ++I)
+ StoredAnnotations[I] = Annotations[I];
+}
+
+unsigned CodeCompletionString::getAnnotationCount() const {
+ return NumAnnotations;
+}
+
+const char *CodeCompletionString::getAnnotation(unsigned AnnotationNr) const {
+ if (AnnotationNr < NumAnnotations)
+ return reinterpret_cast<const char * const*>(end())[AnnotationNr];
+ else
+ return 0;
}
+
std::string CodeCompletionString::getAsString() const {
std::string Result;
llvm::raw_string_ostream OS(Result);
@@ -228,14 +249,14 @@ const char *CodeCompletionString::getTypedText() const {
return 0;
}
-const char *CodeCompletionAllocator::CopyString(llvm::StringRef String) {
+const char *CodeCompletionAllocator::CopyString(StringRef String) {
char *Mem = (char *)Allocate(String.size() + 1, 1);
std::copy(String.begin(), String.end(), Mem);
Mem[String.size()] = 0;
return Mem;
}
-const char *CodeCompletionAllocator::CopyString(llvm::Twine String) {
+const char *CodeCompletionAllocator::CopyString(Twine String) {
// FIXME: It would be more efficient to teach Twine to tell us its size and
// then add a routine there to fill in an allocated char* with the contents
// of the string.
@@ -245,11 +266,13 @@ const char *CodeCompletionAllocator::CopyString(llvm::Twine String) {
CodeCompletionString *CodeCompletionBuilder::TakeString() {
void *Mem = Allocator.Allocate(
- sizeof(CodeCompletionString) + sizeof(Chunk) * Chunks.size(),
+ sizeof(CodeCompletionString) + sizeof(Chunk) * Chunks.size()
+ + sizeof(const char *) * Annotations.size(),
llvm::alignOf<CodeCompletionString>());
CodeCompletionString *Result
= new (Mem) CodeCompletionString(Chunks.data(), Chunks.size(),
- Priority, Availability);
+ Priority, Availability,
+ Annotations.data(), Annotations.size());
Chunks.clear();
return Result;
}
@@ -329,7 +352,7 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
OS << "COMPLETION: ";
switch (Results[I].Kind) {
case CodeCompletionResult::RK_Declaration:
- OS << Results[I].Declaration;
+ OS << *Results[I].Declaration;
if (Results[I].Hidden)
OS << " (Hidden)";
if (CodeCompletionString *CCS
@@ -377,7 +400,7 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
}
}
-void CodeCompletionResult::computeCursorKindAndAvailability() {
+void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) {
switch (Kind) {
case RK_Declaration:
// Set the availability based on attributes.
@@ -419,13 +442,16 @@ void CodeCompletionResult::computeCursorKindAndAvailability() {
// Do nothing: Patterns can come with cursor kinds!
break;
}
+
+ if (!Accessible)
+ Availability = CXAvailability_NotAccessible;
}
/// \brief Retrieve the name that should be used to order a result.
///
/// If the name needs to be constructed as a string, that string will be
/// saved into Saved and the returned StringRef will refer to it.
-static llvm::StringRef getOrderedName(const CodeCompletionResult &R,
+static StringRef getOrderedName(const CodeCompletionResult &R,
std::string &Saved) {
switch (R.Kind) {
case CodeCompletionResult::RK_Keyword:
@@ -460,8 +486,8 @@ static llvm::StringRef getOrderedName(const CodeCompletionResult &R,
bool clang::operator<(const CodeCompletionResult &X,
const CodeCompletionResult &Y) {
std::string XSaved, YSaved;
- llvm::StringRef XStr = getOrderedName(X, XSaved);
- llvm::StringRef YStr = getOrderedName(Y, YSaved);
+ StringRef XStr = getOrderedName(X, XSaved);
+ StringRef YStr = getOrderedName(Y, YSaved);
int cmp = XStr.compare_lower(YStr);
if (cmp)
return cmp < 0;
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index c87f2cff5489..f0a763e4ecfd 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -15,6 +15,7 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/LocInfoType.h"
#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/Sema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/NestedNameSpecifier.h"
@@ -27,7 +28,7 @@
using namespace clang;
-static DiagnosticBuilder Diag(Diagnostic &D, SourceLocation Loc,
+static DiagnosticBuilder Diag(DiagnosticsEngine &D, SourceLocation Loc,
unsigned DiagID) {
return D.Report(Loc, DiagID);
}
@@ -242,6 +243,7 @@ bool Declarator::isDeclarationOfFunction() const {
}
switch (DS.getTypeSpecType()) {
+ case TST_atomic:
case TST_auto:
case TST_bool:
case TST_char:
@@ -255,6 +257,7 @@ bool Declarator::isDeclarationOfFunction() const {
case TST_enum:
case TST_error:
case TST_float:
+ case TST_half:
case TST_int:
case TST_struct:
case TST_union:
@@ -371,6 +374,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
case DeclSpec::TST_char16: return "char16_t";
case DeclSpec::TST_char32: return "char32_t";
case DeclSpec::TST_int: return "int";
+ case DeclSpec::TST_half: return "half";
case DeclSpec::TST_float: return "float";
case DeclSpec::TST_double: return "double";
case DeclSpec::TST_bool: return "_Bool";
@@ -388,6 +392,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
case DeclSpec::TST_decltype: return "(decltype)";
case DeclSpec::TST_underlyingType: return "__underlying_type";
case DeclSpec::TST_unknown_anytype: return "__unknown_anytype";
+ case DeclSpec::TST_atomic: return "_Atomic";
case DeclSpec::TST_error: return "(error)";
}
llvm_unreachable("Unknown typespec!");
@@ -403,21 +408,24 @@ const char *DeclSpec::getSpecifierName(TQ T) {
llvm_unreachable("Unknown typespec!");
}
-bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc,
+bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc,
const char *&PrevSpec,
- unsigned &DiagID,
- const LangOptions &Lang) {
- // OpenCL prohibits extern, auto, register, and static
+ unsigned &DiagID) {
+ // OpenCL 1.1 6.8g: "The extern, static, auto and register storage-class
+ // specifiers are not supported."
// It seems sensible to prohibit private_extern too
- if (Lang.OpenCL) {
- switch (S) {
+ // The cl_clang_storage_class_specifiers extension enables support for
+ // these storage-class specifiers.
+ if (S.getLangOptions().OpenCL &&
+ !S.getOpenCLOptions().cl_clang_storage_class_specifiers) {
+ switch (SC) {
case SCS_extern:
case SCS_private_extern:
case SCS_auto:
case SCS_register:
case SCS_static:
DiagID = diag::err_not_opencl_storage_class_specifier;
- PrevSpec = getSpecifierName(S);
+ PrevSpec = getSpecifierName(SC);
return true;
default:
break;
@@ -425,17 +433,30 @@ bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc,
}
if (StorageClassSpec != SCS_unspecified) {
+ // Maybe this is an attempt to use C++0x 'auto' outside of C++0x mode.
+ bool isInvalid = true;
+ if (TypeSpecType == TST_unspecified && S.getLangOptions().CPlusPlus) {
+ if (SC == SCS_auto)
+ return SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID);
+ if (StorageClassSpec == SCS_auto) {
+ isInvalid = SetTypeSpecType(TST_auto, StorageClassSpecLoc,
+ PrevSpec, DiagID);
+ assert(!isInvalid && "auto SCS -> TST recovery failed");
+ }
+ }
+
// Changing storage class is allowed only if the previous one
// was the 'extern' that is part of a linkage specification and
// the new storage class is 'typedef'.
- if (!(SCS_extern_in_linkage_spec &&
+ if (isInvalid &&
+ !(SCS_extern_in_linkage_spec &&
StorageClassSpec == SCS_extern &&
- S == SCS_typedef))
- return BadSpecifier(S, (SCS)StorageClassSpec, PrevSpec, DiagID);
+ SC == SCS_typedef))
+ return BadSpecifier(SC, (SCS)StorageClassSpec, PrevSpec, DiagID);
}
- StorageClassSpec = S;
+ StorageClassSpec = SC;
StorageClassSpecLoc = Loc;
- assert((unsigned)S == StorageClassSpec && "SCS constants overflow bitfield");
+ assert((unsigned)SC == StorageClassSpec && "SCS constants overflow bitfield");
return false;
}
@@ -637,7 +658,7 @@ bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
TypeQualifiers |= T;
switch (T) {
- default: assert(0 && "Unknown type qualifier!");
+ 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;
@@ -682,6 +703,18 @@ bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec,
return false;
}
+bool DeclSpec::setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID) {
+ if (isModulePrivateSpecified()) {
+ PrevSpec = "__module_private__";
+ DiagID = diag::ext_duplicate_declspec;
+ return true;
+ }
+
+ ModulePrivateLoc = Loc;
+ return false;
+}
+
bool DeclSpec::SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID) {
// 'constexpr constexpr' is ok.
@@ -732,7 +765,7 @@ void DeclSpec::SaveStorageSpecifierAsWritten() {
/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or
/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method,
/// DeclSpec is guaranteed self-consistent, even if an error occurred.
-void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) {
+void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
// Before possibly changing their values, save specs as written.
SaveWrittenBuiltinSpecs();
SaveStorageSpecifierAsWritten();
@@ -836,6 +869,27 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) {
}
}
+ // If no type specifier was provided and we're parsing a language where
+ // the type specifier is not optional, but we got 'auto' as a storage
+ // class specifier, then assume this is an attempt to use C++0x's 'auto'
+ // type specifier.
+ // FIXME: Does Microsoft really support implicit int in C++?
+ if (PP.getLangOptions().CPlusPlus && !PP.getLangOptions().MicrosoftExt &&
+ TypeSpecType == TST_unspecified && StorageClassSpec == SCS_auto) {
+ TypeSpecType = TST_auto;
+ StorageClassSpec = StorageClassSpecAsWritten = 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.getLangOptions().CPlusPlus0x && TypeSpecType == TST_auto)
+ Diag(D, TSTLoc, diag::ext_auto_type_specifier);
+ if (PP.getLangOptions().CPlusPlus && !PP.getLangOptions().CPlusPlus0x &&
+ StorageClassSpec == SCS_auto)
+ Diag(D, StorageClassSpecLoc, diag::warn_auto_storage_class)
+ << FixItHint::CreateRemoval(StorageClassSpecLoc);
+
// C++ [class.friend]p6:
// No storage-class-specifier shall appear in the decl-specifier-seq
// of a friend declaration.
@@ -844,7 +898,7 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) {
const char *SpecName = getSpecifierName(SC);
SourceLocation SCLoc = getStorageClassSpecLoc();
- SourceLocation SCEndLoc = SCLoc.getFileLocWithOffset(strlen(SpecName));
+ SourceLocation SCEndLoc = SCLoc.getLocWithOffset(strlen(SpecName));
Diag(D, SCLoc, diag::err_friend_storage_spec)
<< SpecName
@@ -854,7 +908,7 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) {
}
assert(!TypeSpecOwned || isDeclRep((TST) TypeSpecType));
-
+
// Okay, now we can infer the real type.
// TODO: return "auto function" and other bad things based on the real type.
@@ -902,7 +956,7 @@ bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc,
Specifiers |= VS;
switch (VS) {
- default: assert(0 && "Unknown specifier!");
+ default: llvm_unreachable("Unknown specifier!");
case VS_Override: VS_overrideLoc = Loc; break;
case VS_Final: VS_finalLoc = Loc; break;
}
@@ -912,7 +966,7 @@ bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc,
const char *VirtSpecifiers::getSpecifierName(Specifier VS) {
switch (VS) {
- default: assert(0 && "Unknown specifier");
+ default: llvm_unreachable("Unknown specifier");
case VS_Override: return "override";
case VS_Final: return "final";
}
diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp
index c6744ed80d4b..d6c1ad13a854 100644
--- a/lib/Sema/DelayedDiagnostic.cpp
+++ b/lib/Sema/DelayedDiagnostic.cpp
@@ -21,7 +21,7 @@ using namespace sema;
DelayedDiagnostic DelayedDiagnostic::makeDeprecation(SourceLocation Loc,
const NamedDecl *D,
- llvm::StringRef Msg) {
+ StringRef Msg) {
DelayedDiagnostic DD;
DD.Kind = Deprecation;
DD.Triggered = false;
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index 95420a316ad0..a6432670856a 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -73,7 +73,7 @@ void IdentifierResolver::IdDeclInfo::RemoveDecl(NamedDecl *D) {
}
}
- assert(0 && "Didn't find this decl on its identifier's chain!");
+ llvm_unreachable("Didn't find this decl on its identifier's chain!");
}
bool
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index 59bc2637c8f3..3e74dfccbdb1 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -1,4 +1,4 @@
-//===--- JumpDiagnostics.cpp - Analyze Jump Targets for VLA issues --------===//
+//===--- JumpDiagnostics.cpp - Protected scope jump analysis ------*- C++ -*-=//
//
// The LLVM Compiler Infrastructure
//
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This file implements the JumpScopeChecker class, which is used to diagnose
-// jumps that enter a VLA scope in an invalid way.
+// jumps that enter a protected scope in an invalid way.
//
//===----------------------------------------------------------------------===//
@@ -58,12 +58,12 @@ class JumpScopeChecker {
: ParentScope(parentScope), InDiag(InDiag), OutDiag(OutDiag), Loc(L) {}
};
- llvm::SmallVector<GotoScope, 48> Scopes;
+ SmallVector<GotoScope, 48> Scopes;
llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes;
- llvm::SmallVector<Stmt*, 16> Jumps;
+ SmallVector<Stmt*, 16> Jumps;
- llvm::SmallVector<IndirectGotoStmt*, 4> IndirectJumps;
- llvm::SmallVector<LabelDecl*, 4> IndirectJumpTargets;
+ SmallVector<IndirectGotoStmt*, 4> IndirectJumps;
+ SmallVector<LabelDecl*, 4> IndirectJumpTargets;
public:
JumpScopeChecker(Stmt *Body, Sema &S);
private:
@@ -76,8 +76,8 @@ private:
void VerifyIndirectJumps();
void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope,
LabelDecl *Target, unsigned TargetScope);
- void CheckJump(Stmt *From, Stmt *To,
- SourceLocation DiagLoc, unsigned JumpDiag);
+ void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,
+ unsigned JumpDiag, unsigned JumpDiagWarning);
unsigned GetDeepestCommonScope(unsigned A, unsigned B);
};
@@ -476,7 +476,8 @@ void JumpScopeChecker::VerifyJumps() {
// With a goto,
if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) {
CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(),
- diag::err_goto_into_protected_scope);
+ diag::err_goto_into_protected_scope,
+ diag::warn_goto_into_protected_scope);
continue;
}
@@ -484,7 +485,8 @@ void JumpScopeChecker::VerifyJumps() {
if (IndirectGotoStmt *IGS = dyn_cast<IndirectGotoStmt>(Jump)) {
LabelDecl *Target = IGS->getConstantTarget();
CheckJump(IGS, Target->getStmt(), IGS->getGotoLoc(),
- diag::err_goto_into_protected_scope);
+ diag::err_goto_into_protected_scope,
+ diag::warn_goto_into_protected_scope);
continue;
}
@@ -493,7 +495,7 @@ void JumpScopeChecker::VerifyJumps() {
SC = SC->getNextSwitchCase()) {
assert(LabelAndGotoScopes.count(SC) && "Case not visited?");
CheckJump(SS, SC, SC->getLocStart(),
- diag::err_switch_into_protected_scope);
+ diag::err_switch_into_protected_scope, 0);
}
}
}
@@ -532,10 +534,10 @@ void JumpScopeChecker::VerifyIndirectJumps() {
// indirect goto. For most code bases, this substantially cuts
// down on the number of jump sites we'll have to consider later.
typedef std::pair<unsigned, IndirectGotoStmt*> JumpScope;
- llvm::SmallVector<JumpScope, 32> JumpScopes;
+ SmallVector<JumpScope, 32> JumpScopes;
{
llvm::DenseMap<unsigned, IndirectGotoStmt*> JumpScopesMap;
- for (llvm::SmallVectorImpl<IndirectGotoStmt*>::iterator
+ for (SmallVectorImpl<IndirectGotoStmt*>::iterator
I = IndirectJumps.begin(), E = IndirectJumps.end(); I != E; ++I) {
IndirectGotoStmt *IG = *I;
assert(LabelAndGotoScopes.count(IG) &&
@@ -554,7 +556,7 @@ void JumpScopeChecker::VerifyIndirectJumps() {
// label whose address was taken somewhere in the function.
// For most code bases, there will be only one such scope.
llvm::DenseMap<unsigned, LabelDecl*> TargetScopes;
- for (llvm::SmallVectorImpl<LabelDecl*>::iterator
+ for (SmallVectorImpl<LabelDecl*>::iterator
I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end();
I != E; ++I) {
LabelDecl *TheLabel = *I;
@@ -599,7 +601,7 @@ void JumpScopeChecker::VerifyIndirectJumps() {
// Walk through all the jump sites, checking that they can trivially
// reach this label scope.
- for (llvm::SmallVectorImpl<JumpScope>::iterator
+ for (SmallVectorImpl<JumpScope>::iterator
I = JumpScopes.begin(), E = JumpScopes.end(); I != E; ++I) {
unsigned Scope = I->first;
@@ -660,10 +662,20 @@ void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
S.Diag(Scopes[I].Loc, Scopes[I].InDiag);
}
+/// Return true if a particular error+note combination must be downgraded
+/// to a warning in Microsoft mode.
+static bool IsMicrosoftJumpWarning(unsigned JumpDiag, unsigned InDiagNote)
+{
+ return (JumpDiag == diag::err_goto_into_protected_scope &&
+ (InDiagNote == diag::note_protected_by_variable_init ||
+ InDiagNote == diag::note_protected_by_variable_nontriv_destructor));
+}
+
+
/// CheckJump - Validate that the specified jump statement is valid: that it is
/// jumping within or out of its current scope, not into a deeper one.
-void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To,
- SourceLocation DiagLoc, unsigned JumpDiag) {
+void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,
+ unsigned JumpDiagError, unsigned JumpDiagWarning) {
assert(LabelAndGotoScopes.count(From) && "Jump didn't get added to scopes?");
unsigned FromScope = LabelAndGotoScopes[From];
@@ -679,19 +691,30 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To,
if (CommonScope == ToScope) return;
// Pull out (and reverse) any scopes we might need to diagnose skipping.
- llvm::SmallVector<unsigned, 10> ToScopes;
- for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope)
- if (Scopes[I].InDiag)
- ToScopes.push_back(I);
-
- // If the only scopes present are cleanup scopes, we're okay.
- if (ToScopes.empty()) return;
+ SmallVector<unsigned, 10> ToScopesError;
+ SmallVector<unsigned, 10> ToScopesWarning;
+ for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope) {
+ if (S.getLangOptions().MicrosoftMode && JumpDiagWarning != 0 &&
+ IsMicrosoftJumpWarning(JumpDiagError, Scopes[I].InDiag))
+ ToScopesWarning.push_back(I);
+ else if (Scopes[I].InDiag)
+ ToScopesError.push_back(I);
+ }
- S.Diag(DiagLoc, JumpDiag);
+ // Handle warnings.
+ if (!ToScopesWarning.empty()) {
+ S.Diag(DiagLoc, JumpDiagWarning);
+ for (unsigned i = 0, e = ToScopesWarning.size(); i != e; ++i)
+ S.Diag(Scopes[ToScopesWarning[i]].Loc, Scopes[ToScopesWarning[i]].InDiag);
+ }
- // Emit diagnostics for whatever is left in ToScopes.
- for (unsigned i = 0, e = ToScopes.size(); i != e; ++i)
- S.Diag(Scopes[ToScopes[i]].Loc, Scopes[ToScopes[i]].InDiag);
+ // Handle errors.
+ if (!ToScopesError.empty()) {
+ S.Diag(DiagLoc, JumpDiagError);
+ // Emit diagnostics note for whatever is left in ToScopesError.
+ for (unsigned i = 0, e = ToScopesError.size(); i != e; ++i)
+ S.Diag(Scopes[ToScopesError[i]].Loc, Scopes[ToScopesError[i]].InDiag);
+ }
}
void Sema::DiagnoseInvalidJumps(Stmt *Body) {
diff --git a/lib/Sema/MultiInitializer.cpp b/lib/Sema/MultiInitializer.cpp
new file mode 100644
index 000000000000..8bd2213b5705
--- /dev/null
+++ b/lib/Sema/MultiInitializer.cpp
@@ -0,0 +1,92 @@
+//===--- MultiInitializer.cpp - Initializer expression group ----*- 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 MultiInitializer class, which can represent a list
+// initializer or a parentheses-wrapped group of expressions in a C++ member
+// initializer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/MultiInitializer.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Sema.h"
+#include "clang/AST/Expr.h"
+
+using namespace clang;
+
+InitListExpr *MultiInitializer::getInitList() const {
+ return cast<InitListExpr>(InitListOrExpressions.get<Expr*>());
+}
+
+SourceLocation MultiInitializer::getStartLoc() const {
+ return isInitializerList() ? getInitList()->getLBraceLoc() : LParenLoc;
+}
+
+SourceLocation MultiInitializer::getEndLoc() const {
+ return isInitializerList() ? getInitList()->getRBraceLoc() : RParenLoc;
+}
+
+MultiInitializer::iterator MultiInitializer::begin() const {
+ return isInitializerList() ? getInitList()->getInits() : getExpressions();
+}
+
+MultiInitializer::iterator MultiInitializer::end() const {
+ if (isInitializerList()) {
+ InitListExpr *ILE = getInitList();
+ return ILE->getInits() + ILE->getNumInits();
+ }
+ return getExpressions() + NumInitializers;
+}
+
+bool MultiInitializer::isTypeDependent() const {
+ if (isInitializerList())
+ return getInitList()->isTypeDependent();
+ for (iterator I = begin(), E = end(); I != E; ++I) {
+ if ((*I)->isTypeDependent())
+ return true;
+ }
+ return false;
+}
+
+bool MultiInitializer::DiagnoseUnexpandedParameterPack(Sema &SemaRef) const {
+ if (isInitializerList())
+ return SemaRef.DiagnoseUnexpandedParameterPack(getInitList());
+ for (iterator I = begin(), E = end(); I != E; ++I) {
+ if (SemaRef.DiagnoseUnexpandedParameterPack(*I))
+ return true;
+ }
+ return false;
+}
+
+Expr *MultiInitializer::CreateInitExpr(ASTContext &Ctx, QualType T) const {
+ if (isInitializerList())
+ return InitListOrExpressions.get<Expr*>();
+
+ return new (Ctx) ParenListExpr(Ctx, LParenLoc, getExpressions(),
+ NumInitializers, RParenLoc, T);
+}
+
+ExprResult MultiInitializer::PerformInit(Sema &SemaRef,
+ InitializedEntity Entity,
+ InitializationKind Kind) const {
+ Expr *Single;
+ Expr **Args;
+ unsigned NumArgs;
+ if (isInitializerList()) {
+ Single = InitListOrExpressions.get<Expr*>();
+ Args = &Single;
+ NumArgs = 1;
+ } else {
+ Args = getExpressions();
+ NumArgs = NumInitializers;
+ }
+ InitializationSequence InitSeq(SemaRef, Entity, Kind, Args, NumArgs);
+ return InitSeq.Perform(SemaRef, Entity, Kind,
+ MultiExprArg(SemaRef, Args, NumArgs), 0);
+}
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index fdf3bb3cb012..533b21cb43e9 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -34,6 +34,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
using namespace clang;
@@ -54,99 +55,54 @@ void FunctionScopeInfo::Clear() {
BlockScopeInfo::~BlockScopeInfo() { }
+PrintingPolicy Sema::getPrintingPolicy() const {
+ PrintingPolicy Policy = Context.getPrintingPolicy();
+ Policy.Bool = getLangOptions().Bool;
+ if (!Policy.Bool) {
+ if (MacroInfo *BoolMacro = PP.getMacroInfo(&Context.Idents.get("bool"))) {
+ Policy.Bool = BoolMacro->isObjectLike() &&
+ BoolMacro->getNumTokens() == 1 &&
+ BoolMacro->getReplacementToken(0).is(tok::kw__Bool);
+ }
+ }
+
+ return Policy;
+}
+
void Sema::ActOnTranslationUnitScope(Scope *S) {
TUScope = S;
PushDeclContext(S, Context.getTranslationUnitDecl());
VAListTagName = PP.getIdentifierInfo("__va_list_tag");
- if (!Context.isInt128Installed() && // May be set by ASTReader.
- PP.getTargetInfo().getPointerWidth(0) >= 64) {
- TypeSourceInfo *TInfo;
-
- // Install [u]int128_t for 64-bit targets.
- TInfo = Context.getTrivialTypeSourceInfo(Context.Int128Ty);
- PushOnScopeChains(TypedefDecl::Create(Context, CurContext,
- SourceLocation(),
- SourceLocation(),
- &Context.Idents.get("__int128_t"),
- TInfo), TUScope);
-
- TInfo = Context.getTrivialTypeSourceInfo(Context.UnsignedInt128Ty);
- PushOnScopeChains(TypedefDecl::Create(Context, CurContext,
- SourceLocation(),
- SourceLocation(),
- &Context.Idents.get("__uint128_t"),
- TInfo), TUScope);
- Context.setInt128Installed();
- }
-
-
- if (!PP.getLangOptions().ObjC1) return;
-
- // Built-in ObjC types may already be set by ASTReader (hence isNull checks).
- if (Context.getObjCSelType().isNull()) {
- // Create the built-in typedef for 'SEL'.
- QualType SelT = Context.getPointerType(Context.ObjCBuiltinSelTy);
- TypeSourceInfo *SelInfo = Context.getTrivialTypeSourceInfo(SelT);
- TypedefDecl *SelTypedef
- = TypedefDecl::Create(Context, CurContext,
- SourceLocation(), SourceLocation(),
- &Context.Idents.get("SEL"), SelInfo);
- PushOnScopeChains(SelTypedef, TUScope);
- Context.setObjCSelType(Context.getTypeDeclType(SelTypedef));
- Context.ObjCSelRedefinitionType = Context.getObjCSelType();
- }
-
- // Synthesize "@class Protocol;
- if (Context.getObjCProtoType().isNull()) {
- ObjCInterfaceDecl *ProtocolDecl =
- ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(),
- &Context.Idents.get("Protocol"),
- SourceLocation(), true);
- Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl));
- PushOnScopeChains(ProtocolDecl, TUScope, false);
- }
- // Create the built-in typedef for 'id'.
- if (Context.getObjCIdType().isNull()) {
- QualType T = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, 0, 0);
- T = Context.getObjCObjectPointerType(T);
- TypeSourceInfo *IdInfo = Context.getTrivialTypeSourceInfo(T);
- TypedefDecl *IdTypedef
- = TypedefDecl::Create(Context, CurContext,
- SourceLocation(), SourceLocation(),
- &Context.Idents.get("id"), IdInfo);
- PushOnScopeChains(IdTypedef, TUScope);
- Context.setObjCIdType(Context.getTypeDeclType(IdTypedef));
- Context.ObjCIdRedefinitionType = Context.getObjCIdType();
- }
- // Create the built-in typedef for 'Class'.
- if (Context.getObjCClassType().isNull()) {
- QualType T = Context.getObjCObjectType(Context.ObjCBuiltinClassTy, 0, 0);
- T = Context.getObjCObjectPointerType(T);
- TypeSourceInfo *ClassInfo = Context.getTrivialTypeSourceInfo(T);
- TypedefDecl *ClassTypedef
- = TypedefDecl::Create(Context, CurContext,
- SourceLocation(), SourceLocation(),
- &Context.Idents.get("Class"), ClassInfo);
- PushOnScopeChains(ClassTypedef, TUScope);
- Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef));
- Context.ObjCClassRedefinitionType = Context.getObjCClassType();
- }
+ if (PP.getLangOptions().ObjC1) {
+ // Synthesize "@class Protocol;
+ if (Context.getObjCProtoType().isNull()) {
+ ObjCInterfaceDecl *ProtocolDecl =
+ ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(),
+ &Context.Idents.get("Protocol"),
+ SourceLocation(), true);
+ Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl));
+ PushOnScopeChains(ProtocolDecl, TUScope, false);
+ }
+ }
}
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
- bool CompleteTranslationUnit,
+ TranslationUnitKind TUKind,
CodeCompleteConsumer *CodeCompleter)
: TheTargetAttributesSema(0), FPFeatures(pp.getLangOptions()),
LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
CollectStats(false), ExternalSource(0), CodeCompleter(CodeCompleter),
- CurContext(0), PackContext(0), MSStructPragmaOn(false), VisContext(0),
+ CurContext(0), OriginalLexicalContext(0),
+ PackContext(0), MSStructPragmaOn(false), VisContext(0),
ExprNeedsCleanups(0), LateTemplateParser(0), OpaqueParser(0),
IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
GlobalNewDeleteDeclared(false),
- CompleteTranslationUnit(CompleteTranslationUnit),
+ ObjCShouldCallSuperDealloc(false),
+ ObjCShouldCallSuperFinalize(false),
+ TUKind(TUKind),
NumSFINAEErrors(0), SuppressAccessChecking(false),
AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
@@ -181,6 +137,40 @@ void Sema::Initialize() {
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 either of the 128-bit integer types are unavailable to name lookup,
+ // define them now.
+ DeclarationName Int128 = &Context.Idents.get("__int128_t");
+ if (IdentifierResolver::begin(Int128) == IdentifierResolver::end())
+ PushOnScopeChains(Context.getInt128Decl(), TUScope);
+
+ DeclarationName UInt128 = &Context.Idents.get("__uint128_t");
+ if (IdentifierResolver::begin(UInt128) == IdentifierResolver::end())
+ PushOnScopeChains(Context.getUInt128Decl(), TUScope);
+ }
+
+
+ // Initialize predefined Objective-C types:
+ if (PP.getLangOptions().ObjC1) {
+ // If 'SEL' does not yet refer to any declarations, make it refer to the
+ // predefined 'SEL'.
+ DeclarationName SEL = &Context.Idents.get("SEL");
+ if (IdentifierResolver::begin(SEL) == IdentifierResolver::end())
+ PushOnScopeChains(Context.getObjCSelDecl(), TUScope);
+
+ // If 'id' does not yet refer to any declarations, make it refer to the
+ // predefined 'id'.
+ DeclarationName Id = &Context.Idents.get("id");
+ if (IdentifierResolver::begin(Id) == IdentifierResolver::end())
+ PushOnScopeChains(Context.getObjCIdDecl(), TUScope);
+
+ // Create the built-in typedef for 'Class'.
+ DeclarationName Class = &Context.Idents.get("Class");
+ if (IdentifierResolver::begin(Class) == IdentifierResolver::end())
+ PushOnScopeChains(Context.getObjCClassDecl(), TUScope);
+ }
}
Sema::~Sema() {
@@ -210,7 +200,7 @@ Sema::~Sema() {
/// make the relevant declaration unavailable instead of erroring, do
/// so and return true.
bool Sema::makeUnavailableInSystemHeader(SourceLocation loc,
- llvm::StringRef msg) {
+ StringRef msg) {
// If we're not in a function, it's an error.
FunctionDecl *fn = dyn_cast<FunctionDecl>(CurContext);
if (!fn) return false;
@@ -287,7 +277,9 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
CastKind Sema::ScalarTypeToBooleanCastKind(QualType ScalarTy) {
switch (ScalarTy->getScalarTypeKind()) {
case Type::STK_Bool: return CK_NoOp;
- case Type::STK_Pointer: return CK_PointerToBoolean;
+ case Type::STK_CPointer: return CK_PointerToBoolean;
+ case Type::STK_BlockPointer: return CK_PointerToBoolean;
+ case Type::STK_ObjCObjectPointer: return CK_PointerToBoolean;
case Type::STK_MemberPointer: return CK_MemberPointerToBoolean;
case Type::STK_Integral: return CK_IntegralToBoolean;
case Type::STK_Floating: return CK_FloatingToBoolean;
@@ -297,12 +289,6 @@ CastKind Sema::ScalarTypeToBooleanCastKind(QualType ScalarTy) {
return CK_Invalid;
}
-ExprValueKind Sema::CastCategory(Expr *E) {
- Expr::Classification Classification = E->Classify(Context);
- return Classification.isRValue() ? VK_RValue :
- (Classification.isLValue() ? VK_LValue : VK_XValue);
-}
-
/// \brief Used to prune the decls of Sema's UnusedFileScopedDecls vector.
static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
if (D->isUsed())
@@ -358,7 +344,7 @@ static void checkUndefinedInternals(Sema &S) {
if (S.UndefinedInternals.empty()) return;
// Collect all the still-undefined entities with internal linkage.
- llvm::SmallVector<UndefinedInternal, 16> undefined;
+ SmallVector<UndefinedInternal, 16> undefined;
for (llvm::DenseMap<NamedDecl*,SourceLocation>::iterator
i = S.UndefinedInternals.begin(), e = S.UndefinedInternals.end();
i != e; ++i) {
@@ -389,7 +375,7 @@ static void checkUndefinedInternals(Sema &S) {
// the iteration order through an llvm::DenseMap.
llvm::array_pod_sort(undefined.begin(), undefined.end());
- for (llvm::SmallVectorImpl<UndefinedInternal>::iterator
+ 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)
@@ -398,24 +384,41 @@ static void checkUndefinedInternals(Sema &S) {
}
}
+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) {
+ llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator Pos
+ = WeakUndeclaredIdentifiers.find(WeakIDs[I].first);
+ if (Pos != WeakUndeclaredIdentifiers.end())
+ continue;
+
+ WeakUndeclaredIdentifiers.insert(WeakIDs[I]);
+ }
+}
+
/// ActOnEndOfTranslationUnit - This is called at the very end of the
/// translation unit when EOF is reached and all but the top-level scope is
/// popped.
void Sema::ActOnEndOfTranslationUnit() {
- // At PCH writing, implicit instantiations and VTable handling info are
- // stored and performed when the PCH is included.
- if (CompleteTranslationUnit) {
+ // Only complete translation units define vtables and perform implicit
+ // instantiations.
+ if (TUKind == TU_Complete) {
// If any dynamic classes have their key function defined within
// this translation unit, then those vtables are considered "used" and must
// be emitted.
- for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) {
- assert(!DynamicClasses[I]->isDependentType() &&
+ for (DynamicClassesType::iterator I = DynamicClasses.begin(ExternalSource),
+ E = DynamicClasses.end();
+ I != E; ++I) {
+ assert(!(*I)->isDependentType() &&
"Should not see dependent types here!");
- if (const CXXMethodDecl *KeyFunction
- = Context.getKeyFunction(DynamicClasses[I])) {
+ if (const CXXMethodDecl *KeyFunction = Context.getKeyFunction(*I)) {
const FunctionDecl *Definition = 0;
if (KeyFunction->hasBody(Definition))
- MarkVTableUsed(Definition->getLocation(), DynamicClasses[I], true);
+ MarkVTableUsed(Definition->getLocation(), *I, true);
}
}
@@ -438,13 +441,15 @@ void Sema::ActOnEndOfTranslationUnit() {
}
// Remove file scoped decls that turned out to be used.
- UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(),
+ UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(0,
+ true),
UnusedFileScopedDecls.end(),
std::bind1st(std::ptr_fun(ShouldRemoveFromUnused),
this)),
UnusedFileScopedDecls.end());
- if (!CompleteTranslationUnit) {
+ if (TUKind == TU_Prefix) {
+ // Translation unit prefixes don't need any of the checking below.
TUScope = 0;
return;
}
@@ -452,6 +457,7 @@ void Sema::ActOnEndOfTranslationUnit() {
// Check for #pragma weak identifiers that were never declared
// FIXME: This will cause diagnostics to be emitted in a non-determinstic
// order! Iterating over a densemap like this is bad.
+ LoadExternalWeakUndeclaredIdentifiers();
for (llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator
I = WeakUndeclaredIdentifiers.begin(),
E = WeakUndeclaredIdentifiers.end(); I != E; ++I) {
@@ -461,6 +467,40 @@ void Sema::ActOnEndOfTranslationUnit() {
<< I->first;
}
+ if (TUKind == TU_Module) {
+ // Mark any macros from system headers (in /usr/include) as exported, along
+ // with our own Clang headers.
+ // FIXME: This is a gross hack to deal with the fact that system headers
+ // are #include'd in many places within module headers, but are not
+ // themselves modularized. This doesn't actually work, but it lets us
+ // focus on other issues for the moment.
+ for (Preprocessor::macro_iterator M = PP.macro_begin(false),
+ MEnd = PP.macro_end(false);
+ M != MEnd; ++M) {
+ if (M->second &&
+ !M->second->isExported() &&
+ !M->second->isBuiltinMacro()) {
+ SourceLocation Loc = M->second->getDefinitionLoc();
+ if (SourceMgr.isInSystemHeader(Loc)) {
+ const FileEntry *File
+ = SourceMgr.getFileEntryForID(SourceMgr.getFileID(Loc));
+ if (File &&
+ ((StringRef(File->getName()).find("lib/clang")
+ != StringRef::npos) ||
+ (StringRef(File->getName()).find("usr/include")
+ != StringRef::npos) ||
+ (StringRef(File->getName()).find("usr/local/include")
+ != StringRef::npos)))
+ M->second->setExportLocation(Loc);
+ }
+ }
+ }
+
+ // 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
@@ -473,8 +513,12 @@ 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 (unsigned i = 0, e = TentativeDefinitions.size(); i != e; ++i) {
- VarDecl *VD = TentativeDefinitions[i]->getActingDefinition();
+ for (TentativeDefinitionsType::iterator
+ T = TentativeDefinitions.begin(ExternalSource),
+ TEnd = TentativeDefinitions.end();
+ T != TEnd; ++T)
+ {
+ VarDecl *VD = (*T)->getActingDefinition();
// If the tentative definition was completed, getActingDefinition() returns
// null. If we've already seen this variable before, insert()'s second
@@ -510,16 +554,19 @@ void Sema::ActOnEndOfTranslationUnit() {
if (LangOpts.CPlusPlus0x &&
Diags.getDiagnosticLevel(diag::warn_delegating_ctor_cycle,
SourceLocation())
- != Diagnostic::Ignored)
+ != DiagnosticsEngine::Ignored)
CheckDelegatingCtorCycles();
// If there were errors, disable 'unused' warnings since they will mostly be
// noise.
if (!Diags.hasErrorOccurred()) {
// Output warning for unused file scoped decls.
- for (llvm::SmallVectorImpl<const DeclaratorDecl*>::iterator
- I = UnusedFileScopedDecls.begin(),
+ for (UnusedFileScopedDeclsType::iterator
+ I = UnusedFileScopedDecls.begin(ExternalSource),
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))
@@ -631,7 +678,7 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() {
// Make a copy of this suppressed diagnostic and store it with the
// template-deduction information;
FlushCounts();
- DiagnosticInfo DiagInfo(&SemaRef.Diags);
+ Diagnostic DiagInfo(&SemaRef.Diags);
if (*Info)
(*Info)->addSuppressedDiagnostic(DiagInfo.getLocation(),
@@ -646,6 +693,9 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() {
}
}
+ // Set up the context's printing policy based on our current state.
+ SemaRef.Context.setPrintingPolicy(SemaRef.getPrintingPolicy());
+
// Emit the diagnostic.
if (!this->Emit())
return;
@@ -677,20 +727,20 @@ Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) {
return Builder;
}
-/// \brief Looks through the macro-instantiation chain for the given
-/// location, looking for a macro instantiation with the given name.
+/// \brief Looks through the macro-expansion chain for the given
+/// location, looking for a macro expansion with the given name.
/// If one is found, returns true and sets the location to that
-/// instantiation loc.
-bool Sema::findMacroSpelling(SourceLocation &locref, llvm::StringRef name) {
+/// expansion loc.
+bool Sema::findMacroSpelling(SourceLocation &locref, StringRef name) {
SourceLocation loc = locref;
if (!loc.isMacroID()) return false;
// There's no good way right now to look at the intermediate
- // instantiations, so just jump to the instantiation location.
- loc = getSourceManager().getInstantiationLoc(loc);
+ // expansions, so just jump to the expansion location.
+ loc = getSourceManager().getExpansionLoc(loc);
// If that's written with the name, stop here.
- llvm::SmallVector<char, 16> buffer;
+ SmallVector<char, 16> buffer;
if (getPreprocessor().getSpelling(loc, buffer) == name) {
locref = loc;
return true;
@@ -754,7 +804,7 @@ void Sema::PopFunctionOrBlockScope(const AnalysisBasedWarnings::Policy *WP,
if (WP && D)
AnalysisWarnings.IssueWarnings(*WP, Scope, D, blkExpr);
else {
- for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
+ for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
i = Scope->PossiblyUnreachableDiags.begin(),
e = Scope->PossiblyUnreachableDiags.end();
i != e; ++i) {
@@ -790,10 +840,10 @@ ExternalSemaSource::ReadMethodPool(Selector Sel) {
}
void ExternalSemaSource::ReadKnownNamespaces(
- llvm::SmallVectorImpl<NamespaceDecl *> &Namespaces) {
+ SmallVectorImpl<NamespaceDecl *> &Namespaces) {
}
-void PrettyDeclStackTraceEntry::print(llvm::raw_ostream &OS) const {
+void PrettyDeclStackTraceEntry::print(raw_ostream &OS) const {
SourceLocation Loc = this->Loc;
if (!Loc.isValid() && TheDecl) Loc = TheDecl->getLocation();
if (Loc.isValid()) {
@@ -820,27 +870,38 @@ void PrettyDeclStackTraceEntry::print(llvm::raw_ostream &OS) const {
/// \param ZeroArgCallReturnTy - If the expression can be turned into a call
/// with no arguments, this parameter is set to the type returned by such a
/// call; otherwise, it is set to an empty QualType.
-/// \param NonTemplateOverloads - If the expression is an overloaded function
+/// \param OverloadSet - If the expression is an overloaded function
/// name, this parameter is populated with the decls of the various overloads.
bool Sema::isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy,
- UnresolvedSetImpl &NonTemplateOverloads) {
+ UnresolvedSetImpl &OverloadSet) {
ZeroArgCallReturnTy = QualType();
- NonTemplateOverloads.clear();
- if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(&E)) {
+ OverloadSet.clear();
+
+ if (E.getType() == Context.OverloadTy) {
+ OverloadExpr::FindResult FR = OverloadExpr::find(const_cast<Expr*>(&E));
+ const OverloadExpr *Overloads = FR.Expression;
+
for (OverloadExpr::decls_iterator it = Overloads->decls_begin(),
DeclsEnd = Overloads->decls_end(); it != DeclsEnd; ++it) {
- // Our overload set may include TemplateDecls, which we'll ignore for our
- // present purpose.
- if (const FunctionDecl *OverloadDecl = dyn_cast<FunctionDecl>(*it)) {
- NonTemplateOverloads.addDecl(*it);
+ OverloadSet.addDecl(*it);
+
+ // Check whether the function is a non-template which takes no
+ // arguments.
+ if (const FunctionDecl *OverloadDecl
+ = dyn_cast<FunctionDecl>((*it)->getUnderlyingDecl())) {
if (OverloadDecl->getMinRequiredArguments() == 0)
ZeroArgCallReturnTy = OverloadDecl->getResultType();
}
}
+
+ // Ignore overloads that are pointer-to-member constants.
+ if (FR.HasFormOfMemberPointer)
+ return false;
+
return true;
}
- if (const DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(&E)) {
+ if (const DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E.IgnoreParens())) {
if (const FunctionDecl *Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) {
if (Fun->getMinRequiredArguments() == 0)
ZeroArgCallReturnTy = Fun->getResultType();
@@ -887,8 +948,8 @@ bool Sema::isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy,
/// -fshow-overloads=best, this is the location to attach to the note about too
/// many candidates. Typically this will be the location of the original
/// ill-formed expression.
-void Sema::NoteOverloads(const UnresolvedSetImpl &Overloads,
- const SourceLocation FinalNoteLoc) {
+static void noteOverloads(Sema &S, const UnresolvedSetImpl &Overloads,
+ const SourceLocation FinalNoteLoc) {
int ShownOverloads = 0;
int SuppressedOverloads = 0;
for (UnresolvedSetImpl::iterator It = Overloads.begin(),
@@ -896,15 +957,86 @@ void Sema::NoteOverloads(const UnresolvedSetImpl &Overloads,
// FIXME: Magic number for max shown overloads stolen from
// OverloadCandidateSet::NoteCandidates.
if (ShownOverloads >= 4 &&
- Diags.getShowOverloads() == Diagnostic::Ovl_Best) {
+ S.Diags.getShowOverloads() == DiagnosticsEngine::Ovl_Best) {
++SuppressedOverloads;
continue;
}
- Diag(cast<FunctionDecl>(*It)->getSourceRange().getBegin(),
- diag::note_member_ref_possible_intended_overload);
+
+ NamedDecl *Fn = (*It)->getUnderlyingDecl();
+ S.Diag(Fn->getLocStart(), diag::note_possible_target_of_call);
++ShownOverloads;
}
+
if (SuppressedOverloads)
- Diag(FinalNoteLoc, diag::note_ovl_too_many_candidates)
- << SuppressedOverloads;
+ S.Diag(FinalNoteLoc, diag::note_ovl_too_many_candidates)
+ << SuppressedOverloads;
+}
+
+static void notePlausibleOverloads(Sema &S, SourceLocation Loc,
+ const UnresolvedSetImpl &Overloads,
+ bool (*IsPlausibleResult)(QualType)) {
+ if (!IsPlausibleResult)
+ return noteOverloads(S, Overloads, Loc);
+
+ UnresolvedSet<2> PlausibleOverloads;
+ for (OverloadExpr::decls_iterator It = Overloads.begin(),
+ DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
+ const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It);
+ QualType OverloadResultTy = OverloadDecl->getResultType();
+ if (IsPlausibleResult(OverloadResultTy))
+ PlausibleOverloads.addDecl(It.getDecl());
+ }
+ noteOverloads(S, PlausibleOverloads, Loc);
+}
+
+/// Determine whether the given expression can be called by just
+/// putting parentheses after it. Notably, expressions with unary
+/// operators can't be because the unary operator will start parsing
+/// outside the call.
+static bool IsCallableWithAppend(Expr *E) {
+ E = E->IgnoreImplicit();
+ return (!isa<CStyleCastExpr>(E) &&
+ !isa<UnaryOperator>(E) &&
+ !isa<BinaryOperator>(E) &&
+ !isa<CXXOperatorCallExpr>(E));
+}
+
+bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD,
+ bool ForceComplain,
+ bool (*IsPlausibleResult)(QualType)) {
+ SourceLocation Loc = E.get()->getExprLoc();
+ SourceRange Range = E.get()->getSourceRange();
+
+ QualType ZeroArgCallTy;
+ UnresolvedSet<4> Overloads;
+ if (isExprCallable(*E.get(), ZeroArgCallTy, Overloads) &&
+ !ZeroArgCallTy.isNull() &&
+ (!IsPlausibleResult || IsPlausibleResult(ZeroArgCallTy))) {
+ // At this point, we know E is potentially callable with 0
+ // arguments and that it returns something of a reasonable type,
+ // so we can emit a fixit and carry on pretending that E was
+ // actually a CallExpr.
+ SourceLocation ParenInsertionLoc =
+ PP.getLocForEndOfToken(Range.getEnd());
+ Diag(Loc, PD)
+ << /*zero-arg*/ 1 << Range
+ << (IsCallableWithAppend(E.get())
+ ? FixItHint::CreateInsertion(ParenInsertionLoc, "()")
+ : FixItHint());
+ notePlausibleOverloads(*this, Loc, Overloads, IsPlausibleResult);
+
+ // FIXME: Try this before emitting the fixit, and suppress diagnostics
+ // while doing so.
+ E = ActOnCallExpr(0, E.take(), ParenInsertionLoc,
+ MultiExprArg(*this, 0, 0),
+ ParenInsertionLoc.getLocWithOffset(1));
+ return true;
+ }
+
+ if (!ForceComplain) return false;
+
+ Diag(Loc, PD) << /*not zero-arg*/ 0 << Range;
+ notePlausibleOverloads(*this, Loc, Overloads, IsPlausibleResult);
+ E = ExprError();
+ return true;
}
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index a26737e00e4d..6cd923032685 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -103,7 +103,11 @@ struct EffectiveContext {
} else if (isa<FunctionDecl>(DC)) {
FunctionDecl *Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
Functions.push_back(Function);
- DC = Function->getDeclContext();
+
+ if (Function->getFriendObjectKind())
+ DC = Function->getLexicalDeclContext();
+ else
+ DC = Function->getDeclContext();
} else if (DC->isFileContext()) {
break;
} else {
@@ -126,11 +130,11 @@ struct EffectiveContext {
return Inner;
}
- typedef llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator;
+ typedef SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator;
DeclContext *Inner;
- llvm::SmallVector<FunctionDecl*, 4> Functions;
- llvm::SmallVector<CXXRecordDecl*, 4> Records;
+ SmallVector<FunctionDecl*, 4> Functions;
+ SmallVector<CXXRecordDecl*, 4> Records;
bool Dependent;
};
@@ -146,10 +150,8 @@ struct AccessTarget : public AccessedEntity {
MemberNonce _,
CXXRecordDecl *NamingClass,
DeclAccessPair FoundDecl,
- QualType BaseObjectType,
- bool IsUsingDecl = false)
- : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType),
- IsUsingDeclaration(IsUsingDecl) {
+ QualType BaseObjectType)
+ : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType) {
initialize();
}
@@ -218,7 +220,6 @@ private:
DeclaringClass = DeclaringClass->getCanonicalDecl();
}
- bool IsUsingDeclaration : 1;
bool HasInstanceContext : 1;
mutable bool CalculatedInstanceContext : 1;
mutable const CXXRecordDecl *InstanceContext;
@@ -260,7 +261,7 @@ static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived,
return AR_dependent;
AccessResult OnFailure = AR_inaccessible;
- llvm::SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack
+ SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack
while (true) {
for (CXXRecordDecl::base_class_const_iterator
@@ -421,7 +422,7 @@ static AccessResult MatchesFriend(Sema &S,
// Check whether the friend is the template of a class in the
// context chain.
- for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
+ for (SmallVectorImpl<CXXRecordDecl*>::const_iterator
I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
CXXRecordDecl *Record = *I;
@@ -472,7 +473,7 @@ static AccessResult MatchesFriend(Sema &S,
FunctionDecl *Friend) {
AccessResult OnFailure = AR_inaccessible;
- for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator
+ for (SmallVectorImpl<FunctionDecl*>::const_iterator
I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
if (Friend == *I)
return AR_accessible;
@@ -493,7 +494,7 @@ static AccessResult MatchesFriend(Sema &S,
AccessResult OnFailure = AR_inaccessible;
- for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator
+ for (SmallVectorImpl<FunctionDecl*>::const_iterator
I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate();
@@ -584,7 +585,7 @@ struct ProtectedFriendContext {
bool EverDependent;
/// The path down to the current base class.
- llvm::SmallVector<const CXXRecordDecl*, 20> CurPath;
+ SmallVector<const CXXRecordDecl*, 20> CurPath;
ProtectedFriendContext(Sema &S, const EffectiveContext &EC,
const CXXRecordDecl *InstanceContext,
@@ -1273,7 +1274,7 @@ static AccessResult CheckEffectiveAccess(Sema &S,
AccessTarget &Entity) {
assert(Entity.getAccess() != AS_public && "called for public access!");
- if (S.getLangOptions().Microsoft &&
+ if (S.getLangOptions().MicrosoftMode &&
IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity))
return AR_accessible;
@@ -1554,8 +1555,7 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
Found.getAccess() == AS_public)
return AR_accessible;
- const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>();
- assert(RT && "found member operator but object expr not of record type");
+ const RecordType *RT = ObjectExpr->getType()->castAs<RecordType>();
CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
@@ -1638,13 +1638,34 @@ void Sema::CheckLookupAccess(const LookupResult &R) {
if (I.getAccess() != AS_public) {
AccessTarget Entity(Context, AccessedEntity::Member,
R.getNamingClass(), I.getPair(),
- R.getBaseObjectType(), R.isUsingDeclaration());
+ R.getBaseObjectType());
Entity.setDiag(diag::err_access);
CheckAccess(*this, R.getNameLoc(), Entity);
}
}
}
+/// Checks access to Decl from the given class. The check will take access
+/// specifiers into account, but no member access expressions and such.
+///
+/// \param Decl the declaration to check if it can be accessed
+/// \param Class the class/context from which to start the search
+/// \return true if the Decl is accessible from the Class, false otherwise.
+bool Sema::IsSimplyAccessible(NamedDecl *Decl, CXXRecordDecl *Class) {
+ if (!Class || !Decl->isCXXClassMember())
+ return true;
+
+ QualType qType = Class->getTypeForDecl()->getCanonicalTypeInternal();
+ AccessTarget Entity(Context, AccessedEntity::Member, Class,
+ DeclAccessPair::make(Decl, Decl->getAccess()),
+ qType);
+ if (Entity.getAccess() == AS_public)
+ return true;
+
+ EffectiveContext EC(CurContext);
+ return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible;
+}
+
void Sema::ActOnStartSuppressingAccessChecks() {
assert(!SuppressAccessChecking &&
"Tried to start access check suppression when already started.");
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 53dd297aebb3..77410db01f58 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -189,7 +189,7 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
}
void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
- ExprTy *alignment, SourceLocation PragmaLoc,
+ Expr *alignment, SourceLocation PragmaLoc,
SourceLocation LParenLoc, SourceLocation RParenLoc) {
Expr *Alignment = static_cast<Expr *>(alignment);
@@ -265,7 +265,7 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
break;
default:
- assert(0 && "Invalid #pragma pack kind.");
+ llvm_unreachable("Invalid #pragma pack kind.");
}
}
@@ -300,6 +300,18 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
VD->addAttr(::new (Context) UnusedAttr(IdTok.getLocation(), Context));
}
+void Sema::AddCFAuditedAttribute(Decl *D) {
+ SourceLocation Loc = PP.getPragmaARCCFCodeAuditedLoc();
+ if (!Loc.isValid()) return;
+
+ // Don't add a redundant or conflicting attribute.
+ if (D->hasAttr<CFAuditedTransferAttr>() ||
+ D->hasAttr<CFUnknownTransferAttr>())
+ return;
+
+ D->addAttr(::new (Context) CFAuditedTransferAttr(Loc, Context));
+}
+
typedef std::vector<std::pair<unsigned, SourceLocation> > VisStack;
enum { NoVisibility = (unsigned) -1 };
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 5f8c9c62a409..360a0404b8f4 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -137,8 +137,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
switch (NNS->getKind()) {
case NestedNameSpecifier::Identifier:
- assert(false && "Dependent nested-name-specifier has no DeclContext");
- break;
+ llvm_unreachable("Dependent nested-name-specifier has no DeclContext");
case NestedNameSpecifier::Namespace:
return NNS->getAsNamespace();
@@ -238,7 +237,7 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
// until we see a definition, so awkwardly pull out this special
// case.
if (const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType)) {
- if (!enumType->getDecl()->isDefinition()) {
+ if (!enumType->getDecl()->isCompleteDefinition()) {
Diag(loc, diag::err_incomplete_nested_name_spec)
<< type << SS.getRange();
SS.SetInvalid(SS.getRange());
@@ -615,6 +614,31 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
LookupName(Found, S);
}
+ // In Microsoft mode, if we are within a templated function and we can't
+ // resolve Identifier, then extend the SS with Identifier. This will have
+ // the effect of resolving Identifier during template instantiation.
+ // The goal is to be able to resolve a function call whose
+ // nested-name-specifier is located inside a dependent base class.
+ // Example:
+ //
+ // class C {
+ // public:
+ // static void foo2() { }
+ // };
+ // template <class T> class A { public: typedef C D; };
+ //
+ // template <class T> class B : public A<T> {
+ // public:
+ // void foo() { D::foo2(); }
+ // };
+ if (getLangOptions().MicrosoftExt) {
+ DeclContext *DC = LookupCtx ? LookupCtx : CurContext;
+ if (DC->isDependentContext() && DC->isFunctionOrMethod()) {
+ SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc);
+ return false;
+ }
+ }
+
unsigned DiagID;
if (!Found.empty())
DiagID = diag::err_expected_class_or_namespace;
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCast.cpp
index d053d5a9e9fe..8bd9351e0bd4 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -1,4 +1,4 @@
-//===--- SemaNamedCast.cpp - Semantic Analysis for Named Casts ------------===//
+//===--- SemaCast.cpp - Semantic Analysis for Casts -----------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,13 +7,17 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements semantic analysis for C++ named casts.
+// This file implements semantic analysis for cast expressions, including
+// 1) C-style casts like '(int) x'
+// 2) C++ functional casts like 'int(x)'
+// 3) C++ named casts like 'static_cast<int>(x)'
//
//===----------------------------------------------------------------------===//
#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/Basic/PartialDiagnostic.h"
@@ -39,29 +43,83 @@ enum CastType {
CT_Functional ///< Type(expr)
};
+namespace {
+ struct CastOperation {
+ CastOperation(Sema &S, QualType destType, ExprResult src)
+ : Self(S), SrcExpr(src), DestType(destType),
+ ResultType(destType.getNonLValueExprType(S.Context)),
+ ValueKind(Expr::getValueKindForType(destType)),
+ Kind(CK_Dependent) {
+
+ if (const BuiltinType *placeholder =
+ src.get()->getType()->getAsPlaceholderType()) {
+ PlaceholderKind = placeholder->getKind();
+ } else {
+ PlaceholderKind = (BuiltinType::Kind) 0;
+ }
+ }
+
+ Sema &Self;
+ ExprResult SrcExpr;
+ QualType DestType;
+ QualType ResultType;
+ ExprValueKind ValueKind;
+ CastKind Kind;
+ BuiltinType::Kind PlaceholderKind;
+ CXXCastPath BasePath;
+ SourceRange OpRange;
+ SourceRange DestRange;
+ // Top-level semantics-checking routines.
+ void CheckConstCast();
+ void CheckReinterpretCast();
+ void CheckStaticCast();
+ void CheckDynamicCast();
+ void CheckCXXCStyleCast(bool FunctionalCast);
+ void CheckCStyleCast();
-static void CheckConstCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
- ExprValueKind &VK,
- const SourceRange &OpRange,
- const SourceRange &DestRange);
-static void CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
- ExprValueKind &VK,
- const SourceRange &OpRange,
- const SourceRange &DestRange,
- CastKind &Kind);
-static void CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
- ExprValueKind &VK,
- const SourceRange &OpRange,
- CastKind &Kind,
- CXXCastPath &BasePath);
-static void CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
- ExprValueKind &VK,
- const SourceRange &OpRange,
- const SourceRange &DestRange,
- CastKind &Kind,
- CXXCastPath &BasePath);
+ // Internal convenience methods.
+
+ /// Try to handle the given placeholder expression kind. Return
+ /// true if the source expression has the appropriate placeholder
+ /// kind. A placeholder can only be claimed once.
+ bool claimPlaceholder(BuiltinType::Kind K) {
+ if (PlaceholderKind != K) return false;
+
+ PlaceholderKind = (BuiltinType::Kind) 0;
+ return true;
+ }
+
+ bool isPlaceholder() const {
+ return PlaceholderKind != 0;
+ }
+ bool isPlaceholder(BuiltinType::Kind K) const {
+ return PlaceholderKind == K;
+ }
+
+ void checkCastAlign() {
+ Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange);
+ }
+
+ void checkObjCARCConversion(Sema::CheckedConversionKind CCK) {
+ Expr *src = SrcExpr.get();
+ Self.CheckObjCARCConversion(OpRange, DestType, src, CCK);
+ SrcExpr = src;
+ }
+
+ /// Check for and handle non-overload placeholder expressions.
+ void checkNonOverloadPlaceholders() {
+ if (!isPlaceholder() || isPlaceholder(BuiltinType::Overload))
+ return;
+
+ SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.take());
+ if (SrcExpr.isInvalid())
+ return;
+ PlaceholderKind = (BuiltinType::Kind) 0;
+ }
+ };
+}
static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
bool CheckCVR, bool CheckObjCLifetime);
@@ -162,70 +220,61 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
ExprResult Ex = Owned(E);
QualType DestType = DestTInfo->getType();
- SourceRange OpRange(OpLoc, Parens.getEnd());
- SourceRange DestRange = AngleBrackets;
-
// If the type is dependent, we won't do the semantic analysis now.
// FIXME: should we check this in a more fine-grained manner?
bool TypeDependent = DestType->isDependentType() || Ex.get()->isTypeDependent();
- ExprValueKind VK = VK_RValue;
- if (TypeDependent)
- VK = Expr::getValueKindForType(DestType);
+ CastOperation Op(*this, DestType, E);
+ Op.OpRange = SourceRange(OpLoc, Parens.getEnd());
+ Op.DestRange = AngleBrackets;
switch (Kind) {
default: llvm_unreachable("Unknown C++ cast!");
case tok::kw_const_cast:
if (!TypeDependent) {
- CheckConstCast(*this, Ex, DestType, VK, OpRange, DestRange);
- if (Ex.isInvalid())
+ Op.CheckConstCast();
+ if (Op.SrcExpr.isInvalid())
return ExprError();
}
- return Owned(CXXConstCastExpr::Create(Context,
- DestType.getNonLValueExprType(Context),
- VK, Ex.take(), DestTInfo, OpLoc,
+ return Owned(CXXConstCastExpr::Create(Context, Op.ResultType, Op.ValueKind,
+ Op.SrcExpr.take(), DestTInfo, OpLoc,
Parens.getEnd()));
case tok::kw_dynamic_cast: {
- CastKind Kind = CK_Dependent;
- CXXCastPath BasePath;
if (!TypeDependent) {
- CheckDynamicCast(*this, Ex, DestType, VK, OpRange, DestRange,
- Kind, BasePath);
- if (Ex.isInvalid())
+ Op.CheckDynamicCast();
+ if (Op.SrcExpr.isInvalid())
return ExprError();
}
- return Owned(CXXDynamicCastExpr::Create(Context,
- DestType.getNonLValueExprType(Context),
- VK, Kind, Ex.take(), &BasePath, DestTInfo,
- OpLoc, Parens.getEnd()));
+ return Owned(CXXDynamicCastExpr::Create(Context, Op.ResultType,
+ Op.ValueKind, Op.Kind,
+ Op.SrcExpr.take(), &Op.BasePath,
+ DestTInfo, OpLoc, Parens.getEnd()));
}
case tok::kw_reinterpret_cast: {
- CastKind Kind = CK_Dependent;
if (!TypeDependent) {
- CheckReinterpretCast(*this, Ex, DestType, VK, OpRange, DestRange, Kind);
- if (Ex.isInvalid())
+ Op.CheckReinterpretCast();
+ if (Op.SrcExpr.isInvalid())
return ExprError();
}
- return Owned(CXXReinterpretCastExpr::Create(Context,
- DestType.getNonLValueExprType(Context),
- VK, Kind, Ex.take(), 0,
- DestTInfo, OpLoc, Parens.getEnd()));
+ return Owned(CXXReinterpretCastExpr::Create(Context, Op.ResultType,
+ Op.ValueKind, Op.Kind,
+ Op.SrcExpr.take(), 0,
+ DestTInfo, OpLoc,
+ Parens.getEnd()));
}
case tok::kw_static_cast: {
- CastKind Kind = CK_Dependent;
- CXXCastPath BasePath;
if (!TypeDependent) {
- CheckStaticCast(*this, Ex, DestType, VK, OpRange, Kind, BasePath);
- if (Ex.isInvalid())
+ Op.CheckStaticCast();
+ if (Op.SrcExpr.isInvalid())
return ExprError();
}
- return Owned(CXXStaticCastExpr::Create(Context,
- DestType.getNonLValueExprType(Context),
- VK, Kind, Ex.take(), &BasePath,
- DestTInfo, OpLoc, Parens.getEnd()));
+ return Owned(CXXStaticCastExpr::Create(Context, Op.ResultType, Op.ValueKind,
+ Op.Kind, Op.SrcExpr.take(),
+ &Op.BasePath, DestTInfo, OpLoc,
+ Parens.getEnd()));
}
}
@@ -410,7 +459,7 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
QualType UnwrappedSrcType = Self.Context.getCanonicalType(SrcType),
UnwrappedDestType = Self.Context.getCanonicalType(DestType);
- llvm::SmallVector<Qualifiers, 8> cv1, cv2;
+ SmallVector<Qualifiers, 8> cv1, cv2;
// Find the qualifiers. We only care about cvr-qualifiers for the
// purpose of this check, because other qualifiers (address spaces,
@@ -442,7 +491,7 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
QualType SrcConstruct = Self.Context.VoidTy;
QualType DestConstruct = Self.Context.VoidTy;
ASTContext &Context = Self.Context;
- for (llvm::SmallVector<Qualifiers, 8>::reverse_iterator i1 = cv1.rbegin(),
+ for (SmallVector<Qualifiers, 8>::reverse_iterator i1 = cv1.rbegin(),
i2 = cv2.rbegin();
i1 != cv1.rend(); ++i1, ++i2) {
SrcConstruct
@@ -461,13 +510,9 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
/// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid.
/// Refer to C++ 5.2.7 for details. Dynamic casts are used mostly for runtime-
/// checked downcasts in class hierarchies.
-static void
-CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
- ExprValueKind &VK, const SourceRange &OpRange,
- const SourceRange &DestRange, CastKind &Kind,
- CXXCastPath &BasePath) {
- QualType OrigDestType = DestType, OrigSrcType = SrcExpr.get()->getType();
- DestType = Self.Context.getCanonicalType(DestType);
+void CastOperation::CheckDynamicCast() {
+ QualType OrigSrcType = SrcExpr.get()->getType();
+ QualType DestType = Self.Context.getCanonicalType(this->DestType);
// C++ 5.2.7p1: T shall be a pointer or reference to a complete class type,
// or "pointer to cv void".
@@ -479,12 +524,9 @@ CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
DestPointee = DestPointer->getPointeeType();
} else if ((DestReference = DestType->getAs<ReferenceType>())) {
DestPointee = DestReference->getPointeeType();
- VK = isa<LValueReferenceType>(DestReference) ? VK_LValue
- : isa<RValueReferenceType>(DestReference) ? VK_XValue
- : VK_RValue;
} else {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ref_or_ptr)
- << OrigDestType << DestRange;
+ << this->DestType << DestRange;
return;
}
@@ -519,7 +561,7 @@ CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
} else if (DestReference->isLValueReferenceType()) {
if (!SrcExpr.get()->isLValue()) {
Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue)
- << CT_Dynamic << OrigSrcType << OrigDestType << OpRange;
+ << CT_Dynamic << OrigSrcType << this->DestType << OpRange;
}
SrcPointee = SrcType;
} else {
@@ -547,7 +589,7 @@ CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
// C++ 5.2.7p1: The dynamic_cast operator shall not cast away constness.
if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_qualifiers_away)
- << CT_Dynamic << OrigSrcType << OrigDestType << OpRange;
+ << CT_Dynamic << OrigSrcType << this->DestType << OpRange;
return;
}
@@ -595,11 +637,8 @@ CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
/// like this:
/// const char *str = "literal";
/// legacy_function(const_cast\<char*\>(str));
-void
-CheckConstCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ExprValueKind &VK,
- const SourceRange &OpRange, const SourceRange &DestRange) {
- VK = Expr::getValueKindForType(DestType);
- if (VK == VK_RValue) {
+void CastOperation::CheckConstCast() {
+ if (ValueKind == VK_RValue && !isPlaceholder(BuiltinType::Overload)) {
SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
return;
@@ -617,12 +656,8 @@ CheckConstCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ExprValueKind
/// Refer to C++ 5.2.10 for details. reinterpret_cast is typically used in code
/// like this:
/// char *bytes = reinterpret_cast\<char*\>(int_ptr);
-void
-CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
- ExprValueKind &VK, const SourceRange &OpRange,
- const SourceRange &DestRange, CastKind &Kind) {
- VK = Expr::getValueKindForType(DestType);
- if (VK == VK_RValue) {
+void CastOperation::CheckReinterpretCast() {
+ if (ValueKind == VK_RValue && !isPlaceholder(BuiltinType::Overload)) {
SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
return;
@@ -647,10 +682,7 @@ CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), DestType);
}
} else if (tcr == TC_Success && Self.getLangOptions().ObjCAutoRefCount) {
- Expr *Exp = SrcExpr.get();
- // Note that Exp does not change with CCK_OtherCast cast type
- Self.CheckObjCARCConversion(OpRange, DestType,
- Exp, Sema::CCK_OtherCast);
+ checkObjCARCConversion(Sema::CCK_OtherCast);
}
}
@@ -658,36 +690,34 @@ CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
/// CheckStaticCast - Check that a static_cast\<DestType\>(SrcExpr) is valid.
/// Refer to C++ 5.2.9 for details. Static casts are mostly used for making
/// implicit conversions explicit and getting rid of data loss warnings.
-void
-CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
- ExprValueKind &VK, const SourceRange &OpRange,
- CastKind &Kind, CXXCastPath &BasePath) {
+void CastOperation::CheckStaticCast() {
+ if (isPlaceholder()) {
+ checkNonOverloadPlaceholders();
+ if (SrcExpr.isInvalid())
+ return;
+ }
+
// This test is outside everything else because it's the only case where
// a non-lvalue-reference target type does not lead to decay.
// C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
if (DestType->isVoidType()) {
- SrcExpr = Self.IgnoredValueConversions(SrcExpr.take());
- if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
- return;
- if (SrcExpr.get()->getType() == Self.Context.OverloadTy) {
- ExprResult SingleFunctionExpression =
- Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr.get(),
+ Kind = CK_ToVoid;
+
+ if (claimPlaceholder(BuiltinType::Overload)) {
+ Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr,
false, // Decay Function to ptr
true, // Complain
OpRange, DestType, diag::err_bad_static_cast_overload);
- if (SingleFunctionExpression.isUsable())
- {
- SrcExpr = SingleFunctionExpression;
- Kind = CK_ToVoid;
- }
+ if (SrcExpr.isInvalid())
+ return;
}
- else
- Kind = CK_ToVoid;
+
+ SrcExpr = Self.IgnoredValueConversions(SrcExpr.take());
return;
}
- VK = Expr::getValueKindForType(DestType);
- if (VK == VK_RValue && !DestType->isRecordType()) {
+ if (ValueKind == VK_RValue && !DestType->isRecordType() &&
+ !isPlaceholder(BuiltinType::Overload)) {
SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
return;
@@ -711,16 +741,12 @@ CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
}
} else if (tcr == TC_Success) {
if (Kind == CK_BitCast)
- Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange);
- if (Self.getLangOptions().ObjCAutoRefCount) {
- Expr *Exp = SrcExpr.get();
- // Note that Exp does not change with CCK_OtherCast cast type
- Self.CheckObjCARCConversion(OpRange, DestType,
- Exp, Sema::CCK_OtherCast);
- }
+ checkCastAlign();
+ if (Self.getLangOptions().ObjCAutoRefCount)
+ checkObjCARCConversion(Sema::CCK_OtherCast);
+ } else if (Kind == CK_BitCast) {
+ checkCastAlign();
}
- else if (Kind == CK_BitCast)
- Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange);
}
/// TryStaticCast - Check if a static cast can be performed, and do so if
@@ -815,11 +841,12 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
// The same goes for reverse floating point promotion/conversion and
// floating-integral conversions. Again, only floating->enum is relevant.
if (DestType->isEnumeralType()) {
- if (SrcType->isComplexType() || SrcType->isVectorType()) {
- // Fall through - these cannot be converted.
- } else if (SrcType->isArithmeticType() || SrcType->isEnumeralType()) {
+ if (SrcType->isIntegralOrEnumerationType()) {
Kind = CK_IntegralCast;
return TC_Success;
+ } else if (SrcType->isRealFloatingType()) {
+ Kind = CK_FloatingToIntegral;
+ return TC_Success;
}
}
@@ -870,7 +897,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
else if (DestType->isObjCObjectPointerType()) {
// allow both c-style cast and static_cast of objective-c pointers as
// they are pervasive.
- Kind = CK_AnyPointerToObjCPointerCast;
+ Kind = CK_CPointerToObjCPointerCast;
return TC_Success;
}
else if (CStyle && DestType->isBlockPointerType()) {
@@ -1373,7 +1400,7 @@ void Sema::CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType,
diag::warn_undefined_reinterpret_cast;
if (Diags.getDiagnosticLevel(DiagID, Range.getBegin()) ==
- Diagnostic::Ignored) {
+ DiagnosticsEngine::Ignored) {
return;
}
@@ -1430,17 +1457,19 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
// Is the source an overloaded name? (i.e. &foo)
// If so, reinterpret_cast can not help us here (13.4, p1, bullet 5) ...
if (SrcType == Self.Context.OverloadTy) {
- // ... unless foo<int> resolves to an lvalue unambiguously
- ExprResult SingleFunctionExpr =
- Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr.get(),
+ // ... unless foo<int> resolves to an lvalue unambiguously.
+ // TODO: what if this fails because of DiagnoseUseOfDecl or something
+ // like it?
+ ExprResult SingleFunctionExpr = SrcExpr;
+ if (Self.ResolveAndFixSingleFunctionTemplateSpecialization(
+ SingleFunctionExpr,
Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr
- );
- if (SingleFunctionExpr.isUsable()) {
+ ) && SingleFunctionExpr.isUsable()) {
SrcExpr = move(SingleFunctionExpr);
SrcType = SrcExpr.get()->getType();
- }
- else
+ } else {
return TC_NotApplicable;
+ }
}
if (const ReferenceType *DestTypeTmp = DestType->getAs<ReferenceType>()) {
@@ -1592,7 +1621,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
// integral type size doesn't matter.
if ((Self.Context.getTypeSize(SrcType) >
Self.Context.getTypeSize(DestType)) &&
- !Self.getLangOptions().Microsoft) {
+ !Self.getLangOptions().MicrosoftExt) {
msg = diag::err_bad_reinterpret_cast_small_int;
return TC_Failed;
}
@@ -1629,16 +1658,28 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
(DestType->isBlockPointerType() && SrcType->isObjCObjectPointerType()))
return TC_NotApplicable;
+ if (IsLValueCast) {
+ Kind = CK_LValueBitCast;
+ } else if (DestType->isObjCObjectPointerType()) {
+ Kind = Self.PrepareCastToObjCObjectPointer(SrcExpr);
+ } else if (DestType->isBlockPointerType()) {
+ if (!SrcType->isBlockPointerType()) {
+ Kind = CK_AnyPointerToBlockPointerCast;
+ } else {
+ Kind = CK_BitCast;
+ }
+ } else {
+ Kind = CK_BitCast;
+ }
+
// Any pointer can be cast to an Objective-C pointer type with a C-style
// cast.
if (CStyle && DestType->isObjCObjectPointerType()) {
- Kind = CK_AnyPointerToObjCPointerCast;
return TC_Success;
}
// Not casting away constness, so the only remaining check is for compatible
// pointer categories.
- Kind = IsLValueCast? CK_LValueBitCast : CK_BitCast;
if (SrcType->isFunctionPointerType()) {
if (DestType->isFunctionPointerType()) {
@@ -1673,65 +1714,64 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
return TC_Success;
}
-ExprResult
-Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
- Expr *CastExpr, CastKind &Kind,
- CXXCastPath &BasePath,
- bool FunctionalStyle) {
+void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle) {
+ // Handle placeholders.
+ if (isPlaceholder()) {
+ // C-style casts can resolve __unknown_any types.
+ if (claimPlaceholder(BuiltinType::UnknownAny)) {
+ SrcExpr = Self.checkUnknownAnyCast(DestRange, DestType,
+ SrcExpr.get(), Kind,
+ ValueKind, BasePath);
+ return;
+ }
+
+ checkNonOverloadPlaceholders();
+ if (SrcExpr.isInvalid())
+ return;
+ }
+
+ // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
// This test is outside everything else because it's the only case where
// a non-lvalue-reference target type does not lead to decay.
- // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
- if (CastTy->isVoidType()) {
+ if (DestType->isVoidType()) {
Kind = CK_ToVoid;
- ExprResult CastExprRes = IgnoredValueConversions(CastExpr);
- if (CastExprRes.isInvalid())
- return ExprError();
- CastExpr = CastExprRes.take();
-
- if (CastExpr->getType() == Context.BoundMemberTy)
- return CheckPlaceholderExpr(CastExpr); // will always fail
-
- if (CastExpr->getType() == Context.OverloadTy) {
- ExprResult SingleFunctionExpr =
- ResolveAndFixSingleFunctionTemplateSpecialization(
- CastExpr, /* Decay Function to ptr */ false,
- /* Complain */ true, R, CastTy,
+ if (claimPlaceholder(BuiltinType::Overload)) {
+ Self.ResolveAndFixSingleFunctionTemplateSpecialization(
+ SrcExpr, /* Decay Function to ptr */ false,
+ /* Complain */ true, DestRange, DestType,
diag::err_bad_cstyle_cast_overload);
- if (SingleFunctionExpr.isInvalid())
- return ExprError();
- CastExpr = SingleFunctionExpr.take();
+ if (SrcExpr.isInvalid())
+ return;
}
- assert(!CastExpr->getType()->isPlaceholderType());
+ SrcExpr = Self.IgnoredValueConversions(SrcExpr.take());
+ if (SrcExpr.isInvalid())
+ return;
- return Owned(CastExpr);
+ return;
}
- // Make sure we determine the value kind before we bail out for
- // dependent types.
- VK = Expr::getValueKindForType(CastTy);
-
// If the type is dependent, we won't do any other semantic analysis now.
- if (CastTy->isDependentType() || CastExpr->isTypeDependent()) {
- Kind = CK_Dependent;
- return Owned(CastExpr);
+ if (DestType->isDependentType() || SrcExpr.get()->isTypeDependent()) {
+ assert(Kind == CK_Dependent);
+ return;
}
- if (VK == VK_RValue && !CastTy->isRecordType()) {
- ExprResult CastExprRes = DefaultFunctionArrayLvalueConversion(CastExpr);
- if (CastExprRes.isInvalid())
- return ExprError();
- CastExpr = CastExprRes.take();
+ if (ValueKind == VK_RValue && !DestType->isRecordType() &&
+ !isPlaceholder(BuiltinType::Overload)) {
+ SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
+ if (SrcExpr.isInvalid())
+ return;
}
// AltiVec vector initialization with a single literal.
- if (const VectorType *vecTy = CastTy->getAs<VectorType>())
+ if (const VectorType *vecTy = DestType->getAs<VectorType>())
if (vecTy->getVectorKind() == VectorType::AltiVecVector
- && (CastExpr->getType()->isIntegerType()
- || CastExpr->getType()->isFloatingType())) {
+ && (SrcExpr.get()->getType()->isIntegerType()
+ || SrcExpr.get()->getType()->isFloatingType())) {
Kind = CK_VectorSplat;
- return Owned(CastExpr);
+ return;
}
// C++ [expr.cast]p5: The conversions performed by
@@ -1746,8 +1786,8 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
// even if a cast resulting from that interpretation is ill-formed.
// In plain language, this means trying a const_cast ...
unsigned msg = diag::err_bad_cxx_cast_generic;
- TryCastResult tcr = TryConstCast(*this, CastExpr, CastTy, /*CStyle*/true,
- msg);
+ TryCastResult tcr = TryConstCast(Self, SrcExpr.get(), DestType,
+ /*CStyle*/true, msg);
if (tcr == TC_Success)
Kind = CK_NoOp;
@@ -1756,47 +1796,274 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
: Sema::CCK_CStyleCast;
if (tcr == TC_NotApplicable) {
// ... or if that is not possible, a static_cast, ignoring const, ...
- ExprResult CastExprRes = Owned(CastExpr);
- tcr = TryStaticCast(*this, CastExprRes, CastTy, CCK, R, msg, Kind,
- BasePath);
- if (CastExprRes.isInvalid())
- return ExprError();
- CastExpr = CastExprRes.take();
+ tcr = TryStaticCast(Self, SrcExpr, DestType, CCK, OpRange,
+ msg, Kind, BasePath);
+ if (SrcExpr.isInvalid())
+ return;
+
if (tcr == TC_NotApplicable) {
// ... and finally a reinterpret_cast, ignoring const.
- CastExprRes = Owned(CastExpr);
- tcr = TryReinterpretCast(*this, CastExprRes, CastTy, /*CStyle*/true, R,
- msg, Kind);
- if (CastExprRes.isInvalid())
- return ExprError();
- CastExpr = CastExprRes.take();
+ tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/true,
+ OpRange, msg, Kind);
+ if (SrcExpr.isInvalid())
+ return;
}
}
- if (getLangOptions().ObjCAutoRefCount && tcr == TC_Success)
- CheckObjCARCConversion(R, CastTy, CastExpr, CCK);
+ if (Self.getLangOptions().ObjCAutoRefCount && tcr == TC_Success)
+ checkObjCARCConversion(CCK);
if (tcr != TC_Success && msg != 0) {
- if (CastExpr->getType() == Context.OverloadTy) {
+ if (SrcExpr.get()->getType() == Self.Context.OverloadTy) {
DeclAccessPair Found;
- FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(CastExpr,
- CastTy,
- /* Complain */ true,
+ FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(SrcExpr.get(),
+ DestType,
+ /*Complain*/ true,
Found);
assert(!Fn && "cast failed but able to resolve overload expression!!");
(void)Fn;
} else {
- diagnoseBadCast(*this, msg, (FunctionalStyle ? CT_Functional : CT_CStyle),
- R, CastExpr, CastTy);
+ diagnoseBadCast(Self, msg, (FunctionalStyle ? CT_Functional : CT_CStyle),
+ OpRange, SrcExpr.get(), DestType);
}
+ } else if (Kind == CK_BitCast) {
+ checkCastAlign();
}
- else if (Kind == CK_BitCast)
- CheckCastAlign(CastExpr, CastTy, R);
+ // Clear out SrcExpr if there was a fatal error.
if (tcr != TC_Success)
+ SrcExpr = ExprError();
+}
+
+/// Check the semantics of a C-style cast operation, in C.
+void CastOperation::CheckCStyleCast() {
+ assert(!Self.getLangOptions().CPlusPlus);
+
+ // Handle placeholders.
+ if (isPlaceholder()) {
+ // C-style casts can resolve __unknown_any types.
+ if (claimPlaceholder(BuiltinType::UnknownAny)) {
+ SrcExpr = Self.checkUnknownAnyCast(DestRange, DestType,
+ SrcExpr.get(), Kind,
+ ValueKind, BasePath);
+ return;
+ }
+
+ // We allow overloads in C, but we don't allow them to be resolved
+ // by anything except calls.
+ SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.take());
+ if (SrcExpr.isInvalid())
+ return;
+ }
+
+ assert(!isPlaceholder());
+
+ // C99 6.5.4p2: the cast type needs to be void or scalar and the expression
+ // type needs to be scalar.
+ if (DestType->isVoidType()) {
+ // We don't necessarily do lvalue-to-rvalue conversions on this.
+ SrcExpr = Self.IgnoredValueConversions(SrcExpr.take());
+ if (SrcExpr.isInvalid())
+ return;
+
+ // Cast to void allows any expr type.
+ Kind = CK_ToVoid;
+ return;
+ }
+
+ SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
+ if (SrcExpr.isInvalid())
+ return;
+ QualType SrcType = SrcExpr.get()->getType();
+
+ if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
+ diag::err_typecheck_cast_to_incomplete)) {
+ SrcExpr = ExprError();
+ return;
+ }
+
+ if (!DestType->isScalarType() && !DestType->isVectorType()) {
+ const RecordType *DestRecordTy = DestType->getAs<RecordType>();
+
+ if (DestRecordTy && Self.Context.hasSameUnqualifiedType(DestType, SrcType)){
+ // GCC struct/union extension: allow cast to self.
+ Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_nonscalar)
+ << DestType << SrcExpr.get()->getSourceRange();
+ Kind = CK_NoOp;
+ return;
+ }
+
+ // GCC's cast to union extension.
+ if (DestRecordTy && DestRecordTy->getDecl()->isUnion()) {
+ RecordDecl *RD = DestRecordTy->getDecl();
+ RecordDecl::field_iterator Field, FieldEnd;
+ for (Field = RD->field_begin(), FieldEnd = RD->field_end();
+ Field != FieldEnd; ++Field) {
+ if (Self.Context.hasSameUnqualifiedType(Field->getType(), SrcType) &&
+ !Field->isUnnamedBitfield()) {
+ Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_to_union)
+ << SrcExpr.get()->getSourceRange();
+ break;
+ }
+ }
+ if (Field == FieldEnd) {
+ Self.Diag(OpRange.getBegin(), diag::err_typecheck_cast_to_union_no_type)
+ << SrcType << SrcExpr.get()->getSourceRange();
+ SrcExpr = ExprError();
+ return;
+ }
+ Kind = CK_ToUnion;
+ return;
+ }
+
+ // Reject any other conversions to non-scalar types.
+ Self.Diag(OpRange.getBegin(), diag::err_typecheck_cond_expect_scalar)
+ << DestType << SrcExpr.get()->getSourceRange();
+ SrcExpr = ExprError();
+ return;
+ }
+
+ // The type we're casting to is known to be a scalar or vector.
+
+ // Require the operand to be a scalar or vector.
+ if (!SrcType->isScalarType() && !SrcType->isVectorType()) {
+ Self.Diag(SrcExpr.get()->getExprLoc(),
+ diag::err_typecheck_expect_scalar_operand)
+ << SrcType << SrcExpr.get()->getSourceRange();
+ SrcExpr = ExprError();
+ return;
+ }
+
+ if (DestType->isExtVectorType()) {
+ SrcExpr = Self.CheckExtVectorCast(OpRange, DestType, SrcExpr.take(), Kind);
+ return;
+ }
+
+ if (const VectorType *DestVecTy = DestType->getAs<VectorType>()) {
+ if (DestVecTy->getVectorKind() == VectorType::AltiVecVector &&
+ (SrcType->isIntegerType() || SrcType->isFloatingType())) {
+ Kind = CK_VectorSplat;
+ } else if (Self.CheckVectorCast(OpRange, DestType, SrcType, Kind)) {
+ SrcExpr = ExprError();
+ }
+ return;
+ }
+
+ if (SrcType->isVectorType()) {
+ if (Self.CheckVectorCast(OpRange, SrcType, DestType, Kind))
+ SrcExpr = ExprError();
+ return;
+ }
+
+ // The source and target types are both scalars, i.e.
+ // - arithmetic types (fundamental, enum, and complex)
+ // - all kinds of pointers
+ // Note that member pointers were filtered out with C++, above.
+
+ if (isa<ObjCSelectorExpr>(SrcExpr.get())) {
+ Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_cast_selector_expr);
+ SrcExpr = ExprError();
+ return;
+ }
+
+ // If either type is a pointer, the other type has to be either an
+ // integer or a pointer.
+ if (!DestType->isArithmeticType()) {
+ if (!SrcType->isIntegralType(Self.Context) && SrcType->isArithmeticType()) {
+ Self.Diag(SrcExpr.get()->getExprLoc(),
+ diag::err_cast_pointer_from_non_pointer_int)
+ << SrcType << SrcExpr.get()->getSourceRange();
+ SrcExpr = ExprError();
+ return;
+ }
+ } else if (!SrcType->isArithmeticType()) {
+ if (!DestType->isIntegralType(Self.Context) &&
+ DestType->isArithmeticType()) {
+ Self.Diag(SrcExpr.get()->getLocStart(),
+ diag::err_cast_pointer_to_non_pointer_int)
+ << SrcType << SrcExpr.get()->getSourceRange();
+ SrcExpr = ExprError();
+ return;
+ }
+ }
+
+ // ARC imposes extra restrictions on casts.
+ if (Self.getLangOptions().ObjCAutoRefCount) {
+ checkObjCARCConversion(Sema::CCK_CStyleCast);
+ if (SrcExpr.isInvalid())
+ return;
+
+ if (const PointerType *CastPtr = DestType->getAs<PointerType>()) {
+ if (const PointerType *ExprPtr = SrcType->getAs<PointerType>()) {
+ Qualifiers CastQuals = CastPtr->getPointeeType().getQualifiers();
+ Qualifiers ExprQuals = ExprPtr->getPointeeType().getQualifiers();
+ if (CastPtr->getPointeeType()->isObjCLifetimeType() &&
+ ExprPtr->getPointeeType()->isObjCLifetimeType() &&
+ !CastQuals.compatiblyIncludesObjCLifetime(ExprQuals)) {
+ Self.Diag(SrcExpr.get()->getLocStart(),
+ diag::err_typecheck_incompatible_ownership)
+ << SrcType << DestType << Sema::AA_Casting
+ << SrcExpr.get()->getSourceRange();
+ return;
+ }
+ }
+ }
+ else if (!Self.CheckObjCARCUnavailableWeakConversion(DestType, SrcType)) {
+ Self.Diag(SrcExpr.get()->getLocStart(),
+ diag::err_arc_convesion_of_weak_unavailable)
+ << 1 << SrcType << DestType << SrcExpr.get()->getSourceRange();
+ SrcExpr = ExprError();
+ return;
+ }
+ }
+
+ Kind = Self.PrepareScalarCast(SrcExpr, DestType);
+ if (SrcExpr.isInvalid())
+ return;
+
+ if (Kind == CK_BitCast)
+ checkCastAlign();
+}
+
+ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc,
+ TypeSourceInfo *CastTypeInfo,
+ SourceLocation RPLoc,
+ Expr *CastExpr) {
+ CastOperation Op(*this, CastTypeInfo->getType(), CastExpr);
+ Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange();
+ Op.OpRange = SourceRange(LPLoc, CastExpr->getLocEnd());
+
+ if (getLangOptions().CPlusPlus) {
+ Op.CheckCXXCStyleCast(/*FunctionalStyle=*/ false);
+ } else {
+ Op.CheckCStyleCast();
+ }
+
+ if (Op.SrcExpr.isInvalid())
+ return ExprError();
+
+ return Owned(CStyleCastExpr::Create(Context, Op.ResultType, Op.ValueKind,
+ Op.Kind, Op.SrcExpr.take(), &Op.BasePath,
+ CastTypeInfo, LPLoc, RPLoc));
+}
+
+ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo,
+ SourceLocation LPLoc,
+ Expr *CastExpr,
+ SourceLocation RPLoc) {
+ CastOperation Op(*this, CastTypeInfo->getType(), CastExpr);
+ Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange();
+ Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getLocEnd());
+
+ Op.CheckCXXCStyleCast(/*FunctionalStyle=*/ true);
+ if (Op.SrcExpr.isInvalid())
return ExprError();
- return Owned(CastExpr);
+ return Owned(CXXFunctionalCastExpr::Create(Context, Op.ResultType,
+ Op.ValueKind, CastTypeInfo,
+ Op.DestRange.getBegin(),
+ Op.Kind, Op.SrcExpr.take(),
+ &Op.BasePath, RPLoc));
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 690a29d281d2..310138354bb9 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -12,8 +12,10 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Sema/Initialization.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Initialization.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Analysis/Analyses/FormatString.h"
#include "clang/AST/ASTContext.h"
@@ -87,6 +89,19 @@ static bool checkArgCount(Sema &S, CallExpr *call, unsigned desiredArgCount) {
<< call->getArg(1)->getSourceRange();
}
+/// CheckBuiltinAnnotationString - Checks that string argument to the builtin
+/// annotation is a non wide string literal.
+static bool CheckBuiltinAnnotationString(Sema &S, Expr *Arg) {
+ Arg = Arg->IgnoreParenCasts();
+ StringLiteral *Literal = dyn_cast<StringLiteral>(Arg);
+ if (!Literal || !Literal->isAscii()) {
+ S.Diag(Arg->getLocStart(), diag::err_builtin_annotation_not_string_constant)
+ << Arg->getSourceRange();
+ return true;
+ }
+ return false;
+}
+
ExprResult
Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
ExprResult TheCallResult(Owned(TheCall));
@@ -183,12 +198,38 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case Builtin::BI__sync_lock_release:
case Builtin::BI__sync_swap:
return SemaBuiltinAtomicOverloaded(move(TheCallResult));
+ case Builtin::BI__atomic_load:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Load);
+ case Builtin::BI__atomic_store:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Store);
+ case Builtin::BI__atomic_exchange:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Xchg);
+ case Builtin::BI__atomic_compare_exchange_strong:
+ return SemaAtomicOpsOverloaded(move(TheCallResult),
+ AtomicExpr::CmpXchgStrong);
+ case Builtin::BI__atomic_compare_exchange_weak:
+ return SemaAtomicOpsOverloaded(move(TheCallResult),
+ AtomicExpr::CmpXchgWeak);
+ case Builtin::BI__atomic_fetch_add:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Add);
+ case Builtin::BI__atomic_fetch_sub:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Sub);
+ case Builtin::BI__atomic_fetch_and:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::And);
+ case Builtin::BI__atomic_fetch_or:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Or);
+ case Builtin::BI__atomic_fetch_xor:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Xor);
+ case Builtin::BI__builtin_annotation:
+ if (CheckBuiltinAnnotationString(*this, TheCall->getArg(1)))
+ return ExprError();
+ break;
}
// Since the target specific builtins for each arch overlap, only check those
// of the arch we are compiling for.
if (BuiltinID >= Builtin::FirstTSBuiltin) {
- switch (Context.Target.getTriple().getArch()) {
+ switch (Context.getTargetInfo().getTriple().getArch()) {
case llvm::Triple::arm:
case llvm::Triple::thumb:
if (CheckARMBuiltinFunctionCall(BuiltinID, TheCall))
@@ -319,7 +360,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
TheCall->getCallee()->getLocStart());
}
- // Memset/memcpy/memmove handling
+ // Builtin handling
int CMF = -1;
switch (FDecl->getBuiltinID()) {
case Builtin::BI__builtin_memset:
@@ -339,7 +380,40 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
case Builtin::BImemmove:
CMF = CMF_Memmove;
break;
+
+ case Builtin::BIstrlcpy:
+ case Builtin::BIstrlcat:
+ CheckStrlcpycatArguments(TheCall, FnInfo);
+ break;
+ case Builtin::BI__builtin_memcmp:
+ CMF = CMF_Memcmp;
+ break;
+
+ case Builtin::BI__builtin_strncpy:
+ case Builtin::BI__builtin___strncpy_chk:
+ case Builtin::BIstrncpy:
+ CMF = CMF_Strncpy;
+ break;
+
+ case Builtin::BI__builtin_strncmp:
+ CMF = CMF_Strncmp;
+ break;
+
+ case Builtin::BI__builtin_strncasecmp:
+ CMF = CMF_Strncasecmp;
+ break;
+
+ case Builtin::BI__builtin_strncat:
+ case Builtin::BIstrncat:
+ CMF = CMF_Strncat;
+ break;
+
+ case Builtin::BI__builtin_strndup:
+ case Builtin::BIstrndup:
+ CMF = CMF_Strndup;
+ break;
+
default:
if (FDecl->getLinkage() == ExternalLinkage &&
(!getLangOptions().CPlusPlus || FDecl->isExternC())) {
@@ -349,12 +423,25 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
CMF = CMF_Memcpy;
else if (FnInfo->isStr("memmove"))
CMF = CMF_Memmove;
+ else if (FnInfo->isStr("memcmp"))
+ CMF = CMF_Memcmp;
+ else if (FnInfo->isStr("strncpy"))
+ CMF = CMF_Strncpy;
+ else if (FnInfo->isStr("strncmp"))
+ CMF = CMF_Strncmp;
+ else if (FnInfo->isStr("strncasecmp"))
+ CMF = CMF_Strncasecmp;
+ else if (FnInfo->isStr("strncat"))
+ CMF = CMF_Strncat;
+ else if (FnInfo->isStr("strndup"))
+ CMF = CMF_Strndup;
}
break;
}
+ // Memset/memcpy/memmove handling
if (CMF != -1)
- CheckMemsetcpymoveArguments(TheCall, CheckedMemoryFunction(CMF), FnInfo);
+ CheckMemaccessArguments(TheCall, CheckedMemoryFunction(CMF), FnInfo);
return false;
}
@@ -384,6 +471,170 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) {
return false;
}
+ExprResult
+Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op) {
+ CallExpr *TheCall = cast<CallExpr>(TheCallResult.get());
+ DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+
+ // All these operations take one of the following four forms:
+ // T __atomic_load(_Atomic(T)*, int) (loads)
+ // T* __atomic_add(_Atomic(T*)*, ptrdiff_t, int) (pointer add/sub)
+ // int __atomic_compare_exchange_strong(_Atomic(T)*, T*, T, int, int)
+ // (cmpxchg)
+ // T __atomic_exchange(_Atomic(T)*, T, int) (everything else)
+ // where T is an appropriate type, and the int paremeterss are for orderings.
+ unsigned NumVals = 1;
+ unsigned NumOrders = 1;
+ if (Op == AtomicExpr::Load) {
+ NumVals = 0;
+ } else if (Op == AtomicExpr::CmpXchgWeak || Op == AtomicExpr::CmpXchgStrong) {
+ NumVals = 2;
+ NumOrders = 2;
+ }
+
+ if (TheCall->getNumArgs() < NumVals+NumOrders+1) {
+ Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
+ << 0 << NumVals+NumOrders+1 << TheCall->getNumArgs()
+ << TheCall->getCallee()->getSourceRange();
+ return ExprError();
+ } else if (TheCall->getNumArgs() > NumVals+NumOrders+1) {
+ Diag(TheCall->getArg(NumVals+NumOrders+1)->getLocStart(),
+ diag::err_typecheck_call_too_many_args)
+ << 0 << NumVals+NumOrders+1 << TheCall->getNumArgs()
+ << TheCall->getCallee()->getSourceRange();
+ return ExprError();
+ }
+
+ // Inspect the first argument of the atomic operation. This should always be
+ // a pointer to an _Atomic type.
+ Expr *Ptr = TheCall->getArg(0);
+ Ptr = DefaultFunctionArrayLvalueConversion(Ptr).get();
+ const PointerType *pointerType = Ptr->getType()->getAs<PointerType>();
+ if (!pointerType) {
+ Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic)
+ << Ptr->getType() << Ptr->getSourceRange();
+ return ExprError();
+ }
+
+ QualType AtomTy = pointerType->getPointeeType();
+ if (!AtomTy->isAtomicType()) {
+ Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic)
+ << Ptr->getType() << Ptr->getSourceRange();
+ return ExprError();
+ }
+ QualType ValType = AtomTy->getAs<AtomicType>()->getValueType();
+
+ if ((Op == AtomicExpr::Add || Op == AtomicExpr::Sub) &&
+ !ValType->isIntegerType() && !ValType->isPointerType()) {
+ Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic_int_or_ptr)
+ << Ptr->getType() << Ptr->getSourceRange();
+ return ExprError();
+ }
+
+ if (!ValType->isIntegerType() &&
+ (Op == AtomicExpr::And || Op == AtomicExpr::Or || Op == AtomicExpr::Xor)){
+ Diag(DRE->getLocStart(), diag::err_atomic_op_logical_needs_atomic_int)
+ << Ptr->getType() << Ptr->getSourceRange();
+ return ExprError();
+ }
+
+ switch (ValType.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ // okay
+ break;
+
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Autoreleasing:
+ Diag(DRE->getLocStart(), diag::err_arc_atomic_ownership)
+ << ValType << Ptr->getSourceRange();
+ return ExprError();
+ }
+
+ QualType ResultType = ValType;
+ if (Op == AtomicExpr::Store)
+ ResultType = Context.VoidTy;
+ else if (Op == AtomicExpr::CmpXchgWeak || Op == AtomicExpr::CmpXchgStrong)
+ ResultType = Context.BoolTy;
+
+ // The first argument --- the pointer --- has a fixed type; we
+ // deduce the types of the rest of the arguments accordingly. Walk
+ // the remaining arguments, converting them to the deduced value type.
+ for (unsigned i = 1; i != NumVals+NumOrders+1; ++i) {
+ ExprResult Arg = TheCall->getArg(i);
+ QualType Ty;
+ if (i < NumVals+1) {
+ // The second argument to a cmpxchg is a pointer to the data which will
+ // be exchanged. The second argument to a pointer add/subtract is the
+ // amount to add/subtract, which must be a ptrdiff_t. The third
+ // argument to a cmpxchg and the second argument in all other cases
+ // is the type of the value.
+ if (i == 1 && (Op == AtomicExpr::CmpXchgWeak ||
+ Op == AtomicExpr::CmpXchgStrong))
+ Ty = Context.getPointerType(ValType.getUnqualifiedType());
+ else if (!ValType->isIntegerType() &&
+ (Op == AtomicExpr::Add || Op == AtomicExpr::Sub))
+ Ty = Context.getPointerDiffType();
+ else
+ Ty = ValType;
+ } else {
+ // The order(s) are always converted to int.
+ Ty = Context.IntTy;
+ }
+ InitializedEntity Entity =
+ InitializedEntity::InitializeParameter(Context, Ty, false);
+ Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg);
+ if (Arg.isInvalid())
+ return true;
+ TheCall->setArg(i, Arg.get());
+ }
+
+ SmallVector<Expr*, 5> SubExprs;
+ SubExprs.push_back(Ptr);
+ if (Op == AtomicExpr::Load) {
+ SubExprs.push_back(TheCall->getArg(1)); // Order
+ } else if (Op != AtomicExpr::CmpXchgWeak && Op != AtomicExpr::CmpXchgStrong) {
+ SubExprs.push_back(TheCall->getArg(2)); // Order
+ SubExprs.push_back(TheCall->getArg(1)); // Val1
+ } else {
+ SubExprs.push_back(TheCall->getArg(3)); // Order
+ SubExprs.push_back(TheCall->getArg(1)); // Val1
+ SubExprs.push_back(TheCall->getArg(2)); // Val2
+ SubExprs.push_back(TheCall->getArg(4)); // OrderFail
+ }
+
+ return Owned(new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(),
+ SubExprs.data(), SubExprs.size(),
+ ResultType, Op,
+ TheCall->getRParenLoc()));
+}
+
+
+/// checkBuiltinArgument - Given a call to a builtin function, perform
+/// normal type-checking on the given argument, updating the call in
+/// place. This is useful when a builtin function requires custom
+/// type-checking for some of its arguments but not necessarily all of
+/// them.
+///
+/// Returns true on error.
+static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) {
+ FunctionDecl *Fn = E->getDirectCallee();
+ assert(Fn && "builtin call without direct callee!");
+
+ ParmVarDecl *Param = Fn->getParamDecl(ArgIndex);
+ InitializedEntity Entity =
+ InitializedEntity::InitializeParameter(S.Context, Param);
+
+ ExprResult Arg = E->getArg(0);
+ Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg);
+ if (Arg.isInvalid())
+ return true;
+
+ E->setArg(ArgIndex, Arg.take());
+ return false;
+}
+
/// SemaBuiltinAtomicOverloaded - We have a call to a function like
/// __sync_fetch_and_add, which is an overloaded function based on the pointer
/// type of its first argument. The main ActOnCallExpr routines have already
@@ -441,6 +692,9 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
return ExprError();
}
+ // Strip any qualifiers off ValType.
+ ValType = ValType.getUnqualifiedType();
+
// The majority of builtins return a value, but a few have special return
// types, so allow them to override appropriately below.
QualType ResultType = ValType;
@@ -494,7 +748,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
unsigned BuiltinID = FDecl->getBuiltinID();
unsigned BuiltinIndex, NumFixed = 1;
switch (BuiltinID) {
- default: assert(0 && "Unknown overloaded atomic builtin!");
+ default: llvm_unreachable("Unknown overloaded atomic builtin!");
case Builtin::BI__sync_fetch_and_add: BuiltinIndex = 0; break;
case Builtin::BI__sync_fetch_and_sub: BuiltinIndex = 1; break;
case Builtin::BI__sync_fetch_and_or: BuiltinIndex = 2; break;
@@ -559,11 +813,10 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// GCC does an implicit conversion to the pointer or integer ValType. This
// can fail in some cases (1i -> int**), check for this error case now.
- CastKind Kind = CK_Invalid;
- ExprValueKind VK = VK_RValue;
- CXXCastPath BasePath;
- Arg = CheckCastTypes(Arg.get()->getLocStart(), Arg.get()->getSourceRange(),
- ValType, Arg.take(), Kind, VK, BasePath);
+ // Initialize the argument.
+ InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
+ ValType, /*consume*/ false);
+ Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg);
if (Arg.isInvalid())
return ExprError();
@@ -573,17 +826,23 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// pass in 42. The 42 gets converted to char. This is even more strange
// for things like 45.123 -> char, etc.
// FIXME: Do this check.
- Arg = ImpCastExprToType(Arg.take(), ValType, Kind, VK, &BasePath);
- TheCall->setArg(i+1, Arg.get());
+ TheCall->setArg(i+1, Arg.take());
}
- // Switch the DeclRefExpr to refer to the new decl.
- DRE->setDecl(NewBuiltinDecl);
- DRE->setType(NewBuiltinDecl->getType());
+ ASTContext& Context = this->getASTContext();
+
+ // Create a new DeclRefExpr to refer to the new decl.
+ DeclRefExpr* NewDRE = DeclRefExpr::Create(
+ Context,
+ DRE->getQualifierLoc(),
+ NewBuiltinDecl,
+ DRE->getLocation(),
+ NewBuiltinDecl->getType(),
+ DRE->getValueKind());
// Set the callee in the CallExpr.
// FIXME: This leaks the original parens and implicit casts.
- ExprResult PromotedCall = UsualUnaryConversions(DRE);
+ ExprResult PromotedCall = UsualUnaryConversions(NewDRE);
if (PromotedCall.isInvalid())
return ExprError();
TheCall->setCallee(PromotedCall.take());
@@ -596,7 +855,6 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
return move(TheCallResult);
}
-
/// CheckObjCString - Checks that the argument to the builtin
/// CFString constructor is correct
/// Note: It might also make sense to do the UTF-16 conversion here (would
@@ -605,16 +863,16 @@ bool Sema::CheckObjCString(Expr *Arg) {
Arg = Arg->IgnoreParenCasts();
StringLiteral *Literal = dyn_cast<StringLiteral>(Arg);
- if (!Literal || Literal->isWide()) {
+ if (!Literal || !Literal->isAscii()) {
Diag(Arg->getLocStart(), diag::err_cfstring_literal_not_string_constant)
<< Arg->getSourceRange();
return true;
}
if (Literal->containsNonAsciiOrNull()) {
- llvm::StringRef String = Literal->getString();
+ StringRef String = Literal->getString();
unsigned NumBytes = String.size();
- llvm::SmallVector<UTF16, 128> ToBuf(NumBytes);
+ SmallVector<UTF16, 128> ToBuf(NumBytes);
const UTF8 *FromPtr = (UTF8 *)String.data();
UTF16 *ToPtr = &ToBuf[0];
@@ -649,6 +907,10 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
<< 0 /*function call*/ << 2 << TheCall->getNumArgs();
}
+ // Type-check the first argument normally.
+ if (checkBuiltinArgument(*this, TheCall, 0))
+ return true;
+
// Determine whether the current function is variadic or not.
BlockScopeInfo *CurBlock = getCurBlock();
bool isVariadic;
@@ -844,7 +1106,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
<< TheCall->getArg(i)->getSourceRange());
}
- llvm::SmallVector<Expr*, 32> exprs;
+ SmallVector<Expr*, 32> exprs;
for (unsigned i = 0, e = TheCall->getNumArgs(); i != e; i++) {
exprs.push_back(TheCall->getArg(i));
@@ -1238,7 +1500,7 @@ getSpecifierRange(const char *startSpecifier, unsigned specifierLen) {
SourceLocation End = getLocationOfByte(startSpecifier + specifierLen - 1);
// Advance the end SourceLocation by one due to half-open ranges.
- End = End.getFileLocWithOffset(1);
+ End = End.getLocWithOffset(1);
return CharSourceRange::getCharRange(Start, End);
}
@@ -1322,7 +1584,7 @@ CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex,
}
S.Diag(Loc, diag::warn_format_invalid_conversion)
- << llvm::StringRef(csStart, csLen)
+ << StringRef(csStart, csLen)
<< getSpecifierRange(startSpec, specifierLen);
return keepGoing;
@@ -1805,7 +2067,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
bool isPrintf) {
// CHECK: is the format string a wide literal?
- if (FExpr->isWide()) {
+ if (!FExpr->isAscii()) {
Diag(FExpr->getLocStart(),
diag::warn_format_string_is_wide_literal)
<< OrigFormatExpr->getSourceRange();
@@ -1813,12 +2075,13 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
}
// Str - The format string. NOTE: this is NOT null-terminated!
- llvm::StringRef StrRef = FExpr->getString();
+ StringRef StrRef = FExpr->getString();
const char *Str = StrRef.data();
unsigned StrLen = StrRef.size();
+ const unsigned numDataArgs = TheCall->getNumArgs() - firstDataArg;
// CHECK: empty format string?
- if (StrLen == 0) {
+ if (StrLen == 0 && numDataArgs > 0) {
Diag(FExpr->getLocStart(), diag::warn_empty_format_string)
<< OrigFormatExpr->getSourceRange();
return;
@@ -1826,18 +2089,16 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
if (isPrintf) {
CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
- TheCall->getNumArgs() - firstDataArg,
- isa<ObjCStringLiteral>(OrigFormatExpr), Str,
- HasVAListArg, TheCall, format_idx);
+ numDataArgs, isa<ObjCStringLiteral>(OrigFormatExpr),
+ Str, HasVAListArg, TheCall, format_idx);
if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen))
H.DoneProcessing();
}
else {
CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
- TheCall->getNumArgs() - firstDataArg,
- isa<ObjCStringLiteral>(OrigFormatExpr), Str,
- HasVAListArg, TheCall, format_idx);
+ numDataArgs, isa<ObjCStringLiteral>(OrigFormatExpr),
+ Str, HasVAListArg, TheCall, format_idx);
if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen))
H.DoneProcessing();
@@ -1881,19 +2142,22 @@ static QualType getSizeOfArgType(const Expr* E) {
/// \brief Check for dangerous or invalid arguments to memset().
///
/// This issues warnings on known problematic, dangerous or unspecified
-/// arguments to the standard 'memset', 'memcpy', and 'memmove' function calls.
+/// arguments to the standard 'memset', 'memcpy', 'memmove', and 'memcmp'
+/// function calls.
///
/// \param Call The call expression to diagnose.
-void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call,
- CheckedMemoryFunction CMF,
- IdentifierInfo *FnName) {
+void Sema::CheckMemaccessArguments(const CallExpr *Call,
+ CheckedMemoryFunction CMF,
+ IdentifierInfo *FnName) {
// It is possible to have a non-standard definition of memset. Validate
// we have enough arguments, and if not, abort further checking.
- if (Call->getNumArgs() < 3)
+ unsigned ExpectedNumArgs = (CMF == CMF_Strndup ? 2 : 3);
+ if (Call->getNumArgs() < ExpectedNumArgs)
return;
- unsigned LastArg = (CMF == CMF_Memset? 1 : 2);
- const Expr *LenExpr = Call->getArg(2)->IgnoreParenImpCasts();
+ unsigned LastArg = (CMF == CMF_Memset || CMF == CMF_Strndup ? 1 : 2);
+ unsigned LenArg = (CMF == CMF_Strndup ? 1 : 2);
+ const Expr *LenExpr = Call->getArg(LenArg)->IgnoreParenImpCasts();
// We have special checking when the length is a sizeof expression.
QualType SizeOfArgTy = getSizeOfArgType(LenExpr);
@@ -1927,6 +2191,8 @@ void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call,
llvm::FoldingSetNodeID DestID;
Dest->Profile(DestID, Context, true);
if (DestID == SizeOfArgID) {
+ // TODO: For strncpy() and friends, this could suggest sizeof(dst)
+ // over sizeof(src) as well.
unsigned ActionIdx = 0; // Default is to suggest dereferencing.
if (const UnaryOperator *UnaryOp = dyn_cast<UnaryOperator>(Dest))
if (UnaryOp->getOpcode() == UO_AddrOf)
@@ -1934,9 +2200,10 @@ void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call,
if (Context.getTypeSize(PointeeTy) == Context.getCharWidth())
ActionIdx = 2; // If the pointee's size is sizeof(char),
// suggest an explicit length.
+ unsigned DestSrcSelect = (CMF == CMF_Strndup ? 1 : ArgIdx);
DiagRuntimeBehavior(SizeOfArg->getExprLoc(), Dest,
PDiag(diag::warn_sizeof_pointer_expr_memaccess)
- << FnName << ArgIdx << ActionIdx
+ << FnName << DestSrcSelect << ActionIdx
<< Dest->getSourceRange()
<< SizeOfArg->getSourceRange());
break;
@@ -1958,24 +2225,27 @@ void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call,
}
}
- unsigned DiagID;
-
// Always complain about dynamic classes.
if (isDynamicClassType(PointeeTy))
- DiagID = diag::warn_dyn_class_memaccess;
+ DiagRuntimeBehavior(
+ Dest->getExprLoc(), Dest,
+ PDiag(diag::warn_dyn_class_memaccess)
+ << (CMF == CMF_Memcmp ? ArgIdx + 2 : ArgIdx) << FnName << PointeeTy
+ // "overwritten" if we're warning about the destination for any call
+ // but memcmp; otherwise a verb appropriate to the call.
+ << (ArgIdx == 0 && CMF != CMF_Memcmp ? 0 : (unsigned)CMF)
+ << Call->getCallee()->getSourceRange());
else if (PointeeTy.hasNonTrivialObjCLifetime() && CMF != CMF_Memset)
- DiagID = diag::warn_arc_object_memaccess;
+ DiagRuntimeBehavior(
+ Dest->getExprLoc(), Dest,
+ PDiag(diag::warn_arc_object_memaccess)
+ << ArgIdx << FnName << PointeeTy
+ << Call->getCallee()->getSourceRange());
else
continue;
DiagRuntimeBehavior(
Dest->getExprLoc(), Dest,
- PDiag(DiagID)
- << ArgIdx << FnName << PointeeTy
- << Call->getCallee()->getSourceRange());
-
- DiagRuntimeBehavior(
- Dest->getExprLoc(), Dest,
PDiag(diag::note_bad_memaccess_silence)
<< FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)"));
break;
@@ -1983,10 +2253,107 @@ void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call,
}
}
+// A little helper routine: ignore addition and subtraction of integer literals.
+// This intentionally does not ignore all integer constant expressions because
+// we don't want to remove sizeof().
+static const Expr *ignoreLiteralAdditions(const Expr *Ex, ASTContext &Ctx) {
+ Ex = Ex->IgnoreParenCasts();
+
+ for (;;) {
+ const BinaryOperator * BO = dyn_cast<BinaryOperator>(Ex);
+ if (!BO || !BO->isAdditiveOp())
+ break;
+
+ const Expr *RHS = BO->getRHS()->IgnoreParenCasts();
+ const Expr *LHS = BO->getLHS()->IgnoreParenCasts();
+
+ if (isa<IntegerLiteral>(RHS))
+ Ex = LHS;
+ else if (isa<IntegerLiteral>(LHS))
+ Ex = RHS;
+ else
+ break;
+ }
+
+ return Ex;
+}
+
+// Warn if the user has made the 'size' argument to strlcpy or strlcat
+// be the size of the source, instead of the destination.
+void Sema::CheckStrlcpycatArguments(const CallExpr *Call,
+ IdentifierInfo *FnName) {
+
+ // Don't crash if the user has the wrong number of arguments
+ if (Call->getNumArgs() != 3)
+ return;
+
+ const Expr *SrcArg = ignoreLiteralAdditions(Call->getArg(1), Context);
+ const Expr *SizeArg = ignoreLiteralAdditions(Call->getArg(2), Context);
+ const Expr *CompareWithSrc = NULL;
+
+ // Look for 'strlcpy(dst, x, sizeof(x))'
+ if (const Expr *Ex = getSizeOfExprArg(SizeArg))
+ CompareWithSrc = Ex;
+ else {
+ // Look for 'strlcpy(dst, x, strlen(x))'
+ if (const CallExpr *SizeCall = dyn_cast<CallExpr>(SizeArg)) {
+ if (SizeCall->isBuiltinCall(Context) == Builtin::BIstrlen
+ && SizeCall->getNumArgs() == 1)
+ CompareWithSrc = ignoreLiteralAdditions(SizeCall->getArg(0), Context);
+ }
+ }
+
+ if (!CompareWithSrc)
+ return;
+
+ // Determine if the argument to sizeof/strlen is equal to the source
+ // argument. In principle there's all kinds of things you could do
+ // here, for instance creating an == expression and evaluating it with
+ // EvaluateAsBooleanCondition, but this uses a more direct technique:
+ const DeclRefExpr *SrcArgDRE = dyn_cast<DeclRefExpr>(SrcArg);
+ if (!SrcArgDRE)
+ return;
+
+ const DeclRefExpr *CompareWithSrcDRE = dyn_cast<DeclRefExpr>(CompareWithSrc);
+ if (!CompareWithSrcDRE ||
+ SrcArgDRE->getDecl() != CompareWithSrcDRE->getDecl())
+ return;
+
+ const Expr *OriginalSizeArg = Call->getArg(2);
+ Diag(CompareWithSrcDRE->getLocStart(), diag::warn_strlcpycat_wrong_size)
+ << OriginalSizeArg->getSourceRange() << FnName;
+
+ // Output a FIXIT hint if the destination is an array (rather than a
+ // pointer to an array). This could be enhanced to handle some
+ // pointers if we know the actual size, like if DstArg is 'array+2'
+ // we could say 'sizeof(array)-2'.
+ const Expr *DstArg = Call->getArg(0)->IgnoreParenImpCasts();
+ QualType DstArgTy = DstArg->getType();
+
+ // Only handle constant-sized or VLAs, but not flexible members.
+ if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(DstArgTy)) {
+ // Only issue the FIXIT for arrays of size > 1.
+ if (CAT->getSize().getSExtValue() <= 1)
+ return;
+ } else if (!DstArgTy->isVariableArrayType()) {
+ return;
+ }
+
+ llvm::SmallString<128> sizeString;
+ llvm::raw_svector_ostream OS(sizeString);
+ OS << "sizeof(";
+ DstArg->printPretty(OS, Context, 0, getPrintingPolicy());
+ OS << ")";
+
+ Diag(OriginalSizeArg->getLocStart(), diag::note_strlcpycat_wrong_size)
+ << FixItHint::CreateReplacement(OriginalSizeArg->getSourceRange(),
+ OS.str());
+}
+
//===--- CHECK: Return Address of Stack Variable --------------------------===//
-static Expr *EvalVal(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars);
-static Expr *EvalAddr(Expr* E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars);
+static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars);
+static Expr *EvalAddr(Expr* E, SmallVectorImpl<DeclRefExpr *> &refVars);
/// CheckReturnStackAddr - Check if a return statement returns the address
/// of a stack variable.
@@ -1995,7 +2362,7 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
SourceLocation ReturnLoc) {
Expr *stackE = 0;
- llvm::SmallVector<DeclRefExpr *, 8> refVars;
+ SmallVector<DeclRefExpr *, 8> refVars;
// Perform checking for returned stack addresses, local blocks,
// label addresses or references to temporaries.
@@ -2077,7 +2444,7 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
/// * arbitrary interplay between "&" and "*" operators
/// * pointer arithmetic from an address of a stack variable
/// * taking the address of an array element where the array is on the stack
-static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) {
+static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
if (E->isTypeDependent())
return NULL;
@@ -2222,7 +2589,7 @@ static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) {
/// EvalVal - This function is complements EvalAddr in the mutual recursion.
/// See the comments for EvalAddr for more details.
-static Expr *EvalVal(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) {
+static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
do {
// We should only be called for evaluating non-pointer expressions, or
// expressions with a pointer type that are not used as references but instead
@@ -2339,11 +2706,11 @@ do {
/// Check for comparisons of floating point operands using != and ==.
/// Issue a warning if these are no self-comparisons, as they are not likely
/// to do what the programmer intended.
-void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) {
+void Sema::CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr *RHS) {
bool EmitWarning = true;
- Expr* LeftExprSansParen = lex->IgnoreParenImpCasts();
- Expr* RightExprSansParen = rex->IgnoreParenImpCasts();
+ Expr* LeftExprSansParen = LHS->IgnoreParenImpCasts();
+ Expr* RightExprSansParen = RHS->IgnoreParenImpCasts();
// Special case: check for x == x (which is OK).
// Do not emit warnings for such cases.
@@ -2382,8 +2749,8 @@ void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) {
// Emit the diagnostic.
if (EmitWarning)
- Diag(loc, diag::warn_floatingpoint_eq)
- << lex->getSourceRange() << rex->getSourceRange();
+ Diag(Loc, diag::warn_floatingpoint_eq)
+ << LHS->getSourceRange() << RHS->getSourceRange();
}
//===--- CHECK: Integer mixed-sign comparisons (-Wsign-compare) --------===//
@@ -2427,7 +2794,7 @@ struct IntRange {
// For enum types, use the known bit width of the enumerators.
if (const EnumType *ET = dyn_cast<EnumType>(T)) {
EnumDecl *Enum = ET->getDecl();
- if (!Enum->isDefinition())
+ if (!Enum->isCompleteDefinition())
return IntRange(C.getIntWidth(QualType(T, 0)), false);
unsigned NumPositive = Enum->getNumPositiveBits();
@@ -2455,7 +2822,7 @@ struct IntRange {
if (const ComplexType *CT = dyn_cast<ComplexType>(T))
T = CT->getElementType().getTypePtr();
if (const EnumType *ET = dyn_cast<EnumType>(T))
- T = ET->getDecl()->getIntegerType().getTypePtr();
+ T = C.getCanonicalType(ET->getDecl()->getIntegerType()).getTypePtr();
const BuiltinType *BT = cast<BuiltinType>(T);
assert(BT->isInteger());
@@ -2732,14 +3099,9 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
IntRange::forValueOfType(C, E->getType());
}
- FieldDecl *BitField = E->getBitField();
- if (BitField) {
- llvm::APSInt BitWidthAP = BitField->getBitWidth()->EvaluateAsInt(C);
- unsigned BitWidth = BitWidthAP.getZExtValue();
-
- return IntRange(BitWidth,
+ if (FieldDecl *BitField = E->getBitField())
+ return IntRange(BitField->getBitWidthValue(C),
BitField->getType()->isUnsignedIntegerOrEnumerationType());
- }
return IntRange::forValueOfType(C, E->getType());
}
@@ -2848,10 +3210,7 @@ void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
/// \brief Implements -Wsign-compare.
///
-/// \param lex the left-hand expression
-/// \param rex the right-hand expression
-/// \param OpLoc the location of the joining operator
-/// \param BinOpc binary opcode or 0
+/// \param E the binary operator to check for warnings
void AnalyzeComparison(Sema &S, BinaryOperator *E) {
// The type the comparison is being performed in.
QualType T = E->getLHS()->getType();
@@ -2868,20 +3227,20 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) {
|| E->isValueDependent() || E->isIntegerConstantExpr(S.Context))
return AnalyzeImpConvsInComparison(S, E);
- Expr *lex = E->getLHS()->IgnoreParenImpCasts();
- Expr *rex = E->getRHS()->IgnoreParenImpCasts();
+ Expr *LHS = E->getLHS()->IgnoreParenImpCasts();
+ Expr *RHS = E->getRHS()->IgnoreParenImpCasts();
// Check to see if one of the (unmodified) operands is of different
// signedness.
Expr *signedOperand, *unsignedOperand;
- if (lex->getType()->hasSignedIntegerRepresentation()) {
- assert(!rex->getType()->hasSignedIntegerRepresentation() &&
+ if (LHS->getType()->hasSignedIntegerRepresentation()) {
+ assert(!RHS->getType()->hasSignedIntegerRepresentation() &&
"unsigned comparison between two signed integer expressions?");
- signedOperand = lex;
- unsignedOperand = rex;
- } else if (rex->getType()->hasSignedIntegerRepresentation()) {
- signedOperand = rex;
- unsignedOperand = lex;
+ signedOperand = LHS;
+ unsignedOperand = RHS;
+ } else if (RHS->getType()->hasSignedIntegerRepresentation()) {
+ signedOperand = RHS;
+ unsignedOperand = LHS;
} else {
CheckTrivialUnsignedComparison(S, E);
return AnalyzeImpConvsInComparison(S, E);
@@ -2892,8 +3251,8 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) {
// Go ahead and analyze implicit conversions in the operands. Note
// that we skip the implicit conversions on both sides.
- AnalyzeImplicitConversions(S, lex, E->getOperatorLoc());
- AnalyzeImplicitConversions(S, rex, E->getOperatorLoc());
+ AnalyzeImplicitConversions(S, LHS, E->getOperatorLoc());
+ AnalyzeImplicitConversions(S, RHS, E->getOperatorLoc());
// If the signed range is non-negative, -Wsign-compare won't fire,
// but we should still check for comparisons which are always true
@@ -2918,8 +3277,8 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) {
}
S.Diag(E->getOperatorLoc(), diag::warn_mixed_sign_comparison)
- << lex->getType() << rex->getType()
- << lex->getSourceRange() << rex->getSourceRange();
+ << LHS->getType() << RHS->getType()
+ << LHS->getSourceRange() << RHS->getSourceRange();
}
/// Analyzes an attempt to assign the given value to a bitfield.
@@ -2944,16 +3303,14 @@ bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
Expr *OriginalInit = Init->IgnoreParenImpCasts();
- llvm::APSInt Width(32);
Expr::EvalResult InitValue;
- if (!Bitfield->getBitWidth()->isIntegerConstantExpr(Width, S.Context) ||
- !OriginalInit->Evaluate(InitValue, S.Context) ||
+ if (!OriginalInit->Evaluate(InitValue, S.Context) ||
!InitValue.Val.isInt())
return false;
const llvm::APSInt &Value = InitValue.Val.getInt();
unsigned OriginalWidth = Value.getBitWidth();
- unsigned FieldWidth = Width.getZExtValue();
+ unsigned FieldWidth = Bitfield->getBitWidthValue(S.Context);
if (OriginalWidth <= FieldWidth)
return false;
@@ -3014,34 +3371,22 @@ void DiagnoseImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext,
DiagnoseImpCast(S, E, E->getType(), T, CContext, diag);
}
-/// Diagnose an implicit cast from a literal expression. Also attemps to supply
-/// fixit hints when the cast wouldn't lose information to simply write the
-/// expression with the expected type.
+/// Diagnose an implicit cast from a literal expression. Does not warn when the
+/// cast wouldn't lose information.
void DiagnoseFloatingLiteralImpCast(Sema &S, FloatingLiteral *FL, QualType T,
SourceLocation CContext) {
- // Emit the primary warning first, then try to emit a fixit hint note if
- // reasonable.
- S.Diag(FL->getExprLoc(), diag::warn_impcast_literal_float_to_integer)
- << FL->getType() << T << FL->getSourceRange() << SourceRange(CContext);
-
- const llvm::APFloat &Value = FL->getValue();
-
- // Don't attempt to fix PPC double double literals.
- if (&Value.getSemantics() == &llvm::APFloat::PPCDoubleDouble)
- return;
-
- // Try to convert this exactly to an integer.
+ // Try to convert the literal exactly to an integer. If we can, don't warn.
bool isExact = false;
+ const llvm::APFloat &Value = FL->getValue();
llvm::APSInt IntegerValue(S.Context.getIntWidth(T),
T->hasUnsignedIntegerRepresentation());
if (Value.convertToInteger(IntegerValue,
llvm::APFloat::rmTowardZero, &isExact)
- != llvm::APFloat::opOK || !isExact)
+ == llvm::APFloat::opOK && isExact)
return;
- std::string LiteralValue = IntegerValue.toString(10);
- S.Diag(FL->getExprLoc(), diag::note_fix_integral_float_as_integer)
- << FixItHint::CreateReplacement(FL->getSourceRange(), LiteralValue);
+ S.Diag(FL->getExprLoc(), diag::warn_impcast_literal_float_to_integer)
+ << FL->getType() << T << FL->getSourceRange() << SourceRange(CContext);
}
std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) {
@@ -3067,17 +3412,24 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if (Source == Target) return;
if (Target->isDependentType()) return;
- // If the conversion context location is invalid don't complain.
- // We also don't want to emit a warning if the issue occurs from the
- // instantiation of a system macro. The problem is that 'getSpellingLoc()'
- // is slow, so we delay this check as long as possible. Once we detect
- // we are in that scenario, we just return.
+ // If the conversion context location is invalid don't complain. We also
+ // don't want to emit a warning if the issue occurs from the expansion of
+ // a system macro. The problem is that 'getSpellingLoc()' is slow, so we
+ // delay this check as long as possible. Once we detect we are in that
+ // scenario, we just return.
if (CC.isInvalid())
return;
- // Never diagnose implicit casts to bool.
- if (Target->isSpecificBuiltinType(BuiltinType::Bool))
- return;
+ // Diagnose implicit casts to bool.
+ if (Target->isSpecificBuiltinType(BuiltinType::Bool)) {
+ if (isa<StringLiteral>(E))
+ // Warn on string literal to bool. Checks for string literals in logical
+ // expressions, for instances, assert(0 && "error here"), is prevented
+ // by a check in AnalyzeImplicitConversions().
+ return DiagnoseImpCast(S, E, T, CC,
+ diag::warn_impcast_string_literal_to_bool);
+ return; // Other casts to bool are not checked.
+ }
// Strip vector types.
if (isa<VectorType>(Source)) {
@@ -3145,6 +3497,11 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return;
Expr *InnerE = E->IgnoreParenImpCasts();
+ // We also want to warn on, e.g., "int i = -1.234"
+ if (UnaryOperator *UOp = dyn_cast<UnaryOperator>(InnerE))
+ if (UOp->getOpcode() == UO_Minus || UOp->getOpcode() == UO_Plus)
+ InnerE = UOp->getSubExpr()->IgnoreParenImpCasts();
+
if (FloatingLiteral *FL = dyn_cast<FloatingLiteral>(InnerE)) {
DiagnoseFloatingLiteralImpCast(S, FL, T, CC);
} else {
@@ -3279,29 +3636,16 @@ void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T) {
CC))
return;
- // ...and -Wsign-compare isn't...
- if (!S.Diags.getDiagnosticLevel(diag::warn_mixed_sign_conditional, CC))
- return;
-
// ...then check whether it would have warned about either of the
// candidates for a signedness conversion to the condition type.
- if (E->getType() != T) {
- Suspicious = false;
- CheckImplicitConversion(S, E->getTrueExpr()->IgnoreParenImpCasts(),
+ if (E->getType() == T) return;
+
+ Suspicious = false;
+ CheckImplicitConversion(S, E->getTrueExpr()->IgnoreParenImpCasts(),
+ E->getType(), CC, &Suspicious);
+ if (!Suspicious)
+ CheckImplicitConversion(S, E->getFalseExpr()->IgnoreParenImpCasts(),
E->getType(), CC, &Suspicious);
- if (!Suspicious)
- CheckImplicitConversion(S, E->getFalseExpr()->IgnoreParenImpCasts(),
- E->getType(), CC, &Suspicious);
- if (!Suspicious)
- return;
- }
-
- // If so, emit a diagnostic under -Wsign-compare.
- Expr *lex = E->getTrueExpr()->IgnoreParenImpCasts();
- Expr *rex = E->getFalseExpr()->IgnoreParenImpCasts();
- S.Diag(E->getQuestionLoc(), diag::warn_mixed_sign_conditional)
- << lex->getType() << rex->getType()
- << lex->getSourceRange() << rex->getSourceRange();
}
/// AnalyzeImplicitConversions - Find and report any interesting
@@ -3311,6 +3655,9 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
QualType T = OrigE->getType();
Expr *E = OrigE->IgnoreParenImpCasts();
+ if (E->isTypeDependent() || E->isValueDependent())
+ return;
+
// For conditional operators, we analyze the arguments as if they
// were being fed directly into the output.
if (isa<ConditionalOperator>(E)) {
@@ -3354,8 +3701,16 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
// Now just recurse over the expression's children.
CC = E->getExprLoc();
- for (Stmt::child_range I = E->children(); I; ++I)
- AnalyzeImplicitConversions(S, cast<Expr>(*I), CC);
+ BinaryOperator *BO = dyn_cast<BinaryOperator>(E);
+ bool IsLogicalOperator = BO && BO->isLogicalOp();
+ for (Stmt::child_range I = E->children(); I; ++I) {
+ Expr *ChildExpr = cast<Expr>(*I);
+ if (IsLogicalOperator &&
+ isa<StringLiteral>(ChildExpr->IgnoreParenImpCasts()))
+ // Ignore checking string literals that are in logical operators.
+ continue;
+ AnalyzeImplicitConversions(S, ChildExpr, CC);
+ }
}
} // end anonymous namespace
@@ -3376,6 +3731,11 @@ void Sema::CheckImplicitConversions(Expr *E, SourceLocation CC) {
if (E->isTypeDependent() || E->isValueDependent())
return;
+ // Check for array bounds violations in cases where the check isn't triggered
+ // elsewhere for other Expr types (like BinaryOperators), e.g. when an
+ // ArraySubscriptExpr is on the RHS of a variable initialization.
+ CheckArrayAccess(E);
+
// This is not the right CC for (e.g.) a variable initialization.
AnalyzeImplicitConversions(*this, E, CC);
}
@@ -3442,7 +3802,7 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) {
// cast; don't do it if we're ignoring -Wcast_align (as is the default).
if (getDiagnostics().getDiagnosticLevel(diag::warn_cast_align,
TRange.getBegin())
- == Diagnostic::Ignored)
+ == DiagnosticsEngine::Ignored)
return;
// Ignore dependent types.
@@ -3480,63 +3840,164 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) {
<< TRange << Op->getSourceRange();
}
-static void CheckArrayAccess_Check(Sema &S,
- const clang::ArraySubscriptExpr *E) {
- const Expr *BaseExpr = E->getBase()->IgnoreParenImpCasts();
+static const Type* getElementType(const Expr *BaseExpr) {
+ const Type* EltType = BaseExpr->getType().getTypePtr();
+ if (EltType->isAnyPointerType())
+ return EltType->getPointeeType().getTypePtr();
+ else if (EltType->isArrayType())
+ return EltType->getBaseElementTypeUnsafe();
+ return EltType;
+}
+
+/// \brief Check whether this array fits the idiom of a size-one tail padded
+/// array member of a struct.
+///
+/// We avoid emitting out-of-bounds access warnings for such arrays as they are
+/// commonly used to emulate flexible arrays in C89 code.
+static bool IsTailPaddedMemberArray(Sema &S, llvm::APInt Size,
+ const NamedDecl *ND) {
+ if (Size != 1 || !ND) return false;
+
+ const FieldDecl *FD = dyn_cast<FieldDecl>(ND);
+ if (!FD) return false;
+
+ // Don't consider sizes resulting from macro expansions or template argument
+ // substitution to form C89 tail-padded arrays.
+ ConstantArrayTypeLoc TL =
+ cast<ConstantArrayTypeLoc>(FD->getTypeSourceInfo()->getTypeLoc());
+ const Expr *SizeExpr = dyn_cast<IntegerLiteral>(TL.getSizeExpr());
+ if (!SizeExpr || SizeExpr->getExprLoc().isMacroID())
+ return false;
+
+ const RecordDecl *RD = dyn_cast<RecordDecl>(FD->getDeclContext());
+ if (!RD || !RD->isStruct())
+ return false;
+
+ // See if this is the last field decl in the record.
+ const Decl *D = FD;
+ while ((D = D->getNextDeclInContext()))
+ if (isa<FieldDecl>(D))
+ return false;
+ return true;
+}
+
+void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
+ bool isSubscript, bool AllowOnePastEnd) {
+ const Type* EffectiveType = getElementType(BaseExpr);
+ BaseExpr = BaseExpr->IgnoreParenCasts();
+ IndexExpr = IndexExpr->IgnoreParenCasts();
+
const ConstantArrayType *ArrayTy =
- S.Context.getAsConstantArrayType(BaseExpr->getType());
+ Context.getAsConstantArrayType(BaseExpr->getType());
if (!ArrayTy)
return;
- const Expr *IndexExpr = E->getIdx();
if (IndexExpr->isValueDependent())
return;
llvm::APSInt index;
- if (!IndexExpr->isIntegerConstantExpr(index, S.Context))
+ if (!IndexExpr->isIntegerConstantExpr(index, Context))
return;
+ const NamedDecl *ND = NULL;
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
+ ND = dyn_cast<NamedDecl>(DRE->getDecl());
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr))
+ ND = dyn_cast<NamedDecl>(ME->getMemberDecl());
+
if (index.isUnsigned() || !index.isNegative()) {
llvm::APInt size = ArrayTy->getSize();
if (!size.isStrictlyPositive())
return;
+
+ const Type* BaseType = getElementType(BaseExpr);
+ if (BaseType != EffectiveType) {
+ // Make sure we're comparing apples to apples when comparing index to size
+ uint64_t ptrarith_typesize = Context.getTypeSize(EffectiveType);
+ uint64_t array_typesize = Context.getTypeSize(BaseType);
+ // Handle ptrarith_typesize being zero, such as when casting to void*
+ if (!ptrarith_typesize) ptrarith_typesize = 1;
+ if (ptrarith_typesize != array_typesize) {
+ // There's a cast to a different size type involved
+ uint64_t ratio = array_typesize / ptrarith_typesize;
+ // TODO: Be smarter about handling cases where array_typesize is not a
+ // multiple of ptrarith_typesize
+ if (ptrarith_typesize * ratio == array_typesize)
+ size *= llvm::APInt(size.getBitWidth(), ratio);
+ }
+ }
+
if (size.getBitWidth() > index.getBitWidth())
index = index.sext(size.getBitWidth());
else if (size.getBitWidth() < index.getBitWidth())
size = size.sext(index.getBitWidth());
- if (index.slt(size))
+ // For array subscripting the index must be less than size, but for pointer
+ // arithmetic also allow the index (offset) to be equal to size since
+ // computing the next address after the end of the array is legal and
+ // commonly done e.g. in C++ iterators and range-based for loops.
+ if (AllowOnePastEnd ? index.sle(size) : index.slt(size))
+ return;
+
+ // Also don't warn for arrays of size 1 which are members of some
+ // structure. These are often used to approximate flexible arrays in C89
+ // code.
+ if (IsTailPaddedMemberArray(*this, size, ND))
return;
- S.DiagRuntimeBehavior(E->getBase()->getLocStart(), BaseExpr,
- S.PDiag(diag::warn_array_index_exceeds_bounds)
- << index.toString(10, true)
- << size.toString(10, true)
- << IndexExpr->getSourceRange());
+ unsigned DiagID = diag::warn_ptr_arith_exceeds_bounds;
+ if (isSubscript)
+ DiagID = diag::warn_array_index_exceeds_bounds;
+
+ DiagRuntimeBehavior(BaseExpr->getLocStart(), BaseExpr,
+ PDiag(DiagID) << index.toString(10, true)
+ << size.toString(10, true)
+ << (unsigned)size.getLimitedValue(~0U)
+ << IndexExpr->getSourceRange());
} else {
- S.DiagRuntimeBehavior(E->getBase()->getLocStart(), BaseExpr,
- S.PDiag(diag::warn_array_index_precedes_bounds)
- << index.toString(10, true)
- << IndexExpr->getSourceRange());
+ unsigned DiagID = diag::warn_array_index_precedes_bounds;
+ if (!isSubscript) {
+ DiagID = diag::warn_ptr_arith_precedes_bounds;
+ if (index.isNegative()) index = -index;
+ }
+
+ DiagRuntimeBehavior(BaseExpr->getLocStart(), BaseExpr,
+ PDiag(DiagID) << index.toString(10, true)
+ << IndexExpr->getSourceRange());
}
- const NamedDecl *ND = NULL;
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
- ND = dyn_cast<NamedDecl>(DRE->getDecl());
- if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr))
- ND = dyn_cast<NamedDecl>(ME->getMemberDecl());
if (ND)
- S.DiagRuntimeBehavior(ND->getLocStart(), BaseExpr,
- S.PDiag(diag::note_array_index_out_of_bounds)
- << ND->getDeclName());
+ DiagRuntimeBehavior(ND->getLocStart(), BaseExpr,
+ PDiag(diag::note_array_index_out_of_bounds)
+ << ND->getDeclName());
}
void Sema::CheckArrayAccess(const Expr *expr) {
- while (true) {
- expr = expr->IgnoreParens();
+ int AllowOnePastEnd = 0;
+ while (expr) {
+ expr = expr->IgnoreParenImpCasts();
switch (expr->getStmtClass()) {
- case Stmt::ArraySubscriptExprClass:
- CheckArrayAccess_Check(*this, cast<ArraySubscriptExpr>(expr));
+ case Stmt::ArraySubscriptExprClass: {
+ const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(expr);
+ CheckArrayAccess(ASE->getBase(), ASE->getIdx(), true,
+ AllowOnePastEnd > 0);
return;
+ }
+ case Stmt::UnaryOperatorClass: {
+ // Only unwrap the * and & unary operators
+ const UnaryOperator *UO = cast<UnaryOperator>(expr);
+ expr = UO->getSubExpr();
+ switch (UO->getOpcode()) {
+ case UO_AddrOf:
+ AllowOnePastEnd++;
+ break;
+ case UO_Deref:
+ AllowOnePastEnd--;
+ break;
+ default:
+ return;
+ }
+ break;
+ }
case Stmt::ConditionalOperatorClass: {
const ConditionalOperator *cond = cast<ConditionalOperator>(expr);
if (const Expr *lhs = cond->getLHS())
@@ -3590,7 +4051,7 @@ static bool findRetainCycleOwner(Expr *e, RetainCycleOwner &owner) {
case CK_BitCast:
case CK_LValueBitCast:
case CK_LValueToRValue:
- case CK_ObjCReclaimReturnedObject:
+ case CK_ARCReclaimReturnedObject:
e = cast->getSubExpr();
continue;
@@ -3599,10 +4060,7 @@ static bool findRetainCycleOwner(Expr *e, RetainCycleOwner &owner) {
const ObjCPropertyRefExpr *pre = cast->getSubExpr()->getObjCProperty();
if (pre->isImplicitProperty()) return false;
ObjCPropertyDecl *property = pre->getExplicitProperty();
- if (!(property->getPropertyAttributes() &
- (ObjCPropertyDecl::OBJC_PR_retain |
- ObjCPropertyDecl::OBJC_PR_copy |
- ObjCPropertyDecl::OBJC_PR_strong)) &&
+ if (!property->isRetaining() &&
!(property->getPropertyIvarDecl() &&
property->getPropertyIvarDecl()->getType()
.getObjCLifetime() == Qualifiers::OCL_Strong))
@@ -3723,7 +4181,7 @@ static void diagnoseRetainCycle(Sema &S, Expr *capturer,
static bool isSetterLikeSelector(Selector sel) {
if (sel.isUnarySelector()) return false;
- llvm::StringRef str = sel.getNameForSlot(0);
+ StringRef str = sel.getNameForSlot(0);
while (!str.empty() && str.front() == '_') str = str.substr(1);
if (str.startswith("set") || str.startswith("add"))
str = str.substr(3);
@@ -3775,7 +4233,7 @@ bool Sema::checkUnsafeAssigns(SourceLocation Loc,
return false;
// strip off any implicit cast added to get to the one arc-specific
while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
- if (cast->getCastKind() == CK_ObjCConsumeObject) {
+ if (cast->getCastKind() == CK_ARCConsumeObject) {
Diag(Loc, diag::warn_arc_retained_assign)
<< (LT == Qualifiers::OCL_ExplicitNone)
<< RHS->getSourceRange();
@@ -3806,7 +4264,7 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
unsigned Attributes = PD->getPropertyAttributes();
if (Attributes & ObjCPropertyDecl::OBJC_PR_assign)
while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
- if (cast->getCastKind() == CK_ObjCConsumeObject) {
+ if (cast->getCastKind() == CK_ARCConsumeObject) {
Diag(Loc, diag::warn_arc_retained_property_assign)
<< RHS->getSourceRange();
return;
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index b555c8a9aa1f..405d626ae9ba 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -61,7 +61,7 @@ namespace {
/// a single (declaration, index) mapping (the common case) but
/// can also store a list of (declaration, index) mappings.
class ShadowMapEntry {
- typedef llvm::SmallVector<DeclIndexPair, 4> DeclIndexPairVector;
+ typedef SmallVector<DeclIndexPair, 4> DeclIndexPairVector;
/// \brief Contains either the solitary NamedDecl * or a vector
/// of (declaration, index) pairs.
@@ -434,7 +434,7 @@ static NestedNameSpecifier *
getRequiredQualification(ASTContext &Context,
DeclContext *CurContext,
DeclContext *TargetContext) {
- llvm::SmallVector<DeclContext *, 4> TargetParents;
+ SmallVector<DeclContext *, 4> TargetParents;
for (DeclContext *CommonAncestor = TargetContext;
CommonAncestor && !CommonAncestor->Encloses(CurContext);
@@ -990,9 +990,6 @@ bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const {
else if (SemaRef.getLangOptions().ObjC1) {
if (isa<ObjCIvarDecl>(ND))
return true;
- if (isa<ObjCPropertyDecl>(ND) &&
- SemaRef.canSynthesizeProvisionalIvar(cast<ObjCPropertyDecl>(ND)))
- return true;
}
return ND->getIdentifierNamespace() & IDNS;
@@ -1011,9 +1008,6 @@ bool ResultBuilder::IsOrdinaryNonTypeName(NamedDecl *ND) const {
else if (SemaRef.getLangOptions().ObjC1) {
if (isa<ObjCIvarDecl>(ND))
return true;
- if (isa<ObjCPropertyDecl>(ND) &&
- SemaRef.canSynthesizeProvisionalIvar(cast<ObjCPropertyDecl>(ND)))
- return true;
}
return ND->getIdentifierNamespace() & IDNS;
@@ -1192,8 +1186,16 @@ namespace {
CodeCompletionDeclConsumer(ResultBuilder &Results, DeclContext *CurContext)
: Results(Results), CurContext(CurContext) { }
- virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass) {
- Results.AddResult(ND, CurContext, Hiding, InBaseClass);
+ virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
+ bool InBaseClass) {
+ bool Accessible = true;
+ if (Ctx) {
+ if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx))
+ Accessible = Results.getSema().IsSimplyAccessible(ND, Class);
+ // FIXME: ObjC access checks are missing.
+ }
+ ResultBuilder::Result Result(ND, 0, false, Accessible);
+ Results.AddResult(Result, CurContext, Hiding, InBaseClass);
}
};
}
@@ -1846,6 +1848,14 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
Results.AddResult(Result("operator"));
}
+/// \brief Retrieve a printing policy suitable for code completion.
+static PrintingPolicy getCompletionPrintingPolicy(Sema &S) {
+ PrintingPolicy Policy = S.getPrintingPolicy();
+ Policy.AnonymousTagLocations = false;
+ Policy.SuppressStrongLifetime = true;
+ return Policy;
+}
+
/// \brief Retrieve the string representation of the given type as a string
/// that has the appropriate lifetime for code completion.
///
@@ -1853,15 +1863,12 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
/// common type names.
static const char *GetCompletionTypeString(QualType T,
ASTContext &Context,
+ const PrintingPolicy &Policy,
CodeCompletionAllocator &Allocator) {
- PrintingPolicy Policy(Context.PrintingPolicy);
- Policy.AnonymousTagLocations = false;
- Policy.SuppressStrongLifetime = true;
-
if (!T.getLocalQualifiers()) {
// Built-in type names are constant strings.
if (const BuiltinType *BT = dyn_cast<BuiltinType>(T))
- return BT->getName(Context.getLangOptions());
+ return BT->getName(Policy);
// Anonymous tag types are constant strings.
if (const TagType *TagT = dyn_cast<TagType>(T))
@@ -1885,6 +1892,7 @@ static const char *GetCompletionTypeString(QualType T,
/// \brief If the given declaration has an associated type, add it as a result
/// type chunk.
static void AddResultTypeChunk(ASTContext &Context,
+ const PrintingPolicy &Policy,
NamedDecl *ND,
CodeCompletionBuilder &Result) {
if (!ND)
@@ -1915,7 +1923,7 @@ static void AddResultTypeChunk(ASTContext &Context,
if (T.isNull() || Context.hasSameType(T, Context.DependentTy))
return;
- Result.AddResultTypeChunk(GetCompletionTypeString(T, Context,
+ Result.AddResultTypeChunk(GetCompletionTypeString(T, Context, Policy,
Result.getAllocator()));
}
@@ -1933,13 +1941,32 @@ static void MaybeAddSentinel(ASTContext &Context, NamedDecl *FunctionOrMethod,
}
}
+static void appendWithSpace(std::string &Result, StringRef Text) {
+ if (!Result.empty())
+ Result += ' ';
+ Result += Text.str();
+}
+static std::string formatObjCParamQualifiers(unsigned ObjCQuals) {
+ std::string Result;
+ if (ObjCQuals & Decl::OBJC_TQ_In)
+ appendWithSpace(Result, "in");
+ else if (ObjCQuals & Decl::OBJC_TQ_Inout)
+ appendWithSpace(Result, "inout");
+ else if (ObjCQuals & Decl::OBJC_TQ_Out)
+ appendWithSpace(Result, "out");
+ if (ObjCQuals & Decl::OBJC_TQ_Bycopy)
+ appendWithSpace(Result, "bycopy");
+ else if (ObjCQuals & Decl::OBJC_TQ_Byref)
+ appendWithSpace(Result, "byref");
+ if (ObjCQuals & Decl::OBJC_TQ_Oneway)
+ appendWithSpace(Result, "oneway");
+ return Result;
+}
+
static std::string FormatFunctionParameter(ASTContext &Context,
+ const PrintingPolicy &Policy,
ParmVarDecl *Param,
bool SuppressName = false) {
- PrintingPolicy Policy(Context.PrintingPolicy);
- Policy.AnonymousTagLocations = false;
- Policy.SuppressStrongLifetime = true;
-
bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext());
if (Param->getType()->isDependentType() ||
!Param->getType()->isBlockPointerType()) {
@@ -1953,8 +1980,8 @@ static std::string FormatFunctionParameter(ASTContext &Context,
Param->getType().getAsStringInternal(Result, Policy);
if (ObjCMethodParam) {
- Result = "(" + Result;
- Result += ")";
+ Result = "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier())
+ + Result + ")";
if (Param->getIdentifier() && !SuppressName)
Result += Param->getIdentifier()->getName();
}
@@ -2003,8 +2030,8 @@ static std::string FormatFunctionParameter(ASTContext &Context,
Param->getType().getUnqualifiedType().getAsStringInternal(Result, Policy);
if (ObjCMethodParam) {
- Result = "(" + Result;
- Result += ")";
+ Result = "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier())
+ + Result + ")";
if (Param->getIdentifier())
Result += Param->getIdentifier()->getName();
}
@@ -2030,7 +2057,7 @@ static std::string FormatFunctionParameter(ASTContext &Context,
for (unsigned I = 0, N = Block->getNumArgs(); I != N; ++I) {
if (I)
Result += ", ";
- Result += FormatFunctionParameter(Context, Block->getArg(I));
+ Result += FormatFunctionParameter(Context, Policy, Block->getArg(I));
if (I == N - 1 && BlockProto->getTypePtr()->isVariadic())
Result += ", ...";
@@ -2046,6 +2073,7 @@ 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,
CodeCompletionBuilder &Result,
unsigned Start = 0,
@@ -2062,7 +2090,7 @@ static void AddFunctionParameterChunks(ASTContext &Context,
CodeCompletionBuilder Opt(Result.getAllocator());
if (!FirstParameter)
Opt.AddChunk(Chunk(CodeCompletionString::CK_Comma));
- AddFunctionParameterChunks(Context, Function, Opt, P, true);
+ AddFunctionParameterChunks(Context, Policy, Function, Opt, P, true);
Result.AddOptionalChunk(Opt.TakeString());
break;
}
@@ -2075,7 +2103,8 @@ static void AddFunctionParameterChunks(ASTContext &Context,
InOptional = false;
// Format the placeholder string.
- std::string PlaceholderStr = FormatFunctionParameter(Context, Param);
+ std::string PlaceholderStr = FormatFunctionParameter(Context, Policy,
+ Param);
if (Function->isVariadic() && P == N - 1)
PlaceholderStr += ", ...";
@@ -2097,14 +2126,12 @@ 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,
CodeCompletionBuilder &Result,
unsigned MaxParameters = 0,
unsigned Start = 0,
bool InDefaultArg = false) {
- PrintingPolicy Policy(Context.PrintingPolicy);
- Policy.AnonymousTagLocations = false;
-
typedef CodeCompletionString::Chunk Chunk;
bool FirstParameter = true;
@@ -2155,7 +2182,7 @@ static void AddTemplateParameterChunks(ASTContext &Context,
CodeCompletionBuilder Opt(Result.getAllocator());
if (!FirstParameter)
Opt.AddChunk(Chunk(CodeCompletionString::CK_Comma));
- AddTemplateParameterChunks(Context, Template, Opt, MaxParameters,
+ AddTemplateParameterChunks(Context, Policy, Template, Opt, MaxParameters,
P - Params->begin(), true);
Result.AddOptionalChunk(Opt.TakeString());
break;
@@ -2180,14 +2207,15 @@ static void
AddQualifierToCompletionString(CodeCompletionBuilder &Result,
NestedNameSpecifier *Qualifier,
bool QualifierIsInformative,
- ASTContext &Context) {
+ ASTContext &Context,
+ const PrintingPolicy &Policy) {
if (!Qualifier)
return;
std::string PrintedNNS;
{
llvm::raw_string_ostream OS(PrintedNNS);
- Qualifier->print(OS, Context.PrintingPolicy);
+ Qualifier->print(OS, Policy);
}
if (QualifierIsInformative)
Result.AddInformativeChunk(Result.getAllocator().CopyString(PrintedNNS));
@@ -2233,8 +2261,8 @@ AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result,
}
/// \brief Add the name of the given declaration
-static void AddTypedNameChunk(ASTContext &Context, NamedDecl *ND,
- CodeCompletionBuilder &Result) {
+static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy,
+ NamedDecl *ND, CodeCompletionBuilder &Result) {
typedef CodeCompletionString::Chunk Chunk;
DeclarationName Name = ND->getDeclName();
@@ -2299,7 +2327,7 @@ static void AddTypedNameChunk(ASTContext &Context, NamedDecl *ND,
Result.getAllocator().CopyString(Record->getNameAsString()));
if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) {
Result.AddChunk(Chunk(CodeCompletionString::CK_LeftAngle));
- AddTemplateParameterChunks(Context, Template, Result);
+ AddTemplateParameterChunks(Context, Policy, Template, Result);
Result.AddChunk(Chunk(CodeCompletionString::CK_RightAngle));
}
break;
@@ -2319,10 +2347,7 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
typedef CodeCompletionString::Chunk Chunk;
CodeCompletionBuilder Result(Allocator, Priority, Availability);
- PrintingPolicy Policy(S.Context.PrintingPolicy);
- Policy.AnonymousTagLocations = false;
- Policy.SuppressStrongLifetime = true;
-
+ PrintingPolicy Policy = getCompletionPrintingPolicy(S);
if (Kind == RK_Pattern) {
Pattern->Priority = Priority;
Pattern->Availability = Availability;
@@ -2346,19 +2371,24 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
// Format a function-like macro with placeholders for the arguments.
Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
- for (MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end();
- A != AEnd; ++A) {
+ bool CombineVariadicArgument = false;
+ MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end();
+ if (MI->isVariadic() && AEnd - A > 1) {
+ AEnd -= 2;
+ CombineVariadicArgument = true;
+ }
+ for (MacroInfo::arg_iterator A = MI->arg_begin(); A != AEnd; ++A) {
if (A != MI->arg_begin())
Result.AddChunk(Chunk(CodeCompletionString::CK_Comma));
- if (!MI->isVariadic() || A != AEnd - 1) {
+ if (!MI->isVariadic() || A + 1 != AEnd) {
// Non-variadic argument.
Result.AddPlaceholderChunk(
Result.getAllocator().CopyString((*A)->getName()));
continue;
}
- // Variadic argument; cope with the different between GNU and C99
+ // Variadic argument; cope with the difference between GNU and C99
// variadic macros, providing a single placeholder for the rest of the
// arguments.
if ((*A)->isStr("__VA_ARGS__"))
@@ -2369,6 +2399,18 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
Result.AddPlaceholderChunk(Result.getAllocator().CopyString(Arg));
}
}
+
+ if (CombineVariadicArgument) {
+ // Handle the next-to-last argument, combining it with the variadic
+ // argument.
+ std::string LastArg = (*A)->getName();
+ ++A;
+ if ((*A)->isStr("__VA_ARGS__"))
+ LastArg += ", ...";
+ else
+ LastArg += ", " + (*A)->getName().str() + "...";
+ Result.AddPlaceholderChunk(Result.getAllocator().CopyString(LastArg));
+ }
Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen));
return Result.TakeString();
}
@@ -2382,15 +2424,21 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
Result.AddTextChunk("::");
return Result.TakeString();
}
+
+ for (Decl::attr_iterator i = ND->attr_begin(); i != ND->attr_end(); ++i) {
+ if (AnnotateAttr *Attr = dyn_cast_or_null<AnnotateAttr>(*i)) {
+ Result.AddAnnotation(Result.getAllocator().CopyString(Attr->getAnnotation()));
+ }
+ }
- AddResultTypeChunk(S.Context, ND, Result);
+ AddResultTypeChunk(S.Context, Policy, ND, Result);
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
- S.Context);
- AddTypedNameChunk(S.Context, ND, Result);
+ S.Context, Policy);
+ AddTypedNameChunk(S.Context, Policy, ND, Result);
Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
- AddFunctionParameterChunks(S.Context, Function, Result);
+ AddFunctionParameterChunks(S.Context, Policy, Function, Result);
Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen));
AddFunctionTypeQualsToCompletionString(Result, Function);
return Result.TakeString();
@@ -2398,13 +2446,13 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
- S.Context);
+ S.Context, Policy);
FunctionDecl *Function = FunTmpl->getTemplatedDecl();
- AddTypedNameChunk(S.Context, Function, Result);
+ AddTypedNameChunk(S.Context, Policy, Function, Result);
// Figure out which template parameters are deduced (or have default
// arguments).
- llvm::SmallVector<bool, 16> Deduced;
+ SmallVector<bool, 16> Deduced;
S.MarkDeducedTemplateParameters(FunTmpl, Deduced);
unsigned LastDeducibleArgument;
for (LastDeducibleArgument = Deduced.size(); LastDeducibleArgument > 0;
@@ -2437,14 +2485,14 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
// function call, so we introduce an explicit template argument list
// containing all of the arguments up to the first deducible argument.
Result.AddChunk(Chunk(CodeCompletionString::CK_LeftAngle));
- AddTemplateParameterChunks(S.Context, FunTmpl, Result,
+ AddTemplateParameterChunks(S.Context, Policy, FunTmpl, Result,
LastDeducibleArgument);
Result.AddChunk(Chunk(CodeCompletionString::CK_RightAngle));
}
// Add the function parameters
Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
- AddFunctionParameterChunks(S.Context, Function, Result);
+ AddFunctionParameterChunks(S.Context, Policy, Function, Result);
Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen));
AddFunctionTypeQualsToCompletionString(Result, Function);
return Result.TakeString();
@@ -2452,11 +2500,11 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
if (TemplateDecl *Template = dyn_cast<TemplateDecl>(ND)) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
- S.Context);
+ S.Context, Policy);
Result.AddTypedTextChunk(
Result.getAllocator().CopyString(Template->getNameAsString()));
Result.AddChunk(Chunk(CodeCompletionString::CK_LeftAngle));
- AddTemplateParameterChunks(S.Context, Template, Result);
+ AddTemplateParameterChunks(S.Context, Policy, Template, Result);
Result.AddChunk(Chunk(CodeCompletionString::CK_RightAngle));
return Result.TakeString();
}
@@ -2490,7 +2538,7 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
if (Idx > StartParameter)
Result.AddChunk(CodeCompletionString::CK_HorizontalSpace);
if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Idx))
- Keyword += II->getName().str();
+ Keyword += II->getName();
Keyword += ":";
if (Idx < StartParameter || AllParametersAreInformative)
Result.AddInformativeChunk(Result.getAllocator().CopyString(Keyword));
@@ -2505,13 +2553,14 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
std::string Arg;
if ((*P)->getType()->isBlockPointerType() && !DeclaringEntity)
- Arg = FormatFunctionParameter(S.Context, *P, true);
+ Arg = FormatFunctionParameter(S.Context, Policy, *P, true);
else {
(*P)->getType().getAsStringInternal(Arg, Policy);
- Arg = "(" + Arg + ")";
+ Arg = "(" + formatObjCParamQualifiers((*P)->getObjCDeclQualifier())
+ + Arg + ")";
if (IdentifierInfo *II = (*P)->getIdentifier())
if (DeclaringEntity || AllParametersAreInformative)
- Arg += II->getName().str();
+ Arg += II->getName();
}
if (Method->isVariadic() && (P + 1) == PEnd)
@@ -2543,7 +2592,7 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
if (Qualifier)
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
- S.Context);
+ S.Context, Policy);
Result.AddTypedTextChunk(
Result.getAllocator().CopyString(ND->getNameAsString()));
@@ -2556,14 +2605,12 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
Sema &S,
CodeCompletionAllocator &Allocator) const {
typedef CodeCompletionString::Chunk Chunk;
- PrintingPolicy Policy(S.Context.PrintingPolicy);
- Policy.AnonymousTagLocations = false;
- Policy.SuppressStrongLifetime = true;
+ PrintingPolicy Policy = getCompletionPrintingPolicy(S);
// FIXME: Set priority, availability appropriately.
CodeCompletionBuilder Result(Allocator, 1, CXAvailability_Available);
FunctionDecl *FDecl = getFunction();
- AddResultTypeChunk(S.Context, FDecl, Result);
+ AddResultTypeChunk(S.Context, Policy, FDecl, Result);
const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(getFunctionType());
if (!FDecl && !Proto) {
@@ -2571,7 +2618,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
// highlighted ellipsis.
const FunctionType *FT = getFunctionType();
Result.AddTextChunk(GetCompletionTypeString(FT->getResultType(),
- S.Context,
+ S.Context, Policy,
Result.getAllocator()));
Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
Result.AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, "..."));
@@ -2624,7 +2671,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
return Result.TakeString();
}
-unsigned clang::getMacroUsagePriority(llvm::StringRef MacroName,
+unsigned clang::getMacroUsagePriority(StringRef MacroName,
const LangOptions &LangOpts,
bool PreferredTypeIsPointer) {
unsigned Priority = CCP_Macro;
@@ -2689,6 +2736,7 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) {
case Decl::TemplateTemplateParm:return CXCursor_TemplateTemplateParameter;
case Decl::FunctionTemplate: return CXCursor_FunctionTemplate;
case Decl::ClassTemplate: return CXCursor_ClassTemplate;
+ case Decl::AccessSpec: return CXCursor_CXXAccessSpecifier;
case Decl::ClassTemplatePartialSpecialization:
return CXCursor_ClassTemplatePartialSpecialization;
case Decl::UsingDirective: return CXCursor_UsingDirective;
@@ -2850,6 +2898,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,
return;
}
+ PrintingPolicy Policy = getCompletionPrintingPolicy(S);
for (CXXMethodDecl::method_iterator M = Method->begin_overridden_methods(),
MEnd = Method->end_overridden_methods();
M != MEnd; ++M) {
@@ -2866,7 +2915,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,
if (NNS) {
std::string Str;
llvm::raw_string_ostream OS(Str);
- NNS->print(OS, S.Context.PrintingPolicy);
+ NNS->print(OS, Policy);
Builder.AddTextChunk(Results.getAllocator().CopyString(OS.str()));
}
} else if (!InContext->Equals(Overridden->getDeclContext()))
@@ -3059,7 +3108,7 @@ struct Sema::CodeCompleteExpressionData {
QualType PreferredType;
bool IntegralConstantExpression;
bool ObjCCollection;
- llvm::SmallVector<Decl *, 4> IgnoreDecls;
+ SmallVector<Decl *, 4> IgnoreDecls;
};
/// \brief Perform code-completion in an expression context when we know what
@@ -3146,6 +3195,7 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
// Add nullary methods
if (AllowNullaryMethods) {
ASTContext &Context = Container->getASTContext();
+ PrintingPolicy Policy = getCompletionPrintingPolicy(Results.getSema());
for (ObjCContainerDecl::method_iterator M = Container->meth_begin(),
MEnd = Container->meth_end();
M != MEnd; ++M) {
@@ -3153,7 +3203,7 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
if (IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0))
if (AddedProperties.insert(Name)) {
CodeCompletionBuilder Builder(Results.getAllocator());
- AddResultTypeChunk(Context, *M, Builder);
+ AddResultTypeChunk(Context, Policy, *M, Builder);
Builder.AddTypedTextChunk(
Results.getAllocator().CopyString(Name->getName()));
@@ -3224,7 +3274,7 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
}
}
-void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
+void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *BaseE,
SourceLocation OpLoc,
bool IsArrow) {
if (!BaseE || !CodeCompleter)
@@ -3366,8 +3416,7 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
break;
default:
- assert(false && "Unknown type specifier kind in CodeCompleteTag");
- return;
+ llvm_unreachable("Unknown type specifier kind in CodeCompleteTag");
}
ResultBuilder Results(*this, CodeCompleter->getAllocator(), ContextKind);
@@ -3408,10 +3457,11 @@ void Sema::CodeCompleteTypeQualifiers(DeclSpec &DS) {
void Sema::CodeCompleteCase(Scope *S) {
if (getCurFunction()->SwitchStack.empty() || !CodeCompleter)
return;
-
+
SwitchStmt *Switch = getCurFunction()->SwitchStack.back();
- if (!Switch->getCond()->getType()->isEnumeralType()) {
- CodeCompleteExpressionData Data(Switch->getCond()->getType());
+ QualType type = Switch->getCond()->IgnoreImplicit()->getType();
+ if (!type->isEnumeralType()) {
+ CodeCompleteExpressionData Data(type);
Data.IntegralConstantExpression = true;
CodeCompleteExpression(S, Data);
return;
@@ -3419,7 +3469,7 @@ void Sema::CodeCompleteCase(Scope *S) {
// Code-complete the cases of a switch statement over an enumeration type
// by providing the list of
- EnumDecl *Enum = Switch->getCond()->getType()->getAs<EnumType>()->getDecl();
+ EnumDecl *Enum = type->castAs<EnumType>()->getDecl();
// Determine which enumerators we have already seen in the switch statement.
// FIXME: Ideally, we would also be able to look *past* the code-completion
@@ -3527,8 +3577,8 @@ static bool anyNullArguments(Expr **Args, unsigned NumArgs) {
return false;
}
-void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
- ExprTy **ArgsIn, unsigned NumArgs) {
+void Sema::CodeCompleteCall(Scope *S, Expr *FnIn,
+ Expr **ArgsIn, unsigned NumArgs) {
if (!CodeCompleter)
return;
@@ -3556,7 +3606,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
// FIXME: What if we're calling a member function?
typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate;
- llvm::SmallVector<ResultCandidate, 8> Results;
+ SmallVector<ResultCandidate, 8> Results;
Expr *NakedFn = Fn->IgnoreParenCasts();
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(NakedFn))
@@ -3662,7 +3712,62 @@ void Sema::CodeCompleteReturn(Scope *S) {
CodeCompleteExpression(S, ResultType);
}
-void Sema::CodeCompleteAssignmentRHS(Scope *S, ExprTy *LHS) {
+void Sema::CodeCompleteAfterIf(Scope *S) {
+ typedef CodeCompletionResult Result;
+ ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ mapCodeCompletionContext(*this, PCC_Statement));
+ Results.setFilter(&ResultBuilder::IsOrdinaryName);
+ Results.EnterNewScope();
+
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer,
+ CodeCompleter->includeGlobals());
+
+ AddOrdinaryNameResults(PCC_Statement, S, *this, Results);
+
+ // "else" block
+ CodeCompletionBuilder Builder(Results.getAllocator());
+ Builder.AddTypedTextChunk("else");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
+ Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Builder.AddPlaceholderChunk("statements");
+ Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Builder.AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Builder.TakeString());
+
+ // "else if" block
+ Builder.AddTypedTextChunk("else");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddTextChunk("if");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+ if (getLangOptions().CPlusPlus)
+ Builder.AddPlaceholderChunk("condition");
+ else
+ Builder.AddPlaceholderChunk("expression");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
+ Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Builder.AddPlaceholderChunk("statements");
+ Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Builder.AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Builder.TakeString());
+
+ Results.ExitScope();
+
+ if (S->getFnParent())
+ AddPrettyFunctionResults(PP.getLangOptions(), Results);
+
+ if (CodeCompleter->includeMacros())
+ AddMacroResults(PP, Results);
+
+ HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
+ Results.data(),Results.size());
+}
+
+void Sema::CodeCompleteAssignmentRHS(Scope *S, Expr *LHS) {
if (LHS)
CodeCompleteExpression(S, static_cast<Expr *>(LHS)->getType());
else
@@ -3706,7 +3811,7 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer);
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_Name,
+ Results.getCompletionContext(),
Results.data(),Results.size());
}
@@ -3848,10 +3953,7 @@ void Sema::CodeCompleteOperatorName(Scope *S) {
void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD,
CXXCtorInitializer** Initializers,
unsigned NumInitializers) {
- PrintingPolicy Policy(Context.PrintingPolicy);
- Policy.AnonymousTagLocations = false;
- Policy.SuppressStrongLifetime = true;
-
+ PrintingPolicy Policy = getCompletionPrintingPolicy(*this);
CXXConstructorDecl *Constructor
= static_cast<CXXConstructorDecl *>(ConstructorD);
if (!Constructor)
@@ -4045,15 +4147,14 @@ static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) {
Results.AddResult(Result(Builder.TakeString()));
}
-void Sema::CodeCompleteObjCAtDirective(Scope *S, Decl *ObjCImpDecl,
- bool InInterface) {
+void Sema::CodeCompleteObjCAtDirective(Scope *S) {
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
- if (ObjCImpDecl)
+ if (isa<ObjCImplDecl>(CurContext))
AddObjCImplementationResults(getLangOptions(), Results, false);
- else if (InInterface)
+ else if (CurContext->isObjCContainer())
AddObjCInterfaceResults(getLangOptions(), Results, false);
else
AddObjCTopLevelResults(Results, false);
@@ -4425,14 +4526,14 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
}
-void Sema::CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl) {
+void Sema::CodeCompleteObjCPropertyGetter(Scope *S) {
typedef CodeCompletionResult Result;
// Try to find the interface where getters might live.
- ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(ClassDecl);
+ ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurContext);
if (!Class) {
if (ObjCCategoryDecl *Category
- = dyn_cast_or_null<ObjCCategoryDecl>(ClassDecl))
+ = dyn_cast_or_null<ObjCCategoryDecl>(CurContext))
Class = Category->getClassInterface();
if (!Class)
@@ -4453,15 +4554,15 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl) {
Results.data(),Results.size());
}
-void Sema::CodeCompleteObjCPropertySetter(Scope *S, Decl *ObjCImplDecl) {
+void Sema::CodeCompleteObjCPropertySetter(Scope *S) {
typedef CodeCompletionResult Result;
// Try to find the interface where setters might live.
ObjCInterfaceDecl *Class
- = dyn_cast_or_null<ObjCInterfaceDecl>(ObjCImplDecl);
+ = dyn_cast_or_null<ObjCInterfaceDecl>(CurContext);
if (!Class) {
if (ObjCCategoryDecl *Category
- = dyn_cast_or_null<ObjCCategoryDecl>(ObjCImplDecl))
+ = dyn_cast_or_null<ObjCCategoryDecl>(CurContext))
Class = Category->getClassInterface();
if (!Class)
@@ -4694,7 +4795,8 @@ static ObjCMethodDecl *AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword,
CodeCompletionBuilder Builder(Results.getAllocator());
// Give this completion a return type.
- AddResultTypeChunk(S.Context, SuperMethod, Builder);
+ AddResultTypeChunk(S.Context, getCompletionPrintingPolicy(S), SuperMethod,
+ Builder);
// If we need the "super" keyword, add it (plus some spacing).
if (NeedSuperKeyword) {
@@ -4955,8 +5057,13 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
unsigned NumSelIdents,
bool AtArgumentExpression,
bool IsSuper) {
+
+ QualType T = this->GetTypeFromParser(Receiver);
+
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
- CodeCompletionContext::CCC_ObjCClassMessage);
+ CodeCompletionContext(CodeCompletionContext::CCC_ObjCClassMessage,
+ T, SelIdents, NumSelIdents));
+
AddClassMessageCompletions(*this, S, Receiver, SelIdents, NumSelIdents,
AtArgumentExpression, IsSuper, Results);
@@ -4967,7 +5074,7 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
// our preferred type, improving completion results.
if (AtArgumentExpression) {
QualType PreferredType = getPreferredArgumentTypeForMessageSend(Results,
- NumSelIdents);
+ NumSelIdents);
if (PreferredType.isNull())
CodeCompleteOrdinaryName(S, PCC_Expression);
else
@@ -4976,11 +5083,11 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
}
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_ObjCClassMessage,
+ Results.getCompletionContext(),
Results.data(), Results.size());
}
-void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
+void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
IdentifierInfo **SelIdents,
unsigned NumSelIdents,
bool AtArgumentExpression,
@@ -5019,7 +5126,9 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
// Build the set of methods we can see.
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
- CodeCompletionContext::CCC_ObjCInstanceMessage);
+ CodeCompletionContext(CodeCompletionContext::CCC_ObjCInstanceMessage,
+ ReceiverType, SelIdents, NumSelIdents));
+
Results.EnterNewScope();
// If this is a send-to-super, try to add the special "super" send
@@ -5132,7 +5241,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
}
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_ObjCInstanceMessage,
+ Results.getCompletionContext(),
Results.data(),Results.size());
}
@@ -5196,7 +5305,7 @@ void Sema::CodeCompleteObjCSelector(Scope *S, IdentifierInfo **SelIdents,
}
}
- Accumulator += Sel.getNameForSlot(I).str();
+ Accumulator += Sel.getNameForSlot(I);
Accumulator += ':';
}
Builder.AddTypedTextChunk(Builder.getAllocator().CopyString( Accumulator));
@@ -5303,12 +5412,11 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext,
// Record any forward-declared interfaces we find.
if (ObjCClassDecl *Forward = dyn_cast<ObjCClassDecl>(*D)) {
- for (ObjCClassDecl::iterator C = Forward->begin(), CEnd = Forward->end();
- C != CEnd; ++C)
- if ((!OnlyForwardDeclarations || C->getInterface()->isForwardDecl()) &&
- (!OnlyUnimplemented || !C->getInterface()->getImplementation()))
- Results.AddResult(Result(C->getInterface(), 0), CurContext,
- 0, false);
+ ObjCInterfaceDecl *IDecl = Forward->getForwardInterfaceDecl();
+ if ((!OnlyForwardDeclarations || IDecl->isForwardDecl()) &&
+ (!OnlyUnimplemented || !IDecl->getImplementation()))
+ Results.AddResult(Result(IDecl, 0), CurContext,
+ 0, false);
}
}
}
@@ -5318,21 +5426,23 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) {
CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
- // Add all classes.
- AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, true,
- false, Results);
-
+ if (CodeCompleter->includeGlobals()) {
+ // Add all classes.
+ AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false,
+ false, Results);
+ }
+
Results.ExitScope();
- // FIXME: Use cached global completion results.
+
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_Other,
+ CodeCompletionContext::CCC_ObjCInterfaceName,
Results.data(),Results.size());
}
void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName,
SourceLocation ClassNameLoc) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
- CodeCompletionContext::CCC_ObjCSuperclass);
+ CodeCompletionContext::CCC_ObjCInterfaceName);
Results.EnterNewScope();
// Make sure that we ignore the class we're currently defining.
@@ -5341,14 +5451,16 @@ void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName,
if (CurClass && isa<ObjCInterfaceDecl>(CurClass))
Results.Ignore(CurClass);
- // Add all classes.
- AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false,
- false, Results);
-
+ if (CodeCompleter->includeGlobals()) {
+ // Add all classes.
+ AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false,
+ false, Results);
+ }
+
Results.ExitScope();
- // FIXME: Use cached global completion results.
+
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_ObjCSuperclass,
+ CodeCompletionContext::CCC_ObjCInterfaceName,
Results.data(),Results.size());
}
@@ -5357,14 +5469,16 @@ void Sema::CodeCompleteObjCImplementationDecl(Scope *S) {
CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
- // Add all unimplemented classes.
- AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false,
- true, Results);
-
+ if (CodeCompleter->includeGlobals()) {
+ // Add all unimplemented classes.
+ AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false,
+ true, Results);
+ }
+
Results.ExitScope();
- // FIXME: Use cached global completion results.
+
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_Other,
+ CodeCompletionContext::CCC_ObjCInterfaceName,
Results.data(),Results.size());
}
@@ -5442,14 +5556,14 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
Results.data(),Results.size());
}
-void Sema::CodeCompleteObjCPropertyDefinition(Scope *S, Decl *ObjCImpDecl) {
+void Sema::CodeCompleteObjCPropertyDefinition(Scope *S) {
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompletionContext::CCC_Other);
// Figure out where this @synthesize lives.
ObjCContainerDecl *Container
- = dyn_cast_or_null<ObjCContainerDecl>(ObjCImpDecl);
+ = dyn_cast_or_null<ObjCContainerDecl>(CurContext);
if (!Container ||
(!isa<ObjCImplementationDecl>(Container) &&
!isa<ObjCCategoryImplDecl>(Container)))
@@ -5482,15 +5596,14 @@ void Sema::CodeCompleteObjCPropertyDefinition(Scope *S, Decl *ObjCImpDecl) {
}
void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
- IdentifierInfo *PropertyName,
- Decl *ObjCImpDecl) {
+ IdentifierInfo *PropertyName) {
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompletionContext::CCC_Other);
// Figure out where this @synthesize lives.
ObjCContainerDecl *Container
- = dyn_cast_or_null<ObjCContainerDecl>(ObjCImpDecl);
+ = dyn_cast_or_null<ObjCContainerDecl>(CurContext);
if (!Container ||
(!isa<ObjCImplementationDecl>(Container) &&
!isa<ObjCCategoryImplDecl>(Container)))
@@ -5523,7 +5636,7 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
bool SawSimilarlyNamedIvar = false;
std::string NameWithPrefix;
NameWithPrefix += '_';
- NameWithPrefix += PropertyName->getName().str();
+ NameWithPrefix += PropertyName->getName();
std::string NameWithSuffix = PropertyName->getName().str();
NameWithSuffix += '_';
for(; Class; Class = Class->getSuperClass()) {
@@ -5557,8 +5670,9 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
CodeCompletionAllocator &Allocator = Results.getAllocator();
CodeCompletionBuilder Builder(Allocator, Priority,CXAvailability_Available);
+ PrintingPolicy Policy = getCompletionPrintingPolicy(*this);
Builder.AddResultTypeChunk(GetCompletionTypeString(PropertyType, Context,
- Allocator));
+ Policy, Allocator));
Builder.AddTypedTextChunk(Allocator.CopyString(NameWithPrefix));
Results.AddResult(Result(Builder.TakeString(), Priority,
CXCursor_ObjCIvarDecl));
@@ -5658,9 +5772,10 @@ static void FindImplementableMethods(ASTContext &Context,
/// completion string.
static void AddObjCPassingTypeChunk(QualType Type,
ASTContext &Context,
+ const PrintingPolicy &Policy,
CodeCompletionBuilder &Builder) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
- Builder.AddTextChunk(GetCompletionTypeString(Type, Context,
+ Builder.AddTextChunk(GetCompletionTypeString(Type, Context, Policy,
Builder.getAllocator()));
Builder.AddChunk(CodeCompletionString::CK_RightParen);
}
@@ -5668,7 +5783,7 @@ static void AddObjCPassingTypeChunk(QualType Type,
/// \brief Determine whether the given class is or inherits from a class by
/// the given name.
static bool InheritsFromClassNamed(ObjCInterfaceDecl *Class,
- llvm::StringRef Name) {
+ StringRef Name) {
if (!Class)
return false;
@@ -5690,7 +5805,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
if (!PropName || PropName->getLength() == 0)
return;
-
+ PrintingPolicy Policy = getCompletionPrintingPolicy(Results.getSema());
+
// Builder that will create each code completion.
typedef CodeCompletionResult Result;
CodeCompletionAllocator &Allocator = Results.getAllocator();
@@ -5703,10 +5819,10 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// on demand.
struct KeyHolder {
CodeCompletionAllocator &Allocator;
- llvm::StringRef Key;
+ StringRef Key;
const char *CopiedKey;
- KeyHolder(CodeCompletionAllocator &Allocator, llvm::StringRef Key)
+ KeyHolder(CodeCompletionAllocator &Allocator, StringRef Key)
: Allocator(Allocator), Key(Key), CopiedKey(0) { }
operator const char *() {
@@ -5733,7 +5849,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
KnownSelectors.insert(Selectors.getNullarySelector(PropName)) &&
ReturnTypeMatchesProperty && !Property->getGetterMethodDecl()) {
if (ReturnType.isNull())
- AddObjCPassingTypeChunk(Property->getType(), Context, Builder);
+ AddObjCPassingTypeChunk(Property->getType(), Context, Policy, Builder);
Builder.AddTypedTextChunk(Key);
Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern,
@@ -5748,7 +5864,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
(ReturnType.isNull() &&
(Property->getType()->isIntegerType() ||
Property->getType()->isBooleanType())))) {
- std::string SelectorName = (llvm::Twine("is") + UpperKey).str();
+ std::string SelectorName = (Twine("is") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
if (ReturnType.isNull()) {
@@ -5767,7 +5883,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// Add the normal mutator.
if (IsInstanceMethod && ReturnTypeMatchesVoid &&
!Property->getSetterMethodDecl()) {
- std::string SelectorName = (llvm::Twine("set") + UpperKey).str();
+ std::string SelectorName = (Twine("set") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
@@ -5779,7 +5895,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
Builder.AddTypedTextChunk(
Allocator.CopyString(SelectorId->getName()));
Builder.AddTypedTextChunk(":");
- AddObjCPassingTypeChunk(Property->getType(), Context, Builder);
+ AddObjCPassingTypeChunk(Property->getType(), Context, Policy, Builder);
Builder.AddTextChunk(Key);
Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern,
CXCursor_ObjCInstanceMethodDecl));
@@ -5818,7 +5934,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// Add -(NSUInteger)countOf<key>
if (IsInstanceMethod &&
(ReturnType.isNull() || ReturnType->isIntegerType())) {
- std::string SelectorName = (llvm::Twine("countOf") + UpperKey).str();
+ std::string SelectorName = (Twine("countOf") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
if (ReturnType.isNull()) {
@@ -5841,7 +5957,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
if (IsInstanceMethod &&
(ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) {
std::string SelectorName
- = (llvm::Twine("objectIn") + UpperKey + "AtIndex").str();
+ = (Twine("objectIn") + UpperKey + "AtIndex").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
@@ -5868,7 +5984,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl()
->getName() == "NSArray"))) {
std::string SelectorName
- = (llvm::Twine(Property->getName()) + "AtIndexes").str();
+ = (Twine(Property->getName()) + "AtIndexes").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
@@ -5889,7 +6005,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// Add -(void)getKey:(type **)buffer range:(NSRange)inRange
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
- std::string SelectorName = (llvm::Twine("get") + UpperKey).str();
+ std::string SelectorName = (Twine("get") + UpperKey).str();
IdentifierInfo *SelectorIds[2] = {
&Context.Idents.get(SelectorName),
&Context.Idents.get("range")
@@ -5923,7 +6039,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// - (void)insertObject:(type *)object inKeyAtIndex:(NSUInteger)index
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
- std::string SelectorName = (llvm::Twine("in") + UpperKey + "AtIndex").str();
+ std::string SelectorName = (Twine("in") + UpperKey + "AtIndex").str();
IdentifierInfo *SelectorIds[2] = {
&Context.Idents.get("insertObject"),
&Context.Idents.get(SelectorName)
@@ -5955,7 +6071,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// - (void)insertKey:(NSArray *)array atIndexes:(NSIndexSet *)indexes
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
- std::string SelectorName = (llvm::Twine("insert") + UpperKey).str();
+ std::string SelectorName = (Twine("insert") + UpperKey).str();
IdentifierInfo *SelectorIds[2] = {
&Context.Idents.get(SelectorName),
&Context.Idents.get("atIndexes")
@@ -5987,7 +6103,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// -(void)removeObjectFromKeyAtIndex:(NSUInteger)index
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
std::string SelectorName
- = (llvm::Twine("removeObjectFrom") + UpperKey + "AtIndex").str();
+ = (Twine("removeObjectFrom") + UpperKey + "AtIndex").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
@@ -6009,7 +6125,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// -(void)removeKeyAtIndexes:(NSIndexSet *)indexes
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
std::string SelectorName
- = (llvm::Twine("remove") + UpperKey + "AtIndexes").str();
+ = (Twine("remove") + UpperKey + "AtIndexes").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
@@ -6031,7 +6147,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// - (void)replaceObjectInKeyAtIndex:(NSUInteger)index withObject:(id)object
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
std::string SelectorName
- = (llvm::Twine("replaceObjectIn") + UpperKey + "AtIndex").str();
+ = (Twine("replaceObjectIn") + UpperKey + "AtIndex").str();
IdentifierInfo *SelectorIds[2] = {
&Context.Idents.get(SelectorName),
&Context.Idents.get("withObject")
@@ -6063,8 +6179,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// - (void)replaceKeyAtIndexes:(NSIndexSet *)indexes withKey:(NSArray *)array
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
std::string SelectorName1
- = (llvm::Twine("replace") + UpperKey + "AtIndexes").str();
- std::string SelectorName2 = (llvm::Twine("with") + UpperKey).str();
+ = (Twine("replace") + UpperKey + "AtIndexes").str();
+ std::string SelectorName2 = (Twine("with") + UpperKey).str();
IdentifierInfo *SelectorIds[2] = {
&Context.Idents.get(SelectorName1),
&Context.Idents.get(SelectorName2)
@@ -6101,7 +6217,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() &&
ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl()
->getName() == "NSEnumerator"))) {
- std::string SelectorName = (llvm::Twine("enumeratorOf") + UpperKey).str();
+ std::string SelectorName = (Twine("enumeratorOf") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
if (ReturnType.isNull()) {
@@ -6119,7 +6235,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// - (type *)memberOfKey:(type *)object
if (IsInstanceMethod &&
(ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) {
- std::string SelectorName = (llvm::Twine("memberOf") + UpperKey).str();
+ std::string SelectorName = (Twine("memberOf") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
@@ -6136,6 +6252,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
Builder.AddTextChunk(" *");
} else {
Builder.AddTextChunk(GetCompletionTypeString(ReturnType, Context,
+ Policy,
Builder.getAllocator()));
}
Builder.AddChunk(CodeCompletionString::CK_RightParen);
@@ -6149,7 +6266,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// - (void)addKeyObject:(type *)object
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
std::string SelectorName
- = (llvm::Twine("add") + UpperKey + llvm::Twine("Object")).str();
+ = (Twine("add") + UpperKey + Twine("Object")).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
@@ -6171,7 +6288,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// - (void)addKey:(NSSet *)objects
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
- std::string SelectorName = (llvm::Twine("add") + UpperKey).str();
+ std::string SelectorName = (Twine("add") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
@@ -6193,7 +6310,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// - (void)removeKeyObject:(type *)object
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
std::string SelectorName
- = (llvm::Twine("remove") + UpperKey + llvm::Twine("Object")).str();
+ = (Twine("remove") + UpperKey + Twine("Object")).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
@@ -6215,7 +6332,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// - (void)removeKey:(NSSet *)objects
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
- std::string SelectorName = (llvm::Twine("remove") + UpperKey).str();
+ std::string SelectorName = (Twine("remove") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
@@ -6236,7 +6353,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// - (void)intersectKey:(NSSet *)objects
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
- std::string SelectorName = (llvm::Twine("intersect") + UpperKey).str();
+ std::string SelectorName = (Twine("intersect") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
@@ -6264,7 +6381,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl()
->getName() == "NSSet"))) {
std::string SelectorName
- = (llvm::Twine("keyPathsForValuesAffecting") + UpperKey).str();
+ = (Twine("keyPathsForValuesAffecting") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
if (ReturnType.isNull()) {
@@ -6285,7 +6402,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
ReturnType->isIntegerType() ||
ReturnType->isBooleanType())) {
std::string SelectorName
- = (llvm::Twine("automaticallyNotifiesObserversOf") + UpperKey).str();
+ = (Twine("automaticallyNotifiesObserversOf") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
if (ReturnType.isNull()) {
@@ -6303,12 +6420,15 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
void Sema::CodeCompleteObjCMethodDecl(Scope *S,
bool IsInstanceMethod,
- ParsedType ReturnTy,
- Decl *IDecl) {
+ ParsedType ReturnTy) {
// Determine the return type of the method we're declaring, if
// provided.
QualType ReturnType = GetTypeFromParser(ReturnTy);
-
+ Decl *IDecl = 0;
+ if (CurContext->isObjCContainer()) {
+ ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(CurContext);
+ IDecl = cast<Decl>(OCD);
+ }
// Determine where we should start searching for methods.
ObjCContainerDecl *SearchDecl = 0;
bool IsInImplementation = false;
@@ -6346,9 +6466,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
- PrintingPolicy Policy(Context.PrintingPolicy);
- Policy.AnonymousTagLocations = false;
- Policy.SuppressStrongLifetime = true;
+ PrintingPolicy Policy = getCompletionPrintingPolicy(*this);
for (KnownMethodsMap::iterator M = KnownMethods.begin(),
MEnd = KnownMethods.end();
M != MEnd; ++M) {
@@ -6358,7 +6476,8 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
// If the result type was not already provided, add it to the
// pattern as (type).
if (ReturnType.isNull())
- AddObjCPassingTypeChunk(Method->getResultType(), Context, Builder);
+ AddObjCPassingTypeChunk(Method->getResultType(), Context, Policy,
+ Builder);
Selector Sel = Method->getSelector();
@@ -6382,7 +6501,8 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
break;
// Add the parameter type.
- AddObjCPassingTypeChunk((*P)->getOriginalType(), Context, Builder);
+ AddObjCPassingTypeChunk((*P)->getOriginalType(), Context, Policy,
+ Builder);
if (IdentifierInfo *Id = (*P)->getIdentifier())
Builder.AddTextChunk(Builder.getAllocator().CopyString( Id->getName()));
@@ -6425,7 +6545,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
// Add Key-Value-Coding and Key-Value-Observing accessor methods for all of
// the properties in this class and its categories.
if (Context.getLangOptions().ObjC2) {
- llvm::SmallVector<ObjCContainerDecl *, 4> Containers;
+ SmallVector<ObjCContainerDecl *, 4> Containers;
Containers.push_back(SearchDecl);
VisitedSelectorSet KnownSelectors;
@@ -6748,9 +6868,8 @@ void Sema::CodeCompletePreprocessorMacroArgument(Scope *S,
// FIXME: In the future, we could provide "overload" results, much like we
// do for function calls.
- CodeCompleteOrdinaryName(S,
- S->getFnParent()? Sema::PCC_RecoveryInFunction
- : Sema::PCC_Namespace);
+ // Now just ignore this. There will be another code-completion callback
+ // for the expanded tokens.
}
void Sema::CodeCompleteNaturalLanguage() {
@@ -6760,7 +6879,7 @@ void Sema::CodeCompleteNaturalLanguage() {
}
void Sema::GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator,
- llvm::SmallVectorImpl<CodeCompletionResult> &Results) {
+ SmallVectorImpl<CodeCompletionResult> &Results) {
ResultBuilder Builder(*this, Allocator, CodeCompletionContext::CCC_Recovery);
if (!CodeCompleter || CodeCompleter->includeGlobals()) {
CodeCompletionDeclConsumer Consumer(Builder,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 9d91a48bdcd7..8d993ef61032 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -33,11 +33,13 @@
#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 "llvm/ADT/Triple.h"
#include <algorithm>
#include <cstring>
@@ -69,7 +71,8 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
Scope *S, CXXScopeSpec *SS,
bool isClassName, bool HasTrailingDot,
ParsedType ObjectTypePtr,
- bool WantNontrivialTypeSourceInfo) {
+ bool WantNontrivialTypeSourceInfo,
+ IdentifierInfo **CorrectedII) {
// Determine where we will perform name lookup.
DeclContext *LookupCtx = 0;
if (ObjectTypePtr) {
@@ -144,6 +147,51 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
switch (Result.getResultKind()) {
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
+ if (CorrectedII) {
+ TypoCorrection Correction = CorrectTypo(Result.getLookupNameInfo(),
+ Kind, S, SS, 0, false,
+ Sema::CTC_Type);
+ IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo();
+ TemplateTy Template;
+ bool MemberOfUnknownSpecialization;
+ UnqualifiedId TemplateName;
+ TemplateName.setIdentifier(NewII, NameLoc);
+ NestedNameSpecifier *NNS = Correction.getCorrectionSpecifier();
+ CXXScopeSpec NewSS, *NewSSPtr = SS;
+ if (SS && NNS) {
+ NewSS.MakeTrivial(Context, NNS, SourceRange(NameLoc));
+ NewSSPtr = &NewSS;
+ }
+ if (Correction && (NNS || NewII != &II) &&
+ // Ignore a correction to a template type as the to-be-corrected
+ // identifier is not a template (typo correction for template names
+ // is handled elsewhere).
+ !(getLangOptions().CPlusPlus && NewSSPtr &&
+ isTemplateName(S, *NewSSPtr, false, TemplateName, ParsedType(),
+ false, Template, MemberOfUnknownSpecialization))) {
+ ParsedType Ty = getTypeName(*NewII, NameLoc, S, NewSSPtr,
+ isClassName, HasTrailingDot, ObjectTypePtr,
+ WantNontrivialTypeSourceInfo);
+ if (Ty) {
+ std::string CorrectedStr(Correction.getAsString(getLangOptions()));
+ std::string CorrectedQuotedStr(
+ Correction.getQuoted(getLangOptions()));
+ Diag(NameLoc, diag::err_unknown_typename_suggest)
+ << Result.getLookupName() << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(SourceRange(NameLoc),
+ CorrectedStr);
+ if (NamedDecl *FirstDecl = Correction.getCorrectionDecl())
+ Diag(FirstDecl->getLocation(), diag::note_previous_decl)
+ << CorrectedQuotedStr;
+
+ if (SS && NNS)
+ SS->MakeTrivial(Context, NNS, SourceRange(NameLoc));
+ *CorrectedII = NewII;
+ return Ty;
+ }
+ }
+ }
+ // If typo correction failed or was not performed, fall through
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue:
Result.suppressDiagnostics();
@@ -269,7 +317,7 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
/// A<T>::TYPE a; // no typename required because A<T> is a base class.
/// };
/// @endcode
-bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS) {
+bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) {
if (CurContext->isRecord()) {
const Type *Ty = SS->getScopeRep()->getAsType();
@@ -278,8 +326,9 @@ bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS) {
BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base)
if (Context.hasSameUnqualifiedType(QualType(Ty, 1), Base->getType()))
return true;
+ return S->isFunctionPrototypeScope();
}
- return false;
+ return CurContext->isFunctionOrMethod() || S->isFunctionPrototypeScope();
}
bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
@@ -361,7 +410,7 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
<< &II << DC << SS->getRange();
else if (isDependentScopeSpecifier(*SS)) {
unsigned DiagID = diag::err_typename_missing;
- if (getLangOptions().Microsoft && isMicrosoftMissingTypename(SS))
+ if (getLangOptions().MicrosoftMode && isMicrosoftMissingTypename(SS, S))
DiagID = diag::warn_typename_missing;
Diag(SS->getRange().getBegin(), DiagID)
@@ -419,24 +468,6 @@ Sema::NameClassification Sema::ClassifyName(Scope *S,
ExprResult E = LookupInObjCMethod(Result, S, Name, true);
if (E.get() || E.isInvalid())
return E;
-
- // Synthesize ivars lazily.
- if (getLangOptions().ObjCDefaultSynthProperties &&
- getLangOptions().ObjCNonFragileABI2) {
- if (SynthesizeProvisionalIvar(Result, Name, NameLoc)) {
- if (const ObjCPropertyDecl *Property =
- canSynthesizeProvisionalIvar(Name)) {
- Diag(NameLoc, diag::warn_synthesized_ivar_access) << Name;
- Diag(Property->getLocation(), diag::note_property_declare);
- }
-
- // FIXME: This is strange. Shouldn't we just take the ivar returned
- // from SynthesizeProvisionalIvar and continue with that?
- E = LookupInObjCMethod(Result, S, Name, true);
- if (E.get() || E.isInvalid())
- return E;
- }
- }
}
bool SecondTry = false;
@@ -737,11 +768,6 @@ DeclContext *Sema::getContainingDC(DeclContext *DC) {
return DC;
}
- // ObjCMethodDecls are parsed (for some reason) outside the context
- // of the class.
- if (isa<ObjCMethodDecl>(DC))
- return DC->getLexicalParent()->getLexicalParent();
-
return DC->getLexicalParent();
}
@@ -804,6 +830,29 @@ void Sema::ExitDeclaratorContext(Scope *S) {
// disappear.
}
+
+void Sema::ActOnReenterFunctionContext(Scope* S, Decl *D) {
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ if (FunctionTemplateDecl *TFD = dyn_cast_or_null<FunctionTemplateDecl>(D)) {
+ // We assume that the caller has already called
+ // ActOnReenterTemplateScope
+ FD = TFD->getTemplatedDecl();
+ }
+ if (!FD)
+ return;
+
+ PushDeclContext(S, FD);
+ for (unsigned P = 0, NumParams = FD->getNumParams(); P < NumParams; ++P) {
+ ParmVarDecl *Param = FD->getParamDecl(P);
+ // If the parameter has an identifier, then add it to the scope
+ if (Param->getIdentifier()) {
+ S->AddDecl(Param);
+ IdResolver.AddDecl(Param);
+ }
+ }
+}
+
+
/// \brief Determine whether we allow overloading of the function
/// PrevDecl with another declaration.
///
@@ -843,7 +892,9 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) {
// Out-of-line definitions shouldn't be pushed into scope in C++.
// Out-of-line variable and function definitions shouldn't even in C.
if ((getLangOptions().CPlusPlus || isa<VarDecl>(D) || isa<FunctionDecl>(D)) &&
- D->isOutOfLine())
+ D->isOutOfLine() &&
+ !D->getDeclContext()->getRedeclContext()->Equals(
+ D->getLexicalDeclContext()->getRedeclContext()))
return;
// Template instantiations should also not be pushed into scope.
@@ -1086,12 +1137,28 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return true;
}
+static void GenerateFixForUnusedDecl(const NamedDecl *D, ASTContext &Ctx,
+ FixItHint &Hint) {
+ if (isa<LabelDecl>(D)) {
+ SourceLocation AfterColon = Lexer::findLocationAfterToken(D->getLocEnd(),
+ tok::colon, Ctx.getSourceManager(), Ctx.getLangOptions(), true);
+ if (AfterColon.isInvalid())
+ return;
+ Hint = FixItHint::CreateRemoval(CharSourceRange::
+ getCharRange(D->getLocStart(), AfterColon));
+ }
+ return;
+}
+
/// DiagnoseUnusedDecl - Emit warnings about declarations that are not used
/// unless they are marked attr(unused).
void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
+ FixItHint Hint;
if (!ShouldDiagnoseUnusedDecl(D))
return;
+ GenerateFixForUnusedDecl(D, Context, Hint);
+
unsigned DiagID;
if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable())
DiagID = diag::warn_unused_exception_param;
@@ -1100,7 +1167,7 @@ void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
else
DiagID = diag::warn_unused_variable;
- Diag(D->getLocation(), DiagID) << D->getDeclName();
+ Diag(D->getLocation(), DiagID) << D->getDeclName() << Hint;
}
static void CheckPoppedLabel(LabelDecl *L, Sema &S) {
@@ -1246,7 +1313,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
<< R;
if (Context.BuiltinInfo.getHeaderName(BID) &&
Diags.getDiagnosticLevel(diag::ext_implicit_lib_function_decl, Loc)
- != Diagnostic::Ignored)
+ != DiagnosticsEngine::Ignored)
Diag(Loc, diag::note_please_include_header)
<< Context.BuiltinInfo.getHeaderName(BID)
<< Context.BuiltinInfo.GetName(BID);
@@ -1263,7 +1330,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
// Create Decl objects for each parameter, adding them to the
// FunctionDecl.
if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(R)) {
- llvm::SmallVector<ParmVarDecl*, 16> Params;
+ SmallVector<ParmVarDecl*, 16> Params;
for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) {
ParmVarDecl *parm =
ParmVarDecl::Create(Context, New, SourceLocation(),
@@ -1273,7 +1340,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
parm->setScopeInfo(0, i);
Params.push_back(parm);
}
- New->setParams(Params.data(), Params.size());
+ New->setParams(Params);
}
AddKnownFunctionAttributes(New);
@@ -1308,29 +1375,24 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
case 2:
if (!TypeID->isStr("id"))
break;
- Context.ObjCIdRedefinitionType = New->getUnderlyingType();
+ Context.setObjCIdRedefinitionType(New->getUnderlyingType());
// Install the built-in type for 'id', ignoring the current definition.
New->setTypeForDecl(Context.getObjCIdType().getTypePtr());
return;
case 5:
if (!TypeID->isStr("Class"))
break;
- Context.ObjCClassRedefinitionType = New->getUnderlyingType();
+ Context.setObjCClassRedefinitionType(New->getUnderlyingType());
// Install the built-in type for 'Class', ignoring the current definition.
New->setTypeForDecl(Context.getObjCClassType().getTypePtr());
return;
case 3:
if (!TypeID->isStr("SEL"))
break;
- Context.ObjCSelRedefinitionType = New->getUnderlyingType();
+ Context.setObjCSelRedefinitionType(New->getUnderlyingType());
// Install the built-in type for 'SEL', ignoring the current definition.
New->setTypeForDecl(Context.getObjCSelType().getTypePtr());
return;
- case 8:
- if (!TypeID->isStr("Protocol"))
- break;
- Context.setObjCProtoType(New->getUnderlyingType());
- return;
}
// Fall through - the typedef name was not a builtin type.
}
@@ -1382,7 +1444,13 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Old))
New->setPreviousDeclaration(Typedef);
- if (getLangOptions().Microsoft)
+ // __module_private__ is propagated to later declarations.
+ if (Old->isModulePrivate())
+ New->setModulePrivate();
+ else if (New->isModulePrivate())
+ diagnoseModulePrivateRedeclaration(New, Old);
+
+ if (getLangOptions().MicrosoftExt)
return;
if (getLangOptions().CPlusPlus) {
@@ -1443,8 +1511,14 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
static bool
DeclHasAttr(const Decl *D, const Attr *A) {
const OwnershipAttr *OA = dyn_cast<OwnershipAttr>(A);
+ const AnnotateAttr *Ann = dyn_cast<AnnotateAttr>(A);
for (Decl::attr_iterator i = D->attr_begin(), e = D->attr_end(); i != e; ++i)
if ((*i)->getKind() == A->getKind()) {
+ if (Ann) {
+ if (Ann->getAnnotation() == cast<AnnotateAttr>(*i)->getAnnotation())
+ return true;
+ continue;
+ }
// FIXME: Don't hardcode this check
if (OA && isa<OwnershipAttr>(*i))
return OA->getOwnKind() == cast<OwnershipAttr>(*i)->getOwnKind();
@@ -1456,7 +1530,7 @@ DeclHasAttr(const Decl *D, const Attr *A) {
/// mergeDeclAttributes - Copy attributes from the Old decl to the New one.
static void mergeDeclAttributes(Decl *newDecl, const Decl *oldDecl,
- ASTContext &C) {
+ ASTContext &C, bool mergeDeprecation = true) {
if (!oldDecl->hasAttrs())
return;
@@ -1469,6 +1543,13 @@ static void mergeDeclAttributes(Decl *newDecl, const Decl *oldDecl,
for (specific_attr_iterator<InheritableAttr>
i = oldDecl->specific_attr_begin<InheritableAttr>(),
e = oldDecl->specific_attr_end<InheritableAttr>(); i != e; ++i) {
+ // Ignore deprecated/unavailable/availability attributes if requested.
+ if (!mergeDeprecation &&
+ (isa<DeprecatedAttr>(*i) ||
+ isa<UnavailableAttr>(*i) ||
+ isa<AvailabilityAttr>(*i)))
+ continue;
+
if (!DeclHasAttr(newDecl, *i)) {
InheritableAttr *newAttr = cast<InheritableAttr>((*i)->clone(C));
newAttr->setInherited(true);
@@ -1535,6 +1616,8 @@ Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) {
return Sema::CXXDestructor;
} else if (MD->isCopyAssignmentOperator()) {
return Sema::CXXCopyAssignment;
+ } else if (MD->isMoveAssignmentOperator()) {
+ return Sema::CXXMoveAssignment;
}
return Sema::CXXInvalid;
@@ -1605,7 +1688,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
New->getStorageClass() == SC_Static &&
Old->getStorageClass() != SC_Static &&
!canRedefineFunction(Old, getLangOptions())) {
- if (getLangOptions().Microsoft) {
+ if (getLangOptions().MicrosoftExt) {
Diag(New->getLocation(), diag::warn_static_non_static) << New;
Diag(Old->getLocation(), PrevDiag);
} else {
@@ -1669,6 +1752,18 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
RequiresAdjustment = true;
}
+ // Merge ns_returns_retained attribute.
+ if (OldTypeInfo.getProducesResult() != NewTypeInfo.getProducesResult()) {
+ if (NewTypeInfo.getProducesResult()) {
+ Diag(New->getLocation(), diag::err_returns_retained_mismatch);
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ return true;
+ }
+
+ NewTypeInfo = NewTypeInfo.withProducesResult(true);
+ RequiresAdjustment = true;
+ }
+
if (RequiresAdjustment) {
NewType = Context.adjustFunctionType(NewType, NewTypeInfo);
New->setType(QualType(NewType, 0));
@@ -1706,9 +1801,16 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
// Preserve triviality.
NewMethod->setTrivial(OldMethod->isTrivial());
+ // MSVC allows explicit template specialization at class scope:
+ // 2 CXMethodDecls referring to the same function will be injected.
+ // We don't want a redeclartion error.
+ bool IsClassScopeExplicitSpecialization =
+ OldMethod->isFunctionTemplateSpecialization() &&
+ NewMethod->isFunctionTemplateSpecialization();
bool isFriend = NewMethod->getFriendObjectKind();
- if (!isFriend && NewMethod->getLexicalDeclContext()->isRecord()) {
+ if (!isFriend && NewMethod->getLexicalDeclContext()->isRecord() &&
+ !IsClassScopeExplicitSpecialization) {
// -- Member function declarations with the same name and the
// same parameter types cannot be overloaded if any of them
// is a static member function declaration.
@@ -1790,7 +1892,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
// The old declaration provided a function prototype, but the
// new declaration does not. Merge in the prototype.
assert(!OldProto->hasExceptionSpec() && "Exception spec in C");
- llvm::SmallVector<QualType, 16> ParamTypes(OldProto->arg_type_begin(),
+ SmallVector<QualType, 16> ParamTypes(OldProto->arg_type_begin(),
OldProto->arg_type_end());
NewQType = Context.getFunctionType(NewFuncType->getResultType(),
ParamTypes.data(), ParamTypes.size(),
@@ -1799,7 +1901,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
New->setHasInheritedPrototype();
// Synthesize a parameter for each argument type.
- llvm::SmallVector<ParmVarDecl*, 16> Params;
+ SmallVector<ParmVarDecl*, 16> Params;
for (FunctionProtoType::arg_type_iterator
ParamType = OldProto->arg_type_begin(),
ParamEnd = OldProto->arg_type_end();
@@ -1815,7 +1917,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
Params.push_back(Param);
}
- New->setParams(Params.data(), Params.size());
+ New->setParams(Params);
}
return MergeCompatibleFunctionDecls(New, Old);
@@ -1836,8 +1938,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
Old->hasPrototype() && !New->hasPrototype() &&
New->getType()->getAs<FunctionProtoType>() &&
Old->getNumParams() == New->getNumParams()) {
- llvm::SmallVector<QualType, 16> ArgTypes;
- llvm::SmallVector<GNUCompatibleParamWarning, 16> Warnings;
+ SmallVector<QualType, 16> ArgTypes;
+ SmallVector<GNUCompatibleParamWarning, 16> Warnings;
const FunctionProtoType *OldProto
= Old->getType()->getAs<FunctionProtoType>();
const FunctionProtoType *NewProto
@@ -1933,6 +2035,12 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
if (Old->isPure())
New->setPure();
+ // __module_private__ is propagated to later declarations.
+ if (Old->isModulePrivate())
+ New->setModulePrivate();
+ else if (New->isModulePrivate())
+ diagnoseModulePrivateRedeclaration(New, Old);
+
// Merge attributes from the parameters. These can mismatch with K&R
// declarations.
if (New->getNumParams() == Old->getNumParams())
@@ -1949,15 +2057,20 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
const ObjCMethodDecl *oldMethod) {
+ // We don't want to merge unavailable and deprecated attributes
+ // except from interface to implementation.
+ bool mergeDeprecation = isa<ObjCImplDecl>(newMethod->getDeclContext());
+
// Merge the attributes.
- mergeDeclAttributes(newMethod, oldMethod, Context);
+ mergeDeclAttributes(newMethod, oldMethod, Context, mergeDeprecation);
// Merge attributes from the parameters.
- for (ObjCMethodDecl::param_iterator oi = oldMethod->param_begin(),
+ ObjCMethodDecl::param_const_iterator oi = oldMethod->param_begin();
+ for (ObjCMethodDecl::param_iterator
ni = newMethod->param_begin(), ne = newMethod->param_end();
ni != ne; ++ni, ++oi)
mergeParamDeclAttributes(*ni, *oi, Context);
-
+
CheckObjCMethodOverride(newMethod, oldMethod, true);
}
@@ -2111,6 +2224,12 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
return New->setInvalidDecl();
}
+ // __module_private__ is propagated to later declarations.
+ if (Old->isModulePrivate())
+ New->setModulePrivate();
+ else if (New->isModulePrivate())
+ diagnoseModulePrivateRedeclaration(New, Old);
+
// Variables with external linkage are analyzed in FinalizeDeclaratorGroup.
// FIXME: The test for external storage here seems wrong? We still
@@ -2193,6 +2312,9 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
Tag = dyn_cast<TagDecl>(TagD);
}
+ if (Tag)
+ Tag->setFreeStanding();
+
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."
@@ -2202,6 +2324,20 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
<< DS.getSourceRange();
}
+ if (DS.isConstexprSpecified()) {
+ // C++0x [dcl.constexpr]p1: constexpr can only be applied to declarations
+ // and definitions of functions and variables.
+ if (Tag)
+ Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_tag)
+ << (DS.getTypeSpecType() == DeclSpec::TST_class ? 0 :
+ DS.getTypeSpecType() == DeclSpec::TST_struct ? 1 :
+ DS.getTypeSpecType() == DeclSpec::TST_union ? 2 : 3);
+ else
+ Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_no_declarators);
+ // Don't emit warnings after this error.
+ return TagD;
+ }
+
if (DS.isFriendSpecified()) {
// If we're dealing with a decl but not a TagDecl, assume that
// whatever routines created it handled the friendship aspect.
@@ -2217,7 +2353,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) {
ProcessDeclAttributeList(S, Record, DS.getAttributes().getList());
- if (!Record->getDeclName() && Record->isDefinition() &&
+ if (!Record->getDeclName() && Record->isCompleteDefinition() &&
DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
if (getLangOptions().CPlusPlus ||
Record->getDeclContext()->isRecord())
@@ -2230,7 +2366,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
}
// Check for Microsoft C extension: anonymous struct.
- if (getLangOptions().Microsoft && !getLangOptions().CPlusPlus &&
+ if (getLangOptions().MicrosoftExt && !getLangOptions().CPlusPlus &&
CurContext->isRecord() &&
DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) {
// Handle 2 kinds of anonymous struct:
@@ -2238,7 +2374,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
// and
// STRUCT_TYPE; <- where STRUCT_TYPE is a typedef struct.
RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag);
- if ((Record && Record->getDeclName() && !Record->isDefinition()) ||
+ if ((Record && Record->getDeclName() && !Record->isCompleteDefinition()) ||
(DS.getTypeSpecType() == DeclSpec::TST_typename &&
DS.getRepAsType().get()->isStructureType())) {
Diag(DS.getSourceRange().getBegin(), diag::ext_ms_anonymous_struct)
@@ -2305,6 +2441,12 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
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());
+
// FIXME: Warn on useless attributes
return TagD;
@@ -2379,7 +2521,7 @@ static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S,
DeclContext *Owner,
RecordDecl *AnonRecord,
AccessSpecifier AS,
- llvm::SmallVector<NamedDecl*, 2> &Chaining,
+ SmallVector<NamedDecl*, 2> &Chaining,
bool MSAnonStruct) {
unsigned diagKind
= AnonRecord->isUnion() ? diag::err_anonymous_union_member_redecl
@@ -2511,8 +2653,8 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Invalid = true;
// Recover by adding 'static'.
- DS.SetStorageClassSpec(DeclSpec::SCS_static, SourceLocation(),
- PrevSpec, DiagID, getLangOptions());
+ DS.SetStorageClassSpec(*this, DeclSpec::SCS_static, SourceLocation(),
+ PrevSpec, DiagID);
}
// C++ [class.union]p3:
// A storage class is not allowed in a declaration of an
@@ -2524,8 +2666,8 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Invalid = true;
// Recover by removing the storage specifier.
- DS.SetStorageClassSpec(DeclSpec::SCS_unspecified, SourceLocation(),
- PrevSpec, DiagID, getLangOptions());
+ DS.SetStorageClassSpec(*this, DeclSpec::SCS_unspecified, SourceLocation(),
+ PrevSpec, DiagID);
}
// Ignore const/volatile/restrict qualifiers.
@@ -2582,7 +2724,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
if (!MemRecord->isAnonymousStructOrUnion() &&
MemRecord->getDeclName()) {
// Visual C++ allows type definition in anonymous struct or union.
- if (getLangOptions().Microsoft)
+ if (getLangOptions().MicrosoftExt)
Diag(MemRecord->getLocation(), diag::ext_anonymous_record_with_type)
<< (int)Record->isUnion();
else {
@@ -2606,7 +2748,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
DK = diag::err_anonymous_record_with_static;
// Visual C++ allows type definition in anonymous struct or union.
- if (getLangOptions().Microsoft &&
+ if (getLangOptions().MicrosoftExt &&
DK == diag::err_anonymous_record_with_type)
Diag((*Mem)->getLocation(), diag::ext_anonymous_record_with_type)
<< (int)Record->isUnion();
@@ -2665,6 +2807,12 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Record->getLocation(), /*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
TInfo, SC, SCAsWritten);
+
+ // Default-initialize the implicit variable. This initialization will be
+ // trivial in almost all cases, except if a union member has an in-class
+ // initializer:
+ // union { int n = 0; };
+ ActOnUninitializedDecl(Anon, /*TypeMayContainAuto=*/false);
}
Anon->setImplicit();
@@ -2676,7 +2824,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
// Inject the members of the anonymous struct/union into the owning
// context and into the identifier resolver chain for name lookup
// purposes.
- llvm::SmallVector<NamedDecl*, 2> Chain;
+ SmallVector<NamedDecl*, 2> Chain;
Chain.push_back(Anon);
if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS,
@@ -2740,7 +2888,7 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
// Inject the members of the anonymous struct into the current
// context and into the identifier resolver chain for name lookup
// purposes.
- llvm::SmallVector<NamedDecl*, 2> Chain;
+ SmallVector<NamedDecl*, 2> Chain;
Chain.push_back(Anon);
if (InjectAnonymousStructOrUnionMembers(*this, S, CurContext,
@@ -2855,26 +3003,51 @@ Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) {
} // switch (Name.getKind())
- assert(false && "Unknown name kind");
- return DeclarationNameInfo();
+ llvm_unreachable("Unknown name kind");
+}
+
+static QualType getCoreType(QualType Ty) {
+ do {
+ if (Ty->isPointerType() || Ty->isReferenceType())
+ Ty = Ty->getPointeeType();
+ else if (Ty->isArrayType())
+ Ty = Ty->castAsArrayTypeUnsafe()->getElementType();
+ else
+ return Ty.withoutLocalFastQualifiers();
+ } while (true);
}
-/// isNearlyMatchingFunction - Determine whether the C++ functions
-/// Declaration and Definition are "nearly" matching. This heuristic
-/// is used to improve diagnostics in the case where an out-of-line
-/// function definition doesn't match any declaration within
-/// the class or namespace.
-static bool isNearlyMatchingFunction(ASTContext &Context,
+/// hasSimilarParameters - Determine whether the C++ functions Declaration
+/// and Definition have "nearly" matching parameters. This heuristic is
+/// used to improve diagnostics in the case where an out-of-line function
+/// definition doesn't match any declaration within the class or namespace.
+/// Also sets Params to the list of indices to the parameters that differ
+/// between the declaration and the definition. If hasSimilarParameters
+/// returns true and Params is empty, then all of the parameters match.
+static bool hasSimilarParameters(ASTContext &Context,
FunctionDecl *Declaration,
- FunctionDecl *Definition) {
+ FunctionDecl *Definition,
+ llvm::SmallVectorImpl<unsigned> &Params) {
+ Params.clear();
if (Declaration->param_size() != Definition->param_size())
return false;
for (unsigned Idx = 0; Idx < Declaration->param_size(); ++Idx) {
QualType DeclParamTy = Declaration->getParamDecl(Idx)->getType();
QualType DefParamTy = Definition->getParamDecl(Idx)->getType();
- if (!Context.hasSameUnqualifiedType(DeclParamTy.getNonReferenceType(),
- DefParamTy.getNonReferenceType()))
+ // The parameter types are identical
+ if (Context.hasSameType(DefParamTy, DeclParamTy))
+ continue;
+
+ QualType DeclParamBaseTy = getCoreType(DeclParamTy);
+ QualType DefParamBaseTy = getCoreType(DefParamTy);
+ const IdentifierInfo *DeclTyName = DeclParamBaseTy.getBaseTypeIdentifier();
+ const IdentifierInfo *DefTyName = DefParamBaseTy.getBaseTypeIdentifier();
+
+ if (Context.hasSameUnqualifiedType(DeclParamBaseTy, DefParamBaseTy) ||
+ (DeclTyName && DeclTyName == DefTyName))
+ Params.push_back(Idx);
+ else // The two parameters aren't even close
return false;
}
@@ -2900,7 +3073,8 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
case DeclSpec::TST_typename:
case DeclSpec::TST_typeofType:
case DeclSpec::TST_decltype:
- case DeclSpec::TST_underlyingType: {
+ case DeclSpec::TST_underlyingType:
+ case DeclSpec::TST_atomic: {
// Grab the type from the parser.
TypeSourceInfo *TSI = 0;
QualType T = S.GetTypeFromParser(DS.getRepAsType(), &TSI);
@@ -2955,8 +3129,8 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
}
Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) {
- return HandleDeclarator(S, D, MultiTemplateParamsArg(*this),
- /*IsFunctionDefinition=*/false);
+ D.setFunctionDefinition(false);
+ return HandleDeclarator(S, D, MultiTemplateParamsArg(*this));
}
/// DiagnoseClassNameShadow - Implement C++ [class.mem]p13:
@@ -2980,8 +3154,7 @@ bool Sema::DiagnoseClassNameShadow(DeclContext *DC,
}
Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
- MultiTemplateParamsArg TemplateParamLists,
- bool IsFunctionDefinition) {
+ MultiTemplateParamsArg TemplateParamLists) {
// TODO: consider using NameInfo for diagnostic.
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
DeclarationName Name = NameInfo.getName();
@@ -3180,22 +3353,21 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef)
Previous.clear();
- bool Redeclaration = false;
+ bool AddToScope = true;
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
if (TemplateParamLists.size()) {
Diag(D.getIdentifierLoc(), diag::err_template_typedef);
return 0;
}
- New = ActOnTypedefDeclarator(S, D, DC, R, TInfo, Previous, Redeclaration);
+ New = ActOnTypedefDeclarator(S, D, DC, TInfo, Previous);
} else if (R->isFunctionType()) {
- New = ActOnFunctionDeclarator(S, D, DC, R, TInfo, Previous,
+ New = ActOnFunctionDeclarator(S, D, DC, TInfo, Previous,
move(TemplateParamLists),
- IsFunctionDefinition, Redeclaration);
+ AddToScope);
} else {
- New = ActOnVariableDeclarator(S, D, DC, R, TInfo, Previous,
- move(TemplateParamLists),
- Redeclaration);
+ New = ActOnVariableDeclarator(S, D, DC, TInfo, Previous,
+ move(TemplateParamLists));
}
if (New == 0)
@@ -3203,7 +3375,8 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
// If this has an identifier and is not an invalid redeclaration or
// function template specialization, add it to the scope stack.
- if (New->getDeclName() && !(Redeclaration && New->isInvalidDecl()))
+ if (New->getDeclName() && AddToScope &&
+ !(D.isRedeclaration() && New->isInvalidDecl()))
PushOnScopeChains(New, S);
return New;
@@ -3321,6 +3494,23 @@ Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND,
}
}
+llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
+Sema::findLocallyScopedExternalDecl(DeclarationName Name) {
+ if (ExternalSource) {
+ // Load locally-scoped external decls from the external source.
+ SmallVector<NamedDecl *, 4> Decls;
+ ExternalSource->ReadLocallyScopedExternalDecls(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];
+ }
+ }
+
+ return LocallyScopedExternalDecls.find(Name);
+}
+
/// \brief Diagnose function specifiers on a declaration of an identifier that
/// does not identify a function.
void Sema::DiagnoseFunctionSpecifiers(Declarator& D) {
@@ -3341,8 +3531,7 @@ void Sema::DiagnoseFunctionSpecifiers(Declarator& D) {
NamedDecl*
Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R, TypeSourceInfo *TInfo,
- LookupResult &Previous, bool &Redeclaration) {
+ TypeSourceInfo *TInfo, LookupResult &Previous) {
// Typedef declarators cannot be qualified (C++ [dcl.meaning]p1).
if (D.getCXXScopeSpec().isSet()) {
Diag(D.getIdentifierLoc(), diag::err_qualified_typedef_declarator)
@@ -3362,6 +3551,9 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (D.getDeclSpec().isThreadSpecified())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
+ if (D.getDeclSpec().isConstexprSpecified())
+ Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr)
+ << 1;
if (D.getName().Kind != UnqualifiedId::IK_Identifier) {
Diag(D.getName().StartLocation, diag::err_typedef_not_identifier)
@@ -3369,7 +3561,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
return 0;
}
- TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, TInfo);
+ TypedefDecl *NewTD = ParseTypedefDecl(S, D, TInfo->getType(), TInfo);
if (!NewTD) return 0;
// Handle attributes prior to checking for duplicates in MergeVarDecl
@@ -3377,7 +3569,10 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
CheckTypedefForVariablyModifiedType(S, NewTD);
- return ActOnTypedefNameDecl(S, DC, NewTD, Previous, Redeclaration);
+ bool Redeclaration = D.isRedeclaration();
+ NamedDecl *ND = ActOnTypedefNameDecl(S, DC, NewTD, Previous, Redeclaration);
+ D.setRedeclaration(Redeclaration);
+ return ND;
}
void
@@ -3557,10 +3752,9 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) {
NamedDecl*
Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
- QualType R, TypeSourceInfo *TInfo,
- LookupResult &Previous,
- MultiTemplateParamsArg TemplateParamLists,
- bool &Redeclaration) {
+ TypeSourceInfo *TInfo, LookupResult &Previous,
+ MultiTemplateParamsArg TemplateParamLists) {
+ QualType R = TInfo->getType();
DeclarationName Name = GetNameForDeclarator(D).getName();
// Check that there are no default arguments (C++ only).
@@ -3585,7 +3779,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
IdentifierInfo *II = Name.getAsIdentifierInfo();
if (!II) {
Diag(D.getIdentifierLoc(), diag::err_bad_variable_name)
- << Name.getAsString();
+ << Name;
return 0;
}
@@ -3606,6 +3800,13 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
+ if (getLangOptions().OpenCL) {
+ // Set up the special work-group-local storage class for variables in the
+ // OpenCL __local address space.
+ if (R.getAddressSpace() == LangAS::opencl_local)
+ SC = SC_OpenCLWorkGroupLocal;
+ }
+
bool isExplicitSpecialization = false;
VarDecl *NewVD;
if (!getLangOptions().CPlusPlus) {
@@ -3695,20 +3896,67 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TemplateParamLists.size(),
TemplateParamLists.release());
}
+
+ if (D.getDeclSpec().isConstexprSpecified()) {
+ // FIXME: once we know whether there's an initializer, apply this to
+ // static data members too.
+ if (!NewVD->isStaticDataMember() &&
+ !NewVD->isThisDeclarationADefinition()) {
+ // 'constexpr' is redundant and ill-formed on a non-defining declaration
+ // of a variable. Suggest replacing it with 'const' if appropriate.
+ SourceLocation ConstexprLoc = D.getDeclSpec().getConstexprSpecLoc();
+ SourceRange ConstexprRange(ConstexprLoc, ConstexprLoc);
+ // If the declarator is complex, we need to move the keyword to the
+ // innermost chunk as we switch it from 'constexpr' to 'const'.
+ int Kind = DeclaratorChunk::Paren;
+ for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) {
+ Kind = D.getTypeObject(I).Kind;
+ if (Kind != DeclaratorChunk::Paren)
+ break;
+ }
+ if ((D.getDeclSpec().getTypeQualifiers() & DeclSpec::TQ_const) ||
+ Kind == DeclaratorChunk::Reference)
+ Diag(ConstexprLoc, diag::err_invalid_constexpr_var_decl)
+ << FixItHint::CreateRemoval(ConstexprRange);
+ else if (Kind == DeclaratorChunk::Paren)
+ Diag(ConstexprLoc, diag::err_invalid_constexpr_var_decl)
+ << FixItHint::CreateReplacement(ConstexprRange, "const");
+ else
+ Diag(ConstexprLoc, diag::err_invalid_constexpr_var_decl)
+ << FixItHint::CreateRemoval(ConstexprRange)
+ << FixItHint::CreateInsertion(D.getIdentifierLoc(), "const ");
+ } else {
+ NewVD->setConstexpr(true);
+ }
+ }
}
+ // Set the lexical context. If the declarator has a C++ scope specifier, the
+ // lexical context will be different from the semantic context.
+ NewVD->setLexicalDeclContext(CurContext);
+
if (D.getDeclSpec().isThreadSpecified()) {
if (NewVD->hasLocalStorage())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_non_global);
- else if (!Context.Target.isTLSSupported())
+ else if (!Context.getTargetInfo().isTLSSupported())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_unsupported);
else
NewVD->setThreadSpecified(true);
}
- // Set the lexical context. If the declarator has a C++ scope specifier, the
- // lexical context will be different from the semantic context.
- NewVD->setLexicalDeclContext(CurContext);
+ if (D.getDeclSpec().isModulePrivateSpecified()) {
+ if (isExplicitSpecialization)
+ Diag(NewVD->getLocation(), diag::err_module_private_specialization)
+ << 2
+ << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc());
+ else if (NewVD->hasLocalStorage())
+ Diag(NewVD->getLocation(), diag::err_module_private_local)
+ << 0 << NewVD->getDeclName()
+ << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc())
+ << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc());
+ else
+ NewVD->setModulePrivate();
+ }
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewVD, D);
@@ -3722,7 +3970,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (Expr *E = (Expr*)D.getAsmLabel()) {
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
- llvm::StringRef Label = SE->getString();
+ StringRef Label = SE->getString();
if (S->getFnParent() != 0) {
switch (SC) {
case SC_None:
@@ -3730,12 +3978,13 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label;
break;
case SC_Register:
- if (!Context.Target.isValidGCCRegisterName(Label))
+ if (!Context.getTargetInfo().isValidGCCRegisterName(Label))
Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label;
break;
case SC_Static:
case SC_Extern:
case SC_PrivateExtern:
+ case SC_OpenCLWorkGroupLocal:
break;
}
}
@@ -3754,9 +4003,9 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
FilterLookupForScope(Previous, DC, S, NewVD->hasLinkage(),
isExplicitSpecialization);
- if (!getLangOptions().CPlusPlus)
- CheckVariableDeclaration(NewVD, Previous, Redeclaration);
- else {
+ if (!getLangOptions().CPlusPlus) {
+ D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
+ } else {
// Merge the decl with the existing one if appropriate.
if (!Previous.empty()) {
if (Previous.isSingleResult() &&
@@ -3777,7 +4026,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewVD->setInvalidDecl();
}
- CheckVariableDeclaration(NewVD, Previous, Redeclaration);
+ D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
// This is an explicit specialization of a static data member. Check it.
if (isExplicitSpecialization && !NewVD->isInvalidDecl() &&
@@ -3825,7 +4074,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) {
// Return if warning is ignored.
if (Diags.getDiagnosticLevel(diag::warn_decl_shadow, R.getNameLoc()) ==
- Diagnostic::Ignored)
+ DiagnosticsEngine::Ignored)
return;
// Don't diagnose declarations at file scope.
@@ -3899,7 +4148,7 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) {
/// \brief Check -Wshadow without the advantage of a previous lookup.
void Sema::CheckShadow(Scope *S, VarDecl *D) {
if (Diags.getDiagnosticLevel(diag::warn_decl_shadow, D->getLocation()) ==
- Diagnostic::Ignored)
+ DiagnosticsEngine::Ignored)
return;
LookupResult R(*this, D->getDeclName(), D->getLocation(),
@@ -3918,18 +4167,21 @@ void Sema::CheckShadow(Scope *S, VarDecl *D) {
/// that have been instantiated from a template.
///
/// Sets NewVD->isInvalidDecl() if an error was encountered.
-void Sema::CheckVariableDeclaration(VarDecl *NewVD,
- LookupResult &Previous,
- bool &Redeclaration) {
+///
+/// Returns true if the variable declaration is a redeclaration.
+bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
+ LookupResult &Previous) {
// If the decl is already known invalid, don't check it.
if (NewVD->isInvalidDecl())
- return;
+ return false;
QualType T = NewVD->getType();
if (T->isObjCObjectType()) {
- Diag(NewVD->getLocation(), diag::err_statically_allocated_object);
- return NewVD->setInvalidDecl();
+ Diag(NewVD->getLocation(), diag::err_statically_allocated_object)
+ << FixItHint::CreateInsertion(NewVD->getLocation(), "*");
+ T = Context.getObjCObjectPointerType(T);
+ NewVD->setType(T);
}
// Emit an error if an address space was applied to decl with local storage.
@@ -3938,12 +4190,13 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD,
// ISO/IEC TR 18037 S5.1.2
if (NewVD->hasLocalStorage() && T.getAddressSpace() != 0) {
Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl);
- return NewVD->setInvalidDecl();
+ NewVD->setInvalidDecl();
+ return false;
}
if (NewVD->hasLocalStorage() && T.isObjCGCWeak()
&& !NewVD->hasAttr<BlocksAttr>()) {
- if (getLangOptions().getGCMode() != LangOptions::NonGC)
+ if (getLangOptions().getGC() != LangOptions::NonGC)
Diag(NewVD->getLocation(), diag::warn_gc_attribute_weak_on_local);
else
Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local);
@@ -3977,7 +4230,8 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD,
else
Diag(NewVD->getLocation(), diag::err_vla_decl_has_extern_linkage)
<< SizeRange;
- return NewVD->setInvalidDecl();
+ NewVD->setInvalidDecl();
+ return false;
}
if (FixedTy.isNull()) {
@@ -3985,7 +4239,8 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD,
Diag(NewVD->getLocation(), diag::err_vm_decl_in_file_scope);
else
Diag(NewVD->getLocation(), diag::err_vm_decl_has_extern_linkage);
- return NewVD->setInvalidDecl();
+ NewVD->setInvalidDecl();
+ return false;
}
Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size);
@@ -3997,7 +4252,7 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD,
// an extern "C" variable, look for a non-visible extern "C"
// declaration with the same name.
llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
- = LocallyScopedExternalDecls.find(NewVD->getDeclName());
+ = findLocallyScopedExternalDecl(NewVD->getDeclName());
if (Pos != LocallyScopedExternalDecls.end())
Previous.addDecl(Pos->second);
}
@@ -4005,17 +4260,20 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD,
if (T->isVoidType() && !NewVD->hasExternalStorage()) {
Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type)
<< T;
- return NewVD->setInvalidDecl();
+ NewVD->setInvalidDecl();
+ return false;
}
if (!NewVD->hasLocalStorage() && NewVD->hasAttr<BlocksAttr>()) {
Diag(NewVD->getLocation(), diag::err_block_on_nonlocal);
- return NewVD->setInvalidDecl();
+ NewVD->setInvalidDecl();
+ return false;
}
if (isVM && NewVD->hasAttr<BlocksAttr>()) {
Diag(NewVD->getLocation(), diag::err_block_on_vm);
- return NewVD->setInvalidDecl();
+ NewVD->setInvalidDecl();
+ return false;
}
// Function pointers and references cannot have qualified function type, only
@@ -4032,13 +4290,15 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD,
Pointee->getAs<FunctionProtoType>()->getTypeQuals() != 0) {
Diag(NewVD->getLocation(), diag::err_invalid_qualified_function_pointer)
<< PtrOrRef;
- return NewVD->setInvalidDecl();
+ NewVD->setInvalidDecl();
+ return false;
}
if (!Previous.empty()) {
- Redeclaration = true;
MergeVarDecl(NewVD, Previous);
+ return true;
}
+ return false;
}
/// \brief Data used with FindOverriddenMethod
@@ -4108,233 +4368,397 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
return AddedAny;
}
-static void DiagnoseInvalidRedeclaration(Sema &S, FunctionDecl *NewFD) {
- LookupResult Prev(S, NewFD->getDeclName(), NewFD->getLocation(),
+namespace {
+ // Struct for holding all of the extra arguments needed by
+ // DiagnoseInvalidRedeclaration to call Sema::ActOnFunctionDeclarator.
+ struct ActOnFDArgs {
+ Scope *S;
+ Declarator &D;
+ MultiTemplateParamsArg TemplateParamLists;
+ bool AddToScope;
+ };
+}
+
+/// \brief Generate diagnostics for an invalid function redeclaration.
+///
+/// This routine handles generating the diagnostic messages for an invalid
+/// function redeclaration, including finding possible similar declarations
+/// or performing typo correction if there are no previous declarations with
+/// the same name.
+///
+/// Returns a NamedDecl iff typo correction was performed and substituting in
+/// the new declaration name does not cause new errors.
+static NamedDecl* DiagnoseInvalidRedeclaration(
+ Sema &SemaRef, LookupResult &Previous, FunctionDecl *NewFD,
+ ActOnFDArgs &ExtraArgs) {
+ NamedDecl *Result = NULL;
+ DeclarationName Name = NewFD->getDeclName();
+ DeclContext *NewDC = NewFD->getDeclContext();
+ LookupResult Prev(SemaRef, Name, NewFD->getLocation(),
Sema::LookupOrdinaryName, Sema::ForRedeclaration);
- S.LookupQualifiedName(Prev, NewFD->getDeclContext());
+ llvm::SmallVector<unsigned, 1> MismatchedParams;
+ llvm::SmallVector<std::pair<FunctionDecl*, unsigned>, 1> NearMatches;
+ TypoCorrection Correction;
+ bool isFriendDecl = (SemaRef.getLangOptions().CPlusPlus &&
+ ExtraArgs.D.getDeclSpec().isFriendSpecified());
+ unsigned DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend
+ : diag::err_member_def_does_not_match;
+
+ NewFD->setInvalidDecl();
+ SemaRef.LookupQualifiedName(Prev, NewDC);
assert(!Prev.isAmbiguous() &&
"Cannot have an ambiguity in previous-declaration lookup");
- for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
- Func != FuncEnd; ++Func) {
- if (isa<FunctionDecl>(*Func) &&
- isNearlyMatchingFunction(S.Context, cast<FunctionDecl>(*Func), NewFD))
- S.Diag((*Func)->getLocation(), diag::note_member_def_close_match);
+ if (!Prev.empty()) {
+ for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
+ Func != FuncEnd; ++Func) {
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func);
+ if (FD &&
+ hasSimilarParameters(SemaRef.Context, FD, NewFD, MismatchedParams)) {
+ // Add 1 to the index so that 0 can mean the mismatch didn't
+ // involve a parameter
+ unsigned ParamNum =
+ MismatchedParams.empty() ? 0 : MismatchedParams.front() + 1;
+ NearMatches.push_back(std::make_pair(FD, ParamNum));
+ }
+ }
+ // If the qualified name lookup yielded nothing, try typo correction
+ } else if ((Correction = SemaRef.CorrectTypo(Prev.getLookupNameInfo(),
+ Prev.getLookupKind(), 0, 0, NewDC)) &&
+ Correction.getCorrection() != Name) {
+ // Trap errors.
+ Sema::SFINAETrap Trap(SemaRef);
+
+ // Set up everything for the call to ActOnFunctionDeclarator
+ ExtraArgs.D.SetIdentifier(Correction.getCorrectionAsIdentifierInfo(),
+ ExtraArgs.D.getIdentifierLoc());
+ Previous.clear();
+ Previous.setLookupName(Correction.getCorrection());
+ for (TypoCorrection::decl_iterator CDecl = Correction.begin(),
+ CDeclEnd = Correction.end();
+ CDecl != CDeclEnd; ++CDecl) {
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(*CDecl);
+ if (FD && hasSimilarParameters(SemaRef.Context, FD, NewFD,
+ MismatchedParams)) {
+ Previous.addDecl(FD);
+ }
+ }
+ bool wasRedeclaration = ExtraArgs.D.isRedeclaration();
+ // TODO: Refactor ActOnFunctionDeclarator so that we can call only the
+ // pieces need to verify the typo-corrected C++ declaraction and hopefully
+ // eliminate the need for the parameter pack ExtraArgs.
+ Result = SemaRef.ActOnFunctionDeclarator(ExtraArgs.S, ExtraArgs.D,
+ NewFD->getDeclContext(),
+ NewFD->getTypeSourceInfo(),
+ Previous,
+ ExtraArgs.TemplateParamLists,
+ ExtraArgs.AddToScope);
+ if (Trap.hasErrorOccurred()) {
+ // Pretend the typo correction never occurred
+ ExtraArgs.D.SetIdentifier(Name.getAsIdentifierInfo(),
+ ExtraArgs.D.getIdentifierLoc());
+ ExtraArgs.D.setRedeclaration(wasRedeclaration);
+ Previous.clear();
+ Previous.setLookupName(Name);
+ Result = NULL;
+ } else {
+ for (LookupResult::iterator Func = Previous.begin(),
+ FuncEnd = Previous.end();
+ Func != FuncEnd; ++Func) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func))
+ NearMatches.push_back(std::make_pair(FD, 0));
+ }
+ }
+ if (NearMatches.empty()) {
+ // Ignore the correction if it didn't yield any close FunctionDecl matches
+ Correction = TypoCorrection();
+ } else {
+ DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend_suggest
+ : diag::err_member_def_does_not_match_suggest;
+ }
}
-}
-NamedDecl*
-Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
- QualType R, TypeSourceInfo *TInfo,
- LookupResult &Previous,
- MultiTemplateParamsArg TemplateParamLists,
- bool IsFunctionDefinition, bool &Redeclaration) {
- assert(R.getTypePtr()->isFunctionType());
+ if (Correction)
+ SemaRef.Diag(NewFD->getLocation(), DiagMsg)
+ << Name << NewDC << Correction.getQuoted(SemaRef.getLangOptions())
+ << FixItHint::CreateReplacement(
+ NewFD->getLocation(),
+ Correction.getAsString(SemaRef.getLangOptions()));
+ else
+ SemaRef.Diag(NewFD->getLocation(), DiagMsg)
+ << Name << NewDC << NewFD->getLocation();
+
+ bool NewFDisConst = false;
+ if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD))
+ NewFDisConst = NewMD->getTypeQualifiers() & Qualifiers::Const;
+
+ for (llvm::SmallVector<std::pair<FunctionDecl*, unsigned>, 1>::iterator
+ NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end();
+ NearMatch != NearMatchEnd; ++NearMatch) {
+ FunctionDecl *FD = NearMatch->first;
+ bool FDisConst = false;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
+ FDisConst = MD->getTypeQualifiers() & Qualifiers::Const;
+
+ if (unsigned Idx = NearMatch->second) {
+ ParmVarDecl *FDParam = FD->getParamDecl(Idx-1);
+ SemaRef.Diag(FDParam->getTypeSpecStartLoc(),
+ diag::note_member_def_close_param_match)
+ << Idx << FDParam->getType() << NewFD->getParamDecl(Idx-1)->getType();
+ } else if (Correction) {
+ SemaRef.Diag(FD->getLocation(), diag::note_previous_decl)
+ << Correction.getQuoted(SemaRef.getLangOptions());
+ } else if (FDisConst != NewFDisConst) {
+ SemaRef.Diag(FD->getLocation(), diag::note_member_def_close_const_match)
+ << NewFDisConst << FD->getSourceRange().getEnd();
+ } else
+ SemaRef.Diag(FD->getLocation(), diag::note_member_def_close_match);
+ }
+ return Result;
+}
- // TODO: consider using NameInfo for diagnostic.
- DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
- DeclarationName Name = NameInfo.getName();
- FunctionDecl::StorageClass SC = SC_None;
+static FunctionDecl::StorageClass getFunctionStorageClass(Sema &SemaRef, Declarator &D) {
switch (D.getDeclSpec().getStorageClassSpec()) {
- default: assert(0 && "Unknown storage class!");
+ default: llvm_unreachable("Unknown storage class!");
case DeclSpec::SCS_auto:
case DeclSpec::SCS_register:
case DeclSpec::SCS_mutable:
- Diag(D.getDeclSpec().getStorageClassSpecLoc(),
- diag::err_typecheck_sclass_func);
+ SemaRef.Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ diag::err_typecheck_sclass_func);
D.setInvalidType();
break;
- case DeclSpec::SCS_unspecified: SC = SC_None; break;
- case DeclSpec::SCS_extern: SC = SC_Extern; break;
+ case DeclSpec::SCS_unspecified: break;
+ case DeclSpec::SCS_extern: return SC_Extern;
case DeclSpec::SCS_static: {
- if (CurContext->getRedeclContext()->isFunctionOrMethod()) {
+ if (SemaRef.CurContext->getRedeclContext()->isFunctionOrMethod()) {
// C99 6.7.1p5:
// The declaration of an identifier for a function that has
// block scope shall have no explicit storage-class specifier
// other than extern
// See also (C++ [dcl.stc]p4).
- Diag(D.getDeclSpec().getStorageClassSpecLoc(),
- diag::err_static_block_func);
- SC = SC_None;
+ SemaRef.Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ diag::err_static_block_func);
+ break;
} else
- SC = SC_Static;
- break;
+ return SC_Static;
}
- case DeclSpec::SCS_private_extern: SC = SC_PrivateExtern; break;
+ case DeclSpec::SCS_private_extern: return SC_PrivateExtern;
}
- if (D.getDeclSpec().isThreadSpecified())
- Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
+ // No explicit storage class has already been returned
+ return SC_None;
+}
- // Do not allow returning a objc interface by-value.
- if (R->getAs<FunctionType>()->getResultType()->isObjCObjectType()) {
- Diag(D.getIdentifierLoc(),
- diag::err_object_cannot_be_passed_returned_by_value) << 0
- << R->getAs<FunctionType>()->getResultType();
- D.setInvalidType();
- }
-
- FunctionDecl *NewFD;
+static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
+ DeclContext *DC, QualType &R,
+ TypeSourceInfo *TInfo,
+ FunctionDecl::StorageClass SC,
+ bool &IsVirtualOkay) {
+ DeclarationNameInfo NameInfo = SemaRef.GetNameForDeclarator(D);
+ DeclarationName Name = NameInfo.getName();
+
+ FunctionDecl *NewFD = 0;
bool isInline = D.getDeclSpec().isInlineSpecified();
- bool isFriend = false;
DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten();
FunctionDecl::StorageClass SCAsWritten
= StorageClassSpecToFunctionDeclStorageClass(SCSpec);
- FunctionTemplateDecl *FunctionTemplate = 0;
- bool isExplicitSpecialization = false;
- bool isFunctionTemplateSpecialization = false;
- if (!getLangOptions().CPlusPlus) {
+ if (!SemaRef.getLangOptions().CPlusPlus) {
// Determine whether the function was written with a
// prototype. This true when:
// - there is a prototype in the declarator, or
// - the type R of the function is some kind of typedef or other reference
// to a type name (which eventually refers to a function type).
bool HasPrototype =
- (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) ||
- (!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType());
-
- NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(),
+ (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) ||
+ (!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType());
+
+ NewFD = FunctionDecl::Create(SemaRef.Context, DC, D.getSourceRange().getBegin(),
NameInfo, R, TInfo, SC, SCAsWritten, isInline,
HasPrototype);
if (D.isInvalidType())
NewFD->setInvalidDecl();
-
+
// Set the lexical context.
- NewFD->setLexicalDeclContext(CurContext);
- // Filter out previous declarations that don't match the scope.
- FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(),
- /*ExplicitInstantiationOrSpecialization=*/false);
- } else {
- isFriend = D.getDeclSpec().isFriendSpecified();
- bool isVirtual = D.getDeclSpec().isVirtualSpecified();
- bool isExplicit = D.getDeclSpec().isExplicitSpecified();
- bool isVirtualOkay = false;
-
- // Check that the return type is not an abstract class type.
- // For record types, this is done by the AbstractClassUsageDiagnoser once
- // the class has been completely parsed.
- if (!DC->isRecord() &&
- RequireNonAbstractType(D.getIdentifierLoc(),
- R->getAs<FunctionType>()->getResultType(),
- diag::err_abstract_type_in_decl,
- AbstractReturnType))
- D.setInvalidType();
+ NewFD->setLexicalDeclContext(SemaRef.CurContext);
- if (Name.getNameKind() == DeclarationName::CXXConstructorName) {
- // This is a C++ constructor declaration.
- assert(DC->isRecord() &&
- "Constructors can only be declared in a member context");
-
- R = CheckConstructorDeclarator(D, R, SC);
-
- // Create the new declaration
- CXXConstructorDecl *NewCD = CXXConstructorDecl::Create(
- Context,
- cast<CXXRecordDecl>(DC),
- D.getSourceRange().getBegin(),
- NameInfo, R, TInfo,
- isExplicit, isInline,
- /*isImplicitlyDeclared=*/false);
-
- NewFD = NewCD;
- } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
- // This is a C++ destructor declaration.
- if (DC->isRecord()) {
- R = CheckDestructorDeclarator(D, R, SC);
- CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
-
- CXXDestructorDecl *NewDD = CXXDestructorDecl::Create(Context, Record,
- D.getSourceRange().getBegin(),
- NameInfo, R, TInfo,
- isInline,
- /*isImplicitlyDeclared=*/false);
- NewFD = NewDD;
- isVirtualOkay = true;
-
- // 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 (getLangOptions().CPlusPlus0x && !Record->isDependentType() &&
- Record->getDefinition() && !Record->isBeingDefined() &&
- R->getAs<FunctionProtoType>()->getExceptionSpecType() == EST_None) {
- AdjustDestructorExceptionSpec(Record, NewDD);
- }
+ return NewFD;
+ }
- } else {
- Diag(D.getIdentifierLoc(), diag::err_destructor_not_member);
-
- // Create a FunctionDecl to satisfy the function definition parsing
- // code path.
- NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(),
- D.getIdentifierLoc(), Name, R, TInfo,
- SC, SCAsWritten, isInline,
- /*hasPrototype=*/true);
- D.setInvalidType();
- }
- } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) {
- if (!DC->isRecord()) {
- Diag(D.getIdentifierLoc(),
- diag::err_conv_function_not_member);
- return 0;
- }
+ bool isExplicit = D.getDeclSpec().isExplicitSpecified();
+ bool isConstexpr = D.getDeclSpec().isConstexprSpecified();
+
+ // Check that the return type is not an abstract class type.
+ // For record types, this is done by the AbstractClassUsageDiagnoser once
+ // the class has been completely parsed.
+ if (!DC->isRecord() &&
+ SemaRef.RequireNonAbstractType(D.getIdentifierLoc(),
+ R->getAs<FunctionType>()->getResultType(),
+ diag::err_abstract_type_in_decl,
+ SemaRef.AbstractReturnType))
+ D.setInvalidType();
- CheckConversionDeclarator(D, R, SC);
- NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC),
+ if (Name.getNameKind() == DeclarationName::CXXConstructorName) {
+ // This is a C++ constructor declaration.
+ assert(DC->isRecord() &&
+ "Constructors can only be declared in a member context");
+
+ R = SemaRef.CheckConstructorDeclarator(D, R, SC);
+ return CXXConstructorDecl::Create(SemaRef.Context, cast<CXXRecordDecl>(DC),
+ D.getSourceRange().getBegin(), NameInfo,
+ R, TInfo, isExplicit, isInline,
+ /*isImplicitlyDeclared=*/false,
+ isConstexpr);
+
+ } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
+ // This is a C++ destructor declaration.
+ if (DC->isRecord()) {
+ R = SemaRef.CheckDestructorDeclarator(D, R, SC);
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
+ CXXDestructorDecl *NewDD = CXXDestructorDecl::Create(
+ SemaRef.Context, Record,
D.getSourceRange().getBegin(),
- NameInfo, R, TInfo,
- isInline, isExplicit,
- SourceLocation());
-
- isVirtualOkay = true;
- } else if (DC->isRecord()) {
- // If the of the function is the same as the name of the record, then this
- // must be an invalid constructor that has a return type.
- // (The parser checks for a return type and makes the declarator a
- // constructor if it has no return type).
- // must have an invalid constructor that has a return type
- if (Name.getAsIdentifierInfo() &&
- Name.getAsIdentifierInfo() == cast<CXXRecordDecl>(DC)->getIdentifier()){
- Diag(D.getIdentifierLoc(), diag::err_constructor_return_type)
- << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc())
- << SourceRange(D.getIdentifierLoc());
- return 0;
+ NameInfo, R, TInfo, isInline,
+ /*isImplicitlyDeclared=*/false);
+
+ // 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.getLangOptions().CPlusPlus0x && !Record->isDependentType() &&
+ Record->getDefinition() && !Record->isBeingDefined() &&
+ R->getAs<FunctionProtoType>()->getExceptionSpecType() == EST_None) {
+ SemaRef.AdjustDestructorExceptionSpec(Record, NewDD);
}
- 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;
-
- // This is a C++ method declaration.
- CXXMethodDecl *NewMD = CXXMethodDecl::Create(
- Context, cast<CXXRecordDecl>(DC),
- D.getSourceRange().getBegin(),
- NameInfo, R, TInfo,
- isStatic, SCAsWritten, isInline,
- SourceLocation());
- NewFD = NewMD;
-
- isVirtualOkay = !isStatic;
+ IsVirtualOkay = true;
+ return NewDD;
+
} else {
- // Determine whether the function was written with a
- // prototype. This true when:
- // - we're in C++ (where every function has a prototype),
- NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(),
- NameInfo, R, TInfo, SC, SCAsWritten, isInline,
- true/*HasPrototype*/);
+ SemaRef.Diag(D.getIdentifierLoc(), diag::err_destructor_not_member);
+ D.setInvalidType();
+
+ // Create a FunctionDecl to satisfy the function definition parsing
+ // code path.
+ return FunctionDecl::Create(SemaRef.Context, DC,
+ D.getSourceRange().getBegin(),
+ D.getIdentifierLoc(), Name, R, TInfo,
+ SC, SCAsWritten, isInline,
+ /*hasPrototype=*/true, isConstexpr);
+ }
+
+ } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) {
+ if (!DC->isRecord()) {
+ SemaRef.Diag(D.getIdentifierLoc(),
+ diag::err_conv_function_not_member);
+ return 0;
+ }
+
+ SemaRef.CheckConversionDeclarator(D, R, SC);
+ IsVirtualOkay = true;
+ return CXXConversionDecl::Create(SemaRef.Context, cast<CXXRecordDecl>(DC),
+ D.getSourceRange().getBegin(), NameInfo,
+ R, TInfo, isInline, isExplicit,
+ isConstexpr, SourceLocation());
+
+ } else if (DC->isRecord()) {
+ // If the name of the function is the same as the name of the record,
+ // then this must be an invalid constructor that has a return type.
+ // (The parser checks for a return type and makes the declarator a
+ // constructor if it has no return type).
+ if (Name.getAsIdentifierInfo() &&
+ Name.getAsIdentifierInfo() == cast<CXXRecordDecl>(DC)->getIdentifier()){
+ SemaRef.Diag(D.getIdentifierLoc(), diag::err_constructor_return_type)
+ << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc())
+ << SourceRange(D.getIdentifierLoc());
+ 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.getSourceRange().getBegin(), NameInfo, R,
+ TInfo, isStatic, SCAsWritten, isInline,
+ isConstexpr, SourceLocation());
+
+ } 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.getSourceRange().getBegin(),
+ NameInfo, R, TInfo, SC, SCAsWritten, isInline,
+ true/*HasPrototype*/, isConstexpr);
+ }
+}
+
+NamedDecl*
+Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
+ TypeSourceInfo *TInfo, LookupResult &Previous,
+ MultiTemplateParamsArg TemplateParamLists,
+ bool &AddToScope) {
+ QualType R = TInfo->getType();
+
+ assert(R.getTypePtr()->isFunctionType());
+
+ // TODO: consider using NameInfo for diagnostic.
+ DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
+ DeclarationName Name = NameInfo.getName();
+ FunctionDecl::StorageClass SC = getFunctionStorageClass(*this, D);
+
+ if (D.getDeclSpec().isThreadSpecified())
+ Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
+
+ // Do not allow returning a objc interface by-value.
+ if (R->getAs<FunctionType>()->getResultType()->isObjCObjectType()) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_object_cannot_be_passed_returned_by_value) << 0
+ << R->getAs<FunctionType>()->getResultType()
+ << FixItHint::CreateInsertion(D.getIdentifierLoc(), "*");
+
+ QualType T = R->getAs<FunctionType>()->getResultType();
+ T = Context.getObjCObjectPointerType(T);
+ if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(R)) {
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ R = Context.getFunctionType(T, FPT->arg_type_begin(),
+ FPT->getNumArgs(), EPI);
}
+ else if (isa<FunctionNoProtoType>(R))
+ R = Context.getFunctionNoProtoType(T);
+ }
+
+ bool isFriend = false;
+ FunctionTemplateDecl *FunctionTemplate = 0;
+ bool isExplicitSpecialization = false;
+ bool isFunctionTemplateSpecialization = false;
+ bool isDependentClassScopeExplicitSpecialization = false;
+ bool isVirtualOkay = false;
- if (isFriend && !isInline && IsFunctionDefinition) {
+ FunctionDecl *NewFD = CreateNewFunctionDecl(*this, D, DC, R, TInfo, SC,
+ isVirtualOkay);
+ if (!NewFD) return 0;
+
+ if (getLangOptions().CPlusPlus) {
+ bool isInline = D.getDeclSpec().isInlineSpecified();
+ bool isVirtual = D.getDeclSpec().isVirtualSpecified();
+ bool isExplicit = D.getDeclSpec().isExplicitSpecified();
+ bool isConstexpr = D.getDeclSpec().isConstexprSpecified();
+ isFriend = D.getDeclSpec().isFriendSpecified();
+ if (isFriend && !isInline && D.isFunctionDefinition()) {
// C++ [class.friend]p5
// A function can be defined in a friend declaration of a
// class . . . . Such a function is implicitly inline.
@@ -4377,6 +4801,16 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Diag(NewFD->getLocation(), diag::err_destructor_template);
return 0;
}
+
+ // If we're adding a template to a dependent context, we may need to
+ // rebuilding some of the types used within the template parameter list,
+ // now that we know what the current instantiation is.
+ if (DC->isDependentContext()) {
+ ContextRAII SavedContext(*this, DC);
+ if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams))
+ Invalid = true;
+ }
+
FunctionTemplate = FunctionTemplateDecl::Create(Context, DC,
NewFD->getLocation(),
@@ -4437,7 +4871,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (FunctionTemplate)
FunctionTemplate->setInvalidDecl();
}
-
+
// C++ [dcl.fct.spec]p5:
// The virtual specifier shall only be used in declarations of
// nonstatic class member functions that appear within a
@@ -4474,7 +4908,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc());
}
}
-
+
// C++ [dcl.fct.spec]p6:
// The explicit specifier shall be used only in the declaration of a
// constructor or conversion function within its class definition; see 12.3.1
@@ -4495,10 +4929,32 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
- // Filter out previous declarations that don't match the scope.
- FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(),
- isExplicitSpecialization ||
- isFunctionTemplateSpecialization);
+ if (isConstexpr) {
+ // C++0x [dcl.constexpr]p2: constexpr functions and constexpr constructors
+ // are implicitly inline.
+ NewFD->setImplicitlyInline();
+
+ // C++0x [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))
+ Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor);
+ }
+
+ // If __module_private__ was specified, mark the function accordingly.
+ if (D.getDeclSpec().isModulePrivateSpecified()) {
+ if (isFunctionTemplateSpecialization) {
+ SourceLocation ModulePrivateLoc
+ = D.getDeclSpec().getModulePrivateSpecLoc();
+ Diag(ModulePrivateLoc, diag::err_module_private_specialization)
+ << 0
+ << FixItHint::CreateRemoval(ModulePrivateLoc);
+ } else {
+ NewFD->setModulePrivate();
+ if (FunctionTemplate)
+ FunctionTemplate->setModulePrivate();
+ }
+ }
if (isFriend) {
// For now, claim that the objects have no previous declaration.
@@ -4510,7 +4966,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setAccess(AS_public);
}
- if (isa<CXXMethodDecl>(NewFD) && DC == CurContext && IsFunctionDefinition) {
+ if (isa<CXXMethodDecl>(NewFD) && DC == CurContext &&
+ D.isFunctionDefinition()) {
// A method is implicitly inline if it's defined in its class
// definition.
NewFD->setImplicitlyInline();
@@ -4530,6 +4987,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
}
}
+
+ // Filter out previous declarations that don't match the scope.
+ FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(),
+ isExplicitSpecialization ||
+ isFunctionTemplateSpecialization);
// Handle GNU asm-label extension (encoded as an attribute).
if (Expr *E = (Expr*) D.getAsmLabel()) {
@@ -4541,7 +5003,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Copy the parameter declarations from the declarator D to the function
// declaration NewFD, if they are available. First scavenge them into Params.
- llvm::SmallVector<ParmVarDecl*, 16> Params;
+ SmallVector<ParmVarDecl*, 16> Params;
if (D.isFunctionDeclarator()) {
DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
@@ -4603,8 +5065,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
assert(R->isFunctionNoProtoType() && NewFD->getNumParams() == 0 &&
"Should not need args for typedef of non-prototype fn");
}
+
// Finally, we know we have the right number of parameters, install them.
- NewFD->setParams(Params.data(), Params.size());
+ NewFD->setParams(Params);
// Process the non-inheritable attributes on this declaration.
ProcessDeclAttributes(S, NewFD, D,
@@ -4613,9 +5076,20 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (!getLangOptions().CPlusPlus) {
// Perform semantic checking on the function declaration.
bool isExplicitSpecialization=false;
- CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization,
- Redeclaration);
- assert((NewFD->isInvalidDecl() || !Redeclaration ||
+ if (!NewFD->isInvalidDecl()) {
+ if (NewFD->getResultType()->isVariablyModifiedType()) {
+ // Functions returning a variably modified type violate C99 6.7.5.2p2
+ // because all functions have linkage.
+ Diag(NewFD->getLocation(), diag::err_vm_func_decl);
+ NewFD->setInvalidDecl();
+ } else {
+ if (NewFD->isMain())
+ CheckMain(NewFD, D.getDeclSpec());
+ D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous,
+ isExplicitSpecialization));
+ }
+ }
+ assert((NewFD->isInvalidDecl() || !D.isRedeclaration() ||
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
"previous declaration set still overloaded");
} else {
@@ -4676,8 +5150,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// that either the specialized function type or the specialized
// template is dependent, and therefore matching will fail. In
// this case, don't check the specialization yet.
+ bool InstantiationDependent = false;
if (isFunctionTemplateSpecialization && isFriend &&
- (NewFD->getType()->isDependentType() || DC->isDependentContext())) {
+ (NewFD->getType()->isDependentType() || DC->isDependentContext() ||
+ TemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs.getArgumentArray(), TemplateArgs.size(),
+ InstantiationDependent))) {
assert(HasExplicitTemplateArgs &&
"friend function specialization without template args");
if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs,
@@ -4686,10 +5164,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
} else if (isFunctionTemplateSpecialization) {
if (CurContext->isDependentContext() && CurContext->isRecord()
&& !isFriend) {
- Diag(NewFD->getLocation(), diag::err_function_specialization_in_class)
+ isDependentClassScopeExplicitSpecialization = true;
+ Diag(NewFD->getLocation(), getLangOptions().MicrosoftExt ?
+ diag::ext_function_specialization_in_class :
+ diag::err_function_specialization_in_class)
<< NewFD->getDeclName();
- NewFD->setInvalidDecl();
- return 0;
} else if (CheckFunctionTemplateSpecialization(NewFD,
(HasExplicitTemplateArgs ? &TemplateArgs : 0),
Previous))
@@ -4719,18 +5198,33 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
// Perform semantic checking on the function declaration.
- CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization,
- Redeclaration);
+ if (!isDependentClassScopeExplicitSpecialization) {
+ if (NewFD->isInvalidDecl()) {
+ // If this is a class member, mark the class invalid immediately.
+ // This avoids some consistency errors later.
+ if (CXXMethodDecl* methodDecl = dyn_cast<CXXMethodDecl>(NewFD))
+ methodDecl->getParent()->setInvalidDecl();
+ } else {
+ if (NewFD->isMain())
+ CheckMain(NewFD, D.getDeclSpec());
+ D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous,
+ isExplicitSpecialization));
+ }
+ }
- assert((NewFD->isInvalidDecl() || !Redeclaration ||
+ assert((NewFD->isInvalidDecl() || !D.isRedeclaration() ||
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
"previous declaration set still overloaded");
+ if (NewFD->isConstexpr() && !NewFD->isInvalidDecl() &&
+ !CheckConstexprFunctionDecl(NewFD, CCK_Declaration))
+ NewFD->setInvalidDecl();
+
NamedDecl *PrincipalDecl = (FunctionTemplate
? cast<NamedDecl>(FunctionTemplate)
: NewFD);
- if (isFriend && Redeclaration) {
+ if (isFriend && D.isRedeclaration()) {
AccessSpecifier Access = AS_public;
if (!NewFD->isInvalidDecl())
Access = NewFD->getPreviousDeclaration()->getAccess();
@@ -4752,7 +5246,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(),
PrevTemplate? PrevTemplate->getTemplateParameters() : 0,
D.getDeclSpec().isFriendSpecified()
- ? (IsFunctionDefinition
+ ? (D.isFunctionDefinition()
? TPC_FriendFunctionTemplateDefinition
: TPC_FriendFunctionTemplate)
: (D.getCXXScopeSpec().isSet() &&
@@ -4764,7 +5258,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (NewFD->isInvalidDecl()) {
// Ignore all the rest of this.
- } else if (!Redeclaration) {
+ } else if (!D.isRedeclaration()) {
+ struct ActOnFDArgs ExtraArgs = { S, D, TemplateParamLists,
+ AddToScope };
// Fake up an access specifier if it's supposed to be a class member.
if (isa<CXXRecordDecl>(NewFD->getDeclContext()))
NewFD->setAccess(AS_public);
@@ -4784,38 +5280,43 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
(TemplateParamLists.size() ||
D.getCXXScopeSpec().getScopeRep()->isDependent() ||
CurContext->isDependentContext())) {
- // ignore these
- } else {
- // The user tried to provide an out-of-line definition for a
- // function that is a member of a class or namespace, but there
- // was no such member function declared (C++ [class.mfct]p2,
- // C++ [namespace.memdef]p2). For example:
- //
- // class X {
- // void f() const;
- // };
- //
- // void X::f() { } // ill-formed
- //
- // Complain about this problem, and attempt to suggest close
- // matches (e.g., those that differ only in cv-qualifiers and
- // whether the parameter types are references).
- Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match)
- << Name << DC << D.getCXXScopeSpec().getRange();
- NewFD->setInvalidDecl();
-
- DiagnoseInvalidRedeclaration(*this, NewFD);
- }
+ // ignore these
+ } else {
+ // The user tried to provide an out-of-line definition for a
+ // function that is a member of a class or namespace, but there
+ // was no such member function declared (C++ [class.mfct]p2,
+ // C++ [namespace.memdef]p2). For example:
+ //
+ // class X {
+ // void f() const;
+ // };
+ //
+ // void X::f() { } // ill-formed
+ //
+ // Complain about this problem, and attempt to suggest close
+ // matches (e.g., those that differ only in cv-qualifiers and
+ // whether the parameter types are references).
+
+ if (NamedDecl *Result = DiagnoseInvalidRedeclaration(*this, Previous,
+ NewFD,
+ ExtraArgs)) {
+ AddToScope = ExtraArgs.AddToScope;
+ return Result;
+ }
+ }
// Unqualified local friend declarations are required to resolve
// to something.
- } else if (isFriend && cast<CXXRecordDecl>(CurContext)->isLocalClass()) {
- Diag(D.getIdentifierLoc(), diag::err_no_matching_local_friend);
- NewFD->setInvalidDecl();
- DiagnoseInvalidRedeclaration(*this, NewFD);
+ } else if (isFriend && cast<CXXRecordDecl>(CurContext)->isLocalClass()) {
+ if (NamedDecl *Result = DiagnoseInvalidRedeclaration(*this, Previous,
+ NewFD,
+ ExtraArgs)) {
+ AddToScope = ExtraArgs.AddToScope;
+ return Result;
}
+ }
- } else if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() &&
+ } else if (!D.isFunctionDefinition() && D.getCXXScopeSpec().isSet() &&
!isFriend && !isFunctionTemplateSpecialization &&
!isExplicitSpecialization) {
// An out-of-line member function declaration must also be a
@@ -4839,7 +5340,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// attributes declared post-definition are currently ignored
// FIXME: This should happen during attribute merging
- if (Redeclaration && Previous.isSingleResult()) {
+ if (D.isRedeclaration() && Previous.isSingleResult()) {
const FunctionDecl *Def;
FunctionDecl *PrevFD = dyn_cast<FunctionDecl>(Previous.getFoundDecl());
if (PrevFD && PrevFD->isDefined(Def) && D.hasAttributes()) {
@@ -4871,6 +5372,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (NewFD->getLinkage() == ExternalLinkage && !DC->isRecord())
AddPushedVisibilityAttribute(NewFD);
+ // If there's a #pragma clang arc_cf_code_audited in scope, consider
+ // marking the function.
+ AddCFAuditedAttribute(NewFD);
+
// If this is a locally-scoped extern C function, update the
// map of such names.
if (CurContext->isFunctionOrMethod() && NewFD->isExternC()
@@ -4901,6 +5406,18 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Context.setcudaConfigureCallDecl(NewFD);
}
}
+
+ // Here we have an function template explicit specialization at class scope.
+ // The actually specialization will be postponed to template instatiation
+ // time via the ClassScopeFunctionSpecializationDecl node.
+ if (isDependentClassScopeExplicitSpecialization) {
+ ClassScopeFunctionSpecializationDecl *NewSpec =
+ ClassScopeFunctionSpecializationDecl::Create(
+ Context, CurContext, SourceLocation(),
+ cast<CXXMethodDecl>(NewFD));
+ CurContext->addDecl(NewSpec);
+ AddToScope = false;
+ }
return NewFD;
}
@@ -4919,29 +5436,13 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
/// an explicit specialization of the previous declaration.
///
/// This sets NewFD->isInvalidDecl() to true if there was an error.
-void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
+///
+/// Returns true if the function declaration is a redeclaration.
+bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
LookupResult &Previous,
- bool IsExplicitSpecialization,
- bool &Redeclaration) {
- // If NewFD is already known erroneous, don't do any of this checking.
- if (NewFD->isInvalidDecl()) {
- // If this is a class member, mark the class invalid immediately.
- // This avoids some consistency errors later.
- if (isa<CXXMethodDecl>(NewFD))
- cast<CXXMethodDecl>(NewFD)->getParent()->setInvalidDecl();
-
- return;
- }
-
- if (NewFD->getResultType()->isVariablyModifiedType()) {
- // Functions returning a variably modified type violate C99 6.7.5.2p2
- // because all functions have linkage.
- Diag(NewFD->getLocation(), diag::err_vm_func_decl);
- return NewFD->setInvalidDecl();
- }
-
- if (NewFD->isMain())
- CheckMain(NewFD);
+ bool IsExplicitSpecialization) {
+ assert(!NewFD->getResultType()->isVariablyModifiedType()
+ && "Variably modified return types are not handled here");
// Check for a previous declaration of this name.
if (Previous.empty() && NewFD->isExternC()) {
@@ -4949,11 +5450,13 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// an extern "C" function, look for a non-visible extern "C"
// declaration with the same name.
llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
- = LocallyScopedExternalDecls.find(NewFD->getDeclName());
+ = findLocallyScopedExternalDecl(NewFD->getDeclName());
if (Pos != LocallyScopedExternalDecls.end())
Previous.addDecl(Pos->second);
}
+ bool Redeclaration = false;
+
// Merge or overload the declaration with an existing declaration of
// the same name, if appropriate.
if (!Previous.empty()) {
@@ -5003,8 +5506,10 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
if (Redeclaration) {
// NewFD and OldDecl represent declarations that need to be
// merged.
- if (MergeFunctionDecl(NewFD, OldDecl))
- return NewFD->setInvalidDecl();
+ if (MergeFunctionDecl(NewFD, OldDecl)) {
+ NewFD->setInvalidDecl();
+ return Redeclaration;
+ }
Previous.clear();
Previous.addDecl(OldDecl);
@@ -5028,6 +5533,10 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
NewTemplateDecl->setMemberSpecialization();
assert(OldTemplateDecl->isMemberSpecialization());
}
+
+ if (OldTemplateDecl->isModulePrivate())
+ NewTemplateDecl->setModulePrivate();
+
} else {
if (isa<CXXMethodDecl>(NewFD)) // Set access for out-of-line definitions
NewFD->setAccess(OldDecl->getAccess());
@@ -5054,7 +5563,8 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
Context.getCanonicalType(ClassType));
if (NewFD->getDeclName() != Name) {
Diag(NewFD->getLocation(), diag::err_destructor_name);
- return NewFD->setInvalidDecl();
+ NewFD->setInvalidDecl();
+ return Redeclaration;
}
}
} else if (CXXConversionDecl *Conversion
@@ -5086,13 +5596,17 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// Extra checking for C++ overloaded operators (C++ [over.oper]).
if (NewFD->isOverloadedOperator() &&
- CheckOverloadedOperatorDeclaration(NewFD))
- return NewFD->setInvalidDecl();
+ CheckOverloadedOperatorDeclaration(NewFD)) {
+ NewFD->setInvalidDecl();
+ return Redeclaration;
+ }
// Extra checking for C++0x literal operators (C++0x [over.literal]).
if (NewFD->getLiteralIdentifier() &&
- CheckLiteralOperatorDeclaration(NewFD))
- return NewFD->setInvalidDecl();
+ CheckLiteralOperatorDeclaration(NewFD)) {
+ NewFD->setInvalidDecl();
+ return Redeclaration;
+ }
// In C++, check default arguments now that we have merged decls. Unless
// the lexical context is the class, because in this case this is done
@@ -5112,24 +5626,22 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
}
}
}
+ return Redeclaration;
}
-void Sema::CheckMain(FunctionDecl* FD) {
+void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
// C++ [basic.start.main]p3: A program that declares main to be inline
// or static is ill-formed.
// C99 6.7.4p4: In a hosted environment, the inline function specifier
// shall not appear in a declaration of main.
// static main is not an error under C99, but we should warn about it.
- bool isInline = FD->isInlineSpecified();
- bool isStatic = FD->getStorageClass() == SC_Static;
- if (isInline || isStatic) {
- unsigned diagID = diag::warn_unusual_main_decl;
- if (isInline || getLangOptions().CPlusPlus)
- diagID = diag::err_unusual_main_decl;
-
- int which = isStatic + (isInline << 1) - 1;
- Diag(FD->getLocation(), diagID) << which;
- }
+ if (FD->getStorageClass() == SC_Static)
+ Diag(DS.getStorageClassSpecLoc(), getLangOptions().CPlusPlus
+ ? diag::err_static_main : diag::warn_static_main)
+ << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
+ if (FD->isInlineSpecified())
+ Diag(DS.getInlineSpecLoc(), diag::err_inline_main)
+ << FixItHint::CreateRemoval(DS.getInlineSpecLoc());
QualType T = FD->getType();
assert(T->isFunctionType() && "function decl is not of function type");
@@ -5152,7 +5664,7 @@ void Sema::CheckMain(FunctionDecl* FD) {
// Darwin passes an undocumented fourth argument of type char**. If
// other platforms start sprouting these, the logic below will start
// getting shifty.
- if (nparams == 4 && Context.Target.getTriple().isOSDarwin())
+ if (nparams == 4 && Context.getTargetInfo().getTriple().isOSDarwin())
HasExtraParameters = false;
if (HasExtraParameters) {
@@ -5231,41 +5743,89 @@ namespace {
: public EvaluatedExprVisitor<SelfReferenceChecker> {
Sema &S;
Decl *OrigDecl;
+ bool isRecordType;
+ bool isPODType;
public:
typedef EvaluatedExprVisitor<SelfReferenceChecker> Inherited;
SelfReferenceChecker(Sema &S, Decl *OrigDecl) : Inherited(S.Context),
- S(S), OrigDecl(OrigDecl) { }
+ S(S), OrigDecl(OrigDecl) {
+ isPODType = false;
+ isRecordType = false;
+ if (ValueDecl *VD = dyn_cast<ValueDecl>(OrigDecl)) {
+ isPODType = VD->getType().isPODType(S.Context);
+ isRecordType = VD->getType()->isRecordType();
+ }
+ }
void VisitExpr(Expr *E) {
if (isa<ObjCMessageExpr>(*E)) return;
+ if (isRecordType) {
+ Expr *expr = E;
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ ValueDecl *VD = ME->getMemberDecl();
+ if (isa<EnumConstantDecl>(VD) || isa<VarDecl>(VD)) return;
+ expr = ME->getBase();
+ }
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(expr)) {
+ HandleDeclRefExpr(DRE);
+ return;
+ }
+ }
Inherited::VisitExpr(E);
}
+ void VisitMemberExpr(MemberExpr *E) {
+ if (E->getType()->canDecayToPointerType()) return;
+ if (isa<FieldDecl>(E->getMemberDecl()))
+ if (DeclRefExpr *DRE
+ = dyn_cast<DeclRefExpr>(E->getBase()->IgnoreParenImpCasts())) {
+ HandleDeclRefExpr(DRE);
+ return;
+ }
+ Inherited::VisitMemberExpr(E);
+ }
+
void VisitImplicitCastExpr(ImplicitCastExpr *E) {
- CheckForSelfReference(E);
+ if ((!isRecordType &&E->getCastKind() == CK_LValueToRValue) ||
+ (isRecordType && E->getCastKind() == CK_NoOp)) {
+ Expr* SubExpr = E->getSubExpr()->IgnoreParenImpCasts();
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(SubExpr))
+ SubExpr = ME->getBase()->IgnoreParenImpCasts();
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SubExpr)) {
+ HandleDeclRefExpr(DRE);
+ return;
+ }
+ }
Inherited::VisitImplicitCastExpr(E);
}
- void CheckForSelfReference(ImplicitCastExpr *E) {
- if (E->getCastKind() != CK_LValueToRValue) return;
- Expr* SubExpr = E->getSubExpr()->IgnoreParenImpCasts();
- DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SubExpr);
- if (!DRE) return;
- Decl* ReferenceDecl = DRE->getDecl();
+ void VisitUnaryOperator(UnaryOperator *E) {
+ // For POD record types, addresses of its own members are well-defined.
+ if (isRecordType && isPODType) return;
+ Inherited::VisitUnaryOperator(E);
+ }
+
+ void HandleDeclRefExpr(DeclRefExpr *DRE) {
+ Decl* ReferenceDecl = DRE->getDecl();
if (OrigDecl != ReferenceDecl) return;
LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName,
Sema::NotForRedeclaration);
- S.DiagRuntimeBehavior(SubExpr->getLocStart(), SubExpr,
+ S.DiagRuntimeBehavior(DRE->getLocStart(), DRE,
S.PDiag(diag::warn_uninit_self_reference_in_init)
- << Result.getLookupName()
+ << Result.getLookupName()
<< OrigDecl->getLocation()
- << SubExpr->getSourceRange());
+ << DRE->getSourceRange());
}
};
}
+/// CheckSelfReference - Warns if OrigDecl is used in expression E.
+void Sema::CheckSelfReference(Decl* OrigDecl, Expr *E) {
+ SelfReferenceChecker(*this, OrigDecl).VisitExpr(E);
+}
+
/// AddInitializerToDecl - Adds the initializer Init to the
/// declaration dcl. If DirectInit is true, this is C++ direct
/// initialization rather than copy initialization.
@@ -5281,10 +5841,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// Variables declared within a function/method body are handled
// by a dataflow analysis.
if (!vd->hasLocalStorage() && !vd->isStaticLocal())
- SelfReferenceChecker(*this, RealDecl).VisitExpr(Init);
+ CheckSelfReference(RealDecl, Init);
}
else {
- SelfReferenceChecker(*this, RealDecl).VisitExpr(Init);
+ CheckSelfReference(RealDecl, Init);
}
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
@@ -5392,6 +5952,14 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
}
}
+ // OpenCL 1.1 6.5.2: "Variables allocated in the __local address space inside
+ // a kernel function cannot be initialized."
+ if (VDecl->getStorageClass() == SC_OpenCLWorkGroupLocal) {
+ Diag(VDecl->getLocation(), diag::err_local_cant_init);
+ VDecl->setInvalidDecl();
+ return;
+ }
+
// Capture the variable that is being initialized and the style of
// initialization.
InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
@@ -5456,11 +6024,26 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// A member-declarator can contain a constant-initializer only
// if it declares a static member (9.4) of const integral or
// const enumeration type, see 9.4.2.
+ //
+ // C++0x [class.static.data]p3:
+ // If a non-volatile const static data member is of integral or
+ // enumeration type, its declaration in the class definition can
+ // specify a brace-or-equal-initializer in which every initalizer-clause
+ // that is an assignment-expression is a constant expression. A static
+ // data member of literal type can be declared in the class definition
+ // with the constexpr specifier; if so, its declaration shall specify a
+ // brace-or-equal-initializer in which every initializer-clause that is
+ // an assignment-expression is a constant expression.
QualType T = VDecl->getType();
// Do nothing on dependent types.
if (T->isDependentType()) {
+ // Allow any 'static constexpr' members, whether or not they are of literal
+ // type. We separately check that the initializer is a constant expression,
+ // which implicitly requires the member to be of literal type.
+ } else if (VDecl->isConstexpr()) {
+
// Require constness.
} else if (!T.isConstQualified()) {
Diag(VDecl->getLocation(), diag::err_in_class_initializer_non_const)
@@ -5471,7 +6054,11 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
} else if (T->isIntegralOrEnumerationType()) {
// Check whether the expression is a constant expression.
SourceLocation Loc;
- if (Init->isValueDependent())
+ if (getLangOptions().CPlusPlus0x && T.isVolatileQualified())
+ // In C++0x, a non-constexpr const static data member with an
+ // in-class initializer cannot be volatile.
+ Diag(VDecl->getLocation(), diag::err_in_class_initializer_volatile);
+ else if (Init->isValueDependent())
; // Nothing to check.
else if (Init->isIntegerConstantExpr(Context, &Loc))
; // Ok, it's an ICE!
@@ -5488,31 +6075,33 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
VDecl->setInvalidDecl();
}
- // We allow floating-point constants as an extension in C++03, and
- // C++0x has far more complicated rules that we don't really
- // implement fully.
- } else {
- bool Allowed = false;
- if (getLangOptions().CPlusPlus0x) {
- Allowed = T->isLiteralType();
- } else if (T->isFloatingType()) { // also permits complex, which is ok
- Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type)
- << T << Init->getSourceRange();
- Allowed = true;
- }
-
- if (!Allowed) {
- Diag(VDecl->getLocation(), diag::err_in_class_initializer_bad_type)
- << T << Init->getSourceRange();
- VDecl->setInvalidDecl();
-
- // TODO: there are probably expressions that pass here that shouldn't.
- } else if (!Init->isValueDependent() &&
- !Init->isConstantInitializer(Context, false)) {
+ // We allow floating-point constants as an extension.
+ } else if (T->isFloatingType()) { // also permits complex, which is ok
+ Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type)
+ << T << Init->getSourceRange();
+ if (getLangOptions().CPlusPlus0x)
+ Diag(VDecl->getLocation(),
+ diag::note_in_class_initializer_float_type_constexpr)
+ << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr ");
+
+ if (!Init->isValueDependent() &&
+ !Init->isConstantInitializer(Context, false)) {
Diag(Init->getExprLoc(), diag::err_in_class_initializer_non_constant)
<< Init->getSourceRange();
VDecl->setInvalidDecl();
}
+
+ // Suggest adding 'constexpr' in C++0x for literal types.
+ } else if (getLangOptions().CPlusPlus0x && T->isLiteralType()) {
+ Diag(VDecl->getLocation(), diag::err_in_class_initializer_literal_type)
+ << T << Init->getSourceRange()
+ << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr ");
+ VDecl->setConstexpr(true);
+
+ } else {
+ Diag(VDecl->getLocation(), diag::err_in_class_initializer_bad_type)
+ << T << Init->getSourceRange();
+ VDecl->setInvalidDecl();
}
} else if (VDecl->isFileVarDecl()) {
if (VDecl->getStorageClassAsWritten() == SC_Extern &&
@@ -5547,33 +6136,23 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
VDecl->setType(DclT);
Init->setType(DclT);
}
-
-
- // If this variable is a local declaration with record type, make sure it
- // doesn't have a flexible member initialization. We only support this as a
- // global/static definition.
- if (VDecl->hasLocalStorage())
- if (const RecordType *RT = VDecl->getType()->getAs<RecordType>())
- if (RT->getDecl()->hasFlexibleArrayMember()) {
- // Check whether the initializer tries to initialize the flexible
- // array member itself to anything other than an empty initializer list.
- if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
- unsigned Index = std::distance(RT->getDecl()->field_begin(),
- RT->getDecl()->field_end()) - 1;
- if (Index < ILE->getNumInits() &&
- !(isa<InitListExpr>(ILE->getInit(Index)) &&
- cast<InitListExpr>(ILE->getInit(Index))->getNumInits() == 0)) {
- Diag(VDecl->getLocation(), diag::err_nonstatic_flexible_variable);
- VDecl->setInvalidDecl();
- }
- }
- }
// Check any implicit conversions within the expression.
CheckImplicitConversions(Init, VDecl->getLocation());
if (!VDecl->isInvalidDecl())
checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init);
+
+ if (VDecl->isConstexpr() && !VDecl->isInvalidDecl() &&
+ !VDecl->getType()->isDependentType() &&
+ !Init->isTypeDependent() && !Init->isValueDependent() &&
+ !Init->isConstantInitializer(Context,
+ VDecl->getType()->isReferenceType())) {
+ // FIXME: Improve this diagnostic to explain why the initializer is not
+ // a constant expression.
+ Diag(VDecl->getLocation(), diag::err_constexpr_var_requires_const_init)
+ << VDecl << Init->getSourceRange();
+ }
Init = MaybeCreateExprWithCleanups(Init);
// Attach the initializer to the decl.
@@ -5639,6 +6218,21 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
return;
}
+ // C++0x [dcl.constexpr]p9: An object or reference declared constexpr must
+ // have an initializer.
+ // C++0x [class.static.data]p3: A static data member can be declared with
+ // the constexpr specifier; if so, its declaration shall specify
+ // a brace-or-equal-initializer.
+ //
+ // A static data member's definition may inherit an initializer from an
+ // in-class declaration.
+ if (Var->isConstexpr() && !Var->getAnyInitializer()) {
+ Diag(Var->getLocation(), diag::err_constexpr_var_requires_init)
+ << Var->getDeclName();
+ Var->setInvalidDecl();
+ return;
+ }
+
switch (Var->isThisDeclarationADefinition()) {
case VarDecl::Definition:
if (!Var->isStaticDataMember() || !Var->getAnyInitializer())
@@ -5829,10 +6423,11 @@ void Sema::ActOnCXXForRangeDecl(Decl *D) {
case SC_Register:
Error = 4;
break;
+ case SC_OpenCLWorkGroupLocal:
+ llvm_unreachable("Unexpected storage class");
}
- // FIXME: constexpr isn't allowed here.
- //if (DS.isConstexprSpecified())
- // Error = 5;
+ if (VD->isConstexpr())
+ Error = 5;
if (Error != -1) {
Diag(VD->getOuterLocStart(), diag::err_for_range_storage_class)
<< VD->getDeclName() << Error;
@@ -5916,7 +6511,7 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
Sema::DeclGroupPtrTy
Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
Decl **Group, unsigned NumDecls) {
- llvm::SmallVector<Decl*, 8> Decls;
+ SmallVector<Decl*, 8> Decls;
if (DS.isTypeSpecOwned())
Decls.push_back(DS.getRepAsDecl());
@@ -5996,6 +6591,9 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
if (D.getDeclSpec().isThreadSpecified())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
+ if (D.getDeclSpec().isConstexprSpecified())
+ Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr)
+ << 0;
DiagnoseFunctionSpecifiers(D);
@@ -6074,6 +6672,12 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
ProcessDeclAttributes(S, New, D);
+ if (D.getDeclSpec().isModulePrivateSpecified())
+ Diag(New->getLocation(), diag::err_module_private_local)
+ << 1 << New->getDeclName()
+ << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc())
+ << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc());
+
if (New->hasAttr<BlocksAttr>()) {
Diag(New->getLocation(), diag::err_block_on_nonlocal);
}
@@ -6157,8 +6761,9 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
// - otherwise, it's an error
if (T->isArrayType()) {
if (!T.isConstQualified()) {
- Diag(NameLoc, diag::err_arc_array_param_no_ownership)
- << TSInfo->getTypeLoc().getSourceRange();
+ DelayedDiagnostics.add(
+ sema::DelayedDiagnostic::makeForbiddenType(
+ NameLoc, diag::err_arc_array_param_no_ownership, T, false));
}
lifetime = Qualifiers::OCL_ExplicitNone;
} else {
@@ -6185,8 +6790,10 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
// passed by reference.
if (T->isObjCObjectType()) {
Diag(NameLoc,
- diag::err_object_cannot_be_passed_returned_by_value) << 1 << T;
- New->setInvalidDecl();
+ diag::err_object_cannot_be_passed_returned_by_value) << 1 << T
+ << FixItHint::CreateInsertion(NameLoc, "*");
+ T = Context.getObjCObjectPointerType(T);
+ New->setType(T);
}
// ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage
@@ -6241,9 +6848,9 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope,
assert(D.isFunctionDeclarator() && "Not a function declarator!");
Scope *ParentScope = FnBodyScope->getParent();
+ D.setFunctionDefinition(true);
Decl *DP = HandleDeclarator(ParentScope, D,
- MultiTemplateParamsArg(*this),
- /*IsFunctionDefinition=*/true);
+ MultiTemplateParamsArg(*this));
return ActOnStartOfFunctionDef(FnBodyScope, DP);
}
@@ -6379,7 +6986,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
// dllimport attribute cannot be directly applied to definition.
// Microsoft accepts dllimport for functions defined within class scope.
if (!DA->isInherited() &&
- !(LangOpts.Microsoft && FD->getLexicalDeclContext()->isRecord())) {
+ !(LangOpts.MicrosoftExt && FD->getLexicalDeclContext()->isRecord())) {
Diag(FD->getLocation(),
diag::err_attribute_can_be_applied_only_to_symbol_declaration)
<< "dllimport";
@@ -6389,7 +6996,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
// Visual C++ appears to not think this is an issue, so only issue
// a warning when Microsoft extensions are disabled.
- if (!LangOpts.Microsoft) {
+ if (!LangOpts.MicrosoftExt) {
// If a symbol previously declared dllimport is later defined, the
// attribute is ignored in subsequent references, and a warning is
// emitted.
@@ -6417,7 +7024,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
/// FIXME: Employ a smarter algorithm that accounts for multiple return
/// statements and the lifetimes of the NRVO candidates. We should be able to
/// find a maximal set of NRVO variables.
-static void ComputeNRVO(Stmt *Body, FunctionScopeInfo *Scope) {
+void Sema::computeNRVO(Stmt *Body, FunctionScopeInfo *Scope) {
ReturnStmt **Returns = Scope->Returns.data();
const VarDecl *NRVOCandidate = 0;
@@ -6466,7 +7073,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// MSVC permits the use of pure specifier (=0) on function definition,
// defined at class scope, warn about this non standard construct.
- if (getLangOptions().Microsoft && FD->isPure())
+ if (getLangOptions().MicrosoftExt && FD->isPure())
Diag(FD->getLocation(), diag::warn_pure_function_definition);
if (!FD->isInvalidDecl()) {
@@ -6478,7 +7085,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(FD))
MarkVTableUsed(FD->getLocation(), Constructor->getParent());
- ComputeNRVO(Body, getCurFunction());
+ computeNRVO(Body, getCurFunction());
}
assert(FD == getCurFunctionDecl() && "Function parsing confused");
@@ -6491,11 +7098,27 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
DiagnoseUnusedParameters(MD->param_begin(), MD->param_end());
DiagnoseSizeOfParametersAndReturnValue(MD->param_begin(), MD->param_end(),
MD->getResultType(), MD);
+
+ if (Body)
+ computeNRVO(Body, getCurFunction());
+ }
+ if (ObjCShouldCallSuperDealloc) {
+ Diag(MD->getLocEnd(), diag::warn_objc_missing_super_dealloc);
+ ObjCShouldCallSuperDealloc = false;
+ }
+ if (ObjCShouldCallSuperFinalize) {
+ Diag(MD->getLocEnd(), diag::warn_objc_missing_super_finalize);
+ ObjCShouldCallSuperFinalize = false;
}
} else {
return 0;
}
+ assert(!ObjCShouldCallSuperDealloc && "This should only be set for "
+ "ObjC methods, which should have been handled in the block above.");
+ assert(!ObjCShouldCallSuperFinalize && "This should only be set for "
+ "ObjC methods, which should have been handled in the block above.");
+
// Verify and clean out per-function state.
if (Body) {
// C++ constructors that have function-try-blocks can't have return
@@ -6504,8 +7127,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (FD && isa<CXXConstructorDecl>(FD) && isa<CXXTryStmt>(Body))
DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body));
- // Verify that that gotos and switch cases don't jump into scopes illegally.
- // Verify that that gotos and switch cases don't jump into scopes illegally.
+ // Verify that gotos and switch cases don't jump into scopes illegally.
if (getCurFunction()->NeedsScopeChecking() &&
!dcl->isInvalidDecl() &&
!hasAnyUnrecoverableErrorsInThisFunction())
@@ -6532,6 +7154,10 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
ActivePolicy = &WP;
}
+ if (FD && FD->isConstexpr() && !FD->isInvalidDecl() &&
+ !CheckConstexprFunctionBody(FD, Body))
+ FD->setInvalidDecl();
+
assert(ExprTemporaries.empty() && "Leftover temporaries in function");
assert(!ExprNeedsCleanups && "Unaccounted cleanups in function");
}
@@ -6552,6 +7178,15 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
return dcl;
}
+
+/// When we finish delayed parsing of an attribute, we must attach it to the
+/// relevant Decl.
+void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D,
+ ParsedAttributes &Attrs) {
+ ProcessDeclAttributeList(S, D, Attrs.getList());
+}
+
+
/// ImplicitlyDefineFunction - An undeclared identifier was used in a function
/// call, forming a call to an implicitly defined function (per C99 6.5.1p2).
NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
@@ -6561,7 +7196,7 @@ 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
- = LocallyScopedExternalDecls.find(&II);
+ = findLocallyScopedExternalDecl(&II);
if (Pos != LocallyScopedExternalDecls.end()) {
Diag(Loc, diag::warn_use_out_of_scope_declaration) << Pos->second;
Diag(Pos->second->getLocation(), diag::note_previous_declaration);
@@ -6651,6 +7286,9 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context));
}
+ if (Context.BuiltinInfo.isReturnsTwice(BuiltinID) &&
+ !FD->getAttr<ReturnsTwiceAttr>())
+ FD->addAttr(::new (Context) ReturnsTwiceAttr(FD->getLocation(), Context));
if (Context.BuiltinInfo.isNoThrow(BuiltinID) && !FD->getAttr<NoThrowAttr>())
FD->addAttr(::new (Context) NoThrowAttr(FD->getLocation(), Context));
if (Context.BuiltinInfo.isConst(BuiltinID) && !FD->getAttr<ConstAttr>())
@@ -6712,6 +7350,16 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
return NewTD;
}
+ if (D.getDeclSpec().isModulePrivateSpecified()) {
+ if (CurContext->isFunctionOrMethod())
+ Diag(NewTD->getLocation(), diag::err_module_private_local)
+ << 2 << NewTD->getDeclName()
+ << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc())
+ << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc());
+ else
+ NewTD->setModulePrivate();
+ }
+
// C++ [dcl.typedef]p8:
// If the typedef declaration defines an unnamed class (or
// enum), the first typedef-name declared by the declaration
@@ -6853,6 +7501,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc, CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr, AccessSpecifier AS,
+ SourceLocation ModulePrivateLoc,
MultiTemplateParamsArg TemplateParameterLists,
bool &OwnedDecl, bool &IsDependent,
bool ScopedEnum, bool ScopedEnumUsesClassTag,
@@ -6892,6 +7541,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
DeclResult Result = CheckClassTemplate(S, TagSpec, TUK, KWLoc,
SS, Name, NameLoc, Attr,
TemplateParams, AS,
+ ModulePrivateLoc,
TemplateParameterLists.size() - 1,
(TemplateParameterList**) TemplateParameterLists.release());
return Result.get();
@@ -6934,7 +7584,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
UPPC_FixedUnderlyingType))
EnumUnderlying = Context.IntTy.getTypePtr();
- } else if (getLangOptions().Microsoft)
+ } else if (getLangOptions().MicrosoftExt)
// Microsoft enums are always of int type.
EnumUnderlying = Context.IntTy.getTypePtr();
}
@@ -7233,7 +7883,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// For our current ASTs this shouldn't be a problem, but will
// need to be changed with DeclGroups.
if ((TUK == TUK_Reference && (!PrevTagDecl->getFriendObjectKind() ||
- getLangOptions().Microsoft)) || TUK == TUK_Friend)
+ getLangOptions().MicrosoftExt)) || TUK == TUK_Friend)
return PrevTagDecl;
// Diagnose attempts to redefine a tag.
@@ -7385,7 +8035,7 @@ CreateNewDecl:
Diag(Def->getLocation(), diag::note_previous_definition);
} else {
unsigned DiagID = diag::ext_forward_ref_enum;
- if (getLangOptions().Microsoft)
+ if (getLangOptions().MicrosoftExt)
DiagID = diag::ext_ms_forward_ref_enum;
else if (getLangOptions().CPlusPlus)
DiagID = diag::err_forward_ref_enum;
@@ -7454,6 +8104,23 @@ CreateNewDecl:
AddMsStructLayoutForRecord(RD);
}
+ if (PrevDecl && PrevDecl->isModulePrivate())
+ New->setModulePrivate();
+ else if (ModulePrivateLoc.isValid()) {
+ if (isExplicitSpecialization)
+ Diag(New->getLocation(), diag::err_module_private_specialization)
+ << 2
+ << FixItHint::CreateRemoval(ModulePrivateLoc);
+ else if (PrevDecl && !PrevDecl->isModulePrivate())
+ diagnoseModulePrivateRedeclaration(New, PrevDecl, ModulePrivateLoc);
+ // __module_private__ does not apply to local classes. However, we only
+ // diagnose this as an error when the declaration specifiers are
+ // freestanding. Here, we just ignore the __module_private__.
+ // foobar
+ else if (!SearchDC->isFunctionOrMethod())
+ New->setModulePrivate();
+ }
+
// If this is a specialization of a member class (of a class template),
// check the specialization.
if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous))
@@ -7480,7 +8147,7 @@ CreateNewDecl:
// the tag name visible.
if (TUK == TUK_Friend)
New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty() ||
- getLangOptions().Microsoft);
+ getLangOptions().MicrosoftExt);
// Set the access specifier.
if (!Invalid && SearchDC->isRecord())
@@ -7530,6 +8197,16 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) {
PushDeclContext(S, Tag);
}
+Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) {
+ assert(isa<ObjCContainerDecl>(IDecl) &&
+ "ActOnObjCContainerStartDefinition - Not ObjCContainerDecl");
+ DeclContext *OCD = cast<DeclContext>(IDecl);
+ assert(getContainingDC(OCD) == CurContext &&
+ "The next DeclContext should be lexically contained in the current one.");
+ CurContext = OCD;
+ return IDecl;
+}
+
void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD,
SourceLocation FinalLoc,
SourceLocation LBraceLoc) {
@@ -7581,6 +8258,21 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD,
Consumer.HandleTagDeclDefinition(Tag);
}
+void Sema::ActOnObjCContainerFinishDefinition() {
+ // Exit this scope of this interface definition.
+ PopDeclContext();
+}
+
+void Sema::ActOnObjCTemporaryExitContainerContext() {
+ OriginalLexicalContext = CurContext;
+ ActOnObjCContainerFinishDefinition();
+}
+
+void Sema::ActOnObjCReenterContainerContext() {
+ ActOnObjCContainerStartDefinition(cast<Decl>(OriginalLexicalContext));
+ OriginalLexicalContext = 0;
+}
+
void Sema::ActOnTagDefinitionError(Scope *S, Decl *TagD) {
AdjustDeclIfTemplate(TagD);
TagDecl *Tag = cast<TagDecl>(TagD);
@@ -7669,7 +8361,7 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
/// ActOnField - Each field of a C struct/union is passed into this in order
/// to create a FieldDecl object for it.
Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart,
- Declarator &D, ExprTy *BitfieldWidth) {
+ Declarator &D, Expr *BitfieldWidth) {
FieldDecl *Res = HandleField(S, cast_or_null<RecordDecl>(TagD),
DeclStart, D, static_cast<Expr*>(BitfieldWidth),
/*HasInit=*/false, AS_public);
@@ -7703,6 +8395,9 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
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
LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration);
@@ -7735,6 +8430,9 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
if (NewFD->isInvalidDecl())
Record->setInvalidDecl();
+ if (D.getDeclSpec().isModulePrivateSpecified())
+ NewFD->setModulePrivate();
+
if (NewFD->isInvalidDecl() && PrevDecl) {
// Don't introduce NewFD into scope; there's already something
// with the same name in the same scope.
@@ -7968,8 +8666,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
}
}
- assert(0 && "found no user-declared constructors");
- return;
+ llvm_unreachable("found no user-declared constructors");
}
break;
@@ -8054,7 +8751,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
case CXXDestructor:
hasTrivial = &CXXRecordDecl::hasTrivialDestructor; break;
default:
- assert(0 && "unexpected special member"); return;
+ llvm_unreachable("unexpected special member");
}
// Check for nontrivial bases (and recurse).
@@ -8102,7 +8799,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
}
}
- assert(0 && "found no explanation for non-trivial member");
+ llvm_unreachable("found no explanation for non-trivial member");
}
/// TranslateIvarVisibility - Translate visibility from a token ID to an
@@ -8110,7 +8807,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
static ObjCIvarDecl::AccessControl
TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) {
switch (ivarVisibility) {
- default: assert(0 && "Unknown visitibility kind");
+ default: llvm_unreachable("Unknown visitibility kind");
case tok::objc_private: return ObjCIvarDecl::Private;
case tok::objc_public: return ObjCIvarDecl::Public;
case tok::objc_protected: return ObjCIvarDecl::Protected;
@@ -8122,8 +8819,7 @@ TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) {
/// in order to create an IvarDecl object for it.
Decl *Sema::ActOnIvar(Scope *S,
SourceLocation DeclStart,
- Decl *IntfDecl,
- Declarator &D, ExprTy *BitfieldWidth,
+ Declarator &D, Expr *BitfieldWidth,
tok::ObjCKeywordKind Visibility) {
IdentifierInfo *II = D.getIdentifier();
@@ -8165,7 +8861,7 @@ Decl *Sema::ActOnIvar(Scope *S,
Visibility != tok::objc_not_keyword ? TranslateIvarVisibility(Visibility)
: ObjCIvarDecl::None;
// Must set ivar's DeclContext to its enclosing interface.
- ObjCContainerDecl *EnclosingDecl = cast<ObjCContainerDecl>(IntfDecl);
+ ObjCContainerDecl *EnclosingDecl = cast<ObjCContainerDecl>(CurContext);
ObjCContainerDecl *EnclosingContext;
if (ObjCImplementationDecl *IMPDecl =
dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) {
@@ -8213,6 +8909,9 @@ Decl *Sema::ActOnIvar(Scope *S,
if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(NewID))
NewID->setInvalidDecl();
+ if (D.getDeclSpec().isModulePrivateSpecified())
+ NewID->setModulePrivate();
+
if (II) {
// FIXME: When interfaces are DeclContexts, we'll need to add
// these to the interface.
@@ -8227,23 +8926,19 @@ Decl *Sema::ActOnIvar(Scope *S,
/// 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, Decl *EnclosingDecl,
- llvm::SmallVectorImpl<Decl *> &AllIvarDecls) {
+void Sema::ActOnLastBitfield(SourceLocation DeclLoc,
+ SmallVectorImpl<Decl *> &AllIvarDecls) {
if (!LangOpts.ObjCNonFragileABI2 || AllIvarDecls.empty())
return;
Decl *ivarDecl = AllIvarDecls[AllIvarDecls.size()-1];
ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(ivarDecl);
- if (!Ivar->isBitField())
- return;
- uint64_t BitFieldSize =
- Ivar->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
- if (BitFieldSize == 0)
+ if (!Ivar->isBitField() || Ivar->getBitWidthValue(Context) == 0)
return;
- ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(EnclosingDecl);
+ ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CurContext);
if (!ID) {
- if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) {
+ if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(CurContext)) {
if (!CD->IsClassExtension())
return;
}
@@ -8252,13 +8947,14 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc, Decl *EnclosingDecl,
return;
}
// All conditions are met. Add a new bitfield to the tail end of ivars.
- llvm::APInt Zero(Context.getTypeSize(Context.CharTy), 0);
- Expr * BW = IntegerLiteral::Create(Context, Zero, Context.CharTy, DeclLoc);
+ llvm::APInt Zero(Context.getTypeSize(Context.IntTy), 0);
+ Expr * BW = IntegerLiteral::Create(Context, Zero, Context.IntTy, DeclLoc);
- Ivar = ObjCIvarDecl::Create(Context, cast<ObjCContainerDecl>(EnclosingDecl),
+ Ivar = ObjCIvarDecl::Create(Context, cast<ObjCContainerDecl>(CurContext),
DeclLoc, DeclLoc, 0,
Context.CharTy,
- Context.CreateTypeSourceInfo(Context.CharTy),
+ Context.getTrivialTypeSourceInfo(Context.CharTy,
+ DeclLoc),
ObjCIvarDecl::Private, BW,
true);
AllIvarDecls.push_back(Ivar);
@@ -8266,27 +8962,25 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc, Decl *EnclosingDecl,
void Sema::ActOnFields(Scope* S,
SourceLocation RecLoc, Decl *EnclosingDecl,
- Decl **Fields, unsigned NumFields,
+ llvm::ArrayRef<Decl *> Fields,
SourceLocation LBrac, SourceLocation RBrac,
AttributeList *Attr) {
assert(EnclosingDecl && "missing record or interface decl");
// If the decl this is being inserted into is invalid, then it may be a
// redeclaration or some other bogus case. Don't try to add fields to it.
- if (EnclosingDecl->isInvalidDecl()) {
- // FIXME: Deallocate fields?
+ if (EnclosingDecl->isInvalidDecl())
return;
- }
-
// Verify that all the fields are okay.
unsigned NumNamedMembers = 0;
- llvm::SmallVector<FieldDecl*, 32> RecFields;
+ SmallVector<FieldDecl*, 32> RecFields;
RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
bool ARCErrReported = false;
- for (unsigned i = 0; i != NumFields; ++i) {
- FieldDecl *FD = cast<FieldDecl>(Fields[i]);
+ for (llvm::ArrayRef<Decl *>::iterator i = Fields.begin(), end = Fields.end();
+ i != end; ++i) {
+ FieldDecl *FD = cast<FieldDecl>(*i);
// Get the type for the field.
const Type *FDTy = FD->getType().getTypePtr();
@@ -8321,25 +9015,26 @@ void Sema::ActOnFields(Scope* S,
EnclosingDecl->setInvalidDecl();
continue;
} else if (FDTy->isIncompleteArrayType() && Record &&
- ((i == NumFields - 1 && !Record->isUnion()) ||
- ((getLangOptions().Microsoft || getLangOptions().CPlusPlus) &&
- (i == NumFields - 1 || Record->isUnion())))) {
+ ((i + 1 == Fields.end() && !Record->isUnion()) ||
+ ((getLangOptions().MicrosoftExt ||
+ getLangOptions().CPlusPlus) &&
+ (i + 1 == Fields.end() || Record->isUnion())))) {
// Flexible array member.
// Microsoft and g++ is more permissive regarding flexible array.
// It will accept flexible array in union and also
// as the sole element of a struct/class.
- if (getLangOptions().Microsoft) {
+ if (getLangOptions().MicrosoftExt) {
if (Record->isUnion())
Diag(FD->getLocation(), diag::ext_flexible_array_union_ms)
<< FD->getDeclName();
- else if (NumFields == 1)
+ else if (Fields.size() == 1)
Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate_ms)
<< FD->getDeclName() << Record->getTagKind();
} else if (getLangOptions().CPlusPlus) {
if (Record->isUnion())
Diag(FD->getLocation(), diag::ext_flexible_array_union_gnu)
<< FD->getDeclName();
- else if (NumFields == 1)
+ else if (Fields.size() == 1)
Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate_gnu)
<< FD->getDeclName() << Record->getTagKind();
} else if (NumNamedMembers < 1) {
@@ -8376,7 +9071,7 @@ void Sema::ActOnFields(Scope* S,
// If this is a struct/class and this is not the last element, reject
// it. Note that GCC supports variable sized arrays in the middle of
// structures.
- if (i != NumFields-1)
+ if (i + 1 != Fields.end())
Diag(FD->getLocation(), diag::ext_variable_sized_type_in_struct)
<< FD->getDeclName() << FD->getType();
else {
@@ -8393,10 +9088,10 @@ void Sema::ActOnFields(Scope* S,
Record->setHasObjectMember(true);
} else if (FDTy->isObjCObjectType()) {
/// A field cannot be an Objective-c object
- Diag(FD->getLocation(), diag::err_statically_allocated_object);
- FD->setInvalidDecl();
- EnclosingDecl->setInvalidDecl();
- continue;
+ Diag(FD->getLocation(), diag::err_statically_allocated_object)
+ << FixItHint::CreateInsertion(FD->getLocation(), "*");
+ QualType T = Context.getObjCObjectPointerType(FD->getType());
+ FD->setType(T);
}
else if (!getLangOptions().CPlusPlus) {
if (getLangOptions().ObjCAutoRefCount && Record && !ARCErrReported) {
@@ -8421,7 +9116,7 @@ void Sema::ActOnFields(Scope* S,
}
}
else if (getLangOptions().ObjC1 &&
- getLangOptions().getGCMode() != LangOptions::NonGC &&
+ getLangOptions().getGC() != LangOptions::NonGC &&
Record && !Record->hasObjectMember()) {
if (FD->getType()->isObjCObjectPointerType() ||
FD->getType().isObjCGCStrong())
@@ -8650,7 +9345,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
SourceLocation IdLoc,
IdentifierInfo *Id,
Expr *Val) {
- unsigned IntWidth = Context.Target.getIntWidth();
+ unsigned IntWidth = Context.getTargetInfo().getIntWidth();
llvm::APSInt EnumVal(IntWidth);
QualType EltTy;
@@ -8691,7 +9386,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// ... if the initializing value of an enumerator cannot be
// represented by the underlying type, the program is ill-formed.
if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) {
- if (getLangOptions().Microsoft) {
+ if (getLangOptions().MicrosoftExt) {
Diag(IdLoc, diag::ext_enumerator_too_large) << EltTy;
Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).take();
} else
@@ -8806,7 +9501,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
SourceLocation IdLoc, IdentifierInfo *Id,
AttributeList *Attr,
- SourceLocation EqualLoc, ExprTy *val) {
+ SourceLocation EqualLoc, Expr *val) {
EnumDecl *TheEnumDecl = cast<EnumDecl>(theEnumDecl);
EnumConstantDecl *LastEnumConst =
cast_or_null<EnumConstantDecl>(lastEnumConst);
@@ -8894,9 +9589,9 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
// TODO: If the result value doesn't fit in an int, it must be a long or long
// long value. ISO C does not support this, but GCC does as an extension,
// emit a warning.
- unsigned IntWidth = Context.Target.getIntWidth();
- unsigned CharWidth = Context.Target.getCharWidth();
- unsigned ShortWidth = Context.Target.getShortWidth();
+ unsigned IntWidth = Context.getTargetInfo().getIntWidth();
+ unsigned CharWidth = Context.getTargetInfo().getCharWidth();
+ unsigned ShortWidth = Context.getTargetInfo().getShortWidth();
// Verify that all the values are okay, compute the size of the values, and
// reverse the list.
@@ -8969,12 +9664,12 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
BestType = Context.IntTy;
BestWidth = IntWidth;
} else {
- BestWidth = Context.Target.getLongWidth();
+ BestWidth = Context.getTargetInfo().getLongWidth();
if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth) {
BestType = Context.LongTy;
} else {
- BestWidth = Context.Target.getLongLongWidth();
+ BestWidth = Context.getTargetInfo().getLongLongWidth();
if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth)
Diag(Enum->getLocation(), diag::warn_enum_too_large);
@@ -9001,13 +9696,13 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
= (NumPositiveBits == BestWidth || !getLangOptions().CPlusPlus)
? Context.UnsignedIntTy : Context.IntTy;
} else if (NumPositiveBits <=
- (BestWidth = Context.Target.getLongWidth())) {
+ (BestWidth = Context.getTargetInfo().getLongWidth())) {
BestType = Context.UnsignedLongTy;
BestPromotionType
= (NumPositiveBits == BestWidth || !getLangOptions().CPlusPlus)
? Context.UnsignedLongTy : Context.LongTy;
} else {
- BestWidth = Context.Target.getLongLongWidth();
+ BestWidth = Context.getTargetInfo().getLongLongWidth();
assert(NumPositiveBits <= BestWidth &&
"How could an initializer get larger than ULL?");
BestType = Context.UnsignedLongLongTy;
@@ -9094,6 +9789,33 @@ Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
return New;
}
+DeclResult Sema::ActOnModuleImport(SourceLocation ImportLoc,
+ IdentifierInfo &ModuleName,
+ SourceLocation ModuleNameLoc) {
+ ModuleKey Module = PP.getModuleLoader().loadModule(ImportLoc,
+ ModuleName, ModuleNameLoc);
+ if (!Module)
+ return true;
+
+ // FIXME: Actually create a declaration to describe the module import.
+ (void)Module;
+ return DeclResult((Decl *)0);
+}
+
+void
+Sema::diagnoseModulePrivateRedeclaration(NamedDecl *New, NamedDecl *Old,
+ SourceLocation ModulePrivateKeyword) {
+ assert(!Old->isModulePrivate() && "Old is module-private!");
+
+ Diag(New->getLocation(), diag::err_module_private_follows_public)
+ << New->getDeclName() << SourceRange(ModulePrivateKeyword);
+ Diag(Old->getLocation(), diag::note_previous_declaration)
+ << Old->getDeclName();
+
+ // Drop the __module_private__ from the new declaration, since it's invalid.
+ New->setModulePrivate(false);
+}
+
void Sema::ActOnPragmaWeakID(IdentifierInfo* Name,
SourceLocation PragmaLoc,
SourceLocation NameLoc) {
@@ -9126,3 +9848,16 @@ void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name,
std::pair<IdentifierInfo*,WeakInfo>(AliasName, W));
}
}
+
+Decl *Sema::getObjCDeclContext() const {
+ return (dyn_cast_or_null<ObjCContainerDecl>(CurContext));
+}
+
+AvailabilityResult Sema::getCurContextAvailability() const {
+ const Decl *D = cast<Decl>(getCurLexicalContext());
+ // A category implicitly has the availability of the interface.
+ if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D))
+ D = CatD->getClassInterface();
+
+ return D->getAvailability();
+}
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 61b7b3ee05e3..69baf79ad0fe 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -15,19 +15,21 @@
#include "TargetAttributesSema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.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 "llvm/ADT/StringExtras.h"
using namespace clang;
using namespace sema;
/// These constants match the enumerated choices of
/// warn_attribute_wrong_decl_type and err_attribute_wrong_decl_type.
-enum {
+enum AttributeDeclKind {
ExpectedFunction,
ExpectedUnion,
ExpectedVariableOrFunction,
@@ -42,7 +44,8 @@ enum {
ExpectedClassMember,
ExpectedVariable,
ExpectedMethod,
- ExpectedVariableFunctionOrLabel
+ ExpectedVariableFunctionOrLabel,
+ ExpectedFieldOrGlobalVar
};
//===----------------------------------------------------------------------===//
@@ -194,6 +197,8 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
return RD->getIdentifier() == &Ctx.Idents.get("__CFString");
}
+/// \brief Check if the attribute has exactly as many args as Num. May
+/// output an error.
static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr,
unsigned int Num) {
if (Attr.getNumArgs() != Num) {
@@ -204,6 +209,140 @@ static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr,
return true;
}
+
+/// \brief Check if the attribute has at least as many args as Num. May
+/// output an error.
+static bool checkAttributeAtLeastNumArgs(Sema &S, const AttributeList &Attr,
+ unsigned int Num) {
+ if (Attr.getNumArgs() < Num) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_few_arguments) << Num;
+ return false;
+ }
+
+ return true;
+}
+
+///
+/// \brief Check if passed in Decl is a field or potentially shared global var
+/// \return true if the Decl is a field or potentially shared global variable
+///
+static bool mayBeSharedVariable(const Decl *D) {
+ if (isa<FieldDecl>(D))
+ return true;
+ if (const VarDecl *vd = dyn_cast<VarDecl>(D))
+ return (vd->hasGlobalStorage() && !(vd->isThreadSpecified()));
+
+ return false;
+}
+
+/// \brief Check if the passed-in expression is of type int or bool.
+static bool isIntOrBool(Expr *Exp) {
+ QualType QT = Exp->getType();
+ return QT->isBooleanType() || QT->isIntegerType();
+}
+
+///
+/// \brief Check if passed in Decl is a pointer type.
+/// Note that this function may produce an error message.
+/// \return true if the Decl is a pointer type; false otherwise
+///
+static bool checkIsPointer(Sema &S, const Decl *D, const AttributeList &Attr) {
+ if (const ValueDecl *vd = dyn_cast<ValueDecl>(D)) {
+ QualType QT = vd->getType();
+ if (QT->isAnyPointerType())
+ return true;
+ S.Diag(Attr.getLoc(), diag::warn_pointer_attribute_wrong_type)
+ << Attr.getName()->getName() << QT;
+ } else {
+ S.Diag(Attr.getLoc(), diag::err_attribute_can_be_applied_only_to_value_decl)
+ << Attr.getName();
+ }
+ return false;
+}
+
+/// \brief Checks that the passed in QualType either is of RecordType or points
+/// to RecordType. Returns the relevant RecordType, null if it does not exit.
+static const RecordType *getRecordType(QualType QT) {
+ if (const RecordType *RT = QT->getAs<RecordType>())
+ return RT;
+
+ // Now check if we point to record type.
+ if (const PointerType *PT = QT->getAs<PointerType>())
+ return PT->getPointeeType()->getAs<RecordType>();
+
+ return 0;
+}
+
+/// \brief Thread Safety Analysis: Checks that the passed in RecordType
+/// resolves to a lockable object. May flag an error.
+static bool checkForLockableRecord(Sema &S, Decl *D, const AttributeList &Attr,
+ const RecordType *RT) {
+ // Flag error if could not get record type for this argument.
+ if (!RT) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_class)
+ << Attr.getName();
+ return false;
+ }
+ // Flag error if the type is not lockable.
+ if (!RT->getDecl()->getAttr<LockableAttr>()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_lockable)
+ << Attr.getName();
+ return false;
+ }
+ return true;
+}
+
+/// \brief Thread Safety Analysis: Checks that all attribute arguments, starting
+/// from Sidx, resolve to a lockable object. May flag an error.
+/// \param Sidx The attribute argument index to start checking with.
+/// \param ParamIdxOk Whether an argument can be indexing into a function
+/// parameter list.
+static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
+ const AttributeList &Attr,
+ SmallVectorImpl<Expr*> &Args,
+ int Sidx = 0,
+ bool ParamIdxOk = false) {
+ for(unsigned Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) {
+ Expr *ArgExp = Attr.getArg(Idx);
+
+ if (ArgExp->isTypeDependent()) {
+ // FIXME -- need to processs this again on template instantiation
+ Args.push_back(ArgExp);
+ continue;
+ }
+
+ QualType ArgTy = ArgExp->getType();
+
+ // First see if we can just cast to record type, or point to record type.
+ const RecordType *RT = getRecordType(ArgTy);
+
+ // Now check if we index into a record type function param.
+ if(!RT && ParamIdxOk) {
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ IntegerLiteral *IL = dyn_cast<IntegerLiteral>(ArgExp);
+ if(FD && IL) {
+ unsigned int NumParams = FD->getNumParams();
+ llvm::APInt ArgValue = IL->getValue();
+ uint64_t ParamIdxFromOne = ArgValue.getZExtValue();
+ uint64_t ParamIdxFromZero = ParamIdxFromOne - 1;
+ if(!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_range)
+ << Attr.getName() << Idx + 1 << NumParams;
+ return false;
+ }
+ ArgTy = FD->getParamDecl(ParamIdxFromZero)->getType();
+ RT = getRecordType(ArgTy);
+ }
+ }
+
+ if (!checkForLockableRecord(S, D, Attr, RT))
+ return false;
+
+ Args.push_back(ArgExp);
+ }
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Attribute Implementations
//===----------------------------------------------------------------------===//
@@ -212,6 +351,324 @@ static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr,
// least add some helper functions to check most argument patterns (#
// and types of args).
+static void handleGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr,
+ bool pointer = false) {
+ assert(!Attr.isInvalid());
+
+ if (!checkAttributeNumArgs(S, Attr, 0))
+ return;
+
+ // D must be either a member field or global (potentially shared) variable.
+ if (!mayBeSharedVariable(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFieldOrGlobalVar;
+ return;
+ }
+
+ if (pointer && !checkIsPointer(S, D, Attr))
+ return;
+
+ if (pointer)
+ D->addAttr(::new (S.Context) PtGuardedVarAttr(Attr.getRange(), S.Context));
+ else
+ D->addAttr(::new (S.Context) GuardedVarAttr(Attr.getRange(), S.Context));
+}
+
+static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr,
+ bool pointer = false) {
+ assert(!Attr.isInvalid());
+
+ if (!checkAttributeNumArgs(S, Attr, 1))
+ return;
+
+ Expr *Arg = Attr.getArg(0);
+
+ // D must be either a member field or global (potentially shared) variable.
+ if (!mayBeSharedVariable(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFieldOrGlobalVar;
+ return;
+ }
+
+ if (pointer && !checkIsPointer(S, D, Attr))
+ return;
+
+ if (Arg->isTypeDependent())
+ // FIXME: handle attributes with dependent types
+ return;
+
+ // check that the argument is lockable object
+ if (!checkForLockableRecord(S, D, Attr, getRecordType(Arg->getType())))
+ return;
+
+ if (pointer)
+ D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getRange(),
+ S.Context, Arg));
+ else
+ D->addAttr(::new (S.Context) GuardedByAttr(Attr.getRange(), S.Context, Arg));
+}
+
+
+static void handleLockableAttr(Sema &S, Decl *D, const AttributeList &Attr,
+ bool scoped = false) {
+ assert(!Attr.isInvalid());
+
+ if (!checkAttributeNumArgs(S, Attr, 0))
+ return;
+
+ // FIXME: Lockable structs for C code.
+ if (!isa<CXXRecordDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedClass;
+ return;
+ }
+
+ if (scoped)
+ D->addAttr(::new (S.Context) ScopedLockableAttr(Attr.getRange(), S.Context));
+ else
+ D->addAttr(::new (S.Context) LockableAttr(Attr.getRange(), S.Context));
+}
+
+static void handleNoThreadSafetyAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ assert(!Attr.isInvalid());
+
+ if (!checkAttributeNumArgs(S, Attr, 0))
+ return;
+
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunctionOrMethod;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) NoThreadSafetyAnalysisAttr(Attr.getRange(),
+ S.Context));
+}
+
+static void handleAcquireOrderAttr(Sema &S, Decl *D, const AttributeList &Attr,
+ bool before) {
+ assert(!Attr.isInvalid());
+
+ if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
+ return;
+
+ // D must be either a member field or global (potentially shared) variable.
+ ValueDecl *VD = dyn_cast<ValueDecl>(D);
+ if (!VD || !mayBeSharedVariable(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFieldOrGlobalVar;
+ return;
+ }
+
+ // Check that this attribute only applies to lockable types
+ QualType QT = VD->getType();
+ if (!QT->isDependentType()) {
+ const RecordType *RT = getRecordType(QT);
+ if (!RT || !RT->getDecl()->getAttr<LockableAttr>()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_decl_not_lockable)
+ << Attr.getName();
+ return;
+ }
+ }
+
+ SmallVector<Expr*, 1> Args;
+ // check that all arguments are lockable objects
+ if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args))
+ return;
+
+ unsigned Size = Args.size();
+ assert(Size == Attr.getNumArgs());
+ Expr **StartArg = Size == 0 ? 0 : &Args[0];
+
+ if (before)
+ D->addAttr(::new (S.Context) AcquiredBeforeAttr(Attr.getRange(), S.Context,
+ StartArg, Size));
+ else
+ D->addAttr(::new (S.Context) AcquiredAfterAttr(Attr.getRange(), S.Context,
+ StartArg, Size));
+}
+
+static void handleLockFunAttr(Sema &S, Decl *D, const AttributeList &Attr,
+ bool exclusive = false) {
+ assert(!Attr.isInvalid());
+
+ // zero or more arguments ok
+
+ // check that the attribute is applied to a function
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunctionOrMethod;
+ return;
+ }
+
+ // check that all arguments are lockable objects
+ SmallVector<Expr*, 1> Args;
+ if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true))
+ return;
+
+ unsigned Size = Args.size();
+ assert(Size == Attr.getNumArgs());
+ Expr **StartArg = Size == 0 ? 0 : &Args[0];
+
+ if (exclusive)
+ D->addAttr(::new (S.Context) ExclusiveLockFunctionAttr(Attr.getRange(),
+ S.Context, StartArg,
+ Size));
+ else
+ D->addAttr(::new (S.Context) SharedLockFunctionAttr(Attr.getRange(),
+ S.Context, StartArg,
+ Size));
+}
+
+static void handleTrylockFunAttr(Sema &S, Decl *D, const AttributeList &Attr,
+ bool exclusive = false) {
+ assert(!Attr.isInvalid());
+
+ if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
+ return;
+
+
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunctionOrMethod;
+ return;
+ }
+
+ if (!isIntOrBool(Attr.getArg(0))) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_first_argument_not_int_or_bool)
+ << Attr.getName();
+ return;
+ }
+
+ SmallVector<Expr*, 2> Args;
+ // check that all arguments are lockable objects
+ if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 1))
+ return;
+
+ unsigned Size = Args.size();
+ Expr **StartArg = Size == 0 ? 0 : &Args[0];
+
+ if (exclusive)
+ D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(Attr.getRange(),
+ S.Context,
+ Attr.getArg(0),
+ StartArg, Size));
+ else
+ D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(Attr.getRange(),
+ S.Context,
+ Attr.getArg(0),
+ StartArg, Size));
+}
+
+static void handleLocksRequiredAttr(Sema &S, Decl *D, const AttributeList &Attr,
+ bool exclusive = false) {
+ assert(!Attr.isInvalid());
+
+ if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
+ return;
+
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunctionOrMethod;
+ return;
+ }
+
+ // check that all arguments are lockable objects
+ SmallVector<Expr*, 1> Args;
+ if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args))
+ return;
+
+ unsigned Size = Args.size();
+ assert(Size == Attr.getNumArgs());
+ Expr **StartArg = Size == 0 ? 0 : &Args[0];
+
+ if (exclusive)
+ D->addAttr(::new (S.Context) ExclusiveLocksRequiredAttr(Attr.getRange(),
+ S.Context, StartArg,
+ Size));
+ else
+ D->addAttr(::new (S.Context) SharedLocksRequiredAttr(Attr.getRange(),
+ S.Context, StartArg,
+ Size));
+}
+
+static void handleUnlockFunAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ assert(!Attr.isInvalid());
+
+ // zero or more arguments ok
+
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunctionOrMethod;
+ return;
+ }
+
+ // check that all arguments are lockable objects
+ SmallVector<Expr*, 1> Args;
+ if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true))
+ return;
+
+ unsigned Size = Args.size();
+ assert(Size == Attr.getNumArgs());
+ Expr **StartArg = Size == 0 ? 0 : &Args[0];
+
+ D->addAttr(::new (S.Context) UnlockFunctionAttr(Attr.getRange(), S.Context,
+ StartArg, Size));
+}
+
+static void handleLockReturnedAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ assert(!Attr.isInvalid());
+
+ if (!checkAttributeNumArgs(S, Attr, 1))
+ return;
+ Expr *Arg = Attr.getArg(0);
+
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunctionOrMethod;
+ return;
+ }
+
+ if (Arg->isTypeDependent())
+ return;
+
+ // check that the argument is lockable object
+ if (!checkForLockableRecord(S, D, Attr, getRecordType(Arg->getType())))
+ return;
+
+ D->addAttr(::new (S.Context) LockReturnedAttr(Attr.getRange(), S.Context, Arg));
+}
+
+static void handleLocksExcludedAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ assert(!Attr.isInvalid());
+
+ if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
+ return;
+
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunctionOrMethod;
+ return;
+ }
+
+ // check that all arguments are lockable objects
+ SmallVector<Expr*, 1> Args;
+ if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args))
+ return;
+
+ unsigned Size = Args.size();
+ assert(Size == Attr.getNumArgs());
+ Expr **StartArg = Size == 0 ? 0 : &Args[0];
+
+ D->addAttr(::new (S.Context) LocksExcludedAttr(Attr.getRange(), S.Context,
+ StartArg, Size));
+}
+
+
static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,
const AttributeList &Attr) {
TypedefNameDecl *tDecl = dyn_cast<TypedefNameDecl>(D);
@@ -261,7 +718,7 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
if (TagDecl *TD = dyn_cast<TagDecl>(D))
- TD->addAttr(::new (S.Context) PackedAttr(Attr.getLoc(), S.Context));
+ TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context));
else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
// If the alignment is less than or equal to 8 bits, the packed attribute
// has no effect.
@@ -270,14 +727,14 @@ 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.getLoc(), S.Context));
+ FD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context));
} else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
static void handleMsStructAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (TagDecl *TD = dyn_cast<TagDecl>(D))
- TD->addAttr(::new (S.Context) MsStructAttr(Attr.getLoc(), S.Context));
+ TD->addAttr(::new (S.Context) MsStructAttr(Attr.getRange(), S.Context));
else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
@@ -290,26 +747,48 @@ 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.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) IBActionAttr(Attr.getRange(), S.Context));
return;
}
S.Diag(Attr.getLoc(), diag::warn_attribute_ibaction) << Attr.getName();
}
+static bool checkIBOutletCommon(Sema &S, Decl *D, const AttributeList &Attr) {
+ // The IBOutlet/IBOutletCollection attributes only apply to instance
+ // variables or properties of Objective-C classes. The outlet must also
+ // have an object reference type.
+ if (const ObjCIvarDecl *VD = dyn_cast<ObjCIvarDecl>(D)) {
+ if (!VD->getType()->getAs<ObjCObjectPointerType>()) {
+ S.Diag(Attr.getLoc(), diag::err_iboutlet_object_type)
+ << Attr.getName() << VD->getType() << 0;
+ return false;
+ }
+ }
+ else if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) {
+ if (!PD->getType()->getAs<ObjCObjectPointerType>()) {
+ S.Diag(Attr.getLoc(), diag::err_iboutlet_object_type)
+ << Attr.getName() << PD->getType() << 1;
+ return false;
+ }
+ }
+ else {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName();
+ return false;
+ }
+
+ return true;
+}
+
static void handleIBOutlet(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (!checkAttributeNumArgs(S, Attr, 0))
return;
-
- // The IBOutlet attributes only apply to instance variables of
- // Objective-C classes.
- if (isa<ObjCIvarDecl>(D) || isa<ObjCPropertyDecl>(D)) {
- D->addAttr(::new (S.Context) IBOutletAttr(Attr.getLoc(), S.Context));
+
+ if (!checkIBOutletCommon(S, D, Attr))
return;
- }
- S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName();
+ D->addAttr(::new (S.Context) IBOutletAttr(Attr.getRange(), S.Context));
}
static void handleIBOutletCollection(Sema &S, Decl *D,
@@ -321,25 +800,9 @@ static void handleIBOutletCollection(Sema &S, Decl *D,
return;
}
- // The IBOutletCollection attributes only apply to instance variables of
- // Objective-C classes.
- if (!(isa<ObjCIvarDecl>(D) || isa<ObjCPropertyDecl>(D))) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName();
+ if (!checkIBOutletCommon(S, D, Attr))
return;
- }
- if (const ValueDecl *VD = dyn_cast<ValueDecl>(D))
- if (!VD->getType()->getAs<ObjCObjectPointerType>()) {
- S.Diag(Attr.getLoc(), diag::err_iboutletcollection_object_type)
- << VD->getType() << 0;
- return;
- }
- if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D))
- if (!PD->getType()->getAs<ObjCObjectPointerType>()) {
- S.Diag(Attr.getLoc(), diag::err_iboutletcollection_object_type)
- << PD->getType() << 1;
- return;
- }
-
+
IdentifierInfo *II = Attr.getParameterName();
if (!II)
II = &S.Context.Idents.get("id");
@@ -360,8 +823,8 @@ static void handleIBOutletCollection(Sema &S, Decl *D,
S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << II;
return;
}
- D->addAttr(::new (S.Context) IBOutletCollectionAttr(Attr.getLoc(), S.Context,
- QT));
+ D->addAttr(::new (S.Context) IBOutletCollectionAttr(Attr.getRange(),S.Context,
+ QT, Attr.getParameterLoc()));
}
static void possibleTransparentUnionPointerType(QualType &T) {
@@ -394,7 +857,7 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
// The nonnull attribute only applies to pointers.
- llvm::SmallVector<unsigned, 10> NonNullArgs;
+ SmallVector<unsigned, 10> NonNullArgs;
for (AttributeList::arg_iterator I=Attr.arg_begin(),
E=Attr.arg_end(); I!=E; ++I) {
@@ -466,7 +929,7 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
unsigned* start = &NonNullArgs[0];
unsigned size = NonNullArgs.size();
llvm::array_pod_sort(start, start + size);
- D->addAttr(::new (S.Context) NonNullAttr(Attr.getLoc(), S.Context, start,
+ D->addAttr(::new (S.Context) NonNullAttr(Attr.getRange(), S.Context, start,
size));
}
@@ -526,13 +989,13 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
bool HasImplicitThisParam = isInstanceMethod(D);
unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
- llvm::StringRef Module = AL.getParameterName()->getName();
+ StringRef Module = AL.getParameterName()->getName();
// Normalize the argument, __foo__ becomes foo.
if (Module.startswith("__") && Module.endswith("__"))
Module = Module.substr(2, Module.size() - 4);
- llvm::SmallVector<unsigned, 10> OwnershipArgs;
+ SmallVector<unsigned, 10> OwnershipArgs;
for (AttributeList::arg_iterator I = AL.arg_begin(), E = AL.arg_end(); I != E;
++I) {
@@ -712,18 +1175,18 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Arg = Arg->IgnoreParenCasts();
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
- if (Str == 0 || Str->isWide()) {
+ if (!Str || !Str->isAscii()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "weakref" << 1;
return;
}
// GCC will accept anything as the argument of weakref. Should we
// check for an existing decl?
- D->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context,
Str->getString()));
}
- D->addAttr(::new (S.Context) WeakRefAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) WeakRefAttr(Attr.getRange(), S.Context));
}
static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -737,20 +1200,20 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Arg = Arg->IgnoreParenCasts();
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
- if (Str == 0 || Str->isWide()) {
+ if (!Str || !Str->isAscii()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "alias" << 1;
return;
}
- if (S.Context.Target.getTriple().isOSDarwin()) {
+ if (S.Context.getTargetInfo().getTriple().isOSDarwin()) {
S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_darwin);
return;
}
// FIXME: check if target symbol exists in current file
- D->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context,
Str->getString()));
}
@@ -765,7 +1228,7 @@ static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) NakedAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) NakedAttr(Attr.getRange(), S.Context));
}
static void handleAlwaysInlineAttr(Sema &S, Decl *D,
@@ -782,7 +1245,7 @@ static void handleAlwaysInlineAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getRange(), S.Context));
}
static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -795,7 +1258,7 @@ 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.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) MallocAttr(Attr.getRange(), S.Context));
return;
}
}
@@ -808,13 +1271,13 @@ static void handleMayAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!checkAttributeNumArgs(S, Attr, 0))
return;
- D->addAttr(::new (S.Context) MayAliasAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) MayAliasAttr(Attr.getRange(), S.Context));
}
static void handleNoCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
assert(!Attr.isInvalid());
if (isa<VarDecl>(D))
- D->addAttr(::new (S.Context) NoCommonAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) NoCommonAttr(Attr.getRange(), S.Context));
else
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariable;
@@ -823,7 +1286,7 @@ 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.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) CommonAttr(Attr.getRange(), S.Context));
else
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariable;
@@ -840,7 +1303,7 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) {
return;
}
- D->addAttr(::new (S.Context) NoReturnAttr(attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) NoReturnAttr(attr.getRange(), S.Context));
}
bool Sema::CheckNoReturnAttr(const AttributeList &attr) {
@@ -874,7 +1337,7 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D,
}
}
- D->addAttr(::new (S.Context) AnalyzerNoReturnAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) AnalyzerNoReturnAttr(Attr.getRange(), S.Context));
}
// PS3 PPU-specific.
@@ -935,7 +1398,7 @@ static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) {
count++;
}
- D->addAttr(::new (S.Context) VecReturnAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) VecReturnAttr(Attr.getRange(), S.Context));
}
static void handleDependencyAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -961,7 +1424,24 @@ static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) UnusedAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) UnusedAttr(Attr.getRange(), S.Context));
+}
+
+static void handleReturnsTwiceAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ // check the attribute arguments.
+ if (Attr.hasParameterOrArguments()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (!isa<FunctionDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunction;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) ReturnsTwiceAttr(Attr.getRange(), S.Context));
}
static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -982,7 +1462,7 @@ static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) UsedAttr(Attr.getRange(), S.Context));
}
static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1011,7 +1491,7 @@ static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) ConstructorAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) ConstructorAttr(Attr.getRange(), S.Context,
priority));
}
@@ -1041,7 +1521,7 @@ static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) DestructorAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) DestructorAttr(Attr.getRange(), S.Context,
priority));
}
@@ -1053,7 +1533,7 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
// Handle the case where deprecated attribute has a text message.
- llvm::StringRef Str;
+ StringRef Str;
if (NumArgs == 1) {
StringLiteral *SE = dyn_cast<StringLiteral>(Attr.getArg(0));
if (!SE) {
@@ -1064,7 +1544,7 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Str = SE->getString();
}
- D->addAttr(::new (S.Context) DeprecatedAttr(Attr.getLoc(), S.Context, Str));
+ D->addAttr(::new (S.Context) DeprecatedAttr(Attr.getRange(), S.Context, Str));
}
static void handleUnavailableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1075,7 +1555,7 @@ static void handleUnavailableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
// Handle the case where unavailable attribute has a text message.
- llvm::StringRef Str;
+ StringRef Str;
if (NumArgs == 1) {
StringLiteral *SE = dyn_cast<StringLiteral>(Attr.getArg(0));
if (!SE) {
@@ -1085,7 +1565,7 @@ static void handleUnavailableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
Str = SE->getString();
}
- D->addAttr(::new (S.Context) UnavailableAttr(Attr.getLoc(), S.Context, Str));
+ D->addAttr(::new (S.Context) UnavailableAttr(Attr.getRange(), S.Context, Str));
}
static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D,
@@ -1097,7 +1577,7 @@ static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D,
}
D->addAttr(::new (S.Context) ArcWeakrefUnavailableAttr(
- Attr.getLoc(), S.Context));
+ Attr.getRange(), S.Context));
}
static void handleAvailabilityAttr(Sema &S, Decl *D,
@@ -1105,7 +1585,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
IdentifierInfo *Platform = Attr.getParameterName();
SourceLocation PlatformLoc = Attr.getParameterLoc();
- llvm::StringRef PlatformName
+ StringRef PlatformName
= AvailabilityAttr::getPrettyPlatformName(Platform->getName());
if (PlatformName.empty()) {
S.Diag(PlatformLoc, diag::warn_availability_unknown_platform)
@@ -1119,10 +1599,10 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted();
bool IsUnavailable = Attr.getUnavailableLoc().isValid();
- // Ensure that Introduced < Deprecated < Obsoleted (although not all
+ // Ensure that Introduced <= Deprecated <= Obsoleted (although not all
// of these steps are needed).
if (Introduced.isValid() && Deprecated.isValid() &&
- !(Introduced.Version < Deprecated.Version)) {
+ !(Introduced.Version <= Deprecated.Version)) {
S.Diag(Introduced.KeywordLoc, diag::warn_availability_version_ordering)
<< 1 << PlatformName << Deprecated.Version.getAsString()
<< 0 << Introduced.Version.getAsString();
@@ -1130,7 +1610,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
}
if (Introduced.isValid() && Obsoleted.isValid() &&
- !(Introduced.Version < Obsoleted.Version)) {
+ !(Introduced.Version <= Obsoleted.Version)) {
S.Diag(Introduced.KeywordLoc, diag::warn_availability_version_ordering)
<< 2 << PlatformName << Obsoleted.Version.getAsString()
<< 0 << Introduced.Version.getAsString();
@@ -1138,14 +1618,14 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
}
if (Deprecated.isValid() && Obsoleted.isValid() &&
- !(Deprecated.Version < Obsoleted.Version)) {
+ !(Deprecated.Version <= Obsoleted.Version)) {
S.Diag(Deprecated.KeywordLoc, diag::warn_availability_version_ordering)
<< 2 << PlatformName << Obsoleted.Version.getAsString()
<< 1 << Deprecated.Version.getAsString();
return;
}
- D->addAttr(::new (S.Context) AvailabilityAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) AvailabilityAttr(Attr.getRange(), S.Context,
Platform,
Introduced.Version,
Deprecated.Version,
@@ -1162,13 +1642,13 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Arg = Arg->IgnoreParenCasts();
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
- if (Str == 0 || Str->isWide()) {
+ if (!Str || !Str->isAscii()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "visibility" << 1;
return;
}
- llvm::StringRef TypeStr = Str->getString();
+ StringRef TypeStr = Str->getString();
VisibilityAttr::VisibilityType type;
if (TypeStr == "default")
@@ -1184,7 +1664,7 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) VisibilityAttr(Attr.getLoc(), S.Context, type));
+ D->addAttr(::new (S.Context) VisibilityAttr(Attr.getRange(), S.Context, type));
}
static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl,
@@ -1207,7 +1687,7 @@ static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl,
return;
}
- llvm::StringRef param = Attr.getParameterName()->getName();
+ StringRef param = Attr.getParameterName()->getName();
ObjCMethodFamilyAttr::FamilyKind family;
if (param == "none")
family = ObjCMethodFamilyAttr::OMF_None;
@@ -1236,7 +1716,7 @@ static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl,
return;
}
- method->addAttr(new (S.Context) ObjCMethodFamilyAttr(Attr.getLoc(),
+ method->addAttr(new (S.Context) ObjCMethodFamilyAttr(Attr.getRange(),
S.Context, family));
}
@@ -1251,7 +1731,7 @@ static void handleObjCExceptionAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) ObjCExceptionAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) ObjCExceptionAttr(Attr.getRange(), S.Context));
}
static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1267,7 +1747,7 @@ static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
}
- D->addAttr(::new (S.Context) ObjCNSObjectAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) ObjCNSObjectAttr(Attr.getRange(), S.Context));
}
static void
@@ -1282,7 +1762,7 @@ handleOverloadableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) OverloadableAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) OverloadableAttr(Attr.getRange(), S.Context));
}
static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1306,7 +1786,7 @@ static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) BlocksAttr(Attr.getLoc(), S.Context, type));
+ D->addAttr(::new (S.Context) BlocksAttr(Attr.getRange(), S.Context, type));
}
static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1316,7 +1796,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- int sentinel = 0;
+ unsigned sentinel = 0;
if (Attr.getNumArgs() > 0) {
Expr *E = Attr.getArg(0);
llvm::APSInt Idx(32);
@@ -1326,16 +1806,17 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
<< "sentinel" << 1 << E->getSourceRange();
return;
}
- sentinel = Idx.getZExtValue();
- if (sentinel < 0) {
+ if (Idx.isSigned() && Idx.isNegative()) {
S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_less_than_zero)
<< E->getSourceRange();
return;
}
+
+ sentinel = Idx.getZExtValue();
}
- int nullPos = 0;
+ unsigned nullPos = 0;
if (Attr.getNumArgs() > 1) {
Expr *E = Attr.getArg(1);
llvm::APSInt Idx(32);
@@ -1347,7 +1828,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
nullPos = Idx.getZExtValue();
- if (nullPos > 1 || nullPos < 0) {
+ if ((Idx.isSigned() && Idx.isNegative()) || nullPos > 1) {
// FIXME: This error message could be improved, it would be nice
// to say what the bounds actually are.
S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_not_zero_or_one)
@@ -1357,9 +1838,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- const FunctionType *FT = FD->getType()->getAs<FunctionType>();
- assert(FT && "FunctionDecl has non-function type?");
-
+ const FunctionType *FT = FD->getType()->castAs<FunctionType>();
if (isa<FunctionNoProtoType>(FT)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_named_arguments);
return;
@@ -1398,7 +1877,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
<< Attr.getName() << ExpectedFunctionMethodOrBlock;
return;
}
- D->addAttr(::new (S.Context) SentinelAttr(Attr.getLoc(), S.Context, sentinel,
+ D->addAttr(::new (S.Context) SentinelAttr(Attr.getRange(), S.Context, sentinel,
nullPos));
}
@@ -1425,7 +1904,7 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr)
return;
}
- D->addAttr(::new (S.Context) WarnUnusedResultAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) WarnUnusedResultAttr(Attr.getRange(), S.Context));
}
static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1449,7 +1928,7 @@ static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- nd->addAttr(::new (S.Context) WeakAttr(Attr.getLoc(), S.Context));
+ nd->addAttr(::new (S.Context) WeakAttr(Attr.getRange(), S.Context));
}
static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1466,7 +1945,7 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
diag::warn_attribute_weak_import_invalid_on_definition)
<< "weak_import" << 2 /*variable and function*/;
else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D) ||
- (S.Context.Target.getTriple().isOSDarwin() &&
+ (S.Context.getTargetInfo().getTriple().isOSDarwin() &&
isa<ObjCInterfaceDecl>(D))) {
// Nothing to warn about here.
} else
@@ -1476,7 +1955,7 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) WeakImportAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) WeakImportAttr(Attr.getRange(), S.Context));
}
static void handleReqdWorkGroupSize(Sema &S, Decl *D,
@@ -1497,7 +1976,7 @@ static void handleReqdWorkGroupSize(Sema &S, Decl *D,
}
WGSize[i] = (unsigned) ArgNum.getZExtValue();
}
- D->addAttr(::new (S.Context) ReqdWorkGroupSizeAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) ReqdWorkGroupSizeAttr(Attr.getRange(), S.Context,
WGSize[0], WGSize[1],
WGSize[2]));
}
@@ -1517,7 +1996,7 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
// If the target wants to validate the section specifier, make it happen.
- std::string Error = S.Context.Target.isValidSectionSpecifier(SE->getString());
+ std::string Error = S.Context.getTargetInfo().isValidSectionSpecifier(SE->getString());
if (!Error.empty()) {
S.Diag(SE->getLocStart(), diag::err_attribute_section_invalid_for_target)
<< Error;
@@ -1530,7 +2009,7 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) SectionAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) SectionAttr(Attr.getRange(), S.Context,
SE->getString()));
}
@@ -1544,9 +2023,9 @@ static void handleNothrowAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (NoThrowAttr *Existing = D->getAttr<NoThrowAttr>()) {
if (Existing->getLocation().isInvalid())
- Existing->setLocation(Attr.getLoc());
+ Existing->setRange(Attr.getRange());
} else {
- D->addAttr(::new (S.Context) NoThrowAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) NoThrowAttr(Attr.getRange(), S.Context));
}
}
@@ -1559,9 +2038,9 @@ static void handleConstAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (ConstAttr *Existing = D->getAttr<ConstAttr>()) {
if (Existing->getLocation().isInvalid())
- Existing->setLocation(Attr.getLoc());
+ Existing->setRange(Attr.getRange());
} else {
- D->addAttr(::new (S.Context) ConstAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) ConstAttr(Attr.getRange(), S.Context));
}
}
@@ -1570,7 +2049,7 @@ static void handlePureAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!checkAttributeNumArgs(S, Attr, 0))
return;
- D->addAttr(::new (S.Context) PureAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) PureAttr(Attr.getRange(), S.Context));
}
static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1629,7 +2108,7 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) CleanupAttr(Attr.getLoc(), S.Context, FD));
+ D->addAttr(::new (S.Context) CleanupAttr(Attr.getRange(), S.Context, FD));
S.MarkDeclarationReferenced(Attr.getParameterLoc(), FD);
}
@@ -1704,7 +2183,7 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) FormatArgAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) FormatArgAttr(Attr.getRange(), S.Context,
Idx.getZExtValue()));
}
@@ -1719,7 +2198,7 @@ enum FormatAttrKind {
/// getFormatAttrKind - Map from format attribute names to supported format
/// types.
-static FormatAttrKind getFormatAttrKind(llvm::StringRef Format) {
+static FormatAttrKind getFormatAttrKind(StringRef Format) {
// Check for formats that get handled specially.
if (Format == "NSString")
return NSStringFormat;
@@ -1788,7 +2267,7 @@ static void handleInitPriorityAttr(Sema &S, Decl *D,
Attr.setInvalid();
return;
}
- D->addAttr(::new (S.Context) InitPriorityAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) InitPriorityAttr(Attr.getRange(), S.Context,
prioritynum));
}
@@ -1819,7 +2298,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
unsigned FirstIdx = 1;
- llvm::StringRef Format = Attr.getParameterName()->getName();
+ StringRef Format = Attr.getParameterName()->getName();
// Normalize the argument, __foo__ becomes foo.
if (Format.startswith("__") && Format.endswith("__"))
@@ -1939,12 +2418,12 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// If we don't have a valid location for this attribute, adopt the
// location.
if (f->getLocation().isInvalid())
- f->setLocation(Attr.getLoc());
+ f->setRange(Attr.getRange());
return;
}
}
- D->addAttr(::new (S.Context) FormatAttr(Attr.getLoc(), S.Context, Format,
+ D->addAttr(::new (S.Context) FormatAttr(Attr.getRange(), S.Context, Format,
Idx.getZExtValue(),
FirstArg.getZExtValue()));
}
@@ -1970,7 +2449,7 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D,
return;
}
- if (!RD->isDefinition()) {
+ if (!RD->isCompleteDefinition()) {
S.Diag(Attr.getLoc(),
diag::warn_transparent_union_attribute_not_definition);
return;
@@ -2013,7 +2492,7 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D,
}
}
- RD->addAttr(::new (S.Context) TransparentUnionAttr(Attr.getLoc(), S.Context));
+ RD->addAttr(::new (S.Context) TransparentUnionAttr(Attr.getRange(), S.Context));
}
static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2030,7 +2509,15 @@ static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) {
S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate";
return;
}
- D->addAttr(::new (S.Context) AnnotateAttr(Attr.getLoc(), S.Context,
+
+ // Don't duplicate annotations that are already set.
+ for (specific_attr_iterator<AnnotateAttr>
+ i = D->specific_attr_begin<AnnotateAttr>(),
+ e = D->specific_attr_end<AnnotateAttr>(); i != e; ++i) {
+ if ((*i)->getAnnotation() == SE->getString())
+ return;
+ }
+ D->addAttr(::new (S.Context) AnnotateAttr(Attr.getRange(), S.Context,
SE->getString()));
}
@@ -2046,20 +2533,21 @@ static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// weaker alignment, rather than being silently ignored.
if (Attr.getNumArgs() == 0) {
- D->addAttr(::new (S.Context) AlignedAttr(Attr.getLoc(), S.Context, true, 0));
+ D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context, true, 0));
return;
}
- S.AddAlignedAttr(Attr.getLoc(), D, Attr.getArg(0));
+ S.AddAlignedAttr(Attr.getRange(), D, Attr.getArg(0));
}
-void Sema::AddAlignedAttr(SourceLocation AttrLoc, Decl *D, Expr *E) {
+void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E) {
if (E->isTypeDependent() || E->isValueDependent()) {
// Save dependent expressions in the AST to be instantiated.
- D->addAttr(::new (Context) AlignedAttr(AttrLoc, Context, true, E));
+ D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, E));
return;
}
+ SourceLocation AttrLoc = AttrRange.getBegin();
// FIXME: Cache the number on the Attr object?
llvm::APSInt Alignment(32);
if (!E->isIntegerConstantExpr(Alignment, Context)) {
@@ -2073,13 +2561,13 @@ void Sema::AddAlignedAttr(SourceLocation AttrLoc, Decl *D, Expr *E) {
return;
}
- D->addAttr(::new (Context) AlignedAttr(AttrLoc, Context, true, E));
+ D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, E));
}
-void Sema::AddAlignedAttr(SourceLocation AttrLoc, Decl *D, TypeSourceInfo *TS) {
+void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS) {
// FIXME: Cache the number on the Attr object if non-dependent?
// FIXME: Perform checking of type validity
- D->addAttr(::new (Context) AlignedAttr(AttrLoc, Context, false, TS));
+ D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, false, TS));
return;
}
@@ -2104,7 +2592,7 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- llvm::StringRef Str = Attr.getParameterName()->getName();
+ StringRef Str = Attr.getParameterName()->getName();
// Normalize the attribute name, __foo__ becomes foo.
if (Str.startswith("__") && Str.endswith("__"))
@@ -2136,13 +2624,13 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// FIXME: glibc uses 'word' to define register_t; this is narrower than a
// pointer on PIC16 and other embedded platforms.
if (Str == "word")
- DestWidth = S.Context.Target.getPointerWidth(0);
+ DestWidth = S.Context.getTargetInfo().getPointerWidth(0);
else if (Str == "byte")
- DestWidth = S.Context.Target.getCharWidth();
+ DestWidth = S.Context.getTargetInfo().getCharWidth();
break;
case 7:
if (Str == "pointer")
- DestWidth = S.Context.Target.getPointerWidth(0);
+ DestWidth = S.Context.getTargetInfo().getPointerWidth(0);
break;
}
@@ -2153,7 +2641,7 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
OldTy = VD->getType();
else {
S.Diag(D->getLocation(), diag::err_attr_wrong_decl)
- << "mode" << SourceRange(Attr.getLoc(), Attr.getLoc());
+ << "mode" << Attr.getRange();
return;
}
@@ -2216,12 +2704,12 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!IntegerMode)
NewTy = S.Context.DoubleTy;
else if (OldTy->isSignedIntegerType())
- if (S.Context.Target.getLongWidth() == 64)
+ if (S.Context.getTargetInfo().getLongWidth() == 64)
NewTy = S.Context.LongTy;
else
NewTy = S.Context.LongLongTy;
else
- if (S.Context.Target.getLongWidth() == 64)
+ if (S.Context.getTargetInfo().getLongWidth() == 64)
NewTy = S.Context.UnsignedLongTy;
else
NewTy = S.Context.UnsignedLongLongTy;
@@ -2264,7 +2752,7 @@ static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) NoDebugAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) NoDebugAttr(Attr.getRange(), S.Context));
}
static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2279,7 +2767,7 @@ static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) NoInlineAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) NoInlineAttr(Attr.getRange(), S.Context));
}
static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D,
@@ -2295,7 +2783,7 @@ static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) NoInstrumentFunctionAttr(Attr.getLoc(),
+ D->addAttr(::new (S.Context) NoInstrumentFunctionAttr(Attr.getRange(),
S.Context));
}
@@ -2313,7 +2801,7 @@ static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) CUDAConstantAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) CUDAConstantAttr(Attr.getRange(), S.Context));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "constant";
}
@@ -2333,7 +2821,7 @@ static void handleDeviceAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) CUDADeviceAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) CUDADeviceAttr(Attr.getRange(), S.Context));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "device";
}
@@ -2366,7 +2854,7 @@ static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) CUDAGlobalAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) CUDAGlobalAttr(Attr.getRange(), S.Context));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "global";
}
@@ -2385,7 +2873,7 @@ static void handleHostAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) CUDAHostAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) CUDAHostAttr(Attr.getRange(), S.Context));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "host";
}
@@ -2404,7 +2892,7 @@ static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) CUDASharedAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) CUDASharedAttr(Attr.getRange(), S.Context));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "shared";
}
@@ -2427,7 +2915,7 @@ static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) GNUInlineAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) GNUInlineAttr(Attr.getRange(), S.Context));
}
static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2447,31 +2935,31 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
switch (Attr.getKind()) {
case AttributeList::AT_fastcall:
- D->addAttr(::new (S.Context) FastCallAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) FastCallAttr(Attr.getRange(), S.Context));
return;
case AttributeList::AT_stdcall:
- D->addAttr(::new (S.Context) StdCallAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) StdCallAttr(Attr.getRange(), S.Context));
return;
case AttributeList::AT_thiscall:
- D->addAttr(::new (S.Context) ThisCallAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) ThisCallAttr(Attr.getRange(), S.Context));
return;
case AttributeList::AT_cdecl:
- D->addAttr(::new (S.Context) CDeclAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) CDeclAttr(Attr.getRange(), S.Context));
return;
case AttributeList::AT_pascal:
- D->addAttr(::new (S.Context) PascalAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) PascalAttr(Attr.getRange(), S.Context));
return;
case AttributeList::AT_pcs: {
Expr *Arg = Attr.getArg(0);
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
- if (Str == 0 || Str->isWide()) {
+ if (!Str || !Str->isAscii()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "pcs" << 1;
Attr.setInvalid();
return;
}
- llvm::StringRef StrRef = Str->getString();
+ StringRef StrRef = Str->getString();
PcsAttr::PCSType PCS;
if (StrRef == "aapcs")
PCS = PcsAttr::AAPCS;
@@ -2483,7 +2971,7 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) PcsAttr(Attr.getLoc(), S.Context, PCS));
+ D->addAttr(::new (S.Context) PcsAttr(Attr.getRange(), S.Context, PCS));
}
default:
llvm_unreachable("unexpected attribute kind");
@@ -2493,7 +2981,7 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
static void handleOpenCLKernelAttr(Sema &S, Decl *D, const AttributeList &Attr){
assert(!Attr.isInvalid());
- D->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getRange(), S.Context));
}
bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
@@ -2519,14 +3007,14 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
case AttributeList::AT_pcs: {
Expr *Arg = attr.getArg(0);
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
- if (Str == 0 || Str->isWide()) {
+ if (!Str || !Str->isAscii()) {
Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "pcs" << 1;
attr.setInvalid();
return true;
}
- llvm::StringRef StrRef = Str->getString();
+ StringRef StrRef = Str->getString();
if (StrRef == "aapcs") {
CC = CC_AAPCS;
break;
@@ -2555,7 +3043,7 @@ static void handleRegparmAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) RegparmAttr(Attr.getLoc(), S.Context, numParams));
+ D->addAttr(::new (S.Context) RegparmAttr(Attr.getRange(), S.Context, numParams));
}
/// Checks a regparm attribute, returning true if it is ill-formed and
@@ -2580,7 +3068,7 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) {
return true;
}
- if (Context.Target.getRegParmMax() == 0) {
+ if (Context.getTargetInfo().getRegParmMax() == 0) {
Diag(Attr.getLoc(), diag::err_attribute_regparm_wrong_platform)
<< NumParamsExpr->getSourceRange();
Attr.setInvalid();
@@ -2588,9 +3076,9 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) {
}
numParams = NumParams.getZExtValue();
- if (numParams > Context.Target.getRegParmMax()) {
+ if (numParams > Context.getTargetInfo().getRegParmMax()) {
Diag(Attr.getLoc(), diag::err_attribute_regparm_invalid_number)
- << Context.Target.getRegParmMax() << NumParamsExpr->getSourceRange();
+ << Context.getTargetInfo().getRegParmMax() << NumParamsExpr->getSourceRange();
Attr.setInvalid();
return true;
}
@@ -2635,7 +3123,7 @@ static void handleLaunchBoundsAttr(Sema &S, Decl *D, const AttributeList &Attr){
}
}
- D->addAttr(::new (S.Context) CUDALaunchBoundsAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) CUDALaunchBoundsAttr(Attr.getRange(), S.Context,
MaxThreads.getZExtValue(),
MinBlocks.getZExtValue()));
} else {
@@ -2648,17 +3136,21 @@ static void handleLaunchBoundsAttr(Sema &S, Decl *D, const AttributeList &Attr){
//===----------------------------------------------------------------------===//
static bool isValidSubjectOfNSAttribute(Sema &S, QualType type) {
- return type->isObjCObjectPointerType() || S.Context.isObjCNSObjectType(type);
+ return type->isDependentType() ||
+ type->isObjCObjectPointerType() ||
+ S.Context.isObjCNSObjectType(type);
}
static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) {
- return type->isPointerType() || isValidSubjectOfNSAttribute(S, type);
+ return type->isDependentType() ||
+ type->isPointerType() ||
+ isValidSubjectOfNSAttribute(S, type);
}
static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
ParmVarDecl *param = dyn_cast<ParmVarDecl>(D);
if (!param) {
S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type)
- << SourceRange(Attr.getLoc()) << Attr.getName() << ExpectedParameter;
+ << Attr.getRange() << Attr.getName() << ExpectedParameter;
return;
}
@@ -2673,25 +3165,25 @@ static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!typeOK) {
S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type)
- << SourceRange(Attr.getLoc()) << Attr.getName() << cf;
+ << Attr.getRange() << Attr.getName() << cf;
return;
}
if (cf)
- param->addAttr(::new (S.Context) CFConsumedAttr(Attr.getLoc(), S.Context));
+ param->addAttr(::new (S.Context) CFConsumedAttr(Attr.getRange(), S.Context));
else
- param->addAttr(::new (S.Context) NSConsumedAttr(Attr.getLoc(), S.Context));
+ param->addAttr(::new (S.Context) NSConsumedAttr(Attr.getRange(), S.Context));
}
static void handleNSConsumesSelfAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (!isa<ObjCMethodDecl>(D)) {
S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type)
- << SourceRange(Attr.getLoc()) << Attr.getName() << ExpectedMethod;
+ << Attr.getRange() << Attr.getName() << ExpectedMethod;
return;
}
- D->addAttr(::new (S.Context) NSConsumesSelfAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) NSConsumesSelfAttr(Attr.getRange(), S.Context));
}
static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
@@ -2710,7 +3202,7 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
returnType = FD->getResultType();
else {
S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type)
- << SourceRange(Attr.getLoc()) << Attr.getName()
+ << Attr.getRange() << Attr.getName()
<< ExpectedFunctionOrMethod;
return;
}
@@ -2735,53 +3227,143 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
if (!typeOK) {
S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
- << SourceRange(Attr.getLoc())
- << Attr.getName() << isa<ObjCMethodDecl>(D) << cf;
+ << Attr.getRange() << Attr.getName() << isa<ObjCMethodDecl>(D) << cf;
return;
}
switch (Attr.getKind()) {
default:
- assert(0 && "invalid ownership attribute");
- return;
+ llvm_unreachable("invalid ownership attribute");
case AttributeList::AT_ns_returns_autoreleased:
- D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(Attr.getLoc(),
+ D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(Attr.getRange(),
S.Context));
return;
case AttributeList::AT_cf_returns_not_retained:
- D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(Attr.getLoc(),
+ D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(Attr.getRange(),
S.Context));
return;
case AttributeList::AT_ns_returns_not_retained:
- D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(Attr.getLoc(),
+ D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(Attr.getRange(),
S.Context));
return;
case AttributeList::AT_cf_returns_retained:
- D->addAttr(::new (S.Context) CFReturnsRetainedAttr(Attr.getLoc(),
+ D->addAttr(::new (S.Context) CFReturnsRetainedAttr(Attr.getRange(),
S.Context));
return;
case AttributeList::AT_ns_returns_retained:
- D->addAttr(::new (S.Context) NSReturnsRetainedAttr(Attr.getLoc(),
+ D->addAttr(::new (S.Context) NSReturnsRetainedAttr(Attr.getRange(),
S.Context));
return;
};
}
+static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
+ const AttributeList &attr) {
+ SourceLocation loc = attr.getLoc();
+
+ ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(D);
+
+ if (!isa<ObjCMethodDecl>(method)) {
+ S.Diag(method->getLocStart(), diag::err_attribute_wrong_decl_type)
+ << SourceRange(loc, loc) << attr.getName() << 13 /* methods */;
+ return;
+ }
+
+ // Check that the method returns a normal pointer.
+ QualType resultType = method->getResultType();
+
+ if (!resultType->isReferenceType() &&
+ (!resultType->isPointerType() || resultType->isObjCRetainableType())) {
+ S.Diag(method->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
+ << SourceRange(loc)
+ << attr.getName() << /*method*/ 1 << /*non-retainable pointer*/ 2;
+
+ // Drop the attribute.
+ return;
+ }
+
+ method->addAttr(
+ ::new (S.Context) ObjCReturnsInnerPointerAttr(attr.getRange(), S.Context));
+}
+
+/// Handle cf_audited_transfer and cf_unknown_transfer.
+static void handleCFTransferAttr(Sema &S, Decl *D, const AttributeList &A) {
+ if (!isa<FunctionDecl>(D)) {
+ S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
+ << A.getRange() << A.getName() << 0 /*function*/;
+ return;
+ }
+
+ bool IsAudited = (A.getKind() == AttributeList::AT_cf_audited_transfer);
+
+ // Check whether there's a conflicting attribute already present.
+ Attr *Existing;
+ if (IsAudited) {
+ Existing = D->getAttr<CFUnknownTransferAttr>();
+ } else {
+ Existing = D->getAttr<CFAuditedTransferAttr>();
+ }
+ if (Existing) {
+ S.Diag(D->getLocStart(), diag::err_attributes_are_not_compatible)
+ << A.getName()
+ << (IsAudited ? "cf_unknown_transfer" : "cf_audited_transfer")
+ << A.getRange() << Existing->getRange();
+ return;
+ }
+
+ // All clear; add the attribute.
+ if (IsAudited) {
+ D->addAttr(
+ ::new (S.Context) CFAuditedTransferAttr(A.getRange(), S.Context));
+ } else {
+ D->addAttr(
+ ::new (S.Context) CFUnknownTransferAttr(A.getRange(), S.Context));
+ }
+}
+
+static void handleNSBridgedAttr(Sema &S, Scope *Sc, Decl *D,
+ const AttributeList &Attr) {
+ RecordDecl *RD = dyn_cast<RecordDecl>(D);
+ if (!RD || RD->isUnion()) {
+ S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
+ << Attr.getRange() << Attr.getName() << 14 /*struct */;
+ }
+
+ IdentifierInfo *ParmName = Attr.getParameterName();
+
+ // In Objective-C, verify that the type names an Objective-C type.
+ // We don't want to check this outside of ObjC because people sometimes
+ // do crazy C declarations of Objective-C types.
+ if (ParmName && S.getLangOptions().ObjC1) {
+ // Check for an existing type with this name.
+ LookupResult R(S, DeclarationName(ParmName), Attr.getParameterLoc(),
+ Sema::LookupOrdinaryName);
+ if (S.LookupName(R, Sc)) {
+ NamedDecl *Target = R.getFoundDecl();
+ if (Target && !isa<ObjCInterfaceDecl>(Target)) {
+ S.Diag(D->getLocStart(), diag::err_ns_bridged_not_interface);
+ S.Diag(Target->getLocStart(), diag::note_declared_at);
+ }
+ }
+ }
+
+ D->addAttr(::new (S.Context) NSBridgedAttr(Attr.getRange(), S.Context,
+ ParmName));
+}
+
static void handleObjCOwnershipAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (hasDeclarator(D)) return;
- SourceLocation L = Attr.getLoc();
S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
- << SourceRange(L, L) << Attr.getName() << 12 /* variable */;
+ << Attr.getRange() << Attr.getName() << 12 /* variable */;
}
static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (!isa<VarDecl>(D) && !isa<FieldDecl>(D)) {
- SourceLocation L = Attr.getLoc();
S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
- << SourceRange(L, L) << Attr.getName() << 12 /* variable */;
+ << Attr.getRange() << Attr.getName() << 12 /* variable */;
return;
}
@@ -2820,7 +3402,7 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
}
D->addAttr(::new (S.Context)
- ObjCPreciseLifetimeAttr(Attr.getLoc(), S.Context));
+ ObjCPreciseLifetimeAttr(Attr.getRange(), S.Context));
}
static bool isKnownDeclSpecAttr(const AttributeList &Attr) {
@@ -2834,20 +3416,20 @@ static bool isKnownDeclSpecAttr(const AttributeList &Attr) {
//===----------------------------------------------------------------------===//
static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (S.LangOpts.Microsoft || S.LangOpts.Borland) {
+ if (S.LangOpts.MicrosoftExt || S.LangOpts.Borland) {
// check the attribute arguments.
if (!checkAttributeNumArgs(S, Attr, 1))
return;
Expr *Arg = Attr.getArg(0);
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
- if (Str == 0 || Str->isWide()) {
+ if (!Str || !Str->isAscii()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "uuid" << 1;
return;
}
- llvm::StringRef StrRef = Str->getString();
+ StringRef StrRef = Str->getString();
bool IsCurly = StrRef.size() > 1 && StrRef.front() == '{' &&
StrRef.back() == '}';
@@ -2864,7 +3446,7 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or
// "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
- llvm::StringRef::iterator I = StrRef.begin();
+ StringRef::iterator I = StrRef.begin();
if (IsCurly) // Skip the optional '{'
++I;
@@ -2881,7 +3463,7 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
I++;
}
- D->addAttr(::new (S.Context) UuidAttr(Attr.getLoc(), S.Context,
+ D->addAttr(::new (S.Context) UuidAttr(Attr.getRange(), S.Context,
Str->getString()));
} else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "uuid";
@@ -2969,6 +3551,16 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_objc_precise_lifetime:
handleObjCPreciseLifetimeAttr(S, D, Attr); break;
+ case AttributeList::AT_objc_returns_inner_pointer:
+ handleObjCReturnsInnerPointerAttr(S, D, Attr); break;
+
+ case AttributeList::AT_ns_bridged:
+ handleNSBridgedAttr(S, scope, D, Attr); break;
+
+ case AttributeList::AT_cf_audited_transfer:
+ case AttributeList::AT_cf_unknown_transfer:
+ handleCFTransferAttr(S, D, Attr); break;
+
// Checker-specific.
case AttributeList::AT_cf_consumed:
case AttributeList::AT_ns_consumed: handleNSConsumedAttr (S, D, Attr); break;
@@ -2996,6 +3588,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
handleArcWeakrefUnavailableAttr (S, D, Attr);
break;
case AttributeList::AT_unused: handleUnusedAttr (S, D, Attr); break;
+ case AttributeList::AT_returns_twice:
+ 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_warn_unused_result: handleWarnUnusedResult(S, D, Attr);
@@ -3041,6 +3636,63 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_uuid:
handleUuidAttr(S, D, Attr);
break;
+
+ // Thread safety attributes:
+ case AttributeList::AT_guarded_var:
+ handleGuardedVarAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_pt_guarded_var:
+ handleGuardedVarAttr(S, D, Attr, /*pointer = */true);
+ break;
+ case AttributeList::AT_scoped_lockable:
+ handleLockableAttr(S, D, Attr, /*scoped = */true);
+ break;
+ case AttributeList::AT_no_thread_safety_analysis:
+ handleNoThreadSafetyAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_lockable:
+ handleLockableAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_guarded_by:
+ handleGuardedByAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_pt_guarded_by:
+ handleGuardedByAttr(S, D, Attr, /*pointer = */true);
+ break;
+ case AttributeList::AT_exclusive_lock_function:
+ handleLockFunAttr(S, D, Attr, /*exclusive = */true);
+ break;
+ case AttributeList::AT_exclusive_locks_required:
+ handleLocksRequiredAttr(S, D, Attr, /*exclusive = */true);
+ break;
+ case AttributeList::AT_exclusive_trylock_function:
+ handleTrylockFunAttr(S, D, Attr, /*exclusive = */true);
+ break;
+ case AttributeList::AT_lock_returned:
+ handleLockReturnedAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_locks_excluded:
+ handleLocksExcludedAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_shared_lock_function:
+ handleLockFunAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_shared_locks_required:
+ handleLocksRequiredAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_shared_trylock_function:
+ handleTrylockFunAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_unlock_function:
+ handleUnlockFunAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_acquired_before:
+ handleAcquireOrderAttr(S, D, Attr, /*before = */true);
+ break;
+ case AttributeList::AT_acquired_after:
+ handleAcquireOrderAttr(S, D, Attr, /*before = */false);
+ break;
+
default:
// Ask target about the attribute.
const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema();
@@ -3091,19 +3743,86 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
}
}
+// Annotation attributes are the only attributes allowed after an access
+// specifier.
+bool Sema::ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl,
+ const AttributeList *AttrList) {
+ for (const AttributeList* l = AttrList; l; l = l->getNext()) {
+ if (l->getKind() == AttributeList::AT_annotate) {
+ handleAnnotateAttr(*this, ASDecl, *l);
+ } else {
+ Diag(l->getLoc(), diag::err_only_annotate_after_access_spec);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/// checkUnusedDeclAttributes - Check a list of attributes to see if it
+/// contains any decl attributes that we should warn about.
+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->getKind() == AttributeList::IgnoredAttribute) continue;
+
+ if (A->getKind() == AttributeList::UnknownAttribute) {
+ S.Diag(A->getLoc(), diag::warn_unknown_attribute_ignored)
+ << A->getName() << A->getRange();
+ } else {
+ S.Diag(A->getLoc(), diag::warn_attribute_not_on_decl)
+ << A->getName() << A->getRange();
+ }
+ }
+}
+
+/// checkUnusedDeclAttributes - Given a declarator which is not being
+/// used to build a declaration, complain about any decl attributes
+/// which might be lying around on it.
+void Sema::checkUnusedDeclAttributes(Declarator &D) {
+ ::checkUnusedDeclAttributes(*this, D.getDeclSpec().getAttributes().getList());
+ ::checkUnusedDeclAttributes(*this, D.getAttributes());
+ for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i)
+ ::checkUnusedDeclAttributes(*this, D.getTypeObject(i).getAttrs());
+}
+
/// DeclClonePragmaWeak - clone existing decl (maybe definition),
/// #pragma weak needs a non-definition decl and source may not have one
-NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) {
+NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
+ SourceLocation Loc) {
assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND));
NamedDecl *NewD = 0;
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
- NewD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(),
- FD->getInnerLocStart(),
- FD->getLocation(), DeclarationName(II),
- FD->getType(), FD->getTypeSourceInfo());
- if (FD->getQualifier()) {
- FunctionDecl *NewFD = cast<FunctionDecl>(NewD);
+ FunctionDecl *NewFD;
+ // FIXME: Missing call to CheckFunctionDeclaration().
+ // FIXME: Mangling?
+ // FIXME: Is the qualifier info correct?
+ // FIXME: Is the DeclContext correct?
+ NewFD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(),
+ Loc, Loc, DeclarationName(II),
+ FD->getType(), FD->getTypeSourceInfo(),
+ SC_None, SC_None,
+ false/*isInlineSpecified*/,
+ FD->hasPrototype(),
+ false/*isConstexprSpecified*/);
+ NewD = NewFD;
+
+ if (FD->getQualifier())
NewFD->setQualifierInfo(FD->getQualifierLoc());
+
+ // Fake up parameter variables; they are declared as if this were
+ // a typedef.
+ QualType FDTy = FD->getType();
+ if (const FunctionProtoType *FT = FDTy->getAs<FunctionProtoType>()) {
+ SmallVector<ParmVarDecl*, 16> Params;
+ for (FunctionProtoType::arg_type_iterator AI = FT->arg_type_begin(),
+ AE = FT->arg_type_end(); AI != AE; ++AI) {
+ ParmVarDecl *Param = BuildParmVarDeclForTypedef(NewFD, Loc, *AI);
+ Param->setScopeInfo(0, Params.size());
+ Params.push_back(Param);
+ }
+ NewFD->setParams(Params);
}
} else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) {
NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(),
@@ -3126,7 +3845,7 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
W.setUsed(true);
if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...))
IdentifierInfo *NDId = ND->getIdentifier();
- NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias());
+ NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias(), W.getLocation());
NewD->addAttr(::new (Context) AliasAttr(W.getLocation(), Context,
NDId->getName()));
NewD->addAttr(::new (Context) WeakAttr(W.getLocation(), Context));
@@ -3149,15 +3868,18 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD,
bool NonInheritable, bool Inheritable) {
// It's valid to "forward-declare" #pragma weak, in which case we
// have to do this.
- if (Inheritable && !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;
+ 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;
+ }
}
}
}
@@ -3185,7 +3907,9 @@ static bool isForbiddenTypeAllowed(Sema &S, Decl *decl) {
// Private ivars are always okay. Unfortunately, people don't
// always properly make their ivars private, even in system headers.
// Plus we need to make fields okay, too.
- if (!isa<FieldDecl>(decl) && !isa<ObjCPropertyDecl>(decl))
+ // Function declarations in sys headers will be marked unavailable.
+ if (!isa<FieldDecl>(decl) && !isa<ObjCPropertyDecl>(decl) &&
+ !isa<FunctionDecl>(decl))
return false;
// Require it to be declared in a system header.
@@ -3200,6 +3924,17 @@ static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag,
"this system declaration uses an unsupported type"));
return;
}
+ if (S.getLangOptions().ObjCAutoRefCount)
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(decl)) {
+ // FIXME. we may want to supress diagnostics for all
+ // kind of forbidden type messages on unavailable functions.
+ if (FD->hasAttr<UnavailableAttr>() &&
+ diag.getForbiddenTypeDiagnostic() ==
+ diag::err_arc_array_param_no_ownership) {
+ diag.Triggered = true;
+ return;
+ }
+ }
S.Diag(diag.Loc, diag.getForbiddenTypeDiagnostic())
<< diag.getForbiddenTypeOperand() << diag.getForbiddenTypeArgument();
@@ -3287,6 +4022,9 @@ static bool isDeclDeprecated(Decl *D) {
do {
if (D->isDeprecated())
return true;
+ // A category implicitly has the availability of the interface.
+ if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D))
+ return CatD->getClassInterface()->isDeprecated();
} while ((D = cast_or_null<Decl>(D->getDeclContext())));
return false;
}
@@ -3306,7 +4044,7 @@ void Sema::HandleDelayedDeprecationCheck(DelayedDiagnostic &DD,
<< DD.getDeprecationDecl()->getDeclName();
}
-void Sema::EmitDeprecationWarning(NamedDecl *D, llvm::StringRef Message,
+void Sema::EmitDeprecationWarning(NamedDecl *D, StringRef Message,
SourceLocation Loc,
const ObjCInterfaceDecl *UnknownObjCClass) {
// Delay if we're currently parsing a declaration.
@@ -3316,7 +4054,7 @@ void Sema::EmitDeprecationWarning(NamedDecl *D, llvm::StringRef Message,
}
// Otherwise, don't warn if our current context is deprecated.
- if (isDeclDeprecated(cast<Decl>(CurContext)))
+ if (isDeclDeprecated(cast<Decl>(getCurLexicalContext())))
return;
if (!Message.empty())
Diag(Loc, diag::warn_deprecated_message) << D->getDeclName()
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index d793daf9d826..a39584a107a8 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -392,7 +392,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
// MSVC accepts that default parameters be redefined for member functions
// of template class. The new default parameter's value is ignored.
Invalid = true;
- if (getLangOptions().Microsoft) {
+ if (getLangOptions().MicrosoftExt) {
CXXMethodDecl* MD = dyn_cast<CXXMethodDecl>(New);
if (MD && MD->getParent()->getDescribedClassTemplate()) {
// Merge the old default argument into the new parameter.
@@ -502,6 +502,20 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
}
}
+ // C++0x [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. [Note: An explicit specialization can
+ // differ from the template declaration with respect to the constexpr
+ // specifier. -- end note]
+ //
+ // FIXME: Don't reject changes in constexpr in explicit specializations.
+ if (New->isConstexpr() != Old->isConstexpr()) {
+ Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
+ << New << New->isConstexpr();
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ Invalid = true;
+ }
+
if (CheckEquivalentExceptionSpec(Old, New))
Invalid = true;
@@ -602,6 +616,363 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
}
}
+// CheckConstexprParameterTypes - Check whether a function's parameter types
+// are all literal types. If so, return true. If not, produce a suitable
+// diagnostic depending on @p CCK and return false.
+static bool CheckConstexprParameterTypes(Sema &SemaRef, const FunctionDecl *FD,
+ Sema::CheckConstexprKind CCK) {
+ unsigned ArgIndex = 0;
+ const FunctionProtoType *FT = FD->getType()->getAs<FunctionProtoType>();
+ for (FunctionProtoType::arg_type_iterator i = FT->arg_type_begin(),
+ e = FT->arg_type_end(); i != e; ++i, ++ArgIndex) {
+ const ParmVarDecl *PD = FD->getParamDecl(ArgIndex);
+ SourceLocation ParamLoc = PD->getLocation();
+ if (!(*i)->isDependentType() &&
+ SemaRef.RequireLiteralType(ParamLoc, *i, CCK == Sema::CCK_Declaration ?
+ SemaRef.PDiag(diag::err_constexpr_non_literal_param)
+ << ArgIndex+1 << PD->getSourceRange()
+ << isa<CXXConstructorDecl>(FD) :
+ SemaRef.PDiag(),
+ /*AllowIncompleteType*/ true)) {
+ if (CCK == Sema::CCK_NoteNonConstexprInstantiation)
+ SemaRef.Diag(ParamLoc, diag::note_constexpr_tmpl_non_literal_param)
+ << ArgIndex+1 << PD->getSourceRange()
+ << isa<CXXConstructorDecl>(FD) << *i;
+ return false;
+ }
+ }
+ return true;
+}
+
+// CheckConstexprFunctionDecl - Check whether a function declaration satisfies
+// the requirements of a constexpr function declaration or a constexpr
+// constructor declaration. Return true if it does, false if not.
+//
+// This implements C++0x [dcl.constexpr]p3,4, as amended by N3308.
+//
+// \param CCK Specifies whether to produce diagnostics if the function does not
+// satisfy the requirements.
+bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD,
+ CheckConstexprKind CCK) {
+ assert((CCK != CCK_NoteNonConstexprInstantiation ||
+ (NewFD->getTemplateInstantiationPattern() &&
+ NewFD->getTemplateInstantiationPattern()->isConstexpr())) &&
+ "only constexpr templates can be instantiated non-constexpr");
+
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(NewFD)) {
+ // C++0x [dcl.constexpr]p4:
+ // In the definition of a constexpr constructor, each of the parameter
+ // types shall be a literal type.
+ if (!CheckConstexprParameterTypes(*this, NewFD, CCK))
+ return false;
+
+ // In addition, either its function-body shall be = delete or = default or
+ // it shall satisfy the following constraints:
+ // - the class shall not have any virtual base classes;
+ const CXXRecordDecl *RD = CD->getParent();
+ if (RD->getNumVBases()) {
+ // Note, this is still illegal if the body is = default, since the
+ // implicit body does not satisfy the requirements of a constexpr
+ // constructor. We also reject cases where the body is = delete, as
+ // required by N3308.
+ if (CCK != CCK_Instantiation) {
+ Diag(NewFD->getLocation(),
+ CCK == CCK_Declaration ? diag::err_constexpr_virtual_base
+ : diag::note_constexpr_tmpl_virtual_base)
+ << RD->isStruct() << RD->getNumVBases();
+ for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+ E = RD->vbases_end(); I != E; ++I)
+ Diag(I->getSourceRange().getBegin(),
+ diag::note_constexpr_virtual_base_here) << I->getSourceRange();
+ }
+ return false;
+ }
+ } else {
+ // C++0x [dcl.constexpr]p3:
+ // The definition of a constexpr function shall satisfy the following
+ // constraints:
+ // - it shall not be virtual;
+ const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD);
+ if (Method && Method->isVirtual()) {
+ if (CCK != CCK_Instantiation) {
+ Diag(NewFD->getLocation(),
+ CCK == CCK_Declaration ? diag::err_constexpr_virtual
+ : diag::note_constexpr_tmpl_virtual);
+
+ // If it's not obvious why this function is virtual, find an overridden
+ // function which uses the 'virtual' keyword.
+ const CXXMethodDecl *WrittenVirtual = Method;
+ while (!WrittenVirtual->isVirtualAsWritten())
+ WrittenVirtual = *WrittenVirtual->begin_overridden_methods();
+ if (WrittenVirtual != Method)
+ Diag(WrittenVirtual->getLocation(),
+ diag::note_overridden_virtual_function);
+ }
+ return false;
+ }
+
+ // - its return type shall be a literal type;
+ QualType RT = NewFD->getResultType();
+ if (!RT->isDependentType() &&
+ RequireLiteralType(NewFD->getLocation(), RT, CCK == CCK_Declaration ?
+ PDiag(diag::err_constexpr_non_literal_return) :
+ PDiag(),
+ /*AllowIncompleteType*/ true)) {
+ if (CCK == CCK_NoteNonConstexprInstantiation)
+ Diag(NewFD->getLocation(),
+ diag::note_constexpr_tmpl_non_literal_return) << RT;
+ return false;
+ }
+
+ // - each of its parameter types shall be a literal type;
+ if (!CheckConstexprParameterTypes(*this, NewFD, CCK))
+ return false;
+ }
+
+ return true;
+}
+
+/// Check the given declaration statement is legal within a constexpr function
+/// body. C++0x [dcl.constexpr]p3,p4.
+///
+/// \return true if the body is OK, false if we have diagnosed a problem.
+static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
+ DeclStmt *DS) {
+ // C++0x [dcl.constexpr]p3 and p4:
+ // The definition of a constexpr function(p3) or constructor(p4) [...] shall
+ // contain only
+ for (DeclStmt::decl_iterator DclIt = DS->decl_begin(),
+ DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt) {
+ switch ((*DclIt)->getKind()) {
+ case Decl::StaticAssert:
+ case Decl::Using:
+ case Decl::UsingShadow:
+ case Decl::UsingDirective:
+ case Decl::UnresolvedUsingTypename:
+ // - static_assert-declarations
+ // - using-declarations,
+ // - using-directives,
+ continue;
+
+ case Decl::Typedef:
+ case Decl::TypeAlias: {
+ // - typedef declarations and alias-declarations that do not define
+ // classes or enumerations,
+ TypedefNameDecl *TN = cast<TypedefNameDecl>(*DclIt);
+ if (TN->getUnderlyingType()->isVariablyModifiedType()) {
+ // Don't allow variably-modified types in constexpr functions.
+ TypeLoc TL = TN->getTypeSourceInfo()->getTypeLoc();
+ SemaRef.Diag(TL.getBeginLoc(), diag::err_constexpr_vla)
+ << TL.getSourceRange() << TL.getType()
+ << isa<CXXConstructorDecl>(Dcl);
+ return false;
+ }
+ continue;
+ }
+
+ case Decl::Enum:
+ case Decl::CXXRecord:
+ // As an extension, we allow the declaration (but not the definition) of
+ // classes and enumerations in all declarations, not just in typedef and
+ // alias declarations.
+ if (cast<TagDecl>(*DclIt)->isThisDeclarationADefinition()) {
+ SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_type_definition)
+ << isa<CXXConstructorDecl>(Dcl);
+ return false;
+ }
+ continue;
+
+ case Decl::Var:
+ SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_var_declaration)
+ << isa<CXXConstructorDecl>(Dcl);
+ return false;
+
+ default:
+ SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_body_invalid_stmt)
+ << isa<CXXConstructorDecl>(Dcl);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/// Check that the given field is initialized within a constexpr constructor.
+///
+/// \param Dcl The constexpr constructor being checked.
+/// \param Field The field being checked. This may be a member of an anonymous
+/// struct or union nested within the class being checked.
+/// \param Inits All declarations, including anonymous struct/union members and
+/// indirect members, for which any initialization was provided.
+/// \param Diagnosed Set to true if an error is produced.
+static void CheckConstexprCtorInitializer(Sema &SemaRef,
+ const FunctionDecl *Dcl,
+ FieldDecl *Field,
+ llvm::SmallSet<Decl*, 16> &Inits,
+ bool &Diagnosed) {
+ if (Field->isUnnamedBitfield())
+ return;
+
+ if (!Inits.count(Field)) {
+ if (!Diagnosed) {
+ SemaRef.Diag(Dcl->getLocation(), diag::err_constexpr_ctor_missing_init);
+ Diagnosed = true;
+ }
+ SemaRef.Diag(Field->getLocation(), diag::note_constexpr_ctor_missing_init);
+ } else if (Field->isAnonymousStructOrUnion()) {
+ const RecordDecl *RD = Field->getType()->castAs<RecordType>()->getDecl();
+ for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ I != E; ++I)
+ // If an anonymous union contains an anonymous struct of which any member
+ // is initialized, all members must be initialized.
+ if (!RD->isUnion() || Inits.count(*I))
+ CheckConstexprCtorInitializer(SemaRef, Dcl, *I, Inits, Diagnosed);
+ }
+}
+
+/// Check the body for the given constexpr function declaration only contains
+/// the permitted types of statement. C++11 [dcl.constexpr]p3,p4.
+///
+/// \return true if the body is OK, false if we have diagnosed a problem.
+bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
+ if (isa<CXXTryStmt>(Body)) {
+ // C++0x [dcl.constexpr]p3:
+ // The definition of a constexpr function shall satisfy the following
+ // constraints: [...]
+ // - its function-body shall be = delete, = default, or a
+ // compound-statement
+ //
+ // C++0x [dcl.constexpr]p4:
+ // In the definition of a constexpr constructor, [...]
+ // - its function-body shall not be a function-try-block;
+ Diag(Body->getLocStart(), diag::err_constexpr_function_try_block)
+ << isa<CXXConstructorDecl>(Dcl);
+ return false;
+ }
+
+ // - its function-body shall be [...] a compound-statement that contains only
+ CompoundStmt *CompBody = cast<CompoundStmt>(Body);
+
+ llvm::SmallVector<SourceLocation, 4> ReturnStmts;
+ for (CompoundStmt::body_iterator BodyIt = CompBody->body_begin(),
+ BodyEnd = CompBody->body_end(); BodyIt != BodyEnd; ++BodyIt) {
+ switch ((*BodyIt)->getStmtClass()) {
+ case Stmt::NullStmtClass:
+ // - null statements,
+ continue;
+
+ case Stmt::DeclStmtClass:
+ // - static_assert-declarations
+ // - using-declarations,
+ // - using-directives,
+ // - typedef declarations and alias-declarations that do not define
+ // classes or enumerations,
+ if (!CheckConstexprDeclStmt(*this, Dcl, cast<DeclStmt>(*BodyIt)))
+ return false;
+ continue;
+
+ case Stmt::ReturnStmtClass:
+ // - and exactly one return statement;
+ if (isa<CXXConstructorDecl>(Dcl))
+ break;
+
+ ReturnStmts.push_back((*BodyIt)->getLocStart());
+ // FIXME
+ // - every constructor call and implicit conversion used in initializing
+ // the return value shall be one of those allowed in a constant
+ // expression.
+ // Deal with this as part of a general check that the function can produce
+ // a constant expression (for [dcl.constexpr]p5).
+ continue;
+
+ default:
+ break;
+ }
+
+ Diag((*BodyIt)->getLocStart(), diag::err_constexpr_body_invalid_stmt)
+ << isa<CXXConstructorDecl>(Dcl);
+ return false;
+ }
+
+ if (const CXXConstructorDecl *Constructor
+ = dyn_cast<CXXConstructorDecl>(Dcl)) {
+ const CXXRecordDecl *RD = Constructor->getParent();
+ // - every non-static data member and base class sub-object shall be
+ // initialized;
+ if (RD->isUnion()) {
+ // DR1359: Exactly one member of a union shall be initialized.
+ if (Constructor->getNumCtorInitializers() == 0) {
+ Diag(Dcl->getLocation(), diag::err_constexpr_union_ctor_no_init);
+ return false;
+ }
+ } else if (!Constructor->isDependentContext() &&
+ !Constructor->isDelegatingConstructor()) {
+ assert(RD->getNumVBases() == 0 && "constexpr ctor with virtual bases");
+
+ // Skip detailed checking if we have enough initializers, and we would
+ // allow at most one initializer per member.
+ bool AnyAnonStructUnionMembers = false;
+ unsigned Fields = 0;
+ for (CXXRecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end(); I != E; ++I, ++Fields) {
+ if ((*I)->isAnonymousStructOrUnion()) {
+ AnyAnonStructUnionMembers = true;
+ break;
+ }
+ }
+ if (AnyAnonStructUnionMembers ||
+ Constructor->getNumCtorInitializers() != RD->getNumBases() + Fields) {
+ // Check initialization of non-static data members. Base classes are
+ // always initialized so do not need to be checked. Dependent bases
+ // might not have initializers in the member initializer list.
+ llvm::SmallSet<Decl*, 16> Inits;
+ for (CXXConstructorDecl::init_const_iterator
+ I = Constructor->init_begin(), E = Constructor->init_end();
+ I != E; ++I) {
+ if (FieldDecl *FD = (*I)->getMember())
+ Inits.insert(FD);
+ else if (IndirectFieldDecl *ID = (*I)->getIndirectMember())
+ Inits.insert(ID->chain_begin(), ID->chain_end());
+ }
+
+ bool Diagnosed = false;
+ for (CXXRecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end(); I != E; ++I)
+ CheckConstexprCtorInitializer(*this, Dcl, *I, Inits, Diagnosed);
+ if (Diagnosed)
+ return false;
+ }
+ }
+
+ // FIXME
+ // - every constructor involved in initializing non-static data members
+ // and base class sub-objects shall be a constexpr constructor;
+ // - every assignment-expression that is an initializer-clause appearing
+ // directly or indirectly within a brace-or-equal-initializer for
+ // a non-static data member that is not named by a mem-initializer-id
+ // shall be a constant expression; and
+ // - every implicit conversion used in converting a constructor argument
+ // to the corresponding parameter type and converting
+ // a full-expression to the corresponding member type shall be one of
+ // those allowed in a constant expression.
+ // Deal with these as part of a general check that the function can produce
+ // a constant expression (for [dcl.constexpr]p5).
+ } else {
+ if (ReturnStmts.empty()) {
+ Diag(Dcl->getLocation(), diag::err_constexpr_body_no_return);
+ return false;
+ }
+ if (ReturnStmts.size() > 1) {
+ Diag(ReturnStmts.back(), diag::err_constexpr_body_multiple_return);
+ for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I)
+ Diag(ReturnStmts[I], diag::note_constexpr_body_previous_return);
+ return false;
+ }
+ }
+
+ return true;
+}
+
/// isCurrentClassName - Determine whether the identifier II is the
/// name of the class type currently being defined. In the case of
/// nested classes, this will only return true if II is the name of
@@ -797,7 +1168,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
/// ActOnBaseSpecifiers - Attach the given base specifiers to the
/// class, after checking whether there are any duplicate base
/// classes.
-void Sema::ActOnBaseSpecifiers(Decl *ClassDecl, BaseTy **Bases,
+void Sema::ActOnBaseSpecifiers(Decl *ClassDecl, CXXBaseSpecifier **Bases,
unsigned NumBases) {
if (!ClassDecl || !Bases || !NumBases)
return;
@@ -1005,19 +1376,20 @@ std::string Sema::getAmbiguousPathsDisplayString(CXXBasePaths &Paths) {
//===----------------------------------------------------------------------===//
/// ActOnAccessSpecifier - Parsed an access specifier followed by a colon.
-Decl *Sema::ActOnAccessSpecifier(AccessSpecifier Access,
- SourceLocation ASLoc,
- SourceLocation ColonLoc) {
+bool Sema::ActOnAccessSpecifier(AccessSpecifier Access,
+ SourceLocation ASLoc,
+ SourceLocation ColonLoc,
+ AttributeList *Attrs) {
assert(Access != AS_none && "Invalid kind for syntactic access specifier!");
AccessSpecDecl *ASDecl = AccessSpecDecl::Create(Context, Access, CurContext,
ASLoc, ColonLoc);
CurContext->addHiddenDecl(ASDecl);
- return ASDecl;
+ return ProcessAccessDeclAttributeList(ASDecl, Attrs);
}
/// CheckOverrideControl - Check C++0x override control semantics.
void Sema::CheckOverrideControl(const Decl *D) {
- const CXXMethodDecl *MD = llvm::dyn_cast<CXXMethodDecl>(D);
+ const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D);
if (!MD || !MD->isVirtual())
return;
@@ -1060,9 +1432,8 @@ bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New,
Decl *
Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
- ExprTy *BW, const VirtSpecifiers &VS,
- ExprTy *InitExpr, bool HasDeferredInit,
- bool IsDefinition) {
+ Expr *BW, const VirtSpecifiers &VS,
+ bool HasDeferredInit) {
const DeclSpec &DS = D.getDeclSpec();
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
DeclarationName Name = NameInfo.getName();
@@ -1073,11 +1444,9 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
Loc = D.getSourceRange().getBegin();
Expr *BitWidth = static_cast<Expr*>(BW);
- Expr *Init = static_cast<Expr*>(InitExpr);
assert(isa<CXXRecordDecl>(CurContext));
assert(!DS.isFriendSpecified());
- assert(!Init || !HasDeferredInit);
bool isFunc = D.isDeclarationOfFunction();
@@ -1120,7 +1489,37 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
Decl *Member;
if (isInstField) {
CXXScopeSpec &SS = D.getCXXScopeSpec();
+
+ // Data members must have identifiers for names.
+ if (Name.getNameKind() != DeclarationName::Identifier) {
+ Diag(Loc, diag::err_bad_variable_name)
+ << Name;
+ return 0;
+ }
+ IdentifierInfo *II = Name.getAsIdentifierInfo();
+
+ // Member field could not be with "template" keyword.
+ // So TemplateParameterLists should be empty in this case.
+ if (TemplateParameterLists.size()) {
+ TemplateParameterList* TemplateParams = TemplateParameterLists.get()[0];
+ if (TemplateParams->size()) {
+ // There is no such thing as a member field template.
+ Diag(D.getIdentifierLoc(), diag::err_template_member)
+ << II
+ << SourceRange(TemplateParams->getTemplateLoc(),
+ TemplateParams->getRAngleLoc());
+ } else {
+ // There is an extraneous 'template<>' for this member.
+ Diag(TemplateParams->getTemplateLoc(),
+ diag::err_template_member_noparams)
+ << II
+ << SourceRange(TemplateParams->getTemplateLoc(),
+ TemplateParams->getRAngleLoc());
+ }
+ return 0;
+ }
+
if (SS.isSet() && !SS.isInvalid()) {
// The user provided a superfluous scope specifier inside a class
// definition:
@@ -1138,16 +1537,14 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
SS.clear();
}
-
- // FIXME: Check for template parameters!
- // FIXME: Check that the name is an identifier!
+
Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth,
HasDeferredInit, AS);
assert(Member && "HandleField never returns null");
} else {
assert(!HasDeferredInit);
- Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition);
+ Member = HandleDeclarator(S, D, move(TemplateParameterLists));
if (!Member) {
return 0;
}
@@ -1214,28 +1611,15 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
assert((Name || isInstField) && "No identifier for non-field ?");
- if (Init)
- AddInitializerToDecl(Member, Init, false,
- DS.getTypeSpecType() == DeclSpec::TST_auto);
- else if (DS.getTypeSpecType() == DeclSpec::TST_auto &&
- DS.getStorageClassSpec() == DeclSpec::SCS_static) {
- // C++0x [dcl.spec.auto]p4: 'auto' can only be used in the type of a static
- // data member if a brace-or-equal-initializer is provided.
- Diag(Loc, diag::err_auto_var_requires_init)
- << Name << cast<ValueDecl>(Member)->getType();
- Member->setInvalidDecl();
- }
-
- FinalizeDeclaration(Member);
-
if (isInstField)
FieldCollector->Add(cast<FieldDecl>(Member));
return Member;
}
/// ActOnCXXInClassMemberInitializer - This is invoked after parsing an
-/// in-class initializer for a non-static C++ class member. Such parsing
-/// is deferred until the class is complete.
+/// in-class initializer for a non-static C++ class member, and after
+/// instantiating an in-class initializer in a class template. Such actions
+/// are deferred until the class is complete.
void
Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc,
Expr *InitExpr) {
@@ -1319,7 +1703,21 @@ static bool FindBaseInitializer(Sema &SemaRef,
return DirectBaseSpec || VirtualBaseSpec;
}
-/// ActOnMemInitializer - Handle a C++ member initializer.
+/// \brief Handle a C++ member initializer using braced-init-list syntax.
+MemInitResult
+Sema::ActOnMemInitializer(Decl *ConstructorD,
+ Scope *S,
+ CXXScopeSpec &SS,
+ IdentifierInfo *MemberOrBase,
+ ParsedType TemplateTypeTy,
+ SourceLocation IdLoc,
+ Expr *InitList,
+ SourceLocation EllipsisLoc) {
+ return BuildMemInitializer(ConstructorD, S, SS, MemberOrBase, TemplateTypeTy,
+ IdLoc, MultiInitializer(InitList), EllipsisLoc);
+}
+
+/// \brief Handle a C++ member initializer using parentheses syntax.
MemInitResult
Sema::ActOnMemInitializer(Decl *ConstructorD,
Scope *S,
@@ -1328,9 +1726,25 @@ Sema::ActOnMemInitializer(Decl *ConstructorD,
ParsedType TemplateTypeTy,
SourceLocation IdLoc,
SourceLocation LParenLoc,
- ExprTy **Args, unsigned NumArgs,
+ Expr **Args, unsigned NumArgs,
SourceLocation RParenLoc,
SourceLocation EllipsisLoc) {
+ return BuildMemInitializer(ConstructorD, S, SS, MemberOrBase, TemplateTypeTy,
+ IdLoc, MultiInitializer(LParenLoc, Args, NumArgs,
+ RParenLoc),
+ EllipsisLoc);
+}
+
+/// \brief Handle a C++ member initializer.
+MemInitResult
+Sema::BuildMemInitializer(Decl *ConstructorD,
+ Scope *S,
+ CXXScopeSpec &SS,
+ IdentifierInfo *MemberOrBase,
+ ParsedType TemplateTypeTy,
+ SourceLocation IdLoc,
+ const MultiInitializer &Args,
+ SourceLocation EllipsisLoc) {
if (!ConstructorD)
return true;
@@ -1365,26 +1779,23 @@ Sema::ActOnMemInitializer(Decl *ConstructorD,
= ClassDecl->lookup(MemberOrBase);
if (Result.first != Result.second) {
Member = dyn_cast<FieldDecl>(*Result.first);
-
+
if (Member) {
if (EllipsisLoc.isValid())
Diag(EllipsisLoc, diag::err_pack_expansion_member_init)
- << MemberOrBase << SourceRange(IdLoc, RParenLoc);
-
- return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc,
- LParenLoc, RParenLoc);
+ << MemberOrBase << SourceRange(IdLoc, Args.getEndLoc());
+
+ return BuildMemberInitializer(Member, Args, IdLoc);
}
-
+
// Handle anonymous union case.
if (IndirectFieldDecl* IndirectField
= dyn_cast<IndirectFieldDecl>(*Result.first)) {
if (EllipsisLoc.isValid())
Diag(EllipsisLoc, diag::err_pack_expansion_member_init)
- << MemberOrBase << SourceRange(IdLoc, RParenLoc);
+ << MemberOrBase << SourceRange(IdLoc, Args.getEndLoc());
- return BuildMemberInitializer(IndirectField, (Expr**)Args,
- NumArgs, IdLoc,
- LParenLoc, RParenLoc);
+ return BuildMemberInitializer(IndirectField, Args, IdLoc);
}
}
}
@@ -1443,8 +1854,7 @@ Sema::ActOnMemInitializer(Decl *ConstructorD,
Diag(Member->getLocation(), diag::note_previous_decl)
<< CorrectedQuotedStr;
- return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc,
- LParenLoc, RParenLoc);
+ return BuildMemberInitializer(Member, Args, IdLoc);
}
} else if (TypeDecl *Type = Corr.getCorrectionDeclAs<TypeDecl>()) {
const CXXBaseSpecifier *DirectBaseSpec;
@@ -1473,7 +1883,7 @@ Sema::ActOnMemInitializer(Decl *ConstructorD,
if (!TyD && BaseType.isNull()) {
Diag(IdLoc, diag::err_mem_init_not_member_or_class)
- << MemberOrBase << SourceRange(IdLoc, RParenLoc);
+ << MemberOrBase << SourceRange(IdLoc, Args.getEndLoc());
return true;
}
}
@@ -1493,8 +1903,62 @@ Sema::ActOnMemInitializer(Decl *ConstructorD,
if (!TInfo)
TInfo = Context.getTrivialTypeSourceInfo(BaseType, IdLoc);
- return BuildBaseInitializer(BaseType, TInfo, (Expr **)Args, NumArgs,
- LParenLoc, RParenLoc, ClassDecl, EllipsisLoc);
+ return BuildBaseInitializer(BaseType, TInfo, Args, ClassDecl, EllipsisLoc);
+}
+
+/// Checks a member initializer expression for cases where reference (or
+/// pointer) members are bound to by-value parameters (or their addresses).
+static void CheckForDanglingReferenceOrPointer(Sema &S, ValueDecl *Member,
+ Expr *Init,
+ SourceLocation IdLoc) {
+ QualType MemberTy = Member->getType();
+
+ // We only handle pointers and references currently.
+ // FIXME: Would this be relevant for ObjC object pointers? Or block pointers?
+ if (!MemberTy->isReferenceType() && !MemberTy->isPointerType())
+ return;
+
+ const bool IsPointer = MemberTy->isPointerType();
+ if (IsPointer) {
+ if (const UnaryOperator *Op
+ = dyn_cast<UnaryOperator>(Init->IgnoreParenImpCasts())) {
+ // The only case we're worried about with pointers requires taking the
+ // address.
+ if (Op->getOpcode() != UO_AddrOf)
+ return;
+
+ Init = Op->getSubExpr();
+ } else {
+ // We only handle address-of expression initializers for pointers.
+ return;
+ }
+ }
+
+ if (isa<MaterializeTemporaryExpr>(Init->IgnoreParens())) {
+ // Taking the address of a temporary will be diagnosed as a hard error.
+ if (IsPointer)
+ return;
+
+ S.Diag(Init->getExprLoc(), diag::warn_bind_ref_member_to_temporary)
+ << Member << Init->getSourceRange();
+ } else if (const DeclRefExpr *DRE
+ = dyn_cast<DeclRefExpr>(Init->IgnoreParens())) {
+ // We only warn when referring to a non-reference parameter declaration.
+ const ParmVarDecl *Parameter = dyn_cast<ParmVarDecl>(DRE->getDecl());
+ if (!Parameter || Parameter->getType()->isReferenceType())
+ return;
+
+ S.Diag(Init->getExprLoc(),
+ IsPointer ? diag::warn_init_ptr_member_to_parameter_addr
+ : diag::warn_bind_ref_member_to_parameter)
+ << Member << Parameter << Init->getSourceRange();
+ } else {
+ // Other initializers are fine.
+ return;
+ }
+
+ S.Diag(Member->getLocation(), diag::note_ref_or_ptr_member_declared_here)
+ << (unsigned)IsPointer;
}
/// Checks an initializer expression for use of uninitialized fields, such as
@@ -1566,10 +2030,9 @@ static bool InitExprContainsUninitializedFields(const Stmt *S,
}
MemInitResult
-Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args,
- unsigned NumArgs, SourceLocation IdLoc,
- SourceLocation LParenLoc,
- SourceLocation RParenLoc) {
+Sema::BuildMemberInitializer(ValueDecl *Member,
+ const MultiInitializer &Args,
+ SourceLocation IdLoc) {
FieldDecl *DirectMember = dyn_cast<FieldDecl>(Member);
IndirectFieldDecl *IndirectMember = dyn_cast<IndirectFieldDecl>(Member);
assert((DirectMember || IndirectMember) &&
@@ -1582,9 +2045,13 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args,
// foo(foo)
// where foo is not also a parameter to the constructor.
// TODO: implement -Wuninitialized and fold this into that framework.
- for (unsigned i = 0; i < NumArgs; ++i) {
+ for (MultiInitializer::iterator I = Args.begin(), E = Args.end();
+ I != E; ++I) {
SourceLocation L;
- if (InitExprContainsUninitializedFields(Args[i], Member, &L)) {
+ Expr *Arg = *I;
+ if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Arg))
+ Arg = DIE->getInit();
+ if (InitExprContainsUninitializedFields(Arg, Member, &L)) {
// FIXME: Return true in the case when other fields are used before being
// uninitialized. For example, let this field be the i'th field. When
// initializing the i'th field, throw a warning if any of the >= i'th
@@ -1595,17 +2062,13 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args,
}
}
- bool HasDependentArg = false;
- for (unsigned i = 0; i < NumArgs; i++)
- HasDependentArg |= Args[i]->isTypeDependent();
+ bool HasDependentArg = Args.isTypeDependent();
Expr *Init;
if (Member->getType()->isDependentType() || HasDependentArg) {
// Can't check initialization for a member of dependent type or when
// any of the arguments are type-dependent expressions.
- Init = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
- RParenLoc,
- Member->getType().getNonReferenceType());
+ Init = Args.CreateInitExpr(Context,Member->getType().getNonReferenceType());
DiscardCleanupsInEvaluationContext();
} else {
@@ -1614,17 +2077,14 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args,
DirectMember ? InitializedEntity::InitializeMember(DirectMember, 0)
: InitializedEntity::InitializeMember(IndirectMember, 0);
InitializationKind Kind =
- InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc);
+ InitializationKind::CreateDirect(IdLoc, Args.getStartLoc(),
+ Args.getEndLoc());
- InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs);
-
- ExprResult MemberInit =
- InitSeq.Perform(*this, MemberEntity, Kind,
- MultiExprArg(*this, Args, NumArgs), 0);
+ ExprResult MemberInit = Args.PerformInit(*this, MemberEntity, Kind);
if (MemberInit.isInvalid())
return true;
- CheckImplicitConversions(MemberInit.get(), LParenLoc);
+ CheckImplicitConversions(MemberInit.get(), Args.getStartLoc());
// C++0x [class.base.init]p7:
// The initialization of each base and member constitutes a
@@ -1640,31 +2100,30 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args,
// 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())
- Init = new (Context) ParenListExpr(
- Context, LParenLoc, Args, NumArgs, RParenLoc,
- Member->getType().getNonReferenceType());
- else
+ if (CurContext->isDependentContext()) {
+ Init = Args.CreateInitExpr(Context,
+ Member->getType().getNonReferenceType());
+ } else {
Init = MemberInit.get();
+ CheckForDanglingReferenceOrPointer(*this, Member, Init, IdLoc);
+ }
}
if (DirectMember) {
return new (Context) CXXCtorInitializer(Context, DirectMember,
- IdLoc, LParenLoc, Init,
- RParenLoc);
+ IdLoc, Args.getStartLoc(),
+ Init, Args.getEndLoc());
} else {
return new (Context) CXXCtorInitializer(Context, IndirectMember,
- IdLoc, LParenLoc, Init,
- RParenLoc);
+ IdLoc, Args.getStartLoc(),
+ Init, Args.getEndLoc());
}
}
MemInitResult
Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo,
- Expr **Args, unsigned NumArgs,
+ const MultiInitializer &Args,
SourceLocation NameLoc,
- SourceLocation LParenLoc,
- SourceLocation RParenLoc,
CXXRecordDecl *ClassDecl) {
SourceLocation Loc = TInfo->getTypeLoc().getLocalSourceRange().getBegin();
if (!LangOpts.CPlusPlus0x)
@@ -1675,13 +2134,10 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo,
InitializedEntity DelegationEntity = InitializedEntity::InitializeDelegation(
QualType(ClassDecl->getTypeForDecl(), 0));
InitializationKind Kind =
- InitializationKind::CreateDirect(NameLoc, LParenLoc, RParenLoc);
+ InitializationKind::CreateDirect(NameLoc, Args.getStartLoc(),
+ Args.getEndLoc());
- InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args, NumArgs);
-
- ExprResult DelegationInit =
- InitSeq.Perform(*this, DelegationEntity, Kind,
- MultiExprArg(*this, Args, NumArgs), 0);
+ ExprResult DelegationInit = Args.PerformInit(*this, DelegationEntity, Kind);
if (DelegationInit.isInvalid())
return true;
@@ -1690,7 +2146,7 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo,
= ConExpr->getConstructor();
assert(Constructor && "Delegating constructor with no target?");
- CheckImplicitConversions(DelegationInit.get(), LParenLoc);
+ CheckImplicitConversions(DelegationInit.get(), Args.getStartLoc());
// C++0x [class.base.init]p7:
// The initialization of each base and member constitutes a
@@ -1700,24 +2156,22 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo,
return true;
assert(!CurContext->isDependentContext());
- return new (Context) CXXCtorInitializer(Context, Loc, LParenLoc, Constructor,
+ return new (Context) CXXCtorInitializer(Context, Loc, Args.getStartLoc(),
+ Constructor,
DelegationInit.takeAs<Expr>(),
- RParenLoc);
+ Args.getEndLoc());
}
MemInitResult
Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
- Expr **Args, unsigned NumArgs,
- SourceLocation LParenLoc, SourceLocation RParenLoc,
+ const MultiInitializer &Args,
CXXRecordDecl *ClassDecl,
SourceLocation EllipsisLoc) {
- bool HasDependentArg = false;
- for (unsigned i = 0; i < NumArgs; i++)
- HasDependentArg |= Args[i]->isTypeDependent();
+ bool HasDependentArg = Args.isTypeDependent();
SourceLocation BaseLoc
= BaseTInfo->getTypeLoc().getLocalSourceRange().getBegin();
-
+
if (!BaseType->isDependentType() && !BaseType->isRecordType())
return Diag(BaseLoc, diag::err_base_init_does_not_name_class)
<< BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange();
@@ -1734,28 +2188,26 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
// This is a pack expansion.
if (!BaseType->containsUnexpandedParameterPack()) {
Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
- << SourceRange(BaseLoc, RParenLoc);
-
+ << SourceRange(BaseLoc, Args.getEndLoc());
+
EllipsisLoc = SourceLocation();
}
} else {
// Check for any unexpanded parameter packs.
if (DiagnoseUnexpandedParameterPack(BaseLoc, BaseTInfo, UPPC_Initializer))
return true;
-
- for (unsigned I = 0; I != NumArgs; ++I)
- if (DiagnoseUnexpandedParameterPack(Args[I]))
- return true;
+
+ if (Args.DiagnoseUnexpandedParameterPack(*this))
+ return true;
}
-
+
// Check for direct and virtual base classes.
const CXXBaseSpecifier *DirectBaseSpec = 0;
const CXXBaseSpecifier *VirtualBaseSpec = 0;
if (!Dependent) {
if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0),
BaseType))
- return BuildDelegatingInitializer(BaseTInfo, Args, NumArgs, BaseLoc,
- LParenLoc, RParenLoc, ClassDecl);
+ return BuildDelegatingInitializer(BaseTInfo, Args, BaseLoc, ClassDecl);
FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
VirtualBaseSpec);
@@ -1782,18 +2234,14 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
if (Dependent) {
// Can't check initialization for a base of dependent type or when
// any of the arguments are type-dependent expressions.
- ExprResult BaseInit
- = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
- RParenLoc, BaseType));
+ Expr *BaseInit = Args.CreateInitExpr(Context, BaseType);
DiscardCleanupsInEvaluationContext();
- return new (Context) CXXCtorInitializer(Context, BaseTInfo,
- /*IsVirtual=*/false,
- LParenLoc,
- BaseInit.takeAs<Expr>(),
- RParenLoc,
- EllipsisLoc);
+ return new (Context) CXXCtorInitializer(Context, BaseTInfo,
+ /*IsVirtual=*/false,
+ Args.getStartLoc(), BaseInit,
+ Args.getEndLoc(), EllipsisLoc);
}
// C++ [base.class.init]p2:
@@ -1813,18 +2261,15 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
InitializedEntity BaseEntity =
InitializedEntity::InitializeBase(Context, BaseSpec, VirtualBaseSpec);
InitializationKind Kind =
- InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc);
-
- InitializationSequence InitSeq(*this, BaseEntity, Kind, Args, NumArgs);
-
- ExprResult BaseInit =
- InitSeq.Perform(*this, BaseEntity, Kind,
- MultiExprArg(*this, Args, NumArgs), 0);
+ InitializationKind::CreateDirect(BaseLoc, Args.getStartLoc(),
+ Args.getEndLoc());
+
+ ExprResult BaseInit = Args.PerformInit(*this, BaseEntity, Kind);
if (BaseInit.isInvalid())
return true;
- CheckImplicitConversions(BaseInit.get(), LParenLoc);
-
+ CheckImplicitConversions(BaseInit.get(), Args.getStartLoc());
+
// C++0x [class.base.init]p7:
// The initialization of each base and member constitutes a
// full-expression.
@@ -1839,24 +2284,27 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
// of the information that we have about the base
// 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()) {
- ExprResult Init
- = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
- RParenLoc, BaseType));
- return new (Context) CXXCtorInitializer(Context, BaseTInfo,
- BaseSpec->isVirtual(),
- LParenLoc,
- Init.takeAs<Expr>(),
- RParenLoc,
- EllipsisLoc);
- }
+ if (CurContext->isDependentContext())
+ BaseInit = Owned(Args.CreateInitExpr(Context, BaseType));
return new (Context) CXXCtorInitializer(Context, BaseTInfo,
- BaseSpec->isVirtual(),
- LParenLoc,
- BaseInit.takeAs<Expr>(),
- RParenLoc,
- EllipsisLoc);
+ BaseSpec->isVirtual(),
+ Args.getStartLoc(),
+ BaseInit.takeAs<Expr>(),
+ Args.getEndLoc(), EllipsisLoc);
+}
+
+// Create a static_cast\<T&&>(expr).
+static Expr *CastForMoving(Sema &SemaRef, Expr *E) {
+ QualType ExprType = E->getType();
+ QualType TargetType = SemaRef.Context.getRValueReferenceType(ExprType);
+ SourceLocation ExprLoc = E->getLocStart();
+ TypeSourceInfo *TargetLoc = SemaRef.Context.getTrivialTypeSourceInfo(
+ TargetType, ExprLoc);
+
+ return SemaRef.BuildCXXNamedCast(ExprLoc, tok::kw_static_cast, TargetLoc, E,
+ SourceRange(ExprLoc, ExprLoc),
+ E->getSourceRange()).take();
}
/// ImplicitInitializerKind - How an implicit base or member initializer should
@@ -1889,7 +2337,9 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
break;
}
+ case IIK_Move:
case IIK_Copy: {
+ bool Moving = ImplicitInitKind == IIK_Move;
ParmVarDecl *Param = Constructor->getParamDecl(0);
QualType ParamType = Param->getType().getNonReferenceType();
@@ -1897,17 +2347,22 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), Param,
Constructor->getLocation(), ParamType,
VK_LValue, 0);
-
+
// Cast to the base class to avoid ambiguities.
QualType ArgTy =
SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(),
ParamType.getQualifiers());
+ if (Moving) {
+ CopyCtorArg = CastForMoving(SemaRef, CopyCtorArg);
+ }
+
CXXCastPath BasePath;
BasePath.push_back(BaseSpec);
CopyCtorArg = SemaRef.ImpCastExprToType(CopyCtorArg, ArgTy,
CK_UncheckedDerivedToBase,
- VK_LValue, &BasePath).take();
+ Moving ? VK_XValue : VK_LValue,
+ &BasePath).take();
InitializationKind InitKind
= InitializationKind::CreateDirect(Constructor->getLocation(),
@@ -1918,9 +2373,6 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
MultiExprArg(&CopyCtorArg, 1));
break;
}
-
- case IIK_Move:
- assert(false && "Unhandled initializer kind!");
}
BaseInit = SemaRef.MaybeCreateExprWithCleanups(BaseInit);
@@ -1940,36 +2392,46 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
return false;
}
+static bool RefersToRValueRef(Expr *MemRef) {
+ ValueDecl *Referenced = cast<MemberExpr>(MemRef)->getMemberDecl();
+ return Referenced->getType()->isRValueReferenceType();
+}
+
static bool
BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
ImplicitInitializerKind ImplicitInitKind,
- FieldDecl *Field,
+ FieldDecl *Field, IndirectFieldDecl *Indirect,
CXXCtorInitializer *&CXXMemberInit) {
if (Field->isInvalidDecl())
return true;
SourceLocation Loc = Constructor->getLocation();
- if (ImplicitInitKind == IIK_Copy) {
+ if (ImplicitInitKind == IIK_Copy || ImplicitInitKind == IIK_Move) {
+ bool Moving = ImplicitInitKind == IIK_Move;
ParmVarDecl *Param = Constructor->getParamDecl(0);
QualType ParamType = Param->getType().getNonReferenceType();
// Suppress copying zero-width bitfields.
- if (const Expr *Width = Field->getBitWidth())
- if (Width->EvaluateAsInt(SemaRef.Context) == 0)
- return false;
+ if (Field->isBitField() && Field->getBitWidthValue(SemaRef.Context) == 0)
+ return false;
Expr *MemberExprBase =
DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), Param,
Loc, ParamType, VK_LValue, 0);
+ if (Moving) {
+ MemberExprBase = CastForMoving(SemaRef, MemberExprBase);
+ }
+
// Build a reference to this field within the parameter.
CXXScopeSpec SS;
LookupResult MemberLookup(SemaRef, Field->getDeclName(), Loc,
Sema::LookupMemberName);
- MemberLookup.addDecl(Field, AS_public);
+ MemberLookup.addDecl(Indirect ? cast<ValueDecl>(Indirect)
+ : cast<ValueDecl>(Field), AS_public);
MemberLookup.resolveKind();
- ExprResult CopyCtorArg
+ ExprResult CtorArg
= SemaRef.BuildMemberReferenceExpr(MemberExprBase,
ParamType, Loc,
/*IsArrow=*/false,
@@ -1977,18 +2439,27 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
/*FirstQualifierInScope=*/0,
MemberLookup,
/*TemplateArgs=*/0);
- if (CopyCtorArg.isInvalid())
+ if (CtorArg.isInvalid())
return true;
-
+
+ // C++11 [class.copy]p15:
+ // - if a member m has rvalue reference type T&&, it is direct-initialized
+ // with static_cast<T&&>(x.m);
+ if (RefersToRValueRef(CtorArg.get())) {
+ CtorArg = CastForMoving(SemaRef, CtorArg.take());
+ }
+
// When the field we are copying is an array, create index variables for
// each dimension of the array. We use these index variables to subscript
// the source array, and other clients (e.g., CodeGen) will perform the
// necessary iteration with these index variables.
- llvm::SmallVector<VarDecl *, 4> IndexVariables;
+ SmallVector<VarDecl *, 4> IndexVariables;
QualType BaseType = Field->getType();
QualType SizeType = SemaRef.Context.getSizeType();
+ bool InitializingArray = false;
while (const ConstantArrayType *Array
= SemaRef.Context.getAsConstantArrayType(BaseType)) {
+ InitializingArray = true;
// Create the iteration variable for this array index.
IdentifierInfo *IterationVarName = 0;
{
@@ -2009,24 +2480,30 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
= SemaRef.BuildDeclRefExpr(IterationVar, SizeType, VK_RValue, Loc);
assert(!IterationVarRef.isInvalid() &&
"Reference to invented variable cannot fail!");
-
+
// Subscript the array with this iteration variable.
- CopyCtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(CopyCtorArg.take(),
- Loc,
+ CtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(CtorArg.take(), Loc,
IterationVarRef.take(),
- Loc);
- if (CopyCtorArg.isInvalid())
+ Loc);
+ if (CtorArg.isInvalid())
return true;
-
+
BaseType = Array->getElementType();
}
-
+
+ // The array subscript expression is an lvalue, which is wrong for moving.
+ if (Moving && InitializingArray)
+ CtorArg = CastForMoving(SemaRef, CtorArg.take());
+
// Construct the entity that we will be initializing. For an array, this
// will be first element in the array, which may require several levels
// of array-subscript entities.
- llvm::SmallVector<InitializedEntity, 4> Entities;
+ SmallVector<InitializedEntity, 4> Entities;
Entities.reserve(1 + IndexVariables.size());
- Entities.push_back(InitializedEntity::InitializeMember(Field));
+ if (Indirect)
+ Entities.push_back(InitializedEntity::InitializeMember(Indirect));
+ else
+ Entities.push_back(InitializedEntity::InitializeMember(Field));
for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I)
Entities.push_back(InitializedEntity::InitializeElement(SemaRef.Context,
0,
@@ -2036,22 +2513,31 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
InitializationKind InitKind =
InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation());
- Expr *CopyCtorArgE = CopyCtorArg.takeAs<Expr>();
+ Expr *CtorArgE = CtorArg.takeAs<Expr>();
InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind,
- &CopyCtorArgE, 1);
+ &CtorArgE, 1);
ExprResult MemberInit
= InitSeq.Perform(SemaRef, Entities.back(), InitKind,
- MultiExprArg(&CopyCtorArgE, 1));
+ MultiExprArg(&CtorArgE, 1));
MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit);
if (MemberInit.isInvalid())
return true;
- CXXMemberInit
- = CXXCtorInitializer::Create(SemaRef.Context, Field, Loc, Loc,
- MemberInit.takeAs<Expr>(), Loc,
- IndexVariables.data(),
- IndexVariables.size());
+ if (Indirect) {
+ assert(IndexVariables.size() == 0 &&
+ "Indirect field improperly initialized");
+ CXXMemberInit
+ = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect,
+ Loc, Loc,
+ MemberInit.takeAs<Expr>(),
+ Loc);
+ } else
+ CXXMemberInit = CXXCtorInitializer::Create(SemaRef.Context, Field, Loc,
+ Loc, MemberInit.takeAs<Expr>(),
+ Loc,
+ IndexVariables.data(),
+ IndexVariables.size());
return false;
}
@@ -2061,7 +2547,9 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
SemaRef.Context.getBaseElementType(Field->getType());
if (FieldBaseElementType->isRecordType()) {
- InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field);
+ InitializedEntity InitEntity
+ = Indirect? InitializedEntity::InitializeMember(Indirect)
+ : InitializedEntity::InitializeMember(Field);
InitializationKind InitKind =
InitializationKind::CreateDefault(Loc);
@@ -2073,11 +2561,17 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
if (MemberInit.isInvalid())
return true;
- CXXMemberInit =
- new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context,
- Field, Loc, Loc,
- MemberInit.get(),
- Loc);
+ if (Indirect)
+ CXXMemberInit = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context,
+ Indirect, Loc,
+ Loc,
+ MemberInit.get(),
+ Loc);
+ else
+ CXXMemberInit = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context,
+ Field, Loc, Loc,
+ MemberInit.get(),
+ Loc);
return false;
}
@@ -2129,21 +2623,37 @@ struct BaseAndFieldInfo {
bool AnyErrorsInInits;
ImplicitInitializerKind IIK;
llvm::DenseMap<const void *, CXXCtorInitializer*> AllBaseFields;
- llvm::SmallVector<CXXCtorInitializer*, 8> AllToInit;
+ SmallVector<CXXCtorInitializer*, 8> AllToInit;
BaseAndFieldInfo(Sema &S, CXXConstructorDecl *Ctor, bool ErrorsInInits)
: S(S), Ctor(Ctor), AnyErrorsInInits(ErrorsInInits) {
- // FIXME: Handle implicit move constructors.
- if (Ctor->isImplicit() && Ctor->isCopyConstructor())
+ bool Generated = Ctor->isImplicit() || Ctor->isDefaulted();
+ if (Generated && Ctor->isCopyConstructor())
IIK = IIK_Copy;
+ else if (Generated && Ctor->isMoveConstructor())
+ IIK = IIK_Move;
else
IIK = IIK_Default;
}
};
}
+/// \brief Determine whether the given indirect field declaration is somewhere
+/// within an anonymous union.
+static bool isWithinAnonymousUnion(IndirectFieldDecl *F) {
+ for (IndirectFieldDecl::chain_iterator C = F->chain_begin(),
+ CEnd = F->chain_end();
+ C != CEnd; ++C)
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>((*C)->getDeclContext()))
+ if (Record->isUnion())
+ return true;
+
+ return false;
+}
+
static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
- FieldDecl *Top, FieldDecl *Field) {
+ FieldDecl *Field,
+ IndirectFieldDecl *Indirect = 0) {
// Overwhelmingly common case: we have a direct initializer for this field.
if (CXXCtorInitializer *Init = Info.AllBaseFields.lookup(Field)) {
@@ -2155,53 +2665,26 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
// has a brace-or-equal-initializer, the entity is initialized as specified
// in [dcl.init].
if (Field->hasInClassInitializer()) {
- Info.AllToInit.push_back(
- new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field,
- SourceLocation(),
- SourceLocation(), 0,
- SourceLocation()));
+ CXXCtorInitializer *Init;
+ if (Indirect)
+ Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect,
+ SourceLocation(),
+ SourceLocation(), 0,
+ SourceLocation());
+ else
+ Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field,
+ SourceLocation(),
+ SourceLocation(), 0,
+ SourceLocation());
+ Info.AllToInit.push_back(Init);
return false;
}
- if (Info.IIK == IIK_Default && Field->isAnonymousStructOrUnion()) {
- const RecordType *FieldClassType = Field->getType()->getAs<RecordType>();
- assert(FieldClassType && "anonymous struct/union without record type");
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
-
- // Even though union members never have non-trivial default
- // constructions in C++03, we still build member initializers for aggregate
- // record types which can be union members, and C++0x allows non-trivial
- // default constructors for union members, so we ensure that only one
- // member is initialized for these.
- if (FieldClassDecl->isUnion()) {
- // First check for an explicit initializer for one field.
- for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
- EA = FieldClassDecl->field_end(); FA != EA; FA++) {
- if (CXXCtorInitializer *Init = Info.AllBaseFields.lookup(*FA)) {
- Info.AllToInit.push_back(Init);
-
- // Once we've initialized a field of an anonymous union, the union
- // field in the class is also initialized, so exit immediately.
- return false;
- } else if ((*FA)->isAnonymousStructOrUnion()) {
- if (CollectFieldInitializer(SemaRef, Info, Top, *FA))
- return true;
- }
- }
-
- // FIXME: C++0x unrestricted unions might call a default constructor here.
- return false;
- } else {
- // For structs, we simply descend through to initialize all members where
- // necessary.
- for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
- EA = FieldClassDecl->field_end(); FA != EA; FA++) {
- if (CollectFieldInitializer(SemaRef, Info, Top, *FA))
- return true;
- }
- }
- }
+ // Don't build an implicit initializer for union members if none was
+ // explicitly specified.
+ if (Field->getParent()->isUnion() ||
+ (Indirect && isWithinAnonymousUnion(Indirect)))
+ return false;
// Don't try to build an implicit initializer if there were semantic
// errors in any of the initializers (and therefore we might be
@@ -2210,7 +2693,8 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
return false;
CXXCtorInitializer *Init = 0;
- if (BuildImplicitMemberInitializer(Info.S, Info.Ctor, Info.IIK, Field, Init))
+ if (BuildImplicitMemberInitializer(Info.S, Info.Ctor, Info.IIK, Field,
+ Indirect, Init))
return true;
if (Init)
@@ -2238,12 +2722,12 @@ Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor,
return false;
}
-
+
bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
CXXCtorInitializer **Initializers,
unsigned NumInitializers,
bool AnyErrors) {
- if (Constructor->getDeclContext()->isDependentContext()) {
+ if (Constructor->isDependentContext()) {
// Just store the initializers as written, they will be checked during
// instantiation.
if (NumInitializers > 0) {
@@ -2330,15 +2814,51 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
}
// Fields.
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- E = ClassDecl->field_end(); Field != E; ++Field) {
- if ((*Field)->getType()->isIncompleteArrayType()) {
- assert(ClassDecl->hasFlexibleArrayMember() &&
- "Incomplete array type is not valid");
+ for (DeclContext::decl_iterator Mem = ClassDecl->decls_begin(),
+ MemEnd = ClassDecl->decls_end();
+ Mem != MemEnd; ++Mem) {
+ if (FieldDecl *F = dyn_cast<FieldDecl>(*Mem)) {
+ // C++ [class.bit]p2:
+ // A declaration for a bit-field that omits the identifier declares an
+ // unnamed bit-field. Unnamed bit-fields are not members and cannot be
+ // initialized.
+ if (F->isUnnamedBitfield())
+ continue;
+
+ if (F->getType()->isIncompleteArrayType()) {
+ assert(ClassDecl->hasFlexibleArrayMember() &&
+ "Incomplete array type is not valid");
+ continue;
+ }
+
+ // If we're not generating the implicit copy/move constructor, then we'll
+ // handle anonymous struct/union fields based on their individual
+ // indirect fields.
+ if (F->isAnonymousStructOrUnion() && Info.IIK == IIK_Default)
+ continue;
+
+ if (CollectFieldInitializer(*this, Info, F))
+ HadError = true;
continue;
}
- if (CollectFieldInitializer(*this, Info, *Field, *Field))
- HadError = true;
+
+ // Beyond this point, we only consider default initialization.
+ if (Info.IIK != IIK_Default)
+ continue;
+
+ if (IndirectFieldDecl *F = dyn_cast<IndirectFieldDecl>(*Mem)) {
+ if (F->getType()->isIncompleteArrayType()) {
+ assert(ClassDecl->hasFlexibleArrayMember() &&
+ "Incomplete array type is not valid");
+ continue;
+ }
+
+ // Initialize each field of an anonymous struct individually.
+ if (CollectFieldInitializer(*this, Info, F->getAnonField(), F))
+ HadError = true;
+
+ continue;
+ }
}
NumInitializers = Info.AllToInit.size();
@@ -2414,7 +2934,7 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
CXXCtorInitializer *Init = Inits[InitIndex];
if (SemaRef.Diags.getDiagnosticLevel(diag::warn_initializer_out_of_order,
Init->getSourceLocation())
- != Diagnostic::Ignored) {
+ != DiagnosticsEngine::Ignored) {
ShouldCheckOrder = true;
break;
}
@@ -2425,7 +2945,7 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
// Build the list of bases and members in the order that they'll
// actually be initialized. The explicit initializers should be in
// this same order but may be missing things.
- llvm::SmallVector<const void*, 32> IdealInitKeys;
+ SmallVector<const void*, 32> IdealInitKeys;
const CXXRecordDecl *ClassDecl = Constructor->getParent();
@@ -2445,9 +2965,13 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
// 3. Direct fields.
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- E = ClassDecl->field_end(); Field != E; ++Field)
+ E = ClassDecl->field_end(); Field != E; ++Field) {
+ if (Field->isUnnamedBitfield())
+ continue;
+
IdealInitKeys.push_back(GetKeyForTopLevelField(*Field));
-
+ }
+
unsigned NumIdealInits = IdealInitKeys.size();
unsigned IdealIndex = 0;
@@ -2561,7 +3085,8 @@ bool CheckRedundantUnionInit(Sema &S,
/// ActOnMemInitializers - Handle the member initializers for a constructor.
void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
SourceLocation ColonLoc,
- MemInitTy **meminits, unsigned NumMemInits,
+ CXXCtorInitializer **meminits,
+ unsigned NumMemInits,
bool AnyErrors) {
if (!ConstructorDecl)
return;
@@ -2630,8 +3155,9 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
void
Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
CXXRecordDecl *ClassDecl) {
- // Ignore dependent contexts.
- if (ClassDecl->isDependentContext())
+ // Ignore dependent contexts. Also ignore unions, since their members never
+ // have destructors implicitly called.
+ if (ClassDecl->isDependentContext() || ClassDecl->isUnion())
return;
// FIXME: all the access-control diagnostics are positioned on the
@@ -2903,6 +3429,7 @@ struct CheckAbstractUsage {
CheckPolymorphic(ReferenceTypeLoc)
CheckPolymorphic(MemberPointerTypeLoc)
CheckPolymorphic(BlockPointerTypeLoc)
+ CheckPolymorphic(AtomicTypeLoc)
/// Handle all the types we haven't given a more specific
/// implementation for above.
@@ -3016,7 +3543,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
for (RecordDecl::field_iterator F = Record->field_begin(),
FEnd = Record->field_end();
F != FEnd; ++F) {
- if (F->hasInClassInitializer())
+ if (F->hasInClassInitializer() || F->isUnnamedBitfield())
continue;
if (F->getType()->isReferenceType() ||
@@ -3077,6 +3604,47 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
}
}
+ // C++0x [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.
+ //
+ // It's fine to diagnose constructors here too: such constructors cannot
+ // produce a constant expression, so are ill-formed (no diagnostic required).
+ //
+ // 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() &&
+ !Record->isLiteral() && !Record->getNumVBases()) {
+ for (CXXRecordDecl::method_iterator M = Record->method_begin(),
+ MEnd = Record->method_end();
+ M != MEnd; ++M) {
+ if ((*M)->isConstexpr()) {
+ switch (Record->getTemplateSpecializationKind()) {
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ // If a template instantiates to a non-literal type, but its members
+ // instantiate to constexpr functions, the template is technically
+ // ill-formed, but we allow it for sanity. Such members are treated as
+ // non-constexpr.
+ (*M)->setConstexpr(false);
+ continue;
+
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ RequireLiteralType((*M)->getLocation(), Context.getRecordType(Record),
+ PDiag(diag::err_constexpr_method_non_literal));
+ break;
+ }
+
+ // Only produce one error per class.
+ break;
+ }
+ }
+ }
+
// Declare inherited constructors. We do this eagerly here because:
// - The standard requires an eager diagnostic for conflicting inherited
// constructors from different classes.
@@ -3114,12 +3682,14 @@ void Sema::CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record) {
break;
case CXXMoveConstructor:
+ CheckExplicitlyDefaultedMoveConstructor(cast<CXXConstructorDecl>(*MI));
+ break;
+
case CXXMoveAssignment:
- Diag(MI->getLocation(), diag::err_defaulted_move_unsupported);
+ CheckExplicitlyDefaultedMoveAssignment(*MI);
break;
- default:
- // FIXME: Do moves once they exist
+ case CXXInvalid:
llvm_unreachable("non-special member explicitly defaulted!");
}
}
@@ -3176,7 +3746,7 @@ void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) {
return;
}
- if (ShouldDeleteDefaultConstructor(CD)) {
+ if (ShouldDeleteSpecialMember(CD, CXXDefaultConstructor)) {
if (First) {
CD->setDeletedAsWritten();
} else {
@@ -3243,7 +3813,7 @@ void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) {
return;
}
- if (ShouldDeleteCopyConstructor(CD)) {
+ if (ShouldDeleteSpecialMember(CD, CXXCopyConstructor)) {
if (First) {
CD->setDeletedAsWritten();
} else {
@@ -3288,7 +3858,7 @@ void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) {
Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
QualType ArgType = OperType->getArgType(0);
- if (!ArgType->isReferenceType()) {
+ if (!ArgType->isLValueReferenceType()) {
Diag(MD->getLocation(), diag::err_defaulted_copy_assign_not_ref);
HadError = true;
} else {
@@ -3340,6 +3910,155 @@ void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) {
}
}
+void Sema::CheckExplicitlyDefaultedMoveConstructor(CXXConstructorDecl *CD) {
+ assert(CD->isExplicitlyDefaulted() && CD->isMoveConstructor());
+
+ // Whether this was the first-declared instance of the constructor.
+ bool First = CD == CD->getCanonicalDecl();
+
+ bool HadError = false;
+ if (CD->getNumParams() != 1) {
+ Diag(CD->getLocation(), diag::err_defaulted_move_ctor_params)
+ << CD->getSourceRange();
+ HadError = true;
+ }
+
+ ImplicitExceptionSpecification Spec(
+ ComputeDefaultedMoveCtorExceptionSpec(CD->getParent()));
+
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+ const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(),
+ *ExceptionType = Context.getFunctionType(
+ Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
+
+ // Check for parameter type matching.
+ // This is a move ctor so we know it's a cv-qualified rvalue reference to T.
+ QualType ArgType = CtorType->getArgType(0);
+ if (ArgType->getPointeeType().isVolatileQualified()) {
+ Diag(CD->getLocation(), diag::err_defaulted_move_ctor_volatile_param);
+ HadError = true;
+ }
+ if (ArgType->getPointeeType().isConstQualified()) {
+ Diag(CD->getLocation(), diag::err_defaulted_move_ctor_const_param);
+ HadError = true;
+ }
+
+ if (CtorType->hasExceptionSpec()) {
+ if (CheckEquivalentExceptionSpec(
+ PDiag(diag::err_incorrect_defaulted_exception_spec)
+ << CXXMoveConstructor,
+ PDiag(),
+ ExceptionType, SourceLocation(),
+ CtorType, CD->getLocation())) {
+ HadError = true;
+ }
+ } else if (First) {
+ // We set the declaration to have the computed exception spec here.
+ // We duplicate the one parameter type.
+ EPI.ExtInfo = CtorType->getExtInfo();
+ CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
+ }
+
+ if (HadError) {
+ CD->setInvalidDecl();
+ return;
+ }
+
+ if (ShouldDeleteSpecialMember(CD, CXXMoveConstructor)) {
+ if (First) {
+ CD->setDeletedAsWritten();
+ } else {
+ Diag(CD->getLocation(), diag::err_out_of_line_default_deletes)
+ << CXXMoveConstructor;
+ CD->setInvalidDecl();
+ }
+ }
+}
+
+void Sema::CheckExplicitlyDefaultedMoveAssignment(CXXMethodDecl *MD) {
+ assert(MD->isExplicitlyDefaulted());
+
+ // Whether this was the first-declared instance of the operator
+ bool First = MD == MD->getCanonicalDecl();
+
+ bool HadError = false;
+ if (MD->getNumParams() != 1) {
+ Diag(MD->getLocation(), diag::err_defaulted_move_assign_params)
+ << MD->getSourceRange();
+ HadError = true;
+ }
+
+ QualType ReturnType =
+ MD->getType()->getAs<FunctionType>()->getResultType();
+ if (!ReturnType->isLValueReferenceType() ||
+ !Context.hasSameType(
+ Context.getCanonicalType(ReturnType->getPointeeType()),
+ Context.getCanonicalType(Context.getTypeDeclType(MD->getParent())))) {
+ Diag(MD->getLocation(), diag::err_defaulted_move_assign_return_type);
+ HadError = true;
+ }
+
+ ImplicitExceptionSpecification Spec(
+ ComputeDefaultedMoveCtorExceptionSpec(MD->getParent()));
+
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+ const FunctionProtoType *OperType = MD->getType()->getAs<FunctionProtoType>(),
+ *ExceptionType = Context.getFunctionType(
+ Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
+
+ QualType ArgType = OperType->getArgType(0);
+ if (!ArgType->isRValueReferenceType()) {
+ Diag(MD->getLocation(), diag::err_defaulted_move_assign_not_ref);
+ HadError = true;
+ } else {
+ if (ArgType->getPointeeType().isVolatileQualified()) {
+ Diag(MD->getLocation(), diag::err_defaulted_move_assign_volatile_param);
+ HadError = true;
+ }
+ if (ArgType->getPointeeType().isConstQualified()) {
+ Diag(MD->getLocation(), diag::err_defaulted_move_assign_const_param);
+ HadError = true;
+ }
+ }
+
+ if (OperType->getTypeQuals()) {
+ Diag(MD->getLocation(), diag::err_defaulted_move_assign_quals);
+ HadError = true;
+ }
+
+ if (OperType->hasExceptionSpec()) {
+ if (CheckEquivalentExceptionSpec(
+ PDiag(diag::err_incorrect_defaulted_exception_spec)
+ << CXXMoveAssignment,
+ PDiag(),
+ ExceptionType, SourceLocation(),
+ OperType, MD->getLocation())) {
+ HadError = true;
+ }
+ } else if (First) {
+ // We set the declaration to have the computed exception spec here.
+ // We duplicate the one parameter type.
+ EPI.RefQualifier = OperType->getRefQualifier();
+ EPI.ExtInfo = OperType->getExtInfo();
+ MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI));
+ }
+
+ if (HadError) {
+ MD->setInvalidDecl();
+ return;
+ }
+
+ if (ShouldDeleteMoveAssignmentOperator(MD)) {
+ if (First) {
+ MD->setDeletedAsWritten();
+ } else {
+ Diag(MD->getLocation(), diag::err_out_of_line_default_deletes)
+ << CXXMoveAssignment;
+ MD->setInvalidDecl();
+ }
+ }
+}
+
void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) {
assert(DD->isExplicitlyDefaulted());
@@ -3381,30 +4100,53 @@ void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) {
}
}
-bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
- CXXRecordDecl *RD = CD->getParent();
+/// This function implements the following C++0x paragraphs:
+/// - [class.ctor]/5
+/// - [class.copy]/11
+bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM) {
+ assert(!MD->isInvalidDecl());
+ CXXRecordDecl *RD = MD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
return false;
- SourceLocation Loc = CD->getLocation();
+ bool IsUnion = RD->isUnion();
+ bool IsConstructor = false;
+ bool IsAssignment = false;
+ bool IsMove = false;
+
+ bool ConstArg = false;
- // Do access control from the constructor
- ContextRAII CtorContext(*this, CD);
+ switch (CSM) {
+ case CXXDefaultConstructor:
+ IsConstructor = true;
+ break;
+ case CXXCopyConstructor:
+ IsConstructor = true;
+ ConstArg = MD->getParamDecl(0)->getType().isConstQualified();
+ break;
+ case CXXMoveConstructor:
+ IsConstructor = true;
+ IsMove = true;
+ break;
+ default:
+ llvm_unreachable("function only currently implemented for default ctors");
+ }
+
+ SourceLocation Loc = MD->getLocation();
+
+ // Do access control from the special member function
+ ContextRAII MethodContext(*this, MD);
- bool Union = RD->isUnion();
bool AllConst = true;
// We do this because we should never actually use an anonymous
// union's constructor.
- if (Union && RD->isAnonymousStructOrUnion())
+ if (IsUnion && RD->isAnonymousStructOrUnion())
return false;
// FIXME: We should put some diagnostic logic right into this function.
- // C++0x [class.ctor]/5
- // A defaulted default constructor for class X is defined as deleted if:
-
for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
BE = RD->bases_end();
BI != BE; ++BI) {
@@ -3415,26 +4157,41 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
assert(BaseDecl && "base isn't a CXXRecordDecl");
- // -- any [direct base class] has a type with a destructor that is
- // deleted or inaccessible from the defaulted default constructor
- CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
- if (BaseDtor->isDeleted())
- return true;
- if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
- AR_accessible)
- return true;
+ // Unless we have an assignment operator, the base's destructor must
+ // be accessible and not deleted.
+ if (!IsAssignment) {
+ CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
+ if (BaseDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+ }
- // -- any [direct base class either] has no default constructor or
- // overload resolution as applied to [its] default constructor
- // results in an ambiguity or in a function that is deleted or
- // inaccessible from the defaulted default constructor
- CXXConstructorDecl *BaseDefault = LookupDefaultConstructor(BaseDecl);
- if (!BaseDefault || BaseDefault->isDeleted())
- return true;
+ // Finding the corresponding member in the base should lead to a
+ // unique, accessible, non-deleted function. If we are doing
+ // a destructor, we have already checked this case.
+ if (CSM != CXXDestructor) {
+ SpecialMemberOverloadResult *SMOR =
+ LookupSpecialMember(BaseDecl, CSM, ConstArg, false, false, false,
+ false);
+ if (!SMOR->hasSuccess())
+ return true;
+ CXXMethodDecl *BaseMember = SMOR->getMethod();
+ if (IsConstructor) {
+ CXXConstructorDecl *BaseCtor = cast<CXXConstructorDecl>(BaseMember);
+ if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(),
+ PDiag()) != AR_accessible)
+ return true;
- if (CheckConstructorAccess(Loc, BaseDefault, BaseDefault->getAccess(),
- PDiag()) != AR_accessible)
- return true;
+ // For a move operation, the corresponding operation must actually
+ // be a move operation (and not a copy selected by overload
+ // resolution) unless we are working on a trivially copyable class.
+ if (IsMove && !BaseCtor->isMoveConstructor() &&
+ !BaseDecl->isTriviallyCopyable())
+ return true;
+ }
+ }
}
for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
@@ -3443,69 +4200,76 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
assert(BaseDecl && "base isn't a CXXRecordDecl");
- // -- any [virtual base class] has a type with a destructor that is
- // delete or inaccessible from the defaulted default constructor
- CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
- if (BaseDtor->isDeleted())
- return true;
- if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
- AR_accessible)
- return true;
+ // Unless we have an assignment operator, the base's destructor must
+ // be accessible and not deleted.
+ if (!IsAssignment) {
+ CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
+ if (BaseDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+ }
- // -- any [virtual base class either] has no default constructor or
- // overload resolution as applied to [its] default constructor
- // results in an ambiguity or in a function that is deleted or
- // inaccessible from the defaulted default constructor
- CXXConstructorDecl *BaseDefault = LookupDefaultConstructor(BaseDecl);
- if (!BaseDefault || BaseDefault->isDeleted())
- return true;
+ // Finding the corresponding member in the base should lead to a
+ // unique, accessible, non-deleted function.
+ if (CSM != CXXDestructor) {
+ SpecialMemberOverloadResult *SMOR =
+ LookupSpecialMember(BaseDecl, CSM, ConstArg, false, false, false,
+ false);
+ if (!SMOR->hasSuccess())
+ return true;
+ CXXMethodDecl *BaseMember = SMOR->getMethod();
+ if (IsConstructor) {
+ CXXConstructorDecl *BaseCtor = cast<CXXConstructorDecl>(BaseMember);
+ if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(),
+ PDiag()) != AR_accessible)
+ return true;
- if (CheckConstructorAccess(Loc, BaseDefault, BaseDefault->getAccess(),
- PDiag()) != AR_accessible)
- return true;
+ // For a move operation, the corresponding operation must actually
+ // be a move operation (and not a copy selected by overload
+ // resolution) unless we are working on a trivially copyable class.
+ if (IsMove && !BaseCtor->isMoveConstructor() &&
+ !BaseDecl->isTriviallyCopyable())
+ return true;
+ }
+ }
}
for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
FE = RD->field_end();
FI != FE; ++FI) {
- if (FI->isInvalidDecl())
+ if (FI->isInvalidDecl() || FI->isUnnamedBitfield())
continue;
QualType FieldType = Context.getBaseElementType(FI->getType());
CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
- // -- any non-static data member with no brace-or-equal-initializer is of
- // reference type
- if (FieldType->isReferenceType() && !FI->hasInClassInitializer())
- return true;
-
- // -- X is a union and all its variant members are of const-qualified type
- // (or array thereof)
- if (Union && !FieldType.isConstQualified())
- AllConst = false;
-
- if (FieldRecord) {
- // -- X is a union-like class that has a variant member with a non-trivial
- // default constructor
- if (Union && !FieldRecord->hasTrivialDefaultConstructor())
+ // For a default constructor, all references must be initialized in-class
+ // and, if a union, it must have a non-const member.
+ if (CSM == CXXDefaultConstructor) {
+ if (FieldType->isReferenceType() && !FI->hasInClassInitializer())
return true;
- CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord);
- if (FieldDtor->isDeleted())
- return true;
- if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) !=
- AR_accessible)
+ if (IsUnion && !FieldType.isConstQualified())
+ AllConst = false;
+ // For a copy constructor, data members must not be of rvalue reference
+ // type.
+ } else if (CSM == CXXCopyConstructor) {
+ if (FieldType->isRValueReferenceType())
return true;
+ }
- // -- any non-variant non-static data member of const-qualified type (or
- // array thereof) with no brace-or-equal-initializer does not have a
- // user-provided default constructor
- if (FieldType.isConstQualified() &&
+ if (FieldRecord) {
+ // For a default constructor, a const member must have a user-provided
+ // default constructor or else be explicitly initialized.
+ if (CSM == CXXDefaultConstructor && FieldType.isConstQualified() &&
!FI->hasInClassInitializer() &&
!FieldRecord->hasUserProvidedDefaultConstructor())
return true;
- if (!Union && FieldRecord->isUnion() &&
+ // Some additional restrictions exist on the variant members.
+ if (!IsUnion && FieldRecord->isUnion() &&
FieldRecord->isAnonymousStructOrUnion()) {
// We're okay to reuse AllConst here since we only care about the
// value otherwise if we're in a union.
@@ -3521,12 +4285,49 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
if (!UnionFieldType.isConstQualified())
AllConst = false;
- if (UnionFieldRecord &&
- !UnionFieldRecord->hasTrivialDefaultConstructor())
- return true;
+ if (UnionFieldRecord) {
+ // FIXME: Checking for accessibility and validity of this
+ // destructor is technically going beyond the
+ // standard, but this is believed to be a defect.
+ if (!IsAssignment) {
+ CXXDestructorDecl *FieldDtor = LookupDestructor(UnionFieldRecord);
+ if (FieldDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+ if (!FieldDtor->isTrivial())
+ return true;
+ }
+
+ if (CSM != CXXDestructor) {
+ SpecialMemberOverloadResult *SMOR =
+ LookupSpecialMember(UnionFieldRecord, CSM, ConstArg, false,
+ false, false, false);
+ // FIXME: Checking for accessibility and validity of this
+ // corresponding member is technically going beyond the
+ // standard, but this is believed to be a defect.
+ if (!SMOR->hasSuccess())
+ return true;
+
+ CXXMethodDecl *FieldMember = SMOR->getMethod();
+ // A member of a union must have a trivial corresponding
+ // constructor.
+ if (!FieldMember->isTrivial())
+ return true;
+
+ if (IsConstructor) {
+ CXXConstructorDecl *FieldCtor = cast<CXXConstructorDecl>(FieldMember);
+ if (CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(),
+ PDiag()) != AR_accessible)
+ return true;
+ }
+ }
+ }
}
- if (AllConst)
+ // At least one member in each anonymous union must be non-const
+ if (CSM == CXXDefaultConstructor && AllConst)
return true;
// Don't try to initialize the anonymous union
@@ -3534,51 +4335,81 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
continue;
}
- // -- any non-static data member with no brace-or-equal-initializer has
- // class type M (or array thereof) and either M has no default
- // constructor or overload resolution as applied to M's default
- // constructor results in an ambiguity or in a function that is deleted
- // or inaccessible from the defaulted default constructor.
- if (!FI->hasInClassInitializer()) {
- CXXConstructorDecl *FieldDefault = LookupDefaultConstructor(FieldRecord);
- if (!FieldDefault || FieldDefault->isDeleted())
+ // Unless we're doing assignment, the field's destructor must be
+ // accessible and not deleted.
+ if (!IsAssignment) {
+ CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord);
+ if (FieldDtor->isDeleted())
return true;
- if (CheckConstructorAccess(Loc, FieldDefault, FieldDefault->getAccess(),
- PDiag()) != AR_accessible)
+ if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+ }
+
+ // Check that the corresponding member of the field is accessible,
+ // unique, and non-deleted. We don't do this if it has an explicit
+ // initialization when default-constructing.
+ if (CSM != CXXDestructor &&
+ (CSM != CXXDefaultConstructor || !FI->hasInClassInitializer())) {
+ SpecialMemberOverloadResult *SMOR =
+ LookupSpecialMember(FieldRecord, CSM, ConstArg, false, false, false,
+ false);
+ if (!SMOR->hasSuccess())
+ return true;
+
+ CXXMethodDecl *FieldMember = SMOR->getMethod();
+ if (IsConstructor) {
+ CXXConstructorDecl *FieldCtor = cast<CXXConstructorDecl>(FieldMember);
+ if (CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(),
+ PDiag()) != AR_accessible)
+ return true;
+
+ // For a move operation, the corresponding operation must actually
+ // be a move operation (and not a copy selected by overload
+ // resolution) unless we are working on a trivially copyable class.
+ if (IsMove && !FieldCtor->isMoveConstructor() &&
+ !FieldRecord->isTriviallyCopyable())
+ return true;
+ }
+
+ // We need the corresponding member of a union to be trivial so that
+ // we can safely copy them all simultaneously.
+ // FIXME: Note that performing the check here (where we rely on the lack
+ // of an in-class initializer) is technically ill-formed. However, this
+ // seems most obviously to be a bug in the standard.
+ if (IsUnion && !FieldMember->isTrivial())
return true;
}
- } else if (!Union && FieldType.isConstQualified() &&
- !FI->hasInClassInitializer()) {
- // -- any non-variant non-static data member of const-qualified type (or
- // array thereof) with no brace-or-equal-initializer does not have a
- // user-provided default constructor
+ } else if (CSM == CXXDefaultConstructor && !IsUnion &&
+ FieldType.isConstQualified() && !FI->hasInClassInitializer()) {
+ // We can't initialize a const member of non-class type to any value.
return true;
}
}
- if (Union && AllConst)
+ // We can't have all const members in a union when default-constructing,
+ // or else they're all nonsensical garbage values that can't be changed.
+ if (CSM == CXXDefaultConstructor && IsUnion && AllConst)
return true;
return false;
}
-bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) {
- CXXRecordDecl *RD = CD->getParent();
+bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
+ CXXRecordDecl *RD = MD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
return false;
- SourceLocation Loc = CD->getLocation();
+ SourceLocation Loc = MD->getLocation();
// Do access control from the constructor
- ContextRAII CtorContext(*this, CD);
+ ContextRAII MethodContext(*this, MD);
bool Union = RD->isUnion();
- assert(!CD->getParamDecl(0)->getType()->getPointeeType().isNull() &&
- "copy assignment arg has no pointee type");
unsigned ArgQuals =
- CD->getParamDecl(0)->getType()->getPointeeType().isConstQualified() ?
+ MD->getParamDecl(0)->getType()->getPointeeType().isConstQualified() ?
Qualifiers::Const : 0;
// We do this because we should never actually use an anonymous
@@ -3588,8 +4419,9 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) {
// FIXME: We should put some diagnostic logic right into this function.
- // C++0x [class.copy]/11
- // A defaulted [copy] constructor for class X is defined as delete if X has:
+ // C++0x [class.copy]/20
+ // A defaulted [copy] assignment operator for class X is defined as deleted
+ // if X has:
for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
BE = RD->bases_end();
@@ -3602,24 +4434,15 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) {
CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl();
assert(BaseDecl && "base isn't a CXXRecordDecl");
- // -- any [direct base class] of a type with a destructor that is deleted or
- // inaccessible from the defaulted constructor
- CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
- if (BaseDtor->isDeleted())
- return true;
- if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
- AR_accessible)
- return true;
-
// -- a [direct base class] B that cannot be [copied] because overload
- // resolution, as applied to B's [copy] constructor, results in an
- // ambiguity or a function that is deleted or inaccessible from the
- // defaulted constructor
- CXXConstructorDecl *BaseCtor = LookupCopyingConstructor(BaseDecl, ArgQuals);
- if (!BaseCtor || BaseCtor->isDeleted())
+ // resolution, as applied to B's [copy] assignment operator, results in
+ // an ambiguity or a function that is deleted or inaccessible from the
+ // assignment operator
+ CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false,
+ 0);
+ if (!CopyOper || CopyOper->isDeleted())
return true;
- if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) !=
- AR_accessible)
+ if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible)
return true;
}
@@ -3630,35 +4453,32 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) {
CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl();
assert(BaseDecl && "base isn't a CXXRecordDecl");
- // -- any [virtual base class] of a type with a destructor that is deleted or
- // inaccessible from the defaulted constructor
- CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
- if (BaseDtor->isDeleted())
- return true;
- if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
- AR_accessible)
- return true;
-
// -- a [virtual base class] B that cannot be [copied] because overload
- // resolution, as applied to B's [copy] constructor, results in an
- // ambiguity or a function that is deleted or inaccessible from the
- // defaulted constructor
- CXXConstructorDecl *BaseCtor = LookupCopyingConstructor(BaseDecl, ArgQuals);
- if (!BaseCtor || BaseCtor->isDeleted())
+ // resolution, as applied to B's [copy] assignment operator, results in
+ // an ambiguity or a function that is deleted or inaccessible from the
+ // assignment operator
+ CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false,
+ 0);
+ if (!CopyOper || CopyOper->isDeleted())
return true;
- if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) !=
- AR_accessible)
+ if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible)
return true;
}
for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
FE = RD->field_end();
FI != FE; ++FI) {
+ if (FI->isUnnamedBitfield())
+ continue;
+
QualType FieldType = Context.getBaseElementType(FI->getType());
- // -- for a copy constructor, a non-static data member of rvalue reference
- // type
- if (FieldType->isRValueReferenceType())
+ // -- a non-static data member of reference type
+ if (FieldType->isReferenceType())
+ return true;
+
+ // -- a non-static data member of const non-class type (or array thereof)
+ if (FieldType.isConstQualified() && !FieldType->isRecordType())
return true;
CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
@@ -3675,42 +4495,27 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) {
CXXRecordDecl *UnionFieldRecord =
UnionFieldType->getAsCXXRecordDecl();
- // -- a variant member with a non-trivial [copy] constructor and X
- // is a union-like class
+ // -- a variant member with a non-trivial [copy] assignment operator
+ // and X is a union-like class
if (UnionFieldRecord &&
- !UnionFieldRecord->hasTrivialCopyConstructor())
+ !UnionFieldRecord->hasTrivialCopyAssignment())
return true;
}
}
// Don't try to initalize an anonymous union
continue;
- } else {
- // -- a variant member with a non-trivial [copy] constructor and X is a
- // union-like class
- if (Union && !FieldRecord->hasTrivialCopyConstructor())
- return true;
-
- // -- any [non-static data member] of a type with a destructor that is
- // deleted or inaccessible from the defaulted constructor
- CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord);
- if (FieldDtor->isDeleted())
- return true;
- if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) !=
- AR_accessible)
+ // -- a variant member with a non-trivial [copy] assignment operator
+ // and X is a union-like class
+ } else if (Union && !FieldRecord->hasTrivialCopyAssignment()) {
return true;
}
- // -- a [non-static data member of class type (or array thereof)] B that
- // cannot be [copied] because overload resolution, as applied to B's
- // [copy] constructor, results in an ambiguity or a function that is
- // deleted or inaccessible from the defaulted constructor
- CXXConstructorDecl *FieldCtor = LookupCopyingConstructor(FieldRecord,
- ArgQuals);
- if (!FieldCtor || FieldCtor->isDeleted())
+ CXXMethodDecl *CopyOper = LookupCopyingAssignment(FieldRecord, ArgQuals,
+ false, 0);
+ if (!CopyOper || CopyOper->isDeleted())
return true;
- if (CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(),
- PDiag()) != AR_accessible)
+ if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible)
return true;
}
}
@@ -3718,7 +4523,7 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) {
return false;
}
-bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
+bool Sema::ShouldDeleteMoveAssignmentOperator(CXXMethodDecl *MD) {
CXXRecordDecl *RD = MD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
@@ -3731,66 +4536,52 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
bool Union = RD->isUnion();
- unsigned ArgQuals =
- MD->getParamDecl(0)->getType()->getPointeeType().isConstQualified() ?
- Qualifiers::Const : 0;
-
// We do this because we should never actually use an anonymous
// union's constructor.
if (Union && RD->isAnonymousStructOrUnion())
return false;
- // FIXME: We should put some diagnostic logic right into this function.
-
- // C++0x [class.copy]/11
- // A defaulted [copy] assignment operator for class X is defined as deleted
+ // C++0x [class.copy]/20
+ // A defaulted [move] assignment operator for class X is defined as deleted
// if X has:
+ // -- for the move constructor, [...] any direct or indirect virtual base
+ // class.
+ if (RD->getNumVBases() != 0)
+ return true;
+
for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
BE = RD->bases_end();
BI != BE; ++BI) {
- // We'll handle this one later
- if (BI->isVirtual())
- continue;
QualType BaseType = BI->getType();
CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl();
assert(BaseDecl && "base isn't a CXXRecordDecl");
- // -- a [direct base class] B that cannot be [copied] because overload
- // resolution, as applied to B's [copy] assignment operator, results in
+ // -- a [direct base class] B that cannot be [moved] because overload
+ // resolution, as applied to B's [move] assignment operator, results in
// an ambiguity or a function that is deleted or inaccessible from the
// assignment operator
- CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false,
- 0);
- if (!CopyOper || CopyOper->isDeleted())
+ CXXMethodDecl *MoveOper = LookupMovingAssignment(BaseDecl, false, 0);
+ if (!MoveOper || MoveOper->isDeleted())
return true;
- if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible)
+ if (CheckDirectMemberAccess(Loc, MoveOper, PDiag()) != AR_accessible)
return true;
- }
- for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
- BE = RD->vbases_end();
- BI != BE; ++BI) {
- QualType BaseType = BI->getType();
- CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl();
- assert(BaseDecl && "base isn't a CXXRecordDecl");
-
- // -- a [virtual base class] B that cannot be [copied] because overload
- // resolution, as applied to B's [copy] assignment operator, results in
- // an ambiguity or a function that is deleted or inaccessible from the
- // assignment operator
- CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false,
- 0);
- if (!CopyOper || CopyOper->isDeleted())
- return true;
- if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible)
+ // -- for the move assignment operator, a [direct base class] with a type
+ // that does not have a move assignment operator and is not trivially
+ // copyable.
+ if (!MoveOper->isMoveAssignmentOperator() &&
+ !BaseDecl->isTriviallyCopyable())
return true;
}
for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
FE = RD->field_end();
FI != FE; ++FI) {
+ if (FI->isUnnamedBitfield())
+ continue;
+
QualType FieldType = Context.getBaseElementType(FI->getType());
// -- a non-static data member of reference type
@@ -3800,7 +4591,7 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
// -- a non-static data member of const non-class type (or array thereof)
if (FieldType.isConstQualified() && !FieldType->isRecordType())
return true;
-
+
CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
if (FieldRecord) {
@@ -3815,28 +4606,34 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
CXXRecordDecl *UnionFieldRecord =
UnionFieldType->getAsCXXRecordDecl();
- // -- a variant member with a non-trivial [copy] assignment operator
+ // -- a variant member with a non-trivial [move] assignment operator
// and X is a union-like class
if (UnionFieldRecord &&
- !UnionFieldRecord->hasTrivialCopyAssignment())
+ !UnionFieldRecord->hasTrivialMoveAssignment())
return true;
}
}
// Don't try to initalize an anonymous union
continue;
- // -- a variant member with a non-trivial [copy] assignment operator
+ // -- a variant member with a non-trivial [move] assignment operator
// and X is a union-like class
- } else if (Union && !FieldRecord->hasTrivialCopyAssignment()) {
+ } else if (Union && !FieldRecord->hasTrivialMoveAssignment()) {
return true;
}
- CXXMethodDecl *CopyOper = LookupCopyingAssignment(FieldRecord, ArgQuals,
- false, 0);
- if (!CopyOper || CopyOper->isDeleted())
- return false;
- if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible)
- return false;
+ CXXMethodDecl *MoveOper = LookupMovingAssignment(FieldRecord, false, 0);
+ if (!MoveOper || MoveOper->isDeleted())
+ return true;
+ if (CheckDirectMemberAccess(Loc, MoveOper, PDiag()) != AR_accessible)
+ return true;
+
+ // -- for the move assignment operator, a [non-static data member] with a
+ // type that does not have a move assignment operator and is not
+ // trivially copyable.
+ if (!MoveOper->isMoveAssignmentOperator() &&
+ !FieldRecord->isTriviallyCopyable())
+ return true;
}
}
@@ -3959,7 +4756,7 @@ namespace {
Sema *S;
CXXMethodDecl *Method;
llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverridenAndUsingBaseMethods;
- llvm::SmallVector<CXXMethodDecl *, 8> OverloadedMethods;
+ SmallVector<CXXMethodDecl *, 8> OverloadedMethods;
};
}
@@ -3978,7 +4775,7 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier,
assert(Name.getNameKind() == DeclarationName::Identifier);
bool foundSameNameMethod = false;
- llvm::SmallVector<CXXMethodDecl *, 8> overloadedMethods;
+ SmallVector<CXXMethodDecl *, 8> overloadedMethods;
for (Path.Decls = BaseRecord->lookup(Name);
Path.Decls.first != Path.Decls.second;
++Path.Decls.first) {
@@ -4009,7 +4806,7 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier,
/// overriding any.
void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
if (Diags.getDiagnosticLevel(diag::warn_overloaded_virtual,
- MD->getLocation()) == Diagnostic::Ignored)
+ MD->getLocation()) == DiagnosticsEngine::Ignored)
return;
if (MD->getDeclName().getNameKind() != DeclarationName::Identifier)
return;
@@ -4058,10 +4855,10 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
AdjustDeclIfTemplate(TagDecl);
- ActOnFields(S, RLoc, TagDecl,
+ ActOnFields(S, RLoc, TagDecl, llvm::makeArrayRef(
// strict aliasing violation!
reinterpret_cast<Decl**>(FieldCollector->getCurFields()),
- FieldCollector->getCurNumFields(), LBrac, RBrac, AttrList);
+ FieldCollector->getCurNumFields()), LBrac, RBrac, AttrList);
CheckCompletedCXXClass(
dyn_cast_or_null<CXXRecordDecl>(TagDecl));
@@ -4946,7 +5743,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
IdentLoc, Named, CommonAncestor);
if (IsUsingDirectiveInToplevelContext(CurContext) &&
- !SourceMgr.isFromMainFile(SourceMgr.getInstantiationLoc(IdentLoc))) {
+ !SourceMgr.isFromMainFile(SourceMgr.getExpansionLoc(IdentLoc))) {
Diag(IdentLoc, diag::warn_using_directive_in_header);
}
@@ -5361,7 +6158,6 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
// Otherwise, look up the target name.
LookupResult R(*this, NameInfo, LookupOrdinaryName);
- R.setUsingDeclaration(true);
// Unlike most lookups, we don't always want to hide tag
// declarations: tag names are visible through the using declaration
@@ -5968,7 +6764,9 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
/*TInfo=*/0,
/*isExplicit=*/false,
/*isInline=*/true,
- /*isImplicitlyDeclared=*/true);
+ /*isImplicitlyDeclared=*/true,
+ // FIXME: apply the rules for definitions here
+ /*isConstexpr=*/false);
DefaultCon->setAccess(AS_public);
DefaultCon->setDefaulted();
DefaultCon->setImplicit();
@@ -5981,7 +6779,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
PushOnScopeChains(DefaultCon, S, false);
ClassDecl->addDecl(DefaultCon);
- if (ShouldDeleteDefaultConstructor(DefaultCon))
+ if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor))
DefaultCon->setDeletedAsWritten();
return DefaultCon;
@@ -6075,7 +6873,7 @@ void Sema::DeclareInheritedConstructors(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.
- typedef llvm::SmallVector<const RecordType *, 4> BasesVector;
+ typedef SmallVector<const RecordType *, 4> BasesVector;
BasesVector BasesToInheritFrom;
for (CXXRecordDecl::base_class_iterator BaseIt = ClassDecl->bases_begin(),
BaseE = ClassDecl->bases_end();
@@ -6171,7 +6969,7 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
if (params == maxParams)
NewCtorType = BaseCtorType;
else {
- llvm::SmallVector<QualType, 16> Args;
+ SmallVector<QualType, 16> Args;
for (unsigned i = 0; i < params; ++i) {
Args.push_back(BaseCtorType->getArgType(i));
}
@@ -6219,16 +7017,19 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
// OK, we're there, now add the constructor.
// C++0x [class.inhctor]p8: [...] that would be performed by a
- // user-writtern inline constructor [...]
+ // user-written inline constructor [...]
DeclarationNameInfo DNI(CreatedCtorName, UsingLoc);
CXXConstructorDecl *NewCtor = CXXConstructorDecl::Create(
Context, ClassDecl, UsingLoc, DNI, QualType(NewCtorType, 0),
/*TInfo=*/0, BaseCtor->isExplicit(), /*Inline=*/true,
- /*ImplicitlyDeclared=*/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());
NewCtor->setAccess(BaseCtor->getAccess());
// Build up the parameter decls and add them.
- llvm::SmallVector<ParmVarDecl *, 16> ParamDecls;
+ SmallVector<ParmVarDecl *, 16> ParamDecls;
for (unsigned i = 0; i < params; ++i) {
ParamDecls.push_back(ParmVarDecl::Create(Context, NewCtor,
UsingLoc, UsingLoc,
@@ -6237,7 +7038,7 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
/*TInfo=*/0, SC_None,
SC_None, /*DefaultArg=*/0));
}
- NewCtor->setParams(ParamDecls.data(), ParamDecls.size());
+ NewCtor->setParams(ParamDecls);
NewCtor->setInheritedConstructor(BaseCtor);
PushOnScopeChains(NewCtor, S, false);
@@ -6365,7 +7166,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
SourceLocation Loc = Destructor->getLocation();
Destructor->setBody(new (Context) CompoundStmt(Context, 0, 0, Loc, Loc));
-
+ Destructor->setImplicitlyDefined(true);
Destructor->setUsed();
MarkVTableUsed(CurrentLocation, ClassDecl);
@@ -6388,8 +7189,10 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl,
ImplicitExceptionSpecification exceptSpec =
ComputeDefaultedDtorExceptionSpec(classDecl);
- // Replace the destructor's type.
- FunctionProtoType::ExtProtoInfo epi;
+ // Replace the destructor's type, building off the existing one. Fortunately,
+ // the only thing of interest in the destructor type is its extended info.
+ // The return and arguments are fixed.
+ FunctionProtoType::ExtProtoInfo epi = dtorType->getExtProtoInfo();
epi.ExceptionSpecType = exceptSpec.getExceptionSpecType();
epi.NumExceptions = exceptSpec.size();
epi.Exceptions = exceptSpec.data();
@@ -6403,41 +7206,45 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl,
// However, we don't have a body yet, so it needs to be done somewhere else.
}
-/// \brief Builds a statement that copies the given entity from \p From to
+/// \brief Builds a statement that copies/moves the given entity from \p From to
/// \c To.
///
-/// This routine is used to copy the members of a class with an
-/// implicitly-declared copy assignment operator. When the entities being
+/// This routine is used to copy/move the members of a class with an
+/// implicitly-declared copy/move assignment operator. When the entities being
/// copied are arrays, this routine builds for loops to copy them.
///
/// \param S The Sema object used for type-checking.
///
-/// \param Loc The location where the implicit copy is being generated.
+/// \param Loc The location where the implicit copy/move is being generated.
///
-/// \param T The type of the expressions being copied. Both expressions must
-/// have this type.
+/// \param T The type of the expressions being copied/moved. Both expressions
+/// must have this type.
///
-/// \param To The expression we are copying to.
+/// \param To The expression we are copying/moving to.
///
-/// \param From The expression we are copying from.
+/// \param From The expression we are copying/moving from.
///
-/// \param CopyingBaseSubobject Whether we're copying a base subobject.
+/// \param CopyingBaseSubobject Whether we're copying/moving a base subobject.
/// Otherwise, it's a non-static member subobject.
///
+/// \param Copying Whether we're copying or moving.
+///
/// \param Depth Internal parameter recording the depth of the recursion.
///
/// \returns A statement or a loop that copies the expressions.
static StmtResult
BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
Expr *To, Expr *From,
- bool CopyingBaseSubobject, unsigned Depth = 0) {
- // C++0x [class.copy]p30:
+ bool CopyingBaseSubobject, bool Copying,
+ unsigned Depth = 0) {
+ // C++0x [class.copy]p28:
// Each subobject is assigned in the manner appropriate to its type:
//
- // - 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 the subobject is of class type, as if by a call to operator= with
+ // the subobject as the object expression and the corresponding
+ // 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);
if (const RecordType *RecordTy = T->getAs<RecordType>()) {
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
@@ -6447,14 +7254,15 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
LookupResult OpLookup(S, Name, Loc, Sema::LookupOrdinaryName);
S.LookupQualifiedName(OpLookup, ClassDecl, false);
- // Filter out any result that isn't a copy-assignment operator.
+ // 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())
+ if (Copying ? Method->isCopyAssignmentOperator() :
+ Method->isMoveAssignmentOperator())
continue;
-
+
F.erase();
}
F.done();
@@ -6573,11 +7381,13 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
IterationVarRef, Loc));
To = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(To, Loc,
IterationVarRef, Loc));
-
- // Build the copy for an individual element of the array.
+ 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,
- Depth + 1);
+ Copying, Depth + 1);
if (Copy.isInvalid())
return StmtError();
@@ -6733,7 +7543,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
Context.getFunctionType(RetType, &ArgType, 1, EPI),
/*TInfo=*/0, /*isStatic=*/false,
/*StorageClassAsWritten=*/SC_None,
- /*isInline=*/true,
+ /*isInline=*/true, /*isConstexpr=*/false,
SourceLocation());
CopyAssignment->setAccess(AS_public);
CopyAssignment->setDefaulted();
@@ -6746,7 +7556,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
ArgType, /*TInfo=*/0,
SC_None,
SC_None, 0);
- CopyAssignment->setParams(&FromParam, 1);
+ CopyAssignment->setParams(FromParam);
// Note that we have added this copy-assignment operator.
++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
@@ -6857,7 +7667,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
// Build the copy.
StmtResult Copy = BuildSingleCopyAssign(*this, Loc, BaseType,
To.get(), From,
- /*CopyingBaseSubobject=*/true);
+ /*CopyingBaseSubobject=*/true,
+ /*Copying=*/true);
if (Copy.isInvalid()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
@@ -6878,6 +7689,9 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
FieldEnd = ClassDecl->field_end();
Field != FieldEnd; ++Field) {
+ if (Field->isUnnamedBitfield())
+ continue;
+
// Check for members of reference type; we can't copy those.
if (Field->getType()->isReferenceType()) {
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
@@ -6902,9 +7716,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
}
// Suppress assigning zero-width bitfields.
- if (const Expr *Width = Field->getBitWidth())
- if (Width->EvaluateAsInt(Context) == 0)
- continue;
+ if (Field->isBitField() && Field->getBitWidthValue(Context) == 0)
+ continue;
QualType FieldType = Field->getType().getNonReferenceType();
if (FieldType->isIncompleteArrayType()) {
@@ -6932,8 +7745,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
// 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() &&
- BaseType.hasTrivialCopyAssignment(Context)) {
+ 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),
@@ -7020,8 +7833,9 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
// Build the copy of this field.
StmtResult Copy = BuildSingleCopyAssign(*this, Loc, FieldType,
- To.get(), From.get(),
- /*CopyingBaseSubobject=*/false);
+ To.get(), From.get(),
+ /*CopyingBaseSubobject=*/false,
+ /*Copying=*/true);
if (Copy.isInvalid()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
@@ -7066,6 +7880,436 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
}
}
+Sema::ImplicitExceptionSpecification
+Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) {
+ ImplicitExceptionSpecification ExceptSpec(Context);
+
+ if (ClassDecl->isInvalidDecl())
+ return ExceptSpec;
+
+ // C++0x [except.spec]p14:
+ // An implicitly declared special member function (Clause 12) shall have an
+ // exception-specification. [...]
+
+ // It is unspecified whether or not an implicit move assignment operator
+ // attempts to deduplicate calls to assignment operators of virtual bases are
+ // made. As such, this exception specification is effectively unspecified.
+ // Based on a similar decision made for constness in C++0x, we're erring on
+ // the side of assuming such calls to be made regardless of whether they
+ // actually happen.
+ // Note that a move constructor is not implicitly declared when there are
+ // virtual bases, but it can still be user-declared and explicitly defaulted.
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
+ BaseEnd = ClassDecl->bases_end();
+ Base != BaseEnd; ++Base) {
+ if (Base->isVirtual())
+ continue;
+
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,
+ false, 0))
+ ExceptSpec.CalledDecl(MoveAssign);
+ }
+
+ 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 (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,
+ false, 0))
+ ExceptSpec.CalledDecl(MoveAssign);
+ }
+
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+ FieldEnd = ClassDecl->field_end();
+ Field != FieldEnd;
+ ++Field) {
+ QualType FieldType = Context.getBaseElementType((*Field)->getType());
+ if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
+ if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(FieldClassDecl,
+ false, 0))
+ ExceptSpec.CalledDecl(MoveAssign);
+ }
+ }
+
+ return ExceptSpec;
+}
+
+CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
+ // Note: The following rules are largely analoguous to the move
+ // constructor rules.
+
+ ImplicitExceptionSpecification Spec(
+ ComputeDefaultedMoveAssignmentExceptionSpec(ClassDecl));
+
+ QualType ArgType = Context.getTypeDeclType(ClassDecl);
+ QualType RetType = Context.getLValueReferenceType(ArgType);
+ ArgType = Context.getRValueReferenceType(ArgType);
+
+ // An implicitly-declared move assignment operator is an inline public
+ // member of its class.
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+ DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
+ SourceLocation ClassLoc = ClassDecl->getLocation();
+ DeclarationNameInfo NameInfo(Name, ClassLoc);
+ CXXMethodDecl *MoveAssignment
+ = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
+ Context.getFunctionType(RetType, &ArgType, 1, EPI),
+ /*TInfo=*/0, /*isStatic=*/false,
+ /*StorageClassAsWritten=*/SC_None,
+ /*isInline=*/true,
+ /*isConstexpr=*/false,
+ SourceLocation());
+ MoveAssignment->setAccess(AS_public);
+ MoveAssignment->setDefaulted();
+ MoveAssignment->setImplicit();
+ MoveAssignment->setTrivial(ClassDecl->hasTrivialMoveAssignment());
+
+ // 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;
+
+ // C++0x [class.copy]p9:
+ // If the definition of a class X does not explicitly declare a move
+ // assignment operator, one will be implicitly declared as defaulted if and
+ // only if:
+ // [...]
+ // - the move assignment operator would not be implicitly defined as
+ // deleted.
+ if (ShouldDeleteMoveAssignmentOperator(MoveAssignment)) {
+ // Cache this result so that we don't try to generate this over and over
+ // on every lookup, leaking memory and wasting time.
+ ClassDecl->setFailedImplicitMoveAssignment();
+ return 0;
+ }
+
+ if (Scope *S = getScopeForContext(ClassDecl))
+ PushOnScopeChains(MoveAssignment, S, false);
+ ClassDecl->addDecl(MoveAssignment);
+
+ AddOverriddenMethods(ClassDecl, MoveAssignment);
+ return MoveAssignment;
+}
+
+void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
+ CXXMethodDecl *MoveAssignOperator) {
+ assert((MoveAssignOperator->isDefaulted() &&
+ MoveAssignOperator->isOverloadedOperator() &&
+ MoveAssignOperator->getOverloadedOperator() == OO_Equal &&
+ !MoveAssignOperator->doesThisDeclarationHaveABody()) &&
+ "DefineImplicitMoveAssignment called for wrong function");
+
+ CXXRecordDecl *ClassDecl = MoveAssignOperator->getParent();
+
+ if (ClassDecl->isInvalidDecl() || MoveAssignOperator->isInvalidDecl()) {
+ MoveAssignOperator->setInvalidDecl();
+ return;
+ }
+
+ MoveAssignOperator->setUsed();
+
+ ImplicitlyDefinedFunctionScope Scope(*this, MoveAssignOperator);
+ DiagnosticErrorTrap Trap(Diags);
+
+ // C++0x [class.copy]p28:
+ // The implicitly-defined or move assignment operator for a non-union class
+ // X performs memberwise move assignment of its subobjects. The direct base
+ // classes of X are assigned first, in the order of their declaration in the
+ // base-specifier-list, and then the immediate non-static data members of X
+ // are assigned, in the order in which they were declared in the class
+ // definition.
+
+ // The statements that form the synthesized function body.
+ ASTOwningVector<Stmt*> Statements(*this);
+
+ // The parameter for the "other" object, which we are move from.
+ ParmVarDecl *Other = MoveAssignOperator->getParamDecl(0);
+ QualType OtherRefType = Other->getType()->
+ getAs<RValueReferenceType>()->getPointeeType();
+ assert(OtherRefType.getQualifiers() == 0 &&
+ "Bad argument type of defaulted move assignment");
+
+ // Our location for everything implicitly-generated.
+ SourceLocation Loc = MoveAssignOperator->getLocation();
+
+ // Construct a reference to the "other" object. We'll be using this
+ // throughout the generated ASTs.
+ Expr *OtherRef = BuildDeclRefExpr(Other, OtherRefType, VK_LValue, Loc).take();
+ assert(OtherRef && "Reference to parameter cannot fail!");
+ // Cast to rvalue.
+ OtherRef = CastForMoving(*this, OtherRef);
+
+ // Construct the "this" pointer. We'll be using this throughout the generated
+ // ASTs.
+ Expr *This = ActOnCXXThis(Loc).takeAs<Expr>();
+ assert(This && "Reference to this cannot fail!");
+
+ // Assign base classes.
+ bool Invalid = false;
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
+ E = ClassDecl->bases_end(); Base != E; ++Base) {
+ // Form the assignment:
+ // static_cast<Base*>(this)->Base::operator=(static_cast<Base&&>(other));
+ QualType BaseType = Base->getType().getUnqualifiedType();
+ if (!BaseType->isRecordType()) {
+ Invalid = true;
+ continue;
+ }
+
+ CXXCastPath BasePath;
+ BasePath.push_back(Base);
+
+ // Construct the "from" expression, which is an implicit cast to the
+ // appropriately-qualified base type.
+ Expr *From = OtherRef;
+ From = ImpCastExprToType(From, BaseType, CK_UncheckedDerivedToBase,
+ VK_XValue, &BasePath).take();
+
+ // Dereference "this".
+ ExprResult To = CreateBuiltinUnaryOp(Loc, UO_Deref, This);
+
+ // Implicitly cast "this" to the appropriately-qualified base type.
+ To = ImpCastExprToType(To.take(),
+ Context.getCVRQualifiedType(BaseType,
+ MoveAssignOperator->getTypeQualifiers()),
+ CK_UncheckedDerivedToBase,
+ VK_LValue, &BasePath);
+
+ // Build the move.
+ StmtResult Move = BuildSingleCopyAssign(*this, Loc, BaseType,
+ To.get(), From,
+ /*CopyingBaseSubobject=*/true,
+ /*Copying=*/false);
+ if (Move.isInvalid()) {
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
+ MoveAssignOperator->setInvalidDecl();
+ return;
+ }
+
+ // Success! Record the move.
+ 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();
+ Field != FieldEnd; ++Field) {
+ if (Field->isUnnamedBitfield())
+ continue;
+
+ // Check for members of reference type; we can't move those.
+ if (Field->getType()->isReferenceType()) {
+ Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
+ << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
+ Diag(Field->getLocation(), diag::note_declared_at);
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
+ Invalid = true;
+ continue;
+ }
+
+ // Check for members of const-qualified, non-class type.
+ QualType BaseType = Context.getBaseElementType(Field->getType());
+ if (!BaseType->getAs<RecordType>() && BaseType.isConstQualified()) {
+ Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
+ << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
+ Diag(Field->getLocation(), diag::note_declared_at);
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
+ Invalid = true;
+ continue;
+ }
+
+ // Suppress assigning zero-width bitfields.
+ if (Field->isBitField() && Field->getBitWidthValue(Context) == 0)
+ continue;
+
+ QualType FieldType = Field->getType().getNonReferenceType();
+ if (FieldType->isIncompleteArrayType()) {
+ assert(ClassDecl->hasFlexibleArrayMember() &&
+ "Incomplete array type is not valid");
+ continue;
+ }
+
+ // Build references to the field in the object we're copying from and to.
+ CXXScopeSpec SS; // Intentionally empty
+ LookupResult MemberLookup(*this, Field->getDeclName(), Loc,
+ LookupMemberName);
+ MemberLookup.addDecl(*Field);
+ MemberLookup.resolveKind();
+ ExprResult From = BuildMemberReferenceExpr(OtherRef, OtherRefType,
+ Loc, /*IsArrow=*/false,
+ SS, 0, MemberLookup, 0);
+ ExprResult To = BuildMemberReferenceExpr(This, This->getType(),
+ Loc, /*IsArrow=*/true,
+ SS, 0, MemberLookup, 0);
+ assert(!From.isInvalid() && "Implicit field reference cannot fail");
+ assert(!To.isInvalid() && "Implicit field reference cannot fail");
+
+ assert(!From.get()->isLValue() && // could be xvalue or prvalue
+ "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,
+ CollectableMemCpy->getType(),
+ VK_LValue, 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,
+ BuiltinMemCpy->getType(),
+ VK_LValue, Loc, 0).take();
+ assert(BuiltinMemCpyRef && "Builtin reference cannot fail");
+ }
+
+ ASTOwningVector<Expr*> CallArgs(*this);
+ 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, move_arg(CallArgs),
+ Loc);
+ else
+ Call = ActOnCallExpr(/*Scope=*/0,
+ BuiltinMemCpyRef,
+ Loc, move_arg(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,
+ To.get(), From.get(),
+ /*CopyingBaseSubobject=*/false,
+ /*Copying=*/false);
+ if (Move.isInvalid()) {
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
+ MoveAssignOperator->setInvalidDecl();
+ return;
+ }
+
+ // Success! Record the copy.
+ Statements.push_back(Move.takeAs<Stmt>());
+ }
+
+ if (!Invalid) {
+ // Add a "return *this;"
+ ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This);
+
+ StmtResult Return = ActOnReturnStmt(Loc, ThisObj.get());
+ if (Return.isInvalid())
+ Invalid = true;
+ else {
+ Statements.push_back(Return.takeAs<Stmt>());
+
+ if (Trap.hasErrorOccurred()) {
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
+ Invalid = true;
+ }
+ }
+ }
+
+ if (Invalid) {
+ MoveAssignOperator->setInvalidDecl();
+ return;
+ }
+
+ StmtResult Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements),
+ /*isStmtExpr=*/false);
+ assert(!Body.isInvalid() && "Compound statement creation cannot fail");
+ MoveAssignOperator->setBody(Body.takeAs<Stmt>());
+
+ if (ASTMutationListener *L = getASTMutationListener()) {
+ L->CompletedImplicitDefinition(MoveAssignOperator);
+ }
+}
+
std::pair<Sema::ImplicitExceptionSpecification, bool>
Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
if (ClassDecl->isInvalidDecl())
@@ -7205,7 +8449,9 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
/*TInfo=*/0,
/*isExplicit=*/false,
/*isInline=*/true,
- /*isImplicitlyDeclared=*/true);
+ /*isImplicitlyDeclared=*/true,
+ // FIXME: apply the rules for definitions here
+ /*isConstexpr=*/false);
CopyConstructor->setAccess(AS_public);
CopyConstructor->setDefaulted();
CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
@@ -7220,7 +8466,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
ArgType, /*TInfo=*/0,
SC_None,
SC_None, 0);
- CopyConstructor->setParams(&FromParam, 1);
+ CopyConstructor->setParams(FromParam);
if (Scope *S = getScopeForContext(ClassDecl))
PushOnScopeChains(CopyConstructor, S, false);
@@ -7232,7 +8478,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
// deleted; ...
if (ClassDecl->hasUserDeclaredMoveConstructor() ||
ClassDecl->hasUserDeclaredMoveAssignment() ||
- ShouldDeleteCopyConstructor(CopyConstructor))
+ ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
CopyConstructor->setDeletedAsWritten();
return CopyConstructor;
@@ -7262,19 +8508,184 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
MultiStmtArg(*this, 0, 0),
/*isStmtExpr=*/false)
.takeAs<Stmt>());
+ CopyConstructor->setImplicitlyDefined(true);
}
CopyConstructor->setUsed();
-
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(CopyConstructor);
}
}
+Sema::ImplicitExceptionSpecification
+Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
+ // C++ [except.spec]p14:
+ // An implicitly declared special member function (Clause 12) shall have an
+ // exception-specification. [...]
+ ImplicitExceptionSpecification ExceptSpec(Context);
+ if (ClassDecl->isInvalidDecl())
+ return ExceptSpec;
+
+ // Direct base-class constructors.
+ for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(),
+ BEnd = ClassDecl->bases_end();
+ B != BEnd; ++B) {
+ if (B->isVirtual()) // Handled below.
+ continue;
+
+ if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
+ CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
+ CXXConstructorDecl *Constructor = LookupMovingConstructor(BaseClassDecl);
+ // If this is a deleted function, add it anyway. This might be conformant
+ // with the standard. This might not. I'm not sure. It might not matter.
+ if (Constructor)
+ ExceptSpec.CalledDecl(Constructor);
+ }
+ }
+
+ // Virtual base-class constructors.
+ for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(),
+ BEnd = ClassDecl->vbases_end();
+ B != BEnd; ++B) {
+ if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
+ CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
+ CXXConstructorDecl *Constructor = LookupMovingConstructor(BaseClassDecl);
+ // If this is a deleted function, add it anyway. This might be conformant
+ // with the standard. This might not. I'm not sure. It might not matter.
+ if (Constructor)
+ ExceptSpec.CalledDecl(Constructor);
+ }
+ }
+
+ // Field constructors.
+ for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
+ FEnd = ClassDecl->field_end();
+ F != FEnd; ++F) {
+ if (F->hasInClassInitializer()) {
+ if (Expr *E = F->getInClassInitializer())
+ ExceptSpec.CalledExpr(E);
+ else if (!F->isInvalidDecl())
+ ExceptSpec.SetDelayed();
+ } else if (const RecordType *RecordTy
+ = Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
+ CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
+ CXXConstructorDecl *Constructor = LookupMovingConstructor(FieldRecDecl);
+ // If this is a deleted function, add it anyway. This might be conformant
+ // with the standard. This might not. I'm not sure. It might not matter.
+ // In particular, the problem is that this function never gets called. It
+ // might just be ill-formed because this function attempts to refer to
+ // a deleted function here.
+ if (Constructor)
+ ExceptSpec.CalledDecl(Constructor);
+ }
+ }
+
+ return ExceptSpec;
+}
+
+CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
+ CXXRecordDecl *ClassDecl) {
+ ImplicitExceptionSpecification Spec(
+ ComputeDefaultedMoveCtorExceptionSpec(ClassDecl));
+
+ QualType ClassType = Context.getTypeDeclType(ClassDecl);
+ QualType ArgType = Context.getRValueReferenceType(ClassType);
+
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+
+ DeclarationName Name
+ = Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(ClassType));
+ SourceLocation ClassLoc = ClassDecl->getLocation();
+ DeclarationNameInfo NameInfo(Name, ClassLoc);
+
+ // C++0x [class.copy]p11:
+ // An implicitly-declared copy/move constructor is an inline public
+ // member of its class.
+ CXXConstructorDecl *MoveConstructor
+ = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
+ Context.getFunctionType(Context.VoidTy,
+ &ArgType, 1, EPI),
+ /*TInfo=*/0,
+ /*isExplicit=*/false,
+ /*isInline=*/true,
+ /*isImplicitlyDeclared=*/true,
+ // FIXME: apply the rules for definitions here
+ /*isConstexpr=*/false);
+ MoveConstructor->setAccess(AS_public);
+ MoveConstructor->setDefaulted();
+ MoveConstructor->setTrivial(ClassDecl->hasTrivialMoveConstructor());
+
+ // 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);
+
+ // C++0x [class.copy]p9:
+ // If the definition of a class X does not explicitly declare a move
+ // constructor, one will be implicitly declared as defaulted if and only if:
+ // [...]
+ // - the move constructor would not be implicitly defined as deleted.
+ if (ShouldDeleteSpecialMember(MoveConstructor, CXXMoveConstructor)) {
+ // Cache this result so that we don't try to generate this over and over
+ // on every lookup, leaking memory and wasting time.
+ ClassDecl->setFailedImplicitMoveConstructor();
+ return 0;
+ }
+
+ // Note that we have declared this constructor.
+ ++ASTContext::NumImplicitMoveConstructorsDeclared;
+
+ if (Scope *S = getScopeForContext(ClassDecl))
+ PushOnScopeChains(MoveConstructor, S, false);
+ ClassDecl->addDecl(MoveConstructor);
+
+ return MoveConstructor;
+}
+
+void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
+ CXXConstructorDecl *MoveConstructor) {
+ assert((MoveConstructor->isDefaulted() &&
+ MoveConstructor->isMoveConstructor() &&
+ !MoveConstructor->doesThisDeclarationHaveABody()) &&
+ "DefineImplicitMoveConstructor - call it for implicit move ctor");
+
+ CXXRecordDecl *ClassDecl = MoveConstructor->getParent();
+ assert(ClassDecl && "DefineImplicitMoveConstructor - invalid constructor");
+
+ ImplicitlyDefinedFunctionScope Scope(*this, MoveConstructor);
+ DiagnosticErrorTrap Trap(Diags);
+
+ if (SetCtorInitializers(MoveConstructor, 0, 0, /*AnyErrors=*/false) ||
+ Trap.hasErrorOccurred()) {
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXMoveConstructor << Context.getTagDeclType(ClassDecl);
+ MoveConstructor->setInvalidDecl();
+ } else {
+ MoveConstructor->setBody(ActOnCompoundStmt(MoveConstructor->getLocation(),
+ MoveConstructor->getLocation(),
+ MultiStmtArg(*this, 0, 0),
+ /*isStmtExpr=*/false)
+ .takeAs<Stmt>());
+ MoveConstructor->setImplicitlyDefined(true);
+ }
+
+ MoveConstructor->setUsed();
+
+ if (ASTMutationListener *L = getASTMutationListener()) {
+ L->CompletedImplicitDefinition(MoveConstructor);
+ }
+}
+
ExprResult
Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor,
MultiExprArg ExprArgs,
+ bool HadMultipleCandidates,
bool RequiresZeroInit,
unsigned ConstructKind,
SourceRange ParenRange) {
@@ -7297,8 +8708,8 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
}
return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
- Elidable, move(ExprArgs), RequiresZeroInit,
- ConstructKind, ParenRange);
+ Elidable, move(ExprArgs), HadMultipleCandidates,
+ RequiresZeroInit, ConstructKind, ParenRange);
}
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
@@ -7307,6 +8718,7 @@ ExprResult
Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor, bool Elidable,
MultiExprArg ExprArgs,
+ bool HadMultipleCandidates,
bool RequiresZeroInit,
unsigned ConstructKind,
SourceRange ParenRange) {
@@ -7322,20 +8734,21 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
MarkDeclarationReferenced(ConstructLoc, Constructor);
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
- Constructor, Elidable, Exprs, NumExprs,
- RequiresZeroInit,
+ Constructor, Elidable, Exprs, NumExprs,
+ HadMultipleCandidates, RequiresZeroInit,
static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind),
ParenRange));
}
bool Sema::InitializeVarWithConstructor(VarDecl *VD,
CXXConstructorDecl *Constructor,
- MultiExprArg Exprs) {
+ MultiExprArg Exprs,
+ bool HadMultipleCandidates) {
// FIXME: Provide the correct paren SourceRange when available.
ExprResult TempResult =
BuildCXXConstructExpr(VD->getLocation(), VD->getType(), Constructor,
- move(Exprs), false, CXXConstructExpr::CK_Complete,
- SourceRange());
+ move(Exprs), HadMultipleCandidates, false,
+ CXXConstructExpr::CK_Complete, SourceRange());
if (TempResult.isInvalid())
return true;
@@ -7447,6 +8860,7 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl,
// class type.
if (!VDecl->getType()->isDependentType() &&
+ !VDecl->getType()->isIncompleteArrayType() &&
RequireCompleteType(VDecl->getLocation(), VDecl->getType(),
diag::err_typecheck_decl_incomplete_type)) {
VDecl->setInvalidDecl();
@@ -7522,18 +8936,34 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl,
= InitializationKind::CreateDirect(VDecl->getLocation(),
LParenLoc, RParenLoc);
+ QualType T = VDecl->getType();
InitializationSequence InitSeq(*this, Entity, Kind,
Exprs.get(), Exprs.size());
- ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(Exprs));
+ ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(Exprs), &T);
if (Result.isInvalid()) {
VDecl->setInvalidDecl();
return;
+ } else if (T != VDecl->getType()) {
+ VDecl->setType(T);
+ Result.get()->setType(T);
}
- CheckImplicitConversions(Result.get(), LParenLoc);
- Result = MaybeCreateExprWithCleanups(Result);
- VDecl->setInit(Result.takeAs<Expr>());
+ Expr *Init = Result.get();
+ CheckImplicitConversions(Init, LParenLoc);
+
+ if (VDecl->isConstexpr() && !VDecl->isInvalidDecl() &&
+ !Init->isValueDependent() &&
+ !Init->isConstantInitializer(Context,
+ VDecl->getType()->isReferenceType())) {
+ // FIXME: Improve this diagnostic to explain why the initializer is not
+ // a constant expression.
+ Diag(VDecl->getLocation(), diag::err_constexpr_var_requires_const_init)
+ << VDecl << Init->getSourceRange();
+ }
+
+ Init = MaybeCreateExprWithCleanups(Init);
+ VDecl->setInit(Init);
VDecl->setCXXDirectInitializer(true);
CheckCompleteVariableDeclaration(VDecl);
@@ -7566,7 +8996,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
VariadicCallType CallType =
Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;
- llvm::SmallVector<Expr *, 8> AllArgs;
+ SmallVector<Expr *, 8> AllArgs;
bool Invalid = GatherArgumentsForCall(Loc, Constructor,
Proto, 0, Args, NumArgs, AllArgs,
CallType);
@@ -7928,6 +9358,30 @@ FinishedParams:
return true;
}
+ StringRef LiteralName
+ = FnDecl->getDeclName().getCXXLiteralIdentifier()->getName();
+ if (LiteralName[0] != '_') {
+ // C++0x [usrlit.suffix]p1:
+ // Literal suffix identifiers that do not start with an underscore are
+ // reserved for future standardization.
+ bool IsHexFloat = true;
+ if (LiteralName.size() > 1 &&
+ (LiteralName[0] == 'P' || LiteralName[0] == 'p')) {
+ for (unsigned I = 1, N = LiteralName.size(); I < N; ++I) {
+ if (!isdigit(LiteralName[I])) {
+ IsHexFloat = false;
+ break;
+ }
+ }
+ }
+
+ if (IsHexFloat)
+ Diag(FnDecl->getLocation(), diag::warn_user_literal_hexfloat)
+ << LiteralName;
+ else
+ Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved);
+ }
+
return false;
}
@@ -7940,7 +9394,7 @@ FinishedParams:
/// have any braces.
Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc,
SourceLocation LangLoc,
- llvm::StringRef Lang,
+ StringRef Lang,
SourceLocation LBraceLoc) {
LinkageSpecDecl::LanguageIDs Language;
if (Lang == "\"C\"")
@@ -8265,6 +9719,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
return CheckClassTemplate(S, TagSpec, TUK_Friend, TagLoc,
SS, Name, NameLoc, Attr,
TemplateParams, AS_public,
+ /*ModulePrivateLoc=*/SourceLocation(),
TempParamLists.size() - 1,
(TemplateParameterList**) TempParamLists.release()).take();
} else {
@@ -8427,7 +9882,7 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
return D;
}
-Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
+Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParams) {
const DeclSpec &DS = D.getDeclSpec();
@@ -8436,7 +9891,6 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
SourceLocation Loc = D.getIdentifierLoc();
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
- QualType T = TInfo->getType();
// C++ [class.friend]p1
// A friend of a class is a function or class....
@@ -8448,7 +9902,7 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
// a declaration that does not use the syntactic form of a
// function declarator to have a function type, the program
// is ill-formed.
- if (!T->isFunctionType()) {
+ if (!TInfo->getType()->isFunctionType()) {
Diag(Loc, diag::err_unexpected_friend);
// It might be worthwhile to try to recover by creating an
@@ -8551,6 +10005,14 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
DCScope = getScopeForDeclContext(S, DC);
+ // C++ [class.friend]p6:
+ // A function can be defined in a friend declaration of a class if and
+ // only if the class is a non-local class (9.8), the function name is
+ // unqualified, and the function has namespace scope.
+ if (isLocal && D.isFunctionDefinition()) {
+ Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class);
+ }
+
// - There's a non-dependent scope specifier, in which case we
// compute it and do a previous lookup there for a function
// or function template.
@@ -8576,7 +10038,8 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
if (Previous.empty()) {
D.setInvalidType();
- Diag(Loc, diag::err_qualified_friend_not_found) << Name << T;
+ Diag(Loc, diag::err_qualified_friend_not_found)
+ << Name << TInfo->getType();
return 0;
}
@@ -8584,6 +10047,20 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
// class that is not a member of the class . . .
if (DC->Equals(CurContext))
Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
+
+ if (D.isFunctionDefinition()) {
+ // C++ [class.friend]p6:
+ // A function can be defined in a friend declaration of a class if and
+ // only if the class is a non-local class (9.8), the function name is
+ // unqualified, and the function has namespace scope.
+ SemaDiagnosticBuilder DB
+ = Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def);
+
+ DB << SS.getScopeRep();
+ if (DC->isFileContext())
+ DB << FixItHint::CreateRemoval(SS.getRange());
+ SS.clear();
+ }
// - There's a scope specifier that does not match any template
// parameter lists, in which case we use some arbitrary context,
@@ -8591,10 +10068,19 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
// - There's a scope specifier that does match some template
// parameter lists, which we don't handle right now.
} else {
+ if (D.isFunctionDefinition()) {
+ // C++ [class.friend]p6:
+ // A function can be defined in a friend declaration of a class if and
+ // only if the class is a non-local class (9.8), the function name is
+ // unqualified, and the function has namespace scope.
+ Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def)
+ << SS.getScopeRep();
+ }
+
DC = CurContext;
assert(isa<CXXRecordDecl>(DC) && "friend declaration not in class?");
}
-
+
if (!DC->isRecord()) {
// This implies that it has to be an operator or function.
if (D.getName().getKind() == UnqualifiedId::IK_ConstructorName ||
@@ -8607,11 +10093,9 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
}
}
- bool Redeclaration = false;
- NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, T, TInfo, Previous,
- move(TemplateParams),
- IsDefinition,
- Redeclaration);
+ bool AddToScope = true;
+ NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, TInfo, Previous,
+ move(TemplateParams), AddToScope);
if (!ND) return 0;
assert(ND->getDeclContext() == DC);
@@ -8732,15 +10216,24 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
break;
}
- case CXXMoveConstructor:
- case CXXMoveAssignment:
- Diag(Dcl->getLocation(), diag::err_defaulted_move_unsupported);
+ case CXXMoveConstructor: {
+ CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
+ CheckExplicitlyDefaultedMoveConstructor(CD);
+ if (!CD->isInvalidDecl())
+ DefineImplicitMoveConstructor(DefaultLoc, CD);
break;
+ }
- default:
- // FIXME: Do the rest once we have move functions
+ case CXXMoveAssignment: {
+ CheckExplicitlyDefaultedMoveAssignment(MD);
+ if (!MD->isInvalidDecl())
+ DefineImplicitMoveAssignment(DefaultLoc, MD);
break;
}
+
+ case CXXInvalid:
+ llvm_unreachable("Invalid special member.");
+ }
} else {
Diag(DefaultLoc, diag::err_default_special_members);
}
@@ -8934,6 +10427,30 @@ DeclResult Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) {
return Dcl;
}
+void Sema::LoadExternalVTableUses() {
+ if (!ExternalSource)
+ return;
+
+ SmallVector<ExternalVTableUse, 4> VTables;
+ ExternalSource->ReadUsedVTables(VTables);
+ SmallVector<VTableUse, 4> NewUses;
+ for (unsigned I = 0, N = VTables.size(); I != N; ++I) {
+ llvm::DenseMap<CXXRecordDecl *, bool>::iterator Pos
+ = VTablesUsed.find(VTables[I].Record);
+ // Even if a definition wasn't required before, it may be required now.
+ if (Pos != VTablesUsed.end()) {
+ if (!Pos->second && VTables[I].DefinitionRequired)
+ Pos->second = true;
+ continue;
+ }
+
+ VTablesUsed[VTables[I].Record] = VTables[I].DefinitionRequired;
+ NewUses.push_back(VTableUse(VTables[I].Record, VTables[I].Location));
+ }
+
+ VTableUses.insert(VTableUses.begin(), NewUses.begin(), NewUses.end());
+}
+
void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,
bool DefinitionRequired) {
// Ignore any vtable uses in unevaluated operands or for classes that do
@@ -8944,6 +10461,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,
return;
// Try to insert this class into the map.
+ LoadExternalVTableUses();
Class = cast<CXXRecordDecl>(Class->getCanonicalDecl());
std::pair<llvm::DenseMap<CXXRecordDecl *, bool>::iterator, bool>
Pos = VTablesUsed.insert(std::make_pair(Class, DefinitionRequired));
@@ -8969,6 +10487,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,
}
bool Sema::DefineUsedVTables() {
+ LoadExternalVTableUses();
if (VTableUses.empty())
return false;
@@ -9037,7 +10556,10 @@ bool Sema::DefineUsedVTables() {
// Optionally warn if we're emitting a weak vtable.
if (Class->getLinkage() == ExternalLinkage &&
Class->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) {
- if (!KeyFunction || (KeyFunction->hasBody() && KeyFunction->isInlined()))
+ const FunctionDecl *KeyFunctionDef = 0;
+ if (!KeyFunction ||
+ (KeyFunction->hasBody(KeyFunctionDef) &&
+ KeyFunctionDef->isInlined()))
Diag(Class->getLocation(), diag::warn_weak_vtable) << Class;
}
}
@@ -9078,11 +10600,11 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
if (!getLangOptions().CPlusPlus)
return;
if (ObjCInterfaceDecl *OID = ObjCImplementation->getClassInterface()) {
- llvm::SmallVector<ObjCIvarDecl*, 8> ivars;
+ SmallVector<ObjCIvarDecl*, 8> ivars;
CollectIvarsToConstructOrDestruct(OID, ivars);
if (ivars.empty())
return;
- llvm::SmallVector<CXXCtorInitializer*, 32> AllToInit;
+ SmallVector<CXXCtorInitializer*, 32> AllToInit;
for (unsigned i = 0; i < ivars.size(); i++) {
FieldDecl *Field = ivars[i];
if (Field->isInvalidDecl())
@@ -9199,8 +10721,8 @@ void Sema::CheckDelegatingCtorCycles() {
llvm::SmallSet<CXXConstructorDecl*, 4>::iterator CI = Current.begin(),
CE = Current.end();
- for (llvm::SmallVector<CXXConstructorDecl*, 4>::iterator
- I = DelegatingCtorDecls.begin(),
+ for (DelegatingCtorDeclsType::iterator
+ I = DelegatingCtorDecls.begin(ExternalSource),
E = DelegatingCtorDecls.end();
I != E; ++I) {
DelegatingCycleHelper(*I, Valid, Invalid, Current, *this);
@@ -9209,3 +10731,44 @@ void Sema::CheckDelegatingCtorCycles() {
for (CI = Invalid.begin(), CE = Invalid.end(); CI != CE; ++CI)
(*CI)->setInvalidDecl();
}
+
+/// IdentifyCUDATarget - Determine the CUDA compilation target for this function
+Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) {
+ // Implicitly declared functions (e.g. copy constructors) are
+ // __host__ __device__
+ if (D->isImplicit())
+ return CFT_HostDevice;
+
+ if (D->hasAttr<CUDAGlobalAttr>())
+ return CFT_Global;
+
+ if (D->hasAttr<CUDADeviceAttr>()) {
+ if (D->hasAttr<CUDAHostAttr>())
+ return CFT_HostDevice;
+ else
+ return CFT_Device;
+ }
+
+ return CFT_Host;
+}
+
+bool Sema::CheckCUDATarget(CUDAFunctionTarget CallerTarget,
+ CUDAFunctionTarget CalleeTarget) {
+ // CUDA B.1.1 "The __device__ qualifier declares a function that is...
+ // Callable from the device only."
+ if (CallerTarget == CFT_Host && CalleeTarget == CFT_Device)
+ return true;
+
+ // CUDA B.1.2 "The __global__ qualifier declares a function that is...
+ // Callable from the host only."
+ // CUDA B.1.3 "The __host__ qualifier declares a function that is...
+ // Callable from the host only."
+ if ((CallerTarget == CFT_Device || CallerTarget == CFT_Global) &&
+ (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global))
+ return true;
+
+ if (CallerTarget == CFT_HostDevice && CalleeTarget != CFT_HostDevice)
+ return true;
+
+ return false;
+}
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index aa8152b03b0a..62b4a7c0cc77 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -106,7 +106,7 @@ bool Sema::checkInitMethod(ObjCMethodDecl *method,
return true;
}
-bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
+void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
const ObjCMethodDecl *Overridden,
bool IsImplementation) {
if (Overridden->hasRelatedResultType() &&
@@ -148,105 +148,44 @@ bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
<< ResultTypeRange;
}
- Diag(Overridden->getLocation(), diag::note_related_result_type_overridden)
- << Overridden->getMethodFamily();
+ if (ObjCMethodFamily Family = Overridden->getMethodFamily())
+ Diag(Overridden->getLocation(),
+ diag::note_related_result_type_overridden_family)
+ << Family;
+ else
+ Diag(Overridden->getLocation(),
+ diag::note_related_result_type_overridden);
}
-
- return false;
-}
-
-/// \brief Check for consistency between a given method declaration and the
-/// methods it overrides within the class hierarchy.
-///
-/// This method walks the inheritance hierarchy starting at the given
-/// declaration context (\p DC), invoking Sema::CheckObjCMethodOverride() with
-/// the given new method (\p NewMethod) and any method it directly overrides
-/// in the hierarchy. Sema::CheckObjCMethodOverride() is responsible for
-/// checking consistency, e.g., among return types for methods that return a
-/// related result type.
-static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod,
- DeclContext *DC,
- bool SkipCurrent = true) {
- if (!DC)
- return false;
-
- if (!SkipCurrent) {
- // Look for this method. If we find it, we're done.
- Selector Sel = NewMethod->getSelector();
- bool IsInstance = NewMethod->isInstanceMethod();
- DeclContext::lookup_const_iterator Meth, MethEnd;
- for (llvm::tie(Meth, MethEnd) = DC->lookup(Sel); Meth != MethEnd; ++Meth) {
- ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth);
- if (MD && MD->isInstanceMethod() == IsInstance)
- return S.CheckObjCMethodOverride(NewMethod, MD, false);
+ if (getLangOptions().ObjCAutoRefCount) {
+ if ((NewMethod->hasAttr<NSReturnsRetainedAttr>() !=
+ Overridden->hasAttr<NSReturnsRetainedAttr>())) {
+ Diag(NewMethod->getLocation(),
+ diag::err_nsreturns_retained_attribute_mismatch) << 1;
+ Diag(Overridden->getLocation(), diag::note_previous_decl)
+ << "method";
}
- }
-
- if (ObjCInterfaceDecl *Class = llvm::dyn_cast<ObjCInterfaceDecl>(DC)) {
- // Look through categories.
- for (ObjCCategoryDecl *Category = Class->getCategoryList();
- Category; Category = Category->getNextClassCategory()) {
- if (CheckObjCMethodOverrides(S, NewMethod, Category, false))
- return true;
+ if ((NewMethod->hasAttr<NSReturnsNotRetainedAttr>() !=
+ Overridden->hasAttr<NSReturnsNotRetainedAttr>())) {
+ Diag(NewMethod->getLocation(),
+ diag::err_nsreturns_retained_attribute_mismatch) << 0;
+ Diag(Overridden->getLocation(), diag::note_previous_decl)
+ << "method";
+ }
+ ObjCMethodDecl::param_const_iterator oi = Overridden->param_begin();
+ for (ObjCMethodDecl::param_iterator
+ ni = NewMethod->param_begin(), ne = NewMethod->param_end();
+ ni != ne; ++ni, ++oi) {
+ const ParmVarDecl *oldDecl = (*oi);
+ ParmVarDecl *newDecl = (*ni);
+ if (newDecl->hasAttr<NSConsumedAttr>() !=
+ oldDecl->hasAttr<NSConsumedAttr>()) {
+ Diag(newDecl->getLocation(),
+ diag::err_nsconsumed_attribute_mismatch);
+ Diag(oldDecl->getLocation(), diag::note_previous_decl)
+ << "parameter";
+ }
}
-
- // Look through protocols.
- for (ObjCList<ObjCProtocolDecl>::iterator I = Class->protocol_begin(),
- IEnd = Class->protocol_end();
- I != IEnd; ++I)
- if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
- return true;
-
- // Look in our superclass.
- return CheckObjCMethodOverrides(S, NewMethod, Class->getSuperClass(),
- false);
- }
-
- if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) {
- // Look through protocols.
- for (ObjCList<ObjCProtocolDecl>::iterator I = Category->protocol_begin(),
- IEnd = Category->protocol_end();
- I != IEnd; ++I)
- if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
- return true;
-
- return false;
- }
-
- if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) {
- // Look through protocols.
- for (ObjCList<ObjCProtocolDecl>::iterator I = Protocol->protocol_begin(),
- IEnd = Protocol->protocol_end();
- I != IEnd; ++I)
- if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
- return true;
-
- return false;
}
-
- return false;
-}
-
-bool Sema::CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod,
- DeclContext *DC) {
- if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(DC))
- return ::CheckObjCMethodOverrides(*this, NewMethod, Class);
-
- if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC))
- return ::CheckObjCMethodOverrides(*this, NewMethod, Category);
-
- if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC))
- return ::CheckObjCMethodOverrides(*this, NewMethod, Protocol);
-
- if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(DC))
- return ::CheckObjCMethodOverrides(*this, NewMethod,
- Impl->getClassInterface());
-
- if (ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(DC))
- return ::CheckObjCMethodOverrides(*this, NewMethod,
- CatImpl->getClassInterface());
-
- return ::CheckObjCMethodOverrides(*this, NewMethod, CurContext);
}
/// \brief Check a method declaration for compatibility with the Objective-C
@@ -256,11 +195,13 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
switch (family) {
case OMF_None:
case OMF_dealloc:
+ case OMF_finalize:
case OMF_retain:
case OMF_release:
case OMF_autorelease:
case OMF_retainCount:
case OMF_self:
+ case OMF_performSelector:
return false;
case OMF_init:
@@ -286,11 +227,6 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
method->hasAttr<NSReturnsAutoreleasedAttr>())
return false;
break;
-
- case OMF_performSelector:
- // we don't annotate performSelector's
- return true;
-
}
method->addAttr(new (S.Context) NSReturnsRetainedAttr(SourceLocation(),
@@ -311,6 +247,20 @@ static void DiagnoseObjCImplementedDeprecations(Sema &S,
}
}
+/// AddAnyMethodToGlobalPool - Add any method, instance or factory to global
+/// pool.
+void Sema::AddAnyMethodToGlobalPool(Decl *D) {
+ ObjCMethodDecl *MDecl = dyn_cast_or_null<ObjCMethodDecl>(D);
+
+ // If we don't have a valid method decl, simply return.
+ if (!MDecl)
+ return;
+ if (MDecl->isInstanceMethod())
+ AddInstanceMethodToGlobalPool(MDecl, true);
+ else
+ AddFactoryMethodToGlobalPool(MDecl, true);
+}
+
/// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible
/// and user declared, in the method definition's AST.
void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
@@ -321,12 +271,6 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
if (!MDecl)
return;
- // Allow the rest of sema to find private method decl implementations.
- if (MDecl->isInstanceMethod())
- AddInstanceMethodToGlobalPool(MDecl, true);
- else
- AddFactoryMethodToGlobalPool(MDecl, true);
-
// Allow all of Sema to see that we are entering a method definition.
PushDeclContext(FnBodyScope, MDecl);
PushFunctionScope();
@@ -365,6 +309,7 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
case OMF_None:
case OMF_dealloc:
+ case OMF_finalize:
case OMF_alloc:
case OMF_init:
case OMF_mutableCopy:
@@ -376,14 +321,29 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
}
}
- // Warn on implementating deprecated methods under
- // -Wdeprecated-implementations flag.
- if (ObjCInterfaceDecl *IC = MDecl->getClassInterface())
+ // Warn on deprecated methods under -Wdeprecated-implementations,
+ // and prepare for warning on missing super calls.
+ if (ObjCInterfaceDecl *IC = MDecl->getClassInterface()) {
if (ObjCMethodDecl *IMD =
IC->lookupMethod(MDecl->getSelector(), MDecl->isInstanceMethod()))
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()) {
+ ObjCShouldCallSuperDealloc =
+ !(Context.getLangOptions().ObjCAutoRefCount ||
+ Context.getLangOptions().getGC() == LangOptions::GCOnly) &&
+ MDecl->getMethodFamily() == OMF_dealloc;
+ ObjCShouldCallSuperFinalize =
+ Context.getLangOptions().getGC() != LangOptions::NonGC &&
+ MDecl->getMethodFamily() == OMF_finalize;
+ }
+ }
}
Decl *Sema::
@@ -414,11 +374,11 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
// Return the previous class interface.
// FIXME: don't leak the objects passed in!
- return IDecl;
+ return ActOnObjCContainerStartDefinition(IDecl);
} else {
- IDecl->setLocation(AtInterfaceLoc);
+ IDecl->setLocation(ClassLoc);
IDecl->setForwardDecl(false);
- IDecl->setClassLoc(ClassLoc);
+ IDecl->setAtStartLoc(AtInterfaceLoc);
// If the forward decl was in a PCH, we need to write it again in a
// dependent AST file.
IDecl->setChangedSinceDeserialization(true);
@@ -522,7 +482,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
}
CheckObjCDeclScope(IDecl);
- return IDecl;
+ return ActOnObjCContainerStartDefinition(IDecl);
}
/// ActOnCompatiblityAlias - this action is called after complete parsing of
@@ -618,7 +578,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
Diag(PDecl->getLocation(), diag::note_previous_definition);
// Just return the protocol we already had.
// FIXME: don't leak the objects passed in!
- return PDecl;
+ return ActOnObjCContainerStartDefinition(PDecl);
}
ObjCList<ObjCProtocolDecl> PList;
PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context);
@@ -626,14 +586,18 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
ProtocolName, ProtocolLoc, PDecl->getLocation(), PList);
// Make sure the cached decl gets a valid start location.
- PDecl->setLocation(AtProtoInterfaceLoc);
+ PDecl->setAtStartLoc(AtProtoInterfaceLoc);
+ PDecl->setLocation(ProtocolLoc);
PDecl->setForwardDecl(false);
+ // Since this ObjCProtocolDecl was created by a forward declaration,
+ // we now add it to the DeclContext since it wasn't added before
+ PDecl->setLexicalDeclContext(CurContext);
CurContext->addDecl(PDecl);
// Repeat in dependent AST files.
PDecl->setChangedSinceDeserialization(true);
} else {
- PDecl = ObjCProtocolDecl::Create(Context, CurContext,
- AtProtoInterfaceLoc,ProtocolName);
+ PDecl = ObjCProtocolDecl::Create(Context, CurContext, ProtocolName,
+ ProtocolLoc, AtProtoInterfaceLoc);
PushOnScopeChains(PDecl, TUScope);
PDecl->setForwardDecl(false);
}
@@ -647,7 +611,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
}
CheckObjCDeclScope(PDecl);
- return PDecl;
+ return ActOnObjCContainerStartDefinition(PDecl);
}
/// FindProtocolDeclaration - This routine looks up protocols and
@@ -657,7 +621,7 @@ void
Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
const IdentifierLocPair *ProtocolId,
unsigned NumProtocols,
- llvm::SmallVectorImpl<Decl *> &Protocols) {
+ SmallVectorImpl<Decl *> &Protocols) {
for (unsigned i = 0; i != NumProtocols; ++i) {
ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first,
ProtocolId[i].second);
@@ -725,16 +689,16 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
const IdentifierLocPair *IdentList,
unsigned NumElts,
AttributeList *attrList) {
- llvm::SmallVector<ObjCProtocolDecl*, 32> Protocols;
- llvm::SmallVector<SourceLocation, 8> ProtoLocs;
+ SmallVector<ObjCProtocolDecl*, 32> Protocols;
+ SmallVector<SourceLocation, 8> ProtoLocs;
for (unsigned i = 0; i != NumElts; ++i) {
IdentifierInfo *Ident = IdentList[i].first;
ObjCProtocolDecl *PDecl = LookupProtocol(Ident, IdentList[i].second);
bool isNew = false;
if (PDecl == 0) { // Not already seen?
- PDecl = ObjCProtocolDecl::Create(Context, CurContext,
- IdentList[i].second, Ident);
+ PDecl = ObjCProtocolDecl::Create(Context, CurContext, Ident,
+ IdentList[i].second, AtProtocolLoc);
PushOnScopeChains(PDecl, TUScope, false);
isNew = true;
}
@@ -774,10 +738,10 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
// the enclosing method declarations. We mark the decl invalid
// to make it clear that this isn't a valid AST.
CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc,
- ClassLoc, CategoryLoc, CategoryName);
+ ClassLoc, CategoryLoc, CategoryName,IDecl);
CDecl->setInvalidDecl();
Diag(ClassLoc, diag::err_undef_interface) << ClassName;
- return CDecl;
+ return ActOnObjCContainerStartDefinition(CDecl);
}
if (!CategoryName && IDecl->getImplementation()) {
@@ -786,19 +750,6 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
diag::note_implementation_declared);
}
- CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc,
- ClassLoc, CategoryLoc, CategoryName);
- // FIXME: PushOnScopeChains?
- CurContext->addDecl(CDecl);
-
- CDecl->setClassInterface(IDecl);
- // Insert class extension to the list of class's categories.
- if (!CategoryName)
- CDecl->insertNextClassCategory();
-
- // If the interface is deprecated, warn about it.
- (void)DiagnoseUseOfDecl(IDecl, ClassLoc);
-
if (CategoryName) {
/// Check for duplicate interface declaration for this category
ObjCCategoryDecl *CDeclChain;
@@ -812,10 +763,13 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
break;
}
}
- if (!CDeclChain)
- CDecl->insertNextClassCategory();
}
+ CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc,
+ ClassLoc, CategoryLoc, CategoryName, IDecl);
+ // FIXME: PushOnScopeChains?
+ CurContext->addDecl(CDecl);
+
if (NumProtoRefs) {
CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
ProtoLocs, Context);
@@ -826,7 +780,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
}
CheckObjCDeclScope(CDecl);
- return CDecl;
+ return ActOnObjCContainerStartDefinition(CDecl);
}
/// ActOnStartCategoryImplementation - Perform semantic checks on the
@@ -845,22 +799,26 @@ Decl *Sema::ActOnStartCategoryImplementation(
// Create and install one.
CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, SourceLocation(),
SourceLocation(), SourceLocation(),
- CatName);
- CatIDecl->setClassInterface(IDecl);
- CatIDecl->insertNextClassCategory();
+ CatName, IDecl);
}
}
ObjCCategoryImplDecl *CDecl =
- ObjCCategoryImplDecl::Create(Context, CurContext, AtCatImplLoc, CatName,
- IDecl);
+ ObjCCategoryImplDecl::Create(Context, CurContext, CatName, IDecl,
+ ClassLoc, AtCatImplLoc);
/// Check that class of this category is already completely declared.
- if (!IDecl || IDecl->isForwardDecl())
+ if (!IDecl || IDecl->isForwardDecl()) {
Diag(ClassLoc, diag::err_undef_interface) << ClassName;
+ CDecl->setInvalidDecl();
+ }
// FIXME: PushOnScopeChains?
CurContext->addDecl(CDecl);
+ // If the interface is deprecated/unavailable, warn/error about it.
+ if (IDecl)
+ DiagnoseUseOfDecl(IDecl, ClassLoc);
+
/// Check that CatName, category name, is not used in another implementation.
if (CatIDecl) {
if (CatIDecl->getImplementation()) {
@@ -879,7 +837,7 @@ Decl *Sema::ActOnStartCategoryImplementation(
}
CheckObjCDeclScope(CDecl);
- return CDecl;
+ return ActOnObjCContainerStartDefinition(CDecl);
}
Decl *Sema::ActOnStartClassImplementation(
@@ -969,11 +927,11 @@ Decl *Sema::ActOnStartClassImplementation(
}
ObjCImplementationDecl* IMPDecl =
- ObjCImplementationDecl::Create(Context, CurContext, AtClassImplLoc,
- IDecl, SDecl);
+ ObjCImplementationDecl::Create(Context, CurContext, IDecl, SDecl,
+ ClassLoc, AtClassImplLoc);
if (CheckObjCDeclScope(IMPDecl))
- return IMPDecl;
+ return ActOnObjCContainerStartDefinition(IMPDecl);
// Check that there is no duplicate implementation of this class.
if (IDecl->getImplementation()) {
@@ -990,7 +948,7 @@ Decl *Sema::ActOnStartClassImplementation(
dyn_cast<NamedDecl>(IDecl),
IMPDecl->getLocation(), 1);
}
- return IMPDecl;
+ return ActOnObjCContainerStartDefinition(IMPDecl);
}
void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
@@ -1050,21 +1008,18 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
assert (ClsIvar && "missing class ivar");
// First, make sure the types match.
- if (Context.getCanonicalType(ImplIvar->getType()) !=
- Context.getCanonicalType(ClsIvar->getType())) {
+ if (!Context.hasSameType(ImplIvar->getType(), ClsIvar->getType())) {
Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_type)
<< ImplIvar->getIdentifier()
<< ImplIvar->getType() << ClsIvar->getType();
Diag(ClsIvar->getLocation(), diag::note_previous_definition);
- } else if (ImplIvar->isBitField() && ClsIvar->isBitField()) {
- Expr *ImplBitWidth = ImplIvar->getBitWidth();
- Expr *ClsBitWidth = ClsIvar->getBitWidth();
- if (ImplBitWidth->EvaluateAsInt(Context).getZExtValue() !=
- ClsBitWidth->EvaluateAsInt(Context).getZExtValue()) {
- Diag(ImplBitWidth->getLocStart(), diag::err_conflicting_ivar_bitwidth)
- << ImplIvar->getIdentifier();
- Diag(ClsBitWidth->getLocStart(), diag::note_previous_definition);
- }
+ } else if (ImplIvar->isBitField() && ClsIvar->isBitField() &&
+ ImplIvar->getBitWidthValue(Context) !=
+ ClsIvar->getBitWidthValue(Context)) {
+ Diag(ImplIvar->getBitWidth()->getLocStart(),
+ diag::err_conflicting_ivar_bitwidth) << ImplIvar->getIdentifier();
+ Diag(ClsIvar->getBitWidth()->getLocStart(),
+ diag::note_previous_definition);
}
// Make sure the names are identical.
if (ImplIvar->getIdentifier() != ClsIvar->getIdentifier()) {
@@ -1167,26 +1122,38 @@ static SourceRange getTypeRange(TypeSourceInfo *TSI) {
return (TSI ? TSI->getTypeLoc().getSourceRange() : SourceRange());
}
-static void CheckMethodOverrideReturn(Sema &S,
+static bool CheckMethodOverrideReturn(Sema &S,
ObjCMethodDecl *MethodImpl,
ObjCMethodDecl *MethodDecl,
- bool IsProtocolMethodDecl) {
+ bool IsProtocolMethodDecl,
+ bool IsOverridingMode,
+ bool Warn) {
if (IsProtocolMethodDecl &&
(MethodDecl->getObjCDeclQualifier() !=
MethodImpl->getObjCDeclQualifier())) {
- S.Diag(MethodImpl->getLocation(),
- diag::warn_conflicting_ret_type_modifiers)
- << MethodImpl->getDeclName()
- << getTypeRange(MethodImpl->getResultTypeSourceInfo());
- S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration)
- << getTypeRange(MethodDecl->getResultTypeSourceInfo());
+ if (Warn) {
+ S.Diag(MethodImpl->getLocation(),
+ (IsOverridingMode ?
+ diag::warn_conflicting_overriding_ret_type_modifiers
+ : diag::warn_conflicting_ret_type_modifiers))
+ << MethodImpl->getDeclName()
+ << getTypeRange(MethodImpl->getResultTypeSourceInfo());
+ S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration)
+ << getTypeRange(MethodDecl->getResultTypeSourceInfo());
+ }
+ else
+ return false;
}
if (S.Context.hasSameUnqualifiedType(MethodImpl->getResultType(),
MethodDecl->getResultType()))
- return;
+ return true;
+ if (!Warn)
+ return false;
- unsigned DiagID = diag::warn_conflicting_ret_types;
+ unsigned DiagID =
+ IsOverridingMode ? diag::warn_conflicting_overriding_ret_types
+ : diag::warn_conflicting_ret_types;
// Mismatches between ObjC pointers go into a different warning
// category, and sometimes they're even completely whitelisted.
@@ -1199,9 +1166,11 @@ static void CheckMethodOverrideReturn(Sema &S,
// return types that are subclasses of the declared return type,
// or that are more-qualified versions of the declared type.
if (isObjCTypeSubstitutable(S.Context, IfacePtrTy, ImplPtrTy, false))
- return;
+ return false;
- DiagID = diag::warn_non_covariant_ret_types;
+ DiagID =
+ IsOverridingMode ? diag::warn_non_covariant_overriding_ret_types
+ : diag::warn_non_covariant_ret_types;
}
}
@@ -1210,34 +1179,52 @@ static void CheckMethodOverrideReturn(Sema &S,
<< MethodDecl->getResultType()
<< MethodImpl->getResultType()
<< getTypeRange(MethodImpl->getResultTypeSourceInfo());
- S.Diag(MethodDecl->getLocation(), diag::note_previous_definition)
+ S.Diag(MethodDecl->getLocation(),
+ IsOverridingMode ? diag::note_previous_declaration
+ : diag::note_previous_definition)
<< getTypeRange(MethodDecl->getResultTypeSourceInfo());
+ return false;
}
-static void CheckMethodOverrideParam(Sema &S,
+static bool CheckMethodOverrideParam(Sema &S,
ObjCMethodDecl *MethodImpl,
ObjCMethodDecl *MethodDecl,
ParmVarDecl *ImplVar,
ParmVarDecl *IfaceVar,
- bool IsProtocolMethodDecl) {
+ bool IsProtocolMethodDecl,
+ bool IsOverridingMode,
+ bool Warn) {
if (IsProtocolMethodDecl &&
(ImplVar->getObjCDeclQualifier() !=
IfaceVar->getObjCDeclQualifier())) {
- S.Diag(ImplVar->getLocation(),
- diag::warn_conflicting_param_modifiers)
- << getTypeRange(ImplVar->getTypeSourceInfo())
- << MethodImpl->getDeclName();
- S.Diag(IfaceVar->getLocation(), diag::note_previous_declaration)
- << getTypeRange(IfaceVar->getTypeSourceInfo());
+ if (Warn) {
+ if (IsOverridingMode)
+ S.Diag(ImplVar->getLocation(),
+ diag::warn_conflicting_overriding_param_modifiers)
+ << getTypeRange(ImplVar->getTypeSourceInfo())
+ << MethodImpl->getDeclName();
+ else S.Diag(ImplVar->getLocation(),
+ diag::warn_conflicting_param_modifiers)
+ << getTypeRange(ImplVar->getTypeSourceInfo())
+ << MethodImpl->getDeclName();
+ S.Diag(IfaceVar->getLocation(), diag::note_previous_declaration)
+ << getTypeRange(IfaceVar->getTypeSourceInfo());
+ }
+ else
+ return false;
}
QualType ImplTy = ImplVar->getType();
QualType IfaceTy = IfaceVar->getType();
if (S.Context.hasSameUnqualifiedType(ImplTy, IfaceTy))
- return;
-
- unsigned DiagID = diag::warn_conflicting_param_types;
+ return true;
+
+ if (!Warn)
+ return false;
+ unsigned DiagID =
+ IsOverridingMode ? diag::warn_conflicting_overriding_param_types
+ : diag::warn_conflicting_param_types;
// Mismatches between ObjC pointers go into a different warning
// category, and sometimes they're even completely whitelisted.
@@ -1250,17 +1237,22 @@ static void CheckMethodOverrideParam(Sema &S,
// implementation must accept any objects that the superclass
// accepts, however it may also accept others.
if (isObjCTypeSubstitutable(S.Context, ImplPtrTy, IfacePtrTy, true))
- return;
+ return false;
- DiagID = diag::warn_non_contravariant_param_types;
+ DiagID =
+ IsOverridingMode ? diag::warn_non_contravariant_overriding_param_types
+ : diag::warn_non_contravariant_param_types;
}
}
S.Diag(ImplVar->getLocation(), DiagID)
<< getTypeRange(ImplVar->getTypeSourceInfo())
<< MethodImpl->getDeclName() << IfaceTy << ImplTy;
- S.Diag(IfaceVar->getLocation(), diag::note_previous_definition)
+ S.Diag(IfaceVar->getLocation(),
+ (IsOverridingMode ? diag::note_previous_declaration
+ : diag::note_previous_definition))
<< getTypeRange(IfaceVar->getTypeSourceInfo());
+ return false;
}
/// In ARC, check whether the conventional meanings of the two methods
@@ -1302,6 +1294,7 @@ static bool checkMethodFamilyMismatch(Sema &S, ObjCMethodDecl *impl,
case OMF_release:
case OMF_autorelease:
case OMF_dealloc:
+ case OMF_finalize:
case OMF_retainCount:
case OMF_self:
case OMF_performSelector:
@@ -1341,20 +1334,86 @@ void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
return;
CheckMethodOverrideReturn(*this, ImpMethodDecl, MethodDecl,
- IsProtocolMethodDecl);
+ IsProtocolMethodDecl, false,
+ true);
for (ObjCMethodDecl::param_iterator IM = ImpMethodDecl->param_begin(),
IF = MethodDecl->param_begin(), EM = ImpMethodDecl->param_end();
- IM != EM; ++IM, ++IF)
+ IM != EM; ++IM, ++IF) {
CheckMethodOverrideParam(*this, ImpMethodDecl, MethodDecl, *IM, *IF,
- IsProtocolMethodDecl);
+ IsProtocolMethodDecl, false, true);
+ }
if (ImpMethodDecl->isVariadic() != MethodDecl->isVariadic()) {
- Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_variadic);
+ Diag(ImpMethodDecl->getLocation(),
+ diag::warn_conflicting_variadic);
Diag(MethodDecl->getLocation(), diag::note_previous_declaration);
}
}
+void Sema::CheckConflictingOverridingMethod(ObjCMethodDecl *Method,
+ ObjCMethodDecl *Overridden,
+ bool IsProtocolMethodDecl) {
+
+ CheckMethodOverrideReturn(*this, Method, Overridden,
+ IsProtocolMethodDecl, true,
+ true);
+
+ for (ObjCMethodDecl::param_iterator IM = Method->param_begin(),
+ IF = Overridden->param_begin(), EM = Method->param_end();
+ IM != EM; ++IM, ++IF) {
+ CheckMethodOverrideParam(*this, Method, Overridden, *IM, *IF,
+ IsProtocolMethodDecl, true, true);
+ }
+
+ if (Method->isVariadic() != Overridden->isVariadic()) {
+ Diag(Method->getLocation(),
+ diag::warn_conflicting_overriding_variadic);
+ Diag(Overridden->getLocation(), diag::note_previous_declaration);
+ }
+}
+
+/// WarnExactTypedMethods - This routine issues a warning if method
+/// implementation declaration matches exactly that of its declaration.
+void Sema::WarnExactTypedMethods(ObjCMethodDecl *ImpMethodDecl,
+ ObjCMethodDecl *MethodDecl,
+ bool IsProtocolMethodDecl) {
+ // don't issue warning when protocol method is optional because primary
+ // class is not required to implement it and it is safe for protocol
+ // to implement it.
+ if (MethodDecl->getImplementationControl() == ObjCMethodDecl::Optional)
+ return;
+ // don't issue warning when primary class's method is
+ // depecated/unavailable.
+ if (MethodDecl->hasAttr<UnavailableAttr>() ||
+ MethodDecl->hasAttr<DeprecatedAttr>())
+ return;
+
+ bool match = CheckMethodOverrideReturn(*this, ImpMethodDecl, MethodDecl,
+ IsProtocolMethodDecl, false, false);
+ if (match)
+ for (ObjCMethodDecl::param_iterator IM = ImpMethodDecl->param_begin(),
+ IF = MethodDecl->param_begin(), EM = ImpMethodDecl->param_end();
+ IM != EM; ++IM, ++IF) {
+ match = CheckMethodOverrideParam(*this, ImpMethodDecl, MethodDecl,
+ *IM, *IF,
+ IsProtocolMethodDecl, false, false);
+ if (!match)
+ break;
+ }
+ if (match)
+ match = (ImpMethodDecl->isVariadic() == MethodDecl->isVariadic());
+ if (match)
+ match = !(MethodDecl->isClassMethod() &&
+ MethodDecl->getSelector() == GetNullarySelector("load", Context));
+
+ if (match) {
+ Diag(ImpMethodDecl->getLocation(),
+ diag::warn_category_method_impl_match);
+ Diag(MethodDecl->getLocation(), diag::note_method_declared_at);
+ }
+}
+
/// FIXME: Type hierarchies in Objective-C can be deep. We could most likely
/// improve the efficiency of selector lookups and type checking by associating
/// with each protocol / interface / category the flattened instance tables. If
@@ -1416,7 +1475,7 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
if (!MethodInClass || !MethodInClass->isSynthesized()) {
unsigned DIAG = diag::warn_unimplemented_protocol_method;
if (Diags.getDiagnosticLevel(DIAG, ImpLoc)
- != Diagnostic::Ignored) {
+ != DiagnosticsEngine::Ignored) {
WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG);
Diag(method->getLocation(), diag::note_method_declared_at);
Diag(CDecl->getLocation(), diag::note_required_for_protocol_at)
@@ -1434,7 +1493,8 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
!ClsMap.count(method->getSelector()) &&
(!Super || !Super->lookupClassMethod(method->getSelector()))) {
unsigned DIAG = diag::warn_unimplemented_protocol_method;
- if (Diags.getDiagnosticLevel(DIAG, ImpLoc) != Diagnostic::Ignored) {
+ if (Diags.getDiagnosticLevel(DIAG, ImpLoc) !=
+ DiagnosticsEngine::Ignored) {
WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG);
Diag(method->getLocation(), diag::note_method_declared_at);
Diag(IDecl->getLocation(), diag::note_required_for_protocol_at) <<
@@ -1458,7 +1518,8 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
ObjCImplDecl* IMPDecl,
ObjCContainerDecl* CDecl,
bool &IncompleteImpl,
- bool ImmediateClass) {
+ bool ImmediateClass,
+ bool WarnExactMatch) {
// Check and see if instance methods in class interface have been
// implemented in the implementation class. If so, their types match.
for (ObjCInterfaceDecl::instmeth_iterator I = CDecl->instmeth_begin(),
@@ -1474,15 +1535,19 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
continue;
} else {
ObjCMethodDecl *ImpMethodDecl =
- IMPDecl->getInstanceMethod((*I)->getSelector());
- ObjCMethodDecl *MethodDecl =
- CDecl->getInstanceMethod((*I)->getSelector());
- assert(MethodDecl &&
- "MethodDecl is null in ImplMethodsVsClassMethods");
+ IMPDecl->getInstanceMethod((*I)->getSelector());
+ assert(CDecl->getInstanceMethod((*I)->getSelector()) &&
+ "Expected to find the method through lookup as well");
+ ObjCMethodDecl *MethodDecl = *I;
// ImpMethodDecl may be null as in a @dynamic property.
- if (ImpMethodDecl)
- WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl,
- isa<ObjCProtocolDecl>(CDecl));
+ if (ImpMethodDecl) {
+ if (!WarnExactMatch)
+ WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl,
+ isa<ObjCProtocolDecl>(CDecl));
+ else if (!MethodDecl->isSynthesized())
+ WarnExactTypedMethods(ImpMethodDecl, MethodDecl,
+ isa<ObjCProtocolDecl>(CDecl));
+ }
}
}
@@ -1500,10 +1565,15 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
} else {
ObjCMethodDecl *ImpMethodDecl =
IMPDecl->getClassMethod((*I)->getSelector());
- ObjCMethodDecl *MethodDecl =
- CDecl->getClassMethod((*I)->getSelector());
- WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl,
- isa<ObjCProtocolDecl>(CDecl));
+ assert(CDecl->getClassMethod((*I)->getSelector()) &&
+ "Expected to find the method through lookup as well");
+ ObjCMethodDecl *MethodDecl = *I;
+ if (!WarnExactMatch)
+ WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl,
+ isa<ObjCProtocolDecl>(CDecl));
+ else
+ WarnExactTypedMethods(ImpMethodDecl, MethodDecl,
+ isa<ObjCProtocolDecl>(CDecl));
}
}
@@ -1514,7 +1584,7 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
IMPDecl,
const_cast<ObjCCategoryDecl *>(ClsExtDecl),
- IncompleteImpl, false);
+ IncompleteImpl, false, WarnExactMatch);
// Check for any implementation of a methods declared in protocol.
for (ObjCInterfaceDecl::all_protocol_iterator
@@ -1522,14 +1592,50 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
E = I->all_referenced_protocol_end(); PI != E; ++PI)
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
IMPDecl,
- (*PI), IncompleteImpl, false);
- if (I->getSuperClass())
+ (*PI), IncompleteImpl, false, WarnExactMatch);
+
+ // FIXME. For now, we are not checking for extact match of methods
+ // in category implementation and its primary class's super class.
+ if (!WarnExactMatch && I->getSuperClass())
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
IMPDecl,
I->getSuperClass(), IncompleteImpl, false);
}
}
+/// CheckCategoryVsClassMethodMatches - Checks that methods implemented in
+/// category matches with those implemented in its primary class and
+/// warns each time an exact match is found.
+void Sema::CheckCategoryVsClassMethodMatches(
+ ObjCCategoryImplDecl *CatIMPDecl) {
+ llvm::DenseSet<Selector> InsMap, ClsMap;
+
+ for (ObjCImplementationDecl::instmeth_iterator
+ I = CatIMPDecl->instmeth_begin(),
+ E = CatIMPDecl->instmeth_end(); I!=E; ++I)
+ InsMap.insert((*I)->getSelector());
+
+ for (ObjCImplementationDecl::classmeth_iterator
+ I = CatIMPDecl->classmeth_begin(),
+ E = CatIMPDecl->classmeth_end(); I != E; ++I)
+ ClsMap.insert((*I)->getSelector());
+ if (InsMap.empty() && ClsMap.empty())
+ return;
+
+ // Get category's primary class.
+ ObjCCategoryDecl *CatDecl = CatIMPDecl->getCategoryDecl();
+ if (!CatDecl)
+ return;
+ ObjCInterfaceDecl *IDecl = CatDecl->getClassInterface();
+ if (!IDecl)
+ return;
+ llvm::DenseSet<Selector> InsMapSeen, ClsMapSeen;
+ bool IncompleteImpl = false;
+ MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
+ CatIMPDecl, IDecl,
+ IncompleteImpl, false, true /*WarnExactMatch*/);
+}
+
void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl* CDecl,
bool IncompleteImpl) {
@@ -1559,6 +1665,12 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
IMPDecl, CDecl,
IncompleteImpl, true);
+
+ // check all methods implemented in category against those declared
+ // in its primary class.
+ if (ObjCCategoryImplDecl *CatDecl =
+ dyn_cast<ObjCCategoryImplDecl>(IMPDecl))
+ CheckCategoryVsClassMethodMatches(CatDecl);
// Check the protocol list for unimplemented methods in the @implementation
// class.
@@ -1598,17 +1710,16 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap);
}
} else
- assert(false && "invalid ObjCContainerDecl type.");
+ llvm_unreachable("invalid ObjCContainerDecl type.");
}
/// ActOnForwardClassDeclaration -
-Decl *
+Sema::DeclGroupPtrTy
Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
IdentifierInfo **IdentList,
SourceLocation *IdentLocs,
unsigned NumElts) {
- llvm::SmallVector<ObjCInterfaceDecl*, 32> Interfaces;
-
+ SmallVector<Decl *, 8> DeclsInGroup;
for (unsigned i = 0; i != NumElts; ++i) {
// Check for another declaration kind with the same name.
NamedDecl *PrevDecl
@@ -1653,17 +1764,14 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
PushOnScopeChains(IDecl, TUScope, false);
CurContext->makeDeclVisibleInContext(IDecl, true);
}
-
- Interfaces.push_back(IDecl);
+ ObjCClassDecl *CDecl = ObjCClassDecl::Create(Context, CurContext, AtClassLoc,
+ IDecl, IdentLocs[i]);
+ CurContext->addDecl(CDecl);
+ CheckObjCDeclScope(CDecl);
+ DeclsInGroup.push_back(CDecl);
}
-
- assert(Interfaces.size() == NumElts);
- ObjCClassDecl *CDecl = ObjCClassDecl::Create(Context, CurContext, AtClassLoc,
- Interfaces.data(), IdentLocs,
- Interfaces.size());
- CurContext->addDecl(CDecl);
- CheckObjCDeclScope(CDecl);
- return CDecl;
+
+ return BuildDeclaratorGroup(DeclsInGroup.data(), DeclsInGroup.size(), false);
}
static bool tryMatchRecordTypes(ASTContext &Context,
@@ -1705,11 +1813,16 @@ static bool matchTypes(ASTContext &Context, Sema::MethodMatchStrategy strategy,
if (!left->isScalarType() || !right->isScalarType())
return tryMatchRecordTypes(Context, strategy, left, right);
- // Make scalars agree in kind, except count bools as chars.
+ // Make scalars agree in kind, except count bools as chars, and group
+ // all non-member pointers together.
Type::ScalarTypeKind leftSK = left->getScalarTypeKind();
Type::ScalarTypeKind rightSK = right->getScalarTypeKind();
if (leftSK == Type::STK_Bool) leftSK = Type::STK_Integral;
if (rightSK == Type::STK_Bool) rightSK = Type::STK_Integral;
+ if (leftSK == Type::STK_CPointer || leftSK == Type::STK_BlockPointer)
+ leftSK = Type::STK_ObjCObjectPointer;
+ if (rightSK == Type::STK_CPointer || rightSK == Type::STK_BlockPointer)
+ rightSK = Type::STK_ObjCObjectPointer;
// Note that data member pointers and function member pointers don't
// intermix because of the size differences.
@@ -1764,12 +1877,12 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
!= right->hasAttr<NSConsumesSelfAttr>()))
return false;
- ObjCMethodDecl::param_iterator
+ ObjCMethodDecl::param_const_iterator
li = left->param_begin(), le = left->param_end(), ri = right->param_begin();
for (; li != le; ++li, ++ri) {
assert(ri != right->param_end() && "Param mismatch");
- ParmVarDecl *lparm = *li, *rparm = *ri;
+ const ParmVarDecl *lparm = *li, *rparm = *ri;
if (!matchTypes(Context, strategy, lparm->getType(), rparm->getType()))
return false;
@@ -1887,7 +2000,7 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
(receiverIdOrClass && warn &&
(Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl,
R.getBegin()) !=
- Diagnostic::Ignored));
+ DiagnosticsEngine::Ignored));
if (strictSelectorMatch)
for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) {
if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method,
@@ -2010,15 +2123,14 @@ void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID,
// Note: For class/category implemenations, allMethods/allProperties is
// always null.
void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
- Decl *ClassDecl,
Decl **allMethods, unsigned allNum,
Decl **allProperties, unsigned pNum,
DeclGroupPtrTy *allTUVars, unsigned tuvNum) {
- // FIXME: If we don't have a ClassDecl, we have an error. We should consider
- // always passing in a decl. If the decl has an error, isInvalidDecl()
- // should be true.
- if (!ClassDecl)
+
+ if (!CurContext->isObjCContainer())
return;
+ ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(CurContext);
+ Decl *ClassDecl = cast<Decl>(OCD);
bool isInterfaceDeclKind =
isa<ObjCInterfaceDecl>(ClassDecl) || isa<ObjCCategoryDecl>(ClassDecl)
@@ -2055,6 +2167,8 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
Method->setInvalidDecl();
} else {
+ if (PrevMethod)
+ Method->setAsRedeclaration(PrevMethod);
InsMap[Method->getSelector()] = Method;
/// The following allows us to typecheck messages to "id".
AddInstanceMethodToGlobalPool(Method);
@@ -2074,6 +2188,8 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
Method->setInvalidDecl();
} else {
+ if (PrevMethod)
+ Method->setAsRedeclaration(PrevMethod);
ClsMap[Method->getSelector()] = Method;
/// The following allows us to typecheck messages to "Class".
AddFactoryMethodToGlobalPool(Method);
@@ -2145,10 +2261,6 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
}
}
}
-
- if (LangOpts.ObjCDefaultSynthProperties &&
- LangOpts.ObjCNonFragileABI2)
- DefaultSynthesizeProperties(S, IC, IDecl);
ImplMethodsVsClassMethods(S, IC, IDecl);
AtomicPropertySetterGetterRules(IC, IDecl);
DiagnoseOwningPropertyGetterSynthesis(IC);
@@ -2187,6 +2299,7 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
}
}
}
+ ActOnObjCContainerFinishDefinition();
}
@@ -2208,16 +2321,22 @@ bool containsInvalidMethodImplAttribute(const AttrVec &A) {
return false;
}
+namespace {
+ /// \brief Describes the compatibility of a result type with its method.
+ enum ResultTypeCompatibilityKind {
+ RTC_Compatible,
+ RTC_Incompatible,
+ RTC_Unknown
+ };
+}
+
/// \brief Check whether the declared result type of the given Objective-C
/// method declaration is compatible with the method's class.
///
-static bool
+static ResultTypeCompatibilityKind
CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method,
ObjCInterfaceDecl *CurrentClass) {
QualType ResultType = Method->getResultType();
- SourceRange ResultTypeRange;
- if (const TypeSourceInfo *ResultTypeInfo = Method->getResultTypeSourceInfo())
- ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
// If an Objective-C method inherits its related result type, then its
// declared result type must be compatible with its own class type. The
@@ -2227,52 +2346,171 @@ CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method,
// - it is id or qualified id, or
if (ResultObjectType->isObjCIdType() ||
ResultObjectType->isObjCQualifiedIdType())
- return false;
+ return RTC_Compatible;
if (CurrentClass) {
if (ObjCInterfaceDecl *ResultClass
= ResultObjectType->getInterfaceDecl()) {
// - it is the same as the method's class type, or
if (CurrentClass == ResultClass)
- return false;
+ return RTC_Compatible;
// - it is a superclass of the method's class type
if (ResultClass->isSuperClassOf(CurrentClass))
- return false;
+ return RTC_Compatible;
}
+ } else {
+ // Any Objective-C pointer type might be acceptable for a protocol
+ // method; we just don't know.
+ return RTC_Unknown;
}
}
- return true;
+ return RTC_Incompatible;
}
-/// \brief Determine if any method in the global method pool has an inferred
-/// result type.
-static bool
-anyMethodInfersRelatedResultType(Sema &S, Selector Sel, bool IsInstance) {
- Sema::GlobalMethodPool::iterator Pos = S.MethodPool.find(Sel);
- if (Pos == S.MethodPool.end()) {
- if (S.ExternalSource)
- Pos = S.ReadMethodPool(Sel);
- else
- return 0;
+namespace {
+/// A helper class for searching for methods which a particular method
+/// overrides.
+class OverrideSearch {
+ Sema &S;
+ ObjCMethodDecl *Method;
+ llvm::SmallPtrSet<ObjCContainerDecl*, 8> Searched;
+ llvm::SmallPtrSet<ObjCMethodDecl*, 8> Overridden;
+ bool Recursive;
+
+public:
+ OverrideSearch(Sema &S, ObjCMethodDecl *method) : S(S), Method(method) {
+ Selector selector = method->getSelector();
+
+ // Bypass this search if we've never seen an instance/class method
+ // with this selector before.
+ Sema::GlobalMethodPool::iterator it = S.MethodPool.find(selector);
+ if (it == S.MethodPool.end()) {
+ if (!S.ExternalSource) return;
+ it = S.ReadMethodPool(selector);
+ }
+ ObjCMethodList &list =
+ method->isInstanceMethod() ? it->second.first : it->second.second;
+ if (!list.Method) return;
+
+ ObjCContainerDecl *container
+ = cast<ObjCContainerDecl>(method->getDeclContext());
+
+ // Prevent the search from reaching this container again. This is
+ // important with categories, which override methods from the
+ // interface and each other.
+ Searched.insert(container);
+ searchFromContainer(container);
}
-
- ObjCMethodList &List = IsInstance ? Pos->second.first : Pos->second.second;
- for (ObjCMethodList *M = &List; M; M = M->Next) {
- if (M->Method && M->Method->hasRelatedResultType())
- return true;
- }
-
- return false;
+
+ typedef llvm::SmallPtrSet<ObjCMethodDecl*,8>::iterator iterator;
+ iterator begin() const { return Overridden.begin(); }
+ iterator end() const { return Overridden.end(); }
+
+private:
+ void searchFromContainer(ObjCContainerDecl *container) {
+ if (container->isInvalidDecl()) return;
+
+ switch (container->getDeclKind()) {
+#define OBJCCONTAINER(type, base) \
+ case Decl::type: \
+ searchFrom(cast<type##Decl>(container)); \
+ break;
+#define ABSTRACT_DECL(expansion)
+#define DECL(type, base) \
+ case Decl::type:
+#include "clang/AST/DeclNodes.inc"
+ llvm_unreachable("not an ObjC container!");
+ }
+ }
+
+ void searchFrom(ObjCProtocolDecl *protocol) {
+ // A method in a protocol declaration overrides declarations from
+ // referenced ("parent") protocols.
+ search(protocol->getReferencedProtocols());
+ }
+
+ void searchFrom(ObjCCategoryDecl *category) {
+ // A method in a category declaration overrides declarations from
+ // the main class and from protocols the category references.
+ search(category->getClassInterface());
+ search(category->getReferencedProtocols());
+ }
+
+ void searchFrom(ObjCCategoryImplDecl *impl) {
+ // A method in a category definition that has a category
+ // declaration overrides declarations from the category
+ // declaration.
+ if (ObjCCategoryDecl *category = impl->getCategoryDecl()) {
+ search(category);
+
+ // Otherwise it overrides declarations from the class.
+ } else {
+ search(impl->getClassInterface());
+ }
+ }
+
+ void searchFrom(ObjCInterfaceDecl *iface) {
+ // A method in a class declaration overrides declarations from
+
+ // - categories,
+ for (ObjCCategoryDecl *category = iface->getCategoryList();
+ category; category = category->getNextClassCategory())
+ search(category);
+
+ // - the super class, and
+ if (ObjCInterfaceDecl *super = iface->getSuperClass())
+ search(super);
+
+ // - any referenced protocols.
+ search(iface->getReferencedProtocols());
+ }
+
+ void searchFrom(ObjCImplementationDecl *impl) {
+ // A method in a class implementation overrides declarations from
+ // the class interface.
+ search(impl->getClassInterface());
+ }
+
+
+ void search(const ObjCProtocolList &protocols) {
+ for (ObjCProtocolList::iterator i = protocols.begin(), e = protocols.end();
+ i != e; ++i)
+ search(*i);
+ }
+
+ void search(ObjCContainerDecl *container) {
+ // Abort if we've already searched this container.
+ if (!Searched.insert(container)) return;
+
+ // Check for a method in this container which matches this selector.
+ ObjCMethodDecl *meth = container->getMethod(Method->getSelector(),
+ Method->isInstanceMethod());
+
+ // If we find one, record it and bail out.
+ if (meth) {
+ Overridden.insert(meth);
+ return;
+ }
+
+ // Otherwise, search for methods that a hypothetical method here
+ // would have overridden.
+
+ // Note that we're now in a recursive case.
+ Recursive = true;
+
+ searchFromContainer(container);
+ }
+};
}
Decl *Sema::ActOnMethodDeclaration(
Scope *S,
SourceLocation MethodLoc, SourceLocation EndLoc,
- tok::TokenKind MethodType, Decl *ClassDecl,
+ tok::TokenKind MethodType,
ObjCDeclSpec &ReturnQT, ParsedType ReturnType,
- SourceLocation SelectorStartLoc,
+ ArrayRef<SourceLocation> SelectorLocs,
Selector Sel,
// optional arguments. The number of types/arguments is obtained
// from the Sel.getNumArgs().
@@ -2281,12 +2519,15 @@ Decl *Sema::ActOnMethodDeclaration(
AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind,
bool isVariadic, bool MethodDefinition) {
// Make sure we can establish a context for the method.
- if (!ClassDecl) {
+ if (!CurContext->isObjCContainer()) {
Diag(MethodLoc, diag::error_missing_method_context);
return 0;
}
+ ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(CurContext);
+ Decl *ClassDecl = cast<Decl>(OCD);
QualType resultDeclType;
+ bool HasRelatedResultType = false;
TypeSourceInfo *ResultTInfo = 0;
if (ReturnType) {
resultDeclType = GetTypeFromParser(ReturnType, &ResultTInfo);
@@ -2298,21 +2539,28 @@ Decl *Sema::ActOnMethodDeclaration(
<< 0 << resultDeclType;
return 0;
}
- } else // get the type for "id".
+
+ HasRelatedResultType = (resultDeclType == Context.getObjCInstanceType());
+ } else { // get the type for "id".
resultDeclType = Context.getObjCIdType();
+ Diag(MethodLoc, diag::warn_missing_method_return_type)
+ << FixItHint::CreateInsertion(SelectorLocs.front(), "(id)");
+ }
ObjCMethodDecl* ObjCMethod =
- ObjCMethodDecl::Create(Context, MethodLoc, EndLoc, Sel, resultDeclType,
+ ObjCMethodDecl::Create(Context, MethodLoc, EndLoc, Sel,
+ resultDeclType,
ResultTInfo,
- cast<DeclContext>(ClassDecl),
+ CurContext,
MethodType == tok::minus, isVariadic,
- false, false,
+ /*isSynthesized=*/false,
+ /*isImplicitlyDeclared=*/false, /*isDefined=*/false,
MethodDeclKind == tok::objc_optional
? ObjCMethodDecl::Optional
: ObjCMethodDecl::Required,
- false);
+ HasRelatedResultType);
- llvm::SmallVector<ParmVarDecl*, 16> Params;
+ SmallVector<ParmVarDecl*, 16> Params;
for (unsigned i = 0, e = Sel.getNumArgs(); i != e; ++i) {
QualType ArgType;
@@ -2383,20 +2631,16 @@ Decl *Sema::ActOnMethodDeclaration(
Params.push_back(Param);
}
- ObjCMethod->setMethodParams(Context, Params.data(), Params.size(),
- Sel.getNumArgs());
+ ObjCMethod->setMethodParams(Context, Params, SelectorLocs);
ObjCMethod->setObjCDeclQualifier(
CvtQTToAstBitMask(ReturnQT.getObjCDeclQualifier()));
- const ObjCMethodDecl *PrevMethod = 0;
if (AttrList)
ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList);
- const ObjCMethodDecl *InterfaceMD = 0;
-
// Add the method now.
- if (ObjCImplementationDecl *ImpDecl =
- dyn_cast<ObjCImplementationDecl>(ClassDecl)) {
+ const ObjCMethodDecl *PrevMethod = 0;
+ if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(ClassDecl)) {
if (MethodType == tok::minus) {
PrevMethod = ImpDecl->getInstanceMethod(Sel);
ImpDecl->addInstanceMethod(ObjCMethod);
@@ -2404,24 +2648,6 @@ Decl *Sema::ActOnMethodDeclaration(
PrevMethod = ImpDecl->getClassMethod(Sel);
ImpDecl->addClassMethod(ObjCMethod);
}
- InterfaceMD = ImpDecl->getClassInterface()->getMethod(Sel,
- MethodType == tok::minus);
-
- if (ObjCMethod->hasAttrs() &&
- containsInvalidMethodImplAttribute(ObjCMethod->getAttrs()))
- Diag(EndLoc, diag::warn_attribute_method_def);
- } else if (ObjCCategoryImplDecl *CatImpDecl =
- dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) {
- if (MethodType == tok::minus) {
- PrevMethod = CatImpDecl->getInstanceMethod(Sel);
- CatImpDecl->addInstanceMethod(ObjCMethod);
- } else {
- PrevMethod = CatImpDecl->getClassMethod(Sel);
- CatImpDecl->addClassMethod(ObjCMethod);
- }
-
- if (ObjCCategoryDecl *Cat = CatImpDecl->getCategoryDecl())
- InterfaceMD = Cat->getMethod(Sel, MethodType == tok::minus);
if (ObjCMethod->hasAttrs() &&
containsInvalidMethodImplAttribute(ObjCMethod->getAttrs()))
@@ -2429,6 +2655,7 @@ Decl *Sema::ActOnMethodDeclaration(
} else {
cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod);
}
+
if (PrevMethod) {
// You can never have two method definitions with the same name.
Diag(ObjCMethod->getLocation(), diag::err_duplicate_method_decl)
@@ -2449,28 +2676,44 @@ Decl *Sema::ActOnMethodDeclaration(
= dyn_cast<ObjCCategoryImplDecl>(ClassDecl))
CurrentClass = CatImpl->getClassInterface();
}
-
- // Merge information down from the interface declaration if we have one.
- if (InterfaceMD) {
- // Inherit the related result type, if we can.
- if (InterfaceMD->hasRelatedResultType() &&
- !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass))
+
+ ResultTypeCompatibilityKind RTC
+ = CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass);
+
+ // Search for overridden methods and merge information down from them.
+ OverrideSearch overrides(*this, ObjCMethod);
+ for (OverrideSearch::iterator
+ i = overrides.begin(), e = overrides.end(); i != e; ++i) {
+ ObjCMethodDecl *overridden = *i;
+
+ // Propagate down the 'related result type' bit from overridden methods.
+ if (RTC != RTC_Incompatible && overridden->hasRelatedResultType())
ObjCMethod->SetRelatedResultType();
-
- mergeObjCMethodDecls(ObjCMethod, InterfaceMD);
+
+ // Then merge the declarations.
+ mergeObjCMethodDecls(ObjCMethod, overridden);
+
+ // Check for overriding methods
+ if (isa<ObjCInterfaceDecl>(ObjCMethod->getDeclContext()) ||
+ isa<ObjCImplementationDecl>(ObjCMethod->getDeclContext()))
+ CheckConflictingOverridingMethod(ObjCMethod, overridden,
+ isa<ObjCProtocolDecl>(overridden->getDeclContext()));
}
bool ARCError = false;
if (getLangOptions().ObjCAutoRefCount)
ARCError = CheckARCMethodDecl(*this, ObjCMethod);
- if (!ObjCMethod->hasRelatedResultType() && !ARCError &&
- getLangOptions().ObjCInferRelatedResultType) {
+ // Infer the related result type when possible.
+ if (!ARCError && RTC == RTC_Compatible &&
+ !ObjCMethod->hasRelatedResultType() &&
+ LangOpts.ObjCInferRelatedResultType) {
bool InferRelatedResultType = false;
switch (ObjCMethod->getMethodFamily()) {
case OMF_None:
case OMF_copy:
case OMF_dealloc:
+ case OMF_finalize:
case OMF_mutableCopy:
case OMF_release:
case OMF_retainCount:
@@ -2490,14 +2733,8 @@ Decl *Sema::ActOnMethodDeclaration(
break;
}
- if (InferRelatedResultType &&
- !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass))
+ if (InferRelatedResultType)
ObjCMethod->SetRelatedResultType();
-
- if (!InterfaceMD &&
- anyMethodInfersRelatedResultType(*this, ObjCMethod->getSelector(),
- ObjCMethod->isInstanceMethod()))
- CheckObjCMethodOverrides(ObjCMethod, cast<DeclContext>(ClassDecl));
}
return ObjCMethod;
@@ -2506,7 +2743,12 @@ Decl *Sema::ActOnMethodDeclaration(
bool Sema::CheckObjCDeclScope(Decl *D) {
if (isa<TranslationUnitDecl>(CurContext->getRedeclContext()))
return false;
-
+ // Following is also an error. But it is caused by a missing @end
+ // and diagnostic is issued elsewhere.
+ if (isa<ObjCContainerDecl>(CurContext->getRedeclContext())) {
+ return false;
+ }
+
Diag(D->getLocation(), diag::err_objc_decls_may_only_appear_in_global_scope);
D->setInvalidDecl();
@@ -2517,7 +2759,7 @@ bool Sema::CheckObjCDeclScope(Decl *D) {
/// instance variables of ClassName into Decls.
void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart,
IdentifierInfo *ClassName,
- llvm::SmallVectorImpl<Decl*> &Decls) {
+ SmallVectorImpl<Decl*> &Decls) {
// Check that ClassName is a valid class
ObjCInterfaceDecl *Class = getObjCInterfaceDecl(ClassName, DeclStart);
if (!Class) {
@@ -2530,11 +2772,11 @@ void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart,
}
// Collect the instance variables
- llvm::SmallVector<ObjCIvarDecl*, 32> Ivars;
+ SmallVector<const ObjCIvarDecl*, 32> Ivars;
Context.DeepCollectObjCIvars(Class, true, Ivars);
// For each ivar, create a fresh ObjCAtDefsFieldDecl.
for (unsigned i = 0; i < Ivars.size(); i++) {
- FieldDecl* ID = cast<FieldDecl>(Ivars[i]);
+ const FieldDecl* ID = cast<FieldDecl>(Ivars[i]);
RecordDecl *Record = dyn_cast<RecordDecl>(TagD);
Decl *FD = ObjCAtDefsFieldDecl::Create(Context, Record,
/*FIXME: StartL=*/ID->getLocation(),
@@ -2545,7 +2787,7 @@ void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart,
}
// Introduce all of these fields into the appropriate scope.
- for (llvm::SmallVectorImpl<Decl*>::iterator D = Decls.begin();
+ for (SmallVectorImpl<Decl*>::iterator D = Decls.begin();
D != Decls.end(); ++D) {
FieldDecl *FD = cast<FieldDecl>(*D);
if (getLangOptions().CPlusPlus)
@@ -2647,7 +2889,7 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) {
/// CollectIvarsToConstructOrDestruct - Collect those ivars which require
/// initialization.
void Sema::CollectIvarsToConstructOrDestruct(ObjCInterfaceDecl *OI,
- llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) {
+ SmallVectorImpl<ObjCIvarDecl*> &Ivars) {
for (ObjCIvarDecl *Iv = OI->all_declared_ivar_begin(); Iv;
Iv= Iv->getNextIvar()) {
QualType QT = Context.getBaseElementType(Iv->getType());
@@ -2656,20 +2898,15 @@ void Sema::CollectIvarsToConstructOrDestruct(ObjCInterfaceDecl *OI,
}
}
-void ObjCImplementationDecl::setIvarInitializers(ASTContext &C,
- CXXCtorInitializer ** initializers,
- unsigned numInitializers) {
- if (numInitializers > 0) {
- NumIvarInitializers = numInitializers;
- CXXCtorInitializer **ivarInitializers =
- new (C) CXXCtorInitializer*[NumIvarInitializers];
- memcpy(ivarInitializers, initializers,
- numInitializers * sizeof(CXXCtorInitializer*));
- IvarInitializers = ivarInitializers;
- }
-}
-
void Sema::DiagnoseUseOfUnimplementedSelectors() {
+ // Load referenced selectors from the external source.
+ if (ExternalSource) {
+ SmallVector<std::pair<Selector, SourceLocation>, 4> Sels;
+ ExternalSource->ReadReferencedSelectors(Sels);
+ for (unsigned I = 0, N = Sels.size(); I != N; ++I)
+ ReferencedSelectors[Sels[I].first] = Sels[I].second;
+ }
+
// Warning will be issued only when selector table is
// generated (which means there is at lease one implementation
// in the TU). This is to match gcc's behavior.
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 7bcec315ddab..92af2d914ba0 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -101,7 +101,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
bool MissingExceptionSpecification = false;
bool MissingEmptyExceptionSpecification = false;
unsigned DiagID = diag::err_mismatched_exception_spec;
- if (getLangOptions().Microsoft)
+ if (getLangOptions().MicrosoftExt)
DiagID = diag::warn_mismatched_exception_spec;
if (!CheckEquivalentExceptionSpec(PDiag(DiagID),
@@ -205,7 +205,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
else
OS << ", ";
- OS << E->getAsString(Context.PrintingPolicy);
+ OS << E->getAsString(getPrintingPolicy());
}
OS << ")";
break;
@@ -217,13 +217,13 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
case EST_ComputedNoexcept:
OS << "noexcept(";
- OldProto->getNoexceptExpr()->printPretty(OS, Context, 0,
- Context.PrintingPolicy);
+ OldProto->getNoexceptExpr()->printPretty(OS, Context, 0,
+ getPrintingPolicy());
OS << ")";
break;
default:
- assert(false && "This spec type is compatible with none.");
+ llvm_unreachable("This spec type is compatible with none.");
}
OS.flush();
@@ -264,7 +264,7 @@ bool Sema::CheckEquivalentExceptionSpec(
const FunctionProtoType *Old, SourceLocation OldLoc,
const FunctionProtoType *New, SourceLocation NewLoc) {
unsigned DiagID = diag::err_mismatched_exception_spec;
- if (getLangOptions().Microsoft)
+ if (getLangOptions().MicrosoftExt)
DiagID = diag::warn_mismatched_exception_spec;
return CheckEquivalentExceptionSpec(
PDiag(DiagID),
@@ -717,7 +717,7 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
}
}
unsigned DiagID = diag::err_override_exception_spec;
- if (getLangOptions().Microsoft)
+ if (getLangOptions().MicrosoftExt)
DiagID = diag::warn_override_exception_spec;
return CheckExceptionSpecSubset(PDiag(DiagID),
PDiag(diag::note_overridden_virtual_function),
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 5efc36559d97..170097cc59a9 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -36,10 +36,60 @@
#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"
using namespace clang;
using namespace sema;
+/// \brief Determine whether the use of this declaration is valid, without
+/// emitting diagnostics.
+bool Sema::CanUseDecl(NamedDecl *D) {
+ // See if this is an auto-typed variable whose initializer we are parsing.
+ if (ParsingInitForAutoVars.count(D))
+ return false;
+
+ // See if this is a deleted function.
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->isDeleted())
+ return false;
+ }
+ return true;
+}
+
+static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S,
+ NamedDecl *D, SourceLocation Loc,
+ const ObjCInterfaceDecl *UnknownObjCClass) {
+ // See if this declaration is unavailable or deprecated.
+ std::string Message;
+ AvailabilityResult Result = D->getAvailability(&Message);
+ switch (Result) {
+ case AR_Available:
+ case AR_NotYetIntroduced:
+ break;
+
+ case AR_Deprecated:
+ S.EmitDeprecationWarning(D, Message, Loc, UnknownObjCClass);
+ break;
+
+ case AR_Unavailable:
+ if (S.getCurContextAvailability() != AR_Unavailable) {
+ if (Message.empty()) {
+ if (!UnknownObjCClass)
+ S.Diag(Loc, diag::err_unavailable) << D->getDeclName();
+ else
+ S.Diag(Loc, diag::warn_unavailable_fwdclass_message)
+ << D->getDeclName();
+ }
+ else
+ S.Diag(Loc, diag::err_unavailable_message)
+ << D->getDeclName() << Message;
+ S.Diag(D->getLocation(), diag::note_unavailable_here)
+ << isa<FunctionDecl>(D) << false;
+ }
+ break;
+ }
+ return Result;
+}
/// \brief Determine whether the use of this declaration is valid, and
/// emit any corresponding diagnostics.
@@ -50,9 +100,6 @@ using namespace sema;
/// used, or produce an error (and return true) if a C++0x deleted
/// function is being used.
///
-/// If IgnoreDeprecated is set to true, this should not warn about deprecated
-/// decls.
-///
/// \returns true if there was an error (this declaration cannot be
/// referenced), false otherwise.
///
@@ -61,10 +108,10 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
if (getLangOptions().CPlusPlus && isa<FunctionDecl>(D)) {
// If there were any diagnostics suppressed by template argument deduction,
// emit them now.
- llvm::DenseMap<Decl *, llvm::SmallVector<PartialDiagnosticAt, 1> >::iterator
+ llvm::DenseMap<Decl *, SmallVector<PartialDiagnosticAt, 1> >::iterator
Pos = SuppressedDiagnostics.find(D->getCanonicalDecl());
if (Pos != SuppressedDiagnostics.end()) {
- llvm::SmallVectorImpl<PartialDiagnosticAt> &Suppressed = Pos->second;
+ SmallVectorImpl<PartialDiagnosticAt> &Suppressed = Pos->second;
for (unsigned I = 0, N = Suppressed.size(); I != N; ++I)
Diag(Suppressed[I].first, Suppressed[I].second);
@@ -91,40 +138,22 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
return true;
}
}
-
- // See if this declaration is unavailable or deprecated.
- std::string Message;
- switch (D->getAvailability(&Message)) {
- case AR_Available:
- case AR_NotYetIntroduced:
- break;
-
- case AR_Deprecated:
- EmitDeprecationWarning(D, Message, Loc, UnknownObjCClass);
- break;
-
- case AR_Unavailable:
- if (cast<Decl>(CurContext)->getAvailability() != AR_Unavailable) {
- if (Message.empty()) {
- if (!UnknownObjCClass)
- Diag(Loc, diag::err_unavailable) << D->getDeclName();
- else
- Diag(Loc, diag::warn_unavailable_fwdclass_message)
- << D->getDeclName();
- }
- else
- Diag(Loc, diag::err_unavailable_message)
- << D->getDeclName() << Message;
- Diag(D->getLocation(), diag::note_unavailable_here)
- << isa<FunctionDecl>(D) << false;
- }
- break;
- }
+ AvailabilityResult Result =
+ DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass);
// Warn if this is used but marked unused.
if (D->hasAttr<UnusedAttr>())
Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName();
-
+ // For available enumerator, it will become unavailable/deprecated
+ // if its enum declaration is as such.
+ if (Result == AR_Available)
+ if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) {
+ const DeclContext *DC = ECD->getDeclContext();
+ if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC))
+ DiagnoseAvailabilityOfDecl(*this,
+ const_cast< EnumDecl *>(TheEnumDecl),
+ Loc, UnknownObjCClass);
+ }
return false;
}
@@ -145,94 +174,74 @@ std::string Sema::getDeletedOrUnavailableSuffix(const FunctionDecl *FD) {
return std::string();
}
-/// DiagnoseSentinelCalls - This routine checks on method dispatch calls
-/// (and other functions in future), which have been declared with sentinel
-/// attribute. It warns if call does not have the sentinel argument.
-///
+/// DiagnoseSentinelCalls - This routine checks whether a call or
+/// message-send is to a declaration with the sentinel attribute, and
+/// if so, it checks that the requirements of the sentinel are
+/// satisfied.
void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
- Expr **Args, unsigned NumArgs) {
+ Expr **args, unsigned numArgs) {
const SentinelAttr *attr = D->getAttr<SentinelAttr>();
if (!attr)
return;
- // FIXME: In C++0x, if any of the arguments are parameter pack
- // expansions, we can't check for the sentinel now.
- int sentinelPos = attr->getSentinel();
- int nullPos = attr->getNullPos();
+ // The number of formal parameters of the declaration.
+ unsigned numFormalParams;
+
+ // The kind of declaration. This is also an index into a %select in
+ // the diagnostic.
+ enum CalleeType { CT_Function, CT_Method, CT_Block } calleeType;
- // FIXME. ObjCMethodDecl and FunctionDecl need be derived from the same common
- // base class. Then we won't be needing two versions of the same code.
- unsigned int i = 0;
- bool warnNotEnoughArgs = false;
- int isMethod = 0;
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- // skip over named parameters.
- ObjCMethodDecl::param_iterator P, E = MD->param_end();
- for (P = MD->param_begin(); (P != E && i < NumArgs); ++P) {
- if (nullPos)
- --nullPos;
- else
- ++i;
- }
- warnNotEnoughArgs = (P != E || i >= NumArgs);
- isMethod = 1;
+ numFormalParams = MD->param_size();
+ calleeType = CT_Method;
} else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- // skip over named parameters.
- ObjCMethodDecl::param_iterator P, E = FD->param_end();
- for (P = FD->param_begin(); (P != E && i < NumArgs); ++P) {
- if (nullPos)
- --nullPos;
- else
- ++i;
- }
- warnNotEnoughArgs = (P != E || i >= NumArgs);
- } else if (VarDecl *V = dyn_cast<VarDecl>(D)) {
- // block or function pointer call.
- QualType Ty = V->getType();
- if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
- const FunctionType *FT = Ty->isFunctionPointerType()
- ? Ty->getAs<PointerType>()->getPointeeType()->getAs<FunctionType>()
- : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
- if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) {
- unsigned NumArgsInProto = Proto->getNumArgs();
- unsigned k;
- for (k = 0; (k != NumArgsInProto && i < NumArgs); k++) {
- if (nullPos)
- --nullPos;
- else
- ++i;
- }
- warnNotEnoughArgs = (k != NumArgsInProto || i >= NumArgs);
- }
- if (Ty->isBlockPointerType())
- isMethod = 2;
- } else
+ numFormalParams = FD->param_size();
+ calleeType = CT_Function;
+ } else if (isa<VarDecl>(D)) {
+ QualType type = cast<ValueDecl>(D)->getType();
+ const FunctionType *fn = 0;
+ if (const PointerType *ptr = type->getAs<PointerType>()) {
+ fn = ptr->getPointeeType()->getAs<FunctionType>();
+ if (!fn) return;
+ calleeType = CT_Function;
+ } else if (const BlockPointerType *ptr = type->getAs<BlockPointerType>()) {
+ fn = ptr->getPointeeType()->castAs<FunctionType>();
+ calleeType = CT_Block;
+ } else {
return;
- } else
- return;
+ }
- if (warnNotEnoughArgs) {
- Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName();
- Diag(D->getLocation(), diag::note_sentinel_here) << isMethod;
+ if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fn)) {
+ numFormalParams = proto->getNumArgs();
+ } else {
+ numFormalParams = 0;
+ }
+ } else {
return;
}
- int sentinel = i;
- while (sentinelPos > 0 && i < NumArgs-1) {
- --sentinelPos;
- ++i;
- }
- if (sentinelPos > 0) {
+
+ // "nullPos" is the number of formal parameters at the end which
+ // effectively count as part of the variadic arguments. This is
+ // useful if you would prefer to not have *any* formal parameters,
+ // but the language forces you to have at least one.
+ unsigned nullPos = attr->getNullPos();
+ assert((nullPos == 0 || nullPos == 1) && "invalid null position on sentinel");
+ numFormalParams = (nullPos > numFormalParams ? 0 : numFormalParams - nullPos);
+
+ // The number of arguments which should follow the sentinel.
+ unsigned numArgsAfterSentinel = attr->getSentinel();
+
+ // If there aren't enough arguments for all the formal parameters,
+ // the sentinel, and the args after the sentinel, complain.
+ if (numArgs < numFormalParams + numArgsAfterSentinel + 1) {
Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName();
- Diag(D->getLocation(), diag::note_sentinel_here) << isMethod;
+ Diag(D->getLocation(), diag::note_sentinel_here) << calleeType;
return;
}
- while (i < NumArgs-1) {
- ++i;
- ++sentinel;
- }
- Expr *sentinelExpr = Args[sentinel];
+
+ // Otherwise, find the sentinel expression.
+ Expr *sentinelExpr = args[numArgs - numArgsAfterSentinel - 1];
if (!sentinelExpr) return;
- if (sentinelExpr->isTypeDependent()) return;
if (sentinelExpr->isValueDependent()) return;
// nullptr_t is always treated as null.
@@ -246,13 +255,32 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
// Unfortunately, __null has type 'int'.
if (isa<GNUNullExpr>(sentinelExpr)) return;
- Diag(Loc, diag::warn_missing_sentinel) << isMethod;
- Diag(D->getLocation(), diag::note_sentinel_here) << isMethod;
+ // Pick a reasonable string to insert. Optimistically use 'nil' or
+ // 'NULL' if those are actually defined in the context. Only use
+ // 'nil' for ObjC methods, where it's much more likely that the
+ // variadic arguments form a list of object pointers.
+ SourceLocation MissingNilLoc
+ = PP.getLocForEndOfToken(sentinelExpr->getLocEnd());
+ std::string NullValue;
+ if (calleeType == CT_Method &&
+ PP.getIdentifierInfo("nil")->hasMacroDefinition())
+ NullValue = "nil";
+ else if (PP.getIdentifierInfo("NULL")->hasMacroDefinition())
+ NullValue = "NULL";
+ else
+ NullValue = "(void*) 0";
+
+ if (MissingNilLoc.isInvalid())
+ Diag(Loc, diag::warn_missing_sentinel) << calleeType;
+ else
+ Diag(MissingNilLoc, diag::warn_missing_sentinel)
+ << calleeType
+ << FixItHint::CreateInsertion(MissingNilLoc, ", " + NullValue);
+ Diag(D->getLocation(), diag::note_sentinel_here) << calleeType;
}
-SourceRange Sema::getExprRange(ExprTy *E) const {
- Expr *Ex = (Expr *)E;
- return Ex? Ex->getSourceRange() : SourceRange();
+SourceRange Sema::getExprRange(Expr *E) const {
+ return E ? E->getSourceRange() : SourceRange();
}
//===----------------------------------------------------------------------===//
@@ -261,6 +289,13 @@ SourceRange Sema::getExprRange(ExprTy *E) const {
/// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4).
ExprResult Sema::DefaultFunctionArrayConversion(Expr *E) {
+ // Handle any placeholder expressions which made it here.
+ if (E->getType()->isPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(E);
+ if (result.isInvalid()) return ExprError();
+ E = result.take();
+ }
+
QualType Ty = E->getType();
assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type");
@@ -306,6 +341,13 @@ static void CheckForNullPointerDereference(Sema &S, Expr *E) {
}
ExprResult Sema::DefaultLvalueConversion(Expr *E) {
+ // Handle any placeholder expressions which made it here.
+ if (E->getType()->isPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(E);
+ if (result.isInvalid()) return ExprError();
+ E = result.take();
+ }
+
// C++ [conv.lval]p1:
// A glvalue of a non-function, non-array type T can be
// converted to a prvalue.
@@ -314,6 +356,10 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
QualType T = E->getType();
assert(!T.isNull() && "r-value conversion on typeless expression?");
+ // We can't do lvalue-to-rvalue on atomics yet.
+ if (T->getAs<AtomicType>())
+ return Owned(E);
+
// Create a load out of an ObjCProperty l-value, if necessary.
if (E->getObjectKind() == OK_ObjCProperty) {
ExprResult Res = ConvertPropertyForRValue(E);
@@ -350,14 +396,14 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
// C99 6.3.2.1p2:
// If the lvalue has qualified type, the value has the unqualified
// version of the type of the lvalue; otherwise, the value has the
- // type of the lvalue.
+ // type of the lvalue.
if (T.hasQualifiers())
T = T.getUnqualifiedType();
- CheckArrayAccess(E);
-
- return Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue,
- E, 0, VK_RValue));
+ ExprResult Res = Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue,
+ E, 0, VK_RValue));
+
+ return Res;
}
ExprResult Sema::DefaultFunctionArrayLvalueConversion(Expr *E) {
@@ -382,10 +428,15 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) {
if (Res.isInvalid())
return Owned(E);
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())
+ return ImpCastExprToType(Res.take(), Context.FloatTy, CK_FloatingCast);
+
// Try to perform integral promotions if the object has a theoretically
// promotable type.
if (Ty->isIntegralOrUnscopedEnumerationType()) {
@@ -402,7 +453,7 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) {
// value is converted to an int; otherwise, it is converted to an
// unsigned int. These are called the integer promotions. All
// other types are unchanged by the integer promotions.
-
+
QualType PTy = Context.isPromotableBitField(E);
if (!PTy.isNull()) {
E = ImpCastExprToType(E, PTy, CK_IntegralCast).take();
@@ -433,6 +484,28 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
if (Ty->isSpecificBuiltinType(BuiltinType::Float))
E = ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast).take();
+ // C++ performs lvalue-to-rvalue conversion as a default argument
+ // promotion, even on class types, but note:
+ // C++11 [conv.lval]p2:
+ // When an lvalue-to-rvalue conversion occurs in an unevaluated
+ // operand or a subexpression thereof the value contained in the
+ // referenced object is not accessed. Otherwise, if the glvalue
+ // has a class type, the conversion copy-initializes a temporary
+ // of type T from the glvalue and the result of the conversion
+ // is a prvalue for the temporary.
+ // FIXME: add some way to gate this entire thing for correctness in
+ // potentially potentially evaluated contexts.
+ if (getLangOptions().CPlusPlus && E->isGLValue() &&
+ ExprEvalContexts.back().Context != Unevaluated) {
+ ExprResult Temp = PerformCopyInitialization(
+ InitializedEntity::InitializeTemporary(E->getType()),
+ E->getExprLoc(),
+ Owned(E));
+ if (Temp.isInvalid())
+ return ExprError();
+ E = Temp.get();
+ }
+
return Owned(E);
}
@@ -450,20 +523,17 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
return ExprError();
E = ExprRes.take();
- // __builtin_va_start takes the second argument as a "varargs" argument, but
- // it doesn't actually do anything with it. It doesn't need to be non-pod
- // etc.
- if (FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_va_start)
- return Owned(E);
-
// Don't allow one to pass an Objective-C interface to a vararg.
if (E->getType()->isObjCObjectType() &&
DiagRuntimeBehavior(E->getLocStart(), 0,
PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
<< E->getType() << CT))
return ExprError();
-
- if (!E->getType().isPODType(Context)) {
+
+ // Complain about passing non-POD types through varargs. However, don't
+ // perform this check for incomplete types, which we can get here when we're
+ // in an unevaluated context.
+ if (!E->getType()->isIncompleteType() && !E->getType().isPODType(Context)) {
// C++0x [expr.call]p7:
// Passing a potentially-evaluated argument of class type (Clause 9)
// having a non-trivial copy constructor, a non-trivial move constructor,
@@ -507,8 +577,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
ExprResult Comma = ActOnBinOp(TUScope, E->getLocStart(), tok::comma,
Call.get(), E);
if (Comma.isInvalid())
- return ExprError();
-
+ return ExprError();
E = Comma.get();
}
}
@@ -516,307 +585,363 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
return Owned(E);
}
-/// 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 &lhsExpr, ExprResult &rhsExpr,
- bool isCompAssign) {
- if (!isCompAssign) {
- lhsExpr = UsualUnaryConversions(lhsExpr.take());
- if (lhsExpr.isInvalid())
- return QualType();
+/// \brief Converts an integer to complex float type. Helper function of
+/// UsualArithmeticConversions()
+///
+/// \return false if the integer expression is an integer type and is
+/// successfully converted to the complex type.
+static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr,
+ ExprResult &ComplexExpr,
+ QualType IntTy,
+ QualType ComplexTy,
+ bool SkipCast) {
+ if (IntTy->isComplexType() || IntTy->isRealFloatingType()) return true;
+ if (SkipCast) return false;
+ if (IntTy->isIntegerType()) {
+ QualType fpTy = cast<ComplexType>(ComplexTy)->getElementType();
+ IntExpr = S.ImpCastExprToType(IntExpr.take(), fpTy, CK_IntegralToFloating);
+ IntExpr = S.ImpCastExprToType(IntExpr.take(), ComplexTy,
+ CK_FloatingRealToComplex);
+ } else {
+ assert(IntTy->isComplexIntegerType());
+ IntExpr = S.ImpCastExprToType(IntExpr.take(), ComplexTy,
+ CK_IntegralComplexToFloatingComplex);
}
+ return false;
+}
- rhsExpr = UsualUnaryConversions(rhsExpr.take());
- if (rhsExpr.isInvalid())
- return QualType();
-
- // For conversion purposes, we ignore any qualifiers.
- // For example, "const float" and "float" are equivalent.
- QualType lhs =
- Context.getCanonicalType(lhsExpr.get()->getType()).getUnqualifiedType();
- QualType rhs =
- Context.getCanonicalType(rhsExpr.get()->getType()).getUnqualifiedType();
-
- // If both types are identical, no conversion is needed.
- if (lhs == rhs)
- return lhs;
-
- // If either side is a non-arithmetic type (e.g. a pointer), we are done.
- // The caller can deal with this (e.g. pointer + int).
- if (!lhs->isArithmeticType() || !rhs->isArithmeticType())
- return lhs;
-
- // Apply unary and bitfield promotions to the LHS's type.
- QualType lhs_unpromoted = lhs;
- if (lhs->isPromotableIntegerType())
- lhs = Context.getPromotedIntegerType(lhs);
- QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(lhsExpr.get());
- if (!LHSBitfieldPromoteTy.isNull())
- lhs = LHSBitfieldPromoteTy;
- if (lhs != lhs_unpromoted && !isCompAssign)
- lhsExpr = ImpCastExprToType(lhsExpr.take(), lhs, CK_IntegralCast);
-
- // If both types are identical, no conversion is needed.
- if (lhs == rhs)
- return lhs;
-
- // At this point, we have two different arithmetic types.
-
- // Handle complex types first (C99 6.3.1.8p1).
- bool LHSComplexFloat = lhs->isComplexType();
- bool RHSComplexFloat = rhs->isComplexType();
- if (LHSComplexFloat || RHSComplexFloat) {
- // if we have an integer operand, the result is the complex type.
-
- if (!RHSComplexFloat && !rhs->isRealFloatingType()) {
- if (rhs->isIntegerType()) {
- QualType fp = cast<ComplexType>(lhs)->getElementType();
- rhsExpr = ImpCastExprToType(rhsExpr.take(), fp, CK_IntegralToFloating);
- rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingRealToComplex);
- } else {
- assert(rhs->isComplexIntegerType());
- rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralComplexToFloatingComplex);
- }
- return lhs;
- }
-
- if (!LHSComplexFloat && !lhs->isRealFloatingType()) {
- if (!isCompAssign) {
- // int -> float -> _Complex float
- if (lhs->isIntegerType()) {
- QualType fp = cast<ComplexType>(rhs)->getElementType();
- lhsExpr = ImpCastExprToType(lhsExpr.take(), fp, CK_IntegralToFloating);
- lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingRealToComplex);
- } else {
- assert(lhs->isComplexIntegerType());
- lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralComplexToFloatingComplex);
- }
- }
- return rhs;
- }
-
- // This handles complex/complex, complex/float, or float/complex.
- // When both operands are complex, the shorter operand is converted to the
- // type of the longer, and that is the type of the result. This corresponds
- // to what is done when combining two real floating-point operands.
- // The fun begins when size promotion occur across type domains.
- // From H&S 6.3.4: When one operand is complex and the other is a real
- // floating-point type, the less precise type is converted, within it's
- // real or complex domain, to the precision of the other type. For example,
- // when combining a "long double" with a "double _Complex", the
- // "double _Complex" is promoted to "long double _Complex".
- int order = Context.getFloatingTypeOrder(lhs, rhs);
-
- // If both are complex, just cast to the more precise type.
- if (LHSComplexFloat && RHSComplexFloat) {
- if (order > 0) {
- // _Complex float -> _Complex double
- rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingComplexCast);
- return lhs;
-
- } else if (order < 0) {
- // _Complex float -> _Complex double
- if (!isCompAssign)
- lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingComplexCast);
- return rhs;
- }
- return lhs;
- }
-
- // If just the LHS is complex, the RHS needs to be converted,
- // and the LHS might need to be promoted.
- if (LHSComplexFloat) {
- if (order > 0) { // LHS is wider
- // float -> _Complex double
- QualType fp = cast<ComplexType>(lhs)->getElementType();
- rhsExpr = ImpCastExprToType(rhsExpr.take(), fp, CK_FloatingCast);
- rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingRealToComplex);
- return lhs;
- }
-
- // RHS is at least as wide. Find its corresponding complex type.
- QualType result = (order == 0 ? lhs : Context.getComplexType(rhs));
-
- // double -> _Complex double
- rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_FloatingRealToComplex);
-
- // _Complex float -> _Complex double
- if (!isCompAssign && order < 0)
- lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_FloatingComplexCast);
-
- return result;
- }
-
- // Just the RHS is complex, so the LHS needs to be converted
- // and the RHS might need to be promoted.
- assert(RHSComplexFloat);
-
- if (order < 0) { // RHS is wider
- // float -> _Complex double
- if (!isCompAssign) {
- QualType fp = cast<ComplexType>(rhs)->getElementType();
- lhsExpr = ImpCastExprToType(lhsExpr.take(), fp, CK_FloatingCast);
- lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingRealToComplex);
- }
- return rhs;
- }
-
- // LHS is at least as wide. Find its corresponding complex type.
- QualType result = (order == 0 ? rhs : Context.getComplexType(lhs));
-
- // double -> _Complex double
- if (!isCompAssign)
- lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_FloatingRealToComplex);
+/// \brief Takes two complex float types and converts them to the same type.
+/// Helper function of UsualArithmeticConversions()
+static QualType
+handleComplexFloatToComplexFloatConverstion(Sema &S, ExprResult &LHS,
+ ExprResult &RHS, QualType LHSType,
+ QualType RHSType,
+ bool IsCompAssign) {
+ int order = S.Context.getFloatingTypeOrder(LHSType, RHSType);
+ if (order < 0) {
// _Complex float -> _Complex double
- if (order > 0)
- rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_FloatingComplexCast);
-
- return result;
+ if (!IsCompAssign)
+ LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_FloatingComplexCast);
+ return RHSType;
}
+ if (order > 0)
+ // _Complex float -> _Complex double
+ RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_FloatingComplexCast);
+ return LHSType;
+}
+
+/// \brief Converts otherExpr to complex float and promotes complexExpr if
+/// necessary. Helper function of UsualArithmeticConversions()
+static QualType handleOtherComplexFloatConversion(Sema &S,
+ ExprResult &ComplexExpr,
+ ExprResult &OtherExpr,
+ QualType ComplexTy,
+ QualType OtherTy,
+ bool ConvertComplexExpr,
+ bool ConvertOtherExpr) {
+ int order = S.Context.getFloatingTypeOrder(ComplexTy, OtherTy);
+
+ // If just the complexExpr is complex, the otherExpr needs to be converted,
+ // and the complexExpr might need to be promoted.
+ if (order > 0) { // complexExpr is wider
+ // float -> _Complex double
+ if (ConvertOtherExpr) {
+ QualType fp = cast<ComplexType>(ComplexTy)->getElementType();
+ OtherExpr = S.ImpCastExprToType(OtherExpr.take(), fp, CK_FloatingCast);
+ OtherExpr = S.ImpCastExprToType(OtherExpr.take(), ComplexTy,
+ CK_FloatingRealToComplex);
+ }
+ return ComplexTy;
+ }
+
+ // otherTy is at least as wide. Find its corresponding complex type.
+ QualType result = (order == 0 ? ComplexTy :
+ S.Context.getComplexType(OtherTy));
+
+ // double -> _Complex double
+ if (ConvertOtherExpr)
+ OtherExpr = S.ImpCastExprToType(OtherExpr.take(), result,
+ CK_FloatingRealToComplex);
+
+ // _Complex float -> _Complex double
+ if (ConvertComplexExpr && order < 0)
+ ComplexExpr = S.ImpCastExprToType(ComplexExpr.take(), result,
+ CK_FloatingComplexCast);
- // Now handle "real" floating types (i.e. float, double, long double).
- bool LHSFloat = lhs->isRealFloatingType();
- bool RHSFloat = rhs->isRealFloatingType();
- if (LHSFloat || RHSFloat) {
- // If we have two real floating types, convert the smaller operand
- // to the bigger result.
- if (LHSFloat && RHSFloat) {
- int order = Context.getFloatingTypeOrder(lhs, rhs);
- if (order > 0) {
- rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingCast);
- return lhs;
- }
-
- assert(order < 0 && "illegal float comparison");
- if (!isCompAssign)
- lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingCast);
- return rhs;
- }
-
- // If we have an integer operand, the result is the real floating type.
- if (LHSFloat) {
- if (rhs->isIntegerType()) {
- // Convert rhs to the lhs floating point type.
- rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralToFloating);
- return lhs;
- }
-
- // Convert both sides to the appropriate complex float.
- assert(rhs->isComplexIntegerType());
- QualType result = Context.getComplexType(lhs);
-
- // _Complex int -> _Complex float
- rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_IntegralComplexToFloatingComplex);
-
- // float -> _Complex float
- if (!isCompAssign)
- lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_FloatingRealToComplex);
-
- return result;
- }
-
- assert(RHSFloat);
- if (lhs->isIntegerType()) {
- // Convert lhs to the rhs floating point type.
- if (!isCompAssign)
- lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralToFloating);
- return rhs;
- }
-
- // Convert both sides to the appropriate complex float.
- assert(lhs->isComplexIntegerType());
- QualType result = Context.getComplexType(rhs);
+ return result;
+}
- // _Complex int -> _Complex float
- if (!isCompAssign)
- lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_IntegralComplexToFloatingComplex);
+/// \brief Handle arithmetic conversion with complex types. Helper function of
+/// UsualArithmeticConversions()
+static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS,
+ ExprResult &RHS, QualType LHSType,
+ QualType RHSType,
+ bool IsCompAssign) {
+ // if we have an integer operand, the result is the complex type.
+ if (!handleIntegerToComplexFloatConversion(S, RHS, LHS, RHSType, LHSType,
+ /*skipCast*/false))
+ return LHSType;
+ if (!handleIntegerToComplexFloatConversion(S, LHS, RHS, LHSType, RHSType,
+ /*skipCast*/IsCompAssign))
+ return RHSType;
+
+ // This handles complex/complex, complex/float, or float/complex.
+ // When both operands are complex, the shorter operand is converted to the
+ // type of the longer, and that is the type of the result. This corresponds
+ // to what is done when combining two real floating-point operands.
+ // The fun begins when size promotion occur across type domains.
+ // From H&S 6.3.4: When one operand is complex and the other is a real
+ // floating-point type, the less precise type is converted, within it's
+ // real or complex domain, to the precision of the other type. For example,
+ // when combining a "long double" with a "double _Complex", the
+ // "double _Complex" is promoted to "long double _Complex".
+
+ bool LHSComplexFloat = LHSType->isComplexType();
+ bool RHSComplexFloat = RHSType->isComplexType();
+
+ // If both are complex, just cast to the more precise type.
+ if (LHSComplexFloat && RHSComplexFloat)
+ return handleComplexFloatToComplexFloatConverstion(S, LHS, RHS,
+ LHSType, RHSType,
+ IsCompAssign);
+
+ // If only one operand is complex, promote it if necessary and convert the
+ // other operand to complex.
+ if (LHSComplexFloat)
+ return handleOtherComplexFloatConversion(
+ S, LHS, RHS, LHSType, RHSType, /*convertComplexExpr*/!IsCompAssign,
+ /*convertOtherExpr*/ true);
+
+ assert(RHSComplexFloat);
+ return handleOtherComplexFloatConversion(
+ S, RHS, LHS, RHSType, LHSType, /*convertComplexExpr*/true,
+ /*convertOtherExpr*/ !IsCompAssign);
+}
+
+/// \brief Hande arithmetic conversion from integer to float. Helper function
+/// of UsualArithmeticConversions()
+static QualType handleIntToFloatConversion(Sema &S, ExprResult &FloatExpr,
+ ExprResult &IntExpr,
+ QualType FloatTy, QualType IntTy,
+ bool ConvertFloat, bool ConvertInt) {
+ if (IntTy->isIntegerType()) {
+ if (ConvertInt)
+ // Convert intExpr to the lhs floating point type.
+ IntExpr = S.ImpCastExprToType(IntExpr.take(), FloatTy,
+ CK_IntegralToFloating);
+ return FloatTy;
+ }
+
+ // Convert both sides to the appropriate complex float.
+ assert(IntTy->isComplexIntegerType());
+ QualType result = S.Context.getComplexType(FloatTy);
+
+ // _Complex int -> _Complex float
+ if (ConvertInt)
+ IntExpr = S.ImpCastExprToType(IntExpr.take(), result,
+ CK_IntegralComplexToFloatingComplex);
+
+ // float -> _Complex float
+ if (ConvertFloat)
+ FloatExpr = S.ImpCastExprToType(FloatExpr.take(), result,
+ CK_FloatingRealToComplex);
- // float -> _Complex float
- rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_FloatingRealToComplex);
+ return result;
+}
- return result;
- }
+/// \brief Handle arithmethic conversion with floating point types. Helper
+/// function of UsualArithmeticConversions()
+static QualType handleFloatConversion(Sema &S, ExprResult &LHS,
+ ExprResult &RHS, QualType LHSType,
+ QualType RHSType, bool IsCompAssign) {
+ bool LHSFloat = LHSType->isRealFloatingType();
+ bool RHSFloat = RHSType->isRealFloatingType();
- // Handle GCC complex int extension.
- // FIXME: if the operands are (int, _Complex long), we currently
- // don't promote the complex. Also, signedness?
- const ComplexType *lhsComplexInt = lhs->getAsComplexIntegerType();
- const ComplexType *rhsComplexInt = rhs->getAsComplexIntegerType();
- if (lhsComplexInt && rhsComplexInt) {
- int order = Context.getIntegerTypeOrder(lhsComplexInt->getElementType(),
- rhsComplexInt->getElementType());
+ // If we have two real floating types, convert the smaller operand
+ // to the bigger result.
+ if (LHSFloat && RHSFloat) {
+ int order = S.Context.getFloatingTypeOrder(LHSType, RHSType);
+ if (order > 0) {
+ RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_FloatingCast);
+ return LHSType;
+ }
+
+ assert(order < 0 && "illegal float comparison");
+ if (!IsCompAssign)
+ LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_FloatingCast);
+ return RHSType;
+ }
+
+ if (LHSFloat)
+ return handleIntToFloatConversion(S, LHS, RHS, LHSType, RHSType,
+ /*convertFloat=*/!IsCompAssign,
+ /*convertInt=*/ true);
+ assert(RHSFloat);
+ return handleIntToFloatConversion(S, RHS, LHS, RHSType, LHSType,
+ /*convertInt=*/ true,
+ /*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();
+
+ 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
- rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralComplexCast);
- return lhs;
+ RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralComplexCast);
+ return LHSType;
}
- if (!isCompAssign)
- lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralComplexCast);
- return rhs;
- } else if (lhsComplexInt) {
- // int -> _Complex int
- rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralRealToComplex);
- return lhs;
- } else if (rhsComplexInt) {
+ if (!IsCompAssign)
+ LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralComplexCast);
+ return RHSType;
+ }
+
+ if (LHSComplexInt) {
// int -> _Complex int
- if (!isCompAssign)
- lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralRealToComplex);
- return rhs;
+ RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralRealToComplex);
+ return LHSType;
}
- // Finally, we have two differing integer types.
+ assert(RHSComplexInt);
+ // int -> _Complex int
+ if (!IsCompAssign)
+ LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralRealToComplex);
+ return RHSType;
+}
+
+/// \brief Handle integer arithmetic conversions. Helper function of
+/// UsualArithmeticConversions()
+static QualType handleIntegerConversion(Sema &S, ExprResult &LHS,
+ ExprResult &RHS, QualType LHSType,
+ QualType RHSType, bool IsCompAssign) {
// The rules for this case are in C99 6.3.1.8
- int compare = Context.getIntegerTypeOrder(lhs, rhs);
- bool lhsSigned = lhs->hasSignedIntegerRepresentation(),
- rhsSigned = rhs->hasSignedIntegerRepresentation();
- if (lhsSigned == rhsSigned) {
+ int order = S.Context.getIntegerTypeOrder(LHSType, RHSType);
+ bool LHSSigned = LHSType->hasSignedIntegerRepresentation();
+ bool RHSSigned = RHSType->hasSignedIntegerRepresentation();
+ if (LHSSigned == RHSSigned) {
// Same signedness; use the higher-ranked type
- if (compare >= 0) {
- rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralCast);
- return lhs;
- } else if (!isCompAssign)
- lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralCast);
- return rhs;
- } else if (compare != (lhsSigned ? 1 : -1)) {
+ if (order >= 0) {
+ RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralCast);
+ return LHSType;
+ } else if (!IsCompAssign)
+ LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralCast);
+ 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) {
- rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralCast);
- return lhs;
- } else if (!isCompAssign)
- lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralCast);
- return rhs;
- } else if (Context.getIntWidth(lhs) != Context.getIntWidth(rhs)) {
+ if (RHSSigned) {
+ RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralCast);
+ return LHSType;
+ } else if (!IsCompAssign)
+ LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralCast);
+ 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) {
- rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralCast);
- return lhs;
- } else if (!isCompAssign)
- lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralCast);
- return rhs;
+ if (LHSSigned) {
+ RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralCast);
+ return LHSType;
+ } else if (!IsCompAssign)
+ LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralCast);
+ return RHSType;
} else {
// The signed type is higher-ranked than the unsigned type,
// but isn't actually any bigger (like unsigned int and long
// on most 32-bit systems). Use the unsigned type corresponding
// to the signed type.
QualType result =
- Context.getCorrespondingUnsignedType(lhsSigned ? lhs : rhs);
- rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_IntegralCast);
- if (!isCompAssign)
- lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_IntegralCast);
+ S.Context.getCorrespondingUnsignedType(LHSSigned ? LHSType : RHSType);
+ RHS = S.ImpCastExprToType(RHS.take(), result, CK_IntegralCast);
+ if (!IsCompAssign)
+ LHS = S.ImpCastExprToType(LHS.take(), result, CK_IntegralCast);
return result;
}
}
+/// 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) {
+ LHS = UsualUnaryConversions(LHS.take());
+ if (LHS.isInvalid())
+ return QualType();
+ }
+
+ RHS = UsualUnaryConversions(RHS.take());
+ if (RHS.isInvalid())
+ return QualType();
+
+ // For conversion purposes, we ignore any qualifiers.
+ // For example, "const float" and "float" are equivalent.
+ QualType LHSType =
+ Context.getCanonicalType(LHS.get()->getType()).getUnqualifiedType();
+ QualType RHSType =
+ Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType();
+
+ // If both types are identical, no conversion is needed.
+ if (LHSType == RHSType)
+ return LHSType;
+
+ // If either side is a non-arithmetic type (e.g. a pointer), we are done.
+ // The caller can deal with this (e.g. pointer + int).
+ if (!LHSType->isArithmeticType() || !RHSType->isArithmeticType())
+ return LHSType;
+
+ // Apply unary and bitfield promotions to the LHS's type.
+ QualType LHSUnpromotedType = LHSType;
+ if (LHSType->isPromotableIntegerType())
+ LHSType = Context.getPromotedIntegerType(LHSType);
+ QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(LHS.get());
+ if (!LHSBitfieldPromoteTy.isNull())
+ LHSType = LHSBitfieldPromoteTy;
+ if (LHSType != LHSUnpromotedType && !IsCompAssign)
+ LHS = ImpCastExprToType(LHS.take(), LHSType, CK_IntegralCast);
+
+ // If both types are identical, no conversion is needed.
+ if (LHSType == RHSType)
+ return LHSType;
+
+ // At this point, we have two different arithmetic types.
+
+ // Handle complex types first (C99 6.3.1.8p1).
+ if (LHSType->isComplexType() || RHSType->isComplexType())
+ return handleComplexFloatConversion(*this, LHS, RHS, LHSType, RHSType,
+ IsCompAssign);
+
+ // Now handle "real" floating types (i.e. float, double, long double).
+ if (LHSType->isRealFloatingType() || RHSType->isRealFloatingType())
+ return handleFloatConversion(*this, LHS, RHS, LHSType, RHSType,
+ IsCompAssign);
+
+ // Handle GCC complex int extension.
+ if (LHSType->isComplexIntegerType() || RHSType->isComplexIntegerType())
+ return handleComplexIntConversion(*this, LHS, RHS, LHSType, RHSType,
+ IsCompAssign);
+
+ // Finally, we have two differing integer types.
+ return handleIntegerConversion(*this, LHS, RHS, LHSType, RHSType,
+ IsCompAssign);
+}
+
//===----------------------------------------------------------------------===//
// Semantic Analysis for various Expression Types
//===----------------------------------------------------------------------===//
@@ -827,13 +952,13 @@ Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc,
SourceLocation DefaultLoc,
SourceLocation RParenLoc,
Expr *ControllingExpr,
- MultiTypeArg types,
- MultiExprArg exprs) {
- unsigned NumAssocs = types.size();
- assert(NumAssocs == exprs.size());
+ MultiTypeArg ArgTypes,
+ MultiExprArg ArgExprs) {
+ unsigned NumAssocs = ArgTypes.size();
+ assert(NumAssocs == ArgExprs.size());
- ParsedType *ParsedTypes = types.release();
- Expr **Exprs = exprs.release();
+ ParsedType *ParsedTypes = ArgTypes.release();
+ Expr **Exprs = ArgExprs.release();
TypeSourceInfo **Types = new TypeSourceInfo*[NumAssocs];
for (unsigned i = 0; i < NumAssocs; ++i) {
@@ -922,7 +1047,7 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
Types, Exprs, NumAssocs, DefaultLoc,
RParenLoc, ContainsUnexpandedParameterPack));
- llvm::SmallVector<unsigned, 1> CompatIndices;
+ SmallVector<unsigned, 1> CompatIndices;
unsigned DefaultIndex = -1U;
for (unsigned i = 0; i < NumAssocs; ++i) {
if (!Types[i])
@@ -942,7 +1067,7 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
Diag(ControllingExpr->getLocStart(), diag::err_generic_sel_multi_match)
<< ControllingExpr->getSourceRange() << ControllingExpr->getType()
<< (unsigned) CompatIndices.size();
- for (llvm::SmallVector<unsigned, 1>::iterator I = CompatIndices.begin(),
+ for (SmallVector<unsigned, 1>::iterator I = CompatIndices.begin(),
E = CompatIndices.end(); I != E; ++I) {
Diag(Types[*I]->getTypeLoc().getBeginLoc(),
diag::note_compat_assoc)
@@ -993,16 +1118,30 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
if (Literal.hadError)
return ExprError();
- llvm::SmallVector<SourceLocation, 4> StringTokLocs;
+ SmallVector<SourceLocation, 4> StringTokLocs;
for (unsigned i = 0; i != NumStringToks; ++i)
StringTokLocs.push_back(StringToks[i].getLocation());
QualType StrTy = Context.CharTy;
- if (Literal.AnyWide)
+ if (Literal.isWide())
StrTy = Context.getWCharType();
+ else if (Literal.isUTF16())
+ StrTy = Context.Char16Ty;
+ else if (Literal.isUTF32())
+ StrTy = Context.Char32Ty;
else if (Literal.Pascal)
StrTy = Context.UnsignedCharTy;
+ StringLiteral::StringKind Kind = StringLiteral::Ascii;
+ if (Literal.isWide())
+ Kind = StringLiteral::Wide;
+ else if (Literal.isUTF8())
+ Kind = StringLiteral::UTF8;
+ else if (Literal.isUTF16())
+ Kind = StringLiteral::UTF16;
+ else if (Literal.isUTF32())
+ Kind = StringLiteral::UTF32;
+
// A C++ string literal has a const-qualified element type (C++ 2.13.4p1).
if (getLangOptions().CPlusPlus || getLangOptions().ConstStrings)
StrTy.addConst();
@@ -1016,7 +1155,7 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
// Pass &StringTokLocs[0], StringTokLocs.size() to factory!
return Owned(StringLiteral::Create(Context, Literal.GetString(),
- Literal.AnyWide, Literal.Pascal, StrTy,
+ Kind, Literal.Pascal, StrTy,
&StringTokLocs[0],
StringTokLocs.size()));
}
@@ -1091,21 +1230,21 @@ diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
/// There is a well-formed capture at a particular scope level;
/// propagate it through all the nested blocks.
-static CaptureResult propagateCapture(Sema &S, unsigned validScopeIndex,
- const BlockDecl::Capture &capture) {
- VarDecl *var = capture.getVariable();
+static CaptureResult propagateCapture(Sema &S, unsigned ValidScopeIndex,
+ const BlockDecl::Capture &Capture) {
+ VarDecl *var = Capture.getVariable();
// Update all the inner blocks with the capture information.
- for (unsigned i = validScopeIndex + 1, e = S.FunctionScopes.size();
+ for (unsigned i = ValidScopeIndex + 1, e = S.FunctionScopes.size();
i != e; ++i) {
BlockScopeInfo *innerBlock = cast<BlockScopeInfo>(S.FunctionScopes[i]);
innerBlock->Captures.push_back(
- BlockDecl::Capture(capture.getVariable(), capture.isByRef(),
- /*nested*/ true, capture.getCopyExpr()));
+ BlockDecl::Capture(Capture.getVariable(), Capture.isByRef(),
+ /*nested*/ true, Capture.getCopyExpr()));
innerBlock->CaptureMap[var] = innerBlock->Captures.size(); // +1
}
- return capture.isByRef() ? CR_CaptureByRef : CR_Capture;
+ return Capture.isByRef() ? CR_CaptureByRef : CR_Capture;
}
/// shouldCaptureValueReference - Determine if a reference to the
@@ -1114,9 +1253,9 @@ static CaptureResult propagateCapture(Sema &S, unsigned validScopeIndex,
/// This also keeps the captures set in the BlockScopeInfo records
/// up-to-date.
static CaptureResult shouldCaptureValueReference(Sema &S, SourceLocation loc,
- ValueDecl *value) {
+ ValueDecl *Value) {
// Only variables ever require capture.
- VarDecl *var = dyn_cast<VarDecl>(value);
+ VarDecl *var = dyn_cast<VarDecl>(Value);
if (!var) return CR_NoCapture;
// Fast path: variables from the current context never require capture.
@@ -1225,19 +1364,19 @@ static CaptureResult shouldCaptureValueReference(Sema &S, SourceLocation loc,
blockScope->Captures.back());
}
-static ExprResult BuildBlockDeclRefExpr(Sema &S, ValueDecl *vd,
+static ExprResult BuildBlockDeclRefExpr(Sema &S, ValueDecl *VD,
const DeclarationNameInfo &NameInfo,
- bool byRef) {
- assert(isa<VarDecl>(vd) && "capturing non-variable");
+ bool ByRef) {
+ assert(isa<VarDecl>(VD) && "capturing non-variable");
- VarDecl *var = cast<VarDecl>(vd);
+ VarDecl *var = cast<VarDecl>(VD);
assert(var->hasLocalStorage() && "capturing non-local");
- assert(byRef == var->hasAttr<BlocksAttr>() && "byref set wrong");
+ assert(ByRef == var->hasAttr<BlocksAttr>() && "byref set wrong");
QualType exprType = var->getType().getNonReferenceType();
BlockDeclRefExpr *BDRE;
- if (!byRef) {
+ if (!ByRef) {
// The variable will be bound by copy; make it const within the
// closure, but record that this was done in the expression.
bool constAdded = !exprType.isConstQualified();
@@ -1268,6 +1407,20 @@ ExprResult
Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
const DeclarationNameInfo &NameInfo,
const CXXScopeSpec *SS) {
+ if (getLangOptions().CUDA)
+ if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext))
+ if (const FunctionDecl *Callee = dyn_cast<FunctionDecl>(D)) {
+ CUDAFunctionTarget CallerTarget = IdentifyCUDATarget(Caller),
+ CalleeTarget = IdentifyCUDATarget(Callee);
+ if (CheckCUDATarget(CallerTarget, CalleeTarget)) {
+ Diag(NameInfo.getLoc(), diag::err_ref_bad_target)
+ << CalleeTarget << D->getIdentifier() << CallerTarget;
+ Diag(D->getLocation(), diag::note_previous_decl)
+ << D->getIdentifier();
+ return ExprError();
+ }
+ }
+
MarkDeclarationReferenced(NameInfo.getLoc(), D);
Expr *E = DeclRefExpr::Create(Context,
@@ -1276,7 +1429,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
D, NameInfo, Ty, VK);
// Just in case we're building an illegal pointer-to-member.
- if (isa<FieldDecl>(D) && cast<FieldDecl>(D)->getBitWidth())
+ FieldDecl *FD = dyn_cast<FieldDecl>(D);
+ if (FD && FD->isBitField())
E->setObjectKind(OK_BitField);
return Owned(E);
@@ -1291,10 +1445,11 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
/// This actually loses a lot of source location information for
/// non-standard name kinds; we should consider preserving that in
/// some way.
-void Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id,
- TemplateArgumentListInfo &Buffer,
- DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *&TemplateArgs) {
+void
+Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id,
+ TemplateArgumentListInfo &Buffer,
+ DeclarationNameInfo &NameInfo,
+ const TemplateArgumentListInfo *&TemplateArgs) {
if (Id.getKind() == UnqualifiedId::IK_TemplateId) {
Buffer.setLAngleLoc(Id.TemplateId->LAngleLoc);
Buffer.setRAngleLoc(Id.TemplateId->RAngleLoc);
@@ -1319,7 +1474,9 @@ void Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id,
///
/// \return false if new lookup candidates were found
bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
- CorrectTypoContext CTC) {
+ CorrectTypoContext CTC,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
+ Expr **Args, unsigned NumArgs) {
DeclarationName Name = R.getLookupName();
unsigned diagnostic = diag::err_undeclared_var_use;
@@ -1358,6 +1515,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
CXXMethodDecl *DepMethod = cast_or_null<CXXMethodDecl>(
CurMethod->getInstantiatedFromMemberFunction());
if (DepMethod) {
+ if (getLangOptions().MicrosoftExt)
+ diagnostic = diag::warn_found_via_dependent_bases_lookup;
Diag(R.getNameLoc(), diagnostic) << Name
<< FixItHint::CreateInsertion(R.getNameLoc(), "this->");
QualType DepThisType = DepMethod->getThisType(Context);
@@ -1373,7 +1532,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
CXXDependentScopeMemberExpr::Create(
Context, DepThis, DepThisType, true, SourceLocation(),
SS.getWithLocInContext(Context), NULL,
- R.getLookupNameInfo(), &TList);
+ R.getLookupNameInfo(),
+ ULE->hasExplicitTemplateArgs() ? &TList : 0);
CallsUndergoingInstantiation.back()->setCallee(DepExpr);
} else {
// FIXME: we should be able to handle this case too. It is correct
@@ -1405,6 +1565,30 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
R.setLookupName(Corrected.getCorrection());
if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
+ if (Corrected.isOverloaded()) {
+ OverloadCandidateSet OCS(R.getNameLoc());
+ OverloadCandidateSet::iterator Best;
+ for (TypoCorrection::decl_iterator CD = Corrected.begin(),
+ CDEnd = Corrected.end();
+ CD != CDEnd; ++CD) {
+ if (FunctionTemplateDecl *FTD =
+ dyn_cast<FunctionTemplateDecl>(*CD))
+ AddTemplateOverloadCandidate(
+ FTD, DeclAccessPair::make(FTD, AS_none), ExplicitTemplateArgs,
+ Args, NumArgs, OCS);
+ else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*CD))
+ if (!ExplicitTemplateArgs || ExplicitTemplateArgs->size() == 0)
+ AddOverloadCandidate(FD, DeclAccessPair::make(FD, AS_none),
+ Args, NumArgs, OCS);
+ }
+ switch (OCS.BestViableFunction(*this, R.getNameLoc(), Best)) {
+ case OR_Success:
+ ND = Best->Function;
+ break;
+ default:
+ break;
+ }
+ }
R.addDecl(ND);
if (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)) {
if (SS.isEmpty())
@@ -1430,7 +1614,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// correction, but don't make it a fix-it since we're not going
// to recover well anyway.
if (SS.isEmpty())
- Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr;
+ Diag(R.getNameLoc(), diagnostic_suggest)
+ << Name << CorrectedQuotedStr;
else
Diag(R.getNameLoc(), diag::err_no_member_suggest)
<< Name << computeDeclContext(SS, false) << CorrectedQuotedStr
@@ -1467,96 +1652,12 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
return true;
}
-ObjCPropertyDecl *Sema::canSynthesizeProvisionalIvar(IdentifierInfo *II) {
- ObjCMethodDecl *CurMeth = getCurMethodDecl();
- ObjCInterfaceDecl *IDecl = CurMeth->getClassInterface();
- if (!IDecl)
- return 0;
- ObjCImplementationDecl *ClassImpDecl = IDecl->getImplementation();
- if (!ClassImpDecl)
- return 0;
- ObjCPropertyDecl *property = LookupPropertyDecl(IDecl, II);
- if (!property)
- return 0;
- if (ObjCPropertyImplDecl *PIDecl = ClassImpDecl->FindPropertyImplDecl(II))
- if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic ||
- PIDecl->getPropertyIvarDecl())
- return 0;
- return property;
-}
-
-bool Sema::canSynthesizeProvisionalIvar(ObjCPropertyDecl *Property) {
- ObjCMethodDecl *CurMeth = getCurMethodDecl();
- ObjCInterfaceDecl *IDecl = CurMeth->getClassInterface();
- if (!IDecl)
- return false;
- ObjCImplementationDecl *ClassImpDecl = IDecl->getImplementation();
- if (!ClassImpDecl)
- return false;
- if (ObjCPropertyImplDecl *PIDecl
- = ClassImpDecl->FindPropertyImplDecl(Property->getIdentifier()))
- if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic ||
- PIDecl->getPropertyIvarDecl())
- return false;
-
- return true;
-}
-
-ObjCIvarDecl *Sema::SynthesizeProvisionalIvar(LookupResult &Lookup,
- IdentifierInfo *II,
- SourceLocation NameLoc) {
- ObjCMethodDecl *CurMeth = getCurMethodDecl();
- bool LookForIvars;
- if (Lookup.empty())
- LookForIvars = true;
- else if (CurMeth->isClassMethod())
- LookForIvars = false;
- else
- LookForIvars = (Lookup.isSingleResult() &&
- Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod() &&
- (Lookup.getAsSingle<VarDecl>() != 0));
- if (!LookForIvars)
- return 0;
-
- ObjCInterfaceDecl *IDecl = CurMeth->getClassInterface();
- if (!IDecl)
- return 0;
- ObjCImplementationDecl *ClassImpDecl = IDecl->getImplementation();
- if (!ClassImpDecl)
- return 0;
- bool DynamicImplSeen = false;
- ObjCPropertyDecl *property = LookupPropertyDecl(IDecl, II);
- if (!property)
- return 0;
- if (ObjCPropertyImplDecl *PIDecl = ClassImpDecl->FindPropertyImplDecl(II)) {
- DynamicImplSeen =
- (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic);
- // property implementation has a designated ivar. No need to assume a new
- // one.
- if (!DynamicImplSeen && PIDecl->getPropertyIvarDecl())
- return 0;
- }
- if (!DynamicImplSeen) {
- QualType PropType = Context.getCanonicalType(property->getType());
- ObjCIvarDecl *Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl,
- NameLoc, NameLoc,
- II, PropType, /*Dinfo=*/0,
- ObjCIvarDecl::Private,
- (Expr *)0, true);
- ClassImpDecl->addDecl(Ivar);
- IDecl->makeDeclVisibleInContext(Ivar, false);
- property->setPropertyIvarDecl(Ivar);
- return Ivar;
- }
- return 0;
-}
-
ExprResult Sema::ActOnIdExpression(Scope *S,
CXXScopeSpec &SS,
UnqualifiedId &Id,
bool HasTrailingLParen,
- bool isAddressOfOperand) {
- assert(!(isAddressOfOperand && HasTrailingLParen) &&
+ bool IsAddressOfOperand) {
+ assert(!(IsAddressOfOperand && HasTrailingLParen) &&
"cannot be direct & operand and have a trailing lparen");
if (SS.isInvalid())
@@ -1598,7 +1699,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
}
if (DependentID)
- return ActOnDependentIdExpression(SS, NameInfo, isAddressOfOperand,
+ return ActOnDependentIdExpression(SS, NameInfo, IsAddressOfOperand,
TemplateArgs);
bool IvarLookupFollowUp = false;
@@ -1618,7 +1719,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
if (MemberOfUnknownSpecialization ||
(R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation))
- return ActOnDependentIdExpression(SS, NameInfo, isAddressOfOperand,
+ return ActOnDependentIdExpression(SS, NameInfo, IsAddressOfOperand,
TemplateArgs);
} else {
IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl());
@@ -1627,7 +1728,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
// If the result might be in a dependent base class, this is a dependent
// id-expression.
if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)
- return ActOnDependentIdExpression(SS, NameInfo, isAddressOfOperand,
+ return ActOnDependentIdExpression(SS, NameInfo, IsAddressOfOperand,
TemplateArgs);
// If this reference is in an Objective-C method, then we need to do
@@ -1640,19 +1741,6 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
if (Expr *Ex = E.takeAs<Expr>())
return Owned(Ex);
- // Synthesize ivars lazily.
- if (getLangOptions().ObjCDefaultSynthProperties &&
- getLangOptions().ObjCNonFragileABI2) {
- if (SynthesizeProvisionalIvar(R, II, NameLoc)) {
- if (const ObjCPropertyDecl *Property =
- canSynthesizeProvisionalIvar(II)) {
- Diag(NameLoc, diag::warn_synthesized_ivar_access) << II;
- Diag(Property->getLocation(), diag::note_property_declare);
- }
- return ActOnIdExpression(S, SS, Id, HasTrailingLParen,
- isAddressOfOperand);
- }
- }
// for further use, this must be set to false if in class method.
IvarLookupFollowUp = getCurMethodDecl()->isInstanceMethod();
}
@@ -1676,6 +1764,16 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
// If this name wasn't predeclared and if this is not a function
// call, diagnose the problem.
if (R.empty()) {
+
+ // In Microsoft mode, if we are inside a template class member function
+ // and we can't resolve an identifier then assume the identifier is type
+ // dependent. The goal is to postpone name lookup to instantiation time
+ // to be able to search into type dependent base classes.
+ if (getLangOptions().MicrosoftMode && CurContext->isDependentContext() &&
+ isa<CXXMethodDecl>(CurContext))
+ return ActOnDependentIdExpression(SS, NameInfo, IsAddressOfOperand,
+ TemplateArgs);
+
if (DiagnoseEmptyLookup(S, SS, R, CTC_Unknown))
return ExprError();
@@ -1688,7 +1786,10 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
if (ObjCIvarDecl *Ivar = R.getAsSingle<ObjCIvarDecl>()) {
R.clear();
ExprResult E(LookupInObjCMethod(R, S, Ivar->getIdentifier()));
- assert(E.isInvalid() || E.get());
+ // In a hopelessly buggy code, Objective-C instance variable
+ // lookup fails and no expression will be built to reference it.
+ if (!E.isInvalid() && !E.get())
+ return ExprError();
return move(E);
}
}
@@ -1723,7 +1824,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
// instance method.
if (!R.empty() && (*R.begin())->isCXXClassMember()) {
bool MightBeImplicitMember;
- if (!isAddressOfOperand)
+ if (!IsAddressOfOperand)
MightBeImplicitMember = true;
else if (!SS.isEmpty())
MightBeImplicitMember = false;
@@ -1950,7 +2051,7 @@ Sema::PerformObjectMemberConversion(Expr *From,
SourceRange FromRange = From->getSourceRange();
SourceLocation FromLoc = FromRange.getBegin();
- ExprValueKind VK = CastCategory(From);
+ ExprValueKind VK = From->getValueKind();
// C++ [class.member.lookup]p8:
// [...] Ambiguities can often be resolved by qualifying a name with its
@@ -2341,7 +2442,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
// If we're referring to a method with an __unknown_anytype
// result type, make the entire expression __unknown_anytype.
// This should only be possible with a type written directly.
- if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(VD->getType()))
+ if (const FunctionProtoType *proto
+ = dyn_cast<FunctionProtoType>(VD->getType()))
if (proto->getResultType() == Context.UnknownAnyTy) {
type = Context.UnknownAnyTy;
valueKind = VK_RValue;
@@ -2375,7 +2477,7 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
PredefinedExpr::IdentType IT;
switch (Kind) {
- default: assert(0 && "Unknown simple primary expr!");
+ default: llvm_unreachable("Unknown simple primary expr!");
case tok::kw___func__: IT = PredefinedExpr::Func; break; // [C99 6.4.2.2]
case tok::kw___FUNCTION__: IT = PredefinedExpr::Function; break;
case tok::kw___PRETTY_FUNCTION__: IT = PredefinedExpr::PrettyFunction; break;
@@ -2408,12 +2510,12 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
ExprResult Sema::ActOnCharacterConstant(const Token &Tok) {
llvm::SmallString<16> CharBuffer;
bool Invalid = false;
- llvm::StringRef ThisTok = PP.getSpelling(Tok, CharBuffer, &Invalid);
+ StringRef ThisTok = PP.getSpelling(Tok, CharBuffer, &Invalid);
if (Invalid)
return ExprError();
CharLiteralParser Literal(ThisTok.begin(), ThisTok.end(), Tok.getLocation(),
- PP);
+ PP, Tok.getKind());
if (Literal.hadError())
return ExprError();
@@ -2422,14 +2524,25 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok) {
Ty = Context.IntTy; // 'x' and L'x' -> int in C.
else if (Literal.isWide())
Ty = Context.WCharTy; // L'x' -> wchar_t in C++.
+ else if (Literal.isUTF16())
+ Ty = Context.Char16Ty; // u'x' -> char16_t in C++0x.
+ else if (Literal.isUTF32())
+ Ty = Context.Char32Ty; // U'x' -> char32_t in C++0x.
else if (Literal.isMultiChar())
Ty = Context.IntTy; // 'wxyz' -> int in C++.
else
Ty = Context.CharTy; // 'x' -> char in C++
- return Owned(new (Context) CharacterLiteral(Literal.getValue(),
- Literal.isWide(),
- Ty, Tok.getLocation()));
+ CharacterLiteral::CharacterKind Kind = CharacterLiteral::Ascii;
+ if (Literal.isWide())
+ Kind = CharacterLiteral::Wide;
+ else if (Literal.isUTF16())
+ Kind = CharacterLiteral::UTF16;
+ else if (Literal.isUTF32())
+ Kind = CharacterLiteral::UTF32;
+
+ return Owned(new (Context) CharacterLiteral(Literal.getValue(), Kind, Ty,
+ Tok.getLocation()));
}
ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
@@ -2437,7 +2550,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
// cannot have a trigraph, escaped newline, radix prefix, or type suffix.
if (Tok.getLength() == 1) {
const char Val = PP.getSpellingOfSingleCharacterNumericConstant(Tok);
- unsigned IntSize = Context.Target.getIntWidth();
+ unsigned IntSize = Context.getTargetInfo().getIntWidth();
return Owned(IntegerLiteral::Create(Context, llvm::APInt(IntSize, Val-'0'),
Context.IntTy, Tok.getLocation()));
}
@@ -2492,7 +2605,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
Diag(Tok.getLocation(), diagnostic)
<< Ty
- << llvm::StringRef(buffer.data(), buffer.size());
+ << StringRef(buffer.data(), buffer.size());
}
bool isExact = (result == APFloat::opOK);
@@ -2517,7 +2630,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
Diag(Tok.getLocation(), diag::ext_longlong);
// Get the value in the widest-possible width.
- llvm::APInt ResultVal(Context.Target.getIntMaxTWidth(), 0);
+ llvm::APInt ResultVal(Context.getTargetInfo().getIntMaxTWidth(), 0);
if (Literal.GetIntegerValue(ResultVal)) {
// If this value didn't fit into uintmax_t, warn and force to ull.
@@ -2537,7 +2650,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
unsigned Width = 0;
if (!Literal.isLong && !Literal.isLongLong) {
// Are int/unsigned possibilities?
- unsigned IntSize = Context.Target.getIntWidth();
+ unsigned IntSize = Context.getTargetInfo().getIntWidth();
// Does it fit in a unsigned int?
if (ResultVal.isIntN(IntSize)) {
@@ -2552,7 +2665,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
// Are long/unsigned long possibilities?
if (Ty.isNull() && !Literal.isLongLong) {
- unsigned LongSize = Context.Target.getLongWidth();
+ unsigned LongSize = Context.getTargetInfo().getLongWidth();
// Does it fit in a unsigned long?
if (ResultVal.isIntN(LongSize)) {
@@ -2567,7 +2680,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
// Finally, check long long if needed.
if (Ty.isNull()) {
- unsigned LongLongSize = Context.Target.getLongLongWidth();
+ unsigned LongLongSize = Context.getTargetInfo().getLongLongWidth();
// Does it fit in a unsigned long long?
if (ResultVal.isIntN(LongLongSize)) {
@@ -2575,7 +2688,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
// To be compatible with MSVC, hex integer literals ending with the
// LL or i64 suffix are always signed in Microsoft mode.
if (!Literal.isUnsigned && (ResultVal[LongLongSize-1] == 0 ||
- (getLangOptions().Microsoft && Literal.isLongLong)))
+ (getLangOptions().MicrosoftExt && Literal.isLongLong)))
Ty = Context.LongLongTy;
else if (AllowUnsigned)
Ty = Context.UnsignedLongLongTy;
@@ -2588,7 +2701,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
if (Ty.isNull()) {
Diag(Tok.getLocation(), diag::warn_integer_too_large_for_signed);
Ty = Context.UnsignedLongLongTy;
- Width = Context.Target.getLongLongWidth();
+ Width = Context.getTargetInfo().getLongLongWidth();
}
if (ResultVal.getBitWidth() != Width)
@@ -2605,8 +2718,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
return Owned(Res);
}
-ExprResult Sema::ActOnParenExpr(SourceLocation L,
- SourceLocation R, Expr *E) {
+ExprResult Sema::ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E) {
assert((E != 0) && "ActOnParenExpr() missing expr");
return Owned(new (Context) ParenExpr(L, R, E));
}
@@ -2672,9 +2784,9 @@ static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T,
/// expression. The logic mostly mirrors the type-based overload, but may modify
/// the expression as it completes the type for that expression through template
/// instantiation, etc.
-bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op,
+bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
UnaryExprOrTypeTrait ExprKind) {
- QualType ExprTy = Op->getType();
+ QualType ExprTy = E->getType();
// C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
// the result is the size of the referenced type."
@@ -2684,36 +2796,36 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op,
ExprTy = Ref->getPointeeType();
if (ExprKind == UETT_VecStep)
- return CheckVecStepTraitOperandType(*this, ExprTy, Op->getExprLoc(),
- Op->getSourceRange());
+ return CheckVecStepTraitOperandType(*this, ExprTy, E->getExprLoc(),
+ E->getSourceRange());
// Whitelist some types as extensions
- if (!CheckExtensionTraitOperandType(*this, ExprTy, Op->getExprLoc(),
- Op->getSourceRange(), ExprKind))
+ if (!CheckExtensionTraitOperandType(*this, ExprTy, E->getExprLoc(),
+ E->getSourceRange(), ExprKind))
return false;
- if (RequireCompleteExprType(Op,
+ if (RequireCompleteExprType(E,
PDiag(diag::err_sizeof_alignof_incomplete_type)
- << ExprKind << Op->getSourceRange(),
+ << ExprKind << E->getSourceRange(),
std::make_pair(SourceLocation(), PDiag(0))))
return true;
// Completeing the expression's type may have changed it.
- ExprTy = Op->getType();
+ ExprTy = E->getType();
if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>())
ExprTy = Ref->getPointeeType();
- if (CheckObjCTraitOperandConstraints(*this, ExprTy, Op->getExprLoc(),
- Op->getSourceRange(), ExprKind))
+ if (CheckObjCTraitOperandConstraints(*this, ExprTy, E->getExprLoc(),
+ E->getSourceRange(), ExprKind))
return true;
if (ExprKind == UETT_SizeOf) {
- if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(Op->IgnoreParens())) {
+ if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DeclRef->getFoundDecl())) {
QualType OType = PVD->getOriginalType();
QualType Type = PVD->getType();
if (Type->isPointerType() && OType->isArrayType()) {
- Diag(Op->getExprLoc(), diag::warn_sizeof_array_param)
+ Diag(E->getExprLoc(), diag::warn_sizeof_array_param)
<< Type << OType;
Diag(PVD->getLocation(), diag::note_declared_at);
}
@@ -2739,34 +2851,34 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op,
/// standard conversions are not applied to the operand of sizeof.
///
/// This policy is followed for all of the unary trait expressions.
-bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType exprType,
+bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType,
SourceLocation OpLoc,
SourceRange ExprRange,
UnaryExprOrTypeTrait ExprKind) {
- if (exprType->isDependentType())
+ if (ExprType->isDependentType())
return false;
// C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
// the result is the size of the referenced type."
// C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
// result shall be the alignment of the referenced type."
- if (const ReferenceType *Ref = exprType->getAs<ReferenceType>())
- exprType = Ref->getPointeeType();
+ if (const ReferenceType *Ref = ExprType->getAs<ReferenceType>())
+ ExprType = Ref->getPointeeType();
if (ExprKind == UETT_VecStep)
- return CheckVecStepTraitOperandType(*this, exprType, OpLoc, ExprRange);
+ return CheckVecStepTraitOperandType(*this, ExprType, OpLoc, ExprRange);
// Whitelist some types as extensions
- if (!CheckExtensionTraitOperandType(*this, exprType, OpLoc, ExprRange,
+ if (!CheckExtensionTraitOperandType(*this, ExprType, OpLoc, ExprRange,
ExprKind))
return false;
- if (RequireCompleteType(OpLoc, exprType,
+ if (RequireCompleteType(OpLoc, ExprType,
PDiag(diag::err_sizeof_alignof_incomplete_type)
<< ExprKind << ExprRange))
return true;
- if (CheckObjCTraitOperandConstraints(*this, exprType, OpLoc, ExprRange,
+ if (CheckObjCTraitOperandConstraints(*this, ExprType, OpLoc, ExprRange,
ExprKind))
return true;
@@ -2870,12 +2982,12 @@ Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
/// Note that the ArgRange is invalid if isType is false.
ExprResult
Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc,
- UnaryExprOrTypeTrait ExprKind, bool isType,
+ UnaryExprOrTypeTrait ExprKind, bool IsType,
void *TyOrEx, const SourceRange &ArgRange) {
// If error parsing type, ignore.
if (TyOrEx == 0) return ExprError();
- if (isType) {
+ if (IsType) {
TypeSourceInfo *TInfo;
(void) GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrEx), &TInfo);
return CreateUnaryExprOrTypeTraitExpr(TInfo, OpLoc, ExprKind, ArgRange);
@@ -2887,7 +2999,7 @@ Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc,
}
static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc,
- bool isReal) {
+ bool IsReal) {
if (V.get()->isTypeDependent())
return S.Context.DependentTy;
@@ -2911,12 +3023,12 @@ static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc,
if (PR.isInvalid()) return QualType();
if (PR.get() != V.get()) {
V = move(PR);
- return CheckRealImagOperand(S, V, Loc, isReal);
+ return CheckRealImagOperand(S, V, Loc, IsReal);
}
// Reject anything else.
S.Diag(Loc, diag::err_realimag_invalid_type) << V.get()->getType()
- << (isReal ? "__real" : "__imag");
+ << (IsReal ? "__real" : "__imag");
return QualType();
}
@@ -2927,7 +3039,7 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Kind, Expr *Input) {
UnaryOperatorKind Opc;
switch (Kind) {
- default: assert(0 && "Unknown unary op!");
+ default: llvm_unreachable("Unknown unary op!");
case tok::plusplus: Opc = UO_PostInc; break;
case tok::minusminus: Opc = UO_PostDec; break;
}
@@ -2967,7 +3079,7 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc,
ExprResult
Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
- Expr *Idx, SourceLocation RLoc) {
+ Expr *Idx, SourceLocation RLoc) {
Expr *LHSExp = Base;
Expr *RHSExp = Idx;
@@ -3190,7 +3302,8 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
FunctionDecl *FDecl,
const FunctionProtoType *Proto,
Expr **Args, unsigned NumArgs,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ bool IsExecConfig) {
// Bail out early if calling a builtin with custom typechecking.
// We don't need to do this in the
if (FDecl)
@@ -3202,14 +3315,29 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
// assignment, to the types of the corresponding parameter, ...
unsigned NumArgsInProto = Proto->getNumArgs();
bool Invalid = false;
+ unsigned MinArgs = FDecl ? FDecl->getMinRequiredArguments() : NumArgsInProto;
+ unsigned FnKind = Fn->getType()->isBlockPointerType()
+ ? 1 /* block */
+ : (IsExecConfig ? 3 /* kernel function (exec config) */
+ : 0 /* function */);
// If too few arguments are available (and we don't have default
// arguments for the remaining parameters), don't make the call.
if (NumArgs < NumArgsInProto) {
- if (!FDecl || NumArgs < FDecl->getMinRequiredArguments())
- return Diag(RParenLoc, diag::err_typecheck_call_too_few_args)
- << Fn->getType()->isBlockPointerType()
- << NumArgsInProto << NumArgs << Fn->getSourceRange();
+ if (NumArgs < MinArgs) {
+ Diag(RParenLoc, MinArgs == NumArgsInProto
+ ? diag::err_typecheck_call_too_few_args
+ : diag::err_typecheck_call_too_few_args_at_least)
+ << FnKind
+ << MinArgs << NumArgs << Fn->getSourceRange();
+
+ // Emit the location of the prototype.
+ if (FDecl && !FDecl->getBuiltinID() && !IsExecConfig)
+ Diag(FDecl->getLocStart(), diag::note_callee_decl)
+ << FDecl;
+
+ return true;
+ }
Call->setNumArgs(Context, NumArgsInProto);
}
@@ -3218,24 +3346,25 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
if (NumArgs > NumArgsInProto) {
if (!Proto->isVariadic()) {
Diag(Args[NumArgsInProto]->getLocStart(),
- diag::err_typecheck_call_too_many_args)
- << Fn->getType()->isBlockPointerType()
+ MinArgs == NumArgsInProto
+ ? diag::err_typecheck_call_too_many_args
+ : diag::err_typecheck_call_too_many_args_at_most)
+ << FnKind
<< NumArgsInProto << NumArgs << Fn->getSourceRange()
<< SourceRange(Args[NumArgsInProto]->getLocStart(),
Args[NumArgs-1]->getLocEnd());
// Emit the location of the prototype.
- if (FDecl && !FDecl->getBuiltinID())
- Diag(FDecl->getLocStart(),
- diag::note_typecheck_call_too_many_args)
- << FDecl;
+ if (FDecl && !FDecl->getBuiltinID() && !IsExecConfig)
+ Diag(FDecl->getLocStart(), diag::note_callee_decl)
+ << FDecl;
// This deletes the extra arguments.
Call->setNumArgs(Context, NumArgsInProto);
return true;
}
}
- llvm::SmallVector<Expr *, 8> AllArgs;
+ SmallVector<Expr *, 8> AllArgs;
VariadicCallType CallType =
Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply;
if (Fn->getType()->isBlockPointerType())
@@ -3258,7 +3387,7 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
const FunctionProtoType *Proto,
unsigned FirstProtoArg,
Expr **Args, unsigned NumArgs,
- llvm::SmallVector<Expr *, 8> &AllArgs,
+ SmallVector<Expr *, 8> &AllArgs,
VariadicCallType CallType) {
unsigned NumArgsInProto = Proto->getNumArgs();
unsigned NumArgsToCheck = NumArgs;
@@ -3307,6 +3436,12 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
Arg = ArgExpr.takeAs<Expr>();
}
+
+ // Check for array bounds violations for each argument to the call. This
+ // check only triggers warnings when the argument isn't a more complex Expr
+ // with its own checking, such as a BinaryOperator.
+ CheckArrayAccess(Arg);
+
AllArgs.push_back(Arg);
}
@@ -3330,11 +3465,16 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
// Otherwise do argument promotion, (C99 6.5.2.2p7).
} else {
for (unsigned i = ArgIx; i != NumArgs; ++i) {
- ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], CallType, FDecl);
+ ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], CallType,
+ FDecl);
Invalid |= Arg.isInvalid();
AllArgs.push_back(Arg.take());
}
}
+
+ // Check for array bounds violations.
+ for (unsigned i = ArgIx; i != NumArgs; ++i)
+ CheckArrayAccess(Args[i]);
}
return Invalid;
}
@@ -3348,16 +3488,16 @@ static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn);
/// locations.
ExprResult
Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
- MultiExprArg args, SourceLocation RParenLoc,
- Expr *ExecConfig) {
- unsigned NumArgs = args.size();
+ MultiExprArg ArgExprs, SourceLocation RParenLoc,
+ Expr *ExecConfig, bool IsExecConfig) {
+ unsigned NumArgs = ArgExprs.size();
// Since this might be a postfix expression, get rid of ParenListExprs.
ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Fn);
if (Result.isInvalid()) return ExprError();
Fn = Result.take();
- Expr **Args = args.release();
+ Expr **Args = ArgExprs.release();
if (getLangOptions().CPlusPlus) {
// If this is a pseudo-destructor expression, build the call immediately.
@@ -3419,8 +3559,8 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
if (Fn->getType() == Context.OverloadTy) {
OverloadExpr::FindResult find = OverloadExpr::find(Fn);
- // We aren't supposed to apply this logic if there's an '&' involved.
- if (!find.IsAddressOfOperand) {
+ // We aren't supposed to apply this logic for if there's an '&' involved.
+ if (!find.HasFormOfMemberPointer) {
OverloadExpr *ovl = find.Expression;
if (isa<UnresolvedLookupExpr>(ovl)) {
UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(ovl);
@@ -3448,12 +3588,12 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl();
return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, Args, NumArgs, RParenLoc,
- ExecConfig);
+ ExecConfig, IsExecConfig);
}
ExprResult
Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc,
- MultiExprArg execConfig, SourceLocation GGGLoc) {
+ MultiExprArg ExecConfig, SourceLocation GGGLoc) {
FunctionDecl *ConfigDecl = Context.getcudaConfigureCallDecl();
if (!ConfigDecl)
return ExprError(Diag(LLLLoc, diag::err_undeclared_var_use)
@@ -3463,27 +3603,29 @@ Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc,
DeclRefExpr *ConfigDR = new (Context) DeclRefExpr(
ConfigDecl, ConfigQTy, VK_LValue, LLLLoc);
- return ActOnCallExpr(S, ConfigDR, LLLLoc, execConfig, GGGLoc, 0);
+ return ActOnCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, 0,
+ /*IsExecConfig=*/true);
}
/// ActOnAsTypeExpr - create a new asType (bitcast) from the arguments.
///
/// __builtin_astype( value, dst type )
///
-ExprResult Sema::ActOnAsTypeExpr(Expr *expr, ParsedType destty,
+ExprResult Sema::ActOnAsTypeExpr(Expr *E, ParsedType ParsedDestTy,
SourceLocation BuiltinLoc,
SourceLocation RParenLoc) {
ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary;
- QualType DstTy = GetTypeFromParser(destty);
- QualType SrcTy = expr->getType();
+ QualType DstTy = GetTypeFromParser(ParsedDestTy);
+ QualType SrcTy = E->getType();
if (Context.getTypeSize(DstTy) != Context.getTypeSize(SrcTy))
return ExprError(Diag(BuiltinLoc,
diag::err_invalid_astype_of_different_size)
<< DstTy
<< SrcTy
- << expr->getSourceRange());
- return Owned(new (Context) AsTypeExpr(expr, DstTy, VK, OK, BuiltinLoc, RParenLoc));
+ << E->getSourceRange());
+ return Owned(new (Context) AsTypeExpr(E, DstTy, VK, OK, BuiltinLoc,
+ RParenLoc));
}
/// BuildResolvedCallExpr - Build a call to a resolved expression,
@@ -3497,7 +3639,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
SourceLocation RParenLoc,
- Expr *Config) {
+ Expr *Config, bool IsExecConfig) {
FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
// Promote the function operand.
@@ -3567,6 +3709,11 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
if (!FuncT->getResultType()->isVoidType())
return ExprError(Diag(LParenLoc, diag::err_kern_type_not_void_return)
<< Fn->getType() << Fn->getSourceRange());
+ } else {
+ // CUDA: Calls to global functions must be configured
+ if (FDecl && FDecl->hasAttr<CUDAGlobalAttr>())
+ return ExprError(Diag(LParenLoc, diag::err_global_call_not_config)
+ << FDecl->getName() << Fn->getSourceRange());
}
}
@@ -3582,7 +3729,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FuncT)) {
if (ConvertArgumentsForCall(TheCall, Fn, FDecl, Proto, Args, NumArgs,
- RParenLoc))
+ RParenLoc, IsExecConfig))
return ExprError();
} else {
assert(isa<FunctionNoProtoType>(FuncT) && "Unknown FunctionType!");
@@ -3682,23 +3829,23 @@ Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, ParsedType Ty,
ExprResult
Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
- SourceLocation RParenLoc, Expr *literalExpr) {
+ SourceLocation RParenLoc, Expr *LiteralExpr) {
QualType literalType = TInfo->getType();
if (literalType->isArrayType()) {
if (RequireCompleteType(LParenLoc, Context.getBaseElementType(literalType),
PDiag(diag::err_illegal_decl_array_incomplete_type)
<< SourceRange(LParenLoc,
- literalExpr->getSourceRange().getEnd())))
+ LiteralExpr->getSourceRange().getEnd())))
return ExprError();
if (literalType->isVariableArrayType())
return ExprError(Diag(LParenLoc, diag::err_variable_object_no_init)
- << SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd()));
+ << SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd()));
} else if (!literalType->isDependentType() &&
RequireCompleteType(LParenLoc, literalType,
PDiag(diag::err_typecheck_decl_incomplete_type)
<< SourceRange(LParenLoc,
- literalExpr->getSourceRange().getEnd())))
+ LiteralExpr->getSourceRange().getEnd())))
return ExprError();
InitializedEntity Entity
@@ -3706,17 +3853,17 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
InitializationKind Kind
= InitializationKind::CreateCStyleCast(LParenLoc,
SourceRange(LParenLoc, RParenLoc));
- InitializationSequence InitSeq(*this, Entity, Kind, &literalExpr, 1);
+ InitializationSequence InitSeq(*this, Entity, Kind, &LiteralExpr, 1);
ExprResult Result = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(*this, &literalExpr, 1),
+ MultiExprArg(*this, &LiteralExpr, 1),
&literalType);
if (Result.isInvalid())
return ExprError();
- literalExpr = Result.get();
+ LiteralExpr = Result.get();
bool isFileScope = getCurFunctionOrMethodDecl() == 0;
if (isFileScope) { // 6.5.2.5p3
- if (CheckForConstantInitializer(literalExpr, literalType))
+ if (CheckForConstantInitializer(LiteralExpr, literalType))
return ExprError();
}
@@ -3725,14 +3872,14 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
return MaybeBindToTemporary(
new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType,
- VK, literalExpr, isFileScope));
+ VK, LiteralExpr, isFileScope));
}
ExprResult
-Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist,
+Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
SourceLocation RBraceLoc) {
- unsigned NumInit = initlist.size();
- Expr **InitList = initlist.release();
+ unsigned NumInit = InitArgList.size();
+ Expr **InitList = InitArgList.release();
// Semantic analysis for initializers is done by ActOnDeclarator() and
// CheckInitializer() - it requires knowledge of the object being intialized.
@@ -3743,27 +3890,68 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist,
return Owned(E);
}
+/// Do an explicit extend of the given block pointer if we're in ARC.
+static void maybeExtendBlockObject(Sema &S, ExprResult &E) {
+ assert(E.get()->getType()->isBlockPointerType());
+ assert(E.get()->isRValue());
+
+ // Only do this in an r-value context.
+ if (!S.getLangOptions().ObjCAutoRefCount) return;
+
+ E = ImplicitCastExpr::Create(S.Context, E.get()->getType(),
+ CK_ARCExtendBlockObject, E.get(),
+ /*base path*/ 0, VK_RValue);
+ S.ExprNeedsCleanups = true;
+}
+
+/// Prepare a conversion of the given expression to an ObjC object
+/// pointer type.
+CastKind Sema::PrepareCastToObjCObjectPointer(ExprResult &E) {
+ QualType type = E.get()->getType();
+ if (type->isObjCObjectPointerType()) {
+ return CK_BitCast;
+ } else if (type->isBlockPointerType()) {
+ maybeExtendBlockObject(*this, E);
+ return CK_BlockPointerToObjCPointerCast;
+ } else {
+ assert(type->isPointerType());
+ return CK_CPointerToObjCPointerCast;
+ }
+}
+
/// Prepares for a scalar cast, performing all the necessary stages
/// except the final cast and returning the kind required.
-static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) {
+CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
// Both Src and Dest are scalar types, i.e. arithmetic or pointer.
// Also, callers should have filtered out the invalid cases with
// pointers. Everything else should be possible.
QualType SrcTy = Src.get()->getType();
- if (S.Context.hasSameUnqualifiedType(SrcTy, DestTy))
+ if (Context.hasSameUnqualifiedType(SrcTy, DestTy))
return CK_NoOp;
- switch (SrcTy->getScalarTypeKind()) {
+ switch (Type::ScalarTypeKind SrcKind = SrcTy->getScalarTypeKind()) {
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
- case Type::STK_Pointer:
+ case Type::STK_CPointer:
+ case Type::STK_BlockPointer:
+ case Type::STK_ObjCObjectPointer:
switch (DestTy->getScalarTypeKind()) {
- case Type::STK_Pointer:
- return DestTy->isObjCObjectPointerType() ?
- CK_AnyPointerToObjCPointerCast :
- CK_BitCast;
+ case Type::STK_CPointer:
+ return CK_BitCast;
+ case Type::STK_BlockPointer:
+ return (SrcKind == Type::STK_BlockPointer
+ ? CK_BitCast : CK_AnyPointerToBlockPointerCast);
+ case Type::STK_ObjCObjectPointer:
+ if (SrcKind == Type::STK_ObjCObjectPointer)
+ return CK_BitCast;
+ else if (SrcKind == Type::STK_CPointer)
+ return CK_CPointerToObjCPointerCast;
+ else {
+ maybeExtendBlockObject(*this, Src);
+ return CK_BlockPointerToObjCPointerCast;
+ }
case Type::STK_Bool:
return CK_PointerToBoolean;
case Type::STK_Integral:
@@ -3779,8 +3967,11 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) {
case Type::STK_Bool: // casting from bool is like casting from an integer
case Type::STK_Integral:
switch (DestTy->getScalarTypeKind()) {
- case Type::STK_Pointer:
- if (Src.get()->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull))
+ case Type::STK_CPointer:
+ case Type::STK_ObjCObjectPointer:
+ case Type::STK_BlockPointer:
+ if (Src.get()->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull))
return CK_NullToPointer;
return CK_IntegralToPointer;
case Type::STK_Bool:
@@ -3790,12 +3981,14 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) {
case Type::STK_Floating:
return CK_IntegralToFloating;
case Type::STK_IntegralComplex:
- Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(),
- CK_IntegralCast);
+ Src = ImpCastExprToType(Src.take(),
+ DestTy->castAs<ComplexType>()->getElementType(),
+ CK_IntegralCast);
return CK_IntegralRealToComplex;
case Type::STK_FloatingComplex:
- Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(),
- CK_IntegralToFloating);
+ Src = ImpCastExprToType(Src.take(),
+ DestTy->castAs<ComplexType>()->getElementType(),
+ CK_IntegralToFloating);
return CK_FloatingRealToComplex;
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
@@ -3811,14 +4004,18 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) {
case Type::STK_Integral:
return CK_FloatingToIntegral;
case Type::STK_FloatingComplex:
- Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(),
- CK_FloatingCast);
+ Src = ImpCastExprToType(Src.take(),
+ DestTy->castAs<ComplexType>()->getElementType(),
+ CK_FloatingCast);
return CK_FloatingRealToComplex;
case Type::STK_IntegralComplex:
- Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(),
- CK_FloatingToIntegral);
+ Src = ImpCastExprToType(Src.take(),
+ DestTy->castAs<ComplexType>()->getElementType(),
+ CK_FloatingToIntegral);
return CK_IntegralRealToComplex;
- case Type::STK_Pointer:
+ case Type::STK_CPointer:
+ case Type::STK_ObjCObjectPointer:
+ case Type::STK_BlockPointer:
llvm_unreachable("valid float->pointer cast?");
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
@@ -3832,19 +4029,22 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) {
case Type::STK_IntegralComplex:
return CK_FloatingComplexToIntegralComplex;
case Type::STK_Floating: {
- QualType ET = SrcTy->getAs<ComplexType>()->getElementType();
- if (S.Context.hasSameType(ET, DestTy))
+ QualType ET = SrcTy->castAs<ComplexType>()->getElementType();
+ if (Context.hasSameType(ET, DestTy))
return CK_FloatingComplexToReal;
- Src = S.ImpCastExprToType(Src.take(), ET, CK_FloatingComplexToReal);
+ Src = ImpCastExprToType(Src.take(), ET, CK_FloatingComplexToReal);
return CK_FloatingCast;
}
case Type::STK_Bool:
return CK_FloatingComplexToBoolean;
case Type::STK_Integral:
- Src = S.ImpCastExprToType(Src.take(), SrcTy->getAs<ComplexType>()->getElementType(),
- CK_FloatingComplexToReal);
+ Src = ImpCastExprToType(Src.take(),
+ SrcTy->castAs<ComplexType>()->getElementType(),
+ CK_FloatingComplexToReal);
return CK_FloatingToIntegral;
- case Type::STK_Pointer:
+ case Type::STK_CPointer:
+ case Type::STK_ObjCObjectPointer:
+ case Type::STK_BlockPointer:
llvm_unreachable("valid complex float->pointer cast?");
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
@@ -3858,19 +4058,22 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) {
case Type::STK_IntegralComplex:
return CK_IntegralComplexCast;
case Type::STK_Integral: {
- QualType ET = SrcTy->getAs<ComplexType>()->getElementType();
- if (S.Context.hasSameType(ET, DestTy))
+ QualType ET = SrcTy->castAs<ComplexType>()->getElementType();
+ if (Context.hasSameType(ET, DestTy))
return CK_IntegralComplexToReal;
- Src = S.ImpCastExprToType(Src.take(), ET, CK_IntegralComplexToReal);
+ Src = ImpCastExprToType(Src.take(), ET, CK_IntegralComplexToReal);
return CK_IntegralCast;
}
case Type::STK_Bool:
return CK_IntegralComplexToBoolean;
case Type::STK_Floating:
- Src = S.ImpCastExprToType(Src.take(), SrcTy->getAs<ComplexType>()->getElementType(),
- CK_IntegralComplexToReal);
+ Src = ImpCastExprToType(Src.take(),
+ SrcTy->castAs<ComplexType>()->getElementType(),
+ CK_IntegralComplexToReal);
return CK_IntegralToFloating;
- case Type::STK_Pointer:
+ case Type::STK_CPointer:
+ case Type::STK_ObjCObjectPointer:
+ case Type::STK_BlockPointer:
llvm_unreachable("valid complex int->pointer cast?");
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
@@ -3879,193 +4082,6 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) {
}
llvm_unreachable("Unhandled scalar cast");
- return CK_BitCast;
-}
-
-/// CheckCastTypes - Check type constraints for casting between types.
-ExprResult Sema::CheckCastTypes(SourceLocation CastStartLoc, SourceRange TyR,
- QualType castType, Expr *castExpr,
- CastKind& Kind, ExprValueKind &VK,
- CXXCastPath &BasePath, bool FunctionalStyle) {
- if (castExpr->getType() == Context.UnknownAnyTy)
- return checkUnknownAnyCast(TyR, castType, castExpr, Kind, VK, BasePath);
-
- if (getLangOptions().CPlusPlus)
- return CXXCheckCStyleCast(SourceRange(CastStartLoc,
- castExpr->getLocEnd()),
- castType, VK, castExpr, Kind, BasePath,
- FunctionalStyle);
-
- assert(!castExpr->getType()->isPlaceholderType());
-
- // We only support r-value casts in C.
- VK = VK_RValue;
-
- // C99 6.5.4p2: the cast type needs to be void or scalar and the expression
- // type needs to be scalar.
- if (castType->isVoidType()) {
- // We don't necessarily do lvalue-to-rvalue conversions on this.
- ExprResult castExprRes = IgnoredValueConversions(castExpr);
- if (castExprRes.isInvalid())
- return ExprError();
- castExpr = castExprRes.take();
-
- // Cast to void allows any expr type.
- Kind = CK_ToVoid;
- return Owned(castExpr);
- }
-
- ExprResult castExprRes = DefaultFunctionArrayLvalueConversion(castExpr);
- if (castExprRes.isInvalid())
- return ExprError();
- castExpr = castExprRes.take();
-
- if (RequireCompleteType(TyR.getBegin(), castType,
- diag::err_typecheck_cast_to_incomplete))
- return ExprError();
-
- if (!castType->isScalarType() && !castType->isVectorType()) {
- if (Context.hasSameUnqualifiedType(castType, castExpr->getType()) &&
- (castType->isStructureType() || castType->isUnionType())) {
- // GCC struct/union extension: allow cast to self.
- // FIXME: Check that the cast destination type is complete.
- Diag(TyR.getBegin(), diag::ext_typecheck_cast_nonscalar)
- << castType << castExpr->getSourceRange();
- Kind = CK_NoOp;
- return Owned(castExpr);
- }
-
- if (castType->isUnionType()) {
- // GCC cast to union extension
- RecordDecl *RD = castType->getAs<RecordType>()->getDecl();
- RecordDecl::field_iterator Field, FieldEnd;
- for (Field = RD->field_begin(), FieldEnd = RD->field_end();
- Field != FieldEnd; ++Field) {
- if (Context.hasSameUnqualifiedType(Field->getType(),
- castExpr->getType()) &&
- !Field->isUnnamedBitfield()) {
- Diag(TyR.getBegin(), diag::ext_typecheck_cast_to_union)
- << castExpr->getSourceRange();
- break;
- }
- }
- if (Field == FieldEnd) {
- Diag(TyR.getBegin(), diag::err_typecheck_cast_to_union_no_type)
- << castExpr->getType() << castExpr->getSourceRange();
- return ExprError();
- }
- Kind = CK_ToUnion;
- return Owned(castExpr);
- }
-
- // Reject any other conversions to non-scalar types.
- Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar)
- << castType << castExpr->getSourceRange();
- return ExprError();
- }
-
- // The type we're casting to is known to be a scalar or vector.
-
- // Require the operand to be a scalar or vector.
- if (!castExpr->getType()->isScalarType() &&
- !castExpr->getType()->isVectorType()) {
- Diag(castExpr->getLocStart(),
- diag::err_typecheck_expect_scalar_operand)
- << castExpr->getType() << castExpr->getSourceRange();
- return ExprError();
- }
-
- if (castType->isExtVectorType())
- return CheckExtVectorCast(TyR, castType, castExpr, Kind);
-
- if (castType->isVectorType()) {
- if (castType->getAs<VectorType>()->getVectorKind() ==
- VectorType::AltiVecVector &&
- (castExpr->getType()->isIntegerType() ||
- castExpr->getType()->isFloatingType())) {
- Kind = CK_VectorSplat;
- return Owned(castExpr);
- } else if (CheckVectorCast(TyR, castType, castExpr->getType(), Kind)) {
- return ExprError();
- } else
- return Owned(castExpr);
- }
- if (castExpr->getType()->isVectorType()) {
- if (CheckVectorCast(TyR, castExpr->getType(), castType, Kind))
- return ExprError();
- else
- return Owned(castExpr);
- }
-
- // The source and target types are both scalars, i.e.
- // - arithmetic types (fundamental, enum, and complex)
- // - all kinds of pointers
- // Note that member pointers were filtered out with C++, above.
-
- if (isa<ObjCSelectorExpr>(castExpr)) {
- Diag(castExpr->getLocStart(), diag::err_cast_selector_expr);
- return ExprError();
- }
-
- // If either type is a pointer, the other type has to be either an
- // integer or a pointer.
- QualType castExprType = castExpr->getType();
- if (!castType->isArithmeticType()) {
- if (!castExprType->isIntegralType(Context) &&
- castExprType->isArithmeticType()) {
- Diag(castExpr->getLocStart(),
- diag::err_cast_pointer_from_non_pointer_int)
- << castExprType << castExpr->getSourceRange();
- return ExprError();
- }
- } else if (!castExpr->getType()->isArithmeticType()) {
- if (!castType->isIntegralType(Context) && castType->isArithmeticType()) {
- Diag(castExpr->getLocStart(), diag::err_cast_pointer_to_non_pointer_int)
- << castType << castExpr->getSourceRange();
- return ExprError();
- }
- }
-
- if (getLangOptions().ObjCAutoRefCount) {
- // Diagnose problems with Objective-C casts involving lifetime qualifiers.
- CheckObjCARCConversion(SourceRange(CastStartLoc, castExpr->getLocEnd()),
- castType, castExpr, CCK_CStyleCast);
-
- if (const PointerType *CastPtr = castType->getAs<PointerType>()) {
- if (const PointerType *ExprPtr = castExprType->getAs<PointerType>()) {
- Qualifiers CastQuals = CastPtr->getPointeeType().getQualifiers();
- Qualifiers ExprQuals = ExprPtr->getPointeeType().getQualifiers();
- if (CastPtr->getPointeeType()->isObjCLifetimeType() &&
- ExprPtr->getPointeeType()->isObjCLifetimeType() &&
- !CastQuals.compatiblyIncludesObjCLifetime(ExprQuals)) {
- Diag(castExpr->getLocStart(),
- diag::err_typecheck_incompatible_ownership)
- << castExprType << castType << AA_Casting
- << castExpr->getSourceRange();
-
- return ExprError();
- }
- }
- }
- else if (!CheckObjCARCUnavailableWeakConversion(castType, castExprType)) {
- Diag(castExpr->getLocStart(),
- diag::err_arc_convesion_of_weak_unavailable) << 1
- << castExprType << castType
- << castExpr->getSourceRange();
- return ExprError();
- }
- }
-
- castExprRes = Owned(castExpr);
- Kind = PrepareScalarCast(*this, castExprRes, castType);
- if (castExprRes.isInvalid())
- return ExprError();
- castExpr = castExprRes.take();
-
- if (Kind == CK_BitCast)
- CheckCastAlign(castExpr, castType, TyR);
-
- return Owned(castExpr);
}
bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty,
@@ -4096,8 +4112,12 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy,
// If SrcTy is a VectorType, the total size must match to explicitly cast to
// an ExtVectorType.
+ // In OpenCL, casts between vectors of different types are not allowed.
+ // (See OpenCL 6.2).
if (SrcTy->isVectorType()) {
- if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy)) {
+ if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy)
+ || (getLangOptions().OpenCL &&
+ (DestTy.getCanonicalType() != SrcTy.getCanonicalType()))) {
Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors)
<< DestTy << SrcTy << R;
return ExprError();
@@ -4116,7 +4136,7 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy,
QualType DestElemTy = DestTy->getAs<ExtVectorType>()->getElementType();
ExprResult CastExprRes = Owned(CastExpr);
- CastKind CK = PrepareScalarCast(*this, CastExprRes, DestElemTy);
+ CastKind CK = PrepareScalarCast(CastExprRes, DestElemTy);
if (CastExprRes.isInvalid())
return ExprError();
CastExpr = ImpCastExprToType(CastExprRes.take(), DestElemTy, CK).take();
@@ -4128,11 +4148,11 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy,
ExprResult
Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
Declarator &D, ParsedType &Ty,
- SourceLocation RParenLoc, Expr *castExpr) {
- assert(!D.isInvalidType() && (castExpr != 0) &&
+ SourceLocation RParenLoc, Expr *CastExpr) {
+ assert(!D.isInvalidType() && (CastExpr != 0) &&
"ActOnCastExpr(): missing type or expr");
- TypeSourceInfo *castTInfo = GetTypeForDeclaratorCast(D, castExpr->getType());
+ TypeSourceInfo *castTInfo = GetTypeForDeclaratorCast(D, CastExpr->getType());
if (D.isInvalidType())
return ExprError();
@@ -4141,6 +4161,8 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
CheckExtraCXXDefaultArguments(D);
}
+ checkUnusedDeclAttributes(D);
+
QualType castType = castTInfo->getType();
Ty = CreateParsedType(castType, castTInfo);
@@ -4148,9 +4170,10 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
// Check for an altivec or OpenCL literal,
// i.e. all the elements are integer constants.
- ParenExpr *PE = dyn_cast<ParenExpr>(castExpr);
- ParenListExpr *PLE = dyn_cast<ParenListExpr>(castExpr);
- if (getLangOptions().AltiVec && castType->isVectorType() && (PE || PLE)) {
+ ParenExpr *PE = dyn_cast<ParenExpr>(CastExpr);
+ ParenListExpr *PLE = dyn_cast<ParenListExpr>(CastExpr);
+ if ((getLangOptions().AltiVec || getLangOptions().OpenCL)
+ && castType->isVectorType() && (PE || PLE)) {
if (PLE && PLE->getNumExprs() == 0) {
Diag(PLE->getExprLoc(), diag::err_altivec_empty_initializer);
return ExprError();
@@ -4167,37 +4190,18 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
// If this is a vector initializer, '(' type ')' '(' init, ..., init ')'
// then handle it as such.
if (isVectorLiteral)
- return BuildVectorLiteral(LParenLoc, RParenLoc, castExpr, castTInfo);
+ return BuildVectorLiteral(LParenLoc, RParenLoc, CastExpr, castTInfo);
// If the Expr being casted is a ParenListExpr, handle it specially.
// This is not an AltiVec-style cast, so turn the ParenListExpr into a
// sequence of BinOp comma operators.
- if (isa<ParenListExpr>(castExpr)) {
- ExprResult Result = MaybeConvertParenListExprToParenExpr(S, castExpr);
+ if (isa<ParenListExpr>(CastExpr)) {
+ ExprResult Result = MaybeConvertParenListExprToParenExpr(S, CastExpr);
if (Result.isInvalid()) return ExprError();
- castExpr = Result.take();
+ CastExpr = Result.take();
}
- return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, castExpr);
-}
-
-ExprResult
-Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty,
- SourceLocation RParenLoc, Expr *castExpr) {
- CastKind Kind = CK_Invalid;
- ExprValueKind VK = VK_RValue;
- CXXCastPath BasePath;
- ExprResult CastResult =
- CheckCastTypes(LParenLoc, SourceRange(LParenLoc, RParenLoc), Ty->getType(),
- castExpr, Kind, VK, BasePath);
- if (CastResult.isInvalid())
- return ExprError();
- castExpr = CastResult.take();
-
- return Owned(CStyleCastExpr::Create(Context,
- Ty->getType().getNonLValueExprType(Context),
- VK, Kind, castExpr, &BasePath, Ty,
- LParenLoc, RParenLoc));
+ return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, CastExpr);
}
ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
@@ -4221,7 +4225,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
QualType Ty = TInfo->getType();
assert(Ty->isVectorType() && "Expected vector type");
- llvm::SmallVector<Expr *, 8> initExprs;
+ SmallVector<Expr *, 8> initExprs;
const VectorType *VTy = Ty->getAs<VectorType>();
unsigned numElems = Ty->getAs<VectorType>()->getNumElements();
@@ -4237,7 +4241,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
ExprResult Literal = Owned(exprs[0]);
Literal = ImpCastExprToType(Literal.take(), ElemTy,
- PrepareScalarCast(*this, Literal, ElemTy));
+ PrepareScalarCast(Literal, ElemTy));
return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take());
}
else if (numExprs < numElems) {
@@ -4258,7 +4262,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
ExprResult Literal = Owned(exprs[0]);
Literal = ImpCastExprToType(Literal.take(), ElemTy,
- PrepareScalarCast(*this, Literal, ElemTy));
+ PrepareScalarCast(Literal, ElemTy));
return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take());
}
@@ -4277,10 +4281,10 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
/// This is not an AltiVec-style cast, so turn the ParenListExpr into a sequence
/// of comma binary operators.
ExprResult
-Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *expr) {
- ParenListExpr *E = dyn_cast<ParenListExpr>(expr);
+Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *OrigExpr) {
+ ParenListExpr *E = dyn_cast<ParenListExpr>(OrigExpr);
if (!E)
- return Owned(expr);
+ return Owned(OrigExpr);
ExprResult Result(E->getExpr(0));
@@ -4294,8 +4298,8 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *expr) {
}
ExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L,
- SourceLocation R,
- MultiExprArg Val) {
+ SourceLocation R,
+ MultiExprArg Val) {
unsigned nexprs = Val.size();
Expr **exprs = reinterpret_cast<Expr**>(Val.release());
assert((exprs != 0) && "ActOnParenOrParenListExpr() missing expr list");
@@ -4309,18 +4313,19 @@ ExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L,
}
/// \brief Emit a specialized diagnostic when one expression is a null pointer
-/// constant and the other is not a pointer.
-bool Sema::DiagnoseConditionalForNull(Expr *LHS, Expr *RHS,
+/// constant and the other is not a pointer. Returns true if a diagnostic is
+/// emitted.
+bool Sema::DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr,
SourceLocation QuestionLoc) {
- Expr *NullExpr = LHS;
- Expr *NonPointerExpr = RHS;
+ Expr *NullExpr = LHSExpr;
+ Expr *NonPointerExpr = RHSExpr;
Expr::NullPointerConstantKind NullKind =
NullExpr->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNotNull);
if (NullKind == Expr::NPCK_NotNull) {
- NullExpr = RHS;
- NonPointerExpr = LHS;
+ NullExpr = RHSExpr;
+ NonPointerExpr = LHSExpr;
NullKind =
NullExpr->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNotNull);
@@ -4345,20 +4350,228 @@ bool Sema::DiagnoseConditionalForNull(Expr *LHS, Expr *RHS,
return true;
}
-/// Note that lhs is not null here, even if this is the gnu "x ?: y" extension.
-/// In that case, lhs = cond.
+/// \brief Return false if the condition expression is valid, true otherwise.
+static bool checkCondition(Sema &S, Expr *Cond) {
+ QualType CondTy = Cond->getType();
+
+ // 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.
+ if (S.getLangOptions().OpenCL && CondTy->isVectorType())
+ return false;
+
+ // Emit the proper error message.
+ S.Diag(Cond->getLocStart(), S.getLangOptions().OpenCL ?
+ diag::err_typecheck_cond_expect_scalar :
+ diag::err_typecheck_cond_expect_scalar_or_vector)
+ << CondTy;
+ return true;
+}
+
+/// \brief Return false if the two expressions can be converted to a vector,
+/// true otherwise
+static bool checkConditionalConvertScalarsToVectors(Sema &S, ExprResult &LHS,
+ ExprResult &RHS,
+ QualType CondTy) {
+ // Both operands should be of scalar type.
+ if (!LHS.get()->getType()->isScalarType()) {
+ S.Diag(LHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar)
+ << CondTy;
+ return true;
+ }
+ if (!RHS.get()->getType()->isScalarType()) {
+ S.Diag(RHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar)
+ << CondTy;
+ return true;
+ }
+
+ // Implicity convert these scalars to the type of the condition.
+ LHS = S.ImpCastExprToType(LHS.take(), CondTy, CK_IntegralCast);
+ RHS = S.ImpCastExprToType(RHS.take(), CondTy, CK_IntegralCast);
+ return false;
+}
+
+/// \brief Handle when one or both operands are void type.
+static QualType checkConditionalVoidType(Sema &S, ExprResult &LHS,
+ ExprResult &RHS) {
+ Expr *LHSExpr = LHS.get();
+ Expr *RHSExpr = RHS.get();
+
+ if (!LHSExpr->getType()->isVoidType())
+ S.Diag(RHSExpr->getLocStart(), diag::ext_typecheck_cond_one_void)
+ << RHSExpr->getSourceRange();
+ if (!RHSExpr->getType()->isVoidType())
+ S.Diag(LHSExpr->getLocStart(), diag::ext_typecheck_cond_one_void)
+ << LHSExpr->getSourceRange();
+ LHS = S.ImpCastExprToType(LHS.take(), S.Context.VoidTy, CK_ToVoid);
+ RHS = S.ImpCastExprToType(RHS.take(), S.Context.VoidTy, CK_ToVoid);
+ return S.Context.VoidTy;
+}
+
+/// \brief Return false if the NullExpr can be promoted to PointerTy,
+/// true otherwise.
+static bool checkConditionalNullPointer(Sema &S, ExprResult &NullExpr,
+ QualType PointerTy) {
+ if ((!PointerTy->isAnyPointerType() && !PointerTy->isBlockPointerType()) ||
+ !NullExpr.get()->isNullPointerConstant(S.Context,
+ Expr::NPC_ValueDependentIsNull))
+ return true;
+
+ NullExpr = S.ImpCastExprToType(NullExpr.take(), PointerTy, CK_NullToPointer);
+ return false;
+}
+
+/// \brief Checks compatibility between two pointers and return the resulting
+/// type.
+static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
+ ExprResult &RHS,
+ SourceLocation Loc) {
+ QualType LHSTy = LHS.get()->getType();
+ QualType RHSTy = RHS.get()->getType();
+
+ if (S.Context.hasSameType(LHSTy, RHSTy)) {
+ // Two identical pointers types are always compatible.
+ return LHSTy;
+ }
+
+ QualType lhptee, rhptee;
+
+ // Get the pointee types.
+ if (const BlockPointerType *LHSBTy = LHSTy->getAs<BlockPointerType>()) {
+ lhptee = LHSBTy->getPointeeType();
+ rhptee = RHSTy->castAs<BlockPointerType>()->getPointeeType();
+ } else {
+ lhptee = LHSTy->castAs<PointerType>()->getPointeeType();
+ rhptee = RHSTy->castAs<PointerType>()->getPointeeType();
+ }
+
+ if (!S.Context.typesAreCompatible(lhptee.getUnqualifiedType(),
+ rhptee.getUnqualifiedType())) {
+ S.Diag(Loc, diag::warn_typecheck_cond_incompatible_pointers)
+ << LHSTy << RHSTy << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
+ // In this situation, we assume void* type. No especially good
+ // reason, but this is what gcc does, and we do have to pick
+ // to get a consistent AST.
+ QualType incompatTy = S.Context.getPointerType(S.Context.VoidTy);
+ LHS = S.ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast);
+ RHS = S.ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast);
+ return incompatTy;
+ }
+
+ // The pointer types are compatible.
+ // C99 6.5.15p6: If both operands are pointers to compatible types *or* to
+ // differently qualified versions of compatible types, the result type is
+ // a pointer to an appropriately qualified version of the *composite*
+ // type.
+ // FIXME: Need to calculate the composite type.
+ // FIXME: Need to add qualifiers
+
+ LHS = S.ImpCastExprToType(LHS.take(), LHSTy, CK_BitCast);
+ RHS = S.ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast);
+ return LHSTy;
+}
+
+/// \brief Return the resulting type when the operands are both block pointers.
+static QualType checkConditionalBlockPointerCompatibility(Sema &S,
+ ExprResult &LHS,
+ ExprResult &RHS,
+ SourceLocation Loc) {
+ QualType LHSTy = LHS.get()->getType();
+ QualType RHSTy = RHS.get()->getType();
+
+ if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) {
+ if (LHSTy->isVoidPointerType() || RHSTy->isVoidPointerType()) {
+ QualType destType = S.Context.getPointerType(S.Context.VoidTy);
+ LHS = S.ImpCastExprToType(LHS.take(), destType, CK_BitCast);
+ RHS = S.ImpCastExprToType(RHS.take(), destType, CK_BitCast);
+ return destType;
+ }
+ S.Diag(Loc, diag::err_typecheck_cond_incompatible_operands)
+ << LHSTy << RHSTy << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
+ return QualType();
+ }
+
+ // We have 2 block pointer types.
+ return checkConditionalPointerCompatibility(S, LHS, RHS, Loc);
+}
+
+/// \brief Return the resulting type when the operands are both pointers.
+static QualType
+checkConditionalObjectPointersCompatibility(Sema &S, ExprResult &LHS,
+ ExprResult &RHS,
+ SourceLocation Loc) {
+ // get the pointer types
+ QualType LHSTy = LHS.get()->getType();
+ QualType RHSTy = RHS.get()->getType();
+
+ // get the "pointed to" types
+ QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
+
+ // ignore qualifiers on void (C99 6.5.15p3, clause 6)
+ if (lhptee->isVoidType() && rhptee->isIncompleteOrObjectType()) {
+ // Figure out necessary qualifiers (C99 6.5.15p6)
+ QualType destPointee
+ = S.Context.getQualifiedType(lhptee, rhptee.getQualifiers());
+ QualType destType = S.Context.getPointerType(destPointee);
+ // Add qualifiers if necessary.
+ LHS = S.ImpCastExprToType(LHS.take(), destType, CK_NoOp);
+ // Promote to void*.
+ RHS = S.ImpCastExprToType(RHS.take(), destType, CK_BitCast);
+ return destType;
+ }
+ if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) {
+ QualType destPointee
+ = S.Context.getQualifiedType(rhptee, lhptee.getQualifiers());
+ QualType destType = S.Context.getPointerType(destPointee);
+ // Add qualifiers if necessary.
+ RHS = S.ImpCastExprToType(RHS.take(), destType, CK_NoOp);
+ // Promote to void*.
+ LHS = S.ImpCastExprToType(LHS.take(), destType, CK_BitCast);
+ return destType;
+ }
+
+ return checkConditionalPointerCompatibility(S, LHS, RHS, Loc);
+}
+
+/// \brief Return false if the first expression is not an integer and the second
+/// expression is not a pointer, true otherwise.
+static bool checkPointerIntegerMismatch(Sema &S, ExprResult &Int,
+ Expr* PointerExpr, SourceLocation Loc,
+ bool IsIntFirstExpr) {
+ if (!PointerExpr->getType()->isPointerType() ||
+ !Int.get()->getType()->isIntegerType())
+ return false;
+
+ Expr *Expr1 = IsIntFirstExpr ? Int.get() : PointerExpr;
+ Expr *Expr2 = IsIntFirstExpr ? PointerExpr : Int.get();
+
+ S.Diag(Loc, diag::warn_typecheck_cond_pointer_integer_mismatch)
+ << Expr1->getType() << Expr2->getType()
+ << Expr1->getSourceRange() << Expr2->getSourceRange();
+ Int = S.ImpCastExprToType(Int.take(), PointerExpr->getType(),
+ CK_IntegralToPointer);
+ return true;
+}
+
+/// Note that LHS is not null here, even if this is the gnu "x ?: y" extension.
+/// In that case, LHS = cond.
/// C99 6.5.15
-QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprResult &RHS,
- ExprValueKind &VK, ExprObjectKind &OK,
+QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
+ ExprResult &RHS, ExprValueKind &VK,
+ ExprObjectKind &OK,
SourceLocation QuestionLoc) {
- ExprResult lhsResult = CheckPlaceholderExpr(LHS.get());
- if (!lhsResult.isUsable()) return QualType();
- LHS = move(lhsResult);
+ ExprResult LHSResult = CheckPlaceholderExpr(LHS.get());
+ if (!LHSResult.isUsable()) return QualType();
+ LHS = move(LHSResult);
- ExprResult rhsResult = CheckPlaceholderExpr(RHS.get());
- if (!rhsResult.isUsable()) return QualType();
- RHS = move(rhsResult);
+ ExprResult RHSResult = CheckPlaceholderExpr(RHS.get());
+ if (!RHSResult.isUsable()) return QualType();
+ RHS = move(RHSResult);
// C++ is sufficiently different to merit its own checker.
if (getLangOptions().CPlusPlus)
@@ -4382,23 +4595,8 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR
QualType RHSTy = RHS.get()->getType();
// first, check the condition.
- if (!CondTy->isScalarType()) { // C99 6.5.15p2
- // OpenCL: Sec 6.3.i says the condition is allowed to be a vector or scalar.
- // Throw an error if its not either.
- if (getLangOptions().OpenCL) {
- if (!CondTy->isVectorType()) {
- Diag(Cond.get()->getLocStart(),
- diag::err_typecheck_cond_expect_scalar_or_vector)
- << CondTy;
- return QualType();
- }
- }
- else {
- Diag(Cond.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar)
- << CondTy;
- return QualType();
- }
- }
+ if (checkCondition(*this, Cond.get()))
+ return QualType();
// Now check the two expressions.
if (LHSTy->isVectorType() || RHSTy->isVectorType())
@@ -4407,22 +4605,9 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR
// OpenCL: 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.
- if (getLangOptions().OpenCL && CondTy->isVectorType()) {
- // Both operands should be of scalar type.
- if (!LHSTy->isScalarType()) {
- Diag(LHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar)
- << CondTy;
- return QualType();
- }
- if (!RHSTy->isScalarType()) {
- Diag(RHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar)
- << CondTy;
+ if (getLangOptions().OpenCL && CondTy->isVectorType())
+ if (checkConditionalConvertScalarsToVectors(*this, LHS, RHS, CondTy))
return QualType();
- }
- // Implicity convert these scalars to the type of the condition.
- LHS = ImpCastExprToType(LHS.take(), CondTy, CK_IntegralCast);
- RHS = ImpCastExprToType(RHS.take(), CondTy, CK_IntegralCast);
- }
// If both operands have arithmetic type, do the usual arithmetic conversions
// to find a common type: C99 6.5.15p3,5.
@@ -4447,29 +4632,13 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR
// C99 6.5.15p5: "If both operands have void type, the result has void type."
// The following || allows only one side to be void (a GCC-ism).
if (LHSTy->isVoidType() || RHSTy->isVoidType()) {
- if (!LHSTy->isVoidType())
- Diag(RHS.get()->getLocStart(), diag::ext_typecheck_cond_one_void)
- << RHS.get()->getSourceRange();
- if (!RHSTy->isVoidType())
- Diag(LHS.get()->getLocStart(), diag::ext_typecheck_cond_one_void)
- << LHS.get()->getSourceRange();
- LHS = ImpCastExprToType(LHS.take(), Context.VoidTy, CK_ToVoid);
- RHS = ImpCastExprToType(RHS.take(), Context.VoidTy, CK_ToVoid);
- return Context.VoidTy;
+ return checkConditionalVoidType(*this, LHS, RHS);
}
+
// C99 6.5.15p6 - "if one operand is a null pointer constant, the result has
// the type of the other operand."
- if ((LHSTy->isAnyPointerType() || LHSTy->isBlockPointerType()) &&
- RHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
- // promote the null to a pointer.
- RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_NullToPointer);
- return LHSTy;
- }
- if ((RHSTy->isAnyPointerType() || RHSTy->isBlockPointerType()) &&
- LHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
- LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_NullToPointer);
- return RHSTy;
- }
+ if (!checkConditionalNullPointer(*this, RHS, LHSTy)) return LHSTy;
+ if (!checkConditionalNullPointer(*this, LHS, RHSTy)) return RHSTy;
// All objective-c pointer type analysis is done here.
QualType compositeType = FindCompositeObjCPointerType(LHS, RHS,
@@ -4481,116 +4650,23 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR
// Handle block pointer types.
- if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) {
- if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) {
- if (LHSTy->isVoidPointerType() || RHSTy->isVoidPointerType()) {
- QualType destType = Context.getPointerType(Context.VoidTy);
- LHS = ImpCastExprToType(LHS.take(), destType, CK_BitCast);
- RHS = ImpCastExprToType(RHS.take(), destType, CK_BitCast);
- return destType;
- }
- Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands)
- << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
- return QualType();
- }
- // We have 2 block pointer types.
- if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
- // Two identical block pointer types are always compatible.
- return LHSTy;
- }
- // The block pointer types aren't identical, continue checking.
- QualType lhptee = LHSTy->getAs<BlockPointerType>()->getPointeeType();
- QualType rhptee = RHSTy->getAs<BlockPointerType>()->getPointeeType();
-
- if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
- rhptee.getUnqualifiedType())) {
- Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers)
- << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
- // In this situation, we assume void* type. No especially good
- // reason, but this is what gcc does, and we do have to pick
- // to get a consistent AST.
- QualType incompatTy = Context.getPointerType(Context.VoidTy);
- LHS = ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast);
- RHS = ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast);
- return incompatTy;
- }
- // The block pointer types are compatible.
- LHS = ImpCastExprToType(LHS.take(), LHSTy, CK_BitCast);
- RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast);
- return LHSTy;
- }
+ if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType())
+ return checkConditionalBlockPointerCompatibility(*this, LHS, RHS,
+ QuestionLoc);
// Check constraints for C object pointers types (C99 6.5.15p3,6).
- if (LHSTy->isPointerType() && RHSTy->isPointerType()) {
- // get the "pointed to" types
- QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
- QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
-
- // ignore qualifiers on void (C99 6.5.15p3, clause 6)
- if (lhptee->isVoidType() && rhptee->isIncompleteOrObjectType()) {
- // Figure out necessary qualifiers (C99 6.5.15p6)
- QualType destPointee
- = Context.getQualifiedType(lhptee, rhptee.getQualifiers());
- QualType destType = Context.getPointerType(destPointee);
- // Add qualifiers if necessary.
- LHS = ImpCastExprToType(LHS.take(), destType, CK_NoOp);
- // Promote to void*.
- RHS = ImpCastExprToType(RHS.take(), destType, CK_BitCast);
- return destType;
- }
- if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) {
- QualType destPointee
- = Context.getQualifiedType(rhptee, lhptee.getQualifiers());
- QualType destType = Context.getPointerType(destPointee);
- // Add qualifiers if necessary.
- RHS = ImpCastExprToType(RHS.take(), destType, CK_NoOp);
- // Promote to void*.
- LHS = ImpCastExprToType(LHS.take(), destType, CK_BitCast);
- return destType;
- }
-
- if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
- // Two identical pointer types are always compatible.
- return LHSTy;
- }
- if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
- rhptee.getUnqualifiedType())) {
- Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers)
- << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
- // In this situation, we assume void* type. No especially good
- // reason, but this is what gcc does, and we do have to pick
- // to get a consistent AST.
- QualType incompatTy = Context.getPointerType(Context.VoidTy);
- LHS = ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast);
- RHS = ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast);
- return incompatTy;
- }
- // The pointer types are compatible.
- // C99 6.5.15p6: If both operands are pointers to compatible types *or* to
- // differently qualified versions of compatible types, the result type is
- // a pointer to an appropriately qualified version of the *composite*
- // type.
- // FIXME: Need to calculate the composite type.
- // FIXME: Need to add qualifiers
- LHS = ImpCastExprToType(LHS.take(), LHSTy, CK_BitCast);
- RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast);
- return LHSTy;
- }
+ if (LHSTy->isPointerType() && RHSTy->isPointerType())
+ return checkConditionalObjectPointersCompatibility(*this, LHS, RHS,
+ QuestionLoc);
// GCC compatibility: soften pointer/integer mismatch. Note that
// null pointers have been filtered out by this point.
- if (RHSTy->isPointerType() && LHSTy->isIntegerType()) {
- Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch)
- << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
- LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_IntegralToPointer);
+ if (checkPointerIntegerMismatch(*this, LHS, RHS.get(), QuestionLoc,
+ /*isIntFirstExpr=*/true))
return RHSTy;
- }
- if (LHSTy->isPointerType() && RHSTy->isIntegerType()) {
- Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch)
- << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
- RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_IntegralToPointer);
+ if (checkPointerIntegerMismatch(*this, RHS, LHS.get(), QuestionLoc,
+ /*isIntFirstExpr=*/false))
return LHSTy;
- }
// Emit a better diagnostic if one of the expressions is a null pointer
// constant and the other is not a pointer type. In this case, the user most
@@ -4600,14 +4676,15 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR
// Otherwise, the operands are not compatible.
Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands)
- << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+ << LHSTy << RHSTy << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
return QualType();
}
/// FindCompositeObjCPointerType - Helper method to find composite type of
/// two objective-c pointer types of the two input expressions.
QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
- SourceLocation QuestionLoc) {
+ SourceLocation QuestionLoc) {
QualType LHSTy = LHS.get()->getType();
QualType RHSTy = RHS.get()->getType();
@@ -4615,34 +4692,34 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
// to the pseudo-builtin, because that will be implicitly cast back to the
// redefinition type if an attempt is made to access its fields.
if (LHSTy->isObjCClassType() &&
- (Context.hasSameType(RHSTy, Context.ObjCClassRedefinitionType))) {
- RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast);
+ (Context.hasSameType(RHSTy, Context.getObjCClassRedefinitionType()))) {
+ RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_CPointerToObjCPointerCast);
return LHSTy;
}
if (RHSTy->isObjCClassType() &&
- (Context.hasSameType(LHSTy, Context.ObjCClassRedefinitionType))) {
- LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_BitCast);
+ (Context.hasSameType(LHSTy, Context.getObjCClassRedefinitionType()))) {
+ LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_CPointerToObjCPointerCast);
return RHSTy;
}
// And the same for struct objc_object* / id
if (LHSTy->isObjCIdType() &&
- (Context.hasSameType(RHSTy, Context.ObjCIdRedefinitionType))) {
- RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast);
+ (Context.hasSameType(RHSTy, Context.getObjCIdRedefinitionType()))) {
+ RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_CPointerToObjCPointerCast);
return LHSTy;
}
if (RHSTy->isObjCIdType() &&
- (Context.hasSameType(LHSTy, Context.ObjCIdRedefinitionType))) {
- LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_BitCast);
+ (Context.hasSameType(LHSTy, Context.getObjCIdRedefinitionType()))) {
+ LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_CPointerToObjCPointerCast);
return RHSTy;
}
// And the same for struct objc_selector* / SEL
if (Context.isObjCSelType(LHSTy) &&
- (Context.hasSameType(RHSTy, Context.ObjCSelRedefinitionType))) {
+ (Context.hasSameType(RHSTy, Context.getObjCSelRedefinitionType()))) {
RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast);
return LHSTy;
}
if (Context.isObjCSelType(RHSTy) &&
- (Context.hasSameType(LHSTy, Context.ObjCSelRedefinitionType))) {
+ (Context.hasSameType(LHSTy, Context.getObjCSelRedefinitionType()))) {
LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_BitCast);
return RHSTy;
}
@@ -4653,8 +4730,8 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
// Two identical object pointer types are always compatible.
return LHSTy;
}
- const ObjCObjectPointerType *LHSOPT = LHSTy->getAs<ObjCObjectPointerType>();
- const ObjCObjectPointerType *RHSOPT = RHSTy->getAs<ObjCObjectPointerType>();
+ const ObjCObjectPointerType *LHSOPT = LHSTy->castAs<ObjCObjectPointerType>();
+ const ObjCObjectPointerType *RHSOPT = RHSTy->castAs<ObjCObjectPointerType>();
QualType compositeType = LHSTy;
// If both operands are interfaces and either operand can be
@@ -4752,18 +4829,20 @@ static bool IsArithmeticOp(BinaryOperatorKind Opc) {
/// IsArithmeticBinaryExpr - Returns true if E is an arithmetic binary
/// expression, either using a built-in or overloaded operator,
-/// and sets *OpCode to the opcode and *RHS to the right-hand side expression.
+/// and sets *OpCode to the opcode and *RHSExprs to the right-hand side
+/// expression.
static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode,
- Expr **RHS) {
- E = E->IgnoreParenImpCasts();
+ Expr **RHSExprs) {
+ // Don't strip parenthesis: we should not warn if E is in parenthesis.
+ E = E->IgnoreImpCasts();
E = E->IgnoreConversionOperator();
- E = E->IgnoreParenImpCasts();
+ E = E->IgnoreImpCasts();
// Built-in binary operator.
if (BinaryOperator *OP = dyn_cast<BinaryOperator>(E)) {
if (IsArithmeticOp(OP->getOpcode())) {
*Opcode = OP->getOpcode();
- *RHS = OP->getRHS();
+ *RHSExprs = OP->getRHS();
return true;
}
}
@@ -4782,7 +4861,7 @@ static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode,
BinaryOperatorKind OpKind = BinaryOperator::getOverloadedOpcode(OO);
if (IsArithmeticOp(OpKind)) {
*Opcode = OpKind;
- *RHS = Call->getArg(1);
+ *RHSExprs = Call->getArg(1);
return true;
}
}
@@ -4817,8 +4896,8 @@ static bool ExprLooksBoolean(Expr *E) {
static void DiagnoseConditionalPrecedence(Sema &Self,
SourceLocation OpLoc,
Expr *Condition,
- Expr *LHS,
- Expr *RHS) {
+ Expr *LHSExpr,
+ Expr *RHSExpr) {
BinaryOperatorKind CondOpcode;
Expr *CondRHS;
@@ -4841,7 +4920,7 @@ static void DiagnoseConditionalPrecedence(Sema &Self,
SuggestParentheses(Self, OpLoc,
Self.PDiag(diag::note_precedence_conditional_first),
- SourceRange(CondRHS->getLocStart(), RHS->getLocEnd()));
+ SourceRange(CondRHS->getLocStart(), RHSExpr->getLocEnd()));
}
/// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
@@ -4898,7 +4977,8 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
return Owned(new (Context)
BinaryConditionalOperator(commonExpr, opaqueValue, Cond.take(), LHS.take(),
- RHS.take(), QuestionLoc, ColonLoc, result, VK, OK));
+ RHS.take(), QuestionLoc, ColonLoc, result, VK,
+ OK));
}
// checkPointerTypesForAssignment - This is a very tricky routine (despite
@@ -4907,15 +4987,15 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
// This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3].
// FIXME: add a couple examples in this comment.
static Sema::AssignConvertType
-checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) {
- assert(lhsType.isCanonical() && "LHS not canonicalized!");
- assert(rhsType.isCanonical() && "RHS not canonicalized!");
+checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) {
+ assert(LHSType.isCanonical() && "LHS not canonicalized!");
+ assert(RHSType.isCanonical() && "RHS not canonicalized!");
// get the "pointed to" type (ignoring qualifiers at the top level)
const Type *lhptee, *rhptee;
Qualifiers lhq, rhq;
- llvm::tie(lhptee, lhq) = cast<PointerType>(lhsType)->getPointeeType().split();
- llvm::tie(rhptee, rhq) = cast<PointerType>(rhsType)->getPointeeType().split();
+ llvm::tie(lhptee, lhq) = cast<PointerType>(LHSType)->getPointeeType().split();
+ llvm::tie(rhptee, rhq) = cast<PointerType>(RHSType)->getPointeeType().split();
Sema::AssignConvertType ConvTy = Sema::Compatible;
@@ -5019,6 +5099,9 @@ checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) {
// General pointer incompatibility takes priority over qualifiers.
return Sema::IncompatiblePointer;
}
+ if (!S.getLangOptions().CPlusPlus &&
+ S.IsNoReturnConversion(ltrans, rtrans, ltrans))
+ return Sema::IncompatiblePointer;
return ConvTy;
}
@@ -5027,16 +5110,16 @@ checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) {
/// are compatible. It is more restrict than comparing two function pointer
// types.
static Sema::AssignConvertType
-checkBlockPointerTypesForAssignment(Sema &S, QualType lhsType,
- QualType rhsType) {
- assert(lhsType.isCanonical() && "LHS not canonicalized!");
- assert(rhsType.isCanonical() && "RHS not canonicalized!");
+checkBlockPointerTypesForAssignment(Sema &S, QualType LHSType,
+ QualType RHSType) {
+ assert(LHSType.isCanonical() && "LHS not canonicalized!");
+ assert(RHSType.isCanonical() && "RHS not canonicalized!");
QualType lhptee, rhptee;
// get the "pointed to" type (ignoring qualifiers at the top level)
- lhptee = cast<BlockPointerType>(lhsType)->getPointeeType();
- rhptee = cast<BlockPointerType>(rhsType)->getPointeeType();
+ lhptee = cast<BlockPointerType>(LHSType)->getPointeeType();
+ rhptee = cast<BlockPointerType>(RHSType)->getPointeeType();
// In C++, the types have to match exactly.
if (S.getLangOptions().CPlusPlus)
@@ -5048,7 +5131,7 @@ checkBlockPointerTypesForAssignment(Sema &S, QualType lhsType,
if (lhptee.getLocalQualifiers() != rhptee.getLocalQualifiers())
ConvTy = Sema::CompatiblePointerDiscardsQualifiers;
- if (!S.Context.typesAreBlockPointerCompatible(lhsType, rhsType))
+ if (!S.Context.typesAreBlockPointerCompatible(LHSType, RHSType))
return Sema::IncompatibleBlockPointer;
return ConvTy;
@@ -5057,51 +5140,49 @@ checkBlockPointerTypesForAssignment(Sema &S, QualType lhsType,
/// checkObjCPointerTypesForAssignment - Compares two objective-c pointer types
/// for assignment compatibility.
static Sema::AssignConvertType
-checkObjCPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) {
- assert(lhsType.isCanonical() && "LHS was not canonicalized!");
- assert(rhsType.isCanonical() && "RHS was not canonicalized!");
+checkObjCPointerTypesForAssignment(Sema &S, QualType LHSType,
+ QualType RHSType) {
+ assert(LHSType.isCanonical() && "LHS was not canonicalized!");
+ assert(RHSType.isCanonical() && "RHS was not canonicalized!");
- if (lhsType->isObjCBuiltinType()) {
+ if (LHSType->isObjCBuiltinType()) {
// Class is not compatible with ObjC object pointers.
- if (lhsType->isObjCClassType() && !rhsType->isObjCBuiltinType() &&
- !rhsType->isObjCQualifiedClassType())
+ if (LHSType->isObjCClassType() && !RHSType->isObjCBuiltinType() &&
+ !RHSType->isObjCQualifiedClassType())
return Sema::IncompatiblePointer;
return Sema::Compatible;
}
- if (rhsType->isObjCBuiltinType()) {
- // Class is not compatible with ObjC object pointers.
- if (rhsType->isObjCClassType() && !lhsType->isObjCBuiltinType() &&
- !lhsType->isObjCQualifiedClassType())
+ if (RHSType->isObjCBuiltinType()) {
+ if (RHSType->isObjCClassType() && !LHSType->isObjCBuiltinType() &&
+ !LHSType->isObjCQualifiedClassType())
return Sema::IncompatiblePointer;
return Sema::Compatible;
}
- QualType lhptee =
- lhsType->getAs<ObjCObjectPointerType>()->getPointeeType();
- QualType rhptee =
- rhsType->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType lhptee = LHSType->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType rhptee = RHSType->getAs<ObjCObjectPointerType>()->getPointeeType();
if (!lhptee.isAtLeastAsQualifiedAs(rhptee))
return Sema::CompatiblePointerDiscardsQualifiers;
- if (S.Context.typesAreCompatible(lhsType, rhsType))
+ if (S.Context.typesAreCompatible(LHSType, RHSType))
return Sema::Compatible;
- if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType())
+ if (LHSType->isObjCQualifiedIdType() || RHSType->isObjCQualifiedIdType())
return Sema::IncompatibleObjCQualifiedId;
return Sema::IncompatiblePointer;
}
Sema::AssignConvertType
Sema::CheckAssignmentConstraints(SourceLocation Loc,
- QualType lhsType, QualType rhsType) {
+ QualType LHSType, QualType RHSType) {
// Fake up an opaque expression. We don't actually care about what
// cast operations are required, so if CheckAssignmentConstraints
// adds casts to this they'll be wasted, but fortunately that doesn't
// usually happen on valid code.
- OpaqueValueExpr rhs(Loc, rhsType, VK_RValue);
- ExprResult rhsPtr = &rhs;
+ OpaqueValueExpr RHSExpr(Loc, RHSType, VK_RValue);
+ ExprResult RHSPtr = &RHSExpr;
CastKind K = CK_Invalid;
- return CheckAssignmentConstraints(lhsType, rhsPtr, K);
+ return CheckAssignmentConstraints(LHSType, RHSPtr, K);
}
/// CheckAssignmentConstraints (C99 6.5.16) - This routine currently
@@ -5122,18 +5203,22 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc,
///
/// Sets 'Kind' for any result kind except Incompatible.
Sema::AssignConvertType
-Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
+Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
CastKind &Kind) {
- QualType rhsType = rhs.get()->getType();
- QualType origLhsType = lhsType;
+ QualType RHSType = RHS.get()->getType();
+ QualType OrigLHSType = LHSType;
// Get canonical types. We're not formatting these types, just comparing
// them.
- lhsType = Context.getCanonicalType(lhsType).getUnqualifiedType();
- rhsType = Context.getCanonicalType(rhsType).getUnqualifiedType();
+ LHSType = Context.getCanonicalType(LHSType).getUnqualifiedType();
+ RHSType = Context.getCanonicalType(RHSType).getUnqualifiedType();
+
+ // We can't do assignment from/to atomics yet.
+ if (LHSType->isAtomicType())
+ return Incompatible;
// Common case: no conversion required.
- if (lhsType == rhsType) {
+ if (LHSType == RHSType) {
Kind = CK_NoOp;
return Compatible;
}
@@ -5143,10 +5228,10 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
// e.g., as a parameter type in a built-in function. In this case,
// just make sure that the type referenced is compatible with the
// right-hand side type. The caller is responsible for adjusting
- // lhsType so that the resulting expression does not have reference
+ // LHSType so that the resulting expression does not have reference
// type.
- if (const ReferenceType *lhsTypeRef = lhsType->getAs<ReferenceType>()) {
- if (Context.typesAreCompatible(lhsTypeRef->getPointeeType(), rhsType)) {
+ if (const ReferenceType *LHSTypeRef = LHSType->getAs<ReferenceType>()) {
+ if (Context.typesAreCompatible(LHSTypeRef->getPointeeType(), RHSType)) {
Kind = CK_LValueBitCast;
return Compatible;
}
@@ -5155,16 +5240,16 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
// Allow scalar to ExtVector assignments, and assignments of an ExtVector type
// to the same ExtVector type.
- if (lhsType->isExtVectorType()) {
- if (rhsType->isExtVectorType())
+ if (LHSType->isExtVectorType()) {
+ if (RHSType->isExtVectorType())
return Incompatible;
- if (rhsType->isArithmeticType()) {
+ if (RHSType->isArithmeticType()) {
// CK_VectorSplat does T -> vector T, so first cast to the
// element type.
- QualType elType = cast<ExtVectorType>(lhsType)->getElementType();
- if (elType != rhsType) {
- Kind = PrepareScalarCast(*this, rhs, elType);
- rhs = ImpCastExprToType(rhs.take(), elType, Kind);
+ QualType elType = cast<ExtVectorType>(LHSType)->getElementType();
+ if (elType != RHSType) {
+ Kind = PrepareScalarCast(RHS, elType);
+ RHS = ImpCastExprToType(RHS.take(), elType, Kind);
}
Kind = CK_VectorSplat;
return Compatible;
@@ -5172,11 +5257,11 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
}
// Conversions to or from vector type.
- if (lhsType->isVectorType() || rhsType->isVectorType()) {
- if (lhsType->isVectorType() && rhsType->isVectorType()) {
+ if (LHSType->isVectorType() || RHSType->isVectorType()) {
+ if (LHSType->isVectorType() && RHSType->isVectorType()) {
// Allow assignments of an AltiVec vector type to an equivalent GCC
// vector type and vice versa
- if (Context.areCompatibleVectorTypes(lhsType, rhsType)) {
+ if (Context.areCompatibleVectorTypes(LHSType, RHSType)) {
Kind = CK_BitCast;
return Compatible;
}
@@ -5185,7 +5270,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
// vectors, the total size only needs to be the same. This is a bitcast;
// no bits are changed but the result type is different.
if (getLangOptions().LaxVectorConversions &&
- (Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType))) {
+ (Context.getTypeSize(LHSType) == Context.getTypeSize(RHSType))) {
Kind = CK_BitCast;
return IncompatibleVectors;
}
@@ -5194,38 +5279,39 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
}
// Arithmetic conversions.
- if (lhsType->isArithmeticType() && rhsType->isArithmeticType() &&
- !(getLangOptions().CPlusPlus && lhsType->isEnumeralType())) {
- Kind = PrepareScalarCast(*this, rhs, lhsType);
+ if (LHSType->isArithmeticType() && RHSType->isArithmeticType() &&
+ !(getLangOptions().CPlusPlus && LHSType->isEnumeralType())) {
+ Kind = PrepareScalarCast(RHS, LHSType);
return Compatible;
}
// Conversions to normal pointers.
- if (const PointerType *lhsPointer = dyn_cast<PointerType>(lhsType)) {
+ if (const PointerType *LHSPointer = dyn_cast<PointerType>(LHSType)) {
// U* -> T*
- if (isa<PointerType>(rhsType)) {
+ if (isa<PointerType>(RHSType)) {
Kind = CK_BitCast;
- return checkPointerTypesForAssignment(*this, lhsType, rhsType);
+ return checkPointerTypesForAssignment(*this, LHSType, RHSType);
}
// int -> T*
- if (rhsType->isIntegerType()) {
+ if (RHSType->isIntegerType()) {
Kind = CK_IntegralToPointer; // FIXME: null?
return IntToPointer;
}
// C pointers are not compatible with ObjC object pointers,
// with two exceptions:
- if (isa<ObjCObjectPointerType>(rhsType)) {
+ if (isa<ObjCObjectPointerType>(RHSType)) {
// - conversions to void*
- if (lhsPointer->getPointeeType()->isVoidType()) {
- Kind = CK_AnyPointerToObjCPointerCast;
+ if (LHSPointer->getPointeeType()->isVoidType()) {
+ Kind = CK_BitCast;
return Compatible;
}
// - conversions from 'Class' to the redefinition type
- if (rhsType->isObjCClassType() &&
- Context.hasSameType(lhsType, Context.ObjCClassRedefinitionType)) {
+ if (RHSType->isObjCClassType() &&
+ Context.hasSameType(LHSType,
+ Context.getObjCClassRedefinitionType())) {
Kind = CK_BitCast;
return Compatible;
}
@@ -5235,8 +5321,8 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
}
// U^ -> void*
- if (rhsType->getAs<BlockPointerType>()) {
- if (lhsPointer->getPointeeType()->isVoidType()) {
+ if (RHSType->getAs<BlockPointerType>()) {
+ if (LHSPointer->getPointeeType()->isVoidType()) {
Kind = CK_BitCast;
return Compatible;
}
@@ -5246,27 +5332,27 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
}
// Conversions to block pointers.
- if (isa<BlockPointerType>(lhsType)) {
+ if (isa<BlockPointerType>(LHSType)) {
// U^ -> T^
- if (rhsType->isBlockPointerType()) {
- Kind = CK_AnyPointerToBlockPointerCast;
- return checkBlockPointerTypesForAssignment(*this, lhsType, rhsType);
+ if (RHSType->isBlockPointerType()) {
+ Kind = CK_BitCast;
+ return checkBlockPointerTypesForAssignment(*this, LHSType, RHSType);
}
// int or null -> T^
- if (rhsType->isIntegerType()) {
+ if (RHSType->isIntegerType()) {
Kind = CK_IntegralToPointer; // FIXME: null
return IntToBlockPointer;
}
// id -> T^
- if (getLangOptions().ObjC1 && rhsType->isObjCIdType()) {
+ if (getLangOptions().ObjC1 && RHSType->isObjCIdType()) {
Kind = CK_AnyPointerToBlockPointerCast;
return Compatible;
}
// void* -> T^
- if (const PointerType *RHSPT = rhsType->getAs<PointerType>())
+ if (const PointerType *RHSPT = RHSType->getAs<PointerType>())
if (RHSPT->getPointeeType()->isVoidType()) {
Kind = CK_AnyPointerToBlockPointerCast;
return Compatible;
@@ -5276,48 +5362,49 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
}
// Conversions to Objective-C pointers.
- if (isa<ObjCObjectPointerType>(lhsType)) {
+ if (isa<ObjCObjectPointerType>(LHSType)) {
// A* -> B*
- if (rhsType->isObjCObjectPointerType()) {
+ if (RHSType->isObjCObjectPointerType()) {
Kind = CK_BitCast;
Sema::AssignConvertType result =
- checkObjCPointerTypesForAssignment(*this, lhsType, rhsType);
+ checkObjCPointerTypesForAssignment(*this, LHSType, RHSType);
if (getLangOptions().ObjCAutoRefCount &&
result == Compatible &&
- !CheckObjCARCUnavailableWeakConversion(origLhsType, rhsType))
+ !CheckObjCARCUnavailableWeakConversion(OrigLHSType, RHSType))
result = IncompatibleObjCWeakRef;
return result;
}
// int or null -> A*
- if (rhsType->isIntegerType()) {
+ if (RHSType->isIntegerType()) {
Kind = CK_IntegralToPointer; // FIXME: null
return IntToPointer;
}
// In general, C pointers are not compatible with ObjC object pointers,
// with two exceptions:
- if (isa<PointerType>(rhsType)) {
+ if (isa<PointerType>(RHSType)) {
+ Kind = CK_CPointerToObjCPointerCast;
+
// - conversions from 'void*'
- if (rhsType->isVoidPointerType()) {
- Kind = CK_AnyPointerToObjCPointerCast;
+ if (RHSType->isVoidPointerType()) {
return Compatible;
}
// - conversions to 'Class' from its redefinition type
- if (lhsType->isObjCClassType() &&
- Context.hasSameType(rhsType, Context.ObjCClassRedefinitionType)) {
- Kind = CK_BitCast;
+ if (LHSType->isObjCClassType() &&
+ Context.hasSameType(RHSType,
+ Context.getObjCClassRedefinitionType())) {
return Compatible;
}
- Kind = CK_AnyPointerToObjCPointerCast;
return IncompatiblePointer;
}
// T^ -> A*
- if (rhsType->isBlockPointerType()) {
- Kind = CK_AnyPointerToObjCPointerCast;
+ if (RHSType->isBlockPointerType()) {
+ maybeExtendBlockObject(*this, RHS);
+ Kind = CK_BlockPointerToObjCPointerCast;
return Compatible;
}
@@ -5325,15 +5412,15 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
}
// Conversions from pointers that are not covered by the above.
- if (isa<PointerType>(rhsType)) {
+ if (isa<PointerType>(RHSType)) {
// T* -> _Bool
- if (lhsType == Context.BoolTy) {
+ if (LHSType == Context.BoolTy) {
Kind = CK_PointerToBoolean;
return Compatible;
}
// T* -> int
- if (lhsType->isIntegerType()) {
+ if (LHSType->isIntegerType()) {
Kind = CK_PointerToIntegral;
return PointerToInt;
}
@@ -5342,15 +5429,15 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
}
// Conversions from Objective-C pointers that are not covered by the above.
- if (isa<ObjCObjectPointerType>(rhsType)) {
+ if (isa<ObjCObjectPointerType>(RHSType)) {
// T* -> _Bool
- if (lhsType == Context.BoolTy) {
+ if (LHSType == Context.BoolTy) {
Kind = CK_PointerToBoolean;
return Compatible;
}
// T* -> int
- if (lhsType->isIntegerType()) {
+ if (LHSType->isIntegerType()) {
Kind = CK_PointerToIntegral;
return PointerToInt;
}
@@ -5359,8 +5446,8 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
}
// struct A -> struct B
- if (isa<TagType>(lhsType) && isa<TagType>(rhsType)) {
- if (Context.typesAreCompatible(lhsType, rhsType)) {
+ if (isa<TagType>(LHSType) && isa<TagType>(RHSType)) {
+ if (Context.typesAreCompatible(LHSType, RHSType)) {
Kind = CK_NoOp;
return Compatible;
}
@@ -5371,8 +5458,9 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
/// \brief Constructs a transparent union from an expression that is
/// used to initialize the transparent union.
-static void ConstructTransparentUnion(Sema &S, ASTContext &C, ExprResult &EResult,
- QualType UnionType, FieldDecl *Field) {
+static void ConstructTransparentUnion(Sema &S, ASTContext &C,
+ ExprResult &EResult, QualType UnionType,
+ FieldDecl *Field) {
// Build an initializer list that designates the appropriate member
// of the transparent union.
Expr *E = EResult.take();
@@ -5391,8 +5479,9 @@ static void ConstructTransparentUnion(Sema &S, ASTContext &C, ExprResult &EResul
}
Sema::AssignConvertType
-Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &rExpr) {
- QualType FromType = rExpr.get()->getType();
+Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType,
+ ExprResult &RHS) {
+ QualType RHSType = RHS.get()->getType();
// If the ArgType is a Union type, we want to handle a potential
// transparent_union GCC extension.
@@ -5411,25 +5500,26 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &rEx
// If the transparent union contains a pointer type, we allow:
// 1) void pointer
// 2) null pointer constant
- if (FromType->isPointerType())
- if (FromType->getAs<PointerType>()->getPointeeType()->isVoidType()) {
- rExpr = ImpCastExprToType(rExpr.take(), it->getType(), CK_BitCast);
+ if (RHSType->isPointerType())
+ if (RHSType->castAs<PointerType>()->getPointeeType()->isVoidType()) {
+ RHS = ImpCastExprToType(RHS.take(), it->getType(), CK_BitCast);
InitField = *it;
break;
}
- if (rExpr.get()->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNull)) {
- rExpr = ImpCastExprToType(rExpr.take(), it->getType(), CK_NullToPointer);
+ if (RHS.get()->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull)) {
+ RHS = ImpCastExprToType(RHS.take(), it->getType(),
+ CK_NullToPointer);
InitField = *it;
break;
}
}
CastKind Kind = CK_Invalid;
- if (CheckAssignmentConstraints(it->getType(), rExpr, Kind)
+ if (CheckAssignmentConstraints(it->getType(), RHS, Kind)
== Compatible) {
- rExpr = ImpCastExprToType(rExpr.take(), it->getType(), Kind);
+ RHS = ImpCastExprToType(RHS.take(), it->getType(), Kind);
InitField = *it;
break;
}
@@ -5438,42 +5528,46 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &rEx
if (!InitField)
return Incompatible;
- ConstructTransparentUnion(*this, Context, rExpr, ArgType, InitField);
+ ConstructTransparentUnion(*this, Context, RHS, ArgType, InitField);
return Compatible;
}
Sema::AssignConvertType
-Sema::CheckSingleAssignmentConstraints(QualType lhsType, ExprResult &rExpr) {
+Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
+ bool Diagnose) {
if (getLangOptions().CPlusPlus) {
- if (!lhsType->isRecordType()) {
+ if (!LHSType->isRecordType() && !LHSType->isAtomicType()) {
// C++ 5.17p3: If the left operand is not of class type, the
// expression is implicitly converted (C++ 4) to the
// cv-unqualified type of the left operand.
- ExprResult Res = PerformImplicitConversion(rExpr.get(),
- lhsType.getUnqualifiedType(),
- AA_Assigning);
+ ExprResult Res = PerformImplicitConversion(RHS.get(),
+ LHSType.getUnqualifiedType(),
+ AA_Assigning, Diagnose);
if (Res.isInvalid())
return Incompatible;
Sema::AssignConvertType result = Compatible;
if (getLangOptions().ObjCAutoRefCount &&
- !CheckObjCARCUnavailableWeakConversion(lhsType, rExpr.get()->getType()))
+ !CheckObjCARCUnavailableWeakConversion(LHSType,
+ RHS.get()->getType()))
result = IncompatibleObjCWeakRef;
- rExpr = move(Res);
+ RHS = move(Res);
return result;
}
// FIXME: Currently, we fall through and treat C++ classes like C
// structures.
- }
+ // FIXME: We also fall through for atomics; not sure what should
+ // happen there, though.
+ }
// C99 6.5.16.1p1: the left operand is a pointer and the right is
// a null pointer constant.
- if ((lhsType->isPointerType() ||
- lhsType->isObjCObjectPointerType() ||
- lhsType->isBlockPointerType())
- && rExpr.get()->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNull)) {
- rExpr = ImpCastExprToType(rExpr.take(), lhsType, CK_NullToPointer);
+ if ((LHSType->isPointerType() ||
+ LHSType->isObjCObjectPointerType() ||
+ LHSType->isBlockPointerType())
+ && RHS.get()->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull)) {
+ RHS = ImpCastExprToType(RHS.take(), LHSType, CK_NullToPointer);
return Compatible;
}
@@ -5483,15 +5577,15 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, ExprResult &rExpr) {
// expressions that suppress this implicit conversion (&, sizeof).
//
// Suppress this for references: C++ 8.5.3p5.
- if (!lhsType->isReferenceType()) {
- rExpr = DefaultFunctionArrayLvalueConversion(rExpr.take());
- if (rExpr.isInvalid())
+ if (!LHSType->isReferenceType()) {
+ RHS = DefaultFunctionArrayLvalueConversion(RHS.take());
+ if (RHS.isInvalid())
return Incompatible;
}
CastKind Kind = CK_Invalid;
Sema::AssignConvertType result =
- CheckAssignmentConstraints(lhsType, rExpr, Kind);
+ CheckAssignmentConstraints(LHSType, RHS, Kind);
// C99 6.5.16.1p2: The value of the right operand is converted to the
// type of the assignment expression.
@@ -5499,150 +5593,202 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, ExprResult &rExpr) {
// so that we can use references in built-in functions even in C.
// The getNonReferenceType() call makes sure that the resulting expression
// does not have reference type.
- if (result != Incompatible && rExpr.get()->getType() != lhsType)
- rExpr = ImpCastExprToType(rExpr.take(), lhsType.getNonLValueExprType(Context), Kind);
+ if (result != Incompatible && RHS.get()->getType() != LHSType)
+ RHS = ImpCastExprToType(RHS.take(),
+ LHSType.getNonLValueExprType(Context), Kind);
return result;
}
-QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &lex, ExprResult &rex) {
+QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &LHS,
+ ExprResult &RHS) {
Diag(Loc, diag::err_typecheck_invalid_operands)
- << lex.get()->getType() << rex.get()->getType()
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
+ << LHS.get()->getType() << RHS.get()->getType()
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return QualType();
}
-QualType Sema::CheckVectorOperands(ExprResult &lex, ExprResult &rex,
- SourceLocation Loc, bool isCompAssign) {
+QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
+ SourceLocation Loc, bool IsCompAssign) {
// For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
- QualType lhsType =
- Context.getCanonicalType(lex.get()->getType()).getUnqualifiedType();
- QualType rhsType =
- Context.getCanonicalType(rex.get()->getType()).getUnqualifiedType();
+ QualType LHSType =
+ Context.getCanonicalType(LHS.get()->getType()).getUnqualifiedType();
+ QualType RHSType =
+ Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType();
// If the vector types are identical, return.
- if (lhsType == rhsType)
- return lhsType;
+ if (LHSType == RHSType)
+ return LHSType;
// Handle the case of equivalent AltiVec and GCC vector types
- if (lhsType->isVectorType() && rhsType->isVectorType() &&
- Context.areCompatibleVectorTypes(lhsType, rhsType)) {
- if (lhsType->isExtVectorType()) {
- rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast);
- return lhsType;
+ if (LHSType->isVectorType() && RHSType->isVectorType() &&
+ Context.areCompatibleVectorTypes(LHSType, RHSType)) {
+ if (LHSType->isExtVectorType()) {
+ RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
+ return LHSType;
}
- if (!isCompAssign)
- lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast);
- return rhsType;
+ if (!IsCompAssign)
+ LHS = ImpCastExprToType(LHS.take(), RHSType, CK_BitCast);
+ return RHSType;
}
if (getLangOptions().LaxVectorConversions &&
- Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType)) {
+ Context.getTypeSize(LHSType) == Context.getTypeSize(RHSType)) {
// If we are allowing lax vector conversions, and LHS and RHS are both
// vectors, the total size only needs to be the same. This is a
// bitcast; no bits are changed but the result type is different.
// FIXME: Should we really be allowing this?
- rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast);
- return lhsType;
+ RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
+ return LHSType;
}
// Canonicalize the ExtVector to the LHS, remember if we swapped so we can
// swap back (so that we don't reverse the inputs to a subtract, for instance.
bool swapped = false;
- if (rhsType->isExtVectorType() && !isCompAssign) {
+ if (RHSType->isExtVectorType() && !IsCompAssign) {
swapped = true;
- std::swap(rex, lex);
- std::swap(rhsType, lhsType);
+ std::swap(RHS, LHS);
+ std::swap(RHSType, LHSType);
}
// Handle the case of an ext vector and scalar.
- if (const ExtVectorType *LV = lhsType->getAs<ExtVectorType>()) {
+ if (const ExtVectorType *LV = LHSType->getAs<ExtVectorType>()) {
QualType EltTy = LV->getElementType();
- if (EltTy->isIntegralType(Context) && rhsType->isIntegralType(Context)) {
- int order = Context.getIntegerTypeOrder(EltTy, rhsType);
+ if (EltTy->isIntegralType(Context) && RHSType->isIntegralType(Context)) {
+ int order = Context.getIntegerTypeOrder(EltTy, RHSType);
if (order > 0)
- rex = ImpCastExprToType(rex.take(), EltTy, CK_IntegralCast);
+ RHS = ImpCastExprToType(RHS.take(), EltTy, CK_IntegralCast);
if (order >= 0) {
- rex = ImpCastExprToType(rex.take(), lhsType, CK_VectorSplat);
- if (swapped) std::swap(rex, lex);
- return lhsType;
+ RHS = ImpCastExprToType(RHS.take(), LHSType, CK_VectorSplat);
+ if (swapped) std::swap(RHS, LHS);
+ return LHSType;
}
}
- if (EltTy->isRealFloatingType() && rhsType->isScalarType() &&
- rhsType->isRealFloatingType()) {
- int order = Context.getFloatingTypeOrder(EltTy, rhsType);
+ if (EltTy->isRealFloatingType() && RHSType->isScalarType() &&
+ RHSType->isRealFloatingType()) {
+ int order = Context.getFloatingTypeOrder(EltTy, RHSType);
if (order > 0)
- rex = ImpCastExprToType(rex.take(), EltTy, CK_FloatingCast);
+ RHS = ImpCastExprToType(RHS.take(), EltTy, CK_FloatingCast);
if (order >= 0) {
- rex = ImpCastExprToType(rex.take(), lhsType, CK_VectorSplat);
- if (swapped) std::swap(rex, lex);
- return lhsType;
+ RHS = ImpCastExprToType(RHS.take(), LHSType, CK_VectorSplat);
+ if (swapped) std::swap(RHS, LHS);
+ return LHSType;
}
}
}
// Vectors of different size or scalar and non-ext-vector are errors.
- if (swapped) std::swap(rex, lex);
+ if (swapped) std::swap(RHS, LHS);
Diag(Loc, diag::err_typecheck_vector_not_convertable)
- << lex.get()->getType() << rex.get()->getType()
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
+ << LHS.get()->getType() << RHS.get()->getType()
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return QualType();
}
-QualType Sema::CheckMultiplyDivideOperands(
- ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign, bool isDiv) {
- if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType())
- return CheckVectorOperands(lex, rex, Loc, isCompAssign);
+// checkArithmeticNull - Detect when a NULL constant is used improperly in an
+// expression. These are mainly cases where the null pointer is used as an
+// integer instead of a pointer.
+static void checkArithmeticNull(Sema &S, ExprResult &LHS, ExprResult &RHS,
+ SourceLocation Loc, bool IsCompare) {
+ // The canonical way to check for a GNU null is with isNullPointerConstant,
+ // but we use a bit of a hack here for speed; this is a relatively
+ // hot path, and isNullPointerConstant is slow.
+ bool LHSNull = isa<GNUNullExpr>(LHS.get()->IgnoreParenImpCasts());
+ bool RHSNull = isa<GNUNullExpr>(RHS.get()->IgnoreParenImpCasts());
+
+ QualType NonNullType = LHSNull ? RHS.get()->getType() : LHS.get()->getType();
+
+ // Avoid analyzing cases where the result will either be invalid (and
+ // diagnosed as such) or entirely valid and not something to warn about.
+ if ((!LHSNull && !RHSNull) || NonNullType->isBlockPointerType() ||
+ NonNullType->isMemberPointerType() || NonNullType->isFunctionType())
+ return;
+
+ // Comparison operations would not make sense with a null pointer no matter
+ // what the other expression is.
+ if (!IsCompare) {
+ S.Diag(Loc, diag::warn_null_in_arithmetic_operation)
+ << (LHSNull ? LHS.get()->getSourceRange() : SourceRange())
+ << (RHSNull ? RHS.get()->getSourceRange() : SourceRange());
+ return;
+ }
+
+ // The rest of the operations only make sense with a null pointer
+ // if the other expression is a pointer.
+ if (LHSNull == RHSNull || NonNullType->isAnyPointerType() ||
+ NonNullType->canDecayToPointerType())
+ return;
+
+ S.Diag(Loc, diag::warn_null_in_comparison_operation)
+ << LHSNull /* LHS is NULL */ << NonNullType
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+}
+
+QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
+ SourceLocation Loc,
+ bool IsCompAssign, bool IsDiv) {
+ checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
+
+ if (LHS.get()->getType()->isVectorType() ||
+ RHS.get()->getType()->isVectorType())
+ return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign);
- QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
- if (lex.isInvalid() || rex.isInvalid())
+ QualType compType = UsualArithmeticConversions(LHS, RHS, IsCompAssign);
+ if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
- if (!lex.get()->getType()->isArithmeticType() ||
- !rex.get()->getType()->isArithmeticType())
- return InvalidOperands(Loc, lex, rex);
+ if (!LHS.get()->getType()->isArithmeticType() ||
+ !RHS.get()->getType()->isArithmeticType())
+ return InvalidOperands(Loc, LHS, RHS);
// Check for division by zero.
- if (isDiv &&
- rex.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
- DiagRuntimeBehavior(Loc, rex.get(), PDiag(diag::warn_division_by_zero)
- << rex.get()->getSourceRange());
+ if (IsDiv &&
+ RHS.get()->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNotNull))
+ DiagRuntimeBehavior(Loc, RHS.get(), PDiag(diag::warn_division_by_zero)
+ << RHS.get()->getSourceRange());
return compType;
}
QualType Sema::CheckRemainderOperands(
- ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign) {
- if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
- if (lex.get()->getType()->hasIntegerRepresentation() &&
- rex.get()->getType()->hasIntegerRepresentation())
- return CheckVectorOperands(lex, rex, Loc, isCompAssign);
- return InvalidOperands(Loc, lex, rex);
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign) {
+ checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
+
+ if (LHS.get()->getType()->isVectorType() ||
+ RHS.get()->getType()->isVectorType()) {
+ if (LHS.get()->getType()->hasIntegerRepresentation() &&
+ RHS.get()->getType()->hasIntegerRepresentation())
+ return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign);
+ return InvalidOperands(Loc, LHS, RHS);
}
- QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
- if (lex.isInvalid() || rex.isInvalid())
+ QualType compType = UsualArithmeticConversions(LHS, RHS, IsCompAssign);
+ if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
- if (!lex.get()->getType()->isIntegerType() || !rex.get()->getType()->isIntegerType())
- return InvalidOperands(Loc, lex, rex);
+ if (!LHS.get()->getType()->isIntegerType() ||
+ !RHS.get()->getType()->isIntegerType())
+ return InvalidOperands(Loc, LHS, RHS);
// Check for remainder by zero.
- if (rex.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
- DiagRuntimeBehavior(Loc, rex.get(), PDiag(diag::warn_remainder_by_zero)
- << rex.get()->getSourceRange());
+ if (RHS.get()->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNotNull))
+ DiagRuntimeBehavior(Loc, RHS.get(), PDiag(diag::warn_remainder_by_zero)
+ << RHS.get()->getSourceRange());
return compType;
}
/// \brief Diagnose invalid arithmetic on two void pointers.
static void diagnoseArithmeticOnTwoVoidPointers(Sema &S, SourceLocation Loc,
- Expr *LHS, Expr *RHS) {
+ Expr *LHSExpr, Expr *RHSExpr) {
S.Diag(Loc, S.getLangOptions().CPlusPlus
? diag::err_typecheck_pointer_arith_void_type
: diag::ext_gnu_void_ptr)
- << 1 /* two pointers */ << LHS->getSourceRange() << RHS->getSourceRange();
+ << 1 /* two pointers */ << LHSExpr->getSourceRange()
+ << RHSExpr->getSourceRange();
}
/// \brief Diagnose invalid arithmetic on a void pointer.
@@ -5682,6 +5828,24 @@ static void diagnoseArithmeticOnFunctionPointer(Sema &S, SourceLocation Loc,
<< Pointer->getSourceRange();
}
+/// \brief Emit error if Operand is incomplete pointer type
+///
+/// \returns True if pointer has incomplete type
+static bool checkArithmeticIncompletePointerType(Sema &S, SourceLocation Loc,
+ Expr *Operand) {
+ if ((Operand->getType()->isPointerType() &&
+ !Operand->getType()->isDependentType()) ||
+ Operand->getType()->isObjCObjectPointerType()) {
+ QualType PointeeTy = Operand->getType()->getPointeeType();
+ if (S.RequireCompleteType(
+ Loc, PointeeTy,
+ S.PDiag(diag::err_typecheck_arithmetic_incomplete_type)
+ << PointeeTy << Operand->getSourceRange()))
+ return true;
+ }
+ return false;
+}
+
/// \brief Check the validity of an arithmetic pointer operand.
///
/// If the operand has pointer type, this code will check for pointer types
@@ -5704,16 +5868,7 @@ static bool checkArithmeticOpPointerOperand(Sema &S, SourceLocation Loc,
return !S.getLangOptions().CPlusPlus;
}
- if ((Operand->getType()->isPointerType() &&
- !Operand->getType()->isDependentType()) ||
- Operand->getType()->isObjCObjectPointerType()) {
- QualType PointeeTy = Operand->getType()->getPointeeType();
- if (S.RequireCompleteType(
- Loc, PointeeTy,
- S.PDiag(diag::err_typecheck_arithmetic_incomplete_type)
- << PointeeTy << Operand->getSourceRange()))
- return false;
- }
+ if (checkArithmeticIncompletePointerType(S, Loc, Operand)) return false;
return true;
}
@@ -5728,22 +5883,22 @@ static bool checkArithmeticOpPointerOperand(Sema &S, SourceLocation Loc,
///
/// \returns True when the operand is valid to use (even if as an extension).
static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc,
- Expr *LHS, Expr *RHS) {
- bool isLHSPointer = LHS->getType()->isAnyPointerType();
- bool isRHSPointer = RHS->getType()->isAnyPointerType();
+ Expr *LHSExpr, Expr *RHSExpr) {
+ bool isLHSPointer = LHSExpr->getType()->isAnyPointerType();
+ bool isRHSPointer = RHSExpr->getType()->isAnyPointerType();
if (!isLHSPointer && !isRHSPointer) return true;
QualType LHSPointeeTy, RHSPointeeTy;
- if (isLHSPointer) LHSPointeeTy = LHS->getType()->getPointeeType();
- if (isRHSPointer) RHSPointeeTy = RHS->getType()->getPointeeType();
+ if (isLHSPointer) LHSPointeeTy = LHSExpr->getType()->getPointeeType();
+ if (isRHSPointer) RHSPointeeTy = RHSExpr->getType()->getPointeeType();
// Check for arithmetic on pointers to incomplete types.
bool isLHSVoidPtr = isLHSPointer && LHSPointeeTy->isVoidType();
bool isRHSVoidPtr = isRHSPointer && RHSPointeeTy->isVoidType();
if (isLHSVoidPtr || isRHSVoidPtr) {
- if (!isRHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, LHS);
- else if (!isLHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, RHS);
- else diagnoseArithmeticOnTwoVoidPointers(S, Loc, LHS, RHS);
+ if (!isRHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, LHSExpr);
+ else if (!isLHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, RHSExpr);
+ else diagnoseArithmeticOnTwoVoidPointers(S, Loc, LHSExpr, RHSExpr);
return !S.getLangOptions().CPlusPlus;
}
@@ -5751,160 +5906,179 @@ static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc,
bool isLHSFuncPtr = isLHSPointer && LHSPointeeTy->isFunctionType();
bool isRHSFuncPtr = isRHSPointer && RHSPointeeTy->isFunctionType();
if (isLHSFuncPtr || isRHSFuncPtr) {
- if (!isRHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, LHS);
- else if (!isLHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, RHS);
- else diagnoseArithmeticOnTwoFunctionPointers(S, Loc, LHS, RHS);
+ if (!isRHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, LHSExpr);
+ else if (!isLHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc,
+ RHSExpr);
+ else diagnoseArithmeticOnTwoFunctionPointers(S, Loc, LHSExpr, RHSExpr);
return !S.getLangOptions().CPlusPlus;
}
- Expr *Operands[] = { LHS, RHS };
- for (unsigned i = 0; i < 2; ++i) {
- Expr *Operand = Operands[i];
- if ((Operand->getType()->isPointerType() &&
- !Operand->getType()->isDependentType()) ||
- Operand->getType()->isObjCObjectPointerType()) {
- QualType PointeeTy = Operand->getType()->getPointeeType();
- if (S.RequireCompleteType(
- Loc, PointeeTy,
- S.PDiag(diag::err_typecheck_arithmetic_incomplete_type)
- << PointeeTy << Operand->getSourceRange()))
- return false;
- }
- }
+ if (checkArithmeticIncompletePointerType(S, Loc, LHSExpr)) return false;
+ if (checkArithmeticIncompletePointerType(S, Loc, RHSExpr)) return false;
+
return true;
}
+/// \brief Check bad cases where we step over interface counts.
+static bool checkArithmethicPointerOnNonFragileABI(Sema &S,
+ SourceLocation OpLoc,
+ Expr *Op) {
+ assert(Op->getType()->isAnyPointerType());
+ QualType PointeeTy = Op->getType()->getPointeeType();
+ if (!PointeeTy->isObjCObjectType() || !S.LangOpts.ObjCNonFragileABI)
+ return true;
+
+ S.Diag(OpLoc, diag::err_arithmetic_nonfragile_interface)
+ << PointeeTy << Op->getSourceRange();
+ return false;
+}
+
+/// \brief Emit error when two pointers are incompatible.
+static void diagnosePointerIncompatibility(Sema &S, SourceLocation Loc,
+ Expr *LHSExpr, Expr *RHSExpr) {
+ assert(LHSExpr->getType()->isAnyPointerType());
+ assert(RHSExpr->getType()->isAnyPointerType());
+ S.Diag(Loc, diag::err_typecheck_sub_ptr_compatible)
+ << LHSExpr->getType() << RHSExpr->getType() << LHSExpr->getSourceRange()
+ << RHSExpr->getSourceRange();
+}
+
QualType Sema::CheckAdditionOperands( // C99 6.5.6
- ExprResult &lex, ExprResult &rex, SourceLocation Loc, QualType* CompLHSTy) {
- if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
- QualType compType = CheckVectorOperands(lex, rex, Loc, CompLHSTy);
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, QualType* CompLHSTy) {
+ checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
+
+ if (LHS.get()->getType()->isVectorType() ||
+ RHS.get()->getType()->isVectorType()) {
+ QualType compType = CheckVectorOperands(LHS, RHS, Loc, CompLHSTy);
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
- QualType compType = UsualArithmeticConversions(lex, rex, CompLHSTy);
- if (lex.isInvalid() || rex.isInvalid())
+ QualType compType = UsualArithmeticConversions(LHS, RHS, CompLHSTy);
+ if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
// handle the common case first (both operands are arithmetic).
- if (lex.get()->getType()->isArithmeticType() &&
- rex.get()->getType()->isArithmeticType()) {
+ if (LHS.get()->getType()->isArithmeticType() &&
+ RHS.get()->getType()->isArithmeticType()) {
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
// Put any potential pointer into PExp
- Expr* PExp = lex.get(), *IExp = rex.get();
+ Expr* PExp = LHS.get(), *IExp = RHS.get();
if (IExp->getType()->isAnyPointerType())
std::swap(PExp, IExp);
- if (PExp->getType()->isAnyPointerType()) {
- if (IExp->getType()->isIntegerType()) {
- if (!checkArithmeticOpPointerOperand(*this, Loc, PExp))
- return QualType();
+ if (!PExp->getType()->isAnyPointerType())
+ return InvalidOperands(Loc, LHS, RHS);
- QualType PointeeTy = PExp->getType()->getPointeeType();
+ if (!IExp->getType()->isIntegerType())
+ return InvalidOperands(Loc, LHS, RHS);
- // Diagnose bad cases where we step over interface counts.
- if (PointeeTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
- Diag(Loc, diag::err_arithmetic_nonfragile_interface)
- << PointeeTy << PExp->getSourceRange();
- return QualType();
- }
+ if (!checkArithmeticOpPointerOperand(*this, Loc, PExp))
+ return QualType();
- if (CompLHSTy) {
- QualType LHSTy = Context.isPromotableBitField(lex.get());
- if (LHSTy.isNull()) {
- LHSTy = lex.get()->getType();
- if (LHSTy->isPromotableIntegerType())
- LHSTy = Context.getPromotedIntegerType(LHSTy);
- }
- *CompLHSTy = LHSTy;
- }
- return PExp->getType();
+ // Diagnose bad cases where we step over interface counts.
+ if (!checkArithmethicPointerOnNonFragileABI(*this, Loc, PExp))
+ return QualType();
+
+ // Check array bounds for pointer arithemtic
+ CheckArrayAccess(PExp, IExp);
+
+ if (CompLHSTy) {
+ QualType LHSTy = Context.isPromotableBitField(LHS.get());
+ if (LHSTy.isNull()) {
+ LHSTy = LHS.get()->getType();
+ if (LHSTy->isPromotableIntegerType())
+ LHSTy = Context.getPromotedIntegerType(LHSTy);
}
+ *CompLHSTy = LHSTy;
}
- return InvalidOperands(Loc, lex, rex);
+ return PExp->getType();
}
// C99 6.5.6
-QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
- SourceLocation Loc, QualType* CompLHSTy) {
- if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
- QualType compType = CheckVectorOperands(lex, rex, Loc, CompLHSTy);
+QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
+ SourceLocation Loc,
+ QualType* CompLHSTy) {
+ checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
+
+ if (LHS.get()->getType()->isVectorType() ||
+ RHS.get()->getType()->isVectorType()) {
+ QualType compType = CheckVectorOperands(LHS, RHS, Loc, CompLHSTy);
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
- QualType compType = UsualArithmeticConversions(lex, rex, CompLHSTy);
- if (lex.isInvalid() || rex.isInvalid())
+ QualType compType = UsualArithmeticConversions(LHS, RHS, CompLHSTy);
+ if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
// Enforce type constraints: C99 6.5.6p3.
// Handle the common case first (both operands are arithmetic).
- if (lex.get()->getType()->isArithmeticType() &&
- rex.get()->getType()->isArithmeticType()) {
+ if (LHS.get()->getType()->isArithmeticType() &&
+ RHS.get()->getType()->isArithmeticType()) {
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
// Either ptr - int or ptr - ptr.
- if (lex.get()->getType()->isAnyPointerType()) {
- QualType lpointee = lex.get()->getType()->getPointeeType();
+ if (LHS.get()->getType()->isAnyPointerType()) {
+ QualType lpointee = LHS.get()->getType()->getPointeeType();
// Diagnose bad cases where we step over interface counts.
- if (lpointee->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
- Diag(Loc, diag::err_arithmetic_nonfragile_interface)
- << lpointee << lex.get()->getSourceRange();
+ if (!checkArithmethicPointerOnNonFragileABI(*this, Loc, LHS.get()))
return QualType();
- }
// The result type of a pointer-int computation is the pointer type.
- if (rex.get()->getType()->isIntegerType()) {
- if (!checkArithmeticOpPointerOperand(*this, Loc, lex.get()))
+ if (RHS.get()->getType()->isIntegerType()) {
+ if (!checkArithmeticOpPointerOperand(*this, Loc, LHS.get()))
return QualType();
- if (CompLHSTy) *CompLHSTy = lex.get()->getType();
- return lex.get()->getType();
+ Expr *IExpr = RHS.get()->IgnoreParenCasts();
+ UnaryOperator negRex(IExpr, UO_Minus, IExpr->getType(), VK_RValue,
+ OK_Ordinary, IExpr->getExprLoc());
+ // Check array bounds for pointer arithemtic
+ CheckArrayAccess(LHS.get()->IgnoreParenCasts(), &negRex);
+
+ if (CompLHSTy) *CompLHSTy = LHS.get()->getType();
+ return LHS.get()->getType();
}
// Handle pointer-pointer subtractions.
- if (const PointerType *RHSPTy = rex.get()->getType()->getAs<PointerType>()) {
+ if (const PointerType *RHSPTy
+ = RHS.get()->getType()->getAs<PointerType>()) {
QualType rpointee = RHSPTy->getPointeeType();
if (getLangOptions().CPlusPlus) {
// Pointee types must be the same: C++ [expr.add]
if (!Context.hasSameUnqualifiedType(lpointee, rpointee)) {
- Diag(Loc, diag::err_typecheck_sub_ptr_compatible)
- << lex.get()->getType() << rex.get()->getType()
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- return QualType();
+ diagnosePointerIncompatibility(*this, Loc, LHS.get(), RHS.get());
}
} else {
// Pointee types must be compatible C99 6.5.6p3
if (!Context.typesAreCompatible(
Context.getCanonicalType(lpointee).getUnqualifiedType(),
Context.getCanonicalType(rpointee).getUnqualifiedType())) {
- Diag(Loc, diag::err_typecheck_sub_ptr_compatible)
- << lex.get()->getType() << rex.get()->getType()
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
+ diagnosePointerIncompatibility(*this, Loc, LHS.get(), RHS.get());
return QualType();
}
}
if (!checkArithmeticBinOpPointerOperands(*this, Loc,
- lex.get(), rex.get()))
+ LHS.get(), RHS.get()))
return QualType();
- if (CompLHSTy) *CompLHSTy = lex.get()->getType();
+ if (CompLHSTy) *CompLHSTy = LHS.get()->getType();
return Context.getPointerDiffType();
}
}
- return InvalidOperands(Loc, lex, rex);
+ return InvalidOperands(Loc, LHS, RHS);
}
static bool isScopedEnumerationType(QualType T) {
@@ -5913,26 +6087,27 @@ static bool isScopedEnumerationType(QualType T) {
return false;
}
-static void DiagnoseBadShiftValues(Sema& S, ExprResult &lex, ExprResult &rex,
+static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, unsigned Opc,
- QualType LHSTy) {
+ QualType LHSType) {
llvm::APSInt Right;
// Check right/shifter operand
- if (rex.get()->isValueDependent() || !rex.get()->isIntegerConstantExpr(Right, S.Context))
+ if (RHS.get()->isValueDependent() ||
+ !RHS.get()->isIntegerConstantExpr(Right, S.Context))
return;
if (Right.isNegative()) {
- S.DiagRuntimeBehavior(Loc, rex.get(),
+ S.DiagRuntimeBehavior(Loc, RHS.get(),
S.PDiag(diag::warn_shift_negative)
- << rex.get()->getSourceRange());
+ << RHS.get()->getSourceRange());
return;
}
llvm::APInt LeftBits(Right.getBitWidth(),
- S.Context.getTypeSize(lex.get()->getType()));
+ S.Context.getTypeSize(LHS.get()->getType()));
if (Right.uge(LeftBits)) {
- S.DiagRuntimeBehavior(Loc, rex.get(),
+ S.DiagRuntimeBehavior(Loc, RHS.get(),
S.PDiag(diag::warn_shift_gt_typewidth)
- << rex.get()->getSourceRange());
+ << RHS.get()->getSourceRange());
return;
}
if (Opc != BO_Shl)
@@ -5943,8 +6118,9 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &lex, ExprResult &rex,
// integers have defined behavior modulo one more than the maximum value
// representable in the result type, so never warn for those.
llvm::APSInt Left;
- if (lex.get()->isValueDependent() || !lex.get()->isIntegerConstantExpr(Left, S.Context) ||
- LHSTy->hasUnsignedIntegerRepresentation())
+ if (LHS.get()->isValueDependent() ||
+ !LHS.get()->isIntegerConstantExpr(Left, S.Context) ||
+ LHSType->hasUnsignedIntegerRepresentation())
return;
llvm::APInt ResultBits =
static_cast<llvm::APInt&>(Right) + Left.getMinSignedBits();
@@ -5964,57 +6140,62 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &lex, ExprResult &rex,
// turned off separately if needed.
if (LeftBits == ResultBits - 1) {
S.Diag(Loc, diag::warn_shift_result_sets_sign_bit)
- << HexResult.str() << LHSTy
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
+ << HexResult.str() << LHSType
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return;
}
S.Diag(Loc, diag::warn_shift_result_gt_typewidth)
- << HexResult.str() << Result.getMinSignedBits() << LHSTy
- << Left.getBitWidth() << lex.get()->getSourceRange() << rex.get()->getSourceRange();
+ << HexResult.str() << Result.getMinSignedBits() << LHSType
+ << Left.getBitWidth() << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
}
// C99 6.5.7
-QualType Sema::CheckShiftOperands(ExprResult &lex, ExprResult &rex, SourceLocation Loc,
- unsigned Opc, bool isCompAssign) {
+QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS,
+ SourceLocation Loc, unsigned Opc,
+ bool IsCompAssign) {
+ checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
+
// C99 6.5.7p2: Each of the operands shall have integer type.
- if (!lex.get()->getType()->hasIntegerRepresentation() ||
- !rex.get()->getType()->hasIntegerRepresentation())
- return InvalidOperands(Loc, lex, rex);
+ if (!LHS.get()->getType()->hasIntegerRepresentation() ||
+ !RHS.get()->getType()->hasIntegerRepresentation())
+ return InvalidOperands(Loc, LHS, RHS);
// C++0x: Don't allow scoped enums. FIXME: Use something better than
// hasIntegerRepresentation() above instead of this.
- if (isScopedEnumerationType(lex.get()->getType()) ||
- isScopedEnumerationType(rex.get()->getType())) {
- return InvalidOperands(Loc, lex, rex);
+ if (isScopedEnumerationType(LHS.get()->getType()) ||
+ isScopedEnumerationType(RHS.get()->getType())) {
+ return InvalidOperands(Loc, LHS, RHS);
}
// Vector shifts promote their scalar inputs to vector type.
- if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType())
- return CheckVectorOperands(lex, rex, Loc, isCompAssign);
+ if (LHS.get()->getType()->isVectorType() ||
+ RHS.get()->getType()->isVectorType())
+ return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign);
// Shifts don't perform usual arithmetic conversions, they just do integer
// promotions on each operand. C99 6.5.7p3
// For the LHS, do usual unary conversions, but then reset them away
// if this is a compound assignment.
- ExprResult old_lex = lex;
- lex = UsualUnaryConversions(lex.take());
- if (lex.isInvalid())
+ ExprResult OldLHS = LHS;
+ LHS = UsualUnaryConversions(LHS.take());
+ if (LHS.isInvalid())
return QualType();
- QualType LHSTy = lex.get()->getType();
- if (isCompAssign) lex = old_lex;
+ QualType LHSType = LHS.get()->getType();
+ if (IsCompAssign) LHS = OldLHS;
// The RHS is simpler.
- rex = UsualUnaryConversions(rex.take());
- if (rex.isInvalid())
+ RHS = UsualUnaryConversions(RHS.take());
+ if (RHS.isInvalid())
return QualType();
// Sanity-check shift operands
- DiagnoseBadShiftValues(*this, lex, rex, Loc, Opc, LHSTy);
+ DiagnoseBadShiftValues(*this, LHS, RHS, Loc, Opc, LHSType);
// "The type of the result is that of the promoted left operand."
- return LHSTy;
+ return LHSType;
}
static bool IsWithinTemplateSpecialization(Decl *D) {
@@ -6027,42 +6208,125 @@ static bool IsWithinTemplateSpecialization(Decl *D) {
return false;
}
+/// 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();
+
+ const EnumType *LHSEnumType = LHSStrippedType->getAs<EnumType>();
+ if (!LHSEnumType)
+ return;
+ const EnumType *RHSEnumType = RHSStrippedType->getAs<EnumType>();
+ if (!RHSEnumType)
+ return;
+
+ // Ignore anonymous enums.
+ if (!LHSEnumType->getDecl()->getIdentifier())
+ return;
+ if (!RHSEnumType->getDecl()->getIdentifier())
+ return;
+
+ if (S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType))
+ return;
+
+ S.Diag(Loc, diag::warn_comparison_of_mixed_enum_types)
+ << LHSStrippedType << RHSStrippedType
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+}
+
+/// \brief Diagnose bad pointer comparisons.
+static void diagnoseDistinctPointerComparison(Sema &S, SourceLocation Loc,
+ ExprResult &LHS, ExprResult &RHS,
+ bool IsError) {
+ S.Diag(Loc, IsError ? diag::err_typecheck_comparison_of_distinct_pointers
+ : diag::ext_typecheck_comparison_of_distinct_pointers)
+ << LHS.get()->getType() << RHS.get()->getType()
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+}
+
+/// \brief Returns false if the pointers are converted to a composite type,
+/// true otherwise.
+static bool convertPointersToCompositeType(Sema &S, SourceLocation Loc,
+ ExprResult &LHS, ExprResult &RHS) {
+ // C++ [expr.rel]p2:
+ // [...] Pointer conversions (4.10) and qualification
+ // conversions (4.4) are performed on pointer operands (or on
+ // a pointer operand and a null pointer constant) to bring
+ // them to their composite pointer type. [...]
+ //
+ // C++ [expr.eq]p1 uses the same notion for (in)equality
+ // comparisons of pointers.
+
+ // C++ [expr.eq]p2:
+ // In addition, pointers to members can be compared, or a pointer to
+ // member and a null pointer constant. Pointer to member conversions
+ // (4.11) and qualification conversions (4.4) are performed to bring
+ // them to a common type. If one operand is a null pointer constant,
+ // the common type is the type of the other operand. Otherwise, the
+ // common type is a pointer to member type similar (4.4) to the type
+ // of one of the operands, with a cv-qualification signature (4.4)
+ // that is the union of the cv-qualification signatures of the operand
+ // types.
+
+ QualType LHSType = LHS.get()->getType();
+ QualType RHSType = RHS.get()->getType();
+ assert((LHSType->isPointerType() && RHSType->isPointerType()) ||
+ (LHSType->isMemberPointerType() && RHSType->isMemberPointerType()));
+
+ bool NonStandardCompositeType = false;
+ bool *BoolPtr = S.isSFINAEContext() ? 0 : &NonStandardCompositeType;
+ QualType T = S.FindCompositePointerType(Loc, LHS, RHS, BoolPtr);
+ if (T.isNull()) {
+ diagnoseDistinctPointerComparison(S, Loc, LHS, RHS, /*isError*/true);
+ return true;
+ }
+
+ if (NonStandardCompositeType)
+ S.Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard)
+ << LHSType << RHSType << T << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
+
+ LHS = S.ImpCastExprToType(LHS.take(), T, CK_BitCast);
+ RHS = S.ImpCastExprToType(RHS.take(), T, CK_BitCast);
+ return false;
+}
+
+static void diagnoseFunctionPointerToVoidComparison(Sema &S, SourceLocation Loc,
+ ExprResult &LHS,
+ ExprResult &RHS,
+ bool IsError) {
+ S.Diag(Loc, IsError ? diag::err_typecheck_comparison_of_fptr_to_void
+ : diag::ext_typecheck_comparison_of_fptr_to_void)
+ << LHS.get()->getType() << RHS.get()->getType()
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+}
+
// C99 6.5.8, C++ [expr.rel]
-QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLocation Loc,
- unsigned OpaqueOpc, bool isRelational) {
+QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
+ SourceLocation Loc, unsigned OpaqueOpc,
+ bool IsRelational) {
+ checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/true);
+
BinaryOperatorKind Opc = (BinaryOperatorKind) OpaqueOpc;
// Handle vector comparisons separately.
- if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType())
- return CheckVectorCompareOperands(lex, rex, Loc, isRelational);
+ if (LHS.get()->getType()->isVectorType() ||
+ RHS.get()->getType()->isVectorType())
+ return CheckVectorCompareOperands(LHS, RHS, Loc, IsRelational);
- QualType lType = lex.get()->getType();
- QualType rType = rex.get()->getType();
-
- Expr *LHSStripped = lex.get()->IgnoreParenImpCasts();
- Expr *RHSStripped = rex.get()->IgnoreParenImpCasts();
- QualType LHSStrippedType = LHSStripped->getType();
- QualType RHSStrippedType = RHSStripped->getType();
+ QualType LHSType = LHS.get()->getType();
+ QualType RHSType = RHS.get()->getType();
-
+ Expr *LHSStripped = LHS.get()->IgnoreParenImpCasts();
+ Expr *RHSStripped = RHS.get()->IgnoreParenImpCasts();
- // Two different enums will raise a warning when compared.
- if (const EnumType *LHSEnumType = LHSStrippedType->getAs<EnumType>()) {
- if (const EnumType *RHSEnumType = RHSStrippedType->getAs<EnumType>()) {
- if (LHSEnumType->getDecl()->getIdentifier() &&
- RHSEnumType->getDecl()->getIdentifier() &&
- !Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType)) {
- Diag(Loc, diag::warn_comparison_of_mixed_enum_types)
- << LHSStrippedType << RHSStrippedType
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- }
- }
- }
+ checkEnumComparison(*this, Loc, LHS, RHS);
- if (!lType->hasFloatingRepresentation() &&
- !(lType->isBlockPointerType() && isRelational) &&
- !lex.get()->getLocStart().isMacroID() &&
- !rex.get()->getLocStart().isMacroID()) {
+ if (!LHSType->hasFloatingRepresentation() &&
+ !(LHSType->isBlockPointerType() && IsRelational) &&
+ !LHS.get()->getLocStart().isMacroID() &&
+ !RHS.get()->getLocStart().isMacroID()) {
// For non-floating point types, check for self-comparisons of the form
// x == x, x != x, x < x, etc. These always evaluate to a constant, and
// often indicate logic errors in the program.
@@ -6082,7 +6346,7 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca
<< (Opc == BO_EQ
|| Opc == BO_LE
|| Opc == BO_GE));
- } else if (lType->isArrayType() && rType->isArrayType() &&
+ } else if (LHSType->isArrayType() && RHSType->isArrayType() &&
!DRL->getDecl()->getType()->isReferenceType() &&
!DRR->getDecl()->getType()->isReferenceType()) {
// what is it always going to eval to?
@@ -6118,13 +6382,13 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca
if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) &&
!RHSStripped->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
- literalString = lex.get();
+ literalString = LHS.get();
literalStringStripped = LHSStripped;
} else if ((isa<StringLiteral>(RHSStripped) ||
isa<ObjCEncodeExpr>(RHSStripped)) &&
!LHSStripped->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
- literalString = rex.get();
+ literalString = RHS.get();
literalStringStripped = RHSStripped;
}
@@ -6137,7 +6401,7 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca
case BO_GE: resultComparison = ") >= 0"; break;
case BO_EQ: resultComparison = ") == 0"; break;
case BO_NE: resultComparison = ") != 0"; break;
- default: assert(false && "Invalid comparison operator");
+ default: llvm_unreachable("Invalid comparison operator");
}
DiagRuntimeBehavior(Loc, 0,
@@ -6148,56 +6412,57 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca
}
// C99 6.5.8p3 / C99 6.5.9p4
- if (lex.get()->getType()->isArithmeticType() && rex.get()->getType()->isArithmeticType()) {
- UsualArithmeticConversions(lex, rex);
- if (lex.isInvalid() || rex.isInvalid())
+ if (LHS.get()->getType()->isArithmeticType() &&
+ RHS.get()->getType()->isArithmeticType()) {
+ UsualArithmeticConversions(LHS, RHS);
+ if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
}
else {
- lex = UsualUnaryConversions(lex.take());
- if (lex.isInvalid())
+ LHS = UsualUnaryConversions(LHS.take());
+ if (LHS.isInvalid())
return QualType();
- rex = UsualUnaryConversions(rex.take());
- if (rex.isInvalid())
+ RHS = UsualUnaryConversions(RHS.take());
+ if (RHS.isInvalid())
return QualType();
}
- lType = lex.get()->getType();
- rType = rex.get()->getType();
+ LHSType = LHS.get()->getType();
+ RHSType = RHS.get()->getType();
// The result of comparisons is 'bool' in C++, 'int' in C.
QualType ResultTy = Context.getLogicalOperationType();
- if (isRelational) {
- if (lType->isRealType() && rType->isRealType())
+ if (IsRelational) {
+ if (LHSType->isRealType() && RHSType->isRealType())
return ResultTy;
} else {
// Check for comparisons of floating point operands using != and ==.
- if (lType->hasFloatingRepresentation())
- CheckFloatComparison(Loc, lex.get(), rex.get());
+ if (LHSType->hasFloatingRepresentation())
+ CheckFloatComparison(Loc, LHS.get(), RHS.get());
- if (lType->isArithmeticType() && rType->isArithmeticType())
+ if (LHSType->isArithmeticType() && RHSType->isArithmeticType())
return ResultTy;
}
- bool LHSIsNull = lex.get()->isNullPointerConstant(Context,
+ bool LHSIsNull = LHS.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull);
- bool RHSIsNull = rex.get()->isNullPointerConstant(Context,
+ bool RHSIsNull = RHS.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull);
// All of the following pointer-related warnings are GCC extensions, except
// when handling null pointer constants.
- if (lType->isPointerType() && rType->isPointerType()) { // C99 6.5.8p2
+ if (LHSType->isPointerType() && RHSType->isPointerType()) { // C99 6.5.8p2
QualType LCanPointeeTy =
- Context.getCanonicalType(lType->getAs<PointerType>()->getPointeeType());
+ LHSType->castAs<PointerType>()->getPointeeType().getCanonicalType();
QualType RCanPointeeTy =
- Context.getCanonicalType(rType->getAs<PointerType>()->getPointeeType());
+ RHSType->castAs<PointerType>()->getPointeeType().getCanonicalType();
if (getLangOptions().CPlusPlus) {
if (LCanPointeeTy == RCanPointeeTy)
return ResultTy;
- if (!isRelational &&
+ if (!IsRelational &&
(LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) {
// Valid unless comparison between non-null pointer and function pointer
// This is a gcc extension compatibility comparison.
@@ -6205,214 +6470,178 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca
// conformance with the C++ standard.
if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType())
&& !LHSIsNull && !RHSIsNull) {
- Diag(Loc,
- isSFINAEContext()?
- diag::err_typecheck_comparison_of_fptr_to_void
- : diag::ext_typecheck_comparison_of_fptr_to_void)
- << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
+ diagnoseFunctionPointerToVoidComparison(
+ *this, Loc, LHS, RHS, /*isError*/ isSFINAEContext());
if (isSFINAEContext())
return QualType();
- rex = ImpCastExprToType(rex.take(), lType, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
return ResultTy;
}
}
- // C++ [expr.rel]p2:
- // [...] Pointer conversions (4.10) and qualification
- // conversions (4.4) are performed on pointer operands (or on
- // a pointer operand and a null pointer constant) to bring
- // them to their composite pointer type. [...]
- //
- // C++ [expr.eq]p1 uses the same notion for (in)equality
- // comparisons of pointers.
- bool NonStandardCompositeType = false;
- QualType T = FindCompositePointerType(Loc, lex, rex,
- isSFINAEContext()? 0 : &NonStandardCompositeType);
- if (T.isNull()) {
- Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers)
- << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
+ if (convertPointersToCompositeType(*this, Loc, LHS, RHS))
return QualType();
- } else if (NonStandardCompositeType) {
- Diag(Loc,
- diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard)
- << lType << rType << T
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- }
-
- lex = ImpCastExprToType(lex.take(), T, CK_BitCast);
- rex = ImpCastExprToType(rex.take(), T, CK_BitCast);
- return ResultTy;
+ else
+ return ResultTy;
}
// C99 6.5.9p2 and C99 6.5.8p2
if (Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(),
RCanPointeeTy.getUnqualifiedType())) {
// Valid unless a relational comparison of function pointers
- if (isRelational && LCanPointeeTy->isFunctionType()) {
+ if (IsRelational && LCanPointeeTy->isFunctionType()) {
Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers)
- << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
+ << LHSType << RHSType << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
}
- } else if (!isRelational &&
+ } else if (!IsRelational &&
(LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) {
// Valid unless comparison between non-null pointer and function pointer
if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType())
- && !LHSIsNull && !RHSIsNull) {
- Diag(Loc, diag::ext_typecheck_comparison_of_fptr_to_void)
- << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- }
+ && !LHSIsNull && !RHSIsNull)
+ diagnoseFunctionPointerToVoidComparison(*this, Loc, LHS, RHS,
+ /*isError*/false);
} else {
// Invalid
- Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
- << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
+ diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS, /*isError*/false);
}
if (LCanPointeeTy != RCanPointeeTy) {
if (LHSIsNull && !RHSIsNull)
- lex = ImpCastExprToType(lex.take(), rType, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.take(), RHSType, CK_BitCast);
else
- rex = ImpCastExprToType(rex.take(), lType, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
}
return ResultTy;
}
if (getLangOptions().CPlusPlus) {
// Comparison of nullptr_t with itself.
- if (lType->isNullPtrType() && rType->isNullPtrType())
+ if (LHSType->isNullPtrType() && RHSType->isNullPtrType())
return ResultTy;
// Comparison of pointers with null pointer constants and equality
// comparisons of member pointers to null pointer constants.
if (RHSIsNull &&
- ((lType->isAnyPointerType() || lType->isNullPtrType()) ||
- (!isRelational &&
- (lType->isMemberPointerType() || lType->isBlockPointerType())))) {
- rex = ImpCastExprToType(rex.take(), lType,
- lType->isMemberPointerType()
+ ((LHSType->isAnyPointerType() || LHSType->isNullPtrType()) ||
+ (!IsRelational &&
+ (LHSType->isMemberPointerType() || LHSType->isBlockPointerType())))) {
+ RHS = ImpCastExprToType(RHS.take(), LHSType,
+ LHSType->isMemberPointerType()
? CK_NullToMemberPointer
: CK_NullToPointer);
return ResultTy;
}
if (LHSIsNull &&
- ((rType->isAnyPointerType() || rType->isNullPtrType()) ||
- (!isRelational &&
- (rType->isMemberPointerType() || rType->isBlockPointerType())))) {
- lex = ImpCastExprToType(lex.take(), rType,
- rType->isMemberPointerType()
+ ((RHSType->isAnyPointerType() || RHSType->isNullPtrType()) ||
+ (!IsRelational &&
+ (RHSType->isMemberPointerType() || RHSType->isBlockPointerType())))) {
+ LHS = ImpCastExprToType(LHS.take(), RHSType,
+ RHSType->isMemberPointerType()
? CK_NullToMemberPointer
: CK_NullToPointer);
return ResultTy;
}
// Comparison of member pointers.
- if (!isRelational &&
- lType->isMemberPointerType() && rType->isMemberPointerType()) {
- // C++ [expr.eq]p2:
- // In addition, pointers to members can be compared, or a pointer to
- // member and a null pointer constant. Pointer to member conversions
- // (4.11) and qualification conversions (4.4) are performed to bring
- // them to a common type. If one operand is a null pointer constant,
- // the common type is the type of the other operand. Otherwise, the
- // common type is a pointer to member type similar (4.4) to the type
- // of one of the operands, with a cv-qualification signature (4.4)
- // that is the union of the cv-qualification signatures of the operand
- // types.
- bool NonStandardCompositeType = false;
- QualType T = FindCompositePointerType(Loc, lex, rex,
- isSFINAEContext()? 0 : &NonStandardCompositeType);
- if (T.isNull()) {
- Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers)
- << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
+ if (!IsRelational &&
+ LHSType->isMemberPointerType() && RHSType->isMemberPointerType()) {
+ if (convertPointersToCompositeType(*this, Loc, LHS, RHS))
return QualType();
- } else if (NonStandardCompositeType) {
- Diag(Loc,
- diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard)
- << lType << rType << T
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- }
-
- lex = ImpCastExprToType(lex.take(), T, CK_BitCast);
- rex = ImpCastExprToType(rex.take(), T, CK_BitCast);
- return ResultTy;
+ else
+ return ResultTy;
}
// Handle scoped enumeration types specifically, since they don't promote
// to integers.
- if (lex.get()->getType()->isEnumeralType() &&
- Context.hasSameUnqualifiedType(lex.get()->getType(), rex.get()->getType()))
+ if (LHS.get()->getType()->isEnumeralType() &&
+ Context.hasSameUnqualifiedType(LHS.get()->getType(),
+ RHS.get()->getType()))
return ResultTy;
}
// Handle block pointer types.
- if (!isRelational && lType->isBlockPointerType() && rType->isBlockPointerType()) {
- QualType lpointee = lType->getAs<BlockPointerType>()->getPointeeType();
- QualType rpointee = rType->getAs<BlockPointerType>()->getPointeeType();
+ if (!IsRelational && LHSType->isBlockPointerType() &&
+ RHSType->isBlockPointerType()) {
+ QualType lpointee = LHSType->castAs<BlockPointerType>()->getPointeeType();
+ QualType rpointee = RHSType->castAs<BlockPointerType>()->getPointeeType();
if (!LHSIsNull && !RHSIsNull &&
!Context.typesAreCompatible(lpointee, rpointee)) {
Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks)
- << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
+ << LHSType << RHSType << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
}
- rex = ImpCastExprToType(rex.take(), lType, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
return ResultTy;
}
// Allow block pointers to be compared with null pointer constants.
- if (!isRelational
- && ((lType->isBlockPointerType() && rType->isPointerType())
- || (lType->isPointerType() && rType->isBlockPointerType()))) {
+ if (!IsRelational
+ && ((LHSType->isBlockPointerType() && RHSType->isPointerType())
+ || (LHSType->isPointerType() && RHSType->isBlockPointerType()))) {
if (!LHSIsNull && !RHSIsNull) {
- if (!((rType->isPointerType() && rType->castAs<PointerType>()
+ if (!((RHSType->isPointerType() && RHSType->castAs<PointerType>()
->getPointeeType()->isVoidType())
- || (lType->isPointerType() && lType->castAs<PointerType>()
+ || (LHSType->isPointerType() && LHSType->castAs<PointerType>()
->getPointeeType()->isVoidType())))
Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks)
- << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
+ << LHSType << RHSType << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
}
if (LHSIsNull && !RHSIsNull)
- lex = ImpCastExprToType(lex.take(), rType, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.take(), RHSType,
+ RHSType->isPointerType() ? CK_BitCast
+ : CK_AnyPointerToBlockPointerCast);
else
- rex = ImpCastExprToType(rex.take(), lType, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.take(), LHSType,
+ LHSType->isPointerType() ? CK_BitCast
+ : CK_AnyPointerToBlockPointerCast);
return ResultTy;
}
- if (lType->isObjCObjectPointerType() || rType->isObjCObjectPointerType()) {
- const PointerType *LPT = lType->getAs<PointerType>();
- const PointerType *RPT = rType->getAs<PointerType>();
+ if (LHSType->isObjCObjectPointerType() ||
+ RHSType->isObjCObjectPointerType()) {
+ const PointerType *LPT = LHSType->getAs<PointerType>();
+ const PointerType *RPT = RHSType->getAs<PointerType>();
if (LPT || RPT) {
bool LPtrToVoid = LPT ? LPT->getPointeeType()->isVoidType() : false;
bool RPtrToVoid = RPT ? RPT->getPointeeType()->isVoidType() : false;
if (!LPtrToVoid && !RPtrToVoid &&
- !Context.typesAreCompatible(lType, rType)) {
- Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
- << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
+ !Context.typesAreCompatible(LHSType, RHSType)) {
+ diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS,
+ /*isError*/false);
}
if (LHSIsNull && !RHSIsNull)
- lex = ImpCastExprToType(lex.take(), rType, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.take(), RHSType,
+ RPT ? CK_BitCast :CK_CPointerToObjCPointerCast);
else
- rex = ImpCastExprToType(rex.take(), lType, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.take(), LHSType,
+ LPT ? CK_BitCast :CK_CPointerToObjCPointerCast);
return ResultTy;
}
- if (lType->isObjCObjectPointerType() && rType->isObjCObjectPointerType()) {
- if (!Context.areComparableObjCPointerTypes(lType, rType))
- Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
- << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
+ if (LHSType->isObjCObjectPointerType() &&
+ RHSType->isObjCObjectPointerType()) {
+ if (!Context.areComparableObjCPointerTypes(LHSType, RHSType))
+ diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS,
+ /*isError*/false);
if (LHSIsNull && !RHSIsNull)
- lex = ImpCastExprToType(lex.take(), rType, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.take(), RHSType, CK_BitCast);
else
- rex = ImpCastExprToType(rex.take(), lType, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
return ResultTy;
}
}
- if ((lType->isAnyPointerType() && rType->isIntegerType()) ||
- (lType->isIntegerType() && rType->isAnyPointerType())) {
+ if ((LHSType->isAnyPointerType() && RHSType->isIntegerType()) ||
+ (LHSType->isIntegerType() && RHSType->isAnyPointerType())) {
unsigned DiagID = 0;
bool isError = false;
- if ((LHSIsNull && lType->isIntegerType()) ||
- (RHSIsNull && rType->isIntegerType())) {
- if (isRelational && !getLangOptions().CPlusPlus)
+ if ((LHSIsNull && LHSType->isIntegerType()) ||
+ (RHSIsNull && RHSType->isIntegerType())) {
+ if (IsRelational && !getLangOptions().CPlusPlus)
DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_and_zero;
- } else if (isRelational && !getLangOptions().CPlusPlus)
+ } else if (IsRelational && !getLangOptions().CPlusPlus)
DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer;
else if (getLangOptions().CPlusPlus) {
DiagID = diag::err_typecheck_comparison_of_pointer_integer;
@@ -6422,50 +6651,51 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca
if (DiagID) {
Diag(Loc, DiagID)
- << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
+ << LHSType << RHSType << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
if (isError)
return QualType();
}
- if (lType->isIntegerType())
- lex = ImpCastExprToType(lex.take(), rType,
+ if (LHSType->isIntegerType())
+ LHS = ImpCastExprToType(LHS.take(), RHSType,
LHSIsNull ? CK_NullToPointer : CK_IntegralToPointer);
else
- rex = ImpCastExprToType(rex.take(), lType,
+ RHS = ImpCastExprToType(RHS.take(), LHSType,
RHSIsNull ? CK_NullToPointer : CK_IntegralToPointer);
return ResultTy;
}
// Handle block pointers.
- if (!isRelational && RHSIsNull
- && lType->isBlockPointerType() && rType->isIntegerType()) {
- rex = ImpCastExprToType(rex.take(), lType, CK_NullToPointer);
+ if (!IsRelational && RHSIsNull
+ && LHSType->isBlockPointerType() && RHSType->isIntegerType()) {
+ RHS = ImpCastExprToType(RHS.take(), LHSType, CK_NullToPointer);
return ResultTy;
}
- if (!isRelational && LHSIsNull
- && lType->isIntegerType() && rType->isBlockPointerType()) {
- lex = ImpCastExprToType(lex.take(), rType, CK_NullToPointer);
+ if (!IsRelational && LHSIsNull
+ && LHSType->isIntegerType() && RHSType->isBlockPointerType()) {
+ LHS = ImpCastExprToType(LHS.take(), RHSType, CK_NullToPointer);
return ResultTy;
}
- return InvalidOperands(Loc, lex, rex);
+ return InvalidOperands(Loc, LHS, RHS);
}
/// CheckVectorCompareOperands - vector comparisons are a clang extension that
/// operates on extended vector types. Instead of producing an IntTy result,
/// like a scalar comparison, a vector comparison produces a vector of integer
/// types.
-QualType Sema::CheckVectorCompareOperands(ExprResult &lex, ExprResult &rex,
+QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc,
- bool isRelational) {
+ bool IsRelational) {
// Check to make sure we're operating on vectors of the same type and width,
// Allowing one side to be a scalar of element type.
- QualType vType = CheckVectorOperands(lex, rex, Loc, /*isCompAssign*/false);
+ QualType vType = CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/false);
if (vType.isNull())
return vType;
- QualType lType = lex.get()->getType();
- QualType rType = rex.get()->getType();
+ QualType LHSType = LHS.get()->getType();
+ QualType RHSType = RHS.get()->getType();
// If AltiVec, the comparison results in a numeric type, i.e.
// bool for C++, int for C
@@ -6475,9 +6705,9 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &lex, ExprResult &rex,
// For non-floating point types, check for self-comparisons of the form
// x == x, x != x, x < x, etc. These always evaluate to a constant, and
// often indicate logic errors in the program.
- if (!lType->hasFloatingRepresentation()) {
- if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(lex.get()->IgnoreParens()))
- if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(rex.get()->IgnoreParens()))
+ if (!LHSType->hasFloatingRepresentation()) {
+ if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LHS.get()->IgnoreParens()))
+ if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHS.get()->IgnoreParens()))
if (DRL->getDecl() == DRR->getDecl())
DiagRuntimeBehavior(Loc, 0,
PDiag(diag::warn_comparison_always)
@@ -6487,18 +6717,18 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &lex, ExprResult &rex,
}
// Check for comparisons of floating point operands using != and ==.
- if (!isRelational && lType->hasFloatingRepresentation()) {
- assert (rType->hasFloatingRepresentation());
- CheckFloatComparison(Loc, lex.get(), rex.get());
+ if (!IsRelational && LHSType->hasFloatingRepresentation()) {
+ assert (RHSType->hasFloatingRepresentation());
+ CheckFloatComparison(Loc, LHS.get(), RHS.get());
}
// Return the type for the comparison, which is the same as vector type for
// integer vectors, or an integer type of identical size and number of
// elements for floating point vectors.
- if (lType->hasIntegerRepresentation())
- return lType;
+ if (LHSType->hasIntegerRepresentation())
+ return LHSType;
- const VectorType *VTy = lType->getAs<VectorType>();
+ const VectorType *VTy = LHSType->getAs<VectorType>();
unsigned TypeSize = Context.getTypeSize(VTy->getElementType());
if (TypeSize == Context.getTypeSize(Context.IntTy))
return Context.getExtVectorType(Context.IntTy, VTy->getNumElements());
@@ -6511,36 +6741,41 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &lex, ExprResult &rex,
}
inline QualType Sema::CheckBitwiseOperands(
- ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign) {
- if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
- if (lex.get()->getType()->hasIntegerRepresentation() &&
- rex.get()->getType()->hasIntegerRepresentation())
- return CheckVectorOperands(lex, rex, Loc, isCompAssign);
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign) {
+ checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
+
+ if (LHS.get()->getType()->isVectorType() ||
+ RHS.get()->getType()->isVectorType()) {
+ if (LHS.get()->getType()->hasIntegerRepresentation() &&
+ RHS.get()->getType()->hasIntegerRepresentation())
+ return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign);
- return InvalidOperands(Loc, lex, rex);
+ return InvalidOperands(Loc, LHS, RHS);
}
- ExprResult lexResult = Owned(lex), rexResult = Owned(rex);
- QualType compType = UsualArithmeticConversions(lexResult, rexResult, isCompAssign);
- if (lexResult.isInvalid() || rexResult.isInvalid())
+ ExprResult LHSResult = Owned(LHS), RHSResult = Owned(RHS);
+ QualType compType = UsualArithmeticConversions(LHSResult, RHSResult,
+ IsCompAssign);
+ if (LHSResult.isInvalid() || RHSResult.isInvalid())
return QualType();
- lex = lexResult.take();
- rex = rexResult.take();
+ LHS = LHSResult.take();
+ RHS = RHSResult.take();
- if (lex.get()->getType()->isIntegralOrUnscopedEnumerationType() &&
- rex.get()->getType()->isIntegralOrUnscopedEnumerationType())
+ if (LHS.get()->getType()->isIntegralOrUnscopedEnumerationType() &&
+ RHS.get()->getType()->isIntegralOrUnscopedEnumerationType())
return compType;
- return InvalidOperands(Loc, lex, rex);
+ return InvalidOperands(Loc, LHS, RHS);
}
inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
- ExprResult &lex, ExprResult &rex, SourceLocation Loc, unsigned Opc) {
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc) {
// Diagnose cases where the user write a logical and/or but probably meant a
// bitwise one. We do this when the LHS is a non-bool integer and the RHS
// is a constant.
- if (lex.get()->getType()->isIntegerType() && !lex.get()->getType()->isBooleanType() &&
- rex.get()->getType()->isIntegerType() && !rex.get()->isValueDependent() &&
+ if (LHS.get()->getType()->isIntegerType() &&
+ !LHS.get()->getType()->isBooleanType() &&
+ RHS.get()->getType()->isIntegerType() && !RHS.get()->isValueDependent() &&
// Don't warn in macros or template instantiations.
!Loc.isMacroID() && ActiveTemplateInstantiations.empty()) {
// If the RHS can be constant folded, and if it constant folds to something
@@ -6548,27 +6783,43 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
// happened to fold to true/false) then warn.
// Parens on the RHS are ignored.
Expr::EvalResult Result;
- if (rex.get()->Evaluate(Result, Context) && !Result.HasSideEffects)
- if ((getLangOptions().Bool && !rex.get()->getType()->isBooleanType()) ||
+ if (RHS.get()->Evaluate(Result, Context) && !Result.HasSideEffects)
+ if ((getLangOptions().Bool && !RHS.get()->getType()->isBooleanType()) ||
(Result.Val.getInt() != 0 && Result.Val.getInt() != 1)) {
Diag(Loc, diag::warn_logical_instead_of_bitwise)
- << rex.get()->getSourceRange()
- << (Opc == BO_LAnd ? "&&" : "||")
- << (Opc == BO_LAnd ? "&" : "|");
- }
+ << RHS.get()->getSourceRange()
+ << (Opc == BO_LAnd ? "&&" : "||");
+ // Suggest replacing the logical operator with the bitwise version
+ Diag(Loc, diag::note_logical_instead_of_bitwise_change_operator)
+ << (Opc == BO_LAnd ? "&" : "|")
+ << FixItHint::CreateReplacement(SourceRange(
+ Loc, Lexer::getLocForEndOfToken(Loc, 0, getSourceManager(),
+ getLangOptions())),
+ Opc == BO_LAnd ? "&" : "|");
+ if (Opc == BO_LAnd)
+ // Suggest replacing "Foo() && kNonZero" with "Foo()"
+ Diag(Loc, diag::note_logical_instead_of_bitwise_remove_constant)
+ << FixItHint::CreateRemoval(
+ SourceRange(
+ Lexer::getLocForEndOfToken(LHS.get()->getLocEnd(),
+ 0, getSourceManager(),
+ getLangOptions()),
+ RHS.get()->getLocEnd()));
+ }
}
if (!Context.getLangOptions().CPlusPlus) {
- lex = UsualUnaryConversions(lex.take());
- if (lex.isInvalid())
+ LHS = UsualUnaryConversions(LHS.take());
+ if (LHS.isInvalid())
return QualType();
- rex = UsualUnaryConversions(rex.take());
- if (rex.isInvalid())
+ RHS = UsualUnaryConversions(RHS.take());
+ if (RHS.isInvalid())
return QualType();
- if (!lex.get()->getType()->isScalarType() || !rex.get()->getType()->isScalarType())
- return InvalidOperands(Loc, lex, rex);
+ if (!LHS.get()->getType()->isScalarType() ||
+ !RHS.get()->getType()->isScalarType())
+ return InvalidOperands(Loc, LHS, RHS);
return Context.IntTy;
}
@@ -6579,15 +6830,15 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
// C++ [expr.log.and]p1
// C++ [expr.log.or]p1
// The operands are both contextually converted to type bool.
- ExprResult lexRes = PerformContextuallyConvertToBool(lex.get());
- if (lexRes.isInvalid())
- return InvalidOperands(Loc, lex, rex);
- lex = move(lexRes);
+ ExprResult LHSRes = PerformContextuallyConvertToBool(LHS.get());
+ if (LHSRes.isInvalid())
+ return InvalidOperands(Loc, LHS, RHS);
+ LHS = move(LHSRes);
- ExprResult rexRes = PerformContextuallyConvertToBool(rex.get());
- if (rexRes.isInvalid())
- return InvalidOperands(Loc, lex, rex);
- rex = move(rexRes);
+ ExprResult RHSRes = PerformContextuallyConvertToBool(RHS.get());
+ if (RHSRes.isInvalid())
+ return InvalidOperands(Loc, LHS, RHS);
+ RHS = move(RHSRes);
// C++ [expr.log.and]p2
// C++ [expr.log.or]p2
@@ -6758,25 +7009,26 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
// C99 6.5.16.1
-QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS,
+QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
SourceLocation Loc,
QualType CompoundType) {
// Verify that LHS is a modifiable lvalue, and emit error if not.
- if (CheckForModifiableLvalue(LHS, Loc, *this))
+ if (CheckForModifiableLvalue(LHSExpr, Loc, *this))
return QualType();
- QualType LHSType = LHS->getType();
- QualType RHSType = CompoundType.isNull() ? RHS.get()->getType() : CompoundType;
+ QualType LHSType = LHSExpr->getType();
+ QualType RHSType = CompoundType.isNull() ? RHS.get()->getType() :
+ CompoundType;
AssignConvertType ConvTy;
if (CompoundType.isNull()) {
QualType LHSTy(LHSType);
// Simple assignment "x = y".
- if (LHS->getObjectKind() == OK_ObjCProperty) {
- ExprResult LHSResult = Owned(LHS);
+ if (LHSExpr->getObjectKind() == OK_ObjCProperty) {
+ ExprResult LHSResult = Owned(LHSExpr);
ConvertPropertyForLValue(LHSResult, RHS, LHSTy);
if (LHSResult.isInvalid())
return QualType();
- LHS = LHSResult.take();
+ LHSExpr = LHSResult.take();
}
ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS);
if (RHS.isInvalid())
@@ -6806,10 +7058,10 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS,
UO->getOpcode() == UO_Minus) &&
Loc.isFileID() && UO->getOperatorLoc().isFileID() &&
// Only if the two operators are exactly adjacent.
- Loc.getFileLocWithOffset(1) == UO->getOperatorLoc() &&
+ Loc.getLocWithOffset(1) == UO->getOperatorLoc() &&
// And there is a space or other character before the subexpr of the
// unary +/-. We don't want to warn on "x=-1".
- Loc.getFileLocWithOffset(2) != UO->getSubExpr()->getLocStart() &&
+ Loc.getLocWithOffset(2) != UO->getSubExpr()->getLocStart() &&
UO->getSubExpr()->getLocStart().isFileID()) {
Diag(Loc, diag::warn_not_compound_assign)
<< (UO->getOpcode() == UO_Plus ? "+" : "-")
@@ -6819,9 +7071,9 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS,
if (ConvTy == Compatible) {
if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong)
- checkRetainCycles(LHS, RHS.get());
+ checkRetainCycles(LHSExpr, RHS.get());
else if (getLangOptions().ObjCAutoRefCount)
- checkUnsafeExprAssigns(Loc, LHS, RHS.get());
+ checkUnsafeExprAssigns(Loc, LHSExpr, RHS.get());
}
} else {
// Compound assignment "x += y"
@@ -6832,10 +7084,8 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS,
RHS.get(), AA_Assigning))
return QualType();
- CheckForNullPointerDereference(*this, LHS);
- // Check for trivial buffer overflows.
- CheckArrayAccess(LHS->IgnoreParenCasts());
-
+ CheckForNullPointerDereference(*this, LHSExpr);
+
// C99 6.5.16p3: The type of an assignment expression is the type of the
// left operand unless the left operand has qualified type, in which case
// it is the unqualified version of the type of the left operand.
@@ -6872,7 +7122,8 @@ static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS,
if (RHS.isInvalid())
return QualType();
if (!RHS.get()->getType()->isVoidType())
- S.RequireCompleteType(Loc, RHS.get()->getType(), diag::err_incomplete_type);
+ S.RequireCompleteType(Loc, RHS.get()->getType(),
+ diag::err_incomplete_type);
}
return RHS.get()->getType();
@@ -6883,7 +7134,7 @@ static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS,
static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
ExprValueKind &VK,
SourceLocation OpLoc,
- bool isInc, bool isPrefix) {
+ bool IsInc, bool IsPrefix) {
if (Op->isTypeDependent())
return S.Context.DependentTy;
@@ -6892,7 +7143,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
if (S.getLangOptions().CPlusPlus && ResType->isBooleanType()) {
// Decrement of bool is not allowed.
- if (!isInc) {
+ if (!IsInc) {
S.Diag(OpLoc, diag::err_decrement_bool) << Op->getSourceRange();
return QualType();
}
@@ -6901,18 +7152,13 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
} else if (ResType->isRealType()) {
// OK!
} else if (ResType->isAnyPointerType()) {
- QualType PointeeTy = ResType->getPointeeType();
-
// C99 6.5.2.4p2, 6.5.6p2
if (!checkArithmeticOpPointerOperand(S, OpLoc, Op))
return QualType();
// Diagnose bad cases where we step over interface counts.
- else if (PointeeTy->isObjCObjectType() && S.LangOpts.ObjCNonFragileABI) {
- S.Diag(OpLoc, diag::err_arithmetic_nonfragile_interface)
- << PointeeTy << Op->getSourceRange();
+ else if (!checkArithmethicPointerOnNonFragileABI(S, OpLoc, Op))
return QualType();
- }
} else if (ResType->isAnyComplexType()) {
// C99 does not support ++/-- on complex types, we allow as an extension.
S.Diag(OpLoc, diag::ext_integer_increment_complex)
@@ -6921,12 +7167,12 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
ExprResult PR = S.CheckPlaceholderExpr(Op);
if (PR.isInvalid()) return QualType();
return CheckIncrementDecrementOperand(S, PR.take(), VK, OpLoc,
- isInc, isPrefix);
+ IsInc, IsPrefix);
} else if (S.getLangOptions().AltiVec && ResType->isVectorType()) {
// OK! ( C/C++ Language Extensions for CBEA(Version 2.6) 10.3 )
} else {
S.Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement)
- << ResType << int(isInc) << Op->getSourceRange();
+ << ResType << int(IsInc) << Op->getSourceRange();
return QualType();
}
// At this point, we know we have a real, complex or pointer type.
@@ -6936,7 +7182,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
// In C++, a prefix increment is the same type as the operand. Otherwise
// (in C or with postfix), the increment is the unqualified type of the
// operand.
- if (isPrefix && S.getLangOptions().CPlusPlus) {
+ if (IsPrefix && S.getLangOptions().CPlusPlus) {
VK = VK_LValue;
return ResType;
} else {
@@ -6973,7 +7219,13 @@ ExprResult Sema::ConvertPropertyForRValue(Expr *E) {
<< PRE->getBase()->getType();
}
}
-
+ else {
+ // lvalue-ness of an explicit property is determined by
+ // getter type.
+ QualType ResT = PRE->getGetterResultType();
+ VK = Expr::getValueKindForType(ResT);
+ }
+
E = ImplicitCastExpr::Create(Context, T, CK_GetObjCProperty,
E, 0, VK);
@@ -6984,7 +7236,8 @@ ExprResult Sema::ConvertPropertyForRValue(Expr *E) {
return Owned(E);
}
-void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType &LHSTy) {
+void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS,
+ QualType &LHSTy) {
assert(LHS.get()->getValueKind() == VK_LValue &&
LHS.get()->getObjectKind() == OK_ObjCProperty);
const ObjCPropertyRefExpr *PropRef = LHS.get()->getObjCProperty();
@@ -6996,7 +7249,7 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType &
// setter, RHS expression is being passed to the setter argument. So,
// type conversion (and comparison) is RHS to setter's argument type.
if (const ObjCMethodDecl *SetterMD = PropRef->getImplicitPropertySetter()) {
- ObjCMethodDecl::param_iterator P = SetterMD->param_begin();
+ ObjCMethodDecl::param_const_iterator P = SetterMD->param_begin();
LHSTy = (*P)->getType();
Consumed = (getLangOptions().ObjCAutoRefCount &&
(*P)->hasAttr<NSConsumedAttr>());
@@ -7015,7 +7268,7 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType &
const ObjCMethodDecl *setter
= PropRef->getExplicitProperty()->getSetterMethodDecl();
if (setter) {
- ObjCMethodDecl::param_iterator P = setter->param_begin();
+ ObjCMethodDecl::param_const_iterator P = setter->param_begin();
LHSTy = (*P)->getType();
Consumed = (*P)->hasAttr<NSConsumedAttr>();
}
@@ -7092,6 +7345,23 @@ static ValueDecl *getPrimaryDecl(Expr *E) {
}
}
+namespace {
+ enum {
+ AO_Bit_Field = 0,
+ AO_Vector_Element = 1,
+ AO_Property_Expansion = 2,
+ AO_Register_Variable = 3,
+ AO_No_Error = 4
+ };
+}
+/// \brief Diagnose invalid operand for address of operations.
+///
+/// \param Type The type of operand which cannot have its address taken.
+static void diagnoseAddressOfInvalidType(Sema &S, SourceLocation Loc,
+ Expr *E, unsigned Type) {
+ S.Diag(Loc, diag::err_typecheck_address_of) << Type << E->getSourceRange();
+}
+
/// CheckAddressOfOperand - The operand of & must be either a function
/// designator or an lvalue designating an object. If it is an lvalue, the
/// object cannot be declared with storage class register or be a bit field.
@@ -7103,8 +7373,15 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
SourceLocation OpLoc) {
if (OrigOp->isTypeDependent())
return S.Context.DependentTy;
- if (OrigOp->getType() == S.Context.OverloadTy)
+ if (OrigOp->getType() == S.Context.OverloadTy) {
+ if (!isa<OverloadExpr>(OrigOp->IgnoreParens())) {
+ S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
+ << OrigOp->getSourceRange();
+ return QualType();
+ }
+
return S.Context.OverloadTy;
+ }
if (OrigOp->getType() == S.Context.UnknownAnyTy)
return S.Context.UnknownAnyTy;
if (OrigOp->getType() == S.Context.BoundMemberTy) {
@@ -7131,6 +7408,7 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
}
ValueDecl *dcl = getPrimaryDecl(op);
Expr::LValueClassification lval = op->ClassifyLValue(S.Context);
+ unsigned AddressOfError = AO_No_Error;
if (lval == Expr::LV_ClassTemporary) {
bool sfinae = S.isSFINAEContext();
@@ -7178,19 +7456,13 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
}
} else if (op->getObjectKind() == OK_BitField) { // C99 6.5.3.2p1
// The operand cannot be a bit-field
- S.Diag(OpLoc, diag::err_typecheck_address_of)
- << "bit-field" << op->getSourceRange();
- return QualType();
+ AddressOfError = AO_Bit_Field;
} else if (op->getObjectKind() == OK_VectorComponent) {
// The operand cannot be an element of a vector
- S.Diag(OpLoc, diag::err_typecheck_address_of)
- << "vector element" << op->getSourceRange();
- return QualType();
+ AddressOfError = AO_Vector_Element;
} else if (op->getObjectKind() == OK_ObjCProperty) {
// cannot take address of a property expression.
- S.Diag(OpLoc, diag::err_typecheck_address_of)
- << "property expression" << op->getSourceRange();
- return QualType();
+ AddressOfError = AO_Property_Expansion;
} else if (dcl) { // C99 6.5.3.2p1
// We have an lvalue with a decl. Make sure the decl is not declared
// with the register storage-class specifier.
@@ -7199,9 +7471,7 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
// variable (c++03 7.1.1P3)
if (vd->getStorageClass() == SC_Register &&
!S.getLangOptions().CPlusPlus) {
- S.Diag(OpLoc, diag::err_typecheck_address_of)
- << "register variable" << op->getSourceRange();
- return QualType();
+ AddressOfError = AO_Register_Variable;
}
} else if (isa<FunctionTemplateDecl>(dcl)) {
return S.Context.OverloadTy;
@@ -7225,8 +7495,13 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
S.Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr());
}
}
- } else if (!isa<FunctionDecl>(dcl))
- assert(0 && "Unknown/unexpected decl type");
+ } else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(dcl))
+ llvm_unreachable("Unknown/unexpected decl type");
+ }
+
+ if (AddressOfError != AO_No_Error) {
+ diagnoseAddressOfInvalidType(S, OpLoc, op, AddressOfError);
+ return QualType();
}
if (lval == Expr::LV_IncompleteVoidType) {
@@ -7297,7 +7572,7 @@ static inline BinaryOperatorKind ConvertTokenKindToBinaryOpcode(
tok::TokenKind Kind) {
BinaryOperatorKind Opc;
switch (Kind) {
- default: assert(0 && "Unknown binop!");
+ default: llvm_unreachable("Unknown binop!");
case tok::periodstar: Opc = BO_PtrMemD; break;
case tok::arrowstar: Opc = BO_PtrMemI; break;
case tok::star: Opc = BO_Mul; break;
@@ -7338,7 +7613,7 @@ static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode(
tok::TokenKind Kind) {
UnaryOperatorKind Opc;
switch (Kind) {
- default: assert(0 && "Unknown unary op!");
+ default: llvm_unreachable("Unknown unary op!");
case tok::plusplus: Opc = UO_PreInc; break;
case tok::minusminus: Opc = UO_PreDec; break;
case tok::amp: Opc = UO_AddrOf; break;
@@ -7357,35 +7632,35 @@ static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode(
/// DiagnoseSelfAssignment - Emits a warning if a value is assigned to itself.
/// This warning is only emitted for builtin assignment operations. It is also
/// suppressed in the event of macro expansions.
-static void DiagnoseSelfAssignment(Sema &S, Expr *lhs, Expr *rhs,
+static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr,
SourceLocation OpLoc) {
if (!S.ActiveTemplateInstantiations.empty())
return;
if (OpLoc.isInvalid() || OpLoc.isMacroID())
return;
- lhs = lhs->IgnoreParenImpCasts();
- rhs = rhs->IgnoreParenImpCasts();
- const DeclRefExpr *LeftDeclRef = dyn_cast<DeclRefExpr>(lhs);
- const DeclRefExpr *RightDeclRef = dyn_cast<DeclRefExpr>(rhs);
- if (!LeftDeclRef || !RightDeclRef ||
- LeftDeclRef->getLocation().isMacroID() ||
- RightDeclRef->getLocation().isMacroID())
+ LHSExpr = LHSExpr->IgnoreParenImpCasts();
+ RHSExpr = RHSExpr->IgnoreParenImpCasts();
+ const DeclRefExpr *LHSDeclRef = dyn_cast<DeclRefExpr>(LHSExpr);
+ const DeclRefExpr *RHSDeclRef = dyn_cast<DeclRefExpr>(RHSExpr);
+ if (!LHSDeclRef || !RHSDeclRef ||
+ LHSDeclRef->getLocation().isMacroID() ||
+ RHSDeclRef->getLocation().isMacroID())
return;
- const ValueDecl *LeftDecl =
- cast<ValueDecl>(LeftDeclRef->getDecl()->getCanonicalDecl());
- const ValueDecl *RightDecl =
- cast<ValueDecl>(RightDeclRef->getDecl()->getCanonicalDecl());
- if (LeftDecl != RightDecl)
+ const ValueDecl *LHSDecl =
+ cast<ValueDecl>(LHSDeclRef->getDecl()->getCanonicalDecl());
+ const ValueDecl *RHSDecl =
+ cast<ValueDecl>(RHSDeclRef->getDecl()->getCanonicalDecl());
+ if (LHSDecl != RHSDecl)
return;
- if (LeftDecl->getType().isVolatileQualified())
+ if (LHSDecl->getType().isVolatileQualified())
return;
- if (const ReferenceType *RefTy = LeftDecl->getType()->getAs<ReferenceType>())
+ if (const ReferenceType *RefTy = LHSDecl->getType()->getAs<ReferenceType>())
if (RefTy->getPointeeType().isVolatileQualified())
return;
S.Diag(OpLoc, diag::warn_self_assignment)
- << LeftDeclRef->getType()
- << lhs->getSourceRange() << rhs->getSourceRange();
+ << LHSDeclRef->getType()
+ << LHSExpr->getSourceRange() << RHSExpr->getSourceRange();
}
/// CreateBuiltinBinOp - Creates a new built-in binary operation with
@@ -7393,8 +7668,8 @@ static void DiagnoseSelfAssignment(Sema &S, Expr *lhs, Expr *rhs,
/// built-in operations; ActOnBinOp handles overloaded operators.
ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
BinaryOperatorKind Opc,
- Expr *lhsExpr, Expr *rhsExpr) {
- ExprResult lhs = Owned(lhsExpr), rhs = Owned(rhsExpr);
+ Expr *LHSExpr, Expr *RHSExpr) {
+ ExprResult LHS = Owned(LHSExpr), RHS = Owned(RHSExpr);
QualType ResultTy; // Result type of the binary operator.
// The following two variables are used for compound assignment operators
QualType CompLHSTy; // Type of LHS after promotions for computation
@@ -7410,172 +7685,131 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
// f<int> == 0; // resolve f<int> blindly
// void (*p)(int); p = f<int>; // resolve f<int> using target
if (Opc != BO_Assign) {
- ExprResult resolvedLHS = CheckPlaceholderExpr(lhs.get());
+ ExprResult resolvedLHS = CheckPlaceholderExpr(LHS.get());
if (!resolvedLHS.isUsable()) return ExprError();
- lhs = move(resolvedLHS);
+ LHS = move(resolvedLHS);
- ExprResult resolvedRHS = CheckPlaceholderExpr(rhs.get());
+ ExprResult resolvedRHS = CheckPlaceholderExpr(RHS.get());
if (!resolvedRHS.isUsable()) return ExprError();
- rhs = move(resolvedRHS);
- }
-
- // The canonical way to check for a GNU null is with isNullPointerConstant,
- // but we use a bit of a hack here for speed; this is a relatively
- // hot path, and isNullPointerConstant is slow.
- bool LeftNull = isa<GNUNullExpr>(lhs.get()->IgnoreParenImpCasts());
- bool RightNull = isa<GNUNullExpr>(rhs.get()->IgnoreParenImpCasts());
-
- // Detect when a NULL constant is used improperly in an expression. These
- // are mainly cases where the null pointer is used as an integer instead
- // of a pointer.
- if (LeftNull || RightNull) {
- // Avoid analyzing cases where the result will either be invalid (and
- // diagnosed as such) or entirely valid and not something to warn about.
- QualType LeftType = lhs.get()->getType();
- QualType RightType = rhs.get()->getType();
- if (!LeftType->isBlockPointerType() && !LeftType->isMemberPointerType() &&
- !LeftType->isFunctionType() &&
- !RightType->isBlockPointerType() &&
- !RightType->isMemberPointerType() &&
- !RightType->isFunctionType()) {
- if (Opc == BO_Mul || Opc == BO_Div || Opc == BO_Rem || Opc == BO_Add ||
- Opc == BO_Sub || Opc == BO_Shl || Opc == BO_Shr || Opc == BO_And ||
- Opc == BO_Xor || Opc == BO_Or || Opc == BO_MulAssign ||
- Opc == BO_DivAssign || Opc == BO_AddAssign || Opc == BO_SubAssign ||
- Opc == BO_RemAssign || Opc == BO_ShlAssign || Opc == BO_ShrAssign ||
- Opc == BO_AndAssign || Opc == BO_OrAssign || Opc == BO_XorAssign) {
- // These are the operations that would not make sense with a null pointer
- // no matter what the other expression is.
- Diag(OpLoc, diag::warn_null_in_arithmetic_operation)
- << (LeftNull ? lhs.get()->getSourceRange() : SourceRange())
- << (RightNull ? rhs.get()->getSourceRange() : SourceRange());
- } else if (Opc == BO_LE || Opc == BO_LT || Opc == BO_GE || Opc == BO_GT ||
- Opc == BO_EQ || Opc == BO_NE) {
- // These are the operations that would not make sense with a null pointer
- // if the other expression the other expression is not a pointer.
- if (LeftNull != RightNull &&
- !LeftType->isAnyPointerType() &&
- !LeftType->canDecayToPointerType() &&
- !RightType->isAnyPointerType() &&
- !RightType->canDecayToPointerType()) {
- Diag(OpLoc, diag::warn_null_in_arithmetic_operation)
- << (LeftNull ? lhs.get()->getSourceRange()
- : rhs.get()->getSourceRange());
- }
- }
- }
+ RHS = move(resolvedRHS);
}
switch (Opc) {
case BO_Assign:
- ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, QualType());
+ ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType());
if (getLangOptions().CPlusPlus &&
- lhs.get()->getObjectKind() != OK_ObjCProperty) {
- VK = lhs.get()->getValueKind();
- OK = lhs.get()->getObjectKind();
+ LHS.get()->getObjectKind() != OK_ObjCProperty) {
+ VK = LHS.get()->getValueKind();
+ OK = LHS.get()->getObjectKind();
}
if (!ResultTy.isNull())
- DiagnoseSelfAssignment(*this, lhs.get(), rhs.get(), OpLoc);
+ DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc);
break;
case BO_PtrMemD:
case BO_PtrMemI:
- ResultTy = CheckPointerToMemberOperands(lhs, rhs, VK, OpLoc,
+ ResultTy = CheckPointerToMemberOperands(LHS, RHS, VK, OpLoc,
Opc == BO_PtrMemI);
break;
case BO_Mul:
case BO_Div:
- ResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, false,
+ ResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, false,
Opc == BO_Div);
break;
case BO_Rem:
- ResultTy = CheckRemainderOperands(lhs, rhs, OpLoc);
+ ResultTy = CheckRemainderOperands(LHS, RHS, OpLoc);
break;
case BO_Add:
- ResultTy = CheckAdditionOperands(lhs, rhs, OpLoc);
+ ResultTy = CheckAdditionOperands(LHS, RHS, OpLoc);
break;
case BO_Sub:
- ResultTy = CheckSubtractionOperands(lhs, rhs, OpLoc);
+ ResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc);
break;
case BO_Shl:
case BO_Shr:
- ResultTy = CheckShiftOperands(lhs, rhs, OpLoc, Opc);
+ ResultTy = CheckShiftOperands(LHS, RHS, OpLoc, Opc);
break;
case BO_LE:
case BO_LT:
case BO_GE:
case BO_GT:
- ResultTy = CheckCompareOperands(lhs, rhs, OpLoc, Opc, true);
+ ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, true);
break;
case BO_EQ:
case BO_NE:
- ResultTy = CheckCompareOperands(lhs, rhs, OpLoc, Opc, false);
+ ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, false);
break;
case BO_And:
case BO_Xor:
case BO_Or:
- ResultTy = CheckBitwiseOperands(lhs, rhs, OpLoc);
+ ResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc);
break;
case BO_LAnd:
case BO_LOr:
- ResultTy = CheckLogicalOperands(lhs, rhs, OpLoc, Opc);
+ ResultTy = CheckLogicalOperands(LHS, RHS, OpLoc, Opc);
break;
case BO_MulAssign:
case BO_DivAssign:
- CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true,
+ CompResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, true,
Opc == BO_DivAssign);
CompLHSTy = CompResultTy;
- if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid())
- ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy);
+ if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
+ ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
break;
case BO_RemAssign:
- CompResultTy = CheckRemainderOperands(lhs, rhs, OpLoc, true);
+ CompResultTy = CheckRemainderOperands(LHS, RHS, OpLoc, true);
CompLHSTy = CompResultTy;
- if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid())
- ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy);
+ if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
+ ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
break;
case BO_AddAssign:
- CompResultTy = CheckAdditionOperands(lhs, rhs, OpLoc, &CompLHSTy);
- if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid())
- ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy);
+ CompResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, &CompLHSTy);
+ if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
+ ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
break;
case BO_SubAssign:
- CompResultTy = CheckSubtractionOperands(lhs, rhs, OpLoc, &CompLHSTy);
- if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid())
- ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy);
+ CompResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc, &CompLHSTy);
+ if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
+ ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
break;
case BO_ShlAssign:
case BO_ShrAssign:
- CompResultTy = CheckShiftOperands(lhs, rhs, OpLoc, Opc, true);
+ CompResultTy = CheckShiftOperands(LHS, RHS, OpLoc, Opc, true);
CompLHSTy = CompResultTy;
- if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid())
- ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy);
+ if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
+ ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
break;
case BO_AndAssign:
case BO_XorAssign:
case BO_OrAssign:
- CompResultTy = CheckBitwiseOperands(lhs, rhs, OpLoc, true);
+ CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, true);
CompLHSTy = CompResultTy;
- if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid())
- ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy);
+ if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
+ ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
break;
case BO_Comma:
- ResultTy = CheckCommaOperands(*this, lhs, rhs, OpLoc);
- if (getLangOptions().CPlusPlus && !rhs.isInvalid()) {
- VK = rhs.get()->getValueKind();
- OK = rhs.get()->getObjectKind();
+ ResultTy = CheckCommaOperands(*this, LHS, RHS, OpLoc);
+ if (getLangOptions().CPlusPlus && !RHS.isInvalid()) {
+ VK = RHS.get()->getValueKind();
+ OK = RHS.get()->getObjectKind();
}
break;
}
- if (ResultTy.isNull() || lhs.isInvalid() || rhs.isInvalid())
+ if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid())
return ExprError();
+
+ // Check for array bounds violations for both sides of the BinaryOperator
+ CheckArrayAccess(LHS.get());
+ CheckArrayAccess(RHS.get());
+
if (CompResultTy.isNull())
- return Owned(new (Context) BinaryOperator(lhs.take(), rhs.take(), Opc,
+ return Owned(new (Context) BinaryOperator(LHS.take(), RHS.take(), Opc,
ResultTy, VK, OK, OpLoc));
- if (getLangOptions().CPlusPlus && lhs.get()->getObjectKind() != OK_ObjCProperty) {
+ if (getLangOptions().CPlusPlus && LHS.get()->getObjectKind() !=
+ OK_ObjCProperty) {
VK = VK_LValue;
- OK = lhs.get()->getObjectKind();
+ OK = LHS.get()->getObjectKind();
}
- return Owned(new (Context) CompoundAssignOperator(lhs.take(), rhs.take(), Opc,
+ return Owned(new (Context) CompoundAssignOperator(LHS.take(), RHS.take(), Opc,
ResultTy, VK, OK, CompLHSTy,
CompResultTy, OpLoc));
}
@@ -7585,51 +7819,49 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
/// comparison operators have higher precedence. The most typical example of
/// such code is "flags & 0x0020 != 0", which is equivalent to "flags & 1".
static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc,
- SourceLocation OpLoc,Expr *lhs,Expr *rhs){
+ 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>(lhs))
- lhsopc = BO->getOpcode();
- if (BinOp *BO = dyn_cast<BinOp>(rhs))
- rhsopc = BO->getOpcode();
+ 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)
+ if (LHSopc == -1 && RHSopc == -1)
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)))
+ if ((BinOp::isComparisonOp(LHSopc) || BinOp::isBitwiseOp(LHSopc)) &&
+ (BinOp::isComparisonOp(RHSopc) || BinOp::isBitwiseOp(RHSopc)))
return;
- if (BinOp::isComparisonOp(lhsopc)) {
- Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel)
- << SourceRange(lhs->getLocStart(), OpLoc)
- << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc);
- SuggestParentheses(Self, OpLoc,
- Self.PDiag(diag::note_precedence_bitwise_silence)
- << BinOp::getOpcodeStr(lhsopc),
- lhs->getSourceRange());
- SuggestParentheses(Self, OpLoc,
- Self.PDiag(diag::note_precedence_bitwise_first)
- << BinOp::getOpcodeStr(Opc),
- SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd()));
- } else if (BinOp::isComparisonOp(rhsopc)) {
- Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel)
- << SourceRange(OpLoc, rhs->getLocEnd())
- << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc);
- SuggestParentheses(Self, OpLoc,
- Self.PDiag(diag::note_precedence_bitwise_silence)
- << BinOp::getOpcodeStr(rhsopc),
- rhs->getSourceRange());
- SuggestParentheses(Self, OpLoc,
- Self.PDiag(diag::note_precedence_bitwise_first)
- << BinOp::getOpcodeStr(Opc),
- SourceRange(lhs->getLocStart(),
- cast<BinOp>(rhs)->getLHS()->getLocStart()));
- }
+ 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());
+ std::string OpStr = isLeftComp ? BinOp::getOpcodeStr(LHSopc)
+ : BinOp::getOpcodeStr(RHSopc);
+ SourceRange ParensRange = isLeftComp ?
+ SourceRange(cast<BinOp>(LHSExpr)->getRHS()->getLocStart(),
+ RHSExpr->getLocEnd())
+ : SourceRange(LHSExpr->getLocStart(),
+ cast<BinOp>(RHSExpr)->getLHS()->getLocStart());
+
+ Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel)
+ << DiagRange << BinOp::getOpcodeStr(Opc) << OpStr;
+ SuggestParentheses(Self, OpLoc,
+ Self.PDiag(diag::note_precedence_bitwise_silence) << OpStr,
+ RHSExpr->getSourceRange());
+ SuggestParentheses(Self, OpLoc,
+ Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc),
+ ParensRange);
}
/// \brief It accepts a '&' expr that is inside a '|' one.
@@ -7676,11 +7908,11 @@ static bool EvaluatesAsFalse(Sema &S, Expr *E) {
/// \brief Look for '&&' in the left hand of a '||' expr.
static void DiagnoseLogicalAndInLogicalOrLHS(Sema &S, SourceLocation OpLoc,
- Expr *OrLHS, Expr *OrRHS) {
- if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(OrLHS)) {
+ Expr *LHSExpr, Expr *RHSExpr) {
+ if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(LHSExpr)) {
if (Bop->getOpcode() == BO_LAnd) {
// If it's "a && b || 0" don't warn since the precedence doesn't matter.
- if (EvaluatesAsFalse(S, OrRHS))
+ if (EvaluatesAsFalse(S, RHSExpr))
return;
// If it's "1 && a || b" don't warn since the precedence doesn't matter.
if (!EvaluatesAsTrue(S, Bop->getLHS()))
@@ -7698,11 +7930,11 @@ static void DiagnoseLogicalAndInLogicalOrLHS(Sema &S, SourceLocation OpLoc,
/// \brief Look for '&&' in the right hand of a '||' expr.
static void DiagnoseLogicalAndInLogicalOrRHS(Sema &S, SourceLocation OpLoc,
- Expr *OrLHS, Expr *OrRHS) {
- if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(OrRHS)) {
+ Expr *LHSExpr, Expr *RHSExpr) {
+ if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(RHSExpr)) {
if (Bop->getOpcode() == BO_LAnd) {
// If it's "0 || a && b" don't warn since the precedence doesn't matter.
- if (EvaluatesAsFalse(S, OrLHS))
+ if (EvaluatesAsFalse(S, LHSExpr))
return;
// If it's "a || b && 1" don't warn since the precedence doesn't matter.
if (!EvaluatesAsTrue(S, Bop->getRHS()))
@@ -7723,52 +7955,54 @@ static void DiagnoseBitwiseAndInBitwiseOr(Sema &S, SourceLocation OpLoc,
/// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky
/// precedence.
static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc,
- SourceLocation OpLoc, Expr *lhs, Expr *rhs){
+ SourceLocation OpLoc, Expr *LHSExpr,
+ Expr *RHSExpr){
// Diagnose "arg1 'bitwise' arg2 'eq' arg3".
if (BinaryOperator::isBitwiseOp(Opc))
- DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs);
+ DiagnoseBitwisePrecedence(Self, Opc, OpLoc, LHSExpr, RHSExpr);
// Diagnose "arg1 & arg2 | arg3"
if (Opc == BO_Or && !OpLoc.isMacroID()/* Don't warn in macros. */) {
- DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, lhs);
- DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, rhs);
+ DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, LHSExpr);
+ DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, RHSExpr);
}
// Warn about arg1 || arg2 && arg3, as GCC 4.3+ does.
// We don't warn for 'assert(a || b && "bad")' since this is safe.
if (Opc == BO_LOr && !OpLoc.isMacroID()/* Don't warn in macros. */) {
- DiagnoseLogicalAndInLogicalOrLHS(Self, OpLoc, lhs, rhs);
- DiagnoseLogicalAndInLogicalOrRHS(Self, OpLoc, lhs, rhs);
+ DiagnoseLogicalAndInLogicalOrLHS(Self, OpLoc, LHSExpr, RHSExpr);
+ DiagnoseLogicalAndInLogicalOrRHS(Self, OpLoc, LHSExpr, RHSExpr);
}
}
// Binary Operators. 'Tok' is the token for the operator.
ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
tok::TokenKind Kind,
- Expr *lhs, Expr *rhs) {
+ Expr *LHSExpr, Expr *RHSExpr) {
BinaryOperatorKind Opc = ConvertTokenKindToBinaryOpcode(Kind);
- assert((lhs != 0) && "ActOnBinOp(): missing left expression");
- assert((rhs != 0) && "ActOnBinOp(): missing right expression");
+ assert((LHSExpr != 0) && "ActOnBinOp(): missing left expression");
+ assert((RHSExpr != 0) && "ActOnBinOp(): missing right expression");
// Emit warnings for tricky precedence issues, e.g. "bitfield & 0x4 == 0"
- DiagnoseBinOpPrecedence(*this, Opc, TokLoc, lhs, rhs);
+ DiagnoseBinOpPrecedence(*this, Opc, TokLoc, LHSExpr, RHSExpr);
- return BuildBinOp(S, TokLoc, Opc, lhs, rhs);
+ return BuildBinOp(S, TokLoc, Opc, LHSExpr, RHSExpr);
}
ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
BinaryOperatorKind Opc,
- Expr *lhs, Expr *rhs) {
+ Expr *LHSExpr, Expr *RHSExpr) {
if (getLangOptions().CPlusPlus) {
bool UseBuiltinOperator;
- if (lhs->isTypeDependent() || rhs->isTypeDependent()) {
+ if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent()) {
UseBuiltinOperator = false;
- } else if (Opc == BO_Assign && lhs->getObjectKind() == OK_ObjCProperty) {
+ } else if (Opc == BO_Assign &&
+ LHSExpr->getObjectKind() == OK_ObjCProperty) {
UseBuiltinOperator = true;
} else {
- UseBuiltinOperator = !lhs->getType()->isOverloadableType() &&
- !rhs->getType()->isOverloadableType();
+ UseBuiltinOperator = !LHSExpr->getType()->isOverloadableType() &&
+ !RHSExpr->getType()->isOverloadableType();
}
if (!UseBuiltinOperator) {
@@ -7780,17 +8014,17 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
OverloadedOperatorKind OverOp
= BinaryOperator::getOverloadedOperator(Opc);
if (S && OverOp != OO_None)
- LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
- Functions);
+ LookupOverloadedOperatorName(OverOp, S, LHSExpr->getType(),
+ RHSExpr->getType(), Functions);
// Build the (potentially-overloaded, potentially-dependent)
// binary operation.
- return CreateOverloadedBinOp(OpLoc, Opc, Functions, lhs, rhs);
+ return CreateOverloadedBinOp(OpLoc, Opc, Functions, LHSExpr, RHSExpr);
}
}
// Build a built-in binary operation.
- return CreateBuiltinBinOp(OpLoc, Opc, lhs, rhs);
+ return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr);
}
ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
@@ -7876,6 +8110,13 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
Input = DefaultFunctionArrayLvalueConversion(Input.take());
if (Input.isInvalid()) return ExprError();
resultType = Input.get()->getType();
+
+ // Though we still have to promote half FP to float...
+ if (resultType->isHalfType()) {
+ Input = ImpCastExprToType(Input.take(), Context.FloatTy, CK_FloatingCast).take();
+ resultType = Context.FloatTy;
+ }
+
if (resultType->isDependentType())
break;
if (resultType->isScalarType()) {
@@ -7917,13 +8158,19 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
if (resultType.isNull() || Input.isInvalid())
return ExprError();
+ // Check for array bounds violations in the operand of the UnaryOperator,
+ // except for the '*' and '&' operators that have to be handled specially
+ // by CheckArrayAccess (as there are special cases like &array[arraysize]
+ // that are explicitly defined as valid by the standard).
+ if (Opc != UO_AddrOf && Opc != UO_Deref)
+ CheckArrayAccess(Input.get());
+
return Owned(new (Context) UnaryOperator(Input.take(), Opc, resultType,
VK, OK, OpLoc));
}
ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc,
- UnaryOperatorKind Opc,
- Expr *Input) {
+ UnaryOperatorKind Opc, Expr *Input) {
if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType() &&
UnaryOperator::getOverloadedOperator(Opc) != OO_None) {
// Find all of the overloaded operators visible from this
@@ -7962,13 +8209,13 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
/// ns_returns_retained function) and, if so, rebuild it to hoist the
/// release out of the full-expression. Otherwise, return null.
/// Cannot fail.
-static Expr *maybeRebuildARCConsumingStmt(Stmt *s) {
+static Expr *maybeRebuildARCConsumingStmt(Stmt *Statement) {
// Should always be wrapped with one of these.
- ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(s);
+ ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(Statement);
if (!cleanups) return 0;
ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(cleanups->getSubExpr());
- if (!cast || cast->getCastKind() != CK_ObjCConsumeObject)
+ if (!cast || cast->getCastKind() != CK_ARCConsumeObject)
return 0;
// Splice out the cast. This shouldn't modify any interesting
@@ -8091,8 +8338,8 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
bool DidWarnAboutNonPOD = false;
QualType CurrentType = ArgTy;
typedef OffsetOfExpr::OffsetOfNode OffsetOfNode;
- llvm::SmallVector<OffsetOfNode, 4> Comps;
- llvm::SmallVector<Expr*, 4> Exprs;
+ SmallVector<OffsetOfNode, 4> Comps;
+ SmallVector<Expr*, 4> Exprs;
for (unsigned i = 0; i != NumComponents; ++i) {
const OffsetOfComponent &OC = CompPtr[i];
if (OC.isBrackets) {
@@ -8174,7 +8421,7 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
// (If the specified member is a bit-field, the behavior is undefined.)
//
// We diagnose this as an error.
- if (MemberDecl->getBitWidth()) {
+ if (MemberDecl->isBitField()) {
Diag(OC.LocEnd, diag::err_offsetof_bitfield)
<< MemberDecl->getDeclName()
<< SourceRange(BuiltinLoc, RParenLoc);
@@ -8219,13 +8466,13 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
SourceLocation BuiltinLoc,
SourceLocation TypeLoc,
- ParsedType argty,
+ ParsedType ParsedArgTy,
OffsetOfComponent *CompPtr,
unsigned NumComponents,
- SourceLocation RPLoc) {
+ SourceLocation RParenLoc) {
TypeSourceInfo *ArgTInfo;
- QualType ArgTy = GetTypeFromParser(argty, &ArgTInfo);
+ QualType ArgTy = GetTypeFromParser(ParsedArgTy, &ArgTInfo);
if (ArgTy.isNull())
return ExprError();
@@ -8233,7 +8480,7 @@ ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
ArgTInfo = Context.getTrivialTypeSourceInfo(ArgTy, TypeLoc);
return BuildBuiltinOffsetOf(BuiltinLoc, ArgTInfo, CompPtr, NumComponents,
- RPLoc);
+ RParenLoc);
}
@@ -8279,12 +8526,12 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
//===----------------------------------------------------------------------===//
/// ActOnBlockStart - This callback is invoked when a block literal is started.
-void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) {
+void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) {
BlockDecl *Block = BlockDecl::Create(Context, CurContext, CaretLoc);
- PushBlockScope(BlockScope, Block);
+ PushBlockScope(CurScope, Block);
CurContext->addDecl(Block);
- if (BlockScope)
- PushDeclContext(BlockScope, Block);
+ if (CurScope)
+ PushDeclContext(CurScope, Block);
else
CurContext = Block;
}
@@ -8351,7 +8598,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
CurBlock->ReturnType = RetTy;
// Push block parameters from the declarator if we had them.
- llvm::SmallVector<ParmVarDecl*, 8> Params;
+ SmallVector<ParmVarDecl*, 8> Params;
if (ExplicitSignature) {
for (unsigned I = 0, E = ExplicitSignature.getNumArgs(); I != E; ++I) {
ParmVarDecl *Param = ExplicitSignature.getArg(I);
@@ -8378,7 +8625,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
// Set the parameters on the block decl.
if (!Params.empty()) {
- CurBlock->TheDecl->setParams(Params.data(), Params.size());
+ CurBlock->TheDecl->setParams(Params);
CheckParmsForFunctionDef(CurBlock->TheDecl->param_begin(),
CurBlock->TheDecl->param_end(),
/*CheckParameterNames=*/false);
@@ -8500,6 +8747,8 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
getCurFunction()->setHasBranchProtectedScope();
}
+ computeNRVO(Body, getCurBlock());
+
BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy);
const AnalysisBasedWarnings::Policy &WP = AnalysisWarnings.getDefaultPolicy();
PopFunctionOrBlockScope(&WP, Result->getBlockDecl(), Result);
@@ -8508,11 +8757,11 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
}
ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
- Expr *expr, ParsedType type,
+ Expr *E, ParsedType Ty,
SourceLocation RPLoc) {
TypeSourceInfo *TInfo;
- GetTypeFromParser(type, &TInfo);
- return BuildVAArgExpr(BuiltinLoc, expr, TInfo, RPLoc);
+ GetTypeFromParser(Ty, &TInfo);
+ return BuildVAArgExpr(BuiltinLoc, E, TInfo, RPLoc);
}
ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
@@ -8559,11 +8808,14 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
<< TInfo->getTypeLoc().getSourceRange()))
return ExprError();
- if (!TInfo->getType().isPODType(Context))
+ if (!TInfo->getType().isPODType(Context)) {
Diag(TInfo->getTypeLoc().getBeginLoc(),
- diag::warn_second_parameter_to_va_arg_not_pod)
+ TInfo->getType()->isObjCLifetimeType()
+ ? diag::warn_second_parameter_to_va_arg_ownership_qualified
+ : diag::warn_second_parameter_to_va_arg_not_pod)
<< TInfo->getType()
<< TInfo->getTypeLoc().getSourceRange();
+ }
// Check for va_arg where arguments of the given type will be promoted
// (i.e. this va_arg is guaranteed to have undefined behavior).
@@ -8591,16 +8843,15 @@ ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
// The type of __null will be int or long, depending on the size of
// pointers on the target.
QualType Ty;
- unsigned pw = Context.Target.getPointerWidth(0);
- if (pw == Context.Target.getIntWidth())
+ unsigned pw = Context.getTargetInfo().getPointerWidth(0);
+ if (pw == Context.getTargetInfo().getIntWidth())
Ty = Context.IntTy;
- else if (pw == Context.Target.getLongWidth())
+ else if (pw == Context.getTargetInfo().getLongWidth())
Ty = Context.LongTy;
- else if (pw == Context.Target.getLongLongWidth())
+ else if (pw == Context.getTargetInfo().getLongLongWidth())
Ty = Context.LongLongTy;
else {
- assert(!"I don't know size of pointer!");
- Ty = Context.IntTy;
+ llvm_unreachable("I don't know size of pointer!");
}
return Owned(new (Context) GNUNullExpr(Ty, TokenLoc));
@@ -8625,7 +8876,7 @@ static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType,
// Strip off any parens and casts.
StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr->IgnoreParenCasts());
- if (!SL || SL->isWide())
+ if (!SL || !SL->isAscii())
return;
Hint = FixItHint::CreateInsertion(SL->getLocStart(), "@");
@@ -8644,21 +8895,31 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
bool isInvalid = false;
unsigned DiagKind;
FixItHint Hint;
+ ConversionFixItGenerator ConvHints;
+ bool MayHaveConvFixit = false;
switch (ConvTy) {
- default: assert(0 && "Unknown conversion type");
+ default: llvm_unreachable("Unknown conversion type");
case Compatible: return false;
case PointerToInt:
DiagKind = diag::ext_typecheck_convert_pointer_int;
+ ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
+ MayHaveConvFixit = true;
break;
case IntToPointer:
DiagKind = diag::ext_typecheck_convert_int_pointer;
+ ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
+ MayHaveConvFixit = true;
break;
case IncompatiblePointer:
MakeObjCStringLiteralFixItHint(*this, DstType, SrcExpr, Hint);
DiagKind = diag::ext_typecheck_convert_incompatible_pointer;
CheckInferredResultType = DstType->isObjCObjectPointerType() &&
SrcType->isObjCObjectPointerType();
+ if (Hint.isNull() && !CheckInferredResultType) {
+ ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
+ }
+ MayHaveConvFixit = true;
break;
case IncompatiblePointerSign:
DiagKind = diag::ext_typecheck_convert_incompatible_pointer_sign;
@@ -8722,6 +8983,8 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
break;
case Incompatible:
DiagKind = diag::err_typecheck_convert_incompatible;
+ ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
+ MayHaveConvFixit = true;
isInvalid = true;
break;
}
@@ -8746,8 +9009,23 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
break;
}
- Diag(Loc, DiagKind) << FirstType << SecondType << Action
- << SrcExpr->getSourceRange() << Hint;
+ PartialDiagnostic FDiag = PDiag(DiagKind);
+ FDiag << FirstType << SecondType << Action << SrcExpr->getSourceRange();
+
+ // If we can fix the conversion, suggest the FixIts.
+ assert(ConvHints.isNull() || Hint.isNull());
+ if (!ConvHints.isNull()) {
+ for (llvm::SmallVector<FixItHint, 1>::iterator
+ HI = ConvHints.Hints.begin(), HE = ConvHints.Hints.end();
+ HI != HE; ++HI)
+ FDiag << *HI;
+ } else {
+ FDiag << Hint;
+ }
+ if (MayHaveConvFixit) { FDiag << (unsigned) (ConvHints.Kind); }
+
+ Diag(Loc, FDiag);
+
if (CheckInferredResultType)
EmitRelatedResultTypeNote(SrcExpr);
@@ -8786,7 +9064,7 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){
if (EvalResult.Diag &&
Diags.getDiagnosticLevel(diag::ext_expr_not_ice, EvalResult.DiagLoc)
- != Diagnostic::Ignored)
+ != DiagnosticsEngine::Ignored)
Diag(EvalResult.DiagLoc, EvalResult.Diag);
if (Result)
@@ -8803,8 +9081,7 @@ Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
ExprNeedsCleanups = false;
}
-void
-Sema::PopExpressionEvaluationContext() {
+void Sema::PopExpressionEvaluationContext() {
// Pop the current expression evaluation context off the stack.
ExpressionEvaluationContextRecord Rec = ExprEvalContexts.back();
ExprEvalContexts.pop_back();
@@ -8874,10 +9151,10 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
if (D->isUsed(false))
return;
- // Mark a parameter or variable declaration "used", regardless of whether we're in a
- // template or not. The reason for this is that unevaluated expressions
- // (e.g. (void)sizeof()) constitute a use for warning purposes (-Wunused-variables and
- // -Wunused-parameters)
+ // Mark a parameter or variable declaration "used", regardless of whether
+ // we're in a template or not. The reason for this is that unevaluated
+ // expressions (e.g. (void)sizeof()) constitute a use for warning purposes
+ // (-Wunused-variables and -Wunused-parameters)
if (isa<ParmVarDecl>(D) ||
(isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod())) {
D->setUsed();
@@ -8917,15 +9194,19 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
// Note that this declaration has been used.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
- if (Constructor->isDefaulted() && Constructor->isDefaultConstructor()) {
- if (Constructor->isTrivial())
- return;
- if (!Constructor->isUsed(false))
- DefineImplicitDefaultConstructor(Loc, Constructor);
- } else if (Constructor->isDefaulted() &&
- Constructor->isCopyConstructor()) {
- if (!Constructor->isUsed(false))
- DefineImplicitCopyConstructor(Loc, Constructor);
+ if (Constructor->isDefaulted()) {
+ if (Constructor->isDefaultConstructor()) {
+ if (Constructor->isTrivial())
+ return;
+ if (!Constructor->isUsed(false))
+ DefineImplicitDefaultConstructor(Loc, Constructor);
+ } else if (Constructor->isCopyConstructor()) {
+ if (!Constructor->isUsed(false))
+ DefineImplicitCopyConstructor(Loc, Constructor);
+ } else if (Constructor->isMoveConstructor()) {
+ if (!Constructor->isUsed(false))
+ DefineImplicitMoveConstructor(Loc, Constructor);
+ }
}
MarkVTableUsed(Loc, Constructor->getParent());
@@ -8937,8 +9218,12 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
} else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) {
if (MethodDecl->isDefaulted() && MethodDecl->isOverloadedOperator() &&
MethodDecl->getOverloadedOperator() == OO_Equal) {
- if (!MethodDecl->isUsed(false))
- DefineImplicitCopyAssignment(Loc, MethodDecl);
+ if (!MethodDecl->isUsed(false)) {
+ if (MethodDecl->isCopyAssignmentOperator())
+ DefineImplicitCopyAssignment(Loc, MethodDecl);
+ else
+ DefineImplicitMoveAssignment(Loc, MethodDecl);
+ }
} else if (MethodDecl->isVirtual())
MarkVTableUsed(Loc, MethodDecl->getParent());
}
@@ -9147,7 +9432,7 @@ void Sema::MarkDeclarationsReferencedInExpr(Expr *E) {
/// behavior of a program, such as passing a non-POD value through an ellipsis.
/// Failure to do so will likely result in spurious diagnostics or failures
/// during overload resolution or within sizeof/alignof/typeof/typeid.
-bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *stmt,
+bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement,
const PartialDiagnostic &PD) {
switch (ExprEvalContexts.back().Context) {
case Unevaluated:
@@ -9156,9 +9441,9 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *stmt,
case PotentiallyEvaluated:
case PotentiallyEvaluatedIfUsed:
- if (stmt && getCurFunctionOrMethodDecl()) {
+ if (Statement && getCurFunctionOrMethodDecl()) {
FunctionScopes.back()->PossiblyUnreachableDiags.
- push_back(sema::PossiblyUnreachableDiag(PD, Loc, stmt));
+ push_back(sema::PossiblyUnreachableDiag(PD, Loc, Statement));
}
else
Diag(Loc, PD);
@@ -9203,8 +9488,7 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
unsigned diagnostic = diag::warn_condition_is_assignment;
bool IsOrAssign = false;
- if (isa<BinaryOperator>(E)) {
- BinaryOperator *Op = cast<BinaryOperator>(E);
+ if (BinaryOperator *Op = dyn_cast<BinaryOperator>(E)) {
if (Op->getOpcode() != BO_Assign && Op->getOpcode() != BO_OrAssign)
return;
@@ -9225,8 +9509,7 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
}
Loc = Op->getOperatorLoc();
- } else if (isa<CXXOperatorCallExpr>(E)) {
- CXXOperatorCallExpr *Op = cast<CXXOperatorCallExpr>(E);
+ } else if (CXXOperatorCallExpr *Op = dyn_cast<CXXOperatorCallExpr>(E)) {
if (Op->getOperator() != OO_Equal && Op->getOperator() != OO_PipeEqual)
return;
@@ -9255,16 +9538,16 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
/// \brief Redundant parentheses over an equality comparison can indicate
/// that the user intended an assignment used as condition.
-void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *parenE) {
+void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *ParenE) {
// Don't warn if the parens came from a macro.
- SourceLocation parenLoc = parenE->getLocStart();
+ SourceLocation parenLoc = ParenE->getLocStart();
if (parenLoc.isInvalid() || parenLoc.isMacroID())
return;
// Don't warn for dependent expressions.
- if (parenE->isTypeDependent())
+ if (ParenE->isTypeDependent())
return;
- Expr *E = parenE->IgnoreParens();
+ Expr *E = ParenE->IgnoreParens();
if (BinaryOperator *opE = dyn_cast<BinaryOperator>(E))
if (opE->getOpcode() == BO_EQ &&
@@ -9274,8 +9557,8 @@ void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *parenE) {
Diag(Loc, diag::warn_equality_with_extra_parens) << E->getSourceRange();
Diag(Loc, diag::note_equality_comparison_silence)
- << FixItHint::CreateRemoval(parenE->getSourceRange().getBegin())
- << FixItHint::CreateRemoval(parenE->getSourceRange().getEnd());
+ << FixItHint::CreateRemoval(ParenE->getSourceRange().getBegin())
+ << FixItHint::CreateRemoval(ParenE->getSourceRange().getEnd());
Diag(Loc, diag::note_equality_comparison_to_assign)
<< FixItHint::CreateReplacement(Loc, "=");
}
@@ -9311,11 +9594,11 @@ ExprResult Sema::CheckBooleanCondition(Expr *E, SourceLocation Loc) {
}
ExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc,
- Expr *Sub) {
- if (!Sub)
+ Expr *SubExpr) {
+ if (!SubExpr)
return ExprError();
- return CheckBooleanCondition(Sub, Loc);
+ return CheckBooleanCondition(SubExpr, Loc);
}
namespace {
@@ -9333,76 +9616,76 @@ namespace {
return ExprError();
}
- ExprResult VisitExpr(Expr *expr) {
- S.Diag(expr->getExprLoc(), diag::err_unsupported_unknown_any_call)
- << expr->getSourceRange();
+ ExprResult VisitExpr(Expr *E) {
+ S.Diag(E->getExprLoc(), diag::err_unsupported_unknown_any_call)
+ << E->getSourceRange();
return ExprError();
}
/// Rebuild an expression which simply semantically wraps another
/// expression which it shares the type and value kind of.
- template <class T> ExprResult rebuildSugarExpr(T *expr) {
- ExprResult subResult = Visit(expr->getSubExpr());
- if (subResult.isInvalid()) return ExprError();
+ template <class T> ExprResult rebuildSugarExpr(T *E) {
+ ExprResult SubResult = Visit(E->getSubExpr());
+ if (SubResult.isInvalid()) return ExprError();
- Expr *subExpr = subResult.take();
- expr->setSubExpr(subExpr);
- expr->setType(subExpr->getType());
- expr->setValueKind(subExpr->getValueKind());
- assert(expr->getObjectKind() == OK_Ordinary);
- return expr;
+ Expr *SubExpr = SubResult.take();
+ E->setSubExpr(SubExpr);
+ E->setType(SubExpr->getType());
+ E->setValueKind(SubExpr->getValueKind());
+ assert(E->getObjectKind() == OK_Ordinary);
+ return E;
}
- ExprResult VisitParenExpr(ParenExpr *paren) {
- return rebuildSugarExpr(paren);
+ ExprResult VisitParenExpr(ParenExpr *E) {
+ return rebuildSugarExpr(E);
}
- ExprResult VisitUnaryExtension(UnaryOperator *op) {
- return rebuildSugarExpr(op);
+ ExprResult VisitUnaryExtension(UnaryOperator *E) {
+ return rebuildSugarExpr(E);
}
- ExprResult VisitUnaryAddrOf(UnaryOperator *op) {
- ExprResult subResult = Visit(op->getSubExpr());
- if (subResult.isInvalid()) return ExprError();
+ ExprResult VisitUnaryAddrOf(UnaryOperator *E) {
+ ExprResult SubResult = Visit(E->getSubExpr());
+ if (SubResult.isInvalid()) return ExprError();
- Expr *subExpr = subResult.take();
- op->setSubExpr(subExpr);
- op->setType(S.Context.getPointerType(subExpr->getType()));
- assert(op->getValueKind() == VK_RValue);
- assert(op->getObjectKind() == OK_Ordinary);
- return op;
+ Expr *SubExpr = SubResult.take();
+ E->setSubExpr(SubExpr);
+ E->setType(S.Context.getPointerType(SubExpr->getType()));
+ assert(E->getValueKind() == VK_RValue);
+ assert(E->getObjectKind() == OK_Ordinary);
+ return E;
}
- ExprResult resolveDecl(Expr *expr, ValueDecl *decl) {
- if (!isa<FunctionDecl>(decl)) return VisitExpr(expr);
+ ExprResult resolveDecl(Expr *E, ValueDecl *VD) {
+ if (!isa<FunctionDecl>(VD)) return VisitExpr(E);
- expr->setType(decl->getType());
+ E->setType(VD->getType());
- assert(expr->getValueKind() == VK_RValue);
+ assert(E->getValueKind() == VK_RValue);
if (S.getLangOptions().CPlusPlus &&
- !(isa<CXXMethodDecl>(decl) &&
- cast<CXXMethodDecl>(decl)->isInstance()))
- expr->setValueKind(VK_LValue);
+ !(isa<CXXMethodDecl>(VD) &&
+ cast<CXXMethodDecl>(VD)->isInstance()))
+ E->setValueKind(VK_LValue);
- return expr;
+ return E;
}
- ExprResult VisitMemberExpr(MemberExpr *mem) {
- return resolveDecl(mem, mem->getMemberDecl());
+ ExprResult VisitMemberExpr(MemberExpr *E) {
+ return resolveDecl(E, E->getMemberDecl());
}
- ExprResult VisitDeclRefExpr(DeclRefExpr *ref) {
- return resolveDecl(ref, ref->getDecl());
+ ExprResult VisitDeclRefExpr(DeclRefExpr *E) {
+ return resolveDecl(E, E->getDecl());
}
};
}
/// Given a function expression of unknown-any type, try to rebuild it
/// to have a function type.
-static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn) {
- ExprResult result = RebuildUnknownAnyFunction(S).Visit(fn);
- if (result.isInvalid()) return ExprError();
- return S.DefaultFunctionArrayConversion(result.take());
+static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *FunctionExpr) {
+ ExprResult Result = RebuildUnknownAnyFunction(S).Visit(FunctionExpr);
+ if (Result.isInvalid()) return ExprError();
+ return S.DefaultFunctionArrayConversion(Result.take());
}
namespace {
@@ -9418,80 +9701,80 @@ namespace {
/// The current destination type.
QualType DestType;
- RebuildUnknownAnyExpr(Sema &S, QualType castType)
- : S(S), DestType(castType) {}
+ RebuildUnknownAnyExpr(Sema &S, QualType CastType)
+ : S(S), DestType(CastType) {}
ExprResult VisitStmt(Stmt *S) {
llvm_unreachable("unexpected statement!");
return ExprError();
}
- ExprResult VisitExpr(Expr *expr) {
- S.Diag(expr->getExprLoc(), diag::err_unsupported_unknown_any_expr)
- << expr->getSourceRange();
+ ExprResult VisitExpr(Expr *E) {
+ S.Diag(E->getExprLoc(), diag::err_unsupported_unknown_any_expr)
+ << E->getSourceRange();
return ExprError();
}
- ExprResult VisitCallExpr(CallExpr *call);
- ExprResult VisitObjCMessageExpr(ObjCMessageExpr *message);
+ ExprResult VisitCallExpr(CallExpr *E);
+ ExprResult VisitObjCMessageExpr(ObjCMessageExpr *E);
/// Rebuild an expression which simply semantically wraps another
/// expression which it shares the type and value kind of.
- template <class T> ExprResult rebuildSugarExpr(T *expr) {
- ExprResult subResult = Visit(expr->getSubExpr());
- if (subResult.isInvalid()) return ExprError();
- Expr *subExpr = subResult.take();
- expr->setSubExpr(subExpr);
- expr->setType(subExpr->getType());
- expr->setValueKind(subExpr->getValueKind());
- assert(expr->getObjectKind() == OK_Ordinary);
- return expr;
+ template <class T> ExprResult rebuildSugarExpr(T *E) {
+ ExprResult SubResult = Visit(E->getSubExpr());
+ if (SubResult.isInvalid()) return ExprError();
+ Expr *SubExpr = SubResult.take();
+ E->setSubExpr(SubExpr);
+ E->setType(SubExpr->getType());
+ E->setValueKind(SubExpr->getValueKind());
+ assert(E->getObjectKind() == OK_Ordinary);
+ return E;
}
- ExprResult VisitParenExpr(ParenExpr *paren) {
- return rebuildSugarExpr(paren);
+ ExprResult VisitParenExpr(ParenExpr *E) {
+ return rebuildSugarExpr(E);
}
- ExprResult VisitUnaryExtension(UnaryOperator *op) {
- return rebuildSugarExpr(op);
+ ExprResult VisitUnaryExtension(UnaryOperator *E) {
+ return rebuildSugarExpr(E);
}
- ExprResult VisitUnaryAddrOf(UnaryOperator *op) {
- const PointerType *ptr = DestType->getAs<PointerType>();
- if (!ptr) {
- S.Diag(op->getOperatorLoc(), diag::err_unknown_any_addrof)
- << op->getSourceRange();
+ ExprResult VisitUnaryAddrOf(UnaryOperator *E) {
+ const PointerType *Ptr = DestType->getAs<PointerType>();
+ if (!Ptr) {
+ S.Diag(E->getOperatorLoc(), diag::err_unknown_any_addrof)
+ << E->getSourceRange();
return ExprError();
}
- assert(op->getValueKind() == VK_RValue);
- assert(op->getObjectKind() == OK_Ordinary);
- op->setType(DestType);
+ assert(E->getValueKind() == VK_RValue);
+ assert(E->getObjectKind() == OK_Ordinary);
+ E->setType(DestType);
// Build the sub-expression as if it were an object of the pointee type.
- DestType = ptr->getPointeeType();
- ExprResult subResult = Visit(op->getSubExpr());
- if (subResult.isInvalid()) return ExprError();
- op->setSubExpr(subResult.take());
- return op;
+ DestType = Ptr->getPointeeType();
+ ExprResult SubResult = Visit(E->getSubExpr());
+ if (SubResult.isInvalid()) return ExprError();
+ E->setSubExpr(SubResult.take());
+ return E;
}
- ExprResult VisitImplicitCastExpr(ImplicitCastExpr *ice);
+ ExprResult VisitImplicitCastExpr(ImplicitCastExpr *E);
- ExprResult resolveDecl(Expr *expr, ValueDecl *decl);
+ ExprResult resolveDecl(Expr *E, ValueDecl *VD);
- ExprResult VisitMemberExpr(MemberExpr *mem) {
- return resolveDecl(mem, mem->getMemberDecl());
+ ExprResult VisitMemberExpr(MemberExpr *E) {
+ return resolveDecl(E, E->getMemberDecl());
}
- ExprResult VisitDeclRefExpr(DeclRefExpr *ref) {
- return resolveDecl(ref, ref->getDecl());
+ ExprResult VisitDeclRefExpr(DeclRefExpr *E) {
+ return resolveDecl(E, E->getDecl());
}
};
}
/// Rebuilds a call expression which yielded __unknown_anytype.
-ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *call) {
- Expr *callee = call->getCallee();
+ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *E) {
+ Expr *CalleeExpr = E->getCallee();
enum FnKind {
FK_MemberFunction,
@@ -9499,49 +9782,49 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *call) {
FK_BlockPointer
};
- FnKind kind;
- QualType type = callee->getType();
- if (type == S.Context.BoundMemberTy) {
- assert(isa<CXXMemberCallExpr>(call) || isa<CXXOperatorCallExpr>(call));
- kind = FK_MemberFunction;
- type = Expr::findBoundMemberType(callee);
- } else if (const PointerType *ptr = type->getAs<PointerType>()) {
- type = ptr->getPointeeType();
- kind = FK_FunctionPointer;
+ FnKind Kind;
+ QualType CalleeType = CalleeExpr->getType();
+ if (CalleeType == S.Context.BoundMemberTy) {
+ assert(isa<CXXMemberCallExpr>(E) || isa<CXXOperatorCallExpr>(E));
+ Kind = FK_MemberFunction;
+ CalleeType = Expr::findBoundMemberType(CalleeExpr);
+ } else if (const PointerType *Ptr = CalleeType->getAs<PointerType>()) {
+ CalleeType = Ptr->getPointeeType();
+ Kind = FK_FunctionPointer;
} else {
- type = type->castAs<BlockPointerType>()->getPointeeType();
- kind = FK_BlockPointer;
+ CalleeType = CalleeType->castAs<BlockPointerType>()->getPointeeType();
+ Kind = FK_BlockPointer;
}
- const FunctionType *fnType = type->castAs<FunctionType>();
+ const FunctionType *FnType = CalleeType->castAs<FunctionType>();
// Verify that this is a legal result type of a function.
if (DestType->isArrayType() || DestType->isFunctionType()) {
unsigned diagID = diag::err_func_returning_array_function;
- if (kind == FK_BlockPointer)
+ if (Kind == FK_BlockPointer)
diagID = diag::err_block_returning_array_function;
- S.Diag(call->getExprLoc(), diagID)
+ S.Diag(E->getExprLoc(), diagID)
<< DestType->isFunctionType() << DestType;
return ExprError();
}
// Otherwise, go ahead and set DestType as the call's result.
- call->setType(DestType.getNonLValueExprType(S.Context));
- call->setValueKind(Expr::getValueKindForType(DestType));
- assert(call->getObjectKind() == OK_Ordinary);
+ E->setType(DestType.getNonLValueExprType(S.Context));
+ E->setValueKind(Expr::getValueKindForType(DestType));
+ assert(E->getObjectKind() == OK_Ordinary);
// Rebuild the function type, replacing the result type with DestType.
- if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fnType))
+ if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FnType))
DestType = S.Context.getFunctionType(DestType,
- proto->arg_type_begin(),
- proto->getNumArgs(),
- proto->getExtProtoInfo());
+ Proto->arg_type_begin(),
+ Proto->getNumArgs(),
+ Proto->getExtProtoInfo());
else
DestType = S.Context.getFunctionNoProtoType(DestType,
- fnType->getExtInfo());
+ FnType->getExtInfo());
// Rebuild the appropriate pointer-to-function type.
- switch (kind) {
+ switch (Kind) {
case FK_MemberFunction:
// Nothing to do.
break;
@@ -9556,121 +9839,131 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *call) {
}
// Finally, we can recurse.
- ExprResult calleeResult = Visit(callee);
- if (!calleeResult.isUsable()) return ExprError();
- call->setCallee(calleeResult.take());
+ ExprResult CalleeResult = Visit(CalleeExpr);
+ if (!CalleeResult.isUsable()) return ExprError();
+ E->setCallee(CalleeResult.take());
// Bind a temporary if necessary.
- return S.MaybeBindToTemporary(call);
+ return S.MaybeBindToTemporary(E);
}
-ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *msg) {
+ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *E) {
// Verify that this is a legal result type of a call.
if (DestType->isArrayType() || DestType->isFunctionType()) {
- S.Diag(msg->getExprLoc(), diag::err_func_returning_array_function)
+ S.Diag(E->getExprLoc(), diag::err_func_returning_array_function)
<< DestType->isFunctionType() << DestType;
return ExprError();
}
// Rewrite the method result type if available.
- if (ObjCMethodDecl *method = msg->getMethodDecl()) {
- assert(method->getResultType() == S.Context.UnknownAnyTy);
- method->setResultType(DestType);
+ if (ObjCMethodDecl *Method = E->getMethodDecl()) {
+ assert(Method->getResultType() == S.Context.UnknownAnyTy);
+ Method->setResultType(DestType);
}
// Change the type of the message.
- msg->setType(DestType.getNonReferenceType());
- msg->setValueKind(Expr::getValueKindForType(DestType));
+ E->setType(DestType.getNonReferenceType());
+ E->setValueKind(Expr::getValueKindForType(DestType));
- return S.MaybeBindToTemporary(msg);
+ return S.MaybeBindToTemporary(E);
}
-ExprResult RebuildUnknownAnyExpr::VisitImplicitCastExpr(ImplicitCastExpr *ice) {
+ExprResult RebuildUnknownAnyExpr::VisitImplicitCastExpr(ImplicitCastExpr *E) {
// The only case we should ever see here is a function-to-pointer decay.
- assert(ice->getCastKind() == CK_FunctionToPointerDecay);
- assert(ice->getValueKind() == VK_RValue);
- assert(ice->getObjectKind() == OK_Ordinary);
+ assert(E->getCastKind() == CK_FunctionToPointerDecay);
+ assert(E->getValueKind() == VK_RValue);
+ assert(E->getObjectKind() == OK_Ordinary);
- ice->setType(DestType);
+ E->setType(DestType);
// Rebuild the sub-expression as the pointee (function) type.
DestType = DestType->castAs<PointerType>()->getPointeeType();
- ExprResult result = Visit(ice->getSubExpr());
- if (!result.isUsable()) return ExprError();
+ ExprResult Result = Visit(E->getSubExpr());
+ if (!Result.isUsable()) return ExprError();
- ice->setSubExpr(result.take());
- return S.Owned(ice);
+ E->setSubExpr(Result.take());
+ return S.Owned(E);
}
-ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *expr, ValueDecl *decl) {
- ExprValueKind valueKind = VK_LValue;
- QualType type = DestType;
+ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *E, ValueDecl *VD) {
+ ExprValueKind ValueKind = VK_LValue;
+ QualType Type = DestType;
// We know how to make this work for certain kinds of decls:
// - functions
- if (FunctionDecl *fn = dyn_cast<FunctionDecl>(decl)) {
- // This is true because FunctionDecls must always have function
- // type, so we can't be resolving the entire thing at once.
- assert(type->isFunctionType());
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(VD)) {
+ if (const PointerType *Ptr = Type->getAs<PointerType>()) {
+ DestType = Ptr->getPointeeType();
+ ExprResult Result = resolveDecl(E, VD);
+ if (Result.isInvalid()) return ExprError();
+ return S.ImpCastExprToType(Result.take(), Type,
+ CK_FunctionToPointerDecay, VK_RValue);
+ }
+
+ if (!Type->isFunctionType()) {
+ S.Diag(E->getExprLoc(), diag::err_unknown_any_function)
+ << VD << E->getSourceRange();
+ return ExprError();
+ }
- if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(fn))
- if (method->isInstance()) {
- valueKind = VK_RValue;
- type = S.Context.BoundMemberTy;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
+ if (MD->isInstance()) {
+ ValueKind = VK_RValue;
+ Type = S.Context.BoundMemberTy;
}
// Function references aren't l-values in C.
if (!S.getLangOptions().CPlusPlus)
- valueKind = VK_RValue;
+ ValueKind = VK_RValue;
// - variables
- } else if (isa<VarDecl>(decl)) {
- if (const ReferenceType *refTy = type->getAs<ReferenceType>()) {
- type = refTy->getPointeeType();
- } else if (type->isFunctionType()) {
- S.Diag(expr->getExprLoc(), diag::err_unknown_any_var_function_type)
- << decl << expr->getSourceRange();
+ } else if (isa<VarDecl>(VD)) {
+ if (const ReferenceType *RefTy = Type->getAs<ReferenceType>()) {
+ Type = RefTy->getPointeeType();
+ } else if (Type->isFunctionType()) {
+ S.Diag(E->getExprLoc(), diag::err_unknown_any_var_function_type)
+ << VD << E->getSourceRange();
return ExprError();
}
// - nothing else
} else {
- S.Diag(expr->getExprLoc(), diag::err_unsupported_unknown_any_decl)
- << decl << expr->getSourceRange();
+ S.Diag(E->getExprLoc(), diag::err_unsupported_unknown_any_decl)
+ << VD << E->getSourceRange();
return ExprError();
}
- decl->setType(DestType);
- expr->setType(type);
- expr->setValueKind(valueKind);
- return S.Owned(expr);
+ VD->setType(DestType);
+ E->setType(Type);
+ E->setValueKind(ValueKind);
+ return S.Owned(E);
}
/// Check a cast of an unknown-any type. We intentionally only
/// trigger this for C-style casts.
-ExprResult Sema::checkUnknownAnyCast(SourceRange typeRange, QualType castType,
- Expr *castExpr, CastKind &castKind,
- ExprValueKind &VK, CXXCastPath &path) {
+ExprResult Sema::checkUnknownAnyCast(SourceRange TypeRange, QualType CastType,
+ Expr *CastExpr, CastKind &CastKind,
+ ExprValueKind &VK, CXXCastPath &Path) {
// Rewrite the casted expression from scratch.
- ExprResult result = RebuildUnknownAnyExpr(*this, castType).Visit(castExpr);
+ ExprResult result = RebuildUnknownAnyExpr(*this, CastType).Visit(CastExpr);
if (!result.isUsable()) return ExprError();
- castExpr = result.take();
- VK = castExpr->getValueKind();
- castKind = CK_NoOp;
+ CastExpr = result.take();
+ VK = CastExpr->getValueKind();
+ CastKind = CK_NoOp;
- return castExpr;
+ return CastExpr;
}
-static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *e) {
- Expr *orig = e;
+static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) {
+ Expr *orig = E;
unsigned diagID = diag::err_uncasted_use_of_unknown_any;
while (true) {
- e = e->IgnoreParenImpCasts();
- if (CallExpr *call = dyn_cast<CallExpr>(e)) {
- e = call->getCallee();
+ E = E->IgnoreParenImpCasts();
+ if (CallExpr *call = dyn_cast<CallExpr>(E)) {
+ E = call->getCallee();
diagID = diag::err_uncasted_call_of_unknown_any;
} else {
break;
@@ -9679,20 +9972,25 @@ static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *e) {
SourceLocation loc;
NamedDecl *d;
- if (DeclRefExpr *ref = dyn_cast<DeclRefExpr>(e)) {
+ if (DeclRefExpr *ref = dyn_cast<DeclRefExpr>(E)) {
loc = ref->getLocation();
d = ref->getDecl();
- } else if (MemberExpr *mem = dyn_cast<MemberExpr>(e)) {
+ } else if (MemberExpr *mem = dyn_cast<MemberExpr>(E)) {
loc = mem->getMemberLoc();
d = mem->getMemberDecl();
- } else if (ObjCMessageExpr *msg = dyn_cast<ObjCMessageExpr>(e)) {
+ } else if (ObjCMessageExpr *msg = dyn_cast<ObjCMessageExpr>(E)) {
diagID = diag::err_uncasted_call_of_unknown_any;
- loc = msg->getSelectorLoc();
+ loc = msg->getSelectorStartLoc();
d = msg->getMethodDecl();
- assert(d && "unknown method returning __unknown_any?");
+ if (!d) {
+ S.Diag(loc, diag::err_uncasted_send_to_unknown_any_method)
+ << static_cast<unsigned>(msg->isClassMessage()) << msg->getSelector()
+ << orig->getSourceRange();
+ return ExprError();
+ }
} else {
- S.Diag(e->getExprLoc(), diag::err_unsupported_unknown_any_expr)
- << e->getSourceRange();
+ S.Diag(E->getExprLoc(), diag::err_unsupported_unknown_any_expr)
+ << E->getSourceRange();
return ExprError();
}
@@ -9709,17 +10007,27 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
QualType type = E->getType();
// Overloaded expressions.
- if (type == Context.OverloadTy)
- return ResolveAndFixSingleFunctionTemplateSpecialization(E, false, true,
- E->getSourceRange(),
- QualType(),
- diag::err_ovl_unresolvable);
+ if (type == Context.OverloadTy) {
+ // Try to resolve a single function template specialization.
+ // This is obligatory.
+ ExprResult result = Owned(E);
+ if (ResolveAndFixSingleFunctionTemplateSpecialization(result, false)) {
+ return result;
+
+ // If that failed, try to recover with a call.
+ } else {
+ tryToRecoverWithCall(result, PDiag(diag::err_ovl_unresolvable),
+ /*complain*/ true);
+ return result;
+ }
+ }
// Bound member functions.
if (type == Context.BoundMemberTy) {
- Diag(E->getLocStart(), diag::err_invalid_use_of_bound_member_func)
- << E->getSourceRange();
- return ExprError();
+ ExprResult result = Owned(E);
+ tryToRecoverWithCall(result, PDiag(diag::err_bound_member_function),
+ /*complain*/ true);
+ return result;
}
// Expressions of unknown type.
@@ -9730,10 +10038,10 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
return Owned(E);
}
-bool Sema::CheckCaseExpression(Expr *expr) {
- if (expr->isTypeDependent())
+bool Sema::CheckCaseExpression(Expr *E) {
+ if (E->isTypeDependent())
return true;
- if (expr->isValueDependent() || expr->isIntegerConstantExpr(Context))
- return expr->getType()->isIntegralOrEnumerationType();
+ if (E->isValueDependent() || E->isIntegerConstantExpr(Context))
+ return E->getType()->isIntegralOrEnumerationType();
return false;
}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index e804fcd60c74..3300444a1c1e 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -295,6 +295,12 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
SourceLocation RParenLoc) {
bool isUnevaluatedOperand = true;
if (E && !E->isTypeDependent()) {
+ if (E->getType()->isPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(E);
+ if (result.isInvalid()) return ExprError();
+ E = result.take();
+ }
+
QualType T = E->getType();
if (const RecordType *RecordT = T->getAs<RecordType>()) {
CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl());
@@ -325,7 +331,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
QualType UnqualT = Context.getUnqualifiedArrayType(T, Quals);
if (!Context.hasSameType(T, UnqualT)) {
T = UnqualT;
- E = ImpCastExprToType(E, UnqualT, CK_NoOp, CastCategory(E)).take();
+ E = ImpCastExprToType(E, UnqualT, CK_NoOp, E->getValueKind()).take();
}
}
@@ -545,7 +551,7 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
// or "pointer to function returning T", [...]
if (E->getType().hasQualifiers())
E = ImpCastExprToType(E, E->getType().getUnqualifiedType(), CK_NoOp,
- CastCategory(E)).take();
+ E->getValueKind()).take();
ExprResult Res = DefaultFunctionArrayConversion(E);
if (Res.isInvalid())
@@ -739,27 +745,10 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
// If the expression list is a single expression, the type conversion
// expression is equivalent (in definedness, and if defined in meaning) to the
// corresponding cast expression.
- //
if (NumExprs == 1) {
- CastKind Kind = CK_Invalid;
- ExprValueKind VK = VK_RValue;
- CXXCastPath BasePath;
- ExprResult CastExpr =
- CheckCastTypes(TInfo->getTypeLoc().getBeginLoc(),
- TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0],
- Kind, VK, BasePath,
- /*FunctionalStyle=*/true);
- if (CastExpr.isInvalid())
- return ExprError();
- Exprs[0] = CastExpr.take();
-
+ Expr *Arg = Exprs[0];
exprs.release();
-
- return Owned(CXXFunctionalCastExpr::Create(Context,
- Ty.getNonLValueExprType(Context),
- VK, TInfo, TyBeginLoc, Kind,
- Exprs[0], &BasePath,
- RParenLoc));
+ return BuildCXXFunctionalCastExpr(TInfo, LParenLoc, Arg, RParenLoc);
}
InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo);
@@ -1058,7 +1047,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
UsualArrayDeleteWantsSize
= doesUsualArrayDeleteWantSize(*this, StartLoc, AllocType);
- llvm::SmallVector<Expr *, 8> AllPlaceArgs;
+ SmallVector<Expr *, 8> AllPlaceArgs;
if (OperatorNew) {
// Add default arguments, if any.
const FunctionProtoType *Proto =
@@ -1079,6 +1068,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
bool Init = ConstructorLParen.isValid();
// --- Choosing a constructor ---
CXXConstructorDecl *Constructor = 0;
+ bool HadMultipleCandidates = false;
Expr **ConsArgs = (Expr**)ConstructorArgs.get();
unsigned NumConsArgs = ConstructorArgs.size();
ASTOwningVector<Expr*> ConvertedConstructorArgs(*this);
@@ -1125,6 +1115,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (CXXConstructExpr *Construct
= dyn_cast<CXXConstructExpr>(FullInitExpr)) {
Constructor = Construct->getConstructor();
+ HadMultipleCandidates = Construct->hadMultipleCandidates();
for (CXXConstructExpr::arg_iterator A = Construct->arg_begin(),
AEnd = Construct->arg_end();
A != AEnd; ++A)
@@ -1166,7 +1157,9 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
return Owned(new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew,
PlaceArgs, NumPlaceArgs, TypeIdParens,
ArraySize, Constructor, Init,
- ConsArgs, NumConsArgs, OperatorDelete,
+ ConsArgs, NumConsArgs,
+ HadMultipleCandidates,
+ OperatorDelete,
UsualArrayDeleteWantsSize,
ResultType, AllocTypeInfo,
StartLoc,
@@ -1246,12 +1239,12 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// 3) The first argument is always size_t. Append the arguments from the
// placement form.
- llvm::SmallVector<Expr*, 8> AllocArgs(1 + NumPlaceArgs);
+ SmallVector<Expr*, 8> AllocArgs(1 + NumPlaceArgs);
// We don't care about the actual value of this argument.
// FIXME: Should the Sema create the expression and embed it in the syntax
// tree? Or should the consumer just recalculate the value?
IntegerLiteral Size(Context, llvm::APInt::getNullValue(
- Context.Target.getPointerWidth(0)),
+ Context.getTargetInfo().getPointerWidth(0)),
Context.getSizeType(),
SourceLocation());
AllocArgs[0] = &Size;
@@ -1325,7 +1318,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
FoundDelete.suppressDiagnostics();
- llvm::SmallVector<std::pair<DeclAccessPair,FunctionDecl*>, 2> Matches;
+ SmallVector<std::pair<DeclAccessPair,FunctionDecl*>, 2> Matches;
// Whether we're looking for a placement operator delete is dictated
// by whether we selected a placement operator new, not by whether
@@ -1352,7 +1345,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
const FunctionProtoType *Proto
= OperatorNew->getType()->getAs<FunctionProtoType>();
- llvm::SmallVector<QualType, 4> ArgTypes;
+ SmallVector<QualType, 4> ArgTypes;
ArgTypes.push_back(Context.VoidPtrTy);
for (unsigned I = 1, N = Proto->getNumArgs(); I < N; ++I)
ArgTypes.push_back(Proto->getArgType(I));
@@ -1525,8 +1518,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
return true;
}
}
- assert(false && "Unreachable, bad result from BestViableFunction");
- return true;
+ llvm_unreachable("Unreachable, bad result from BestViableFunction");
}
@@ -1671,7 +1663,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
SourceLocation(), 0,
Argument, /*TInfo=*/0,
SC_None, SC_None, 0);
- Alloc->setParams(&Param, 1);
+ Alloc->setParams(Param);
// FIXME: Also add this declaration to the IdentifierResolver, but
// make sure it is at the end of the chain to coincide with the
@@ -1691,7 +1683,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
Found.suppressDiagnostics();
- llvm::SmallVector<DeclAccessPair,4> Matches;
+ SmallVector<DeclAccessPair,4> Matches;
for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
F != FEnd; ++F) {
NamedDecl *ND = (*F)->getUnderlyingDecl();
@@ -1727,7 +1719,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found)
<< Name << RD;
- for (llvm::SmallVectorImpl<DeclAccessPair>::iterator
+ for (SmallVectorImpl<DeclAccessPair>::iterator
F = Matches.begin(), FEnd = Matches.end(); F != FEnd; ++F)
Diag((*F)->getUnderlyingDecl()->getLocation(),
diag::note_member_declared_here) << Name;
@@ -1792,7 +1784,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
PDiag(diag::err_delete_incomplete_class_type)))
return ExprError();
- llvm::SmallVector<CXXConversionDecl*, 4> ObjectPtrConversions;
+ SmallVector<CXXConversionDecl*, 4> ObjectPtrConversions;
CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions();
@@ -1840,24 +1832,32 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
<< Type << Ex.get()->getSourceRange());
QualType Pointee = Type->getAs<PointerType>()->getPointeeType();
+ QualType PointeeElem = Context.getBaseElementType(Pointee);
+
+ if (unsigned AddressSpace = Pointee.getAddressSpace())
+ return Diag(Ex.get()->getLocStart(),
+ diag::err_address_space_qualified_delete)
+ << Pointee.getUnqualifiedType() << AddressSpace;
+
+ CXXRecordDecl *PointeeRD = 0;
if (Pointee->isVoidType() && !isSFINAEContext()) {
// The C++ standard bans deleting a pointer to a non-object type, which
// effectively bans deletion of "void*". However, most compilers support
// this, so we treat it as a warning unless we're in a SFINAE context.
Diag(StartLoc, diag::ext_delete_void_ptr_operand)
<< Type << Ex.get()->getSourceRange();
- } else if (Pointee->isFunctionType() || Pointee->isVoidType())
+ } else if (Pointee->isFunctionType() || Pointee->isVoidType()) {
return ExprError(Diag(StartLoc, diag::err_delete_operand)
<< Type << Ex.get()->getSourceRange());
- else if (!Pointee->isDependentType() &&
- RequireCompleteType(StartLoc, Pointee,
- PDiag(diag::warn_delete_incomplete)
- << Ex.get()->getSourceRange()))
- return ExprError();
- else if (unsigned AddressSpace = Pointee.getAddressSpace())
- return Diag(Ex.get()->getLocStart(),
- diag::err_address_space_qualified_delete)
- << Pointee.getUnqualifiedType() << AddressSpace;
+ } else if (!Pointee->isDependentType()) {
+ if (!RequireCompleteType(StartLoc, Pointee,
+ PDiag(diag::warn_delete_incomplete)
+ << Ex.get()->getSourceRange())) {
+ if (const RecordType *RT = PointeeElem->getAs<RecordType>())
+ PointeeRD = cast<CXXRecordDecl>(RT->getDecl());
+ }
+ }
+
// C++ [expr.delete]p2:
// [Note: a pointer to a const type can be the operand of a
// delete-expression; it is not necessary to cast away the constness
@@ -1877,12 +1877,10 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName(
ArrayForm ? OO_Array_Delete : OO_Delete);
- QualType PointeeElem = Context.getBaseElementType(Pointee);
- if (const RecordType *RT = PointeeElem->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
-
+ if (PointeeRD) {
if (!UseGlobal &&
- FindDeallocationFunction(StartLoc, RD, DeleteName, OperatorDelete))
+ FindDeallocationFunction(StartLoc, PointeeRD, DeleteName,
+ OperatorDelete))
return ExprError();
// If we're allocating an array of records, check whether the
@@ -1900,8 +1898,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
UsualArrayDeleteWantsSize = (OperatorDelete->getNumParams() == 2);
}
- if (!RD->hasTrivialDestructor())
- if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) {
+ if (!PointeeRD->hasTrivialDestructor())
+ if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) {
MarkDeclarationReferenced(StartLoc,
const_cast<CXXDestructorDecl*>(Dtor));
DiagnoseUseOfDecl(Dtor, StartLoc);
@@ -1915,10 +1913,20 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
// behavior is undefined.
//
// Note: a final class cannot be derived from, no issue there
- if (!ArrayForm && RD->isPolymorphic() && !RD->hasAttr<FinalAttr>()) {
- CXXDestructorDecl *dtor = RD->getDestructor();
- if (!dtor || !dtor->isVirtual())
- Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem;
+ if (PointeeRD->isPolymorphic() && !PointeeRD->hasAttr<FinalAttr>()) {
+ CXXDestructorDecl *dtor = PointeeRD->getDestructor();
+ if (dtor && !dtor->isVirtual()) {
+ if (PointeeRD->isAbstract()) {
+ // If the class is abstract, we warn by default, because we're
+ // sure the code has undefined behavior.
+ Diag(StartLoc, diag::warn_delete_abstract_non_virtual_dtor)
+ << PointeeElem;
+ } else if (!ArrayForm) {
+ // Otherwise, if this is not an array delete, it's a bit suspect,
+ // but not necessarily wrong.
+ Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem;
+ }
+ }
}
} else if (getLangOptions().ObjCAutoRefCount &&
@@ -1944,9 +1952,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
MarkDeclarationReferenced(StartLoc, OperatorDelete);
// Check access and ambiguity of operator delete and destructor.
- if (const RecordType *RT = PointeeElem->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) {
+ if (PointeeRD) {
+ if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) {
CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor,
PDiag(diag::err_access_dtor) << PointeeElem);
}
@@ -2026,12 +2033,20 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) {
= ToPtrType->getPointeeType()->getAs<BuiltinType>()) {
// This conversion is considered only when there is an
// explicit appropriate pointer target type (C++ 4.2p2).
- if (!ToPtrType->getPointeeType().hasQualifiers() &&
- ((StrLit->isWide() && ToPointeeType->isWideCharType()) ||
- (!StrLit->isWide() &&
- (ToPointeeType->getKind() == BuiltinType::Char_U ||
- ToPointeeType->getKind() == BuiltinType::Char_S))))
- return true;
+ if (!ToPtrType->getPointeeType().hasQualifiers()) {
+ switch (StrLit->getKind()) {
+ case StringLiteral::UTF8:
+ case StringLiteral::UTF16:
+ case StringLiteral::UTF32:
+ // We don't allow UTF literals to be implicitly converted
+ break;
+ case StringLiteral::Ascii:
+ return (ToPointeeType->getKind() == BuiltinType::Char_U ||
+ ToPointeeType->getKind() == BuiltinType::Char_S);
+ case StringLiteral::Wide:
+ return ToPointeeType->isWideCharType();
+ }
+ }
}
return false;
@@ -2042,23 +2057,28 @@ static ExprResult BuildCXXCastArgument(Sema &S,
QualType Ty,
CastKind Kind,
CXXMethodDecl *Method,
- NamedDecl *FoundDecl,
+ DeclAccessPair FoundDecl,
+ bool HadMultipleCandidates,
Expr *From) {
switch (Kind) {
- default: assert(0 && "Unhandled cast kind!");
+ default: llvm_unreachable("Unhandled cast kind!");
case CK_ConstructorConversion: {
+ CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Method);
ASTOwningVector<Expr*> ConstructorArgs(S);
- if (S.CompleteConstructorCall(cast<CXXConstructorDecl>(Method),
+ if (S.CompleteConstructorCall(Constructor,
MultiExprArg(&From, 1),
CastLoc, ConstructorArgs))
return ExprError();
- ExprResult Result =
- S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method),
- move_arg(ConstructorArgs),
- /*ZeroInit*/ false, CXXConstructExpr::CK_Complete,
- SourceRange());
+ S.CheckConstructorAccess(CastLoc, Constructor, Constructor->getAccess(),
+ S.PDiag(diag::err_access_ctor));
+
+ ExprResult Result
+ = S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method),
+ move_arg(ConstructorArgs),
+ HadMultipleCandidates, /*ZeroInit*/ false,
+ CXXConstructExpr::CK_Complete, SourceRange());
if (Result.isInvalid())
return ExprError();
@@ -2069,10 +2089,13 @@ static ExprResult BuildCXXCastArgument(Sema &S,
assert(!From->getType()->isPointerType() && "Arg can't have pointer type!");
// Create an implicit call expr that calls it.
- ExprResult Result = S.BuildCXXMemberCallExpr(From, FoundDecl, Method);
+ ExprResult Result = S.BuildCXXMemberCallExpr(From, FoundDecl, Method,
+ HadMultipleCandidates);
if (Result.isInvalid())
return ExprError();
+ S.CheckMemberOperatorAccess(CastLoc, From, /*arg*/ 0, FoundDecl);
+
return S.MaybeBindToTemporary(Result.get());
}
}
@@ -2138,6 +2161,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
ToType.getNonReferenceType(),
CastKind, cast<CXXMethodDecl>(FD),
ICS.UserDefined.FoundConversionFunction,
+ ICS.UserDefined.HadMultipleCandidates,
From);
if (CastArg.isInvalid())
@@ -2156,8 +2180,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
return ExprError();
case ImplicitConversionSequence::EllipsisConversion:
- assert(false && "Cannot perform an ellipsis conversion");
- return Owned(From);
+ llvm_unreachable("Cannot perform an ellipsis conversion");
case ImplicitConversionSequence::BadConversion:
return ExprError();
@@ -2198,6 +2221,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
ToType, SCS.CopyConstructor,
move_arg(ConstructorArgs),
+ /*HadMultipleCandidates*/ false,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
@@ -2205,6 +2229,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
ToType, SCS.CopyConstructor,
MultiExprArg(*this, &From, 1),
+ /*HadMultipleCandidates*/ false,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
@@ -2241,9 +2266,6 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
if (!From->isGLValue()) break;
}
- // Check for trivial buffer overflows.
- CheckArrayAccess(From);
-
FromType = FromType.getUnqualifiedType();
From = ImplicitCastExpr::Create(Context, FromType, CK_LValueToRValue,
From, 0, VK_RValue);
@@ -2262,8 +2284,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
break;
default:
- assert(false && "Improper first standard conversion");
- break;
+ llvm_unreachable("Improper first standard conversion");
}
// Perform the second implicit conversion
@@ -2340,12 +2361,12 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
Diag(From->getSourceRange().getBegin(),
diag::ext_typecheck_convert_incompatible_pointer)
<< ToType << From->getType() << Action
- << From->getSourceRange();
+ << From->getSourceRange() << 0;
else
Diag(From->getSourceRange().getBegin(),
diag::ext_typecheck_convert_incompatible_pointer)
<< From->getType() << ToType << Action
- << From->getSourceRange();
+ << From->getSourceRange() << 0;
if (From->getType()->isObjCObjectPointerType() &&
ToType->isObjCObjectPointerType())
@@ -2354,20 +2375,29 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
else if (getLangOptions().ObjCAutoRefCount &&
!CheckObjCARCUnavailableWeakConversion(ToType,
From->getType())) {
- if (Action == AA_Initializing)
- Diag(From->getSourceRange().getBegin(),
- diag::err_arc_weak_unavailable_assign);
- else
- Diag(From->getSourceRange().getBegin(),
- diag::err_arc_convesion_of_weak_unavailable)
- << (Action == AA_Casting) << From->getType() << ToType
- << From->getSourceRange();
- }
+ if (Action == AA_Initializing)
+ Diag(From->getSourceRange().getBegin(),
+ diag::err_arc_weak_unavailable_assign);
+ else
+ Diag(From->getSourceRange().getBegin(),
+ diag::err_arc_convesion_of_weak_unavailable)
+ << (Action == AA_Casting) << From->getType() << ToType
+ << From->getSourceRange();
+ }
CastKind Kind = CK_Invalid;
CXXCastPath BasePath;
if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle))
return ExprError();
+
+ // Make sure we extend blocks if necessary.
+ // FIXME: doing this here is really ugly.
+ if (Kind == CK_BlockPointerToObjCPointerCast) {
+ ExprResult E = From;
+ (void) PrepareCastToObjCObjectPointer(E);
+ From = E.take();
+ }
+
From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK)
.take();
break;
@@ -2386,6 +2416,12 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
}
case ICK_Boolean_Conversion:
+ // Perform half-to-boolean conversion via float.
+ if (From->getType()->isHalfType()) {
+ From = ImpCastExprToType(From, Context.FloatTy, CK_FloatingCast).take();
+ FromType = Context.FloatTy;
+ }
+
From = ImpCastExprToType(From, Context.BoolTy,
ScalarTypeToBooleanCastKind(FromType),
VK_RValue, /*BasePath=*/0, CCK).take();
@@ -2402,7 +2438,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
return ExprError();
From = ImpCastExprToType(From, ToType.getNonReferenceType(),
- CK_DerivedToBase, CastCategory(From),
+ CK_DerivedToBase, From->getValueKind(),
&BasePath, CCK).take();
break;
}
@@ -2493,8 +2529,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
case ICK_Function_To_Pointer:
case ICK_Qualification:
case ICK_Num_Conversion_Kinds:
- assert(false && "Improper second standard conversion");
- break;
+ llvm_unreachable("Improper second standard conversion");
}
switch (SCS.Third) {
@@ -2506,7 +2541,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
// The qualification keeps the category of the inner expression, unless the
// target type isn't a reference.
ExprValueKind VK = ToType->isReferenceType() ?
- CastCategory(From) : VK_RValue;
+ From->getValueKind() : VK_RValue;
From = ImpCastExprToType(From, ToType.getNonLValueExprType(Context),
CK_NoOp, VK, /*BasePath=*/0, CCK).take();
@@ -2519,8 +2554,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
}
default:
- assert(false && "Improper third standard conversion");
- break;
+ llvm_unreachable("Improper third standard conversion");
}
return Owned(From);
@@ -2835,8 +2869,12 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
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;
@@ -2849,7 +2887,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
}
}
}
-
+
return FoundAssign;
}
return false;
@@ -3240,34 +3278,34 @@ ExprResult Sema::BuildExpressionTrait(ExpressionTrait ET,
RParen, Context.BoolTy));
}
-QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex,
+QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS,
ExprValueKind &VK,
SourceLocation Loc,
bool isIndirect) {
- assert(!lex.get()->getType()->isPlaceholderType() &&
- !rex.get()->getType()->isPlaceholderType() &&
+ assert(!LHS.get()->getType()->isPlaceholderType() &&
+ !RHS.get()->getType()->isPlaceholderType() &&
"placeholders should have been weeded out by now");
// The LHS undergoes lvalue conversions if this is ->*.
if (isIndirect) {
- lex = DefaultLvalueConversion(lex.take());
- if (lex.isInvalid()) return QualType();
+ LHS = DefaultLvalueConversion(LHS.take());
+ if (LHS.isInvalid()) return QualType();
}
// The RHS always undergoes lvalue conversions.
- rex = DefaultLvalueConversion(rex.take());
- if (rex.isInvalid()) return QualType();
+ RHS = DefaultLvalueConversion(RHS.take());
+ if (RHS.isInvalid()) return QualType();
const char *OpSpelling = isIndirect ? "->*" : ".*";
// C++ 5.5p2
// The binary operator .* [p3: ->*] binds its second operand, which shall
// be of type "pointer to member of T" (where T is a completely-defined
// class type) [...]
- QualType RType = rex.get()->getType();
- const MemberPointerType *MemPtr = RType->getAs<MemberPointerType>();
+ QualType RHSType = RHS.get()->getType();
+ const MemberPointerType *MemPtr = RHSType->getAs<MemberPointerType>();
if (!MemPtr) {
Diag(Loc, diag::err_bad_memptr_rhs)
- << OpSpelling << RType << rex.get()->getSourceRange();
+ << OpSpelling << RHSType << RHS.get()->getSourceRange();
return QualType();
}
@@ -3283,21 +3321,21 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex,
// [...] to its first operand, which shall be of class T or of a class of
// which T is an unambiguous and accessible base class. [p3: a pointer to
// such a class]
- QualType LType = lex.get()->getType();
+ QualType LHSType = LHS.get()->getType();
if (isIndirect) {
- if (const PointerType *Ptr = LType->getAs<PointerType>())
- LType = Ptr->getPointeeType();
+ if (const PointerType *Ptr = LHSType->getAs<PointerType>())
+ LHSType = Ptr->getPointeeType();
else {
Diag(Loc, diag::err_bad_memptr_lhs)
- << OpSpelling << 1 << LType
+ << OpSpelling << 1 << LHSType
<< FixItHint::CreateReplacement(SourceRange(Loc), ".*");
return QualType();
}
}
- if (!Context.hasSameUnqualifiedType(Class, LType)) {
+ if (!Context.hasSameUnqualifiedType(Class, LHSType)) {
// If we want to check the hierarchy, we need a complete type.
- if (RequireCompleteType(Loc, LType, PDiag(diag::err_bad_memptr_lhs)
+ if (RequireCompleteType(Loc, LHSType, PDiag(diag::err_bad_memptr_lhs)
<< OpSpelling << (int)isIndirect)) {
return QualType();
}
@@ -3305,23 +3343,23 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex,
/*DetectVirtual=*/false);
// FIXME: Would it be useful to print full ambiguity paths, or is that
// overkill?
- if (!IsDerivedFrom(LType, Class, Paths) ||
+ if (!IsDerivedFrom(LHSType, Class, Paths) ||
Paths.isAmbiguous(Context.getCanonicalType(Class))) {
Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling
- << (int)isIndirect << lex.get()->getType();
+ << (int)isIndirect << LHS.get()->getType();
return QualType();
}
// Cast LHS to type of use.
QualType UseType = isIndirect ? Context.getPointerType(Class) : Class;
- ExprValueKind VK =
- isIndirect ? VK_RValue : CastCategory(lex.get());
+ ExprValueKind VK = isIndirect ? VK_RValue : LHS.get()->getValueKind();
CXXCastPath BasePath;
BuildBasePathArray(Paths, BasePath);
- lex = ImpCastExprToType(lex.take(), UseType, CK_DerivedToBase, VK, &BasePath);
+ LHS = ImpCastExprToType(LHS.take(), UseType, CK_DerivedToBase, VK,
+ &BasePath);
}
- if (isa<CXXScalarValueInitExpr>(rex.get()->IgnoreParens())) {
+ if (isa<CXXScalarValueInitExpr>(RHS.get()->IgnoreParens())) {
// Diagnose use of pointer-to-member type which when used as
// the functional cast in a pointer-to-member expression.
Diag(Loc, diag::err_pointer_to_member_type) << isIndirect;
@@ -3334,7 +3372,7 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex,
// The cv qualifiers are the union of those in the pointer and the left side,
// in accordance with 5.5p5 and 5.2.5.
QualType Result = MemPtr->getPointeeType();
- Result = Context.getCVRQualifiedType(Result, LType.getCVRQualifiers());
+ Result = Context.getCVRQualifiedType(Result, LHSType.getCVRQualifiers());
// C++0x [expr.mptr.oper]p6:
// In a .* expression whose object expression is an rvalue, the program is
@@ -3349,15 +3387,15 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex,
break;
case RQ_LValue:
- if (!isIndirect && !lex.get()->Classify(Context).isLValue())
+ if (!isIndirect && !LHS.get()->Classify(Context).isLValue())
Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
- << RType << 1 << lex.get()->getSourceRange();
+ << RHSType << 1 << LHS.get()->getSourceRange();
break;
case RQ_RValue:
- if (isIndirect || !lex.get()->Classify(Context).isRValue())
+ if (isIndirect || !LHS.get()->Classify(Context).isRValue())
Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
- << RType << 0 << lex.get()->getSourceRange();
+ << RHSType << 0 << LHS.get()->getSourceRange();
break;
}
}
@@ -3375,7 +3413,7 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex,
} else if (isIndirect) {
VK = VK_LValue;
} else {
- VK = lex.get()->getValueKind();
+ VK = LHS.get()->getValueKind();
}
return Result;
@@ -3528,8 +3566,7 @@ static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS
break;
case OR_Deleted:
- assert(false && "Conditional operator has only built-in overloads");
- break;
+ llvm_unreachable("Conditional operator has only built-in overloads");
}
return true;
}
@@ -3838,9 +3875,9 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
// conversions in both directions. If only one works, or if the two composite
// types are the same, we have succeeded.
// FIXME: extended qualifiers?
- typedef llvm::SmallVector<unsigned, 4> QualifierVector;
+ typedef SmallVector<unsigned, 4> QualifierVector;
QualifierVector QualifierUnion;
- typedef llvm::SmallVector<std::pair<const Type *, const Type *>, 4>
+ typedef SmallVector<std::pair<const Type *, const Type *>, 4>
ContainingClassVector;
ContainingClassVector MemberOfClass;
QualType Composite1 = Context.getCanonicalType(T1),
@@ -4044,27 +4081,30 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
// actual method. FIXME: we should infer retention by selector in
// cases where we don't have an actual method.
} else {
- Decl *D = 0;
+ ObjCMethodDecl *D = 0;
if (ObjCMessageExpr *Send = dyn_cast<ObjCMessageExpr>(E)) {
D = Send->getMethodDecl();
} else {
CastExpr *CE = cast<CastExpr>(E);
- // FIXME. What other cast kinds to check for?
- if (CE->getCastKind() == CK_ObjCProduceObject ||
- CE->getCastKind() == CK_LValueToRValue)
- return MaybeBindToTemporary(CE->getSubExpr());
assert(CE->getCastKind() == CK_GetObjCProperty);
const ObjCPropertyRefExpr *PRE = CE->getSubExpr()->getObjCProperty();
D = (PRE->isImplicitProperty() ? PRE->getImplicitPropertyGetter() : 0);
}
ReturnsRetained = (D && D->hasAttr<NSReturnsRetainedAttr>());
+
+ // Don't do reclaims on performSelector calls; despite their
+ // return type, the invoked method doesn't necessarily actually
+ // return an object.
+ if (!ReturnsRetained &&
+ D && D->getMethodFamily() == OMF_performSelector)
+ return Owned(E);
}
ExprNeedsCleanups = true;
- CastKind ck = (ReturnsRetained ? CK_ObjCConsumeObject
- : CK_ObjCReclaimReturnedObject);
+ CastKind ck = (ReturnsRetained ? CK_ARCConsumeObject
+ : CK_ARCReclaimReturnedObject);
return Owned(ImplicitCastExpr::Create(Context, E->getType(), ck, E, 0,
VK_RValue));
}
@@ -4172,7 +4212,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc,
if (OpKind == tok::arrow) {
// The set of types we've considered so far.
llvm::SmallPtrSet<CanQualType,8> CTypes;
- llvm::SmallVector<SourceLocation, 8> Locations;
+ SmallVector<SourceLocation, 8> Locations;
CTypes.insert(Context.getCanonicalType(BaseType));
while (BaseType->isRecordType()) {
@@ -4509,7 +4549,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
}
ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
- CXXMethodDecl *Method) {
+ CXXMethodDecl *Method,
+ bool HadMultipleCandidates) {
ExprResult Exp = PerformObjectArgumentInitialization(E, /*Qualifier=*/0,
FoundDecl, Method);
if (Exp.isInvalid())
@@ -4519,6 +4560,9 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
new (Context) MemberExpr(Exp.take(), /*IsArrow=*/false, Method,
SourceLocation(), Method->getType(),
VK_RValue, OK_Ordinary);
+ if (HadMultipleCandidates)
+ ME->setHadMultipleCandidates(true);
+
QualType ResultType = Method->getResultType();
ExprValueKind VK = Expr::getValueKindForType(ResultType);
ResultType = ResultType.getNonLValueExprType(Context);
@@ -4608,7 +4652,7 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE) {
if (FullExpr.isInvalid())
return ExprError();
- CheckImplicitConversions(FullExpr.get());
+ CheckImplicitConversions(FullExpr.get(), FullExpr.get()->getExprLoc());
return MaybeCreateExprWithCleanups(FullExpr);
}
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index 2488dc8849dd..26867c21a1aa 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -298,7 +298,7 @@ CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK,
// We didn't get to the end of the string. This means the component names
// didn't come from the same set *or* we encountered an illegal name.
S.Diag(OpLoc, diag::err_ext_vector_component_name_illegal)
- << llvm::StringRef(compStr, 1) << SourceRange(CompLoc);
+ << StringRef(compStr, 1) << SourceRange(CompLoc);
return QualType();
}
@@ -337,10 +337,14 @@ CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK,
QualType VT = S.Context.getExtVectorType(vecType->getElementType(), CompSize);
// Now look up the TypeDefDecl from the vector type. Without this,
// diagostics look bad. We want extended vector types to appear built-in.
- for (unsigned i = 0, E = S.ExtVectorDecls.size(); i != E; ++i) {
- if (S.ExtVectorDecls[i]->getUnderlyingType() == VT)
- return S.Context.getTypedefType(S.ExtVectorDecls[i]);
+ for (Sema::ExtVectorDeclsType::iterator
+ I = S.ExtVectorDecls.begin(S.ExternalSource),
+ E = S.ExtVectorDecls.end();
+ I != E; ++I) {
+ if ((*I)->getUnderlyingType() == VT)
+ return S.Context.getTypedefType(*I);
}
+
return VT; // should never get here (a typedef type should always be found).
}
@@ -949,9 +953,9 @@ static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) {
QualType redef;
if (ty->isObjCId()) {
- redef = S.Context.ObjCIdRedefinitionType;
+ redef = S.Context.getObjCIdRedefinitionType();
} else if (ty->isObjCClass()) {
- redef = S.Context.ObjCClassRedefinitionType;
+ redef = S.Context.getObjCClassRedefinitionType();
} else {
return false;
}
@@ -966,6 +970,15 @@ static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) {
return true;
}
+static bool isRecordType(QualType T) {
+ return T->isRecordType();
+}
+static bool isPointerToRecordType(QualType T) {
+ if (const PointerType *PT = T->getAs<PointerType>())
+ return PT->getPointeeType()->isRecordType();
+ return false;
+}
+
/// Look up the given member of the given non-type-dependent
/// expression. This can return in one of two ways:
/// * If it returns a sentinel null-but-valid result, the caller will
@@ -985,6 +998,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
// Perform default conversions.
BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
+ if (BaseExpr.isInvalid())
+ return ExprError();
if (IsArrow) {
BaseExpr = DefaultLvalueConversion(BaseExpr.take());
@@ -1041,6 +1056,13 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
// Handle ivar access to Objective-C objects.
if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>()) {
+ if (!SS.isEmpty() && !SS.isInvalid()) {
+ Diag(SS.getRange().getBegin(), diag::err_qualified_objc_access)
+ << 1 << SS.getScopeRep()
+ << FixItHint::CreateRemoval(SS.getRange());
+ SS.clear();
+ }
+
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
// There are three cases for the base type:
@@ -1159,6 +1181,13 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
// Objective-C property access.
const ObjCObjectPointerType *OPT;
if (!IsArrow && (OPT = BaseType->getAs<ObjCObjectPointerType>())) {
+ if (!SS.isEmpty() && !SS.isInvalid()) {
+ Diag(SS.getRange().getBegin(), diag::err_qualified_objc_access)
+ << 0 << SS.getScopeRep()
+ << FixItHint::CreateRemoval(SS.getRange());
+ SS.clear();
+ }
+
// This actually uses the base as an r-value.
BaseExpr = DefaultLvalueConversion(BaseExpr.take());
if (BaseExpr.isInvalid())
@@ -1318,8 +1347,9 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
// not just a pointer to builtin-sel again.
if (IsArrow &&
BaseType->isSpecificBuiltinType(BuiltinType::ObjCSel) &&
- !Context.ObjCSelRedefinitionType->isObjCSelType()) {
- BaseExpr = ImpCastExprToType(BaseExpr.take(), Context.ObjCSelRedefinitionType,
+ !Context.getObjCSelRedefinitionType()->isObjCSelType()) {
+ BaseExpr = ImpCastExprToType(BaseExpr.take(),
+ Context.getObjCSelRedefinitionType(),
CK_BitCast);
return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl, HasTemplateArgs);
@@ -1351,50 +1381,15 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
// If the user is trying to apply -> or . to a function name, it's probably
// because they forgot parentheses to call that function.
- QualType ZeroArgCallTy;
- UnresolvedSet<4> Overloads;
- if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) {
- if (ZeroArgCallTy.isNull()) {
- Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
- << (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange();
- UnresolvedSet<2> PlausibleOverloads;
- for (OverloadExpr::decls_iterator It = Overloads.begin(),
- DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
- const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It);
- QualType OverloadResultTy = OverloadDecl->getResultType();
- if ((!IsArrow && OverloadResultTy->isRecordType()) ||
- (IsArrow && OverloadResultTy->isPointerType() &&
- OverloadResultTy->getPointeeType()->isRecordType()))
- PlausibleOverloads.addDecl(It.getDecl());
- }
- NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc());
+ if (tryToRecoverWithCall(BaseExpr,
+ PDiag(diag::err_member_reference_needs_call),
+ /*complain*/ false,
+ IsArrow ? &isRecordType : &isPointerToRecordType)) {
+ if (BaseExpr.isInvalid())
return ExprError();
- }
- if ((!IsArrow && ZeroArgCallTy->isRecordType()) ||
- (IsArrow && ZeroArgCallTy->isPointerType() &&
- ZeroArgCallTy->getPointeeType()->isRecordType())) {
- // At this point, we know BaseExpr looks like it's potentially callable
- // with 0 arguments, and that it returns something of a reasonable type,
- // so we can emit a fixit and carry on pretending that BaseExpr was
- // actually a CallExpr.
- SourceLocation ParenInsertionLoc =
- PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd());
- Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
- << (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
- // FIXME: Try this before emitting the fixit, and suppress diagnostics
- // while doing so.
- ExprResult NewBase =
- ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc,
- MultiExprArg(*this, 0, 0),
- ParenInsertionLoc.getFileLocWithOffset(1));
- if (NewBase.isInvalid())
- return ExprError();
- BaseExpr = NewBase;
- BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- }
+ BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
}
Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
@@ -1427,7 +1422,7 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
return ExprError();
// Warn about the explicit constructor calls Microsoft extension.
- if (getLangOptions().Microsoft &&
+ if (getLangOptions().MicrosoftExt &&
Id.getKind() == UnqualifiedId::IK_ConstructorName)
Diag(Id.getSourceRange().getBegin(),
diag::ext_ms_explicit_constructor_call);
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 02a4682cc840..20098b21366d 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -16,6 +16,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Initialization.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprObjC.h"
@@ -26,6 +27,7 @@
using namespace clang;
using namespace sema;
+using llvm::makeArrayRef;
ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
Expr **strings,
@@ -42,13 +44,13 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
if (NumStrings != 1) {
// Concatenate objc strings.
llvm::SmallString<128> StrBuf;
- llvm::SmallVector<SourceLocation, 8> StrLocs;
+ SmallVector<SourceLocation, 8> StrLocs;
for (unsigned i = 0; i != NumStrings; ++i) {
S = Strings[i];
- // ObjC strings can't be wide.
- if (S->isWide()) {
+ // ObjC strings can't be wide or UTF.
+ if (!S->isAscii()) {
Diag(S->getLocStart(), diag::err_cfstring_literal_not_string_constant)
<< S->getSourceRange();
return true;
@@ -64,7 +66,7 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
// Create the aggregate string with the appropriate content and location
// information.
S = StringLiteral::Create(Context, StrBuf,
- /*Wide=*/false, /*Pascal=*/false,
+ StringLiteral::Ascii, /*Pascal=*/false,
Context.getPointerType(Context.CharTy),
&StrLocs[0], StrLocs.size());
}
@@ -203,6 +205,7 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
case OMF_None:
case OMF_alloc:
case OMF_copy:
+ case OMF_finalize:
case OMF_init:
case OMF_mutableCopy:
case OMF_new:
@@ -270,6 +273,13 @@ ObjCMethodDecl *Sema::tryCaptureObjCSelf() {
return method;
}
+static QualType stripObjCInstanceType(ASTContext &Context, QualType T) {
+ if (T == Context.getObjCInstanceType())
+ return Context.getObjCIdType();
+
+ return T;
+}
+
QualType Sema::getMessageSendResultType(QualType ReceiverType,
ObjCMethodDecl *Method,
bool isClassMessage, bool isSuperMessage) {
@@ -282,7 +292,7 @@ QualType Sema::getMessageSendResultType(QualType ReceiverType,
// was a class message send, T is the declared return type of the method
// found
if (Method->isInstanceMethod() && isClassMessage)
- return Method->getSendResultType();
+ return stripObjCInstanceType(Context, Method->getSendResultType());
// - if the receiver is super, T is a pointer to the class of the
// enclosing method definition
@@ -301,7 +311,7 @@ QualType Sema::getMessageSendResultType(QualType ReceiverType,
// T is the declared return type of the method.
if (ReceiverType->isObjCClassType() ||
ReceiverType->isObjCQualifiedClassType())
- return Method->getSendResultType();
+ return stripObjCInstanceType(Context, Method->getSendResultType());
// - if the receiver is id, qualified id, Class, or qualified Class, T
// is the receiver type, otherwise
@@ -327,6 +337,10 @@ void Sema::EmitRelatedResultTypeNote(const Expr *E) {
MsgSend->getType()))
return;
+ if (!Context.hasSameUnqualifiedType(Method->getResultType(),
+ Context.getObjCInstanceType()))
+ return;
+
Diag(Method->getLocation(), diag::note_related_result_type_inferred)
<< Method->isInstanceMethod() << Method->getSelector()
<< MsgSend->getType();
@@ -356,8 +370,9 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
else
DiagID = isClassMessage ? diag::warn_class_method_not_found
: diag::warn_inst_method_not_found;
- Diag(lbrac, DiagID)
- << Sel << isClassMessage << SourceRange(lbrac, rbrac);
+ if (!getLangOptions().DebuggerSupport)
+ Diag(lbrac, DiagID)
+ << Sel << isClassMessage << SourceRange(lbrac, rbrac);
// In debuggers, we want to use __unknown_anytype for these
// results so that clients can cast them.
@@ -947,7 +962,7 @@ ExprResult Sema::ActOnSuperMessage(Scope *S,
SourceLocation SuperLoc,
Selector Sel,
SourceLocation LBracLoc,
- SourceLocation SelectorLoc,
+ ArrayRef<SourceLocation> SelectorLocs,
SourceLocation RBracLoc,
MultiExprArg Args) {
// Determine whether we are inside a method or not.
@@ -975,13 +990,18 @@ ExprResult Sema::ActOnSuperMessage(Scope *S,
// We are in a method whose class has a superclass, so 'super'
// is acting as a keyword.
if (Method->isInstanceMethod()) {
+ if (Sel.getMethodFamily() == OMF_dealloc)
+ ObjCShouldCallSuperDealloc = false;
+ if (Sel.getMethodFamily() == OMF_finalize)
+ ObjCShouldCallSuperFinalize = false;
+
// Since we are in an instance method, this is an instance
// message to the superclass instance.
QualType SuperTy = Context.getObjCInterfaceType(Super);
SuperTy = Context.getObjCObjectPointerType(SuperTy);
return BuildInstanceMessage(0, SuperTy, SuperLoc,
Sel, /*Method=*/0,
- LBracLoc, SelectorLoc, RBracLoc, move(Args));
+ LBracLoc, SelectorLocs, RBracLoc, move(Args));
}
// Since we are in a class method, this is a class message to
@@ -989,7 +1009,7 @@ ExprResult Sema::ActOnSuperMessage(Scope *S,
return BuildClassMessage(/*ReceiverTypeInfo=*/0,
Context.getObjCInterfaceType(Super),
SuperLoc, Sel, /*Method=*/0,
- LBracLoc, SelectorLoc, RBracLoc, move(Args));
+ LBracLoc, SelectorLocs, RBracLoc, move(Args));
}
/// \brief Build an Objective-C class message expression.
@@ -1026,7 +1046,7 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
Selector Sel,
ObjCMethodDecl *Method,
SourceLocation LBracLoc,
- SourceLocation SelectorLoc,
+ ArrayRef<SourceLocation> SelectorLocs,
SourceLocation RBracLoc,
MultiExprArg ArgsIn) {
SourceLocation Loc = SuperLoc.isValid()? SuperLoc
@@ -1045,8 +1065,8 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
assert(SuperLoc.isInvalid() && "Message to super with dependent type");
return Owned(ObjCMessageExpr::Create(Context, ReceiverType,
VK_RValue, LBracLoc, ReceiverTypeInfo,
- Sel, SelectorLoc, /*Method=*/0,
- Args, NumArgs, RBracLoc));
+ Sel, SelectorLocs, /*Method=*/0,
+ makeArrayRef(Args, NumArgs),RBracLoc));
}
// Find the class to which we are sending this message.
@@ -1107,12 +1127,14 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
if (SuperLoc.isValid())
Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
SuperLoc, /*IsInstanceSuper=*/false,
- ReceiverType, Sel, SelectorLoc,
- Method, Args, NumArgs, RBracLoc);
+ ReceiverType, Sel, SelectorLocs,
+ Method, makeArrayRef(Args, NumArgs),
+ RBracLoc);
else
Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
- ReceiverTypeInfo, Sel, SelectorLoc,
- Method, Args, NumArgs, RBracLoc);
+ ReceiverTypeInfo, Sel, SelectorLocs,
+ Method, makeArrayRef(Args, NumArgs),
+ RBracLoc);
return MaybeBindToTemporary(Result);
}
@@ -1123,7 +1145,7 @@ ExprResult Sema::ActOnClassMessage(Scope *S,
ParsedType Receiver,
Selector Sel,
SourceLocation LBracLoc,
- SourceLocation SelectorLoc,
+ ArrayRef<SourceLocation> SelectorLocs,
SourceLocation RBracLoc,
MultiExprArg Args) {
TypeSourceInfo *ReceiverTypeInfo;
@@ -1137,7 +1159,7 @@ ExprResult Sema::ActOnClassMessage(Scope *S,
return BuildClassMessage(ReceiverTypeInfo, ReceiverType,
/*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0,
- LBracLoc, SelectorLoc, RBracLoc, move(Args));
+ LBracLoc, SelectorLocs, RBracLoc, move(Args));
}
/// \brief Build an Objective-C instance message expression.
@@ -1174,7 +1196,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
Selector Sel,
ObjCMethodDecl *Method,
SourceLocation LBracLoc,
- SourceLocation SelectorLoc,
+ ArrayRef<SourceLocation> SelectorLocs,
SourceLocation RBracLoc,
MultiExprArg ArgsIn) {
// The location of the receiver.
@@ -1197,8 +1219,9 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
assert(SuperLoc.isInvalid() && "Message to super with dependent type");
return Owned(ObjCMessageExpr::Create(Context, Context.DependentTy,
VK_RValue, LBracLoc, Receiver, Sel,
- SelectorLoc, /*Method=*/0,
- Args, NumArgs, RBracLoc));
+ SelectorLocs, /*Method=*/0,
+ makeArrayRef(Args, NumArgs),
+ RBracLoc));
}
// If necessary, apply function/array conversion to the receiver.
@@ -1346,7 +1369,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
<< Receiver->getSourceRange();
if (ReceiverType->isPointerType())
Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
- CK_BitCast).take();
+ CK_CPointerToObjCPointerCast).take();
else {
// TODO: specialized warning on null receivers?
bool IsNull = Receiver->isNullPointerConstant(Context,
@@ -1355,24 +1378,19 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
IsNull ? CK_NullToPointer : CK_IntegralToPointer).take();
}
ReceiverType = Receiver->getType();
- }
- else {
+ } else {
ExprResult ReceiverRes;
if (getLangOptions().CPlusPlus)
- ReceiverRes = PerformContextuallyConvertToObjCId(Receiver);
+ ReceiverRes = PerformContextuallyConvertToObjCPointer(Receiver);
if (ReceiverRes.isUsable()) {
Receiver = ReceiverRes.take();
- if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Receiver)) {
- Receiver = ICE->getSubExpr();
- ReceiverType = Receiver->getType();
- }
return BuildInstanceMessage(Receiver,
ReceiverType,
SuperLoc,
Sel,
Method,
LBracLoc,
- SelectorLoc,
+ SelectorLocs,
RBracLoc,
move(ArgsIn));
} else {
@@ -1402,6 +1420,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
diag::err_illegal_message_expr_incomplete_type))
return ExprError();
+ SourceLocation SelLoc = SelectorLocs.front();
+
// In ARC, forbid the user from sending messages to
// retain/release/autorelease/dealloc/retainCount explicitly.
if (getLangOptions().ObjCAutoRefCount) {
@@ -1415,6 +1435,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
case OMF_None:
case OMF_alloc:
case OMF_copy:
+ case OMF_finalize:
case OMF_mutableCopy:
case OMF_new:
case OMF_self:
@@ -1426,7 +1447,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
case OMF_autorelease:
case OMF_retainCount:
Diag(Loc, diag::err_arc_illegal_explicit_message)
- << Sel << SelectorLoc;
+ << Sel << SelLoc;
break;
case OMF_performSelector:
@@ -1452,7 +1473,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// Issue error, unless ns_returns_not_retained.
if (!SelMethod->hasAttr<NSReturnsNotRetainedAttr>()) {
// selector names a +1 method
- Diag(SelectorLoc,
+ Diag(SelLoc,
diag::err_arc_perform_selector_retains);
Diag(SelMethod->getLocation(), diag::note_method_declared_at);
}
@@ -1461,7 +1482,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// +0 call. OK. unless ns_returns_retained.
if (SelMethod->hasAttr<NSReturnsRetainedAttr>()) {
// selector names a +1 method
- Diag(SelectorLoc,
+ Diag(SelLoc,
diag::err_arc_perform_selector_retains);
Diag(SelMethod->getLocation(), diag::note_method_declared_at);
}
@@ -1470,7 +1491,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
} else {
// error (may leak).
- Diag(SelectorLoc, diag::warn_arc_perform_selector_leaks);
+ Diag(SelLoc, diag::warn_arc_perform_selector_leaks);
Diag(Args[0]->getExprLoc(), diag::note_used_here);
}
}
@@ -1483,12 +1504,12 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
if (SuperLoc.isValid())
Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
SuperLoc, /*IsInstanceSuper=*/true,
- ReceiverType, Sel, SelectorLoc, Method,
- Args, NumArgs, RBracLoc);
+ ReceiverType, Sel, SelectorLocs, Method,
+ makeArrayRef(Args, NumArgs), RBracLoc);
else
Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
- Receiver, Sel, SelectorLoc, Method,
- Args, NumArgs, RBracLoc);
+ Receiver, Sel, SelectorLocs, Method,
+ makeArrayRef(Args, NumArgs), RBracLoc);
if (getLangOptions().ObjCAutoRefCount) {
// In ARC, annotate delegate init calls.
@@ -1520,7 +1541,7 @@ ExprResult Sema::ActOnInstanceMessage(Scope *S,
Expr *Receiver,
Selector Sel,
SourceLocation LBracLoc,
- SourceLocation SelectorLoc,
+ ArrayRef<SourceLocation> SelectorLocs,
SourceLocation RBracLoc,
MultiExprArg Args) {
if (!Receiver)
@@ -1528,206 +1549,360 @@ ExprResult Sema::ActOnInstanceMessage(Scope *S,
return BuildInstanceMessage(Receiver, Receiver->getType(),
/*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0,
- LBracLoc, SelectorLoc, RBracLoc, move(Args));
+ LBracLoc, SelectorLocs, RBracLoc, move(Args));
}
enum ARCConversionTypeClass {
+ /// int, void, struct A
ACTC_none,
+
+ /// id, void (^)()
ACTC_retainable,
- ACTC_indirectRetainable
+
+ /// id*, id***, void (^*)(),
+ ACTC_indirectRetainable,
+
+ /// void* might be a normal C type, or it might a CF type.
+ ACTC_voidPtr,
+
+ /// struct A*
+ ACTC_coreFoundation
};
+static bool isAnyRetainable(ARCConversionTypeClass ACTC) {
+ return (ACTC == ACTC_retainable ||
+ ACTC == ACTC_coreFoundation ||
+ ACTC == ACTC_voidPtr);
+}
+static bool isAnyCLike(ARCConversionTypeClass ACTC) {
+ return ACTC == ACTC_none ||
+ ACTC == ACTC_voidPtr ||
+ ACTC == ACTC_coreFoundation;
+}
+
static ARCConversionTypeClass classifyTypeForARCConversion(QualType type) {
- ARCConversionTypeClass ACTC = ACTC_retainable;
+ bool isIndirect = false;
// Ignore an outermost reference type.
- if (const ReferenceType *ref = type->getAs<ReferenceType>())
+ if (const ReferenceType *ref = type->getAs<ReferenceType>()) {
type = ref->getPointeeType();
+ isIndirect = true;
+ }
// Drill through pointers and arrays recursively.
while (true) {
if (const PointerType *ptr = type->getAs<PointerType>()) {
type = ptr->getPointeeType();
+
+ // The first level of pointer may be the innermost pointer on a CF type.
+ if (!isIndirect) {
+ if (type->isVoidType()) return ACTC_voidPtr;
+ if (type->isRecordType()) return ACTC_coreFoundation;
+ }
} else if (const ArrayType *array = type->getAsArrayTypeUnsafe()) {
type = QualType(array->getElementType()->getBaseElementTypeUnsafe(), 0);
} else {
break;
}
- ACTC = ACTC_indirectRetainable;
+ isIndirect = true;
}
- if (!type->isObjCRetainableType()) return ACTC_none;
- return ACTC;
+ if (isIndirect) {
+ if (type->isObjCARCBridgableType())
+ return ACTC_indirectRetainable;
+ return ACTC_none;
+ }
+
+ if (type->isObjCARCBridgableType())
+ return ACTC_retainable;
+
+ return ACTC_none;
}
namespace {
- /// Return true if the given expression can be reasonably converted
- /// between a retainable pointer type and a C pointer type.
- struct ARCCastChecker : StmtVisitor<ARCCastChecker, bool> {
+ /// A result from the cast checker.
+ enum ACCResult {
+ /// Cannot be casted.
+ ACC_invalid,
+
+ /// Can be safely retained or not retained.
+ ACC_bottom,
+
+ /// Can be casted at +0.
+ ACC_plusZero,
+
+ /// Can be casted at +1.
+ ACC_plusOne
+ };
+ ACCResult merge(ACCResult left, ACCResult right) {
+ if (left == right) return left;
+ if (left == ACC_bottom) return right;
+ if (right == ACC_bottom) return left;
+ return ACC_invalid;
+ }
+
+ /// A checker which white-lists certain expressions whose conversion
+ /// to or from retainable type would otherwise be forbidden in ARC.
+ class ARCCastChecker : public StmtVisitor<ARCCastChecker, ACCResult> {
+ typedef StmtVisitor<ARCCastChecker, ACCResult> super;
+
ASTContext &Context;
- ARCCastChecker(ASTContext &Context) : Context(Context) {}
- bool VisitStmt(Stmt *s) {
- return false;
+ ARCConversionTypeClass SourceClass;
+ ARCConversionTypeClass TargetClass;
+
+ static bool isCFType(QualType type) {
+ // Someday this can use ns_bridged. For now, it has to do this.
+ return type->isCARCBridgableType();
}
- bool VisitExpr(Expr *e) {
- return e->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull);
+
+ public:
+ ARCCastChecker(ASTContext &Context, ARCConversionTypeClass source,
+ ARCConversionTypeClass target)
+ : Context(Context), SourceClass(source), TargetClass(target) {}
+
+ using super::Visit;
+ ACCResult Visit(Expr *e) {
+ return super::Visit(e->IgnoreParens());
}
-
- bool VisitParenExpr(ParenExpr *e) {
- return Visit(e->getSubExpr());
+
+ ACCResult VisitStmt(Stmt *s) {
+ return ACC_invalid;
+ }
+
+ /// Null pointer constants can be casted however you please.
+ ACCResult VisitExpr(Expr *e) {
+ if (e->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
+ return ACC_bottom;
+ return ACC_invalid;
}
- bool VisitCastExpr(CastExpr *e) {
+
+ /// Objective-C string literals can be safely casted.
+ ACCResult VisitObjCStringLiteral(ObjCStringLiteral *e) {
+ // If we're casting to any retainable type, go ahead. Global
+ // strings are immune to retains, so this is bottom.
+ if (isAnyRetainable(TargetClass)) return ACC_bottom;
+
+ return ACC_invalid;
+ }
+
+ /// Look through certain implicit and explicit casts.
+ ACCResult VisitCastExpr(CastExpr *e) {
switch (e->getCastKind()) {
case CK_NullToPointer:
- return true;
+ return ACC_bottom;
+
case CK_NoOp:
case CK_LValueToRValue:
case CK_BitCast:
- case CK_AnyPointerToObjCPointerCast:
+ case CK_GetObjCProperty:
+ case CK_CPointerToObjCPointerCast:
+ case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
return Visit(e->getSubExpr());
+
default:
- return false;
+ return ACC_invalid;
}
}
- bool VisitUnaryExtension(UnaryOperator *e) {
+
+ /// Look through unary extension.
+ ACCResult VisitUnaryExtension(UnaryOperator *e) {
return Visit(e->getSubExpr());
}
- bool VisitBinComma(BinaryOperator *e) {
+
+ /// Ignore the LHS of a comma operator.
+ ACCResult VisitBinComma(BinaryOperator *e) {
return Visit(e->getRHS());
}
- bool VisitConditionalOperator(ConditionalOperator *e) {
- // Conditional operators are okay if both sides are okay.
- return Visit(e->getTrueExpr()) && Visit(e->getFalseExpr());
- }
- bool VisitObjCStringLiteral(ObjCStringLiteral *e) {
- // Always white-list Objective-C string literals.
- return true;
+
+ /// Conditional operators are okay if both sides are okay.
+ ACCResult VisitConditionalOperator(ConditionalOperator *e) {
+ ACCResult left = Visit(e->getTrueExpr());
+ if (left == ACC_invalid) return ACC_invalid;
+ return merge(left, Visit(e->getFalseExpr()));
}
- bool VisitStmtExpr(StmtExpr *e) {
+
+ /// Statement expressions are okay if their result expression is okay.
+ ACCResult VisitStmtExpr(StmtExpr *e) {
return Visit(e->getSubStmt()->body_back());
}
- bool VisitDeclRefExpr(DeclRefExpr *e) {
- // White-list references to global extern strings from system
- // headers.
- if (VarDecl *var = dyn_cast<VarDecl>(e->getDecl()))
- if (var->getStorageClass() == SC_Extern &&
- var->getType().isConstQualified() &&
- Context.getSourceManager().isInSystemHeader(var->getLocation()))
- return true;
- return false;
+
+ /// Some declaration references are okay.
+ ACCResult VisitDeclRefExpr(DeclRefExpr *e) {
+ // References to global constants from system headers are okay.
+ // These are things like 'kCFStringTransformToLatin'. They are
+ // can also be assumed to be immune to retains.
+ VarDecl *var = dyn_cast<VarDecl>(e->getDecl());
+ if (isAnyRetainable(TargetClass) &&
+ isAnyRetainable(SourceClass) &&
+ var &&
+ var->getStorageClass() == SC_Extern &&
+ var->getType().isConstQualified() &&
+ Context.getSourceManager().isInSystemHeader(var->getLocation())) {
+ return ACC_bottom;
+ }
+
+ // Nothing else.
+ return ACC_invalid;
}
- };
-}
-bool
-Sema::ValidObjCARCNoBridgeCastExpr(Expr *&Exp, QualType castType) {
- Expr *NewExp = Exp->IgnoreParenCasts();
-
- if (!isa<ObjCMessageExpr>(NewExp) && !isa<ObjCPropertyRefExpr>(NewExp)
- && !isa<CallExpr>(NewExp))
- return false;
- ObjCMethodDecl *method = 0;
- bool MethodReturnsPlusOne = false;
-
- if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(NewExp)) {
- method = PRE->getExplicitProperty()->getGetterMethodDecl();
- }
- else if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(NewExp))
- method = ME->getMethodDecl();
- else {
- CallExpr *CE = cast<CallExpr>(NewExp);
- Decl *CallDecl = CE->getCalleeDecl();
- if (!CallDecl)
- return false;
- if (CallDecl->hasAttr<CFReturnsNotRetainedAttr>())
- return true;
- MethodReturnsPlusOne = CallDecl->hasAttr<CFReturnsRetainedAttr>();
- if (!MethodReturnsPlusOne) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>(CallDecl))
- if (const IdentifierInfo *Id = ND->getIdentifier())
- if (Id->isStr("__builtin___CFStringMakeConstantString"))
- return true;
+ /// Some calls are okay.
+ ACCResult VisitCallExpr(CallExpr *e) {
+ if (FunctionDecl *fn = e->getDirectCallee())
+ if (ACCResult result = checkCallToFunction(fn))
+ return result;
+
+ return super::VisitCallExpr(e);
}
- }
-
- if (!MethodReturnsPlusOne) {
- if (!method)
- return false;
- if (method->hasAttr<CFReturnsNotRetainedAttr>())
- return true;
- MethodReturnsPlusOne = method->hasAttr<CFReturnsRetainedAttr>();
- if (!MethodReturnsPlusOne) {
- ObjCMethodFamily family = method->getSelector().getMethodFamily();
- switch (family) {
- case OMF_alloc:
- case OMF_copy:
- case OMF_mutableCopy:
- case OMF_new:
- MethodReturnsPlusOne = true;
- break;
- default:
- break;
+
+ ACCResult checkCallToFunction(FunctionDecl *fn) {
+ // Require a CF*Ref return type.
+ if (!isCFType(fn->getResultType()))
+ return ACC_invalid;
+
+ if (!isAnyRetainable(TargetClass))
+ return ACC_invalid;
+
+ // Honor an explicit 'not retained' attribute.
+ if (fn->hasAttr<CFReturnsNotRetainedAttr>())
+ return ACC_plusZero;
+
+ // Honor an explicit 'retained' attribute, except that for
+ // now we're not going to permit implicit handling of +1 results,
+ // because it's a bit frightening.
+ if (fn->hasAttr<CFReturnsRetainedAttr>())
+ return ACC_invalid; // ACC_plusOne if we start accepting this
+
+ // Recognize this specific builtin function, which is used by CFSTR.
+ unsigned builtinID = fn->getBuiltinID();
+ if (builtinID == Builtin::BI__builtin___CFStringMakeConstantString)
+ return ACC_bottom;
+
+ // Otherwise, don't do anything implicit with an unaudited function.
+ if (!fn->hasAttr<CFAuditedTransferAttr>())
+ return ACC_invalid;
+
+ // Otherwise, it's +0 unless it follows the create convention.
+ if (ento::coreFoundation::followsCreateRule(fn))
+ return ACC_invalid; // ACC_plusOne if we start accepting this
+
+ return ACC_plusZero;
+ }
+
+ ACCResult VisitObjCMessageExpr(ObjCMessageExpr *e) {
+ return checkCallToMethod(e->getMethodDecl());
+ }
+
+ ACCResult VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *e) {
+ ObjCMethodDecl *method;
+ if (e->isExplicitProperty())
+ method = e->getExplicitProperty()->getGetterMethodDecl();
+ else
+ method = e->getImplicitPropertyGetter();
+ return checkCallToMethod(method);
+ }
+
+ ACCResult checkCallToMethod(ObjCMethodDecl *method) {
+ if (!method) return ACC_invalid;
+
+ // Check for message sends to functions returning CF types. We
+ // just obey the Cocoa conventions with these, even though the
+ // return type is CF.
+ if (!isAnyRetainable(TargetClass) || !isCFType(method->getResultType()))
+ return ACC_invalid;
+
+ // If the method is explicitly marked not-retained, it's +0.
+ if (method->hasAttr<CFReturnsNotRetainedAttr>())
+ return ACC_plusZero;
+
+ // If the method is explicitly marked as returning retained, or its
+ // selector follows a +1 Cocoa convention, treat it as +1.
+ if (method->hasAttr<CFReturnsRetainedAttr>())
+ return ACC_plusOne;
+
+ switch (method->getSelector().getMethodFamily()) {
+ case OMF_alloc:
+ case OMF_copy:
+ case OMF_mutableCopy:
+ case OMF_new:
+ return ACC_plusOne;
+
+ default:
+ // Otherwise, treat it as +0.
+ return ACC_plusZero;
}
}
- }
-
- if (MethodReturnsPlusOne) {
- TypeSourceInfo *TSInfo =
- Context.getTrivialTypeSourceInfo(castType, SourceLocation());
- ExprResult ExpRes = BuildObjCBridgedCast(SourceLocation(), OBC_BridgeTransfer,
- SourceLocation(), TSInfo, Exp);
- Exp = ExpRes.take();
- }
- return true;
+ };
}
void
Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
Expr *&castExpr, CheckedConversionKind CCK) {
QualType castExprType = castExpr->getType();
+
+ // For the purposes of the classification, we assume reference types
+ // will bind to temporaries.
+ QualType effCastType = castType;
+ if (const ReferenceType *ref = castType->getAs<ReferenceType>())
+ effCastType = ref->getPointeeType();
ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExprType);
- ARCConversionTypeClass castACTC = classifyTypeForARCConversion(castType);
+ ARCConversionTypeClass castACTC = classifyTypeForARCConversion(effCastType);
if (exprACTC == castACTC) return;
- if (exprACTC && castType->isIntegralType(Context)) return;
+ if (isAnyCLike(exprACTC) && isAnyCLike(castACTC)) return;
+
+ // Allow all of these types to be cast to integer types (but not
+ // vice-versa).
+ if (castACTC == ACTC_none && castType->isIntegralType(Context))
+ return;
// Allow casts between pointers to lifetime types (e.g., __strong id*)
// and pointers to void (e.g., cv void *). Casting from void* to lifetime*
// must be explicit.
- if (const PointerType *CastPtr = castType->getAs<PointerType>()) {
- if (const PointerType *CastExprPtr = castExprType->getAs<PointerType>()) {
- QualType CastPointee = CastPtr->getPointeeType();
- QualType CastExprPointee = CastExprPtr->getPointeeType();
- if ((CCK != CCK_ImplicitConversion &&
- CastPointee->isObjCIndirectLifetimeType() &&
- CastExprPointee->isVoidType()) ||
- (CastPointee->isVoidType() &&
- CastExprPointee->isObjCIndirectLifetimeType()))
- return;
- }
- }
-
- if (ARCCastChecker(Context).Visit(castExpr))
+ if (exprACTC == ACTC_indirectRetainable && castACTC == ACTC_voidPtr)
+ return;
+ if (castACTC == ACTC_indirectRetainable && exprACTC == ACTC_voidPtr &&
+ CCK != CCK_ImplicitConversion)
return;
+
+ switch (ARCCastChecker(Context, exprACTC, castACTC).Visit(castExpr)) {
+ // For invalid casts, fall through.
+ case ACC_invalid:
+ break;
+
+ // Do nothing for both bottom and +0.
+ case ACC_bottom:
+ case ACC_plusZero:
+ return;
+
+ // If the result is +1, consume it here.
+ case ACC_plusOne:
+ castExpr = ImplicitCastExpr::Create(Context, castExpr->getType(),
+ CK_ARCConsumeObject, castExpr,
+ 0, VK_RValue);
+ ExprNeedsCleanups = true;
+ return;
+ }
SourceLocation loc =
- (castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc());
+ (castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc());
if (makeUnavailableInSystemHeader(loc,
- "converts between Objective-C and C pointers in -fobjc-arc"))
+ "converts between Objective-C and C pointers in -fobjc-arc"))
return;
unsigned srcKind = 0;
switch (exprACTC) {
- case ACTC_none:
- srcKind = (castExprType->isPointerType() ? 1 : 0);
- break;
- case ACTC_retainable:
- srcKind = (castExprType->isBlockPointerType() ? 2 : 3);
- break;
- case ACTC_indirectRetainable:
- srcKind = 4;
- break;
+ case ACTC_none:
+ case ACTC_coreFoundation:
+ case ACTC_voidPtr:
+ srcKind = (castExprType->isPointerType() ? 1 : 0);
+ break;
+ case ACTC_retainable:
+ srcKind = (castExprType->isBlockPointerType() ? 2 : 3);
+ break;
+ case ACTC_indirectRetainable:
+ srcKind = 4;
+ break;
}
if (CCK == CCK_CStyleCast) {
@@ -1735,12 +1910,7 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
SourceLocation AfterLParen = PP.getLocForEndOfToken(castRange.getBegin());
SourceLocation NoteLoc = AfterLParen.isValid()? AfterLParen : loc;
- if (castType->isObjCARCBridgableType() &&
- castExprType->isCARCBridgableType()) {
- // explicit unbridged casts are allowed if the source of the cast is a
- // message sent to an objc method (or property access)
- if (ValidObjCARCNoBridgeCastExpr(castExpr, castType))
- return;
+ if (castACTC == ACTC_retainable && isAnyRetainable(exprACTC)) {
Diag(loc, diag::err_arc_cast_requires_bridge)
<< 2
<< castExprType
@@ -1757,8 +1927,7 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
return;
}
- if (castType->isCARCBridgableType() &&
- castExprType->isObjCARCBridgableType()){
+ if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC)) {
Diag(loc, diag::err_arc_cast_requires_bridge)
<< (castExprType->isBlockPointerType()? 1 : 0)
<< castExprType
@@ -1806,7 +1975,7 @@ static Expr *maybeUndoReclaimObject(Expr *e) {
// value-propagating subexpressions --- we can't reliably rebuild
// in-place because of expression sharing.
if (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e))
- if (ice->getCastKind() == CK_ObjCReclaimReturnedObject)
+ if (ice->getCastKind() == CK_ARCReclaimReturnedObject)
return ice->getSubExpr();
return e;
@@ -1817,14 +1986,23 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
SourceLocation BridgeKeywordLoc,
TypeSourceInfo *TSInfo,
Expr *SubExpr) {
+ ExprResult SubResult = UsualUnaryConversions(SubExpr);
+ if (SubResult.isInvalid()) return ExprError();
+ SubExpr = SubResult.take();
+
QualType T = TSInfo->getType();
QualType FromType = SubExpr->getType();
+ CastKind CK;
+
bool MustConsume = false;
if (T->isDependentType() || SubExpr->isTypeDependent()) {
// Okay: we'll build a dependent expression type.
+ CK = CK_Dependent;
} else if (T->isObjCARCBridgableType() && FromType->isCARCBridgableType()) {
// Casting CF -> id
+ CK = (T->isBlockPointerType() ? CK_AnyPointerToBlockPointerCast
+ : CK_CPointerToObjCPointerCast);
switch (Kind) {
case OBC_Bridge:
break;
@@ -1854,6 +2032,7 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
}
} else if (T->isCARCBridgableType() && FromType->isObjCARCBridgableType()) {
// Okay: id -> CF
+ CK = CK_BitCast;
switch (Kind) {
case OBC_Bridge:
// Reclaiming a value that's going to be __bridge-casted to CF
@@ -1864,7 +2043,7 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
case OBC_BridgeRetained:
// Produce the object before casting it.
SubExpr = ImplicitCastExpr::Create(Context, FromType,
- CK_ObjCProduceObject,
+ CK_ARCProduceObject,
SubExpr, 0, VK_RValue);
break;
@@ -1894,13 +2073,13 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
return ExprError();
}
- Expr *Result = new (Context) ObjCBridgedCastExpr(LParenLoc, Kind,
+ Expr *Result = new (Context) ObjCBridgedCastExpr(LParenLoc, Kind, CK,
BridgeKeywordLoc,
TSInfo, SubExpr);
if (MustConsume) {
ExprNeedsCleanups = true;
- Result = ImplicitCastExpr::Create(Context, T, CK_ObjCConsumeObject, Result,
+ Result = ImplicitCastExpr::Create(Context, T, CK_ARCConsumeObject, Result,
0, VK_RValue);
}
diff --git a/lib/Sema/SemaFixItUtils.cpp b/lib/Sema/SemaFixItUtils.cpp
new file mode 100644
index 000000000000..8e8a46da73e4
--- /dev/null
+++ b/lib/Sema/SemaFixItUtils.cpp
@@ -0,0 +1,160 @@
+//===--- SemaFixItUtils.cpp - Sema FixIts ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines helper classes for generation of Sema FixItHints.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaFixItUtils.h"
+
+using namespace clang;
+
+bool ConversionFixItGenerator::compareTypesSimple(CanQualType From,
+ CanQualType To,
+ Sema &S,
+ SourceLocation Loc,
+ ExprValueKind FromVK) {
+ if (!To.isAtLeastAsQualifiedAs(From))
+ return false;
+
+ From = From.getNonReferenceType();
+ To = To.getNonReferenceType();
+
+ // If both are pointer types, work with the pointee types.
+ if (isa<PointerType>(From) && isa<PointerType>(To)) {
+ From = S.Context.getCanonicalType(
+ (cast<PointerType>(From))->getPointeeType());
+ To = S.Context.getCanonicalType(
+ (cast<PointerType>(To))->getPointeeType());
+ }
+
+ const CanQualType FromUnq = From.getUnqualifiedType();
+ const CanQualType ToUnq = To.getUnqualifiedType();
+
+ if ((FromUnq == ToUnq || (S.IsDerivedFrom(FromUnq, ToUnq)) ) &&
+ To.isAtLeastAsQualifiedAs(From))
+ return true;
+ return false;
+}
+
+bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr,
+ const QualType FromTy,
+ const QualType ToTy,
+ Sema &S) {
+ if (!FullExpr)
+ return false;
+
+ const CanQualType FromQTy = S.Context.getCanonicalType(FromTy);
+ const CanQualType ToQTy = S.Context.getCanonicalType(ToTy);
+ const SourceLocation Begin = FullExpr->getSourceRange().getBegin();
+ const SourceLocation End = S.PP.getLocForEndOfToken(FullExpr->getSourceRange()
+ .getEnd());
+
+ // Strip the implicit casts - those are implied by the compiler, not the
+ // original source code.
+ const Expr* Expr = FullExpr->IgnoreImpCasts();
+
+ bool NeedParen = true;
+ if (isa<ArraySubscriptExpr>(Expr) ||
+ isa<CallExpr>(Expr) ||
+ isa<DeclRefExpr>(Expr) ||
+ isa<CastExpr>(Expr) ||
+ isa<CXXNewExpr>(Expr) ||
+ isa<CXXConstructExpr>(Expr) ||
+ isa<CXXDeleteExpr>(Expr) ||
+ isa<CXXNoexceptExpr>(Expr) ||
+ isa<CXXPseudoDestructorExpr>(Expr) ||
+ isa<CXXScalarValueInitExpr>(Expr) ||
+ isa<CXXThisExpr>(Expr) ||
+ isa<CXXTypeidExpr>(Expr) ||
+ isa<CXXUnresolvedConstructExpr>(Expr) ||
+ isa<ObjCMessageExpr>(Expr) ||
+ isa<ObjCPropertyRefExpr>(Expr) ||
+ isa<ObjCProtocolExpr>(Expr) ||
+ isa<MemberExpr>(Expr) ||
+ isa<ParenExpr>(FullExpr) ||
+ isa<ParenListExpr>(Expr) ||
+ isa<SizeOfPackExpr>(Expr) ||
+ isa<UnaryOperator>(Expr))
+ NeedParen = false;
+
+ // Check if the argument needs to be dereferenced:
+ // (type * -> type) or (type * -> type &).
+ if (const PointerType *FromPtrTy = dyn_cast<PointerType>(FromQTy)) {
+ OverloadFixItKind FixKind = OFIK_Dereference;
+
+ bool CanConvert = CompareTypes(
+ S.Context.getCanonicalType(FromPtrTy->getPointeeType()), ToQTy,
+ S, Begin, VK_LValue);
+ if (CanConvert) {
+ // Do not suggest dereferencing a Null pointer.
+ if (Expr->IgnoreParenCasts()->
+ isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull))
+ return false;
+
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) {
+ if (UO->getOpcode() == UO_AddrOf) {
+ FixKind = OFIK_RemoveTakeAddress;
+ Hints.push_back(FixItHint::CreateRemoval(
+ CharSourceRange::getTokenRange(Begin, Begin)));
+ }
+ } else if (NeedParen) {
+ Hints.push_back(FixItHint::CreateInsertion(Begin, "*("));
+ Hints.push_back(FixItHint::CreateInsertion(End, ")"));
+ } else {
+ Hints.push_back(FixItHint::CreateInsertion(Begin, "*"));
+ }
+
+ NumConversionsFixed++;
+ if (NumConversionsFixed == 1)
+ Kind = FixKind;
+ return true;
+ }
+ }
+
+ // Check if the pointer to the argument needs to be passed:
+ // (type -> type *) or (type & -> type *).
+ if (isa<PointerType>(ToQTy)) {
+ bool CanConvert = false;
+ OverloadFixItKind FixKind = OFIK_TakeAddress;
+
+ // Only suggest taking address of L-values.
+ if (!Expr->isLValue() || Expr->getObjectKind() != OK_Ordinary)
+ return false;
+
+ CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy,
+ S, Begin, VK_RValue);
+ if (CanConvert) {
+
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) {
+ if (UO->getOpcode() == UO_Deref) {
+ FixKind = OFIK_RemoveDereference;
+ Hints.push_back(FixItHint::CreateRemoval(
+ CharSourceRange::getTokenRange(Begin, Begin)));
+ }
+ } else if (NeedParen) {
+ Hints.push_back(FixItHint::CreateInsertion(Begin, "&("));
+ Hints.push_back(FixItHint::CreateInsertion(End, ")"));
+ } else {
+ Hints.push_back(FixItHint::CreateInsertion(Begin, "&"));
+ }
+
+ NumConversionsFixed++;
+ if (NumConversionsFixed == 1)
+ Kind = FixKind;
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 9fbcbab0b7d0..7ed3fa84c8d5 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -7,9 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements semantic analysis for initializers. The main entry
-// point is Sema::CheckInitList(), but all of the work is performed
-// within the InitListChecker class.
+// This file implements semantic analysis for initializers.
//
//===----------------------------------------------------------------------===//
@@ -24,6 +22,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/TypeLoc.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
#include <map>
using namespace clang;
@@ -48,20 +47,30 @@ static Expr *IsStringInit(Expr *Init, const ArrayType *AT,
if (SL == 0) return 0;
QualType ElemTy = Context.getCanonicalType(AT->getElementType());
- // char array can be initialized with a narrow string.
- // Only allow char x[] = "foo"; not char x[] = L"foo";
- if (!SL->isWide())
+
+ switch (SL->getKind()) {
+ case StringLiteral::Ascii:
+ case StringLiteral::UTF8:
+ // char array can be initialized with a narrow string.
+ // Only allow char x[] = "foo"; not char x[] = L"foo";
return ElemTy->isCharType() ? Init : 0;
+ case StringLiteral::UTF16:
+ return ElemTy->isChar16Type() ? Init : 0;
+ case StringLiteral::UTF32:
+ return ElemTy->isChar32Type() ? Init : 0;
+ case StringLiteral::Wide:
+ // wchar_t array can be initialized with a wide string: C99 6.7.8p15 (with
+ // correction from DR343): "An array with element type compatible with a
+ // qualified or unqualified version of wchar_t may be initialized by a wide
+ // string literal, optionally enclosed in braces."
+ if (Context.typesAreCompatible(Context.getWCharType(),
+ ElemTy.getUnqualifiedType()))
+ return Init;
- // wchar_t array can be initialized with a wide string: C99 6.7.8p15 (with
- // correction from DR343): "An array with element type compatible with a
- // qualified or unqualified version of wchar_t may be initialized by a wide
- // string literal, optionally enclosed in braces."
- if (Context.typesAreCompatible(Context.getWCharType(),
- ElemTy.getUnqualifiedType()))
- return Init;
+ return 0;
+ }
- return 0;
+ llvm_unreachable("missed a StringLiteral kind?");
}
static Expr *IsStringInit(Expr *init, QualType declType, ASTContext &Context) {
@@ -160,14 +169,14 @@ namespace {
class InitListChecker {
Sema &SemaRef;
bool hadError;
+ bool VerifyOnly; // no diagnostics, no structure building
std::map<InitListExpr *, InitListExpr *> SyntacticToSemantic;
InitListExpr *FullyStructuredList;
void CheckImplicitInitList(const InitializedEntity &Entity,
InitListExpr *ParentIList, QualType T,
unsigned &Index, InitListExpr *StructuredList,
- unsigned &StructuredIndex,
- bool TopLevelObject = false);
+ unsigned &StructuredIndex);
void CheckExplicitInitList(const InitializedEntity &Entity,
InitListExpr *IList, QualType &T,
unsigned &Index, InitListExpr *StructuredList,
@@ -185,6 +194,11 @@ class InitListChecker {
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
+ void CheckComplexType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType DeclType,
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex);
void CheckScalarType(const InitializedEntity &Entity,
InitListExpr *IList, QualType DeclType,
unsigned &Index,
@@ -239,9 +253,12 @@ class InitListChecker {
InitListExpr *ILE, bool &RequiresSecondPass);
void FillInValueInitializations(const InitializedEntity &Entity,
InitListExpr *ILE, bool &RequiresSecondPass);
+ bool CheckFlexibleArrayInit(const InitializedEntity &Entity,
+ Expr *InitExpr, FieldDecl *Field,
+ bool TopLevelObject);
public:
InitListChecker(Sema &S, const InitializedEntity &Entity,
- InitListExpr *IL, QualType &T);
+ InitListExpr *IL, QualType &T, bool VerifyOnly);
bool HadError() { return hadError; }
// @brief Retrieves the fully-structured initializer list used for
@@ -434,8 +451,9 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
- InitListExpr *IL, QualType &T)
- : SemaRef(S) {
+ InitListExpr *IL, QualType &T,
+ bool VerifyOnly)
+ : SemaRef(S), VerifyOnly(VerifyOnly) {
hadError = false;
unsigned newIndex = 0;
@@ -446,7 +464,7 @@ InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
FullyStructuredList, newStructuredIndex,
/*TopLevelObject=*/true);
- if (!hadError) {
+ if (!hadError && !VerifyOnly) {
bool RequiresSecondPass = false;
FillInValueInitializations(Entity, FullyStructuredList, RequiresSecondPass);
if (RequiresSecondPass && !hadError)
@@ -472,7 +490,7 @@ int InitListChecker::numStructUnionElements(QualType DeclType) {
Field = structDecl->field_begin(),
FieldEnd = structDecl->field_end();
Field != FieldEnd; ++Field) {
- if ((*Field)->getIdentifier() || !(*Field)->isBitField())
+ if (!Field->isUnnamedBitfield())
++InitializableMembers;
}
if (structDecl->isUnion())
@@ -484,8 +502,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
InitListExpr *ParentIList,
QualType T, unsigned &Index,
InitListExpr *StructuredList,
- unsigned &StructuredIndex,
- bool TopLevelObject) {
+ unsigned &StructuredIndex) {
int maxElements = 0;
if (T->isArrayType())
@@ -495,11 +512,12 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
else if (T->isVectorType())
maxElements = T->getAs<VectorType>()->getNumElements();
else
- assert(0 && "CheckImplicitInitList(): Illegal type");
+ llvm_unreachable("CheckImplicitInitList(): Illegal type");
if (maxElements == 0) {
- SemaRef.Diag(ParentIList->getInit(Index)->getLocStart(),
- diag::err_implicit_empty_initializer);
+ if (!VerifyOnly)
+ SemaRef.Diag(ParentIList->getInit(Index)->getLocStart(),
+ diag::err_implicit_empty_initializer);
++Index;
hadError = true;
return;
@@ -518,29 +536,31 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
CheckListElementTypes(Entity, ParentIList, T,
/*SubobjectIsDesignatorContext=*/false, Index,
StructuredSubobjectInitList,
- StructuredSubobjectInitIndex,
- TopLevelObject);
+ StructuredSubobjectInitIndex);
unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1);
- StructuredSubobjectInitList->setType(T);
-
- // Update the structured sub-object initializer so that it's ending
- // range corresponds with the end of the last initializer it used.
- if (EndIndex < ParentIList->getNumInits()) {
- SourceLocation EndLoc
- = ParentIList->getInit(EndIndex)->getSourceRange().getEnd();
- StructuredSubobjectInitList->setRBraceLoc(EndLoc);
- }
-
- // Warn about missing braces.
- if (T->isArrayType() || T->isRecordType()) {
- SemaRef.Diag(StructuredSubobjectInitList->getLocStart(),
- diag::warn_missing_braces)
- << StructuredSubobjectInitList->getSourceRange()
- << FixItHint::CreateInsertion(StructuredSubobjectInitList->getLocStart(),
- "{")
- << FixItHint::CreateInsertion(SemaRef.PP.getLocForEndOfToken(
+ if (!VerifyOnly) {
+ StructuredSubobjectInitList->setType(T);
+
+ // Update the structured sub-object initializer so that it's ending
+ // range corresponds with the end of the last initializer it used.
+ if (EndIndex < ParentIList->getNumInits()) {
+ SourceLocation EndLoc
+ = ParentIList->getInit(EndIndex)->getSourceRange().getEnd();
+ StructuredSubobjectInitList->setRBraceLoc(EndLoc);
+ }
+
+ // Warn about missing braces.
+ if (T->isArrayType() || T->isRecordType()) {
+ SemaRef.Diag(StructuredSubobjectInitList->getLocStart(),
+ diag::warn_missing_braces)
+ << StructuredSubobjectInitList->getSourceRange()
+ << FixItHint::CreateInsertion(
+ StructuredSubobjectInitList->getLocStart(), "{")
+ << FixItHint::CreateInsertion(
+ SemaRef.PP.getLocForEndOfToken(
StructuredSubobjectInitList->getLocEnd()),
- "}");
+ "}");
+ }
}
}
@@ -551,18 +571,31 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
unsigned &StructuredIndex,
bool TopLevelObject) {
assert(IList->isExplicit() && "Illegal Implicit InitListExpr");
- SyntacticToSemantic[IList] = StructuredList;
- StructuredList->setSyntacticForm(IList);
+ if (!VerifyOnly) {
+ SyntacticToSemantic[IList] = StructuredList;
+ StructuredList->setSyntacticForm(IList);
+ }
CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true,
Index, StructuredList, StructuredIndex, TopLevelObject);
- QualType ExprTy = T.getNonLValueExprType(SemaRef.Context);
- IList->setType(ExprTy);
- StructuredList->setType(ExprTy);
+ if (!VerifyOnly) {
+ QualType ExprTy = T.getNonLValueExprType(SemaRef.Context);
+ IList->setType(ExprTy);
+ StructuredList->setType(ExprTy);
+ }
if (hadError)
return;
if (Index < IList->getNumInits()) {
// We have leftover initializers
+ if (VerifyOnly) {
+ if (SemaRef.getLangOptions().CPlusPlus ||
+ (SemaRef.getLangOptions().OpenCL &&
+ IList->getType()->isVectorType())) {
+ hadError = true;
+ }
+ return;
+ }
+
if (StructuredIndex == 1 &&
IsStringInit(StructuredList->getInit(0), T, SemaRef.Context)) {
unsigned DK = diag::warn_excess_initializers_in_char_array_initializer;
@@ -599,7 +632,8 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
}
}
- if (T->isScalarType() && !TopLevelObject)
+ if (!VerifyOnly && T->isScalarType() && IList->getNumInits() == 1 &&
+ !TopLevelObject)
SemaRef.Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init)
<< IList->getSourceRange()
<< FixItHint::CreateRemoval(IList->getLocStart())
@@ -614,7 +648,12 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject) {
- if (DeclType->isScalarType()) {
+ if (DeclType->isAnyComplexType() && SubobjectIsDesignatorContext) {
+ // Explicitly braced initializer for complex type can be real+imaginary
+ // parts.
+ CheckComplexType(Entity, IList, DeclType, Index,
+ StructuredList, StructuredIndex);
+ } else if (DeclType->isScalarType()) {
CheckScalarType(Entity, IList, DeclType, Index,
StructuredList, StructuredIndex);
} else if (DeclType->isVectorType()) {
@@ -635,12 +674,13 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
SubobjectIsDesignatorContext, Index,
StructuredList, StructuredIndex);
} else
- assert(0 && "Aggregate that isn't a structure or array?!");
+ llvm_unreachable("Aggregate that isn't a structure or array?!");
} else if (DeclType->isVoidType() || DeclType->isFunctionType()) {
// This type is invalid, issue a diagnostic.
++Index;
- SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type)
- << DeclType;
+ if (!VerifyOnly)
+ SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type)
+ << DeclType;
hadError = true;
} else if (DeclType->isRecordType()) {
// C++ [dcl.init]p14:
@@ -651,19 +691,22 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
// we have an initializer list and a destination type that is not
// an aggregate.
// FIXME: In C++0x, this is yet another form of initialization.
- SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list)
- << DeclType << IList->getSourceRange();
+ if (!VerifyOnly)
+ SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list)
+ << DeclType << IList->getSourceRange();
hadError = true;
} else if (DeclType->isReferenceType()) {
CheckReferenceType(Entity, IList, DeclType, Index,
StructuredList, StructuredIndex);
} else if (DeclType->isObjCObjectType()) {
- SemaRef.Diag(IList->getLocStart(), diag::err_init_objc_class)
- << DeclType;
+ if (!VerifyOnly)
+ SemaRef.Diag(IList->getLocStart(), diag::err_init_objc_class)
+ << DeclType;
hadError = true;
} else {
- SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type)
- << DeclType;
+ if (!VerifyOnly)
+ SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type)
+ << DeclType;
hadError = true;
}
}
@@ -701,8 +744,10 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// type here, though.
if (Expr *Str = IsStringInit(expr, arrayType, SemaRef.Context)) {
- CheckStringInit(Str, ElemType, arrayType, SemaRef);
- UpdateStructuredListElement(StructuredList, StructuredIndex, Str);
+ if (!VerifyOnly) {
+ CheckStringInit(Str, ElemType, arrayType, SemaRef);
+ UpdateStructuredListElement(StructuredList, StructuredIndex, Str);
+ }
++Index;
return;
}
@@ -712,7 +757,7 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
} else if (SemaRef.getLangOptions().CPlusPlus) {
// C++ [dcl.init.aggr]p12:
// All implicit type conversions (clause 4) are considered when
- // initializing the aggregate member with an ini- tializer from
+ // initializing the aggregate member with an initializer from
// an initializer-list. If the initializer can initialize a
// member, the member is initialized. [...]
@@ -722,13 +767,15 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
InitializationSequence Seq(SemaRef, Entity, Kind, &expr, 1);
if (Seq) {
- ExprResult Result =
- Seq.Perform(SemaRef, Entity, Kind, MultiExprArg(&expr, 1));
- if (Result.isInvalid())
- hadError = true;
-
- UpdateStructuredListElement(StructuredList, StructuredIndex,
- Result.takeAs<Expr>());
+ if (!VerifyOnly) {
+ ExprResult Result =
+ Seq.Perform(SemaRef, Entity, Kind, MultiExprArg(&expr, 1));
+ if (Result.isInvalid())
+ hadError = true;
+
+ UpdateStructuredListElement(StructuredList, StructuredIndex,
+ Result.takeAs<Expr>());
+ }
++Index;
return;
}
@@ -745,7 +792,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// that of the expression.
ExprResult ExprRes = SemaRef.Owned(expr);
if ((ElemType->isRecordType() || ElemType->isVectorType()) &&
- SemaRef.CheckSingleAssignmentConstraints(ElemType, ExprRes)
+ SemaRef.CheckSingleAssignmentConstraints(ElemType, ExprRes,
+ !VerifyOnly)
== Sema::Compatible) {
if (ExprRes.isInvalid())
hadError = true;
@@ -775,25 +823,68 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
StructuredIndex);
++StructuredIndex;
} else {
- // We cannot initialize this element, so let
- // PerformCopyInitialization produce the appropriate diagnostic.
- SemaRef.PerformCopyInitialization(Entity, SourceLocation(),
- SemaRef.Owned(expr));
+ if (!VerifyOnly) {
+ // We cannot initialize this element, so let
+ // PerformCopyInitialization produce the appropriate diagnostic.
+ SemaRef.PerformCopyInitialization(Entity, SourceLocation(),
+ SemaRef.Owned(expr),
+ /*TopLevelOfInitList=*/true);
+ }
hadError = true;
++Index;
++StructuredIndex;
}
}
+void InitListChecker::CheckComplexType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType DeclType,
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex) {
+ assert(Index == 0 && "Index in explicit init list must be zero");
+
+ // As an extension, clang supports complex initializers, which initialize
+ // a complex number component-wise. When an explicit initializer list for
+ // a complex number contains two two initializers, this extension kicks in:
+ // it exepcts the initializer list to contain two elements convertible to
+ // the element type of the complex type. The first element initializes
+ // the real part, and the second element intitializes the imaginary part.
+
+ if (IList->getNumInits() != 2)
+ return CheckScalarType(Entity, IList, DeclType, Index, StructuredList,
+ StructuredIndex);
+
+ // This is an extension in C. (The builtin _Complex type does not exist
+ // in the C++ standard.)
+ if (!SemaRef.getLangOptions().CPlusPlus && !VerifyOnly)
+ SemaRef.Diag(IList->getLocStart(), diag::ext_complex_component_init)
+ << IList->getSourceRange();
+
+ // Initialize the complex number.
+ QualType elementType = DeclType->getAs<ComplexType>()->getElementType();
+ InitializedEntity ElementEntity =
+ InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity);
+
+ for (unsigned i = 0; i < 2; ++i) {
+ ElementEntity.setElementIndex(Index);
+ CheckSubElementType(ElementEntity, IList, elementType, Index,
+ StructuredList, StructuredIndex);
+ }
+}
+
+
void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
if (Index >= IList->getNumInits()) {
- SemaRef.Diag(IList->getLocStart(), diag::err_empty_scalar_initializer)
- << IList->getSourceRange();
- hadError = true;
+ if (!SemaRef.getLangOptions().CPlusPlus0x) {
+ if (!VerifyOnly)
+ SemaRef.Diag(IList->getLocStart(), diag::err_empty_scalar_initializer)
+ << IList->getSourceRange();
+ hadError = true;
+ }
++Index;
++StructuredIndex;
return;
@@ -801,26 +892,36 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
Expr *expr = IList->getInit(Index);
if (InitListExpr *SubIList = dyn_cast<InitListExpr>(expr)) {
- SemaRef.Diag(SubIList->getLocStart(),
- diag::warn_many_braces_around_scalar_init)
- << SubIList->getSourceRange();
+ if (!VerifyOnly)
+ SemaRef.Diag(SubIList->getLocStart(),
+ diag::warn_many_braces_around_scalar_init)
+ << SubIList->getSourceRange();
CheckScalarType(Entity, SubIList, DeclType, Index, StructuredList,
StructuredIndex);
return;
} else if (isa<DesignatedInitExpr>(expr)) {
- SemaRef.Diag(expr->getSourceRange().getBegin(),
- diag::err_designator_for_scalar_init)
- << DeclType << expr->getSourceRange();
+ if (!VerifyOnly)
+ SemaRef.Diag(expr->getSourceRange().getBegin(),
+ diag::err_designator_for_scalar_init)
+ << DeclType << expr->getSourceRange();
hadError = true;
++Index;
++StructuredIndex;
return;
}
+ if (VerifyOnly) {
+ if (!SemaRef.CanPerformCopyInitialization(Entity, SemaRef.Owned(expr)))
+ hadError = true;
+ ++Index;
+ return;
+ }
+
ExprResult Result =
SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(),
- SemaRef.Owned(expr));
+ SemaRef.Owned(expr),
+ /*TopLevelOfInitList=*/true);
Expr *ResultExpr = 0;
@@ -846,46 +947,57 @@ void InitListChecker::CheckReferenceType(const InitializedEntity &Entity,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
- if (Index < IList->getNumInits()) {
- Expr *expr = IList->getInit(Index);
- if (isa<InitListExpr>(expr)) {
- SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list)
- << DeclType << IList->getSourceRange();
- hadError = true;
- ++Index;
- ++StructuredIndex;
- return;
- }
-
- ExprResult Result =
- SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(),
- SemaRef.Owned(expr));
-
- if (Result.isInvalid())
- hadError = true;
-
- expr = Result.takeAs<Expr>();
- IList->setInit(Index, expr);
-
- if (hadError)
- ++StructuredIndex;
- else
- UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
- ++Index;
- } else {
+ if (Index >= IList->getNumInits()) {
// FIXME: It would be wonderful if we could point at the actual member. In
// general, it would be useful to pass location information down the stack,
// so that we know the location (or decl) of the "current object" being
// initialized.
- SemaRef.Diag(IList->getLocStart(),
- diag::err_init_reference_member_uninitialized)
- << DeclType
- << IList->getSourceRange();
+ if (!VerifyOnly)
+ SemaRef.Diag(IList->getLocStart(),
+ diag::err_init_reference_member_uninitialized)
+ << DeclType
+ << IList->getSourceRange();
hadError = true;
++Index;
++StructuredIndex;
return;
}
+
+ Expr *expr = IList->getInit(Index);
+ if (isa<InitListExpr>(expr)) {
+ // FIXME: Allowed in C++11.
+ if (!VerifyOnly)
+ SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list)
+ << DeclType << IList->getSourceRange();
+ hadError = true;
+ ++Index;
+ ++StructuredIndex;
+ return;
+ }
+
+ if (VerifyOnly) {
+ if (!SemaRef.CanPerformCopyInitialization(Entity, SemaRef.Owned(expr)))
+ hadError = true;
+ ++Index;
+ return;
+ }
+
+ ExprResult Result =
+ SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(),
+ SemaRef.Owned(expr),
+ /*TopLevelOfInitList=*/true);
+
+ if (Result.isInvalid())
+ hadError = true;
+
+ expr = Result.takeAs<Expr>();
+ IList->setInit(Index, expr);
+
+ if (hadError)
+ ++StructuredIndex;
+ else
+ UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+ ++Index;
}
void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
@@ -906,9 +1018,17 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
// instead of breaking it apart (which is doomed to failure anyway).
Expr *Init = IList->getInit(Index);
if (!isa<InitListExpr>(Init) && Init->getType()->isVectorType()) {
+ if (VerifyOnly) {
+ if (!SemaRef.CanPerformCopyInitialization(Entity, SemaRef.Owned(Init)))
+ hadError = true;
+ ++Index;
+ return;
+ }
+
ExprResult Result =
SemaRef.PerformCopyInitialization(Entity, Init->getLocStart(),
- SemaRef.Owned(Init));
+ SemaRef.Owned(Init),
+ /*TopLevelOfInitList=*/true);
Expr *ResultExpr = 0;
if (Result.isInvalid())
@@ -924,7 +1044,8 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
if (hadError)
++StructuredIndex;
else
- UpdateStructuredListElement(StructuredList, StructuredIndex, ResultExpr);
+ UpdateStructuredListElement(StructuredList, StructuredIndex,
+ ResultExpr);
++Index;
return;
}
@@ -977,11 +1098,11 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
}
// OpenCL requires all elements to be initialized.
- if (numEltsInit != maxElements)
- if (SemaRef.getLangOptions().OpenCL)
- SemaRef.Diag(IList->getSourceRange().getBegin(),
- diag::err_vector_incorrect_num_initializers)
- << (numEltsInit < maxElements) << maxElements << numEltsInit;
+ // FIXME: Shouldn't this set hadError to true then?
+ if (numEltsInit != maxElements && !VerifyOnly)
+ SemaRef.Diag(IList->getSourceRange().getBegin(),
+ diag::err_vector_incorrect_num_initializers)
+ << (numEltsInit < maxElements) << maxElements << numEltsInit;
}
void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
@@ -997,14 +1118,16 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
if (Index < IList->getNumInits()) {
if (Expr *Str = IsStringInit(IList->getInit(Index), arrayType,
SemaRef.Context)) {
- CheckStringInit(Str, DeclType, arrayType, SemaRef);
// We place the string literal directly into the resulting
// initializer list. This is the only place where the structure
// of the structured initializer list doesn't match exactly,
// because doing so would involve allocating one character
// constant for each string.
- UpdateStructuredListElement(StructuredList, StructuredIndex, Str);
- StructuredList->resizeInits(SemaRef.Context, StructuredIndex);
+ if (!VerifyOnly) {
+ CheckStringInit(Str, DeclType, arrayType, SemaRef);
+ UpdateStructuredListElement(StructuredList, StructuredIndex, Str);
+ StructuredList->resizeInits(SemaRef.Context, StructuredIndex);
+ }
++Index;
return;
}
@@ -1013,9 +1136,10 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
// Check for VLAs; in standard C it would be possible to check this
// earlier, but I don't know where clang accepts VLAs (gcc accepts
// them in all sorts of strange places).
- SemaRef.Diag(VAT->getSizeExpr()->getLocStart(),
- diag::err_variable_object_no_init)
- << VAT->getSizeExpr()->getSourceRange();
+ if (!VerifyOnly)
+ SemaRef.Diag(VAT->getSizeExpr()->getLocStart(),
+ diag::err_variable_object_no_init)
+ << VAT->getSizeExpr()->getSourceRange();
hadError = true;
++Index;
++StructuredIndex;
@@ -1085,7 +1209,7 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
if (!maxElementsKnown && elementIndex > maxElements)
maxElements = elementIndex;
}
- if (!hadError && DeclType->isIncompleteArrayType()) {
+ if (!hadError && DeclType->isIncompleteArrayType() && !VerifyOnly) {
// If this is an incomplete array type, the actual type needs to
// be calculated here.
llvm::APSInt Zero(maxElements.getBitWidth(), maxElements.isUnsigned());
@@ -1101,6 +1225,45 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
}
}
+bool InitListChecker::CheckFlexibleArrayInit(const InitializedEntity &Entity,
+ Expr *InitExpr,
+ FieldDecl *Field,
+ bool TopLevelObject) {
+ // Handle GNU flexible array initializers.
+ unsigned FlexArrayDiag;
+ if (isa<InitListExpr>(InitExpr) &&
+ cast<InitListExpr>(InitExpr)->getNumInits() == 0) {
+ // Empty flexible array init always allowed as an extension
+ FlexArrayDiag = diag::ext_flexible_array_init;
+ } else if (SemaRef.getLangOptions().CPlusPlus) {
+ // Disallow flexible array init in C++; it is not required for gcc
+ // compatibility, and it needs work to IRGen correctly in general.
+ FlexArrayDiag = diag::err_flexible_array_init;
+ } else if (!TopLevelObject) {
+ // Disallow flexible array init on non-top-level object
+ FlexArrayDiag = diag::err_flexible_array_init;
+ } else if (Entity.getKind() != InitializedEntity::EK_Variable) {
+ // Disallow flexible array init on anything which is not a variable.
+ FlexArrayDiag = diag::err_flexible_array_init;
+ } else if (cast<VarDecl>(Entity.getDecl())->hasLocalStorage()) {
+ // Disallow flexible array init on local variables.
+ FlexArrayDiag = diag::err_flexible_array_init;
+ } else {
+ // Allow other cases.
+ FlexArrayDiag = diag::ext_flexible_array_init;
+ }
+
+ if (!VerifyOnly) {
+ SemaRef.Diag(InitExpr->getSourceRange().getBegin(),
+ FlexArrayDiag)
+ << InitExpr->getSourceRange().getBegin();
+ SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
+ << Field;
+ }
+
+ return FlexArrayDiag != diag::ext_flexible_array_init;
+}
+
void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
InitListExpr *IList,
QualType DeclType,
@@ -1120,13 +1283,15 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
}
if (DeclType->isUnionType() && IList->getNumInits() == 0) {
- // Value-initialize the first named member of the union.
- RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
- for (RecordDecl::field_iterator FieldEnd = RD->field_end();
- Field != FieldEnd; ++Field) {
- if (Field->getDeclName()) {
- StructuredList->setInitializedFieldInUnion(*Field);
- break;
+ if (!VerifyOnly) {
+ // Value-initialize the first named member of the union.
+ RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
+ for (RecordDecl::field_iterator FieldEnd = RD->field_end();
+ Field != FieldEnd; ++Field) {
+ if (Field->getDeclName()) {
+ StructuredList->setInitializedFieldInUnion(*Field);
+ break;
+ }
}
}
return;
@@ -1186,13 +1351,18 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
}
// Make sure we can use this declaration.
- if (SemaRef.DiagnoseUseOfDecl(*Field,
- IList->getInit(Index)->getLocStart())) {
+ bool InvalidUse;
+ if (VerifyOnly)
+ InvalidUse = !SemaRef.CanUseDecl(*Field);
+ else
+ InvalidUse = SemaRef.DiagnoseUseOfDecl(*Field,
+ IList->getInit(Index)->getLocStart());
+ if (InvalidUse) {
++Index;
++Field;
hadError = true;
continue;
- }
+ }
InitializedEntity MemberEntity =
InitializedEntity::InitializeMember(*Field, &Entity);
@@ -1200,7 +1370,7 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
StructuredList, StructuredIndex);
InitializedSomething = true;
- if (DeclType->isUnionType()) {
+ if (DeclType->isUnionType() && !VerifyOnly) {
// Initialize the first field within the union.
StructuredList->setInitializedFieldInUnion(*Field);
}
@@ -1209,8 +1379,9 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
}
// Emit warnings for missing struct field initializers.
- if (InitializedSomething && CheckForMissingFields && Field != FieldEnd &&
- !Field->getType()->isIncompleteArrayType() && !DeclType->isUnionType()) {
+ if (!VerifyOnly && InitializedSomething && CheckForMissingFields &&
+ Field != FieldEnd && !Field->getType()->isIncompleteArrayType() &&
+ !DeclType->isUnionType()) {
// It is possible we have one or more unnamed bitfields remaining.
// Find first (if any) named field and emit warning.
for (RecordDecl::field_iterator it = Field, end = RD->field_end();
@@ -1227,24 +1398,11 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
Index >= IList->getNumInits())
return;
- // Handle GNU flexible array initializers.
- if (!TopLevelObject &&
- (!isa<InitListExpr>(IList->getInit(Index)) ||
- cast<InitListExpr>(IList->getInit(Index))->getNumInits() > 0)) {
- SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(),
- diag::err_flexible_array_init_nonempty)
- << IList->getInit(Index)->getSourceRange().getBegin();
- SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
- << *Field;
+ if (CheckFlexibleArrayInit(Entity, IList->getInit(Index), *Field,
+ TopLevelObject)) {
hadError = true;
++Index;
return;
- } else {
- SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(),
- diag::ext_flexible_array_init)
- << IList->getInit(Index)->getSourceRange().getBegin();
- SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
- << *Field;
}
InitializedEntity MemberEntity =
@@ -1269,7 +1427,7 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
typedef DesignatedInitExpr::Designator Designator;
// Build the replacement designators.
- llvm::SmallVector<Designator, 4> Replacements;
+ SmallVector<Designator, 4> Replacements;
for (IndirectFieldDecl::chain_iterator PI = IndirectField->chain_begin(),
PE = IndirectField->chain_end(); PI != PE; ++PI) {
if (PI + 1 == PE)
@@ -1304,6 +1462,18 @@ static IndirectFieldDecl *FindIndirectFieldDesignator(FieldDecl *AnonField,
return 0;
}
+static DesignatedInitExpr *CloneDesignatedInitExpr(Sema &SemaRef,
+ DesignatedInitExpr *DIE) {
+ unsigned NumIndexExprs = DIE->getNumSubExprs() - 1;
+ SmallVector<Expr*, 4> IndexExprs(NumIndexExprs);
+ for (unsigned I = 0; I < NumIndexExprs; ++I)
+ IndexExprs[I] = DIE->getSubExpr(I + 1);
+ return DesignatedInitExpr::Create(SemaRef.Context, DIE->designators_begin(),
+ DIE->size(), IndexExprs.data(),
+ NumIndexExprs, DIE->getEqualOrColonLoc(),
+ DIE->usesGNUSyntax(), DIE->getInit());
+}
+
/// @brief Check the well-formedness of a C99 designated initializer.
///
/// Determines whether the designated initializer @p DIE, which
@@ -1342,14 +1512,14 @@ static IndirectFieldDecl *FindIndirectFieldDesignator(FieldDecl *AnonField,
bool
InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
InitListExpr *IList,
- DesignatedInitExpr *DIE,
- unsigned DesigIdx,
- QualType &CurrentObjectType,
- RecordDecl::field_iterator *NextField,
- llvm::APSInt *NextElementIndex,
- unsigned &Index,
- InitListExpr *StructuredList,
- unsigned &StructuredIndex,
+ DesignatedInitExpr *DIE,
+ unsigned DesigIdx,
+ QualType &CurrentObjectType,
+ RecordDecl::field_iterator *NextField,
+ llvm::APSInt *NextElementIndex,
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex,
bool FinishSubobjectInit,
bool TopLevelObject) {
if (DesigIdx == DIE->size()) {
@@ -1374,19 +1544,21 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
return hadError && !prevHadError;
}
- bool IsFirstDesignator = (DesigIdx == 0);
- assert((IsFirstDesignator || StructuredList) &&
- "Need a non-designated initializer list to start from");
-
DesignatedInitExpr::Designator *D = DIE->getDesignator(DesigIdx);
- // Determine the structural initializer list that corresponds to the
- // current subobject.
- StructuredList = IsFirstDesignator? SyntacticToSemantic[IList]
- : getStructuredSubobjectInit(IList, Index, CurrentObjectType,
- StructuredList, StructuredIndex,
- SourceRange(D->getStartLocation(),
- DIE->getSourceRange().getEnd()));
- assert(StructuredList && "Expected a structured initializer list");
+ bool IsFirstDesignator = (DesigIdx == 0);
+ if (!VerifyOnly) {
+ assert((IsFirstDesignator || StructuredList) &&
+ "Need a non-designated initializer list to start from");
+
+ // Determine the structural initializer list that corresponds to the
+ // current subobject.
+ StructuredList = IsFirstDesignator? SyntacticToSemantic[IList]
+ : getStructuredSubobjectInit(IList, Index, CurrentObjectType,
+ StructuredList, StructuredIndex,
+ SourceRange(D->getStartLocation(),
+ DIE->getSourceRange().getEnd()));
+ assert(StructuredList && "Expected a structured initializer list");
+ }
if (D->isFieldDesignator()) {
// C99 6.7.8p7:
@@ -1403,8 +1575,9 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
SourceLocation Loc = D->getDotLoc();
if (Loc.isInvalid())
Loc = D->getFieldLoc();
- SemaRef.Diag(Loc, diag::err_field_designator_non_aggr)
- << SemaRef.getLangOptions().CPlusPlus << CurrentObjectType;
+ if (!VerifyOnly)
+ SemaRef.Diag(Loc, diag::err_field_designator_non_aggr)
+ << SemaRef.getLangOptions().CPlusPlus << CurrentObjectType;
++Index;
return true;
}
@@ -1427,6 +1600,9 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
if (!KnownField && Field->isAnonymousStructOrUnion()) {
if (IndirectFieldDecl *IF =
FindIndirectFieldDesignator(*Field, FieldName)) {
+ // In verify mode, don't modify the original.
+ if (VerifyOnly)
+ DIE = CloneDesignatedInitExpr(SemaRef, DIE);
ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, IF);
D = DIE->getDesignator(DesigIdx);
break;
@@ -1441,6 +1617,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
}
if (Field == FieldEnd) {
+ if (VerifyOnly) {
+ ++Index;
+ return true; // No typo correction when just trying this out.
+ }
+
// There was no normal field in the struct with the designated
// name. Perform another lookup for this name, which may find
// something that we can't designate (e.g., a member function),
@@ -1470,6 +1651,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
<< FixItHint::CreateReplacement(D->getFieldLoc(), CorrectedStr);
SemaRef.Diag(ReplacementField->getLocation(),
diag::note_previous_decl) << CorrectedQuotedStr;
+ hadError = true;
} else {
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
<< FieldName << CurrentObjectType;
@@ -1510,22 +1692,30 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// the initializer list.
if (RT->getDecl()->isUnion()) {
FieldIndex = 0;
- StructuredList->setInitializedFieldInUnion(*Field);
+ if (!VerifyOnly)
+ StructuredList->setInitializedFieldInUnion(*Field);
}
// Make sure we can use this declaration.
- if (SemaRef.DiagnoseUseOfDecl(*Field, D->getFieldLoc())) {
+ bool InvalidUse;
+ if (VerifyOnly)
+ InvalidUse = !SemaRef.CanUseDecl(*Field);
+ else
+ InvalidUse = SemaRef.DiagnoseUseOfDecl(*Field, D->getFieldLoc());
+ if (InvalidUse) {
++Index;
return true;
- }
+ }
- // Update the designator with the field declaration.
- D->setField(*Field);
+ if (!VerifyOnly) {
+ // Update the designator with the field declaration.
+ D->setField(*Field);
- // Make sure that our non-designated initializer list has space
- // for a subobject corresponding to this field.
- if (FieldIndex >= StructuredList->getNumInits())
- StructuredList->resizeInits(SemaRef.Context, FieldIndex + 1);
+ // Make sure that our non-designated initializer list has space
+ // for a subobject corresponding to this field.
+ if (FieldIndex >= StructuredList->getNumInits())
+ StructuredList->resizeInits(SemaRef.Context, FieldIndex + 1);
+ }
// This designator names a flexible array member.
if (Field->getType()->isIncompleteArrayType()) {
@@ -1533,38 +1723,36 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
if ((DesigIdx + 1) != DIE->size()) {
// We can't designate an object within the flexible array
// member (because GCC doesn't allow it).
- DesignatedInitExpr::Designator *NextD
- = DIE->getDesignator(DesigIdx + 1);
- SemaRef.Diag(NextD->getStartLocation(),
- diag::err_designator_into_flexible_array_member)
- << SourceRange(NextD->getStartLocation(),
- DIE->getSourceRange().getEnd());
- SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
- << *Field;
+ if (!VerifyOnly) {
+ DesignatedInitExpr::Designator *NextD
+ = DIE->getDesignator(DesigIdx + 1);
+ SemaRef.Diag(NextD->getStartLocation(),
+ diag::err_designator_into_flexible_array_member)
+ << SourceRange(NextD->getStartLocation(),
+ DIE->getSourceRange().getEnd());
+ SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
+ << *Field;
+ }
Invalid = true;
}
if (!hadError && !isa<InitListExpr>(DIE->getInit()) &&
!isa<StringLiteral>(DIE->getInit())) {
// The initializer is not an initializer list.
- SemaRef.Diag(DIE->getInit()->getSourceRange().getBegin(),
- diag::err_flexible_array_init_needs_braces)
- << DIE->getInit()->getSourceRange();
- SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
- << *Field;
+ if (!VerifyOnly) {
+ SemaRef.Diag(DIE->getInit()->getSourceRange().getBegin(),
+ diag::err_flexible_array_init_needs_braces)
+ << DIE->getInit()->getSourceRange();
+ SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
+ << *Field;
+ }
Invalid = true;
}
- // Handle GNU flexible array initializers.
- if (!Invalid && !TopLevelObject &&
- cast<InitListExpr>(DIE->getInit())->getNumInits() > 0) {
- SemaRef.Diag(DIE->getSourceRange().getBegin(),
- diag::err_flexible_array_init_nonempty)
- << DIE->getSourceRange().getBegin();
- SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
- << *Field;
+ // Check GNU flexible array initializer.
+ if (!Invalid && CheckFlexibleArrayInit(Entity, DIE->getInit(), *Field,
+ TopLevelObject))
Invalid = true;
- }
if (Invalid) {
++Index;
@@ -1651,8 +1839,9 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// [ constant-expression ... constant-expression ]
const ArrayType *AT = SemaRef.Context.getAsArrayType(CurrentObjectType);
if (!AT) {
- SemaRef.Diag(D->getLBracketLoc(), diag::err_array_designator_non_array)
- << CurrentObjectType;
+ if (!VerifyOnly)
+ SemaRef.Diag(D->getLBracketLoc(), diag::err_array_designator_non_array)
+ << CurrentObjectType;
++Index;
return true;
}
@@ -1661,15 +1850,15 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
llvm::APSInt DesignatedStartIndex, DesignatedEndIndex;
if (D->isArrayDesignator()) {
IndexExpr = DIE->getArrayIndex(*D);
- DesignatedStartIndex = IndexExpr->EvaluateAsInt(SemaRef.Context);
+ DesignatedStartIndex = IndexExpr->EvaluateKnownConstInt(SemaRef.Context);
DesignatedEndIndex = DesignatedStartIndex;
} else {
assert(D->isArrayRangeDesignator() && "Need array-range designator");
DesignatedStartIndex =
- DIE->getArrayRangeStart(*D)->EvaluateAsInt(SemaRef.Context);
+ DIE->getArrayRangeStart(*D)->EvaluateKnownConstInt(SemaRef.Context);
DesignatedEndIndex =
- DIE->getArrayRangeEnd(*D)->EvaluateAsInt(SemaRef.Context);
+ DIE->getArrayRangeEnd(*D)->EvaluateKnownConstInt(SemaRef.Context);
IndexExpr = DIE->getArrayRangeEnd(*D);
// Codegen can't handle evaluating array range designators that have side
@@ -1678,7 +1867,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// elements with something that has a side effect, so codegen can emit an
// "error unsupported" error instead of miscompiling the app.
if (DesignatedStartIndex.getZExtValue()!=DesignatedEndIndex.getZExtValue()&&
- DIE->getInit()->HasSideEffects(SemaRef.Context))
+ DIE->getInit()->HasSideEffects(SemaRef.Context) && !VerifyOnly)
FullyStructuredList->sawArrayRangeDesignator();
}
@@ -1691,10 +1880,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
= DesignatedEndIndex.extOrTrunc(MaxElements.getBitWidth());
DesignatedEndIndex.setIsUnsigned(MaxElements.isUnsigned());
if (DesignatedEndIndex >= MaxElements) {
- SemaRef.Diag(IndexExpr->getSourceRange().getBegin(),
- diag::err_array_designator_too_large)
- << DesignatedEndIndex.toString(10) << MaxElements.toString(10)
- << IndexExpr->getSourceRange();
+ if (!VerifyOnly)
+ SemaRef.Diag(IndexExpr->getSourceRange().getBegin(),
+ diag::err_array_designator_too_large)
+ << DesignatedEndIndex.toString(10) << MaxElements.toString(10)
+ << IndexExpr->getSourceRange();
++Index;
return true;
}
@@ -1713,7 +1903,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// Make sure that our non-designated initializer list has space
// for a subobject corresponding to this array element.
- if (DesignatedEndIndex.getZExtValue() >= StructuredList->getNumInits())
+ if (!VerifyOnly &&
+ DesignatedEndIndex.getZExtValue() >= StructuredList->getNumInits())
StructuredList->resizeInits(SemaRef.Context,
DesignatedEndIndex.getZExtValue() + 1);
@@ -1773,6 +1964,8 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
InitListExpr *StructuredList,
unsigned StructuredIndex,
SourceRange InitRange) {
+ if (VerifyOnly)
+ return 0; // No structured list in verification-only mode.
Expr *ExistingInit = 0;
if (!StructuredList)
ExistingInit = SyntacticToSemantic[IList];
@@ -1844,9 +2037,6 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
RDecl->field_end());
}
- if (NumElements < NumInits)
- NumElements = IList->getNumInits();
-
Result->reserveInits(SemaRef.Context, NumElements);
// Link this new initializer list into the structured initializer
@@ -1915,8 +2105,8 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
typedef DesignatedInitExpr::Designator ASTDesignator;
bool Invalid = false;
- llvm::SmallVector<ASTDesignator, 32> Designators;
- llvm::SmallVector<Expr *, 32> InitExpressions;
+ SmallVector<ASTDesignator, 32> Designators;
+ SmallVector<Expr *, 32> InitExpressions;
// Build designators and check array designator expressions.
for (unsigned Idx = 0; Idx < Desig.getNumDesignators(); ++Idx) {
@@ -2007,15 +2197,6 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
return Owned(DIE);
}
-bool Sema::CheckInitList(const InitializedEntity &Entity,
- InitListExpr *&InitList, QualType &DeclType) {
- InitListChecker CheckInitList(*this, Entity, InitList, DeclType);
- if (!CheckInitList.HadError())
- InitList = CheckInitList.getFullyStructuredList();
-
- return CheckInitList.HadError();
-}
-
//===----------------------------------------------------------------------===//
// Initialization entity
//===----------------------------------------------------------------------===//
@@ -2027,9 +2208,14 @@ InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index,
if (const ArrayType *AT = Context.getAsArrayType(Parent.getType())) {
Kind = EK_ArrayElement;
Type = AT->getElementType();
- } else {
+ } else if (const VectorType *VT = Parent.getType()->getAs<VectorType>()) {
Kind = EK_VectorElement;
- Type = Parent.getType()->getAs<VectorType>()->getElementType();
+ Type = VT->getElementType();
+ } else {
+ const ComplexType *CT = Parent.getType()->getAs<ComplexType>();
+ assert(CT && "Unexpected type");
+ Kind = EK_ComplexElement;
+ Type = CT->getElementType();
}
}
@@ -2066,6 +2252,7 @@ DeclarationName InitializedEntity::getName() const {
case EK_Delegating:
case EK_ArrayElement:
case EK_VectorElement:
+ case EK_ComplexElement:
case EK_BlockElement:
return DeclarationName();
}
@@ -2091,6 +2278,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const {
case EK_Delegating:
case EK_ArrayElement:
case EK_VectorElement:
+ case EK_ComplexElement:
case EK_BlockElement:
return 0;
}
@@ -2114,6 +2302,7 @@ bool InitializedEntity::allowsNRVO() const {
case EK_Delegating:
case EK_ArrayElement:
case EK_VectorElement:
+ case EK_ComplexElement:
case EK_BlockElement:
break;
}
@@ -2139,6 +2328,7 @@ void InitializationSequence::Step::Destroy() {
case SK_QualificationConversionXValue:
case SK_QualificationConversionLValue:
case SK_ListInitialization:
+ case SK_ListConstructorCall:
case SK_ConstructorInitialization:
case SK_ZeroInitialization:
case SK_CAssignment:
@@ -2182,6 +2372,7 @@ bool InitializationSequence::isAmbiguous() const {
case FK_Incomplete:
case FK_ArrayTypeMismatch:
case FK_NonConstantArrayInit:
+ case FK_ListInitializationFailed:
return false;
case FK_ReferenceInitOverloadFailed:
@@ -2197,12 +2388,171 @@ bool InitializationSequence::isConstructorInitialization() const {
return !Steps.empty() && Steps.back().Kind == SK_ConstructorInitialization;
}
+bool InitializationSequence::endsWithNarrowing(ASTContext &Ctx,
+ const Expr *Initializer,
+ bool *isInitializerConstant,
+ APValue *ConstantValue) const {
+ if (Steps.empty() || Initializer->isValueDependent())
+ return false;
+
+ const Step &LastStep = Steps.back();
+ if (LastStep.Kind != SK_ConversionSequence)
+ return false;
+
+ const ImplicitConversionSequence &ICS = *LastStep.ICS;
+ const StandardConversionSequence *SCS = NULL;
+ switch (ICS.getKind()) {
+ case ImplicitConversionSequence::StandardConversion:
+ SCS = &ICS.Standard;
+ break;
+ case ImplicitConversionSequence::UserDefinedConversion:
+ SCS = &ICS.UserDefined.After;
+ break;
+ case ImplicitConversionSequence::AmbiguousConversion:
+ case ImplicitConversionSequence::EllipsisConversion:
+ case ImplicitConversionSequence::BadConversion:
+ return false;
+ }
+
+ // Check if SCS represents a narrowing conversion, according to C++0x
+ // [dcl.init.list]p7:
+ //
+ // A narrowing conversion is an implicit conversion ...
+ ImplicitConversionKind PossibleNarrowing = SCS->Second;
+ QualType FromType = SCS->getToType(0);
+ QualType ToType = SCS->getToType(1);
+ switch (PossibleNarrowing) {
+ // * from a floating-point type to an integer type, or
+ //
+ // * from an integer type or unscoped enumeration type to a floating-point
+ // type, except where the source is a constant expression and the actual
+ // value after conversion will fit into the target type and will produce
+ // the original value when converted back to the original type, or
+ case ICK_Floating_Integral:
+ if (FromType->isRealFloatingType() && ToType->isIntegralType(Ctx)) {
+ *isInitializerConstant = false;
+ return true;
+ } else if (FromType->isIntegralType(Ctx) && ToType->isRealFloatingType()) {
+ llvm::APSInt IntConstantValue;
+ if (Initializer &&
+ Initializer->isIntegerConstantExpr(IntConstantValue, Ctx)) {
+ // Convert the integer to the floating type.
+ llvm::APFloat Result(Ctx.getFloatTypeSemantics(ToType));
+ Result.convertFromAPInt(IntConstantValue, IntConstantValue.isSigned(),
+ llvm::APFloat::rmNearestTiesToEven);
+ // And back.
+ llvm::APSInt ConvertedValue = IntConstantValue;
+ bool ignored;
+ Result.convertToInteger(ConvertedValue,
+ llvm::APFloat::rmTowardZero, &ignored);
+ // If the resulting value is different, this was a narrowing conversion.
+ if (IntConstantValue != ConvertedValue) {
+ *isInitializerConstant = true;
+ *ConstantValue = APValue(IntConstantValue);
+ return true;
+ }
+ } else {
+ // Variables are always narrowings.
+ *isInitializerConstant = false;
+ return true;
+ }
+ }
+ return false;
+
+ // * from long double to double or float, or from double to float, except
+ // where the source is a constant expression and the actual value after
+ // conversion is within the range of values that can be represented (even
+ // if it cannot be represented exactly), or
+ case ICK_Floating_Conversion:
+ if (1 == Ctx.getFloatingTypeOrder(FromType, ToType)) {
+ // FromType is larger than ToType.
+ Expr::EvalResult InitializerValue;
+ // FIXME: Check whether Initializer is a constant expression according
+ // to C++0x [expr.const], rather than just whether it can be folded.
+ if (Initializer->Evaluate(InitializerValue, Ctx) &&
+ !InitializerValue.HasSideEffects && InitializerValue.Val.isFloat()) {
+ // Constant! (Except for FIXME above.)
+ llvm::APFloat FloatVal = InitializerValue.Val.getFloat();
+ // Convert the source value into the target type.
+ bool ignored;
+ llvm::APFloat::opStatus ConvertStatus = FloatVal.convert(
+ Ctx.getFloatTypeSemantics(ToType),
+ llvm::APFloat::rmNearestTiesToEven, &ignored);
+ // If there was no overflow, the source value is within the range of
+ // values that can be represented.
+ if (ConvertStatus & llvm::APFloat::opOverflow) {
+ *isInitializerConstant = true;
+ *ConstantValue = InitializerValue.Val;
+ return true;
+ }
+ } else {
+ *isInitializerConstant = false;
+ return true;
+ }
+ }
+ return false;
+
+ // * from an integer type or unscoped enumeration type to an integer type
+ // that cannot represent all the values of the original type, except where
+ // the source is a constant expression and the actual value after
+ // conversion will fit into the target type and will produce the original
+ // value when converted back to the original type.
+ case ICK_Boolean_Conversion: // Bools are integers too.
+ if (!FromType->isIntegralOrUnscopedEnumerationType()) {
+ // Boolean conversions can be from pointers and pointers to members
+ // [conv.bool], and those aren't considered narrowing conversions.
+ return false;
+ } // Otherwise, fall through to the integral case.
+ case ICK_Integral_Conversion: {
+ assert(FromType->isIntegralOrUnscopedEnumerationType());
+ assert(ToType->isIntegralOrUnscopedEnumerationType());
+ const bool FromSigned = FromType->isSignedIntegerOrEnumerationType();
+ const unsigned FromWidth = Ctx.getIntWidth(FromType);
+ const bool ToSigned = ToType->isSignedIntegerOrEnumerationType();
+ const unsigned ToWidth = Ctx.getIntWidth(ToType);
+
+ if (FromWidth > ToWidth ||
+ (FromWidth == ToWidth && FromSigned != ToSigned)) {
+ // Not all values of FromType can be represented in ToType.
+ llvm::APSInt InitializerValue;
+ if (Initializer->isIntegerConstantExpr(InitializerValue, Ctx)) {
+ *isInitializerConstant = true;
+ *ConstantValue = APValue(InitializerValue);
+
+ // Add a bit to the InitializerValue so we don't have to worry about
+ // signed vs. unsigned comparisons.
+ InitializerValue = InitializerValue.extend(
+ InitializerValue.getBitWidth() + 1);
+ // Convert the initializer to and from the target width and signed-ness.
+ llvm::APSInt ConvertedValue = InitializerValue;
+ ConvertedValue = ConvertedValue.trunc(ToWidth);
+ ConvertedValue.setIsSigned(ToSigned);
+ ConvertedValue = ConvertedValue.extend(InitializerValue.getBitWidth());
+ ConvertedValue.setIsSigned(InitializerValue.isSigned());
+ // If the result is different, this was a narrowing conversion.
+ return ConvertedValue != InitializerValue;
+ } else {
+ // Variables are always narrowings.
+ *isInitializerConstant = false;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ default:
+ // Other kinds of conversions are not narrowings.
+ return false;
+ }
+}
+
void InitializationSequence::AddAddressOverloadResolutionStep(
FunctionDecl *Function,
DeclAccessPair Found) {
Step S;
S.Kind = SK_ResolveAddressOfOverloadedFunction;
S.Type = Function->getType();
+ S.Function.HadMultipleCandidates = false;
S.Function.Function = Function;
S.Function.FoundDecl = Found;
Steps.push_back(S);
@@ -2242,6 +2592,7 @@ void InitializationSequence::AddUserConversionStep(FunctionDecl *Function,
Step S;
S.Kind = SK_UserConversion;
S.Type = T;
+ S.Function.HadMultipleCandidates = false;
S.Function.Function = Function;
S.Function.FoundDecl = FoundDecl;
Steps.push_back(S);
@@ -2291,6 +2642,7 @@ InitializationSequence::AddConstructorInitializationStep(
Step S;
S.Kind = SK_ConstructorInitialization;
S.Type = T;
+ S.Function.HadMultipleCandidates = false;
S.Function.Function = Constructor;
S.Function.FoundDecl = DeclAccessPair::make(Constructor, Access);
Steps.push_back(S);
@@ -2391,44 +2743,33 @@ static void TryListInitialization(Sema &S,
const InitializationKind &Kind,
InitListExpr *InitList,
InitializationSequence &Sequence) {
- // FIXME: We only perform rudimentary checking of list
- // initializations at this point, then assume that any list
- // initialization of an array, aggregate, or scalar will be
- // well-formed. When we actually "perform" list initialization, we'll
- // do all of the necessary checking. C++0x initializer lists will
- // force us to perform more checking here.
-
QualType DestType = Entity.getType();
- // C++ [dcl.init]p13:
- // If T is a scalar type, then a declaration of the form
- //
- // T x = { a };
- //
- // is equivalent to
- //
- // T x = a;
- if (DestType->isScalarType()) {
- if (InitList->getNumInits() > 1 && S.getLangOptions().CPlusPlus) {
- Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForScalar);
- return;
- }
-
- // Assume scalar initialization from a single value works.
- } else if (DestType->isAggregateType()) {
- // Assume aggregate initialization works.
- } else if (DestType->isVectorType()) {
- // Assume vector initialization works.
- } else if (DestType->isReferenceType()) {
- // FIXME: C++0x defines behavior for this.
+ // C++ doesn't allow scalar initialization with more than one argument.
+ // But C99 complex numbers are scalars and it makes sense there.
+ if (S.getLangOptions().CPlusPlus && DestType->isScalarType() &&
+ !DestType->isAnyComplexType() && InitList->getNumInits() > 1) {
+ Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForScalar);
+ return;
+ }
+ // FIXME: C++0x defines behavior for these two cases.
+ if (DestType->isReferenceType()) {
Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList);
return;
- } else if (DestType->isRecordType()) {
- // FIXME: C++0x defines behavior for this
+ }
+ if (DestType->isRecordType() && !DestType->isAggregateType()) {
Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType);
+ return;
}
- // Add a general "list initialization" step.
+ InitListChecker CheckInitList(S, Entity, InitList,
+ DestType, /*VerifyOnly=*/true);
+ if (CheckInitList.HadError()) {
+ Sequence.SetFailed(InitializationSequence::FK_ListInitializationFailed);
+ return;
+ }
+
+ // Add the list initialization step with the built init list.
Sequence.AddListInitializationStep(DestType);
}
@@ -2767,7 +3108,7 @@ static void TryReferenceInitialization(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.getLangOptions().CPlusPlus0x && !S.getLangOptions().Microsoft)
+ if (!S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt)
Sequence.AddExtraneousCopyToTemporary(cv2T2);
}
@@ -2887,6 +3228,14 @@ static void TryConstructorInitialization(Sema &S,
Expr **Args, unsigned NumArgs,
QualType DestType,
InitializationSequence &Sequence) {
+ // Check constructor arguments for self reference.
+ if (DeclaratorDecl *DD = Entity.getDecl())
+ // Parameters arguments are occassionially constructed with itself,
+ // for instance, in recursive functions. Skip them.
+ if (!isa<ParmVarDecl>(DD))
+ for (unsigned i = 0; i < NumArgs; ++i)
+ S.CheckSelfReference(DD, Args[i]);
+
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
@@ -3577,7 +3926,7 @@ InitializationSequence::InitializationSequence(Sema &S,
}
InitializationSequence::~InitializationSequence() {
- for (llvm::SmallVectorImpl<Step>::iterator Step = Steps.begin(),
+ for (SmallVectorImpl<Step>::iterator Step = Steps.begin(),
StepEnd = Steps.end();
Step != StepEnd; ++Step)
Step->Destroy();
@@ -3613,6 +3962,7 @@ getAssignmentAction(const InitializedEntity &Entity) {
case InitializedEntity::EK_Member:
case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_VectorElement:
+ case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_BlockElement:
return Sema::AA_Initializing;
}
@@ -3632,6 +3982,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Delegating:
case InitializedEntity::EK_VectorElement:
+ case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_Exception:
case InitializedEntity::EK_BlockElement:
return false;
@@ -3654,6 +4005,7 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) {
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Delegating:
case InitializedEntity::EK_VectorElement:
+ case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_BlockElement:
return false;
@@ -3739,6 +4091,7 @@ static ExprResult CopyObject(Sema &S,
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Delegating:
case InitializedEntity::EK_VectorElement:
+ case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_BlockElement:
Loc = CurInitExpr->getLocStart();
break;
@@ -3790,6 +4143,8 @@ static ExprResult CopyObject(Sema &S,
&CurInitExpr, 1, CandidateSet, true);
}
+ bool HadMultipleCandidates = (CandidateSet.size() > 1);
+
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(S, Loc, Best)) {
case OR_Success:
@@ -3867,6 +4222,7 @@ static ExprResult CopyObject(Sema &S,
// Actually perform the constructor call.
CurInit = S.BuildCXXConstructExpr(Loc, T, Constructor, Elidable,
move_arg(ConstructorArgs),
+ HadMultipleCandidates,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
@@ -3982,6 +4338,7 @@ InitializationSequence::Perform(Sema &S,
case SK_QualificationConversionXValue:
case SK_QualificationConversionRValue:
case SK_ConversionSequence:
+ case SK_ListConstructorCall:
case SK_ListInitialization:
case SK_CAssignment:
case SK_StringInit:
@@ -4127,8 +4484,8 @@ InitializationSequence::Perform(Sema &S,
bool IsCopy = false;
FunctionDecl *Fn = Step->Function.Function;
DeclAccessPair FoundFn = Step->Function.FoundDecl;
+ bool HadMultipleCandidates = Step->Function.HadMultipleCandidates;
bool CreatedObject = false;
- bool IsLvalue = false;
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) {
// Build a call to the selected constructor.
ASTOwningVector<Expr*> ConstructorArgs(S);
@@ -4146,6 +4503,7 @@ InitializationSequence::Perform(Sema &S,
// Build the an expression that constructs a temporary.
CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor,
move_arg(ConstructorArgs),
+ HadMultipleCandidates,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
@@ -4166,7 +4524,6 @@ InitializationSequence::Perform(Sema &S,
} else {
// Build a call to the conversion function.
CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn);
- IsLvalue = Conversion->getResultType()->isLValueReferenceType();
S.CheckMemberOperatorAccess(Kind.getLocation(), CurInit.get(), 0,
FoundFn);
S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation());
@@ -4182,7 +4539,8 @@ InitializationSequence::Perform(Sema &S,
CurInit = move(CurInitExprRes);
// Build the actual call to the conversion function.
- CurInit = S.BuildCXXMemberCallExpr(CurInit.get(), FoundFn, Conversion);
+ CurInit = S.BuildCXXMemberCallExpr(CurInit.get(), FoundFn, Conversion,
+ HadMultipleCandidates);
if (CurInit.isInvalid() || !CurInit.get())
return ExprError();
@@ -4206,11 +4564,10 @@ InitializationSequence::Perform(Sema &S,
}
}
- // FIXME: xvalues
CurInit = S.Owned(ImplicitCastExpr::Create(S.Context,
CurInit.get()->getType(),
CastKind, CurInit.get(), 0,
- IsLvalue ? VK_LValue : VK_RValue));
+ CurInit.get()->getValueKind()));
if (RequiresCopy)
CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity,
@@ -4251,18 +4608,24 @@ InitializationSequence::Perform(Sema &S,
case SK_ListInitialization: {
InitListExpr *InitList = cast<InitListExpr>(CurInit.get());
QualType Ty = Step->Type;
- if (S.CheckInitList(Entity, InitList, ResultType? *ResultType : Ty))
+ InitListChecker PerformInitList(S, Entity, InitList,
+ ResultType ? *ResultType : Ty, /*VerifyOnly=*/false);
+ if (PerformInitList.HadError())
return ExprError();
CurInit.release();
- CurInit = S.Owned(InitList);
+ CurInit = S.Owned(PerformInitList.getFullyStructuredList());
break;
}
+ case SK_ListConstructorCall:
+ assert(false && "List constructor calls not yet supported.");
+
case SK_ConstructorInitialization: {
unsigned NumArgs = Args.size();
CXXConstructorDecl *Constructor
= cast<CXXConstructorDecl>(Step->Function.Function);
+ bool HadMultipleCandidates = Step->Function.HadMultipleCandidates;
// Build a call to the selected constructor.
ASTOwningVector<Expr*> ConstructorArgs(S);
@@ -4309,6 +4672,7 @@ InitializationSequence::Perform(Sema &S,
Exprs,
NumExprs,
Kind.getParenRange(),
+ HadMultipleCandidates,
ConstructorInitRequiresZeroInit));
} else {
CXXConstructExpr::ConstructionKind ConstructKind =
@@ -4333,6 +4697,7 @@ InitializationSequence::Perform(Sema &S,
CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
Constructor, /*Elidable=*/true,
move_arg(ConstructorArgs),
+ HadMultipleCandidates,
ConstructorInitRequiresZeroInit,
ConstructKind,
parenRange);
@@ -4340,6 +4705,7 @@ InitializationSequence::Perform(Sema &S,
CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
Constructor,
move_arg(ConstructorArgs),
+ HadMultipleCandidates,
ConstructorInitRequiresZeroInit,
ConstructKind,
parenRange);
@@ -4427,7 +4793,7 @@ InitializationSequence::Perform(Sema &S,
case SK_ObjCObjectConversion:
CurInit = S.ImpCastExprToType(CurInit.take(), Step->Type,
CK_ObjCObjectLValueCast,
- S.CastCategory(CurInit.get()));
+ CurInit.get()->getValueKind());
break;
case SK_ArrayInit:
@@ -4463,7 +4829,7 @@ InitializationSequence::Perform(Sema &S,
case SK_ProduceObjCObject:
CurInit = S.Owned(ImplicitCastExpr::Create(S.Context, Step->Type,
- CK_ObjCProduceObject,
+ CK_ARCProduceObject,
CurInit.take(), 0, VK_RValue));
break;
}
@@ -4759,17 +5125,28 @@ bool InitializationSequence::Diagnose(Sema &S,
}
break;
- case FK_Incomplete:
- S.RequireCompleteType(Kind.getLocation(), DestType,
- diag::err_init_incomplete_type);
- break;
+ case FK_Incomplete:
+ S.RequireCompleteType(Kind.getLocation(), DestType,
+ diag::err_init_incomplete_type);
+ break;
+
+ case FK_ListInitializationFailed: {
+ // Run the init list checker again to emit diagnostics.
+ InitListExpr* InitList = cast<InitListExpr>(Args[0]);
+ QualType DestType = Entity.getType();
+ InitListChecker DiagnoseInitList(S, Entity, InitList,
+ DestType, /*VerifyOnly=*/false);
+ assert(DiagnoseInitList.HadError() &&
+ "Inconsistent init list check result.");
+ break;
+ }
}
PrintInitLocationNote(S, Entity);
return true;
}
-void InitializationSequence::dump(llvm::raw_ostream &OS) const {
+void InitializationSequence::dump(raw_ostream &OS) const {
switch (SequenceKind) {
case FailedSequence: {
OS << "Failed sequence: ";
@@ -4857,6 +5234,9 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
case FK_Incomplete:
OS << "initialization of incomplete type";
break;
+
+ case FK_ListInitializationFailed:
+ OS << "list initialization checker failure";
}
OS << '\n';
return;
@@ -4906,7 +5286,7 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
break;
case SK_UserConversion:
- OS << "user-defined conversion via " << S->Function.Function;
+ OS << "user-defined conversion via " << *S->Function.Function;
break;
case SK_QualificationConversionRValue:
@@ -4926,7 +5306,11 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
break;
case SK_ListInitialization:
- OS << "list initialization";
+ OS << "list aggregate initialization";
+ break;
+
+ case SK_ListConstructorCall:
+ OS << "list initialization via constructor";
break;
case SK_ConstructorInitialization:
@@ -4972,6 +5356,51 @@ void InitializationSequence::dump() const {
dump(llvm::errs());
}
+static void DiagnoseNarrowingInInitList(
+ Sema& S, QualType EntityType, const Expr *InitE,
+ bool Constant, const APValue &ConstantValue) {
+ if (Constant) {
+ S.Diag(InitE->getLocStart(),
+ S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt
+ ? diag::err_init_list_constant_narrowing
+ : diag::warn_init_list_constant_narrowing)
+ << InitE->getSourceRange()
+ << ConstantValue
+ << EntityType.getLocalUnqualifiedType();
+ } else
+ S.Diag(InitE->getLocStart(),
+ S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt
+ ? diag::err_init_list_variable_narrowing
+ : diag::warn_init_list_variable_narrowing)
+ << InitE->getSourceRange()
+ << InitE->getType().getLocalUnqualifiedType()
+ << EntityType.getLocalUnqualifiedType();
+
+ llvm::SmallString<128> StaticCast;
+ llvm::raw_svector_ostream OS(StaticCast);
+ OS << "static_cast<";
+ if (const TypedefType *TT = EntityType->getAs<TypedefType>()) {
+ // It's important to use the typedef's name if there is one so that the
+ // fixit doesn't break code using types like int64_t.
+ //
+ // FIXME: This will break if the typedef requires qualification. But
+ // getQualifiedNameAsString() includes non-machine-parsable components.
+ OS << *TT->getDecl();
+ } else if (const BuiltinType *BT = EntityType->getAs<BuiltinType>())
+ OS << BT->getName(S.getLangOptions());
+ else {
+ // Oops, we didn't find the actual type of the variable. Don't emit a fixit
+ // with a broken cast.
+ return;
+ }
+ OS << ">(";
+ S.Diag(InitE->getLocStart(), diag::note_init_list_narrowing_override)
+ << InitE->getSourceRange()
+ << FixItHint::CreateInsertion(InitE->getLocStart(), OS.str())
+ << FixItHint::CreateInsertion(
+ S.getPreprocessor().getLocForEndOfToken(InitE->getLocEnd()), ")");
+}
+
//===----------------------------------------------------------------------===//
// Initialization helper functions
//===----------------------------------------------------------------------===//
@@ -4993,7 +5422,8 @@ Sema::CanPerformCopyInitialization(const InitializedEntity &Entity,
ExprResult
Sema::PerformCopyInitialization(const InitializedEntity &Entity,
SourceLocation EqualLoc,
- ExprResult Init) {
+ ExprResult Init,
+ bool TopLevelOfInitList) {
if (Init.isInvalid())
return ExprError();
@@ -5007,5 +5437,13 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity,
EqualLoc);
InitializationSequence Seq(*this, Entity, Kind, &InitE, 1);
Init.release();
+
+ bool Constant = false;
+ APValue Result;
+ if (TopLevelOfInitList &&
+ Seq.endsWithNarrowing(Context, InitE, &Constant, &Result)) {
+ DiagnoseNarrowingInInitList(*this, Entity.getType(), InitE,
+ Constant, Result);
+ }
return Seq.Perform(*this, Entity, Kind, MultiExprArg(&InitE, 1));
}
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 0e448e31207d..d5bee1d0e368 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -35,6 +35,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Support/ErrorHandling.h"
#include <limits>
#include <list>
@@ -86,7 +87,7 @@ namespace {
/// A collection of using directives, as used by C++ unqualified
/// lookup.
class UnqualUsingDirectiveSet {
- typedef llvm::SmallVector<UnqualUsingEntry, 8> ListTy;
+ typedef SmallVector<UnqualUsingEntry, 8> ListTy;
ListTy list;
llvm::SmallPtrSet<DeclContext*, 8> visited;
@@ -147,7 +148,7 @@ namespace {
// by its using directives, transitively) as if they appeared in
// the given effective context.
void addUsingDirectives(DeclContext *DC, DeclContext *EffectiveDC) {
- llvm::SmallVector<DeclContext*,4> queue;
+ SmallVector<DeclContext*,4> queue;
while (true) {
DeclContext::udir_iterator I, End;
for (llvm::tie(I, End) = DC->getUsingDirectives(); I != End; ++I) {
@@ -460,7 +461,7 @@ void LookupResult::setAmbiguousBaseSubobjectTypes(CXXBasePaths &P) {
setAmbiguous(AmbiguousBaseSubobjectTypes);
}
-void LookupResult::print(llvm::raw_ostream &Out) {
+void LookupResult::print(raw_ostream &Out) {
Out << Decls.size() << " result(s)";
if (isAmbiguous()) Out << ", ambiguous";
if (Paths) Out << ", base paths present";
@@ -549,6 +550,16 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) {
if (!Class->hasDeclaredCopyAssignment())
DeclareImplicitCopyAssignment(Class);
+ if (getLangOptions().CPlusPlus0x) {
+ // If the move constructor has not yet been declared, do so now.
+ if (Class->needsImplicitMoveConstructor())
+ DeclareImplicitMoveConstructor(Class); // might not actually do it
+
+ // If the move assignment operator has not yet been declared, do so now.
+ if (Class->needsImplicitMoveAssignment())
+ DeclareImplicitMoveAssignment(Class); // might not actually do it
+ }
+
// If the destructor has not yet been declared, do so now.
if (!Class->hasDeclaredDestructor())
DeclareImplicitDestructor(Class);
@@ -585,11 +596,14 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S,
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC))
if (Record->getDefinition() &&
CanDeclareSpecialMemberFunction(S.Context, Record)) {
+ CXXRecordDecl *Class = const_cast<CXXRecordDecl *>(Record);
if (Record->needsImplicitDefaultConstructor())
- S.DeclareImplicitDefaultConstructor(
- const_cast<CXXRecordDecl *>(Record));
+ S.DeclareImplicitDefaultConstructor(Class);
if (!Record->hasDeclaredCopyConstructor())
- S.DeclareImplicitCopyConstructor(const_cast<CXXRecordDecl *>(Record));
+ S.DeclareImplicitCopyConstructor(Class);
+ if (S.getLangOptions().CPlusPlus0x &&
+ Record->needsImplicitMoveConstructor())
+ S.DeclareImplicitMoveConstructor(Class);
}
break;
@@ -604,10 +618,17 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S,
if (Name.getCXXOverloadedOperator() != OO_Equal)
break;
- if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC))
- if (Record->getDefinition() && !Record->hasDeclaredCopyAssignment() &&
- CanDeclareSpecialMemberFunction(S.Context, Record))
- S.DeclareImplicitCopyAssignment(const_cast<CXXRecordDecl *>(Record));
+ if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) {
+ if (Record->getDefinition() &&
+ CanDeclareSpecialMemberFunction(S.Context, Record)) {
+ CXXRecordDecl *Class = const_cast<CXXRecordDecl *>(Record);
+ if (!Record->hasDeclaredCopyAssignment())
+ S.DeclareImplicitCopyAssignment(Class);
+ if (S.getLangOptions().CPlusPlus0x &&
+ Record->needsImplicitMoveAssignment())
+ S.DeclareImplicitMoveAssignment(Class);
+ }
+ }
break;
default:
@@ -648,7 +669,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
// name lookup. Instead, any conversion function templates visible in the
// context of the use are considered. [...]
const CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
- if (!Record->isDefinition())
+ if (!Record->isCompleteDefinition())
return Found;
const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions();
@@ -1187,7 +1208,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
// We have not yet looked into these namespaces, much less added
// their "using-children" to the queue.
- llvm::SmallVector<NamespaceDecl*, 8> Queue;
+ SmallVector<NamespaceDecl*, 8> Queue;
// We have already looked into the initial namespace; seed the queue
// with its using-children.
@@ -1332,7 +1353,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// Make sure that the declaration context is complete.
assert((!isa<TagDecl>(LookupCtx) ||
LookupCtx->isDependentContext() ||
- cast<TagDecl>(LookupCtx)->isDefinition() ||
+ cast<TagDecl>(LookupCtx)->isCompleteDefinition() ||
Context.getTypeDeclType(cast<TagDecl>(LookupCtx))->getAs<TagType>()
->isBeingDefined()) &&
"Declaration context must already be complete!");
@@ -1802,7 +1823,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
// Add direct and indirect base classes along with their associated
// namespaces.
- llvm::SmallVector<CXXRecordDecl *, 32> Bases;
+ SmallVector<CXXRecordDecl *, 32> Bases;
Bases.push_back(Class);
while (!Bases.empty()) {
// Pop this class off the stack.
@@ -1852,7 +1873,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
// the types do not contribute to this set. The sets of namespaces
// and classes are determined in the following way:
- llvm::SmallVector<const Type *, 16> Queue;
+ SmallVector<const Type *, 16> Queue;
const Type *T = Ty->getCanonicalTypeInternal().getTypePtr();
while (true) {
@@ -1979,6 +2000,12 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
case Type::ObjCObjectPointer:
Result.Namespaces.insert(Result.S.Context.getTranslationUnitDecl());
break;
+
+ // Atomic types are just wrappers; use the associations of the
+ // contained type.
+ case Type::Atomic:
+ T = cast<AtomicType>(T)->getValueType().getTypePtr();
+ continue;
}
if (Queue.empty()) break;
@@ -2210,12 +2237,14 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
if (!RD->hasDeclaredCopyConstructor())
DeclareImplicitCopyConstructor(RD);
- // TODO: Move constructors
+ if (getLangOptions().CPlusPlus0x && RD->needsImplicitMoveConstructor())
+ DeclareImplicitMoveConstructor(RD);
} else {
Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
if (!RD->hasDeclaredCopyAssignment())
DeclareImplicitCopyAssignment(RD);
- // TODO: Move assignment
+ if (getLangOptions().CPlusPlus0x && RD->needsImplicitMoveAssignment())
+ DeclareImplicitMoveAssignment(RD);
}
QualType ArgType = CanTy;
@@ -2358,6 +2387,15 @@ CXXConstructorDecl *Sema::LookupCopyingConstructor(CXXRecordDecl *Class,
return cast_or_null<CXXConstructorDecl>(Result->getMethod());
}
+/// \brief Look up the moving constructor for the given class.
+CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class) {
+ SpecialMemberOverloadResult *Result =
+ LookupSpecialMember(Class, CXXMoveConstructor, false,
+ false, false, false, false);
+
+ return cast_or_null<CXXConstructorDecl>(Result->getMethod());
+}
+
/// \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.
@@ -2366,6 +2404,8 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) {
DeclareImplicitDefaultConstructor(Class);
if (!Class->hasDeclaredCopyConstructor())
DeclareImplicitCopyConstructor(Class);
+ if (getLangOptions().CPlusPlus0x && Class->needsImplicitMoveConstructor())
+ DeclareImplicitMoveConstructor(Class);
}
CanQualType T = Context.getCanonicalType(Context.getTypeDeclType(Class));
@@ -2394,6 +2434,20 @@ CXXMethodDecl *Sema::LookupCopyingAssignment(CXXRecordDecl *Class,
return Result->getMethod();
}
+/// \brief Look up the moving assignment operator for the given class.
+CXXMethodDecl *Sema::LookupMovingAssignment(CXXRecordDecl *Class,
+ bool RValueThis,
+ unsigned ThisQuals) {
+ assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) &&
+ "non-const, non-volatile qualifiers for copy assignment this");
+ SpecialMemberOverloadResult *Result =
+ LookupSpecialMember(Class, CXXMoveAssignment, false, false, RValueThis,
+ ThisQuals & Qualifiers::Const,
+ ThisQuals & Qualifiers::Volatile);
+
+ return Result->getMethod();
+}
+
/// \brief Look for the destructor of the given class.
///
/// During semantic analysis, this routine should be used in lieu of
@@ -2530,24 +2584,7 @@ public:
/// \brief An entry in the shadow map, which is optimized to store a
/// single declaration (the common case) but can also store a list
/// of declarations.
- class ShadowMapEntry {
- typedef llvm::SmallVector<NamedDecl *, 4> DeclVector;
-
- /// \brief Contains either the solitary NamedDecl * or a vector
- /// of declarations.
- llvm::PointerUnion<NamedDecl *, DeclVector*> DeclOrVector;
-
- public:
- ShadowMapEntry() : DeclOrVector() { }
-
- void Add(NamedDecl *ND);
- void Destroy();
-
- // Iteration.
- typedef NamedDecl * const *iterator;
- iterator begin();
- iterator end();
- };
+ typedef llvm::TinyPtrVector<NamedDecl*> ShadowMapEntry;
private:
/// \brief A mapping from declaration names to the declarations that have
@@ -2581,7 +2618,9 @@ public:
NamedDecl *checkHidden(NamedDecl *ND);
/// \brief Add a declaration to the current shadow map.
- void add(NamedDecl *ND) { ShadowMaps.back()[ND->getDeclName()].Add(ND); }
+ void add(NamedDecl *ND) {
+ ShadowMaps.back()[ND->getDeclName()].push_back(ND);
+ }
};
/// \brief RAII object that records when we've entered a shadow context.
@@ -2596,66 +2635,12 @@ public:
}
~ShadowContextRAII() {
- for (ShadowMap::iterator E = Visible.ShadowMaps.back().begin(),
- EEnd = Visible.ShadowMaps.back().end();
- E != EEnd;
- ++E)
- E->second.Destroy();
-
Visible.ShadowMaps.pop_back();
}
};
} // end anonymous namespace
-void VisibleDeclsRecord::ShadowMapEntry::Add(NamedDecl *ND) {
- if (DeclOrVector.isNull()) {
- // 0 - > 1 elements: just set the single element information.
- DeclOrVector = ND;
- return;
- }
-
- if (NamedDecl *PrevND = DeclOrVector.dyn_cast<NamedDecl *>()) {
- // 1 -> 2 elements: create the vector of results and push in the
- // existing declaration.
- DeclVector *Vec = new DeclVector;
- Vec->push_back(PrevND);
- DeclOrVector = Vec;
- }
-
- // Add the new element to the end of the vector.
- DeclOrVector.get<DeclVector*>()->push_back(ND);
-}
-
-void VisibleDeclsRecord::ShadowMapEntry::Destroy() {
- if (DeclVector *Vec = DeclOrVector.dyn_cast<DeclVector *>()) {
- delete Vec;
- DeclOrVector = ((NamedDecl *)0);
- }
-}
-
-VisibleDeclsRecord::ShadowMapEntry::iterator
-VisibleDeclsRecord::ShadowMapEntry::begin() {
- if (DeclOrVector.isNull())
- return 0;
-
- if (DeclOrVector.is<NamedDecl *>())
- return DeclOrVector.getAddrOf<NamedDecl *>();
-
- return DeclOrVector.get<DeclVector *>()->begin();
-}
-
-VisibleDeclsRecord::ShadowMapEntry::iterator
-VisibleDeclsRecord::ShadowMapEntry::end() {
- if (DeclOrVector.isNull())
- return 0;
-
- if (DeclOrVector.is<NamedDecl *>())
- return DeclOrVector.getAddrOf<NamedDecl *>() + 1;
-
- return DeclOrVector.get<DeclVector *>()->end();
-}
-
NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) {
// Look through using declarations.
ND = ND->getUnderlyingDecl();
@@ -2722,7 +2707,7 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
D != DEnd; ++D) {
if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) {
if (Result.isAcceptableDecl(ND)) {
- Consumer.FoundDecl(ND, Visited.checkHidden(ND), InBaseClass);
+ Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
Visited.add(ND);
}
} else if (ObjCForwardProtocolDecl *ForwardProto
@@ -2733,19 +2718,17 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
P != PEnd;
++P) {
if (Result.isAcceptableDecl(*P)) {
- Consumer.FoundDecl(*P, Visited.checkHidden(*P), InBaseClass);
+ Consumer.FoundDecl(*P, Visited.checkHidden(*P), Ctx, InBaseClass);
Visited.add(*P);
}
}
} else if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(*D)) {
- for (ObjCClassDecl::iterator I = Class->begin(), IEnd = Class->end();
- I != IEnd; ++I) {
- ObjCInterfaceDecl *IFace = I->getInterface();
+ ObjCInterfaceDecl *IFace = Class->getForwardInterfaceDecl();
if (Result.isAcceptableDecl(IFace)) {
- Consumer.FoundDecl(IFace, Visited.checkHidden(IFace), InBaseClass);
+ Consumer.FoundDecl(IFace, Visited.checkHidden(IFace), Ctx,
+ InBaseClass);
Visited.add(IFace);
}
- }
}
// Visit transparent contexts and inline namespaces inside this context.
@@ -2885,7 +2868,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
D != DEnd; ++D) {
if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
if (Result.isAcceptableDecl(ND)) {
- Consumer.FoundDecl(ND, Visited.checkHidden(ND), false);
+ Consumer.FoundDecl(ND, Visited.checkHidden(ND), 0, false);
Visited.add(ND);
}
}
@@ -2909,24 +2892,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
Result.getNameLoc(), Sema::LookupMemberName);
if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) {
LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false,
- /*InBaseClass=*/false, Consumer, Visited);
-
- // Look for properties from which we can synthesize ivars, if
- // permitted.
- if (Result.getSema().getLangOptions().ObjCNonFragileABI2 &&
- IFace->getImplementation() &&
- Result.getLookupKind() == Sema::LookupOrdinaryName) {
- for (ObjCInterfaceDecl::prop_iterator
- P = IFace->prop_begin(),
- PEnd = IFace->prop_end();
- P != PEnd; ++P) {
- if (Result.getSema().canSynthesizeProvisionalIvar(*P) &&
- !IFace->lookupInstanceVariable((*P)->getIdentifier())) {
- Consumer.FoundDecl(*P, Visited.checkHidden(*P), false);
- Visited.add(*P);
- }
- }
- }
+ /*InBaseClass=*/false, Consumer, Visited);
}
}
@@ -3056,7 +3022,7 @@ static const unsigned MaxTypoDistanceResultSets = 5;
class TypoCorrectionConsumer : public VisibleDeclConsumer {
/// \brief The name written that is a typo in the source.
- llvm::StringRef Typo;
+ StringRef Typo;
/// \brief The results found that have the smallest edit distance
/// found (so far) with the typo name.
@@ -3084,11 +3050,12 @@ public:
delete I->second;
}
- virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass);
- void FoundName(llvm::StringRef Name);
- void addKeywordResult(llvm::StringRef Keyword);
- void addName(llvm::StringRef Name, NamedDecl *ND, unsigned Distance,
- NestedNameSpecifier *NNS=NULL);
+ virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
+ bool InBaseClass);
+ void FoundName(StringRef Name);
+ void addKeywordResult(StringRef Keyword);
+ void addName(StringRef Name, NamedDecl *ND, unsigned Distance,
+ NestedNameSpecifier *NNS=NULL, bool isKeyword=false);
void addCorrection(TypoCorrection Correction);
typedef TypoResultsMap::iterator result_iterator;
@@ -3099,7 +3066,7 @@ public:
unsigned size() const { return BestResults.size(); }
bool empty() const { return BestResults.empty(); }
- TypoCorrection &operator[](llvm::StringRef Name) {
+ TypoCorrection &operator[](StringRef Name) {
return (*BestResults.begin()->second)[Name];
}
@@ -3115,7 +3082,7 @@ public:
}
void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
- bool InBaseClass) {
+ DeclContext *Ctx, bool InBaseClass) {
// Don't consider hidden names for typo correction.
if (Hiding)
return;
@@ -3130,7 +3097,7 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
FoundName(Name->getName());
}
-void TypoCorrectionConsumer::FoundName(llvm::StringRef Name) {
+void TypoCorrectionConsumer::FoundName(StringRef Name) {
// Use a simple length-based heuristic to determine the minimum possible
// edit distance. If the minimum isn't good enough, bail out early.
unsigned MinED = abs((int)Name.size() - (int)Typo.size());
@@ -3156,7 +3123,7 @@ void TypoCorrectionConsumer::FoundName(llvm::StringRef Name) {
addName(Name, NULL, ED);
}
-void TypoCorrectionConsumer::addKeywordResult(llvm::StringRef Keyword) {
+void TypoCorrectionConsumer::addKeywordResult(StringRef Keyword) {
// Compute the edit distance between the typo and this keyword.
// If this edit distance is not worse than the best edit
// distance we've seen so far, add it to the list of results.
@@ -3167,19 +3134,21 @@ void TypoCorrectionConsumer::addKeywordResult(llvm::StringRef Keyword) {
return;
}
- addName(Keyword, TypoCorrection::KeywordDecl(), ED);
+ addName(Keyword, NULL, ED, NULL, true);
}
-void TypoCorrectionConsumer::addName(llvm::StringRef Name,
+void TypoCorrectionConsumer::addName(StringRef Name,
NamedDecl *ND,
unsigned Distance,
- NestedNameSpecifier *NNS) {
- addCorrection(TypoCorrection(&SemaRef.Context.Idents.get(Name),
- ND, NNS, Distance));
+ NestedNameSpecifier *NNS,
+ bool isKeyword) {
+ TypoCorrection TC(&SemaRef.Context.Idents.get(Name), ND, NNS, Distance);
+ if (isKeyword) TC.makeKeyword();
+ addCorrection(TC);
}
void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) {
- llvm::StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName();
+ StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName();
TypoResultsMap *& Map = BestResults[Correction.getEditDistance()];
if (!Map)
Map = new TypoResultsMap;
@@ -3213,8 +3182,8 @@ class SpecifierInfo {
: DeclCtx(Ctx), NameSpecifier(NNS), EditDistance(ED) {}
};
-typedef llvm::SmallVector<DeclContext*, 4> DeclContextList;
-typedef llvm::SmallVector<SpecifierInfo, 16> SpecifierInfoList;
+typedef SmallVector<DeclContext*, 4> DeclContextList;
+typedef SmallVector<SpecifierInfo, 16> SpecifierInfoList;
class NamespaceSpecifierSet {
ASTContext &Context;
@@ -3264,14 +3233,14 @@ DeclContextList NamespaceSpecifierSet::BuildContextChain(DeclContext *Start) {
}
void NamespaceSpecifierSet::SortNamespaces() {
- llvm::SmallVector<unsigned, 4> sortedDistances;
+ SmallVector<unsigned, 4> sortedDistances;
sortedDistances.append(Distances.begin(), Distances.end());
if (sortedDistances.size() > 1)
std::sort(sortedDistances.begin(), sortedDistances.end());
Specifiers.clear();
- for (llvm::SmallVector<unsigned, 4>::iterator DI = sortedDistances.begin(),
+ for (SmallVector<unsigned, 4>::iterator DI = sortedDistances.begin(),
DIEnd = sortedDistances.end();
DI != DIEnd; ++DI) {
SpecifierInfoList &SpecList = DistanceMap[*DI];
@@ -3648,7 +3617,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
= Context.Idents.getExternalIdentifierLookup()) {
llvm::OwningPtr<IdentifierIterator> Iter(External->getIdentifiers());
do {
- llvm::StringRef Name = Iter->Next();
+ StringRef Name = Iter->Next();
if (Name.empty())
break;
@@ -3692,7 +3661,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
if (getLangOptions().CPlusPlus) {
// Load any externally-known namespaces.
if (ExternalSource && !LoadedExternalKnownNamespaces) {
- llvm::SmallVector<NamespaceDecl *, 4> ExternalKnownNamespaces;
+ SmallVector<NamespaceDecl *, 4> ExternalKnownNamespaces;
LoadedExternalKnownNamespaces = true;
ExternalSource->ReadKnownNamespaces(ExternalKnownNamespaces);
for (unsigned I = 0, N = ExternalKnownNamespaces.size(); I != N; ++I)
@@ -3730,6 +3699,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
switch (TmpRes.getResultKind()) {
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
+ case LookupResult::FoundUnresolvedValue:
QualifiedResults.insert(Name);
// We didn't find this name in our scope, or didn't like what we found;
// ignore it.
@@ -3745,12 +3715,18 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// We don't deal with ambiguities.
return TypoCorrection();
+ case LookupResult::FoundOverloaded: {
+ // Store all of the Decls for overloaded symbols
+ for (LookupResult::iterator TRD = TmpRes.begin(),
+ TRDEnd = TmpRes.end();
+ TRD != TRDEnd; ++TRD)
+ I->second.addCorrectionDecl(*TRD);
+ ++I;
+ break;
+ }
+
case LookupResult::Found:
- case LookupResult::FoundOverloaded:
- case LookupResult::FoundUnresolvedValue:
I->second.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>());
- // FIXME: This sets the CorrectionDecl to NULL for overloaded functions.
- // It would be nice to find the right one with overload resolution.
++I;
break;
}
@@ -3786,14 +3762,23 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
switch (TmpRes.getResultKind()) {
case LookupResult::Found:
- case LookupResult::FoundOverloaded:
- case LookupResult::FoundUnresolvedValue:
Consumer.addName((*QRI)->getName(), TmpRes.getAsSingle<NamedDecl>(),
QualifiedED, NI->NameSpecifier);
break;
+ case LookupResult::FoundOverloaded: {
+ TypoCorrection corr(&Context.Idents.get((*QRI)->getName()), NULL,
+ NI->NameSpecifier, QualifiedED);
+ for (LookupResult::iterator TRD = TmpRes.begin(),
+ TRDEnd = TmpRes.end();
+ TRD != TRDEnd; ++TRD)
+ corr.addCorrectionDecl(*TRD);
+ Consumer.addCorrection(corr);
+ break;
+ }
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
case LookupResult::Ambiguous:
+ case LookupResult::FoundUnresolvedValue:
break;
}
}
@@ -3870,6 +3855,18 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
return TypoCorrection();
}
+void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) {
+ if (!CDecl) return;
+
+ if (isKeyword())
+ CorrectionDecls.clear();
+
+ CorrectionDecls.push_back(CDecl);
+
+ if (!CorrectionName)
+ CorrectionName = CDecl->getDeclName();
+}
+
std::string TypoCorrection::getAsString(const LangOptions &LO) const {
if (CorrectionNameSpec) {
std::string tmpBuffer;
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index d826ea8d84a4..751f553945cd 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -16,6 +16,7 @@
#include "clang/Sema/Initialization.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/ExprCXX.h"
#include "llvm/ADT/DenseSet.h"
using namespace clang;
@@ -24,6 +25,37 @@ using namespace clang;
// Grammar actions.
//===----------------------------------------------------------------------===//
+/// getImpliedARCOwnership - Given a set of property attributes and a
+/// type, infer an expected lifetime. The type's ownership qualification
+/// is not considered.
+///
+/// Returns OCL_None if the attributes as stated do not imply an ownership.
+/// Never returns OCL_Autoreleasing.
+static Qualifiers::ObjCLifetime getImpliedARCOwnership(
+ ObjCPropertyDecl::PropertyAttributeKind attrs,
+ QualType type) {
+ // retain, strong, copy, weak, and unsafe_unretained are only legal
+ // on properties of retainable pointer type.
+ if (attrs & (ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_strong |
+ ObjCPropertyDecl::OBJC_PR_copy)) {
+ return type->getObjCARCImplicitLifetime();
+ } else if (attrs & ObjCPropertyDecl::OBJC_PR_weak) {
+ return Qualifiers::OCL_Weak;
+ } else if (attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained) {
+ return Qualifiers::OCL_ExplicitNone;
+ }
+
+ // assign can appear on other types, so we have to check the
+ // property type.
+ if (attrs & ObjCPropertyDecl::OBJC_PR_assign &&
+ type->isObjCRetainableType()) {
+ return Qualifiers::OCL_ExplicitNone;
+ }
+
+ return Qualifiers::OCL_None;
+}
+
/// Check the internal consistency of a property declaration.
static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) {
if (property->isInvalidDecl()) return;
@@ -36,26 +68,23 @@ static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) {
// Nothing to do if we don't have a lifetime.
if (propertyLifetime == Qualifiers::OCL_None) return;
- Qualifiers::ObjCLifetime expectedLifetime;
- unsigned selector;
-
- // Strong properties should have either strong or no lifetime.
- if (propertyKind & (ObjCPropertyDecl::OBJC_PR_retain |
- ObjCPropertyDecl::OBJC_PR_strong |
- ObjCPropertyDecl::OBJC_PR_copy)) {
- expectedLifetime = Qualifiers::OCL_Strong;
- selector = 0;
- } else if (propertyKind & ObjCPropertyDecl::OBJC_PR_weak) {
- expectedLifetime = Qualifiers::OCL_Weak;
- selector = 1;
- } else if (propertyKind & (ObjCPropertyDecl::OBJC_PR_assign |
- ObjCPropertyDecl::OBJC_PR_unsafe_unretained) &&
- property->getType()->isObjCRetainableType()) {
- expectedLifetime = Qualifiers::OCL_ExplicitNone;
- selector = 2;
- } else {
+ Qualifiers::ObjCLifetime expectedLifetime
+ = getImpliedARCOwnership(propertyKind, property->getType());
+ if (!expectedLifetime) {
// We have a lifetime qualifier but no dominating property
- // attribute. That's okay.
+ // attribute. That's okay, but restore reasonable invariants by
+ // setting the property attribute according to the lifetime
+ // qualifier.
+ ObjCPropertyDecl::PropertyAttributeKind attr;
+ if (propertyLifetime == Qualifiers::OCL_Strong) {
+ attr = ObjCPropertyDecl::OBJC_PR_strong;
+ } else if (propertyLifetime == Qualifiers::OCL_Weak) {
+ attr = ObjCPropertyDecl::OBJC_PR_weak;
+ } else {
+ assert(propertyLifetime == Qualifiers::OCL_ExplicitNone);
+ attr = ObjCPropertyDecl::OBJC_PR_unsafe_unretained;
+ }
+ property->setPropertyAttributes(attr);
return;
}
@@ -65,7 +94,7 @@ static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) {
S.Diag(property->getLocation(),
diag::err_arc_inconsistent_property_ownership)
<< property->getDeclName()
- << selector
+ << expectedLifetime
<< propertyLifetime;
}
@@ -74,14 +103,13 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
ObjCDeclSpec &ODS,
Selector GetterSel,
Selector SetterSel,
- Decl *ClassCategory,
bool *isOverridingProperty,
tok::ObjCKeywordKind MethodImplKind,
DeclContext *lexicalDC) {
unsigned Attributes = ODS.getPropertyAttributes();
TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S);
QualType T = TSI->getType();
- if ((getLangOptions().getGCMode() != LangOptions::NonGC &&
+ if ((getLangOptions().getGC() != LangOptions::NonGC &&
T.isObjCGCWeak()) ||
(getLangOptions().ObjCAutoRefCount &&
T.getObjCLifetime() == Qualifiers::OCL_Weak))
@@ -101,12 +129,11 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
!(Attributes & ObjCDeclSpec::DQ_PR_weak)));
// Proceed with constructing the ObjCPropertDecls.
- ObjCContainerDecl *ClassDecl =
- cast<ObjCContainerDecl>(ClassCategory);
+ ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(CurContext);
if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl))
if (CDecl->IsClassExtension()) {
- Decl *Res = HandlePropertyInClassExtension(S, CDecl, AtLoc,
+ Decl *Res = HandlePropertyInClassExtension(S, AtLoc,
FD, GetterSel, SetterSel,
isAssign, isReadWrite,
Attributes,
@@ -137,7 +164,7 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
}
Decl *
-Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl,
+Sema::HandlePropertyInClassExtension(Scope *S,
SourceLocation AtLoc, FieldDeclarator &FD,
Selector GetterSel, Selector SetterSel,
const bool isAssign,
@@ -146,9 +173,9 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl,
bool *isOverridingProperty,
TypeSourceInfo *T,
tok::ObjCKeywordKind MethodImplKind) {
-
+ ObjCCategoryDecl *CDecl = cast<ObjCCategoryDecl>(CurContext);
// Diagnose if this property is already in continuation class.
- DeclContext *DC = cast<DeclContext>(CDecl);
+ DeclContext *DC = CurContext;
IdentifierInfo *PropertyId = FD.D.getIdentifier();
ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface();
@@ -209,7 +236,13 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl,
/* lexicalDC = */ CDecl);
return PDecl;
}
-
+ if (PIDecl->getType().getCanonicalType()
+ != PDecl->getType().getCanonicalType()) {
+ Diag(AtLoc,
+ diag::warn_type_mismatch_continuation_class) << PDecl->getType();
+ Diag(PIDecl->getLocation(), diag::note_property_declare);
+ }
+
// The property 'PIDecl's readonly attribute will be over-ridden
// with continuation class's readwrite property attribute!
unsigned PIkind = PIDecl->getPropertyAttributesAsWritten();
@@ -235,12 +268,15 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl,
ProtocolPropertyODS.
setPropertyAttributes((ObjCDeclSpec::ObjCPropertyAttributeKind)
PIkind);
-
+ // Must re-establish the context from class extension to primary
+ // class context.
+ ContextRAII SavedContext(*this, CCPrimary);
+
Decl *ProtocolPtrTy =
ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS,
PIDecl->getGetterName(),
PIDecl->getSetterName(),
- CCPrimary, isOverridingProperty,
+ isOverridingProperty,
MethodImplKind,
/* lexicalDC = */ CDecl);
PIDecl = cast<ObjCPropertyDecl>(ProtocolPtrTy);
@@ -290,7 +326,7 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
// Issue a warning if property is 'assign' as default and its object, which is
// gc'able conforms to NSCopying protocol
- if (getLangOptions().getGCMode() != LangOptions::NonGC &&
+ if (getLangOptions().getGC() != LangOptions::NonGC &&
isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign))
if (const ObjCObjectPointerType *ObjPtrTy =
T->getAs<ObjCObjectPointerType>()) {
@@ -392,9 +428,10 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
if (isAssign)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
+ // In the semantic attributes, one of nonatomic or atomic is always set.
if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic);
- else if (Attributes & ObjCDeclSpec::DQ_PR_atomic)
+ else
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic);
// 'unsafe_unretained' is alias for 'assign'.
@@ -416,82 +453,49 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,
ObjCIvarDecl *ivar) {
if (property->isInvalidDecl() || ivar->isInvalidDecl()) return;
- QualType propertyType = property->getType();
- Qualifiers::ObjCLifetime propertyLifetime = propertyType.getObjCLifetime();
- ObjCPropertyDecl::PropertyAttributeKind propertyKind
- = property->getPropertyAttributes();
-
QualType ivarType = ivar->getType();
Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime();
-
- // Case 1: strong properties.
- if (propertyLifetime == Qualifiers::OCL_Strong ||
- (propertyKind & (ObjCPropertyDecl::OBJC_PR_retain |
- ObjCPropertyDecl::OBJC_PR_strong |
- ObjCPropertyDecl::OBJC_PR_copy))) {
- switch (ivarLifetime) {
- case Qualifiers::OCL_Strong:
- // Okay.
- return;
-
- case Qualifiers::OCL_None:
- case Qualifiers::OCL_Autoreleasing:
- // These aren't valid lifetimes for object ivars; don't diagnose twice.
- return;
-
- case Qualifiers::OCL_ExplicitNone:
- case Qualifiers::OCL_Weak:
- S.Diag(propertyImplLoc, diag::err_arc_strong_property_ownership)
- << property->getDeclName()
- << ivar->getDeclName()
- << ivarLifetime;
- break;
- }
- // Case 2: weak properties.
- } else if (propertyLifetime == Qualifiers::OCL_Weak ||
- (propertyKind & ObjCPropertyDecl::OBJC_PR_weak)) {
- switch (ivarLifetime) {
- case Qualifiers::OCL_Weak:
- // Okay.
- return;
-
- case Qualifiers::OCL_None:
- case Qualifiers::OCL_Autoreleasing:
- // These aren't valid lifetimes for object ivars; don't diagnose twice.
- return;
-
- case Qualifiers::OCL_ExplicitNone:
- case Qualifiers::OCL_Strong:
- S.Diag(propertyImplLoc, diag::error_weak_property)
- << property->getDeclName()
- << ivar->getDeclName();
- break;
- }
+ // The lifetime implied by the property's attributes.
+ Qualifiers::ObjCLifetime propertyLifetime =
+ getImpliedARCOwnership(property->getPropertyAttributes(),
+ property->getType());
- // Case 3: assign properties.
- } else if ((propertyKind & ObjCPropertyDecl::OBJC_PR_assign) &&
- propertyType->isObjCRetainableType()) {
- switch (ivarLifetime) {
- case Qualifiers::OCL_ExplicitNone:
- // Okay.
- return;
-
- case Qualifiers::OCL_None:
- case Qualifiers::OCL_Autoreleasing:
- // These aren't valid lifetimes for object ivars; don't diagnose twice.
- return;
-
- case Qualifiers::OCL_Weak:
- case Qualifiers::OCL_Strong:
- S.Diag(propertyImplLoc, diag::err_arc_assign_property_ownership)
- << property->getDeclName()
- << ivar->getDeclName();
- break;
- }
+ // We're fine if they match.
+ if (propertyLifetime == ivarLifetime) return;
- // Any other property should be ignored.
- } else {
+ // These aren't valid lifetimes for object ivars; don't diagnose twice.
+ if (ivarLifetime == Qualifiers::OCL_None ||
+ ivarLifetime == Qualifiers::OCL_Autoreleasing)
+ return;
+
+ switch (propertyLifetime) {
+ case Qualifiers::OCL_Strong:
+ S.Diag(propertyImplLoc, diag::err_arc_strong_property_ownership)
+ << property->getDeclName()
+ << ivar->getDeclName()
+ << ivarLifetime;
+ break;
+
+ case Qualifiers::OCL_Weak:
+ S.Diag(propertyImplLoc, diag::error_weak_property)
+ << property->getDeclName()
+ << ivar->getDeclName();
+ break;
+
+ case Qualifiers::OCL_ExplicitNone:
+ S.Diag(propertyImplLoc, diag::err_arc_assign_property_ownership)
+ << property->getDeclName()
+ << ivar->getDeclName()
+ << ((property->getPropertyAttributesAsWritten()
+ & ObjCPropertyDecl::OBJC_PR_assign) != 0);
+ break;
+
+ case Qualifiers::OCL_Autoreleasing:
+ llvm_unreachable("properties cannot be autoreleasing");
+
+ case Qualifiers::OCL_None:
+ // Any other property should be ignored.
return;
}
@@ -507,12 +511,11 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
SourceLocation AtLoc,
SourceLocation PropertyLoc,
bool Synthesize,
- Decl *ClassCatImpDecl,
IdentifierInfo *PropertyId,
IdentifierInfo *PropertyIvar,
SourceLocation PropertyIvarLoc) {
ObjCContainerDecl *ClassImpDecl =
- cast_or_null<ObjCContainerDecl>(ClassCatImpDecl);
+ dyn_cast<ObjCContainerDecl>(CurContext);
// Make sure we have a context for the property implementation declaration.
if (!ClassImpDecl) {
Diag(AtLoc, diag::error_missing_property_context);
@@ -586,61 +589,65 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
ObjCIvarDecl *Ivar = 0;
// Check that we have a valid, previously declared ivar for @synthesize
if (Synthesize) {
- if (getLangOptions().ObjCAutoRefCount &&
- !property->hasWrittenStorageAttribute() &&
- property->getType()->isObjCRetainableType()) {
- Diag(PropertyLoc, diag::err_arc_objc_property_default_assign_on_object);
- Diag(property->getLocation(), diag::note_property_declare);
- }
-
// @synthesize
if (!PropertyIvar)
PropertyIvar = PropertyId;
ObjCPropertyDecl::PropertyAttributeKind kind
= property->getPropertyAttributes();
- QualType PropType = Context.getCanonicalType(property->getType());
- QualType PropertyIvarType = PropType;
- if (PropType->isReferenceType())
- PropertyIvarType = cast<ReferenceType>(PropType)->getPointeeType();
+ QualType PropType = property->getType();
+
+ QualType PropertyIvarType = PropType.getNonReferenceType();
+
+ // Add GC __weak to the ivar type if the property is weak.
+ if ((kind & ObjCPropertyDecl::OBJC_PR_weak) &&
+ getLangOptions().getGC() != LangOptions::NonGC) {
+ assert(!getLangOptions().ObjCAutoRefCount);
+ if (PropertyIvarType.isObjCGCStrong()) {
+ Diag(PropertyLoc, diag::err_gc_weak_property_strong_type);
+ Diag(property->getLocation(), diag::note_property_declare);
+ } else {
+ PropertyIvarType =
+ Context.getObjCGCQualType(PropertyIvarType, Qualifiers::Weak);
+ }
+ }
+
// Check that this is a previously declared 'ivar' in 'IDecl' interface
ObjCInterfaceDecl *ClassDeclared;
Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
if (!Ivar) {
- // In ARC, give the ivar a lifetime qualifier based on its
+ // In ARC, give the ivar a lifetime qualifier based on the
// property attributes.
if (getLangOptions().ObjCAutoRefCount &&
- !PropertyIvarType.getObjCLifetime()) {
-
- // retain/copy have retaining lifetime.
- if (kind & (ObjCPropertyDecl::OBJC_PR_retain |
- ObjCPropertyDecl::OBJC_PR_strong |
- ObjCPropertyDecl::OBJC_PR_copy)) {
- Qualifiers qs;
- qs.addObjCLifetime(Qualifiers::OCL_Strong);
- PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs);
- }
- else if (kind & ObjCPropertyDecl::OBJC_PR_weak) {
- if (!getLangOptions().ObjCRuntimeHasWeak) {
+ !PropertyIvarType.getObjCLifetime() &&
+ PropertyIvarType->isObjCRetainableType()) {
+
+ // It's an error if we have to do this and the user didn't
+ // explicitly write an ownership attribute on the property.
+ if (!property->hasWrittenStorageAttribute() &&
+ !(kind & ObjCPropertyDecl::OBJC_PR_strong)) {
+ Diag(PropertyLoc,
+ diag::err_arc_objc_property_default_assign_on_object);
+ Diag(property->getLocation(), diag::note_property_declare);
+ } else {
+ Qualifiers::ObjCLifetime lifetime =
+ getImpliedARCOwnership(kind, PropertyIvarType);
+ assert(lifetime && "no lifetime for property?");
+
+ if (lifetime == Qualifiers::OCL_Weak &&
+ !getLangOptions().ObjCRuntimeHasWeak) {
Diag(PropertyLoc, diag::err_arc_weak_no_runtime);
Diag(property->getLocation(), diag::note_property_declare);
}
+
Qualifiers qs;
- qs.addObjCLifetime(Qualifiers::OCL_Weak);
+ qs.addObjCLifetime(lifetime);
PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs);
}
- else if (kind & ObjCPropertyDecl::OBJC_PR_assign &&
- PropertyIvarType->isObjCRetainableType()) {
- // assume that an 'assign' property synthesizes __unsafe_unretained
- // ivar
- Qualifiers qs;
- qs.addObjCLifetime(Qualifiers::OCL_ExplicitNone);
- PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs);
- }
}
if (kind & ObjCPropertyDecl::OBJC_PR_weak &&
!getLangOptions().ObjCAutoRefCount &&
- getLangOptions().getGCMode() == LangOptions::NonGC) {
+ getLangOptions().getGC() == LangOptions::NonGC) {
Diag(PropertyLoc, diag::error_synthesize_weak_non_arc_or_gc);
Diag(property->getLocation(), diag::note_property_declare);
}
@@ -670,7 +677,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
QualType IvarType = Context.getCanonicalType(Ivar->getType());
// Check that type of property and its ivar are type compatible.
- if (PropertyIvarType != IvarType) {
+ if (Context.getCanonicalType(PropertyIvarType) != IvarType) {
bool compat = false;
if (isa<ObjCObjectPointerType>(PropertyIvarType)
&& isa<ObjCObjectPointerType>(IvarType))
@@ -709,15 +716,16 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
}
// __weak is explicit. So it works on Canonical type.
if ((PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&
- getLangOptions().getGCMode() != LangOptions::NonGC)) {
+ getLangOptions().getGC() != LangOptions::NonGC)) {
Diag(PropertyLoc, diag::error_weak_property)
<< property->getDeclName() << Ivar->getDeclName();
+ Diag(Ivar->getLocation(), diag::note_ivar_decl);
// Fall thru - see previous comment
}
// Fall thru - see previous comment
if ((property->getType()->isObjCObjectPointerType() ||
PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
- getLangOptions().getGCMode() != LangOptions::NonGC) {
+ getLangOptions().getGC() != LangOptions::NonGC) {
Diag(PropertyLoc, diag::error_strong_property)
<< property->getDeclName() << Ivar->getDeclName();
// Fall thru - see previous comment
@@ -793,6 +801,17 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
VK_LValue, SourceLocation());
ExprResult Res = BuildBinOp(S, lhs->getLocEnd(),
BO_Assign, lhs, rhs);
+ if (property->getPropertyAttributes() &
+ ObjCPropertyDecl::OBJC_PR_atomic) {
+ Expr *callExpr = Res.takeAs<Expr>();
+ if (const CXXOperatorCallExpr *CXXCE =
+ dyn_cast_or_null<CXXOperatorCallExpr>(callExpr))
+ if (const FunctionDecl *FuncDecl = CXXCE->getDirectCallee())
+ if (!FuncDecl->isTrivial())
+ Diag(PropertyLoc,
+ diag::warn_atomic_property_nontrivial_assign_op)
+ << property->getType();
+ }
PIDecl->setSetterCXXAssignment(Res.takeAs<Expr>());
}
}
@@ -880,7 +899,7 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
!= (SAttr & ObjCPropertyDecl::OBJC_PR_copy))
Diag(Property->getLocation(), diag::warn_property_attribute)
<< Property->getDeclName() << "copy" << inheritedName;
- else {
+ else if (!(SAttr & ObjCPropertyDecl::OBJC_PR_readonly)){
unsigned CAttrRetain =
(CAttr &
(ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong));
@@ -917,9 +936,11 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
QualType ConvertedType;
if (!isObjCPointerConversion(RHSType, LHSType,
ConvertedType, IncompatibleObjC) ||
- IncompatibleObjC)
+ IncompatibleObjC) {
Diag(Property->getLocation(), diag::warn_property_types_are_incompatible)
<< Property->getType() << SuperProperty->getType() << inheritedName;
+ Diag(SuperProperty->getLocation(), diag::note_property_declare);
+ }
}
}
@@ -1146,7 +1167,8 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
ObjCPropertyDecl *PropertyFromSuper = SuperPropMap[Prop->getIdentifier()];
// Exclude property for protocols which conform to class's super-class,
// as super-class has to implement the property.
- if (!PropertyFromSuper || PropertyFromSuper != Prop) {
+ if (!PropertyFromSuper ||
+ PropertyFromSuper->getIdentifier() != Prop->getIdentifier()) {
ObjCPropertyDecl *&PropEntry = PropMap[Prop->getIdentifier()];
if (!PropEntry)
PropEntry = Prop;
@@ -1241,10 +1263,20 @@ ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl,
return 0;
}
+static IdentifierInfo * getDefaultSynthIvarName(ObjCPropertyDecl *Prop,
+ ASTContext &Ctx) {
+ llvm::SmallString<128> ivarName;
+ {
+ llvm::raw_svector_ostream os(ivarName);
+ os << '_' << Prop->getIdentifier()->getName();
+ }
+ return &Ctx.Idents.get(ivarName.str());
+}
+
/// DefaultSynthesizeProperties - This routine default synthesizes all
/// properties which must be synthesized in class's @implementation.
-void Sema::DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl,
- ObjCInterfaceDecl *IDecl) {
+void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
+ ObjCInterfaceDecl *IDecl) {
llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap;
CollectClassPropertyImplementations(IDecl, PropMap);
@@ -1280,12 +1312,23 @@ void Sema::DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl,
// Saying that they are located at the @implementation isn't really going
// to help users.
ActOnPropertyImplDecl(S, SourceLocation(), SourceLocation(),
- true,IMPDecl,
- Prop->getIdentifier(), Prop->getIdentifier(),
+ true,
+ /* property = */ Prop->getIdentifier(),
+ /* ivar = */ getDefaultSynthIvarName(Prop, Context),
SourceLocation());
}
}
+void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) {
+ if (!LangOpts.ObjCDefaultSynthProperties || !LangOpts.ObjCNonFragileABI2)
+ return;
+ ObjCImplementationDecl *IC=dyn_cast_or_null<ObjCImplementationDecl>(D);
+ if (!IC)
+ return;
+ if (ObjCInterfaceDecl* IDecl = IC->getClassInterface())
+ DefaultSynthesizeProperties(S, IC, IDecl);
+}
+
void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl *CDecl,
const llvm::DenseSet<Selector>& InsMap) {
@@ -1313,23 +1356,23 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
PropImplMap.count(Prop) || Prop->hasAttr<UnavailableAttr>())
continue;
if (!InsMap.count(Prop->getGetterName())) {
- Diag(Prop->getLocation(),
+ Diag(IMPDecl->getLocation(),
isa<ObjCCategoryDecl>(CDecl) ?
diag::warn_setter_getter_impl_required_in_category :
diag::warn_setter_getter_impl_required)
<< Prop->getDeclName() << Prop->getGetterName();
- Diag(IMPDecl->getLocation(),
- diag::note_property_impl_required);
+ Diag(Prop->getLocation(),
+ diag::note_property_declare);
}
if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) {
- Diag(Prop->getLocation(),
+ Diag(IMPDecl->getLocation(),
isa<ObjCCategoryDecl>(CDecl) ?
diag::warn_setter_getter_impl_required_in_category :
diag::warn_setter_getter_impl_required)
<< Prop->getDeclName() << Prop->getSetterName();
- Diag(IMPDecl->getLocation(),
- diag::note_property_impl_required);
+ Diag(Prop->getLocation(),
+ diag::note_property_declare);
}
}
}
@@ -1338,7 +1381,7 @@ void
Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
ObjCContainerDecl* IDecl) {
// Rules apply in non-GC mode only
- if (getLangOptions().getGCMode() != LangOptions::NonGC)
+ if (getLangOptions().getGC() != LangOptions::NonGC)
return;
for (ObjCContainerDecl::prop_iterator I = IDecl->prop_begin(),
E = IDecl->prop_end();
@@ -1349,10 +1392,10 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
bool LookedUpGetterSetter = false;
unsigned Attributes = Property->getPropertyAttributes();
- unsigned AttributesAsWrittern = Property->getPropertyAttributesAsWritten();
+ unsigned AttributesAsWritten = Property->getPropertyAttributesAsWritten();
- if (!(AttributesAsWrittern & ObjCPropertyDecl::OBJC_PR_atomic) &&
- !(AttributesAsWrittern & ObjCPropertyDecl::OBJC_PR_nonatomic)) {
+ if (!(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_atomic) &&
+ !(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_nonatomic)) {
GetterMethod = IMPDecl->getInstanceMethod(Property->getGetterName());
SetterMethod = IMPDecl->getInstanceMethod(Property->getSetterName());
LookedUpGetterSetter = true;
@@ -1388,7 +1431,9 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
(GetterMethod ? GetterMethod->getLocation()
: SetterMethod->getLocation());
Diag(MethodLoc, diag::warn_atomic_property_rule)
- << Property->getIdentifier();
+ << Property->getIdentifier() << (GetterMethod != 0)
+ << (SetterMethod != 0);
+ Diag(MethodLoc, diag::note_atomic_property_fixup_suggest);
Diag(Property->getLocation(), diag::note_property_declare);
}
}
@@ -1396,7 +1441,7 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
}
void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D) {
- if (getLangOptions().getGCMode() == LangOptions::GCOnly)
+ if (getLangOptions().getGC() == LangOptions::GCOnly)
return;
for (ObjCImplementationDecl::propimpl_iterator
@@ -1417,7 +1462,7 @@ void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D
if (getLangOptions().ObjCAutoRefCount)
Diag(PID->getLocation(), diag::err_ownin_getter_rule);
else
- Diag(PID->getLocation(), diag::warn_ownin_getter_rule);
+ Diag(PID->getLocation(), diag::warn_owning_getter_rule);
Diag(PD->getLocation(), diag::note_property_declare);
}
}
@@ -1464,7 +1509,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
Context.VoidTy)
Diag(SetterMethod->getLocation(), diag::err_setter_type_void);
if (SetterMethod->param_size() != 1 ||
- ((*SetterMethod->param_begin())->getType() != property->getType())) {
+ !Context.hasSameUnqualifiedType(
+ (*SetterMethod->param_begin())->getType(), property->getType())) {
Diag(property->getLocation(),
diag::warn_accessor_property_type_mismatch)
<< property->getDeclName()
@@ -1489,8 +1535,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
GetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc,
property->getGetterName(),
- property->getType(), 0, CD, true, false, true,
- false,
+ property->getType(), 0, CD, /*isInstance=*/true,
+ /*isVariadic=*/false, /*isSynthesized=*/true,
+ /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
(property->getPropertyImplementation() ==
ObjCPropertyDecl::Optional) ?
ObjCMethodDecl::Optional :
@@ -1526,7 +1573,10 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
SetterMethod =
ObjCMethodDecl::Create(Context, Loc, Loc,
property->getSetterName(), Context.VoidTy, 0,
- CD, true, false, true, false,
+ CD, /*isInstance=*/true, /*isVariadic=*/false,
+ /*isSynthesized=*/true,
+ /*isImplicitlyDeclared=*/true,
+ /*isDefined=*/false,
(property->getPropertyImplementation() ==
ObjCPropertyDecl::Optional) ?
ObjCMethodDecl::Optional :
@@ -1542,7 +1592,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
SC_None,
SC_None,
0);
- SetterMethod->setMethodParams(Context, &Argument, 1, 1);
+ SetterMethod->setMethodParams(Context, Argument,
+ ArrayRef<SourceLocation>());
AddPropertyAttrs(*this, SetterMethod, property);
@@ -1686,7 +1737,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
(Attributes & ObjCDeclSpec::DQ_PR_weak)) {
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "retain" << "weak";
- Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
+ Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
}
else if ((Attributes & ObjCDeclSpec::DQ_PR_strong) &&
(Attributes & ObjCDeclSpec::DQ_PR_weak)) {
@@ -1695,6 +1746,13 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
}
+ if ((Attributes & ObjCDeclSpec::DQ_PR_atomic) &&
+ (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "atomic" << "nonatomic";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_atomic;
+ }
+
// Warn if user supplied no assignment attribute, property is
// readwrite, and this is an object type.
if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy |
@@ -1703,13 +1761,19 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
ObjCDeclSpec::DQ_PR_weak)) &&
!(Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
PropertyTy->isObjCObjectPointerType()) {
- // Skip this warning in gc-only mode.
- if (getLangOptions().getGCMode() != LangOptions::GCOnly)
- Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
+ if (getLangOptions().ObjCAutoRefCount)
+ // With arc, @property definitions should default to (strong) when
+ // not specified
+ PropertyDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
+ else {
+ // Skip this warning in gc-only mode.
+ if (getLangOptions().getGC() != LangOptions::GCOnly)
+ Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
- // If non-gc code warn that this is likely inappropriate.
- if (getLangOptions().getGCMode() == LangOptions::NonGC)
- Diag(Loc, diag::warn_objc_property_default_assign_on_object);
+ // If non-gc code warn that this is likely inappropriate.
+ if (getLangOptions().getGC() == LangOptions::NonGC)
+ Diag(Loc, diag::warn_objc_property_default_assign_on_object);
+ }
// FIXME: Implement warning dependent on NSCopying being
// implemented. See also:
@@ -1719,7 +1783,13 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
if (!(Attributes & ObjCDeclSpec::DQ_PR_copy)
&&!(Attributes & ObjCDeclSpec::DQ_PR_readonly)
- && getLangOptions().getGCMode() == LangOptions::GCOnly
+ && getLangOptions().getGC() == LangOptions::GCOnly
&& PropertyTy->isBlockPointerType())
Diag(Loc, diag::warn_objc_property_copy_missing_on_block);
+ else if (getLangOptions().ObjCAutoRefCount &&
+ (Attributes & ObjCDeclSpec::DQ_PR_retain) &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_strong) &&
+ PropertyTy->isBlockPointerType())
+ Diag(Loc, diag::warn_objc_property_retain_of_block);
}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 437b2b5c6d43..b0dd5e280ebd 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -37,11 +37,14 @@ using namespace sema;
/// A convenience routine for creating a decayed reference to a
/// function.
static ExprResult
-CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn,
+CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, bool HadMultipleCandidates,
SourceLocation Loc = SourceLocation(),
const DeclarationNameLoc &LocInfo = DeclarationNameLoc()){
- ExprResult E = S.Owned(new (S.Context) DeclRefExpr(Fn, Fn->getType(),
- VK_LValue, Loc, LocInfo));
+ DeclRefExpr *DRE = new (S.Context) DeclRefExpr(Fn, Fn->getType(),
+ VK_LValue, Loc, LocInfo);
+ if (HadMultipleCandidates)
+ DRE->setHadMultipleCandidates(true);
+ ExprResult E = S.Owned(DRE);
E = S.DefaultFunctionArrayConversion(E.take());
if (E.isInvalid())
return ExprError();
@@ -258,7 +261,7 @@ isPointerConversionToVoidPointer(ASTContext& Context) const {
/// DebugPrint - Print this standard conversion sequence to standard
/// error. Useful for debugging overloading issues.
void StandardConversionSequence::DebugPrint() const {
- llvm::raw_ostream &OS = llvm::errs();
+ raw_ostream &OS = llvm::errs();
bool PrintedSomething = false;
if (First != ICK_Identity) {
OS << GetImplicitConversionName(First);
@@ -297,12 +300,12 @@ void StandardConversionSequence::DebugPrint() const {
/// DebugPrint - Print this user-defined conversion sequence to standard
/// error. Useful for debugging overloading issues.
void UserDefinedConversionSequence::DebugPrint() const {
- llvm::raw_ostream &OS = llvm::errs();
+ raw_ostream &OS = llvm::errs();
if (Before.First || Before.Second || Before.Third) {
Before.DebugPrint();
OS << " -> ";
}
- OS << '\'' << ConversionFunction << '\'';
+ OS << '\'' << *ConversionFunction << '\'';
if (After.First || After.Second || After.Third) {
OS << " -> ";
After.DebugPrint();
@@ -312,7 +315,7 @@ void UserDefinedConversionSequence::DebugPrint() const {
/// DebugPrint - Print this implicit conversion sequence to standard
/// error. Useful for debugging overloading issues.
void ImplicitConversionSequence::DebugPrint() const {
- llvm::raw_ostream &OS = llvm::errs();
+ raw_ostream &OS = llvm::errs();
switch (ConversionKind) {
case StandardConversion:
OS << "Standard conversion: ";
@@ -909,20 +912,22 @@ Sema::TryImplicitConversion(Expr *From, QualType ToType,
/// explicit user-defined conversions are permitted.
ExprResult
Sema::PerformImplicitConversion(Expr *From, QualType ToType,
- AssignmentAction Action, bool AllowExplicit) {
+ AssignmentAction Action, bool AllowExplicit,
+ bool Diagnose) {
ImplicitConversionSequence ICS;
- return PerformImplicitConversion(From, ToType, Action, AllowExplicit, ICS);
+ return PerformImplicitConversion(From, ToType, Action, AllowExplicit, ICS,
+ Diagnose);
}
ExprResult
Sema::PerformImplicitConversion(Expr *From, QualType ToType,
AssignmentAction Action, bool AllowExplicit,
- ImplicitConversionSequence& ICS) {
+ ImplicitConversionSequence& ICS,
+ bool Diagnose) {
// Objective-C ARC: Determine whether we will allow the writeback conversion.
bool AllowObjCWritebackConversion
= getLangOptions().ObjCAutoRefCount &&
(Action == AA_Passing || Action == AA_Sending);
-
ICS = clang::TryImplicitConversion(*this, From, ToType,
/*SuppressUserConversions=*/false,
@@ -930,6 +935,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
/*InOverloadResolution=*/false,
/*CStyle=*/false,
AllowObjCWritebackConversion);
+ if (!Diagnose && ICS.isFailure())
+ return ExprError();
return PerformImplicitConversion(From, ToType, ICS, Action);
}
@@ -1113,10 +1120,10 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
return false;
}
}
- // Lvalue-to-rvalue conversion (C++ 4.1):
- // An lvalue (3.10) of a non-function, non-array type T can be
- // converted to an rvalue.
- bool argIsLValue = From->isLValue();
+ // Lvalue-to-rvalue conversion (C++11 4.1):
+ // A glvalue (3.10) of a non-function, non-array type T can
+ // be converted to a prvalue.
+ bool argIsLValue = From->isGLValue();
if (argIsLValue &&
!FromType->isFunctionType() && !FromType->isArrayType() &&
S.Context.getCanonicalType(FromType) != S.Context.OverloadTy) {
@@ -1392,12 +1399,9 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
ToType->isIntegerType()) {
// Determine whether the type we're converting from is signed or
// unsigned.
- bool FromIsSigned;
+ bool FromIsSigned = FromType->isSignedIntegerType();
uint64_t FromSize = Context.getTypeSize(FromType);
- // FIXME: Is wchar_t signed or unsigned? We assume it's signed for now.
- FromIsSigned = true;
-
// The types we'll try to promote to, in the appropriate
// order. Try each of these types.
QualType PromoteTypes[6] = {
@@ -1465,10 +1469,10 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
/// FromType to ToType is a floating point promotion (C++ 4.6). If so,
/// returns true and sets PromotedType to the promoted type.
bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) {
- /// An rvalue of type float can be converted to an rvalue of type
- /// double. (C++ 4.6p1).
if (const BuiltinType *FromBuiltin = FromType->getAs<BuiltinType>())
if (const BuiltinType *ToBuiltin = ToType->getAs<BuiltinType>()) {
+ /// An rvalue of type float can be converted to an rvalue of type
+ /// double. (C++ 4.6p1).
if (FromBuiltin->getKind() == BuiltinType::Float &&
ToBuiltin->getKind() == BuiltinType::Double)
return true;
@@ -1481,6 +1485,11 @@ bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) {
FromBuiltin->getKind() == BuiltinType::Double) &&
(ToBuiltin->getKind() == BuiltinType::LongDouble))
return true;
+
+ // Half can be promoted to float.
+ if (FromBuiltin->getKind() == BuiltinType::Half &&
+ ToBuiltin->getKind() == BuiltinType::Float)
+ return true;
}
return false;
@@ -1668,7 +1677,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
}
// MSVC allows implicit function to void* type conversion.
- if (getLangOptions().Microsoft && FromPointeeType->isFunctionType() &&
+ if (getLangOptions().MicrosoftExt && FromPointeeType->isFunctionType() &&
ToPointeeType->isVoidType()) {
ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
ToPointeeType,
@@ -2073,6 +2082,11 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
// Argument types are too different. Abort.
return false;
}
+ if (LangOpts.ObjCAutoRefCount &&
+ !Context.FunctionTypesMatchOnNSConsumedAttrs(FromFunctionType,
+ ToFunctionType))
+ return false;
+
ConvertedType = ToType;
return true;
}
@@ -2136,8 +2150,8 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
PDiag(diag::warn_impcast_bool_to_null_pointer)
<< ToType << From->getSourceRange());
- if (const PointerType *FromPtrType = FromType->getAs<PointerType>())
- if (const PointerType *ToPtrType = ToType->getAs<PointerType>()) {
+ if (const PointerType *ToPtrType = ToType->getAs<PointerType>()) {
+ if (const PointerType *FromPtrType = FromType->getAs<PointerType>()) {
QualType FromPointeeType = FromPtrType->getPointeeType(),
ToPointeeType = ToPtrType->getPointeeType();
@@ -2155,16 +2169,23 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
Kind = CK_DerivedToBase;
}
}
- if (const ObjCObjectPointerType *FromPtrType =
- FromType->getAs<ObjCObjectPointerType>()) {
- if (const ObjCObjectPointerType *ToPtrType =
- ToType->getAs<ObjCObjectPointerType>()) {
+ } else if (const ObjCObjectPointerType *ToPtrType =
+ ToType->getAs<ObjCObjectPointerType>()) {
+ if (const ObjCObjectPointerType *FromPtrType =
+ FromType->getAs<ObjCObjectPointerType>()) {
// Objective-C++ conversions are always okay.
// FIXME: We should have a different class of conversions for the
// Objective-C++ implicit conversions.
if (FromPtrType->isObjCBuiltinType() || ToPtrType->isObjCBuiltinType())
return false;
+ } else if (FromType->isBlockPointerType()) {
+ Kind = CK_BlockPointerToObjCPointerCast;
+ } else {
+ Kind = CK_CPointerToObjCPointerCast;
}
+ } else if (ToType->isBlockPointerType()) {
+ if (!FromType->isBlockPointerType())
+ Kind = CK_AnyPointerToBlockPointerCast;
}
// We shouldn't fall into this case unless it's valid for other
@@ -2483,6 +2504,8 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
}
}
+ bool HadMultipleCandidates = (CandidateSet.size() > 1);
+
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(S, From->getLocStart(), Best, true)) {
case OR_Success:
@@ -2504,8 +2527,9 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
User.Before = Best->Conversions[0].Standard;
User.EllipsisConversion = false;
}
+ User.HadMultipleCandidates = HadMultipleCandidates;
User.ConversionFunction = Constructor;
- User.FoundConversionFunction = Best->FoundDecl.getDecl();
+ User.FoundConversionFunction = Best->FoundDecl;
User.After.setAsIdentityConversion();
User.After.setFromType(ThisType->getAs<PointerType>()->getPointeeType());
User.After.setAllToTypes(ToType);
@@ -2521,8 +2545,9 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
// conversion sequence converts the source type to the
// implicit object parameter of the conversion function.
User.Before = Best->Conversions[0].Standard;
+ User.HadMultipleCandidates = HadMultipleCandidates;
User.ConversionFunction = Conversion;
- User.FoundConversionFunction = Best->FoundDecl.getDecl();
+ User.FoundConversionFunction = Best->FoundDecl;
User.EllipsisConversion = false;
// C++ [over.ics.user]p2:
@@ -2862,6 +2887,25 @@ CompareStandardConversionSequences(Sema &S,
}
}
+ // In Microsoft mode, prefer an integral conversion to a
+ // floating-to-integral conversion if the integral conversion
+ // is between types of the same size.
+ // For example:
+ // void f(float);
+ // void f(int);
+ // int main {
+ // long a;
+ // f(a);
+ // }
+ // Here, MSVC will call f(int) instead of generating a compile error
+ // as clang will do in standard mode.
+ if (S.getLangOptions().MicrosoftMode &&
+ SCS1.Second == ICK_Integral_Conversion &&
+ SCS2.Second == ICK_Floating_Integral &&
+ S.Context.getTypeSize(SCS1.getFromType()) ==
+ S.Context.getTypeSize(SCS1.getToType(2)))
+ return ImplicitConversionSequence::Better;
+
return ImplicitConversionSequence::Indistinguishable;
}
@@ -3292,6 +3336,16 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
bool DerivedToBase = false;
bool ObjCConversion = false;
bool ObjCLifetimeConversion = false;
+
+ // If we are initializing an rvalue reference, don't permit conversion
+ // functions that return lvalues.
+ if (!ConvTemplate && DeclType->isRValueReferenceType()) {
+ const ReferenceType *RefType
+ = Conv->getConversionType()->getAs<LValueReferenceType>();
+ if (RefType && !RefType->getPointeeType()->isFunctionType())
+ continue;
+ }
+
if (!ConvTemplate &&
S.CompareReferenceRelationship(
DeclLoc,
@@ -3322,6 +3376,8 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
DeclType, CandidateSet);
}
+ bool HadMultipleCandidates = (CandidateSet.size() > 1);
+
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) {
case OR_Success:
@@ -3343,8 +3399,9 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
ICS.setUserDefined();
ICS.UserDefined.Before = Best->Conversions[0].Standard;
ICS.UserDefined.After = Best->FinalConversion;
+ ICS.UserDefined.HadMultipleCandidates = HadMultipleCandidates;
ICS.UserDefined.ConversionFunction = Best->Function;
- ICS.UserDefined.FoundConversionFunction = Best->FoundDecl.getDecl();
+ ICS.UserDefined.FoundConversionFunction = Best->FoundDecl;
ICS.UserDefined.EllipsisConversion = false;
assert(ICS.UserDefined.After.ReferenceBinding &&
ICS.UserDefined.After.DirectBinding &&
@@ -3611,12 +3668,25 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
ICS.Standard.ObjCLifetimeConversionBinding = false;
} else if (ICS.isUserDefined()) {
+ // Don't allow rvalue references to bind to lvalues.
+ if (DeclType->isRValueReferenceType()) {
+ if (const ReferenceType *RefType
+ = ICS.UserDefined.ConversionFunction->getResultType()
+ ->getAs<LValueReferenceType>()) {
+ if (!RefType->getPointeeType()->isFunctionType()) {
+ ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, Init,
+ DeclType);
+ return ICS;
+ }
+ }
+ }
+
ICS.UserDefined.After.ReferenceBinding = true;
- ICS.Standard.IsLvalueReference = !isRValRef;
- ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
- ICS.Standard.BindsToRvalue = true;
- ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
- ICS.Standard.ObjCLifetimeConversionBinding = false;
+ ICS.UserDefined.After.IsLvalueReference = !isRValRef;
+ ICS.UserDefined.After.BindsToFunctionLvalue = T2->isFunctionType();
+ ICS.UserDefined.After.BindsToRvalue = true;
+ ICS.UserDefined.After.BindsImplicitObjectArgumentWithoutRefQualifier = false;
+ ICS.UserDefined.After.ObjCLifetimeConversionBinding = false;
}
return ICS;
@@ -3647,6 +3717,18 @@ TryCopyInitialization(Sema &S, Expr *From, QualType ToType,
AllowObjCWritebackConversion);
}
+static bool TryCopyInitialization(const CanQualType FromQTy,
+ const CanQualType ToQTy,
+ Sema &S,
+ SourceLocation Loc,
+ ExprValueKind FromVK) {
+ OpaqueValueExpr TmpExpr(Loc, FromQTy, FromVK);
+ ImplicitConversionSequence ICS =
+ TryCopyInitialization(S, &TmpExpr, ToQTy, true, true, false);
+
+ return !ICS.isBad();
+}
+
/// TryObjectArgumentInitialization - Try to initialize the object
/// parameter of the given member function (@c Method) from the
/// expression @p From.
@@ -3852,25 +3934,57 @@ ExprResult Sema::PerformContextuallyConvertToBool(Expr *From) {
return ExprError();
}
-/// TryContextuallyConvertToObjCId - Attempt to contextually convert the
-/// expression From to 'id'.
+/// dropPointerConversions - If the given standard conversion sequence
+/// involves any pointer conversions, remove them. This may change
+/// the result type of the conversion sequence.
+static void dropPointerConversion(StandardConversionSequence &SCS) {
+ if (SCS.Second == ICK_Pointer_Conversion) {
+ SCS.Second = ICK_Identity;
+ SCS.Third = ICK_Identity;
+ SCS.ToTypePtrs[2] = SCS.ToTypePtrs[1] = SCS.ToTypePtrs[0];
+ }
+}
+
+/// TryContextuallyConvertToObjCPointer - Attempt to contextually
+/// convert the expression From to an Objective-C pointer type.
static ImplicitConversionSequence
-TryContextuallyConvertToObjCId(Sema &S, Expr *From) {
+TryContextuallyConvertToObjCPointer(Sema &S, Expr *From) {
+ // Do an implicit conversion to 'id'.
QualType Ty = S.Context.getObjCIdType();
- return TryImplicitConversion(S, From, Ty,
- // FIXME: Are these flags correct?
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/true,
- /*InOverloadResolution=*/false,
- /*CStyle=*/false,
- /*AllowObjCWritebackConversion=*/false);
+ ImplicitConversionSequence ICS
+ = TryImplicitConversion(S, From, Ty,
+ // FIXME: Are these flags correct?
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/true,
+ /*InOverloadResolution=*/false,
+ /*CStyle=*/false,
+ /*AllowObjCWritebackConversion=*/false);
+
+ // Strip off any final conversions to 'id'.
+ switch (ICS.getKind()) {
+ case ImplicitConversionSequence::BadConversion:
+ case ImplicitConversionSequence::AmbiguousConversion:
+ case ImplicitConversionSequence::EllipsisConversion:
+ break;
+
+ case ImplicitConversionSequence::UserDefinedConversion:
+ dropPointerConversion(ICS.UserDefined.After);
+ break;
+
+ case ImplicitConversionSequence::StandardConversion:
+ dropPointerConversion(ICS.Standard);
+ break;
+ }
+
+ return ICS;
}
-/// PerformContextuallyConvertToObjCId - Perform a contextual conversion
-/// of the expression From to 'id'.
-ExprResult Sema::PerformContextuallyConvertToObjCId(Expr *From) {
+/// PerformContextuallyConvertToObjCPointer - Perform a contextual
+/// conversion of the expression From to an Objective-C pointer type.
+ExprResult Sema::PerformContextuallyConvertToObjCPointer(Expr *From) {
QualType Ty = Context.getObjCIdType();
- ImplicitConversionSequence ICS = TryContextuallyConvertToObjCId(*this, From);
+ ImplicitConversionSequence ICS =
+ TryContextuallyConvertToObjCPointer(*this, From);
if (!ICS.isBad())
return PerformImplicitConversion(From, Ty, ICS, AA_Converting);
return ExprError();
@@ -3951,6 +4065,8 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
const UnresolvedSetImpl *Conversions
= cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions();
+ bool HadMultipleCandidates = (Conversions->size() > 1);
+
for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end();
I != E;
@@ -3978,7 +4094,7 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
QualType ConvTy
= Conversion->getConversionType().getNonReferenceType();
std::string TypeStr;
- ConvTy.getAsStringInternal(TypeStr, Context.PrintingPolicy);
+ ConvTy.getAsStringInternal(TypeStr, getPrintingPolicy());
Diag(Loc, ExplicitConvDiag)
<< T << ConvTy
@@ -3995,7 +4111,8 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
return ExprError();
CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);
- ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion);
+ ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion,
+ HadMultipleCandidates);
if (Result.isInvalid())
return ExprError();
@@ -4022,8 +4139,8 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
<< T << ConvTy->isEnumeralType() << ConvTy << From->getSourceRange();
}
- ExprResult Result = BuildCXXMemberCallExpr(From, Found,
- cast<CXXConversionDecl>(Found->getUnderlyingDecl()));
+ ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion,
+ HadMultipleCandidates);
if (Result.isInvalid())
return ExprError();
@@ -4144,6 +4261,15 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
return;
}
+ // (CUDA B.1): Check for invalid calls between targets.
+ if (getLangOptions().CUDA)
+ if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext))
+ if (CheckCUDATarget(Caller, Function)) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_target;
+ return;
+ }
+
// Determine the implicit conversion sequences for each of the
// arguments.
Candidate.Conversions.resize(NumArgs);
@@ -4590,7 +4716,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
break;
default:
- assert(false &&
+ llvm_unreachable(
"Can only end up with a standard conversion sequence or failure");
}
}
@@ -4686,9 +4812,9 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
Candidate.Conversions[0].setUserDefined();
Candidate.Conversions[0].UserDefined.Before = ObjectInit.Standard;
Candidate.Conversions[0].UserDefined.EllipsisConversion = false;
+ Candidate.Conversions[0].UserDefined.HadMultipleCandidates = false;
Candidate.Conversions[0].UserDefined.ConversionFunction = Conversion;
- Candidate.Conversions[0].UserDefined.FoundConversionFunction
- = FoundDecl.getDecl();
+ Candidate.Conversions[0].UserDefined.FoundConversionFunction = FoundDecl;
Candidate.Conversions[0].UserDefined.After
= Candidate.Conversions[0].UserDefined.Before;
Candidate.Conversions[0].UserDefined.After.setAsIdentityConversion();
@@ -4973,7 +5099,7 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty,
buildObjCPtr = true;
}
else
- assert(false && "type was not a pointer type!");
+ llvm_unreachable("type was not a pointer type!");
}
else
PointeeTy = PointerTy->getPointeeType();
@@ -5230,7 +5356,7 @@ class BuiltinOperatorOverloadBuilder {
unsigned NumArgs;
Qualifiers VisibleTypeConversionsQuals;
bool HasArithmeticOrEnumeralCandidateType;
- llvm::SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes;
+ SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes;
OverloadCandidateSet &CandidateSet;
// Define some constants used to index and iterate over the arithemetic types
@@ -5366,7 +5492,7 @@ public:
Sema &S, Expr **Args, unsigned NumArgs,
Qualifiers VisibleTypeConversionsQuals,
bool HasArithmeticOrEnumeralCandidateType,
- llvm::SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes,
+ SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes,
OverloadCandidateSet &CandidateSet)
: S(S), Args(Args), NumArgs(NumArgs),
VisibleTypeConversionsQuals(VisibleTypeConversionsQuals),
@@ -6235,7 +6361,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
bool HasNonRecordCandidateType = false;
bool HasArithmeticOrEnumeralCandidateType = false;
- llvm::SmallVector<BuiltinCandidateTypeSet, 2> CandidateTypes;
+ SmallVector<BuiltinCandidateTypeSet, 2> CandidateTypes;
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
CandidateTypes.push_back(BuiltinCandidateTypeSet(*this));
CandidateTypes[ArgIdx].AddTypesConvertedFrom(Args[ArgIdx]->getType(),
@@ -6254,7 +6380,11 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// Exit early when no non-record types have been added to the candidate set
// for any of the arguments to the operator.
- if (!HasNonRecordCandidateType)
+ //
+ // We can't exit early for !, ||, or &&, since there we have always have
+ // 'bool' overloads.
+ if (!HasNonRecordCandidateType &&
+ !(Op == OO_Exclaim || Op == OO_AmpAmp || Op == OO_PipePipe))
return;
// Setup an object to manage the common state for building overloads.
@@ -6267,16 +6397,15 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
switch (Op) {
case OO_None:
case NUM_OVERLOADED_OPERATORS:
- assert(false && "Expected an overloaded operator");
- break;
+ llvm_unreachable("Expected an overloaded operator");
case OO_New:
case OO_Delete:
case OO_Array_New:
case OO_Array_Delete:
case OO_Call:
- assert(false && "Special operators don't use AddBuiltinOperatorCandidates");
- break;
+ llvm_unreachable(
+ "Special operators don't use AddBuiltinOperatorCandidates");
case OO_Comma:
case OO_Arrow:
@@ -6846,6 +6975,17 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
return;
}
+ // Special diagnostic for failure to convert an initializer list, since
+ // telling the user that it has type void is not useful.
+ if (FromExpr && isa<InitListExpr>(FromExpr)) {
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_list_argument)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromTy << ToTy << (unsigned) isObjectArgument << I+1;
+ MaybeEmitInheritedConstructorNote(S, Fn);
+ return;
+ }
+
// Diagnose references or pointers to incomplete types differently,
// since it's far from impossible that the incompleteness triggered
// the failure.
@@ -6902,11 +7042,34 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
return;
}
- // TODO: specialize more based on the kind of mismatch
- S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv)
- << (unsigned) FnKind << FnDesc
+ if (isa<ObjCObjectPointerType>(CFromTy) &&
+ isa<PointerType>(CToTy)) {
+ Qualifiers FromQs = CFromTy.getQualifiers();
+ Qualifiers ToQs = CToTy.getQualifiers();
+ if (FromQs.getObjCLifetime() != ToQs.getObjCLifetime()) {
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_arc_conv)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromTy << ToTy << (unsigned) isObjectArgument << I+1;
+ MaybeEmitInheritedConstructorNote(S, Fn);
+ return;
+ }
+ }
+
+ // Emit the generic diagnostic and, optionally, add the hints to it.
+ PartialDiagnostic FDiag = S.PDiag(diag::note_ovl_candidate_bad_conv);
+ FDiag << (unsigned) FnKind << FnDesc
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
- << FromTy << ToTy << (unsigned) isObjectArgument << I+1;
+ << FromTy << ToTy << (unsigned) isObjectArgument << I + 1
+ << (unsigned) (Cand->Fix.Kind);
+
+ // If we can fix the conversion, suggest the FixIts.
+ for (SmallVector<FixItHint, 1>::iterator
+ HI = Cand->Fix.Hints.begin(), HE = Cand->Fix.Hints.end();
+ HI != HE; ++HI)
+ FDiag << *HI;
+ S.Diag(Fn->getLocation(), FDiag);
+
MaybeEmitInheritedConstructorNote(S, Fn);
}
@@ -7081,6 +7244,21 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
}
}
+/// CUDA: diagnose an invalid call across targets.
+void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) {
+ FunctionDecl *Caller = cast<FunctionDecl>(S.CurContext);
+ FunctionDecl *Callee = Cand->Function;
+
+ Sema::CUDAFunctionTarget CallerTarget = S.IdentifyCUDATarget(Caller),
+ CalleeTarget = S.IdentifyCUDATarget(Callee);
+
+ std::string FnDesc;
+ OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Callee, FnDesc);
+
+ S.Diag(Callee->getLocation(), diag::note_ovl_candidate_bad_target)
+ << (unsigned) FnKind << CalleeTarget << CallerTarget;
+}
+
/// Generates a 'note' diagnostic for an overload candidate. We've
/// already generated a primary error at the call site.
///
@@ -7140,6 +7318,9 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
// those conditions and diagnose them well.
return S.NoteOverloadCandidate(Fn);
}
+
+ case ovl_fail_bad_target:
+ return DiagnoseBadTarget(S, Cand);
}
}
@@ -7217,6 +7398,37 @@ SourceLocation GetLocationForCandidate(const OverloadCandidate *Cand) {
return SourceLocation();
}
+static unsigned
+RankDeductionFailure(const OverloadCandidate::DeductionFailureInfo &DFI) {
+ switch ((Sema::TemplateDeductionResult)DFI.Result) {
+ case Sema::TDK_Success:
+ llvm_unreachable("TDK_success while diagnosing bad deduction");
+
+ case Sema::TDK_Incomplete:
+ return 1;
+
+ case Sema::TDK_Underqualified:
+ case Sema::TDK_Inconsistent:
+ return 2;
+
+ case Sema::TDK_SubstitutionFailure:
+ case Sema::TDK_NonDeducedMismatch:
+ return 3;
+
+ case Sema::TDK_InstantiationDepth:
+ case Sema::TDK_FailedOverloadResolution:
+ return 4;
+
+ case Sema::TDK_InvalidExplicitArguments:
+ return 5;
+
+ case Sema::TDK_TooManyArguments:
+ case Sema::TDK_TooFewArguments:
+ return 6;
+ }
+ llvm_unreachable("Unhandled deduction result");
+}
+
struct CompareOverloadCandidatesForDisplay {
Sema &S;
CompareOverloadCandidatesForDisplay(Sema &S) : S(S) {}
@@ -7256,6 +7468,19 @@ struct CompareOverloadCandidatesForDisplay {
if (R->FailureKind != ovl_fail_bad_conversion)
return true;
+ // The conversion that can be fixed with a smaller number of changes,
+ // comes first.
+ unsigned numLFixes = L->Fix.NumConversionsFixed;
+ unsigned numRFixes = R->Fix.NumConversionsFixed;
+ numLFixes = (numLFixes == 0) ? UINT_MAX : numLFixes;
+ numRFixes = (numRFixes == 0) ? UINT_MAX : numRFixes;
+ if (numLFixes != numRFixes) {
+ if (numLFixes < numRFixes)
+ return true;
+ else
+ return false;
+ }
+
// If there's any ordering between the defined conversions...
// FIXME: this might not be transitive.
assert(L->Conversions.size() == R->Conversions.size());
@@ -7284,6 +7509,16 @@ struct CompareOverloadCandidatesForDisplay {
} else if (R->FailureKind == ovl_fail_bad_conversion)
return false;
+ if (L->FailureKind == ovl_fail_bad_deduction) {
+ if (R->FailureKind != ovl_fail_bad_deduction)
+ return true;
+
+ if (L->DeductionFailure.Result != R->DeductionFailure.Result)
+ return RankDeductionFailure(L->DeductionFailure)
+ < RankDeductionFailure(R->DeductionFailure);
+ } else if (R->FailureKind == ovl_fail_bad_deduction)
+ return false;
+
// TODO: others?
}
@@ -7300,7 +7535,7 @@ struct CompareOverloadCandidatesForDisplay {
};
/// CompleteNonViableCandidate - Normally, overload resolution only
-/// computes up to the first
+/// computes up to the first. Produces the FixIt set if possible.
void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
Expr **Args, unsigned NumArgs) {
assert(!Cand->Viable);
@@ -7308,14 +7543,21 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
// Don't do anything on failures other than bad conversion.
if (Cand->FailureKind != ovl_fail_bad_conversion) return;
+ // We only want the FixIts if all the arguments can be corrected.
+ bool Unfixable = false;
+ // Use a implicit copy initialization to check conversion fixes.
+ Cand->Fix.setConversionChecker(TryCopyInitialization);
+
// Skip forward to the first bad conversion.
unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0);
unsigned ConvCount = Cand->Conversions.size();
while (true) {
assert(ConvIdx != ConvCount && "no bad conversion in candidate");
ConvIdx++;
- if (Cand->Conversions[ConvIdx - 1].isBad())
+ if (Cand->Conversions[ConvIdx - 1].isBad()) {
+ Unfixable = !Cand->TryToFixBadConversion(ConvIdx - 1, S);
break;
+ }
}
if (ConvIdx == ConvCount)
@@ -7360,13 +7602,17 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
// Fill in the rest of the conversions.
unsigned NumArgsInProto = Proto->getNumArgs();
for (; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) {
- if (ArgIdx < NumArgsInProto)
+ if (ArgIdx < NumArgsInProto) {
Cand->Conversions[ConvIdx]
= TryCopyInitialization(S, Args[ArgIdx], Proto->getArgType(ArgIdx),
SuppressUserConversions,
/*InOverloadResolution=*/true,
/*AllowObjCWritebackConversion=*/
S.getLangOptions().ObjCAutoRefCount);
+ // Store the FixIt in the candidate if it exists.
+ if (!Unfixable && Cand->Conversions[ConvIdx].isBad())
+ Unfixable = !Cand->TryToFixBadConversion(ConvIdx, S);
+ }
else
Cand->Conversions[ConvIdx].setEllipsis();
}
@@ -7384,7 +7630,7 @@ void OverloadCandidateSet::NoteCandidates(Sema &S,
SourceLocation OpLoc) {
// Sort the candidates by viability and position. Sorting directly would
// be prohibitive, so we make a set of pointers and sort those.
- llvm::SmallVector<OverloadCandidate*, 32> Cands;
+ SmallVector<OverloadCandidate*, 32> Cands;
if (OCD == OCD_AllCandidates) Cands.reserve(size());
for (iterator Cand = begin(), LastCand = end(); Cand != LastCand; ++Cand) {
if (Cand->Viable)
@@ -7403,8 +7649,9 @@ void OverloadCandidateSet::NoteCandidates(Sema &S,
bool ReportedAmbiguousConversions = false;
- llvm::SmallVectorImpl<OverloadCandidate*>::iterator I, E;
- const Diagnostic::OverloadsShown ShowOverloads = S.Diags.getShowOverloads();
+ SmallVectorImpl<OverloadCandidate*>::iterator I, E;
+ const DiagnosticsEngine::OverloadsShown ShowOverloads =
+ S.Diags.getShowOverloads();
unsigned CandsShown = 0;
for (I = Cands.begin(), E = Cands.end(); I != E; ++I) {
OverloadCandidate *Cand = *I;
@@ -7412,7 +7659,7 @@ void OverloadCandidateSet::NoteCandidates(Sema &S,
// Set an arbitrary limit on the number of candidate functions we'll spam
// the user with. FIXME: This limit should depend on details of the
// candidate list.
- if (CandsShown >= 4 && ShowOverloads == Diagnostic::Ovl_Best) {
+ if (CandsShown >= 4 && ShowOverloads == DiagnosticsEngine::Ovl_Best) {
break;
}
++CandsShown;
@@ -7485,7 +7732,7 @@ class AddressOfFunctionResolver
OverloadExpr::FindResult OvlExprInfo;
OverloadExpr *OvlExpr;
TemplateArgumentListInfo OvlExplicitTemplateArgs;
- llvm::SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches;
+ SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches;
public:
AddressOfFunctionResolver(Sema &S, Expr* SourceExpr,
@@ -7607,6 +7854,11 @@ private:
return false;
if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(Fn)) {
+ if (S.getLangOptions().CUDA)
+ if (FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext))
+ if (S.CheckCUDATarget(Caller, FunDecl))
+ return false;
+
QualType ResultTy;
if (Context.hasSameUnqualifiedType(TargetFunctionType,
FunDecl->getType()) ||
@@ -7873,25 +8125,31 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
-// Resolve and fix an overloaded expression that
-// can be resolved because it identifies a single function
-// template specialization
+// Resolve and fix an overloaded expression that can be resolved
+// because it identifies a single function template specialization.
+//
// Last three arguments should only be supplied if Complain = true
-ExprResult Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
- Expr *SrcExpr, bool doFunctionPointerConverion, bool complain,
- const SourceRange& OpRangeForComplaining,
+//
+// Return true if it was logically possible to so resolve the
+// expression, regardless of whether or not it succeeded. Always
+// returns true if 'complain' is set.
+bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
+ ExprResult &SrcExpr, bool doFunctionPointerConverion,
+ bool complain, const SourceRange& OpRangeForComplaining,
QualType DestTypeForComplaining,
unsigned DiagIDForComplaining) {
- assert(SrcExpr->getType() == Context.OverloadTy);
+ assert(SrcExpr.get()->getType() == Context.OverloadTy);
- OverloadExpr::FindResult ovl = OverloadExpr::find(SrcExpr);
+ OverloadExpr::FindResult ovl = OverloadExpr::find(SrcExpr.get());
DeclAccessPair found;
ExprResult SingleFunctionExpression;
if (FunctionDecl *fn = ResolveSingleFunctionTemplateSpecialization(
ovl.Expression, /*complain*/ false, &found)) {
- if (DiagnoseUseOfDecl(fn, SrcExpr->getSourceRange().getBegin()))
- return ExprError();
+ if (DiagnoseUseOfDecl(fn, SrcExpr.get()->getSourceRange().getBegin())) {
+ SrcExpr = ExprError();
+ return true;
+ }
// It is only correct to resolve to an instance method if we're
// resolving a form that's permitted to be a pointer to member.
@@ -7900,28 +8158,34 @@ ExprResult Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
if (!ovl.HasFormOfMemberPointer &&
isa<CXXMethodDecl>(fn) &&
cast<CXXMethodDecl>(fn)->isInstance()) {
- if (complain) {
- Diag(ovl.Expression->getExprLoc(),
- diag::err_invalid_use_of_bound_member_func)
- << ovl.Expression->getSourceRange();
- // TODO: I believe we only end up here if there's a mix of
- // static and non-static candidates (otherwise the expression
- // would have 'bound member' type, not 'overload' type).
- // Ideally we would note which candidate was chosen and why
- // the static candidates were rejected.
- }
-
- return ExprError();
+ if (!complain) return false;
+
+ Diag(ovl.Expression->getExprLoc(),
+ diag::err_bound_member_function)
+ << 0 << ovl.Expression->getSourceRange();
+
+ // TODO: I believe we only end up here if there's a mix of
+ // static and non-static candidates (otherwise the expression
+ // would have 'bound member' type, not 'overload' type).
+ // Ideally we would note which candidate was chosen and why
+ // the static candidates were rejected.
+ SrcExpr = ExprError();
+ return true;
}
// Fix the expresion to refer to 'fn'.
SingleFunctionExpression =
- Owned(FixOverloadedFunctionReference(SrcExpr, found, fn));
+ Owned(FixOverloadedFunctionReference(SrcExpr.take(), found, fn));
// If desired, do function-to-pointer decay.
- if (doFunctionPointerConverion)
+ if (doFunctionPointerConverion) {
SingleFunctionExpression =
DefaultFunctionArrayLvalueConversion(SingleFunctionExpression.take());
+ if (SingleFunctionExpression.isInvalid()) {
+ SrcExpr = ExprError();
+ return true;
+ }
+ }
}
if (!SingleFunctionExpression.isUsable()) {
@@ -7931,12 +8195,17 @@ ExprResult Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
<< DestTypeForComplaining
<< OpRangeForComplaining
<< ovl.Expression->getQualifierLoc().getSourceRange();
- NoteAllOverloadCandidates(SrcExpr);
- }
- return ExprError();
+ NoteAllOverloadCandidates(SrcExpr.get());
+
+ SrcExpr = ExprError();
+ return true;
+ }
+
+ return false;
}
- return SingleFunctionExpression;
+ SrcExpr = SingleFunctionExpression;
+ return true;
}
/// \brief Add a single candidate to the overload set.
@@ -8164,7 +8433,8 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
if (!DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R,
ExplicitTemplateArgs, Args, NumArgs) &&
(!EmptyLookup ||
- SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression)))
+ SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression,
+ ExplicitTemplateArgs, Args, NumArgs)))
return ExprError();
assert(!R.empty() && "lookup results empty despite recovery");
@@ -8214,7 +8484,7 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
if (ULE->decls_begin() + 1 == ULE->decls_end() &&
(F = dyn_cast<FunctionDecl>(*ULE->decls_begin())) &&
F->getBuiltinID() && F->isImplicit())
- assert(0 && "performing ADL for builtin");
+ llvm_unreachable("performing ADL for builtin");
// We don't perform ADL in C.
assert(getLangOptions().CPlusPlus && "ADL enabled in C");
@@ -8232,9 +8502,22 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
// If we found nothing, try to recover.
// BuildRecoveryCallExpr diagnoses the error itself, so we just bail
// out if it fails.
- if (CandidateSet.empty())
+ if (CandidateSet.empty()) {
+ // In Microsoft mode, if we are inside a template class member function then
+ // create a type dependent CallExpr. The goal is to postpone name lookup
+ // to instantiation time to be able to search into type dependent base
+ // classes.
+ if (getLangOptions().MicrosoftExt && CurContext->isDependentContext() &&
+ isa<CXXMethodDecl>(CurContext)) {
+ CallExpr *CE = new (Context) CallExpr(Context, Fn, Args, NumArgs,
+ Context.DependentTy, VK_RValue,
+ RParenLoc);
+ CE->setTypeDependent(true);
+ return Owned(CE);
+ }
return BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc, Args, NumArgs,
RParenLoc, /*EmptyLookup=*/true);
+ }
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best)) {
@@ -8379,6 +8662,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
// Add builtin operator candidates.
AddBuiltinOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet);
+ bool HadMultipleCandidates = (CandidateSet.size() > 1);
+
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) {
@@ -8423,7 +8708,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
ResultTy = ResultTy.getNonLValueExprType(Context);
// Build the actual expression node.
- ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl);
+ ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
+ HadMultipleCandidates);
if (FnExpr.isInvalid())
return ExprError();
@@ -8468,8 +8754,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
<< UnaryOperator::getOpcodeStr(Opc)
<< Input->getType()
<< Input->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_ViableCandidates,
- Args, NumArgs,
+ CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs,
UnaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
@@ -8479,7 +8764,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
<< UnaryOperator::getOpcodeStr(Opc)
<< getDeletedOrUnavailableSuffix(Best->Function)
<< Input->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs,
+ UnaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
}
@@ -8627,6 +8913,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// Add builtin operator candidates.
AddBuiltinOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet);
+ bool HadMultipleCandidates = (CandidateSet.size() > 1);
+
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) {
@@ -8688,7 +8976,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
ResultTy = ResultTy.getNonLValueExprType(Context);
// Build the actual expression node.
- ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, OpLoc);
+ ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
+ HadMultipleCandidates, OpLoc);
if (FnExpr.isInvalid())
return ExprError();
@@ -8774,7 +9063,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
<< BinaryOperator::getOpcodeStr(Opc)
<< getDeletedOrUnavailableSuffix(Best->Function)
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2);
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2,
+ BinaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
}
@@ -8837,6 +9127,8 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// Add builtin operator candidates.
AddBuiltinOperatorCandidates(OO_Subscript, LLoc, Args, 2, CandidateSet);
+ bool HadMultipleCandidates = (CandidateSet.size() > 1);
+
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(*this, LLoc, Best)) {
@@ -8883,7 +9175,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
DeclarationNameLoc LocInfo;
LocInfo.CXXOperatorName.BeginOpNameLoc = LLoc.getRawEncoding();
LocInfo.CXXOperatorName.EndOpNameLoc = RLoc.getRawEncoding();
- ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, LLoc, LocInfo);
+ ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
+ HadMultipleCandidates,
+ LLoc, LocInfo);
if (FnExpr.isInvalid())
return ExprError();
@@ -9059,7 +9353,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
// Microsoft supports direct constructor calls.
- if (getLangOptions().Microsoft && isa<CXXConstructorDecl>(Func)) {
+ if (getLangOptions().MicrosoftExt && isa<CXXConstructorDecl>(Func)) {
AddOverloadCandidate(cast<CXXConstructorDecl>(Func), I.getPair(), Args, NumArgs,
CandidateSet);
} else if ((Method = dyn_cast<CXXMethodDecl>(Func))) {
@@ -9231,8 +9525,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
}
// C++ [over.call.object]p2:
- // In addition, for each conversion function declared in T of the
- // form
+ // In addition, for each (non-explicit in C++0x) conversion function
+ // declared in T of the form
//
// operator conversion-type-id () cv-qualifier;
//
@@ -9262,18 +9556,23 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
continue;
CXXConversionDecl *Conv = cast<CXXConversionDecl>(D);
-
- // Strip the reference type (if any) and then the pointer type (if
- // any) to get down to what might be a function type.
- QualType ConvType = Conv->getConversionType().getNonReferenceType();
- if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
- ConvType = ConvPtrType->getPointeeType();
-
- if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>())
- AddSurrogateCandidate(Conv, I.getPair(), ActingContext, Proto,
- Object.get(), Args, NumArgs, CandidateSet);
+ if (!Conv->isExplicit()) {
+ // Strip the reference type (if any) and then the pointer type (if
+ // any) to get down to what might be a function type.
+ QualType ConvType = Conv->getConversionType().getNonReferenceType();
+ if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
+ ConvType = ConvPtrType->getPointeeType();
+
+ if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>())
+ {
+ AddSurrogateCandidate(Conv, I.getPair(), ActingContext, Proto,
+ Object.get(), Args, NumArgs, CandidateSet);
+ }
+ }
}
+ bool HadMultipleCandidates = (CandidateSet.size() > 1);
+
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(*this, Object.get()->getLocStart(),
@@ -9332,7 +9631,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
// Create an implicit member expr to refer to the conversion operator.
// and then call it.
- ExprResult Call = BuildCXXMemberCallExpr(Object.get(), Best->FoundDecl, Conv);
+ ExprResult Call = BuildCXXMemberCallExpr(Object.get(), Best->FoundDecl,
+ Conv, HadMultipleCandidates);
if (Call.isInvalid())
return ExprError();
@@ -9368,7 +9668,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
MethodArgs[ArgIdx + 1] = Args[ArgIdx];
- ExprResult NewFn = CreateFunctionRefExpr(*this, Method);
+ ExprResult NewFn = CreateFunctionRefExpr(*this, Method,
+ HadMultipleCandidates);
if (NewFn.isInvalid())
return true;
@@ -9498,6 +9799,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
0, 0, CandidateSet, /*SuppressUserConversions=*/false);
}
+ bool HadMultipleCandidates = (CandidateSet.size() > 1);
+
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) {
@@ -9545,7 +9848,8 @@ 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,
+ HadMultipleCandidates);
if (FnExpr.isInvalid())
return ExprError();
@@ -9648,14 +9952,16 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
TemplateArgs = &TemplateArgsBuffer;
}
- return DeclRefExpr::Create(Context,
- ULE->getQualifierLoc(),
- Fn,
- ULE->getNameLoc(),
- Fn->getType(),
- VK_LValue,
- Found.getDecl(),
- TemplateArgs);
+ DeclRefExpr *DRE = DeclRefExpr::Create(Context,
+ ULE->getQualifierLoc(),
+ Fn,
+ ULE->getNameLoc(),
+ Fn->getType(),
+ VK_LValue,
+ Found.getDecl(),
+ TemplateArgs);
+ DRE->setHadMultipleCandidates(ULE->getNumDecls() > 1);
+ return DRE;
}
if (UnresolvedMemberExpr *MemExpr = dyn_cast<UnresolvedMemberExpr>(E)) {
@@ -9672,14 +9978,16 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
// implicit member access, rewrite to a simple decl ref.
if (MemExpr->isImplicitAccess()) {
if (cast<CXXMethodDecl>(Fn)->isStatic()) {
- return DeclRefExpr::Create(Context,
- MemExpr->getQualifierLoc(),
- Fn,
- MemExpr->getMemberLoc(),
- Fn->getType(),
- VK_LValue,
- Found.getDecl(),
- TemplateArgs);
+ DeclRefExpr *DRE = DeclRefExpr::Create(Context,
+ MemExpr->getQualifierLoc(),
+ Fn,
+ MemExpr->getMemberLoc(),
+ Fn->getType(),
+ VK_LValue,
+ Found.getDecl(),
+ TemplateArgs);
+ DRE->setHadMultipleCandidates(MemExpr->getNumDecls() > 1);
+ return DRE;
} else {
SourceLocation Loc = MemExpr->getMemberLoc();
if (MemExpr->getQualifier())
@@ -9701,14 +10009,16 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
type = Context.BoundMemberTy;
}
- return MemberExpr::Create(Context, Base,
- MemExpr->isArrow(),
- MemExpr->getQualifierLoc(),
- Fn,
- Found,
- MemExpr->getMemberNameInfo(),
- TemplateArgs,
- type, valueKind, OK_Ordinary);
+ MemberExpr *ME = MemberExpr::Create(Context, Base,
+ MemExpr->isArrow(),
+ MemExpr->getQualifierLoc(),
+ Fn,
+ Found,
+ MemExpr->getMemberNameInfo(),
+ TemplateArgs,
+ type, valueKind, OK_Ordinary);
+ ME->setHadMultipleCandidates(true);
+ return ME;
}
llvm_unreachable("Invalid reference to overloaded function");
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 65f431d46075..5351896204ca 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -47,8 +47,8 @@ StmtResult Sema::ActOnExprStmt(FullExprArg expr) {
StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc,
- SourceLocation LeadingEmptyMacroLoc) {
- return Owned(new (Context) NullStmt(SemiLoc, LeadingEmptyMacroLoc));
+ bool HasLeadingEmptyMacro) {
+ return Owned(new (Context) NullStmt(SemiLoc, HasLeadingEmptyMacro));
}
StmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, SourceLocation StartLoc,
@@ -92,6 +92,56 @@ void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) {
}
}
+/// \brief Diagnose unused '==' and '!=' as likely typos for '=' or '|='.
+///
+/// Adding a cast to void (or other expression wrappers) will prevent the
+/// warning from firing.
+static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) {
+ SourceLocation Loc;
+ bool IsNotEqual, CanAssign;
+
+ if (const BinaryOperator *Op = dyn_cast<BinaryOperator>(E)) {
+ if (Op->getOpcode() != BO_EQ && Op->getOpcode() != BO_NE)
+ return false;
+
+ Loc = Op->getOperatorLoc();
+ IsNotEqual = Op->getOpcode() == BO_NE;
+ CanAssign = Op->getLHS()->IgnoreParenImpCasts()->isLValue();
+ } else if (const CXXOperatorCallExpr *Op = dyn_cast<CXXOperatorCallExpr>(E)) {
+ if (Op->getOperator() != OO_EqualEqual &&
+ Op->getOperator() != OO_ExclaimEqual)
+ return false;
+
+ Loc = Op->getOperatorLoc();
+ IsNotEqual = Op->getOperator() == OO_ExclaimEqual;
+ CanAssign = Op->getArg(0)->IgnoreParenImpCasts()->isLValue();
+ } else {
+ // Not a typo-prone comparison.
+ return false;
+ }
+
+ // Suppress warnings when the operator, suspicious as it may be, comes from
+ // a macro expansion.
+ if (Loc.isMacroID())
+ return false;
+
+ S.Diag(Loc, diag::warn_unused_comparison)
+ << (unsigned)IsNotEqual << E->getSourceRange();
+
+ // If the LHS is a plausible entity to assign to, provide a fixit hint to
+ // correct common typos.
+ if (CanAssign) {
+ if (IsNotEqual)
+ S.Diag(Loc, diag::note_inequality_comparison_to_or_assign)
+ << FixItHint::CreateReplacement(Loc, "|=");
+ else
+ S.Diag(Loc, diag::note_equality_comparison_to_assign)
+ << FixItHint::CreateReplacement(Loc, "=");
+ }
+
+ return true;
+}
+
void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
if (const LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S))
return DiagnoseUnusedExprResult(Label->getSubStmt());
@@ -114,6 +164,9 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
if (const CXXBindTemporaryExpr *TempExpr = dyn_cast<CXXBindTemporaryExpr>(E))
E = TempExpr->getSubExpr();
+ if (DiagnoseUnusedComparison(*this, E))
+ return;
+
E = E->IgnoreParenImpCasts();
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
if (E->getType()->isVoidType())
@@ -123,7 +176,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
// a more specific message to make it clear what is happening.
if (const Decl *FD = CE->getCalleeDecl()) {
if (FD->getAttr<WarnUnusedResultAttr>()) {
- Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result";
+ Diag(Loc, diag::warn_unused_result) << R1 << R2;
return;
}
if (FD->getAttr<PureAttr>()) {
@@ -142,7 +195,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
}
const ObjCMethodDecl *MD = ME->getMethodDecl();
if (MD && MD->getAttr<WarnUnusedResultAttr>()) {
- Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result";
+ Diag(Loc, diag::warn_unused_result) << R1 << R2;
return;
}
} else if (isa<ObjCPropertyRefExpr>(E)) {
@@ -238,6 +291,8 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal,
/// ActOnCaseStmtBody - This installs a statement as the body of a case.
void Sema::ActOnCaseStmtBody(Stmt *caseStmt, Stmt *SubStmt) {
+ DiagnoseUnusedExprResult(SubStmt);
+
CaseStmt *CS = static_cast<CaseStmt*>(caseStmt);
CS->setSubStmt(SubStmt);
}
@@ -245,6 +300,8 @@ void Sema::ActOnCaseStmtBody(Stmt *caseStmt, Stmt *SubStmt) {
StmtResult
Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc,
Stmt *SubStmt, Scope *CurScope) {
+ DiagnoseUnusedExprResult(SubStmt);
+
if (getCurFunction()->SwitchStack.empty()) {
Diag(DefaultLoc, diag::err_default_not_in_switch);
return Owned(SubStmt);
@@ -407,13 +464,12 @@ static bool EqEnumVals(const std::pair<llvm::APSInt, EnumConstantDecl*>& lhs,
/// GetTypeBeforeIntegralPromotion - Returns the pre-promotion type of
/// potentially integral-promoted expression @p expr.
-static QualType GetTypeBeforeIntegralPromotion(const Expr* expr) {
- if (const CastExpr *ImplicitCast = dyn_cast<ImplicitCastExpr>(expr)) {
- const Expr *ExprBeforePromotion = ImplicitCast->getSubExpr();
- QualType TypeBeforePromotion = ExprBeforePromotion->getType();
- if (TypeBeforePromotion->isIntegralOrEnumerationType()) {
- return TypeBeforePromotion;
- }
+static QualType GetTypeBeforeIntegralPromotion(Expr *&expr) {
+ if (ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(expr))
+ expr = cleanups->getSubExpr();
+ while (ImplicitCastExpr *impcast = dyn_cast<ImplicitCastExpr>(expr)) {
+ if (impcast->getCastKind() != CK_IntegralCast) break;
+ expr = impcast->getSubExpr();
}
return expr->getType();
}
@@ -449,6 +505,11 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond,
if (CondResult.isInvalid()) return StmtError();
Cond = CondResult.take();
+ // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
+ CondResult = UsualUnaryConversions(Cond);
+ if (CondResult.isInvalid()) return StmtError();
+ Cond = CondResult.take();
+
if (!CondVar) {
CheckImplicitConversions(Cond, SwitchLoc);
CondResult = MaybeCreateExprWithCleanups(Cond);
@@ -482,21 +543,14 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
SS->setBody(BodyStmt, SwitchLoc);
getCurFunction()->SwitchStack.pop_back();
- if (SS->getCond() == 0)
- return StmtError();
-
Expr *CondExpr = SS->getCond();
- Expr *CondExprBeforePromotion = CondExpr;
- QualType CondTypeBeforePromotion =
- GetTypeBeforeIntegralPromotion(CondExpr);
+ if (!CondExpr) return StmtError();
- // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
- ExprResult CondResult = UsualUnaryConversions(CondExpr);
- if (CondResult.isInvalid())
- return StmtError();
- CondExpr = CondResult.take();
QualType CondType = CondExpr->getType();
- SS->setCond(CondExpr);
+
+ Expr *CondExprBeforePromotion = CondExpr;
+ QualType CondTypeBeforePromotion =
+ GetTypeBeforeIntegralPromotion(CondExprBeforePromotion);
// C++ 6.4.2.p2:
// Integral promotions are performed (on the switch condition).
@@ -533,7 +587,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// Accumulate all of the case values in a vector so that we can sort them
// and detect duplicates. This vector contains the APInt for the case after
// it has been converted to the condition type.
- typedef llvm::SmallVector<std::pair<llvm::APSInt, CaseStmt*>, 64> CaseValsTy;
+ typedef SmallVector<std::pair<llvm::APSInt, CaseStmt*>, 64> CaseValsTy;
CaseValsTy CaseVals;
// Keep track of any GNU case ranges we see. The APSInt is the low value.
@@ -572,7 +626,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
break;
}
- llvm::APSInt LoVal = Lo->EvaluateAsInt(Context);
+ llvm::APSInt LoVal = Lo->EvaluateKnownConstInt(Context);
// Convert the value to the same width/sign as the condition.
ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned,
@@ -651,7 +705,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
llvm::APSInt &LoVal = CaseRanges[i].first;
CaseStmt *CR = CaseRanges[i].second;
Expr *Hi = CR->getRHS();
- llvm::APSInt HiVal = Hi->EvaluateAsInt(Context);
+ llvm::APSInt HiVal = Hi->EvaluateKnownConstInt(Context);
// Convert the value to the same width/sign as the condition.
ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned,
@@ -750,7 +804,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// If switch has default case, then ignore it.
if (!CaseListIsErroneous && !HasConstantCond && ET) {
const EnumDecl *ED = ET->getDecl();
- typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64>
+ typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64>
EnumValsTy;
EnumValsTy EnumVals;
@@ -791,7 +845,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
<< ED->getDeclName();
}
- llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context);
+ llvm::APSInt Hi =
+ RI->second->getRHS()->EvaluateKnownConstInt(Context);
AdjustAPSInt(Hi, CondWidth, CondIsSigned);
while (EI != EIend && EI->first < Hi)
EI++;
@@ -806,7 +861,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
CaseRangesTy::const_iterator RI = CaseRanges.begin();
bool hasCasesNotInSwitch = false;
- llvm::SmallVector<DeclarationName,8> UnhandledNames;
+ SmallVector<DeclarationName,8> UnhandledNames;
for (EnumValsTy::const_iterator EI = EnumVals.begin(); EI != EIend; EI++){
// Drop unneeded case values
@@ -819,7 +874,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// Drop unneeded case ranges
for (; RI != CaseRanges.end(); RI++) {
- llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context);
+ llvm::APSInt Hi =
+ RI->second->getRHS()->EvaluateKnownConstInt(Context);
AdjustAPSInt(Hi, CondWidth, CondIsSigned);
if (EI->first <= Hi)
break;
@@ -965,6 +1021,76 @@ StmtResult Sema::ActOnForEachLValueExpr(Expr *E) {
return Owned(static_cast<Stmt*>(Result.get()));
}
+ExprResult
+Sema::ActOnObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) {
+ assert(collection);
+
+ // Bail out early if we've got a type-dependent expression.
+ if (collection->isTypeDependent()) return Owned(collection);
+
+ // Perform normal l-value conversion.
+ ExprResult result = DefaultFunctionArrayLvalueConversion(collection);
+ if (result.isInvalid())
+ return ExprError();
+ collection = result.take();
+
+ // The operand needs to have object-pointer type.
+ // TODO: should we do a contextual conversion?
+ const ObjCObjectPointerType *pointerType =
+ collection->getType()->getAs<ObjCObjectPointerType>();
+ if (!pointerType)
+ return Diag(forLoc, diag::err_collection_expr_type)
+ << collection->getType() << collection->getSourceRange();
+
+ // Check that the operand provides
+ // - countByEnumeratingWithState:objects:count:
+ const ObjCObjectType *objectType = pointerType->getObjectType();
+ ObjCInterfaceDecl *iface = objectType->getInterface();
+
+ // If we have a forward-declared type, we can't do this check.
+ if (iface && iface->isForwardDecl()) {
+ // This is ill-formed under ARC.
+ if (getLangOptions().ObjCAutoRefCount) {
+ Diag(forLoc, diag::err_arc_collection_forward)
+ << pointerType->getPointeeType() << collection->getSourceRange();
+ }
+
+ // Otherwise, if we have any useful type information, check that
+ // the type declares the appropriate method.
+ } else if (iface || !objectType->qual_empty()) {
+ IdentifierInfo *selectorIdents[] = {
+ &Context.Idents.get("countByEnumeratingWithState"),
+ &Context.Idents.get("objects"),
+ &Context.Idents.get("count")
+ };
+ Selector selector = Context.Selectors.getSelector(3, &selectorIdents[0]);
+
+ ObjCMethodDecl *method = 0;
+
+ // If there's an interface, look in both the public and private APIs.
+ if (iface) {
+ method = iface->lookupInstanceMethod(selector);
+ if (!method) method = LookupPrivateInstanceMethod(selector, iface);
+ }
+
+ // Also check protocol qualifiers.
+ if (!method)
+ method = LookupMethodInQualifiedType(selector, pointerType,
+ /*instance*/ true);
+
+ // If we didn't find it anywhere, give up.
+ if (!method) {
+ Diag(forLoc, diag::warn_collection_expr_type)
+ << collection->getType() << selector << collection->getSourceRange();
+ }
+
+ // TODO: check for an incompatible signature?
+ }
+
+ // Wrap up any cleanups in the expression.
+ return Owned(MaybeCreateExprWithCleanups(collection));
+}
+
StmtResult
Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
SourceLocation LParenLoc,
@@ -1000,38 +1126,7 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
Diag(ForLoc, diag::err_selector_element_type)
<< FirstType << First->getSourceRange();
}
- if (Second && !Second->isTypeDependent()) {
- ExprResult Result = DefaultFunctionArrayLvalueConversion(Second);
- if (Result.isInvalid())
- return StmtError();
- Second = Result.take();
- QualType SecondType = Second->getType();
- if (!SecondType->isObjCObjectPointerType())
- Diag(ForLoc, diag::err_collection_expr_type)
- << SecondType << Second->getSourceRange();
- else if (const ObjCObjectPointerType *OPT =
- SecondType->getAsObjCInterfacePointerType()) {
- llvm::SmallVector<IdentifierInfo *, 4> KeyIdents;
- IdentifierInfo* selIdent =
- &Context.Idents.get("countByEnumeratingWithState");
- KeyIdents.push_back(selIdent);
- selIdent = &Context.Idents.get("objects");
- KeyIdents.push_back(selIdent);
- selIdent = &Context.Idents.get("count");
- KeyIdents.push_back(selIdent);
- Selector CSelector = Context.Selectors.getSelector(3, &KeyIdents[0]);
- if (ObjCInterfaceDecl *IDecl = OPT->getInterfaceDecl()) {
- if (!IDecl->isForwardDecl() &&
- !IDecl->lookupInstanceMethod(CSelector) &&
- !LookupMethodInQualifiedType(CSelector, OPT, true)) {
- // Must further look into private implementation methods.
- if (!LookupPrivateInstanceMethod(CSelector, IDecl))
- Diag(ForLoc, diag::warn_collection_expr_type)
- << SecondType << CSelector << Second->getSourceRange();
- }
- }
- }
- }
+
return Owned(new (Context) ObjCForCollectionStmt(First, Second, Body,
ForLoc, RParenLoc));
}
@@ -1244,10 +1339,16 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
if (!BeginEndDecl.get() && !RangeVarType->isDependentType()) {
SourceLocation RangeLoc = RangeVar->getLocation();
- ExprResult RangeRef = BuildDeclRefExpr(RangeVar,
- RangeVarType.getNonReferenceType(),
- VK_LValue, ColonLoc);
- if (RangeRef.isInvalid())
+ const QualType RangeVarNonRefType = RangeVarType.getNonReferenceType();
+
+ ExprResult BeginRangeRef = BuildDeclRefExpr(RangeVar, RangeVarNonRefType,
+ VK_LValue, ColonLoc);
+ if (BeginRangeRef.isInvalid())
+ return StmtError();
+
+ ExprResult EndRangeRef = BuildDeclRefExpr(RangeVar, RangeVarNonRefType,
+ VK_LValue, ColonLoc);
+ if (EndRangeRef.isInvalid())
return StmtError();
QualType AutoType = Context.getAutoDeductType();
@@ -1275,8 +1376,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
// the program is ill-formed;
// begin-expr is __range.
- BeginExpr = RangeRef;
- if (FinishForRangeVarDecl(*this, BeginVar, RangeRef.get(), ColonLoc,
+ BeginExpr = BeginRangeRef;
+ if (FinishForRangeVarDecl(*this, BeginVar, BeginRangeRef.get(), ColonLoc,
diag::err_for_range_iter_deduction_failure)) {
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
return StmtError();
@@ -1294,12 +1395,11 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
else {
// Can't be a DependentSizedArrayType or an IncompleteArrayType since
// UnqAT is not incomplete and Range is not type-dependent.
- assert(0 && "Unexpected array type in for-range");
- return StmtError();
+ llvm_unreachable("Unexpected array type in for-range");
}
// end-expr is __range + __bound.
- EndExpr = ActOnBinOp(S, ColonLoc, tok::plus, RangeRef.get(),
+ EndExpr = ActOnBinOp(S, ColonLoc, tok::plus, EndRangeRef.get(),
BoundExpr.get());
if (EndExpr.isInvalid())
return StmtError();
@@ -1340,13 +1440,14 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
BeginExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, BeginVar,
BEF_begin, BeginNameInfo,
- BeginMemberLookup, RangeRef.get());
+ BeginMemberLookup,
+ BeginRangeRef.get());
if (BeginExpr.isInvalid())
return StmtError();
EndExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, EndVar,
BEF_end, EndNameInfo,
- EndMemberLookup, RangeRef.get());
+ EndMemberLookup, EndRangeRef.get());
if (EndExpr.isInvalid())
return StmtError();
}
@@ -1366,11 +1467,16 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
BuildDeclaratorGroup(BeginEndDecls, 2, /*TypeMayContainAuto=*/false);
BeginEndDecl = ActOnDeclStmt(BeginEndGroup, ColonLoc, ColonLoc);
- ExprResult BeginRef = BuildDeclRefExpr(BeginVar,
- BeginType.getNonReferenceType(),
+ const QualType BeginRefNonRefType = BeginType.getNonReferenceType();
+ ExprResult BeginRef = BuildDeclRefExpr(BeginVar, BeginRefNonRefType,
VK_LValue, ColonLoc);
+ if (BeginRef.isInvalid())
+ return StmtError();
+
ExprResult EndRef = BuildDeclRefExpr(EndVar, EndType.getNonReferenceType(),
VK_LValue, ColonLoc);
+ if (EndRef.isInvalid())
+ return StmtError();
// Build and check __begin != __end expression.
NotEqExpr = ActOnBinOp(S, ColonLoc, tok::exclaimequal,
@@ -1385,6 +1491,11 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
}
// Build and check ++__begin expression.
+ BeginRef = BuildDeclRefExpr(BeginVar, BeginRefNonRefType,
+ VK_LValue, ColonLoc);
+ if (BeginRef.isInvalid())
+ return StmtError();
+
IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get());
IncrExpr = ActOnFinishFullExpr(IncrExpr.get());
if (IncrExpr.isInvalid()) {
@@ -1393,6 +1504,11 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
}
// Build and check *__begin expression.
+ BeginRef = BuildDeclRefExpr(BeginVar, BeginRefNonRefType,
+ VK_LValue, ColonLoc);
+ if (BeginRef.isInvalid())
+ return StmtError();
+
ExprResult DerefExpr = ActOnUnaryOp(S, ColonLoc, tok::star, BeginRef.get());
if (DerefExpr.isInvalid()) {
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
@@ -1651,54 +1767,49 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// Otherwise, verify that this result type matches the previous one. We are
// pickier with blocks than for normal functions because we don't have GCC
// compatibility to worry about here.
- ReturnStmt *Result = 0;
- if (CurBlock->ReturnType->isVoidType()) {
- if (RetValExp && !RetValExp->isTypeDependent() &&
- (!getLangOptions().CPlusPlus || !RetValExp->getType()->isVoidType())) {
+ const VarDecl *NRVOCandidate = 0;
+ if (FnRetType->isDependentType()) {
+ // Delay processing for now. TODO: there are lots of dependent
+ // types we can conclusively prove aren't void.
+ } else if (FnRetType->isVoidType()) {
+ if (RetValExp &&
+ !(getLangOptions().CPlusPlus &&
+ (RetValExp->isTypeDependent() ||
+ RetValExp->getType()->isVoidType()))) {
Diag(ReturnLoc, diag::err_return_block_has_expr);
RetValExp = 0;
}
- Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0);
} else if (!RetValExp) {
- if (!CurBlock->ReturnType->isDependentType())
- return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr));
-
- Result = new (Context) ReturnStmt(ReturnLoc, 0, 0);
- } else {
- const VarDecl *NRVOCandidate = 0;
-
- if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
- // we have a non-void block with an expression, continue checking
-
- // 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
- // function return.
-
- // In C++ the return statement is handled via a copy initialization.
- // the C version of which boils down to CheckSingleAssignmentConstraints.
- NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false);
- InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc,
- FnRetType,
+ return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr));
+ } else if (!RetValExp->isTypeDependent()) {
+ // we have a non-void block with an expression, continue checking
+
+ // 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
+ // function return.
+
+ // In C++ the return statement is handled via a copy initialization.
+ // the C version of which boils down to CheckSingleAssignmentConstraints.
+ NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false);
+ InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc,
+ FnRetType,
NRVOCandidate != 0);
- ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate,
- FnRetType, RetValExp);
- if (Res.isInvalid()) {
- // FIXME: Cleanup temporaries here, anyway?
- return StmtError();
- }
-
- if (RetValExp) {
- CheckImplicitConversions(RetValExp, ReturnLoc);
- RetValExp = MaybeCreateExprWithCleanups(RetValExp);
- }
-
- RetValExp = Res.takeAs<Expr>();
- if (RetValExp)
- CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+ ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate,
+ FnRetType, RetValExp);
+ if (Res.isInvalid()) {
+ // FIXME: Cleanup temporaries here, anyway?
+ return StmtError();
}
+ RetValExp = Res.take();
+ CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+ }
- Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate);
+ if (RetValExp) {
+ CheckImplicitConversions(RetValExp, ReturnLoc);
+ RetValExp = MaybeCreateExprWithCleanups(RetValExp);
}
+ ReturnStmt *Result = new (Context) ReturnStmt(ReturnLoc, RetValExp,
+ NRVOCandidate);
// If we need to check for the named return value optimization, save the
// return statement in our scope for later processing.
@@ -1883,7 +1994,7 @@ static bool CheckAsmLValue(const Expr *E, Sema &S) {
/// isOperandMentioned - Return true if the specified operand # is mentioned
/// anywhere in the decomposed asm string.
static bool isOperandMentioned(unsigned OpNo,
- llvm::ArrayRef<AsmStmt::AsmStringPiece> AsmStrPieces) {
+ ArrayRef<AsmStmt::AsmStringPiece> AsmStrPieces) {
for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) {
const AsmStmt::AsmStringPiece &Piece = AsmStrPieces[p];
if (!Piece.isOperand()) continue;
@@ -1910,25 +2021,25 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
StringLiteral *AsmString = cast<StringLiteral>(asmString);
StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.get());
- llvm::SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
+ SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
// The parser verifies that there is a string literal here.
- if (AsmString->isWide())
+ if (!AsmString->isAscii())
return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character)
<< AsmString->getSourceRange());
for (unsigned i = 0; i != NumOutputs; i++) {
StringLiteral *Literal = Constraints[i];
- if (Literal->isWide())
+ if (!Literal->isAscii())
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
<< Literal->getSourceRange());
- llvm::StringRef OutputName;
+ StringRef OutputName;
if (Names[i])
OutputName = Names[i]->getName();
TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName);
- if (!Context.Target.validateOutputConstraint(Info))
+ if (!Context.getTargetInfo().validateOutputConstraint(Info))
return StmtError(Diag(Literal->getLocStart(),
diag::err_asm_invalid_output_constraint)
<< Info.getConstraintStr());
@@ -1944,20 +2055,20 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
OutputConstraintInfos.push_back(Info);
}
- llvm::SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
+ SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) {
StringLiteral *Literal = Constraints[i];
- if (Literal->isWide())
+ if (!Literal->isAscii())
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
<< Literal->getSourceRange());
- llvm::StringRef InputName;
+ StringRef InputName;
if (Names[i])
InputName = Names[i]->getName();
TargetInfo::ConstraintInfo Info(Literal->getString(), InputName);
- if (!Context.Target.validateInputConstraint(OutputConstraintInfos.data(),
+ if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos.data(),
NumOutputs, Info)) {
return StmtError(Diag(Literal->getLocStart(),
diag::err_asm_invalid_input_constraint)
@@ -1995,13 +2106,13 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
// Check that the clobbers are valid.
for (unsigned i = 0; i != NumClobbers; i++) {
StringLiteral *Literal = Clobbers[i];
- if (Literal->isWide())
+ if (!Literal->isAscii())
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
<< Literal->getSourceRange());
- llvm::StringRef Clobber = Literal->getString();
+ StringRef Clobber = Literal->getString();
- if (!Context.Target.isValidClobber(Clobber))
+ if (!Context.getTargetInfo().isValidClobber(Clobber))
return StmtError(Diag(Literal->getLocStart(),
diag::err_asm_unknown_register_name) << Clobber);
}
@@ -2012,7 +2123,7 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
AsmString, NumClobbers, Clobbers, RParenLoc);
// Validate the asm string, ensuring it makes sense given the operands we
// have.
- llvm::SmallVector<AsmStmt::AsmStringPiece, 8> Pieces;
+ SmallVector<AsmStmt::AsmStringPiece, 8> Pieces;
unsigned DiagOffs;
if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) {
Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID)
@@ -2033,6 +2144,10 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
unsigned InputOpNo = i+NumOutputs;
Expr *OutputExpr = Exprs[TiedTo];
Expr *InputExpr = Exprs[InputOpNo];
+
+ if (OutputExpr->isTypeDependent() || InputExpr->isTypeDependent())
+ continue;
+
QualType InTy = InputExpr->getType();
QualType OutTy = OutputExpr->getType();
if (Context.hasSameType(InTy, OutTy))
@@ -2154,6 +2269,7 @@ Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try,
StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc,
Expr *Throw) {
if (Throw) {
+ Throw = MaybeCreateExprWithCleanups(Throw);
ExprResult Result = DefaultLvalueConversion(Throw);
if (Result.isInvalid())
return StmtError();
@@ -2188,29 +2304,36 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw,
if (!AtCatchParent)
return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch));
}
-
+
return BuildObjCAtThrowStmt(AtLoc, Throw);
}
-StmtResult
-Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SyncExpr,
- Stmt *SyncBody) {
- getCurFunction()->setHasBranchProtectedScope();
-
- ExprResult Result = DefaultLvalueConversion(SyncExpr);
- if (Result.isInvalid())
- return StmtError();
+ExprResult
+Sema::ActOnObjCAtSynchronizedOperand(SourceLocation atLoc, Expr *operand) {
+ ExprResult result = DefaultLvalueConversion(operand);
+ if (result.isInvalid())
+ return ExprError();
+ operand = result.take();
- SyncExpr = Result.take();
// Make sure the expression type is an ObjC pointer or "void *".
- if (!SyncExpr->getType()->isDependentType() &&
- !SyncExpr->getType()->isObjCObjectPointerType()) {
- const PointerType *PT = SyncExpr->getType()->getAs<PointerType>();
- if (!PT || !PT->getPointeeType()->isVoidType())
- return StmtError(Diag(AtLoc, diag::error_objc_synchronized_expects_object)
- << SyncExpr->getType() << SyncExpr->getSourceRange());
+ QualType type = operand->getType();
+ if (!type->isDependentType() &&
+ !type->isObjCObjectPointerType()) {
+ const PointerType *pointerType = type->getAs<PointerType>();
+ if (!pointerType || !pointerType->getPointeeType()->isVoidType())
+ return Diag(atLoc, diag::error_objc_synchronized_expects_object)
+ << type << operand->getSourceRange();
}
+ // The operand to @synchronized is a full-expression.
+ return MaybeCreateExprWithCleanups(operand);
+}
+
+StmtResult
+Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SyncExpr,
+ Stmt *SyncBody) {
+ // We can't jump into or indirect-jump out of a @synchronized block.
+ getCurFunction()->setHasBranchProtectedScope();
return Owned(new (Context) ObjCAtSynchronizedStmt(AtLoc, SyncExpr, SyncBody));
}
@@ -2278,10 +2401,10 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
"The parser shouldn't call this if there are no handlers.");
Stmt **Handlers = RawHandlers.get();
- llvm::SmallVector<TypeWithHandler, 8> TypesWithHandlers;
+ SmallVector<TypeWithHandler, 8> TypesWithHandlers;
for (unsigned i = 0; i < NumHandlers; ++i) {
- CXXCatchStmt *Handler = llvm::cast<CXXCatchStmt>(Handlers[i]);
+ CXXCatchStmt *Handler = cast<CXXCatchStmt>(Handlers[i]);
if (!Handler->getExceptionDecl()) {
if (i < NumHandlers - 1)
return StmtError(Diag(Handler->getLocStart(),
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 3ac190e1d4c8..8dda34c8ab5d 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -344,10 +344,12 @@ void Sema::LookupTemplateName(LookupResult &Found,
if (FoundOuter.empty()) {
// - if the name is not found, the name found in the class of the
// object expression is used, otherwise
- } else if (!FoundOuter.getAsSingle<ClassTemplateDecl>()) {
+ } else if (!FoundOuter.getAsSingle<ClassTemplateDecl>() ||
+ FoundOuter.isAmbiguous()) {
// - if the name is found in the context of the entire
// postfix-expression and does not name a class template, the name
// found in the class of the object expression is used, otherwise
+ FoundOuter.clear();
} else if (!Found.isSuppressingDiagnostics()) {
// - if the name found is a class template, it must refer to the same
// entity as the one found in the class of the object expression,
@@ -422,7 +424,7 @@ bool Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) {
assert(PrevDecl->isTemplateParameter() && "Not a template parameter");
// Microsoft Visual C++ permits template parameters to be shadowed.
- if (getLangOptions().Microsoft)
+ if (getLangOptions().MicrosoftExt)
return false;
// C++ [temp.local]p4:
@@ -712,7 +714,7 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
/// has been parsed. S is the current scope.
Decl *Sema::ActOnTemplateTemplateParameter(Scope* S,
SourceLocation TmpLoc,
- TemplateParamsTy *Params,
+ TemplateParameterList *Params,
SourceLocation EllipsisLoc,
IdentifierInfo *Name,
SourceLocation NameLoc,
@@ -783,7 +785,7 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S,
/// ActOnTemplateParameterList - Builds a TemplateParameterList that
/// contains the template parameters in Params/NumParams.
-Sema::TemplateParamsTy *
+TemplateParameterList *
Sema::ActOnTemplateParameterList(unsigned Depth,
SourceLocation ExportLoc,
SourceLocation TemplateLoc,
@@ -809,7 +811,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr,
TemplateParameterList *TemplateParams,
- AccessSpecifier AS,
+ AccessSpecifier AS, SourceLocation ModulePrivateLoc,
unsigned NumOuterTemplateParamLists,
TemplateParameterList** OuterTemplateParamLists) {
assert(TemplateParams && TemplateParams->size() > 0 &&
@@ -844,6 +846,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (RequireCompleteDeclContext(SS, SemanticContext))
return true;
+ // If we're adding a template to a dependent context, we may need to
+ // rebuilding some of the types used within the template parameter list,
+ // now that we know what the current instantiation is.
+ if (SemanticContext->isDependentContext()) {
+ ContextRAII SavedContext(*this, SemanticContext);
+ if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams))
+ Invalid = true;
+ }
+
LookupQualifiedName(Previous, SemanticContext);
} else {
SemanticContext = CurContext;
@@ -943,7 +954,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// definition, as part of error recovery?
return true;
}
- }
+ }
} else if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(NameLoc, PrevDecl);
@@ -997,7 +1008,17 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
DeclarationName(Name), TemplateParams,
NewClass, PrevClassTemplate);
NewClass->setDescribedClassTemplate(NewTemplate);
-
+
+ if (PrevClassTemplate && PrevClassTemplate->isModulePrivate()) {
+ NewTemplate->setModulePrivate();
+ } else if (ModulePrivateLoc.isValid()) {
+ if (PrevClassTemplate && !PrevClassTemplate->isModulePrivate())
+ diagnoseModulePrivateRedeclaration(NewTemplate, PrevClassTemplate,
+ ModulePrivateLoc);
+ else
+ NewTemplate->setModulePrivate();
+ }
+
// Build the type for the class template declaration now.
QualType T = NewTemplate->getInjectedClassNameSpecialization();
T = Context.getInjectedClassNameType(NewClass, T);
@@ -1519,7 +1540,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
// The sequence of nested types to which we will match up the template
// parameter lists. We first build this list by starting with the type named
// by the nested-name-specifier and walking out until we run out of types.
- llvm::SmallVector<QualType, 4> NestedTypes;
+ SmallVector<QualType, 4> NestedTypes;
QualType T;
if (SS.getScopeRep()) {
if (CXXRecordDecl *Record
@@ -1888,7 +1909,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// Check that the template argument list is well-formed for this
// template.
- llvm::SmallVector<TemplateArgument, 4> Converted;
+ SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs,
false, Converted))
return QualType();
@@ -1995,7 +2016,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
Decl = ClassTemplateSpecializationDecl::Create(Context,
ClassTemplate->getTemplatedDecl()->getTagKind(),
ClassTemplate->getDeclContext(),
- ClassTemplate->getLocation(),
+ ClassTemplate->getTemplatedDecl()->getLocStart(),
ClassTemplate->getLocation(),
ClassTemplate,
Converted.data(),
@@ -2129,7 +2150,7 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs);
if (Result.isNull())
- return TypeResult();
+ return TypeResult(true);
// Check the tag kind
if (const RecordType *RT = Result->getAs<RecordType>()) {
@@ -2311,7 +2332,8 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
return TNK_Dependent_template_name;
case UnqualifiedId::IK_LiteralOperatorId:
- assert(false && "We don't support these; Parse shouldn't have allowed propagation");
+ llvm_unreachable(
+ "We don't support these; Parse shouldn't have allowed propagation");
default:
break;
@@ -2327,7 +2349,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
const TemplateArgumentLoc &AL,
- llvm::SmallVectorImpl<TemplateArgument> &Converted) {
+ SmallVectorImpl<TemplateArgument> &Converted) {
const TemplateArgument &Arg = AL.getArgument();
// Check template type parameter.
@@ -2408,7 +2430,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
TemplateTypeParmDecl *Param,
- llvm::SmallVectorImpl<TemplateArgument> &Converted) {
+ SmallVectorImpl<TemplateArgument> &Converted) {
TypeSourceInfo *ArgType = Param->getDefaultArgumentInfo();
// If the argument type is dependent, instantiate it now based
@@ -2461,7 +2483,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
NonTypeTemplateParmDecl *Param,
- llvm::SmallVectorImpl<TemplateArgument> &Converted) {
+ SmallVectorImpl<TemplateArgument> &Converted) {
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
Converted.data(), Converted.size());
@@ -2507,7 +2529,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
TemplateTemplateParmDecl *Param,
- llvm::SmallVectorImpl<TemplateArgument> &Converted,
+ SmallVectorImpl<TemplateArgument> &Converted,
NestedNameSpecifierLoc &QualifierLoc) {
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
Converted.data(), Converted.size());
@@ -2543,7 +2565,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
Decl *Param,
- llvm::SmallVectorImpl<TemplateArgument> &Converted) {
+ SmallVectorImpl<TemplateArgument> &Converted) {
if (TemplateTypeParmDecl *TypeParm = dyn_cast<TemplateTypeParmDecl>(Param)) {
if (!TypeParm->hasDefaultArgument())
return TemplateArgumentLoc();
@@ -2629,7 +2651,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
unsigned ArgumentPackIndex,
- llvm::SmallVectorImpl<TemplateArgument> &Converted,
+ SmallVectorImpl<TemplateArgument> &Converted,
CheckTemplateArgumentKind CTAK) {
// Check template type parameters.
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
@@ -2669,8 +2691,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
switch (Arg.getArgument().getKind()) {
case TemplateArgument::Null:
- assert(false && "Should never see a NULL template argument here");
- return true;
+ llvm_unreachable("Should never see a NULL template argument here");
case TemplateArgument::Expression: {
TemplateArgument Result;
@@ -2792,8 +2813,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
switch (Arg.getArgument().getKind()) {
case TemplateArgument::Null:
- assert(false && "Should never see a NULL template argument here");
- return true;
+ llvm_unreachable("Should never see a NULL template argument here");
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
@@ -2834,7 +2854,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs,
bool PartialTemplateArgs,
- llvm::SmallVectorImpl<TemplateArgument> &Converted) {
+ SmallVectorImpl<TemplateArgument> &Converted) {
TemplateParameterList *Params = Template->getTemplateParameters();
unsigned NumParams = Params->size();
unsigned NumArgs = TemplateArgs.size();
@@ -2871,7 +2891,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// corresponding parameter declared by the template in its
// template-parameter-list.
bool isTemplateTemplateParameter = isa<TemplateTemplateParmDecl>(Template);
- llvm::SmallVector<TemplateArgument, 2> ArgumentPack;
+ SmallVector<TemplateArgument, 2> ArgumentPack;
TemplateParameterList::iterator Param = Params->begin(),
ParamEnd = Params->end();
unsigned ArgIdx = 0;
@@ -3235,6 +3255,10 @@ bool UnnamedLocalNoLinkageFinder::VisitObjCObjectPointerType(
return false;
}
+bool UnnamedLocalNoLinkageFinder::VisitAtomicType(const AtomicType* T) {
+ return Visit(T->getValueType());
+}
+
bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) {
if (Tag->getDeclContext()->isFunctionOrMethod()) {
S.Diag(SR.getBegin(), diag::ext_template_arg_local_type)
@@ -3358,7 +3382,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
}
}
- if (S.getLangOptions().Microsoft && isa<CXXUuidofExpr>(Arg)) {
+ if (S.getLangOptions().MicrosoftExt && isa<CXXUuidofExpr>(Arg)) {
Converted = TemplateArgument(ArgIn);
return false;
}
@@ -3820,8 +3844,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
Converted = TemplateArgument(Value,
- ParamType->isEnumeralType() ? ParamType
- : IntegerType);
+ ParamType->isEnumeralType()
+ ? Context.getCanonicalType(ParamType)
+ : IntegerType);
return Owned(Arg);
}
@@ -3892,7 +3917,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
bool ObjCLifetimeConversion;
if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType(),
false, ObjCLifetimeConversion)) {
- Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)).take();
+ Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp,
+ Arg->getValueKind()).take();
} else if (!Context.hasSameUnqualifiedType(ArgType,
ParamType.getNonReferenceType())) {
// We can't perform this conversion.
@@ -3963,7 +3989,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// Types match exactly: nothing more to do here.
} else if (IsQualificationConversion(ArgType, ParamType, false,
ObjCLifetimeConversion)) {
- Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)).take();
+ Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp,
+ Arg->getValueKind()).take();
} else {
// We can't perform this conversion.
Diag(Arg->getSourceRange().getBegin(),
@@ -4131,10 +4158,22 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
assert(Arg.getKind() == TemplateArgument::Integral &&
"Operation is only valid for integral template arguments");
QualType T = Arg.getIntegralType();
- if (T->isCharType() || T->isWideCharType())
+ if (T->isAnyCharacterType()) {
+ CharacterLiteral::CharacterKind Kind;
+ if (T->isWideCharType())
+ Kind = CharacterLiteral::Wide;
+ else if (T->isChar16Type())
+ Kind = CharacterLiteral::UTF16;
+ else if (T->isChar32Type())
+ Kind = CharacterLiteral::UTF32;
+ else
+ Kind = CharacterLiteral::Ascii;
+
return Owned(new (Context) CharacterLiteral(
- Arg.getAsIntegral()->getZExtValue(),
- T->isWideCharType(), T, Loc));
+ Arg.getAsIntegral()->getZExtValue(),
+ Kind, T, Loc));
+ }
+
if (T->isBooleanType())
return Owned(new (Context) CXXBoolLiteralExpr(
Arg.getAsIntegral()->getBoolValue(),
@@ -4496,9 +4535,18 @@ static bool CheckTemplateSpecializationScope(Sema &S,
}
if (S.CurContext->isRecord() && !IsPartialSpecialization) {
- S.Diag(Loc, diag::err_template_spec_decl_class_scope)
- << Specialized;
- return true;
+ if (S.getLangOptions().MicrosoftExt) {
+ // Do not warn for class scope explicit specialization during
+ // instantiation, warning was already emitted during pattern
+ // semantic analysis.
+ if (!S.ActiveTemplateInstantiations.size())
+ S.Diag(Loc, diag::ext_function_specialization_in_class)
+ << Specialized;
+ } else {
+ S.Diag(Loc, diag::err_template_spec_decl_class_scope)
+ << Specialized;
+ return true;
+ }
}
// C++ [temp.class.spec]p6:
@@ -4653,7 +4701,7 @@ static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S,
/// \returns true if there was an error, false otherwise.
static bool CheckClassTemplatePartialSpecializationArgs(Sema &S,
TemplateParameterList *TemplateParams,
- llvm::SmallVectorImpl<TemplateArgument> &TemplateArgs) {
+ SmallVectorImpl<TemplateArgument> &TemplateArgs) {
const TemplateArgument *ArgList = TemplateArgs.data();
for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
@@ -4691,6 +4739,7 @@ DeclResult
Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
TagUseKind TUK,
SourceLocation KWLoc,
+ SourceLocation ModulePrivateLoc,
CXXScopeSpec &SS,
TemplateTy TemplateD,
SourceLocation TemplateNameLoc,
@@ -4821,7 +4870,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// Check that the template argument list is well-formed for this
// template.
- llvm::SmallVector<TemplateArgument, 4> Converted;
+ SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc,
TemplateArgs, false, Converted))
return true;
@@ -4907,14 +4956,14 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// -- The argument list of the specialization shall not be identical
// to the implicit argument list of the primary template.
Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template)
- << (TUK == TUK_Definition)
- << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc));
+ << (TUK == TUK_Definition)
+ << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc));
return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS,
ClassTemplate->getIdentifier(),
TemplateNameLoc,
Attr,
TemplateParams,
- AS_none,
+ AS_none, /*ModulePrivateLoc=*/SourceLocation(),
TemplateParameterLists.size() - 1,
(TemplateParameterList**) TemplateParameterLists.release());
}
@@ -4956,7 +5005,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// partial specialization are deducible from the template
// arguments. If not, this class template partial specialization
// will never be used.
- llvm::SmallVector<bool, 8> DeducibleParams;
+ SmallVector<bool, 8> DeducibleParams;
DeducibleParams.resize(TemplateParams->size());
MarkUsedTemplateParameters(Partial->getTemplateArgs(), true,
TemplateParams->getDepth(),
@@ -5056,6 +5105,11 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
if (Attr)
ProcessDeclAttributeList(S, Specialization, Attr);
+ if (ModulePrivateLoc.isValid())
+ Diag(Specialization->getLocation(), diag::err_module_private_specialization)
+ << (isPartialSpecialization? 1 : 0)
+ << FixItHint::CreateRemoval(ModulePrivateLoc);
+
// Build the fully-sugared type for this class template
// specialization as the user wrote in the specialization
// itself. This means that we'll pretty-print the type retrieved
@@ -5105,7 +5159,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
Decl *Sema::ActOnTemplateDeclarator(Scope *S,
MultiTemplateParamsArg TemplateParameterLists,
Declarator &D) {
- return HandleDeclarator(S, D, move(TemplateParameterLists), false);
+ return HandleDeclarator(S, D, move(TemplateParameterLists));
}
Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
@@ -5120,9 +5174,9 @@ Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
Scope *ParentScope = FnBodyScope->getParent();
+ D.setFunctionDefinition(true);
Decl *DP = HandleDeclarator(ParentScope, D,
- move(TemplateParameterLists),
- /*IsFunctionDefinition=*/true);
+ move(TemplateParameterLists));
if (FunctionTemplateDecl *FunctionTemplate
= dyn_cast_or_null<FunctionTemplateDecl>(DP))
return ActOnStartOfFunctionDef(FnBodyScope,
@@ -5176,8 +5230,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
switch (NewTSK) {
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
- assert(false && "Don't check implicit instantiations here");
- return false;
+ llvm_unreachable("Don't check implicit instantiations here");
case TSK_ExplicitSpecialization:
switch (PrevTSK) {
@@ -5309,9 +5362,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
break;
}
- assert(false && "Missing specialization/instantiation case?");
-
- return false;
+ llvm_unreachable("Missing specialization/instantiation case?");
}
/// \brief Perform semantic analysis for the given dependent function
@@ -5482,12 +5533,10 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// Take copies of (semantic and syntactic) template argument lists.
const TemplateArgumentList* TemplArgs = new (Context)
TemplateArgumentList(Specialization->getTemplateSpecializationArgs());
- const TemplateArgumentListInfo* TemplArgsAsWritten = ExplicitTemplateArgs
- ? new (Context) TemplateArgumentListInfo(*ExplicitTemplateArgs) : 0;
FD->setFunctionTemplateSpecialization(Specialization->getPrimaryTemplate(),
TemplArgs, /*InsertPos=*/0,
SpecInfo->getTemplateSpecializationKind(),
- TemplArgsAsWritten);
+ ExplicitTemplateArgs);
FD->setStorageClass(Specialization->getStorageClass());
// The "previous declaration" for this function template specialization is
@@ -5793,7 +5842,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// Check that the template argument list is well-formed for this
// template.
- llvm::SmallVector<TemplateArgument, 4> Converted;
+ SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc,
TemplateArgs, false, Converted))
return true;
@@ -5949,6 +5998,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
bool IsDependent = false;
Decl *TagD = ActOnTag(S, TagSpec, Sema::TUK_Reference,
KWLoc, SS, Name, NameLoc, Attr, AS_none,
+ /*ModulePrivateLoc=*/SourceLocation(),
MultiTemplateParamsArg(*this, 0, 0),
Owned, IsDependent, false, false,
TypeResult());
@@ -6114,9 +6164,12 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (D.getDeclSpec().isInlineSpecified() && getLangOptions().CPlusPlus0x)
Diag(D.getDeclSpec().getInlineSpecLoc(),
diag::err_explicit_instantiation_inline)
- <<FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc());
-
- // FIXME: check for constexpr specifier.
+ << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc());
+ if (D.getDeclSpec().isConstexprSpecified())
+ // FIXME: Add a fix-it to remove the 'constexpr' and add a 'const' if one is
+ // not already specified.
+ Diag(D.getDeclSpec().getConstexprSpecLoc(),
+ diag::err_explicit_instantiation_constexpr);
// C++0x [temp.explicit]p2:
// There are two forms of explicit instantiation: an explicit instantiation
@@ -6658,6 +6711,45 @@ bool Sema::RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS) {
return false;
}
+/// \brief Rebuild the template parameters now that we know we're in a current
+/// instantiation.
+bool Sema::RebuildTemplateParamsInCurrentInstantiation(
+ TemplateParameterList *Params) {
+ for (unsigned I = 0, N = Params->size(); I != N; ++I) {
+ Decl *Param = Params->getParam(I);
+
+ // There is nothing to rebuild in a type parameter.
+ if (isa<TemplateTypeParmDecl>(Param))
+ continue;
+
+ // Rebuild the template parameter list of a template template parameter.
+ if (TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(Param)) {
+ if (RebuildTemplateParamsInCurrentInstantiation(
+ TTP->getTemplateParameters()))
+ return true;
+
+ continue;
+ }
+
+ // Rebuild the type of a non-type template parameter.
+ NonTypeTemplateParmDecl *NTTP = cast<NonTypeTemplateParmDecl>(Param);
+ TypeSourceInfo *NewTSI
+ = RebuildTypeInCurrentInstantiation(NTTP->getTypeSourceInfo(),
+ NTTP->getLocation(),
+ NTTP->getDeclName());
+ if (!NewTSI)
+ return true;
+
+ if (NewTSI != NTTP->getTypeSourceInfo()) {
+ NTTP->setTypeSourceInfo(NewTSI);
+ NTTP->setType(NewTSI->getType());
+ }
+ }
+
+ return false;
+}
+
/// \brief Produces a formatted string that describes the binding of
/// template parameters to template arguments.
std::string
@@ -6692,7 +6784,7 @@ Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params,
}
Out << " = ";
- Args[I].print(Context.PrintingPolicy, Out);
+ Args[I].print(getPrintingPolicy(), Out);
}
Out << ']';
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index dcb4ff286060..93ea89d6285d 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -85,7 +85,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateArgument &Param,
TemplateArgument Arg,
TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced);
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced);
/// \brief Whether template argument deduction for two reference parameters
/// resulted in the argument type, parameter type, or neither type being more
@@ -117,10 +117,10 @@ DeduceTemplateArguments(Sema &S,
QualType Param,
QualType Arg,
TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned TDF,
bool PartialOrdering = false,
- llvm::SmallVectorImpl<RefParamPartialOrderingComparison> *
+ SmallVectorImpl<RefParamPartialOrderingComparison> *
RefParamComparisons = 0);
static Sema::TemplateDeductionResult
@@ -129,7 +129,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateArgument *Params, unsigned NumParams,
const TemplateArgument *Args, unsigned NumArgs,
TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool NumberOfArgumentsMustMatch = true);
/// \brief If the given expression is of a form that permits the deduction
@@ -288,7 +288,7 @@ DeduceNonTypeTemplateArgument(Sema &S,
llvm::APSInt Value, QualType ValueType,
bool DeducedFromArrayBound,
TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
@@ -316,7 +316,7 @@ DeduceNonTypeTemplateArgument(Sema &S,
NonTypeTemplateParmDecl *NTTP,
Expr *Value,
TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
assert((Value->isTypeDependent() || Value->isValueDependent()) &&
@@ -347,7 +347,7 @@ DeduceNonTypeTemplateArgument(Sema &S,
NonTypeTemplateParmDecl *NTTP,
Decl *D,
TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
@@ -372,7 +372,7 @@ DeduceTemplateArguments(Sema &S,
TemplateName Param,
TemplateName Arg,
TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
TemplateDecl *ParamDecl = Param.getAsTemplateDecl();
if (!ParamDecl) {
// The parameter type is dependent and is not a template template parameter,
@@ -431,7 +431,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateSpecializationType *Param,
QualType Arg,
TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(Arg.isCanonical() && "Argument type must be canonical");
// Check whether the template argument is a dependent template-id.
@@ -546,11 +546,11 @@ static TemplateParameter makeTemplateParameter(Decl *D) {
/// \brief Prepare to perform template argument deduction for all of the
/// arguments in a set of argument packs.
static void PrepareArgumentPackDeduction(Sema &S,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- const llvm::SmallVectorImpl<unsigned> &PackIndices,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &SavedPacks,
- llvm::SmallVectorImpl<
- llvm::SmallVector<DeducedTemplateArgument, 4> > &NewlyDeducedPacks) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ const SmallVectorImpl<unsigned> &PackIndices,
+ SmallVectorImpl<DeducedTemplateArgument> &SavedPacks,
+ SmallVectorImpl<
+ SmallVector<DeducedTemplateArgument, 4> > &NewlyDeducedPacks) {
// Save the deduced template arguments for each parameter pack expanded
// by this pack expansion, then clear out the deduction.
for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
@@ -581,11 +581,11 @@ static Sema::TemplateDeductionResult
FinishArgumentPackDeduction(Sema &S,
TemplateParameterList *TemplateParams,
bool HasAnyArguments,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- const llvm::SmallVectorImpl<unsigned> &PackIndices,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &SavedPacks,
- llvm::SmallVectorImpl<
- llvm::SmallVector<DeducedTemplateArgument, 4> > &NewlyDeducedPacks,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ const SmallVectorImpl<unsigned> &PackIndices,
+ SmallVectorImpl<DeducedTemplateArgument> &SavedPacks,
+ SmallVectorImpl<
+ SmallVector<DeducedTemplateArgument, 4> > &NewlyDeducedPacks,
TemplateDeductionInfo &Info) {
// Build argument packs for each of the parameter packs expanded by this
// pack expansion.
@@ -668,10 +668,10 @@ DeduceTemplateArguments(Sema &S,
const QualType *Params, unsigned NumParams,
const QualType *Args, unsigned NumArgs,
TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned TDF,
bool PartialOrdering = false,
- llvm::SmallVectorImpl<RefParamPartialOrderingComparison> *
+ SmallVectorImpl<RefParamPartialOrderingComparison> *
RefParamComparisons = 0) {
// Fast-path check to see if we have too many/too few arguments.
if (NumParams != NumArgs &&
@@ -733,11 +733,11 @@ DeduceTemplateArguments(Sema &S,
// Compute the set of template parameter indices that correspond to
// parameter packs expanded by the pack expansion.
- llvm::SmallVector<unsigned, 2> PackIndices;
+ SmallVector<unsigned, 2> PackIndices;
QualType Pattern = Expansion->getPattern();
{
llvm::BitVector SawIndices(TemplateParams->size());
- llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
unsigned Depth, Index;
@@ -753,9 +753,9 @@ DeduceTemplateArguments(Sema &S,
// Keep track of the deduced template arguments for each parameter pack
// expanded by this pack expansion (the outer index) and for each
// template argument (the inner SmallVectors).
- llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2>
+ SmallVector<SmallVector<DeducedTemplateArgument, 4>, 2>
NewlyDeducedPacks(PackIndices.size());
- llvm::SmallVector<DeducedTemplateArgument, 2>
+ SmallVector<DeducedTemplateArgument, 2>
SavedPacks(PackIndices.size());
PrepareArgumentPackDeduction(S, Deduced, PackIndices, SavedPacks,
NewlyDeducedPacks);
@@ -862,10 +862,10 @@ DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
QualType ParamIn, QualType ArgIn,
TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned TDF,
bool PartialOrdering,
- llvm::SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) {
+ SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) {
// We only want to look at the canonical types, since typedefs and
// sugar are not part of template argument deduction.
QualType Param = S.Context.getCanonicalType(ParamIn);
@@ -977,6 +977,10 @@ DeduceTemplateArguments(Sema &S,
// cv-list T
if (const TemplateTypeParmType *TemplateTypeParm
= Param->getAs<TemplateTypeParmType>()) {
+ // Just skip any attempts to deduce from a placeholder type.
+ if (Arg->isPlaceholderType())
+ return Sema::TDK_Success;
+
unsigned Index = TemplateTypeParm->getIndex();
bool RecanonicalizeArg = false;
@@ -1018,6 +1022,17 @@ DeduceTemplateArguments(Sema &S,
DeducedQs.removeObjCLifetime();
// Objective-C ARC:
+ // If template deduction would produce a lifetime qualifier on a type
+ // that is not a lifetime type, template argument deduction fails.
+ if (ParamQs.hasObjCLifetime() && !DeducedType->isObjCLifetimeType() &&
+ !DeducedType->isDependentType()) {
+ Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
+ Info.FirstArg = TemplateArgument(Param);
+ Info.SecondArg = TemplateArgument(Arg);
+ return Sema::TDK_Underqualified;
+ }
+
+ // Objective-C ARC:
// If template deduction would produce an argument type with lifetime type
// but no lifetime qualifier, the __strong lifetime qualifier is inferred.
if (S.getLangOptions().ObjCAutoRefCount &&
@@ -1101,7 +1116,17 @@ DeduceTemplateArguments(Sema &S,
Info, Deduced, TDF);
return Sema::TDK_NonDeducedMismatch;
-
+
+ // _Atomic T [extension]
+ case Type::Atomic:
+ if (const AtomicType *AtomicArg = Arg->getAs<AtomicType>())
+ return DeduceTemplateArguments(S, TemplateParams,
+ cast<AtomicType>(Param)->getValueType(),
+ AtomicArg->getValueType(),
+ Info, Deduced, TDF);
+
+ return Sema::TDK_NonDeducedMismatch;
+
// T *
case Type::Pointer: {
QualType PointeeType;
@@ -1306,10 +1331,10 @@ DeduceTemplateArguments(Sema &S,
// Visited contains the set of nodes we have already visited, while
// ToVisit is our stack of records that we still need to visit.
llvm::SmallPtrSet<const RecordType *, 8> Visited;
- llvm::SmallVector<const RecordType *, 8> ToVisit;
+ SmallVector<const RecordType *, 8> ToVisit;
ToVisit.push_back(RecordT);
bool Successful = false;
- llvm::SmallVectorImpl<DeducedTemplateArgument> DeducedOrig(0);
+ SmallVectorImpl<DeducedTemplateArgument> DeducedOrig(0);
DeducedOrig = Deduced;
while (!ToVisit.empty()) {
// Retrieve the next class in the inheritance hierarchy.
@@ -1515,7 +1540,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateArgument &Param,
TemplateArgument Arg,
TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
// If the template argument is a pack expansion, perform template argument
// deduction against the pattern of that expansion. This only occurs during
// partial ordering.
@@ -1524,8 +1549,7 @@ DeduceTemplateArguments(Sema &S,
switch (Param.getKind()) {
case TemplateArgument::Null:
- assert(false && "Null template argument in parameter list");
- break;
+ llvm_unreachable("Null template argument in parameter list");
case TemplateArgument::Type:
if (Arg.getKind() == TemplateArgument::Type)
@@ -1667,7 +1691,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateArgument *Params, unsigned NumParams,
const TemplateArgument *Args, unsigned NumArgs,
TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool NumberOfArgumentsMustMatch) {
// C++0x [temp.deduct.type]p9:
// If the template argument list of P contains a pack expansion that is not
@@ -1720,10 +1744,10 @@ DeduceTemplateArguments(Sema &S,
// Compute the set of template parameter indices that correspond to
// parameter packs expanded by the pack expansion.
- llvm::SmallVector<unsigned, 2> PackIndices;
+ SmallVector<unsigned, 2> PackIndices;
{
llvm::BitVector SawIndices(TemplateParams->size());
- llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
unsigned Depth, Index;
@@ -1742,9 +1766,9 @@ DeduceTemplateArguments(Sema &S,
// Save the deduced template arguments for each parameter pack expanded
// by this pack expansion, then clear out the deduction.
- llvm::SmallVector<DeducedTemplateArgument, 2>
+ SmallVector<DeducedTemplateArgument, 2>
SavedPacks(PackIndices.size());
- llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2>
+ SmallVector<SmallVector<DeducedTemplateArgument, 4>, 2>
NewlyDeducedPacks(PackIndices.size());
PrepareArgumentPackDeduction(S, Deduced, PackIndices, SavedPacks,
NewlyDeducedPacks);
@@ -1799,7 +1823,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateArgumentList &ParamList,
const TemplateArgumentList &ArgList,
TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
return DeduceTemplateArguments(S, TemplateParams,
ParamList.data(), ParamList.size(),
ArgList.data(), ArgList.size(),
@@ -1815,8 +1839,7 @@ static bool isSameTemplateArg(ASTContext &Context,
switch (X.getKind()) {
case TemplateArgument::Null:
- assert(false && "Comparing NULL template argument");
- break;
+ llvm_unreachable("Comparing NULL template argument");
case TemplateArgument::Type:
return Context.getCanonicalType(X.getAsType()) ==
@@ -1940,11 +1963,11 @@ static bool ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
unsigned ArgumentPackIndex,
TemplateDeductionInfo &Info,
bool InFunctionTemplate,
- llvm::SmallVectorImpl<TemplateArgument> &Output) {
+ SmallVectorImpl<TemplateArgument> &Output) {
if (Arg.getKind() == TemplateArgument::Pack) {
// This is a template argument pack, so check each of its arguments against
// the template parameter.
- llvm::SmallVector<TemplateArgument, 2> PackedArgsBuilder;
+ SmallVector<TemplateArgument, 2> PackedArgsBuilder;
for (TemplateArgument::pack_iterator PA = Arg.pack_begin(),
PAEnd = Arg.pack_end();
PA != PAEnd; ++PA) {
@@ -1996,7 +2019,7 @@ static Sema::TemplateDeductionResult
FinishTemplateArgumentDeduction(Sema &S,
ClassTemplatePartialSpecializationDecl *Partial,
const TemplateArgumentList &TemplateArgs,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
TemplateDeductionInfo &Info) {
// Trap errors.
Sema::SFINAETrap Trap(S);
@@ -2006,7 +2029,7 @@ FinishTemplateArgumentDeduction(Sema &S,
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
- llvm::SmallVector<TemplateArgument, 4> Builder;
+ SmallVector<TemplateArgument, 4> Builder;
TemplateParameterList *PartialParams = Partial->getTemplateParameters();
for (unsigned I = 0, N = PartialParams->size(); I != N; ++I) {
NamedDecl *Param = PartialParams->getParam(I);
@@ -2089,7 +2112,7 @@ FinishTemplateArgumentDeduction(Sema &S,
return Sema::TDK_SubstitutionFailure;
}
- llvm::SmallVector<TemplateArgument, 4> ConvertedInstArgs;
+ SmallVector<TemplateArgument, 4> ConvertedInstArgs;
if (S.CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(),
InstArgs, false, ConvertedInstArgs))
return Sema::TDK_SubstitutionFailure;
@@ -2125,7 +2148,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
// specialization can be deduced from the actual template argument
// list (14.8.2).
SFINAETrap Trap(*this);
- llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
+ SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(Partial->getTemplateParameters()->size());
if (TemplateDeductionResult Result
= ::DeduceTemplateArguments(*this,
@@ -2183,8 +2206,8 @@ Sema::TemplateDeductionResult
Sema::SubstituteExplicitTemplateArguments(
FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentListInfo &ExplicitTemplateArgs,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- llvm::SmallVectorImpl<QualType> &ParamTypes,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ SmallVectorImpl<QualType> &ParamTypes,
QualType *FunctionType,
TemplateDeductionInfo &Info) {
FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
@@ -2214,7 +2237,7 @@ Sema::SubstituteExplicitTemplateArguments(
// declaration order of their corresponding template-parameters. The
// template argument list shall not specify more template-arguments than
// there are corresponding template-parameters.
- llvm::SmallVector<TemplateArgument, 4> Builder;
+ SmallVector<TemplateArgument, 4> Builder;
// Enter a new template instantiation context where we check the
// explicitly-specified template arguments against this function template,
@@ -2420,11 +2443,11 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
/// which the deduced argument types should be compared.
Sema::TemplateDeductionResult
Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
- llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned NumExplicitlySpecified,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs) {
+ SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs) {
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
@@ -2446,7 +2469,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
- llvm::SmallVector<TemplateArgument, 4> Builder;
+ SmallVector<TemplateArgument, 4> Builder;
for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
NamedDecl *Param = TemplateParams->getParam(I);
@@ -2566,7 +2589,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
Specialization = cast_or_null<FunctionDecl>(
SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner,
MultiLevelTemplateArgumentList(*DeducedArgumentList)));
- if (!Specialization)
+ if (!Specialization || Specialization->isInvalidDecl())
return TDK_SubstitutionFailure;
assert(Specialization->getPrimaryTemplate()->getCanonicalDecl() ==
@@ -2578,6 +2601,14 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
!Trap.hasErrorOccurred())
Info.take();
+ // There may have been an error that did not prevent us from constructing a
+ // declaration. Mark the declaration invalid and return with a substitution
+ // failure.
+ if (Trap.hasErrorOccurred()) {
+ Specialization->setInvalidDecl(true);
+ return TDK_SubstitutionFailure;
+ }
+
if (OriginalCallArgs) {
// C++ [temp.deduct.call]p4:
// In general, the deduction process attempts to find template argument
@@ -2596,20 +2627,12 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
}
}
- // There may have been an error that did not prevent us from constructing a
- // declaration. Mark the declaration invalid and return with a substitution
- // failure.
- if (Trap.hasErrorOccurred()) {
- Specialization->setInvalidDecl(true);
- return TDK_SubstitutionFailure;
- }
-
// If we suppressed any diagnostics while performing template argument
// deduction, and if we haven't already instantiated this declaration,
// keep track of these diagnostics. They'll be emitted if this specialization
// is actually used.
if (Info.diag_begin() != Info.diag_end()) {
- llvm::DenseMap<Decl *, llvm::SmallVector<PartialDiagnosticAt, 1> >::iterator
+ llvm::DenseMap<Decl *, SmallVector<PartialDiagnosticAt, 1> >::iterator
Pos = SuppressedDiagnostics.find(Specialization->getCanonicalDecl());
if (Pos == SuppressedDiagnostics.end())
SuppressedDiagnostics[Specialization->getCanonicalDecl()]
@@ -2710,7 +2733,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
// Type deduction is done independently for each P/A pair, and
// the deduced template argument values are then combined.
// So we do not reject deductions which were made elsewhere.
- llvm::SmallVector<DeducedTemplateArgument, 8>
+ SmallVector<DeducedTemplateArgument, 8>
Deduced(TemplateParams->size());
TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc());
Sema::TemplateDeductionResult Result
@@ -2900,8 +2923,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
LocalInstantiationScope InstScope(*this);
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
- llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
- llvm::SmallVector<QualType, 4> ParamTypes;
+ SmallVector<DeducedTemplateArgument, 4> Deduced;
+ SmallVector<QualType, 4> ParamTypes;
unsigned NumExplicitlySpecified = 0;
if (ExplicitTemplateArgs) {
TemplateDeductionResult Result =
@@ -2924,7 +2947,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// Deduce template arguments from the function parameters.
Deduced.resize(TemplateParams->size());
unsigned ArgIdx = 0;
- llvm::SmallVector<OriginalCallArg, 4> OriginalCallArgs;
+ SmallVector<OriginalCallArg, 4> OriginalCallArgs;
for (unsigned ParamIdx = 0, NumParams = ParamTypes.size();
ParamIdx != NumParams; ++ParamIdx) {
QualType OrigParamType = ParamTypes[ParamIdx];
@@ -2946,16 +2969,19 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
TDF))
continue;
+ // If we have nothing to deduce, we're done.
+ if (!hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType))
+ continue;
+
// Keep track of the argument type and corresponding parameter index,
// so we can check for compatibility between the deduced A and A.
- if (hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType))
- OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx-1,
- ArgType));
+ OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx-1,
+ ArgType));
if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(*this, TemplateParams,
- ParamType, ArgType, Info, Deduced,
- TDF))
+ = ::DeduceTemplateArguments(*this, TemplateParams,
+ ParamType, ArgType, Info, Deduced,
+ TDF))
return Result;
continue;
@@ -2974,10 +3000,10 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
break;
QualType ParamPattern = ParamExpansion->getPattern();
- llvm::SmallVector<unsigned, 2> PackIndices;
+ SmallVector<unsigned, 2> PackIndices;
{
llvm::BitVector SawIndices(TemplateParams->size());
- llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
collectUnexpandedParameterPacks(ParamPattern, Unexpanded);
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
unsigned Depth, Index;
@@ -2993,9 +3019,9 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// Keep track of the deduced template arguments for each parameter pack
// expanded by this pack expansion (the outer index) and for each
// template argument (the inner SmallVectors).
- llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2>
+ SmallVector<SmallVector<DeducedTemplateArgument, 4>, 2>
NewlyDeducedPacks(PackIndices.size());
- llvm::SmallVector<DeducedTemplateArgument, 2>
+ SmallVector<DeducedTemplateArgument, 2>
SavedPacks(PackIndices.size());
PrepareArgumentPackDeduction(*this, Deduced, PackIndices, SavedPacks,
NewlyDeducedPacks);
@@ -3095,9 +3121,9 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// Substitute any explicit template arguments.
LocalInstantiationScope InstScope(*this);
- llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
+ SmallVector<DeducedTemplateArgument, 4> Deduced;
unsigned NumExplicitlySpecified = 0;
- llvm::SmallVector<QualType, 4> ParamTypes;
+ SmallVector<QualType, 4> ParamTypes;
if (ExplicitTemplateArgs) {
if (TemplateDeductionResult Result
= SubstituteExplicitTemplateArguments(FunctionTemplate,
@@ -3205,7 +3231,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// A) as described in 14.8.2.4.
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
- llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
+ SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(TemplateParams->size());
// C++0x [temp.deduct.conv]p4:
@@ -3226,7 +3252,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// both P and A are pointers or member pointers. In this case, we
// just ignore cv-qualifiers completely).
if ((P->isPointerType() && A->isPointerType()) ||
- (P->isMemberPointerType() && P->isMemberPointerType()))
+ (P->isMemberPointerType() && A->isMemberPointerType()))
TDF |= TDF_IgnoreQualifiers;
if (TemplateDeductionResult Result
= ::DeduceTemplateArguments(*this, TemplateParams,
@@ -3342,7 +3368,7 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *Init,
QualType FuncParam = FuncParamInfo->getType();
// Deduce type of TemplParam in Func(Init)
- llvm::SmallVector<DeducedTemplateArgument, 1> Deduced;
+ SmallVector<DeducedTemplateArgument, 1> Deduced;
Deduced.resize(1);
QualType InitType = Init->getType();
unsigned TDF = 0;
@@ -3380,12 +3406,12 @@ static void
MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
bool OnlyDeduced,
unsigned Level,
- llvm::SmallVectorImpl<bool> &Deduced);
+ SmallVectorImpl<bool> &Deduced);
/// \brief If this is a non-static member function,
static void MaybeAddImplicitObjectParameterType(ASTContext &Context,
CXXMethodDecl *Method,
- llvm::SmallVectorImpl<QualType> &ArgTypes) {
+ SmallVectorImpl<QualType> &ArgTypes) {
if (Method->isStatic())
return;
@@ -3414,7 +3440,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
FunctionTemplateDecl *FT2,
TemplatePartialOrderingContext TPOC,
unsigned NumCallArguments,
- llvm::SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) {
+ SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) {
FunctionDecl *FD1 = FT1->getTemplatedDecl();
FunctionDecl *FD2 = FT2->getTemplatedDecl();
const FunctionProtoType *Proto1 = FD1->getType()->getAs<FunctionProtoType>();
@@ -3422,7 +3448,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
assert(Proto1 && Proto2 && "Function templates must have prototypes");
TemplateParameterList *TemplateParams = FT2->getTemplateParameters();
- llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
+ SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(TemplateParams->size());
// C++0x [temp.deduct.partial]p3:
@@ -3454,7 +3480,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
// C++98/03 doesn't have this provision, so instead we drop the
// first argument of the free function or static member, which
// seems to match existing practice.
- llvm::SmallVector<QualType, 4> Args1;
+ SmallVector<QualType, 4> Args1;
unsigned Skip1 = !S.getLangOptions().CPlusPlus0x &&
IsNonStatic2 && !IsNonStatic1;
if (S.getLangOptions().CPlusPlus0x && IsNonStatic1 && !IsNonStatic2)
@@ -3462,7 +3488,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
Args1.insert(Args1.end(),
Proto1->arg_type_begin() + Skip1, Proto1->arg_type_end());
- llvm::SmallVector<QualType, 4> Args2;
+ SmallVector<QualType, 4> Args2;
Skip2 = !S.getLangOptions().CPlusPlus0x &&
IsNonStatic1 && !IsNonStatic2;
if (S.getLangOptions().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1)
@@ -3524,7 +3550,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
}
// Figure out which template parameters were used.
- llvm::SmallVector<bool, 4> UsedParameters;
+ SmallVector<bool, 4> UsedParameters;
UsedParameters.resize(TemplateParams->size());
switch (TPOC) {
case TPOC_Call: {
@@ -3605,7 +3631,7 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
SourceLocation Loc,
TemplatePartialOrderingContext TPOC,
unsigned NumCallArguments) {
- llvm::SmallVector<RefParamPartialOrderingComparison, 4> RefParamComparisons;
+ SmallVector<RefParamPartialOrderingComparison, 4> RefParamComparisons;
bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC,
NumCallArguments, 0);
bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
@@ -3853,7 +3879,7 @@ Sema::getMoreSpecializedPartialSpecialization(
// know that every template parameter is deducible from the class
// template partial specialization's template arguments, for
// example.
- llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
+ SmallVector<DeducedTemplateArgument, 4> Deduced;
TemplateDeductionInfo Info(Context, Loc);
QualType PT1 = PS1->getInjectedSpecializationType();
@@ -3899,7 +3925,7 @@ MarkUsedTemplateParameters(Sema &SemaRef,
const TemplateArgument &TemplateArg,
bool OnlyDeduced,
unsigned Depth,
- llvm::SmallVectorImpl<bool> &Used);
+ SmallVectorImpl<bool> &Used);
/// \brief Mark the template parameters that are used by the given
/// expression.
@@ -3908,7 +3934,7 @@ MarkUsedTemplateParameters(Sema &SemaRef,
const Expr *E,
bool OnlyDeduced,
unsigned Depth,
- llvm::SmallVectorImpl<bool> &Used) {
+ SmallVectorImpl<bool> &Used) {
// We can deduce from a pack expansion.
if (const PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(E))
E = Expansion->getPattern();
@@ -3939,7 +3965,7 @@ MarkUsedTemplateParameters(Sema &SemaRef,
NestedNameSpecifier *NNS,
bool OnlyDeduced,
unsigned Depth,
- llvm::SmallVectorImpl<bool> &Used) {
+ SmallVectorImpl<bool> &Used) {
if (!NNS)
return;
@@ -3956,7 +3982,7 @@ MarkUsedTemplateParameters(Sema &SemaRef,
TemplateName Name,
bool OnlyDeduced,
unsigned Depth,
- llvm::SmallVectorImpl<bool> &Used) {
+ SmallVectorImpl<bool> &Used) {
if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
if (TemplateTemplateParmDecl *TTP
= dyn_cast<TemplateTemplateParmDecl>(Template)) {
@@ -3980,7 +4006,7 @@ static void
MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
bool OnlyDeduced,
unsigned Depth,
- llvm::SmallVectorImpl<bool> &Used) {
+ SmallVectorImpl<bool> &Used) {
if (T.isNull())
return;
@@ -4113,6 +4139,13 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
OnlyDeduced, Depth, Used);
break;
+ case Type::Atomic:
+ if (!OnlyDeduced)
+ MarkUsedTemplateParameters(SemaRef,
+ cast<AtomicType>(T)->getValueType(),
+ OnlyDeduced, Depth, Used);
+ break;
+
case Type::DependentName:
if (!OnlyDeduced)
MarkUsedTemplateParameters(SemaRef,
@@ -4206,7 +4239,7 @@ MarkUsedTemplateParameters(Sema &SemaRef,
const TemplateArgument &TemplateArg,
bool OnlyDeduced,
unsigned Depth,
- llvm::SmallVectorImpl<bool> &Used) {
+ SmallVectorImpl<bool> &Used) {
switch (TemplateArg.getKind()) {
case TemplateArgument::Null:
case TemplateArgument::Integral:
@@ -4251,7 +4284,7 @@ MarkUsedTemplateParameters(Sema &SemaRef,
void
Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
bool OnlyDeduced, unsigned Depth,
- llvm::SmallVectorImpl<bool> &Used) {
+ SmallVectorImpl<bool> &Used) {
// 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
@@ -4269,7 +4302,7 @@ Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
/// call to the given function template.
void
Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
- llvm::SmallVectorImpl<bool> &Deduced) {
+ SmallVectorImpl<bool> &Deduced) {
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
Deduced.clear();
@@ -4289,7 +4322,7 @@ bool hasDeducibleTemplateParameters(Sema &S,
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
- llvm::SmallVector<bool, 4> Deduced;
+ SmallVector<bool, 4> Deduced;
Deduced.resize(TemplateParams->size());
::MarkUsedTemplateParameters(S, T, true, TemplateParams->getDepth(),
Deduced);
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 1988f1445814..301bf6a11260 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -98,8 +98,9 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
// Add template arguments from a function template specialization.
else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) {
if (!RelativeToPrimary &&
- Function->getTemplateSpecializationKind()
- == TSK_ExplicitSpecialization)
+ (Function->getTemplateSpecializationKind() ==
+ TSK_ExplicitSpecialization &&
+ !Function->getClassScopeSpecializationPattern()))
break;
if (const TemplateArgumentList *TemplateArgs
@@ -428,7 +429,7 @@ void Sema::PrintInstantiationStack() {
// FIXME: In all of these cases, we need to show the template arguments
unsigned InstantiationIdx = 0;
- for (llvm::SmallVector<ActiveTemplateInstantiation, 16>::reverse_iterator
+ for (SmallVector<ActiveTemplateInstantiation, 16>::reverse_iterator
Active = ActiveTemplateInstantiations.rbegin(),
ActiveEnd = ActiveTemplateInstantiations.rend();
Active != ActiveEnd;
@@ -483,7 +484,7 @@ void Sema::PrintInstantiationStack() {
= TemplateSpecializationType::PrintTemplateArgumentList(
Active->TemplateArgs,
Active->NumTemplateArgs,
- Context.PrintingPolicy);
+ getPrintingPolicy());
Diags.Report(Active->PointOfInstantiation,
diag::note_default_arg_instantiation_here)
<< (Template->getNameAsString() + TemplateArgsStr)
@@ -537,7 +538,7 @@ void Sema::PrintInstantiationStack() {
= TemplateSpecializationType::PrintTemplateArgumentList(
Active->TemplateArgs,
Active->NumTemplateArgs,
- Context.PrintingPolicy);
+ getPrintingPolicy());
Diags.Report(Active->PointOfInstantiation,
diag::note_default_function_arg_instantiation_here)
<< (FD->getNameAsString() + TemplateArgsStr)
@@ -591,7 +592,6 @@ void Sema::PrintInstantiationStack() {
}
llvm::Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
- using llvm::SmallVector;
if (InNonInstantiationSFINAEContext)
return llvm::Optional<TemplateDeductionInfo *>(0);
@@ -681,14 +681,12 @@ namespace {
bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
SourceRange PatternRange,
- const UnexpandedParameterPack *Unexpanded,
- unsigned NumUnexpanded,
+ llvm::ArrayRef<UnexpandedParameterPack> Unexpanded,
bool &ShouldExpand,
bool &RetainExpansion,
llvm::Optional<unsigned> &NumExpansions) {
return getSema().CheckParameterPacksForExpansion(EllipsisLoc,
PatternRange, Unexpanded,
- NumUnexpanded,
TemplateArgs,
ShouldExpand,
RetainExpansion,
@@ -1535,8 +1533,8 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
bool Sema::SubstParmTypes(SourceLocation Loc,
ParmVarDecl **Params, unsigned NumParams,
const MultiLevelTemplateArgumentList &TemplateArgs,
- llvm::SmallVectorImpl<QualType> &ParamTypes,
- llvm::SmallVectorImpl<ParmVarDecl *> *OutParams) {
+ SmallVectorImpl<QualType> &ParamTypes,
+ SmallVectorImpl<ParmVarDecl *> *OutParams) {
assert(!ActiveTemplateInstantiations.empty() &&
"Cannot perform an instantiation without some context on the "
"instantiation stack");
@@ -1558,7 +1556,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
CXXRecordDecl *Pattern,
const MultiLevelTemplateArgumentList &TemplateArgs) {
bool Invalid = false;
- llvm::SmallVector<CXXBaseSpecifier*, 4> InstantiatedBases;
+ SmallVector<CXXBaseSpecifier*, 4> InstantiatedBases;
for (ClassTemplateSpecializationDecl::base_class_iterator
Base = Pattern->bases_begin(), BaseEnd = Pattern->bases_end();
Base != BaseEnd; ++Base) {
@@ -1572,7 +1570,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
if (Base->isPackExpansion()) {
// This is a pack expansion. See whether we should expand it now, or
// wait until later.
- llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
collectUnexpandedParameterPacks(Base->getTypeSourceInfo()->getTypeLoc(),
Unexpanded);
bool ShouldExpand = false;
@@ -1580,7 +1578,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
llvm::Optional<unsigned> NumExpansions;
if (CheckParameterPacksForExpansion(Base->getEllipsisLoc(),
Base->getSourceRange(),
- Unexpanded.data(), Unexpanded.size(),
+ Unexpanded,
TemplateArgs, ShouldExpand,
RetainExpansion,
NumExpansions)) {
@@ -1755,8 +1753,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Invalid = true;
TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs);
- llvm::SmallVector<Decl*, 4> Fields;
- llvm::SmallVector<std::pair<FieldDecl*, FieldDecl*>, 4>
+ SmallVector<Decl*, 4> Fields;
+ SmallVector<std::pair<FieldDecl*, FieldDecl*>, 4>
FieldsWithMemberInitializers;
for (RecordDecl::decl_iterator Member = Pattern->decls_begin(),
MemberEnd = Pattern->decls_end();
@@ -1796,9 +1794,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
}
// Finish checking fields.
- ActOnFields(0, Instantiation->getLocation(), Instantiation,
- Fields.data(), Fields.size(), SourceLocation(), SourceLocation(),
- 0);
+ ActOnFields(0, Instantiation->getLocation(), Instantiation, Fields,
+ SourceLocation(), SourceLocation(), 0);
CheckCompletedCXXClass(Instantiation);
// Attach any in-class member initializers now the class is complete.
@@ -1806,39 +1803,24 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
FieldDecl *OldField = FieldsWithMemberInitializers[I].first;
FieldDecl *NewField = FieldsWithMemberInitializers[I].second;
Expr *OldInit = OldField->getInClassInitializer();
- ExprResult NewInit = SubstExpr(OldInit, TemplateArgs);
-
- // If the initialization is no longer dependent, check it now.
- if ((OldField->getType()->isDependentType() || OldInit->isTypeDependent() ||
- OldInit->isValueDependent()) &&
- !NewField->getType()->isDependentType() &&
- !NewInit.get()->isTypeDependent() &&
- !NewInit.get()->isValueDependent()) {
- // FIXME: handle list-initialization
- SourceLocation EqualLoc = NewField->getLocation();
- NewInit = PerformCopyInitialization(
- InitializedEntity::InitializeMember(NewField), EqualLoc,
- NewInit.release());
-
- if (!NewInit.isInvalid()) {
- CheckImplicitConversions(NewInit.get(), EqualLoc);
-
- // C++0x [class.base.init]p7:
- // The initialization of each base and member constitutes a
- // full-expression.
- NewInit = MaybeCreateExprWithCleanups(NewInit);
- }
- }
- if (NewInit.isInvalid())
+ SourceLocation LParenLoc, RParenLoc;
+ ASTOwningVector<Expr*> NewArgs(*this);
+ if (InstantiateInitializer(OldInit, TemplateArgs, LParenLoc, NewArgs,
+ RParenLoc))
NewField->setInvalidDecl();
- else
- NewField->setInClassInitializer(NewInit.release());
+ else {
+ assert(NewArgs.size() == 1 && "wrong number of in-class initializers");
+ ActOnCXXInClassMemberInitializer(NewField, LParenLoc, NewArgs[0]);
+ }
}
if (!FieldsWithMemberInitializers.empty())
ActOnFinishDelayedMemberInitializers(Instantiation);
+ if (TSK == TSK_ImplicitInstantiation)
+ Instantiation->setRBraceLoc(Pattern->getRBraceLoc());
+
if (Instantiation->isInvalidDecl())
Invalid = true;
else {
@@ -1931,8 +1913,8 @@ Sema::InstantiateClassTemplateSpecialization(
// specialization with the template argument lists of the partial
// specializations.
typedef PartialSpecMatchResult MatchResult;
- llvm::SmallVector<MatchResult, 4> Matched;
- llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
+ SmallVector<MatchResult, 4> Matched;
+ SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
Template->getPartialSpecializations(PartialSpecs);
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
@@ -1954,10 +1936,10 @@ Sema::InstantiateClassTemplateSpecialization(
// If we're dealing with a member template where the template parameters
// have been instantiated, this provides the original template parameters
// from which the member template's parameters were instantiated.
- llvm::SmallVector<const NamedDecl *, 4> InstantiatedTemplateParameters;
+ SmallVector<const NamedDecl *, 4> InstantiatedTemplateParameters;
if (Matched.size() >= 1) {
- llvm::SmallVector<MatchResult, 4>::iterator Best = Matched.begin();
+ SmallVector<MatchResult, 4>::iterator Best = Matched.begin();
if (Matched.size() == 1) {
// -- If exactly one matching specialization is found, the
// instantiation is generated from that specialization.
@@ -1970,7 +1952,7 @@ Sema::InstantiateClassTemplateSpecialization(
// specialized than all of the other matching
// specializations, then the use of the class template is
// ambiguous and the program is ill-formed.
- for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1,
+ for (SmallVector<MatchResult, 4>::iterator P = Best + 1,
PEnd = Matched.end();
P != PEnd; ++P) {
if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial,
@@ -1982,7 +1964,7 @@ Sema::InstantiateClassTemplateSpecialization(
// Determine if the best partial specialization is more specialized than
// the others.
bool Ambiguous = false;
- for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
+ for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
PEnd = Matched.end();
P != PEnd; ++P) {
if (P != Best &&
@@ -2001,7 +1983,7 @@ Sema::InstantiateClassTemplateSpecialization(
<< ClassTemplateSpec;
// Print the matching partial specializations.
- for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
+ for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
PEnd = Matched.end();
P != PEnd; ++P)
Diag(P->Partial->getLocation(), diag::note_partial_spec_match)
@@ -2240,7 +2222,7 @@ Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) {
bool Sema::SubstExprs(Expr **Exprs, unsigned NumExprs, bool IsCall,
const MultiLevelTemplateArgumentList &TemplateArgs,
- llvm::SmallVectorImpl<Expr *> &Outputs) {
+ SmallVectorImpl<Expr *> &Outputs) {
if (NumExprs == 0)
return false;
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 29385e50b8c1..02a05d518251 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -29,14 +29,14 @@ bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl,
DeclaratorDecl *NewDecl) {
if (!OldDecl->getQualifierLoc())
return false;
-
+
NestedNameSpecifierLoc NewQualifierLoc
- = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(),
+ = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(),
TemplateArgs);
-
+
if (!NewQualifierLoc)
return true;
-
+
NewDecl->setQualifierInfo(NewQualifierLoc);
return false;
}
@@ -45,14 +45,14 @@ bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl,
TagDecl *NewDecl) {
if (!OldDecl->getQualifierLoc())
return false;
-
+
NestedNameSpecifierLoc NewQualifierLoc
- = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(),
+ = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(),
TemplateArgs);
-
+
if (!NewQualifierLoc)
return true;
-
+
NewDecl->setQualifierInfo(NewQualifierLoc);
return false;
}
@@ -79,7 +79,7 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
else {
TypeSourceInfo *Result = SubstType(Aligned->getAlignmentType(),
TemplateArgs,
- Aligned->getLocation(),
+ Aligned->getLocation(),
DeclarationName());
if (Result)
AddAlignedAttr(Aligned->getLocation(), New, Result);
@@ -96,8 +96,7 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
Decl *
TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
- assert(false && "Translation units cannot be instantiated");
- return D;
+ llvm_unreachable("Translation units cannot be instantiated");
}
Decl *
@@ -110,8 +109,7 @@ TemplateDeclInstantiator::VisitLabelDecl(LabelDecl *D) {
Decl *
TemplateDeclInstantiator::VisitNamespaceDecl(NamespaceDecl *D) {
- assert(false && "Namespaces cannot be instantiated");
- return D;
+ llvm_unreachable("Namespaces cannot be instantiated");
}
Decl *
@@ -165,13 +163,13 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
newTag->setTypedefNameForAnonDecl(Typedef);
}
}
-
+
if (TypedefNameDecl *Prev = D->getPreviousDeclaration()) {
NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(D->getLocation(), Prev,
TemplateArgs);
if (!InstPrev)
return 0;
-
+
Typedef->setPreviousDeclaration(cast<TypedefNameDecl>(InstPrev));
}
@@ -230,7 +228,7 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
if (!PrevAliasTemplate)
Inst->setInstantiatedFromMemberTemplate(D);
-
+
Owner->addDecl(Inst);
return Inst;
@@ -239,8 +237,6 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
/// \brief Instantiate an initializer, breaking it into separate
/// initialization arguments.
///
-/// \param S The semantic analysis object.
-///
/// \param Init The initializer to instantiate.
///
/// \param TemplateArgs Template arguments to be substituted into the
@@ -249,11 +245,11 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
/// \param NewArgs Will be filled in with the instantiation arguments.
///
/// \returns true if an error occurred, false otherwise
-static bool InstantiateInitializer(Sema &S, Expr *Init,
+bool Sema::InstantiateInitializer(Expr *Init,
const MultiLevelTemplateArgumentList &TemplateArgs,
- SourceLocation &LParenLoc,
- ASTOwningVector<Expr*> &NewArgs,
- SourceLocation &RParenLoc) {
+ SourceLocation &LParenLoc,
+ ASTOwningVector<Expr*> &NewArgs,
+ SourceLocation &RParenLoc) {
NewArgs.clear();
LParenLoc = SourceLocation();
RParenLoc = SourceLocation();
@@ -273,24 +269,24 @@ static bool InstantiateInitializer(Sema &S, Expr *Init,
if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
LParenLoc = ParenList->getLParenLoc();
RParenLoc = ParenList->getRParenLoc();
- return S.SubstExprs(ParenList->getExprs(), ParenList->getNumExprs(),
- true, TemplateArgs, NewArgs);
+ return SubstExprs(ParenList->getExprs(), ParenList->getNumExprs(),
+ true, TemplateArgs, NewArgs);
}
if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init)) {
if (!isa<CXXTemporaryObjectExpr>(Construct)) {
- if (S.SubstExprs(Construct->getArgs(), Construct->getNumArgs(), true,
- TemplateArgs, NewArgs))
+ if (SubstExprs(Construct->getArgs(), Construct->getNumArgs(), true,
+ TemplateArgs, NewArgs))
return true;
// FIXME: Fake locations!
- LParenLoc = S.PP.getLocForEndOfToken(Init->getLocStart());
+ LParenLoc = PP.getLocForEndOfToken(Init->getLocStart());
RParenLoc = LParenLoc;
return false;
}
}
-
- ExprResult Result = S.SubstExpr(Init, TemplateArgs);
+
+ ExprResult Result = SubstExpr(Init, TemplateArgs);
if (Result.isInvalid())
return true;
@@ -319,7 +315,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
<< D->isStaticDataMember() << DI->getType();
return 0;
}
-
+
// Build the instantiated declaration
VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner,
D->getInnerLocStart(),
@@ -342,21 +338,20 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
Var->setLexicalDeclContext(D->getLexicalDeclContext());
Var->setAccess(D->getAccess());
-
+
if (!D->isStaticDataMember()) {
Var->setUsed(D->isUsed(false));
Var->setReferenced(D->isReferenced());
}
-
+
// FIXME: In theory, we could have a previous declaration for variables that
// are not static data members.
- bool Redeclaration = false;
// FIXME: having to fake up a LookupResult is dumb.
LookupResult Previous(SemaRef, Var->getDeclName(), Var->getLocation(),
Sema::LookupOrdinaryName, Sema::ForRedeclaration);
if (D->isStaticDataMember())
SemaRef.LookupQualifiedName(Previous, Owner, false);
- SemaRef.CheckVariableDeclaration(Var, Previous, Redeclaration);
+ SemaRef.CheckVariableDeclaration(Var, Previous);
if (D->isOutOfLine()) {
if (!D->isStaticDataMember())
@@ -368,13 +363,13 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Var);
}
SemaRef.InstantiateAttrs(TemplateArgs, D, Var);
-
+
// Link instantiations of static data members back to the template from
// which they were instantiated.
if (Var->isStaticDataMember())
- SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D,
+ SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D,
TSK_ImplicitInstantiation);
-
+
if (Var->getAnyInitializer()) {
// We already have an initializer in the class.
} else if (D->getInit()) {
@@ -386,8 +381,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
// Instantiate the initializer.
SourceLocation LParenLoc, RParenLoc;
ASTOwningVector<Expr*> InitArgs(SemaRef);
- if (!InstantiateInitializer(SemaRef, D->getInit(), TemplateArgs, LParenLoc,
- InitArgs, RParenLoc)) {
+ if (!SemaRef.InstantiateInitializer(D->getInit(), TemplateArgs, LParenLoc,
+ InitArgs, RParenLoc)) {
bool TypeMayContainAuto = true;
// Attach the initializer to the declaration, if we have one.
if (InitArgs.size() == 0)
@@ -409,7 +404,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
// because of a bogus initializer.
Var->setInvalidDecl();
}
-
+
SemaRef.PopExpressionEvaluationContext();
} else if ((!Var->isStaticDataMember() || Var->isOutOfLine()) &&
!Var->isCXXForRangeDecl())
@@ -489,14 +484,14 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
}
SemaRef.InstantiateAttrs(TemplateArgs, D, Field);
-
+
if (Invalid)
Field->setInvalidDecl();
if (!Field->getDeclName()) {
// Keep track of where this decl came from.
SemaRef.Context.setInstantiatedFromUnnamedFieldDecl(Field, D);
- }
+ }
if (CXXRecordDecl *Parent= dyn_cast<CXXRecordDecl>(Field->getDeclContext())) {
if (Parent->isAnonymousStructOrUnion() &&
Parent->getRedeclContext()->isFunctionOrMethod())
@@ -518,11 +513,11 @@ Decl *TemplateDeclInstantiator::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
for (IndirectFieldDecl::chain_iterator PI =
D->chain_begin(), PE = D->chain_end();
PI != PE; ++PI) {
- NamedDecl *Next = SemaRef.FindInstantiatedDecl(D->getLocation(), *PI,
+ NamedDecl *Next = SemaRef.FindInstantiatedDecl(D->getLocation(), *PI,
TemplateArgs);
if (!Next)
return 0;
-
+
NamedChain[i++] = Next;
}
@@ -560,13 +555,13 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getFriendLoc(), InstTy);
if (!FD)
return 0;
-
+
FD->setAccess(AS_public);
FD->setUnsupportedFriend(D->isUnsupportedFriend());
Owner->addDecl(FD);
return FD;
- }
-
+ }
+
NamedDecl *ND = D->getFriendDecl();
assert(ND && "friend decl must be a decl or a type!");
@@ -578,7 +573,7 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
if (!NewND) return 0;
FriendDecl *FD =
- FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(),
cast<NamedDecl>(NewND), D->getFriendLoc());
FD->setAccess(AS_public);
FD->setUnsupportedFriend(D->isUnsupportedFriend());
@@ -620,7 +615,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
TemplateArgs,
UnderlyingLoc,
DeclarationName()));
-
+
if (!Enum->getIntegerTypeSourceInfo())
Enum->setIntegerType(SemaRef.Context.IntTy);
}
@@ -641,8 +636,8 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
if (D->getDeclContext()->isFunctionOrMethod())
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
-
- llvm::SmallVector<Decl*, 4> Enumerators;
+
+ SmallVector<Decl*, 4> Enumerators;
EnumConstantDecl *LastEnumConst = 0;
for (EnumDecl::enumerator_iterator EC = D->enumerator_begin(),
@@ -683,7 +678,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
Enum->addDecl(EnumConst);
Enumerators.push_back(EnumConst);
LastEnumConst = EnumConst;
-
+
if (D->getDeclContext()->isFunctionOrMethod()) {
// If the enumeration is within a function or method, record the enum
// constant as a local.
@@ -703,8 +698,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
}
Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) {
- assert(false && "EnumConstantDecls can only occur within EnumDecls.");
- return 0;
+ llvm_unreachable("EnumConstantDecls can only occur within EnumDecls.");
}
Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
@@ -789,7 +783,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// template parameters of the original declaration. In this one
// case, we don't complain about the ill-formed friend
// declaration.
- if (isFriend && Pattern->getIdentifier() &&
+ if (isFriend && Pattern->getIdentifier() &&
Pattern->getIdentifier()->isStr("_Map_base") &&
DC->isNamespace() &&
cast<NamespaceDecl>(DC)->getIdentifier() &&
@@ -812,7 +806,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// Make sure the parameter lists match.
if (!SemaRef.TemplateParameterListsAreEqual(InstParams, PrevParams,
- Complain,
+ Complain,
Sema::TPL_TemplateMatch)) {
if (Complain)
return 0;
@@ -859,7 +853,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (!PrevClassTemplate)
Inst->setInstantiatedFromMemberTemplate(D);
}
-
+
// Trigger creation of the type for the instantiation.
SemaRef.Context.getInjectedClassNameType(RecordInst,
Inst->getInjectedClassNameSpecialization());
@@ -869,14 +863,14 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
DC->makeDeclVisibleInContext(Inst, /*Recoverable*/ false);
return Inst;
}
-
+
Owner->addDecl(Inst);
if (!PrevClassTemplate) {
// Queue up any out-of-line partial specializations of this member
// class template; the client will force their instantiation once
// the enclosing class has been instantiated.
- llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
+ SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
D->getPartialSpecializations(PartialSpecs);
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I)
if (PartialSpecs[I]->isOutOfLine())
@@ -890,19 +884,19 @@ Decl *
TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D) {
ClassTemplateDecl *ClassTemplate = D->getSpecializedTemplate();
-
+
// Lookup the already-instantiated declaration in the instantiation
// of the class template and return that.
DeclContext::lookup_result Found
= Owner->lookup(ClassTemplate->getDeclName());
if (Found.first == Found.second)
return 0;
-
+
ClassTemplateDecl *InstClassTemplate
= dyn_cast<ClassTemplateDecl>(*Found.first);
if (!InstClassTemplate)
return 0;
-
+
if (ClassTemplatePartialSpecializationDecl *Result
= InstClassTemplate->findPartialSpecInstantiatedFromMember(D))
return Result;
@@ -914,7 +908,7 @@ Decl *
TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
// Create a local instantiation scope for this function template, which
// will contain the instantiations of the template parameters and then get
- // merged with the local instantiation scope for the function template
+ // merged with the local instantiation scope for the function template
// itself.
LocalInstantiationScope Scope(SemaRef);
@@ -922,16 +916,16 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
return NULL;
-
+
FunctionDecl *Instantiated = 0;
if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(D->getTemplatedDecl()))
- Instantiated = cast_or_null<FunctionDecl>(VisitCXXMethodDecl(DMethod,
+ Instantiated = cast_or_null<FunctionDecl>(VisitCXXMethodDecl(DMethod,
InstParams));
else
Instantiated = cast_or_null<FunctionDecl>(VisitFunctionDecl(
- D->getTemplatedDecl(),
+ D->getTemplatedDecl(),
InstParams));
-
+
if (!Instantiated)
return 0;
@@ -939,10 +933,10 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
// Link the instantiated function template declaration to the function
// template from which it was instantiated.
- FunctionTemplateDecl *InstTemplate
+ FunctionTemplateDecl *InstTemplate
= Instantiated->getDescribedFunctionTemplate();
InstTemplate->setAccess(D->getAccess());
- assert(InstTemplate &&
+ assert(InstTemplate &&
"VisitFunctionDecl/CXXMethodDecl didn't create a template!");
bool isFriend = (InstTemplate->getFriendObjectKind() != Decl::FOK_None);
@@ -952,7 +946,7 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
if (!InstTemplate->getInstantiatedFromMemberTemplate() &&
!(isFriend && !D->getTemplatedDecl()->isThisDeclarationADefinition()))
InstTemplate->setInstantiatedFromMemberTemplate(D);
-
+
// Make declarations visible in the appropriate context.
if (!isFriend)
Owner->addDecl(InstTemplate);
@@ -1018,7 +1012,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
void *InsertPos = 0;
if (FunctionTemplate && !TemplateParams) {
- std::pair<const TemplateArgument *, unsigned> Innermost
+ std::pair<const TemplateArgument *, unsigned> Innermost
= TemplateArgs.getInnermost();
FunctionDecl *SpecFunc
@@ -1038,11 +1032,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
bool MergeWithParentScope = (TemplateParams != 0) ||
Owner->isFunctionOrMethod() ||
- !(isa<Decl>(Owner) &&
+ !(isa<Decl>(Owner) &&
cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);
- llvm::SmallVector<ParmVarDecl *, 4> Params;
+ SmallVector<ParmVarDecl *, 4> Params;
TypeSourceInfo *TInfo = D->getTypeSourceInfo();
TInfo = SubstFunctionType(D, Params);
if (!TInfo)
@@ -1068,7 +1062,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
DC = SemaRef.computeDeclContext(SS);
if (!DC) return 0;
} else {
- DC = SemaRef.FindInstantiatedContext(D->getLocation(), D->getDeclContext(),
+ DC = SemaRef.FindInstantiatedContext(D->getLocation(), D->getDeclContext(),
TemplateArgs);
}
@@ -1076,7 +1070,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
FunctionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(),
D->getLocation(), D->getDeclName(), T, TInfo,
D->getStorageClass(), D->getStorageClassAsWritten(),
- D->isInlineSpecified(), D->hasWrittenPrototype());
+ D->isInlineSpecified(), D->hasWrittenPrototype(),
+ /*isConstexpr*/ false);
if (QualifierLoc)
Function->setQualifierInfo(QualifierLoc);
@@ -1110,7 +1105,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Params.push_back(Param);
}
}
- Function->setParams(Params.data(), Params.size());
+ Function->setParams(Params);
SourceLocation InstantiateAtPOI;
if (TemplateParams) {
@@ -1124,7 +1119,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
//
// X<int> x;
//
- // We are instantiating the friend function template "f" within X<int>,
+ // We are instantiating the friend function template "f" within X<int>,
// which means substituting int for T, but leaving "f" as a friend function
// template.
// Build the function template itself.
@@ -1144,25 +1139,28 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
}
} else if (FunctionTemplate) {
// Record this function template specialization.
- std::pair<const TemplateArgument *, unsigned> Innermost
+ std::pair<const TemplateArgument *, unsigned> Innermost
= TemplateArgs.getInnermost();
Function->setFunctionTemplateSpecialization(FunctionTemplate,
TemplateArgumentList::CreateCopy(SemaRef.Context,
Innermost.first,
Innermost.second),
InsertPos);
- } else if (isFriend && D->isThisDeclarationADefinition()) {
- // TODO: should we remember this connection regardless of whether
- // the friend declaration provided a body?
+ } else if (isFriend) {
+ // Note, we need this connection even if the friend doesn't have a body.
+ // Its body may exist but not have been attached yet due to deferred
+ // parsing.
+ // FIXME: It might be cleaner to set this when attaching the body to the
+ // friend function declaration, however that would require finding all the
+ // instantiations and modifying them.
Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
}
-
+
if (InitFunctionInstantiation(Function, D))
Function->setInvalidDecl();
- bool Redeclaration = false;
bool isExplicitSpecialization = false;
-
+
LookupResult Previous(SemaRef, Function->getDeclName(), SourceLocation(),
Sema::LookupOrdinaryName, Sema::ForRedeclaration);
@@ -1194,15 +1192,15 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
&ExplicitArgs,
Previous))
Function->setInvalidDecl();
-
+
isExplicitSpecialization = true;
} else if (TemplateParams || !FunctionTemplate) {
- // Look only into the namespace where the friend would be declared to
- // find a previous declaration. This is the innermost enclosing namespace,
+ // Look only into the namespace where the friend would be declared to
+ // find a previous declaration. This is the innermost enclosing namespace,
// as described in ActOnFriendFunctionDecl.
SemaRef.LookupQualifiedName(Previous, DC);
-
+
// In C++, the previous declaration we find might be a tag type
// (class or enum). In this case, the new declaration will hide the
// tag type. Note that this does does not apply if we're declaring a
@@ -1210,9 +1208,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
if (Previous.isSingleTagDecl())
Previous.clear();
}
-
+
SemaRef.CheckFunctionDeclaration(/*Scope*/ 0, Function, Previous,
- isExplicitSpecialization, Redeclaration);
+ isExplicitSpecialization);
NamedDecl *PrincipalDecl = (TemplateParams
? cast<NamedDecl>(FunctionTemplate)
@@ -1238,11 +1236,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
const FunctionDecl *Definition = 0;
if (Function->isDefined(Definition) &&
Definition->getTemplateSpecializationKind() == TSK_Undeclared) {
- SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
+ SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
<< Function->getDeclName();
SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition);
- Function->setInvalidDecl();
- }
+ Function->setInvalidDecl();
+ }
// Check for redefinitions due to other instantiations of this or
// a similar friend function.
else for (FunctionDecl::redecl_iterator R = Function->redecls_begin(),
@@ -1269,7 +1267,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
if (const FunctionDecl *RPattern
= R->getTemplateInstantiationPattern())
if (RPattern->isDefined(RPattern)) {
- SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
+ SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
<< Function->getDeclName();
SemaRef.Diag(R->getLocation(), diag::note_previous_definition);
Function->setInvalidDecl();
@@ -1290,14 +1288,15 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Decl *
TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
- TemplateParameterList *TemplateParams) {
+ TemplateParameterList *TemplateParams,
+ bool IsClassScopeSpecialization) {
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
void *InsertPos = 0;
if (FunctionTemplate && !TemplateParams) {
// We are creating a function template specialization from a function
// template. Check whether there is already a function template
// specialization for this particular set of template arguments.
- std::pair<const TemplateArgument *, unsigned> Innermost
+ std::pair<const TemplateArgument *, unsigned> Innermost
= TemplateArgs.getInnermost();
FunctionDecl *SpecFunc
@@ -1316,12 +1315,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
bool MergeWithParentScope = (TemplateParams != 0) ||
- !(isa<Decl>(Owner) &&
+ !(isa<Decl>(Owner) &&
cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);
// Instantiate enclosing template arguments for friends.
- llvm::SmallVector<TemplateParameterList *, 4> TempParamLists;
+ SmallVector<TemplateParameterList *, 4> TempParamLists;
unsigned NumTempParamLists = 0;
if (isFriend && (NumTempParamLists = D->getNumTemplateParameterLists())) {
TempParamLists.set_size(NumTempParamLists);
@@ -1334,7 +1333,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
}
}
- llvm::SmallVector<ParmVarDecl *, 4> Params;
+ SmallVector<ParmVarDecl *, 4> Params;
TypeSourceInfo *TInfo = D->getTypeSourceInfo();
TInfo = SubstFunctionType(D, Params);
if (!TInfo)
@@ -1352,18 +1351,18 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
// synthesized in the method declaration.
if (!isa<FunctionProtoType>(T.IgnoreParens())) {
assert(!Params.size() && "Instantiating type could not yield parameters");
- llvm::SmallVector<QualType, 4> ParamTypes;
- if (SemaRef.SubstParmTypes(D->getLocation(), D->param_begin(),
- D->getNumParams(), TemplateArgs, ParamTypes,
+ SmallVector<QualType, 4> ParamTypes;
+ if (SemaRef.SubstParmTypes(D->getLocation(), D->param_begin(),
+ D->getNumParams(), TemplateArgs, ParamTypes,
&Params))
- return 0;
+ return 0;
}
NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc();
if (QualifierLoc) {
QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
TemplateArgs);
- if (!QualifierLoc)
+ if (!QualifierLoc)
return 0;
}
@@ -1396,7 +1395,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
StartLoc, NameInfo, T, TInfo,
Constructor->isExplicit(),
Constructor->isInlineSpecified(),
- false);
+ false, /*isConstexpr*/ false);
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
StartLoc, NameInfo, T, TInfo,
@@ -1407,6 +1406,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
StartLoc, NameInfo, T, TInfo,
Conversion->isInlineSpecified(),
Conversion->isExplicit(),
+ /*isConstexpr*/ false,
Conversion->getLocEnd());
} else {
Method = CXXMethodDecl::Create(SemaRef.Context, Record,
@@ -1414,7 +1414,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
D->isStatic(),
D->getStorageClassAsWritten(),
D->isInlineSpecified(),
- D->getLocEnd());
+ /*isConstexpr*/ false, D->getLocEnd());
}
if (QualifierLoc)
@@ -1446,7 +1446,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Method->setDescribedFunctionTemplate(FunctionTemplate);
} else if (FunctionTemplate) {
// Record this function template specialization.
- std::pair<const TemplateArgument *, unsigned> Innermost
+ std::pair<const TemplateArgument *, unsigned> Innermost
= TemplateArgs.getInnermost();
Method->setFunctionTemplateSpecialization(FunctionTemplate,
TemplateArgumentList::CreateCopy(SemaRef.Context,
@@ -1457,7 +1457,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
// Record that this is an instantiation of a member function.
Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
}
-
+
// If we are instantiating a member function defined
// out-of-line, the instantiation will have the same lexical
// context (which will be a namespace scope) as the template.
@@ -1475,7 +1475,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
Params[P]->setOwningFunction(Method);
- Method->setParams(Params.data(), Params.size());
+ Method->setParams(Params);
if (InitMethodInstantiation(Method, D))
Method->setInvalidDecl();
@@ -1494,8 +1494,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Previous.clear();
}
- bool Redeclaration = false;
- SemaRef.CheckFunctionDeclaration(0, Method, Previous, false, Redeclaration);
+ if (!IsClassScopeSpecialization)
+ SemaRef.CheckFunctionDeclaration(0, Method, Previous, false);
if (D->isPure())
SemaRef.CheckPureMethod(Method, SourceRange());
@@ -1514,7 +1514,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
: Method);
if (isFriend)
Record->makeDeclVisibleInContext(DeclToAdd);
- else
+ else if (!IsClassScopeSpecialization)
Owner->addDecl(DeclToAdd);
}
@@ -1558,14 +1558,14 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
D->wasDeclaredWithTypename(),
D->isParameterPack());
Inst->setAccess(AS_public);
-
+
if (D->hasDefaultArgument())
- Inst->setDefaultArgument(D->getDefaultArgumentInfo(), false);
+ Inst->setDefaultArgument(D->getDefaultArgumentInfo(), false);
- // Introduce this template parameter's instantiation into the instantiation
+ // Introduce this template parameter's instantiation into the instantiation
// scope.
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Inst);
-
+
return Inst;
}
@@ -1573,26 +1573,26 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
NonTypeTemplateParmDecl *D) {
// Substitute into the type of the non-type template parameter.
TypeLoc TL = D->getTypeSourceInfo()->getTypeLoc();
- llvm::SmallVector<TypeSourceInfo *, 4> ExpandedParameterPackTypesAsWritten;
- llvm::SmallVector<QualType, 4> ExpandedParameterPackTypes;
+ SmallVector<TypeSourceInfo *, 4> ExpandedParameterPackTypesAsWritten;
+ SmallVector<QualType, 4> ExpandedParameterPackTypes;
bool IsExpandedParameterPack = false;
- TypeSourceInfo *DI;
+ TypeSourceInfo *DI;
QualType T;
bool Invalid = false;
if (D->isExpandedParameterPack()) {
- // The non-type template parameter pack is an already-expanded pack
+ // The non-type template parameter pack is an already-expanded pack
// expansion of types. Substitute into each of the expanded types.
ExpandedParameterPackTypes.reserve(D->getNumExpansionTypes());
ExpandedParameterPackTypesAsWritten.reserve(D->getNumExpansionTypes());
for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) {
TypeSourceInfo *NewDI =SemaRef.SubstType(D->getExpansionTypeSourceInfo(I),
TemplateArgs,
- D->getLocation(),
+ D->getLocation(),
D->getDeclName());
if (!NewDI)
return 0;
-
+
ExpandedParameterPackTypesAsWritten.push_back(NewDI);
QualType NewT =SemaRef.CheckNonTypeTemplateParameterType(NewDI->getType(),
D->getLocation());
@@ -1600,7 +1600,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
return 0;
ExpandedParameterPackTypes.push_back(NewT);
}
-
+
IsExpandedParameterPack = true;
DI = D->getTypeSourceInfo();
T = DI->getType();
@@ -1610,9 +1610,9 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
// types.
PackExpansionTypeLoc Expansion = cast<PackExpansionTypeLoc>(TL);
TypeLoc Pattern = Expansion.getPatternLoc();
- llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded);
-
+
// Determine whether the set of unexpanded parameter packs can and should
// be expanded.
bool Expand = true;
@@ -1622,22 +1622,21 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
llvm::Optional<unsigned> NumExpansions = OrigNumExpansions;
if (SemaRef.CheckParameterPacksForExpansion(Expansion.getEllipsisLoc(),
Pattern.getSourceRange(),
- Unexpanded.data(),
- Unexpanded.size(),
+ Unexpanded,
TemplateArgs,
- Expand, RetainExpansion,
+ Expand, RetainExpansion,
NumExpansions))
return 0;
-
+
if (Expand) {
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I);
TypeSourceInfo *NewDI = SemaRef.SubstType(Pattern, TemplateArgs,
- D->getLocation(),
+ D->getLocation(),
D->getDeclName());
if (!NewDI)
return 0;
-
+
ExpandedParameterPackTypesAsWritten.push_back(NewDI);
QualType NewT = SemaRef.CheckNonTypeTemplateParameterType(
NewDI->getType(),
@@ -1646,7 +1645,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
return 0;
ExpandedParameterPackTypes.push_back(NewT);
}
-
+
// Note that we have an expanded parameter pack. The "type" of this
// expanded parameter pack is the original expansion type, but callers
// will end up using the expanded parameter pack types for type-checking.
@@ -1658,62 +1657,62 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
// pattern and create a new pack expansion type.
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1);
TypeSourceInfo *NewPattern = SemaRef.SubstType(Pattern, TemplateArgs,
- D->getLocation(),
+ D->getLocation(),
D->getDeclName());
if (!NewPattern)
return 0;
-
+
DI = SemaRef.CheckPackExpansion(NewPattern, Expansion.getEllipsisLoc(),
NumExpansions);
if (!DI)
return 0;
-
+
T = DI->getType();
}
} else {
// Simple case: substitution into a parameter that is not a parameter pack.
- DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs,
+ DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs,
D->getLocation(), D->getDeclName());
if (!DI)
return 0;
-
+
// Check that this type is acceptable for a non-type template parameter.
- T = SemaRef.CheckNonTypeTemplateParameterType(DI->getType(),
+ T = SemaRef.CheckNonTypeTemplateParameterType(DI->getType(),
D->getLocation());
if (T.isNull()) {
T = SemaRef.Context.IntTy;
Invalid = true;
}
}
-
+
NonTypeTemplateParmDecl *Param;
if (IsExpandedParameterPack)
- Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner,
+ Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner,
D->getInnerLocStart(),
D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(),
- D->getPosition(),
+ D->getDepth() - TemplateArgs.getNumLevels(),
+ D->getPosition(),
D->getIdentifier(), T,
DI,
ExpandedParameterPackTypes.data(),
ExpandedParameterPackTypes.size(),
ExpandedParameterPackTypesAsWritten.data());
else
- Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner,
+ Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner,
D->getInnerLocStart(),
D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(),
- D->getPosition(),
- D->getIdentifier(), T,
+ D->getDepth() - TemplateArgs.getNumLevels(),
+ D->getPosition(),
+ D->getIdentifier(), T,
D->isParameterPack(), DI);
-
+
Param->setAccess(AS_public);
if (Invalid)
Param->setInvalidDecl();
-
+
Param->setDefaultArgument(D->getDefaultArgument(), false);
-
- // Introduce this template parameter's instantiation into the instantiation
+
+ // Introduce this template parameter's instantiation into the instantiation
// scope.
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param);
return Param;
@@ -1732,34 +1731,34 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
return NULL;
- }
-
+ }
+
// Build the template template parameter.
TemplateTemplateParmDecl *Param
= TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(),
- D->getPosition(), D->isParameterPack(),
+ D->getDepth() - TemplateArgs.getNumLevels(),
+ D->getPosition(), D->isParameterPack(),
D->getIdentifier(), InstParams);
Param->setDefaultArgument(D->getDefaultArgument(), false);
Param->setAccess(AS_public);
-
- // Introduce this template parameter's instantiation into the instantiation
+
+ // Introduce this template parameter's instantiation into the instantiation
// scope.
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param);
-
+
return Param;
}
Decl *TemplateDeclInstantiator::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
// Using directives are never dependent (and never contain any types or
// expressions), so they require no explicit instantiation work.
-
+
UsingDirectiveDecl *Inst
= UsingDirectiveDecl::Create(SemaRef.Context, Owner, D->getLocation(),
- D->getNamespaceKeyLocation(),
+ D->getNamespaceKeyLocation(),
D->getQualifierLoc(),
- D->getIdentLocation(),
- D->getNominatedNamespace(),
+ D->getIdentLocation(),
+ D->getNominatedNamespace(),
D->getCommonAncestor());
Owner->addDecl(Inst);
return Inst;
@@ -1863,7 +1862,7 @@ Decl *TemplateDeclInstantiator::VisitUsingShadowDecl(UsingShadowDecl *D) {
Decl * TemplateDeclInstantiator
::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
NestedNameSpecifierLoc QualifierLoc
- = SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(),
+ = SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(),
TemplateArgs);
if (!QualifierLoc)
return 0;
@@ -1891,7 +1890,7 @@ Decl * TemplateDeclInstantiator
= SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(), TemplateArgs);
if (!QualifierLoc)
return 0;
-
+
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
@@ -1909,6 +1908,29 @@ Decl * TemplateDeclInstantiator
return UD;
}
+
+Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl(
+ ClassScopeFunctionSpecializationDecl *Decl) {
+ CXXMethodDecl *OldFD = Decl->getSpecialization();
+ CXXMethodDecl *NewFD = cast<CXXMethodDecl>(VisitCXXMethodDecl(OldFD, 0, true));
+
+ LookupResult Previous(SemaRef, NewFD->getNameInfo(), Sema::LookupOrdinaryName,
+ Sema::ForRedeclaration);
+
+ SemaRef.LookupQualifiedName(Previous, SemaRef.CurContext);
+ if (SemaRef.CheckFunctionTemplateSpecialization(NewFD, 0, Previous)) {
+ NewFD->setInvalidDecl();
+ return NewFD;
+ }
+
+ // Associate the specialization with the pattern.
+ FunctionDecl *Specialization = cast<FunctionDecl>(Previous.getFoundDecl());
+ assert(Specialization && "Class scope Specialization is null");
+ SemaRef.Context.setClassScopeSpecializationPattern(Specialization, OldFD);
+
+ return NewFD;
+}
+
Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs) {
TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);
@@ -1930,7 +1952,7 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
bool Invalid = false;
unsigned N = L->size();
- typedef llvm::SmallVector<NamedDecl *, 8> ParamVector;
+ typedef SmallVector<NamedDecl *, 8> ParamVector;
ParamVector Params;
Params.reserve(N);
for (TemplateParameterList::iterator PI = L->begin(), PE = L->end();
@@ -1951,13 +1973,13 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
return InstL;
}
-/// \brief Instantiate the declaration of a class template partial
+/// \brief Instantiate the declaration of a class template partial
/// specialization.
///
/// \param ClassTemplate the (instantiated) class template that is partially
// specialized by the instantiation of \p PartialSpec.
///
-/// \param PartialSpec the (uninstantiated) class template partial
+/// \param PartialSpec the (uninstantiated) class template partial
/// specialization that we are instantiating.
///
/// \returns The instantiated partial specialization, if successful; otherwise,
@@ -1970,28 +1992,28 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
// specialization, which will contain the instantiations of the template
// parameters.
LocalInstantiationScope Scope(SemaRef);
-
+
// Substitute into the template parameters of the class template partial
// specialization.
TemplateParameterList *TempParams = PartialSpec->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
return 0;
-
+
// Substitute into the template arguments of the class template partial
// specialization.
TemplateArgumentListInfo InstTemplateArgs; // no angle locations
- if (SemaRef.Subst(PartialSpec->getTemplateArgsAsWritten(),
- PartialSpec->getNumTemplateArgsAsWritten(),
+ if (SemaRef.Subst(PartialSpec->getTemplateArgsAsWritten(),
+ PartialSpec->getNumTemplateArgsAsWritten(),
InstTemplateArgs, TemplateArgs))
return 0;
-
+
// Check that the template argument list is well-formed for this
// class template.
- llvm::SmallVector<TemplateArgument, 4> Converted;
- if (SemaRef.CheckTemplateArgumentList(ClassTemplate,
+ SmallVector<TemplateArgument, 4> Converted;
+ if (SemaRef.CheckTemplateArgumentList(ClassTemplate,
PartialSpec->getLocation(),
- InstTemplateArgs,
+ InstTemplateArgs,
false,
Converted))
return 0;
@@ -2002,10 +2024,10 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
ClassTemplateSpecializationDecl *PrevDecl
= ClassTemplate->findPartialSpecialization(Converted.data(),
Converted.size(), InsertPos);
-
+
// Build the canonical type that describes the converted template
// arguments of the class template partial specialization.
- QualType CanonType
+ QualType CanonType
= SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate),
Converted.data(),
Converted.size());
@@ -2023,7 +2045,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
PartialSpec->getLocation(),
InstTemplateArgs,
CanonType);
-
+
if (PrevDecl) {
// We've already seen a partial specialization with the same template
// parameters and template arguments. This can happen, for example, when
@@ -2046,17 +2068,17 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
<< SemaRef.Context.getTypeDeclType(PrevDecl);
return 0;
}
-
-
+
+
// Create the class template partial specialization declaration.
ClassTemplatePartialSpecializationDecl *InstPartialSpec
- = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context,
+ = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context,
PartialSpec->getTagKind(),
- Owner,
+ Owner,
PartialSpec->getLocStart(),
PartialSpec->getLocation(),
InstParams,
- ClassTemplate,
+ ClassTemplate,
Converted.data(),
Converted.size(),
InstTemplateArgs,
@@ -2069,7 +2091,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
InstPartialSpec->setInstantiatedFromMember(PartialSpec);
InstPartialSpec->setTypeAsWritten(WrittenTy);
-
+
// Add this partial specialization to the set of class template partial
// specializations.
ClassTemplate->AddPartialSpecialization(InstPartialSpec, InsertPos);
@@ -2078,7 +2100,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
TypeSourceInfo*
TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
- llvm::SmallVectorImpl<ParmVarDecl *> &Params) {
+ SmallVectorImpl<ParmVarDecl *> &Params) {
TypeSourceInfo *OldTInfo = D->getTypeSourceInfo();
assert(OldTInfo && "substituting function without type source info");
assert(Params.empty() && "parameter vector is non-empty at start");
@@ -2104,7 +2126,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
if (!OldParam->isParameterPack() ||
(NewIdx < NumNewParams &&
NewProtoLoc->getArg(NewIdx)->isParameterPack())) {
- // Simple case: normal parameter, or a parameter pack that's
+ // Simple case: normal parameter, or a parameter pack that's
// instantiated to a (still-dependent) parameter pack.
ParmVarDecl *NewParam = NewProtoLoc->getArg(NewIdx++);
Params.push_back(NewParam);
@@ -2112,7 +2134,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
NewParam);
continue;
}
-
+
// Parameter pack: make the instantiation an argument pack.
SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(
OldParam);
@@ -2184,43 +2206,42 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
if (Proto->hasExceptionSpec() || Proto->getNoReturnAttr()) {
// The function has an exception specification or a "noreturn"
// attribute. Substitute into each of the exception types.
- llvm::SmallVector<QualType, 4> Exceptions;
+ SmallVector<QualType, 4> Exceptions;
for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) {
// FIXME: Poor location information!
if (const PackExpansionType *PackExpansion
= Proto->getExceptionType(I)->getAs<PackExpansionType>()) {
// We have a pack expansion. Instantiate it.
- llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(),
Unexpanded);
- assert(!Unexpanded.empty() &&
+ assert(!Unexpanded.empty() &&
"Pack expansion without parameter packs?");
bool Expand = false;
bool RetainExpansion = false;
llvm::Optional<unsigned> NumExpansions
= PackExpansion->getNumExpansions();
- if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(),
+ if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(),
SourceRange(),
- Unexpanded.data(),
- Unexpanded.size(),
+ Unexpanded,
TemplateArgs,
- Expand,
+ Expand,
RetainExpansion,
NumExpansions))
break;
if (!Expand) {
// We can't expand this pack expansion into separate arguments yet;
- // just substitute into the pattern and create a new pack expansion
+ // just substitute into the pattern and create a new pack expansion
// type.
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1);
- QualType T = SemaRef.SubstType(PackExpansion->getPattern(),
+ QualType T = SemaRef.SubstType(PackExpansion->getPattern(),
TemplateArgs,
New->getLocation(), New->getDeclName());
if (T.isNull())
break;
-
+
T = SemaRef.Context.getPackExpansionType(T, NumExpansions);
Exceptions.push_back(T);
continue;
@@ -2230,8 +2251,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
bool Invalid = false;
for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, ArgIdx);
-
- QualType T = SemaRef.SubstType(PackExpansion->getPattern(),
+
+ QualType T = SemaRef.SubstType(PackExpansion->getPattern(),
TemplateArgs,
New->getLocation(), New->getDeclName());
if (T.isNull()) {
@@ -2247,11 +2268,11 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
continue;
}
-
+
QualType T
= SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs,
New->getLocation(), New->getDeclName());
- if (T.isNull() ||
+ if (T.isNull() ||
SemaRef.CheckSpecifiedExceptionType(T, New->getLocation()))
continue;
@@ -2262,10 +2283,24 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs);
if (E.isUsable())
+ E = SemaRef.CheckBooleanCondition(E.get(), E.get()->getLocStart());
+
+ if (E.isUsable()) {
+ SourceLocation ErrLoc;
+ llvm::APSInt NoexceptVal;
NoexceptExpr = E.take();
+ if (!NoexceptExpr->isTypeDependent() &&
+ !NoexceptExpr->isValueDependent() &&
+ !NoexceptExpr->isIntegerConstantExpr(NoexceptVal, SemaRef.Context,
+ &ErrLoc, /*evaluated=*/false)){
+ SemaRef.Diag(ErrLoc, diag::err_noexcept_needs_constant_expression)
+ << NoexceptExpr->getSourceRange();
+ NoexceptExpr = 0;
+ }
+ }
}
- // Rebuild the function type
+ // Rebuild the function type
FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
EPI.ExceptionSpecType = Proto->getExceptionSpecType();
@@ -2283,6 +2318,13 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
EPI));
}
+ // C++0x [dcl.constexpr]p6: If the instantiated template specialization of
+ // a constexpr function template satisfies the requirements for a constexpr
+ // function, then it is a constexpr function.
+ if (Tmpl->isConstexpr() &&
+ SemaRef.CheckConstexprFunctionDecl(New, Sema::CCK_Instantiation))
+ New->setConstexpr(true);
+
const FunctionDecl* Definition = Tmpl;
// Get the definition. Leaves the variable unchanged if undefined.
@@ -2337,8 +2379,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (Function->isInvalidDecl() || Function->isDefined())
return;
- // Never instantiate an explicit specialization.
- if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ // Never instantiate an explicit specialization except if it is a class scope
+ // explicit specialization.
+ if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization &&
+ !Function->getClassScopeSpecializationPattern())
return;
// Find the function body that we'll be substituting.
@@ -2362,7 +2406,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
}
// Call the LateTemplateParser callback if there a need to late parse
- // a templated function definition.
+ // a templated function definition.
if (!Pattern && PatternDecl->isLateTemplateParsed() &&
LateTemplateParser) {
LateTemplateParser(OpaqueParser, PatternDecl);
@@ -2372,16 +2416,16 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (!Pattern && !PatternDecl->isDefaulted()) {
if (DefinitionRequired) {
if (Function->getPrimaryTemplate())
- Diag(PointOfInstantiation,
+ Diag(PointOfInstantiation,
diag::err_explicit_instantiation_undefined_func_template)
<< Function->getPrimaryTemplate();
else
- Diag(PointOfInstantiation,
+ Diag(PointOfInstantiation,
diag::err_explicit_instantiation_undefined_member)
<< 1 << Function->getDeclName() << Function->getDeclContext();
-
+
if (PatternDecl)
- Diag(PatternDecl->getLocation(),
+ Diag(PatternDecl->getLocation(),
diag::note_explicit_instantiation_here);
Function->setInvalidDecl();
} else if (Function->getTemplateSpecializationKind()
@@ -2404,19 +2448,19 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
if (Inst)
- return;
-
+ return;
+
// If we're performing recursive template instantiation, create our own
// queue of pending implicit instantiations that we will instantiate later,
// while we're still within our own instantiation context.
- llvm::SmallVector<VTableUse, 16> SavedVTableUses;
+ SmallVector<VTableUse, 16> SavedVTableUses;
std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
if (Recursive) {
VTableUses.swap(SavedVTableUses);
PendingInstantiations.swap(SavedPendingInstantiations);
}
- EnterExpressionEvaluationContext EvalContext(*this,
+ EnterExpressionEvaluationContext EvalContext(*this,
Sema::PotentiallyEvaluated);
ActOnStartOfFunctionDef(0, Function);
@@ -2445,11 +2489,11 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
++FParamIdx;
continue;
}
-
+
// Expand the parameter pack.
Scope.MakeInstantiatedLocalArgPack(PatternParam);
- for (unsigned NumFParams = Function->getNumParams();
- FParamIdx < NumFParams;
+ for (unsigned NumFParams = Function->getNumParams();
+ FParamIdx < NumFParams;
++FParamIdx) {
ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
FunctionParam->setDeclName(PatternParam->getDeclName());
@@ -2481,7 +2525,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (Body.isInvalid())
Function->setInvalidDecl();
-
+
ActOnFinishFunctionBody(Function, Body.get(),
/*IsInstantiation=*/true);
}
@@ -2545,7 +2589,7 @@ void Sema::InstantiateStaticDataMemberDefinition(
// Find the out-of-line definition of this static data member.
VarDecl *Def = Var->getInstantiatedFromStaticDataMember();
assert(Def && "This data member was not instantiated from a template?");
- assert(Def->isStaticDataMember() && "Not a static data member?");
+ assert(Def->isStaticDataMember() && "Not a static data member?");
Def = Def->getOutOfLineDefinition();
if (!Def) {
@@ -2555,7 +2599,7 @@ void Sema::InstantiateStaticDataMemberDefinition(
// another translation unit.
if (DefinitionRequired) {
Def = Var->getInstantiatedFromStaticDataMember();
- Diag(PointOfInstantiation,
+ Diag(PointOfInstantiation,
diag::err_explicit_instantiation_undefined_member)
<< 2 << Var->getDeclName() << Var->getDeclContext();
Diag(Def->getLocation(), diag::note_explicit_instantiation_here);
@@ -2571,12 +2615,12 @@ void Sema::InstantiateStaticDataMemberDefinition(
// Never instantiate an explicit specialization.
if (Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
return;
-
+
// C++0x [temp.explicit]p9:
// Except for inline functions, other explicit instantiation declarations
// have the effect of suppressing the implicit instantiation of the entity
// to which they refer.
- if (Var->getTemplateSpecializationKind()
+ if (Var->getTemplateSpecializationKind()
== TSK_ExplicitInstantiationDeclaration)
return;
@@ -2591,7 +2635,7 @@ void Sema::InstantiateStaticDataMemberDefinition(
// If we're performing recursive template instantiation, create our own
// queue of pending implicit instantiations that we will instantiate later,
// while we're still within our own instantiation context.
- llvm::SmallVector<VTableUse, 16> SavedVTableUses;
+ SmallVector<VTableUse, 16> SavedVTableUses;
std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
if (Recursive) {
VTableUses.swap(SavedVTableUses);
@@ -2639,14 +2683,26 @@ void Sema::InstantiateStaticDataMemberDefinition(
}
}
+static MultiInitializer CreateMultiInitializer(SmallVectorImpl<Expr*> &Args,
+ const CXXCtorInitializer *Init) {
+ // FIXME: This is a hack that will do slightly the wrong thing for an
+ // initializer of the form foo({...}).
+ // The right thing to do would be to modify InstantiateInitializer to create
+ // the MultiInitializer.
+ if (Args.size() == 1 && isa<InitListExpr>(Args[0]))
+ return MultiInitializer(Args[0]);
+ return MultiInitializer(Init->getLParenLoc(), Args.data(),
+ Args.size(), Init->getRParenLoc());
+}
+
void
Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
const CXXConstructorDecl *Tmpl,
const MultiLevelTemplateArgumentList &TemplateArgs) {
- llvm::SmallVector<MemInitTy*, 4> NewInits;
+ SmallVector<CXXCtorInitializer*, 4> NewInits;
bool AnyErrors = false;
-
+
// Instantiate all the initializers.
for (CXXConstructorDecl::init_const_iterator Inits = Tmpl->init_begin(),
InitsEnd = Tmpl->init_end();
@@ -2662,20 +2718,19 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
ASTOwningVector<Expr*> NewArgs(*this);
SourceLocation EllipsisLoc;
-
+
if (Init->isPackExpansion()) {
// This is a pack expansion. We should expand it now.
TypeLoc BaseTL = Init->getBaseClassInfo()->getTypeLoc();
- llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
collectUnexpandedParameterPacks(BaseTL, Unexpanded);
bool ShouldExpand = false;
bool RetainExpansion = false;
llvm::Optional<unsigned> NumExpansions;
- if (CheckParameterPacksForExpansion(Init->getEllipsisLoc(),
+ if (CheckParameterPacksForExpansion(Init->getEllipsisLoc(),
BaseTL.getSourceRange(),
- Unexpanded.data(),
- Unexpanded.size(),
- TemplateArgs, ShouldExpand,
+ Unexpanded,
+ TemplateArgs, ShouldExpand,
RetainExpansion,
NumExpansions)) {
AnyErrors = true;
@@ -2683,22 +2738,22 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
continue;
}
assert(ShouldExpand && "Partial instantiation of base initializer?");
-
- // Loop over all of the arguments in the argument pack(s),
+
+ // Loop over all of the arguments in the argument pack(s),
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, I);
// Instantiate the initializer.
- if (InstantiateInitializer(*this, Init->getInit(), TemplateArgs,
+ if (InstantiateInitializer(Init->getInit(), TemplateArgs,
LParenLoc, NewArgs, RParenLoc)) {
AnyErrors = true;
break;
}
// Instantiate the base type.
- TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(),
- TemplateArgs,
- Init->getSourceLocation(),
+ TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(),
+ TemplateArgs,
+ Init->getSourceLocation(),
New->getDeclName());
if (!BaseTInfo) {
AnyErrors = true;
@@ -2706,52 +2761,45 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
}
// Build the initializer.
- MemInitResult NewInit = BuildBaseInitializer(BaseTInfo->getType(),
- BaseTInfo,
- (Expr **)NewArgs.data(),
- NewArgs.size(),
- Init->getLParenLoc(),
- Init->getRParenLoc(),
+ MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init));
+ MemInitResult NewInit = BuildBaseInitializer(BaseTInfo->getType(),
+ BaseTInfo, MultiInit,
New->getParent(),
SourceLocation());
if (NewInit.isInvalid()) {
AnyErrors = true;
break;
}
-
+
NewInits.push_back(NewInit.get());
NewArgs.clear();
}
-
+
continue;
}
// Instantiate the initializer.
- if (InstantiateInitializer(*this, Init->getInit(), TemplateArgs,
+ if (InstantiateInitializer(Init->getInit(), TemplateArgs,
LParenLoc, NewArgs, RParenLoc)) {
AnyErrors = true;
continue;
}
-
+
MemInitResult NewInit;
if (Init->isBaseInitializer()) {
- TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(),
- TemplateArgs,
- Init->getSourceLocation(),
+ TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(),
+ TemplateArgs,
+ Init->getSourceLocation(),
New->getDeclName());
if (!BaseTInfo) {
AnyErrors = true;
New->setInvalidDecl();
continue;
}
-
- NewInit = BuildBaseInitializer(BaseTInfo->getType(), BaseTInfo,
- (Expr **)NewArgs.data(),
- NewArgs.size(),
- Init->getLParenLoc(),
- Init->getRParenLoc(),
- New->getParent(),
- EllipsisLoc);
+
+ MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init));
+ NewInit = BuildBaseInitializer(BaseTInfo->getType(), BaseTInfo, MultiInit,
+ New->getParent(), EllipsisLoc);
} else if (Init->isMemberInitializer()) {
FieldDecl *Member = cast_or_null<FieldDecl>(FindInstantiatedDecl(
Init->getMemberLocation(),
@@ -2763,11 +2811,9 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
continue;
}
- NewInit = BuildMemberInitializer(Member, (Expr **)NewArgs.data(),
- NewArgs.size(),
- Init->getSourceLocation(),
- Init->getLParenLoc(),
- Init->getRParenLoc());
+ MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init));
+ NewInit = BuildMemberInitializer(Member, MultiInit,
+ Init->getSourceLocation());
} else if (Init->isIndirectMemberInitializer()) {
IndirectFieldDecl *IndirectMember =
cast_or_null<IndirectFieldDecl>(FindInstantiatedDecl(
@@ -2777,14 +2823,12 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
if (!IndirectMember) {
AnyErrors = true;
New->setInvalidDecl();
- continue;
+ continue;
}
-
- NewInit = BuildMemberInitializer(IndirectMember, (Expr **)NewArgs.data(),
- NewArgs.size(),
- Init->getSourceLocation(),
- Init->getLParenLoc(),
- Init->getRParenLoc());
+
+ MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init));
+ NewInit = BuildMemberInitializer(IndirectMember, MultiInit,
+ Init->getSourceLocation());
}
if (NewInit.isInvalid()) {
@@ -2794,7 +2838,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
// FIXME: It would be nice if ASTOwningVector had a release function.
NewArgs.take();
- NewInits.push_back((MemInitTy *)NewInit.get());
+ NewInits.push_back(NewInit.get());
}
}
@@ -2824,20 +2868,20 @@ static bool isInstantiationOf(ClassTemplateDecl *Pattern,
static bool isInstantiationOf(FunctionTemplateDecl *Pattern,
FunctionTemplateDecl *Instance) {
Pattern = Pattern->getCanonicalDecl();
-
+
do {
Instance = Instance->getCanonicalDecl();
if (Pattern == Instance) return true;
Instance = Instance->getInstantiatedFromMemberTemplate();
} while (Instance);
-
+
return false;
}
-static bool
+static bool
isInstantiationOf(ClassTemplatePartialSpecializationDecl *Pattern,
ClassTemplatePartialSpecializationDecl *Instance) {
- Pattern
+ Pattern
= cast<ClassTemplatePartialSpecializationDecl>(Pattern->getCanonicalDecl());
do {
Instance = cast<ClassTemplatePartialSpecializationDecl>(
@@ -2846,7 +2890,7 @@ isInstantiationOf(ClassTemplatePartialSpecializationDecl *Pattern,
return true;
Instance = Instance->getInstantiatedFromMember();
} while (Instance);
-
+
return false;
}
@@ -3052,11 +3096,11 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
llvm::PointerUnion<Decl *, DeclArgumentPack *> *Found
= CurrentInstantiationScope->findInstantiationOf(D);
-
+
if (Found) {
if (Decl *FD = Found->dyn_cast<Decl *>())
return cast<NamedDecl>(FD);
-
+
unsigned PackIdx = ArgumentPackSubstitutionIndex;
return cast<NamedDecl>((*Found->get<DeclArgumentPack *>())[PackIdx]);
}
@@ -3064,10 +3108,10 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// If we didn't find the decl, then we must have a label decl that hasn't
// been found yet. Lazily instantiate it and return it now.
assert(isa<LabelDecl>(D));
-
+
Decl *Inst = SubstDecl(D, CurContext, TemplateArgs);
assert(Inst && "Failed to instantiate label??");
-
+
CurrentInstantiationScope->InstantiatedLocal(D, Inst);
return cast<LabelDecl>(Inst);
}
@@ -3075,7 +3119,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
if (!Record->isDependentContext())
return D;
-
+
// If the RecordDecl is actually the injected-class-name or a
// "templated" declaration for a class template, class template
// partial specialization, or a member class of a class template,
@@ -3083,7 +3127,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// or partial specialization to find the new DeclContext.
QualType T;
ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate();
-
+
if (ClassTemplate) {
T = ClassTemplate->getInjectedClassNameSpecialization();
} else if (ClassTemplatePartialSpecializationDecl *PartialSpec
@@ -3096,26 +3140,26 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
assert(isa<InjectedClassNameType>(T) &&
"type of partial specialization is not an InjectedClassNameType");
T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType();
- }
-
+ }
+
if (!T.isNull()) {
// Substitute into the injected-class-name to get the type
// corresponding to the instantiation we want, which may also be
// the current instantiation (if we're in a template
// definition). This substitution should never fail, since we
// know we can instantiate the injected-class-name or we
- // wouldn't have gotten to the injected-class-name!
+ // wouldn't have gotten to the injected-class-name!
// FIXME: Can we use the CurrentInstantiationScope to avoid this
// extra instantiation in the common case?
T = SubstType(T, TemplateArgs, Loc, DeclarationName());
assert(!T.isNull() && "Instantiation of injected-class-name cannot fail.");
-
+
if (!T->isDependentType()) {
assert(T->isRecordType() && "Instantiation must produce a record type");
return T->getAs<RecordType>()->getDecl();
}
-
+
// We are performing "partial" template instantiation to create
// the member declarations for the members of a class template
// specialization. Therefore, D is actually referring to something
@@ -3128,7 +3172,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
DC = DC->getParent()) {
if (ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(DC))
- if (isInstantiationOf(ClassTemplate,
+ if (isInstantiationOf(ClassTemplate,
Spec->getSpecializedTemplate()))
return Spec;
@@ -3139,10 +3183,10 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// We're performing "instantiation" of a member of the current
// instantiation while we are type-checking the
// definition. Compute the declaration context and return that.
- assert(!SawNonDependentContext &&
+ assert(!SawNonDependentContext &&
"No dependent context while instantiating record");
DeclContext *DC = computeDeclContext(T);
- assert(DC &&
+ assert(DC &&
"Unable to find declaration for the current instantiation");
return cast<CXXRecordDecl>(DC);
}
@@ -3153,7 +3197,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
if (!ParentDC->isDependentContext())
return D;
-
+
ParentDC = FindInstantiatedContext(Loc, ParentDC, TemplateArgs);
if (!ParentDC)
return 0;
@@ -3207,7 +3251,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// declaration failed to instantiate. There's no point in complaining
// further, since this is normal in invalid code.
} else if (IsBeingInstantiated) {
- // The class in which this member exists is currently being
+ // The class in which this member exists is currently being
// instantiated, and we haven't gotten around to instantiating this
// member yet. This can happen when the code uses forward declarations
// of member classes, and introduces ordering dependencies via
@@ -3221,7 +3265,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
llvm_unreachable("Unable to find instantiation of declaration!");
}
}
-
+
D = Result;
}
@@ -3231,6 +3275,14 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
/// \brief Performs template instantiation for all implicit template
/// instantiations we have seen until this point.
void Sema::PerformPendingInstantiations(bool LocalOnly) {
+ // Load pending instantiations from the external source.
+ if (!LocalOnly && ExternalSource) {
+ SmallVector<std::pair<ValueDecl *, SourceLocation>, 4> Pending;
+ ExternalSource->ReadPendingInstantiations(Pending);
+ PendingInstantiations.insert(PendingInstantiations.begin(),
+ Pending.begin(), Pending.end());
+ }
+
while (!PendingLocalImplicitInstantiations.empty() ||
(!LocalOnly && !PendingInstantiations.empty())) {
PendingImplicitInstantiation Inst;
@@ -3267,7 +3319,7 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
// and removed the need for implicit instantiation.
switch (Var->getMostRecentDeclaration()->getTemplateSpecializationKind()) {
case TSK_Undeclared:
- assert(false && "Cannot instantitiate an undeclared specialization.");
+ llvm_unreachable("Cannot instantitiate an undeclared specialization.");
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitSpecialization:
continue; // No longer need to instantiate this type.
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index daa1523363c0..e383db935064 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -32,11 +32,11 @@ namespace {
typedef RecursiveASTVisitor<CollectUnexpandedParameterPacksVisitor>
inherited;
- llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded;
+ SmallVectorImpl<UnexpandedParameterPack> &Unexpanded;
public:
explicit CollectUnexpandedParameterPacksVisitor(
- llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded)
+ SmallVectorImpl<UnexpandedParameterPack> &Unexpanded)
: Unexpanded(Unexpanded) { }
bool shouldWalkTypesOfTypeLocs() const { return false; }
@@ -158,9 +158,9 @@ namespace {
static void
DiagnoseUnexpandedParameterPacks(Sema &S, SourceLocation Loc,
Sema::UnexpandedParameterPackContext UPPC,
- const llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
- llvm::SmallVector<SourceLocation, 4> Locations;
- llvm::SmallVector<IdentifierInfo *, 4> Names;
+ const SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
+ SmallVector<SourceLocation, 4> Locations;
+ SmallVector<IdentifierInfo *, 4> Names;
llvm::SmallPtrSet<IdentifierInfo *, 4> NamesKnown;
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
@@ -201,7 +201,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
if (!T->getType()->containsUnexpandedParameterPack())
return false;
- llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(
T->getTypeLoc());
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
@@ -217,7 +217,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(Expr *E,
if (!E->containsUnexpandedParameterPack())
return false;
- llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(E);
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
DiagnoseUnexpandedParameterPacks(*this, E->getLocStart(), UPPC, Unexpanded);
@@ -233,7 +233,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS,
!SS.getScopeRep()->containsUnexpandedParameterPack())
return false;
- llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
CollectUnexpandedParameterPacksVisitor(Unexpanded)
.TraverseNestedNameSpecifier(SS.getScopeRep());
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
@@ -270,7 +270,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo,
break;
}
- llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
CollectUnexpandedParameterPacksVisitor(Unexpanded)
.TraverseType(NameInfo.getName().getCXXNameType());
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
@@ -285,7 +285,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
if (Template.isNull() || !Template.containsUnexpandedParameterPack())
return false;
- llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
CollectUnexpandedParameterPacksVisitor(Unexpanded)
.TraverseTemplateName(Template);
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
@@ -299,7 +299,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg,
!Arg.getArgument().containsUnexpandedParameterPack())
return false;
- llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
CollectUnexpandedParameterPacksVisitor(Unexpanded)
.TraverseTemplateArgumentLoc(Arg);
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
@@ -308,24 +308,24 @@ bool Sema::DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg,
}
void Sema::collectUnexpandedParameterPacks(TemplateArgument Arg,
- llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
+ SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
CollectUnexpandedParameterPacksVisitor(Unexpanded)
.TraverseTemplateArgument(Arg);
}
void Sema::collectUnexpandedParameterPacks(TemplateArgumentLoc Arg,
- llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
+ SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
CollectUnexpandedParameterPacksVisitor(Unexpanded)
.TraverseTemplateArgumentLoc(Arg);
}
void Sema::collectUnexpandedParameterPacks(QualType T,
- llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
+ SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(T);
}
void Sema::collectUnexpandedParameterPacks(TypeLoc TL,
- llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
+ SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(TL);
}
@@ -462,8 +462,7 @@ getDepthAndIndex(NamedDecl *ND) {
bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
SourceRange PatternRange,
- const UnexpandedParameterPack *Unexpanded,
- unsigned NumUnexpanded,
+ ArrayRef<UnexpandedParameterPack> Unexpanded,
const MultiLevelTemplateArgumentList &TemplateArgs,
bool &ShouldExpand,
bool &RetainExpansion,
@@ -473,19 +472,21 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
std::pair<IdentifierInfo *, SourceLocation> FirstPack;
bool HaveFirstPack = false;
- for (unsigned I = 0; I != NumUnexpanded; ++I) {
+ for (ArrayRef<UnexpandedParameterPack>::iterator i = Unexpanded.begin(),
+ end = Unexpanded.end();
+ i != end; ++i) {
// Compute the depth and index for this parameter pack.
unsigned Depth = 0, Index = 0;
IdentifierInfo *Name;
bool IsFunctionParameterPack = false;
if (const TemplateTypeParmType *TTP
- = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) {
+ = i->first.dyn_cast<const TemplateTypeParmType *>()) {
Depth = TTP->getDepth();
Index = TTP->getIndex();
Name = TTP->getIdentifier();
} else {
- NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>();
+ NamedDecl *ND = i->first.get<NamedDecl *>();
if (isa<ParmVarDecl>(ND))
IsFunctionParameterPack = true;
else
@@ -502,7 +503,7 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation
= CurrentInstantiationScope->findInstantiationOf(
- Unexpanded[I].first.get<NamedDecl *>());
+ i->first.get<NamedDecl *>());
if (Instantiation->is<DeclArgumentPack *>()) {
// We could expand this function parameter pack.
NewPackSize = Instantiation->get<DeclArgumentPack *>()->size();
@@ -545,7 +546,7 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
// Record it.
NumExpansions = NewPackSize;
FirstPack.first = Name;
- FirstPack.second = Unexpanded[I].second;
+ FirstPack.second = i->second;
HaveFirstPack = true;
continue;
}
@@ -557,11 +558,11 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
if (HaveFirstPack)
Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict)
<< FirstPack.first << Name << *NumExpansions << NewPackSize
- << SourceRange(FirstPack.second) << SourceRange(Unexpanded[I].second);
+ << SourceRange(FirstPack.second) << SourceRange(i->second);
else
Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel)
<< Name << *NumExpansions << NewPackSize
- << SourceRange(Unexpanded[I].second);
+ << SourceRange(i->second);
return true;
}
}
@@ -572,7 +573,7 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
unsigned Sema::getNumArgumentsInExpansion(QualType T,
const MultiLevelTemplateArgumentList &TemplateArgs) {
QualType Pattern = cast<PackExpansionType>(T)->getPattern();
- llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(Pattern);
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
@@ -618,7 +619,8 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
switch (DS.getTypeSpecType()) {
case TST_typename:
case TST_typeofType:
- case TST_underlyingType: {
+ case TST_underlyingType:
+ case TST_atomic: {
QualType T = DS.getRepAsType().get();
if (!T.isNull() && T->containsUnexpandedParameterPack())
return true;
@@ -639,6 +641,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
case TST_char16:
case TST_char32:
case TST_int:
+ case TST_half:
case TST_float:
case TST_double:
case TST_bool:
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index f3e73ec5a723..2b563a50a99f 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -52,18 +52,18 @@ static bool isOmittedBlockReturnType(const Declarator &D) {
/// doesn't apply to the given type.
static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
QualType type) {
- bool useInstantiationLoc = false;
+ bool useExpansionLoc = false;
unsigned diagID = 0;
switch (attr.getKind()) {
case AttributeList::AT_objc_gc:
diagID = diag::warn_pointer_attribute_wrong_type;
- useInstantiationLoc = true;
+ useExpansionLoc = true;
break;
case AttributeList::AT_objc_ownership:
diagID = diag::warn_objc_object_attribute_wrong_type;
- useInstantiationLoc = true;
+ useExpansionLoc = true;
break;
default:
@@ -73,10 +73,10 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
}
SourceLocation loc = attr.getLoc();
- llvm::StringRef name = attr.getName()->getName();
+ StringRef name = attr.getName()->getName();
// The GC attributes are usually written with macros; special-case them.
- if (useInstantiationLoc && loc.isMacroID() && attr.getParameterName()) {
+ if (useExpansionLoc && loc.isMacroID() && attr.getParameterName()) {
if (attr.getParameterName()->isStr("strong")) {
if (S.findMacroSpelling(loc, "__strong")) name = "__strong";
} else if (attr.getParameterName()->isStr("weak")) {
@@ -125,11 +125,11 @@ namespace {
bool hasSavedAttrs;
/// The original set of attributes on the DeclSpec.
- llvm::SmallVector<AttributeList*, 2> savedAttrs;
+ SmallVector<AttributeList*, 2> savedAttrs;
/// A list of attributes to diagnose the uselessness of when the
/// processing is complete.
- llvm::SmallVector<AttributeList*, 2> ignoredTypeAttrs;
+ SmallVector<AttributeList*, 2> ignoredTypeAttrs;
public:
TypeProcessingState(Sema &sema, Declarator &declarator)
@@ -183,7 +183,7 @@ namespace {
/// Diagnose all the ignored type attributes, given that the
/// declarator worked out to the given type.
void diagnoseIgnoredTypeAttrs(QualType type) const {
- for (llvm::SmallVectorImpl<AttributeList*>::const_iterator
+ for (SmallVectorImpl<AttributeList*>::const_iterator
i = ignoredTypeAttrs.begin(), e = ignoredTypeAttrs.end();
i != e; ++i)
diagnoseBadTypeAttribute(getSema(), **i, type);
@@ -664,7 +664,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// each struct declaration and type name."
// FIXME: Does Microsoft really have the implicit int extension in C++?
if (S.getLangOptions().CPlusPlus &&
- !S.getLangOptions().Microsoft) {
+ !S.getLangOptions().MicrosoftExt) {
S.Diag(DeclLoc, diag::err_missing_type_specifier)
<< DS.getSourceRange();
@@ -711,6 +711,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
}
break;
}
+ case DeclSpec::TST_half: Result = Context.HalfTy; break;
case DeclSpec::TST_float: Result = Context.FloatTy; break;
case DeclSpec::TST_double:
if (DS.getTypeSpecWidth() == DeclSpec::TSW_long)
@@ -856,6 +857,16 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
Result = Context.UnknownAnyTy;
break;
+ case DeclSpec::TST_atomic:
+ Result = S.GetTypeFromParser(DS.getRepAsType());
+ assert(!Result.isNull() && "Didn't get a type for _Atomic?");
+ Result = S.BuildAtomicType(Result, DS.getTypeSpecTypeLoc());
+ if (Result.isNull()) {
+ Result = Context.IntTy;
+ declarator.setInvalidType(true);
+ }
+ break;
+
case DeclSpec::TST_error:
Result = Context.IntTy;
declarator.setInvalidType(true);
@@ -1038,6 +1049,11 @@ static QualType inferARCLifetimeForPointee(Sema &S, QualType type,
} else if (type->isObjCARCImplicitlyUnretainedType()) {
implicitLifetime = Qualifiers::OCL_ExplicitNone;
+ // If we are in an unevaluated context, like sizeof, assume ExplicitNone and
+ // don't give error.
+ } else if (S.ExprEvalContexts.back().Context == Sema::Unevaluated) {
+ implicitLifetime = Qualifiers::OCL_ExplicitNone;
+
// If that failed, give an error and recover using __autoreleasing.
} else {
// These types can show up in private ivars in system headers, so
@@ -1419,13 +1435,26 @@ QualType Sema::BuildFunctionType(QualType T,
<< T->isFunctionType() << T;
return QualType();
}
-
+
+ // Functions cannot return half FP.
+ if (T->isHalfType()) {
+ Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 1 <<
+ FixItHint::CreateInsertion(Loc, "*");
+ return QualType();
+ }
+
bool Invalid = false;
for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) {
+ // FIXME: Loc is too inprecise here, should use proper locations for args.
QualType ParamType = Context.getAdjustedParameterType(ParamTypes[Idx]);
if (ParamType->isVoidType()) {
Diag(Loc, diag::err_param_with_void_type);
Invalid = true;
+ } else if (ParamType->isHalfType()) {
+ // Disallow half FP arguments.
+ Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 0 <<
+ FixItHint::CreateInsertion(Loc, "*");
+ Invalid = true;
}
ParamTypes[Idx] = ParamType;
@@ -1492,7 +1521,7 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
// 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.Target.getCXXABI() == CXXABI_Microsoft &&
+ if (Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft &&
RequireCompleteType(Loc, Class, diag::err_incomplete_type))
return QualType();
@@ -1745,9 +1774,10 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
switch (D.getContext()) {
case Declarator::KNRTypeListContext:
- assert(0 && "K&R type lists aren't allowed in C++");
+ llvm_unreachable("K&R type lists aren't allowed in C++");
break;
- case Declarator::ObjCPrototypeContext:
+ case Declarator::ObjCParameterContext:
+ case Declarator::ObjCResultContext:
case Declarator::PrototypeContext:
Error = 0; // Function prototype
break;
@@ -1755,7 +1785,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)
break;
switch (cast<TagDecl>(SemaRef.CurContext)->getTagKind()) {
- case TTK_Enum: assert(0 && "unhandled tag kind"); break;
+ case TTK_Enum: llvm_unreachable("unhandled tag kind");
case TTK_Struct: Error = 1; /* Struct member */ break;
case TTK_Union: Error = 2; /* Union member */ break;
case TTK_Class: Error = 3; /* Class member */ break;
@@ -1825,7 +1855,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
}
if (SemaRef.getLangOptions().CPlusPlus &&
- OwnedTagDecl && OwnedTagDecl->isDefinition()) {
+ OwnedTagDecl && OwnedTagDecl->isCompleteDefinition()) {
// Check the contexts where C++ forbids the declaration of a new class
// or enumeration in a type-specifier-seq.
switch (D.getContext()) {
@@ -1856,7 +1886,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
<< SemaRef.Context.getTypeDeclType(OwnedTagDecl);
break;
case Declarator::PrototypeContext:
- case Declarator::ObjCPrototypeContext:
+ case Declarator::ObjCParameterContext:
+ case Declarator::ObjCResultContext:
case Declarator::KNRTypeListContext:
// C++ [dcl.fct]p6:
// Types shall not be defined in return or parameter types.
@@ -1916,7 +1947,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
state.setCurrentChunkIndex(chunkIndex);
DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex);
switch (DeclType.Kind) {
- default: assert(0 && "Unknown decltype!");
+ default: llvm_unreachable("Unknown decltype!");
case DeclaratorChunk::Paren:
T = S.BuildParenType(T);
break;
@@ -2045,6 +2076,15 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
D.setInvalidType(true);
}
+ // 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);
+ }
+
// cv-qualifiers on return types are pointless except when the type is a
// class type in C++.
if (isa<PointerType>(T) && T.getLocalCVRQualifiers() &&
@@ -2077,7 +2117,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// C++ [dcl.fct]p6:
// Types shall not be defined in return or parameter types.
TagDecl *Tag = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
- if (Tag->isDefinition())
+ if (Tag->isCompleteDefinition())
S.Diag(Tag->getLocation(), diag::err_type_defined_in_result_type)
<< Context.getTypeDeclType(Tag);
}
@@ -2127,10 +2167,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Otherwise, we have a function with an argument list that is
// potentially variadic.
- llvm::SmallVector<QualType, 16> ArgTys;
+ SmallVector<QualType, 16> ArgTys;
ArgTys.reserve(FTI.NumArgs);
- llvm::SmallVector<bool, 16> ConsumedArguments;
+ SmallVector<bool, 16> ConsumedArguments;
ConsumedArguments.reserve(FTI.NumArgs);
bool HasAnyConsumedArguments = false;
@@ -2168,6 +2208,13 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Do not add 'void' to the ArgTys list.
break;
}
+ } 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();
} else if (!FTI.hasPrototype) {
if (ArgTy->isPromotableIntegerType()) {
ArgTy = Context.getPromotedIntegerType(ArgTy);
@@ -2192,7 +2239,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if (HasAnyConsumedArguments)
EPI.ConsumedArguments = ConsumedArguments.data();
- llvm::SmallVector<QualType, 4> Exceptions;
+ SmallVector<QualType, 4> Exceptions;
EPI.ExceptionSpecType = FTI.getExceptionSpecType();
if (FTI.getExceptionSpecType() == EST_Dynamic) {
Exceptions.reserve(FTI.NumExceptions);
@@ -2320,6 +2367,20 @@ 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.
+ if (D.getDeclSpec().isConstexprSpecified() && !FreeFunction &&
+ 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);
+ }
+
// C++0x [dcl.fct]p6:
// A ref-qualifier shall only be part of the function type for a
// non-static member function, the function type to which a pointer to
@@ -2457,13 +2518,17 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// it expands those parameter packs.
if (T->containsUnexpandedParameterPack())
T = Context.getPackExpansionType(T, llvm::Optional<unsigned>());
- else if (!LangOpts.CPlusPlus0x)
- S.Diag(D.getEllipsisLoc(), diag::ext_variadic_templates);
+ else
+ S.Diag(D.getEllipsisLoc(),
+ LangOpts.CPlusPlus0x
+ ? diag::warn_cxx98_compat_variadic_templates
+ : diag::ext_variadic_templates);
break;
case Declarator::FileContext:
case Declarator::KNRTypeListContext:
- case Declarator::ObjCPrototypeContext: // FIXME: special diagnostic here?
+ case Declarator::ObjCParameterContext: // FIXME: special diagnostic here?
+ case Declarator::ObjCResultContext: // FIXME: special diagnostic here?
case Declarator::TypeNameContext:
case Declarator::CXXNewContext:
case Declarator::AliasDeclContext:
@@ -2850,6 +2915,14 @@ namespace {
void VisitTagTypeLoc(TagTypeLoc TL) {
TL.setNameLoc(DS.getTypeSpecTypeNameLoc());
}
+ void VisitAtomicTypeLoc(AtomicTypeLoc TL) {
+ TL.setKWLoc(DS.getTypeSpecTypeLoc());
+ TL.setParensRange(DS.getTypeofParensRange());
+
+ TypeSourceInfo *TInfo = 0;
+ Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
+ TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc());
+ }
void VisitTypeLoc(TypeLoc TL) {
// FIXME: add other typespec types and change this to an assert.
@@ -3030,7 +3103,7 @@ ParsedType Sema::CreateParsedType(QualType T, TypeSourceInfo *TInfo) {
void LocInfoType::getAsStringInternal(std::string &Str,
const PrintingPolicy &Policy) const {
- assert(false && "LocInfoType leaked into the type system; an opaque TypeTy*"
+ llvm_unreachable("LocInfoType leaked into the type system; an opaque TypeTy*"
" was used directly instead of getting the QualType through"
" GetTypeFromParser");
}
@@ -3045,6 +3118,12 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
if (D.isInvalidType())
return true;
+ // 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)
+ checkUnusedDeclAttributes(D);
+
if (getLangOptions().CPlusPlus) {
// Check that there are no default arguments (C++ only).
CheckExtraCXXDefaultArguments(D);
@@ -3053,6 +3132,13 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
return CreateParsedType(T, TInfo);
}
+ParsedType Sema::ActOnObjCInstanceType(SourceLocation Loc) {
+ QualType T = Context.getObjCInstanceType();
+ TypeSourceInfo *TInfo = Context.getTrivialTypeSourceInfo(T, Loc);
+ return CreateParsedType(T, TInfo);
+}
+
+
//===----------------------------------------------------------------------===//
// Type Attribute Processing
//===----------------------------------------------------------------------===//
@@ -3064,14 +3150,22 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
const AttributeList &Attr, Sema &S){
// If this type is already address space qualified, reject it.
- // Clause 6.7.3 - Type qualifiers: "No type shall be qualified by qualifiers
- // for two or more different address spaces."
+ // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified by
+ // qualifiers for two or more different address spaces."
if (Type.getAddressSpace()) {
S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers);
Attr.setInvalid();
return;
}
+ // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "A function type shall not be
+ // qualified by an address-space qualifier."
+ if (Type->isFunctionType()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_address_function_type);
+ Attr.setInvalid();
+ return;
+ }
+
// Check the attribute arguments.
if (Attr.getNumArgs() != 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
@@ -3122,15 +3216,18 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
return false;
Sema &S = state.getSema();
+ SourceLocation AttrLoc = attr.getLoc();
+ if (AttrLoc.isMacroID())
+ AttrLoc = S.getSourceManager().getImmediateExpansionRange(AttrLoc).first;
if (type.getQualifiers().getObjCLifetime()) {
- S.Diag(attr.getLoc(), diag::err_attr_objc_ownership_redundant)
+ S.Diag(AttrLoc, diag::err_attr_objc_ownership_redundant)
<< type;
return true;
}
if (!attr.getParameterName()) {
- S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string)
+ S.Diag(AttrLoc, diag::err_attribute_argument_n_not_string)
<< "objc_ownership" << 1;
attr.setInvalid();
return true;
@@ -3146,7 +3243,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
else if (attr.getParameterName()->isStr("autoreleasing"))
lifetime = Qualifiers::OCL_Autoreleasing;
else {
- S.Diag(attr.getLoc(), diag::warn_attribute_type_not_supported)
+ S.Diag(AttrLoc, diag::warn_attribute_type_not_supported)
<< "objc_ownership" << attr.getParameterName();
attr.setInvalid();
return true;
@@ -3164,7 +3261,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
// If we have a valid source location for the attribute, use an
// AttributedType instead.
- if (attr.getLoc().isValid())
+ if (AttrLoc.isValid())
type = S.Context.getAttributedType(AttributedType::attr_objc_ownership,
origType, type);
@@ -3175,10 +3272,11 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
// Actually, delay this until we know what we're parsing.
if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
S.DelayedDiagnostics.add(
- sema::DelayedDiagnostic::makeForbiddenType(attr.getLoc(),
+ sema::DelayedDiagnostic::makeForbiddenType(
+ S.getSourceManager().getExpansionLoc(AttrLoc),
diag::err_arc_weak_no_runtime, type, /*ignored*/ 0));
} else {
- S.Diag(attr.getLoc(), diag::err_arc_weak_no_runtime);
+ S.Diag(AttrLoc, diag::err_arc_weak_no_runtime);
}
attr.setInvalid();
@@ -3194,7 +3292,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) {
ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl();
if (Class->isArcWeakrefUnavailable()) {
- S.Diag(attr.getLoc(), diag::err_arc_unsupported_weak_class);
+ S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class);
S.Diag(ObjT->getInterfaceDecl()->getLocation(),
diag::note_class_declared);
}
@@ -3283,7 +3381,7 @@ namespace {
QualType Original;
const FunctionType *Fn;
- llvm::SmallVector<unsigned char /*WrapKind*/, 8> Stack;
+ SmallVector<unsigned char /*WrapKind*/, 8> Stack;
FunctionTypeUnwrapper(Sema &S, QualType T) : Original(T) {
while (true) {
@@ -3474,7 +3572,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
return true;
}
- if (CCOld != CC_Default) {
+ if (CCOld != (S.LangOpts.MRTD ? CC_X86StdCall : CC_Default)) {
// Should we diagnose reapplications of the same convention?
S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible)
<< FunctionType::getNameForCallConv(CC)
@@ -3718,32 +3816,44 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
switch (attr.getKind()) {
default: break;
+ case AttributeList::AT_may_alias:
+ // FIXME: This attribute needs to actually be handled, but if we ignore
+ // it it breaks large amounts of Linux software.
+ attr.setUsedAsTypeAttr();
+ break;
case AttributeList::AT_address_space:
HandleAddressSpaceTypeAttribute(type, attr, state.getSema());
+ attr.setUsedAsTypeAttr();
break;
OBJC_POINTER_TYPE_ATTRS_CASELIST:
if (!handleObjCPointerTypeAttr(state, attr, type))
distributeObjCPointerTypeAttr(state, attr, type);
+ attr.setUsedAsTypeAttr();
break;
case AttributeList::AT_vector_size:
HandleVectorSizeAttr(type, attr, state.getSema());
+ attr.setUsedAsTypeAttr();
break;
case AttributeList::AT_ext_vector_type:
if (state.getDeclarator().getDeclSpec().getStorageClassSpec()
!= DeclSpec::SCS_typedef)
HandleExtVectorTypeAttr(type, attr, state.getSema());
+ attr.setUsedAsTypeAttr();
break;
case AttributeList::AT_neon_vector_type:
HandleNeonVectorTypeAttr(type, attr, state.getSema(),
VectorType::NeonVector, "neon_vector_type");
+ attr.setUsedAsTypeAttr();
break;
case AttributeList::AT_neon_polyvector_type:
HandleNeonVectorTypeAttr(type, attr, state.getSema(),
VectorType::NeonPolyVector,
"neon_polyvector_type");
+ attr.setUsedAsTypeAttr();
break;
case AttributeList::AT_opencl_image_access:
HandleOpenCLImageAccessAttribute(type, attr, state.getSema());
+ attr.setUsedAsTypeAttr();
break;
case AttributeList::AT_ns_returns_retained:
@@ -3752,6 +3862,8 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
// fallthrough into the function attrs
FUNCTION_TYPE_ATTRS_CASELIST:
+ attr.setUsedAsTypeAttr();
+
// Never process function type attributes as part of the
// declaration-specifiers.
if (isDeclSpec)
@@ -3954,6 +4066,121 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
std::make_pair(SourceLocation(), PDiag(0)));
}
+/// @brief Ensure that the type T is a literal type.
+///
+/// This routine checks whether the type @p T is a literal type. If @p T is an
+/// incomplete type, an attempt is made to complete it. If @p T is a literal
+/// type, or @p AllowIncompleteType is true and @p T is an incomplete type,
+/// returns false. Otherwise, this routine issues the diagnostic @p PD (giving
+/// it the type @p T), along with notes explaining why the type is not a
+/// literal type, and returns true.
+///
+/// @param Loc The location in the source that the non-literal type
+/// diagnostic should refer to.
+///
+/// @param T The type that this routine is examining for literalness.
+///
+/// @param PD The partial diagnostic that will be printed out if T is not a
+/// literal type.
+///
+/// @param AllowIncompleteType If true, an incomplete type will be considered
+/// acceptable.
+///
+/// @returns @c true if @p T is not a literal type and a diagnostic was emitted,
+/// @c false otherwise.
+bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
+ const PartialDiagnostic &PD,
+ bool AllowIncompleteType) {
+ assert(!T->isDependentType() && "type should not be dependent");
+
+ bool Incomplete = RequireCompleteType(Loc, T, 0);
+ if (T->isLiteralType() || (AllowIncompleteType && Incomplete))
+ return false;
+
+ if (PD.getDiagID() == 0)
+ return true;
+
+ Diag(Loc, PD) << T;
+
+ if (T->isVariableArrayType())
+ return true;
+
+ const RecordType *RT = T->getBaseElementTypeUnsafe()->getAs<RecordType>();
+ if (!RT)
+ return true;
+
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ // If the class has virtual base classes, then it's not an aggregate, and
+ // cannot have any constexpr constructors, so is non-literal. This is better
+ // to diagnose than the resulting absence of constexpr constructors.
+ if (RD->getNumVBases()) {
+ Diag(RD->getLocation(), diag::note_non_literal_virtual_base)
+ << RD->isStruct() << RD->getNumVBases();
+ for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+ E = RD->vbases_end(); I != E; ++I)
+ Diag(I->getSourceRange().getBegin(),
+ diag::note_constexpr_virtual_base_here) << I->getSourceRange();
+ } else if (!RD->isAggregate() && !RD->hasConstexprNonCopyMoveConstructor()) {
+ Diag(RD->getLocation(), diag::note_non_literal_no_constexpr_ctors) << RD;
+
+ switch (RD->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ break;
+
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ // If the base template had constexpr constructors which were
+ // instantiated as non-constexpr constructors, explain why.
+ for (CXXRecordDecl::ctor_iterator I = RD->ctor_begin(),
+ E = RD->ctor_end(); I != E; ++I) {
+ if ((*I)->isCopyConstructor() || (*I)->isMoveConstructor())
+ continue;
+
+ FunctionDecl *Base = (*I)->getInstantiatedFromMemberFunction();
+ if (Base && Base->isConstexpr())
+ CheckConstexprFunctionDecl(*I, CCK_NoteNonConstexprInstantiation);
+ }
+ }
+ } else if (RD->hasNonLiteralTypeFieldsOrBases()) {
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ if (!I->getType()->isLiteralType()) {
+ Diag(I->getSourceRange().getBegin(),
+ diag::note_non_literal_base_class)
+ << RD << I->getType() << I->getSourceRange();
+ return true;
+ }
+ }
+ for (CXXRecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end(); I != E; ++I) {
+ if (!(*I)->getType()->isLiteralType()) {
+ Diag((*I)->getLocation(), diag::note_non_literal_field)
+ << RD << (*I) << (*I)->getType();
+ return true;
+ } else if ((*I)->isMutable()) {
+ Diag((*I)->getLocation(), diag::note_non_literal_mutable_field) << RD;
+ return true;
+ }
+ }
+ } else if (!RD->hasTrivialDestructor()) {
+ // All fields and bases are of literal types, so have trivial destructors.
+ // If this class's destructor is non-trivial it must be user-declared.
+ CXXDestructorDecl *Dtor = RD->getDestructor();
+ assert(Dtor && "class has literal fields and bases but no dtor?");
+ if (!Dtor)
+ return true;
+
+ Diag(Dtor->getLocation(), Dtor->isUserProvided() ?
+ diag::note_non_literal_user_provided_dtor :
+ diag::note_non_literal_nontrivial_dtor) << RD;
+ }
+
+ return true;
+}
+
/// \brief Retrieve a version of the type 'T' that is elaborated by Keyword
/// and qualified by the nested-name-specifier contained in SS.
QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword,
@@ -4015,3 +4242,36 @@ QualType Sema::BuildUnaryTransformType(QualType BaseType,
}
llvm_unreachable("unknown unary transform type");
}
+
+QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) {
+ if (!T->isDependentType()) {
+ int DisallowedKind = -1;
+ if (T->isIncompleteType())
+ // FIXME: It isn't entirely clear whether incomplete atomic types
+ // are allowed or not; for simplicity, ban them for the moment.
+ DisallowedKind = 0;
+ else if (T->isArrayType())
+ DisallowedKind = 1;
+ else if (T->isFunctionType())
+ DisallowedKind = 2;
+ else if (T->isReferenceType())
+ DisallowedKind = 3;
+ else if (T->isAtomicType())
+ DisallowedKind = 4;
+ else if (T.hasQualifiers())
+ DisallowedKind = 5;
+ else if (!T.isTriviallyCopyableType(Context))
+ // Some other non-trivially-copyable type (probably a C++ class)
+ DisallowedKind = 6;
+
+ if (DisallowedKind != -1) {
+ Diag(Loc, diag::err_atomic_specifier_bad_type) << DisallowedKind << T;
+ return QualType();
+ }
+
+ // FIXME: Do we need any handling for ARC here?
+ }
+
+ // Build the pointer type.
+ return Context.getAtomicType(T);
+}
diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp
index ab697eeed53b..aa0bc08ef7f4 100644
--- a/lib/Sema/TargetAttributesSema.cpp
+++ b/lib/Sema/TargetAttributesSema.cpp
@@ -147,7 +147,8 @@ static void HandleX86ForceAlignArgPointerAttr(Decl *D,
return;
}
- D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(Attr.getLoc(), S.Context));
+ D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(Attr.getRange(),
+ S.Context));
}
static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
@@ -168,7 +169,7 @@ static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// Apparently Visual C++ thinks it is okay to not emit a warning
// in this case, so only emit a warning when -fms-extensions is not
// specified.
- if (!S.getLangOptions().Microsoft)
+ if (!S.getLangOptions().MicrosoftExt)
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 2 /*variable and function*/;
return;
@@ -236,7 +237,7 @@ namespace {
X86AttributesSema() { }
bool ProcessDeclAttribute(Scope *scope, Decl *D,
const AttributeList &Attr, Sema &S) const {
- const llvm::Triple &Triple(S.Context.Target.getTriple());
+ const llvm::Triple &Triple(S.Context.getTargetInfo().getTriple());
if (Triple.getOS() == llvm::Triple::Win32 ||
Triple.getOS() == llvm::Triple::MinGW32) {
switch (Attr.getKind()) {
@@ -247,8 +248,9 @@ namespace {
default: break;
}
}
- if (Attr.getName()->getName() == "force_align_arg_pointer" ||
- Attr.getName()->getName() == "__force_align_arg_pointer__") {
+ if (Triple.getArch() != llvm::Triple::x86_64 &&
+ (Attr.getName()->getName() == "force_align_arg_pointer" ||
+ Attr.getName()->getName() == "__force_align_arg_pointer__")) {
HandleX86ForceAlignArgPointerAttr(D, Attr, S);
return true;
}
@@ -261,16 +263,16 @@ const TargetAttributesSema &Sema::getTargetAttributesSema() const {
if (TheTargetAttributesSema)
return *TheTargetAttributesSema;
- const llvm::Triple &Triple(Context.Target.getTriple());
+ const llvm::Triple &Triple(Context.getTargetInfo().getTriple());
switch (Triple.getArch()) {
- default:
- return *(TheTargetAttributesSema = new TargetAttributesSema);
-
case llvm::Triple::msp430:
return *(TheTargetAttributesSema = new MSP430AttributesSema);
case llvm::Triple::mblaze:
return *(TheTargetAttributesSema = new MBlazeAttributesSema);
case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
return *(TheTargetAttributesSema = new X86AttributesSema);
+ default:
+ return *(TheTargetAttributesSema = new TargetAttributesSema);
}
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index fa87217821aa..bb49eee2f332 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -31,6 +31,7 @@
#include "clang/Sema/Ownership.h"
#include "clang/Sema/Designator.h"
#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/ErrorHandling.h"
#include "TypeLocBuilder.h"
#include <algorithm>
@@ -244,8 +245,7 @@ public:
/// must be set.
bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
SourceRange PatternRange,
- const UnexpandedParameterPack *Unexpanded,
- unsigned NumUnexpanded,
+ llvm::ArrayRef<UnexpandedParameterPack> Unexpanded,
bool &ShouldExpand,
bool &RetainExpansion,
llvm::Optional<unsigned> &NumExpansions) {
@@ -345,7 +345,7 @@ public:
///
/// \returns true if an error occurred, false otherwise.
bool TransformExprs(Expr **Inputs, unsigned NumInputs, bool IsCall,
- llvm::SmallVectorImpl<Expr *> &Outputs,
+ SmallVectorImpl<Expr *> &Outputs,
bool *ArgChanged = 0);
/// \brief Transform the given declaration, which is referenced from a type
@@ -520,8 +520,8 @@ public:
bool TransformFunctionTypeParams(SourceLocation Loc,
ParmVarDecl **Params, unsigned NumParams,
const QualType *ParamTypes,
- llvm::SmallVectorImpl<QualType> &PTypes,
- llvm::SmallVectorImpl<ParmVarDecl*> *PVars);
+ SmallVectorImpl<QualType> &PTypes,
+ SmallVectorImpl<ParmVarDecl*> *PVars);
/// \brief Transforms a single function-type parameter. Return null
/// on error.
@@ -905,6 +905,12 @@ public:
NumExpansions);
}
+ /// \brief Build a new atomic type given its value type.
+ ///
+ /// By default, performs semantic analysis when building the atomic type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildAtomicType(QualType ValueType, SourceLocation KWLoc);
+
/// \brief Build a new template name given a nested name specifier, a flag
/// indicating whether the "template" keyword was provided, and the template
/// that the template name refers to.
@@ -1181,15 +1187,22 @@ public:
return getSema().BuildObjCAtThrowStmt(AtLoc, Operand);
}
+ /// \brief Rebuild the operand to an Objective-C @synchronized statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildObjCAtSynchronizedOperand(SourceLocation atLoc,
+ Expr *object) {
+ return getSema().ActOnObjCAtSynchronizedOperand(atLoc, object);
+ }
+
/// \brief Build a new Objective-C @synchronized statement.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
StmtResult RebuildObjCAtSynchronizedStmt(SourceLocation AtLoc,
- Expr *Object,
- Stmt *Body) {
- return getSema().ActOnObjCAtSynchronizedStmt(AtLoc, Object,
- Body);
+ Expr *Object, Stmt *Body) {
+ return getSema().ActOnObjCAtSynchronizedStmt(AtLoc, Object, Body);
}
/// \brief Build a new Objective-C @autoreleasepool statement.
@@ -1200,7 +1213,16 @@ public:
Stmt *Body) {
return getSema().ActOnObjCAutoreleasePoolStmt(AtLoc, Body);
}
-
+
+ /// \brief Build the collection operand to a new Objective-C fast
+ /// enumeration statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildObjCForCollectionOperand(SourceLocation forLoc,
+ Expr *collection) {
+ return getSema().ActOnObjCForCollectionOperand(forLoc, collection);
+ }
/// \brief Build a new Objective-C fast enumeration statement.
///
@@ -1712,8 +1734,7 @@ public:
SubExpr, RParenLoc);
default:
- assert(false && "Invalid C++ named cast");
- break;
+ llvm_unreachable("Invalid C++ named cast");
}
return ExprError();
@@ -2016,13 +2037,14 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildCXXConstructExpr(QualType T,
- SourceLocation Loc,
- CXXConstructorDecl *Constructor,
- bool IsElidable,
- MultiExprArg Args,
- bool RequiresZeroInit,
+ SourceLocation Loc,
+ CXXConstructorDecl *Constructor,
+ bool IsElidable,
+ MultiExprArg Args,
+ bool HadMultipleCandidates,
+ bool RequiresZeroInit,
CXXConstructExpr::ConstructionKind ConstructKind,
- SourceRange ParenRange) {
+ SourceRange ParenRange) {
ASTOwningVector<Expr*> ConvertedArgs(SemaRef);
if (getSema().CompleteConstructorCall(Constructor, move(Args), Loc,
ConvertedArgs))
@@ -2030,6 +2052,7 @@ public:
return getSema().BuildCXXConstructExpr(Loc, T, Constructor, IsElidable,
move_arg(ConvertedArgs),
+ HadMultipleCandidates,
RequiresZeroInit, ConstructKind,
ParenRange);
}
@@ -2117,10 +2140,15 @@ public:
ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc, NamedDecl *Pack,
SourceLocation PackLoc,
SourceLocation RParenLoc,
- unsigned Length) {
+ llvm::Optional<unsigned> Length) {
+ if (Length)
+ return new (SemaRef.Context) SizeOfPackExpr(SemaRef.Context.getSizeType(),
+ OperatorLoc, Pack, PackLoc,
+ RParenLoc, *Length);
+
return new (SemaRef.Context) SizeOfPackExpr(SemaRef.Context.getSizeType(),
OperatorLoc, Pack, PackLoc,
- RParenLoc, Length);
+ RParenLoc);
}
/// \brief Build a new Objective-C @encode expression.
@@ -2137,7 +2165,7 @@ public:
/// \brief Build a new Objective-C class message.
ExprResult RebuildObjCMessageExpr(TypeSourceInfo *ReceiverTypeInfo,
Selector Sel,
- SourceLocation SelectorLoc,
+ ArrayRef<SourceLocation> SelectorLocs,
ObjCMethodDecl *Method,
SourceLocation LBracLoc,
MultiExprArg Args,
@@ -2145,14 +2173,14 @@ public:
return SemaRef.BuildClassMessage(ReceiverTypeInfo,
ReceiverTypeInfo->getType(),
/*SuperLoc=*/SourceLocation(),
- Sel, Method, LBracLoc, SelectorLoc,
+ Sel, Method, LBracLoc, SelectorLocs,
RBracLoc, move(Args));
}
/// \brief Build a new Objective-C instance message.
ExprResult RebuildObjCMessageExpr(Expr *Receiver,
Selector Sel,
- SourceLocation SelectorLoc,
+ ArrayRef<SourceLocation> SelectorLocs,
ObjCMethodDecl *Method,
SourceLocation LBracLoc,
MultiExprArg Args,
@@ -2160,7 +2188,7 @@ public:
return SemaRef.BuildInstanceMessage(Receiver,
Receiver->getType(),
/*SuperLoc=*/SourceLocation(),
- Sel, Method, LBracLoc, SelectorLoc,
+ Sel, Method, LBracLoc, SelectorLocs,
RBracLoc, move(Args));
}
@@ -2357,7 +2385,26 @@ public:
llvm::Optional<unsigned> NumExpansions) {
return getSema().CheckPackExpansion(Pattern, EllipsisLoc, NumExpansions);
}
-
+
+ /// \brief Build a new atomic operation expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildAtomicExpr(SourceLocation BuiltinLoc,
+ MultiExprArg SubExprs,
+ QualType RetTy,
+ AtomicExpr::AtomicOp Op,
+ SourceLocation RParenLoc) {
+ // Just create the expression; there is not any interesting semantic
+ // analysis here because we can't actually build an AtomicExpr until
+ // we are sure it is semantically sound.
+ unsigned NumSubExprs = SubExprs.size();
+ Expr **Subs = (Expr **)SubExprs.release();
+ return new (SemaRef.Context) AtomicExpr(BuiltinLoc, Subs,
+ NumSubExprs, RetTy, Op,
+ RParenLoc);
+ }
+
private:
TypeLoc TransformTypeInObjectScope(TypeLoc TL,
QualType ObjectType,
@@ -2424,7 +2471,7 @@ template<typename Derived>
bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
unsigned NumInputs,
bool IsCall,
- llvm::SmallVectorImpl<Expr *> &Outputs,
+ SmallVectorImpl<Expr *> &Outputs,
bool *ArgChanged) {
for (unsigned I = 0; I != NumInputs; ++I) {
// If requested, drop call arguments that need to be dropped.
@@ -2438,7 +2485,7 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
if (PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(Inputs[I])) {
Expr *Pattern = Expansion->getPattern();
- llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded);
assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
@@ -2451,8 +2498,7 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
llvm::Optional<unsigned> NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(Expansion->getEllipsisLoc(),
Pattern->getSourceRange(),
- Unexpanded.data(),
- Unexpanded.size(),
+ Unexpanded,
Expand, RetainExpansion,
NumExpansions))
return true;
@@ -2522,7 +2568,7 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
NestedNameSpecifierLoc NNS,
QualType ObjectType,
NamedDecl *FirstQualifierInScope) {
- llvm::SmallVector<NestedNameSpecifierLoc, 4> Qualifiers;
+ SmallVector<NestedNameSpecifierLoc, 4> Qualifiers;
for (NestedNameSpecifierLoc Qualifier = NNS; Qualifier;
Qualifier = Qualifier.getPrefix())
Qualifiers.push_back(Qualifier);
@@ -2666,8 +2712,7 @@ TreeTransform<Derived>
}
}
- assert(0 && "Unknown name kind.");
- return DeclarationNameInfo();
+ llvm_unreachable("Unknown name kind.");
}
template<typename Derived>
@@ -2887,7 +2932,7 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
}
case TemplateArgument::Pack: {
- llvm::SmallVector<TemplateArgument, 4> TransformedArgs;
+ SmallVector<TemplateArgument, 4> TransformedArgs;
TransformedArgs.reserve(Arg.pack_size());
for (TemplateArgument::pack_iterator A = Arg.pack_begin(),
AEnd = Arg.pack_end();
@@ -3016,7 +3061,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
= In.getPackExpansionPattern(Ellipsis, OrigNumExpansions,
getSema().Context);
- llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded);
assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
@@ -3027,8 +3072,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
llvm::Optional<unsigned> NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(Ellipsis,
Pattern.getSourceRange(),
- Unexpanded.data(),
- Unexpanded.size(),
+ Unexpanded,
Expand,
RetainExpansion,
NumExpansions))
@@ -3809,8 +3853,8 @@ bool TreeTransform<Derived>::
TransformFunctionTypeParams(SourceLocation Loc,
ParmVarDecl **Params, unsigned NumParams,
const QualType *ParamTypes,
- llvm::SmallVectorImpl<QualType> &OutParamTypes,
- llvm::SmallVectorImpl<ParmVarDecl*> *PVars) {
+ SmallVectorImpl<QualType> &OutParamTypes,
+ SmallVectorImpl<ParmVarDecl*> *PVars) {
int indexAdjustment = 0;
for (unsigned i = 0; i != NumParams; ++i) {
@@ -3821,7 +3865,7 @@ bool TreeTransform<Derived>::
ParmVarDecl *NewParm = 0;
if (OldParm->isParameterPack()) {
// We have a function parameter pack that may need to be expanded.
- llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
// Find the parameter packs that could be expanded.
TypeLoc TL = OldParm->getTypeSourceInfo()->getTypeLoc();
@@ -3838,8 +3882,7 @@ bool TreeTransform<Derived>::
NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
Pattern.getSourceRange(),
- Unexpanded.data(),
- Unexpanded.size(),
+ Unexpanded,
ShouldExpand,
RetainExpansion,
NumExpansions)) {
@@ -3921,15 +3964,14 @@ bool TreeTransform<Derived>::
= dyn_cast<PackExpansionType>(OldType)) {
// We have a function parameter pack that may need to be expanded.
QualType Pattern = Expansion->getPattern();
- llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded);
// Determine whether we should expand the parameter packs.
bool ShouldExpand = false;
bool RetainExpansion = false;
if (getDerived().TryExpandParameterPacks(Loc, SourceRange(),
- Unexpanded.data(),
- Unexpanded.size(),
+ Unexpanded,
ShouldExpand,
RetainExpansion,
NumExpansions)) {
@@ -4014,8 +4056,8 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
// parameters before the return type, since the return type can then refer
// to the parameters themselves (via decltype, sizeof, etc.).
//
- llvm::SmallVector<QualType, 4> ParamTypes;
- llvm::SmallVector<ParmVarDecl*, 4> ParamDecls;
+ SmallVector<QualType, 4> ParamTypes;
+ SmallVector<ParmVarDecl*, 4> ParamDecls;
const FunctionProtoType *T = TL.getTypePtr();
QualType ResultType;
@@ -4387,6 +4429,29 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
return getDerived().TransformTemplateSpecializationType(TLB, TL, Template);
}
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformAtomicType(TypeLocBuilder &TLB,
+ AtomicTypeLoc TL) {
+ QualType ValueType = getDerived().TransformType(TLB, TL.getValueLoc());
+ if (ValueType.isNull())
+ return QualType();
+
+ QualType Result = TL.getType();
+ if (getDerived().AlwaysRebuild() ||
+ ValueType != TL.getValueLoc().getType()) {
+ Result = getDerived().RebuildAtomicType(ValueType, TL.getKWLoc());
+ if (Result.isNull())
+ return QualType();
+ }
+
+ AtomicTypeLoc NewTL = TLB.push<AtomicTypeLoc>(Result);
+ NewTL.setKWLoc(TL.getKWLoc());
+ NewTL.setLParenLoc(TL.getLParenLoc());
+ NewTL.setRParenLoc(TL.getRParenLoc());
+
+ return Result;
+}
+
namespace {
/// \brief Simple iterator that traverses the template arguments in a
/// container that provides a \c getArgLoc() member function.
@@ -5256,7 +5321,7 @@ template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformDeclStmt(DeclStmt *S) {
bool DeclChanged = false;
- llvm::SmallVector<Decl *, 4> Decls;
+ SmallVector<Decl *, 4> Decls;
for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
D != DEnd; ++D) {
Decl *Transformed = getDerived().TransformDefinition((*D)->getLocation(),
@@ -5283,7 +5348,7 @@ TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) {
ASTOwningVector<Expr*> Constraints(getSema());
ASTOwningVector<Expr*> Exprs(getSema());
- llvm::SmallVector<IdentifierInfo *, 4> Names;
+ SmallVector<IdentifierInfo *, 4> Names;
ExprResult AsmString;
ASTOwningVector<Expr*> Clobbers(getSema());
@@ -5470,6 +5535,11 @@ TreeTransform<Derived>::TransformObjCAtSynchronizedStmt(
ExprResult Object = getDerived().TransformExpr(S->getSynchExpr());
if (Object.isInvalid())
return StmtError();
+ Object =
+ getDerived().RebuildObjCAtSynchronizedOperand(S->getAtSynchronizedLoc(),
+ Object.get());
+ if (Object.isInvalid())
+ return StmtError();
// Transform the body.
StmtResult Body = getDerived().TransformStmt(S->getSynchBody());
@@ -5519,6 +5589,10 @@ TreeTransform<Derived>::TransformObjCForCollectionStmt(
ExprResult Collection = getDerived().TransformExpr(S->getCollection());
if (Collection.isInvalid())
return StmtError();
+ Collection = getDerived().RebuildObjCForCollectionOperand(S->getForLoc(),
+ Collection.take());
+ if (Collection.isInvalid())
+ return StmtError();
// Transform the body.
StmtResult Body = getDerived().TransformStmt(S->getBody());
@@ -5813,8 +5887,8 @@ TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) {
if (ControllingExpr.isInvalid())
return ExprError();
- llvm::SmallVector<Expr *, 4> AssocExprs;
- llvm::SmallVector<TypeSourceInfo *, 4> AssocTypes;
+ SmallVector<Expr *, 4> AssocExprs;
+ SmallVector<TypeSourceInfo *, 4> AssocTypes;
for (unsigned i = 0; i != E->getNumAssocs(); ++i) {
TypeSourceInfo *TS = E->getAssocTypeSourceInfo(i);
if (TS) {
@@ -5887,7 +5961,7 @@ TreeTransform<Derived>::TransformOffsetOfExpr(OffsetOfExpr *E) {
bool ExprChanged = false;
typedef Sema::OffsetOfComponent Component;
typedef OffsetOfExpr::OffsetOfNode Node;
- llvm::SmallVector<Component, 4> Components;
+ SmallVector<Component, 4> Components;
for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) {
const Node &ON = E->getComponent(I);
Component Comp;
@@ -6902,6 +6976,19 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorNew);
if (OperatorDelete)
SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorDelete);
+
+ if (E->isArray() && Constructor &&
+ !E->getAllocatedType()->isDependentType()) {
+ QualType ElementType
+ = SemaRef.Context.getBaseElementType(E->getAllocatedType());
+ if (const RecordType *RecordT = ElementType->getAs<RecordType>()) {
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordT->getDecl());
+ if (CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(Record)) {
+ SemaRef.MarkDeclarationReferenced(E->getLocStart(), Destructor);
+ }
+ }
+ }
+
return SemaRef.Owned(E);
}
@@ -7313,6 +7400,7 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
return getDerived().RebuildCXXConstructExpr(T, /*FIXME:*/E->getLocStart(),
Constructor, E->isElidable(),
move_arg(Args),
+ E->hadMultipleCandidates(),
E->requiresZeroInitialization(),
E->getConstructionKind(),
E->getParenRange());
@@ -7640,19 +7728,28 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
bool RetainExpansion = false;
llvm::Optional<unsigned> NumExpansions;
if (getDerived().TryExpandParameterPacks(E->getOperatorLoc(), E->getPackLoc(),
- &Unexpanded, 1,
+ Unexpanded,
ShouldExpand, RetainExpansion,
NumExpansions))
return ExprError();
- if (!ShouldExpand || RetainExpansion)
+ if (RetainExpansion)
return SemaRef.Owned(E);
+
+ NamedDecl *Pack = E->getPack();
+ if (!ShouldExpand) {
+ Pack = cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getPackLoc(),
+ Pack));
+ if (!Pack)
+ return ExprError();
+ }
+
// We now know the length of the parameter pack, so build a new expression
// that stores that length.
- return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(),
+ return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), Pack,
E->getPackLoc(), E->getRParenLoc(),
- *NumExpansions);
+ NumExpansions);
}
template<typename Derived>
@@ -7762,9 +7859,11 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
return SemaRef.Owned(E);
// Build a new class message send.
+ SmallVector<SourceLocation, 16> SelLocs;
+ E->getSelectorLocs(SelLocs);
return getDerived().RebuildObjCMessageExpr(ReceiverTypeInfo,
E->getSelector(),
- E->getSelectorLoc(),
+ SelLocs,
E->getMethodDecl(),
E->getLeftLoc(),
move_arg(Args),
@@ -7785,9 +7884,11 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
return SemaRef.Owned(E);
// Build a new instance message send.
+ SmallVector<SourceLocation, 16> SelLocs;
+ E->getSelectorLocs(SelLocs);
return getDerived().RebuildObjCMessageExpr(Receiver.get(),
E->getSelector(),
- E->getSelectorLoc(),
+ SelLocs,
E->getMethodDecl(),
E->getLeftLoc(),
move_arg(Args),
@@ -7908,8 +8009,8 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
// expression.
blockScope->CapturesCXXThis = oldBlock->capturesCXXThis();
- llvm::SmallVector<ParmVarDecl*, 4> params;
- llvm::SmallVector<QualType, 4> paramTypes;
+ SmallVector<ParmVarDecl*, 4> params;
+ SmallVector<QualType, 4> paramTypes;
// Parameter substitution.
if (getDerived().TransformFunctionTypeParams(E->getCaretLocation(),
@@ -7951,7 +8052,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
// Set the parameters on the block decl.
if (!params.empty())
- blockScope->TheDecl->setParams(params.data(), params.size());
+ blockScope->TheDecl->setParams(params);
// If the return type wasn't explicitly set, it will have been marked as a
// dependent type (DependentTy); clear out the return type setting so
@@ -8015,8 +8116,26 @@ TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) {
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformAsTypeExpr(AsTypeExpr *E) {
- assert(false && "Cannot transform asType expressions yet");
- return SemaRef.Owned(E);
+ llvm_unreachable("Cannot transform asType expressions yet");
+}
+
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformAtomicExpr(AtomicExpr *E) {
+ QualType RetTy = getDerived().TransformType(E->getType());
+ bool ArgumentChanged = false;
+ ASTOwningVector<Expr*> SubExprs(SemaRef);
+ SubExprs.reserve(E->getNumSubExprs());
+ if (getDerived().TransformExprs(E->getSubExprs(), E->getNumSubExprs(), false,
+ SubExprs, &ArgumentChanged))
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ !ArgumentChanged)
+ return SemaRef.Owned(E);
+
+ return getDerived().RebuildAtomicExpr(E->getBuiltinLoc(), move_arg(SubExprs),
+ RetTy, E->getOp(), E->getRParenLoc());
}
//===----------------------------------------------------------------------===//
@@ -8239,6 +8358,12 @@ QualType TreeTransform<Derived>::RebuildTemplateSpecializationType(
}
template<typename Derived>
+QualType TreeTransform<Derived>::RebuildAtomicType(QualType ValueType,
+ SourceLocation KWLoc) {
+ return SemaRef.BuildAtomicType(ValueType, KWLoc);
+}
+
+template<typename Derived>
TemplateName
TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
bool TemplateKW,
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp
index 782e5c6aa79f..445e750834eb 100644
--- a/lib/Serialization/ASTCommon.cpp
+++ b/lib/Serialization/ASTCommon.cpp
@@ -43,6 +43,7 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
case BuiltinType::Long: ID = PREDEF_TYPE_LONG_ID; break;
case BuiltinType::LongLong: ID = PREDEF_TYPE_LONGLONG_ID; break;
case BuiltinType::Int128: ID = PREDEF_TYPE_INT128_ID; break;
+ case BuiltinType::Half: ID = PREDEF_TYPE_HALF_ID; break;
case BuiltinType::Float: ID = PREDEF_TYPE_FLOAT_ID; break;
case BuiltinType::Double: ID = PREDEF_TYPE_DOUBLE_ID; break;
case BuiltinType::LongDouble: ID = PREDEF_TYPE_LONGDOUBLE_ID; break;
diff --git a/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h
index 838df13f2d8f..367f57f7153a 100644
--- a/lib/Serialization/ASTCommon.h
+++ b/lib/Serialization/ASTCommon.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_SERIALIZATION_LIB_AST_COMMON_H
#include "clang/Serialization/ASTBitCodes.h"
+#include "clang/AST/ASTContext.h"
namespace clang {
@@ -31,7 +32,7 @@ enum DeclUpdateKind {
TypeIdx TypeIdxFromBuiltin(const BuiltinType *BT);
template <typename IdxForTypeTy>
-TypeID MakeTypeID(QualType T, IdxForTypeTy IdxForType) {
+TypeID MakeTypeID(ASTContext &Context, QualType T, IdxForTypeTy IdxForType) {
if (T.isNull())
return PREDEF_TYPE_NULL_ID;
@@ -46,6 +47,11 @@ TypeID MakeTypeID(QualType T, IdxForTypeTy IdxForType) {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr()))
return TypeIdxFromBuiltin(BT).asTypeID(FastQuals);
+ if (T == Context.AutoDeductTy)
+ return TypeIdx(PREDEF_TYPE_AUTO_DEDUCT).asTypeID(FastQuals);
+ if (T == Context.AutoRRefDeductTy)
+ return TypeIdx(PREDEF_TYPE_AUTO_RREF_DEDUCT).asTypeID(FastQuals);
+
return IdxForType(T).asTypeID(FastQuals);
}
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index a4ed5f4da48c..fe1cc30158d1 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -13,7 +13,9 @@
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/ASTDeserializationListener.h"
+#include "clang/Serialization/ModuleManager.h"
#include "ASTCommon.h"
+#include "ASTReaderInternals.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/Utils.h"
#include "clang/Sema/Sema.h"
@@ -52,6 +54,7 @@
using namespace clang;
using namespace clang::serialization;
+using namespace clang::serialization::reader;
//===----------------------------------------------------------------------===//
// PCH validator implementation
@@ -62,103 +65,36 @@ ASTReaderListener::~ASTReaderListener() {}
bool
PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
const LangOptions &PPLangOpts = PP.getLangOptions();
-#define PARSE_LANGOPT_BENIGN(Option)
-#define PARSE_LANGOPT_IMPORTANT(Option, DiagID) \
- if (PPLangOpts.Option != LangOpts.Option) { \
- Reader.Diag(DiagID) << LangOpts.Option << PPLangOpts.Option; \
- return true; \
- }
-
- PARSE_LANGOPT_BENIGN(Trigraphs);
- PARSE_LANGOPT_BENIGN(BCPLComment);
- PARSE_LANGOPT_BENIGN(DollarIdents);
- PARSE_LANGOPT_BENIGN(AsmPreprocessor);
- PARSE_LANGOPT_IMPORTANT(GNUMode, diag::warn_pch_gnu_extensions);
- PARSE_LANGOPT_IMPORTANT(GNUKeywords, diag::warn_pch_gnu_keywords);
- PARSE_LANGOPT_BENIGN(ImplicitInt);
- PARSE_LANGOPT_BENIGN(Digraphs);
- PARSE_LANGOPT_BENIGN(HexFloats);
- PARSE_LANGOPT_IMPORTANT(C99, diag::warn_pch_c99);
- PARSE_LANGOPT_IMPORTANT(C1X, diag::warn_pch_c1x);
- PARSE_LANGOPT_IMPORTANT(Microsoft, diag::warn_pch_microsoft_extensions);
- PARSE_LANGOPT_BENIGN(MSCVersion);
- PARSE_LANGOPT_IMPORTANT(CPlusPlus, diag::warn_pch_cplusplus);
- PARSE_LANGOPT_IMPORTANT(CPlusPlus0x, diag::warn_pch_cplusplus0x);
- PARSE_LANGOPT_BENIGN(CXXOperatorName);
- PARSE_LANGOPT_IMPORTANT(ObjC1, diag::warn_pch_objective_c);
- PARSE_LANGOPT_IMPORTANT(ObjC2, diag::warn_pch_objective_c2);
- PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI, diag::warn_pch_nonfragile_abi);
- PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI2, diag::warn_pch_nonfragile_abi2);
- PARSE_LANGOPT_IMPORTANT(AppleKext, diag::warn_pch_apple_kext);
- PARSE_LANGOPT_IMPORTANT(ObjCDefaultSynthProperties,
- diag::warn_pch_objc_auto_properties);
- PARSE_LANGOPT_BENIGN(ObjCInferRelatedResultType)
- PARSE_LANGOPT_IMPORTANT(NoConstantCFStrings,
- diag::warn_pch_no_constant_cfstrings);
- PARSE_LANGOPT_BENIGN(PascalStrings);
- PARSE_LANGOPT_BENIGN(WritableStrings);
- PARSE_LANGOPT_IMPORTANT(LaxVectorConversions,
- diag::warn_pch_lax_vector_conversions);
- PARSE_LANGOPT_IMPORTANT(AltiVec, diag::warn_pch_altivec);
- PARSE_LANGOPT_IMPORTANT(Exceptions, diag::warn_pch_exceptions);
- PARSE_LANGOPT_IMPORTANT(ObjCExceptions, diag::warn_pch_objc_exceptions);
- PARSE_LANGOPT_IMPORTANT(CXXExceptions, diag::warn_pch_cxx_exceptions);
- PARSE_LANGOPT_IMPORTANT(SjLjExceptions, diag::warn_pch_sjlj_exceptions);
- PARSE_LANGOPT_IMPORTANT(MSBitfields, diag::warn_pch_ms_bitfields);
- PARSE_LANGOPT_IMPORTANT(NeXTRuntime, diag::warn_pch_objc_runtime);
- PARSE_LANGOPT_IMPORTANT(Freestanding, diag::warn_pch_freestanding);
- PARSE_LANGOPT_IMPORTANT(NoBuiltin, diag::warn_pch_builtins);
- PARSE_LANGOPT_IMPORTANT(ThreadsafeStatics,
- diag::warn_pch_thread_safe_statics);
- PARSE_LANGOPT_IMPORTANT(POSIXThreads, diag::warn_pch_posix_threads);
- PARSE_LANGOPT_IMPORTANT(Blocks, diag::warn_pch_blocks);
- PARSE_LANGOPT_BENIGN(EmitAllDecls);
- PARSE_LANGOPT_IMPORTANT(MathErrno, diag::warn_pch_math_errno);
- PARSE_LANGOPT_BENIGN(getSignedOverflowBehavior());
- PARSE_LANGOPT_IMPORTANT(HeinousExtensions,
- diag::warn_pch_heinous_extensions);
- // FIXME: Most of the options below are benign if the macro wasn't
- // used. Unfortunately, this means that a PCH compiled without
- // optimization can't be used with optimization turned on, even
- // though the only thing that changes is whether __OPTIMIZE__ was
- // defined... but if __OPTIMIZE__ never showed up in the header, it
- // doesn't matter. We could consider making this some special kind
- // of check.
- PARSE_LANGOPT_IMPORTANT(Optimize, diag::warn_pch_optimize);
- PARSE_LANGOPT_IMPORTANT(OptimizeSize, diag::warn_pch_optimize_size);
- PARSE_LANGOPT_IMPORTANT(Static, diag::warn_pch_static);
- PARSE_LANGOPT_IMPORTANT(PICLevel, diag::warn_pch_pic_level);
- PARSE_LANGOPT_IMPORTANT(GNUInline, diag::warn_pch_gnu_inline);
- PARSE_LANGOPT_IMPORTANT(NoInline, diag::warn_pch_no_inline);
- PARSE_LANGOPT_IMPORTANT(Deprecated, diag::warn_pch_deprecated);
- PARSE_LANGOPT_IMPORTANT(AccessControl, diag::warn_pch_access_control);
- PARSE_LANGOPT_IMPORTANT(CharIsSigned, diag::warn_pch_char_signed);
- PARSE_LANGOPT_IMPORTANT(ShortWChar, diag::warn_pch_short_wchar);
- PARSE_LANGOPT_IMPORTANT(ShortEnums, diag::warn_pch_short_enums);
- if ((PPLangOpts.getGCMode() != 0) != (LangOpts.getGCMode() != 0)) {
- Reader.Diag(diag::warn_pch_gc_mode)
- << LangOpts.getGCMode() << PPLangOpts.getGCMode();
- return true;
+
+#define LANGOPT(Name, Bits, Default, Description) \
+ if (PPLangOpts.Name != LangOpts.Name) { \
+ Reader.Diag(diag::err_pch_langopt_mismatch) \
+ << Description << LangOpts.Name << PPLangOpts.Name; \
+ return true; \
+ }
+
+#define VALUE_LANGOPT(Name, Bits, Default, Description) \
+ if (PPLangOpts.Name != LangOpts.Name) { \
+ Reader.Diag(diag::err_pch_langopt_value_mismatch) \
+ << Description; \
+ return true; \
+}
+
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ if (PPLangOpts.get##Name() != LangOpts.get##Name()) { \
+ Reader.Diag(diag::err_pch_langopt_value_mismatch) \
+ << Description; \
+ return true; \
}
- PARSE_LANGOPT_BENIGN(getVisibilityMode());
- PARSE_LANGOPT_IMPORTANT(getStackProtectorMode(),
- diag::warn_pch_stack_protector);
- PARSE_LANGOPT_BENIGN(InstantiationDepth);
- PARSE_LANGOPT_IMPORTANT(OpenCL, diag::warn_pch_opencl);
- PARSE_LANGOPT_IMPORTANT(CUDA, diag::warn_pch_cuda);
- PARSE_LANGOPT_BENIGN(CatchUndefined);
- PARSE_LANGOPT_BENIGN(DefaultFPContract);
- PARSE_LANGOPT_IMPORTANT(ElideConstructors, diag::warn_pch_elide_constructors);
- PARSE_LANGOPT_BENIGN(SpellChecking);
- PARSE_LANGOPT_IMPORTANT(ObjCAutoRefCount, diag::warn_pch_auto_ref_count);
- PARSE_LANGOPT_BENIGN(ObjCInferRelatedReturnType);
-#undef PARSE_LANGOPT_IMPORTANT
-#undef PARSE_LANGOPT_BENIGN
+#define BENIGN_LANGOPT(Name, Bits, Default, Description)
+#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
+#include "clang/Basic/LangOptions.def"
+
return false;
}
-bool PCHValidator::ReadTargetTriple(llvm::StringRef Triple) {
+bool PCHValidator::ReadTargetTriple(StringRef Triple) {
if (Triple == PP.getTargetInfo().getTriple().str())
return false;
@@ -169,14 +105,14 @@ bool PCHValidator::ReadTargetTriple(llvm::StringRef Triple) {
namespace {
struct EmptyStringRef {
- bool operator ()(llvm::StringRef r) const { return r.empty(); }
+ bool operator ()(StringRef r) const { return r.empty(); }
};
struct EmptyBlock {
bool operator ()(const PCHPredefinesBlock &r) const {return r.Data.empty();}
};
}
-static bool EqualConcatenations(llvm::SmallVector<llvm::StringRef, 2> L,
+static bool EqualConcatenations(SmallVector<StringRef, 2> L,
PCHPredefinesBlocks R) {
// First, sum up the lengths.
unsigned LL = 0, RL = 0;
@@ -196,7 +132,7 @@ static bool EqualConcatenations(llvm::SmallVector<llvm::StringRef, 2> L,
R.erase(std::remove_if(R.begin(), R.end(), EmptyBlock()), R.end());
// Do it the hard way. At this point, both vectors must be non-empty.
- llvm::StringRef LR = L[0], RR = R[0].Data;
+ StringRef LR = L[0], RR = R[0].Data;
unsigned LI = 0, RI = 0, LN = L.size(), RN = R.size();
(void) RN;
for (;;) {
@@ -236,12 +172,12 @@ static bool EqualConcatenations(llvm::SmallVector<llvm::StringRef, 2> L,
}
}
-static std::pair<FileID, llvm::StringRef::size_type>
-FindMacro(const PCHPredefinesBlocks &Buffers, llvm::StringRef MacroDef) {
- std::pair<FileID, llvm::StringRef::size_type> Res;
+static std::pair<FileID, StringRef::size_type>
+FindMacro(const PCHPredefinesBlocks &Buffers, StringRef MacroDef) {
+ std::pair<FileID, StringRef::size_type> Res;
for (unsigned I = 0, N = Buffers.size(); I != N; ++I) {
Res.second = Buffers[I].Data.find(MacroDef);
- if (Res.second != llvm::StringRef::npos) {
+ if (Res.second != StringRef::npos) {
Res.first = Buffers[I].BufferID;
break;
}
@@ -250,7 +186,7 @@ FindMacro(const PCHPredefinesBlocks &Buffers, llvm::StringRef MacroDef) {
}
bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
- llvm::StringRef OriginalFileName,
+ StringRef OriginalFileName,
std::string &SuggestedPredefines,
FileManager &FileMgr) {
// We are in the context of an implicit include, so the predefines buffer will
@@ -261,9 +197,9 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
PCHInclude += "#include \"";
PCHInclude += NormalizeDashIncludePath(OriginalFileName, FileMgr);
PCHInclude += "\"\n";
- std::pair<llvm::StringRef,llvm::StringRef> Split =
- llvm::StringRef(PP.getPredefines()).split(PCHInclude.str());
- llvm::StringRef Left = Split.first, Right = Split.second;
+ std::pair<StringRef,StringRef> Split =
+ StringRef(PP.getPredefines()).split(PCHInclude.str());
+ StringRef Left = Split.first, Right = Split.second;
if (Left == PP.getPredefines()) {
Error("Missing PCH include entry!");
return true;
@@ -271,7 +207,7 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
// If the concatenation of all the PCH buffers is equal to the adjusted
// command line, we're done.
- llvm::SmallVector<llvm::StringRef, 2> CommandLine;
+ SmallVector<StringRef, 2> CommandLine;
CommandLine.push_back(Left);
CommandLine.push_back(Right);
if (EqualConcatenations(CommandLine, Buffers))
@@ -281,18 +217,18 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
// The predefines buffers are different. Determine what the differences are,
// and whether they require us to reject the PCH file.
- llvm::SmallVector<llvm::StringRef, 8> PCHLines;
+ SmallVector<StringRef, 8> PCHLines;
for (unsigned I = 0, N = Buffers.size(); I != N; ++I)
Buffers[I].Data.split(PCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
- llvm::SmallVector<llvm::StringRef, 8> CmdLineLines;
+ SmallVector<StringRef, 8> CmdLineLines;
Left.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
// Pick out implicit #includes after the PCH and don't consider them for
// validation; we will insert them into SuggestedPredefines so that the
// preprocessor includes them.
std::string IncludesAfterPCH;
- llvm::SmallVector<llvm::StringRef, 8> AfterPCHLines;
+ SmallVector<StringRef, 8> AfterPCHLines;
Right.split(AfterPCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
for (unsigned i = 0, e = AfterPCHLines.size(); i != e; ++i) {
if (AfterPCHLines[i].startswith("#include ")) {
@@ -325,7 +261,7 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
// Determine which predefines that were used to build the PCH file are missing
// from the command line.
- std::vector<llvm::StringRef> MissingPredefines;
+ std::vector<StringRef> MissingPredefines;
std::set_difference(PCHLines.begin(), PCHLines.end(),
CmdLineLines.begin(), CmdLineLines.end(),
std::back_inserter(MissingPredefines));
@@ -333,7 +269,7 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
bool MissingDefines = false;
bool ConflictingDefines = false;
for (unsigned I = 0, N = MissingPredefines.size(); I != N; ++I) {
- llvm::StringRef Missing = MissingPredefines[I];
+ StringRef Missing = MissingPredefines[I];
if (Missing.startswith("#include ")) {
// An -include was specified when generating the PCH; it is included in
// the PCH, just ignore it.
@@ -351,13 +287,13 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
= Missing.find_first_of("( \n\r", StartOfMacroName);
assert(EndOfMacroName != std::string::npos &&
"Couldn't find the end of the macro name");
- llvm::StringRef MacroName = Missing.slice(StartOfMacroName, EndOfMacroName);
+ StringRef MacroName = Missing.slice(StartOfMacroName, EndOfMacroName);
// Determine whether this macro was given a different definition on the
// command line.
std::string MacroDefStart = "#define " + MacroName.str();
std::string::size_type MacroDefLen = MacroDefStart.size();
- llvm::SmallVector<llvm::StringRef, 8>::iterator ConflictPos
+ SmallVector<StringRef, 8>::iterator ConflictPos
= std::lower_bound(CmdLineLines.begin(), CmdLineLines.end(),
MacroDefStart);
for (; ConflictPos != CmdLineLines.end(); ++ConflictPos) {
@@ -382,12 +318,12 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
<< MacroName;
// Show the definition of this macro within the PCH file.
- std::pair<FileID, llvm::StringRef::size_type> MacroLoc =
+ std::pair<FileID, StringRef::size_type> MacroLoc =
FindMacro(Buffers, Missing);
- assert(MacroLoc.second!=llvm::StringRef::npos && "Unable to find macro!");
+ assert(MacroLoc.second!=StringRef::npos && "Unable to find macro!");
SourceLocation PCHMissingLoc =
SourceMgr.getLocForStartOfFile(MacroLoc.first)
- .getFileLocWithOffset(MacroLoc.second);
+ .getLocWithOffset(MacroLoc.second);
Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) << MacroName;
ConflictingDefines = true;
@@ -405,12 +341,12 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
}
// Show the definition of this macro within the PCH file.
- std::pair<FileID, llvm::StringRef::size_type> MacroLoc =
+ std::pair<FileID, StringRef::size_type> MacroLoc =
FindMacro(Buffers, Missing);
- assert(MacroLoc.second!=llvm::StringRef::npos && "Unable to find macro!");
+ assert(MacroLoc.second!=StringRef::npos && "Unable to find macro!");
SourceLocation PCHMissingLoc =
SourceMgr.getLocForStartOfFile(MacroLoc.first)
- .getFileLocWithOffset(MacroLoc.second);
+ .getLocWithOffset(MacroLoc.second);
Reader.Diag(PCHMissingLoc, diag::note_using_macro_def_from_pch);
}
@@ -421,12 +357,12 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
// parameters that were not present when building the PCH
// file. Extra #defines are okay, so long as the identifiers being
// defined were not used within the precompiled header.
- std::vector<llvm::StringRef> ExtraPredefines;
+ std::vector<StringRef> ExtraPredefines;
std::set_difference(CmdLineLines.begin(), CmdLineLines.end(),
PCHLines.begin(), PCHLines.end(),
std::back_inserter(ExtraPredefines));
for (unsigned I = 0, N = ExtraPredefines.size(); I != N; ++I) {
- llvm::StringRef &Extra = ExtraPredefines[I];
+ StringRef &Extra = ExtraPredefines[I];
if (!Extra.startswith("#define ")) {
Reader.Diag(diag::warn_pch_compiler_options_mismatch);
return true;
@@ -439,7 +375,7 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
= Extra.find_first_of("( \n\r", StartOfMacroName);
assert(EndOfMacroName != std::string::npos &&
"Couldn't find the end of the macro name");
- llvm::StringRef MacroName = Extra.slice(StartOfMacroName, EndOfMacroName);
+ StringRef MacroName = Extra.slice(StartOfMacroName, EndOfMacroName);
// Check whether this name was used somewhere in the PCH file. If
// so, defining it as a macro could change behavior, so we reject
@@ -479,440 +415,321 @@ ASTReader::setDeserializationListener(ASTDeserializationListener *Listener) {
}
-namespace {
-class ASTSelectorLookupTrait {
- ASTReader &Reader;
-public:
- struct data_type {
- SelectorID ID;
- ObjCMethodList Instance, Factory;
- };
+unsigned ASTSelectorLookupTrait::ComputeHash(Selector Sel) {
+ return serialization::ComputeHash(Sel);
+}
- typedef Selector external_key_type;
- typedef external_key_type internal_key_type;
- explicit ASTSelectorLookupTrait(ASTReader &Reader) : Reader(Reader) { }
+std::pair<unsigned, unsigned>
+ASTSelectorLookupTrait::ReadKeyDataLength(const unsigned char*& d) {
+ using namespace clang::io;
+ unsigned KeyLen = ReadUnalignedLE16(d);
+ unsigned DataLen = ReadUnalignedLE16(d);
+ return std::make_pair(KeyLen, DataLen);
+}
- static bool EqualKey(const internal_key_type& a,
- const internal_key_type& b) {
- return a == b;
- }
+ASTSelectorLookupTrait::internal_key_type
+ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) {
+ using namespace clang::io;
+ SelectorTable &SelTable = Reader.getContext().Selectors;
+ unsigned N = ReadUnalignedLE16(d);
+ IdentifierInfo *FirstII
+ = Reader.getLocalIdentifier(F, ReadUnalignedLE32(d));
+ if (N == 0)
+ return SelTable.getNullarySelector(FirstII);
+ else if (N == 1)
+ return SelTable.getUnarySelector(FirstII);
- static unsigned ComputeHash(Selector Sel) {
- return serialization::ComputeHash(Sel);
- }
+ SmallVector<IdentifierInfo *, 16> Args;
+ Args.push_back(FirstII);
+ for (unsigned I = 1; I != N; ++I)
+ Args.push_back(Reader.getLocalIdentifier(F, ReadUnalignedLE32(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; }
+ return SelTable.getSelector(N, Args.data());
+}
- 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);
- }
+ASTSelectorLookupTrait::data_type
+ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d,
+ unsigned DataLen) {
+ using namespace clang::io;
- internal_key_type ReadKey(const unsigned char* d, unsigned) {
- using namespace clang::io;
- SelectorTable &SelTable = Reader.getContext()->Selectors;
- unsigned N = ReadUnalignedLE16(d);
- IdentifierInfo *FirstII
- = Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d));
- if (N == 0)
- return SelTable.getNullarySelector(FirstII);
- else if (N == 1)
- return SelTable.getUnarySelector(FirstII);
+ data_type Result;
- llvm::SmallVector<IdentifierInfo *, 16> Args;
- Args.push_back(FirstII);
- for (unsigned I = 1; I != N; ++I)
- Args.push_back(Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d)));
+ Result.ID = Reader.getGlobalSelectorID(F, ReadUnalignedLE32(d));
+ unsigned NumInstanceMethods = ReadUnalignedLE16(d);
+ unsigned NumFactoryMethods = ReadUnalignedLE16(d);
- return SelTable.getSelector(N, Args.data());
+ // Load instance methods
+ for (unsigned I = 0; I != NumInstanceMethods; ++I) {
+ if (ObjCMethodDecl *Method
+ = Reader.GetLocalDeclAs<ObjCMethodDecl>(F, ReadUnalignedLE32(d)))
+ Result.Instance.push_back(Method);
}
- data_type ReadData(Selector, const unsigned char* d, unsigned DataLen) {
- using namespace clang::io;
-
- data_type Result;
-
- Result.ID = ReadUnalignedLE32(d);
- unsigned NumInstanceMethods = ReadUnalignedLE16(d);
- unsigned NumFactoryMethods = ReadUnalignedLE16(d);
-
- // Load instance methods
- ObjCMethodList *Prev = 0;
- for (unsigned I = 0; I != NumInstanceMethods; ++I) {
- ObjCMethodDecl *Method
- = cast<ObjCMethodDecl>(Reader.GetDecl(ReadUnalignedLE32(d)));
- if (!Result.Instance.Method) {
- // This is the first method, which is the easy case.
- Result.Instance.Method = Method;
- Prev = &Result.Instance;
- continue;
- }
-
- ObjCMethodList *Mem =
- Reader.getSema()->BumpAlloc.Allocate<ObjCMethodList>();
- Prev->Next = new (Mem) ObjCMethodList(Method, 0);
- Prev = Prev->Next;
- }
-
- // Load factory methods
- Prev = 0;
- for (unsigned I = 0; I != NumFactoryMethods; ++I) {
- ObjCMethodDecl *Method
- = cast<ObjCMethodDecl>(Reader.GetDecl(ReadUnalignedLE32(d)));
- if (!Result.Factory.Method) {
- // This is the first method, which is the easy case.
- Result.Factory.Method = Method;
- Prev = &Result.Factory;
- continue;
- }
-
- ObjCMethodList *Mem =
- Reader.getSema()->BumpAlloc.Allocate<ObjCMethodList>();
- Prev->Next = new (Mem) ObjCMethodList(Method, 0);
- Prev = Prev->Next;
- }
-
- return Result;
+ // Load factory methods
+ for (unsigned I = 0; I != NumFactoryMethods; ++I) {
+ if (ObjCMethodDecl *Method
+ = Reader.GetLocalDeclAs<ObjCMethodDecl>(F, ReadUnalignedLE32(d)))
+ Result.Factory.push_back(Method);
}
-};
-
-} // end anonymous namespace
-
-/// \brief The on-disk hash table used for the global method pool.
-typedef OnDiskChainedHashTable<ASTSelectorLookupTrait>
- ASTSelectorLookupTable;
-
-namespace clang {
-class ASTIdentifierLookupTrait {
- ASTReader &Reader;
- ASTReader::PerFileData &F;
-
- // If we know the IdentifierInfo in advance, it is here and we will
- // not build a new one. Used when deserializing information about an
- // identifier that was constructed before the AST file was read.
- IdentifierInfo *KnownII;
-
-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, ASTReader::PerFileData &F,
- IdentifierInfo *II = 0)
- : Reader(Reader), F(F), KnownII(II) { }
+ return Result;
+}
- 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;
- }
+unsigned ASTIdentifierLookupTrait::ComputeHash(const internal_key_type& a) {
+ return llvm::HashString(StringRef(a.first, a.second));
+}
- static unsigned ComputeHash(const internal_key_type& a) {
- return llvm::HashString(llvm::StringRef(a.first, a.second));
- }
+std::pair<unsigned, unsigned>
+ASTIdentifierLookupTrait::ReadKeyDataLength(const unsigned char*& d) {
+ using namespace clang::io;
+ unsigned DataLen = ReadUnalignedLE16(d);
+ unsigned KeyLen = ReadUnalignedLE16(d);
+ return std::make_pair(KeyLen, DataLen);
+}
- // This hopefully will just get inlined and removed by the optimizer.
- static const internal_key_type&
- GetInternalKey(const external_key_type& x) { return x; }
+std::pair<const char*, unsigned>
+ASTIdentifierLookupTrait::ReadKey(const unsigned char* d, unsigned n) {
+ assert(n >= 2 && d[n-1] == '\0');
+ return std::make_pair((const char*) d, n-1);
+}
- // This hopefully will just get inlined and removed by the optimizer.
- static const external_key_type&
- GetExternalKey(const internal_key_type& x) { return x; }
+IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
+ const unsigned char* d,
+ unsigned DataLen) {
+ using namespace clang::io;
+ unsigned RawID = ReadUnalignedLE32(d);
+ bool IsInteresting = RawID & 0x01;
- static std::pair<unsigned, unsigned>
- ReadKeyDataLength(const unsigned char*& d) {
- using namespace clang::io;
- unsigned DataLen = ReadUnalignedLE16(d);
- unsigned KeyLen = ReadUnalignedLE16(d);
- return std::make_pair(KeyLen, DataLen);
- }
+ // Wipe out the "is interesting" bit.
+ RawID = RawID >> 1;
- static std::pair<const char*, unsigned>
- ReadKey(const unsigned char* d, unsigned n) {
- assert(n >= 2 && d[n-1] == '\0');
- return std::make_pair((const char*) d, n-1);
- }
-
- IdentifierInfo *ReadData(const internal_key_type& k,
- const unsigned char* d,
- unsigned DataLen) {
- using namespace clang::io;
- IdentID ID = ReadUnalignedLE32(d);
- bool IsInteresting = ID & 0x01;
-
- // Wipe out the "is interesting" bit.
- ID = ID >> 1;
-
- if (!IsInteresting) {
- // For uninteresting identifiers, just build the IdentifierInfo
- // and associate it with the persistent ID.
- IdentifierInfo *II = KnownII;
- if (!II)
- II = &Reader.getIdentifierTable().getOwn(llvm::StringRef(k.first,
- k.second));
- Reader.SetIdentifierInfo(ID, II);
- II->setIsFromAST();
- return II;
- }
-
- unsigned Bits = ReadUnalignedLE16(d);
- bool CPlusPlusOperatorKeyword = Bits & 0x01;
- Bits >>= 1;
- bool HasRevertedTokenIDToIdentifier = Bits & 0x01;
- Bits >>= 1;
- bool Poisoned = Bits & 0x01;
- Bits >>= 1;
- bool ExtensionToken = Bits & 0x01;
- Bits >>= 1;
- bool hasMacroDefinition = Bits & 0x01;
- Bits >>= 1;
- unsigned ObjCOrBuiltinID = Bits & 0x3FF;
- Bits >>= 10;
-
- assert(Bits == 0 && "Extra bits in the identifier?");
- DataLen -= 6;
-
- // Build the IdentifierInfo itself and link the identifier ID with
- // the new IdentifierInfo.
+ IdentID ID = Reader.getGlobalIdentifierID(F, RawID);
+ if (!IsInteresting) {
+ // For uninteresting identifiers, just build the IdentifierInfo
+ // and associate it with the persistent ID.
IdentifierInfo *II = KnownII;
if (!II)
- II = &Reader.getIdentifierTable().getOwn(llvm::StringRef(k.first,
- k.second));
+ II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second));
Reader.SetIdentifierInfo(ID, II);
-
- // Set or check the various bits in the IdentifierInfo structure.
- // Token IDs are read-only.
- if (HasRevertedTokenIDToIdentifier)
- II->RevertTokenIDToIdentifier();
- II->setObjCOrBuiltinID(ObjCOrBuiltinID);
- assert(II->isExtensionToken() == ExtensionToken &&
- "Incorrect extension token flag");
- (void)ExtensionToken;
- II->setIsPoisoned(Poisoned);
- assert(II->isCPlusPlusOperatorKeyword() == CPlusPlusOperatorKeyword &&
- "Incorrect C++ operator keyword flag");
- (void)CPlusPlusOperatorKeyword;
-
- // If this identifier is a macro, deserialize the macro
- // definition.
- if (hasMacroDefinition) {
- uint32_t Offset = ReadUnalignedLE32(d);
- Reader.SetIdentifierIsMacro(II, F, Offset);
- DataLen -= 4;
- }
-
- // Read all of the declarations visible at global scope with this
- // name.
- if (Reader.getContext() == 0) return II;
- if (DataLen > 0) {
- llvm::SmallVector<uint32_t, 4> DeclIDs;
- for (; DataLen > 0; DataLen -= 4)
- DeclIDs.push_back(ReadUnalignedLE32(d));
- Reader.SetGloballyVisibleDecls(II, DeclIDs);
- }
-
II->setIsFromAST();
return II;
}
-};
-
-} // end anonymous namespace
-
-/// \brief The on-disk hash table used to contain information about
-/// all of the identifiers in the program.
-typedef OnDiskChainedHashTable<ASTIdentifierLookupTrait>
- ASTIdentifierLookupTable;
-
-namespace {
-class ASTDeclContextNameLookupTrait {
- ASTReader &Reader;
-
-public:
- /// \brief Pair of begin/end iterators for DeclIDs.
- typedef std::pair<DeclID *, DeclID *> data_type;
-
- /// \brief Special internal key for declaration names.
- /// The hash table creates keys for comparison; we do not create
- /// a DeclarationName for the internal key to avoid deserializing types.
- struct DeclNameKey {
- DeclarationName::NameKind Kind;
- uint64_t Data;
- DeclNameKey() : Kind((DeclarationName::NameKind)0), Data(0) { }
- };
-
- typedef DeclarationName external_key_type;
- typedef DeclNameKey internal_key_type;
-
- explicit ASTDeclContextNameLookupTrait(ASTReader &Reader) : Reader(Reader) { }
-
- static bool EqualKey(const internal_key_type& a,
- const internal_key_type& b) {
- return a.Kind == b.Kind && a.Data == b.Data;
- }
-
- unsigned ComputeHash(const DeclNameKey &Key) const {
- llvm::FoldingSetNodeID ID;
- ID.AddInteger(Key.Kind);
- switch (Key.Kind) {
- case DeclarationName::Identifier:
- case DeclarationName::CXXLiteralOperatorName:
- ID.AddString(((IdentifierInfo*)Key.Data)->getName());
- break;
- case DeclarationName::ObjCZeroArgSelector:
- case DeclarationName::ObjCOneArgSelector:
- case DeclarationName::ObjCMultiArgSelector:
- ID.AddInteger(serialization::ComputeHash(Selector(Key.Data)));
- break;
- case DeclarationName::CXXConstructorName:
- case DeclarationName::CXXDestructorName:
- case DeclarationName::CXXConversionFunctionName:
- ID.AddInteger((TypeID)Key.Data);
- break;
- case DeclarationName::CXXOperatorName:
- ID.AddInteger((OverloadedOperatorKind)Key.Data);
- break;
- case DeclarationName::CXXUsingDirective:
- break;
- }
-
- return ID.ComputeHash();
+ unsigned Bits = ReadUnalignedLE16(d);
+ bool CPlusPlusOperatorKeyword = Bits & 0x01;
+ Bits >>= 1;
+ bool HasRevertedTokenIDToIdentifier = Bits & 0x01;
+ Bits >>= 1;
+ bool Poisoned = Bits & 0x01;
+ Bits >>= 1;
+ bool ExtensionToken = Bits & 0x01;
+ Bits >>= 1;
+ bool hasMacroDefinition = Bits & 0x01;
+ Bits >>= 1;
+ unsigned ObjCOrBuiltinID = Bits & 0x3FF;
+ Bits >>= 10;
+
+ assert(Bits == 0 && "Extra bits in the identifier?");
+ DataLen -= 6;
+
+ // Build the IdentifierInfo itself and link the identifier ID with
+ // the new IdentifierInfo.
+ IdentifierInfo *II = KnownII;
+ if (!II)
+ II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second));
+ Reader.SetIdentifierInfo(ID, II);
+
+ // Set or check the various bits in the IdentifierInfo structure.
+ // Token IDs are read-only.
+ if (HasRevertedTokenIDToIdentifier)
+ II->RevertTokenIDToIdentifier();
+ II->setObjCOrBuiltinID(ObjCOrBuiltinID);
+ assert(II->isExtensionToken() == ExtensionToken &&
+ "Incorrect extension token flag");
+ (void)ExtensionToken;
+ if (Poisoned)
+ II->setIsPoisoned(true);
+ assert(II->isCPlusPlusOperatorKeyword() == CPlusPlusOperatorKeyword &&
+ "Incorrect C++ operator keyword flag");
+ (void)CPlusPlusOperatorKeyword;
+
+ // If this identifier is a macro, deserialize the macro
+ // definition.
+ if (hasMacroDefinition) {
+ // FIXME: Check for conflicts?
+ uint32_t Offset = ReadUnalignedLE32(d);
+ Reader.SetIdentifierIsMacro(II, F, Offset);
+ DataLen -= 4;
+ }
+
+ // Read all of the declarations visible at global scope with this
+ // name.
+ if (DataLen > 0) {
+ SmallVector<uint32_t, 4> DeclIDs;
+ for (; DataLen > 0; DataLen -= 4)
+ DeclIDs.push_back(Reader.getGlobalDeclID(F, ReadUnalignedLE32(d)));
+ Reader.SetGloballyVisibleDecls(II, DeclIDs);
+ }
+
+ II->setIsFromAST();
+ return II;
+}
+
+unsigned
+ASTDeclContextNameLookupTrait::ComputeHash(const DeclNameKey &Key) const {
+ llvm::FoldingSetNodeID ID;
+ ID.AddInteger(Key.Kind);
+
+ switch (Key.Kind) {
+ case DeclarationName::Identifier:
+ case DeclarationName::CXXLiteralOperatorName:
+ ID.AddString(((IdentifierInfo*)Key.Data)->getName());
+ break;
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ ID.AddInteger(serialization::ComputeHash(Selector(Key.Data)));
+ break;
+ case DeclarationName::CXXOperatorName:
+ ID.AddInteger((OverloadedOperatorKind)Key.Data);
+ break;
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ case DeclarationName::CXXUsingDirective:
+ break;
}
- internal_key_type GetInternalKey(const external_key_type& Name) const {
- DeclNameKey Key;
- Key.Kind = Name.getNameKind();
- switch (Name.getNameKind()) {
- case DeclarationName::Identifier:
- Key.Data = (uint64_t)Name.getAsIdentifierInfo();
- break;
- case DeclarationName::ObjCZeroArgSelector:
- case DeclarationName::ObjCOneArgSelector:
- case DeclarationName::ObjCMultiArgSelector:
- Key.Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr();
- break;
- case DeclarationName::CXXConstructorName:
- case DeclarationName::CXXDestructorName:
- case DeclarationName::CXXConversionFunctionName:
- Key.Data = Reader.GetTypeID(Name.getCXXNameType());
- break;
- case DeclarationName::CXXOperatorName:
- Key.Data = Name.getCXXOverloadedOperator();
- break;
- case DeclarationName::CXXLiteralOperatorName:
- Key.Data = (uint64_t)Name.getCXXLiteralIdentifier();
- break;
- case DeclarationName::CXXUsingDirective:
- break;
- }
+ return ID.ComputeHash();
+}
- return Key;
+ASTDeclContextNameLookupTrait::internal_key_type
+ASTDeclContextNameLookupTrait::GetInternalKey(
+ const external_key_type& Name) const {
+ DeclNameKey Key;
+ Key.Kind = Name.getNameKind();
+ switch (Name.getNameKind()) {
+ case DeclarationName::Identifier:
+ Key.Data = (uint64_t)Name.getAsIdentifierInfo();
+ break;
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ Key.Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr();
+ break;
+ case DeclarationName::CXXOperatorName:
+ Key.Data = Name.getCXXOverloadedOperator();
+ break;
+ case DeclarationName::CXXLiteralOperatorName:
+ Key.Data = (uint64_t)Name.getCXXLiteralIdentifier();
+ break;
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ case DeclarationName::CXXUsingDirective:
+ Key.Data = 0;
+ break;
}
- external_key_type GetExternalKey(const internal_key_type& Key) const {
- ASTContext *Context = Reader.getContext();
- switch (Key.Kind) {
- case DeclarationName::Identifier:
- return DeclarationName((IdentifierInfo*)Key.Data);
-
- case DeclarationName::ObjCZeroArgSelector:
- case DeclarationName::ObjCOneArgSelector:
- case DeclarationName::ObjCMultiArgSelector:
- return DeclarationName(Selector(Key.Data));
+ return Key;
+}
- case DeclarationName::CXXConstructorName:
- return Context->DeclarationNames.getCXXConstructorName(
- Context->getCanonicalType(Reader.GetType(Key.Data)));
+ASTDeclContextNameLookupTrait::external_key_type
+ASTDeclContextNameLookupTrait::GetExternalKey(
+ const internal_key_type& Key) const {
+ ASTContext &Context = Reader.getContext();
+ switch (Key.Kind) {
+ case DeclarationName::Identifier:
+ return DeclarationName((IdentifierInfo*)Key.Data);
- case DeclarationName::CXXDestructorName:
- return Context->DeclarationNames.getCXXDestructorName(
- Context->getCanonicalType(Reader.GetType(Key.Data)));
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ return DeclarationName(Selector(Key.Data));
- case DeclarationName::CXXConversionFunctionName:
- return Context->DeclarationNames.getCXXConversionFunctionName(
- Context->getCanonicalType(Reader.GetType(Key.Data)));
+ case DeclarationName::CXXConstructorName:
+ return Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(Reader.getLocalType(F, Key.Data)));
- case DeclarationName::CXXOperatorName:
- return Context->DeclarationNames.getCXXOperatorName(
- (OverloadedOperatorKind)Key.Data);
+ case DeclarationName::CXXDestructorName:
+ return Context.DeclarationNames.getCXXDestructorName(
+ Context.getCanonicalType(Reader.getLocalType(F, Key.Data)));
- case DeclarationName::CXXLiteralOperatorName:
- return Context->DeclarationNames.getCXXLiteralOperatorName(
- (IdentifierInfo*)Key.Data);
+ case DeclarationName::CXXConversionFunctionName:
+ return Context.DeclarationNames.getCXXConversionFunctionName(
+ Context.getCanonicalType(Reader.getLocalType(F, Key.Data)));
- case DeclarationName::CXXUsingDirective:
- return DeclarationName::getUsingDirectiveName();
- }
+ case DeclarationName::CXXOperatorName:
+ return Context.DeclarationNames.getCXXOperatorName(
+ (OverloadedOperatorKind)Key.Data);
- llvm_unreachable("Invalid Name Kind ?");
- }
+ case DeclarationName::CXXLiteralOperatorName:
+ return Context.DeclarationNames.getCXXLiteralOperatorName(
+ (IdentifierInfo*)Key.Data);
- 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);
+ case DeclarationName::CXXUsingDirective:
+ return DeclarationName::getUsingDirectiveName();
}
- internal_key_type ReadKey(const unsigned char* d, unsigned) {
- using namespace clang::io;
+ llvm_unreachable("Invalid Name Kind ?");
+}
- DeclNameKey Key;
- Key.Kind = (DeclarationName::NameKind)*d++;
- switch (Key.Kind) {
- case DeclarationName::Identifier:
- Key.Data = (uint64_t)Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d));
- break;
- case DeclarationName::ObjCZeroArgSelector:
- case DeclarationName::ObjCOneArgSelector:
- case DeclarationName::ObjCMultiArgSelector:
- Key.Data =
- (uint64_t)Reader.DecodeSelector(ReadUnalignedLE32(d)).getAsOpaquePtr();
- break;
- case DeclarationName::CXXConstructorName:
- case DeclarationName::CXXDestructorName:
- case DeclarationName::CXXConversionFunctionName:
- Key.Data = ReadUnalignedLE32(d); // TypeID
- break;
- case DeclarationName::CXXOperatorName:
- Key.Data = *d++; // OverloadedOperatorKind
- break;
- case DeclarationName::CXXLiteralOperatorName:
- Key.Data = (uint64_t)Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d));
- break;
- case DeclarationName::CXXUsingDirective:
- break;
- }
+std::pair<unsigned, unsigned>
+ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char*& d) {
+ using namespace clang::io;
+ unsigned KeyLen = ReadUnalignedLE16(d);
+ unsigned DataLen = ReadUnalignedLE16(d);
+ return std::make_pair(KeyLen, DataLen);
+}
- return Key;
- }
+ASTDeclContextNameLookupTrait::internal_key_type
+ASTDeclContextNameLookupTrait::ReadKey(const unsigned char* d, unsigned) {
+ using namespace clang::io;
- data_type ReadData(internal_key_type, const unsigned char* d,
- unsigned DataLen) {
- using namespace clang::io;
- unsigned NumDecls = ReadUnalignedLE16(d);
- DeclID *Start = (DeclID *)d;
- return std::make_pair(Start, Start + NumDecls);
+ DeclNameKey Key;
+ Key.Kind = (DeclarationName::NameKind)*d++;
+ switch (Key.Kind) {
+ case DeclarationName::Identifier:
+ Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d));
+ break;
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ Key.Data =
+ (uint64_t)Reader.getLocalSelector(F, ReadUnalignedLE32(d))
+ .getAsOpaquePtr();
+ break;
+ case DeclarationName::CXXOperatorName:
+ Key.Data = *d++; // OverloadedOperatorKind
+ break;
+ case DeclarationName::CXXLiteralOperatorName:
+ Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d));
+ break;
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ case DeclarationName::CXXUsingDirective:
+ Key.Data = 0;
+ break;
}
-};
-} // end anonymous namespace
+ return Key;
+}
-/// \brief The on-disk hash table used for the DeclContext's Name lookup table.
-typedef OnDiskChainedHashTable<ASTDeclContextNameLookupTrait>
- ASTDeclContextNameLookupTable;
+ASTDeclContextNameLookupTrait::data_type
+ASTDeclContextNameLookupTrait::ReadData(internal_key_type,
+ const unsigned char* d,
+ unsigned DataLen) {
+ using namespace clang::io;
+ unsigned NumDecls = ReadUnalignedLE16(d);
+ DeclID *Start = (DeclID *)d;
+ return std::make_pair(Start, Start + NumDecls);
+}
-bool ASTReader::ReadDeclContextStorage(llvm::BitstreamCursor &Cursor,
+bool ASTReader::ReadDeclContextStorage(Module &M,
+ llvm::BitstreamCursor &Cursor,
const std::pair<uint64_t, uint64_t> &Offsets,
DeclContextInfo &Info) {
SavedStreamPosition SavedPosition(Cursor);
@@ -932,9 +749,6 @@ bool ASTReader::ReadDeclContextStorage(llvm::BitstreamCursor &Cursor,
Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair*>(Blob);
Info.NumLexicalDecls = BlobLen / sizeof(KindDeclIDPair);
- } else {
- Info.LexicalDecls = 0;
- Info.NumLexicalDecls = 0;
}
// Now the lookup table.
@@ -954,20 +768,18 @@ bool ASTReader::ReadDeclContextStorage(llvm::BitstreamCursor &Cursor,
= ASTDeclContextNameLookupTable::Create(
(const unsigned char *)Blob + Record[0],
(const unsigned char *)Blob,
- ASTDeclContextNameLookupTrait(*this));
- } else {
- Info.NameLookupTableData = 0;
+ ASTDeclContextNameLookupTrait(*this, M));
}
return false;
}
-void ASTReader::Error(llvm::StringRef Msg) {
+void ASTReader::Error(StringRef Msg) {
Error(diag::err_fe_pch_malformed, Msg);
}
void ASTReader::Error(unsigned DiagID,
- llvm::StringRef Arg1, llvm::StringRef Arg2) {
+ StringRef Arg1, StringRef Arg2) {
if (Diags.isDiagnosticInFlight())
Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2);
else
@@ -990,8 +802,8 @@ bool ASTReader::CheckPredefinesBuffers() {
/// \brief Read the line table in the source manager block.
/// \returns true if there was an error.
-bool ASTReader::ParseLineTable(PerFileData &F,
- llvm::SmallVectorImpl<uint64_t> &Record) {
+bool ASTReader::ParseLineTable(Module &F,
+ SmallVectorImpl<uint64_t> &Record) {
unsigned Idx = 0;
LineTableInfo &LineTable = SourceMgr.getLineTable();
@@ -1010,6 +822,9 @@ bool ASTReader::ParseLineTable(PerFileData &F,
std::vector<LineEntry> Entries;
while (Idx < Record.size()) {
int FID = Record[Idx++];
+ assert(FID >= 0 && "Serialized line entries for non-local file.");
+ // Remap FileID from 1-based old view.
+ FID += F.SLocEntryBaseID - 1;
// Extract the line entries
unsigned NumEntries = Record[Idx++];
@@ -1131,7 +946,7 @@ public:
/// \brief Read a source manager block
-ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(PerFileData &F) {
+ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(Module &F) {
using namespace SrcMgr;
llvm::BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor;
@@ -1188,11 +1003,6 @@ ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(PerFileData &F) {
default: // Default behavior: ignore.
break;
- case SM_LINE_TABLE:
- if (ParseLineTable(F, Record))
- return Failure;
- break;
-
case SM_SLOC_FILE_ENTRY:
case SM_SLOC_BUFFER_ENTRY:
case SM_SLOC_EXPANSION_ENTRY:
@@ -1235,38 +1045,20 @@ resolveFileRelativeToOriginalDir(const std::string &Filename,
return currPCHPath.str();
}
-/// \brief Get a cursor that's correctly positioned for reading the source
-/// location entry with the given ID.
-ASTReader::PerFileData *ASTReader::SLocCursorForID(unsigned ID) {
- assert(ID != 0 && ID <= TotalNumSLocEntries &&
- "SLocCursorForID should only be called for real IDs.");
-
- ID -= 1;
- PerFileData *F = 0;
- for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- F = Chain[N - I - 1];
- if (ID < F->LocalNumSLocEntries)
- break;
- ID -= F->LocalNumSLocEntries;
- }
- assert(F && F->LocalNumSLocEntries > ID && "Chain corrupted");
-
- F->SLocEntryCursor.JumpToBit(F->SLocOffsets[ID]);
- return F;
-}
-
/// \brief Read in the source location entry with the given ID.
-ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(unsigned ID) {
+ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
if (ID == 0)
return Success;
- if (ID > TotalNumSLocEntries) {
+ if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) {
Error("source location entry ID out-of-range for AST file");
return Failure;
}
- PerFileData *F = SLocCursorForID(ID);
+ Module *F = GlobalSLocEntryMap.find(-ID)->second;
+ F->SLocEntryCursor.JumpToBit(F->SLocEntryOffsets[ID - F->SLocEntryBaseID]);
llvm::BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor;
+ unsigned BaseOffset = F->SLocEntryBaseOffset;
++NumSLocEntriesRead;
unsigned Code = SLocEntryCursor.ReadCode();
@@ -1326,12 +1118,19 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(unsigned ID) {
return Failure;
}
- FileID FID = SourceMgr.createFileID(File, ReadSourceLocation(*F, Record[1]),
+ SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
+ if (IncludeLoc.isInvalid() && F->Kind != MK_MainFile) {
+ // This is the module's main file.
+ IncludeLoc = getImportLocation(F);
+ }
+ FileID FID = SourceMgr.createFileID(File, IncludeLoc,
(SrcMgr::CharacteristicKind)Record[2],
- ID, Record[0]);
+ ID, BaseOffset + Record[0]);
+ SrcMgr::FileInfo &FileInfo =
+ const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile());
+ FileInfo.NumCreatedFIDs = Record[6];
if (Record[3])
- const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile())
- .setHasLineDirectives();
+ FileInfo.setHasLineDirectives();
break;
}
@@ -1350,14 +1149,15 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(unsigned ID) {
}
llvm::MemoryBuffer *Buffer
- = llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(BlobStart, BlobLen - 1),
+ = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1),
Name);
- FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer, ID, Offset);
+ FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer, ID,
+ BaseOffset + Offset);
if (strcmp(Name, "<built-in>") == 0) {
PCHPredefinesBlock Block = {
BufferID,
- llvm::StringRef(BlobStart, BlobLen - 1)
+ StringRef(BlobStart, BlobLen - 1)
};
PCHPredefinesBuffers.push_back(Block);
}
@@ -1367,12 +1167,12 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(unsigned ID) {
case SM_SLOC_EXPANSION_ENTRY: {
SourceLocation SpellingLoc = ReadSourceLocation(*F, Record[1]);
- SourceMgr.createInstantiationLoc(SpellingLoc,
+ SourceMgr.createExpansionLoc(SpellingLoc,
ReadSourceLocation(*F, Record[2]),
ReadSourceLocation(*F, Record[3]),
Record[4],
ID,
- Record[0]);
+ BaseOffset + Record[0]);
break;
}
}
@@ -1380,6 +1180,25 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(unsigned ID) {
return Success;
}
+/// \brief Find the location where the module F is imported.
+SourceLocation ASTReader::getImportLocation(Module *F) {
+ if (F->ImportLoc.isValid())
+ return F->ImportLoc;
+
+ // Otherwise we have a PCH. It's considered to be "imported" at the first
+ // location of its includer.
+ if (F->ImportedBy.empty() || !F->ImportedBy[0]) {
+ // Main file is the importer. We assume that it is the first entry in the
+ // entry table. We can't ask the manager, because at the time of PCH loading
+ // the main file entry doesn't exist yet.
+ // The very first entry is the invalid instantiation loc, which takes up
+ // offsets 0 and 1.
+ return SourceLocation::getFromRawEncoding(2U);
+ }
+ //return F->Loaders[0]->FirstLoc;
+ return F->ImportedBy[0]->FirstLoc;
+}
+
/// 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.
@@ -1403,8 +1222,7 @@ bool ASTReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor,
}
}
-PreprocessedEntity *ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) {
- assert(PP && "Forgot to set Preprocessor ?");
+void ASTReader::ReadMacroRecord(Module &F, uint64_t Offset) {
llvm::BitstreamCursor &Stream = F.MacroCursor;
// Keep track of where we are in the stream, then jump back there
@@ -1413,21 +1231,21 @@ PreprocessedEntity *ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset)
Stream.JumpToBit(Offset);
RecordData Record;
- llvm::SmallVector<IdentifierInfo*, 16> MacroArgs;
+ SmallVector<IdentifierInfo*, 16> MacroArgs;
MacroInfo *Macro = 0;
while (true) {
unsigned Code = Stream.ReadCode();
switch (Code) {
case llvm::bitc::END_BLOCK:
- return 0;
+ 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 0;
+ return;
}
continue;
@@ -1451,50 +1269,55 @@ PreprocessedEntity *ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset)
// of the definition of the macro we were looking for. We're
// done.
if (Macro)
- return 0;
+ return;
- IdentifierInfo *II = DecodeIdentifierInfo(Record[0]);
+ IdentifierInfo *II = getLocalIdentifier(F, Record[0]);
if (II == 0) {
Error("macro must have a name in AST file");
- return 0;
+ return;
}
SourceLocation Loc = ReadSourceLocation(F, Record[1]);
bool isUsed = Record[2];
- MacroInfo *MI = PP->AllocateMacroInfo(Loc);
+ MacroInfo *MI = PP.AllocateMacroInfo(Loc);
MI->setIsUsed(isUsed);
MI->setIsFromAST();
unsigned NextIndex = 3;
+ MI->setExportLocation(ReadSourceLocation(F, Record, NextIndex));
+
if (RecType == PP_MACRO_FUNCTION_LIKE) {
// Decode function-like macro info.
- bool isC99VarArgs = Record[3];
- bool isGNUVarArgs = Record[4];
+ bool isC99VarArgs = Record[NextIndex++];
+ bool isGNUVarArgs = Record[NextIndex++];
MacroArgs.clear();
- unsigned NumArgs = Record[5];
- NextIndex = 6 + NumArgs;
+ unsigned NumArgs = Record[NextIndex++];
for (unsigned i = 0; i != NumArgs; ++i)
- MacroArgs.push_back(DecodeIdentifierInfo(Record[6+i]));
+ MacroArgs.push_back(getLocalIdentifier(F, Record[NextIndex++]));
// Install function-like macro info.
MI->setIsFunctionLike();
if (isC99VarArgs) MI->setIsC99Varargs();
if (isGNUVarArgs) MI->setIsGNUVarargs();
MI->setArgumentList(MacroArgs.data(), MacroArgs.size(),
- PP->getPreprocessorAllocator());
+ PP.getPreprocessorAllocator());
}
// Finally, install the macro.
- PP->setMacroInfo(II, MI);
+ PP.setMacroInfo(II, MI);
// Remember that we saw this macro last so that we add the tokens that
// form its body to it.
Macro = MI;
- if (NextIndex + 1 == Record.size() && PP->getPreprocessingRecord()) {
- // We have a macro definition. Load it now.
- PP->getPreprocessingRecord()->RegisterMacroDefinition(Macro,
- getMacroDefinition(Record[NextIndex]));
+ if (NextIndex + 1 == Record.size() && PP.getPreprocessingRecord() &&
+ Record[NextIndex]) {
+ // We have a macro definition. Register the association
+ PreprocessedEntityID
+ GlobalID = getGlobalPreprocessedEntityID(F, Record[NextIndex]);
+ PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
+ PPRec.RegisterMacroDefinition(Macro,
+ PPRec.getPPEntityID(GlobalID-1, /*isLoaded=*/true));
}
++NumMacrosRead;
@@ -1510,7 +1333,7 @@ PreprocessedEntity *ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset)
Tok.startToken();
Tok.setLocation(ReadSourceLocation(F, Record[0]));
Tok.setLength(Record[1]);
- if (IdentifierInfo *II = DecodeIdentifierInfo(Record[2]))
+ if (IdentifierInfo *II = getLocalIdentifier(F, Record[2]))
Tok.setIdentifierInfo(II);
Tok.setKind((tok::TokenKind)Record[3]);
Tok.setFlag((Token::TokenFlags)Record[4]);
@@ -1520,234 +1343,98 @@ PreprocessedEntity *ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset)
}
}
- return 0;
+ return;
}
-PreprocessedEntity *ASTReader::LoadPreprocessedEntity(PerFileData &F) {
- assert(PP && "Forgot to set Preprocessor ?");
- unsigned Code = F.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;
- }
-
- // Read the record.
- PreprocessingRecord &PPRec = *PP->getPreprocessingRecord();
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
- RecordData Record;
- PreprocessorDetailRecordTypes RecType =
- (PreprocessorDetailRecordTypes)F.PreprocessorDetailCursor.ReadRecord(
- Code, Record, BlobStart, BlobLen);
- switch (RecType) {
- case PPD_MACRO_EXPANSION: {
- if (PreprocessedEntity *PE = PPRec.getPreprocessedEntity(Record[0]))
- return PE;
-
- MacroExpansion *ME =
- new (PPRec) MacroExpansion(DecodeIdentifierInfo(Record[3]),
- SourceRange(ReadSourceLocation(F, Record[1]),
- ReadSourceLocation(F, Record[2])),
- getMacroDefinition(Record[4]));
- PPRec.SetPreallocatedEntity(Record[0], ME);
- return ME;
- }
-
- case PPD_MACRO_DEFINITION: {
- if (PreprocessedEntity *PE = PPRec.getPreprocessedEntity(Record[0]))
- return PE;
-
- if (Record[1] > MacroDefinitionsLoaded.size()) {
- Error("out-of-bounds macro definition record");
- return 0;
- }
-
- // Decode the identifier info and then check again; if the macro is
- // still defined and associated with the identifier,
- IdentifierInfo *II = DecodeIdentifierInfo(Record[4]);
- if (!MacroDefinitionsLoaded[Record[1] - 1]) {
- MacroDefinition *MD
- = new (PPRec) MacroDefinition(II,
- ReadSourceLocation(F, Record[5]),
- SourceRange(
- ReadSourceLocation(F, Record[2]),
- ReadSourceLocation(F, Record[3])));
-
- PPRec.SetPreallocatedEntity(Record[0], MD);
- MacroDefinitionsLoaded[Record[1] - 1] = MD;
-
- if (DeserializationListener)
- DeserializationListener->MacroDefinitionRead(Record[1], MD);
- }
-
- return MacroDefinitionsLoaded[Record[1] - 1];
- }
-
- case PPD_INCLUSION_DIRECTIVE: {
- if (PreprocessedEntity *PE = PPRec.getPreprocessedEntity(Record[0]))
- return PE;
-
- const char *FullFileNameStart = BlobStart + Record[3];
- const FileEntry *File
- = PP->getFileManager().getFile(llvm::StringRef(FullFileNameStart,
- BlobLen - Record[3]));
-
- // FIXME: Stable encoding
- InclusionDirective::InclusionKind Kind
- = static_cast<InclusionDirective::InclusionKind>(Record[5]);
- InclusionDirective *ID
- = new (PPRec) InclusionDirective(PPRec, Kind,
- llvm::StringRef(BlobStart, Record[3]),
- Record[4],
- File,
- SourceRange(ReadSourceLocation(F, Record[1]),
- ReadSourceLocation(F, Record[2])));
- PPRec.SetPreallocatedEntity(Record[0], ID);
- return ID;
- }
- }
+PreprocessedEntityID
+ASTReader::getGlobalPreprocessedEntityID(Module &M, unsigned LocalID) const {
+ ContinuousRangeMap<uint32_t, int, 2>::const_iterator
+ I = M.PreprocessedEntityRemap.find(LocalID - NUM_PREDEF_PP_ENTITY_IDS);
+ assert(I != M.PreprocessedEntityRemap.end()
+ && "Invalid index into preprocessed entity index remap");
- Error("invalid offset in preprocessor detail block");
- return 0;
+ return LocalID + I->second;
}
-namespace {
- /// \brief Trait class used to search the on-disk hash table containing all of
- /// the header search information.
- ///
- /// The on-disk hash table contains a mapping from each header path to
- /// information about that header (how many times it has been included, its
- /// controlling macro, etc.). Note that we actually hash based on the
- /// filename, and support "deep" comparisons of file names based on current
- /// inode numbers, so that the search can cope with non-normalized path names
- /// and symlinks.
- class HeaderFileInfoTrait {
- 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 HeaderFileInfo data_type;
-
- HeaderFileInfoTrait(const char *SearchPath = 0) : SearchPath(SearchPath) { }
-
- static unsigned ComputeHash(const char *path) {
- return llvm::HashString(llvm::sys::path::filename(path));
- }
+unsigned HeaderFileInfoTrait::ComputeHash(const char *path) {
+ return llvm::HashString(llvm::sys::path::filename(path));
+}
- static internal_key_type GetInternalKey(const char *path) { return path; }
+HeaderFileInfoTrait::internal_key_type
+HeaderFileInfoTrait::GetInternalKey(const char *path) { return path; }
- bool 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))
- return false;
-
- // The file names match, but the path names don't. stat() the files to
- // see if they are the same.
- struct stat StatBufA, StatBufB;
- if (StatSimpleCache(a, &StatBufA) || StatSimpleCache(b, &StatBufB))
- return false;
-
- return StatBufA.st_ino == StatBufB.st_ino;
- }
-
- static std::pair<unsigned, unsigned>
- ReadKeyDataLength(const unsigned char*& d) {
- unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d);
- unsigned DataLen = (unsigned) *d++;
- return std::make_pair(KeyLen + 1, DataLen);
- }
+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))
+ return false;
+
+ // The file names match, but the path names don't. stat() the files to
+ // see if they are the same.
+ struct stat StatBufA, StatBufB;
+ if (StatSimpleCache(a, &StatBufA) || StatSimpleCache(b, &StatBufB))
+ return false;
+
+ return StatBufA.st_ino == StatBufB.st_ino;
+}
- static internal_key_type ReadKey(const unsigned char *d, unsigned) {
- return (const char *)d;
- }
+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);
+}
- static data_type ReadData(const internal_key_type, const unsigned char *d,
+HeaderFileInfoTrait::data_type
+HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d,
unsigned DataLen) {
- const unsigned char *End = d + DataLen;
- using namespace clang::io;
- HeaderFileInfo HFI;
- unsigned Flags = *d++;
- HFI.isImport = (Flags >> 4) & 0x01;
- HFI.isPragmaOnce = (Flags >> 3) & 0x01;
- HFI.DirInfo = (Flags >> 1) & 0x03;
- HFI.Resolved = Flags & 0x01;
- HFI.NumIncludes = ReadUnalignedLE16(d);
- HFI.ControllingMacroID = ReadUnalignedLE32(d);
- assert(End == d && "Wrong data length in HeaderFileInfo deserialization");
- (void)End;
-
- // This HeaderFileInfo was externally loaded.
- HFI.External = true;
- return HFI;
- }
- };
+ const unsigned char *End = d + DataLen;
+ using namespace clang::io;
+ HeaderFileInfo HFI;
+ unsigned Flags = *d++;
+ HFI.isImport = (Flags >> 5) & 0x01;
+ HFI.isPragmaOnce = (Flags >> 4) & 0x01;
+ HFI.DirInfo = (Flags >> 2) & 0x03;
+ HFI.Resolved = (Flags >> 1) & 0x01;
+ HFI.IndexHeaderMapHeader = Flags & 0x01;
+ HFI.NumIncludes = ReadUnalignedLE16(d);
+ HFI.ControllingMacroID = Reader.getGlobalDeclID(M, ReadUnalignedLE32(d));
+ if (unsigned FrameworkOffset = ReadUnalignedLE32(d)) {
+ // The framework offset is 1 greater than the actual offset,
+ // since 0 is used as an indicator for "no framework name".
+ StringRef FrameworkName(FrameworkStrings + FrameworkOffset - 1);
+ HFI.Framework = HS->getUniqueFrameworkName(FrameworkName);
+ }
+
+ assert(End == d && "Wrong data length in HeaderFileInfo deserialization");
+ (void)End;
+
+ // This HeaderFileInfo was externally loaded.
+ HFI.External = true;
+ return HFI;
}
-/// \brief The on-disk hash table used for the global method pool.
-typedef OnDiskChainedHashTable<HeaderFileInfoTrait>
- HeaderFileInfoLookupTable;
-
-void ASTReader::SetIdentifierIsMacro(IdentifierInfo *II, PerFileData &F,
- uint64_t Offset) {
+void ASTReader::SetIdentifierIsMacro(IdentifierInfo *II, Module &F,
+ uint64_t LocalOffset) {
// Note that this identifier has a macro definition.
II->setHasMacroDefinition(true);
- // Adjust the offset based on our position in the chain.
- for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- if (Chain[I] == &F)
- break;
-
- Offset += Chain[I]->SizeInBits;
- }
-
- UnreadMacroRecordOffsets[II] = Offset;
+ // Adjust the offset to a global offset.
+ UnreadMacroRecordOffsets[II] = F.GlobalBitOffset + LocalOffset;
}
void ASTReader::ReadDefinedMacros() {
- for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- PerFileData &F = *Chain[N - I - 1];
- llvm::BitstreamCursor &MacroCursor = F.MacroCursor;
+ for (ModuleReverseIterator I = ModuleMgr.rbegin(),
+ E = ModuleMgr.rend(); I != E; ++I) {
+ llvm::BitstreamCursor &MacroCursor = (*I)->MacroCursor;
// If there was no preprocessor block, skip this file.
if (!MacroCursor.getBitStreamReader())
continue;
llvm::BitstreamCursor Cursor = MacroCursor;
- Cursor.JumpToBit(F.MacroStartOffset);
+ Cursor.JumpToBit((*I)->MacroStartOffset);
RecordData Record;
while (true) {
@@ -1780,7 +1467,7 @@ void ASTReader::ReadDefinedMacros() {
case PP_MACRO_OBJECT_LIKE:
case PP_MACRO_FUNCTION_LIKE:
- DecodeIdentifierInfo(Record[0]);
+ getLocalIdentifier(**I, Record[0]);
break;
case PP_TOKEN:
@@ -1798,24 +1485,11 @@ void ASTReader::ReadDefinedMacros() {
void ASTReader::LoadMacroDefinition(
llvm::DenseMap<IdentifierInfo *, uint64_t>::iterator Pos) {
assert(Pos != UnreadMacroRecordOffsets.end() && "Unknown macro definition");
- PerFileData *F = 0;
uint64_t Offset = Pos->second;
UnreadMacroRecordOffsets.erase(Pos);
- for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- if (Offset < Chain[I]->SizeInBits) {
- F = Chain[I];
- break;
- }
-
- Offset -= Chain[I]->SizeInBits;
- }
- if (!F) {
- Error("Malformed macro record offset");
- return;
- }
-
- ReadMacroRecord(*F, Offset);
+ RecordLocation Loc = getLocalBitOffset(Offset);
+ ReadMacroRecord(*Loc.F, Loc.Offset);
}
void ASTReader::LoadMacroDefinition(IdentifierInfo *II) {
@@ -1824,29 +1498,7 @@ void ASTReader::LoadMacroDefinition(IdentifierInfo *II) {
LoadMacroDefinition(Pos);
}
-MacroDefinition *ASTReader::getMacroDefinition(MacroID ID) {
- if (ID == 0 || ID > MacroDefinitionsLoaded.size())
- return 0;
-
- if (!MacroDefinitionsLoaded[ID - 1]) {
- unsigned Index = ID - 1;
- for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- PerFileData &F = *Chain[N - I - 1];
- if (Index < F.LocalNumMacroDefinitions) {
- SavedStreamPosition SavedPosition(F.PreprocessorDetailCursor);
- F.PreprocessorDetailCursor.JumpToBit(F.MacroDefinitionOffsets[Index]);
- LoadPreprocessedEntity(F);
- break;
- }
- Index -= F.LocalNumMacroDefinitions;
- }
- assert(MacroDefinitionsLoaded[ID - 1] && "Broken chain");
- }
-
- return MacroDefinitionsLoaded[ID - 1];
-}
-
-const FileEntry *ASTReader::getFileEntry(llvm::StringRef filenameStrRef) {
+const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) {
std::string Filename = filenameStrRef;
MaybeAddSystemRootToFilename(Filename);
const FileEntry *File = FileMgr.getFile(Filename);
@@ -1873,21 +1525,21 @@ void ASTReader::MaybeAddSystemRootToFilename(std::string &Filename) {
if (Filename.empty() || llvm::sys::path::is_absolute(Filename))
return;
- if (isysroot == 0) {
+ if (isysroot.empty()) {
// If no system root was given, default to '/'
Filename.insert(Filename.begin(), '/');
return;
}
- unsigned Length = strlen(isysroot);
+ unsigned Length = isysroot.size();
if (isysroot[Length - 1] != '/')
Filename.insert(Filename.begin(), '/');
- Filename.insert(Filename.begin(), isysroot, isysroot + Length);
+ Filename.insert(Filename.begin(), isysroot.begin(), isysroot.end());
}
ASTReader::ASTReadResult
-ASTReader::ReadASTBlock(PerFileData &F) {
+ASTReader::ReadASTBlock(Module &F) {
llvm::BitstreamCursor &Stream = F.Stream;
if (Stream.EnterSubBlock(AST_BLOCK_ID)) {
@@ -1897,7 +1549,6 @@ ASTReader::ReadASTBlock(PerFileData &F) {
// Read all of the records and blocks for the ASt file.
RecordData Record;
- bool First = true;
while (!Stream.AtEndOfStream()) {
unsigned Code = Stream.ReadCode();
if (Code == llvm::bitc::END_BLOCK) {
@@ -1934,8 +1585,8 @@ ASTReader::ReadASTBlock(PerFileData &F) {
case PREPROCESSOR_BLOCK_ID:
F.MacroCursor = Stream;
- if (PP)
- PP->setExternalSource(this);
+ if (!PP.getExternalSource())
+ PP.setExternalSource(this);
if (Stream.SkipBlock() ||
ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) {
@@ -1955,6 +1606,11 @@ ASTReader::ReadASTBlock(PerFileData &F) {
}
F.PreprocessorDetailStartOffset
= F.PreprocessorDetailCursor.GetCurrentBitNo();
+
+ if (!PP.getPreprocessingRecord())
+ PP.createPreprocessingRecord(true);
+ if (!PP.getPreprocessingRecord()->getExternalSource())
+ PP.getPreprocessingRecord()->SetExternalSource(*this);
break;
case SOURCE_MANAGER_BLOCK_ID:
@@ -1971,7 +1627,6 @@ ASTReader::ReadASTBlock(PerFileData &F) {
}
break;
}
- First = false;
continue;
}
@@ -2005,79 +1660,108 @@ ASTReader::ReadASTBlock(PerFileData &F) {
break;
}
- case CHAINED_METADATA: {
- if (!First) {
- Error("CHAINED_METADATA is not first record in block");
- return Failure;
- }
- if (Record[0] != VERSION_MAJOR && !DisableValidation) {
- Diag(Record[0] < VERSION_MAJOR? diag::warn_pch_version_too_old
- : diag::warn_pch_version_too_new);
- return IgnorePCH;
- }
-
- // Load the chained file, which is always a PCH file.
- switch(ReadASTCore(llvm::StringRef(BlobStart, BlobLen), PCH)) {
- case Failure: return Failure;
- // If we have to ignore the dependency, we'll have to ignore this too.
- case IgnorePCH: return IgnorePCH;
- case Success: break;
+ case IMPORTS: {
+ // Load each of the imported PCH files.
+ unsigned Idx = 0, N = Record.size();
+ while (Idx < N) {
+ // Read information about the AST file.
+ ModuleKind ImportedKind = (ModuleKind)Record[Idx++];
+ unsigned Length = Record[Idx++];
+ llvm::SmallString<128> ImportedFile(Record.begin() + Idx,
+ Record.begin() + Idx + Length);
+ Idx += Length;
+
+ // Load the AST file.
+ switch(ReadASTCore(ImportedFile, ImportedKind, &F)) {
+ case Failure: return Failure;
+ // If we have to ignore the dependency, we'll have to ignore this too.
+ case IgnorePCH: return IgnorePCH;
+ case Success: break;
+ }
}
break;
}
- case TYPE_OFFSET:
+ case TYPE_OFFSET: {
if (F.LocalNumTypes != 0) {
Error("duplicate TYPE_OFFSET record in AST file");
return Failure;
}
F.TypeOffsets = (const uint32_t *)BlobStart;
F.LocalNumTypes = Record[0];
+ unsigned LocalBaseTypeIndex = Record[1];
+ F.BaseTypeIndex = getTotalNumTypes();
+
+ if (F.LocalNumTypes > 0) {
+ // Introduce the global -> local mapping for types within this module.
+ GlobalTypeMap.insert(std::make_pair(getTotalNumTypes(), &F));
+
+ // Introduce the local -> global mapping for types within this module.
+ F.TypeRemap.insert(std::make_pair(LocalBaseTypeIndex,
+ F.BaseTypeIndex - LocalBaseTypeIndex));
+
+ TypesLoaded.resize(TypesLoaded.size() + F.LocalNumTypes);
+ }
break;
-
- case DECL_OFFSET:
+ }
+
+ case DECL_OFFSET: {
if (F.LocalNumDecls != 0) {
Error("duplicate DECL_OFFSET record in AST file");
return Failure;
}
F.DeclOffsets = (const uint32_t *)BlobStart;
F.LocalNumDecls = Record[0];
+ unsigned LocalBaseDeclID = Record[1];
+ F.BaseDeclID = getTotalNumDecls();
+
+ if (F.LocalNumDecls > 0) {
+ // Introduce the global -> local mapping for declarations within this
+ // module.
+ GlobalDeclMap.insert(
+ std::make_pair(getTotalNumDecls() + NUM_PREDEF_DECL_IDS, &F));
+
+ // Introduce the local -> global mapping for declarations within this
+ // module.
+ F.DeclRemap.insert(std::make_pair(LocalBaseDeclID,
+ F.BaseDeclID - LocalBaseDeclID));
+
+ DeclsLoaded.resize(DeclsLoaded.size() + F.LocalNumDecls);
+ }
break;
-
+ }
+
case TU_UPDATE_LEXICAL: {
- DeclContextInfo Info = {
- /* No visible information */ 0,
- reinterpret_cast<const KindDeclIDPair *>(BlobStart),
- BlobLen / sizeof(KindDeclIDPair)
- };
- DeclContextOffsets[Context ? Context->getTranslationUnitDecl() : 0]
- .push_back(Info);
+ DeclContext *TU = Context.getTranslationUnitDecl();
+ DeclContextInfo &Info = F.DeclContextInfos[TU];
+ Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair *>(BlobStart);
+ Info.NumLexicalDecls
+ = static_cast<unsigned int>(BlobLen / sizeof(KindDeclIDPair));
+ TU->setHasExternalLexicalStorage(true);
break;
}
case UPDATE_VISIBLE: {
- serialization::DeclID ID = Record[0];
+ unsigned Idx = 0;
+ serialization::DeclID ID = ReadDeclID(F, Record, Idx);
void *Table = ASTDeclContextNameLookupTable::Create(
- (const unsigned char *)BlobStart + Record[1],
+ (const unsigned char *)BlobStart + Record[Idx++],
(const unsigned char *)BlobStart,
- ASTDeclContextNameLookupTrait(*this));
- if (ID == 1 && Context) { // Is it the TU?
- DeclContextInfo Info = {
- Table, /* No lexical inforamtion */ 0, 0
- };
- DeclContextOffsets[Context->getTranslationUnitDecl()].push_back(Info);
+ ASTDeclContextNameLookupTrait(*this, F));
+ if (ID == PREDEF_DECL_TRANSLATION_UNIT_ID) { // Is it the TU?
+ DeclContext *TU = Context.getTranslationUnitDecl();
+ F.DeclContextInfos[TU].NameLookupTableData = Table;
+ TU->setHasExternalVisibleStorage(true);
} else
- PendingVisibleUpdates[ID].push_back(Table);
+ PendingVisibleUpdates[ID].push_back(std::make_pair(Table, &F));
break;
}
case REDECLS_UPDATE_LATEST: {
assert(Record.size() % 2 == 0 && "Expected pairs of DeclIDs");
- for (unsigned i = 0, e = Record.size(); i < e; i += 2) {
- DeclID First = Record[i], Latest = Record[i+1];
- assert((FirstLatestDeclIDs.find(First) == FirstLatestDeclIDs.end() ||
- Latest > FirstLatestDeclIDs[First]) &&
- "The new latest is supposed to come after the previous latest");
+ for (unsigned i = 0, e = Record.size(); i < e; /* in loop */) {
+ DeclID First = ReadDeclID(F, Record, i);
+ DeclID Latest = ReadDeclID(F, Record, i);
FirstLatestDeclIDs[First] = Latest;
}
break;
@@ -2096,35 +1780,47 @@ ASTReader::ReadASTBlock(PerFileData &F) {
(const unsigned char *)F.IdentifierTableData + Record[0],
(const unsigned char *)F.IdentifierTableData,
ASTIdentifierLookupTrait(*this, F));
- if (PP)
- PP->getIdentifierTable().setExternalIdentifierLookup(this);
+
+ PP.getIdentifierTable().setExternalIdentifierLookup(this);
}
break;
- case IDENTIFIER_OFFSET:
+ case IDENTIFIER_OFFSET: {
if (F.LocalNumIdentifiers != 0) {
Error("duplicate IDENTIFIER_OFFSET record in AST file");
return Failure;
}
F.IdentifierOffsets = (const uint32_t *)BlobStart;
F.LocalNumIdentifiers = Record[0];
+ unsigned LocalBaseIdentifierID = Record[1];
+ F.BaseIdentifierID = getTotalNumIdentifiers();
+
+ if (F.LocalNumIdentifiers > 0) {
+ // Introduce the global -> local mapping for identifiers within this
+ // module.
+ GlobalIdentifierMap.insert(std::make_pair(getTotalNumIdentifiers() + 1,
+ &F));
+
+ // Introduce the local -> global mapping for identifiers within this
+ // module.
+ F.IdentifierRemap.insert(
+ std::make_pair(LocalBaseIdentifierID,
+ F.BaseIdentifierID - LocalBaseIdentifierID));
+
+ IdentifiersLoaded.resize(IdentifiersLoaded.size()
+ + F.LocalNumIdentifiers);
+ }
break;
-
+ }
+
case EXTERNAL_DEFINITIONS:
- // Optimization for the first block.
- if (ExternalDefinitions.empty())
- ExternalDefinitions.swap(Record);
- else
- ExternalDefinitions.insert(ExternalDefinitions.end(),
- Record.begin(), Record.end());
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ ExternalDefinitions.push_back(getGlobalDeclID(F, Record[I]));
break;
case SPECIAL_TYPES:
- // Optimization for the first block
- if (SpecialTypes.empty())
- SpecialTypes.swap(Record);
- else
- SpecialTypes.insert(SpecialTypes.end(), Record.begin(), Record.end());
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ SpecialTypes.push_back(getGlobalTypeID(F, Record[I]));
break;
case STATISTICS:
@@ -2135,42 +1831,63 @@ ASTReader::ReadASTBlock(PerFileData &F) {
break;
case UNUSED_FILESCOPED_DECLS:
- // Optimization for the first block.
- if (UnusedFileScopedDecls.empty())
- UnusedFileScopedDecls.swap(Record);
- else
- UnusedFileScopedDecls.insert(UnusedFileScopedDecls.end(),
- Record.begin(), Record.end());
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ UnusedFileScopedDecls.push_back(getGlobalDeclID(F, Record[I]));
break;
case DELEGATING_CTORS:
- // Optimization for the first block.
- if (DelegatingCtorDecls.empty())
- DelegatingCtorDecls.swap(Record);
- else
- DelegatingCtorDecls.insert(DelegatingCtorDecls.end(),
- Record.begin(), Record.end());
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ DelegatingCtorDecls.push_back(getGlobalDeclID(F, Record[I]));
break;
case WEAK_UNDECLARED_IDENTIFIERS:
- // Later blocks overwrite earlier ones.
- WeakUndeclaredIdentifiers.swap(Record);
+ if (Record.size() % 4 != 0) {
+ Error("invalid weak identifiers record");
+ return Failure;
+ }
+
+ // FIXME: Ignore weak undeclared identifiers from non-original PCH
+ // files. This isn't the way to do it :)
+ WeakUndeclaredIdentifiers.clear();
+
+ // Translate the weak, undeclared identifiers into global IDs.
+ for (unsigned I = 0, N = Record.size(); I < N; /* in loop */) {
+ WeakUndeclaredIdentifiers.push_back(
+ getGlobalIdentifierID(F, Record[I++]));
+ WeakUndeclaredIdentifiers.push_back(
+ getGlobalIdentifierID(F, Record[I++]));
+ WeakUndeclaredIdentifiers.push_back(
+ ReadSourceLocation(F, Record, I).getRawEncoding());
+ WeakUndeclaredIdentifiers.push_back(Record[I++]);
+ }
break;
case LOCALLY_SCOPED_EXTERNAL_DECLS:
- // Optimization for the first block.
- if (LocallyScopedExternalDecls.empty())
- LocallyScopedExternalDecls.swap(Record);
- else
- LocallyScopedExternalDecls.insert(LocallyScopedExternalDecls.end(),
- Record.begin(), Record.end());
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ LocallyScopedExternalDecls.push_back(getGlobalDeclID(F, Record[I]));
break;
- case SELECTOR_OFFSETS:
+ case SELECTOR_OFFSETS: {
F.SelectorOffsets = (const uint32_t *)BlobStart;
F.LocalNumSelectors = Record[0];
- break;
+ unsigned LocalBaseSelectorID = Record[1];
+ F.BaseSelectorID = getTotalNumSelectors();
+
+ if (F.LocalNumSelectors > 0) {
+ // Introduce the global -> local mapping for selectors within this
+ // module.
+ GlobalSelectorMap.insert(std::make_pair(getTotalNumSelectors()+1, &F));
+
+ // Introduce the local -> global mapping for selectors within this
+ // module.
+ F.SelectorRemap.insert(std::make_pair(LocalBaseSelectorID,
+ F.BaseSelectorID - LocalBaseSelectorID));
+ SelectorsLoaded.resize(SelectorsLoaded.size() + F.LocalNumSelectors);
+ }
+ break;
+ }
+
case METHOD_POOL:
F.SelectorLookupTableData = (const unsigned char *)BlobStart;
if (Record[0])
@@ -2178,12 +1895,19 @@ ASTReader::ReadASTBlock(PerFileData &F) {
= ASTSelectorLookupTable::Create(
F.SelectorLookupTableData + Record[0],
F.SelectorLookupTableData,
- ASTSelectorLookupTrait(*this));
+ ASTSelectorLookupTrait(*this, F));
TotalNumMethodPoolEntries += Record[1];
break;
case REFERENCED_SELECTOR_POOL:
- F.ReferencedSelectorsData.swap(Record);
+ if (!Record.empty()) {
+ for (unsigned Idx = 0, N = Record.size() - 1; Idx < N; /* in loop */) {
+ ReferencedSelectorsData.push_back(getGlobalSelectorID(F,
+ Record[Idx++]));
+ ReferencedSelectorsData.push_back(ReadSourceLocation(F, Record, Idx).
+ getRawEncoding());
+ }
+ }
break;
case PP_COUNTER_VALUE:
@@ -2191,10 +1915,94 @@ ASTReader::ReadASTBlock(PerFileData &F) {
Listener->ReadCounter(Record[0]);
break;
- case SOURCE_LOCATION_OFFSETS:
- F.SLocOffsets = (const uint32_t *)BlobStart;
+ case SOURCE_LOCATION_OFFSETS: {
+ F.SLocEntryOffsets = (const uint32_t *)BlobStart;
F.LocalNumSLocEntries = Record[0];
- F.LocalSLocSize = Record[1];
+ unsigned SLocSpaceSize = Record[1];
+ llvm::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) =
+ SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries,
+ SLocSpaceSize);
+ // Make our entry in the range map. BaseID is negative and growing, so
+ // we invert it. Because we invert it, though, we need the other end of
+ // the range.
+ unsigned RangeStart =
+ unsigned(-F.SLocEntryBaseID) - F.LocalNumSLocEntries + 1;
+ GlobalSLocEntryMap.insert(std::make_pair(RangeStart, &F));
+ F.FirstLoc = SourceLocation::getFromRawEncoding(F.SLocEntryBaseOffset);
+
+ // SLocEntryBaseOffset is lower than MaxLoadedOffset and decreasing.
+ assert((F.SLocEntryBaseOffset & (1U << 31U)) == 0);
+ GlobalSLocOffsetMap.insert(
+ std::make_pair(SourceManager::MaxLoadedOffset - F.SLocEntryBaseOffset
+ - SLocSpaceSize,&F));
+
+ // Initialize the remapping table.
+ // Invalid stays invalid.
+ F.SLocRemap.insert(std::make_pair(0U, 0));
+ // This module. Base was 2 when being compiled.
+ F.SLocRemap.insert(std::make_pair(2U,
+ static_cast<int>(F.SLocEntryBaseOffset - 2)));
+
+ TotalNumSLocEntries += F.LocalNumSLocEntries;
+ break;
+ }
+
+ case MODULE_OFFSET_MAP: {
+ // Additional remapping information.
+ const unsigned char *Data = (const unsigned char*)BlobStart;
+ const unsigned char *DataEnd = Data + BlobLen;
+
+ // Continuous range maps we may be updating in our module.
+ ContinuousRangeMap<uint32_t, int, 2>::Builder SLocRemap(F.SLocRemap);
+ ContinuousRangeMap<uint32_t, int, 2>::Builder
+ IdentifierRemap(F.IdentifierRemap);
+ ContinuousRangeMap<uint32_t, int, 2>::Builder
+ PreprocessedEntityRemap(F.PreprocessedEntityRemap);
+ ContinuousRangeMap<uint32_t, int, 2>::Builder
+ SelectorRemap(F.SelectorRemap);
+ ContinuousRangeMap<uint32_t, int, 2>::Builder DeclRemap(F.DeclRemap);
+ ContinuousRangeMap<uint32_t, int, 2>::Builder TypeRemap(F.TypeRemap);
+
+ while(Data < DataEnd) {
+ uint16_t Len = io::ReadUnalignedLE16(Data);
+ StringRef Name = StringRef((const char*)Data, Len);
+ Data += Len;
+ Module *OM = ModuleMgr.lookup(Name);
+ if (!OM) {
+ Error("SourceLocation remap refers to unknown module");
+ return Failure;
+ }
+
+ uint32_t SLocOffset = io::ReadUnalignedLE32(Data);
+ uint32_t IdentifierIDOffset = io::ReadUnalignedLE32(Data);
+ uint32_t PreprocessedEntityIDOffset = io::ReadUnalignedLE32(Data);
+ uint32_t SelectorIDOffset = io::ReadUnalignedLE32(Data);
+ uint32_t DeclIDOffset = io::ReadUnalignedLE32(Data);
+ uint32_t TypeIndexOffset = io::ReadUnalignedLE32(Data);
+
+ // Source location offset is mapped to OM->SLocEntryBaseOffset.
+ SLocRemap.insert(std::make_pair(SLocOffset,
+ static_cast<int>(OM->SLocEntryBaseOffset - SLocOffset)));
+ IdentifierRemap.insert(
+ std::make_pair(IdentifierIDOffset,
+ OM->BaseIdentifierID - IdentifierIDOffset));
+ PreprocessedEntityRemap.insert(
+ std::make_pair(PreprocessedEntityIDOffset,
+ OM->BasePreprocessedEntityID - PreprocessedEntityIDOffset));
+ SelectorRemap.insert(std::make_pair(SelectorIDOffset,
+ OM->BaseSelectorID - SelectorIDOffset));
+ DeclRemap.insert(std::make_pair(DeclIDOffset,
+ OM->BaseDeclID - DeclIDOffset));
+
+ TypeRemap.insert(std::make_pair(TypeIndexOffset,
+ OM->BaseTypeIndex - TypeIndexOffset));
+ }
+ break;
+ }
+
+ case SOURCE_MANAGER_LINE_TABLE:
+ if (ParseLineTable(F, Record))
+ return Failure;
break;
case FILE_SOURCE_LOCATION_OFFSETS:
@@ -2202,13 +2010,17 @@ ASTReader::ReadASTBlock(PerFileData &F) {
F.LocalNumSLocFileEntries = Record[0];
break;
- case SOURCE_LOCATION_PRELOADS:
- if (PreloadSLocEntries.empty())
- PreloadSLocEntries.swap(Record);
- else
- PreloadSLocEntries.insert(PreloadSLocEntries.end(),
- Record.begin(), Record.end());
+ case SOURCE_LOCATION_PRELOADS: {
+ // Need to transform from the local view (1-based IDs) to the global view,
+ // which is based off F.SLocEntryBaseID.
+ if (!F.PreloadSLocEntries.empty()) {
+ Error("Multiple SOURCE_LOCATION_PRELOADS records in AST file");
+ return Failure;
+ }
+
+ F.PreloadSLocEntries.swap(Record);
break;
+ }
case STAT_CACHE: {
if (!DisableStatCache) {
@@ -2223,35 +2035,56 @@ ASTReader::ReadASTBlock(PerFileData &F) {
}
case EXT_VECTOR_DECLS:
- // Optimization for the first block.
- if (ExtVectorDecls.empty())
- ExtVectorDecls.swap(Record);
- else
- ExtVectorDecls.insert(ExtVectorDecls.end(),
- Record.begin(), Record.end());
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ ExtVectorDecls.push_back(getGlobalDeclID(F, Record[I]));
break;
case VTABLE_USES:
+ if (Record.size() % 3 != 0) {
+ Error("Invalid VTABLE_USES record");
+ return Failure;
+ }
+
// Later tables overwrite earlier ones.
- VTableUses.swap(Record);
+ // FIXME: Modules will have some trouble with this. This is clearly not
+ // the right way to do this.
+ VTableUses.clear();
+
+ for (unsigned Idx = 0, N = Record.size(); Idx != N; /* In loop */) {
+ VTableUses.push_back(getGlobalDeclID(F, Record[Idx++]));
+ VTableUses.push_back(
+ ReadSourceLocation(F, Record, Idx).getRawEncoding());
+ VTableUses.push_back(Record[Idx++]);
+ }
break;
case DYNAMIC_CLASSES:
- // Optimization for the first block.
- if (DynamicClasses.empty())
- DynamicClasses.swap(Record);
- else
- DynamicClasses.insert(DynamicClasses.end(),
- Record.begin(), Record.end());
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ DynamicClasses.push_back(getGlobalDeclID(F, Record[I]));
break;
case PENDING_IMPLICIT_INSTANTIATIONS:
- F.PendingInstantiations.swap(Record);
+ if (PendingInstantiations.size() % 2 != 0) {
+ Error("Invalid PENDING_IMPLICIT_INSTANTIATIONS block");
+ return Failure;
+ }
+
+ // Later lists of pending instantiations overwrite earlier ones.
+ // FIXME: This is most certainly wrong for modules.
+ PendingInstantiations.clear();
+ for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
+ PendingInstantiations.push_back(getGlobalDeclID(F, Record[I++]));
+ PendingInstantiations.push_back(
+ ReadSourceLocation(F, Record, I).getRawEncoding());
+ }
break;
case SEMA_DECL_REFS:
// Later tables overwrite earlier ones.
- SemaDeclRefs.swap(Record);
+ // FIXME: Modules will have some trouble with this.
+ SemaDeclRefs.clear();
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ SemaDeclRefs.push_back(getGlobalDeclID(F, Record[I]));
break;
case ORIGINAL_FILE_NAME:
@@ -2274,28 +2107,54 @@ ASTReader::ReadASTBlock(PerFileData &F) {
case VERSION_CONTROL_BRANCH_REVISION: {
const std::string &CurBranch = getClangFullRepositoryVersion();
- llvm::StringRef ASTBranch(BlobStart, BlobLen);
- if (llvm::StringRef(CurBranch) != ASTBranch && !DisableValidation) {
+ StringRef ASTBranch(BlobStart, BlobLen);
+ if (StringRef(CurBranch) != ASTBranch && !DisableValidation) {
Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch;
return IgnorePCH;
}
break;
}
- case MACRO_DEFINITION_OFFSETS:
- F.MacroDefinitionOffsets = (const uint32_t *)BlobStart;
- F.NumPreallocatedPreprocessingEntities = Record[0];
- F.LocalNumMacroDefinitions = Record[1];
- break;
+ case PPD_ENTITIES_OFFSETS: {
+ F.PreprocessedEntityOffsets = (const PPEntityOffset *)BlobStart;
+ assert(BlobLen % sizeof(PPEntityOffset) == 0);
+ F.NumPreprocessedEntities = BlobLen / sizeof(PPEntityOffset);
+
+ unsigned LocalBasePreprocessedEntityID = Record[0];
+
+ unsigned StartingID;
+ if (!PP.getPreprocessingRecord())
+ PP.createPreprocessingRecord(true);
+ if (!PP.getPreprocessingRecord()->getExternalSource())
+ PP.getPreprocessingRecord()->SetExternalSource(*this);
+ StartingID
+ = PP.getPreprocessingRecord()
+ ->allocateLoadedEntities(F.NumPreprocessedEntities);
+ F.BasePreprocessedEntityID = StartingID;
+
+ if (F.NumPreprocessedEntities > 0) {
+ // Introduce the global -> local mapping for preprocessed entities in
+ // this module.
+ GlobalPreprocessedEntityMap.insert(std::make_pair(StartingID, &F));
+
+ // Introduce the local -> global mapping for preprocessed entities in
+ // this module.
+ F.PreprocessedEntityRemap.insert(
+ std::make_pair(LocalBasePreprocessedEntityID,
+ F.BasePreprocessedEntityID - LocalBasePreprocessedEntityID));
+ }
+ break;
+ }
+
case DECL_UPDATE_OFFSETS: {
if (Record.size() % 2 != 0) {
Error("invalid DECL_UPDATE_OFFSETS block in AST file");
return Failure;
}
for (unsigned I = 0, N = Record.size(); I != N; I += 2)
- DeclUpdateOffsets[static_cast<DeclID>(Record[I])]
- .push_back(std::make_pair(&F, Record[I+1]));
+ DeclUpdateOffsets[getGlobalDeclID(F, Record[I])]
+ .push_back(std::make_pair(&F, Record[I+1]));
break;
}
@@ -2305,8 +2164,22 @@ ASTReader::ReadASTBlock(PerFileData &F) {
return Failure;
}
for (unsigned I = 0, N = Record.size(); I != N; I += 2)
- ReplacedDecls[static_cast<DeclID>(Record[I])] =
- std::make_pair(&F, Record[I+1]);
+ ReplacedDecls[getGlobalDeclID(F, Record[I])]
+ = std::make_pair(&F, Record[I+1]);
+ break;
+ }
+
+ case OBJC_CHAINED_CATEGORIES: {
+ if (Record.size() % 3 != 0) {
+ Error("invalid OBJC_CHAINED_CATEGORIES block in AST file");
+ return Failure;
+ }
+ for (unsigned I = 0, N = Record.size(); I != N; I += 3) {
+ serialization::GlobalDeclID GlobID = getGlobalDeclID(F, Record[I]);
+ F.ChainedObjCCategories[GlobID] = std::make_pair(Record[I+1],
+ Record[I+2]);
+ ObjCChainedCategoriesInterfaces.insert(GlobID);
+ }
break;
}
@@ -2318,6 +2191,7 @@ ASTReader::ReadASTBlock(PerFileData &F) {
F.LocalNumCXXBaseSpecifiers = Record[0];
F.CXXBaseSpecifiersOffsets = (const uint32_t *)BlobStart;
+ NumCXXBaseSpecifiersLoaded += F.LocalNumCXXBaseSpecifiers;
break;
}
@@ -2326,31 +2200,42 @@ ASTReader::ReadASTBlock(PerFileData &F) {
Error("invalid DIAG_USER_MAPPINGS block in AST file");
return Failure;
}
- if (PragmaDiagMappings.empty())
- PragmaDiagMappings.swap(Record);
+
+ if (F.PragmaDiagMappings.empty())
+ F.PragmaDiagMappings.swap(Record);
else
- PragmaDiagMappings.insert(PragmaDiagMappings.end(),
- Record.begin(), Record.end());
+ F.PragmaDiagMappings.insert(F.PragmaDiagMappings.end(),
+ Record.begin(), Record.end());
break;
case CUDA_SPECIAL_DECL_REFS:
// Later tables overwrite earlier ones.
- CUDASpecialDeclRefs.swap(Record);
+ // FIXME: Modules will have trouble with this.
+ CUDASpecialDeclRefs.clear();
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ CUDASpecialDeclRefs.push_back(getGlobalDeclID(F, Record[I]));
break;
- case HEADER_SEARCH_TABLE:
+ case HEADER_SEARCH_TABLE: {
F.HeaderFileInfoTableData = BlobStart;
F.LocalNumHeaderFileInfos = Record[1];
+ F.HeaderFileFrameworkStrings = BlobStart + Record[2];
if (Record[0]) {
F.HeaderFileInfoTable
= HeaderFileInfoLookupTable::Create(
(const unsigned char *)F.HeaderFileInfoTableData + Record[0],
- (const unsigned char *)F.HeaderFileInfoTableData);
- if (PP)
- PP->getHeaderSearchInfo().SetExternalSource(this);
+ (const unsigned char *)F.HeaderFileInfoTableData,
+ HeaderFileInfoTrait(*this, F,
+ &PP.getHeaderSearchInfo(),
+ BlobStart + Record[2]));
+
+ PP.getHeaderSearchInfo().SetExternalSource(this);
+ if (!PP.getHeaderSearchInfo().getExternalLookup())
+ PP.getHeaderSearchInfo().SetExternalLookup(this);
}
break;
-
+ }
+
case FP_PRAGMA_OPTIONS:
// Later tables overwrite earlier ones.
FPPragmaOptions.swap(Record);
@@ -2362,272 +2247,222 @@ ASTReader::ReadASTBlock(PerFileData &F) {
break;
case TENTATIVE_DEFINITIONS:
- // Optimization for the first block.
- if (TentativeDefinitions.empty())
- TentativeDefinitions.swap(Record);
- else
- TentativeDefinitions.insert(TentativeDefinitions.end(),
- Record.begin(), Record.end());
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ TentativeDefinitions.push_back(getGlobalDeclID(F, Record[I]));
break;
case KNOWN_NAMESPACES:
- // Optimization for the first block.
- if (KnownNamespaces.empty())
- KnownNamespaces.swap(Record);
- else
- KnownNamespaces.insert(KnownNamespaces.end(),
- Record.begin(), Record.end());
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ KnownNamespaces.push_back(getGlobalDeclID(F, Record[I]));
break;
}
- First = false;
}
Error("premature end of bitstream in AST file");
return Failure;
}
-ASTReader::ASTReadResult ASTReader::validateFileEntries() {
- for (unsigned CI = 0, CN = Chain.size(); CI != CN; ++CI) {
- PerFileData *F = Chain[CI];
- llvm::BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor;
+ASTReader::ASTReadResult ASTReader::validateFileEntries(Module &M) {
+ llvm::BitstreamCursor &SLocEntryCursor = M.SLocEntryCursor;
- for (unsigned i = 0, e = F->LocalNumSLocFileEntries; i != e; ++i) {
- SLocEntryCursor.JumpToBit(F->SLocFileOffsets[i]);
- unsigned Code = SLocEntryCursor.ReadCode();
- if (Code == llvm::bitc::END_BLOCK ||
- Code == llvm::bitc::ENTER_SUBBLOCK ||
- Code == llvm::bitc::DEFINE_ABBREV) {
- Error("incorrectly-formatted source location entry in AST file");
- return Failure;
+ for (unsigned i = 0, e = M.LocalNumSLocFileEntries; i != e; ++i) {
+ SLocEntryCursor.JumpToBit(M.SLocFileOffsets[i]);
+ unsigned Code = SLocEntryCursor.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK ||
+ Code == llvm::bitc::ENTER_SUBBLOCK ||
+ Code == llvm::bitc::DEFINE_ABBREV) {
+ Error("incorrectly-formatted source location entry in AST file");
+ return Failure;
+ }
+
+ RecordData Record;
+ const char *BlobStart;
+ unsigned BlobLen;
+ switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ default:
+ Error("incorrectly-formatted source location entry in AST file");
+ return Failure;
+
+ case SM_SLOC_FILE_ENTRY: {
+ StringRef Filename(BlobStart, BlobLen);
+ const FileEntry *File = getFileEntry(Filename);
+
+ if (File == 0) {
+ std::string ErrorStr = "could not find file '";
+ ErrorStr += Filename;
+ ErrorStr += "' referenced by AST file";
+ Error(ErrorStr.c_str());
+ return IgnorePCH;
}
-
- RecordData Record;
- const char *BlobStart;
- unsigned BlobLen;
- switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
- default:
- Error("incorrectly-formatted source location entry in AST file");
+
+ if (Record.size() < 6) {
+ Error("source location entry is incorrect");
return Failure;
-
- case SM_SLOC_FILE_ENTRY: {
- llvm::StringRef Filename(BlobStart, BlobLen);
- const FileEntry *File = getFileEntry(Filename);
-
- if (File == 0) {
- std::string ErrorStr = "could not find file '";
- ErrorStr += Filename;
- ErrorStr += "' referenced by AST file";
- Error(ErrorStr.c_str());
- return IgnorePCH;
- }
-
- if (Record.size() < 6) {
- Error("source location entry is incorrect");
- return Failure;
- }
+ }
- // 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();
- }
+ // The stat info from the FileEntry came from the cached stat
+ // info of the PCH, so we cannot trust it.
+ struct stat StatBuf;
+ if (::stat(File->getName(), &StatBuf) != 0) {
+ StatBuf.st_size = File->getSize();
+ StatBuf.st_mtime = File->getModificationTime();
+ }
- if (((off_t)Record[4] != StatBuf.st_size
+ if (((off_t)Record[4] != StatBuf.st_size
#if !defined(LLVM_ON_WIN32)
- // In our regression testing, the Windows file system seems to
- // have inconsistent modification times that sometimes
- // erroneously trigger this error-handling path.
- || (time_t)Record[5] != StatBuf.st_mtime
+ // In our regression testing, the Windows file system seems to
+ // have inconsistent modification times that sometimes
+ // erroneously trigger this error-handling path.
+ || (time_t)Record[5] != StatBuf.st_mtime
#endif
- )) {
- Error(diag::err_fe_pch_file_modified, Filename);
- return IgnorePCH;
- }
-
- break;
- }
+ )) {
+ Error(diag::err_fe_pch_file_modified, Filename);
+ return IgnorePCH;
}
+
+ break;
+ }
}
}
return Success;
}
+namespace {
+ /// \brief Visitor class used to look up identifirs in an AST file.
+ class IdentifierLookupVisitor {
+ StringRef Name;
+ IdentifierInfo *Found;
+ public:
+ explicit IdentifierLookupVisitor(StringRef Name) : Name(Name), Found() { }
+
+ static bool visit(Module &M, void *UserData) {
+ IdentifierLookupVisitor *This
+ = static_cast<IdentifierLookupVisitor *>(UserData);
+
+ ASTIdentifierLookupTable *IdTable
+ = (ASTIdentifierLookupTable *)M.IdentifierLookupTable;
+ if (!IdTable)
+ return false;
+
+ std::pair<const char*, unsigned> Key(This->Name.begin(),
+ This->Name.size());
+ ASTIdentifierLookupTable::iterator Pos = IdTable->find(Key);
+ 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->Found = *Pos;
+ return true;
+ }
+
+ // \brief Retrieve the identifier info found within the module
+ // files.
+ IdentifierInfo *getIdentifierInfo() const { return Found; }
+ };
+}
+
+
ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
- ASTFileType Type) {
- switch(ReadASTCore(FileName, Type)) {
+ ModuleKind Type) {
+ switch(ReadASTCore(FileName, Type, /*ImportedBy=*/0)) {
case Failure: return Failure;
case IgnorePCH: return IgnorePCH;
case Success: break;
}
// Here comes stuff that we only do once the entire chain is loaded.
-
- if (!DisableValidation) {
- switch(validateFileEntries()) {
- case Failure: return Failure;
- case IgnorePCH: return IgnorePCH;
- case Success: break;
- }
- }
-
- // Allocate space for loaded slocentries, identifiers, decls and types.
- unsigned TotalNumIdentifiers = 0, TotalNumTypes = 0, TotalNumDecls = 0,
- TotalNumPreallocatedPreprocessingEntities = 0, TotalNumMacroDefs = 0,
- TotalNumSelectors = 0;
- for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- TotalNumSLocEntries += Chain[I]->LocalNumSLocEntries;
- NextSLocOffset += Chain[I]->LocalSLocSize;
- TotalNumIdentifiers += Chain[I]->LocalNumIdentifiers;
- TotalNumTypes += Chain[I]->LocalNumTypes;
- TotalNumDecls += Chain[I]->LocalNumDecls;
- TotalNumPreallocatedPreprocessingEntities +=
- Chain[I]->NumPreallocatedPreprocessingEntities;
- TotalNumMacroDefs += Chain[I]->LocalNumMacroDefinitions;
- TotalNumSelectors += Chain[I]->LocalNumSelectors;
- }
- SourceMgr.PreallocateSLocEntries(this, TotalNumSLocEntries, NextSLocOffset);
- IdentifiersLoaded.resize(TotalNumIdentifiers);
- TypesLoaded.resize(TotalNumTypes);
- DeclsLoaded.resize(TotalNumDecls);
- MacroDefinitionsLoaded.resize(TotalNumMacroDefs);
- if (PP) {
- if (TotalNumIdentifiers > 0)
- PP->getHeaderSearchInfo().SetExternalLookup(this);
- if (TotalNumPreallocatedPreprocessingEntities > 0) {
- if (!PP->getPreprocessingRecord())
- PP->createPreprocessingRecord(true);
- PP->getPreprocessingRecord()->SetExternalSource(*this,
- TotalNumPreallocatedPreprocessingEntities);
- }
- }
- SelectorsLoaded.resize(TotalNumSelectors);
- // Preload SLocEntries.
- for (unsigned I = 0, N = PreloadSLocEntries.size(); I != N; ++I) {
- ASTReadResult Result = ReadSLocEntryRecord(PreloadSLocEntries[I]);
- if (Result != Success)
- return Result;
- }
-
+
// Check the predefines buffers.
- if (!DisableValidation && CheckPredefinesBuffers())
+ if (!DisableValidation && Type != MK_Module && Type != MK_Preamble &&
+ // FIXME: CheckPredefinesBuffers also sets the SuggestedPredefines;
+ // if DisableValidation is true, defines that were set on command-line
+ // but not in the PCH file will not be added to SuggestedPredefines.
+ CheckPredefinesBuffers())
return IgnorePCH;
- if (PP) {
- // Initialization of keywords and pragmas occurs before the
- // AST file is read, so there may be some identifiers that were
- // loaded into the IdentifierTable before we intercepted the
- // creation of identifiers. Iterate through the list of known
- // identifiers and determine whether we have to establish
- // preprocessor definitions or top-level identifier declaration
- // chains for those identifiers.
- //
- // We copy the IdentifierInfo pointers to a small vector first,
- // since de-serializing declarations or macro definitions can add
- // new entries into the identifier table, invalidating the
- // iterators.
- llvm::SmallVector<IdentifierInfo *, 128> Identifiers;
- for (IdentifierTable::iterator Id = PP->getIdentifierTable().begin(),
- IdEnd = PP->getIdentifierTable().end();
- Id != IdEnd; ++Id)
- Identifiers.push_back(Id->second);
- // We need to search the tables in all files.
- for (unsigned J = 0, M = Chain.size(); J != M; ++J) {
- ASTIdentifierLookupTable *IdTable
- = (ASTIdentifierLookupTable *)Chain[J]->IdentifierLookupTable;
- // Not all AST files necessarily have identifier tables, only the useful
- // ones.
- if (!IdTable)
- continue;
- for (unsigned I = 0, N = Identifiers.size(); I != N; ++I) {
- IdentifierInfo *II = Identifiers[I];
- // Look in the on-disk hash tables for an entry for this identifier
- ASTIdentifierLookupTrait Info(*this, *Chain[J], II);
- std::pair<const char*,unsigned> Key(II->getNameStart(),II->getLength());
- ASTIdentifierLookupTable::iterator Pos = IdTable->find(Key, &Info);
- if (Pos == IdTable->end())
- continue;
-
- // Dereferencing the iterator has the effect of populating the
- // IdentifierInfo node with the various declarations it needs.
- (void)*Pos;
- }
- }
+ // Initialization of keywords and pragmas occurs before the
+ // AST file is read, so there may be some identifiers that were
+ // loaded into the IdentifierTable before we intercepted the
+ // creation of identifiers. Iterate through the list of known
+ // identifiers and determine whether we have to establish
+ // preprocessor definitions or top-level identifier declaration
+ // chains for those identifiers.
+ //
+ // We copy the IdentifierInfo pointers to a small vector first,
+ // since de-serializing declarations or macro definitions can add
+ // new entries into the identifier table, invalidating the
+ // iterators.
+ //
+ // FIXME: We need a lazier way to load this information, e.g., by marking
+ // the identifier data as 'dirty', so that it will be looked up in the
+ // AST file(s) if it is uttered in the source. This could save us some
+ // module load time.
+ SmallVector<IdentifierInfo *, 128> Identifiers;
+ for (IdentifierTable::iterator Id = PP.getIdentifierTable().begin(),
+ IdEnd = PP.getIdentifierTable().end();
+ Id != IdEnd; ++Id)
+ Identifiers.push_back(Id->second);
+
+ for (unsigned I = 0, N = Identifiers.size(); I != N; ++I) {
+ IdentifierLookupVisitor Visitor(Identifiers[I]->getName());
+ ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor);
}
- if (Context)
- InitializeContext(*Context);
+ InitializeContext();
if (DeserializationListener)
DeserializationListener->ReaderInitialized(this);
- // If this AST file is a precompiled preamble, then set the main file ID of
- // the source manager to the file source file from which the preamble was
- // built. This is the only valid way to use a precompiled preamble.
- if (Type == Preamble) {
- if (OriginalFileID.isInvalid()) {
- SourceLocation Loc
- = SourceMgr.getLocation(FileMgr.getFile(getOriginalSourceFile()), 1, 1);
- if (Loc.isValid())
- OriginalFileID = SourceMgr.getDecomposedLoc(Loc).first;
+ // If this AST file is a precompiled preamble, then set the preamble file ID
+ // of the source manager to the file source file from which the preamble was
+ // built.
+ if (Type == MK_Preamble) {
+ if (!OriginalFileID.isInvalid()) {
+ OriginalFileID = FileID::get(ModuleMgr.getPrimaryModule().SLocEntryBaseID
+ + OriginalFileID.getOpaqueValue() - 1);
+ SourceMgr.setPreambleFileID(OriginalFileID);
}
-
- if (!OriginalFileID.isInvalid())
- SourceMgr.SetPreambleFileID(OriginalFileID);
}
return Success;
}
-ASTReader::ASTReadResult ASTReader::ReadASTCore(llvm::StringRef FileName,
- ASTFileType Type) {
- PerFileData *Prev = Chain.empty() ? 0 : Chain.back();
- Chain.push_back(new PerFileData(Type));
- PerFileData &F = *Chain.back();
- if (Prev)
- Prev->NextInSource = &F;
- else
- FirstInSource = &F;
- F.Loaders.push_back(Prev);
+ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName,
+ ModuleKind Type,
+ Module *ImportedBy) {
+ Module *M;
+ bool NewModule;
+ std::string ErrorStr;
+ llvm::tie(M, NewModule) = ModuleMgr.addModule(FileName, Type, ImportedBy,
+ ErrorStr);
+
+ if (!M) {
+ // We couldn't load the module.
+ std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
+ + ErrorStr;
+ Error(Msg);
+ return Failure;
+ }
- // Set the AST file name.
- F.FileName = FileName;
+ if (!NewModule) {
+ // We've already loaded this module.
+ return Success;
+ }
+ // FIXME: This seems rather a hack. Should CurrentDir be part of the
+ // module?
if (FileName != "-") {
CurrentDir = llvm::sys::path::parent_path(FileName);
if (CurrentDir.empty()) CurrentDir = ".";
}
- if (!ASTBuffers.empty()) {
- F.Buffer.reset(ASTBuffers.back());
- ASTBuffers.pop_back();
- assert(F.Buffer && "Passed null buffer");
- } else {
- // Open the AST file.
- //
- // FIXME: This shouldn't be here, we should just take a raw_ostream.
- std::string ErrStr;
- llvm::error_code ec;
- if (FileName == "-") {
- ec = llvm::MemoryBuffer::getSTDIN(F.Buffer);
- if (ec)
- ErrStr = ec.message();
- } else
- F.Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrStr));
- if (!F.Buffer) {
- Error(ErrStr.c_str());
- return IgnorePCH;
- }
- }
-
- // Initialize the stream
- F.StreamFile.init((const unsigned char *)F.Buffer->getBufferStart(),
- (const unsigned char *)F.Buffer->getBufferEnd());
+ Module &F = *M;
llvm::BitstreamCursor &Stream = F.Stream;
Stream.init(F.StreamFile);
F.SizeInBits = F.Buffer->getBufferSize() * 8;
-
+
// Sniff for the signature.
if (Stream.Read(8) != 'C' ||
Stream.Read(8) != 'P' ||
@@ -2668,9 +2503,8 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(llvm::StringRef FileName,
// AST block, skipping subblocks, to see if there are other
// AST blocks elsewhere.
- // Clear out any preallocated source location entries, so that
- // the source manager does not try to resolve them later.
- SourceMgr.ClearPreallocatedSLocEntries();
+ // FIXME: We can't clear loaded slocentries anymore.
+ //SourceMgr.ClearPreallocatedSLocEntries();
// Remove the stat cache.
if (F.StatCache)
@@ -2687,143 +2521,152 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(llvm::StringRef FileName,
break;
}
}
+
+ // Once read, set the Module bit base offset and update the size in
+ // bits of all files we've seen.
+ F.GlobalBitOffset = TotalModulesSizeInBits;
+ TotalModulesSizeInBits += F.SizeInBits;
+ GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F));
- return Success;
-}
+ // Make sure that the files this module was built against are still available.
+ if (!DisableValidation) {
+ switch(validateFileEntries(*M)) {
+ case Failure: return Failure;
+ case IgnorePCH: return IgnorePCH;
+ case Success: break;
+ }
+ }
+
+ // Preload SLocEntries.
+ for (unsigned I = 0, N = M->PreloadSLocEntries.size(); I != N; ++I) {
+ int Index = int(M->PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID;
+ // Load it through the SourceManager and don't call ReadSLocEntryRecord()
+ // directly because the entry may have already been loaded in which case
+ // calling ReadSLocEntryRecord() directly would trigger an assertion in
+ // SourceManager.
+ SourceMgr.getLoadedSLocEntryByID(Index);
+ }
-void ASTReader::setPreprocessor(Preprocessor &pp) {
- PP = &pp;
- unsigned TotalNum = 0;
- for (unsigned I = 0, N = Chain.size(); I != N; ++I)
- TotalNum += Chain[I]->NumPreallocatedPreprocessingEntities;
- if (TotalNum) {
- if (!PP->getPreprocessingRecord())
- PP->createPreprocessingRecord(true);
- PP->getPreprocessingRecord()->SetExternalSource(*this, TotalNum);
- }
+ return Success;
}
-void ASTReader::InitializeContext(ASTContext &Ctx) {
- Context = &Ctx;
- assert(Context && "Passed null context!");
+void ASTReader::InitializeContext() {
+ // If there's a listener, notify them that we "read" the translation unit.
+ if (DeserializationListener)
+ DeserializationListener->DeclRead(PREDEF_DECL_TRANSLATION_UNIT_ID,
+ Context.getTranslationUnitDecl());
- assert(PP && "Forgot to set Preprocessor ?");
- PP->getIdentifierTable().setExternalIdentifierLookup(this);
- PP->getHeaderSearchInfo().SetExternalLookup(this);
- PP->setExternalSource(this);
- PP->getHeaderSearchInfo().SetExternalSource(this);
+ // Make sure we load the declaration update records for the translation unit,
+ // if there are any.
+ loadDeclUpdateRecords(PREDEF_DECL_TRANSLATION_UNIT_ID,
+ Context.getTranslationUnitDecl());
+
+ // FIXME: Find a better way to deal with collisions between these
+ // built-in types. Right now, we just ignore the problem.
- // If we have an update block for the TU waiting, we have to add it before
- // deserializing the decl.
- DeclContextOffsetsMap::iterator DCU = DeclContextOffsets.find(0);
- if (DCU != DeclContextOffsets.end()) {
- // Insertion could invalidate map, so grab vector.
- DeclContextInfos T;
- T.swap(DCU->second);
- DeclContextOffsets.erase(DCU);
- DeclContextOffsets[Ctx.getTranslationUnitDecl()].swap(T);
- }
-
- // Load the translation unit declaration
- GetTranslationUnitDecl();
-
// Load the special types.
- Context->setBuiltinVaListType(
- GetType(SpecialTypes[SPECIAL_TYPE_BUILTIN_VA_LIST]));
- if (unsigned Id = SpecialTypes[SPECIAL_TYPE_OBJC_ID])
- Context->setObjCIdType(GetType(Id));
- if (unsigned Sel = SpecialTypes[SPECIAL_TYPE_OBJC_SELECTOR])
- Context->setObjCSelType(GetType(Sel));
- if (unsigned Proto = SpecialTypes[SPECIAL_TYPE_OBJC_PROTOCOL])
- Context->setObjCProtoType(GetType(Proto));
- if (unsigned Class = SpecialTypes[SPECIAL_TYPE_OBJC_CLASS])
- Context->setObjCClassType(GetType(Class));
-
- if (unsigned String = SpecialTypes[SPECIAL_TYPE_CF_CONSTANT_STRING])
- Context->setCFConstantStringType(GetType(String));
- if (unsigned FastEnum
- = SpecialTypes[SPECIAL_TYPE_OBJC_FAST_ENUMERATION_STATE])
- Context->setObjCFastEnumerationStateType(GetType(FastEnum));
- if (unsigned File = SpecialTypes[SPECIAL_TYPE_FILE]) {
- QualType FileType = GetType(File);
- if (FileType.isNull()) {
- Error("FILE type is NULL");
- return;
+ if (SpecialTypes.size() > NumSpecialTypeIDs) {
+ if (Context.getBuiltinVaListType().isNull()) {
+ Context.setBuiltinVaListType(
+ GetType(SpecialTypes[SPECIAL_TYPE_BUILTIN_VA_LIST]));
}
- if (const TypedefType *Typedef = FileType->getAs<TypedefType>())
- Context->setFILEDecl(Typedef->getDecl());
- else {
- const TagType *Tag = FileType->getAs<TagType>();
- if (!Tag) {
- Error("Invalid FILE type in AST file");
+
+ if (unsigned Proto = SpecialTypes[SPECIAL_TYPE_OBJC_PROTOCOL]) {
+ if (Context.ObjCProtoType.isNull())
+ Context.ObjCProtoType = GetType(Proto);
+ }
+
+ if (unsigned String = SpecialTypes[SPECIAL_TYPE_CF_CONSTANT_STRING]) {
+ if (!Context.CFConstantStringTypeDecl)
+ Context.setCFConstantStringType(GetType(String));
+ }
+
+ if (unsigned File = SpecialTypes[SPECIAL_TYPE_FILE]) {
+ QualType FileType = GetType(File);
+ if (FileType.isNull()) {
+ Error("FILE type is NULL");
return;
}
- Context->setFILEDecl(Tag->getDecl());
+
+ if (!Context.FILEDecl) {
+ if (const TypedefType *Typedef = FileType->getAs<TypedefType>())
+ Context.setFILEDecl(Typedef->getDecl());
+ else {
+ const TagType *Tag = FileType->getAs<TagType>();
+ if (!Tag) {
+ Error("Invalid FILE type in AST file");
+ return;
+ }
+ Context.setFILEDecl(Tag->getDecl());
+ }
+ }
}
- }
- if (unsigned Jmp_buf = SpecialTypes[SPECIAL_TYPE_jmp_buf]) {
- QualType Jmp_bufType = GetType(Jmp_buf);
- if (Jmp_bufType.isNull()) {
- Error("jmp_bug type is NULL");
- return;
+
+ if (unsigned Jmp_buf = SpecialTypes[SPECIAL_TYPE_jmp_buf]) {
+ QualType Jmp_bufType = GetType(Jmp_buf);
+ if (Jmp_bufType.isNull()) {
+ Error("jmp_buf type is NULL");
+ return;
+ }
+
+ if (!Context.jmp_bufDecl) {
+ if (const TypedefType *Typedef = Jmp_bufType->getAs<TypedefType>())
+ Context.setjmp_bufDecl(Typedef->getDecl());
+ else {
+ const TagType *Tag = Jmp_bufType->getAs<TagType>();
+ if (!Tag) {
+ Error("Invalid jmp_buf type in AST file");
+ return;
+ }
+ Context.setjmp_bufDecl(Tag->getDecl());
+ }
+ }
}
- if (const TypedefType *Typedef = Jmp_bufType->getAs<TypedefType>())
- Context->setjmp_bufDecl(Typedef->getDecl());
- else {
- const TagType *Tag = Jmp_bufType->getAs<TagType>();
- if (!Tag) {
- Error("Invalid jmp_buf type in AST file");
+
+ if (unsigned Sigjmp_buf = SpecialTypes[SPECIAL_TYPE_sigjmp_buf]) {
+ QualType Sigjmp_bufType = GetType(Sigjmp_buf);
+ if (Sigjmp_bufType.isNull()) {
+ Error("sigjmp_buf type is NULL");
return;
}
- Context->setjmp_bufDecl(Tag->getDecl());
+
+ if (!Context.sigjmp_bufDecl) {
+ if (const TypedefType *Typedef = Sigjmp_bufType->getAs<TypedefType>())
+ Context.setsigjmp_bufDecl(Typedef->getDecl());
+ else {
+ const TagType *Tag = Sigjmp_bufType->getAs<TagType>();
+ assert(Tag && "Invalid sigjmp_buf type in AST file");
+ Context.setsigjmp_bufDecl(Tag->getDecl());
+ }
+ }
}
- }
- if (unsigned Sigjmp_buf = SpecialTypes[SPECIAL_TYPE_sigjmp_buf]) {
- QualType Sigjmp_bufType = GetType(Sigjmp_buf);
- if (Sigjmp_bufType.isNull()) {
- Error("sigjmp_buf type is NULL");
- return;
+
+ if (unsigned ObjCIdRedef
+ = SpecialTypes[SPECIAL_TYPE_OBJC_ID_REDEFINITION]) {
+ if (Context.ObjCIdRedefinitionType.isNull())
+ Context.ObjCIdRedefinitionType = GetType(ObjCIdRedef);
}
- if (const TypedefType *Typedef = Sigjmp_bufType->getAs<TypedefType>())
- Context->setsigjmp_bufDecl(Typedef->getDecl());
- else {
- const TagType *Tag = Sigjmp_bufType->getAs<TagType>();
- assert(Tag && "Invalid sigjmp_buf type in AST file");
- Context->setsigjmp_bufDecl(Tag->getDecl());
+
+ if (unsigned ObjCClassRedef
+ = SpecialTypes[SPECIAL_TYPE_OBJC_CLASS_REDEFINITION]) {
+ if (Context.ObjCClassRedefinitionType.isNull())
+ Context.ObjCClassRedefinitionType = GetType(ObjCClassRedef);
+ }
+
+ if (unsigned ObjCSelRedef
+ = SpecialTypes[SPECIAL_TYPE_OBJC_SEL_REDEFINITION]) {
+ if (Context.ObjCSelRedefinitionType.isNull())
+ Context.ObjCSelRedefinitionType = GetType(ObjCSelRedef);
}
}
- if (unsigned ObjCIdRedef
- = SpecialTypes[SPECIAL_TYPE_OBJC_ID_REDEFINITION])
- Context->ObjCIdRedefinitionType = GetType(ObjCIdRedef);
- if (unsigned ObjCClassRedef
- = SpecialTypes[SPECIAL_TYPE_OBJC_CLASS_REDEFINITION])
- Context->ObjCClassRedefinitionType = GetType(ObjCClassRedef);
- if (unsigned String = SpecialTypes[SPECIAL_TYPE_BLOCK_DESCRIPTOR])
- Context->setBlockDescriptorType(GetType(String));
- if (unsigned String
- = SpecialTypes[SPECIAL_TYPE_BLOCK_EXTENDED_DESCRIPTOR])
- Context->setBlockDescriptorExtendedType(GetType(String));
- if (unsigned ObjCSelRedef
- = SpecialTypes[SPECIAL_TYPE_OBJC_SEL_REDEFINITION])
- Context->ObjCSelRedefinitionType = GetType(ObjCSelRedef);
- if (unsigned String = SpecialTypes[SPECIAL_TYPE_NS_CONSTANT_STRING])
- Context->setNSConstantStringType(GetType(String));
-
- if (SpecialTypes[SPECIAL_TYPE_INT128_INSTALLED])
- Context->setInt128Installed();
-
- if (unsigned AutoDeduct = SpecialTypes[SPECIAL_TYPE_AUTO_DEDUCT])
- Context->AutoDeductTy = GetType(AutoDeduct);
- if (unsigned AutoRRefDeduct = SpecialTypes[SPECIAL_TYPE_AUTO_RREF_DEDUCT])
- Context->AutoRRefDeductTy = GetType(AutoRRefDeduct);
-
- ReadPragmaDiagnosticMappings(Context->getDiagnostics());
+
+ ReadPragmaDiagnosticMappings(Context.getDiagnostics());
// If there were any CUDA special declarations, deserialize them.
if (!CUDASpecialDeclRefs.empty()) {
assert(CUDASpecialDeclRefs.size() == 1 && "More decl refs than expected!");
- Context->setcudaConfigureCallDecl(
+ Context.setcudaConfigureCallDecl(
cast<FunctionDecl>(GetDecl(CUDASpecialDeclRefs[0])));
}
}
@@ -2833,7 +2676,7 @@ void ASTReader::InitializeContext(ASTContext &Ctx) {
/// file.
std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
FileManager &FileMgr,
- Diagnostic &Diags) {
+ DiagnosticsEngine &Diags) {
// Open the AST file.
std::string ErrStr;
llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
@@ -2917,181 +2760,349 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
///
/// \returns true if the listener deems the file unacceptable, false otherwise.
bool ASTReader::ParseLanguageOptions(
- const llvm::SmallVectorImpl<uint64_t> &Record) {
+ const SmallVectorImpl<uint64_t> &Record) {
if (Listener) {
LangOptions LangOpts;
-
- #define PARSE_LANGOPT(Option) \
- LangOpts.Option = Record[Idx]; \
- ++Idx
-
unsigned Idx = 0;
- PARSE_LANGOPT(Trigraphs);
- PARSE_LANGOPT(BCPLComment);
- PARSE_LANGOPT(DollarIdents);
- PARSE_LANGOPT(AsmPreprocessor);
- PARSE_LANGOPT(GNUMode);
- PARSE_LANGOPT(GNUKeywords);
- PARSE_LANGOPT(ImplicitInt);
- PARSE_LANGOPT(Digraphs);
- PARSE_LANGOPT(HexFloats);
- PARSE_LANGOPT(C99);
- PARSE_LANGOPT(C1X);
- PARSE_LANGOPT(Microsoft);
- PARSE_LANGOPT(CPlusPlus);
- PARSE_LANGOPT(CPlusPlus0x);
- PARSE_LANGOPT(CXXOperatorNames);
- PARSE_LANGOPT(ObjC1);
- PARSE_LANGOPT(ObjC2);
- PARSE_LANGOPT(ObjCNonFragileABI);
- PARSE_LANGOPT(ObjCNonFragileABI2);
- PARSE_LANGOPT(AppleKext);
- PARSE_LANGOPT(ObjCDefaultSynthProperties);
- PARSE_LANGOPT(ObjCInferRelatedResultType);
- PARSE_LANGOPT(NoConstantCFStrings);
- PARSE_LANGOPT(PascalStrings);
- PARSE_LANGOPT(WritableStrings);
- PARSE_LANGOPT(LaxVectorConversions);
- PARSE_LANGOPT(AltiVec);
- PARSE_LANGOPT(Exceptions);
- PARSE_LANGOPT(ObjCExceptions);
- PARSE_LANGOPT(CXXExceptions);
- PARSE_LANGOPT(SjLjExceptions);
- PARSE_LANGOPT(MSBitfields);
- PARSE_LANGOPT(NeXTRuntime);
- PARSE_LANGOPT(Freestanding);
- PARSE_LANGOPT(NoBuiltin);
- PARSE_LANGOPT(ThreadsafeStatics);
- PARSE_LANGOPT(POSIXThreads);
- PARSE_LANGOPT(Blocks);
- PARSE_LANGOPT(EmitAllDecls);
- PARSE_LANGOPT(MathErrno);
- LangOpts.setSignedOverflowBehavior((LangOptions::SignedOverflowBehaviorTy)
- Record[Idx++]);
- PARSE_LANGOPT(HeinousExtensions);
- PARSE_LANGOPT(Optimize);
- PARSE_LANGOPT(OptimizeSize);
- PARSE_LANGOPT(Static);
- PARSE_LANGOPT(PICLevel);
- PARSE_LANGOPT(GNUInline);
- PARSE_LANGOPT(NoInline);
- PARSE_LANGOPT(Deprecated);
- PARSE_LANGOPT(AccessControl);
- PARSE_LANGOPT(CharIsSigned);
- PARSE_LANGOPT(ShortWChar);
- PARSE_LANGOPT(ShortEnums);
- LangOpts.setGCMode((LangOptions::GCMode)Record[Idx++]);
- LangOpts.setVisibilityMode((Visibility)Record[Idx++]);
- LangOpts.setStackProtectorMode((LangOptions::StackProtectorMode)
- Record[Idx++]);
- PARSE_LANGOPT(InstantiationDepth);
- PARSE_LANGOPT(OpenCL);
- PARSE_LANGOPT(CUDA);
- PARSE_LANGOPT(CatchUndefined);
- PARSE_LANGOPT(DefaultFPContract);
- PARSE_LANGOPT(ElideConstructors);
- PARSE_LANGOPT(SpellChecking);
- PARSE_LANGOPT(MRTD);
- PARSE_LANGOPT(ObjCAutoRefCount);
- #undef PARSE_LANGOPT
-
+#define LANGOPT(Name, Bits, Default, Description) \
+ LangOpts.Name = Record[Idx++];
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ LangOpts.set##Name(static_cast<LangOptions::Type>(Record[Idx++]));
+#include "clang/Basic/LangOptions.def"
+
return Listener->ReadLanguageOptions(LangOpts);
}
return false;
}
-void ASTReader::ReadPreprocessedEntities() {
- for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- PerFileData &F = *Chain[I];
- if (!F.PreprocessorDetailCursor.getBitStreamReader())
- continue;
+PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
+ PreprocessedEntityID PPID = Index+1;
+ GlobalPreprocessedEntityMapType::iterator
+ I = GlobalPreprocessedEntityMap.find(Index);
+ assert(I != GlobalPreprocessedEntityMap.end() &&
+ "Corrupted global preprocessed entity map");
+ Module &M = *I->second;
+ unsigned LocalIndex = Index - M.BasePreprocessedEntityID;
+ const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex];
- SavedStreamPosition SavedPosition(F.PreprocessorDetailCursor);
- F.PreprocessorDetailCursor.JumpToBit(F.PreprocessorDetailStartOffset);
- while (LoadPreprocessedEntity(F)) { }
+ 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;
}
-}
-PreprocessedEntity *ASTReader::ReadPreprocessedEntityAtOffset(uint64_t Offset) {
- PerFileData *F = 0;
- for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- if (Offset < Chain[I]->SizeInBits) {
- F = Chain[I];
- break;
+ if (!PP.getPreprocessingRecord()) {
+ Error("no preprocessing 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;
+ RecordData Record;
+ PreprocessorDetailRecordTypes RecType =
+ (PreprocessorDetailRecordTypes)M.PreprocessorDetailCursor.ReadRecord(
+ Code, Record, BlobStart, BlobLen);
+ switch (RecType) {
+ case PPD_MACRO_EXPANSION: {
+ bool isBuiltin = Record[0];
+ IdentifierInfo *Name = 0;
+ MacroDefinition *Def = 0;
+ if (isBuiltin)
+ Name = getLocalIdentifier(M, Record[1]);
+ else {
+ PreprocessedEntityID
+ GlobalID = getGlobalPreprocessedEntityID(M, Record[1]);
+ Def =cast<MacroDefinition>(PPRec.getLoadedPreprocessedEntity(GlobalID-1));
}
+
+ MacroExpansion *ME;
+ if (isBuiltin)
+ ME = new (PPRec) MacroExpansion(Name, Range);
+ else
+ ME = new (PPRec) MacroExpansion(Def, Range);
+
+ return ME;
+ }
+
+ case PPD_MACRO_DEFINITION: {
+ // Decode the identifier info and then check again; if the macro is
+ // still defined and associated with the identifier,
+ IdentifierInfo *II = getLocalIdentifier(M, Record[0]);
+ MacroDefinition *MD
+ = new (PPRec) MacroDefinition(II, Range);
+
+ if (DeserializationListener)
+ DeserializationListener->MacroDefinitionRead(PPID, MD);
+
+ return MD;
+ }
+
+ case PPD_INCLUSION_DIRECTIVE: {
+ const char *FullFileNameStart = BlobStart + Record[0];
+ const FileEntry *File
+ = PP.getFileManager().getFile(StringRef(FullFileNameStart,
+ BlobLen - Record[0]));
- Offset -= Chain[I]->SizeInBits;
+ // FIXME: Stable encoding
+ InclusionDirective::InclusionKind Kind
+ = static_cast<InclusionDirective::InclusionKind>(Record[2]);
+ InclusionDirective *ID
+ = new (PPRec) InclusionDirective(PPRec, Kind,
+ StringRef(BlobStart, Record[0]),
+ Record[1],
+ File,
+ Range);
+ return ID;
+ }
}
- if (!F) {
- Error("Malformed preprocessed entity offset");
- return 0;
+ Error("invalid offset in preprocessor detail block");
+ return 0;
+}
+
+/// \brief \arg SLocMapI points at a chunk of a module that contains no
+/// preprocessed entities or the entities it contains are not the ones we are
+/// looking for. Find the next module that contains entities and return the ID
+/// of the first entry.
+PreprocessedEntityID ASTReader::findNextPreprocessedEntity(
+ GlobalSLocOffsetMapType::const_iterator SLocMapI) const {
+ ++SLocMapI;
+ for (GlobalSLocOffsetMapType::const_iterator
+ EndI = GlobalSLocOffsetMap.end(); SLocMapI != EndI; ++SLocMapI) {
+ Module &M = *SLocMapI->second;
+ if (M.NumPreprocessedEntities)
+ return getGlobalPreprocessedEntityID(M, M.BasePreprocessedEntityID);
}
- // Keep track of where we are in the stream, then jump back there
- // after reading this entity.
- SavedStreamPosition SavedPosition(F->PreprocessorDetailCursor);
- F->PreprocessorDetailCursor.JumpToBit(Offset);
- return LoadPreprocessedEntity(*F);
+ return getTotalNumPreprocessedEntities();
}
-HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) {
- HeaderFileInfoTrait Trait(FE->getName());
- for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- PerFileData &F = *Chain[I];
- HeaderFileInfoLookupTable *Table
- = static_cast<HeaderFileInfoLookupTable *>(F.HeaderFileInfoTable);
- if (!Table)
- continue;
+namespace {
+
+template <unsigned PPEntityOffset::*PPLoc>
+struct PPEntityComp {
+ const ASTReader &Reader;
+ Module &M;
+
+ PPEntityComp(const ASTReader &Reader, Module &M) : Reader(Reader), M(M) { }
+
+ bool operator()(const PPEntityOffset &L, const PPEntityOffset &R) const {
+ SourceLocation LHS = getLoc(L);
+ SourceLocation RHS = getLoc(R);
+ return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ bool operator()(const PPEntityOffset &L, SourceLocation RHS) const {
+ SourceLocation LHS = getLoc(L);
+ return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ bool operator()(SourceLocation LHS, const PPEntityOffset &R) const {
+ SourceLocation RHS = getLoc(R);
+ return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ SourceLocation getLoc(const PPEntityOffset &PPE) const {
+ return Reader.ReadSourceLocation(M, PPE.*PPLoc);
+ }
+};
+
+}
+
+/// \brief Returns the first preprocessed entity ID that ends after \arg BLoc.
+PreprocessedEntityID
+ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const {
+ if (SourceMgr.isLocalSourceLocation(BLoc))
+ return getTotalNumPreprocessedEntities();
+
+ GlobalSLocOffsetMapType::const_iterator
+ SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset -
+ BLoc.getOffset());
+ assert(SLocMapI != GlobalSLocOffsetMap.end() &&
+ "Corrupted global sloc offset map");
+
+ if (SLocMapI->second->NumPreprocessedEntities == 0)
+ return findNextPreprocessedEntity(SLocMapI);
+
+ Module &M = *SLocMapI->second;
+ typedef const PPEntityOffset *pp_iterator;
+ pp_iterator pp_begin = M.PreprocessedEntityOffsets;
+ pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities;
+
+ size_t Count = M.NumPreprocessedEntities;
+ size_t Half;
+ pp_iterator First = pp_begin;
+ pp_iterator PPI;
+
+ // Do a binary search manually instead of using std::lower_bound because
+ // The end locations of entities may be unordered (when a macro expansion
+ // is inside another macro argument), but for this case it is not important
+ // whether we get the first macro expansion or its containing macro.
+ while (Count > 0) {
+ Half = Count/2;
+ PPI = First;
+ std::advance(PPI, Half);
+ if (SourceMgr.isBeforeInTranslationUnit(ReadSourceLocation(M, PPI->End),
+ BLoc)){
+ First = PPI;
+ ++First;
+ Count = Count - Half - 1;
+ } else
+ Count = Half;
+ }
+
+ if (PPI == pp_end)
+ return findNextPreprocessedEntity(SLocMapI);
+
+ return getGlobalPreprocessedEntityID(M,
+ M.BasePreprocessedEntityID + (PPI - pp_begin));
+}
+
+/// \brief Returns the first preprocessed entity ID that begins after \arg ELoc.
+PreprocessedEntityID
+ASTReader::findEndPreprocessedEntity(SourceLocation ELoc) const {
+ if (SourceMgr.isLocalSourceLocation(ELoc))
+ return getTotalNumPreprocessedEntities();
+
+ GlobalSLocOffsetMapType::const_iterator
+ SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset -
+ ELoc.getOffset());
+ assert(SLocMapI != GlobalSLocOffsetMap.end() &&
+ "Corrupted global sloc offset map");
+
+ if (SLocMapI->second->NumPreprocessedEntities == 0)
+ return findNextPreprocessedEntity(SLocMapI);
+
+ Module &M = *SLocMapI->second;
+ typedef const PPEntityOffset *pp_iterator;
+ pp_iterator pp_begin = M.PreprocessedEntityOffsets;
+ pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities;
+ pp_iterator PPI =
+ std::upper_bound(pp_begin, pp_end, ELoc,
+ PPEntityComp<&PPEntityOffset::Begin>(*this, M));
+
+ if (PPI == pp_end)
+ return findNextPreprocessedEntity(SLocMapI);
+
+ return getGlobalPreprocessedEntityID(M,
+ M.BasePreprocessedEntityID + (PPI - pp_begin));
+}
+
+/// \brief Returns a pair of [Begin, End) indices of preallocated
+/// preprocessed entities that \arg Range encompasses.
+std::pair<unsigned, unsigned>
+ ASTReader::findPreprocessedEntitiesInRange(SourceRange Range) {
+ if (Range.isInvalid())
+ return std::make_pair(0,0);
+ assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin()));
+
+ PreprocessedEntityID BeginID = findBeginPreprocessedEntity(Range.getBegin());
+ PreprocessedEntityID EndID = findEndPreprocessedEntity(Range.getEnd());
+ return std::make_pair(BeginID, EndID);
+}
+
+namespace {
+ /// \brief Visitor used to search for information about a header file.
+ class HeaderFileInfoVisitor {
+ ASTReader &Reader;
+ const FileEntry *FE;
- // Look in the on-disk hash table for an entry for this file name.
- HeaderFileInfoLookupTable::iterator Pos = Table->find(FE->getName(),
- &Trait);
- if (Pos == Table->end())
- continue;
+ llvm::Optional<HeaderFileInfo> HFI;
+
+ public:
+ HeaderFileInfoVisitor(ASTReader &Reader, const FileEntry *FE)
+ : Reader(Reader), FE(FE) { }
+
+ static bool visit(Module &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;
- HeaderFileInfo HFI = *Pos;
- if (Listener)
- Listener->ReadHeaderFileInfo(HFI, FE->getUID());
+ // Look in the on-disk hash table for an entry for this file name.
+ HeaderFileInfoLookupTable::iterator Pos = Table->find(This->FE->getName(),
+ &Trait);
+ if (Pos == Table->end())
+ return false;
+
+ This->HFI = *Pos;
+ return true;
+ }
+
+ llvm::Optional<HeaderFileInfo> getHeaderFileInfo() const { return HFI; }
+ };
+}
- return HFI;
+HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) {
+ HeaderFileInfoVisitor Visitor(*this, FE);
+ ModuleMgr.visit(&HeaderFileInfoVisitor::visit, &Visitor);
+ if (llvm::Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo()) {
+ if (Listener)
+ Listener->ReadHeaderFileInfo(*HFI, FE->getUID());
+ return *HFI;
}
return HeaderFileInfo();
}
-void ASTReader::ReadPragmaDiagnosticMappings(Diagnostic &Diag) {
- unsigned Idx = 0;
- while (Idx < PragmaDiagMappings.size()) {
- SourceLocation
- Loc = SourceLocation::getFromRawEncoding(PragmaDiagMappings[Idx++]);
- while (1) {
- assert(Idx < PragmaDiagMappings.size() &&
- "Invalid data, didn't find '-1' marking end of diag/map pairs");
- if (Idx >= PragmaDiagMappings.size())
- break; // Something is messed up but at least avoid infinite loop in
- // release build.
- unsigned DiagID = PragmaDiagMappings[Idx++];
- if (DiagID == (unsigned)-1)
- break; // no more diag/map pairs for this location.
- diag::Mapping Map = (diag::Mapping)PragmaDiagMappings[Idx++];
- Diag.setDiagnosticMapping(DiagID, Map, Loc);
+void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
+ for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) {
+ Module &F = *(*I);
+ unsigned Idx = 0;
+ while (Idx < F.PragmaDiagMappings.size()) {
+ SourceLocation Loc = ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]);
+ while (1) {
+ assert(Idx < F.PragmaDiagMappings.size() &&
+ "Invalid data, didn't find '-1' marking end of diag/map pairs");
+ if (Idx >= F.PragmaDiagMappings.size()) {
+ break; // Something is messed up but at least avoid infinite loop in
+ // release build.
+ }
+ unsigned DiagID = F.PragmaDiagMappings[Idx++];
+ if (DiagID == (unsigned)-1) {
+ break; // no more diag/map pairs for this location.
+ }
+ diag::Mapping Map = (diag::Mapping)F.PragmaDiagMappings[Idx++];
+ // The user bit gets set by WritePragmaDiagnosticMappings.
+ Diag.setDiagnosticMapping(DiagID, Map, Loc);
+ }
}
}
}
/// \brief Get the correct cursor and offset for loading a type.
ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) {
- PerFileData *F = 0;
- for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- F = Chain[N - I - 1];
- if (Index < F->LocalNumTypes)
- break;
- Index -= F->LocalNumTypes;
- }
- assert(F && F->LocalNumTypes > Index && "Broken chain");
- return RecordLocation(F, F->TypeOffsets[Index]);
+ GlobalTypeMapType::iterator I = GlobalTypeMap.find(Index);
+ assert(I != GlobalTypeMap.end() && "Corrupted global type map");
+ Module *M = I->second;
+ return RecordLocation(M, M->TypeOffsets[Index - M->BaseTypeIndex]);
}
/// \brief Read and return the type with the given index..
@@ -3100,7 +3111,7 @@ ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) {
/// routine actually reads the record corresponding to the type at the given
/// location. It is a helper routine for GetType, which deals with reading type
/// IDs.
-QualType ASTReader::ReadTypeRecord(unsigned Index) {
+QualType ASTReader::readTypeRecord(unsigned Index) {
RecordLocation Loc = TypeCursorForIndex(Index);
llvm::BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor;
@@ -3113,6 +3124,7 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
// Note that we are loading a type record.
Deserializing AType(this);
+ unsigned Idx = 0;
DeclsCursor.JumpToBit(Loc.Offset);
RecordData Record;
unsigned Code = DeclsCursor.ReadCode();
@@ -3122,9 +3134,9 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
Error("Incorrect encoding of extended qualifier type");
return QualType();
}
- QualType Base = GetType(Record[0]);
- Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[1]);
- return Context->getQualifiedType(Base, Quals);
+ QualType Base = readType(*Loc.F, Record, Idx);
+ Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[Idx++]);
+ return Context.getQualifiedType(Base, Quals);
}
case TYPE_COMPLEX: {
@@ -3132,8 +3144,8 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
Error("Incorrect encoding of complex type");
return QualType();
}
- QualType ElemType = GetType(Record[0]);
- return Context->getComplexType(ElemType);
+ QualType ElemType = readType(*Loc.F, Record, Idx);
+ return Context.getComplexType(ElemType);
}
case TYPE_POINTER: {
@@ -3141,8 +3153,8 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
Error("Incorrect encoding of pointer type");
return QualType();
}
- QualType PointeeType = GetType(Record[0]);
- return Context->getPointerType(PointeeType);
+ QualType PointeeType = readType(*Loc.F, Record, Idx);
+ return Context.getPointerType(PointeeType);
}
case TYPE_BLOCK_POINTER: {
@@ -3150,8 +3162,8 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
Error("Incorrect encoding of block pointer type");
return QualType();
}
- QualType PointeeType = GetType(Record[0]);
- return Context->getBlockPointerType(PointeeType);
+ QualType PointeeType = readType(*Loc.F, Record, Idx);
+ return Context.getBlockPointerType(PointeeType);
}
case TYPE_LVALUE_REFERENCE: {
@@ -3159,8 +3171,8 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
Error("Incorrect encoding of lvalue reference type");
return QualType();
}
- QualType PointeeType = GetType(Record[0]);
- return Context->getLValueReferenceType(PointeeType, Record[1]);
+ QualType PointeeType = readType(*Loc.F, Record, Idx);
+ return Context.getLValueReferenceType(PointeeType, Record[1]);
}
case TYPE_RVALUE_REFERENCE: {
@@ -3168,8 +3180,8 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
Error("Incorrect encoding of rvalue reference type");
return QualType();
}
- QualType PointeeType = GetType(Record[0]);
- return Context->getRValueReferenceType(PointeeType);
+ QualType PointeeType = readType(*Loc.F, Record, Idx);
+ return Context.getRValueReferenceType(PointeeType);
}
case TYPE_MEMBER_POINTER: {
@@ -3177,38 +3189,38 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
Error("Incorrect encoding of member pointer type");
return QualType();
}
- QualType PointeeType = GetType(Record[0]);
- QualType ClassType = GetType(Record[1]);
+ QualType PointeeType = readType(*Loc.F, Record, Idx);
+ QualType ClassType = readType(*Loc.F, Record, Idx);
if (PointeeType.isNull() || ClassType.isNull())
return QualType();
- return Context->getMemberPointerType(PointeeType, ClassType.getTypePtr());
+ return Context.getMemberPointerType(PointeeType, ClassType.getTypePtr());
}
case TYPE_CONSTANT_ARRAY: {
- QualType ElementType = GetType(Record[0]);
+ QualType ElementType = readType(*Loc.F, Record, Idx);
ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
unsigned IndexTypeQuals = Record[2];
unsigned Idx = 3;
llvm::APInt Size = ReadAPInt(Record, Idx);
- return Context->getConstantArrayType(ElementType, Size,
+ return Context.getConstantArrayType(ElementType, Size,
ASM, IndexTypeQuals);
}
case TYPE_INCOMPLETE_ARRAY: {
- QualType ElementType = GetType(Record[0]);
+ QualType ElementType = readType(*Loc.F, Record, Idx);
ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
unsigned IndexTypeQuals = Record[2];
- return Context->getIncompleteArrayType(ElementType, ASM, IndexTypeQuals);
+ return Context.getIncompleteArrayType(ElementType, ASM, IndexTypeQuals);
}
case TYPE_VARIABLE_ARRAY: {
- QualType ElementType = GetType(Record[0]);
+ QualType ElementType = readType(*Loc.F, Record, Idx);
ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
unsigned IndexTypeQuals = Record[2];
SourceLocation LBLoc = ReadSourceLocation(*Loc.F, Record[3]);
SourceLocation RBLoc = ReadSourceLocation(*Loc.F, Record[4]);
- return Context->getVariableArrayType(ElementType, ReadExpr(*Loc.F),
+ return Context.getVariableArrayType(ElementType, ReadExpr(*Loc.F),
ASM, IndexTypeQuals,
SourceRange(LBLoc, RBLoc));
}
@@ -3219,10 +3231,10 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
return QualType();
}
- QualType ElementType = GetType(Record[0]);
+ QualType ElementType = readType(*Loc.F, Record, Idx);
unsigned NumElements = Record[1];
unsigned VecKind = Record[2];
- return Context->getVectorType(ElementType, NumElements,
+ return Context.getVectorType(ElementType, NumElements,
(VectorType::VectorKind)VecKind);
}
@@ -3232,9 +3244,9 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
return QualType();
}
- QualType ElementType = GetType(Record[0]);
+ QualType ElementType = readType(*Loc.F, Record, Idx);
unsigned NumElements = Record[1];
- return Context->getExtVectorType(ElementType, NumElements);
+ return Context.getExtVectorType(ElementType, NumElements);
}
case TYPE_FUNCTION_NO_PROTO: {
@@ -3242,14 +3254,14 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
Error("incorrect encoding of no-proto function type");
return QualType();
}
- QualType ResultType = GetType(Record[0]);
+ QualType ResultType = readType(*Loc.F, Record, Idx);
FunctionType::ExtInfo Info(Record[1], Record[2], Record[3],
(CallingConv)Record[4], Record[5]);
- return Context->getFunctionNoProtoType(ResultType, Info);
+ return Context.getFunctionNoProtoType(ResultType, Info);
}
case TYPE_FUNCTION_PROTO: {
- QualType ResultType = GetType(Record[0]);
+ QualType ResultType = readType(*Loc.F, Record, Idx);
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExtInfo = FunctionType::ExtInfo(/*noreturn*/ Record[1],
@@ -3260,9 +3272,9 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
unsigned Idx = 6;
unsigned NumParams = Record[Idx++];
- llvm::SmallVector<QualType, 16> ParamTypes;
+ SmallVector<QualType, 16> ParamTypes;
for (unsigned I = 0; I != NumParams; ++I)
- ParamTypes.push_back(GetType(Record[Idx++]));
+ ParamTypes.push_back(readType(*Loc.F, Record, Idx));
EPI.Variadic = Record[Idx++];
EPI.TypeQuals = Record[Idx++];
@@ -3272,65 +3284,70 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
EPI.ExceptionSpecType = EST;
if (EST == EST_Dynamic) {
EPI.NumExceptions = Record[Idx++];
- llvm::SmallVector<QualType, 2> Exceptions;
+ SmallVector<QualType, 2> Exceptions;
for (unsigned I = 0; I != EPI.NumExceptions; ++I)
- Exceptions.push_back(GetType(Record[Idx++]));
+ Exceptions.push_back(readType(*Loc.F, Record, Idx));
EPI.Exceptions = Exceptions.data();
} else if (EST == EST_ComputedNoexcept) {
EPI.NoexceptExpr = ReadExpr(*Loc.F);
}
- return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams,
+ return Context.getFunctionType(ResultType, ParamTypes.data(), NumParams,
EPI);
}
- case TYPE_UNRESOLVED_USING:
- return Context->getTypeDeclType(
- cast<UnresolvedUsingTypenameDecl>(GetDecl(Record[0])));
-
+ case TYPE_UNRESOLVED_USING: {
+ unsigned Idx = 0;
+ return Context.getTypeDeclType(
+ ReadDeclAs<UnresolvedUsingTypenameDecl>(*Loc.F, Record, Idx));
+ }
+
case TYPE_TYPEDEF: {
if (Record.size() != 2) {
Error("incorrect encoding of typedef type");
return QualType();
}
- TypedefNameDecl *Decl = cast<TypedefNameDecl>(GetDecl(Record[0]));
- QualType Canonical = GetType(Record[1]);
+ unsigned Idx = 0;
+ TypedefNameDecl *Decl = ReadDeclAs<TypedefNameDecl>(*Loc.F, Record, Idx);
+ QualType Canonical = readType(*Loc.F, Record, Idx);
if (!Canonical.isNull())
- Canonical = Context->getCanonicalType(Canonical);
- return Context->getTypedefType(Decl, Canonical);
+ Canonical = Context.getCanonicalType(Canonical);
+ return Context.getTypedefType(Decl, Canonical);
}
case TYPE_TYPEOF_EXPR:
- return Context->getTypeOfExprType(ReadExpr(*Loc.F));
+ return Context.getTypeOfExprType(ReadExpr(*Loc.F));
case TYPE_TYPEOF: {
if (Record.size() != 1) {
Error("incorrect encoding of typeof(type) in AST file");
return QualType();
}
- QualType UnderlyingType = GetType(Record[0]);
- return Context->getTypeOfType(UnderlyingType);
+ QualType UnderlyingType = readType(*Loc.F, Record, Idx);
+ return Context.getTypeOfType(UnderlyingType);
}
case TYPE_DECLTYPE:
- return Context->getDecltypeType(ReadExpr(*Loc.F));
+ return Context.getDecltypeType(ReadExpr(*Loc.F));
case TYPE_UNARY_TRANSFORM: {
- QualType BaseType = GetType(Record[0]);
- QualType UnderlyingType = GetType(Record[1]);
+ QualType BaseType = readType(*Loc.F, Record, Idx);
+ QualType UnderlyingType = readType(*Loc.F, Record, Idx);
UnaryTransformType::UTTKind UKind = (UnaryTransformType::UTTKind)Record[2];
- return Context->getUnaryTransformType(BaseType, UnderlyingType, UKind);
+ return Context.getUnaryTransformType(BaseType, UnderlyingType, UKind);
}
case TYPE_AUTO:
- return Context->getAutoType(GetType(Record[0]));
+ return Context.getAutoType(readType(*Loc.F, Record, Idx));
case TYPE_RECORD: {
if (Record.size() != 2) {
Error("incorrect encoding of record type");
return QualType();
}
- bool IsDependent = Record[0];
- QualType T = Context->getRecordType(cast<RecordDecl>(GetDecl(Record[1])));
+ unsigned Idx = 0;
+ bool IsDependent = Record[Idx++];
+ QualType T
+ = Context.getRecordType(ReadDeclAs<RecordDecl>(*Loc.F, Record, Idx));
const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
return T;
}
@@ -3340,8 +3357,10 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
Error("incorrect encoding of enum type");
return QualType();
}
- bool IsDependent = Record[0];
- QualType T = Context->getEnumType(cast<EnumDecl>(GetDecl(Record[1])));
+ unsigned Idx = 0;
+ bool IsDependent = Record[Idx++];
+ QualType T
+ = Context.getEnumType(ReadDeclAs<EnumDecl>(*Loc.F, Record, Idx));
const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
return T;
}
@@ -3351,10 +3370,10 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
Error("incorrect encoding of attributed type");
return QualType();
}
- QualType modifiedType = GetType(Record[0]);
- QualType equivalentType = GetType(Record[1]);
+ QualType modifiedType = readType(*Loc.F, Record, Idx);
+ QualType equivalentType = readType(*Loc.F, Record, Idx);
AttributedType::Kind kind = static_cast<AttributedType::Kind>(Record[2]);
- return Context->getAttributedType(kind, modifiedType, equivalentType);
+ return Context.getAttributedType(kind, modifiedType, equivalentType);
}
case TYPE_PAREN: {
@@ -3362,8 +3381,8 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
Error("incorrect encoding of paren type");
return QualType();
}
- QualType InnerType = GetType(Record[0]);
- return Context->getParenType(InnerType);
+ QualType InnerType = readType(*Loc.F, Record, Idx);
+ return Context.getParenType(InnerType);
}
case TYPE_PACK_EXPANSION: {
@@ -3371,70 +3390,71 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
Error("incorrect encoding of pack expansion type");
return QualType();
}
- QualType Pattern = GetType(Record[0]);
+ QualType Pattern = readType(*Loc.F, Record, Idx);
if (Pattern.isNull())
return QualType();
llvm::Optional<unsigned> NumExpansions;
if (Record[1])
NumExpansions = Record[1] - 1;
- return Context->getPackExpansionType(Pattern, NumExpansions);
+ return Context.getPackExpansionType(Pattern, NumExpansions);
}
case TYPE_ELABORATED: {
unsigned Idx = 0;
ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
- NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx);
- QualType NamedType = GetType(Record[Idx++]);
- return Context->getElaboratedType(Keyword, NNS, NamedType);
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
+ QualType NamedType = readType(*Loc.F, Record, Idx);
+ return Context.getElaboratedType(Keyword, NNS, NamedType);
}
case TYPE_OBJC_INTERFACE: {
unsigned Idx = 0;
- ObjCInterfaceDecl *ItfD = cast<ObjCInterfaceDecl>(GetDecl(Record[Idx++]));
- return Context->getObjCInterfaceType(ItfD);
+ ObjCInterfaceDecl *ItfD
+ = ReadDeclAs<ObjCInterfaceDecl>(*Loc.F, Record, Idx);
+ return Context.getObjCInterfaceType(ItfD);
}
case TYPE_OBJC_OBJECT: {
unsigned Idx = 0;
- QualType Base = GetType(Record[Idx++]);
+ QualType Base = readType(*Loc.F, Record, Idx);
unsigned NumProtos = Record[Idx++];
- llvm::SmallVector<ObjCProtocolDecl*, 4> Protos;
+ SmallVector<ObjCProtocolDecl*, 4> Protos;
for (unsigned I = 0; I != NumProtos; ++I)
- Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++])));
- return Context->getObjCObjectType(Base, Protos.data(), NumProtos);
+ Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx));
+ return Context.getObjCObjectType(Base, Protos.data(), NumProtos);
}
case TYPE_OBJC_OBJECT_POINTER: {
unsigned Idx = 0;
- QualType Pointee = GetType(Record[Idx++]);
- return Context->getObjCObjectPointerType(Pointee);
+ QualType Pointee = readType(*Loc.F, Record, Idx);
+ return Context.getObjCObjectPointerType(Pointee);
}
case TYPE_SUBST_TEMPLATE_TYPE_PARM: {
unsigned Idx = 0;
- QualType Parm = GetType(Record[Idx++]);
- QualType Replacement = GetType(Record[Idx++]);
+ QualType Parm = readType(*Loc.F, Record, Idx);
+ QualType Replacement = readType(*Loc.F, Record, Idx);
return
- Context->getSubstTemplateTypeParmType(cast<TemplateTypeParmType>(Parm),
+ Context.getSubstTemplateTypeParmType(cast<TemplateTypeParmType>(Parm),
Replacement);
}
case TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK: {
unsigned Idx = 0;
- QualType Parm = GetType(Record[Idx++]);
+ QualType Parm = readType(*Loc.F, Record, Idx);
TemplateArgument ArgPack = ReadTemplateArgument(*Loc.F, Record, Idx);
- return Context->getSubstTemplateTypeParmPackType(
+ return Context.getSubstTemplateTypeParmPackType(
cast<TemplateTypeParmType>(Parm),
ArgPack);
}
case TYPE_INJECTED_CLASS_NAME: {
- CXXRecordDecl *D = cast<CXXRecordDecl>(GetDecl(Record[0]));
- QualType TST = GetType(Record[1]); // probably derivable
+ CXXRecordDecl *D = ReadDeclAs<CXXRecordDecl>(*Loc.F, Record, Idx);
+ QualType TST = readType(*Loc.F, Record, Idx); // probably derivable
// FIXME: ASTContext::getInjectedClassNameType is not currently suitable
// for AST reading, too much interdependencies.
return
- QualType(new (*Context, TypeAlignment) InjectedClassNameType(D, TST), 0);
+ QualType(new (Context, TypeAlignment) InjectedClassNameType(D, TST), 0);
}
case TYPE_TEMPLATE_TYPE_PARM: {
@@ -3442,33 +3462,33 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
unsigned Depth = Record[Idx++];
unsigned Index = Record[Idx++];
bool Pack = Record[Idx++];
- TemplateTypeParmDecl *D =
- cast_or_null<TemplateTypeParmDecl>(GetDecl(Record[Idx++]));
- return Context->getTemplateTypeParmType(Depth, Index, Pack, D);
+ TemplateTypeParmDecl *D
+ = ReadDeclAs<TemplateTypeParmDecl>(*Loc.F, Record, Idx);
+ return Context.getTemplateTypeParmType(Depth, Index, Pack, D);
}
case TYPE_DEPENDENT_NAME: {
unsigned Idx = 0;
ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
- NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx);
- const IdentifierInfo *Name = this->GetIdentifierInfo(Record, Idx);
- QualType Canon = GetType(Record[Idx++]);
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
+ const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx);
+ QualType Canon = readType(*Loc.F, Record, Idx);
if (!Canon.isNull())
- Canon = Context->getCanonicalType(Canon);
- return Context->getDependentNameType(Keyword, NNS, Name, Canon);
+ Canon = Context.getCanonicalType(Canon);
+ return Context.getDependentNameType(Keyword, NNS, Name, Canon);
}
case TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION: {
unsigned Idx = 0;
ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
- NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx);
- const IdentifierInfo *Name = this->GetIdentifierInfo(Record, Idx);
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
+ const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx);
unsigned NumArgs = Record[Idx++];
- llvm::SmallVector<TemplateArgument, 8> Args;
+ SmallVector<TemplateArgument, 8> Args;
Args.reserve(NumArgs);
while (NumArgs--)
Args.push_back(ReadTemplateArgument(*Loc.F, Record, Idx));
- return Context->getDependentTemplateSpecializationType(Keyword, NNS, Name,
+ return Context.getDependentTemplateSpecializationType(Keyword, NNS, Name,
Args.size(), Args.data());
}
@@ -3476,7 +3496,7 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
unsigned Idx = 0;
// ArrayType
- QualType ElementType = GetType(Record[Idx++]);
+ QualType ElementType = readType(*Loc.F, Record, Idx);
ArrayType::ArraySizeModifier ASM
= (ArrayType::ArraySizeModifier)Record[Idx++];
unsigned IndexTypeQuals = Record[Idx++];
@@ -3485,7 +3505,7 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
Expr *NumElts = ReadExpr(*Loc.F);
SourceRange Brackets = ReadSourceRange(*Loc.F, Record, Idx);
- return Context->getDependentSizedArrayType(ElementType, NumElts, ASM,
+ return Context.getDependentSizedArrayType(ElementType, NumElts, ASM,
IndexTypeQuals, Brackets);
}
@@ -3493,19 +3513,28 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
unsigned Idx = 0;
bool IsDependent = Record[Idx++];
TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx);
- llvm::SmallVector<TemplateArgument, 8> Args;
+ SmallVector<TemplateArgument, 8> Args;
ReadTemplateArgumentList(Args, *Loc.F, Record, Idx);
- QualType Underlying = GetType(Record[Idx++]);
+ QualType Underlying = readType(*Loc.F, Record, Idx);
QualType T;
if (Underlying.isNull())
- T = Context->getCanonicalTemplateSpecializationType(Name, Args.data(),
+ T = Context.getCanonicalTemplateSpecializationType(Name, Args.data(),
Args.size());
else
- T = Context->getTemplateSpecializationType(Name, Args.data(),
+ T = Context.getTemplateSpecializationType(Name, Args.data(),
Args.size(), Underlying);
const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
return T;
}
+
+ case TYPE_ATOMIC: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of atomic type");
+ return QualType();
+ }
+ QualType ValueType = readType(*Loc.F, Record, Idx);
+ return Context.getAtomicType(ValueType);
+ }
}
// Suppress a GCC warning
return QualType();
@@ -3513,7 +3542,7 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
class clang::TypeLocReader : public TypeLocVisitor<TypeLocReader> {
ASTReader &Reader;
- ASTReader::PerFileData &F;
+ Module &F;
llvm::BitstreamCursor &DeclsCursor;
const ASTReader::RecordData &Record;
unsigned &Idx;
@@ -3523,8 +3552,13 @@ class clang::TypeLocReader : public TypeLocVisitor<TypeLocReader> {
return Reader.ReadSourceLocation(F, R, I);
}
+ template<typename T>
+ T *ReadDeclAs(const ASTReader::RecordData &Record, unsigned &Idx) {
+ return Reader.ReadDeclAs<T>(F, Record, Idx);
+ }
+
public:
- TypeLocReader(ASTReader &Reader, ASTReader::PerFileData &F,
+ TypeLocReader(ASTReader &Reader, Module &F,
const ASTReader::RecordData &Record, unsigned &Idx)
: Reader(Reader), F(F), DeclsCursor(F.DeclsCursor), Record(Record), Idx(Idx)
{ }
@@ -3608,7 +3642,7 @@ void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
TL.setLocalRangeEnd(ReadSourceLocation(Record, Idx));
TL.setTrailingReturn(Record[Idx++]);
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) {
- TL.setArg(i, cast_or_null<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
+ TL.setArg(i, ReadDeclAs<ParmVarDecl>(Record, Idx));
}
}
void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
@@ -3735,15 +3769,20 @@ void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
TL.setStarLoc(ReadSourceLocation(Record, Idx));
}
+void TypeLocReader::VisitAtomicTypeLoc(AtomicTypeLoc TL) {
+ TL.setKWLoc(ReadSourceLocation(Record, Idx));
+ TL.setLParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setRParenLoc(ReadSourceLocation(Record, Idx));
+}
-TypeSourceInfo *ASTReader::GetTypeSourceInfo(PerFileData &F,
+TypeSourceInfo *ASTReader::GetTypeSourceInfo(Module &F,
const RecordData &Record,
unsigned &Idx) {
- QualType InfoTy = GetType(Record[Idx++]);
+ QualType InfoTy = readType(F, Record, Idx);
if (InfoTy.isNull())
return 0;
- TypeSourceInfo *TInfo = getContext()->CreateTypeSourceInfo(InfoTy);
+ TypeSourceInfo *TInfo = getContext().CreateTypeSourceInfo(InfoTy);
TypeLocReader TLR(*this, F, Record, Idx);
for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc())
TLR.Visit(TL);
@@ -3758,41 +3797,47 @@ QualType ASTReader::GetType(TypeID ID) {
QualType T;
switch ((PredefinedTypeIDs)Index) {
case PREDEF_TYPE_NULL_ID: return QualType();
- case PREDEF_TYPE_VOID_ID: T = Context->VoidTy; break;
- case PREDEF_TYPE_BOOL_ID: T = Context->BoolTy; break;
+ case PREDEF_TYPE_VOID_ID: T = Context.VoidTy; break;
+ case PREDEF_TYPE_BOOL_ID: T = Context.BoolTy; break;
case PREDEF_TYPE_CHAR_U_ID:
case PREDEF_TYPE_CHAR_S_ID:
// FIXME: Check that the signedness of CharTy is correct!
- T = Context->CharTy;
+ T = Context.CharTy;
break;
- case PREDEF_TYPE_UCHAR_ID: T = Context->UnsignedCharTy; break;
- case PREDEF_TYPE_USHORT_ID: T = Context->UnsignedShortTy; break;
- case PREDEF_TYPE_UINT_ID: T = Context->UnsignedIntTy; break;
- case PREDEF_TYPE_ULONG_ID: T = Context->UnsignedLongTy; break;
- case PREDEF_TYPE_ULONGLONG_ID: T = Context->UnsignedLongLongTy; break;
- case PREDEF_TYPE_UINT128_ID: T = Context->UnsignedInt128Ty; break;
- case PREDEF_TYPE_SCHAR_ID: T = Context->SignedCharTy; break;
- case PREDEF_TYPE_WCHAR_ID: T = Context->WCharTy; break;
- case PREDEF_TYPE_SHORT_ID: T = Context->ShortTy; break;
- case PREDEF_TYPE_INT_ID: T = Context->IntTy; break;
- case PREDEF_TYPE_LONG_ID: T = Context->LongTy; break;
- case PREDEF_TYPE_LONGLONG_ID: T = Context->LongLongTy; break;
- case PREDEF_TYPE_INT128_ID: T = Context->Int128Ty; break;
- case PREDEF_TYPE_FLOAT_ID: T = Context->FloatTy; break;
- case PREDEF_TYPE_DOUBLE_ID: T = Context->DoubleTy; break;
- case PREDEF_TYPE_LONGDOUBLE_ID: T = Context->LongDoubleTy; break;
- case PREDEF_TYPE_OVERLOAD_ID: T = Context->OverloadTy; break;
- case PREDEF_TYPE_BOUND_MEMBER: T = Context->BoundMemberTy; break;
- case PREDEF_TYPE_DEPENDENT_ID: T = Context->DependentTy; break;
- case PREDEF_TYPE_UNKNOWN_ANY: T = Context->UnknownAnyTy; break;
- case PREDEF_TYPE_NULLPTR_ID: T = Context->NullPtrTy; break;
- case PREDEF_TYPE_CHAR16_ID: T = Context->Char16Ty; break;
- case PREDEF_TYPE_CHAR32_ID: T = Context->Char32Ty; break;
- 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_UCHAR_ID: T = Context.UnsignedCharTy; break;
+ case PREDEF_TYPE_USHORT_ID: T = Context.UnsignedShortTy; break;
+ case PREDEF_TYPE_UINT_ID: T = Context.UnsignedIntTy; break;
+ case PREDEF_TYPE_ULONG_ID: T = Context.UnsignedLongTy; break;
+ case PREDEF_TYPE_ULONGLONG_ID: T = Context.UnsignedLongLongTy; break;
+ case PREDEF_TYPE_UINT128_ID: T = Context.UnsignedInt128Ty; break;
+ case PREDEF_TYPE_SCHAR_ID: T = Context.SignedCharTy; break;
+ case PREDEF_TYPE_WCHAR_ID: T = Context.WCharTy; break;
+ case PREDEF_TYPE_SHORT_ID: T = Context.ShortTy; break;
+ case PREDEF_TYPE_INT_ID: T = Context.IntTy; break;
+ case PREDEF_TYPE_LONG_ID: T = Context.LongTy; break;
+ case PREDEF_TYPE_LONGLONG_ID: T = Context.LongLongTy; break;
+ case PREDEF_TYPE_INT128_ID: T = Context.Int128Ty; break;
+ case PREDEF_TYPE_HALF_ID: T = Context.HalfTy; break;
+ case PREDEF_TYPE_FLOAT_ID: T = Context.FloatTy; break;
+ case PREDEF_TYPE_DOUBLE_ID: T = Context.DoubleTy; break;
+ case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break;
+ case PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break;
+ case PREDEF_TYPE_BOUND_MEMBER: T = Context.BoundMemberTy; break;
+ case PREDEF_TYPE_DEPENDENT_ID: T = Context.DependentTy; break;
+ case PREDEF_TYPE_UNKNOWN_ANY: T = Context.UnknownAnyTy; break;
+ case PREDEF_TYPE_NULLPTR_ID: T = Context.NullPtrTy; break;
+ case PREDEF_TYPE_CHAR16_ID: T = Context.Char16Ty; break;
+ case PREDEF_TYPE_CHAR32_ID: T = Context.Char32Ty; break;
+ 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_AUTO_DEDUCT: T = Context.getAutoDeductType(); break;
+
+ case PREDEF_TYPE_AUTO_RREF_DEDUCT:
+ T = Context.getAutoRRefDeductType();
+ break;
}
assert(!T.isNull() && "Unknown predefined type");
@@ -3802,12 +3847,11 @@ QualType ASTReader::GetType(TypeID ID) {
Index -= NUM_PREDEF_TYPE_IDS;
assert(Index < TypesLoaded.size() && "Type index out-of-range");
if (TypesLoaded[Index].isNull()) {
- TypesLoaded[Index] = ReadTypeRecord(Index);
+ TypesLoaded[Index] = readTypeRecord(Index);
if (TypesLoaded[Index].isNull())
return QualType();
TypesLoaded[Index]->setFromAST();
- TypeIdxs[TypesLoaded[Index]] = TypeIdx::fromTypeID(ID);
if (DeserializationListener)
DeserializationListener->TypeRead(TypeIdx::fromTypeID(ID),
TypesLoaded[Index]);
@@ -3816,37 +3860,28 @@ QualType ASTReader::GetType(TypeID ID) {
return TypesLoaded[Index].withFastQualifiers(FastQuals);
}
-TypeID ASTReader::GetTypeID(QualType T) const {
- return MakeTypeID(T,
- std::bind1st(std::mem_fun(&ASTReader::GetTypeIdx), this));
+QualType ASTReader::getLocalType(Module &F, unsigned LocalID) {
+ return GetType(getGlobalTypeID(F, LocalID));
}
-TypeIdx ASTReader::GetTypeIdx(QualType T) const {
- if (T.isNull())
- return TypeIdx();
- assert(!T.getLocalFastQualifiers());
-
- TypeIdxMap::const_iterator I = TypeIdxs.find(T);
- // GetTypeIdx is mostly used for computing the hash of DeclarationNames and
- // comparing keys of ASTDeclContextNameLookupTable.
- // If the type didn't come from the AST file use a specially marked index
- // so that any hash/key comparison fail since no such index is stored
- // in a AST file.
- if (I == TypeIdxs.end())
- return TypeIdx(-1);
- return I->second;
-}
+serialization::TypeID
+ASTReader::getGlobalTypeID(Module &F, unsigned LocalID) const {
+ unsigned FastQuals = LocalID & Qualifiers::FastMask;
+ unsigned LocalIndex = LocalID >> Qualifiers::FastWidth;
+
+ if (LocalIndex < NUM_PREDEF_TYPE_IDS)
+ return LocalID;
-unsigned ASTReader::getTotalNumCXXBaseSpecifiers() const {
- unsigned Result = 0;
- for (unsigned I = 0, N = Chain.size(); I != N; ++I)
- Result += Chain[I]->LocalNumCXXBaseSpecifiers;
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = F.TypeRemap.find(LocalIndex - NUM_PREDEF_TYPE_IDS);
+ assert(I != F.TypeRemap.end() && "Invalid index into type index remap");
- return Result;
+ unsigned GlobalIndex = LocalIndex + I->second;
+ return (GlobalIndex << Qualifiers::FastWidth) | FastQuals;
}
TemplateArgumentLocInfo
-ASTReader::GetTemplateArgumentLocInfo(PerFileData &F,
+ASTReader::GetTemplateArgumentLocInfo(Module &F,
TemplateArgument::ArgKind Kind,
const RecordData &Record,
unsigned &Index) {
@@ -3881,7 +3916,7 @@ ASTReader::GetTemplateArgumentLocInfo(PerFileData &F,
}
TemplateArgumentLoc
-ASTReader::ReadTemplateArgumentLoc(PerFileData &F,
+ASTReader::ReadTemplateArgumentLoc(Module &F,
const RecordData &Record, unsigned &Index) {
TemplateArgument Arg = ReadTemplateArgument(F, Record, Index);
@@ -3897,47 +3932,20 @@ Decl *ASTReader::GetExternalDecl(uint32_t ID) {
return GetDecl(ID);
}
-uint64_t
-ASTReader::GetCXXBaseSpecifiersOffset(serialization::CXXBaseSpecifiersID ID) {
- if (ID == 0)
+uint64_t ASTReader::readCXXBaseSpecifiers(Module &M, const RecordData &Record,
+ unsigned &Idx){
+ if (Idx >= Record.size())
return 0;
- --ID;
- uint64_t Offset = 0;
- for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- PerFileData &F = *Chain[N - I - 1];
-
- if (ID < F.LocalNumCXXBaseSpecifiers)
- return Offset + F.CXXBaseSpecifiersOffsets[ID];
-
- ID -= F.LocalNumCXXBaseSpecifiers;
- Offset += F.SizeInBits;
- }
-
- assert(false && "CXXBaseSpecifiers not found");
- return 0;
+ unsigned LocalID = Record[Idx++];
+ return getGlobalBitOffset(M, M.CXXBaseSpecifiersOffsets[LocalID - 1]);
}
CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
- // Figure out which AST file contains this offset.
- PerFileData *F = 0;
- for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- if (Offset < Chain[N - I - 1]->SizeInBits) {
- F = Chain[N - I - 1];
- break;
- }
-
- Offset -= Chain[N - I - 1]->SizeInBits;
- }
-
- if (!F) {
- Error("Malformed AST file: C++ base specifiers at impossible offset");
- return 0;
- }
-
- llvm::BitstreamCursor &Cursor = F->DeclsCursor;
+ RecordLocation Loc = getLocalBitOffset(Offset);
+ llvm::BitstreamCursor &Cursor = Loc.F->DeclsCursor;
SavedStreamPosition SavedPosition(Cursor);
- Cursor.JumpToBit(Offset);
+ Cursor.JumpToBit(Loc.Offset);
ReadingKindTracker ReadingKind(Read_Decl, *this);
RecordData Record;
unsigned Code = Cursor.ReadCode();
@@ -3949,35 +3957,72 @@ CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
unsigned Idx = 0;
unsigned NumBases = Record[Idx++];
- void *Mem = Context->Allocate(sizeof(CXXBaseSpecifier) * NumBases);
+ void *Mem = Context.Allocate(sizeof(CXXBaseSpecifier) * NumBases);
CXXBaseSpecifier *Bases = new (Mem) CXXBaseSpecifier [NumBases];
for (unsigned I = 0; I != NumBases; ++I)
- Bases[I] = ReadCXXBaseSpecifier(*F, Record, Idx);
+ Bases[I] = ReadCXXBaseSpecifier(*Loc.F, Record, Idx);
return Bases;
}
-TranslationUnitDecl *ASTReader::GetTranslationUnitDecl() {
- if (!DeclsLoaded[0]) {
- ReadDeclRecord(0, 1);
- if (DeserializationListener)
- DeserializationListener->DeclRead(1, DeclsLoaded[0]);
- }
+serialization::DeclID
+ASTReader::getGlobalDeclID(Module &F, unsigned LocalID) const {
+ if (LocalID < NUM_PREDEF_DECL_IDS)
+ return LocalID;
+
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = F.DeclRemap.find(LocalID - NUM_PREDEF_DECL_IDS);
+ assert(I != F.DeclRemap.end() && "Invalid index into decl index remap");
+
+ return LocalID + I->second;
+}
- return cast<TranslationUnitDecl>(DeclsLoaded[0]);
+bool ASTReader::isDeclIDFromModule(serialization::GlobalDeclID ID,
+ Module &M) const {
+ GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(ID);
+ assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
+ return &M == I->second;
}
Decl *ASTReader::GetDecl(DeclID ID) {
- if (ID == 0)
+ if (ID < NUM_PREDEF_DECL_IDS) {
+ switch ((PredefinedDeclIDs)ID) {
+ case PREDEF_DECL_NULL_ID:
+ return 0;
+
+ case PREDEF_DECL_TRANSLATION_UNIT_ID:
+ return Context.getTranslationUnitDecl();
+
+ case PREDEF_DECL_OBJC_ID_ID:
+ return Context.getObjCIdDecl();
+
+ case PREDEF_DECL_OBJC_SEL_ID:
+ return Context.getObjCSelDecl();
+
+ case PREDEF_DECL_OBJC_CLASS_ID:
+ return Context.getObjCClassDecl();
+
+ case PREDEF_DECL_INT_128_ID:
+ return Context.getInt128Decl();
+
+ case PREDEF_DECL_UNSIGNED_INT_128_ID:
+ return Context.getUInt128Decl();
+
+ case PREDEF_DECL_OBJC_INSTANCETYPE_ID:
+ return Context.getObjCInstanceTypeDecl();
+ }
+
return 0;
+ }
+
+ unsigned Index = ID - NUM_PREDEF_DECL_IDS;
- if (ID > DeclsLoaded.size()) {
+ if (Index > DeclsLoaded.size()) {
Error("declaration ID out-of-range for AST file");
return 0;
}
-
- unsigned Index = ID - 1;
- if (!DeclsLoaded[Index]) {
- ReadDeclRecord(Index, ID);
+
+if (!DeclsLoaded[Index]) {
+ ReadDeclRecord(ID);
if (DeserializationListener)
DeserializationListener->DeclRead(ID, DeclsLoaded[Index]);
}
@@ -3985,6 +4030,17 @@ Decl *ASTReader::GetDecl(DeclID ID) {
return DeclsLoaded[Index];
}
+serialization::DeclID ASTReader::ReadDeclID(Module &F,
+ const RecordData &Record,
+ unsigned &Idx) {
+ if (Idx >= Record.size()) {
+ Error("Corrupted AST file");
+ return 0;
+ }
+
+ return getGlobalDeclID(F, Record[Idx++]);
+}
+
/// \brief Resolve the offset of a statement into a statement.
///
/// This operation will read a new statement from the external
@@ -3995,49 +4051,137 @@ Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) {
ClearSwitchCaseIDs();
// Offset here is a global offset across the entire chain.
- for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- PerFileData &F = *Chain[N - I - 1];
- if (Offset < F.SizeInBits) {
- // Since we know that this statement is part of a decl, make sure to use
- // the decl cursor to read it.
- F.DeclsCursor.JumpToBit(Offset);
- return ReadStmtFromStream(F);
- }
- Offset -= F.SizeInBits;
- }
- llvm_unreachable("Broken chain");
+ RecordLocation Loc = getLocalBitOffset(Offset);
+ Loc.F->DeclsCursor.JumpToBit(Loc.Offset);
+ return ReadStmtFromStream(*Loc.F);
}
-ExternalLoadResult ASTReader::FindExternalLexicalDecls(const DeclContext *DC,
- bool (*isKindWeWant)(Decl::Kind),
- llvm::SmallVectorImpl<Decl*> &Decls) {
- // There might be lexical decls in multiple parts of the chain, for the TU
- // at least.
- // DeclContextOffsets might reallocate as we load additional decls below,
- // so make a copy of the vector.
- DeclContextInfos Infos = DeclContextOffsets[DC];
- for (DeclContextInfos::iterator I = Infos.begin(), E = Infos.end();
- I != E; ++I) {
- // IDs can be 0 if this context doesn't contain declarations.
- if (!I->LexicalDecls)
- continue;
+namespace {
+ class FindExternalLexicalDeclsVisitor {
+ ASTReader &Reader;
+ const DeclContext *DC;
+ bool (*isKindWeWant)(Decl::Kind);
+
+ SmallVectorImpl<Decl*> &Decls;
+ bool PredefsVisited[NUM_PREDEF_DECL_IDS];
- // Load all of the declaration IDs
- for (const KindDeclIDPair *ID = I->LexicalDecls,
- *IDE = ID + I->NumLexicalDecls; ID != IDE; ++ID) {
- if (isKindWeWant && !isKindWeWant((Decl::Kind)ID->first))
- continue;
+ public:
+ FindExternalLexicalDeclsVisitor(ASTReader &Reader, const DeclContext *DC,
+ bool (*isKindWeWant)(Decl::Kind),
+ SmallVectorImpl<Decl*> &Decls)
+ : Reader(Reader), DC(DC), isKindWeWant(isKindWeWant), Decls(Decls)
+ {
+ for (unsigned I = 0; I != NUM_PREDEF_DECL_IDS; ++I)
+ PredefsVisited[I] = false;
+ }
- Decl *D = GetDecl(ID->second);
- assert(D && "Null decl in lexical decls");
- Decls.push_back(D);
+ static bool visit(Module &M, bool Preorder, void *UserData) {
+ if (Preorder)
+ return false;
+
+ FindExternalLexicalDeclsVisitor *This
+ = static_cast<FindExternalLexicalDeclsVisitor *>(UserData);
+
+ Module::DeclContextInfosMap::iterator Info
+ = M.DeclContextInfos.find(This->DC);
+ if (Info == M.DeclContextInfos.end() || !Info->second.LexicalDecls)
+ return false;
+
+ // Load all of the declaration IDs
+ for (const KindDeclIDPair *ID = Info->second.LexicalDecls,
+ *IDE = ID + Info->second.NumLexicalDecls;
+ ID != IDE; ++ID) {
+ if (This->isKindWeWant && !This->isKindWeWant((Decl::Kind)ID->first))
+ continue;
+
+ // Don't add predefined declarations to the lexical context more
+ // than once.
+ if (ID->second < NUM_PREDEF_DECL_IDS) {
+ if (This->PredefsVisited[ID->second])
+ continue;
+
+ This->PredefsVisited[ID->second] = true;
+ }
+
+ if (Decl *D = This->Reader.GetLocalDecl(M, ID->second)) {
+ if (!This->DC->isDeclInLexicalTraversal(D))
+ This->Decls.push_back(D);
+ }
+ }
+
+ return false;
}
- }
+ };
+}
+ExternalLoadResult ASTReader::FindExternalLexicalDecls(const DeclContext *DC,
+ bool (*isKindWeWant)(Decl::Kind),
+ SmallVectorImpl<Decl*> &Decls) {
+ // There might be lexical decls in multiple modules, for the TU at
+ // least. Walk all of the modules in the order they were loaded.
+ FindExternalLexicalDeclsVisitor Visitor(*this, DC, isKindWeWant, Decls);
+ ModuleMgr.visitDepthFirst(&FindExternalLexicalDeclsVisitor::visit, &Visitor);
++NumLexicalDeclContextsRead;
return ELR_Success;
}
+namespace {
+ /// \brief Module visitor used to perform name lookup into a
+ /// declaration context.
+ class DeclContextNameLookupVisitor {
+ ASTReader &Reader;
+ const DeclContext *DC;
+ DeclarationName Name;
+ SmallVectorImpl<NamedDecl *> &Decls;
+
+ public:
+ DeclContextNameLookupVisitor(ASTReader &Reader,
+ const DeclContext *DC, DeclarationName Name,
+ SmallVectorImpl<NamedDecl *> &Decls)
+ : Reader(Reader), DC(DC), Name(Name), Decls(Decls) { }
+
+ static bool visit(Module &M, void *UserData) {
+ DeclContextNameLookupVisitor *This
+ = static_cast<DeclContextNameLookupVisitor *>(UserData);
+
+ // Check whether we have any visible declaration information for
+ // this context in this module.
+ Module::DeclContextInfosMap::iterator Info
+ = M.DeclContextInfos.find(This->DC);
+ if (Info == M.DeclContextInfos.end() || !Info->second.NameLookupTableData)
+ return false;
+
+ // Look for this name within this module.
+ ASTDeclContextNameLookupTable *LookupTable =
+ (ASTDeclContextNameLookupTable*)Info->second.NameLookupTableData;
+ ASTDeclContextNameLookupTable::iterator Pos
+ = LookupTable->find(This->Name);
+ if (Pos == LookupTable->end())
+ return false;
+
+ bool FoundAnything = false;
+ ASTDeclContextNameLookupTrait::data_type Data = *Pos;
+ for (; Data.first != Data.second; ++Data.first) {
+ NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M, *Data.first);
+ if (!ND)
+ continue;
+
+ if (ND->getDeclName() != This->Name) {
+ assert(!This->Name.getCXXNameType().isNull() &&
+ "Name mismatch without a type");
+ continue;
+ }
+
+ // Record this declaration.
+ FoundAnything = true;
+ This->Decls.push_back(ND);
+ }
+
+ return FoundAnything;
+ }
+ };
+}
+
DeclContext::lookup_result
ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) {
@@ -4047,69 +4191,39 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
return DeclContext::lookup_result(DeclContext::lookup_iterator(0),
DeclContext::lookup_iterator(0));
- llvm::SmallVector<NamedDecl *, 64> Decls;
- // There might be visible decls in multiple parts of the chain, for the TU
- // and namespaces. For any given name, the last available results replace
- // all earlier ones. For this reason, we walk in reverse.
- DeclContextInfos &Infos = DeclContextOffsets[DC];
- for (DeclContextInfos::reverse_iterator I = Infos.rbegin(), E = Infos.rend();
- I != E; ++I) {
- if (!I->NameLookupTableData)
- continue;
-
- ASTDeclContextNameLookupTable *LookupTable =
- (ASTDeclContextNameLookupTable*)I->NameLookupTableData;
- ASTDeclContextNameLookupTable::iterator Pos = LookupTable->find(Name);
- if (Pos == LookupTable->end())
- continue;
-
- ASTDeclContextNameLookupTrait::data_type Data = *Pos;
- for (; Data.first != Data.second; ++Data.first)
- Decls.push_back(cast<NamedDecl>(GetDecl(*Data.first)));
- break;
- }
-
+ SmallVector<NamedDecl *, 64> Decls;
+ DeclContextNameLookupVisitor Visitor(*this, DC, Name, Decls);
+ ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor);
++NumVisibleDeclContextsRead;
-
SetExternalVisibleDeclsForName(DC, Name, Decls);
return const_cast<DeclContext*>(DC)->lookup(Name);
}
-void ASTReader::MaterializeVisibleDecls(const DeclContext *DC) {
- assert(DC->hasExternalVisibleStorage() &&
- "DeclContext has no visible decls in storage");
+/// \brief Under non-PCH compilation the consumer receives the objc methods
+/// before receiving the implementation, and codegen depends on this.
+/// We simulate this by deserializing and passing to consumer the methods of the
+/// implementation before passing the deserialized implementation decl.
+static void PassObjCImplDeclToConsumer(ObjCImplDecl *ImplD,
+ ASTConsumer *Consumer) {
+ assert(ImplD && Consumer);
- llvm::SmallVector<NamedDecl *, 64> Decls;
- // There might be visible decls in multiple parts of the chain, for the TU
- // and namespaces.
- DeclContextInfos &Infos = DeclContextOffsets[DC];
- for (DeclContextInfos::iterator I = Infos.begin(), E = Infos.end();
- I != E; ++I) {
- if (!I->NameLookupTableData)
- continue;
+ for (ObjCImplDecl::method_iterator
+ I = ImplD->meth_begin(), E = ImplD->meth_end(); I != E; ++I)
+ Consumer->HandleInterestingDecl(DeclGroupRef(*I));
- ASTDeclContextNameLookupTable *LookupTable =
- (ASTDeclContextNameLookupTable*)I->NameLookupTableData;
- for (ASTDeclContextNameLookupTable::item_iterator
- ItemI = LookupTable->item_begin(),
- ItemEnd = LookupTable->item_end() ; ItemI != ItemEnd; ++ItemI) {
- ASTDeclContextNameLookupTable::item_iterator::value_type Val
- = *ItemI;
- ASTDeclContextNameLookupTrait::data_type Data = Val.second;
- Decls.clear();
- for (; Data.first != Data.second; ++Data.first)
- Decls.push_back(cast<NamedDecl>(GetDecl(*Data.first)));
- MaterializeVisibleDeclsForName(DC, Val.first, Decls);
- }
- }
+ Consumer->HandleInterestingDecl(DeclGroupRef(ImplD));
}
void ASTReader::PassInterestingDeclsToConsumer() {
assert(Consumer);
while (!InterestingDecls.empty()) {
- DeclGroupRef DG(InterestingDecls.front());
+ Decl *D = InterestingDecls.front();
InterestingDecls.pop_front();
- Consumer->HandleInterestingDecl(DG);
+
+ if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D))
+ PassObjCImplDeclToConsumer(ImplD, Consumer);
+ else
+ Consumer->HandleInterestingDecl(DeclGroupRef(D));
}
}
@@ -4124,6 +4238,7 @@ void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) {
// passing to the consumer.
GetDecl(ExternalDefinitions[I]);
}
+ ExternalDefinitions.clear();
PassInterestingDeclsToConsumer();
}
@@ -4148,7 +4263,7 @@ void ASTReader::PrintStats() {
std::fprintf(stderr, " %u stat cache hits\n", NumStatHits);
std::fprintf(stderr, " %u stat cache misses\n", NumStatMisses);
- if (TotalNumSLocEntries)
+ if (unsigned TotalNumSLocEntries = getTotalNumSLocs())
std::fprintf(stderr, " %u/%u source location entries read (%f%%)\n",
NumSLocEntriesRead, TotalNumSLocEntries,
((float)NumSLocEntriesRead/TotalNumSLocEntries * 100));
@@ -4194,13 +4309,51 @@ void ASTReader::PrintStats() {
std::fprintf(stderr, " %u method pool misses\n", NumMethodPoolMisses);
}
std::fprintf(stderr, "\n");
+ dump();
+ std::fprintf(stderr, "\n");
+}
+
+template<typename Key, typename Module, unsigned InitialCapacity>
+static void
+dumpModuleIDMap(StringRef Name,
+ const ContinuousRangeMap<Key, Module *,
+ InitialCapacity> &Map) {
+ if (Map.begin() == Map.end())
+ return;
+
+ typedef ContinuousRangeMap<Key, Module *, InitialCapacity> MapType;
+ llvm::errs() << Name << ":\n";
+ for (typename MapType::const_iterator I = Map.begin(), IEnd = Map.end();
+ I != IEnd; ++I) {
+ llvm::errs() << " " << I->first << " -> " << I->second->FileName
+ << "\n";
+ }
+}
+
+void ASTReader::dump() {
+ llvm::errs() << "*** PCH/Module Remappings:\n";
+ dumpModuleIDMap("Global bit offset map", GlobalBitOffsetsMap);
+ dumpModuleIDMap("Global source location entry map", GlobalSLocEntryMap);
+ dumpModuleIDMap("Global type map", GlobalTypeMap);
+ dumpModuleIDMap("Global declaration map", GlobalDeclMap);
+ dumpModuleIDMap("Global identifier map", GlobalIdentifierMap);
+ dumpModuleIDMap("Global selector map", GlobalSelectorMap);
+ dumpModuleIDMap("Global preprocessed entity map",
+ GlobalPreprocessedEntityMap);
+
+ llvm::errs() << "\n*** PCH/Modules Loaded:";
+ for (ModuleManager::ModuleConstIterator M = ModuleMgr.begin(),
+ MEnd = ModuleMgr.end();
+ M != MEnd; ++M)
+ (*M)->dump();
}
/// Return the amount of memory used by memory buffers, breaking down
/// by heap-backed versus mmap'ed memory.
void ASTReader::getMemoryBufferSizes(MemoryBufferSizes &sizes) const {
- for (unsigned i = 0, e = Chain.size(); i != e; ++i)
- if (llvm::MemoryBuffer *buf = Chain[i]->Buffer.get()) {
+ for (ModuleConstIterator I = ModuleMgr.begin(),
+ E = ModuleMgr.end(); I != E; ++I) {
+ if (llvm::MemoryBuffer *buf = (*I)->Buffer.get()) {
size_t bytes = buf->getBufferSize();
switch (buf->getBufferKind()) {
case llvm::MemoryBuffer::MemoryBuffer_Malloc:
@@ -4211,6 +4364,7 @@ void ASTReader::getMemoryBufferSizes(MemoryBufferSizes &sizes) const {
break;
}
}
+ }
}
void ASTReader::InitializeSema(Sema &S) {
@@ -4227,114 +4381,14 @@ void ASTReader::InitializeSema(Sema &S) {
}
PreloadedDecls.clear();
- // If there were any tentative definitions, deserialize them and add
- // them to Sema's list of tentative definitions.
- for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) {
- VarDecl *Var = cast<VarDecl>(GetDecl(TentativeDefinitions[I]));
- SemaObj->TentativeDefinitions.push_back(Var);
- }
-
- // If there were any unused file scoped decls, deserialize them and add to
- // Sema's list of unused file scoped decls.
- for (unsigned I = 0, N = UnusedFileScopedDecls.size(); I != N; ++I) {
- DeclaratorDecl *D = cast<DeclaratorDecl>(GetDecl(UnusedFileScopedDecls[I]));
- SemaObj->UnusedFileScopedDecls.push_back(D);
- }
-
- // If there were any delegating constructors, add them to Sema's list
- for (unsigned I = 0, N = DelegatingCtorDecls.size(); I != N; ++I) {
- CXXConstructorDecl *D
- = cast<CXXConstructorDecl>(GetDecl(DelegatingCtorDecls[I]));
- SemaObj->DelegatingCtorDecls.push_back(D);
- }
-
- // If there were any locally-scoped external declarations,
- // deserialize them and add them to Sema's table of locally-scoped
- // external declarations.
- for (unsigned I = 0, N = LocallyScopedExternalDecls.size(); I != N; ++I) {
- NamedDecl *D = cast<NamedDecl>(GetDecl(LocallyScopedExternalDecls[I]));
- SemaObj->LocallyScopedExternalDecls[D->getDeclName()] = D;
- }
-
- // If there were any ext_vector type declarations, deserialize them
- // and add them to Sema's vector of such declarations.
- for (unsigned I = 0, N = ExtVectorDecls.size(); I != N; ++I)
- SemaObj->ExtVectorDecls.push_back(
- cast<TypedefNameDecl>(GetDecl(ExtVectorDecls[I])));
-
- // FIXME: Do VTable uses and dynamic classes deserialize too much ?
- // Can we cut them down before writing them ?
-
- // If there were any dynamic classes declarations, deserialize them
- // and add them to Sema's vector of such declarations.
- for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I)
- SemaObj->DynamicClasses.push_back(
- cast<CXXRecordDecl>(GetDecl(DynamicClasses[I])));
-
// Load the offsets of the declarations that Sema references.
// They will be lazily deserialized when needed.
if (!SemaDeclRefs.empty()) {
assert(SemaDeclRefs.size() == 2 && "More decl refs than expected!");
- SemaObj->StdNamespace = SemaDeclRefs[0];
- SemaObj->StdBadAlloc = SemaDeclRefs[1];
- }
-
- for (PerFileData *F = FirstInSource; F; F = F->NextInSource) {
-
- // If there are @selector references added them to its pool. This is for
- // implementation of -Wselector.
- if (!F->ReferencedSelectorsData.empty()) {
- unsigned int DataSize = F->ReferencedSelectorsData.size()-1;
- unsigned I = 0;
- while (I < DataSize) {
- Selector Sel = DecodeSelector(F->ReferencedSelectorsData[I++]);
- SourceLocation SelLoc = ReadSourceLocation(
- *F, F->ReferencedSelectorsData, I);
- SemaObj->ReferencedSelectors.insert(std::make_pair(Sel, SelLoc));
- }
- }
- }
-
- // The special data sets below always come from the most recent PCH,
- // which is at the front of the chain.
- PerFileData &F = *Chain.front();
-
- // If there were any pending implicit instantiations, deserialize them
- // and add them to Sema's queue of such instantiations.
- assert(F.PendingInstantiations.size() % 2 == 0 &&
- "Expected pairs of entries");
- for (unsigned Idx = 0, N = F.PendingInstantiations.size(); Idx < N;) {
- ValueDecl *D=cast<ValueDecl>(GetDecl(F.PendingInstantiations[Idx++]));
- SourceLocation Loc = ReadSourceLocation(F, F.PendingInstantiations,Idx);
- SemaObj->PendingInstantiations.push_back(std::make_pair(D, Loc));
- }
-
- // If there were any weak undeclared identifiers, deserialize them and add to
- // Sema's list of weak undeclared identifiers.
- if (!WeakUndeclaredIdentifiers.empty()) {
- unsigned Idx = 0;
- for (unsigned I = 0, N = WeakUndeclaredIdentifiers[Idx++]; I != N; ++I) {
- IdentifierInfo *WeakId = GetIdentifierInfo(WeakUndeclaredIdentifiers,Idx);
- IdentifierInfo *AliasId= GetIdentifierInfo(WeakUndeclaredIdentifiers,Idx);
- SourceLocation Loc = ReadSourceLocation(F, WeakUndeclaredIdentifiers,Idx);
- bool Used = WeakUndeclaredIdentifiers[Idx++];
- Sema::WeakInfo WI(AliasId, Loc);
- WI.setUsed(Used);
- SemaObj->WeakUndeclaredIdentifiers.insert(std::make_pair(WeakId, WI));
- }
- }
-
- // If there were any VTable uses, deserialize the information and add it
- // to Sema's vector and map of VTable uses.
- if (!VTableUses.empty()) {
- unsigned Idx = 0;
- for (unsigned I = 0, N = VTableUses[Idx++]; I != N; ++I) {
- CXXRecordDecl *Class = cast<CXXRecordDecl>(GetDecl(VTableUses[Idx++]));
- SourceLocation Loc = ReadSourceLocation(F, VTableUses, Idx);
- bool DefinitionRequired = VTableUses[Idx++];
- SemaObj->VTableUses.push_back(std::make_pair(Class, Loc));
- SemaObj->VTablesUsed[Class] = DefinitionRequired;
- }
+ if (!SemaObj->StdNamespace)
+ SemaObj->StdNamespace = SemaDeclRefs[0];
+ if (!SemaObj->StdBadAlloc)
+ SemaObj->StdBadAlloc = SemaDeclRefs[1];
}
if (!FPPragmaOptions.empty()) {
@@ -4352,24 +4406,9 @@ void ASTReader::InitializeSema(Sema &S) {
}
IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) {
- // Try to find this name within our on-disk hash tables. We start with the
- // most recent one, since that one contains the most up-to-date info.
- for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- ASTIdentifierLookupTable *IdTable
- = (ASTIdentifierLookupTable *)Chain[I]->IdentifierLookupTable;
- if (!IdTable)
- continue;
- std::pair<const char*, unsigned> Key(NameStart, NameEnd - NameStart);
- ASTIdentifierLookupTable::iterator Pos = IdTable->find(Key);
- if (Pos == IdTable->end())
- continue;
-
- // Dereferencing the iterator has the effect of building the
- // IdentifierInfo node and populating it with the various
- // declarations it needs.
- return *Pos;
- }
- return 0;
+ IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart));
+ ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor);
+ return Visitor.getIdentifierInfo();
}
namespace clang {
@@ -4394,27 +4433,28 @@ namespace clang {
public:
explicit ASTIdentifierIterator(const ASTReader &Reader);
- virtual llvm::StringRef Next();
+ virtual StringRef Next();
};
}
ASTIdentifierIterator::ASTIdentifierIterator(const ASTReader &Reader)
- : Reader(Reader), Index(Reader.Chain.size() - 1) {
+ : Reader(Reader), Index(Reader.ModuleMgr.size() - 1) {
ASTIdentifierLookupTable *IdTable
- = (ASTIdentifierLookupTable *)Reader.Chain[Index]->IdentifierLookupTable;
+ = (ASTIdentifierLookupTable *)Reader.ModuleMgr[Index].IdentifierLookupTable;
Current = IdTable->key_begin();
End = IdTable->key_end();
}
-llvm::StringRef ASTIdentifierIterator::Next() {
+StringRef ASTIdentifierIterator::Next() {
while (Current == End) {
// If we have exhausted all of our AST files, we're done.
if (Index == 0)
- return llvm::StringRef();
+ return StringRef();
--Index;
ASTIdentifierLookupTable *IdTable
- = (ASTIdentifierLookupTable *)Reader.Chain[Index]->IdentifierLookupTable;
+ = (ASTIdentifierLookupTable *)Reader.ModuleMgr[Index].
+ IdentifierLookupTable;
Current = IdTable->key_begin();
End = IdTable->key_end();
}
@@ -4423,43 +4463,103 @@ llvm::StringRef ASTIdentifierIterator::Next() {
// the next one.
std::pair<const char*, unsigned> Key = *Current;
++Current;
- return llvm::StringRef(Key.first, Key.second);
+ return StringRef(Key.first, Key.second);
}
IdentifierIterator *ASTReader::getIdentifiers() const {
return new ASTIdentifierIterator(*this);
}
-std::pair<ObjCMethodList, ObjCMethodList>
-ASTReader::ReadMethodPool(Selector Sel) {
- // Find this selector in a hash table. We want to find the most recent entry.
- for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- PerFileData &F = *Chain[I];
- if (!F.SelectorLookupTable)
- continue;
-
- ASTSelectorLookupTable *PoolTable
- = (ASTSelectorLookupTable*)F.SelectorLookupTable;
- ASTSelectorLookupTable::iterator Pos = PoolTable->find(Sel);
- if (Pos != PoolTable->end()) {
- ++NumSelectorsRead;
+namespace clang { namespace serialization {
+ class ReadMethodPoolVisitor {
+ ASTReader &Reader;
+ Selector Sel;
+ llvm::SmallVector<ObjCMethodDecl *, 4> InstanceMethods;
+ llvm::SmallVector<ObjCMethodDecl *, 4> FactoryMethods;
+
+ /// \brief Build an ObjCMethodList from a vector of Objective-C method
+ /// declarations.
+ ObjCMethodList
+ buildObjCMethodList(const SmallVectorImpl<ObjCMethodDecl *> &Vec) const
+ {
+ ObjCMethodList List;
+ ObjCMethodList *Prev = 0;
+ for (unsigned I = 0, N = Vec.size(); I != N; ++I) {
+ if (!List.Method) {
+ // This is the first method, which is the easy case.
+ List.Method = Vec[I];
+ Prev = &List;
+ continue;
+ }
+
+ ObjCMethodList *Mem =
+ Reader.getSema()->BumpAlloc.Allocate<ObjCMethodList>();
+ Prev->Next = new (Mem) ObjCMethodList(Vec[I], 0);
+ Prev = Prev->Next;
+ }
+
+ return List;
+ }
+
+ public:
+ ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel)
+ : Reader(Reader), Sel(Sel) { }
+
+ static bool visit(Module &M, void *UserData) {
+ ReadMethodPoolVisitor *This
+ = static_cast<ReadMethodPoolVisitor *>(UserData);
+
+ if (!M.SelectorLookupTable)
+ return false;
+
+ ASTSelectorLookupTable *PoolTable
+ = (ASTSelectorLookupTable*)M.SelectorLookupTable;
+ ASTSelectorLookupTable::iterator Pos = PoolTable->find(This->Sel);
+ if (Pos == PoolTable->end())
+ return false;
+
+ ++This->Reader.NumSelectorsRead;
// FIXME: Not quite happy with the statistics here. We probably should
// disable this tracking when called via LoadSelector.
// Also, should entries without methods count as misses?
- ++NumMethodPoolEntriesRead;
+ ++This->Reader.NumMethodPoolEntriesRead;
ASTSelectorLookupTrait::data_type Data = *Pos;
- if (DeserializationListener)
- DeserializationListener->SelectorRead(Data.ID, Sel);
- return std::make_pair(Data.Instance, Data.Factory);
+ if (This->Reader.DeserializationListener)
+ This->Reader.DeserializationListener->SelectorRead(Data.ID,
+ This->Sel);
+
+ This->InstanceMethods.append(Data.Instance.begin(), Data.Instance.end());
+ This->FactoryMethods.append(Data.Factory.begin(), Data.Factory.end());
+ return true;
+ }
+
+ /// \brief Retrieve the instance methods found by this visitor.
+ ObjCMethodList getInstanceMethods() const {
+ return buildObjCMethodList(InstanceMethods);
}
- }
- ++NumMethodPoolMisses;
- return std::pair<ObjCMethodList, ObjCMethodList>();
+ /// \brief Retrieve the instance methods found by this visitor.
+ ObjCMethodList getFactoryMethods() const {
+ return buildObjCMethodList(FactoryMethods);
+ }
+ };
+} } // end namespace clang::serialization
+
+std::pair<ObjCMethodList, ObjCMethodList>
+ASTReader::ReadMethodPool(Selector Sel) {
+ ReadMethodPoolVisitor Visitor(*this, Sel);
+ ModuleMgr.visit(&ReadMethodPoolVisitor::visit, &Visitor);
+ std::pair<ObjCMethodList, ObjCMethodList> Result;
+ Result.first = Visitor.getInstanceMethods();
+ Result.second = Visitor.getFactoryMethods();
+
+ if (!Result.first.Method && !Result.second.Method)
+ ++NumMethodPoolMisses;
+ return Result;
}
void ASTReader::ReadKnownNamespaces(
- llvm::SmallVectorImpl<NamespaceDecl *> &Namespaces) {
+ SmallVectorImpl<NamespaceDecl *> &Namespaces) {
Namespaces.clear();
for (unsigned I = 0, N = KnownNamespaces.size(); I != N; ++I) {
@@ -4469,12 +4569,136 @@ void ASTReader::ReadKnownNamespaces(
}
}
+void ASTReader::ReadTentativeDefinitions(
+ SmallVectorImpl<VarDecl *> &TentativeDefs) {
+ for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) {
+ VarDecl *Var = dyn_cast_or_null<VarDecl>(GetDecl(TentativeDefinitions[I]));
+ if (Var)
+ TentativeDefs.push_back(Var);
+ }
+ TentativeDefinitions.clear();
+}
+
+void ASTReader::ReadUnusedFileScopedDecls(
+ SmallVectorImpl<const DeclaratorDecl *> &Decls) {
+ for (unsigned I = 0, N = UnusedFileScopedDecls.size(); I != N; ++I) {
+ DeclaratorDecl *D
+ = dyn_cast_or_null<DeclaratorDecl>(GetDecl(UnusedFileScopedDecls[I]));
+ if (D)
+ Decls.push_back(D);
+ }
+ UnusedFileScopedDecls.clear();
+}
+
+void ASTReader::ReadDelegatingConstructors(
+ SmallVectorImpl<CXXConstructorDecl *> &Decls) {
+ for (unsigned I = 0, N = DelegatingCtorDecls.size(); I != N; ++I) {
+ CXXConstructorDecl *D
+ = dyn_cast_or_null<CXXConstructorDecl>(GetDecl(DelegatingCtorDecls[I]));
+ if (D)
+ Decls.push_back(D);
+ }
+ DelegatingCtorDecls.clear();
+}
+
+void ASTReader::ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl *> &Decls) {
+ for (unsigned I = 0, N = ExtVectorDecls.size(); I != N; ++I) {
+ TypedefNameDecl *D
+ = dyn_cast_or_null<TypedefNameDecl>(GetDecl(ExtVectorDecls[I]));
+ if (D)
+ Decls.push_back(D);
+ }
+ ExtVectorDecls.clear();
+}
+
+void ASTReader::ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls) {
+ for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) {
+ CXXRecordDecl *D
+ = dyn_cast_or_null<CXXRecordDecl>(GetDecl(DynamicClasses[I]));
+ if (D)
+ Decls.push_back(D);
+ }
+ DynamicClasses.clear();
+}
+
+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]));
+ if (D)
+ Decls.push_back(D);
+ }
+ LocallyScopedExternalDecls.clear();
+}
+
+void ASTReader::ReadReferencedSelectors(
+ SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels) {
+ if (ReferencedSelectorsData.empty())
+ return;
+
+ // If there are @selector references added them to its pool. This is for
+ // implementation of -Wselector.
+ unsigned int DataSize = ReferencedSelectorsData.size()-1;
+ unsigned I = 0;
+ while (I < DataSize) {
+ Selector Sel = DecodeSelector(ReferencedSelectorsData[I++]);
+ SourceLocation SelLoc
+ = SourceLocation::getFromRawEncoding(ReferencedSelectorsData[I++]);
+ Sels.push_back(std::make_pair(Sel, SelLoc));
+ }
+ ReferencedSelectorsData.clear();
+}
+
+void ASTReader::ReadWeakUndeclaredIdentifiers(
+ SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo> > &WeakIDs) {
+ if (WeakUndeclaredIdentifiers.empty())
+ return;
+
+ for (unsigned I = 0, N = WeakUndeclaredIdentifiers.size(); I < N; /*none*/) {
+ IdentifierInfo *WeakId
+ = DecodeIdentifierInfo(WeakUndeclaredIdentifiers[I++]);
+ IdentifierInfo *AliasId
+ = DecodeIdentifierInfo(WeakUndeclaredIdentifiers[I++]);
+ SourceLocation Loc
+ = SourceLocation::getFromRawEncoding(WeakUndeclaredIdentifiers[I++]);
+ bool Used = WeakUndeclaredIdentifiers[I++];
+ WeakInfo WI(AliasId, Loc);
+ WI.setUsed(Used);
+ WeakIDs.push_back(std::make_pair(WeakId, WI));
+ }
+ WeakUndeclaredIdentifiers.clear();
+}
+
+void ASTReader::ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables) {
+ for (unsigned Idx = 0, N = VTableUses.size(); Idx < N; /* In loop */) {
+ ExternalVTableUse VT;
+ VT.Record = dyn_cast_or_null<CXXRecordDecl>(GetDecl(VTableUses[Idx++]));
+ VT.Location = SourceLocation::getFromRawEncoding(VTableUses[Idx++]);
+ VT.DefinitionRequired = VTableUses[Idx++];
+ VTables.push_back(VT);
+ }
+
+ VTableUses.clear();
+}
+
+void ASTReader::ReadPendingInstantiations(
+ SmallVectorImpl<std::pair<ValueDecl *, SourceLocation> > &Pending) {
+ for (unsigned Idx = 0, N = PendingInstantiations.size(); Idx < N;) {
+ ValueDecl *D = cast<ValueDecl>(GetDecl(PendingInstantiations[Idx++]));
+ SourceLocation Loc
+ = SourceLocation::getFromRawEncoding(PendingInstantiations[Idx++]);
+ Pending.push_back(std::make_pair(D, Loc));
+ }
+ PendingInstantiations.clear();
+}
+
void ASTReader::LoadSelector(Selector Sel) {
// It would be complicated to avoid reading the methods anyway. So don't.
ReadMethodPool(Sel);
}
-void ASTReader::SetIdentifierInfo(unsigned ID, IdentifierInfo *II) {
+void ASTReader::SetIdentifierInfo(IdentifierID ID, IdentifierInfo *II) {
assert(ID && "Non-zero identifier ID required");
assert(ID <= IdentifiersLoaded.size() && "identifier ID out of range");
IdentifiersLoaded[ID - 1] = II;
@@ -4500,7 +4724,7 @@ void ASTReader::SetIdentifierInfo(unsigned ID, IdentifierInfo *II) {
/// will not be placed onto the pending queue.
void
ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II,
- const llvm::SmallVectorImpl<uint32_t> &DeclIDs,
+ const SmallVectorImpl<uint32_t> &DeclIDs,
bool Nonrecursive) {
if (NumCurrentElementsDeserializing && !Nonrecursive) {
PendingIdentifierInfos.push_back(PendingIdentifierInfo());
@@ -4529,7 +4753,7 @@ ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II,
}
}
-IdentifierInfo *ASTReader::DecodeIdentifierInfo(unsigned ID) {
+IdentifierInfo *ASTReader::DecodeIdentifierInfo(IdentifierID ID) {
if (ID == 0)
return 0;
@@ -4538,21 +4762,13 @@ IdentifierInfo *ASTReader::DecodeIdentifierInfo(unsigned ID) {
return 0;
}
- assert(PP && "Forgot to set Preprocessor ?");
ID -= 1;
if (!IdentifiersLoaded[ID]) {
- unsigned Index = ID;
- const char *Str = 0;
- for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- PerFileData *F = Chain[N - I - 1];
- if (Index < F->LocalNumIdentifiers) {
- uint32_t Offset = F->IdentifierOffsets[Index];
- Str = F->IdentifierTableData + Offset;
- break;
- }
- Index -= F->LocalNumIdentifiers;
- }
- assert(Str && "Broken Chain");
+ GlobalIdentifierMapType::iterator I = GlobalIdentifierMap.find(ID + 1);
+ assert(I != GlobalIdentifierMap.end() && "Corrupted global identifier map");
+ Module *M = I->second;
+ unsigned Index = ID - M->BaseIdentifierID;
+ const char *Str = M->IdentifierTableData + M->IdentifierOffsets[Index];
// All of the strings in the AST file are preceded by a 16-bit length.
// Extract that 16-bit length to avoid having to execute strlen().
@@ -4563,7 +4779,7 @@ IdentifierInfo *ASTReader::DecodeIdentifierInfo(unsigned ID) {
unsigned StrLen = (((unsigned) StrLenPtr[0])
| (((unsigned) StrLenPtr[1]) << 8)) - 1;
IdentifiersLoaded[ID]
- = &PP->getIdentifierTable().get(llvm::StringRef(Str, StrLen));
+ = &PP.getIdentifierTable().get(StringRef(Str, StrLen));
if (DeserializationListener)
DeserializationListener->IdentifierRead(ID + 1, IdentifiersLoaded[ID]);
}
@@ -4571,11 +4787,31 @@ IdentifierInfo *ASTReader::DecodeIdentifierInfo(unsigned ID) {
return IdentifiersLoaded[ID];
}
-bool ASTReader::ReadSLocEntry(unsigned ID) {
+IdentifierInfo *ASTReader::getLocalIdentifier(Module &M, unsigned LocalID) {
+ return DecodeIdentifierInfo(getGlobalIdentifierID(M, LocalID));
+}
+
+IdentifierID ASTReader::getGlobalIdentifierID(Module &M, unsigned LocalID) {
+ if (LocalID < NUM_PREDEF_IDENT_IDS)
+ return LocalID;
+
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = M.IdentifierRemap.find(LocalID - NUM_PREDEF_IDENT_IDS);
+ assert(I != M.IdentifierRemap.end()
+ && "Invalid index into identifier index remap");
+
+ return LocalID + I->second;
+}
+
+bool ASTReader::ReadSLocEntry(int ID) {
return ReadSLocEntryRecord(ID) != Success;
}
-Selector ASTReader::DecodeSelector(unsigned ID) {
+Selector ASTReader::getLocalSelector(Module &M, unsigned LocalID) {
+ return DecodeSelector(getGlobalSelectorID(M, LocalID));
+}
+
+Selector ASTReader::DecodeSelector(serialization::SelectorID ID) {
if (ID == 0)
return Selector();
@@ -4586,25 +4822,21 @@ Selector ASTReader::DecodeSelector(unsigned ID) {
if (SelectorsLoaded[ID - 1].getAsOpaquePtr() == 0) {
// Load this selector from the selector table.
- unsigned Idx = ID - 1;
- for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- PerFileData &F = *Chain[N - I - 1];
- if (Idx < F.LocalNumSelectors) {
- ASTSelectorLookupTrait Trait(*this);
- SelectorsLoaded[ID - 1] =
- Trait.ReadKey(F.SelectorLookupTableData + F.SelectorOffsets[Idx], 0);
- if (DeserializationListener)
- DeserializationListener->SelectorRead(ID, SelectorsLoaded[ID - 1]);
- break;
- }
- Idx -= F.LocalNumSelectors;
- }
+ GlobalSelectorMapType::iterator I = GlobalSelectorMap.find(ID);
+ assert(I != GlobalSelectorMap.end() && "Corrupted global selector map");
+ Module &M = *I->second;
+ ASTSelectorLookupTrait Trait(*this, M);
+ unsigned Idx = ID - M.BaseSelectorID - NUM_PREDEF_SELECTOR_IDS;
+ SelectorsLoaded[ID - 1] =
+ Trait.ReadKey(M.SelectorLookupTableData + M.SelectorOffsets[Idx], 0);
+ if (DeserializationListener)
+ DeserializationListener->SelectorRead(ID, SelectorsLoaded[ID - 1]);
}
return SelectorsLoaded[ID - 1];
}
-Selector ASTReader::GetExternalSelector(uint32_t ID) {
+Selector ASTReader::GetExternalSelector(serialization::SelectorID ID) {
return DecodeSelector(ID);
}
@@ -4613,37 +4845,51 @@ uint32_t ASTReader::GetNumExternalSelectors() {
return getTotalNumSelectors() + 1;
}
+serialization::SelectorID
+ASTReader::getGlobalSelectorID(Module &M, unsigned LocalID) const {
+ if (LocalID < NUM_PREDEF_SELECTOR_IDS)
+ return LocalID;
+
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = M.SelectorRemap.find(LocalID - NUM_PREDEF_SELECTOR_IDS);
+ assert(I != M.SelectorRemap.end()
+ && "Invalid index into identifier index remap");
+
+ return LocalID + I->second;
+}
+
DeclarationName
-ASTReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) {
+ASTReader::ReadDeclarationName(Module &F,
+ const RecordData &Record, unsigned &Idx) {
DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];
switch (Kind) {
case DeclarationName::Identifier:
- return DeclarationName(GetIdentifierInfo(Record, Idx));
+ return DeclarationName(GetIdentifierInfo(F, Record, Idx));
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
- return DeclarationName(GetSelector(Record, Idx));
+ return DeclarationName(ReadSelector(F, Record, Idx));
case DeclarationName::CXXConstructorName:
- return Context->DeclarationNames.getCXXConstructorName(
- Context->getCanonicalType(GetType(Record[Idx++])));
+ return Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(readType(F, Record, Idx)));
case DeclarationName::CXXDestructorName:
- return Context->DeclarationNames.getCXXDestructorName(
- Context->getCanonicalType(GetType(Record[Idx++])));
+ return Context.DeclarationNames.getCXXDestructorName(
+ Context.getCanonicalType(readType(F, Record, Idx)));
case DeclarationName::CXXConversionFunctionName:
- return Context->DeclarationNames.getCXXConversionFunctionName(
- Context->getCanonicalType(GetType(Record[Idx++])));
+ return Context.DeclarationNames.getCXXConversionFunctionName(
+ Context.getCanonicalType(readType(F, Record, Idx)));
case DeclarationName::CXXOperatorName:
- return Context->DeclarationNames.getCXXOperatorName(
+ return Context.DeclarationNames.getCXXOperatorName(
(OverloadedOperatorKind)Record[Idx++]);
case DeclarationName::CXXLiteralOperatorName:
- return Context->DeclarationNames.getCXXLiteralOperatorName(
- GetIdentifierInfo(Record, Idx));
+ return Context.DeclarationNames.getCXXLiteralOperatorName(
+ GetIdentifierInfo(F, Record, Idx));
case DeclarationName::CXXUsingDirective:
return DeclarationName::getUsingDirectiveName();
@@ -4653,7 +4899,7 @@ ASTReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) {
return DeclarationName();
}
-void ASTReader::ReadDeclarationNameLoc(PerFileData &F,
+void ASTReader::ReadDeclarationNameLoc(Module &F,
DeclarationNameLoc &DNLoc,
DeclarationName Name,
const RecordData &Record, unsigned &Idx) {
@@ -4685,72 +4931,73 @@ void ASTReader::ReadDeclarationNameLoc(PerFileData &F,
}
}
-void ASTReader::ReadDeclarationNameInfo(PerFileData &F,
+void ASTReader::ReadDeclarationNameInfo(Module &F,
DeclarationNameInfo &NameInfo,
const RecordData &Record, unsigned &Idx) {
- NameInfo.setName(ReadDeclarationName(Record, Idx));
+ NameInfo.setName(ReadDeclarationName(F, Record, Idx));
NameInfo.setLoc(ReadSourceLocation(F, Record, Idx));
DeclarationNameLoc DNLoc;
ReadDeclarationNameLoc(F, DNLoc, NameInfo.getName(), Record, Idx);
NameInfo.setInfo(DNLoc);
}
-void ASTReader::ReadQualifierInfo(PerFileData &F, QualifierInfo &Info,
+void ASTReader::ReadQualifierInfo(Module &F, QualifierInfo &Info,
const RecordData &Record, unsigned &Idx) {
Info.QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, Idx);
unsigned NumTPLists = Record[Idx++];
Info.NumTemplParamLists = NumTPLists;
if (NumTPLists) {
- Info.TemplParamLists = new (*Context) TemplateParameterList*[NumTPLists];
+ Info.TemplParamLists = new (Context) TemplateParameterList*[NumTPLists];
for (unsigned i=0; i != NumTPLists; ++i)
Info.TemplParamLists[i] = ReadTemplateParameterList(F, Record, Idx);
}
}
TemplateName
-ASTReader::ReadTemplateName(PerFileData &F, const RecordData &Record,
+ASTReader::ReadTemplateName(Module &F, const RecordData &Record,
unsigned &Idx) {
TemplateName::NameKind Kind = (TemplateName::NameKind)Record[Idx++];
switch (Kind) {
case TemplateName::Template:
- return TemplateName(cast_or_null<TemplateDecl>(GetDecl(Record[Idx++])));
+ return TemplateName(ReadDeclAs<TemplateDecl>(F, Record, Idx));
case TemplateName::OverloadedTemplate: {
unsigned size = Record[Idx++];
UnresolvedSet<8> Decls;
while (size--)
- Decls.addDecl(cast<NamedDecl>(GetDecl(Record[Idx++])));
+ Decls.addDecl(ReadDeclAs<NamedDecl>(F, Record, Idx));
- return Context->getOverloadedTemplateName(Decls.begin(), Decls.end());
+ return Context.getOverloadedTemplateName(Decls.begin(), Decls.end());
}
case TemplateName::QualifiedTemplate: {
- NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx);
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx);
bool hasTemplKeyword = Record[Idx++];
- TemplateDecl *Template = cast<TemplateDecl>(GetDecl(Record[Idx++]));
- return Context->getQualifiedTemplateName(NNS, hasTemplKeyword, Template);
+ TemplateDecl *Template = ReadDeclAs<TemplateDecl>(F, Record, Idx);
+ return Context.getQualifiedTemplateName(NNS, hasTemplKeyword, Template);
}
case TemplateName::DependentTemplate: {
- NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx);
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx);
if (Record[Idx++]) // isIdentifier
- return Context->getDependentTemplateName(NNS,
- GetIdentifierInfo(Record, Idx));
- return Context->getDependentTemplateName(NNS,
+ return Context.getDependentTemplateName(NNS,
+ GetIdentifierInfo(F, Record,
+ Idx));
+ return Context.getDependentTemplateName(NNS,
(OverloadedOperatorKind)Record[Idx++]);
}
case TemplateName::SubstTemplateTemplateParm: {
TemplateTemplateParmDecl *param
- = cast_or_null<TemplateTemplateParmDecl>(GetDecl(Record[Idx++]));
+ = ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx);
if (!param) return TemplateName();
TemplateName replacement = ReadTemplateName(F, Record, Idx);
- return Context->getSubstTemplateTemplateParm(param, replacement);
+ return Context.getSubstTemplateTemplateParm(param, replacement);
}
case TemplateName::SubstTemplateTemplateParmPack: {
TemplateTemplateParmDecl *Param
- = cast_or_null<TemplateTemplateParmDecl>(GetDecl(Record[Idx++]));
+ = ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx);
if (!Param)
return TemplateName();
@@ -4758,28 +5005,27 @@ ASTReader::ReadTemplateName(PerFileData &F, const RecordData &Record,
if (ArgPack.getKind() != TemplateArgument::Pack)
return TemplateName();
- return Context->getSubstTemplateTemplateParmPack(Param, ArgPack);
+ return Context.getSubstTemplateTemplateParmPack(Param, ArgPack);
}
}
- assert(0 && "Unhandled template name kind!");
- return TemplateName();
+ llvm_unreachable("Unhandled template name kind!");
}
TemplateArgument
-ASTReader::ReadTemplateArgument(PerFileData &F,
+ASTReader::ReadTemplateArgument(Module &F,
const RecordData &Record, unsigned &Idx) {
TemplateArgument::ArgKind Kind = (TemplateArgument::ArgKind)Record[Idx++];
switch (Kind) {
case TemplateArgument::Null:
return TemplateArgument();
case TemplateArgument::Type:
- return TemplateArgument(GetType(Record[Idx++]));
+ return TemplateArgument(readType(F, Record, Idx));
case TemplateArgument::Declaration:
- return TemplateArgument(GetDecl(Record[Idx++]));
+ return TemplateArgument(ReadDecl(F, Record, Idx));
case TemplateArgument::Integral: {
llvm::APSInt Value = ReadAPSInt(Record, Idx);
- QualType T = GetType(Record[Idx++]);
+ QualType T = readType(F, Record, Idx);
return TemplateArgument(Value, T);
}
case TemplateArgument::Template:
@@ -4795,40 +5041,39 @@ ASTReader::ReadTemplateArgument(PerFileData &F,
return TemplateArgument(ReadExpr(F));
case TemplateArgument::Pack: {
unsigned NumArgs = Record[Idx++];
- TemplateArgument *Args = new (*Context) TemplateArgument[NumArgs];
+ TemplateArgument *Args = new (Context) TemplateArgument[NumArgs];
for (unsigned I = 0; I != NumArgs; ++I)
Args[I] = ReadTemplateArgument(F, Record, Idx);
return TemplateArgument(Args, NumArgs);
}
}
- assert(0 && "Unhandled template argument kind!");
- return TemplateArgument();
+ llvm_unreachable("Unhandled template argument kind!");
}
TemplateParameterList *
-ASTReader::ReadTemplateParameterList(PerFileData &F,
+ASTReader::ReadTemplateParameterList(Module &F,
const RecordData &Record, unsigned &Idx) {
SourceLocation TemplateLoc = ReadSourceLocation(F, Record, Idx);
SourceLocation LAngleLoc = ReadSourceLocation(F, Record, Idx);
SourceLocation RAngleLoc = ReadSourceLocation(F, Record, Idx);
unsigned NumParams = Record[Idx++];
- llvm::SmallVector<NamedDecl *, 16> Params;
+ SmallVector<NamedDecl *, 16> Params;
Params.reserve(NumParams);
while (NumParams--)
- Params.push_back(cast<NamedDecl>(GetDecl(Record[Idx++])));
+ Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx));
TemplateParameterList* TemplateParams =
- TemplateParameterList::Create(*Context, TemplateLoc, LAngleLoc,
+ TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc,
Params.data(), Params.size(), RAngleLoc);
return TemplateParams;
}
void
ASTReader::
-ReadTemplateArgumentList(llvm::SmallVector<TemplateArgument, 8> &TemplArgs,
- PerFileData &F, const RecordData &Record,
+ReadTemplateArgumentList(SmallVector<TemplateArgument, 8> &TemplArgs,
+ Module &F, const RecordData &Record,
unsigned &Idx) {
unsigned NumTemplateArgs = Record[Idx++];
TemplArgs.reserve(NumTemplateArgs);
@@ -4837,18 +5082,18 @@ ReadTemplateArgumentList(llvm::SmallVector<TemplateArgument, 8> &TemplArgs,
}
/// \brief Read a UnresolvedSet structure.
-void ASTReader::ReadUnresolvedSet(UnresolvedSetImpl &Set,
+void ASTReader::ReadUnresolvedSet(Module &F, UnresolvedSetImpl &Set,
const RecordData &Record, unsigned &Idx) {
unsigned NumDecls = Record[Idx++];
while (NumDecls--) {
- NamedDecl *D = cast<NamedDecl>(GetDecl(Record[Idx++]));
+ NamedDecl *D = ReadDeclAs<NamedDecl>(F, Record, Idx);
AccessSpecifier AS = (AccessSpecifier)Record[Idx++];
Set.addDecl(D, AS);
}
}
CXXBaseSpecifier
-ASTReader::ReadCXXBaseSpecifier(PerFileData &F,
+ASTReader::ReadCXXBaseSpecifier(Module &F,
const RecordData &Record, unsigned &Idx) {
bool isVirtual = static_cast<bool>(Record[Idx++]);
bool isBaseOfClass = static_cast<bool>(Record[Idx++]);
@@ -4864,15 +5109,13 @@ ASTReader::ReadCXXBaseSpecifier(PerFileData &F,
}
std::pair<CXXCtorInitializer **, unsigned>
-ASTReader::ReadCXXCtorInitializers(PerFileData &F, const RecordData &Record,
+ASTReader::ReadCXXCtorInitializers(Module &F, const RecordData &Record,
unsigned &Idx) {
CXXCtorInitializer **CtorInitializers = 0;
unsigned NumInitializers = Record[Idx++];
if (NumInitializers) {
- ASTContext &C = *getContext();
-
CtorInitializers
- = new (C) CXXCtorInitializer*[NumInitializers];
+ = new (Context) CXXCtorInitializer*[NumInitializers];
for (unsigned i=0; i != NumInitializers; ++i) {
TypeSourceInfo *BaseClassInfo = 0;
bool IsBaseVirtual = false;
@@ -4888,15 +5131,15 @@ ASTReader::ReadCXXCtorInitializers(PerFileData &F, const RecordData &Record,
break;
case CTOR_INITIALIZER_DELEGATING:
- Target = cast<CXXConstructorDecl>(GetDecl(Record[Idx++]));
+ Target = ReadDeclAs<CXXConstructorDecl>(F, Record, Idx);
break;
case CTOR_INITIALIZER_MEMBER:
- Member = cast<FieldDecl>(GetDecl(Record[Idx++]));
+ Member = ReadDeclAs<FieldDecl>(F, Record, Idx);
break;
case CTOR_INITIALIZER_INDIRECT_MEMBER:
- IndirectMember = cast<IndirectFieldDecl>(GetDecl(Record[Idx++]));
+ IndirectMember = ReadDeclAs<IndirectFieldDecl>(F, Record, Idx);
break;
}
@@ -4906,34 +5149,34 @@ ASTReader::ReadCXXCtorInitializers(PerFileData &F, const RecordData &Record,
SourceLocation RParenLoc = ReadSourceLocation(F, Record, Idx);
bool IsWritten = Record[Idx++];
unsigned SourceOrderOrNumArrayIndices;
- llvm::SmallVector<VarDecl *, 8> Indices;
+ SmallVector<VarDecl *, 8> Indices;
if (IsWritten) {
SourceOrderOrNumArrayIndices = Record[Idx++];
} else {
SourceOrderOrNumArrayIndices = Record[Idx++];
Indices.reserve(SourceOrderOrNumArrayIndices);
for (unsigned i=0; i != SourceOrderOrNumArrayIndices; ++i)
- Indices.push_back(cast<VarDecl>(GetDecl(Record[Idx++])));
+ Indices.push_back(ReadDeclAs<VarDecl>(F, Record, Idx));
}
CXXCtorInitializer *BOMInit;
if (Type == CTOR_INITIALIZER_BASE) {
- BOMInit = new (C) CXXCtorInitializer(C, BaseClassInfo, IsBaseVirtual,
+ BOMInit = new (Context) CXXCtorInitializer(Context, BaseClassInfo, IsBaseVirtual,
LParenLoc, Init, RParenLoc,
MemberOrEllipsisLoc);
} else if (Type == CTOR_INITIALIZER_DELEGATING) {
- BOMInit = new (C) CXXCtorInitializer(C, MemberOrEllipsisLoc, LParenLoc,
+ BOMInit = new (Context) CXXCtorInitializer(Context, MemberOrEllipsisLoc, LParenLoc,
Target, Init, RParenLoc);
} else if (IsWritten) {
if (Member)
- BOMInit = new (C) CXXCtorInitializer(C, Member, MemberOrEllipsisLoc,
+ BOMInit = new (Context) CXXCtorInitializer(Context, Member, MemberOrEllipsisLoc,
LParenLoc, Init, RParenLoc);
else
- BOMInit = new (C) CXXCtorInitializer(C, IndirectMember,
+ BOMInit = new (Context) CXXCtorInitializer(Context, IndirectMember,
MemberOrEllipsisLoc, LParenLoc,
Init, RParenLoc);
} else {
- BOMInit = CXXCtorInitializer::Create(C, Member, MemberOrEllipsisLoc,
+ BOMInit = CXXCtorInitializer::Create(Context, Member, MemberOrEllipsisLoc,
LParenLoc, Init, RParenLoc,
Indices.data(), Indices.size());
}
@@ -4948,7 +5191,8 @@ ASTReader::ReadCXXCtorInitializers(PerFileData &F, const RecordData &Record,
}
NestedNameSpecifier *
-ASTReader::ReadNestedNameSpecifier(const RecordData &Record, unsigned &Idx) {
+ASTReader::ReadNestedNameSpecifier(Module &F,
+ const RecordData &Record, unsigned &Idx) {
unsigned N = Record[Idx++];
NestedNameSpecifier *NNS = 0, *Prev = 0;
for (unsigned I = 0; I != N; ++I) {
@@ -4956,37 +5200,36 @@ ASTReader::ReadNestedNameSpecifier(const RecordData &Record, unsigned &Idx) {
= (NestedNameSpecifier::SpecifierKind)Record[Idx++];
switch (Kind) {
case NestedNameSpecifier::Identifier: {
- IdentifierInfo *II = GetIdentifierInfo(Record, Idx);
- NNS = NestedNameSpecifier::Create(*Context, Prev, II);
+ IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx);
+ NNS = NestedNameSpecifier::Create(Context, Prev, II);
break;
}
case NestedNameSpecifier::Namespace: {
- NamespaceDecl *NS = cast<NamespaceDecl>(GetDecl(Record[Idx++]));
- NNS = NestedNameSpecifier::Create(*Context, Prev, NS);
+ NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx);
+ NNS = NestedNameSpecifier::Create(Context, Prev, NS);
break;
}
case NestedNameSpecifier::NamespaceAlias: {
- NamespaceAliasDecl *Alias
- = cast<NamespaceAliasDecl>(GetDecl(Record[Idx++]));
- NNS = NestedNameSpecifier::Create(*Context, Prev, Alias);
+ NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx);
+ NNS = NestedNameSpecifier::Create(Context, Prev, Alias);
break;
}
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
- const Type *T = GetType(Record[Idx++]).getTypePtrOrNull();
+ const Type *T = readType(F, Record, Idx).getTypePtrOrNull();
if (!T)
return 0;
bool Template = Record[Idx++];
- NNS = NestedNameSpecifier::Create(*Context, Prev, Template, T);
+ NNS = NestedNameSpecifier::Create(Context, Prev, Template, T);
break;
}
case NestedNameSpecifier::Global: {
- NNS = NestedNameSpecifier::GlobalSpecifier(*Context);
+ NNS = NestedNameSpecifier::GlobalSpecifier(Context);
// No associated value, and there can't be a prefix.
break;
}
@@ -4997,7 +5240,7 @@ ASTReader::ReadNestedNameSpecifier(const RecordData &Record, unsigned &Idx) {
}
NestedNameSpecifierLoc
-ASTReader::ReadNestedNameSpecifierLoc(PerFileData &F, const RecordData &Record,
+ASTReader::ReadNestedNameSpecifierLoc(Module &F, const RecordData &Record,
unsigned &Idx) {
unsigned N = Record[Idx++];
NestedNameSpecifierLocBuilder Builder;
@@ -5006,24 +5249,23 @@ ASTReader::ReadNestedNameSpecifierLoc(PerFileData &F, const RecordData &Record,
= (NestedNameSpecifier::SpecifierKind)Record[Idx++];
switch (Kind) {
case NestedNameSpecifier::Identifier: {
- IdentifierInfo *II = GetIdentifierInfo(Record, Idx);
+ IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx);
SourceRange Range = ReadSourceRange(F, Record, Idx);
- Builder.Extend(*Context, II, Range.getBegin(), Range.getEnd());
+ Builder.Extend(Context, II, Range.getBegin(), Range.getEnd());
break;
}
case NestedNameSpecifier::Namespace: {
- NamespaceDecl *NS = cast<NamespaceDecl>(GetDecl(Record[Idx++]));
+ NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx);
SourceRange Range = ReadSourceRange(F, Record, Idx);
- Builder.Extend(*Context, NS, Range.getBegin(), Range.getEnd());
+ Builder.Extend(Context, NS, Range.getBegin(), Range.getEnd());
break;
}
case NestedNameSpecifier::NamespaceAlias: {
- NamespaceAliasDecl *Alias
- = cast<NamespaceAliasDecl>(GetDecl(Record[Idx++]));
+ NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx);
SourceRange Range = ReadSourceRange(F, Record, Idx);
- Builder.Extend(*Context, Alias, Range.getBegin(), Range.getEnd());
+ Builder.Extend(Context, Alias, Range.getBegin(), Range.getEnd());
break;
}
@@ -5036,7 +5278,7 @@ ASTReader::ReadNestedNameSpecifierLoc(PerFileData &F, const RecordData &Record,
SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx);
// FIXME: 'template' keyword location not saved anywhere, so we fake it.
- Builder.Extend(*Context,
+ Builder.Extend(Context,
Template? T->getTypeLoc().getBeginLoc() : SourceLocation(),
T->getTypeLoc(), ColonColonLoc);
break;
@@ -5044,17 +5286,17 @@ ASTReader::ReadNestedNameSpecifierLoc(PerFileData &F, const RecordData &Record,
case NestedNameSpecifier::Global: {
SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx);
- Builder.MakeGlobal(*Context, ColonColonLoc);
+ Builder.MakeGlobal(Context, ColonColonLoc);
break;
}
}
}
- return Builder.getWithLocInContext(*Context);
+ return Builder.getWithLocInContext(Context);
}
SourceRange
-ASTReader::ReadSourceRange(PerFileData &F, const RecordData &Record,
+ASTReader::ReadSourceRange(Module &F, const RecordData &Record,
unsigned &Idx) {
SourceLocation beg = ReadSourceLocation(F, Record, Idx);
SourceLocation end = ReadSourceLocation(F, Record, Idx);
@@ -5101,10 +5343,11 @@ VersionTuple ASTReader::ReadVersionTuple(const RecordData &Record,
return VersionTuple(Major, Minor - 1, Subminor - 1);
}
-CXXTemporary *ASTReader::ReadCXXTemporary(const RecordData &Record,
+CXXTemporary *ASTReader::ReadCXXTemporary(Module &F,
+ const RecordData &Record,
unsigned &Idx) {
- CXXDestructorDecl *Decl = cast<CXXDestructorDecl>(GetDecl(Record[Idx++]));
- return CXXTemporary::Create(*Context, Decl);
+ CXXDestructorDecl *Decl = ReadDeclAs<CXXDestructorDecl>(F, Record, Idx);
+ return CXXTemporary::Create(Context, Decl);
}
DiagnosticBuilder ASTReader::Diag(unsigned DiagID) {
@@ -5118,8 +5361,7 @@ DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) {
/// \brief Retrieve the identifier table associated with the
/// preprocessor.
IdentifierTable &ASTReader::getIdentifierTable() {
- assert(PP && "Forgot to set Preprocessor ?");
- return PP->getIdentifierTable();
+ return PP.getIdentifierTable();
}
/// \brief Record that the given ID maps to the given switch-case
@@ -5169,56 +5411,29 @@ void ASTReader::FinishedDeserializing() {
--NumCurrentElementsDeserializing;
}
-ASTReader::ASTReader(Preprocessor &PP, ASTContext *Context,
- const char *isysroot, bool DisableValidation,
+ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
+ StringRef isysroot, bool DisableValidation,
bool DisableStatCache)
: Listener(new PCHValidator(PP, *this)), DeserializationListener(0),
SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()),
- Diags(PP.getDiagnostics()), SemaObj(0), PP(&PP), Context(Context),
- Consumer(0), isysroot(isysroot), DisableValidation(DisableValidation),
+ Diags(PP.getDiagnostics()), SemaObj(0), PP(PP), Context(Context),
+ Consumer(0), ModuleMgr(FileMgr.getFileSystemOptions()),
+ RelocatablePCH(false), isysroot(isysroot),
+ DisableValidation(DisableValidation),
DisableStatCache(DisableStatCache), NumStatHits(0), NumStatMisses(0),
- NumSLocEntriesRead(0), TotalNumSLocEntries(0), NextSLocOffset(0),
+ NumSLocEntriesRead(0), TotalNumSLocEntries(0),
NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0),
TotalNumMacros(0), NumSelectorsRead(0), NumMethodPoolEntriesRead(0),
NumMethodPoolMisses(0), TotalNumMethodPoolEntries(0),
NumLexicalDeclContextsRead(0), TotalLexicalDeclContexts(0),
- NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0),
- NumCurrentElementsDeserializing(0)
+ NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0),
+ TotalModulesSizeInBits(0), NumCurrentElementsDeserializing(0),
+ NumCXXBaseSpecifiersLoaded(0)
{
- RelocatablePCH = false;
-}
-
-ASTReader::ASTReader(SourceManager &SourceMgr, FileManager &FileMgr,
- Diagnostic &Diags, const char *isysroot,
- bool DisableValidation, bool DisableStatCache)
- : DeserializationListener(0), SourceMgr(SourceMgr), FileMgr(FileMgr),
- Diags(Diags), SemaObj(0), PP(0), Context(0), Consumer(0),
- isysroot(isysroot), DisableValidation(DisableValidation),
- DisableStatCache(DisableStatCache), NumStatHits(0), NumStatMisses(0),
- NumSLocEntriesRead(0), TotalNumSLocEntries(0),
- NextSLocOffset(0), NumStatementsRead(0), TotalNumStatements(0),
- NumMacrosRead(0), TotalNumMacros(0), NumSelectorsRead(0),
- NumMethodPoolEntriesRead(0), NumMethodPoolMisses(0),
- TotalNumMethodPoolEntries(0), NumLexicalDeclContextsRead(0),
- TotalLexicalDeclContexts(0), NumVisibleDeclContextsRead(0),
- TotalVisibleDeclContexts(0), NumCurrentElementsDeserializing(0) {
- RelocatablePCH = false;
+ SourceMgr.setExternalSLocEntrySource(this);
}
ASTReader::~ASTReader() {
- for (unsigned i = 0, e = Chain.size(); i != e; ++i)
- delete Chain[e - i - 1];
- // Delete all visible decl lookup tables
- for (DeclContextOffsetsMap::iterator I = DeclContextOffsets.begin(),
- E = DeclContextOffsets.end();
- I != E; ++I) {
- for (DeclContextInfos::iterator J = I->second.begin(), F = I->second.end();
- J != F; ++J) {
- if (J->NameLookupTableData)
- delete static_cast<ASTDeclContextNameLookupTable*>(
- J->NameLookupTableData);
- }
- }
for (DeclContextVisibleUpdatesPending::iterator
I = PendingVisibleUpdates.begin(),
E = PendingVisibleUpdates.end();
@@ -5226,27 +5441,6 @@ ASTReader::~ASTReader() {
for (DeclContextVisibleUpdates::iterator J = I->second.begin(),
F = I->second.end();
J != F; ++J)
- delete static_cast<ASTDeclContextNameLookupTable*>(*J);
- }
-}
-
-ASTReader::PerFileData::PerFileData(ASTFileType Ty)
- : Type(Ty), SizeInBits(0), LocalNumSLocEntries(0), SLocOffsets(0),
- SLocFileOffsets(0), LocalSLocSize(0),
- LocalNumIdentifiers(0), IdentifierOffsets(0), IdentifierTableData(0),
- IdentifierLookupTable(0), LocalNumMacroDefinitions(0),
- MacroDefinitionOffsets(0),
- LocalNumHeaderFileInfos(0), HeaderFileInfoTableData(0),
- HeaderFileInfoTable(0),
- LocalNumSelectors(0), SelectorOffsets(0),
- SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0),
- DeclOffsets(0), LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(0),
- LocalNumTypes(0), TypeOffsets(0), StatCache(0),
- NumPreallocatedPreprocessingEntities(0), NextInSource(0)
-{}
-
-ASTReader::PerFileData::~PerFileData() {
- delete static_cast<ASTIdentifierLookupTable *>(IdentifierLookupTable);
- delete static_cast<HeaderFileInfoLookupTable *>(HeaderFileInfoTable);
- delete static_cast<ASTSelectorLookupTable *>(SelectorLookupTable);
+ delete static_cast<ASTDeclContextNameLookupTable*>(J->first);
+ }
}
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 24ab544dcd1c..6cc3f0a70bc1 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -14,6 +14,7 @@
#include "ASTCommon.h"
#include "clang/Serialization/ASTReader.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclVisitor.h"
@@ -31,7 +32,7 @@ using namespace clang::serialization;
namespace clang {
class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> {
ASTReader &Reader;
- ASTReader::PerFileData &F;
+ Module &F;
llvm::BitstreamCursor &Cursor;
const DeclID ThisDeclID;
typedef ASTReader::RecordData RecordData;
@@ -43,23 +44,42 @@ namespace clang {
DeclID LexicalDeclContextIDForTemplateParmDecl;
uint64_t GetCurrentCursorOffset();
+
SourceLocation ReadSourceLocation(const RecordData &R, unsigned &I) {
return Reader.ReadSourceLocation(F, R, I);
}
+
SourceRange ReadSourceRange(const RecordData &R, unsigned &I) {
return Reader.ReadSourceRange(F, R, I);
}
+
TypeSourceInfo *GetTypeSourceInfo(const RecordData &R, unsigned &I) {
return Reader.GetTypeSourceInfo(F, R, I);
}
+
+ serialization::DeclID ReadDeclID(const RecordData &R, unsigned &I) {
+ return Reader.ReadDeclID(F, R, I);
+ }
+
+ Decl *ReadDecl(const RecordData &R, unsigned &I) {
+ return Reader.ReadDecl(F, R, I);
+ }
+
+ template<typename T>
+ T *ReadDeclAs(const RecordData &R, unsigned &I) {
+ return Reader.ReadDeclAs<T>(F, R, I);
+ }
+
void ReadQualifierInfo(QualifierInfo &Info,
const RecordData &R, unsigned &I) {
Reader.ReadQualifierInfo(F, Info, R, I);
}
+
void ReadDeclarationNameLoc(DeclarationNameLoc &DNLoc, DeclarationName Name,
const RecordData &R, unsigned &I) {
Reader.ReadDeclarationNameLoc(F, DNLoc, Name, R, I);
}
+
void ReadDeclarationNameInfo(DeclarationNameInfo &NameInfo,
const RecordData &R, unsigned &I) {
Reader.ReadDeclarationNameInfo(F, NameInfo, R, I);
@@ -72,7 +92,7 @@ namespace clang {
CXXRecordDecl *DefinitionDecl,
const RecordData &Record, unsigned &Idx);
public:
- ASTDeclReader(ASTReader &Reader, ASTReader::PerFileData &F,
+ ASTDeclReader(ASTReader &Reader, Module &F,
llvm::BitstreamCursor &Cursor, DeclID thisDeclID,
const RecordData &Record, unsigned &Idx)
: Reader(Reader), F(F), Cursor(Cursor), ThisDeclID(thisDeclID),
@@ -82,9 +102,14 @@ namespace clang {
void Visit(Decl *D);
- void UpdateDecl(Decl *D, ASTReader::PerFileData &Module,
+ void UpdateDecl(Decl *D, Module &Module,
const RecordData &Record);
+ static void setNextObjCCategory(ObjCCategoryDecl *Cat,
+ ObjCCategoryDecl *Next) {
+ Cat->NextClassCategory = Next;
+ }
+
void VisitDecl(Decl *D);
void VisitTranslationUnitDecl(TranslationUnitDecl *TU);
void VisitNamedDecl(NamedDecl *ND);
@@ -104,6 +129,8 @@ namespace clang {
ClassTemplateSpecializationDecl *D);
void VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D);
+ void VisitClassScopeFunctionSpecializationDecl(
+ ClassScopeFunctionSpecializationDecl *D);
void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
void VisitValueDecl(ValueDecl *VD);
void VisitEnumConstantDecl(EnumConstantDecl *ECD);
@@ -159,16 +186,7 @@ namespace clang {
}
uint64_t ASTDeclReader::GetCurrentCursorOffset() {
- uint64_t Off = 0;
- for (unsigned I = 0, N = Reader.Chain.size(); I != N; ++I) {
- ASTReader::PerFileData &F = *Reader.Chain[N - I - 1];
- if (&Cursor == &F.DeclsCursor) {
- Off += F.DeclsCursor.GetCurrentBitNo();
- break;
- }
- Off += F.SizeInBits;
- }
- return Off;
+ return F.DeclsCursor.GetCurrentBitNo() + F.GlobalBitOffset;
}
void ASTDeclReader::Visit(Decl *D) {
@@ -211,13 +229,12 @@ 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 = Record[Idx++];
- LexicalDeclContextIDForTemplateParmDecl = Record[Idx++];
- D->setDeclContext(Reader.getContext()->getTranslationUnitDecl());
+ DeclContextIDForTemplateParmDecl = ReadDeclID(Record, Idx);
+ LexicalDeclContextIDForTemplateParmDecl = ReadDeclID(Record, Idx);
+ D->setDeclContext(Reader.getContext().getTranslationUnitDecl());
} else {
- D->setDeclContext(cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++])));
- D->setLexicalDeclContext(
- cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++])));
+ D->setDeclContext(ReadDeclAs<DeclContext>(Record, Idx));
+ D->setLexicalDeclContext(ReadDeclAs<DeclContext>(Record, Idx));
}
D->setLocation(ReadSourceLocation(Record, Idx));
D->setInvalidDecl(Record[Idx++]);
@@ -230,25 +247,24 @@ void ASTDeclReader::VisitDecl(Decl *D) {
D->setUsed(Record[Idx++]);
D->setReferenced(Record[Idx++]);
D->setAccess((AccessSpecifier)Record[Idx++]);
- D->setPCHLevel(Record[Idx++] + (F.Type <= ASTReader::PCH));
+ D->FromASTFile = true;
+ D->ModulePrivate = Record[Idx++];
}
void ASTDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
- VisitDecl(TU);
- TU->setAnonymousNamespace(
- cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++])));
+ llvm_unreachable("Translation units are not serialized");
}
void ASTDeclReader::VisitNamedDecl(NamedDecl *ND) {
VisitDecl(ND);
- ND->setDeclName(Reader.ReadDeclarationName(Record, Idx));
+ ND->setDeclName(Reader.ReadDeclarationName(F, Record, Idx));
}
void ASTDeclReader::VisitTypeDecl(TypeDecl *TD) {
VisitNamedDecl(TD);
TD->setLocStart(ReadSourceLocation(Record, Idx));
// Delay type reading until after we have fully initialized the decl.
- TypeIDForTypeDecl = Record[Idx++];
+ TypeIDForTypeDecl = Reader.getGlobalTypeID(F, Record[Idx++]);
}
void ASTDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
@@ -266,16 +282,16 @@ void ASTDeclReader::VisitTagDecl(TagDecl *TD) {
VisitRedeclarable(TD);
TD->IdentifierNamespace = Record[Idx++];
TD->setTagKind((TagDecl::TagKind)Record[Idx++]);
- TD->setDefinition(Record[Idx++]);
+ TD->setCompleteDefinition(Record[Idx++]);
TD->setEmbeddedInDeclarator(Record[Idx++]);
+ TD->setFreeStanding(Record[Idx++]);
TD->setRBraceLoc(ReadSourceLocation(Record, Idx));
if (Record[Idx++]) { // hasExtInfo
- TagDecl::ExtInfo *Info = new (*Reader.getContext()) TagDecl::ExtInfo();
+ TagDecl::ExtInfo *Info = new (Reader.getContext()) TagDecl::ExtInfo();
ReadQualifierInfo(*Info, Record, Idx);
TD->TypedefNameDeclOrQualifier = Info;
} else
- TD->setTypedefNameForAnonDecl(
- cast_or_null<TypedefNameDecl>(Reader.GetDecl(Record[Idx++])));
+ TD->setTypedefNameForAnonDecl(ReadDeclAs<TypedefNameDecl>(Record, Idx));
}
void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
@@ -283,15 +299,14 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
if (TypeSourceInfo *TI = Reader.GetTypeSourceInfo(F, Record, Idx))
ED->setIntegerTypeSourceInfo(TI);
else
- ED->setIntegerType(Reader.GetType(Record[Idx++]));
- ED->setPromotionType(Reader.GetType(Record[Idx++]));
+ ED->setIntegerType(Reader.readType(F, Record, Idx));
+ ED->setPromotionType(Reader.readType(F, Record, Idx));
ED->setNumPositiveBits(Record[Idx++]);
ED->setNumNegativeBits(Record[Idx++]);
ED->IsScoped = Record[Idx++];
ED->IsScopedUsingClassTag = Record[Idx++];
ED->IsFixed = Record[Idx++];
- ED->setInstantiationOfMemberEnum(
- cast_or_null<EnumDecl>(Reader.GetDecl(Record[Idx++])));
+ ED->setInstantiationOfMemberEnum(ReadDeclAs<EnumDecl>(Record, Idx));
}
void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) {
@@ -303,7 +318,7 @@ void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) {
void ASTDeclReader::VisitValueDecl(ValueDecl *VD) {
VisitNamedDecl(VD);
- VD->setType(Reader.GetType(Record[Idx++]));
+ VD->setType(Reader.readType(F, Record, Idx));
}
void ASTDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) {
@@ -318,7 +333,7 @@ void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
DD->setInnerLocStart(ReadSourceLocation(Record, Idx));
if (Record[Idx++]) { // hasExtInfo
DeclaratorDecl::ExtInfo *Info
- = new (*Reader.getContext()) DeclaratorDecl::ExtInfo();
+ = new (Reader.getContext()) DeclaratorDecl::ExtInfo();
ReadQualifierInfo(*Info, Record, Idx);
DD->DeclInfo = Info;
}
@@ -331,35 +346,35 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
ReadDeclarationNameLoc(FD->DNLoc, FD->getDeclName(), Record, Idx);
FD->IdentifierNamespace = Record[Idx++];
switch ((FunctionDecl::TemplatedKind)Record[Idx++]) {
- default: assert(false && "Unhandled TemplatedKind!");
- break;
+ default: llvm_unreachable("Unhandled TemplatedKind!");
case FunctionDecl::TK_NonTemplate:
break;
case FunctionDecl::TK_FunctionTemplate:
- FD->setDescribedFunctionTemplate(
- cast<FunctionTemplateDecl>(Reader.GetDecl(Record[Idx++])));
+ FD->setDescribedFunctionTemplate(ReadDeclAs<FunctionTemplateDecl>(Record,
+ Idx));
break;
case FunctionDecl::TK_MemberSpecialization: {
- FunctionDecl *InstFD = cast<FunctionDecl>(Reader.GetDecl(Record[Idx++]));
+ FunctionDecl *InstFD = ReadDeclAs<FunctionDecl>(Record, Idx);
TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
SourceLocation POI = ReadSourceLocation(Record, Idx);
- FD->setInstantiationOfMemberFunction(*Reader.getContext(), InstFD, TSK);
+ FD->setInstantiationOfMemberFunction(Reader.getContext(), InstFD, TSK);
FD->getMemberSpecializationInfo()->setPointOfInstantiation(POI);
break;
}
case FunctionDecl::TK_FunctionTemplateSpecialization: {
- FunctionTemplateDecl *Template
- = cast<FunctionTemplateDecl>(Reader.GetDecl(Record[Idx++]));
+ FunctionTemplateDecl *Template = ReadDeclAs<FunctionTemplateDecl>(Record,
+ Idx);
TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
// Template arguments.
- llvm::SmallVector<TemplateArgument, 8> TemplArgs;
+ SmallVector<TemplateArgument, 8> TemplArgs;
Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx);
// Template args as written.
- llvm::SmallVector<TemplateArgumentLoc, 8> TemplArgLocs;
+ SmallVector<TemplateArgumentLoc, 8> TemplArgLocs;
SourceLocation LAngleLoc, RAngleLoc;
- if (Record[Idx++]) { // TemplateArgumentsAsWritten != 0
+ bool HasTemplateArgumentsAsWritten = Record[Idx++];
+ if (HasTemplateArgumentsAsWritten) {
unsigned NumTemplateArgLocs = Record[Idx++];
TemplArgLocs.reserve(NumTemplateArgLocs);
for (unsigned i=0; i != NumTemplateArgLocs; ++i)
@@ -372,24 +387,24 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
SourceLocation POI = ReadSourceLocation(Record, Idx);
- ASTContext &C = *Reader.getContext();
+ ASTContext &C = Reader.getContext();
TemplateArgumentList *TemplArgList
= TemplateArgumentList::CreateCopy(C, TemplArgs.data(), TemplArgs.size());
- TemplateArgumentListInfo *TemplArgsInfo
- = new (C) TemplateArgumentListInfo(LAngleLoc, RAngleLoc);
+ TemplateArgumentListInfo TemplArgsInfo(LAngleLoc, RAngleLoc);
for (unsigned i=0, e = TemplArgLocs.size(); i != e; ++i)
- TemplArgsInfo->addArgument(TemplArgLocs[i]);
+ TemplArgsInfo.addArgument(TemplArgLocs[i]);
FunctionTemplateSpecializationInfo *FTInfo
= FunctionTemplateSpecializationInfo::Create(C, FD, Template, TSK,
TemplArgList,
- TemplArgsInfo, POI);
+ HasTemplateArgumentsAsWritten ? &TemplArgsInfo : 0,
+ POI);
FD->TemplateOrSpecialization = FTInfo;
if (FD->isCanonicalDecl()) { // if canonical add to template's set.
// The template that contains the specializations set. It's not safe to
// use getCanonicalDecl on Template since it may still be initializing.
FunctionTemplateDecl *CanonTemplate
- = cast<FunctionTemplateDecl>(Reader.GetDecl(Record[Idx++]));
+ = ReadDeclAs<FunctionTemplateDecl>(Record, Idx);
// Get the InsertPos by FindNodeOrInsertPos() instead of calling
// InsertNode(FTInfo) directly to avoid the getASTContext() call in
// FunctionTemplateSpecializationInfo's Profile().
@@ -410,7 +425,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
UnresolvedSet<8> TemplDecls;
unsigned NumTemplates = Record[Idx++];
while (NumTemplates--)
- TemplDecls.addDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++])));
+ TemplDecls.addDecl(ReadDeclAs<NamedDecl>(Record, Idx));
// Templates args.
TemplateArgumentListInfo TemplArgs;
@@ -420,7 +435,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
TemplArgs.setLAngleLoc(ReadSourceLocation(Record, Idx));
TemplArgs.setRAngleLoc(ReadSourceLocation(Record, Idx));
- FD->setDependentTemplateSpecialization(*Reader.getContext(),
+ FD->setDependentTemplateSpecialization(Reader.getContext(),
TemplDecls, TemplArgs);
break;
}
@@ -442,15 +457,16 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->IsDefaulted = Record[Idx++];
FD->IsExplicitlyDefaulted = Record[Idx++];
FD->HasImplicitReturnZero = Record[Idx++];
+ FD->IsConstexpr = Record[Idx++];
FD->EndRangeLoc = ReadSourceLocation(Record, Idx);
// Read in the parameters.
unsigned NumParams = Record[Idx++];
- llvm::SmallVector<ParmVarDecl *, 16> Params;
+ SmallVector<ParmVarDecl *, 16> Params;
Params.reserve(NumParams);
for (unsigned I = 0; I != NumParams; ++I)
- Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
- FD->setParams(*Reader.getContext(), Params.data(), NumParams);
+ Params.push_back(ReadDeclAs<ParmVarDecl>(Record, Idx));
+ FD->setParams(Reader.getContext(), Params);
}
void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
@@ -459,77 +475,87 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
// In practice, this won't be executed (since method definitions
// don't occur in header files).
MD->setBody(Reader.ReadStmt(F));
- MD->setSelfDecl(cast<ImplicitParamDecl>(Reader.GetDecl(Record[Idx++])));
- MD->setCmdDecl(cast<ImplicitParamDecl>(Reader.GetDecl(Record[Idx++])));
+ MD->setSelfDecl(ReadDeclAs<ImplicitParamDecl>(Record, Idx));
+ MD->setCmdDecl(ReadDeclAs<ImplicitParamDecl>(Record, Idx));
}
MD->setInstanceMethod(Record[Idx++]);
MD->setVariadic(Record[Idx++]);
MD->setSynthesized(Record[Idx++]);
MD->setDefined(Record[Idx++]);
+
+ MD->IsRedeclaration = Record[Idx++];
+ MD->HasRedeclaration = Record[Idx++];
+ if (MD->HasRedeclaration)
+ Reader.getContext().setObjCMethodRedeclaration(MD,
+ ReadDeclAs<ObjCMethodDecl>(Record, Idx));
+
MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record[Idx++]);
MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]);
MD->SetRelatedResultType(Record[Idx++]);
- MD->setNumSelectorArgs(unsigned(Record[Idx++]));
- MD->setResultType(Reader.GetType(Record[Idx++]));
+ MD->setResultType(Reader.readType(F, Record, Idx));
MD->setResultTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
MD->setEndLoc(ReadSourceLocation(Record, Idx));
unsigned NumParams = Record[Idx++];
- llvm::SmallVector<ParmVarDecl *, 16> Params;
+ SmallVector<ParmVarDecl *, 16> Params;
Params.reserve(NumParams);
for (unsigned I = 0; I != NumParams; ++I)
- Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
- MD->setMethodParams(*Reader.getContext(), Params.data(), NumParams,
- NumParams);
+ Params.push_back(ReadDeclAs<ParmVarDecl>(Record, Idx));
+
+ MD->SelLocsKind = Record[Idx++];
+ unsigned NumStoredSelLocs = Record[Idx++];
+ SmallVector<SourceLocation, 16> SelLocs;
+ SelLocs.reserve(NumStoredSelLocs);
+ for (unsigned i = 0; i != NumStoredSelLocs; ++i)
+ SelLocs.push_back(ReadSourceLocation(Record, Idx));
+
+ MD->setParamsAndSelLocs(Reader.getContext(), Params, SelLocs);
}
void ASTDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) {
VisitNamedDecl(CD);
- SourceLocation A = ReadSourceLocation(Record, Idx);
- SourceLocation B = ReadSourceLocation(Record, Idx);
- CD->setAtEndRange(SourceRange(A, B));
+ CD->setAtStartLoc(ReadSourceLocation(Record, Idx));
+ CD->setAtEndRange(ReadSourceRange(Record, Idx));
}
void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
VisitObjCContainerDecl(ID);
- ID->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtrOrNull());
- ID->setSuperClass(cast_or_null<ObjCInterfaceDecl>
- (Reader.GetDecl(Record[Idx++])));
+ ID->setTypeForDecl(Reader.readType(F, Record, Idx).getTypePtrOrNull());
+ ID->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
// Read the directly referenced protocols and their SourceLocations.
unsigned NumProtocols = Record[Idx++];
- llvm::SmallVector<ObjCProtocolDecl *, 16> Protocols;
+ SmallVector<ObjCProtocolDecl *, 16> Protocols;
Protocols.reserve(NumProtocols);
for (unsigned I = 0; I != NumProtocols; ++I)
- Protocols.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
- llvm::SmallVector<SourceLocation, 16> ProtoLocs;
+ Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
+ SmallVector<SourceLocation, 16> ProtoLocs;
ProtoLocs.reserve(NumProtocols);
for (unsigned I = 0; I != NumProtocols; ++I)
ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
ID->setProtocolList(Protocols.data(), NumProtocols, ProtoLocs.data(),
- *Reader.getContext());
+ Reader.getContext());
// Read the transitive closure of protocols referenced by this class.
NumProtocols = Record[Idx++];
Protocols.clear();
Protocols.reserve(NumProtocols);
for (unsigned I = 0; I != NumProtocols; ++I)
- Protocols.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
+ Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
ID->AllReferencedProtocols.set(Protocols.data(), NumProtocols,
- *Reader.getContext());
+ Reader.getContext());
// Read the ivars.
unsigned NumIvars = Record[Idx++];
- llvm::SmallVector<ObjCIvarDecl *, 16> IVars;
+ SmallVector<ObjCIvarDecl *, 16> IVars;
IVars.reserve(NumIvars);
for (unsigned I = 0; I != NumIvars; ++I)
- IVars.push_back(cast<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++])));
- ID->setCategoryList(
- cast_or_null<ObjCCategoryDecl>(Reader.GetDecl(Record[Idx++])));
+ IVars.push_back(ReadDeclAs<ObjCIvarDecl>(Record, Idx));
+ ID->setCategoryList(ReadDeclAs<ObjCCategoryDecl>(Record, Idx));
+
// We will rebuild this list lazily.
ID->setIvarList(0);
ID->setForwardDecl(Record[Idx++]);
ID->setImplicitInterfaceDecl(Record[Idx++]);
- ID->setClassLoc(ReadSourceLocation(Record, Idx));
ID->setSuperClassLoc(ReadSourceLocation(Record, Idx));
ID->setLocEnd(ReadSourceLocation(Record, Idx));
}
@@ -548,16 +574,16 @@ void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) {
PD->setForwardDecl(Record[Idx++]);
PD->setLocEnd(ReadSourceLocation(Record, Idx));
unsigned NumProtoRefs = Record[Idx++];
- llvm::SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
+ SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
ProtoRefs.reserve(NumProtoRefs);
for (unsigned I = 0; I != NumProtoRefs; ++I)
- ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
- llvm::SmallVector<SourceLocation, 16> ProtoLocs;
+ ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
+ SmallVector<SourceLocation, 16> ProtoLocs;
ProtoLocs.reserve(NumProtoRefs);
for (unsigned I = 0; I != NumProtoRefs; ++I)
ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
- *Reader.getContext());
+ Reader.getContext());
}
void ASTDeclReader::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *FD) {
@@ -566,57 +592,48 @@ void ASTDeclReader::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *FD) {
void ASTDeclReader::VisitObjCClassDecl(ObjCClassDecl *CD) {
VisitDecl(CD);
- unsigned NumClassRefs = Record[Idx++];
- llvm::SmallVector<ObjCInterfaceDecl *, 16> ClassRefs;
- ClassRefs.reserve(NumClassRefs);
- for (unsigned I = 0; I != NumClassRefs; ++I)
- ClassRefs.push_back(cast<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
- llvm::SmallVector<SourceLocation, 16> SLocs;
- SLocs.reserve(NumClassRefs);
- for (unsigned I = 0; I != NumClassRefs; ++I)
- SLocs.push_back(ReadSourceLocation(Record, Idx));
- CD->setClassList(*Reader.getContext(), ClassRefs.data(), SLocs.data(),
- NumClassRefs);
+ ObjCInterfaceDecl *ClassRef = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
+ SourceLocation SLoc = ReadSourceLocation(Record, Idx);
+ CD->setClass(Reader.getContext(), ClassRef, SLoc);
}
void ASTDeclReader::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *FPD) {
VisitDecl(FPD);
unsigned NumProtoRefs = Record[Idx++];
- llvm::SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
+ SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
ProtoRefs.reserve(NumProtoRefs);
for (unsigned I = 0; I != NumProtoRefs; ++I)
- ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
- llvm::SmallVector<SourceLocation, 16> ProtoLocs;
+ ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
+ SmallVector<SourceLocation, 16> ProtoLocs;
ProtoLocs.reserve(NumProtoRefs);
for (unsigned I = 0; I != NumProtoRefs; ++I)
ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
FPD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
- *Reader.getContext());
+ Reader.getContext());
}
void ASTDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) {
VisitObjCContainerDecl(CD);
- CD->setClassInterface(cast<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
+ CD->ClassInterface = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
unsigned NumProtoRefs = Record[Idx++];
- llvm::SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
+ SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
ProtoRefs.reserve(NumProtoRefs);
for (unsigned I = 0; I != NumProtoRefs; ++I)
- ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
- llvm::SmallVector<SourceLocation, 16> ProtoLocs;
+ ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
+ SmallVector<SourceLocation, 16> ProtoLocs;
ProtoLocs.reserve(NumProtoRefs);
for (unsigned I = 0; I != NumProtoRefs; ++I)
ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
CD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
- *Reader.getContext());
- CD->setNextClassCategory(cast_or_null<ObjCCategoryDecl>(Reader.GetDecl(Record[Idx++])));
+ Reader.getContext());
+ CD->NextClassCategory = ReadDeclAs<ObjCCategoryDecl>(Record, Idx);
CD->setHasSynthBitfield(Record[Idx++]);
- CD->setAtLoc(ReadSourceLocation(Record, Idx));
CD->setCategoryNameLoc(ReadSourceLocation(Record, Idx));
}
void ASTDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {
VisitNamedDecl(CAD);
- CAD->setClassInterface(cast<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
+ CAD->setClassInterface(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
}
void ASTDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
@@ -631,31 +648,26 @@ void ASTDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
// FIXME: stable encoding
D->setPropertyImplementation(
(ObjCPropertyDecl::PropertyControl)Record[Idx++]);
- D->setGetterName(Reader.ReadDeclarationName(Record, Idx).getObjCSelector());
- D->setSetterName(Reader.ReadDeclarationName(Record, Idx).getObjCSelector());
- D->setGetterMethodDecl(
- cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
- D->setSetterMethodDecl(
- cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
- D->setPropertyIvarDecl(
- cast_or_null<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++])));
+ D->setGetterName(Reader.ReadDeclarationName(F,Record, Idx).getObjCSelector());
+ D->setSetterName(Reader.ReadDeclarationName(F,Record, Idx).getObjCSelector());
+ D->setGetterMethodDecl(ReadDeclAs<ObjCMethodDecl>(Record, Idx));
+ D->setSetterMethodDecl(ReadDeclAs<ObjCMethodDecl>(Record, Idx));
+ D->setPropertyIvarDecl(ReadDeclAs<ObjCIvarDecl>(Record, Idx));
}
void ASTDeclReader::VisitObjCImplDecl(ObjCImplDecl *D) {
VisitObjCContainerDecl(D);
- D->setClassInterface(
- cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
+ D->setClassInterface(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
}
void ASTDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
VisitObjCImplDecl(D);
- D->setIdentifier(Reader.GetIdentifierInfo(Record, Idx));
+ D->setIdentifier(Reader.GetIdentifierInfo(F, Record, Idx));
}
void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
VisitObjCImplDecl(D);
- D->setSuperClass(
- cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
+ D->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
llvm::tie(D->IvarInitializers, D->NumIvarInitializers)
= Reader.ReadCXXCtorInitializers(F, Record, Idx);
D->setHasSynthBitfield(Record[Idx++]);
@@ -665,10 +677,8 @@ void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
void ASTDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
VisitDecl(D);
D->setAtLoc(ReadSourceLocation(Record, Idx));
- D->setPropertyDecl(
- cast_or_null<ObjCPropertyDecl>(Reader.GetDecl(Record[Idx++])));
- D->PropertyIvarDecl =
- cast_or_null<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++]));
+ D->setPropertyDecl(ReadDeclAs<ObjCPropertyDecl>(Record, Idx));
+ D->PropertyIvarDecl = ReadDeclAs<ObjCIvarDecl>(Record, Idx);
D->IvarLoc = ReadSourceLocation(Record, Idx);
D->setGetterCXXConstructor(Reader.ReadExpr(F));
D->setSetterCXXAssignment(Reader.ReadExpr(F));
@@ -683,9 +693,8 @@ void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) {
else if (BitWidthOrInitializer == 2)
FD->setInClassInitializer(Reader.ReadExpr(F));
if (!FD->getDeclName()) {
- FieldDecl *Tmpl = cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++]));
- if (Tmpl)
- Reader.getContext()->setInstantiatedFromUnnamedFieldDecl(FD, Tmpl);
+ if (FieldDecl *Tmpl = ReadDeclAs<FieldDecl>(Record, Idx))
+ Reader.getContext().setInstantiatedFromUnnamedFieldDecl(FD, Tmpl);
}
}
@@ -694,10 +703,10 @@ void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) {
FD->ChainingSize = Record[Idx++];
assert(FD->ChainingSize >= 2 && "Anonymous chaining must be >= 2");
- FD->Chaining = new (*Reader.getContext())NamedDecl*[FD->ChainingSize];
+ FD->Chaining = new (Reader.getContext())NamedDecl*[FD->ChainingSize];
for (unsigned I = 0; I != FD->ChainingSize; ++I)
- FD->Chaining[I] = cast<NamedDecl>(Reader.GetDecl(Record[Idx++]));
+ FD->Chaining[I] = ReadDeclAs<NamedDecl>(Record, Idx);
}
void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
@@ -715,10 +724,10 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
VD->setInit(Reader.ReadExpr(F));
if (Record[Idx++]) { // HasMemberSpecializationInfo.
- VarDecl *Tmpl = cast<VarDecl>(Reader.GetDecl(Record[Idx++]));
+ VarDecl *Tmpl = ReadDeclAs<VarDecl>(Record, Idx);
TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
SourceLocation POI = ReadSourceLocation(Record, Idx);
- Reader.getContext()->setInstantiatedFromStaticDataMember(VD, Tmpl, TSK,POI);
+ Reader.getContext().setInstantiatedFromStaticDataMember(VD, Tmpl, TSK,POI);
}
}
@@ -756,18 +765,18 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) {
BD->setBody(cast_or_null<CompoundStmt>(Reader.ReadStmt(F)));
BD->setSignatureAsWritten(GetTypeSourceInfo(Record, Idx));
unsigned NumParams = Record[Idx++];
- llvm::SmallVector<ParmVarDecl *, 16> Params;
+ SmallVector<ParmVarDecl *, 16> Params;
Params.reserve(NumParams);
for (unsigned I = 0; I != NumParams; ++I)
- Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
- BD->setParams(Params.data(), NumParams);
+ Params.push_back(ReadDeclAs<ParmVarDecl>(Record, Idx));
+ BD->setParams(Params);
bool capturesCXXThis = Record[Idx++];
unsigned numCaptures = Record[Idx++];
- llvm::SmallVector<BlockDecl::Capture, 16> captures;
+ SmallVector<BlockDecl::Capture, 16> captures;
captures.reserve(numCaptures);
for (unsigned i = 0; i != numCaptures; ++i) {
- VarDecl *decl = cast<VarDecl>(Reader.GetDecl(Record[Idx++]));
+ VarDecl *decl = ReadDeclAs<VarDecl>(Record, Idx);
unsigned flags = Record[Idx++];
bool byRef = (flags & 1);
bool nested = (flags & 2);
@@ -775,7 +784,7 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) {
captures.push_back(BlockDecl::Capture(decl, byRef, nested, copyExpr));
}
- BD->setCaptures(*Reader.getContext(), captures.begin(),
+ BD->setCaptures(Reader.getContext(), captures.begin(),
captures.end(), capturesCXXThis);
}
@@ -800,9 +809,10 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
D->NextNamespace = Record[Idx++];
bool IsOriginal = Record[Idx++];
+ // FIXME: Modules will likely have trouble with pointing directly at
+ // the original namespace.
D->OrigOrAnonNamespace.setInt(IsOriginal);
- D->OrigOrAnonNamespace.setPointer(
- cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++])));
+ D->OrigOrAnonNamespace.setPointer(ReadDeclAs<NamespaceDecl>(Record, Idx));
}
void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
@@ -810,7 +820,7 @@ void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
D->NamespaceLoc = ReadSourceLocation(Record, Idx);
D->IdentLoc = ReadSourceLocation(Record, Idx);
D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
- D->Namespace = cast<NamedDecl>(Reader.GetDecl(Record[Idx++]));
+ D->Namespace = ReadDeclAs<NamedDecl>(Record, Idx);
}
void ASTDeclReader::VisitUsingDecl(UsingDecl *D) {
@@ -818,21 +828,19 @@ void ASTDeclReader::VisitUsingDecl(UsingDecl *D) {
D->setUsingLocation(ReadSourceLocation(Record, Idx));
D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
ReadDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record, Idx);
- D->FirstUsingShadow = cast_or_null<UsingShadowDecl>(Reader.GetDecl(Record[Idx++]));
+ D->FirstUsingShadow = ReadDeclAs<UsingShadowDecl>(Record, Idx);
D->setTypeName(Record[Idx++]);
- NamedDecl *Pattern = cast_or_null<NamedDecl>(Reader.GetDecl(Record[Idx++]));
- if (Pattern)
- Reader.getContext()->setInstantiatedFromUsingDecl(D, Pattern);
+ if (NamedDecl *Pattern = ReadDeclAs<NamedDecl>(Record, Idx))
+ Reader.getContext().setInstantiatedFromUsingDecl(D, Pattern);
}
void ASTDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) {
VisitNamedDecl(D);
- D->setTargetDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++])));
- D->UsingOrNextShadow = cast_or_null<NamedDecl>(Reader.GetDecl(Record[Idx++]));
- UsingShadowDecl *Pattern
- = cast_or_null<UsingShadowDecl>(Reader.GetDecl(Record[Idx++]));
+ D->setTargetDecl(ReadDeclAs<NamedDecl>(Record, Idx));
+ D->UsingOrNextShadow = ReadDeclAs<NamedDecl>(Record, Idx);
+ UsingShadowDecl *Pattern = ReadDeclAs<UsingShadowDecl>(Record, Idx);
if (Pattern)
- Reader.getContext()->setInstantiatedFromUsingShadowDecl(D, Pattern);
+ Reader.getContext().setInstantiatedFromUsingShadowDecl(D, Pattern);
}
void ASTDeclReader::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
@@ -840,8 +848,8 @@ void ASTDeclReader::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
D->UsingLoc = ReadSourceLocation(Record, Idx);
D->NamespaceLoc = ReadSourceLocation(Record, Idx);
D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
- D->NominatedNamespace = cast<NamedDecl>(Reader.GetDecl(Record[Idx++]));
- D->CommonAncestor = cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++]));
+ D->NominatedNamespace = ReadDeclAs<NamedDecl>(Record, Idx);
+ D->CommonAncestor = ReadDeclAs<DeclContext>(Record, Idx);
}
void ASTDeclReader::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
@@ -863,7 +871,9 @@ void ASTDeclReader::ReadCXXDefinitionData(
const RecordData &Record, unsigned &Idx) {
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.Aggregate = Record[Idx++];
Data.PlainOldData = Record[Idx++];
@@ -877,7 +887,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.HasPublicFields = Record[Idx++];
Data.HasMutableFields = Record[Idx++];
Data.HasTrivialDefaultConstructor = Record[Idx++];
- Data.HasConstExprNonCopyMoveConstructor = Record[Idx++];
+ Data.HasConstexprNonCopyMoveConstructor = Record[Idx++];
Data.HasTrivialCopyConstructor = Record[Idx++];
Data.HasTrivialMoveConstructor = Record[Idx++];
Data.HasTrivialCopyAssignment = Record[Idx++];
@@ -888,28 +898,31 @@ void ASTDeclReader::ReadCXXDefinitionData(
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.FailedImplicitMoveConstructor = Record[Idx++];
+ Data.FailedImplicitMoveAssignment = Record[Idx++];
Data.NumBases = Record[Idx++];
if (Data.NumBases)
- Data.Bases = Reader.GetCXXBaseSpecifiersOffset(Record[Idx++]);
+ Data.Bases = Reader.readCXXBaseSpecifiers(F, Record, Idx);
Data.NumVBases = Record[Idx++];
if (Data.NumVBases)
- Data.VBases = Reader.GetCXXBaseSpecifiersOffset(Record[Idx++]);
+ Data.VBases = Reader.readCXXBaseSpecifiers(F, Record, Idx);
- Reader.ReadUnresolvedSet(Data.Conversions, Record, Idx);
- Reader.ReadUnresolvedSet(Data.VisibleConversions, Record, Idx);
+ Reader.ReadUnresolvedSet(F, Data.Conversions, Record, Idx);
+ Reader.ReadUnresolvedSet(F, Data.VisibleConversions, Record, Idx);
assert(Data.Definition && "Data.Definition should be already set!");
- Data.FirstFriend
- = cast_or_null<FriendDecl>(Reader.GetDecl(Record[Idx++]));
+ Data.FirstFriend = ReadDeclAs<FriendDecl>(Record, Idx);
}
void ASTDeclReader::InitializeCXXDefinitionData(CXXRecordDecl *D,
CXXRecordDecl *DefinitionDecl,
const RecordData &Record,
unsigned &Idx) {
- ASTContext &C = *Reader.getContext();
+ ASTContext &C = Reader.getContext();
if (D == DefinitionDecl) {
D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D);
@@ -942,26 +955,24 @@ void ASTDeclReader::InitializeCXXDefinitionData(CXXRecordDecl *D,
void ASTDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) {
VisitRecordDecl(D);
- CXXRecordDecl *DefinitionDecl
- = cast_or_null<CXXRecordDecl>(Reader.GetDecl(Record[Idx++]));
+ CXXRecordDecl *DefinitionDecl = ReadDeclAs<CXXRecordDecl>(Record, Idx);
InitializeCXXDefinitionData(D, DefinitionDecl, Record, Idx);
- ASTContext &C = *Reader.getContext();
+ ASTContext &C = Reader.getContext();
enum CXXRecKind {
CXXRecNotTemplate = 0, CXXRecTemplate, CXXRecMemberSpecialization
};
switch ((CXXRecKind)Record[Idx++]) {
default:
- assert(false && "Out of sync with ASTDeclWriter::VisitCXXRecordDecl?");
+ llvm_unreachable("Out of sync with ASTDeclWriter::VisitCXXRecordDecl?");
case CXXRecNotTemplate:
break;
case CXXRecTemplate:
- D->TemplateOrInstantiation
- = cast<ClassTemplateDecl>(Reader.GetDecl(Record[Idx++]));
+ D->TemplateOrInstantiation = ReadDeclAs<ClassTemplateDecl>(Record, Idx);
break;
case CXXRecMemberSpecialization: {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(Reader.GetDecl(Record[Idx++]));
+ CXXRecordDecl *RD = ReadDeclAs<CXXRecordDecl>(Record, Idx);
TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
SourceLocation POI = ReadSourceLocation(Record, Idx);
MemberSpecializationInfo *MSI = new (C) MemberSpecializationInfo(RD, TSK);
@@ -973,10 +984,8 @@ void ASTDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) {
// Load the key function to avoid deserializing every method so we can
// compute it.
- if (D->IsDefinition) {
- CXXMethodDecl *Key
- = cast_or_null<CXXMethodDecl>(Reader.GetDecl(Record[Idx++]));
- if (Key)
+ if (D->IsCompleteDefinition) {
+ if (CXXMethodDecl *Key = ReadDeclAs<CXXMethodDecl>(Record, Idx))
C.KeyFunctions[D] = Key;
}
}
@@ -985,10 +994,10 @@ void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) {
VisitFunctionDecl(D);
unsigned NumOverridenMethods = Record[Idx++];
while (NumOverridenMethods--) {
- CXXMethodDecl *MD = cast<CXXMethodDecl>(Reader.GetDecl(Record[Idx++]));
// Avoid invariant checking of CXXMethodDecl::addOverriddenMethod,
// MD may be initializing.
- Reader.getContext()->addOverriddenMethod(D, MD);
+ if (CXXMethodDecl *MD = ReadDeclAs<CXXMethodDecl>(Record, Idx))
+ Reader.getContext().addOverriddenMethod(D, MD);
}
}
@@ -1005,7 +1014,7 @@ void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
VisitCXXMethodDecl(D);
D->ImplicitlyDefined = Record[Idx++];
- D->OperatorDelete = cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++]));
+ D->OperatorDelete = ReadDeclAs<FunctionDecl>(Record, Idx);
}
void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) {
@@ -1023,7 +1032,7 @@ void ASTDeclReader::VisitFriendDecl(FriendDecl *D) {
if (Record[Idx++])
D->Friend = GetTypeSourceInfo(Record, Idx);
else
- D->Friend = cast<NamedDecl>(Reader.GetDecl(Record[Idx++]));
+ D->Friend = ReadDeclAs<NamedDecl>(Record, Idx);
D->NextFriend = Record[Idx++];
D->UnsupportedFriend = (Record[Idx++] != 0);
D->FriendLoc = ReadSourceLocation(Record, Idx);
@@ -1037,7 +1046,7 @@ void ASTDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
for (unsigned i = 0; i != NumParams; ++i)
D->Params[i] = Reader.ReadTemplateParameterList(F, Record, Idx);
if (Record[Idx++]) // HasFriendDecl
- D->Friend = cast<NamedDecl>(Reader.GetDecl(Record[Idx++]));
+ D->Friend = ReadDeclAs<NamedDecl>(Record, Idx);
else
D->Friend = GetTypeSourceInfo(Record, Idx);
D->FriendLoc = ReadSourceLocation(Record, Idx);
@@ -1046,8 +1055,7 @@ void ASTDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
void ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
VisitNamedDecl(D);
- NamedDecl *TemplatedDecl
- = cast_or_null<NamedDecl>(Reader.GetDecl(Record[Idx++]));
+ NamedDecl *TemplatedDecl = ReadDeclAs<NamedDecl>(Record, Idx);
TemplateParameterList* TemplateParams
= Reader.ReadTemplateParameterList(F, Record, Idx);
D->init(TemplatedDecl, TemplateParams);
@@ -1058,8 +1066,8 @@ void ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
// can be used while this is still initializing.
assert(D->CommonOrPrev.isNull() && "getCommonPtr was called earlier on this");
- DeclID PreviousDeclID = Record[Idx++];
- DeclID FirstDeclID = PreviousDeclID ? Record[Idx++] : 0;
+ DeclID PreviousDeclID = ReadDeclID(Record, Idx);
+ DeclID FirstDeclID = PreviousDeclID ? ReadDeclID(Record, Idx) : 0;
// We delay loading of the redeclaration chain to avoid deeply nested calls.
// We temporarily set the first (canonical) declaration as the previous one
// which is the one that matters and mark the real previous DeclID to be
@@ -1074,9 +1082,9 @@ void ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
if (PreviousDeclID != FirstDeclID)
Reader.PendingPreviousDecls.push_back(std::make_pair(D, PreviousDeclID));
} else {
- D->CommonOrPrev = D->newCommon(*Reader.getContext());
+ D->CommonOrPrev = D->newCommon(Reader.getContext());
if (RedeclarableTemplateDecl *RTD
- = cast_or_null<RedeclarableTemplateDecl>(Reader.GetDecl(Record[Idx++]))) {
+ = ReadDeclAs<RedeclarableTemplateDecl>(Record, Idx)) {
assert(RTD->getKind() == D->getKind() &&
"InstantiatedFromMemberTemplate kind mismatch");
D->setInstantiatedFromMemberTemplateImpl(RTD);
@@ -1084,8 +1092,8 @@ void ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
D->setMemberSpecialization();
}
- RedeclarableTemplateDecl *LatestDecl =
- cast_or_null<RedeclarableTemplateDecl>(Reader.GetDecl(Record[Idx++]));
+ RedeclarableTemplateDecl *LatestDecl
+ = ReadDeclAs<RedeclarableTemplateDecl>(Record, Idx);
// This decl is a first one and the latest declaration that it points to is
// in the same AST file. However, if this actually needs to point to a
@@ -1095,14 +1103,8 @@ void ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
ASTReader::FirstLatestDeclIDMap::iterator I
= Reader.FirstLatestDeclIDs.find(ThisDeclID);
if (I != Reader.FirstLatestDeclIDs.end()) {
- Decl *NewLatest = Reader.GetDecl(I->second);
- assert((LatestDecl->getLocation().isInvalid() ||
- NewLatest->getLocation().isInvalid() ||
- !Reader.SourceMgr.isBeforeInTranslationUnit(
- NewLatest->getLocation(),
- LatestDecl->getLocation())) &&
- "The new latest is supposed to come after the previous latest");
- LatestDecl = cast<RedeclarableTemplateDecl>(NewLatest);
+ if (Decl *NewLatest = Reader.GetDecl(I->second))
+ LatestDecl = cast<RedeclarableTemplateDecl>(NewLatest);
}
assert(LatestDecl->getKind() == D->getKind() && "Latest kind mismatch");
@@ -1119,27 +1121,27 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (D->getPreviousDeclaration() == 0) {
// This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of
// the specializations.
- llvm::SmallVector<serialization::DeclID, 2> SpecIDs;
+ SmallVector<serialization::DeclID, 2> SpecIDs;
SpecIDs.push_back(0);
// Specializations.
unsigned Size = Record[Idx++];
SpecIDs[0] += Size;
- SpecIDs.append(Record.begin() + Idx, Record.begin() + Idx + Size);
- Idx += Size;
+ for (unsigned I = 0; I != Size; ++I)
+ SpecIDs.push_back(ReadDeclID(Record, Idx));
// Partial specializations.
Size = Record[Idx++];
SpecIDs[0] += Size;
- SpecIDs.append(Record.begin() + Idx, Record.begin() + Idx + Size);
- Idx += Size;
+ for (unsigned I = 0; I != Size; ++I)
+ SpecIDs.push_back(ReadDeclID(Record, Idx));
if (SpecIDs[0]) {
typedef serialization::DeclID DeclID;
ClassTemplateDecl::Common *CommonPtr = D->getCommonPtr();
CommonPtr->LazySpecializations
- = new (*Reader.getContext()) DeclID [SpecIDs.size()];
+ = new (Reader.getContext()) DeclID [SpecIDs.size()];
memcpy(CommonPtr->LazySpecializations, SpecIDs.data(),
SpecIDs.size() * sizeof(DeclID));
}
@@ -1152,12 +1154,12 @@ void ASTDeclReader::VisitClassTemplateSpecializationDecl(
ClassTemplateSpecializationDecl *D) {
VisitCXXRecordDecl(D);
- ASTContext &C = *Reader.getContext();
- if (Decl *InstD = Reader.GetDecl(Record[Idx++])) {
+ ASTContext &C = Reader.getContext();
+ if (Decl *InstD = ReadDecl(Record, Idx)) {
if (ClassTemplateDecl *CTD = dyn_cast<ClassTemplateDecl>(InstD)) {
D->SpecializedTemplate = CTD;
} else {
- llvm::SmallVector<TemplateArgument, 8> TemplArgs;
+ SmallVector<TemplateArgument, 8> TemplArgs;
Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx);
TemplateArgumentList *ArgList
= TemplateArgumentList::CreateCopy(C, TemplArgs.data(),
@@ -1182,7 +1184,7 @@ void ASTDeclReader::VisitClassTemplateSpecializationDecl(
D->ExplicitInfo = ExplicitInfo;
}
- llvm::SmallVector<TemplateArgument, 8> TemplArgs;
+ SmallVector<TemplateArgument, 8> TemplArgs;
Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx);
D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs.data(),
TemplArgs.size());
@@ -1190,8 +1192,7 @@ void ASTDeclReader::VisitClassTemplateSpecializationDecl(
D->SpecializationKind = (TemplateSpecializationKind)Record[Idx++];
if (D->isCanonicalDecl()) { // It's kept in the folding set.
- ClassTemplateDecl *CanonPattern
- = cast<ClassTemplateDecl>(Reader.GetDecl(Record[Idx++]));
+ ClassTemplateDecl *CanonPattern = ReadDeclAs<ClassTemplateDecl>(Record,Idx);
if (ClassTemplatePartialSpecializationDecl *Partial
= dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
CanonPattern->getCommonPtr()->PartialSpecializations.InsertNode(Partial);
@@ -1205,7 +1206,7 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D) {
VisitClassTemplateSpecializationDecl(D);
- ASTContext &C = *Reader.getContext();
+ ASTContext &C = Reader.getContext();
D->TemplateParams = Reader.ReadTemplateParameterList(F, Record, Idx);
unsigned NumArgs = Record[Idx++];
@@ -1221,12 +1222,17 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
// These are read/set from/to the first declaration.
if (D->getPreviousDeclaration() == 0) {
D->InstantiatedFromMember.setPointer(
- cast_or_null<ClassTemplatePartialSpecializationDecl>(
- Reader.GetDecl(Record[Idx++])));
+ ReadDeclAs<ClassTemplatePartialSpecializationDecl>(Record, Idx));
D->InstantiatedFromMember.setInt(Record[Idx++]);
}
}
+void ASTDeclReader::VisitClassScopeFunctionSpecializationDecl(
+ ClassScopeFunctionSpecializationDecl *D) {
+ VisitDecl(D);
+ D->Specialization = ReadDeclAs<CXXMethodDecl>(Record, Idx);
+}
+
void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
VisitRedeclarableTemplateDecl(D);
@@ -1238,7 +1244,7 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
// when reading the specialized FunctionDecl.
unsigned NumSpecs = Record[Idx++];
while (NumSpecs--)
- Reader.GetDecl(Record[Idx++]);
+ (void)ReadDecl(Record, Idx);
}
}
@@ -1260,7 +1266,7 @@ void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
if (D->isExpandedParameterPack()) {
void **Data = reinterpret_cast<void **>(D + 1);
for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) {
- Data[2*I] = Reader.GetType(Record[Idx++]).getAsOpaquePtr();
+ Data[2*I] = Reader.readType(F, Record, Idx).getAsOpaquePtr();
Data[2*I + 1] = GetTypeSourceInfo(Record, Idx);
}
} else {
@@ -1310,13 +1316,13 @@ void ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
RedeclKind Kind = (RedeclKind)Record[Idx++];
switch (Kind) {
default:
- assert(0 && "Out of sync with ASTDeclWriter::VisitRedeclarable or messed up"
- " reading");
+ llvm_unreachable("Out of sync with ASTDeclWriter::VisitRedeclarable or"
+ " messed up reading");
case NoRedeclaration:
break;
case PointsToPrevious: {
- DeclID PreviousDeclID = Record[Idx++];
- DeclID FirstDeclID = Record[Idx++];
+ DeclID PreviousDeclID = ReadDeclID(Record, Idx);
+ DeclID FirstDeclID = ReadDeclID(Record, Idx);
// We delay loading of the redeclaration chain to avoid deeply nested calls.
// We temporarily set the first (canonical) declaration as the previous one
// which is the one that matters and mark the real previous DeclID to be
@@ -1330,7 +1336,7 @@ void ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
}
case PointsToLatest:
D->RedeclLink = typename Redeclarable<T>::LatestDeclLink(
- cast_or_null<T>(Reader.GetDecl(Record[Idx++])));
+ ReadDeclAs<T>(Record, Idx));
break;
}
@@ -1361,12 +1367,12 @@ void ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
//===----------------------------------------------------------------------===//
/// \brief Reads attributes from the current stream position.
-void ASTReader::ReadAttributes(PerFileData &F, AttrVec &Attrs,
+void ASTReader::ReadAttributes(Module &F, AttrVec &Attrs,
const RecordData &Record, unsigned &Idx) {
for (unsigned i = 0, e = Record[Idx++]; i != e; ++i) {
Attr *New = 0;
attr::Kind Kind = (attr::Kind)Record[Idx++];
- SourceLocation Loc = ReadSourceLocation(F, Record, Idx);
+ SourceRange Range = ReadSourceRange(F, Record, Idx);
#include "clang/Serialization/AttrPCHRead.inc"
@@ -1398,33 +1404,47 @@ inline void ASTReader::LoadedDecl(unsigned Index, Decl *D) {
/// code generation, e.g., inline function definitions, Objective-C
/// declarations with metadata, etc.
static bool isConsumerInterestedIn(Decl *D) {
- if (isa<FileScopeAsmDecl>(D))
+ // An ObjCMethodDecl is never considered as "interesting" because its
+ // implementation container always is.
+
+ if (isa<FileScopeAsmDecl>(D) ||
+ isa<ObjCProtocolDecl>(D) ||
+ isa<ObjCImplDecl>(D))
return true;
if (VarDecl *Var = dyn_cast<VarDecl>(D))
return Var->isFileVarDecl() &&
Var->isThisDeclarationADefinition() == VarDecl::Definition;
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
return Func->doesThisDeclarationHaveABody();
- return isa<ObjCProtocolDecl>(D) || isa<ObjCImplementationDecl>(D);
+
+ return false;
}
-/// \brief Get the correct cursor and offset for loading a type.
+/// \brief Get the correct cursor and offset for loading a declaration.
ASTReader::RecordLocation
-ASTReader::DeclCursorForIndex(unsigned Index, DeclID ID) {
+ASTReader::DeclCursorForID(DeclID ID) {
// See if there's an override.
DeclReplacementMap::iterator It = ReplacedDecls.find(ID);
if (It != ReplacedDecls.end())
return RecordLocation(It->second.first, It->second.second);
- PerFileData *F = 0;
- for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- F = Chain[N - I - 1];
- if (Index < F->LocalNumDecls)
- break;
- Index -= F->LocalNumDecls;
- }
- assert(F && F->LocalNumDecls > Index && "Broken chain");
- return RecordLocation(F, F->DeclOffsets[Index]);
+ GlobalDeclMapType::iterator I = GlobalDeclMap.find(ID);
+ assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
+ Module *M = I->second;
+ return RecordLocation(M,
+ M->DeclOffsets[ID - M->BaseDeclID - NUM_PREDEF_DECL_IDS]);
+}
+
+ASTReader::RecordLocation ASTReader::getLocalBitOffset(uint64_t GlobalOffset) {
+ ContinuousRangeMap<uint64_t, Module*, 4>::iterator I
+ = GlobalBitOffsetsMap.find(GlobalOffset);
+
+ assert(I != GlobalBitOffsetsMap.end() && "Corrupted global bit offsets map");
+ return RecordLocation(I->second, GlobalOffset - I->second->GlobalBitOffset);
+}
+
+uint64_t ASTReader::getGlobalBitOffset(Module &M, uint32_t LocalOffset) {
+ return LocalOffset + M.GlobalBitOffset;
}
void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *previous) {
@@ -1447,8 +1467,9 @@ void ASTReader::loadAndAttachPreviousDecl(Decl *D, serialization::DeclID ID) {
}
/// \brief Read the declaration at the given offset from the AST file.
-Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
- RecordLocation Loc = DeclCursorForIndex(Index, ID);
+Decl *ASTReader::ReadDeclRecord(DeclID ID) {
+ unsigned Index = ID - NUM_PREDEF_DECL_IDS;
+ RecordLocation Loc = DeclCursorForID(ID);
llvm::BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor;
// Keep track of where we are in the stream, then jump back there
// after reading this declaration.
@@ -1469,215 +1490,216 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
switch ((DeclCode)DeclsCursor.ReadRecord(Code, Record)) {
case DECL_CONTEXT_LEXICAL:
case DECL_CONTEXT_VISIBLE:
- assert(false && "Record cannot be de-serialized with ReadDeclRecord");
- break;
- case DECL_TRANSLATION_UNIT:
- assert(Index == 0 && "Translation unit must be at index 0");
- D = Context->getTranslationUnitDecl();
- break;
+ llvm_unreachable("Record cannot be de-serialized with ReadDeclRecord");
case DECL_TYPEDEF:
- D = TypedefDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
+ D = TypedefDecl::Create(Context, 0, SourceLocation(), SourceLocation(),
0, 0);
break;
case DECL_TYPEALIAS:
- D = TypeAliasDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
+ D = TypeAliasDecl::Create(Context, 0, SourceLocation(), SourceLocation(),
0, 0);
break;
case DECL_ENUM:
- D = EnumDecl::Create(*Context, Decl::EmptyShell());
+ D = EnumDecl::Create(Context, Decl::EmptyShell());
break;
case DECL_RECORD:
- D = RecordDecl::Create(*Context, Decl::EmptyShell());
+ D = RecordDecl::Create(Context, Decl::EmptyShell());
break;
case DECL_ENUM_CONSTANT:
- D = EnumConstantDecl::Create(*Context, 0, SourceLocation(), 0, QualType(),
+ D = EnumConstantDecl::Create(Context, 0, SourceLocation(), 0, QualType(),
0, llvm::APSInt());
break;
case DECL_FUNCTION:
- D = FunctionDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
+ D = FunctionDecl::Create(Context, 0, SourceLocation(), SourceLocation(),
DeclarationName(), QualType(), 0);
break;
case DECL_LINKAGE_SPEC:
- D = LinkageSpecDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
+ D = LinkageSpecDecl::Create(Context, 0, SourceLocation(), SourceLocation(),
(LinkageSpecDecl::LanguageIDs)0,
SourceLocation());
break;
case DECL_LABEL:
- D = LabelDecl::Create(*Context, 0, SourceLocation(), 0);
+ D = LabelDecl::Create(Context, 0, SourceLocation(), 0);
break;
case DECL_NAMESPACE:
- D = NamespaceDecl::Create(*Context, 0, SourceLocation(),
+ D = NamespaceDecl::Create(Context, 0, SourceLocation(),
SourceLocation(), 0);
break;
case DECL_NAMESPACE_ALIAS:
- D = NamespaceAliasDecl::Create(*Context, 0, SourceLocation(),
+ D = NamespaceAliasDecl::Create(Context, 0, SourceLocation(),
SourceLocation(), 0,
NestedNameSpecifierLoc(),
SourceLocation(), 0);
break;
case DECL_USING:
- D = UsingDecl::Create(*Context, 0, SourceLocation(),
+ D = UsingDecl::Create(Context, 0, SourceLocation(),
NestedNameSpecifierLoc(), DeclarationNameInfo(),
false);
break;
case DECL_USING_SHADOW:
- D = UsingShadowDecl::Create(*Context, 0, SourceLocation(), 0, 0);
+ D = UsingShadowDecl::Create(Context, 0, SourceLocation(), 0, 0);
break;
case DECL_USING_DIRECTIVE:
- D = UsingDirectiveDecl::Create(*Context, 0, SourceLocation(),
+ D = UsingDirectiveDecl::Create(Context, 0, SourceLocation(),
SourceLocation(), NestedNameSpecifierLoc(),
SourceLocation(), 0, 0);
break;
case DECL_UNRESOLVED_USING_VALUE:
- D = UnresolvedUsingValueDecl::Create(*Context, 0, SourceLocation(),
+ D = UnresolvedUsingValueDecl::Create(Context, 0, SourceLocation(),
NestedNameSpecifierLoc(),
DeclarationNameInfo());
break;
case DECL_UNRESOLVED_USING_TYPENAME:
- D = UnresolvedUsingTypenameDecl::Create(*Context, 0, SourceLocation(),
+ D = UnresolvedUsingTypenameDecl::Create(Context, 0, SourceLocation(),
SourceLocation(),
NestedNameSpecifierLoc(),
SourceLocation(),
DeclarationName());
break;
case DECL_CXX_RECORD:
- D = CXXRecordDecl::Create(*Context, Decl::EmptyShell());
+ D = CXXRecordDecl::Create(Context, Decl::EmptyShell());
break;
case DECL_CXX_METHOD:
- D = CXXMethodDecl::Create(*Context, 0, SourceLocation(),
+ D = CXXMethodDecl::Create(Context, 0, SourceLocation(),
DeclarationNameInfo(), QualType(), 0,
- false, SC_None, false, SourceLocation());
+ false, SC_None, false, false, SourceLocation());
break;
case DECL_CXX_CONSTRUCTOR:
- D = CXXConstructorDecl::Create(*Context, Decl::EmptyShell());
+ D = CXXConstructorDecl::Create(Context, Decl::EmptyShell());
break;
case DECL_CXX_DESTRUCTOR:
- D = CXXDestructorDecl::Create(*Context, Decl::EmptyShell());
+ D = CXXDestructorDecl::Create(Context, Decl::EmptyShell());
break;
case DECL_CXX_CONVERSION:
- D = CXXConversionDecl::Create(*Context, Decl::EmptyShell());
+ D = CXXConversionDecl::Create(Context, Decl::EmptyShell());
break;
case DECL_ACCESS_SPEC:
- D = AccessSpecDecl::Create(*Context, Decl::EmptyShell());
+ D = AccessSpecDecl::Create(Context, Decl::EmptyShell());
break;
case DECL_FRIEND:
- D = FriendDecl::Create(*Context, Decl::EmptyShell());
+ D = FriendDecl::Create(Context, Decl::EmptyShell());
break;
case DECL_FRIEND_TEMPLATE:
- D = FriendTemplateDecl::Create(*Context, Decl::EmptyShell());
+ D = FriendTemplateDecl::Create(Context, Decl::EmptyShell());
break;
case DECL_CLASS_TEMPLATE:
- D = ClassTemplateDecl::Create(*Context, Decl::EmptyShell());
+ D = ClassTemplateDecl::Create(Context, Decl::EmptyShell());
break;
case DECL_CLASS_TEMPLATE_SPECIALIZATION:
- D = ClassTemplateSpecializationDecl::Create(*Context, Decl::EmptyShell());
+ D = ClassTemplateSpecializationDecl::Create(Context, Decl::EmptyShell());
break;
case DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION:
- D = ClassTemplatePartialSpecializationDecl::Create(*Context,
+ D = ClassTemplatePartialSpecializationDecl::Create(Context,
Decl::EmptyShell());
break;
+ case DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION:
+ D = ClassScopeFunctionSpecializationDecl::Create(Context,
+ Decl::EmptyShell());
+ break;
case DECL_FUNCTION_TEMPLATE:
- D = FunctionTemplateDecl::Create(*Context, Decl::EmptyShell());
+ D = FunctionTemplateDecl::Create(Context, Decl::EmptyShell());
break;
case DECL_TEMPLATE_TYPE_PARM:
- D = TemplateTypeParmDecl::Create(*Context, Decl::EmptyShell());
+ D = TemplateTypeParmDecl::Create(Context, Decl::EmptyShell());
break;
case DECL_NON_TYPE_TEMPLATE_PARM:
- D = NonTypeTemplateParmDecl::Create(*Context, 0, SourceLocation(),
+ D = NonTypeTemplateParmDecl::Create(Context, 0, SourceLocation(),
SourceLocation(), 0, 0, 0, QualType(),
false, 0);
break;
case DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK:
- D = NonTypeTemplateParmDecl::Create(*Context, 0, SourceLocation(),
+ D = NonTypeTemplateParmDecl::Create(Context, 0, SourceLocation(),
SourceLocation(), 0, 0, 0, QualType(),
0, 0, Record[Idx++], 0);
break;
case DECL_TEMPLATE_TEMPLATE_PARM:
- D = TemplateTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0, 0,
+ D = TemplateTemplateParmDecl::Create(Context, 0, SourceLocation(), 0, 0,
false, 0, 0);
break;
case DECL_TYPE_ALIAS_TEMPLATE:
- D = TypeAliasTemplateDecl::Create(*Context, Decl::EmptyShell());
+ D = TypeAliasTemplateDecl::Create(Context, Decl::EmptyShell());
break;
case DECL_STATIC_ASSERT:
- D = StaticAssertDecl::Create(*Context, 0, SourceLocation(), 0, 0,
+ D = StaticAssertDecl::Create(Context, 0, SourceLocation(), 0, 0,
SourceLocation());
break;
case DECL_OBJC_METHOD:
- D = ObjCMethodDecl::Create(*Context, SourceLocation(), SourceLocation(),
+ D = ObjCMethodDecl::Create(Context, SourceLocation(), SourceLocation(),
Selector(), QualType(), 0, 0);
break;
case DECL_OBJC_INTERFACE:
- D = ObjCInterfaceDecl::Create(*Context, 0, SourceLocation(), 0);
+ D = ObjCInterfaceDecl::Create(Context, 0, SourceLocation(), 0);
break;
case DECL_OBJC_IVAR:
- D = ObjCIvarDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
+ D = ObjCIvarDecl::Create(Context, 0, SourceLocation(), SourceLocation(),
0, QualType(), 0, ObjCIvarDecl::None);
break;
case DECL_OBJC_PROTOCOL:
- D = ObjCProtocolDecl::Create(*Context, 0, SourceLocation(), 0);
+ D = ObjCProtocolDecl::Create(Context, 0, 0, SourceLocation(),
+ SourceLocation());
break;
case DECL_OBJC_AT_DEFS_FIELD:
- D = ObjCAtDefsFieldDecl::Create(*Context, 0, SourceLocation(),
+ D = ObjCAtDefsFieldDecl::Create(Context, 0, SourceLocation(),
SourceLocation(), 0, QualType(), 0);
break;
case DECL_OBJC_CLASS:
- D = ObjCClassDecl::Create(*Context, 0, SourceLocation());
+ D = ObjCClassDecl::Create(Context, 0, SourceLocation());
break;
case DECL_OBJC_FORWARD_PROTOCOL:
- D = ObjCForwardProtocolDecl::Create(*Context, 0, SourceLocation());
+ D = ObjCForwardProtocolDecl::Create(Context, 0, SourceLocation());
break;
case DECL_OBJC_CATEGORY:
- D = ObjCCategoryDecl::Create(*Context, 0, SourceLocation(),
- SourceLocation(), SourceLocation(), 0);
+ D = ObjCCategoryDecl::Create(Context, Decl::EmptyShell());
break;
case DECL_OBJC_CATEGORY_IMPL:
- D = ObjCCategoryImplDecl::Create(*Context, 0, SourceLocation(), 0, 0);
+ D = ObjCCategoryImplDecl::Create(Context, 0, 0, 0, SourceLocation(),
+ SourceLocation());
break;
case DECL_OBJC_IMPLEMENTATION:
- D = ObjCImplementationDecl::Create(*Context, 0, SourceLocation(), 0, 0);
+ D = ObjCImplementationDecl::Create(Context, 0, 0, 0, SourceLocation(),
+ SourceLocation());
break;
case DECL_OBJC_COMPATIBLE_ALIAS:
- D = ObjCCompatibleAliasDecl::Create(*Context, 0, SourceLocation(), 0, 0);
+ D = ObjCCompatibleAliasDecl::Create(Context, 0, SourceLocation(), 0, 0);
break;
case DECL_OBJC_PROPERTY:
- D = ObjCPropertyDecl::Create(*Context, 0, SourceLocation(), 0, SourceLocation(),
+ D = ObjCPropertyDecl::Create(Context, 0, SourceLocation(), 0, SourceLocation(),
0);
break;
case DECL_OBJC_PROPERTY_IMPL:
- D = ObjCPropertyImplDecl::Create(*Context, 0, SourceLocation(),
+ D = ObjCPropertyImplDecl::Create(Context, 0, SourceLocation(),
SourceLocation(), 0,
ObjCPropertyImplDecl::Dynamic, 0,
SourceLocation());
break;
case DECL_FIELD:
- D = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), 0,
+ D = FieldDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0,
QualType(), 0, 0, false, false);
break;
case DECL_INDIRECTFIELD:
- D = IndirectFieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(),
+ D = IndirectFieldDecl::Create(Context, 0, SourceLocation(), 0, QualType(),
0, 0);
break;
case DECL_VAR:
- D = VarDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), 0,
+ D = VarDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0,
QualType(), 0, SC_None, SC_None);
break;
case DECL_IMPLICIT_PARAM:
- D = ImplicitParamDecl::Create(*Context, 0, SourceLocation(), 0, QualType());
+ D = ImplicitParamDecl::Create(Context, 0, SourceLocation(), 0, QualType());
break;
case DECL_PARM_VAR:
- D = ParmVarDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), 0,
+ D = ParmVarDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0,
QualType(), 0, SC_None, SC_None, 0);
break;
case DECL_FILE_SCOPE_ASM:
- D = FileScopeAsmDecl::Create(*Context, 0, 0, SourceLocation(),
+ D = FileScopeAsmDecl::Create(Context, 0, 0, SourceLocation(),
SourceLocation());
break;
case DECL_BLOCK:
- D = BlockDecl::Create(*Context, 0, SourceLocation());
+ D = BlockDecl::Create(Context, 0, SourceLocation());
break;
case DECL_CXX_BASE_SPECIFIERS:
Error("attempt to read a C++ base-specifier record as a declaration");
@@ -1693,16 +1715,13 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
if (DeclContext *DC = dyn_cast<DeclContext>(D)) {
std::pair<uint64_t, uint64_t> Offsets = Reader.VisitDeclContext(DC);
if (Offsets.first || Offsets.second) {
- DC->setHasExternalLexicalStorage(Offsets.first != 0);
- DC->setHasExternalVisibleStorage(Offsets.second != 0);
- DeclContextInfo Info;
- if (ReadDeclContextStorage(DeclsCursor, Offsets, Info))
+ if (Offsets.first != 0)
+ DC->setHasExternalLexicalStorage(true);
+ if (Offsets.second != 0)
+ DC->setHasExternalVisibleStorage(true);
+ if (ReadDeclContextStorage(*Loc.F, DeclsCursor, Offsets,
+ Loc.F->DeclContextInfos[DC]))
return 0;
- DeclContextInfos &Infos = DeclContextOffsets[DC];
- // Reading the TU will happen after reading its lexical update blocks,
- // so we need to make sure we insert in front. For all other contexts,
- // the vector is empty here anyway, so there's no loss in efficiency.
- Infos.insert(Infos.begin(), Info);
}
// Now add the pending visible updates for this decl context, if it has any.
@@ -1713,20 +1732,32 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
// storage, even if the original stored version didn't.
DC->setHasExternalVisibleStorage(true);
DeclContextVisibleUpdates &U = I->second;
- DeclContextInfos &Infos = DeclContextOffsets[DC];
- DeclContextInfo Info;
- Info.LexicalDecls = 0;
- Info.NumLexicalDecls = 0;
for (DeclContextVisibleUpdates::iterator UI = U.begin(), UE = U.end();
UI != UE; ++UI) {
- Info.NameLookupTableData = *UI;
- Infos.push_back(Info);
+ UI->second->DeclContextInfos[DC].NameLookupTableData = UI->first;
}
PendingVisibleUpdates.erase(I);
}
}
assert(Idx == Record.size());
+ // Load any relevant update records.
+ loadDeclUpdateRecords(ID, D);
+
+ if (ObjCChainedCategoriesInterfaces.count(ID))
+ loadObjCChainedCategories(ID, cast<ObjCInterfaceDecl>(D));
+
+ // If we have deserialized a declaration that has a definition the
+ // AST consumer might need to know about, queue it.
+ // We don't pass it to the consumer immediately because we may be in recursive
+ // loading, and some declarations may still be initializing.
+ if (isConsumerInterestedIn(D))
+ InterestingDecls.push_back(D);
+
+ return D;
+}
+
+void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
// The declaration may have been modified by files later in the chain.
// If this is the case, read the record containing the updates from each file
// and pass it to ASTDeclReader to make the modifications.
@@ -1734,8 +1765,8 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
if (UpdI != DeclUpdateOffsets.end()) {
FileOffsetsTy &UpdateOffsets = UpdI->second;
for (FileOffsetsTy::iterator
- I = UpdateOffsets.begin(), E = UpdateOffsets.end(); I != E; ++I) {
- PerFileData *F = I->first;
+ I = UpdateOffsets.begin(), E = UpdateOffsets.end(); I != E; ++I) {
+ Module *F = I->first;
uint64_t Offset = I->second;
llvm::BitstreamCursor &Cursor = F->DeclsCursor;
SavedStreamPosition SavedPosition(Cursor);
@@ -1745,45 +1776,166 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
unsigned RecCode = Cursor.ReadRecord(Code, Record);
(void)RecCode;
assert(RecCode == DECL_UPDATES && "Expected DECL_UPDATES record!");
+
+ unsigned Idx = 0;
+ ASTDeclReader Reader(*this, *F, Cursor, ID, Record, Idx);
Reader.UpdateDecl(D, *F, Record);
}
}
+}
- // If we have deserialized a declaration that has a definition the
- // AST consumer might need to know about, queue it.
- // We don't pass it to the consumer immediately because we may be in recursive
- // loading, and some declarations may still be initializing.
- if (isConsumerInterestedIn(D))
- InterestingDecls.push_back(D);
+namespace {
+ /// \brief Given an ObjC interface, goes through the modules and links to the
+ /// interface all the categories for it.
+ class ObjCChainedCategoriesVisitor {
+ ASTReader &Reader;
+ serialization::GlobalDeclID InterfaceID;
+ ObjCInterfaceDecl *Interface;
+ ObjCCategoryDecl *GlobHeadCat, *GlobTailCat;
+ llvm::DenseMap<DeclarationName, ObjCCategoryDecl *> NameCategoryMap;
- return D;
+ public:
+ ObjCChainedCategoriesVisitor(ASTReader &Reader,
+ serialization::GlobalDeclID InterfaceID,
+ ObjCInterfaceDecl *Interface)
+ : Reader(Reader), InterfaceID(InterfaceID), Interface(Interface),
+ GlobHeadCat(0), GlobTailCat(0) { }
+
+ static bool visit(Module &M, void *UserData) {
+ return static_cast<ObjCChainedCategoriesVisitor *>(UserData)->visit(M);
+ }
+
+ bool visit(Module &M) {
+ if (Reader.isDeclIDFromModule(InterfaceID, M))
+ return true; // We reached the module where the interface originated
+ // from. Stop traversing the imported modules.
+
+ Module::ChainedObjCCategoriesMap::iterator
+ I = M.ChainedObjCCategories.find(InterfaceID);
+ if (I == M.ChainedObjCCategories.end())
+ return false;
+
+ ObjCCategoryDecl *
+ HeadCat = Reader.GetLocalDeclAs<ObjCCategoryDecl>(M, I->second.first);
+ ObjCCategoryDecl *
+ TailCat = Reader.GetLocalDeclAs<ObjCCategoryDecl>(M, I->second.second);
+
+ addCategories(HeadCat, TailCat);
+ return false;
+ }
+
+ void addCategories(ObjCCategoryDecl *HeadCat,
+ ObjCCategoryDecl *TailCat = 0) {
+ if (!HeadCat) {
+ assert(!TailCat);
+ return;
+ }
+
+ if (!TailCat) {
+ TailCat = HeadCat;
+ while (TailCat->getNextClassCategory())
+ TailCat = TailCat->getNextClassCategory();
+ }
+
+ if (!GlobHeadCat) {
+ GlobHeadCat = HeadCat;
+ GlobTailCat = TailCat;
+ } else {
+ ASTDeclReader::setNextObjCCategory(GlobTailCat, HeadCat);
+ GlobTailCat = TailCat;
+ }
+
+ llvm::DenseSet<DeclarationName> Checked;
+ for (ObjCCategoryDecl *Cat = HeadCat,
+ *CatEnd = TailCat->getNextClassCategory();
+ Cat != CatEnd; Cat = Cat->getNextClassCategory()) {
+ if (Checked.count(Cat->getDeclName()))
+ continue;
+ Checked.insert(Cat->getDeclName());
+ checkForDuplicate(Cat);
+ }
+ }
+
+ /// \brief Warns for duplicate categories that come from different modules.
+ void checkForDuplicate(ObjCCategoryDecl *Cat) {
+ DeclarationName Name = Cat->getDeclName();
+ // Find the top category with the same name. We do not want to warn for
+ // duplicates along the established chain because there were already
+ // warnings for them when the module was created. We only want to warn for
+ // duplicates between non-dependent modules:
+ //
+ // MT //
+ // / \ //
+ // ML MR //
+ //
+ // We want to warn for duplicates between ML and MR,not between ML and MT.
+ //
+ // FIXME: We should not warn for duplicates in diamond:
+ //
+ // MT //
+ // / \ //
+ // ML MR //
+ // \ / //
+ // MB //
+ //
+ // If there are duplicates in ML/MR, there will be warning when creating
+ // MB *and* when importing MB. We should not warn when importing.
+ for (ObjCCategoryDecl *Next = Cat->getNextClassCategory(); Next;
+ Next = Next->getNextClassCategory()) {
+ if (Next->getDeclName() == Name)
+ Cat = Next;
+ }
+
+ ObjCCategoryDecl *&PrevCat = NameCategoryMap[Name];
+ if (!PrevCat)
+ PrevCat = Cat;
+
+ if (PrevCat != Cat) {
+ Reader.Diag(Cat->getLocation(), diag::warn_dup_category_def)
+ << Interface->getDeclName() << Name;
+ Reader.Diag(PrevCat->getLocation(), diag::note_previous_definition);
+ }
+ }
+
+ ObjCCategoryDecl *getHeadCategory() const { return GlobHeadCat; }
+ };
+}
+
+void ASTReader::loadObjCChainedCategories(serialization::GlobalDeclID ID,
+ ObjCInterfaceDecl *D) {
+ ObjCChainedCategoriesVisitor Visitor(*this, ID, D);
+ ModuleMgr.visit(ObjCChainedCategoriesVisitor::visit, &Visitor);
+ // Also add the categories that the interface already links to.
+ Visitor.addCategories(D->getCategoryList());
+ D->setCategoryList(Visitor.getHeadCategory());
}
-void ASTDeclReader::UpdateDecl(Decl *D, ASTReader::PerFileData &Module,
+void ASTDeclReader::UpdateDecl(Decl *D, Module &Module,
const RecordData &Record) {
unsigned Idx = 0;
while (Idx < Record.size()) {
switch ((DeclUpdateKind)Record[Idx++]) {
case UPD_CXX_SET_DEFINITIONDATA: {
CXXRecordDecl *RD = cast<CXXRecordDecl>(D);
- CXXRecordDecl *
- DefinitionDecl = cast<CXXRecordDecl>(Reader.GetDecl(Record[Idx++]));
+ CXXRecordDecl *DefinitionDecl
+ = Reader.ReadDeclAs<CXXRecordDecl>(Module, Record, Idx);
assert(!RD->DefinitionData && "DefinitionData is already set!");
InitializeCXXDefinitionData(RD, DefinitionDecl, Record, Idx);
break;
}
case UPD_CXX_ADDED_IMPLICIT_MEMBER:
- cast<CXXRecordDecl>(D)->addedMember(Reader.GetDecl(Record[Idx++]));
+ cast<CXXRecordDecl>(D)->addedMember(Reader.ReadDecl(Module, Record, Idx));
break;
case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
// It will be added to the template's specializations set when loaded.
- Reader.GetDecl(Record[Idx++]);
+ (void)Reader.ReadDecl(Module, Record, Idx);
break;
case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: {
- NamespaceDecl *Anon = cast<NamespaceDecl>(Reader.GetDecl(Record[Idx++]));
+ NamespaceDecl *Anon
+ = Reader.ReadDeclAs<NamespaceDecl>(Module, Record, Idx);
// Guard against these being loaded out of original order. Don't use
// getNextNamespace(), since it tries to access the context and can't in
// the middle of deserialization.
diff --git a/lib/Serialization/ASTReaderInternals.h b/lib/Serialization/ASTReaderInternals.h
new file mode 100644
index 000000000000..99e8be5ee272
--- /dev/null
+++ b/lib/Serialization/ASTReaderInternals.h
@@ -0,0 +1,243 @@
+//===--- ASTReaderInternals.h - AST Reader Internals ------------*- 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 internal definitions used in the AST reader.
+//
+//===----------------------------------------------------------------------===//
+#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 <utility>
+#include <sys/stat.h>
+
+namespace clang {
+
+class ASTReader;
+class HeaderSearch;
+struct HeaderFileInfo;
+
+namespace serialization {
+
+class Module;
+
+namespace reader {
+
+/// \brief Class that performs name lookup into a DeclContext stored
+/// in an AST file.
+class ASTDeclContextNameLookupTrait {
+ ASTReader &Reader;
+ Module &F;
+
+public:
+ /// \brief Pair of begin/end iterators for DeclIDs.
+ ///
+ /// Note that these declaration IDs are local to the module that contains this
+ /// particular lookup t
+ typedef std::pair<DeclID *, DeclID *> data_type;
+
+ /// \brief Special internal key for declaration names.
+ /// The hash table creates keys for comparison; we do not create
+ /// a DeclarationName for the internal key to avoid deserializing types.
+ struct DeclNameKey {
+ DeclarationName::NameKind Kind;
+ uint64_t Data;
+ DeclNameKey() : Kind((DeclarationName::NameKind)0), Data(0) { }
+ };
+
+ typedef DeclarationName external_key_type;
+ typedef DeclNameKey internal_key_type;
+
+ explicit ASTDeclContextNameLookupTrait(ASTReader &Reader,
+ Module &F)
+ : Reader(Reader), F(F) { }
+
+ static bool EqualKey(const internal_key_type& a,
+ const internal_key_type& b) {
+ return a.Kind == b.Kind && a.Data == b.Data;
+ }
+
+ unsigned ComputeHash(const DeclNameKey &Key) const;
+ internal_key_type GetInternalKey(const external_key_type& Name) const;
+ external_key_type GetExternalKey(const internal_key_type& Key) const;
+
+ static std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const unsigned char*& d);
+
+ internal_key_type ReadKey(const unsigned char* d, unsigned);
+
+ data_type ReadData(internal_key_type, const unsigned char* d,
+ unsigned DataLen);
+};
+
+/// \brief The on-disk hash table used for the DeclContext's Name lookup table.
+typedef OnDiskChainedHashTable<ASTDeclContextNameLookupTrait>
+ ASTDeclContextNameLookupTable;
+
+/// \brief Class that performs lookup for an identifier stored in an AST file.
+class ASTIdentifierLookupTrait {
+ ASTReader &Reader;
+ Module &F;
+
+ // If we know the IdentifierInfo in advance, it is here and we will
+ // not build a new one. Used when deserializing information about an
+ // identifier that was constructed before the AST file was read.
+ IdentifierInfo *KnownII;
+
+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, Module &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);
+};
+
+/// \brief The on-disk hash table used to contain information about
+/// all of the identifiers in the program.
+typedef OnDiskChainedHashTable<ASTIdentifierLookupTrait>
+ ASTIdentifierLookupTable;
+
+/// \brief Class that performs lookup for a selector's entries in the global
+/// method pool stored in an AST file.
+class ASTSelectorLookupTrait {
+ ASTReader &Reader;
+ Module &F;
+
+public:
+ struct data_type {
+ SelectorID ID;
+ llvm::SmallVector<ObjCMethodDecl *, 2> Instance;
+ llvm::SmallVector<ObjCMethodDecl *, 2> Factory;
+ };
+
+ typedef Selector external_key_type;
+ typedef external_key_type internal_key_type;
+
+ ASTSelectorLookupTrait(ASTReader &Reader, Module &F)
+ : Reader(Reader), F(F) { }
+
+ static bool EqualKey(const internal_key_type& a,
+ const internal_key_type& b) {
+ return a == b;
+ }
+
+ static unsigned ComputeHash(Selector Sel);
+
+ static const internal_key_type&
+ GetInternalKey(const external_key_type& x) { return x; }
+
+ static std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const unsigned char*& d);
+
+ internal_key_type ReadKey(const unsigned char* d, unsigned);
+ data_type ReadData(Selector, const unsigned char* d, unsigned DataLen);
+};
+
+/// \brief The on-disk hash table used for the global method pool.
+typedef OnDiskChainedHashTable<ASTSelectorLookupTrait>
+ ASTSelectorLookupTable;
+
+/// \brief Trait class used to search the on-disk hash table containing all of
+/// the header search information.
+///
+/// The on-disk hash table contains a mapping from each header path to
+/// information about that header (how many times it has been included, its
+/// controlling macro, etc.). Note that we actually hash based on the
+/// filename, and support "deep" comparisons of file names based on current
+/// inode numbers, so that the search can cope with non-normalized path names
+/// and symlinks.
+class HeaderFileInfoTrait {
+ ASTReader &Reader;
+ Module &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 HeaderFileInfo data_type;
+
+ HeaderFileInfoTrait(ASTReader &Reader, Module &M, HeaderSearch *HS,
+ const char *FrameworkStrings,
+ const char *SearchPath = 0)
+ : Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings),
+ SearchPath(SearchPath) { }
+
+ 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 std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const unsigned char*& d);
+
+ static internal_key_type ReadKey(const unsigned char *d, unsigned) {
+ return (const char *)d;
+ }
+
+ data_type ReadData(const internal_key_type, const unsigned char *d,
+ unsigned DataLen);
+};
+
+/// \brief The on-disk hash table used for known header files.
+typedef OnDiskChainedHashTable<HeaderFileInfoTrait>
+ HeaderFileInfoLookupTable;
+
+} // end namespace clang::serialization::reader
+} // end namespace clang::serialization
+} // end namespace clang
+
+
+#endif
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 14927b9e3bc8..ab07b85bf4c3 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -22,34 +22,51 @@ using namespace clang::serialization;
namespace clang {
class ASTStmtReader : public StmtVisitor<ASTStmtReader> {
+ typedef ASTReader::RecordData RecordData;
+
ASTReader &Reader;
- ASTReader::PerFileData &F;
+ Module &F;
llvm::BitstreamCursor &DeclsCursor;
const ASTReader::RecordData &Record;
unsigned &Idx;
- SourceLocation ReadSourceLocation(const ASTReader::RecordData &R,
- unsigned &I) {
+ SourceLocation ReadSourceLocation(const RecordData &R, unsigned &I) {
return Reader.ReadSourceLocation(F, R, I);
}
- SourceRange ReadSourceRange(const ASTReader::RecordData &R, unsigned &I) {
+
+ SourceRange ReadSourceRange(const RecordData &R, unsigned &I) {
return Reader.ReadSourceRange(F, R, I);
}
- TypeSourceInfo *GetTypeSourceInfo(const ASTReader::RecordData &R,
- unsigned &I) {
+
+ TypeSourceInfo *GetTypeSourceInfo(const RecordData &R, unsigned &I) {
return Reader.GetTypeSourceInfo(F, R, I);
}
+
+ serialization::DeclID ReadDeclID(const RecordData &R, unsigned &I) {
+ return Reader.ReadDeclID(F, R, I);
+ }
+
+ Decl *ReadDecl(const RecordData &R, unsigned &I) {
+ return Reader.ReadDecl(F, R, I);
+ }
+
+ template<typename T>
+ T *ReadDeclAs(const RecordData &R, unsigned &I) {
+ return Reader.ReadDeclAs<T>(F, R, I);
+ }
+
void ReadDeclarationNameLoc(DeclarationNameLoc &DNLoc, DeclarationName Name,
const ASTReader::RecordData &R, unsigned &I) {
Reader.ReadDeclarationNameLoc(F, DNLoc, Name, R, I);
}
+
void ReadDeclarationNameInfo(DeclarationNameInfo &NameInfo,
const ASTReader::RecordData &R, unsigned &I) {
Reader.ReadDeclarationNameInfo(F, NameInfo, R, I);
}
public:
- ASTStmtReader(ASTReader &Reader, ASTReader::PerFileData &F,
+ ASTStmtReader(ASTReader &Reader, Module &F,
llvm::BitstreamCursor &Cursor,
const ASTReader::RecordData &Record, unsigned &Idx)
: Reader(Reader), F(F), DeclsCursor(Cursor), Record(Record), Idx(Idx) { }
@@ -63,7 +80,7 @@ namespace clang {
static const unsigned NumExprFields = NumStmtFields + 7;
/// \brief Read and initialize a ExplicitTemplateArgumentList structure.
- void ReadExplicitTemplateArgumentList(ExplicitTemplateArgumentList &ArgList,
+ void ReadExplicitTemplateArgumentList(ASTTemplateArgumentListInfo &ArgList,
unsigned NumTemplateArgs);
void VisitStmt(Stmt *S);
@@ -74,7 +91,7 @@ namespace clang {
}
void ASTStmtReader::
-ReadExplicitTemplateArgumentList(ExplicitTemplateArgumentList &ArgList,
+ReadExplicitTemplateArgumentList(ASTTemplateArgumentListInfo &ArgList,
unsigned NumTemplateArgs) {
TemplateArgumentListInfo ArgInfo;
ArgInfo.setLAngleLoc(ReadSourceLocation(Record, Idx));
@@ -92,16 +109,16 @@ void ASTStmtReader::VisitStmt(Stmt *S) {
void ASTStmtReader::VisitNullStmt(NullStmt *S) {
VisitStmt(S);
S->setSemiLoc(ReadSourceLocation(Record, Idx));
- S->LeadingEmptyMacro = ReadSourceLocation(Record, Idx);
+ S->HasLeadingEmptyMacro = Record[Idx++];
}
void ASTStmtReader::VisitCompoundStmt(CompoundStmt *S) {
VisitStmt(S);
- llvm::SmallVector<Stmt *, 16> Stmts;
+ SmallVector<Stmt *, 16> Stmts;
unsigned NumStmts = Record[Idx++];
while (NumStmts--)
Stmts.push_back(Reader.ReadSubStmt());
- S->setStmts(*Reader.getContext(), Stmts.data(), Stmts.size());
+ S->setStmts(Reader.getContext(), Stmts.data(), Stmts.size());
S->setLBracLoc(ReadSourceLocation(Record, Idx));
S->setRBracLoc(ReadSourceLocation(Record, Idx));
}
@@ -130,7 +147,7 @@ void ASTStmtReader::VisitDefaultStmt(DefaultStmt *S) {
void ASTStmtReader::VisitLabelStmt(LabelStmt *S) {
VisitStmt(S);
- LabelDecl *LD = cast<LabelDecl>(Reader.GetDecl(Record[Idx++]));
+ LabelDecl *LD = ReadDeclAs<LabelDecl>(Record, Idx);
LD->setStmt(S);
S->setDecl(LD);
S->setSubStmt(Reader.ReadSubStmt());
@@ -139,8 +156,8 @@ void ASTStmtReader::VisitLabelStmt(LabelStmt *S) {
void ASTStmtReader::VisitIfStmt(IfStmt *S) {
VisitStmt(S);
- S->setConditionVariable(*Reader.getContext(),
- cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
+ S->setConditionVariable(Reader.getContext(),
+ ReadDeclAs<VarDecl>(Record, Idx));
S->setCond(Reader.ReadSubExpr());
S->setThen(Reader.ReadSubStmt());
S->setElse(Reader.ReadSubStmt());
@@ -150,8 +167,8 @@ void ASTStmtReader::VisitIfStmt(IfStmt *S) {
void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) {
VisitStmt(S);
- S->setConditionVariable(*Reader.getContext(),
- cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
+ S->setConditionVariable(Reader.getContext(),
+ ReadDeclAs<VarDecl>(Record, Idx));
S->setCond(Reader.ReadSubExpr());
S->setBody(Reader.ReadSubStmt());
S->setSwitchLoc(ReadSourceLocation(Record, Idx));
@@ -172,8 +189,9 @@ void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) {
void ASTStmtReader::VisitWhileStmt(WhileStmt *S) {
VisitStmt(S);
- S->setConditionVariable(*Reader.getContext(),
- cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
+ S->setConditionVariable(Reader.getContext(),
+ ReadDeclAs<VarDecl>(Record, Idx));
+
S->setCond(Reader.ReadSubExpr());
S->setBody(Reader.ReadSubStmt());
S->setWhileLoc(ReadSourceLocation(Record, Idx));
@@ -192,8 +210,8 @@ void ASTStmtReader::VisitForStmt(ForStmt *S) {
VisitStmt(S);
S->setInit(Reader.ReadSubStmt());
S->setCond(Reader.ReadSubExpr());
- S->setConditionVariable(*Reader.getContext(),
- cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
+ S->setConditionVariable(Reader.getContext(),
+ ReadDeclAs<VarDecl>(Record, Idx));
S->setInc(Reader.ReadSubExpr());
S->setBody(Reader.ReadSubStmt());
S->setForLoc(ReadSourceLocation(Record, Idx));
@@ -203,7 +221,7 @@ void ASTStmtReader::VisitForStmt(ForStmt *S) {
void ASTStmtReader::VisitGotoStmt(GotoStmt *S) {
VisitStmt(S);
- S->setLabel(cast<LabelDecl>(Reader.GetDecl(Record[Idx++])));
+ S->setLabel(ReadDeclAs<LabelDecl>(Record, Idx));
S->setGotoLoc(ReadSourceLocation(Record, Idx));
S->setLabelLoc(ReadSourceLocation(Record, Idx));
}
@@ -229,7 +247,7 @@ void ASTStmtReader::VisitReturnStmt(ReturnStmt *S) {
VisitStmt(S);
S->setRetValue(Reader.ReadSubExpr());
S->setReturnLoc(ReadSourceLocation(Record, Idx));
- S->setNRVOCandidate(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
+ S->setNRVOCandidate(ReadDeclAs<VarDecl>(Record, Idx));
}
void ASTStmtReader::VisitDeclStmt(DeclStmt *S) {
@@ -239,13 +257,13 @@ void ASTStmtReader::VisitDeclStmt(DeclStmt *S) {
if (Idx + 1 == Record.size()) {
// Single declaration
- S->setDeclGroup(DeclGroupRef(Reader.GetDecl(Record[Idx++])));
+ S->setDeclGroup(DeclGroupRef(ReadDecl(Record, Idx)));
} else {
- llvm::SmallVector<Decl *, 16> Decls;
- Decls.reserve(Record.size() - Idx);
- for (unsigned N = Record.size(); Idx != N; ++Idx)
- Decls.push_back(Reader.GetDecl(Record[Idx]));
- S->setDeclGroup(DeclGroupRef(DeclGroup::Create(*Reader.getContext(),
+ SmallVector<Decl *, 16> Decls;
+ Decls.reserve(Record.size() - Idx);
+ for (unsigned N = Record.size(); Idx != N; )
+ Decls.push_back(ReadDecl(Record, Idx));
+ S->setDeclGroup(DeclGroupRef(DeclGroup::Create(Reader.getContext(),
Decls.data(),
Decls.size())));
}
@@ -265,21 +283,21 @@ void ASTStmtReader::VisitAsmStmt(AsmStmt *S) {
S->setAsmString(cast_or_null<StringLiteral>(Reader.ReadSubStmt()));
// Outputs and inputs
- llvm::SmallVector<IdentifierInfo *, 16> Names;
- llvm::SmallVector<StringLiteral*, 16> Constraints;
- llvm::SmallVector<Stmt*, 16> Exprs;
+ SmallVector<IdentifierInfo *, 16> Names;
+ SmallVector<StringLiteral*, 16> Constraints;
+ SmallVector<Stmt*, 16> Exprs;
for (unsigned I = 0, N = NumOutputs + NumInputs; I != N; ++I) {
- Names.push_back(Reader.GetIdentifierInfo(Record, Idx));
+ Names.push_back(Reader.GetIdentifierInfo(F, Record, Idx));
Constraints.push_back(cast_or_null<StringLiteral>(Reader.ReadSubStmt()));
Exprs.push_back(Reader.ReadSubStmt());
}
// Constraints
- llvm::SmallVector<StringLiteral*, 16> Clobbers;
+ SmallVector<StringLiteral*, 16> Clobbers;
for (unsigned I = 0; I != NumClobbers; ++I)
Clobbers.push_back(cast_or_null<StringLiteral>(Reader.ReadSubStmt()));
- S->setOutputsAndInputsAndClobbers(*Reader.getContext(),
+ S->setOutputsAndInputsAndClobbers(Reader.getContext(),
Names.data(), Constraints.data(),
Exprs.data(), NumOutputs, NumInputs,
Clobbers.data(), NumClobbers);
@@ -287,7 +305,7 @@ void ASTStmtReader::VisitAsmStmt(AsmStmt *S) {
void ASTStmtReader::VisitExpr(Expr *E) {
VisitStmt(E);
- E->setType(Reader.GetType(Record[Idx++]));
+ E->setType(Reader.readType(F, Record, Idx));
E->setTypeDependent(Record[Idx++]);
E->setValueDependent(Record[Idx++]);
E->setInstantiationDependent(Record[Idx++]);
@@ -309,6 +327,7 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
E->DeclRefExprBits.HasQualifier = Record[Idx++];
E->DeclRefExprBits.HasFoundDecl = Record[Idx++];
E->DeclRefExprBits.HasExplicitTemplateArgs = Record[Idx++];
+ E->DeclRefExprBits.HadMultipleCandidates = Record[Idx++];
unsigned NumTemplateArgs = 0;
if (E->hasExplicitTemplateArgs())
NumTemplateArgs = Record[Idx++];
@@ -318,13 +337,13 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
= Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
if (E->hasFoundDecl())
- E->getInternalFoundDecl() = cast<NamedDecl>(Reader.GetDecl(Record[Idx++]));
+ E->getInternalFoundDecl() = ReadDeclAs<NamedDecl>(Record, Idx);
if (E->hasExplicitTemplateArgs())
ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(),
NumTemplateArgs);
- E->setDecl(cast<ValueDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setDecl(ReadDeclAs<ValueDecl>(Record, Idx));
E->setLocation(ReadSourceLocation(Record, Idx));
ReadDeclarationNameLoc(E->DNLoc, E->getDecl()->getDeclName(), Record, Idx);
}
@@ -332,12 +351,12 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
void ASTStmtReader::VisitIntegerLiteral(IntegerLiteral *E) {
VisitExpr(E);
E->setLocation(ReadSourceLocation(Record, Idx));
- E->setValue(*Reader.getContext(), Reader.ReadAPInt(Record, Idx));
+ E->setValue(Reader.getContext(), Reader.ReadAPInt(Record, Idx));
}
void ASTStmtReader::VisitFloatingLiteral(FloatingLiteral *E) {
VisitExpr(E);
- E->setValue(*Reader.getContext(), Reader.ReadAPFloat(Record, Idx));
+ E->setValue(Reader.getContext(), Reader.ReadAPFloat(Record, Idx));
E->setExact(Record[Idx++]);
E->setLocation(ReadSourceLocation(Record, Idx));
}
@@ -353,12 +372,12 @@ void ASTStmtReader::VisitStringLiteral(StringLiteral *E) {
assert(Record[Idx] == E->getNumConcatenated() &&
"Wrong number of concatenated tokens!");
++Idx;
- E->IsWide = Record[Idx++];
+ E->Kind = static_cast<StringLiteral::StringKind>(Record[Idx++]);
E->IsPascal = Record[Idx++];
// Read string data
llvm::SmallString<16> Str(&Record[Idx], &Record[Idx] + Len);
- E->setString(*Reader.getContext(), Str.str());
+ E->setString(Reader.getContext(), Str.str());
Idx += Len;
// Read source locations
@@ -370,7 +389,7 @@ void ASTStmtReader::VisitCharacterLiteral(CharacterLiteral *E) {
VisitExpr(E);
E->setValue(Record[Idx++]);
E->setLocation(ReadSourceLocation(Record, Idx));
- E->setWide(Record[Idx++]);
+ E->setKind(static_cast<CharacterLiteral::CharacterKind>(Record[Idx++]));
}
void ASTStmtReader::VisitParenExpr(ParenExpr *E) {
@@ -383,7 +402,7 @@ void ASTStmtReader::VisitParenExpr(ParenExpr *E) {
void ASTStmtReader::VisitParenListExpr(ParenListExpr *E) {
VisitExpr(E);
unsigned NumExprs = Record[Idx++];
- E->Exprs = new (*Reader.getContext()) Stmt*[NumExprs];
+ E->Exprs = new (Reader.getContext()) Stmt*[NumExprs];
for (unsigned i = 0; i != NumExprs; ++i)
E->Exprs[i] = Reader.ReadSubStmt();
E->NumExprs = NumExprs;
@@ -418,18 +437,18 @@ void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) {
break;
case Node::Field:
- E->setComponent(I,
- Node(Start,
- dyn_cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++])),
- End));
+ E->setComponent(I, Node(Start, ReadDeclAs<FieldDecl>(Record, Idx), End));
break;
case Node::Identifier:
- E->setComponent(I, Node(Start, Reader.GetIdentifier(Record[Idx++]), End));
+ E->setComponent(I,
+ Node(Start,
+ Reader.GetIdentifierInfo(F, Record, Idx),
+ End));
break;
case Node::Base: {
- CXXBaseSpecifier *Base = new (*Reader.getContext()) CXXBaseSpecifier();
+ CXXBaseSpecifier *Base = new (Reader.getContext()) CXXBaseSpecifier();
*Base = Reader.ReadCXXBaseSpecifier(F, Record, Idx);
E->setComponent(I, Node(Base));
break;
@@ -463,7 +482,7 @@ void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
void ASTStmtReader::VisitCallExpr(CallExpr *E) {
VisitExpr(E);
- E->setNumArgs(*Reader.getContext(), Record[Idx++]);
+ E->setNumArgs(Reader.getContext(), Record[Idx++]);
E->setRParenLoc(ReadSourceLocation(Record, Idx));
E->setCallee(Reader.ReadSubExpr());
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
@@ -509,7 +528,7 @@ void ASTStmtReader::VisitCastExpr(CastExpr *E) {
E->setCastKind((CastExpr::CastKind)Record[Idx++]);
CastExpr::path_iterator BaseI = E->path_begin();
while (NumBaseSpecs--) {
- CXXBaseSpecifier *BaseSpec = new (*Reader.getContext()) CXXBaseSpecifier;
+ CXXBaseSpecifier *BaseSpec = new (Reader.getContext()) CXXBaseSpecifier;
*BaseSpec = Reader.ReadCXXBaseSpecifier(F, Record, Idx);
*BaseI++ = BaseSpec;
}
@@ -525,8 +544,8 @@ void ASTStmtReader::VisitBinaryOperator(BinaryOperator *E) {
void ASTStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
VisitBinaryOperator(E);
- E->setComputationLHSType(Reader.GetType(Record[Idx++]));
- E->setComputationResultType(Reader.GetType(Record[Idx++]));
+ E->setComputationLHSType(Reader.readType(F, Record, Idx));
+ E->setComputationResultType(Reader.readType(F, Record, Idx));
}
void ASTStmtReader::VisitConditionalOperator(ConditionalOperator *E) {
@@ -578,7 +597,7 @@ void ASTStmtReader::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
void ASTStmtReader::VisitExtVectorElementExpr(ExtVectorElementExpr *E) {
VisitExpr(E);
E->setBase(Reader.ReadSubExpr());
- E->setAccessor(Reader.GetIdentifierInfo(Record, Idx));
+ E->setAccessor(Reader.GetIdentifierInfo(F, Record, Idx));
E->setAccessorLoc(ReadSourceLocation(Record, Idx));
}
@@ -593,19 +612,18 @@ void ASTStmtReader::VisitInitListExpr(InitListExpr *E) {
filler = Reader.ReadSubExpr();
E->ArrayFillerOrUnionFieldInit = filler;
} else
- E->ArrayFillerOrUnionFieldInit
- = cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++]));
+ E->ArrayFillerOrUnionFieldInit = ReadDeclAs<FieldDecl>(Record, Idx);
E->sawArrayRangeDesignator(Record[Idx++]);
unsigned NumInits = Record[Idx++];
- E->reserveInits(*Reader.getContext(), NumInits);
+ E->reserveInits(Reader.getContext(), NumInits);
if (isArrayFiller) {
for (unsigned I = 0; I != NumInits; ++I) {
Expr *init = Reader.ReadSubExpr();
- E->updateInit(*Reader.getContext(), I, init ? init : filler);
+ E->updateInit(Reader.getContext(), I, init ? init : filler);
}
} else {
for (unsigned I = 0; I != NumInits; ++I)
- E->updateInit(*Reader.getContext(), I, Reader.ReadSubExpr());
+ E->updateInit(Reader.getContext(), I, Reader.ReadSubExpr());
}
}
@@ -620,11 +638,11 @@ void ASTStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
E->setEqualOrColonLoc(ReadSourceLocation(Record, Idx));
E->setGNUSyntax(Record[Idx++]);
- llvm::SmallVector<Designator, 4> Designators;
+ SmallVector<Designator, 4> Designators;
while (Idx < Record.size()) {
switch ((DesignatorTypes)Record[Idx++]) {
case DESIG_FIELD_DECL: {
- FieldDecl *Field = cast<FieldDecl>(Reader.GetDecl(Record[Idx++]));
+ FieldDecl *Field = ReadDeclAs<FieldDecl>(Record, Idx);
SourceLocation DotLoc
= ReadSourceLocation(Record, Idx);
SourceLocation FieldLoc
@@ -636,7 +654,7 @@ void ASTStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
}
case DESIG_FIELD_NAME: {
- const IdentifierInfo *Name = Reader.GetIdentifierInfo(Record, Idx);
+ const IdentifierInfo *Name = Reader.GetIdentifierInfo(F, Record, Idx);
SourceLocation DotLoc
= ReadSourceLocation(Record, Idx);
SourceLocation FieldLoc
@@ -669,7 +687,7 @@ void ASTStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
}
}
}
- E->setDesignators(*Reader.getContext(),
+ E->setDesignators(Reader.getContext(),
Designators.data(), Designators.size());
}
@@ -689,7 +707,7 @@ void ASTStmtReader::VisitAddrLabelExpr(AddrLabelExpr *E) {
VisitExpr(E);
E->setAmpAmpLoc(ReadSourceLocation(Record, Idx));
E->setLabelLoc(ReadSourceLocation(Record, Idx));
- E->setLabel(cast<LabelDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setLabel(ReadDeclAs<LabelDecl>(Record, Idx));
}
void ASTStmtReader::VisitStmtExpr(StmtExpr *E) {
@@ -715,23 +733,23 @@ void ASTStmtReader::VisitGNUNullExpr(GNUNullExpr *E) {
void ASTStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
VisitExpr(E);
- llvm::SmallVector<Expr *, 16> Exprs;
+ SmallVector<Expr *, 16> Exprs;
unsigned NumExprs = Record[Idx++];
while (NumExprs--)
Exprs.push_back(Reader.ReadSubExpr());
- E->setExprs(*Reader.getContext(), Exprs.data(), Exprs.size());
+ E->setExprs(Reader.getContext(), Exprs.data(), Exprs.size());
E->setBuiltinLoc(ReadSourceLocation(Record, Idx));
E->setRParenLoc(ReadSourceLocation(Record, Idx));
}
void ASTStmtReader::VisitBlockExpr(BlockExpr *E) {
VisitExpr(E);
- E->setBlockDecl(cast_or_null<BlockDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setBlockDecl(ReadDeclAs<BlockDecl>(Record, Idx));
}
void ASTStmtReader::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
VisitExpr(E);
- E->setDecl(cast<VarDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setDecl(ReadDeclAs<VarDecl>(Record, Idx));
E->setLocation(ReadSourceLocation(Record, Idx));
E->setByRef(Record[Idx++]);
E->setConstQualAdded(Record[Idx++]);
@@ -740,9 +758,9 @@ void ASTStmtReader::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
void ASTStmtReader::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
VisitExpr(E);
E->NumAssocs = Record[Idx++];
- E->AssocTypes = new (*Reader.getContext()) TypeSourceInfo*[E->NumAssocs];
+ E->AssocTypes = new (Reader.getContext()) TypeSourceInfo*[E->NumAssocs];
E->SubExprs =
- new(*Reader.getContext()) Stmt*[GenericSelectionExpr::END_EXPR+E->NumAssocs];
+ new(Reader.getContext()) Stmt*[GenericSelectionExpr::END_EXPR+E->NumAssocs];
E->SubExprs[GenericSelectionExpr::CONTROLLING] = Reader.ReadSubExpr();
for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) {
@@ -756,6 +774,25 @@ void ASTStmtReader::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
E->RParenLoc = ReadSourceLocation(Record, Idx);
}
+void ASTStmtReader::VisitAtomicExpr(AtomicExpr *E) {
+ VisitExpr(E);
+ E->setOp(AtomicExpr::AtomicOp(Record[Idx++]));
+ E->setPtr(Reader.ReadSubExpr());
+ E->setOrder(Reader.ReadSubExpr());
+ E->setNumSubExprs(2);
+ if (E->getOp() != AtomicExpr::Load) {
+ E->setVal1(Reader.ReadSubExpr());
+ E->setNumSubExprs(3);
+ }
+ if (E->isCmpXChg()) {
+ E->setOrderFail(Reader.ReadSubExpr());
+ E->setVal2(Reader.ReadSubExpr());
+ E->setNumSubExprs(5);
+ }
+ E->setBuiltinLoc(ReadSourceLocation(Record, Idx));
+ E->setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+
//===----------------------------------------------------------------------===//
// Objective-C Expressions and Statements
@@ -774,21 +811,21 @@ void ASTStmtReader::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
void ASTStmtReader::VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
VisitExpr(E);
- E->setSelector(Reader.GetSelector(Record, Idx));
+ E->setSelector(Reader.ReadSelector(F, Record, Idx));
E->setAtLoc(ReadSourceLocation(Record, Idx));
E->setRParenLoc(ReadSourceLocation(Record, Idx));
}
void ASTStmtReader::VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
VisitExpr(E);
- E->setProtocol(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setProtocol(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
E->setAtLoc(ReadSourceLocation(Record, Idx));
E->setRParenLoc(ReadSourceLocation(Record, Idx));
}
void ASTStmtReader::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
VisitExpr(E);
- E->setDecl(cast<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setDecl(ReadDeclAs<ObjCIvarDecl>(Record, Idx));
E->setLocation(ReadSourceLocation(Record, Idx));
E->setBase(Reader.ReadSubExpr());
E->setIsArrow(Record[Idx++]);
@@ -799,14 +836,11 @@ void ASTStmtReader::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
VisitExpr(E);
bool Implicit = Record[Idx++] != 0;
if (Implicit) {
- ObjCMethodDecl *Getter =
- cast<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++]));
- ObjCMethodDecl *Setter =
- cast<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++]));
+ ObjCMethodDecl *Getter = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
+ ObjCMethodDecl *Setter = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
E->setImplicitProperty(Getter, Setter);
} else {
- E->setExplicitProperty(
- cast<ObjCPropertyDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setExplicitProperty(ReadDeclAs<ObjCPropertyDecl>(Record, Idx));
}
E->setLocation(ReadSourceLocation(Record, Idx));
E->setReceiverLocation(ReadSourceLocation(Record, Idx));
@@ -815,11 +849,10 @@ void ASTStmtReader::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
E->setBase(Reader.ReadSubExpr());
break;
case 1:
- E->setSuperReceiver(Reader.GetType(Record[Idx++]));
+ E->setSuperReceiver(Reader.readType(F, Record, Idx));
break;
case 2:
- E->setClassReceiver(
- cast<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setClassReceiver(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
break;
}
}
@@ -828,6 +861,8 @@ void ASTStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) {
VisitExpr(E);
assert(Record[Idx] == E->getNumArgs());
++Idx;
+ unsigned NumStoredSelLocs = Record[Idx++];
+ E->SelLocsKind = Record[Idx++];
E->setDelegateInitCall(Record[Idx++]);
ObjCMessageExpr::ReceiverKind Kind
= static_cast<ObjCMessageExpr::ReceiverKind>(Record[Idx++]);
@@ -842,7 +877,7 @@ void ASTStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) {
case ObjCMessageExpr::SuperClass:
case ObjCMessageExpr::SuperInstance: {
- QualType T = Reader.GetType(Record[Idx++]);
+ QualType T = Reader.readType(F, Record, Idx);
SourceLocation SuperLoc = ReadSourceLocation(Record, Idx);
E->setSuper(SuperLoc, T, Kind == ObjCMessageExpr::SuperInstance);
break;
@@ -852,16 +887,19 @@ void ASTStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) {
assert(Kind == E->getReceiverKind());
if (Record[Idx++])
- E->setMethodDecl(cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setMethodDecl(ReadDeclAs<ObjCMethodDecl>(Record, Idx));
else
- E->setSelector(Reader.GetSelector(Record, Idx));
+ E->setSelector(Reader.ReadSelector(F, Record, Idx));
E->LBracLoc = ReadSourceLocation(Record, Idx);
E->RBracLoc = ReadSourceLocation(Record, Idx);
- E->SelectorLoc = ReadSourceLocation(Record, Idx);
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
E->setArg(I, Reader.ReadSubExpr());
+
+ SourceLocation *Locs = E->getStoredSelLocs();
+ for (unsigned I = 0; I != NumStoredSelLocs; ++I)
+ Locs[I] = ReadSourceLocation(Record, Idx);
}
void ASTStmtReader::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
@@ -876,7 +914,7 @@ void ASTStmtReader::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
void ASTStmtReader::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
VisitStmt(S);
S->setCatchBody(Reader.ReadSubStmt());
- S->setCatchParamDecl(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
+ S->setCatchParamDecl(ReadDeclAs<VarDecl>(Record, Idx));
S->setAtCatchLoc(ReadSourceLocation(Record, Idx));
S->setRParenLoc(ReadSourceLocation(Record, Idx));
}
@@ -927,7 +965,7 @@ void ASTStmtReader::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
void ASTStmtReader::VisitCXXCatchStmt(CXXCatchStmt *S) {
VisitStmt(S);
S->CatchLoc = ReadSourceLocation(Record, Idx);
- S->ExceptionDecl = cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]));
+ S->ExceptionDecl = ReadDeclAs<VarDecl>(Record, Idx);
S->HandlerBlock = Reader.ReadSubStmt();
}
@@ -963,12 +1001,13 @@ void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
VisitExpr(E);
E->NumArgs = Record[Idx++];
if (E->NumArgs)
- E->Args = new (*Reader.getContext()) Stmt*[E->NumArgs];
+ E->Args = new (Reader.getContext()) Stmt*[E->NumArgs];
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
E->setArg(I, Reader.ReadSubExpr());
- E->setConstructor(cast<CXXConstructorDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setConstructor(ReadDeclAs<CXXConstructorDecl>(Record, Idx));
E->setLocation(ReadSourceLocation(Record, Idx));
- E->setElidable(Record[Idx++]);
+ E->setElidable(Record[Idx++]);
+ E->setHadMultipleCandidates(Record[Idx++]);
E->setRequiresZeroInitialization(Record[Idx++]);
E->setConstructionKind((CXXConstructExpr::ConstructionKind)Record[Idx++]);
E->ParenRange = ReadSourceRange(Record, Idx);
@@ -1048,15 +1087,15 @@ void ASTStmtReader::VisitCXXThrowExpr(CXXThrowExpr *E) {
void ASTStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
VisitExpr(E);
- assert(Record[Idx] == E->Param.getInt() && "We messed up at creation ?");
+ assert((bool)Record[Idx] == E->Param.getInt() && "We messed up at creation ?");
++Idx; // HasOtherExprStored and SubExpr was handled during creation.
- E->Param.setPointer(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
+ E->Param.setPointer(ReadDeclAs<ParmVarDecl>(Record, Idx));
E->Loc = ReadSourceLocation(Record, Idx);
}
void ASTStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
VisitExpr(E);
- E->setTemporary(Reader.ReadCXXTemporary(Record, Idx));
+ E->setTemporary(Reader.ReadCXXTemporary(F, Record, Idx));
E->setSubExpr(Reader.ReadSubExpr());
}
@@ -1072,13 +1111,12 @@ void ASTStmtReader::VisitCXXNewExpr(CXXNewExpr *E) {
E->Initializer = Record[Idx++];
E->UsualArrayDeleteWantsSize = Record[Idx++];
bool isArray = Record[Idx++];
+ E->setHadMultipleCandidates(Record[Idx++]);
unsigned NumPlacementArgs = Record[Idx++];
unsigned NumCtorArgs = Record[Idx++];
- E->setOperatorNew(cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++])));
- E->setOperatorDelete(
- cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++])));
- E->setConstructor(
- cast_or_null<CXXConstructorDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setOperatorNew(ReadDeclAs<FunctionDecl>(Record, Idx));
+ E->setOperatorDelete(ReadDeclAs<FunctionDecl>(Record, Idx));
+ E->setConstructor(ReadDeclAs<CXXConstructorDecl>(Record, Idx));
E->AllocatedTypeInfo = GetTypeSourceInfo(Record, Idx);
SourceRange TypeIdParens;
TypeIdParens.setBegin(ReadSourceLocation(Record, Idx));
@@ -1089,7 +1127,7 @@ void ASTStmtReader::VisitCXXNewExpr(CXXNewExpr *E) {
E->ConstructorLParen = ReadSourceLocation(Record, Idx);
E->ConstructorRParen = ReadSourceLocation(Record, Idx);
- E->AllocateArgsArray(*Reader.getContext(), isArray, NumPlacementArgs,
+ E->AllocateArgsArray(Reader.getContext(), isArray, NumPlacementArgs,
NumCtorArgs);
// Install all the subexpressions.
@@ -1104,7 +1142,7 @@ void ASTStmtReader::VisitCXXDeleteExpr(CXXDeleteExpr *E) {
E->ArrayForm = Record[Idx++];
E->ArrayFormAsWritten = Record[Idx++];
E->UsualArrayDeleteWantsSize = Record[Idx++];
- E->OperatorDelete = cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++]));
+ E->OperatorDelete = ReadDeclAs<FunctionDecl>(Record, Idx);
E->Argument = Reader.ReadSubExpr();
E->Loc = ReadSourceLocation(Record, Idx);
}
@@ -1120,7 +1158,7 @@ void ASTStmtReader::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
E->ColonColonLoc = ReadSourceLocation(Record, Idx);
E->TildeLoc = ReadSourceLocation(Record, Idx);
- IdentifierInfo *II = Reader.GetIdentifierInfo(Record, Idx);
+ IdentifierInfo *II = Reader.GetIdentifierInfo(F, Record, Idx);
if (II)
E->setDestroyedType(II, ReadSourceLocation(Record, Idx));
else
@@ -1131,9 +1169,9 @@ void ASTStmtReader::VisitExprWithCleanups(ExprWithCleanups *E) {
VisitExpr(E);
unsigned NumTemps = Record[Idx++];
if (NumTemps) {
- E->setNumTemporaries(*Reader.getContext(), NumTemps);
+ E->setNumTemporaries(Reader.getContext(), NumTemps);
for (unsigned i = 0; i != NumTemps; ++i)
- E->setTemporary(i, Reader.ReadCXXTemporary(Record, Idx));
+ E->setTemporary(i, Reader.ReadCXXTemporary(F, Record, Idx));
}
E->setSubExpr(Reader.ReadSubExpr());
}
@@ -1147,12 +1185,11 @@ ASTStmtReader::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){
Record[Idx++]);
E->Base = Reader.ReadSubExpr();
- E->BaseType = Reader.GetType(Record[Idx++]);
+ E->BaseType = Reader.readType(F, Record, Idx);
E->IsArrow = Record[Idx++];
E->OperatorLoc = ReadSourceLocation(Record, Idx);
E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
- E->FirstQualifierFoundInScope
- = cast_or_null<NamedDecl>(Reader.GetDecl(Record[Idx++]));
+ E->FirstQualifierFoundInScope = ReadDeclAs<NamedDecl>(Record, Idx);
ReadDeclarationNameInfo(E->MemberNameInfo, Record, Idx);
}
@@ -1191,11 +1228,11 @@ void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) {
unsigned NumDecls = Record[Idx++];
UnresolvedSet<8> Decls;
for (unsigned i = 0; i != NumDecls; ++i) {
- NamedDecl *D = cast<NamedDecl>(Reader.GetDecl(Record[Idx++]));
+ NamedDecl *D = ReadDeclAs<NamedDecl>(Record, Idx);
AccessSpecifier AS = (AccessSpecifier)Record[Idx++];
Decls.addDecl(D, AS);
}
- E->initializeResults(*Reader.getContext(), Decls.begin(), Decls.end());
+ E->initializeResults(Reader.getContext(), Decls.begin(), Decls.end());
ReadDeclarationNameInfo(E->NameInfo, Record, Idx);
E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
@@ -1206,7 +1243,7 @@ void ASTStmtReader::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
E->IsArrow = Record[Idx++];
E->HasUnresolvedUsing = Record[Idx++];
E->Base = Reader.ReadSubExpr();
- E->BaseType = Reader.GetType(Record[Idx++]);
+ E->BaseType = Reader.readType(F, Record, Idx);
E->OperatorLoc = ReadSourceLocation(Record, Idx);
}
@@ -1216,7 +1253,7 @@ void ASTStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
if (E->RequiresADL)
E->StdIsAssociatedNamespace = Record[Idx++];
E->Overloaded = Record[Idx++];
- E->NamingClass = cast_or_null<CXXRecordDecl>(Reader.GetDecl(Record[Idx++]));
+ E->NamingClass = ReadDeclAs<CXXRecordDecl>(Record, Idx);
}
void ASTStmtReader::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
@@ -1280,14 +1317,13 @@ void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
E->PackLoc = ReadSourceLocation(Record, Idx);
E->RParenLoc = ReadSourceLocation(Record, Idx);
E->Length = Record[Idx++];
- E->Pack = cast_or_null<NamedDecl>(Reader.GetDecl(Record[Idx++]));
+ E->Pack = ReadDeclAs<NamedDecl>(Record, Idx);
}
void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr(
SubstNonTypeTemplateParmExpr *E) {
VisitExpr(E);
- E->Param
- = cast_or_null<NonTypeTemplateParmDecl>(Reader.GetDecl(Record[Idx++]));
+ E->Param = ReadDeclAs<NonTypeTemplateParmDecl>(Record, Idx);
E->NameLoc = ReadSourceLocation(Record, Idx);
E->Replacement = Reader.ReadSubExpr();
}
@@ -1295,8 +1331,7 @@ void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr(
void ASTStmtReader::VisitSubstNonTypeTemplateParmPackExpr(
SubstNonTypeTemplateParmPackExpr *E) {
VisitExpr(E);
- E->Param
- = cast_or_null<NonTypeTemplateParmDecl>(Reader.GetDecl(Record[Idx++]));
+ E->Param = ReadDeclAs<NonTypeTemplateParmDecl>(Record, Idx);
TemplateArgument ArgPack = Reader.ReadTemplateArgument(F, Record, Idx);
if (ArgPack.getKind() != TemplateArgument::Pack)
return;
@@ -1377,7 +1412,7 @@ void ASTStmtReader::VisitAsTypeExpr(AsTypeExpr *E) {
// ASTReader Implementation
//===----------------------------------------------------------------------===//
-Stmt *ASTReader::ReadStmt(PerFileData &F) {
+Stmt *ASTReader::ReadStmt(Module &F) {
switch (ReadingKind) {
case Read_Decl:
case Read_Type:
@@ -1390,7 +1425,7 @@ Stmt *ASTReader::ReadStmt(PerFileData &F) {
return 0;
}
-Expr *ASTReader::ReadExpr(PerFileData &F) {
+Expr *ASTReader::ReadExpr(Module &F) {
return cast_or_null<Expr>(ReadStmt(F));
}
@@ -1405,7 +1440,7 @@ Expr *ASTReader::ReadSubExpr() {
// the stack, with expressions having operands removing those operands from the
// stack. Evaluation terminates when we see a STMT_STOP record, and
// the single remaining expression on the stack is our result.
-Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
+Stmt *ASTReader::ReadStmtFromStream(Module &F) {
ReadingKindTracker ReadingKind(Read_Stmt, *this);
llvm::BitstreamCursor &Cursor = F.DeclsCursor;
@@ -1531,20 +1566,20 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
case EXPR_DECL_REF:
S = DeclRefExpr::CreateEmpty(
- *Context,
+ Context,
/*HasQualifier=*/Record[ASTStmtReader::NumExprFields],
/*HasFoundDecl=*/Record[ASTStmtReader::NumExprFields + 1],
/*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 2],
/*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 2] ?
- Record[ASTStmtReader::NumExprFields + 3] : 0);
+ Record[ASTStmtReader::NumExprFields + 4] : 0);
break;
case EXPR_INTEGER_LITERAL:
- S = IntegerLiteral::Create(*Context, Empty);
+ S = IntegerLiteral::Create(Context, Empty);
break;
case EXPR_FLOATING_LITERAL:
- S = FloatingLiteral::Create(*Context, Empty);
+ S = FloatingLiteral::Create(Context, Empty);
break;
case EXPR_IMAGINARY_LITERAL:
@@ -1552,7 +1587,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
break;
case EXPR_STRING_LITERAL:
- S = StringLiteral::CreateEmpty(*Context,
+ S = StringLiteral::CreateEmpty(Context,
Record[ASTStmtReader::NumExprFields + 1]);
break;
@@ -1573,7 +1608,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
break;
case EXPR_OFFSETOF:
- S = OffsetOfExpr::CreateEmpty(*Context,
+ S = OffsetOfExpr::CreateEmpty(Context,
Record[ASTStmtReader::NumExprFields],
Record[ASTStmtReader::NumExprFields + 1]);
break;
@@ -1587,7 +1622,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
break;
case EXPR_CALL:
- S = new (Context) CallExpr(*Context, Stmt::CallExprClass, Empty);
+ S = new (Context) CallExpr(Context, Stmt::CallExprClass, Empty);
break;
case EXPR_MEMBER: {
@@ -1610,25 +1645,29 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
for (unsigned i = 0; i != NumTemplateArgs; ++i)
ArgInfo.addArgument(ReadTemplateArgumentLoc(F, Record, Idx));
}
-
- NamedDecl *FoundD = cast_or_null<NamedDecl>(GetDecl(Record[Idx++]));
+
+ bool HadMultipleCandidates = Record[Idx++];
+
+ NamedDecl *FoundD = ReadDeclAs<NamedDecl>(F, Record, Idx);
AccessSpecifier AS = (AccessSpecifier)Record[Idx++];
DeclAccessPair FoundDecl = DeclAccessPair::make(FoundD, AS);
- QualType T = GetType(Record[Idx++]);
+ QualType T = readType(F, Record, Idx);
ExprValueKind VK = static_cast<ExprValueKind>(Record[Idx++]);
ExprObjectKind OK = static_cast<ExprObjectKind>(Record[Idx++]);
Expr *Base = ReadSubExpr();
- ValueDecl *MemberD = cast<ValueDecl>(GetDecl(Record[Idx++]));
+ ValueDecl *MemberD = ReadDeclAs<ValueDecl>(F, Record, Idx);
SourceLocation MemberLoc = ReadSourceLocation(F, Record, Idx);
DeclarationNameInfo MemberNameInfo(MemberD->getDeclName(), MemberLoc);
bool IsArrow = Record[Idx++];
- S = MemberExpr::Create(*Context, Base, IsArrow, QualifierLoc,
+ S = MemberExpr::Create(Context, Base, IsArrow, QualifierLoc,
MemberD, FoundDecl, MemberNameInfo,
HasExplicitTemplateArgs ? &ArgInfo : 0, T, VK, OK);
ReadDeclarationNameLoc(F, cast<MemberExpr>(S)->MemberDNLoc,
MemberD->getDeclName(), Record, Idx);
+ if (HadMultipleCandidates)
+ cast<MemberExpr>(S)->setHadMultipleCandidates(true);
break;
}
@@ -1649,12 +1688,12 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
break;
case EXPR_IMPLICIT_CAST:
- S = ImplicitCastExpr::CreateEmpty(*Context,
+ S = ImplicitCastExpr::CreateEmpty(Context,
/*PathSize*/ Record[ASTStmtReader::NumExprFields]);
break;
case EXPR_CSTYLE_CAST:
- S = CStyleCastExpr::CreateEmpty(*Context,
+ S = CStyleCastExpr::CreateEmpty(Context,
/*PathSize*/ Record[ASTStmtReader::NumExprFields]);
break;
@@ -1667,11 +1706,11 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
break;
case EXPR_INIT_LIST:
- S = new (Context) InitListExpr(*getContext(), Empty);
+ S = new (Context) InitListExpr(getContext(), Empty);
break;
case EXPR_DESIGNATED_INIT:
- S = DesignatedInitExpr::CreateEmpty(*Context,
+ S = DesignatedInitExpr::CreateEmpty(Context,
Record[ASTStmtReader::NumExprFields] - 1);
break;
@@ -1738,8 +1777,9 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
llvm_unreachable("mismatching AST file");
break;
case EXPR_OBJC_MESSAGE_EXPR:
- S = ObjCMessageExpr::CreateEmpty(*Context,
- Record[ASTStmtReader::NumExprFields]);
+ S = ObjCMessageExpr::CreateEmpty(Context,
+ Record[ASTStmtReader::NumExprFields],
+ Record[ASTStmtReader::NumExprFields + 1]);
break;
case EXPR_OBJC_ISA:
S = new (Context) ObjCIsaExpr(Empty);
@@ -1760,7 +1800,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
S = new (Context) ObjCAtFinallyStmt(Empty);
break;
case STMT_OBJC_AT_TRY:
- S = ObjCAtTryStmt::CreateEmpty(*Context,
+ S = ObjCAtTryStmt::CreateEmpty(Context,
Record[ASTStmtReader::NumStmtFields],
Record[ASTStmtReader::NumStmtFields + 1]);
break;
@@ -1787,7 +1827,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
break;
case STMT_CXX_TRY:
- S = CXXTryStmt::Create(*Context, Empty,
+ S = CXXTryStmt::Create(Context, Empty,
/*NumHandlers=*/Record[ASTStmtReader::NumStmtFields]);
break;
@@ -1796,11 +1836,11 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
break;
case EXPR_CXX_OPERATOR_CALL:
- S = new (Context) CXXOperatorCallExpr(*Context, Empty);
+ S = new (Context) CXXOperatorCallExpr(Context, Empty);
break;
case EXPR_CXX_MEMBER_CALL:
- S = new (Context) CXXMemberCallExpr(*Context, Empty);
+ S = new (Context) CXXMemberCallExpr(Context, Empty);
break;
case EXPR_CXX_CONSTRUCT:
@@ -1812,26 +1852,26 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
break;
case EXPR_CXX_STATIC_CAST:
- S = CXXStaticCastExpr::CreateEmpty(*Context,
+ S = CXXStaticCastExpr::CreateEmpty(Context,
/*PathSize*/ Record[ASTStmtReader::NumExprFields]);
break;
case EXPR_CXX_DYNAMIC_CAST:
- S = CXXDynamicCastExpr::CreateEmpty(*Context,
+ S = CXXDynamicCastExpr::CreateEmpty(Context,
/*PathSize*/ Record[ASTStmtReader::NumExprFields]);
break;
case EXPR_CXX_REINTERPRET_CAST:
- S = CXXReinterpretCastExpr::CreateEmpty(*Context,
+ S = CXXReinterpretCastExpr::CreateEmpty(Context,
/*PathSize*/ Record[ASTStmtReader::NumExprFields]);
break;
case EXPR_CXX_CONST_CAST:
- S = CXXConstCastExpr::CreateEmpty(*Context);
+ S = CXXConstCastExpr::CreateEmpty(Context);
break;
case EXPR_CXX_FUNCTIONAL_CAST:
- S = CXXFunctionalCastExpr::CreateEmpty(*Context,
+ S = CXXFunctionalCastExpr::CreateEmpty(Context,
/*PathSize*/ Record[ASTStmtReader::NumExprFields]);
break;
@@ -1864,7 +1904,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
bool HasOtherExprStored = Record[ASTStmtReader::NumExprFields];
if (HasOtherExprStored) {
Expr *SubExpr = ReadSubExpr();
- S = CXXDefaultArgExpr::Create(*Context, SourceLocation(), 0, SubExpr);
+ S = CXXDefaultArgExpr::Create(Context, SourceLocation(), 0, SubExpr);
} else
S = new (Context) CXXDefaultArgExpr(Empty);
break;
@@ -1891,7 +1931,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
break;
case EXPR_CXX_DEPENDENT_SCOPE_MEMBER:
- S = CXXDependentScopeMemberExpr::CreateEmpty(*Context,
+ S = CXXDependentScopeMemberExpr::CreateEmpty(Context,
/*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields],
/*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields]
? Record[ASTStmtReader::NumExprFields + 1]
@@ -1899,7 +1939,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
break;
case EXPR_CXX_DEPENDENT_SCOPE_DECL_REF:
- S = DependentScopeDeclRefExpr::CreateEmpty(*Context,
+ S = DependentScopeDeclRefExpr::CreateEmpty(Context,
/*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields],
/*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields]
? Record[ASTStmtReader::NumExprFields + 1]
@@ -1907,12 +1947,12 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
break;
case EXPR_CXX_UNRESOLVED_CONSTRUCT:
- S = CXXUnresolvedConstructExpr::CreateEmpty(*Context,
+ S = CXXUnresolvedConstructExpr::CreateEmpty(Context,
/*NumArgs=*/Record[ASTStmtReader::NumExprFields]);
break;
case EXPR_CXX_UNRESOLVED_MEMBER:
- S = UnresolvedMemberExpr::CreateEmpty(*Context,
+ S = UnresolvedMemberExpr::CreateEmpty(Context,
/*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields],
/*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields]
? Record[ASTStmtReader::NumExprFields + 1]
@@ -1920,7 +1960,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
break;
case EXPR_CXX_UNRESOLVED_LOOKUP:
- S = UnresolvedLookupExpr::CreateEmpty(*Context,
+ S = UnresolvedLookupExpr::CreateEmpty(Context,
/*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields],
/*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields]
? Record[ASTStmtReader::NumExprFields + 1]
@@ -1983,12 +2023,16 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
}
case EXPR_CUDA_KERNEL_CALL:
- S = new (Context) CUDAKernelCallExpr(*Context, Empty);
+ S = new (Context) CUDAKernelCallExpr(Context, Empty);
break;
case EXPR_ASTYPE:
S = new (Context) AsTypeExpr(Empty);
break;
+
+ case EXPR_ATOMIC:
+ S = new (Context) AtomicExpr(Empty);
+ break;
}
// We hit a STMT_STOP, so we're done with this expression.
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 39f2fbddf80e..b31262d375fe 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -12,7 +12,6 @@
//===----------------------------------------------------------------------===//
#include "clang/Serialization/ASTWriter.h"
-#include "clang/Serialization/ASTSerializationListener.h"
#include "ASTCommon.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/IdentifierResolver.h"
@@ -45,21 +44,23 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
+#include <algorithm>
#include <cstdio>
#include <string.h>
+#include <utility>
using namespace clang;
using namespace clang::serialization;
template <typename T, typename Allocator>
-static llvm::StringRef data(const std::vector<T, Allocator> &v) {
- if (v.empty()) return llvm::StringRef();
- return llvm::StringRef(reinterpret_cast<const char*>(&v[0]),
+static StringRef data(const std::vector<T, Allocator> &v) {
+ if (v.empty()) return StringRef();
+ return StringRef(reinterpret_cast<const char*>(&v[0]),
sizeof(T) * v.size());
}
template <typename T>
-static llvm::StringRef data(const llvm::SmallVectorImpl<T> &v) {
- return llvm::StringRef(reinterpret_cast<const char*>(v.data()),
+static StringRef data(const SmallVectorImpl<T> &v) {
+ return StringRef(reinterpret_cast<const char*>(v.data()),
sizeof(T) * v.size());
}
@@ -90,7 +91,7 @@ namespace {
}
void ASTTypeWriter::VisitBuiltinType(const BuiltinType *T) {
- assert(false && "Built-in types are never serialized");
+ llvm_unreachable("Built-in types are never serialized");
}
void ASTTypeWriter::VisitComplexType(const ComplexType *T) {
@@ -304,7 +305,7 @@ void
ASTTypeWriter::VisitDependentSizedExtVectorType(
const DependentSizedExtVectorType *T) {
// FIXME: Serialize this type (C++ only)
- assert(false && "Cannot serialize dependent sized extended vector types");
+ llvm_unreachable("Cannot serialize dependent sized extended vector types");
}
void
@@ -387,6 +388,12 @@ ASTTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
Code = TYPE_OBJC_OBJECT_POINTER;
}
+void
+ASTTypeWriter::VisitAtomicType(const AtomicType *T) {
+ Writer.AddTypeRef(T->getValueType(), Record);
+ Code = TYPE_ATOMIC;
+}
+
namespace {
class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> {
@@ -595,6 +602,11 @@ void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
void TypeLocWriter::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
Writer.AddSourceLocation(TL.getStarLoc(), Record);
}
+void TypeLocWriter::VisitAtomicTypeLoc(AtomicTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getKWLoc(), Record);
+ Writer.AddSourceLocation(TL.getLParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getRParenLoc(), Record);
+}
//===----------------------------------------------------------------------===//
// ASTWriter Implementation
@@ -762,8 +774,8 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(STAT_CACHE);
RECORD(EXT_VECTOR_DECLS);
RECORD(VERSION_CONTROL_BRANCH_REVISION);
- RECORD(MACRO_DEFINITION_OFFSETS);
- RECORD(CHAINED_METADATA);
+ RECORD(PPD_ENTITIES_OFFSETS);
+ RECORD(IMPORTS);
RECORD(REFERENCED_SELECTOR_POOL);
RECORD(TU_UPDATE_LEXICAL);
RECORD(REDECLS_UPDATE_LATEST);
@@ -778,11 +790,14 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(DIAG_PRAGMA_MAPPINGS);
RECORD(CUDA_SPECIAL_DECL_REFS);
RECORD(HEADER_SEARCH_TABLE);
+ RECORD(ORIGINAL_PCH_DIR);
RECORD(FP_PRAGMA_OPTIONS);
RECORD(OPENCL_EXTENSIONS);
RECORD(DELEGATING_CTORS);
RECORD(FILE_SOURCE_LOCATION_OFFSETS);
RECORD(KNOWN_NAMESPACES);
+ RECORD(MODULE_OFFSET_MAP);
+ RECORD(SOURCE_MANAGER_LINE_TABLE);
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
@@ -790,7 +805,6 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(SM_SLOC_BUFFER_ENTRY);
RECORD(SM_SLOC_BUFFER_BLOB);
RECORD(SM_SLOC_EXPANSION_ENTRY);
- RECORD(SM_LINE_TABLE);
// Preprocessor Block.
BLOCK(PREPROCESSOR_BLOCK);
@@ -837,7 +851,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(TYPE_PACK_EXPANSION);
RECORD(TYPE_ATTRIBUTED);
RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK);
- RECORD(DECL_TRANSLATION_UNIT);
+ RECORD(TYPE_ATOMIC);
RECORD(DECL_TYPEDEF);
RECORD(DECL_ENUM);
RECORD(DECL_RECORD);
@@ -916,15 +930,15 @@ void ASTWriter::WriteBlockInfoBlock() {
/// \returns either the original filename (if it needs no adjustment) or the
/// adjusted filename (which points into the @p Filename parameter).
static const char *
-adjustFilenameForRelocatablePCH(const char *Filename, const char *isysroot) {
+adjustFilenameForRelocatablePCH(const char *Filename, StringRef isysroot) {
assert(Filename && "No file name to adjust?");
- if (!isysroot)
+ if (isysroot.empty())
return Filename;
// Verify that the filename and the system root have the same prefix.
unsigned Pos = 0;
- for (; Filename[Pos] && isysroot[Pos]; ++Pos)
+ for (; Filename[Pos] && Pos < isysroot.size(); ++Pos)
if (Filename[Pos] != isysroot[Pos])
return Filename; // Prefixes don't match.
@@ -942,34 +956,52 @@ adjustFilenameForRelocatablePCH(const char *Filename, const char *isysroot) {
}
/// \brief Write the AST metadata (e.g., i686-apple-darwin9).
-void ASTWriter::WriteMetadata(ASTContext &Context, const char *isysroot,
+void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot,
const std::string &OutputFile) {
using namespace llvm;
// Metadata
- const TargetInfo &Target = Context.Target;
+ const TargetInfo &Target = Context.getTargetInfo();
BitCodeAbbrev *MetaAbbrev = new BitCodeAbbrev();
- MetaAbbrev->Add(BitCodeAbbrevOp(
- Chain ? CHAINED_METADATA : METADATA));
+ MetaAbbrev->Add(BitCodeAbbrevOp(METADATA));
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // AST major
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // AST minor
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang major
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang minor
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable
- // Target triple or chained PCH name
- MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Target triple
unsigned MetaAbbrevCode = Stream.EmitAbbrev(MetaAbbrev);
RecordData Record;
- Record.push_back(Chain ? CHAINED_METADATA : METADATA);
+ Record.push_back(METADATA);
Record.push_back(VERSION_MAJOR);
Record.push_back(VERSION_MINOR);
Record.push_back(CLANG_VERSION_MAJOR);
Record.push_back(CLANG_VERSION_MINOR);
- Record.push_back(isysroot != 0);
- // FIXME: This writes the absolute path for chained headers.
- const std::string &BlobStr = Chain ? Chain->getFileName() : Target.getTriple().getTriple();
- Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, BlobStr);
+ Record.push_back(!isysroot.empty());
+ const std::string &Triple = Target.getTriple().getTriple();
+ Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, Triple);
+
+ if (Chain) {
+ serialization::ModuleManager &Mgr = Chain->getModuleManager();
+ llvm::SmallVector<char, 128> ModulePaths;
+ Record.clear();
+
+ for (ModuleManager::ModuleIterator M = Mgr.begin(), MEnd = Mgr.end();
+ M != MEnd; ++M) {
+ // Skip modules that weren't directly imported.
+ if (!(*M)->isDirectlyImported())
+ continue;
+
+ Record.push_back((unsigned)(*M)->Kind); // FIXME: Stable encoding
+ // FIXME: Write import location, once it matters.
+ // FIXME: This writes the absolute path for AST files we depend on.
+ const std::string &FileName = (*M)->FileName;
+ Record.push_back(FileName.size());
+ Record.append(FileName.begin(), FileName.end());
+ }
+ Stream.EmitRecord(IMPORTS, Record);
+ }
// Original file name and file ID
SourceManager &SM = Context.getSourceManager();
@@ -1026,94 +1058,11 @@ void ASTWriter::WriteMetadata(ASTContext &Context, const char *isysroot,
/// \brief Write the LangOptions structure.
void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
RecordData Record;
- Record.push_back(LangOpts.Trigraphs);
- Record.push_back(LangOpts.BCPLComment); // BCPL-style '//' comments.
- Record.push_back(LangOpts.DollarIdents); // '$' allowed in identifiers.
- Record.push_back(LangOpts.AsmPreprocessor); // Preprocessor in asm mode.
- Record.push_back(LangOpts.GNUMode); // True in gnu99 mode false in c99 mode (etc)
- Record.push_back(LangOpts.GNUKeywords); // Allow GNU-extension keywords
- Record.push_back(LangOpts.ImplicitInt); // C89 implicit 'int'.
- Record.push_back(LangOpts.Digraphs); // C94, C99 and C++
- Record.push_back(LangOpts.HexFloats); // C99 Hexadecimal float constants.
- Record.push_back(LangOpts.C99); // C99 Support
- Record.push_back(LangOpts.C1X); // C1X Support
- Record.push_back(LangOpts.Microsoft); // Microsoft extensions.
- // LangOpts.MSCVersion is ignored because all it does it set a macro, which is
- // already saved elsewhere.
- Record.push_back(LangOpts.CPlusPlus); // C++ Support
- Record.push_back(LangOpts.CPlusPlus0x); // C++0x Support
- Record.push_back(LangOpts.CXXOperatorNames); // Treat C++ operator names as keywords.
-
- Record.push_back(LangOpts.ObjC1); // Objective-C 1 support enabled.
- Record.push_back(LangOpts.ObjC2); // Objective-C 2 support enabled.
- Record.push_back(LangOpts.ObjCNonFragileABI); // Objective-C
- // modern abi enabled.
- Record.push_back(LangOpts.ObjCNonFragileABI2); // Objective-C enhanced
- // modern abi enabled.
- Record.push_back(LangOpts.AppleKext); // Apple's kernel extensions ABI
- Record.push_back(LangOpts.ObjCDefaultSynthProperties); // Objective-C auto-synthesized
- // properties enabled.
- Record.push_back(LangOpts.ObjCInferRelatedResultType);
- Record.push_back(LangOpts.NoConstantCFStrings); // non cfstring generation enabled..
-
- Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings
- Record.push_back(LangOpts.WritableStrings); // Allow writable strings
- Record.push_back(LangOpts.LaxVectorConversions);
- Record.push_back(LangOpts.AltiVec);
- Record.push_back(LangOpts.Exceptions); // Support exception handling.
- Record.push_back(LangOpts.ObjCExceptions);
- Record.push_back(LangOpts.CXXExceptions);
- Record.push_back(LangOpts.SjLjExceptions);
-
- Record.push_back(LangOpts.MSBitfields); // MS-compatible structure layout
- Record.push_back(LangOpts.NeXTRuntime); // Use NeXT runtime.
- Record.push_back(LangOpts.Freestanding); // Freestanding implementation
- Record.push_back(LangOpts.NoBuiltin); // Do not use builtin functions (-fno-builtin)
-
- // Whether static initializers are protected by locks.
- Record.push_back(LangOpts.ThreadsafeStatics);
- Record.push_back(LangOpts.POSIXThreads);
- Record.push_back(LangOpts.Blocks); // block extension to C
- Record.push_back(LangOpts.EmitAllDecls); // Emit all declarations, even if
- // they are unused.
- Record.push_back(LangOpts.MathErrno); // Math functions must respect errno
- // (modulo the platform support).
-
- Record.push_back(LangOpts.getSignedOverflowBehavior());
- Record.push_back(LangOpts.HeinousExtensions);
-
- Record.push_back(LangOpts.Optimize); // Whether __OPTIMIZE__ should be defined.
- Record.push_back(LangOpts.OptimizeSize); // Whether __OPTIMIZE_SIZE__ should be
- // defined.
- Record.push_back(LangOpts.Static); // Should __STATIC__ be defined (as
- // opposed to __DYNAMIC__).
- Record.push_back(LangOpts.PICLevel); // The value for __PIC__, if non-zero.
-
- Record.push_back(LangOpts.GNUInline); // Should GNU inline semantics be
- // used (instead of C99 semantics).
- Record.push_back(LangOpts.NoInline); // Should __NO_INLINE__ be defined.
- Record.push_back(LangOpts.Deprecated); // Should __DEPRECATED be defined.
- Record.push_back(LangOpts.AccessControl); // Whether C++ access control should
- // be enabled.
- Record.push_back(LangOpts.CharIsSigned); // Whether char is a signed or
- // unsigned type
- Record.push_back(LangOpts.ShortWChar); // force wchar_t to be unsigned short
- Record.push_back(LangOpts.ShortEnums); // Should the enum type be equivalent
- // to the smallest integer type with
- // enough room.
- Record.push_back(LangOpts.getGCMode());
- Record.push_back(LangOpts.getVisibilityMode());
- Record.push_back(LangOpts.getStackProtectorMode());
- Record.push_back(LangOpts.InstantiationDepth);
- Record.push_back(LangOpts.OpenCL);
- Record.push_back(LangOpts.CUDA);
- Record.push_back(LangOpts.CatchUndefined);
- Record.push_back(LangOpts.DefaultFPContract);
- Record.push_back(LangOpts.ElideConstructors);
- Record.push_back(LangOpts.SpellChecking);
- Record.push_back(LangOpts.MRTD);
- Record.push_back(LangOpts.ObjCAutoRefCount);
- Record.push_back(LangOpts.ObjCInferRelatedReturnType);
+#define LANGOPT(Name, Bits, Default, Description) \
+ Record.push_back(LangOpts.Name);
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ Record.push_back(static_cast<unsigned>(LangOpts.get##Name()));
+#include "clang/Basic/LangOptions.def"
Stream.EmitRecord(LANGUAGE_OPTIONS, Record);
}
@@ -1136,7 +1085,7 @@ public:
}
std::pair<unsigned,unsigned>
- EmitKeyDataLength(llvm::raw_ostream& Out, const char *path,
+ EmitKeyDataLength(raw_ostream& Out, const char *path,
data_type_ref Data) {
unsigned StrLen = strlen(path);
clang::io::Emit16(Out, StrLen);
@@ -1145,11 +1094,11 @@ public:
return std::make_pair(StrLen + 1, DataLen);
}
- void EmitKey(llvm::raw_ostream& Out, const char *path, unsigned KeyLen) {
+ void EmitKey(raw_ostream& Out, const char *path, unsigned KeyLen) {
Out.write(path, KeyLen);
}
- void EmitData(llvm::raw_ostream &Out, key_type_ref,
+ 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;
@@ -1174,7 +1123,7 @@ void ASTWriter::WriteStatCache(MemorizeStatCalls &StatCalls) {
for (MemorizeStatCalls::iterator Stat = StatCalls.begin(),
StatEnd = StatCalls.end();
Stat != StatEnd; ++Stat, ++NumStatEntries) {
- llvm::StringRef Filename = Stat->first();
+ StringRef Filename = Stat->first();
Generator.insert(Filename.data(), Stat->second);
}
@@ -1222,6 +1171,7 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) {
// FileEntry fields.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumCreatedFIDs
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
return Stream.EmitAbbrev(Abbrev);
}
@@ -1270,6 +1220,10 @@ namespace {
ASTWriter &Writer;
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, HeaderSearch &HS)
: Writer(Writer), HS(HS) { }
@@ -1289,28 +1243,29 @@ namespace {
}
std::pair<unsigned,unsigned>
- EmitKeyDataLength(llvm::raw_ostream& Out, const char *path,
+ EmitKeyDataLength(raw_ostream& Out, const char *path,
data_type_ref Data) {
unsigned StrLen = strlen(path);
clang::io::Emit16(Out, StrLen);
- unsigned DataLen = 1 + 2 + 4;
+ unsigned DataLen = 1 + 2 + 4 + 4;
clang::io::Emit8(Out, DataLen);
return std::make_pair(StrLen + 1, DataLen);
}
- void EmitKey(llvm::raw_ostream& Out, const char *path, unsigned KeyLen) {
+ void EmitKey(raw_ostream& Out, const char *path, unsigned KeyLen) {
Out.write(path, KeyLen);
}
- void EmitData(llvm::raw_ostream &Out, key_type_ref,
+ 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;
- unsigned char Flags = (Data.isImport << 4)
- | (Data.isPragmaOnce << 3)
- | (Data.DirInfo << 1)
- | Data.Resolved;
+ unsigned char Flags = (Data.isImport << 5)
+ | (Data.isPragmaOnce << 4)
+ | (Data.DirInfo << 2)
+ | (Data.Resolved << 1)
+ | Data.IndexHeaderMapHeader;
Emit8(Out, (uint8_t)Flags);
Emit16(Out, (uint16_t) Data.NumIncludes);
@@ -1318,8 +1273,29 @@ namespace {
Emit32(Out, (uint32_t)Data.ControllingMacroID);
else
Emit32(Out, (uint32_t)Writer.getIdentifierRef(Data.ControllingMacro));
+
+ unsigned Offset = 0;
+ if (!Data.Framework.empty()) {
+ // If this header refers into a framework, save the framework name.
+ llvm::StringMap<unsigned>::iterator Pos
+ = FrameworkNameOffset.find(Data.Framework);
+ if (Pos == FrameworkNameOffset.end()) {
+ Offset = FrameworkStringData.size() + 1;
+ FrameworkStringData.append(Data.Framework.begin(),
+ Data.Framework.end());
+ FrameworkStringData.push_back(0);
+
+ FrameworkNameOffset[Data.Framework] = Offset;
+ } else
+ Offset = Pos->second;
+ }
+ Emit32(Out, Offset);
+
assert(Out.tell() - Start == DataLen && "Wrong data length");
}
+
+ const char *strings_begin() const { return FrameworkStringData.begin(); }
+ const char *strings_end() const { return FrameworkStringData.end(); }
};
} // end anonymous namespace
@@ -1328,8 +1304,8 @@ namespace {
/// \param HS The header search structure to save.
///
/// \param Chain Whether we're creating a chained AST file.
-void ASTWriter::WriteHeaderSearch(HeaderSearch &HS, const char* isysroot) {
- llvm::SmallVector<const FileEntry *, 16> FilesByUID;
+void ASTWriter::WriteHeaderSearch(HeaderSearch &HS, StringRef isysroot) {
+ SmallVector<const FileEntry *, 16> FilesByUID;
HS.getFileMgr().GetUniqueIDMapping(FilesByUID);
if (FilesByUID.size() > HS.header_file_size())
@@ -1337,7 +1313,7 @@ void ASTWriter::WriteHeaderSearch(HeaderSearch &HS, const char* isysroot) {
HeaderFileInfoTrait GeneratorTrait(*this, HS);
OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator;
- llvm::SmallVector<const char *, 4> SavedStrings;
+ SmallVector<const char *, 4> SavedStrings;
unsigned NumHeaderSearchEntries = 0;
for (unsigned UID = 0, LastUID = FilesByUID.size(); UID != LastUID; ++UID) {
const FileEntry *File = FilesByUID[UID];
@@ -1379,14 +1355,17 @@ void ASTWriter::WriteHeaderSearch(HeaderSearch &HS, const char* isysroot) {
Abbrev->Add(BitCodeAbbrevOp(HEADER_SEARCH_TABLE));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned TableAbbrev = Stream.EmitAbbrev(Abbrev);
- // Write the stat cache
+ // Write the header search table
RecordData Record;
Record.push_back(HEADER_SEARCH_TABLE);
Record.push_back(BucketOffset);
Record.push_back(NumHeaderSearchEntries);
+ Record.push_back(TableData.size());
+ TableData.append(GeneratorTrait.strings_begin(),GeneratorTrait.strings_end());
Stream.EmitRecordWithBlob(TableAbbrev, Record, TableData.str());
// Free all of the strings we had to duplicate.
@@ -1404,7 +1383,7 @@ void ASTWriter::WriteHeaderSearch(HeaderSearch &HS, const char* isysroot) {
/// the files in the AST.
void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
const Preprocessor &PP,
- const char *isysroot) {
+ StringRef isysroot) {
RecordData Record;
// Enter the source manager block.
@@ -1416,43 +1395,6 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
unsigned SLocBufferBlobAbbrv = CreateSLocBufferBlobAbbrev(Stream);
unsigned SLocExpansionAbbrv = CreateSLocExpansionAbbrev(Stream);
- // Write the line table.
- if (SourceMgr.hasLineTable()) {
- LineTableInfo &LineTable = SourceMgr.getLineTable();
-
- // Emit the file names
- Record.push_back(LineTable.getNumFilenames());
- for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I) {
- // Emit the file name
- const char *Filename = LineTable.getFilename(I);
- Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
- unsigned FilenameLen = Filename? strlen(Filename) : 0;
- Record.push_back(FilenameLen);
- if (FilenameLen)
- Record.insert(Record.end(), Filename, Filename + FilenameLen);
- }
-
- // Emit the line entries
- for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end();
- L != LEnd; ++L) {
- // Emit the file ID
- Record.push_back(L->first);
-
- // Emit the line entries
- Record.push_back(L->second.size());
- for (std::vector<LineEntry>::iterator LE = L->second.begin(),
- LEEnd = L->second.end();
- LE != LEEnd; ++LE) {
- Record.push_back(LE->FileOffset);
- Record.push_back(LE->LineNo);
- Record.push_back(LE->FilenameID);
- Record.push_back((unsigned)LE->FileKind);
- Record.push_back(LE->IncludeOffset);
- }
- }
- Stream.EmitRecord(SM_LINE_TABLE, Record);
- }
-
// Write out the source location entry table. We skip the first
// entry, which is always the same dummy entry.
std::vector<uint32_t> SLocEntryOffsets;
@@ -1460,12 +1402,11 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// We will go through them in ASTReader::validateFileEntries().
std::vector<uint32_t> SLocFileEntryOffsets;
RecordData PreloadSLocs;
- unsigned BaseSLocID = Chain ? Chain->getTotalNumSLocs() : 0;
- SLocEntryOffsets.reserve(SourceMgr.sloc_entry_size() - 1 - BaseSLocID);
- for (unsigned I = BaseSLocID + 1, N = SourceMgr.sloc_entry_size();
+ SLocEntryOffsets.reserve(SourceMgr.local_sloc_entry_size() - 1);
+ for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size();
I != N; ++I) {
// Get this source location entry.
- const SrcMgr::SLocEntry *SLoc = &SourceMgr.getSLocEntry(I);
+ const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I);
// Record the offset of this source-location entry.
SLocEntryOffsets.push_back(Stream.GetCurrentBitNo());
@@ -1483,7 +1424,8 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
Record.clear();
Record.push_back(Code);
- Record.push_back(SLoc->getOffset());
+ // Starting offset of this entry within this module, so skip the dummy.
+ Record.push_back(SLoc->getOffset() - 2);
if (SLoc->isFile()) {
const SrcMgr::FileInfo &File = SLoc->getFile();
Record.push_back(File.getIncludeLoc().getRawEncoding());
@@ -1502,6 +1444,8 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
Record.push_back(Content->OrigEntry->getSize());
Record.push_back(Content->OrigEntry->getModificationTime());
+ Record.push_back(File.NumCreatedFIDs);
+
// Turn the file name into an absolute path, if it isn't already.
const char *Filename = Content->OrigEntry->getName();
llvm::SmallString<128> FilePath(Filename);
@@ -1528,27 +1472,29 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
= Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager());
const char *Name = Buffer->getBufferIdentifier();
Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record,
- llvm::StringRef(Name, strlen(Name) + 1));
+ StringRef(Name, strlen(Name) + 1));
Record.clear();
Record.push_back(SM_SLOC_BUFFER_BLOB);
Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record,
- llvm::StringRef(Buffer->getBufferStart(),
+ StringRef(Buffer->getBufferStart(),
Buffer->getBufferSize() + 1));
- if (strcmp(Name, "<built-in>") == 0)
- PreloadSLocs.push_back(BaseSLocID + SLocEntryOffsets.size());
+ if (strcmp(Name, "<built-in>") == 0) {
+ PreloadSLocs.push_back(SLocEntryOffsets.size());
+ }
}
} else {
// The source location entry is a macro expansion.
- const SrcMgr::InstantiationInfo &Inst = SLoc->getInstantiation();
- Record.push_back(Inst.getSpellingLoc().getRawEncoding());
- Record.push_back(Inst.getInstantiationLocStart().getRawEncoding());
- Record.push_back(Inst.getInstantiationLocEnd().getRawEncoding());
+ const SrcMgr::ExpansionInfo &Expansion = SLoc->getExpansion();
+ Record.push_back(Expansion.getSpellingLoc().getRawEncoding());
+ Record.push_back(Expansion.getExpansionLocStart().getRawEncoding());
+ Record.push_back(Expansion.isMacroArgExpansion() ? 0
+ : Expansion.getExpansionLocEnd().getRawEncoding());
// Compute the token length for this macro expansion.
- unsigned NextOffset = SourceMgr.getNextOffset();
+ unsigned NextOffset = SourceMgr.getNextLocalOffset();
if (I + 1 != N)
- NextOffset = SourceMgr.getSLocEntry(I + 1).getOffset();
+ NextOffset = SourceMgr.getLocalSLocEntry(I + 1).getOffset();
Record.push_back(NextOffset - SLoc->getOffset() - 1);
Stream.EmitRecordWithAbbrev(SLocExpansionAbbrv, Record);
}
@@ -1565,15 +1511,14 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SOURCE_LOCATION_OFFSETS));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // next offset
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // total size
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets
unsigned SLocOffsetsAbbrev = Stream.EmitAbbrev(Abbrev);
Record.clear();
Record.push_back(SOURCE_LOCATION_OFFSETS);
Record.push_back(SLocEntryOffsets.size());
- unsigned BaseOffset = Chain ? Chain->getNextSLocOffset() : 0;
- Record.push_back(SourceMgr.getNextOffset() - BaseOffset);
+ Record.push_back(SourceMgr.getNextLocalOffset() - 1); // skip dummy
Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, data(SLocEntryOffsets));
Abbrev = new BitCodeAbbrev();
@@ -1591,6 +1536,49 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// Write the source location entry preloads array, telling the AST
// reader which source locations entries it should load eagerly.
Stream.EmitRecord(SOURCE_LOCATION_PRELOADS, PreloadSLocs);
+
+ // Write the line table. It depends on remapping working, so it must come
+ // after the source location offsets.
+ if (SourceMgr.hasLineTable()) {
+ LineTableInfo &LineTable = SourceMgr.getLineTable();
+
+ Record.clear();
+ // Emit the file names
+ Record.push_back(LineTable.getNumFilenames());
+ for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I) {
+ // Emit the file name
+ const char *Filename = LineTable.getFilename(I);
+ Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
+ unsigned FilenameLen = Filename? strlen(Filename) : 0;
+ Record.push_back(FilenameLen);
+ if (FilenameLen)
+ Record.insert(Record.end(), Filename, Filename + FilenameLen);
+ }
+
+ // Emit the line entries
+ for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end();
+ L != LEnd; ++L) {
+ // Only emit entries for local files.
+ if (L->first < 0)
+ continue;
+
+ // Emit the file ID
+ Record.push_back(L->first);
+
+ // Emit the line entries
+ Record.push_back(L->second.size());
+ for (std::vector<LineEntry>::iterator LE = L->second.begin(),
+ LEEnd = L->second.end();
+ LE != LEEnd; ++LE) {
+ Record.push_back(LE->FileOffset);
+ Record.push_back(LE->LineNo);
+ Record.push_back(LE->FilenameID);
+ Record.push_back((unsigned)LE->FileKind);
+ Record.push_back(LE->IncludeOffset);
+ }
+ }
+ Stream.EmitRecord(SOURCE_MANAGER_LINE_TABLE, Record);
+ }
}
//===----------------------------------------------------------------------===//
@@ -1608,7 +1596,11 @@ static int compareMacroDefinitions(const void *XPtr, const void *YPtr) {
/// \brief Writes the block containing the serialized form of the
/// preprocessor.
///
-void ASTWriter::WritePreprocessor(const Preprocessor &PP) {
+void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
+ PreprocessingRecord *PPRec = PP.getPreprocessingRecord();
+ if (PPRec)
+ WritePreprocessorDetail(*PPRec);
+
RecordData Record;
// If the preprocessor __COUNTER__ value has been bumped, remember it.
@@ -1629,17 +1621,18 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP) {
// Loop over all the macro definitions that are live at the end of the file,
// emitting each to the PP section.
- PreprocessingRecord *PPRec = PP.getPreprocessingRecord();
// Construct the list of macro definitions that need to be serialized.
- llvm::SmallVector<std::pair<const IdentifierInfo *, MacroInfo *>, 2>
+ 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);
I != E; ++I) {
- MacroDefinitionsSeen.insert(I->first);
- MacrosToEmit.push_back(std::make_pair(I->first, I->second));
+ if (!IsModule || I->second->isExported()) {
+ MacroDefinitionsSeen.insert(I->first);
+ MacrosToEmit.push_back(std::make_pair(I->first, I->second));
+ }
}
// Sort the set of macro definitions that need to be serialized by the
@@ -1671,14 +1664,15 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP) {
// chained PCH, by storing the offset into the original PCH rather than
// writing the macro definition a second time.
if (MI->isBuiltinMacro() ||
- (Chain && Name->isFromAST() && MI->isFromAST()))
+ (Chain && Name->isFromAST() && MI->isFromAST() &&
+ !MI->hasChangedAfterLoad()))
continue;
AddIdentifierRef(Name, Record);
MacroOffsets[Name] = Stream.GetCurrentBitNo();
Record.push_back(MI->getDefinitionLoc().getRawEncoding());
Record.push_back(MI->isUsed());
-
+ AddSourceLocation(MI->getExportLocation(), Record);
unsigned Code;
if (MI->isObjectLike()) {
Code = PP_MACRO_OBJECT_LIKE;
@@ -1696,7 +1690,7 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP) {
// If we have a detailed preprocessing record, record the macro definition
// ID that corresponds to this macro.
if (PPRec)
- Record.push_back(getMacroDefinitionID(PPRec->findMacroDefinition(MI)));
+ Record.push_back(MacroDefinitions[PPRec->findMacroDefinition(MI)]);
Stream.EmitRecord(Code, Record);
Record.clear();
@@ -1725,15 +1719,14 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP) {
++NumMacros;
}
Stream.ExitBlock();
-
- if (PPRec)
- WritePreprocessorDetail(*PPRec);
}
void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {
- if (PPRec.begin(Chain) == PPRec.end(Chain))
+ if (PPRec.local_begin() == PPRec.local_end())
return;
-
+
+ SmallVector<PPEntityOffset, 64> PreprocessedEntityOffsets;
+
// Enter the preprocessor block.
Stream.EnterSubblock(PREPROCESSOR_DETAIL_BLOCK_ID, 3);
@@ -1746,9 +1739,6 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {
{
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(PPD_INCLUSION_DIRECTIVE));
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // index
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // start location
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // end location
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // filename length
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // in quotes
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // kind
@@ -1756,65 +1746,41 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {
InclusionAbbrev = Stream.EmitAbbrev(Abbrev);
}
- unsigned IndexBase = Chain ? PPRec.getNumPreallocatedEntities() : 0;
+ unsigned FirstPreprocessorEntityID
+ = (Chain ? PPRec.getNumLoadedPreprocessedEntities() : 0)
+ + NUM_PREDEF_PP_ENTITY_IDS;
+ unsigned NextPreprocessorEntityID = FirstPreprocessorEntityID;
RecordData Record;
- for (PreprocessingRecord::iterator E = PPRec.begin(Chain),
- EEnd = PPRec.end(Chain);
- E != EEnd; ++E) {
+ for (PreprocessingRecord::iterator E = PPRec.local_begin(),
+ EEnd = PPRec.local_end();
+ E != EEnd;
+ (void)++E, ++NumPreprocessingRecords, ++NextPreprocessorEntityID) {
Record.clear();
+ PreprocessedEntityOffsets.push_back(PPEntityOffset((*E)->getSourceRange(),
+ Stream.GetCurrentBitNo()));
+
if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*E)) {
- // Record this macro definition's location.
- MacroID ID = getMacroDefinitionID(MD);
-
- // Don't write the macro definition if it is from another AST file.
- if (ID < FirstMacroID)
- continue;
+ // Record this macro definition's ID.
+ MacroDefinitions[MD] = NextPreprocessorEntityID;
- // Notify the serialization listener that we're serializing this entity.
- if (SerializationListener)
- SerializationListener->SerializedPreprocessedEntity(*E,
- Stream.GetCurrentBitNo());
-
- unsigned Position = ID - FirstMacroID;
- if (Position != MacroDefinitionOffsets.size()) {
- if (Position > MacroDefinitionOffsets.size())
- MacroDefinitionOffsets.resize(Position + 1);
-
- MacroDefinitionOffsets[Position] = Stream.GetCurrentBitNo();
- } else
- MacroDefinitionOffsets.push_back(Stream.GetCurrentBitNo());
-
- Record.push_back(IndexBase + NumPreprocessingRecords++);
- Record.push_back(ID);
- AddSourceLocation(MD->getSourceRange().getBegin(), Record);
- AddSourceLocation(MD->getSourceRange().getEnd(), Record);
AddIdentifierRef(MD->getName(), Record);
- AddSourceLocation(MD->getLocation(), Record);
Stream.EmitRecord(PPD_MACRO_DEFINITION, Record);
continue;
}
- // Notify the serialization listener that we're serializing this entity.
- if (SerializationListener)
- SerializationListener->SerializedPreprocessedEntity(*E,
- Stream.GetCurrentBitNo());
-
if (MacroExpansion *ME = dyn_cast<MacroExpansion>(*E)) {
- Record.push_back(IndexBase + NumPreprocessingRecords++);
- AddSourceLocation(ME->getSourceRange().getBegin(), Record);
- AddSourceLocation(ME->getSourceRange().getEnd(), Record);
- AddIdentifierRef(ME->getName(), Record);
- Record.push_back(getMacroDefinitionID(ME->getDefinition()));
+ Record.push_back(ME->isBuiltinMacro());
+ if (ME->isBuiltinMacro())
+ AddIdentifierRef(ME->getName(), Record);
+ else
+ Record.push_back(MacroDefinitions[ME->getDefinition()]);
Stream.EmitRecord(PPD_MACRO_EXPANSION, Record);
continue;
}
if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*E)) {
Record.push_back(PPD_INCLUSION_DIRECTIVE);
- Record.push_back(IndexBase + NumPreprocessingRecords++);
- AddSourceLocation(ID->getSourceRange().getBegin(), Record);
- AddSourceLocation(ID->getSourceRange().getEnd(), Record);
Record.push_back(ID->getFileName().size());
Record.push_back(ID->wasInQuotes());
Record.push_back(static_cast<unsigned>(ID->getKind()));
@@ -1831,40 +1797,39 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {
// Write the offsets table for the preprocessing record.
if (NumPreprocessingRecords > 0) {
+ assert(PreprocessedEntityOffsets.size() == NumPreprocessingRecords);
+
// Write the offsets table for identifier IDs.
using namespace llvm;
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
- Abbrev->Add(BitCodeAbbrevOp(MACRO_DEFINITION_OFFSETS));
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of records
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macro defs
+ Abbrev->Add(BitCodeAbbrevOp(PPD_ENTITIES_OFFSETS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first pp entity
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
- unsigned MacroDefOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+ unsigned PPEOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
Record.clear();
- Record.push_back(MACRO_DEFINITION_OFFSETS);
- Record.push_back(NumPreprocessingRecords);
- Record.push_back(MacroDefinitionOffsets.size());
- Stream.EmitRecordWithBlob(MacroDefOffsetAbbrev, Record,
- data(MacroDefinitionOffsets));
+ Record.push_back(PPD_ENTITIES_OFFSETS);
+ Record.push_back(FirstPreprocessorEntityID - NUM_PREDEF_PP_ENTITY_IDS);
+ Stream.EmitRecordWithBlob(PPEOffsetAbbrev, Record,
+ data(PreprocessedEntityOffsets));
}
}
-void ASTWriter::WritePragmaDiagnosticMappings(const Diagnostic &Diag) {
+void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag) {
RecordData Record;
- for (Diagnostic::DiagStatePointsTy::const_iterator
+ for (DiagnosticsEngine::DiagStatePointsTy::const_iterator
I = Diag.DiagStatePoints.begin(), E = Diag.DiagStatePoints.end();
I != E; ++I) {
- const Diagnostic::DiagStatePoint &point = *I;
+ const DiagnosticsEngine::DiagStatePoint &point = *I;
if (point.Loc.isInvalid())
continue;
Record.push_back(point.Loc.getRawEncoding());
- for (Diagnostic::DiagState::iterator
+ for (DiagnosticsEngine::DiagState::const_iterator
I = point.State->begin(), E = point.State->end(); I != E; ++I) {
- unsigned diag = I->first, map = I->second;
- if (map & 0x10) { // mapping from a diagnostic pragma.
- Record.push_back(diag);
- Record.push_back(map & 0x7);
+ if (I->second.isPragma()) {
+ Record.push_back(I->first);
+ Record.push_back(I->second.getMapping());
}
}
Record.push_back(-1); // mark the end of the diag/map pairs for this
@@ -1890,7 +1855,7 @@ void ASTWriter::WriteCXXBaseSpecifiersOffsets() {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned BaseSpecifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
- // Write the selector offsets table.
+ // Write the base specifier offsets table.
Record.clear();
Record.push_back(CXX_BASE_SPECIFIER_OFFSETS);
Record.push_back(CXXBaseSpecifiersOffsets.size());
@@ -1964,7 +1929,7 @@ uint64_t ASTWriter::WriteDeclContextLexicalBlock(ASTContext &Context,
uint64_t Offset = Stream.GetCurrentBitNo();
RecordData Record;
Record.push_back(DECL_CONTEXT_LEXICAL);
- llvm::SmallVector<KindDeclIDPair, 64> Decls;
+ SmallVector<KindDeclIDPair, 64> Decls;
for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end();
D != DEnd; ++D)
Decls.push_back(std::make_pair((*D)->getKind(), GetDeclRef(*D)));
@@ -1982,22 +1947,26 @@ void ASTWriter::WriteTypeDeclOffsets() {
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(TYPE_OFFSET));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of types
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // base type index
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // types block
unsigned TypeOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
Record.clear();
Record.push_back(TYPE_OFFSET);
Record.push_back(TypeOffsets.size());
+ Record.push_back(FirstTypeID - NUM_PREDEF_TYPE_IDS);
Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, data(TypeOffsets));
// Write the declaration offsets array
Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(DECL_OFFSET));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of declarations
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // base decl ID
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // declarations block
unsigned DeclOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
Record.clear();
Record.push_back(DECL_OFFSET);
Record.push_back(DeclOffsets.size());
+ Record.push_back(FirstDeclID - NUM_PREDEF_DECL_IDS);
Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, data(DeclOffsets));
}
@@ -2027,7 +1996,7 @@ public:
}
std::pair<unsigned,unsigned>
- EmitKeyDataLength(llvm::raw_ostream& Out, Selector Sel,
+ EmitKeyDataLength(raw_ostream& Out, Selector Sel,
data_type_ref Methods) {
unsigned KeyLen = 2 + (Sel.getNumArgs()? Sel.getNumArgs() * 4 : 4);
clang::io::Emit16(Out, KeyLen);
@@ -2044,7 +2013,7 @@ public:
return std::make_pair(KeyLen, DataLen);
}
- void EmitKey(llvm::raw_ostream& Out, Selector Sel, unsigned) {
+ void EmitKey(raw_ostream& Out, Selector Sel, unsigned) {
uint64_t Start = Out.tell();
assert((Start >> 32) == 0 && "Selector key offset too large");
Writer.SetSelectorOffset(Sel, Start);
@@ -2057,7 +2026,7 @@ public:
Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I)));
}
- void EmitData(llvm::raw_ostream& Out, key_type_ref,
+ void EmitData(raw_ostream& Out, key_type_ref,
data_type_ref Methods, unsigned DataLen) {
uint64_t Start = Out.tell(); (void)Start;
clang::io::Emit32(Out, Methods.ID);
@@ -2130,12 +2099,12 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) {
bool changed = false;
for (ObjCMethodList *M = &Data.Instance; !changed && M && M->Method;
M = M->Next) {
- if (M->Method->getPCHLevel() == 0)
+ if (!M->Method->isFromASTFile())
changed = true;
}
for (ObjCMethodList *M = &Data.Factory; !changed && M && M->Method;
M = M->Next) {
- if (M->Method->getPCHLevel() == 0)
+ if (!M->Method->isFromASTFile())
changed = true;
}
if (!changed)
@@ -2177,6 +2146,7 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) {
Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SELECTOR_OFFSETS));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned SelectorOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
@@ -2184,6 +2154,7 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) {
Record.clear();
Record.push_back(SELECTOR_OFFSETS);
Record.push_back(SelectorOffsets.size());
+ Record.push_back(FirstSelectorID - NUM_PREDEF_SELECTOR_IDS);
Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record,
data(SelectorOffsets));
}
@@ -2219,41 +2190,53 @@ namespace {
class ASTIdentifierTableTrait {
ASTWriter &Writer;
Preprocessor &PP;
-
+ bool IsModule;
+
/// \brief Determines whether this is an "interesting" identifier
/// that needs a full IdentifierInfo structure written into the hash
/// table.
- static bool isInterestingIdentifier(const IdentifierInfo *II) {
- return II->isPoisoned() ||
- II->isExtensionToken() ||
- II->hasMacroDefinition() ||
- II->getObjCOrBuiltinID() ||
- II->getFETokenInfo<void>();
+ bool isInterestingIdentifier(IdentifierInfo *II, MacroInfo *&Macro) {
+ if (II->isPoisoned() ||
+ II->isExtensionToken() ||
+ II->getObjCOrBuiltinID() ||
+ II->getFETokenInfo<void>())
+ return true;
+
+ return hasMacroDefinition(II, Macro);
+ }
+
+ bool hasMacroDefinition(IdentifierInfo *II, MacroInfo *&Macro) {
+ if (!II->hasMacroDefinition())
+ return false;
+
+ if (Macro || (Macro = PP.getMacroInfo(II)))
+ return !Macro->isBuiltinMacro() && (!IsModule || Macro->isExported());
+
+ return false;
}
public:
- typedef const IdentifierInfo* key_type;
+ typedef IdentifierInfo* key_type;
typedef key_type key_type_ref;
typedef IdentID data_type;
typedef data_type data_type_ref;
- ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP)
- : Writer(Writer), PP(PP) { }
+ ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP, bool IsModule)
+ : Writer(Writer), PP(PP), IsModule(IsModule) { }
static unsigned ComputeHash(const IdentifierInfo* II) {
return llvm::HashString(II->getName());
}
std::pair<unsigned,unsigned>
- EmitKeyDataLength(llvm::raw_ostream& Out, const IdentifierInfo* II,
- IdentID ID) {
+ EmitKeyDataLength(raw_ostream& Out, IdentifierInfo* II, IdentID ID) {
unsigned KeyLen = II->getLength() + 1;
unsigned DataLen = 4; // 4 bytes for the persistent ID << 1
- if (isInterestingIdentifier(II)) {
+ MacroInfo *Macro = 0;
+ if (isInterestingIdentifier(II, Macro)) {
DataLen += 2; // 2 bytes for builtin ID, flags
- if (II->hasMacroDefinition() &&
- !PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro())
+ if (hasMacroDefinition(II, Macro))
DataLen += 4;
for (IdentifierResolver::iterator D = IdentifierResolver::begin(II),
DEnd = IdentifierResolver::end();
@@ -2268,7 +2251,7 @@ public:
return std::make_pair(KeyLen, DataLen);
}
- void EmitKey(llvm::raw_ostream& Out, const IdentifierInfo* II,
+ void EmitKey(raw_ostream& Out, const IdentifierInfo* II,
unsigned KeyLen) {
// Record the location of the key data. This is used when generating
// the mapping from persistent IDs to strings.
@@ -2276,27 +2259,26 @@ public:
Out.write(II->getNameStart(), KeyLen);
}
- void EmitData(llvm::raw_ostream& Out, const IdentifierInfo* II,
+ void EmitData(raw_ostream& Out, IdentifierInfo* II,
IdentID ID, unsigned) {
- if (!isInterestingIdentifier(II)) {
+ MacroInfo *Macro = 0;
+ if (!isInterestingIdentifier(II, Macro)) {
clang::io::Emit32(Out, ID << 1);
return;
}
clang::io::Emit32(Out, (ID << 1) | 0x01);
uint32_t Bits = 0;
- bool hasMacroDefinition =
- II->hasMacroDefinition() &&
- !PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro();
+ bool HasMacroDefinition = hasMacroDefinition(II, Macro);
Bits = (uint32_t)II->getObjCOrBuiltinID();
- Bits = (Bits << 1) | unsigned(hasMacroDefinition);
+ Bits = (Bits << 1) | unsigned(HasMacroDefinition);
Bits = (Bits << 1) | unsigned(II->isExtensionToken());
Bits = (Bits << 1) | unsigned(II->isPoisoned());
Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier());
Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword());
clang::io::Emit16(Out, Bits);
- if (hasMacroDefinition)
+ if (HasMacroDefinition)
clang::io::Emit32(Out, Writer.getMacroOffset(II));
// Emit the declaration IDs in reverse order, because the
@@ -2306,9 +2288,9 @@ public:
// adds declarations to the end of the list (so we need to see the
// struct "status" before the function "status").
// Only emit declarations that aren't from a chained PCH, though.
- llvm::SmallVector<Decl *, 16> Decls(IdentifierResolver::begin(II),
+ SmallVector<Decl *, 16> Decls(IdentifierResolver::begin(II),
IdentifierResolver::end());
- for (llvm::SmallVector<Decl *, 16>::reverse_iterator D = Decls.rbegin(),
+ for (SmallVector<Decl *, 16>::reverse_iterator D = Decls.rbegin(),
DEnd = Decls.rend();
D != DEnd; ++D)
clang::io::Emit32(Out, Writer.getDeclID(*D));
@@ -2321,14 +2303,14 @@ public:
/// The identifier table consists of a blob containing string data
/// (the actual identifiers themselves) and a separate "offsets" index
/// that maps identifier IDs to locations within the blob.
-void ASTWriter::WriteIdentifierTable(Preprocessor &PP) {
+void ASTWriter::WriteIdentifierTable(Preprocessor &PP, bool IsModule) {
using namespace llvm;
// Create and write out the blob that contains the identifier
// strings.
{
OnDiskChainedHashTableGenerator<ASTIdentifierTableTrait> Generator;
- ASTIdentifierTableTrait Trait(*this, PP);
+ ASTIdentifierTableTrait Trait(*this, PP, IsModule);
// Look for any identifiers that were named while processing the
// headers, but are otherwise not needed. We add these to the hash
@@ -2348,14 +2330,15 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP) {
ID != IDEnd; ++ID) {
assert(ID->first && "NULL identifier in identifier table");
if (!Chain || !ID->first->isFromAST())
- Generator.insert(ID->first, ID->second, Trait);
+ Generator.insert(const_cast<IdentifierInfo *>(ID->first), ID->second,
+ Trait);
}
// Create the on-disk hash table in a buffer.
llvm::SmallString<4096> IdentifierTable;
uint32_t BucketOffset;
{
- ASTIdentifierTableTrait Trait(*this, PP);
+ ASTIdentifierTableTrait Trait(*this, PP, IsModule);
llvm::raw_svector_ostream Out(IdentifierTable);
// Make sure that no bucket is at offset 0
clang::io::Emit32(Out, 0);
@@ -2380,12 +2363,14 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP) {
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_OFFSET));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of identifiers
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned IdentifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
RecordData Record;
Record.push_back(IDENTIFIER_OFFSET);
Record.push_back(IdentifierOffsets.size());
+ Record.push_back(FirstIdentID - NUM_PREDEF_IDENT_IDS);
Stream.EmitRecordWithBlob(IdentifierOffsetAbbrev, Record,
data(IdentifierOffsets));
}
@@ -2424,7 +2409,6 @@ public:
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
- ID.AddInteger(Writer.GetOrCreateTypeID(Name.getCXXNameType()));
break;
case DeclarationName::CXXOperatorName:
ID.AddInteger(Name.getCXXOverloadedOperator());
@@ -2439,7 +2423,7 @@ public:
}
std::pair<unsigned,unsigned>
- EmitKeyDataLength(llvm::raw_ostream& Out, DeclarationName Name,
+ EmitKeyDataLength(raw_ostream& Out, DeclarationName Name,
data_type_ref Lookup) {
unsigned KeyLen = 1;
switch (Name.getNameKind()) {
@@ -2447,15 +2431,15 @@ public:
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
- case DeclarationName::CXXConstructorName:
- case DeclarationName::CXXDestructorName:
- case DeclarationName::CXXConversionFunctionName:
case DeclarationName::CXXLiteralOperatorName:
KeyLen += 4;
break;
case DeclarationName::CXXOperatorName:
KeyLen += 1;
break;
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
case DeclarationName::CXXUsingDirective:
break;
}
@@ -2468,7 +2452,7 @@ public:
return std::make_pair(KeyLen, DataLen);
}
- void EmitKey(llvm::raw_ostream& Out, DeclarationName Name, unsigned) {
+ void EmitKey(raw_ostream& Out, DeclarationName Name, unsigned) {
using namespace clang::io;
assert(Name.getNameKind() < 0x100 && "Invalid name kind ?");
@@ -2482,11 +2466,6 @@ public:
case DeclarationName::ObjCMultiArgSelector:
Emit32(Out, Writer.getSelectorRef(Name.getObjCSelector()));
break;
- case DeclarationName::CXXConstructorName:
- case DeclarationName::CXXDestructorName:
- case DeclarationName::CXXConversionFunctionName:
- Emit32(Out, Writer.getTypeID(Name.getCXXNameType()));
- break;
case DeclarationName::CXXOperatorName:
assert(Name.getCXXOverloadedOperator() < 0x100 && "Invalid operator ?");
Emit8(Out, Name.getCXXOverloadedOperator());
@@ -2494,12 +2473,15 @@ public:
case DeclarationName::CXXLiteralOperatorName:
Emit32(Out, Writer.getIdentifierRef(Name.getCXXLiteralIdentifier()));
break;
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
case DeclarationName::CXXUsingDirective:
break;
}
}
- void EmitData(llvm::raw_ostream& Out, key_type_ref,
+ 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);
@@ -2534,9 +2516,7 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
return 0;
// Force the DeclContext to build a its name-lookup table.
- if (DC->hasExternalVisibleStorage())
- DC->MaterializeVisibleDeclsFromExternalStorage();
- else
+ if (!DC->hasExternalVisibleStorage())
DC->lookup(DeclarationName());
// Serialize the contents of the mapping used for lookup. Note that,
@@ -2553,13 +2533,37 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
ASTDeclContextNameLookupTrait Trait(*this);
// Create the on-disk hash table representation.
+ DeclarationName ConversionName;
+ llvm::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();
- Generator.insert(Name, Result, Trait);
+ if (Result.first != Result.second) {
+ 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
+ // key (since such type information is not stable across different
+ // modules), so the intended effect is to coalesce all of the conversion
+ // functions under a single key.
+ if (!ConversionName)
+ ConversionName = Name;
+ ConversionDecls.append(Result.first, Result.second);
+ continue;
+ }
+
+ Generator.insert(Name, Result, Trait);
+ }
}
+ // Add the conversion functions
+ if (!ConversionDecls.empty()) {
+ Generator.insert(ConversionName,
+ DeclContext::lookup_result(ConversionDecls.begin(),
+ ConversionDecls.end()),
+ Trait);
+ }
+
// Create the on-disk hash table in a buffer.
llvm::SmallString<4096> LookupTable;
uint32_t BucketOffset;
@@ -2602,7 +2606,8 @@ 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.
- Generator.insert(Name, Result, Trait);
+ if (Result.first != Result.second)
+ Generator.insert(Name, Result, Trait);
}
// Create the on-disk hash table in a buffer.
@@ -2652,14 +2657,14 @@ void ASTWriter::WriteAttributes(const AttrVec &Attrs, RecordDataImpl &Record) {
for (AttrVec::const_iterator i = Attrs.begin(), e = Attrs.end(); i != e; ++i){
const Attr * A = *i;
Record.push_back(A->getKind()); // FIXME: stable encoding, target attrs
- AddSourceLocation(A->getLocation(), Record);
+ AddSourceRange(A->getRange(), Record);
#include "clang/Serialization/AttrPCHWrite.inc"
}
}
-void ASTWriter::AddString(llvm::StringRef Str, RecordDataImpl &Record) {
+void ASTWriter::AddString(StringRef Str, RecordDataImpl &Record) {
Record.push_back(Str.size());
Record.insert(Record.end(), Str.begin(), Str.end());
}
@@ -2700,15 +2705,15 @@ void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) {
}
ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
- : Stream(Stream), Chain(0), SerializationListener(0),
- FirstDeclID(1), NextDeclID(FirstDeclID),
+ : Stream(Stream), Context(0), Chain(0), WritingAST(false),
+ FirstDeclID(NUM_PREDEF_DECL_IDS), NextDeclID(FirstDeclID),
FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID),
- FirstIdentID(1), NextIdentID(FirstIdentID), FirstSelectorID(1),
- NextSelectorID(FirstSelectorID), FirstMacroID(1), NextMacroID(FirstMacroID),
+ FirstIdentID(NUM_PREDEF_IDENT_IDS), NextIdentID(FirstIdentID),
+ FirstSelectorID(NUM_PREDEF_SELECTOR_IDS), NextSelectorID(FirstSelectorID),
CollectedStmts(&StmtsToEmit),
NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0),
NumVisibleDeclContexts(0),
- FirstCXXBaseSpecifiersID(1), NextCXXBaseSpecifiersID(1),
+ NextCXXBaseSpecifiersID(1),
DeclParmVarAbbrev(0), DeclContextLexicalAbbrev(0),
DeclContextVisibleLookupAbbrev(0), UpdateVisibleAbbrev(0),
DeclRefExprAbbrev(0), CharacterLiteralAbbrev(0),
@@ -2721,7 +2726,9 @@ ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
const std::string &OutputFile,
- const char *isysroot) {
+ bool IsModule, StringRef isysroot) {
+ WritingAST = true;
+
// Emit the file header.
Stream.Emit((unsigned)'C', 8);
Stream.Emit((unsigned)'P', 8);
@@ -2730,30 +2737,53 @@ void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
WriteBlockInfoBlock();
- if (Chain)
- WriteASTChain(SemaRef, StatCalls, isysroot);
- else
- WriteASTCore(SemaRef, StatCalls, isysroot, OutputFile);
+ Context = &SemaRef.Context;
+ WriteASTCore(SemaRef, StatCalls, isysroot, OutputFile, IsModule);
+ Context = 0;
+
+ WritingAST = false;
+}
+
+template<typename Vector>
+static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec,
+ ASTWriter::RecordData &Record) {
+ for (typename Vector::iterator I = Vec.begin(0, true), E = Vec.end();
+ I != E; ++I) {
+ Writer.AddDeclRef(*I, Record);
+ }
}
void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
- const char *isysroot,
- const std::string &OutputFile) {
+ StringRef isysroot,
+ const std::string &OutputFile, bool IsModule) {
using namespace llvm;
ASTContext &Context = SemaRef.Context;
Preprocessor &PP = SemaRef.PP;
- // The translation unit is the first declaration we'll emit.
- DeclIDs[Context.getTranslationUnitDecl()] = 1;
- ++NextDeclID;
- DeclTypesToEmit.push(Context.getTranslationUnitDecl());
-
- // Make sure that we emit IdentifierInfos (and any attached
- // declarations) for builtins.
- {
+ // Set up predefined declaration IDs.
+ DeclIDs[Context.getTranslationUnitDecl()] = PREDEF_DECL_TRANSLATION_UNIT_ID;
+ if (Context.ObjCIdDecl)
+ DeclIDs[Context.ObjCIdDecl] = PREDEF_DECL_OBJC_ID_ID;
+ if (Context.ObjCSelDecl)
+ DeclIDs[Context.ObjCSelDecl] = PREDEF_DECL_OBJC_SEL_ID;
+ if (Context.ObjCClassDecl)
+ DeclIDs[Context.ObjCClassDecl] = PREDEF_DECL_OBJC_CLASS_ID;
+ if (Context.Int128Decl)
+ DeclIDs[Context.Int128Decl] = PREDEF_DECL_INT_128_ID;
+ if (Context.UInt128Decl)
+ DeclIDs[Context.UInt128Decl] = PREDEF_DECL_UNSIGNED_INT_128_ID;
+ if (Context.ObjCInstanceTypeDecl)
+ DeclIDs[Context.ObjCInstanceTypeDecl] = PREDEF_DECL_OBJC_INSTANCETYPE_ID;
+
+ if (!Chain) {
+ // Make sure that we emit IdentifierInfos (and any attached
+ // declarations) for builtins. We don't need to do this when we're
+ // emitting chained PCH files, because all of the builtins will be
+ // in the original PCH file.
+ // FIXME: Modules won't like this at all.
IdentifierTable &Table = PP.getIdentifierTable();
- llvm::SmallVector<const char *, 32> BuiltinNames;
+ SmallVector<const char *, 32> BuiltinNames;
Context.BuiltinInfo.GetBuiltinNames(BuiltinNames,
Context.getLangOptions().NoBuiltin);
for (unsigned I = 0, N = BuiltinNames.size(); I != N; ++I)
@@ -2764,24 +2794,24 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
// TentativeDefinitions order. Generally, this record will be empty for
// headers.
RecordData TentativeDefinitions;
- for (unsigned i = 0, e = SemaRef.TentativeDefinitions.size(); i != e; ++i) {
- AddDeclRef(SemaRef.TentativeDefinitions[i], TentativeDefinitions);
- }
-
+ AddLazyVectorDecls(*this, SemaRef.TentativeDefinitions, TentativeDefinitions);
+
// Build a record containing all of the file scoped decls in this file.
RecordData UnusedFileScopedDecls;
- for (unsigned i=0, e = SemaRef.UnusedFileScopedDecls.size(); i !=e; ++i)
- AddDeclRef(SemaRef.UnusedFileScopedDecls[i], UnusedFileScopedDecls);
+ AddLazyVectorDecls(*this, SemaRef.UnusedFileScopedDecls,
+ UnusedFileScopedDecls);
+ // Build a record containing all of the delegating constructors we still need
+ // to resolve.
RecordData DelegatingCtorDecls;
- for (unsigned i=0, e = SemaRef.DelegatingCtorDecls.size(); i != e; ++i)
- AddDeclRef(SemaRef.DelegatingCtorDecls[i], DelegatingCtorDecls);
+ 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
+ // the results at the end of the chain.
RecordData WeakUndeclaredIdentifiers;
if (!SemaRef.WeakUndeclaredIdentifiers.empty()) {
- WeakUndeclaredIdentifiers.push_back(
- SemaRef.WeakUndeclaredIdentifiers.size());
- for (llvm::DenseMap<IdentifierInfo*,Sema::WeakInfo>::iterator
+ for (llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator
I = SemaRef.WeakUndeclaredIdentifiers.begin(),
E = SemaRef.WeakUndeclaredIdentifiers.end(); I != E; ++I) {
AddIdentifierRef(I->first, WeakUndeclaredIdentifiers);
@@ -2800,18 +2830,18 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
for (llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
TD = SemaRef.LocallyScopedExternalDecls.begin(),
TDEnd = SemaRef.LocallyScopedExternalDecls.end();
- TD != TDEnd; ++TD)
- AddDeclRef(TD->second, LocallyScopedExternalDecls);
-
+ TD != TDEnd; ++TD) {
+ if (!TD->second->isFromASTFile())
+ AddDeclRef(TD->second, LocallyScopedExternalDecls);
+ }
+
// Build a record containing all of the ext_vector declarations.
RecordData ExtVectorDecls;
- for (unsigned I = 0, N = SemaRef.ExtVectorDecls.size(); I != N; ++I)
- AddDeclRef(SemaRef.ExtVectorDecls[I], ExtVectorDecls);
+ AddLazyVectorDecls(*this, SemaRef.ExtVectorDecls, ExtVectorDecls);
// Build a record containing all of the VTable uses information.
RecordData VTableUses;
if (!SemaRef.VTableUses.empty()) {
- VTableUses.push_back(SemaRef.VTableUses.size());
for (unsigned I = 0, N = SemaRef.VTableUses.size(); I != N; ++I) {
AddDeclRef(SemaRef.VTableUses[I].first, VTableUses);
AddSourceLocation(SemaRef.VTableUses[I].second, VTableUses);
@@ -2821,8 +2851,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
// Build a record containing all of dynamic classes declarations.
RecordData DynamicClasses;
- for (unsigned I = 0, N = SemaRef.DynamicClasses.size(); I != N; ++I)
- AddDeclRef(SemaRef.DynamicClasses[I], DynamicClasses);
+ AddLazyVectorDecls(*this, SemaRef.DynamicClasses, DynamicClasses);
// Build a record containing all of pending implicit instantiations.
RecordData PendingInstantiations;
@@ -2862,155 +2891,65 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
Stream.EnterSubblock(AST_BLOCK_ID, 5);
WriteMetadata(Context, isysroot, OutputFile);
WriteLanguageOptions(Context.getLangOptions());
- if (StatCalls && !isysroot)
+ if (StatCalls && isysroot.empty())
WriteStatCache(*StatCalls);
WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot);
- // Write the record of special types.
- Record.clear();
-
- AddTypeRef(Context.getBuiltinVaListType(), Record);
- AddTypeRef(Context.getObjCIdType(), Record);
- AddTypeRef(Context.getObjCSelType(), Record);
- AddTypeRef(Context.getObjCProtoType(), Record);
- AddTypeRef(Context.getObjCClassType(), Record);
- AddTypeRef(Context.getRawCFConstantStringType(), Record);
- AddTypeRef(Context.getRawObjCFastEnumerationStateType(), Record);
- AddTypeRef(Context.getFILEType(), Record);
- AddTypeRef(Context.getjmp_bufType(), Record);
- AddTypeRef(Context.getsigjmp_bufType(), Record);
- AddTypeRef(Context.ObjCIdRedefinitionType, Record);
- AddTypeRef(Context.ObjCClassRedefinitionType, Record);
- AddTypeRef(Context.getRawBlockdescriptorType(), Record);
- AddTypeRef(Context.getRawBlockdescriptorExtendedType(), Record);
- AddTypeRef(Context.ObjCSelRedefinitionType, Record);
- AddTypeRef(Context.getRawNSConstantStringType(), Record);
- Record.push_back(Context.isInt128Installed());
- AddTypeRef(Context.AutoDeductTy, Record);
- AddTypeRef(Context.AutoRRefDeductTy, Record);
- Stream.EmitRecord(SPECIAL_TYPES, Record);
-
- // Keep writing types and declarations until all types and
- // declarations have been written.
- Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
- WriteDeclsBlockAbbrevs();
- while (!DeclTypesToEmit.empty()) {
- DeclOrType DOT = DeclTypesToEmit.front();
- DeclTypesToEmit.pop();
- if (DOT.isType())
- WriteType(DOT.getType());
- else
- WriteDecl(Context, DOT.getDecl());
- }
- Stream.ExitBlock();
-
- WritePreprocessor(PP);
- WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot);
- WriteSelectors(SemaRef);
- WriteReferencedSelectorsPool(SemaRef);
- WriteIdentifierTable(PP);
- WriteFPPragmaOptions(SemaRef.getFPOptions());
- WriteOpenCLExtensions(SemaRef);
-
- WriteTypeDeclOffsets();
- WritePragmaDiagnosticMappings(Context.getDiagnostics());
-
- WriteCXXBaseSpecifiersOffsets();
-
- // Write the record containing external, unnamed definitions.
- if (!ExternalDefinitions.empty())
- Stream.EmitRecord(EXTERNAL_DEFINITIONS, ExternalDefinitions);
-
- // Write the record containing tentative definitions.
- if (!TentativeDefinitions.empty())
- Stream.EmitRecord(TENTATIVE_DEFINITIONS, TentativeDefinitions);
-
- // Write the record containing unused file scoped decls.
- if (!UnusedFileScopedDecls.empty())
- Stream.EmitRecord(UNUSED_FILESCOPED_DECLS, UnusedFileScopedDecls);
-
- // Write the record containing weak undeclared identifiers.
- if (!WeakUndeclaredIdentifiers.empty())
- 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 ext_vector type names.
- if (!ExtVectorDecls.empty())
- Stream.EmitRecord(EXT_VECTOR_DECLS, ExtVectorDecls);
-
- // Write the record containing VTable uses information.
- if (!VTableUses.empty())
- Stream.EmitRecord(VTABLE_USES, VTableUses);
-
- // Write the record containing dynamic classes declarations.
- if (!DynamicClasses.empty())
- Stream.EmitRecord(DYNAMIC_CLASSES, DynamicClasses);
-
- // Write the record containing pending implicit instantiations.
- if (!PendingInstantiations.empty())
- Stream.EmitRecord(PENDING_IMPLICIT_INSTANTIATIONS, PendingInstantiations);
-
- // Write the record containing declaration references of Sema.
- if (!SemaDeclRefs.empty())
- Stream.EmitRecord(SEMA_DECL_REFS, SemaDeclRefs);
-
- // Write the record containing CUDA-specific declaration references.
- if (!CUDASpecialDeclRefs.empty())
- Stream.EmitRecord(CUDA_SPECIAL_DECL_REFS, CUDASpecialDeclRefs);
- // Write the delegating constructors.
- if (!DelegatingCtorDecls.empty())
- Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls);
-
- // Write the known namespaces.
- if (!KnownNamespaces.empty())
- Stream.EmitRecord(KNOWN_NAMESPACES, KnownNamespaces);
-
- // Some simple statistics
- Record.clear();
- Record.push_back(NumStatements);
- Record.push_back(NumMacros);
- Record.push_back(NumLexicalDeclContexts);
- Record.push_back(NumVisibleDeclContexts);
- Stream.EmitRecord(STATISTICS, Record);
- Stream.ExitBlock();
-}
-
-void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
- const char *isysroot) {
- using namespace llvm;
-
- ASTContext &Context = SemaRef.Context;
- Preprocessor &PP = SemaRef.PP;
-
- RecordData Record;
- Stream.EnterSubblock(AST_BLOCK_ID, 5);
- WriteMetadata(Context, isysroot, "");
- if (StatCalls && !isysroot)
- WriteStatCache(*StatCalls);
- // FIXME: Source manager block should only write new stuff, which could be
- // done by tracking the largest ID in the chain
- WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot);
-
- // The special types are in the chained PCH.
+ if (Chain) {
+ // Write the mapping information describing our module dependencies and how
+ // each of those modules were mapped into our own offset/ID space, so that
+ // the reader can build the appropriate mapping to its own offset/ID space.
+ // The map consists solely of a blob with the following format:
+ // *(module-name-len:i16 module-name:len*i8
+ // source-location-offset:i32
+ // identifier-id:i32
+ // preprocessed-entity-id:i32
+ // macro-definition-id:i32
+ // selector-id:i32
+ // declaration-id:i32
+ // c++-base-specifiers-id:i32
+ // type-id:i32)
+ //
+ llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(MODULE_OFFSET_MAP));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned ModuleOffsetMapAbbrev = Stream.EmitAbbrev(Abbrev);
+ llvm::SmallString<2048> Buffer;
+ {
+ llvm::raw_svector_ostream Out(Buffer);
+ for (ModuleManager::ModuleConstIterator M = Chain->ModuleMgr.begin(),
+ MEnd = Chain->ModuleMgr.end();
+ M != MEnd; ++M) {
+ StringRef FileName = (*M)->FileName;
+ io::Emit16(Out, FileName.size());
+ Out.write(FileName.data(), FileName.size());
+ io::Emit32(Out, (*M)->SLocEntryBaseOffset);
+ io::Emit32(Out, (*M)->BaseIdentifierID);
+ io::Emit32(Out, (*M)->BasePreprocessedEntityID);
+ io::Emit32(Out, (*M)->BaseSelectorID);
+ io::Emit32(Out, (*M)->BaseDeclID);
+ io::Emit32(Out, (*M)->BaseTypeIndex);
+ }
+ }
+ Record.clear();
+ Record.push_back(MODULE_OFFSET_MAP);
+ Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record,
+ Buffer.data(), Buffer.size());
+ }
- // We don't start with the translation unit, but with its decls that
- // don't come from the chained PCH.
+ // 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();
- llvm::SmallVector<KindDeclIDPair, 64> NewGlobalDecls;
+ SmallVector<KindDeclIDPair, 64> NewGlobalDecls;
for (DeclContext::decl_iterator I = TU->noload_decls_begin(),
E = TU->noload_decls_end();
I != E; ++I) {
- if ((*I)->getPCHLevel() == 0)
+ if (!(*I)->isFromASTFile())
NewGlobalDecls.push_back(std::make_pair((*I)->getKind(), GetDeclRef(*I)));
else if ((*I)->isChangedSinceDeserialization())
(void)GetDeclRef(*I); // Make sure it's written, but don't record it.
}
- // We also need to write a lexical updates block for the TU.
+
llvm::BitCodeAbbrev *Abv = new llvm::BitCodeAbbrev();
Abv->Add(llvm::BitCodeAbbrevOp(TU_UPDATE_LEXICAL));
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
@@ -3019,7 +2958,8 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
Record.push_back(TU_UPDATE_LEXICAL);
Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record,
data(NewGlobalDecls));
- // And a visible updates block for the DeclContexts.
+
+ // And a visible updates block for the translation unit.
Abv = new llvm::BitCodeAbbrev();
Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_VISIBLE));
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6));
@@ -3027,108 +2967,41 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
UpdateVisibleAbbrev = Stream.EmitAbbrev(Abv);
WriteDeclContextVisibleUpdate(TU);
-
- // Build a record containing all of the new tentative definitions in this
- // file, in TentativeDefinitions order.
- RecordData TentativeDefinitions;
- for (unsigned i = 0, e = SemaRef.TentativeDefinitions.size(); i != e; ++i) {
- if (SemaRef.TentativeDefinitions[i]->getPCHLevel() == 0)
- AddDeclRef(SemaRef.TentativeDefinitions[i], TentativeDefinitions);
- }
-
- // Build a record containing all of the file scoped decls in this file.
- RecordData UnusedFileScopedDecls;
- for (unsigned i=0, e = SemaRef.UnusedFileScopedDecls.size(); i !=e; ++i) {
- if (SemaRef.UnusedFileScopedDecls[i]->getPCHLevel() == 0)
- AddDeclRef(SemaRef.UnusedFileScopedDecls[i], UnusedFileScopedDecls);
- }
-
- // Build a record containing all of the delegating constructor decls in this
- // file.
- RecordData DelegatingCtorDecls;
- for (unsigned i=0, e = SemaRef.DelegatingCtorDecls.size(); i != e; ++i) {
- if (SemaRef.DelegatingCtorDecls[i]->getPCHLevel() == 0)
- AddDeclRef(SemaRef.DelegatingCtorDecls[i], DelegatingCtorDecls);
- }
-
- // We write the entire table, overwriting the tables from the chain.
- RecordData WeakUndeclaredIdentifiers;
- if (!SemaRef.WeakUndeclaredIdentifiers.empty()) {
- WeakUndeclaredIdentifiers.push_back(
- SemaRef.WeakUndeclaredIdentifiers.size());
- for (llvm::DenseMap<IdentifierInfo*,Sema::WeakInfo>::iterator
- I = SemaRef.WeakUndeclaredIdentifiers.begin(),
- E = SemaRef.WeakUndeclaredIdentifiers.end(); I != E; ++I) {
- AddIdentifierRef(I->first, WeakUndeclaredIdentifiers);
- AddIdentifierRef(I->second.getAlias(), WeakUndeclaredIdentifiers);
- AddSourceLocation(I->second.getLocation(), WeakUndeclaredIdentifiers);
- WeakUndeclaredIdentifiers.push_back(I->second.getUsed());
- }
- }
-
- // Build a record containing all of the locally-scoped external
- // declarations in this header file. Generally, this record will be
- // empty.
- RecordData LocallyScopedExternalDecls;
- // 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 != TDEnd; ++TD) {
- if (TD->second->getPCHLevel() == 0)
- AddDeclRef(TD->second, LocallyScopedExternalDecls);
- }
-
- // Build a record containing all of the ext_vector declarations.
- RecordData ExtVectorDecls;
- for (unsigned I = 0, N = SemaRef.ExtVectorDecls.size(); I != N; ++I) {
- if (SemaRef.ExtVectorDecls[I]->getPCHLevel() == 0)
- AddDeclRef(SemaRef.ExtVectorDecls[I], ExtVectorDecls);
- }
-
- // Build a record containing all of the VTable uses information.
- // We write everything here, because it's too hard to determine whether
- // a use is new to this part.
- RecordData VTableUses;
- if (!SemaRef.VTableUses.empty()) {
- VTableUses.push_back(SemaRef.VTableUses.size());
- for (unsigned I = 0, N = SemaRef.VTableUses.size(); I != N; ++I) {
- AddDeclRef(SemaRef.VTableUses[I].first, VTableUses);
- AddSourceLocation(SemaRef.VTableUses[I].second, VTableUses);
- VTableUses.push_back(SemaRef.VTablesUsed[SemaRef.VTableUses[I].first]);
+
+ // If the translation unit has an anonymous namespace, and we don't already
+ // have an update block for it, write it as an update block.
+ if (NamespaceDecl *NS = TU->getAnonymousNamespace()) {
+ ASTWriter::UpdateRecord &Record = DeclUpdates[TU];
+ if (Record.empty()) {
+ Record.push_back(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE);
+ Record.push_back(reinterpret_cast<uint64_t>(NS));
}
}
-
- // Build a record containing all of dynamic classes declarations.
- RecordData DynamicClasses;
- for (unsigned I = 0, N = SemaRef.DynamicClasses.size(); I != N; ++I)
- if (SemaRef.DynamicClasses[I]->getPCHLevel() == 0)
- AddDeclRef(SemaRef.DynamicClasses[I], DynamicClasses);
-
- // Build a record containing all of pending implicit instantiations.
- RecordData PendingInstantiations;
- for (std::deque<Sema::PendingImplicitInstantiation>::iterator
- I = SemaRef.PendingInstantiations.begin(),
- N = SemaRef.PendingInstantiations.end(); I != N; ++I) {
- AddDeclRef(I->first, PendingInstantiations);
- AddSourceLocation(I->second, PendingInstantiations);
- }
- assert(SemaRef.PendingLocalImplicitInstantiations.empty() &&
- "There are local ones at end of translation unit!");
-
- // Build a record containing some declaration references.
- // It's not worth the effort to avoid duplication here.
- RecordData SemaDeclRefs;
- if (SemaRef.StdNamespace || SemaRef.StdBadAlloc) {
- AddDeclRef(SemaRef.getStdNamespace(), SemaDeclRefs);
- AddDeclRef(SemaRef.getStdBadAlloc(), SemaDeclRefs);
- }
-
+
+ // Resolve any declaration pointers within the declaration updates block and
+ // chained Objective-C categories block to declaration IDs.
+ ResolveDeclUpdatesBlocks();
+ ResolveChainedObjCCategories();
+
+ // Form the record of special types.
+ RecordData SpecialTypes;
+ AddTypeRef(Context.getBuiltinVaListType(), SpecialTypes);
+ AddTypeRef(Context.ObjCProtoType, SpecialTypes);
+ AddTypeRef(Context.getRawCFConstantStringType(), SpecialTypes);
+ AddTypeRef(Context.getFILEType(), SpecialTypes);
+ AddTypeRef(Context.getjmp_bufType(), SpecialTypes);
+ AddTypeRef(Context.getsigjmp_bufType(), SpecialTypes);
+ AddTypeRef(Context.ObjCIdRedefinitionType, SpecialTypes);
+ AddTypeRef(Context.ObjCClassRedefinitionType, SpecialTypes);
+ AddTypeRef(Context.ObjCSelRedefinitionType, SpecialTypes);
+
+ // Keep writing types and declarations until all types and
+ // declarations have been written.
Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
WriteDeclsBlockAbbrevs();
- for (DeclsToRewriteTy::iterator
- I = DeclsToRewrite.begin(), E = DeclsToRewrite.end(); I != E; ++I)
+ for (DeclsToRewriteTy::iterator I = DeclsToRewrite.begin(),
+ E = DeclsToRewrite.end();
+ I != E; ++I)
DeclTypesToEmit.push(const_cast<Decl*>(*I));
while (!DeclTypesToEmit.empty()) {
DeclOrType DOT = DeclTypesToEmit.front();
@@ -3140,30 +3013,31 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
}
Stream.ExitBlock();
- WritePreprocessor(PP);
+ WritePreprocessor(PP, IsModule);
+ WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot);
WriteSelectors(SemaRef);
WriteReferencedSelectorsPool(SemaRef);
- WriteIdentifierTable(PP);
+ WriteIdentifierTable(PP, IsModule);
WriteFPPragmaOptions(SemaRef.getFPOptions());
WriteOpenCLExtensions(SemaRef);
WriteTypeDeclOffsets();
- // FIXME: For chained PCH only write the new mappings (we currently
- // write all of them again).
WritePragmaDiagnosticMappings(Context.getDiagnostics());
WriteCXXBaseSpecifiersOffsets();
+
+ Stream.EmitRecord(SPECIAL_TYPES, SpecialTypes);
/// Build a record containing first declarations from a chained PCH and the
/// most recent declarations in this AST that they point to.
RecordData FirstLatestDeclIDs;
- for (FirstLatestDeclMap::iterator
- I = FirstLatestDecls.begin(), E = FirstLatestDecls.end(); I != E; ++I) {
- assert(I->first->getPCHLevel() > I->second->getPCHLevel() &&
- "Expected first & second to be in different PCHs");
+ for (FirstLatestDeclMap::iterator I = FirstLatestDecls.begin(),
+ E = FirstLatestDecls.end();
+ I != E; ++I) {
AddDeclRef(I->first, FirstLatestDeclIDs);
AddDeclRef(I->second, FirstLatestDeclIDs);
}
+
if (!FirstLatestDeclIDs.empty())
Stream.EmitRecord(REDECLS_UPDATE_LATEST, FirstLatestDeclIDs);
@@ -3208,30 +3082,70 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
// Write the record containing declaration references of Sema.
if (!SemaDeclRefs.empty())
Stream.EmitRecord(SEMA_DECL_REFS, SemaDeclRefs);
+
+ // Write the record containing CUDA-specific declaration references.
+ if (!CUDASpecialDeclRefs.empty())
+ Stream.EmitRecord(CUDA_SPECIAL_DECL_REFS, CUDASpecialDeclRefs);
// Write the delegating constructors.
if (!DelegatingCtorDecls.empty())
Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls);
- // Write the updates to DeclContexts.
+ // Write the known namespaces.
+ if (!KnownNamespaces.empty())
+ Stream.EmitRecord(KNOWN_NAMESPACES, KnownNamespaces);
+
+ // Write the visible updates to DeclContexts.
for (llvm::SmallPtrSet<const DeclContext *, 16>::iterator
- I = UpdatedDeclContexts.begin(),
- E = UpdatedDeclContexts.end();
- I != E; ++I)
+ I = UpdatedDeclContexts.begin(),
+ E = UpdatedDeclContexts.end();
+ I != E; ++I)
WriteDeclContextVisibleUpdate(*I);
WriteDeclUpdatesBlocks();
+ WriteDeclReplacementsBlock();
+ WriteChainedObjCCategories();
+ // Some simple statistics
Record.clear();
Record.push_back(NumStatements);
Record.push_back(NumMacros);
Record.push_back(NumLexicalDeclContexts);
Record.push_back(NumVisibleDeclContexts);
- WriteDeclReplacementsBlock();
Stream.EmitRecord(STATISTICS, Record);
Stream.ExitBlock();
}
+/// \brief Go through the declaration update blocks and resolve declaration
+/// pointers into declaration IDs.
+void ASTWriter::ResolveDeclUpdatesBlocks() {
+ for (DeclUpdateMap::iterator
+ I = DeclUpdates.begin(), E = DeclUpdates.end(); I != E; ++I) {
+ const Decl *D = I->first;
+ UpdateRecord &URec = I->second;
+
+ if (DeclsToRewrite.count(D))
+ continue; // The decl will be written completely
+
+ unsigned Idx = 0, N = URec.size();
+ while (Idx < N) {
+ switch ((DeclUpdateKind)URec[Idx++]) {
+ case UPD_CXX_SET_DEFINITIONDATA:
+ case UPD_CXX_ADDED_IMPLICIT_MEMBER:
+ case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
+ case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE:
+ URec[Idx] = GetDeclRef(reinterpret_cast<Decl *>(URec[Idx]));
+ ++Idx;
+ break;
+
+ case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER:
+ ++Idx;
+ break;
+ }
+ }
+ }
+}
+
void ASTWriter::WriteDeclUpdatesBlocks() {
if (DeclUpdates.empty())
return;
@@ -3261,7 +3175,7 @@ void ASTWriter::WriteDeclReplacementsBlock() {
return;
RecordData Record;
- for (llvm::SmallVector<std::pair<DeclID, uint64_t>, 16>::iterator
+ for (SmallVector<std::pair<DeclID, uint64_t>, 16>::iterator
I = ReplacedDecls.begin(), E = ReplacedDecls.end(); I != E; ++I) {
Record.push_back(I->first);
Record.push_back(I->second);
@@ -3269,6 +3183,37 @@ void ASTWriter::WriteDeclReplacementsBlock() {
Stream.EmitRecord(DECL_REPLACEMENTS, Record);
}
+void ASTWriter::ResolveChainedObjCCategories() {
+ for (SmallVector<ChainedObjCCategoriesData, 16>::iterator
+ I = LocalChainedObjCCategories.begin(),
+ E = LocalChainedObjCCategories.end(); I != E; ++I) {
+ ChainedObjCCategoriesData &Data = *I;
+ Data.InterfaceID = GetDeclRef(Data.Interface);
+ Data.TailCategoryID = GetDeclRef(Data.TailCategory);
+ }
+
+}
+
+void ASTWriter::WriteChainedObjCCategories() {
+ if (LocalChainedObjCCategories.empty())
+ return;
+
+ RecordData Record;
+ for (SmallVector<ChainedObjCCategoriesData, 16>::iterator
+ I = LocalChainedObjCCategories.begin(),
+ E = LocalChainedObjCCategories.end(); I != E; ++I) {
+ ChainedObjCCategoriesData &Data = *I;
+ serialization::DeclID
+ HeadCatID = getDeclID(Data.Interface->getCategoryList());
+ assert(HeadCatID != 0 && "Category not written ?");
+
+ Record.push_back(Data.InterfaceID);
+ Record.push_back(HeadCatID);
+ Record.push_back(Data.TailCategoryID);
+ }
+ Stream.EmitRecord(OBJC_CHAINED_CATEGORIES, Record);
+}
+
void ASTWriter::AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record) {
Record.push_back(Loc.getRawEncoding());
}
@@ -3307,16 +3252,6 @@ IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) {
return ID;
}
-MacroID ASTWriter::getMacroDefinitionID(MacroDefinition *MD) {
- if (MD == 0)
- return 0;
-
- MacroID &ID = MacroDefinitions[MD];
- if (ID == 0)
- ID = NextMacroID++;
- return ID;
-}
-
void ASTWriter::AddSelectorRef(const Selector SelRef, RecordDataImpl &Record) {
Record.push_back(getSelectorRef(SelRef));
}
@@ -3416,13 +3351,13 @@ void ASTWriter::AddTypeRef(QualType T, RecordDataImpl &Record) {
Record.push_back(GetOrCreateTypeID(T));
}
-TypeID ASTWriter::GetOrCreateTypeID(QualType T) {
- return MakeTypeID(T,
+TypeID ASTWriter::GetOrCreateTypeID( QualType T) {
+ return MakeTypeID(*Context, T,
std::bind1st(std::mem_fun(&ASTWriter::GetOrCreateTypeIdx), this));
}
TypeID ASTWriter::getTypeID(QualType T) const {
- return MakeTypeID(T,
+ return MakeTypeID(*Context, T,
std::bind1st(std::mem_fun(&ASTWriter::getTypeIdx), this));
}
@@ -3456,6 +3391,8 @@ void ASTWriter::AddDeclRef(const Decl *D, RecordDataImpl &Record) {
}
DeclID ASTWriter::GetDeclRef(const Decl *D) {
+ assert(WritingAST && "Cannot request a declaration ID before AST writing");
+
if (D == 0) {
return 0;
}
@@ -3571,7 +3508,7 @@ void ASTWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS,
RecordDataImpl &Record) {
// Nested name specifiers usually aren't too long. I think that 8 would
// typically accommodate the vast majority.
- llvm::SmallVector<NestedNameSpecifier *, 8> NestedNames;
+ SmallVector<NestedNameSpecifier *, 8> NestedNames;
// Push each of the NNS's onto a stack for serialization in reverse order.
while (NNS) {
@@ -3614,7 +3551,7 @@ void ASTWriter::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
RecordDataImpl &Record) {
// Nested name specifiers usually aren't too long. I think that 8 would
// typically accommodate the vast majority.
- llvm::SmallVector<NestedNameSpecifierLoc , 8> NestedNames;
+ SmallVector<NestedNameSpecifierLoc , 8> NestedNames;
// Push each of the nested-name-specifiers's onto a stack for
// serialization in reverse order.
@@ -3805,7 +3742,7 @@ void ASTWriter::FlushCXXBaseSpecifiers() {
Record.clear();
// Record the offset of this base-specifier set.
- unsigned Index = CXXBaseSpecifiersToWrite[I].ID - FirstCXXBaseSpecifiersID;
+ unsigned Index = CXXBaseSpecifiersToWrite[I].ID - 1;
if (Index == CXXBaseSpecifiersOffsets.size())
CXXBaseSpecifiersOffsets.push_back(Stream.GetCurrentBitNo());
else {
@@ -3871,7 +3808,9 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
struct CXXRecordDecl::DefinitionData &Data = *D->DefinitionData;
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.Aggregate);
Record.push_back(Data.PlainOldData);
@@ -3885,7 +3824,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Data.HasPublicFields);
Record.push_back(Data.HasMutableFields);
Record.push_back(Data.HasTrivialDefaultConstructor);
- Record.push_back(Data.HasConstExprNonCopyMoveConstructor);
+ Record.push_back(Data.HasConstexprNonCopyMoveConstructor);
Record.push_back(Data.HasTrivialCopyConstructor);
Record.push_back(Data.HasTrivialMoveConstructor);
Record.push_back(Data.HasTrivialCopyAssignment);
@@ -3896,8 +3835,12 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
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.FailedImplicitMoveConstructor);
+ Record.push_back(Data.FailedImplicitMoveAssignment);
Record.push_back(Data.NumBases);
if (Data.NumBases > 0)
@@ -3918,28 +3861,23 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
void ASTWriter::ReaderInitialized(ASTReader *Reader) {
assert(Reader && "Cannot remove chain");
- assert(!Chain && "Cannot replace chain");
+ assert((!Chain || Chain == Reader) && "Cannot replace chain");
assert(FirstDeclID == NextDeclID &&
FirstTypeID == NextTypeID &&
FirstIdentID == NextIdentID &&
FirstSelectorID == NextSelectorID &&
- FirstMacroID == NextMacroID &&
- FirstCXXBaseSpecifiersID == NextCXXBaseSpecifiersID &&
"Setting chain after writing has started.");
+
Chain = Reader;
- FirstDeclID += Chain->getTotalNumDecls();
- FirstTypeID += Chain->getTotalNumTypes();
- FirstIdentID += Chain->getTotalNumIdentifiers();
- FirstSelectorID += Chain->getTotalNumSelectors();
- FirstMacroID += Chain->getTotalNumMacroDefinitions();
- FirstCXXBaseSpecifiersID += Chain->getTotalNumCXXBaseSpecifiers();
+ FirstDeclID = NUM_PREDEF_DECL_IDS + Chain->getTotalNumDecls();
+ FirstTypeID = NUM_PREDEF_TYPE_IDS + Chain->getTotalNumTypes();
+ FirstIdentID = NUM_PREDEF_IDENT_IDS + Chain->getTotalNumIdentifiers();
+ FirstSelectorID = NUM_PREDEF_SELECTOR_IDS + Chain->getTotalNumSelectors();
NextDeclID = FirstDeclID;
NextTypeID = FirstTypeID;
NextIdentID = FirstIdentID;
NextSelectorID = FirstSelectorID;
- NextMacroID = FirstMacroID;
- NextCXXBaseSpecifiersID = FirstCXXBaseSpecifiersID;
}
void ASTWriter::IdentifierRead(IdentID ID, IdentifierInfo *II) {
@@ -3967,16 +3905,18 @@ void ASTWriter::SelectorRead(SelectorID ID, Selector S) {
SelectorIDs[S] = ID;
}
-void ASTWriter::MacroDefinitionRead(serialization::MacroID ID,
+void ASTWriter::MacroDefinitionRead(serialization::PreprocessedEntityID ID,
MacroDefinition *MD) {
+ assert(MacroDefinitions.find(MD) == MacroDefinitions.end());
MacroDefinitions[MD] = ID;
}
void ASTWriter::CompletedTagDefinition(const TagDecl *D) {
- assert(D->isDefinition());
+ assert(D->isCompleteDefinition());
+ assert(!WritingAST && "Already writing the AST!");
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
// We are interested when a PCH decl is modified.
- if (RD->getPCHLevel() > 0) {
+ if (RD->isFromASTFile()) {
// A forward reference was mutated into a definition. Rewrite it.
// FIXME: This happens during template instantiation, should we
// have created a new definition decl instead ?
@@ -3990,67 +3930,73 @@ void ASTWriter::CompletedTagDefinition(const TagDecl *D) {
continue;
// We are interested when a PCH decl is modified.
- if (Redecl->getPCHLevel() > 0) {
+ if (Redecl->isFromASTFile()) {
UpdateRecord &Record = DeclUpdates[Redecl];
Record.push_back(UPD_CXX_SET_DEFINITIONDATA);
assert(Redecl->DefinitionData);
assert(Redecl->DefinitionData->Definition == D);
- AddDeclRef(D, Record); // the DefinitionDecl
+ Record.push_back(reinterpret_cast<uint64_t>(D)); // the DefinitionDecl
}
}
}
}
void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) {
+ assert(!WritingAST && "Already writing the AST!");
+
// TU and namespaces are handled elsewhere.
if (isa<TranslationUnitDecl>(DC) || isa<NamespaceDecl>(DC))
return;
- if (!(D->getPCHLevel() == 0 && cast<Decl>(DC)->getPCHLevel() > 0))
+ if (!(!D->isFromASTFile() && cast<Decl>(DC)->isFromASTFile()))
return; // Not a source decl added to a DeclContext from PCH.
AddUpdatedDeclContext(DC);
}
void ASTWriter::AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) {
+ assert(!WritingAST && "Already writing the AST!");
assert(D->isImplicit());
- if (!(D->getPCHLevel() == 0 && RD->getPCHLevel() > 0))
+ if (!(!D->isFromASTFile() && RD->isFromASTFile()))
return; // Not a source member added to a class from PCH.
if (!isa<CXXMethodDecl>(D))
return; // We are interested in lazily declared implicit methods.
// A decl coming from PCH was modified.
- assert(RD->isDefinition());
+ assert(RD->isCompleteDefinition());
UpdateRecord &Record = DeclUpdates[RD];
Record.push_back(UPD_CXX_ADDED_IMPLICIT_MEMBER);
- AddDeclRef(D, Record);
+ Record.push_back(reinterpret_cast<uint64_t>(D));
}
void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
const ClassTemplateSpecializationDecl *D) {
// The specializations set is kept in the canonical template.
+ assert(!WritingAST && "Already writing the AST!");
TD = TD->getCanonicalDecl();
- if (!(D->getPCHLevel() == 0 && TD->getPCHLevel() > 0))
+ if (!(!D->isFromASTFile() && TD->isFromASTFile()))
return; // Not a source specialization added to a template from PCH.
UpdateRecord &Record = DeclUpdates[TD];
Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION);
- AddDeclRef(D, Record);
+ Record.push_back(reinterpret_cast<uint64_t>(D));
}
void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
const FunctionDecl *D) {
// The specializations set is kept in the canonical template.
+ assert(!WritingAST && "Already writing the AST!");
TD = TD->getCanonicalDecl();
- if (!(D->getPCHLevel() == 0 && TD->getPCHLevel() > 0))
+ if (!(!D->isFromASTFile() && TD->isFromASTFile()))
return; // Not a source specialization added to a template from PCH.
UpdateRecord &Record = DeclUpdates[TD];
Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION);
- AddDeclRef(D, Record);
+ Record.push_back(reinterpret_cast<uint64_t>(D));
}
void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) {
- if (D->getPCHLevel() == 0)
+ assert(!WritingAST && "Already writing the AST!");
+ if (!D->isFromASTFile())
return; // Declaration not imported from PCH.
// Implicit decl from a PCH was defined.
@@ -4059,7 +4005,8 @@ void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) {
}
void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) {
- if (D->getPCHLevel() == 0)
+ assert(!WritingAST && "Already writing the AST!");
+ if (!D->isFromASTFile())
return;
// Since the actual instantiation is delayed, this really means that we need
@@ -4070,4 +4017,16 @@ void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) {
D->getMemberSpecializationInfo()->getPointOfInstantiation(), Record);
}
-ASTSerializationListener::~ASTSerializationListener() { }
+void ASTWriter::AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
+ const ObjCInterfaceDecl *IFD) {
+ assert(!WritingAST && "Already writing the AST!");
+ if (!IFD->isFromASTFile())
+ return; // Declaration not imported from PCH.
+ if (CatD->getNextClassCategory() &&
+ !CatD->getNextClassCategory()->isFromASTFile())
+ return; // We already recorded that the tail of a category chain should be
+ // attached to an interface.
+
+ ChainedObjCCategoriesData Data = { IFD, CatD, 0, 0 };
+ LocalChainedObjCCategories.push_back(Data);
+}
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 2b8349495751..a8243e502e30 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -65,6 +65,8 @@ namespace clang {
ClassTemplateSpecializationDecl *D);
void VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D);
+ void VisitClassScopeFunctionSpecializationDecl(
+ ClassScopeFunctionSpecializationDecl *D);
void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
void VisitValueDecl(ValueDecl *D);
void VisitEnumConstantDecl(EnumConstantDecl *D);
@@ -153,13 +155,11 @@ void ASTDeclWriter::VisitDecl(Decl *D) {
Record.push_back(D->isUsed(false));
Record.push_back(D->isReferenced());
Record.push_back(D->getAccess());
- Record.push_back(D->getPCHLevel());
+ Record.push_back(D->ModulePrivate);
}
void ASTDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
- VisitDecl(D);
- Writer.AddDeclRef(D->getAnonymousNamespace(), Record);
- Code = serialization::DECL_TRANSLATION_UNIT;
+ llvm_unreachable("Translation units aren't directly serialized");
}
void ASTDeclWriter::VisitNamedDecl(NamedDecl *D) {
@@ -180,11 +180,11 @@ void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
if (!D->hasAttrs() &&
!D->isImplicit() &&
!D->isUsed(false) &&
- D->getPCHLevel() == 0 &&
D->RedeclLink.getNext() == D &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
D->getAccess() == AS_none &&
+ !D->isModulePrivate() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier)
AbbrevToUse = Writer.getDeclTypedefAbbrev();
@@ -202,8 +202,9 @@ void ASTDeclWriter::VisitTagDecl(TagDecl *D) {
VisitRedeclarable(D);
Record.push_back(D->getIdentifierNamespace());
Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding
- Record.push_back(D->isDefinition());
+ Record.push_back(D->isCompleteDefinition());
Record.push_back(D->isEmbeddedInDeclarator());
+ Record.push_back(D->isFreeStanding());
Writer.AddSourceLocation(D->getRBraceLoc(), Record);
Record.push_back(D->hasExtInfo());
if (D->hasExtInfo())
@@ -228,12 +229,12 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
if (!D->hasAttrs() &&
!D->isImplicit() &&
!D->isUsed(false) &&
- D->getPCHLevel() == 0 &&
!D->hasExtInfo() &&
D->RedeclLink.getNext() == D &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
D->getAccess() == AS_none &&
+ !D->isModulePrivate() &&
!CXXRecordDecl::classofKind(D->getKind()) &&
!D->getIntegerTypeSourceInfo() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier)
@@ -251,12 +252,12 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
if (!D->hasAttrs() &&
!D->isImplicit() &&
!D->isUsed(false) &&
- D->getPCHLevel() == 0 &&
!D->hasExtInfo() &&
D->RedeclLink.getNext() == D &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
D->getAccess() == AS_none &&
+ !D->isModulePrivate() &&
!CXXRecordDecl::classofKind(D->getKind()) &&
D->getDeclName().getNameKind() == DeclarationName::Identifier)
AbbrevToUse = Writer.getDeclRecordAbbrev();
@@ -295,8 +296,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Record.push_back(D->getIdentifierNamespace());
Record.push_back(D->getTemplatedKind());
switch (D->getTemplatedKind()) {
- default: assert(false && "Unhandled TemplatedKind!");
- break;
+ default: llvm_unreachable("Unhandled TemplatedKind!");
case FunctionDecl::TK_NonTemplate:
break;
case FunctionDecl::TK_FunctionTemplate:
@@ -321,13 +321,14 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
// Template args as written.
Record.push_back(FTSInfo->TemplateArgumentsAsWritten != 0);
if (FTSInfo->TemplateArgumentsAsWritten) {
- Record.push_back(FTSInfo->TemplateArgumentsAsWritten->size());
- for (int i=0, e = FTSInfo->TemplateArgumentsAsWritten->size(); i!=e; ++i)
+ Record.push_back(FTSInfo->TemplateArgumentsAsWritten->NumTemplateArgs);
+ for (int i=0, e = FTSInfo->TemplateArgumentsAsWritten->NumTemplateArgs;
+ i!=e; ++i)
Writer.AddTemplateArgumentLoc((*FTSInfo->TemplateArgumentsAsWritten)[i],
Record);
- Writer.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->getLAngleLoc(),
+ Writer.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->LAngleLoc,
Record);
- Writer.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->getRAngleLoc(),
+ Writer.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->RAngleLoc,
Record);
}
@@ -375,6 +376,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Record.push_back(D->isDefaulted());
Record.push_back(D->isExplicitlyDefaulted());
Record.push_back(D->hasImplicitReturnZero());
+ Record.push_back(D->isConstexpr());
Writer.AddSourceLocation(D->getLocEnd(), Record);
Record.push_back(D->param_size());
@@ -400,12 +402,19 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
Record.push_back(D->isVariadic());
Record.push_back(D->isSynthesized());
Record.push_back(D->isDefined());
+
+ Record.push_back(D->IsRedeclaration);
+ Record.push_back(D->HasRedeclaration);
+ if (D->HasRedeclaration) {
+ assert(Context.getObjCMethodRedeclaration(D));
+ Writer.AddDeclRef(Context.getObjCMethodRedeclaration(D), Record);
+ }
+
// FIXME: stable encoding for @required/@optional
Record.push_back(D->getImplementationControl());
// FIXME: stable encoding for in/out/inout/bycopy/byref/oneway
Record.push_back(D->getObjCDeclQualifier());
Record.push_back(D->hasRelatedResultType());
- Record.push_back(D->getNumSelectorArgs());
Writer.AddTypeRef(D->getResultType(), Record);
Writer.AddTypeSourceInfo(D->getResultTypeSourceInfo(), Record);
Writer.AddSourceLocation(D->getLocEnd(), Record);
@@ -413,11 +422,20 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
for (ObjCMethodDecl::param_iterator P = D->param_begin(),
PEnd = D->param_end(); P != PEnd; ++P)
Writer.AddDeclRef(*P, Record);
+
+ Record.push_back(D->SelLocsKind);
+ unsigned NumStoredSelLocs = D->getNumStoredSelLocs();
+ SourceLocation *SelLocs = D->getStoredSelLocs();
+ Record.push_back(NumStoredSelLocs);
+ for (unsigned i = 0; i != NumStoredSelLocs; ++i)
+ Writer.AddSourceLocation(SelLocs[i], Record);
+
Code = serialization::DECL_OBJC_METHOD;
}
void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
VisitNamedDecl(D);
+ Writer.AddSourceLocation(D->getAtStartLoc(), Record);
Writer.AddSourceRange(D->getAtEndRange(), Record);
// Abstract class (no need to define a stable serialization::DECL code).
}
@@ -454,7 +472,6 @@ void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
Writer.AddDeclRef(D->getCategoryList(), Record);
Record.push_back(D->isForwardDecl());
Record.push_back(D->isImplicitInterfaceDecl());
- Writer.AddSourceLocation(D->getClassLoc(), Record);
Writer.AddSourceLocation(D->getSuperClassLoc(), Record);
Writer.AddSourceLocation(D->getLocEnd(), Record);
Code = serialization::DECL_OBJC_INTERFACE;
@@ -471,7 +488,7 @@ void ASTDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
!D->isUsed(false) &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
- D->getPCHLevel() == 0 &&
+ !D->isModulePrivate() &&
!D->getBitWidth() &&
!D->hasExtInfo() &&
D->getDeclName())
@@ -502,11 +519,8 @@ void ASTDeclWriter::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) {
void ASTDeclWriter::VisitObjCClassDecl(ObjCClassDecl *D) {
VisitDecl(D);
- Record.push_back(D->size());
- for (ObjCClassDecl::iterator I = D->begin(), IEnd = D->end(); I != IEnd; ++I)
- Writer.AddDeclRef(I->getInterface(), Record);
- for (ObjCClassDecl::iterator I = D->begin(), IEnd = D->end(); I != IEnd; ++I)
- Writer.AddSourceLocation(I->getLocation(), Record);
+ Writer.AddDeclRef(D->getForwardInterfaceDecl(), Record);
+ Writer.AddSourceLocation(D->getForwardDecl()->getLocation(), Record);
Code = serialization::DECL_OBJC_CLASS;
}
@@ -536,7 +550,6 @@ void ASTDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
Writer.AddSourceLocation(*PL, Record);
Writer.AddDeclRef(D->getNextClassCategory(), Record);
Record.push_back(D->hasSynthBitfield());
- Writer.AddSourceLocation(D->getAtLoc(), Record);
Writer.AddSourceLocation(D->getCategoryNameLoc(), Record);
Code = serialization::DECL_OBJC_CATEGORY;
}
@@ -612,7 +625,7 @@ void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) {
!D->isUsed(false) &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
- D->getPCHLevel() == 0 &&
+ !D->isModulePrivate() &&
!D->getBitWidth() &&
!D->hasInClassInitializer() &&
!D->hasExtInfo() &&
@@ -665,7 +678,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
!D->isInvalidDecl() &&
!D->isReferenced() &&
D->getAccess() == AS_none &&
- D->getPCHLevel() == 0 &&
+ !D->isModulePrivate() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
!D->hasExtInfo() &&
D->RedeclLink.getNext() == D &&
@@ -706,7 +719,7 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
!D->isImplicit() &&
!D->isUsed(false) &&
D->getAccess() == AS_none &&
- D->getPCHLevel() == 0 &&
+ !D->isModulePrivate() &&
D->getStorageClass() == 0 &&
!D->hasCXXDirectInitializer() && // Can params have this ever?
D->getFunctionScopeDepth() == 0 &&
@@ -793,7 +806,7 @@ void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
Code = serialization::DECL_NAMESPACE;
if (Writer.hasChain() && !D->isOriginalNamespace() &&
- D->getOriginalNamespace()->getPCHLevel() > 0) {
+ D->getOriginalNamespace()->isFromASTFile()) {
NamespaceDecl *NS = D->getOriginalNamespace();
Writer.AddUpdatedDeclContext(NS);
@@ -819,7 +832,7 @@ void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
// anonymous namespace.
Decl *Parent = cast<Decl>(
D->getParent()->getRedeclContext()->getPrimaryContext());
- if (Parent->getPCHLevel() > 0) {
+ if (Parent->isFromASTFile() || isa<TranslationUnitDecl>(Parent)) {
ASTWriter::UpdateRecord &Record = Writer.DeclUpdates[Parent];
Record.push_back(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE);
Writer.AddDeclRef(D, Record);
@@ -909,7 +922,7 @@ void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
// Store the key function to avoid deserializing every method so we can
// compute it.
- if (D->IsDefinition)
+ if (D->IsCompleteDefinition)
Writer.AddDeclRef(Context.getKeyFunction(D), Record);
Code = serialization::DECL_CXX_RECORD;
@@ -1015,7 +1028,7 @@ void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
// in a chained PCH, keep track of the association with the map so we can
// update the first decl during AST reading.
if (First->getMostRecentDeclaration() == D &&
- First->getPCHLevel() > D->getPCHLevel()) {
+ First->isFromASTFile() && !D->isFromASTFile()) {
assert(Writer.FirstLatestDecls.find(First)==Writer.FirstLatestDecls.end()
&& "The latest is already set");
Writer.FirstLatestDecls[First] = D;
@@ -1058,16 +1071,12 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
llvm::PointerUnion<ClassTemplateDecl *,
ClassTemplatePartialSpecializationDecl *> InstFrom
= D->getSpecializedTemplateOrPartial();
- Decl *InstFromD;
- if (InstFrom.is<ClassTemplateDecl *>()) {
- InstFromD = InstFrom.get<ClassTemplateDecl *>();
+ if (Decl *InstFromD = InstFrom.dyn_cast<ClassTemplateDecl *>()) {
Writer.AddDeclRef(InstFromD, Record);
} else {
- InstFromD = InstFrom.get<ClassTemplatePartialSpecializationDecl *>();
- Writer.AddDeclRef(InstFromD, Record);
+ Writer.AddDeclRef(InstFrom.get<ClassTemplatePartialSpecializationDecl *>(),
+ Record);
Writer.AddTemplateArgumentList(&D->getTemplateInstantiationArgs(), Record);
- InstFromD = cast<ClassTemplatePartialSpecializationDecl>(InstFromD)->
- getSpecializedTemplate();
}
// Explicit info.
@@ -1110,6 +1119,14 @@ void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
Code = serialization::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION;
}
+void ASTDeclWriter::VisitClassScopeFunctionSpecializationDecl(
+ ClassScopeFunctionSpecializationDecl *D) {
+ VisitDecl(D);
+ Writer.AddDeclRef(D->getSpecialization(), Record);
+ Code = serialization::DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION;
+}
+
+
void ASTDeclWriter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
VisitRedeclarableTemplateDecl(D);
@@ -1233,7 +1250,7 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
// in a chained PCH, keep track of the association with the map so we can
// update the first decl during AST reading.
if (ThisDecl != First && First->getMostRecentDeclaration() == ThisDecl &&
- First->getPCHLevel() > ThisDecl->getPCHLevel()) {
+ First->isFromASTFile() && !ThisDecl->isFromASTFile()) {
assert(Writer.FirstLatestDecls.find(First) == Writer.FirstLatestDecls.end()
&& "The latest is already set");
Writer.FirstLatestDecls[First] = ThisDecl;
@@ -1262,7 +1279,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier
- Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1293,7 +1310,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier
- Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1327,7 +1344,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
- Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1339,8 +1356,9 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
// TagDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getTagKind
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isDefinition
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCompleteDefinition
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // EmbeddedInDeclarator
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFreeStanding
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypedefNameAnonDecl
@@ -1372,7 +1390,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
- Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1384,8 +1402,9 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
// TagDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getTagKind
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isDefinition
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCompleteDefinition
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // EmbeddedInDeclarator
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFreeStanding
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypedefNameAnonDecl
@@ -1411,7 +1430,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
- Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1459,7 +1478,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
- Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1484,7 +1503,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
- Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1527,6 +1546,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //HasQualifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //GetDeclFound
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ExplicitTemplateArgs
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //HadMultipleCandidates
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclRef
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
DeclRefExprAbbrev = Stream.EmitAbbrev(Abv);
@@ -1592,8 +1612,11 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
/// relatively painless since they would presumably only do it for top-level
/// decls.
static bool isRequiredDecl(const Decl *D, ASTContext &Context) {
+ // An ObjCMethodDecl is never considered as "required" because its
+ // implementation container always is.
+
// File scoped assembly or obj-c implementation must be seen.
- if (isa<FileScopeAsmDecl>(D) || isa<ObjCImplementationDecl>(D))
+ if (isa<FileScopeAsmDecl>(D) || isa<ObjCImplDecl>(D))
return true;
return Context.DeclMustBeEmitted(D);
@@ -1648,7 +1671,7 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) {
if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset);
if (!W.Code)
- llvm::report_fatal_error(llvm::StringRef("unexpected declaration kind '") +
+ llvm::report_fatal_error(StringRef("unexpected declaration kind '") +
D->getDeclKindName() + "'");
Stream.EmitRecord(W.Code, Record, W.AbbrevToUse);
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 1d73ed447b4f..7e2d45c5e7f9 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -36,7 +36,7 @@ namespace clang {
: Writer(Writer), Record(Record) { }
void
- AddExplicitTemplateArgumentList(const ExplicitTemplateArgumentList &Args);
+ AddExplicitTemplateArgumentList(const ASTTemplateArgumentListInfo &Args);
void VisitStmt(Stmt *S);
#define STMT(Type, Base) \
@@ -46,7 +46,7 @@ namespace clang {
}
void ASTStmtWriter::
-AddExplicitTemplateArgumentList(const ExplicitTemplateArgumentList &Args) {
+AddExplicitTemplateArgumentList(const ASTTemplateArgumentListInfo &Args) {
Writer.AddSourceLocation(Args.LAngleLoc, Record);
Writer.AddSourceLocation(Args.RAngleLoc, Record);
for (unsigned i=0; i != Args.NumTemplateArgs; ++i)
@@ -59,7 +59,7 @@ void ASTStmtWriter::VisitStmt(Stmt *S) {
void ASTStmtWriter::VisitNullStmt(NullStmt *S) {
VisitStmt(S);
Writer.AddSourceLocation(S->getSemiLoc(), Record);
- Writer.AddSourceLocation(S->LeadingEmptyMacro, Record);
+ Record.push_back(S->HasLeadingEmptyMacro);
Code = serialization::STMT_NULL;
}
@@ -265,6 +265,7 @@ void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
Record.push_back(E->hasQualifier());
Record.push_back(E->getDecl() != E->getFoundDecl());
Record.push_back(E->hasExplicitTemplateArgs());
+ Record.push_back(E->hadMultipleCandidates());
if (E->hasExplicitTemplateArgs()) {
unsigned NumTemplateArgs = E->getNumTemplateArgs();
@@ -324,7 +325,7 @@ void ASTStmtWriter::VisitStringLiteral(StringLiteral *E) {
VisitExpr(E);
Record.push_back(E->getByteLength());
Record.push_back(E->getNumConcatenated());
- Record.push_back(E->isWide());
+ Record.push_back(E->getKind());
Record.push_back(E->isPascal());
// FIXME: String data should be stored as a blob at the end of the
// StringLiteral. However, we can't do so now because we have no
@@ -340,7 +341,7 @@ void ASTStmtWriter::VisitCharacterLiteral(CharacterLiteral *E) {
VisitExpr(E);
Record.push_back(E->getValue());
Writer.AddSourceLocation(E->getLocation(), Record);
- Record.push_back(E->isWide());
+ Record.push_back(E->getKind());
AbbrevToUse = Writer.getCharacterLiteralAbbrev();
@@ -457,7 +458,9 @@ void ASTStmtWriter::VisitMemberExpr(MemberExpr *E) {
for (unsigned i=0; i != NumTemplateArgs; ++i)
Writer.AddTemplateArgumentLoc(E->getTemplateArgs()[i], Record);
}
-
+
+ Record.push_back(E->hadMultipleCandidates());
+
DeclAccessPair FoundDecl = E->getFoundDecl();
Writer.AddDeclRef(FoundDecl.getDecl(), Record);
Record.push_back(FoundDecl.getAccess());
@@ -733,6 +736,21 @@ void ASTStmtWriter::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
Code = serialization::EXPR_GENERIC_SELECTION;
}
+void ASTStmtWriter::VisitAtomicExpr(AtomicExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getOp());
+ Writer.AddStmt(E->getPtr());
+ Writer.AddStmt(E->getOrder());
+ if (E->getOp() != AtomicExpr::Load)
+ Writer.AddStmt(E->getVal1());
+ if (E->isCmpXChg()) {
+ Writer.AddStmt(E->getOrderFail());
+ Writer.AddStmt(E->getVal2());
+ }
+ Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+}
+
//===----------------------------------------------------------------------===//
// Objective-C Expressions and Statements.
//===----------------------------------------------------------------------===//
@@ -806,6 +824,8 @@ void ASTStmtWriter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
void ASTStmtWriter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
VisitExpr(E);
Record.push_back(E->getNumArgs());
+ Record.push_back(E->getNumStoredSelLocs());
+ Record.push_back(E->SelLocsKind);
Record.push_back(E->isDelegateInitCall());
Record.push_back((unsigned)E->getReceiverKind()); // FIXME: stable encoding
switch (E->getReceiverKind()) {
@@ -834,11 +854,15 @@ void ASTStmtWriter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
Writer.AddSourceLocation(E->getLeftLoc(), Record);
Writer.AddSourceLocation(E->getRightLoc(), Record);
- Writer.AddSourceLocation(E->getSelectorLoc(), Record);
for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end();
Arg != ArgEnd; ++Arg)
Writer.AddStmt(*Arg);
+
+ SourceLocation *Locs = E->getStoredSelLocs();
+ for (unsigned i = 0, e = E->getNumStoredSelLocs(); i != e; ++i)
+ Writer.AddSourceLocation(Locs[i], Record);
+
Code = serialization::EXPR_OBJC_MESSAGE_EXPR;
}
@@ -952,6 +976,7 @@ void ASTStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) {
Writer.AddDeclRef(E->getConstructor(), Record);
Writer.AddSourceLocation(E->getLocation(), Record);
Record.push_back(E->isElidable());
+ Record.push_back(E->hadMultipleCandidates());
Record.push_back(E->requiresZeroInitialization());
Record.push_back(E->getConstructionKind()); // FIXME: stable encoding
Writer.AddSourceRange(E->getParenRange(), Record);
@@ -1071,6 +1096,7 @@ void ASTStmtWriter::VisitCXXNewExpr(CXXNewExpr *E) {
Record.push_back(E->hasInitializer());
Record.push_back(E->doesUsualArrayDeleteWantSize());
Record.push_back(E->isArray());
+ Record.push_back(E->hadMultipleCandidates());
Record.push_back(E->getNumPlacementArgs());
Record.push_back(E->getNumConstructorArgs());
Writer.AddDeclRef(E->getOperatorNew(), Record);
@@ -1142,7 +1168,7 @@ ASTStmtWriter::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){
Record.push_back(E->hasExplicitTemplateArgs());
if (E->hasExplicitTemplateArgs()) {
- const ExplicitTemplateArgumentList &Args = E->getExplicitTemplateArgs();
+ const ASTTemplateArgumentListInfo &Args = E->getExplicitTemplateArgs();
Record.push_back(Args.NumTemplateArgs);
AddExplicitTemplateArgumentList(Args);
}
@@ -1168,7 +1194,7 @@ ASTStmtWriter::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
// emitted first.
Record.push_back(E->hasExplicitTemplateArgs());
if (E->hasExplicitTemplateArgs()) {
- const ExplicitTemplateArgumentList &Args = E->getExplicitTemplateArgs();
+ const ASTTemplateArgumentListInfo &Args = E->getExplicitTemplateArgs();
Record.push_back(Args.NumTemplateArgs);
AddExplicitTemplateArgumentList(Args);
}
@@ -1197,7 +1223,7 @@ void ASTStmtWriter::VisitOverloadExpr(OverloadExpr *E) {
// Don't emit anything here, hasExplicitTemplateArgs() must be emitted first.
Record.push_back(E->hasExplicitTemplateArgs());
if (E->hasExplicitTemplateArgs()) {
- const ExplicitTemplateArgumentList &Args = E->getExplicitTemplateArgs();
+ const ASTTemplateArgumentListInfo &Args = E->getExplicitTemplateArgs();
Record.push_back(Args.NumTemplateArgs);
AddExplicitTemplateArgumentList(Args);
}
@@ -1428,7 +1454,7 @@ void ASTWriter::WriteSubStmt(Stmt *S) {
}
// Redirect ASTWriter::AddStmt to collect sub stmts.
- llvm::SmallVector<Stmt *, 16> SubStmts;
+ SmallVector<Stmt *, 16> SubStmts;
CollectedStmts = &SubStmts;
Writer.Code = serialization::STMT_NULL_PTR;
@@ -1440,7 +1466,7 @@ void ASTWriter::WriteSubStmt(Stmt *S) {
SourceManager &SrcMgr
= DeclIDs.begin()->first->getASTContext().getSourceManager();
S->dump(SrcMgr);
- assert(0 && "Unhandled sub statement writing AST file");
+ llvm_unreachable("Unhandled sub statement writing AST file");
}
#endif
diff --git a/lib/Serialization/CMakeLists.txt b/lib/Serialization/CMakeLists.txt
index 66a72ee19d08..5611056f0172 100644
--- a/lib/Serialization/CMakeLists.txt
+++ b/lib/Serialization/CMakeLists.txt
@@ -2,6 +2,8 @@
#set(LLVM_USED_LIBS ???)
add_clang_library(clangSerialization
+ ASTCommon.h
+ ASTReaderInternals.h
ASTCommon.cpp
ASTReader.cpp
ASTReaderDecl.cpp
@@ -11,6 +13,8 @@ add_clang_library(clangSerialization
ASTWriterStmt.cpp
ChainedIncludesSource.cpp
GeneratePCH.cpp
+ Module.cpp
+ ModuleManager.cpp
)
add_dependencies(clangSerialization
diff --git a/lib/Serialization/ChainedIncludesSource.cpp b/lib/Serialization/ChainedIncludesSource.cpp
index 3b7cd23b92ae..5fcf11a36e3c 100644
--- a/lib/Serialization/ChainedIncludesSource.cpp
+++ b/lib/Serialization/ChainedIncludesSource.cpp
@@ -26,17 +26,20 @@
using namespace clang;
static ASTReader *createASTReader(CompilerInstance &CI,
- llvm::StringRef pchFile,
- llvm::MemoryBuffer **memBufs,
- unsigned numBufs,
+ StringRef pchFile,
+ SmallVector<llvm::MemoryBuffer *, 4> &memBufs,
+ SmallVector<std::string, 4> &bufNames,
ASTDeserializationListener *deserialListener = 0) {
Preprocessor &PP = CI.getPreprocessor();
llvm::OwningPtr<ASTReader> Reader;
- Reader.reset(new ASTReader(PP, &CI.getASTContext(), /*isysroot=*/0,
+ Reader.reset(new ASTReader(PP, CI.getASTContext(), /*isysroot=*/"",
/*DisableValidation=*/true));
- Reader->setASTMemoryBuffers(memBufs, numBufs);
+ for (unsigned ti = 0; ti < bufNames.size(); ++ti) {
+ StringRef sr(bufNames[ti]);
+ Reader->addInMemoryBuffer(sr, memBufs[ti]);
+ }
Reader->setDeserializationListener(deserialListener);
- switch (Reader->ReadAST(pchFile, ASTReader::PCH)) {
+ switch (Reader->ReadAST(pchFile, serialization::MK_PCH)) {
case ASTReader::Success:
// Set the predefines buffer as suggested by the PCH reader.
PP.setPredefines(Reader->getSuggestedPredefines());
@@ -62,7 +65,8 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
llvm::OwningPtr<ChainedIncludesSource> source(new ChainedIncludesSource());
InputKind IK = CI.getFrontendOpts().Inputs[0].first;
- llvm::SmallVector<llvm::MemoryBuffer *, 4> serialBufs;
+ SmallVector<llvm::MemoryBuffer *, 4> serialBufs;
+ SmallVector<std::string, 4> serialBufNames;
for (unsigned i = 0, e = includes.size(); i != e; ++i) {
bool firstInclude = (i == 0);
@@ -83,8 +87,8 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
TextDiagnosticPrinter *DiagClient =
new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic(DiagID,
- DiagClient));
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, DiagClient));
llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance());
Clang->setInvocation(CInvok.take());
@@ -98,16 +102,15 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
&Clang->getPreprocessor());
Clang->createASTContext();
- llvm::SmallVector<char, 256> serialAST;
+ SmallVector<char, 256> serialAST;
llvm::raw_svector_ostream OS(serialAST);
llvm::OwningPtr<ASTConsumer> consumer;
consumer.reset(new PCHGenerator(Clang->getPreprocessor(), "-",
- /*Chaining=*/!firstInclude,
- /*isysroot=*/0, &OS));
+ /*IsModule=*/false, /*isysroot=*/"", &OS));
Clang->getASTContext().setASTMutationListener(
consumer->GetASTMutationListener());
Clang->setASTConsumer(consumer.take());
- Clang->createSema(/*CompleteTranslationUnit=*/false, 0);
+ Clang->createSema(TU_Prefix, 0);
if (firstInclude) {
Preprocessor &PP = Clang->getPreprocessor();
@@ -115,19 +118,23 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
PP.getLangOptions());
} else {
assert(!serialBufs.empty());
- llvm::SmallVector<llvm::MemoryBuffer *, 4> bufs;
+ SmallVector<llvm::MemoryBuffer *, 4> bufs;
for (unsigned si = 0, se = serialBufs.size(); si != se; ++si) {
bufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(
- llvm::StringRef(serialBufs[si]->getBufferStart(),
+ StringRef(serialBufs[si]->getBufferStart(),
serialBufs[si]->getBufferSize())));
}
std::string pchName = includes[i-1];
llvm::raw_string_ostream os(pchName);
os << ".pch" << i-1;
os.flush();
+
+ serialBufNames.push_back(pchName);
+
llvm::OwningPtr<ExternalASTSource> Reader;
- Reader.reset(createASTReader(*Clang, pchName, bufs.data(), bufs.size(),
- Clang->getASTConsumer().GetASTDeserializationListener()));
+
+ Reader.reset(createASTReader(*Clang, pchName, bufs, serialBufNames,
+ Clang->getASTConsumer().GetASTDeserializationListener()));
if (!Reader)
return 0;
Clang->getASTContext().setExternalSource(Reader);
@@ -140,16 +147,16 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
OS.flush();
Clang->getDiagnosticClient().EndSourceFile();
serialBufs.push_back(
- llvm::MemoryBuffer::getMemBufferCopy(llvm::StringRef(serialAST.data(),
+ llvm::MemoryBuffer::getMemBufferCopy(StringRef(serialAST.data(),
serialAST.size())));
source->CIs.push_back(Clang.take());
}
assert(!serialBufs.empty());
std::string pchName = includes.back() + ".pch-final";
+ serialBufNames.push_back(pchName);
llvm::OwningPtr<ASTReader> Reader;
- Reader.reset(createASTReader(CI, pchName,
- serialBufs.data(), serialBufs.size()));
+ Reader.reset(createASTReader(CI, pchName, serialBufs, serialBufNames));
if (!Reader)
return 0;
@@ -182,13 +189,10 @@ ChainedIncludesSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) {
return getFinalReader().FindExternalVisibleDeclsByName(DC, Name);
}
-void ChainedIncludesSource::MaterializeVisibleDecls(const DeclContext *DC) {
- return getFinalReader().MaterializeVisibleDecls(DC);
-}
ExternalLoadResult
ChainedIncludesSource::FindExternalLexicalDecls(const DeclContext *DC,
bool (*isKindWeWant)(Decl::Kind),
- llvm::SmallVectorImpl<Decl*> &Result) {
+ SmallVectorImpl<Decl*> &Result) {
return getFinalReader().FindExternalLexicalDecls(DC, isKindWeWant, Result);
}
void ChainedIncludesSource::CompleteType(TagDecl *Tag) {
diff --git a/lib/Serialization/GeneratePCH.cpp b/lib/Serialization/GeneratePCH.cpp
index b8833ceacc7e..a2534db82cdd 100644
--- a/lib/Serialization/GeneratePCH.cpp
+++ b/lib/Serialization/GeneratePCH.cpp
@@ -27,31 +27,29 @@
using namespace clang;
PCHGenerator::PCHGenerator(const Preprocessor &PP,
- const std::string &OutputFile,
- bool Chaining,
- const char *isysroot,
- llvm::raw_ostream *OS)
- : PP(PP), OutputFile(OutputFile), isysroot(isysroot), Out(OS), SemaPtr(0),
- StatCalls(0), Stream(Buffer), Writer(Stream), Chaining(Chaining) {
+ StringRef OutputFile,
+ bool IsModule,
+ StringRef isysroot,
+ raw_ostream *OS)
+ : PP(PP), OutputFile(OutputFile), IsModule(IsModule),
+ isysroot(isysroot.str()), Out(OS),
+ SemaPtr(0), StatCalls(0), Stream(Buffer), Writer(Stream) {
// Install a stat() listener to keep track of all of the stat()
// calls.
StatCalls = new MemorizeStatCalls();
- // If we have a chain, we want new stat calls only, so install the memorizer
- // *after* the already installed ASTReader's stat cache.
- PP.getFileManager().addStatCache(StatCalls,
- /*AtBeginning=*/!Chaining);
+ PP.getFileManager().addStatCache(StatCalls, /*AtBeginning=*/false);
+}
+
+PCHGenerator::~PCHGenerator() {
}
void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
if (PP.getDiagnostics().hasErrorOccurred())
return;
-
- // Set up the serialization listener.
- Writer.SetSerializationListener(GetASTSerializationListener());
// Emit the PCH file
assert(SemaPtr && "No Sema?");
- Writer.WriteAST(*SemaPtr, StatCalls, OutputFile, isysroot);
+ Writer.WriteAST(*SemaPtr, StatCalls, OutputFile, IsModule, isysroot);
// Write the generated bitstream to "Out".
Out->write((char *)&Buffer.front(), Buffer.size());
@@ -64,13 +62,7 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
}
ASTMutationListener *PCHGenerator::GetASTMutationListener() {
- if (Chaining)
- return &Writer;
- return 0;
-}
-
-ASTSerializationListener *PCHGenerator::GetASTSerializationListener() {
- return 0;
+ return &Writer;
}
ASTDeserializationListener *PCHGenerator::GetASTDeserializationListener() {
diff --git a/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp
new file mode 100644
index 000000000000..0a721c4365af
--- /dev/null
+++ b/lib/Serialization/Module.cpp
@@ -0,0 +1,109 @@
+//===--- Module.cpp - Module description ------------------------*- 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 Module class, which describes a module that has
+// been loaded from an AST file.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Serialization/Module.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "ASTReaderInternals.h"
+
+using namespace clang;
+using namespace serialization;
+using namespace reader;
+
+Module::Module(ModuleKind Kind)
+ : Kind(Kind), DirectlyImported(false), SizeInBits(0),
+ LocalNumSLocEntries(0), SLocEntryBaseID(0),
+ SLocEntryBaseOffset(0), SLocEntryOffsets(0),
+ SLocFileOffsets(0), LocalNumIdentifiers(0),
+ IdentifierOffsets(0), BaseIdentifierID(0), IdentifierTableData(0),
+ IdentifierLookupTable(0), BasePreprocessedEntityID(0),
+ PreprocessedEntityOffsets(0), NumPreprocessedEntities(0),
+ LocalNumHeaderFileInfos(0),
+ HeaderFileInfoTableData(0), HeaderFileInfoTable(0),
+ HeaderFileFrameworkStrings(0),
+ LocalNumSelectors(0), SelectorOffsets(0), BaseSelectorID(0),
+ SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0),
+ DeclOffsets(0), BaseDeclID(0),
+ LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(0),
+ LocalNumTypes(0), TypeOffsets(0), BaseTypeIndex(0), StatCache(0)
+{}
+
+Module::~Module() {
+ for (DeclContextInfosMap::iterator I = DeclContextInfos.begin(),
+ E = DeclContextInfos.end();
+ I != E; ++I) {
+ if (I->second.NameLookupTableData)
+ delete static_cast<ASTDeclContextNameLookupTable*>(
+ I->second.NameLookupTableData);
+ }
+
+ delete static_cast<ASTIdentifierLookupTable *>(IdentifierLookupTable);
+ delete static_cast<HeaderFileInfoLookupTable *>(HeaderFileInfoTable);
+ delete static_cast<ASTSelectorLookupTable *>(SelectorLookupTable);
+}
+
+template<typename Key, typename Offset, unsigned InitialCapacity>
+static void
+dumpLocalRemap(StringRef Name,
+ const ContinuousRangeMap<Key, Offset, InitialCapacity> &Map) {
+ if (Map.begin() == Map.end())
+ return;
+
+ typedef ContinuousRangeMap<Key, Offset, InitialCapacity> MapType;
+ llvm::errs() << " " << Name << ":\n";
+ for (typename MapType::const_iterator I = Map.begin(), IEnd = Map.end();
+ I != IEnd; ++I) {
+ llvm::errs() << " " << I->first << " -> " << I->second << "\n";
+ }
+}
+
+void Module::dump() {
+ llvm::errs() << "\nModule: " << FileName << "\n";
+ if (!Imports.empty()) {
+ llvm::errs() << " Imports: ";
+ for (unsigned I = 0, N = Imports.size(); I != N; ++I) {
+ if (I)
+ llvm::errs() << ", ";
+ llvm::errs() << Imports[I]->FileName;
+ }
+ llvm::errs() << "\n";
+ }
+
+ // Remapping tables.
+ llvm::errs() << " Base source location offset: " << SLocEntryBaseOffset
+ << '\n';
+ dumpLocalRemap("Source location offset local -> global map", SLocRemap);
+
+ llvm::errs() << " Base identifier ID: " << BaseIdentifierID << '\n'
+ << " Number of identifiers: " << LocalNumIdentifiers << '\n';
+ dumpLocalRemap("Identifier ID local -> global map", IdentifierRemap);
+
+ llvm::errs() << " Base selector ID: " << BaseSelectorID << '\n'
+ << " Number of selectors: " << LocalNumSelectors << '\n';
+ dumpLocalRemap("Selector ID local -> global map", SelectorRemap);
+
+ llvm::errs() << " Base preprocessed entity ID: " << BasePreprocessedEntityID
+ << '\n'
+ << " Number of preprocessed entities: "
+ << NumPreprocessedEntities << '\n';
+ dumpLocalRemap("Preprocessed entity ID local -> global map",
+ PreprocessedEntityRemap);
+
+ llvm::errs() << " Base type index: " << BaseTypeIndex << '\n'
+ << " Number of types: " << LocalNumTypes << '\n';
+ dumpLocalRemap("Type index local -> global map", TypeRemap);
+
+ llvm::errs() << " Base decl ID: " << BaseDeclID << '\n'
+ << " Number of decls: " << LocalNumDecls << '\n';
+ dumpLocalRemap("Decl ID local -> global map", DeclRemap);
+}
diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp
new file mode 100644
index 000000000000..c4b1f7199bed
--- /dev/null
+++ b/lib/Serialization/ModuleManager.cpp
@@ -0,0 +1,253 @@
+//===--- ModuleManager.cpp - Module Manager ---------------------*- 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 ModuleManager class, which manages a set of loaded
+// modules for the ASTReader.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Serialization/ModuleManager.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
+
+#ifndef NDEBUG
+#include "llvm/Support/GraphWriter.h"
+#endif
+
+using namespace clang;
+using namespace serialization;
+
+Module *ModuleManager::lookup(StringRef Name) {
+ const FileEntry *Entry = FileMgr.getFile(Name);
+ return Modules[Entry];
+}
+
+llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) {
+ const FileEntry *Entry = FileMgr.getFile(Name);
+ return InMemoryBuffers[Entry];
+}
+
+std::pair<Module *, bool>
+ModuleManager::addModule(StringRef FileName, ModuleKind Type,
+ Module *ImportedBy, std::string &ErrorStr) {
+ const FileEntry *Entry = FileMgr.getFile(FileName);
+ if (!Entry && FileName != "-") {
+ ErrorStr = "file not found";
+ return std::make_pair(static_cast<Module*>(0), false);
+ }
+
+ // Check whether we already loaded this module, before
+ Module *&ModuleEntry = Modules[Entry];
+ bool NewModule = false;
+ if (!ModuleEntry) {
+ // Allocate a new module.
+ Module *New = new Module(Type);
+ New->FileName = FileName.str();
+ 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.
+ assert(Buffer && "Passed null buffer");
+ New->Buffer.reset(Buffer);
+ } else {
+ // Open the AST file.
+ llvm::error_code ec;
+ if (FileName == "-") {
+ ec = llvm::MemoryBuffer::getSTDIN(New->Buffer);
+ if (ec)
+ ErrorStr = ec.message();
+ } else
+ New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr));
+
+ if (!New->Buffer)
+ return std::make_pair(static_cast<Module*>(0), false);
+ }
+
+ // Initialize the stream
+ New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(),
+ (const unsigned char *)New->Buffer->getBufferEnd()); }
+
+ if (ImportedBy) {
+ ModuleEntry->ImportedBy.insert(ImportedBy);
+ ImportedBy->Imports.insert(ModuleEntry);
+ } else {
+ ModuleEntry->DirectlyImported = true;
+ }
+
+ return std::make_pair(ModuleEntry, NewModule);
+}
+
+void ModuleManager::addInMemoryBuffer(StringRef FileName,
+ llvm::MemoryBuffer *Buffer) {
+
+ const FileEntry *Entry = FileMgr.getVirtualFile(FileName,
+ Buffer->getBufferSize(), 0);
+ InMemoryBuffers[Entry] = Buffer;
+}
+
+ModuleManager::ModuleManager(const FileSystemOptions &FSO) : FileMgr(FSO) { }
+
+ModuleManager::~ModuleManager() {
+ for (unsigned i = 0, e = Chain.size(); i != e; ++i)
+ delete Chain[e - i - 1];
+}
+
+void ModuleManager::visit(bool (*Visitor)(Module &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<Module *, 4> Queue;
+ Queue.reserve(N);
+ llvm::DenseMap<Module *, 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<Module *, 4> Skipped;
+ unsigned QueueStart = 0;
+ while (QueueStart < Queue.size()) {
+ Module *CurrentModule = Queue[QueueStart++];
+
+ // Check whether this module should be skipped.
+ if (Skipped.count(CurrentModule))
+ 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<Module *, 4> Stack;
+ Stack.push_back(CurrentModule);
+ Skipped.insert(CurrentModule);
+ while (!Stack.empty()) {
+ Module *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<Module *>::iterator
+ M = NextModule->Imports.begin(),
+ MEnd = NextModule->Imports.end();
+ M != MEnd; ++M) {
+ if (Skipped.insert(*M))
+ Stack.push_back(*M);
+ }
+ }
+ 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<Module *>::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);
+ }
+ }
+}
+
+/// \brief Perform a depth-first visit of the current module.
+static bool visitDepthFirst(Module &M,
+ bool (*Visitor)(Module &M, bool Preorder,
+ void *UserData),
+ void *UserData,
+ llvm::SmallPtrSet<Module *, 4> &Visited) {
+ // Preorder visitation
+ if (Visitor(M, /*Preorder=*/true, UserData))
+ return true;
+
+ // Visit children
+ for (llvm::SetVector<Module *>::iterator IM = M.Imports.begin(),
+ IMEnd = M.Imports.end();
+ IM != IMEnd; ++IM) {
+ if (!Visited.insert(*IM))
+ continue;
+
+ if (visitDepthFirst(**IM, Visitor, UserData, Visited))
+ return true;
+ }
+
+ // Postorder visitation
+ return Visitor(M, /*Preorder=*/false, UserData);
+}
+
+void ModuleManager::visitDepthFirst(bool (*Visitor)(Module &M, bool Preorder,
+ void *UserData),
+ void *UserData) {
+ llvm::SmallPtrSet<Module *, 4> Visited;
+ for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
+ if (!Visited.insert(Chain[I]))
+ continue;
+
+ if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited))
+ return;
+ }
+}
+
+#ifndef NDEBUG
+namespace llvm {
+ template<>
+ struct GraphTraits<ModuleManager> {
+ typedef Module NodeType;
+ typedef llvm::SetVector<Module *>::const_iterator ChildIteratorType;
+ typedef ModuleManager::ModuleConstIterator nodes_iterator;
+
+ static ChildIteratorType child_begin(NodeType *Node) {
+ return Node->Imports.begin();
+ }
+
+ static ChildIteratorType child_end(NodeType *Node) {
+ return Node->Imports.end();
+ }
+
+ static nodes_iterator nodes_begin(const ModuleManager &Manager) {
+ return Manager.begin();
+ }
+
+ static nodes_iterator nodes_end(const ModuleManager &Manager) {
+ return Manager.end();
+ }
+ };
+
+ template<>
+ struct DOTGraphTraits<ModuleManager> : public DefaultDOTGraphTraits {
+ explicit DOTGraphTraits(bool IsSimple = false)
+ : DefaultDOTGraphTraits(IsSimple) { }
+
+ static bool renderGraphFromBottomUp() {
+ return true;
+ }
+
+ std::string getNodeLabel(Module *M, const ModuleManager&) {
+ return llvm::sys::path::stem(M->FileName);
+ }
+ };
+}
+
+void ModuleManager::viewGraph() {
+ llvm::ViewGraph(*this, "Modules");
+}
+#endif
diff --git a/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp b/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp
index 8fc6d2a2933e..dc524ba24e06 100644
--- a/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp
@@ -37,7 +37,7 @@ void AdjustedReturnValueChecker::checkPostStmt(const CallExpr *CE,
QualType expectedResultTy = CE->getType();
// Fetch the signature of the called function.
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
SVal V = state->getSVal(CE);
diff --git a/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
index 983427afb62d..cd977bf54c67 100644
--- a/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
@@ -80,7 +80,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
const NamedDecl *ND = cast<NamedDecl>(D);
- output << ND;
+ output << *ND;
}
else if (isa<BlockDecl>(D)) {
output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
@@ -94,7 +94,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
<< (Eng.hasEmptyWorkList() ? "yes" : "no");
B.EmitBasicReport("Analyzer Statistics", "Internal Statistics", output.str(),
- D->getLocation());
+ PathDiagnosticLocation(D, SM));
// Emit warning for each block we bailed out on
typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator;
@@ -106,7 +106,8 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
const CFGElement &CE = Exit->front();
if (const CFGStmt *CS = dyn_cast<CFGStmt>(&CE))
B.EmitBasicReport("Bailout Point", "Internal Statistics", "The analyzer "
- "stopped analyzing at this point", CS->getStmt()->getLocStart());
+ "stopped analyzing at this point",
+ PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC));
}
}
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
index eb9665a4a343..6935c5f1c192 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
@@ -27,11 +27,12 @@ class ArrayBoundChecker :
public Checker<check::Location> {
mutable llvm::OwningPtr<BuiltinBug> BT;
public:
- void checkLocation(SVal l, bool isLoad, CheckerContext &C) const;
+ void checkLocation(SVal l, bool isLoad, const Stmt* S,
+ CheckerContext &C) const;
};
}
-void ArrayBoundChecker::checkLocation(SVal l, bool isLoad,
+void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
CheckerContext &C) const {
// Check for out of bound array element access.
const MemRegion *R = l.getAsRegion();
@@ -50,15 +51,15 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad,
if (Idx.isZeroConstant())
return;
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
// Get the size of the array.
DefinedOrUnknownSVal NumElements
= C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
ER->getValueType());
- const GRState *StInBound = state->assumeInBound(Idx, NumElements, true);
- const GRState *StOutBound = state->assumeInBound(Idx, NumElements, false);
+ const ProgramState *StInBound = state->assumeInBound(Idx, NumElements, true);
+ const ProgramState *StOutBound = state->assumeInBound(Idx, NumElements, false);
if (StOutBound && !StInBound) {
ExplodedNode *N = C.generateSink(StOutBound);
if (!N)
@@ -73,10 +74,10 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad,
// reference is outside the range.
// Generate a report for this bug.
- RangedBugReport *report =
- new RangedBugReport(*BT, BT->getDescription(), N);
+ BugReport *report =
+ new BugReport(*BT, BT->getDescription(), N);
- report->addRange(C.getStmt()->getSourceRange());
+ report->addRange(LoadS->getSourceRange());
C.EmitReport(report);
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index 65a6e633dc8e..6175028a9b20 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -30,11 +30,12 @@ class ArrayBoundCheckerV2 :
enum OOB_Kind { OOB_Precedes, OOB_Excedes };
- void reportOOB(CheckerContext &C, const GRState *errorState,
+ void reportOOB(CheckerContext &C, const ProgramState *errorState,
OOB_Kind kind) const;
public:
- void checkLocation(SVal l, bool isLoad, CheckerContext &C) const;
+ void checkLocation(SVal l, bool isLoad, const Stmt*S,
+ CheckerContext &C) const;
};
// FIXME: Eventually replace RegionRawOffset with this class.
@@ -53,12 +54,12 @@ public:
NonLoc getByteOffset() const { return cast<NonLoc>(byteOffset); }
const SubRegion *getRegion() const { return baseRegion; }
- static RegionRawOffsetV2 computeOffset(const GRState *state,
+ static RegionRawOffsetV2 computeOffset(const ProgramState *state,
SValBuilder &svalBuilder,
SVal location);
void dump() const;
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
};
}
@@ -79,9 +80,10 @@ static SVal computeExtentBegin(SValBuilder &svalBuilder,
}
void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
+ const Stmt* LoadS,
CheckerContext &checkerContext) const {
- // NOTE: Instead of using GRState::assumeInBound(), we are prototyping
+ // NOTE: Instead of using ProgramState::assumeInBound(), we are prototyping
// some new logic here that reasons directly about memory region extents.
// Once that logic is more mature, we can bring it back to assumeInBound()
// for all clients to use.
@@ -90,8 +92,8 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
// memory access is within the extent of the base region. Since we
// have some flexibility in defining the base region, we can achieve
// various levels of conservatism in our buffer overflow checking.
- const GRState *state = checkerContext.getState();
- const GRState *originalState = state;
+ const ProgramState *state = checkerContext.getState();
+ const ProgramState *originalState = state;
SValBuilder &svalBuilder = checkerContext.getSValBuilder();
const RegionRawOffsetV2 &rawOffset =
@@ -116,7 +118,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
if (!lowerBoundToCheck)
return;
- const GRState *state_precedesLowerBound, *state_withinLowerBound;
+ const ProgramState *state_precedesLowerBound, *state_withinLowerBound;
llvm::tie(state_precedesLowerBound, state_withinLowerBound) =
state->assume(*lowerBoundToCheck);
@@ -148,7 +150,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
if (!upperboundToCheck)
break;
- const GRState *state_exceedsUpperBound, *state_withinUpperBound;
+ const ProgramState *state_exceedsUpperBound, *state_withinUpperBound;
llvm::tie(state_exceedsUpperBound, state_withinUpperBound) =
state->assume(*upperboundToCheck);
@@ -168,7 +170,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
}
void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext,
- const GRState *errorState,
+ const ProgramState *errorState,
OOB_Kind kind) const {
ExplodedNode *errorNode = checkerContext.generateSink(errorState);
@@ -187,14 +189,14 @@ void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext,
<< (kind == OOB_Precedes ? "(accessed memory precedes memory block)"
: "(access exceeds upper limit of memory block)");
- checkerContext.EmitReport(new RangedBugReport(*BT, os.str(), errorNode));
+ checkerContext.EmitReport(new BugReport(*BT, os.str(), errorNode));
}
void RegionRawOffsetV2::dump() const {
dumpToStream(llvm::errs());
}
-void RegionRawOffsetV2::dumpToStream(llvm::raw_ostream& os) const {
+void RegionRawOffsetV2::dumpToStream(raw_ostream &os) const {
os << "raw_offset_v2{" << getRegion() << ',' << getByteOffset() << '}';
}
@@ -219,7 +221,7 @@ static inline SVal getValue(SVal val, SValBuilder &svalBuilder) {
// Scale a base value by a scaling factor, and return the scaled
// value as an SVal. Used by 'computeOffset'.
-static inline SVal scaleValue(const GRState *state,
+static inline SVal scaleValue(const ProgramState *state,
NonLoc baseVal, CharUnits scaling,
SValBuilder &sb) {
return sb.evalBinOpNN(state, BO_Mul, baseVal,
@@ -229,7 +231,7 @@ static inline SVal scaleValue(const GRState *state,
// Add an SVal to another, treating unknown and undefined values as
// summing to UnknownVal. Used by 'computeOffset'.
-static SVal addValue(const GRState *state, SVal x, SVal y,
+static SVal addValue(const ProgramState *state, SVal x, SVal y,
SValBuilder &svalBuilder) {
// We treat UnknownVals and UndefinedVals the same here because we
// only care about computing offsets.
@@ -243,7 +245,7 @@ static SVal addValue(const GRState *state, SVal x, SVal y,
/// Compute a raw byte offset from a base region. Used for array bounds
/// checking.
-RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(const GRState *state,
+RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(const ProgramState *state,
SValBuilder &svalBuilder,
SVal location)
{
diff --git a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
index d88a111e9a56..8296eb93c5ae 100644
--- a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
@@ -33,12 +33,12 @@ public:
void AttrNonNullChecker::checkPreStmt(const CallExpr *CE,
CheckerContext &C) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
// Check if the callee has a 'nonnull' attribute.
SVal X = state->getSVal(CE->getCallee());
- const FunctionDecl* FD = X.getAsFunctionDecl();
+ const FunctionDecl *FD = X.getAsFunctionDecl();
if (!FD)
return;
@@ -85,7 +85,7 @@ void AttrNonNullChecker::checkPreStmt(const CallExpr *CE,
}
ConstraintManager &CM = C.getConstraintManager();
- const GRState *stateNotNull, *stateNull;
+ const ProgramState *stateNotNull, *stateNull;
llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
if (stateNull && !stateNotNull) {
@@ -100,16 +100,15 @@ void AttrNonNullChecker::checkPreStmt(const CallExpr *CE,
BT.reset(new BugType("Argument with 'nonnull' attribute passed null",
"API"));
- EnhancedBugReport *R =
- new EnhancedBugReport(*BT,
- "Null pointer passed as an argument to a "
- "'nonnull' parameter", errorNode);
+ 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.
const Expr *arg = *I;
R->addRange(arg->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, arg);
-
+ R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(errorNode,
+ arg));
// Emit the bug report.
C.EmitReport(R);
}
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 9fc8163ab8b9..08cff0fd4292 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -20,7 +20,8 @@
#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/GRState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.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"
@@ -49,7 +50,7 @@ static const char* GetReceiverNameType(const ObjCMessage &msg) {
}
static bool isReceiverClassOrSuperclass(const ObjCInterfaceDecl *ID,
- llvm::StringRef ClassName) {
+ StringRef ClassName) {
if (ID->getIdentifier()->getName() == ClassName)
return true;
@@ -92,7 +93,7 @@ void NilArgChecker::WarnNilArg(CheckerContext &C,
os << "Argument to '" << GetReceiverNameType(msg) << "' method '"
<< msg.getSelector().getAsString() << "' cannot be nil";
- RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
+ BugReport *R = new BugReport(*BT, os.str(), N);
R->addRange(msg.getArgSourceRange(Arg));
C.EmitReport(R);
}
@@ -114,7 +115,7 @@ void NilArgChecker::checkPreObjCMessage(ObjCMessage msg,
// lexical comparisons.
std::string NameStr = S.getAsString();
- llvm::StringRef Name(NameStr);
+ StringRef Name(NameStr);
assert(!Name.empty());
// FIXME: Checking for initWithFormat: will not work in most cases
@@ -148,7 +149,7 @@ public:
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
private:
- void EmitError(const TypedRegion* R, const Expr* Ex,
+ void EmitError(const TypedRegion* R, const Expr *Ex,
uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
};
} // end anonymous namespace
@@ -194,7 +195,7 @@ namespace {
};
}
-static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
+static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
if (i < kCFNumberCharType)
@@ -248,10 +249,10 @@ static const char* GetCFNumberTypeStr(uint64_t i) {
void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
CheckerContext &C) const {
- const Expr* Callee = CE->getCallee();
- const GRState *state = C.getState();
+ const Expr *Callee = CE->getCallee();
+ const ProgramState *state = C.getState();
SVal CallV = state->getSVal(Callee);
- const FunctionDecl* FD = CallV.getAsFunctionDecl();
+ const FunctionDecl *FD = CallV.getAsFunctionDecl();
if (!FD)
return;
@@ -290,7 +291,7 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
if (!LV)
return;
- const TypedRegion* R = dyn_cast<TypedRegion>(LV->stripCasts());
+ const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
if (!R)
return;
@@ -335,7 +336,7 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
if (!BT)
BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
- RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
+ BugReport *report = new BugReport(*BT, os.str(), N);
report->addRange(CE->getArg(2)->getSourceRange());
C.EmitReport(report);
}
@@ -351,21 +352,21 @@ class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
mutable IdentifierInfo *Retain, *Release;
public:
CFRetainReleaseChecker(): Retain(0), Release(0) {}
- void checkPreStmt(const CallExpr* CE, CheckerContext& C) const;
+ void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
};
} // end anonymous namespace
-void CFRetainReleaseChecker::checkPreStmt(const CallExpr* CE,
- CheckerContext& C) const {
+void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
+ CheckerContext &C) const {
// If the CallExpr doesn't have exactly 1 argument just give up checking.
if (CE->getNumArgs() != 1)
return;
// Get the function declaration of the callee.
- const GRState* state = C.getState();
+ const ProgramState *state = C.getState();
SVal X = state->getSVal(CE->getCallee());
- const FunctionDecl* FD = X.getAsFunctionDecl();
+ const FunctionDecl *FD = X.getAsFunctionDecl();
if (!FD)
return;
@@ -400,7 +401,7 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr* CE,
DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
// Are they equal?
- const GRState *stateTrue, *stateFalse;
+ const ProgramState *stateTrue, *stateFalse;
llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
if (stateTrue && !stateFalse) {
@@ -412,9 +413,9 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr* CE,
? "Null pointer argument in call to CFRetain"
: "Null pointer argument in call to CFRelease";
- EnhancedBugReport *report = new EnhancedBugReport(*BT, description, N);
+ BugReport *report = new BugReport(*BT, description, N);
report->addRange(Arg->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Arg);
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Arg));
C.EmitReport(report);
return;
}
@@ -471,7 +472,7 @@ void ClassReleaseChecker::checkPreObjCMessage(ObjCMessage msg,
"of class '" << Class->getName()
<< "' and not the class directly";
- RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
+ BugReport *report = new BugReport(*BT, os.str(), N);
report->addRange(msg.getSourceRange());
C.EmitReport(report);
}
@@ -586,7 +587,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg,
// Verify that all arguments have Objective-C types.
llvm::Optional<ExplodedNode*> errorNode;
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
QualType ArgTy = msg.getArgType(I);
@@ -629,7 +630,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg,
<< "' should be an Objective-C pointer type, not '"
<< ArgTy.getAsString() << "'";
- RangedBugReport *R = new RangedBugReport(*BT, os.str(),
+ BugReport *R = new BugReport(*BT, os.str(),
errorNode.getValue());
R->addRange(msg.getArgSourceRange(I));
C.EmitReport(R);
diff --git a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index 12ac652ba060..a57d03175c5f 100644
--- a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -31,7 +31,7 @@ public:
bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
CheckerContext &C) const{
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
const FunctionDecl *FD = L.getAsFunctionDecl();
@@ -57,7 +57,7 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
// FIXME: Refactor into StoreManager itself?
MemRegionManager& RM = C.getStoreManager().getRegionManager();
const AllocaRegion* R =
- RM.getAllocaRegion(CE, C.getNodeBuilder().getCurrentBlockCount(),
+ RM.getAllocaRegion(CE, C.getCurrentBlockCount(),
C.getPredecessor()->getLocationContext());
// Set the extent of the region in bytes. This enables us to use the
diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 8dc7f385a58d..3e0d0946daaf 100644
--- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -22,7 +22,7 @@ add_clang_library(clangStaticAnalyzerCheckers
CheckSecuritySyntaxOnly.cpp
CheckSizeofPointer.cpp
ChrootChecker.cpp
- ClangSACheckerProvider.cpp
+ ClangCheckers.cpp
DeadStoresChecker.cpp
DebugCheckers.cpp
DereferenceChecker.cpp
@@ -31,8 +31,10 @@ add_clang_library(clangStaticAnalyzerCheckers
IdempotentOperationChecker.cpp
IteratorsChecker.cpp
LLVMConventionsChecker.cpp
+ MacOSKeychainAPIChecker.cpp
MacOSXAPIChecker.cpp
MallocChecker.cpp
+ MallocOverflowSecurityChecker.cpp
NSAutoreleasePoolChecker.cpp
NSErrorChecker.cpp
NoReturnFunctionChecker.cpp
@@ -43,6 +45,7 @@ add_clang_library(clangStaticAnalyzerCheckers
PointerArithChecker.cpp
PointerSubChecker.cpp
PthreadLockChecker.cpp
+ RetainCountChecker.cpp
ReturnPointerRangeChecker.cpp
ReturnUndefChecker.cpp
StackAddrEscapeChecker.cpp
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index c5dac5d21626..1625219fc877 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -1,4 +1,4 @@
-//= CStringChecker.h - Checks calls to C string functions ----------*- C++ -*-//
+//= CStringChecker.cpp - Checks calls to C string functions --------*- C++ -*-//
//
// The LLVM Compiler Infrastructure
//
@@ -17,7 +17,7 @@
#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/GRStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
@@ -40,14 +40,15 @@ public:
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const;
- void checkLiveSymbols(const GRState *state, SymbolReaper &SR) const;
+ void checkLiveSymbols(const ProgramState *state, SymbolReaper &SR) const;
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
- bool wantsRegionChangeUpdate(const GRState *state) const;
+ bool wantsRegionChangeUpdate(const ProgramState *state) const;
- const GRState *checkRegionChanges(const GRState *state,
- const StoreManager::InvalidatedSymbols *,
- const MemRegion * const *Begin,
- const MemRegion * const *End) const;
+ const ProgramState *
+ checkRegionChanges(const ProgramState *state,
+ const StoreManager::InvalidatedSymbols *,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions) const;
typedef void (CStringChecker::*FnCheck)(CheckerContext &,
const CallExpr *) const;
@@ -57,8 +58,10 @@ public:
void evalMemmove(CheckerContext &C, const CallExpr *CE) const;
void evalBcopy(CheckerContext &C, const CallExpr *CE) const;
void evalCopyCommon(CheckerContext &C, const CallExpr *CE,
- const GRState *state,
- const Expr *Size, const Expr *Source, const Expr *Dest,
+ const ProgramState *state,
+ const Expr *Size,
+ const Expr *Source,
+ const Expr *Dest,
bool Restricted = false,
bool IsMempcpy = false) const;
@@ -66,14 +69,18 @@ public:
void evalstrLength(CheckerContext &C, const CallExpr *CE) const;
void evalstrnLength(CheckerContext &C, const CallExpr *CE) const;
- void evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
+ void evalstrLengthCommon(CheckerContext &C,
+ const CallExpr *CE,
bool IsStrnlen = false) const;
void evalStrcpy(CheckerContext &C, const CallExpr *CE) const;
void evalStrncpy(CheckerContext &C, const CallExpr *CE) const;
void evalStpcpy(CheckerContext &C, const CallExpr *CE) const;
- void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd,
- bool isBounded, bool isAppending) const;
+ void evalStrcpyCommon(CheckerContext &C,
+ const CallExpr *CE,
+ bool returnEnd,
+ bool isBounded,
+ bool isAppending) const;
void evalStrcat(CheckerContext &C, const CallExpr *CE) const;
void evalStrncat(CheckerContext &C, const CallExpr *CE) const;
@@ -82,64 +89,85 @@ public:
void evalStrncmp(CheckerContext &C, const CallExpr *CE) const;
void evalStrcasecmp(CheckerContext &C, const CallExpr *CE) const;
void evalStrncasecmp(CheckerContext &C, const CallExpr *CE) const;
- void evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
- bool isBounded = false, bool ignoreCase = false) const;
+ void evalStrcmpCommon(CheckerContext &C,
+ const CallExpr *CE,
+ bool isBounded = false,
+ bool ignoreCase = false) const;
// Utility methods
- std::pair<const GRState*, const GRState*>
+ std::pair<const ProgramState*, const ProgramState*>
static assumeZero(CheckerContext &C,
- const GRState *state, SVal V, QualType Ty);
+ const ProgramState *state, SVal V, QualType Ty);
- static const GRState *setCStringLength(const GRState *state,
- const MemRegion *MR, SVal strLength);
+ static const ProgramState *setCStringLength(const ProgramState *state,
+ const MemRegion *MR,
+ SVal strLength);
static SVal getCStringLengthForRegion(CheckerContext &C,
- const GRState *&state,
- const Expr *Ex, const MemRegion *MR,
+ const ProgramState *&state,
+ const Expr *Ex,
+ const MemRegion *MR,
bool hypothetical);
- SVal getCStringLength(CheckerContext &C, const GRState *&state,
- const Expr *Ex, SVal Buf,
+ SVal getCStringLength(CheckerContext &C,
+ const ProgramState *&state,
+ const Expr *Ex,
+ SVal Buf,
bool hypothetical = false) const;
const StringLiteral *getCStringLiteral(CheckerContext &C,
- const GRState *&state,
+ const ProgramState *&state,
const Expr *expr,
SVal val) const;
- static const GRState *InvalidateBuffer(CheckerContext &C,
- const GRState *state,
- const Expr *Ex, SVal V);
+ static const ProgramState *InvalidateBuffer(CheckerContext &C,
+ const ProgramState *state,
+ const Expr *Ex, SVal V);
- static bool SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx,
+ static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
const MemRegion *MR);
// Re-usable checks
- const GRState *checkNonNull(CheckerContext &C, const GRState *state,
- const Expr *S, SVal l) const;
- const GRState *CheckLocation(CheckerContext &C, const GRState *state,
- const Expr *S, SVal l,
- const char *message = NULL) const;
- const GRState *CheckBufferAccess(CheckerContext &C, const GRState *state,
- const Expr *Size,
- const Expr *FirstBuf,
- const Expr *SecondBuf,
- const char *firstMessage = NULL,
- const char *secondMessage = NULL,
- bool WarnAboutSize = false) const;
- const GRState *CheckBufferAccess(CheckerContext &C, const GRState *state,
- const Expr *Size, const Expr *Buf,
- const char *message = NULL,
- bool WarnAboutSize = false) const {
+ const ProgramState *checkNonNull(CheckerContext &C,
+ const ProgramState *state,
+ const Expr *S,
+ SVal l) const;
+ const ProgramState *CheckLocation(CheckerContext &C,
+ const ProgramState *state,
+ const Expr *S,
+ SVal l,
+ const char *message = NULL) const;
+ const ProgramState *CheckBufferAccess(CheckerContext &C,
+ const ProgramState *state,
+ const Expr *Size,
+ const Expr *FirstBuf,
+ const Expr *SecondBuf,
+ const char *firstMessage = NULL,
+ const char *secondMessage = NULL,
+ bool WarnAboutSize = false) const;
+
+ const ProgramState *CheckBufferAccess(CheckerContext &C,
+ const ProgramState *state,
+ const Expr *Size,
+ const Expr *Buf,
+ const char *message = NULL,
+ bool WarnAboutSize = false) const {
// This is a convenience override.
return CheckBufferAccess(C, state, Size, Buf, NULL, message, NULL,
WarnAboutSize);
}
- const GRState *CheckOverlap(CheckerContext &C, const GRState *state,
- const Expr *Size, const Expr *First,
- const Expr *Second) const;
- void emitOverlapBug(CheckerContext &C, const GRState *state,
- const Stmt *First, const Stmt *Second) const;
- const GRState *checkAdditionOverflow(CheckerContext &C, const GRState *state,
- NonLoc left, NonLoc right) const;
+ const ProgramState *CheckOverlap(CheckerContext &C,
+ const ProgramState *state,
+ const Expr *Size,
+ const Expr *First,
+ const Expr *Second) const;
+ void emitOverlapBug(CheckerContext &C,
+ const ProgramState *state,
+ const Stmt *First,
+ const Stmt *Second) const;
+
+ const ProgramState *checkAdditionOverflow(CheckerContext &C,
+ const ProgramState *state,
+ NonLoc left,
+ NonLoc right) const;
};
class CStringLength {
@@ -151,8 +179,8 @@ public:
namespace clang {
namespace ento {
template <>
- struct GRStateTrait<CStringLength>
- : public GRStatePartialTrait<CStringLength::EntryMap> {
+ struct ProgramStateTrait<CStringLength>
+ : public ProgramStatePartialTrait<CStringLength::EntryMap> {
static void *GDMIndex() { return CStringChecker::getTag(); }
};
}
@@ -162,26 +190,26 @@ namespace ento {
// Individual checks and utility methods.
//===----------------------------------------------------------------------===//
-std::pair<const GRState*, const GRState*>
-CStringChecker::assumeZero(CheckerContext &C, const GRState *state, SVal V,
+std::pair<const ProgramState*, const ProgramState*>
+CStringChecker::assumeZero(CheckerContext &C, const ProgramState *state, SVal V,
QualType Ty) {
DefinedSVal *val = dyn_cast<DefinedSVal>(&V);
if (!val)
- return std::pair<const GRState*, const GRState *>(state, state);
+ return std::pair<const ProgramState*, const ProgramState *>(state, state);
SValBuilder &svalBuilder = C.getSValBuilder();
DefinedOrUnknownSVal zero = svalBuilder.makeZeroVal(Ty);
return state->assume(svalBuilder.evalEQ(state, *val, zero));
}
-const GRState *CStringChecker::checkNonNull(CheckerContext &C,
- const GRState *state,
+const ProgramState *CStringChecker::checkNonNull(CheckerContext &C,
+ const ProgramState *state,
const Expr *S, SVal l) const {
// If a previous check has failed, propagate the failure.
if (!state)
return NULL;
- const GRState *stateNull, *stateNonNull;
+ const ProgramState *stateNull, *stateNonNull;
llvm::tie(stateNull, stateNonNull) = assumeZero(C, state, l, S->getType());
if (stateNull && !stateNonNull) {
@@ -200,10 +228,10 @@ const GRState *CStringChecker::checkNonNull(CheckerContext &C,
// Generate a report for this bug.
BuiltinBug *BT = static_cast<BuiltinBug*>(BT_Null.get());
- EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N);
+ BugReport *report = new BugReport(*BT, os.str(), N);
report->addRange(S->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, S);
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, S));
C.EmitReport(report);
return NULL;
}
@@ -214,8 +242,8 @@ const GRState *CStringChecker::checkNonNull(CheckerContext &C,
}
// FIXME: This was originally copied from ArrayBoundChecker.cpp. Refactor?
-const GRState *CStringChecker::CheckLocation(CheckerContext &C,
- const GRState *state,
+const ProgramState *CStringChecker::CheckLocation(CheckerContext &C,
+ const ProgramState *state,
const Expr *S, SVal l,
const char *warningMsg) const {
// If a previous check has failed, propagate the failure.
@@ -244,8 +272,8 @@ const GRState *CStringChecker::CheckLocation(CheckerContext &C,
// Get the index of the accessed element.
DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
- const GRState *StInBound = state->assumeInBound(Idx, Size, true);
- const GRState *StOutBound = state->assumeInBound(Idx, Size, false);
+ const ProgramState *StInBound = state->assumeInBound(Idx, Size, true);
+ const ProgramState *StOutBound = state->assumeInBound(Idx, Size, false);
if (StOutBound && !StInBound) {
ExplodedNode *N = C.generateSink(StOutBound);
if (!N)
@@ -258,9 +286,9 @@ const GRState *CStringChecker::CheckLocation(CheckerContext &C,
BuiltinBug *BT = static_cast<BuiltinBug*>(BT_Bounds.get());
// Generate a report for this bug.
- RangedBugReport *report;
+ BugReport *report;
if (warningMsg) {
- report = new RangedBugReport(*BT, warningMsg, N);
+ report = new BugReport(*BT, warningMsg, N);
} else {
assert(CurrentFunctionDescription);
assert(CurrentFunctionDescription[0] != '\0');
@@ -270,7 +298,7 @@ const GRState *CStringChecker::CheckLocation(CheckerContext &C,
os << (char)toupper(CurrentFunctionDescription[0])
<< &CurrentFunctionDescription[1]
<< " accesses out-of-bound array element";
- report = new RangedBugReport(*BT, os.str(), N);
+ report = new BugReport(*BT, os.str(), N);
}
// FIXME: It would be nice to eventually make this diagnostic more clear,
@@ -287,8 +315,8 @@ const GRState *CStringChecker::CheckLocation(CheckerContext &C,
return StInBound;
}
-const GRState *CStringChecker::CheckBufferAccess(CheckerContext &C,
- const GRState *state,
+const ProgramState *CStringChecker::CheckBufferAccess(CheckerContext &C,
+ const ProgramState *state,
const Expr *Size,
const Expr *FirstBuf,
const Expr *SecondBuf,
@@ -359,8 +387,8 @@ const GRState *CStringChecker::CheckBufferAccess(CheckerContext &C,
return state;
}
-const GRState *CStringChecker::CheckOverlap(CheckerContext &C,
- const GRState *state,
+const ProgramState *CStringChecker::CheckOverlap(CheckerContext &C,
+ const ProgramState *state,
const Expr *Size,
const Expr *First,
const Expr *Second) const {
@@ -372,7 +400,7 @@ const GRState *CStringChecker::CheckOverlap(CheckerContext &C,
if (!state)
return NULL;
- const GRState *stateTrue, *stateFalse;
+ const ProgramState *stateTrue, *stateFalse;
// Get the buffer values and make sure they're known locations.
SVal firstVal = state->getSVal(First);
@@ -470,7 +498,7 @@ const GRState *CStringChecker::CheckOverlap(CheckerContext &C,
return stateFalse;
}
-void CStringChecker::emitOverlapBug(CheckerContext &C, const GRState *state,
+void CStringChecker::emitOverlapBug(CheckerContext &C, const ProgramState *state,
const Stmt *First, const Stmt *Second) const {
ExplodedNode *N = C.generateSink(state);
if (!N)
@@ -480,8 +508,8 @@ void CStringChecker::emitOverlapBug(CheckerContext &C, const GRState *state,
BT_Overlap.reset(new BugType("Unix API", "Improper arguments"));
// Generate a report for this bug.
- RangedBugReport *report =
- new RangedBugReport(*BT_Overlap,
+ BugReport *report =
+ new BugReport(*BT_Overlap,
"Arguments must not be overlapping buffers", N);
report->addRange(First->getSourceRange());
report->addRange(Second->getSourceRange());
@@ -489,8 +517,8 @@ void CStringChecker::emitOverlapBug(CheckerContext &C, const GRState *state,
C.EmitReport(report);
}
-const GRState *CStringChecker::checkAdditionOverflow(CheckerContext &C,
- const GRState *state,
+const ProgramState *CStringChecker::checkAdditionOverflow(CheckerContext &C,
+ const ProgramState *state,
NonLoc left,
NonLoc right) const {
// If a previous check has failed, propagate the failure.
@@ -521,7 +549,7 @@ const GRState *CStringChecker::checkAdditionOverflow(CheckerContext &C,
SVal willOverflow = svalBuilder.evalBinOpNN(state, BO_GT, left,
*maxMinusRightNL, cmpTy);
- const GRState *stateOverflow, *stateOkay;
+ const ProgramState *stateOverflow, *stateOkay;
llvm::tie(stateOverflow, stateOkay) =
state->assume(cast<DefinedOrUnknownSVal>(willOverflow));
@@ -557,7 +585,7 @@ const GRState *CStringChecker::checkAdditionOverflow(CheckerContext &C,
return state;
}
-const GRState *CStringChecker::setCStringLength(const GRState *state,
+const ProgramState *CStringChecker::setCStringLength(const ProgramState *state,
const MemRegion *MR,
SVal strLength) {
assert(!strLength.isUndef() && "Attempt to set an undefined string length");
@@ -598,7 +626,7 @@ const GRState *CStringChecker::setCStringLength(const GRState *state,
}
SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
- const GRState *&state,
+ const ProgramState *&state,
const Expr *Ex,
const MemRegion *MR,
bool hypothetical) {
@@ -610,7 +638,7 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
}
// Otherwise, get a new symbol and update the state.
- unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+ unsigned Count = C.getCurrentBlockCount();
SValBuilder &svalBuilder = C.getSValBuilder();
QualType sizeTy = svalBuilder.getContext().getSizeType();
SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(),
@@ -622,7 +650,7 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
return strLength;
}
-SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state,
+SVal CStringChecker::getCStringLength(CheckerContext &C, const ProgramState *&state,
const Expr *Ex, SVal Buf,
bool hypothetical) const {
const MemRegion *MR = Buf.getAsRegion();
@@ -644,7 +672,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state,
<< "', which is not a null-terminated string";
// Generate a report for this bug.
- EnhancedBugReport *report = new EnhancedBugReport(*BT_NotCString,
+ BugReport *report = new BugReport(*BT_NotCString,
os.str(), N);
report->addRange(Ex->getSourceRange());
@@ -705,7 +733,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state,
os << "not a null-terminated string";
// Generate a report for this bug.
- EnhancedBugReport *report = new EnhancedBugReport(*BT_NotCString,
+ BugReport *report = new BugReport(*BT_NotCString,
os.str(), N);
report->addRange(Ex->getSourceRange());
@@ -717,7 +745,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state,
}
const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C,
- const GRState *&state, const Expr *expr, SVal val) const {
+ const ProgramState *&state, const Expr *expr, SVal val) const {
// Get the memory region pointed to by the val.
const MemRegion *bufRegion = val.getAsRegion();
@@ -736,8 +764,8 @@ const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C,
return strRegion->getStringLiteral();
}
-const GRState *CStringChecker::InvalidateBuffer(CheckerContext &C,
- const GRState *state,
+const ProgramState *CStringChecker::InvalidateBuffer(CheckerContext &C,
+ const ProgramState *state,
const Expr *E, SVal V) {
Loc *L = dyn_cast<Loc>(&V);
if (!L)
@@ -757,8 +785,8 @@ const GRState *CStringChecker::InvalidateBuffer(CheckerContext &C,
}
// Invalidate this region.
- unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
- return state->invalidateRegion(R, E, Count, NULL);
+ unsigned Count = C.getCurrentBlockCount();
+ return state->invalidateRegions(R, E, Count);
}
// If we have a non-region value by chance, just remove the binding.
@@ -767,17 +795,15 @@ const GRState *CStringChecker::InvalidateBuffer(CheckerContext &C,
return state->unbindLoc(*L);
}
-bool CStringChecker::SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx,
+bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
const MemRegion *MR) {
- const TypedRegion *TR = dyn_cast<TypedRegion>(MR);
- if (!TR)
- return false;
+ const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(MR);
- switch (TR->getKind()) {
+ switch (MR->getKind()) {
case MemRegion::FunctionTextRegionKind: {
- const FunctionDecl *FD = cast<FunctionTextRegion>(TR)->getDecl();
+ const FunctionDecl *FD = cast<FunctionTextRegion>(MR)->getDecl();
if (FD)
- os << "the address of the function '" << FD << "'";
+ os << "the address of the function '" << *FD << '\'';
else
os << "the address of a function";
return true;
@@ -790,16 +816,16 @@ bool CStringChecker::SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx,
return true;
case MemRegion::CXXThisRegionKind:
case MemRegion::CXXTempObjectRegionKind:
- os << "a C++ temp object of type " << TR->getValueType().getAsString();
+ os << "a C++ temp object of type " << TVR->getValueType().getAsString();
return true;
case MemRegion::VarRegionKind:
- os << "a variable of type" << TR->getValueType().getAsString();
+ os << "a variable of type" << TVR->getValueType().getAsString();
return true;
case MemRegion::FieldRegionKind:
- os << "a field of type " << TR->getValueType().getAsString();
+ os << "a field of type " << TVR->getValueType().getAsString();
return true;
case MemRegion::ObjCIvarRegionKind:
- os << "an instance variable of type " << TR->getValueType().getAsString();
+ os << "an instance variable of type " << TVR->getValueType().getAsString();
return true;
default:
return false;
@@ -812,7 +838,7 @@ bool CStringChecker::SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx,
void CStringChecker::evalCopyCommon(CheckerContext &C,
const CallExpr *CE,
- const GRState *state,
+ const ProgramState *state,
const Expr *Size, const Expr *Dest,
const Expr *Source, bool Restricted,
bool IsMempcpy) const {
@@ -822,7 +848,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
SVal sizeVal = state->getSVal(Size);
QualType sizeTy = Size->getType();
- const GRState *stateZeroSize, *stateNonZeroSize;
+ const ProgramState *stateZeroSize, *stateNonZeroSize;
llvm::tie(stateZeroSize, stateNonZeroSize) =
assumeZero(C, state, sizeVal, sizeTy);
@@ -887,7 +913,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
} else {
// If we don't know how much we copied, we can at least
// conjure a return value for later.
- unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+ unsigned Count = C.getCurrentBlockCount();
SVal result =
C.getSValBuilder().getConjuredSymbolVal(NULL, CE, Count);
state = state->BindExpr(CE, result);
@@ -914,7 +940,7 @@ void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const {
// void *memcpy(void *restrict dst, const void *restrict src, size_t n);
// The return value is the address of the destination buffer.
const Expr *Dest = CE->getArg(0);
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true);
}
@@ -923,7 +949,7 @@ void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const {
// void *mempcpy(void *restrict dst, const void *restrict src, size_t n);
// The return value is a pointer to the byte following the last written byte.
const Expr *Dest = CE->getArg(0);
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true, true);
}
@@ -932,7 +958,7 @@ void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
// void *memmove(void *dst, const void *src, size_t n);
// The return value is the address of the destination buffer.
const Expr *Dest = CE->getArg(0);
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1));
}
@@ -951,14 +977,14 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
const Expr *Right = CE->getArg(1);
const Expr *Size = CE->getArg(2);
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
SValBuilder &svalBuilder = C.getSValBuilder();
// See if the size argument is zero.
SVal sizeVal = state->getSVal(Size);
QualType sizeTy = Size->getType();
- const GRState *stateZeroSize, *stateNonZeroSize;
+ const ProgramState *stateZeroSize, *stateNonZeroSize;
llvm::tie(stateZeroSize, stateNonZeroSize) =
assumeZero(C, state, sizeVal, sizeTy);
@@ -981,7 +1007,7 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
// See if they are the same.
DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV);
- const GRState *StSameBuf, *StNotSameBuf;
+ const ProgramState *StSameBuf, *StNotSameBuf;
llvm::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
// If the two arguments might be the same buffer, we know the result is 0,
@@ -1002,7 +1028,7 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
state = CheckBufferAccess(C, state, Size, Left, Right);
if (state) {
// The return value is the comparison result, which we don't know.
- unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+ unsigned Count = C.getCurrentBlockCount();
SVal CmpV = svalBuilder.getConjuredSymbolVal(NULL, CE, Count);
state = state->BindExpr(CE, CmpV);
C.addTransition(state);
@@ -1026,13 +1052,13 @@ void CStringChecker::evalstrnLength(CheckerContext &C,
void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
bool IsStrnlen) const {
CurrentFunctionDescription = "string length function";
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
if (IsStrnlen) {
const Expr *maxlenExpr = CE->getArg(1);
SVal maxlenVal = state->getSVal(maxlenExpr);
- const GRState *stateZeroSize, *stateNonZeroSize;
+ const ProgramState *stateZeroSize, *stateNonZeroSize;
llvm::tie(stateZeroSize, stateNonZeroSize) =
assumeZero(C, state, maxlenVal, maxlenExpr->getType());
@@ -1084,7 +1110,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
NonLoc *maxlenValNL = dyn_cast<NonLoc>(&maxlenVal);
if (strLengthNL && maxlenValNL) {
- const GRState *stateStringTooLong, *stateStringNotTooLong;
+ const ProgramState *stateStringTooLong, *stateStringNotTooLong;
// Check if the strLength is greater than the maxlen.
llvm::tie(stateStringTooLong, stateStringNotTooLong) =
@@ -1108,7 +1134,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
// no guarantee the full string length will actually be returned.
// All we know is the return value is the min of the string length
// and the limit. This is better than nothing.
- unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+ unsigned Count = C.getCurrentBlockCount();
result = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, Count);
NonLoc *resultNL = cast<NonLoc>(&result);
@@ -1136,7 +1162,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
// If we don't know the length of the string, conjure a return
// value, so it can be used in constraints, at least.
if (result.isUnknown()) {
- unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+ unsigned Count = C.getCurrentBlockCount();
result = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, Count);
}
}
@@ -1191,7 +1217,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
bool returnEnd, bool isBounded,
bool isAppending) const {
CurrentFunctionDescription = "string copy function";
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
// Check that the destination is non-null.
const Expr *Dst = CE->getArg(0);
@@ -1241,7 +1267,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// If we know both values, we might be able to figure out how much
// we're copying.
if (strLengthNL && lenValNL) {
- const GRState *stateSourceTooLong, *stateSourceNotTooLong;
+ const ProgramState *stateSourceTooLong, *stateSourceNotTooLong;
// 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-
@@ -1480,7 +1506,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// If this is a stpcpy-style copy, but we were unable to check for a buffer
// overflow, we still need a result. Conjure a return value.
if (returnEnd && Result.isUnknown()) {
- unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+ unsigned Count = C.getCurrentBlockCount();
Result = svalBuilder.getConjuredSymbolVal(NULL, CE, Count);
}
@@ -1514,7 +1540,7 @@ void CStringChecker::evalStrncasecmp(CheckerContext &C,
void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
bool isBounded, bool ignoreCase) const {
CurrentFunctionDescription = "string comparison function";
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
// Check that the first string is non-null
const Expr *s1 = CE->getArg(0);
@@ -1549,7 +1575,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
// See if they are the same.
SValBuilder &svalBuilder = C.getSValBuilder();
DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV);
- const GRState *StSameBuf, *StNotSameBuf;
+ const ProgramState *StSameBuf, *StNotSameBuf;
llvm::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
// If the two arguments might be the same buffer, we know the result is 0,
@@ -1575,8 +1601,8 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
bool canComputeResult = false;
if (s1StrLiteral && s2StrLiteral) {
- llvm::StringRef s1StrRef = s1StrLiteral->getString();
- llvm::StringRef s2StrRef = s2StrLiteral->getString();
+ StringRef s1StrRef = s1StrLiteral->getString();
+ StringRef s2StrRef = s2StrLiteral->getString();
if (isBounded) {
// Get the max number of characters to compare.
@@ -1598,11 +1624,11 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
if (canComputeResult) {
// Real strcmp stops at null characters.
size_t s1Term = s1StrRef.find('\0');
- if (s1Term != llvm::StringRef::npos)
+ if (s1Term != StringRef::npos)
s1StrRef = s1StrRef.substr(0, s1Term);
size_t s2Term = s2StrRef.find('\0');
- if (s2Term != llvm::StringRef::npos)
+ if (s2Term != StringRef::npos)
s2StrRef = s2StrRef.substr(0, s2Term);
// Use StringRef's comparison methods to compute the actual result.
@@ -1624,7 +1650,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
if (!canComputeResult) {
// Conjure a symbolic value. It's the best we can do.
- unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+ unsigned Count = C.getCurrentBlockCount();
SVal resultVal = svalBuilder.getConjuredSymbolVal(NULL, CE, Count);
state = state->BindExpr(CE, resultVal);
}
@@ -1640,7 +1666,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
// Get the callee. All the functions we care about are C functions
// with simple identifiers.
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl();
@@ -1651,7 +1677,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
IdentifierInfo *II = FD->getIdentifier();
if (!II) // if no identifier, not a simple C function
return false;
- llvm::StringRef Name = II->getName();
+ StringRef Name = II->getName();
if (Name.startswith("__builtin_"))
Name = Name.substr(10);
@@ -1689,7 +1715,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
// Record string length for char a[] = "abc";
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
for (DeclStmt::const_decl_iterator I = DS->decl_begin(), E = DS->decl_end();
I != E; ++I) {
@@ -1723,16 +1749,16 @@ void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
C.addTransition(state);
}
-bool CStringChecker::wantsRegionChangeUpdate(const GRState *state) const {
+bool CStringChecker::wantsRegionChangeUpdate(const ProgramState *state) const {
CStringLength::EntryMap Entries = state->get<CStringLength>();
return !Entries.isEmpty();
}
-const GRState *
-CStringChecker::checkRegionChanges(const GRState *state,
+const ProgramState *
+CStringChecker::checkRegionChanges(const ProgramState *state,
const StoreManager::InvalidatedSymbols *,
- const MemRegion * const *Begin,
- const MemRegion * const *End) const {
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions) const {
CStringLength::EntryMap Entries = state->get<CStringLength>();
if (Entries.isEmpty())
return state;
@@ -1741,8 +1767,9 @@ CStringChecker::checkRegionChanges(const GRState *state,
llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions;
// First build sets for the changed regions and their super-regions.
- for ( ; Begin != End; ++Begin) {
- const MemRegion *MR = *Begin;
+ for (ArrayRef<const MemRegion *>::iterator
+ I = Regions.begin(), E = Regions.end(); I != E; ++I) {
+ const MemRegion *MR = *I;
Invalidated.insert(MR);
SuperRegions.insert(MR);
@@ -1779,7 +1806,7 @@ CStringChecker::checkRegionChanges(const GRState *state,
return state->set<CStringLength>(Entries);
}
-void CStringChecker::checkLiveSymbols(const GRState *state,
+void CStringChecker::checkLiveSymbols(const ProgramState *state,
SymbolReaper &SR) const {
// Mark all symbols in our string length map as valid.
CStringLength::EntryMap Entries = state->get<CStringLength>();
@@ -1799,7 +1826,7 @@ void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
if (!SR.hasDeadSymbols())
return;
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
CStringLength::EntryMap Entries = state->get<CStringLength>();
if (Entries.isEmpty())
return;
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 6c3dfacec331..4db6ac0181a0 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -16,6 +16,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/AST/ParentMap.h"
#include "clang/Basic/TargetInfo.h"
@@ -47,7 +48,8 @@ private:
void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg,
ExplodedNode *N) const;
- void HandleNilReceiver(CheckerContext &C, const GRState *state,
+ void HandleNilReceiver(CheckerContext &C,
+ const ProgramState *state,
ObjCMessage msg) const;
static void LazyInit_BT(const char *desc, llvm::OwningPtr<BugType> &BT) {
@@ -63,9 +65,9 @@ void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
if (!N)
return;
- EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- bugreporter::GetCalleeExpr(N));
+ BugReport *R = new BugReport(*BT, BT->getName(), N);
+ R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
+ bugreporter::GetCalleeExpr(N)));
C.EmitReport(R);
}
@@ -91,10 +93,10 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
LazyInit_BT(BT_desc, BT);
// Generate a report for this bug.
- EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
+ BugReport *R = new BugReport(*BT, BT->getName(), N);
R->addRange(argRange);
if (argEx)
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, argEx);
+ R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, argEx));
C.EmitReport(R);
}
return true;
@@ -105,7 +107,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
class FindUninitializedField {
public:
- llvm::SmallVector<const FieldDecl *, 10> FieldChain;
+ SmallVector<const FieldDecl *, 10> FieldChain;
private:
ASTContext &C;
StoreManager &StoreMgr;
@@ -116,7 +118,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
MemRegionManager &mrMgr, Store s)
: C(c), StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
- bool Find(const TypedRegion *R) {
+ bool Find(const TypedValueRegion *R) {
QualType T = R->getValueType();
if (const RecordType *RT = T->getAsStructureType()) {
const RecordDecl *RD = RT->getDecl()->getDefinition();
@@ -157,23 +159,23 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
os << "Passed-by-value struct argument contains uninitialized data";
if (F.FieldChain.size() == 1)
- os << " (e.g., field: '" << F.FieldChain[0] << "')";
+ os << " (e.g., field: '" << *F.FieldChain[0] << "')";
else {
os << " (e.g., via the field chain: '";
bool first = true;
- for (llvm::SmallVectorImpl<const FieldDecl *>::iterator
+ for (SmallVectorImpl<const FieldDecl *>::iterator
DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
if (first)
first = false;
else
os << '.';
- os << *DI;
+ os << **DI;
}
os << "')";
}
// Generate a report for this bug.
- EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N);
+ BugReport *R = new BugReport(*BT, os.str(), N);
R->addRange(argRange);
// FIXME: enhance track back for uninitialized value for arbitrary
@@ -216,7 +218,7 @@ void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg,
CheckerContext &C) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
// FIXME: Handle 'super'?
if (const Expr *receiver = msg.getInstanceReceiver()) {
@@ -226,11 +228,11 @@ void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg,
if (!BT_msg_undef)
BT_msg_undef.reset(new BuiltinBug("Receiver in message expression is "
"an uninitialized value"));
- EnhancedBugReport *R =
- new EnhancedBugReport(*BT_msg_undef, BT_msg_undef->getName(), N);
+ BugReport *R =
+ new BugReport(*BT_msg_undef, BT_msg_undef->getName(), N);
R->addRange(receiver->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- receiver);
+ R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
+ receiver));
C.EmitReport(R);
}
return;
@@ -238,7 +240,7 @@ void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg,
// Bifurcate the state into nil and non-nil ones.
DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
- const GRState *notNilState, *nilState;
+ const ProgramState *notNilState, *nilState;
llvm::tie(notNilState, nilState) = state->assume(receiverVal);
// Handle receiver must be nil.
@@ -271,11 +273,11 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
<< "' is nil and returns a value of type '"
<< msg.getType(C.getASTContext()).getAsString() << "' that will be garbage";
- EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
+ BugReport *report = new BugReport(*BT_msg_ret, os.str(), N);
if (const Expr *receiver = msg.getInstanceReceiver()) {
report->addRange(receiver->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- receiver);
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
+ receiver));
}
C.EmitReport(report);
}
@@ -288,7 +290,7 @@ static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
}
void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
- const GRState *state,
+ const ProgramState *state,
ObjCMessage msg) const {
ASTContext &Ctx = C.getASTContext();
@@ -303,7 +305,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
// have the "use of undefined value" be smarter about where the
// undefined value came from.
if (C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())){
- if (ExplodedNode* N = C.generateSink(state))
+ if (ExplodedNode *N = C.generateSink(state))
emitNilReceiverBug(C, msg, N);
return;
}
@@ -322,13 +324,13 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
if (voidPtrSize < returnTypeSize &&
- !(supportsNilWithFloatRet(Ctx.Target.getTriple()) &&
+ !(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 (ExplodedNode *N = C.generateSink(state))
emitNilReceiverBug(C, msg, N);
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
index 585a87d498d3..84a9e6b3c528 100644
--- a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
@@ -44,7 +44,7 @@ void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
if (ToPointeeTy->isIncompleteType())
return;
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
const MemRegion *R = state->getSVal(E).getAsRegion();
if (R == 0)
return;
@@ -72,7 +72,7 @@ void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
BT.reset(new BuiltinBug("Cast region with wrong size.",
"Cast a region whose size is not a multiple of the"
" destination type size."));
- RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(),
+ BugReport *R = new BugReport(*BT, BT->getDescription(),
errorNode);
R->addRange(CE->getSourceRange());
C.EmitReport(R);
diff --git a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
index 3210b0a4bb61..c85521066711 100644
--- a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
@@ -62,7 +62,7 @@ void CastToStructChecker::checkPreStmt(const CastExpr *CE,
"Casting a non-structure type to a structure type "
"and accessing a field can lead to memory access "
"errors or data corruption."));
- RangedBugReport *R = new RangedBugReport(*BT,BT->getDescription(), N);
+ BugReport *R = new BugReport(*BT,BT->getDescription(), N);
R->addRange(CE->getSourceRange());
C.EmitReport(R);
}
diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index 0c693a0bd1b6..c325bb1517f3 100644
--- a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
@@ -27,9 +27,9 @@
using namespace clang;
using namespace ento;
-static bool scan_dealloc(Stmt* S, Selector Dealloc) {
+static bool scan_dealloc(Stmt *S, Selector Dealloc) {
- if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
+ if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S))
if (ME->getSelector() == Dealloc) {
switch (ME->getReceiverKind()) {
case ObjCMessageExpr::Instance: return false;
@@ -48,26 +48,26 @@ static bool scan_dealloc(Stmt* S, Selector Dealloc) {
return false;
}
-static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID,
- const ObjCPropertyDecl* PD,
+static bool scan_ivar_release(Stmt *S, ObjCIvarDecl *ID,
+ const ObjCPropertyDecl *PD,
Selector Release,
IdentifierInfo* SelfII,
- ASTContext& Ctx) {
+ ASTContext &Ctx) {
// [mMyIvar release]
- if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
+ if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S))
if (ME->getSelector() == Release)
if (ME->getInstanceReceiver())
- if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
- if (ObjCIvarRefExpr* E = dyn_cast<ObjCIvarRefExpr>(Receiver))
+ if (Expr *Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
+ if (ObjCIvarRefExpr *E = dyn_cast<ObjCIvarRefExpr>(Receiver))
if (E->getDecl() == ID)
return true;
// [self setMyIvar:nil];
- if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
+ if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S))
if (ME->getInstanceReceiver())
- if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
- if (DeclRefExpr* E = dyn_cast<DeclRefExpr>(Receiver))
+ if (Expr *Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
+ if (DeclRefExpr *E = dyn_cast<DeclRefExpr>(Receiver))
if (E->getDecl()->getIdentifier() == SelfII)
if (ME->getMethodDecl() == PD->getSetterMethodDecl() &&
ME->getNumArgs() == 1 &&
@@ -78,7 +78,7 @@ static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID,
// self.myIvar = nil;
if (BinaryOperator* BO = dyn_cast<BinaryOperator>(S))
if (BO->isAssignmentOp())
- if (ObjCPropertyRefExpr* PRE =
+ if (ObjCPropertyRefExpr *PRE =
dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParenCasts()))
if (PRE->isExplicitProperty() && PRE->getExplicitProperty() == PD)
if (BO->getRHS()->isNullPointerConstant(Ctx,
@@ -96,13 +96,13 @@ static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID,
return false;
}
-static void checkObjCDealloc(const ObjCImplementationDecl* D,
+static void checkObjCDealloc(const ObjCImplementationDecl *D,
const LangOptions& LOpts, BugReporter& BR) {
- assert (LOpts.getGCMode() != LangOptions::GCOnly);
+ assert (LOpts.getGC() != LangOptions::GCOnly);
- ASTContext& Ctx = BR.getContext();
- const ObjCInterfaceDecl* ID = D->getClassInterface();
+ ASTContext &Ctx = BR.getContext();
+ const ObjCInterfaceDecl *ID = D->getClassInterface();
// Does the class contain any ivars that are pointers (or id<...>)?
// If not, skip the check entirely.
@@ -114,7 +114,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl* D,
for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), E=ID->ivar_end();
I!=E; ++I) {
- ObjCIvarDecl* ID = *I;
+ ObjCIvarDecl *ID = *I;
QualType T = ID->getType();
if (!T->isObjCObjectPointerType() ||
@@ -154,7 +154,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl* D,
// Get the "dealloc" selector.
IdentifierInfo* II = &Ctx.Idents.get("dealloc");
Selector S = Ctx.Selectors.getSelector(0, &II);
- ObjCMethodDecl* MD = 0;
+ ObjCMethodDecl *MD = 0;
// Scan the instance methods for "dealloc".
for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(),
@@ -166,9 +166,12 @@ static void checkObjCDealloc(const ObjCImplementationDecl* D,
}
}
+ PathDiagnosticLocation DLoc =
+ PathDiagnosticLocation::createBegin(D, BR.getSourceManager());
+
if (!MD) { // No dealloc found.
- const char* name = LOpts.getGCMode() == LangOptions::NonGC
+ const char* name = LOpts.getGC() == LangOptions::NonGC
? "missing -dealloc"
: "missing -dealloc (Hybrid MM, non-GC)";
@@ -176,14 +179,14 @@ static void checkObjCDealloc(const ObjCImplementationDecl* D,
llvm::raw_string_ostream os(buf);
os << "Objective-C class '" << D << "' lacks a 'dealloc' instance method";
- BR.EmitBasicReport(name, os.str(), D->getLocStart());
+ BR.EmitBasicReport(name, os.str(), DLoc);
return;
}
// dealloc found. Scan for missing [super dealloc].
if (MD->getBody() && !scan_dealloc(MD->getBody(), S)) {
- const char* name = LOpts.getGCMode() == LangOptions::NonGC
+ const char* name = LOpts.getGC() == LangOptions::NonGC
? "missing [super dealloc]"
: "missing [super dealloc] (Hybrid MM, non-GC)";
@@ -193,7 +196,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl* D,
<< "' does not send a 'dealloc' message to its super class"
" (missing [super dealloc])";
- BR.EmitBasicReport(name, os.str(), D->getLocStart());
+ BR.EmitBasicReport(name, os.str(), DLoc);
return;
}
@@ -213,7 +216,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl* D,
if ((*I)->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
continue;
- ObjCIvarDecl* ID = (*I)->getPropertyIvarDecl();
+ ObjCIvarDecl *ID = (*I)->getPropertyIvarDecl();
if (!ID)
continue;
@@ -221,13 +224,13 @@ static void checkObjCDealloc(const ObjCImplementationDecl* D,
if (!T->isObjCObjectPointerType()) // Skip non-pointer ivars
continue;
- const ObjCPropertyDecl* PD = (*I)->getPropertyDecl();
+ const ObjCPropertyDecl *PD = (*I)->getPropertyDecl();
if (!PD)
continue;
// ivars cannot be set via read-only properties, so we'll skip them
if (PD->isReadOnly())
- continue;
+ continue;
// ivar must be released if and only if the kind of setter was not 'assign'
bool requiresRelease = PD->getSetterKind() != ObjCPropertyDecl::Assign;
@@ -240,24 +243,27 @@ static void checkObjCDealloc(const ObjCImplementationDecl* D,
llvm::raw_string_ostream os(buf);
if (requiresRelease) {
- name = LOpts.getGCMode() == LangOptions::NonGC
+ name = LOpts.getGC() == LangOptions::NonGC
? "missing ivar release (leak)"
: "missing ivar release (Hybrid MM, non-GC)";
- os << "The '" << ID
+ os << "The '" << *ID
<< "' instance variable was retained by a synthesized property but "
"wasn't released in 'dealloc'";
} else {
- name = LOpts.getGCMode() == LangOptions::NonGC
+ name = LOpts.getGC() == LangOptions::NonGC
? "extra ivar release (use-after-release)"
: "extra ivar release (Hybrid MM, non-GC)";
- os << "The '" << ID
+ os << "The '" << *ID
<< "' instance variable was not retained by a synthesized property "
"but was released in 'dealloc'";
}
- BR.EmitBasicReport(name, category, os.str(), (*I)->getLocation());
+ PathDiagnosticLocation SDLoc =
+ PathDiagnosticLocation::createBegin((*I), BR.getSourceManager());
+
+ BR.EmitBasicReport(name, category, os.str(), SDLoc);
}
}
}
@@ -272,7 +278,7 @@ class ObjCDeallocChecker : public Checker<
public:
void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr,
BugReporter &BR) const {
- if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)
+ if (mgr.getLangOptions().getGC() == LangOptions::GCOnly)
return;
checkObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR);
}
diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
index fec06a95350e..c076c1e39b08 100644
--- a/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
@@ -28,7 +28,7 @@ using namespace clang;
using namespace ento;
static bool AreTypesCompatible(QualType Derived, QualType Ancestor,
- ASTContext& C) {
+ ASTContext &C) {
// Right now don't compare the compatibility of pointers. That involves
// looking at subtyping relationships. FIXME: Future patch.
@@ -51,36 +51,40 @@ static void CompareReturnTypes(const ObjCMethodDecl *MethDerived,
llvm::raw_string_ostream os(sbuf);
os << "The Objective-C class '"
- << MethDerived->getClassInterface()
+ << *MethDerived->getClassInterface()
<< "', which is derived from class '"
- << MethAncestor->getClassInterface()
+ << *MethAncestor->getClassInterface()
<< "', defines the instance method '"
<< MethDerived->getSelector().getAsString()
<< "' whose return type is '"
<< ResDerived.getAsString()
<< "'. A method with the same name (same selector) is also defined in "
"class '"
- << MethAncestor->getClassInterface()
+ << *MethAncestor->getClassInterface()
<< "' and has a return type of '"
<< ResAncestor.getAsString()
<< "'. These two types are incompatible, and may result in undefined "
"behavior for clients of these classes.";
+ PathDiagnosticLocation MethDLoc =
+ PathDiagnosticLocation::createBegin(MethDerived,
+ BR.getSourceManager());
+
BR.EmitBasicReport("Incompatible instance method return type",
- os.str(), MethDerived->getLocStart());
+ os.str(), MethDLoc);
}
}
-static void CheckObjCInstMethSignature(const ObjCImplementationDecl* ID,
+static void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID,
BugReporter& BR) {
- const ObjCInterfaceDecl* D = ID->getClassInterface();
- const ObjCInterfaceDecl* C = D->getSuperClass();
+ const ObjCInterfaceDecl *D = ID->getClassInterface();
+ const ObjCInterfaceDecl *C = D->getSuperClass();
if (!C)
return;
- ASTContext& Ctx = BR.getContext();
+ ASTContext &Ctx = BR.getContext();
// Build a DenseMap of the methods for quick querying.
typedef llvm::DenseMap<Selector,ObjCMethodDecl*> MapTy;
@@ -90,7 +94,7 @@ static void CheckObjCInstMethSignature(const ObjCImplementationDecl* ID,
for (ObjCImplementationDecl::instmeth_iterator I=ID->instmeth_begin(),
E=ID->instmeth_end(); I!=E; ++I) {
- ObjCMethodDecl* M = *I;
+ ObjCMethodDecl *M = *I;
IMeths[M->getSelector()] = M;
++NumMethods;
}
@@ -101,7 +105,7 @@ static void CheckObjCInstMethSignature(const ObjCImplementationDecl* ID,
for (ObjCInterfaceDecl::instmeth_iterator I=C->instmeth_begin(),
E=C->instmeth_end(); I!=E; ++I) {
- ObjCMethodDecl* M = *I;
+ ObjCMethodDecl *M = *I;
Selector S = M->getSelector();
MapTy::iterator MI = IMeths.find(S);
@@ -110,7 +114,7 @@ static void CheckObjCInstMethSignature(const ObjCImplementationDecl* ID,
continue;
--NumMethods;
- ObjCMethodDecl* MethDerived = MI->second;
+ ObjCMethodDecl *MethDerived = MI->second;
MI->second = 0;
CompareReturnTypes(MethDerived, M, BR, Ctx, ID);
diff --git a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index 53810eed1255..bf7ba185b5aa 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
@@ -12,18 +12,20 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/AST/StmtVisitor.h"
-#include "llvm/Support/raw_ostream.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
static bool isArc4RandomAvailable(const ASTContext &Ctx) {
- const llvm::Triple &T = Ctx.Target.getTriple();
+ const llvm::Triple &T = Ctx.getTargetInfo().getTriple();
return T.getVendor() == llvm::Triple::Apple ||
T.getOS() == llvm::Triple::FreeBSD ||
T.getOS() == llvm::Triple::NetBSD ||
@@ -34,14 +36,16 @@ static bool isArc4RandomAvailable(const ASTContext &Ctx) {
namespace {
class WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
+ AnalysisContext* AC;
enum { num_setids = 6 };
IdentifierInfo *II_setid[num_setids];
const bool CheckRand;
public:
- WalkAST(BugReporter &br) : BR(br), II_setid(),
- CheckRand(isArc4RandomAvailable(BR.getContext())) {}
+ WalkAST(BugReporter &br, AnalysisContext* ac)
+ : BR(br), AC(ac), II_setid(),
+ CheckRand(isArc4RandomAvailable(BR.getContext())) {}
// Statement visitor methods.
void VisitCallExpr(CallExpr *CE);
@@ -52,7 +56,6 @@ public:
void VisitChildren(Stmt *S);
// Helpers.
- IdentifierInfo *getIdentifier(IdentifierInfo *& II, const char *str);
bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD);
typedef void (WalkAST::*FnCheck)(const CallExpr *,
@@ -67,22 +70,12 @@ public:
void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD);
void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD);
void checkCall_random(const CallExpr *CE, const FunctionDecl *FD);
+ void checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD);
void checkUncheckedReturnValue(CallExpr *CE);
};
} // end anonymous namespace
//===----------------------------------------------------------------------===//
-// Helper methods.
-//===----------------------------------------------------------------------===//
-
-IdentifierInfo *WalkAST::getIdentifier(IdentifierInfo *& II, const char *str) {
- if (!II)
- II = &BR.getContext().Idents.get(str);
-
- return II;
-}
-
-//===----------------------------------------------------------------------===//
// AST walking.
//===----------------------------------------------------------------------===//
@@ -103,7 +96,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
IdentifierInfo *II = FD->getIdentifier();
if (!II) // if no identifier, not a simple C function
return;
- llvm::StringRef Name = II->getName();
+ StringRef Name = II->getName();
if (Name.startswith("__builtin_"))
Name = Name.substr(10);
@@ -124,6 +117,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
.Case("rand", &WalkAST::checkCall_rand)
.Case("rand_r", &WalkAST::checkCall_rand)
.Case("random", &WalkAST::checkCall_random)
+ .Case("vfork", &WalkAST::checkCall_vfork)
.Default(NULL);
// If the callee isn't defined, it is not of security concern.
@@ -247,7 +241,7 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
// referenced the compared variable.
const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
- llvm::SmallVector<SourceRange, 2> ranges;
+ SmallVector<SourceRange, 2> ranges;
llvm::SmallString<256> sbuf;
llvm::raw_svector_ostream os(sbuf);
@@ -259,8 +253,11 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
ranges.push_back(drInc->getSourceRange());
const char *bugType = "Floating point variable used as loop counter";
+
+ PathDiagnosticLocation FSLoc =
+ PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC);
BR.EmitBasicReport(bugType, "Security", os.str(),
- FS->getLocStart(), ranges.data(), ranges.size());
+ FSLoc, ranges.data(), ranges.size());
}
//===----------------------------------------------------------------------===//
@@ -290,11 +287,13 @@ void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
// Issue a warning.
SourceRange R = CE->getCallee()->getSourceRange();
+ PathDiagnosticLocation CELoc =
+ PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
BR.EmitBasicReport("Potential buffer overflow in call to 'gets'",
"Security",
"Call to function 'gets' is extremely insecure as it can "
"always result in a buffer overflow",
- CE->getLocStart(), &R, 1);
+ CELoc, &R, 1);
}
//===----------------------------------------------------------------------===//
@@ -326,11 +325,13 @@ void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
// Issue a warning.
SourceRange R = CE->getCallee()->getSourceRange();
+ PathDiagnosticLocation CELoc =
+ PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
BR.EmitBasicReport("Potential buffer overflow in call to 'getpw'",
"Security",
"The getpw() function is dangerous as it may overflow the "
"provided buffer. It is obsoleted by getpwuid().",
- CE->getLocStart(), &R, 1);
+ CELoc, &R, 1);
}
//===----------------------------------------------------------------------===//
@@ -359,11 +360,13 @@ void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
// Issue a waring.
SourceRange R = CE->getCallee()->getSourceRange();
+ PathDiagnosticLocation CELoc =
+ PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
BR.EmitBasicReport("Potential insecure temporary file in call 'mktemp'",
"Security",
"Call to function 'mktemp' is insecure as it always "
"creates or uses insecure temporary file. Use 'mkstemp' instead",
- CE->getLocStart(), &R, 1);
+ CELoc, &R, 1);
}
//===----------------------------------------------------------------------===//
@@ -378,6 +381,8 @@ void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
// Issue a warning.
SourceRange R = CE->getCallee()->getSourceRange();
+ PathDiagnosticLocation CELoc =
+ PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
BR.EmitBasicReport("Potential insecure memory buffer bounds restriction in "
"call 'strcpy'",
"Security",
@@ -385,7 +390,7 @@ void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
"provide bounding of the memory buffer. Replace "
"unbounded copy functions with analogous functions that "
"support length arguments such as 'strncpy'. CWE-119.",
- CE->getLocStart(), &R, 1);
+ CELoc, &R, 1);
}
//===----------------------------------------------------------------------===//
@@ -400,6 +405,8 @@ void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
// Issue a warning.
SourceRange R = CE->getCallee()->getSourceRange();
+ PathDiagnosticLocation CELoc =
+ PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
BR.EmitBasicReport("Potential insecure memory buffer bounds restriction in "
"call 'strcat'",
"Security",
@@ -407,7 +414,7 @@ void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
"provide bounding of the memory buffer. Replace "
"unbounded copy functions with analogous functions that "
"support length arguments such as 'strncat'. CWE-119.",
- CE->getLocStart(), &R, 1);
+ CELoc, &R, 1);
}
//===----------------------------------------------------------------------===//
@@ -470,16 +477,18 @@ void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
// Issue a warning.
llvm::SmallString<256> buf1;
llvm::raw_svector_ostream os1(buf1);
- os1 << '\'' << FD << "' is a poor random number generator";
+ os1 << '\'' << *FD << "' is a poor random number generator";
llvm::SmallString<256> buf2;
llvm::raw_svector_ostream os2(buf2);
- os2 << "Function '" << FD
+ os2 << "Function '" << *FD
<< "' is obsolete because it implements a poor random number generator."
<< " Use 'arc4random' instead";
SourceRange R = CE->getCallee()->getSourceRange();
- BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1);
+ PathDiagnosticLocation CELoc =
+ PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
+ BR.EmitBasicReport(os1.str(), "Security", os2.str(), CELoc, &R, 1);
}
//===----------------------------------------------------------------------===//
@@ -502,11 +511,33 @@ void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
// Issue a warning.
SourceRange R = CE->getCallee()->getSourceRange();
+ PathDiagnosticLocation CELoc =
+ PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
BR.EmitBasicReport("'random' is not a secure random number generator",
"Security",
"The 'random' function produces a sequence of values that "
"an adversary may be able to predict. Use 'arc4random' "
- "instead", CE->getLocStart(), &R, 1);
+ "instead", CELoc, &R, 1);
+}
+
+//===----------------------------------------------------------------------===//
+// Check: 'vfork' should not be used.
+// POS33-C: Do not use vfork().
+//===----------------------------------------------------------------------===//
+
+void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
+ // All calls to vfork() are insecure, issue a warning.
+ SourceRange R = CE->getCallee()->getSourceRange();
+ PathDiagnosticLocation CELoc =
+ PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
+ BR.EmitBasicReport("Potential insecure implementation-specific behavior in "
+ "call 'vfork'",
+ "Security",
+ "Call to function 'vfork' is insecure as it can lead to "
+ "denial of service situations in the parent process. "
+ "Replace calls to vfork with calls to the safer "
+ "'posix_spawn' function",
+ CELoc, &R, 1);
}
//===----------------------------------------------------------------------===//
@@ -557,16 +588,18 @@ void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
// Issue a warning.
llvm::SmallString<256> buf1;
llvm::raw_svector_ostream os1(buf1);
- os1 << "Return value is not checked in call to '" << FD << '\'';
+ os1 << "Return value is not checked in call to '" << *FD << '\'';
llvm::SmallString<256> buf2;
llvm::raw_svector_ostream os2(buf2);
- os2 << "The return value from the call to '" << FD
- << "' is not checked. If an error occurs in '" << FD
+ os2 << "The return value from the call to '" << *FD
+ << "' is not checked. If an error occurs in '" << *FD
<< "', the following code may execute with unexpected privileges";
SourceRange R = CE->getCallee()->getSourceRange();
- BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1);
+ PathDiagnosticLocation CELoc =
+ PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
+ BR.EmitBasicReport(os1.str(), "Security", os2.str(), CELoc, &R, 1);
}
//===----------------------------------------------------------------------===//
@@ -578,7 +611,7 @@ class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
- WalkAST walker(BR);
+ WalkAST walker(BR, mgr.getAnalysisContext(D));
walker.Visit(D->getBody());
}
};
diff --git a/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp b/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
index abf53fd3db28..469be05fb71f 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
@@ -13,9 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/AST/StmtVisitor.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
using namespace clang;
using namespace ento;
@@ -23,9 +24,10 @@ using namespace ento;
namespace {
class WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
+ AnalysisContext* AC;
public:
- WalkAST(BugReporter &br) : BR(br) {}
+ WalkAST(BugReporter &br, AnalysisContext* ac) : BR(br), AC(ac) {}
void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
void VisitStmt(Stmt *S) { VisitChildren(S); }
void VisitChildren(Stmt *S);
@@ -59,11 +61,13 @@ void WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
return;
SourceRange R = ArgEx->getSourceRange();
+ PathDiagnosticLocation ELoc =
+ PathDiagnosticLocation::createBegin(E, BR.getSourceManager(), AC);
BR.EmitBasicReport("Potential unintended use of sizeof() on pointer type",
"Logic",
"The code calls sizeof() on a pointer type. "
"This can produce an unexpected result.",
- E->getLocStart(), &R, 1);
+ ELoc, &R, 1);
}
}
@@ -76,7 +80,7 @@ class SizeofPointerChecker : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
- WalkAST walker(BR);
+ WalkAST walker(BR, mgr.getAnalysisContext(D));
walker.Visit(D->getBody());
}
};
diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td
index 2c196b597b7d..d53e0b887e75 100644
--- a/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -10,41 +10,32 @@
include "clang/StaticAnalyzer/Checkers/CheckerBase.td"
//===----------------------------------------------------------------------===//
-// Groups.
-//===----------------------------------------------------------------------===//
-
-def AllExperimental : CheckerGroup<"all-experimental">;
-
-//===----------------------------------------------------------------------===//
// Packages.
//===----------------------------------------------------------------------===//
+def Experimental : Package<"experimental">;
+
def Core : Package<"core">;
def CoreBuiltin : Package<"builtin">, InPackage<Core>;
def CoreUninitialized : Package<"uninitialized">, InPackage<Core>;
-def CoreExperimental : Package<"experimental">, InPackage<Core>,
- InGroup<AllExperimental>, Hidden;
+def CoreExperimental : Package<"core">, InPackage<Experimental>, Hidden;
def Cplusplus : Package<"cplusplus">;
-def CplusplusExperimental : Package<"experimental">, InPackage<Cplusplus>,
- InGroup<AllExperimental>, Hidden;
+def CplusplusExperimental : Package<"cplusplus">, InPackage<Experimental>, Hidden;
def DeadCode : Package<"deadcode">;
-def DeadCodeExperimental : Package<"experimental">, InPackage<DeadCode>,
- InGroup<AllExperimental>, Hidden;
+def DeadCodeExperimental : Package<"deadcode">, InPackage<Experimental>, Hidden;
def Security : Package <"security">;
-def SecurityExperimental : Package<"experimental">, InPackage<Security>,
- InGroup<AllExperimental>, Hidden;
+def SecurityExperimental : Package<"security">, InPackage<Experimental>, Hidden;
def Unix : Package<"unix">;
-def UnixExperimental : Package<"experimental">, InPackage<Unix>,
- InGroup<AllExperimental>, Hidden;
+def UnixExperimental : Package<"unix">, InPackage<Experimental>, Hidden;
def OSX : Package<"osx">;
+def OSXExperimental : Package<"osx">, InPackage<Experimental>, Hidden;
def Cocoa : Package<"cocoa">, InPackage<OSX>;
-def CocoaExperimental : Package<"experimental">, InPackage<Cocoa>,
- InGroup<AllExperimental>, Hidden;
+def CocoaExperimental : Package<"cocoa">, InPackage<OSXExperimental>, Hidden;
def CoreFoundation : Package<"coreFoundation">, InPackage<OSX>;
def LLVM : Package<"llvm">;
@@ -220,6 +211,10 @@ def ReturnPointerRangeChecker : Checker<"ReturnPtrRange">,
HelpText<"Check for an out-of-bound pointer being returned to callers">,
DescFile<"ReturnPointerRangeChecker.cpp">;
+def MallocOverflowSecurityChecker : Checker<"MallocOverflow">,
+ HelpText<"Check for overflows in the arguments to malloc()">,
+ DescFile<"MallocOverflowSecurityChecker.cpp">;
+
} // end "security.experimental"
//===----------------------------------------------------------------------===//
@@ -274,6 +269,11 @@ def OSAtomicChecker : Checker<"AtomicCAS">,
HelpText<"Evaluate calls to OSAtomic functions">,
DescFile<"OSAtomicChecker.cpp">;
+def MacOSKeychainAPIChecker : Checker<"SecKeychainAPI">,
+ InPackage<OSX>,
+ HelpText<"Check for proper uses of Secure Keychain APIs">,
+ DescFile<"MacOSKeychainAPIChecker.cpp">;
+
} // end "macosx"
let ParentPackage = Cocoa in {
@@ -311,6 +311,10 @@ def NSErrorChecker : Checker<"NSError">,
HelpText<"Check usage of NSError** parameters">,
DescFile<"NSErrorChecker.cpp">;
+def RetainCountChecker : Checker<"RetainCount">,
+ HelpText<"Check for leaks and improper reference count management">,
+ DescFile<"RetainCountChecker.cpp">;
+
} // end "cocoa"
let ParentPackage = CocoaExperimental in {
diff --git a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
index 50b57d1ae497..3c9238190da4 100644
--- a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
@@ -16,8 +16,8 @@
#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/GRState.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "llvm/ADT/ImmutableMap.h"
using namespace clang;
@@ -62,7 +62,7 @@ private:
} // end anonymous namespace
bool ChrootChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
const FunctionDecl *FD = L.getAsFunctionDecl();
@@ -88,8 +88,8 @@ bool ChrootChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
}
void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) const {
- const GRState *state = C.getState();
- GRStateManager &Mgr = state->getStateManager();
+ const ProgramState *state = C.getState();
+ ProgramStateManager &Mgr = state->getStateManager();
// Once encouter a chroot(), set the enum value ROOT_CHANGED directly in
// the GDM.
@@ -98,11 +98,11 @@ void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) const {
}
void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) const {
- const GRState *state = C.getState();
- GRStateManager &Mgr = state->getStateManager();
+ const ProgramState *state = C.getState();
+ ProgramStateManager &Mgr = state->getStateManager();
// If there are no jail state in the GDM, just return.
- const void* k = state->FindGDM(ChrootChecker::getTag());
+ const void *k = state->FindGDM(ChrootChecker::getTag());
if (!k)
return;
@@ -125,7 +125,7 @@ void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) const {
// Check the jail state before any function call except chroot and chdir().
void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
const FunctionDecl *FD = L.getAsFunctionDecl();
@@ -143,7 +143,7 @@ void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
return;
// If jail state is ROOT_CHANGED, generate BugReport.
- void* const* k = state->FindGDM(ChrootChecker::getTag());
+ void *const* k = state->FindGDM(ChrootChecker::getTag());
if (k)
if (isRootChanged((intptr_t) *k))
if (ExplodedNode *N = C.generateNode()) {
diff --git a/lib/StaticAnalyzer/Checkers/ClangCheckers.cpp b/lib/StaticAnalyzer/Checkers/ClangCheckers.cpp
new file mode 100644
index 000000000000..77a5a7226453
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/ClangCheckers.cpp
@@ -0,0 +1,32 @@
+//===--- ClangCheckers.h - Provides builtin checkers ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Checkers/ClangCheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
+
+// FIXME: This is only necessary as long as there are checker registration
+// functions that do additional work besides mgr.registerChecker<CLASS>().
+// The only checkers that currently do this are:
+// - NSAutoreleasePoolChecker
+// - NSErrorChecker
+// - ObjCAtSyncChecker
+// It's probably worth including this information in Checkers.td to minimize
+// boilerplate code.
+#include "ClangSACheckers.h"
+
+using namespace clang;
+using namespace ento;
+
+void ento::registerBuiltinCheckers(CheckerRegistry &registry) {
+#define GET_CHECKERS
+#define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,GROUPINDEX,HIDDEN) \
+ registry.addChecker(register##CLASS, FULLNAME, HELPTEXT);
+#include "Checkers.inc"
+#undef GET_CHECKERS
+}
diff --git a/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp b/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp
deleted file mode 100644
index 291f8e01f4b9..000000000000
--- a/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp
+++ /dev/null
@@ -1,289 +0,0 @@
-//===--- ClangSACheckerProvider.cpp - Clang SA Checkers Provider ----------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Defines the CheckerProvider for the checkers defined in
-// libclangStaticAnalyzerCheckers.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ClangSACheckerProvider.h"
-#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/CheckerProvider.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/ADT/DenseSet.h"
-#include "map"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-
-/// \brief Provider for all the checkers in libclangStaticAnalyzerCheckers.
-class ClangSACheckerProvider : public CheckerProvider {
-public:
- virtual void registerCheckers(CheckerManager &checkerMgr,
- CheckerOptInfo *checkOpts, unsigned numCheckOpts);
- virtual void printHelp(llvm::raw_ostream &OS);
-};
-
-}
-
-CheckerProvider *ento::createClangSACheckerProvider() {
- return new ClangSACheckerProvider();
-}
-
-namespace {
-
-struct StaticCheckerInfoRec {
- const char *FullName;
- void (*RegFunc)(CheckerManager &mgr);
- const char *HelpText;
- int GroupIndex;
- bool Hidden;
-};
-
-struct StaticPackageInfoRec {
- const char *FullName;
- int GroupIndex;
- bool Hidden;
-};
-
-struct StaticGroupInfoRec {
- const char *FullName;
-};
-
-} // end anonymous namespace.
-
-static const StaticPackageInfoRec StaticPackageInfo[] = {
-#define GET_PACKAGES
-#define PACKAGE(FULLNAME, GROUPINDEX, HIDDEN) \
- { FULLNAME, GROUPINDEX, HIDDEN },
-#include "Checkers.inc"
- { 0, -1, 0 }
-#undef PACKAGE
-#undef GET_PACKAGES
-};
-
-static const unsigned NumPackages = sizeof(StaticPackageInfo)
- / sizeof(StaticPackageInfoRec) - 1;
-
-static const StaticGroupInfoRec StaticGroupInfo[] = {
-#define GET_GROUPS
-#define GROUP(FULLNAME) \
- { FULLNAME },
-#include "Checkers.inc"
- { 0 }
-#undef GROUP
-#undef GET_GROUPS
-};
-
-static const unsigned NumGroups = sizeof(StaticGroupInfo)
- / sizeof(StaticGroupInfoRec) - 1;
-
-static const StaticCheckerInfoRec StaticCheckerInfo[] = {
-#define GET_CHECKERS
-#define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,GROUPINDEX,HIDDEN) \
- { FULLNAME, register##CLASS, HELPTEXT, GROUPINDEX, HIDDEN },
-#include "Checkers.inc"
- { 0, 0, 0, -1, 0}
-#undef CHECKER
-#undef GET_CHECKERS
-};
-
-static const unsigned NumCheckers = sizeof(StaticCheckerInfo)
- / sizeof(StaticCheckerInfoRec) - 1;
-
-namespace {
-
-struct CheckNameOption {
- const char *Name;
- const short *Members;
- const short *SubGroups;
- bool Hidden;
-};
-
-} // end anonymous namespace.
-
-#define GET_MEMBER_ARRAYS
-#include "Checkers.inc"
-#undef GET_MEMBER_ARRAYS
-
-// The table of check name options, sorted by name for fast binary lookup.
-static const CheckNameOption CheckNameTable[] = {
-#define GET_CHECKNAME_TABLE
-#include "Checkers.inc"
-#undef GET_CHECKNAME_TABLE
-};
-static const size_t
- CheckNameTableSize = sizeof(CheckNameTable) / sizeof(CheckNameTable[0]);
-
-static bool CheckNameOptionCompare(const CheckNameOption &LHS,
- const CheckNameOption &RHS) {
- return strcmp(LHS.Name, RHS.Name) < 0;
-}
-
-static void collectCheckers(const CheckNameOption *checkName,
- bool enable,
- llvm::DenseSet<const StaticCheckerInfoRec *> &checkers,
- bool collectHidden) {
- if (checkName->Hidden && !collectHidden)
- return;
-
- if (const short *member = checkName->Members) {
- if (enable) {
- for (; *member != -1; ++member)
- if (collectHidden || !StaticCheckerInfo[*member].Hidden)
- checkers.insert(&StaticCheckerInfo[*member]);
- } else {
- for (; *member != -1; ++member)
- checkers.erase(&StaticCheckerInfo[*member]);
- }
- }
-
- // Enable/disable all subgroups along with this one.
- if (const short *subGroups = checkName->SubGroups) {
- for (; *subGroups != -1; ++subGroups) {
- const CheckNameOption *sub = &CheckNameTable[*subGroups];
- collectCheckers(sub, enable, checkers, collectHidden && !sub->Hidden);
- }
- }
-}
-
-static void collectCheckers(CheckerOptInfo &opt,
- llvm::DenseSet<const StaticCheckerInfoRec *> &checkers) {
- const char *optName = opt.getName();
- CheckNameOption key = { optName, 0, 0, false };
- const CheckNameOption *found =
- std::lower_bound(CheckNameTable, CheckNameTable + CheckNameTableSize, key,
- CheckNameOptionCompare);
- if (found == CheckNameTable + CheckNameTableSize ||
- strcmp(found->Name, optName) != 0)
- return; // Check name not found.
-
- opt.claim();
- collectCheckers(found, opt.isEnabled(), checkers, /*collectHidden=*/true);
-}
-
-void ClangSACheckerProvider::registerCheckers(CheckerManager &checkerMgr,
- CheckerOptInfo *checkOpts, unsigned numCheckOpts) {
- llvm::DenseSet<const StaticCheckerInfoRec *> enabledCheckers;
- for (unsigned i = 0; i != numCheckOpts; ++i)
- collectCheckers(checkOpts[i], enabledCheckers);
- for (llvm::DenseSet<const StaticCheckerInfoRec *>::iterator
- I = enabledCheckers.begin(), E = enabledCheckers.end(); I != E; ++I) {
- (*I)->RegFunc(checkerMgr);
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Printing Help.
-//===----------------------------------------------------------------------===//
-
-static void printPackageOption(llvm::raw_ostream &OS) {
- // Find the maximum option length.
- unsigned OptionFieldWidth = 0;
- for (unsigned i = 0; i != NumPackages; ++i) {
- // Limit the amount of padding we are willing to give up for alignment.
- unsigned Length = strlen(StaticPackageInfo[i].FullName);
- if (Length <= 30)
- OptionFieldWidth = std::max(OptionFieldWidth, Length);
- }
-
- const unsigned InitialPad = 2;
- for (unsigned i = 0; i != NumPackages; ++i) {
- const StaticPackageInfoRec &package = StaticPackageInfo[i];
- const std::string &Option = package.FullName;
- int Pad = OptionFieldWidth - int(Option.size());
- OS.indent(InitialPad) << Option;
-
- if (package.GroupIndex != -1 || package.Hidden) {
- // Break on long option names.
- if (Pad < 0) {
- OS << "\n";
- Pad = OptionFieldWidth + InitialPad;
- }
- OS.indent(Pad + 1) << "[";
- if (package.GroupIndex != -1) {
- OS << "Group=" << StaticGroupInfo[package.GroupIndex].FullName;
- if (package.Hidden)
- OS << ", ";
- }
- if (package.Hidden)
- OS << "Hidden";
- OS << "]";
- }
-
- OS << "\n";
- }
-}
-
-typedef std::map<std::string, const StaticCheckerInfoRec *> SortedCheckers;
-
-static void printCheckerOption(llvm::raw_ostream &OS,SortedCheckers &checkers) {
- // Find the maximum option length.
- unsigned OptionFieldWidth = 0;
- for (SortedCheckers::iterator
- I = checkers.begin(), E = checkers.end(); I != E; ++I) {
- // Limit the amount of padding we are willing to give up for alignment.
- unsigned Length = strlen(I->second->FullName);
- if (Length <= 30)
- OptionFieldWidth = std::max(OptionFieldWidth, Length);
- }
-
- const unsigned InitialPad = 2;
- for (SortedCheckers::iterator
- I = checkers.begin(), E = checkers.end(); I != E; ++I) {
- const std::string &Option = I->first;
- const StaticCheckerInfoRec &checker = *I->second;
- int Pad = OptionFieldWidth - int(Option.size());
- OS.indent(InitialPad) << Option;
-
- // Break on long option names.
- if (Pad < 0) {
- OS << "\n";
- Pad = OptionFieldWidth + InitialPad;
- }
- OS.indent(Pad + 1) << checker.HelpText;
-
- if (checker.GroupIndex != -1 || checker.Hidden) {
- OS << " [";
- if (checker.GroupIndex != -1) {
- OS << "Group=" << StaticGroupInfo[checker.GroupIndex].FullName;
- if (checker.Hidden)
- OS << ", ";
- }
- if (checker.Hidden)
- OS << "Hidden";
- OS << "]";
- }
-
- OS << "\n";
- }
-}
-
-void ClangSACheckerProvider::printHelp(llvm::raw_ostream &OS) {
- OS << "USAGE: -analyzer-checker <CHECKER or PACKAGE or GROUP,...>\n";
-
- OS << "\nGROUPS:\n";
- for (unsigned i = 0; i != NumGroups; ++i)
- OS.indent(2) << StaticGroupInfo[i].FullName << "\n";
-
- OS << "\nPACKAGES:\n";
- printPackageOption(OS);
-
- OS << "\nCHECKERS:\n";
-
- // Sort checkers according to their full name.
- SortedCheckers checkers;
- for (unsigned i = 0; i != NumCheckers; ++i)
- checkers[StaticCheckerInfo[i].FullName] = &StaticCheckerInfo[i];
-
- printCheckerOption(OS, checkers);
-}
diff --git a/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.h b/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.h
deleted file mode 100644
index f6c80119fdc0..000000000000
--- a/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.h
+++ /dev/null
@@ -1,29 +0,0 @@
-//===--- ClangSACheckerProvider.h - Clang SA Checkers Provider --*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Defines the entry point for creating the provider for the checkers defined
-// in libclangStaticAnalyzerCheckers.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_SA_CHECKERS_CLANGSACHECKERPROVIDER_H
-#define LLVM_CLANG_SA_CHECKERS_CLANGSACHECKERPROVIDER_H
-
-namespace clang {
-
-namespace ento {
- class CheckerProvider;
-
-CheckerProvider *createClangSACheckerProvider();
-
-} // end ento namespace
-
-} // end clang namespace
-
-#endif
diff --git a/lib/StaticAnalyzer/Checkers/ClangSACheckers.h b/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
index 5524b0f53276..289ce8d8c3ba 100644
--- a/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
+++ b/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
@@ -19,6 +19,7 @@ namespace clang {
namespace ento {
class CheckerManager;
+class CheckerRegistry;
#define GET_CHECKERS
#define CHECKER(FULLNAME,CLASS,CXXFILE,HELPTEXT,GROUPINDEX,HIDDEN) \
diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index ec2a88a55681..901af43c5f26 100644
--- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -50,7 +50,7 @@ void ReachableCode::computeReachableBlocks() {
if (!cfg.getNumBlockIDs())
return;
- llvm::SmallVector<const CFGBlock*, 10> worklist;
+ SmallVector<const CFGBlock*, 10> worklist;
worklist.push_back(&cfg.getEntry());
while (!worklist.empty()) {
@@ -68,12 +68,13 @@ void ReachableCode::computeReachableBlocks() {
}
namespace {
-class DeadStoreObs : public LiveVariables::ObserverTy {
+class DeadStoreObs : public LiveVariables::Observer {
const CFG &cfg;
ASTContext &Ctx;
BugReporter& BR;
+ AnalysisContext* AC;
ParentMap& Parents;
- llvm::SmallPtrSet<VarDecl*, 20> Escaped;
+ llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
llvm::OwningPtr<ReachableCode> reachableCode;
const CFGBlock *currentBlock;
@@ -81,14 +82,15 @@ class DeadStoreObs : public LiveVariables::ObserverTy {
public:
DeadStoreObs(const CFG &cfg, ASTContext &ctx,
- BugReporter& br, ParentMap& parents,
- llvm::SmallPtrSet<VarDecl*, 20> &escaped)
- : cfg(cfg), Ctx(ctx), BR(br), Parents(parents),
+ BugReporter& br, AnalysisContext* ac, ParentMap& parents,
+ llvm::SmallPtrSet<const VarDecl*, 20> &escaped)
+ : cfg(cfg), Ctx(ctx), BR(br), AC(ac), Parents(parents),
Escaped(escaped), currentBlock(0) {}
virtual ~DeadStoreObs() {}
- void Report(VarDecl* V, DeadStoreKind dsk, SourceLocation L, SourceRange R) {
+ void Report(const VarDecl *V, DeadStoreKind dsk,
+ PathDiagnosticLocation L, SourceRange R) {
if (Escaped.count(V))
return;
@@ -102,26 +104,25 @@ public:
if (!reachableCode->isReachable(currentBlock))
return;
- const std::string &name = V->getNameAsString();
-
- const char* BugType = 0;
- std::string msg;
+ llvm::SmallString<64> buf;
+ llvm::raw_svector_ostream os(buf);
+ const char *BugType = 0;
switch (dsk) {
default:
- assert(false && "Impossible dead store type.");
+ llvm_unreachable("Impossible dead store type.");
case DeadInit:
BugType = "Dead initialization";
- msg = "Value stored to '" + name +
- "' during its initialization is never read";
+ os << "Value stored to '" << *V
+ << "' during its initialization is never read";
break;
case DeadIncrement:
BugType = "Dead increment";
case Standard:
if (!BugType) BugType = "Dead assignment";
- msg = "Value stored to '" + name + "' is never read";
+ os << "Value stored to '" << *V << "' is never read";
break;
case Enclosing:
@@ -131,13 +132,12 @@ public:
return;
}
- BR.EmitBasicReport(BugType, "Dead store", msg, L, R);
+ BR.EmitBasicReport(BugType, "Dead store", os.str(), L, R);
}
- void CheckVarDecl(VarDecl* VD, Expr* Ex, Expr* Val,
+ void CheckVarDecl(const VarDecl *VD, const Expr *Ex, const Expr *Val,
DeadStoreKind dsk,
- const LiveVariables::AnalysisDataTy& AD,
- const LiveVariables::ValTy& Live) {
+ const LiveVariables::LivenessValues &Live) {
if (!VD->hasLocalStorage())
return;
@@ -146,30 +146,32 @@ public:
if (VD->getType()->getAs<ReferenceType>())
return;
- if (!Live(VD, AD) &&
- !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>()))
- Report(VD, dsk, Ex->getSourceRange().getBegin(),
- Val->getSourceRange());
+ if (!Live.isLive(VD) &&
+ !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>())) {
+
+ PathDiagnosticLocation ExLoc =
+ PathDiagnosticLocation::createBegin(Ex, BR.getSourceManager(), AC);
+ Report(VD, dsk, ExLoc, Val->getSourceRange());
+ }
}
- void CheckDeclRef(DeclRefExpr* DR, Expr* Val, DeadStoreKind dsk,
- const LiveVariables::AnalysisDataTy& AD,
- const LiveVariables::ValTy& Live) {
- if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
- CheckVarDecl(VD, DR, Val, dsk, AD, Live);
+ void CheckDeclRef(const DeclRefExpr *DR, const Expr *Val, DeadStoreKind dsk,
+ const LiveVariables::LivenessValues& Live) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
+ CheckVarDecl(VD, DR, Val, dsk, Live);
}
- bool isIncrement(VarDecl* VD, BinaryOperator* B) {
+ bool isIncrement(VarDecl *VD, const BinaryOperator* B) {
if (B->isCompoundAssignmentOp())
return true;
- Expr* RHS = B->getRHS()->IgnoreParenCasts();
- BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS);
+ const Expr *RHS = B->getRHS()->IgnoreParenCasts();
+ const BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS);
if (!BRHS)
return false;
- DeclRefExpr *DR;
+ const DeclRefExpr *DR;
if ((DR = dyn_cast<DeclRefExpr>(BRHS->getLHS()->IgnoreParenCasts())))
if (DR->getDecl() == VD)
@@ -182,9 +184,8 @@ public:
return false;
}
- virtual void ObserveStmt(Stmt* S, const CFGBlock *block,
- const LiveVariables::AnalysisDataTy& AD,
- const LiveVariables::ValTy& Live) {
+ virtual void observeStmt(const Stmt *S, const CFGBlock *block,
+ const LiveVariables::LivenessValues &Live) {
currentBlock = block;
@@ -194,10 +195,10 @@ public:
// Only cover dead stores from regular assignments. ++/-- dead stores
// have never flagged a real bug.
- if (BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
+ if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
if (!B->isAssignmentOp()) return; // Skip non-assignments.
- if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()))
+ if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(B->getLHS()))
if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
// Special case: check for assigning null to a pointer.
// This is a common form of defensive programming.
@@ -208,10 +209,10 @@ public:
return;
}
- Expr* RHS = B->getRHS()->IgnoreParenCasts();
+ Expr *RHS = B->getRHS()->IgnoreParenCasts();
// Special case: self-assignments. These are often used to shut up
// "unused variable" compiler warnings.
- if (DeclRefExpr* RhsDR = dyn_cast<DeclRefExpr>(RHS))
+ if (DeclRefExpr *RhsDR = dyn_cast<DeclRefExpr>(RHS))
if (VD == dyn_cast<VarDecl>(RhsDR->getDecl()))
return;
@@ -220,29 +221,29 @@ public:
? Enclosing
: (isIncrement(VD,B) ? DeadIncrement : Standard);
- CheckVarDecl(VD, DR, B->getRHS(), dsk, AD, Live);
+ CheckVarDecl(VD, DR, B->getRHS(), dsk, Live);
}
}
- else if (UnaryOperator* U = dyn_cast<UnaryOperator>(S)) {
+ else if (const UnaryOperator* U = dyn_cast<UnaryOperator>(S)) {
if (!U->isIncrementOp() || U->isPrefix())
return;
- Stmt *parent = Parents.getParentIgnoreParenCasts(U);
+ const Stmt *parent = Parents.getParentIgnoreParenCasts(U);
if (!parent || !isa<ReturnStmt>(parent))
return;
- Expr *Ex = U->getSubExpr()->IgnoreParenCasts();
+ const Expr *Ex = U->getSubExpr()->IgnoreParenCasts();
- if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(Ex))
- CheckDeclRef(DR, U, DeadIncrement, AD, Live);
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex))
+ CheckDeclRef(DR, U, DeadIncrement, Live);
}
- else if (DeclStmt* DS = dyn_cast<DeclStmt>(S))
+ else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S))
// Iterate through the decls. Warn if any initializers are complex
// expressions that are not live (never used).
- for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE=DS->decl_end();
+ for (DeclStmt::const_decl_iterator DI=DS->decl_begin(), DE=DS->decl_end();
DI != DE; ++DI) {
- VarDecl* V = dyn_cast<VarDecl>(*DI);
+ VarDecl *V = dyn_cast<VarDecl>(*DI);
if (!V)
continue;
@@ -253,7 +254,7 @@ public:
if (V->getType()->getAs<ReferenceType>())
return;
- if (Expr* E = V->getInit()) {
+ if (Expr *E = V->getInit()) {
while (ExprWithCleanups *exprClean = dyn_cast<ExprWithCleanups>(E))
E = exprClean->getSubExpr();
@@ -265,7 +266,7 @@ public:
// A dead initialization is a variable that is dead after it
// is initialized. We don't flag warnings for those variables
// marked 'unused'.
- if (!Live(V, AD) && V->getAttr<UnusedAttr>() == 0) {
+ if (!Live.isLive(V) && V->getAttr<UnusedAttr>() == 0) {
// Special case: check for initializations with constants.
//
// e.g. : int x = 0;
@@ -296,7 +297,9 @@ public:
return;
}
- Report(V, DeadInit, V->getLocation(), E->getSourceRange());
+ PathDiagnosticLocation Loc =
+ PathDiagnosticLocation::create(V, BR.getSourceManager());
+ Report(V, DeadInit, Loc, E->getSourceRange());
}
}
}
@@ -318,15 +321,15 @@ public:
CFG& getCFG() { return *cfg; }
- llvm::SmallPtrSet<VarDecl*, 20> Escaped;
+ llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
void VisitUnaryOperator(UnaryOperator* U) {
// Check for '&'. Any VarDecl whose value has its address-taken we
// treat as escaped.
- Expr* E = U->getSubExpr()->IgnoreParenCasts();
+ Expr *E = U->getSubExpr()->IgnoreParenCasts();
if (U->getOpcode() == UO_AddrOf)
- if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E))
- if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
+ if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
Escaped.insert(VD);
return;
}
@@ -345,13 +348,14 @@ class DeadStoresChecker : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
- if (LiveVariables *L = mgr.getLiveVariables(D)) {
+ if (LiveVariables *L = mgr.getAnalysis<LiveVariables>(D)) {
CFG &cfg = *mgr.getCFG(D);
+ AnalysisContext *AC = mgr.getAnalysisContext(D);
ParentMap &pmap = mgr.getParentMap(D);
FindEscaped FS(&cfg);
FS.getCFG().VisitBlockStmts(FS);
- DeadStoreObs A(cfg, BR.getContext(), BR, pmap, FS.Escaped);
- L->runOnAllBlocks(cfg, &A);
+ DeadStoreObs A(cfg, BR.getContext(), BR, AC, pmap, FS.Escaped);
+ L->runOnAllBlocks(A);
}
}
};
diff --git a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
index 486b7f7feb1b..d9d569423d3c 100644
--- a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
+++ b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
@@ -28,7 +28,7 @@ class LiveVariablesDumper : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
- if (LiveVariables* L = mgr.getLiveVariables(D)) {
+ if (LiveVariables* L = mgr.getAnalysis<LiveVariables>(D)) {
L->dumpBlockLiveness(mgr.getSourceManager());
}
}
diff --git a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
index baaf8b3aff8a..eeda734a0766 100644
--- a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
@@ -29,16 +29,17 @@ class DereferenceChecker
mutable llvm::OwningPtr<BuiltinBug> BT_undef;
public:
- void checkLocation(SVal location, bool isLoad, CheckerContext &C) const;
+ void checkLocation(SVal location, bool isLoad, const Stmt* S,
+ CheckerContext &C) const;
- static void AddDerefSource(llvm::raw_ostream &os,
- llvm::SmallVectorImpl<SourceRange> &Ranges,
+ static void AddDerefSource(raw_ostream &os,
+ SmallVectorImpl<SourceRange> &Ranges,
const Expr *Ex, bool loadedFrom = false);
};
} // end anonymous namespace
-void DereferenceChecker::AddDerefSource(llvm::raw_ostream &os,
- llvm::SmallVectorImpl<SourceRange> &Ranges,
+void DereferenceChecker::AddDerefSource(raw_ostream &os,
+ SmallVectorImpl<SourceRange> &Ranges,
const Expr *Ex,
bool loadedFrom) {
Ex = Ex->IgnoreParenLValueCasts();
@@ -65,7 +66,7 @@ void DereferenceChecker::AddDerefSource(llvm::raw_ostream &os,
}
}
-void DereferenceChecker::checkLocation(SVal l, bool isLoad,
+void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
CheckerContext &C) const {
// Check for dereference of an undefined value.
if (l.isUndef()) {
@@ -73,10 +74,10 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad,
if (!BT_undef)
BT_undef.reset(new BuiltinBug("Dereference of undefined pointer value"));
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- bugreporter::GetDerefExpr(N));
+ BugReport *report =
+ new BugReport(*BT_undef, BT_undef->getDescription(), N);
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
+ bugreporter::GetDerefExpr(N)));
C.EmitReport(report);
}
return;
@@ -88,9 +89,8 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad,
if (!isa<Loc>(location))
return;
- const Stmt *S = C.getStmt();
- const GRState *state = C.getState();
- const GRState *notNullState, *nullState;
+ const ProgramState *state = C.getState();
+ const ProgramState *notNullState, *nullState;
llvm::tie(notNullState, nullState) = state->assume(location);
// The explicit NULL case.
@@ -107,7 +107,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad,
BT_null.reset(new BuiltinBug("Dereference of null pointer"));
llvm::SmallString<100> buf;
- llvm::SmallVector<SourceRange, 2> Ranges;
+ SmallVector<SourceRange, 2> Ranges;
// Walk through lvalue casts to get the original expression
// that syntactically caused the load.
@@ -157,15 +157,15 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad,
break;
}
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT_null,
+ BugReport *report =
+ new BugReport(*BT_null,
buf.empty() ? BT_null->getDescription():buf.str(),
N);
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- bugreporter::GetDerefExpr(N));
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
+ bugreporter::GetDerefExpr(N)));
- for (llvm::SmallVectorImpl<SourceRange>::iterator
+ for (SmallVectorImpl<SourceRange>::iterator
I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
report->addRange(*I);
diff --git a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
index 07fb5aa998be..75b7cc47aa79 100644
--- a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
@@ -52,7 +52,7 @@ void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
// Check for divide by zero.
ConstraintManager &CM = C.getConstraintManager();
- const GRState *stateNotZero, *stateZero;
+ const ProgramState *stateNotZero, *stateZero;
llvm::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);
if (stateZero && !stateNotZero) {
@@ -60,11 +60,11 @@ void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
if (!BT)
BT.reset(new BuiltinBug("Division by zero"));
- EnhancedBugReport *R =
- new EnhancedBugReport(*BT, BT->getDescription(), N);
+ BugReport *R =
+ new BugReport(*BT, BT->getDescription(), N);
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- bugreporter::GetDenomExpr(N));
+ R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
+ bugreporter::GetDenomExpr(N)));
C.EmitReport(R);
}
diff --git a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
index d699deecd768..531d87e42631 100644
--- a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
@@ -44,7 +44,7 @@ void FixedAddressChecker::checkPreStmt(const BinaryOperator *B,
if (!T->isPointerType())
return;
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
SVal RV = state->getSVal(B->getRHS());
@@ -57,7 +57,7 @@ void FixedAddressChecker::checkPreStmt(const BinaryOperator *B,
"Using a fixed address is not portable because that "
"address will probably not be valid in all "
"environments or platforms."));
- RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
+ BugReport *R = new BugReport(*BT, BT->getDescription(), N);
R->addRange(B->getRHS()->getSourceRange());
C.EmitReport(R);
}
diff --git a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
index b0c07fc7d264..5c257e595be3 100644
--- a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
@@ -96,10 +96,9 @@ private:
// Hash table and related data structures
struct BinaryOperatorData {
- BinaryOperatorData() : assumption(Possible), analysisContext(0) {}
+ BinaryOperatorData() : assumption(Possible) {}
Assumption assumption;
- AnalysisContext *analysisContext;
ExplodedNodeSet explodedNodes; // Set of ExplodedNodes that refer to a
// BinaryOperator
};
@@ -118,7 +117,6 @@ void IdempotentOperationChecker::checkPreStmt(const BinaryOperator *B,
BinaryOperatorData &Data = hash[B];
Assumption &A = Data.assumption;
AnalysisContext *AC = C.getCurrentAnalysisContext();
- Data.analysisContext = AC;
// If we already have visited this node on a path that does not contain an
// idempotent operation, return immediately.
@@ -143,7 +141,7 @@ void IdempotentOperationChecker::checkPreStmt(const BinaryOperator *B,
|| containsNonLocalVarDecl(RHS);
}
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
SVal LHSVal = state->getSVal(LHS);
SVal RHSVal = state->getSVal(RHS);
@@ -351,9 +349,14 @@ void IdempotentOperationChecker::checkEndAnalysis(ExplodedGraph &G,
// Unpack the hash contents
const BinaryOperatorData &Data = i->second;
const Assumption &A = Data.assumption;
- AnalysisContext *AC = Data.analysisContext;
const ExplodedNodeSet &ES = Data.explodedNodes;
+ // If there are no nodes accosted with the expression, nothing to report.
+ // FIXME: This is possible because the checker does part of processing in
+ // checkPreStmt and part in checkPostStmt.
+ if (ES.begin() == ES.end())
+ continue;
+
const BinaryOperator *B = i->first;
if (A == Impossible)
@@ -363,6 +366,8 @@ void IdempotentOperationChecker::checkEndAnalysis(ExplodedGraph &G,
// warning
if (Eng.hasWorkRemaining()) {
// If we can trace back
+ AnalysisContext *AC = (*ES.begin())->getLocationContext()
+ ->getAnalysisContext();
if (!pathWasCompletelyAnalyzed(AC,
AC->getCFGStmtMap()->getBlock(B),
Eng.getCoreEngine()))
@@ -407,18 +412,18 @@ void IdempotentOperationChecker::checkEndAnalysis(ExplodedGraph &G,
// Add a report for each ExplodedNode
for (ExplodedNodeSet::iterator I = ES.begin(), E = ES.end(); I != E; ++I) {
- EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), *I);
+ BugReport *report = new BugReport(*BT, os.str(), *I);
// Add source ranges and visitor hooks
if (LHSRelevant) {
const Expr *LHS = i->first->getLHS();
report->addRange(LHS->getSourceRange());
- report->addVisitorCreator(bugreporter::registerVarDeclsLastStore, LHS);
+ FindLastStoreBRVisitor::registerStatementVarDecls(*report, LHS);
}
if (RHSRelevant) {
const Expr *RHS = i->first->getRHS();
report->addRange(i->first->getRHS()->getSourceRange());
- report->addVisitorCreator(bugreporter::registerVarDeclsLastStore, RHS);
+ FindLastStoreBRVisitor::registerStatementVarDecls(*report, RHS);
}
BR.EmitReport(report);
diff --git a/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp b/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp
index de6da4f8c377..fbc57d336f90 100644
--- a/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp
@@ -20,7 +20,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Type.h"
@@ -117,16 +117,28 @@ public:
CheckerContext &C) const;
private:
- const GRState *handleAssign(const GRState *state, const Expr *lexp,
- const Expr *rexp, const LocationContext *LC) const;
- const GRState *handleAssign(const GRState *state, const MemRegion *MR,
- const Expr *rexp, const LocationContext *LC) const;
- const GRState *invalidateIterators(const GRState *state, const MemRegion *MR,
- const MemberExpr *ME) const;
+ const ProgramState *handleAssign(const ProgramState *state,
+ const Expr *lexp,
+ const Expr *rexp,
+ const LocationContext *LC) const;
+
+ const ProgramState *handleAssign(const ProgramState *state,
+ const MemRegion *MR,
+ const Expr *rexp,
+ const LocationContext *LC) const;
+
+ const ProgramState *invalidateIterators(const ProgramState *state,
+ const MemRegion *MR,
+ const MemberExpr *ME) const;
+
void checkExpr(CheckerContext &C, const Expr *E) const;
+
void checkArgs(CheckerContext &C, const CallExpr *CE) const;
- const MemRegion *getRegion(const GRState *state, const Expr *E,
- const LocationContext *LC) const;
+
+ const MemRegion *getRegion(const ProgramState *state,
+ const Expr *E,
+ const LocationContext *LC) const;
+
const DeclRefExpr *getDeclRefExpr(const Expr *E) const;
};
@@ -139,8 +151,8 @@ public:
namespace clang {
namespace ento {
template <>
- struct GRStateTrait<IteratorState>
- : public GRStatePartialTrait<IteratorState::EntryMap> {
+ struct ProgramStateTrait<IteratorState>
+ : public ProgramStatePartialTrait<IteratorState::EntryMap> {
static void *GDMIndex() { return IteratorsChecker::getTag(); }
};
}
@@ -162,7 +174,7 @@ static RefKind getTemplateKind(const NamedDecl *td) {
|| nameSpace->getName() != "std")
return NoKind;
- llvm::StringRef name = td->getName();
+ StringRef name = td->getName();
return llvm::StringSwitch<RefKind>(name)
.Cases("vector", "deque", VectorKind)
.Default(NoKind);
@@ -215,7 +227,7 @@ static RefKind getTemplateKind(QualType T) {
// Iterate through our map and invalidate any iterators that were
// initialized fromt the specified instance MemRegion.
-const GRState *IteratorsChecker::invalidateIterators(const GRState *state,
+const ProgramState *IteratorsChecker::invalidateIterators(const ProgramState *state,
const MemRegion *MR, const MemberExpr *ME) const {
IteratorState::EntryMap Map = state->get<IteratorState>();
if (Map.isEmpty())
@@ -234,7 +246,7 @@ const GRState *IteratorsChecker::invalidateIterators(const GRState *state,
}
// Handle assigning to an iterator where we don't have the LValue MemRegion.
-const GRState *IteratorsChecker::handleAssign(const GRState *state,
+const ProgramState *IteratorsChecker::handleAssign(const ProgramState *state,
const Expr *lexp, const Expr *rexp, const LocationContext *LC) const {
// Skip the cast if present.
if (const MaterializeTemporaryExpr *M
@@ -259,7 +271,7 @@ const GRState *IteratorsChecker::handleAssign(const GRState *state,
}
// handle assigning to an iterator
-const GRState *IteratorsChecker::handleAssign(const GRState *state,
+const ProgramState *IteratorsChecker::handleAssign(const ProgramState *state,
const MemRegion *MR, const Expr *rexp, const LocationContext *LC) const {
// Assume unknown until we find something definite.
state = state->set<IteratorState>(MR, RefState::getUnknown());
@@ -287,7 +299,7 @@ const GRState *IteratorsChecker::handleAssign(const GRState *state,
return state;
// Finally, see if it is one of the calls that will create
// a valid iterator and mark it if so, else mark as Unknown.
- llvm::StringRef mName = ME->getMemberDecl()->getName();
+ StringRef mName = ME->getMemberDecl()->getName();
if (llvm::StringSwitch<bool>(mName)
.Cases("begin", "insert", "erase", true).Default(false)) {
@@ -364,7 +376,7 @@ const DeclRefExpr *IteratorsChecker::getDeclRefExpr(const Expr *E) const {
}
// Get the MemRegion associated with the expresssion.
-const MemRegion *IteratorsChecker::getRegion(const GRState *state,
+const MemRegion *IteratorsChecker::getRegion(const ProgramState *state,
const Expr *E, const LocationContext *LC) const {
const DeclRefExpr *DRE = getDeclRefExpr(E);
if (!DRE)
@@ -382,7 +394,7 @@ const MemRegion *IteratorsChecker::getRegion(const GRState *state,
// use those nodes. We also cannot create multiple nodes at one ProgramPoint
// with the same tag.
void IteratorsChecker::checkExpr(CheckerContext &C, const Expr *E) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
const MemRegion *MR = getRegion(state, E,
C.getPredecessor()->getLocationContext());
if (!MR)
@@ -410,7 +422,7 @@ void IteratorsChecker::checkExpr(CheckerContext &C, const Expr *E) const {
"container to its container";
}
- EnhancedBugReport *R = new EnhancedBugReport(*BT_Invalid, msg, N);
+ BugReport *R = new BugReport(*BT_Invalid, msg, N);
R->addRange(getDeclRefExpr(E)->getSourceRange());
C.EmitReport(R);
}
@@ -422,7 +434,7 @@ void IteratorsChecker::checkExpr(CheckerContext &C, const Expr *E) const {
const_cast<IteratorsChecker*>(this)->BT_Undefined =
new BuiltinBug("Use of iterator that is not defined");
- EnhancedBugReport *R = new EnhancedBugReport(*BT_Undefined,
+ BugReport *R = new BugReport(*BT_Undefined,
BT_Undefined->getDescription(), N);
R->addRange(getDeclRefExpr(E)->getSourceRange());
C.EmitReport(R);
@@ -455,7 +467,7 @@ void IteratorsChecker::checkPreStmt(const CXXOperatorCallExpr *OCE,
CheckerContext &C) const
{
const LocationContext *LC = C.getPredecessor()->getLocationContext();
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
OverloadedOperatorKind Kind = OCE->getOperator();
if (Kind == OO_Equal) {
checkExpr(C, OCE->getArg(1));
@@ -491,8 +503,8 @@ void IteratorsChecker::checkPreStmt(const CXXOperatorCallExpr *OCE,
new BuiltinBug(
"Cannot compare iterators from different containers");
- EnhancedBugReport *R = new EnhancedBugReport(*BT_Incompatible,
- BT_Incompatible->getDescription(), N);
+ BugReport *R = new BugReport(*BT_Incompatible,
+ BT_Incompatible->getDescription(), N);
R->addRange(OCE->getSourceRange());
C.EmitReport(R);
}
@@ -505,14 +517,14 @@ void IteratorsChecker::checkPreStmt(const CXXOperatorCallExpr *OCE,
// uninitialized ones as Undefined.
void IteratorsChecker::checkPreStmt(const DeclStmt *DS,
CheckerContext &C) const {
- const Decl* D = *DS->decl_begin();
- const VarDecl* VD = dyn_cast<VarDecl>(D);
+ const Decl *D = *DS->decl_begin();
+ const VarDecl *VD = dyn_cast<VarDecl>(D);
// Only care about iterators.
if (getTemplateKind(VD->getType()) != VectorIteratorKind)
return;
// Get the MemRegion associated with the iterator and mark it as Undefined.
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
Loc VarLoc = state->getLValue(VD, C.getPredecessor()->getLocationContext());
const MemRegion *MR = VarLoc.getAsRegion();
if (!MR)
@@ -520,7 +532,7 @@ void IteratorsChecker::checkPreStmt(const DeclStmt *DS,
state = state->set<IteratorState>(MR, RefState::getUndefined());
// if there is an initializer, handle marking Valid if a proper initializer
- const Expr* InitEx = VD->getInit();
+ const Expr *InitEx = VD->getInit();
if (InitEx) {
// FIXME: This is too syntactic. Since 'InitEx' will be analyzed first
// it should resolve to an SVal that we can check for validity
@@ -544,8 +556,8 @@ void IteratorsChecker::checkPreStmt(const DeclStmt *DS,
namespace { struct CalledReserved {}; }
namespace clang { namespace ento {
-template<> struct GRStateTrait<CalledReserved>
- : public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
+template<> struct ProgramStateTrait<CalledReserved>
+ : public ProgramStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
static void *GDMIndex() { static int index = 0; return &index; }
};
}}
@@ -571,8 +583,8 @@ void IteratorsChecker::checkPreStmt(const CXXMemberCallExpr *MCE,
return;
// If we are calling a function that invalidates iterators, mark them
// appropriately by finding matching instances.
- const GRState *state = C.getState();
- llvm::StringRef mName = ME->getMemberDecl()->getName();
+ const ProgramState *state = C.getState();
+ StringRef mName = ME->getMemberDecl()->getName();
if (llvm::StringSwitch<bool>(mName)
.Cases("insert", "reserve", "push_back", true)
.Cases("erase", "pop_back", "clear", "resize", true)
diff --git a/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp b/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
index 3d1b5e2d1051..e398fcb32257 100644
--- a/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
@@ -32,13 +32,13 @@ static bool IsLLVMStringRef(QualType T) {
if (!RT)
return false;
- return llvm::StringRef(QualType(RT, 0).getAsString()) ==
- "class llvm::StringRef";
+ return StringRef(QualType(RT, 0).getAsString()) ==
+ "class StringRef";
}
/// Check whether the declaration is semantically inside the top-level
/// namespace named by ns.
-static bool InNamespace(const Decl *D, llvm::StringRef NS) {
+static bool InNamespace(const Decl *D, StringRef NS) {
const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext());
if (!ND)
return false;
@@ -109,7 +109,7 @@ static bool IsSmallVector(QualType T) {
}
//===----------------------------------------------------------------------===//
-// CHECK: a llvm::StringRef should not be bound to a temporary std::string whose
+// CHECK: a StringRef should not be bound to a temporary std::string whose
// lifetime is shorter than the StringRef's.
//===----------------------------------------------------------------------===//
@@ -150,7 +150,7 @@ void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) {
return;
// Pattern match for:
- // llvm::StringRef x = call() (where call returns std::string)
+ // StringRef x = call() (where call returns std::string)
if (!IsLLVMStringRef(VD->getType()))
return;
ExprWithCleanups *Ex1 = dyn_cast<ExprWithCleanups>(Init);
@@ -175,9 +175,10 @@ void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) {
// Okay, badness! Report an error.
const char *desc = "StringRef should not be bound to temporary "
"std::string that it outlives";
-
+ PathDiagnosticLocation VDLoc =
+ PathDiagnosticLocation::createBegin(VD, BR.getSourceManager());
BR.EmitBasicReport(desc, "LLVM Conventions", desc,
- VD->getLocStart(), Init->getSourceRange());
+ VDLoc, Init->getSourceRange());
}
//===----------------------------------------------------------------------===//
@@ -210,7 +211,7 @@ static bool IsPartOfAST(const CXXRecordDecl *R) {
namespace {
class ASTFieldVisitor {
- llvm::SmallVector<FieldDecl*, 10> FieldChain;
+ SmallVector<FieldDecl*, 10> FieldChain;
const CXXRecordDecl *Root;
BugReporter &BR;
public:
@@ -260,7 +261,7 @@ void ASTFieldVisitor::ReportError(QualType T) {
if (FieldChain.size() > 1) {
os << " via the following chain: ";
bool isFirst = true;
- for (llvm::SmallVectorImpl<FieldDecl*>::iterator I=FieldChain.begin(),
+ for (SmallVectorImpl<FieldDecl*>::iterator I=FieldChain.begin(),
E=FieldChain.end(); I!=E; ++I) {
if (!isFirst)
os << '.';
@@ -279,8 +280,10 @@ void ASTFieldVisitor::ReportError(QualType T) {
// just report warnings when we see an out-of-line method definition for a
// class, as that heuristic doesn't always work (the complete definition of
// the class may be in the header file, for example).
+ PathDiagnosticLocation L = PathDiagnosticLocation::createBegin(
+ FieldChain.front(), BR.getSourceManager());
BR.EmitBasicReport("AST node allocates heap memory", "LLVM Conventions",
- os.str(), FieldChain.front()->getLocStart());
+ os.str(), L);
}
//===----------------------------------------------------------------------===//
@@ -294,7 +297,7 @@ class LLVMConventionsChecker : public Checker<
public:
void checkASTDecl(const CXXRecordDecl *R, AnalysisManager& mgr,
BugReporter &BR) const {
- if (R->isDefinition())
+ if (R->isCompleteDefinition())
CheckASTMemory(R, BR);
}
diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
new file mode 100644
index 000000000000..2607db80ba8e
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -0,0 +1,632 @@
+//==--- MacOSKeychainAPIChecker.cpp ------------------------------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This checker flags misuses of KeyChainAPI. In particular, the password data
+// allocated/returned by SecKeychainItemCopyContent,
+// SecKeychainFindGenericPassword, SecKeychainFindInternetPassword functions has
+// to be freed using a call to SecKeychainItemFreeContent.
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.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"
+
+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 llvm::OwningPtr<BugType> BT;
+
+public:
+ /// AllocationState is a part of the checker specific state together with the
+ /// MemRegion corresponding to the allocated data.
+ struct AllocationState {
+ /// The index of the allocator function.
+ unsigned int AllocatorIdx;
+ SymbolRef Region;
+
+ AllocationState(const Expr *E, unsigned int Idx, SymbolRef R) :
+ AllocatorIdx(Idx),
+ Region(R) {}
+
+ bool operator==(const AllocationState &X) const {
+ return (AllocatorIdx == X.AllocatorIdx &&
+ Region == X.Region);
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(AllocatorIdx);
+ ID.AddPointer(Region);
+ }
+ };
+
+ 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(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
+
+private:
+ typedef std::pair<SymbolRef, const AllocationState*> AllocationPair;
+ typedef llvm::SmallVector<AllocationPair, 2> AllocationPairVec;
+
+ enum APIKind {
+ /// Denotes functions tracked by this checker.
+ ValidAPI = 0,
+ /// The functions commonly/mistakenly used in place of the given API.
+ ErrorAPI = 1,
+ /// The functions which may allocate the data. These are tracked to reduce
+ /// the false alarm rate.
+ PossibleAPI = 2
+ };
+ /// Stores the information about the allocator and deallocator functions -
+ /// these are the functions the checker is tracking.
+ struct ADFunctionInfo {
+ const char* Name;
+ unsigned int Param;
+ unsigned int DeallocatorIdx;
+ APIKind Kind;
+ };
+ static const unsigned InvalidIdx = 100000;
+ static const unsigned FunctionsToTrackSize = 8;
+ static const ADFunctionInfo FunctionsToTrack[FunctionsToTrackSize];
+ /// The value, which represents no error return value for allocator functions.
+ static const unsigned NoErr = 0;
+
+ /// Given the function name, returns the index of the allocator/deallocator
+ /// function.
+ static unsigned getTrackedFunctionIndex(StringRef Name, bool IsAllocator);
+
+ inline void initBugType() const {
+ if (!BT)
+ BT.reset(new BugType("Improper use of SecKeychain API", "Mac OS API"));
+ }
+
+ void generateDeallocatorMismatchReport(const AllocationPair &AP,
+ const Expr *ArgExpr,
+ CheckerContext &C) const;
+
+ BugReport *generateAllocatedDataNotReleasedReport(const AllocationPair &AP,
+ ExplodedNode *N) const;
+
+ /// Check if RetSym evaluates to an error value in the current state.
+ bool definitelyReturnedError(SymbolRef RetSym,
+ const ProgramState *State,
+ SValBuilder &Builder,
+ bool noError = false) const;
+
+ /// Check if RetSym evaluates to a NoErr value in the current state.
+ bool definitelyDidnotReturnError(SymbolRef RetSym,
+ const ProgramState *State,
+ SValBuilder &Builder) const {
+ return definitelyReturnedError(RetSym, State, Builder, true);
+ }
+
+ /// The bug visitor which allows us to print extra diagnostics along the
+ /// BugReport path. For example, showing the allocation site of the leaked
+ /// region.
+ class SecKeychainBugVisitor : public BugReporterVisitor {
+ protected:
+ // The allocated region symbol tracked by the main analysis.
+ SymbolRef Sym;
+
+ public:
+ SecKeychainBugVisitor(SymbolRef S) : Sym(S) {}
+ virtual ~SecKeychainBugVisitor() {}
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ static int X = 0;
+ ID.AddPointer(&X);
+ ID.AddPointer(Sym);
+ }
+
+ PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR);
+ };
+};
+}
+
+/// ProgramState traits to store the currently allocated (and not yet freed)
+/// symbols. This is a map from the allocated content symbol to the
+/// corresponding AllocationState.
+typedef llvm::ImmutableMap<SymbolRef,
+ MacOSKeychainAPIChecker::AllocationState> AllocatedSetTy;
+
+namespace { struct AllocatedData {}; }
+namespace clang { namespace ento {
+template<> struct ProgramStateTrait<AllocatedData>
+ : public ProgramStatePartialTrait<AllocatedSetTy > {
+ static void *GDMIndex() { static int index = 0; return &index; }
+};
+}}
+
+static bool isEnclosingFunctionParam(const Expr *E) {
+ E = E->IgnoreParenCasts();
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ const ValueDecl *VD = DRE->getDecl();
+ if (isa<ImplicitParamDecl>(VD) || isa<ParmVarDecl>(VD))
+ return true;
+ }
+ return false;
+}
+
+const MacOSKeychainAPIChecker::ADFunctionInfo
+ MacOSKeychainAPIChecker::FunctionsToTrack[FunctionsToTrackSize] = {
+ {"SecKeychainItemCopyContent", 4, 3, ValidAPI}, // 0
+ {"SecKeychainFindGenericPassword", 6, 3, ValidAPI}, // 1
+ {"SecKeychainFindInternetPassword", 13, 3, ValidAPI}, // 2
+ {"SecKeychainItemFreeContent", 1, InvalidIdx, ValidAPI}, // 3
+ {"SecKeychainItemCopyAttributesAndData", 5, 5, ValidAPI}, // 4
+ {"SecKeychainItemFreeAttributesAndData", 1, InvalidIdx, ValidAPI}, // 5
+ {"free", 0, InvalidIdx, ErrorAPI}, // 6
+ {"CFStringCreateWithBytesNoCopy", 1, InvalidIdx, PossibleAPI}, // 7
+};
+
+unsigned MacOSKeychainAPIChecker::getTrackedFunctionIndex(StringRef Name,
+ bool IsAllocator) {
+ for (unsigned I = 0; I < FunctionsToTrackSize; ++I) {
+ ADFunctionInfo FI = FunctionsToTrack[I];
+ if (FI.Name != Name)
+ continue;
+ // Make sure the function is of the right type (allocator vs deallocator).
+ if (IsAllocator && (FI.DeallocatorIdx == InvalidIdx))
+ return InvalidIdx;
+ if (!IsAllocator && (FI.DeallocatorIdx != InvalidIdx))
+ return InvalidIdx;
+
+ return I;
+ }
+ // The function is not tracked.
+ return InvalidIdx;
+}
+
+static SymbolRef getSymbolForRegion(CheckerContext &C,
+ const MemRegion *R) {
+ // Implicit casts (ex: void* -> char*) can turn Symbolic region into element
+ // region, if that is the case, get the underlining region.
+ R = R->StripCasts();
+ if (!isa<SymbolicRegion>(R)) {
+ return 0;
+ }
+ return cast<SymbolicRegion>(R)->getSymbol();
+}
+
+static bool isBadDeallocationArgument(const MemRegion *Arg) {
+ if (isa<AllocaRegion>(Arg) ||
+ isa<BlockDataRegion>(Arg) ||
+ isa<TypedRegion>(Arg)) {
+ return true;
+ }
+ return false;
+}
+/// Given the address expression, retrieve the value it's pointing to. Assume
+/// that value is itself an address, and return the corresponding symbol.
+static SymbolRef getAsPointeeSymbol(const Expr *Expr,
+ CheckerContext &C) {
+ const ProgramState *State = C.getState();
+ SVal ArgV = State->getSVal(Expr);
+
+ if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&ArgV)) {
+ StoreManager& SM = C.getStoreManager();
+ const MemRegion *V = SM.Retrieve(State->getStore(), *X).getAsRegion();
+ if (V)
+ return getSymbolForRegion(C, V);
+ }
+ return 0;
+}
+
+// When checking for error code, we need to consider the following cases:
+// 1) noErr / [0]
+// 2) someErr / [1, inf]
+// 3) unknown
+// If noError, returns true iff (1).
+// If !noError, returns true iff (2).
+bool MacOSKeychainAPIChecker::definitelyReturnedError(SymbolRef RetSym,
+ const ProgramState *State,
+ SValBuilder &Builder,
+ bool noError) const {
+ DefinedOrUnknownSVal NoErrVal = Builder.makeIntVal(NoErr,
+ Builder.getSymbolManager().getType(RetSym));
+ DefinedOrUnknownSVal NoErr = Builder.evalEQ(State, NoErrVal,
+ nonloc::SymbolVal(RetSym));
+ const ProgramState *ErrState = State->assume(NoErr, noError);
+ if (ErrState == State) {
+ return true;
+ }
+
+ return false;
+}
+
+// Report deallocator mismatch. Remove the region from tracking - reporting a
+// missing free error after this one is redundant.
+void MacOSKeychainAPIChecker::
+ generateDeallocatorMismatchReport(const AllocationPair &AP,
+ const Expr *ArgExpr,
+ CheckerContext &C) const {
+ const ProgramState *State = C.getState();
+ State = State->remove<AllocatedData>(AP.first);
+ ExplodedNode *N = C.generateNode(State);
+
+ if (!N)
+ return;
+ initBugType();
+ llvm::SmallString<80> sbuf;
+ llvm::raw_svector_ostream os(sbuf);
+ unsigned int PDeallocIdx =
+ FunctionsToTrack[AP.second->AllocatorIdx].DeallocatorIdx;
+
+ os << "Deallocator doesn't match the allocator: '"
+ << FunctionsToTrack[PDeallocIdx].Name << "' should be used.";
+ BugReport *Report = new BugReport(*BT, os.str(), N);
+ Report->addVisitor(new SecKeychainBugVisitor(AP.first));
+ Report->addRange(ArgExpr->getSourceRange());
+ C.EmitReport(Report);
+}
+
+void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
+ CheckerContext &C) const {
+ const ProgramState *State = C.getState();
+ const Expr *Callee = CE->getCallee();
+ SVal L = State->getSVal(Callee);
+ unsigned idx = InvalidIdx;
+
+ const FunctionDecl *funDecl = L.getAsFunctionDecl();
+ if (!funDecl)
+ return;
+ IdentifierInfo *funI = funDecl->getIdentifier();
+ if (!funI)
+ return;
+ StringRef funName = funI->getName();
+
+ // If it is a call to an allocator function, it could be a double allocation.
+ idx = getTrackedFunctionIndex(funName, true);
+ if (idx != InvalidIdx) {
+ const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
+ if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C))
+ if (const AllocationState *AS = State->get<AllocatedData>(V)) {
+ if (!definitelyReturnedError(AS->Region, State, C.getSValBuilder())) {
+ // Remove the value from the state. The new symbol will be added for
+ // tracking when the second allocator is processed in checkPostStmt().
+ State = State->remove<AllocatedData>(V);
+ ExplodedNode *N = C.generateNode(State);
+ if (!N)
+ return;
+ initBugType();
+ llvm::SmallString<128> sbuf;
+ llvm::raw_svector_ostream os(sbuf);
+ unsigned int DIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx;
+ os << "Allocated data should be released before another call to "
+ << "the allocator: missing a call to '"
+ << FunctionsToTrack[DIdx].Name
+ << "'.";
+ BugReport *Report = new BugReport(*BT, os.str(), N);
+ Report->addVisitor(new SecKeychainBugVisitor(V));
+ Report->addRange(ArgExpr->getSourceRange());
+ C.EmitReport(Report);
+ }
+ }
+ return;
+ }
+
+ // Is it a call to one of deallocator functions?
+ idx = getTrackedFunctionIndex(funName, false);
+ if (idx == InvalidIdx)
+ return;
+
+ // Check the argument to the deallocator.
+ const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
+ SVal ArgSVal = State->getSVal(ArgExpr);
+
+ // Undef is reported by another checker.
+ if (ArgSVal.isUndef())
+ return;
+
+ const MemRegion *Arg = ArgSVal.getAsRegion();
+ if (!Arg)
+ return;
+
+ SymbolRef ArgSM = getSymbolForRegion(C, Arg);
+ bool RegionArgIsBad = ArgSM ? false : isBadDeallocationArgument(Arg);
+ // If the argument is coming from the heap, globals, or unknown, do not
+ // report it.
+ if (!ArgSM && !RegionArgIsBad)
+ return;
+
+ // Is the argument to the call being tracked?
+ const AllocationState *AS = State->get<AllocatedData>(ArgSM);
+ if (!AS && FunctionsToTrack[idx].Kind != ValidAPI) {
+ return;
+ }
+ // If trying to free data which has not been allocated yet, report as a bug.
+ // TODO: We might want a more precise diagnostic for double free
+ // (that would involve tracking all the freed symbols in the checker state).
+ if (!AS || RegionArgIsBad) {
+ // It is possible that this is a false positive - the argument might
+ // have entered as an enclosing function parameter.
+ if (isEnclosingFunctionParam(ArgExpr))
+ return;
+
+ ExplodedNode *N = C.generateNode(State);
+ if (!N)
+ return;
+ initBugType();
+ BugReport *Report = new BugReport(*BT,
+ "Trying to free data which has not been allocated.", N);
+ Report->addRange(ArgExpr->getSourceRange());
+ C.EmitReport(Report);
+ return;
+ }
+
+ // Process functions which might deallocate.
+ if (FunctionsToTrack[idx].Kind == PossibleAPI) {
+
+ if (funName == "CFStringCreateWithBytesNoCopy") {
+ const Expr *DeallocatorExpr = CE->getArg(5)->IgnoreParenCasts();
+ // NULL ~ default deallocator, so warn.
+ if (DeallocatorExpr->isNullPointerConstant(C.getASTContext(),
+ Expr::NPC_ValueDependentIsNotNull)) {
+ const AllocationPair AP = std::make_pair(ArgSM, AS);
+ generateDeallocatorMismatchReport(AP, ArgExpr, C);
+ return;
+ }
+ // One of the default allocators, so warn.
+ if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(DeallocatorExpr)) {
+ StringRef DeallocatorName = DE->getFoundDecl()->getName();
+ if (DeallocatorName == "kCFAllocatorDefault" ||
+ DeallocatorName == "kCFAllocatorSystemDefault" ||
+ DeallocatorName == "kCFAllocatorMalloc") {
+ const AllocationPair AP = std::make_pair(ArgSM, AS);
+ generateDeallocatorMismatchReport(AP, ArgExpr, C);
+ 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);
+ return;
+ }
+ }
+ }
+ return;
+ }
+
+ // The call is deallocating a value we previously allocated, so remove it
+ // from the next state.
+ State = State->remove<AllocatedData>(ArgSM);
+
+ // Check if the proper deallocator is used.
+ unsigned int PDeallocIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx;
+ if (PDeallocIdx != idx || (FunctionsToTrack[idx].Kind == ErrorAPI)) {
+ const AllocationPair AP = std::make_pair(ArgSM, AS);
+ generateDeallocatorMismatchReport(AP, ArgExpr, C);
+ return;
+ }
+
+ // If the return status is undefined or is error, report a bad call to free.
+ if (!definitelyDidnotReturnError(AS->Region, State, C.getSValBuilder())) {
+ ExplodedNode *N = C.generateNode(State);
+ if (!N)
+ return;
+ initBugType();
+ BugReport *Report = new BugReport(*BT,
+ "Call to free data when error was returned during allocation.", N);
+ Report->addVisitor(new SecKeychainBugVisitor(ArgSM));
+ Report->addRange(ArgExpr->getSourceRange());
+ C.EmitReport(Report);
+ return;
+ }
+
+ C.addTransition(State);
+}
+
+void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE,
+ CheckerContext &C) const {
+ const ProgramState *State = C.getState();
+ const Expr *Callee = CE->getCallee();
+ SVal L = State->getSVal(Callee);
+
+ const FunctionDecl *funDecl = L.getAsFunctionDecl();
+ if (!funDecl)
+ return;
+ IdentifierInfo *funI = funDecl->getIdentifier();
+ if (!funI)
+ return;
+ StringRef funName = funI->getName();
+
+ // If a value has been allocated, add it to the set for tracking.
+ unsigned idx = getTrackedFunctionIndex(funName, true);
+ if (idx == InvalidIdx)
+ return;
+
+ const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
+ // If the argument entered as an enclosing function parameter, skip it to
+ // avoid false positives.
+ if (isEnclosingFunctionParam(ArgExpr))
+ return;
+
+ if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C)) {
+ // If the argument points to something that's not a symbolic region, it
+ // can be:
+ // - unknown (cannot reason about it)
+ // - undefined (already reported by other checker)
+ // - constant (null - should not be tracked,
+ // other constant will generate a compiler warning)
+ // - goto (should be reported by other checker)
+
+ // The call return value symbol should stay alive for as long as the
+ // allocated value symbol, since our diagnostics depend on the value
+ // returned by the call. Ex: Data should only be freed if noErr was
+ // returned during allocation.)
+ SymbolRef RetStatusSymbol = State->getSVal(CE).getAsSymbol();
+ C.getSymbolManager().addSymbolDependency(V, RetStatusSymbol);
+
+ // Track the allocated value in the checker state.
+ State = State->set<AllocatedData>(V, AllocationState(ArgExpr, idx,
+ RetStatusSymbol));
+ assert(State);
+ C.addTransition(State);
+ }
+}
+
+void MacOSKeychainAPIChecker::checkPreStmt(const ReturnStmt *S,
+ CheckerContext &C) const {
+ const Expr *retExpr = S->getRetValue();
+ if (!retExpr)
+ return;
+
+ // Check if the value is escaping through the return.
+ const ProgramState *state = C.getState();
+ const MemRegion *V = state->getSVal(retExpr).getAsRegion();
+ if (!V)
+ return;
+ state = state->remove<AllocatedData>(getSymbolForRegion(C, V));
+
+ // Proceed from the new state.
+ C.addTransition(state);
+}
+
+BugReport *MacOSKeychainAPIChecker::
+ generateAllocatedDataNotReleasedReport(const AllocationPair &AP,
+ ExplodedNode *N) const {
+ const ADFunctionInfo &FI = FunctionsToTrack[AP.second->AllocatorIdx];
+ initBugType();
+ llvm::SmallString<70> sbuf;
+ llvm::raw_svector_ostream os(sbuf);
+
+ os << "Allocated data is not released: missing a call to '"
+ << FunctionsToTrack[FI.DeallocatorIdx].Name << "'.";
+ BugReport *Report = new BugReport(*BT, os.str(), N);
+ Report->addVisitor(new SecKeychainBugVisitor(AP.first));
+ Report->addRange(SourceRange());
+ return Report;
+}
+
+void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
+ CheckerContext &C) const {
+ const ProgramState *State = C.getState();
+ AllocatedSetTy ASet = State->get<AllocatedData>();
+ if (ASet.isEmpty())
+ return;
+
+ bool Changed = false;
+ AllocationPairVec Errors;
+ for (AllocatedSetTy::iterator I = ASet.begin(), E = ASet.end(); I != E; ++I) {
+ if (SR.isLive(I->first))
+ continue;
+
+ Changed = true;
+ State = State->remove<AllocatedData>(I->first);
+ // If the allocated symbol is null or if the allocation call might have
+ // returned an error, do not report.
+ if (State->getSymVal(I->first) ||
+ definitelyReturnedError(I->second.Region, State, C.getSValBuilder()))
+ continue;
+ Errors.push_back(std::make_pair(I->first, &I->second));
+ }
+ if (!Changed)
+ return;
+
+ // Generate the new, cleaned up state.
+ ExplodedNode *N = C.generateNode(State);
+ if (!N)
+ return;
+
+ // Generate the error reports.
+ for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end();
+ I != E; ++I) {
+ C.EmitReport(generateAllocatedDataNotReleasedReport(*I, N));
+ }
+}
+
+// TODO: Remove this after we ensure that checkDeadSymbols are always called.
+void MacOSKeychainAPIChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
+ ExprEngine &Eng) const {
+ const ProgramState *state = B.getState();
+ AllocatedSetTy 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 (AllocatedSetTy::iterator I = AS.begin(), E = AS.end(); I != E; ++I ) {
+ Changed = true;
+ state = state->remove<AllocatedData>(I->first);
+ // If the allocated symbol is null or if error code was returned at
+ // allocation, do not report.
+ if (state->getSymVal(I.getKey()) ||
+ definitelyReturnedError(I->second.Region, state,
+ Eng.getSValBuilder())) {
+ continue;
+ }
+ Errors.push_back(std::make_pair(I->first, &I->second));
+ }
+
+ // If no change, do not generate a new state.
+ if (!Changed)
+ return;
+
+ ExplodedNode *N = B.generateNode(state);
+ if (!N)
+ return;
+
+ // Generate the error reports.
+ for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end();
+ I != E; ++I) {
+ Eng.getBugReporter().EmitReport(
+ generateAllocatedDataNotReleasedReport(*I, N));
+ }
+}
+
+
+PathDiagnosticPiece *MacOSKeychainAPIChecker::SecKeychainBugVisitor::VisitNode(
+ const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+ const AllocationState *AS = N->getState()->get<AllocatedData>(Sym);
+ if (!AS)
+ return 0;
+ const AllocationState *ASPrev = PrevN->getState()->get<AllocatedData>(Sym);
+ if (ASPrev)
+ return 0;
+
+ // (!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 FunctionDecl *funDecl = CE->getDirectCallee();
+ assert(funDecl && "We do not support indirect function calls as of now.");
+ StringRef funName = funDecl->getName();
+
+ // Get the expression of the corresponding argument.
+ unsigned Idx = getTrackedFunctionIndex(funName, true);
+ assert(Idx != InvalidIdx && "This should be a call to an allocator.");
+ const Expr *ArgExpr = CE->getArg(FunctionsToTrack[Idx].Param);
+ PathDiagnosticLocation Pos(ArgExpr, BRC.getSourceManager(),
+ N->getLocationContext());
+ return new PathDiagnosticEventPiece(Pos, "Data is allocated here.");
+}
+
+void ento::registerMacOSKeychainAPIChecker(CheckerManager &mgr) {
+ mgr.registerChecker<MacOSKeychainAPIChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index f8d076b54e3d..88d492e8d9a2 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -20,7 +20,7 @@
#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/GRStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
@@ -56,7 +56,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
// Check if the first argument is stack allocated. If so, issue a warning
// because that's likely to be bad news.
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
return;
@@ -81,7 +81,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
os << " Perhaps you intended to declare the variable as 'static'?";
- RangedBugReport *report = new RangedBugReport(*BT_dispatchOnce, os.str(), N);
+ BugReport *report = new BugReport(*BT_dispatchOnce, os.str(), N);
report->addRange(CE->getArg(0)->getSourceRange());
C.EmitReport(report);
}
@@ -94,7 +94,7 @@ void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE,
CheckerContext &C) const {
// FIXME: This sort of logic is common to several checkers, including
// UnixAPIChecker, PthreadLockChecker, and CStringChecker. Should refactor.
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
const FunctionDecl *Fn = state->getSVal(Callee).getAsFunctionDecl();
diff --git a/lib/StaticAnalyzer/Checkers/Makefile b/lib/StaticAnalyzer/Checkers/Makefile
index 97f46424e472..2582908b95d0 100644
--- a/lib/StaticAnalyzer/Checkers/Makefile
+++ b/lib/StaticAnalyzer/Checkers/Makefile
@@ -19,6 +19,6 @@ TABLEGEN_INC_FILES_COMMON = 1
include $(CLANG_LEVEL)/Makefile
-$(ObjDir)/Checkers.inc.tmp : Checkers.td $(PROJ_SRC_DIR)/$(CLANG_LEVEL)/include/clang/StaticAnalyzer/Checkers/CheckerBase.td $(TBLGEN) $(ObjDir)/.dir
+$(ObjDir)/Checkers.inc.tmp : Checkers.td $(PROJ_SRC_DIR)/$(CLANG_LEVEL)/include/clang/StaticAnalyzer/Checkers/CheckerBase.td $(CLANG_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang SA Checkers tables with tblgen"
- $(Verb) $(TableGen) -gen-clang-sa-checkers -I $(PROJ_SRC_DIR)/$(CLANG_LEVEL)/include -o $(call SYSPATH, $@) $<
+ $(Verb) $(ClangTableGen) -gen-clang-sa-checkers -I $(PROJ_SRC_DIR)/$(CLANG_LEVEL)/include -o $(call SYSPATH, $@) $<
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 91002158c57f..5631802b7c34 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -17,8 +17,8 @@
#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/GRState.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "llvm/ADT/ImmutableMap.h"
using namespace clang;
@@ -80,35 +80,37 @@ public:
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
- const GRState *evalAssume(const GRState *state, SVal Cond,
+ const ProgramState *evalAssume(const ProgramState *state, SVal Cond,
bool Assumption) const;
- void checkLocation(SVal l, bool isLoad, CheckerContext &C) const;
- void checkBind(SVal location, SVal val, CheckerContext &C) 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;
private:
static void MallocMem(CheckerContext &C, const CallExpr *CE);
static void MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
const OwnershipAttr* Att);
- static const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
+ static const ProgramState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
const Expr *SizeEx, SVal Init,
- const GRState *state) {
+ const ProgramState *state) {
return MallocMemAux(C, CE, state->getSVal(SizeEx), Init, state);
}
- static const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
+ static const ProgramState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
SVal SizeEx, SVal Init,
- const GRState *state);
+ const ProgramState *state);
void FreeMem(CheckerContext &C, const CallExpr *CE) const;
void FreeMemAttr(CheckerContext &C, const CallExpr *CE,
const OwnershipAttr* Att) const;
- const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE,
- const GRState *state, unsigned Num, bool Hold) const;
+ const ProgramState *FreeMemAux(CheckerContext &C, const CallExpr *CE,
+ const ProgramState *state, unsigned Num, bool Hold) const;
void ReallocMem(CheckerContext &C, const CallExpr *CE) const;
static void CallocMem(CheckerContext &C, const CallExpr *CE);
- static bool SummarizeValue(llvm::raw_ostream& os, SVal V);
- static bool SummarizeRegion(llvm::raw_ostream& os, const MemRegion *MR);
+ 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;
};
} // end anonymous namespace
@@ -118,15 +120,15 @@ typedef llvm::ImmutableMap<SymbolRef, RefState> RegionStateTy;
namespace clang {
namespace ento {
template <>
- struct GRStateTrait<RegionState>
- : public GRStatePartialTrait<RegionStateTy> {
+ struct ProgramStateTrait<RegionState>
+ : public ProgramStatePartialTrait<RegionStateTy> {
static void *GDMIndex() { static int x; return &x; }
};
}
}
bool MallocChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
@@ -193,7 +195,7 @@ bool MallocChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
}
void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(),
+ const ProgramState *state = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(),
C.getState());
C.addTransition(state);
}
@@ -205,21 +207,21 @@ void MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
if (I != E) {
- const GRState *state =
+ const ProgramState *state =
MallocMemAux(C, CE, CE->getArg(*I), UndefinedVal(), C.getState());
C.addTransition(state);
return;
}
- const GRState *state = MallocMemAux(C, CE, UnknownVal(), UndefinedVal(),
+ const ProgramState *state = MallocMemAux(C, CE, UnknownVal(), UndefinedVal(),
C.getState());
C.addTransition(state);
}
-const GRState *MallocChecker::MallocMemAux(CheckerContext &C,
+const ProgramState *MallocChecker::MallocMemAux(CheckerContext &C,
const CallExpr *CE,
SVal Size, SVal Init,
- const GRState *state) {
- unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+ const ProgramState *state) {
+ unsigned Count = C.getCurrentBlockCount();
SValBuilder &svalBuilder = C.getSValBuilder();
// Set the return value.
@@ -247,7 +249,7 @@ const GRState *MallocChecker::MallocMemAux(CheckerContext &C,
}
void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) const {
- const GRState *state = FreeMemAux(C, CE, C.getState(), 0, false);
+ const ProgramState *state = FreeMemAux(C, CE, C.getState(), 0, false);
if (state)
C.addTransition(state);
@@ -260,15 +262,15 @@ void MallocChecker::FreeMemAttr(CheckerContext &C, const CallExpr *CE,
for (OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
I != E; ++I) {
- const GRState *state = FreeMemAux(C, CE, C.getState(), *I,
+ const ProgramState *state = FreeMemAux(C, CE, C.getState(), *I,
Att->getOwnKind() == OwnershipAttr::Holds);
if (state)
C.addTransition(state);
}
}
-const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
- const GRState *state, unsigned Num,
+const ProgramState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
+ const ProgramState *state, unsigned Num,
bool Hold) const {
const Expr *ArgExpr = CE->getArg(Num);
SVal ArgVal = state->getSVal(ArgExpr);
@@ -281,7 +283,7 @@ const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
// FIXME: Technically using 'Assume' here can result in a path
// bifurcation. In such cases we need to return two states, not just one.
- const GRState *notNullState, *nullState;
+ const ProgramState *notNullState, *nullState;
llvm::tie(notNullState, nullState) = state->assume(location);
// The explicit NULL case, no operation is performed.
@@ -364,7 +366,7 @@ const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
return notNullState->set<RegionState>(Sym, RefState::getReleased(CE));
}
-bool MallocChecker::SummarizeValue(llvm::raw_ostream& os, SVal V) {
+bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
if (nonloc::ConcreteInt *IntVal = dyn_cast<nonloc::ConcreteInt>(&V))
os << "an integer (" << IntVal->getValue() << ")";
else if (loc::ConcreteInt *ConstAddr = dyn_cast<loc::ConcreteInt>(&V))
@@ -377,13 +379,13 @@ bool MallocChecker::SummarizeValue(llvm::raw_ostream& os, SVal V) {
return true;
}
-bool MallocChecker::SummarizeRegion(llvm::raw_ostream& os,
+bool MallocChecker::SummarizeRegion(raw_ostream &os,
const MemRegion *MR) {
switch (MR->getKind()) {
case MemRegion::FunctionTextRegionKind: {
const FunctionDecl *FD = cast<FunctionTextRegion>(MR)->getDecl();
if (FD)
- os << "the address of the function '" << FD << "'";
+ os << "the address of the function '" << *FD << '\'';
else
os << "the address of a function";
return true;
@@ -484,14 +486,14 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
os << "not memory allocated by malloc()";
}
- EnhancedBugReport *R = new EnhancedBugReport(*BT_BadFree, os.str(), N);
+ BugReport *R = new BugReport(*BT_BadFree, os.str(), N);
R->addRange(range);
C.EmitReport(R);
}
}
void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
const Expr *arg0Expr = CE->getArg(0);
DefinedOrUnknownSVal arg0Val
= cast<DefinedOrUnknownSVal>(state->getSVal(arg0Expr));
@@ -517,7 +519,7 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
// If the ptr is NULL and the size is not 0, the call is equivalent to
// malloc(size).
- const GRState *stateEqual = state->assume(PtrEQ, true);
+ const ProgramState *stateEqual = state->assume(PtrEQ, true);
if (stateEqual && state->assume(SizeZero, false)) {
// Hack: set the NULL symbolic region to released to suppress false warning.
// In the future we should add more states for allocated regions, e.g.,
@@ -527,28 +529,25 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
if (Sym)
stateEqual = stateEqual->set<RegionState>(Sym, RefState::getReleased(CE));
- const GRState *stateMalloc = MallocMemAux(C, CE, CE->getArg(1),
+ const ProgramState *stateMalloc = MallocMemAux(C, CE, CE->getArg(1),
UndefinedVal(), stateEqual);
C.addTransition(stateMalloc);
}
- if (const GRState *stateNotEqual = state->assume(PtrEQ, false)) {
+ if (const ProgramState *stateNotEqual = state->assume(PtrEQ, false)) {
// If the size is 0, free the memory.
- if (const GRState *stateSizeZero = stateNotEqual->assume(SizeZero, true))
- if (const GRState *stateFree =
+ if (const ProgramState *stateSizeZero = stateNotEqual->assume(SizeZero, true))
+ if (const ProgramState *stateFree =
FreeMemAux(C, CE, stateSizeZero, 0, false)) {
- // Add the state transition to set input pointer argument to be free.
- C.addTransition(stateFree);
-
- // Bind the return value to UndefinedVal because it is now free.
- C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true));
+ // Bind the return value to NULL because it is now free.
+ C.addTransition(stateFree->BindExpr(CE, svalBuilder.makeNull(), true));
}
- if (const GRState *stateSizeNotZero = stateNotEqual->assume(SizeZero,false))
- if (const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero,
+ if (const ProgramState *stateSizeNotZero = stateNotEqual->assume(SizeZero,false))
+ if (const ProgramState *stateFree = FreeMemAux(C, CE, stateSizeNotZero,
0, false)) {
// FIXME: We should copy the content of the original buffer.
- const GRState *stateRealloc = MallocMemAux(C, CE, CE->getArg(1),
+ const ProgramState *stateRealloc = MallocMemAux(C, CE, CE->getArg(1),
UnknownVal(), stateFree);
C.addTransition(stateRealloc);
}
@@ -556,7 +555,7 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
}
void MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
SValBuilder &svalBuilder = C.getSValBuilder();
SVal count = state->getSVal(CE->getArg(0));
@@ -574,33 +573,40 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
if (!SymReaper.hasDeadSymbols())
return;
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
RegionStateTy RS = state->get<RegionState>();
RegionStateTy::Factory &F = state->get_context<RegionState>();
+ bool generateReport = false;
+
for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
if (SymReaper.isDead(I->first)) {
- if (I->second.isAllocated()) {
- if (ExplodedNode *N = C.generateNode()) {
- if (!BT_Leak)
- BT_Leak.reset(new BuiltinBug("Memory leak",
- "Allocated memory never released. Potential memory leak."));
- // FIXME: where it is allocated.
- BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
- C.EmitReport(R);
- }
- }
+ if (I->second.isAllocated())
+ generateReport = true;
// Remove the dead symbol from the map.
RS = F.remove(RS, I->first);
+
}
}
- C.generateNode(state->set<RegionState>(RS));
+
+ ExplodedNode *N = C.generateNode(state->set<RegionState>(RS));
+
+ // FIXME: This does not handle when we have multiple leaks at a single
+ // place.
+ if (N && generateReport) {
+ if (!BT_Leak)
+ BT_Leak.reset(new BuiltinBug("Memory leak",
+ "Allocated memory never released. Potential memory leak."));
+ // FIXME: where it is allocated.
+ BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
+ C.EmitReport(R);
+ }
}
void MallocChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
ExprEngine &Eng) const {
- const GRState *state = B.getState();
+ const ProgramState *state = B.getState();
RegionStateTy M = state->get<RegionState>();
for (RegionStateTy::iterator I = M.begin(), E = M.end(); I != E; ++I) {
@@ -623,7 +629,7 @@ void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
if (!retExpr)
return;
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
SymbolRef Sym = state->getSVal(retExpr).getAsSymbol();
if (!Sym)
@@ -640,7 +646,7 @@ void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
C.addTransition(state);
}
-const GRState *MallocChecker::evalAssume(const GRState *state, SVal Cond,
+const ProgramState *MallocChecker::evalAssume(const ProgramState *state, SVal Cond,
bool Assumption) const {
// If a symblic region is assumed to NULL, set its state to AllocateFailed.
// FIXME: should also check symbols assumed to non-null.
@@ -657,7 +663,8 @@ const GRState *MallocChecker::evalAssume(const GRState *state, SVal Cond,
}
// Check if the location is a freed symbolic region.
-void MallocChecker::checkLocation(SVal l, bool isLoad,CheckerContext &C) const {
+void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S,
+ CheckerContext &C) const {
SymbolRef Sym = l.getLocSymbolInBase();
if (Sym) {
const RefState *RS = C.getState()->get<RegionState>(Sym);
@@ -675,13 +682,14 @@ void MallocChecker::checkLocation(SVal l, bool isLoad,CheckerContext &C) const {
}
}
-void MallocChecker::checkBind(SVal location, SVal val,CheckerContext &C) const {
+void MallocChecker::checkBind(SVal location, SVal val,
+ const Stmt *BindS, CheckerContext &C) const {
// The PreVisitBind implements the same algorithm as already used by the
// Objective C ownership checker: if the pointer escaped from this scope by
// assignment, let it go. However, assigning to fields of a stack-storage
// structure does not transfer ownership.
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
DefinedOrUnknownSVal l = cast<DefinedOrUnknownSVal>(location);
// Check for null dereferences.
@@ -694,7 +702,7 @@ void MallocChecker::checkBind(SVal location, SVal val,CheckerContext &C) const {
if (Sym) {
if (const RefState *RS = state->get<RegionState>(Sym)) {
// If ptr is NULL, no operation is performed.
- const GRState *notNullState, *nullState;
+ const ProgramState *notNullState, *nullState;
llvm::tie(notNullState, nullState) = state->assume(l);
// Generate a transition for 'nullState' to record the assumption
@@ -724,7 +732,7 @@ void MallocChecker::checkBind(SVal location, SVal val,CheckerContext &C) const {
// We no longer own this pointer.
notNullState =
notNullState->set<RegionState>(Sym,
- RefState::getRelinquished(C.getStmt()));
+ RefState::getRelinquished(BindS));
}
while (false);
}
diff --git a/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
new file mode 100644
index 000000000000..cf5501a4ac15
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
@@ -0,0 +1,268 @@
+// MallocOverflowSecurityChecker.cpp - Check for malloc overflows -*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This checker detects a common memory allocation security flaw.
+// Suppose 'unsigned int n' comes from an untrusted source. If the
+// code looks like 'malloc (n * 4)', and an attacker can make 'n' be
+// say MAX_UINT/4+2, then instead of allocating the correct 'n' 4-byte
+// elements, this will actually allocate only two because of overflow.
+// Then when the rest of the program attempts to store values past the
+// second element, these values will actually overwrite other items in
+// the heap, probably allowing the attacker to execute arbitrary code.
+//
+//===----------------------------------------------------------------------===//
+
+#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 "llvm/ADT/SmallVector.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+struct MallocOverflowCheck {
+ const BinaryOperator *mulop;
+ const Expr *variable;
+
+ MallocOverflowCheck (const BinaryOperator *m, const Expr *v)
+ : mulop(m), variable (v)
+ {}
+};
+
+class MallocOverflowSecurityChecker : public Checker<check::ASTCodeBody> {
+public:
+ void checkASTCodeBody(const Decl *D, AnalysisManager &mgr,
+ BugReporter &BR) const;
+
+ void CheckMallocArgument(
+ llvm::SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
+ const Expr *TheArgument, ASTContext &Context) const;
+
+ void OutputPossibleOverflows(
+ llvm::SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
+ const Decl *D, BugReporter &BR, AnalysisManager &mgr) const;
+
+};
+} // end anonymous namespace
+
+void MallocOverflowSecurityChecker::CheckMallocArgument(
+ llvm::SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
+ const Expr *TheArgument,
+ ASTContext &Context) const {
+
+ /* Look for a linear combination with a single variable, and at least
+ one multiplication.
+ Reject anything that applies to the variable: an explicit cast,
+ conditional expression, an operation that could reduce the range
+ of the result, or anything too complicated :-). */
+ const Expr * e = TheArgument;
+ const BinaryOperator * mulop = NULL;
+
+ for (;;) {
+ e = e->IgnoreParenImpCasts();
+ if (isa<BinaryOperator>(e)) {
+ const BinaryOperator * binop = dyn_cast<BinaryOperator>(e);
+ BinaryOperatorKind opc = binop->getOpcode();
+ // TODO: ignore multiplications by 1, reject if multiplied by 0.
+ if (mulop == NULL && opc == BO_Mul)
+ mulop = binop;
+ if (opc != BO_Mul && opc != BO_Add && opc != BO_Sub && opc != BO_Shl)
+ return;
+
+ const Expr *lhs = binop->getLHS();
+ const Expr *rhs = binop->getRHS();
+ if (rhs->isEvaluatable(Context))
+ e = lhs;
+ else if ((opc == BO_Add || opc == BO_Mul)
+ && lhs->isEvaluatable(Context))
+ e = rhs;
+ else
+ return;
+ }
+ else if (isa<DeclRefExpr>(e) || isa<MemberExpr>(e))
+ break;
+ else
+ return;
+ }
+
+ if (mulop == NULL)
+ return;
+
+ // We've found the right structure of malloc argument, now save
+ // the data so when the body of the function is completely available
+ // we can check for comparisons.
+
+ // TODO: Could push this into the innermost scope where 'e' is
+ // defined, rather than the whole function.
+ PossibleMallocOverflows.push_back(MallocOverflowCheck(mulop, e));
+}
+
+namespace {
+// A worker class for OutputPossibleOverflows.
+class CheckOverflowOps :
+ public EvaluatedExprVisitor<CheckOverflowOps> {
+public:
+ typedef llvm::SmallVectorImpl<MallocOverflowCheck> theVecType;
+
+private:
+ theVecType &toScanFor;
+ ASTContext &Context;
+
+ bool isIntZeroExpr(const Expr *E) const {
+ if (!E->getType()->isIntegralOrEnumerationType())
+ return false;
+ llvm::APSInt Result;
+ if (E->EvaluateAsInt(Result, Context))
+ return Result == 0;
+ return false;
+ }
+
+ void CheckExpr(const Expr *E_p) {
+ const Expr *E = E_p->IgnoreParenImpCasts();
+
+ theVecType::iterator i = toScanFor.end();
+ theVecType::iterator e = toScanFor.begin();
+
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) {
+ const Decl * EdreD = DR->getDecl();
+ while (i != e) {
+ --i;
+ if (const DeclRefExpr *DR_i = dyn_cast<DeclRefExpr>(i->variable)) {
+ if (DR_i->getDecl() == EdreD)
+ i = toScanFor.erase(i);
+ }
+ }
+ }
+ else if (isa<MemberExpr>(E)) {
+ // No points-to analysis, just look at the member
+ const Decl * EmeMD = dyn_cast<MemberExpr>(E)->getMemberDecl();
+ while (i != e) {
+ --i;
+ if (isa<MemberExpr>(i->variable)) {
+ if (dyn_cast<MemberExpr>(i->variable)->getMemberDecl() == EmeMD)
+ i = toScanFor.erase (i);
+ }
+ }
+ }
+ }
+
+ public:
+ void VisitBinaryOperator(BinaryOperator *E) {
+ if (E->isComparisonOp()) {
+ const Expr * lhs = E->getLHS();
+ const Expr * rhs = E->getRHS();
+ // Ignore comparisons against zero, since they generally don't
+ // protect against an overflow.
+ if (!isIntZeroExpr(lhs) && ! isIntZeroExpr(rhs)) {
+ CheckExpr(lhs);
+ CheckExpr(rhs);
+ }
+ }
+ EvaluatedExprVisitor<CheckOverflowOps>::VisitBinaryOperator(E);
+ }
+
+ /* We specifically ignore loop conditions, because they're typically
+ not error checks. */
+ void VisitWhileStmt(WhileStmt *S) {
+ return this->Visit(S->getBody());
+ }
+ void VisitForStmt(ForStmt *S) {
+ return this->Visit(S->getBody());
+ }
+ void VisitDoStmt(DoStmt *S) {
+ return this->Visit(S->getBody());
+ }
+
+ CheckOverflowOps(theVecType &v, ASTContext &ctx)
+ : EvaluatedExprVisitor<CheckOverflowOps>(ctx),
+ toScanFor(v), Context(ctx)
+ { }
+ };
+}
+
+// OutputPossibleOverflows - We've found a possible overflow earlier,
+// now check whether Body might contain a comparison which might be
+// preventing the overflow.
+// This doesn't do flow analysis, range analysis, or points-to analysis; it's
+// just a dumb "is there a comparison" scan. The aim here is to
+// detect the most blatent cases of overflow and educate the
+// programmer.
+void MallocOverflowSecurityChecker::OutputPossibleOverflows(
+ llvm::SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
+ const Decl *D, BugReporter &BR, AnalysisManager &mgr) const {
+ // By far the most common case: nothing to check.
+ if (PossibleMallocOverflows.empty())
+ return;
+
+ // Delete any possible overflows which have a comparison.
+ CheckOverflowOps c(PossibleMallocOverflows, BR.getContext());
+ c.Visit(mgr.getAnalysisContext(D)->getBody());
+
+ // Output warnings for all overflows that are left.
+ for (CheckOverflowOps::theVecType::iterator
+ i = PossibleMallocOverflows.begin(),
+ e = PossibleMallocOverflows.end();
+ i != e;
+ ++i) {
+ SourceRange R = i->mulop->getSourceRange();
+ BR.EmitBasicReport("MallocOverflowSecurityChecker",
+ "the computation of the size of the memory allocation may overflow",
+ PathDiagnosticLocation::createOperatorLoc(i->mulop,
+ BR.getSourceManager()),
+ &R, 1);
+ }
+}
+
+void MallocOverflowSecurityChecker::checkASTCodeBody(const Decl *D,
+ AnalysisManager &mgr,
+ BugReporter &BR) const {
+
+ CFG *cfg = mgr.getCFG(D);
+ if (!cfg)
+ return;
+
+ // A list of variables referenced in possibly overflowing malloc operands.
+ llvm::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 (const CallExpr *TheCall = dyn_cast<CallExpr>(CS->getStmt())) {
+ // Get the callee.
+ const FunctionDecl *FD = TheCall->getDirectCallee();
+
+ if (!FD)
+ return;
+
+ // Get the name of the callee. If it's a builtin, strip off the prefix.
+ IdentifierInfo *FnInfo = FD->getIdentifier();
+ if (!FnInfo)
+ return;
+
+ if (FnInfo->isStr ("malloc") || FnInfo->isStr ("_MALLOC")) {
+ if (TheCall->getNumArgs() == 1)
+ CheckMallocArgument(PossibleMallocOverflows, TheCall->getArg(0),
+ mgr.getASTContext());
+ }
+ }
+ }
+ }
+ }
+
+ OutputPossibleOverflows(PossibleMallocOverflows, D, BR, mgr);
+}
+
+void ento::registerMallocOverflowSecurityChecker(CheckerManager &mgr) {
+ mgr.registerChecker<MallocOverflowSecurityChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
index f11db6458cc0..7f74a7d015d6 100644
--- a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
@@ -9,7 +9,7 @@
//
// This file defines a NSAutoreleasePoolChecker, a small checker that warns
// about subpar uses of NSAutoreleasePool. Note that while the check itself
-// (in it's current form) could be written as a flow-insensitive check, in
+// (in its current form) could be written as a flow-insensitive check, in
// can be potentially enhanced in the future with flow-sensitive information.
// It is also a good example of the CheckerVisitor interface.
//
@@ -18,9 +18,10 @@
#include "ClangSACheckers.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Decl.h"
@@ -53,7 +54,7 @@ void NSAutoreleasePoolChecker::checkPreObjCMessage(ObjCMessage msg,
if (!PT)
return;
- const ObjCInterfaceDecl* OD = PT->getInterfaceDecl();
+ const ObjCInterfaceDecl *OD = PT->getInterfaceDecl();
if (!OD)
return;
if (!OD->getIdentifier()->getName().equals("NSAutoreleasePool"))
@@ -66,14 +67,18 @@ void NSAutoreleasePoolChecker::checkPreObjCMessage(ObjCMessage msg,
return;
SourceRange R = msg.getSourceRange();
-
+ BugReporter &BR = C.getBugReporter();
+ const LocationContext *LC = C.getPredecessor()->getLocationContext();
+ const SourceManager &SM = BR.getSourceManager();
+ const Expr *E = msg.getMsgOrPropExpr();
+ PathDiagnosticLocation L = PathDiagnosticLocation::createBegin(E, SM, LC);
C.getBugReporter().EmitBasicReport("Use -drain instead of -release",
"API Upgrade (Apple)",
"Use -drain instead of -release when using NSAutoreleasePool "
- "and garbage collection", R.getBegin(), &R, 1);
+ "and garbage collection", L, &R, 1);
}
void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) {
- if (mgr.getLangOptions().getGCMode() != LangOptions::NonGC)
+ if (mgr.getLangOptions().getGC() != LangOptions::NonGC)
mgr.registerChecker<NSAutoreleasePoolChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index a51d8e0d19ae..56789983593e 100644
--- a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -19,7 +19,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.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"
@@ -60,7 +60,7 @@ void NSErrorMethodChecker::checkASTDecl(const ObjCMethodDecl *D,
II = &D->getASTContext().Idents.get("NSError");
bool hasNSError = false;
- for (ObjCMethodDecl::param_iterator
+ for (ObjCMethodDecl::param_const_iterator
I = D->param_begin(), E = D->param_end(); I != E; ++I) {
if (IsNSError((*I)->getType(), II)) {
hasNSError = true;
@@ -72,8 +72,10 @@ void NSErrorMethodChecker::checkASTDecl(const ObjCMethodDecl *D,
const char *err = "Method accepting NSError** "
"should have a non-void return value to indicate whether or not an "
"error occurred";
+ PathDiagnosticLocation L =
+ PathDiagnosticLocation::create(D, BR.getSourceManager());
BR.EmitBasicReport("Bad return type when passing NSError**",
- "Coding conventions (Apple)", err, D->getLocation());
+ "Coding conventions (Apple)", err, L);
}
}
@@ -118,8 +120,10 @@ void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D,
const char *err = "Function accepting CFErrorRef* "
"should have a non-void return value to indicate whether or not an "
"error occurred";
+ PathDiagnosticLocation L =
+ PathDiagnosticLocation::create(D, BR.getSourceManager());
BR.EmitBasicReport("Bad return type when passing CFErrorRef*",
- "Coding conventions (Apple)", err, D->getLocation());
+ "Coding conventions (Apple)", err, L);
}
}
@@ -153,7 +157,8 @@ public:
NSOrCFErrorDerefChecker() : NSErrorII(0), CFErrorII(0),
ShouldCheckNSError(0), ShouldCheckCFError(0) { }
- void checkLocation(SVal loc, bool isLoad, CheckerContext &C) const;
+ void checkLocation(SVal loc, bool isLoad, const Stmt *S,
+ CheckerContext &C) const;
void checkEvent(ImplicitNullDerefEvent event) const;
};
}
@@ -166,18 +171,18 @@ typedef llvm::ImmutableMap<SymbolRef, unsigned> ErrorOutFlag;
namespace clang {
namespace ento {
template <>
- struct GRStateTrait<NSErrorOut> : public GRStatePartialTrait<ErrorOutFlag> {
+ struct ProgramStateTrait<NSErrorOut> : public ProgramStatePartialTrait<ErrorOutFlag> {
static void *GDMIndex() { static int index = 0; return &index; }
};
template <>
- struct GRStateTrait<CFErrorOut> : public GRStatePartialTrait<ErrorOutFlag> {
+ struct ProgramStateTrait<CFErrorOut> : public ProgramStatePartialTrait<ErrorOutFlag> {
static void *GDMIndex() { static int index = 0; return &index; }
};
}
}
template <typename T>
-static bool hasFlag(SVal val, const GRState *state) {
+static bool hasFlag(SVal val, const ProgramState *state) {
if (SymbolRef sym = val.getAsSymbol())
if (const unsigned *attachedFlags = state->get<T>(sym))
return *attachedFlags;
@@ -185,7 +190,7 @@ static bool hasFlag(SVal val, const GRState *state) {
}
template <typename T>
-static void setFlag(const GRState *state, SVal val, CheckerContext &C) {
+static void setFlag(const ProgramState *state, SVal val, CheckerContext &C) {
// We tag the symbol that the SVal wraps.
if (SymbolRef sym = val.getAsSymbol())
C.addTransition(state->set<T>(sym, true));
@@ -207,6 +212,7 @@ static QualType parameterTypeFromSVal(SVal val, CheckerContext &C) {
}
void NSOrCFErrorDerefChecker::checkLocation(SVal loc, bool isLoad,
+ const Stmt *S,
CheckerContext &C) const {
if (!isLoad)
return;
@@ -214,7 +220,7 @@ void NSOrCFErrorDerefChecker::checkLocation(SVal loc, bool isLoad,
return;
ASTContext &Ctx = C.getASTContext();
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
// If we are loading from NSError**/CFErrorRef* parameter, mark the resulting
// SVal so that we can later check it when handling the
@@ -247,7 +253,7 @@ void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const {
return;
SVal loc = event.Location;
- const GRState *state = event.SinkNode->getState();
+ const ProgramState *state = event.SinkNode->getState();
BugReporter &BR = *event.BR;
bool isNSError = hasFlag<NSErrorOut>(loc, state);
@@ -277,7 +283,7 @@ void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const {
bug = new NSErrorDerefBug();
else
bug = new CFErrorDerefBug();
- EnhancedBugReport *report = new EnhancedBugReport(*bug, os.str(),
+ BugReport *report = new BugReport(*bug, os.str(),
event.SinkNode);
BR.EmitReport(report);
}
diff --git a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
index 2d0af9c978dc..81f1924b2c7a 100644
--- a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
@@ -16,23 +16,27 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
#include "llvm/ADT/StringSwitch.h"
+#include <cstdarg>
using namespace clang;
using namespace ento;
namespace {
-class NoReturnFunctionChecker : public Checker< check::PostStmt<CallExpr> > {
+class NoReturnFunctionChecker : public Checker< check::PostStmt<CallExpr>,
+ check::PostObjCMessage > {
public:
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkPostObjCMessage(const ObjCMessage &msg, CheckerContext &C) const;
};
}
void NoReturnFunctionChecker::checkPostStmt(const CallExpr *CE,
CheckerContext &C) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
bool BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();
@@ -50,7 +54,7 @@ void NoReturnFunctionChecker::checkPostStmt(const CallExpr *CE,
// Here are a few hardwired ones. If this takes too long, we can
// potentially cache these results.
BuildSinks
- = llvm::StringSwitch<bool>(llvm::StringRef(II->getName()))
+ = llvm::StringSwitch<bool>(StringRef(II->getName()))
.Case("exit", true)
.Case("panic", true)
.Case("error", true)
@@ -73,9 +77,70 @@ void NoReturnFunctionChecker::checkPostStmt(const CallExpr *CE,
}
if (BuildSinks)
- C.generateSink(CE);
+ C.generateSink();
}
+static bool END_WITH_NULL isMultiArgSelector(const Selector *Sel, ...) {
+ va_list argp;
+ va_start(argp, Sel);
+
+ unsigned Slot = 0;
+ const char *Arg;
+ while ((Arg = va_arg(argp, const char *))) {
+ if (!Sel->getNameForSlot(Slot).equals(Arg))
+ break; // still need to va_end!
+ ++Slot;
+ }
+
+ va_end(argp);
+
+ // We only succeeded if we made it to the end of the argument list.
+ return (Arg == NULL);
+}
+
+void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMessage &Msg,
+ CheckerContext &C) const {
+ // HACK: This entire check is to handle two messages in the Cocoa frameworks:
+ // -[NSAssertionHandler
+ // handleFailureInMethod:object:file:lineNumber:description:]
+ // -[NSAssertionHandler
+ // handleFailureInFunction:file:lineNumber:description:]
+ // Eventually these should be annotated with __attribute__((noreturn)).
+ // Because ObjC messages use dynamic dispatch, it is not generally safe to
+ // assume certain methods can't return. In cases where it is definitely valid,
+ // see if you can mark the methods noreturn or analyzer_noreturn instead of
+ // adding more explicit checks to this method.
+
+ if (!Msg.isInstanceMessage())
+ return;
+
+ const ObjCInterfaceDecl *Receiver = Msg.getReceiverInterface();
+ if (!Receiver)
+ return;
+ if (!Receiver->getIdentifier()->isStr("NSAssertionHandler"))
+ return;
+
+ Selector Sel = Msg.getSelector();
+ switch (Sel.getNumArgs()) {
+ default:
+ return;
+ case 4:
+ if (!isMultiArgSelector(&Sel, "handleFailureInFunction", "file",
+ "lineNumber", "description", NULL))
+ return;
+ break;
+ case 5:
+ if (!isMultiArgSelector(&Sel, "handleFailureInMethod", "object", "file",
+ "lineNumber", "description", NULL))
+ return;
+ break;
+ }
+
+ // If we got here, it's one of the messages we care about.
+ C.generateSink();
+}
+
+
void ento::registerNoReturnFunctionChecker(CheckerManager &mgr) {
mgr.registerChecker<NoReturnFunctionChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp b/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
index 7262bc36404d..f426265f6713 100644
--- a/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
@@ -22,22 +22,32 @@ using namespace ento;
namespace {
-class OSAtomicChecker : public Checker<eval::Call> {
+class OSAtomicChecker : public Checker<eval::InlineCall> {
public:
- bool evalCall(const CallExpr *CE, CheckerContext &C) const;
+ bool inlineCall(const CallExpr *CE, ExprEngine &Eng,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst) const;
private:
- static bool evalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE);
+ bool evalOSAtomicCompareAndSwap(const CallExpr *CE,
+ ExprEngine &Eng,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) const;
+
+ ExplodedNode *generateNode(const ProgramState *State,
+ ExplodedNode *Pred, const CallExpr *Statement,
+ StmtNodeBuilder &B, ExplodedNodeSet &Dst) const;
};
-
}
-bool OSAtomicChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
- const GRState *state = C.getState();
+bool OSAtomicChecker::inlineCall(const CallExpr *CE,
+ ExprEngine &Eng,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) const {
+ const ProgramState *state = Pred->getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
- const FunctionDecl* FD = L.getAsFunctionDecl();
+ const FunctionDecl *FD = L.getAsFunctionDecl();
if (!FD)
return false;
@@ -45,24 +55,38 @@ bool OSAtomicChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
if (!II)
return false;
- llvm::StringRef FName(II->getName());
+ StringRef FName(II->getName());
// Check for compare and swap.
if (FName.startswith("OSAtomicCompareAndSwap") ||
FName.startswith("objc_atomicCompareAndSwap"))
- return evalOSAtomicCompareAndSwap(C, CE);
+ return evalOSAtomicCompareAndSwap(CE, Eng, Pred, Dst);
// FIXME: Other atomics.
return false;
}
-bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C,
- const CallExpr *CE) {
+ExplodedNode *OSAtomicChecker::generateNode(const ProgramState *State,
+ ExplodedNode *Pred,
+ const CallExpr *Statement,
+ StmtNodeBuilder &B,
+ ExplodedNodeSet &Dst) const {
+ ExplodedNode *N = B.generateNode(Statement, State, Pred, this);
+ if (N)
+ Dst.Add(N);
+ return N;
+}
+
+bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE,
+ ExprEngine &Eng,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) const {
// Not enough arguments to match OSAtomicCompareAndSwap?
if (CE->getNumArgs() != 3)
return false;
- ASTContext &Ctx = C.getASTContext();
+ StmtNodeBuilder &Builder = Eng.getBuilder();
+ ASTContext &Ctx = Eng.getContext();
const Expr *oldValueExpr = CE->getArg(0);
QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType());
@@ -87,15 +111,11 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C,
if (theValueTypePointee != newValueType)
return false;
- static unsigned magic_load = 0;
- static unsigned magic_store = 0;
-
- const void *OSAtomicLoadTag = &magic_load;
- const void *OSAtomicStoreTag = &magic_store;
-
+ static SimpleProgramPointTag OSAtomicLoadTag("OSAtomicChecker : Load");
+ static SimpleProgramPointTag OSAtomicStoreTag("OSAtomicChecker : Store");
+
// Load 'theValue'.
- ExprEngine &Engine = C.getEngine();
- const GRState *state = C.getState();
+ const ProgramState *state = Pred->getState();
ExplodedNodeSet Tmp;
SVal location = state->getSVal(theValueExpr);
// Here we should use the value type of the region as the load type, because
@@ -106,19 +126,19 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C,
// LoadTy specifying can be omitted. But we put it here to emphasize the
// semantics.
QualType LoadTy;
- if (const TypedRegion *TR =
- dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
+ if (const TypedValueRegion *TR =
+ dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
LoadTy = TR->getValueType();
}
- Engine.evalLoad(Tmp, theValueExpr, C.getPredecessor(),
- state, location, OSAtomicLoadTag, LoadTy);
+ Eng.evalLoad(Tmp, theValueExpr, Pred,
+ state, location, &OSAtomicLoadTag, LoadTy);
if (Tmp.empty()) {
// If no nodes were generated, other checkers must generated sinks. But
// since the builder state was restored, we set it manually to prevent
// auto transition.
// FIXME: there should be a better approach.
- C.getNodeBuilder().BuildSinks = true;
+ Builder.BuildSinks = true;
return true;
}
@@ -126,7 +146,7 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C,
I != E; ++I) {
ExplodedNode *N = *I;
- const GRState *stateLoad = N->getState();
+ const ProgramState *stateLoad = N->getState();
// Use direct bindings from the environment since we are forcing a load
// from a location that the Environment would typically not be used
@@ -145,12 +165,13 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C,
DefinedOrUnknownSVal oldValueVal =
cast<DefinedOrUnknownSVal>(oldValueVal_untested);
- SValBuilder &svalBuilder = Engine.getSValBuilder();
+ SValBuilder &svalBuilder = Eng.getSValBuilder();
// Perform the comparison.
- DefinedOrUnknownSVal Cmp = svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal);
+ DefinedOrUnknownSVal Cmp =
+ svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal);
- const GRState *stateEqual = stateLoad->assume(Cmp, true);
+ const ProgramState *stateEqual = stateLoad->assume(Cmp, true);
// Were they equal?
if (stateEqual) {
@@ -159,20 +180,20 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C,
SVal val = stateEqual->getSVal(newValueExpr);
// Handle implicit value casts.
- if (const TypedRegion *R =
- dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
+ if (const TypedValueRegion *R =
+ dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
val = svalBuilder.evalCast(val,R->getValueType(), newValueExpr->getType());
}
- Engine.evalStore(TmpStore, NULL, theValueExpr, N,
- stateEqual, location, val, OSAtomicStoreTag);
+ Eng.evalStore(TmpStore, NULL, theValueExpr, N,
+ stateEqual, location, val, &OSAtomicStoreTag);
if (TmpStore.empty()) {
// If no nodes were generated, other checkers must generated sinks. But
// since the builder state was restored, we set it manually to prevent
// auto transition.
// FIXME: there should be a better approach.
- C.getNodeBuilder().BuildSinks = true;
+ Builder.BuildSinks = true;
return true;
}
@@ -180,24 +201,24 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C,
for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
E2 = TmpStore.end(); I2 != E2; ++I2) {
ExplodedNode *predNew = *I2;
- const GRState *stateNew = predNew->getState();
+ const ProgramState *stateNew = predNew->getState();
// Check for 'void' return type if we have a bogus function prototype.
SVal Res = UnknownVal();
QualType T = CE->getType();
if (!T->isVoidType())
- Res = Engine.getSValBuilder().makeTruthVal(true, T);
- C.generateNode(stateNew->BindExpr(CE, Res), predNew);
+ Res = Eng.getSValBuilder().makeTruthVal(true, T);
+ generateNode(stateNew->BindExpr(CE, Res), predNew, CE, Builder, Dst);
}
}
// Were they not equal?
- if (const GRState *stateNotEqual = stateLoad->assume(Cmp, false)) {
+ if (const ProgramState *stateNotEqual = stateLoad->assume(Cmp, false)) {
// Check for 'void' return type if we have a bogus function prototype.
SVal Res = UnknownVal();
QualType T = CE->getType();
if (!T->isVoidType())
- Res = Engine.getSValBuilder().makeTruthVal(false, CE->getType());
- C.generateNode(stateNotEqual->BindExpr(CE, Res), N);
+ Res = Eng.getSValBuilder().makeTruthVal(false, CE->getType());
+ generateNode(stateNotEqual->BindExpr(CE, Res), N, CE, Builder, Dst);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
index a1180492a937..3e4e07b65057 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
@@ -38,7 +38,7 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
CheckerContext &C) const {
const Expr *Ex = S->getSynchExpr();
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
SVal V = state->getSVal(Ex);
// Uninitialized value used for the mutex?
@@ -47,9 +47,9 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
if (!BT_undef)
BT_undef.reset(new BuiltinBug("Uninitialized value used as mutex "
"for @synchronized"));
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
+ BugReport *report =
+ new BugReport(*BT_undef, BT_undef->getDescription(), N);
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex));
C.EmitReport(report);
}
return;
@@ -59,7 +59,7 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
return;
// Check for null mutexes.
- const GRState *notNullState, *nullState;
+ const ProgramState *notNullState, *nullState;
llvm::tie(notNullState, nullState) = state->assume(cast<DefinedSVal>(V));
if (nullState) {
@@ -70,10 +70,9 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
if (!BT_null)
BT_null.reset(new BuiltinBug("Nil value used as mutex for @synchronized() "
"(no synchronization will occur)"));
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT_null, BT_null->getDescription(), N);
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- Ex);
+ BugReport *report =
+ new BugReport(*BT_null, BT_null->getDescription(), N);
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex));
C.EmitReport(report);
return;
diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index 4c05867631f3..2fb9944afaa7 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
@@ -50,7 +50,8 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/AST/ParentMap.h"
@@ -76,7 +77,8 @@ public:
void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
- void checkLocation(SVal location, bool isLoad, CheckerContext &C) const;
+ void checkLocation(SVal location, bool isLoad, const Stmt *S,
+ CheckerContext &C) const;
};
} // end anonymous namespace
@@ -109,11 +111,11 @@ namespace { struct PreCallSelfFlags {}; }
namespace clang {
namespace ento {
template<>
- struct GRStateTrait<SelfFlag> : public GRStatePartialTrait<SelfFlag> {
- static void* GDMIndex() { static int index = 0; return &index; }
+ struct ProgramStateTrait<SelfFlag> : public ProgramStatePartialTrait<SelfFlag> {
+ static void *GDMIndex() { static int index = 0; return &index; }
};
template <>
- struct GRStateTrait<CalledInit> : public GRStatePartialTrait<bool> {
+ struct ProgramStateTrait<CalledInit> : public ProgramStatePartialTrait<bool> {
static void *GDMIndex() { static int index = 0; return &index; }
};
@@ -122,13 +124,13 @@ namespace ento {
/// object before the call so we can assign them to the new object that 'self'
/// points to after the call.
template <>
- struct GRStateTrait<PreCallSelfFlags> : public GRStatePartialTrait<unsigned> {
+ struct ProgramStateTrait<PreCallSelfFlags> : public ProgramStatePartialTrait<unsigned> {
static void *GDMIndex() { static int index = 0; return &index; }
};
}
}
-static SelfFlagEnum getSelfFlags(SVal val, const GRState *state) {
+static SelfFlagEnum getSelfFlags(SVal val, const ProgramState *state) {
if (SymbolRef sym = val.getAsSymbol())
if (const unsigned *attachedFlags = state->get<SelfFlag>(sym))
return (SelfFlagEnum)*attachedFlags;
@@ -139,7 +141,7 @@ static SelfFlagEnum getSelfFlags(SVal val, CheckerContext &C) {
return getSelfFlags(val, C.getState());
}
-static void addSelfFlag(const GRState *state, SVal val,
+static void addSelfFlag(const ProgramState *state, SVal val,
SelfFlagEnum flag, CheckerContext &C) {
// We tag the symbol that the SVal wraps.
if (SymbolRef sym = val.getAsSymbol())
@@ -179,8 +181,8 @@ static void checkForInvalidSelf(const Expr *E, CheckerContext &C,
if (!N)
return;
- EnhancedBugReport *report =
- new EnhancedBugReport(*new InitSelfBug(), errorStr, N);
+ BugReport *report =
+ new BugReport(*new InitSelfBug(), errorStr, N);
C.EmitReport(report);
}
@@ -197,7 +199,7 @@ void ObjCSelfInitChecker::checkPostObjCMessage(ObjCMessage msg,
if (isInitMessage(msg)) {
// Tag the return value as the result of an initializer.
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
// FIXME this really should be context sensitive, where we record
// the current stack frame (for IPA). Also, we need to clean this
@@ -257,7 +259,7 @@ void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S,
void ObjCSelfInitChecker::checkPreStmt(const CallExpr *CE,
CheckerContext &C) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
for (CallExpr::const_arg_iterator
I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) {
SVal argV = state->getSVal(*I);
@@ -275,7 +277,7 @@ void ObjCSelfInitChecker::checkPreStmt(const CallExpr *CE,
void ObjCSelfInitChecker::checkPostStmt(const CallExpr *CE,
CheckerContext &C) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
for (CallExpr::const_arg_iterator
I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) {
SVal argV = state->getSVal(*I);
@@ -294,10 +296,11 @@ void ObjCSelfInitChecker::checkPostStmt(const CallExpr *CE,
}
void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad,
+ const Stmt *S,
CheckerContext &C) const {
// Tag the result of a load from 'self' so that we can easily know that the
// value is the object that 'self' points to.
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
if (isSelfVar(location, C))
addSelfFlag(state, state->getSVal(cast<Loc>(location)), SelfFlag_Self, C);
}
@@ -315,9 +318,9 @@ static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND) {
// self = [super init] applies only to NSObject subclasses.
// For instance, NSProxy doesn't implement -init.
- ASTContext& Ctx = MD->getASTContext();
+ ASTContext &Ctx = MD->getASTContext();
IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
- ObjCInterfaceDecl* ID = MD->getClassInterface()->getSuperClass();
+ ObjCInterfaceDecl *ID = MD->getClassInterface()->getSuperClass();
for ( ; ID ; ID = ID->getSuperClass()) {
IdentifierInfo *II = ID->getIdentifier();
diff --git a/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
index d78e5ceb533d..bbc262fe8ef7 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
@@ -29,7 +29,7 @@ using namespace ento;
enum IVarState { Unused, Used };
typedef llvm::DenseMap<const ObjCIvarDecl*,IVarState> IvarUsageMap;
-static void Scan(IvarUsageMap& M, const Stmt* S) {
+static void Scan(IvarUsageMap& M, const Stmt *S) {
if (!S)
return;
@@ -51,11 +51,11 @@ static void Scan(IvarUsageMap& M, const Stmt* S) {
Scan(M, *I);
}
-static void Scan(IvarUsageMap& M, const ObjCPropertyImplDecl* D) {
+static void Scan(IvarUsageMap& M, const ObjCPropertyImplDecl *D) {
if (!D)
return;
- const ObjCIvarDecl* ID = D->getPropertyIvarDecl();
+ const ObjCIvarDecl *ID = D->getPropertyIvarDecl();
if (!ID)
return;
@@ -65,7 +65,7 @@ static void Scan(IvarUsageMap& M, const ObjCPropertyImplDecl* D) {
I->second = Used;
}
-static void Scan(IvarUsageMap& M, const ObjCContainerDecl* D) {
+static void Scan(IvarUsageMap& M, const ObjCContainerDecl *D) {
// Scan the methods for accesses.
for (ObjCContainerDecl::instmeth_iterator I = D->instmeth_begin(),
E = D->instmeth_end(); I!=E; ++I)
@@ -102,14 +102,14 @@ static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID,
static void checkObjCUnusedIvar(const ObjCImplementationDecl *D,
BugReporter &BR) {
- const ObjCInterfaceDecl* ID = D->getClassInterface();
+ const ObjCInterfaceDecl *ID = D->getClassInterface();
IvarUsageMap M;
// Iterate over the ivars.
for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(),
E=ID->ivar_end(); I!=E; ++I) {
- const ObjCIvarDecl* ID = *I;
+ const ObjCIvarDecl *ID = *I;
// Ignore ivars that...
// (a) aren't private
@@ -155,12 +155,14 @@ static void checkObjCUnusedIvar(const ObjCImplementationDecl *D,
if (I->second == Unused) {
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
- os << "Instance variable '" << I->first << "' in class '" << ID
+ os << "Instance variable '" << *I->first << "' in class '" << *ID
<< "' is never used by the methods in its @implementation "
"(although it may be used by category methods).";
+ PathDiagnosticLocation L =
+ PathDiagnosticLocation::create(I->first, BR.getSourceManager());
BR.EmitBasicReport("Unused instance variable", "Optimization",
- os.str(), I->first->getLocation());
+ os.str(), L);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
index 7c21acc5bee7..202522b1949c 100644
--- a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
@@ -36,7 +36,7 @@ void PointerArithChecker::checkPreStmt(const BinaryOperator *B,
if (B->getOpcode() != BO_Sub && B->getOpcode() != BO_Add)
return;
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
SVal LV = state->getSVal(B->getLHS());
SVal RV = state->getSVal(B->getRHS());
@@ -56,7 +56,7 @@ void PointerArithChecker::checkPreStmt(const BinaryOperator *B,
"Pointer arithmetic done on non-array variables "
"means reliance on memory layout, which is "
"dangerous."));
- RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
+ BugReport *R = new BugReport(*BT, BT->getDescription(), N);
R->addRange(B->getSourceRange());
C.EmitReport(R);
}
diff --git a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index 16ede2095eae..924c7f2ad3ea 100644
--- a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -39,7 +39,7 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
if (B->getOpcode() != BO_Sub)
return;
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
SVal LV = state->getSVal(B->getLHS());
SVal RV = state->getSVal(B->getRHS());
@@ -64,7 +64,7 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
BT.reset(new BuiltinBug("Pointer subtraction",
"Subtraction of two pointers that do not point to "
"the same memory chunk may cause incorrect result."));
- RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
+ BugReport *R = new BugReport(*BT, BT->getDescription(), N);
R->addRange(B->getSourceRange());
C.EmitReport(R);
}
diff --git a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index 74199bb1f6db..c02b5b14ca64 100644
--- a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -1,4 +1,4 @@
-//===--- PthreadLockChecker.h - Undefined arguments checker ----*- C++ -*--===//
+//===--- PthreadLockChecker.cpp - Check for locking problems ---*- C++ -*--===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
//
-// This defines PthreadLockChecker, a simple lock -> unlock checker. Eventually
-// this shouldn't be registered with ExprEngineInternalChecks.
+// This defines PthreadLockChecker, a simple lock -> unlock checker.
+// Also handles XNU locks, which behave similarly enough to share code.
//
//===----------------------------------------------------------------------===//
@@ -16,25 +16,29 @@
#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/PathSensitive/GRStateTrait.h"
-#include "llvm/ADT/ImmutableSet.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "llvm/ADT/ImmutableList.h"
using namespace clang;
using namespace ento;
namespace {
-class PthreadLockChecker
- : public Checker< check::PostStmt<CallExpr> > {
+class PthreadLockChecker : public Checker< check::PostStmt<CallExpr> > {
+ mutable llvm::OwningPtr<BugType> BT_doublelock;
+ mutable llvm::OwningPtr<BugType> BT_lor;
+ enum LockingSemantics {
+ NotApplicable = 0,
+ PthreadSemantics,
+ XNUSemantics
+ };
public:
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
- void AcquireLock(CheckerContext &C, const CallExpr *CE,
- SVal lock, bool isTryLock) const;
+ void AcquireLock(CheckerContext &C, const CallExpr *CE, SVal lock,
+ bool isTryLock, enum LockingSemantics semantics) const;
- void ReleaseLock(CheckerContext &C, const CallExpr *CE,
- SVal lock) const;
-
+ void ReleaseLock(CheckerContext &C, const CallExpr *CE, SVal lock) const;
};
} // end anonymous namespace
@@ -42,80 +46,117 @@ public:
namespace { class LockSet {}; }
namespace clang {
namespace ento {
-template <> struct GRStateTrait<LockSet> :
- public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
- static void* GDMIndex() { static int x = 0; return &x; }
+template <> struct ProgramStateTrait<LockSet> :
+ public ProgramStatePartialTrait<llvm::ImmutableList<const MemRegion*> > {
+ static void *GDMIndex() { static int x = 0; return &x; }
};
-} // end GR namespace
+} // end of ento (ProgramState) namespace
} // end clang namespace
void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
CheckerContext &C) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
- const FunctionTextRegion *R =
- dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
-
- if (!R)
+ const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl();
+
+ if (!FD)
return;
-
- IdentifierInfo *II = R->getDecl()->getIdentifier();
+
+ // Get the name of the callee.
+ IdentifierInfo *II = FD->getIdentifier();
if (!II) // if no identifier, not a simple C function
return;
- llvm::StringRef FName = II->getName();
-
- if (FName == "pthread_mutex_lock") {
- if (CE->getNumArgs() != 1)
- return;
- AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false);
- }
- else if (FName == "pthread_mutex_trylock") {
- if (CE->getNumArgs() != 1)
- return;
- AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true);
- }
- else if (FName == "pthread_mutex_unlock") {
- if (CE->getNumArgs() != 1)
- return;
+ StringRef FName = II->getName();
+
+ if (CE->getNumArgs() != 1)
+ return;
+
+ if (FName == "pthread_mutex_lock" ||
+ FName == "pthread_rwlock_rdlock" ||
+ FName == "pthread_rwlock_wrlock")
+ AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false, PthreadSemantics);
+ else if (FName == "lck_mtx_lock" ||
+ FName == "lck_rw_lock_exclusive" ||
+ FName == "lck_rw_lock_shared")
+ AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false, XNUSemantics);
+ else if (FName == "pthread_mutex_trylock" ||
+ FName == "pthread_rwlock_tryrdlock" ||
+ FName == "pthread_rwlock_tryrwlock")
+ AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true, PthreadSemantics);
+ else if (FName == "lck_mtx_try_lock" ||
+ FName == "lck_rw_try_lock_exclusive" ||
+ FName == "lck_rw_try_lock_shared")
+ AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true, XNUSemantics);
+ else if (FName == "pthread_mutex_unlock" ||
+ FName == "pthread_rwlock_unlock" ||
+ FName == "lck_mtx_unlock" ||
+ FName == "lck_rw_done")
ReleaseLock(C, CE, state->getSVal(CE->getArg(0)));
- }
}
void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
- SVal lock, bool isTryLock) const {
+ SVal lock, bool isTryLock,
+ enum LockingSemantics semantics) const {
const MemRegion *lockR = lock.getAsRegion();
if (!lockR)
return;
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
SVal X = state->getSVal(CE);
if (X.isUnknownOrUndef())
return;
DefinedSVal retVal = cast<DefinedSVal>(X);
- const GRState *lockSucc = state;
-
+
+ if (state->contains<LockSet>(lockR)) {
+ if (!BT_doublelock)
+ BT_doublelock.reset(new BugType("Double locking", "Lock checker"));
+ ExplodedNode *N = C.generateSink();
+ if (!N)
+ return;
+ BugReport *report = new BugReport(*BT_doublelock,
+ "This lock has already "
+ "been acquired", N);
+ report->addRange(CE->getArg(0)->getSourceRange());
+ C.EmitReport(report);
+ return;
+ }
+
+ const ProgramState *lockSucc = state;
if (isTryLock) {
- // Bifurcate the state, and allow a mode where the lock acquisition fails.
- const GRState *lockFail;
- llvm::tie(lockFail, lockSucc) = state->assume(retVal);
+ // Bifurcate the state, and allow a mode where the lock acquisition fails.
+ const ProgramState *lockFail;
+ switch (semantics) {
+ case PthreadSemantics:
+ llvm::tie(lockFail, lockSucc) = state->assume(retVal);
+ break;
+ case XNUSemantics:
+ llvm::tie(lockSucc, lockFail) = state->assume(retVal);
+ break;
+ default:
+ llvm_unreachable("Unknown tryLock locking semantics");
+ break;
+ }
assert(lockFail && lockSucc);
- C.addTransition(C.generateNode(CE, lockFail));
- }
- else {
- // Assume that the return value was 0.
+ C.addTransition(lockFail);
+
+ } else if (semantics == PthreadSemantics) {
+ // Assume that the return value was 0.
lockSucc = state->assume(retVal, false);
assert(lockSucc);
+
+ } else {
+ // XNU locking semantics return void on non-try locks
+ assert((semantics == XNUSemantics) && "Unknown locking semantics");
+ lockSucc = state;
}
- // Record that the lock was acquired.
+ // Record that the lock was acquired.
lockSucc = lockSucc->add<LockSet>(lockR);
-
- C.addTransition(lockSucc != state ? C.generateNode(CE, lockSucc) :
- C.getPredecessor());
+ C.addTransition(lockSucc);
}
void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
@@ -125,19 +166,37 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
if (!lockR)
return;
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
+ llvm::ImmutableList<const MemRegion*> LS = state->get<LockSet>();
- // Record that the lock was released.
- // FIXME: Handle unlocking locks that were never acquired. This may
- // require IPA for wrappers.
- const GRState *unlockState = state->remove<LockSet>(lockR);
-
- if (state == unlockState)
+ // FIXME: Better analysis requires IPA for wrappers.
+ // FIXME: check for double unlocks
+ if (LS.isEmpty())
return;
- C.addTransition(C.generateNode(CE, unlockState));
+ const MemRegion *firstLockR = LS.getHead();
+ if (firstLockR != lockR) {
+ if (!BT_lor)
+ BT_lor.reset(new BugType("Lock order reversal", "Lock checker"));
+ ExplodedNode *N = C.generateSink();
+ if (!N)
+ return;
+ BugReport *report = new BugReport(*BT_lor,
+ "This was not the most "
+ "recently acquired lock. "
+ "Possible lock order "
+ "reversal", N);
+ report->addRange(CE->getArg(0)->getSourceRange());
+ C.EmitReport(report);
+ return;
+ }
+
+ // Record that the lock was released.
+ state = state->set<LockSet>(LS.getTail());
+ C.addTransition(state);
}
+
void ento::registerPthreadLockChecker(CheckerManager &mgr) {
mgr.registerChecker<PthreadLockChecker>();
}
diff --git a/lib/StaticAnalyzer/Core/CFRefCount.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index bf5302920819..93e0fe5b4f96 100644
--- a/lib/StaticAnalyzer/Core/CFRefCount.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -1,4 +1,4 @@
-// CFRefCount.cpp - Transfer functions for tracking simple values -*- C++ -*--//
+//==-- RetainCountChecker.cpp - Checks for leaks and other issues -*- C++ -*--//
//
// The LLVM Compiler Infrastructure
//
@@ -7,111 +7,56 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines the methods for CFRefCount, which implements
-// a reference count checker for Core Foundation (Mac OS X).
+// This file defines the methods for RetainCountChecker, which implements
+// a reference count checker for Core Foundation and Cocoa on (Mac OS X).
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "ClangSACheckers.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
-#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.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/Checkers/LocalCheckers.h"
-#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
-#include <stdarg.h>
+#include <cstdarg>
using namespace clang;
using namespace ento;
-using llvm::StringRef;
using llvm::StrInStrNoCase;
namespace {
-class InstanceReceiver {
- ObjCMessage Msg;
- const LocationContext *LC;
-public:
- InstanceReceiver() : LC(0) { }
- InstanceReceiver(const ObjCMessage &msg,
- const LocationContext *lc = 0) : Msg(msg), LC(lc) {}
-
- bool isValid() const {
- return Msg.isValid() && Msg.isInstanceMessage();
- }
- operator bool() const {
- return isValid();
- }
-
- SVal getSValAsScalarOrLoc(const GRState *state) {
- assert(isValid());
- // We have an expression for the receiver? Fetch the value
- // of that expression.
- if (const Expr *Ex = Msg.getInstanceReceiver())
- return state->getSValAsScalarOrLoc(Ex);
-
- // Otherwise we are sending a message to super. In this case the
- // object reference is the same as 'self'.
- if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl())
- return state->getSVal(state->getRegion(SelfDecl, LC));
-
- return UnknownVal();
- }
-
- SourceRange getSourceRange() const {
- assert(isValid());
- if (const Expr *Ex = Msg.getInstanceReceiver())
- return Ex->getSourceRange();
-
- // Otherwise we are sending a message to super.
- SourceLocation L = Msg.getSuperLoc();
- assert(L.isValid());
- return SourceRange(L, L);
- }
-};
-}
-
-static const ObjCMethodDecl*
-ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) {
- const ObjCInterfaceDecl *ID = MD->getClassInterface();
-
- return MD->isInstanceMethod()
- ? ID->lookupInstanceMethod(MD->getSelector())
- : ID->lookupClassMethod(MD->getSelector());
-}
-
-namespace {
+/// Wrapper around different kinds of node builder, so that helper functions
+/// can have a common interface.
class GenericNodeBuilderRefCount {
- StmtNodeBuilder *SNB;
- const Stmt *S;
- const void *tag;
+ CheckerContext *C;
+ const ProgramPointTag *tag;
EndOfFunctionNodeBuilder *ENB;
public:
- GenericNodeBuilderRefCount(StmtNodeBuilder &snb, const Stmt *s,
- const void *t)
- : SNB(&snb), S(s), tag(t), ENB(0) {}
+ GenericNodeBuilderRefCount(CheckerContext &c,
+ const ProgramPointTag *t)
+ : C(&c), tag(t), ENB(0) {}
GenericNodeBuilderRefCount(EndOfFunctionNodeBuilder &enb)
- : SNB(0), S(0), tag(0), ENB(&enb) {}
+ : C(0), tag(0), ENB(&enb) {}
- ExplodedNode *MakeNode(const GRState *state, ExplodedNode *Pred) {
- if (SNB)
- return SNB->generateNode(PostStmt(S, Pred->getLocationContext(), tag),
- state, Pred);
+ ExplodedNode *MakeNode(const ProgramState *state, ExplodedNode *Pred) {
+ if (C)
+ return C->generateNode(state, Pred, tag, false);
assert(ENB);
return ENB->generateNode(state, Pred);
@@ -125,9 +70,9 @@ public:
/// ArgEffect is used to summarize a function/method call's effect on a
/// particular argument.
-enum ArgEffect { Autorelease, Dealloc, DecRef, DecRefMsg, DoNothing,
+enum ArgEffect { DoNothing, Autorelease, Dealloc, DecRef, DecRefMsg,
DecRefBridgedTransfered,
- DoNothingByRef, IncRefMsg, IncRef, MakeCollectable, MayEscape,
+ IncRefMsg, IncRef, MakeCollectable, MayEscape,
NewAutoreleasePool, SelfOwn, StopTracking };
namespace llvm {
@@ -148,9 +93,8 @@ namespace {
/// respect to its return value.
class RetEffect {
public:
- enum Kind { NoRet, Alias, OwnedSymbol, OwnedAllocatedSymbol,
+ enum Kind { NoRet, OwnedSymbol, OwnedAllocatedSymbol,
NotOwnedSymbol, GCNotOwnedSymbol, ARCNotOwnedSymbol,
- ReceiverAlias,
OwnedWhenTrackedReceiver };
enum ObjKind { CF, ObjC, AnyObj };
@@ -158,36 +102,27 @@ public:
private:
Kind K;
ObjKind O;
- unsigned index;
- RetEffect(Kind k, unsigned idx = 0) : K(k), O(AnyObj), index(idx) {}
- RetEffect(Kind k, ObjKind o) : K(k), O(o), index(0) {}
+ RetEffect(Kind k, ObjKind o = AnyObj) : K(k), O(o) {}
public:
Kind getKind() const { return K; }
ObjKind getObjKind() const { return O; }
- unsigned getIndex() const {
- assert(getKind() == Alias);
- return index;
- }
-
bool isOwned() const {
return K == OwnedSymbol || K == OwnedAllocatedSymbol ||
K == OwnedWhenTrackedReceiver;
}
+ bool operator==(const RetEffect &Other) const {
+ return K == Other.K && O == Other.O;
+ }
+
static RetEffect MakeOwnedWhenTrackedReceiver() {
return RetEffect(OwnedWhenTrackedReceiver, ObjC);
}
- static RetEffect MakeAlias(unsigned Idx) {
- return RetEffect(Alias, Idx);
- }
- static RetEffect MakeReceiverAlias() {
- return RetEffect(ReceiverAlias);
- }
static RetEffect MakeOwned(ObjKind o, bool isAllocated = false) {
return RetEffect(isAllocated ? OwnedAllocatedSymbol : OwnedSymbol, o);
}
@@ -314,15 +249,15 @@ public:
ID.Add(T);
}
- void print(llvm::raw_ostream& Out) const;
+ void print(raw_ostream &Out) const;
};
-void RefVal::print(llvm::raw_ostream& Out) const {
+void RefVal::print(raw_ostream &Out) const {
if (!T.isNull())
- Out << "Tracked Type:" << T.getAsString() << '\n';
+ Out << "Tracked " << T.getAsString() << '/';
switch (getKind()) {
- default: assert(false);
+ default: llvm_unreachable("Invalid RefVal kind");
case Owned: {
Out << "Owned";
unsigned cnt = getCount();
@@ -406,18 +341,19 @@ typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings;
namespace clang {
namespace ento {
- template<>
- struct GRStateTrait<RefBindings> : public GRStatePartialTrait<RefBindings> {
- static void* GDMIndex() {
- static int RefBIndex = 0;
- return &RefBIndex;
- }
- };
+template<>
+struct ProgramStateTrait<RefBindings>
+ : public ProgramStatePartialTrait<RefBindings> {
+ static void *GDMIndex() {
+ static int RefBIndex = 0;
+ return &RefBIndex;
+ }
+};
}
}
//===----------------------------------------------------------------------===//
-// Summaries
+// Function/Method behavior summaries.
//===----------------------------------------------------------------------===//
namespace {
@@ -436,19 +372,13 @@ class RetainSummary {
ArgEffect Receiver;
/// Ret - The effect on the return value. Used to indicate if the
- /// function/method call returns a new tracked symbol, returns an
- /// alias of one of the arguments in the call, and so on.
+ /// function/method call returns a new tracked symbol.
RetEffect Ret;
- /// EndPath - Indicates that execution of this method/function should
- /// terminate the simulation of a path.
- bool EndPath;
-
public:
RetainSummary(ArgEffects A, RetEffect R, ArgEffect defaultEff,
- ArgEffect ReceiverEff, bool endpath = false)
- : Args(A), DefaultArgEffect(defaultEff), Receiver(ReceiverEff), Ret(R),
- EndPath(endpath) {}
+ ArgEffect ReceiverEff)
+ : Args(A), DefaultArgEffect(defaultEff), Receiver(ReceiverEff), Ret(R) {}
/// getArg - Return the argument effect on the argument specified by
/// idx (starting from 0).
@@ -474,10 +404,6 @@ public:
/// setRetEffect - Set the effect of the return value of the call.
void setRetEffect(RetEffect E) { Ret = E; }
- /// isEndPath - Returns true if executing the given method/function should
- /// terminate the path.
- bool isEndPath() const { return EndPath; }
-
/// Sets the effect on the receiver of the message.
void setReceiverEffect(ArgEffect e) { Receiver = e; }
@@ -485,6 +411,14 @@ public:
/// getReceiverEffect - Returns the effect on the receiver of the call.
/// This is only meaningful if the summary applies to an ObjCMessageExpr*.
ArgEffect getReceiverEffect() const { return Receiver; }
+
+ /// Test if two retain summaries are identical. Note that merely equivalent
+ /// summaries are not necessarily identical (for example, if an explicit
+ /// argument effect matches the default effect).
+ bool operator==(const RetainSummary &Other) const {
+ return Args == Other.Args && DefaultArgEffect == Other.DefaultArgEffect &&
+ Receiver == Other.Receiver && Ret == Other.Ret;
+ }
};
} // end anonymous namespace
@@ -500,10 +434,10 @@ public:
ObjCSummaryKey(IdentifierInfo* ii, Selector s)
: II(ii), S(s) {}
- ObjCSummaryKey(const ObjCInterfaceDecl* d, Selector s)
+ ObjCSummaryKey(const ObjCInterfaceDecl *d, Selector s)
: II(d ? d->getIdentifier() : 0), S(s) {}
- ObjCSummaryKey(const ObjCInterfaceDecl* d, IdentifierInfo *ii, Selector s)
+ ObjCSummaryKey(const ObjCInterfaceDecl *d, IdentifierInfo *ii, Selector s)
: II(d ? d->getIdentifier() : ii), S(s) {}
ObjCSummaryKey(Selector s)
@@ -547,19 +481,19 @@ struct isPodLike<ObjCSummaryKey> { static const bool value = true; };
namespace {
class ObjCSummaryCache {
- typedef llvm::DenseMap<ObjCSummaryKey, RetainSummary*> MapTy;
+ typedef llvm::DenseMap<ObjCSummaryKey, const RetainSummary *> MapTy;
MapTy M;
public:
ObjCSummaryCache() {}
- RetainSummary* find(const ObjCInterfaceDecl* D, IdentifierInfo *ClsName,
+ const RetainSummary * find(const ObjCInterfaceDecl *D, IdentifierInfo *ClsName,
Selector S) {
// Lookup the method using the decl for the class @interface. If we
// have no decl, lookup using the class name.
return D ? find(D, S) : find(ClsName, S);
}
- RetainSummary* find(const ObjCInterfaceDecl* D, Selector S) {
+ const RetainSummary * find(const ObjCInterfaceDecl *D, Selector S) {
// Do a lookup with the (D,S) pair. If we find a match return
// the iterator.
ObjCSummaryKey K(D, S);
@@ -574,7 +508,7 @@ public:
// generate initial summaries without having to worry about NSObject
// being declared.
// FIXME: We may change this at some point.
- for (ObjCInterfaceDecl* C=D->getSuperClass() ;; C=C->getSuperClass()) {
+ for (ObjCInterfaceDecl *C=D->getSuperClass() ;; C=C->getSuperClass()) {
if ((I = M.find(ObjCSummaryKey(C, S))) != M.end())
break;
@@ -584,12 +518,12 @@ public:
// Cache the summary with original key to make the next lookup faster
// and return the iterator.
- RetainSummary *Summ = I->second;
+ const RetainSummary *Summ = I->second;
M[K] = Summ;
return Summ;
}
- RetainSummary* find(IdentifierInfo* II, Selector S) {
+ const RetainSummary * find(IdentifierInfo* II, Selector S) {
// FIXME: Class method lookup. Right now we dont' have a good way
// of going between IdentifierInfo* and the class hierarchy.
MapTy::iterator I = M.find(ObjCSummaryKey(II, S));
@@ -600,11 +534,11 @@ public:
return I == M.end() ? NULL : I->second;
}
- RetainSummary*& operator[](ObjCSummaryKey K) {
+ const RetainSummary *& operator[](ObjCSummaryKey K) {
return M[K];
}
- RetainSummary*& operator[](Selector S) {
+ const RetainSummary *& operator[](Selector S) {
return M[ ObjCSummaryKey(S) ];
}
};
@@ -621,7 +555,7 @@ class RetainSummaryManager {
// Typedefs.
//==-----------------------------------------------------------------==//
- typedef llvm::DenseMap<const FunctionDecl*, RetainSummary*>
+ typedef llvm::DenseMap<const FunctionDecl*, const RetainSummary *>
FuncSummariesTy;
typedef ObjCSummaryCache ObjCMethodSummariesTy;
@@ -631,11 +565,7 @@ class RetainSummaryManager {
//==-----------------------------------------------------------------==//
/// Ctx - The ASTContext object for the analyzed ASTs.
- ASTContext& Ctx;
-
- /// CFDictionaryCreateII - An IdentifierInfo* representing the indentifier
- /// "CFDictionaryCreate".
- IdentifierInfo* CFDictionaryCreateII;
+ ASTContext &Ctx;
/// GCEnabled - Records whether or not the analyzed code runs in GC mode.
const bool GCEnabled;
@@ -672,7 +602,7 @@ class RetainSummaryManager {
RetEffect ObjCInitRetE;
RetainSummary DefaultSummary;
- RetainSummary* StopSummary;
+ const RetainSummary *StopSummary;
//==-----------------------------------------------------------------==//
// Methods.
@@ -687,30 +617,28 @@ class RetainSummaryManager {
public:
RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; }
- RetainSummary *getDefaultSummary() {
- RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>();
- return new (Summ) RetainSummary(DefaultSummary);
+ const RetainSummary *getDefaultSummary() {
+ return &DefaultSummary;
}
+
+ const RetainSummary * getUnarySummary(const FunctionType* FT,
+ UnaryFuncKind func);
- RetainSummary* getUnarySummary(const FunctionType* FT, UnaryFuncKind func);
-
- RetainSummary* getCFSummaryCreateRule(const FunctionDecl* FD);
- RetainSummary* getCFSummaryGetRule(const FunctionDecl* FD);
- RetainSummary* getCFCreateGetRuleSummary(const FunctionDecl* FD,
- StringRef FName);
+ const RetainSummary * getCFSummaryCreateRule(const FunctionDecl *FD);
+ const RetainSummary * getCFSummaryGetRule(const FunctionDecl *FD);
+ const RetainSummary * getCFCreateGetRuleSummary(const FunctionDecl *FD);
- RetainSummary* getPersistentSummary(ArgEffects AE, RetEffect RetEff,
- ArgEffect ReceiverEff = DoNothing,
- ArgEffect DefaultEff = MayEscape,
- bool isEndPath = false);
+ const RetainSummary * getPersistentSummary(ArgEffects AE, RetEffect RetEff,
+ ArgEffect ReceiverEff = DoNothing,
+ ArgEffect DefaultEff = MayEscape);
- RetainSummary* getPersistentSummary(RetEffect RE,
- ArgEffect ReceiverEff = DoNothing,
- ArgEffect DefaultEff = MayEscape) {
+ const RetainSummary * getPersistentSummary(RetEffect RE,
+ ArgEffect ReceiverEff = DoNothing,
+ ArgEffect DefaultEff = MayEscape) {
return getPersistentSummary(getArgEffects(), RE, ReceiverEff, DefaultEff);
}
- RetainSummary *getPersistentStopSummary() {
+ const RetainSummary *getPersistentStopSummary() {
if (StopSummary)
return StopSummary;
@@ -720,35 +648,35 @@ public:
return StopSummary;
}
- RetainSummary *getInitMethodSummary(QualType RetTy);
+ const RetainSummary *getInitMethodSummary(QualType RetTy);
void InitializeClassMethodSummaries();
void InitializeMethodSummaries();
private:
- void addNSObjectClsMethSummary(Selector S, RetainSummary *Summ) {
+ void addNSObjectClsMethSummary(Selector S, const RetainSummary *Summ) {
ObjCClassMethodSummaries[S] = Summ;
}
- void addNSObjectMethSummary(Selector S, RetainSummary *Summ) {
+ void addNSObjectMethSummary(Selector S, const RetainSummary *Summ) {
ObjCMethodSummaries[S] = Summ;
}
void addClassMethSummary(const char* Cls, const char* nullaryName,
- RetainSummary *Summ) {
+ const RetainSummary *Summ) {
IdentifierInfo* ClsII = &Ctx.Idents.get(Cls);
Selector S = GetNullarySelector(nullaryName, Ctx);
ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ;
}
void addInstMethSummary(const char* Cls, const char* nullaryName,
- RetainSummary *Summ) {
+ const RetainSummary *Summ) {
IdentifierInfo* ClsII = &Ctx.Idents.get(Cls);
Selector S = GetNullarySelector(nullaryName, Ctx);
ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ;
}
Selector generateSelector(va_list argp) {
- llvm::SmallVector<IdentifierInfo*, 10> II;
+ SmallVector<IdentifierInfo*, 10> II;
while (const char* s = va_arg(argp, const char*))
II.push_back(&Ctx.Idents.get(s));
@@ -757,47 +685,36 @@ private:
}
void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy& Summaries,
- RetainSummary* Summ, va_list argp) {
+ const RetainSummary * Summ, va_list argp) {
Selector S = generateSelector(argp);
Summaries[ObjCSummaryKey(ClsII, S)] = Summ;
}
- void addInstMethSummary(const char* Cls, RetainSummary* Summ, ...) {
+ void addInstMethSummary(const char* Cls, const RetainSummary * Summ, ...) {
va_list argp;
va_start(argp, Summ);
addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, argp);
va_end(argp);
}
- void addClsMethSummary(const char* Cls, RetainSummary* Summ, ...) {
+ void addClsMethSummary(const char* Cls, const RetainSummary * Summ, ...) {
va_list argp;
va_start(argp, Summ);
addMethodSummary(&Ctx.Idents.get(Cls),ObjCClassMethodSummaries, Summ, argp);
va_end(argp);
}
- void addClsMethSummary(IdentifierInfo *II, RetainSummary* Summ, ...) {
+ void addClsMethSummary(IdentifierInfo *II, const RetainSummary * Summ, ...) {
va_list argp;
va_start(argp, Summ);
addMethodSummary(II, ObjCClassMethodSummaries, Summ, argp);
va_end(argp);
}
- void addPanicSummary(const char* Cls, ...) {
- RetainSummary* Summ = getPersistentSummary(AF.getEmptyMap(),
- RetEffect::MakeNoRet(),
- DoNothing, DoNothing, true);
- va_list argp;
- va_start (argp, Cls);
- addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, argp);
- va_end(argp);
- }
-
public:
- RetainSummaryManager(ASTContext& ctx, bool gcenabled, bool usesARC)
+ RetainSummaryManager(ASTContext &ctx, bool gcenabled, bool usesARC)
: Ctx(ctx),
- CFDictionaryCreateII(&ctx.Idents.get("CFDictionaryCreate")),
GCEnabled(gcenabled),
ARCEnabled(usesARC),
AF(BPAlloc), ScratchArgs(AF.getEmptyMap()),
@@ -819,31 +736,31 @@ public:
InitializeMethodSummaries();
}
- ~RetainSummaryManager();
-
- RetainSummary* getSummary(const FunctionDecl* FD);
+ const RetainSummary * getSummary(const FunctionDecl *FD);
- RetainSummary *getInstanceMethodSummary(const ObjCMessage &msg,
- const GRState *state,
- const LocationContext *LC);
+ const RetainSummary *getInstanceMethodSummary(const ObjCMessage &msg,
+ const ProgramState *state,
+ const LocationContext *LC);
- RetainSummary* getInstanceMethodSummary(const ObjCMessage &msg,
- const ObjCInterfaceDecl* ID) {
+ const RetainSummary * getInstanceMethodSummary(const ObjCMessage &msg,
+ const ObjCInterfaceDecl *ID) {
return getInstanceMethodSummary(msg.getSelector(), 0,
ID, msg.getMethodDecl(), msg.getType(Ctx));
}
- RetainSummary* getInstanceMethodSummary(Selector S, IdentifierInfo *ClsName,
- const ObjCInterfaceDecl* ID,
- const ObjCMethodDecl *MD,
- QualType RetTy);
+ const RetainSummary * getInstanceMethodSummary(Selector S,
+ IdentifierInfo *ClsName,
+ const ObjCInterfaceDecl *ID,
+ const ObjCMethodDecl *MD,
+ QualType RetTy);
- RetainSummary *getClassMethodSummary(Selector S, IdentifierInfo *ClsName,
- const ObjCInterfaceDecl *ID,
- const ObjCMethodDecl *MD,
- QualType RetTy);
+ const RetainSummary *getClassMethodSummary(Selector S,
+ IdentifierInfo *ClsName,
+ const ObjCInterfaceDecl *ID,
+ const ObjCMethodDecl *MD,
+ QualType RetTy);
- RetainSummary *getClassMethodSummary(const ObjCMessage &msg) {
+ const RetainSummary *getClassMethodSummary(const ObjCMessage &msg) {
const ObjCInterfaceDecl *Class = 0;
if (!msg.isInstanceMessage())
Class = msg.getReceiverInterface();
@@ -856,30 +773,26 @@ public:
/// getMethodSummary - This version of getMethodSummary is used to query
/// the summary for the current method being analyzed.
- RetainSummary *getMethodSummary(const ObjCMethodDecl *MD) {
+ const RetainSummary *getMethodSummary(const ObjCMethodDecl *MD) {
// FIXME: Eventually this should be unneeded.
const ObjCInterfaceDecl *ID = MD->getClassInterface();
Selector S = MD->getSelector();
IdentifierInfo *ClsName = ID->getIdentifier();
QualType ResultTy = MD->getResultType();
- // Resolve the method decl last.
- if (const ObjCMethodDecl *InterfaceMD = ResolveToInterfaceMethodDecl(MD))
- MD = InterfaceMD;
-
if (MD->isInstanceMethod())
return getInstanceMethodSummary(S, ClsName, ID, MD, ResultTy);
else
return getClassMethodSummary(S, ClsName, ID, MD, ResultTy);
}
- RetainSummary* getCommonMethodSummary(const ObjCMethodDecl* MD,
- Selector S, QualType RetTy);
+ const RetainSummary * getCommonMethodSummary(const ObjCMethodDecl *MD,
+ Selector S, QualType RetTy);
- void updateSummaryFromAnnotations(RetainSummary &Summ,
+ void updateSummaryFromAnnotations(const RetainSummary *&Summ,
const ObjCMethodDecl *MD);
- void updateSummaryFromAnnotations(RetainSummary &Summ,
+ void updateSummaryFromAnnotations(const RetainSummary *&Summ,
const FunctionDecl *FD);
bool isGCEnabled() const { return GCEnabled; }
@@ -888,35 +801,69 @@ public:
bool isARCorGCEnabled() const { return GCEnabled || ARCEnabled; }
- RetainSummary *copySummary(RetainSummary *OldSumm) {
- RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>();
+ const RetainSummary *copySummary(const RetainSummary *OldSumm) {
+ RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>();
new (Summ) RetainSummary(*OldSumm);
return Summ;
}
};
+// Used to avoid allocating long-term (BPAlloc'd) memory for default retain
+// summaries. If a function or method looks like it has a default summary, but
+// it has annotations, the annotations are added to the stack-based template
+// and then copied into managed memory.
+class RetainSummaryTemplate {
+ RetainSummaryManager &Manager;
+ const RetainSummary *&RealSummary;
+ const RetainSummary *BaseSummary;
+ RetainSummary ScratchSummary;
+ bool Accessed;
+public:
+ RetainSummaryTemplate(const RetainSummary *&real, const RetainSummary &base,
+ RetainSummaryManager &manager)
+ : Manager(manager),
+ RealSummary(real),
+ BaseSummary(&base),
+ ScratchSummary(base),
+ Accessed(false) {}
+
+ ~RetainSummaryTemplate() {
+ if (Accessed)
+ RealSummary = Manager.copySummary(&ScratchSummary);
+ else if (!RealSummary)
+ RealSummary = BaseSummary;
+ }
+
+ RetainSummary &operator*() {
+ Accessed = true;
+ return ScratchSummary;
+ }
+
+ RetainSummary *operator->() {
+ Accessed = true;
+ return &ScratchSummary;
+ }
+};
+
} // end anonymous namespace
//===----------------------------------------------------------------------===//
// Implementation of checker data structures.
//===----------------------------------------------------------------------===//
-RetainSummaryManager::~RetainSummaryManager() {}
-
ArgEffects RetainSummaryManager::getArgEffects() {
ArgEffects AE = ScratchArgs;
ScratchArgs = AF.getEmptyMap();
return AE;
}
-RetainSummary*
+const RetainSummary *
RetainSummaryManager::getPersistentSummary(ArgEffects AE, RetEffect RetEff,
ArgEffect ReceiverEff,
- ArgEffect DefaultEff,
- bool isEndPath) {
+ ArgEffect DefaultEff) {
// Create the summary and return it.
- RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>();
- new (Summ) RetainSummary(AE, RetEff, DefaultEff, ReceiverEff, isEndPath);
+ RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>();
+ new (Summ) RetainSummary(AE, RetEff, DefaultEff, ReceiverEff);
return Summ;
}
@@ -924,22 +871,28 @@ RetainSummaryManager::getPersistentSummary(ArgEffects AE, RetEffect RetEff,
// Summary creation for functions (largely uses of Core Foundation).
//===----------------------------------------------------------------------===//
-static bool isRetain(const FunctionDecl* FD, StringRef FName) {
+static bool isRetain(const FunctionDecl *FD, StringRef FName) {
return FName.endswith("Retain");
}
-static bool isRelease(const FunctionDecl* FD, StringRef FName) {
+static bool isRelease(const FunctionDecl *FD, StringRef FName) {
return FName.endswith("Release");
}
-RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl* FD) {
+static bool isMakeCollectable(const FunctionDecl *FD, StringRef FName) {
+ // FIXME: Remove FunctionDecl parameter.
+ // FIXME: Is it really okay if MakeCollectable isn't a suffix?
+ return FName.find("MakeCollectable") != StringRef::npos;
+}
+
+const RetainSummary * RetainSummaryManager::getSummary(const FunctionDecl *FD) {
// Look up a summary in our cache of FunctionDecls -> Summaries.
FuncSummariesTy::iterator I = FuncSummaries.find(FD);
if (I != FuncSummaries.end())
return I->second;
// No summary? Generate one.
- RetainSummary *S = 0;
+ const RetainSummary *S = 0;
do {
// We generate "stop" summaries for implicitly defined functions.
@@ -1054,10 +1007,10 @@ RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl* FD) {
if (cocoa::isRefType(RetTy, "CF", FName)) {
if (isRetain(FD, FName))
S = getUnarySummary(FT, cfretain);
- else if (FName.find("MakeCollectable") != StringRef::npos)
+ else if (isMakeCollectable(FD, FName))
S = getUnarySummary(FT, cfmakecollectable);
else
- S = getCFCreateGetRuleSummary(FD, FName);
+ S = getCFCreateGetRuleSummary(FD);
break;
}
@@ -1067,7 +1020,7 @@ RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl* FD) {
if (isRetain(FD, FName))
S = getUnarySummary(FT, cfretain);
else
- S = getCFCreateGetRuleSummary(FD, FName);
+ S = getCFCreateGetRuleSummary(FD);
break;
}
@@ -1076,7 +1029,7 @@ RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl* FD) {
if (cocoa::isRefType(RetTy, "DADisk") ||
cocoa::isRefType(RetTy, "DADissenter") ||
cocoa::isRefType(RetTy, "DASessionRef")) {
- S = getCFCreateGetRuleSummary(FD, FName);
+ S = getCFCreateGetRuleSummary(FD);
break;
}
@@ -1121,27 +1074,22 @@ RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl* FD) {
}
while (0);
- if (!S)
- S = getDefaultSummary();
-
// Annotations override defaults.
- assert(S);
- updateSummaryFromAnnotations(*S, FD);
+ updateSummaryFromAnnotations(S, FD);
FuncSummaries[FD] = S;
return S;
}
-RetainSummary*
-RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl* FD,
- StringRef FName) {
- if (coreFoundation::followsCreateRule(FName))
+const RetainSummary *
+RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl *FD) {
+ if (coreFoundation::followsCreateRule(FD))
return getCFSummaryCreateRule(FD);
return getCFSummaryGetRule(FD);
}
-RetainSummary*
+const RetainSummary *
RetainSummaryManager::getUnarySummary(const FunctionType* FT,
UnaryFuncKind func) {
@@ -1153,44 +1101,27 @@ RetainSummaryManager::getUnarySummary(const FunctionType* FT,
assert (ScratchArgs.isEmpty());
+ ArgEffect Effect;
switch (func) {
- case cfretain: {
- ScratchArgs = AF.add(ScratchArgs, 0, IncRef);
- return getPersistentSummary(RetEffect::MakeAlias(0),
- DoNothing, DoNothing);
- }
-
- case cfrelease: {
- ScratchArgs = AF.add(ScratchArgs, 0, DecRef);
- return getPersistentSummary(RetEffect::MakeNoRet(),
- DoNothing, DoNothing);
- }
-
- case cfmakecollectable: {
- ScratchArgs = AF.add(ScratchArgs, 0, MakeCollectable);
- return getPersistentSummary(RetEffect::MakeAlias(0),DoNothing, DoNothing);
- }
-
- default:
- assert (false && "Not a supported unary function.");
- return getDefaultSummary();
+ case cfretain: Effect = IncRef; break;
+ case cfrelease: Effect = DecRef; break;
+ case cfmakecollectable: Effect = MakeCollectable; break;
+ default: llvm_unreachable("Not a supported unary function.");
}
+
+ ScratchArgs = AF.add(ScratchArgs, 0, Effect);
+ return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
}
-RetainSummary*
-RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl* FD) {
+const RetainSummary *
+RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) {
assert (ScratchArgs.isEmpty());
- if (FD->getIdentifier() == CFDictionaryCreateII) {
- ScratchArgs = AF.add(ScratchArgs, 1, DoNothingByRef);
- ScratchArgs = AF.add(ScratchArgs, 2, DoNothingByRef);
- }
-
return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true));
}
-RetainSummary*
-RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl* FD) {
+const RetainSummary *
+RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {
assert (ScratchArgs.isEmpty());
return getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::CF),
DoNothing, DoNothing);
@@ -1200,7 +1131,7 @@ RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl* FD) {
// Summary creation for Selectors.
//===----------------------------------------------------------------------===//
-RetainSummary*
+const RetainSummary *
RetainSummaryManager::getInitMethodSummary(QualType RetTy) {
assert(ScratchArgs.isEmpty());
// 'init' methods conceptually return a newly allocated object and claim
@@ -1213,22 +1144,24 @@ RetainSummaryManager::getInitMethodSummary(QualType RetTy) {
}
void
-RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
+RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
const FunctionDecl *FD) {
if (!FD)
return;
+ RetainSummaryTemplate Template(Summ, DefaultSummary, *this);
+
// Effects on the parameters.
unsigned parm_idx = 0;
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)
- Summ.addArg(AF, parm_idx, DecRef);
- }
- else if(pd->getAttr<CFConsumedAttr>()) {
- Summ.addArg(AF, parm_idx, DecRef);
+ if (!GCEnabled) {
+ Template->addArg(AF, parm_idx, DecRef);
+ }
+ } else if (pd->getAttr<CFConsumedAttr>()) {
+ Template->addArg(AF, parm_idx, DecRef);
}
}
@@ -1237,83 +1170,84 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
// Determine if there is a special return effect for this method.
if (cocoa::isCocoaObjectRef(RetTy)) {
if (FD->getAttr<NSReturnsRetainedAttr>()) {
- Summ.setRetEffect(ObjCAllocRetE);
+ Template->setRetEffect(ObjCAllocRetE);
}
else if (FD->getAttr<CFReturnsRetainedAttr>()) {
- Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
+ Template->setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
}
else if (FD->getAttr<NSReturnsNotRetainedAttr>()) {
- Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC));
+ Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC));
}
else if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
- Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
+ Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
}
- }
- else if (RetTy->getAs<PointerType>()) {
+ } else if (RetTy->getAs<PointerType>()) {
if (FD->getAttr<CFReturnsRetainedAttr>()) {
- Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
+ Template->setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
}
else if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
- Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
+ Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
}
}
}
void
-RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
- const ObjCMethodDecl *MD) {
+RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
+ const ObjCMethodDecl *MD) {
if (!MD)
return;
+ RetainSummaryTemplate Template(Summ, DefaultSummary, *this);
+
bool isTrackedLoc = false;
// Effects on the receiver.
if (MD->getAttr<NSConsumesSelfAttr>()) {
if (!GCEnabled)
- Summ.setReceiverEffect(DecRefMsg);
+ Template->setReceiverEffect(DecRefMsg);
}
// Effects on the parameters.
unsigned parm_idx = 0;
- for (ObjCMethodDecl::param_iterator pi=MD->param_begin(), pe=MD->param_end();
+ for (ObjCMethodDecl::param_const_iterator
+ pi=MD->param_begin(), pe=MD->param_end();
pi != pe; ++pi, ++parm_idx) {
const ParmVarDecl *pd = *pi;
if (pd->getAttr<NSConsumedAttr>()) {
if (!GCEnabled)
- Summ.addArg(AF, parm_idx, DecRef);
+ Template->addArg(AF, parm_idx, DecRef);
}
else if(pd->getAttr<CFConsumedAttr>()) {
- Summ.addArg(AF, parm_idx, DecRef);
+ 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>()) {
- Summ.setRetEffect(ObjCAllocRetE);
+ Template->setRetEffect(ObjCAllocRetE);
return;
}
if (MD->getAttr<NSReturnsNotRetainedAttr>()) {
- Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC));
+ Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC));
return;
}
isTrackedLoc = true;
- }
-
- if (!isTrackedLoc)
+ } else {
isTrackedLoc = MD->getResultType()->getAs<PointerType>() != NULL;
+ }
if (isTrackedLoc) {
if (MD->getAttr<CFReturnsRetainedAttr>())
- Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
+ Template->setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
else if (MD->getAttr<CFReturnsNotRetainedAttr>())
- Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
+ Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
}
}
-RetainSummary*
-RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
+const RetainSummary *
+RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl *MD,
Selector S, QualType RetTy) {
if (MD) {
@@ -1322,9 +1256,9 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
// Delegates are a frequent form of false positives with the retain
// count checker.
unsigned i = 0;
- for (ObjCMethodDecl::param_iterator I = MD->param_begin(),
+ for (ObjCMethodDecl::param_const_iterator I = MD->param_begin(),
E = MD->param_end(); I != E; ++I, ++i)
- if (ParmVarDecl *PD = *I) {
+ if (const ParmVarDecl *PD = *I) {
QualType Ty = Ctx.getCanonicalType(PD->getType());
if (Ty.getLocalUnqualifiedType() == Ctx.VoidPtrTy)
ScratchArgs = AF.add(ScratchArgs, i, StopTracking);
@@ -1370,15 +1304,15 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
return getPersistentSummary(RetEffect::MakeNoRet(), ReceiverEff, MayEscape);
}
-RetainSummary*
+const RetainSummary *
RetainSummaryManager::getInstanceMethodSummary(const ObjCMessage &msg,
- const GRState *state,
+ const ProgramState *state,
const LocationContext *LC) {
// We need the type-information of the tracked receiver object
// Retrieve it from the state.
const Expr *Receiver = msg.getInstanceReceiver();
- const ObjCInterfaceDecl* ID = 0;
+ const ObjCInterfaceDecl *ID = 0;
// FIXME: Is this really working as expected? There are cases where
// we just use the 'ID' from the message expression.
@@ -1410,19 +1344,18 @@ RetainSummaryManager::getInstanceMethodSummary(const ObjCMessage &msg,
// FIXME: The receiver could be a reference to a class, meaning that
// we should use the class method.
- RetainSummary *Summ = getInstanceMethodSummary(msg, ID);
- return Summ ? Summ : getDefaultSummary();
+ return getInstanceMethodSummary(msg, ID);
}
-RetainSummary*
+const RetainSummary *
RetainSummaryManager::getInstanceMethodSummary(Selector S,
IdentifierInfo *ClsName,
- const ObjCInterfaceDecl* ID,
+ const ObjCInterfaceDecl *ID,
const ObjCMethodDecl *MD,
QualType RetTy) {
// Look up a summary in our summary cache.
- RetainSummary *Summ = ObjCMethodSummaries.find(ID, ClsName, S);
+ const RetainSummary *Summ = ObjCMethodSummaries.find(ID, ClsName, S);
if (!Summ) {
assert(ScratchArgs.isEmpty());
@@ -1434,7 +1367,7 @@ RetainSummaryManager::getInstanceMethodSummary(Selector S,
Summ = getCommonMethodSummary(MD, S, RetTy);
// Annotations override defaults.
- updateSummaryFromAnnotations(*Summ, MD);
+ updateSummaryFromAnnotations(Summ, MD);
// Memoize the summary.
ObjCMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ;
@@ -1443,19 +1376,21 @@ RetainSummaryManager::getInstanceMethodSummary(Selector S,
return Summ;
}
-RetainSummary*
+const RetainSummary *
RetainSummaryManager::getClassMethodSummary(Selector S, IdentifierInfo *ClsName,
const ObjCInterfaceDecl *ID,
const ObjCMethodDecl *MD,
QualType RetTy) {
assert(ClsName && "Class name must be specified.");
- RetainSummary *Summ = ObjCClassMethodSummaries.find(ID, ClsName, S);
+ const RetainSummary *Summ = ObjCClassMethodSummaries.find(ID, ClsName, S);
if (!Summ) {
Summ = getCommonMethodSummary(MD, S, RetTy);
+
// Annotations override defaults.
- updateSummaryFromAnnotations(*Summ, MD);
+ updateSummaryFromAnnotations(Summ, MD);
+
// Memoize the summary.
ObjCClassMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ;
}
@@ -1465,8 +1400,6 @@ RetainSummaryManager::getClassMethodSummary(Selector S, IdentifierInfo *ClsName,
void RetainSummaryManager::InitializeClassMethodSummaries() {
assert(ScratchArgs.isEmpty());
- RetainSummary* Summ = getPersistentSummary(ObjCAllocRetE);
-
// Create the [NSAssertionHandler currentHander] summary.
addClassMethSummary("NSAssertionHandler", "currentHandler",
getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::ObjC)));
@@ -1482,7 +1415,8 @@ void RetainSummaryManager::InitializeClassMethodSummaries() {
// used for delegates that can release the object. When we have better
// inter-procedural analysis we can potentially do something better. This
// workaround is to remove false positives.
- Summ = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, StopTracking);
+ const RetainSummary *Summ =
+ getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, StopTracking);
IdentifierInfo *NSObjectII = &Ctx.Idents.get("NSObject");
addClsMethSummary(NSObjectII, Summ, "performSelector", "withObject",
"afterDelay", NULL);
@@ -1506,7 +1440,7 @@ void RetainSummaryManager::InitializeMethodSummaries() {
// Create the "init" selector. It just acts as a pass-through for the
// receiver.
- RetainSummary *InitSumm = getPersistentSummary(ObjCInitRetE, DecRefMsg);
+ const RetainSummary *InitSumm = getPersistentSummary(ObjCInitRetE, DecRefMsg);
addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm);
// awakeAfterUsingCoder: behaves basically like an 'init' method. It
@@ -1515,35 +1449,34 @@ void RetainSummaryManager::InitializeMethodSummaries() {
InitSumm);
// The next methods are allocators.
- RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE);
- RetainSummary *CFAllocSumm =
+ const RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE);
+ const RetainSummary *CFAllocSumm =
getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true));
// Create the "retain" selector.
- RetEffect E = RetEffect::MakeReceiverAlias();
- RetainSummary *Summ = getPersistentSummary(E, IncRefMsg);
+ RetEffect NoRet = RetEffect::MakeNoRet();
+ const RetainSummary *Summ = getPersistentSummary(NoRet, IncRefMsg);
addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ);
// Create the "release" selector.
- Summ = getPersistentSummary(E, DecRefMsg);
+ Summ = getPersistentSummary(NoRet, DecRefMsg);
addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ);
// Create the "drain" selector.
- Summ = getPersistentSummary(E, isGCEnabled() ? DoNothing : DecRef);
+ Summ = getPersistentSummary(NoRet, isGCEnabled() ? DoNothing : DecRef);
addNSObjectMethSummary(GetNullarySelector("drain", Ctx), Summ);
// Create the -dealloc summary.
- Summ = getPersistentSummary(RetEffect::MakeNoRet(), Dealloc);
+ Summ = getPersistentSummary(NoRet, Dealloc);
addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ);
// Create the "autorelease" selector.
- Summ = getPersistentSummary(E, Autorelease);
+ Summ = getPersistentSummary(NoRet, Autorelease);
addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ);
// Specially handle NSAutoreleasePool.
addInstMethSummary("NSAutoreleasePool", "init",
- getPersistentSummary(RetEffect::MakeReceiverAlias(),
- NewAutoreleasePool));
+ getPersistentSummary(NoRet, NewAutoreleasePool));
// For NSWindow, allocated objects are (initially) self-owned.
// FIXME: For now we opt for false negatives with NSWindow, as these objects
@@ -1551,7 +1484,7 @@ void RetainSummaryManager::InitializeMethodSummaries() {
// Thus, we need to track an NSWindow's display status.
// This is tracked in <rdar://problem/6062711>.
// See also http://llvm.org/bugs/show_bug.cgi?id=3714.
- RetainSummary *NoTrackYet = getPersistentSummary(RetEffect::MakeNoRet(),
+ const RetainSummary *NoTrackYet = getPersistentSummary(RetEffect::MakeNoRet(),
StopTracking,
StopTracking);
@@ -1583,13 +1516,6 @@ void RetainSummaryManager::InitializeMethodSummaries() {
// exit a method.
addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet);
- // Create NSAssertionHandler summaries.
- addPanicSummary("NSAssertionHandler", "handleFailureInFunction", "file",
- "lineNumber", "description", NULL);
-
- addPanicSummary("NSAssertionHandler", "handleFailureInMethod", "object",
- "file", "lineNumber", "description", NULL);
-
// Create summaries QCRenderer/QCView -createSnapShotImageOfType:
addInstMethSummary("QCRenderer", AllocSumm,
"createSnapshotImageOfType", NULL);
@@ -1623,26 +1549,27 @@ namespace { class AutoreleaseStack {}; }
namespace clang {
namespace ento {
-template<> struct GRStateTrait<AutoreleaseStack>
- : public GRStatePartialTrait<ARStack> {
- static inline void* GDMIndex() { return &AutoRBIndex; }
+template<> struct ProgramStateTrait<AutoreleaseStack>
+ : public ProgramStatePartialTrait<ARStack> {
+ static inline void *GDMIndex() { return &AutoRBIndex; }
};
-template<> struct GRStateTrait<AutoreleasePoolContents>
- : public GRStatePartialTrait<ARPoolContents> {
- static inline void* GDMIndex() { return &AutoRCIndex; }
+template<> struct ProgramStateTrait<AutoreleasePoolContents>
+ : public ProgramStatePartialTrait<ARPoolContents> {
+ static inline void *GDMIndex() { return &AutoRCIndex; }
};
} // end GR namespace
} // end clang namespace
-static SymbolRef GetCurrentAutoreleasePool(const GRState* state) {
+static SymbolRef GetCurrentAutoreleasePool(const ProgramState *state) {
ARStack stack = state->get<AutoreleaseStack>();
return stack.isEmpty() ? SymbolRef() : stack.getHead();
}
-static const GRState * SendAutorelease(const GRState *state,
- ARCounts::Factory &F, SymbolRef sym) {
-
+static const ProgramState *
+SendAutorelease(const ProgramState *state,
+ ARCounts::Factory &F,
+ SymbolRef sym) {
SymbolRef pool = GetCurrentAutoreleasePool(state);
const ARCounts *cnts = state->get<AutoreleasePoolContents>(pool);
ARCounts newCnts(0);
@@ -1658,196 +1585,11 @@ static const GRState * SendAutorelease(const GRState *state,
}
//===----------------------------------------------------------------------===//
-// Transfer functions.
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class CFRefCount : public TransferFuncs {
-public:
- class BindingsPrinter : public GRState::Printer {
- public:
- virtual void Print(llvm::raw_ostream& Out, const GRState* state,
- const char* nl, const char* sep);
- };
-
- typedef llvm::DenseMap<const ExplodedNode*, const RetainSummary*>
- SummaryLogTy;
-
- RetainSummaryManager Summaries;
- SummaryLogTy SummaryLog;
- const LangOptions& LOpts;
- ARCounts::Factory ARCountFactory;
-
- BugType *useAfterRelease, *releaseNotOwned;
- BugType *deallocGC, *deallocNotOwned;
- BugType *leakWithinFunction, *leakAtReturn;
- BugType *overAutorelease;
- BugType *returnNotOwnedForOwned;
- BugReporter *BR;
-
- const GRState * Update(const GRState * state, SymbolRef sym, RefVal V, ArgEffect E,
- RefVal::Kind& hasErr);
-
- void ProcessNonLeakError(ExplodedNodeSet& Dst,
- StmtNodeBuilder& Builder,
- const Expr* NodeExpr, SourceRange ErrorRange,
- ExplodedNode* Pred,
- const GRState* St,
- RefVal::Kind hasErr, SymbolRef Sym);
-
- const GRState * HandleSymbolDeath(const GRState * state, SymbolRef sid, RefVal V,
- llvm::SmallVectorImpl<SymbolRef> &Leaked);
-
- ExplodedNode* ProcessLeaks(const GRState * state,
- llvm::SmallVectorImpl<SymbolRef> &Leaked,
- GenericNodeBuilderRefCount &Builder,
- ExprEngine &Eng,
- ExplodedNode *Pred = 0);
-
-public:
- CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts)
- : Summaries(Ctx, gcenabled, (bool)lopts.ObjCAutoRefCount),
- LOpts(lopts), useAfterRelease(0), releaseNotOwned(0),
- deallocGC(0), deallocNotOwned(0),
- leakWithinFunction(0), leakAtReturn(0), overAutorelease(0),
- returnNotOwnedForOwned(0), BR(0) {}
-
- virtual ~CFRefCount() {}
-
- void RegisterChecks(ExprEngine &Eng);
-
- virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {
- Printers.push_back(new BindingsPrinter());
- }
-
- bool isGCEnabled() const { return Summaries.isGCEnabled(); }
- bool isARCorGCEnabled() const { return Summaries.isARCorGCEnabled(); }
-
- const LangOptions& getLangOptions() const { return LOpts; }
-
- const RetainSummary *getSummaryOfNode(const ExplodedNode *N) const {
- SummaryLogTy::const_iterator I = SummaryLog.find(N);
- return I == SummaryLog.end() ? 0 : I->second;
- }
-
- // Calls.
-
- void evalSummary(ExplodedNodeSet& Dst,
- ExprEngine& Eng,
- StmtNodeBuilder& Builder,
- const Expr* Ex,
- const CallOrObjCMessage &callOrMsg,
- InstanceReceiver Receiver,
- const RetainSummary& Summ,
- const MemRegion *Callee,
- ExplodedNode* Pred, const GRState *state);
-
- virtual void evalCall(ExplodedNodeSet& Dst,
- ExprEngine& Eng,
- StmtNodeBuilder& Builder,
- const CallExpr* CE, SVal L,
- ExplodedNode* Pred);
-
-
- virtual void evalObjCMessage(ExplodedNodeSet& Dst,
- ExprEngine& Engine,
- StmtNodeBuilder& Builder,
- ObjCMessage msg,
- ExplodedNode* Pred,
- const GRState *state);
- // Stores.
- virtual void evalBind(StmtNodeBuilderRef& B, SVal location, SVal val);
-
- // End-of-path.
-
- virtual void evalEndPath(ExprEngine& Engine,
- EndOfFunctionNodeBuilder& Builder);
-
- virtual void evalDeadSymbols(ExplodedNodeSet& Dst,
- ExprEngine& Engine,
- StmtNodeBuilder& Builder,
- ExplodedNode* Pred,
- const GRState* state,
- SymbolReaper& SymReaper);
-
- std::pair<ExplodedNode*, const GRState *>
- HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilderRefCount Bd,
- ExplodedNode* Pred, ExprEngine &Eng,
- SymbolRef Sym, RefVal V, bool &stop);
- // Return statements.
-
- virtual void evalReturn(ExplodedNodeSet& Dst,
- ExprEngine& Engine,
- StmtNodeBuilder& Builder,
- const ReturnStmt* S,
- ExplodedNode* Pred);
-
- void evalReturnWithRetEffect(ExplodedNodeSet& Dst,
- ExprEngine& Engine,
- StmtNodeBuilder& Builder,
- const ReturnStmt* S,
- ExplodedNode* Pred,
- RetEffect RE, RefVal X,
- SymbolRef Sym, const GRState *state);
-
-
- // Assumptions.
-
- virtual const GRState *evalAssume(const GRState* state, SVal condition,
- bool assumption);
-};
-
-} // end anonymous namespace
-
-static void PrintPool(llvm::raw_ostream &Out, SymbolRef Sym,
- const GRState *state) {
- Out << ' ';
- if (Sym)
- Out << Sym->getSymbolID();
- else
- Out << "<pool>";
- Out << ":{";
-
- // Get the contents of the pool.
- if (const ARCounts *cnts = state->get<AutoreleasePoolContents>(Sym))
- for (ARCounts::iterator J=cnts->begin(), EJ=cnts->end(); J != EJ; ++J)
- Out << '(' << J.getKey() << ',' << J.getData() << ')';
-
- Out << '}';
-}
-
-void CFRefCount::BindingsPrinter::Print(llvm::raw_ostream& Out,
- const GRState* state,
- const char* nl, const char* sep) {
-
- RefBindings B = state->get<RefBindings>();
-
- if (!B.isEmpty())
- Out << sep << nl;
-
- for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
- Out << (*I).first << " : ";
- (*I).second.print(Out);
- Out << nl;
- }
-
- // Print the autorelease stack.
- Out << sep << nl << "AR pool stack:";
- ARStack stack = state->get<AutoreleaseStack>();
-
- PrintPool(Out, SymbolRef(), state); // Print the caller's pool.
- for (ARStack::iterator I=stack.begin(), E=stack.end(); I!=E; ++I)
- PrintPool(Out, *I, state);
-
- Out << nl;
-}
-
-//===----------------------------------------------------------------------===//
// Error reporting.
//===----------------------------------------------------------------------===//
-
namespace {
+ typedef llvm::DenseMap<const ExplodedNode *, const RetainSummary *>
+ SummaryLogTy;
//===-------------===//
// Bug Descriptions. //
@@ -1855,35 +1597,30 @@ namespace {
class CFRefBug : public BugType {
protected:
- CFRefCount& TF;
-
- CFRefBug(CFRefCount* tf, llvm::StringRef name)
- : BugType(name, "Memory (Core Foundation/Objective-C)"), TF(*tf) {}
+ CFRefBug(StringRef name)
+ : BugType(name, "Memory (Core Foundation/Objective-C)") {}
public:
- CFRefCount& getTF() { return TF; }
-
// FIXME: Eventually remove.
- virtual const char* getDescription() const = 0;
+ virtual const char *getDescription() const = 0;
virtual bool isLeak() const { return false; }
};
class UseAfterRelease : public CFRefBug {
public:
- UseAfterRelease(CFRefCount* tf)
- : CFRefBug(tf, "Use-after-release") {}
+ UseAfterRelease() : CFRefBug("Use-after-release") {}
- const char* getDescription() const {
+ const char *getDescription() const {
return "Reference-counted object is used after it is released";
}
};
class BadRelease : public CFRefBug {
public:
- BadRelease(CFRefCount* tf) : CFRefBug(tf, "Bad release") {}
+ BadRelease() : CFRefBug("Bad release") {}
- const char* getDescription() const {
+ const char *getDescription() const {
return "Incorrect decrement of the reference count of an object that is "
"not owned at this point by the caller";
}
@@ -1891,8 +1628,8 @@ namespace {
class DeallocGC : public CFRefBug {
public:
- DeallocGC(CFRefCount *tf)
- : CFRefBug(tf, "-dealloc called while using garbage collection") {}
+ DeallocGC()
+ : CFRefBug("-dealloc called while using garbage collection") {}
const char *getDescription() const {
return "-dealloc called while using garbage collection";
@@ -1901,8 +1638,8 @@ namespace {
class DeallocNotOwned : public CFRefBug {
public:
- DeallocNotOwned(CFRefCount *tf)
- : CFRefBug(tf, "-dealloc sent to non-exclusively owned object") {}
+ DeallocNotOwned()
+ : CFRefBug("-dealloc sent to non-exclusively owned object") {}
const char *getDescription() const {
return "-dealloc sent to object that may be referenced elsewhere";
@@ -1911,8 +1648,8 @@ namespace {
class OverAutorelease : public CFRefBug {
public:
- OverAutorelease(CFRefCount *tf) :
- CFRefBug(tf, "Object sent -autorelease too many times") {}
+ OverAutorelease()
+ : CFRefBug("Object sent -autorelease too many times") {}
const char *getDescription() const {
return "Object sent -autorelease too many times";
@@ -1921,8 +1658,8 @@ namespace {
class ReturnedNotOwnedForOwned : public CFRefBug {
public:
- ReturnedNotOwnedForOwned(CFRefCount *tf) :
- CFRefBug(tf, "Method should return an owned object") {}
+ ReturnedNotOwnedForOwned()
+ : CFRefBug("Method should return an owned object") {}
const char *getDescription() const {
return "Object with a +0 retain count returned to caller where a +1 "
@@ -1933,141 +1670,170 @@ namespace {
class Leak : public CFRefBug {
const bool isReturn;
protected:
- Leak(CFRefCount* tf, llvm::StringRef name, bool isRet)
- : CFRefBug(tf, name), isReturn(isRet) {}
+ Leak(StringRef name, bool isRet)
+ : CFRefBug(name), isReturn(isRet) {
+ // Leaks should not be reported if they are post-dominated by a sink.
+ setSuppressOnSink(true);
+ }
public:
- const char* getDescription() const { return ""; }
+ const char *getDescription() const { return ""; }
bool isLeak() const { return true; }
};
class LeakAtReturn : public Leak {
public:
- LeakAtReturn(CFRefCount* tf, llvm::StringRef name)
- : Leak(tf, name, true) {}
+ LeakAtReturn(StringRef name)
+ : Leak(name, true) {}
};
class LeakWithinFunction : public Leak {
public:
- LeakWithinFunction(CFRefCount* tf, llvm::StringRef name)
- : Leak(tf, name, false) {}
+ LeakWithinFunction(StringRef name)
+ : Leak(name, false) {}
};
//===---------===//
// Bug Reports. //
//===---------===//
- class CFRefReport : public RangedBugReport {
+ class CFRefReportVisitor : public BugReporterVisitor {
protected:
SymbolRef Sym;
- const CFRefCount &TF;
+ const SummaryLogTy &SummaryLog;
+ bool GCEnabled;
+
public:
- CFRefReport(CFRefBug& D, const CFRefCount &tf,
- ExplodedNode *n, SymbolRef sym)
- : RangedBugReport(D, D.getDescription(), n), Sym(sym), TF(tf) {}
+ CFRefReportVisitor(SymbolRef sym, bool gcEnabled, const SummaryLogTy &log)
+ : Sym(sym), SummaryLog(log), GCEnabled(gcEnabled) {}
- CFRefReport(CFRefBug& D, const CFRefCount &tf,
- ExplodedNode *n, SymbolRef sym, llvm::StringRef endText)
- : RangedBugReport(D, D.getDescription(), endText, n), Sym(sym), TF(tf) {}
-
- virtual ~CFRefReport() {}
-
- CFRefBug& getBugType() const {
- return (CFRefBug&) RangedBugReport::getBugType();
+ virtual void Profile(llvm::FoldingSetNodeID &ID) const {
+ static int x = 0;
+ ID.AddPointer(&x);
+ ID.AddPointer(Sym);
}
- virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const {
- if (!getBugType().isLeak())
- return RangedBugReport::getRanges();
- else
- return std::make_pair(ranges_iterator(), ranges_iterator());
- }
+ virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR);
- SymbolRef getSymbol() const { return Sym; }
+ virtual PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR);
+ };
- PathDiagnosticPiece* getEndPath(BugReporterContext& BRC,
- const ExplodedNode* N);
+ class CFRefLeakReportVisitor : public CFRefReportVisitor {
+ public:
+ CFRefLeakReportVisitor(SymbolRef sym, bool GCEnabled,
+ const SummaryLogTy &log)
+ : CFRefReportVisitor(sym, GCEnabled, log) {}
- std::pair<const char**,const char**> getExtraDescriptiveText();
+ PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR);
+ };
+
+ class CFRefReport : public BugReport {
+ void addGCModeDescription(const LangOptions &LOpts, bool GCEnabled);
- PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
- const ExplodedNode* PrevN,
- BugReporterContext& BRC);
+ public:
+ CFRefReport(CFRefBug &D, const LangOptions &LOpts, bool GCEnabled,
+ const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
+ bool registerVisitor = true)
+ : BugReport(D, D.getDescription(), n) {
+ if (registerVisitor)
+ addVisitor(new CFRefReportVisitor(sym, GCEnabled, Log));
+ addGCModeDescription(LOpts, GCEnabled);
+ }
+
+ CFRefReport(CFRefBug &D, const LangOptions &LOpts, bool GCEnabled,
+ const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
+ StringRef endText)
+ : BugReport(D, D.getDescription(), endText, n) {
+ addVisitor(new CFRefReportVisitor(sym, GCEnabled, Log));
+ addGCModeDescription(LOpts, GCEnabled);
+ }
+
+ virtual std::pair<ranges_iterator, ranges_iterator> getRanges() {
+ const CFRefBug& BugTy = static_cast<CFRefBug&>(getBugType());
+ if (!BugTy.isLeak())
+ return BugReport::getRanges();
+ else
+ return std::make_pair(ranges_iterator(), ranges_iterator());
+ }
};
class CFRefLeakReport : public CFRefReport {
- SourceLocation AllocSite;
const MemRegion* AllocBinding;
- public:
- CFRefLeakReport(CFRefBug& D, const CFRefCount &tf,
- ExplodedNode *n, SymbolRef sym,
- ExprEngine& Eng);
- PathDiagnosticPiece* getEndPath(BugReporterContext& BRC,
- const ExplodedNode* N);
+ public:
+ CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, bool GCEnabled,
+ const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
+ ExprEngine &Eng);
- SourceLocation getLocation() const { return AllocSite; }
+ PathDiagnosticLocation getLocation(const SourceManager &SM) const {
+ assert(Location.isValid());
+ return Location;
+ }
};
} // end anonymous namespace
-
-
-static const char* Msgs[] = {
- // GC only
- "Code is compiled to only use garbage collection",
- // No GC.
- "Code is compiled to use reference counts",
- // Hybrid, with GC.
- "Code is compiled to use either garbage collection (GC) or reference counts"
- " (non-GC). The bug occurs with GC enabled",
- // Hybrid, without GC
- "Code is compiled to use either garbage collection (GC) or reference counts"
- " (non-GC). The bug occurs in non-GC mode"
-};
-
-std::pair<const char**,const char**> CFRefReport::getExtraDescriptiveText() {
- CFRefCount& TF = static_cast<CFRefBug&>(getBugType()).getTF();
-
- switch (TF.getLangOptions().getGCMode()) {
- default:
- assert(false);
-
- case LangOptions::GCOnly:
- assert (TF.isGCEnabled());
- return std::make_pair(&Msgs[0], &Msgs[0]+1);
-
- case LangOptions::NonGC:
- assert (!TF.isGCEnabled());
- return std::make_pair(&Msgs[1], &Msgs[1]+1);
-
- case LangOptions::HybridGC:
- if (TF.isGCEnabled())
- return std::make_pair(&Msgs[2], &Msgs[2]+1);
- else
- return std::make_pair(&Msgs[3], &Msgs[3]+1);
+void CFRefReport::addGCModeDescription(const LangOptions &LOpts,
+ bool GCEnabled) {
+ const char *GCModeDescription = 0;
+
+ switch (LOpts.getGC()) {
+ case LangOptions::GCOnly:
+ assert(GCEnabled);
+ GCModeDescription = "Code is compiled to only use garbage collection";
+ break;
+
+ case LangOptions::NonGC:
+ assert(!GCEnabled);
+ GCModeDescription = "Code is compiled to use reference counts";
+ break;
+
+ case LangOptions::HybridGC:
+ if (GCEnabled) {
+ GCModeDescription = "Code is compiled to use either garbage collection "
+ "(GC) or reference counts (non-GC). The bug occurs "
+ "with GC enabled";
+ break;
+ } else {
+ GCModeDescription = "Code is compiled to use either garbage collection "
+ "(GC) or reference counts (non-GC). The bug occurs "
+ "in non-GC mode";
+ break;
+ }
}
+
+ assert(GCModeDescription && "invalid/unknown GC mode");
+ addExtraText(GCModeDescription);
}
-static inline bool contains(const llvm::SmallVectorImpl<ArgEffect>& V,
+// FIXME: This should be a method on SmallVector.
+static inline bool contains(const SmallVectorImpl<ArgEffect>& V,
ArgEffect X) {
- for (llvm::SmallVectorImpl<ArgEffect>::const_iterator I=V.begin(), E=V.end();
+ for (SmallVectorImpl<ArgEffect>::const_iterator I=V.begin(), E=V.end();
I!=E; ++I)
if (*I == X) return true;
return false;
}
-PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
- const ExplodedNode* PrevN,
- BugReporterContext& BRC) {
+PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) {
- if (!isa<PostStmt>(N->getLocation()))
+ if (!isa<StmtPoint>(N->getLocation()))
return NULL;
// Check if the type state has changed.
- const GRState *PrevSt = PrevN->getState();
- const GRState *CurrSt = N->getState();
+ const ProgramState *PrevSt = PrevN->getState();
+ const ProgramState *CurrSt = N->getState();
const RefVal* CurrT = CurrSt->get<RefBindings>(Sym);
if (!CurrT) return NULL;
@@ -2083,13 +1849,13 @@ PathDiagnosticPiece* CFRefReport::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<PostStmt>(N->getLocation()).getStmt();
+ const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt();
if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
// Get the name of the callee (if it is available).
SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee());
- if (const FunctionDecl* FD = X.getAsFunctionDecl())
- os << "Call to function '" << FD << '\'';
+ if (const FunctionDecl *FD = X.getAsFunctionDecl())
+ os << "Call to function '" << *FD << '\'';
else
os << "function call";
}
@@ -2110,7 +1876,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
if (CurrV.isOwned()) {
os << "+1 retain count";
- if (static_cast<CFRefBug&>(getBugType()).getTF().isGCEnabled()) {
+ if (GCEnabled) {
assert(CurrV.getObjKind() == RetEffect::CF);
os << ". "
"Core Foundation objects are not automatically garbage collected.";
@@ -2121,19 +1887,20 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
os << "+0 retain count";
}
- PathDiagnosticLocation Pos(S, BRC.getSourceManager());
+ PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
+ N->getLocationContext());
return new PathDiagnosticEventPiece(Pos, os.str());
}
// Gather up the effects that were performed on the object at this
// program point
- llvm::SmallVector<ArgEffect, 2> AEffects;
+ SmallVector<ArgEffect, 2> AEffects;
- if (const RetainSummary *Summ =
- TF.getSummaryOfNode(BRC.getNodeResolver().getOriginalNode(N))) {
+ const ExplodedNode *OrigNode = BRC.getNodeResolver().getOriginalNode(N);
+ if (const RetainSummary *Summ = SummaryLog.lookup(OrigNode)) {
// We only have summaries attached to nodes after evaluating CallExpr and
// ObjCMessageExprs.
- const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
+ const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt();
if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
// Iterate through the parameter expressions and see if the symbol
@@ -2166,7 +1933,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
RefVal PrevV = *PrevT;
// Specially handle -dealloc.
- if (!TF.isGCEnabled() && contains(AEffects, Dealloc)) {
+ if (!GCEnabled && contains(AEffects, Dealloc)) {
// Determine if the object's reference count was pushed to zero.
assert(!(PrevV == CurrV) && "The typestate *must* have changed.");
// We may not have transitioned to 'release' if we hit an error.
@@ -2181,16 +1948,15 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
// Specially handle CFMakeCollectable and friends.
if (contains(AEffects, MakeCollectable)) {
// Get the name of the function.
- const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
+ const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt();
SVal X = CurrSt->getSValAsScalarOrLoc(cast<CallExpr>(S)->getCallee());
- const FunctionDecl* FD = X.getAsFunctionDecl();
- const std::string& FName = FD->getNameAsString();
+ const FunctionDecl *FD = X.getAsFunctionDecl();
- if (TF.isGCEnabled()) {
+ if (GCEnabled) {
// Determine if the object's reference count was pushed to zero.
assert(!(PrevV == CurrV) && "The typestate *must* have changed.");
- os << "In GC mode a call to '" << FName
+ os << "In GC mode a call to '" << *FD
<< "' decrements an object's retain count and registers the "
"object with the garbage collector. ";
@@ -2205,7 +1971,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
<< '.';
}
else
- os << "When GC is not enabled a call to '" << FName
+ os << "When GC is not enabled a call to '" << *FD
<< "' has no effect on its argument.";
// Nothing more to say.
@@ -2237,7 +2003,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
os << " The object now has a +" << Count << " retain count.";
if (PrevV.getKind() == RefVal::Released) {
- assert(TF.isGCEnabled() && CurrV.getCount() > 0);
+ assert(GCEnabled && CurrV.getCount() > 0);
os << " The object is not eligible for garbage collection until the "
"retain count reaches 0 again.";
}
@@ -2262,11 +2028,11 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
}
// Emit any remaining diagnostics for the argument effects (if any).
- for (llvm::SmallVectorImpl<ArgEffect>::iterator I=AEffects.begin(),
+ for (SmallVectorImpl<ArgEffect>::iterator I=AEffects.begin(),
E=AEffects.end(); I != E; ++I) {
// A bunch of things have alternate behavior under GC.
- if (TF.isGCEnabled())
+ if (GCEnabled)
switch (*I) {
default: break;
case Autorelease:
@@ -2285,15 +2051,16 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
if (os.str().empty())
return 0; // We have nothing to say!
- const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
- PathDiagnosticLocation Pos(S, BRC.getSourceManager());
- PathDiagnosticPiece* P = new PathDiagnosticEventPiece(Pos, os.str());
+ const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt();
+ PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
+ N->getLocationContext());
+ PathDiagnosticPiece *P = new PathDiagnosticEventPiece(Pos, os.str());
// Add the range by scanning the children of the statement for any bindings
// to Sym.
for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
I!=E; ++I)
- if (const Expr* Exp = dyn_cast_or_null<Expr>(*I))
+ if (const Expr *Exp = dyn_cast_or_null<Expr>(*I))
if (CurrSt->getSValAsScalarOrLoc(Exp).getAsLocSymbol() == Sym) {
P->addRange(Exp->getSourceRange());
break;
@@ -2335,16 +2102,16 @@ namespace {
}
static std::pair<const ExplodedNode*,const MemRegion*>
-GetAllocationSite(GRStateManager& StateMgr, const ExplodedNode* N,
+GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N,
SymbolRef Sym) {
// Find both first node that referred to the tracked symbol and the
// memory location that value was store to.
- const ExplodedNode* Last = N;
+ const ExplodedNode *Last = N;
const MemRegion* FirstBinding = 0;
while (N) {
- const GRState* St = N->getState();
+ const ProgramState *St = N->getState();
RefBindings B = St->get<RefBindings>();
if (!B.lookup(Sym))
@@ -2362,17 +2129,19 @@ GetAllocationSite(GRStateManager& StateMgr, const ExplodedNode* N,
}
PathDiagnosticPiece*
-CFRefReport::getEndPath(BugReporterContext& BRC,
- const ExplodedNode* EndN) {
+CFRefReportVisitor::getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *EndN,
+ BugReport &BR) {
// Tell the BugReporterContext to report cases when the tracked symbol is
// assigned to different variables, etc.
BRC.addNotableSymbol(Sym);
- return RangedBugReport::getEndPath(BRC, EndN);
+ return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR);
}
PathDiagnosticPiece*
-CFRefLeakReport::getEndPath(BugReporterContext& BRC,
- const ExplodedNode* EndN){
+CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *EndN,
+ BugReport &BR) {
// Tell the BugReporterContext to report cases when the tracked symbol is
// assigned to different variables, etc.
@@ -2381,41 +2150,19 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC,
// We are reporting a leak. Walk up the graph to get to the first node where
// the symbol appeared, and also get the first VarDecl that tracked object
// is stored to.
- const ExplodedNode* AllocNode = 0;
+ const ExplodedNode *AllocNode = 0;
const MemRegion* FirstBinding = 0;
llvm::tie(AllocNode, FirstBinding) =
GetAllocationSite(BRC.getStateManager(), EndN, Sym);
- SourceManager& SMgr = BRC.getSourceManager();
+ SourceManager& SM = BRC.getSourceManager();
// Compute an actual location for the leak. Sometimes a leak doesn't
// occur at an actual statement (e.g., transition between blocks; end
// of function) so we need to walk the graph and compute a real location.
- const ExplodedNode* LeakN = EndN;
- PathDiagnosticLocation L;
-
- while (LeakN) {
- ProgramPoint P = LeakN->getLocation();
-
- if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
- L = PathDiagnosticLocation(PS->getStmt()->getLocStart(), SMgr);
- break;
- }
- else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
- if (const Stmt* Term = BE->getSrc()->getTerminator()) {
- L = PathDiagnosticLocation(Term->getLocStart(), SMgr);
- break;
- }
- }
-
- LeakN = LeakN->succ_empty() ? 0 : *(LeakN->succ_begin());
- }
-
- if (!L.isValid()) {
- const Decl &D = EndN->getCodeDecl();
- L = PathDiagnosticLocation(D.getBodyRBrace(), SMgr);
- }
+ const ExplodedNode *LeakN = EndN;
+ PathDiagnosticLocation L = PathDiagnosticLocation::createEndOfPath(LeakN, SM);
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
@@ -2454,7 +2201,7 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC,
}
}
else if (RV->getKind() == RefVal::ErrorGCLeakReturned) {
- ObjCMethodDecl& MD = cast<ObjCMethodDecl>(EndN->getCodeDecl());
+ 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 "
@@ -2468,10 +2215,11 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC,
return new PathDiagnosticEventPiece(L, os.str());
}
-CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf,
- ExplodedNode *n,
- SymbolRef sym, ExprEngine& Eng)
-: CFRefReport(D, tf, n, sym) {
+CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
+ bool GCEnabled, const SummaryLogTy &Log,
+ ExplodedNode *n, SymbolRef sym,
+ ExprEngine &Eng)
+: CFRefReport(D, LOpts, GCEnabled, Log, n, sym, false) {
// Most bug reports are cached at the location where they occurred.
// With leaks, we want to unique them by the location where they were
@@ -2481,41 +2229,418 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf,
// Note that this is *not* the trimmed graph; we are guaranteed, however,
// that all ancestor nodes that represent the allocation site have the
// same SourceLocation.
- const ExplodedNode* AllocNode = 0;
+ const ExplodedNode *AllocNode = 0;
+
+ const SourceManager& SMgr = Eng.getContext().getSourceManager();
llvm::tie(AllocNode, AllocBinding) = // Set AllocBinding.
- GetAllocationSite(Eng.getStateManager(), getErrorNode(), getSymbol());
+ GetAllocationSite(Eng.getStateManager(), getErrorNode(), sym);
// Get the SourceLocation for the allocation site.
ProgramPoint P = AllocNode->getLocation();
- AllocSite = cast<PostStmt>(P).getStmt()->getLocStart();
-
+ const Stmt *AllocStmt = cast<PostStmt>(P).getStmt();
+ Location = PathDiagnosticLocation::createBegin(AllocStmt, SMgr,
+ n->getLocationContext());
// Fill in the description of the bug.
Description.clear();
llvm::raw_string_ostream os(Description);
- SourceManager& SMgr = Eng.getContext().getSourceManager();
- unsigned AllocLine = SMgr.getInstantiationLineNumber(AllocSite);
+ unsigned AllocLine = SMgr.getExpansionLineNumber(AllocStmt->getLocStart());
os << "Potential leak ";
- if (tf.isGCEnabled()) {
+ if (GCEnabled)
os << "(when using garbage collection) ";
- }
os << "of an object allocated on line " << AllocLine;
// FIXME: AllocBinding doesn't get populated for RegionStore yet.
if (AllocBinding)
os << " and stored into '" << AllocBinding->getString() << '\'';
+
+ addVisitor(new CFRefLeakReportVisitor(sym, GCEnabled, Log));
}
//===----------------------------------------------------------------------===//
// Main checker logic.
//===----------------------------------------------------------------------===//
+namespace {
+class RetainCountChecker
+ : public Checker< check::Bind,
+ check::DeadSymbols,
+ check::EndAnalysis,
+ check::EndPath,
+ check::PostStmt<BlockExpr>,
+ check::PostStmt<CastExpr>,
+ check::PostStmt<CallExpr>,
+ check::PostStmt<CXXConstructExpr>,
+ check::PostObjCMessage,
+ check::PreStmt<ReturnStmt>,
+ check::RegionChanges,
+ eval::Assume,
+ eval::Call > {
+ mutable llvm::OwningPtr<CFRefBug> useAfterRelease, releaseNotOwned;
+ mutable llvm::OwningPtr<CFRefBug> deallocGC, deallocNotOwned;
+ mutable llvm::OwningPtr<CFRefBug> overAutorelease, returnNotOwnedForOwned;
+ mutable llvm::OwningPtr<CFRefBug> leakWithinFunction, leakAtReturn;
+ mutable llvm::OwningPtr<CFRefBug> leakWithinFunctionGC, leakAtReturnGC;
+
+ typedef llvm::DenseMap<SymbolRef, const SimpleProgramPointTag *> SymbolTagMap;
+
+ // This map is only used to ensure proper deletion of any allocated tags.
+ mutable SymbolTagMap DeadSymbolTags;
+
+ mutable llvm::OwningPtr<RetainSummaryManager> Summaries;
+ mutable llvm::OwningPtr<RetainSummaryManager> SummariesGC;
+
+ mutable ARCounts::Factory ARCountFactory;
+
+ mutable SummaryLogTy SummaryLog;
+ mutable bool ShouldResetSummaryLog;
+
+public:
+ RetainCountChecker() : ShouldResetSummaryLog(false) {}
+
+ virtual ~RetainCountChecker() {
+ DeleteContainerSeconds(DeadSymbolTags);
+ }
+
+ void checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
+ ExprEngine &Eng) const {
+ // FIXME: This is a hack to make sure the summary log gets cleared between
+ // analyses of different code bodies.
+ //
+ // Why is this necessary? Because a checker's lifetime is tied to a
+ // translation unit, but an ExplodedGraph's lifetime is just a code body.
+ // Once in a blue moon, a new ExplodedNode will have the same address as an
+ // old one with an associated summary, and the bug report visitor gets very
+ // confused. (To make things worse, the summary lifetime is currently also
+ // tied to a code body, so we get a crash instead of incorrect results.)
+ //
+ // Why is this a bad solution? Because if the lifetime of the ExplodedGraph
+ // changes, things will start going wrong again. Really the lifetime of this
+ // log needs to be tied to either the specific nodes in it or the entire
+ // ExplodedGraph, not to a specific part of the code being analyzed.
+ //
+ // (Also, having stateful local data means that the same checker can't be
+ // used from multiple threads, but a lot of checkers have incorrect
+ // assumptions about that anyway. So that wasn't a priority at the time of
+ // this fix.)
+ //
+ // This happens at the end of analysis, but bug reports are emitted /after/
+ // this point. So we can't just clear the summary log now. Instead, we mark
+ // that the next time we access the summary log, it should be cleared.
+
+ // If we never reset the summary log during /this/ code body analysis,
+ // there were no new summaries. There might still have been summaries from
+ // the /last/ analysis, so clear them out to make sure the bug report
+ // visitors don't get confused.
+ if (ShouldResetSummaryLog)
+ SummaryLog.clear();
+
+ ShouldResetSummaryLog = !SummaryLog.empty();
+ }
+
+ CFRefBug *getLeakWithinFunctionBug(const LangOptions &LOpts,
+ bool GCEnabled) const {
+ if (GCEnabled) {
+ if (!leakWithinFunctionGC)
+ leakWithinFunctionGC.reset(new LeakWithinFunction("Leak of object when "
+ "using garbage "
+ "collection"));
+ return leakWithinFunctionGC.get();
+ } else {
+ if (!leakWithinFunction) {
+ if (LOpts.getGC() == LangOptions::HybridGC) {
+ leakWithinFunction.reset(new LeakWithinFunction("Leak of object when "
+ "not using garbage "
+ "collection (GC) in "
+ "dual GC/non-GC "
+ "code"));
+ } else {
+ leakWithinFunction.reset(new LeakWithinFunction("Leak"));
+ }
+ }
+ return leakWithinFunction.get();
+ }
+ }
+
+ CFRefBug *getLeakAtReturnBug(const LangOptions &LOpts, bool GCEnabled) const {
+ if (GCEnabled) {
+ if (!leakAtReturnGC)
+ leakAtReturnGC.reset(new LeakAtReturn("Leak of returned object when "
+ "using garbage collection"));
+ return leakAtReturnGC.get();
+ } else {
+ if (!leakAtReturn) {
+ if (LOpts.getGC() == LangOptions::HybridGC) {
+ leakAtReturn.reset(new LeakAtReturn("Leak of returned object when "
+ "not using garbage collection "
+ "(GC) in dual GC/non-GC code"));
+ } else {
+ leakAtReturn.reset(new LeakAtReturn("Leak of returned object"));
+ }
+ }
+ return leakAtReturn.get();
+ }
+ }
+
+ RetainSummaryManager &getSummaryManager(ASTContext &Ctx,
+ bool GCEnabled) const {
+ // FIXME: We don't support ARC being turned on and off during one analysis.
+ // (nor, for that matter, do we support changing ASTContexts)
+ bool ARCEnabled = (bool)Ctx.getLangOptions().ObjCAutoRefCount;
+ if (GCEnabled) {
+ if (!SummariesGC)
+ SummariesGC.reset(new RetainSummaryManager(Ctx, true, ARCEnabled));
+ else
+ assert(SummariesGC->isARCEnabled() == ARCEnabled);
+ return *SummariesGC;
+ } else {
+ if (!Summaries)
+ Summaries.reset(new RetainSummaryManager(Ctx, false, ARCEnabled));
+ else
+ assert(Summaries->isARCEnabled() == ARCEnabled);
+ return *Summaries;
+ }
+ }
+
+ RetainSummaryManager &getSummaryManager(CheckerContext &C) const {
+ return getSummaryManager(C.getASTContext(), C.isObjCGCEnabled());
+ }
+
+ void printState(raw_ostream &Out, const ProgramState *State,
+ const char *NL, const char *Sep) const;
+
+ void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const;
+ void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
+ void checkPostStmt(const CastExpr *CE, CheckerContext &C) const;
+
+ void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkPostStmt(const CXXConstructExpr *CE, CheckerContext &C) const;
+ void checkPostObjCMessage(const ObjCMessage &Msg, CheckerContext &C) const;
+ void checkSummary(const RetainSummary &Summ, const CallOrObjCMessage &Call,
+ CheckerContext &C) const;
+
+ bool evalCall(const CallExpr *CE, CheckerContext &C) const;
+
+ const ProgramState *evalAssume(const ProgramState *state, SVal Cond,
+ bool Assumption) const;
+
+ const ProgramState *
+ checkRegionChanges(const ProgramState *state,
+ const StoreManager::InvalidatedSymbols *invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions) const;
+
+ bool wantsRegionChangeUpdate(const ProgramState *state) const {
+ return true;
+ }
+
+ void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
+ void checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C,
+ ExplodedNode *Pred, RetEffect RE, RefVal X,
+ SymbolRef Sym, const ProgramState *state) const;
+
+ void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
+ void checkEndPath(EndOfFunctionNodeBuilder &Builder, ExprEngine &Eng) const;
+
+ const ProgramState *updateSymbol(const ProgramState *state, SymbolRef sym,
+ RefVal V, ArgEffect E, RefVal::Kind &hasErr,
+ CheckerContext &C) const;
+
+ void processNonLeakError(const ProgramState *St, SourceRange ErrorRange,
+ RefVal::Kind ErrorKind, SymbolRef Sym,
+ CheckerContext &C) const;
+
+ const ProgramPointTag *getDeadSymbolTag(SymbolRef sym) const;
+
+ const ProgramState *handleSymbolDeath(const ProgramState *state,
+ SymbolRef sid, RefVal V,
+ SmallVectorImpl<SymbolRef> &Leaked) const;
+
+ std::pair<ExplodedNode *, const ProgramState *>
+ handleAutoreleaseCounts(const ProgramState *state,
+ GenericNodeBuilderRefCount Bd, ExplodedNode *Pred,
+ ExprEngine &Eng, SymbolRef Sym, RefVal V) const;
+
+ ExplodedNode *processLeaks(const ProgramState *state,
+ SmallVectorImpl<SymbolRef> &Leaked,
+ GenericNodeBuilderRefCount &Builder,
+ ExprEngine &Eng,
+ ExplodedNode *Pred = 0) const;
+};
+} // end anonymous namespace
+
+namespace {
+class StopTrackingCallback : public SymbolVisitor {
+ const ProgramState *state;
+public:
+ StopTrackingCallback(const ProgramState *st) : state(st) {}
+ const ProgramState *getState() const { return state; }
+
+ bool VisitSymbol(SymbolRef sym) {
+ state = state->remove<RefBindings>(sym);
+ return true;
+ }
+};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Handle statements that may have an effect on refcounts.
+//===----------------------------------------------------------------------===//
+
+void RetainCountChecker::checkPostStmt(const BlockExpr *BE,
+ CheckerContext &C) const {
+
+ // Scan the BlockDecRefExprs for any object the retain count checker
+ // may be tracking.
+ if (!BE->getBlockDecl()->hasCaptures())
+ return;
+
+ const ProgramState *state = C.getState();
+ const BlockDataRegion *R =
+ cast<BlockDataRegion>(state->getSVal(BE).getAsRegion());
+
+ BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
+ E = R->referenced_vars_end();
+
+ if (I == E)
+ return;
+
+ // FIXME: For now we invalidate the tracking of all symbols passed to blocks
+ // via captured variables, even though captured variables result in a copy
+ // and in implicit increment/decrement of a retain count.
+ SmallVector<const MemRegion*, 10> Regions;
+ const LocationContext *LC = C.getPredecessor()->getLocationContext();
+ MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
+
+ for ( ; I != E; ++I) {
+ const VarRegion *VR = *I;
+ if (VR->getSuperRegion() == R) {
+ VR = MemMgr.getVarRegion(VR->getDecl(), LC);
+ }
+ Regions.push_back(VR);
+ }
+
+ state =
+ state->scanReachableSymbols<StopTrackingCallback>(Regions.data(),
+ Regions.data() + Regions.size()).getState();
+ C.addTransition(state);
+}
+
+void RetainCountChecker::checkPostStmt(const CastExpr *CE,
+ CheckerContext &C) const {
+ const ObjCBridgedCastExpr *BE = dyn_cast<ObjCBridgedCastExpr>(CE);
+ if (!BE)
+ return;
+
+ ArgEffect AE = IncRef;
+
+ switch (BE->getBridgeKind()) {
+ case clang::OBC_Bridge:
+ // Do nothing.
+ return;
+ case clang::OBC_BridgeRetained:
+ AE = IncRef;
+ break;
+ case clang::OBC_BridgeTransfer:
+ AE = DecRefBridgedTransfered;
+ break;
+ }
+
+ const ProgramState *state = C.getState();
+ SymbolRef Sym = state->getSVal(CE).getAsLocSymbol();
+ if (!Sym)
+ return;
+ const RefVal* T = state->get<RefBindings>(Sym);
+ if (!T)
+ return;
+
+ RefVal::Kind hasErr = (RefVal::Kind) 0;
+ state = updateSymbol(state, Sym, *T, AE, hasErr, C);
+
+ if (hasErr) {
+ // FIXME: If we get an error during a bridge cast, should we report it?
+ // Should we assert that there is no error?
+ return;
+ }
+
+ C.generateNode(state);
+}
+
+void RetainCountChecker::checkPostStmt(const CallExpr *CE,
+ CheckerContext &C) const {
+ // Get the callee.
+ const ProgramState *state = C.getState();
+ const Expr *Callee = CE->getCallee();
+ SVal L = state->getSVal(Callee);
+
+ RetainSummaryManager &Summaries = getSummaryManager(C);
+ const RetainSummary *Summ = 0;
+
+ // FIXME: Better support for blocks. For now we stop tracking anything
+ // that is passed to blocks.
+ // FIXME: Need to handle variables that are "captured" by the block.
+ if (dyn_cast_or_null<BlockDataRegion>(L.getAsRegion())) {
+ Summ = Summaries.getPersistentStopSummary();
+ } else if (const FunctionDecl *FD = L.getAsFunctionDecl()) {
+ Summ = Summaries.getSummary(FD);
+ } else if (const CXXMemberCallExpr *me = dyn_cast<CXXMemberCallExpr>(CE)) {
+ if (const CXXMethodDecl *MD = me->getMethodDecl())
+ Summ = Summaries.getSummary(MD);
+ }
+
+ if (!Summ)
+ Summ = Summaries.getDefaultSummary();
+
+ checkSummary(*Summ, CallOrObjCMessage(CE, state), C);
+}
+
+void RetainCountChecker::checkPostStmt(const CXXConstructExpr *CE,
+ CheckerContext &C) const {
+ const CXXConstructorDecl *Ctor = CE->getConstructor();
+ if (!Ctor)
+ return;
+
+ RetainSummaryManager &Summaries = getSummaryManager(C);
+ const RetainSummary *Summ = Summaries.getSummary(Ctor);
+
+ // If we didn't get a summary, this constructor doesn't affect retain counts.
+ if (!Summ)
+ return;
+
+ const ProgramState *state = C.getState();
+ checkSummary(*Summ, CallOrObjCMessage(CE, state), C);
+}
+
+void RetainCountChecker::checkPostObjCMessage(const ObjCMessage &Msg,
+ CheckerContext &C) const {
+ const ProgramState *state = C.getState();
+ ExplodedNode *Pred = C.getPredecessor();
+
+ RetainSummaryManager &Summaries = getSummaryManager(C);
+
+ const RetainSummary *Summ;
+ if (Msg.isInstanceMessage()) {
+ const LocationContext *LC = Pred->getLocationContext();
+ Summ = Summaries.getInstanceMethodSummary(Msg, state, LC);
+ } else {
+ Summ = Summaries.getClassMethodSummary(Msg);
+ }
+
+ // If we didn't get a summary, this message doesn't affect retain counts.
+ if (!Summ)
+ return;
+
+ checkSummary(*Summ, CallOrObjCMessage(Msg, state), C);
+}
+
/// GetReturnType - Used to get the return type of a message expression or
/// function call with the intention of affixing that type to a tracked symbol.
/// While the the return type can be queried directly from RetEx, when
/// invoking class methods we augment to the return type to be that of
/// a pointer to the class (as opposed it just being id).
-static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) {
+// FIXME: We may be able to do this with related result types instead.
+// This function is probably overestimating.
+static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) {
QualType RetTy = RetE->getType();
// If RetE is not a message expression just return its type.
// If RetE is a message expression, return its types if it is something
@@ -2536,167 +2661,43 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) {
return RetTy;
}
-
-// HACK: Symbols that have ref-count state that are referenced directly
-// (not as structure or array elements, or via bindings) by an argument
-// should not have their ref-count state stripped after we have
-// done an invalidation pass.
-//
-// FIXME: This is a global to currently share between CFRefCount and
-// RetainReleaseChecker. Eventually all functionality in CFRefCount should
-// be migrated to RetainReleaseChecker, and we can make this a non-global.
-llvm::DenseSet<SymbolRef> WhitelistedSymbols;
-namespace {
-struct ResetWhiteList {
- ResetWhiteList() {}
- ~ResetWhiteList() { WhitelistedSymbols.clear(); }
-};
-}
-
-void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
- ExprEngine& Eng,
- StmtNodeBuilder& Builder,
- const Expr* Ex,
- const CallOrObjCMessage &callOrMsg,
- InstanceReceiver Receiver,
- const RetainSummary& Summ,
- const MemRegion *Callee,
- ExplodedNode* Pred, const GRState *state) {
+void RetainCountChecker::checkSummary(const RetainSummary &Summ,
+ const CallOrObjCMessage &CallOrMsg,
+ CheckerContext &C) const {
+ const ProgramState *state = C.getState();
// Evaluate the effect of the arguments.
RefVal::Kind hasErr = (RefVal::Kind) 0;
SourceRange ErrorRange;
SymbolRef ErrorSym = 0;
- llvm::SmallVector<const MemRegion*, 10> RegionsToInvalidate;
-
- // Use RAII to make sure the whitelist is properly cleared.
- ResetWhiteList resetWhiteList;
+ for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
+ SVal V = CallOrMsg.getArgSVal(idx);
- // Invalidate all instance variables of the receiver of a message.
- // FIXME: We should be able to do better with inter-procedural analysis.
- if (Receiver) {
- SVal V = Receiver.getSValAsScalarOrLoc(state);
if (SymbolRef Sym = V.getAsLocSymbol()) {
- if (state->get<RefBindings>(Sym))
- WhitelistedSymbols.insert(Sym);
- }
- if (const MemRegion *region = V.getAsRegion())
- RegionsToInvalidate.push_back(region);
- }
-
- // Invalidate all instance variables for the callee of a C++ method call.
- // FIXME: We should be able to do better with inter-procedural analysis.
- // FIXME: we can probably do better for const versus non-const methods.
- if (callOrMsg.isCXXCall()) {
- if (const MemRegion *callee = callOrMsg.getCXXCallee().getAsRegion())
- RegionsToInvalidate.push_back(callee);
- }
-
- for (unsigned idx = 0, e = callOrMsg.getNumArgs(); idx != e; ++idx) {
- SVal V = callOrMsg.getArgSValAsScalarOrLoc(idx);
- SymbolRef Sym = V.getAsLocSymbol();
-
- if (Sym)
- if (RefBindings::data_type* T = state->get<RefBindings>(Sym)) {
- WhitelistedSymbols.insert(Sym);
- state = Update(state, Sym, *T, Summ.getArg(idx), hasErr);
+ if (RefBindings::data_type *T = state->get<RefBindings>(Sym)) {
+ state = updateSymbol(state, Sym, *T, Summ.getArg(idx), hasErr, C);
if (hasErr) {
- ErrorRange = callOrMsg.getArgSourceRange(idx);
+ ErrorRange = CallOrMsg.getArgSourceRange(idx);
ErrorSym = Sym;
break;
}
}
-
- tryAgain:
- if (isa<Loc>(V)) {
- if (loc::MemRegionVal* MR = dyn_cast<loc::MemRegionVal>(&V)) {
- if (Summ.getArg(idx) == DoNothingByRef)
- continue;
-
- // Invalidate the value of the variable passed by reference.
- const MemRegion *R = MR->getRegion();
-
- // Are we dealing with an ElementRegion? If the element type is
- // a basic integer type (e.g., char, int) and the underying 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
- // approriately 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);
- continue;
- }
- else {
- // Nuke all other arguments passed by reference.
- // FIXME: is this necessary or correct? This handles the non-Region
- // cases. Is it ever valid to store to these?
- state = state->unbindLoc(cast<Loc>(V));
- }
}
- else if (isa<nonloc::LocAsInteger>(V)) {
- // If we are passing a location wrapped as an integer, unwrap it and
- // invalidate the values referred by the location.
- V = cast<nonloc::LocAsInteger>(V).getLoc();
- goto tryAgain;
- }
- }
-
- // Block calls result in all captured values passed-via-reference to be
- // invalidated.
- if (const BlockDataRegion *BR = dyn_cast_or_null<BlockDataRegion>(Callee)) {
- RegionsToInvalidate.push_back(BR);
}
- // Invalidate regions we designed for invalidation use the batch invalidation
- // API.
-
- // FIXME: We can have collisions on the conjured symbol if the
- // expression *I also creates conjured symbols. We probably want
- // to identify conjured symbols by an expression pair: the enclosing
- // expression (the context) and the expression itself. This should
- // disambiguate conjured symbols.
- unsigned Count = Builder.getCurrentBlockCount();
- StoreManager::InvalidatedSymbols IS;
-
- // NOTE: Even if RegionsToInvalidate is empty, we must still invalidate
- // global variables.
- // NOTE: RetainReleaseChecker handles the actual invalidation of symbols.
- state =
- state->invalidateRegions(RegionsToInvalidate.data(),
- RegionsToInvalidate.data() +
- RegionsToInvalidate.size(),
- Ex, Count, &IS,
- /* invalidateGlobals = */
- Eng.doesInvalidateGlobals(callOrMsg));
-
// Evaluate the effect on the message receiver.
- if (!ErrorRange.isValid() && Receiver) {
- SymbolRef Sym = Receiver.getSValAsScalarOrLoc(state).getAsLocSymbol();
- if (Sym) {
- if (const RefVal* T = state->get<RefBindings>(Sym)) {
- state = Update(state, Sym, *T, Summ.getReceiverEffect(), hasErr);
+ bool ReceiverIsTracked = false;
+ if (!hasErr && CallOrMsg.isObjCMessage()) {
+ const LocationContext *LC = C.getPredecessor()->getLocationContext();
+ SVal Receiver = CallOrMsg.getInstanceMessageReceiver(LC);
+ if (SymbolRef Sym = Receiver.getAsLocSymbol()) {
+ if (const RefVal *T = state->get<RefBindings>(Sym)) {
+ ReceiverIsTracked = true;
+ state = updateSymbol(state, Sym, *T, Summ.getReceiverEffect(),
+ hasErr, C);
if (hasErr) {
- ErrorRange = Receiver.getSourceRange();
+ ErrorRange = CallOrMsg.getReceiverSourceRange();
ErrorSym = Sym;
}
}
@@ -2705,8 +2706,7 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
// Process any errors.
if (hasErr) {
- ProcessNonLeakError(Dst, Builder, Ex, ErrorRange, Pred, state,
- hasErr, ErrorSym);
+ processNonLeakError(state, ErrorRange, hasErr, ErrorSym, C);
return;
}
@@ -2714,75 +2714,34 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
RetEffect RE = Summ.getRetEffect();
if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
- bool found = false;
- if (Receiver) {
- SVal V = Receiver.getSValAsScalarOrLoc(state);
- if (SymbolRef Sym = V.getAsLocSymbol())
- if (state->get<RefBindings>(Sym)) {
- found = true;
- RE = Summaries.getObjAllocRetEffect();
- }
- } // FIXME: Otherwise, this is a send-to-super instance message.
- if (!found)
+ if (ReceiverIsTracked)
+ RE = getSummaryManager(C).getObjAllocRetEffect();
+ else
RE = RetEffect::MakeNoRet();
}
switch (RE.getKind()) {
default:
- assert (false && "Unhandled RetEffect."); break;
-
- case RetEffect::NoRet: {
- // Make up a symbol for the return value (not reference counted).
- // FIXME: Most of this logic is not specific to the retain/release
- // checker.
-
- // FIXME: We eventually should handle structs and other compound types
- // that are returned by value.
-
- // Use the result type from callOrMsg as it automatically adjusts
- // for methods/functions that return references.
- QualType resultTy = callOrMsg.getResultType(Eng.getContext());
- if (Loc::isLocType(resultTy) ||
- (resultTy->isIntegerType() && resultTy->isScalarType())) {
- unsigned Count = Builder.getCurrentBlockCount();
- SValBuilder &svalBuilder = Eng.getSValBuilder();
- SVal X = svalBuilder.getConjuredSymbolVal(NULL, Ex, resultTy, Count);
- state = state->BindExpr(Ex, X, false);
- }
-
- break;
- }
-
- case RetEffect::Alias: {
- unsigned idx = RE.getIndex();
- assert (idx < callOrMsg.getNumArgs());
- SVal V = callOrMsg.getArgSValAsScalarOrLoc(idx);
- state = state->BindExpr(Ex, V, false);
- break;
- }
+ llvm_unreachable("Unhandled RetEffect."); break;
- case RetEffect::ReceiverAlias: {
- assert(Receiver);
- SVal V = Receiver.getSValAsScalarOrLoc(state);
- state = state->BindExpr(Ex, V, false);
+ case RetEffect::NoRet:
+ // No work necessary.
break;
- }
case RetEffect::OwnedAllocatedSymbol:
case RetEffect::OwnedSymbol: {
- unsigned Count = Builder.getCurrentBlockCount();
- SValBuilder &svalBuilder = Eng.getSValBuilder();
- SymbolRef Sym = svalBuilder.getConjuredSymbol(Ex, Count);
+ SymbolRef Sym = state->getSVal(CallOrMsg.getOriginExpr()).getAsSymbol();
+ if (!Sym)
+ break;
// Use the result type from callOrMsg as it automatically adjusts
- // for methods/functions that return references.
- QualType resultTy = callOrMsg.getResultType(Eng.getContext());
+ // for methods/functions that return references.
+ QualType ResultTy = CallOrMsg.getResultType(C.getASTContext());
state = state->set<RefBindings>(Sym, RefVal::makeOwned(RE.getObjKind(),
- resultTy));
- state = state->BindExpr(Ex, svalBuilder.makeLoc(Sym), false);
+ ResultTy));
// FIXME: Add a flag to the checker where allocations are assumed to
- // *not fail.
+ // *not* fail. (The code below is out-of-date, though.)
#if 0
if (RE.getKind() == RetEffect::OwnedAllocatedSymbol) {
bool isFeasible;
@@ -2797,151 +2756,324 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
case RetEffect::GCNotOwnedSymbol:
case RetEffect::ARCNotOwnedSymbol:
case RetEffect::NotOwnedSymbol: {
- unsigned Count = Builder.getCurrentBlockCount();
- SValBuilder &svalBuilder = Eng.getSValBuilder();
- SymbolRef Sym = svalBuilder.getConjuredSymbol(Ex, Count);
- QualType RetT = GetReturnType(Ex, svalBuilder.getContext());
+ const Expr *Ex = CallOrMsg.getOriginExpr();
+ SymbolRef Sym = state->getSVal(Ex).getAsSymbol();
+ if (!Sym)
+ break;
+
+ // Use GetReturnType in order to give [NSFoo alloc] the type NSFoo *.
+ QualType ResultTy = GetReturnType(Ex, C.getASTContext());
state = state->set<RefBindings>(Sym, RefVal::makeNotOwned(RE.getObjKind(),
- RetT));
- state = state->BindExpr(Ex, svalBuilder.makeLoc(Sym), false);
+ ResultTy));
break;
}
}
- // Generate a sink node if we are at the end of a path.
- ExplodedNode *NewNode =
- Summ.isEndPath() ? Builder.MakeSinkNode(Dst, Ex, Pred, state)
- : Builder.MakeNode(Dst, Ex, Pred, state);
+ // This check is actually necessary; otherwise the statement builder thinks
+ // we've hit a previously-found path.
+ // Normally addTransition takes care of this, but we want the node pointer.
+ ExplodedNode *NewNode;
+ if (state == C.getState()) {
+ NewNode = C.getPredecessor();
+ } else {
+ NewNode = C.generateNode(state);
+ }
- // Annotate the edge with summary we used.
- if (NewNode) SummaryLog[NewNode] = &Summ;
+ // Annotate the node with summary we used.
+ if (NewNode) {
+ // FIXME: This is ugly. See checkEndAnalysis for why it's necessary.
+ if (ShouldResetSummaryLog) {
+ SummaryLog.clear();
+ ShouldResetSummaryLog = false;
+ }
+ SummaryLog[NewNode] = &Summ;
+ }
}
-void CFRefCount::evalCall(ExplodedNodeSet& Dst,
- ExprEngine& Eng,
- StmtNodeBuilder& Builder,
- const CallExpr* CE, SVal L,
- ExplodedNode* Pred) {
-
- RetainSummary *Summ = 0;
+const ProgramState *
+RetainCountChecker::updateSymbol(const ProgramState *state, SymbolRef sym,
+ RefVal V, ArgEffect E, RefVal::Kind &hasErr,
+ CheckerContext &C) const {
+ // In GC mode [... release] and [... retain] do nothing.
+ // In ARC mode they shouldn't exist at all, but we just ignore them.
+ bool IgnoreRetainMsg = C.isObjCGCEnabled();
+ if (!IgnoreRetainMsg)
+ IgnoreRetainMsg = (bool)C.getASTContext().getLangOptions().ObjCAutoRefCount;
- // FIXME: Better support for blocks. For now we stop tracking anything
- // that is passed to blocks.
- // FIXME: Need to handle variables that are "captured" by the block.
- if (dyn_cast_or_null<BlockDataRegion>(L.getAsRegion())) {
- Summ = Summaries.getPersistentStopSummary();
- }
- else if (const FunctionDecl* FD = L.getAsFunctionDecl()) {
- Summ = Summaries.getSummary(FD);
+ switch (E) {
+ default: break;
+ case IncRefMsg: E = IgnoreRetainMsg ? DoNothing : IncRef; break;
+ case DecRefMsg: E = IgnoreRetainMsg ? DoNothing : DecRef; break;
+ case MakeCollectable: E = C.isObjCGCEnabled() ? DecRef : DoNothing; break;
+ case NewAutoreleasePool: E = C.isObjCGCEnabled() ? DoNothing :
+ NewAutoreleasePool; break;
}
- else if (const CXXMemberCallExpr *me = dyn_cast<CXXMemberCallExpr>(CE)) {
- if (const CXXMethodDecl *MD = me->getMethodDecl())
- Summ = Summaries.getSummary(MD);
- else
- Summ = Summaries.getDefaultSummary();
+
+ // Handle all use-after-releases.
+ if (!C.isObjCGCEnabled() && V.getKind() == RefVal::Released) {
+ V = V ^ RefVal::ErrorUseAfterRelease;
+ hasErr = V.getKind();
+ return state->set<RefBindings>(sym, V);
}
- else
- Summ = Summaries.getDefaultSummary();
- assert(Summ);
- evalSummary(Dst, Eng, Builder, CE,
- CallOrObjCMessage(CE, Builder.GetState(Pred)),
- InstanceReceiver(), *Summ,L.getAsRegion(),
- Pred, Builder.GetState(Pred));
-}
+ switch (E) {
+ case DecRefMsg:
+ case IncRefMsg:
+ case MakeCollectable:
+ llvm_unreachable("DecRefMsg/IncRefMsg/MakeCollectable already converted");
+ return state;
-void CFRefCount::evalObjCMessage(ExplodedNodeSet& Dst,
- ExprEngine& Eng,
- StmtNodeBuilder& Builder,
- ObjCMessage msg,
- ExplodedNode* Pred,
- const GRState *state) {
- RetainSummary *Summ =
- msg.isInstanceMessage()
- ? Summaries.getInstanceMethodSummary(msg, state,Pred->getLocationContext())
- : Summaries.getClassMethodSummary(msg);
-
- assert(Summ && "RetainSummary is null");
- evalSummary(Dst, Eng, Builder, msg.getOriginExpr(),
- CallOrObjCMessage(msg, Builder.GetState(Pred)),
- InstanceReceiver(msg, Pred->getLocationContext()), *Summ, NULL,
- Pred, state);
-}
+ case Dealloc:
+ // Any use of -dealloc in GC is *bad*.
+ if (C.isObjCGCEnabled()) {
+ V = V ^ RefVal::ErrorDeallocGC;
+ hasErr = V.getKind();
+ break;
+ }
-namespace {
-class StopTrackingCallback : public SymbolVisitor {
- const GRState *state;
-public:
- StopTrackingCallback(const GRState *st) : state(st) {}
- const GRState *getState() const { return state; }
+ switch (V.getKind()) {
+ default:
+ llvm_unreachable("Invalid RefVal state for an explicit dealloc.");
+ break;
+ case RefVal::Owned:
+ // The object immediately transitions to the released state.
+ V = V ^ RefVal::Released;
+ V.clearCounts();
+ return state->set<RefBindings>(sym, V);
+ case RefVal::NotOwned:
+ V = V ^ RefVal::ErrorDeallocNotOwned;
+ hasErr = V.getKind();
+ break;
+ }
+ break;
- bool VisitSymbol(SymbolRef sym) {
- state = state->remove<RefBindings>(sym);
- return true;
- }
-};
-} // end anonymous namespace
+ case NewAutoreleasePool:
+ assert(!C.isObjCGCEnabled());
+ return state->add<AutoreleaseStack>(sym);
+ case MayEscape:
+ if (V.getKind() == RefVal::Owned) {
+ V = V ^ RefVal::NotOwned;
+ break;
+ }
-void CFRefCount::evalBind(StmtNodeBuilderRef& B, SVal location, SVal val) {
- // Are we storing to something that causes the value to "escape"?
- bool escapes = false;
+ // Fall-through.
- // A value escapes in three possible cases (this may change):
- //
- // (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.
- const GRState *state = B.getState();
+ case DoNothing:
+ return state;
- if (!isa<loc::MemRegionVal>(location))
- escapes = true;
- else {
- const MemRegion* R = cast<loc::MemRegionVal>(location).getRegion();
- escapes = !R->hasStackStorage();
+ case Autorelease:
+ if (C.isObjCGCEnabled())
+ return state;
- if (!escapes) {
- // To test (3), generate a new state with the binding removed. If it is
- // the same state, then it escapes (since the store cannot represent
- // the binding).
- escapes = (state == (state->bindLoc(cast<Loc>(location), UnknownVal())));
- }
+ // Update the autorelease counts.
+ state = SendAutorelease(state, ARCountFactory, sym);
+ V = V.autorelease();
+ break;
+
+ case StopTracking:
+ return state->remove<RefBindings>(sym);
+
+ case IncRef:
+ switch (V.getKind()) {
+ default:
+ llvm_unreachable("Invalid RefVal state for a retain.");
+ break;
+ case RefVal::Owned:
+ case RefVal::NotOwned:
+ V = V + 1;
+ break;
+ case RefVal::Released:
+ // Non-GC cases are handled above.
+ assert(C.isObjCGCEnabled());
+ V = (V ^ RefVal::Owned) + 1;
+ break;
+ }
+ break;
+
+ case SelfOwn:
+ V = V ^ RefVal::NotOwned;
+ // Fall-through.
+ case DecRef:
+ case DecRefBridgedTransfered:
+ switch (V.getKind()) {
+ default:
+ // case 'RefVal::Released' handled above.
+ llvm_unreachable("Invalid RefVal state for a release.");
+ break;
+
+ case RefVal::Owned:
+ assert(V.getCount() > 0);
+ if (V.getCount() == 1)
+ V = V ^ (E == DecRefBridgedTransfered ?
+ RefVal::NotOwned : RefVal::Released);
+ V = V - 1;
+ break;
+
+ case RefVal::NotOwned:
+ if (V.getCount() > 0)
+ V = V - 1;
+ else {
+ V = V ^ RefVal::ErrorReleaseNotOwned;
+ hasErr = V.getKind();
+ }
+ break;
+
+ case RefVal::Released:
+ // Non-GC cases are handled above.
+ assert(C.isObjCGCEnabled());
+ V = V ^ RefVal::ErrorUseAfterRelease;
+ hasErr = V.getKind();
+ break;
+ }
+ break;
}
+ return state->set<RefBindings>(sym, V);
+}
- // 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)
+void RetainCountChecker::processNonLeakError(const ProgramState *St,
+ SourceRange ErrorRange,
+ RefVal::Kind ErrorKind,
+ SymbolRef Sym,
+ CheckerContext &C) const {
+ ExplodedNode *N = C.generateSink(St);
+ if (!N)
+ return;
+
+ CFRefBug *BT;
+ switch (ErrorKind) {
+ default:
+ llvm_unreachable("Unhandled error.");
return;
+ case RefVal::ErrorUseAfterRelease:
+ if (!useAfterRelease)
+ useAfterRelease.reset(new UseAfterRelease());
+ BT = &*useAfterRelease;
+ break;
+ case RefVal::ErrorReleaseNotOwned:
+ if (!releaseNotOwned)
+ releaseNotOwned.reset(new BadRelease());
+ BT = &*releaseNotOwned;
+ break;
+ case RefVal::ErrorDeallocGC:
+ if (!deallocGC)
+ deallocGC.reset(new DeallocGC());
+ BT = &*deallocGC;
+ break;
+ case RefVal::ErrorDeallocNotOwned:
+ if (!deallocNotOwned)
+ deallocNotOwned.reset(new DeallocNotOwned());
+ BT = &*deallocNotOwned;
+ break;
+ }
- // Otherwise, find all symbols referenced by 'val' that we are tracking
- // and stop tracking them.
- B.MakeNode(state->scanReachableSymbols<StopTrackingCallback>(val).getState());
+ assert(BT);
+ CFRefReport *report = new CFRefReport(*BT, C.getASTContext().getLangOptions(),
+ C.isObjCGCEnabled(), SummaryLog,
+ N, Sym);
+ report->addRange(ErrorRange);
+ C.EmitReport(report);
}
- // Return statements.
+//===----------------------------------------------------------------------===//
+// Handle the return values of retain-count-related functions.
+//===----------------------------------------------------------------------===//
+
+bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
+ // Get the callee. We're only interested in simple C functions.
+ const ProgramState *state = C.getState();
+ const Expr *Callee = CE->getCallee();
+ SVal L = state->getSVal(Callee);
-void CFRefCount::evalReturn(ExplodedNodeSet& Dst,
- ExprEngine& Eng,
- StmtNodeBuilder& Builder,
- const ReturnStmt* S,
- ExplodedNode* Pred) {
+ const FunctionDecl *FD = L.getAsFunctionDecl();
+ if (!FD)
+ return false;
+
+ IdentifierInfo *II = FD->getIdentifier();
+ if (!II)
+ return false;
+
+ // For now, we're only handling the functions that return aliases of their
+ // arguments: CFRetain and CFMakeCollectable (and their families).
+ // Eventually we should add other functions we can model entirely,
+ // such as CFRelease, which don't invalidate their arguments or globals.
+ if (CE->getNumArgs() != 1)
+ return false;
+
+ // Get the name of the function.
+ StringRef FName = II->getName();
+ FName = FName.substr(FName.find_first_not_of('_'));
+
+ // See if it's one of the specific functions we know how to eval.
+ bool canEval = false;
+
+ QualType ResultTy = FD->getResultType();
+ if (ResultTy->isObjCIdType()) {
+ // Handle: id NSMakeCollectable(CFTypeRef)
+ canEval = II->isStr("NSMakeCollectable");
+ } else if (ResultTy->isPointerType()) {
+ // Handle: (CF|CG)Retain
+ // CFMakeCollectable
+ // It's okay to be a little sloppy here (CGMakeCollectable doesn't exist).
+ if (cocoa::isRefType(ResultTy, "CF", FName) ||
+ cocoa::isRefType(ResultTy, "CG", FName)) {
+ canEval = isRetain(FD, FName) || isMakeCollectable(FD, FName);
+ }
+ }
+
+ if (!canEval)
+ return false;
+
+ // Bind the return value.
+ SVal RetVal = state->getSVal(CE->getArg(0));
+ if (RetVal.isUnknown()) {
+ // If the receiver is unknown, conjure a return value.
+ SValBuilder &SVB = C.getSValBuilder();
+ unsigned Count = C.getCurrentBlockCount();
+ SVal RetVal = SVB.getConjuredSymbolVal(0, CE, ResultTy, Count);
+ }
+ state = state->BindExpr(CE, RetVal, false);
+
+ // FIXME: This should not be necessary, but otherwise the argument seems to be
+ // considered alive during the next statement.
+ if (const MemRegion *ArgRegion = RetVal.getAsRegion()) {
+ // Save the refcount status of the argument.
+ SymbolRef Sym = RetVal.getAsLocSymbol();
+ RefBindings::data_type *Binding = 0;
+ if (Sym)
+ Binding = state->get<RefBindings>(Sym);
+
+ // Invalidate the argument region.
+ unsigned Count = C.getCurrentBlockCount();
+ state = state->invalidateRegions(ArgRegion, CE, Count);
+
+ // Restore the refcount status of the argument.
+ if (Binding)
+ state = state->set<RefBindings>(Sym, *Binding);
+ }
+
+ C.addTransition(state);
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Handle return statements.
+//===----------------------------------------------------------------------===//
- const Expr* RetE = S->getRetValue();
+void RetainCountChecker::checkPreStmt(const ReturnStmt *S,
+ CheckerContext &C) const {
+ const Expr *RetE = S->getRetValue();
if (!RetE)
return;
- const GRState *state = Builder.GetState(Pred);
+ const ProgramState *state = C.getState();
SymbolRef Sym = state->getSValAsScalarOrLoc(RetE).getAsLocSymbol();
-
if (!Sym)
return;
// Get the reference count binding (if any).
- const RefVal* T = state->get<RefBindings>(Sym);
-
+ const RefVal *T = state->get<RefBindings>(Sym);
if (!T)
return;
@@ -2951,7 +3083,7 @@ void CFRefCount::evalReturn(ExplodedNodeSet& Dst,
switch (X.getKind()) {
case RefVal::Owned: {
unsigned cnt = X.getCount();
- assert (cnt > 0);
+ assert(cnt > 0);
X.setCount(cnt - 1);
X = X ^ RefVal::ReturnedOwned;
break;
@@ -2975,21 +3107,25 @@ void CFRefCount::evalReturn(ExplodedNodeSet& Dst,
// Update the binding.
state = state->set<RefBindings>(Sym, X);
- Pred = Builder.MakeNode(Dst, S, Pred, state);
+ ExplodedNode *Pred = C.generateNode(state);
+
+ // At this point we have updated the state properly.
+ // Everything after this is merely checking to see if the return value has
+ // been over- or under-retained.
// Did we cache out?
if (!Pred)
return;
// Update the autorelease counts.
- static unsigned autoreleasetag = 0;
- GenericNodeBuilderRefCount Bd(Builder, S, &autoreleasetag);
- bool stop = false;
- llvm::tie(Pred, state) = HandleAutoreleaseCounts(state , Bd, Pred, Eng, Sym,
- X, stop);
+ static SimpleProgramPointTag
+ AutoreleaseTag("RetainCountChecker : Autorelease");
+ GenericNodeBuilderRefCount Bd(C, &AutoreleaseTag);
+ llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred,
+ C.getEngine(), Sym, X);
// Did we cache out?
- if (!Pred || stop)
+ if (!Pred)
return;
// Get the updated binding.
@@ -2998,36 +3134,37 @@ void CFRefCount::evalReturn(ExplodedNodeSet& Dst,
X = *T;
// Consult the summary of the enclosing method.
- Decl const *CD = &Pred->getCodeDecl();
+ RetainSummaryManager &Summaries = getSummaryManager(C);
+ const Decl *CD = &Pred->getCodeDecl();
- if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) {
- const RetainSummary &Summ = *Summaries.getMethodSummary(MD);
- return evalReturnWithRetEffect(Dst, Eng, Builder, S,
- Pred, Summ.getRetEffect(), X,
- Sym, state);
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CD)) {
+ // Unlike regular functions, /all/ ObjC methods are assumed to always
+ // follow Cocoa retain-count conventions, not just those with special
+ // names or attributes.
+ const RetainSummary *Summ = Summaries.getMethodSummary(MD);
+ RetEffect RE = Summ ? Summ->getRetEffect() : RetEffect::MakeNoRet();
+ checkReturnWithRetEffect(S, C, Pred, RE, X, Sym, state);
}
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) {
if (!isa<CXXMethodDecl>(FD))
if (const RetainSummary *Summ = Summaries.getSummary(FD))
- return evalReturnWithRetEffect(Dst, Eng, Builder, S,
- Pred, Summ->getRetEffect(), X,
- Sym, state);
+ checkReturnWithRetEffect(S, C, Pred, Summ->getRetEffect(), X,
+ Sym, state);
}
}
-void CFRefCount::evalReturnWithRetEffect(ExplodedNodeSet &Dst,
- ExprEngine &Eng,
- StmtNodeBuilder &Builder,
- const ReturnStmt *S,
- ExplodedNode *Pred,
- RetEffect RE, RefVal X,
- SymbolRef Sym, const GRState *state) {
+void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
+ CheckerContext &C,
+ ExplodedNode *Pred,
+ RetEffect RE, RefVal X,
+ SymbolRef Sym,
+ const ProgramState *state) const {
// Any leaks or other errors?
if (X.isReturnedOwned() && X.getCount() == 0) {
if (RE.getKind() != RetEffect::NoRet) {
bool hasError = false;
- if (isGCEnabled() && RE.getObjKind() == RetEffect::ObjC) {
+ if (C.isObjCGCEnabled() && RE.getObjKind() == RetEffect::ObjC) {
// Things are more complicated with garbage collection. If the
// returned object is suppose to be an Objective-C object, we have
// a leak (as the caller expects a GC'ed object) because no
@@ -3045,46 +3182,88 @@ void CFRefCount::evalReturnWithRetEffect(ExplodedNodeSet &Dst,
if (hasError) {
// Generate an error node.
- static int ReturnOwnLeakTag = 0;
state = state->set<RefBindings>(Sym, X);
- ExplodedNode *N =
- Builder.generateNode(PostStmt(S, Pred->getLocationContext(),
- &ReturnOwnLeakTag), state, Pred);
+
+ static SimpleProgramPointTag
+ ReturnOwnLeakTag("RetainCountChecker : ReturnsOwnLeak");
+ ExplodedNode *N = C.generateNode(state, Pred, &ReturnOwnLeakTag);
if (N) {
+ const LangOptions &LOpts = C.getASTContext().getLangOptions();
+ bool GCEnabled = C.isObjCGCEnabled();
CFRefReport *report =
- new CFRefLeakReport(*static_cast<CFRefBug*>(leakAtReturn), *this,
- N, Sym, Eng);
- BR->EmitReport(report);
+ new CFRefLeakReport(*getLeakAtReturnBug(LOpts, GCEnabled),
+ LOpts, GCEnabled, SummaryLog,
+ N, Sym, C.getEngine());
+ C.EmitReport(report);
}
}
}
- return;
- }
-
- if (X.isReturnedNotOwned()) {
+ } else if (X.isReturnedNotOwned()) {
if (RE.isOwned()) {
// Trying to return a not owned object to a caller expecting an
// owned object.
-
- static int ReturnNotOwnedForOwnedTag = 0;
state = state->set<RefBindings>(Sym, X ^ RefVal::ErrorReturnedNotOwned);
- if (ExplodedNode *N =
- Builder.generateNode(PostStmt(S, Pred->getLocationContext(),
- &ReturnNotOwnedForOwnedTag),
- state, Pred)) {
- CFRefReport *report =
- new CFRefReport(*static_cast<CFRefBug*>(returnNotOwnedForOwned),
- *this, N, Sym);
- BR->EmitReport(report);
+
+ static SimpleProgramPointTag
+ ReturnNotOwnedTag("RetainCountChecker : ReturnNotOwnedForOwned");
+ ExplodedNode *N = C.generateNode(state, Pred, &ReturnNotOwnedTag);
+ if (N) {
+ if (!returnNotOwnedForOwned)
+ returnNotOwnedForOwned.reset(new ReturnedNotOwnedForOwned());
+
+ CFRefReport *report =
+ new CFRefReport(*returnNotOwnedForOwned,
+ C.getASTContext().getLangOptions(),
+ C.isObjCGCEnabled(), SummaryLog, N, Sym);
+ C.EmitReport(report);
}
}
}
}
-// Assumptions.
+//===----------------------------------------------------------------------===//
+// Check various ways a symbol can be invalidated.
+//===----------------------------------------------------------------------===//
+
+void RetainCountChecker::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;
+
+ // A value escapes in three possible cases (this may change):
+ //
+ // (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.
+ const ProgramState *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).
+ 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);
+}
-const GRState* CFRefCount::evalAssume(const GRState *state,
- SVal Cond, bool Assumption) {
+const ProgramState *RetainCountChecker::evalAssume(const ProgramState *state,
+ SVal Cond,
+ bool Assumption) const {
// FIXME: We may add to the interface of evalAssume the list of symbols
// whose assumptions have changed. For now we just iterate through the
@@ -3098,9 +3277,9 @@ const GRState* CFRefCount::evalAssume(const GRState *state,
return state;
bool changed = false;
- RefBindings::Factory& RefBFactory = state->get_context<RefBindings>();
+ RefBindings::Factory &RefBFactory = state->get_context<RefBindings>();
- for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
+ for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
// Check if the symbol is null (or equal to any constant).
// If this is the case, stop tracking the symbol.
if (state->getSymVal(I.getKey())) {
@@ -3115,161 +3294,48 @@ const GRState* CFRefCount::evalAssume(const GRState *state,
return state;
}
-const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym,
- RefVal V, ArgEffect E,
- RefVal::Kind& hasErr) {
-
- // In GC mode [... release] and [... retain] do nothing.
- switch (E) {
- default: break;
- case IncRefMsg: E = isARCorGCEnabled() ? DoNothing : IncRef; break;
- case DecRefMsg: E = isARCorGCEnabled() ? DoNothing : DecRef; break;
- case MakeCollectable: E = isGCEnabled() ? DecRef : DoNothing; break;
- case NewAutoreleasePool: E = isGCEnabled() ? DoNothing :
- NewAutoreleasePool; break;
- }
+const ProgramState *
+RetainCountChecker::checkRegionChanges(const ProgramState *state,
+ const StoreManager::InvalidatedSymbols *invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions) const {
+ if (!invalidated)
+ return state;
- // Handle all use-after-releases.
- if (!isGCEnabled() && V.getKind() == RefVal::Released) {
- V = V ^ RefVal::ErrorUseAfterRelease;
- hasErr = V.getKind();
- return state->set<RefBindings>(sym, V);
+ llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols;
+ for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(),
+ E = ExplicitRegions.end(); I != E; ++I) {
+ if (const SymbolicRegion *SR = (*I)->StripCasts()->getAs<SymbolicRegion>())
+ WhitelistedSymbols.insert(SR->getSymbol());
}
- switch (E) {
- case DecRefMsg:
- case IncRefMsg:
- case MakeCollectable:
- assert(false &&
- "DecRefMsg/IncRefMsg/MakeCollectable already transformed");
- return state;
-
- case Dealloc:
- // Any use of -dealloc in GC is *bad*.
- if (isGCEnabled()) {
- V = V ^ RefVal::ErrorDeallocGC;
- hasErr = V.getKind();
- break;
- }
-
- switch (V.getKind()) {
- default:
- assert(false && "Invalid case.");
- case RefVal::Owned:
- // The object immediately transitions to the released state.
- V = V ^ RefVal::Released;
- V.clearCounts();
- return state->set<RefBindings>(sym, V);
- case RefVal::NotOwned:
- V = V ^ RefVal::ErrorDeallocNotOwned;
- hasErr = V.getKind();
- break;
- }
- break;
-
- case NewAutoreleasePool:
- assert(!isGCEnabled());
- return state->add<AutoreleaseStack>(sym);
-
- case MayEscape:
- if (V.getKind() == RefVal::Owned) {
- V = V ^ RefVal::NotOwned;
- break;
- }
-
- // Fall-through.
-
- case DoNothingByRef:
- case DoNothing:
- return state;
-
- case Autorelease:
- if (isGCEnabled())
- return state;
-
- // Update the autorelease counts.
- state = SendAutorelease(state, ARCountFactory, sym);
- V = V.autorelease();
- break;
-
- case StopTracking:
- return state->remove<RefBindings>(sym);
-
- case IncRef:
- switch (V.getKind()) {
- default:
- assert(false);
-
- case RefVal::Owned:
- case RefVal::NotOwned:
- V = V + 1;
- break;
- case RefVal::Released:
- // Non-GC cases are handled above.
- assert(isGCEnabled());
- V = (V ^ RefVal::Owned) + 1;
- break;
- }
- break;
-
- case SelfOwn:
- V = V ^ RefVal::NotOwned;
- // Fall-through.
- case DecRef:
- case DecRefBridgedTransfered:
- switch (V.getKind()) {
- default:
- // case 'RefVal::Released' handled above.
- assert (false);
-
- case RefVal::Owned:
- assert(V.getCount() > 0);
- if (V.getCount() == 1)
- V = V ^ (E == DecRefBridgedTransfered ?
- RefVal::NotOwned : RefVal::Released);
- V = V - 1;
- break;
-
- case RefVal::NotOwned:
- if (V.getCount() > 0)
- V = V - 1;
- else {
- V = V ^ RefVal::ErrorReleaseNotOwned;
- hasErr = V.getKind();
- }
- break;
-
- case RefVal::Released:
- // Non-GC cases are handled above.
- assert(isGCEnabled());
- V = V ^ RefVal::ErrorUseAfterRelease;
- hasErr = V.getKind();
- break;
- }
- break;
+ for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(),
+ E = invalidated->end(); I!=E; ++I) {
+ SymbolRef sym = *I;
+ if (WhitelistedSymbols.count(sym))
+ continue;
+ // Remove any existing reference-count binding.
+ state = state->remove<RefBindings>(sym);
}
- return state->set<RefBindings>(sym, V);
+ return state;
}
//===----------------------------------------------------------------------===//
// Handle dead symbols and end-of-path.
//===----------------------------------------------------------------------===//
-std::pair<ExplodedNode*, const GRState *>
-CFRefCount::HandleAutoreleaseCounts(const GRState * state,
- GenericNodeBuilderRefCount Bd,
- ExplodedNode* Pred,
- ExprEngine &Eng,
- SymbolRef Sym, RefVal V, bool &stop) {
-
+std::pair<ExplodedNode *, const ProgramState *>
+RetainCountChecker::handleAutoreleaseCounts(const ProgramState *state,
+ GenericNodeBuilderRefCount Bd,
+ ExplodedNode *Pred, ExprEngine &Eng,
+ SymbolRef Sym, RefVal V) const {
unsigned ACnt = V.getAutoreleaseCount();
- stop = false;
// No autorelease counts? Nothing to be done.
if (!ACnt)
return std::make_pair(Pred, state);
- assert(!isGCEnabled() && "Autorelease counts in GC mode?");
+ assert(!Eng.isObjCGCEnabled() && "Autorelease counts in GC mode?");
unsigned Cnt = V.getCount();
// FIXME: Handle sending 'autorelease' to already released object.
@@ -3284,48 +3350,54 @@ CFRefCount::HandleAutoreleaseCounts(const GRState * state,
V = V ^ RefVal::ReturnedNotOwned;
else
V = V ^ RefVal::NotOwned;
- }
- else {
+ } else {
V.setCount(Cnt - ACnt);
V.setAutoreleaseCount(0);
}
state = state->set<RefBindings>(Sym, V);
ExplodedNode *N = Bd.MakeNode(state, Pred);
- stop = (N == 0);
+ if (N == 0)
+ state = 0;
return std::make_pair(N, state);
}
// Woah! More autorelease counts then retain counts left.
// Emit hard error.
- stop = true;
V = V ^ RefVal::ErrorOverAutorelease;
state = state->set<RefBindings>(Sym, V);
if (ExplodedNode *N = Bd.MakeNode(state, Pred)) {
N->markAsSink();
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
+ llvm::SmallString<128> sbuf;
+ llvm::raw_svector_ostream os(sbuf);
os << "Object over-autoreleased: object was sent -autorelease ";
if (V.getAutoreleaseCount() > 1)
os << V.getAutoreleaseCount() << " times ";
os << "but the object has a +" << V.getCount() << " retain count";
+ if (!overAutorelease)
+ overAutorelease.reset(new OverAutorelease());
+
+ const LangOptions &LOpts = Eng.getContext().getLangOptions();
CFRefReport *report =
- new CFRefReport(*static_cast<CFRefBug*>(overAutorelease),
- *this, N, Sym, os.str());
- BR->EmitReport(report);
+ new CFRefReport(*overAutorelease, LOpts, /* GCEnabled = */ false,
+ SummaryLog, N, Sym, os.str());
+ Eng.getBugReporter().EmitReport(report);
}
- return std::make_pair((ExplodedNode*)0, state);
+ return std::make_pair((ExplodedNode *)0, (const ProgramState *)0);
}
-const GRState *
-CFRefCount::HandleSymbolDeath(const GRState * state, SymbolRef sid, RefVal V,
- llvm::SmallVectorImpl<SymbolRef> &Leaked) {
-
- bool hasLeak = V.isOwned() ||
- ((V.isNotOwned() || V.isReturnedOwned()) && V.getCount() > 0);
+const ProgramState *
+RetainCountChecker::handleSymbolDeath(const ProgramState *state,
+ SymbolRef sid, RefVal V,
+ SmallVectorImpl<SymbolRef> &Leaked) const {
+ bool hasLeak = false;
+ if (V.isOwned())
+ hasLeak = true;
+ else if (V.isNotOwned() || V.isReturnedOwned())
+ hasLeak = (V.getCount() > 0);
if (!hasLeak)
return state->remove<RefBindings>(sid);
@@ -3334,13 +3406,11 @@ CFRefCount::HandleSymbolDeath(const GRState * state, SymbolRef sid, RefVal V,
return state->set<RefBindings>(sid, V ^ RefVal::ErrorLeak);
}
-ExplodedNode*
-CFRefCount::ProcessLeaks(const GRState * state,
- llvm::SmallVectorImpl<SymbolRef> &Leaked,
- GenericNodeBuilderRefCount &Builder,
- ExprEngine& Eng,
- ExplodedNode *Pred) {
-
+ExplodedNode *
+RetainCountChecker::processLeaks(const ProgramState *state,
+ SmallVectorImpl<SymbolRef> &Leaked,
+ GenericNodeBuilderRefCount &Builder,
+ ExprEngine &Eng, ExplodedNode *Pred) const {
if (Leaked.empty())
return Pred;
@@ -3348,85 +3418,94 @@ CFRefCount::ProcessLeaks(const GRState * state,
ExplodedNode *N = Builder.MakeNode(state, Pred);
if (N) {
- for (llvm::SmallVectorImpl<SymbolRef>::iterator
+ for (SmallVectorImpl<SymbolRef>::iterator
I = Leaked.begin(), E = Leaked.end(); I != E; ++I) {
- CFRefBug *BT = static_cast<CFRefBug*>(Pred ? leakWithinFunction
- : leakAtReturn);
+ const LangOptions &LOpts = Eng.getContext().getLangOptions();
+ bool GCEnabled = Eng.isObjCGCEnabled();
+ CFRefBug *BT = Pred ? getLeakWithinFunctionBug(LOpts, GCEnabled)
+ : getLeakAtReturnBug(LOpts, GCEnabled);
assert(BT && "BugType not initialized.");
- CFRefLeakReport* report = new CFRefLeakReport(*BT, *this, N, *I, Eng);
- BR->EmitReport(report);
+
+ CFRefLeakReport *report = new CFRefLeakReport(*BT, LOpts, GCEnabled,
+ SummaryLog, N, *I, Eng);
+ Eng.getBugReporter().EmitReport(report);
}
}
return N;
}
-void CFRefCount::evalEndPath(ExprEngine& Eng,
- EndOfFunctionNodeBuilder& Builder) {
-
- const GRState *state = Builder.getState();
+void RetainCountChecker::checkEndPath(EndOfFunctionNodeBuilder &Builder,
+ ExprEngine &Eng) const {
+ const ProgramState *state = Builder.getState();
GenericNodeBuilderRefCount Bd(Builder);
RefBindings B = state->get<RefBindings>();
- ExplodedNode *Pred = 0;
+ ExplodedNode *Pred = Builder.getPredecessor();
for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- bool stop = false;
- llvm::tie(Pred, state) = HandleAutoreleaseCounts(state, Bd, Pred, Eng,
- (*I).first,
- (*I).second, stop);
-
- if (stop)
+ llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, Eng,
+ I->first, I->second);
+ if (!state)
return;
}
B = state->get<RefBindings>();
- llvm::SmallVector<SymbolRef, 10> Leaked;
+ SmallVector<SymbolRef, 10> Leaked;
for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I)
- state = HandleSymbolDeath(state, (*I).first, (*I).second, Leaked);
+ state = handleSymbolDeath(state, I->first, I->second, Leaked);
- ProcessLeaks(state, Leaked, Bd, Eng, Pred);
+ processLeaks(state, Leaked, Bd, Eng, Pred);
+}
+
+const ProgramPointTag *
+RetainCountChecker::getDeadSymbolTag(SymbolRef sym) const {
+ const SimpleProgramPointTag *&tag = DeadSymbolTags[sym];
+ if (!tag) {
+ llvm::SmallString<64> buf;
+ llvm::raw_svector_ostream out(buf);
+ out << "RetainCountChecker : Dead Symbol : " << sym->getSymbolID();
+ tag = new SimpleProgramPointTag(out.str());
+ }
+ return tag;
}
-void CFRefCount::evalDeadSymbols(ExplodedNodeSet& Dst,
- ExprEngine& Eng,
- StmtNodeBuilder& Builder,
- ExplodedNode* Pred,
- const GRState* state,
- SymbolReaper& SymReaper) {
- const Stmt *S = Builder.getStmt();
+void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
+ CheckerContext &C) const {
+ ExprEngine &Eng = C.getEngine();
+ ExplodedNode *Pred = C.getPredecessor();
+
+ const ProgramState *state = C.getState();
RefBindings B = state->get<RefBindings>();
// Update counts from autorelease pools
for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
E = SymReaper.dead_end(); I != E; ++I) {
SymbolRef Sym = *I;
- if (const RefVal* T = B.lookup(Sym)){
+ if (const RefVal *T = B.lookup(Sym)){
// Use the symbol as the tag.
// FIXME: This might not be as unique as we would like.
- GenericNodeBuilderRefCount Bd(Builder, S, Sym);
- bool stop = false;
- llvm::tie(Pred, state) = HandleAutoreleaseCounts(state, Bd, Pred, Eng,
- Sym, *T, stop);
- if (stop)
+ GenericNodeBuilderRefCount Bd(C, getDeadSymbolTag(Sym));
+ llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, Eng,
+ Sym, *T);
+ if (!state)
return;
}
}
B = state->get<RefBindings>();
- llvm::SmallVector<SymbolRef, 10> Leaked;
+ 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 (const RefVal *T = B.lookup(*I))
+ state = handleSymbolDeath(state, *I, *T, Leaked);
}
- static unsigned LeakPPTag = 0;
{
- GenericNodeBuilderRefCount Bd(Builder, S, &LeakPPTag);
- Pred = ProcessLeaks(state, Leaked, Bd, Eng, Pred);
+ GenericNodeBuilderRefCount Bd(C, this);
+ Pred = processLeaks(state, Leaked, Bd, Eng, Pred);
}
// Did we cache out?
@@ -3434,256 +3513,76 @@ void CFRefCount::evalDeadSymbols(ExplodedNodeSet& Dst,
return;
// Now generate a new node that nukes the old bindings.
- RefBindings::Factory& F = state->get_context<RefBindings>();
+ RefBindings::Factory &F = state->get_context<RefBindings>();
for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
- E = SymReaper.dead_end(); I!=E; ++I) B = F.remove(B, *I);
+ E = SymReaper.dead_end(); I != E; ++I)
+ B = F.remove(B, *I);
state = state->set<RefBindings>(B);
- Builder.MakeNode(Dst, S, Pred, state);
-}
-
-void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst,
- StmtNodeBuilder& Builder,
- const Expr* NodeExpr,
- SourceRange ErrorRange,
- ExplodedNode* Pred,
- const GRState* St,
- RefVal::Kind hasErr, SymbolRef Sym) {
- Builder.BuildSinks = true;
- ExplodedNode *N = Builder.MakeNode(Dst, NodeExpr, Pred, St);
-
- if (!N)
- return;
-
- CFRefBug *BT = 0;
-
- switch (hasErr) {
- default:
- assert(false && "Unhandled error.");
- return;
- case RefVal::ErrorUseAfterRelease:
- BT = static_cast<CFRefBug*>(useAfterRelease);
- break;
- case RefVal::ErrorReleaseNotOwned:
- BT = static_cast<CFRefBug*>(releaseNotOwned);
- break;
- case RefVal::ErrorDeallocGC:
- BT = static_cast<CFRefBug*>(deallocGC);
- break;
- case RefVal::ErrorDeallocNotOwned:
- BT = static_cast<CFRefBug*>(deallocNotOwned);
- break;
- }
-
- CFRefReport *report = new CFRefReport(*BT, *this, N, Sym);
- report->addRange(ErrorRange);
- BR->EmitReport(report);
+ C.generateNode(state, Pred);
}
//===----------------------------------------------------------------------===//
-// Pieces of the retain/release checker implemented using a CheckerVisitor.
-// More pieces of the retain/release checker will be migrated to this interface
-// (ideally, all of it some day).
+// Debug printing of refcount bindings and autorelease pools.
//===----------------------------------------------------------------------===//
-namespace {
-class RetainReleaseChecker
- : public Checker< check::PostStmt<BlockExpr>,
- check::PostStmt<CastExpr>,
- check::RegionChanges > {
-public:
- bool wantsRegionUpdate;
-
- RetainReleaseChecker() : wantsRegionUpdate(true) {}
-
-
- void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
-
- void checkPostStmt(const CastExpr *CE, CheckerContext &C) const;
-
- const GRState *checkRegionChanges(const GRState *state,
- const StoreManager::InvalidatedSymbols *invalidated,
- const MemRegion * const *begin,
- const MemRegion * const *end) const;
-
- bool wantsRegionChangeUpdate(const GRState *state) const {
- return wantsRegionUpdate;
- }
-};
-} // end anonymous namespace
+static void PrintPool(raw_ostream &Out, SymbolRef Sym,
+ const ProgramState *State) {
+ Out << ' ';
+ if (Sym)
+ Out << Sym->getSymbolID();
+ else
+ Out << "<pool>";
+ Out << ":{";
-const GRState *
-RetainReleaseChecker::checkRegionChanges(const GRState *state,
- const StoreManager::InvalidatedSymbols *invalidated,
- const MemRegion * const *begin,
- const MemRegion * const *end) const {
- if (!invalidated)
- return state;
+ // Get the contents of the pool.
+ if (const ARCounts *Cnts = State->get<AutoreleasePoolContents>(Sym))
+ for (ARCounts::iterator I = Cnts->begin(), E = Cnts->end(); I != E; ++I)
+ Out << '(' << I.getKey() << ',' << I.getData() << ')';
- for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(),
- E = invalidated->end(); I!=E; ++I) {
- SymbolRef sym = *I;
- if (WhitelistedSymbols.count(sym))
- continue;
- // Remove any existing reference-count binding.
- state = state->remove<RefBindings>(sym);
- }
- return state;
+ Out << '}';
}
-void RetainReleaseChecker::checkPostStmt(const BlockExpr *BE,
- CheckerContext &C) const {
-
- // Scan the BlockDecRefExprs for any object the retain/release checker
- // may be tracking.
- if (!BE->getBlockDecl()->hasCaptures())
- return;
+static bool UsesAutorelease(const ProgramState *state) {
+ // A state uses autorelease if it allocated an autorelease pool or if it has
+ // objects in the caller's autorelease pool.
+ return !state->get<AutoreleaseStack>().isEmpty() ||
+ state->get<AutoreleasePoolContents>(SymbolRef());
+}
- const GRState *state = C.getState();
- const BlockDataRegion *R =
- cast<BlockDataRegion>(state->getSVal(BE).getAsRegion());
+void RetainCountChecker::printState(raw_ostream &Out, const ProgramState *State,
+ const char *NL, const char *Sep) const {
- BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
- E = R->referenced_vars_end();
+ RefBindings B = State->get<RefBindings>();
- if (I == E)
- return;
-
- // FIXME: For now we invalidate the tracking of all symbols passed to blocks
- // via captured variables, even though captured variables result in a copy
- // and in implicit increment/decrement of a retain count.
- llvm::SmallVector<const MemRegion*, 10> Regions;
- const LocationContext *LC = C.getPredecessor()->getLocationContext();
- MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
+ if (!B.isEmpty())
+ Out << Sep << NL;
- for ( ; I != E; ++I) {
- const VarRegion *VR = *I;
- if (VR->getSuperRegion() == R) {
- VR = MemMgr.getVarRegion(VR->getDecl(), LC);
- }
- Regions.push_back(VR);
+ for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ Out << I->first << " : ";
+ I->second.print(Out);
+ Out << NL;
}
- state =
- state->scanReachableSymbols<StopTrackingCallback>(Regions.data(),
- Regions.data() + Regions.size()).getState();
- C.addTransition(state);
-}
+ // Print the autorelease stack.
+ if (UsesAutorelease(State)) {
+ Out << Sep << NL << "AR pool stack:";
+ ARStack Stack = State->get<AutoreleaseStack>();
-void RetainReleaseChecker::checkPostStmt(const CastExpr *CE,
- CheckerContext &C) const {
- const ObjCBridgedCastExpr *BE = dyn_cast<ObjCBridgedCastExpr>(CE);
- if (!BE)
- return;
-
- ArgEffect AE = IncRef;
-
- switch (BE->getBridgeKind()) {
- case clang::OBC_Bridge:
- // Do nothing.
- return;
- case clang::OBC_BridgeRetained:
- AE = IncRef;
- break;
- case clang::OBC_BridgeTransfer:
- AE = DecRefBridgedTransfered;
- break;
- }
-
- const GRState *state = C.getState();
- SymbolRef Sym = state->getSVal(CE).getAsLocSymbol();
- if (!Sym)
- return;
- const RefVal* T = state->get<RefBindings>(Sym);
- if (!T)
- return;
+ PrintPool(Out, SymbolRef(), State); // Print the caller's pool.
+ for (ARStack::iterator I = Stack.begin(), E = Stack.end(); I != E; ++I)
+ PrintPool(Out, *I, State);
- // This is gross. Once the checker and CFRefCount are unified,
- // this will go away.
- CFRefCount &cf = static_cast<CFRefCount&>(C.getEngine().getTF());
- RefVal::Kind hasErr = (RefVal::Kind) 0;
- state = cf.Update(state, Sym, *T, AE, hasErr);
-
- if (hasErr) {
-
- return;
+ Out << NL;
}
-
- C.generateNode(state);
}
//===----------------------------------------------------------------------===//
-// Transfer function creation for external clients.
+// Checker registration.
//===----------------------------------------------------------------------===//
-void CFRefCount::RegisterChecks(ExprEngine& Eng) {
- BugReporter &BR = Eng.getBugReporter();
-
- useAfterRelease = new UseAfterRelease(this);
- BR.Register(useAfterRelease);
-
- releaseNotOwned = new BadRelease(this);
- BR.Register(releaseNotOwned);
-
- deallocGC = new DeallocGC(this);
- BR.Register(deallocGC);
-
- deallocNotOwned = new DeallocNotOwned(this);
- BR.Register(deallocNotOwned);
-
- overAutorelease = new OverAutorelease(this);
- BR.Register(overAutorelease);
-
- returnNotOwnedForOwned = new ReturnedNotOwnedForOwned(this);
- BR.Register(returnNotOwnedForOwned);
-
- // First register "return" leaks.
- const char* name = 0;
-
- if (isGCEnabled())
- name = "Leak of returned object when using garbage collection";
- else if (getLangOptions().getGCMode() == LangOptions::HybridGC)
- name = "Leak of returned object when not using garbage collection (GC) in "
- "dual GC/non-GC code";
- else {
- assert(getLangOptions().getGCMode() == LangOptions::NonGC);
- name = "Leak of returned object";
- }
-
- // Leaks should not be reported if they are post-dominated by a sink.
- leakAtReturn = new LeakAtReturn(this, name);
- leakAtReturn->setSuppressOnSink(true);
- BR.Register(leakAtReturn);
-
- // Second, register leaks within a function/method.
- if (isGCEnabled())
- name = "Leak of object when using garbage collection";
- else if (getLangOptions().getGCMode() == LangOptions::HybridGC)
- name = "Leak of object when not using garbage collection (GC) in "
- "dual GC/non-GC code";
- else {
- assert(getLangOptions().getGCMode() == LangOptions::NonGC);
- name = "Leak";
- }
-
- // Leaks should not be reported if they are post-dominated by sinks.
- leakWithinFunction = new LeakWithinFunction(this, name);
- leakWithinFunction->setSuppressOnSink(true);
- BR.Register(leakWithinFunction);
-
- // Save the reference to the BugReporter.
- this->BR = &BR;
-
- // Register the RetainReleaseChecker with the ExprEngine object.
- // Functionality in CFRefCount will be migrated to RetainReleaseChecker
- // over time.
- // FIXME: HACK! Remove TransferFuncs and turn all of CFRefCount into fully
- // using the checker mechanism.
- Eng.getCheckerManager().registerChecker<RetainReleaseChecker>();
+void ento::registerRetainCountChecker(CheckerManager &Mgr) {
+ Mgr.registerChecker<RetainCountChecker>();
}
-TransferFuncs* ento::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
- const LangOptions& lopts) {
- return new CFRefCount(Ctx, GCEnabled, lopts);
-}
diff --git a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
index 1729b25a2979..e761bff85583 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
@@ -33,7 +33,7 @@ public:
void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
CheckerContext &C) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
const Expr *RetE = RS->getRetValue();
if (!RetE)
@@ -58,8 +58,8 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
= C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
ER->getValueType());
- const GRState *StInBound = state->assumeInBound(Idx, NumElements, true);
- const GRState *StOutBound = state->assumeInBound(Idx, NumElements, false);
+ const ProgramState *StInBound = state->assumeInBound(Idx, NumElements, true);
+ const ProgramState *StOutBound = state->assumeInBound(Idx, NumElements, false);
if (StOutBound && !StInBound) {
ExplodedNode *N = C.generateSink(StOutBound);
@@ -78,8 +78,8 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
// reference is outside the range.
// Generate a report for this bug.
- RangedBugReport *report =
- new RangedBugReport(*BT, BT->getDescription(), N);
+ BugReport *report =
+ new BugReport(*BT, BT->getDescription(), N);
report->addRange(RetE->getSourceRange());
C.EmitReport(report);
diff --git a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
index 7c215b7cf318..e8c8d902a5e5 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
@@ -50,11 +50,11 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS,
BT.reset(new BuiltinBug("Garbage return value",
"Undefined or garbage value returned to caller"));
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT, BT->getDescription(), N);
+ BugReport *report =
+ new BugReport(*BT, BT->getDescription(), N);
report->addRange(RetE->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, RetE);
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, RetE));
C.EmitReport(report);
}
diff --git a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 73ce359edc3e..91c4b96d695e 100644
--- a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -17,7 +17,7 @@
#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/GRState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -35,12 +35,12 @@ public:
private:
void EmitStackError(CheckerContext &C, const MemRegion *R,
const Expr *RetE) const;
- static SourceRange GenName(llvm::raw_ostream &os, const MemRegion *R,
+ static SourceRange GenName(raw_ostream &os, const MemRegion *R,
SourceManager &SM);
};
}
-SourceRange StackAddrEscapeChecker::GenName(llvm::raw_ostream &os,
+SourceRange StackAddrEscapeChecker::GenName(raw_ostream &os,
const MemRegion *R,
SourceManager &SM) {
// Get the base region, stripping away fields and elements.
@@ -50,34 +50,39 @@ SourceRange StackAddrEscapeChecker::GenName(llvm::raw_ostream &os,
// Check if the region is a compound literal.
if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {
- const CompoundLiteralExpr* CL = CR->getLiteralExpr();
+ const CompoundLiteralExpr *CL = CR->getLiteralExpr();
os << "stack memory associated with a compound literal "
"declared on line "
- << SM.getInstantiationLineNumber(CL->getLocStart())
+ << SM.getExpansionLineNumber(CL->getLocStart())
<< " returned to caller";
range = CL->getSourceRange();
}
else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) {
- const Expr* ARE = AR->getExpr();
+ const Expr *ARE = AR->getExpr();
SourceLocation L = ARE->getLocStart();
range = ARE->getSourceRange();
os << "stack memory allocated by call to alloca() on line "
- << SM.getInstantiationLineNumber(L);
+ << SM.getExpansionLineNumber(L);
}
else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
const BlockDecl *BD = BR->getCodeRegion()->getDecl();
SourceLocation L = BD->getLocStart();
range = BD->getSourceRange();
os << "stack-allocated block declared on line "
- << SM.getInstantiationLineNumber(L);
+ << SM.getExpansionLineNumber(L);
}
else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
os << "stack memory associated with local variable '"
<< VR->getString() << '\'';
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() << '\'';
+ range = TOR->getExpr()->getSourceRange();
+ }
else {
- assert(false && "Invalid region in ReturnStackAddressChecker.");
+ llvm_unreachable("Invalid region in ReturnStackAddressChecker.");
}
return range;
@@ -99,7 +104,7 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *
llvm::raw_svector_ostream os(buf);
SourceRange range = GenName(os, R, C.getSourceManager());
os << " returned to caller";
- RangedBugReport *report = new RangedBugReport(*BT_returnstack, os.str(), N);
+ BugReport *report = new BugReport(*BT_returnstack, os.str(), N);
report->addRange(RetE->getSourceRange());
if (range.isValid())
report->addRange(range);
@@ -134,7 +139,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
ExprEngine &Eng) const {
- const GRState *state = B.getState();
+ const ProgramState *state = B.getState();
// Iterate over all bindings to global variables and see if it contains
// a memory region in the stack space.
@@ -143,7 +148,7 @@ void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
ExprEngine &Eng;
const StackFrameContext *CurSFC;
public:
- llvm::SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V;
+ SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V;
CallBack(ExprEngine &Eng, const LocationContext *LCtx)
: Eng(Eng), CurSFC(LCtx->getCurrentStackFrame()) {}
@@ -202,9 +207,9 @@ void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
Eng.getContext().getSourceManager());
os << " is still referred to by the global variable '";
const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion());
- os << VR->getDecl()->getNameAsString()
+ os << *VR->getDecl()
<< "' upon returning to the caller. This will be a dangling reference";
- RangedBugReport *report = new RangedBugReport(*BT_stackleak, os.str(), N);
+ BugReport *report = new BugReport(*BT_stackleak, os.str(), N);
if (range.isValid())
report->addRange(range);
diff --git a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index 711c672c1448..1d14e9e15e42 100644
--- a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -16,8 +16,8 @@
#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/GRState.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "llvm/ADT/ImmutableMap.h"
@@ -96,9 +96,9 @@ private:
void OpenFileAux(CheckerContext &C, const CallExpr *CE) const;
- const GRState *CheckNullStream(SVal SV, const GRState *state,
+ const ProgramState *CheckNullStream(SVal SV, const ProgramState *state,
CheckerContext &C) const;
- const GRState *CheckDoubleClose(const CallExpr *CE, const GRState *state,
+ const ProgramState *CheckDoubleClose(const CallExpr *CE, const ProgramState *state,
CheckerContext &C) const;
};
@@ -107,15 +107,15 @@ private:
namespace clang {
namespace ento {
template <>
- struct GRStateTrait<StreamState>
- : public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, StreamState> > {
+ struct ProgramStateTrait<StreamState>
+ : public ProgramStatePartialTrait<llvm::ImmutableMap<SymbolRef, StreamState> > {
static void *GDMIndex() { static int x; return &x; }
};
}
}
bool StreamChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
const FunctionDecl *FD = L.getAsFunctionDecl();
@@ -221,8 +221,8 @@ void StreamChecker::Tmpfile(CheckerContext &C, const CallExpr *CE) const {
}
void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
- const GRState *state = C.getState();
- unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+ const ProgramState *state = C.getState();
+ unsigned Count = C.getCurrentBlockCount();
SValBuilder &svalBuilder = C.getSValBuilder();
DefinedSVal RetVal =
cast<DefinedSVal>(svalBuilder.getConjuredSymbolVal(0, CE, Count));
@@ -231,7 +231,7 @@ void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
ConstraintManager &CM = C.getConstraintManager();
// Bifurcate the state into two: one with a valid FILE* pointer, the other
// with a NULL.
- const GRState *stateNotNull, *stateNull;
+ const ProgramState *stateNotNull, *stateNull;
llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, RetVal);
if (SymbolRef Sym = RetVal.getAsSymbol()) {
@@ -247,25 +247,25 @@ void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
}
void StreamChecker::Fclose(CheckerContext &C, const CallExpr *CE) const {
- const GRState *state = CheckDoubleClose(CE, C.getState(), C);
+ const ProgramState *state = CheckDoubleClose(CE, C.getState(), C);
if (state)
C.addTransition(state);
}
void StreamChecker::Fread(CheckerContext &C, const CallExpr *CE) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C))
return;
}
void StreamChecker::Fwrite(CheckerContext &C, const CallExpr *CE) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C))
return;
}
void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
if (!(state = CheckNullStream(state->getSVal(CE->getArg(0)), state, C)))
return;
// Check the legality of the 'whence' argument of 'fseek'.
@@ -291,61 +291,61 @@ void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const {
}
void StreamChecker::Ftell(CheckerContext &C, const CallExpr *CE) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
void StreamChecker::Rewind(CheckerContext &C, const CallExpr *CE) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
void StreamChecker::Fgetpos(CheckerContext &C, const CallExpr *CE) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
void StreamChecker::Fsetpos(CheckerContext &C, const CallExpr *CE) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
void StreamChecker::Clearerr(CheckerContext &C, const CallExpr *CE) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
void StreamChecker::Feof(CheckerContext &C, const CallExpr *CE) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
void StreamChecker::Ferror(CheckerContext &C, const CallExpr *CE) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
void StreamChecker::Fileno(CheckerContext &C, const CallExpr *CE) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
-const GRState *StreamChecker::CheckNullStream(SVal SV, const GRState *state,
+const ProgramState *StreamChecker::CheckNullStream(SVal SV, const ProgramState *state,
CheckerContext &C) const {
const DefinedSVal *DV = dyn_cast<DefinedSVal>(&SV);
if (!DV)
return 0;
ConstraintManager &CM = C.getConstraintManager();
- const GRState *stateNotNull, *stateNull;
+ const ProgramState *stateNotNull, *stateNull;
llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
if (!stateNotNull && stateNull) {
@@ -361,8 +361,8 @@ const GRState *StreamChecker::CheckNullStream(SVal SV, const GRState *state,
return stateNotNull;
}
-const GRState *StreamChecker::CheckDoubleClose(const CallExpr *CE,
- const GRState *state,
+const ProgramState *StreamChecker::CheckDoubleClose(const CallExpr *CE,
+ const ProgramState *state,
CheckerContext &C) const {
SymbolRef Sym = state->getSVal(CE->getArg(0)).getAsSymbol();
if (!Sym)
@@ -399,7 +399,7 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
E = SymReaper.dead_end(); I != E; ++I) {
SymbolRef Sym = *I;
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
const StreamState *SS = state->get<StreamState>(Sym);
if (!SS)
return;
@@ -420,7 +420,7 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
void StreamChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
ExprEngine &Eng) const {
- const GRState *state = B.getState();
+ const ProgramState *state = B.getState();
typedef llvm::ImmutableMap<SymbolRef, StreamState> SymMap;
SymMap M = state->get<StreamState>();
@@ -445,7 +445,7 @@ void StreamChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
if (!RetE)
return;
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
SymbolRef Sym = state->getSVal(RetE).getAsSymbol();
if (!Sym)
diff --git a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
index 1fb181591b42..b860b34ff359 100644
--- a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
@@ -27,26 +27,25 @@ class UndefBranchChecker : public Checker<check::BranchCondition> {
mutable llvm::OwningPtr<BuiltinBug> BT;
struct FindUndefExpr {
- GRStateManager& VM;
- const GRState* St;
+ const ProgramState *St;
- FindUndefExpr(GRStateManager& V, const GRState* S) : VM(V), St(S) {}
+ FindUndefExpr(const ProgramState *S) : St(S) {}
- const Expr* FindExpr(const Expr* Ex) {
+ const Expr *FindExpr(const Expr *Ex) {
if (!MatchesCriteria(Ex))
return 0;
for (Stmt::const_child_iterator I = Ex->child_begin(),
E = Ex->child_end();I!=E;++I)
- if (const Expr* ExI = dyn_cast_or_null<Expr>(*I)) {
- const Expr* E2 = FindExpr(ExI);
+ if (const Expr *ExI = dyn_cast_or_null<Expr>(*I)) {
+ const Expr *E2 = FindExpr(ExI);
if (E2) return E2;
}
return Ex;
}
- bool MatchesCriteria(const Expr* Ex) { return St->getSVal(Ex).isUndef(); }
+ bool MatchesCriteria(const Expr *Ex) { return St->getSVal(Ex).isUndef(); }
};
public:
@@ -59,10 +58,10 @@ public:
void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
BranchNodeBuilder &Builder,
ExprEngine &Eng) const {
- const GRState *state = Builder.getState();
+ const ProgramState *state = Builder.getState();
SVal X = state->getSVal(Condition);
if (X.isUndef()) {
- ExplodedNode *N = Builder.generateNode(state, true);
+ ExplodedNode *N = Builder.generateNode(Condition, state);
if (N) {
N->markAsSink();
if (!BT)
@@ -74,33 +73,31 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
// branch condition." We do a recursive walk of the condition's
// subexpressions and roughly look for the most nested subexpression
// that binds to Undefined. We then highlight that expression's range.
- BlockEdge B = cast<BlockEdge>(N->getLocation());
- const Expr* Ex = cast<Expr>(B.getSrc()->getTerminatorCondition());
- assert (Ex && "Block must have a terminator.");
// Get the predecessor node and check if is a PostStmt with the Stmt
// being the terminator condition. We want to inspect the state
// of that node instead because it will contain main information about
// the subexpressions.
- assert (!N->pred_empty());
// Note: any predecessor will do. They should have identical state,
// since all the BlockEdge did was act as an error sink since the value
// had to already be undefined.
+ assert (!N->pred_empty());
+ const Expr *Ex = cast<Expr>(Condition);
ExplodedNode *PrevN = *N->pred_begin();
ProgramPoint P = PrevN->getLocation();
- const GRState* St = N->getState();
+ const ProgramState *St = N->getState();
- if (PostStmt* PS = dyn_cast<PostStmt>(&P))
+ if (PostStmt *PS = dyn_cast<PostStmt>(&P))
if (PS->getStmt() == Ex)
St = PrevN->getState();
- FindUndefExpr FindIt(Eng.getStateManager(), St);
+ FindUndefExpr FindIt(St);
Ex = FindIt.FindExpr(Ex);
// Emit the bug report.
- EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getDescription(),N);
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
+ BugReport *R = new BugReport(*BT, BT->getDescription(), N);
+ R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex));
R->addRange(Ex->getSourceRange());
Eng.getBugReporter().EmitReport(R);
diff --git a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
index 69958d11f717..2aebed9346d6 100644
--- a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
@@ -55,7 +55,7 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
if (!BE->getBlockDecl()->hasCaptures())
return;
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
const BlockDataRegion *R =
cast<BlockDataRegion>(state->getSVal(BE).getAsRegion());
@@ -74,8 +74,9 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
// Get the VarRegion associated with VD in the local stack frame.
const LocationContext *LC = C.getPredecessor()->getLocationContext();
VR = C.getSValBuilder().getRegionManager().getVarRegion(VD, LC);
+ SVal VRVal = state->getSVal(VR);
- if (state->getSVal(VR).isUndef())
+ if (VRVal.isUndef())
if (ExplodedNode *N = C.generateSink()) {
if (!BT)
BT.reset(new BuiltinBug("uninitialized variable captured by block"));
@@ -87,10 +88,10 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
os << "Variable '" << VD->getName()
<< "' is uninitialized when captured by block";
- EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N);
+ BugReport *R = new BugReport(*BT, os.str(), N);
if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD))
R->addRange(Ex->getSourceRange());
- R->addVisitorCreator(bugreporter::registerFindLastStore, VR);
+ R->addVisitor(new FindLastStoreBRVisitor(VRVal, VR));
// need location of block
C.EmitReport(R);
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
index 7fa3804639d6..7ae966865c86 100644
--- a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
@@ -35,7 +35,7 @@ public:
void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
CheckerContext &C) const {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
if (state->getSVal(B).isUndef()) {
// Generate an error node.
ExplodedNode *N = C.generateSink();
@@ -71,13 +71,13 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
<< BinaryOperator::getOpcodeStr(B->getOpcode())
<< "' expression is undefined";
}
- EnhancedBugReport *report = new EnhancedBugReport(*BT, OS.str(), N);
+ BugReport *report = new BugReport(*BT, OS.str(), N);
if (Ex) {
report->addRange(Ex->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex));
}
else
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, B);
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, B));
C.EmitReport(report);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
index e51ab20d2f30..bb6831b78301 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
@@ -40,10 +40,10 @@ UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
BT.reset(new BuiltinBug("Array subscript is undefined"));
// Generate a report for this bug.
- EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
+ BugReport *R = new BugReport(*BT, BT->getName(), N);
R->addRange(A->getIdx()->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- A->getIdx());
+ R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
+ A->getIdx()));
C.EmitReport(R);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
index 28806e3db917..5ca4a9fe46d2 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
@@ -27,11 +27,13 @@ class UndefinedAssignmentChecker
mutable llvm::OwningPtr<BugType> BT;
public:
- void checkBind(SVal location, SVal val, CheckerContext &C) const;
+ void checkBind(SVal location, SVal val, const Stmt *S,
+ CheckerContext &C) const;
};
}
void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
+ const Stmt *StoreE,
CheckerContext &C) const {
if (!val.isUndef())
return;
@@ -49,11 +51,10 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
// Generate a report for this bug.
const Expr *ex = 0;
- const Stmt *StoreE = C.getStmt();
while (StoreE) {
if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) {
if (B->isCompoundAssignmentOp()) {
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
if (state->getSVal(B->getLHS()).isUndef()) {
str = "The left expression of the compound assignment is an "
"uninitialized value. The computed value will also be garbage";
@@ -67,17 +68,17 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
}
if (const DeclStmt *DS = dyn_cast<DeclStmt>(StoreE)) {
- const VarDecl* VD = dyn_cast<VarDecl>(DS->getSingleDecl());
+ const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
ex = VD->getInit();
}
break;
}
- EnhancedBugReport *R = new EnhancedBugReport(*BT, str, N);
+ BugReport *R = new BugReport(*BT, str, N);
if (ex) {
R->addRange(ex->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, ex);
+ R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, ex));
}
C.EmitReport(R);
}
diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index 0ecc391f3e8f..cec286d2f3e9 100644
--- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -62,7 +62,8 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
// The definition of O_CREAT is platform specific. We need a better way
// of querying this information from the checking environment.
if (!Val_O_CREAT.hasValue()) {
- if (C.getASTContext().Target.getTriple().getVendor() == llvm::Triple::Apple)
+ if (C.getASTContext().getTargetInfo().getTriple().getVendor()
+ == llvm::Triple::Apple)
Val_O_CREAT = 0x0200;
else {
// FIXME: We need a more general way of getting the O_CREAT value.
@@ -73,7 +74,7 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
}
// Look at the 'oflags' argument for the O_CREAT flag.
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
if (CE->getNumArgs() < 2) {
// The frontend should issue a warning for this case, so this is a sanity
@@ -101,7 +102,7 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
DefinedSVal maskedFlags = cast<DefinedSVal>(maskedFlagsUC);
// Check if maskedFlags is non-zero.
- const GRState *trueState, *falseState;
+ const ProgramState *trueState, *falseState;
llvm::tie(trueState, falseState) = state->assume(maskedFlags);
// Only emit an error if the value of 'maskedFlags' is properly
@@ -116,8 +117,8 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
LazyInitialize(BT_open, "Improper use of 'open'");
- RangedBugReport *report =
- new RangedBugReport(*BT_open,
+ BugReport *report =
+ new BugReport(*BT_open,
"Call to 'open' requires a third argument when "
"the 'O_CREAT' flag is set", N);
report->addRange(oflagsEx->getSourceRange());
@@ -140,7 +141,7 @@ void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C,
// Check if the first argument is stack allocated. If so, issue a warning
// because that's likely to be bad news.
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
return;
@@ -163,7 +164,7 @@ void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C,
LazyInitialize(BT_pthreadOnce, "Improper use of 'pthread_once'");
- RangedBugReport *report = new RangedBugReport(*BT_pthreadOnce, os.str(), N);
+ BugReport *report = new BugReport(*BT_pthreadOnce, os.str(), N);
report->addRange(CE->getArg(0)->getSourceRange());
C.EmitReport(report);
}
@@ -182,13 +183,13 @@ void UnixAPIChecker::CheckMallocZero(CheckerContext &C,
return;
// Check if the allocation size is 0.
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
SVal argVal = state->getSVal(CE->getArg(0));
if (argVal.isUnknownOrUndef())
return;
- const GRState *trueState, *falseState;
+ const ProgramState *trueState, *falseState;
llvm::tie(trueState, falseState) = state->assume(cast<DefinedSVal>(argVal));
// Is the value perfectly constrained to zero?
@@ -202,12 +203,12 @@ void UnixAPIChecker::CheckMallocZero(CheckerContext &C,
LazyInitialize(BT_mallocZero, "Undefined allocation of 0 bytes");
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT_mallocZero, "Call to 'malloc' has an allocation"
+ BugReport *report =
+ new BugReport(*BT_mallocZero, "Call to 'malloc' has an allocation"
" size of 0 bytes", N);
report->addRange(CE->getArg(0)->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- CE->getArg(0));
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
+ CE->getArg(0)));
C.EmitReport(report);
return;
}
@@ -225,7 +226,7 @@ void UnixAPIChecker::CheckMallocZero(CheckerContext &C,
void UnixAPIChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
// Get the callee. All the functions we care about are C functions
// with simple identifiers.
- const GRState *state = C.getState();
+ const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
const FunctionDecl *Fn = state->getSVal(Callee).getAsFunctionDecl();
diff --git a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
index b540bce98170..459ee65d19d9 100644
--- a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
@@ -60,11 +60,12 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
CFG *C = 0;
ParentMap *PM = 0;
+ const LocationContext *LC = 0;
// Iterate over ExplodedGraph
for (ExplodedGraph::node_iterator I = G.nodes_begin(), E = G.nodes_end();
I != E; ++I) {
const ProgramPoint &P = I->getLocation();
- const LocationContext *LC = P.getLocationContext();
+ LC = P.getLocationContext();
// Save the CFG if we don't have it already
if (!C)
@@ -111,22 +112,30 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
// FIXME: This should be extended to include other unreachable markers,
// such as llvm_unreachable.
if (!CB->empty()) {
- CFGElement First = CB->front();
- if (const CFGStmt *S = First.getAs<CFGStmt>()) {
- if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) {
- if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable)
- continue;
- }
+ bool foundUnreachable = false;
+ for (CFGBlock::const_iterator ci = CB->begin(), ce = CB->end();
+ ci != ce; ++ci) {
+ if (const CFGStmt *S = (*ci).getAs<CFGStmt>())
+ if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) {
+ if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable) {
+ foundUnreachable = true;
+ break;
+ }
+ }
}
+ if (foundUnreachable)
+ continue;
}
// We found a block that wasn't covered - find the statement to report
SourceRange SR;
+ PathDiagnosticLocation DL;
SourceLocation SL;
if (const Stmt *S = getUnreachableStmt(CB)) {
SR = S->getSourceRange();
- SL = S->getLocStart();
- if (SR.isInvalid() || SL.isInvalid())
+ DL = PathDiagnosticLocation::createBegin(S, B.getSourceManager(), LC);
+ SL = DL.asLocation();
+ if (SR.isInvalid() || !SL.isValid())
continue;
}
else
@@ -138,7 +147,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
continue;
B.EmitBasicReport("Unreachable code", "Dead code", "This statement is never"
- " executed", SL, SR);
+ " executed", DL, SR);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
index 875dce2e994a..b34b97c5b301 100644
--- a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
@@ -48,8 +48,8 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
return;
// FIXME: Handle multi-dimensional VLAs.
- const Expr* SE = VLA->getSizeExpr();
- const GRState *state = C.getState();
+ const Expr *SE = VLA->getSizeExpr();
+ const ProgramState *state = C.getState();
SVal sizeV = state->getSVal(SE);
if (sizeV.isUndef()) {
@@ -62,10 +62,10 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
BT_undef.reset(new BuiltinBug("Declared variable-length array (VLA) "
"uses a garbage value as its size"));
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT_undef, BT_undef->getName(), N);
+ BugReport *report =
+ new BugReport(*BT_undef, BT_undef->getName(), N);
report->addRange(SE->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, SE));
C.EmitReport(report);
return;
}
@@ -78,19 +78,19 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
// Check if the size is zero.
DefinedSVal sizeD = cast<DefinedSVal>(sizeV);
- const GRState *stateNotZero, *stateZero;
+ const ProgramState *stateNotZero, *stateZero;
llvm::tie(stateNotZero, stateZero) = state->assume(sizeD);
if (stateZero && !stateNotZero) {
- ExplodedNode* N = C.generateSink(stateZero);
+ ExplodedNode *N = C.generateSink(stateZero);
if (!BT_zero)
BT_zero.reset(new BuiltinBug("Declared variable-length array (VLA) has "
"zero size"));
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT_zero, BT_zero->getName(), N);
+ BugReport *report =
+ new BugReport(*BT_zero, BT_zero->getName(), N);
report->addRange(SE->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, SE));
C.EmitReport(report);
return;
}
diff --git a/lib/StaticAnalyzer/Core/AggExprVisitor.cpp b/lib/StaticAnalyzer/Core/AggExprVisitor.cpp
index 901190d901dd..0936d61784ac 100644
--- a/lib/StaticAnalyzer/Core/AggExprVisitor.cpp
+++ b/lib/StaticAnalyzer/Core/AggExprVisitor.cpp
@@ -46,7 +46,7 @@ public:
void AggExprVisitor::VisitCastExpr(CastExpr *E) {
switch (E->getCastKind()) {
default:
- assert(0 && "Unhandled cast kind");
+ llvm_unreachable("Unhandled cast kind");
case CK_NoOp:
case CK_ConstructorConversion:
case CK_UserDefinedConversion:
diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
index 5f4f83c0a8dc..17ec70d39b90 100644
--- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -14,6 +14,58 @@
using namespace clang;
using namespace ento;
+AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
+ const LangOptions &lang,
+ PathDiagnosticConsumer *pd,
+ StoreManagerCreator storemgr,
+ ConstraintManagerCreator constraintmgr,
+ CheckerManager *checkerMgr,
+ idx::Indexer *idxer,
+ unsigned maxnodes, unsigned maxvisit,
+ bool vizdot, bool vizubi,
+ AnalysisPurgeMode purge,
+ bool eager, bool trim,
+ bool inlinecall, bool useUnoptimizedCFG,
+ bool addImplicitDtors, bool addInitializers,
+ bool eagerlyTrimEGraph)
+ : AnaCtxMgr(useUnoptimizedCFG, addImplicitDtors, addInitializers),
+ Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd),
+ CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),
+ CheckerMgr(checkerMgr), Idxer(idxer),
+ AScope(ScopeDecl), MaxNodes(maxnodes), MaxVisit(maxvisit),
+ VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge),
+ EagerlyAssume(eager), TrimGraph(trim), InlineCall(inlinecall),
+ EagerlyTrimEGraph(eagerlyTrimEGraph)
+{
+ AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd();
+}
+
+AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
+ AnalysisManager &ParentAM)
+ : AnaCtxMgr(ParentAM.AnaCtxMgr.getUseUnoptimizedCFG(),
+ ParentAM.AnaCtxMgr.getCFGBuildOptions().AddImplicitDtors,
+ ParentAM.AnaCtxMgr.getCFGBuildOptions().AddInitializers),
+ Ctx(ctx), Diags(diags),
+ LangInfo(ParentAM.LangInfo), PD(ParentAM.getPathDiagnosticConsumer()),
+ CreateStoreMgr(ParentAM.CreateStoreMgr),
+ CreateConstraintMgr(ParentAM.CreateConstraintMgr),
+ CheckerMgr(ParentAM.CheckerMgr),
+ Idxer(ParentAM.Idxer),
+ AScope(ScopeDecl),
+ MaxNodes(ParentAM.MaxNodes),
+ MaxVisit(ParentAM.MaxVisit),
+ VisualizeEGDot(ParentAM.VisualizeEGDot),
+ VisualizeEGUbi(ParentAM.VisualizeEGUbi),
+ PurgeDead(ParentAM.PurgeDead),
+ EagerlyAssume(ParentAM.EagerlyAssume),
+ TrimGraph(ParentAM.TrimGraph),
+ InlineCall(ParentAM.InlineCall),
+ EagerlyTrimEGraph(ParentAM.EagerlyTrimEGraph)
+{
+ AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd();
+}
+
+
AnalysisContext *
AnalysisManager::getAnalysisContextInAnotherTU(const Decl *D) {
idx::Entity Ent = idx::Entity::get(const_cast<Decl *>(D),
diff --git a/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp b/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp
index 3050ca3ce3cc..6c748b6ad01a 100644
--- a/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp
@@ -8,14 +8,13 @@
//===----------------------------------------------------------------------===//
//
// This file defines BasicConstraintManager, a class that tracks simple
-// equality and inequality constraints on symbolic values of GRState.
+// equality and inequality constraints on symbolic values of ProgramState.
//
//===----------------------------------------------------------------------===//
#include "SimpleConstraintManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -25,7 +24,7 @@ using namespace ento;
namespace { class ConstNotEq {}; }
namespace { class ConstEq {}; }
-typedef llvm::ImmutableMap<SymbolRef,GRState::IntSetTy> ConstNotEqTy;
+typedef llvm::ImmutableMap<SymbolRef,ProgramState::IntSetTy> ConstNotEqTy;
typedef llvm::ImmutableMap<SymbolRef,const llvm::APSInt*> ConstEqTy;
static int ConstEqIndex = 0;
@@ -34,13 +33,14 @@ static int ConstNotEqIndex = 0;
namespace clang {
namespace ento {
template<>
-struct GRStateTrait<ConstNotEq> : public GRStatePartialTrait<ConstNotEqTy> {
- static inline void* GDMIndex() { return &ConstNotEqIndex; }
+struct ProgramStateTrait<ConstNotEq> :
+ public ProgramStatePartialTrait<ConstNotEqTy> {
+ static inline void *GDMIndex() { return &ConstNotEqIndex; }
};
template<>
-struct GRStateTrait<ConstEq> : public GRStatePartialTrait<ConstEqTy> {
- static inline void* GDMIndex() { return &ConstEqIndex; }
+struct ProgramStateTrait<ConstEq> : public ProgramStatePartialTrait<ConstEqTy> {
+ static inline void *GDMIndex() { return &ConstEqIndex; }
};
}
}
@@ -50,62 +50,81 @@ namespace {
// constants and integer variables.
class BasicConstraintManager
: public SimpleConstraintManager {
- GRState::IntSetTy::Factory ISetFactory;
+ ProgramState::IntSetTy::Factory ISetFactory;
public:
- BasicConstraintManager(GRStateManager &statemgr, SubEngine &subengine)
+ BasicConstraintManager(ProgramStateManager &statemgr, SubEngine &subengine)
: SimpleConstraintManager(subengine),
ISetFactory(statemgr.getAllocator()) {}
- const GRState *assumeSymNE(const GRState* state, SymbolRef sym,
- const llvm::APSInt& V,
- const llvm::APSInt& Adjustment);
-
- const GRState *assumeSymEQ(const GRState* state, SymbolRef sym,
- const llvm::APSInt& V,
- const llvm::APSInt& Adjustment);
-
- const GRState *assumeSymLT(const GRState* state, SymbolRef sym,
- const llvm::APSInt& V,
- const llvm::APSInt& Adjustment);
-
- const GRState *assumeSymGT(const GRState* state, SymbolRef sym,
- const llvm::APSInt& V,
- const llvm::APSInt& Adjustment);
-
- const GRState *assumeSymGE(const GRState* state, SymbolRef sym,
- const llvm::APSInt& V,
- const llvm::APSInt& Adjustment);
-
- const GRState *assumeSymLE(const GRState* state, SymbolRef sym,
- const llvm::APSInt& V,
- const llvm::APSInt& Adjustment);
-
- const GRState* AddEQ(const GRState* state, SymbolRef sym, const llvm::APSInt& V);
-
- const GRState* AddNE(const GRState* state, SymbolRef sym, const llvm::APSInt& V);
-
- const llvm::APSInt* getSymVal(const GRState* state, SymbolRef sym) const;
- bool isNotEqual(const GRState* state, SymbolRef sym, const llvm::APSInt& V)
- const;
- bool isEqual(const GRState* state, SymbolRef sym, const llvm::APSInt& V)
- const;
-
- const GRState* removeDeadBindings(const GRState* state, SymbolReaper& SymReaper);
-
- void print(const GRState* state, llvm::raw_ostream& Out,
- const char* nl, const char *sep);
+ const ProgramState *assumeSymNE(const ProgramState *state,
+ SymbolRef sym,
+ const llvm::APSInt& V,
+ const llvm::APSInt& Adjustment);
+
+ const ProgramState *assumeSymEQ(const ProgramState *state,
+ SymbolRef sym,
+ const llvm::APSInt& V,
+ const llvm::APSInt& Adjustment);
+
+ const ProgramState *assumeSymLT(const ProgramState *state,
+ SymbolRef sym,
+ const llvm::APSInt& V,
+ const llvm::APSInt& Adjustment);
+
+ const ProgramState *assumeSymGT(const ProgramState *state,
+ SymbolRef sym,
+ const llvm::APSInt& V,
+ const llvm::APSInt& Adjustment);
+
+ const ProgramState *assumeSymGE(const ProgramState *state,
+ SymbolRef sym,
+ const llvm::APSInt& V,
+ const llvm::APSInt& Adjustment);
+
+ const ProgramState *assumeSymLE(const ProgramState *state,
+ SymbolRef sym,
+ const llvm::APSInt& V,
+ const llvm::APSInt& Adjustment);
+
+ const ProgramState *AddEQ(const ProgramState *state,
+ SymbolRef sym,
+ const llvm::APSInt& V);
+
+ const ProgramState *AddNE(const ProgramState *state,
+ SymbolRef sym,
+ const llvm::APSInt& V);
+
+ const llvm::APSInt* getSymVal(const ProgramState *state,
+ SymbolRef sym) const;
+
+ bool isNotEqual(const ProgramState *state,
+ SymbolRef sym,
+ const llvm::APSInt& V) const;
+
+ bool isEqual(const ProgramState *state,
+ SymbolRef sym,
+ const llvm::APSInt& V) const;
+
+ const ProgramState *removeDeadBindings(const ProgramState *state,
+ SymbolReaper& SymReaper);
+
+ void print(const ProgramState *state,
+ raw_ostream &Out,
+ const char* nl,
+ const char *sep);
};
} // end anonymous namespace
-ConstraintManager* ento::CreateBasicConstraintManager(GRStateManager& statemgr,
- SubEngine &subengine) {
+ConstraintManager*
+ento::CreateBasicConstraintManager(ProgramStateManager& statemgr,
+ SubEngine &subengine) {
return new BasicConstraintManager(statemgr, subengine);
}
-
-const GRState*
-BasicConstraintManager::assumeSymNE(const GRState *state, SymbolRef sym,
+const ProgramState*
+BasicConstraintManager::assumeSymNE(const ProgramState *state,
+ SymbolRef sym,
const llvm::APSInt &V,
const llvm::APSInt &Adjustment) {
// First, determine if sym == X, where X+Adjustment != V.
@@ -124,8 +143,9 @@ BasicConstraintManager::assumeSymNE(const GRState *state, SymbolRef sym,
return AddNE(state, sym, Adjusted);
}
-const GRState*
-BasicConstraintManager::assumeSymEQ(const GRState *state, SymbolRef sym,
+const ProgramState*
+BasicConstraintManager::assumeSymEQ(const ProgramState *state,
+ SymbolRef sym,
const llvm::APSInt &V,
const llvm::APSInt &Adjustment) {
// First, determine if sym == X, where X+Adjustment != V.
@@ -145,8 +165,9 @@ BasicConstraintManager::assumeSymEQ(const GRState *state, SymbolRef sym,
}
// The logic for these will be handled in another ConstraintManager.
-const GRState*
-BasicConstraintManager::assumeSymLT(const GRState *state, SymbolRef sym,
+const ProgramState*
+BasicConstraintManager::assumeSymLT(const ProgramState *state,
+ SymbolRef sym,
const llvm::APSInt &V,
const llvm::APSInt &Adjustment) {
// Is 'V' the smallest possible value?
@@ -159,8 +180,9 @@ BasicConstraintManager::assumeSymLT(const GRState *state, SymbolRef sym,
return assumeSymNE(state, sym, V, Adjustment);
}
-const GRState*
-BasicConstraintManager::assumeSymGT(const GRState *state, SymbolRef sym,
+const ProgramState*
+BasicConstraintManager::assumeSymGT(const ProgramState *state,
+ SymbolRef sym,
const llvm::APSInt &V,
const llvm::APSInt &Adjustment) {
// Is 'V' the largest possible value?
@@ -173,8 +195,9 @@ BasicConstraintManager::assumeSymGT(const GRState *state, SymbolRef sym,
return assumeSymNE(state, sym, V, Adjustment);
}
-const GRState*
-BasicConstraintManager::assumeSymGE(const GRState *state, SymbolRef sym,
+const ProgramState*
+BasicConstraintManager::assumeSymGE(const ProgramState *state,
+ SymbolRef sym,
const llvm::APSInt &V,
const llvm::APSInt &Adjustment) {
// Reject a path if the value of sym is a constant X and !(X+Adj >= V).
@@ -201,8 +224,9 @@ BasicConstraintManager::assumeSymGE(const GRState *state, SymbolRef sym,
return state;
}
-const GRState*
-BasicConstraintManager::assumeSymLE(const GRState *state, SymbolRef sym,
+const ProgramState*
+BasicConstraintManager::assumeSymLE(const ProgramState *state,
+ SymbolRef sym,
const llvm::APSInt &V,
const llvm::APSInt &Adjustment) {
// Reject a path if the value of sym is a constant X and !(X+Adj <= V).
@@ -229,18 +253,20 @@ BasicConstraintManager::assumeSymLE(const GRState *state, SymbolRef sym,
return state;
}
-const GRState* BasicConstraintManager::AddEQ(const GRState* state, SymbolRef sym,
+const ProgramState *BasicConstraintManager::AddEQ(const ProgramState *state,
+ SymbolRef sym,
const llvm::APSInt& V) {
// Create a new state with the old binding replaced.
return state->set<ConstEq>(sym, &state->getBasicVals().getValue(V));
}
-const GRState* BasicConstraintManager::AddNE(const GRState* state, SymbolRef sym,
- const llvm::APSInt& V) {
+const ProgramState *BasicConstraintManager::AddNE(const ProgramState *state,
+ SymbolRef sym,
+ const llvm::APSInt& V) {
// First, retrieve the NE-set associated with the given symbol.
ConstNotEqTy::data_type* T = state->get<ConstNotEq>(sym);
- GRState::IntSetTy S = T ? *T : ISetFactory.getEmptySet();
+ ProgramState::IntSetTy S = T ? *T : ISetFactory.getEmptySet();
// Now add V to the NE set.
S = ISetFactory.add(S, &state->getBasicVals().getValue(V));
@@ -249,13 +275,14 @@ const GRState* BasicConstraintManager::AddNE(const GRState* state, SymbolRef sym
return state->set<ConstNotEq>(sym, S);
}
-const llvm::APSInt* BasicConstraintManager::getSymVal(const GRState* state,
+const llvm::APSInt* BasicConstraintManager::getSymVal(const ProgramState *state,
SymbolRef sym) const {
const ConstEqTy::data_type* T = state->get<ConstEq>(sym);
return T ? *T : NULL;
}
-bool BasicConstraintManager::isNotEqual(const GRState* state, SymbolRef sym,
+bool BasicConstraintManager::isNotEqual(const ProgramState *state,
+ SymbolRef sym,
const llvm::APSInt& V) const {
// Retrieve the NE-set associated with the given symbol.
@@ -265,7 +292,8 @@ bool BasicConstraintManager::isNotEqual(const GRState* state, SymbolRef sym,
return T ? T->contains(&state->getBasicVals().getValue(V)) : false;
}
-bool BasicConstraintManager::isEqual(const GRState* state, SymbolRef sym,
+bool BasicConstraintManager::isEqual(const ProgramState *state,
+ SymbolRef sym,
const llvm::APSInt& V) const {
// Retrieve the EQ-set associated with the given symbol.
const ConstEqTy::data_type* T = state->get<ConstEq>(sym);
@@ -275,8 +303,8 @@ bool BasicConstraintManager::isEqual(const GRState* state, SymbolRef sym,
/// Scan all symbols referenced by the constraints. If the symbol is not alive
/// as marked in LSymbols, mark it as dead in DSymbols.
-const GRState*
-BasicConstraintManager::removeDeadBindings(const GRState* state,
+const ProgramState*
+BasicConstraintManager::removeDeadBindings(const ProgramState *state,
SymbolReaper& SymReaper) {
ConstEqTy CE = state->get<ConstEq>();
@@ -301,7 +329,8 @@ BasicConstraintManager::removeDeadBindings(const GRState* state,
return state->set<ConstNotEq>(CNE);
}
-void BasicConstraintManager::print(const GRState* state, llvm::raw_ostream& Out,
+void BasicConstraintManager::print(const ProgramState *state,
+ raw_ostream &Out,
const char* nl, const char *sep) {
// Print equality constraints.
@@ -324,7 +353,7 @@ void BasicConstraintManager::print(const GRState* state, llvm::raw_ostream& Out,
Out << nl << " $" << I.getKey() << " : ";
bool isFirst = true;
- GRState::IntSetTy::iterator J = I.getData().begin(),
+ ProgramState::IntSetTy::iterator J = I.getData().begin(),
EJ = I.getData().end();
for ( ; J != EJ; ++J) {
diff --git a/lib/StaticAnalyzer/Core/BasicStore.cpp b/lib/StaticAnalyzer/Core/BasicStore.cpp
deleted file mode 100644
index 7c9f45a474c1..000000000000
--- a/lib/StaticAnalyzer/Core/BasicStore.cpp
+++ /dev/null
@@ -1,605 +0,0 @@
-//== BasicStore.cpp - Basic map from Locations to Values --------*- C++ -*--==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defined the BasicStore and BasicStoreManager classes.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/Analysis/AnalysisContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
-#include "llvm/ADT/ImmutableMap.h"
-
-using namespace clang;
-using namespace ento;
-
-typedef llvm::ImmutableMap<const MemRegion*,SVal> BindingsTy;
-
-namespace {
-
-class BasicStoreSubRegionMap : public SubRegionMap {
-public:
- BasicStoreSubRegionMap() {}
-
- bool iterSubRegions(const MemRegion* R, Visitor& V) const {
- return true; // Do nothing. No subregions.
- }
-};
-
-class BasicStoreManager : public StoreManager {
- BindingsTy::Factory VBFactory;
-public:
- BasicStoreManager(GRStateManager& mgr)
- : StoreManager(mgr), VBFactory(mgr.getAllocator()) {}
-
- ~BasicStoreManager() {}
-
- SubRegionMap *getSubRegionMap(Store store) {
- return new BasicStoreSubRegionMap();
- }
-
- SVal Retrieve(Store store, Loc loc, QualType T = QualType());
-
- StoreRef invalidateRegion(Store store, const MemRegion *R, const Expr *E,
- unsigned Count, InvalidatedSymbols &IS);
-
- StoreRef invalidateRegions(Store store, const MemRegion * const *Begin,
- const MemRegion * const *End, const Expr *E,
- unsigned Count, InvalidatedSymbols &IS,
- bool invalidateGlobals,
- InvalidatedRegions *Regions);
-
- StoreRef scanForIvars(Stmt *B, const Decl* SelfDecl,
- const MemRegion *SelfRegion, Store St);
-
- StoreRef Bind(Store St, Loc loc, SVal V);
- StoreRef Remove(Store St, Loc loc);
- StoreRef getInitialStore(const LocationContext *InitLoc);
-
- StoreRef BindCompoundLiteral(Store store, const CompoundLiteralExpr*,
- const LocationContext*, SVal val) {
- return StoreRef(store, *this);
- }
-
- /// ArrayToPointer - Used by ExprEngine::VistCast to handle implicit
- /// conversions between arrays and pointers.
- SVal ArrayToPointer(Loc Array) { return Array; }
-
- /// removeDeadBindings - Scans a BasicStore of 'state' for dead values.
- /// It updatees the GRState object in place with the values removed.
- StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx,
- SymbolReaper& SymReaper,
- llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
-
- void iterBindings(Store store, BindingsHandler& f);
-
- StoreRef BindDecl(Store store, const VarRegion *VR, SVal InitVal) {
- return BindDeclInternal(store, VR, &InitVal);
- }
-
- StoreRef BindDeclWithNoInit(Store store, const VarRegion *VR) {
- return BindDeclInternal(store, VR, 0);
- }
-
- StoreRef BindDeclInternal(Store store, const VarRegion *VR, SVal *InitVal);
-
- static inline BindingsTy GetBindings(Store store) {
- return BindingsTy(static_cast<const BindingsTy::TreeTy*>(store));
- }
-
- void print(Store store, llvm::raw_ostream& Out, const char* nl,
- const char *sep);
-
-private:
- SVal LazyRetrieve(Store store, const TypedRegion *R);
-};
-
-} // end anonymous namespace
-
-
-StoreManager* ento::CreateBasicStoreManager(GRStateManager& StMgr) {
- return new BasicStoreManager(StMgr);
-}
-
-static bool isHigherOrderRawPtr(QualType T, ASTContext &C) {
- bool foundPointer = false;
- while (1) {
- const PointerType *PT = T->getAs<PointerType>();
- if (!PT) {
- if (!foundPointer)
- return false;
-
- // intptr_t* or intptr_t**, etc?
- if (T->isIntegerType() && C.getTypeSize(T) == C.getTypeSize(C.VoidPtrTy))
- return true;
-
- QualType X = C.getCanonicalType(T).getUnqualifiedType();
- return X == C.VoidTy;
- }
-
- foundPointer = true;
- T = PT->getPointeeType();
- }
-}
-
-SVal BasicStoreManager::LazyRetrieve(Store store, const TypedRegion *R) {
- const VarRegion *VR = dyn_cast<VarRegion>(R);
- if (!VR)
- return UnknownVal();
-
- const VarDecl *VD = VR->getDecl();
- QualType T = VD->getType();
-
- // Only handle simple types that we can symbolicate.
- if (!SymbolManager::canSymbolicate(T) || !T->isScalarType())
- return UnknownVal();
-
- // Globals and parameters start with symbolic values.
- // Local variables initially are undefined.
-
- // Non-static globals may have had their values reset by invalidateRegions.
- const MemSpaceRegion *MS = VR->getMemorySpace();
- if (isa<NonStaticGlobalSpaceRegion>(MS)) {
- BindingsTy B = GetBindings(store);
- // FIXME: Copy-and-pasted from RegionStore.cpp.
- if (BindingsTy::data_type *Val = B.lookup(MS)) {
- if (SymbolRef parentSym = Val->getAsSymbol())
- return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R);
-
- if (Val->isZeroConstant())
- return svalBuilder.makeZeroVal(T);
-
- if (Val->isUnknownOrUndef())
- return *Val;
-
- assert(0 && "Unknown default value.");
- }
- }
-
- if (VR->hasGlobalsOrParametersStorage() ||
- isa<UnknownSpaceRegion>(VR->getMemorySpace()))
- return svalBuilder.getRegionValueSymbolVal(R);
-
- return UndefinedVal();
-}
-
-SVal BasicStoreManager::Retrieve(Store store, Loc loc, QualType T) {
- if (isa<UnknownVal>(loc))
- return UnknownVal();
-
- assert(!isa<UndefinedVal>(loc));
-
- switch (loc.getSubKind()) {
-
- case loc::MemRegionKind: {
- const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion();
-
- if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R) ||
- isa<CXXThisRegion>(R)))
- return UnknownVal();
-
- BindingsTy B = GetBindings(store);
- BindingsTy::data_type *Val = B.lookup(R);
- const TypedRegion *TR = cast<TypedRegion>(R);
-
- if (Val)
- return CastRetrievedVal(*Val, TR, T);
-
- SVal V = LazyRetrieve(store, TR);
- return V.isUnknownOrUndef() ? V : CastRetrievedVal(V, TR, T);
- }
-
- case loc::ObjCPropRefKind:
- case loc::ConcreteIntKind:
- // Support direct accesses to memory. It's up to individual checkers
- // to flag an error.
- return UnknownVal();
-
- default:
- assert (false && "Invalid Loc.");
- break;
- }
-
- return UnknownVal();
-}
-
-StoreRef BasicStoreManager::Bind(Store store, Loc loc, SVal V) {
- if (isa<loc::ConcreteInt>(loc))
- return StoreRef(store, *this);
-
- const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion();
-
- // Special case: a default symbol assigned to the NonStaticGlobalsSpaceRegion
- // that is used to derive other symbols.
- if (isa<NonStaticGlobalSpaceRegion>(R)) {
- BindingsTy B = GetBindings(store);
- return StoreRef(VBFactory.add(B, R, V).getRoot(), *this);
- }
-
- // Special case: handle store of pointer values (Loc) to pointers via
- // a cast to intXX_t*, void*, etc. This is needed to handle
- // OSCompareAndSwap32Barrier/OSCompareAndSwap64Barrier.
- if (isa<Loc>(V) || isa<nonloc::LocAsInteger>(V))
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
- // FIXME: Should check for index 0.
- QualType T = ER->getLocationType();
-
- if (isHigherOrderRawPtr(T, Ctx))
- R = ER->getSuperRegion();
- }
-
- if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R) || isa<CXXThisRegion>(R)))
- return StoreRef(store, *this);
-
- const TypedRegion *TyR = cast<TypedRegion>(R);
-
- // Do not bind to arrays. We need to explicitly check for this so that
- // we do not encounter any weirdness of trying to load/store from arrays.
- if (TyR->isBoundable() && TyR->getValueType()->isArrayType())
- return StoreRef(store, *this);
-
- if (nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(&V)) {
- // Only convert 'V' to a location iff the underlying region type
- // is a location as well.
- // FIXME: We are allowing a store of an arbitrary location to
- // a pointer. We may wish to flag a type error here if the types
- // are incompatible. This may also cause lots of breakage
- // elsewhere. Food for thought.
- if (TyR->isBoundable() && Loc::isLocType(TyR->getValueType()))
- V = X->getLoc();
- }
-
- BindingsTy B = GetBindings(store);
- return StoreRef(V.isUnknown()
- ? VBFactory.remove(B, R).getRoot()
- : VBFactory.add(B, R, V).getRoot(), *this);
-}
-
-StoreRef BasicStoreManager::Remove(Store store, Loc loc) {
- switch (loc.getSubKind()) {
- case loc::MemRegionKind: {
- const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion();
-
- if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R) ||
- isa<CXXThisRegion>(R)))
- return StoreRef(store, *this);
-
- return StoreRef(VBFactory.remove(GetBindings(store), R).getRoot(), *this);
- }
- default:
- assert ("Remove for given Loc type not yet implemented.");
- return StoreRef(store, *this);
- }
-}
-
-StoreRef BasicStoreManager::removeDeadBindings(Store store,
- const StackFrameContext *LCtx,
- SymbolReaper& SymReaper,
- llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
-{
- BindingsTy B = GetBindings(store);
- typedef SVal::symbol_iterator symbol_iterator;
-
- // Iterate over the variable bindings.
- for (BindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) {
- if (const VarRegion *VR = dyn_cast<VarRegion>(I.getKey())) {
- if (SymReaper.isLive(VR))
- RegionRoots.push_back(VR);
- else
- continue;
- }
- else if (isa<ObjCIvarRegion>(I.getKey()) ||
- isa<NonStaticGlobalSpaceRegion>(I.getKey()) ||
- isa<CXXThisRegion>(I.getKey()))
- RegionRoots.push_back(I.getKey());
- else
- continue;
-
- // Mark the bindings in the data as live.
- SVal X = I.getData();
- for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
- SymReaper.markLive(*SI);
- }
-
- // Scan for live variables and live symbols.
- llvm::SmallPtrSet<const MemRegion*, 10> Marked;
-
- while (!RegionRoots.empty()) {
- const MemRegion* MR = RegionRoots.back();
- RegionRoots.pop_back();
-
- while (MR) {
- if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(MR)) {
- SymReaper.markLive(SymR->getSymbol());
- break;
- }
- else if (isa<VarRegion>(MR) || isa<ObjCIvarRegion>(MR) ||
- isa<NonStaticGlobalSpaceRegion>(MR) || isa<CXXThisRegion>(MR)) {
- if (Marked.count(MR))
- break;
-
- Marked.insert(MR);
- SVal X = Retrieve(store, loc::MemRegionVal(MR));
-
- // FIXME: We need to handle symbols nested in region definitions.
- for (symbol_iterator SI=X.symbol_begin(),SE=X.symbol_end();SI!=SE;++SI)
- SymReaper.markLive(*SI);
-
- if (!isa<loc::MemRegionVal>(X))
- break;
-
- const loc::MemRegionVal& LVD = cast<loc::MemRegionVal>(X);
- RegionRoots.push_back(LVD.getRegion());
- break;
- }
- else if (const SubRegion* R = dyn_cast<SubRegion>(MR))
- MR = R->getSuperRegion();
- else
- break;
- }
- }
-
- // Remove dead variable bindings.
- StoreRef newStore(store, *this);
- for (BindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) {
- const MemRegion* R = I.getKey();
-
- if (!Marked.count(R)) {
- newStore = Remove(newStore.getStore(), svalBuilder.makeLoc(R));
- SVal X = I.getData();
-
- for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
- SymReaper.maybeDead(*SI);
- }
- }
-
- return newStore;
-}
-
-StoreRef BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl,
- const MemRegion *SelfRegion,
- Store St) {
-
- StoreRef newStore(St, *this);
-
- for (Stmt::child_iterator CI=B->child_begin(), CE=B->child_end();
- CI != CE; ++CI) {
-
- if (!*CI)
- continue;
-
- // Check if the statement is an ivar reference. We only
- // care about self.ivar.
- if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(*CI)) {
- const Expr *Base = IV->getBase()->IgnoreParenCasts();
- if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Base)) {
- if (DR->getDecl() == SelfDecl) {
- const ObjCIvarRegion *IVR = MRMgr.getObjCIvarRegion(IV->getDecl(),
- SelfRegion);
- SVal X = svalBuilder.getRegionValueSymbolVal(IVR);
- newStore = Bind(newStore.getStore(), svalBuilder.makeLoc(IVR), X);
- }
- }
- }
- else
- newStore = scanForIvars(*CI, SelfDecl, SelfRegion, newStore.getStore());
- }
-
- return newStore;
-}
-
-StoreRef BasicStoreManager::getInitialStore(const LocationContext *InitLoc) {
- // The LiveVariables information already has a compilation of all VarDecls
- // used in the function. Iterate through this set, and "symbolicate"
- // any VarDecl whose value originally comes from outside the function.
- typedef LiveVariables::AnalysisDataTy LVDataTy;
- LVDataTy& D = InitLoc->getLiveVariables()->getAnalysisData();
- StoreRef St(VBFactory.getEmptyMap().getRoot(), *this);
-
- for (LVDataTy::decl_iterator I=D.begin_decl(), E=D.end_decl(); I != E; ++I) {
- const NamedDecl* ND = I->first;
-
- // Handle implicit parameters.
- if (const ImplicitParamDecl* PD = dyn_cast<ImplicitParamDecl>(ND)) {
- const Decl& CD = *InitLoc->getDecl();
- if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(&CD)) {
- if (MD->getSelfDecl() == PD) {
- // FIXME: Add type constraints (when they become available) to
- // SelfRegion? (i.e., it implements MD->getClassInterface()).
- const VarRegion *VR = MRMgr.getVarRegion(PD, InitLoc);
- const MemRegion *SelfRegion =
- svalBuilder.getRegionValueSymbolVal(VR).getAsRegion();
- assert(SelfRegion);
- St = Bind(St.getStore(), svalBuilder.makeLoc(VR),
- loc::MemRegionVal(SelfRegion));
- // Scan the method for ivar references. While this requires an
- // entire AST scan, the cost should not be high in practice.
- St = scanForIvars(MD->getBody(), PD, SelfRegion, St.getStore());
- }
- }
- }
- }
-
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(InitLoc->getDecl())) {
- // For C++ non-static member variables, add a symbolic region for 'this' in
- // the initial stack frame.
- if (MD->isInstance()) {
- QualType ThisT = MD->getThisType(StateMgr.getContext());
- MemRegionManager &RegMgr = svalBuilder.getRegionManager();
- const CXXThisRegion *ThisR = RegMgr.getCXXThisRegion(ThisT, InitLoc);
- SVal ThisV = svalBuilder.getRegionValueSymbolVal(ThisR);
- St = Bind(St.getStore(), svalBuilder.makeLoc(ThisR), ThisV);
- }
- }
-
- return St;
-}
-
-StoreRef BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR,
- SVal* InitVal) {
-
- BasicValueFactory& BasicVals = StateMgr.getBasicVals();
- const VarDecl *VD = VR->getDecl();
- StoreRef newStore(store, *this);
-
- // BasicStore does not model arrays and structs.
- if (VD->getType()->isArrayType() || VD->getType()->isStructureOrClassType())
- return newStore;
-
- if (VD->hasGlobalStorage()) {
- // Handle variables with global storage: extern, static, PrivateExtern.
-
- // FIXME:: static variables may have an initializer, but the second time a
- // function is called those values may not be current. Currently, a function
- // will not be called more than once.
-
- // Static global variables should not be visited here.
- assert(!(VD->getStorageClass() == SC_Static &&
- VD->isFileVarDecl()));
-
- // Process static variables.
- if (VD->getStorageClass() == SC_Static) {
- // C99: 6.7.8 Initialization
- // If an object that has static storage duration is not initialized
- // explicitly, then:
- // -if it has pointer type, it is initialized to a null pointer;
- // -if it has arithmetic type, it is initialized to (positive or
- // unsigned) zero;
- if (!InitVal) {
- QualType T = VD->getType();
- if (Loc::isLocType(T))
- newStore = Bind(store, loc::MemRegionVal(VR),
- loc::ConcreteInt(BasicVals.getValue(0, T)));
- else if (T->isIntegerType() && T->isScalarType())
- newStore = Bind(store, loc::MemRegionVal(VR),
- nonloc::ConcreteInt(BasicVals.getValue(0, T)));
- } else {
- newStore = Bind(store, loc::MemRegionVal(VR), *InitVal);
- }
- }
- } else {
- // Process local scalar variables.
- QualType T = VD->getType();
- // BasicStore only supports scalars.
- if ((T->isScalarType() || T->isReferenceType()) &&
- svalBuilder.getSymbolManager().canSymbolicate(T)) {
- SVal V = InitVal ? *InitVal : UndefinedVal();
- newStore = Bind(store, loc::MemRegionVal(VR), V);
- }
- }
-
- return newStore;
-}
-
-void BasicStoreManager::print(Store store, llvm::raw_ostream& Out,
- const char* nl, const char *sep) {
-
- BindingsTy B = GetBindings(store);
- Out << "Variables:" << nl;
-
- bool isFirst = true;
-
- for (BindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) {
- if (isFirst)
- isFirst = false;
- else
- Out << nl;
-
- Out << ' ' << I.getKey() << " : " << I.getData();
- }
-}
-
-
-void BasicStoreManager::iterBindings(Store store, BindingsHandler& f) {
- BindingsTy B = GetBindings(store);
-
- for (BindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I)
- if (!f.HandleBinding(*this, store, I.getKey(), I.getData()))
- return;
-
-}
-
-StoreManager::BindingsHandler::~BindingsHandler() {}
-
-//===----------------------------------------------------------------------===//
-// Binding invalidation.
-//===----------------------------------------------------------------------===//
-
-
-StoreRef BasicStoreManager::invalidateRegions(Store store,
- const MemRegion * const *I,
- const MemRegion * const *End,
- const Expr *E, unsigned Count,
- InvalidatedSymbols &IS,
- bool invalidateGlobals,
- InvalidatedRegions *Regions) {
- StoreRef newStore(store, *this);
-
- if (invalidateGlobals) {
- BindingsTy B = GetBindings(store);
- for (BindingsTy::iterator I=B.begin(), End=B.end(); I != End; ++I) {
- const MemRegion *R = I.getKey();
- if (isa<NonStaticGlobalSpaceRegion>(R->getMemorySpace()))
- newStore = invalidateRegion(newStore.getStore(), R, E, Count, IS);
- }
- }
-
- for ( ; I != End ; ++I) {
- const MemRegion *R = *I;
- // Don't invalidate globals twice.
- if (invalidateGlobals) {
- if (isa<NonStaticGlobalSpaceRegion>(R->getMemorySpace()))
- continue;
- }
- newStore = invalidateRegion(newStore.getStore(), *I, E, Count, IS);
- if (Regions)
- Regions->push_back(R);
- }
-
- // FIXME: This is copy-and-paste from RegionStore.cpp.
- if (invalidateGlobals) {
- // Bind the non-static globals memory space to a new symbol that we will
- // use to derive the bindings for all non-static globals.
- const GlobalsSpaceRegion *GS = MRMgr.getGlobalsRegion();
- SVal V =
- svalBuilder.getConjuredSymbolVal(/* SymbolTag = */ (void*) GS, E,
- /* symbol type, doesn't matter */ Ctx.IntTy,
- Count);
-
- newStore = Bind(newStore.getStore(), loc::MemRegionVal(GS), V);
- if (Regions)
- Regions->push_back(GS);
- }
-
- return newStore;
-}
-
-
-StoreRef BasicStoreManager::invalidateRegion(Store store,
- const MemRegion *R,
- const Expr *E,
- unsigned Count,
- InvalidatedSymbols &IS) {
- R = R->StripCasts();
-
- if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
- return StoreRef(store, *this);
-
- BindingsTy B = GetBindings(store);
- if (BindingsTy::data_type *Val = B.lookup(R)) {
- if (SymbolRef Sym = Val->getAsSymbol())
- IS.insert(Sym);
- }
-
- QualType T = cast<TypedRegion>(R)->getValueType();
- SVal V = svalBuilder.getConjuredSymbolVal(R, E, T, Count);
- return Bind(store, loc::MemRegionVal(R), V);
-}
diff --git a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
index 0ed4ff143171..fe96700772d6 100644
--- a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -27,7 +27,7 @@ void CompoundValData::Profile(llvm::FoldingSetNodeID& ID, QualType T,
void LazyCompoundValData::Profile(llvm::FoldingSetNodeID& ID,
const StoreRef &store,
- const TypedRegion *region) {
+ const TypedValueRegion *region) {
ID.AddPointer(store.getStore());
ID.AddPointer(region);
}
@@ -70,7 +70,7 @@ BasicValueFactory::~BasicValueFactory() {
const llvm::APSInt& BasicValueFactory::getValue(const llvm::APSInt& X) {
llvm::FoldingSetNodeID ID;
- void* InsertPos;
+ void *InsertPos;
typedef llvm::FoldingSetNodeWrapper<llvm::APSInt> FoldNodeTy;
X.Profile(ID);
@@ -113,7 +113,7 @@ BasicValueFactory::getCompoundValData(QualType T,
llvm::FoldingSetNodeID ID;
CompoundValData::Profile(ID, T, Vals);
- void* InsertPos;
+ void *InsertPos;
CompoundValData* D = CompoundValDataSet.FindNodeOrInsertPos(ID, InsertPos);
@@ -128,10 +128,10 @@ BasicValueFactory::getCompoundValData(QualType T,
const LazyCompoundValData*
BasicValueFactory::getLazyCompoundValData(const StoreRef &store,
- const TypedRegion *region) {
+ const TypedValueRegion *region) {
llvm::FoldingSetNodeID ID;
LazyCompoundValData::Profile(ID, store, region);
- void* InsertPos;
+ void *InsertPos;
LazyCompoundValData *D =
LazyCompoundValDataSet.FindNodeOrInsertPos(ID, InsertPos);
@@ -243,7 +243,7 @@ BasicValueFactory::getPersistentSValWithData(const SVal& V, uintptr_t Data) {
if (!PersistentSVals) PersistentSVals = new PersistentSValsTy();
llvm::FoldingSetNodeID ID;
- void* InsertPos;
+ void *InsertPos;
V.Profile(ID);
ID.AddPointer((void*) Data);
@@ -268,7 +268,7 @@ BasicValueFactory::getPersistentSValPair(const SVal& V1, const SVal& V2) {
if (!PersistentSValPairs) PersistentSValPairs = new PersistentSValPairsTy();
llvm::FoldingSetNodeID ID;
- void* InsertPos;
+ void *InsertPos;
V1.Profile(ID);
V2.Profile(ID);
diff --git a/lib/StaticAnalyzer/Core/BlockCounter.cpp b/lib/StaticAnalyzer/Core/BlockCounter.cpp
index ed52b6b012b7..74d761e1ecc1 100644
--- a/lib/StaticAnalyzer/Core/BlockCounter.cpp
+++ b/lib/StaticAnalyzer/Core/BlockCounter.cpp
@@ -48,11 +48,11 @@ public:
typedef llvm::ImmutableMap<CountKey, unsigned> CountMap;
-static inline CountMap GetMap(void* D) {
+static inline CountMap GetMap(void *D) {
return CountMap(static_cast<CountMap::TreeTy*>(D));
}
-static inline CountMap::Factory& GetFactory(void* F) {
+static inline CountMap::Factory& GetFactory(void *F) {
return *static_cast<CountMap::Factory*>(F);
}
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index 8b5d383ed07f..fbbdb040e4f2 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -33,52 +33,31 @@ using namespace clang;
using namespace ento;
BugReporterVisitor::~BugReporterVisitor() {}
-BugReporterContext::~BugReporterContext() {
- for (visitor_iterator I = visitor_begin(), E = visitor_end(); I != E; ++I)
- if ((*I)->isOwnedByReporterContext()) delete *I;
-}
-
-void BugReporterContext::addVisitor(BugReporterVisitor* visitor) {
- if (!visitor)
- return;
-
- llvm::FoldingSetNodeID ID;
- visitor->Profile(ID);
- void *InsertPos;
-
- if (CallbacksSet.FindNodeOrInsertPos(ID, InsertPos)) {
- delete visitor;
- return;
- }
-
- CallbacksSet.InsertNode(visitor, InsertPos);
- Callbacks = F.add(visitor, Callbacks);
-}
//===----------------------------------------------------------------------===//
// Helper routines for walking the ExplodedGraph and fetching statements.
//===----------------------------------------------------------------------===//
-static inline const Stmt* GetStmt(const ProgramPoint &P) {
+static inline const Stmt *GetStmt(const ProgramPoint &P) {
if (const StmtPoint* SP = dyn_cast<StmtPoint>(&P))
return SP->getStmt();
- else if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P))
+ else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P))
return BE->getSrc()->getTerminator();
return 0;
}
static inline const ExplodedNode*
-GetPredecessorNode(const ExplodedNode* N) {
+GetPredecessorNode(const ExplodedNode *N) {
return N->pred_empty() ? NULL : *(N->pred_begin());
}
static inline const ExplodedNode*
-GetSuccessorNode(const ExplodedNode* N) {
+GetSuccessorNode(const ExplodedNode *N) {
return N->succ_empty() ? NULL : *(N->succ_begin());
}
-static const Stmt* GetPreviousStmt(const ExplodedNode* N) {
+static const Stmt *GetPreviousStmt(const ExplodedNode *N) {
for (N = GetPredecessorNode(N); N; N = GetPredecessorNode(N))
if (const Stmt *S = GetStmt(N->getLocation()))
return S;
@@ -86,7 +65,7 @@ static const Stmt* GetPreviousStmt(const ExplodedNode* N) {
return 0;
}
-static const Stmt* GetNextStmt(const ExplodedNode* N) {
+static const Stmt *GetNextStmt(const ExplodedNode *N) {
for (N = GetSuccessorNode(N); N; N = GetSuccessorNode(N))
if (const Stmt *S = GetStmt(N->getLocation())) {
// Check if the statement is '?' or '&&'/'||'. These are "merges",
@@ -104,11 +83,6 @@ static const Stmt* GetNextStmt(const ExplodedNode* N) {
default:
break;
}
-
- // Some expressions don't have locations.
- if (S->getLocStart().isInvalid())
- continue;
-
return S;
}
@@ -116,7 +90,7 @@ static const Stmt* GetNextStmt(const ExplodedNode* N) {
}
static inline const Stmt*
-GetCurrentOrPreviousStmt(const ExplodedNode* N) {
+GetCurrentOrPreviousStmt(const ExplodedNode *N) {
if (const Stmt *S = GetStmt(N->getLocation()))
return S;
@@ -124,7 +98,7 @@ GetCurrentOrPreviousStmt(const ExplodedNode* N) {
}
static inline const Stmt*
-GetCurrentOrNextStmt(const ExplodedNode* N) {
+GetCurrentOrNextStmt(const ExplodedNode *N) {
if (const Stmt *S = GetStmt(N->getLocation()))
return S;
@@ -145,7 +119,7 @@ public:
NodeMapClosure(NodeBackMap *m) : M(*m) {}
~NodeMapClosure() {}
- const ExplodedNode* getOriginalNode(const ExplodedNode* N) {
+ const ExplodedNode *getOriginalNode(const ExplodedNode *N) {
NodeBackMap::iterator I = M.find(N);
return I == M.end() ? 0 : I->second;
}
@@ -153,25 +127,29 @@ public:
class PathDiagnosticBuilder : public BugReporterContext {
BugReport *R;
- PathDiagnosticClient *PDC;
+ PathDiagnosticConsumer *PDC;
llvm::OwningPtr<ParentMap> PM;
NodeMapClosure NMC;
public:
PathDiagnosticBuilder(GRBugReporter &br,
BugReport *r, NodeBackMap *Backmap,
- PathDiagnosticClient *pdc)
+ PathDiagnosticConsumer *pdc)
: BugReporterContext(br),
- R(r), PDC(pdc), NMC(Backmap) {
- addVisitor(R);
- }
+ R(r), PDC(pdc), NMC(Backmap) {}
- PathDiagnosticLocation ExecutionContinues(const ExplodedNode* N);
+ PathDiagnosticLocation ExecutionContinues(const ExplodedNode *N);
- PathDiagnosticLocation ExecutionContinues(llvm::raw_string_ostream& os,
- const ExplodedNode* N);
+ PathDiagnosticLocation ExecutionContinues(llvm::raw_string_ostream &os,
+ const ExplodedNode *N);
+
+ BugReport *getBugReport() { return R; }
Decl const &getCodeDecl() { return R->getErrorNode()->getCodeDecl(); }
+ const LocationContext* getLocationContext() {
+ return R->getErrorNode()->getLocationContext();
+ }
+
ParentMap& getParentMap() { return R->getErrorNode()->getParentMap(); }
const Stmt *getParent(const Stmt *S) {
@@ -182,8 +160,8 @@ public:
PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S);
- PathDiagnosticClient::PathGenerationScheme getGenerationScheme() const {
- return PDC ? PDC->getGenerationScheme() : PathDiagnosticClient::Extensive;
+ PathDiagnosticConsumer::PathGenerationScheme getGenerationScheme() const {
+ return PDC ? PDC->getGenerationScheme() : PathDiagnosticConsumer::Extensive;
}
bool supportsLogicalOpControlFlow() const {
@@ -193,17 +171,17 @@ public:
} // end anonymous namespace
PathDiagnosticLocation
-PathDiagnosticBuilder::ExecutionContinues(const ExplodedNode* N) {
+PathDiagnosticBuilder::ExecutionContinues(const ExplodedNode *N) {
if (const Stmt *S = GetNextStmt(N))
- return PathDiagnosticLocation(S, getSourceManager());
+ return PathDiagnosticLocation(S, getSourceManager(), getLocationContext());
- return FullSourceLoc(N->getLocationContext()->getDecl()->getBodyRBrace(),
- getSourceManager());
+ return PathDiagnosticLocation::createDeclEnd(N->getLocationContext(),
+ getSourceManager());
}
PathDiagnosticLocation
-PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream& os,
- const ExplodedNode* N) {
+PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream &os,
+ const ExplodedNode *N) {
// Slow, but probably doesn't matter.
if (os.str().empty())
@@ -213,7 +191,7 @@ PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream& os,
if (Loc.asStmt())
os << "Execution continues on line "
- << getSourceManager().getInstantiationLineNumber(Loc.asLocation())
+ << getSourceManager().getExpansionLineNumber(Loc.asLocation())
<< '.';
else {
os << "Execution jumps to the end of the ";
@@ -253,9 +231,10 @@ static bool IsNested(const Stmt *S, ParentMap &PM) {
PathDiagnosticLocation
PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
- assert(S && "Null Stmt* passed to getEnclosingStmtLocation");
+ assert(S && "Null Stmt *passed to getEnclosingStmtLocation");
ParentMap &P = getParentMap();
SourceManager &SMgr = getSourceManager();
+ const LocationContext *LC = getLocationContext();
while (IsNested(S, P)) {
const Stmt *Parent = P.getParentIgnoreParens(S);
@@ -267,44 +246,44 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
case Stmt::BinaryOperatorClass: {
const BinaryOperator *B = cast<BinaryOperator>(Parent);
if (B->isLogicalOp())
- return PathDiagnosticLocation(S, SMgr);
+ return PathDiagnosticLocation(S, SMgr, LC);
break;
}
case Stmt::CompoundStmtClass:
case Stmt::StmtExprClass:
- return PathDiagnosticLocation(S, SMgr);
+ return PathDiagnosticLocation(S, SMgr, LC);
case Stmt::ChooseExprClass:
// Similar to '?' if we are referring to condition, just have the edge
// point to the entire choose expression.
if (cast<ChooseExpr>(Parent)->getCond() == S)
- return PathDiagnosticLocation(Parent, SMgr);
+ return PathDiagnosticLocation(Parent, SMgr, LC);
else
- return PathDiagnosticLocation(S, SMgr);
+ return PathDiagnosticLocation(S, SMgr, LC);
case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass:
// For '?', if we are referring to condition, just have the edge point
// to the entire '?' expression.
if (cast<AbstractConditionalOperator>(Parent)->getCond() == S)
- return PathDiagnosticLocation(Parent, SMgr);
+ return PathDiagnosticLocation(Parent, SMgr, LC);
else
- return PathDiagnosticLocation(S, SMgr);
+ return PathDiagnosticLocation(S, SMgr, LC);
case Stmt::DoStmtClass:
- return PathDiagnosticLocation(S, SMgr);
+ return PathDiagnosticLocation(S, SMgr, LC);
case Stmt::ForStmtClass:
if (cast<ForStmt>(Parent)->getBody() == S)
- return PathDiagnosticLocation(S, SMgr);
+ return PathDiagnosticLocation(S, SMgr, LC);
break;
case Stmt::IfStmtClass:
if (cast<IfStmt>(Parent)->getCond() != S)
- return PathDiagnosticLocation(S, SMgr);
+ return PathDiagnosticLocation(S, SMgr, LC);
break;
case Stmt::ObjCForCollectionStmtClass:
if (cast<ObjCForCollectionStmt>(Parent)->getBody() == S)
- return PathDiagnosticLocation(S, SMgr);
+ return PathDiagnosticLocation(S, SMgr, LC);
break;
case Stmt::WhileStmtClass:
if (cast<WhileStmt>(Parent)->getCond() != S)
- return PathDiagnosticLocation(S, SMgr);
+ return PathDiagnosticLocation(S, SMgr, LC);
break;
default:
break;
@@ -322,7 +301,7 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
switch (Parent->getStmtClass()) {
case Stmt::ForStmtClass:
case Stmt::ObjCForCollectionStmtClass:
- return PathDiagnosticLocation(Parent, SMgr);
+ return PathDiagnosticLocation(Parent, SMgr, LC);
default:
break;
}
@@ -335,20 +314,20 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
if (const ForStmt *FS =
dyn_cast_or_null<ForStmt>(P.getParentIgnoreParens(S))) {
if (FS->getInit() == S)
- return PathDiagnosticLocation(FS, SMgr);
+ return PathDiagnosticLocation(FS, SMgr, LC);
}
}
- return PathDiagnosticLocation(S, SMgr);
+ return PathDiagnosticLocation(S, SMgr, LC);
}
//===----------------------------------------------------------------------===//
// ScanNotableSymbols: closure-like callback for scanning Store bindings.
//===----------------------------------------------------------------------===//
-static const VarDecl*
-GetMostRecentVarDeclBinding(const ExplodedNode* N,
- GRStateManager& VMgr, SVal X) {
+static const VarDecl* GetMostRecentVarDeclBinding(const ExplodedNode *N,
+ ProgramStateManager& VMgr,
+ SVal X) {
for ( ; N ; N = N->pred_empty() ? 0 : *N->pred_begin()) {
@@ -357,7 +336,7 @@ GetMostRecentVarDeclBinding(const ExplodedNode* N,
if (!isa<PostStmt>(P))
continue;
- const DeclRefExpr* DR = dyn_cast<DeclRefExpr>(cast<PostStmt>(P).getStmt());
+ const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(cast<PostStmt>(P).getStmt());
if (!DR)
continue;
@@ -367,7 +346,7 @@ GetMostRecentVarDeclBinding(const ExplodedNode* N,
if (X != Y)
continue;
- const VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl());
+ const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
if (!VD)
continue;
@@ -383,19 +362,29 @@ class NotableSymbolHandler
: public StoreManager::BindingsHandler {
SymbolRef Sym;
- const GRState* PrevSt;
- const Stmt* S;
- GRStateManager& VMgr;
- const ExplodedNode* Pred;
+ const ProgramState *PrevSt;
+ const Stmt *S;
+ ProgramStateManager& VMgr;
+ const ExplodedNode *Pred;
PathDiagnostic& PD;
BugReporter& BR;
public:
- NotableSymbolHandler(SymbolRef sym, const GRState* prevst, const Stmt* s,
- GRStateManager& vmgr, const ExplodedNode* pred,
- PathDiagnostic& pd, BugReporter& br)
- : Sym(sym), PrevSt(prevst), S(s), VMgr(vmgr), Pred(pred), PD(pd), BR(br) {}
+ NotableSymbolHandler(SymbolRef sym,
+ const ProgramState *prevst,
+ const Stmt *s,
+ ProgramStateManager& vmgr,
+ const ExplodedNode *pred,
+ PathDiagnostic& pd,
+ BugReporter& br)
+ : Sym(sym),
+ PrevSt(prevst),
+ S(s),
+ VMgr(vmgr),
+ Pred(pred),
+ PD(pd),
+ BR(br) {}
bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R,
SVal V) {
@@ -422,14 +411,14 @@ public:
return true;
// What variable did we assign to?
- DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenCasts());
+ DeclRefExpr *DR = dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenCasts());
if (!DR)
return true;
VD = dyn_cast<VarDecl>(DR->getDecl());
}
- else if (const DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
+ else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
// FIXME: Eventually CFGs won't have DeclStmts. Right now we
// assume that each DeclStmt has a single Decl. This invariant
// holds by construction in the CFG.
@@ -440,19 +429,20 @@ public:
return true;
// What is the most recently referenced variable with this binding?
- const VarDecl* MostRecent = GetMostRecentVarDeclBinding(Pred, VMgr, V);
+ const VarDecl *MostRecent = GetMostRecentVarDeclBinding(Pred, VMgr, V);
if (!MostRecent)
return true;
// Create the diagnostic.
- FullSourceLoc L(S->getLocStart(), BR.getSourceManager());
-
if (Loc::isLocType(VD->getType())) {
- std::string msg = "'" + std::string(VD->getNameAsString()) +
- "' now aliases '" + MostRecent->getNameAsString() + "'";
-
- PD.push_front(new PathDiagnosticEventPiece(L, msg));
+ llvm::SmallString<64> buf;
+ llvm::raw_svector_ostream os(buf);
+ os << '\'' << *VD << "' now aliases '" << *MostRecent << '\'';
+ PathDiagnosticLocation L =
+ PathDiagnosticLocation::createBegin(S, BR.getSourceManager(),
+ Pred->getLocationContext());
+ PD.push_front(new PathDiagnosticEventPiece(L, os.str()));
}
return true;
@@ -460,20 +450,20 @@ public:
};
}
-static void HandleNotableSymbol(const ExplodedNode* N,
- const Stmt* S,
+static void HandleNotableSymbol(const ExplodedNode *N,
+ const Stmt *S,
SymbolRef Sym, BugReporter& BR,
PathDiagnostic& PD) {
- const ExplodedNode* Pred = N->pred_empty() ? 0 : *N->pred_begin();
- const GRState* PrevSt = Pred ? Pred->getState() : 0;
+ const ExplodedNode *Pred = N->pred_empty() ? 0 : *N->pred_begin();
+ const ProgramState *PrevSt = Pred ? Pred->getState() : 0;
if (!PrevSt)
return;
// Look at the region bindings of the current state that map to the
// specified symbol. Are any of them not in the previous state?
- GRStateManager& VMgr = cast<GRBugReporter>(BR).getStateManager();
+ ProgramStateManager& VMgr = cast<GRBugReporter>(BR).getStateManager();
NotableSymbolHandler H(Sym, PrevSt, S, VMgr, Pred, PD, BR);
cast<GRBugReporter>(BR).getStateManager().iterBindings(N->getState(), H);
}
@@ -483,13 +473,13 @@ class ScanNotableSymbols
: public StoreManager::BindingsHandler {
llvm::SmallSet<SymbolRef, 10> AlreadyProcessed;
- const ExplodedNode* N;
- const Stmt* S;
+ const ExplodedNode *N;
+ const Stmt *S;
GRBugReporter& BR;
PathDiagnostic& PD;
public:
- ScanNotableSymbols(const ExplodedNode* n, const Stmt* s,
+ ScanNotableSymbols(const ExplodedNode *n, const Stmt *s,
GRBugReporter& br, PathDiagnostic& pd)
: N(n), S(s), BR(br), PD(pd) {}
@@ -526,7 +516,8 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
const ExplodedNode *N) {
SourceManager& SMgr = PDB.getSourceManager();
- const ExplodedNode* NextNode = N->pred_empty()
+ const LocationContext *LC = PDB.getLocationContext();
+ const ExplodedNode *NextNode = N->pred_empty()
? NULL : *(N->pred_begin());
while (NextNode) {
N = NextNode;
@@ -534,15 +525,17 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
ProgramPoint P = N->getLocation();
- if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P)) {
- const CFGBlock* Src = BE->getSrc();
- const CFGBlock* Dst = BE->getDst();
- const Stmt* T = Src->getTerminator();
+ if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+ const CFGBlock *Src = BE->getSrc();
+ const CFGBlock *Dst = BE->getDst();
+ const Stmt *T = Src->getTerminator();
if (!T)
continue;
- FullSourceLoc Start(T->getLocStart(), SMgr);
+ PathDiagnosticLocation Start =
+ PathDiagnosticLocation::createBegin(T, SMgr,
+ N->getLocationContext());
switch (T->getStmtClass()) {
default:
@@ -550,7 +543,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
case Stmt::GotoStmtClass:
case Stmt::IndirectGotoStmtClass: {
- const Stmt* S = GetNextStmt(N);
+ const Stmt *S = GetNextStmt(N);
if (!S)
continue;
@@ -560,7 +553,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
const PathDiagnosticLocation &End = PDB.getEnclosingStmtLocation(S);
os << "Control jumps to line "
- << End.asLocation().getInstantiationLineNumber();
+ << End.asLocation().getExpansionLineNumber();
PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
os.str()));
break;
@@ -571,45 +564,45 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
- if (const Stmt* S = Dst->getLabel()) {
- PathDiagnosticLocation End(S, SMgr);
+ if (const Stmt *S = Dst->getLabel()) {
+ PathDiagnosticLocation End(S, SMgr, LC);
switch (S->getStmtClass()) {
default:
os << "No cases match in the switch statement. "
"Control jumps to line "
- << End.asLocation().getInstantiationLineNumber();
+ << End.asLocation().getExpansionLineNumber();
break;
case Stmt::DefaultStmtClass:
os << "Control jumps to the 'default' case at line "
- << End.asLocation().getInstantiationLineNumber();
+ << End.asLocation().getExpansionLineNumber();
break;
case Stmt::CaseStmtClass: {
os << "Control jumps to 'case ";
- const CaseStmt* Case = cast<CaseStmt>(S);
- const Expr* LHS = Case->getLHS()->IgnoreParenCasts();
+ const CaseStmt *Case = cast<CaseStmt>(S);
+ const Expr *LHS = Case->getLHS()->IgnoreParenCasts();
// Determine if it is an enum.
bool GetRawInt = true;
- if (const DeclRefExpr* DR = dyn_cast<DeclRefExpr>(LHS)) {
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) {
// FIXME: Maybe this should be an assertion. Are there cases
// were it is not an EnumConstantDecl?
- const EnumConstantDecl* D =
+ const EnumConstantDecl *D =
dyn_cast<EnumConstantDecl>(DR->getDecl());
if (D) {
GetRawInt = false;
- os << D;
+ os << *D;
}
}
if (GetRawInt)
- os << LHS->EvaluateAsInt(PDB.getASTContext());
+ os << LHS->EvaluateKnownConstInt(PDB.getASTContext());
os << ":' at line "
- << End.asLocation().getInstantiationLineNumber();
+ << End.asLocation().getExpansionLineNumber();
break;
}
}
@@ -673,14 +666,15 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (*(Src->succ_begin()+1) == Dst) {
os << "false";
- PathDiagnosticLocation End(B->getLHS(), SMgr);
- PathDiagnosticLocation Start(B->getOperatorLoc(), SMgr);
+ PathDiagnosticLocation End(B->getLHS(), SMgr, LC);
+ PathDiagnosticLocation Start =
+ PathDiagnosticLocation::createOperatorLoc(B, SMgr);
PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
os.str()));
}
else {
os << "true";
- PathDiagnosticLocation Start(B->getLHS(), SMgr);
+ PathDiagnosticLocation Start(B->getLHS(), SMgr, LC);
PathDiagnosticLocation End = PDB.ExecutionContinues(N);
PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
os.str()));
@@ -692,15 +686,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (*(Src->succ_begin()+1) == Dst) {
os << "false";
- PathDiagnosticLocation Start(B->getLHS(), SMgr);
+ PathDiagnosticLocation Start(B->getLHS(), SMgr, LC);
PathDiagnosticLocation End = PDB.ExecutionContinues(N);
PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
os.str()));
}
else {
os << "true";
- PathDiagnosticLocation End(B->getLHS(), SMgr);
- PathDiagnosticLocation Start(B->getOperatorLoc(), SMgr);
+ PathDiagnosticLocation End(B->getLHS(), SMgr, LC);
+ PathDiagnosticLocation Start =
+ PathDiagnosticLocation::createOperatorLoc(B, SMgr);
PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
os.str()));
}
@@ -781,14 +776,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
}
if (NextNode) {
- for (BugReporterContext::visitor_iterator I = PDB.visitor_begin(),
- E = PDB.visitor_end(); I!=E; ++I) {
- if (PathDiagnosticPiece* p = (*I)->VisitNode(N, NextNode, PDB))
+ // Add diagnostic pieces from custom visitors.
+ BugReport *R = PDB.getBugReport();
+ for (BugReport::visitor_iterator I = R->visitor_begin(),
+ E = R->visitor_end(); I!=E; ++I) {
+ if (PathDiagnosticPiece *p = (*I)->VisitNode(N, NextNode, PDB, *R))
PD.push_front(p);
}
}
- if (const PostStmt* PS = dyn_cast<PostStmt>(&P)) {
+ if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
// Scan the region bindings, and see if a "notable" symbol has a new
// lval binding.
ScanNotableSymbols SNS(N, PS->getStmt(), PDB.getBugReporter(), PD);
@@ -882,11 +879,11 @@ class EdgeBuilder {
}
if (S != Original)
- L = PathDiagnosticLocation(S, L.getManager());
+ L = PathDiagnosticLocation(S, L.getManager(), PDB.getLocationContext());
}
if (firstCharOnly)
- L = PathDiagnosticLocation(L.asLocation());
+ L = PathDiagnosticLocation::createSingleLocation(L);
return L;
}
@@ -915,17 +912,14 @@ public:
~EdgeBuilder() {
while (!CLocs.empty()) popLocation();
-
+
// Finally, add an initial edge from the start location of the first
// statement (if it doesn't already exist).
- // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
- if (const CompoundStmt *CS =
- dyn_cast_or_null<CompoundStmt>(PDB.getCodeDecl().getBody()))
- if (!CS->body_empty()) {
- SourceLocation Loc = (*CS->body_begin())->getLocStart();
- rawAddEdge(PathDiagnosticLocation(Loc, PDB.getSourceManager()));
- }
-
+ PathDiagnosticLocation L = PathDiagnosticLocation::createDeclBegin(
+ PDB.getLocationContext(),
+ PDB.getSourceManager());
+ if (L.isValid())
+ rawAddEdge(L);
}
void addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd = false);
@@ -974,15 +968,15 @@ bool EdgeBuilder::containsLocation(const PathDiagnosticLocation &Container,
SourceRange ContaineeR = Containee.asRange();
SourceManager &SM = PDB.getSourceManager();
- SourceLocation ContainerRBeg = SM.getInstantiationLoc(ContainerR.getBegin());
- SourceLocation ContainerREnd = SM.getInstantiationLoc(ContainerR.getEnd());
- SourceLocation ContaineeRBeg = SM.getInstantiationLoc(ContaineeR.getBegin());
- SourceLocation ContaineeREnd = SM.getInstantiationLoc(ContaineeR.getEnd());
+ SourceLocation ContainerRBeg = SM.getExpansionLoc(ContainerR.getBegin());
+ SourceLocation ContainerREnd = SM.getExpansionLoc(ContainerR.getEnd());
+ SourceLocation ContaineeRBeg = SM.getExpansionLoc(ContaineeR.getBegin());
+ SourceLocation ContaineeREnd = SM.getExpansionLoc(ContaineeR.getEnd());
- unsigned ContainerBegLine = SM.getInstantiationLineNumber(ContainerRBeg);
- unsigned ContainerEndLine = SM.getInstantiationLineNumber(ContainerREnd);
- unsigned ContaineeBegLine = SM.getInstantiationLineNumber(ContaineeRBeg);
- unsigned ContaineeEndLine = SM.getInstantiationLineNumber(ContaineeREnd);
+ unsigned ContainerBegLine = SM.getExpansionLineNumber(ContainerRBeg);
+ unsigned ContainerEndLine = SM.getExpansionLineNumber(ContainerREnd);
+ unsigned ContaineeBegLine = SM.getExpansionLineNumber(ContaineeRBeg);
+ unsigned ContaineeEndLine = SM.getExpansionLineNumber(ContaineeREnd);
assert(ContainerBegLine <= ContainerEndLine);
assert(ContaineeBegLine <= ContaineeEndLine);
@@ -990,11 +984,11 @@ bool EdgeBuilder::containsLocation(const PathDiagnosticLocation &Container,
return (ContainerBegLine <= ContaineeBegLine &&
ContainerEndLine >= ContaineeEndLine &&
(ContainerBegLine != ContaineeBegLine ||
- SM.getInstantiationColumnNumber(ContainerRBeg) <=
- SM.getInstantiationColumnNumber(ContaineeRBeg)) &&
+ SM.getExpansionColumnNumber(ContainerRBeg) <=
+ SM.getExpansionColumnNumber(ContaineeRBeg)) &&
(ContainerEndLine != ContaineeEndLine ||
- SM.getInstantiationColumnNumber(ContainerREnd) >=
- SM.getInstantiationColumnNumber(ContainerREnd)));
+ SM.getExpansionColumnNumber(ContainerREnd) >=
+ SM.getExpansionColumnNumber(ContainerREnd)));
}
void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) {
@@ -1010,8 +1004,8 @@ void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) {
return;
// FIXME: Ignore intra-macro edges for now.
- if (NewLocClean.asLocation().getInstantiationLoc() ==
- PrevLocClean.asLocation().getInstantiationLoc())
+ if (NewLocClean.asLocation().getExpansionLoc() ==
+ PrevLocClean.asLocation().getExpansionLoc())
return;
PD.push_front(new PathDiagnosticControlFlowPiece(NewLocClean, PrevLocClean));
@@ -1099,7 +1093,7 @@ void EdgeBuilder::addContext(const Stmt *S) {
if (!S)
return;
- PathDiagnosticLocation L(S, PDB.getSourceManager());
+ PathDiagnosticLocation L(S, PDB.getSourceManager(), PDB.getLocationContext());
while (!CLocs.empty()) {
const PathDiagnosticLocation &TopContextLoc = CLocs.back();
@@ -1124,8 +1118,9 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticBuilder &PDB,
const ExplodedNode *N) {
EdgeBuilder EB(PD, PDB);
+ const SourceManager& SM = PDB.getSourceManager();
- const ExplodedNode* NextNode = N->pred_empty() ? NULL : *(N->pred_begin());
+ const ExplodedNode *NextNode = N->pred_empty() ? NULL : *(N->pred_begin());
while (NextNode) {
N = NextNode;
NextNode = GetPredecessorNode(N);
@@ -1139,7 +1134,7 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
// Are we jumping to the head of a loop? Add a special diagnostic.
if (const Stmt *Loop = BE->getDst()->getLoopTarget()) {
- PathDiagnosticLocation L(Loop, PDB.getSourceManager());
+ PathDiagnosticLocation L(Loop, SM, PDB.getLocationContext());
const CompoundStmt *CS = NULL;
if (!Term) {
@@ -1157,9 +1152,8 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PD.push_front(p);
if (CS) {
- PathDiagnosticLocation BL(CS->getRBracLoc(),
- PDB.getSourceManager());
- BL = PathDiagnosticLocation(BL.asLocation());
+ PathDiagnosticLocation BL =
+ PathDiagnosticLocation::createEndBrace(CS, SM);
EB.addEdge(BL);
}
}
@@ -1188,9 +1182,11 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
if (!NextNode)
continue;
- for (BugReporterContext::visitor_iterator I = PDB.visitor_begin(),
- E = PDB.visitor_end(); I!=E; ++I) {
- if (PathDiagnosticPiece* p = (*I)->VisitNode(N, NextNode, PDB)) {
+ // Add pieces from custom visitors.
+ BugReport *R = PDB.getBugReport();
+ for (BugReport::visitor_iterator I = R->visitor_begin(),
+ E = R->visitor_end(); I!=E; ++I) {
+ if (PathDiagnosticPiece *p = (*I)->VisitNode(N, NextNode, PDB, *R)) {
const PathDiagnosticLocation &Loc = p->getLocation();
EB.addEdge(Loc, true);
PD.push_front(p);
@@ -1211,14 +1207,58 @@ void BugType::FlushReports(BugReporter &BR) {}
//===----------------------------------------------------------------------===//
// Methods for BugReport and subclasses.
//===----------------------------------------------------------------------===//
-BugReport::~BugReport() {}
-RangedBugReport::~RangedBugReport() {}
-const Stmt* BugReport::getStmt() const {
+void BugReport::addVisitor(BugReporterVisitor* visitor) {
+ if (!visitor)
+ return;
+
+ llvm::FoldingSetNodeID ID;
+ visitor->Profile(ID);
+ void *InsertPos;
+
+ if (CallbacksSet.FindNodeOrInsertPos(ID, InsertPos)) {
+ delete visitor;
+ return;
+ }
+
+ CallbacksSet.InsertNode(visitor, InsertPos);
+ Callbacks = F.add(visitor, Callbacks);
+}
+
+BugReport::~BugReport() {
+ for (visitor_iterator I = visitor_begin(), E = visitor_end(); I != E; ++I) {
+ delete *I;
+ }
+}
+
+void BugReport::Profile(llvm::FoldingSetNodeID& hash) const {
+ hash.AddPointer(&BT);
+ hash.AddString(Description);
+ if (Location.isValid()) {
+ Location.Profile(hash);
+ } else {
+ assert(ErrorNode);
+ hash.AddPointer(GetCurrentOrPreviousStmt(ErrorNode));
+ }
+
+ for (SmallVectorImpl<SourceRange>::const_iterator I =
+ Ranges.begin(), E = Ranges.end(); I != E; ++I) {
+ const SourceRange range = *I;
+ if (!range.isValid())
+ continue;
+ hash.AddInteger(range.getBegin().getRawEncoding());
+ hash.AddInteger(range.getEnd().getRawEncoding());
+ }
+}
+
+const Stmt *BugReport::getStmt() const {
+ if (!ErrorNode)
+ return 0;
+
ProgramPoint ProgP = ErrorNode->getLocation();
const Stmt *S = NULL;
- if (BlockEntrance* BE = dyn_cast<BlockEntrance>(&ProgP)) {
+ if (BlockEntrance *BE = dyn_cast<BlockEntrance>(&ProgP)) {
CFGBlock &Exit = ProgP.getLocationContext()->getCFG()->getExit();
if (BE->getBlock() == &Exit)
S = GetPreviousStmt(ErrorNode);
@@ -1229,61 +1269,47 @@ const Stmt* BugReport::getStmt() const {
return S;
}
-PathDiagnosticPiece*
-BugReport::getEndPath(BugReporterContext& BRC,
- const ExplodedNode* EndPathNode) {
-
- const Stmt* S = getStmt();
-
- if (!S)
- return NULL;
-
- BugReport::ranges_iterator Beg, End;
- llvm::tie(Beg, End) = getRanges();
- PathDiagnosticLocation L(S, BRC.getSourceManager());
-
- // Only add the statement itself as a range if we didn't specify any
- // special ranges for this report.
- PathDiagnosticPiece* P = new PathDiagnosticEventPiece(L, getDescription(),
- Beg == End);
+std::pair<BugReport::ranges_iterator, BugReport::ranges_iterator>
+BugReport::getRanges() {
+ // If no custom ranges, add the range of the statement corresponding to
+ // the error node.
+ if (Ranges.empty()) {
+ if (const Expr *E = dyn_cast_or_null<Expr>(getStmt()))
+ addRange(E->getSourceRange());
+ else
+ return std::make_pair(ranges_iterator(), ranges_iterator());
+ }
- for (; Beg != End; ++Beg)
- P->addRange(*Beg);
+ // User-specified absence of range info.
+ if (Ranges.size() == 1 && !Ranges.begin()->isValid())
+ return std::make_pair(ranges_iterator(), ranges_iterator());
- return P;
+ return std::make_pair(Ranges.begin(), Ranges.end());
}
-std::pair<BugReport::ranges_iterator, BugReport::ranges_iterator>
-BugReport::getRanges() const {
- if (const Expr* E = dyn_cast_or_null<Expr>(getStmt())) {
- R = E->getSourceRange();
- assert(R.isValid());
- return std::make_pair(&R, &R+1);
- }
- else
- return std::make_pair(ranges_iterator(), ranges_iterator());
-}
+PathDiagnosticLocation BugReport::getLocation(const SourceManager &SM) const {
+ if (ErrorNode) {
+ assert(!Location.isValid() &&
+ "Either Location or ErrorNode should be specified but not both.");
+
+ if (const Stmt *S = GetCurrentOrPreviousStmt(ErrorNode)) {
+ const LocationContext *LC = ErrorNode->getLocationContext();
-SourceLocation BugReport::getLocation() const {
- if (ErrorNode)
- if (const Stmt* S = GetCurrentOrPreviousStmt(ErrorNode)) {
// For member expressions, return the location of the '.' or '->'.
if (const MemberExpr *ME = dyn_cast<MemberExpr>(S))
- return ME->getMemberLoc();
+ return PathDiagnosticLocation::createMemberLoc(ME, SM);
// For binary operators, return the location of the operator.
if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S))
- return B->getOperatorLoc();
+ return PathDiagnosticLocation::createOperatorLoc(B, SM);
- return S->getLocStart();
+ return PathDiagnosticLocation::createBegin(S, SM, LC);
}
+ } else {
+ assert(Location.isValid());
+ return Location;
+ }
- return FullSourceLoc();
-}
-
-PathDiagnosticPiece* BugReport::VisitNode(const ExplodedNode* N,
- const ExplodedNode* PrevN,
- BugReporterContext &BRC) {
- return NULL;
+ return PathDiagnosticLocation();
}
//===----------------------------------------------------------------------===//
@@ -1299,10 +1325,19 @@ BugReporterData::~BugReporterData() {}
ExplodedGraph &GRBugReporter::getGraph() { return Eng.getGraph(); }
-GRStateManager&
+ProgramStateManager&
GRBugReporter::getStateManager() { return Eng.getStateManager(); }
-BugReporter::~BugReporter() { FlushReports(); }
+BugReporter::~BugReporter() {
+ FlushReports();
+
+ // Free the bug reports we are tracking.
+ typedef std::vector<BugReportEquivClass *> ContTy;
+ for (ContTy::iterator I = EQClassesVector.begin(), E = EQClassesVector.end();
+ I != E; ++I) {
+ delete *I;
+ }
+}
void BugReporter::FlushReports() {
if (BugTypes.isEmpty())
@@ -1312,10 +1347,10 @@ void BugReporter::FlushReports() {
// warnings and new BugTypes.
// FIXME: Only NSErrorChecker needs BugType's FlushReports.
// Turn NSErrorChecker into a proper checker and remove this.
- llvm::SmallVector<const BugType*, 16> bugTypes;
+ SmallVector<const BugType*, 16> bugTypes;
for (BugTypesTy::iterator I=BugTypes.begin(), E=BugTypes.end(); I!=E; ++I)
bugTypes.push_back(*I);
- for (llvm::SmallVector<const BugType*, 16>::iterator
+ for (SmallVector<const BugType*, 16>::iterator
I = bugTypes.begin(), E = bugTypes.end(); I != E; ++I)
const_cast<BugType*>(*I)->FlushReports(*this);
@@ -1344,7 +1379,7 @@ void BugReporter::FlushReports() {
static std::pair<std::pair<ExplodedGraph*, NodeBackMap*>,
std::pair<ExplodedNode*, unsigned> >
MakeReportGraph(const ExplodedGraph* G,
- llvm::SmallVectorImpl<const ExplodedNode*> &nodes) {
+ SmallVectorImpl<const ExplodedNode*> &nodes) {
// 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
@@ -1390,10 +1425,10 @@ MakeReportGraph(const ExplodedGraph* G,
llvm::DenseMap<const void*,unsigned> Visited;
unsigned cnt = 0;
- const ExplodedNode* Root = 0;
+ const ExplodedNode *Root = 0;
while (!WS.empty()) {
- const ExplodedNode* Node = WS.front();
+ const ExplodedNode *Node = WS.front();
WS.pop();
if (Visited.find(Node) != Visited.end())
@@ -1426,7 +1461,7 @@ MakeReportGraph(const ExplodedGraph* G,
// 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(N->getLocation(), N->getState());
// Store the mapping to the original node.
llvm::DenseMap<const void*, const void*>::iterator IMitr=InverseMap.find(N);
@@ -1495,7 +1530,7 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) {
// Determine the instantiation location, which is the location we group
// related PathDiagnosticPieces.
SourceLocation InstantiationLoc = Loc.isMacroID() ?
- SM.getInstantiationLoc(Loc) :
+ SM.getExpansionLoc(Loc) :
SourceLocation();
if (Loc.isFileID()) {
@@ -1517,7 +1552,7 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) {
PathDiagnosticMacroPiece *MacroGroup = 0;
SourceLocation ParentInstantiationLoc = InstantiationLoc.isMacroID() ?
- SM.getInstantiationLoc(Loc) :
+ SM.getExpansionLoc(Loc) :
SourceLocation();
// Walk the entire macro stack.
@@ -1537,7 +1572,9 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) {
if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {
// Create a new macro group and add it to the stack.
- PathDiagnosticMacroPiece *NewGroup = new PathDiagnosticMacroPiece(Loc);
+ PathDiagnosticMacroPiece *NewGroup =
+ new PathDiagnosticMacroPiece(
+ PathDiagnosticLocation::createSingleLocation(I->getLocation()));
if (MacroGroup)
MacroGroup->push_back(NewGroup);
@@ -1569,11 +1606,11 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) {
}
void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
- llvm::SmallVectorImpl<BugReport *> &bugReports) {
+ SmallVectorImpl<BugReport *> &bugReports) {
assert(!bugReports.empty());
- llvm::SmallVector<const ExplodedNode *, 10> errorNodes;
- for (llvm::SmallVectorImpl<BugReport*>::iterator I = bugReports.begin(),
+ SmallVector<const ExplodedNode *, 10> errorNodes;
+ for (SmallVectorImpl<BugReport*>::iterator I = bugReports.begin(),
E = bugReports.end(); I != E; ++I) {
errorNodes.push_back((*I)->getErrorNode());
}
@@ -1594,22 +1631,36 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
const ExplodedNode *N = GPair.second.first;
// Start building the path diagnostic...
- PathDiagnosticBuilder PDB(*this, R, BackMap.get(), getPathDiagnosticClient());
-
- if (PathDiagnosticPiece* Piece = R->getEndPath(PDB, N))
- PD.push_back(Piece);
+ PathDiagnosticBuilder PDB(*this, R, BackMap.get(),
+ getPathDiagnosticConsumer());
+
+ // Register additional node visitors.
+ R->addVisitor(new NilReceiverBRVisitor());
+ R->addVisitor(new ConditionBRVisitor());
+
+ // Generate the very last diagnostic piece - the piece is visible before
+ // the trace is expanded.
+ PathDiagnosticPiece *LastPiece = 0;
+ for (BugReport::visitor_iterator I = R->visitor_begin(),
+ E = R->visitor_end(); I!=E; ++I) {
+ if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) {
+ assert (!LastPiece &&
+ "There can only be one final piece in a diagnostic.");
+ LastPiece = Piece;
+ }
+ }
+ if (!LastPiece)
+ LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R);
+ if (LastPiece)
+ PD.push_back(LastPiece);
else
return;
- // Register node visitors.
- R->registerInitialVisitors(PDB, N);
- bugreporter::registerNilReceiverVisitor(PDB);
-
switch (PDB.getGenerationScheme()) {
- case PathDiagnosticClient::Extensive:
+ case PathDiagnosticConsumer::Extensive:
GenerateExtensivePathDiagnostic(PD, PDB, N);
break;
- case PathDiagnosticClient::Minimal:
+ case PathDiagnosticConsumer::Minimal:
GenerateMinimalPathDiagnostic(PD, PDB, N);
break;
}
@@ -1633,6 +1684,7 @@ void BugReporter::EmitReport(BugReport* R) {
if (!EQ) {
EQ = new BugReportEquivClass(R);
EQClasses.InsertNode(EQ, InsertPos);
+ EQClassesVector.push_back(EQ);
}
else
EQ->AddReport(R);
@@ -1655,7 +1707,7 @@ struct FRIEC_WLItem {
static BugReport *
FindReportInEquivalenceClass(BugReportEquivClass& EQ,
- llvm::SmallVectorImpl<BugReport*> &bugReports) {
+ SmallVectorImpl<BugReport*> &bugReports) {
BugReportEquivClass::iterator I = EQ.begin(), E = EQ.end();
assert(I != E);
@@ -1667,7 +1719,7 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ,
// to 'Nodes'. Any of the reports will serve as a "representative" report.
if (!BT.isSuppressOnSink()) {
for (BugReportEquivClass::iterator I=EQ.begin(), E=EQ.end(); I!=E; ++I) {
- const ExplodedNode* N = I->getErrorNode();
+ const ExplodedNode *N = I->getErrorNode();
if (N) {
R = *I;
bugReports.push_back(R);
@@ -1691,9 +1743,8 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ,
if (!errorNode)
continue;
if (errorNode->isSink()) {
- assert(false &&
+ llvm_unreachable(
"BugType::isSuppressSink() should not be 'true' for sink end nodes");
- return 0;
}
// No successors? By definition this nodes isn't post-dominated by a sink.
if (errorNode->succ_empty()) {
@@ -1706,7 +1757,7 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ,
// At this point we know that 'N' is not a sink and it has at least one
// successor. Use a DFS worklist to find a non-sink end-of-path node.
typedef FRIEC_WLItem WLItem;
- typedef llvm::SmallVector<WLItem, 10> DFSWorkList;
+ typedef SmallVector<WLItem, 10> DFSWorkList;
llvm::DenseMap<const ExplodedNode *, unsigned> Visited;
DFSWorkList WL;
@@ -1763,11 +1814,8 @@ class DiagCacheItem : public llvm::FoldingSetNode {
llvm::FoldingSetNodeID ID;
public:
DiagCacheItem(BugReport *R, PathDiagnostic *PD) {
- ID.AddString(R->getBugType().getName());
- ID.AddString(R->getBugType().getCategory());
- ID.AddString(R->getDescription());
- ID.AddInteger(R->getLocation().getRawEncoding());
- PD->Profile(ID);
+ R->Profile(ID);
+ PD->Profile(ID);
}
void Profile(llvm::FoldingSetNodeID &id) {
@@ -1798,12 +1846,12 @@ static bool IsCachedDiagnostic(BugReport *R, PathDiagnostic *PD) {
}
void BugReporter::FlushReport(BugReportEquivClass& EQ) {
- llvm::SmallVector<BugReport*, 10> bugReports;
+ SmallVector<BugReport*, 10> bugReports;
BugReport *exampleReport = FindReportInEquivalenceClass(EQ, bugReports);
if (!exampleReport)
return;
- PathDiagnosticClient* PD = getPathDiagnosticClient();
+ PathDiagnosticConsumer* PD = getPathDiagnosticConsumer();
// FIXME: Make sure we use the 'R' for the path that was actually used.
// Probably doesn't make a difference in practice.
@@ -1823,47 +1871,50 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
return;
// Get the meta data.
- std::pair<const char**, const char**> Meta =
- exampleReport->getExtraDescriptiveText();
- for (const char** s = Meta.first; s != Meta.second; ++s)
- D->addMeta(*s);
+ const BugReport::ExtraTextList &Meta =
+ exampleReport->getExtraText();
+ for (BugReport::ExtraTextList::const_iterator i = Meta.begin(),
+ e = Meta.end(); i != e; ++i) {
+ D->addMeta(*i);
+ }
// Emit a summary diagnostic to the regular Diagnostics engine.
BugReport::ranges_iterator Beg, End;
llvm::tie(Beg, End) = exampleReport->getRanges();
- Diagnostic &Diag = getDiagnostic();
- FullSourceLoc L(exampleReport->getLocation(), getSourceManager());
+ DiagnosticsEngine &Diag = getDiagnostic();
// Search the description for '%', as that will be interpretted as a
// format character by FormatDiagnostics.
- llvm::StringRef desc = exampleReport->getShortDescription();
+ StringRef desc = exampleReport->getShortDescription();
unsigned ErrorDiag;
{
llvm::SmallString<512> TmpStr;
llvm::raw_svector_ostream Out(TmpStr);
- for (llvm::StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I)
+ for (StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I)
if (*I == '%')
Out << "%%";
else
Out << *I;
Out.flush();
- ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning, TmpStr);
+ ErrorDiag = Diag.getCustomDiagID(DiagnosticsEngine::Warning, TmpStr);
}
{
- DiagnosticBuilder diagBuilder = Diag.Report(L, ErrorDiag);
+ DiagnosticBuilder diagBuilder = Diag.Report(
+ exampleReport->getLocation(getSourceManager()).asLocation(), ErrorDiag);
for (BugReport::ranges_iterator I = Beg; I != End; ++I)
diagBuilder << *I;
}
- // Emit a full diagnostic for the path if we have a PathDiagnosticClient.
+ // Emit a full diagnostic for the path if we have a PathDiagnosticConsumer.
if (!PD)
return;
if (D->empty()) {
- PathDiagnosticPiece* piece =
- new PathDiagnosticEventPiece(L, exampleReport->getDescription());
+ PathDiagnosticPiece *piece = new PathDiagnosticEventPiece(
+ exampleReport->getLocation(getSourceManager()),
+ exampleReport->getDescription());
for ( ; Beg != End; ++Beg) piece->addRange(*Beg);
D->push_back(piece);
@@ -1872,27 +1923,26 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
PD->HandlePathDiagnostic(D.take());
}
-void BugReporter::EmitBasicReport(llvm::StringRef name, llvm::StringRef str,
- SourceLocation Loc,
+void BugReporter::EmitBasicReport(StringRef name, StringRef str,
+ PathDiagnosticLocation Loc,
SourceRange* RBeg, unsigned NumRanges) {
EmitBasicReport(name, "", str, Loc, RBeg, NumRanges);
}
-void BugReporter::EmitBasicReport(llvm::StringRef name,
- llvm::StringRef category,
- llvm::StringRef str, SourceLocation Loc,
+void BugReporter::EmitBasicReport(StringRef name,
+ StringRef category,
+ StringRef str, PathDiagnosticLocation Loc,
SourceRange* RBeg, unsigned NumRanges) {
// 'BT' is owned by BugReporter.
BugType *BT = getBugTypeForName(name, category);
- FullSourceLoc L = getContext().getFullLoc(Loc);
- RangedBugReport *R = new DiagBugReport(*BT, str, L);
+ BugReport *R = new BugReport(*BT, str, Loc);
for ( ; NumRanges > 0 ; --NumRanges, ++RBeg) R->addRange(*RBeg);
EmitReport(R);
}
-BugType *BugReporter::getBugTypeForName(llvm::StringRef name,
- llvm::StringRef category) {
+BugType *BugReporter::getBugTypeForName(StringRef name,
+ StringRef category) {
llvm::SmallString<136> fullDesc;
llvm::raw_svector_ostream(fullDesc) << name << ":" << category;
llvm::StringMapEntry<BugType *> &
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 8e31adead188..1abd8baef624 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -11,13 +11,15 @@
// enhance the diagnostics reported for a bug.
//
//===----------------------------------------------------------------------===//
+#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/ExplodedGraph.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
using namespace ento;
@@ -39,8 +41,6 @@ const Stmt *bugreporter::GetDerefExpr(const ExplodedNode *N) {
return ME->getBase()->IgnoreParenCasts();
}
else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) {
- // Retrieve the base for arrays since BasicStoreManager doesn't know how
- // to reason about them.
return AE->getBase();
}
@@ -73,248 +73,255 @@ const Stmt *bugreporter::GetRetValExpr(const ExplodedNode *N) {
// Definitions for bug reporter visitors.
//===----------------------------------------------------------------------===//
-namespace {
-class FindLastStoreBRVisitor : public BugReporterVisitor {
- const MemRegion *R;
- SVal V;
- bool satisfied;
- const ExplodedNode *StoreSite;
-public:
- FindLastStoreBRVisitor(SVal v, const MemRegion *r)
- : R(r), V(v), satisfied(false), StoreSite(0) {}
-
- virtual void Profile(llvm::FoldingSetNodeID &ID) const {
- static int tag = 0;
- ID.AddPointer(&tag);
- ID.AddPointer(R);
- ID.Add(V);
+PathDiagnosticPiece*
+BugReporterVisitor::getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *EndPathNode,
+ BugReport &BR) {
+ return 0;
+}
+
+PathDiagnosticPiece*
+BugReporterVisitor::getDefaultEndPath(BugReporterContext &BRC,
+ const ExplodedNode *EndPathNode,
+ BugReport &BR) {
+ const ProgramPoint &PP = EndPathNode->getLocation();
+ PathDiagnosticLocation L;
+
+ if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&PP)) {
+ const CFGBlock *block = BE->getBlock();
+ if (block->getBlockID() == 0) {
+ L = PathDiagnosticLocation::createDeclEnd(PP.getLocationContext(),
+ BRC.getSourceManager());
+ }
}
- PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
- const ExplodedNode *PrevN,
- BugReporterContext& BRC) {
+ if (!L.isValid()) {
+ const Stmt *S = BR.getStmt();
- if (satisfied)
+ if (!S)
return NULL;
- if (!StoreSite) {
- const ExplodedNode *Node = N, *Last = NULL;
+ L = PathDiagnosticLocation(S, BRC.getSourceManager(),
+ PP.getLocationContext());
+ }
- for ( ; Node ; Last = Node, Node = Node->getFirstPred()) {
+ BugReport::ranges_iterator Beg, End;
+ llvm::tie(Beg, End) = BR.getRanges();
- if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- if (const PostStmt *P = Node->getLocationAs<PostStmt>())
- if (const DeclStmt *DS = P->getStmtAs<DeclStmt>())
- if (DS->getSingleDecl() == VR->getDecl()) {
- Last = Node;
- break;
- }
- }
+ // Only add the statement itself as a range if we didn't specify any
+ // special ranges for this report.
+ PathDiagnosticPiece *P = new PathDiagnosticEventPiece(L,
+ BR.getDescription(),
+ Beg == End);
+ for (; Beg != End; ++Beg)
+ P->addRange(*Beg);
- if (Node->getState()->getSVal(R) != V)
- break;
- }
+ return P;
+}
- if (!Node || !Last) {
- satisfied = true;
- return NULL;
+
+void FindLastStoreBRVisitor ::Profile(llvm::FoldingSetNodeID &ID) const {
+ static int tag = 0;
+ ID.AddPointer(&tag);
+ ID.AddPointer(R);
+ ID.Add(V);
+}
+
+PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+
+ if (satisfied)
+ return NULL;
+
+ if (!StoreSite) {
+ const ExplodedNode *Node = N, *Last = NULL;
+
+ for ( ; Node ; Last = Node, Node = Node->getFirstPred()) {
+
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+ if (const PostStmt *P = Node->getLocationAs<PostStmt>())
+ if (const DeclStmt *DS = P->getStmtAs<DeclStmt>())
+ if (DS->getSingleDecl() == VR->getDecl()) {
+ Last = Node;
+ break;
+ }
}
- StoreSite = Last;
+ if (Node->getState()->getSVal(R) != V)
+ break;
}
- if (StoreSite != N)
+ if (!Node || !Last) {
+ satisfied = true;
return NULL;
+ }
- satisfied = true;
- llvm::SmallString<256> sbuf;
- llvm::raw_svector_ostream os(sbuf);
+ StoreSite = Last;
+ }
- if (const PostStmt *PS = N->getLocationAs<PostStmt>()) {
- if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
+ if (StoreSite != N)
+ return NULL;
- if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- os << "Variable '" << VR->getDecl() << "' ";
- }
- else
- return NULL;
-
- if (isa<loc::ConcreteInt>(V)) {
- bool b = false;
- if (R->isBoundable()) {
- if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
- if (TR->getValueType()->isObjCObjectPointerType()) {
- os << "initialized to nil";
- b = true;
- }
- }
- }
+ satisfied = true;
+ llvm::SmallString<256> sbuf;
+ llvm::raw_svector_ostream os(sbuf);
- if (!b)
- os << "initialized to a null pointer value";
- }
- else if (isa<nonloc::ConcreteInt>(V)) {
- os << "initialized to " << cast<nonloc::ConcreteInt>(V).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";
- }
- }
+ if (const PostStmt *PS = N->getLocationAs<PostStmt>()) {
+ if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
+
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+ os << "Variable '" << *VR->getDecl() << "' ";
}
- }
+ else
+ return NULL;
- if (os.str().empty()) {
if (isa<loc::ConcreteInt>(V)) {
bool b = false;
if (R->isBoundable()) {
- if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
+ if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) {
if (TR->getValueType()->isObjCObjectPointerType()) {
- os << "nil object reference stored to ";
+ os << "initialized to nil";
b = true;
}
}
}
if (!b)
- os << "Null pointer value stored to ";
- }
- else if (V.isUndef()) {
- os << "Uninitialized value stored to ";
+ os << "initialized to a null pointer value";
}
else if (isa<nonloc::ConcreteInt>(V)) {
- os << "The value " << cast<nonloc::ConcreteInt>(V).getValue()
- << " is assigned to ";
+ os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue();
}
- else
- return NULL;
-
- if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- os << '\'' << VR->getDecl() << '\'';
+ 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
- return NULL;
}
+ }
- // FIXME: Refactor this into BugReporterContext.
- const Stmt *S = 0;
- ProgramPoint P = N->getLocation();
+ if (os.str().empty()) {
+ if (isa<loc::ConcreteInt>(V)) {
+ bool b = false;
+ if (R->isBoundable()) {
+ if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) {
+ if (TR->getValueType()->isObjCObjectPointerType()) {
+ os << "nil object reference stored to ";
+ b = true;
+ }
+ }
+ }
- if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
- const CFGBlock *BSrc = BE->getSrc();
- S = BSrc->getTerminatorCondition();
+ if (!b)
+ os << "Null pointer value stored to ";
}
- else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) {
- S = PS->getStmt();
+ else if (V.isUndef()) {
+ os << "Uninitialized value stored to ";
}
-
- if (!S)
+ else if (isa<nonloc::ConcreteInt>(V)) {
+ os << "The value " << cast<nonloc::ConcreteInt>(V).getValue()
+ << " is assigned to ";
+ }
+ else
return NULL;
- // Construct a new PathDiagnosticPiece.
- PathDiagnosticLocation L(S, BRC.getSourceManager());
- return new PathDiagnosticEventPiece(L, os.str());
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+ os << '\'' << *VR->getDecl() << '\'';
+ }
+ else
+ return NULL;
}
-};
-
-static void registerFindLastStore(BugReporterContext& BRC, const MemRegion *R,
- SVal V) {
- BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
+ // Construct a new PathDiagnosticPiece.
+ ProgramPoint P = N->getLocation();
+ PathDiagnosticLocation L =
+ PathDiagnosticLocation::create(P, BRC.getSourceManager());
+ if (!L.isValid())
+ return NULL;
+ return new PathDiagnosticEventPiece(L, os.str());
}
-class TrackConstraintBRVisitor : public BugReporterVisitor {
- DefinedSVal Constraint;
- const bool Assumption;
- bool isSatisfied;
-public:
- TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
- : Constraint(constraint), Assumption(assumption), isSatisfied(false) {}
-
- void Profile(llvm::FoldingSetNodeID &ID) const {
- static int tag = 0;
- ID.AddPointer(&tag);
- ID.AddBoolean(Assumption);
- ID.Add(Constraint);
- }
-
- PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
- const ExplodedNode *PrevN,
- BugReporterContext& BRC) {
- 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)) {
-
- 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))
- 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);
+void TrackConstraintBRVisitor::Profile(llvm::FoldingSetNodeID &ID) const {
+ static int tag = 0;
+ ID.AddPointer(&tag);
+ ID.AddBoolean(Assumption);
+ ID.Add(Constraint);
+}
- if (isa<Loc>(Constraint)) {
- os << "Assuming pointer value is ";
- os << (Assumption ? "non-null" : "null");
- }
+PathDiagnosticPiece *
+TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+ if (isSatisfied)
+ return NULL;
- if (os.str().empty())
- return NULL;
+ // Check if in the previous state it was feasible for this constraint
+ // to *not* be true.
+ if (PrevN->getState()->assume(Constraint, !Assumption)) {
- // FIXME: Refactor this into BugReporterContext.
- const Stmt *S = 0;
- ProgramPoint P = N->getLocation();
+ isSatisfied = true;
- if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
- const CFGBlock *BSrc = BE->getSrc();
- S = BSrc->getTerminatorCondition();
- }
- else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) {
- S = PS->getStmt();
- }
+ // 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))
+ return NULL;
- if (!S)
- 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);
- // Construct a new PathDiagnosticPiece.
- PathDiagnosticLocation L(S, BRC.getSourceManager());
- return new PathDiagnosticEventPiece(L, os.str());
+ if (isa<Loc>(Constraint)) {
+ os << "Assuming pointer value is ";
+ os << (Assumption ? "non-null" : "null");
}
- return NULL;
+ if (os.str().empty())
+ return NULL;
+
+ // Construct a new PathDiagnosticPiece.
+ ProgramPoint P = N->getLocation();
+ PathDiagnosticLocation L =
+ PathDiagnosticLocation::create(P, BRC.getSourceManager());
+ if (!L.isValid())
+ return NULL;
+ return new PathDiagnosticEventPiece(L, os.str());
}
-};
-} // end anonymous namespace
-static void registerTrackConstraint(BugReporterContext& BRC,
- DefinedSVal Constraint,
- bool Assumption) {
- BRC.addVisitor(new TrackConstraintBRVisitor(Constraint, Assumption));
+ return NULL;
}
-void bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC,
- const void *data,
- const ExplodedNode* N) {
-
- const Stmt *S = static_cast<const Stmt*>(data);
-
- if (!S)
- return;
+BugReporterVisitor *
+bugreporter::getTrackNullOrUndefValueVisitor(const ExplodedNode *N,
+ const Stmt *S) {
+ if (!S || !N)
+ return 0;
+
+ ProgramStateManager &StateMgr = N->getState()->getStateManager();
+
+ // Walk through nodes until we get one that matches the statement
+ // exactly.
+ while (N) {
+ const ProgramPoint &pp = N->getLocation();
+ if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) {
+ if (ps->getStmt() == S)
+ break;
+ }
+ N = N->getFirstPred();
+ }
- GRStateManager &StateMgr = BRC.getStateManager();
- const GRState *state = N->getState();
+ if (!N)
+ return 0;
+
+ const ProgramState *state = N->getState();
// Walk through lvalue-to-rvalue conversions.
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S)) {
@@ -327,7 +334,7 @@ void bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC,
if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)
|| V.isUndef()) {
- ::registerFindLastStore(BRC, R, V);
+ return new FindLastStoreBRVisitor(V, R);
}
}
}
@@ -347,94 +354,73 @@ void bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC,
if (R) {
assert(isa<SymbolicRegion>(R));
- registerTrackConstraint(BRC, loc::MemRegionVal(R), false);
+ return new TrackConstraintBRVisitor(loc::MemRegionVal(R), false);
}
}
-}
-
-void bugreporter::registerFindLastStore(BugReporterContext& BRC,
- const void *data,
- const ExplodedNode* N) {
- const MemRegion *R = static_cast<const MemRegion*>(data);
+ return 0;
+}
- if (!R)
- return;
+BugReporterVisitor *
+FindLastStoreBRVisitor::createVisitorObject(const ExplodedNode *N,
+ const MemRegion *R) {
+ assert(R && "The memory region is null.");
- const GRState *state = N->getState();
+ const ProgramState *state = N->getState();
SVal V = state->getSVal(R);
-
if (V.isUnknown())
- return;
+ return 0;
- BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
+ return new FindLastStoreBRVisitor(V, R);
}
-namespace {
-class NilReceiverVisitor : public BugReporterVisitor {
-public:
- NilReceiverVisitor() {}
-
- void Profile(llvm::FoldingSetNodeID &ID) const {
- static int x = 0;
- ID.AddPointer(&x);
- }
-
- PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
- const ExplodedNode *PrevN,
- BugReporterContext& BRC) {
-
- const PostStmt *P = N->getLocationAs<PostStmt>();
- if (!P)
- return 0;
- const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>();
- if (!ME)
- return 0;
- const Expr *Receiver = ME->getInstanceReceiver();
- if (!Receiver)
- return 0;
- const GRState *state = N->getState();
- const SVal &V = state->getSVal(Receiver);
- 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::registerTrackNullOrUndefValue(BRC, Receiver, N);
- // Issue a message saying that the method was skipped.
- PathDiagnosticLocation L(Receiver, BRC.getSourceManager());
- return new PathDiagnosticEventPiece(L, "No method actually called "
- "because the receiver is nil");
- }
-};
-} // end anonymous namespace
-
-void bugreporter::registerNilReceiverVisitor(BugReporterContext &BRC) {
- BRC.addVisitor(new NilReceiverVisitor());
+PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+ const PostStmt *P = N->getLocationAs<PostStmt>();
+ if (!P)
+ return 0;
+ const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>();
+ if (!ME)
+ return 0;
+ const Expr *Receiver = ME->getInstanceReceiver();
+ if (!Receiver)
+ return 0;
+ const ProgramState *state = N->getState();
+ const SVal &V = state->getSVal(Receiver);
+ 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.
+ BR.addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Receiver));
+ // Issue a message saying that the method was skipped.
+ PathDiagnosticLocation L(Receiver, BRC.getSourceManager(),
+ N->getLocationContext());
+ return new PathDiagnosticEventPiece(L, "No method actually called "
+ "because the receiver is nil");
}
-// Registers every VarDecl inside a Stmt with a last store vistor.
-void bugreporter::registerVarDeclsLastStore(BugReporterContext &BRC,
- const void *stmt,
- const ExplodedNode *N) {
- const Stmt *S = static_cast<const Stmt *>(stmt);
-
+// Registers every VarDecl inside a Stmt with a last store visitor.
+void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR,
+ const Stmt *S) {
+ const ExplodedNode *N = BR.getErrorNode();
std::deque<const Stmt *> WorkList;
-
WorkList.push_back(S);
while (!WorkList.empty()) {
const Stmt *Head = WorkList.front();
WorkList.pop_front();
- GRStateManager &StateMgr = BRC.getStateManager();
- const GRState *state = N->getState();
+ const ProgramState *state = N->getState();
+ ProgramStateManager &StateMgr = state->getStateManager();
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Head)) {
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
@@ -445,7 +431,8 @@ void bugreporter::registerVarDeclsLastStore(BugReporterContext &BRC,
SVal V = state->getSVal(S);
if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)) {
- ::registerFindLastStore(BRC, R, V);
+ // Register a new visitor with the BugReport.
+ BR.addVisitor(new FindLastStoreBRVisitor(V, R));
}
}
}
@@ -455,3 +442,248 @@ void bugreporter::registerVarDeclsLastStore(BugReporterContext &BRC,
WorkList.push_back(*I);
}
}
+
+//===----------------------------------------------------------------------===//
+// Visitor that tries to report interesting diagnostics from conditions.
+//===----------------------------------------------------------------------===//
+PathDiagnosticPiece *ConditionBRVisitor::VisitNode(const ExplodedNode *N,
+ const ExplodedNode *Prev,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+
+ const ProgramPoint &progPoint = N->getLocation();
+
+ const ProgramState *CurrentState = N->getState();
+ const ProgramState *PrevState = Prev->getState();
+
+ // Compare the GDMs of the state, because that is where constraints
+ // are managed. Note that ensure that we only look at nodes that
+ // were generated by the analyzer engine proper, not checkers.
+ if (CurrentState->getGDM().getRoot() ==
+ PrevState->getGDM().getRoot())
+ return 0;
+
+ // 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)) {
+ const CFGBlock *srcBlk = BE->getSrc();
+ if (const Stmt *term = srcBlk->getTerminator())
+ return VisitTerminator(term, N, srcBlk, BE->getDst(), BRC);
+ return 0;
+ }
+
+ if (const PostStmt *PS = dyn_cast<PostStmt>(&progPoint)) {
+ // FIXME: Assuming that BugReporter is a GRBugReporter is a layering
+ // violation.
+ const std::pair<const ProgramPointTag *, const ProgramPointTag *> &tags =
+ cast<GRBugReporter>(BRC.getBugReporter()).
+ getEngine().getEagerlyAssumeTags();
+
+ const ProgramPointTag *tag = PS->getTag();
+ if (tag == tags.first)
+ return VisitTrueTest(cast<Expr>(PS->getStmt()), true,
+ BRC, N->getLocationContext());
+ if (tag == tags.second)
+ return VisitTrueTest(cast<Expr>(PS->getStmt()), false,
+ BRC, N->getLocationContext());
+
+ return 0;
+ }
+
+ return 0;
+}
+
+PathDiagnosticPiece *
+ConditionBRVisitor::VisitTerminator(const Stmt *Term,
+ const ExplodedNode *N,
+ const CFGBlock *srcBlk,
+ const CFGBlock *dstBlk,
+ BugReporterContext &BRC) {
+ const Expr *Cond = 0;
+
+ switch (Term->getStmtClass()) {
+ default:
+ return 0;
+ case Stmt::IfStmtClass:
+ Cond = cast<IfStmt>(Term)->getCond();
+ break;
+ case Stmt::ConditionalOperatorClass:
+ Cond = cast<ConditionalOperator>(Term)->getCond();
+ break;
+ }
+
+ assert(Cond);
+ assert(srcBlk->succ_size() == 2);
+ const bool tookTrue = *(srcBlk->succ_begin()) == dstBlk;
+ return VisitTrueTest(Cond->IgnoreParenNoopCasts(BRC.getASTContext()),
+ tookTrue, BRC, N->getLocationContext());
+}
+
+PathDiagnosticPiece *
+ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
+ bool tookTrue,
+ BugReporterContext &BRC,
+ const LocationContext *LC) {
+
+ const Expr *Ex = Cond;
+
+ while (true) {
+ Ex = Ex->IgnoreParens();
+ switch (Ex->getStmtClass()) {
+ default:
+ return 0;
+ case Stmt::BinaryOperatorClass:
+ return VisitTrueTest(Cond, cast<BinaryOperator>(Ex), tookTrue, BRC, LC);
+ case Stmt::DeclRefExprClass:
+ return VisitTrueTest(Cond, cast<DeclRefExpr>(Ex), tookTrue, BRC, LC);
+ case Stmt::UnaryOperatorClass: {
+ const UnaryOperator *UO = cast<UnaryOperator>(Ex);
+ if (UO->getOpcode() == UO_LNot) {
+ tookTrue = !tookTrue;
+ Ex = UO->getSubExpr()->IgnoreParenNoopCasts(BRC.getASTContext());
+ continue;
+ }
+ return 0;
+ }
+ }
+ }
+}
+
+bool ConditionBRVisitor::patternMatch(const Expr *Ex, llvm::raw_ostream &Out,
+ BugReporterContext &BRC) {
+ const Expr *OriginalExpr = Ex;
+ Ex = Ex->IgnoreParenCasts();
+
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) {
+ const bool quotes = isa<VarDecl>(DR->getDecl());
+ if (quotes)
+ Out << '\'';
+ Out << DR->getDecl()->getDeclName().getAsString();
+ if (quotes)
+ Out << '\'';
+ return quotes;
+ }
+
+ if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(Ex)) {
+ QualType OriginalTy = OriginalExpr->getType();
+ if (OriginalTy->isPointerType()) {
+ if (IL->getValue() == 0) {
+ Out << "null";
+ return false;
+ }
+ }
+ else if (OriginalTy->isObjCObjectPointerType()) {
+ if (IL->getValue() == 0) {
+ Out << "nil";
+ return false;
+ }
+ }
+
+ Out << IL->getValue();
+ return false;
+ }
+
+ return false;
+}
+
+PathDiagnosticPiece *
+ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
+ const BinaryOperator *BExpr,
+ const bool tookTrue,
+ BugReporterContext &BRC,
+ const LocationContext *LC) {
+
+ bool shouldInvert = false;
+
+ llvm::SmallString<128> LhsString, RhsString;
+ {
+ llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
+ const bool isVarLHS = patternMatch(BExpr->getLHS(), OutLHS, BRC);
+ const bool isVarRHS = patternMatch(BExpr->getRHS(), OutRHS, BRC);
+
+ shouldInvert = !isVarLHS && isVarRHS;
+ }
+
+ if (LhsString.empty() || RhsString.empty())
+ return 0;
+
+ // Should we invert the strings if the LHS is not a variable name?
+
+ llvm::SmallString<256> buf;
+ llvm::raw_svector_ostream Out(buf);
+ Out << "Assuming " << (shouldInvert ? RhsString : LhsString) << " is ";
+
+ // Do we need to invert the opcode?
+ BinaryOperator::Opcode Op = BExpr->getOpcode();
+
+ if (shouldInvert)
+ switch (Op) {
+ default: break;
+ case BO_LT: Op = BO_GT; break;
+ case BO_GT: Op = BO_LT; break;
+ case BO_LE: Op = BO_GE; break;
+ case BO_GE: Op = BO_LE; break;
+ }
+
+ if (!tookTrue)
+ switch (Op) {
+ case BO_EQ: Op = BO_NE; break;
+ case BO_NE: Op = BO_EQ; break;
+ case BO_LT: Op = BO_GE; break;
+ case BO_GT: Op = BO_LE; break;
+ case BO_LE: Op = BO_GT; break;
+ case BO_GE: Op = BO_LT; break;
+ default:
+ return 0;
+ }
+
+ switch (BExpr->getOpcode()) {
+ case BO_EQ:
+ Out << "equal to ";
+ break;
+ case BO_NE:
+ Out << "not equal to ";
+ break;
+ default:
+ Out << BinaryOperator::getOpcodeStr(Op) << ' ';
+ break;
+ }
+
+ Out << (shouldInvert ? LhsString : RhsString);
+
+ PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LC);
+ return new PathDiagnosticEventPiece(Loc, Out.str());
+}
+
+PathDiagnosticPiece *
+ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
+ const DeclRefExpr *DR,
+ const bool tookTrue,
+ BugReporterContext &BRC,
+ const LocationContext *LC) {
+
+ const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
+ if (!VD)
+ return 0;
+
+ llvm::SmallString<256> Buf;
+ llvm::raw_svector_ostream Out(Buf);
+
+ Out << "Assuming '";
+ VD->getDeclName().printName(Out);
+ Out << "' is ";
+
+ QualType VDTy = VD->getType();
+
+ if (VDTy->isPointerType())
+ Out << (tookTrue ? "non-null" : "null");
+ else if (VDTy->isObjCObjectPointerType())
+ Out << (tookTrue ? "non-nil" : "nil");
+ else if (VDTy->isScalarType())
+ Out << (tookTrue ? "not equal to 0" : "0");
+ else
+ return 0;
+
+ PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LC);
+ return new PathDiagnosticEventPiece(Loc, Out.str());
+}
diff --git a/lib/StaticAnalyzer/Core/CMakeLists.txt b/lib/StaticAnalyzer/Core/CMakeLists.txt
index 089a5cc39037..391a781ab09d 100644
--- a/lib/StaticAnalyzer/Core/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Core/CMakeLists.txt
@@ -6,34 +6,36 @@ add_clang_library(clangStaticAnalyzerCore
AggExprVisitor.cpp
AnalysisManager.cpp
BasicConstraintManager.cpp
- BasicStore.cpp
BasicValueFactory.cpp
BlockCounter.cpp
BugReporter.cpp
BugReporterVisitors.cpp
- CFRefCount.cpp
- CXXExprEngine.cpp
+ Checker.cpp
CheckerContext.cpp
CheckerHelpers.cpp
CheckerManager.cpp
+ CheckerRegistry.cpp
CoreEngine.cpp
Environment.cpp
ExplodedGraph.cpp
ExprEngine.cpp
- FlatStore.cpp
- GRState.cpp
+ ExprEngineC.cpp
+ ExprEngineCXX.cpp
+ ExprEngineCallAndReturn.cpp
+ ExprEngineObjC.cpp
HTMLDiagnostics.cpp
MemRegion.cpp
ObjCMessage.cpp
PathDiagnostic.cpp
PlistDiagnostics.cpp
+ ProgramState.cpp
RangeConstraintManager.cpp
RegionStore.cpp
+ SValBuilder.cpp
+ SVals.cpp
SimpleConstraintManager.cpp
SimpleSValBuilder.cpp
Store.cpp
- SValBuilder.cpp
- SVals.cpp
SymbolManager.cpp
TextPathDiagnostics.cpp
)
diff --git a/lib/StaticAnalyzer/Core/Checker.cpp b/lib/StaticAnalyzer/Core/Checker.cpp
new file mode 100644
index 000000000000..a3bf2c236f6e
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/Checker.cpp
@@ -0,0 +1,22 @@
+//== Checker.cpp - Registration mechanism for checkers -----------*- 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 Checker, used to create and register checkers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/Checker.h"
+
+using namespace clang;
+using namespace ento;
+
+StringRef CheckerBase::getTagDescription() const {
+ // FIXME: We want to return the package + name of the checker here.
+ return "A Checker";
+}
diff --git a/lib/StaticAnalyzer/Core/CheckerContext.cpp b/lib/StaticAnalyzer/Core/CheckerContext.cpp
index f6fb8f256c01..5356edc752fa 100644
--- a/lib/StaticAnalyzer/Core/CheckerContext.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerContext.cpp
@@ -23,8 +23,8 @@ CheckerContext::~CheckerContext() {
// if we are building sinks or we generated a node and decided to not
// add it as a transition.
if (Dst.size() == size && !B.BuildSinks && !B.hasGeneratedNode) {
- if (ST && ST != B.GetState(Pred)) {
- static int autoTransitionTag = 0;
+ if (ST && ST != Pred->getState()) {
+ static SimpleProgramPointTag autoTransitionTag("CheckerContext : auto");
addTransition(ST, &autoTransitionTag);
}
else
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index ba7c384e5c36..acacfb0e18c6 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -12,8 +12,9 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/CheckerProvider.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/AST/DeclBase.h"
@@ -33,7 +34,8 @@ bool CheckerManager::hasPathSensitiveCheckers() const {
!DeadSymbolsCheckers.empty() ||
!RegionChangesCheckers.empty() ||
!EvalAssumeCheckers.empty() ||
- !EvalCallCheckers.empty();
+ !EvalCallCheckers.empty() ||
+ !InlineCallCheckers.empty();
}
void CheckerManager::finishedCheckerRegistration() {
@@ -122,7 +124,7 @@ static void expandGraphWithCheckers(CHECK_CTX checkCtx,
namespace {
struct CheckStmtContext {
- typedef llvm::SmallVectorImpl<CheckerManager::CheckStmtFunc> CheckersTy;
+ typedef SmallVectorImpl<CheckerManager::CheckStmtFunc> CheckersTy;
bool IsPreVisit;
const CheckersTy &Checkers;
const Stmt *S;
@@ -138,9 +140,12 @@ namespace {
void runChecker(CheckerManager::CheckStmtFunc checkFn,
ExplodedNodeSet &Dst, ExplodedNode *Pred) {
// FIXME: Remove respondsToCallback from CheckerContext;
- CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker,
- IsPreVisit ? ProgramPoint::PreStmtKind :
- ProgramPoint::PostStmtKind, 0, S);
+ ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind :
+ ProgramPoint::PostStmtKind;
+ const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
+ Pred->getLocationContext(), checkFn.Checker);
+ CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
+
checkFn(S, C);
}
};
@@ -174,10 +179,12 @@ namespace {
void runChecker(CheckerManager::CheckObjCMessageFunc checkFn,
ExplodedNodeSet &Dst, ExplodedNode *Pred) {
- CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker,
- IsPreVisit ? ProgramPoint::PreStmtKind :
- ProgramPoint::PostStmtKind, 0,
- Msg.getOriginExpr());
+ ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind :
+ ProgramPoint::PostStmtKind;
+ const ProgramPoint &L = ProgramPoint::getProgramPoint(Msg.getOriginExpr(),
+ K, Pred->getLocationContext(), checkFn.Checker);
+ CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
+
checkFn(Msg, C);
}
};
@@ -214,10 +221,13 @@ namespace {
void runChecker(CheckerManager::CheckLocationFunc checkFn,
ExplodedNodeSet &Dst, ExplodedNode *Pred) {
- CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker,
- IsLoad ? ProgramPoint::PreLoadKind :
- ProgramPoint::PreStoreKind, 0, S);
- checkFn(Loc, IsLoad, C);
+ ProgramPoint::Kind K = IsLoad ? ProgramPoint::PreLoadKind :
+ ProgramPoint::PreStoreKind;
+ const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
+ Pred->getLocationContext(), checkFn.Checker);
+ CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
+
+ checkFn(Loc, IsLoad, S, C);
}
};
}
@@ -249,9 +259,12 @@ namespace {
void runChecker(CheckerManager::CheckBindFunc checkFn,
ExplodedNodeSet &Dst, ExplodedNode *Pred) {
- CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker,
- ProgramPoint::PreStmtKind, 0, S);
- checkFn(Loc, Val, C);
+ ProgramPoint::Kind K = ProgramPoint::PreStmtKind;
+ const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
+ Pred->getLocationContext(), checkFn.Checker);
+ CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
+
+ checkFn(Loc, Val, S, C);
}
};
}
@@ -293,7 +306,7 @@ void CheckerManager::runCheckersForBranchCondition(const Stmt *condition,
}
/// \brief Run checkers for live symbols.
-void CheckerManager::runCheckersForLiveSymbols(const GRState *state,
+void CheckerManager::runCheckersForLiveSymbols(const ProgramState *state,
SymbolReaper &SymReaper) {
for (unsigned i = 0, e = LiveSymbolsCheckers.size(); i != e; ++i)
LiveSymbolsCheckers[i](state, SymReaper);
@@ -316,8 +329,11 @@ namespace {
void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn,
ExplodedNodeSet &Dst, ExplodedNode *Pred) {
- CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker,
- ProgramPoint::PostPurgeDeadSymbolsKind, 0, S);
+ ProgramPoint::Kind K = ProgramPoint::PostPurgeDeadSymbolsKind;
+ const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
+ Pred->getLocationContext(), checkFn.Checker);
+ CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
+
checkFn(SR, C);
}
};
@@ -334,7 +350,7 @@ void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst,
}
/// \brief True if at least one checker wants to check region changes.
-bool CheckerManager::wantsRegionChangeUpdate(const GRState *state) {
+bool CheckerManager::wantsRegionChangeUpdate(const ProgramState *state) {
for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i)
if (RegionChangesCheckers[i].WantUpdateFn(state))
return true;
@@ -343,24 +359,25 @@ bool CheckerManager::wantsRegionChangeUpdate(const GRState *state) {
}
/// \brief Run checkers for region changes.
-const GRState *
-CheckerManager::runCheckersForRegionChanges(const GRState *state,
+const ProgramState *
+CheckerManager::runCheckersForRegionChanges(const ProgramState *state,
const StoreManager::InvalidatedSymbols *invalidated,
- const MemRegion * const *Begin,
- const MemRegion * const *End) {
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions) {
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.
if (!state)
return NULL;
- state = RegionChangesCheckers[i].CheckFn(state, invalidated, Begin, End);
+ state = RegionChangesCheckers[i].CheckFn(state, invalidated,
+ ExplicitRegions, Regions);
}
return state;
}
/// \brief Run checkers for handling assumptions on symbolic values.
-const GRState *
-CheckerManager::runCheckersForEvalAssume(const GRState *state,
+const ProgramState *
+CheckerManager::runCheckersForEvalAssume(const ProgramState *state,
SVal Cond, bool Assumption) {
for (unsigned i = 0, e = EvalAssumeCheckers.size(); i != e; ++i) {
// If any checker declares the state infeasible (or if it starts that way),
@@ -379,7 +396,9 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
const CallExpr *CE,
ExprEngine &Eng,
GraphExpander *defaultEval) {
- if (EvalCallCheckers.empty() && defaultEval == 0) {
+ if (EvalCallCheckers.empty() &&
+ InlineCallCheckers.empty() &&
+ defaultEval == 0) {
Dst.insert(Src);
return;
}
@@ -389,13 +408,50 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
ExplodedNode *Pred = *NI;
bool anyEvaluated = false;
+
+ // First, check if any of the InlineCall callbacks can evaluate the call.
+ assert(InlineCallCheckers.size() <= 1 &&
+ "InlineCall is a special hacky callback to allow intrusive"
+ "evaluation of the call (which simulates inlining). It is "
+ "currently only used by OSAtomicChecker and should go away "
+ "at some point.");
+ for (std::vector<InlineCallFunc>::iterator
+ EI = InlineCallCheckers.begin(), EE = InlineCallCheckers.end();
+ EI != EE; ++EI) {
+ ExplodedNodeSet checkDst;
+ bool evaluated = (*EI)(CE, Eng, Pred, checkDst);
+ assert(!(evaluated && anyEvaluated)
+ && "There are more than one checkers evaluating the call");
+ if (evaluated) {
+ anyEvaluated = true;
+ Dst.insert(checkDst);
+#ifdef NDEBUG
+ break; // on release don't check that no other checker also evals.
+#endif
+ }
+ }
+
+#ifdef NDEBUG // on release don't check that no other checker also evals.
+ if (anyEvaluated) {
+ break;
+ }
+#endif
+
+ // Next, check if any of the EvalCall callbacks can evaluate the call.
for (std::vector<EvalCallFunc>::iterator
EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end();
EI != EE; ++EI) {
ExplodedNodeSet checkDst;
- CheckerContext C(checkDst, Eng.getBuilder(), Eng, Pred, EI->Checker,
- ProgramPoint::PostStmtKind, 0, CE);
- bool evaluated = (*EI)(CE, C);
+ ProgramPoint::Kind K = ProgramPoint::PostStmtKind;
+ const ProgramPoint &L = ProgramPoint::getProgramPoint(CE, K,
+ Pred->getLocationContext(), EI->Checker);
+ bool evaluated = false;
+ { // CheckerContext generates transitions(populates checkDest) on
+ // destruction, so introduce the scope to make sure it gets properly
+ // populated.
+ CheckerContext C(checkDst, Eng.getBuilder(), Eng, Pred, L, 0);
+ evaluated = (*EI)(CE, C);
+ }
assert(!(evaluated && anyEvaluated)
&& "There are more than one checkers evaluating the call");
if (evaluated) {
@@ -407,6 +463,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
}
}
+ // If none of the checkers evaluated the call, ask ExprEngine to handle it.
if (!anyEvaluated) {
if (defaultEval)
defaultEval->expandGraph(Dst, Pred);
@@ -425,6 +482,14 @@ void CheckerManager::runCheckersOnEndOfTranslationUnit(
EndOfTranslationUnitCheckers[i](TU, mgr, BR);
}
+void CheckerManager::runCheckersForPrintState(raw_ostream &Out,
+ const ProgramState *State,
+ const char *NL, const char *Sep) {
+ for (llvm::DenseMap<CheckerTag, CheckerRef>::iterator
+ I = CheckerTags.begin(), E = CheckerTags.end(); I != E; ++I)
+ I->second->printState(Out, State, NL, Sep);
+}
+
//===----------------------------------------------------------------------===//
// Internal registration functions for AST traversing.
//===----------------------------------------------------------------------===//
@@ -504,6 +569,10 @@ void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) {
EvalCallCheckers.push_back(checkfn);
}
+void CheckerManager::_registerForInlineCall(InlineCallFunc checkfn) {
+ InlineCallCheckers.push_back(checkfn);
+}
+
void CheckerManager::_registerForEndOfTranslationUnit(
CheckEndOfTranslationUnit checkfn) {
EndOfTranslationUnitCheckers.push_back(checkfn);
@@ -542,7 +611,4 @@ CheckerManager::~CheckerManager() {
}
// Anchor for the vtable.
-CheckerProvider::~CheckerProvider() { }
-
-// Anchor for the vtable.
GraphExpander::~GraphExpander() { }
diff --git a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
new file mode 100644
index 000000000000..13401acf3da9
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
@@ -0,0 +1,149 @@
+//===--- CheckerRegistry.cpp - Maintains all available checkers -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
+#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
+
+using namespace clang;
+using namespace ento;
+
+static const char PackageSeparator = '.';
+typedef llvm::DenseSet<const CheckerRegistry::CheckerInfo *> CheckerInfoSet;
+
+
+static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a,
+ const CheckerRegistry::CheckerInfo &b) {
+ return a.FullName < b.FullName;
+}
+
+static bool isInPackage(const CheckerRegistry::CheckerInfo &checker,
+ StringRef packageName) {
+ // Does the checker's full name have the package as a prefix?
+ if (!checker.FullName.startswith(packageName))
+ return false;
+
+ // Is the package actually just the name of a specific checker?
+ if (checker.FullName.size() == packageName.size())
+ return true;
+
+ // Is the checker in the package (or a subpackage)?
+ if (checker.FullName[packageName.size()] == PackageSeparator)
+ return true;
+
+ return false;
+}
+
+static void collectCheckers(const CheckerRegistry::CheckerInfoList &checkers,
+ const llvm::StringMap<size_t> &packageSizes,
+ CheckerOptInfo &opt, CheckerInfoSet &collected) {
+ // Use a binary search to find the possible start of the package.
+ CheckerRegistry::CheckerInfo packageInfo(NULL, opt.getName(), "");
+ CheckerRegistry::CheckerInfoList::const_iterator e = checkers.end();
+ CheckerRegistry::CheckerInfoList::const_iterator i =
+ std::lower_bound(checkers.begin(), e, packageInfo, checkerNameLT);
+
+ // If we didn't even find a possible package, give up.
+ if (i == e)
+ return;
+
+ // If what we found doesn't actually start the package, give up.
+ if (!isInPackage(*i, opt.getName()))
+ return;
+
+ // There is at least one checker in the package; claim the option.
+ opt.claim();
+
+ // See how large the package is.
+ // If the package doesn't exist, assume the option refers to a single checker.
+ size_t size = 1;
+ llvm::StringMap<size_t>::const_iterator packageSize =
+ packageSizes.find(opt.getName());
+ if (packageSize != packageSizes.end())
+ size = packageSize->getValue();
+
+ // Step through all the checkers in the package.
+ for (e = i+size; i != e; ++i) {
+ if (opt.isEnabled())
+ collected.insert(&*i);
+ else
+ collected.erase(&*i);
+ }
+}
+
+void CheckerRegistry::addChecker(InitializationFunction fn, StringRef name,
+ StringRef desc) {
+ Checkers.push_back(CheckerInfo(fn, name, desc));
+
+ // Record the presence of the checker in its packages.
+ StringRef packageName, leafName;
+ llvm::tie(packageName, leafName) = name.rsplit(PackageSeparator);
+ while (!leafName.empty()) {
+ Packages[packageName] += 1;
+ llvm::tie(packageName, leafName) = packageName.rsplit(PackageSeparator);
+ }
+}
+
+void CheckerRegistry::initializeManager(CheckerManager &checkerMgr,
+ SmallVectorImpl<CheckerOptInfo> &opts) const {
+ // Sort checkers for efficient collection.
+ std::sort(Checkers.begin(), Checkers.end(), checkerNameLT);
+
+ // Collect checkers enabled by the options.
+ CheckerInfoSet enabledCheckers;
+ for (SmallVectorImpl<CheckerOptInfo>::iterator
+ i = opts.begin(), e = opts.end(); i != e; ++i) {
+ collectCheckers(Checkers, Packages, *i, enabledCheckers);
+ }
+
+ // Initialize the CheckerManager with all enabled checkers.
+ for (CheckerInfoSet::iterator
+ i = enabledCheckers.begin(), e = enabledCheckers.end(); i != e; ++i) {
+ (*i)->Initialize(checkerMgr);
+ }
+}
+
+void CheckerRegistry::printHelp(llvm::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
+ // that's ASCIIbetically last?
+ std::sort(Checkers.begin(), Checkers.end(), checkerNameLT);
+
+ // FIXME: Print available packages.
+
+ out << "CHECKERS:\n";
+
+ // Find the maximum option length.
+ size_t optionFieldWidth = 0;
+ for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end();
+ i != e; ++i) {
+ // Limit the amount of padding we are willing to give up for alignment.
+ // Package.Name Description [Hidden]
+ size_t nameLength = i->FullName.size();
+ if (nameLength <= maxNameChars)
+ optionFieldWidth = std::max(optionFieldWidth, nameLength);
+ }
+
+ const size_t initialPad = 2;
+ for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end();
+ i != e; ++i) {
+ out.indent(initialPad) << i->FullName;
+
+ int pad = optionFieldWidth - i->FullName.size();
+
+ // Break on long option names.
+ if (pad < 0) {
+ out << '\n';
+ pad = optionFieldWidth + initialPad;
+ }
+ out.indent(pad + 2) << i->Desc;
+
+ out << '\n';
+ }
+}
diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp
index 34cd6e8884a0..525219846a93 100644
--- a/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -17,22 +17,12 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/Index/TranslationUnit.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/StmtCXX.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/DenseMap.h"
-
-using llvm::cast;
-using llvm::isa;
using namespace clang;
using namespace ento;
-// This should be removed in the future.
-namespace clang {
-namespace ento {
-TransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
- const LangOptions& lopts);
-}
-}
-
//===----------------------------------------------------------------------===//
// Worklist classes for exploration of reachable states.
//===----------------------------------------------------------------------===//
@@ -41,7 +31,7 @@ WorkList::Visitor::~Visitor() {}
namespace {
class DFS : public WorkList {
- llvm::SmallVector<WorkListUnit,20> Stack;
+ SmallVector<WorkListUnit,20> Stack;
public:
virtual bool hasWork() const {
return !Stack.empty();
@@ -59,7 +49,7 @@ public:
}
virtual bool visitItemsInWorkList(Visitor &V) {
- for (llvm::SmallVectorImpl<WorkListUnit>::iterator
+ for (SmallVectorImpl<WorkListUnit>::iterator
I = Stack.begin(), E = Stack.end(); I != E; ++I) {
if (V.visit(*I))
return true;
@@ -107,7 +97,7 @@ WorkList *WorkList::makeBFS() { return new BFS(); }
namespace {
class BFSBlockDFSContents : public WorkList {
std::deque<WorkListUnit> Queue;
- llvm::SmallVector<WorkListUnit,20> Stack;
+ SmallVector<WorkListUnit,20> Stack;
public:
virtual bool hasWork() const {
return !Queue.empty() || !Stack.empty();
@@ -136,7 +126,7 @@ namespace {
return U;
}
virtual bool visitItemsInWorkList(Visitor &V) {
- for (llvm::SmallVectorImpl<WorkListUnit>::iterator
+ for (SmallVectorImpl<WorkListUnit>::iterator
I = Stack.begin(), E = Stack.end(); I != E; ++I) {
if (V.visit(*I))
return true;
@@ -162,12 +152,12 @@ WorkList* WorkList::makeBFSBlockDFSContents() {
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps,
- const GRState *InitState) {
+ const ProgramState *InitState) {
if (G->num_roots() == 0) { // Initialize the analysis by constructing
// the root if none exists.
- const CFGBlock* Entry = &(L->getCFG()->getEntry());
+ const CFGBlock *Entry = &(L->getCFG()->getEntry());
assert (Entry->empty() &&
"Entry block must be empty.");
@@ -176,7 +166,7 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps,
"Entry block must have 1 successor.");
// Get the solitary successor.
- const CFGBlock* Succ = *(Entry->succ_begin());
+ const CFGBlock *Succ = *(Entry->succ_begin());
// Construct an edge representing the
// starting location in the function.
@@ -208,7 +198,7 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps,
WList->setBlockCounter(WU.getBlockCounter());
// Retrieve the node.
- ExplodedNode* Node = WU.getNode();
+ ExplodedNode *Node = WU.getNode();
// Dispatch on the location type.
switch (Node->getLocation().getKind()) {
@@ -246,11 +236,11 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps,
}
void CoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L,
- unsigned Steps,
- const GRState *InitState,
- ExplodedNodeSet &Dst) {
+ unsigned Steps,
+ const ProgramState *InitState,
+ ExplodedNodeSet &Dst) {
ExecuteWorkList(L, Steps, InitState);
- for (llvm::SmallVectorImpl<ExplodedNode*>::iterator I = G->EndNodes.begin(),
+ for (SmallVectorImpl<ExplodedNode*>::iterator I = G->EndNodes.begin(),
E = G->EndNodes.end(); I != E; ++I) {
Dst.Add(*I);
}
@@ -268,9 +258,9 @@ void CoreEngine::HandleCallExit(const CallExit &L, ExplodedNode *Pred) {
SubEng.processCallExit(Builder);
}
-void CoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) {
+void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
- const CFGBlock* Blk = L.getDst();
+ const CFGBlock *Blk = L.getDst();
// Check if we are entering the EXIT block.
if (Blk == &(L.getLocationContext()->getCFG()->getExit())) {
@@ -305,15 +295,15 @@ void CoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) {
}
}
- for (llvm::SmallVectorImpl<ExplodedNode*>::const_iterator
+ for (SmallVectorImpl<ExplodedNode*>::const_iterator
I = nodeBuilder.sinks().begin(), E = nodeBuilder.sinks().end();
I != E; ++I) {
blocksExhausted.push_back(std::make_pair(L, *I));
}
}
-void CoreEngine::HandleBlockEntrance(const BlockEntrance& L,
- ExplodedNode* Pred) {
+void CoreEngine::HandleBlockEntrance(const BlockEntrance &L,
+ ExplodedNode *Pred) {
// Increment the block counter.
BlockCounter Counter = WList->getBlockCounter();
@@ -324,21 +314,19 @@ void CoreEngine::HandleBlockEntrance(const BlockEntrance& L,
// Process the entrance of the block.
if (CFGElement E = L.getFirstElement()) {
- StmtNodeBuilder Builder(L.getBlock(), 0, Pred, this,
- SubEng.getStateManager());
+ StmtNodeBuilder Builder(L.getBlock(), 0, Pred, this);
SubEng.processCFGElement(E, Builder);
}
else
HandleBlockExit(L.getBlock(), Pred);
}
-void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode* Pred) {
+void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
- if (const Stmt* Term = B->getTerminator()) {
+ if (const Stmt *Term = B->getTerminator()) {
switch (Term->getStmtClass()) {
default:
- assert(false && "Analysis for this terminator not implemented.");
- break;
+ llvm_unreachable("Analysis for this terminator not implemented.");
case Stmt::BinaryOperatorClass: // '&&' and '||'
HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred);
@@ -361,6 +349,10 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode* Pred) {
HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred);
return;
+ case Stmt::CXXForRangeStmtClass:
+ HandleBranch(cast<CXXForRangeStmt>(Term)->getCond(), Term, B, Pred);
+ return;
+
case Stmt::ForStmtClass:
HandleBranch(cast<ForStmt>(Term)->getCond(), Term, B, Pred);
return;
@@ -422,34 +414,34 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode* Pred) {
Pred->State, Pred);
}
-void CoreEngine::HandleBranch(const Stmt* Cond, const Stmt* Term,
- const CFGBlock * B, ExplodedNode* Pred) {
+void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term,
+ const CFGBlock * B, ExplodedNode *Pred) {
assert(B->succ_size() == 2);
BranchNodeBuilder Builder(B, *(B->succ_begin()), *(B->succ_begin()+1),
Pred, this);
SubEng.processBranch(Cond, Term, Builder);
}
-void CoreEngine::HandlePostStmt(const CFGBlock* B, unsigned StmtIdx,
- ExplodedNode* Pred) {
+void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx,
+ ExplodedNode *Pred) {
assert (!B->empty());
if (StmtIdx == B->size())
HandleBlockExit(B, Pred);
else {
- StmtNodeBuilder Builder(B, StmtIdx, Pred, this,
- SubEng.getStateManager());
+ StmtNodeBuilder Builder(B, StmtIdx, Pred, this);
SubEng.processCFGElement((*B)[StmtIdx], Builder);
}
}
/// generateNode - Utility method to generate nodes, hook up successors,
/// and add nodes to the worklist.
-void CoreEngine::generateNode(const ProgramPoint& Loc,
- const GRState* State, ExplodedNode* Pred) {
+void CoreEngine::generateNode(const ProgramPoint &Loc,
+ const ProgramState *State,
+ ExplodedNode *Pred) {
bool IsNew;
- ExplodedNode* Node = G->getNode(Loc, State, &IsNew);
+ ExplodedNode *Node = G->getNode(Loc, State, &IsNew);
if (Pred)
Node->addPredecessor(Pred, *G); // Link 'Node' with its predecessor.
@@ -463,7 +455,7 @@ void CoreEngine::generateNode(const ProgramPoint& Loc,
}
ExplodedNode *
-GenericNodeBuilderImpl::generateNodeImpl(const GRState *state,
+GenericNodeBuilderImpl::generateNodeImpl(const ProgramState *state,
ExplodedNode *pred,
ProgramPoint programPoint,
bool asSink) {
@@ -483,14 +475,14 @@ GenericNodeBuilderImpl::generateNodeImpl(const GRState *state,
return 0;
}
-StmtNodeBuilder::StmtNodeBuilder(const CFGBlock* b, unsigned idx,
- ExplodedNode* N, CoreEngine* e,
- GRStateManager &mgr)
- : Eng(*e), B(*b), Idx(idx), Pred(N), Mgr(mgr),
+StmtNodeBuilder::StmtNodeBuilder(const CFGBlock *b,
+ unsigned idx,
+ ExplodedNode *N,
+ CoreEngine* e)
+ : Eng(*e), B(*b), Idx(idx), Pred(N),
PurgingDeadSymbols(false), BuildSinks(false), hasGeneratedNode(false),
PointKind(ProgramPoint::PostStmtKind), Tag(0) {
Deferred.insert(N);
- CleanedState = Pred->getState();
}
StmtNodeBuilder::~StmtNodeBuilder() {
@@ -499,7 +491,7 @@ StmtNodeBuilder::~StmtNodeBuilder() {
GenerateAutoTransition(*I);
}
-void StmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) {
+void StmtNodeBuilder::GenerateAutoTransition(ExplodedNode *N) {
assert (!N->isSink());
// Check if this node entered a callee.
@@ -526,18 +518,20 @@ void StmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) {
}
bool IsNew;
- ExplodedNode* Succ = Eng.G->getNode(Loc, N->State, &IsNew);
+ ExplodedNode *Succ = Eng.G->getNode(Loc, N->State, &IsNew);
Succ->addPredecessor(N, *Eng.G);
if (IsNew)
Eng.WList->enqueue(Succ, &B, Idx+1);
}
-ExplodedNode* StmtNodeBuilder::MakeNode(ExplodedNodeSet& Dst, const Stmt* S,
- ExplodedNode* Pred, const GRState* St,
- ProgramPoint::Kind K) {
+ExplodedNode *StmtNodeBuilder::MakeNode(ExplodedNodeSet &Dst,
+ const Stmt *S,
+ ExplodedNode *Pred,
+ const ProgramState *St,
+ ProgramPoint::Kind K) {
- ExplodedNode* N = generateNode(S, St, Pred, K);
+ ExplodedNode *N = generateNode(S, St, Pred, K);
if (N) {
if (BuildSinks)
@@ -549,46 +543,24 @@ ExplodedNode* StmtNodeBuilder::MakeNode(ExplodedNodeSet& Dst, const Stmt* S,
return N;
}
-static ProgramPoint GetProgramPoint(const Stmt *S, ProgramPoint::Kind K,
- const LocationContext *LC, const void *tag){
- switch (K) {
- default:
- assert(false && "Unhandled ProgramPoint kind");
- case ProgramPoint::PreStmtKind:
- return PreStmt(S, LC, tag);
- case ProgramPoint::PostStmtKind:
- return PostStmt(S, LC, tag);
- case ProgramPoint::PreLoadKind:
- return PreLoad(S, LC, tag);
- case ProgramPoint::PostLoadKind:
- return PostLoad(S, LC, tag);
- case ProgramPoint::PreStoreKind:
- return PreStore(S, LC, tag);
- case ProgramPoint::PostStoreKind:
- return PostStore(S, LC, tag);
- case ProgramPoint::PostLValueKind:
- return PostLValue(S, LC, tag);
- case ProgramPoint::PostPurgeDeadSymbolsKind:
- return PostPurgeDeadSymbols(S, LC, tag);
- }
-}
-
ExplodedNode*
-StmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* state,
- ExplodedNode* Pred,
- ProgramPoint::Kind K,
- const void *tag) {
+StmtNodeBuilder::generateNodeInternal(const Stmt *S,
+ const ProgramState *state,
+ ExplodedNode *Pred,
+ ProgramPoint::Kind K,
+ const ProgramPointTag *tag) {
- const ProgramPoint &L = GetProgramPoint(S, K, Pred->getLocationContext(),tag);
+ const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
+ Pred->getLocationContext(), tag);
return generateNodeInternal(L, state, Pred);
}
ExplodedNode*
StmtNodeBuilder::generateNodeInternal(const ProgramPoint &Loc,
- const GRState* State,
- ExplodedNode* Pred) {
+ const ProgramState *State,
+ ExplodedNode *Pred) {
bool IsNew;
- ExplodedNode* N = Eng.G->getNode(Loc, State, &IsNew);
+ ExplodedNode *N = Eng.G->getNode(Loc, State, &IsNew);
N->addPredecessor(Pred, *Eng.G);
Deferred.erase(Pred);
@@ -601,11 +573,11 @@ StmtNodeBuilder::generateNodeInternal(const ProgramPoint &Loc,
}
// This function generate a new ExplodedNode but not a new branch(block edge).
-ExplodedNode* BranchNodeBuilder::generateNode(const Stmt* Condition,
- const GRState* State) {
+ExplodedNode *BranchNodeBuilder::generateNode(const Stmt *Condition,
+ const ProgramState *State) {
bool IsNew;
- ExplodedNode* Succ
+ ExplodedNode *Succ
= Eng.G->getNode(PostCondition(Condition, Pred->getLocationContext()), State,
&IsNew);
@@ -619,8 +591,8 @@ ExplodedNode* BranchNodeBuilder::generateNode(const Stmt* Condition,
return NULL;
}
-ExplodedNode* BranchNodeBuilder::generateNode(const GRState* State,
- bool branch) {
+ExplodedNode *BranchNodeBuilder::generateNode(const ProgramState *State,
+ bool branch) {
// If the branch has been marked infeasible we should not generate a node.
if (!isFeasible(branch))
@@ -628,7 +600,7 @@ ExplodedNode* BranchNodeBuilder::generateNode(const GRState* State,
bool IsNew;
- ExplodedNode* Succ =
+ ExplodedNode *Succ =
Eng.G->getNode(BlockEdge(Src,branch ? DstT:DstF,Pred->getLocationContext()),
State, &IsNew);
@@ -657,11 +629,12 @@ BranchNodeBuilder::~BranchNodeBuilder() {
ExplodedNode*
-IndirectGotoNodeBuilder::generateNode(const iterator& I, const GRState* St,
- bool isSink) {
+IndirectGotoNodeBuilder::generateNode(const iterator &I,
+ const ProgramState *St,
+ bool isSink) {
bool IsNew;
- ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(),
+ ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(),
Pred->getLocationContext()), St, &IsNew);
Succ->addPredecessor(Pred, *Eng.G);
@@ -681,34 +654,38 @@ IndirectGotoNodeBuilder::generateNode(const iterator& I, const GRState* St,
ExplodedNode*
-SwitchNodeBuilder::generateCaseStmtNode(const iterator& I, const GRState* St){
+SwitchNodeBuilder::generateCaseStmtNode(const iterator &I,
+ const ProgramState *St) {
bool IsNew;
-
- ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(),
- Pred->getLocationContext()), St, &IsNew);
+ ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(),
+ Pred->getLocationContext()),
+ St, &IsNew);
Succ->addPredecessor(Pred, *Eng.G);
-
if (IsNew) {
Eng.WList->enqueue(Succ);
return Succ;
}
-
return NULL;
}
ExplodedNode*
-SwitchNodeBuilder::generateDefaultCaseNode(const GRState* St, bool isSink) {
-
+SwitchNodeBuilder::generateDefaultCaseNode(const ProgramState *St,
+ bool isSink) {
// Get the block for the default case.
- assert (Src->succ_rbegin() != Src->succ_rend());
- CFGBlock* DefaultBlock = *Src->succ_rbegin();
+ assert(Src->succ_rbegin() != Src->succ_rend());
+ CFGBlock *DefaultBlock = *Src->succ_rbegin();
+ // Sanity check for default blocks that are unreachable and not caught
+ // by earlier stages.
+ if (!DefaultBlock)
+ return NULL;
+
bool IsNew;
- ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, DefaultBlock,
- Pred->getLocationContext()), St, &IsNew);
+ ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, DefaultBlock,
+ Pred->getLocationContext()), St, &IsNew);
Succ->addPredecessor(Pred, *Eng.G);
if (IsNew) {
@@ -735,12 +712,13 @@ EndOfFunctionNodeBuilder::~EndOfFunctionNodeBuilder() {
}
ExplodedNode*
-EndOfFunctionNodeBuilder::generateNode(const GRState* State,
- ExplodedNode* P, const void *tag) {
+EndOfFunctionNodeBuilder::generateNode(const ProgramState *State,
+ ExplodedNode *P,
+ const ProgramPointTag *tag) {
hasGeneratedNode = true;
bool IsNew;
- ExplodedNode* Node = Eng.G->getNode(BlockEntrance(&B,
+ ExplodedNode *Node = Eng.G->getNode(BlockEntrance(&B,
Pred->getLocationContext(), tag ? tag : Tag),
State, &IsNew);
@@ -754,7 +732,7 @@ EndOfFunctionNodeBuilder::generateNode(const GRState* State,
return NULL;
}
-void EndOfFunctionNodeBuilder::GenerateCallExitNode(const GRState *state) {
+void EndOfFunctionNodeBuilder::GenerateCallExitNode(const ProgramState *state) {
hasGeneratedNode = true;
// Create a CallExit node and enqueue it.
const StackFrameContext *LocCtx
@@ -773,7 +751,7 @@ void EndOfFunctionNodeBuilder::GenerateCallExitNode(const GRState *state) {
}
-void CallEnterNodeBuilder::generateNode(const GRState *state) {
+void CallEnterNodeBuilder::generateNode(const ProgramState *state) {
// Check if the callee is in the same translation unit.
if (CalleeCtx->getTranslationUnit() !=
Pred->getLocationContext()->getTranslationUnit()) {
@@ -787,30 +765,13 @@ void CallEnterNodeBuilder::generateNode(const GRState *state) {
// Create a new AnalysisManager with components of the callee's
// TranslationUnit.
- // The Diagnostic is actually shared when we create ASTUnits from AST files.
- AnalysisManager AMgr(TU->getASTContext(), TU->getDiagnostic(),
- OldMgr.getLangOptions(),
- OldMgr.getPathDiagnosticClient(),
- OldMgr.getStoreManagerCreator(),
- OldMgr.getConstraintManagerCreator(),
- OldMgr.getCheckerManager(),
- OldMgr.getIndexer(),
- OldMgr.getMaxNodes(), OldMgr.getMaxVisit(),
- OldMgr.shouldVisualizeGraphviz(),
- OldMgr.shouldVisualizeUbigraph(),
- OldMgr.shouldPurgeDead(),
- OldMgr.shouldEagerlyAssume(),
- OldMgr.shouldTrimGraph(),
- OldMgr.shouldInlineCall(),
- OldMgr.getAnalysisContextManager().getUseUnoptimizedCFG(),
- OldMgr.getAnalysisContextManager().getAddImplicitDtors(),
- OldMgr.getAnalysisContextManager().getAddInitializers(),
- OldMgr.shouldEagerlyTrimExplodedGraph());
- llvm::OwningPtr<TransferFuncs> TF(MakeCFRefCountTF(AMgr.getASTContext(),
- /* GCEnabled */ false,
- AMgr.getLangOptions()));
+ // The Diagnostic is actually shared when we create ASTUnits from AST files.
+ AnalysisManager AMgr(TU->getASTContext(), TU->getDiagnostic(), OldMgr);
+
// Create the new engine.
- ExprEngine NewEng(AMgr, TF.take());
+ // FIXME: This cast isn't really safe.
+ bool GCEnabled = static_cast<ExprEngine&>(Eng.SubEng).isObjCGCEnabled();
+ ExprEngine NewEng(AMgr, GCEnabled);
// Create the new LocationContext.
AnalysisContext *NewAnaCtx = AMgr.getAnalysisContext(CalleeCtx->getDecl(),
@@ -823,8 +784,8 @@ void CallEnterNodeBuilder::generateNode(const GRState *state) {
OldLocCtx->getIndex());
// Now create an initial state for the new engine.
- const GRState *NewState = NewEng.getStateManager().MarshalState(state,
- NewLocCtx);
+ const ProgramState *NewState =
+ NewEng.getStateManager().MarshalState(state, NewLocCtx);
ExplodedNodeSet ReturnNodes;
NewEng.ExecuteWorkListWithInitialState(NewLocCtx, AMgr.getMaxNodes(),
NewState, ReturnNodes);
@@ -850,7 +811,7 @@ void CallEnterNodeBuilder::generateNode(const GRState *state) {
Eng.WList->enqueue(Node);
}
-void CallExitNodeBuilder::generateNode(const GRState *state) {
+void CallExitNodeBuilder::generateNode(const ProgramState *state) {
// Get the callee's location context.
const StackFrameContext *LocCtx
= cast<StackFrameContext>(Pred->getLocationContext());
diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp
index 3961c7b95259..e1b982c08cfc 100644
--- a/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/lib/StaticAnalyzer/Core/Environment.cpp
@@ -11,14 +11,15 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/ExprObjC.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
using namespace clang;
using namespace ento;
-SVal Environment::lookupExpr(const Stmt* E) const {
+SVal Environment::lookupExpr(const Stmt *E) const {
const SVal* X = ExprBindings.lookup(E);
if (X) {
SVal V = *X;
@@ -83,9 +84,9 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder,
case Stmt::CXXBindTemporaryExprClass:
E = cast<CXXBindTemporaryExpr>(E)->getSubExpr();
continue;
- case Stmt::MaterializeTemporaryExprClass:
- E = cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr();
- continue;
+ case Stmt::ObjCPropertyRefExprClass:
+ return loc::ObjCPropRef(cast<ObjCPropertyRefExpr>(E));
+
// Handle all other Stmt* using a lookup.
default:
break;
@@ -129,18 +130,6 @@ public:
};
} // end anonymous namespace
-static bool isBlockExprInCallers(const Stmt *E, const LocationContext *LC) {
- const LocationContext *ParentLC = LC->getParent();
- while (ParentLC) {
- CFG &C = *ParentLC->getCFG();
- if (C.isBlkExpr(E))
- return true;
- ParentLC = ParentLC->getParent();
- }
-
- return false;
-}
-
// In addition to mapping from Stmt * - > SVals in the Environment, we also
// maintain a mapping from Stmt * -> SVals (locations) that were used during
// a load and store.
@@ -158,24 +147,27 @@ static inline bool IsLocation(const Stmt *S) {
Environment
EnvironmentManager::removeDeadBindings(Environment Env,
SymbolReaper &SymReaper,
- const GRState *ST,
- llvm::SmallVectorImpl<const MemRegion*> &DRoots) {
-
- CFG &C = *SymReaper.getLocationContext()->getCFG();
+ const ProgramState *ST) {
// We construct a new Environment object entirely, as this is cheaper than
// individually removing all the subexpression bindings (which will greatly
// outnumber block-level expression bindings).
Environment NewEnv = getInitialEnvironment();
- llvm::SmallVector<std::pair<const Stmt*, SVal>, 10> deferredLocations;
+ SmallVector<std::pair<const Stmt*, SVal>, 10> deferredLocations;
+
+ MarkLiveCallback CB(SymReaper);
+ ScanReachableSymbols RSScaner(ST, CB);
+
+ llvm::ImmutableMapRef<const Stmt*,SVal>
+ EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(),
+ F.getTreeFactory());
// Iterate over the block-expr bindings.
for (Environment::iterator I = Env.begin(), E = Env.end();
I != E; ++I) {
const Stmt *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.
@@ -185,41 +177,20 @@ EnvironmentManager::removeDeadBindings(Environment Env,
deferredLocations.push_back(std::make_pair(BlkExpr, I.getData()));
continue;
}
-
const SVal &X = I.getData();
- // Block-level expressions in callers are assumed always live.
- if (isBlockExprInCallers(BlkExpr, SymReaper.getLocationContext())) {
- NewEnv.ExprBindings = F.add(NewEnv.ExprBindings, BlkExpr, X);
-
- if (isa<loc::MemRegionVal>(X)) {
- const MemRegion* R = cast<loc::MemRegionVal>(X).getRegion();
- DRoots.push_back(R);
- }
-
- // Mark all symbols in the block expr's value live.
- MarkLiveCallback cb(SymReaper);
- ST->scanReachableSymbols(X, cb);
- continue;
- }
-
- // Not a block-level expression?
- if (!C.isBlkExpr(BlkExpr))
- continue;
-
if (SymReaper.isLive(BlkExpr)) {
// Copy the binding to the new map.
- NewEnv.ExprBindings = F.add(NewEnv.ExprBindings, BlkExpr, X);
+ 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();
- DRoots.push_back(R);
+ const MemRegion *R = cast<loc::MemRegionVal>(X).getRegion();
+ SymReaper.markLive(R);
}
// Mark all symbols in the block expr's value live.
- MarkLiveCallback cb(SymReaper);
- ST->scanReachableSymbols(X, cb);
+ RSScaner.scan(X);
continue;
}
@@ -228,17 +199,18 @@ EnvironmentManager::removeDeadBindings(Environment Env,
// beginning of itself, but we need its UndefinedVal to determine its
// SVal.
if (X.isUndef() && cast<UndefinedVal>(X).getData())
- NewEnv.ExprBindings = F.add(NewEnv.ExprBindings, BlkExpr, X);
+ EBMapRef = EBMapRef.add(BlkExpr, X);
}
// Go through he deferred locations and add them to the new environment if
// the correspond Stmt* is in the map as well.
- for (llvm::SmallVectorImpl<std::pair<const Stmt*, SVal> >::iterator
+ for (SmallVectorImpl<std::pair<const Stmt*, SVal> >::iterator
I = deferredLocations.begin(), E = deferredLocations.end(); I != E; ++I) {
const Stmt *S = (Stmt*) (((uintptr_t) I->first) & (uintptr_t) ~0x1);
- if (NewEnv.ExprBindings.lookup(S))
- NewEnv.ExprBindings = F.add(NewEnv.ExprBindings, I->first, I->second);
+ if (EBMapRef.lookup(S))
+ EBMapRef = EBMapRef.add(I->first, I->second);
}
+ NewEnv.ExprBindings = EBMapRef.asImmutableMap();
return NewEnv;
}
diff --git a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index fa16fead9f1d..5762a21600e4 100644
--- a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/AST/Stmt.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/DenseMap.h"
@@ -93,18 +93,17 @@ void ExplodedGraph::reclaimRecentlyAllocatedNodes() {
ProgramPoint progPoint = node->getLocation();
if (!isa<PostStmt>(progPoint))
continue;
-
// Condition 4.
PostStmt ps = cast<PostStmt>(progPoint);
- if (ps.getTag() || isa<PostStmtCustom>(ps))
+ if (ps.getTag())
continue;
if (isa<BinaryOperator>(ps.getStmt()))
continue;
// Conditions 5, 6, and 7.
- const GRState *state = node->getState();
- const GRState *pred_state = pred->getState();
+ const ProgramState *state = node->getState();
+ const ProgramState *pred_state = pred->getState();
if (state->store != pred_state->store || state->GDM != pred_state->GDM ||
progPoint.getLocationContext() != pred->getLocationContext())
continue;
@@ -134,11 +133,11 @@ void ExplodedGraph::reclaimRecentlyAllocatedNodes() {
// ExplodedNode.
//===----------------------------------------------------------------------===//
-static inline BumpVector<ExplodedNode*>& getVector(void* P) {
+static inline BumpVector<ExplodedNode*>& getVector(void *P) {
return *reinterpret_cast<BumpVector<ExplodedNode*>*>(P);
}
-void ExplodedNode::addPredecessor(ExplodedNode* V, ExplodedGraph &G) {
+void ExplodedNode::addPredecessor(ExplodedNode *V, ExplodedGraph &G) {
assert (!V->isSink());
Preds.addNode(V, G);
V->Succs.addNode(this, G);
@@ -153,12 +152,12 @@ void ExplodedNode::NodeGroup::replaceNode(ExplodedNode *node) {
assert(getKind() == Size1);
}
-void ExplodedNode::NodeGroup::addNode(ExplodedNode* N, ExplodedGraph &G) {
+void ExplodedNode::NodeGroup::addNode(ExplodedNode *N, ExplodedGraph &G) {
assert((reinterpret_cast<uintptr_t>(N) & Mask) == 0x0);
assert(!getFlag());
if (getKind() == Size1) {
- if (ExplodedNode* NOld = getNode()) {
+ if (ExplodedNode *NOld = getNode()) {
BumpVectorContext &Ctx = G.getNodeAllocator();
BumpVector<ExplodedNode*> *V =
G.getAllocator().Allocate<BumpVector<ExplodedNode*> >();
@@ -215,11 +214,11 @@ ExplodedNode** ExplodedNode::NodeGroup::end() const {
}
}
-ExplodedNode *ExplodedGraph::getNode(const ProgramPoint& L,
- const GRState* State, bool* IsNew) {
+ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L,
+ const ProgramState *State, bool* IsNew) {
// Profile 'State' to determine if we already have an existing node.
llvm::FoldingSetNodeID profile;
- void* InsertPos = 0;
+ void *InsertPos = 0;
NodeTy::Profile(profile, L, State);
NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos);
@@ -285,7 +284,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> Pass2Ty;
Pass2Ty& Pass2 = M->M;
- llvm::SmallVector<const ExplodedNode*, 10> WL1, WL2;
+ SmallVector<const ExplodedNode*, 10> WL1, WL2;
// ===- Pass 1 (reverse DFS) -===
for (const ExplodedNode* const* I = BeginSources; I != EndSources; ++I) {
@@ -326,7 +325,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
// ===- Pass 2 (forward DFS to construct the new graph) -===
while (!WL2.empty()) {
- const ExplodedNode* N = WL2.back();
+ const ExplodedNode *N = WL2.back();
WL2.pop_back();
// Skip this node if we have already processed it.
@@ -335,7 +334,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
// Create the corresponding node in the new graph and record the mapping
// from the old node to the new node.
- ExplodedNode* NewN = G->getNode(N->getLocation(), N->State, NULL);
+ ExplodedNode *NewN = G->getNode(N->getLocation(), N->State, NULL);
Pass2[N] = NewN;
// Also record the reverse mapping from the new node to the old node.
@@ -383,7 +382,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
}
ExplodedNode*
-InterExplodedGraphMap::getMappedNode(const ExplodedNode* N) const {
+InterExplodedGraphMap::getMappedNode(const ExplodedNode *N) const {
llvm::DenseMap<const ExplodedNode*, ExplodedNode*>::const_iterator I =
M.find(N);
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index ffe5f0b6cdf2..ac9cf0b08d44 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -18,6 +18,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
@@ -35,25 +36,13 @@
using namespace clang;
using namespace ento;
-using llvm::dyn_cast;
-using llvm::dyn_cast_or_null;
-using llvm::cast;
using llvm::APSInt;
-namespace {
- // Trait class for recording returned expression in the state.
- struct ReturnExpr {
- static int TagInt;
- typedef const Stmt *data_type;
- };
- int ReturnExpr::TagInt;
-}
-
//===----------------------------------------------------------------------===//
// Utility functions.
//===----------------------------------------------------------------------===//
-static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
+static inline Selector GetNullarySelector(const char* name, ASTContext &Ctx) {
IdentifierInfo* II = &Ctx.Idents.get(name);
return Ctx.Selectors.getSelector(0, &II);
}
@@ -62,7 +51,7 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
// Engine construction and deletion.
//===----------------------------------------------------------------------===//
-ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf)
+ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled)
: AMgr(mgr),
Engine(*this),
G(Engine.getGraph()),
@@ -75,11 +64,7 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf)
EntryNode(NULL), currentStmt(NULL),
NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
RaiseSel(GetNullarySelector("raise", getContext())),
- BR(mgr, *this), TF(tf) {
-
- // FIXME: Eventually remove the TF object entirely.
- TF->RegisterChecks(*this);
- TF->RegisterPrinters(getStateManager().Printers);
+ ObjCGCEnabled(gcEnabled), BR(mgr, *this) {
if (mgr.shouldEagerlyTrimExplodedGraph()) {
// Enable eager node reclaimation when constructing the ExplodedGraph.
@@ -96,8 +81,8 @@ ExprEngine::~ExprEngine() {
// Utility methods.
//===----------------------------------------------------------------------===//
-const GRState* ExprEngine::getInitialState(const LocationContext *InitLoc) {
- const GRState *state = StateMgr.getInitialState(InitLoc);
+const ProgramState *ExprEngine::getInitialState(const LocationContext *InitLoc) {
+ const ProgramState *state = StateMgr.getInitialState(InitLoc);
// Preconditions.
@@ -132,7 +117,7 @@ const GRState* ExprEngine::getInitialState(const LocationContext *InitLoc) {
if (!Constraint)
break;
- if (const GRState *newState = state->assume(*Constraint, true))
+ if (const ProgramState *newState = state->assume(*Constraint, true))
state = newState;
break;
@@ -162,11 +147,11 @@ ExprEngine::doesInvalidateGlobals(const CallOrObjCMessage &callOrMessage) const
if (callOrMessage.isFunctionCall() && !callOrMessage.isCXXCall()) {
SVal calleeV = callOrMessage.getFunctionCallee();
if (const FunctionTextRegion *codeR =
- llvm::dyn_cast_or_null<FunctionTextRegion>(calleeV.getAsRegion())) {
+ dyn_cast_or_null<FunctionTextRegion>(calleeV.getAsRegion())) {
const FunctionDecl *fd = codeR->getDecl();
if (const IdentifierInfo *ii = fd->getIdentifier()) {
- llvm::StringRef fname = ii->getName();
+ StringRef fname = ii->getName();
if (fname == "strlen")
return false;
}
@@ -183,28 +168,27 @@ ExprEngine::doesInvalidateGlobals(const CallOrObjCMessage &callOrMessage) const
/// evalAssume - Called by ConstraintManager. Used to call checker-specific
/// logic for handling assumptions on symbolic values.
-const GRState *ExprEngine::processAssume(const GRState *state, SVal cond,
- bool assumption) {
- state = getCheckerManager().runCheckersForEvalAssume(state, cond, assumption);
-
- // If the state is infeasible at this point, bail out.
- if (!state)
- return NULL;
-
- return TF->evalAssume(state, cond, assumption);
+const ProgramState *ExprEngine::processAssume(const ProgramState *state,
+ SVal cond, bool assumption) {
+ return getCheckerManager().runCheckersForEvalAssume(state, cond, assumption);
}
-bool ExprEngine::wantsRegionChangeUpdate(const GRState* state) {
+bool ExprEngine::wantsRegionChangeUpdate(const ProgramState *state) {
return getCheckerManager().wantsRegionChangeUpdate(state);
}
-const GRState *
-ExprEngine::processRegionChanges(const GRState *state,
+const ProgramState *
+ExprEngine::processRegionChanges(const ProgramState *state,
const StoreManager::InvalidatedSymbols *invalidated,
- const MemRegion * const *Begin,
- const MemRegion * const *End) {
+ ArrayRef<const MemRegion *> Explicits,
+ ArrayRef<const MemRegion *> Regions) {
return getCheckerManager().runCheckersForRegionChanges(state, invalidated,
- Begin, End);
+ Explicits, Regions);
+}
+
+void ExprEngine::printState(raw_ostream &Out, const ProgramState *State,
+ const char *NL, const char *Sep) {
+ getCheckerManager().runCheckersForPrintState(Out, State, NL, Sep);
}
void ExprEngine::processEndWorklist(bool hasWorkRemaining) {
@@ -217,7 +201,7 @@ void ExprEngine::processCFGElement(const CFGElement E,
case CFGElement::Invalid:
llvm_unreachable("Unexpected CFGElement kind.");
case CFGElement::Statement:
- ProcessStmt(E.getAs<CFGStmt>()->getStmt(), builder);
+ ProcessStmt(const_cast<Stmt*>(E.getAs<CFGStmt>()->getStmt()), builder);
return;
case CFGElement::Initializer:
ProcessInitializer(E.getAs<CFGInitializer>()->getInitializer(), builder);
@@ -232,9 +216,12 @@ void ExprEngine::processCFGElement(const CFGElement E,
}
void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
+ // TODO: Use RAII to remove the unnecessary, tagged nodes.
+ //RegisterCreatedNodes registerCreatedNodes(getGraph());
+
// Reclaim any unnecessary nodes in the ExplodedGraph.
G.reclaimRecentlyAllocatedNodes();
- // Recycle any unused states in the GRStateManager.
+ // Recycle any unused states in the ProgramStateManager.
StateMgr.recycleUnusedStates();
currentStmt = S.getStmt();
@@ -242,74 +229,93 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
currentStmt->getLocStart(),
"Error evaluating statement");
+ // A tag to track convenience transitions, which can be removed at cleanup.
+ static SimpleProgramPointTag cleanupTag("ExprEngine : Clean Node");
Builder = &builder;
EntryNode = builder.getPredecessor();
+ const ProgramState *EntryState = EntryNode->getState();
+ CleanedState = EntryState;
+ ExplodedNode *CleanedNode = 0;
+
// Create the cleaned state.
const LocationContext *LC = EntryNode->getLocationContext();
- SymbolReaper SymReaper(LC, currentStmt, SymMgr);
+ SymbolReaper SymReaper(LC, currentStmt, SymMgr, getStoreManager());
- if (AMgr.shouldPurgeDead()) {
- const GRState *St = EntryNode->getState();
- getCheckerManager().runCheckersForLiveSymbols(St, SymReaper);
+ if (AMgr.getPurgeMode() != PurgeNone) {
+ getCheckerManager().runCheckersForLiveSymbols(CleanedState, SymReaper);
const StackFrameContext *SFC = LC->getCurrentStackFrame();
- CleanedState = StateMgr.removeDeadBindings(St, SFC, SymReaper);
- } else {
- CleanedState = EntryNode->getState();
+
+ // 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.
+ CleanedState = StateMgr.removeDeadBindings(CleanedState, SFC, SymReaper);
}
// Process any special transfer function for dead symbols.
ExplodedNodeSet Tmp;
+ if (!SymReaper.hasDeadSymbols()) {
+ // Generate a CleanedNode that has the environment and store cleaned
+ // up. Since no symbols are dead, we can optimize and not clean out
+ // the constraint manager.
+ CleanedNode =
+ Builder->generateNode(currentStmt, CleanedState, EntryNode, &cleanupTag);
+ Tmp.Add(CleanedNode);
- if (!SymReaper.hasDeadSymbols())
- Tmp.Add(EntryNode);
- else {
+ } else {
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
SaveOr OldHasGen(Builder->hasGeneratedNode);
SaveAndRestore<bool> OldPurgeDeadSymbols(Builder->PurgingDeadSymbols);
Builder->PurgingDeadSymbols = true;
- // FIXME: This should soon be removed.
- ExplodedNodeSet Tmp2;
- getTF().evalDeadSymbols(Tmp2, *this, *Builder, EntryNode,
- CleanedState, SymReaper);
-
- getCheckerManager().runCheckersForDeadSymbols(Tmp, Tmp2,
+ // Call checkers with the non-cleaned state so that they could query the
+ // values of the soon to be dead symbols.
+ ExplodedNodeSet CheckedSet;
+ getCheckerManager().runCheckersForDeadSymbols(CheckedSet, EntryNode,
SymReaper, currentStmt, *this);
- if (!Builder->BuildSinks && !Builder->hasGeneratedNode)
- Tmp.Add(EntryNode);
- }
+ // For each node in CheckedSet, generate CleanedNodes that have the
+ // environment, the store, and the constraints cleaned up but have the
+ // user-supplied states as the predecessors.
+ for (ExplodedNodeSet::const_iterator
+ I = CheckedSet.begin(), E = CheckedSet.end(); I != E; ++I) {
+ const ProgramState *CheckerState = (*I)->getState();
- bool HasAutoGenerated = false;
+ // The constraint manager has not been cleaned up yet, so clean up now.
+ CheckerState = getConstraintManager().removeDeadBindings(CheckerState,
+ SymReaper);
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- ExplodedNodeSet Dst;
+ assert(StateMgr.haveEqualEnvironments(CheckerState, EntryState) &&
+ "Checkers are not allowed to modify the Environment as a part of "
+ "checkDeadSymbols processing.");
+ assert(StateMgr.haveEqualStores(CheckerState, EntryState) &&
+ "Checkers are not allowed to modify the Store as a part of "
+ "checkDeadSymbols processing.");
- // Set the cleaned state.
- Builder->SetCleanedState(*I == EntryNode ? CleanedState : GetState(*I));
+ // Create a state based on CleanedState with CheckerState GDM and
+ // generate a transition to that state.
+ const ProgramState *CleanedCheckerSt =
+ StateMgr.getPersistentStateWithGDM(CleanedState, CheckerState);
+ ExplodedNode *CleanedNode = Builder->generateNode(currentStmt,
+ CleanedCheckerSt, *I,
+ &cleanupTag);
+ Tmp.Add(CleanedNode);
+ }
+ }
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+ // TODO: Remove Dest set, it's no longer needed.
+ ExplodedNodeSet Dst;
// Visit the statement.
Visit(currentStmt, *I, Dst);
-
- // Do we need to auto-generate a node? We only need to do this to generate
- // a node with a "cleaned" state; CoreEngine will actually handle
- // auto-transitions for other cases.
- if (Dst.size() == 1 && *Dst.begin() == EntryNode
- && !Builder->hasGeneratedNode && !HasAutoGenerated) {
- HasAutoGenerated = true;
- builder.generateNode(currentStmt, GetState(EntryNode), *I);
- }
}
// NULL out these variables to cleanup.
CleanedState = NULL;
EntryNode = NULL;
-
currentStmt = 0;
-
Builder = NULL;
}
@@ -334,7 +340,7 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init,
for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I){
ExplodedNode *Pred = *I;
- const GRState *state = Pred->getState();
+ const ProgramState *state = Pred->getState();
const FieldDecl *FD = BMI->getAnyMember();
@@ -391,7 +397,7 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor dtor,
StmtNodeBuilder &builder) {
ExplodedNode *pred = builder.getPredecessor();
- const GRState *state = pred->getState();
+ const ProgramState *state = pred->getState();
const VarDecl *varDecl = dtor.getVarDecl();
QualType varType = varDecl->getType();
@@ -422,8 +428,8 @@ void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
StmtNodeBuilder &builder) {
}
-void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
+void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
S->getLocStart(),
"Error evaluating statement");
@@ -447,9 +453,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
case Stmt::CXXBindTemporaryExprClass:
case Stmt::CXXCatchStmtClass:
case Stmt::CXXDependentScopeMemberExprClass:
- case Stmt::CXXForRangeStmtClass:
case Stmt::CXXPseudoDestructorExprClass:
- case Stmt::CXXTemporaryObjectExprClass:
case Stmt::CXXThrowExprClass:
case Stmt::CXXTryStmtClass:
case Stmt::CXXTypeidExprClass:
@@ -472,7 +476,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
{
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
Builder->BuildSinks = true;
- const ExplodedNode *node = MakeNode(Dst, S, Pred, GetState(Pred));
+ const ExplodedNode *node = MakeNode(Dst, S, Pred, Pred->getState());
Engine.addAbortedBlock(node, Builder->getBlock());
break;
}
@@ -495,6 +499,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
case Stmt::CaseStmtClass:
case Stmt::CompoundStmtClass:
case Stmt::ContinueStmtClass:
+ case Stmt::CXXForRangeStmtClass:
case Stmt::DefaultStmtClass:
case Stmt::DoStmtClass:
case Stmt::ForStmtClass:
@@ -511,7 +516,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
case Stmt::GNUNullExprClass: {
// GNU __null is a pointer-width integer, not an actual pointer.
- const GRState *state = GetState(Pred);
+ const ProgramState *state = Pred->getState();
state = state->BindExpr(S, svalBuilder.makeIntValWithPtrWidth(0, false));
MakeNode(Dst, S, Pred, state);
break;
@@ -522,11 +527,12 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
break;
case Stmt::ObjCPropertyRefExprClass:
- VisitObjCPropertyRefExpr(cast<ObjCPropertyRefExpr>(S), Pred, Dst);
+ // Implicitly handled by Environment::getSVal().
+ Dst.Add(Pred);
break;
case Stmt::ImplicitValueInitExprClass: {
- const GRState *state = GetState(Pred);
+ const ProgramState *state = Pred->getState();
QualType ty = cast<ImplicitValueInitExpr>(S)->getType();
SVal val = svalBuilder.makeZeroVal(ty);
MakeNode(Dst, S, Pred, state->BindExpr(S, val));
@@ -558,6 +564,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
case Stmt::CUDAKernelCallExprClass:
case Stmt::OpaqueValueExprClass:
case Stmt::AsTypeExprClass:
+ case Stmt::AtomicExprClass:
// Fall through.
// Cases we intentionally don't evaluate, since they don't need
@@ -597,7 +604,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
break;
}
else if (B->getOpcode() == BO_Comma) {
- const GRState* state = GetState(Pred);
+ const ProgramState *state = Pred->getState();
MakeNode(Dst, B, Pred, state->BindExpr(B, state->getSVal(B->getRHS())));
break;
}
@@ -621,6 +628,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
break;
}
+ case Stmt::CXXTemporaryObjectExprClass:
case Stmt::CXXConstructExprClass: {
const CXXConstructExpr *C = cast<CXXConstructExpr>(S);
// For block-level CXXConstructExpr, we don't have a destination region.
@@ -644,7 +652,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
// the CFG do not model them as explicit control-flow.
case Stmt::ChooseExprClass: { // __builtin_choose_expr
- const ChooseExpr* C = cast<ChooseExpr>(S);
+ const ChooseExpr *C = cast<ChooseExpr>(S);
VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst);
break;
}
@@ -687,7 +695,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
case Stmt::CXXConstCastExprClass:
case Stmt::CXXFunctionalCastExprClass:
case Stmt::ObjCBridgedCastExprClass: {
- const CastExpr* C = cast<CastExpr>(S);
+ const CastExpr *C = cast<CastExpr>(S);
// Handle the previsit checks.
ExplodedNodeSet dstPrevisit;
getCheckerManager().runCheckersForPreStmt(dstPrevisit, Pred, C, *this);
@@ -708,7 +716,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
const MaterializeTemporaryExpr *Materialize
= cast<MaterializeTemporaryExpr>(S);
if (!Materialize->getType()->isRecordType())
- CreateCXXTemporaryObject(Materialize->GetTemporaryExpr(), Pred, Dst);
+ CreateCXXTemporaryObject(Materialize, Pred, Dst);
else
Visit(Materialize->GetTemporaryExpr(), Pred, Dst);
break;
@@ -730,7 +738,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
break;
case Stmt::ObjCMessageExprClass:
- VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), Pred, Dst);
+ VisitObjCMessage(cast<ObjCMessageExpr>(S), Pred, Dst);
break;
case Stmt::ObjCAtThrowStmtClass: {
@@ -738,7 +746,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
// an abort.
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
Builder->BuildSinks = true;
- MakeNode(Dst, S, Pred, GetState(Pred));
+ MakeNode(Dst, S, Pred, Pred->getState());
break;
}
@@ -756,7 +764,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
break;
case Stmt::StmtExprClass: {
- const StmtExpr* SE = cast<StmtExpr>(S);
+ const StmtExpr *SE = cast<StmtExpr>(S);
if (SE->getSubStmt()->body_empty()) {
// Empty statement expression.
@@ -766,8 +774,8 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
break;
}
- if (Expr* LastExpr = dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) {
- const GRState* state = GetState(Pred);
+ if (Expr *LastExpr = dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) {
+ const ProgramState *state = Pred->getState();
MakeNode(Dst, SE, Pred, state->BindExpr(SE, state->getSVal(LastExpr)));
}
else
@@ -777,7 +785,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
}
case Stmt::StringLiteralClass: {
- const GRState* state = GetState(Pred);
+ const ProgramState *state = Pred->getState();
SVal V = state->getLValue(cast<StringLiteral>(S));
MakeNode(Dst, S, Pred, state->BindExpr(S, V));
return;
@@ -811,8 +819,7 @@ void ExprEngine::processCFGBlockEntrance(ExplodedNodeSet &dstNodes,
if (nodeBuilder.getBlockCounter().getNumVisited(
pred->getLocationContext()->getCurrentStackFrame(),
block->getBlockID()) >= AMgr.getMaxVisit()) {
-
- static int tag = 0;
+ static SimpleProgramPointTag tag("ExprEngine : Block count exceeded");
nodeBuilder.generateNode(pred->getState(), pred, &tag, true);
}
}
@@ -821,11 +828,12 @@ void ExprEngine::processCFGBlockEntrance(ExplodedNodeSet &dstNodes,
// Generic node creation.
//===----------------------------------------------------------------------===//
-ExplodedNode* ExprEngine::MakeNode(ExplodedNodeSet& Dst, const Stmt* S,
- ExplodedNode* Pred, const GRState* St,
- ProgramPoint::Kind K, const void *tag) {
+ExplodedNode *ExprEngine::MakeNode(ExplodedNodeSet &Dst, const Stmt *S,
+ ExplodedNode *Pred, const ProgramState *St,
+ ProgramPoint::Kind K,
+ const ProgramPointTag *tag) {
assert (Builder && "StmtNodeBuilder not present.");
- SaveAndRestore<const void*> OldTag(Builder->Tag);
+ SaveAndRestore<const ProgramPointTag*> OldTag(Builder->Tag);
Builder->Tag = tag;
return Builder->MakeNode(Dst, S, Pred, St, K);
}
@@ -834,8 +842,8 @@ ExplodedNode* ExprEngine::MakeNode(ExplodedNodeSet& Dst, const Stmt* S,
// Branch processing.
//===----------------------------------------------------------------------===//
-const GRState* ExprEngine::MarkBranch(const GRState* state,
- const Stmt* Terminator,
+const ProgramState *ExprEngine::MarkBranch(const ProgramState *state,
+ const Stmt *Terminator,
bool branchTaken) {
switch (Terminator->getStmtClass()) {
@@ -855,7 +863,7 @@ const GRState* ExprEngine::MarkBranch(const GRState* state,
// For ||, if we take the false branch, then the value of the whole
// expression is that of the RHS expression.
- const Expr* Ex = (Op == BO_LAnd && branchTaken) ||
+ const Expr *Ex = (Op == BO_LAnd && branchTaken) ||
(Op == BO_LOr && !branchTaken)
? B->getRHS() : B->getLHS();
@@ -870,7 +878,7 @@ const GRState* ExprEngine::MarkBranch(const GRState* state,
// For ?, if branchTaken == true then the value is either the LHS or
// the condition itself. (GNU extension).
- const Expr* Ex;
+ const Expr *Ex;
if (branchTaken)
Ex = C->getTrueExpr();
@@ -882,9 +890,9 @@ const GRState* ExprEngine::MarkBranch(const GRState* state,
case Stmt::ChooseExprClass: { // ?:
- const ChooseExpr* C = cast<ChooseExpr>(Terminator);
+ const ChooseExpr *C = cast<ChooseExpr>(Terminator);
- const Expr* Ex = branchTaken ? C->getLHS() : C->getRHS();
+ const Expr *Ex = branchTaken ? C->getLHS() : C->getRHS();
return state->BindExpr(C, UndefinedVal(Ex));
}
}
@@ -895,8 +903,10 @@ const GRState* ExprEngine::MarkBranch(const GRState* state,
/// integers that promote their values (which are currently not tracked well).
/// This function returns the SVal bound to Condition->IgnoreCasts if all the
// cast(s) did was sign-extend the original value.
-static SVal RecoverCastedSymbol(GRStateManager& StateMgr, const GRState* state,
- const Stmt* Condition, ASTContext& Ctx) {
+static SVal RecoverCastedSymbol(ProgramStateManager& StateMgr,
+ const ProgramState *state,
+ const Stmt *Condition,
+ ASTContext &Ctx) {
const Expr *Ex = dyn_cast<Expr>(Condition);
if (!Ex)
@@ -929,7 +939,7 @@ static SVal RecoverCastedSymbol(GRStateManager& StateMgr, const GRState* state,
return state->getSVal(Ex);
}
-void ExprEngine::processBranch(const Stmt* Condition, const Stmt* Term,
+void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
BranchNodeBuilder& builder) {
// Check for NULL conditions; e.g. "for(;;)"
@@ -948,7 +958,7 @@ void ExprEngine::processBranch(const Stmt* Condition, const Stmt* Term,
if (!builder.isFeasible(true) && !builder.isFeasible(false))
return;
- const GRState* PrevState = builder.getState();
+ const ProgramState *PrevState = builder.getState();
SVal X = PrevState->getSVal(Condition);
if (X.isUnknownOrUndef()) {
@@ -980,7 +990,7 @@ void ExprEngine::processBranch(const Stmt* Condition, const Stmt* Term,
// Process the true branch.
if (builder.isFeasible(true)) {
- if (const GRState *state = PrevState->assume(V, true))
+ if (const ProgramState *state = PrevState->assume(V, true))
builder.generateNode(MarkBranch(state, Term, true), true);
else
builder.markInfeasible(true);
@@ -988,7 +998,7 @@ void ExprEngine::processBranch(const Stmt* Condition, const Stmt* Term,
// Process the false branch.
if (builder.isFeasible(false)) {
- if (const GRState *state = PrevState->assume(V, false))
+ if (const ProgramState *state = PrevState->assume(V, false))
builder.generateNode(MarkBranch(state, Term, false), false);
else
builder.markInfeasible(false);
@@ -999,7 +1009,7 @@ void ExprEngine::processBranch(const Stmt* Condition, const Stmt* Term,
/// nodes by processing the 'effects' of a computed goto jump.
void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
- const GRState *state = builder.getState();
+ const ProgramState *state = builder.getState();
SVal V = state->getSVal(builder.getTarget());
// Three possibilities:
@@ -1021,8 +1031,7 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
}
}
- assert(false && "No block with label.");
- return;
+ llvm_unreachable("No block with label.");
}
if (isa<loc::ConcreteInt>(V) || isa<UndefinedVal>(V)) {
@@ -1040,31 +1049,9 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
builder.generateNode(I, state);
}
-
-void ExprEngine::VisitGuardedExpr(const Expr* Ex, const Expr* L,
- const Expr* R,
- ExplodedNode* Pred, ExplodedNodeSet& Dst) {
-
- assert(Ex == currentStmt &&
- Pred->getLocationContext()->getCFG()->isBlkExpr(Ex));
-
- const GRState* state = GetState(Pred);
- SVal X = state->getSVal(Ex);
-
- assert (X.isUndef());
-
- const Expr *SE = (Expr*) cast<UndefinedVal>(X).getData();
- assert(SE);
- X = state->getSVal(SE);
-
- // Make sure that we invalidate the previous binding.
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, X, true));
-}
-
/// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
/// nodes when the control reaches the end of a function.
void ExprEngine::processEndOfFunction(EndOfFunctionNodeBuilder& builder) {
- getTF().evalEndPath(*this, builder);
StateMgr.EndPath(builder.getState());
getCheckerManager().runCheckersForEndPath(builder, *this);
}
@@ -1073,8 +1060,8 @@ void ExprEngine::processEndOfFunction(EndOfFunctionNodeBuilder& builder) {
/// nodes by processing the 'effects' of a switch statement.
void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
typedef SwitchNodeBuilder::iterator iterator;
- const GRState* state = builder.getState();
- const Expr* CondE = builder.getCondition();
+ const ProgramState *state = builder.getState();
+ const Expr *CondE = builder.getCondition();
SVal CondV_untested = state->getSVal(CondE);
if (CondV_untested.isUndef()) {
@@ -1086,7 +1073,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
}
DefinedOrUnknownSVal CondV = cast<DefinedOrUnknownSVal>(CondV_untested);
- const GRState *DefaultSt = state;
+ const ProgramState *DefaultSt = state;
iterator I = builder.begin(), EI = builder.end();
bool defaultIsFeasible = I == EI;
@@ -1096,28 +1083,16 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
if (!I.getBlock())
continue;
- const CaseStmt* Case = I.getCase();
+ const CaseStmt *Case = I.getCase();
// Evaluate the LHS of the case value.
- Expr::EvalResult V1;
- bool b = Case->getLHS()->Evaluate(V1, getContext());
-
- // Sanity checks. These go away in Release builds.
- assert(b && V1.Val.isInt() && !V1.HasSideEffects
- && "Case condition must evaluate to an integer constant.");
- (void)b; // silence unused variable warning
- assert(V1.Val.getInt().getBitWidth() ==
- getContext().getTypeSize(CondE->getType()));
+ llvm::APSInt V1 = Case->getLHS()->EvaluateKnownConstInt(getContext());
+ assert(V1.getBitWidth() == getContext().getTypeSize(CondE->getType()));
// Get the RHS of the case, if it exists.
- Expr::EvalResult V2;
-
- if (const Expr* E = Case->getRHS()) {
- b = E->Evaluate(V2, getContext());
- assert(b && V2.Val.isInt() && !V2.HasSideEffects
- && "Case condition must evaluate to an integer constant.");
- (void)b; // silence unused variable warning
- }
+ llvm::APSInt V2;
+ if (const Expr *E = Case->getRHS())
+ V2 = E->EvaluateKnownConstInt(getContext());
else
V2 = V1;
@@ -1126,12 +1101,12 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
// This should be easy once we have "ranges" for NonLVals.
do {
- nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt()));
+ nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1));
DefinedOrUnknownSVal Res = svalBuilder.evalEQ(DefaultSt ? DefaultSt : state,
CondV, CaseVal);
// Now "assume" that the case matches.
- if (const GRState* stateNew = state->assume(Res, true)) {
+ if (const ProgramState *stateNew = state->assume(Res, true)) {
builder.generateCaseStmtNode(I, stateNew);
// If CondV evaluates to a constant, then we know that this
@@ -1144,7 +1119,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
// Now "assume" that the case doesn't match. Add this state
// to the default state (if it is feasible).
if (DefaultSt) {
- if (const GRState *stateNew = DefaultSt->assume(Res, false)) {
+ if (const ProgramState *stateNew = DefaultSt->assume(Res, false)) {
defaultIsFeasible = true;
DefaultSt = stateNew;
}
@@ -1155,11 +1130,11 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
}
// Concretize the next value in the range.
- if (V1.Val.getInt() == V2.Val.getInt())
+ if (V1 == V2)
break;
- ++V1.Val.getInt();
- assert (V1.Val.getInt() <= V2.Val.getInt());
+ ++V1;
+ assert (V1 <= V2);
} while (true);
}
@@ -1184,120 +1159,16 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
builder.generateDefaultCaseNode(DefaultSt);
}
-void ExprEngine::processCallEnter(CallEnterNodeBuilder &B) {
- const GRState *state = B.getState()->enterStackFrame(B.getCalleeContext());
- B.generateNode(state);
-}
-
-void ExprEngine::processCallExit(CallExitNodeBuilder &B) {
- const GRState *state = B.getState();
- const ExplodedNode *Pred = B.getPredecessor();
- const StackFrameContext *calleeCtx =
- cast<StackFrameContext>(Pred->getLocationContext());
- const Stmt *CE = calleeCtx->getCallSite();
-
- // If the callee returns an expression, bind its value to CallExpr.
- const Stmt *ReturnedExpr = state->get<ReturnExpr>();
- if (ReturnedExpr) {
- SVal RetVal = state->getSVal(ReturnedExpr);
- state = state->BindExpr(CE, RetVal);
- // Clear the return expr GDM.
- state = state->remove<ReturnExpr>();
- }
-
- // Bind the constructed object value to CXXConstructExpr.
- if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) {
- const CXXThisRegion *ThisR =
- getCXXThisRegion(CCE->getConstructor()->getParent(), calleeCtx);
-
- SVal ThisV = state->getSVal(ThisR);
- // Always bind the region to the CXXConstructExpr.
- state = state->BindExpr(CCE, ThisV);
- }
-
- B.generateNode(state);
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer functions: logical operations ('&&', '||').
-//===----------------------------------------------------------------------===//
-
-void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
-
- assert(B->getOpcode() == BO_LAnd ||
- B->getOpcode() == BO_LOr);
-
- assert(B==currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(B));
-
- const GRState* state = GetState(Pred);
- SVal X = state->getSVal(B);
- assert(X.isUndef());
-
- const Expr *Ex = (const Expr*) cast<UndefinedVal>(X).getData();
- assert(Ex);
-
- if (Ex == B->getRHS()) {
- X = state->getSVal(Ex);
-
- // Handle undefined values.
- if (X.isUndef()) {
- MakeNode(Dst, B, Pred, state->BindExpr(B, X));
- return;
- }
-
- DefinedOrUnknownSVal XD = cast<DefinedOrUnknownSVal>(X);
-
- // We took the RHS. Because the value of the '&&' or '||' expression must
- // evaluate to 0 or 1, we must assume the value of the RHS evaluates to 0
- // or 1. Alternatively, we could take a lazy approach, and calculate this
- // value later when necessary. We don't have the machinery in place for
- // this right now, and since most logical expressions are used for branches,
- // the payoff is not likely to be large. Instead, we do eager evaluation.
- if (const GRState *newState = state->assume(XD, true))
- MakeNode(Dst, B, Pred,
- newState->BindExpr(B, svalBuilder.makeIntVal(1U, B->getType())));
-
- if (const GRState *newState = state->assume(XD, false))
- MakeNode(Dst, B, Pred,
- newState->BindExpr(B, svalBuilder.makeIntVal(0U, B->getType())));
- }
- else {
- // We took the LHS expression. Depending on whether we are '&&' or
- // '||' we know what the value of the expression is via properties of
- // the short-circuiting.
- X = svalBuilder.makeIntVal(B->getOpcode() == BO_LAnd ? 0U : 1U,
- B->getType());
- MakeNode(Dst, B, Pred, state->BindExpr(B, X));
- }
-}
-
//===----------------------------------------------------------------------===//
// Transfer functions: Loads and stores.
//===----------------------------------------------------------------------===//
-void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
-
- ExplodedNodeSet Tmp;
-
- CanQualType T = getContext().getCanonicalType(BE->getType());
- SVal V = svalBuilder.getBlockPointer(BE->getBlockDecl(), T,
- Pred->getLocationContext());
-
- MakeNode(Tmp, BE, Pred, GetState(Pred)->BindExpr(BE, V),
- ProgramPoint::PostLValueKind);
-
- // Post-visit the BlockExpr.
- getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this);
-}
-
void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- const GRState *state = GetState(Pred);
+ const ProgramState *state = Pred->getState();
- if (const VarDecl* VD = dyn_cast<VarDecl>(D)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
assert(Ex->isLValue());
SVal V = state->getLValue(VD, Pred->getLocationContext());
@@ -1314,13 +1185,13 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
ProgramPoint::PostLValueKind);
return;
}
- if (const EnumConstantDecl* ED = dyn_cast<EnumConstantDecl>(D)) {
+ if (const EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D)) {
assert(!Ex->isLValue());
SVal V = svalBuilder.makeIntVal(ED->getInitVal());
MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V));
return;
}
- if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
SVal V = svalBuilder.getFunctionPointer(FD);
MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V),
ProgramPoint::PostLValueKind);
@@ -1331,124 +1202,93 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
}
/// VisitArraySubscriptExpr - Transfer function for array accesses
-void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr* A,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst){
+void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst){
- const Expr* Base = A->getBase()->IgnoreParens();
- const Expr* Idx = A->getIdx()->IgnoreParens();
+ const Expr *Base = A->getBase()->IgnoreParens();
+ const Expr *Idx = A->getIdx()->IgnoreParens();
- // Evaluate the base.
- ExplodedNodeSet Tmp;
- Visit(Base, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I1=Tmp.begin(), E1=Tmp.end(); I1!=E1; ++I1) {
- ExplodedNodeSet Tmp2;
- Visit(Idx, *I1, Tmp2); // Evaluate the index.
- ExplodedNodeSet Tmp3;
- getCheckerManager().runCheckersForPreStmt(Tmp3, Tmp2, A, *this);
-
- for (ExplodedNodeSet::iterator I2=Tmp3.begin(),E2=Tmp3.end();I2!=E2; ++I2) {
- const GRState* state = GetState(*I2);
- SVal V = state->getLValue(A->getType(), state->getSVal(Idx),
- state->getSVal(Base));
- assert(A->isLValue());
- MakeNode(Dst, A, *I2, state->BindExpr(A, V), ProgramPoint::PostLValueKind);
- }
+
+ ExplodedNodeSet checkerPreStmt;
+ getCheckerManager().runCheckersForPreStmt(checkerPreStmt, Pred, A, *this);
+
+ for (ExplodedNodeSet::iterator it = checkerPreStmt.begin(),
+ ei = checkerPreStmt.end(); it != ei; ++it) {
+ const ProgramState *state = (*it)->getState();
+ SVal V = state->getLValue(A->getType(), state->getSVal(Idx),
+ state->getSVal(Base));
+ assert(A->isLValue());
+ MakeNode(Dst, A, *it, state->BindExpr(A, V), ProgramPoint::PostLValueKind);
}
}
/// VisitMemberExpr - Transfer function for member expressions.
-void ExprEngine::VisitMemberExpr(const MemberExpr* M, ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
-
- Expr *baseExpr = M->getBase()->IgnoreParens();
- ExplodedNodeSet dstBase;
- Visit(baseExpr, Pred, dstBase);
+void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
- FieldDecl *field = dyn_cast<FieldDecl>(M->getMemberDecl());
+ Decl *member = M->getMemberDecl();
+ if (VarDecl *VD = dyn_cast<VarDecl>(member)) {
+ assert(M->isLValue());
+ VisitCommonDeclRefExpr(M, VD, Pred, Dst);
+ return;
+ }
+
+ FieldDecl *field = dyn_cast<FieldDecl>(member);
if (!field) // FIXME: skipping member expressions for non-fields
return;
- for (ExplodedNodeSet::iterator I = dstBase.begin(), E = dstBase.end();
- I != E; ++I) {
- const GRState* state = GetState(*I);
- SVal baseExprVal = state->getSVal(baseExpr);
- if (isa<nonloc::LazyCompoundVal>(baseExprVal) ||
- isa<nonloc::CompoundVal>(baseExprVal) ||
- // FIXME: This can originate by conjuring a symbol for an unknown
- // temporary struct object, see test/Analysis/fields.c:
- // (p = getit()).x
- isa<nonloc::SymbolVal>(baseExprVal)) {
- MakeNode(Dst, M, *I, state->BindExpr(M, UnknownVal()));
- continue;
- }
+ Expr *baseExpr = M->getBase()->IgnoreParens();
+ const ProgramState *state = Pred->getState();
+ SVal baseExprVal = state->getSVal(baseExpr);
+ if (isa<nonloc::LazyCompoundVal>(baseExprVal) ||
+ isa<nonloc::CompoundVal>(baseExprVal) ||
+ // FIXME: This can originate by conjuring a symbol for an unknown
+ // temporary struct object, see test/Analysis/fields.c:
+ // (p = getit()).x
+ isa<nonloc::SymbolVal>(baseExprVal)) {
+ MakeNode(Dst, M, Pred, state->BindExpr(M, UnknownVal()));
+ return;
+ }
- // FIXME: Should we insert some assumption logic in here to determine
- // if "Base" is a valid piece of memory? Before we put this assumption
- // later when using FieldOffset lvals (which we no longer have).
+ // FIXME: Should we insert some assumption logic in here to determine
+ // if "Base" is a valid piece of memory? Before we put this assumption
+ // later when using FieldOffset lvals (which we no longer have).
- // For all other cases, compute an lvalue.
- SVal L = state->getLValue(field, baseExprVal);
- if (M->isLValue())
- MakeNode(Dst, M, *I, state->BindExpr(M, L), ProgramPoint::PostLValueKind);
- else
- evalLoad(Dst, M, *I, state, L);
- }
+ // For all other cases, compute an lvalue.
+ SVal L = state->getLValue(field, baseExprVal);
+ if (M->isLValue())
+ MakeNode(Dst, M, Pred, state->BindExpr(M, L), ProgramPoint::PostLValueKind);
+ else
+ evalLoad(Dst, M, Pred, state, L);
}
/// 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,
- ExplodedNode* Pred, const GRState* state,
- SVal location, SVal Val, bool atDeclInit) {
-
+void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
+ ExplodedNode *Pred,
+ SVal location, SVal Val, bool atDeclInit) {
// Do a previsit of the bind.
- ExplodedNodeSet CheckedSet, Src;
- Src.Add(Pred);
- getCheckerManager().runCheckersForBind(CheckedSet, Src, location, Val, StoreE,
- *this);
+ ExplodedNodeSet CheckedSet;
+ getCheckerManager().runCheckersForBind(CheckedSet, Pred, location, Val,
+ StoreE, *this);
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
I!=E; ++I) {
- if (Pred != *I)
- state = GetState(*I);
-
- const GRState* newState = 0;
+ const ProgramState *state = (*I)->getState();
if (atDeclInit) {
const VarRegion *VR =
cast<VarRegion>(cast<loc::MemRegionVal>(location).getRegion());
- newState = state->bindDecl(VR, Val);
- }
- else {
- if (location.isUnknown()) {
- // We know that the new state will be the same as the old state since
- // the location of the binding is "unknown". Consequently, there
- // is no reason to just create a new node.
- newState = state;
- }
- else {
- // We are binding to a value other than 'unknown'. Perform the binding
- // using the StoreManager.
- newState = state->bindLoc(cast<Loc>(location), Val);
- }
+ state = state->bindDecl(VR, Val);
+ } else {
+ state = state->bindLoc(location, Val);
}
- // The next thing to do is check if the TransferFuncs object wants to
- // update the state based on the new binding. If the GRTransferFunc object
- // doesn't do anything, just auto-propagate the current state.
-
- // NOTE: We use 'AssignE' for the location of the PostStore if 'AssignE'
- // is non-NULL. Checkers typically care about
-
- StmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, newState, StoreE,
- true);
-
- getTF().evalBind(BuilderRef, location, Val);
+ MakeNode(Dst, StoreE, *I, state);
}
}
@@ -1460,11 +1300,11 @@ void ExprEngine::evalBind(ExplodedNodeSet& Dst, const Stmt* StoreE,
/// @param state The current simulation state
/// @param location The location to store the value
/// @param Val The value to be stored
-void ExprEngine::evalStore(ExplodedNodeSet& Dst, const Expr *AssignE,
- const Expr* LocationE,
- ExplodedNode* Pred,
- const GRState* state, SVal location, SVal Val,
- const void *tag) {
+void ExprEngine::evalStore(ExplodedNodeSet &Dst, const Expr *AssignE,
+ const Expr *LocationE,
+ ExplodedNode *Pred,
+ const ProgramState *state, SVal location, SVal Val,
+ const ProgramPointTag *tag) {
assert(Builder && "StmtNodeBuilder must be defined.");
@@ -1474,9 +1314,8 @@ void ExprEngine::evalStore(ExplodedNodeSet& Dst, const Expr *AssignE,
if (isa<loc::ObjCPropRef>(location)) {
loc::ObjCPropRef prop = cast<loc::ObjCPropRef>(location);
- ExplodedNodeSet src = Pred;
return VisitObjCMessage(ObjCPropertySetter(prop.getPropRefExpr(),
- StoreE, Val), src, Dst);
+ StoreE, Val), Pred, Dst);
}
// Evaluate the location (checks for bad dereferences).
@@ -1493,38 +1332,38 @@ void ExprEngine::evalStore(ExplodedNodeSet& Dst, const Expr *AssignE,
ProgramPoint::PostStoreKind);
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
- evalBind(Dst, StoreE, *NI, GetState(*NI), location, Val);
+ evalBind(Dst, StoreE, *NI, location, Val);
}
-void ExprEngine::evalLoad(ExplodedNodeSet& Dst, const Expr *Ex,
- ExplodedNode* Pred,
- const GRState* state, SVal location,
- const void *tag, QualType LoadTy) {
+void ExprEngine::evalLoad(ExplodedNodeSet &Dst, const Expr *Ex,
+ ExplodedNode *Pred,
+ const ProgramState *state, SVal location,
+ const ProgramPointTag *tag, QualType LoadTy) {
assert(!isa<NonLoc>(location) && "location cannot be a NonLoc.");
if (isa<loc::ObjCPropRef>(location)) {
loc::ObjCPropRef prop = cast<loc::ObjCPropRef>(location);
- ExplodedNodeSet src = Pred;
return VisitObjCMessage(ObjCPropertyGetter(prop.getPropRefExpr(), Ex),
- src, Dst);
+ Pred, Dst);
}
// 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
// referenced value.
- if (const TypedRegion *TR =
- dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
+ if (const TypedValueRegion *TR =
+ dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
QualType ValTy = TR->getValueType();
if (const ReferenceType *RT = ValTy->getAs<ReferenceType>()) {
- static int loadReferenceTag = 0;
+ static SimpleProgramPointTag
+ loadReferenceTag("ExprEngine : Load Reference");
ExplodedNodeSet Tmp;
evalLoadCommon(Tmp, Ex, Pred, state, location, &loadReferenceTag,
getContext().getPointerType(RT->getPointeeType()));
// Perform the load from the referenced value.
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end() ; I!=E; ++I) {
- state = GetState(*I);
+ state = (*I)->getState();
location = state->getSVal(Ex);
evalLoadCommon(Dst, Ex, *I, state, location, tag, LoadTy);
}
@@ -1535,10 +1374,10 @@ void ExprEngine::evalLoad(ExplodedNodeSet& Dst, const Expr *Ex,
evalLoadCommon(Dst, Ex, Pred, state, location, tag, LoadTy);
}
-void ExprEngine::evalLoadCommon(ExplodedNodeSet& Dst, const Expr *Ex,
- ExplodedNode* Pred,
- const GRState* state, SVal location,
- const void *tag, QualType LoadTy) {
+void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst, const Expr *Ex,
+ ExplodedNode *Pred,
+ const ProgramState *state, SVal location,
+ const ProgramPointTag *tag, QualType LoadTy) {
// Evaluate the location (checks for bad dereferences).
ExplodedNodeSet Tmp;
@@ -1554,7 +1393,7 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet& Dst, const Expr *Ex,
// Proceed with the load.
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
- state = GetState(*NI);
+ state = (*NI)->getState();
if (location.isUnknown()) {
// This is important. We must nuke the old binding.
@@ -1572,9 +1411,9 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet& Dst, const Expr *Ex,
}
void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S,
- ExplodedNode* Pred,
- const GRState* state, SVal location,
- const void *tag, bool isLoad) {
+ ExplodedNode *Pred,
+ const ProgramState *state, SVal location,
+ const ProgramPointTag *tag, bool isLoad) {
// Early checks for performance reason.
if (location.isUnknown()) {
Dst.Add(Pred);
@@ -1582,7 +1421,7 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S,
}
ExplodedNodeSet Src;
- if (Builder->GetState(Pred) == state) {
+ if (Pred->getState() == state) {
Src.Add(Pred);
} else {
// Associate this new state with an ExplodedNode.
@@ -1593,7 +1432,11 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S,
// "p = 0" is not noted as "Null pointer value stored to 'p'" but
// instead "int *p" is noted as
// "Variable 'p' initialized to a null pointer value"
- ExplodedNode *N = Builder->generateNode(S, state, Pred, this);
+
+ // FIXME: why is 'tag' not used instead of etag?
+ static SimpleProgramPointTag etag("ExprEngine: Location");
+
+ ExplodedNode *N = Builder->generateNode(S, state, Pred, &etag);
Src.Add(N ? N : Pred);
}
getCheckerManager().runCheckersForLocation(Dst, Src, location, isLoad, S,
@@ -1611,7 +1454,7 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
// cases as well.
#if 0
- const GRState *state = GetState(Pred);
+ const ProgramState *state = Pred->getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
@@ -1627,7 +1470,7 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
case Stmt::CXXOperatorCallExprClass: {
const CXXOperatorCallExpr *opCall = cast<CXXOperatorCallExpr>(CE);
methodDecl =
- llvm::dyn_cast_or_null<CXXMethodDecl>(opCall->getCalleeDecl());
+ dyn_cast_or_null<CXXMethodDecl>(opCall->getCalleeDecl());
break;
}
case Stmt::CXXMemberCallExprClass: {
@@ -1676,126 +1519,18 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
#endif
}
-void ExprEngine::VisitCallExpr(const CallExpr* CE, ExplodedNode* Pred,
- ExplodedNodeSet& dst) {
-
- // Determine the type of function we're calling (if available).
- const FunctionProtoType *Proto = NULL;
- QualType FnType = CE->getCallee()->IgnoreParens()->getType();
- if (const PointerType *FnTypePtr = FnType->getAs<PointerType>())
- Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>();
-
- // Should the first argument be evaluated as an lvalue?
- bool firstArgumentAsLvalue = false;
- switch (CE->getStmtClass()) {
- case Stmt::CXXOperatorCallExprClass:
- firstArgumentAsLvalue = true;
- break;
- default:
- break;
- }
-
- // Evaluate the arguments.
- ExplodedNodeSet dstArgsEvaluated;
- evalArguments(CE->arg_begin(), CE->arg_end(), Proto, Pred, dstArgsEvaluated,
- firstArgumentAsLvalue);
-
- // Evaluate the callee.
- ExplodedNodeSet dstCalleeEvaluated;
- evalCallee(CE, dstArgsEvaluated, dstCalleeEvaluated);
-
- // Perform the previsit of the CallExpr.
- ExplodedNodeSet dstPreVisit;
- getCheckerManager().runCheckersForPreStmt(dstPreVisit, dstCalleeEvaluated,
- CE, *this);
-
- // Now evaluate the call itself.
- class DefaultEval : public GraphExpander {
- ExprEngine &Eng;
- const CallExpr *CE;
- public:
-
- DefaultEval(ExprEngine &eng, const CallExpr *ce)
- : Eng(eng), CE(ce) {}
- virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) {
- // Should we inline the call?
- if (Eng.getAnalysisManager().shouldInlineCall() &&
- Eng.InlineCall(Dst, CE, Pred)) {
- return;
- }
-
- StmtNodeBuilder &Builder = Eng.getBuilder();
- assert(&Builder && "StmtNodeBuilder must be defined.");
-
- // Dispatch to the plug-in transfer function.
- unsigned oldSize = Dst.size();
- SaveOr OldHasGen(Builder.hasGeneratedNode);
-
- // Dispatch to transfer function logic to handle the call itself.
- const Expr* Callee = CE->getCallee()->IgnoreParens();
- const GRState* state = Eng.GetState(Pred);
- SVal L = state->getSVal(Callee);
- Eng.getTF().evalCall(Dst, Eng, Builder, CE, L, Pred);
-
- // Handle the case where no nodes where generated. Auto-generate that
- // contains the updated state if we aren't generating sinks.
- if (!Builder.BuildSinks && Dst.size() == oldSize &&
- !Builder.hasGeneratedNode)
- Eng.MakeNode(Dst, CE, Pred, state);
- }
- };
-
- // Finally, evaluate the function call. We try each of the checkers
- // to see if the can evaluate the function call.
- ExplodedNodeSet dstCallEvaluated;
- DefaultEval defEval(*this, CE);
- getCheckerManager().runCheckersForEvalCall(dstCallEvaluated,
- dstPreVisit,
- CE, *this, &defEval);
-
- // Finally, perform the post-condition check of the CallExpr and store
- // the created nodes in 'Dst'.
- getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE,
- *this);
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer function: Objective-C dot-syntax to access a property.
-//===----------------------------------------------------------------------===//
-
-void ExprEngine::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Ex,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- ExplodedNodeSet dstBase;
-
- // Visit the receiver (if any).
- if (Ex->isObjectReceiver())
- Visit(Ex->getBase(), Pred, dstBase);
- else
- dstBase = Pred;
-
- ExplodedNodeSet dstPropRef;
-
- // Using the base, compute the lvalue of the instance variable.
- for (ExplodedNodeSet::iterator I = dstBase.begin(), E = dstBase.end();
- I!=E; ++I) {
- ExplodedNode *nodeBase = *I;
- const GRState *state = GetState(nodeBase);
- MakeNode(dstPropRef, Ex, *I, state->BindExpr(Ex, loc::ObjCPropRef(Ex)));
- }
-
- Dst.insert(dstPropRef);
+std::pair<const ProgramPointTag *, const ProgramPointTag*>
+ExprEngine::getEagerlyAssumeTags() {
+ static SimpleProgramPointTag
+ EagerlyAssumeTrue("ExprEngine : Eagerly Assume True"),
+ EagerlyAssumeFalse("ExprEngine : Eagerly Assume False");
+ return std::make_pair(&EagerlyAssumeTrue, &EagerlyAssumeFalse);
}
-//===----------------------------------------------------------------------===//
-// Transfer function: Objective-C ivar references.
-//===----------------------------------------------------------------------===//
-
-static std::pair<const void*,const void*> EagerlyAssumeTag
- = std::pair<const void*,const void*>(&EagerlyAssumeTag,static_cast<void*>(0));
-
void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
const Expr *Ex) {
+
+
for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) {
ExplodedNode *Pred = *I;
@@ -1808,25 +1543,24 @@ void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
continue;
}
- const GRState* state = GetState(Pred);
+ const ProgramState *state = Pred->getState();
SVal V = state->getSVal(Ex);
if (nonloc::SymExprVal *SEV = dyn_cast<nonloc::SymExprVal>(&V)) {
+ const std::pair<const ProgramPointTag *, const ProgramPointTag*> &tags =
+ getEagerlyAssumeTags();
+
// First assume that the condition is true.
- if (const GRState *stateTrue = state->assume(*SEV, true)) {
- stateTrue = stateTrue->BindExpr(Ex,
- svalBuilder.makeIntVal(1U, Ex->getType()));
- Dst.Add(Builder->generateNode(PostStmtCustom(Ex,
- &EagerlyAssumeTag, Pred->getLocationContext()),
- stateTrue, Pred));
+ if (const ProgramState *StateTrue = state->assume(*SEV, true)) {
+ SVal Val = svalBuilder.makeIntVal(1U, Ex->getType());
+ StateTrue = StateTrue->BindExpr(Ex, Val);
+ Dst.Add(Builder->generateNode(Ex, StateTrue, Pred, tags.first));
}
// Next, assume that the condition is false.
- if (const GRState *stateFalse = state->assume(*SEV, false)) {
- stateFalse = stateFalse->BindExpr(Ex,
- svalBuilder.makeIntVal(0U, Ex->getType()));
- Dst.Add(Builder->generateNode(PostStmtCustom(Ex, &EagerlyAssumeTag,
- Pred->getLocationContext()),
- stateFalse, Pred));
+ if (const ProgramState *StateFalse = state->assume(*SEV, false)) {
+ SVal Val = svalBuilder.makeIntVal(0U, Ex->getType());
+ StateFalse = StateFalse->BindExpr(Ex, Val);
+ Dst.Add(Builder->generateNode(Ex, StateFalse, Pred, tags.second));
}
}
else
@@ -1834,954 +1568,15 @@ void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
}
}
-//===----------------------------------------------------------------------===//
-// Transfer function: Objective-C @synchronized.
-//===----------------------------------------------------------------------===//
-
-void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
-
- // The mutex expression is a CFGElement, so we don't need to explicitly
- // visit it since it will already be processed.
-
- // Pre-visit the ObjCAtSynchronizedStmt.
- ExplodedNodeSet Tmp;
- Tmp.Add(Pred);
- getCheckerManager().runCheckersForPreStmt(Dst, Tmp, S, *this);
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer function: Objective-C ivar references.
-//===----------------------------------------------------------------------===//
-
-void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr* Ex,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
-
- // Visit the base expression, which is needed for computing the lvalue
- // of the ivar.
- ExplodedNodeSet dstBase;
- const Expr *baseExpr = Ex->getBase();
- Visit(baseExpr, Pred, dstBase);
-
- ExplodedNodeSet dstIvar;
-
- // Using the base, compute the lvalue of the instance variable.
- for (ExplodedNodeSet::iterator I = dstBase.begin(), E = dstBase.end();
- I!=E; ++I) {
- ExplodedNode *nodeBase = *I;
- const GRState *state = GetState(nodeBase);
- SVal baseVal = state->getSVal(baseExpr);
- SVal location = state->getLValue(Ex->getDecl(), baseVal);
- MakeNode(dstIvar, Ex, *I, state->BindExpr(Ex, location));
- }
-
- // Perform the post-condition check of the ObjCIvarRefExpr and store
- // the created nodes in 'Dst'.
- getCheckerManager().runCheckersForPostStmt(Dst, dstIvar, Ex, *this);
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer function: Objective-C fast enumeration 'for' statements.
-//===----------------------------------------------------------------------===//
-
-void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt* S,
- ExplodedNode* Pred, ExplodedNodeSet& Dst) {
-
- // ObjCForCollectionStmts are processed in two places. This method
- // handles the case where an ObjCForCollectionStmt* occurs as one of the
- // statements within a basic block. This transfer function does two things:
- //
- // (1) binds the next container value to 'element'. This creates a new
- // node in the ExplodedGraph.
- //
- // (2) binds the value 0/1 to the ObjCForCollectionStmt* itself, indicating
- // whether or not the container has any more elements. This value
- // will be tested in ProcessBranch. We need to explicitly bind
- // this value because a container can contain nil elements.
- //
- // FIXME: Eventually this logic should actually do dispatches to
- // 'countByEnumeratingWithState:objects:count:' (NSFastEnumeration).
- // This will require simulating a temporary NSFastEnumerationState, either
- // through an SVal or through the use of MemRegions. This value can
- // be affixed to the ObjCForCollectionStmt* instead of 0/1; when the loop
- // terminates we reclaim the temporary (it goes out of scope) and we
- // we can test if the SVal is 0 or if the MemRegion is null (depending
- // on what approach we take).
- //
- // For now: simulate (1) by assigning either a symbol or nil if the
- // container is empty. Thus this transfer function will by default
- // result in state splitting.
-
- const Stmt* elem = S->getElement();
- SVal ElementV;
-
- if (const DeclStmt* DS = dyn_cast<DeclStmt>(elem)) {
- const VarDecl* ElemD = cast<VarDecl>(DS->getSingleDecl());
- assert (ElemD->getInit() == 0);
- ElementV = GetState(Pred)->getLValue(ElemD, Pred->getLocationContext());
- VisitObjCForCollectionStmtAux(S, Pred, Dst, ElementV);
- return;
- }
-
- ExplodedNodeSet Tmp;
- Visit(cast<Expr>(elem), Pred, Tmp);
- for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
- const GRState* state = GetState(*I);
- VisitObjCForCollectionStmtAux(S, *I, Dst, state->getSVal(elem));
- }
-}
-
-void ExprEngine::VisitObjCForCollectionStmtAux(const ObjCForCollectionStmt* S,
- ExplodedNode* Pred, ExplodedNodeSet& Dst,
- SVal ElementV) {
-
- // Check if the location we are writing back to is a null pointer.
- const Stmt* elem = S->getElement();
- ExplodedNodeSet Tmp;
- evalLocation(Tmp, elem, Pred, GetState(Pred), ElementV, NULL, false);
-
- if (Tmp.empty())
- return;
-
- for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
- Pred = *NI;
- const GRState *state = GetState(Pred);
-
- // Handle the case where the container still has elements.
- SVal TrueV = svalBuilder.makeTruthVal(1);
- const GRState *hasElems = state->BindExpr(S, TrueV);
-
- // Handle the case where the container has no elements.
- SVal FalseV = svalBuilder.makeTruthVal(0);
- const GRState *noElems = state->BindExpr(S, FalseV);
-
- if (loc::MemRegionVal* MV = dyn_cast<loc::MemRegionVal>(&ElementV))
- if (const TypedRegion* R = dyn_cast<TypedRegion>(MV->getRegion())) {
- // FIXME: The proper thing to do is to really iterate over the
- // container. We will do this with dispatch logic to the store.
- // For now, just 'conjure' up a symbolic value.
- QualType T = R->getValueType();
- assert(Loc::isLocType(T));
- unsigned Count = Builder->getCurrentBlockCount();
- SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count);
- SVal V = svalBuilder.makeLoc(Sym);
- hasElems = hasElems->bindLoc(ElementV, V);
-
- // Bind the location to 'nil' on the false branch.
- SVal nilV = svalBuilder.makeIntVal(0, T);
- noElems = noElems->bindLoc(ElementV, nilV);
- }
-
- // Create the new nodes.
- MakeNode(Dst, S, Pred, hasElems);
- MakeNode(Dst, S, Pred, noElems);
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer function: Objective-C message expressions.
-//===----------------------------------------------------------------------===//
-
-namespace {
-class ObjCMsgWLItem {
-public:
- ObjCMessageExpr::const_arg_iterator I;
- ExplodedNode *N;
-
- ObjCMsgWLItem(const ObjCMessageExpr::const_arg_iterator &i, ExplodedNode *n)
- : I(i), N(n) {}
-};
-} // end anonymous namespace
-
-void ExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst){
-
- // Create a worklist to process both the arguments.
- llvm::SmallVector<ObjCMsgWLItem, 20> WL;
-
- // But first evaluate the receiver (if any).
- ObjCMessageExpr::const_arg_iterator AI = ME->arg_begin(), AE = ME->arg_end();
- if (const Expr *Receiver = ME->getInstanceReceiver()) {
- ExplodedNodeSet Tmp;
- Visit(Receiver, Pred, Tmp);
-
- if (Tmp.empty())
- return;
-
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I)
- WL.push_back(ObjCMsgWLItem(AI, *I));
- }
- else
- WL.push_back(ObjCMsgWLItem(AI, Pred));
-
- // Evaluate the arguments.
- ExplodedNodeSet ArgsEvaluated;
- while (!WL.empty()) {
- ObjCMsgWLItem Item = WL.back();
- WL.pop_back();
-
- if (Item.I == AE) {
- ArgsEvaluated.insert(Item.N);
- continue;
- }
-
- // Evaluate the subexpression.
- ExplodedNodeSet Tmp;
-
- // FIXME: [Objective-C++] handle arguments that are references
- Visit(*Item.I, Item.N, Tmp);
-
- // Enqueue evaluating the next argument on the worklist.
- ++(Item.I);
- for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
- WL.push_back(ObjCMsgWLItem(Item.I, *NI));
- }
-
- // Now that the arguments are processed, handle the ObjC message.
- VisitObjCMessage(ME, ArgsEvaluated, Dst);
-}
-
-void ExprEngine::VisitObjCMessage(const ObjCMessage &msg,
- ExplodedNodeSet &Src, ExplodedNodeSet& Dst) {
-
- // Handle the previsits checks.
- ExplodedNodeSet DstPrevisit;
- getCheckerManager().runCheckersForPreObjCMessage(DstPrevisit, Src, msg,*this);
-
- // Proceed with evaluate the message expression.
- ExplodedNodeSet dstEval;
-
- for (ExplodedNodeSet::iterator DI = DstPrevisit.begin(),
- DE = DstPrevisit.end(); DI != DE; ++DI) {
-
- ExplodedNode *Pred = *DI;
- bool RaisesException = false;
- unsigned oldSize = dstEval.size();
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- SaveOr OldHasGen(Builder->hasGeneratedNode);
-
- if (const Expr *Receiver = msg.getInstanceReceiver()) {
- const GRState *state = GetState(Pred);
- SVal recVal = state->getSVal(Receiver);
- if (!recVal.isUndef()) {
- // Bifurcate the state into nil and non-nil ones.
- DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
-
- const GRState *notNilState, *nilState;
- llvm::tie(notNilState, nilState) = state->assume(receiverVal);
-
- // There are three cases: can be nil or non-nil, must be nil, must be
- // non-nil. We ignore must be nil, and merge the rest two into non-nil.
- if (nilState && !notNilState) {
- dstEval.insert(Pred);
- continue;
- }
-
- // Check if the "raise" message was sent.
- assert(notNilState);
- if (msg.getSelector() == RaiseSel)
- RaisesException = true;
-
- // Check if we raise an exception. For now treat these as sinks.
- // Eventually we will want to handle exceptions properly.
- if (RaisesException)
- Builder->BuildSinks = true;
-
- // Dispatch to plug-in transfer function.
- evalObjCMessage(dstEval, msg, Pred, notNilState);
- }
- }
- else if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) {
- IdentifierInfo* ClsName = Iface->getIdentifier();
- Selector S = msg.getSelector();
-
- // Check for special instance methods.
- if (!NSExceptionII) {
- ASTContext& Ctx = getContext();
- NSExceptionII = &Ctx.Idents.get("NSException");
- }
-
- if (ClsName == NSExceptionII) {
- enum { NUM_RAISE_SELECTORS = 2 };
-
- // Lazily create a cache of the selectors.
- if (!NSExceptionInstanceRaiseSelectors) {
- ASTContext& Ctx = getContext();
- NSExceptionInstanceRaiseSelectors =
- new Selector[NUM_RAISE_SELECTORS];
- llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
- unsigned idx = 0;
-
- // raise:format:
- II.push_back(&Ctx.Idents.get("raise"));
- II.push_back(&Ctx.Idents.get("format"));
- NSExceptionInstanceRaiseSelectors[idx++] =
- Ctx.Selectors.getSelector(II.size(), &II[0]);
-
- // raise:format::arguments:
- II.push_back(&Ctx.Idents.get("arguments"));
- NSExceptionInstanceRaiseSelectors[idx++] =
- Ctx.Selectors.getSelector(II.size(), &II[0]);
- }
-
- for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i)
- if (S == NSExceptionInstanceRaiseSelectors[i]) {
- RaisesException = true;
- break;
- }
- }
-
- // Check if we raise an exception. For now treat these as sinks.
- // Eventually we will want to handle exceptions properly.
- if (RaisesException)
- Builder->BuildSinks = true;
-
- // Dispatch to plug-in transfer function.
- evalObjCMessage(dstEval, msg, Pred, Builder->GetState(Pred));
- }
-
- // Handle the case where no nodes where generated. Auto-generate that
- // contains the updated state if we aren't generating sinks.
- if (!Builder->BuildSinks && dstEval.size() == oldSize &&
- !Builder->hasGeneratedNode)
- MakeNode(dstEval, msg.getOriginExpr(), Pred, GetState(Pred));
- }
-
- // Finally, perform the post-condition check of the ObjCMessageExpr and store
- // the created nodes in 'Dst'.
- getCheckerManager().runCheckersForPostObjCMessage(Dst, dstEval, msg, *this);
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer functions: Miscellaneous statements.
-//===----------------------------------------------------------------------===//
-
-void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
- ExplodedNode *Pred, ExplodedNodeSet &Dst) {
-
- ExplodedNodeSet S1;
- Visit(Ex, Pred, S1);
- ExplodedNodeSet S2;
- getCheckerManager().runCheckersForPreStmt(S2, S1, CastE, *this);
-
- if (CastE->getCastKind() == CK_LValueToRValue ||
- CastE->getCastKind() == CK_GetObjCProperty) {
- for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I!=E; ++I) {
- ExplodedNode *subExprNode = *I;
- const GRState *state = GetState(subExprNode);
- evalLoad(Dst, CastE, subExprNode, state, state->getSVal(Ex));
- }
- return;
- }
-
- // All other casts.
- QualType T = CastE->getType();
- QualType ExTy = Ex->getType();
-
- if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE))
- T = ExCast->getTypeAsWritten();
-
- for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
- Pred = *I;
-
- switch (CastE->getCastKind()) {
- case CK_LValueToRValue:
- assert(false && "LValueToRValue casts handled earlier.");
- case CK_GetObjCProperty:
- assert(false && "GetObjCProperty casts handled earlier.");
- case CK_ToVoid:
- Dst.Add(Pred);
- continue;
- // The analyzer doesn't do anything special with these casts,
- // since it understands retain/release semantics already.
- case CK_ObjCProduceObject:
- case CK_ObjCConsumeObject:
- case CK_ObjCReclaimReturnedObject: // Fall-through.
- // True no-ops.
- case CK_NoOp:
- case CK_FunctionToPointerDecay: {
- // Copy the SVal of Ex to CastE.
- const GRState *state = GetState(Pred);
- SVal V = state->getSVal(Ex);
- state = state->BindExpr(CastE, V);
- MakeNode(Dst, CastE, Pred, state);
- continue;
- }
- case CK_Dependent:
- case CK_ArrayToPointerDecay:
- case CK_BitCast:
- case CK_LValueBitCast:
- case CK_IntegralCast:
- case CK_NullToPointer:
- case CK_IntegralToPointer:
- case CK_PointerToIntegral:
- case CK_PointerToBoolean:
- case CK_IntegralToBoolean:
- case CK_IntegralToFloating:
- case CK_FloatingToIntegral:
- case CK_FloatingToBoolean:
- case CK_FloatingCast:
- case CK_FloatingRealToComplex:
- case CK_FloatingComplexToReal:
- case CK_FloatingComplexToBoolean:
- case CK_FloatingComplexCast:
- case CK_FloatingComplexToIntegralComplex:
- case CK_IntegralRealToComplex:
- case CK_IntegralComplexToReal:
- case CK_IntegralComplexToBoolean:
- case CK_IntegralComplexCast:
- case CK_IntegralComplexToFloatingComplex:
- case CK_AnyPointerToObjCPointerCast:
- case CK_AnyPointerToBlockPointerCast:
- case CK_ObjCObjectLValueCast: {
- // Delegate to SValBuilder to process.
- const GRState* state = GetState(Pred);
- SVal V = state->getSVal(Ex);
- V = svalBuilder.evalCast(V, T, ExTy);
- state = state->BindExpr(CastE, V);
- MakeNode(Dst, CastE, Pred, state);
- continue;
- }
- case CK_DerivedToBase:
- case CK_UncheckedDerivedToBase: {
- // For DerivedToBase cast, delegate to the store manager.
- const GRState *state = GetState(Pred);
- SVal val = state->getSVal(Ex);
- val = getStoreManager().evalDerivedToBase(val, T);
- state = state->BindExpr(CastE, val);
- MakeNode(Dst, CastE, Pred, state);
- continue;
- }
- // Various C++ casts that are not handled yet.
- case CK_Dynamic:
- case CK_ToUnion:
- case CK_BaseToDerived:
- case CK_NullToMemberPointer:
- case CK_BaseToDerivedMemberPointer:
- case CK_DerivedToBaseMemberPointer:
- case CK_UserDefinedConversion:
- case CK_ConstructorConversion:
- case CK_VectorSplat:
- case CK_MemberPointerToBoolean: {
- // Recover some path-sensitivty by conjuring a new value.
- QualType resultType = CastE->getType();
- if (CastE->isLValue())
- resultType = getContext().getPointerType(resultType);
-
- SVal result =
- svalBuilder.getConjuredSymbolVal(NULL, CastE, resultType,
- Builder->getCurrentBlockCount());
-
- const GRState *state = GetState(Pred)->BindExpr(CastE, result);
- MakeNode(Dst, CastE, Pred, state);
- continue;
- }
- }
- }
-}
-
-void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr* CL,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
- const InitListExpr* ILE
- = cast<InitListExpr>(CL->getInitializer()->IgnoreParens());
- ExplodedNodeSet Tmp;
- Visit(ILE, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I!=EI; ++I) {
- const GRState* state = GetState(*I);
- SVal ILV = state->getSVal(ILE);
- const LocationContext *LC = (*I)->getLocationContext();
- state = state->bindCompoundLiteral(CL, LC, ILV);
-
- if (CL->isLValue()) {
- MakeNode(Dst, CL, *I, state->BindExpr(CL, state->getLValue(CL, LC)));
- }
- else
- MakeNode(Dst, CL, *I, state->BindExpr(CL, ILV));
- }
-}
-
-void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
- ExplodedNodeSet& Dst) {
-
- // The CFG has one DeclStmt per Decl.
- const Decl* D = *DS->decl_begin();
-
- if (!D || !isa<VarDecl>(D))
- return;
-
- const VarDecl* VD = dyn_cast<VarDecl>(D);
- const Expr* InitEx = VD->getInit();
-
- // FIXME: static variables may have an initializer, but the second
- // time a function is called those values may not be current.
- ExplodedNodeSet Tmp;
-
- if (InitEx)
- Visit(InitEx, Pred, Tmp);
- else
- Tmp.Add(Pred);
-
- ExplodedNodeSet Tmp2;
- getCheckerManager().runCheckersForPreStmt(Tmp2, Tmp, DS, *this);
-
- for (ExplodedNodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I) {
- ExplodedNode *N = *I;
- const GRState *state = GetState(N);
-
- // Decls without InitExpr are not initialized explicitly.
- const LocationContext *LC = N->getLocationContext();
-
- if (InitEx) {
- SVal InitVal = state->getSVal(InitEx);
-
- // We bound the temp obj region to the CXXConstructExpr. Now recover
- // the lazy compound value when the variable is not a reference.
- if (AMgr.getLangOptions().CPlusPlus && VD->getType()->isRecordType() &&
- !VD->getType()->isReferenceType() && isa<loc::MemRegionVal>(InitVal)){
- InitVal = state->getSVal(cast<loc::MemRegionVal>(InitVal).getRegion());
- assert(isa<nonloc::LazyCompoundVal>(InitVal));
- }
-
- // Recover some path-sensitivity if a scalar value evaluated to
- // UnknownVal.
- if ((InitVal.isUnknown() ||
- !getConstraintManager().canReasonAbout(InitVal)) &&
- !VD->getType()->isReferenceType()) {
- InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx,
- Builder->getCurrentBlockCount());
- }
-
- evalBind(Dst, DS, *I, state,
- loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
- }
- else {
- state = state->bindDeclWithNoInit(state->getRegion(VD, LC));
- MakeNode(Dst, DS, *I, state);
- }
- }
-}
-
-namespace {
- // This class is used by VisitInitListExpr as an item in a worklist
- // for processing the values contained in an InitListExpr.
-class InitListWLItem {
-public:
- llvm::ImmutableList<SVal> Vals;
- ExplodedNode* N;
- InitListExpr::const_reverse_iterator Itr;
-
- InitListWLItem(ExplodedNode* n, llvm::ImmutableList<SVal> vals,
- InitListExpr::const_reverse_iterator itr)
- : Vals(vals), N(n), Itr(itr) {}
-};
-}
-
-
-void ExprEngine::VisitInitListExpr(const InitListExpr* E, ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
-
- const GRState* state = GetState(Pred);
- QualType T = getContext().getCanonicalType(E->getType());
- unsigned NumInitElements = E->getNumInits();
-
- if (T->isArrayType() || T->isRecordType() || T->isVectorType()) {
- llvm::ImmutableList<SVal> StartVals = getBasicVals().getEmptySValList();
-
- // Handle base case where the initializer has no elements.
- // e.g: static int* myArray[] = {};
- if (NumInitElements == 0) {
- SVal V = svalBuilder.makeCompoundVal(T, StartVals);
- MakeNode(Dst, E, Pred, state->BindExpr(E, V));
- return;
- }
-
- // Create a worklist to process the initializers.
- llvm::SmallVector<InitListWLItem, 10> WorkList;
- WorkList.reserve(NumInitElements);
- WorkList.push_back(InitListWLItem(Pred, StartVals, E->rbegin()));
- InitListExpr::const_reverse_iterator ItrEnd = E->rend();
- assert(!(E->rbegin() == E->rend()));
-
- // Process the worklist until it is empty.
- while (!WorkList.empty()) {
- InitListWLItem X = WorkList.back();
- WorkList.pop_back();
-
- ExplodedNodeSet Tmp;
- Visit(*X.Itr, X.N, Tmp);
-
- InitListExpr::const_reverse_iterator NewItr = X.Itr + 1;
-
- for (ExplodedNodeSet::iterator NI=Tmp.begin(),NE=Tmp.end();NI!=NE;++NI) {
- // Get the last initializer value.
- state = GetState(*NI);
- SVal InitV = state->getSVal(cast<Expr>(*X.Itr));
-
- // Construct the new list of values by prepending the new value to
- // the already constructed list.
- llvm::ImmutableList<SVal> NewVals =
- getBasicVals().consVals(InitV, X.Vals);
-
- if (NewItr == ItrEnd) {
- // Now we have a list holding all init values. Make CompoundValData.
- SVal V = svalBuilder.makeCompoundVal(T, NewVals);
-
- // Make final state and node.
- MakeNode(Dst, E, *NI, state->BindExpr(E, V));
- }
- else {
- // Still some initializer values to go. Push them onto the worklist.
- WorkList.push_back(InitListWLItem(*NI, NewVals, NewItr));
- }
- }
- }
-
- return;
- }
-
- if (Loc::isLocType(T) || T->isIntegerType()) {
- assert (E->getNumInits() == 1);
- ExplodedNodeSet Tmp;
- const Expr* Init = E->getInit(0);
- Visit(Init, Pred, Tmp);
- for (ExplodedNodeSet::iterator I=Tmp.begin(), EI=Tmp.end(); I != EI; ++I) {
- state = GetState(*I);
- MakeNode(Dst, E, *I, state->BindExpr(E, state->getSVal(Init)));
- }
- return;
- }
-
- assert(0 && "unprocessed InitListExpr type");
-}
-
-/// VisitUnaryExprOrTypeTraitExpr - Transfer function for sizeof(type).
-void ExprEngine::VisitUnaryExprOrTypeTraitExpr(
- const UnaryExprOrTypeTraitExpr* Ex,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
- QualType T = Ex->getTypeOfArgument();
-
- if (Ex->getKind() == UETT_SizeOf) {
- if (!T->isIncompleteType() && !T->isConstantSizeType()) {
- assert(T->isVariableArrayType() && "Unknown non-constant-sized type.");
-
- // FIXME: Add support for VLA type arguments, not just VLA expressions.
- // When that happens, we should probably refactor VLASizeChecker's code.
- if (Ex->isArgumentType()) {
- Dst.Add(Pred);
- return;
- }
-
- // Get the size by getting the extent of the sub-expression.
- // First, visit the sub-expression to find its region.
- const Expr *Arg = Ex->getArgumentExpr();
- ExplodedNodeSet Tmp;
- Visit(Arg, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- const GRState* state = GetState(*I);
- const MemRegion *MR = state->getSVal(Arg).getAsRegion();
-
- // If the subexpression can't be resolved to a region, we don't know
- // anything about its size. Just leave the state as is and continue.
- if (!MR) {
- Dst.Add(*I);
- continue;
- }
-
- // The result is the extent of the VLA.
- SVal Extent = cast<SubRegion>(MR)->getExtent(svalBuilder);
- MakeNode(Dst, Ex, *I, state->BindExpr(Ex, Extent));
- }
-
- return;
- }
- else if (T->getAs<ObjCObjectType>()) {
- // Some code tries to take the sizeof an ObjCObjectType, relying that
- // the compiler has laid out its representation. Just report Unknown
- // for these.
- Dst.Add(Pred);
- return;
- }
- }
-
- Expr::EvalResult Result;
- Ex->Evaluate(Result, getContext());
- CharUnits amt = CharUnits::fromQuantity(Result.Val.getInt().getZExtValue());
-
- MakeNode(Dst, Ex, Pred,
- GetState(Pred)->BindExpr(Ex,
- svalBuilder.makeIntVal(amt.getQuantity(), Ex->getType())));
-}
-
-void ExprEngine::VisitOffsetOfExpr(const OffsetOfExpr* OOE,
- ExplodedNode* Pred, ExplodedNodeSet& Dst) {
- Expr::EvalResult Res;
- if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) {
- const APSInt &IV = Res.Val.getInt();
- assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType()));
- assert(OOE->getType()->isIntegerType());
- assert(IV.isSigned() == OOE->getType()->isSignedIntegerOrEnumerationType());
- SVal X = svalBuilder.makeIntVal(IV);
- MakeNode(Dst, OOE, Pred, GetState(Pred)->BindExpr(OOE, X));
- return;
- }
- // FIXME: Handle the case where __builtin_offsetof is not a constant.
- Dst.Add(Pred);
-}
-
-void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
-
- switch (U->getOpcode()) {
-
- default:
- break;
-
- case UO_Real: {
- const Expr* Ex = U->getSubExpr()->IgnoreParens();
- ExplodedNodeSet Tmp;
- Visit(Ex, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
-
- // FIXME: We don't have complex SValues yet.
- if (Ex->getType()->isAnyComplexType()) {
- // Just report "Unknown."
- Dst.Add(*I);
- continue;
- }
-
- // For all other types, UO_Real is an identity operation.
- assert (U->getType() == Ex->getType());
- const GRState* state = GetState(*I);
- MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex)));
- }
-
- return;
- }
-
- case UO_Imag: {
-
- const Expr* Ex = U->getSubExpr()->IgnoreParens();
- ExplodedNodeSet Tmp;
- Visit(Ex, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- // FIXME: We don't have complex SValues yet.
- if (Ex->getType()->isAnyComplexType()) {
- // Just report "Unknown."
- Dst.Add(*I);
- continue;
- }
-
- // For all other types, UO_Imag returns 0.
- const GRState* state = GetState(*I);
- SVal X = svalBuilder.makeZeroVal(Ex->getType());
- MakeNode(Dst, U, *I, state->BindExpr(U, X));
- }
-
- return;
- }
-
- case UO_Plus:
- assert(!U->isLValue());
- // FALL-THROUGH.
- case UO_Deref:
- case UO_AddrOf:
- case UO_Extension: {
-
- // Unary "+" is a no-op, similar to a parentheses. We still have places
- // where it may be a block-level expression, so we need to
- // generate an extra node that just propagates the value of the
- // subexpression.
-
- const Expr* Ex = U->getSubExpr()->IgnoreParens();
- ExplodedNodeSet Tmp;
- Visit(Ex, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- const GRState* state = GetState(*I);
- MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex)));
- }
-
- return;
- }
-
- case UO_LNot:
- case UO_Minus:
- case UO_Not: {
- assert (!U->isLValue());
- const Expr* Ex = U->getSubExpr()->IgnoreParens();
- ExplodedNodeSet Tmp;
- Visit(Ex, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- const GRState* state = GetState(*I);
-
- // Get the value of the subexpression.
- SVal V = state->getSVal(Ex);
-
- if (V.isUnknownOrUndef()) {
- MakeNode(Dst, U, *I, state->BindExpr(U, V));
- continue;
- }
-
-// QualType DstT = getContext().getCanonicalType(U->getType());
-// QualType SrcT = getContext().getCanonicalType(Ex->getType());
-//
-// if (DstT != SrcT) // Perform promotions.
-// V = evalCast(V, DstT);
-//
-// if (V.isUnknownOrUndef()) {
-// MakeNode(Dst, U, *I, BindExpr(St, U, V));
-// continue;
-// }
-
- switch (U->getOpcode()) {
- default:
- assert(false && "Invalid Opcode.");
- break;
-
- case UO_Not:
- // FIXME: Do we need to handle promotions?
- state = state->BindExpr(U, evalComplement(cast<NonLoc>(V)));
- break;
-
- case UO_Minus:
- // FIXME: Do we need to handle promotions?
- state = state->BindExpr(U, evalMinus(cast<NonLoc>(V)));
- break;
-
- case UO_LNot:
-
- // C99 6.5.3.3: "The expression !E is equivalent to (0==E)."
- //
- // Note: technically we do "E == 0", but this is the same in the
- // transfer functions as "0 == E".
- SVal Result;
-
- if (isa<Loc>(V)) {
- Loc X = svalBuilder.makeNull();
- Result = evalBinOp(state, BO_EQ, cast<Loc>(V), X,
- U->getType());
- }
- else {
- nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
- Result = evalBinOp(state, BO_EQ, cast<NonLoc>(V), X,
- U->getType());
- }
-
- state = state->BindExpr(U, Result);
-
- break;
- }
-
- MakeNode(Dst, U, *I, state);
- }
-
- return;
- }
- }
-
- // Handle ++ and -- (both pre- and post-increment).
- assert (U->isIncrementDecrementOp());
- ExplodedNodeSet Tmp;
- const Expr* Ex = U->getSubExpr()->IgnoreParens();
- Visit(Ex, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
-
- const GRState* state = GetState(*I);
- SVal loc = state->getSVal(Ex);
-
- // Perform a load.
- ExplodedNodeSet Tmp2;
- evalLoad(Tmp2, Ex, *I, state, loc);
-
- for (ExplodedNodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end();I2!=E2;++I2) {
-
- state = GetState(*I2);
- SVal V2_untested = state->getSVal(Ex);
-
- // Propagate unknown and undefined values.
- if (V2_untested.isUnknownOrUndef()) {
- MakeNode(Dst, U, *I2, state->BindExpr(U, V2_untested));
- continue;
- }
- DefinedSVal V2 = cast<DefinedSVal>(V2_untested);
-
- // Handle all other values.
- BinaryOperator::Opcode Op = U->isIncrementOp() ? BO_Add
- : BO_Sub;
-
- // If the UnaryOperator has non-location type, use its type to create the
- // constant value. If the UnaryOperator has location type, create the
- // constant with int type and pointer width.
- SVal RHS;
-
- if (U->getType()->isAnyPointerType())
- RHS = svalBuilder.makeArrayIndex(1);
- else
- RHS = svalBuilder.makeIntVal(1, U->getType());
-
- SVal Result = evalBinOp(state, Op, V2, RHS, U->getType());
-
- // Conjure a new symbol if necessary to recover precision.
- if (Result.isUnknown() || !getConstraintManager().canReasonAbout(Result)){
- DefinedOrUnknownSVal SymVal =
- svalBuilder.getConjuredSymbolVal(NULL, Ex,
- Builder->getCurrentBlockCount());
- Result = SymVal;
-
- // If the value is a location, ++/-- should always preserve
- // non-nullness. Check if the original value was non-null, and if so
- // propagate that constraint.
- if (Loc::isLocType(U->getType())) {
- DefinedOrUnknownSVal Constraint =
- svalBuilder.evalEQ(state, V2,svalBuilder.makeZeroVal(U->getType()));
-
- if (!state->assume(Constraint, true)) {
- // It isn't feasible for the original value to be null.
- // Propagate this constraint.
- Constraint = svalBuilder.evalEQ(state, SymVal,
- svalBuilder.makeZeroVal(U->getType()));
-
-
- state = state->assume(Constraint, false);
- assert(state);
- }
- }
- }
-
- // Since the lvalue-to-rvalue conversion is explicit in the AST,
- // we bind an l-value if the operator is prefix and an lvalue (in C++).
- if (U->isLValue())
- state = state->BindExpr(U, loc);
- else
- state = state->BindExpr(U, U->isPostfix() ? V2 : Result);
-
- // Perform the store.
- evalStore(Dst, NULL, U, *I2, state, loc, Result);
- }
- }
-}
-
-void ExprEngine::VisitAsmStmt(const AsmStmt* A, ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
+void ExprEngine::VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst);
}
-void ExprEngine::VisitAsmStmtHelperOutputs(const AsmStmt* A,
+void ExprEngine::VisitAsmStmtHelperOutputs(const AsmStmt *A,
AsmStmt::const_outputs_iterator I,
AsmStmt::const_outputs_iterator E,
- ExplodedNode* Pred, ExplodedNodeSet& Dst) {
+ ExplodedNode *Pred, ExplodedNodeSet &Dst) {
if (I == E) {
VisitAsmStmtHelperInputs(A, A->begin_inputs(), A->end_inputs(), Pred, Dst);
return;
@@ -2795,11 +1590,11 @@ void ExprEngine::VisitAsmStmtHelperOutputs(const AsmStmt* A,
VisitAsmStmtHelperOutputs(A, I, E, *NI, Dst);
}
-void ExprEngine::VisitAsmStmtHelperInputs(const AsmStmt* A,
+void ExprEngine::VisitAsmStmtHelperInputs(const AsmStmt *A,
AsmStmt::const_inputs_iterator I,
AsmStmt::const_inputs_iterator E,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
if (I == E) {
// We have processed both the inputs and the outputs. All of the outputs
@@ -2809,7 +1604,7 @@ void ExprEngine::VisitAsmStmtHelperInputs(const AsmStmt* A,
// which interprets the inline asm and stores proper results in the
// outputs.
- const GRState* state = GetState(Pred);
+ const ProgramState *state = Pred->getState();
for (AsmStmt::const_outputs_iterator OI = A->begin_outputs(),
OE = A->end_outputs(); OI != OE; ++OI) {
@@ -2834,198 +1629,6 @@ void ExprEngine::VisitAsmStmtHelperInputs(const AsmStmt* A,
VisitAsmStmtHelperInputs(A, I, E, *NI, Dst);
}
-void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- ExplodedNodeSet Src;
- if (const Expr *RetE = RS->getRetValue()) {
- // Record the returned expression in the state. It will be used in
- // processCallExit to bind the return value to the call expr.
- {
- static int tag = 0;
- const GRState *state = GetState(Pred);
- state = state->set<ReturnExpr>(RetE);
- Pred = Builder->generateNode(RetE, state, Pred, &tag);
- }
- // We may get a NULL Pred because we generated a cached node.
- if (Pred)
- Visit(RetE, Pred, Src);
- }
- else {
- Src.Add(Pred);
- }
-
- ExplodedNodeSet CheckedSet;
- getCheckerManager().runCheckersForPreStmt(CheckedSet, Src, RS, *this);
-
- for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
- I != E; ++I) {
-
- assert(Builder && "StmtNodeBuilder must be defined.");
-
- Pred = *I;
- unsigned size = Dst.size();
-
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- SaveOr OldHasGen(Builder->hasGeneratedNode);
-
- getTF().evalReturn(Dst, *this, *Builder, RS, Pred);
-
- // Handle the case where no nodes where generated.
- if (!Builder->BuildSinks && Dst.size() == size &&
- !Builder->hasGeneratedNode)
- MakeNode(Dst, RS, Pred, GetState(Pred));
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer functions: Binary operators.
-//===----------------------------------------------------------------------===//
-
-void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
- ExplodedNodeSet Tmp1;
- Expr* LHS = B->getLHS()->IgnoreParens();
- Expr* RHS = B->getRHS()->IgnoreParens();
-
- Visit(LHS, Pred, Tmp1);
- ExplodedNodeSet Tmp3;
-
- for (ExplodedNodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1!=E1; ++I1) {
- SVal LeftV = GetState(*I1)->getSVal(LHS);
- ExplodedNodeSet Tmp2;
- Visit(RHS, *I1, Tmp2);
-
- ExplodedNodeSet CheckedSet;
- getCheckerManager().runCheckersForPreStmt(CheckedSet, Tmp2, B, *this);
-
- // With both the LHS and RHS evaluated, process the operation itself.
-
- for (ExplodedNodeSet::iterator I2=CheckedSet.begin(), E2=CheckedSet.end();
- I2 != E2; ++I2) {
-
- const GRState *state = GetState(*I2);
- SVal RightV = state->getSVal(RHS);
-
- BinaryOperator::Opcode Op = B->getOpcode();
-
- if (Op == BO_Assign) {
- // EXPERIMENTAL: "Conjured" symbols.
- // FIXME: Handle structs.
- if (RightV.isUnknown() ||!getConstraintManager().canReasonAbout(RightV))
- {
- unsigned Count = Builder->getCurrentBlockCount();
- RightV = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), Count);
- }
-
- SVal ExprVal = B->isLValue() ? LeftV : RightV;
-
- // Simulate the effects of a "store": bind the value of the RHS
- // to the L-Value represented by the LHS.
- evalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV,RightV);
- continue;
- }
-
- if (!B->isAssignmentOp()) {
- // Process non-assignments except commas or short-circuited
- // logical expressions (LAnd and LOr).
- SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType());
-
- if (Result.isUnknown()) {
- MakeNode(Tmp3, B, *I2, state);
- continue;
- }
-
- state = state->BindExpr(B, Result);
-
- MakeNode(Tmp3, B, *I2, state);
- continue;
- }
-
- assert (B->isCompoundAssignmentOp());
-
- switch (Op) {
- default:
- assert(0 && "Invalid opcode for compound assignment.");
- case BO_MulAssign: Op = BO_Mul; break;
- case BO_DivAssign: Op = BO_Div; break;
- case BO_RemAssign: Op = BO_Rem; break;
- case BO_AddAssign: Op = BO_Add; break;
- case BO_SubAssign: Op = BO_Sub; break;
- case BO_ShlAssign: Op = BO_Shl; break;
- case BO_ShrAssign: Op = BO_Shr; break;
- case BO_AndAssign: Op = BO_And; break;
- case BO_XorAssign: Op = BO_Xor; break;
- case BO_OrAssign: Op = BO_Or; break;
- }
-
- // Perform a load (the LHS). This performs the checks for
- // null dereferences, and so on.
- ExplodedNodeSet Tmp4;
- SVal location = state->getSVal(LHS);
- evalLoad(Tmp4, LHS, *I2, state, location);
-
- for (ExplodedNodeSet::iterator I4=Tmp4.begin(), E4=Tmp4.end(); I4!=E4;
- ++I4) {
- state = GetState(*I4);
- SVal V = state->getSVal(LHS);
-
- // Get the computation type.
- QualType CTy =
- cast<CompoundAssignOperator>(B)->getComputationResultType();
- CTy = getContext().getCanonicalType(CTy);
-
- QualType CLHSTy =
- cast<CompoundAssignOperator>(B)->getComputationLHSType();
- CLHSTy = getContext().getCanonicalType(CLHSTy);
-
- QualType LTy = getContext().getCanonicalType(LHS->getType());
-
- // Promote LHS.
- V = svalBuilder.evalCast(V, CLHSTy, LTy);
-
- // Compute the result of the operation.
- SVal Result = svalBuilder.evalCast(evalBinOp(state, Op, V, RightV, CTy),
- B->getType(), CTy);
-
- // EXPERIMENTAL: "Conjured" symbols.
- // FIXME: Handle structs.
-
- SVal LHSVal;
-
- if (Result.isUnknown() ||
- !getConstraintManager().canReasonAbout(Result)) {
-
- unsigned Count = Builder->getCurrentBlockCount();
-
- // The symbolic value is actually for the type of the left-hand side
- // expression, not the computation type, as this is the value the
- // LValue on the LHS will bind to.
- LHSVal = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), LTy, Count);
-
- // However, we need to convert the symbol to the computation type.
- Result = svalBuilder.evalCast(LHSVal, CTy, LTy);
- }
- else {
- // The left-hand side may bind to a different value then the
- // computation type.
- LHSVal = svalBuilder.evalCast(Result, LTy, CTy);
- }
-
- // In C++, assignment and compound assignment operators return an
- // lvalue.
- if (B->isLValue())
- state = state->BindExpr(B, location);
- else
- state = state->BindExpr(B, Result);
-
- evalStore(Tmp3, B, LHS, *I4, state, location, LHSVal);
- }
- }
- }
-
- getCheckerManager().runCheckersForPostStmt(Dst, Tmp3, B, *this);
-}
//===----------------------------------------------------------------------===//
// Visualization.
@@ -3044,7 +1647,7 @@ struct DOTGraphTraits<ExplodedNode*> :
// FIXME: Since we do not cache error nodes in ExprEngine now, this does not
// work.
- static std::string getNodeAttributes(const ExplodedNode* N, void*) {
+ static std::string getNodeAttributes(const ExplodedNode *N, void*) {
#if 0
// FIXME: Replace with a general scheme to tell if the node is
@@ -3065,7 +1668,7 @@ struct DOTGraphTraits<ExplodedNode*> :
return "";
}
- static std::string getNodeLabel(const ExplodedNode* N, void*){
+ static std::string getNodeLabel(const ExplodedNode *N, void*){
std::string sbuf;
llvm::raw_string_ostream Out(sbuf);
@@ -3093,7 +1696,7 @@ struct DOTGraphTraits<ExplodedNode*> :
default: {
if (StmtPoint *L = dyn_cast<StmtPoint>(&Loc)) {
- const Stmt* S = L->getStmt();
+ const Stmt *S = L->getStmt();
SourceLocation SLoc = S->getLocStart();
Out << S->getStmtClassName() << ' ' << (void*) S << ' ';
@@ -3102,9 +1705,9 @@ struct DOTGraphTraits<ExplodedNode*> :
if (SLoc.isFileID()) {
Out << "\\lline="
- << GraphPrintSourceManager->getInstantiationLineNumber(SLoc)
+ << GraphPrintSourceManager->getExpansionLineNumber(SLoc)
<< " col="
- << GraphPrintSourceManager->getInstantiationColumnNumber(SLoc)
+ << GraphPrintSourceManager->getExpansionColumnNumber(SLoc)
<< "\\l";
}
@@ -3141,11 +1744,11 @@ struct DOTGraphTraits<ExplodedNode*> :
break;
}
- const BlockEdge& E = cast<BlockEdge>(Loc);
+ const BlockEdge &E = cast<BlockEdge>(Loc);
Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B"
<< E.getDst()->getBlockID() << ')';
- if (const Stmt* T = E.getSrc()->getTerminator()) {
+ if (const Stmt *T = E.getSrc()->getTerminator()) {
SourceLocation SLoc = T->getLocStart();
@@ -3155,21 +1758,21 @@ struct DOTGraphTraits<ExplodedNode*> :
if (SLoc.isFileID()) {
Out << "\\lline="
- << GraphPrintSourceManager->getInstantiationLineNumber(SLoc)
+ << GraphPrintSourceManager->getExpansionLineNumber(SLoc)
<< " col="
- << GraphPrintSourceManager->getInstantiationColumnNumber(SLoc);
+ << GraphPrintSourceManager->getExpansionColumnNumber(SLoc);
}
if (isa<SwitchStmt>(T)) {
- const Stmt* Label = E.getDst()->getLabel();
+ const Stmt *Label = E.getDst()->getLabel();
if (Label) {
- if (const CaseStmt* C = dyn_cast<CaseStmt>(Label)) {
+ if (const CaseStmt *C = dyn_cast<CaseStmt>(Label)) {
Out << "\\lcase ";
LangOptions LO; // FIXME.
C->getLHS()->printPretty(Out, 0, PrintingPolicy(LO));
- if (const Stmt* RHS = C->getRHS()) {
+ if (const Stmt *RHS = C->getRHS()) {
Out << " .. ";
RHS->printPretty(Out, 0, PrintingPolicy(LO));
}
@@ -3208,11 +1811,17 @@ struct DOTGraphTraits<ExplodedNode*> :
}
}
- const GRState *state = N->getState();
+ const ProgramState *state = N->getState();
Out << "\\|StateID: " << (void*) state
<< " NodeID: " << (void*) N << "\\|";
state->printDOT(Out, *N->getLocationContext()->getCFG());
- Out << "\\l";
+
+ Out << "\\l";
+
+ if (const ProgramPointTag *tag = Loc.getTag()) {
+ Out << "\\|Tag: " << tag->getTagDescription();
+ Out << "\\l";
+ }
return Out.str();
}
};
@@ -3221,7 +1830,7 @@ struct DOTGraphTraits<ExplodedNode*> :
#ifndef NDEBUG
template <typename ITERATOR>
-ExplodedNode* GetGraphNode(ITERATOR I) { return *I; }
+ExplodedNode *GetGraphNode(ITERATOR I) { return *I; }
template <> ExplodedNode*
GetGraphNode<llvm::DenseMap<ExplodedNode*, Expr*>::iterator>
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
new file mode 100644
index 000000000000..68ccc59ac952
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -0,0 +1,752 @@
+//=-- ExprEngineC.cpp - ExprEngine support for C expressions ----*- 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 ExprEngine's support for C expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/Analysis/Support/SaveAndRestore.h"
+
+using namespace clang;
+using namespace ento;
+using llvm::APSInt;
+
+void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+
+ Expr *LHS = B->getLHS()->IgnoreParens();
+ Expr *RHS = B->getRHS()->IgnoreParens();
+
+ // FIXME: Prechecks eventually go in ::Visit().
+ ExplodedNodeSet CheckedSet;
+ ExplodedNodeSet Tmp2;
+ getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, B, *this);
+
+ // With both the LHS and RHS evaluated, process the operation itself.
+ for (ExplodedNodeSet::iterator it=CheckedSet.begin(), ei=CheckedSet.end();
+ it != ei; ++it) {
+
+ const ProgramState *state = (*it)->getState();
+ SVal LeftV = state->getSVal(LHS);
+ SVal RightV = state->getSVal(RHS);
+
+ BinaryOperator::Opcode Op = B->getOpcode();
+
+ if (Op == BO_Assign) {
+ // EXPERIMENTAL: "Conjured" symbols.
+ // FIXME: Handle structs.
+ if (RightV.isUnknown() ||
+ !getConstraintManager().canReasonAbout(RightV)) {
+ unsigned Count = Builder->getCurrentBlockCount();
+ RightV = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), Count);
+ }
+ // Simulate the effects of a "store": bind the value of the RHS
+ // to the L-Value represented by the LHS.
+ SVal ExprVal = B->isLValue() ? LeftV : RightV;
+ evalStore(Tmp2, B, LHS, *it, state->BindExpr(B, ExprVal), LeftV, RightV);
+ continue;
+ }
+
+ if (!B->isAssignmentOp()) {
+ // Process non-assignments except commas or short-circuited
+ // logical expressions (LAnd and LOr).
+ SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType());
+ if (Result.isUnknown()) {
+ MakeNode(Tmp2, B, *it, state);
+ continue;
+ }
+
+ state = state->BindExpr(B, Result);
+ MakeNode(Tmp2, B, *it, state);
+ continue;
+ }
+
+ assert (B->isCompoundAssignmentOp());
+
+ switch (Op) {
+ default:
+ llvm_unreachable("Invalid opcode for compound assignment.");
+ case BO_MulAssign: Op = BO_Mul; break;
+ case BO_DivAssign: Op = BO_Div; break;
+ case BO_RemAssign: Op = BO_Rem; break;
+ case BO_AddAssign: Op = BO_Add; break;
+ case BO_SubAssign: Op = BO_Sub; break;
+ case BO_ShlAssign: Op = BO_Shl; break;
+ case BO_ShrAssign: Op = BO_Shr; break;
+ case BO_AndAssign: Op = BO_And; break;
+ case BO_XorAssign: Op = BO_Xor; break;
+ case BO_OrAssign: Op = BO_Or; break;
+ }
+
+ // Perform a load (the LHS). This performs the checks for
+ // null dereferences, and so on.
+ ExplodedNodeSet Tmp;
+ SVal location = LeftV;
+ evalLoad(Tmp, LHS, *it, state, location);
+
+ for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E;
+ ++I) {
+
+ state = (*I)->getState();
+ SVal V = state->getSVal(LHS);
+
+ // Get the computation type.
+ QualType CTy =
+ cast<CompoundAssignOperator>(B)->getComputationResultType();
+ CTy = getContext().getCanonicalType(CTy);
+
+ QualType CLHSTy =
+ cast<CompoundAssignOperator>(B)->getComputationLHSType();
+ CLHSTy = getContext().getCanonicalType(CLHSTy);
+
+ QualType LTy = getContext().getCanonicalType(LHS->getType());
+
+ // Promote LHS.
+ V = svalBuilder.evalCast(V, CLHSTy, LTy);
+
+ // Compute the result of the operation.
+ SVal Result = svalBuilder.evalCast(evalBinOp(state, Op, V, RightV, CTy),
+ B->getType(), CTy);
+
+ // EXPERIMENTAL: "Conjured" symbols.
+ // FIXME: Handle structs.
+
+ SVal LHSVal;
+
+ if (Result.isUnknown() ||
+ !getConstraintManager().canReasonAbout(Result)) {
+
+ unsigned Count = Builder->getCurrentBlockCount();
+
+ // The symbolic value is actually for the type of the left-hand side
+ // expression, not the computation type, as this is the value the
+ // LValue on the LHS will bind to.
+ LHSVal = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), LTy,
+ Count);
+
+ // However, we need to convert the symbol to the computation type.
+ Result = svalBuilder.evalCast(LHSVal, CTy, LTy);
+ }
+ else {
+ // The left-hand side may bind to a different value then the
+ // computation type.
+ LHSVal = svalBuilder.evalCast(Result, LTy, CTy);
+ }
+
+ // In C++, assignment and compound assignment operators return an
+ // lvalue.
+ if (B->isLValue())
+ state = state->BindExpr(B, location);
+ else
+ state = state->BindExpr(B, Result);
+
+ evalStore(Tmp2, B, LHS, *I, state, location, LHSVal);
+ }
+ }
+
+ // FIXME: postvisits eventually go in ::Visit()
+ getCheckerManager().runCheckersForPostStmt(Dst, Tmp2, B, *this);
+}
+
+void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+
+ CanQualType T = getContext().getCanonicalType(BE->getType());
+ SVal V = svalBuilder.getBlockPointer(BE->getBlockDecl(), T,
+ Pred->getLocationContext());
+
+ ExplodedNodeSet Tmp;
+ MakeNode(Tmp, BE, Pred, Pred->getState()->BindExpr(BE, V),
+ ProgramPoint::PostLValueKind);
+
+ // FIXME: Move all post/pre visits to ::Visit().
+ getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this);
+}
+
+void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst) {
+
+ ExplodedNodeSet dstPreStmt;
+ getCheckerManager().runCheckersForPreStmt(dstPreStmt, Pred, CastE, *this);
+
+ if (CastE->getCastKind() == CK_LValueToRValue ||
+ CastE->getCastKind() == CK_GetObjCProperty) {
+ for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end();
+ I!=E; ++I) {
+ ExplodedNode *subExprNode = *I;
+ const ProgramState *state = subExprNode->getState();
+ evalLoad(Dst, CastE, subExprNode, state, state->getSVal(Ex));
+ }
+ return;
+ }
+
+ // All other casts.
+ QualType T = CastE->getType();
+ QualType ExTy = Ex->getType();
+
+ if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE))
+ T = ExCast->getTypeAsWritten();
+
+ for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end();
+ I != E; ++I) {
+
+ Pred = *I;
+
+ switch (CastE->getCastKind()) {
+ case CK_LValueToRValue:
+ llvm_unreachable("LValueToRValue casts handled earlier.");
+ case CK_GetObjCProperty:
+ llvm_unreachable("GetObjCProperty casts handled earlier.");
+ case CK_ToVoid:
+ Dst.Add(Pred);
+ continue;
+ // The analyzer doesn't do anything special with these casts,
+ // since it understands retain/release semantics already.
+ case CK_ARCProduceObject:
+ case CK_ARCConsumeObject:
+ case CK_ARCReclaimReturnedObject:
+ case CK_ARCExtendBlockObject: // Fall-through.
+ // True no-ops.
+ case CK_NoOp:
+ case CK_FunctionToPointerDecay: {
+ // Copy the SVal of Ex to CastE.
+ const ProgramState *state = Pred->getState();
+ SVal V = state->getSVal(Ex);
+ state = state->BindExpr(CastE, V);
+ MakeNode(Dst, CastE, Pred, state);
+ continue;
+ }
+ case CK_Dependent:
+ case CK_ArrayToPointerDecay:
+ case CK_BitCast:
+ case CK_LValueBitCast:
+ case CK_IntegralCast:
+ case CK_NullToPointer:
+ case CK_IntegralToPointer:
+ case CK_PointerToIntegral:
+ case CK_PointerToBoolean:
+ case CK_IntegralToBoolean:
+ case CK_IntegralToFloating:
+ case CK_FloatingToIntegral:
+ case CK_FloatingToBoolean:
+ case CK_FloatingCast:
+ case CK_FloatingRealToComplex:
+ case CK_FloatingComplexToReal:
+ case CK_FloatingComplexToBoolean:
+ case CK_FloatingComplexCast:
+ case CK_FloatingComplexToIntegralComplex:
+ case CK_IntegralRealToComplex:
+ case CK_IntegralComplexToReal:
+ case CK_IntegralComplexToBoolean:
+ case CK_IntegralComplexCast:
+ case CK_IntegralComplexToFloatingComplex:
+ case CK_CPointerToObjCPointerCast:
+ case CK_BlockPointerToObjCPointerCast:
+ case CK_AnyPointerToBlockPointerCast:
+ case CK_ObjCObjectLValueCast: {
+ // Delegate to SValBuilder to process.
+ const ProgramState *state = Pred->getState();
+ SVal V = state->getSVal(Ex);
+ V = svalBuilder.evalCast(V, T, ExTy);
+ state = state->BindExpr(CastE, V);
+ MakeNode(Dst, CastE, Pred, state);
+ continue;
+ }
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase: {
+ // For DerivedToBase cast, delegate to the store manager.
+ const ProgramState *state = Pred->getState();
+ SVal val = state->getSVal(Ex);
+ val = getStoreManager().evalDerivedToBase(val, T);
+ state = state->BindExpr(CastE, val);
+ MakeNode(Dst, CastE, Pred, state);
+ continue;
+ }
+ // Various C++ casts that are not handled yet.
+ case CK_Dynamic:
+ case CK_ToUnion:
+ case CK_BaseToDerived:
+ case CK_NullToMemberPointer:
+ case CK_BaseToDerivedMemberPointer:
+ case CK_DerivedToBaseMemberPointer:
+ case CK_UserDefinedConversion:
+ case CK_ConstructorConversion:
+ case CK_VectorSplat:
+ case CK_MemberPointerToBoolean: {
+ // Recover some path-sensitivty by conjuring a new value.
+ QualType resultType = CastE->getType();
+ if (CastE->isLValue())
+ resultType = getContext().getPointerType(resultType);
+
+ SVal result =
+ svalBuilder.getConjuredSymbolVal(NULL, CastE, resultType,
+ Builder->getCurrentBlockCount());
+
+ const ProgramState *state = Pred->getState()->BindExpr(CastE, result);
+ MakeNode(Dst, CastE, Pred, state);
+ continue;
+ }
+ }
+ }
+}
+
+void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ const InitListExpr *ILE
+ = cast<InitListExpr>(CL->getInitializer()->IgnoreParens());
+
+ const ProgramState *state = Pred->getState();
+ SVal ILV = state->getSVal(ILE);
+ const LocationContext *LC = Pred->getLocationContext();
+ state = state->bindCompoundLiteral(CL, LC, ILV);
+
+ if (CL->isLValue())
+ MakeNode(Dst, CL, Pred, state->BindExpr(CL, state->getLValue(CL, LC)));
+ else
+ MakeNode(Dst, CL, Pred, state->BindExpr(CL, ILV));
+}
+
+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))
+ return;
+
+ // FIXME: all pre/post visits should eventually be handled by ::Visit().
+ ExplodedNodeSet dstPreVisit;
+ getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this);
+
+ const VarDecl *VD = dyn_cast<VarDecl>(D);
+
+ for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end();
+ I!=E; ++I) {
+ ExplodedNode *N = *I;
+ const ProgramState *state = N->getState();
+
+ // Decls without InitExpr are not initialized explicitly.
+ const LocationContext *LC = N->getLocationContext();
+
+ if (const Expr *InitEx = VD->getInit()) {
+ SVal InitVal = state->getSVal(InitEx);
+
+ // We bound the temp obj region to the CXXConstructExpr. Now recover
+ // the lazy compound value when the variable is not a reference.
+ if (AMgr.getLangOptions().CPlusPlus && VD->getType()->isRecordType() &&
+ !VD->getType()->isReferenceType() && isa<loc::MemRegionVal>(InitVal)){
+ InitVal = state->getSVal(cast<loc::MemRegionVal>(InitVal).getRegion());
+ assert(isa<nonloc::LazyCompoundVal>(InitVal));
+ }
+
+ // Recover some path-sensitivity if a scalar value evaluated to
+ // UnknownVal.
+ if ((InitVal.isUnknown() ||
+ !getConstraintManager().canReasonAbout(InitVal)) &&
+ !VD->getType()->isReferenceType()) {
+ InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx,
+ Builder->getCurrentBlockCount());
+ }
+
+ evalBind(Dst, DS, N, state->getLValue(VD, LC), InitVal, true);
+ }
+ else {
+ MakeNode(Dst, DS, N, state->bindDeclWithNoInit(state->getRegion(VD, LC)));
+ }
+ }
+}
+
+void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+
+ assert(B->getOpcode() == BO_LAnd ||
+ B->getOpcode() == BO_LOr);
+
+ const ProgramState *state = Pred->getState();
+ SVal X = state->getSVal(B);
+ assert(X.isUndef());
+
+ const Expr *Ex = (const Expr*) cast<UndefinedVal>(X).getData();
+ assert(Ex);
+
+ if (Ex == B->getRHS()) {
+ X = state->getSVal(Ex);
+
+ // Handle undefined values.
+ if (X.isUndef()) {
+ MakeNode(Dst, B, Pred, state->BindExpr(B, X));
+ return;
+ }
+
+ DefinedOrUnknownSVal XD = cast<DefinedOrUnknownSVal>(X);
+
+ // We took the RHS. Because the value of the '&&' or '||' expression must
+ // evaluate to 0 or 1, we must assume the value of the RHS evaluates to 0
+ // or 1. Alternatively, we could take a lazy approach, and calculate this
+ // value later when necessary. We don't have the machinery in place for
+ // this right now, and since most logical expressions are used for branches,
+ // the payoff is not likely to be large. Instead, we do eager evaluation.
+ if (const ProgramState *newState = state->assume(XD, true))
+ MakeNode(Dst, B, Pred,
+ newState->BindExpr(B, svalBuilder.makeIntVal(1U, B->getType())));
+
+ if (const ProgramState *newState = state->assume(XD, false))
+ MakeNode(Dst, B, Pred,
+ newState->BindExpr(B, svalBuilder.makeIntVal(0U, B->getType())));
+ }
+ else {
+ // We took the LHS expression. Depending on whether we are '&&' or
+ // '||' we know what the value of the expression is via properties of
+ // the short-circuiting.
+ X = svalBuilder.makeIntVal(B->getOpcode() == BO_LAnd ? 0U : 1U,
+ B->getType());
+ MakeNode(Dst, B, Pred, state->BindExpr(B, X));
+ }
+}
+
+void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+
+ const ProgramState *state = Pred->getState();
+ QualType T = getContext().getCanonicalType(IE->getType());
+ unsigned NumInitElements = IE->getNumInits();
+
+ if (T->isArrayType() || T->isRecordType() || T->isVectorType()) {
+ llvm::ImmutableList<SVal> vals = getBasicVals().getEmptySValList();
+
+ // Handle base case where the initializer has no elements.
+ // e.g: static int* myArray[] = {};
+ if (NumInitElements == 0) {
+ SVal V = svalBuilder.makeCompoundVal(T, vals);
+ MakeNode(Dst, IE, Pred, state->BindExpr(IE, V));
+ return;
+ }
+
+ for (InitListExpr::const_reverse_iterator it = IE->rbegin(),
+ ei = IE->rend(); it != ei; ++it) {
+ vals = getBasicVals().consVals(state->getSVal(cast<Expr>(*it)), vals);
+ }
+
+ MakeNode(Dst, IE, Pred,
+ state->BindExpr(IE, svalBuilder.makeCompoundVal(T, vals)));
+ return;
+ }
+
+ if (Loc::isLocType(T) || T->isIntegerType()) {
+ assert(IE->getNumInits() == 1);
+ const Expr *initEx = IE->getInit(0);
+ MakeNode(Dst, IE, Pred, state->BindExpr(IE, state->getSVal(initEx)));
+ return;
+ }
+
+ llvm_unreachable("unprocessed InitListExpr type");
+}
+
+void ExprEngine::VisitGuardedExpr(const Expr *Ex,
+ const Expr *L,
+ const Expr *R,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+
+ const ProgramState *state = Pred->getState();
+ SVal X = state->getSVal(Ex);
+ assert (X.isUndef());
+ const Expr *SE = (Expr*) cast<UndefinedVal>(X).getData();
+ assert(SE);
+ X = state->getSVal(SE);
+
+ // Make sure that we invalidate the previous binding.
+ MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, X, true));
+}
+
+void ExprEngine::
+VisitOffsetOfExpr(const OffsetOfExpr *OOE,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst) {
+ Expr::EvalResult Res;
+ if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) {
+ const APSInt &IV = Res.Val.getInt();
+ assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType()));
+ assert(OOE->getType()->isIntegerType());
+ assert(IV.isSigned() == OOE->getType()->isSignedIntegerOrEnumerationType());
+ SVal X = svalBuilder.makeIntVal(IV);
+ MakeNode(Dst, OOE, Pred, Pred->getState()->BindExpr(OOE, X));
+ return;
+ }
+ // FIXME: Handle the case where __builtin_offsetof is not a constant.
+ Dst.Add(Pred);
+}
+
+
+void ExprEngine::
+VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+
+ QualType T = Ex->getTypeOfArgument();
+
+ if (Ex->getKind() == UETT_SizeOf) {
+ if (!T->isIncompleteType() && !T->isConstantSizeType()) {
+ assert(T->isVariableArrayType() && "Unknown non-constant-sized type.");
+
+ // FIXME: Add support for VLA type arguments and VLA expressions.
+ // When that happens, we should probably refactor VLASizeChecker's code.
+ Dst.Add(Pred);
+ return;
+ }
+ else if (T->getAs<ObjCObjectType>()) {
+ // Some code tries to take the sizeof an ObjCObjectType, relying that
+ // the compiler has laid out its representation. Just report Unknown
+ // for these.
+ Dst.Add(Pred);
+ return;
+ }
+ }
+
+ Expr::EvalResult Result;
+ Ex->Evaluate(Result, getContext());
+ CharUnits amt = CharUnits::fromQuantity(Result.Val.getInt().getZExtValue());
+
+ const ProgramState *state = Pred->getState();
+ state = state->BindExpr(Ex, svalBuilder.makeIntVal(amt.getQuantity(),
+ Ex->getType()));
+ MakeNode(Dst, Ex, Pred, state);
+}
+
+void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ switch (U->getOpcode()) {
+ default:
+ break;
+ case UO_Real: {
+ const Expr *Ex = U->getSubExpr()->IgnoreParens();
+ ExplodedNodeSet Tmp;
+ Visit(Ex, Pred, Tmp);
+
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+
+ // FIXME: We don't have complex SValues yet.
+ if (Ex->getType()->isAnyComplexType()) {
+ // Just report "Unknown."
+ Dst.Add(*I);
+ continue;
+ }
+
+ // For all other types, UO_Real is an identity operation.
+ assert (U->getType() == Ex->getType());
+ const ProgramState *state = (*I)->getState();
+ MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex)));
+ }
+
+ return;
+ }
+
+ case UO_Imag: {
+
+ const Expr *Ex = U->getSubExpr()->IgnoreParens();
+ ExplodedNodeSet Tmp;
+ Visit(Ex, Pred, Tmp);
+
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+ // FIXME: We don't have complex SValues yet.
+ if (Ex->getType()->isAnyComplexType()) {
+ // Just report "Unknown."
+ Dst.Add(*I);
+ continue;
+ }
+
+ // For all other types, UO_Imag returns 0.
+ const ProgramState *state = (*I)->getState();
+ SVal X = svalBuilder.makeZeroVal(Ex->getType());
+ MakeNode(Dst, U, *I, state->BindExpr(U, X));
+ }
+
+ return;
+ }
+
+ case UO_Plus:
+ assert(!U->isLValue());
+ // FALL-THROUGH.
+ case UO_Deref:
+ case UO_AddrOf:
+ case UO_Extension: {
+
+ // Unary "+" is a no-op, similar to a parentheses. We still have places
+ // where it may be a block-level expression, so we need to
+ // generate an extra node that just propagates the value of the
+ // subexpression.
+
+ const Expr *Ex = U->getSubExpr()->IgnoreParens();
+ ExplodedNodeSet Tmp;
+ Visit(Ex, Pred, Tmp);
+
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+ const ProgramState *state = (*I)->getState();
+ MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex)));
+ }
+
+ return;
+ }
+
+ case UO_LNot:
+ case UO_Minus:
+ case UO_Not: {
+ assert (!U->isLValue());
+ const Expr *Ex = U->getSubExpr()->IgnoreParens();
+ ExplodedNodeSet Tmp;
+ Visit(Ex, Pred, Tmp);
+
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+ const ProgramState *state = (*I)->getState();
+
+ // Get the value of the subexpression.
+ SVal V = state->getSVal(Ex);
+
+ if (V.isUnknownOrUndef()) {
+ MakeNode(Dst, U, *I, state->BindExpr(U, V));
+ continue;
+ }
+
+ switch (U->getOpcode()) {
+ default:
+ llvm_unreachable("Invalid Opcode.");
+
+ case UO_Not:
+ // FIXME: Do we need to handle promotions?
+ state = state->BindExpr(U, evalComplement(cast<NonLoc>(V)));
+ break;
+
+ case UO_Minus:
+ // FIXME: Do we need to handle promotions?
+ state = state->BindExpr(U, evalMinus(cast<NonLoc>(V)));
+ break;
+
+ case UO_LNot:
+
+ // C99 6.5.3.3: "The expression !E is equivalent to (0==E)."
+ //
+ // Note: technically we do "E == 0", but this is the same in the
+ // transfer functions as "0 == E".
+ SVal Result;
+
+ if (isa<Loc>(V)) {
+ Loc X = svalBuilder.makeNull();
+ Result = evalBinOp(state, BO_EQ, cast<Loc>(V), X,
+ U->getType());
+ }
+ else {
+ nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
+ Result = evalBinOp(state, BO_EQ, cast<NonLoc>(V), X,
+ U->getType());
+ }
+
+ state = state->BindExpr(U, Result);
+
+ break;
+ }
+
+ MakeNode(Dst, U, *I, state);
+ }
+
+ return;
+ }
+ }
+
+ // Handle ++ and -- (both pre- and post-increment).
+ assert (U->isIncrementDecrementOp());
+ ExplodedNodeSet Tmp;
+ const Expr *Ex = U->getSubExpr()->IgnoreParens();
+ Visit(Ex, Pred, Tmp);
+
+ for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
+
+ const ProgramState *state = (*I)->getState();
+ SVal loc = state->getSVal(Ex);
+
+ // Perform a load.
+ ExplodedNodeSet Tmp2;
+ evalLoad(Tmp2, Ex, *I, state, loc);
+
+ for (ExplodedNodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end();I2!=E2;++I2) {
+
+ state = (*I2)->getState();
+ SVal V2_untested = state->getSVal(Ex);
+
+ // Propagate unknown and undefined values.
+ if (V2_untested.isUnknownOrUndef()) {
+ MakeNode(Dst, U, *I2, state->BindExpr(U, V2_untested));
+ continue;
+ }
+ DefinedSVal V2 = cast<DefinedSVal>(V2_untested);
+
+ // Handle all other values.
+ BinaryOperator::Opcode Op = U->isIncrementOp() ? BO_Add
+ : BO_Sub;
+
+ // If the UnaryOperator has non-location type, use its type to create the
+ // constant value. If the UnaryOperator has location type, create the
+ // constant with int type and pointer width.
+ SVal RHS;
+
+ if (U->getType()->isAnyPointerType())
+ RHS = svalBuilder.makeArrayIndex(1);
+ else
+ RHS = svalBuilder.makeIntVal(1, U->getType());
+
+ SVal Result = evalBinOp(state, Op, V2, RHS, U->getType());
+
+ // Conjure a new symbol if necessary to recover precision.
+ if (Result.isUnknown() || !getConstraintManager().canReasonAbout(Result)){
+ DefinedOrUnknownSVal SymVal =
+ svalBuilder.getConjuredSymbolVal(NULL, Ex,
+ Builder->getCurrentBlockCount());
+ Result = SymVal;
+
+ // If the value is a location, ++/-- should always preserve
+ // non-nullness. Check if the original value was non-null, and if so
+ // propagate that constraint.
+ if (Loc::isLocType(U->getType())) {
+ DefinedOrUnknownSVal Constraint =
+ svalBuilder.evalEQ(state, V2,svalBuilder.makeZeroVal(U->getType()));
+
+ if (!state->assume(Constraint, true)) {
+ // It isn't feasible for the original value to be null.
+ // Propagate this constraint.
+ Constraint = svalBuilder.evalEQ(state, SymVal,
+ svalBuilder.makeZeroVal(U->getType()));
+
+
+ state = state->assume(Constraint, false);
+ assert(state);
+ }
+ }
+ }
+
+ // Since the lvalue-to-rvalue conversion is explicit in the AST,
+ // we bind an l-value if the operator is prefix and an lvalue (in C++).
+ if (U->isLValue())
+ state = state->BindExpr(U, loc);
+ else
+ state = state->BindExpr(U, U->isPostfix() ? V2 : Result);
+
+ // Perform the store.
+ evalStore(Dst, NULL, U, *I2, state, loc, Result);
+ }
+ }
+}
diff --git a/lib/StaticAnalyzer/Core/CXXExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index ef7bc2016cdf..acb007490ee1 100644
--- a/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -1,4 +1,4 @@
-//===- GRCXXExprEngine.cpp - C++ expr evaluation engine ---------*- C++ -*-===//
+//===- ExprEngineCXX.cpp - ExprEngine support for C++ -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -14,6 +14,7 @@
#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/ObjCMessage.h"
#include "clang/AST/DeclCXX.h"
using namespace clang;
@@ -36,7 +37,7 @@ void ExprEngine::evalArguments(ConstExprIterator AI, ConstExprIterator AE,
bool FstArgAsLValue) {
- llvm::SmallVector<CallExprWLItem, 20> WorkList;
+ SmallVector<CallExprWLItem, 20> WorkList;
WorkList.reserve(AE - AI);
WorkList.push_back(CallExprWLItem(AI, Pred));
@@ -103,24 +104,22 @@ const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXMethodDecl *decl,
getCXXThisRegion(decl->getThisType(getContext()), frameCtx);
}
-void ExprEngine::CreateCXXTemporaryObject(const Expr *Ex, ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- ExplodedNodeSet Tmp;
- Visit(Ex, Pred, Tmp);
- for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
- const GRState *state = GetState(*I);
+void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ const Expr *tempExpr = ME->GetTemporaryExpr()->IgnoreParens();
+ const ProgramState *state = Pred->getState();
- // Bind the temporary object to the value of the expression. Then bind
- // the expression to the location of the object.
- SVal V = state->getSVal(Ex);
+ // 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);
- const MemRegion *R =
- svalBuilder.getRegionManager().getCXXTempObjectRegion(Ex,
- Pred->getLocationContext());
+ const MemRegion *R =
+ svalBuilder.getRegionManager().getCXXTempObjectRegion(ME,
+ Pred->getLocationContext());
- state = state->bindLoc(loc::MemRegionVal(R), V);
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R)));
- }
+ state = state->bindLoc(loc::MemRegionVal(R), V);
+ MakeNode(Dst, ME, Pred, state->BindExpr(ME, loc::MemRegionVal(R)));
}
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
@@ -186,7 +185,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(),
NE = argsEvaluated.end(); NI != NE; ++NI) {
- const GRState *state = GetState(*NI);
+ const ProgramState *state = (*NI)->getState();
// Setup 'this' region, so that the ctor is evaluated on the object pointed
// by 'Dest'.
state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest));
@@ -197,17 +196,6 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
#endif
// Default semantics: invalidate all regions passed as arguments.
- llvm::SmallVector<const MemRegion*, 10> regionsToInvalidate;
-
- // FIXME: We can have collisions on the conjured symbol if the
- // expression *I also creates conjured symbols. We probably want
- // to identify conjured symbols by an expression pair: the enclosing
- // expression (the context) and the expression itself. This should
- // disambiguate conjured symbols.
- unsigned blockCount = Builder->getCurrentBlockCount();
-
- // NOTE: Even if RegionsToInvalidate is empty, we must still invalidate
- // global variables.
ExplodedNodeSet destCall;
for (ExplodedNodeSet::iterator
@@ -215,25 +203,10 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
i != e; ++i)
{
ExplodedNode *Pred = *i;
- const GRState *state = GetState(Pred);
+ const LocationContext *LC = Pred->getLocationContext();
+ const ProgramState *state = Pred->getState();
- // Accumulate list of regions that are invalidated.
- for (CXXConstructExpr::const_arg_iterator
- ai = E->arg_begin(), ae = E->arg_end();
- ai != ae; ++ai)
- {
- SVal val = state->getSVal(*ai);
- if (const MemRegion *region = val.getAsRegion())
- regionsToInvalidate.push_back(region);
- }
-
- // Invalidate the regions.
- state = state->invalidateRegions(regionsToInvalidate.data(),
- regionsToInvalidate.data() +
- regionsToInvalidate.size(),
- E, blockCount, 0,
- /* invalidateGlobals = */ true);
-
+ state = invalidateArguments(state, CallOrObjCMessage(E, state), LC);
Builder->MakeNode(destCall, E, Pred, state);
}
@@ -258,7 +231,7 @@ void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,
CallEnter PP(S, SFC, Pred->getLocationContext());
- const GRState *state = Pred->getState();
+ const ProgramState *state = Pred->getState();
state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest));
ExplodedNode *N = Builder->generateNode(PP, state, Pred);
if (N)
@@ -279,7 +252,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
if (CNE->isArray()) {
// FIXME: allocating an array requires simulating the constructors.
// For now, just return a symbolicated region.
- const GRState *state = GetState(Pred);
+ const ProgramState *state = Pred->getState();
state = state->BindExpr(CNE, loc::MemRegionVal(EleReg));
MakeNode(Dst, CNE, Pred, state);
return;
@@ -298,12 +271,12 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
for (ExplodedNodeSet::iterator I = argsEvaluated.begin(),
E = argsEvaluated.end(); I != E; ++I) {
- const GRState *state = GetState(*I);
+ const ProgramState *state = (*I)->getState();
// Accumulate list of regions that are invalidated.
// FIXME: Eventually we should unify the logic for constructor
// processing in one place.
- llvm::SmallVector<const MemRegion*, 10> regionsToInvalidate;
+ SmallVector<const MemRegion*, 10> regionsToInvalidate;
for (CXXNewExpr::const_arg_iterator
ai = CNE->constructor_arg_begin(), ae = CNE->constructor_arg_end();
ai != ae; ++ai)
@@ -316,17 +289,13 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
if (ObjTy->isRecordType()) {
regionsToInvalidate.push_back(EleReg);
// Invalidate the regions.
- state = state->invalidateRegions(regionsToInvalidate.data(),
- regionsToInvalidate.data() +
- regionsToInvalidate.size(),
+ state = state->invalidateRegions(regionsToInvalidate,
CNE, blockCount, 0,
/* invalidateGlobals = */ true);
} else {
// Invalidate the regions.
- state = state->invalidateRegions(regionsToInvalidate.data(),
- regionsToInvalidate.data() +
- regionsToInvalidate.size(),
+ state = state->invalidateRegions(regionsToInvalidate,
CNE, blockCount, 0,
/* invalidateGlobals = */ true);
@@ -351,7 +320,7 @@ void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE,
Visit(CDE->getArgument(), Pred, Argevaluated);
for (ExplodedNodeSet::iterator I = Argevaluated.begin(),
E = Argevaluated.end(); I != E; ++I) {
- const GRState *state = GetState(*I);
+ const ProgramState *state = (*I)->getState();
MakeNode(Dst, CDE, *I, state);
}
}
@@ -364,7 +333,7 @@ void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
getContext().getCanonicalType(TE->getType()),
Pred->getLocationContext());
- const GRState *state = GetState(Pred);
+ const ProgramState *state = Pred->getState();
SVal V = state->getSVal(loc::MemRegionVal(R));
MakeNode(Dst, TE, Pred, state->BindExpr(TE, V));
}
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
new file mode 100644
index 000000000000..6d377b959136
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -0,0 +1,253 @@
+//=-- ExprEngineCallAndReturn.cpp - Support for call/return -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines ExprEngine's support for calls and returns.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/Analysis/Support/SaveAndRestore.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+ // Trait class for recording returned expression in the state.
+ struct ReturnExpr {
+ static int TagInt;
+ typedef const Stmt *data_type;
+ };
+ int ReturnExpr::TagInt;
+}
+
+void ExprEngine::processCallEnter(CallEnterNodeBuilder &B) {
+ const ProgramState *state =
+ B.getState()->enterStackFrame(B.getCalleeContext());
+ B.generateNode(state);
+}
+
+void ExprEngine::processCallExit(CallExitNodeBuilder &B) {
+ const ProgramState *state = B.getState();
+ const ExplodedNode *Pred = B.getPredecessor();
+ const StackFrameContext *calleeCtx =
+ cast<StackFrameContext>(Pred->getLocationContext());
+ const Stmt *CE = calleeCtx->getCallSite();
+
+ // If the callee returns an expression, bind its value to CallExpr.
+ const Stmt *ReturnedExpr = state->get<ReturnExpr>();
+ if (ReturnedExpr) {
+ SVal RetVal = state->getSVal(ReturnedExpr);
+ state = state->BindExpr(CE, RetVal);
+ // Clear the return expr GDM.
+ state = state->remove<ReturnExpr>();
+ }
+
+ // Bind the constructed object value to CXXConstructExpr.
+ if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) {
+ const CXXThisRegion *ThisR =
+ getCXXThisRegion(CCE->getConstructor()->getParent(), calleeCtx);
+
+ SVal ThisV = state->getSVal(ThisR);
+ // Always bind the region to the CXXConstructExpr.
+ state = state->BindExpr(CCE, ThisV);
+ }
+
+ B.generateNode(state);
+}
+
+const ProgramState *
+ExprEngine::invalidateArguments(const ProgramState *State,
+ const CallOrObjCMessage &Call,
+ const LocationContext *LC) {
+ SmallVector<const MemRegion *, 8> RegionsToInvalidate;
+
+ if (Call.isObjCMessage()) {
+ // Invalidate all instance variables of the receiver of an ObjC message.
+ // FIXME: We should be able to do better with inter-procedural analysis.
+ if (const MemRegion *MR = Call.getInstanceMessageReceiver(LC).getAsRegion())
+ RegionsToInvalidate.push_back(MR);
+
+ } else if (Call.isCXXCall()) {
+ // Invalidate all instance variables for the callee of a C++ method call.
+ // FIXME: We should be able to do better with inter-procedural analysis.
+ // FIXME: We can probably do better for const versus non-const methods.
+ if (const MemRegion *Callee = Call.getCXXCallee().getAsRegion())
+ RegionsToInvalidate.push_back(Callee);
+
+ } else if (Call.isFunctionCall()) {
+ // Block calls invalidate all captured-by-reference values.
+ if (const MemRegion *Callee = Call.getFunctionCallee().getAsRegion()) {
+ if (isa<BlockDataRegion>(Callee))
+ RegionsToInvalidate.push_back(Callee);
+ }
+ }
+
+ for (unsigned idx = 0, e = Call.getNumArgs(); idx != e; ++idx) {
+ SVal V = Call.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 underying 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
+ // approriately 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);
+ } else {
+ // Nuke all other arguments passed by reference.
+ // FIXME: is this necessary or correct? This handles the non-Region
+ // cases. Is it ever valid to store to these?
+ State = State->unbindLoc(cast<Loc>(V));
+ }
+ }
+
+ // Invalidate designated regions using the batch invalidation API.
+
+ // FIXME: We can have collisions on the conjured symbol if the
+ // expression *I also creates conjured symbols. We probably want
+ // to identify conjured symbols by an expression pair: the enclosing
+ // expression (the context) and the expression itself. This should
+ // disambiguate conjured symbols.
+ assert(Builder && "Invalidating arguments outside of a statement context");
+ unsigned Count = Builder->getCurrentBlockCount();
+ StoreManager::InvalidatedSymbols IS;
+
+ // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate
+ // global variables.
+ return State->invalidateRegions(RegionsToInvalidate,
+ Call.getOriginExpr(), Count,
+ &IS, doesInvalidateGlobals(Call));
+
+}
+
+void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
+ ExplodedNodeSet &dst) {
+ // Perform the previsit of the CallExpr.
+ ExplodedNodeSet dstPreVisit;
+ getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, CE, *this);
+
+ // Now evaluate the call itself.
+ class DefaultEval : public GraphExpander {
+ ExprEngine &Eng;
+ const CallExpr *CE;
+ public:
+
+ DefaultEval(ExprEngine &eng, const CallExpr *ce)
+ : Eng(eng), CE(ce) {}
+ virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+ // Should we inline the call?
+ if (Eng.getAnalysisManager().shouldInlineCall() &&
+ Eng.InlineCall(Dst, CE, Pred)) {
+ return;
+ }
+
+ // First handle the return value.
+ StmtNodeBuilder &Builder = Eng.getBuilder();
+ assert(&Builder && "StmtNodeBuilder must be defined.");
+
+ // Get the callee.
+ const Expr *Callee = CE->getCallee()->IgnoreParens();
+ const ProgramState *state = Pred->getState();
+ SVal L = state->getSVal(Callee);
+
+ // Figure out the result type. We do this dance to handle references.
+ QualType ResultTy;
+ if (const FunctionDecl *FD = L.getAsFunctionDecl())
+ ResultTy = FD->getResultType();
+ else
+ ResultTy = CE->getType();
+
+ if (CE->isLValue())
+ ResultTy = Eng.getContext().getPointerType(ResultTy);
+
+ // Conjure a symbol value to use as the result.
+ SValBuilder &SVB = Eng.getSValBuilder();
+ unsigned Count = Builder.getCurrentBlockCount();
+ SVal RetVal = SVB.getConjuredSymbolVal(0, CE, ResultTy, Count);
+
+ // Generate a new state with the return value set.
+ state = state->BindExpr(CE, RetVal);
+
+ // Invalidate the arguments.
+ const LocationContext *LC = Pred->getLocationContext();
+ state = Eng.invalidateArguments(state, CallOrObjCMessage(CE, state), LC);
+
+ // And make the result node.
+ Eng.MakeNode(Dst, CE, Pred, state);
+ }
+ };
+
+ // Finally, evaluate the function call. We try each of the checkers
+ // to see if the can evaluate the function call.
+ ExplodedNodeSet dstCallEvaluated;
+ DefaultEval defEval(*this, CE);
+ getCheckerManager().runCheckersForEvalCall(dstCallEvaluated,
+ dstPreVisit,
+ CE, *this, &defEval);
+
+ // Finally, perform the post-condition check of the CallExpr and store
+ // the created nodes in 'Dst'.
+ getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE,
+ *this);
+}
+
+void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ ExplodedNodeSet Src;
+ if (const Expr *RetE = RS->getRetValue()) {
+ // Record the returned expression in the state. It will be used in
+ // processCallExit to bind the return value to the call expr.
+ {
+ static SimpleProgramPointTag tag("ExprEngine: ReturnStmt");
+ const ProgramState *state = Pred->getState();
+ state = state->set<ReturnExpr>(RetE);
+ Pred = Builder->generateNode(RetE, state, Pred, &tag);
+ }
+ // We may get a NULL Pred because we generated a cached node.
+ if (Pred)
+ Visit(RetE, Pred, Src);
+ }
+ else {
+ Src.Add(Pred);
+ }
+
+ getCheckerManager().runCheckersForPreStmt(Dst, Src, RS, *this);
+}
diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
new file mode 100644
index 000000000000..e0560fdfe460
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -0,0 +1,279 @@
+//=-- ExprEngineObjC.cpp - ExprEngine support for Objective-C ---*- 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 ExprEngine's support for Objective-C expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
+#include "clang/Analysis/Support/SaveAndRestore.h"
+
+using namespace clang;
+using namespace ento;
+
+void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+
+ const ProgramState *state = Pred->getState();
+ SVal baseVal = state->getSVal(Ex->getBase());
+ SVal location = state->getLValue(Ex->getDecl(), baseVal);
+
+ ExplodedNodeSet dstIvar;
+ MakeNode(dstIvar, Ex, Pred, state->BindExpr(Ex, location));
+
+ // Perform the post-condition check of the ObjCIvarRefExpr and store
+ // the created nodes in 'Dst'.
+ getCheckerManager().runCheckersForPostStmt(Dst, dstIvar, Ex, *this);
+}
+
+void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ getCheckerManager().runCheckersForPreStmt(Dst, Pred, S, *this);
+}
+
+void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+
+ // ObjCForCollectionStmts are processed in two places. This method
+ // handles the case where an ObjCForCollectionStmt* occurs as one of the
+ // statements within a basic block. This transfer function does two things:
+ //
+ // (1) binds the next container value to 'element'. This creates a new
+ // node in the ExplodedGraph.
+ //
+ // (2) binds the value 0/1 to the ObjCForCollectionStmt* itself, indicating
+ // whether or not the container has any more elements. This value
+ // will be tested in ProcessBranch. We need to explicitly bind
+ // this value because a container can contain nil elements.
+ //
+ // FIXME: Eventually this logic should actually do dispatches to
+ // 'countByEnumeratingWithState:objects:count:' (NSFastEnumeration).
+ // This will require simulating a temporary NSFastEnumerationState, either
+ // through an SVal or through the use of MemRegions. This value can
+ // be affixed to the ObjCForCollectionStmt* instead of 0/1; when the loop
+ // terminates we reclaim the temporary (it goes out of scope) and we
+ // we can test if the SVal is 0 or if the MemRegion is null (depending
+ // on what approach we take).
+ //
+ // For now: simulate (1) by assigning either a symbol or nil if the
+ // container is empty. Thus this transfer function will by default
+ // result in state splitting.
+
+ const Stmt *elem = S->getElement();
+ const ProgramState *state = Pred->getState();
+ SVal elementV;
+
+ if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) {
+ const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl());
+ assert(elemD->getInit() == 0);
+ elementV = state->getLValue(elemD, Pred->getLocationContext());
+ }
+ else {
+ elementV = state->getSVal(elem);
+ }
+
+ ExplodedNodeSet dstLocation;
+ evalLocation(dstLocation, elem, Pred, state, elementV, NULL, false);
+
+ if (dstLocation.empty())
+ return;
+
+ for (ExplodedNodeSet::iterator NI = dstLocation.begin(),
+ NE = dstLocation.end(); NI!=NE; ++NI) {
+ Pred = *NI;
+ const ProgramState *state = Pred->getState();
+
+ // Handle the case where the container still has elements.
+ SVal TrueV = svalBuilder.makeTruthVal(1);
+ const ProgramState *hasElems = state->BindExpr(S, TrueV);
+
+ // Handle the case where the container has no elements.
+ SVal FalseV = svalBuilder.makeTruthVal(0);
+ const ProgramState *noElems = state->BindExpr(S, FalseV);
+
+ if (loc::MemRegionVal *MV = dyn_cast<loc::MemRegionVal>(&elementV))
+ if (const TypedValueRegion *R =
+ dyn_cast<TypedValueRegion>(MV->getRegion())) {
+ // FIXME: The proper thing to do is to really iterate over the
+ // container. We will do this with dispatch logic to the store.
+ // For now, just 'conjure' up a symbolic value.
+ QualType T = R->getValueType();
+ assert(Loc::isLocType(T));
+ unsigned Count = Builder->getCurrentBlockCount();
+ SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count);
+ SVal V = svalBuilder.makeLoc(Sym);
+ hasElems = hasElems->bindLoc(elementV, V);
+
+ // Bind the location to 'nil' on the false branch.
+ SVal nilV = svalBuilder.makeIntVal(0, T);
+ noElems = noElems->bindLoc(elementV, nilV);
+ }
+
+ // Create the new nodes.
+ MakeNode(Dst, S, Pred, hasElems);
+ MakeNode(Dst, S, Pred, noElems);
+ }
+}
+
+void ExprEngine::VisitObjCMessage(const ObjCMessage &msg,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+
+ // Handle the previsits checks.
+ ExplodedNodeSet dstPrevisit;
+ getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred,
+ msg, *this);
+
+ // Proceed with evaluate the message expression.
+ ExplodedNodeSet dstEval;
+
+ for (ExplodedNodeSet::iterator DI = dstPrevisit.begin(),
+ DE = dstPrevisit.end(); DI != DE; ++DI) {
+
+ ExplodedNode *Pred = *DI;
+ bool RaisesException = false;
+ SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+ SaveOr OldHasGen(Builder->hasGeneratedNode);
+
+ if (const Expr *Receiver = msg.getInstanceReceiver()) {
+ const ProgramState *state = Pred->getState();
+ SVal recVal = state->getSVal(Receiver);
+ if (!recVal.isUndef()) {
+ // Bifurcate the state into nil and non-nil ones.
+ DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
+
+ const ProgramState *notNilState, *nilState;
+ llvm::tie(notNilState, nilState) = state->assume(receiverVal);
+
+ // There are three cases: can be nil or non-nil, must be nil, must be
+ // non-nil. We ignore must be nil, and merge the rest two into non-nil.
+ if (nilState && !notNilState) {
+ dstEval.insert(Pred);
+ continue;
+ }
+
+ // Check if the "raise" message was sent.
+ assert(notNilState);
+ if (msg.getSelector() == RaiseSel)
+ RaisesException = true;
+
+ // Check if we raise an exception. For now treat these as sinks.
+ // Eventually we will want to handle exceptions properly.
+ if (RaisesException)
+ Builder->BuildSinks = true;
+
+ // Dispatch to plug-in transfer function.
+ evalObjCMessage(dstEval, msg, Pred, notNilState);
+ }
+ }
+ else if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) {
+ IdentifierInfo* ClsName = Iface->getIdentifier();
+ Selector S = msg.getSelector();
+
+ // Check for special instance methods.
+ if (!NSExceptionII) {
+ ASTContext &Ctx = getContext();
+ NSExceptionII = &Ctx.Idents.get("NSException");
+ }
+
+ if (ClsName == NSExceptionII) {
+ enum { NUM_RAISE_SELECTORS = 2 };
+
+ // Lazily create a cache of the selectors.
+ if (!NSExceptionInstanceRaiseSelectors) {
+ ASTContext &Ctx = getContext();
+ NSExceptionInstanceRaiseSelectors =
+ new Selector[NUM_RAISE_SELECTORS];
+ SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
+ unsigned idx = 0;
+
+ // raise:format:
+ II.push_back(&Ctx.Idents.get("raise"));
+ II.push_back(&Ctx.Idents.get("format"));
+ NSExceptionInstanceRaiseSelectors[idx++] =
+ Ctx.Selectors.getSelector(II.size(), &II[0]);
+
+ // raise:format::arguments:
+ II.push_back(&Ctx.Idents.get("arguments"));
+ NSExceptionInstanceRaiseSelectors[idx++] =
+ Ctx.Selectors.getSelector(II.size(), &II[0]);
+ }
+
+ for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i)
+ if (S == NSExceptionInstanceRaiseSelectors[i]) {
+ RaisesException = true;
+ break;
+ }
+ }
+
+ // Check if we raise an exception. For now treat these as sinks.
+ // Eventually we will want to handle exceptions properly.
+ if (RaisesException)
+ Builder->BuildSinks = true;
+
+ // Dispatch to plug-in transfer function.
+ evalObjCMessage(dstEval, msg, Pred, Pred->getState());
+ }
+
+ assert(Builder->BuildSinks || Builder->hasGeneratedNode);
+ }
+
+ // Finally, perform the post-condition check of the ObjCMessageExpr and store
+ // the created nodes in 'Dst'.
+ getCheckerManager().runCheckersForPostObjCMessage(Dst, dstEval, msg, *this);
+}
+
+void ExprEngine::evalObjCMessage(ExplodedNodeSet &Dst, const ObjCMessage &msg,
+ ExplodedNode *Pred,
+ const ProgramState *state) {
+ assert (Builder && "StmtNodeBuilder must be defined.");
+
+ // First handle the return value.
+ SVal ReturnValue = UnknownVal();
+
+ // Some method families have known return values.
+ switch (msg.getMethodFamily()) {
+ default:
+ break;
+ case OMF_autorelease:
+ case OMF_retain:
+ case OMF_self: {
+ // These methods return their receivers.
+ const Expr *ReceiverE = msg.getInstanceReceiver();
+ if (ReceiverE)
+ ReturnValue = state->getSVal(ReceiverE);
+ break;
+ }
+ }
+
+ // If we failed to figure out the return value, use a conjured value instead.
+ if (ReturnValue.isUnknown()) {
+ SValBuilder &SVB = getSValBuilder();
+ QualType ResultTy = msg.getResultType(getContext());
+ unsigned Count = Builder->getCurrentBlockCount();
+ const Expr *CurrentE = cast<Expr>(currentStmt);
+ ReturnValue = SVB.getConjuredSymbolVal(NULL, CurrentE, ResultTy, Count);
+ }
+
+ // Bind the return value.
+ state = state->BindExpr(currentStmt, ReturnValue);
+
+ // Invalidate the arguments (and the receiver)
+ const LocationContext *LC = Pred->getLocationContext();
+ state = invalidateArguments(state, CallOrObjCMessage(msg, state), LC);
+
+ // And create the new node.
+ MakeNode(Dst, msg.getOriginExpr(), Pred, state);
+}
+
diff --git a/lib/StaticAnalyzer/Core/FlatStore.cpp b/lib/StaticAnalyzer/Core/FlatStore.cpp
deleted file mode 100644
index ca867aebded4..000000000000
--- a/lib/StaticAnalyzer/Core/FlatStore.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-//=== FlatStore.cpp - Flat region-based store model -------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
-#include "llvm/ADT/ImmutableIntervalMap.h"
-#include "llvm/Support/ErrorHandling.h"
-
-using namespace clang;
-using namespace ento;
-using llvm::Interval;
-
-// The actual store type.
-typedef llvm::ImmutableIntervalMap<SVal> BindingVal;
-typedef llvm::ImmutableMap<const MemRegion *, BindingVal> RegionBindings;
-
-namespace {
-class FlatStoreManager : public StoreManager {
- RegionBindings::Factory RBFactory;
- BindingVal::Factory BVFactory;
-
-public:
- FlatStoreManager(GRStateManager &mgr)
- : StoreManager(mgr),
- RBFactory(mgr.getAllocator()),
- BVFactory(mgr.getAllocator()) {}
-
- SVal Retrieve(Store store, Loc L, QualType T);
- StoreRef Bind(Store store, Loc L, SVal val);
- StoreRef Remove(Store St, Loc L);
- StoreRef BindCompoundLiteral(Store store, const CompoundLiteralExpr* cl,
- const LocationContext *LC, SVal v);
-
- StoreRef getInitialStore(const LocationContext *InitLoc) {
- return StoreRef(RBFactory.getEmptyMap().getRoot(), *this);
- }
-
- SubRegionMap *getSubRegionMap(Store store) {
- return 0;
- }
-
- SVal ArrayToPointer(Loc Array);
- StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx,
- SymbolReaper& SymReaper,
- llvm::SmallVectorImpl<const MemRegion*>& RegionRoots){
- return StoreRef(store, *this);
- }
-
- StoreRef BindDecl(Store store, const VarRegion *VR, SVal initVal);
-
- StoreRef BindDeclWithNoInit(Store store, const VarRegion *VR);
-
- typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols;
-
- StoreRef invalidateRegions(Store store, const MemRegion * const *I,
- const MemRegion * const *E, const Expr *Ex,
- unsigned Count, InvalidatedSymbols &IS,
- bool invalidateGlobals,
- InvalidatedRegions *Regions);
-
- void print(Store store, llvm::raw_ostream& Out, const char* nl,
- const char *sep);
- void iterBindings(Store store, BindingsHandler& f);
-
-private:
- static RegionBindings getRegionBindings(Store store) {
- return RegionBindings(static_cast<const RegionBindings::TreeTy*>(store));
- }
-
- class RegionInterval {
- public:
- const MemRegion *R;
- Interval I;
- RegionInterval(const MemRegion *r, int64_t s, int64_t e) : R(r), I(s, e){}
- };
-
- RegionInterval RegionToInterval(const MemRegion *R);
-
- SVal RetrieveRegionWithNoBinding(const MemRegion *R, QualType T);
-};
-} // end anonymous namespace
-
-StoreManager *ento::CreateFlatStoreManager(GRStateManager &StMgr) {
- return new FlatStoreManager(StMgr);
-}
-
-SVal FlatStoreManager::Retrieve(Store store, Loc L, QualType T) {
- // For access to concrete addresses, return UnknownVal. Checks
- // for null dereferences (and similar errors) are done by checkers, not
- // the Store.
- // 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)) {
- return UnknownVal();
- }
- if (!isa<loc::MemRegionVal>(L)) {
- return UnknownVal();
- }
-
- const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion();
- RegionInterval RI = RegionToInterval(R);
- // FIXME: FlatStore should handle regions with unknown intervals.
- if (!RI.R)
- return UnknownVal();
-
- RegionBindings B = getRegionBindings(store);
- const BindingVal *BV = B.lookup(RI.R);
- if (BV) {
- const SVal *V = BVFactory.lookup(*BV, RI.I);
- if (V)
- return *V;
- else
- return RetrieveRegionWithNoBinding(R, T);
- }
- return RetrieveRegionWithNoBinding(R, T);
-}
-
-SVal FlatStoreManager::RetrieveRegionWithNoBinding(const MemRegion *R,
- QualType T) {
- if (R->hasStackNonParametersStorage())
- return UndefinedVal();
- else
- return svalBuilder.getRegionValueSymbolVal(cast<TypedRegion>(R));
-}
-
-StoreRef FlatStoreManager::Bind(Store store, Loc L, SVal val) {
- const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion();
- RegionBindings B = getRegionBindings(store);
- const BindingVal *V = B.lookup(R);
-
- BindingVal BV = BVFactory.getEmptyMap();
- if (V)
- BV = *V;
-
- RegionInterval RI = RegionToInterval(R);
- // FIXME: FlatStore should handle regions with unknown intervals.
- if (!RI.R)
- return StoreRef(B.getRoot(), *this);
- BV = BVFactory.add(BV, RI.I, val);
- B = RBFactory.add(B, RI.R, BV);
- return StoreRef(B.getRoot(), *this);
-}
-
-StoreRef FlatStoreManager::Remove(Store store, Loc L) {
- return StoreRef(store, *this);
-}
-
-StoreRef FlatStoreManager::BindCompoundLiteral(Store store,
- const CompoundLiteralExpr* cl,
- const LocationContext *LC,
- SVal v) {
- return StoreRef(store, *this);
-}
-
-SVal FlatStoreManager::ArrayToPointer(Loc Array) {
- return Array;
-}
-
-StoreRef FlatStoreManager::BindDecl(Store store, const VarRegion *VR,
- SVal initVal) {
- return Bind(store, svalBuilder.makeLoc(VR), initVal);
-}
-
-StoreRef FlatStoreManager::BindDeclWithNoInit(Store store, const VarRegion *VR){
- return StoreRef(store, *this);
-}
-
-StoreRef FlatStoreManager::invalidateRegions(Store store,
- const MemRegion * const *I,
- const MemRegion * const *E,
- const Expr *Ex, unsigned Count,
- InvalidatedSymbols &IS,
- bool invalidateGlobals,
- InvalidatedRegions *Regions) {
- assert(false && "Not implemented");
- return StoreRef(store, *this);
-}
-
-void FlatStoreManager::print(Store store, llvm::raw_ostream& Out,
- const char* nl, const char *sep) {
-}
-
-void FlatStoreManager::iterBindings(Store store, BindingsHandler& f) {
-}
-
-FlatStoreManager::RegionInterval
-FlatStoreManager::RegionToInterval(const MemRegion *R) {
- switch (R->getKind()) {
- case MemRegion::VarRegionKind: {
- QualType T = cast<VarRegion>(R)->getValueType();
- int64_t Size = Ctx.getTypeSize(T);
- return RegionInterval(R, 0, Size-1);
- }
-
- case MemRegion::ElementRegionKind:
- case MemRegion::FieldRegionKind: {
- RegionOffset Offset = R->getAsOffset();
- // We cannot compute offset for all regions, for example, elements
- // with symbolic offsets.
- if (!Offset.getRegion())
- return RegionInterval(0, 0, 0);
- int64_t Start = Offset.getOffset();
- int64_t Size = Ctx.getTypeSize(cast<TypedRegion>(R)->getValueType());
- return RegionInterval(Offset.getRegion(), Start, Start+Size);
- }
-
- default:
- llvm_unreachable("Region kind unhandled.");
- return RegionInterval(0, 0, 0);
- }
-}
diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index 1ebc28c044fd..0c4e4277e4d6 100644
--- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Core/PathDiagnosticClients.h"
+#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
@@ -35,7 +35,7 @@ using namespace ento;
namespace {
-class HTMLDiagnostics : public PathDiagnosticClient {
+class HTMLDiagnostics : public PathDiagnosticConsumer {
llvm::sys::Path Directory, FilePrefix;
bool createdDir, noDir;
const Preprocessor &PP;
@@ -45,15 +45,15 @@ public:
virtual ~HTMLDiagnostics() { FlushDiagnostics(NULL); }
- virtual void FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade);
+ virtual void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade);
- virtual void HandlePathDiagnostic(const PathDiagnostic* D);
+ virtual void HandlePathDiagnosticImpl(const PathDiagnostic* D);
- virtual llvm::StringRef getName() const {
+ virtual StringRef getName() const {
return "HTMLDiagnostics";
}
- unsigned ProcessMacroPiece(llvm::raw_ostream& os,
+ unsigned ProcessMacroPiece(raw_ostream &os,
const PathDiagnosticMacroPiece& P,
unsigned num);
@@ -65,7 +65,7 @@ public:
const char *HighlightEnd = "</span>");
void ReportDiag(const PathDiagnostic& D,
- llvm::SmallVectorImpl<std::string> *FilesMade);
+ SmallVectorImpl<std::string> *FilesMade);
};
} // end anonymous namespace
@@ -78,8 +78,8 @@ HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix,
FilePrefix.appendComponent("report");
}
-PathDiagnosticClient*
-ento::createHTMLDiagnosticClient(const std::string& prefix,
+PathDiagnosticConsumer*
+ento::createHTMLDiagnosticConsumer(const std::string& prefix,
const Preprocessor &PP) {
return new HTMLDiagnostics(prefix, PP);
}
@@ -88,7 +88,7 @@ ento::createHTMLDiagnosticClient(const std::string& prefix,
// Report processing.
//===----------------------------------------------------------------------===//
-void HTMLDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
+void HTMLDiagnostics::HandlePathDiagnosticImpl(const PathDiagnostic* D) {
if (!D)
return;
@@ -102,7 +102,7 @@ void HTMLDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
}
void
-HTMLDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade)
+HTMLDiagnostics::FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade)
{
while (!BatchedDiags.empty()) {
const PathDiagnostic* D = BatchedDiags.back();
@@ -115,7 +115,7 @@ HTMLDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade)
}
void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
- llvm::SmallVectorImpl<std::string> *FilesMade){
+ SmallVectorImpl<std::string> *FilesMade){
// Create the HTML directory if it is missing.
if (!createdDir) {
createdDir = true;
@@ -143,7 +143,7 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
// Verify that the entire path is from the same FileID.
for (PathDiagnostic::const_iterator I = D.begin(), E = D.end(); I != E; ++I) {
- FullSourceLoc L = I->getLocation().asLocation().getInstantiationLoc();
+ FullSourceLoc L = I->getLocation().asLocation().getExpansionLoc();
if (FID.isInvalid()) {
FID = SMgr.getFileID(L);
@@ -154,12 +154,12 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
for (PathDiagnosticPiece::range_iterator RI=I->ranges_begin(),
RE=I->ranges_end(); RI!=RE; ++RI) {
- SourceLocation L = SMgr.getInstantiationLoc(RI->getBegin());
+ SourceLocation L = SMgr.getExpansionLoc(RI->getBegin());
if (!L.isFileID() || SMgr.getFileID(L) != FID)
return; // FIXME: Emit a warning?
- L = SMgr.getInstantiationLoc(RI->getEnd());
+ L = SMgr.getExpansionLoc(RI->getEnd());
if (!L.isFileID() || SMgr.getFileID(L) != FID)
return; // FIXME: Emit a warning?
@@ -221,9 +221,9 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
<< html::EscapeText(Entry->getName())
<< "</td></tr>\n<tr><td class=\"rowname\">Location:</td><td>"
"<a href=\"#EndPath\">line "
- << (*D.rbegin()).getLocation().asLocation().getInstantiationLineNumber()
+ << (*D.rbegin()).getLocation().asLocation().getExpansionLineNumber()
<< ", column "
- << (*D.rbegin()).getLocation().asLocation().getInstantiationColumnNumber()
+ << (*D.rbegin()).getLocation().asLocation().getExpansionColumnNumber()
<< "</a></td></tr>\n"
"<tr><td class=\"rowname\">Description:</td><td>"
<< D.getDescription() << "</td></tr>\n";
@@ -261,7 +261,7 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n";
os << "\n<!-- BUGLINE "
- << D.back()->getLocation().asLocation().getInstantiationLineNumber()
+ << D.back()->getLocation().asLocation().getExpansionLineNumber()
<< " -->\n";
os << "\n<!-- BUGPATHLENGTH " << D.size() << " -->\n";
@@ -324,7 +324,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
SourceManager &SM = R.getSourceMgr();
assert(&Pos.getManager() == &SM && "SourceManagers are different!");
- std::pair<FileID, unsigned> LPosInfo = SM.getDecomposedInstantiationLoc(Pos);
+ std::pair<FileID, unsigned> LPosInfo = SM.getDecomposedExpansionLoc(Pos);
if (LPosInfo.first != BugFileID)
return;
@@ -335,7 +335,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
// Compute the column number. Rewind from the current position to the start
// of the line.
unsigned ColNo = SM.getColumnNumber(LPosInfo.first, LPosInfo.second);
- const char *TokInstantiationPtr =Pos.getInstantiationLoc().getCharacterData();
+ const char *TokInstantiationPtr =Pos.getExpansionLoc().getCharacterData();
const char *LineStart = TokInstantiationPtr-ColNo;
// Compute LineEnd.
@@ -441,9 +441,9 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
// Get the name of the macro by relexing it.
{
- FullSourceLoc L = MP->getLocation().asLocation().getInstantiationLoc();
+ FullSourceLoc L = MP->getLocation().asLocation().getExpansionLoc();
assert(L.isFileID());
- llvm::StringRef BufferInfo = L.getBufferData();
+ StringRef BufferInfo = L.getBufferData();
const char* MacroName = L.getDecomposedLoc().second + BufferInfo.data();
Lexer rawLexer(L, PP.getLangOptions(), BufferInfo.begin(),
MacroName, BufferInfo.end());
@@ -474,7 +474,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
// Insert the new html.
unsigned DisplayPos = LineEnd - FileStart;
SourceLocation Loc =
- SM.getLocForStartOfFile(LPosInfo.first).getFileLocWithOffset(DisplayPos);
+ SM.getLocForStartOfFile(LPosInfo.first).getLocWithOffset(DisplayPos);
R.InsertTextBefore(Loc, os.str());
@@ -504,7 +504,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
#endif
}
-static void EmitAlphaCounter(llvm::raw_ostream& os, unsigned n) {
+static void EmitAlphaCounter(raw_ostream &os, unsigned n) {
unsigned x = n % ('z' - 'a');
n /= 'z' - 'a';
@@ -514,7 +514,7 @@ static void EmitAlphaCounter(llvm::raw_ostream& os, unsigned n) {
os << char('a' + x);
}
-unsigned HTMLDiagnostics::ProcessMacroPiece(llvm::raw_ostream& os,
+unsigned HTMLDiagnostics::ProcessMacroPiece(raw_ostream &os,
const PathDiagnosticMacroPiece& P,
unsigned num) {
@@ -549,11 +549,11 @@ void HTMLDiagnostics::HighlightRange(Rewriter& R, FileID BugFileID,
SourceManager &SM = R.getSourceMgr();
const LangOptions &LangOpts = R.getLangOpts();
- SourceLocation InstantiationStart = SM.getInstantiationLoc(Range.getBegin());
- unsigned StartLineNo = SM.getInstantiationLineNumber(InstantiationStart);
+ SourceLocation InstantiationStart = SM.getExpansionLoc(Range.getBegin());
+ unsigned StartLineNo = SM.getExpansionLineNumber(InstantiationStart);
- SourceLocation InstantiationEnd = SM.getInstantiationLoc(Range.getEnd());
- unsigned EndLineNo = SM.getInstantiationLineNumber(InstantiationEnd);
+ SourceLocation InstantiationEnd = SM.getExpansionLoc(Range.getEnd());
+ unsigned EndLineNo = SM.getExpansionLineNumber(InstantiationEnd);
if (EndLineNo < StartLineNo)
return;
@@ -563,7 +563,7 @@ void HTMLDiagnostics::HighlightRange(Rewriter& R, FileID BugFileID,
return;
// Compute the column number of the end.
- unsigned EndColNo = SM.getInstantiationColumnNumber(InstantiationEnd);
+ unsigned EndColNo = SM.getExpansionColumnNumber(InstantiationEnd);
unsigned OldEndColNo = EndColNo;
if (EndColNo) {
@@ -575,7 +575,7 @@ void HTMLDiagnostics::HighlightRange(Rewriter& R, FileID BugFileID,
// selected range.
SourceLocation E =
- InstantiationEnd.getFileLocWithOffset(EndColNo - OldEndColNo);
+ InstantiationEnd.getLocWithOffset(EndColNo - OldEndColNo);
html::HighlightRange(R, InstantiationStart, E, HighlightStart, HighlightEnd);
}
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp
index d9e884a4b208..6f92da8f3e5f 100644
--- a/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -38,7 +38,7 @@ RegionTy* MemRegionManager::getRegion(const A1 a1) {
llvm::FoldingSetNodeID ID;
RegionTy::ProfileRegion(ID, a1, superRegion);
- void* InsertPos;
+ void *InsertPos;
RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
InsertPos));
@@ -56,7 +56,7 @@ RegionTy* MemRegionManager::getSubRegion(const A1 a1,
const MemRegion *superRegion) {
llvm::FoldingSetNodeID ID;
RegionTy::ProfileRegion(ID, a1, superRegion);
- void* InsertPos;
+ void *InsertPos;
RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
InsertPos));
@@ -77,7 +77,7 @@ RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) {
llvm::FoldingSetNodeID ID;
RegionTy::ProfileRegion(ID, a1, a2, superRegion);
- void* InsertPos;
+ void *InsertPos;
RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
InsertPos));
@@ -96,7 +96,7 @@ RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2,
llvm::FoldingSetNodeID ID;
RegionTy::ProfileRegion(ID, a1, a2, superRegion);
- void* InsertPos;
+ void *InsertPos;
RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
InsertPos));
@@ -115,7 +115,7 @@ RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, const A3 a3,
llvm::FoldingSetNodeID ID;
RegionTy::ProfileRegion(ID, a1, a2, a3, superRegion);
- void* InsertPos;
+ void *InsertPos;
RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
InsertPos));
@@ -178,7 +178,7 @@ const StackFrameContext *VarRegion::getStackFrame() const {
//===----------------------------------------------------------------------===//
DefinedOrUnknownSVal DeclRegion::getExtent(SValBuilder &svalBuilder) const {
- ASTContext& Ctx = svalBuilder.getContext();
+ ASTContext &Ctx = svalBuilder.getContext();
QualType T = getDesugaredValueType(Ctx);
if (isa<VariableArrayType>(T))
@@ -250,7 +250,7 @@ void StringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
}
void AllocaRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- const Expr* Ex, unsigned cnt,
+ const Expr *Ex, unsigned cnt,
const MemRegion *) {
ID.AddInteger((unsigned) AllocaRegionKind);
ID.AddPointer(Ex);
@@ -266,7 +266,7 @@ void CompoundLiteralRegion::Profile(llvm::FoldingSetNodeID& ID) const {
}
void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- const CompoundLiteralExpr* CL,
+ const CompoundLiteralExpr *CL,
const MemRegion* superRegion) {
ID.AddInteger((unsigned) CompoundLiteralRegionKind);
ID.AddPointer(CL);
@@ -285,7 +285,7 @@ void CXXThisRegion::Profile(llvm::FoldingSetNodeID &ID) const {
CXXThisRegion::ProfileRegion(ID, ThisPointerTy, superRegion);
}
-void DeclRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D,
+void DeclRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D,
const MemRegion* superRegion, Kind k) {
ID.AddInteger((unsigned) k);
ID.AddPointer(D);
@@ -398,81 +398,82 @@ std::string MemRegion::getString() const {
return os.str();
}
-void MemRegion::dumpToStream(llvm::raw_ostream& os) const {
+void MemRegion::dumpToStream(raw_ostream &os) const {
os << "<Unknown Region>";
}
-void AllocaRegion::dumpToStream(llvm::raw_ostream& os) const {
+void AllocaRegion::dumpToStream(raw_ostream &os) const {
os << "alloca{" << (void*) Ex << ',' << Cnt << '}';
}
-void FunctionTextRegion::dumpToStream(llvm::raw_ostream& os) const {
+void FunctionTextRegion::dumpToStream(raw_ostream &os) const {
os << "code{" << getDecl()->getDeclName().getAsString() << '}';
}
-void BlockTextRegion::dumpToStream(llvm::raw_ostream& os) const {
+void BlockTextRegion::dumpToStream(raw_ostream &os) const {
os << "block_code{" << (void*) this << '}';
}
-void BlockDataRegion::dumpToStream(llvm::raw_ostream& os) const {
+void BlockDataRegion::dumpToStream(raw_ostream &os) const {
os << "block_data{" << BC << '}';
}
-void CompoundLiteralRegion::dumpToStream(llvm::raw_ostream& os) const {
+void CompoundLiteralRegion::dumpToStream(raw_ostream &os) const {
// FIXME: More elaborate pretty-printing.
os << "{ " << (void*) CL << " }";
}
-void CXXTempObjectRegion::dumpToStream(llvm::raw_ostream &os) const {
- os << "temp_object";
+void CXXTempObjectRegion::dumpToStream(raw_ostream &os) const {
+ os << "temp_object{" << getValueType().getAsString() << ','
+ << (void*) Ex << '}';
}
-void CXXBaseObjectRegion::dumpToStream(llvm::raw_ostream &os) const {
+void CXXBaseObjectRegion::dumpToStream(raw_ostream &os) const {
os << "base " << decl->getName();
}
-void CXXThisRegion::dumpToStream(llvm::raw_ostream &os) const {
+void CXXThisRegion::dumpToStream(raw_ostream &os) const {
os << "this";
}
-void ElementRegion::dumpToStream(llvm::raw_ostream& os) const {
+void ElementRegion::dumpToStream(raw_ostream &os) const {
os << "element{" << superRegion << ','
<< Index << ',' << getElementType().getAsString() << '}';
}
-void FieldRegion::dumpToStream(llvm::raw_ostream& os) const {
- os << superRegion << "->" << getDecl();
+void FieldRegion::dumpToStream(raw_ostream &os) const {
+ os << superRegion << "->" << *getDecl();
}
-void NonStaticGlobalSpaceRegion::dumpToStream(llvm::raw_ostream &os) const {
+void NonStaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const {
os << "NonStaticGlobalSpaceRegion";
}
-void ObjCIvarRegion::dumpToStream(llvm::raw_ostream& os) const {
- os << "ivar{" << superRegion << ',' << getDecl() << '}';
+void ObjCIvarRegion::dumpToStream(raw_ostream &os) const {
+ os << "ivar{" << superRegion << ',' << *getDecl() << '}';
}
-void StringRegion::dumpToStream(llvm::raw_ostream& os) const {
+void StringRegion::dumpToStream(raw_ostream &os) const {
Str->printPretty(os, 0, PrintingPolicy(getContext().getLangOptions()));
}
-void SymbolicRegion::dumpToStream(llvm::raw_ostream& os) const {
+void SymbolicRegion::dumpToStream(raw_ostream &os) const {
os << "SymRegion{" << sym << '}';
}
-void VarRegion::dumpToStream(llvm::raw_ostream& os) const {
- os << cast<VarDecl>(D);
+void VarRegion::dumpToStream(raw_ostream &os) const {
+ os << *cast<VarDecl>(D);
}
void RegionRawOffset::dump() const {
dumpToStream(llvm::errs());
}
-void RegionRawOffset::dumpToStream(llvm::raw_ostream& os) const {
+void RegionRawOffset::dumpToStream(raw_ostream &os) const {
os << "raw_offset{" << getRegion() << ',' << getOffset().getQuantity() << '}';
}
-void StaticGlobalSpaceRegion::dumpToStream(llvm::raw_ostream &os) const {
+void StaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const {
os << "StaticGlobalsMemSpace{" << CR << '}';
}
@@ -631,7 +632,7 @@ MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC,
}
const CompoundLiteralRegion*
-MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL,
+MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr *CL,
const LocationContext *LC) {
const MemRegion *sReg = 0;
@@ -650,14 +651,14 @@ MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL,
const ElementRegion*
MemRegionManager::getElementRegion(QualType elementType, NonLoc Idx,
const MemRegion* superRegion,
- ASTContext& Ctx){
+ ASTContext &Ctx){
QualType T = Ctx.getCanonicalType(elementType).getUnqualifiedType();
llvm::FoldingSetNodeID ID;
ElementRegion::ProfileRegion(ID, T, Idx, superRegion);
- void* InsertPos;
+ void *InsertPos;
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
ElementRegion* R = cast_or_null<ElementRegion>(data);
@@ -688,13 +689,13 @@ const SymbolicRegion *MemRegionManager::getSymbolicRegion(SymbolRef sym) {
}
const FieldRegion*
-MemRegionManager::getFieldRegion(const FieldDecl* d,
+MemRegionManager::getFieldRegion(const FieldDecl *d,
const MemRegion* superRegion){
return getSubRegion<FieldRegion>(d, superRegion);
}
const ObjCIvarRegion*
-MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d,
+MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl *d,
const MemRegion* superRegion) {
return getSubRegion<ObjCIvarRegion>(d, superRegion);
}
@@ -724,7 +725,7 @@ MemRegionManager::getCXXThisRegion(QualType thisPointerTy,
}
const AllocaRegion*
-MemRegionManager::getAllocaRegion(const Expr* E, unsigned cnt,
+MemRegionManager::getAllocaRegion(const Expr *E, unsigned cnt,
const LocationContext *LC) {
const StackFrameContext *STC = LC->getCurrentStackFrame();
assert(STC);
@@ -896,7 +897,7 @@ RegionOffset MemRegion::getAsOffset() const {
case FieldRegionKind: {
const FieldRegion *FR = cast<FieldRegion>(R);
const RecordDecl *RD = FR->getDecl()->getParent();
- if (!RD->isDefinition())
+ if (!RD->isCompleteDefinition())
// We cannot compute offset for incomplete type.
return RegionOffset(0);
// Get the field number.
diff --git a/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/lib/StaticAnalyzer/Core/ObjCMessage.cpp
index c00060047498..0974fe877ac2 100644
--- a/lib/StaticAnalyzer/Core/ObjCMessage.cpp
+++ b/lib/StaticAnalyzer/Core/ObjCMessage.cpp
@@ -112,18 +112,22 @@ QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const {
QualType resultTy;
bool isLVal = false;
- if (CallE) {
- isLVal = CallE->isLValue();
- const Expr *Callee = CallE->getCallee();
- if (const FunctionDecl *FD = State->getSVal(Callee).getAsFunctionDecl())
- resultTy = FD->getResultType();
- else
- resultTy = CallE->getType();
- }
- else {
+ if (isObjCMessage()) {
isLVal = isa<ObjCMessageExpr>(Msg.getOriginExpr()) &&
Msg.getOriginExpr()->isLValue();
resultTy = Msg.getResultType(ctx);
+ } else if (const CXXConstructExpr *Ctor =
+ CallE.dyn_cast<const CXXConstructExpr *>()) {
+ resultTy = Ctor->getType();
+ } else {
+ const CallExpr *FunctionCall = CallE.get<const CallExpr *>();
+
+ isLVal = FunctionCall->isLValue();
+ const Expr *Callee = FunctionCall->getCallee();
+ if (const FunctionDecl *FD = State->getSVal(Callee).getAsFunctionDecl())
+ resultTy = FD->getResultType();
+ else
+ resultTy = FunctionCall->getType();
}
if (isLVal)
@@ -132,25 +136,29 @@ QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const {
return resultTy;
}
-SVal CallOrObjCMessage::getArgSValAsScalarOrLoc(unsigned i) const {
- assert(i < getNumArgs());
- if (CallE) return State->getSValAsScalarOrLoc(CallE->getArg(i));
- QualType argT = Msg.getArgType(i);
- if (Loc::isLocType(argT) || argT->isIntegerType())
- return Msg.getArgSVal(i, State);
- return UnknownVal();
-}
-
SVal CallOrObjCMessage::getFunctionCallee() const {
assert(isFunctionCall());
assert(!isCXXCall());
- const Expr *callee = CallE->getCallee()->IgnoreParenCasts();
- return State->getSVal(callee);
+ const Expr *Fun = CallE.get<const CallExpr *>()->getCallee()->IgnoreParens();
+ return State->getSVal(Fun);
}
SVal CallOrObjCMessage::getCXXCallee() const {
assert(isCXXCall());
+ const CallExpr *ActualCall = CallE.get<const CallExpr *>();
const Expr *callee =
- cast<CXXMemberCallExpr>(CallE)->getImplicitObjectArgument();
- return State->getSVal(callee);
+ cast<CXXMemberCallExpr>(ActualCall)->getImplicitObjectArgument();
+
+ // FIXME: Will eventually need to cope with member pointers. This is
+ // a limitation in getImplicitObjectArgument().
+ if (!callee)
+ return UnknownVal();
+
+ return State->getSVal(callee);
+}
+
+SVal
+CallOrObjCMessage::getInstanceMessageReceiver(const LocationContext *LC) const {
+ assert(isObjCMessage());
+ return Msg.getInstanceReceiverSVal(State, LC);
}
diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
index 872bbfe9e160..3a879030da11 100644
--- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -12,17 +12,16 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtCXX.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/Casting.h"
using namespace clang;
using namespace ento;
-using llvm::dyn_cast;
-using llvm::isa;
bool PathDiagnosticMacroPiece::containsEvent() const {
for (const_iterator I = begin(), E = end(); I!=E; ++I) {
@@ -37,14 +36,14 @@ bool PathDiagnosticMacroPiece::containsEvent() const {
return false;
}
-static llvm::StringRef StripTrailingDots(llvm::StringRef s) {
- for (llvm::StringRef::size_type i = s.size(); i != 0; --i)
+static StringRef StripTrailingDots(StringRef s) {
+ for (StringRef::size_type i = s.size(); i != 0; --i)
if (s[i - 1] != '.')
return s.substr(0, i);
return "";
}
-PathDiagnosticPiece::PathDiagnosticPiece(llvm::StringRef s,
+PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
Kind k, DisplayHint hint)
: str(StripTrailingDots(s)), kind(k), Hint(hint) {}
@@ -76,55 +75,161 @@ void PathDiagnostic::resetPath(bool deletePieces) {
}
-PathDiagnostic::PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc,
- llvm::StringRef category)
+PathDiagnostic::PathDiagnostic(StringRef bugtype, StringRef desc,
+ StringRef category)
: Size(0),
BugType(StripTrailingDots(bugtype)),
Desc(StripTrailingDots(desc)),
Category(StripTrailingDots(category)) {}
-void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
- const DiagnosticInfo &Info) {
- // Default implementation (Warnings/errors count).
- DiagnosticClient::HandleDiagnostic(DiagLevel, Info);
+void PathDiagnosticConsumer::HandlePathDiagnostic(const PathDiagnostic *D) {
+ // For now this simply forwards to HandlePathDiagnosticImpl. In the future
+ // we can use this indirection to control for multi-threaded access to
+ // the PathDiagnosticConsumer from multiple bug reporters.
+ HandlePathDiagnosticImpl(D);
+}
+
+//===----------------------------------------------------------------------===//
+// PathDiagnosticLocation methods.
+//===----------------------------------------------------------------------===//
+
+static SourceLocation getValidSourceLocation(const Stmt* S,
+ LocationOrAnalysisContext LAC) {
+ SourceLocation L = S->getLocStart();
+ assert(!LAC.isNull() && "A valid LocationContext or AnalysisContext should "
+ "be passed to PathDiagnosticLocation upon creation.");
+
+ // S might be a temporary statement that does not have a location in the
+ // source code, so find an enclosing statement and use it's location.
+ if (!L.isValid()) {
+
+ ParentMap *PM = 0;
+ if (LAC.is<const LocationContext*>())
+ PM = &LAC.get<const LocationContext*>()->getParentMap();
+ else
+ PM = &LAC.get<AnalysisContext*>()->getParentMap();
+
+ while (!L.isValid()) {
+ S = PM->getParent(S);
+ L = S->getLocStart();
+ }
+ }
+
+ return L;
+}
- // Create a PathDiagnostic with a single piece.
+PathDiagnosticLocation
+ PathDiagnosticLocation::createBegin(const Decl *D,
+ const SourceManager &SM) {
+ return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK);
+}
- PathDiagnostic* D = new PathDiagnostic();
+PathDiagnosticLocation
+ PathDiagnosticLocation::createBegin(const Stmt *S,
+ const SourceManager &SM,
+ LocationOrAnalysisContext LAC) {
+ return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
+ SM, SingleLocK);
+}
- const char *LevelStr;
- switch (DiagLevel) {
- default:
- case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type");
- case Diagnostic::Note: LevelStr = "note: "; break;
- case Diagnostic::Warning: LevelStr = "warning: "; break;
- case Diagnostic::Error: LevelStr = "error: "; break;
- case Diagnostic::Fatal: LevelStr = "fatal error: "; break;
+PathDiagnosticLocation
+ PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
+ const SourceManager &SM) {
+ return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
+}
+
+PathDiagnosticLocation
+ PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
+ const SourceManager &SM) {
+ return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
+}
+
+PathDiagnosticLocation
+ PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
+ const SourceManager &SM) {
+ SourceLocation L = CS->getLBracLoc();
+ return PathDiagnosticLocation(L, SM, SingleLocK);
+}
+
+PathDiagnosticLocation
+ PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
+ const SourceManager &SM) {
+ SourceLocation L = CS->getRBracLoc();
+ return PathDiagnosticLocation(L, SM, SingleLocK);
+}
+
+PathDiagnosticLocation
+ PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
+ const SourceManager &SM) {
+ // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
+ if (const CompoundStmt *CS =
+ dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
+ if (!CS->body_empty()) {
+ SourceLocation Loc = (*CS->body_begin())->getLocStart();
+ return PathDiagnosticLocation(Loc, SM, SingleLocK);
+ }
+
+ return PathDiagnosticLocation();
+}
+
+PathDiagnosticLocation
+ PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
+ const SourceManager &SM) {
+ SourceLocation L = LC->getDecl()->getBodyRBrace();
+ return PathDiagnosticLocation(L, SM, SingleLocK);
+}
+
+PathDiagnosticLocation
+ PathDiagnosticLocation::create(const ProgramPoint& P,
+ const SourceManager &SMng) {
+
+ const Stmt* S = 0;
+ if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+ const CFGBlock *BSrc = BE->getSrc();
+ S = BSrc->getTerminatorCondition();
+ }
+ else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
+ S = PS->getStmt();
}
- llvm::SmallString<100> StrC;
- StrC += LevelStr;
- Info.FormatDiagnostic(StrC);
+ return PathDiagnosticLocation(S, SMng, P.getLocationContext());
- PathDiagnosticPiece *P =
- new PathDiagnosticEventPiece(FullSourceLoc(Info.getLocation(),
- Info.getSourceManager()),
- StrC.str());
+ if (!S)
+ return PathDiagnosticLocation();
+}
- for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i)
- P->addRange(Info.getRange(i).getAsRange());
- for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i)
- P->addFixItHint(Info.getFixItHint(i));
- D->push_front(P);
+PathDiagnosticLocation
+ PathDiagnosticLocation::createEndOfPath(const ExplodedNode* N,
+ const SourceManager &SM) {
+ assert(N && "Cannot create a location with a null node.");
+
+ const ExplodedNode *NI = N;
+
+ while (NI) {
+ ProgramPoint P = NI->getLocation();
+ const LocationContext *LC = P.getLocationContext();
+ if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P))
+ return PathDiagnosticLocation(PS->getStmt(), SM, LC);
+ else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+ const Stmt *Term = BE->getSrc()->getTerminator();
+ assert(Term);
+ return PathDiagnosticLocation(Term, SM, LC);
+ }
+ NI = NI->succ_empty() ? 0 : *(NI->succ_begin());
+ }
- HandlePathDiagnostic(D);
+ return createDeclEnd(N->getLocationContext(), SM);
}
-//===----------------------------------------------------------------------===//
-// PathDiagnosticLocation methods.
-//===----------------------------------------------------------------------===//
+PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
+ const PathDiagnosticLocation &PDL) {
+ FullSourceLoc L = PDL.asLocation();
+ return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
+}
-FullSourceLoc PathDiagnosticLocation::asLocation() const {
+FullSourceLoc
+ PathDiagnosticLocation::genLocation(SourceLocation L,
+ LocationOrAnalysisContext LAC) const {
assert(isValid());
// Note that we want a 'switch' here so that the compiler can warn us in
// case we add more cases.
@@ -133,21 +238,23 @@ FullSourceLoc PathDiagnosticLocation::asLocation() const {
case RangeK:
break;
case StmtK:
- return FullSourceLoc(S->getLocStart(), const_cast<SourceManager&>(*SM));
+ return FullSourceLoc(getValidSourceLocation(S, LAC),
+ const_cast<SourceManager&>(*SM));
case DeclK:
return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
}
- return FullSourceLoc(R.getBegin(), const_cast<SourceManager&>(*SM));
+ return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
}
-PathDiagnosticRange PathDiagnosticLocation::asRange() const {
+PathDiagnosticRange
+ PathDiagnosticLocation::genRange(LocationOrAnalysisContext LAC) const {
assert(isValid());
// Note that we want a 'switch' here so that the compiler can warn us in
// case we add more cases.
switch (K) {
case SingleLocK:
- return PathDiagnosticRange(R, true);
+ return PathDiagnosticRange(SourceRange(Loc,Loc), true);
case RangeK:
break;
case StmtK: {
@@ -176,12 +283,14 @@ PathDiagnosticRange PathDiagnosticLocation::asRange() const {
case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass:
case Stmt::ObjCForCollectionStmtClass: {
- SourceLocation L = S->getLocStart();
+ SourceLocation L = getValidSourceLocation(S, LAC);
return SourceRange(L, L);
}
}
-
- return S->getSourceRange();
+ SourceRange R = S->getSourceRange();
+ if (R.isValid())
+ return R;
+ break;
}
case DeclK:
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
@@ -196,19 +305,16 @@ PathDiagnosticRange PathDiagnosticLocation::asRange() const {
}
}
- return R;
+ return SourceRange(Loc,Loc);
}
void PathDiagnosticLocation::flatten() {
if (K == StmtK) {
- R = asRange();
K = RangeK;
S = 0;
D = 0;
}
else if (K == DeclK) {
- SourceLocation L = D->getLocation();
- R = SourceRange(L, L);
K = SingleLocK;
S = 0;
D = 0;
@@ -220,22 +326,9 @@ void PathDiagnosticLocation::flatten() {
//===----------------------------------------------------------------------===//
void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddInteger((unsigned) K);
- switch (K) {
- case RangeK:
- ID.AddInteger(R.getBegin().getRawEncoding());
- ID.AddInteger(R.getEnd().getRawEncoding());
- break;
- case SingleLocK:
- ID.AddInteger(R.getBegin().getRawEncoding());
- break;
- case StmtK:
- ID.Add(S);
- break;
- case DeclK:
- ID.Add(D);
- break;
- }
+ ID.AddInteger(Range.getBegin().getRawEncoding());
+ ID.AddInteger(Range.getEnd().getRawEncoding());
+ ID.AddInteger(Loc.getRawEncoding());
return;
}
diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index fbbbd46ac149..5ae95c61f819 100644
--- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Core/PathDiagnosticClients.h"
+#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
@@ -22,14 +22,9 @@
#include "llvm/ADT/SmallVector.h"
using namespace clang;
using namespace ento;
-using llvm::cast;
typedef llvm::DenseMap<FileID, unsigned> FIDMap;
-namespace clang {
- class Preprocessor;
-}
-
namespace {
struct CompareDiagnostics {
// Compare if 'X' is "<" than 'Y'.
@@ -43,16 +38,16 @@ struct CompareDiagnostics {
return false;
// Next, compare by bug type.
- llvm::StringRef XBugType = X->getBugType();
- llvm::StringRef YBugType = Y->getBugType();
+ StringRef XBugType = X->getBugType();
+ StringRef YBugType = Y->getBugType();
if (XBugType < YBugType)
return true;
if (XBugType != YBugType)
return false;
// Next, compare by bug description.
- llvm::StringRef XDesc = X->getDescription();
- llvm::StringRef YDesc = Y->getDescription();
+ StringRef XDesc = X->getDescription();
+ StringRef YDesc = Y->getDescription();
if (XDesc < YDesc)
return true;
if (XDesc != YDesc)
@@ -65,23 +60,23 @@ struct CompareDiagnostics {
}
namespace {
- class PlistDiagnostics : public PathDiagnosticClient {
+ class PlistDiagnostics : public PathDiagnosticConsumer {
std::vector<const PathDiagnostic*> BatchedDiags;
const std::string OutputFile;
const LangOptions &LangOpts;
- llvm::OwningPtr<PathDiagnosticClient> SubPD;
+ llvm::OwningPtr<PathDiagnosticConsumer> SubPD;
bool flushed;
public:
PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts,
- PathDiagnosticClient *subPD);
+ PathDiagnosticConsumer *subPD);
~PlistDiagnostics() { FlushDiagnostics(NULL); }
- void FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade);
+ void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade);
- void HandlePathDiagnostic(const PathDiagnostic* D);
+ void HandlePathDiagnosticImpl(const PathDiagnostic* D);
- virtual llvm::StringRef getName() const {
+ virtual StringRef getName() const {
return "PlistDiagnostics";
}
@@ -94,27 +89,27 @@ namespace {
PlistDiagnostics::PlistDiagnostics(const std::string& output,
const LangOptions &LO,
- PathDiagnosticClient *subPD)
+ PathDiagnosticConsumer *subPD)
: OutputFile(output), LangOpts(LO), SubPD(subPD), flushed(false) {}
-PathDiagnosticClient*
-ento::createPlistDiagnosticClient(const std::string& s, const Preprocessor &PP,
- PathDiagnosticClient *subPD) {
+PathDiagnosticConsumer*
+ento::createPlistDiagnosticConsumer(const std::string& s, const Preprocessor &PP,
+ PathDiagnosticConsumer *subPD) {
return new PlistDiagnostics(s, PP.getLangOptions(), subPD);
}
-PathDiagnosticClient::PathGenerationScheme
+PathDiagnosticConsumer::PathGenerationScheme
PlistDiagnostics::getGenerationScheme() const {
- if (const PathDiagnosticClient *PD = SubPD.get())
+ if (const PathDiagnosticConsumer *PD = SubPD.get())
return PD->getGenerationScheme();
return Extensive;
}
-static void AddFID(FIDMap &FIDs, llvm::SmallVectorImpl<FileID> &V,
+static void AddFID(FIDMap &FIDs, SmallVectorImpl<FileID> &V,
const SourceManager* SM, SourceLocation L) {
- FileID FID = SM->getFileID(SM->getInstantiationLoc(L));
+ FileID FID = SM->getFileID(SM->getExpansionLoc(L));
FIDMap::iterator I = FIDs.find(FID);
if (I != FIDs.end()) return;
FIDs[FID] = V.size();
@@ -123,23 +118,23 @@ static void AddFID(FIDMap &FIDs, llvm::SmallVectorImpl<FileID> &V,
static unsigned GetFID(const FIDMap& FIDs, const SourceManager &SM,
SourceLocation L) {
- FileID FID = SM.getFileID(SM.getInstantiationLoc(L));
+ FileID FID = SM.getFileID(SM.getExpansionLoc(L));
FIDMap::const_iterator I = FIDs.find(FID);
assert(I != FIDs.end());
return I->second;
}
-static llvm::raw_ostream& Indent(llvm::raw_ostream& o, const unsigned indent) {
+static raw_ostream &Indent(raw_ostream &o, const unsigned indent) {
for (unsigned i = 0; i < indent; ++i) o << ' ';
return o;
}
-static void EmitLocation(llvm::raw_ostream& o, const SourceManager &SM,
+static void EmitLocation(raw_ostream &o, const SourceManager &SM,
const LangOptions &LangOpts,
SourceLocation L, const FIDMap &FM,
unsigned indent, bool extend = false) {
- FullSourceLoc Loc(SM.getInstantiationLoc(L), const_cast<SourceManager&>(SM));
+ FullSourceLoc Loc(SM.getExpansionLoc(L), const_cast<SourceManager&>(SM));
// Add in the length of the token, so that we cover multi-char tokens.
unsigned offset =
@@ -147,22 +142,22 @@ static void EmitLocation(llvm::raw_ostream& o, const SourceManager &SM,
Indent(o, indent) << "<dict>\n";
Indent(o, indent) << " <key>line</key><integer>"
- << Loc.getInstantiationLineNumber() << "</integer>\n";
+ << Loc.getExpansionLineNumber() << "</integer>\n";
Indent(o, indent) << " <key>col</key><integer>"
- << Loc.getInstantiationColumnNumber() + offset << "</integer>\n";
+ << Loc.getExpansionColumnNumber() + offset << "</integer>\n";
Indent(o, indent) << " <key>file</key><integer>"
<< GetFID(FM, SM, Loc) << "</integer>\n";
Indent(o, indent) << "</dict>\n";
}
-static void EmitLocation(llvm::raw_ostream& o, const SourceManager &SM,
+static void EmitLocation(raw_ostream &o, const SourceManager &SM,
const LangOptions &LangOpts,
const PathDiagnosticLocation &L, const FIDMap& FM,
unsigned indent, bool extend = false) {
EmitLocation(o, SM, LangOpts, L.asLocation(), FM, indent, extend);
}
-static void EmitRange(llvm::raw_ostream& o, const SourceManager &SM,
+static void EmitRange(raw_ostream &o, const SourceManager &SM,
const LangOptions &LangOpts,
PathDiagnosticRange R, const FIDMap &FM,
unsigned indent) {
@@ -172,7 +167,7 @@ static void EmitRange(llvm::raw_ostream& o, const SourceManager &SM,
Indent(o, indent) << "</array>\n";
}
-static llvm::raw_ostream& EmitString(llvm::raw_ostream& o,
+static raw_ostream &EmitString(raw_ostream &o,
const std::string& s) {
o << "<string>";
for (std::string::const_iterator I=s.begin(), E=s.end(); I!=E; ++I) {
@@ -190,7 +185,7 @@ static llvm::raw_ostream& EmitString(llvm::raw_ostream& o,
return o;
}
-static void ReportControlFlow(llvm::raw_ostream& o,
+static void ReportControlFlow(raw_ostream &o,
const PathDiagnosticControlFlowPiece& P,
const FIDMap& FM,
const SourceManager &SM,
@@ -233,7 +228,7 @@ static void ReportControlFlow(llvm::raw_ostream& o,
Indent(o, indent) << "</dict>\n";
}
-static void ReportEvent(llvm::raw_ostream& o, const PathDiagnosticPiece& P,
+static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P,
const FIDMap& FM,
const SourceManager &SM,
const LangOptions &LangOpts,
@@ -280,7 +275,7 @@ static void ReportEvent(llvm::raw_ostream& o, const PathDiagnosticPiece& P,
Indent(o, indent); o << "</dict>\n";
}
-static void ReportMacro(llvm::raw_ostream& o,
+static void ReportMacro(raw_ostream &o,
const PathDiagnosticMacroPiece& P,
const FIDMap& FM, const SourceManager &SM,
const LangOptions &LangOpts,
@@ -304,7 +299,7 @@ static void ReportMacro(llvm::raw_ostream& o,
}
}
-static void ReportDiag(llvm::raw_ostream& o, const PathDiagnosticPiece& P,
+static void ReportDiag(raw_ostream &o, const PathDiagnosticPiece& P,
const FIDMap& FM, const SourceManager &SM,
const LangOptions &LangOpts) {
@@ -326,7 +321,7 @@ static void ReportDiag(llvm::raw_ostream& o, const PathDiagnosticPiece& P,
}
}
-void PlistDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
+void PlistDiagnostics::HandlePathDiagnosticImpl(const PathDiagnostic* D) {
if (!D)
return;
@@ -342,7 +337,7 @@ void PlistDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
BatchedDiags.push_back(D);
}
-void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string>
+void PlistDiagnostics::FlushDiagnostics(SmallVectorImpl<std::string>
*FilesMade) {
if (flushed)
@@ -358,7 +353,7 @@ void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string>
// Build up a set of FIDs that we use by scanning the locations and
// ranges of the diagnostics.
FIDMap FM;
- llvm::SmallVector<FileID, 10> Fids;
+ SmallVector<FileID, 10> Fids;
const SourceManager* SM = 0;
if (!BatchedDiags.empty())
@@ -401,7 +396,7 @@ void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string>
" <key>files</key>\n"
" <array>\n";
- for (llvm::SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end();
+ for (SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end();
I!=E; ++I) {
o << " ";
EmitString(o, SM->getFileEntryForID(*I)->getName()) << '\n';
@@ -444,7 +439,7 @@ void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string>
// Output the diagnostic to the sub-diagnostic client, if any.
if (SubPD) {
SubPD->HandlePathDiagnostic(OwnedD.take());
- llvm::SmallVector<std::string, 1> SubFilesMade;
+ SmallVector<std::string, 1> SubFilesMade;
SubPD->FlushDiagnostics(SubFilesMade);
if (!SubFilesMade.empty()) {
diff --git a/lib/StaticAnalyzer/Core/GRState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index 0f6ff1ef588c..73788cc42efb 100644
--- a/lib/StaticAnalyzer/Core/GRState.cpp
+++ b/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -1,4 +1,4 @@
-//= GRState.cpp - Path-Sensitive "State" for tracking values -----*- C++ -*--=//
+//= ProgramState.cpp - Path-Sensitive "State" for tracking values --*- C++ -*--=
//
// The LLVM Compiler Infrastructure
//
@@ -7,15 +7,14 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements GRState and GRStateManager.
+// This file implements ProgramState and ProgramStateManager.
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/CFG.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.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/TransferFuncs.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -25,7 +24,7 @@ using namespace ento;
// FIXME: Move this elsewhere.
ConstraintManager::~ConstraintManager() {}
-GRState::GRState(GRStateManager *mgr, const Environment& env,
+ProgramState::ProgramState(ProgramStateManager *mgr, const Environment& env,
StoreRef st, GenericDataMap gdm)
: stateMgr(mgr),
Env(env),
@@ -35,7 +34,7 @@ GRState::GRState(GRStateManager *mgr, const Environment& env,
stateMgr->getStoreManager().incrementReferenceCount(store);
}
-GRState::GRState(const GRState& RHS)
+ProgramState::ProgramState(const ProgramState &RHS)
: llvm::FoldingSetNode(),
stateMgr(RHS.stateMgr),
Env(RHS.Env),
@@ -45,23 +44,19 @@ GRState::GRState(const GRState& RHS)
stateMgr->getStoreManager().incrementReferenceCount(store);
}
-GRState::~GRState() {
+ProgramState::~ProgramState() {
if (store)
stateMgr->getStoreManager().decrementReferenceCount(store);
}
-GRStateManager::~GRStateManager() {
- for (std::vector<GRState::Printer*>::iterator I=Printers.begin(),
- E=Printers.end(); I!=E; ++I)
- delete *I;
-
+ProgramStateManager::~ProgramStateManager() {
for (GDMContextsTy::iterator I=GDMContexts.begin(), E=GDMContexts.end();
I!=E; ++I)
I->second.second(I->second.first);
}
-const GRState*
-GRStateManager::removeDeadBindings(const GRState* state,
+const ProgramState*
+ProgramStateManager::removeDeadBindings(const ProgramState *state,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper) {
@@ -71,23 +66,23 @@ GRStateManager::removeDeadBindings(const GRState* state,
// those around. This code more than likely can be made faster, and the
// frequency of which this method is called should be experimented with
// for optimum performance.
- llvm::SmallVector<const MemRegion*, 10> RegionRoots;
- GRState NewState = *state;
+ ProgramState NewState = *state;
- NewState.Env = EnvMgr.removeDeadBindings(NewState.Env, SymReaper,
- state, RegionRoots);
+ NewState.Env = EnvMgr.removeDeadBindings(NewState.Env, SymReaper, state);
// Clean up the store.
- NewState.setStore(StoreMgr->removeDeadBindings(NewState.getStore(), LCtx,
- SymReaper, RegionRoots));
- state = getPersistentState(NewState);
- return ConstraintMgr->removeDeadBindings(state, SymReaper);
+ StoreRef newStore = StoreMgr->removeDeadBindings(NewState.getStore(), LCtx,
+ SymReaper);
+ NewState.setStore(newStore);
+ SymReaper.setReapedStore(newStore);
+
+ return getPersistentState(NewState);
}
-const GRState *GRStateManager::MarshalState(const GRState *state,
+const ProgramState *ProgramStateManager::MarshalState(const ProgramState *state,
const StackFrameContext *InitLoc) {
// make up an empty state for now.
- GRState State(this,
+ ProgramState State(this,
EnvMgr.getInitialEnvironment(),
StoreMgr->getInitialStore(InitLoc),
GDMFactory.getEmptyMap());
@@ -95,7 +90,7 @@ const GRState *GRStateManager::MarshalState(const GRState *state,
return getPersistentState(State);
}
-const GRState *GRState::bindCompoundLiteral(const CompoundLiteralExpr* CL,
+const ProgramState *ProgramState::bindCompoundLiteral(const CompoundLiteralExpr *CL,
const LocationContext *LC,
SVal V) const {
const StoreRef &newStore =
@@ -103,21 +98,21 @@ const GRState *GRState::bindCompoundLiteral(const CompoundLiteralExpr* CL,
return makeWithStore(newStore);
}
-const GRState *GRState::bindDecl(const VarRegion* VR, SVal IVal) const {
+const ProgramState *ProgramState::bindDecl(const VarRegion* VR, SVal IVal) const {
const StoreRef &newStore =
getStateManager().StoreMgr->BindDecl(getStore(), VR, IVal);
return makeWithStore(newStore);
}
-const GRState *GRState::bindDeclWithNoInit(const VarRegion* VR) const {
+const ProgramState *ProgramState::bindDeclWithNoInit(const VarRegion* VR) const {
const StoreRef &newStore =
getStateManager().StoreMgr->BindDeclWithNoInit(getStore(), VR);
return makeWithStore(newStore);
}
-const GRState *GRState::bindLoc(Loc LV, SVal V) const {
- GRStateManager &Mgr = getStateManager();
- const GRState *newState = makeWithStore(Mgr.StoreMgr->Bind(getStore(),
+const ProgramState *ProgramState::bindLoc(Loc LV, SVal V) const {
+ ProgramStateManager &Mgr = getStateManager();
+ const ProgramState *newState = makeWithStore(Mgr.StoreMgr->Bind(getStore(),
LV, V));
const MemRegion *MR = LV.getAsRegion();
if (MR && Mgr.getOwningEngine())
@@ -126,56 +121,53 @@ const GRState *GRState::bindLoc(Loc LV, SVal V) const {
return newState;
}
-const GRState *GRState::bindDefault(SVal loc, SVal V) const {
- GRStateManager &Mgr = getStateManager();
+const ProgramState *ProgramState::bindDefault(SVal loc, SVal V) const {
+ ProgramStateManager &Mgr = getStateManager();
const MemRegion *R = cast<loc::MemRegionVal>(loc).getRegion();
const StoreRef &newStore = Mgr.StoreMgr->BindDefault(getStore(), R, V);
- const GRState *new_state = makeWithStore(newStore);
+ const ProgramState *new_state = makeWithStore(newStore);
return Mgr.getOwningEngine() ?
Mgr.getOwningEngine()->processRegionChange(new_state, R) :
new_state;
}
-const GRState *GRState::invalidateRegions(const MemRegion * const *Begin,
- const MemRegion * const *End,
- const Expr *E, unsigned Count,
- StoreManager::InvalidatedSymbols *IS,
- bool invalidateGlobals) const {
+const ProgramState *
+ProgramState::invalidateRegions(ArrayRef<const MemRegion *> Regions,
+ const Expr *E, unsigned Count,
+ StoreManager::InvalidatedSymbols *IS,
+ bool invalidateGlobals) const {
if (!IS) {
StoreManager::InvalidatedSymbols invalidated;
- return invalidateRegionsImpl(Begin, End, E, Count,
- invalidated, invalidateGlobals);
+ return invalidateRegionsImpl(Regions, E, Count,
+ invalidated, invalidateGlobals);
}
- return invalidateRegionsImpl(Begin, End, E, Count, *IS, invalidateGlobals);
+ return invalidateRegionsImpl(Regions, E, Count, *IS, invalidateGlobals);
}
-const GRState *
-GRState::invalidateRegionsImpl(const MemRegion * const *Begin,
- const MemRegion * const *End,
- const Expr *E, unsigned Count,
- StoreManager::InvalidatedSymbols &IS,
- bool invalidateGlobals) const {
- GRStateManager &Mgr = getStateManager();
+const ProgramState *
+ProgramState::invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions,
+ const Expr *E, unsigned Count,
+ StoreManager::InvalidatedSymbols &IS,
+ bool invalidateGlobals) const {
+ ProgramStateManager &Mgr = getStateManager();
SubEngine* Eng = Mgr.getOwningEngine();
if (Eng && Eng->wantsRegionChangeUpdate(this)) {
- StoreManager::InvalidatedRegions Regions;
+ StoreManager::InvalidatedRegions Invalidated;
const StoreRef &newStore
- = Mgr.StoreMgr->invalidateRegions(getStore(), Begin, End, E, Count, IS,
- invalidateGlobals, &Regions);
- const GRState *newState = makeWithStore(newStore);
- return Eng->processRegionChanges(newState, &IS,
- &Regions.front(),
- &Regions.back()+1);
+ = Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, IS,
+ invalidateGlobals, &Invalidated);
+ const ProgramState *newState = makeWithStore(newStore);
+ return Eng->processRegionChanges(newState, &IS, Regions, Invalidated);
}
const StoreRef &newStore =
- Mgr.StoreMgr->invalidateRegions(getStore(), Begin, End, E, Count, IS,
+ Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, IS,
invalidateGlobals, NULL);
return makeWithStore(newStore);
}
-const GRState *GRState::unbindLoc(Loc LV) const {
+const ProgramState *ProgramState::unbindLoc(Loc LV) const {
assert(!isa<loc::MemRegionVal>(LV) && "Use invalidateRegion instead.");
Store OldStore = getStore();
@@ -187,20 +179,20 @@ const GRState *GRState::unbindLoc(Loc LV) const {
return makeWithStore(newStore);
}
-const GRState *GRState::enterStackFrame(const StackFrameContext *frame) const {
+const ProgramState *ProgramState::enterStackFrame(const StackFrameContext *frame) const {
const StoreRef &new_store =
getStateManager().StoreMgr->enterStackFrame(this, frame);
return makeWithStore(new_store);
}
-SVal GRState::getSValAsScalarOrLoc(const MemRegion *R) const {
+SVal ProgramState::getSValAsScalarOrLoc(const MemRegion *R) const {
// We only want to do fetches from regions that we can actually bind
// values. For example, SymbolicRegions of type 'id<...>' cannot
// have direct bindings (but their can be bindings on their subregions).
if (!R->isBoundable())
return UnknownVal();
- if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
+ if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) {
QualType T = TR->getValueType();
if (Loc::isLocType(T) || T->isIntegerType())
return getSVal(R);
@@ -209,7 +201,7 @@ SVal GRState::getSValAsScalarOrLoc(const MemRegion *R) const {
return UnknownVal();
}
-SVal GRState::getSVal(Loc location, QualType T) const {
+SVal ProgramState::getSVal(Loc location, QualType T) const {
SVal V = getRawSVal(cast<Loc>(location), T);
// If 'V' is a symbolic value that is *perfectly* constrained to
@@ -246,18 +238,18 @@ SVal GRState::getSVal(Loc location, QualType T) const {
return V;
}
-const GRState *GRState::BindExpr(const Stmt* S, SVal V, bool Invalidate) const{
+const ProgramState *ProgramState::BindExpr(const Stmt *S, SVal V, bool Invalidate) const{
Environment NewEnv = getStateManager().EnvMgr.bindExpr(Env, S, V,
Invalidate);
if (NewEnv == Env)
return this;
- GRState NewSt = *this;
+ ProgramState NewSt = *this;
NewSt.Env = NewEnv;
return getStateManager().getPersistentState(NewSt);
}
-const GRState *GRState::bindExprAndLocation(const Stmt *S, SVal location,
+const ProgramState *ProgramState::bindExprAndLocation(const Stmt *S, SVal location,
SVal V) const {
Environment NewEnv =
getStateManager().EnvMgr.bindExprAndLocation(Env, S, location, V);
@@ -265,12 +257,12 @@ const GRState *GRState::bindExprAndLocation(const Stmt *S, SVal location,
if (NewEnv == Env)
return this;
- GRState NewSt = *this;
+ ProgramState NewSt = *this;
NewSt.Env = NewEnv;
return getStateManager().getPersistentState(NewSt);
}
-const GRState *GRState::assumeInBound(DefinedOrUnknownSVal Idx,
+const ProgramState *ProgramState::assumeInBound(DefinedOrUnknownSVal Idx,
DefinedOrUnknownSVal UpperBound,
bool Assumption) const {
if (Idx.isUnknown() || UpperBound.isUnknown())
@@ -279,7 +271,7 @@ const GRState *GRState::assumeInBound(DefinedOrUnknownSVal Idx,
// Build an expression for 0 <= Idx < UpperBound.
// This is the same as Idx + MIN < UpperBound + MIN, if overflow is allowed.
// FIXME: This should probably be part of SValBuilder.
- GRStateManager &SM = getStateManager();
+ ProgramStateManager &SM = getStateManager();
SValBuilder &svalBuilder = SM.getSValBuilder();
ASTContext &Ctx = svalBuilder.getContext();
@@ -315,8 +307,8 @@ const GRState *GRState::assumeInBound(DefinedOrUnknownSVal Idx,
return CM.assume(this, cast<DefinedSVal>(inBound), Assumption);
}
-const GRState* GRStateManager::getInitialState(const LocationContext *InitLoc) {
- GRState State(this,
+const ProgramState *ProgramStateManager::getInitialState(const LocationContext *InitLoc) {
+ ProgramState State(this,
EnvMgr.getInitialEnvironment(),
StoreMgr->getInitialStore(InitLoc),
GDMFactory.getEmptyMap());
@@ -324,49 +316,57 @@ const GRState* GRStateManager::getInitialState(const LocationContext *InitLoc) {
return getPersistentState(State);
}
-void GRStateManager::recycleUnusedStates() {
- for (std::vector<GRState*>::iterator i = recentlyAllocatedStates.begin(),
+void ProgramStateManager::recycleUnusedStates() {
+ for (std::vector<ProgramState*>::iterator i = recentlyAllocatedStates.begin(),
e = recentlyAllocatedStates.end(); i != e; ++i) {
- GRState *state = *i;
+ ProgramState *state = *i;
if (state->referencedByExplodedNode())
continue;
StateSet.RemoveNode(state);
freeStates.push_back(state);
- state->~GRState();
+ state->~ProgramState();
}
recentlyAllocatedStates.clear();
}
-const GRState* GRStateManager::getPersistentState(GRState& State) {
+const ProgramState *ProgramStateManager::getPersistentStateWithGDM(
+ const ProgramState *FromState,
+ const ProgramState *GDMState) {
+ ProgramState NewState = *FromState;
+ NewState.GDM = GDMState->GDM;
+ return getPersistentState(NewState);
+}
+
+const ProgramState *ProgramStateManager::getPersistentState(ProgramState &State) {
llvm::FoldingSetNodeID ID;
State.Profile(ID);
- void* InsertPos;
+ void *InsertPos;
- if (GRState* I = StateSet.FindNodeOrInsertPos(ID, InsertPos))
+ if (ProgramState *I = StateSet.FindNodeOrInsertPos(ID, InsertPos))
return I;
- GRState *newState = 0;
+ ProgramState *newState = 0;
if (!freeStates.empty()) {
newState = freeStates.back();
freeStates.pop_back();
}
else {
- newState = (GRState*) Alloc.Allocate<GRState>();
+ newState = (ProgramState*) Alloc.Allocate<ProgramState>();
}
- new (newState) GRState(State);
+ new (newState) ProgramState(State);
StateSet.InsertNode(newState, InsertPos);
recentlyAllocatedStates.push_back(newState);
return newState;
}
-const GRState* GRState::makeWithStore(const StoreRef &store) const {
- GRState NewSt = *this;
+const ProgramState *ProgramState::makeWithStore(const StoreRef &store) const {
+ ProgramState NewSt = *this;
NewSt.setStore(store);
return getStateManager().getPersistentState(NewSt);
}
-void GRState::setStore(const StoreRef &newStore) {
+void ProgramState::setStore(const StoreRef &newStore) {
Store newStoreStore = newStore.getStore();
if (newStoreStore)
stateMgr->getStoreManager().incrementReferenceCount(newStoreStore);
@@ -384,11 +384,11 @@ static bool IsEnvLoc(const Stmt *S) {
return (bool) (((uintptr_t) S) & 0x1);
}
-void GRState::print(llvm::raw_ostream& Out, CFG &C, const char* nl,
- const char* sep) const {
+void ProgramState::print(raw_ostream &Out, CFG &C,
+ const char *NL, const char *Sep) const {
// Print the store.
- GRStateManager &Mgr = getStateManager();
- Mgr.getStoreManager().print(getStore(), Out, nl, sep);
+ ProgramStateManager &Mgr = getStateManager();
+ Mgr.getStoreManager().print(getStore(), Out, NL, Sep);
// Print Subexpression bindings.
bool isFirst = true;
@@ -399,10 +399,11 @@ void GRState::print(llvm::raw_ostream& Out, CFG &C, const char* nl,
continue;
if (isFirst) {
- Out << nl << nl << "Sub-Expressions:" << nl;
+ Out << NL << NL << "Sub-Expressions:" << NL;
isFirst = false;
+ } else {
+ Out << NL;
}
- else { Out << nl; }
Out << " (" << (void*) I.getKey() << ") ";
LangOptions LO; // FIXME.
@@ -418,10 +419,11 @@ void GRState::print(llvm::raw_ostream& Out, CFG &C, const char* nl,
continue;
if (isFirst) {
- Out << nl << nl << "Block-level Expressions:" << nl;
+ Out << NL << NL << "Block-level Expressions:" << NL;
isFirst = false;
+ } else {
+ Out << NL;
}
- else { Out << nl; }
Out << " (" << (void*) I.getKey() << ") ";
LangOptions LO; // FIXME.
@@ -437,10 +439,11 @@ void GRState::print(llvm::raw_ostream& Out, CFG &C, const char* nl,
continue;
if (isFirst) {
- Out << nl << nl << "Load/store locations:" << nl;
+ Out << NL << NL << "Load/store locations:" << NL;
isFirst = false;
+ } else {
+ Out << NL;
}
- else { Out << nl; }
const Stmt *S = (Stmt*) (((uintptr_t) I.getKey()) & ((uintptr_t) ~0x1));
@@ -450,20 +453,17 @@ void GRState::print(llvm::raw_ostream& Out, CFG &C, const char* nl,
Out << " : " << I.getData();
}
- Mgr.getConstraintManager().print(this, Out, nl, sep);
+ Mgr.getConstraintManager().print(this, Out, NL, Sep);
// Print checker-specific data.
- for (std::vector<Printer*>::iterator I = Mgr.Printers.begin(),
- E = Mgr.Printers.end(); I != E; ++I) {
- (*I)->Print(Out, this, nl, sep);
- }
+ Mgr.getOwningEngine()->printState(Out, this, NL, Sep);
}
-void GRState::printDOT(llvm::raw_ostream& Out, CFG &C) const {
+void ProgramState::printDOT(raw_ostream &Out, CFG &C) const {
print(Out, C, "\\l", "\\|");
}
-void GRState::printStdErr(CFG &C) const {
+void ProgramState::printStdErr(CFG &C) const {
print(llvm::errs(), C);
}
@@ -471,13 +471,13 @@ void GRState::printStdErr(CFG &C) const {
// Generic Data Map.
//===----------------------------------------------------------------------===//
-void* const* GRState::FindGDM(void* K) const {
+void *const* ProgramState::FindGDM(void *K) const {
return GDM.lookup(K);
}
void*
-GRStateManager::FindGDMContext(void* K,
- void* (*CreateContext)(llvm::BumpPtrAllocator&),
+ProgramStateManager::FindGDMContext(void *K,
+ void *(*CreateContext)(llvm::BumpPtrAllocator&),
void (*DeleteContext)(void*)) {
std::pair<void*, void (*)(void*)>& p = GDMContexts[K];
@@ -489,58 +489,30 @@ GRStateManager::FindGDMContext(void* K,
return p.first;
}
-const GRState* GRStateManager::addGDM(const GRState* St, void* Key, void* Data){
- GRState::GenericDataMap M1 = St->getGDM();
- GRState::GenericDataMap M2 = GDMFactory.add(M1, Key, Data);
+const ProgramState *ProgramStateManager::addGDM(const ProgramState *St, void *Key, void *Data){
+ ProgramState::GenericDataMap M1 = St->getGDM();
+ ProgramState::GenericDataMap M2 = GDMFactory.add(M1, Key, Data);
if (M1 == M2)
return St;
- GRState NewSt = *St;
+ ProgramState NewSt = *St;
NewSt.GDM = M2;
return getPersistentState(NewSt);
}
-const GRState *GRStateManager::removeGDM(const GRState *state, void *Key) {
- GRState::GenericDataMap OldM = state->getGDM();
- GRState::GenericDataMap NewM = GDMFactory.remove(OldM, Key);
+const ProgramState *ProgramStateManager::removeGDM(const ProgramState *state, void *Key) {
+ ProgramState::GenericDataMap OldM = state->getGDM();
+ ProgramState::GenericDataMap NewM = GDMFactory.remove(OldM, Key);
if (NewM == OldM)
return state;
- GRState NewState = *state;
+ ProgramState NewState = *state;
NewState.GDM = NewM;
return getPersistentState(NewState);
}
-//===----------------------------------------------------------------------===//
-// Utility.
-//===----------------------------------------------------------------------===//
-
-namespace {
-class ScanReachableSymbols : public SubRegionMap::Visitor {
- typedef llvm::DenseSet<const MemRegion*> VisitedRegionsTy;
-
- VisitedRegionsTy visited;
- const GRState *state;
- SymbolVisitor &visitor;
- llvm::OwningPtr<SubRegionMap> SRM;
-public:
-
- ScanReachableSymbols(const GRState *st, SymbolVisitor& v)
- : state(st), visitor(v) {}
-
- bool scan(nonloc::CompoundVal val);
- bool scan(SVal val);
- bool scan(const MemRegion *R);
-
- // From SubRegionMap::Visitor.
- bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) {
- return scan(SubRegion);
- }
-};
-}
-
bool ScanReachableSymbols::scan(nonloc::CompoundVal val) {
for (nonloc::CompoundVal::iterator I=val.begin(), E=val.end(); I!=E; ++I)
if (!scan(*I))
@@ -549,6 +521,33 @@ bool ScanReachableSymbols::scan(nonloc::CompoundVal val) {
return true;
}
+bool ScanReachableSymbols::scan(const SymExpr *sym) {
+ unsigned &isVisited = visited[sym];
+ if (isVisited)
+ return true;
+ isVisited = 1;
+
+ if (const SymbolData *sData = dyn_cast<SymbolData>(sym))
+ if (!visitor.VisitSymbol(sData))
+ return false;
+
+ switch (sym->getKind()) {
+ case SymExpr::RegionValueKind:
+ case SymExpr::ConjuredKind:
+ case SymExpr::DerivedKind:
+ case SymExpr::ExtentKind:
+ case SymExpr::MetadataKind:
+ break;
+ case SymExpr::SymIntKind:
+ return scan(cast<SymIntExpr>(sym)->getLHS());
+ case SymExpr::SymSymKind: {
+ const SymSymExpr *x = cast<SymSymExpr>(sym);
+ return scan(x->getLHS()) && scan(x->getRHS());
+ }
+ }
+ return true;
+}
+
bool ScanReachableSymbols::scan(SVal val) {
if (loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&val))
return scan(X->getRegion());
@@ -557,7 +556,10 @@ bool ScanReachableSymbols::scan(SVal val) {
return scan(X->getLoc());
if (SymbolRef Sym = val.getAsSymbol())
- return visitor.VisitSymbol(Sym);
+ return scan(Sym);
+
+ if (const SymExpr *Sym = val.getAsSymbolicExpression())
+ return scan(Sym);
if (nonloc::CompoundVal *X = dyn_cast<nonloc::CompoundVal>(&val))
return scan(*X);
@@ -566,10 +568,13 @@ bool ScanReachableSymbols::scan(SVal val) {
}
bool ScanReachableSymbols::scan(const MemRegion *R) {
- if (isa<MemSpaceRegion>(R) || visited.count(R))
+ if (isa<MemSpaceRegion>(R))
return true;
-
- visited.insert(R);
+
+ unsigned &isVisited = visited[R];
+ if (isVisited)
+ return true;
+ isVisited = 1;
// If this is a symbolic region, visit the symbol for the region.
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
@@ -593,12 +598,12 @@ bool ScanReachableSymbols::scan(const MemRegion *R) {
return SRM->iterSubRegions(R, *this);
}
-bool GRState::scanReachableSymbols(SVal val, SymbolVisitor& visitor) const {
+bool ProgramState::scanReachableSymbols(SVal val, SymbolVisitor& visitor) const {
ScanReachableSymbols S(this, visitor);
return S.scan(val);
}
-bool GRState::scanReachableSymbols(const SVal *I, const SVal *E,
+bool ProgramState::scanReachableSymbols(const SVal *I, const SVal *E,
SymbolVisitor &visitor) const {
ScanReachableSymbols S(this, visitor);
for ( ; I != E; ++I) {
@@ -608,7 +613,7 @@ bool GRState::scanReachableSymbols(const SVal *I, const SVal *E,
return true;
}
-bool GRState::scanReachableSymbols(const MemRegion * const *I,
+bool ProgramState::scanReachableSymbols(const MemRegion * const *I,
const MemRegion * const *E,
SymbolVisitor &visitor) const {
ScanReachableSymbols S(this, visitor);
diff --git a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 389fff5ed593..9337788535ab 100644
--- a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -8,14 +8,13 @@
//===----------------------------------------------------------------------===//
//
// This file defines RangeConstraintManager, a class that tracks simple
-// equality and inequality constraints on symbolic values of GRState.
+// equality and inequality constraints on symbolic values of ProgramState.
//
//===----------------------------------------------------------------------===//
#include "SimpleConstraintManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.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"
@@ -170,7 +169,7 @@ public:
return newRanges;
}
- void print(llvm::raw_ostream &os) const {
+ void print(raw_ostream &os) const {
bool isFirst = true;
os << "{ ";
for (iterator i = begin(), e = end(); i != e; ++i) {
@@ -196,55 +195,55 @@ typedef llvm::ImmutableMap<SymbolRef,RangeSet> ConstraintRangeTy;
namespace clang {
namespace ento {
template<>
-struct GRStateTrait<ConstraintRange>
- : public GRStatePartialTrait<ConstraintRangeTy> {
- static inline void* GDMIndex() { return &ConstraintRangeIndex; }
+struct ProgramStateTrait<ConstraintRange>
+ : public ProgramStatePartialTrait<ConstraintRangeTy> {
+ static inline void *GDMIndex() { return &ConstraintRangeIndex; }
};
}
}
namespace {
class RangeConstraintManager : public SimpleConstraintManager{
- RangeSet GetRange(const GRState *state, SymbolRef sym);
+ RangeSet GetRange(const ProgramState *state, SymbolRef sym);
public:
RangeConstraintManager(SubEngine &subengine)
: SimpleConstraintManager(subengine) {}
- const GRState *assumeSymNE(const GRState* state, SymbolRef sym,
+ const ProgramState *assumeSymNE(const ProgramState *state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment);
- const GRState *assumeSymEQ(const GRState* state, SymbolRef sym,
+ const ProgramState *assumeSymEQ(const ProgramState *state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment);
- const GRState *assumeSymLT(const GRState* state, SymbolRef sym,
+ const ProgramState *assumeSymLT(const ProgramState *state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment);
- const GRState *assumeSymGT(const GRState* state, SymbolRef sym,
+ const ProgramState *assumeSymGT(const ProgramState *state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment);
- const GRState *assumeSymGE(const GRState* state, SymbolRef sym,
+ const ProgramState *assumeSymGE(const ProgramState *state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment);
- const GRState *assumeSymLE(const GRState* state, SymbolRef sym,
+ const ProgramState *assumeSymLE(const ProgramState *state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment);
- const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) const;
+ const llvm::APSInt* getSymVal(const ProgramState *St, SymbolRef sym) const;
// FIXME: Refactor into SimpleConstraintManager?
- bool isEqual(const GRState* St, SymbolRef sym, const llvm::APSInt& V) const {
+ bool isEqual(const ProgramState *St, SymbolRef sym, const llvm::APSInt& V) const {
const llvm::APSInt *i = getSymVal(St, sym);
return i ? *i == V : false;
}
- const GRState* removeDeadBindings(const GRState* St, SymbolReaper& SymReaper);
+ const ProgramState *removeDeadBindings(const ProgramState *St, SymbolReaper& SymReaper);
- void print(const GRState* St, llvm::raw_ostream& Out,
+ void print(const ProgramState *St, raw_ostream &Out,
const char* nl, const char *sep);
private:
@@ -253,12 +252,12 @@ private:
} // end anonymous namespace
-ConstraintManager* ento::CreateRangeConstraintManager(GRStateManager&,
+ConstraintManager* ento::CreateRangeConstraintManager(ProgramStateManager&,
SubEngine &subeng) {
return new RangeConstraintManager(subeng);
}
-const llvm::APSInt* RangeConstraintManager::getSymVal(const GRState* St,
+const llvm::APSInt* RangeConstraintManager::getSymVal(const ProgramState *St,
SymbolRef sym) const {
const ConstraintRangeTy::data_type *T = St->get<ConstraintRange>(sym);
return T ? T->getConcreteValue() : NULL;
@@ -266,8 +265,8 @@ const llvm::APSInt* RangeConstraintManager::getSymVal(const GRState* St,
/// Scan all symbols referenced by the constraints. If the symbol is not alive
/// as marked in LSymbols, mark it as dead in DSymbols.
-const GRState*
-RangeConstraintManager::removeDeadBindings(const GRState* state,
+const ProgramState*
+RangeConstraintManager::removeDeadBindings(const ProgramState *state,
SymbolReaper& SymReaper) {
ConstraintRangeTy CR = state->get<ConstraintRange>();
@@ -283,7 +282,7 @@ RangeConstraintManager::removeDeadBindings(const GRState* state,
}
RangeSet
-RangeConstraintManager::GetRange(const GRState *state, SymbolRef sym) {
+RangeConstraintManager::GetRange(const ProgramState *state, SymbolRef sym) {
if (ConstraintRangeTy::data_type* V = state->get<ConstraintRange>(sym))
return *V;
@@ -306,8 +305,8 @@ RangeConstraintManager::GetRange(const GRState *state, SymbolRef sym) {
// As an example, the range [UINT_MAX-1, 3) contains five values: UINT_MAX-1,
// UINT_MAX, 0, 1, and 2.
-const GRState*
-RangeConstraintManager::assumeSymNE(const GRState* state, SymbolRef sym,
+const ProgramState*
+RangeConstraintManager::assumeSymNE(const ProgramState *state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment) {
BasicValueFactory &BV = state->getBasicVals();
@@ -323,8 +322,8 @@ RangeConstraintManager::assumeSymNE(const GRState* state, SymbolRef sym,
return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
}
-const GRState*
-RangeConstraintManager::assumeSymEQ(const GRState* state, SymbolRef sym,
+const ProgramState*
+RangeConstraintManager::assumeSymEQ(const ProgramState *state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment) {
// [Int-Adjustment, Int-Adjustment]
@@ -334,8 +333,8 @@ RangeConstraintManager::assumeSymEQ(const GRState* state, SymbolRef sym,
return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
}
-const GRState*
-RangeConstraintManager::assumeSymLT(const GRState* state, SymbolRef sym,
+const ProgramState*
+RangeConstraintManager::assumeSymLT(const ProgramState *state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment) {
BasicValueFactory &BV = state->getBasicVals();
@@ -355,8 +354,8 @@ RangeConstraintManager::assumeSymLT(const GRState* state, SymbolRef sym,
return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
}
-const GRState*
-RangeConstraintManager::assumeSymGT(const GRState* state, SymbolRef sym,
+const ProgramState*
+RangeConstraintManager::assumeSymGT(const ProgramState *state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment) {
BasicValueFactory &BV = state->getBasicVals();
@@ -376,8 +375,8 @@ RangeConstraintManager::assumeSymGT(const GRState* state, SymbolRef sym,
return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
}
-const GRState*
-RangeConstraintManager::assumeSymGE(const GRState* state, SymbolRef sym,
+const ProgramState*
+RangeConstraintManager::assumeSymGE(const ProgramState *state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment) {
BasicValueFactory &BV = state->getBasicVals();
@@ -398,8 +397,8 @@ RangeConstraintManager::assumeSymGE(const GRState* state, SymbolRef sym,
return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
}
-const GRState*
-RangeConstraintManager::assumeSymLE(const GRState* state, SymbolRef sym,
+const ProgramState*
+RangeConstraintManager::assumeSymLE(const ProgramState *state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment) {
BasicValueFactory &BV = state->getBasicVals();
@@ -424,7 +423,7 @@ RangeConstraintManager::assumeSymLE(const GRState* state, SymbolRef sym,
// Pretty-printing.
//===------------------------------------------------------------------------===/
-void RangeConstraintManager::print(const GRState* St, llvm::raw_ostream& Out,
+void RangeConstraintManager::print(const ProgramState *St, raw_ostream &Out,
const char* nl, const char *sep) {
ConstraintRangeTy Ranges = St->get<ConstraintRange>();
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index 23dd6416a8f1..4b76cf1a3deb 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -20,8 +20,8 @@
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.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"
@@ -94,7 +94,7 @@ BindingKey BindingKey::Make(const MemRegion *R, Kind k) {
namespace llvm {
static inline
- llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingKey K) {
+ raw_ostream &operator<<(raw_ostream &os, BindingKey K) {
os << '(' << K.getRegion() << ',' << K.getOffset()
<< ',' << (K.isDirect() ? "direct" : "default")
<< ')';
@@ -157,7 +157,7 @@ public:
return false;
}
- void process(llvm::SmallVectorImpl<const SubRegion*> &WL, const SubRegion *R);
+ void process(SmallVectorImpl<const SubRegion*> &WL, const SubRegion *R);
~RegionStoreSubRegionMap() {}
@@ -183,7 +183,7 @@ public:
};
void
-RegionStoreSubRegionMap::process(llvm::SmallVectorImpl<const SubRegion*> &WL,
+RegionStoreSubRegionMap::process(SmallVectorImpl<const SubRegion*> &WL,
const SubRegion *R) {
const MemRegion *superR = R->getSuperRegion();
if (add(superR, R))
@@ -196,7 +196,7 @@ class RegionStoreManager : public StoreManager {
RegionBindings::Factory RBFactory;
public:
- RegionStoreManager(GRStateManager& mgr, const RegionStoreFeatures &f)
+ RegionStoreManager(ProgramStateManager& mgr, const RegionStoreFeatures &f)
: StoreManager(mgr),
Features(f),
RBFactory(mgr.getAllocator()) {}
@@ -236,13 +236,11 @@ public:
// Binding values to regions.
//===-------------------------------------------------------------------===//
- StoreRef invalidateRegions(Store store,
- const MemRegion * const *Begin,
- const MemRegion * const *End,
+ StoreRef invalidateRegions(Store store, ArrayRef<const MemRegion *> Regions,
const Expr *E, unsigned Count,
InvalidatedSymbols &IS,
bool invalidateGlobals,
- InvalidatedRegions *Regions);
+ InvalidatedRegions *Invalidated);
public: // Made public for helper classes.
@@ -278,7 +276,7 @@ public: // Part of public interface to class.
return StoreRef(addBinding(B, R, BindingKey::Default, V).getRootWithoutRetain(), *this);
}
- StoreRef BindCompoundLiteral(Store store, const CompoundLiteralExpr* CL,
+ StoreRef BindCompoundLiteral(Store store, const CompoundLiteralExpr *CL,
const LocationContext *LC, SVal V);
StoreRef BindDecl(Store store, const VarRegion *VR, SVal InitVal);
@@ -288,9 +286,9 @@ public: // Part of public interface to class.
}
/// BindStruct - Bind a compound value to a structure.
- StoreRef BindStruct(Store store, const TypedRegion* R, SVal V);
+ StoreRef BindStruct(Store store, const TypedValueRegion* R, SVal V);
- StoreRef BindArray(Store store, const TypedRegion* R, SVal V);
+ StoreRef BindArray(Store store, const TypedValueRegion* R, SVal V);
/// KillStruct - Set the entire struct to unknown.
StoreRef KillStruct(Store store, const TypedRegion* R, SVal DefaultVal);
@@ -307,6 +305,8 @@ public: // Part of public interface to class.
void decrementReferenceCount(Store store) {
GetRegionBindings(store).manualRelease();
}
+
+ bool includedInBindings(Store store, const MemRegion *region) const;
//===------------------------------------------------------------------===//
// Loading values from regions.
@@ -333,9 +333,9 @@ public: // Part of public interface to class.
SVal RetrieveVar(Store store, const VarRegion *R);
- SVal RetrieveLazySymbol(const TypedRegion *R);
+ SVal RetrieveLazySymbol(const TypedValueRegion *R);
- SVal RetrieveFieldOrElementCommon(Store store, const TypedRegion *R,
+ SVal RetrieveFieldOrElementCommon(Store store, const TypedValueRegion *R,
QualType Ty, const MemRegion *superR);
SVal RetrieveLazyBinding(const MemRegion *lazyBindingRegion,
@@ -346,15 +346,16 @@ public: // Part of public interface to class.
/// struct s x, y;
/// x = y;
/// y's value is retrieved by this method.
- SVal RetrieveStruct(Store store, const TypedRegion* R);
+ SVal RetrieveStruct(Store store, const TypedValueRegion* R);
- SVal RetrieveArray(Store store, const TypedRegion* R);
+ SVal RetrieveArray(Store store, const TypedValueRegion* R);
/// Used to lazily generate derived symbols for bindings that are defined
/// implicitly by default bindings in a super region.
Optional<SVal> RetrieveDerivedDefaultValue(RegionBindings B,
const MemRegion *superR,
- const TypedRegion *R, QualType Ty);
+ const TypedValueRegion *R,
+ QualType Ty);
/// Get the state and region whose binding this region R corresponds to.
std::pair<Store, const MemRegion*>
@@ -371,17 +372,17 @@ public: // Part of public interface to class.
/// removeDeadBindings - Scans the RegionStore of 'state' for dead values.
/// It returns a new Store with these values removed.
StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx,
- SymbolReaper& SymReaper,
- llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
+ SymbolReaper& SymReaper);
- StoreRef enterStackFrame(const GRState *state, const StackFrameContext *frame);
+ StoreRef enterStackFrame(const ProgramState *state,
+ const StackFrameContext *frame);
//===------------------------------------------------------------------===//
// Region "extents".
//===------------------------------------------------------------------===//
// FIXME: This method will soon be eliminated; see the note in Store.h.
- DefinedOrUnknownSVal getSizeInElements(const GRState *state,
+ DefinedOrUnknownSVal getSizeInElements(const ProgramState *state,
const MemRegion* R, QualType EleTy);
//===------------------------------------------------------------------===//
@@ -392,7 +393,7 @@ public: // Part of public interface to class.
return RegionBindings(static_cast<const RegionBindings::TreeTy*>(store));
}
- void print(Store store, llvm::raw_ostream& Out, const char* nl,
+ void print(Store store, raw_ostream &Out, const char* nl,
const char *sep);
void iterBindings(Store store, BindingsHandler& f) {
@@ -416,12 +417,12 @@ public: // Part of public interface to class.
// RegionStore creation.
//===----------------------------------------------------------------------===//
-StoreManager *ento::CreateRegionStoreManager(GRStateManager& StMgr) {
+StoreManager *ento::CreateRegionStoreManager(ProgramStateManager& StMgr) {
RegionStoreFeatures F = maximal_features_tag();
return new RegionStoreManager(StMgr, F);
}
-StoreManager *ento::CreateFieldsOnlyRegionStoreManager(GRStateManager &StMgr) {
+StoreManager *ento::CreateFieldsOnlyRegionStoreManager(ProgramStateManager &StMgr) {
RegionStoreFeatures F = minimal_features_tag();
F.enableFields(true);
return new RegionStoreManager(StMgr, F);
@@ -433,7 +434,7 @@ RegionStoreManager::getRegionStoreSubRegionMap(Store store) {
RegionBindings B = GetRegionBindings(store);
RegionStoreSubRegionMap *M = new RegionStoreSubRegionMap();
- llvm::SmallVector<const SubRegion*, 10> WL;
+ SmallVector<const SubRegion*, 10> WL;
for (RegionBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I)
if (const SubRegion *R = dyn_cast<SubRegion>(I.getKey().getRegion()))
@@ -461,7 +462,7 @@ protected:
typedef BumpVector<BindingKey> RegionCluster;
typedef llvm::DenseMap<const MemRegion *, RegionCluster *> ClusterMap;
llvm::DenseMap<const RegionCluster*, unsigned> Visited;
- typedef llvm::SmallVector<std::pair<const MemRegion *, RegionCluster*>, 10>
+ typedef SmallVector<std::pair<const MemRegion *, RegionCluster*>, 10>
WorkList;
BumpVectorContext BVC;
@@ -477,7 +478,7 @@ protected:
const bool includeGlobals;
public:
- ClusterAnalysis(RegionStoreManager &rm, GRStateManager &StateMgr,
+ ClusterAnalysis(RegionStoreManager &rm, ProgramStateManager &StateMgr,
RegionBindings b, const bool includeGlobals)
: RM(rm), Ctx(StateMgr.getContext()),
svalBuilder(StateMgr.getSValBuilder()),
@@ -590,7 +591,7 @@ class invalidateRegionsWorker : public ClusterAnalysis<invalidateRegionsWorker>
StoreManager::InvalidatedRegions *Regions;
public:
invalidateRegionsWorker(RegionStoreManager &rm,
- GRStateManager &stateMgr,
+ ProgramStateManager &stateMgr,
RegionBindings b,
const Expr *ex, unsigned count,
StoreManager::InvalidatedSymbols &is,
@@ -681,7 +682,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
if (!baseR->isBoundable())
return;
- const TypedRegion *TR = cast<TypedRegion>(baseR);
+ const TypedValueRegion *TR = cast<TypedValueRegion>(baseR);
QualType T = TR->getValueType();
// Invalidate the binding.
@@ -718,21 +719,21 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
}
StoreRef RegionStoreManager::invalidateRegions(Store store,
- const MemRegion * const *I,
- const MemRegion * const *E,
+ ArrayRef<const MemRegion *> Regions,
const Expr *Ex, unsigned Count,
InvalidatedSymbols &IS,
bool invalidateGlobals,
- InvalidatedRegions *Regions) {
+ InvalidatedRegions *Invalidated) {
invalidateRegionsWorker W(*this, StateMgr,
RegionStoreManager::GetRegionBindings(store),
- Ex, Count, IS, Regions, invalidateGlobals);
+ Ex, Count, IS, Invalidated, invalidateGlobals);
// Scan the bindings and generate the clusters.
W.GenerateClusters();
- // Add I .. E to the worklist.
- for ( ; I != E; ++I)
+ // Add the regions to the worklist.
+ for (ArrayRef<const MemRegion *>::iterator
+ I = Regions.begin(), E = Regions.end(); I != E; ++I)
W.AddToWorkList(*I);
W.RunWorkList();
@@ -752,8 +753,8 @@ StoreRef RegionStoreManager::invalidateRegions(Store store,
// Even if there are no bindings in the global scope, we still need to
// record that we touched it.
- if (Regions)
- Regions->push_back(GS);
+ if (Invalidated)
+ Invalidated->push_back(GS);
}
return StoreRef(B.getRootWithoutRetain(), *this);
@@ -763,7 +764,7 @@ StoreRef RegionStoreManager::invalidateRegions(Store store,
// Extents for regions.
//===----------------------------------------------------------------------===//
-DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
+DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const ProgramState *state,
const MemRegion *R,
QualType EleTy) {
SVal Size = cast<SubRegion>(R)->getExtent(svalBuilder);
@@ -803,7 +804,7 @@ SVal RegionStoreManager::ArrayToPointer(Loc Array) {
return UnknownVal();
const MemRegion* R = cast<loc::MemRegionVal>(&Array)->getRegion();
- const TypedRegion* ArrayR = dyn_cast<TypedRegion>(R);
+ const TypedValueRegion* ArrayR = dyn_cast<TypedValueRegion>(R);
if (!ArrayR)
return UnknownVal();
@@ -852,7 +853,7 @@ Optional<SVal> RegionStoreManager::getDirectBinding(RegionBindings B,
Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
const MemRegion *R) {
if (R->isBoundable())
- if (const TypedRegion *TR = dyn_cast<TypedRegion>(R))
+ if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R))
if (TR->getValueType()->isUnionType())
return UnknownVal();
@@ -890,13 +891,12 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
}
if (isa<CodeTextRegion>(MR)) {
- assert(0 && "Why load from a code text region?");
- return UnknownVal();
+ llvm_unreachable("Why load from a code text region?");
}
// FIXME: Perhaps this method should just take a 'const MemRegion*' argument
// instead of 'Loc', and have the other Loc cases handled at a higher level.
- const TypedRegion *R = cast<TypedRegion>(MR);
+ const TypedValueRegion *R = cast<TypedValueRegion>(MR);
QualType RTy = R->getValueType();
// FIXME: We should eventually handle funny addressing. e.g.:
@@ -1042,6 +1042,10 @@ SVal RegionStoreManager::RetrieveElement(Store store,
SVal Idx = R->getIndex();
if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Idx)) {
int64_t i = CI->getValue().getSExtValue();
+ // Abort on string underrun. This can be possible by arbitrary
+ // clients of RetrieveElement().
+ if (i < 0)
+ return UndefinedVal();
int64_t byteLength = Str->getByteLength();
// Technically, only i == byteLength is guaranteed to be null.
// However, such overflows should be caught before reaching this point;
@@ -1068,7 +1072,8 @@ SVal RegionStoreManager::RetrieveElement(Store store,
if (!O.getRegion())
return UnknownVal();
- if (const TypedRegion *baseR = dyn_cast_or_null<TypedRegion>(O.getRegion())) {
+ if (const TypedValueRegion *baseR =
+ dyn_cast_or_null<TypedValueRegion>(O.getRegion())) {
QualType baseT = baseR->getValueType();
if (baseT->isScalarType()) {
QualType elemT = R->getElementType();
@@ -1106,7 +1111,7 @@ SVal RegionStoreManager::RetrieveField(Store store,
Optional<SVal>
RegionStoreManager::RetrieveDerivedDefaultValue(RegionBindings B,
const MemRegion *superR,
- const TypedRegion *R,
+ const TypedValueRegion *R,
QualType Ty) {
if (const Optional<SVal> &D = getDefaultBinding(B, superR)) {
@@ -1124,7 +1129,7 @@ RegionStoreManager::RetrieveDerivedDefaultValue(RegionBindings B,
if (isa<nonloc::LazyCompoundVal>(val))
return Optional<SVal>();
- assert(0 && "Unknown default value");
+ llvm_unreachable("Unknown default value");
}
return Optional<SVal>();
@@ -1140,7 +1145,7 @@ SVal RegionStoreManager::RetrieveLazyBinding(const MemRegion *lazyBindingRegion,
}
SVal RegionStoreManager::RetrieveFieldOrElementCommon(Store store,
- const TypedRegion *R,
+ const TypedValueRegion *R,
QualType Ty,
const MemRegion *superR) {
@@ -1175,7 +1180,8 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(Store store,
if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
// Currently we don't reason specially about Clang-style vectors. Check
// if superR is a vector and if so return Unknown.
- if (const TypedRegion *typedSuperR = dyn_cast<TypedRegion>(superR)) {
+ if (const TypedValueRegion *typedSuperR =
+ dyn_cast<TypedValueRegion>(superR)) {
if (typedSuperR->getValueType()->isVectorType())
return UnknownVal();
}
@@ -1264,22 +1270,41 @@ SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) {
return UndefinedVal();
}
-SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) {
+SVal RegionStoreManager::RetrieveLazySymbol(const TypedValueRegion *R) {
// All other values are symbolic.
return svalBuilder.getRegionValueSymbolVal(R);
}
-SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) {
+SVal RegionStoreManager::RetrieveStruct(Store store,
+ const TypedValueRegion* R) {
QualType T = R->getValueType();
assert(T->isStructureOrClassType());
return svalBuilder.makeLazyCompoundVal(StoreRef(store, *this), R);
}
-SVal RegionStoreManager::RetrieveArray(Store store, const TypedRegion * R) {
+SVal RegionStoreManager::RetrieveArray(Store store,
+ const TypedValueRegion * R) {
assert(Ctx.getAsConstantArrayType(R->getValueType()));
return svalBuilder.makeLazyCompoundVal(StoreRef(store, *this), R);
}
+bool RegionStoreManager::includedInBindings(Store store,
+ const MemRegion *region) const {
+ RegionBindings B = GetRegionBindings(store);
+ region = region->getBaseRegion();
+
+ for (RegionBindings::iterator it = B.begin(), ei = B.end(); it != ei; ++it) {
+ const BindingKey &K = it.getKey();
+ if (region == K.getRegion())
+ return true;
+ const SVal &D = it.getData();
+ if (const MemRegion *r = D.getAsRegion())
+ if (r == region)
+ return true;
+ }
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Binding values to regions.
//===----------------------------------------------------------------------===//
@@ -1302,14 +1327,14 @@ StoreRef RegionStoreManager::Bind(Store store, Loc L, SVal V) {
const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion();
// Check if the region is a struct region.
- if (const TypedRegion* TR = dyn_cast<TypedRegion>(R))
+ if (const TypedValueRegion* TR = dyn_cast<TypedValueRegion>(R))
if (TR->getValueType()->isStructureOrClassType())
return BindStruct(store, TR, V);
if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
if (ER->getIndex().isZeroConstant()) {
- if (const TypedRegion *superR =
- dyn_cast<TypedRegion>(ER->getSuperRegion())) {
+ if (const TypedValueRegion *superR =
+ dyn_cast<TypedValueRegion>(ER->getSuperRegion())) {
QualType superTy = superR->getValueType();
// For now, just invalidate the fields of the struct/union/class.
// This is for test rdar_test_7185607 in misc-ps-region-store.m.
@@ -1389,7 +1414,7 @@ StoreRef RegionStoreManager::setImplicitDefaultValue(Store store,
V).getRootWithoutRetain(), *this);
}
-StoreRef RegionStoreManager::BindArray(Store store, const TypedRegion* R,
+StoreRef RegionStoreManager::BindArray(Store store, const TypedValueRegion* R,
SVal Init) {
const ArrayType *AT =cast<ArrayType>(Ctx.getCanonicalType(R->getValueType()));
@@ -1448,7 +1473,7 @@ StoreRef RegionStoreManager::BindArray(Store store, const TypedRegion* R,
return newStore;
}
-StoreRef RegionStoreManager::BindStruct(Store store, const TypedRegion* R,
+StoreRef RegionStoreManager::BindStruct(Store store, const TypedValueRegion* R,
SVal V) {
if (!Features.supportsFields())
@@ -1458,9 +1483,9 @@ StoreRef RegionStoreManager::BindStruct(Store store, const TypedRegion* R,
assert(T->isStructureOrClassType());
const RecordType* RT = T->getAs<RecordType>();
- RecordDecl* RD = RT->getDecl();
+ RecordDecl *RD = RT->getDecl();
- if (!RD->isDefinition())
+ if (!RD->isCompleteDefinition())
return StoreRef(store, *this);
// Handle lazy compound values.
@@ -1611,12 +1636,12 @@ RegionBindings RegionStoreManager::removeBinding(RegionBindings B,
namespace {
class removeDeadBindingsWorker :
public ClusterAnalysis<removeDeadBindingsWorker> {
- llvm::SmallVector<const SymbolicRegion*, 12> Postponed;
+ SmallVector<const SymbolicRegion*, 12> Postponed;
SymbolReaper &SymReaper;
const StackFrameContext *CurrentLCtx;
public:
- removeDeadBindingsWorker(RegionStoreManager &rm, GRStateManager &stateMgr,
+ removeDeadBindingsWorker(RegionStoreManager &rm, ProgramStateManager &stateMgr,
RegionBindings b, SymbolReaper &symReaper,
const StackFrameContext *LCtx)
: ClusterAnalysis<removeDeadBindingsWorker>(rm, stateMgr, b,
@@ -1736,7 +1761,7 @@ bool removeDeadBindingsWorker::UpdatePostponed() {
// having done a scan.
bool changed = false;
- for (llvm::SmallVectorImpl<const SymbolicRegion*>::iterator
+ for (SmallVectorImpl<const SymbolicRegion*>::iterator
I = Postponed.begin(), E = Postponed.end() ; I != E ; ++I) {
if (const SymbolicRegion *SR = cast_or_null<SymbolicRegion>(*I)) {
if (SymReaper.isLive(SR->getSymbol())) {
@@ -1751,17 +1776,16 @@ bool removeDeadBindingsWorker::UpdatePostponed() {
StoreRef RegionStoreManager::removeDeadBindings(Store store,
const StackFrameContext *LCtx,
- SymbolReaper& SymReaper,
- llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
-{
+ SymbolReaper& SymReaper) {
RegionBindings B = GetRegionBindings(store);
removeDeadBindingsWorker W(*this, StateMgr, B, SymReaper, LCtx);
W.GenerateClusters();
// Enqueue the region roots onto the worklist.
- for (llvm::SmallVectorImpl<const MemRegion*>::iterator I=RegionRoots.begin(),
- E=RegionRoots.end(); I!=E; ++I)
+ for (SymbolReaper::region_iterator I = SymReaper.region_begin(),
+ E = SymReaper.region_end(); I != E; ++I) {
W.AddToWorkList(*I);
+ }
do W.RunWorkList(); while (W.UpdatePostponed());
@@ -1792,7 +1816,7 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store,
}
-StoreRef RegionStoreManager::enterStackFrame(const GRState *state,
+StoreRef RegionStoreManager::enterStackFrame(const ProgramState *state,
const StackFrameContext *frame) {
FunctionDecl const *FD = cast<FunctionDecl>(frame->getDecl());
FunctionDecl::param_const_iterator PI = FD->param_begin(),
@@ -1831,7 +1855,7 @@ StoreRef RegionStoreManager::enterStackFrame(const GRState *state,
// Utility methods.
//===----------------------------------------------------------------------===//
-void RegionStoreManager::print(Store store, llvm::raw_ostream& OS,
+void RegionStoreManager::print(Store store, raw_ostream &OS,
const char* nl, const char *sep) {
RegionBindings B = GetRegionBindings(store);
OS << "Store (direct and default bindings):" << nl;
diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 71f2b4abb9c3..ebf7ae2fd4b1 100644
--- a/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -15,7 +15,7 @@
#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/GRState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
using namespace clang;
@@ -70,7 +70,7 @@ SVal SValBuilder::convertToArrayIndex(SVal val) {
}
DefinedOrUnknownSVal
-SValBuilder::getRegionValueSymbolVal(const TypedRegion* region) {
+SValBuilder::getRegionValueSymbolVal(const TypedValueRegion* region) {
QualType T = region->getValueType();
if (!SymbolManager::canSymbolicate(T))
@@ -133,7 +133,7 @@ DefinedSVal SValBuilder::getMetadataSymbolVal(const void *symbolTag,
DefinedOrUnknownSVal
SValBuilder::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol,
- const TypedRegion *region) {
+ const TypedValueRegion *region) {
QualType T = region->getValueType();
if (!SymbolManager::canSymbolicate(T))
@@ -147,7 +147,7 @@ SValBuilder::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol,
return nonloc::SymbolVal(sym);
}
-DefinedSVal SValBuilder::getFunctionPointer(const FunctionDecl* func) {
+DefinedSVal SValBuilder::getFunctionPointer(const FunctionDecl *func) {
return loc::MemRegionVal(MemMgr.getFunctionTextRegion(func));
}
@@ -162,7 +162,7 @@ DefinedSVal SValBuilder::getBlockPointer(const BlockDecl *block,
//===----------------------------------------------------------------------===//
-SVal SValBuilder::evalBinOp(const GRState *state, BinaryOperator::Opcode op,
+SVal SValBuilder::evalBinOp(const ProgramState *state, BinaryOperator::Opcode op,
SVal lhs, SVal rhs, QualType type) {
if (lhs.isUndef() || rhs.isUndef())
@@ -190,7 +190,7 @@ SVal SValBuilder::evalBinOp(const GRState *state, BinaryOperator::Opcode op,
return evalBinOpNN(state, op, cast<NonLoc>(lhs), cast<NonLoc>(rhs), type);
}
-DefinedOrUnknownSVal SValBuilder::evalEQ(const GRState *state,
+DefinedOrUnknownSVal SValBuilder::evalEQ(const ProgramState *state,
DefinedOrUnknownSVal lhs,
DefinedOrUnknownSVal rhs) {
return cast<DefinedOrUnknownSVal>(evalBinOp(state, BO_EQ, lhs, rhs,
@@ -213,8 +213,13 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
return UnknownVal();
// Check for casts from integers to integers.
- if (castTy->isIntegerType() && originalTy->isIntegerType())
- return evalCastFromNonLoc(cast<NonLoc>(val), castTy);
+ if (castTy->isIntegerType() && originalTy->isIntegerType()) {
+ if (isa<Loc>(val))
+ // This can be a cast to ObjC property of type int.
+ return evalCastFromLoc(cast<Loc>(val), castTy);
+ else
+ return evalCastFromNonLoc(cast<NonLoc>(val), castTy);
+ }
// Check for casts from pointers to integers.
if (castTy->isIntegerType() && Loc::isLocType(originalTy))
diff --git a/lib/StaticAnalyzer/Core/SVals.cpp b/lib/StaticAnalyzer/Core/SVals.cpp
index 4614e349dece..b5980b96938a 100644
--- a/lib/StaticAnalyzer/Core/SVals.cpp
+++ b/lib/StaticAnalyzer/Core/SVals.cpp
@@ -12,14 +12,11 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Basic/IdentifierTable.h"
-
using namespace clang;
using namespace ento;
-using llvm::dyn_cast;
-using llvm::cast;
using llvm::APSInt;
//===----------------------------------------------------------------------===//
@@ -146,7 +143,7 @@ SVal::symbol_iterator::symbol_iterator(const SymExpr *SE) {
while (!isa<SymbolData>(itr.back())) expand();
}
-SVal::symbol_iterator& SVal::symbol_iterator::operator++() {
+SVal::symbol_iterator &SVal::symbol_iterator::operator++() {
assert(!itr.empty() && "attempting to iterate on an 'end' iterator");
assert(isa<SymbolData>(itr.back()));
itr.pop_back();
@@ -174,7 +171,7 @@ void SVal::symbol_iterator::expand() {
return;
}
- assert(false && "unhandled expansion case");
+ llvm_unreachable("unhandled expansion case");
}
const void *nonloc::LazyCompoundVal::getStore() const {
@@ -270,7 +267,7 @@ SVal loc::ConcreteInt::evalBinOp(BasicValueFactory& BasicVals,
void SVal::dump() const { dumpToStream(llvm::errs()); }
-void SVal::dumpToStream(llvm::raw_ostream& os) const {
+void SVal::dumpToStream(raw_ostream &os) const {
switch (getBaseKind()) {
case UnknownKind:
os << "Unknown";
@@ -289,7 +286,7 @@ void SVal::dumpToStream(llvm::raw_ostream& os) const {
}
}
-void NonLoc::dumpToStream(llvm::raw_ostream& os) const {
+void NonLoc::dumpToStream(raw_ostream &os) const {
switch (getSubKind()) {
case nonloc::ConcreteIntKind: {
const nonloc::ConcreteInt& C = *cast<nonloc::ConcreteInt>(this);
@@ -344,7 +341,7 @@ void NonLoc::dumpToStream(llvm::raw_ostream& os) const {
}
}
-void Loc::dumpToStream(llvm::raw_ostream& os) const {
+void Loc::dumpToStream(raw_ostream &os) const {
switch (getSubKind()) {
case loc::ConcreteIntKind:
os << cast<loc::ConcreteInt>(this)->getValue().getZExtValue() << " (Loc)";
@@ -372,7 +369,6 @@ void Loc::dumpToStream(llvm::raw_ostream& os) const {
break;
}
default:
- assert(false && "Pretty-printing not implemented for this Loc.");
- break;
+ llvm_unreachable("Pretty-printing not implemented for this Loc.");
}
}
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
index 20762e07dd22..79d8b8bf9de3 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
@@ -14,7 +14,7 @@
#include "SimpleConstraintManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
namespace clang {
@@ -56,7 +56,7 @@ bool SimpleConstraintManager::canReasonAbout(SVal X) const {
return true;
}
-const GRState *SimpleConstraintManager::assume(const GRState *state,
+const ProgramState *SimpleConstraintManager::assume(const ProgramState *state,
DefinedSVal Cond,
bool Assumption) {
if (isa<NonLoc>(Cond))
@@ -65,13 +65,13 @@ const GRState *SimpleConstraintManager::assume(const GRState *state,
return assume(state, cast<Loc>(Cond), Assumption);
}
-const GRState *SimpleConstraintManager::assume(const GRState *state, Loc cond,
+const ProgramState *SimpleConstraintManager::assume(const ProgramState *state, Loc cond,
bool assumption) {
state = assumeAux(state, cond, assumption);
return SU.processAssume(state, cond, assumption);
}
-const GRState *SimpleConstraintManager::assumeAux(const GRState *state,
+const ProgramState *SimpleConstraintManager::assumeAux(const ProgramState *state,
Loc Cond, bool Assumption) {
BasicValueFactory &BasicVals = state->getBasicVals();
@@ -113,7 +113,7 @@ const GRState *SimpleConstraintManager::assumeAux(const GRState *state,
} // end switch
}
-const GRState *SimpleConstraintManager::assume(const GRState *state,
+const ProgramState *SimpleConstraintManager::assume(const ProgramState *state,
NonLoc cond,
bool assumption) {
state = assumeAux(state, cond, assumption);
@@ -125,7 +125,7 @@ static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) {
// the only place it's used. (This code was copied from SimpleSValBuilder.cpp.)
switch (op) {
default:
- assert(false && "Invalid opcode.");
+ llvm_unreachable("Invalid opcode.");
case BO_LT: return BO_GE;
case BO_GT: return BO_LE;
case BO_LE: return BO_GT;
@@ -135,7 +135,7 @@ static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) {
}
}
-const GRState *SimpleConstraintManager::assumeAux(const GRState *state,
+const ProgramState *SimpleConstraintManager::assumeAux(const ProgramState *state,
NonLoc Cond,
bool Assumption) {
@@ -152,7 +152,7 @@ const GRState *SimpleConstraintManager::assumeAux(const GRState *state,
switch (Cond.getSubKind()) {
default:
- assert(false && "'Assume' not implemented for this NonLoc");
+ llvm_unreachable("'Assume' not implemented for this NonLoc");
case nonloc::SymbolValKind: {
nonloc::SymbolVal& SV = cast<nonloc::SymbolVal>(Cond);
@@ -202,7 +202,7 @@ const GRState *SimpleConstraintManager::assumeAux(const GRState *state,
} // end switch
}
-const GRState *SimpleConstraintManager::assumeSymRel(const GRState *state,
+const ProgramState *SimpleConstraintManager::assumeSymRel(const ProgramState *state,
const SymExpr *LHS,
BinaryOperator::Opcode op,
const llvm::APSInt& Int) {
@@ -256,7 +256,7 @@ const GRState *SimpleConstraintManager::assumeSymRel(const GRState *state,
// be of the same type as the symbol, which is not always correct. Really the
// comparisons should be performed using the Int's type, then mapped back to
// the symbol's range of values.
- GRStateManager &StateMgr = state->getStateManager();
+ ProgramStateManager &StateMgr = state->getStateManager();
ASTContext &Ctx = StateMgr.getContext();
QualType T = Sym->getType(Ctx);
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
index a2952afa7351..d4295d42d95e 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
@@ -15,7 +15,7 @@
#define LLVM_CLANG_GR_SIMPLE_CONSTRAINT_MANAGER_H
#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
namespace clang {
@@ -33,14 +33,14 @@ public:
bool canReasonAbout(SVal X) const;
- const GRState *assume(const GRState *state, DefinedSVal Cond,
+ const ProgramState *assume(const ProgramState *state, DefinedSVal Cond,
bool Assumption);
- const GRState *assume(const GRState *state, Loc Cond, bool Assumption);
+ const ProgramState *assume(const ProgramState *state, Loc Cond, bool Assumption);
- const GRState *assume(const GRState *state, NonLoc Cond, bool Assumption);
+ const ProgramState *assume(const ProgramState *state, NonLoc Cond, bool Assumption);
- const GRState *assumeSymRel(const GRState *state,
+ const ProgramState *assumeSymRel(const ProgramState *state,
const SymExpr *LHS,
BinaryOperator::Opcode op,
const llvm::APSInt& Int);
@@ -53,27 +53,27 @@ protected:
// Each of these is of the form "$sym+Adj <> V", where "<>" is the comparison
// operation for the method being invoked.
- virtual const GRState *assumeSymNE(const GRState *state, SymbolRef sym,
+ virtual const ProgramState *assumeSymNE(const ProgramState *state, SymbolRef sym,
const llvm::APSInt& V,
const llvm::APSInt& Adjustment) = 0;
- virtual const GRState *assumeSymEQ(const GRState *state, SymbolRef sym,
+ virtual const ProgramState *assumeSymEQ(const ProgramState *state, SymbolRef sym,
const llvm::APSInt& V,
const llvm::APSInt& Adjustment) = 0;
- virtual const GRState *assumeSymLT(const GRState *state, SymbolRef sym,
+ virtual const ProgramState *assumeSymLT(const ProgramState *state, SymbolRef sym,
const llvm::APSInt& V,
const llvm::APSInt& Adjustment) = 0;
- virtual const GRState *assumeSymGT(const GRState *state, SymbolRef sym,
+ virtual const ProgramState *assumeSymGT(const ProgramState *state, SymbolRef sym,
const llvm::APSInt& V,
const llvm::APSInt& Adjustment) = 0;
- virtual const GRState *assumeSymLE(const GRState *state, SymbolRef sym,
+ virtual const ProgramState *assumeSymLE(const ProgramState *state, SymbolRef sym,
const llvm::APSInt& V,
const llvm::APSInt& Adjustment) = 0;
- virtual const GRState *assumeSymGE(const GRState *state, SymbolRef sym,
+ virtual const ProgramState *assumeSymGE(const ProgramState *state, SymbolRef sym,
const llvm::APSInt& V,
const llvm::APSInt& Adjustment) = 0;
@@ -81,9 +81,9 @@ protected:
// Internal implementation.
//===------------------------------------------------------------------===//
- const GRState *assumeAux(const GRState *state, Loc Cond,bool Assumption);
+ const ProgramState *assumeAux(const ProgramState *state, Loc Cond,bool Assumption);
- const GRState *assumeAux(const GRState *state, NonLoc Cond, bool Assumption);
+ const ProgramState *assumeAux(const ProgramState *state, NonLoc Cond, bool Assumption);
};
} // end GR namespace
diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index 80c18a335fde..bd63ecf775d3 100644
--- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
using namespace clang;
using namespace ento;
@@ -25,22 +25,22 @@ protected:
public:
SimpleSValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
- GRStateManager &stateMgr)
+ ProgramStateManager &stateMgr)
: SValBuilder(alloc, context, stateMgr) {}
virtual ~SimpleSValBuilder() {}
virtual SVal evalMinus(NonLoc val);
virtual SVal evalComplement(NonLoc val);
- virtual SVal evalBinOpNN(const GRState *state, BinaryOperator::Opcode op,
+ virtual SVal evalBinOpNN(const ProgramState *state, BinaryOperator::Opcode op,
NonLoc lhs, NonLoc rhs, QualType resultTy);
- virtual SVal evalBinOpLL(const GRState *state, BinaryOperator::Opcode op,
+ virtual SVal evalBinOpLL(const ProgramState *state, BinaryOperator::Opcode op,
Loc lhs, Loc rhs, QualType resultTy);
- virtual SVal evalBinOpLN(const GRState *state, BinaryOperator::Opcode op,
+ virtual SVal evalBinOpLN(const ProgramState *state, BinaryOperator::Opcode op,
Loc lhs, NonLoc rhs, QualType resultTy);
/// getKnownValue - evaluates a given SVal. If the SVal has only one possible
/// (integer) value, that value is returned. Otherwise, returns NULL.
- virtual const llvm::APSInt *getKnownValue(const GRState *state, SVal V);
+ virtual const llvm::APSInt *getKnownValue(const ProgramState *state, SVal V);
SVal MakeSymIntVal(const SymExpr *LHS, BinaryOperator::Opcode op,
const llvm::APSInt &RHS, QualType resultTy);
@@ -49,7 +49,7 @@ public:
SValBuilder *ento::createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
ASTContext &context,
- GRStateManager &stateMgr) {
+ ProgramStateManager &stateMgr) {
return new SimpleSValBuilder(alloc, context, stateMgr);
}
@@ -171,7 +171,7 @@ SVal SimpleSValBuilder::evalComplement(NonLoc X) {
static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) {
switch (op) {
default:
- assert(false && "Invalid opcode.");
+ llvm_unreachable("Invalid opcode.");
case BO_LT: return BO_GE;
case BO_GT: return BO_LE;
case BO_LE: return BO_GT;
@@ -184,7 +184,7 @@ static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) {
static BinaryOperator::Opcode ReverseComparison(BinaryOperator::Opcode op) {
switch (op) {
default:
- assert(false && "Invalid opcode.");
+ llvm_unreachable("Invalid opcode.");
case BO_LT: return BO_GT;
case BO_GT: return BO_LT;
case BO_LE: return BO_GE;
@@ -270,7 +270,7 @@ SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS,
return makeNonLoc(LHS, op, RHS, resultTy);
}
-SVal SimpleSValBuilder::evalBinOpNN(const GRState *state,
+SVal SimpleSValBuilder::evalBinOpNN(const ProgramState *state,
BinaryOperator::Opcode op,
NonLoc lhs, NonLoc rhs,
QualType resultTy) {
@@ -347,8 +347,7 @@ SVal SimpleSValBuilder::evalBinOpNN(const GRState *state,
break;
case BO_LAnd:
case BO_LOr:
- assert(false && "Logical operators handled by branching logic.");
- return UnknownVal();
+ llvm_unreachable("Logical operators handled by branching logic.");
case BO_Assign:
case BO_MulAssign:
case BO_DivAssign:
@@ -361,12 +360,10 @@ SVal SimpleSValBuilder::evalBinOpNN(const GRState *state,
case BO_XorAssign:
case BO_OrAssign:
case BO_Comma:
- assert(false && "'=' and ',' operators handled by ExprEngine.");
- return UnknownVal();
+ llvm_unreachable("'=' and ',' operators handled by ExprEngine.");
case BO_PtrMemD:
case BO_PtrMemI:
- assert(false && "Pointer arithmetic not handled here.");
- return UnknownVal();
+ llvm_unreachable("Pointer arithmetic not handled here.");
case BO_LT:
case BO_GT:
case BO_LE:
@@ -539,7 +536,7 @@ SVal SimpleSValBuilder::evalBinOpNN(const GRState *state,
}
// FIXME: all this logic will change if/when we have MemRegion::getLocation().
-SVal SimpleSValBuilder::evalBinOpLL(const GRState *state,
+SVal SimpleSValBuilder::evalBinOpLL(const ProgramState *state,
BinaryOperator::Opcode op,
Loc lhs, Loc rhs,
QualType resultTy) {
@@ -556,8 +553,7 @@ SVal SimpleSValBuilder::evalBinOpLL(const GRState *state,
if (lhs == rhs) {
switch (op) {
default:
- assert(false && "Unimplemented operation for two identical values");
- return UnknownVal();
+ llvm_unreachable("Unimplemented operation for two identical values");
case BO_Sub:
return makeZeroVal(resultTy);
case BO_EQ:
@@ -573,8 +569,7 @@ SVal SimpleSValBuilder::evalBinOpLL(const GRState *state,
switch (lhs.getSubKind()) {
default:
- assert(false && "Ordering not implemented for this Loc.");
- return UnknownVal();
+ llvm_unreachable("Ordering not implemented for this Loc.");
case loc::GotoLabelKind:
// The only thing we know about labels is that they're non-null.
@@ -827,7 +822,7 @@ SVal SimpleSValBuilder::evalBinOpLL(const GRState *state,
return makeTruthVal(!leftFirst, resultTy);
}
- assert(false && "Fields not found in parent record's definition");
+ llvm_unreachable("Fields not found in parent record's definition");
}
// If we get here, we have no way of comparing the regions.
@@ -836,7 +831,7 @@ SVal SimpleSValBuilder::evalBinOpLL(const GRState *state,
}
}
-SVal SimpleSValBuilder::evalBinOpLN(const GRState *state,
+SVal SimpleSValBuilder::evalBinOpLN(const ProgramState *state,
BinaryOperator::Opcode op,
Loc lhs, NonLoc rhs, QualType resultTy) {
@@ -930,7 +925,7 @@ SVal SimpleSValBuilder::evalBinOpLN(const GRState *state,
return UnknownVal();
}
-const llvm::APSInt *SimpleSValBuilder::getKnownValue(const GRState *state,
+const llvm::APSInt *SimpleSValBuilder::getKnownValue(const ProgramState *state,
SVal V) {
if (V.isUnknownOrUndef())
return NULL;
diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp
index b936738009ec..48a6f4f60f8a 100644
--- a/lib/StaticAnalyzer/Core/Store.cpp
+++ b/lib/StaticAnalyzer/Core/Store.cpp
@@ -12,17 +12,17 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/AST/CharUnits.h"
using namespace clang;
using namespace ento;
-StoreManager::StoreManager(GRStateManager &stateMgr)
+StoreManager::StoreManager(ProgramStateManager &stateMgr)
: svalBuilder(stateMgr.getSValBuilder()), StateMgr(stateMgr),
MRMgr(svalBuilder.getRegionManager()), Ctx(stateMgr.getContext()) {}
-StoreRef StoreManager::enterStackFrame(const GRState *state,
+StoreRef StoreManager::enterStackFrame(const ProgramState *state,
const StackFrameContext *frame) {
return StoreRef(state->getStore(), *this);
}
@@ -57,7 +57,7 @@ const ElementRegion *StoreManager::GetElementZeroRegion(const MemRegion *R,
const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy) {
- ASTContext& Ctx = StateMgr.getContext();
+ ASTContext &Ctx = StateMgr.getContext();
// Handle casts to Objective-C objects.
if (CastToTy->isObjCObjectPointerType())
@@ -87,7 +87,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
// Handle casts from compatible types.
if (R->isBoundable())
- if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
+ if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) {
QualType ObjTy = Ctx.getCanonicalType(TR->getValueType());
if (CanonPointeeTy == ObjTy)
return R;
@@ -103,8 +103,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
case MemRegion::UnknownSpaceRegionKind:
case MemRegion::NonStaticGlobalSpaceRegionKind:
case MemRegion::StaticGlobalSpaceRegionKind: {
- assert(0 && "Invalid region cast");
- break;
+ llvm_unreachable("Invalid region cast");
}
case MemRegion::FunctionTextRegionKind:
@@ -157,7 +156,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
// Edge case: we are at 0 bytes off the beginning of baseR. We
// check to see if type we are casting to is the same as the base
// region. If so, just return the base region.
- if (const TypedRegion *TR = dyn_cast<TypedRegion>(baseR)) {
+ if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(baseR)) {
QualType ObjTy = Ctx.getCanonicalType(TR->getValueType());
QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy);
if (CanonPointeeTy == ObjTy)
@@ -203,15 +202,14 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
}
}
- assert(0 && "unreachable");
- return 0;
+ llvm_unreachable("unreachable");
}
/// CastRetrievedVal - Used by subclasses of StoreManager to implement
/// implicit casts that arise from loads from regions that are reinterpreted
/// as another region.
-SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
+SVal StoreManager::CastRetrievedVal(SVal V, const TypedValueRegion *R,
QualType castTy, bool performTestOnly) {
if (castTy.isNull())
@@ -237,7 +235,7 @@ SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
return V;
}
-SVal StoreManager::getLValueFieldOrIvar(const Decl* D, SVal Base) {
+SVal StoreManager::getLValueFieldOrIvar(const Decl *D, SVal Base) {
if (Base.isUnknownOrUndef())
return Base;
@@ -261,8 +259,7 @@ SVal StoreManager::getLValueFieldOrIvar(const Decl* D, SVal Base) {
return Base;
default:
- assert(0 && "Unhandled Base.");
- return Base;
+ llvm_unreachable("Unhandled Base.");
}
// NOTE: We must have this check first because ObjCIvarDecl is a subclass
@@ -336,3 +333,6 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
return loc::MemRegionVal(MRMgr.getElementRegion(elementType, NewIdx, ArrayR,
Ctx));
}
+
+StoreManager::BindingsHandler::~BindingsHandler() {}
+
diff --git a/lib/StaticAnalyzer/Core/SymbolManager.cpp b/lib/StaticAnalyzer/Core/SymbolManager.cpp
index c1ca1cfcdc07..b843ab1a903b 100644
--- a/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -15,6 +15,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -24,11 +25,10 @@ void SymExpr::dump() const {
dumpToStream(llvm::errs());
}
-static void print(llvm::raw_ostream& os, BinaryOperator::Opcode Op) {
+static void print(raw_ostream &os, BinaryOperator::Opcode Op) {
switch (Op) {
default:
- assert(false && "operator printing not implemented");
- break;
+ llvm_unreachable("operator printing not implemented");
case BO_Mul: os << '*' ; break;
case BO_Div: os << '/' ; break;
case BO_Rem: os << '%' ; break;
@@ -48,7 +48,7 @@ static void print(llvm::raw_ostream& os, BinaryOperator::Opcode Op) {
}
}
-void SymIntExpr::dumpToStream(llvm::raw_ostream& os) const {
+void SymIntExpr::dumpToStream(raw_ostream &os) const {
os << '(';
getLHS()->dumpToStream(os);
os << ") ";
@@ -57,7 +57,7 @@ void SymIntExpr::dumpToStream(llvm::raw_ostream& os) const {
if (getRHS().isUnsigned()) os << 'U';
}
-void SymSymExpr::dumpToStream(llvm::raw_ostream& os) const {
+void SymSymExpr::dumpToStream(raw_ostream &os) const {
os << '(';
getLHS()->dumpToStream(os);
os << ") ";
@@ -66,33 +66,33 @@ void SymSymExpr::dumpToStream(llvm::raw_ostream& os) const {
os << ')';
}
-void SymbolConjured::dumpToStream(llvm::raw_ostream& os) const {
+void SymbolConjured::dumpToStream(raw_ostream &os) const {
os << "conj_$" << getSymbolID() << '{' << T.getAsString() << '}';
}
-void SymbolDerived::dumpToStream(llvm::raw_ostream& os) const {
+void SymbolDerived::dumpToStream(raw_ostream &os) const {
os << "derived_$" << getSymbolID() << '{'
<< getParentSymbol() << ',' << getRegion() << '}';
}
-void SymbolExtent::dumpToStream(llvm::raw_ostream& os) const {
+void SymbolExtent::dumpToStream(raw_ostream &os) const {
os << "extent_$" << getSymbolID() << '{' << getRegion() << '}';
}
-void SymbolMetadata::dumpToStream(llvm::raw_ostream& os) const {
+void SymbolMetadata::dumpToStream(raw_ostream &os) const {
os << "meta_$" << getSymbolID() << '{'
<< getRegion() << ',' << T.getAsString() << '}';
}
-void SymbolRegionValue::dumpToStream(llvm::raw_ostream& os) const {
+void SymbolRegionValue::dumpToStream(raw_ostream &os) const {
os << "reg_$" << getSymbolID() << "<" << R << ">";
}
const SymbolRegionValue*
-SymbolManager::getRegionValueSymbol(const TypedRegion* R) {
+SymbolManager::getRegionValueSymbol(const TypedValueRegion* R) {
llvm::FoldingSetNodeID profile;
SymbolRegionValue::Profile(profile, R);
- void* InsertPos;
+ void *InsertPos;
SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
if (!SD) {
SD = (SymExpr*) BPAlloc.Allocate<SymbolRegionValue>();
@@ -105,12 +105,12 @@ SymbolManager::getRegionValueSymbol(const TypedRegion* R) {
}
const SymbolConjured*
-SymbolManager::getConjuredSymbol(const Stmt* E, QualType T, unsigned Count,
- const void* SymbolTag) {
+SymbolManager::getConjuredSymbol(const Stmt *E, QualType T, unsigned Count,
+ const void *SymbolTag) {
llvm::FoldingSetNodeID profile;
SymbolConjured::Profile(profile, E, T, Count, SymbolTag);
- void* InsertPos;
+ void *InsertPos;
SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
if (!SD) {
SD = (SymExpr*) BPAlloc.Allocate<SymbolConjured>();
@@ -124,11 +124,11 @@ SymbolManager::getConjuredSymbol(const Stmt* E, QualType T, unsigned Count,
const SymbolDerived*
SymbolManager::getDerivedSymbol(SymbolRef parentSymbol,
- const TypedRegion *R) {
+ const TypedValueRegion *R) {
llvm::FoldingSetNodeID profile;
SymbolDerived::Profile(profile, parentSymbol, R);
- void* InsertPos;
+ void *InsertPos;
SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
if (!SD) {
SD = (SymExpr*) BPAlloc.Allocate<SymbolDerived>();
@@ -144,7 +144,7 @@ const SymbolExtent*
SymbolManager::getExtentSymbol(const SubRegion *R) {
llvm::FoldingSetNodeID profile;
SymbolExtent::Profile(profile, R);
- void* InsertPos;
+ void *InsertPos;
SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
if (!SD) {
SD = (SymExpr*) BPAlloc.Allocate<SymbolExtent>();
@@ -157,12 +157,12 @@ SymbolManager::getExtentSymbol(const SubRegion *R) {
}
const SymbolMetadata*
-SymbolManager::getMetadataSymbol(const MemRegion* R, const Stmt* S, QualType T,
- unsigned Count, const void* SymbolTag) {
+SymbolManager::getMetadataSymbol(const MemRegion* R, const Stmt *S, QualType T,
+ unsigned Count, const void *SymbolTag) {
llvm::FoldingSetNodeID profile;
SymbolMetadata::Profile(profile, R, S, T, Count, SymbolTag);
- void* InsertPos;
+ void *InsertPos;
SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
if (!SD) {
SD = (SymExpr*) BPAlloc.Allocate<SymbolMetadata>();
@@ -214,11 +214,11 @@ QualType SymbolConjured::getType(ASTContext&) const {
return T;
}
-QualType SymbolDerived::getType(ASTContext& Ctx) const {
+QualType SymbolDerived::getType(ASTContext &Ctx) const {
return R->getValueType();
}
-QualType SymbolExtent::getType(ASTContext& Ctx) const {
+QualType SymbolExtent::getType(ASTContext &Ctx) const {
return Ctx.getSizeType();
}
@@ -226,11 +226,17 @@ QualType SymbolMetadata::getType(ASTContext&) const {
return T;
}
-QualType SymbolRegionValue::getType(ASTContext& C) const {
+QualType SymbolRegionValue::getType(ASTContext &C) const {
return R->getValueType();
}
-SymbolManager::~SymbolManager() {}
+SymbolManager::~SymbolManager() {
+ for (SymbolDependTy::const_iterator I = SymbolDependencies.begin(),
+ E = SymbolDependencies.end(); I != E; ++I) {
+ delete I->second;
+ }
+
+}
bool SymbolManager::canSymbolicate(QualType T) {
T = T.getCanonicalType();
@@ -247,9 +253,53 @@ bool SymbolManager::canSymbolicate(QualType T) {
return false;
}
+void SymbolManager::addSymbolDependency(const SymbolRef Primary,
+ const SymbolRef Dependent) {
+ SymbolDependTy::iterator I = SymbolDependencies.find(Primary);
+ SymbolRefSmallVectorTy *dependencies = 0;
+ if (I == SymbolDependencies.end()) {
+ dependencies = new SymbolRefSmallVectorTy();
+ SymbolDependencies[Primary] = dependencies;
+ } else {
+ dependencies = I->second;
+ }
+ dependencies->push_back(Dependent);
+}
+
+const SymbolRefSmallVectorTy *SymbolManager::getDependentSymbols(
+ const SymbolRef Primary) {
+ SymbolDependTy::const_iterator I = SymbolDependencies.find(Primary);
+ if (I == SymbolDependencies.end())
+ return 0;
+ return I->second;
+}
+
+void SymbolReaper::markDependentsLive(SymbolRef sym) {
+ // Do not mark dependents more then once.
+ SymbolMapTy::iterator LI = TheLiving.find(sym);
+ assert(LI != TheLiving.end() && "The primary symbol is not live.");
+ if (LI->second == HaveMarkedDependents)
+ return;
+ LI->second = HaveMarkedDependents;
+
+ if (const SymbolRefSmallVectorTy *Deps = SymMgr.getDependentSymbols(sym)) {
+ for (SymbolRefSmallVectorTy::const_iterator I = Deps->begin(),
+ E = Deps->end(); I != E; ++I) {
+ if (TheLiving.find(*I) != TheLiving.end())
+ continue;
+ markLive(*I);
+ }
+ }
+}
+
void SymbolReaper::markLive(SymbolRef sym) {
- TheLiving.insert(sym);
+ TheLiving[sym] = NotProcessed;
TheDead.erase(sym);
+ markDependentsLive(sym);
+}
+
+void SymbolReaper::markLive(const MemRegion *region) {
+ RegionRoots.insert(region);
}
void SymbolReaper::markInUse(SymbolRef sym) {
@@ -265,14 +315,17 @@ bool SymbolReaper::maybeDead(SymbolRef sym) {
return true;
}
-static bool IsLiveRegion(SymbolReaper &Reaper, const MemRegion *MR) {
+bool SymbolReaper::isLiveRegion(const MemRegion *MR) {
+ if (RegionRoots.count(MR))
+ return true;
+
MR = MR->getBaseRegion();
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
- return Reaper.isLive(SR->getSymbol());
+ return isLive(SR->getSymbol());
if (const VarRegion *VR = dyn_cast<VarRegion>(MR))
- return Reaper.isLive(VR);
+ return isLive(VR, true);
// FIXME: This is a gross over-approximation. What we really need is a way to
// tell if anything still refers to this region. Unlike SymbolicRegions,
@@ -291,8 +344,10 @@ static bool IsLiveRegion(SymbolReaper &Reaper, const MemRegion *MR) {
}
bool SymbolReaper::isLive(SymbolRef sym) {
- if (TheLiving.count(sym))
+ if (TheLiving.count(sym)) {
+ markDependentsLive(sym);
return true;
+ }
if (const SymbolDerived *derived = dyn_cast<SymbolDerived>(sym)) {
if (isLive(derived->getParentSymbol())) {
@@ -303,7 +358,7 @@ bool SymbolReaper::isLive(SymbolRef sym) {
}
if (const SymbolExtent *extent = dyn_cast<SymbolExtent>(sym)) {
- if (IsLiveRegion(*this, extent->getRegion())) {
+ if (isLiveRegion(extent->getRegion())) {
markLive(sym);
return true;
}
@@ -312,7 +367,7 @@ bool SymbolReaper::isLive(SymbolRef sym) {
if (const SymbolMetadata *metadata = dyn_cast<SymbolMetadata>(sym)) {
if (MetadataInUse.count(sym)) {
- if (IsLiveRegion(*this, metadata->getRegion())) {
+ if (isLiveRegion(metadata->getRegion())) {
markLive(sym);
MetadataInUse.erase(sym);
return true;
@@ -326,18 +381,38 @@ bool SymbolReaper::isLive(SymbolRef sym) {
return isa<SymbolRegionValue>(sym);
}
-bool SymbolReaper::isLive(const Stmt* ExprVal) const {
- return LCtx->getAnalysisContext()->getRelaxedLiveVariables()->
- isLive(Loc, ExprVal);
+bool SymbolReaper::isLive(const Stmt *ExprVal) const {
+ return LCtx->getAnalysis<RelaxedLiveVariables>()->isLive(Loc, ExprVal);
}
-bool SymbolReaper::isLive(const VarRegion *VR) const {
+bool SymbolReaper::isLive(const VarRegion *VR, bool includeStoreBindings) const{
const StackFrameContext *VarContext = VR->getStackFrame();
const StackFrameContext *CurrentContext = LCtx->getCurrentStackFrame();
- if (VarContext == CurrentContext)
- return LCtx->getAnalysisContext()->getRelaxedLiveVariables()->
- isLive(Loc, VR->getDecl());
+ if (VarContext == CurrentContext) {
+ if (LCtx->getAnalysis<RelaxedLiveVariables>()->isLive(Loc, VR->getDecl()))
+ return true;
+
+ if (!includeStoreBindings)
+ return false;
+
+ unsigned &cachedQuery =
+ const_cast<SymbolReaper*>(this)->includedRegionCache[VR];
+
+ if (cachedQuery) {
+ return cachedQuery == 1;
+ }
+
+ // Query the store to see if the region occurs in any live bindings.
+ if (Store store = reapedStore.getStore()) {
+ bool hasRegion =
+ reapedStore.getStoreManager().includedInBindings(store, VR);
+ cachedQuery = hasRegion ? 1 : 2;
+ return hasRegion;
+ }
+
+ return false;
+ }
return VarContext->isParentOf(CurrentContext);
}
diff --git a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
index 230b6a1087dc..3543f7ff13dc 100644
--- a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Core/PathDiagnosticClients.h"
+#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/raw_ostream.h"
@@ -23,19 +23,19 @@ namespace {
/// \brief Simple path diagnostic client used for outputting as diagnostic notes
/// the sequence of events.
-class TextPathDiagnostics : public PathDiagnosticClient {
+class TextPathDiagnostics : public PathDiagnosticConsumer {
const std::string OutputFile;
- Diagnostic &Diag;
+ DiagnosticsEngine &Diag;
public:
- TextPathDiagnostics(const std::string& output, Diagnostic &diag)
+ TextPathDiagnostics(const std::string& output, DiagnosticsEngine &diag)
: OutputFile(output), Diag(diag) {}
- void HandlePathDiagnostic(const PathDiagnostic* D);
+ void HandlePathDiagnosticImpl(const PathDiagnostic* D);
- void FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade) { }
+ void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade) { }
- virtual llvm::StringRef getName() const {
+ virtual StringRef getName() const {
return "TextPathDiagnostics";
}
@@ -47,13 +47,13 @@ public:
} // end anonymous namespace
-PathDiagnosticClient*
-ento::createTextPathDiagnosticClient(const std::string& out,
+PathDiagnosticConsumer*
+ento::createTextPathDiagnosticConsumer(const std::string& out,
const Preprocessor &PP) {
return new TextPathDiagnostics(out, PP.getDiagnostics());
}
-void TextPathDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
+void TextPathDiagnostics::HandlePathDiagnosticImpl(const PathDiagnostic* D) {
if (!D)
return;
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index b8dbb545041e..34a358ff200b 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -25,8 +25,7 @@
#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/PathSensitive/TransferFuncs.h"
-#include "clang/StaticAnalyzer/Core/PathDiagnosticClients.h"
+#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
@@ -43,15 +42,15 @@ using namespace ento;
static ExplodedNode::Auditor* CreateUbiViz();
//===----------------------------------------------------------------------===//
-// Special PathDiagnosticClients.
+// Special PathDiagnosticConsumers.
//===----------------------------------------------------------------------===//
-static PathDiagnosticClient*
-createPlistHTMLDiagnosticClient(const std::string& prefix,
+static PathDiagnosticConsumer*
+createPlistHTMLDiagnosticConsumer(const std::string& prefix,
const Preprocessor &PP) {
- PathDiagnosticClient *PD =
- createHTMLDiagnosticClient(llvm::sys::path::parent_path(prefix), PP);
- return createPlistDiagnosticClient(prefix, PP, PD);
+ PathDiagnosticConsumer *PD =
+ createHTMLDiagnosticConsumer(llvm::sys::path::parent_path(prefix), PP);
+ return createPlistDiagnosticConsumer(prefix, PP, PD);
}
//===----------------------------------------------------------------------===//
@@ -62,13 +61,14 @@ namespace {
class AnalysisConsumer : public ASTConsumer {
public:
- ASTContext* Ctx;
+ ASTContext *Ctx;
const Preprocessor &PP;
const std::string OutDir;
AnalyzerOptions Opts;
+ ArrayRef<std::string> Plugins;
// PD is owned by AnalysisManager.
- PathDiagnosticClient *PD;
+ PathDiagnosticConsumer *PD;
StoreManagerCreator CreateStoreMgr;
ConstraintManagerCreator CreateConstraintMgr;
@@ -78,14 +78,14 @@ public:
AnalysisConsumer(const Preprocessor& pp,
const std::string& outdir,
- const AnalyzerOptions& opts)
- : Ctx(0), PP(pp), OutDir(outdir),
- Opts(opts), PD(0) {
+ const AnalyzerOptions& opts,
+ ArrayRef<std::string> plugins)
+ : Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins), PD(0) {
DigestAnalyzerOptions();
}
void DigestAnalyzerOptions() {
- // Create the PathDiagnosticClient.
+ // Create the PathDiagnosticConsumer.
if (!OutDir.empty()) {
switch (Opts.AnalysisDiagOpt) {
default:
@@ -96,13 +96,13 @@ public:
} else if (Opts.AnalysisDiagOpt == PD_TEXT) {
// Create the text client even without a specified output file since
// it just uses diagnostic notes.
- PD = createTextPathDiagnosticClient("", PP);
+ PD = createTextPathDiagnosticConsumer("", PP);
}
// Create the analyzer component creators.
switch (Opts.AnalysisStoreOpt) {
default:
- assert(0 && "Unknown store manager.");
+ llvm_unreachable("Unknown store manager.");
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \
case NAME##Model: CreateStoreMgr = CREATEFN; break;
#include "clang/Frontend/Analyses.def"
@@ -110,7 +110,7 @@ public:
switch (Opts.AnalysisConstraintsOpt) {
default:
- assert(0 && "Unknown store manager.");
+ llvm_unreachable("Unknown store manager.");
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
case NAME##Model: CreateConstraintMgr = CREATEFN; break;
#include "clang/Frontend/Analyses.def"
@@ -128,7 +128,7 @@ public:
if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
const NamedDecl *ND = cast<NamedDecl>(D);
- llvm::errs() << ' ' << ND << '\n';
+ llvm::errs() << ' ' << *ND << '\n';
}
else if (isa<BlockDecl>(D)) {
llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:"
@@ -143,8 +143,8 @@ public:
virtual void Initialize(ASTContext &Context) {
Ctx = &Context;
- checkerMgr.reset(registerCheckers(Opts, PP.getLangOptions(),
- PP.getDiagnostics()));
+ checkerMgr.reset(createCheckerManager(Opts, PP.getLangOptions(), Plugins,
+ PP.getDiagnostics()));
Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
PP.getLangOptions(), PD,
CreateStoreMgr, CreateConstraintMgr,
@@ -152,7 +152,7 @@ public:
/* Indexer */ 0,
Opts.MaxNodes, Opts.MaxLoop,
Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
- Opts.PurgeDead, Opts.EagerlyAssume,
+ Opts.AnalysisPurgeOpt, Opts.EagerlyAssume,
Opts.TrimGraph, Opts.InlineCall,
Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors,
Opts.CFGAddInitializers,
@@ -161,6 +161,7 @@ public:
virtual void HandleTranslationUnit(ASTContext &C);
void HandleDeclContext(ASTContext &C, DeclContext *dc);
+ void HandleDeclContextDecl(ASTContext &C, Decl *D);
void HandleCode(Decl *D);
};
@@ -171,61 +172,67 @@ public:
//===----------------------------------------------------------------------===//
void AnalysisConsumer::HandleDeclContext(ASTContext &C, DeclContext *dc) {
- BugReporter BR(*Mgr);
for (DeclContext::decl_iterator I = dc->decls_begin(), E = dc->decls_end();
I != E; ++I) {
- Decl *D = *I;
+ HandleDeclContextDecl(C, *I);
+ }
+}
+
+void AnalysisConsumer::HandleDeclContextDecl(ASTContext &C, Decl *D) {
+ { // Handle callbacks for arbitrary decls.
+ BugReporter BR(*Mgr);
checkerMgr->runCheckersOnASTDecl(D, *Mgr, BR);
+ }
- switch (D->getKind()) {
- case Decl::Namespace: {
- HandleDeclContext(C, cast<NamespaceDecl>(D));
- break;
+ switch (D->getKind()) {
+ case Decl::Namespace: {
+ HandleDeclContext(C, cast<NamespaceDecl>(D));
+ break;
+ }
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ case Decl::CXXMethod:
+ case Decl::Function: {
+ FunctionDecl *FD = cast<FunctionDecl>(D);
+ // We skip function template definitions, as their semantics is
+ // only determined when they are instantiated.
+ if (FD->isThisDeclarationADefinition() &&
+ !FD->isDependentContext()) {
+ if (!Opts.AnalyzeSpecificFunction.empty() &&
+ FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction)
+ break;
+ DisplayFunction(FD);
+ HandleCode(FD);
}
- case Decl::CXXConstructor:
- case Decl::CXXDestructor:
- case Decl::CXXConversion:
- case Decl::CXXMethod:
- case Decl::Function: {
- FunctionDecl* FD = cast<FunctionDecl>(D);
- // We skip function template definitions, as their semantics is
- // only determined when they are instantiated.
- if (FD->isThisDeclarationADefinition() &&
- !FD->isDependentContext()) {
+ break;
+ }
+
+ case Decl::ObjCCategoryImpl:
+ case Decl::ObjCImplementation: {
+ ObjCImplDecl *ID = cast<ObjCImplDecl>(D);
+ HandleCode(ID);
+
+ for (ObjCContainerDecl::method_iterator MI = ID->meth_begin(),
+ ME = ID->meth_end(); MI != ME; ++MI) {
+ BugReporter BR(*Mgr);
+ checkerMgr->runCheckersOnASTDecl(*MI, *Mgr, BR);
+
+ if ((*MI)->isThisDeclarationADefinition()) {
if (!Opts.AnalyzeSpecificFunction.empty() &&
- FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction)
- break;
- DisplayFunction(FD);
- HandleCode(FD);
+ Opts.AnalyzeSpecificFunction !=
+ (*MI)->getSelector().getAsString())
+ continue;
+ DisplayFunction(*MI);
+ HandleCode(*MI);
}
- break;
}
-
- case Decl::ObjCCategoryImpl:
- case Decl::ObjCImplementation: {
- ObjCImplDecl* ID = cast<ObjCImplDecl>(*I);
- HandleCode(ID);
-
- for (ObjCContainerDecl::method_iterator MI = ID->meth_begin(),
- ME = ID->meth_end(); MI != ME; ++MI) {
- checkerMgr->runCheckersOnASTDecl(*MI, *Mgr, BR);
-
- if ((*MI)->isThisDeclarationADefinition()) {
- if (!Opts.AnalyzeSpecificFunction.empty() &&
- Opts.AnalyzeSpecificFunction !=
- (*MI)->getSelector().getAsString())
- break;
- DisplayFunction(*MI);
- HandleCode(*MI);
- }
- }
- break;
- }
-
- default:
- break;
+ break;
}
- }
+
+ default:
+ break;
+ }
}
void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
@@ -237,14 +244,14 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
// After all decls handled, run checkers on the entire TranslationUnit.
checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
- // Explicitly destroy the PathDiagnosticClient. This will flush its output.
+ // Explicitly destroy the PathDiagnosticConsumer. This will flush its output.
// FIXME: This should be replaced with something that doesn't rely on
- // side-effects in PathDiagnosticClient's destructor. This is required when
+ // side-effects in PathDiagnosticConsumer's destructor. This is required when
// used with option -disable-free.
Mgr.reset(NULL);
}
-static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) {
+static void FindBlocks(DeclContext *D, SmallVectorImpl<Decl*> &WL) {
if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
WL.push_back(BD);
@@ -254,20 +261,20 @@ static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) {
FindBlocks(DC, WL);
}
-static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr,
- Decl *D);
+static void RunPathSensitiveChecks(AnalysisConsumer &C, AnalysisManager &mgr,
+ Decl *D);
void AnalysisConsumer::HandleCode(Decl *D) {
// Don't run the actions if an error has occurred with parsing the file.
- Diagnostic &Diags = PP.getDiagnostics();
+ DiagnosticsEngine &Diags = PP.getDiagnostics();
if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
return;
// Don't run the actions on declarations in header files unless
// otherwise specified.
SourceManager &SM = Ctx->getSourceManager();
- SourceLocation SL = SM.getInstantiationLoc(D->getLocation());
+ SourceLocation SL = SM.getExpansionLoc(D->getLocation());
if (!Opts.AnalyzeAll && !SM.isFromMainFile(SL))
return;
@@ -275,19 +282,19 @@ void AnalysisConsumer::HandleCode(Decl *D) {
Mgr->ClearContexts();
// Dispatch on the actions.
- llvm::SmallVector<Decl*, 10> WL;
+ SmallVector<Decl*, 10> WL;
WL.push_back(D);
if (D->hasBody() && Opts.AnalyzeNestedBlocks)
FindBlocks(cast<DeclContext>(D), WL);
BugReporter BR(*Mgr);
- for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
+ for (SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
WI != WE; ++WI)
if ((*WI)->hasBody()) {
checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR);
if (checkerMgr->hasPathSensitiveCheckers())
- ActionObjCMemChecker(*this, *Mgr, *WI);
+ RunPathSensitiveChecks(*this, *Mgr, *WI);
}
}
@@ -295,18 +302,13 @@ void AnalysisConsumer::HandleCode(Decl *D) {
// Path-sensitive checking.
//===----------------------------------------------------------------------===//
-static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
- Decl *D,
- TransferFuncs* tf) {
-
- llvm::OwningPtr<TransferFuncs> TF(tf);
-
- // Construct the analysis engine. We first query for the LiveVariables
- // information to see if the CFG is valid.
+static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager &mgr,
+ Decl *D, bool ObjCGCEnabled) {
+ // Construct the analysis engine. First check if the CFG is valid.
// FIXME: Inter-procedural analysis will need to handle invalid CFGs.
- if (!mgr.getLiveVariables(D))
+ if (!mgr.getCFG(D))
return;
- ExprEngine Eng(mgr, TF.take());
+ ExprEngine Eng(mgr, ObjCGCEnabled);
// Set the graph auditor.
llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
@@ -330,35 +332,25 @@ static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
Eng.getBugReporter().FlushReports();
}
-static void ActionObjCMemCheckerAux(AnalysisConsumer &C, AnalysisManager& mgr,
- Decl *D, bool GCEnabled) {
-
- TransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(),
- GCEnabled,
- mgr.getLangOptions());
-
- ActionExprEngine(C, mgr, D, TF);
-}
-
-static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr,
- Decl *D) {
-
- switch (mgr.getLangOptions().getGCMode()) {
- default:
- assert (false && "Invalid GC mode.");
- case LangOptions::NonGC:
- ActionObjCMemCheckerAux(C, mgr, D, false);
- break;
-
- case LangOptions::GCOnly:
- ActionObjCMemCheckerAux(C, mgr, D, true);
- break;
-
- case LangOptions::HybridGC:
- ActionObjCMemCheckerAux(C, mgr, D, false);
- ActionObjCMemCheckerAux(C, mgr, D, true);
- break;
- }
+static void RunPathSensitiveChecks(AnalysisConsumer &C, AnalysisManager &mgr,
+ Decl *D) {
+
+ switch (mgr.getLangOptions().getGC()) {
+ default:
+ llvm_unreachable("Invalid GC mode.");
+ case LangOptions::NonGC:
+ ActionExprEngine(C, mgr, D, false);
+ break;
+
+ case LangOptions::GCOnly:
+ ActionExprEngine(C, mgr, D, true);
+ break;
+
+ case LangOptions::HybridGC:
+ ActionExprEngine(C, mgr, D, false);
+ ActionExprEngine(C, mgr, D, true);
+ break;
+ }
}
//===----------------------------------------------------------------------===//
@@ -366,14 +358,13 @@ static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr,
//===----------------------------------------------------------------------===//
ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
- const std::string& OutDir,
- const AnalyzerOptions& Opts) {
- llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(pp, OutDir, Opts));
-
- // Last, disable the effects of '-Werror' when using the AnalysisConsumer.
+ const std::string& outDir,
+ const AnalyzerOptions& opts,
+ ArrayRef<std::string> plugins) {
+ // Disable the effects of '-Werror' when using the AnalysisConsumer.
pp.getDiagnostics().setWarningsAsErrors(false);
- return C.take();
+ return new AnalysisConsumer(pp, outDir, opts, plugins);
}
//===----------------------------------------------------------------------===//
@@ -383,7 +374,7 @@ ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
namespace {
class UbigraphViz : public ExplodedNode::Auditor {
- llvm::OwningPtr<llvm::raw_ostream> Out;
+ llvm::OwningPtr<raw_ostream> Out;
llvm::sys::Path Dir, Filename;
unsigned Cntr;
@@ -391,12 +382,12 @@ class UbigraphViz : public ExplodedNode::Auditor {
VMap M;
public:
- UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir,
+ UbigraphViz(raw_ostream *out, llvm::sys::Path& dir,
llvm::sys::Path& filename);
~UbigraphViz();
- virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst);
+ virtual void AddEdge(ExplodedNode *Src, ExplodedNode *Dst);
};
} // end anonymous namespace
@@ -426,7 +417,7 @@ static ExplodedNode::Auditor* CreateUbiViz() {
return new UbigraphViz(Stream.take(), Dir, Filename);
}
-void UbigraphViz::AddEdge(ExplodedNode* Src, ExplodedNode* Dst) {
+void UbigraphViz::AddEdge(ExplodedNode *Src, ExplodedNode *Dst) {
assert (Src != Dst && "Self-edges are not allowed.");
@@ -460,7 +451,7 @@ void UbigraphViz::AddEdge(ExplodedNode* Src, ExplodedNode* Dst) {
<< ", ('arrow','true'), ('oriented', 'true'))\n";
}
-UbigraphViz::UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir,
+UbigraphViz::UbigraphViz(raw_ostream *out, llvm::sys::Path& dir,
llvm::sys::Path& filename)
: Out(out), Dir(dir), Filename(filename), Cntr(0) {
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h
index 646fe97564b8..5a16bffeacf3 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h
@@ -15,6 +15,7 @@
#ifndef LLVM_CLANG_GR_ANALYSISCONSUMER_H
#define LLVM_CLANG_GR_ANALYSISCONSUMER_H
+#include "clang/Basic/LLVM.h"
#include <string>
namespace clang {
@@ -22,7 +23,7 @@ namespace clang {
class AnalyzerOptions;
class ASTConsumer;
class Preprocessor;
-class Diagnostic;
+class DiagnosticsEngine;
namespace ento {
class CheckerManager;
@@ -32,7 +33,8 @@ class CheckerManager;
/// options.)
ASTConsumer* CreateAnalysisConsumer(const Preprocessor &pp,
const std::string &output,
- const AnalyzerOptions& Opts);
+ const AnalyzerOptions& opts,
+ ArrayRef<std::string> plugins);
} // end GR namespace
diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
index d7edc7e599df..a59fcad6f819 100644
--- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
+++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
@@ -13,53 +13,121 @@
#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
-#include "../Checkers/ClangSACheckerProvider.h"
+#include "clang/StaticAnalyzer/Checkers/ClangCheckers.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/CheckerProvider.h"
+#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
+#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
#include "clang/Frontend/AnalyzerOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Basic/Diagnostic.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;
+using llvm::sys::DynamicLibrary;
-CheckerManager *ento::registerCheckers(const AnalyzerOptions &opts,
- const LangOptions &langOpts,
- Diagnostic &diags) {
+namespace {
+class ClangCheckerRegistry : public CheckerRegistry {
+ typedef void (*RegisterCheckersFn)(CheckerRegistry &);
+
+ static bool isCompatibleAPIVersion(const char *versionString);
+ static void warnIncompatible(DiagnosticsEngine *diags, StringRef pluginPath,
+ const char *pluginAPIVersion);
+
+public:
+ ClangCheckerRegistry(ArrayRef<std::string> plugins,
+ DiagnosticsEngine *diags = 0);
+};
+
+} // end anonymous namespace
+
+ClangCheckerRegistry::ClangCheckerRegistry(ArrayRef<std::string> plugins,
+ DiagnosticsEngine *diags) {
+ registerBuiltinCheckers(*this);
+
+ for (ArrayRef<std::string>::iterator i = plugins.begin(), e = plugins.end();
+ i != e; ++i) {
+ // Get access to the plugin.
+ DynamicLibrary lib = DynamicLibrary::getPermanentLibrary(i->c_str());
+
+ // See if it's compatible with this build of clang.
+ const char *pluginAPIVersion =
+ (const char *) lib.getAddressOfSymbol("clang_analyzerAPIVersionString");
+ if (!isCompatibleAPIVersion(pluginAPIVersion)) {
+ warnIncompatible(diags, *i, pluginAPIVersion);
+ continue;
+ }
+
+ // Register its checkers.
+ RegisterCheckersFn registerPluginCheckers =
+ (RegisterCheckersFn) (intptr_t) lib.getAddressOfSymbol(
+ "clang_registerCheckers");
+ if (registerPluginCheckers)
+ registerPluginCheckers(*this);
+ }
+}
+
+bool ClangCheckerRegistry::isCompatibleAPIVersion(const char *versionString) {
+ // If the version string is null, it's not an analyzer plugin.
+ if (versionString == 0)
+ return false;
+
+ // For now, none of the static analyzer API is considered stable.
+ // Versions must match exactly.
+ if (strcmp(versionString, CLANG_ANALYZER_API_VERSION_STRING) == 0)
+ return true;
+
+ return false;
+}
+
+void ClangCheckerRegistry::warnIncompatible(DiagnosticsEngine *diags,
+ StringRef pluginPath,
+ const char *pluginAPIVersion) {
+ if (!diags)
+ return;
+ if (!pluginAPIVersion)
+ return;
+
+ diags->Report(diag::warn_incompatible_analyzer_plugin_api)
+ << llvm::sys::path::filename(pluginPath);
+ diags->Report(diag::note_incompatible_analyzer_plugin_api)
+ << CLANG_ANALYZER_API_VERSION_STRING
+ << pluginAPIVersion;
+}
+
+
+CheckerManager *ento::createCheckerManager(const AnalyzerOptions &opts,
+ const LangOptions &langOpts,
+ ArrayRef<std::string> plugins,
+ DiagnosticsEngine &diags) {
llvm::OwningPtr<CheckerManager> checkerMgr(new CheckerManager(langOpts));
- llvm::SmallVector<CheckerOptInfo, 8> checkerOpts;
+ SmallVector<CheckerOptInfo, 8> checkerOpts;
for (unsigned i = 0, e = opts.CheckersControlList.size(); i != e; ++i) {
const std::pair<std::string, bool> &opt = opts.CheckersControlList[i];
checkerOpts.push_back(CheckerOptInfo(opt.first.c_str(), opt.second));
}
- llvm::OwningPtr<CheckerProvider> provider(createClangSACheckerProvider());
- provider->registerCheckers(*checkerMgr,
- checkerOpts.data(), checkerOpts.size());
-
- // FIXME: Load CheckerProviders from plugins.
-
+ ClangCheckerRegistry allCheckers(plugins, &diags);
+ allCheckers.initializeManager(*checkerMgr, checkerOpts);
checkerMgr->finishedCheckerRegistration();
for (unsigned i = 0, e = checkerOpts.size(); i != e; ++i) {
if (checkerOpts[i].isUnclaimed())
- diags.Report(diag::warn_unkwown_analyzer_checker)
+ diags.Report(diag::warn_unknown_analyzer_checker)
<< checkerOpts[i].getName();
}
return checkerMgr.take();
}
-void ento::printCheckerHelp(llvm::raw_ostream &OS) {
- OS << "OVERVIEW: Clang Static Analyzer Checkers List\n";
- OS << '\n';
-
- llvm::OwningPtr<CheckerProvider> provider(createClangSACheckerProvider());
- provider->printHelp(OS);
+void ento::printCheckerHelp(raw_ostream &out, ArrayRef<std::string> plugins) {
+ out << "OVERVIEW: Clang Static Analyzer Checkers List\n\n";
+ out << "USAGE: -analyzer-checker <CHECKER or PACKAGE,...>\n\n";
- // FIXME: Load CheckerProviders from plugins.
+ ClangCheckerRegistry(plugins).printHelp(out);
}
diff --git a/lib/StaticAnalyzer/Frontend/FrontendActions.cpp b/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
index a59cc6888fdb..85a18ec98ead 100644
--- a/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
+++ b/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
@@ -14,9 +14,10 @@ using namespace clang;
using namespace ento;
ASTConsumer *AnalysisAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
+ StringRef InFile) {
return CreateAnalysisConsumer(CI.getPreprocessor(),
CI.getFrontendOpts().OutputFile,
- CI.getAnalyzerOpts());
+ CI.getAnalyzerOpts(),
+ CI.getFrontendOpts().Plugins);
}
diff --git a/lib/StaticAnalyzer/README.txt b/lib/StaticAnalyzer/README.txt
index 1406eca8c85f..d4310c57d849 100644
--- a/lib/StaticAnalyzer/README.txt
+++ b/lib/StaticAnalyzer/README.txt
@@ -20,7 +20,7 @@ The analyzer is inspired by several foundational research papers ([1],
In a nutshell, the analyzer is basically a source code simulator that
traces out possible paths of execution. The state of the program
(values of variables and expressions) is encapsulated by the state
-(GRState). A location in the program is called a program point
+(ProgramState). A location in the program is called a program point
(ProgramPoint), and the combination of state and program point is a
node in an exploded graph (ExplodedGraph). The term "exploded" comes
from exploding the control-flow edges in the control-flow graph (CFG).
@@ -39,7 +39,7 @@ then bifurcating the state: on the true branch the conditions of the
branch are assumed to be true and on the false branch the conditions
of the branch are assumed to be false. Such "assumptions" create
constraints on the values of the program, and those constraints are
-recorded in the GRState object (and are manipulated by the
+recorded in the ProgramState object (and are manipulated by the
ConstraintManager). If assuming the conditions of a branch would
cause the constraints to be unsatisfiable, the branch is considered
infeasible and that path is not taken. This is how we get
@@ -49,9 +49,9 @@ would get generated, the path "caches out" and we simply reuse the
existing node. Thus the ExplodedGraph is not a DAG; it can contain
cycles as paths loop back onto each other and cache out.
-GRState and ExplodedNodes are basically immutable once created. Once
-one creates a GRState, you need to create a new one to get a new
-GRState. This immutability is key since the ExplodedGraph represents
+ProgramState and ExplodedNodes are basically immutable once created. Once
+one creates a ProgramState, you need to create a new one to get a new
+ProgramState. This immutability is key since the ExplodedGraph represents
the behavior of the analyzed program from the entry point. To
represent these efficiently, we use functional data structures (e.g.,
ImmutableMaps) which share data between instances.
@@ -62,7 +62,7 @@ For example, the PreVisitCallExpr() method is called by GRExprEngine
to tell the Checker that we are about to analyze a CallExpr, and the
checker is asked to check for any preconditions that might not be
satisfied. The checker can do nothing, or it can generate a new
-GRState and ExplodedNode which contains updated checker state. If it
+ProgramState and ExplodedNode which contains updated checker state. If it
finds a bug, it can tell the BugReporter object about the bug,
providing it an ExplodedNode which is the last node in the path that
triggered the problem.
diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt
index e53d805cbd64..68ee266ecae9 100644
--- a/runtime/CMakeLists.txt
+++ b/runtime/CMakeLists.txt
@@ -2,6 +2,7 @@
set(known_subdirs
"compiler-rt"
+ "libcxx"
)
foreach (dir ${known_subdirs})
diff --git a/runtime/Makefile b/runtime/Makefile
index 784eb66fc540..4b0625d4b612 100644
--- a/runtime/Makefile
+++ b/runtime/Makefile
@@ -12,7 +12,7 @@ include $(CLANG_LEVEL)/../../Makefile.config
ifndef NO_RUNTIME_LIBS
-PARALLEL_DIRS := compiler-rt
+PARALLEL_DIRS := compiler-rt libcxx
endif
diff --git a/runtime/compiler-rt/Makefile b/runtime/compiler-rt/Makefile
index 0d770db17c47..8888556738af 100644
--- a/runtime/compiler-rt/Makefile
+++ b/runtime/compiler-rt/Makefile
@@ -1,4 +1,4 @@
-##===- clang/runtime/Makefile ------------------------------*- Makefile -*-===##
+##===- clang/runtime/compiler-rt/Makefile ------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
diff --git a/runtime/libcxx/Makefile b/runtime/libcxx/Makefile
new file mode 100644
index 000000000000..a65c906e8da3
--- /dev/null
+++ b/runtime/libcxx/Makefile
@@ -0,0 +1,35 @@
+##===- clang/runtime/libcxx/Makefile -----------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This file defines support for installing a copy of the libcxx headers where
+# the driver expects them.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../..
+include $(CLANG_LEVEL)/Makefile
+
+PROJ_libcxx_hdrs := $(DESTDIR)$(PROJ_prefix)/lib/c++/v1
+
+# Expect libcxx to be in llvm/projects/libcxx
+LIBCXX_SRC_ROOT := $(LLVM_SRC_ROOT)/projects/libcxx
+
+ifneq ($(CLANG_NO_RUNTIME),1)
+ifeq ($(shell test -d $(LIBCXX_SRC_ROOT) && echo OK),OK)
+
+install-local::
+ mkdir -p $(PROJ_libcxx_hdrs)/ext
+ rsync -r --exclude=".*" $(LIBCXX_SRC_ROOT)/include/* $(PROJ_libcxx_hdrs)
+ chmod 755 $(PROJ_libcxx_hdrs)
+ chmod 644 $(PROJ_libcxx_hdrs)/*
+ chmod 755 $(PROJ_libcxx_hdrs)/ext
+ chmod 644 $(PROJ_libcxx_hdrs)/ext/*
+
+endif
+endif
diff --git a/test/ARCMT/Common.h b/test/ARCMT/Common.h
index c57f3e75e49e..2603730cad9d 100644
--- a/test/ARCMT/Common.h
+++ b/test/ARCMT/Common.h
@@ -4,6 +4,10 @@
#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE
#endif
+#define CF_CONSUMED __attribute__((cf_consumed))
+
+#define nil ((void*) 0)
+
typedef int BOOL;
typedef unsigned NSUInteger;
typedef int int32_t;
@@ -11,8 +15,14 @@ typedef unsigned char uint8_t;
typedef int32_t UChar32;
typedef unsigned char UChar;
+typedef struct _NSZone NSZone;
+
+typedef const void * CFTypeRef;
+CFTypeRef CFRetain(CFTypeRef cf);
+
@protocol NSObject
- (BOOL)isEqual:(id)object;
+- (NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
- (id)retain NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
- (NSUInteger)retainCount NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
- (oneway void)release NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
diff --git a/test/ARCMT/api.m b/test/ARCMT/api.m
new file mode 100644
index 000000000000..b186ec724745
--- /dev/null
+++ b/test/ARCMT/api.m
@@ -0,0 +1,9 @@
+// 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
+
+#include "Common.h"
+
+void test(NSObject *o) {
+ NSZone *z = [o zone];
+}
diff --git a/test/ARCMT/api.m.result b/test/ARCMT/api.m.result
new file mode 100644
index 000000000000..e3093751b626
--- /dev/null
+++ b/test/ARCMT/api.m.result
@@ -0,0 +1,9 @@
+// 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
+
+#include "Common.h"
+
+void test(NSObject *o) {
+ NSZone *z = nil;
+}
diff --git a/test/ARCMT/assign-prop-no-arc-runtime.m b/test/ARCMT/assign-prop-no-arc-runtime.m
index 0baa1d28ff56..de1c456b3d19 100644
--- a/test/ARCMT/assign-prop-no-arc-runtime.m
+++ b/test/ARCMT/assign-prop-no-arc-runtime.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-macosx10.6 -fobjc-nonfragile-abi -fsyntax-only %s > %t
+// 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-macosx10.6 -fsyntax-only %s > %t
// RUN: diff %t %s.result
#include "Common.h"
diff --git a/test/ARCMT/assign-prop-no-arc-runtime.m.result b/test/ARCMT/assign-prop-no-arc-runtime.m.result
index 49e91d83cfec..23848d357268 100644
--- a/test/ARCMT/assign-prop-no-arc-runtime.m.result
+++ b/test/ARCMT/assign-prop-no-arc-runtime.m.result
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-macosx10.6 -fobjc-nonfragile-abi -fsyntax-only %s > %t
+// 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-macosx10.6 -fsyntax-only %s > %t
// RUN: diff %t %s.result
#include "Common.h"
diff --git a/test/ARCMT/assign-prop-with-arc-runtime.m b/test/ARCMT/assign-prop-with-arc-runtime.m
index 4e4ae774a25c..9e10b58f621f 100644
--- a/test/ARCMT/assign-prop-with-arc-runtime.m
+++ b/test/ARCMT/assign-prop-with-arc-runtime.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fobjc-nonfragile-abi -fsyntax-only %s > %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fsyntax-only %s > %t
// RUN: diff %t %s.result
#include "Common.h"
@@ -20,8 +20,9 @@ typedef _NSCachedAttributedString *BadClassForWeak;
id not_safe1;
NSObject *not_safe2;
Forw *not_safe3;
+ Foo *assign_plus1;
}
-@property (readonly,assign) Foo *x;
+@property (readonly) Foo *x;
@property (assign) Foo *w;
@property Foo *q1, *q2;
@property (assign) WeakOptOut *oo;
@@ -29,6 +30,9 @@ typedef _NSCachedAttributedString *BadClassForWeak;
@property (assign) id not_safe1;
@property () NSObject *not_safe2;
@property Forw *not_safe3;
+@property (readonly) Foo *assign_plus1;
+@property (readonly) Foo *assign_plus2;
+@property (readonly) Foo *assign_plus3;
@property (assign) Foo *no_user_ivar1;
@property (readonly) Foo *no_user_ivar2;
@@ -37,4 +41,11 @@ typedef _NSCachedAttributedString *BadClassForWeak;
@implementation Foo
@synthesize x,w,q1,q2,oo,bcw,not_safe1,not_safe2,not_safe3;
@synthesize no_user_ivar1, no_user_ivar2;
+@synthesize assign_plus1, assign_plus2, assign_plus3;
+
+-(void)test:(Foo *)parm {
+ assign_plus1 = [[Foo alloc] init];
+ assign_plus2 = [Foo new];
+ assign_plus3 = [parm retain];
+}
@end
diff --git a/test/ARCMT/assign-prop-with-arc-runtime.m.result b/test/ARCMT/assign-prop-with-arc-runtime.m.result
index eb34c168e406..8a3a0f78b6b6 100644
--- a/test/ARCMT/assign-prop-with-arc-runtime.m.result
+++ b/test/ARCMT/assign-prop-with-arc-runtime.m.result
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fobjc-nonfragile-abi -fsyntax-only %s > %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fsyntax-only %s > %t
// RUN: diff %t %s.result
#include "Common.h"
@@ -20,8 +20,9 @@ typedef _NSCachedAttributedString *BadClassForWeak;
id __unsafe_unretained not_safe1;
NSObject *__unsafe_unretained not_safe2;
Forw *__unsafe_unretained not_safe3;
+ Foo *assign_plus1;
}
-@property (readonly,weak) Foo *x;
+@property (readonly) Foo *x;
@property (weak) Foo *w;
@property (weak) Foo *q1, *q2;
@property (unsafe_unretained) WeakOptOut *oo;
@@ -29,6 +30,9 @@ typedef _NSCachedAttributedString *BadClassForWeak;
@property (unsafe_unretained) id not_safe1;
@property (unsafe_unretained) NSObject *not_safe2;
@property (unsafe_unretained) Forw *not_safe3;
+@property (readonly) Foo *assign_plus1;
+@property (strong, readonly) Foo *assign_plus2;
+@property (strong, readonly) Foo *assign_plus3;
@property (weak) Foo *no_user_ivar1;
@property (weak, readonly) Foo *no_user_ivar2;
@@ -37,4 +41,11 @@ typedef _NSCachedAttributedString *BadClassForWeak;
@implementation Foo
@synthesize x,w,q1,q2,oo,bcw,not_safe1,not_safe2,not_safe3;
@synthesize no_user_ivar1, no_user_ivar2;
+@synthesize assign_plus1, assign_plus2, assign_plus3;
+
+-(void)test:(Foo *)parm {
+ assign_plus1 = [[Foo alloc] init];
+ assign_plus2 = [Foo new];
+ assign_plus3 = parm;
+}
@end
diff --git a/test/ARCMT/atautorelease-2.m b/test/ARCMT/atautorelease-2.m
index 5d2977227781..b9bc10655325 100644
--- a/test/ARCMT/atautorelease-2.m
+++ b/test/ARCMT/atautorelease-2.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
@interface NSAutoreleasePool
diff --git a/test/ARCMT/atautorelease-2.m.result b/test/ARCMT/atautorelease-2.m.result
index 7bb164723e19..205473380b73 100644
--- a/test/ARCMT/atautorelease-2.m.result
+++ b/test/ARCMT/atautorelease-2.m.result
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
@interface NSAutoreleasePool
diff --git a/test/ARCMT/atautorelease-3.m b/test/ARCMT/atautorelease-3.m
index 5d71c33b6bc8..87b80af9350e 100644
--- a/test/ARCMT/atautorelease-3.m
+++ b/test/ARCMT/atautorelease-3.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
@interface NSAutoreleasePool
diff --git a/test/ARCMT/atautorelease-3.m.result b/test/ARCMT/atautorelease-3.m.result
index 682118e82f28..801376a7e82b 100644
--- a/test/ARCMT/atautorelease-3.m.result
+++ b/test/ARCMT/atautorelease-3.m.result
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
@interface NSAutoreleasePool
diff --git a/test/ARCMT/atautorelease-check.m b/test/ARCMT/atautorelease-check.m
index 6528f3e62d1e..d74ef3b61d1f 100644
--- a/test/ARCMT/atautorelease-check.m
+++ b/test/ARCMT/atautorelease-check.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi %s
+// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 %s
#if __has_feature(objc_arr)
#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode")))
diff --git a/test/ARCMT/atautorelease.m b/test/ARCMT/atautorelease.m
index bdf77197a8a5..a6aed146497b 100644
--- a/test/ARCMT/atautorelease.m
+++ b/test/ARCMT/atautorelease.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
#include "Common.h"
@@ -45,3 +45,17 @@ int main2(int argc, char *argv[]) {
[pool release];
return result;
}
+
+@interface Foo : NSObject
+@property (assign) id myProp;
+@end
+
+@implementation Foo
+@synthesize myProp;
+
+-(void)test:(id)p {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [pool drain];
+ self.myProp = p;
+}
+@end
diff --git a/test/ARCMT/atautorelease.m.result b/test/ARCMT/atautorelease.m.result
index ccce1bd87570..e24339a3b9e3 100644
--- a/test/ARCMT/atautorelease.m.result
+++ b/test/ARCMT/atautorelease.m.result
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
#include "Common.h"
@@ -44,3 +44,17 @@ int main2(int argc, char *argv[]) {
return result;
}
}
+
+@interface Foo : NSObject
+@property (unsafe_unretained) id myProp;
+@end
+
+@implementation Foo
+@synthesize myProp;
+
+-(void)test:(id)p {
+ @autoreleasepool {
+ }
+ self.myProp = p;
+}
+@end
diff --git a/test/ARCMT/autoreleases.m b/test/ARCMT/autoreleases.m
index a12db8178f7a..ed78cb4e2e57 100644
--- a/test/ARCMT/autoreleases.m
+++ b/test/ARCMT/autoreleases.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
typedef unsigned char BOOL;
diff --git a/test/ARCMT/autoreleases.m.result b/test/ARCMT/autoreleases.m.result
index 796bfbb9d659..acb81b50647a 100644
--- a/test/ARCMT/autoreleases.m.result
+++ b/test/ARCMT/autoreleases.m.result
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
typedef unsigned char BOOL;
diff --git a/test/ARCMT/check-api.m b/test/ARCMT/check-api.m
new file mode 100644
index 000000000000..11f431377da6
--- /dev/null
+++ b/test/ARCMT/check-api.m
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-macosx10.7 %s
+
+#include "Common.h"
+
+@interface NSInvocation : NSObject
+- (void)getReturnValue:(void *)retLoc;
+- (void)setReturnValue:(void *)retLoc;
+
+- (void)getArgument:(void *)argumentLocation atIndex:(int)idx;
+- (void)setArgument:(void *)argumentLocation atIndex:(int)idx;
+@end
+
+@interface Test
+@end
+
+@implementation Test {
+ id strong_id;
+ __weak id weak_id;
+ __unsafe_unretained id unsafe_id;
+ int arg;
+}
+- (void) test:(NSInvocation *)invok {
+ [invok getReturnValue:&strong_id]; // expected-error {{NSInvocation's getReturnValue is not safe to be used with an object with ownership other than __unsafe_unretained}}
+ [invok getReturnValue:&weak_id]; // expected-error {{NSInvocation's getReturnValue is not safe to be used with an object with ownership other than __unsafe_unretained}}
+ [invok getReturnValue:&unsafe_id];
+ [invok getReturnValue:&arg];
+
+ [invok setReturnValue:&strong_id]; // expected-error {{NSInvocation's setReturnValue is not safe to be used with an object with ownership other than __unsafe_unretained}}
+ [invok setReturnValue:&weak_id]; // expected-error {{NSInvocation's setReturnValue is not safe to be used with an object with ownership other than __unsafe_unretained}}
+ [invok setReturnValue:&unsafe_id];
+ [invok setReturnValue:&arg];
+
+ [invok getArgument:&strong_id atIndex:0]; // expected-error {{NSInvocation's getArgument is not safe to be used with an object with ownership other than __unsafe_unretained}}
+ [invok getArgument:&weak_id atIndex:0]; // expected-error {{NSInvocation's getArgument is not safe to be used with an object with ownership other than __unsafe_unretained}}
+ [invok getArgument:&unsafe_id atIndex:0];
+ [invok getArgument:&arg atIndex:0];
+
+ [invok setArgument:&strong_id atIndex:0]; // expected-error {{NSInvocation's setArgument is not safe to be used with an object with ownership other than __unsafe_unretained}}
+ [invok setArgument:&weak_id atIndex:0]; // expected-error {{NSInvocation's setArgument is not safe to be used with an object with ownership other than __unsafe_unretained}}
+ [invok setArgument:&unsafe_id atIndex:0];
+ [invok setArgument:&arg atIndex:0];
+}
+@end
diff --git a/test/ARCMT/checking.m b/test/ARCMT/checking.m
index eea7a9f2547c..7c24dc485a2d 100644
--- a/test/ARCMT/checking.m
+++ b/test/ARCMT/checking.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi %s
+// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 %s
#include "Common.h"
diff --git a/test/ARCMT/cxx-checking.mm b/test/ARCMT/cxx-checking.mm
index 27e0ea3869b8..ab6b29bafe62 100644
--- a/test/ARCMT/cxx-checking.mm
+++ b/test/ARCMT/cxx-checking.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fblocks -Warc-abi %s
+// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 -fsyntax-only -fblocks -Warc-abi %s
// Classes that have an Objective-C object pointer.
struct HasObjectMember0 { // expected-warning{{'HasObjectMember0' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
diff --git a/test/ARCMT/cxx-rewrite.mm b/test/ARCMT/cxx-rewrite.mm
index aba3f7568b03..4a9c50c92426 100644
--- a/test/ARCMT/cxx-rewrite.mm
+++ b/test/ARCMT/cxx-rewrite.mm
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c++ %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c++ %s > %t
+// 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
#include "Common.h"
@@ -14,6 +14,8 @@ struct foo {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
[[[NSString string] retain] release];
[pool drain];
+ if (s)
+ [s release];
}
~foo(){ [s release]; }
private:
diff --git a/test/ARCMT/cxx-rewrite.mm.result b/test/ARCMT/cxx-rewrite.mm.result
index 145ccd39e884..0dd67e8b27f4 100644
--- a/test/ARCMT/cxx-rewrite.mm.result
+++ b/test/ARCMT/cxx-rewrite.mm.result
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c++ %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c++ %s > %t
+// 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
#include "Common.h"
diff --git a/test/ARCMT/dealloc.m b/test/ARCMT/dealloc.m
index dac964403f27..d7a72af4f726 100644
--- a/test/ARCMT/dealloc.m
+++ b/test/ARCMT/dealloc.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
@interface A
diff --git a/test/ARCMT/dealloc.m.result b/test/ARCMT/dealloc.m.result
index 24756d25484b..fbd9e445d275 100644
--- a/test/ARCMT/dealloc.m.result
+++ b/test/ARCMT/dealloc.m.result
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
@interface A
diff --git a/test/ARCMT/driver-migrate.m b/test/ARCMT/driver-migrate.m
index e283857cb574..32e84d757819 100644
--- a/test/ARCMT/driver-migrate.m
+++ b/test/ARCMT/driver-migrate.m
@@ -1,3 +1,12 @@
// RUN: %clang -### -ccc-arcmt-migrate /foo/bar -fsyntax-only %s 2>&1 | FileCheck %s
// CHECK: "-arcmt-migrate" "-arcmt-migrate-directory" "{{[^"]*}}/foo/bar"
+
+// RUN: touch %t.o
+// RUN: %clang -ccc-arcmt-check -ccc-host-triple i386-apple-darwin9 -### %t.o 2> %t.log
+// RUN: FileCheck -check-prefix=LINK %s < %t.log
+// RUN: %clang -ccc-arcmt-migrate /foo/bar -ccc-host-triple i386-apple-darwin9 -### %t.o 2> %t.log
+// RUN: FileCheck -check-prefix=LINK %s < %t.log
+
+// LINK-NOT: {{ld(.exe)?"}}
+// LINK: {{touch(.exe)?"}}
diff --git a/test/ARCMT/init.m b/test/ARCMT/init.m
index f0d24f60e1e3..8636e3733d22 100644
--- a/test/ARCMT/init.m
+++ b/test/ARCMT/init.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
@interface NSObject
diff --git a/test/ARCMT/init.m.result b/test/ARCMT/init.m.result
index 4f3b4e724e2e..0140bb96919c 100644
--- a/test/ARCMT/init.m.result
+++ b/test/ARCMT/init.m.result
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
@interface NSObject
diff --git a/test/ARCMT/migrate-emit-errors.m b/test/ARCMT/migrate-emit-errors.m
new file mode 100644
index 000000000000..6a4a3963ca0b
--- /dev/null
+++ b/test/ARCMT/migrate-emit-errors.m
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t -arcmt-migrate-emit-errors %s 2>&1 | FileCheck %s
+// RUN: rm -rf %t
+
+@protocol NSObject
+- (oneway void)release;
+@end
+
+void test(id p) {
+ [p release];
+}
+
+// CHECK: error: ARC forbids explicit message send of 'release' \ No newline at end of file
diff --git a/test/ARCMT/migrate-plist-output.m b/test/ARCMT/migrate-plist-output.m
new file mode 100644
index 000000000000..e5b74e91f8d0
--- /dev/null
+++ b/test/ARCMT/migrate-plist-output.m
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t.dir -arcmt-migrate-report-output %t.plist %s
+// RUN: FileCheck %s -input-file=%t.plist
+// RUN: rm -rf %t.dir
+
+@protocol NSObject
+- (oneway void)release;
+@end
+
+void test(id p) {
+ [p release];
+}
+
+// CHECK: <?xml version="1.0" encoding="UTF-8"?>
+// CHECK: <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+// CHECK: <plist version="1.0">
+// CHECK: <dict>
+// CHECK: <key>files</key>
+// CHECK: <array>
+// CHECK: </array>
+// CHECK: <key>diagnostics</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>description</key><string>ARC forbids explicit message send of &apos;release&apos;</string>
+// CHECK: <key>category</key><string>Automatic Reference Counting Issue</string>
+// CHECK: <key>type</key><string>error</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>12</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </plist>
diff --git a/test/ARCMT/migrate-space-in-path.m b/test/ARCMT/migrate-space-in-path.m
new file mode 100644
index 000000000000..32617666a96e
--- /dev/null
+++ b/test/ARCMT/migrate-space-in-path.m
@@ -0,0 +1,5 @@
+// RUN: rm -rf %t.migrate
+// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t.migrate %S/"with space"/test1.m.in -x objective-c
+// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t.migrate %S/"with space"/test2.m.in -x objective-c
+// RUN: c-arcmt-test -arcmt-migrate-directory %t.migrate | arcmt-test -verify-transformed-files %S/"with space"/test1.m.in.result %S/"with space"/test2.m.in.result %S/"with space"/test.h.result
+// RUN: rm -rf %t.migrate
diff --git a/test/ARCMT/migrate.m b/test/ARCMT/migrate.m
index 51029c5204f7..cfd7115acc1e 100644
--- a/test/ARCMT/migrate.m
+++ b/test/ARCMT/migrate.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t %S/Inputs/test1.m.in -x objective-c -fobjc-nonfragile-abi
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t %S/Inputs/test2.m.in -x objective-c -fobjc-nonfragile-abi
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t %S/Inputs/test1.m.in -x objective-c
+// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t %S/Inputs/test2.m.in -x objective-c
// RUN: c-arcmt-test -arcmt-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
diff --git a/test/ARCMT/nonobjc-to-objc-cast-2.m b/test/ARCMT/nonobjc-to-objc-cast-2.m
index 46ef02400e8c..5dba61f023fd 100644
--- a/test/ARCMT/nonobjc-to-objc-cast-2.m
+++ b/test/ARCMT/nonobjc-to-objc-cast-2.m
@@ -1,9 +1,13 @@
-// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi %s
+// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 %s
-typedef int BOOL;
-typedef const struct __CFString * CFStringRef;
+#include "Common.h"
+
+@interface NSString : NSObject
+-(id)string;
+-(id)newString;
+@end
-@class NSString;
+typedef const struct __CFString * CFStringRef;
void f(BOOL b) {
CFStringRef cfstr;
@@ -12,3 +16,16 @@ void f(BOOL b) {
// expected-note{{use __bridge_transfer to transfer ownership of a +1 'CFStringRef' (aka 'const struct __CFString *') into ARC}}
void *vp = str; // expected-error {{disallowed}}
}
+
+void f2(NSString *s) {
+ CFStringRef ref;
+ ref = [(CFStringRef)[s string] retain]; // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef' (aka 'const struct __CFString *') requires a bridged cast}} \
+ // expected-error {{ bad receiver type 'CFStringRef' (aka 'const struct __CFString *')}} \
+ // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note{{use __bridge_retained to make an ARC object available as a +1 'CFStringRef' (aka 'const struct __CFString *')}}
+}
+
+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}}
+}
diff --git a/test/ARCMT/nonobjc-to-objc-cast.m b/test/ARCMT/nonobjc-to-objc-cast.m
index 4e1e293efbac..4fa110919917 100644
--- a/test/ARCMT/nonobjc-to-objc-cast.m
+++ b/test/ARCMT/nonobjc-to-objc-cast.m
@@ -1,10 +1,12 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
#include "Common.h"
@interface NSString : NSObject
+-(id)string;
+-(id)newString;
@end
typedef const struct __CFString * CFStringRef;
@@ -27,6 +29,7 @@ void f(BOOL b, id p) {
CFUUIDRef _uuid;
NSString *_uuidString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, _uuid);
_uuidString = [(NSString *)CFUUIDCreateString(kCFAllocatorDefault, _uuid) autorelease];
+ _uuidString = CFRetain(_uuid);
}
@implementation NSString (StrExt)
@@ -36,3 +39,23 @@ void f(BOOL b, id p) {
return self;
}
@end
+
+extern void consumeParam(CFStringRef CF_CONSUMED p);
+
+void f2(NSString *s) {
+ CFStringRef ref = [s string];
+ ref = (CFStringRef)[s string];
+ ref = s.string;
+ ref = [NSString new];
+ ref = [s newString];
+ ref = (CFStringRef)[NSString new];
+ ref = [[NSString alloc] init];
+ ref = [[s string] retain];
+ ref = CFRetain((CFStringRef)[s string]);
+ ref = CFRetain([s string]);
+ ref = CFRetain(s);
+ ref = [s retain];
+
+ consumeParam((CFStringRef)s);
+ consumeParam(s);
+}
diff --git a/test/ARCMT/nonobjc-to-objc-cast.m.result b/test/ARCMT/nonobjc-to-objc-cast.m.result
index 53dde7553d6d..bf6aad931948 100644
--- a/test/ARCMT/nonobjc-to-objc-cast.m.result
+++ b/test/ARCMT/nonobjc-to-objc-cast.m.result
@@ -1,10 +1,12 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
#include "Common.h"
@interface NSString : NSObject
+-(id)string;
+-(id)newString;
@end
typedef const struct __CFString * CFStringRef;
@@ -27,6 +29,7 @@ void f(BOOL b, id p) {
CFUUIDRef _uuid;
NSString *_uuidString = (__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, _uuid);
_uuidString = (__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, _uuid);
+ _uuidString = (__bridge_transfer NSString *)(CFRetain(_uuid));
}
@implementation NSString (StrExt)
@@ -36,3 +39,23 @@ void f(BOOL b, id p) {
return self;
}
@end
+
+extern void consumeParam(CFStringRef CF_CONSUMED p);
+
+void f2(NSString *s) {
+ CFStringRef ref = (__bridge CFStringRef)([s string]);
+ ref = (__bridge CFStringRef)[s string];
+ ref = (__bridge CFStringRef)(s.string);
+ ref = (__bridge_retained CFStringRef)([NSString new]);
+ ref = (__bridge_retained CFStringRef)([s newString]);
+ ref = (__bridge_retained CFStringRef)[NSString new];
+ ref = (__bridge_retained CFStringRef)([[NSString alloc] init]);
+ ref = (__bridge_retained CFStringRef)([s string]);
+ ref = (__bridge_retained CFStringRef)[s string];
+ ref = (__bridge_retained CFTypeRef)([s string]);
+ ref = (__bridge_retained CFTypeRef)(s);
+ ref = (__bridge_retained CFStringRef)(s);
+
+ consumeParam((__bridge_retained CFStringRef)s);
+ consumeParam((__bridge_retained CFStringRef)(s));
+}
diff --git a/test/ARCMT/releases-driver.m b/test/ARCMT/releases-driver.m
index a016b26f4482..b75432ac2318 100644
--- a/test/ARCMT/releases-driver.m
+++ b/test/ARCMT/releases-driver.m
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: %clang_cc1 -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: cp %s %t
-// RUN: %clang_cc1 -arcmt-modify -triple x86_64-apple-macosx10.6 -fobjc-nonfragile-abi -x objective-c %t
+// RUN: %clang_cc1 -arcmt-modify -triple x86_64-apple-macosx10.6 -x objective-c %t
// RUN: diff %t %s.result
// RUN: rm %t
diff --git a/test/ARCMT/releases-driver.m.result b/test/ARCMT/releases-driver.m.result
index c5f527fec1c1..70c0aecaf475 100644
--- a/test/ARCMT/releases-driver.m.result
+++ b/test/ARCMT/releases-driver.m.result
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: %clang_cc1 -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: cp %s %t
-// RUN: %clang_cc1 -arcmt-modify -triple x86_64-apple-macosx10.6 -fobjc-nonfragile-abi -x objective-c %t
+// RUN: %clang_cc1 -arcmt-modify -triple x86_64-apple-macosx10.6 -x objective-c %t
// RUN: diff %t %s.result
// RUN: rm %t
diff --git a/test/ARCMT/releases.m b/test/ARCMT/releases.m
index d5f21dc4c2a7..867fab9cec74 100644
--- a/test/ARCMT/releases.m
+++ b/test/ARCMT/releases.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-exceptions -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-exceptions -fblocks -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: %clang_cc1 -fobjc-exceptions -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-exceptions -fblocks -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
#define nil 0
@@ -85,3 +85,15 @@ void test2(id p) {
RELEASE_MACRO(p);
RELEASE_MACRO2(p);
}
+
+@implementation Foo2
+
+static id internal_var = 0;
+
++ (void)setIt:(id)newone {
+ if (internal_var != newone) {
+ [internal_var release];
+ internal_var = [newone retain];
+ }
+}
+@end
diff --git a/test/ARCMT/releases.m.result b/test/ARCMT/releases.m.result
index 1d36f3e6b7de..556610ab2a53 100644
--- a/test/ARCMT/releases.m.result
+++ b/test/ARCMT/releases.m.result
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-exceptions -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-exceptions -fblocks -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: %clang_cc1 -fobjc-exceptions -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-exceptions -fblocks -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
#define nil 0
@@ -77,3 +77,14 @@ void block_test(Foo *p) {
void test2(id p) {
}
+
+@implementation Foo2
+
+static id internal_var = 0;
+
++ (void)setIt:(id)newone {
+ if (internal_var != newone) {
+ internal_var = newone;
+ }
+}
+@end
diff --git a/test/ARCMT/remove-dealloc-method.m b/test/ARCMT/remove-dealloc-method.m
index 5c2d785ba716..8e39fc874c95 100644
--- a/test/ARCMT/remove-dealloc-method.m
+++ b/test/ARCMT/remove-dealloc-method.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
#define nil ((void*) 0)
diff --git a/test/ARCMT/remove-dealloc-method.m.result b/test/ARCMT/remove-dealloc-method.m.result
index ecb752cf2f88..47e31f9d249a 100644
--- a/test/ARCMT/remove-dealloc-method.m.result
+++ b/test/ARCMT/remove-dealloc-method.m.result
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
#define nil ((void*) 0)
diff --git a/test/ARCMT/remove-dealloc-zerouts.m b/test/ARCMT/remove-dealloc-zerouts.m
index 3ba85f1edcab..4176ec580c3e 100644
--- a/test/ARCMT/remove-dealloc-zerouts.m
+++ b/test/ARCMT/remove-dealloc-zerouts.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
@interface Foo
diff --git a/test/ARCMT/remove-dealloc-zerouts.m.result b/test/ARCMT/remove-dealloc-zerouts.m.result
index dc6ffd311490..9ae831abacf2 100644
--- a/test/ARCMT/remove-dealloc-zerouts.m.result
+++ b/test/ARCMT/remove-dealloc-zerouts.m.result
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
@interface Foo
diff --git a/test/ARCMT/remove-statements.m b/test/ARCMT/remove-statements.m
index 7e102961263a..286a8e715e0d 100644
--- a/test/ARCMT/remove-statements.m
+++ b/test/ARCMT/remove-statements.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
#include "Common.h"
diff --git a/test/ARCMT/remove-statements.m.result b/test/ARCMT/remove-statements.m.result
index 9a1153e287c2..6a4ea08b8c95 100644
--- a/test/ARCMT/remove-statements.m.result
+++ b/test/ARCMT/remove-statements.m.result
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
#include "Common.h"
diff --git a/test/ARCMT/retains.m b/test/ARCMT/retains.m
index fa90f218dd5d..60283a695ff4 100644
--- a/test/ARCMT/retains.m
+++ b/test/ARCMT/retains.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fblocks -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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"
diff --git a/test/ARCMT/retains.m.result b/test/ARCMT/retains.m.result
index 54df864e58cb..2011e506360c 100644
--- a/test/ARCMT/retains.m.result
+++ b/test/ARCMT/retains.m.result
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fblocks -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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"
diff --git a/test/ARCMT/rewrite-block-var.m b/test/ARCMT/rewrite-block-var.m
index 81407f92e9bb..e6a8fb72e00a 100644
--- a/test/ARCMT/rewrite-block-var.m
+++ b/test/ARCMT/rewrite-block-var.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -fsyntax-only -fobjc-arc -x objective-c -fobjc-runtime-has-weak %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fobjc-nonfragile-abi -fblocks -fsyntax-only %s > %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -fsyntax-only -fobjc-arc -x objective-c -fobjc-runtime-has-weak %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fblocks -fsyntax-only %s > %t
// RUN: diff %t %s.result
#include "Common.h"
diff --git a/test/ARCMT/rewrite-block-var.m.result b/test/ARCMT/rewrite-block-var.m.result
index 85093ac52d27..27c81bd58825 100644
--- a/test/ARCMT/rewrite-block-var.m.result
+++ b/test/ARCMT/rewrite-block-var.m.result
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -fsyntax-only -fobjc-arc -x objective-c -fobjc-runtime-has-weak %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fobjc-nonfragile-abi -fblocks -fsyntax-only %s > %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -fsyntax-only -fobjc-arc -x objective-c -fobjc-runtime-has-weak %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fblocks -fsyntax-only %s > %t
// RUN: diff %t %s.result
#include "Common.h"
diff --git a/test/ARCMT/safe-arc-assign.m b/test/ARCMT/safe-arc-assign.m
index 368c2b6639da..4a0a575794e1 100644
--- a/test/ARCMT/safe-arc-assign.m
+++ b/test/ARCMT/safe-arc-assign.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
void test12(id collection) {
diff --git a/test/ARCMT/safe-arc-assign.m.result b/test/ARCMT/safe-arc-assign.m.result
index cacd1093c524..c25955ea7d1c 100644
--- a/test/ARCMT/safe-arc-assign.m.result
+++ b/test/ARCMT/safe-arc-assign.m.result
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// 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
void test12(id collection) {
diff --git a/test/ARCMT/with space/test.h b/test/ARCMT/with space/test.h
new file mode 100644
index 000000000000..756295f27e69
--- /dev/null
+++ b/test/ARCMT/with space/test.h
@@ -0,0 +1,15 @@
+@protocol NSObject
+- (oneway void)release;
+@end
+
+#ifdef PART1
+static inline void part1(id p) {
+ [p release];
+}
+#endif
+
+#ifdef PART2
+static inline void part2(id p) {
+ [p release];
+}
+#endif
diff --git a/test/ARCMT/with space/test.h.result b/test/ARCMT/with space/test.h.result
new file mode 100644
index 000000000000..0638a3378c1c
--- /dev/null
+++ b/test/ARCMT/with space/test.h.result
@@ -0,0 +1,13 @@
+@protocol NSObject
+- (oneway void)release;
+@end
+
+#ifdef PART1
+static inline void part1(id p) {
+}
+#endif
+
+#ifdef PART2
+static inline void part2(id p) {
+}
+#endif
diff --git a/test/ARCMT/with space/test1.m.in b/test/ARCMT/with space/test1.m.in
new file mode 100644
index 000000000000..8416a8896569
--- /dev/null
+++ b/test/ARCMT/with space/test1.m.in
@@ -0,0 +1,6 @@
+#define PART1
+#include "test.h"
+
+void test1(id p) {
+ [p release];
+}
diff --git a/test/ARCMT/with space/test1.m.in.result b/test/ARCMT/with space/test1.m.in.result
new file mode 100644
index 000000000000..f351fe6c8355
--- /dev/null
+++ b/test/ARCMT/with space/test1.m.in.result
@@ -0,0 +1,5 @@
+#define PART1
+#include "test.h"
+
+void test1(id p) {
+}
diff --git a/test/ARCMT/with space/test2.m.in b/test/ARCMT/with space/test2.m.in
new file mode 100644
index 000000000000..99f87b072171
--- /dev/null
+++ b/test/ARCMT/with space/test2.m.in
@@ -0,0 +1,6 @@
+#define PART2
+#include "test.h"
+
+void test2(id p) {
+ [p release];
+}
diff --git a/test/ARCMT/with space/test2.m.in.result b/test/ARCMT/with space/test2.m.in.result
new file mode 100644
index 000000000000..f8e918ce2598
--- /dev/null
+++ b/test/ARCMT/with space/test2.m.in.result
@@ -0,0 +1,5 @@
+#define PART2
+#include "test.h"
+
+void test2(id p) {
+}
diff --git a/test/ARCMT/with-arc-mode-check.m b/test/ARCMT/with-arc-mode-check.m
index c3146ef3b614..33f31f522a58 100644
--- a/test/ARCMT/with-arc-mode-check.m
+++ b/test/ARCMT/with-arc-mode-check.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -arcmt-check -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s
+// RUN: %clang_cc1 -arcmt-check -fsyntax-only -fobjc-arc -x objective-c %s
@protocol NSObject
- (oneway void)release;
diff --git a/test/ARCMT/with-arc-mode-migrate.m b/test/ARCMT/with-arc-mode-migrate.m
index 3851bc77312e..32bcad195042 100644
--- a/test/ARCMT/with-arc-mode-migrate.m
+++ b/test/ARCMT/with-arc-mode-migrate.m
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc %s
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t -fsyntax-only -fobjc-arc %s
// RUN: c-arcmt-test -arcmt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
// RUN: rm -rf %t
diff --git a/test/ARCMT/with-arc-mode-migrate.m.result b/test/ARCMT/with-arc-mode-migrate.m.result
index c2222ae7b659..f060793f6eb4 100644
--- a/test/ARCMT/with-arc-mode-migrate.m.result
+++ b/test/ARCMT/with-arc-mode-migrate.m.result
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc %s
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t -fsyntax-only -fobjc-arc %s
// RUN: c-arcmt-test -arcmt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
// RUN: rm -rf %t
diff --git a/test/ARCMT/with-arc-mode-modify.m b/test/ARCMT/with-arc-mode-modify.m
index 17a398072e1f..fbbd630700f4 100644
--- a/test/ARCMT/with-arc-mode-modify.m
+++ b/test/ARCMT/with-arc-mode-modify.m
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: cp %s %t
-// RUN: %clang_cc1 -arcmt-modify -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %t
+// RUN: %clang_cc1 -arcmt-modify -fsyntax-only -fobjc-arc -x objective-c %t
// RUN: diff %t %s.result
// RUN: rm %t
diff --git a/test/ARCMT/with-arc-mode-modify.m.result b/test/ARCMT/with-arc-mode-modify.m.result
index 97c5128cd950..631f276516f6 100644
--- a/test/ARCMT/with-arc-mode-modify.m.result
+++ b/test/ARCMT/with-arc-mode-modify.m.result
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: cp %s %t
-// RUN: %clang_cc1 -arcmt-modify -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %t
+// RUN: %clang_cc1 -arcmt-modify -fsyntax-only -fobjc-arc -x objective-c %t
// RUN: diff %t %s.result
// RUN: rm %t
diff --git a/test/ASTMerge/interface.m b/test/ASTMerge/interface.m
index e37e3807e514..747ef38223ec 100644
--- a/test/ASTMerge/interface.m
+++ b/test/ASTMerge/interface.m
@@ -4,7 +4,7 @@
// CHECK: interface2.m:16:9: error: instance variable 'ivar2' declared with incompatible types in different translation units ('float' vs. 'int')
// CHECK: interface1.m:16:7: note: declared here with type 'int'
-// CHECK: interface1.m:21:1: error: class 'I4' has incompatible superclasses
+// CHECK: interface1.m:21:12: error: class 'I4' has incompatible superclasses
// CHECK: interface1.m:21:17: note: inherits from superclass 'I2' here
// CHECK: interface2.m:21:17: note: inherits from superclass 'I1' here
// CHECK: interface2.m:33:1: error: class method 'foo' has incompatible result types in different translation units ('float' vs. 'int')
@@ -15,8 +15,8 @@
// CHECK: interface1.m:46:1: note: class method 'bar:' also declared here
// CHECK: interface2.m:57:20: error: instance method 'bar:' has a parameter with a different types in different translation units ('double' vs. 'float')
// CHECK: interface1.m:58:19: note: declared here with type 'float'
-// CHECK: interface1.m:100:1: error: class 'I15' has incompatible superclasses
-// CHECK: interface1.m:100:1: note: inherits from superclass 'I12' here
-// CHECK: interface2.m:99:1: note: inherits from superclass 'I11' here
+// CHECK: interface1.m:100:17: error: class 'I15' has incompatible superclasses
+// CHECK: interface1.m:100:17: note: inherits from superclass 'I12' here
+// CHECK: interface2.m:99:17: note: inherits from superclass 'I11' here
// CHECK: 8 errors generated
diff --git a/test/Analysis/CFDateGC.m b/test/Analysis/CFDateGC.m
index bd1a4b7967ca..69b99f052b01 100644
--- a/test/Analysis/CFDateGC.m
+++ b/test/Analysis/CFDateGC.m
@@ -1,8 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -verify -fobjc-gc -analyzer-constraints=basic %s -Wno-implicit-function-declaration
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -verify -fobjc-gc -analyzer-constraints=range %s -Wno-implicit-function-declaration
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -verify -fobjc-gc -disable-free %s -Wno-implicit-function-declaration
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=basic -verify -fobjc-gc %s -Wno-implicit-function-declaration
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=range -verify -fobjc-gc %s -Wno-implicit-function-declaration
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=basic -verify -fobjc-gc %s -Wno-implicit-function-declaration
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=range -verify -fobjc-gc %s -Wno-implicit-function-declaration
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from
diff --git a/test/Analysis/CFNumber.c b/test/Analysis/CFNumber.c
index 11af0747a317..fbbe4d15f49f 100644
--- a/test/Analysis/CFNumber.c
+++ b/test/Analysis/CFNumber.c
@@ -1,7 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.coreFoundation.CFNumber -analyzer-store=basic -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.coreFoundation.CFNumber -analyzer-store=basic -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.coreFoundation.CFNumber -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.coreFoundation.CFNumber -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.coreFoundation.CFNumber,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.coreFoundation.CFNumber,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
typedef signed long CFIndex;
typedef const struct __CFAllocator * CFAllocatorRef;
diff --git a/test/Analysis/CFRetainRelease_NSAssertionHandler.m b/test/Analysis/CFRetainRelease_NSAssertionHandler.m
index ee52201e6285..e0c9be1c1ebf 100644
--- a/test/Analysis/CFRetainRelease_NSAssertionHandler.m
+++ b/test/Analysis/CFRetainRelease_NSAssertionHandler.m
@@ -1,7 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -verify %s -analyzer-constraints=basic -analyzer-store=basic
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -verify %s -analyzer-constraints=range -analyzer-store=basic
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -verify %s -analyzer-constraints=basic -analyzer-store=region
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -verify %s -analyzer-constraints=range -analyzer-store=region
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -verify %s -analyzer-constraints=basic -analyzer-store=region
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -verify %s -analyzer-constraints=range -analyzer-store=region
typedef struct objc_selector *SEL;
typedef signed char BOOL;
@@ -22,6 +20,7 @@ extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
@interface NSAssertionHandler : NSObject {}
+ (NSAssertionHandler *)currentHandler;
- (void)handleFailureInMethod:(SEL)selector object:(id)object file:(NSString *)fileName lineNumber:(NSInteger)line description:(NSString *)format,...;
+- (void)handleFailureInFunction:(NSString *)functionName file:(NSString *)fileName lineNumber:(NSInteger)line description:(NSString *)format,...;
@end
extern NSString * const NSConnectionReplyMode;
@@ -65,3 +64,10 @@ extern NSString * const NSConnectionReplyMode;
}
@end
+
+void pointerFunction (int *x) {
+ // Manual expansion of NSCAssert( x != 0, @"")
+ do { if (!((x != 0))) { [[NSAssertionHandler currentHandler] handleFailureInFunction:[NSString stringWithUTF8String:__PRETTY_FUNCTION__] file:[NSString stringWithUTF8String:__FILE__] lineNumber:__LINE__ description:((@""))]; } } while(0);
+
+ *x = 1; // no-warning
+}
diff --git a/test/Analysis/CGColorSpace.c b/test/Analysis/CGColorSpace.c
index ea458404c5dd..1bd20fa1cfa1 100644
--- a/test/Analysis/CGColorSpace.c
+++ b/test/Analysis/CGColorSpace.c
@@ -1,7 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=range -verify %s
typedef struct CGColorSpace *CGColorSpaceRef;
extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void);
diff --git a/test/Analysis/CheckNSError.m b/test/Analysis/CheckNSError.m
index 3bc7d8f748e1..5bf7e08a587a 100644
--- a/test/Analysis/CheckNSError.m
+++ b/test/Analysis/CheckNSError.m
@@ -1,6 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSError,osx.coreFoundation.CFError -analyzer-store=basic -analyzer-constraints=basic -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSError,osx.coreFoundation.CFError -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSError,osx.coreFoundation.CFError -analyzer-store=basic -analyzer-constraints=range -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSError,osx.coreFoundation.CFError -analyzer-store=region -analyzer-constraints=range -verify %s
diff --git a/test/Analysis/MissingDealloc.m b/test/Analysis/MissingDealloc.m
index e7930d1223b7..51a5912d4443 100644
--- a/test/Analysis/MissingDealloc.m
+++ b/test/Analysis/MissingDealloc.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.experimental.Dealloc '-DIBOutlet=__attribute__((iboutlet))' %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.osx.cocoa.Dealloc '-DIBOutlet=__attribute__((iboutlet))' %s -verify
typedef signed char BOOL;
@protocol NSObject
- (BOOL)isEqual:(id)object;
diff --git a/test/Analysis/NSPanel.m b/test/Analysis/NSPanel.m
index 19b72d8f692f..ac725716457f 100644
--- a/test/Analysis/NSPanel.m
+++ b/test/Analysis/NSPanel.m
@@ -1,7 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
// BEGIN delta-debugging reduced header stuff
diff --git a/test/Analysis/NSString.m b/test/Analysis/NSString.m
index 6ff4bb1e554f..48450daa013d 100644
--- a/test/Analysis/NSString.m
+++ b/test/Analysis/NSString.m
@@ -1,13 +1,8 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,core.experimental -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,core.experimental -analyzer-store=region -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,core.experimental -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,core.experimental -analyzer-store=region -analyzer-constraints=range -verify %s
-
-// ==-- FIXME: -analyzer-store=basic fails on this file (false negatives). --==
-// NOTWORK: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,core.experimental -analyzer-store=basic -analyzer-constraints=range -verify %s &&
-// NOTWORK: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,core.experimental -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
-// NOTWORK: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,core.experimental -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
-// NOTWORK: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,core.experimental -analyzer-store=basic -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
+
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from
diff --git a/test/Analysis/NSWindow.m b/test/Analysis/NSWindow.m
index 404448574ea1..495f8e19d8ef 100644
--- a/test/Analysis/NSWindow.m
+++ b/test/Analysis/NSWindow.m
@@ -1,7 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-checker=deadcode.DeadStores -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-checker=deadcode.DeadStores -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-checker=deadcode.DeadStores -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-checker=deadcode.DeadStores -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core,deadcode.DeadStores -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core,deadcode.DeadStores -analyzer-store=region -analyzer-constraints=range -verify %s
// These declarations were reduced using Delta-Debugging from Foundation.h
// on Mac OS X. The test cases are below.
diff --git a/test/Analysis/NoReturn.m b/test/Analysis/NoReturn.m
index 42952ed3a7cc..ea2efd061711 100644
--- a/test/Analysis/NoReturn.m
+++ b/test/Analysis/NoReturn.m
@@ -1,7 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
#include <stdarg.h>
diff --git a/test/Analysis/ObjCProperties.m b/test/Analysis/ObjCProperties.m
index 103db486b1c2..d88e0571e4c1 100644
--- a/test/Analysis/ObjCProperties.m
+++ b/test/Analysis/ObjCProperties.m
@@ -1,7 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=basic %s -verify
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=range %s -verify
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=basic %s -verify
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=basic %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range %s -verify
// The point of this test cases is to exercise properties in the static
// analyzer
diff --git a/test/Analysis/ObjCRetSigs.m b/test/Analysis/ObjCRetSigs.m
index 9778e41d9ced..02be25717a63 100644
--- a/test/Analysis/ObjCRetSigs.m
+++ b/test/Analysis/ObjCRetSigs.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-checker=osx.cocoa.IncompatibleMethodTypes -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core -analyzer-checker=osx.cocoa.IncompatibleMethodTypes -verify %s
int printf(const char *, ...);
diff --git a/test/Analysis/PR2599.m b/test/Analysis/PR2599.m
index b9e9d6b757de..5436063738a6 100644
--- a/test/Analysis/PR2599.m
+++ b/test/Analysis/PR2599.m
@@ -1,7 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=basic -fobjc-gc -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=range -analyzer-store=basic -fobjc-gc -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=basic -fobjc-gc -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=range -analyzer-store=region -fobjc-gc -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-constraints=range -analyzer-store=region -fobjc-gc -verify %s
typedef const void * CFTypeRef;
typedef const struct __CFString * CFStringRef;
diff --git a/test/Analysis/PR2978.m b/test/Analysis/PR2978.m
index c07150f0ce2a..ea139d28af82 100644
--- a/test/Analysis/PR2978.m
+++ b/test/Analysis/PR2978.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-checker=osx.cocoa.experimental.Dealloc %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core -analyzer-checker=experimental.osx.cocoa.Dealloc %s -verify
// Tests for the checker which checks missing/extra ivar 'release' calls
// in dealloc.
diff --git a/test/Analysis/PR3991.m b/test/Analysis/PR3991.m
index 23f199311e47..38d0bc0b5293 100644
--- a/test/Analysis/PR3991.m
+++ b/test/Analysis/PR3991.m
@@ -1,7 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
//===----------------------------------------------------------------------===//
// Delta-debugging produced forward declarations.
diff --git a/test/Analysis/PR9741.cpp b/test/Analysis/PR9741.cpp
index e20e56c9406a..7497d5627c91 100644
--- a/test/Analysis/PR9741.cpp
+++ b/test/Analysis/PR9741.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -cc1 -std=c++0x -Wuninitialized -verify %s
+// RUN: %clang_cc1 -cc1 -std=c++11 -Wuninitialized -verify %s
void f() {
int a[] = { 1, 2, 3 };
diff --git a/test/Analysis/additive-folding-range-constraints.c b/test/Analysis/additive-folding-range-constraints.c
index e342bb453cda..32e0cfe142ad 100644
--- a/test/Analysis/additive-folding-range-constraints.c
+++ b/test/Analysis/additive-folding-range-constraints.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -verify -analyzer-constraints=range %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -verify -analyzer-constraints=range %s
// These are used to trigger warnings.
typedef typeof(sizeof(int)) size_t;
diff --git a/test/Analysis/additive-folding.c b/test/Analysis/additive-folding.c
index 17d9db6ea23a..71d0151f22af 100644
--- a/test/Analysis/additive-folding.c
+++ b/test/Analysis/additive-folding.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.experimental.UnreachableCode,unix.experimental.Malloc -verify -analyzer-constraints=basic %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.experimental.UnreachableCode,unix.experimental.Malloc -verify -analyzer-constraints=range %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,experimental.unix.Malloc -verify -analyzer-constraints=basic %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,experimental.unix.Malloc -verify -analyzer-constraints=range %s
// These are used to trigger warnings.
typedef typeof(sizeof(int)) size_t;
diff --git a/test/Analysis/analyzeOneFunction.m b/test/Analysis/analyzeOneFunction.m
new file mode 100644
index 000000000000..1ff2fc8fe8a3
--- /dev/null
+++ b/test/Analysis/analyzeOneFunction.m
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -analyze -analyze-function="myMethodWithY:withX:" -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -verify %s
+
+typedef signed char BOOL;
+typedef unsigned int NSUInteger;
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject - (BOOL)isEqual:(id)object; @end
+@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end
+@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
+@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end
+@interface NSObject <NSObject> {}
++(id)alloc;
+-(id)init;
+-(id)autorelease;
+-(id)copy;
+-(id)retain;
+@end
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
+- (NSUInteger)length;
+-(id)initWithFormat:(NSString *)f,...;
+-(BOOL)isEqualToString:(NSString *)s;
++ (id)string;
+@end
+
+@interface Test1 : NSObject {
+ NSString *text;
+}
+-(id)myMethod;
+-(id)myMethodWithY:(int)Y withX:(int)X;
+
+@property (nonatomic, assign) NSString *text;
+@end
+
+@implementation Test1
+
+@synthesize text;
+
+-(id)myMethod {
+ Test1 *cell = [[[Test1 alloc] init] autorelease];
+
+ NSString *string1 = [[NSString alloc] initWithFormat:@"test %f", 0.0]; // No warning: this function is not analized.
+ cell.text = string1;
+
+ return cell;
+}
+
+-(id)myMethodWithY:(int)Y withX:(int)X {
+ Test1 *cell = [[[Test1 alloc] init] autorelease];
+
+ NSString *string1 = [[NSString alloc] initWithFormat:@"test %f %d", 0.0, X+Y]; // expected-warning {{Potential leak}}
+ cell.text = string1;
+
+ return cell;
+}
+
+@end
diff --git a/test/Analysis/array-struct-region.c b/test/Analysis/array-struct-region.c
index 37a6f75b3ca2..1284933db09d 100644
--- a/test/Analysis/array-struct-region.c
+++ b/test/Analysis/array-struct-region.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental,deadcode.experimental.UnreachableCode -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental,deadcode.experimental.UnreachableCode -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,experimental.deadcode.UnreachableCode -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,experimental.deadcode.UnreachableCode -analyzer-store=region -analyzer-constraints=range -verify %s
int string_literal_init() {
char a[] = "abc";
diff --git a/test/Analysis/array-struct.c b/test/Analysis/array-struct.c
index 6b8bb6c5f675..c5bdb86a14ed 100644
--- a/test/Analysis/array-struct.c
+++ b/test/Analysis/array-struct.c
@@ -1,7 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental.CastToStruct -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental.CastToStruct -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental.CastToStruct -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental.CastToStruct -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core.CastToStruct -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core.CastToStruct -analyzer-store=region -analyzer-constraints=range -verify %s
struct s {
int data;
diff --git a/test/Analysis/auto-obj-dtors-cfg-output.cpp b/test/Analysis/auto-obj-dtors-cfg-output.cpp
index c877061eb6ae..17aa486de0ce 100644
--- a/test/Analysis/auto-obj-dtors-cfg-output.cpp
+++ b/test/Analysis/auto-obj-dtors-cfg-output.cpp
@@ -155,655 +155,718 @@ void test_catch_copy() {
}
}
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: 3: const A &b = a;
-// CHECK: 4: A()
-// CHECK: 5: const A &c = A();
-// CHECK: 6: [B1.5].~A() (Implicit destructor)
-// CHECK: 7: [B1.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1:
-// CHECK: 2: A a[2];
-// CHECK: 3:
-// CHECK: 4: A b[0];
-// CHECK: 5: [B1.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: 3:
-// CHECK: 4: A c;
-// CHECK: 5:
-// CHECK: 6: A d;
-// CHECK: 7: [B1.6].~A() (Implicit destructor)
-// CHECK: 8: [B1.4].~A() (Implicit destructor)
-// CHECK: 9:
-// CHECK: 10: A b;
-// CHECK: 11: [B1.10].~A() (Implicit destructor)
-// CHECK: 12: [B1.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B4 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B3
-// CHECK: [ B1 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: [B1.2].~A() (Implicit destructor)
-// CHECK: 4: [B3.4].~A() (Implicit destructor)
-// CHECK: 5: [B3.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: return;
-// CHECK: 2: [B3.4].~A() (Implicit destructor)
-// CHECK: 3: [B3.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B3
-// CHECK: Successors (1): B0
-// CHECK: [ B3 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: 3:
-// CHECK: 4: A b;
-// CHECK: 5: UV
-// CHECK: T: if [B3.5]
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (2): B2 B1
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (2): B1 B2
-// CHECK: Successors (0):
-// CHECK: [ B8 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B7
-// CHECK: [ B1 ]
-// CHECK: l1:
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: [B1.2].~A() (Implicit destructor)
-// CHECK: 4: [B6.2].~A() (Implicit destructor)
-// CHECK: 5: [B7.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B2 B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1:
-// CHECK: 2: A b;
-// CHECK: 3: [B2.2].~A() (Implicit destructor)
-// CHECK: 4: [B6.4].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1: [B6.4].~A() (Implicit destructor)
-// CHECK: T: goto l1;
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B4 ]
-// CHECK: 1: UV
-// CHECK: T: if [B4.1]
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (2): B3 B2
-// CHECK: [ B5 ]
-// CHECK: 1: [B6.4].~A() (Implicit destructor)
-// CHECK: 2: [B6.2].~A() (Implicit destructor)
-// CHECK: T: goto l0;
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (1): B6
-// CHECK: [ B6 ]
-// CHECK: l0:
-// CHECK: 1:
-// CHECK: 2: A b;
-// CHECK: 3:
-// CHECK: 4: A a;
-// CHECK: 5: UV
-// CHECK: T: if [B6.5]
-// CHECK: Predecessors (2): B7 B5
-// CHECK: Successors (2): B5 B4
-// CHECK: [ B7 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (1): B6
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B5 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B4
-// CHECK: [ B1 ]
-// CHECK: 1: [B4.4].~A() (Implicit destructor)
-// CHECK: 2: [B4.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B2 B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: [B2.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: [B3.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B4 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: 3: a
-// CHECK: 4: A b = a;
-// CHECK: 5: b.operator int()
-// CHECK: 6: [B4.5]
-// CHECK: T: if [B4.6]
-// CHECK: Predecessors (1): B5
-// CHECK: Successors (2): B3 B2
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B9 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B8
-// CHECK: [ B1 ]
-// CHECK: 1: [B8.4].~A() (Implicit destructor)
-// CHECK: 2:
-// CHECK: 3: A e;
-// CHECK: 4: [B1.3].~A() (Implicit destructor)
-// CHECK: 5: [B8.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B2 B5
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1:
-// CHECK: 2: A d;
-// CHECK: 3: [B2.2].~A() (Implicit destructor)
-// CHECK: 4: [B4.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1: return;
-// CHECK: 2: [B4.2].~A() (Implicit destructor)
-// CHECK: 3: [B8.4].~A() (Implicit destructor)
-// CHECK: 4: [B8.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B0
-// CHECK: [ B4 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: UV
-// CHECK: T: if [B4.3]
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (2): B3 B2
-// CHECK: [ B5 ]
-// CHECK: 1:
-// CHECK: 2: A d;
-// CHECK: 3: [B5.2].~A() (Implicit destructor)
-// CHECK: 4: [B7.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B1
-// CHECK: [ B6 ]
-// CHECK: 1: return;
-// CHECK: 2: [B7.2].~A() (Implicit destructor)
-// CHECK: 3: [B8.4].~A() (Implicit destructor)
-// CHECK: 4: [B8.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B0
-// CHECK: [ B7 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: UV
-// CHECK: T: if [B7.3]
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (2): B6 B5
-// CHECK: [ B8 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: 3: a
-// CHECK: 4: A b = a;
-// CHECK: 5: b.operator int()
-// CHECK: 6: [B8.5]
-// CHECK: T: if [B8.6]
-// CHECK: Predecessors (1): B9
-// CHECK: Successors (2): B7 B4
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (3): B1 B3 B6
-// CHECK: Successors (0):
-// CHECK: [ B6 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B5
-// CHECK: [ B1 ]
-// CHECK: 1: [B2.2].~A() (Implicit destructor)
-// CHECK: 2: [B5.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: a
-// CHECK: 2: A b = a;
-// CHECK: 3: b.operator int()
-// CHECK: 4: [B2.3]
-// CHECK: T: while [B2.4]
-// CHECK: Predecessors (2): B3 B5
-// CHECK: Successors (2): B4 B1
-// CHECK: [ B3 ]
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B2
-// CHECK: [ B4 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: [B4.2].~A() (Implicit destructor)
-// CHECK: 4: [B2.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B3
-// CHECK: [ B5 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (1): B2
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B12 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B11
-// CHECK: [ B1 ]
-// CHECK: 1: [B2.2].~A() (Implicit destructor)
-// CHECK: 2:
-// CHECK: 3: A e;
-// CHECK: 4: [B1.3].~A() (Implicit destructor)
-// CHECK: 5: [B11.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B9 B2
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: a
-// CHECK: 2: A b = a;
-// CHECK: 3: b.operator int()
-// CHECK: 4: [B2.3]
-// CHECK: T: while [B2.4]
-// CHECK: Predecessors (2): B3 B11
-// CHECK: Successors (2): B10 B1
-// CHECK: [ B3 ]
-// CHECK: Predecessors (2): B4 B7
-// CHECK: Successors (1): B2
-// CHECK: [ B4 ]
-// CHECK: 1:
-// CHECK: 2: A d;
-// CHECK: 3: [B4.2].~A() (Implicit destructor)
-// CHECK: 4: [B10.2].~A() (Implicit destructor)
-// CHECK: 5: [B2.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (1): B3
-// CHECK: [ B5 ]
-// CHECK: 1: return;
-// CHECK: 2: [B10.2].~A() (Implicit destructor)
-// CHECK: 3: [B2.2].~A() (Implicit destructor)
-// CHECK: 4: [B11.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (1): B0
-// CHECK: [ B6 ]
-// CHECK: 1: UV
-// CHECK: T: if [B6.1]
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (2): B5 B4
-// CHECK: [ B7 ]
-// CHECK: 1: [B10.2].~A() (Implicit destructor)
-// CHECK: 2: [B2.2].~A() (Implicit destructor)
-// CHECK: T: continue;
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (1): B3
-// CHECK: [ B8 ]
-// CHECK: 1: UV
-// CHECK: T: if [B8.1]
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (2): B7 B6
-// CHECK: [ B9 ]
-// CHECK: 1: [B10.2].~A() (Implicit destructor)
-// CHECK: T: break;
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (1): B1
-// CHECK: [ B10 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: UV
-// CHECK: T: if [B10.3]
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (2): B9 B8
-// CHECK: [ B11 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: Predecessors (1): B12
-// CHECK: Successors (1): B2
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (2): B1 B5
-// CHECK: Successors (0):
-// CHECK: [ B4 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B2
-// CHECK: [ B1 ]
-// CHECK: 1: UV
-// CHECK: T: do ... while [B1.1]
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (2): B3 B0
-// CHECK: [ B2 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: 3: [B2.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B3 B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (1): B2
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B12 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B11
-// CHECK: [ B1 ]
-// CHECK: 1:
-// CHECK: 2: A d;
-// CHECK: 3: [B1.2].~A() (Implicit destructor)
-// CHECK: 4: [B11.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B8 B2
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: UV
-// CHECK: T: do ... while [B2.1]
-// CHECK: Predecessors (2): B3 B6
-// CHECK: Successors (2): B10 B1
-// CHECK: [ B3 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: [B3.2].~A() (Implicit destructor)
-// CHECK: 4: [B9.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B5
-// CHECK: Successors (1): B2
-// CHECK: [ B4 ]
-// CHECK: 1: return;
-// CHECK: 2: [B9.2].~A() (Implicit destructor)
-// CHECK: 3: [B11.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B5
-// CHECK: Successors (1): B0
-// CHECK: [ B5 ]
-// CHECK: 1: UV
-// CHECK: T: if [B5.1]
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (2): B4 B3
-// CHECK: [ B6 ]
-// CHECK: 1: [B9.2].~A() (Implicit destructor)
-// CHECK: T: continue;
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B2
-// CHECK: [ B7 ]
-// CHECK: 1: UV
-// CHECK: T: if [B7.1]
-// CHECK: Predecessors (1): B9
-// CHECK: Successors (2): B6 B5
-// CHECK: [ B8 ]
-// CHECK: 1: [B9.2].~A() (Implicit destructor)
-// CHECK: T: break;
-// CHECK: Predecessors (1): B9
-// CHECK: Successors (1): B1
-// CHECK: [ B9 ]
-// CHECK: 1:
-// CHECK: 2: A b;
-// CHECK: 3: UV
-// CHECK: T: if [B9.3]
-// CHECK: Predecessors (2): B10 B11
-// CHECK: Successors (2): B8 B7
-// CHECK: [ B10 ]
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B9
-// CHECK: [ B11 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: Predecessors (1): B12
-// CHECK: Successors (1): B9
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (2): B1 B4
-// CHECK: Successors (0):
-// CHECK: [ B4 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B2
-// CHECK: [ B1 ]
-// CHECK: 1: [B2.4].~A() (Implicit destructor)
-// CHECK: 2: [B2.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B3 B2
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: 3: a
-// CHECK: 4: A b = a;
-// CHECK: 5: b.operator int()
-// CHECK: T: switch [B2.5]
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: [B3.2].~A() (Implicit destructor)
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B9 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B2
-// CHECK: [ B1 ]
-// CHECK: 1: [B2.4].~A() (Implicit destructor)
-// CHECK: 2:
-// CHECK: 3: A g;
-// CHECK: 4: [B1.3].~A() (Implicit destructor)
-// CHECK: 5: [B2.2].~A() (Implicit destructor)
-// CHECK: Predecessors (3): B3 B7 B2
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: 3: a
-// CHECK: 4: A b = a;
-// CHECK: 5: b.operator int()
-// CHECK: T: switch [B2.5]
-// CHECK: Predecessors (1): B9
-// CHECK: Successors (3): B3 B8
-// CHECK: B1
-// CHECK: [ B3 ]
-// CHECK: case 1:
-// CHECK: T: break;
-// CHECK: Predecessors (2): B2 B4
-// CHECK: Successors (1): B1
-// CHECK: [ B4 ]
-// CHECK: 1:
-// CHECK: 2: A f;
-// CHECK: 3: [B4.2].~A() (Implicit destructor)
-// CHECK: 4: [B8.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (1): B3
-// CHECK: [ B5 ]
-// CHECK: 1: return;
-// CHECK: 2: [B8.2].~A() (Implicit destructor)
-// CHECK: 3: [B2.4].~A() (Implicit destructor)
-// CHECK: 4: [B2.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (1): B0
-// CHECK: [ B6 ]
-// CHECK: 1: UV
-// CHECK: T: if [B6.1]
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (2): B5 B4
-// CHECK: [ B7 ]
-// CHECK: 1: [B8.2].~A() (Implicit destructor)
-// CHECK: T: break;
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (1): B1
-// CHECK: [ B8 ]
-// CHECK: case 0:
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: UV
-// CHECK: T: if [B8.3]
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (2): B7 B6
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (2): B1 B5
-// CHECK: Successors (0):
-// CHECK: [ B6 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B5
-// CHECK: [ B1 ]
-// CHECK: 1: [B2.2].~A() (Implicit destructor)
-// CHECK: 2: [B5.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: a
-// CHECK: 2: A b = a;
-// CHECK: 3: b.operator int()
-// CHECK: 4: [B2.3]
-// CHECK: T: for (...; [B2.4]; )
-// CHECK: Predecessors (2): B3 B5
-// CHECK: Successors (2): B4 B1
-// CHECK: [ B3 ]
-// CHECK: 1: [B2.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B2
-// CHECK: [ B4 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: [B4.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B3
-// CHECK: [ B5 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (1): B2
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B12 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B11
-// CHECK: [ B1 ]
-// CHECK: 1: [B2.2].~A() (Implicit destructor)
-// CHECK: 2: [B11.4].~A() (Implicit destructor)
-// CHECK: 3:
-// CHECK: 4: A f;
-// CHECK: 5: [B1.4].~A() (Implicit destructor)
-// CHECK: 6: [B11.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B9 B2
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: b
-// CHECK: 2: A c = b;
-// CHECK: 3: c.operator int()
-// CHECK: 4: [B2.3]
-// CHECK: T: for (...; [B2.4]; )
-// CHECK: Predecessors (2): B3 B11
-// CHECK: Successors (2): B10 B1
-// CHECK: [ B3 ]
-// CHECK: 1: [B2.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B4 B7
-// CHECK: Successors (1): B2
-// CHECK: [ B4 ]
-// CHECK: 1:
-// CHECK: 2: A e;
-// CHECK: 3: [B4.2].~A() (Implicit destructor)
-// CHECK: 4: [B10.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (1): B3
-// CHECK: [ B5 ]
-// CHECK: 1: return;
-// CHECK: 2: [B10.2].~A() (Implicit destructor)
-// CHECK: 3: [B2.2].~A() (Implicit destructor)
-// CHECK: 4: [B11.4].~A() (Implicit destructor)
-// CHECK: 5: [B11.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (1): B0
-// CHECK: [ B6 ]
-// CHECK: 1: UV
-// CHECK: T: if [B6.1]
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (2): B5 B4
-// CHECK: [ B7 ]
-// CHECK: 1: [B10.2].~A() (Implicit destructor)
-// CHECK: T: continue;
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (1): B3
-// CHECK: [ B8 ]
-// CHECK: 1: UV
-// CHECK: T: if [B8.1]
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (2): B7 B6
-// CHECK: [ B9 ]
-// CHECK: 1: [B10.2].~A() (Implicit destructor)
-// CHECK: T: break;
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (1): B1
-// CHECK: [ B10 ]
-// CHECK: 1:
-// CHECK: 2: A d;
-// CHECK: 3: UV
-// CHECK: T: if [B10.3]
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (2): B9 B8
-// CHECK: [ B11 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: 3:
-// CHECK: 4: A b;
-// CHECK: Predecessors (1): B12
-// CHECK: Successors (1): B2
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (2): B1 B5
-// CHECK: Successors (0):
-// CHECK: [ B3 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B0
-// CHECK: [ B1 ]
-// CHECK: T: try ...
-// CHECK: Predecessors (0):
-// CHECK: Successors (2): B2 B0
-// CHECK: [ B2 ]
-// CHECK: catch (const A &e):
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (3): B2 B1 B3
-// CHECK: Successors (0):
-// CHECK: [ B3 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B0
-// CHECK: [ B1 ]
-// CHECK: T: try ...
-// CHECK: Predecessors (0):
-// CHECK: Successors (2): B2 B0
-// CHECK: [ B2 ]
-// CHECK: catch (A e):
-// CHECK: 1: .~A() (Implicit destructor)
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (3): B2 B1 B3
-// CHECK: Successors (0):
+// CHECK: [ B2 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B1
+// CHECK: [ B1 ]
+// CHECK: 1:
+// CHECK: 2: A a;
+// CHECK: 3: a
+// CHECK: 4: [B1.3]
+// CHECK: 5: const A &b = a;
+// CHECK: 6: A()
+// CHECK: 7: [B1.6] (BindTemporary)
+// CHECK: 8: [B1.7]
+// CHECK: 9: [B1.8]
+// CHECK: 10: const A &c = A();
+// CHECK: 11: [B1.10].~A() (Implicit destructor)
+// CHECK: 12: [B1.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (1): B0
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B2 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B1
+// CHECK: [ B1 ]
+// CHECK: 1:
+// CHECK: 2: A a[2];
+// CHECK: 3:
+// CHECK: 4: A b[0];
+// CHECK: 5: [B1.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (1): B0
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B2 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B1
+// CHECK: [ B1 ]
+// CHECK: 1:
+// CHECK: 2: A a;
+// CHECK: 3:
+// CHECK: 4: A c;
+// CHECK: 5:
+// CHECK: 6: A d;
+// CHECK: 7: [B1.6].~A() (Implicit destructor)
+// CHECK: 8: [B1.4].~A() (Implicit destructor)
+// CHECK: 9:
+// CHECK: 10: A b;
+// CHECK: 11: [B1.10].~A() (Implicit destructor)
+// CHECK: 12: [B1.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (1): B0
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B4 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B3
+// CHECK: [ B1 ]
+// CHECK: 1:
+// CHECK: 2: A c;
+// CHECK: 3: [B1.2].~A() (Implicit destructor)
+// CHECK: 4: [B3.4].~A() (Implicit destructor)
+// CHECK: 5: [B3.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B3
+// CHECK: Successors (1): B0
+// CHECK: [ B2 ]
+// CHECK: 1: return;
+// CHECK: 2: [B3.4].~A() (Implicit destructor)
+// CHECK: 3: [B3.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B3
+// CHECK: Successors (1): B0
+// CHECK: [ B3 ]
+// CHECK: 1:
+// CHECK: 2: A a;
+// CHECK: 3:
+// CHECK: 4: A b;
+// CHECK: 5: UV
+// CHECK: 6: [B3.5]
+// CHECK: T: if [B3.6]
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (2): B2 B1
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (2): B1 B2
+// CHECK: Successors (0):
+// CHECK: [ B8 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B7
+// CHECK: [ B1 ]
+// CHECK: l1:
+// CHECK: 1:
+// CHECK: 2: A c;
+// CHECK: 3: [B1.2].~A() (Implicit destructor)
+// CHECK: 4: [B6.2].~A() (Implicit destructor)
+// CHECK: 5: [B7.2].~A() (Implicit destructor)
+// CHECK: Predecessors (2): B2 B3
+// CHECK: Successors (1): B0
+// CHECK: [ B2 ]
+// CHECK: 1:
+// CHECK: 2: A b;
+// CHECK: 3: [B2.2].~A() (Implicit destructor)
+// CHECK: 4: [B6.4].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B1
+// CHECK: [ B3 ]
+// CHECK: 1: [B6.4].~A() (Implicit destructor)
+// CHECK: T: goto l1;
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B1
+// CHECK: [ B4 ]
+// CHECK: 1: UV
+// CHECK: 2: [B4.1]
+// CHECK: T: if [B4.2]
+// CHECK: Predecessors (1): B6
+// CHECK: Successors (2): B3 B2
+// CHECK: [ B5 ]
+// CHECK: 1: [B6.4].~A() (Implicit destructor)
+// CHECK: 2: [B6.2].~A() (Implicit destructor)
+// CHECK: T: goto l0;
+// CHECK: Predecessors (1): B6
+// CHECK: Successors (1): B6
+// CHECK: [ B6 ]
+// CHECK: l0:
+// CHECK: 1:
+// CHECK: 2: A b;
+// CHECK: 3:
+// CHECK: 4: A a;
+// CHECK: 5: UV
+// CHECK: 6: [B6.5]
+// CHECK: T: if [B6.6]
+// CHECK: Predecessors (2): B7 B5
+// CHECK: Successors (2): B5 B4
+// CHECK: [ B7 ]
+// CHECK: 1:
+// CHECK: 2: A a;
+// CHECK: Predecessors (1): B8
+// CHECK: Successors (1): B6
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B5 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B4
+// CHECK: [ B1 ]
+// CHECK: 1: [B4.6].~A() (Implicit destructor)
+// CHECK: 2: [B4.2].~A() (Implicit destructor)
+// CHECK: Predecessors (2): B2 B3
+// CHECK: Successors (1): B0
+// CHECK: [ B2 ]
+// CHECK: 1:
+// CHECK: 2: A c;
+// CHECK: 3: [B2.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B1
+// CHECK: [ B3 ]
+// CHECK: 1:
+// CHECK: 2: A c;
+// CHECK: 3: [B3.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B1
+// CHECK: [ B4 ]
+// CHECK: 1:
+// CHECK: 2: A a;
+// CHECK: 3: a
+// CHECK: 4: [B4.3]
+// CHECK: 5: [B4.4]
+// CHECK: 6: A b = a;
+// CHECK: 7: b
+// CHECK: 8: [B4.7]
+// CHECK: 9: [B4.8].operator int
+// CHECK: 10: [B4.9]()
+// CHECK: 11: [B4.10]
+// CHECK: T: if [B4.11]
+// CHECK: Predecessors (1): B5
+// CHECK: Successors (2): B3 B2
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B9 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B8
+// CHECK: [ B1 ]
+// CHECK: 1: [B8.6].~A() (Implicit destructor)
+// CHECK: 2:
+// CHECK: 3: A e;
+// CHECK: 4: [B1.3].~A() (Implicit destructor)
+// CHECK: 5: [B8.2].~A() (Implicit destructor)
+// CHECK: Predecessors (2): B2 B5
+// CHECK: Successors (1): B0
+// CHECK: [ B2 ]
+// CHECK: 1:
+// CHECK: 2: A d;
+// CHECK: 3: [B2.2].~A() (Implicit destructor)
+// CHECK: 4: [B4.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B1
+// CHECK: [ B3 ]
+// CHECK: 1: return;
+// CHECK: 2: [B4.2].~A() (Implicit destructor)
+// CHECK: 3: [B8.6].~A() (Implicit destructor)
+// CHECK: 4: [B8.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B0
+// CHECK: [ B4 ]
+// CHECK: 1:
+// CHECK: 2: A c;
+// CHECK: 3: UV
+// CHECK: 4: [B4.3]
+// CHECK: T: if [B4.4]
+// CHECK: Predecessors (1): B8
+// CHECK: Successors (2): B3 B2
+// CHECK: [ B5 ]
+// CHECK: 1:
+// CHECK: 2: A d;
+// CHECK: 3: [B5.2].~A() (Implicit destructor)
+// CHECK: 4: [B7.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B7
+// CHECK: Successors (1): B1
+// CHECK: [ B6 ]
+// CHECK: 1: return;
+// CHECK: 2: [B7.2].~A() (Implicit destructor)
+// CHECK: 3: [B8.6].~A() (Implicit destructor)
+// CHECK: 4: [B8.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B7
+// CHECK: Successors (1): B0
+// CHECK: [ B7 ]
+// CHECK: 1:
+// CHECK: 2: A c;
+// CHECK: 3: UV
+// CHECK: 4: [B7.3]
+// CHECK: T: if [B7.4]
+// CHECK: Predecessors (1): B8
+// CHECK: Successors (2): B6 B5
+// CHECK: [ B8 ]
+// CHECK: 1:
+// CHECK: 2: A a;
+// CHECK: 3: a
+// CHECK: 4: [B8.3]
+// CHECK: 5: [B8.4]
+// CHECK: 6: A b = a;
+// CHECK: 7: b
+// CHECK: 8: [B8.7]
+// CHECK: 9: [B8.8].operator int
+// CHECK: 10: [B8.9]()
+// CHECK: 11: [B8.10]
+// CHECK: T: if [B8.11]
+// CHECK: Predecessors (1): B9
+// CHECK: Successors (2): B7 B4
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (3): B1 B3 B6
+// CHECK: Successors (0):
+// CHECK: [ B6 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B5
+// CHECK: [ B1 ]
+// CHECK: 1: [B2.4].~A() (Implicit destructor)
+// CHECK: 2: [B5.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (1): B0
+// CHECK: [ B2 ]
+// CHECK: 1: a
+// CHECK: 2: [B2.1]
+// CHECK: 3: [B2.2]
+// CHECK: 4: A b = a;
+// CHECK: 5: b
+// CHECK: 6: [B2.5]
+// CHECK: 7: [B2.6].operator int
+// CHECK: 8: [B2.7]()
+// CHECK: 9: [B2.8]
+// CHECK: T: while [B2.9]
+// CHECK: Predecessors (2): B3 B5
+// CHECK: Successors (2): B4 B1
+// CHECK: [ B3 ]
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B2
+// CHECK: [ B4 ]
+// CHECK: 1:
+// CHECK: 2: A c;
+// CHECK: 3: [B4.2].~A() (Implicit destructor)
+// CHECK: 4: [B2.4].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (1): B3
+// CHECK: [ B5 ]
+// CHECK: 1:
+// CHECK: 2: A a;
+// CHECK: Predecessors (1): B6
+// CHECK: Successors (1): B2
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B12 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B11
+// CHECK: [ B1 ]
+// CHECK: 1: [B2.4].~A() (Implicit destructor)
+// CHECK: 2:
+// CHECK: 3: A e;
+// CHECK: 4: [B1.3].~A() (Implicit destructor)
+// CHECK: 5: [B11.2].~A() (Implicit destructor)
+// CHECK: Predecessors (2): B9 B2
+// CHECK: Successors (1): B0
+// CHECK: [ B2 ]
+// CHECK: 1: a
+// CHECK: 2: [B2.1]
+// CHECK: 3: [B2.2]
+// CHECK: 4: A b = a;
+// CHECK: 5: b
+// CHECK: 6: [B2.5]
+// CHECK: 7: [B2.6].operator int
+// CHECK: 8: [B2.7]()
+// CHECK: 9: [B2.8]
+// CHECK: T: while [B2.9]
+// CHECK: Predecessors (2): B3 B11
+// CHECK: Successors (2): B10 B1
+// CHECK: [ B3 ]
+// CHECK: Predecessors (2): B4 B7
+// CHECK: Successors (1): B2
+// CHECK: [ B4 ]
+// CHECK: 1:
+// CHECK: 2: A d;
+// CHECK: 3: [B4.2].~A() (Implicit destructor)
+// CHECK: 4: [B10.2].~A() (Implicit destructor)
+// CHECK: 5: [B2.4].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B6
+// CHECK: Successors (1): B3
+// CHECK: [ B5 ]
+// CHECK: 1: return;
+// CHECK: 2: [B10.2].~A() (Implicit destructor)
+// CHECK: 3: [B2.4].~A() (Implicit destructor)
+// CHECK: 4: [B11.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B6
+// CHECK: Successors (1): B0
+// CHECK: [ B6 ]
+// CHECK: 1: UV
+// CHECK: 2: [B6.1]
+// CHECK: T: if [B6.2]
+// CHECK: Predecessors (1): B8
+// CHECK: Successors (2): B5 B4
+// CHECK: [ B7 ]
+// CHECK: 1: [B10.2].~A() (Implicit destructor)
+// CHECK: 2: [B2.4].~A() (Implicit destructor)
+// CHECK: T: continue;
+// CHECK: Predecessors (1): B8
+// CHECK: Successors (1): B3
+// CHECK: [ B8 ]
+// CHECK: 1: UV
+// CHECK: 2: [B8.1]
+// CHECK: T: if [B8.2]
+// CHECK: Predecessors (1): B10
+// CHECK: Successors (2): B7 B6
+// CHECK: [ B9 ]
+// CHECK: 1: [B10.2].~A() (Implicit destructor)
+// CHECK: T: break;
+// CHECK: Predecessors (1): B10
+// CHECK: Successors (1): B1
+// CHECK: [ B10 ]
+// CHECK: 1:
+// CHECK: 2: A c;
+// CHECK: 3: UV
+// CHECK: 4: [B10.3]
+// CHECK: T: if [B10.4]
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (2): B9 B8
+// CHECK: [ B11 ]
+// CHECK: 1:
+// CHECK: 2: A a;
+// CHECK: Predecessors (1): B12
+// CHECK: Successors (1): B2
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (2): B1 B5
+// CHECK: Successors (0):
+// CHECK: [ B4 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B2
+// CHECK: [ B1 ]
+// CHECK: 1: UV
+// CHECK: 2: [B1.1]
+// CHECK: T: do ... while [B1.2]
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (2): B3 B0
+// CHECK: [ B2 ]
+// CHECK: 1:
+// CHECK: 2: A a;
+// CHECK: 3: [B2.2].~A() (Implicit destructor)
+// CHECK: Predecessors (2): B3 B4
+// CHECK: Successors (1): B1
+// CHECK: [ B3 ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (1): B2
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B12 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B11
+// CHECK: [ B1 ]
+// CHECK: 1:
+// CHECK: 2: A d;
+// CHECK: 3: [B1.2].~A() (Implicit destructor)
+// CHECK: 4: [B11.2].~A() (Implicit destructor)
+// CHECK: Predecessors (2): B8 B2
+// CHECK: Successors (1): B0
+// CHECK: [ B2 ]
+// CHECK: 1: UV
+// CHECK: 2: [B2.1]
+// CHECK: T: do ... while [B2.2]
+// CHECK: Predecessors (2): B3 B6
+// CHECK: Successors (2): B10 B1
+// CHECK: [ B3 ]
+// CHECK: 1:
+// CHECK: 2: A c;
+// CHECK: 3: [B3.2].~A() (Implicit destructor)
+// CHECK: 4: [B9.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B5
+// CHECK: Successors (1): B2
+// CHECK: [ B4 ]
+// CHECK: 1: return;
+// CHECK: 2: [B9.2].~A() (Implicit destructor)
+// CHECK: 3: [B11.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B5
+// CHECK: Successors (1): B0
+// CHECK: [ B5 ]
+// CHECK: 1: UV
+// CHECK: 2: [B5.1]
+// CHECK: T: if [B5.2]
+// CHECK: Predecessors (1): B7
+// CHECK: Successors (2): B4 B3
+// CHECK: [ B6 ]
+// CHECK: 1: [B9.2].~A() (Implicit destructor)
+// CHECK: T: continue;
+// CHECK: Predecessors (1): B7
+// CHECK: Successors (1): B2
+// CHECK: [ B7 ]
+// CHECK: 1: UV
+// CHECK: 2: [B7.1]
+// CHECK: T: if [B7.2]
+// CHECK: Predecessors (1): B9
+// CHECK: Successors (2): B6 B5
+// CHECK: [ B8 ]
+// CHECK: 1: [B9.2].~A() (Implicit destructor)
+// CHECK: T: break;
+// CHECK: Predecessors (1): B9
+// CHECK: Successors (1): B1
+// CHECK: [ B9 ]
+// CHECK: 1:
+// CHECK: 2: A b;
+// CHECK: 3: UV
+// CHECK: 4: [B9.3]
+// CHECK: T: if [B9.4]
+// CHECK: Predecessors (2): B10 B11
+// CHECK: Successors (2): B8 B7
+// CHECK: [ B10 ]
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (1): B9
+// CHECK: [ B11 ]
+// CHECK: 1:
+// CHECK: 2: A a;
+// CHECK: Predecessors (1): B12
+// CHECK: Successors (1): B9
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (2): B1 B4
+// CHECK: Successors (0):
+// CHECK: [ B4 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B2
+// CHECK: [ B1 ]
+// CHECK: 1: [B2.6].~A() (Implicit destructor)
+// CHECK: 2: [B2.2].~A() (Implicit destructor)
+// CHECK: Predecessors (2): B3 B2
+// CHECK: Successors (1): B0
+// CHECK: [ B2 ]
+// CHECK: 1:
+// CHECK: 2: A a;
+// CHECK: 3: a
+// CHECK: 4: [B2.3]
+// CHECK: 5: [B2.4]
+// CHECK: 6: A b = a;
+// CHECK: 7: b
+// CHECK: 8: [B2.7]
+// CHECK: 9: [B2.8].operator int
+// CHECK: 10: [B2.9]()
+// CHECK: T: switch [B2.10]
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B1
+// CHECK: [ B3 ]
+// CHECK: 1:
+// CHECK: 2: A c;
+// CHECK: 3: [B3.2].~A() (Implicit destructor)
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B1
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B9 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B2
+// CHECK: [ B1 ]
+// CHECK: 1: [B2.6].~A() (Implicit destructor)
+// CHECK: 2:
+// CHECK: 3: A g;
+// CHECK: 4: [B1.3].~A() (Implicit destructor)
+// CHECK: 5: [B2.2].~A() (Implicit destructor)
+// CHECK: Predecessors (3): B3 B7 B2
+// CHECK: Successors (1): B0
+// CHECK: [ B2 ]
+// CHECK: 1:
+// CHECK: 2: A a;
+// CHECK: 3: a
+// CHECK: 4: [B2.3]
+// CHECK: 5: [B2.4]
+// CHECK: 6: A b = a;
+// CHECK: 7: b
+// CHECK: 8: [B2.7]
+// CHECK: 9: [B2.8].operator int
+// CHECK: 10: [B2.9]()
+// CHECK: T: switch [B2.10]
+// CHECK: Predecessors (1): B9
+// CHECK: Successors (3): B3 B8
+// CHECK: B1
+// CHECK: [ B3 ]
+// CHECK: case 1:
+// CHECK: T: break;
+// CHECK: Predecessors (2): B2 B4
+// CHECK: Successors (1): B1
+// CHECK: [ B4 ]
+// CHECK: 1:
+// CHECK: 2: A f;
+// CHECK: 3: [B4.2].~A() (Implicit destructor)
+// CHECK: 4: [B8.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B6
+// CHECK: Successors (1): B3
+// CHECK: [ B5 ]
+// CHECK: 1: return;
+// CHECK: 2: [B8.2].~A() (Implicit destructor)
+// CHECK: 3: [B2.6].~A() (Implicit destructor)
+// CHECK: 4: [B2.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B6
+// CHECK: Successors (1): B0
+// CHECK: [ B6 ]
+// CHECK: 1: UV
+// CHECK: 2: [B6.1]
+// CHECK: T: if [B6.2]
+// CHECK: Predecessors (1): B8
+// CHECK: Successors (2): B5 B4
+// CHECK: [ B7 ]
+// CHECK: 1: [B8.2].~A() (Implicit destructor)
+// CHECK: T: break;
+// CHECK: Predecessors (1): B8
+// CHECK: Successors (1): B1
+// CHECK: [ B8 ]
+// CHECK: case 0:
+// CHECK: 1:
+// CHECK: 2: A c;
+// CHECK: 3: UV
+// CHECK: 4: [B8.3]
+// CHECK: T: if [B8.4]
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (2): B7 B6
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (2): B1 B5
+// CHECK: Successors (0):
+// CHECK: [ B6 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B5
+// CHECK: [ B1 ]
+// CHECK: 1: [B2.4].~A() (Implicit destructor)
+// CHECK: 2: [B5.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (1): B0
+// CHECK: [ B2 ]
+// CHECK: 1: a
+// CHECK: 2: [B2.1]
+// CHECK: 3: [B2.2]
+// CHECK: 4: A b = a;
+// CHECK: 5: b
+// CHECK: 6: [B2.5]
+// CHECK: 7: [B2.6].operator int
+// CHECK: 8: [B2.7]()
+// CHECK: 9: [B2.8]
+// CHECK: T: for (...; [B2.9]; )
+// CHECK: Predecessors (2): B3 B5
+// CHECK: Successors (2): B4 B1
+// CHECK: [ B3 ]
+// CHECK: 1: [B2.4].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B2
+// CHECK: [ B4 ]
+// CHECK: 1:
+// CHECK: 2: A c;
+// CHECK: 3: [B4.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (1): B3
+// CHECK: [ B5 ]
+// CHECK: 1:
+// CHECK: 2: A a;
+// CHECK: Predecessors (1): B6
+// CHECK: Successors (1): B2
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B12 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B11
+// CHECK: [ B1 ]
+// CHECK: 1: [B2.4].~A() (Implicit destructor)
+// CHECK: 2: [B11.4].~A() (Implicit destructor)
+// CHECK: 3:
+// CHECK: 4: A f;
+// CHECK: 5: [B1.4].~A() (Implicit destructor)
+// CHECK: 6: [B11.2].~A() (Implicit destructor)
+// CHECK: Predecessors (2): B9 B2
+// CHECK: Successors (1): B0
+// CHECK: [ B2 ]
+// CHECK: 1: b
+// CHECK: 2: [B2.1]
+// CHECK: 3: [B2.2]
+// CHECK: 4: A c = b;
+// CHECK: 5: c
+// CHECK: 6: [B2.5]
+// CHECK: 7: [B2.6].operator int
+// CHECK: 8: [B2.7]()
+// CHECK: 9: [B2.8]
+// CHECK: T: for (...; [B2.9]; )
+// CHECK: Predecessors (2): B3 B11
+// CHECK: Successors (2): B10 B1
+// CHECK: [ B3 ]
+// CHECK: 1: [B2.4].~A() (Implicit destructor)
+// CHECK: Predecessors (2): B4 B7
+// CHECK: Successors (1): B2
+// CHECK: [ B4 ]
+// CHECK: 1:
+// CHECK: 2: A e;
+// CHECK: 3: [B4.2].~A() (Implicit destructor)
+// CHECK: 4: [B10.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B6
+// CHECK: Successors (1): B3
+// CHECK: [ B5 ]
+// CHECK: 1: return;
+// CHECK: 2: [B10.2].~A() (Implicit destructor)
+// CHECK: 3: [B2.4].~A() (Implicit destructor)
+// CHECK: 4: [B11.4].~A() (Implicit destructor)
+// CHECK: 5: [B11.2].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B6
+// CHECK: Successors (1): B0
+// CHECK: [ B6 ]
+// CHECK: 1: UV
+// CHECK: 2: [B6.1]
+// CHECK: T: if [B6.2]
+// CHECK: Predecessors (1): B8
+// CHECK: Successors (2): B5 B4
+// CHECK: [ B7 ]
+// CHECK: 1: [B10.2].~A() (Implicit destructor)
+// CHECK: T: continue;
+// CHECK: Predecessors (1): B8
+// CHECK: Successors (1): B3
+// CHECK: [ B8 ]
+// CHECK: 1: UV
+// CHECK: 2: [B8.1]
+// CHECK: T: if [B8.2]
+// CHECK: Predecessors (1): B10
+// CHECK: Successors (2): B7 B6
+// CHECK: [ B9 ]
+// CHECK: 1: [B10.2].~A() (Implicit destructor)
+// CHECK: T: break;
+// CHECK: Predecessors (1): B10
+// CHECK: Successors (1): B1
+// CHECK: [ B10 ]
+// CHECK: 1:
+// CHECK: 2: A d;
+// CHECK: 3: UV
+// CHECK: 4: [B10.3]
+// CHECK: T: if [B10.4]
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (2): B9 B8
+// CHECK: [ B11 ]
+// CHECK: 1:
+// CHECK: 2: A a;
+// CHECK: 3:
+// CHECK: 4: A b;
+// CHECK: Predecessors (1): B12
+// CHECK: Successors (1): B2
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (2): B1 B5
+// CHECK: Successors (0):
+// CHECK: [ B3 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B0
+// CHECK: [ B1 ]
+// CHECK: T: try ...
+// CHECK: Predecessors (0):
+// CHECK: Successors (2): B2 B0
+// CHECK: [ B2 ]
+// CHECK: catch (const A &e):
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (1): B0
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (3): B2 B1 B3
+// CHECK: Successors (0):
+// CHECK: [ B3 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B0
+// CHECK: [ B1 ]
+// CHECK: T: try ...
+// CHECK: Predecessors (0):
+// CHECK: Successors (2): B2 B0
+// CHECK: [ B2 ]
+// CHECK: catch (A e):
+// CHECK: 1: .~A() (Implicit destructor)
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (1): B0
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (3): B2 B1 B3
+// CHECK: Successors (0):
diff --git a/test/Analysis/bstring.c b/test/Analysis/bstring.c
index cd43e36d0351..e23059fcec48 100644
--- a/test/Analysis/bstring.c
+++ b/test/Analysis/bstring.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.unix.CString -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,experimental.unix.CString -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,experimental.unix.CString -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,experimental.unix.CString -analyzer-store=region -Wno-null-dereference -verify %s
//===----------------------------------------------------------------------===
// Declarations
diff --git a/test/Analysis/casts.c b/test/Analysis/casts.c
index 35d97fec675d..8b88a2db432e 100644
--- a/test/Analysis/casts.c
+++ b/test/Analysis/casts.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
// Test if the 'storage' region gets properly initialized after it is cast to
// 'struct sockaddr *'.
diff --git a/test/Analysis/casts.m b/test/Analysis/casts.m
index d073dff963fc..d9700fe5c754 100644
--- a/test/Analysis/casts.m
+++ b/test/Analysis/casts.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
// Test function pointer casts. Currently we track function addresses using
// loc::FunctionVal. Because casts can be arbitrary, do we need to model
@@ -20,3 +19,23 @@ void* test2(void *p) {
MyFuncTest1 fp = (MyFuncTest1) p;
return (*fp)();
}
+
+// <radar://10087620>
+// A cast from int onjective C property reference to int.
+typedef signed char BOOL;
+@protocol NSObject - (BOOL)isEqual:(id)object; @end
+@interface NSObject <NSObject> {} - (id)init; @end
+typedef enum {
+ EEOne,
+ EETwo
+} RDR10087620Enum;
+@interface RDR10087620 : NSObject {
+ RDR10087620Enum elem;
+}
+@property (readwrite, nonatomic) RDR10087620Enum elem;
+static void
+adium_media_ready_cb(RDR10087620 *InObj)
+{
+ InObj.elem |= EEOne;
+}
+@end \ No newline at end of file
diff --git a/test/Analysis/cfref_PR2519.c b/test/Analysis/cfref_PR2519.c
index 280676330a46..529210986916 100644
--- a/test/Analysis/cfref_PR2519.c
+++ b/test/Analysis/cfref_PR2519.c
@@ -1,7 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
typedef unsigned char Boolean;
typedef signed long CFIndex;
diff --git a/test/Analysis/cfref_rdar6080742.c b/test/Analysis/cfref_rdar6080742.c
index aceefbe54872..ea4c3ee6d549 100644
--- a/test/Analysis/cfref_rdar6080742.c
+++ b/test/Analysis/cfref_rdar6080742.c
@@ -1,7 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
// This test case was reported in <rdar:problem/6080742>.
// It tests path-sensitivity with respect to '!(cfstring != 0)' (negation of inequality).
diff --git a/test/Analysis/chroot.c b/test/Analysis/chroot.c
index 7a584da6c05c..1948f48471f1 100644
--- a/test/Analysis/chroot.c
+++ b/test/Analysis/chroot.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=unix.experimental.Chroot -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.unix.Chroot -analyzer-store region -verify %s
extern int chroot(const char* path);
extern int chdir(const char* path);
diff --git a/test/Analysis/complex.c b/test/Analysis/complex.c
index b125a502f1df..c118a61455af 100644
--- a/test/Analysis/complex.c
+++ b/test/Analysis/complex.c
@@ -1,5 +1,3 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -analyzer-constraints=basic -verify -Wno-unreachable-code -ffreestanding %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -analyzer-constraints=range -verify -Wno-unreachable-code -ffreestanding %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=basic -verify -Wno-unreachable-code -ffreestanding %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=range -verify -Wno-unreachable-code -ffreestanding %s
diff --git a/test/Analysis/concrete-address.c b/test/Analysis/concrete-address.c
index a722ab092e2c..f6c445ebf56e 100644
--- a/test/Analysis/concrete-address.c
+++ b/test/Analysis/concrete-address.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
void foo() {
int *p = (int*) 0x10000; // Should not crash here.
diff --git a/test/Analysis/constant-folding.c b/test/Analysis/constant-folding.c
index d3cbf9c56479..e7a5705fa59a 100644
--- a/test/Analysis/constant-folding.c
+++ b/test/Analysis/constant-folding.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.experimental.UnreachableCode -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode -Wno-null-dereference -verify %s
// Trigger a warning if the analyzer reaches this point in the control flow.
#define WARN ((void)*(char*)0)
diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c
index 85ea1ee2cb64..5ddb4528c1b2 100644
--- a/test/Analysis/dead-stores.c
+++ b/test/Analysis/dead-stores.c
@@ -1,6 +1,4 @@
// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,deadcode.IdempotentOperations -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,deadcode.IdempotentOperations -analyzer-store=basic -analyzer-constraints=basic -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,deadcode.IdempotentOperations -analyzer-store=basic -analyzer-constraints=range -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,deadcode.IdempotentOperations -analyzer-store=region -analyzer-constraints=basic -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,deadcode.IdempotentOperations -analyzer-store=region -analyzer-constraints=range -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
diff --git a/test/Analysis/dead-stores.cpp b/test/Analysis/dead-stores.cpp
index 932e94092847..43d8796ce091 100644
--- a/test/Analysis/dead-stores.cpp
+++ b/test/Analysis/dead-stores.cpp
@@ -1,6 +1,4 @@
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-store=basic -analyzer-constraints=basic -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-store=basic -analyzer-constraints=range -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-store=region -analyzer-constraints=basic -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-store=region -analyzer-constraints=range -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
diff --git a/test/Analysis/dead-stores.m b/test/Analysis/dead-stores.m
index 3a06a8adeb0d..4ed71c4e8bfa 100644
--- a/test/Analysis/dead-stores.m
+++ b/test/Analysis/dead-stores.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-checker=deadcode.DeadStores -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core -analyzer-checker=deadcode.DeadStores,osx.cocoa.RetainCount -verify %s
typedef signed char BOOL;
typedef unsigned int NSUInteger;
diff --git a/test/Analysis/default-diagnostic-visitors.c b/test/Analysis/default-diagnostic-visitors.c
new file mode 100644
index 000000000000..9cb9ba8c33e3
--- /dev/null
+++ b/test/Analysis/default-diagnostic-visitors.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-output=text -verify %s
+
+// This file is for testing enhanced diagnostics produced by the default BugReporterVisitors.
+
+int getPasswordAndItem()
+{
+ int err = 0;
+ int *password; // expected-note {{Variable '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;
+ }
+ return err;
+}
diff --git a/test/Analysis/delegates.m b/test/Analysis/delegates.m
index 218083598919..8f42b83b0eeb 100644
--- a/test/Analysis/delegates.m
+++ b/test/Analysis/delegates.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -verify %s
//===----------------------------------------------------------------------===//
diff --git a/test/Analysis/div-zero.cpp b/test/Analysis/div-zero.cpp
new file mode 100644
index 000000000000..d1261dc57335
--- /dev/null
+++ b/test/Analysis/div-zero.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core.DivideZero -verify %s
+
+int fooPR10616 (int qX ) {
+ int a, c, d;
+
+ d = (qX-1);
+ while ( d != 0 ) {
+ d = c - (c/d) * d;
+ }
+
+ return (a % (qX-1)); // expected-warning {{Division by zero}}
+
+}
diff --git a/test/Analysis/elementtype.c b/test/Analysis/elementtype.c
index d41202a1f07f..7452a0a124fe 100644
--- a/test/Analysis/elementtype.c
+++ b/test/Analysis/elementtype.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region %s
typedef struct added_obj_st {
int type;
diff --git a/test/Analysis/exercise-ps.c b/test/Analysis/exercise-ps.c
index 02772a148b6b..5dd1f3f12bd2 100644
--- a/test/Analysis/exercise-ps.c
+++ b/test/Analysis/exercise-ps.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
//
// Just exercise the analyzer on code that has at one point caused issues
// (i.e., no assertions or crashes).
diff --git a/test/Analysis/fields.c b/test/Analysis/fields.c
index 0991d00868cf..2e72c77d9fac 100644
--- a/test/Analysis/fields.c
+++ b/test/Analysis/fields.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental %s -analyzer-store=basic -verify
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental %s -analyzer-store=region -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core %s -analyzer-store=region -verify
unsigned foo();
typedef struct bf { unsigned x:2; } bf;
diff --git a/test/Analysis/flat-store.c b/test/Analysis/flat-store.c
deleted file mode 100644
index bf93c724400f..000000000000
--- a/test/Analysis/flat-store.c
+++ /dev/null
@@ -1,11 +0,0 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=flat -Wno-null-dereference -verify %s
-#define FAIL ((void)*(char*)0)
-struct simple { int x; };
-
-void PR7297 () {
- struct simple a;
- struct simple *p = &a;
- p->x = 5;
- if (!p[0].x) FAIL; // no-warning
- if (p[0].x) FAIL; // expected-warning {{null}}
-}
diff --git a/test/Analysis/free.c b/test/Analysis/free.c
index d57da69ba456..44c4f19f1b3c 100644
--- a/test/Analysis/free.c
+++ b/test/Analysis/free.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,unix.experimental.Malloc -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,experimental.unix.Malloc -fblocks -verify %s
void free(void *);
void t1 () {
diff --git a/test/Analysis/func.c b/test/Analysis/func.c
index 0694f7bd4c26..b6cebde81091 100644
--- a/test/Analysis/func.c
+++ b/test/Analysis/func.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
void f(void) {
void (*p)(void);
diff --git a/test/Analysis/idempotent-operations.m b/test/Analysis/idempotent-operations.m
index 8f534940c975..b4765082d84a 100644
--- a/test/Analysis/idempotent-operations.m
+++ b/test/Analysis/idempotent-operations.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=deadcode.IdempotentOperations -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=deadcode.IdempotentOperations,osx.cocoa.RetainCount -verify %s
typedef signed char BOOL;
typedef unsigned long NSUInteger;
diff --git a/test/Analysis/initializers-cfg-output.cpp b/test/Analysis/initializers-cfg-output.cpp
index 5c5d51494749..b73809f2b83a 100644
--- a/test/Analysis/initializers-cfg-output.cpp
+++ b/test/Analysis/initializers-cfg-output.cpp
@@ -44,51 +44,60 @@ TestControlFlow::TestControlFlow(bool b)
int v;
}
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1:
-// CHECK: 2: A([B1.1]) (Base initializer)
-// CHECK: 3:
-// CHECK: 4: C([B1.3]) (Base initializer)
-// CHECK: 5:
-// CHECK: 6: B([B1.5]) (Base initializer)
-// CHECK: 7:
-// CHECK: 8: A([B1.7]) (Base initializer)
-// CHECK: 9: i(/*implicit*/int()) (Member initializer)
-// CHECK: 10: r(this->i) (Member initializer)
-// CHECK: 11:
-// CHECK: 12: A a;
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B5 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B4
-// CHECK: [ B1 ]
-// CHECK: 1: [B4.2] ? [B2.1] : [B3.1]
-// CHECK: 2: y([B1.1]) (Member initializer)
-// CHECK: 3: z(this->y) (Member initializer)
-// CHECK: 4: int v;
-// CHECK: Predecessors (2): B2 B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: 0
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1: 1
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B4 ]
-// CHECK: 1: x(0) (Member initializer)
-// CHECK: 2: b
-// CHECK: T: [B4.2] ? ... : ...
-// CHECK: Predecessors (1): B5
-// CHECK: Successors (2): B2 B3
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
+// CHECK: [ B2 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B1
+// CHECK: [ B1 ]
+// CHECK: 1:
+// CHECK: 2: A([B1.1]) (Base initializer)
+// CHECK: 3:
+// CHECK: 4: C([B1.3]) (Base initializer)
+// CHECK: 5:
+// CHECK: 6: B([B1.5]) (Base initializer)
+// CHECK: 7:
+// CHECK: 8: A([B1.7]) (Base initializer)
+// CHECK: 9: /*implicit*/int()
+// CHECK: 10: i([B1.9]) (Member initializer)
+// CHECK: 11: this
+// CHECK: 12: [B1.11]->i
+// CHECK: 13: r([B1.12]) (Member initializer)
+// CHECK: 14:
+// CHECK: 15: A a;
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (1): B0
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B5 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B4
+// CHECK: [ B1 ]
+// CHECK: 1: [B4.4] ? [B2.1] : [B3.1]
+// CHECK: 2: y([B1.1]) (Member initializer)
+// CHECK: 3: this
+// CHECK: 4: [B1.3]->y
+// CHECK: 5: [B1.4]
+// CHECK: 6: z([B1.5]) (Member initializer)
+// CHECK: 7: int v;
+// CHECK: Predecessors (2): B2 B3
+// CHECK: Successors (1): B0
+// CHECK: [ B2 ]
+// CHECK: 1: 0
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B1
+// CHECK: [ B3 ]
+// CHECK: 1: 1
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B1
+// CHECK: [ B4 ]
+// CHECK: 1: 0
+// CHECK: 2: x([B4.1]) (Member initializer)
+// CHECK: 3: b
+// CHECK: 4: [B4.3]
+// CHECK: T: [B4.4] ? ... : ...
+// CHECK: Predecessors (1): B5
+// CHECK: Successors (2): B2 B3
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+
diff --git a/test/Analysis/iterators.cpp b/test/Analysis/iterators.cpp
index c3416f5beac1..741970aa6c47 100644
--- a/test/Analysis/iterators.cpp
+++ b/test/Analysis/iterators.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.experimental.Iterators -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.cplusplus.Iterators -verify %s
// XFAIL: win32
#include <vector>
diff --git a/test/Analysis/keychainAPI-diagnostic-visitor.m b/test/Analysis/keychainAPI-diagnostic-visitor.m
new file mode 100644
index 000000000000..a78b114a00fb
--- /dev/null
+++ b/test/Analysis/keychainAPI-diagnostic-visitor.m
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=osx.SecKeychainAPI -analyzer-store=region -analyzer-output=text -verify %s
+
+// This file is for testing enhanced diagnostics produced by the default SecKeychainAPI checker.
+
+typedef unsigned int OSStatus;
+typedef unsigned int SecKeychainAttributeList;
+typedef unsigned int SecKeychainItemRef;
+typedef unsigned int SecItemClass;
+typedef unsigned int UInt32;
+enum {
+ noErr = 0,
+ GenericError = 1
+};
+OSStatus SecKeychainItemCopyContent (
+ SecKeychainItemRef itemRef,
+ SecItemClass *itemClass,
+ SecKeychainAttributeList *attrList,
+ UInt32 *length,
+ void **outData
+ );
+
+void DellocWithCFStringCreate4() {
+ unsigned int *ptr = 0;
+ OSStatus st = 0;
+ UInt32 length;
+ char *bytes;
+ char *x;
+ st = SecKeychainItemCopyContent(2, ptr, ptr, &length, (void **)&bytes); // expected-note {{Data is allocated here}}
+ x = bytes;
+ if (st == noErr) // expected-note {{Assuming 'st' is equal to noErr}} // expected-note{{Taking true branch}}
+ x = bytes;;
+
+ length++; // expected-warning {{Allocated data is not released}} // expected-note{{Allocated data is not released}}
+}
+
diff --git a/test/Analysis/keychainAPI.m b/test/Analysis/keychainAPI.m
new file mode 100644
index 000000000000..d10600dea590
--- /dev/null
+++ b/test/Analysis/keychainAPI.m
@@ -0,0 +1,323 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=osx.SecKeychainAPI %s -verify
+
+// Fake typedefs.
+typedef unsigned int OSStatus;
+typedef unsigned int SecKeychainAttributeList;
+typedef unsigned int SecKeychainItemRef;
+typedef unsigned int SecItemClass;
+typedef unsigned int UInt32;
+typedef unsigned int CFTypeRef;
+typedef unsigned int UInt16;
+typedef unsigned int SecProtocolType;
+typedef unsigned int SecAuthenticationType;
+typedef unsigned int SecKeychainAttributeInfo;
+enum {
+ noErr = 0,
+ GenericError = 1
+};
+
+// Functions that allocate data.
+OSStatus SecKeychainItemCopyContent (
+ SecKeychainItemRef itemRef,
+ SecItemClass *itemClass,
+ SecKeychainAttributeList *attrList,
+ UInt32 *length,
+ void **outData
+);
+OSStatus SecKeychainFindGenericPassword (
+ CFTypeRef keychainOrArray,
+ UInt32 serviceNameLength,
+ const char *serviceName,
+ UInt32 accountNameLength,
+ const char *accountName,
+ UInt32 *passwordLength,
+ void **passwordData,
+ SecKeychainItemRef *itemRef
+);
+OSStatus SecKeychainFindInternetPassword (
+ CFTypeRef keychainOrArray,
+ UInt32 serverNameLength,
+ const char *serverName,
+ UInt32 securityDomainLength,
+ const char *securityDomain,
+ UInt32 accountNameLength,
+ const char *accountName,
+ UInt32 pathLength,
+ const char *path,
+ UInt16 port,
+ SecProtocolType protocol,
+ SecAuthenticationType authenticationType,
+ UInt32 *passwordLength,
+ void **passwordData,
+ SecKeychainItemRef *itemRef
+);
+OSStatus SecKeychainItemCopyAttributesAndData (
+ SecKeychainItemRef itemRef,
+ SecKeychainAttributeInfo *info,
+ SecItemClass *itemClass,
+ SecKeychainAttributeList **attrList,
+ UInt32 *length,
+ void **outData
+);
+
+// Functions which free data.
+OSStatus SecKeychainItemFreeContent (
+ SecKeychainAttributeList *attrList,
+ void *data
+);
+OSStatus SecKeychainItemFreeAttributesAndData (
+ SecKeychainAttributeList *attrList,
+ void *data
+);
+
+void errRetVal() {
+ unsigned int *ptr = 0;
+ OSStatus st = 0;
+ 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'.}}
+ SecKeychainItemFreeContent(ptr, outData); // expected-warning{{Call to free data when error was returned during allocation.}}
+}
+
+// If null is passed in, the data is not allocated, so no need for the matching free.
+void fooDoNotReportNull() {
+ unsigned int *ptr = 0;
+ OSStatus st = 0;
+ UInt32 *length = 0;
+ void **outData = 0;
+ SecKeychainItemCopyContent(2, ptr, ptr, 0, 0);
+ SecKeychainItemCopyContent(2, ptr, ptr, length, outData);
+}// no-warning
+
+void doubleAlloc() {
+ unsigned int *ptr = 0;
+ OSStatus st = 0;
+ UInt32 length;
+ void *outData;
+ st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
+ st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); // expected-warning {{Allocated data should be released before another call to the allocator:}}
+ if (st == noErr)
+ SecKeychainItemFreeContent(ptr, outData);
+}
+
+void fooOnlyFree() {
+ unsigned int *ptr = 0;
+ OSStatus st = 0;
+ UInt32 length;
+ void *outData = &length;
+ SecKeychainItemFreeContent(ptr, outData);// expected-warning{{Trying to free data which has not been allocated}}
+}
+
+// Do not warn if undefined value is passed to a function.
+void fooOnlyFreeUndef() {
+ unsigned int *ptr = 0;
+ OSStatus st = 0;
+ UInt32 length;
+ void *outData;
+ SecKeychainItemFreeContent(ptr, outData);
+}// no-warning
+
+// Do not warn if the address is a parameter in the enclosing function.
+void fooOnlyFreeParam(void *attrList, void* X) {
+ SecKeychainItemFreeContent(attrList, X);
+}// no-warning
+
+// If we are returning the value, do not report.
+void* returnContent() {
+ unsigned int *ptr = 0;
+ OSStatus st = 0;
+ UInt32 length;
+ void *outData;
+ st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
+ return outData;
+} // no-warning
+
+// Password was passed in as an argument and does nt have to be deleted.
+OSStatus getPasswordAndItem(void** password, UInt32* passwordLength) {
+ OSStatus err;
+ SecKeychainItemRef item;
+ err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx",
+ passwordLength, password, &item);
+ return err;
+} // no-warning
+
+// Make sure we do not report an error if we call free only if password != 0.
+// Also, do not report double allocation if first allocation returned an error.
+OSStatus testSecKeychainFindGenericPassword(UInt32* passwordLength,
+ CFTypeRef keychainOrArray, SecProtocolType protocol,
+ SecAuthenticationType authenticationType) {
+ OSStatus err;
+ SecKeychainItemRef item;
+ void *password;
+ err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx",
+ passwordLength, &password, &item);
+ if( err == GenericError ) {
+ err = SecKeychainFindInternetPassword(keychainOrArray,
+ 16, "server", 16, "domain", 16, "account",
+ 16, "path", 222, protocol, authenticationType,
+ passwordLength, &(password), 0);
+ }
+
+ if (err == noErr && password) {
+ SecKeychainItemFreeContent(0, password);
+ }
+ return err;
+}
+
+int apiMismatch(SecKeychainItemRef itemRef,
+ SecKeychainAttributeInfo *info,
+ SecItemClass *itemClass) {
+ OSStatus st = 0;
+ SecKeychainAttributeList *attrList;
+ UInt32 length;
+ void *outData;
+
+ st = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass,
+ &attrList, &length, &outData);
+ if (st == noErr)
+ SecKeychainItemFreeContent(attrList, outData); // expected-warning{{Deallocator doesn't match the allocator}}
+ return 0;
+}
+
+int ErrorCodesFromDifferentAPISDoNotInterfere(SecKeychainItemRef itemRef,
+ SecKeychainAttributeInfo *info,
+ SecItemClass *itemClass) {
+ unsigned int *ptr = 0;
+ OSStatus st = 0;
+ UInt32 length;
+ void *outData;
+ OSStatus st2 = 0;
+ SecKeychainAttributeList *attrList;
+ UInt32 length2;
+ void *outData2;
+
+ st2 = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass,
+ &attrList, &length2, &outData2);
+ st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
+ if (st == noErr) {
+ SecKeychainItemFreeContent(ptr, outData);
+ if (st2 == noErr) {
+ SecKeychainItemFreeAttributesAndData(attrList, outData2);
+ }
+ }
+ return 0; // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeAttributesAndData'}}
+}
+
+int foo(CFTypeRef keychainOrArray, SecProtocolType protocol,
+ SecAuthenticationType authenticationType, SecKeychainItemRef *itemRef) {
+ unsigned int *ptr = 0;
+ OSStatus st = 0;
+
+ UInt32 length;
+ void *outData[5];
+
+ st = SecKeychainFindInternetPassword(keychainOrArray,
+ 16, "server", 16, "domain", 16, "account",
+ 16, "path", 222, protocol, authenticationType,
+ &length, &(outData[3]), itemRef);
+ if (length == 5) {
+ if (st == noErr)
+ SecKeychainItemFreeContent(ptr, outData[3]);
+ }
+ if (length) { // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'.}}
+ length++;
+ }
+ return 0;
+}// no-warning
+
+void free(void *ptr);
+void deallocateWithFree() {
+ unsigned int *ptr = 0;
+ OSStatus st = 0;
+ UInt32 length;
+ void *outData;
+ st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
+ if (st == noErr)
+ free(outData); // expected-warning{{Deallocator doesn't match the allocator: 'SecKeychainItemFreeContent' should be used}}
+}
+
+// Typesdefs for CFStringCreateWithBytesNoCopy.
+typedef char uint8_t;
+typedef signed long CFIndex;
+typedef UInt32 CFStringEncoding;
+typedef unsigned Boolean;
+typedef const struct __CFString * CFStringRef;
+typedef const struct __CFAllocator * CFAllocatorRef;
+extern const CFAllocatorRef kCFAllocatorDefault;
+extern const CFAllocatorRef kCFAllocatorSystemDefault;
+extern const CFAllocatorRef kCFAllocatorMalloc;
+extern const CFAllocatorRef kCFAllocatorMallocZone;
+extern const CFAllocatorRef kCFAllocatorNull;
+extern const CFAllocatorRef kCFAllocatorUseContext;
+CFStringRef CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, const uint8_t *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean externalFormat, CFAllocatorRef contentsDeallocator);
+extern void CFRelease(CFStringRef cf);
+
+void DellocWithCFStringCreate1(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) {
+ CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorDefault); // expected-warning{{Deallocator doesn't match the allocator:}}
+ CFRelease(userStr);
+ }
+}
+
+void DellocWithCFStringCreate2(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) {
+ CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorNull); // expected-warning{{Allocated data is not released}}
+ CFRelease(userStr);
+ }
+}
+
+void DellocWithCFStringCreate3(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) {
+ CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorUseContext);
+ CFRelease(userStr);
+ }
+}
+
+void DellocWithCFStringCreate4(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) {
+ CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, 0); // expected-warning{{Deallocator doesn't match the allocator:}}
+ CFRelease(userStr);
+ }
+}
+
+//Example from bug 10797.
+__inline__ static
+const char *__WBASLLevelString(int level) {
+ return "foo";
+}
+
+static int *bug10798(int *p, int columns, int prevRow) {
+ int *row = 0;
+ row = p + prevRow * columns;
+ prevRow += 2;
+ do {
+ ++prevRow;
+ row+=columns;
+ } while(10 >= row[1]);
+ return row;
+}
diff --git a/test/Analysis/malloc-overflow.c b/test/Analysis/malloc-overflow.c
new file mode 100644
index 000000000000..714fd3d308ad
--- /dev/null
+++ b/test/Analysis/malloc-overflow.c
@@ -0,0 +1,113 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.security.MallocOverflow -verify %s
+
+#define NULL ((void *) 0)
+typedef __typeof__(sizeof(int)) size_t;
+extern void * malloc(size_t);
+
+void * f1(int n)
+{
+ return malloc(n * sizeof(int)); // expected-warning {{the computation of the size of the memory allocation may overflow}}
+}
+
+void * f2(int n)
+{
+ return malloc(sizeof(int) * n); // // expected-warning {{the computation of the size of the memory allocation may overflow}}
+}
+
+void * f3()
+{
+ return malloc(4 * sizeof(int)); // no-warning
+}
+
+struct s4
+{
+ int n;
+};
+
+void * f4(struct s4 *s)
+{
+ return malloc(s->n * sizeof(int)); // expected-warning {{the computation of the size of the memory allocation may overflow}}
+}
+
+void * f5(struct s4 *s)
+{
+ struct s4 s2 = *s;
+ return malloc(s2.n * sizeof(int)); // expected-warning {{the computation of the size of the memory allocation may overflow}}
+}
+
+void * f6(int n)
+{
+ return malloc((n + 1) * sizeof(int)); // expected-warning {{the computation of the size of the memory allocation may overflow}}
+}
+
+extern void * malloc (size_t);
+
+void * f7(int n)
+{
+ if (n > 10)
+ return NULL;
+ return malloc(n * sizeof(int)); // no-warning
+}
+
+void * f8(int n)
+{
+ if (n < 10)
+ return malloc(n * sizeof(int)); // no-warning
+ else
+ return NULL;
+}
+
+void * f9(int n)
+{
+ int * x = malloc(n * sizeof(int)); // expected-warning {{the computation of the size of the memory allocation may overflow}}
+ for (int i = 0; i < n; i++)
+ x[i] = i;
+ return x;
+}
+
+void * f10(int n)
+{
+ int * x = malloc(n * sizeof(int)); // expected-warning {{the computation of the size of the memory allocation may overflow}}
+ int i = 0;
+ while (i < n)
+ x[i++] = 0;
+ return x;
+}
+
+void * f11(int n)
+{
+ int * x = malloc(n * sizeof(int)); // expected-warning {{the computation of the size of the memory allocation may overflow}}
+ int i = 0;
+ do {
+ x[i++] = 0;
+ } while (i < n);
+ return x;
+}
+
+void * f12(int n)
+{
+ n = (n > 10 ? 10 : n);
+ int * x = malloc(n * sizeof(int)); // no-warning
+ for (int i = 0; i < n; i++)
+ x[i] = i;
+ return x;
+}
+
+struct s13
+{
+ int n;
+};
+
+void * f13(struct s13 *s)
+{
+ if (s->n > 10)
+ return NULL;
+ return malloc(s->n * sizeof(int)); // no warning
+}
+
+void * f14(int n)
+{
+ if (n < 0)
+ return NULL;
+ return malloc(n * sizeof(int)); // expected-warning {{the computation of the size of the memory allocation may overflow}}
+}
diff --git a/test/Analysis/malloc-overflow.cpp b/test/Analysis/malloc-overflow.cpp
new file mode 100644
index 000000000000..c1ac6be4b029
--- /dev/null
+++ b/test/Analysis/malloc-overflow.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.security.MallocOverflow -verify %s
+
+class A {
+public:
+ A& operator<<(const A &a);
+};
+
+void f() {
+ A a = A(), b = A();
+ a << b;
+}
diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c
index f9af199b5fad..d9087ab83093 100644
--- a/test/Analysis/malloc.c
+++ b/test/Analysis/malloc.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.experimental.UnreachableCode,core.experimental.CastSize,unix.experimental.Malloc -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,experimental.core.CastSize,experimental.unix.Malloc -analyzer-store=region -verify %s
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
void free(void *);
@@ -41,7 +41,7 @@ void f2_realloc_0() {
void f2_realloc_1() {
int *p = malloc(12);
- int *q = realloc(p,0); // expected-warning{{Assigned value is garbage or undefined}}
+ int *q = realloc(p,0); // no-warning
}
// ownership attributes tests
diff --git a/test/Analysis/misc-ps-64.m b/test/Analysis/misc-ps-64.m
index 1cd738292781..e20a27f611e7 100644
--- a/test/Analysis/misc-ps-64.m
+++ b/test/Analysis/misc-ps-64.m
@@ -1,7 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=basic -verify -fblocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=basic -verify -fblocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s
// <rdar://problem/6440393> - A bunch of misc. failures involving evaluating
// these expressions and building CFGs. These tests are here to prevent
diff --git a/test/Analysis/misc-ps-basic-store.m b/test/Analysis/misc-ps-basic-store.m
deleted file mode 100644
index a29326d8b0e7..000000000000
--- a/test/Analysis/misc-ps-basic-store.m
+++ /dev/null
@@ -1,35 +0,0 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify -fblocks %s
-
-//---------------------------------------------------------------------------
-// Test case 'checkaccess_union' differs for region store and basic store.
-// The basic store doesn't reason about compound literals, so the code
-// below won't fire an "uninitialized value" warning.
-//---------------------------------------------------------------------------
-
-// PR 2948 (testcase; crash on VisitLValue for union types)
-// http://llvm.org/bugs/show_bug.cgi?id=2948
-
-void checkaccess_union() {
- int ret = 0, status;
- if (((((__extension__ (((union { // no-warning
- __typeof (status) __in; int __i;}
- )
- {
- .__in = (status)}
- ).__i))) & 0xff00) >> 8) == 1)
- ret = 1;
-}
-
-// BasicStore handles this case incorrectly because it doesn't reason about
-// the value pointed to by 'x' and thus creates different symbolic values
-// at the declarations of 'a' and 'b' respectively. See the companion test
-// in 'misc-ps-region-store.m'.
-void test_trivial_symbolic_comparison_pointer_parameter(int *x) {
- int a = *x;
- int b = *x;
- if (a != b) {
- int *p = 0;
- *p = 0xDEADBEEF; // expected-warning{{null}}
- }
-}
-
diff --git a/test/Analysis/misc-ps-cxx0x.cpp b/test/Analysis/misc-ps-cxx0x.cpp
index f21e82c4bcb4..53b6fa29ad6e 100644
--- a/test/Analysis/misc-ps-cxx0x.cpp
+++ b/test/Analysis/misc-ps-cxx0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang --analyze -std=c++0x %s -Xclang -verify
+// RUN: %clang --analyze -std=c++11 %s -Xclang -verify -o /dev/null
void test_static_assert() {
static_assert(sizeof(void *) == sizeof(void*), "test_static_assert");
@@ -9,3 +9,62 @@ void test_analyzer_working() {
*p = 0xDEADBEEF; // expected-warning {{null}}
}
+// Test that pointer-to-member functions don't cause the analyzer
+// to crash.
+struct RDar10243398 {
+ void bar(int x);
+};
+
+typedef void (RDar10243398::*RDar10243398MemberFn)(int x);
+
+void test_rdar10243398(RDar10243398 *p) {
+ RDar10243398MemberFn q = &RDar10243398::bar;
+ ((*p).*(q))(1);
+}
+
+// Tests for CXXTemporaryObjectExpr.
+struct X {
+ X( int *ip, int );
+};
+
+// Test to see if CXXTemporaryObjectExpr is being handled.
+int tempobj1()
+{
+ int j;
+ int i;
+ X a = X( &j, 1 );
+
+ return i; // expected-warning {{Undefined or garbage value returned to caller}}
+}
+
+// Test to see if CXXTemporaryObjectExpr invalidates arguments.
+int tempobj2()
+{
+ int j;
+ X a = X( &j, 1 );
+
+ return j; // no-warning
+}
+
+
+// Test for correct handling of C++ ForRange statement.
+void test1() {
+ int array[2] = { 1, 2 };
+ int j = 0;
+ for ( int i : array )
+ j += i;
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning {{null}}
+}
+
+void test2() {
+ int array[2] = { 1, 2 };
+ int j = 0;
+ for (int i : array)
+ j += i;
+ if (j == 3)
+ return;
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+}
+
diff --git a/test/Analysis/misc-ps-eager-assume.m b/test/Analysis/misc-ps-eager-assume.m
index 4380a187b800..0aff8e49b274 100644
--- a/test/Analysis/misc-ps-eager-assume.m
+++ b/test/Analysis/misc-ps-eager-assume.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s -analyzer-eagerly-assume
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s -analyzer-eagerly-assume
// Delta-reduced header stuff (needed for test cases).
typedef signed char BOOL;
diff --git a/test/Analysis/misc-ps-flat-store.c b/test/Analysis/misc-ps-flat-store.c
deleted file mode 100644
index e6369cbfb079..000000000000
--- a/test/Analysis/misc-ps-flat-store.c
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=flat -verify %s
-
-void f1() {
- int x;
- int *p;
- x = 1;
- p = 0;
- if (x != 1)
- *p = 1; // no-warning
-}
diff --git a/test/Analysis/misc-ps-ranges.m b/test/Analysis/misc-ps-ranges.m
index f2851f3257dd..00337f448147 100644
--- a/test/Analysis/misc-ps-ranges.m
+++ b/test/Analysis/misc-ps-ranges.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s
// <rdar://problem/6776949>
// main's 'argc' argument is always > 0
diff --git a/test/Analysis/misc-ps-region-store-i386.m b/test/Analysis/misc-ps-region-store-i386.m
index 2988dca4abd9..3106a24c5c7f 100644
--- a/test/Analysis/misc-ps-region-store-i386.m
+++ b/test/Analysis/misc-ps-region-store-i386.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify -fblocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks %s
// Here is a case where a pointer is treated as integer, invalidated as an
// integer, and then used again as a pointer. This test just makes sure
diff --git a/test/Analysis/misc-ps-region-store-x86_64.m b/test/Analysis/misc-ps-region-store-x86_64.m
index 9f1498ef47f4..2c604cfdcdf7 100644
--- a/test/Analysis/misc-ps-region-store-x86_64.m
+++ b/test/Analysis/misc-ps-region-store-x86_64.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks %s
// Here is a case where a pointer is treated as integer, invalidated as an
// integer, and then used again as a pointer. This test just makes sure
diff --git a/test/Analysis/misc-ps-region-store.cpp b/test/Analysis/misc-ps-region-store.cpp
index 795935959628..37153f765062 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,core.experimental -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
// Test basic handling of references.
char &test1_aux();
@@ -414,3 +414,56 @@ void TestAssignIntoSymbolicOffset::test(int x, int y) {
}
}
+// Test loads from static fields. This previously triggered an uninitialized
+// value warning.
+class ClassWithStatic {
+public:
+ static const unsigned value = 1;
+};
+
+int rdar9948787_negative() {
+ ClassWithStatic classWithStatic;
+ unsigned value = classWithStatic.value;
+ if (value == 1)
+ return 1;
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+ return 0;
+}
+
+int rdar9948787_positive() {
+ ClassWithStatic classWithStatic;
+ unsigned value = classWithStatic.value;
+ if (value == 0)
+ return 1;
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning {{null}}
+ return 0;
+}
+
+// Regression test against global constants and switches.
+enum rdar10202899_ValT { rdar10202899_ValTA, rdar10202899_ValTB, rdar10202899_ValTC };
+const rdar10202899_ValT val = rdar10202899_ValTA;
+void rdar10202899_test1() {
+ switch (val) {
+ case rdar10202899_ValTA: {}
+ };
+}
+
+void rdar10202899_test2() {
+ if (val == rdar10202899_ValTA)
+ return;
+ int *p = 0;
+ *p = 0xDEADBEEF;
+}
+
+void rdar10202899_test3() {
+ switch (val) {
+ case rdar10202899_ValTA: return;
+ default: ;
+ };
+ int *p = 0;
+ *p = 0xDEADBEEF;
+}
+
+
diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m
index 27f12c9a893a..0fdab83d7f8a 100644
--- a/test/Analysis/misc-ps-region-store.m
+++ b/test/Analysis/misc-ps-region-store.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental.CastToStruct,security.experimental.ReturnPtrRange,security.experimental.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -DTEST_64 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental.CastToStruct,security.experimental.ReturnPtrRange,security.experimental.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,experimental.core.CastToStruct,experimental.security.ReturnPtrRange,experimental.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -DTEST_64 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,experimental.core.CastToStruct,experimental.security.ReturnPtrRange,experimental.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
typedef long unsigned int size_t;
void *memcpy(void *, const void *, size_t);
diff --git a/test/Analysis/misc-ps-region-store.mm b/test/Analysis/misc-ps-region-store.mm
index 08f3e2486f8a..fee9433dac3b 100644
--- a/test/Analysis/misc-ps-region-store.mm
+++ b/test/Analysis/misc-ps-region-store.mm
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
//===------------------------------------------------------------------------------------------===//
// This files tests our path-sensitive handling of Objective-c++ files.
diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m
index da84b2487a8e..007c558299f5 100644
--- a/test/Analysis/misc-ps.m
+++ b/test/Analysis/misc-ps.m
@@ -1,12 +1,8 @@
// NOTE: Use '-fobjc-gc' to test the analysis being run twice, and multiple reports are not issued.
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-disable-checker=unix.experimental.Malloc -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-disable-checker=unix.experimental.Malloc -analyzer-store=basic -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-disable-checker=unix.experimental.Malloc -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-disable-checker=unix.experimental.Malloc -analyzer-store=basic -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
#ifndef __clang_analyzer__
#error __clang__analyzer__ not defined
@@ -553,7 +549,6 @@ int test_array_compound(int *q, int *r, int *z) {
return j;
}
-// This test case previously crashed with -analyzer-store=basic because the
// symbolic value stored in 'x' wouldn't be implicitly casted to a signed value
// during the comparison.
int rdar_7124210(unsigned int x) {
diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m
index 80eeaf69ddbc..e2ad1176e33f 100644
--- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m
+++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=range -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=range -analyzer-store=region -verify %s
// <rdar://problem/6888289> - This test case shows that a nil instance
// variable can possibly be initialized by a method.
diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
index 3fcbc55044ea..eb15435600b9 100644
--- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
+++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
@@ -1,9 +1,6 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin8 %s
-// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin8 %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin9 %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin9 %s
-// RUN: %clang_cc1 -triple thumbv6-apple-darwin4.0.0-iphoneos -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin9 %s
-// RUN: %clang_cc1 -triple thumbv6-apple-darwin4.0.0-iphoneos -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin9 %s
+// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin8 %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin9 %s
+// RUN: %clang_cc1 -triple thumbv6-apple-darwin4.0.0-iphoneos -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin9 %s
@interface MyClass {}
- (void *)voidPtrM;
diff --git a/test/Analysis/no-exit-cfg.c b/test/Analysis/no-exit-cfg.c
index cfcd76d6e0cf..1a80a254cba9 100644
--- a/test/Analysis/no-exit-cfg.c
+++ b/test/Analysis/no-exit-cfg.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
// This is a test case for the issue reported in PR 2819:
// http://llvm.org/bugs/show_bug.cgi?id=2819
diff --git a/test/Analysis/no-outofbounds.c b/test/Analysis/no-outofbounds.c
index 2d77cc92adf9..821f48610fc0 100644
--- a/test/Analysis/no-outofbounds.c
+++ b/test/Analysis/no-outofbounds.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental,unix.experimental,security.experimental.ArrayBound -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental,unix.experimental,security.experimental.ArrayBound -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,experimental.unix,experimental.security.ArrayBound -analyzer-store=region -verify %s
//===----------------------------------------------------------------------===//
// This file tests cases where we should not flag out-of-bounds warnings.
diff --git a/test/Analysis/null-deref-ps-region.c b/test/Analysis/null-deref-ps-region.c
index 85784558161e..08bfac748c2b 100644
--- a/test/Analysis/null-deref-ps-region.c
+++ b/test/Analysis/null-deref-ps-region.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -std=gnu99 -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -std=gnu99 -analyzer-store=region -verify %s
// The store for 'a[1]' should not be removed mistakenly. SymbolicRegions may
diff --git a/test/Analysis/null-deref-ps.c b/test/Analysis/null-deref-ps.c
index 4d0cc3fbddad..641dde207558 100644
--- a/test/Analysis/null-deref-ps.c
+++ b/test/Analysis/null-deref-ps.c
@@ -1,7 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,core.experimental -std=gnu99 -verify %s -analyzer-constraints=basic -analyzer-store=basic -Wreturn-type
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,core.experimental -std=gnu99 -verify %s -analyzer-constraints=range -analyzer-store=basic -Wreturn-type
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,core.experimental -std=gnu99 -analyzer-store=region -analyzer-constraints=range -analyzer-no-purge-dead -verify %s -Wreturn-type
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,core.experimental -std=gnu99 -analyzer-store=region -analyzer-constraints=range -verify %s -Wreturn-type
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,experimental.core -std=gnu99 -analyzer-store=region -analyzer-constraints=range -analyzer-purge=none -verify %s -Wreturn-type
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,experimental.core -std=gnu99 -analyzer-store=region -analyzer-constraints=range -verify %s -Wreturn-type
typedef unsigned uintptr_t;
diff --git a/test/Analysis/nullptr.cpp b/test/Analysis/nullptr.cpp
index 6f78baebfe22..fc7e7ef482b8 100644
--- a/test/Analysis/nullptr.cpp
+++ b/test/Analysis/nullptr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -analyze -analyzer-checker=core -analyzer-store region -verify %s
+// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=core -analyzer-store region -verify %s
// test to see if nullptr is detected as a null pointer
void foo1(void) {
diff --git a/test/Analysis/objc-arc.m b/test/Analysis/objc-arc.m
index 6b22fd099b06..b02af0515186 100644
--- a/test/Analysis/objc-arc.m
+++ b/test/Analysis/objc-arc.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core -analyzer-checker=deadcode -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -fobjc-nonfragile-abi -fobjc-arc %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,deadcode -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -fobjc-arc %s
typedef signed char BOOL;
typedef struct _NSZone NSZone;
@@ -147,3 +147,9 @@ void test_objc_unretainedObject() {
(void) x;
}
+// Previously this resulted in a "return of stack address" warning.
+id test_return() {
+ id x = (__bridge_transfer id) CFCreateString();
+ return x; // no-warning
+}
+
diff --git a/test/Analysis/operator-calls.cpp b/test/Analysis/operator-calls.cpp
index 766d16140ed0..73cd28ac0d56 100644
--- a/test/Analysis/operator-calls.cpp
+++ b/test/Analysis/operator-calls.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -verify %s
struct X0 { };
bool operator==(const X0&, const X0&);
diff --git a/test/Analysis/out-of-bounds.c b/test/Analysis/out-of-bounds.c
index 8c65b478f1c2..ac2cdc82598d 100644
--- a/test/Analysis/out-of-bounds.c
+++ b/test/Analysis/out-of-bounds.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,security.experimental.ArrayBoundV2 -verify %s
+// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,experimental.security.ArrayBoundV2 -verify %s
// Tests doing an out-of-bounds access after the end of an array using:
// - constant integer index
@@ -94,7 +94,6 @@ void test2_ptr(int x) {
p[-1] = 1; // expected-warning{{Out of bound memory access}}
}
-// ** FIXME ** Doesn't work yet because we don't support pointer arithmetic.
// Tests doing an out-of-bounds access before the start of an array using:
// - indirect pointer to buffer, manipulated using simple pointer arithmetic
// - constant integer index
@@ -103,7 +102,7 @@ void test2_ptr_arith(int x) {
int buf[100];
int *p = buf;
--p;
- p[0] = 1; // no-warning
+ p[0] = 1; // expected-warning {{Out of bound memory access (accessed memory precedes memory block)}}
}
// Tests doing an out-of-bounds access before the start of a multi-dimensional
diff --git a/test/Analysis/outofbound-notwork.c b/test/Analysis/outofbound-notwork.c
new file mode 100644
index 000000000000..45e713b6880a
--- /dev/null
+++ b/test/Analysis/outofbound-notwork.c
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,experimental.unix,experimental.security.ArrayBound -analyzer-store=region -verify %s
+// XFAIL: *
+
+// Once we better handle modeling of sizes of VLAs, we can pull this back
+// into outofbound.c.
+
+void sizeof_vla(int a) {
+ if (a == 5) {
+ char x[a];
+ int y[sizeof(x)];
+ y[4] = 4; // no-warning
+ y[5] = 5; // expected-warning{{out-of-bound}}
+ }
+}
+
+void sizeof_vla_2(int a) {
+ if (a == 5) {
+ char x[a];
+ int y[sizeof(x) / sizeof(char)];
+ y[4] = 4; // no-warning
+ y[5] = 5; // expected-warning{{out-of-bound}}
+ }
+}
+
+void sizeof_vla_3(int a) {
+ if (a == 5) {
+ char x[a];
+ int y[sizeof(*&*&*&x)];
+ y[4] = 4; // no-warning
+ y[5] = 5; // expected-warning{{out-of-bound}}
+ }
+}
diff --git a/test/Analysis/outofbound.c b/test/Analysis/outofbound.c
index 891719c1932f..2e7a7d30d67f 100644
--- a/test/Analysis/outofbound.c
+++ b/test/Analysis/outofbound.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,unix.experimental,security.experimental.ArrayBound -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,experimental.unix,experimental.security.ArrayBound -analyzer-store=region -verify %s
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
@@ -63,15 +63,6 @@ void vla(int a) {
}
}
-void sizeof_vla(int a) {
- if (a == 5) {
- char x[a];
- int y[sizeof(x)];
- y[4] = 4; // no-warning
- y[5] = 5; // expected-warning{{out-of-bound}}
- }
-}
-
void alloca_region(int a) {
if (a == 5) {
char *x = __builtin_alloca(a);
diff --git a/test/Analysis/override-werror.c b/test/Analysis/override-werror.c
index 1b1f9e1c0169..d3b75f694d0b 100644
--- a/test/Analysis/override-werror.c
+++ b/test/Analysis/override-werror.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -Werror %s -analyzer-store=basic -verify
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -Werror %s -analyzer-store=region -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -Werror %s -analyzer-store=region -verify
// This test case illustrates that using '-analyze' overrides the effect of
// -Werror. This allows basic warnings not to interfere with producing
diff --git a/test/Analysis/plist-output-alternate.m b/test/Analysis/plist-output-alternate.m
index 0f4d3aee0744..23a260a129c7 100644
--- a/test/Analysis/plist-output-alternate.m
+++ b/test/Analysis/plist-output-alternate.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o - %s | FileCheck %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o - %s | FileCheck %s
void test_null_init(void) {
int *p = 0;
@@ -69,34 +69,6 @@ void rdar8331641(int x) {
// CHECK: <key>path</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>4</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>4</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>4</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
-// CHECK: </dict>
-// CHECK: <dict>
// CHECK: <key>kind</key><string>control</string>
// CHECK: <key>edges</key>
// CHECK: <array>
@@ -110,7 +82,7 @@ void rdar8331641(int x) {
// CHECK: </dict>
// CHECK: <dict>
// CHECK: <key>line</key><integer>4</integer>
-// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -193,13 +165,13 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
+// 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>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// 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>
@@ -210,7 +182,7 @@ void rdar8331641(int x) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>line</key><integer>11</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -218,22 +190,36 @@ void rdar8331641(int x) {
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
// CHECK: <key>extended_message</key>
-// CHECK: <string>Null pointer value stored to &apos;p&apos;</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>message</key>
-// CHECK: <string>Null pointer value stored to &apos;p&apos;</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK: <key>category</key><string>Logic error</string>
+// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
// CHECK: <dict>
// CHECK: <key>kind</key><string>control</string>
// CHECK: <key>edges</key>
@@ -242,12 +228,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>line</key><integer>15</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>line</key><integer>15</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -255,12 +241,12 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>line</key><integer>18</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>line</key><integer>18</integer>
// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -272,7 +258,7 @@ void rdar8331641(int x) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>line</key><integer>18</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -280,29 +266,29 @@ void rdar8331641(int x) {
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>line</key><integer>18</integer>
// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>line</key><integer>18</integer>
// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
// CHECK: </dict>
// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
// CHECK: <key>category</key><string>Logic error</string>
// CHECK: <key>type</key><string>Dereference of null pointer</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>line</key><integer>18</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -318,12 +304,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>15</integer>
+// 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>15</integer>
+// CHECK: <key>line</key><integer>22</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -331,12 +317,12 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
+// CHECK: <key>line</key><integer>22</integer>
// CHECK: <key>col</key><integer>8</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -348,29 +334,29 @@ void rdar8331641(int x) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <key>ranges</key>
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
+// CHECK: <key>line</key><integer>22</integer>
// CHECK: <key>col</key><integer>8</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
// CHECK: <key>extended_message</key>
-// CHECK: <string>Variable &apos;q&apos; initialized to a null pointer value</string>
+// CHECK: <string>Assuming &apos;p&apos; is null</string>
// CHECK: <key>message</key>
-// CHECK: <string>Variable &apos;q&apos; initialized to a null pointer value</string>
+// CHECK: <string>Assuming &apos;p&apos; is null</string>
// CHECK: </dict>
// CHECK: <dict>
// CHECK: <key>kind</key><string>control</string>
@@ -380,12 +366,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
+// CHECK: <key>line</key><integer>22</integer>
// CHECK: <key>col</key><integer>8</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -393,13 +379,13 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>6</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -410,38 +396,38 @@ void rdar8331641(int x) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <key>ranges</key>
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>6</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>6</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: </dict>
// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
+// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>category</key><string>Logic error</string>
// CHECK: <key>type</key><string>Dereference of null pointer</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </dict>
@@ -456,12 +442,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>line</key><integer>28</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>line</key><integer>28</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -469,13 +455,13 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>8</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -486,44 +472,30 @@ void rdar8331641(int x) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <key>ranges</key>
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>8</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK: <string>Assuming &apos;q&apos; is null</string>
// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK: <string>Assuming &apos;q&apos; is null</string>
// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
// CHECK: <dict>
// CHECK: <key>kind</key><string>control</string>
// CHECK: <key>edges</key>
@@ -533,12 +505,12 @@ void rdar8331641(int x) {
// CHECK: <array>
// CHECK: <dict>
// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>col</key><integer>8</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -551,7 +523,7 @@ void rdar8331641(int x) {
// CHECK: </dict>
// CHECK: <dict>
// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>10</integer>
+// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -559,34 +531,6 @@ void rdar8331641(int x) {
// CHECK: </array>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
-// CHECK: </dict>
-// CHECK: <dict>
// CHECK: <key>kind</key><string>control</string>
// CHECK: <key>edges</key>
// CHECK: <array>
@@ -600,7 +544,7 @@ void rdar8331641(int x) {
// CHECK: </dict>
// CHECK: <dict>
// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>10</integer>
+// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -676,7 +620,7 @@ void rdar8331641(int x) {
// CHECK: </dict>
// CHECK: <dict>
// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -923,13 +867,75 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
+// CHECK: <key>line</key><integer>54</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>54</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>54</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>54</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>54</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Assuming &apos;x&apos; is 0</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Assuming &apos;x&apos; is 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>54</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>54</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>col</key><integer>10</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>col</key><integer>10</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -945,12 +951,12 @@ void rdar8331641(int x) {
// CHECK: <array>
// CHECK: <dict>
// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>col</key><integer>10</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>col</key><integer>10</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -978,21 +984,6 @@ void rdar8331641(int x) {
// CHECK: <key>col</key><integer>1</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
// CHECK: <key>extended_message</key>
// CHECK: <string>Object leaked: object allocated and stored into &apos;value&apos; is not referenced later in this execution path and has a retain count of +1</string>
// CHECK: <key>message</key>
@@ -1001,7 +992,7 @@ void rdar8331641(int x) {
// CHECK: </array>
// CHECK: <key>description</key><string>Potential leak of an object allocated on line 53 and stored into &apos;value&apos;</string>
// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Leak of returned object</string>
+// CHECK: <key>type</key><string>Leak</string>
// CHECK: <key>location</key>
// CHECK: <dict>
// CHECK: <key>line</key><integer>57</integer>
@@ -1012,4 +1003,3 @@ void rdar8331641(int x) {
// CHECK: </array>
// CHECK: </dict>
// CHECK: </plist>
-
diff --git a/test/Analysis/plist-output.m b/test/Analysis/plist-output.m
index 224f5194765e..e08ccc43dec8 100644
--- a/test/Analysis/plist-output.m
+++ b/test/Analysis/plist-output.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o - %s | FileCheck %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o - %s | FileCheck %s
// XFAIL: *
void test_null_init(void) {
diff --git a/test/Analysis/pr4209.m b/test/Analysis/pr4209.m
index e3bc5cc14333..e16d1aa0ed5b 100644
--- a/test/Analysis/pr4209.m
+++ b/test/Analysis/pr4209.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
// This test case was crashing due to how CFRefCount.cpp resolved the
// ObjCInterfaceDecl* and ClassName in EvalObjCMessageExpr.
diff --git a/test/Analysis/pr_2542_rdar_6793404.m b/test/Analysis/pr_2542_rdar_6793404.m
index 73218d8bc80e..d5125a649d2b 100644
--- a/test/Analysis/pr_2542_rdar_6793404.m
+++ b/test/Analysis/pr_2542_rdar_6793404.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -pedantic -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -pedantic -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -pedantic -analyzer-store=region -verify %s
// BEGIN delta-debugging reduced header stuff
diff --git a/test/Analysis/pr_4164.c b/test/Analysis/pr_4164.c
index c58c8abe3f67..187f4c6bca43 100644
--- a/test/Analysis/pr_4164.c
+++ b/test/Analysis/pr_4164.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
// PR 4164: http://llvm.org/bugs/show_bug.cgi?id=4164
//
diff --git a/test/Analysis/properties.m b/test/Analysis/properties.m
index ad9db1ad6818..6d04a4ab4e78 100644
--- a/test/Analysis/properties.m
+++ b/test/Analysis/properties.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -verify %s
typedef signed char BOOL;
typedef unsigned int NSUInteger;
diff --git a/test/Analysis/pthreadlock.c b/test/Analysis/pthreadlock.c
new file mode 100644
index 000000000000..4735d20eaa5c
--- /dev/null
+++ b/test/Analysis/pthreadlock.c
@@ -0,0 +1,137 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.unix.PthreadLock -verify %s
+
+// Tests performing normal locking patterns and wrong locking orders
+
+typedef struct {
+ void *foo;
+} pthread_mutex_t;
+
+typedef pthread_mutex_t lck_mtx_t;
+
+extern int pthread_mutex_lock(pthread_mutex_t *);
+extern int pthread_mutex_unlock(pthread_mutex_t *);
+extern int pthread_mutex_trylock(pthread_mutex_t *);
+extern int lck_mtx_lock(lck_mtx_t *);
+extern int lck_mtx_unlock(lck_mtx_t *);
+extern int lck_mtx_try_lock(lck_mtx_t *);
+
+pthread_mutex_t mtx1, mtx2;
+lck_mtx_t lck1, lck2;
+
+void
+ok1(void)
+{
+ pthread_mutex_lock(&mtx1); // no-warning
+}
+
+void
+ok2(void)
+{
+ pthread_mutex_unlock(&mtx1); // no-warning
+}
+
+void
+ok3(void)
+{
+ pthread_mutex_lock(&mtx1); // no-warning
+ pthread_mutex_unlock(&mtx1); // no-warning
+ pthread_mutex_lock(&mtx1); // no-warning
+ pthread_mutex_unlock(&mtx1); // no-warning
+}
+
+void
+ok4(void)
+{
+ pthread_mutex_lock(&mtx1); // no-warning
+ pthread_mutex_unlock(&mtx1); // no-warning
+ pthread_mutex_lock(&mtx2); // no-warning
+ pthread_mutex_unlock(&mtx2); // no-warning
+}
+
+void
+ok5(void)
+{
+ if (pthread_mutex_trylock(&mtx1) == 0) // no-warning
+ pthread_mutex_unlock(&mtx1); // no-warning
+}
+
+void
+ok6(void)
+{
+ lck_mtx_lock(&lck1); // no-warning
+}
+
+void
+ok7(void)
+{
+ if (lck_mtx_try_lock(&lck1) != 0) // no-warning
+ lck_mtx_unlock(&lck1); // no-warning
+}
+
+void
+bad1(void)
+{
+ pthread_mutex_lock(&mtx1); // no-warning
+ pthread_mutex_lock(&mtx1); // expected-warning{{This lock has already been acquired}}
+}
+
+void
+bad2(void)
+{
+ pthread_mutex_lock(&mtx1); // no-warning
+ pthread_mutex_unlock(&mtx1); // no-warning
+ pthread_mutex_lock(&mtx1); // no-warning
+ pthread_mutex_lock(&mtx1); // expected-warning{{This lock has already been acquired}}
+}
+
+void
+bad3(void)
+{
+ pthread_mutex_lock(&mtx1); // no-warning
+ pthread_mutex_lock(&mtx2); // no-warning
+ pthread_mutex_unlock(&mtx1); // expected-warning{{This was not the most recently acquired lock}}
+ pthread_mutex_unlock(&mtx2);
+}
+
+void
+bad4(void)
+{
+ if (pthread_mutex_trylock(&mtx1)) // no-warning
+ return;
+ pthread_mutex_lock(&mtx2); // no-warning
+ pthread_mutex_unlock(&mtx1); // expected-warning{{This was not the most recently acquired lock}}
+}
+
+void
+bad5(void)
+{
+ lck_mtx_lock(&lck1); // no-warning
+ lck_mtx_lock(&lck1); // expected-warning{{This lock has already been acquired}}
+}
+
+void
+bad6(void)
+{
+ lck_mtx_lock(&lck1); // no-warning
+ lck_mtx_unlock(&lck1); // no-warning
+ lck_mtx_lock(&lck1); // no-warning
+ lck_mtx_lock(&lck1); // expected-warning{{This lock has already been acquired}}
+}
+
+void
+bad7(void)
+{
+ lck_mtx_lock(&lck1); // no-warning
+ lck_mtx_lock(&lck2); // no-warning
+ lck_mtx_unlock(&lck1); // expected-warning{{This was not the most recently acquired lock}}
+ lck_mtx_unlock(&lck2);
+}
+
+void
+bad8(void)
+{
+ if (lck_mtx_try_lock(&lck1) == 0) // no-warning
+ return;
+ lck_mtx_lock(&lck2); // no-warning
+ lck_mtx_unlock(&lck1); // expected-warning{{This was not the most recently acquired lock}}
+}
diff --git a/test/Analysis/ptr-arith.c b/test/Analysis/ptr-arith.c
index 502de6c3ef9a..995470a369cb 100644
--- a/test/Analysis/ptr-arith.c
+++ b/test/Analysis/ptr-arith.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.FixedAddr,core.experimental.PointerArithm,core.experimental.PointerSub -analyzer-store=region -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.FixedAddr,core.experimental.PointerArithm,core.experimental.PointerSub -analyzer-store=region -verify -triple i686-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core.FixedAddr,experimental.core.PointerArithm,experimental.core.PointerSub -analyzer-store=region -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core.FixedAddr,experimental.core.PointerArithm,experimental.core.PointerSub -analyzer-store=region -verify -triple i686-apple-darwin9 %s
// Used to trigger warnings for unreachable paths.
#define WARN do { int a, b; int c = &b-&a; } while (0)
diff --git a/test/Analysis/rdar-6442306-1.m b/test/Analysis/rdar-6442306-1.m
index d576eae8f652..62992d0146aa 100644
--- a/test/Analysis/rdar-6442306-1.m
+++ b/test/Analysis/rdar-6442306-1.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental %s -analyzer-store=basic -verify
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental %s -analyzer-store=region -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core %s -analyzer-store=region -verify
typedef int bar_return_t;
typedef struct {
diff --git a/test/Analysis/rdar-6540084.m b/test/Analysis/rdar-6540084.m
index 4c70dbc0758f..b2a113c20dcf 100644
--- a/test/Analysis/rdar-6540084.m
+++ b/test/Analysis/rdar-6540084.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-checker=deadcode.DeadStores -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core -analyzer-checker=deadcode.DeadStores -verify %s
//
// This test exercises the live variables analysis (LiveVariables.cpp).
// The case originally identified a non-termination bug.
diff --git a/test/Analysis/rdar-6541136-region.c b/test/Analysis/rdar-6541136-region.c
index 5555b018578f..b90d4f43ddf7 100644
--- a/test/Analysis/rdar-6541136-region.c
+++ b/test/Analysis/rdar-6541136-region.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -analyze -analyzer-checker=core,security.experimental.ArrayBound -analyzer-store=region %s
+// RUN: %clang_cc1 -verify -analyze -analyzer-checker=core,experimental.security.ArrayBound -analyzer-store=region %s
struct tea_cheese { unsigned magic; };
typedef struct tea_cheese kernel_tea_cheese_t;
diff --git a/test/Analysis/rdar-6541136.c b/test/Analysis/rdar-6541136.c
deleted file mode 100644
index 095aefadb8ce..000000000000
--- a/test/Analysis/rdar-6541136.c
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clang_cc1 -verify -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic %s
-
-struct tea_cheese { unsigned magic; };
-typedef struct tea_cheese kernel_tea_cheese_t;
-extern kernel_tea_cheese_t _wonky_gesticulate_cheese;
-
-// This test case exercises the ElementRegion::getRValueType() logic.
-// All it tests is that it does not crash or do anything weird.
-// The out-of-bounds-access on line 19 is caught using the region store variant.
-
-void foo( void )
-{
- kernel_tea_cheese_t *wonky = &_wonky_gesticulate_cheese;
- struct load_wine *cmd = (void*) &wonky[1];
- cmd = cmd;
- char *p = (void*) &wonky[1];
- *p = 1;
- kernel_tea_cheese_t *q = &wonky[1];
- kernel_tea_cheese_t r = *q; // no-warning
-}
diff --git a/test/Analysis/rdar-6562655.m b/test/Analysis/rdar-6562655.m
index 1e0998aa974e..3a592730a897 100644
--- a/test/Analysis/rdar-6562655.m
+++ b/test/Analysis/rdar-6562655.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-constraints=basic -analyzer-store=region -verify %s
//
// This test case mainly checks that the retain/release checker doesn't crash
// on this file.
diff --git a/test/Analysis/rdar-6582778-basic-store.c b/test/Analysis/rdar-6582778-basic-store.c
deleted file mode 100644
index 0642b64cd7fd..000000000000
--- a/test/Analysis/rdar-6582778-basic-store.c
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
-
-typedef const void * CFTypeRef;
-typedef double CFTimeInterval;
-typedef CFTimeInterval CFAbsoluteTime;
-typedef const struct __CFAllocator * CFAllocatorRef;
-typedef const struct __CFDate * CFDateRef;
-
-extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at);
-CFAbsoluteTime CFAbsoluteTimeGetCurrent(void);
-
-void f(void) {
- CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
- CFTypeRef vals[] = { CFDateCreate(0, t) }; // no-warning
-}
-
-CFTypeRef global;
-
-void g(void) {
- CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
- global = CFDateCreate(0, t); // no-warning
-}
diff --git a/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m
index 03b2656c7ee6..e9711e70c204 100644
--- a/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m
+++ b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=basic %s -verify
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=region %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region %s -verify
typedef struct Foo { int x; } Bar;
diff --git a/test/Analysis/rdar-7168531.m b/test/Analysis/rdar-7168531.m
index b2b66b279296..151625569ca7 100644
--- a/test/Analysis/rdar-7168531.m
+++ b/test/Analysis/rdar-7168531.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -triple i386-apple-darwin10 -analyzer-store=region %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -triple i386-apple-darwin10 -analyzer-store=basic %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -triple i386-apple-darwin10 -fobjc-fragile-abi -analyzer-store=region %s
// Note that the target triple is important for this test case. It specifies that we use the
// fragile Objective-C ABI.
diff --git a/test/Analysis/refcnt_naming.m b/test/Analysis/refcnt_naming.m
index 8e99f3409b81..aff713be49f2 100644
--- a/test/Analysis/refcnt_naming.m
+++ b/test/Analysis/refcnt_naming.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -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 3422b58d3fe8..c7912f4f029e 100644
--- a/test/Analysis/reference.cpp
+++ b/test/Analysis/reference.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
+// XFAIL
typedef typeof(sizeof(int)) size_t;
void malloc (size_t);
diff --git a/test/Analysis/region-1.m b/test/Analysis/region-1.m
index 7f4cd26e405e..be9276609136 100644
--- a/test/Analysis/region-1.m
+++ b/test/Analysis/region-1.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
//
// This test case simply should not crash. It evaluates the logic of not
// using MemRegion::getRValueType in incorrect places.
diff --git a/test/Analysis/retain-release-basic-store.m b/test/Analysis/retain-release-basic-store.m
deleted file mode 100644
index 7fd17ffb995f..000000000000
--- a/test/Analysis/retain-release-basic-store.m
+++ /dev/null
@@ -1,104 +0,0 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -verify %s
-
-//===----------------------------------------------------------------------===//
-// The following code is reduced using delta-debugging from
-// Foundation.h (Mac OS X).
-//
-// It includes the basic definitions for the test cases below.
-// Not including Foundation.h directly makes this test case both svelte and
-// portable to non-Mac platforms.
-//===----------------------------------------------------------------------===//
-
-typedef unsigned int __darwin_natural_t;
-typedef unsigned long UInt32;
-typedef signed long CFIndex;
-typedef const void * CFTypeRef;
-typedef const struct __CFString * CFStringRef;
-typedef const struct __CFAllocator * CFAllocatorRef;
-extern const CFAllocatorRef kCFAllocatorDefault;
-extern CFTypeRef CFRetain(CFTypeRef cf);
-extern void CFRelease(CFTypeRef cf);
-typedef struct {
-}
-CFArrayCallBacks;
-extern const CFArrayCallBacks kCFTypeArrayCallBacks;
-typedef const struct __CFArray * CFArrayRef;
-typedef struct __CFArray * CFMutableArrayRef;
-extern CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks);
-extern const void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx);
-typedef const struct __CFDictionary * CFDictionaryRef;
-typedef UInt32 CFStringEncoding;
-enum {
-kCFStringEncodingMacRoman = 0, kCFStringEncodingWindowsLatin1 = 0x0500, kCFStringEncodingISOLatin1 = 0x0201, kCFStringEncodingNextStepLatin = 0x0B01, kCFStringEncodingASCII = 0x0600, kCFStringEncodingUnicode = 0x0100, kCFStringEncodingUTF8 = 0x08000100, kCFStringEncodingNonLossyASCII = 0x0BFF , kCFStringEncodingUTF16 = 0x0100, kCFStringEncodingUTF16BE = 0x10000100, kCFStringEncodingUTF16LE = 0x14000100, kCFStringEncodingUTF32 = 0x0c000100, kCFStringEncodingUTF32BE = 0x18000100, kCFStringEncodingUTF32LE = 0x1c000100 };
-extern CFStringRef CFStringCreateWithCString(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding);
-typedef double CFTimeInterval;
-typedef CFTimeInterval CFAbsoluteTime;
-typedef const struct __CFDate * CFDateRef;
-extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at);
-extern CFAbsoluteTime CFDateGetAbsoluteTime(CFDateRef theDate);
-typedef __darwin_natural_t natural_t;
-typedef natural_t mach_port_name_t;
-typedef mach_port_name_t mach_port_t;
-typedef signed char BOOL;
-typedef struct _NSZone NSZone;
-@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
-@protocol NSObject - (BOOL)isEqual:(id)object;
-- (id)retain;
-- (oneway void)release;
-@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone;
-@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
-@end @interface NSObject <NSObject> {
-}
-@end typedef float CGFloat;
-typedef double NSTimeInterval;
-@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate;
-@end enum {
-NSObjCNoType = 0, NSObjCVoidType = 'v', NSObjCCharType = 'c', NSObjCShortType = 's', NSObjCLongType = 'l', NSObjCLonglongType = 'q', NSObjCFloatType = 'f', NSObjCDoubleType = 'd', NSObjCBoolType = 'B', NSObjCSelectorType = ':', NSObjCObjectType = '@', NSObjCStructType = '{', NSObjCPointerType = '^', NSObjCStringType = '*', NSObjCArrayType = '[', NSObjCUnionType = '(', NSObjCBitfield = 'b' }
-__attribute__((deprecated));
-typedef int kern_return_t;
-typedef kern_return_t mach_error_t;
-typedef mach_port_t io_object_t;
-typedef io_object_t io_service_t;
-typedef struct __DASession * DASessionRef;
-extern DASessionRef DASessionCreate( CFAllocatorRef allocator );
-typedef struct __DADisk * DADiskRef;
-extern DADiskRef DADiskCreateFromBSDName( CFAllocatorRef allocator, DASessionRef session, const char * name );
-extern DADiskRef DADiskCreateFromIOMedia( CFAllocatorRef allocator, DASessionRef session, io_service_t media );
-extern CFDictionaryRef DADiskCopyDescription( DADiskRef disk );
-extern DADiskRef DADiskCopyWholeDisk( DADiskRef disk );
-@interface NSAppleEventManager : NSObject {
-}
-@end enum {
-kDAReturnSuccess = 0, kDAReturnError = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01, kDAReturnBusy = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02, kDAReturnBadArgument = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03, kDAReturnExclusiveAccess = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04, kDAReturnNoResources = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05, kDAReturnNotFound = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06, kDAReturnNotMounted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07, kDAReturnNotPermitted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08, kDAReturnNotPrivileged = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09, kDAReturnNotReady = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A, kDAReturnNotWritable = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B, kDAReturnUnsupported = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0C };
-typedef mach_error_t DAReturn;
-typedef const struct __DADissenter * DADissenterRef;
-extern DADissenterRef DADissenterCreate( CFAllocatorRef allocator, DAReturn status, CFStringRef string );
-
-//===----------------------------------------------------------------------===//
-// Test cases.
-//===----------------------------------------------------------------------===//
-
-// Test to see if we supresss an error when we store the pointer
-// to a struct. This is because the value "escapes" the basic reasoning
-// of basic store.
-
-struct foo {
- NSDate* f;
-};
-
-CFAbsoluteTime CFAbsoluteTimeGetCurrent(void);
-
-CFAbsoluteTime f4() {
- struct foo x;
-
- CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
- CFDateRef date = CFDateCreate(0, t);
- [((NSDate*) date) retain];
- CFRelease(date);
- CFDateGetAbsoluteTime(date); // no-warning
- x.f = (NSDate*) date;
- [((NSDate*) date) release];
- t = CFDateGetAbsoluteTime(date); // no-warning
- return t;
-}
-
diff --git a/test/Analysis/retain-release-gc-only.m b/test/Analysis/retain-release-gc-only.m
index ee1a6b4b782e..4e1b8466c322 100644
--- a/test/Analysis/retain-release-gc-only.m
+++ b/test/Analysis/retain-release-gc-only.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSAutoreleasePool -analyzer-store=basic -verify -fobjc-gc-only -fblocks %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSAutoreleasePool -analyzer-store=region -fobjc-gc-only -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.NSAutoreleasePool -analyzer-store=region -fobjc-gc-only -fblocks -verify %s
//===----------------------------------------------------------------------===//
// Header stuff.
@@ -92,7 +91,7 @@ typedef struct _NSZone NSZone;
+ (id)allocWithZone:(NSZone *)zone;
+ (id)alloc;
- (void)dealloc;
-- (void)release;
+- (oneway void)release;
- (id)copy;
@end
@interface NSObject (NSCoderMethods)
diff --git a/test/Analysis/retain-release-path-notes-gc.m b/test/Analysis/retain-release-path-notes-gc.m
index 21d314fa1541..19e6d7b8b337 100644
--- a/test/Analysis/retain-release-path-notes-gc.m
+++ b/test/Analysis/retain-release-path-notes-gc.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=basic -analyzer-output=text -fobjc-gc-only -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=region -analyzer-output=text -fobjc-gc-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=text -fobjc-gc-only -verify %s
/***
This file is for testing the path-sensitive notes for retain/release errors.
diff --git a/test/Analysis/retain-release-path-notes.m b/test/Analysis/retain-release-path-notes.m
index bac0afb3f7ab..e34942a8968c 100644
--- a/test/Analysis/retain-release-path-notes.m
+++ b/test/Analysis/retain-release-path-notes.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=basic -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=region -analyzer-output=text -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=text -verify %s
/***
This file is for testing the path-sensitive notes for retain/release errors.
diff --git a/test/Analysis/retain-release-region-store.m b/test/Analysis/retain-release-region-store.m
index ac2362a4a73c..89950ce7cd25 100644
--- a/test/Analysis/retain-release-region-store.m
+++ b/test/Analysis/retain-release-region-store.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-max-loop 6 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-max-loop 6 -verify %s
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index 71ae756cf045..6f8bf09ebd74 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -1,7 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=basic -fblocks -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=region -fblocks -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=basic -fblocks -verify -x objective-c++ %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=region -fblocks -verify -x objective-c++ %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify -x objective-c++ %s
#if __has_feature(attribute_ns_returns_retained)
#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
@@ -148,7 +146,9 @@ NSFastEnumerationState;
typedef double NSTimeInterval;
@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate;
@end typedef unsigned short unichar;
-@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
+- (NSUInteger)length;
+- (NSString *)stringByAppendingString:(NSString *)aString;
- ( const char *)UTF8String;
- (id)initWithUTF8String:(const char *)nullTerminatedCString;
+ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
@@ -270,6 +270,12 @@ extern void CGContextDrawLinearGradient(CGContextRef context,
CGGradientDrawingOptions options);
extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void);
+@interface NSMutableArray : NSObject
+- (void)addObject:(id)object;
++ (id)array;
+@end
+
+
//===----------------------------------------------------------------------===//
// Test cases.
//===----------------------------------------------------------------------===//
@@ -654,6 +660,12 @@ void rdar6704930(unsigned char *s, unsigned int length) {
[window release];
[super dealloc];
}
+
+- (void)radar10102244 {
+ NSMutableDictionary *dict = [[NSMutableDictionary dictionaryWithCapacity:4] retain]; // expected-warning{{leak}}
+ if (window)
+ NSLog(@"%@", window);
+}
@end
//===----------------------------------------------------------------------===//
@@ -1446,7 +1458,7 @@ static void rdar_8724287(CFErrorRef error)
while (error_to_dump != ((void*)0)) {
CFDictionaryRef info;
- info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object allocated on line 1449 and stored into 'info'}}
+ info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object allocated on line}}
if (info != ((void*)0)) {
}
@@ -1540,3 +1552,55 @@ CFArrayRef camel_copymachine() {
return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning {{leak}}
}
+// rdar://problem/8024350
+@protocol F18P
+- (id) clone;
+@end
+@interface F18 : NSObject<F18P> @end
+@interface F18(Cat)
+- (id) clone NS_RETURNS_RETAINED;
+@end
+
+@implementation F18
+- (id) clone {
+ return [F18 alloc];
+}
+@end
+
+// Radar 6582778.
+void rdar6582778(void) {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFTypeRef vals[] = { CFDateCreate(0, t) }; // expected-warning {{leak}}
+}
+
+CFTypeRef global;
+
+void rdar6582778_2(void) {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ global = CFDateCreate(0, t); // no-warning
+}
+
+// <rdar://problem/10232019> - Test that objects passed to containers
+// are marked "escaped".
+
+void rdar10232019() {
+ NSMutableArray *array = [NSMutableArray array];
+
+ NSString *string = [[NSString alloc] initWithUTF8String:"foo"];
+ [array addObject:string];
+ [string release];
+
+ NSString *otherString = [string stringByAppendingString:@"bar"]; // no-warning
+ NSLog(@"%@", otherString);
+}
+
+void rdar10232019_positive() {
+ NSMutableArray *array = [NSMutableArray array];
+
+ NSString *string = [[NSString alloc] initWithUTF8String:"foo"];
+ [string release];
+
+ NSString *otherString = [string stringByAppendingString:@"bar"]; // expected-warning {{Reference-counted object is used after it is release}}
+ NSLog(@"%@", otherString);
+}
+
diff --git a/test/Analysis/retain-release.mm b/test/Analysis/retain-release.mm
index bdc3dc03964a..bae8dc339254 100644
--- a/test/Analysis/retain-release.mm
+++ b/test/Analysis/retain-release.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=region -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify %s
#if __has_feature(attribute_ns_returns_retained)
#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
@@ -304,4 +304,14 @@ void test_smartpointer_3() {
foo.noAdopt(x);
}
+extern CFStringRef ElectronMicroscopyEngage(void);
+void test_microscopy() {
+ NSString *token = (NSString*) ElectronMicroscopyEngage();
+ [token release]; // expected-warning {{object that is not owned}}
+}
+extern CFStringRef Scopy(void);
+void test_Scopy() {
+ NSString *token = (NSString*) Scopy();
+ [token release]; // expected-warning {{object that is not owned}}
+}
diff --git a/test/Analysis/security-syntax-checks-no-emit.c b/test/Analysis/security-syntax-checks-no-emit.c
index 4e37c44247c2..cbd432a19b31 100644
--- a/test/Analysis/security-syntax-checks-no-emit.c
+++ b/test/Analysis/security-syntax-checks-no-emit.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i686-pc-linux-gnu -analyze -analyzer-checker=security.experimental.SecuritySyntactic %s -verify
+// RUN: %clang_cc1 -triple i686-pc-linux-gnu -analyze -analyzer-checker=experimental.security.SecuritySyntactic %s -verify
// This file complements 'security-syntax-checks.m', but tests that we omit
// specific checks on platforms where they don't make sense.
diff --git a/test/Analysis/security-syntax-checks.m b/test/Analysis/security-syntax-checks.m
index 160dcf657387..6fb5b3cf14ef 100644
--- a/test/Analysis/security-syntax-checks.m
+++ b/test/Analysis/security-syntax-checks.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=security.experimental.SecuritySyntactic %s -verify
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DUSE_BUILTINS -analyzer-checker=security.experimental.SecuritySyntactic %s -verify
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DVARIANT -analyzer-checker=security.experimental.SecuritySyntactic %s -verify
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=security.experimental.SecuritySyntactic %s -verify
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=experimental.security.SecuritySyntactic %s -verify
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DUSE_BUILTINS -analyzer-checker=experimental.security.SecuritySyntactic %s -verify
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DVARIANT -analyzer-checker=experimental.security.SecuritySyntactic %s -verify
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=experimental.security.SecuritySyntactic %s -verify
#ifdef USE_BUILTINS
# define BUILTIN(f) __builtin_ ## f
@@ -164,3 +164,14 @@ void test_strcat() {
strcat(x, y); //expected-warning{{Call to function 'strcat' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strncat'. CWE-119.}}
}
+
+//===----------------------------------------------------------------------===
+// vfork()
+//===----------------------------------------------------------------------===
+typedef int __int32_t;
+typedef __int32_t pid_t;
+pid_t vfork(void); //expected-warning{{declaration of built-in function 'vfork' requires inclusion of the header <setjmp.h>}}
+
+void test_vfork() {
+ vfork(); //expected-warning{{Call to function 'vfork' is insecure as it can lead to denial of service situations in the parent process.}}
+}
diff --git a/test/Analysis/self-init.m b/test/Analysis/self-init.m
index 92006a6d2459..019fdcd0c2bf 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.experimental.SelfInit %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.osx.cocoa.SelfInit %s -verify
@class NSZone, NSCoder;
@protocol NSObject
diff --git a/test/Analysis/sizeofpointer.c b/test/Analysis/sizeofpointer.c
index 6d0a2c4d2c26..0c86de88ae28 100644
--- a/test/Analysis/sizeofpointer.c
+++ b/test/Analysis/sizeofpointer.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.SizeofPtr -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core.SizeofPtr -verify %s
struct s {
};
diff --git a/test/Analysis/stack-addr-ps.c b/test/Analysis/stack-addr-ps.c
index bf2a4fa4e13c..558986d308d4 100644
--- a/test/Analysis/stack-addr-ps.c
+++ b/test/Analysis/stack-addr-ps.c
@@ -1,4 +1,3 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -fblocks -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -fblocks -verify %s
int* f1() {
@@ -59,7 +58,7 @@ int struct_test(struct baz byVal, int flag) {
typedef int (^ComparatorBlock)(int a, int b);
ComparatorBlock test_return_block(void) {
ComparatorBlock b = ^int(int a, int b){ return a > b; };
- return b; // expected-warning{{Address of stack-allocated block declared on line 61 returned to caller}}
+ return b; // expected-warning{{Address of stack-allocated block declared on line 60 returned to caller}}
}
ComparatorBlock test_return_block_neg_aux(void);
diff --git a/test/Analysis/stack-addr-ps.cpp b/test/Analysis/stack-addr-ps.cpp
index 0c1ffba4f8c5..b09e43560830 100644
--- a/test/Analysis/stack-addr-ps.cpp
+++ b/test/Analysis/stack-addr-ps.cpp
@@ -1,38 +1,38 @@
-// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
// FIXME: Only the stack-address checking in Sema catches this right now, and
// the stack analyzer doesn't handle the ImplicitCastExpr (lvalue).
const int& g() {
int s;
- return s; // expected-warning{{reference to stack memory associated with local variable 's' returned}}
+ return s; // expected-warning{{Address of stack memory associated with local variable 's' returned}} expected-warning{{reference to stack memory associated with local variable 's' returned}}
}
const int& g2() {
int s1;
int &s2 = s1; // expected-note {{binding reference variable 's2' here}}
- return s2; // expected-warning {{reference to stack memory associated with local variable 's1' returned}}
+ return s2; // expected-warning{{Address of stack memory associated with local variable 's1' returned}} expected-warning {{reference to stack memory associated with local variable 's1' returned}}
}
const int& g3() {
int s1;
int &s2 = s1; // expected-note {{binding reference variable 's2' here}}
int &s3 = s2; // expected-note {{binding reference variable 's3' here}}
- return s3; // expected-warning {{reference to stack memory associated with local variable 's1' returned}}
+ return s3; // expected-warning{{Address of stack memory associated with local variable 's1' returned}} expected-warning {{reference to stack memory associated with local variable 's1' returned}}
}
int get_value();
-const int &get_reference1() { return get_value(); } // 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 'const 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 {{returning reference to local temporary}}
+ return x; // 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_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 {{returning reference to local temporary}}
+ return x2; // expected-warning{{Address of stack memory associated with temporary object of type 'const int' returned}} expected-warning {{returning reference to local temporary}}
}
int global_var;
@@ -44,19 +44,19 @@ int *f1() {
int *f2() {
int x1;
int &x2 = x1; // expected-note {{binding reference variable 'x2' here}}
- return &x2; // expected-warning {{address of stack memory associated with local variable 'x1' returned}}
+ return &x2; // expected-warning{{Address of stack memory associated with local variable 'x1' returned}} expected-warning {{address of stack memory associated with local variable 'x1' returned}}
}
int *f3() {
int x1;
int *const &x2 = &x1; // expected-note {{binding reference variable 'x2' here}}
- return x2; // expected-warning {{address of stack memory associated with local variable 'x1' returned}}
+ return x2; // expected-warning {{address of stack memory associated with local variable 'x1' returned}} expected-warning {{Address of stack memory associated with local variable 'x1' returned to caller}}
}
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 {{returning address of local temporary}}
+ return &x2; // expected-warning{{Address of stack memory associated with temporary object of type 'const int' returned}} expected-warning {{returning address of local temporary}}
}
struct S {
@@ -67,7 +67,7 @@ int *mf() {
S s1;
S &s2 = s1; // expected-note {{binding reference variable 's2' here}}
int &x = s2.x; // expected-note {{binding reference variable 'x' here}}
- return &x; // expected-warning {{address of stack memory associated with local variable 's1' returned}}
+ return &x; // expected-warning{{Address of stack memory associated with local variable 's1' returned}} expected-warning {{address of stack memory associated with local variable 's1' returned}}
}
void *lf() {
@@ -76,14 +76,6 @@ void *lf() {
return x; // expected-warning {{returning address of label, which is local}}
}
-typedef void (^bptr)(void);
-
-bptr bf(int j) {
- __block int i;
- const bptr &qq = ^{ i=0; }; // expected-note {{binding reference variable 'qq' here}}
- return qq; // expected-error {{returning block that lives on the local stack}}
-}
-
template <typename T>
struct TS {
int *get();
diff --git a/test/Analysis/stack-block-returned.cpp b/test/Analysis/stack-block-returned.cpp
new file mode 100644
index 000000000000..af2cec776697
--- /dev/null
+++ b/test/Analysis/stack-block-returned.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -fblocks -verify %s
+
+typedef void (^bptr)(void);
+
+bptr bf(int j) {
+ __block int i;
+ const bptr &qq = ^{ i=0; }; // expected-note {{binding reference variable 'qq' here}}
+ return qq; // expected-error {{returning block that lives on the local stack}}
+}
diff --git a/test/Analysis/stream.c b/test/Analysis/stream.c
index 2f372e755153..e68835e5cfc4 100644
--- a/test/Analysis/stream.c
+++ b/test/Analysis/stream.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=unix.experimental.Stream -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.unix.Stream -analyzer-store region -verify %s
typedef __typeof__(sizeof(int)) size_t;
typedef struct _IO_FILE FILE;
diff --git a/test/Analysis/string-fail.c b/test/Analysis/string-fail.c
index 64ac504d6d80..3bff6d40dd51 100644
--- a/test/Analysis/string-fail.c
+++ b/test/Analysis/string-fail.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.unix.CString,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,experimental.unix.CString,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
// XFAIL: *
// This file is for tests that may eventually go into string.c, or may be
diff --git a/test/Analysis/string.c b/test/Analysis/string.c
index dc97e1a119e0..a71e1f008817 100644
--- a/test/Analysis/string.c
+++ b/test/Analysis/string.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.unix.CString,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,experimental.unix.CString,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,experimental.unix.CString,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,experimental.unix.CString,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
//===----------------------------------------------------------------------===
// Declarations
diff --git a/test/Analysis/temp-obj-dtors-cfg-output.cpp b/test/Analysis/temp-obj-dtors-cfg-output.cpp
index 5ed782c690a1..17864e4c5485 100644
--- a/test/Analysis/temp-obj-dtors-cfg-output.cpp
+++ b/test/Analysis/temp-obj-dtors-cfg-output.cpp
@@ -106,486 +106,661 @@ TestCtorInits::TestCtorInits()
: a(int(A()) + int(B()))
, b() {}
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1: A()
-// CHECK: 2: [B1.1].operator int()
-// CHECK: 3: B()
-// CHECK: 4: [B1.3].operator int()
-// CHECK: 5: int a = int(A().operator int()) + int(B().operator int());
-// CHECK: 6: ~B() (Temporary object destructor)
-// CHECK: 7: ~A() (Temporary object destructor)
-// CHECK: 8: A()
-// CHECK: 9: [B1.8].operator int()
-// CHECK: 10: B()
-// CHECK: 11: [B1.10].operator int()
-// CHECK: 12: foo(int([B1.9]) + int([B1.11]))
-// CHECK: 13: ~B() (Temporary object destructor)
-// CHECK: 14: ~A() (Temporary object destructor)
-// CHECK: 15: int b;
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B10 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B8
-// CHECK: [ B1 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: int b;
-// CHECK: Predecessors (2): B2 B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: ~B() (Temporary object destructor)
-// CHECK: Predecessors (1): B3
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1: [B4.3] && [B5.2]
-// CHECK: 2: foo([B3.1])
-// CHECK: T: [B4.3] && ...
-// CHECK: Predecessors (2): B5 B4
-// CHECK: Successors (2): B2 B1
-// CHECK: [ B4 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: A()
-// CHECK: 3: [B4.2].operator _Bool()
-// CHECK: T: [B4.3] && ...
-// CHECK: Predecessors (2): B6 B7
-// CHECK: Successors (2): B5 B3
-// CHECK: [ B5 ]
-// CHECK: 1: B()
-// CHECK: 2: [B5.1].operator _Bool()
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B3
-// CHECK: [ B6 ]
-// CHECK: 1: ~B() (Temporary object destructor)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B7 ]
-// CHECK: 1: [B8.2] && [B9.2]
-// CHECK: 2: bool a = A().operator _Bool() && B().operator _Bool();
-// CHECK: T: [B8.2] && ...
-// CHECK: Predecessors (2): B9 B8
-// CHECK: Successors (2): B6 B4
-// CHECK: [ B8 ]
-// CHECK: 1: A()
-// CHECK: 2: [B8.1].operator _Bool()
-// CHECK: T: [B8.2] && ...
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (2): B9 B7
-// CHECK: [ B9 ]
-// CHECK: 1: B()
-// CHECK: 2: [B9.1].operator _Bool()
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (1): B7
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B10 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B8
-// CHECK: [ B1 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: int b;
-// CHECK: Predecessors (2): B2 B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: ~B() (Temporary object destructor)
-// CHECK: Predecessors (1): B3
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1: [B4.3] || [B5.2]
-// CHECK: 2: foo([B3.1])
-// CHECK: T: [B4.3] || ...
-// CHECK: Predecessors (2): B5 B4
-// CHECK: Successors (2): B1 B2
-// CHECK: [ B4 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: A()
-// CHECK: 3: [B4.2].operator _Bool()
-// CHECK: T: [B4.3] || ...
-// CHECK: Predecessors (2): B6 B7
-// CHECK: Successors (2): B3 B5
-// CHECK: [ B5 ]
-// CHECK: 1: B()
-// CHECK: 2: [B5.1].operator _Bool()
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B3
-// CHECK: [ B6 ]
-// CHECK: 1: ~B() (Temporary object destructor)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B7 ]
-// CHECK: 1: [B8.2] || [B9.2]
-// CHECK: 2: bool a = A().operator _Bool() || B().operator _Bool();
-// CHECK: T: [B8.2] || ...
-// CHECK: Predecessors (2): B9 B8
-// CHECK: Successors (2): B4 B6
-// CHECK: [ B8 ]
-// CHECK: 1: A()
-// CHECK: 2: [B8.1].operator _Bool()
-// CHECK: T: [B8.2] || ...
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (2): B7 B9
-// CHECK: [ B9 ]
-// CHECK: 1: B()
-// CHECK: 2: [B9.1].operator _Bool()
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (1): B7
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B11 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B10
-// CHECK: [ B1 ]
-// CHECK: 1: int b;
-// CHECK: 2: [B7.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B2 B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: foo(0)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1: foo(0)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B4 ]
-// CHECK: 1: ~B() (Temporary object destructor)
-// CHECK: 2: B()
-// CHECK: 3: [B4.2].operator _Bool()
-// CHECK: 4: ~B() (Temporary object destructor)
-// CHECK: T: if [B4.3]
-// CHECK: Predecessors (2): B5 B6
-// CHECK: Successors (2): B3 B2
-// CHECK: [ B5 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: ~A() (Temporary object destructor)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B6 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: ~A() (Temporary object destructor)
-// CHECK: 3: ~A() (Temporary object destructor)
-// CHECK: 4: ~B() (Temporary object destructor)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B7 ]
-// CHECK: 1: [B10.2] ? [B8.2] : [B9.3]
-// CHECK: 2: A a = B().operator _Bool() ? A() : A(B().operator A());
-// CHECK: T: [B10.2] ? ... : ...
-// CHECK: Predecessors (2): B8 B9
-// CHECK: Successors (2): B5 B6
-// CHECK: [ B8 ]
-// CHECK: 1: A()
-// CHECK: 2: [B8.1] (BindTemporary)
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (1): B7
-// CHECK: [ B9 ]
-// CHECK: 1: B()
-// CHECK: 2: [B9.1].operator A()
-// CHECK: 3: A([B9.2]) (BindTemporary)
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (1): B7
-// CHECK: [ B10 ]
-// CHECK: 1: B()
-// CHECK: 2: [B10.1].operator _Bool()
-// CHECK: T: [B10.2] ? ... : ...
-// CHECK: Predecessors (1): B11
-// CHECK: Successors (2): B8 B9
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B14 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B13
-// CHECK: [ B1 ]
-// CHECK: 1: ~B() (Temporary object destructor)
-// CHECK: 2: int b;
-// CHECK: 3: [B10.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B2 B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: ~A() (Temporary object destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: ~A() (Temporary object destructor)
-// CHECK: 3: ~A() (Temporary object destructor)
-// CHECK: 4: ~B() (Temporary object destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B4 ]
-// CHECK: 1: [B7.3] ? [B5.2] : [B6.3]
-// CHECK: 2: foo([B4.1])
-// CHECK: T: [B7.3] ? ... : ...
-// CHECK: Predecessors (2): B5 B6
-// CHECK: Successors (2): B2 B3
-// CHECK: [ B5 ]
-// CHECK: 1: A()
-// CHECK: 2: [B5.1] (BindTemporary)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B6 ]
-// CHECK: 1: B()
-// CHECK: 2: [B6.1].operator A()
-// CHECK: 3: A([B6.2]) (BindTemporary)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B7 ]
-// CHECK: 1: ~B() (Temporary object destructor)
-// CHECK: 2: B()
-// CHECK: 3: [B7.2].operator _Bool()
-// CHECK: T: [B7.3] ? ... : ...
-// CHECK: Predecessors (2): B8 B9
-// CHECK: Successors (2): B5 B6
-// CHECK: [ B8 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (1): B7
-// CHECK: [ B9 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: ~A() (Temporary object destructor)
-// CHECK: 3: ~B() (Temporary object destructor)
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (1): B7
-// CHECK: [ B10 ]
-// CHECK: 1: [B13.2] ? [B11.2] : [B12.3]
-// CHECK: 2: const A &a = B().operator _Bool() ? A() : A(B().operator A());
-// CHECK: T: [B13.2] ? ... : ...
-// CHECK: Predecessors (2): B11 B12
-// CHECK: Successors (2): B8 B9
-// CHECK: [ B11 ]
-// CHECK: 1: A()
-// CHECK: 2: [B11.1] (BindTemporary)
-// CHECK: Predecessors (1): B13
-// CHECK: Successors (1): B10
-// CHECK: [ B12 ]
-// CHECK: 1: B()
-// CHECK: 2: [B12.1].operator A()
-// CHECK: 3: A([B12.2]) (BindTemporary)
-// CHECK: Predecessors (1): B13
-// CHECK: Successors (1): B10
-// CHECK: [ B13 ]
-// CHECK: 1: B()
-// CHECK: 2: [B13.1].operator _Bool()
-// CHECK: T: [B13.2] ? ... : ...
-// CHECK: Predecessors (1): B14
-// CHECK: Successors (2): B11 B12
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B8 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B7
-// CHECK: [ B1 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: int b;
-// CHECK: 3: [B4.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B2 B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: ~A() (Temporary object destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B4 ]
-// CHECK: 1: [B7.2] ?: [B6.2]
-// CHECK: 2: A a = A() ?: A();
-// CHECK: T: [B7.3] ? ... : ...
-// CHECK: Predecessors (2): B5 B6
-// CHECK: Successors (2): B2 B3
-// CHECK: [ B5 ]
-// CHECK: 1:
-// CHECK: 2: [B5.1] (BindTemporary)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B6 ]
-// CHECK: 1: A()
-// CHECK: 2: [B6.1] (BindTemporary)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B7 ]
-// CHECK: 1: A()
-// CHECK: 2: [B7.1] (BindTemporary)
-// CHECK: 3: .operator _Bool()
-// CHECK: T: [B7.3] ? ... : ...
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (2): B5 B6
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B13 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B12
-// CHECK: [ B1 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: int b;
-// CHECK: 3: [B9.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B2 B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: ~A() (Temporary object destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B4 ]
-// CHECK: 1: [B7.3] ?: [B6.2]
-// CHECK: 2: foo([B4.1])
-// CHECK: T: [B7.4] ? ... : ...
-// CHECK: Predecessors (2): B5 B6
-// CHECK: Successors (2): B2 B3
-// CHECK: [ B5 ]
-// CHECK: 1:
-// CHECK: 2: [B5.1] (BindTemporary)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B6 ]
-// CHECK: 1: A()
-// CHECK: 2: [B6.1] (BindTemporary)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B7 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: A()
-// CHECK: 3: [B7.2] (BindTemporary)
-// CHECK: 4: .operator _Bool()
-// CHECK: T: [B7.4] ? ... : ...
-// CHECK: Predecessors (2): B9 B8
-// CHECK: Successors (2): B5 B6
-// CHECK: [ B8 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: Predecessors (1): B9
-// CHECK: Successors (1): B7
-// CHECK: [ B9 ]
-// CHECK: 1: [B12.2] ?: [B11.2]
-// CHECK: 2: const A &a = A() ?: A();
-// CHECK: T: [B12.3] ? ... : ...
-// CHECK: Predecessors (2): B10 B11
-// CHECK: Successors (2): B7 B8
-// CHECK: [ B10 ]
-// CHECK: 1:
-// CHECK: 2: [B10.1] (BindTemporary)
-// CHECK: Predecessors (1): B12
-// CHECK: Successors (1): B9
-// CHECK: [ B11 ]
-// CHECK: 1: A()
-// CHECK: 2: [B11.1] (BindTemporary)
-// CHECK: Predecessors (1): B12
-// CHECK: Successors (1): B9
-// CHECK: [ B12 ]
-// CHECK: 1: A()
-// CHECK: 2: [B12.1] (BindTemporary)
-// CHECK: 3: .operator _Bool()
-// CHECK: T: [B12.3] ? ... : ...
-// CHECK: Predecessors (1): B13
-// CHECK: Successors (2): B10 B11
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1: A()
-// CHECK: 2: A a = A();
-// CHECK: 3: ~A() (Temporary object destructor)
-// CHECK: 4: int b;
-// CHECK: 5: [B1.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1: A()
-// CHECK: 2: const A &a = A();
-// CHECK: 3: A()
-// CHECK: 4: foo([B1.3])
-// CHECK: 5: ~A() (Temporary object destructor)
-// CHECK: 6: int b;
-// CHECK: 7: [B1.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1: A::make()
-// CHECK: 2: A a = A::make();
-// CHECK: 3: ~A() (Temporary object destructor)
-// CHECK: 4: int b;
-// CHECK: 5: [B1.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1: A::make()
-// CHECK: 2: const A &a = A::make();
-// CHECK: 3: A::make()
-// CHECK: 4: foo([B1.3])
-// CHECK: 5: ~A() (Temporary object destructor)
-// CHECK: 6: int b;
-// CHECK: 7: [B1.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1: int a;
-// CHECK: 2: A()
-// CHECK: 3: [B1.2].operator int()
-// CHECK: 4: a = [B1.3]
-// CHECK: 5: ~A() (Temporary object destructor)
-// CHECK: 6: int b;
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1: A()
-// CHECK: 2: [B1.1].operator int()
-// CHECK: 3: B()
-// CHECK: 4: [B1.3].operator int()
-// CHECK: 5: a(int([B1.2]) + int([B1.4])) (Member initializer)
-// CHECK: 6: ~B() (Temporary object destructor)
-// CHECK: 7: ~A() (Temporary object destructor)
-// CHECK: 8: b(/*implicit*/int()) (Member initializer)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
+// CHECK: [ B2 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B1
+// CHECK: [ B1 ]
+// CHECK: 1: A()
+// CHECK: 2: [B1.1] (BindTemporary)
+// CHECK: 3: [B1.2].operator int
+// CHECK: 4: [B1.3]()
+// CHECK: 5: [B1.4]
+// CHECK: 6: int([B1.5])
+// CHECK: 7: B()
+// CHECK: 8: [B1.7] (BindTemporary)
+// CHECK: 9: [B1.8].operator int
+// CHECK: 10: [B1.9]()
+// CHECK: 11: [B1.10]
+// CHECK: 12: int([B1.11])
+// CHECK: 13: [B1.6] + [B1.12]
+// 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()
+// CHECK: 18: [B1.17] (BindTemporary)
+// CHECK: 19: [B1.18].operator int
+// CHECK: 20: [B1.19]()
+// CHECK: 21: [B1.20]
+// CHECK: 22: int([B1.21])
+// CHECK: 23: B()
+// CHECK: 24: [B1.23] (BindTemporary)
+// CHECK: 25: [B1.24].operator int
+// CHECK: 26: [B1.25]()
+// CHECK: 27: [B1.26]
+// CHECK: 28: int([B1.27])
+// CHECK: 29: [B1.22] + [B1.28]
+// CHECK: 30: foo
+// CHECK: 31: [B1.30]
+// CHECK: 32: [B1.31]([B1.29])
+// CHECK: 33: ~B() (Temporary object destructor)
+// CHECK: 34: ~A() (Temporary object destructor)
+// CHECK: 35: int b;
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (1): B0
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B10 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B8
+// CHECK: [ B1 ]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: int b;
+// CHECK: Predecessors (2): B2 B3
+// CHECK: Successors (1): B0
+// CHECK: [ B2 ]
+// CHECK: 1: ~B() (Temporary object destructor)
+// CHECK: Predecessors (1): B3
+// CHECK: Successors (1): B1
+// CHECK: [ B3 ]
+// CHECK: 1: [B4.5] && [B5.4]
+// CHECK: 2: foo
+// CHECK: 3: [B3.2]
+// CHECK: 4: [B3.3]([B3.1])
+// CHECK: T: [B4.5] && ...
+// CHECK: Predecessors (2): B5 B4
+// CHECK: Successors (2): B2 B1
+// CHECK: [ B4 ]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: A()
+// CHECK: 3: [B4.2] (BindTemporary)
+// CHECK: 4: [B4.3].operator _Bool
+// CHECK: 5: [B4.4]()
+// CHECK: T: [B4.5] && ...
+// CHECK: Predecessors (2): B6 B7
+// CHECK: Successors (2): B5 B3
+// CHECK: [ B5 ]
+// CHECK: 1: B()
+// CHECK: 2: [B5.1] (BindTemporary)
+// CHECK: 3: [B5.2].operator _Bool
+// CHECK: 4: [B5.3]()
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B3
+// CHECK: [ B6 ]
+// CHECK: 1: ~B() (Temporary object destructor)
+// CHECK: Predecessors (1): B7
+// CHECK: Successors (1): B4
+// CHECK: [ B7 ]
+// CHECK: 1: [B8.4] && [B9.4]
+// CHECK: 2: bool a = A().operator _Bool() && B().operator _Bool();
+// CHECK: T: [B8.4] && ...
+// CHECK: Predecessors (2): B9 B8
+// CHECK: Successors (2): B6 B4
+// CHECK: [ B8 ]
+// CHECK: 1: A()
+// CHECK: 2: [B8.1] (BindTemporary)
+// CHECK: 3: [B8.2].operator _Bool
+// CHECK: 4: [B8.3]()
+// CHECK: T: [B8.4] && ...
+// CHECK: Predecessors (1): B10
+// CHECK: Successors (2): B9 B7
+// CHECK: [ B9 ]
+// CHECK: 1: B()
+// CHECK: 2: [B9.1] (BindTemporary)
+// CHECK: 3: [B9.2].operator _Bool
+// CHECK: 4: [B9.3]()
+// CHECK: Predecessors (1): B8
+// CHECK: Successors (1): B7
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B10 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B8
+// CHECK: [ B1 ]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: int b;
+// CHECK: Predecessors (2): B2 B3
+// CHECK: Successors (1): B0
+// CHECK: [ B2 ]
+// CHECK: 1: ~B() (Temporary object destructor)
+// CHECK: Predecessors (1): B3
+// CHECK: Successors (1): B1
+// CHECK: [ B3 ]
+// CHECK: 1: [B4.5] || [B5.4]
+// CHECK: 2: foo
+// CHECK: 3: [B3.2]
+// CHECK: 4: [B3.3]([B3.1])
+// CHECK: T: [B4.5] || ...
+// CHECK: Predecessors (2): B5 B4
+// CHECK: Successors (2): B1 B2
+// CHECK: [ B4 ]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: A()
+// CHECK: 3: [B4.2] (BindTemporary)
+// CHECK: 4: [B4.3].operator _Bool
+// CHECK: 5: [B4.4]()
+// CHECK: T: [B4.5] || ...
+// CHECK: Predecessors (2): B6 B7
+// CHECK: Successors (2): B3 B5
+// CHECK: [ B5 ]
+// CHECK: 1: B()
+// CHECK: 2: [B5.1] (BindTemporary)
+// CHECK: 3: [B5.2].operator _Bool
+// CHECK: 4: [B5.3]()
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B3
+// CHECK: [ B6 ]
+// CHECK: 1: ~B() (Temporary object destructor)
+// CHECK: Predecessors (1): B7
+// CHECK: Successors (1): B4
+// CHECK: [ B7 ]
+// CHECK: 1: [B8.4] || [B9.4]
+// CHECK: 2: bool a = A().operator _Bool() || B().operator _Bool();
+// CHECK: T: [B8.4] || ...
+// CHECK: Predecessors (2): B9 B8
+// CHECK: Successors (2): B4 B6
+// CHECK: [ B8 ]
+// CHECK: 1: A()
+// CHECK: 2: [B8.1] (BindTemporary)
+// CHECK: 3: [B8.2].operator _Bool
+// CHECK: 4: [B8.3]()
+// CHECK: T: [B8.4] || ...
+// CHECK: Predecessors (1): B10
+// CHECK: Successors (2): B7 B9
+// CHECK: [ B9 ]
+// CHECK: 1: B()
+// CHECK: 2: [B9.1] (BindTemporary)
+// CHECK: 3: [B9.2].operator _Bool
+// CHECK: 4: [B9.3]()
+// CHECK: Predecessors (1): B8
+// CHECK: Successors (1): B7
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B11 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B10
+// CHECK: [ B1 ]
+// CHECK: 1: int b;
+// CHECK: 2: [B7.4].~A() (Implicit destructor)
+// CHECK: Predecessors (2): B2 B3
+// CHECK: Successors (1): B0
+// CHECK: [ B2 ]
+// CHECK: 1: 0
+// CHECK: 2: foo
+// CHECK: 3: [B2.2]
+// CHECK: 4: [B2.3]([B2.1])
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B1
+// CHECK: [ B3 ]
+// CHECK: 1: 0
+// CHECK: 2: foo
+// CHECK: 3: [B3.2]
+// CHECK: 4: [B3.3]([B3.1])
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B1
+// CHECK: [ B4 ]
+// CHECK: 1: ~B() (Temporary object destructor)
+// CHECK: 2: B()
+// CHECK: 3: [B4.2] (BindTemporary)
+// CHECK: 4: [B4.3].operator _Bool
+// CHECK: 5: [B4.4]()
+// CHECK: 6: ~B() (Temporary object destructor)
+// CHECK: T: if [B4.5]
+// CHECK: Predecessors (2): B5 B6
+// CHECK: Successors (2): B3 B2
+// CHECK: [ B5 ]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: ~A() (Temporary object destructor)
+// CHECK: Predecessors (1): B7
+// CHECK: Successors (1): B4
+// CHECK: [ B6 ]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: ~A() (Temporary object destructor)
+// CHECK: 3: ~A() (Temporary object destructor)
+// CHECK: 4: ~B() (Temporary object destructor)
+// CHECK: Predecessors (1): B7
+// CHECK: Successors (1): B4
+// CHECK: [ B7 ]
+// CHECK: 1: [B10.4] ? [B8.5] : [B9.13]
+// CHECK: 2: [B7.1]
+// CHECK: 3: [B7.2]
+// CHECK: 4: A a = B().operator _Bool() ? A() : A(B().operator A());
+// CHECK: T: [B10.4] ? ... : ...
+// CHECK: Predecessors (2): B8 B9
+// CHECK: Successors (2): B5 B6
+// CHECK: [ B8 ]
+// CHECK: 1: A()
+// CHECK: 2: [B8.1] (BindTemporary)
+// CHECK: 3: [B8.2]
+// CHECK: 4: [B8.3]
+// CHECK: 5: [B8.4] (BindTemporary)
+// CHECK: Predecessors (1): B10
+// CHECK: Successors (1): B7
+// CHECK: [ B9 ]
+// CHECK: 1: B()
+// CHECK: 2: [B9.1] (BindTemporary)
+// CHECK: 3: [B9.2].operator A
+// CHECK: 4: [B9.3]()
+// CHECK: 5: [B9.4] (BindTemporary)
+// CHECK: 6: [B9.5]
+// CHECK: 7: [B9.6]
+// CHECK: 8: [B9.7]
+// CHECK: 9: [B9.8] (BindTemporary)
+// CHECK: 10: A([B9.9])
+// CHECK: 11: [B9.10]
+// CHECK: 12: [B9.11]
+// CHECK: 13: [B9.12] (BindTemporary)
+// CHECK: Predecessors (1): B10
+// CHECK: Successors (1): B7
+// CHECK: [ B10 ]
+// CHECK: 1: B()
+// CHECK: 2: [B10.1] (BindTemporary)
+// CHECK: 3: [B10.2].operator _Bool
+// CHECK: 4: [B10.3]()
+// CHECK: T: [B10.4] ? ... : ...
+// CHECK: Predecessors (1): B11
+// CHECK: Successors (2): B8 B9
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B14 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B13
+// CHECK: [ B1 ]
+// CHECK: 1: ~B() (Temporary object destructor)
+// CHECK: 2: int b;
+// CHECK: 3: [B10.4].~A() (Implicit destructor)
+// CHECK: Predecessors (2): B2 B3
+// CHECK: Successors (1): B0
+// CHECK: [ B2 ]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: ~A() (Temporary object destructor)
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B1
+// CHECK: [ B3 ]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: ~A() (Temporary object destructor)
+// CHECK: 3: ~A() (Temporary object destructor)
+// CHECK: 4: ~B() (Temporary object destructor)
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B1
+// CHECK: [ B4 ]
+// CHECK: 1: [B7.5] ? [B5.5] : [B6.13]
+// CHECK: 2: [B4.1]
+// CHECK: 3: [B4.2]
+// CHECK: 4: foo
+// CHECK: 5: [B4.4]
+// CHECK: 6: [B4.5]([B4.3])
+// CHECK: T: [B7.5] ? ... : ...
+// CHECK: Predecessors (2): B5 B6
+// CHECK: Successors (2): B2 B3
+// CHECK: [ B5 ]
+// CHECK: 1: A()
+// CHECK: 2: [B5.1] (BindTemporary)
+// CHECK: 3: [B5.2]
+// CHECK: 4: [B5.3]
+// CHECK: 5: [B5.4] (BindTemporary)
+// CHECK: Predecessors (1): B7
+// CHECK: Successors (1): B4
+// CHECK: [ B6 ]
+// CHECK: 1: B()
+// CHECK: 2: [B6.1] (BindTemporary)
+// CHECK: 3: [B6.2].operator A
+// CHECK: 4: [B6.3]()
+// CHECK: 5: [B6.4] (BindTemporary)
+// CHECK: 6: [B6.5]
+// CHECK: 7: [B6.6]
+// CHECK: 8: [B6.7]
+// CHECK: 9: [B6.8] (BindTemporary)
+// CHECK: 10: A([B6.9])
+// CHECK: 11: [B6.10]
+// CHECK: 12: [B6.11]
+// CHECK: 13: [B6.12] (BindTemporary)
+// CHECK: Predecessors (1): B7
+// CHECK: Successors (1): B4
+// CHECK: [ B7 ]
+// CHECK: 1: ~B() (Temporary object destructor)
+// CHECK: 2: B()
+// CHECK: 3: [B7.2] (BindTemporary)
+// CHECK: 4: [B7.3].operator _Bool
+// CHECK: 5: [B7.4]()
+// CHECK: T: [B7.5] ? ... : ...
+// CHECK: Predecessors (2): B8 B9
+// CHECK: Successors (2): B5 B6
+// CHECK: [ B8 ]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: Predecessors (1): B10
+// CHECK: Successors (1): B7
+// CHECK: [ B9 ]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: ~A() (Temporary object destructor)
+// CHECK: 3: ~B() (Temporary object destructor)
+// CHECK: Predecessors (1): B10
+// CHECK: Successors (1): B7
+// CHECK: [ B10 ]
+// CHECK: 1: [B13.4] ? [B11.5] : [B12.13]
+// CHECK: 2: [B10.1]
+// CHECK: 3: [B10.2]
+// CHECK: 4: const A &a = B().operator _Bool() ? A() : A(B().operator A());
+// CHECK: T: [B13.4] ? ... : ...
+// CHECK: Predecessors (2): B11 B12
+// CHECK: Successors (2): B8 B9
+// CHECK: [ B11 ]
+// CHECK: 1: A()
+// CHECK: 2: [B11.1] (BindTemporary)
+// CHECK: 3: [B11.2]
+// CHECK: 4: [B11.3]
+// CHECK: 5: [B11.4] (BindTemporary)
+// CHECK: Predecessors (1): B13
+// CHECK: Successors (1): B10
+// CHECK: [ B12 ]
+// CHECK: 1: B()
+// CHECK: 2: [B12.1] (BindTemporary)
+// CHECK: 3: [B12.2].operator A
+// CHECK: 4: [B12.3]()
+// CHECK: 5: [B12.4] (BindTemporary)
+// CHECK: 6: [B12.5]
+// CHECK: 7: [B12.6]
+// CHECK: 8: [B12.7]
+// CHECK: 9: [B12.8] (BindTemporary)
+// CHECK: 10: A([B12.9])
+// CHECK: 11: [B12.10]
+// CHECK: 12: [B12.11]
+// CHECK: 13: [B12.12] (BindTemporary)
+// CHECK: Predecessors (1): B13
+// CHECK: Successors (1): B10
+// CHECK: [ B13 ]
+// CHECK: 1: B()
+// CHECK: 2: [B13.1] (BindTemporary)
+// CHECK: 3: [B13.2].operator _Bool
+// CHECK: 4: [B13.3]()
+// CHECK: T: [B13.4] ? ... : ...
+// CHECK: Predecessors (1): B14
+// CHECK: Successors (2): B11 B12
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B8 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B7
+// CHECK: [ B1 ]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: int b;
+// CHECK: 3: [B4.4].~A() (Implicit destructor)
+// CHECK: Predecessors (2): B2 B3
+// CHECK: Successors (1): B0
+// CHECK: [ B2 ]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B1
+// CHECK: [ B3 ]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: ~A() (Temporary object destructor)
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B1
+// CHECK: [ B4 ]
+// CHECK: 1: [B7.2] ?: [B6.5]
+// CHECK: 2: [B4.1]
+// CHECK: 3: [B4.2]
+// CHECK: 4: A a = A() ?: A();
+// CHECK: T: [B7.5] ? ... : ...
+// CHECK: Predecessors (2): B5 B6
+// CHECK: Successors (2): B2 B3
+// CHECK: [ B5 ]
+// CHECK: 1: [B7.3]
+// CHECK: 2: [B7.3]
+// CHECK: 3: [B5.2]
+// CHECK: 4: [B5.3]
+// CHECK: 5: [B5.4] (BindTemporary)
+// CHECK: Predecessors (1): B7
+// CHECK: Successors (1): B4
+// CHECK: [ B6 ]
+// CHECK: 1: A()
+// CHECK: 2: [B6.1] (BindTemporary)
+// CHECK: 3: [B6.2]
+// CHECK: 4: [B6.3]
+// CHECK: 5: [B6.4] (BindTemporary)
+// CHECK: Predecessors (1): B7
+// CHECK: Successors (1): B4
+// CHECK: [ B7 ]
+// CHECK: 1: A()
+// CHECK: 2: [B7.1] (BindTemporary)
+// CHECK: 3:
+// CHECK: 4: [B7.3].operator _Bool
+// CHECK: 5: [B7.4]()
+// CHECK: T: [B7.5] ? ... : ...
+// CHECK: Predecessors (1): B8
+// CHECK: Successors (2): B5 B6
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B13 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B12
+// CHECK: [ B1 ]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: int b;
+// CHECK: 3: [B9.4].~A() (Implicit destructor)
+// CHECK: Predecessors (2): B2 B3
+// CHECK: Successors (1): B0
+// CHECK: [ B2 ]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B1
+// CHECK: [ B3 ]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: ~A() (Temporary object destructor)
+// CHECK: Predecessors (1): B4
+// CHECK: Successors (1): B1
+// CHECK: [ B4 ]
+// CHECK: 1: [B7.3] ?: [B6.5]
+// CHECK: 2: [B4.1]
+// CHECK: 3: [B4.2]
+// CHECK: 4: foo
+// CHECK: 5: [B4.4]
+// CHECK: 6: [B4.5]([B4.3])
+// CHECK: T: [B7.6] ? ... : ...
+// CHECK: Predecessors (2): B5 B6
+// CHECK: Successors (2): B2 B3
+// CHECK: [ B5 ]
+// CHECK: 1: [B7.4]
+// CHECK: 2: [B7.4]
+// CHECK: 3: [B5.2]
+// CHECK: 4: [B5.3]
+// CHECK: 5: [B5.4] (BindTemporary)
+// CHECK: Predecessors (1): B7
+// CHECK: Successors (1): B4
+// CHECK: [ B6 ]
+// CHECK: 1: A()
+// CHECK: 2: [B6.1] (BindTemporary)
+// CHECK: 3: [B6.2]
+// CHECK: 4: [B6.3]
+// CHECK: 5: [B6.4] (BindTemporary)
+// CHECK: Predecessors (1): B7
+// CHECK: Successors (1): B4
+// CHECK: [ B7 ]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: A()
+// CHECK: 3: [B7.2] (BindTemporary)
+// CHECK: 4:
+// CHECK: 5: [B7.4].operator _Bool
+// CHECK: 6: [B7.5]()
+// CHECK: T: [B7.6] ? ... : ...
+// CHECK: Predecessors (2): B9 B8
+// CHECK: Successors (2): B5 B6
+// CHECK: [ B8 ]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: Predecessors (1): B9
+// CHECK: Successors (1): B7
+// CHECK: [ B9 ]
+// CHECK: 1: [B12.2] ?: [B11.5]
+// CHECK: 2: [B9.1]
+// CHECK: 3: [B9.2]
+// CHECK: 4: const A &a = A() ?: A();
+// CHECK: T: [B12.5] ? ... : ...
+// CHECK: Predecessors (2): B10 B11
+// CHECK: Successors (2): B7 B8
+// CHECK: [ B10 ]
+// CHECK: 1: [B12.3]
+// CHECK: 2: [B12.3]
+// CHECK: 3: [B10.2]
+// CHECK: 4: [B10.3]
+// CHECK: 5: [B10.4] (BindTemporary)
+// CHECK: Predecessors (1): B12
+// CHECK: Successors (1): B9
+// CHECK: [ B11 ]
+// CHECK: 1: A()
+// CHECK: 2: [B11.1] (BindTemporary)
+// CHECK: 3: [B11.2]
+// CHECK: 4: [B11.3]
+// CHECK: 5: [B11.4] (BindTemporary)
+// CHECK: Predecessors (1): B12
+// CHECK: Successors (1): B9
+// CHECK: [ B12 ]
+// CHECK: 1: A()
+// CHECK: 2: [B12.1] (BindTemporary)
+// CHECK: 3:
+// CHECK: 4: [B12.3].operator _Bool
+// CHECK: 5: [B12.4]()
+// CHECK: T: [B12.5] ? ... : ...
+// CHECK: Predecessors (1): B13
+// CHECK: Successors (2): B10 B11
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B2 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B1
+// CHECK: [ B1 ]
+// CHECK: 1: A()
+// CHECK: 2: [B1.1] (BindTemporary)
+// CHECK: 3: [B1.2]
+// CHECK: 4: [B1.3]
+// CHECK: 5: A a = A();
+// CHECK: 6: ~A() (Temporary object destructor)
+// CHECK: 7: int b;
+// CHECK: 8: [B1.5].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (1): B0
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B2 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B1
+// CHECK: [ B1 ]
+// CHECK: 1: A()
+// CHECK: 2: [B1.1] (BindTemporary)
+// CHECK: 3: [B1.2]
+// CHECK: 4: [B1.3]
+// CHECK: 5: const A &a = A();
+// CHECK: 6: A()
+// CHECK: 7: [B1.6] (BindTemporary)
+// CHECK: 8: [B1.7]
+// CHECK: 9: [B1.8]
+// CHECK: 10: foo
+// CHECK: 11: [B1.10]
+// CHECK: 12: [B1.11]([B1.9])
+// CHECK: 13: ~A() (Temporary object destructor)
+// CHECK: 14: int b;
+// CHECK: 15: [B1.5].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (1): B0
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B2 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B1
+// CHECK: [ B1 ]
+// CHECK: 1: A::make
+// CHECK: 2: [B1.1]
+// CHECK: 3: [B1.2]()
+// CHECK: 4: [B1.3] (BindTemporary)
+// CHECK: 5: [B1.4]
+// CHECK: 6: [B1.5]
+// CHECK: 7: A a = A::make();
+// CHECK: 8: ~A() (Temporary object destructor)
+// CHECK: 9: int b;
+// CHECK: 10: [B1.7].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (1): B0
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B2 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B1
+// CHECK: [ B1 ]
+// CHECK: 1: A::make
+// CHECK: 2: [B1.1]
+// CHECK: 3: [B1.2]()
+// CHECK: 4: [B1.3] (BindTemporary)
+// CHECK: 5: [B1.4]
+// CHECK: 6: [B1.5]
+// CHECK: 7: const A &a = A::make();
+// CHECK: 8: A::make
+// CHECK: 9: [B1.8]
+// CHECK: 10: [B1.9]()
+// CHECK: 11: [B1.10] (BindTemporary)
+// CHECK: 12: [B1.11]
+// CHECK: 13: [B1.12]
+// CHECK: 14: foo
+// CHECK: 15: [B1.14]
+// CHECK: 16: [B1.15]([B1.13])
+// CHECK: 17: ~A() (Temporary object destructor)
+// CHECK: 18: int b;
+// CHECK: 19: [B1.7].~A() (Implicit destructor)
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (1): B0
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B2 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B1
+// CHECK: [ B1 ]
+// CHECK: 1: int a;
+// CHECK: 2: A()
+// CHECK: 3: [B1.2] (BindTemporary)
+// CHECK: 4: [B1.3].operator int
+// CHECK: 5: [B1.4]()
+// CHECK: 6: a
+// CHECK: 7: [B1.6] = [B1.5]
+// CHECK: 8: ~A() (Temporary object destructor)
+// CHECK: 9: int b;
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (1): B0
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+// CHECK: [ B2 (ENTRY) ]
+// CHECK: Predecessors (0):
+// CHECK: Successors (1): B1
+// CHECK: [ B1 ]
+// CHECK: 1: A()
+// CHECK: 2: [B1.1] (BindTemporary)
+// CHECK: 3: [B1.2].operator int
+// CHECK: 4: [B1.3]()
+// CHECK: 5: [B1.4]
+// CHECK: 6: int([B1.5])
+// CHECK: 7: B()
+// CHECK: 8: [B1.7] (BindTemporary)
+// CHECK: 9: [B1.8].operator int
+// CHECK: 10: [B1.9]()
+// CHECK: 11: [B1.10]
+// CHECK: 12: int([B1.11])
+// CHECK: 13: [B1.6] + [B1.12]
+// CHECK: 14: a([B1.13]) (Member initializer)
+// CHECK: 15: ~B() (Temporary object destructor)
+// CHECK: 16: ~A() (Temporary object destructor)
+// CHECK: 17: /*implicit*/int()
+// CHECK: 18: b([B1.17]) (Member initializer)
+// CHECK: Predecessors (1): B2
+// CHECK: Successors (1): B0
+// CHECK: [ B0 (EXIT) ]
+// CHECK: Predecessors (1): B1
+// CHECK: Successors (0):
+
diff --git a/test/Analysis/undef-buffers.c b/test/Analysis/undef-buffers.c
index df124b10d10e..cfdd7f4e1a83 100644
--- a/test/Analysis/undef-buffers.c
+++ b/test/Analysis/undef-buffers.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.experimental,core.uninitialized -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.unix,core.uninitialized -analyzer-store=region -verify %s
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
void free(void *);
@@ -15,6 +15,17 @@ char stackBased2 () {
return buf[0]; // expected-warning{{Undefined}}
}
+// Exercise the conditional visitor. Radar://10105448
+char stackBased3 (int *x) {
+ char buf[2];
+ int *y;
+ buf[0] = 'a';
+ if (!(y = x)) {
+ return buf[1]; // expected-warning{{Undefined}}
+ }
+ return buf[0];
+}
+
char heapBased1 () {
char *buf = malloc(2);
buf[0] = 'a';
diff --git a/test/Analysis/uninit-msg-expr.m b/test/Analysis/uninit-msg-expr.m
index 743d36ff56de..19fdf611c865 100644
--- a/test/Analysis/uninit-msg-expr.m
+++ b/test/Analysis/uninit-msg-expr.m
@@ -1,4 +1,3 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
//===----------------------------------------------------------------------===//
diff --git a/test/Analysis/uninit-ps-rdar6145427.m b/test/Analysis/uninit-ps-rdar6145427.m
index f4df91396a84..c18116f21ae5 100644
--- a/test/Analysis/uninit-ps-rdar6145427.m
+++ b/test/Analysis/uninit-ps-rdar6145427.m
@@ -1,4 +1,3 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -analyzer-store=basic %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -analyzer-store=region %s
// Delta-Debugging reduced preamble.
diff --git a/test/Analysis/uninit-vals-ps.c b/test/Analysis/uninit-vals-ps.c
index 915961aa11da..f3011570a85a 100644
--- a/test/Analysis/uninit-vals-ps.c
+++ b/test/Analysis/uninit-vals-ps.c
@@ -1,4 +1,3 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
struct FPRec {
diff --git a/test/Analysis/uninit-vals.m b/test/Analysis/uninit-vals.m
index 4b7e6f42cf8f..4ba26f59b720 100644
--- a/test/Analysis/uninit-vals.m
+++ b/test/Analysis/uninit-vals.m
@@ -1,4 +1,3 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
typedef unsigned int NSUInteger;
diff --git a/test/Analysis/unix-fns.c b/test/Analysis/unix-fns.c
index 5df6b37bb91a..cf5ca810de33 100644
--- a/test/Analysis/unix-fns.c
+++ b/test/Analysis/unix-fns.c
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=unix.API,osx.API %s -analyzer-store=region -fblocks -verify
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=unix.API,osx.API %s -analyzer-store=basic -fblocks -verify
struct _opaque_pthread_once_t {
long __sig;
diff --git a/test/Analysis/unreachable-code-path.c b/test/Analysis/unreachable-code-path.c
index 7df52402e735..da14f4c010d6 100644
--- a/test/Analysis/unreachable-code-path.c
+++ b/test/Analysis/unreachable-code-path.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.DeadStores,deadcode.experimental.UnreachableCode -verify -analyzer-opt-analyze-nested-blocks -Wno-unused-value %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.DeadStores,experimental.deadcode.UnreachableCode -verify -analyzer-opt-analyze-nested-blocks -Wno-unused-value %s
extern void foo(int a);
diff --git a/test/Analysis/unused-ivars.m b/test/Analysis/unused-ivars.m
index 931c84a3745a..42bde1004dcc 100644
--- a/test/Analysis/unused-ivars.m
+++ b/test/Analysis/unused-ivars.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fblocks -analyze -analyzer-checker=osx.cocoa.UnusedIvars %s -verify
+// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=osx.cocoa.UnusedIvars %s -verify
//===--- BEGIN: Delta-debugging reduced headers. --------------------------===//
@@ -97,7 +97,7 @@ int radar_7254495(RDar7254495 *a) {
@end
//===----------------------------------------------------------------------===//
// <rdar://problem/8481311> Unused bitfield ivars trigger cause weird
-// diagnostic: "Instance variable '' in class…"
+// diagnostic: "Instance variable '' in class..."
//===----------------------------------------------------------------------===//
@interface RDar8481311 {
diff --git a/test/Analysis/variadic-method-types.m b/test/Analysis/variadic-method-types.m
index 03c309a5004a..caa0c59debba 100644
--- a/test/Analysis/variadic-method-types.m
+++ b/test/Analysis/variadic-method-types.m
@@ -1,4 +1,3 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.VariadicMethodTypes -analyzer-store=basic -fblocks -verify %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.VariadicMethodTypes -analyzer-store=region -fblocks -verify %s
//===----------------------------------------------------------------------===//
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 0f00e5075a52..b7356c2de01a 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -2,6 +2,7 @@ set(CLANG_TEST_DIRECTORIES
"Analysis"
"CodeCompletion"
"CodeGen"
+ "CodeGenCUDA"
"CodeGenCXX"
"CodeGenObjC"
"CodeGenOpenCL"
@@ -88,7 +89,7 @@ if(PYTHONINTERP_FOUND)
set_target_properties(clang-test PROPERTIES FOLDER "Clang tests")
if( NOT CLANG_BUILT_STANDALONE )
- add_custom_target(check-all
+ add_custom_target(check-all
COMMAND ${PYTHON_EXECUTABLE}
${LIT}
--param build_config=${CMAKE_CFG_INTDIR}
@@ -99,18 +100,19 @@ if(PYTHONINTERP_FOUND)
COMMENT "Running Clang and LLVM regression tests")
add_dependencies(check-all clang-test.deps)
if ( LLVM_INCLUDE_TESTS )
- add_dependencies(clang-test.deps check.deps ClangUnitTests)
+ add_dependencies(clang-test.deps ClangUnitTests)
+ add_dependencies(check-all check.deps)
endif ( LLVM_INCLUDE_TESTS )
add_dependencies(clang-test.deps
- llvm-dis llc opt
+ llvm-dis llc opt
FileCheck count not
)
- set_target_properties(check-all PROPERTIES FOLDER "Clang tests")
- endif()
+ set_target_properties(check-all PROPERTIES FOLDER "Clang tests")
+ endif()
add_dependencies(clang-test clang-test.deps)
add_dependencies(clang-test.deps
- clang clang-headers c-index-test arcmt-test c-arcmt-test
+ clang clang-headers c-index-test diagtool arcmt-test c-arcmt-test
)
endif()
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp b/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp
index 3fde0daa96cf..c35af1def208 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp
@@ -44,3 +44,21 @@ void resolves_to_different() {
v.set<double>(3.2);
}
}
+
+namespace rdar9915664 {
+ struct A {
+ template<typename T> void a();
+ };
+
+ struct B : A { };
+
+ struct C : A { };
+
+ struct D : B, C {
+ A &getA() { return static_cast<B&>(*this); }
+
+ void test_a() {
+ getA().a<int>();
+ }
+ };
+}
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.classref/p3.cpp b/test/CXX/basic/basic.lookup/basic.lookup.classref/p3.cpp
index 4a0b38737976..cd7e669527bc 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.classref/p3.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.classref/p3.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// C++0x [basic.lookup.classref]p3:
-// If the unqualified-id is ∼type-name, the type-name is looked up in the
+// If the unqualified-id is ~type-name, the type-name is looked up in the
// context of the entire postfix-expression. If the type T of the object
// expression is of a class type C, the type-name is also looked up in the
// scope of class C. At least one of the lookups shall find a name that
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.qual/p6-0x.cpp b/test/CXX/basic/basic.lookup/basic.lookup.qual/p6-0x.cpp
index 355ac4a2ecad..c745c8451bc8 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.qual/p6-0x.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.qual/p6-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// XFAIL: *
// Our C++0x doesn't currently have specialized destructor name handling,
// since the specification is still in flux.
diff --git a/test/CXX/basic/basic.scope/basic.scope.local/p4-0x.cpp b/test/CXX/basic/basic.scope/basic.scope.local/p4-0x.cpp
index d930f97ce791..cd51c78a5e9c 100644
--- a/test/CXX/basic/basic.scope/basic.scope.local/p4-0x.cpp
+++ b/test/CXX/basic/basic.scope/basic.scope.local/p4-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
void f() {
int b;
diff --git a/test/CXX/basic/basic.scope/basic.scope.pdecl/p3.cpp b/test/CXX/basic/basic.scope/basic.scope.pdecl/p3.cpp
index 751c0df6b867..407a5f744e37 100644
--- a/test/CXX/basic/basic.scope/basic.scope.pdecl/p3.cpp
+++ b/test/CXX/basic/basic.scope/basic.scope.pdecl/p3.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// Classes.
namespace Class {
diff --git a/test/CXX/basic/basic.types/p10.cpp b/test/CXX/basic/basic.types/p10.cpp
new file mode 100644
index 000000000000..3b438d15f28b
--- /dev/null
+++ b/test/CXX/basic/basic.types/p10.cpp
@@ -0,0 +1,127 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+struct NonLiteral { NonLiteral(); };
+
+// A type is a literal type if it is:
+
+// - a scalar type
+constexpr int f1(double);
+
+// - a reference type
+struct S { S(); };
+constexpr int f2(S &);
+
+// - a class type that has all of the following properties:
+
+// - it has a trivial destructor
+struct UserProvDtor {
+ constexpr UserProvDtor(); // expected-error {{non-literal type 'UserProvDtor' cannot have constexpr members}}
+ ~UserProvDtor(); // expected-note {{has a user-provided destructor}}
+};
+struct NonTrivDtor {
+ constexpr NonTrivDtor(); // expected-error {{non-literal type 'NonTrivDtor' cannot have constexpr members}}
+ virtual ~NonTrivDtor() = default; // expected-note {{has a non-trivial destructor}}
+};
+struct NonTrivDtorBase {
+ ~NonTrivDtorBase();
+};
+template<typename T>
+struct DerivedFromNonTrivDtor : T { // expected-note {{'DerivedFromNonTrivDtor<NonTrivDtorBase>' is not literal because it has base class 'NonTrivDtorBase' of non-literal type}}
+ constexpr DerivedFromNonTrivDtor();
+};
+constexpr int f(DerivedFromNonTrivDtor<NonTrivDtorBase>); // expected-error {{constexpr function's 1st parameter type 'DerivedFromNonTrivDtor<NonTrivDtorBase>' is not a literal type}}
+struct TrivDtor {
+ constexpr TrivDtor();
+};
+// FIXME: when building DefinitionData we look at 'isUserProvided' before it's set up!
+#if 0
+struct TrivDefaultedDtor {
+ constexpr TrivDefaultedDtor();
+ ~TrivDefaultedDtor() = default;
+};
+#endif
+
+// - it is an aggregate type or has at least one constexpr constructor or
+// constexpr constructor template that is not a copy or move constructor
+struct Agg {
+ int a;
+ char *b;
+};
+constexpr int f3(Agg a) { return a.a; }
+struct CtorTemplate {
+ template<typename T> constexpr CtorTemplate(T);
+};
+struct CopyCtorOnly { // expected-note {{'CopyCtorOnly' is not literal because it is not an aggregate and has no constexpr constructors other than copy or move constructors}}
+ constexpr CopyCtorOnly(CopyCtorOnly&); // expected-error {{non-literal type 'CopyCtorOnly' cannot have constexpr members}}
+};
+struct MoveCtorOnly { // expected-note {{no constexpr constructors other than copy or move constructors}}
+ constexpr MoveCtorOnly(MoveCtorOnly&&); // expected-error {{non-literal type 'MoveCtorOnly' cannot have constexpr members}}
+};
+template<typename T>
+struct CtorArg { // expected-note {{no constexpr constructors other than copy or move constructors}}
+ constexpr CtorArg(T); // expected-note {{constructor template instantiation is not constexpr because 1st parameter type 'NonLiteral' is not a literal type}}
+};
+constexpr int f(CtorArg<int>);
+constexpr int f(CtorArg<NonLiteral>); // expected-error {{not a literal type}}
+// We have a special-case diagnostic for classes with virtual base classes.
+struct VBase {};
+struct HasVBase : virtual VBase {}; // expected-note 2{{virtual base class declared here}}
+struct Derived : HasVBase {
+ constexpr Derived(); // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
+};
+template<typename T> struct DerivedFromVBase : T { // expected-note {{struct with virtual base class is not a literal type}}
+ constexpr DerivedFromVBase();
+};
+constexpr int f(DerivedFromVBase<HasVBase>); // expected-error {{constexpr function's 1st parameter type 'DerivedFromVBase<HasVBase>' is not a literal type}}
+
+// - it has all non-static data members and base classes of literal types
+struct NonLitMember {
+ S s; // expected-note {{has data member 's' of non-literal type 'S'}}
+};
+constexpr int f(NonLitMember); // expected-error {{1st parameter type 'NonLitMember' is not a literal type}}
+struct NonLitBase :
+ S { // expected-note {{base class 'S' of non-literal type}}
+ constexpr NonLitBase(); // expected-error {{non-literal type 'NonLitBase' cannot have constexpr members}}
+};
+struct LitMemBase : Agg {
+ Agg agg;
+};
+template<typename T>
+struct MemberType {
+ T t; // expected-note {{'MemberType<NonLiteral>' is not literal because it has data member 't' of non-literal type 'NonLiteral'}}
+ constexpr MemberType();
+};
+constexpr int f(MemberType<int>);
+constexpr int f(MemberType<NonLiteral>); // expected-error {{not a literal type}}
+
+// - an array of literal type
+struct ArrGood {
+ Agg agg[24];
+ double d[12];
+ TrivDtor td[3];
+};
+constexpr int f(ArrGood);
+
+struct ArrBad {
+ S s[3]; // expected-note {{data member 's' of non-literal type 'S [3]'}}
+};
+constexpr int f(ArrBad); // expected-error {{1st parameter type 'ArrBad' is not a literal type}}
+
+
+// As a non-conforming tweak to the standard, we do not allow a literal type to
+// have any mutable data members.
+namespace MutableMembers {
+ struct MM {
+ mutable int n; // expected-note {{'MM' is not literal because it has a mutable data member}}
+ };
+ constexpr int f(MM); // expected-error {{not a literal type}}
+
+ // Here's one reason why allowing this would be a disaster...
+ template<int n> struct Id { int k = n; };
+ int f() {
+ // FIXME: correctly check whether the initializer is a constant expression.
+ constexpr MM m = { 0 }; // desired-error {{must be a constant expression}}
+ ++m.n;
+ return Id<m.n>().k; // expected-error {{not an integral constant expression}}
+ }
+}
diff --git a/test/CXX/class.access/class.friend/p1.cpp b/test/CXX/class.access/class.friend/p1.cpp
index 1668155c1819..68ff83fee83c 100644
--- a/test/CXX/class.access/class.friend/p1.cpp
+++ b/test/CXX/class.access/class.friend/p1.cpp
@@ -341,3 +341,16 @@ namespace test12 {
void *var = static_cast<B*>(this)->mem;
}
}
+
+namespace PR9103 {
+ struct base {
+ protected:
+ static void foo(void) {}
+ };
+
+ struct cls: base {
+ friend void bar(void) {
+ base::foo();
+ }
+ };
+}
diff --git a/test/CXX/class.access/class.friend/p2-cxx03.cpp b/test/CXX/class.access/class.friend/p2-cxx03.cpp
index 82cddc2bad50..f8cabfd78a8f 100644
--- a/test/CXX/class.access/class.friend/p2-cxx03.cpp
+++ b/test/CXX/class.access/class.friend/p2-cxx03.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
template<typename T>
class X0 {
- friend T; // expected-warning{{non-class friend type 'T' is a C++0x extension}}
+ friend T; // expected-warning{{non-class friend type 'T' is a C++11 extension}}
};
class X1 { };
diff --git a/test/CXX/class.access/class.friend/p3-cxx0x.cpp b/test/CXX/class.access/class.friend/p3-cxx0x.cpp
index 4f55e5339ab2..00fc0a33bef2 100644
--- a/test/CXX/class.access/class.friend/p3-cxx0x.cpp
+++ b/test/CXX/class.access/class.friend/p3-cxx0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
template<typename T>
class X0 {
friend T;
diff --git a/test/CXX/class.access/class.friend/p6.cpp b/test/CXX/class.access/class.friend/p6.cpp
new file mode 100644
index 000000000000..7f7d90990328
--- /dev/null
+++ b/test/CXX/class.access/class.friend/p6.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void f1();
+
+struct X {
+ void f2();
+};
+
+struct Y {
+ friend void ::f1() { } // expected-error{{friend function definition cannot be qualified with '::'}}
+ friend void X::f2() { } // expected-error{{friend function definition cannot be qualified with 'X::'}}
+};
+
+void local() {
+ void f();
+
+ struct Local {
+ friend void f() { } // expected-error{{friend function cannot be defined in a local class}}
+ };
+}
diff --git a/test/CXX/class.access/class.protected/p1.cpp b/test/CXX/class.access/class.protected/p1.cpp
index 8698fb1da8a5..79bb6cd67eab 100644
--- a/test/CXX/class.access/class.protected/p1.cpp
+++ b/test/CXX/class.access/class.protected/p1.cpp
@@ -423,7 +423,7 @@ namespace test12 {
// This friendship is not considered because a public member of A is
// inaccessible in C.
namespace test13 {
- class A { protected: int foo(); }; // expected-note {{declared protected here}}
+ class A { protected: int foo(); }; // expected-note {{object type 'test13::D' must derive from context type 'test13::C'}}
class B : private virtual A {};
class C : private B { friend void test(); };
class D : public virtual A {};
diff --git a/test/CXX/class.access/p6.cpp b/test/CXX/class.access/p6.cpp
index fe3304a22253..932b4f42f2a3 100644
--- a/test/CXX/class.access/p6.cpp
+++ b/test/CXX/class.access/p6.cpp
@@ -168,3 +168,25 @@ namespace test7 {
void foo(int arg[__builtin_offsetof(B, ins)]);
}
}
+
+// rdar://problem/10155256
+namespace test8 {
+ class A {
+ typedef void* (A::*UnspecifiedBoolType)() const;
+ operator UnspecifiedBoolType() const; // expected-note {{implicitly declared private here}}
+ };
+
+ void test(A &a) {
+ if (a) return; // expected-error {{'operator void *(class test8::A::*)(void) const' is a private member of 'test8::A'}}
+ }
+}
+
+namespace test9 {
+ class A {
+ operator char*() const; // expected-note {{implicitly declared private here}}
+ };
+
+ void test(A &a) {
+ delete a; // expected-error {{'operator char *' is a private member of 'test9::A'}}
+ }
+}
diff --git a/test/CXX/class.derived/class.virtual/p3-0x.cpp b/test/CXX/class.derived/class.virtual/p3-0x.cpp
index 4bd9efda1f6c..c4a401bb27c5 100644
--- a/test/CXX/class.derived/class.virtual/p3-0x.cpp
+++ b/test/CXX/class.derived/class.virtual/p3-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
namespace Test1 {
diff --git a/test/CXX/class/class.bit/p2.cpp b/test/CXX/class/class.bit/p2.cpp
new file mode 100644
index 000000000000..7962330d1612
--- /dev/null
+++ b/test/CXX/class/class.bit/p2.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+struct A {
+private:
+ int : 0;
+};
+
+A a = { };
+A a2 = { 1 }; // expected-error{{excess elements in struct initializer}}
+
+struct B {
+ const int : 0;
+};
+
+B b;
+
+void testB() {
+ B b2(b);
+ B b3(static_cast<B&&>(b2));
+ b = b;
+ b = static_cast<B&&>(b);
+}
diff --git a/test/CXX/class/class.friend/p2.cpp b/test/CXX/class/class.friend/p2.cpp
index 87b69c095fbd..fb3cd19b2b18 100644
--- a/test/CXX/class/class.friend/p2.cpp
+++ b/test/CXX/class/class.friend/p2.cpp
@@ -4,7 +4,7 @@ struct B0;
class A {
friend class B {}; // expected-error {{cannot define a type in a friend declaration}}
- friend int; // expected-warning {{non-class friend type 'int' is a C++0x extension}}
+ friend int; // expected-warning {{non-class friend type 'int' is a C++11 extension}}
friend B0; // expected-warning {{specify 'struct' to befriend 'B0'}}
friend class C; // okay
};
diff --git a/test/CXX/class/class.friend/p6.cpp b/test/CXX/class/class.friend/p6.cpp
index bd4630e2aa9d..82a90ff82f20 100644
--- a/test/CXX/class/class.friend/p6.cpp
+++ b/test/CXX/class/class.friend/p6.cpp
@@ -3,7 +3,7 @@
class A {
friend static class B; // expected-error {{'static' is invalid in friend declarations}}
friend extern class C; // expected-error {{'extern' is invalid in friend declarations}}
- friend auto class D; // expected-error {{'auto' is invalid in friend declarations}}
+ friend auto class D; // expected-warning {{incompatible with C++11}} expected-error {{'auto' is invalid in friend declarations}}
friend register class E; // expected-error {{'register' is invalid in friend declarations}}
friend mutable class F; // expected-error {{'mutable' is invalid in friend declarations}}
friend typedef class G; // expected-error {{'typedef' is invalid in friend declarations}}
diff --git a/test/CXX/class/class.mem/p5-0x.cpp b/test/CXX/class/class.mem/p5-0x.cpp
index 78560e2d5daa..6061c4c20a67 100644
--- a/test/CXX/class/class.mem/p5-0x.cpp
+++ b/test/CXX/class/class.mem/p5-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
int f();
diff --git a/test/CXX/class/class.mem/p8-0x.cpp b/test/CXX/class/class.mem/p8-0x.cpp
index 836ebad48ee1..d2c3dc36075b 100644
--- a/test/CXX/class/class.mem/p8-0x.cpp
+++ b/test/CXX/class/class.mem/p8-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
struct Base1 {
virtual void g();
diff --git a/test/CXX/class/class.nest/p1-cxx0x.cpp b/test/CXX/class/class.nest/p1-cxx0x.cpp
index f8b06ac5f7e3..0f12579ee4f8 100644
--- a/test/CXX/class/class.nest/p1-cxx0x.cpp
+++ b/test/CXX/class/class.nest/p1-cxx0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
class Outer {
int x;
diff --git a/test/CXX/class/class.static/class.static.data/p3.cpp b/test/CXX/class/class.static/class.static.data/p3.cpp
new file mode 100644
index 000000000000..007e416e6a49
--- /dev/null
+++ b/test/CXX/class/class.static/class.static.data/p3.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+struct NonLit {
+ NonLit();
+};
+
+struct S {
+ static constexpr int a = 0;
+ static constexpr int b; // expected-error {{declaration of constexpr variable 'b' requires an initializer}}
+
+ static constexpr int c = 0;
+ static const int d;
+ 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 char *const g = 0; // expected-error {{requires 'constexpr' specifier}}
+ static const NonLit h = NonLit(); // expected-error {{must be initialized out of line}}
+};
+
+constexpr int S::a;
+constexpr int S::b = 0;
+
+const int S::c;
+constexpr int S::d = 0;
+constexpr int S::d2;
diff --git a/test/CXX/class/p1-0x.cpp b/test/CXX/class/p1-0x.cpp
index e677dec4caf1..be5fdffb43f4 100644
--- a/test/CXX/class/p1-0x.cpp
+++ b/test/CXX/class/p1-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
namespace Test1 {
class A final { };
diff --git a/test/CXX/class/p2-0x.cpp b/test/CXX/class/p2-0x.cpp
index 630aa7e70f90..dbb01e5ad528 100644
--- a/test/CXX/class/p2-0x.cpp
+++ b/test/CXX/class/p2-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
namespace Test1 {
class A final { }; // expected-note {{'A' declared here}}
diff --git a/test/CXX/class/p6-0x.cpp b/test/CXX/class/p6-0x.cpp
index fc83e065fa6f..3384af09c788 100644
--- a/test/CXX/class/p6-0x.cpp
+++ b/test/CXX/class/p6-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
class Trivial { int n; void f(); };
class NonTrivial1 { NonTrivial1(const NonTrivial1 &); };
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp
index e3d3d683ceb7..98d12f99a598 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
namespace NIL {} // expected-note {{previous definition}}
inline namespace NIL {} // expected-error {{cannot be reopened as inline}}
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
index 7c4a21c35a7d..3bc485601ca5 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// Fun things you can do with inline namespaces:
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp
index 3f3bf4a2eccb..f61437ead6e4 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// C++0x N2914.
struct B {
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 cd71d55fc5ce..ed98c1e9c56d 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-// XFAIL: *
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct notlit {
notlit() {}
@@ -12,35 +11,82 @@ struct notlit2 {
constexpr int i1 = 0;
constexpr int f1() { return 0; }
struct s1 {
- constexpr static int mi = 0;
+ constexpr static int mi1 = 0;
+ const static int mi2;
};
+constexpr int s1::mi2 = 0;
// invalid declarations
// not a definition of an object
-constexpr extern int i2; // x
+constexpr extern int i2; // expected-error {{constexpr variable declaration must be a definition}}
// not a literal type
-constexpr notlit nl1; // x
+constexpr notlit nl1; // expected-error {{declaration of constexpr variable 'nl1' requires an initializer}}
// function parameters
-void f2(constexpr int i) {} // x
+void f2(constexpr int i) {} // expected-error {{function parameter cannot be constexpr}}
// non-static member
struct s2 {
- constexpr int mi; // x
+ constexpr int mi1; // expected-error {{non-static data member cannot be constexpr}}
+ static constexpr int mi2; // expected-error {{requires an initializer}}
};
+// typedef
+typedef constexpr int CI; // expected-error {{typedef cannot be constexpr}}
+// tag
+constexpr class C1 {}; // expected-error {{class cannot be marked constexpr}}
+constexpr struct S1 {}; // expected-error {{struct cannot be marked constexpr}}
+constexpr union U1 {}; // expected-error {{union cannot be marked constexpr}}
+constexpr enum E1 {}; // expected-error {{enum cannot be marked constexpr}}
+class C2 {} constexpr; // expected-error {{class cannot be marked constexpr}}
+struct S2 {} constexpr; // expected-error {{struct cannot be marked constexpr}}
+union U2 {} constexpr; // expected-error {{union cannot be marked constexpr}}
+enum E2 {} constexpr; // expected-error {{enum cannot be marked constexpr}}
+constexpr class C3 {} c3 = C3();
+constexpr struct S3 {} s3 = S3();
+constexpr union U3 {} u3 = {};
+constexpr enum E3 { V3 } e3 = V3;
+class C4 {} constexpr c4 = C4();
+struct S4 {} constexpr s4 = S4();
+union U4 {} constexpr u4 = {};
+enum E4 { V4 } constexpr e4 = V4;
+constexpr int; // expected-error {{constexpr can only be used in variable and function declarations}}
// redeclaration mismatch
-constexpr int f3(); // n
-int f3(); // x
-int f4(); // n
-constexpr int f4(); // x
+constexpr int f3(); // expected-note {{previous declaration is here}}
+int f3(); // expected-error {{non-constexpr declaration of 'f3' follows constexpr declaration}}
+int f4(); // expected-note {{previous declaration is here}}
+constexpr int f4(); // expected-error {{constexpr declaration of 'f4' follows non-constexpr declaration}}
+template<typename T> constexpr T f5(T);
+template<typename T> constexpr T f5(T); // expected-note {{previous}}
+template<typename T> T f5(T); // expected-error {{non-constexpr declaration of 'f5' follows constexpr declaration}}
+template<typename T> T f6(T); // expected-note {{here}}
+template<typename T> constexpr T f6(T); // expected-error {{constexpr declaration of 'f6' follows non-constexpr declaration}}
+// destructor
+struct ConstexprDtor {
+ constexpr ~ConstexprDtor() = default; // expected-error {{destructor cannot be marked constexpr}}
+};
// template stuff
-template <typename T>
-constexpr T ft(T t) { return t; }
+template <typename T> constexpr T ft(T t) { return t; }
+template <typename T> T gt(T t) { return t; }
+struct S {
+ template<typename T> constexpr T f();
+ template<typename T> T g() const;
+};
-// specialization can differ in constepxr
-template <>
-notlit ft(notlit nl) { return nl; }
+// explicit specialization can differ in constepxr
+// FIXME: When checking the explicit specialization, we implicitly instantiate
+// the primary template then claim a constexpr mismatch.
+template <> notlit ft(notlit nl) { return nl; }
+template <> char ft(char c) { return c; } // desired-note {{previous}} unexpected-error {{follows constexpr declaration}} unexpected-note {{here}}
+template <> constexpr char ft(char nl); // desired-error {{constexpr declaration of 'ft<char>' follows non-constexpr declaration}}
+template <> constexpr int gt(int nl) { return nl; } // unexpected-error {{follows non-constexpr declaration}} unexpected-note {{here}}
+template <> notlit S::f() const { return notlit(); }
+template <> constexpr int S::g() { return 0; } // desired-note {{previous}} unexpected-error {{follows non-constexpr declaration}} unexpected-note {{here}}
+template <> int S::g() const; // desired-error {{non-constexpr declaration of 'g<int>' follows constexpr declaration}}
+// specializations can drop the 'constexpr' but not the implied 'const'.
+template <> char S::g() { return 0; } // expected-error {{no function template matches}}
+template <> double S::g() const { return 0; } // ok
-constexpr int i3 = ft(1);
+// FIXME: The initializer is a constant expression.
+constexpr int i3 = ft(1); // unexpected-error {{must be initialized by a constant expression}}
void test() {
// ignore constexpr when instantiating with non-literal
@@ -52,7 +98,7 @@ void test() {
constexpr int square(int x);
constexpr int bufsz = 1024;
-constexpr struct pixel { // x
+constexpr struct pixel { // expected-error {{struct cannot be marked constexpr}}
int x;
int y;
constexpr pixel(int);
@@ -62,17 +108,17 @@ constexpr pixel::pixel(int a)
: x(square(a)), y(square(a))
{ }
-constexpr pixel small(2); // x (no definition of square(int) yet, so can't
- // constexpr-eval pixel(int))
+constexpr pixel small(2); // expected-error {{must be initialized by a constant expression}}
constexpr int square(int x) {
return x * x;
}
-constexpr pixel large(4); // now valid
+// FIXME: The initializer is a constant expression.
+constexpr pixel large(4); // unexpected-error {{must be initialized by a constant expression}}
-int next(constexpr int x) { // x
+int next(constexpr int x) { // expected-error {{function parameter cannot be constexpr}}
return x + 1;
}
-extern constexpr int memsz; // x
+extern constexpr int memsz; // expected-error {{constexpr variable declaration must be a definition}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p2.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p2.cpp
new file mode 100644
index 000000000000..001a086a008b
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p2.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - | FileCheck %s
+
+// constexpr functions and constexpr constructors are implicitly inline.
+struct S {
+ constexpr S(int n);
+ constexpr int g();
+ int n;
+};
+
+constexpr S::S(int n) : n(n) {}
+
+constexpr S f(S s) {
+ return s.n * 2;
+}
+
+constexpr int S::g() {
+ return f(*this).n;
+}
+
+// CHECK: define linkonce_odr {{.*}} @_Z1f1S(
+// CHECK: define linkonce_odr {{.*}} @_ZN1SC1Ei(
+// CHECK: define linkonce_odr {{.*}} @_ZNK1S1gEv(
+
+int g() {
+ return f(42).g();
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
new file mode 100644
index 000000000000..03406dbf918a
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
@@ -0,0 +1,125 @@
+// RUN: %clang_cc1 -verify -std=c++11 %s
+
+namespace N {
+ typedef char C;
+}
+
+namespace M {
+ typedef double D;
+}
+
+struct NonLiteral { // expected-note 4{{no constexpr constructors}}
+ NonLiteral() {}
+ NonLiteral(int) {}
+};
+struct Literal {
+ constexpr Literal() {}
+ operator int() const { return 0; }
+};
+
+struct S {
+ virtual int ImplicitlyVirtual() const = 0; // expected-note {{overridden virtual function}}
+};
+struct SS : S {
+ int ImplicitlyVirtual() const;
+};
+
+// Note, the wording applies constraints to the definition of constexpr
+// functions, but we intentionally apply all that we can to the declaration
+// instead. See DR1360.
+
+// The definition of a constexpr function shall satisfy the following
+// constraints:
+struct T : SS { // expected-note {{base class 'SS' of non-literal type}}
+ constexpr T(); // expected-error {{non-literal type 'T' cannot have constexpr members}}
+
+ // - it shall not be virtual;
+ virtual constexpr int ExplicitlyVirtual(); // expected-error {{virtual function cannot be constexpr}}
+
+ constexpr int ImplicitlyVirtual(); // expected-error {{virtual function cannot be constexpr}}
+
+ // - its return type shall be a literal type;
+ constexpr NonLiteral NonLiteralReturn(); // expected-error {{constexpr function's return type 'NonLiteral' is not a literal type}}
+ constexpr ~T(); // expected-error {{destructor cannot be marked constexpr}}
+ typedef NonLiteral F();
+ constexpr F NonLiteralReturn2; // expected-error {{constexpr function's return type 'NonLiteral' is not a literal type}}
+
+ // - each of its parameter types shall be a literal type;
+ constexpr int NonLiteralParam(NonLiteral); // expected-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}}
+ typedef int G(NonLiteral);
+ constexpr G NonLiteralParam2; // expected-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}}
+
+ // - its function-body shall be = delete, = default,
+ constexpr int Deleted() = delete;
+ // It's not possible for the function-body to legally be "= default" here.
+ // Other than constructors, only the copy- and move-assignment operators and
+ // destructor can be defaulted. Destructors can't be constexpr since they
+ // don't have a literal return type. Defaulted assignment operators can't be
+ // constexpr since they can't be const.
+ constexpr T &operator=(const T&) = default; // expected-error {{an explicitly-defaulted copy assignment operator may not have 'const', 'constexpr' or 'volatile' qualifiers}}
+};
+struct U {
+ constexpr U SelfReturn();
+ constexpr int SelfParam(U);
+};
+
+// or a compound-statememt that contains only
+constexpr int AllowedStmts() {
+ // - null statements
+ ;
+
+ // - static_assert-declarations
+ static_assert(true, "the impossible happened!");
+
+ // - typedef declarations and alias-declarations that do not define classes
+ // or enumerations
+ typedef int I;
+ typedef struct S T;
+ using J = int;
+ using K = int[sizeof(I) + sizeof(J)];
+ // Note, the standard requires we reject this.
+ struct U;
+
+ // - using-declarations
+ using N::C;
+
+ // - using-directives
+ using namespace N;
+
+ // - and exactly one return statement
+ return sizeof(K) + sizeof(C) + sizeof(K);
+}
+constexpr int ForStmt() {
+ for (int n = 0; n < 10; ++n) // expected-error {{statement not allowed in constexpr function}}
+ return 0;
+}
+constexpr int VarDecl() {
+ constexpr int a = 0; // expected-error {{variables cannot be declared in a constexpr function}}
+ return 0;
+}
+constexpr int FuncDecl() {
+ constexpr int ForwardDecl(int); // expected-error {{statement not allowed in constexpr function}}
+ return ForwardDecl(42);
+}
+constexpr int ClassDecl1() {
+ typedef struct { } S1; // expected-error {{types cannot be defined in a constexpr function}}
+ return 0;
+}
+constexpr int ClassDecl2() {
+ using S2 = struct { }; // expected-error {{types cannot be defined in a constexpr function}}
+ return 0;
+}
+constexpr int ClassDecl3() {
+ struct S3 { }; // expected-error {{types cannot be defined in a constexpr function}}
+ return 0;
+}
+constexpr int NoReturn() {} // expected-error {{no return statement in constexpr function}}
+constexpr int MultiReturn() {
+ return 0; // expected-note {{return statement}}
+ return 0; // expected-error {{multiple return statements in constexpr function}}
+}
+
+// - every constructor call and implicit conversion used in initializing the
+// return value shall be one of those allowed in a constant expression.
+//
+// We implement the proposed resolution of DR1364 and ignore this bullet.
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
new file mode 100644
index 000000000000..9218bcf45bb4
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
@@ -0,0 +1,226 @@
+// RUN: %clang_cc1 -verify -std=c++11 -fcxx-exceptions %s
+
+namespace N {
+ typedef char C;
+}
+
+namespace M {
+ typedef double D;
+}
+
+struct NonLiteral { // expected-note 2{{no constexpr constructors}}
+ NonLiteral() {}
+ NonLiteral(int) {}
+};
+struct Literal {
+ constexpr Literal() {}
+ operator int() const { return 0; }
+};
+
+// Note, the wording applies constraints to the definition of constexpr
+// constructors, but we intentionally apply all that we can to the declaration
+// instead. See DR1360.
+
+// In the definition of a constexpr constructor, each of the parameter types
+// shall be a literal type.
+struct S {
+ constexpr S(int, N::C);
+ constexpr S(int, NonLiteral, N::C); // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}}
+ constexpr S(int, NonLiteral = 42); // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}}
+
+ // In addition, either its function-body shall be = delete or = default
+ constexpr S() = default;
+ constexpr S(Literal) = delete;
+};
+
+// or it shall satisfy the following constraints:
+
+// - the class shall not have any virtual base classes;
+struct T : virtual S { // expected-note {{here}}
+ constexpr T(); // expected-error {{constexpr constructor not allowed in struct with virtual base classes}}
+};
+namespace IndirectVBase {
+ struct A {};
+ struct B : virtual A {}; // expected-note {{here}}
+ class C : public B {
+ public:
+ constexpr C(); // expected-error {{constexpr constructor not allowed in class with virtual base classes}}
+ };
+}
+
+// - its function-body shall not be a function-try-block;
+struct U {
+ constexpr U()
+ try // expected-error {{function try block not allowed in constexpr constructor}}
+ : u() {
+ } catch (...) {
+ throw;
+ }
+ int u;
+};
+
+// - the compound-statememt of its function-body shall contain only
+struct V {
+ constexpr V() {
+ // - null statements,
+ ;
+
+ // - static_assert-declarations,
+ static_assert(true, "the impossible happened!");
+
+ // - typedef declarations and alias-declarations that do not define classes
+ // or enumerations,
+ typedef int I;
+ typedef struct S T;
+ using J = int;
+ using K = int[sizeof(I) + sizeof(J)];
+ // Note, the standard requires we reject this.
+ struct U;
+
+ // - using-declarations,
+ using N::C;
+
+ // - and using-directives;
+ using namespace N;
+ }
+
+ constexpr V(int(&)[1]) {
+ for (int n = 0; n < 10; ++n) // expected-error {{statement not allowed in constexpr constructor}}
+ /**/;
+ }
+ constexpr V(int(&)[2]) {
+ constexpr int a = 0; // expected-error {{variables cannot be declared in a constexpr constructor}}
+ }
+ constexpr V(int(&)[3]) {
+ constexpr int ForwardDecl(int); // expected-error {{statement not allowed in constexpr constructor}}
+ }
+ constexpr V(int(&)[4]) {
+ typedef struct { } S1; // expected-error {{types cannot be defined in a constexpr constructor}}
+ }
+ constexpr V(int(&)[5]) {
+ using S2 = struct { }; // expected-error {{types cannot be defined in a constexpr constructor}}
+ }
+ constexpr V(int(&)[6]) {
+ struct S3 { }; // expected-error {{types cannot be defined in a constexpr constructor}}
+ }
+ constexpr V(int(&)[7]) {
+ return; // expected-error {{statement not allowed in constexpr constructor}}
+ }
+};
+
+// - every non-static data member and base class sub-object shall be initialized
+struct W {
+ int n; // expected-note {{member not initialized by constructor}}
+ constexpr W() {} // expected-error {{constexpr constructor must initialize all members}}
+};
+struct AnonMembers {
+ int a; // expected-note {{member not initialized by constructor}}
+ union { // expected-note 2{{member not initialized by constructor}}
+ char b;
+ struct {
+ double c;
+ long d; // expected-note {{member not initialized by constructor}}
+ };
+ union {
+ char e;
+ void *f;
+ };
+ };
+ struct { // expected-note {{member not initialized by constructor}}
+ long long g;
+ struct {
+ int h; // expected-note {{member not initialized by constructor}}
+ double i; // expected-note {{member not initialized by constructor}}
+ };
+ union { // expected-note 2{{member not initialized by constructor}}
+ char *j;
+ AnonMembers *k;
+ };
+ };
+
+ constexpr AnonMembers(int(&)[1]) : a(), b(), g(), h(), i(), j() {} // ok
+ // missing d, i, j/k union
+ constexpr AnonMembers(int(&)[2]) : a(), c(), g(), h() {} // expected-error {{constexpr constructor must initialize all members}}
+ constexpr AnonMembers(int(&)[3]) : a(), e(), g(), h(), i(), k() {} // ok
+ // missing h, j/k union
+ constexpr AnonMembers(int(&)[4]) : a(), c(), d(), g(), i() {} // expected-error {{constexpr constructor must initialize all members}}
+ // missing b/c/d/e/f union
+ constexpr AnonMembers(int(&)[5]) : a(), g(), h(), i(), k() {} // expected-error {{constexpr constructor must initialize all members}}
+ // missing a, b/c/d/e/f union, g/h/i/j/k struct
+ constexpr AnonMembers(int(&)[6]) {} // expected-error {{constexpr constructor must initialize all members}}
+};
+
+template<typename T> using Int = int;
+template<typename T>
+struct TemplateInit {
+ T a;
+ int b; // desired-note {{not initialized}}
+ Int<T> c; // desired-note {{not initialized}}
+ struct {
+ T d;
+ int e; // desired-note {{not initialized}}
+ Int<T> f; // desired-note {{not initialized}}
+ };
+ struct {
+ Literal l;
+ Literal m;
+ Literal n[3];
+ };
+ union { // desired-note {{not initialized}}
+ T g;
+ T h;
+ };
+ // FIXME: This is ill-formed (no diagnostic required). We should diagnose it.
+ constexpr TemplateInit() {} // desired-error {{must initialize all members}}
+};
+template<typename T> struct TemplateInit2 {
+ Literal l;
+ constexpr TemplateInit2() {} // ok
+};
+
+template<typename T> struct weak_ptr {
+ constexpr weak_ptr() : p(0) {}
+ T *p;
+};
+template<typename T> struct enable_shared_from_this {
+ weak_ptr<T> weak_this;
+ constexpr enable_shared_from_this() {} // ok
+};
+constexpr int f(enable_shared_from_this<int>);
+
+// - every constructor involved in initializing non-static data members and base
+// class sub-objects shall be a constexpr constructor.
+//
+// FIXME: Implement this as part of the 'must be able to produce a constant
+// expression' rules.
+
+// - every assignment-expression that is an initializer-caluse appearing
+// directly or indirectly within a brace-or-equal-initializer for a non-static
+// data member that is not named by a mem-initializer-id shall be a constant
+// expression; and
+//
+// Note, we deliberately do not implement this bullet, so that we can allow the
+// following example. (See N3308).
+struct X {
+ int a = 0;
+ int b = 2 * a + 1; // ok, not a constant expression.
+
+ constexpr X() {}
+ constexpr X(int c) : a(c) {} // ok, b initialized by 2 * c + 1
+};
+
+// - every implicit conversion used in converting a constructor argument to the
+// corresponding parameter type and converting a full-expression to the
+// corresponding member type shall be one of those allowed in a constant
+// expression.
+//
+// We implement the proposed resolution of DR1364 and ignore this bullet.
+
+
+namespace StdExample {
+ struct Length {
+ explicit constexpr Length(int i = 0) : val(i) { }
+ private:
+ int val;
+ };
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
new file mode 100644
index 000000000000..e383bc09226c
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -verify -std=c++11 %s
+
+namespace N {
+ typedef char C;
+}
+
+namespace M {
+ typedef double D;
+}
+
+struct NonLiteral {
+ NonLiteral() {}
+ NonLiteral(int) {}
+ operator int() const { return 0; }
+};
+struct Literal {
+ constexpr Literal() {}
+ operator int() const { return 0; }
+};
+
+struct S {
+ virtual int ImplicitlyVirtual();
+};
+struct T {};
+
+template<typename T> struct ImplicitVirtualFromDependentBase : T {
+ constexpr int ImplicitlyVirtual() { return 0; }
+};
+
+// FIXME: Can't test this until we have function invocation substitution
+#if 0
+constexpr int a = ImplicitVirtualFromDependentBase<S>().ImplicitlyVirtual(); // desired-error {{not a constant expression}}
+constexpr int b = ImplicitVirtualFromDependentBase<T>().ImplicitlyVirtual(); // ok
+#endif
+
+template<typename R> struct ConstexprMember {
+ constexpr R F() { return 0; }
+};
+// FIXME: Can't test this until we have function invocation substitution
+#if 0
+constexpr int c = ConstexprMember<int>().F(); // ok
+constexpr int d = ConstexprMember<NonLiteral>().F(); // desired-error {{not a constant expression}}
+#endif
+
+template<typename ...P> struct ConstexprCtor { // expected-note 2{{no constexpr constructors}}
+ constexpr ConstexprCtor(P...); // expected-note {{constructor template instantiation is not constexpr because 1st parameter type 'NonLiteral' is not a literal type}} \
+ expected-note {{constructor template instantiation is not constexpr because 2nd parameter type 'NonLiteral' is not a literal type}}
+};
+constexpr ConstexprCtor<> f1(); // ok
+constexpr ConstexprCtor<int> f2(); // ok
+constexpr ConstexprCtor<NonLiteral> f3(); // expected-error {{not a literal type}}
+constexpr ConstexprCtor<int, NonLiteral> f4(); // expected-error {{not a literal type}}
+
+struct VirtBase : virtual S {}; // expected-note {{here}}
+
+namespace TemplateVBase {
+ template<typename T> struct T1 : virtual Literal { // expected-note {{here}}
+ constexpr T1(); // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
+ };
+
+ template<typename T> struct T2 : virtual T { // expected-note {{struct with virtual base class is not a literal type}} expected-note {{here}}
+ // FIXME: This is ill-formed (no diagnostic required).
+ // We should diagnose it now rather than waiting until instantiation.
+ constexpr T2(); // desired-error {{constexpr constructor not allowed in class with virtual base classes}}
+ };
+ constexpr T2<Literal> g2(); // expected-error {{not a literal type}}
+
+ template<typename T> class T3 : public T { // expected-note {{class with virtual base class is not a literal type}}
+ public:
+ constexpr T3() {}
+ };
+ constexpr T3<Literal> g3(); // ok
+ constexpr T3<VirtBase> g4(); // expected-error {{not a literal type}}
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp
new file mode 100644
index 000000000000..f7da24dfc20a
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+struct S {
+ constexpr void f();
+ constexpr void g() const;
+};
+
+void f(const S &s) {
+ s.f();
+ s.g();
+}
+
+namespace std_example {
+
+ class debug_flag { // expected-note {{not an aggregate and has no constexpr constructors}}
+ public:
+ explicit debug_flag(bool);
+ constexpr bool is_on(); // expected-error {{non-literal type 'std_example::debug_flag' cannot have constexpr members}}
+ private:
+ bool flag;
+ };
+
+ constexpr int bar(int x, int y) // expected-note {{here}}
+ { return x + y + x*y; }
+ int bar(int x, int y) // expected-error {{non-constexpr declaration of 'bar' follows constexpr declaration}}
+ { return x * 2 + 3 * y; }
+
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
new file mode 100644
index 000000000000..53d232d8a90a
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+// A constexpr specifier used in an object declaration declares the object as
+// const.
+constexpr int a = 0;
+extern const int a;
+
+int i;
+constexpr int *b = &i;
+extern int *const b;
+
+constexpr int &c = i;
+extern int &c;
+
+constexpr int (*d)(int) = 0;
+extern int (*const d)(int);
+
+// A variable declaration which uses the constexpr specifier shall have an
+// initializer and shall be initialized by a constant expression.
+constexpr int ni1; // expected-error {{declaration of constexpr variable 'ni1' requires an initializer}}
+constexpr struct C { C(); } ni2; // expected-error {{declaration of constexpr variable 'ni2' requires an initializer}}
+constexpr double &ni3; // expected-error {{declaration of constexpr variable 'ni3' requires an initializer}}
+
+constexpr int nc1 = i; // expected-error {{constexpr variable 'nc1' must be initialized by a constant expression}}
+constexpr C nc2 = C(); // expected-error {{constexpr variable 'nc2' must be initialized by a constant expression}}
+int &f();
+constexpr int &nc3 = f(); // expected-error {{constexpr variable 'nc3' must be initialized by a constant expression}}
+constexpr int nc4(i); // expected-error {{constexpr variable 'nc4' must be initialized by a constant expression}}
+constexpr C nc5((C())); // expected-error {{constexpr variable 'nc5' must be initialized by a constant expression}}
+int &f();
+constexpr int &nc6(f()); // expected-error {{constexpr variable 'nc6' must be initialized by a constant expression}}
+
+struct pixel {
+ int x, y;
+};
+constexpr pixel ur = { 1294, 1024 }; // ok
+constexpr pixel origin; // expected-error {{requires an initializer}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp
index fcc1334b1506..ee870d960161 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp
@@ -4,7 +4,7 @@ class A {
public:
explicit A();
- explicit operator int(); // expected-warning {{explicit conversion functions are a C++0x extension}}
+ explicit operator int(); // expected-warning {{explicit conversion functions are a C++11 extension}}
explicit void f0(); // expected-error {{'explicit' can only be applied to a constructor or conversion function}}
@@ -12,5 +12,5 @@ public:
};
explicit A::A() { } // expected-error {{'explicit' can only be specified inside the class definition}}
-explicit A::operator bool() { return false; } // expected-warning {{explicit conversion functions are a C++0x extension}}\
+explicit A::operator bool() { return false; } // expected-warning {{explicit conversion functions are a C++11 extension}}\
// expected-error {{'explicit' can only be specified inside the class definition}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp
index 1b1f11a660b5..7b5577520d42 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s -std=c++11
struct S {
virtual ~S();
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp
index b675fb8013e3..682ee9f7e4ec 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++0x-extensions
void f() {
auto a = a; // expected-error{{variable 'a' declared with 'auto' type cannot appear in its own initializer}}
auto *b = b; // expected-error{{variable 'b' declared with 'auto' type cannot appear in its own initializer}}
@@ -39,10 +40,12 @@ void p3example() {
auto x = 5;
const auto *v = &x, u = 6;
static auto y = 0.0;
- auto int r; // expected-warning {{'auto' storage class specifier is redundant and will be removed in future releases}}
-
- same<decltype(x), int> xHasTypeInt;
- same<decltype(v), const int*> vHasTypeConstIntPtr;
- same<decltype(u), const int> uHasTypeConstInt;
- same<decltype(y), double> yHasTypeDouble;
+ // In C++98: 'auto' storage class specifier is redundant and incompatible with C++0x
+ // In C++0x: 'auto' storage class specifier is not permitted in C++0x, and will not be supported in future releases
+ auto int r; // expected-warning {{'auto' storage class specifier}}
+
+ same<__typeof(x), int> xHasTypeInt;
+ same<__typeof(v), const int*> vHasTypeConstIntPtr;
+ same<__typeof(u), const int> uHasTypeConstInt;
+ same<__typeof(y), double> yHasTypeDouble;
}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
index 8a68e4bcd795..095c031a1a0e 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++0x-extensions
template<typename T>
struct only {
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
index 54da854dab55..a52ef41504ac 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s -std=c++11
struct S {
virtual ~S();
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp
index 8b4b70398471..7ed4daec5dec 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++0x-extensions
template<typename T>
struct only {
@@ -82,4 +83,21 @@ struct S {
}
};
+namespace PR10939 {
+ struct X {
+ int method(int);
+ int method(float);
+ };
+
+ template<typename T> T g(T);
+
+ void f(X *x) {
+ auto value = x->method; // expected-error{{variable 'value' with type 'auto' has incompatible initializer of type '<bound member function type>'}}
+ if (value) { }
+
+ auto funcptr = &g<int>;
+ int (*funcptr2)(int) = funcptr;
+ }
+}
+
// TODO: if the initializer is a braced-init-list, deduce auto as std::initializer_list<T>.
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp
index de87a93a2bc1..4f230cfb8d40 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++0x-extensions
void f() {
auto a = 0, b = 0, c = 0;
auto d = 0, e = 0.0; // expected-error {{'int' in declaration of 'd' and deduced as 'double' in declaration of 'e'}}
@@ -18,6 +19,14 @@ void f() {
}
void g() {
- auto a = 0, (*b)() -> void, c = 0;
- auto d = 0, (*e)() -> void, f = 0.0; // expected-error {{'auto' deduced as 'int' in declaration of 'd' and deduced as 'double' in declaration of 'f'}}
+ auto a = 0,
+#if __has_feature(cxx_trailing_return)
+ (*b)() -> void,
+#endif
+ c = 0;
+ auto d = 0, // expected-error {{'auto' deduced as 'int' in declaration of 'd' and deduced as 'double' in declaration of 'f'}}
+#if __has_feature(cxx_trailing_return)
+ (*e)() -> void,
+#endif
+ f = 0.0;
}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp
index 81204d89a697..027104151ac6 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
struct A { typedef int type; };
template<typename T> using X = A; // expected-note {{declared here}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p4-cxx0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p4-cxx0x.cpp
index 19159e159a0c..bc60b5e55a33 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p4-cxx0x.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p4-cxx0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
template<typename T, typename U>
struct is_same {
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
index b93e8e35b139..e32774a2ee0f 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
using X = struct { // ok
};
@@ -7,8 +7,9 @@ template<typename T> using Y = struct { // expected-error {{can not be defined i
class K {
virtual ~K();
- // FIXME: the diagnostic here is really bad
- operator struct S {} (); // expected-error 2{{}} expected-note {{}}
+ // FIXME: Diagnostic could use some work
+ operator struct S {} (); // expected-error{{ 'operator S' cannot be the name of a variable or data member}} \
+ // expected-error{{expected ';' at end of declaration list}}
};
void f() {
@@ -33,8 +34,7 @@ void f() {
void g() throw (struct Ex {}) { // expected-error {{'Ex' can not be defined in a type specifier}}
}
-// FIXME: this currently gives a strange error because alignas is not recognised as a keyword yet.
-int alignas(struct Aa {}) x; // expected-error {{'Aa' can not be defined in a parameter type}} expected-error {{expected function body}}
+int alignas(struct Aa {}) x; // expected-error {{'Aa' can not be defined in a type specifier}}
int a = sizeof(struct So {}); // expected-error {{'So' can not be defined in a type specifier}}
int b = alignof(struct Ao {}); // expected-error {{'Ao' can not be defined in a type specifier}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp
index a51cfbfffcce..0ff40bccef9f 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -std=c++0x %s
+// RUN: %clang_cc1 -verify -std=c++11 %s
namespace RedeclAliasTypedef {
typedef int T;
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
index 9b92340fa457..b8c1e18a2e13 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// An aggregate is an array or a class...
struct Aggr {
@@ -18,11 +18,10 @@ struct NonAggr1a {
NonAggr1a(int, int);
int k;
};
-// In C++03, this is {{non-aggregate type 'NonAggr1a'}}.
// In C++0x, 'user-provided' is only defined for special member functions, so
-// this type is considered to be an aggregate. This is probably a langauge
-// defect.
-NonAggr1a na1a = { 42 };
+// this type is considered to be an aggregate. This is considered to be
+// a language defect.
+NonAggr1a na1a = { 42 }; // expected-error {{non-aggregate type 'NonAggr1a'}}
struct NonAggr1b {
NonAggr1b(const NonAggr1b &);
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p4.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p4.cpp
index c38bd292efdb..104157115335 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p4.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p4.cpp
@@ -15,4 +15,4 @@ void tf() {
}
// Allowed by GNU extension
-int a4[] = {}; // expected-warning {{zero size arrays}}
+int a4[] = {}; // expected-error {{zero size arrays}}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x-fixits.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x-fixits.cpp
new file mode 100644
index 000000000000..dc49deabdea4
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x-fixits.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fsyntax-only -Wc++0x-compat -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+// Verify that the appropriate fixits are emitted for narrowing conversions in
+// initializer lists.
+
+typedef short int16_t;
+
+void fixits() {
+ int x = 999;
+ struct {char c;} c2 = {x};
+ // CHECK: warning:{{.*}} cannot be narrowed
+ // CHECK: fix-it:{{.*}}:26}:"static_cast<char>("
+ // CHECK: fix-it:{{.*}}:27}:")"
+ struct {int16_t i;} i16 = {70000};
+ // CHECK: warning:{{.*}} cannot be narrowed
+ // CHECK: fix-it:{{.*}}:30}:"static_cast<int16_t>("
+ // CHECK: fix-it:{{.*}}:35}:")"
+}
+
+template<typename T>
+void maybe_shrink_int(T t) {
+ struct {T t;} t2 = {700};
+}
+
+void test_template() {
+ maybe_shrink_int((char)3);
+ // CHECK: warning:{{.*}} cannot be narrowed
+ // CHECK: note:{{.*}} in instantiation
+ // CHECK: note:{{.*}} override
+ // FIXME: This should be static_cast<T>.
+ // CHECK: fix-it:{{.*}}"static_cast<char>("
+ // CHECK: fix-it:{{.*}}")"
+}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
new file mode 100644
index 000000000000..2294a4eb0894
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
@@ -0,0 +1,175 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -triple x86_64-apple-macosx10.6.7 -verify %s
+
+// Verify that narrowing conversions in initializer lists cause errors in C++0x
+// mode.
+
+void std_example() {
+ int x = 999; // x is not a constant expression
+ const int y = 999;
+ const int z = 99;
+ char c1 = x; // OK, though it might narrow (in this case, it does narrow)
+ char c2{x}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ char c3{y}; // expected-error {{ cannot be narrowed }} expected-note {{override}} expected-warning {{changes value}}
+ char c4{z}; // OK: no narrowing needed
+ unsigned char uc1 = {5}; // OK: no narrowing needed
+ unsigned char uc2 = {-1}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ unsigned int ui1 = {-1}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ signed int si1 =
+ { (unsigned int)-1 }; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ int ii = {2.0}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ float f1 { x }; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ float f2 { 7 }; // OK: 7 can be exactly represented as a float
+ int f(int);
+ int a[] =
+ { 2, f(2), f(2.0) }; // OK: the double-to-int conversion is not at the top level
+}
+
+// Test each rule individually.
+
+template<typename T>
+struct Agg {
+ T t;
+};
+
+// C++0x [dcl.init.list]p7: A narrowing conversion is an implicit conversion
+//
+// * from a floating-point type to an integer type, or
+
+void float_to_int() {
+ Agg<char> a1 = {1.0F}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ Agg<char> a2 = {1.0}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ Agg<char> a3 = {1.0L}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+
+ float f = 1.0;
+ double d = 1.0;
+ long double ld = 1.0;
+ Agg<char> a4 = {f}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ Agg<char> a5 = {d}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ Agg<char> a6 = {ld}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+}
+
+// * from long double to double or float, or from double to float, except where
+// the source is a constant expression and the actual value after conversion
+// is within the range of values that can be represented (even if it cannot be
+// represented exactly), or
+
+void shrink_float() {
+ // These aren't constant expressions.
+ float f = 1.0;
+ double d = 1.0;
+ long double ld = 1.0;
+
+ // Variables.
+ Agg<float> f1 = {f}; // OK (no-op)
+ Agg<float> f2 = {d}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ Agg<float> f3 = {ld}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ // Exact constants.
+ Agg<float> f4 = {1.0}; // OK (double constant represented exactly)
+ Agg<float> f5 = {1.0L}; // OK (long double constant represented exactly)
+ // Inexact but in-range constants.
+ Agg<float> f6 = {0.1}; // OK (double constant in range but rounded)
+ Agg<float> f7 = {0.1L}; // OK (long double constant in range but rounded)
+ // Out of range constants.
+ Agg<float> f8 = {1E50}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ Agg<float> f9 = {1E50L}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ // More complex constant expression.
+ constexpr long double e40 = 1E40L, e30 = 1E30L, e39 = 1E39L;
+ Agg<float> f10 = {e40 - 5 * e39 + e30 - 5 * e39}; // OK
+
+ // Variables.
+ Agg<double> d1 = {f}; // OK (widening)
+ Agg<double> d2 = {d}; // OK (no-op)
+ Agg<double> d3 = {ld}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ // Exact constant.
+ Agg<double> d4 = {1.0L}; // OK (long double constant represented exactly)
+ // Inexact but in-range constant.
+ Agg<double> d5 = {0.1L}; // OK (long double constant in range but rounded)
+ // Out of range constant.
+ Agg<double> d6 = {1E315L}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ // More complex constant expression.
+ constexpr long double e315 = 1E315L, e305 = 1E305L, e314 = 1E314L;
+ Agg<double> d7 = {e315 - 5 * e314 + e305 - 5 * e314}; // OK
+}
+
+// * from an integer type or unscoped enumeration type to a floating-point type,
+// except where the source is a constant expression and the actual value after
+// conversion will fit into the target type and will produce the original
+// value when converted back to the original type, or
+void int_to_float() {
+ // Not a constant expression.
+ char c = 1;
+
+ // Variables. Yes, even though all char's will fit into any floating type.
+ Agg<float> f1 = {c}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ Agg<double> f2 = {c}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ Agg<long double> f3 = {c}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+
+ // Constants.
+ Agg<float> f4 = {12345678}; // OK (exactly fits in a float)
+ Agg<float> f5 = {123456789}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+}
+
+// * from an integer type or unscoped enumeration type to an integer type that
+// cannot represent all the values of the original type, except where the
+// source is a constant expression and the actual value after conversion will
+// fit into the target type and will produce the original value when converted
+// back to the original type.
+void shrink_int() {
+ // Not a constant expression.
+ short s = 1;
+ unsigned short us = 1;
+ Agg<char> c1 = {s}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ Agg<unsigned short> s1 = {s}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ Agg<short> s2 = {us}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+
+ // "that cannot represent all the values of the original type" means that the
+ // validity of the program depends on the relative sizes of integral types.
+ // This test compiles with -m64, so sizeof(int)<sizeof(long)==sizeof(long
+ // long).
+ long l1 = 1;
+ Agg<int> i1 = {l1}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ long long ll = 1;
+ Agg<long> l2 = {ll}; // OK
+
+ // Constants.
+ Agg<char> c2 = {127}; // OK
+ Agg<char> c3 = {300}; // expected-error {{ cannot be narrowed }} expected-note {{override}} expected-warning {{changes value}}
+
+ Agg<int> i2 = {0x7FFFFFFFU}; // OK
+ Agg<int> i3 = {0x80000000U}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ Agg<unsigned int> i4 = {-0x80000000L}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+
+ // Bool is also an integer type, but conversions to it are a different AST
+ // node.
+ Agg<bool> b1 = {0}; // OK
+ Agg<bool> b2 = {1}; // OK
+ Agg<bool> b3 = {-1}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+
+ // Conversions from pointers to booleans aren't narrowing conversions.
+ Agg<bool> b = {&b1}; // OK
+}
+
+// Be sure that type- and value-dependent expressions in templates get the error
+// too.
+
+template<int I, typename T>
+void maybe_shrink_int(T t) {
+ Agg<short> s1 = {t}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ Agg<short> s2 = {I}; // expected-error {{ cannot be narrowed }} expected-note {{override}} expected-warning {{changes value}}
+ Agg<T> t2 = {700}; // expected-error {{ cannot be narrowed }} expected-note {{override}} expected-warning {{changes value}}
+}
+
+void test_template() {
+ maybe_shrink_int<15>((int)3); // expected-note {{in instantiation}}
+ maybe_shrink_int<70000>((char)3); // expected-note {{in instantiation}}
+}
+
+
+// We don't want qualifiers on the types in the diagnostic.
+
+void test_qualifiers(int i) {
+ const int j = i;
+ struct {const unsigned char c;} c1 = {j}; // expected-error {{from type 'int' to 'unsigned char' in}} expected-note {{override}}
+ // Template arguments make it harder to avoid printing qualifiers:
+ Agg<const unsigned char> c2 = {j}; // expected-error {{from type 'int' to 'const unsigned char' in}} expected-note {{override}}
+}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp
index bd08ab5423b0..20c059eab6f3 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
int g(int);
void f() {
int i;
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 7b0fb9c52ba4..95cc56cbab53 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
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify -pedantic %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -pedantic %s
// Test the C++0x-specific reference initialization rules, e.g., the
// rules for rvalue references.
@@ -17,7 +17,7 @@ int f(int);
template<typename T>
struct ConvertsTo {
- operator T(); // expected-note 4{{candidate function}}
+ operator T(); // expected-note 2{{candidate function}}
};
void test_rvalue_refs() {
@@ -132,7 +132,9 @@ namespace std_example_2 {
namespace argument_passing {
void base_rvalue_ref(Base&&);
- void int_rvalue_ref(int&&); // expected-note 2{{passing argument to parameter here}}
+ void int_rvalue_ref(int&&); // expected-note{{candidate function not viable: no known conversion from 'ConvertsTo<int &>' to 'int &&' for 1st argument}} \
+ // expected-note{{candidate function not viable: no known conversion from 'ConvertsTo<float &>' to 'int &&' for 1st argument}}
+
void array_rvalue_ref(int (&&)[5]);
void function_rvalue_ref(int (&&)(int));
@@ -157,8 +159,36 @@ namespace argument_passing {
function_rvalue_ref(ConvertsTo<int(&)(int)>());
- int_rvalue_ref(ConvertsTo<int&>()); // expected-error{{no viable conversion from 'ConvertsTo<int &>' to 'int'}}
- int_rvalue_ref(ConvertsTo<float&>()); // expected-error{{no viable conversion from 'ConvertsTo<float &>' to 'int'}}
+ int_rvalue_ref(ConvertsTo<int&>()); // expected-error{{no matching function for call to 'int_rvalue_ref'}}
+ int_rvalue_ref(ConvertsTo<float&>()); // expected-error{{no matching function for call to 'int_rvalue_ref'}}
}
}
+
+namespace pr10644 {
+ struct string {
+ string(const char* __s);
+ };
+ class map {
+ int& operator[](const string& __k);
+ public:
+ int& operator[](const string&& __k);
+ };
+ void foo() {
+ static map key_map;
+ key_map["line"];
+ }
+}
+
+namespace PR11003 {
+ class Value {
+ };
+ struct MoveRef {
+ operator Value &() const ;
+ };
+ MoveRef Move(int);
+ void growTo() {
+ Value x = Move(0);
+ Value y(Move(0));
+ }
+}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx0x-no-extra-copy.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx0x-no-extra-copy.cpp
index 5cfb11a1fc1b..27eb6d1c078f 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx0x-no-extra-copy.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx0x-no-extra-copy.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// C++03 requires that we check for a copy constructor when binding a
// reference to a reference-compatible rvalue, since we are allowed to
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp
new file mode 100644
index 000000000000..07a5cef30478
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+char x1[]("hello");
+extern char x1[6];
+
+char x2[] = "hello";
+extern char x2[6];
diff --git a/test/CXX/dcl.decl/dcl.init/p14-0x.cpp b/test/CXX/dcl.decl/dcl.init/p14-0x.cpp
index e5b58899545c..419f2bff1282 100644
--- a/test/CXX/dcl.decl/dcl.init/p14-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.init/p14-0x.cpp
@@ -1,10 +1,10 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct NoDefault {
NoDefault() = delete; // expected-note {{here}}
NoDefault(int);
};
-struct Explicit { // expected-note {{candidate}} expected-note {{here}}
+struct Explicit { // expected-note 2 {{candidate}} expected-note {{here}}
explicit Explicit(int);
};
struct NoCopy {
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.array/p1-cxx0x.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.array/p1-cxx0x.cpp
index b0575b8236bb..102746c3db29 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.array/p1-cxx0x.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.array/p1-cxx0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
void f() {
int b[5];
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp
index 9d26561ca8de..385e45dadfae 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp
@@ -5,7 +5,7 @@ struct A {
};
struct B : public A {
- void f(int a);
+ void f(int a); // expected-note{{'f' declared here}}
};
void m() {
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
index b2129b259bb3..f3dec52f63b3 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
@@ -41,7 +41,7 @@ namespace N1 {
void m()
{
- void f(int, int);
+ void f(int, int); // expected-note{{'f' declared here}}
f(4); // expected-error{{too few arguments to function call}}
void f(int, int = 5); // expected-note{{previous definition}}
f(4); // okay
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
new file mode 100644
index 000000000000..a87982906631
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+// FIXME: test with non-std qualifiers
+
+namespace move {
+ struct Const {
+ Const(const Const&&) = default; // expected-error {{the parameter for an explicitly-defaulted move constructor may not be const}}
+ Const& operator=(const Const&&) = default; // expected-error {{the parameter for an explicitly-defaulted move assignment operator may not be const}}
+ };
+
+ struct Volatile {
+ Volatile(volatile Volatile&&) = default; // expected-error {{the parameter for an explicitly-defaulted move constructor may not be volatile}}
+ Volatile& operator=(volatile Volatile&&) = default; // expected-error {{the parameter for an explicitly-defaulted move assignment operator may not be volatile}}
+ };
+
+ struct AssignmentRet1 {
+ AssignmentRet1&& operator=(AssignmentRet1&&) = default; // expected-error {{an explicitly-defaulted move assignment operator must return an unqualified lvalue reference to its class type}}
+ };
+
+ struct AssignmentRet2 {
+ const AssignmentRet2& operator=(AssignmentRet2&&) = default; // expected-error {{an explicitly-defaulted move assignment operator must return an unqualified lvalue reference to its class type}}
+ };
+
+ struct ConstAssignment {
+ ConstAssignment& operator=(ConstAssignment&&) const = default; // expected-error {{an explicitly-defaulted move assignment operator may not have 'const', 'constexpr' or 'volatile' qualifiers}}
+ };
+}
+
+namespace copy {
+ struct Volatile {
+ Volatile(const volatile Volatile&) = default; // expected-error {{the parameter for an explicitly-defaulted copy constructor may not be volatile}}
+ Volatile& operator=(const volatile Volatile&) = default; // expected-error {{the parameter for an explicitly-defaulted copy assignment operator may not be volatile}}
+ };
+
+ struct Const {
+ Const(const Const&) = default;
+ Const& operator=(const Const&) = default;
+ };
+
+ struct NonConst {
+ NonConst(NonConst&) = default;
+ NonConst& operator=(NonConst&) = default;
+ };
+
+ struct BadConst {
+ NonConst nc; // makes implicit copy non-const
+ BadConst(const BadConst&) = default; // expected-error {{is const, but}}
+ BadConst& operator=(const BadConst&) = default; // expected-error {{is const, but}}
+ };
+
+ struct AssignmentRet1 {
+ AssignmentRet1&& operator=(const AssignmentRet1&) = default; // expected-error {{an explicitly-defaulted copy assignment operator must return an unqualified lvalue reference to its class type}}
+ };
+
+ struct AssignmentRet2 {
+ const AssignmentRet2& operator=(const AssignmentRet2&) = default; // expected-error {{an explicitly-defaulted copy assignment operator must return an unqualified lvalue reference to its class type}}
+ };
+
+ struct ConstAssignment {
+ ConstAssignment& operator=(const ConstAssignment&) const = default; // expected-error {{an explicitly-defaulted copy assignment operator may not have 'const', 'constexpr' or 'volatile' qualifiers}}
+ };
+}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
index 868d009003ee..19a5f23e3f17 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -fcxx-exceptions -fexceptions -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fcxx-exceptions -fexceptions -verify %s
// When it is part of a parameter-declaration-clause, the parameter
// pack is a function parameter pack.
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp
index 1293a067576a..0e69521fbdfc 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
template<typename T> struct identity;
template<typename ...Types> struct tuple;
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p2-cxx0x.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p2-cxx0x.cpp
index 70c9aeb48819..6b1f3e438d8f 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p2-cxx0x.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p2-cxx0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
auto a() -> int; // ok
const auto b() -> int; // expected-error {{function with trailing return type must specify return type 'auto', not 'auto const'}}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp
index c81c844f3448..ce0a082462a2 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
void f0() &; // expected-error{{ref-qualifier '&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
void f1() &&; // expected-error{{ref-qualifier '&&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p8-0x.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p8-0x.cpp
index 21efbfff1ab9..11926f1bd6cb 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p8-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p8-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
auto f() -> int[32]; // expected-error{{function cannot return array}}
auto g() -> int(int); // expected-error{{function cannot return function}}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp
index ca4701554be4..4d71a8e4b4c6 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp
@@ -1,3 +1,3 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
auto j() -> enum { e3 }; // expected-error{{can not be defined in a type specifier}}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p6-0x.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p6-0x.cpp
index 789cde75241a..4ce80bc35ac9 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p6-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p6-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
template<typename T, typename U>
struct is_same {
diff --git a/test/CXX/dcl.decl/p4-0x.cpp b/test/CXX/dcl.decl/p4-0x.cpp
index 9fa2ea19d411..98c33b25f4d2 100644
--- a/test/CXX/dcl.decl/p4-0x.cpp
+++ b/test/CXX/dcl.decl/p4-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
struct X {
void f() &;
diff --git a/test/CXX/except/except.spec/canonical.cpp b/test/CXX/except/except.spec/canonical.cpp
index 9bc26de14440..81ca2ae0a20e 100644
--- a/test/CXX/except/except.spec/canonical.cpp
+++ b/test/CXX/except/except.spec/canonical.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// PR10087: Make sure that we don't conflate exception specifications
// from different functions in the canonical type system.
diff --git a/test/CXX/except/except.spec/p1.cpp b/test/CXX/except/except.spec/p1.cpp
index 86924bb49d75..a6e785024778 100644
--- a/test/CXX/except/except.spec/p1.cpp
+++ b/test/CXX/except/except.spec/p1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
// Simple parser tests, dynamic specification.
@@ -60,14 +60,22 @@ namespace noex {
}
namespace noexcept_unevaluated {
- template<typename T> void f(T) {
+ template<typename T> bool f(T) {
T* x = 1;
}
template<typename T>
- void g(T x) noexcept((f(x), sizeof(T) == 4)) { }
+ void g(T x) noexcept((sizeof(T) == sizeof(int)) || f(x)) { }
void h() {
g(1);
}
}
+
+namespace PR11084 {
+ template<int X> struct A {
+ static int f() noexcept(1/X) { return 10; } // expected-error{{argument to noexcept specifier must be a constant expression}}
+ };
+
+ void g() { A<0>::f(); } // expected-note{{in instantiation of template class 'PR11084::A<0>' requested here}}
+}
diff --git a/test/CXX/except/except.spec/p11.cpp b/test/CXX/except/except.spec/p11.cpp
index 268b53ad79d0..0e4fad53e350 100644
--- a/test/CXX/except/except.spec/p11.cpp
+++ b/test/CXX/except/except.spec/p11.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
// This is the "let the user shoot himself in the foot" clause.
void f() noexcept {
diff --git a/test/CXX/except/except.spec/p14.cpp b/test/CXX/except/except.spec/p14.cpp
index f42fbe907ffe..8763a7028195 100644
--- a/test/CXX/except/except.spec/p14.cpp
+++ b/test/CXX/except/except.spec/p14.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -verify -std=c++0x %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -verify -std=c++11 %s
struct A { };
struct B { };
struct C { };
diff --git a/test/CXX/except/except.spec/p15.cpp b/test/CXX/except/except.spec/p15.cpp
index 2dae9623e0cc..110ec3fa0300 100644
--- a/test/CXX/except/except.spec/p15.cpp
+++ b/test/CXX/except/except.spec/p15.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
// Deallocation functions are implicitly noexcept.
// Thus, explicit specs aren't allowed to conflict.
diff --git a/test/CXX/except/except.spec/p2-places.cpp b/test/CXX/except/except.spec/p2-places.cpp
index db1ee77463fb..67647fb043a9 100644
--- a/test/CXX/except/except.spec/p2-places.cpp
+++ b/test/CXX/except/except.spec/p2-places.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
// Tests where specs are allowed and where they aren't.
diff --git a/test/CXX/except/except.spec/p3.cpp b/test/CXX/except/except.spec/p3.cpp
index 5df5f26a8f8f..d77aea40602c 100644
--- a/test/CXX/except/except.spec/p3.cpp
+++ b/test/CXX/except/except.spec/p3.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
// Exception specification compatibility.
// We test function pointers, because functions have an extra rule in p4.
diff --git a/test/CXX/except/except.spec/p5-pointers.cpp b/test/CXX/except/except.spec/p5-pointers.cpp
index 171afff22b5b..dd3c0600ce92 100644
--- a/test/CXX/except/except.spec/p5-pointers.cpp
+++ b/test/CXX/except/except.spec/p5-pointers.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
// Assignment of function pointers.
diff --git a/test/CXX/except/except.spec/p5-virtual.cpp b/test/CXX/except/except.spec/p5-virtual.cpp
index ceea9f8f2500..69daec6ee533 100644
--- a/test/CXX/except/except.spec/p5-virtual.cpp
+++ b/test/CXX/except/except.spec/p5-virtual.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
// Compatibility of virtual functions.
diff --git a/test/CXX/except/except.spec/p9-dynamic.cpp b/test/CXX/except/except.spec/p9-dynamic.cpp
index 3f496f25c9ba..4559e0d467b1 100644
--- a/test/CXX/except/except.spec/p9-dynamic.cpp
+++ b/test/CXX/except/except.spec/p9-dynamic.cpp
@@ -7,5 +7,6 @@ void target() throw(int)
// CHECK: invoke void @_Z8externalv()
external();
}
-// CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector({{.*}} i8* bitcast (i8** @_ZTIi to i8*)) nounwind
-// CHECK: call void @__cxa_call_unexpected
+// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+// CHECK-NEXT: filter [1 x i8*] [i8* bitcast (i8** @_ZTIi to i8*)]
+// CHECK: call void @__cxa_call_unexpected
diff --git a/test/CXX/except/except.spec/p9-noexcept.cpp b/test/CXX/except/except.spec/p9-noexcept.cpp
index 76ac66c841b9..7c8d0ef1fb44 100644
--- a/test/CXX/except/except.spec/p9-noexcept.cpp
+++ b/test/CXX/except/except.spec/p9-noexcept.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -std=c++0x -triple=x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions | FileCheck %s
+// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions | FileCheck %s
void external();
@@ -7,7 +7,8 @@ void target() noexcept
// CHECK: invoke void @_Z8externalv()
external();
}
-// CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector({{.*}} i8* null) nounwind
+// CHECK: 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: unreachable
diff --git a/test/CXX/except/except.spec/template.cpp b/test/CXX/except/except.spec/template.cpp
index f8b7270344a7..805a604db588 100644
--- a/test/CXX/except/except.spec/template.cpp
+++ b/test/CXX/except/except.spec/template.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
// We use pointer assignment compatibility to test instantiation.
diff --git a/test/CXX/expr/expr.cast/p4-0x.cpp b/test/CXX/expr/expr.cast/p4-0x.cpp
index 5824cd21f1e7..96bf5f91196b 100644
--- a/test/CXX/expr/expr.cast/p4-0x.cpp
+++ b/test/CXX/expr/expr.cast/p4-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
struct X { };
struct Y : X { };
diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp
index 1b38cf19b42e..2c6a46b3beaf 100644
--- a/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/test/CXX/expr/expr.const/p2-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
// PR9999
template<bool v>
diff --git a/test/CXX/expr/expr.mptr.oper/p6-0x.cpp b/test/CXX/expr/expr.mptr.oper/p6-0x.cpp
index d5dc7d2cbe58..917b2dab7c32 100644
--- a/test/CXX/expr/expr.mptr.oper/p6-0x.cpp
+++ b/test/CXX/expr/expr.mptr.oper/p6-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
struct X { };
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 bb4726dd3309..d51ba09835d2 100644
--- a/test/CXX/expr/expr.post/expr.call/p7-0x.cpp
+++ b/test/CXX/expr/expr.post/expr.call/p7-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct X1 {
X1();
@@ -15,3 +15,16 @@ void f(X1 x1, X2 x2) {
vararg(x1); // okay
vararg(x2); // expected-error{{cannot pass object of non-trivial type 'X2' through variadic function; call will abort at runtime}}
}
+
+
+namespace PR11131 {
+ struct S;
+
+ S &getS();
+
+ void f(...);
+
+ void g() {
+ (void)sizeof(f(getS()));
+ }
+}
diff --git a/test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp b/test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp
index d46488107ba6..6ba8d519346e 100644
--- a/test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp
+++ b/test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// The result of the expression const_cast<T>(v) is of type T. If T is
// an lvalue reference to object type, the result is an lvalue; if T
diff --git a/test/CXX/expr/expr.post/expr.dynamic.cast/p3-0x.cpp b/test/CXX/expr/expr.post/expr.dynamic.cast/p3-0x.cpp
index 3b448a80db2b..cddd5cf25e3b 100644
--- a/test/CXX/expr/expr.post/expr.dynamic.cast/p3-0x.cpp
+++ b/test/CXX/expr/expr.post/expr.dynamic.cast/p3-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
struct X { virtual ~X(); };
struct Y : public X { };
diff --git a/test/CXX/expr/expr.post/expr.reinterpret.cast/p1-0x.cpp b/test/CXX/expr/expr.post/expr.reinterpret.cast/p1-0x.cpp
index e80082a0408a..22892a63ab16 100644
--- a/test/CXX/expr/expr.post/expr.reinterpret.cast/p1-0x.cpp
+++ b/test/CXX/expr/expr.post/expr.reinterpret.cast/p1-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// If T is an lvalue reference type or an rvalue reference to function
// type, the result is an lvalue; if T is an rvalue reference to
diff --git a/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp b/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp
index c10335183e21..9ef15e6642b1 100644
--- a/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp
+++ b/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// A glvalue of type "cv1 T1" can be cast to type "rvalue reference to
// cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1" (8.5.3).
diff --git a/test/CXX/expr/expr.post/expr.static.cast/p9-0x.cpp b/test/CXX/expr/expr.post/expr.static.cast/p9-0x.cpp
index 4acafb89acaf..731c50844428 100644
--- a/test/CXX/expr/expr.post/expr.static.cast/p9-0x.cpp
+++ b/test/CXX/expr/expr.post/expr.static.cast/p9-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
enum class EC { ec1 };
diff --git a/test/CXX/expr/expr.prim/p12-0x.cpp b/test/CXX/expr/expr.prim/p12-0x.cpp
index 0ff29a18825b..aec62ddd97a7 100644
--- a/test/CXX/expr/expr.prim/p12-0x.cpp
+++ b/test/CXX/expr/expr.prim/p12-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct S {
int *j = &nonexistent; // expected-error {{use of undeclared identifier 'nonexistent'}}
diff --git a/test/CXX/expr/expr.prim/p4-0x.cpp b/test/CXX/expr/expr.prim/p4-0x.cpp
index 13735fab4a9d..143ba897ae95 100644
--- a/test/CXX/expr/expr.prim/p4-0x.cpp
+++ b/test/CXX/expr/expr.prim/p4-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct S {
S *p = this; // ok
diff --git a/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp b/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp
index c9a8887d2644..4ebbfce289ea 100644
--- a/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp
+++ b/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
template<typename T>
struct only {
diff --git a/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp b/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp
index 4c924b137ccd..eca1ec790199 100644
--- a/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp
+++ b/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x -fexceptions %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -fexceptions %s
typedef __SIZE_TYPE__ size_t;
struct S {
diff --git a/test/CXX/expr/expr.unary/expr.sizeof/p5-0x.cpp b/test/CXX/expr/expr.unary/expr.sizeof/p5-0x.cpp
index 382461541546..afd8ef05302f 100644
--- a/test/CXX/expr/expr.unary/expr.sizeof/p5-0x.cpp
+++ b/test/CXX/expr/expr.unary/expr.sizeof/p5-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// Test parsing + semantic analysis
template<typename ...Types> struct count_types {
diff --git a/test/CXX/expr/expr.unary/expr.unary.noexcept/cg.cpp b/test/CXX/expr/expr.unary/expr.unary.noexcept/cg.cpp
index 67d853a287f8..5c1029f1a3ff 100644
--- a/test/CXX/expr/expr.unary/expr.unary.noexcept/cg.cpp
+++ b/test/CXX/expr/expr.unary/expr.unary.noexcept/cg.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin10 -S -emit-llvm -std=c++0x -include %S/ser.h %s -o - | FileCheck %s
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin10 -emit-pch -o %t-ser.pch -std=c++0x -x c++ %S/ser.h
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin10 -S -emit-llvm -std=c++0x -include-pch %t-ser.pch %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin10 -S -emit-llvm -std=c++11 -include %S/ser.h %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin10 -emit-pch -o %t-ser.pch -std=c++11 -x c++ %S/ser.h
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin10 -S -emit-llvm -std=c++11 -include-pch %t-ser.pch %s -o - | FileCheck %s
struct D {
~D() throw();
diff --git a/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp b/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp
index 6d1e523b51bf..b5de1a7f8fee 100644
--- a/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp
+++ b/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++0x -fms-extensions %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -fms-extensions %s
#define P(e) static_assert(noexcept(e), "expected nothrow")
#define N(e) static_assert(!noexcept(e), "expected throw")
diff --git a/test/CXX/expr/expr.unary/expr.unary.op/p6.cpp b/test/CXX/expr/expr.unary/expr.unary.op/p6.cpp
index 30f8c5491951..ac11940c80da 100644
--- a/test/CXX/expr/expr.unary/expr.unary.op/p6.cpp
+++ b/test/CXX/expr/expr.unary/expr.unary.op/p6.cpp
@@ -29,8 +29,7 @@ bool b8 = !S(); //expected-error {{invalid argument type 'S'}}
namespace PR8181
{
- void f() { } // expected-note{{candidate function}}
- void f(char) { } // expected-note{{candidate function}}
- bool b = !&f; //expected-error {{cannot resolve overloaded function 'f' from context}}
-
+ bool f() { } // expected-note{{possible target for call}}
+ void f(char) { } // expected-note{{possible target for call}}
+ bool b = !&f; //expected-error {{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}}
}
diff --git a/test/CXX/lex/lex.literal/lex.ccon/p1.cpp b/test/CXX/lex/lex.literal/lex.ccon/p1.cpp
index 7b65f7ee8320..5342153b63ba 100644
--- a/test/CXX/lex/lex.literal/lex.ccon/p1.cpp
+++ b/test/CXX/lex/lex.literal/lex.ccon/p1.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// Check types of char literals
extern char a;
@@ -7,3 +8,9 @@ extern int b;
extern __typeof('asdf') b;
extern wchar_t c;
extern __typeof(L'a') c;
+#if __cplusplus >= 201103L
+extern char16_t d;
+extern __typeof(u'a') d;
+extern char32_t e;
+extern __typeof(U'a') e;
+#endif
diff --git a/test/CXX/lex/lex.literal/lex.ext/p1.cpp b/test/CXX/lex/lex.literal/lex.ext/p1.cpp
new file mode 100644
index 000000000000..39812280c090
--- /dev/null
+++ b/test/CXX/lex/lex.literal/lex.ext/p1.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+int * operator "" p31(long double); // expected-warning{{user-defined literal with suffix 'p31' is preempted by C99 hexfloat extension}}
+long double operator "" _p31(long double);
+long double operator "" pi(long double); // expected-warning{{user-defined literals not starting with '_' are reserved by the implementation}}
+
+float hexfloat = 0x1p31; // allow hexfloats
diff --git a/test/CXX/lex/lex.pptoken/p3-0x.cpp b/test/CXX/lex/lex.pptoken/p3-0x.cpp
index 4ae867c2095e..3d56ac17bd5b 100644
--- a/test/CXX/lex/lex.pptoken/p3-0x.cpp
+++ b/test/CXX/lex/lex.pptoken/p3-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
int a<::> = { 1, 2, 3 };
int b = a<:::a<:0:>:>;
diff --git a/test/CXX/over/over.built/p23.cpp b/test/CXX/over/over.built/p23.cpp
new file mode 100644
index 000000000000..41255214ec6a
--- /dev/null
+++ b/test/CXX/over/over.built/p23.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+struct Variant {
+ template <typename T> operator T();
+};
+
+Variant getValue();
+
+void testVariant() {
+ bool ret1 = getValue() || getValue();
+ bool ret2 = getValue() && getValue();
+ bool ret3 = !getValue();
+}
+
+struct ExplicitVariant {
+ template <typename T> explicit operator T();
+};
+
+ExplicitVariant getExplicitValue();
+
+void testExplicitVariant() {
+ bool ret1 = getExplicitValue() || getExplicitValue();
+ bool ret2 = getExplicitValue() && getExplicitValue();
+ bool ret3 = !getExplicitValue();
+}
diff --git a/test/CXX/over/over.built/p25.cpp b/test/CXX/over/over.built/p25.cpp
index c185fb4fb96d..aea3854a420e 100644
--- a/test/CXX/over/over.built/p25.cpp
+++ b/test/CXX/over/over.built/p25.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
enum class Color { Red, Green, Blue };
diff --git a/test/CXX/over/over.load/p2-0x.cpp b/test/CXX/over/over.load/p2-0x.cpp
index f0ace9044a2d..cf38741056ab 100644
--- a/test/CXX/over/over.load/p2-0x.cpp
+++ b/test/CXX/over/over.load/p2-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// Member function declarations with the same name and the same
// parameter-type-list as well as mem- ber function template
diff --git a/test/CXX/over/over.match/over.match.best/over.best.ics/over.ics.user/p3-0x.cpp b/test/CXX/over/over.match/over.match.best/over.best.ics/over.ics.user/p3-0x.cpp
index d9e0ff88bd8d..1c71468e453d 100644
--- a/test/CXX/over/over.match/over.match.best/over.best.ics/over.ics.user/p3-0x.cpp
+++ b/test/CXX/over/over.match/over.match.best/over.best.ics/over.ics.user/p3-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
namespace PR6285 {
template<typename T> struct identity
diff --git a/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp b/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp
index ab171bc3f6f4..3971acc58169 100644
--- a/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp
+++ b/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
namespace std_example {
int i;
int f1();
diff --git a/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp b/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp
index 8ccc5b6204d0..3845af09d14c 100644
--- a/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp
+++ b/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
template<typename T> T &lvalue();
template<typename T> T &&xvalue();
diff --git a/test/CXX/over/over.over/p2-resolve-single-template-id.cpp b/test/CXX/over/over.over/p2-resolve-single-template-id.cpp
index 544a66d9e39a..d2a23ce96df2 100644
--- a/test/CXX/over/over.over/p2-resolve-single-template-id.cpp
+++ b/test/CXX/over/over.over/p2-resolve-single-template-id.cpp
@@ -27,26 +27,26 @@ namespace DontAllowUnresolvedOverloadedExpressionInAnUnusedExpression
void one() { }
template<class T> void oneT() { }
- void two() { } //expected-note 2{{candidate}}
- void two(int) { } //expected-note 2{{candidate}}
- template<class T> void twoT() { } //expected-note 2{{candidate}}
- template<class T> void twoT(T) { } //expected-note 2{{candidate}}
+ void two() { } // expected-note 2 {{possible target for call}}
+ void two(int) { } // expected-note 2 {{possible target for call}}
+ template<class T> void twoT() { } // expected-note 2 {{possible target for call}}
+ template<class T> void twoT(T) { } // expected-note 2 {{possible target for call}}
void check()
{
one; // expected-warning {{expression result unused}}
- two; // expected-error{{cannot resolve overloaded function 'two' from context}}
+ two; // expected-error{{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}}
oneT<int>; // expected-warning {{expression result unused}}
- twoT<int>; // expected-error {{cannot resolve overloaded function 'twoT' from context}}
+ twoT<int>; // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}}
}
// check the template function case
template<class T> void check()
{
one; // expected-warning {{expression result unused}}
- two; // expected-error{{cannot resolve overloaded function 'two' from context}}
+ two; // expected-error{{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}}
oneT<int>; // expected-warning {{expression result unused}}
- twoT<int>; // expected-error {{cannot resolve overloaded function 'twoT' from context}}
+ twoT<int>; // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}}
}
@@ -128,8 +128,8 @@ namespace member_pointers {
template <typename T> bool f(T) { return false; }
template <typename T> static bool g(T) { return false; }
- template <typename T> bool h(T) { return false; }
- template <int N> static bool h(int) { return false; }
+ template <typename T> bool h(T) { return false; } // expected-note 3 {{possible target for call}}
+ template <int N> static bool h(int) { return false; } // expected-note 3 {{possible target for call}}
};
void test(S s) {
@@ -137,8 +137,8 @@ namespace member_pointers {
if (S::f<int>) return; // expected-error {{call to non-static member function without an object argument}}
if (&S::f<char>) return;
if (&S::f<int>) return;
- if (s.f<char>) return; // expected-error {{a bound member function may only be called}}
- if (s.f<int>) return; // expected-error {{a bound member function may only be called}}
+ if (s.f<char>) return; // expected-error {{reference to non-static member function must be called}}
+ if (s.f<int>) return; // expected-error {{reference to non-static member function must be called}}
if (&s.f<char>) return; // expected-error {{cannot create a non-constant pointer to member function}}
if (&s.f<int>) return; // expected-error {{cannot create a non-constant pointer to member function}}
@@ -152,13 +152,13 @@ namespace member_pointers {
if (&s.g<int>) return;
if (S::h<42>) return;
- if (S::h<int>) return; // expected-error {{a bound member function may only be called}}
+ if (S::h<int>) return; // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}}
if (&S::h<42>) return;
if (&S::h<int>) return;
if (s.h<42>) return;
- if (s.h<int>) return; // expected-error {{a bound member function may only be called}}
+ if (s.h<int>) return; // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}}
if (&s.h<42>) return;
- if (&s.h<int>) return; // expected-error {{a bound member function may only be called}}
+ if (&s.h<int>) return; // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}}
{ bool b = S::f<char>; } // expected-error {{call to non-static member function without an object argument}}
{ bool b = S::f<int>; } // expected-error {{call to non-static member function without an object argument}}
diff --git a/test/CXX/special/class.copy/implicit-move-def.cpp b/test/CXX/special/class.copy/implicit-move-def.cpp
new file mode 100644
index 000000000000..94023cbc1d7b
--- /dev/null
+++ b/test/CXX/special/class.copy/implicit-move-def.cpp
@@ -0,0 +1,116 @@
+// RUN: %clang_cc1 -emit-llvm -o - -std=c++11 %s | FileCheck -check-prefix=CHECK-ASSIGN %s
+// RUN: %clang_cc1 -emit-llvm -o - -std=c++11 %s | FileCheck -check-prefix=CHECK-CTOR %s
+
+// construct
+
+struct E {
+ E();
+ E(E&&);
+};
+
+struct F {
+ F();
+ F(F&&);
+};
+
+struct G {
+ E e;
+};
+
+struct H : G {
+ F l;
+ E m;
+ F ar[2];
+};
+
+void f() {
+ H s;
+ // CHECK: call void @_ZN1HC1EOS_
+ H t(static_cast<H&&>(s));
+}
+
+
+// assign
+
+struct A {
+ A &operator =(A&&);
+};
+
+struct B {
+ B &operator =(B&&);
+};
+
+struct C {
+ A a;
+};
+
+struct D : C {
+ A a;
+ B b;
+ A ar[2];
+};
+
+void g() {
+ D d;
+ // CHECK: call {{.*}} @_ZN1DaSEOS_
+ d = D();
+}
+
+// PR10822
+struct I {
+ unsigned var[1];
+};
+
+// CHECK: define void @_Z1hv() nounwind {
+void h() {
+ I i;
+ // CHECK: call void @llvm.memcpy.
+ i = I();
+ // CHECK-NEXT: ret void
+}
+
+// PR10860
+struct Empty { };
+struct VirtualWithEmptyBase : Empty {
+ virtual void f();
+};
+
+// CHECK: define void @_Z25move_VirtualWithEmptyBaseR20VirtualWithEmptyBaseS0_
+void move_VirtualWithEmptyBase(VirtualWithEmptyBase &x, VirtualWithEmptyBase &y) {
+ // CHECK: call {{.*}} @_ZN20VirtualWithEmptyBaseaSEOS_
+ x = static_cast<VirtualWithEmptyBase&&>(y);
+ // CHECK-NEXT: ret void
+}
+
+// move assignment ops
+
+// CHECK-ASSIGN: define linkonce_odr {{.*}} @_ZN1DaSEOS_
+// CHECK-ASSIGN: call {{.*}} @_ZN1CaSEOS_
+// CHECK-ASSIGN: call {{.*}} @_ZN1AaSEOS_
+// CHECK-ASSIGN: call {{.*}} @_ZN1BaSEOS_
+// array loop
+// CHECK-ASSIGN: br i1
+// CHECK-ASSIGN: call {{.*}} @_ZN1AaSEOS_
+
+// VirtualWithEmptyBase move assignment operatpr
+// CHECK-ASSIGN: define linkonce_odr {{.*}} @_ZN20VirtualWithEmptyBaseaSEOS_
+// CHECK-ASSIGN: store
+// CHECK-ASSIGN-NEXT: store
+// CHECK-NOT: call
+// CHECK: ret
+
+// CHECK-ASSIGN: define linkonce_odr {{.*}} @_ZN1CaSEOS_
+// CHECK-ASSIGN: call {{.*}} @_ZN1AaSEOS_
+
+// move ctors
+
+// CHECK-CTOR: define linkonce_odr void @_ZN1HC2EOS_
+// CHECK-CTOR: call void @_ZN1GC2EOS_
+// CHECK-CTOR: call void @_ZN1FC1EOS_
+// CHECK-CTOR: call void @_ZN1EC1EOS_
+// array loop
+// CHECK-CTOR: br i1
+// CHECK-CTOR: call void @_ZN1FC1EOS_
+
+// CHECK-CTOR: define linkonce_odr void @_ZN1GC2EOS_
+// CHECK-CTOR: call void @_ZN1EC1EOS_
diff --git a/test/CXX/special/class.copy/implicit-move.cpp b/test/CXX/special/class.copy/implicit-move.cpp
new file mode 100644
index 000000000000..74f7eee9ee89
--- /dev/null
+++ b/test/CXX/special/class.copy/implicit-move.cpp
@@ -0,0 +1,164 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+// Tests for implicit (non-)declaration of move constructor and
+// assignment: p9, p11, p20, p23.
+
+// This class, used as a member, allows to distinguish move from copy because
+// move operations are no-throw, copy operations aren't.
+struct ThrowingCopy {
+ ThrowingCopy() noexcept;
+ ThrowingCopy(ThrowingCopy &&) noexcept;
+ ThrowingCopy(const ThrowingCopy &) noexcept(false);
+ ThrowingCopy & operator =(ThrowingCopy &&) noexcept;
+ ThrowingCopy & operator =(const ThrowingCopy &) noexcept(false);
+};
+
+struct HasCopyConstructor {
+ ThrowingCopy tc;
+ HasCopyConstructor() noexcept;
+ HasCopyConstructor(const HasCopyConstructor &) noexcept(false);
+};
+
+struct HasCopyAssignment {
+ ThrowingCopy tc;
+ HasCopyAssignment() noexcept;
+ HasCopyAssignment & operator =(const HasCopyAssignment &) noexcept(false);
+};
+
+struct HasMoveConstructor { // expected-note {{implicit copy assignment}}
+ ThrowingCopy tc;
+ HasMoveConstructor() noexcept;
+ HasMoveConstructor(HasMoveConstructor &&) noexcept;
+};
+
+struct HasMoveAssignment { // expected-note {{implicit copy constructor}}
+ ThrowingCopy tc;
+ HasMoveAssignment() noexcept;
+ HasMoveAssignment & operator =(HasMoveAssignment &&) noexcept;
+};
+
+struct HasDestructor {
+ ThrowingCopy tc;
+ HasDestructor() noexcept;
+ ~HasDestructor() noexcept;
+};
+
+void test_basic_exclusion() {
+ static_assert(!noexcept(HasCopyConstructor((HasCopyConstructor()))), "");
+ HasCopyConstructor hcc;
+ static_assert(!noexcept(hcc = HasCopyConstructor()), "");
+
+ static_assert(!noexcept(HasCopyAssignment((HasCopyAssignment()))), "");
+ HasCopyAssignment hca;
+ static_assert(!noexcept(hca = HasCopyAssignment()), "");
+
+ static_assert(noexcept(HasMoveConstructor((HasMoveConstructor()))), "");
+ HasMoveConstructor hmc;
+ hmc = HasMoveConstructor(); // expected-error {{selected deleted operator}}
+
+ (HasMoveAssignment(HasMoveAssignment())); // expected-error {{uses deleted function}}
+ HasMoveAssignment hma;
+ static_assert(noexcept(hma = HasMoveAssignment()), "");
+
+ static_assert(!noexcept(HasDestructor((HasDestructor()))), "");
+ HasDestructor hd;
+ static_assert(!noexcept(hd = HasDestructor()), "");
+}
+
+struct PrivateMove {
+ PrivateMove() noexcept;
+ PrivateMove(const PrivateMove &) noexcept(false);
+ PrivateMove & operator =(const PrivateMove &) noexcept(false);
+private:
+ PrivateMove(PrivateMove &&) noexcept;
+ PrivateMove & operator =(PrivateMove &&) noexcept;
+};
+
+struct InheritsPrivateMove : PrivateMove {};
+struct ContainsPrivateMove {
+ PrivateMove pm;
+};
+
+struct PrivateDestructor {
+ PrivateDestructor() noexcept;
+ PrivateDestructor(const PrivateDestructor &) noexcept(false);
+ PrivateDestructor(PrivateDestructor &&) noexcept;
+private:
+ ~PrivateDestructor() noexcept;
+};
+
+struct InheritsPrivateDestructor : PrivateDestructor {}; // expected-note {{explicitly marked deleted}}
+struct ContainsPrivateDestructor { // expected-note {{explicitly marked deleted}}
+ PrivateDestructor pd;
+};
+
+struct NonTrivialCopyOnly {
+ NonTrivialCopyOnly() noexcept;
+ NonTrivialCopyOnly(const NonTrivialCopyOnly &) noexcept(false);
+ NonTrivialCopyOnly & operator =(const NonTrivialCopyOnly &) noexcept(false);
+};
+
+struct InheritsNonTrivialCopyOnly : NonTrivialCopyOnly {};
+struct ContainsNonTrivialCopyOnly {
+ NonTrivialCopyOnly ntco;
+};
+
+struct ContainsConst {
+ const int i;
+ ContainsConst() noexcept;
+ ContainsConst & operator =(ContainsConst &); // expected-note {{not viable}}
+};
+
+struct ContainsRef {
+ int &i;
+ ContainsRef() noexcept;
+ ContainsRef & operator =(ContainsRef &); // expected-note {{not viable}}
+};
+
+struct Base {
+ Base & operator =(Base &);
+};
+struct DirectVirtualBase : virtual Base {}; // expected-note {{copy assignment operator) not viable}}
+struct IndirectVirtualBase : DirectVirtualBase {}; // expected-note {{copy assignment operator) not viable}}
+
+void test_deletion_exclusion() {
+ // FIXME: How to test the union thing?
+
+ static_assert(!noexcept(InheritsPrivateMove(InheritsPrivateMove())), "");
+ static_assert(!noexcept(ContainsPrivateMove(ContainsPrivateMove())), "");
+ InheritsPrivateMove ipm;
+ static_assert(!noexcept(ipm = InheritsPrivateMove()), "");
+ ContainsPrivateMove cpm;
+ static_assert(!noexcept(cpm = ContainsPrivateMove()), "");
+
+ (InheritsPrivateDestructor(InheritsPrivateDestructor())); // expected-error {{call to deleted constructor}}
+ (ContainsPrivateDestructor(ContainsPrivateDestructor())); // expected-error {{call to deleted constructor}}
+
+ static_assert(!noexcept(InheritsNonTrivialCopyOnly(InheritsNonTrivialCopyOnly())), "");
+ static_assert(!noexcept(ContainsNonTrivialCopyOnly(ContainsNonTrivialCopyOnly())), "");
+ InheritsNonTrivialCopyOnly intco;
+ static_assert(!noexcept(intco = InheritsNonTrivialCopyOnly()), "");
+ ContainsNonTrivialCopyOnly cntco;
+ static_assert(!noexcept(cntco = ContainsNonTrivialCopyOnly()), "");
+
+ ContainsConst cc;
+ cc = ContainsConst(); // expected-error {{no viable}}
+
+ ContainsRef cr;
+ cr = ContainsRef(); // expected-error {{no viable}}
+
+ DirectVirtualBase dvb;
+ dvb = DirectVirtualBase(); // expected-error {{no viable}}
+
+ IndirectVirtualBase ivb;
+ ivb = IndirectVirtualBase(); // expected-error {{no viable}}
+}
+
+struct ContainsRValueRef {
+ int&& ri;
+ ContainsRValueRef() noexcept;
+};
+
+void test_contains_rref() {
+ (ContainsRValueRef(ContainsRValueRef()));
+}
diff --git a/test/CXX/special/class.copy/p11.0x.copy.cpp b/test/CXX/special/class.copy/p11.0x.copy.cpp
new file mode 100644
index 000000000000..752872adb9f5
--- /dev/null
+++ b/test/CXX/special/class.copy/p11.0x.copy.cpp
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+struct NonTrivial {
+ NonTrivial(const NonTrivial&);
+};
+
+union DeletedNTVariant { // expected-note{{here}}
+ NonTrivial NT;
+ DeletedNTVariant();
+};
+DeletedNTVariant DVa;
+DeletedNTVariant DVb(DVa); // expected-error{{call to deleted constructor}}
+
+struct DeletedNTVariant2 { // expected-note{{here}}
+ union {
+ NonTrivial NT;
+ };
+ DeletedNTVariant2();
+};
+DeletedNTVariant2 DV2a;
+DeletedNTVariant2 DV2b(DV2a); // expected-error{{call to deleted constructor}}
+
+struct NoAccess {
+ NoAccess() = default;
+private:
+ NoAccess(const NoAccess&);
+
+ friend struct HasAccess;
+};
+
+struct HasNoAccess { // expected-note{{here}}
+ NoAccess NA;
+};
+HasNoAccess HNAa;
+HasNoAccess HNAb(HNAa); // expected-error{{call to deleted constructor}}
+
+struct HasAccess {
+ NoAccess NA;
+};
+
+HasAccess HAa;
+HasAccess HAb(HAa);
+
+struct NonConst {
+ NonConst(NonConst&);
+};
+struct Ambiguity {
+ Ambiguity(const Ambiguity&);
+ Ambiguity(volatile Ambiguity&);
+};
+
+struct IsAmbiguous { // expected-note{{here}}
+ NonConst NC;
+ Ambiguity A;
+ IsAmbiguous();
+};
+IsAmbiguous IAa;
+IsAmbiguous IAb(IAa); // expected-error{{call to deleted constructor}}
+
+struct Deleted { // expected-note{{here}}
+ IsAmbiguous IA;
+};
+Deleted Da;
+Deleted Db(Da); // expected-error{{call to deleted constructor}}
+
+struct NoAccessDtor {
+private:
+ ~NoAccessDtor();
+ friend struct HasAccessDtor;
+};
+
+struct HasNoAccessDtor { // expected-note{{here}}
+ NoAccessDtor NAD;
+ HasNoAccessDtor();
+ ~HasNoAccessDtor();
+};
+HasNoAccessDtor HNADa;
+HasNoAccessDtor HNADb(HNADa); // expected-error{{call to deleted constructor}}
+
+struct HasAccessDtor {
+ NoAccessDtor NAD;
+};
+HasAccessDtor HADa;
+HasAccessDtor HADb(HADa);
+
+struct RValue { // expected-note{{here}}
+ int && ri = 1;
+};
+RValue RVa;
+RValue RVb(RVa); // expected-error{{call to deleted constructor}}
diff --git a/test/CXX/special/class.copy/p11.0x.move.cpp b/test/CXX/special/class.copy/p11.0x.move.cpp
new file mode 100644
index 000000000000..402bc31d5eec
--- /dev/null
+++ b/test/CXX/special/class.copy/p11.0x.move.cpp
@@ -0,0 +1,85 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+struct NonTrivial {
+ NonTrivial(NonTrivial&&);
+};
+
+union DeletedNTVariant {
+ NonTrivial NT;
+ DeletedNTVariant(DeletedNTVariant&&);
+};
+DeletedNTVariant::DeletedNTVariant(DeletedNTVariant&&) = default; // expected-error{{would delete}}
+
+struct DeletedNTVariant2 {
+ union {
+ NonTrivial NT;
+ };
+ DeletedNTVariant2(DeletedNTVariant2&&);
+};
+DeletedNTVariant2::DeletedNTVariant2(DeletedNTVariant2&&) = default; // expected-error{{would delete}}
+
+struct NoAccess {
+ NoAccess() = default;
+private:
+ NoAccess(NoAccess&&);
+
+ friend struct HasAccess;
+};
+
+struct HasNoAccess {
+ NoAccess NA;
+ HasNoAccess(HasNoAccess&&);
+};
+HasNoAccess::HasNoAccess(HasNoAccess&&) = default; // expected-error{{would delete}}
+
+struct HasAccess {
+ NoAccess NA;
+ HasAccess(HasAccess&&);
+};
+HasAccess::HasAccess(HasAccess&&) = default;
+
+struct NoAccessDtor {
+ NoAccessDtor(NoAccessDtor&&);
+private:
+ ~NoAccessDtor();
+ friend struct HasAccessDtor;
+};
+
+struct HasNoAccessDtor {
+ NoAccessDtor NAD;
+ HasNoAccessDtor(HasNoAccessDtor&&);
+};
+HasNoAccessDtor::HasNoAccessDtor(HasNoAccessDtor&&) = default; // expected-error{{would delete}}
+
+struct HasAccessDtor {
+ NoAccessDtor NAD;
+ HasAccessDtor(HasAccessDtor&&);
+};
+HasAccessDtor::HasAccessDtor(HasAccessDtor&&) = default;
+
+struct RValue {
+ int &&ri = 1;
+ RValue(RValue&&);
+};
+RValue::RValue(RValue&&) = default;
+
+struct CopyOnly {
+ CopyOnly(const CopyOnly&);
+};
+
+struct NonMove {
+ CopyOnly CO;
+ NonMove(NonMove&&);
+};
+NonMove::NonMove(NonMove&&) = default; // expected-error{{would delete}}
+
+struct Moveable {
+ Moveable();
+ Moveable(Moveable&&);
+};
+
+struct HasMove {
+ Moveable M;
+ HasMove(HasMove&&);
+};
+HasMove::HasMove(HasMove&&) = default;
diff --git a/test/CXX/special/class.copy/p15-0x.cpp b/test/CXX/special/class.copy/p15-0x.cpp
new file mode 100644
index 000000000000..32b2714fd702
--- /dev/null
+++ b/test/CXX/special/class.copy/p15-0x.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+namespace PR10622 {
+ struct foo {
+ const int first;
+ foo(const foo&) = default;
+ };
+ void find_or_insert(const foo& __obj) {
+ foo x(__obj);
+ }
+
+ struct bar : foo {
+ bar(const bar&) = default;
+ };
+ void test_bar(const bar &obj) {
+ bar obj2(obj);
+ }
+}
diff --git a/test/CXX/special/class.copy/p33-0x.cpp b/test/CXX/special/class.copy/p33-0x.cpp
index b196865c8225..b66e19ab4c4f 100644
--- a/test/CXX/special/class.copy/p33-0x.cpp
+++ b/test/CXX/special/class.copy/p33-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++11 -fsyntax-only -verify %s
class X {
X(const X&);
diff --git a/test/CXX/special/class.ctor/p4-0x.cpp b/test/CXX/special/class.ctor/p4-0x.cpp
index e3508e2e8c47..509beb490302 100644
--- a/test/CXX/special/class.ctor/p4-0x.cpp
+++ b/test/CXX/special/class.ctor/p4-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// A constructor shall not be declared with a ref-qualifier.
struct X {
diff --git a/test/CXX/special/class.ctor/p5-0x.cpp b/test/CXX/special/class.ctor/p5-0x.cpp
index 2123d1662358..de2dea5be16b 100644
--- a/test/CXX/special/class.ctor/p5-0x.cpp
+++ b/test/CXX/special/class.ctor/p5-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
struct DefaultedDefCtor1 {};
struct DefaultedDefCtor2 { DefaultedDefCtor2() = default; };
@@ -23,10 +23,6 @@ int n;
// default constructor,
union Deleted1a { UserProvidedDefCtor u; }; // expected-note {{deleted here}}
Deleted1a d1a; // expected-error {{deleted constructor}}
-// FIXME: treating this as having a deleted default constructor is probably a
-// bug in the standard.
-union Deleted1b { UserProvidedDefCtor u = UserProvidedDefCtor(); }; // expected-note {{deleted here}}
-Deleted1b d1b; // expected-error {{deleted constructor}}
union NotDeleted1a { DefaultedDefCtor1 nu; };
NotDeleted1a nd1a;
// FIXME: clang implements the pre-FDIS rule, under which DefaultedDefCtor2's
diff --git a/test/CXX/special/class.dtor/p2-0x.cpp b/test/CXX/special/class.dtor/p2-0x.cpp
index 53a2e033efc1..c7b1b586fbcb 100644
--- a/test/CXX/special/class.dtor/p2-0x.cpp
+++ b/test/CXX/special/class.dtor/p2-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// A destructor shall not be declared with a ref-qualifier.
struct X {
diff --git a/test/CXX/special/class.dtor/p3-0x.cpp b/test/CXX/special/class.dtor/p3-0x.cpp
index 6cdd167983bc..44bf5aa01978 100644
--- a/test/CXX/special/class.dtor/p3-0x.cpp
+++ b/test/CXX/special/class.dtor/p3-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -emit-llvm -o - %s | FileCheck %s
struct A {
~A();
diff --git a/test/CXX/special/class.inhctor/elsewhere.cpp b/test/CXX/special/class.inhctor/elsewhere.cpp
index 82944d65dfd1..60cfff80889e 100644
--- a/test/CXX/special/class.inhctor/elsewhere.cpp
+++ b/test/CXX/special/class.inhctor/elsewhere.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// Tests related to constructor inheriting, but not specified in [class.inhctor]
diff --git a/test/CXX/special/class.inhctor/p3.cpp b/test/CXX/special/class.inhctor/p3.cpp
index 021f701ab495..989c17c8b462 100644
--- a/test/CXX/special/class.inhctor/p3.cpp
+++ b/test/CXX/special/class.inhctor/p3.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
struct B1 {
B1(int);
@@ -14,7 +14,7 @@ D1 fd1() { return 1; }
struct B2 {
explicit B2(int, int = 0, int = 0);
};
-struct D2 : B2 { // expected-note {{candidate constructor}}
+struct D2 : B2 { // expected-note 2 {{candidate constructor}}
using B2::B2;
};
D2 d2a(1), d2b(1, 1), d2c(1, 1, 1);
@@ -24,7 +24,7 @@ D2 fd2() { return 1; } // expected-error {{no viable conversion}}
struct B3 {
B3(void*); // expected-note {{inherited from here}}
};
-struct D3 : B3 { // expected-note {{candidate constructor}}
+struct D3 : B3 { // expected-note 2 {{candidate constructor}}
using B3::B3; // expected-note {{candidate constructor (inherited)}}
};
D3 fd3() { return 1; } // expected-error {{no viable conversion}}
diff --git a/test/CXX/special/class.inhctor/p7.cpp b/test/CXX/special/class.inhctor/p7.cpp
index 3ad761f08baa..736754d8a3e3 100644
--- a/test/CXX/special/class.inhctor/p7.cpp
+++ b/test/CXX/special/class.inhctor/p7.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// Straight from the standard
struct B1 {
diff --git a/test/CXX/special/class.init/class.base.init/p8-0x.cpp b/test/CXX/special/class.init/class.base.init/p8-0x.cpp
index 8512a9f7bb3a..3e26e4992d0d 100644
--- a/test/CXX/special/class.init/class.base.init/p8-0x.cpp
+++ b/test/CXX/special/class.init/class.base.init/p8-0x.cpp
@@ -1,15 +1,19 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
int n;
struct S {
int &a; // expected-note 2{{here}}
int &b = n;
+ union {
+ const int k = 42;
+ };
+
S() {} // expected-error {{constructor for 'S' must explicitly initialize the reference member 'a'}}
S(int) : a(n) {} // ok
S(char) : b(n) {} // expected-error {{constructor for 'S' must explicitly initialize the reference member 'a'}}
S(double) : a(n), b(n) {} // ok
-};
+} s(0);
union U {
int a = 0;
@@ -21,3 +25,35 @@ union U {
U(char) : b('y') {} // desired-error {{at most one member of a union may be initialized}}
U(double) : a(1), b('y') {} // desired-error {{at most one member of a union may be initialized}}
};
+
+// PR10954: variant members do not acquire an implicit initializer.
+namespace VariantMembers {
+ struct NoDefaultCtor {
+ NoDefaultCtor(int);
+ };
+ union V {
+ NoDefaultCtor ndc;
+ int n;
+
+ V() {}
+ V(int n) : n(n) {}
+ V(int n, bool) : ndc(n) {}
+ };
+ struct K {
+ union {
+ NoDefaultCtor ndc;
+ int n;
+ };
+ K() {}
+ K(int n) : n(n) {}
+ K(int n, bool) : ndc(n) {}
+ };
+ struct Nested {
+ Nested() {}
+ union {
+ struct {
+ NoDefaultCtor ndc;
+ };
+ };
+ };
+}
diff --git a/test/CXX/special/class.init/class.base.init/p9-0x.cpp b/test/CXX/special/class.init/class.base.init/p9-0x.cpp
index 039b1c271a3d..ca5e8072d82f 100644
--- a/test/CXX/special/class.init/class.base.init/p9-0x.cpp
+++ b/test/CXX/special/class.init/class.base.init/p9-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -std=c++0x %s -O1 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -std=c++11 %s -O1 -emit-llvm -o - | FileCheck %s
struct S {
int n = 10;
diff --git a/test/CXX/special/class.temporary/p1.cpp b/test/CXX/special/class.temporary/p1.cpp
new file mode 100644
index 000000000000..384b1f89fda8
--- /dev/null
+++ b/test/CXX/special/class.temporary/p1.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+namespace test0 {
+ struct A {
+ A() = default;
+ int x;
+ int y;
+
+ A(const A&) = delete; // expected-note {{function has been explicitly marked deleted here}}
+ };
+
+ void foo(...);
+
+ void test() {
+ A a;
+ foo(a); // expected-error {{call to deleted constructor of 'test0::A'}}
+ }
+}
+
+namespace test1 {
+ struct A {
+ A() = default;
+ int x;
+ int y;
+
+ private:
+ A(const A&) = default; // expected-note {{declared private here}}
+ };
+
+ void foo(...);
+
+ void test() {
+ A a;
+ // FIXME: this error about variadics is bogus
+ foo(a); // expected-error {{calling a private constructor of class 'test1::A'}} expected-error {{cannot pass object of non-trivial type 'test1::A' through variadic function}}
+ }
+}
+
+// Don't enforce this in an unevaluated context.
+namespace test2 {
+ struct A {
+ A(const A&) = delete; // expected-note {{marked deleted here}}
+ };
+
+ typedef char one[1];
+ typedef char two[2];
+
+ one &meta(bool);
+ two &meta(...);
+
+ void a(A &a) {
+ char check[sizeof(meta(a)) == 2 ? 1 : -1];
+ }
+
+ void b(A &a) {
+ meta(a); // expected-error {{call to deleted constructor}}
+ }
+}
diff --git a/test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp b/test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp
index 40b4c23841c8..574cb40c4670 100644
--- a/test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp
+++ b/test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// PR10034
struct X {};
diff --git a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
index 0c92f62582cf..b157fd4b0f92 100644
--- a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
+++ b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
namespace std {
template<typename T>
@@ -21,7 +21,7 @@ namespace std {
using namespace inner;
}
-struct A { // expected-note {{candidate constructor}}
+struct A { // expected-note 2 {{candidate constructor}}
A();
int *begin(); // expected-note 3{{selected 'begin' function with iterator type 'int *'}} expected-note {{'begin' declared here}}
int *end();
@@ -100,8 +100,7 @@ void g() {
for (extern int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'extern'}}
for (static int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'static'}}
for (register int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'register'}}
- // FIXME: when clang supports constexpr, this should be rejected.
- for (constexpr int a : A()) {} // desired-error {{loop variable 'a' may not be declared 'constexpr'}}
+ for (constexpr int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'constexpr'}}
struct NoBeginADL {
null_t alt_end();
diff --git a/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp b/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
index 794a0502582b..1c13bffa212f 100644
--- a/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
+++ b/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
template <class T> struct eval; // expected-note 3{{template is declared here}}
diff --git a/test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp b/test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp
index 6f6286f71078..b03ed46e92f0 100644
--- a/test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp
+++ b/test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
// C++03 imposed restrictions in this paragraph that were lifted with 0x, so we
// just test that the example given now parses cleanly.
diff --git a/test/CXX/temp/temp.decls/p3.cpp b/test/CXX/temp/temp.decls/p3.cpp
index 54800e4061ee..41811ff16531 100644
--- a/test/CXX/temp/temp.decls/p3.cpp
+++ b/test/CXX/temp/temp.decls/p3.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
template<typename T> using A = int;
template<typename T> using A<T*> = char; // expected-error {{partial specialization of alias templates is not permitted}}
diff --git a/test/CXX/temp/temp.decls/temp.alias/p1.cpp b/test/CXX/temp/temp.decls/temp.alias/p1.cpp
index 80079b33a53b..966e3c10e5de 100644
--- a/test/CXX/temp/temp.decls/temp.alias/p1.cpp
+++ b/test/CXX/temp/temp.decls/temp.alias/p1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
template<typename T> using U = T;
diff --git a/test/CXX/temp/temp.decls/temp.alias/p2.cpp b/test/CXX/temp/temp.decls/temp.alias/p2.cpp
index e145727a8dd7..a5b39fe5c51f 100644
--- a/test/CXX/temp/temp.decls/temp.alias/p2.cpp
+++ b/test/CXX/temp/temp.decls/temp.alias/p2.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
template<typename T> using U = T;
diff --git a/test/CXX/temp/temp.decls/temp.alias/p3.cpp b/test/CXX/temp/temp.decls/temp.alias/p3.cpp
index 2e9e55cdcb6b..afd9b4b0de30 100644
--- a/test/CXX/temp/temp.decls/temp.alias/p3.cpp
+++ b/test/CXX/temp/temp.decls/temp.alias/p3.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// The example given in the standard (this is rejected for other reasons anyway).
template<class T> struct A;
diff --git a/test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp b/test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp
index 14152cf339a8..aa1e2d443fdd 100644
--- a/test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp
+++ b/test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
template<int ...Values> struct X1;
diff --git a/test/CXX/temp/temp.decls/temp.class.spec/p9-0x.cpp b/test/CXX/temp/temp.decls/temp.class.spec/p9-0x.cpp
index d8e07b83e1be..b754368600aa 100644
--- a/test/CXX/temp/temp.decls/temp.class.spec/p9-0x.cpp
+++ b/test/CXX/temp/temp.decls/temp.class.spec/p9-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// -- The argument list of the specialization shall not be identical
// to the implicit argument list of the primary template.
diff --git a/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3-0x.cpp b/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3-0x.cpp
index 11ec28918e42..63909fb7cdbd 100644
--- a/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3-0x.cpp
+++ b/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// Core DR 532.
namespace PR8130 {
diff --git a/test/CXX/temp/temp.decls/temp.friend/p1.cpp b/test/CXX/temp/temp.decls/temp.friend/p1.cpp
index 578de2952d94..63f569be0861 100644
--- a/test/CXX/temp/temp.decls/temp.friend/p1.cpp
+++ b/test/CXX/temp/temp.decls/temp.friend/p1.cpp
@@ -332,3 +332,27 @@ namespace test15 {
template class B<int>; // expected-note {{in instantiation}}
}
+
+namespace PR10913 {
+ template<class T> class X;
+
+ template<class T> void f(X<T> *x) {
+ x->member = 0;
+ }
+
+ template<class U, class T> void f2(X<T> *x) {
+ x->member = 0; // expected-error{{'member' is a protected member of 'PR10913::X<int>'}}
+ }
+
+ template<class T> class X {
+ friend void f<T>(X<T> *x);
+ friend void f2<T>(X<int> *x);
+
+ protected:
+ int member; // expected-note{{declared protected here}}
+ };
+
+ template void f(X<int> *);
+ template void f2<int>(X<int> *);
+ template void f2<float>(X<int> *); // expected-note{{in instantiation of function template specialization 'PR10913::f2<float, int>' requested here}}
+}
diff --git a/test/CXX/temp/temp.decls/temp.mem/p5.cpp b/test/CXX/temp/temp.decls/temp.mem/p5.cpp
index a188f05d535e..8bcd773ee98b 100644
--- a/test/CXX/temp/temp.decls/temp.mem/p5.cpp
+++ b/test/CXX/temp/temp.decls/temp.mem/p5.cpp
@@ -63,7 +63,8 @@ struct X0 {
template<typename T> operator const T*() const {
T x = T();
- return x; // expected-error{{cannot initialize return object of type 'const char *' with an lvalue of type 'char'}}
+ return x; // expected-error{{cannot initialize return object of type 'const char *' with an lvalue of type 'char'}} \
+ // expected-error{{cannot initialize return object of type 'const int *' with an lvalue of type 'int'}}
}
};
@@ -72,7 +73,7 @@ template X0::operator const int*(); // expected-note{{'X0::operator const int *<
template X0::operator float*() const; // expected-error{{explicit instantiation of undefined function template}}
void test_X0(X0 x0, const X0 &x0c) {
- x0.operator const int*();
+ x0.operator const int*(); // expected-note{{in instantiation of function template specialization}}
x0.operator float *();
x0c.operator const char*();
}
diff --git a/test/CXX/temp/temp.decls/temp.variadic/deduction.cpp b/test/CXX/temp/temp.decls/temp.variadic/deduction.cpp
index 383e268054b6..fec8060955e3 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/deduction.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/deduction.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
namespace DeductionForInstantiation {
template<unsigned I, typename ...Types>
diff --git a/test/CXX/temp/temp.decls/temp.variadic/example-bind.cpp b/test/CXX/temp/temp.decls/temp.variadic/example-bind.cpp
index 83db1719b769..db28eea98a54 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/example-bind.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/example-bind.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// Example bind implementation from the variadic templates proposal,
// ISO C++ committee document number N2080.
diff --git a/test/CXX/temp/temp.decls/temp.variadic/example-function.cpp b/test/CXX/temp/temp.decls/temp.variadic/example-function.cpp
index b3d010c88d95..e15203abc615 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/example-function.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/example-function.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// Example function implementation from the variadic templates proposal,
// ISO C++ committee document number N2080.
diff --git a/test/CXX/temp/temp.decls/temp.variadic/example-tuple.cpp b/test/CXX/temp/temp.decls/temp.variadic/example-tuple.cpp
index 3b4bd7777d55..9de5fa84b48a 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/example-tuple.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/example-tuple.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// Example tuple implementation from the variadic templates proposal,
// ISO C++ committee document number N2080.
diff --git a/test/CXX/temp/temp.decls/temp.variadic/ext-blocks.cpp b/test/CXX/temp/temp.decls/temp.variadic/ext-blocks.cpp
index 7375f98ec9c3..6d9d8c50af68 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/ext-blocks.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/ext-blocks.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fblocks -fsyntax-only -verify %s
// Tests the use of blocks with variadic templates.
template<typename ...Args>
diff --git a/test/CXX/temp/temp.decls/temp.variadic/injected-class-name.cpp b/test/CXX/temp/temp.decls/temp.variadic/injected-class-name.cpp
index a76ef8067dfd..b5786acf82a2 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/injected-class-name.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/injected-class-name.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// Check for declaration matching with out-of-line declarations and
// variadic templates, which involves proper computation of the
diff --git a/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp b/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp
index d80182c1b657..73cbd0749cbd 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// This is a collection of various template metafunctions involving
// variadic templates, which are meant to exercise common use cases.
diff --git a/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp b/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
index cda9ac8b045c..21aa24fb522d 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
template<typename T, T ...Values> struct value_tuple {};
template<typename...> struct tuple { };
@@ -234,3 +234,18 @@ namespace ExpandingFunctionParameters {
x1.f(17, 3.14159);
}
}
+
+namespace PR10230 {
+ template<typename>
+ struct s
+ {
+ template<typename... Args>
+ auto f() -> int(&)[sizeof...(Args)];
+ };
+
+ void main()
+ {
+ int (&ir1)[1] = s<int>().f<int>();
+ int (&ir3)[3] = s<int>().f<int, float, double>();
+ }
+}
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p1.cpp b/test/CXX/temp/temp.decls/temp.variadic/p1.cpp
index 02f4c59b760b..daff9d189690 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/p1.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/p1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
template<class ...Types> struct Tuple;
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p2.cpp b/test/CXX/temp/temp.decls/temp.variadic/p2.cpp
index 100ae2c52f9a..ce19582c2282 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/p2.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/p2.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
template<class ... Types> void f(Types ... args);
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p4.cpp b/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
index 71839727e0d1..05e492167cbe 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -fexceptions -fcxx-exceptions -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fexceptions -fcxx-exceptions -verify %s
template<typename... Types> struct tuple;
template<int I> struct int_c;
@@ -52,6 +52,7 @@ struct HasMixins : public Mixins... {
};
struct A { }; // expected-note{{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const A' for 1st argument}} \
+// expected-note{{candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to 'A' for 1st argument}} \
// expected-note{{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}}
struct B { };
struct C { };
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
index 25338e3bae67..0f409e709e98 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++0x -fblocks -fms-extensions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++11 -fblocks -fms-extensions -fsyntax-only -verify %s
template<typename T, typename U> struct pair;
template<typename ...> struct tuple;
diff --git a/test/CXX/temp/temp.decls/temp.variadic/parameter-matching.cpp b/test/CXX/temp/temp.decls/temp.variadic/parameter-matching.cpp
index 989ff9f6d9f5..79340c3741a8 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/parameter-matching.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/parameter-matching.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// Check for template type parameter pack (mis-)matches with template
// type parameters.
diff --git a/test/CXX/temp/temp.decls/temp.variadic/partial-ordering.cpp b/test/CXX/temp/temp.decls/temp.variadic/partial-ordering.cpp
index 372317838e74..71bd6aa8eb52 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/partial-ordering.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/partial-ordering.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// Various tests related to partial ordering of variadic templates.
template<typename ...Types> struct tuple;
diff --git a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-0x.cpp
index 46d70b671f6e..4d29b740d803 100644
--- a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
namespace ParameterPacksWithFunctions {
template<typename ...> struct count;
diff --git a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp
index 1140aaee6c17..de3b44f1b513 100644
--- a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp
@@ -29,8 +29,8 @@ struct is_same<T, T> {
int typeof0[is_same<__typeof__(f<int>), void (int)>::value? 1 : -1];
int typeof1[is_same<__typeof__(&f<int>), void (*)(int)>::value? 1 : -1];
-template <typename T> void g(T); // expected-note{{candidate function}}
-template <typename T> void g(T, T); // expected-note{{candidate function}}
+template <typename T> void g(T); // expected-note{{possible target for call}}
+template <typename T> void g(T, T); // expected-note{{possible target for call}}
int typeof2[is_same<__typeof__(g<float>), void (int)>::value? 1 : -1]; // \
- // expected-error{{cannot resolve overloaded function 'g' from context}}
+ // expected-error{{reference to overloaded function could not be resolved; did you mean to call it?}}
diff --git a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp
index b38cc2760937..81addfe4bdcd 100644
--- a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// Metafunction to extract the Nth type from a set of types.
template<unsigned N, typename ...Types> struct get_nth_type;
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/cwg1170.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/cwg1170.cpp
index d3af0d4b9132..c14b063ab746 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/cwg1170.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/cwg1170.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
#if !__has_feature(cxx_access_control_sfinae)
# error No support for access control as part of SFINAE?
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp
index 8933b63ee6df..8b192fa547b2 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
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// Metafunction to extract the Nth type from a set of types.
template<unsigned N, typename ...Types> struct get_nth_type;
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
index f18a74a1e4ef..e470dd016644 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// If P is an rvalue reference to a cv-unqualified template parameter
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
new file mode 100644
index 000000000000..9236efce2b83
--- /dev/null
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace PR8598 {
+ template<class T> struct identity { typedef T type; };
+
+ template<class T, class C>
+ void f(T C::*, typename identity<T>::type*){}
+
+ struct X { void f() {}; };
+
+ void g() { (f)(&X::f, 0); }
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p12.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p12.cpp
index 116810082d9f..b96530056b2c 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p12.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p12.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// Note: Partial ordering of function templates containing template
// parameter packs is independent of the number of deduced arguments
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p9-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p9-0x.cpp
index 46ea4db779ce..f204caf57abd 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p9-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p9-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
template<typename T> int &f0(T&);
template<typename T> float &f0(T&&);
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p10-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p10-0x.cpp
index 9d342c8f8ed6..8183061a8ab4 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p10-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p10-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
template<typename T> void f(T&&);
template<> void f(int&) { }
void (*fp)(int&) = &f;
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp
index 198f11fe5298..5b031c24ed71 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// If type deduction cannot be done for any P/A pair, or if for any
// pair the deduction leads to more than one possible set of deduced
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p21.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p21.cpp
index 247b98113ae5..4e98a6d15e1a 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p21.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p21.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// Note: Template argument deduction involving parameter packs
// (14.5.3) can deduce zero or more arguments for each parameter pack.
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p22.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p22.cpp
index 4326a691cb2e..fcc6cf7ec732 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p22.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p22.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// If the original function parameter associated with A is a function
// parameter pack and the function parameter associated with P is not
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p5-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p5-0x.cpp
index cf68a01a3593..c819d973a941 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p5-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p5-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// FIXME: More bullets to go!
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp
index a9173fd6be86..a6b1172afccc 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// Deductions specific to C++0x.
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 508722437c39..7774b5c77fa8 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
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
template<typename ...Types> struct tuple;
template<unsigned> struct unsigned_c;
diff --git a/test/CXX/temp/temp.param/p10-0x.cpp b/test/CXX/temp/temp.param/p10-0x.cpp
index bc7e616fb13d..37bb284a36eb 100644
--- a/test/CXX/temp/temp.param/p10-0x.cpp
+++ b/test/CXX/temp/temp.param/p10-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<typename> struct Y1;
template<typename, int> struct Y2;
diff --git a/test/CXX/temp/temp.param/p11-0x.cpp b/test/CXX/temp/temp.param/p11-0x.cpp
index 10a44380c8d1..1971aa10c2c7 100644
--- a/test/CXX/temp/temp.param/p11-0x.cpp
+++ b/test/CXX/temp/temp.param/p11-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// If a template-parameter of a class template or alias template has a default
// template-argument, each subsequent template-parameter shall either have a
diff --git a/test/CXX/temp/temp.param/p15-cxx0x.cpp b/test/CXX/temp/temp.param/p15-cxx0x.cpp
index f4be5b960b6c..5fc57a43f541 100644
--- a/test/CXX/temp/temp.param/p15-cxx0x.cpp
+++ b/test/CXX/temp/temp.param/p15-cxx0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
template<typename T> struct X;
template<int I> struct Y;
diff --git a/test/CXX/temp/temp.param/p15.cpp b/test/CXX/temp/temp.param/p15.cpp
index 13087791a3db..ee572e986b93 100644
--- a/test/CXX/temp/temp.param/p15.cpp
+++ b/test/CXX/temp/temp.param/p15.cpp
@@ -9,4 +9,4 @@ X<X<X<X<int>> // expected-error{{a space is required between consecutive right a
>> *x3; // expected-error{{a space is required between consecutive right angle brackets (use '> >')}}
Y<(1 >> 2)> *y1;
-Y<1 >> 2> *y2; // expected-warning{{use of right-shift operator ('>>') in template argument will require parentheses in C++0x}}
+Y<1 >> 2> *y2; // expected-warning{{use of right-shift operator ('>>') in template argument will require parentheses in C++11}}
diff --git a/test/CXX/temp/temp.param/p9-0x.cpp b/test/CXX/temp/temp.param/p9-0x.cpp
index 1dc6640fe266..29a7549a8f1a 100644
--- a/test/CXX/temp/temp.param/p9-0x.cpp
+++ b/test/CXX/temp/temp.param/p9-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// A default template-argument may be specified for any kind of
// template-parameter that is not a template parameter pack.
diff --git a/test/CXX/temp/temp.param/p9.cpp b/test/CXX/temp/temp.param/p9.cpp
index 62af522cd2c9..b2318c275e44 100644
--- a/test/CXX/temp/temp.param/p9.cpp
+++ b/test/CXX/temp/temp.param/p9.cpp
@@ -2,9 +2,9 @@
// A default template-argument shall not be specified in a function
// template declaration or a function template definition
-template<typename T = int> // expected-warning{{default template arguments for a function template are a C++0x extension}}
+template<typename T = int> // expected-warning{{default template arguments for a function template are a C++11 extension}}
void foo0(T);
-template<typename T = int> // expected-warning{{default template arguments for a function template are a C++0x extension}}
+template<typename T = int> // expected-warning{{default template arguments for a function template are a C++11 extension}}
void foo1(T) { }
// [...] nor in the template-parameter-list of the definition of a
diff --git a/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp b/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
index 1d1d350cf337..81b070f040ee 100644
--- a/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
+++ b/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// Examples from CWG1056.
namespace Example1 {
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 4a17ceca7cb6..acfbb46447de 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
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// This test creates cases where implicit instantiations of various entities
// would cause a diagnostic, but provides expliict specializations for those
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
index a4caceae4954..97e78fd791fa 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
@@ -1,10 +1,15 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
template<typename T>
struct X {
void f() {}
};
-template inline void X<int>::f(); // expected-error{{'inline'}}
+template inline void X<int>::f(); // expected-error{{explicit instantiation cannot be 'inline'}}
-// FIXME: test constexpr
+template<typename T>
+struct Y {
+ constexpr int f() { return 0; }
+};
+
+template constexpr int Y<int>::f(); // expected-error{{explicit instantiation cannot be 'constexpr'}}
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp b/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp
index fdb922abcf9b..1028830abe75 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -verify %s
+// RUN: %clang_cc1 -std=c++11 -verify %s
// If the name declared in the explicit instantiation is an
// unqualified name, the explicit instantiation shall appear in the
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p9-linkage.cpp b/test/CXX/temp/temp.spec/temp.explicit/p9-linkage.cpp
index 57b012f9a946..04e7df5741e2 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p9-linkage.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p9-linkage.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -O1 -emit-llvm -std=c++0x -o - %s | FileCheck %s
+// RUN: %clang_cc1 -O1 -emit-llvm -std=c++11 -o - %s | FileCheck %s
template<typename T>
struct X0 {
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p9.cpp b/test/CXX/temp/temp.spec/temp.explicit/p9.cpp
index ad973bb7c589..86490175f0c3 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p9.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p9.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
template<typename T>
struct X0 {
diff --git a/test/CXX/temp/temp.type/p1-0x.cpp b/test/CXX/temp/temp.type/p1-0x.cpp
index c22af22f9865..35d00c2fab20 100644
--- a/test/CXX/temp/temp.type/p1-0x.cpp
+++ b/test/CXX/temp/temp.type/p1-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
namespace Old {
template<template<class> class TT> struct X { };
diff --git a/test/CodeCompletion/truncation.c b/test/CodeCompletion/truncation.c
index 1b446b7d92ca..473e85847e56 100644
--- a/test/CodeCompletion/truncation.c
+++ b/test/CodeCompletion/truncation.c
@@ -1,18 +1,15 @@
#include "truncation.c.h"
-struct
-
/* foo */
+struct
+
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s.h:4:8 -o - %s | FileCheck -check-prefix=CC1 %s
// CHECK-CC1: X
// CHECK-CC1-NEXT: Y
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:3:8 -o - %s | FileCheck -check-prefix=CC2 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:8 -o - %s | FileCheck -check-prefix=CC2 %s
// CHECK-CC2: X
// CHECK-CC2: Xa
// CHECK-CC2: Y
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:3 -o - %s | FileCheck -check-prefix=CC3 %s
-// CHECK-CC3: X
-// CHECK-CC3: Xa
-// CHECK-CC3: Y
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:3:3 -o - %s
diff --git a/test/CodeGen/2002-01-23-LoadQISIReloadFailure.c b/test/CodeGen/2002-01-23-LoadQISIReloadFailure.c
new file mode 100644
index 000000000000..ec454c826835
--- /dev/null
+++ b/test/CodeGen/2002-01-23-LoadQISIReloadFailure.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+/* Regression test. Just compile .c -> .ll to test */
+int foo(void) {
+ unsigned char *pp;
+ unsigned w_cnt;
+
+ w_cnt += *pp;
+
+ return w_cnt;
+}
diff --git a/test/CodeGen/2002-01-24-ComplexSpaceInType.c b/test/CodeGen/2002-01-24-ComplexSpaceInType.c
new file mode 100644
index 000000000000..9af533dfa414
--- /dev/null
+++ b/test/CodeGen/2002-01-24-ComplexSpaceInType.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+// This caused generation of the following type name:
+// %Array = uninitialized global [10 x %complex int]
+//
+// which caused problems because of the space int the complex int type
+//
+
+struct { int X, Y; } Array[10];
+
+void foo() {}
diff --git a/test/CodeGen/2002-01-24-HandleCallInsnSEGV.c b/test/CodeGen/2002-01-24-HandleCallInsnSEGV.c
new file mode 100644
index 000000000000..739a841bbdff
--- /dev/null
+++ b/test/CodeGen/2002-01-24-HandleCallInsnSEGV.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+void *dlclose(void*);
+
+void ap_os_dso_unload(void *handle)
+{
+ dlclose(handle);
+ return; /* This return triggers the bug: Weird */
+}
diff --git a/test/CodeGen/2002-02-13-ConditionalInCall.c b/test/CodeGen/2002-02-13-ConditionalInCall.c
new file mode 100644
index 000000000000..d389371dd323
--- /dev/null
+++ b/test/CodeGen/2002-02-13-ConditionalInCall.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+/* Test problem where bad code was generated with a ?: statement was
+ in a function call argument */
+
+void foo(int, double, float);
+
+void bar(int x) {
+ foo(x, x ? 1.0 : 12.5, 1.0f);
+}
+
diff --git a/test/CodeGen/2002-02-13-ReloadProblem.c b/test/CodeGen/2002-02-13-ReloadProblem.c
new file mode 100644
index 000000000000..da7f5e4fe00c
--- /dev/null
+++ b/test/CodeGen/2002-02-13-ReloadProblem.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+/* This triggered a problem in reload, fixed by disabling most of the
+ * steps of compilation in GCC. Before this change, the code went through
+ * the entire backend of GCC, even though it was unnecessary for LLVM output
+ * now it is skipped entirely, and since reload doesn't run, it can't cause
+ * a problem.
+ */
+
+extern int tolower(int);
+
+const char *rangematch(const char *pattern, int test, int c) {
+
+ if ((c <= test) | (tolower(c) <= tolower((unsigned char)test)))
+ return 0;
+
+ return pattern;
+}
diff --git a/test/CodeGen/2002-02-13-TypeVarNameCollision.c b/test/CodeGen/2002-02-13-TypeVarNameCollision.c
new file mode 100644
index 000000000000..c76aef05109f
--- /dev/null
+++ b/test/CodeGen/2002-02-13-TypeVarNameCollision.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+/* This testcase causes a symbol table collision. Type names and variable
+ * names should be in distinct namespaces
+ */
+
+typedef struct foo {
+ int X, Y;
+} FOO;
+
+static FOO foo[100];
+
+int test() {
+ return foo[4].Y;
+}
+
diff --git a/test/CodeGen/2002-02-13-UnnamedLocal.c b/test/CodeGen/2002-02-13-UnnamedLocal.c
new file mode 100644
index 000000000000..58a9f5ab1c0b
--- /dev/null
+++ b/test/CodeGen/2002-02-13-UnnamedLocal.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+/* Testcase for a problem where GCC allocated xqic to a register,
+ * and did not have a VAR_DECL that explained the stack slot to LLVM.
+ * Now the LLVM code synthesizes a stack slot if one is presented that
+ * has not been previously recognized. This is where alloca's named
+ * 'local' come from now.
+ */
+
+typedef struct {
+ short x;
+} foostruct;
+
+int foo(foostruct ic);
+
+void test() {
+ foostruct xqic;
+ foo(xqic);
+}
+
+
diff --git a/test/CodeGen/2002-02-14-EntryNodePreds.c b/test/CodeGen/2002-02-14-EntryNodePreds.c
new file mode 100644
index 000000000000..60d1104f9667
--- /dev/null
+++ b/test/CodeGen/2002-02-14-EntryNodePreds.c
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+/* GCC Used to generate code that contained a branch to the entry node of
+ * the do_merge function. This is illegal LLVM code. To fix this, GCC now
+ * inserts an entry node regardless of whether or not it has to insert allocas.
+ */
+
+struct edge_rec
+{
+ struct VERTEX *v;
+ struct edge_rec *next;
+ int wasseen;
+ int more_data;
+};
+
+typedef struct edge_rec *QUAD_EDGE;
+
+typedef struct {
+ QUAD_EDGE left, right;
+} EDGE_PAIR;
+
+struct EDGE_STACK {
+ int ptr;
+ QUAD_EDGE *elts;
+ int stack_size;
+};
+
+int do_merge(QUAD_EDGE ldo, QUAD_EDGE rdo) {
+ int lvalid;
+ QUAD_EDGE basel,rcand;
+ while (1) {
+ if (!lvalid) {
+ return (int)basel->next;
+ }
+ }
+}
+
diff --git a/test/CodeGen/2002-02-16-RenamingTest.c b/test/CodeGen/2002-02-16-RenamingTest.c
new file mode 100644
index 000000000000..bb23e680f25a
--- /dev/null
+++ b/test/CodeGen/2002-02-16-RenamingTest.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+/* test that locals are renamed with . notation */
+
+void abc(void *);
+
+void Test5(double X) {
+ abc(&X);
+ {
+ int X;
+ abc(&X);
+ {
+ float X;
+ abc(&X);
+ }
+ }
+}
+
diff --git a/test/CodeGen/2002-02-17-ArgumentAddress.c b/test/CodeGen/2002-02-17-ArgumentAddress.c
new file mode 100644
index 000000000000..d1ad6a885ee1
--- /dev/null
+++ b/test/CodeGen/2002-02-17-ArgumentAddress.c
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+int test(int X) {
+ return X;
+}
+
+void abc(int *X);
+int def(int Y, int Z) {
+ abc(&Z);
+ return Y;
+}
+
+struct Test { short X, x; int Y, Z; };
+
+int Testing(struct Test *A) {
+ return A->X+A->Y;
+}
+
+int Test2(int X, struct Test A, int Y) {
+ return X+Y+A.X+A.Y;
+}
+int Test3(struct Test A, struct Test B) {
+ return A.X+A.Y+B.Y+B.Z;
+}
+
+struct Test Test4(struct Test A) {
+ return A;
+}
+
+int Test6() {
+ int B[200];
+ return B[4];
+}
+
+struct STest2 { int X; short Y[4]; double Z; };
+
+struct STest2 Test7(struct STest2 X) {
+ return X;
+}
diff --git a/test/CodeGen/2002-02-18-64bitConstant.c b/test/CodeGen/2002-02-18-64bitConstant.c
new file mode 100644
index 000000000000..95da72dc30a3
--- /dev/null
+++ b/test/CodeGen/2002-02-18-64bitConstant.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+/* GCC wasn't handling 64 bit constants right fixed */
+
+int printf(const char * restrict format, ...);
+
+int main() {
+ long long Var = 123455678902ll;
+ printf("%lld\n", Var);
+}
diff --git a/test/CodeGen/2002-02-18-StaticData.c b/test/CodeGen/2002-02-18-StaticData.c
new file mode 100644
index 000000000000..d0cf52477252
--- /dev/null
+++ b/test/CodeGen/2002-02-18-StaticData.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+double FOO = 17;
+double BAR = 12.0;
+float XX = 12.0f;
+
+static char *procnames[] = {
+ "EXIT"
+};
+
+void *Data[] = { &FOO, &BAR, &XX };
+
diff --git a/test/CodeGen/2002-03-11-LargeCharInString.c b/test/CodeGen/2002-03-11-LargeCharInString.c
new file mode 100644
index 000000000000..927087349bcb
--- /dev/null
+++ b/test/CodeGen/2002-03-11-LargeCharInString.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+int strcmp(const char *s1, const char *s2);
+
+int test(char *X) {
+ /* LLVM-GCC used to emit:
+ %.LC0 = internal global [3 x sbyte] c"\1F\FFFFFF8B\00"
+ */
+ return strcmp(X, "\037\213");
+}
diff --git a/test/CodeGen/2002-03-12-ArrayInitialization.c b/test/CodeGen/2002-03-12-ArrayInitialization.c
new file mode 100644
index 000000000000..f05b83861bab
--- /dev/null
+++ b/test/CodeGen/2002-03-12-ArrayInitialization.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+/* GCC would generate bad code if not enough initializers are
+ specified for an array.
+ */
+
+int a[10] = { 0, 2};
+
+char str[10] = "x";
+
+void *Arr[5] = { 0, 0 };
+
+float F[12] = { 1.23f, 34.7f };
+
+struct Test { int X; double Y; };
+
+struct Test Array[10] = { { 2, 12.0 }, { 3, 24.0 } };
+
+int B[4][4] = { { 1, 2, 3, 4}, { 5, 6, 7 }, { 8, 9 } };
diff --git a/test/CodeGen/2002-03-12-StructInitialize.c b/test/CodeGen/2002-03-12-StructInitialize.c
new file mode 100644
index 000000000000..1316fbbd0e4a
--- /dev/null
+++ b/test/CodeGen/2002-03-12-StructInitialize.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+typedef struct Connection_Type {
+ long to;
+ char type[10];
+ long length;
+} Connection;
+
+Connection link[3]
+= { {1, "link1", 10},
+ {2, "link2", 20},
+ {3, "link3", 30} };
+
diff --git a/test/CodeGen/2002-03-12-StructInitializer.c b/test/CodeGen/2002-03-12-StructInitializer.c
new file mode 100644
index 000000000000..a65675b13786
--- /dev/null
+++ b/test/CodeGen/2002-03-12-StructInitializer.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+/* GCC was not emitting string constants of the correct length when
+ * embedded into a structure field like this. It thought the strlength
+ * was -1.
+ */
+
+typedef struct Connection_Type {
+ long to;
+ char type[10];
+ long length;
+} Connection;
+
+Connection link[3]
+= { {1, "link1", 10},
+ {2, "link2", 20},
+ {3, "link3", 30} };
+
diff --git a/test/CodeGen/2002-03-14-BrokenPHINode.c b/test/CodeGen/2002-03-14-BrokenPHINode.c
new file mode 100644
index 000000000000..eb058598c505
--- /dev/null
+++ b/test/CodeGen/2002-03-14-BrokenPHINode.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+/* GCC was generating PHI nodes with an arity < #pred of the basic block the
+ * PHI node lived in. This was breaking LLVM because the number of entries
+ * in a PHI node must equal the number of predecessors for a basic block.
+ */
+
+int trys(char *s, int x)
+{
+ int asa;
+ double Val;
+ int LLS;
+ if (x) {
+ asa = LLS + asa;
+ } else {
+ }
+ return asa+(int)Val;
+}
+
diff --git a/test/CodeGen/2002-03-14-BrokenSSA.c b/test/CodeGen/2002-03-14-BrokenSSA.c
new file mode 100644
index 000000000000..65e5cfad815e
--- /dev/null
+++ b/test/CodeGen/2002-03-14-BrokenSSA.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+/* This code used to break GCC's SSA computation code. It would create
+ uses of B & C that are not dominated by their definitions. See:
+ http://gcc.gnu.org/ml/gcc/2002-03/msg00697.html
+ */
+int bar();
+int foo()
+{
+ int a,b,c;
+
+ a = b + c;
+ b = bar();
+ c = bar();
+ return a + b + c;
+}
+
diff --git a/test/CodeGen/2002-03-14-QuotesInStrConst.c b/test/CodeGen/2002-03-14-QuotesInStrConst.c
new file mode 100644
index 000000000000..de4bdd658078
--- /dev/null
+++ b/test/CodeGen/2002-03-14-QuotesInStrConst.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+/* GCC was not escaping quotes in string constants correctly, so this would
+ * get emitted:
+ * %.LC1 = internal global [32 x sbyte] c"*** Word "%s" on line %d is not\00"
+ */
+
+const char *Foo() {
+ return "*** Word \"%s\" on line %d is not";
+}
diff --git a/test/CodeGen/2002-04-07-SwitchStmt.c b/test/CodeGen/2002-04-07-SwitchStmt.c
new file mode 100644
index 000000000000..cf1ec79b08a5
--- /dev/null
+++ b/test/CodeGen/2002-04-07-SwitchStmt.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+int printf(const char *, ...);
+int foo();
+
+int main() {
+ while (foo()) {
+ switch (foo()) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ printf("3");
+ case 4: printf("4");
+ case 5:
+ case 6:
+ default:
+ break;
+ }
+ }
+ return 0;
+}
diff --git a/test/CodeGen/2002-04-08-LocalArray.c b/test/CodeGen/2002-04-08-LocalArray.c
new file mode 100644
index 000000000000..9b5ef7921456
--- /dev/null
+++ b/test/CodeGen/2002-04-08-LocalArray.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+/* GCC is not outputting the static array to the LLVM backend, so bad things
+ * happen. Note that if this is defined static, everything seems fine.
+ */
+double test(unsigned X) {
+ double student_t[30]={0.0 , 12.706 , 4.303 , 3.182 , 2.776 , 2.571 ,
+ 2.447 , 2.365 , 2.306 , 2.262 , 2.228 ,
+ 2.201 , 2.179 , 2.160 , 2.145 , 2.131 ,
+ 2.120 , 2.110 , 2.101 , 2.093 , 2.086 ,
+ 2.080 , 2.074 , 2.069 , 2.064 , 2.060 ,
+ 2.056 , 2.052 , 2.048 , 2.045 };
+ return student_t[X];
+}
diff --git a/test/CodeGen/2002-04-09-StructRetVal.c b/test/CodeGen/2002-04-09-StructRetVal.c
new file mode 100644
index 000000000000..f043ab721095
--- /dev/null
+++ b/test/CodeGen/2002-04-09-StructRetVal.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+struct S {
+ int i;
+ short s1, s2;
+};
+
+struct S func_returning_struct(void);
+
+void loop(void) {
+ func_returning_struct();
+}
diff --git a/test/CodeGen/2002-04-10-StructParameters.c b/test/CodeGen/2002-04-10-StructParameters.c
new file mode 100644
index 000000000000..72cebc64481f
--- /dev/null
+++ b/test/CodeGen/2002-04-10-StructParameters.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+typedef struct {
+ char p;
+ short q;
+ char r;
+ int X;
+ short Y, Z;
+ int Q;
+} foo;
+
+int test(foo X, float);
+int testE(char,short,char,int,int,float);
+void test3(foo *X) {
+ X->q = 1;
+}
+
+void test2(foo Y) {
+ testE(Y.p, Y.q, Y.r, Y.X, Y.Y, 0.1f);
+ test(Y, 0.1f);
+ test2(Y);
+ test3(&Y);
+}
+
diff --git a/test/CodeGen/2002-05-23-StaticValues.c b/test/CodeGen/2002-05-23-StaticValues.c
new file mode 100644
index 000000000000..b8c25b73c71f
--- /dev/null
+++ b/test/CodeGen/2002-05-23-StaticValues.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+/* Make sure the frontend is correctly marking static stuff as internal! */
+
+int X;
+static int Y = 12;
+
+static void foo(int Z) {
+ Y = Z;
+}
+
+void *test() {
+ foo(12);
+ return &Y;
+}
diff --git a/test/CodeGen/2002-05-23-TypeNameCollision.c b/test/CodeGen/2002-05-23-TypeNameCollision.c
new file mode 100644
index 000000000000..c15c952e7797
--- /dev/null
+++ b/test/CodeGen/2002-05-23-TypeNameCollision.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+/* Testcase for when struct tag conflicts with typedef name... grr */
+
+typedef struct foo {
+ struct foo *X;
+ int Y;
+} * foo;
+
+foo F1;
+struct foo *F2;
+
+enum bar { test1, test2 };
+
+typedef float bar;
+
+enum bar B1;
+bar B2;
+
diff --git a/test/CodeGen/2002-05-24-Alloca.c b/test/CodeGen/2002-05-24-Alloca.c
new file mode 100644
index 000000000000..30ba8bb8e218
--- /dev/null
+++ b/test/CodeGen/2002-05-24-Alloca.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+typedef __SIZE_TYPE__ size_t;
+void *alloca(size_t size);
+char *strcpy(char *restrict s1, const char *restrict s2);
+int puts(const char *s);
+int main(int argc, char **argv) {
+ char *C = (char*)alloca(argc);
+ strcpy(C, argv[0]);
+ puts(C);
+}
diff --git a/test/CodeGen/2002-06-25-FWriteInterfaceFailure.c b/test/CodeGen/2002-06-25-FWriteInterfaceFailure.c
new file mode 100644
index 000000000000..24c67d1520a1
--- /dev/null
+++ b/test/CodeGen/2002-06-25-FWriteInterfaceFailure.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+typedef struct _IO_FILE FILE;
+extern FILE *stderr;
+int fprintf(FILE * restrict stream, const char * restrict format, ...);
+
+void test() {
+ fprintf(stderr, "testing\n");
+}
diff --git a/test/CodeGen/2002-07-14-MiscListTests.c b/test/CodeGen/2002-07-14-MiscListTests.c
new file mode 100644
index 000000000000..901701a17654
--- /dev/null
+++ b/test/CodeGen/2002-07-14-MiscListTests.c
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+// Test list stuff
+
+void *malloc(unsigned);
+
+// Test opaque structure support. the list type is defined later
+struct list;
+
+struct list *PassThroughList(struct list *L) {
+ return L;
+}
+
+
+// Recursive data structure tests...
+
+typedef struct list {
+ int Data;
+ struct list *Next;
+} list;
+
+list *Data;
+
+void foo() {
+ static int Foo = 0; // Test static local variable
+ Foo += 1; // Increment static variable
+
+ Data = (list*)malloc(12); // This is not a proper list allocation
+}
+
+extern list ListNode1;
+list ListNode3 = { 4, 0 };
+list ListNode2 = { 3, &ListNode3 };
+list ListNode0 = { 1, &ListNode1 };
+list ListNode1 = { 2, &ListNode2 };
+
+
+list ListArray[10];
+
+// Iterative insert fn
+void InsertIntoListTail(list **L, int Data) {
+ while (*L)
+ L = &(*L)->Next;
+ *L = (list*)malloc(sizeof(list));
+ (*L)->Data = Data;
+ (*L)->Next = 0;
+}
+
+// Recursive list search fn
+list *FindData(list *L, int Data) {
+ if (L == 0) return 0;
+ if (L->Data == Data) return L;
+ return FindData(L->Next, Data);
+}
+
+void foundIt(void);
+
+// Driver fn...
+void DoListStuff() {
+ list *MyList = 0;
+ InsertIntoListTail(&MyList, 100);
+ InsertIntoListTail(&MyList, 12);
+ InsertIntoListTail(&MyList, 42);
+ InsertIntoListTail(&MyList, 1123);
+ InsertIntoListTail(&MyList, 1213);
+
+ if (FindData(MyList, 75)) foundIt();
+ if (FindData(MyList, 42)) foundIt();
+ if (FindData(MyList, 700)) foundIt();
+}
+
diff --git a/test/CodeGen/2002-07-14-MiscTests.c b/test/CodeGen/2002-07-14-MiscTests.c
new file mode 100644
index 000000000000..2a651248b55c
--- /dev/null
+++ b/test/CodeGen/2002-07-14-MiscTests.c
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -w -emit-llvm %s -o /dev/null
+
+/* These are random tests that I used when working on the GCC frontend
+ originally. */
+
+// test floating point comparison!
+int floatcomptest(double *X, double *Y, float *x, float *y) {
+ return *X < *Y || *x < *y;
+}
+
+extern void *malloc(unsigned);
+
+// Exposed a bug
+void *memset_impl(void *dstpp, int c, unsigned len) {
+ long long int dstp = (long long int) dstpp;
+
+ while (dstp % 4 != 0)
+ {
+ ((unsigned char *) dstp)[0] = c;
+ dstp += 1;
+ len -= 1;
+ }
+ return dstpp;
+}
+
+// TEST problem with signed/unsigned versions of the same constants being shared
+// incorrectly!
+//
+static char *temp;
+static int remaining;
+static char *localmalloc(int size) {
+ char *blah;
+
+ if (size>remaining)
+ {
+ temp = (char *) malloc(32768);
+ remaining = 32768;
+ return temp;
+ }
+ return 0;
+}
+
+typedef struct { double X; double Y; int Z; } PBVTest;
+
+PBVTest testRetStruct(float X, double Y, int Z) {
+ PBVTest T = { X, Y, Z };
+ return T;
+}
+PBVTest testRetStruct2(void); // external func no inlining
+
+
+double CallRetStruct(float X, double Y, int Z) {
+ PBVTest T = testRetStruct2();
+ return T.X+X+Y+Z;
+}
+
+
diff --git a/test/CodeGen/2002-07-14-MiscTests2.c b/test/CodeGen/2002-07-14-MiscTests2.c
new file mode 100644
index 000000000000..ad1301766d3a
--- /dev/null
+++ b/test/CodeGen/2002-07-14-MiscTests2.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+// Test ?: in function calls
+extern fp(int, char*);
+char *Ext;
+void
+__bb_exit_func (void)
+{
+ fp (12, Ext ? Ext : "<none>");
+}
+
+
diff --git a/test/CodeGen/2002-07-14-MiscTests3.c b/test/CodeGen/2002-07-14-MiscTests3.c
new file mode 100644
index 000000000000..f7ded4e720de
--- /dev/null
+++ b/test/CodeGen/2002-07-14-MiscTests3.c
@@ -0,0 +1,182 @@
+// RUN: %clang_cc1 -w -emit-llvm %s -o /dev/null
+
+void *malloc(unsigned);
+int puts(const char *s);
+
+struct FunStructTest {
+ int Test1;
+ char *Pointer;
+ int Array[12];
+};
+
+struct SubStruct {
+ short X, Y;
+};
+
+struct Quad {
+ int w;
+ struct SubStruct SS;
+ struct SubStruct *SSP;
+ char c;
+ int y;
+};
+
+struct Quad GlobalQuad = { 4, {1, 2}, 0, 3, 156 };
+
+typedef int (*FuncPtr)(int);
+
+unsigned PtrFunc(int (*Func)(int), int X) {
+ return Func(X);
+}
+
+char PtrFunc2(FuncPtr FuncTab[30], int Num) {
+ return FuncTab[Num]('b');
+}
+
+extern char SmallArgs2(char w, char x, long long Zrrk, char y, char z);
+extern int SomeFunc(void);
+char SmallArgs(char w, char x, char y, char z) {
+ SomeFunc();
+ return SmallArgs2(w-1, x+1, y, z, w);
+}
+
+static int F0(struct Quad Q, int i) { /* Pass Q by value */
+ struct Quad R;
+ if (i) R.SS = Q.SS;
+ Q.SSP = &R.SS;
+ Q.w = Q.y = Q.c = 1;
+ return Q.SS.Y + i + R.y - Q.c;
+}
+
+int F1(struct Quad *Q, int i) { /* Pass Q by address */
+ struct Quad R;
+#if 0
+ if (i) R.SS = Q->SS;
+#else
+ if (i) R = *Q;
+#endif
+ Q->w = Q->y = Q->c = 1;
+ return Q->SS.Y+i+R.y-Q->c;
+}
+
+
+int BadFunc(float Val) {
+ int Result;
+ if (Val > 12.345) Result = 4;
+ return Result; /* Test use of undefined value */
+}
+
+int RealFunc(void) {
+ return SomeUndefinedFunction(1, 4, 5);
+}
+
+extern int EF1(int *, char *, int *);
+
+int Func(int Param, long long Param2) {
+ int Result = Param;
+
+ {{{{
+ char c; int X;
+ EF1(&Result, &c, &X);
+ }}}
+
+ { // c & X are duplicate names!
+ char c; int X;
+ EF1(&Result, &c, &X);
+ }
+
+ }
+ return Result;
+}
+
+
+short FunFunc(long long x, char z) {
+ return x+z;
+}
+
+unsigned castTest(int X) { return X; }
+
+double TestAdd(double X, float Y) {
+ return X+Y+.5;
+}
+
+int func(int i, int j) {
+ while (i != 20)
+ i += 2;
+
+ j += func(2, i);
+ return (i * 3 + j*2)*j;
+}
+
+int SumArray(int Array[], int Num) {
+ int i, Result = 0;
+ for (i = 0; i < Num; ++i)
+ Result += Array[i];
+
+ return Result;
+}
+
+int ArrayParam(int Values[100]) {
+ return EF1((int*)Values[50], (char*)1, &Values[50]);
+}
+
+int ArrayToSum(void) {
+ int A[100], i;
+ for (i = 0; i < 100; ++i)
+ A[i] = i*4;
+
+ return A[A[0]]; //SumArray(A, 100);
+}
+
+
+int ExternFunc(long long, unsigned*, short, unsigned char);
+
+int main(int argc, char *argv[]) {
+ unsigned i;
+ puts("Hello world!\n");
+
+ ExternFunc(-1, 0, (short)argc, 2);
+ //func(argc, argc);
+
+ for (i = 0; i < 10; i++)
+ puts(argv[3]);
+ return 0;
+}
+
+double MathFunc(double X, double Y, double Z,
+ double AA, double BB, double CC, double DD,
+ double EE, double FF, double GG, double HH,
+ double aAA, double aBB, double aCC, double aDD,
+ double aEE, double aFF) {
+ return X + Y + Z + AA + BB + CC + DD + EE + FF + GG + HH
+ + aAA + aBB + aCC + aDD + aEE + aFF;
+}
+
+
+
+void strcpy(char *s1, char *s2) {
+ while (*s1++ = *s2++);
+}
+
+void strcat(char *s1, char *s2) {
+ while (*s1++);
+ s1--;
+ while (*s1++ = *s2++);
+}
+
+int strcmp(char *s1, char *s2) {
+ while (*s1++ == *s2++);
+ if (*s1 == 0) {
+ if (*s2 == 0) {
+ return 0;
+ } else {
+ return -1;
+ }
+ } else {
+ if (*s2 == 0) {
+ return 1;
+ } else {
+ return (*(--s1) - *(--s2));
+ }
+ }
+}
diff --git a/test/CodeGen/2002-07-16-HardStringInit.c b/test/CodeGen/2002-07-16-HardStringInit.c
new file mode 100644
index 000000000000..b307359b0fc9
--- /dev/null
+++ b/test/CodeGen/2002-07-16-HardStringInit.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+ char auto_kibitz_list[100][20] = {
+ {"diepx"},
+ {"ferret"},
+ {"knightc"},
+ {"knightcap"}};
+
diff --git a/test/CodeGen/2002-07-17-StringConstant.c b/test/CodeGen/2002-07-17-StringConstant.c
new file mode 100644
index 000000000000..5b86a5b7dff6
--- /dev/null
+++ b/test/CodeGen/2002-07-17-StringConstant.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+char * foo() { return "\\begin{"; }
diff --git a/test/CodeGen/2002-07-30-SubregSetAssertion.c b/test/CodeGen/2002-07-30-SubregSetAssertion.c
new file mode 100644
index 000000000000..39e97b3b4aec
--- /dev/null
+++ b/test/CodeGen/2002-07-30-SubregSetAssertion.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+union X {
+ void *B;
+};
+
+union X foo() {
+ union X A;
+ A.B = (void*)123;
+ return A;
+}
diff --git a/test/CodeGen/2002-07-30-UnionTest.c b/test/CodeGen/2002-07-30-UnionTest.c
new file mode 100644
index 000000000000..d5b92e710657
--- /dev/null
+++ b/test/CodeGen/2002-07-30-UnionTest.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+union X;
+struct Empty {};
+union F {};
+union Q { union Q *X; };
+union X {
+ char C;
+ int A, Z;
+ long long B;
+ void *b1;
+ struct { int A; long long Z; } Q;
+};
+
+union X foo(union X A) {
+ A.C = 123;
+ A.A = 39249;
+ //A.B = (void*)123040123321;
+ A.B = 12301230123123LL;
+ A.Z = 1;
+ return A;
+}
diff --git a/test/CodeGen/2002-07-30-VarArgsCallFailure.c b/test/CodeGen/2002-07-30-VarArgsCallFailure.c
new file mode 100644
index 000000000000..784305d6d3b6
--- /dev/null
+++ b/test/CodeGen/2002-07-30-VarArgsCallFailure.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+int tcount;
+void test(char *, const char*, int);
+void foo() {
+ char Buf[10];
+ test(Buf, "n%%%d", tcount++);
+}
diff --git a/test/CodeGen/2002-07-31-BadAssert.c b/test/CodeGen/2002-07-31-BadAssert.c
new file mode 100644
index 000000000000..512a63a09a29
--- /dev/null
+++ b/test/CodeGen/2002-07-31-BadAssert.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+typedef struct
+{
+ unsigned char type; /* Indicates, NORMAL, SUBNORMAL, etc. */
+} InternalFPF;
+
+
+static void SetInternalFPFZero(InternalFPF *dest) {
+ dest->type=0;
+}
+
+void denormalize(InternalFPF *ptr) {
+ SetInternalFPFZero(ptr);
+}
+
diff --git a/test/CodeGen/2002-07-31-SubregFailure.c b/test/CodeGen/2002-07-31-SubregFailure.c
new file mode 100644
index 000000000000..5c7f38f00579
--- /dev/null
+++ b/test/CodeGen/2002-07-31-SubregFailure.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+typedef union {
+ long (*ap)[4];
+} ptrs;
+
+void DoAssignIteration() {
+ ptrs abase;
+ abase.ap+=27;
+ Assignment(*abase.ap);
+}
+
+
diff --git a/test/CodeGen/2002-08-02-UnionTest.c b/test/CodeGen/2002-08-02-UnionTest.c
new file mode 100644
index 000000000000..2be149909be5
--- /dev/null
+++ b/test/CodeGen/2002-08-02-UnionTest.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+/* In this testcase, the return value of foo() is being promoted to a register
+ * which breaks stuff
+ */
+int printf(const char * restrict format, ...);
+
+union X { char X; void *B; int a, b, c, d;};
+
+union X foo() {
+ union X Global;
+ Global.B = (void*)123; /* Interesting part */
+ return Global;
+}
+
+int main() {
+ union X test = foo();
+ printf("0x%p", test.B);
+}
diff --git a/test/CodeGen/2002-08-19-RecursiveLocals.c b/test/CodeGen/2002-08-19-RecursiveLocals.c
new file mode 100644
index 000000000000..89c67bad663a
--- /dev/null
+++ b/test/CodeGen/2002-08-19-RecursiveLocals.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+/* This testcase doesn't actually test a bug, it's just the result of me
+ * figuring out the syntax for forward declaring a static variable. */
+struct list {
+ int x;
+ struct list *Next;
+};
+
+static struct list B; /* Forward declare static */
+static struct list A = { 7, &B };
+static struct list B = { 8, &A };
+
+extern struct list D; /* forward declare normal var */
+
+struct list C = { 7, &D };
+struct list D = { 8, &C };
+
diff --git a/test/CodeGen/2002-09-08-PointerShifts.c b/test/CodeGen/2002-09-08-PointerShifts.c
new file mode 100644
index 000000000000..7d1ba6e90fe4
--- /dev/null
+++ b/test/CodeGen/2002-09-08-PointerShifts.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+int foo(int *A, unsigned X) {
+ return A[X];
+}
diff --git a/test/CodeGen/2002-09-18-UnionProblem.c b/test/CodeGen/2002-09-18-UnionProblem.c
new file mode 100644
index 000000000000..d299c19009ca
--- /dev/null
+++ b/test/CodeGen/2002-09-18-UnionProblem.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+struct DWstruct {
+ char high, low;
+};
+
+typedef union {
+ struct DWstruct s;
+ short ll;
+} DWunion;
+
+short __udivmodhi4 (char n1, char bm) {
+ DWunion rr;
+
+ if (bm == 0)
+ {
+ rr.s.high = n1;
+ }
+ else
+ {
+ rr.s.high = bm;
+ }
+
+ return rr.ll;
+}
diff --git a/test/CodeGen/2002-09-19-StarInLabel.c b/test/CodeGen/2002-09-19-StarInLabel.c
new file mode 100644
index 000000000000..e046e2b00297
--- /dev/null
+++ b/test/CodeGen/2002-09-19-StarInLabel.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+extern void start() __asm__("start");
+extern void _start() __asm__("_start");
+extern void __start() __asm__("__start");
+void start() {}
+void _start() {}
+void __start() {}
+
diff --git a/test/CodeGen/2002-10-12-TooManyArguments.c b/test/CodeGen/2002-10-12-TooManyArguments.c
new file mode 100644
index 000000000000..2324c2aa4662
--- /dev/null
+++ b/test/CodeGen/2002-10-12-TooManyArguments.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+void foo() {}
+
+void bar() {
+ foo(1, 2, 3); /* Too many arguments passed */
+}
diff --git a/test/CodeGen/2002-12-15-GlobalBoolTest.c b/test/CodeGen/2002-12-15-GlobalBoolTest.c
new file mode 100644
index 000000000000..3c4133f4be73
--- /dev/null
+++ b/test/CodeGen/2002-12-15-GlobalBoolTest.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+_Bool X = 0;
+
diff --git a/test/CodeGen/2002-12-15-GlobalConstantTest.c b/test/CodeGen/2002-12-15-GlobalConstantTest.c
new file mode 100644
index 000000000000..8203f569625d
--- /dev/null
+++ b/test/CodeGen/2002-12-15-GlobalConstantTest.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+const char *W = "foo";
+const int X = 7;
+int Y = 8;
+const char * const Z = "bar";
+
diff --git a/test/CodeGen/2002-12-15-GlobalRedefinition.c b/test/CodeGen/2002-12-15-GlobalRedefinition.c
new file mode 100644
index 000000000000..646e91ec3dfa
--- /dev/null
+++ b/test/CodeGen/2002-12-15-GlobalRedefinition.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+extern char algbrfile[9];
+char algbrfile[9] = "abcdefgh";
+
diff --git a/test/CodeGen/2002-12-15-StructParameters.c b/test/CodeGen/2002-12-15-StructParameters.c
new file mode 100644
index 000000000000..f6b59de7f0a6
--- /dev/null
+++ b/test/CodeGen/2002-12-15-StructParameters.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+typedef struct
+{
+ void *stack;
+ unsigned size;
+ unsigned avail;
+} compile_stack_type;
+
+void foo(void*);
+void bar(compile_stack_type T, unsigned);
+
+void test() {
+ compile_stack_type CST;
+ foo(&CST);
+
+ bar(CST, 12);
+}
diff --git a/test/CodeGen/2003-01-30-UnionInit.c b/test/CodeGen/2003-01-30-UnionInit.c
new file mode 100644
index 000000000000..98aee727b4ec
--- /dev/null
+++ b/test/CodeGen/2003-01-30-UnionInit.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+union foo {
+ struct { char A, B; } X;
+ int C;
+};
+
+union foo V = { {1, 2} };
diff --git a/test/CodeGen/2003-03-03-DeferredType.c b/test/CodeGen/2003-03-03-DeferredType.c
new file mode 100644
index 000000000000..a7a4ce38e635
--- /dev/null
+++ b/test/CodeGen/2003-03-03-DeferredType.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+
+
+struct foo A;
+
+struct foo {
+ int x;
+double D;
+};
+
diff --git a/test/CodeGen/2003-06-22-UnionCrash.c b/test/CodeGen/2003-06-22-UnionCrash.c
new file mode 100644
index 000000000000..eb5014c37e7d
--- /dev/null
+++ b/test/CodeGen/2003-06-22-UnionCrash.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+struct Blend_Map_Entry {
+ union {
+ float Colour[5];
+ double Point_Slope[2];
+ } Vals;
+};
+
+void test(struct Blend_Map_Entry* Foo)
+{
+}
+
diff --git a/test/CodeGen/2003-06-23-GCC-fold-infinite-recursion.c b/test/CodeGen/2003-06-23-GCC-fold-infinite-recursion.c
new file mode 100644
index 000000000000..51d4824681a8
--- /dev/null
+++ b/test/CodeGen/2003-06-23-GCC-fold-infinite-recursion.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+double Test(double A, double B, double C, double D) {
+ return -(A-B) - (C-D);
+}
+
diff --git a/test/CodeGen/2003-06-26-CFECrash.c b/test/CodeGen/2003-06-26-CFECrash.c
new file mode 100644
index 000000000000..dd874b7b4547
--- /dev/null
+++ b/test/CodeGen/2003-06-26-CFECrash.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+typedef struct min_info {
+ long offset;
+ unsigned file_attr;
+} min_info;
+
+typedef struct Globals {
+ char answerbuf;
+ min_info info[1];
+ min_info *pInfo;
+} Uz_Globs;
+
+extern Uz_Globs G;
+
+int extract_or_test_files() {
+ G.pInfo = G.info;
+}
+
diff --git a/test/CodeGen/2003-06-29-MultipleFunctionDefinition.c b/test/CodeGen/2003-06-29-MultipleFunctionDefinition.c
new file mode 100644
index 000000000000..99b3a7f5ba36
--- /dev/null
+++ b/test/CodeGen/2003-06-29-MultipleFunctionDefinition.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -std=gnu89 -emit-llvm %s -o /dev/null
+
+/* This is apparently legal C.
+ */
+extern __inline__ void test() { }
+
+void test() {
+}
diff --git a/test/CodeGen/2003-07-22-ArrayAccessTypeSafety.c b/test/CodeGen/2003-07-22-ArrayAccessTypeSafety.c
new file mode 100644
index 000000000000..d0703ef5e914
--- /dev/null
+++ b/test/CodeGen/2003-07-22-ArrayAccessTypeSafety.c
@@ -0,0 +1,7 @@
+/* RUN: %clang_cc1 %s -emit-llvm -o - | grep -v alloca | not grep bitcast
+ */
+
+void test(int* array, long long N) {
+ array[N] = N[array] = 33;
+}
+
diff --git a/test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c b/test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c
new file mode 100644
index 000000000000..12bce268cfac
--- /dev/null
+++ b/test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c
@@ -0,0 +1,14 @@
+/* RUN: %clang_cc1 %s -emit-llvm -o - | not grep __builtin_
+ *
+ * __builtin_longjmp/setjmp should get transformed into llvm.setjmp/longjmp
+ * just like explicit setjmp/longjmp calls are.
+ */
+
+void jumpaway(int *ptr) {
+ __builtin_longjmp(ptr,1);
+}
+
+int main(void) {
+ __builtin_setjmp(0);
+ jumpaway(0);
+}
diff --git a/test/CodeGen/2003-08-17-DeadCodeShortCircuit.c b/test/CodeGen/2003-08-17-DeadCodeShortCircuit.c
new file mode 100644
index 000000000000..031b530672a3
--- /dev/null
+++ b/test/CodeGen/2003-08-17-DeadCodeShortCircuit.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -x c %s -emit-llvm -o /dev/null
+
+int test(_Bool pos, _Bool color) {
+ return 0;
+ return (pos && color);
+}
diff --git a/test/CodeGen/2003-08-18-SigSetJmp.c b/test/CodeGen/2003-08-18-SigSetJmp.c
new file mode 100644
index 000000000000..1b1b18f6eecc
--- /dev/null
+++ b/test/CodeGen/2003-08-18-SigSetJmp.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm %s -o /dev/null
+
+#define _JBLEN ((9 * 2) + 3 + 16)
+typedef int sigjmp_buf[_JBLEN + 1];
+int sigsetjmp(sigjmp_buf env, int savemask);
+sigjmp_buf B;
+int foo() {
+ sigsetjmp(B, 1);
+ bar();
+}
diff --git a/test/CodeGen/2003-08-18-StructAsValue.c b/test/CodeGen/2003-08-18-StructAsValue.c
new file mode 100644
index 000000000000..9b8b5a2b1c19
--- /dev/null
+++ b/test/CodeGen/2003-08-18-StructAsValue.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+typedef struct {
+ int op;
+} event_t;
+
+event_t test(int X) {
+ event_t foo = { 1 }, bar = { 2 };
+ return X ? foo : bar;
+}
diff --git a/test/CodeGen/2003-08-20-BadBitfieldRef.c b/test/CodeGen/2003-08-20-BadBitfieldRef.c
new file mode 100644
index 000000000000..a001546fb55d
--- /dev/null
+++ b/test/CodeGen/2003-08-20-BadBitfieldRef.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+void foo()
+{
+ char *ap;
+ ap[1] == '-' && ap[2] == 0;
+}
+
diff --git a/test/CodeGen/2003-08-20-PrototypeMismatch.c b/test/CodeGen/2003-08-20-PrototypeMismatch.c
new file mode 100644
index 000000000000..fa42ca581a0a
--- /dev/null
+++ b/test/CodeGen/2003-08-20-PrototypeMismatch.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+
+static int foo(int);
+
+static int foo(C)
+char C;
+{
+ return C;
+}
+
+void test() {
+ foo(7);
+}
diff --git a/test/CodeGen/2003-08-20-vfork-bug.c b/test/CodeGen/2003-08-20-vfork-bug.c
new file mode 100644
index 000000000000..7ec0048828c1
--- /dev/null
+++ b/test/CodeGen/2003-08-20-vfork-bug.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+extern int vfork(void);
+test() {
+ vfork();
+}
diff --git a/test/CodeGen/2003-08-21-BinOp-Type-Mismatch.c b/test/CodeGen/2003-08-21-BinOp-Type-Mismatch.c
new file mode 100644
index 000000000000..d86b0244e17b
--- /dev/null
+++ b/test/CodeGen/2003-08-21-BinOp-Type-Mismatch.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+struct bar;
+
+void foo()
+{
+ unsigned int frame, focus;
+ (struct bar *) focus == (focus ? ((struct bar *) frame) : 0);
+}
+
diff --git a/test/CodeGen/2003-08-21-StmtExpr.c b/test/CodeGen/2003-08-21-StmtExpr.c
new file mode 100644
index 000000000000..39db694400d8
--- /dev/null
+++ b/test/CodeGen/2003-08-21-StmtExpr.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+typedef struct {
+ unsigned long val;
+} structty;
+
+void bar(structty new_mask);
+static void foo() {
+ bar(({ structty mask; mask; }));
+}
+
diff --git a/test/CodeGen/2003-08-21-WideString.c b/test/CodeGen/2003-08-21-WideString.c
new file mode 100644
index 000000000000..4071d17c7970
--- /dev/null
+++ b/test/CodeGen/2003-08-21-WideString.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+// This bit is taken from Sema/wchar.c so we can avoid the wchar.h include.
+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(__sun) || defined(__AuroraUX__)
+ #define WCHAR_T_TYPE long
+#else /* Solaris or AuroraUX. */
+ #define WCHAR_T_TYPE int
+#endif
+
+struct {
+ wchar_t *name;
+} syms = { L"NUL" };
diff --git a/test/CodeGen/2003-08-23-LocalUnionTest.c b/test/CodeGen/2003-08-23-LocalUnionTest.c
new file mode 100644
index 000000000000..50b01e425878
--- /dev/null
+++ b/test/CodeGen/2003-08-23-LocalUnionTest.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+
+union foo { int X; };
+
+int test(union foo* F) {
+ {
+ union foo { float X; } A;
+ }
+}
diff --git a/test/CodeGen/2003-08-29-BitFieldStruct.c b/test/CodeGen/2003-08-29-BitFieldStruct.c
new file mode 100644
index 000000000000..d8995eab3df9
--- /dev/null
+++ b/test/CodeGen/2003-08-29-BitFieldStruct.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+struct Word {
+ short bar;
+ short baz;
+ int final:1;
+ short quux;
+} *word_limit;
+
+void foo ()
+{
+ word_limit->final = (word_limit->final && word_limit->final);
+}
diff --git a/test/CodeGen/2003-08-29-HugeCharConst.c b/test/CodeGen/2003-08-29-HugeCharConst.c
new file mode 100644
index 000000000000..cd3eb54b31d4
--- /dev/null
+++ b/test/CodeGen/2003-08-29-HugeCharConst.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+void foo() {
+ unsigned char int_latin1[] = "f\200\372b\200\343\200\340";
+}
diff --git a/test/CodeGen/2003-08-29-StructLayoutBug.c b/test/CodeGen/2003-08-29-StructLayoutBug.c
new file mode 100644
index 000000000000..0f45fc94e340
--- /dev/null
+++ b/test/CodeGen/2003-08-29-StructLayoutBug.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+struct foo {
+ unsigned int I:1;
+ unsigned char J[1];
+ unsigned int K:1;
+ };
+
+void test(struct foo *X) {}
+
diff --git a/test/CodeGen/2003-08-30-AggregateInitializer.c b/test/CodeGen/2003-08-30-AggregateInitializer.c
new file mode 100644
index 000000000000..5beb14e5f8f0
--- /dev/null
+++ b/test/CodeGen/2003-08-30-AggregateInitializer.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+struct istruct {
+ unsigned char C;
+};
+
+struct foo {
+ unsigned int I:1;
+ struct istruct J;
+ unsigned char L[1];
+ unsigned int K:1;
+};
+
+struct foo F = { 1, { 7 }, { 123 } , 1 };
+
+
diff --git a/test/CodeGen/2003-08-30-LargeIntegerBitfieldMember.c b/test/CodeGen/2003-08-30-LargeIntegerBitfieldMember.c
new file mode 100644
index 000000000000..483cb668a28b
--- /dev/null
+++ b/test/CodeGen/2003-08-30-LargeIntegerBitfieldMember.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+struct foo {
+ unsigned int I:1;
+ unsigned char J[1][123];
+ unsigned int K:1;
+ };
+
+struct foo F;
diff --git a/test/CodeGen/2003-09-18-BitfieldTests.c b/test/CodeGen/2003-09-18-BitfieldTests.c
new file mode 100644
index 000000000000..6807f5a1fa4d
--- /dev/null
+++ b/test/CodeGen/2003-09-18-BitfieldTests.c
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -w -emit-llvm %s -o /dev/null
+
+
+typedef struct BF {
+ int A : 1;
+ char B;
+ int C : 13;
+} BF;
+
+char *test1(BF *b) {
+ return &b->B; // Must be able to address non-bitfield
+}
+
+void test2(BF *b) { // Increment and decrement operators
+ b->A++;
+ --b->C;
+}
+
+void test3(BF *b) {
+ b->C = 12345; // Store
+}
+
+int test4(BF *b) {
+ return b->C; // Load
+}
+
+void test5(BF *b, int i) { // array ref
+ b[i].C = 12345;
+}
+
diff --git a/test/CodeGen/2003-09-30-StructLayout.c b/test/CodeGen/2003-09-30-StructLayout.c
new file mode 100644
index 000000000000..45ef69ce60f8
--- /dev/null
+++ b/test/CodeGen/2003-09-30-StructLayout.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+enum En {
+ ENUM_VAL
+};
+
+struct St {
+ unsigned char A;
+ enum En B;
+ unsigned char C;
+ enum En D;
+ float E;
+};
+
+
+void func(struct St* A) {
+ A->D = ENUM_VAL;
+}
diff --git a/test/CodeGen/2003-10-02-UnionLValueError.c b/test/CodeGen/2003-10-02-UnionLValueError.c
new file mode 100644
index 000000000000..180eb1080be9
--- /dev/null
+++ b/test/CodeGen/2003-10-02-UnionLValueError.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+int sprintf(char * restrict str, const char * restrict format, ...);
+union U{
+ int i[8];
+ char s[80];
+};
+
+void format_message(char *buffer, union U *u) {
+ sprintf(buffer, u->s);
+}
diff --git a/test/CodeGen/2003-10-06-NegateExprType.c b/test/CodeGen/2003-10-06-NegateExprType.c
new file mode 100644
index 000000000000..6d692c1323de
--- /dev/null
+++ b/test/CodeGen/2003-10-06-NegateExprType.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+extern int A[10];
+void Func(int *B) {
+ B - &A[5];
+}
+
diff --git a/test/CodeGen/2003-10-09-UnionInitializerBug.c b/test/CodeGen/2003-10-09-UnionInitializerBug.c
new file mode 100644
index 000000000000..a14fd084c699
--- /dev/null
+++ b/test/CodeGen/2003-10-09-UnionInitializerBug.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+struct Foo {
+ unsigned a;
+ unsigned b;
+ unsigned c;
+};
+
+struct Bar {
+ union {
+ void **a;
+ struct Foo b;
+ }u;
+};
+
+struct Bar test = {0};
+
diff --git a/test/CodeGen/2003-10-28-ident.c b/test/CodeGen/2003-10-28-ident.c
new file mode 100644
index 000000000000..d1e54476b9ad
--- /dev/null
+++ b/test/CodeGen/2003-10-28-ident.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+#ident "foo"
diff --git a/test/CodeGen/2003-10-29-AsmRename.c b/test/CodeGen/2003-10-29-AsmRename.c
new file mode 100644
index 000000000000..d0f19af32276
--- /dev/null
+++ b/test/CodeGen/2003-10-29-AsmRename.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -emit-llvm %s -triple x86_64-apple-darwin -o /dev/null
+
+
+struct foo { int X; };
+struct bar { int Y; };
+
+extern int Func(struct foo*) __asm__("Func64");
+extern int Func64(struct bar*);
+
+int Func(struct foo *F) {
+ return 1;
+}
+
+int Func64(struct bar* B) {
+ return 0;
+}
+
+
+int test() {
+ Func(0); /* should be renamed to call Func64 */
+ Func64(0);
+}
diff --git a/test/CodeGen/2003-11-01-C99-CompoundLiteral.c b/test/CodeGen/2003-11-01-C99-CompoundLiteral.c
new file mode 100644
index 000000000000..f4d3824fa647
--- /dev/null
+++ b/test/CodeGen/2003-11-01-C99-CompoundLiteral.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+typedef struct { int foo; } spinlock_t;
+typedef struct wait_queue_head_t { spinlock_t lock; } wait_queue_head_t;
+void call_usermodehelper(void) {
+ struct wait_queue_head_t work = { lock: (spinlock_t) { 0 }, };
+}
+
diff --git a/test/CodeGen/2003-11-01-EmptyStructCrash.c b/test/CodeGen/2003-11-01-EmptyStructCrash.c
new file mode 100644
index 000000000000..e0f231af5994
--- /dev/null
+++ b/test/CodeGen/2003-11-01-EmptyStructCrash.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+typedef struct { } the_coolest_struct_in_the_world;
+extern the_coolest_struct_in_the_world xyzzy;
+void *foo() { return &xyzzy; }
+
diff --git a/test/CodeGen/2003-11-01-GlobalUnionInit.c b/test/CodeGen/2003-11-01-GlobalUnionInit.c
new file mode 100644
index 000000000000..8290379494b6
--- /dev/null
+++ b/test/CodeGen/2003-11-01-GlobalUnionInit.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+union bdflush_param {
+ struct { int x; } b_un;
+ int y[1];
+} bdf_prm = {{30}};
+
diff --git a/test/CodeGen/2003-11-03-AddrArrayElement.c b/test/CodeGen/2003-11-03-AddrArrayElement.c
new file mode 100644
index 000000000000..50e81d6fd86a
--- /dev/null
+++ b/test/CodeGen/2003-11-03-AddrArrayElement.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+// This should be turned into a tasty getelementptr instruction, not a nasty
+// series of casts and address arithmetic.
+
+char Global[100];
+
+char *test1(unsigned i) {
+ // CHECK: getelementptr
+ return &Global[i];
+}
diff --git a/test/CodeGen/2003-11-04-EmptyStruct.c b/test/CodeGen/2003-11-04-EmptyStruct.c
new file mode 100644
index 000000000000..e771b8830070
--- /dev/null
+++ b/test/CodeGen/2003-11-04-EmptyStruct.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+typedef struct { } rwlock_t;
+struct fs_struct { rwlock_t lock; int umask; };
+void __copy_fs_struct(struct fs_struct *fs) { fs->lock = (rwlock_t) { }; }
+
diff --git a/test/CodeGen/2003-11-04-OutOfMemory.c b/test/CodeGen/2003-11-04-OutOfMemory.c
new file mode 100644
index 000000000000..579c93daae58
--- /dev/null
+++ b/test/CodeGen/2003-11-04-OutOfMemory.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+void schedule_timeout(signed long timeout)
+{
+ switch (timeout)
+ {
+ case ((long)(~0UL>>1)): break;
+ }
+}
diff --git a/test/CodeGen/2003-11-08-PointerSubNotGetelementptr.c b/test/CodeGen/2003-11-08-PointerSubNotGetelementptr.c
new file mode 100644
index 000000000000..9a9c642f11a5
--- /dev/null
+++ b/test/CodeGen/2003-11-08-PointerSubNotGetelementptr.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+char *test(char* C) {
+ // CHECK: getelementptr
+ return C-1; // Should turn into a GEP
+}
+
+int *test2(int* I) {
+ return I-1;
+}
diff --git a/test/CodeGen/2003-11-12-VoidString.c b/test/CodeGen/2003-11-12-VoidString.c
new file mode 100644
index 000000000000..d22e9f45cbd1
--- /dev/null
+++ b/test/CodeGen/2003-11-12-VoidString.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+void query_newnamebuf(void) { ((void)"query_newnamebuf"); }
+
diff --git a/test/CodeGen/2003-11-13-TypeSafety.c b/test/CodeGen/2003-11-13-TypeSafety.c
new file mode 100644
index 000000000000..b9add6c175a3
--- /dev/null
+++ b/test/CodeGen/2003-11-13-TypeSafety.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | grep getelementptr
+
+int *test(int *X, int Y) {
+ return X + Y;
+}
diff --git a/test/CodeGen/2003-11-16-StaticArrayInit.c b/test/CodeGen/2003-11-16-StaticArrayInit.c
new file mode 100644
index 000000000000..8a11c05d08db
--- /dev/null
+++ b/test/CodeGen/2003-11-16-StaticArrayInit.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+void bar () {
+ static char x[10];
+ static char *xend = x + 10;
+}
+
+
diff --git a/test/CodeGen/2003-11-18-CondExprLValue.c b/test/CodeGen/2003-11-18-CondExprLValue.c
new file mode 100644
index 000000000000..62968e5fbfc9
--- /dev/null
+++ b/test/CodeGen/2003-11-18-CondExprLValue.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+void split_large_page(unsigned long addr, pgprot_t prot)
+{
+ (addr ? prot : ((pgprot_t) { 0x001 } )).pgprot;
+}
+
diff --git a/test/CodeGen/2003-11-19-AddressOfRegister.c b/test/CodeGen/2003-11-19-AddressOfRegister.c
new file mode 100644
index 000000000000..e80ff654cff2
--- /dev/null
+++ b/test/CodeGen/2003-11-19-AddressOfRegister.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 %s -emit-llvm -o /dev/null
+
+struct item {
+ short delta[4];
+};
+
+int TEST(int nt) {
+ register struct item *aa;
+ aa[nt].delta;
+ return 1;
+}
diff --git a/test/CodeGen/2003-11-19-BitFieldArray.c b/test/CodeGen/2003-11-19-BitFieldArray.c
new file mode 100644
index 000000000000..841156306193
--- /dev/null
+++ b/test/CodeGen/2003-11-19-BitFieldArray.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+struct _GIOChannel {
+ int write_buf;
+ char partial_write_buf[6];
+ int d :1;
+};
+
+void g_io_channel_init (struct _GIOChannel *channel) {
+ channel->partial_write_buf[0];
+}
+
diff --git a/test/CodeGen/2003-11-20-Bitfields.c b/test/CodeGen/2003-11-20-Bitfields.c
new file mode 100644
index 000000000000..5284cde4a946
--- /dev/null
+++ b/test/CodeGen/2003-11-20-Bitfields.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+struct face_cachel {
+ unsigned int reverse :1;
+ unsigned char font_specified[1];
+};
+
+void
+ensure_face_cachel_contains_charset (struct face_cachel *cachel) {
+ cachel->font_specified[0] = 0;
+}
+
diff --git a/test/CodeGen/2003-11-20-ComplexDivision.c b/test/CodeGen/2003-11-20-ComplexDivision.c
new file mode 100644
index 000000000000..ecd780b9b3f8
--- /dev/null
+++ b/test/CodeGen/2003-11-20-ComplexDivision.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+int test() {
+ __complex__ double C;
+ double D;
+ C / D;
+}
diff --git a/test/CodeGen/2003-11-20-UnionBitfield.c b/test/CodeGen/2003-11-20-UnionBitfield.c
new file mode 100644
index 000000000000..6ffe76a17197
--- /dev/null
+++ b/test/CodeGen/2003-11-20-UnionBitfield.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+struct printf_spec {
+ unsigned int minus_flag:1;
+ char converter;
+};
+
+void parse_doprnt_spec () {
+ struct printf_spec spec;
+ spec.minus_flag = 1;
+}
+
diff --git a/test/CodeGen/2003-11-26-PointerShift.c b/test/CodeGen/2003-11-26-PointerShift.c
new file mode 100644
index 000000000000..530759eb0c10
--- /dev/null
+++ b/test/CodeGen/2003-11-26-PointerShift.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+unsigned long do_csum(const unsigned char *buff, int len, unsigned long result) {
+ if (2 & (unsigned long) buff) result += 1;
+ return result;
+}
diff --git a/test/CodeGen/2003-11-27-ConstructorCast.c b/test/CodeGen/2003-11-27-ConstructorCast.c
new file mode 100644
index 000000000000..f04fa213b94a
--- /dev/null
+++ b/test/CodeGen/2003-11-27-ConstructorCast.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+struct i387_soft_struct {
+ long cwd;
+};
+union i387_union {
+ struct i387_soft_struct soft;
+};
+struct thread_struct {
+ union i387_union i387;
+};
+void _init_task_union(void) {
+ struct thread_struct thread = (struct thread_struct) { {{0}} };
+}
diff --git a/test/CodeGen/2003-11-27-UnionCtorInitialization.c b/test/CodeGen/2003-11-27-UnionCtorInitialization.c
new file mode 100644
index 000000000000..ca80173bfdc7
--- /dev/null
+++ b/test/CodeGen/2003-11-27-UnionCtorInitialization.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+struct i387_soft_struct {
+ long cwd;
+ long twd;
+ long fip;
+};
+union i387_union {
+ struct i387_soft_struct soft;
+};
+struct thread_struct {
+ union i387_union i387;
+};
+void _init_task_union(void) {
+ struct thread_struct thread = (struct thread_struct) { {{0}} };
+}
diff --git a/test/CodeGen/2003-12-14-ExternInlineSupport.c b/test/CodeGen/2003-12-14-ExternInlineSupport.c
new file mode 100644
index 000000000000..eb3859c38092
--- /dev/null
+++ b/test/CodeGen/2003-12-14-ExternInlineSupport.c
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -std=gnu89 %s -emit-llvm -o - | not grep dead_function
+
+extern __inline__ void dead_function() {}
diff --git a/test/CodeGen/2004-01-01-UnknownInitSize.c b/test/CodeGen/2004-01-01-UnknownInitSize.c
new file mode 100644
index 000000000000..25ddebddccb0
--- /dev/null
+++ b/test/CodeGen/2004-01-01-UnknownInitSize.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+/*
+ * This regression test ensures that the C front end can compile initializers
+ * even when it cannot determine the size (as below).
+*/
+struct one
+{
+ int a;
+ int values [];
+};
+
+struct one hobbit = {5, {1, 2, 3}};
+
diff --git a/test/CodeGen/2004-01-08-ExternInlineRedefine.c b/test/CodeGen/2004-01-08-ExternInlineRedefine.c
new file mode 100644
index 000000000000..358a9c28f775
--- /dev/null
+++ b/test/CodeGen/2004-01-08-ExternInlineRedefine.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=gnu89 -emit-llvm %s -o /dev/null
+
+
+extern __inline long int
+__strtol_l (int a)
+{
+ return 0;
+}
+
+long int
+__strtol_l (int a)
+{
+ return 0;
+}
diff --git a/test/CodeGen/2004-02-12-LargeAggregateCopy.c b/test/CodeGen/2004-02-12-LargeAggregateCopy.c
new file mode 100644
index 000000000000..811ee8e3f641
--- /dev/null
+++ b/test/CodeGen/2004-02-12-LargeAggregateCopy.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+struct X { int V[10000]; };
+struct X Global1, Global2;
+void test() {
+ // CHECK: llvm.memcpy
+ Global2 = Global1;
+}
diff --git a/test/CodeGen/2004-02-13-BuiltinFrameReturnAddress.c b/test/CodeGen/2004-02-13-BuiltinFrameReturnAddress.c
new file mode 100644
index 000000000000..8c0b7ba8fff0
--- /dev/null
+++ b/test/CodeGen/2004-02-13-BuiltinFrameReturnAddress.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+void *test1() {
+ // CHECK: call i8* @llvm.returnaddress
+ return __builtin_return_address(1);
+}
+void *test2() {
+ // CHECK: call i8* @llvm.frameaddress
+ return __builtin_frame_address(0);
+}
diff --git a/test/CodeGen/2004-02-13-IllegalVararg.c b/test/CodeGen/2004-02-13-IllegalVararg.c
new file mode 100644
index 000000000000..cbc9151ec631
--- /dev/null
+++ b/test/CodeGen/2004-02-13-IllegalVararg.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -w -emit-llvm -o -
+
+float test(int X, ...) {
+ __builtin_va_list ap;
+ float F;
+ __builtin_va_start(ap, X);
+ F = __builtin_va_arg(ap, float);
+ return F;
+}
diff --git a/test/CodeGen/2004-02-13-Memset.c b/test/CodeGen/2004-02-13-Memset.c
new file mode 100644
index 000000000000..23a4d3b99a45
--- /dev/null
+++ b/test/CodeGen/2004-02-13-Memset.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | grep llvm.memset | count 3
+
+typedef __SIZE_TYPE__ size_t;
+void *memset(void*, int, size_t);
+void bzero(void*, size_t);
+
+void test(int* X, char *Y) {
+ // CHECK: call i8* llvm.memset
+ memset(X, 4, 1000);
+ // CHECK: call void bzero
+ bzero(Y, 100);
+}
diff --git a/test/CodeGen/2004-02-14-ZeroInitializer.c b/test/CodeGen/2004-02-14-ZeroInitializer.c
new file mode 100644
index 000000000000..3379a06c6284
--- /dev/null
+++ b/test/CodeGen/2004-02-14-ZeroInitializer.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: zeroinitializer
+int X[1000];
diff --git a/test/CodeGen/2004-02-20-Builtins.c b/test/CodeGen/2004-02-20-Builtins.c
new file mode 100644
index 000000000000..9be0523b4afd
--- /dev/null
+++ b/test/CodeGen/2004-02-20-Builtins.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | not grep builtin
+double sqrt(double x);
+void zsqrtxxx(float num) {
+ num = sqrt(num);
+}
diff --git a/test/CodeGen/2004-03-07-ComplexDivEquals.c b/test/CodeGen/2004-03-07-ComplexDivEquals.c
new file mode 100644
index 000000000000..e2cd539a80ab
--- /dev/null
+++ b/test/CodeGen/2004-03-07-ComplexDivEquals.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+void test(__complex__ double D, double X) {
+ D /= X;
+}
diff --git a/test/CodeGen/2004-03-07-ExternalConstant.c b/test/CodeGen/2004-03-07-ExternalConstant.c
new file mode 100644
index 000000000000..2de3a69bd679
--- /dev/null
+++ b/test/CodeGen/2004-03-07-ExternalConstant.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: @a = external constan
+extern const int a[]; // 'a' should be marked constant even though it's external!
+int foo () {
+ return a[0];
+}
diff --git a/test/CodeGen/2004-03-09-LargeArrayInitializers.c b/test/CodeGen/2004-03-09-LargeArrayInitializers.c
new file mode 100644
index 000000000000..b34af0d29907
--- /dev/null
+++ b/test/CodeGen/2004-03-09-LargeArrayInitializers.c
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+// Test that these initializers are handled efficiently
+
+int test(int x) {
+ const int XX[1000] = { 0, 0 };
+ const char S [1000] = "foo";
+
+ const int array[] = {
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ 17, 23, 123, 123, 49, 17, 23, 123, 123, 49, 17, 23, 123, 123, 49,
+ };
+ return array[x];
+}
diff --git a/test/CodeGen/2004-03-15-SimpleIndirectGoto.c b/test/CodeGen/2004-03-15-SimpleIndirectGoto.c
new file mode 100644
index 000000000000..93fb59ff142e
--- /dev/null
+++ b/test/CodeGen/2004-03-15-SimpleIndirectGoto.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+int code[]={0,0,0,0,1};
+void foo(int x) {
+ volatile int b;
+ b = 0xffffffff;
+}
+void bar(int *pc) {
+ static const void *l[] = {&&lab0, &&end};
+
+ foo(0);
+ goto *l[*pc];
+ lab0:
+ foo(0);
+ pc++;
+ goto *l[*pc];
+ end:
+ return;
+}
+int main() {
+ bar(code);
+ return 0;
+}
diff --git a/test/CodeGen/2004-03-16-AsmRegisterCrash.c b/test/CodeGen/2004-03-16-AsmRegisterCrash.c
new file mode 100644
index 000000000000..515d2436b1a8
--- /dev/null
+++ b/test/CodeGen/2004-03-16-AsmRegisterCrash.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+// XFAIL: *
+// XTARGET: arm, i386, i686, x86_64
+
+int foo() {
+#ifdef __arm__
+ register int X __asm__("r1");
+#else
+ register int X __asm__("ebx");
+#endif
+ return X;
+}
diff --git a/test/CodeGen/2004-05-07-VarArrays.c b/test/CodeGen/2004-05-07-VarArrays.c
new file mode 100644
index 000000000000..1ef5cf32e0b7
--- /dev/null
+++ b/test/CodeGen/2004-05-07-VarArrays.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+int foo(int len, char arr[][len], int X) {
+ return arr[X][0];
+}
diff --git a/test/CodeGen/2004-05-21-IncompleteEnum.c b/test/CodeGen/2004-05-21-IncompleteEnum.c
new file mode 100644
index 000000000000..41652d11a4fe
--- /dev/null
+++ b/test/CodeGen/2004-05-21-IncompleteEnum.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -w -emit-llvm %s -o /dev/null
+
+void test(enum foo *X) {
+}
+
diff --git a/test/CodeGen/2004-06-08-OpaqueStructArg.c b/test/CodeGen/2004-06-08-OpaqueStructArg.c
new file mode 100644
index 000000000000..cec44591f398
--- /dev/null
+++ b/test/CodeGen/2004-06-08-OpaqueStructArg.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+ struct fu;
+ void foo(struct fu);
+ void bar() {
+ foo;
+ }
diff --git a/test/CodeGen/2004-06-17-UnorderedBuiltins.c b/test/CodeGen/2004-06-17-UnorderedBuiltins.c
new file mode 100644
index 000000000000..90360c4b58c0
--- /dev/null
+++ b/test/CodeGen/2004-06-17-UnorderedBuiltins.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+_Bool A, B, C, D, E, F, G, H;
+void TestF(float X, float Y) {
+ A = __builtin_isgreater(X, Y);
+ B = __builtin_isgreaterequal(X, Y);
+ C = __builtin_isless(X, Y);
+ D = __builtin_islessequal(X, Y);
+ E = __builtin_islessgreater(X, Y);
+ F = __builtin_isunordered(X, Y);
+ //G = __builtin_isordered(X, Y); // Our current snapshot of GCC doesn't include this builtin
+ H = __builtin_isunordered(X, Y);
+}
+void TestD(double X, double Y) {
+ A = __builtin_isgreater(X, Y);
+ B = __builtin_isgreaterequal(X, Y);
+ C = __builtin_isless(X, Y);
+ D = __builtin_islessequal(X, Y);
+ E = __builtin_islessgreater(X, Y);
+ F = __builtin_isunordered(X, Y);
+ //G = __builtin_isordered(X, Y); // Our current snapshot doesn't include this builtin. FIXME
+ H = __builtin_isunordered(X, Y);
+}
diff --git a/test/CodeGen/2004-06-17-UnorderedCompares.c b/test/CodeGen/2004-06-17-UnorderedCompares.c
new file mode 100644
index 000000000000..7d2ba9614741
--- /dev/null
+++ b/test/CodeGen/2004-06-17-UnorderedCompares.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c99 %s -emit-llvm -o - | grep -v llvm.isunordered | not grep call
+
+_Bool A, B, C, D, E, F;
+void TestF(float X, float Y) {
+ A = __builtin_isgreater(X, Y);
+ B = __builtin_isgreaterequal(X, Y);
+ C = __builtin_isless(X, Y);
+ D = __builtin_islessequal(X, Y);
+ E = __builtin_islessgreater(X, Y);
+ F = __builtin_isunordered(X, Y);
+}
+void TestD(double X, double Y) {
+ A = __builtin_isgreater(X, Y);
+ B = __builtin_isgreaterequal(X, Y);
+ C = __builtin_isless(X, Y);
+ D = __builtin_islessequal(X, Y);
+ E = __builtin_islessgreater(X, Y);
+ F = __builtin_isunordered(X, Y);
+}
diff --git a/test/CodeGen/2004-06-18-VariableLengthArrayOfStructures.c b/test/CodeGen/2004-06-18-VariableLengthArrayOfStructures.c
new file mode 100644
index 000000000000..abf78fb09556
--- /dev/null
+++ b/test/CodeGen/2004-06-18-VariableLengthArrayOfStructures.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+struct S { };
+
+int xxxx(int a) {
+ struct S comps[a];
+ comps[0];
+}
+
diff --git a/test/CodeGen/2004-07-06-FunctionCast.c b/test/CodeGen/2004-07-06-FunctionCast.c
new file mode 100644
index 000000000000..32931e2fce71
--- /dev/null
+++ b/test/CodeGen/2004-07-06-FunctionCast.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+static int unused_func(void) {
+ return 1;
+}
+
+int foo(void) {
+ (void)unused_func; /* avoid compiler warning */
+ return 2;
+}
diff --git a/test/CodeGen/2004-08-06-LargeStructTest.c b/test/CodeGen/2004-08-06-LargeStructTest.c
new file mode 100644
index 000000000000..ee57f0b5af80
--- /dev/null
+++ b/test/CodeGen/2004-08-06-LargeStructTest.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+
+#define A(X) int X;
+#define B(X) A(X##0) A(X##1) A(X##2) A(X##3) A(X##4) A(X##5) A(X##6) A(X##7) \
+ A(X##8) A(X##9) A(X##A) A(X##B) A(X##C) A(X##D) A(X##E) A(X##F)
+#define C(X) B(X##0) B(X##1) B(X##2) B(X##3) B(X##4) B(X##5) B(X##6) B(X##7) \
+ B(X##8) B(X##9) B(X##A) B(X##B) B(X##C) B(X##D) B(X##E) B(X##F)
+
+struct foo {
+ C(x); // 256
+ C(y); // 256
+ C(z);
+};
+
+
+int test(struct foo *F) {
+ return F->xA1 + F->yFF + F->zC4;
+}
diff --git a/test/CodeGen/2004-11-25-UnnamedBitfieldPadding.c b/test/CodeGen/2004-11-25-UnnamedBitfieldPadding.c
new file mode 100644
index 000000000000..a6af2a574411
--- /dev/null
+++ b/test/CodeGen/2004-11-25-UnnamedBitfieldPadding.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+// This is a testcase for PR461
+typedef struct {
+ unsigned min_align: 1;
+ unsigned : 1;
+} addr_diff_vec_flags;
+
+addr_diff_vec_flags X;
diff --git a/test/CodeGen/2004-11-27-InvalidConstantExpr.c b/test/CodeGen/2004-11-27-InvalidConstantExpr.c
new file mode 100644
index 000000000000..431dccffc1a1
--- /dev/null
+++ b/test/CodeGen/2004-11-27-InvalidConstantExpr.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | not grep {foo\\* sub}
+// This should not produce a subtrace constantexpr of a pointer
+struct foo {
+ int Y;
+ char X[100];
+} F;
+
+int test(char *Y) {
+ return Y - F.X;
+}
diff --git a/test/CodeGen/2004-11-27-StaticFunctionRedeclare.c b/test/CodeGen/2004-11-27-StaticFunctionRedeclare.c
new file mode 100644
index 000000000000..55efa86865de
--- /dev/null
+++ b/test/CodeGen/2004-11-27-StaticFunctionRedeclare.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | \
+// RUN: opt -std-compile-opts -emit-llvm | not grep {declare i32.*func}
+
+// There should not be an unresolved reference to func here. Believe it or not,
+// the "expected result" is a function named 'func' which is internal and
+// referenced by bar().
+
+// This is PR244
+
+static int func();
+void bar() {
+ int func();
+ foo(func);
+}
+static int func(char** A, char ** B) {}
diff --git a/test/CodeGen/2005-01-02-ConstantInits.c b/test/CodeGen/2005-01-02-ConstantInits.c
new file mode 100644
index 000000000000..d85f5198650d
--- /dev/null
+++ b/test/CodeGen/2005-01-02-ConstantInits.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+// This tests all kinds of hard cases with initializers and
+// array subscripts. This corresponds to PR487.
+
+struct X { int a[2]; };
+
+int test() {
+ static int i23 = (int) &(((struct X *)0)->a[1]);
+ return i23;
+}
+
+int i = (int) &( ((struct X *)0) -> a[1]);
+
+int Arr[100];
+
+int foo(int i) { return bar(&Arr[49])+bar(&Arr[i]); }
+int foo2(int i) {
+ static const int *X = &Arr[49];
+ static int i23 = (int) &( ((struct X *)0) -> a[0]);
+ int *P = Arr;
+ ++P;
+ return bar(Arr+i);
+}
diff --git a/test/CodeGen/2005-01-02-PointerDifference.c b/test/CodeGen/2005-01-02-PointerDifference.c
new file mode 100644
index 000000000000..1114ef5c25de
--- /dev/null
+++ b/test/CodeGen/2005-01-02-PointerDifference.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: sdiv exact
+int Diff(int *P, int *Q) { return P-Q; }
diff --git a/test/CodeGen/2005-01-02-VAArgError-ICE.c b/test/CodeGen/2005-01-02-VAArgError-ICE.c
new file mode 100644
index 000000000000..06377c23d2aa
--- /dev/null
+++ b/test/CodeGen/2005-01-02-VAArgError-ICE.c
@@ -0,0 +1,9 @@
+// This file is erroneous, but should not cause the compiler to ICE.
+// PR481
+// RUN: %clang_cc1 %s -emit-llvm -o /dev/null
+
+int flags(int a, int b, ...) {
+ __builtin_va_list args;
+ __builtin_va_start(args,a); // not the last named arg
+ foo(args);
+}
diff --git a/test/CodeGen/2005-02-20-AggregateSAVEEXPR.c b/test/CodeGen/2005-02-20-AggregateSAVEEXPR.c
new file mode 100644
index 000000000000..99efb1bf79f3
--- /dev/null
+++ b/test/CodeGen/2005-02-20-AggregateSAVEEXPR.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 %s -o /dev/null -emit-llvm
+
+int foo(__complex float c) {
+ return creal(c);
+}
diff --git a/test/CodeGen/2005-02-27-MarkGlobalConstant.c b/test/CodeGen/2005-02-27-MarkGlobalConstant.c
new file mode 100644
index 000000000000..dc2cdbfa726f
--- /dev/null
+++ b/test/CodeGen/2005-02-27-MarkGlobalConstant.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// PR10414
+
+// The synthetic global made by the CFE for big initializer should be marked
+// constant.
+
+void bar();
+void foo() {
+ // CHECK: private unnamed_addr constant
+ char Blah[] = "asdlfkajsdlfkajsd;lfkajds;lfkjasd;flkajsd;lkfja;sdlkfjasd";
+ bar(Blah);
+}
diff --git a/test/CodeGen/2005-03-05-OffsetOfHack.c b/test/CodeGen/2005-03-05-OffsetOfHack.c
new file mode 100644
index 000000000000..442098107504
--- /dev/null
+++ b/test/CodeGen/2005-03-05-OffsetOfHack.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+struct s {
+ unsigned long int field[0];
+};
+
+#define OFFS \
+ (((char *) &((struct s *) 0)->field[0]) - (char *) 0)
+
+int foo[OFFS];
+
+
diff --git a/test/CodeGen/2005-03-06-OffsetOfStructCrash.c b/test/CodeGen/2005-03-06-OffsetOfStructCrash.c
new file mode 100644
index 000000000000..46968bb8db64
--- /dev/null
+++ b/test/CodeGen/2005-03-06-OffsetOfStructCrash.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+struct Y {};
+struct XXX {
+ struct Y F;
+};
+
+void test1() {
+ (int)&((struct XXX*)(((void *)0)))->F;
+}
+
+void test2() {
+ &((struct XXX*)(((void *)0)))->F;
+}
diff --git a/test/CodeGen/2005-03-11-Prefetch.c b/test/CodeGen/2005-03-11-Prefetch.c
new file mode 100644
index 000000000000..8d7d12edcbd2
--- /dev/null
+++ b/test/CodeGen/2005-03-11-Prefetch.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+void foo(int *P) {
+ // CHECK: llvm.prefetch
+ __builtin_prefetch(P);
+ __builtin_prefetch(P, 1);
+}
diff --git a/test/CodeGen/2005-04-09-ComplexOps.c b/test/CodeGen/2005-04-09-ComplexOps.c
new file mode 100644
index 000000000000..23716d362c9a
--- /dev/null
+++ b/test/CodeGen/2005-04-09-ComplexOps.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+#define I 1.0iF
+
+double __complex test(double X) { return ~-(X*I); }
+
+_Bool EQ(double __complex A, double __complex B) { return A == B; }
+_Bool NE(double __complex A, double __complex B) { return A != B; }
diff --git a/test/CodeGen/2005-05-06-CountBuiltins.c b/test/CodeGen/2005-05-06-CountBuiltins.c
new file mode 100644
index 000000000000..4c12100dc50c
--- /dev/null
+++ b/test/CodeGen/2005-05-06-CountBuiltins.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 %s -emit-llvm -o %t
+// RUN: not grep call*__builtin %t
+
+int G, H, I;
+void foo(int P) {
+ G = __builtin_clz(P);
+ H = __builtin_ctz(P);
+ I = __builtin_popcount(P);
+}
+
+long long g, h, i;
+void fooll(float P) {
+ g = __builtin_clzll(P);
+ g = __builtin_clzll(P);
+ h = __builtin_ctzll(P);
+ i = __builtin_popcountll(P);
+}
diff --git a/test/CodeGen/2005-05-10-GlobalUnionInit.c b/test/CodeGen/2005-05-10-GlobalUnionInit.c
new file mode 100644
index 000000000000..ddd7f5e92475
--- /dev/null
+++ b/test/CodeGen/2005-05-10-GlobalUnionInit.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+union A { // { uint }
+ union B { double *C; } D;
+} E = { { (double*)12312 } };
+
diff --git a/test/CodeGen/2005-06-15-ExpandGotoInternalProblem.c b/test/CodeGen/2005-06-15-ExpandGotoInternalProblem.c
new file mode 100644
index 000000000000..dd1acc54bc1d
--- /dev/null
+++ b/test/CodeGen/2005-06-15-ExpandGotoInternalProblem.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c99 %s -emit-llvm -o - | \
+// RUN: opt -std-compile-opts -disable-output
+// PR580
+
+int X, Y;
+int foo() {
+ int i;
+ for (i=0; i<100; i++ )
+ {
+ break;
+ i = ( X || Y ) ;
+ }
+}
+
diff --git a/test/CodeGen/2005-07-20-SqrtNoErrno.c b/test/CodeGen/2005-07-20-SqrtNoErrno.c
new file mode 100644
index 000000000000..f40f61d27f31
--- /dev/null
+++ b/test/CodeGen/2005-07-20-SqrtNoErrno.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// llvm.sqrt has undefined behavior on negative inputs, so it is
+// inappropriate to translate C/C++ sqrt to this.
+float sqrtf(float x);
+float foo(float X) {
+ // CHECK: foo
+ // CHECK: call float @sqrtf(float %
+ // Check that this is marked readonly when errno is ignored.
+ return sqrtf(X);
+}
diff --git a/test/CodeGen/2005-07-26-UnionInitCrash.c b/test/CodeGen/2005-07-26-UnionInitCrash.c
new file mode 100644
index 000000000000..557224018123
--- /dev/null
+++ b/test/CodeGen/2005-07-26-UnionInitCrash.c
@@ -0,0 +1,3 @@
+// PR607
+// RUN: %clang_cc1 %s -emit-llvm -o -
+union { char bytes[8]; double alignment; }EQ1 = {0,0,0,0,0,0,0,0};
diff --git a/test/CodeGen/2005-07-28-IncorrectWeakGlobal.c b/test/CodeGen/2005-07-28-IncorrectWeakGlobal.c
new file mode 100644
index 000000000000..cbacf2253911
--- /dev/null
+++ b/test/CodeGen/2005-07-28-IncorrectWeakGlobal.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | grep TheGlobal | not grep weak
+
+extern int TheGlobal;
+int foo() { return TheGlobal; }
+int TheGlobal = 1;
diff --git a/test/CodeGen/2005-09-20-ComplexConstants.c b/test/CodeGen/2005-09-20-ComplexConstants.c
new file mode 100644
index 000000000000..a23ccee0de2e
--- /dev/null
+++ b/test/CodeGen/2005-09-20-ComplexConstants.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 %s -emit-llvm -o /dev/null
+
+const double _Complex x[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+
diff --git a/test/CodeGen/2005-09-24-AsmUserPrefix.c b/test/CodeGen/2005-09-24-AsmUserPrefix.c
new file mode 100644
index 000000000000..16283130beb0
--- /dev/null
+++ b/test/CodeGen/2005-09-24-AsmUserPrefix.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | opt -std-compile-opts | llc | \
+// RUN: not grep _foo2
+
+void foo() __asm__("foo2");
+
+void bar() {
+ foo();
+}
diff --git a/test/CodeGen/2005-09-24-BitFieldCrash.c b/test/CodeGen/2005-09-24-BitFieldCrash.c
new file mode 100644
index 000000000000..d687d2f39d26
--- /dev/null
+++ b/test/CodeGen/2005-09-24-BitFieldCrash.c
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+struct tree_common {};
+
+struct tree_int_cst {
+ struct tree_common common;
+ struct tree_int_cst_lowhi {
+ unsigned long long low;
+ long long high;
+ } int_cst;
+};
+
+enum XXX { yyy };
+
+struct tree_function_decl {
+ struct tree_common common;
+ long long locus, y;
+ __extension__ enum XXX built_in_class : 2;
+
+};
+
+
+union tree_node {
+ struct tree_int_cst int_cst;
+ struct tree_function_decl function_decl;
+};
+
+
+void foo (union tree_node * decl) {
+ decl->function_decl.built_in_class != 0;
+}
+
+
diff --git a/test/CodeGen/2005-12-04-AttributeUsed.c b/test/CodeGen/2005-12-04-AttributeUsed.c
new file mode 100644
index 000000000000..4be6b798fd43
--- /dev/null
+++ b/test/CodeGen/2005-12-04-AttributeUsed.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: @llvm.used = appending global [2 x i8*] [i8* bitcast (void ()* @foo to i8*), i8* bitcast (i32* @X to i8*)], section "llvm.metadata"
+int X __attribute__((used));
+int Y;
+
+__attribute__((used)) void foo() {}
diff --git a/test/CodeGen/2005-12-04-DeclarationLineNumbers.c b/test/CodeGen/2005-12-04-DeclarationLineNumbers.c
new file mode 100644
index 000000000000..596d3eed24fc
--- /dev/null
+++ b/test/CodeGen/2005-12-04-DeclarationLineNumbers.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 %s -emit-llvm -g -o - | grep DW_TAG_compile_unit | count 1
+// PR664: ensure that line #'s are emitted for declarations
+
+
+short test(short br_data_0,
+short br_data_1,
+short br_data_2,
+short br_data_3,
+short br_data_4,
+short br_data_5,
+short br_data_6,
+short br_data_7) {
+
+short sm07 = br_data_0 + br_data_7;
+short sm16 = br_data_1 + br_data_6;
+short sm25 = br_data_2 + br_data_5;
+short sm34 = br_data_3 + br_data_4;
+short s0734 = sm07 + sm34;
+short s1625 = sm16 + sm25;
+
+return s0734 + s1625;
+}
+
diff --git a/test/CodeGen/2006-01-13-Includes.c b/test/CodeGen/2006-01-13-Includes.c
new file mode 100644
index 000000000000..9cc45cec55ef
--- /dev/null
+++ b/test/CodeGen/2006-01-13-Includes.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 %s -g -emit-llvm -o - | FileCheck %s
+// PR676
+
+int printf(const char * restrict format, ...);
+
+void test() {
+ printf("Hello World\n");
+}
+
+// CHECK: test{{[\\/]}}CodeGen
diff --git a/test/CodeGen/2006-01-13-StackSave.c b/test/CodeGen/2006-01-13-StackSave.c
new file mode 100644
index 000000000000..7c506b31f2a0
--- /dev/null
+++ b/test/CodeGen/2006-01-13-StackSave.c
@@ -0,0 +1,11 @@
+// PR691
+// RUN: %clang_cc1 %s -emit-llvm -o - | opt -std-compile-opts | \
+// RUN: llvm-dis | grep llvm.stacksave
+
+void test(int N) {
+ int i;
+ for (i = 0; i < N; ++i) {
+ int VLA[i];
+ external(VLA);
+ }
+}
diff --git a/test/CodeGen/2006-01-16-BitCountIntrinsicsUnsigned.c b/test/CodeGen/2006-01-16-BitCountIntrinsicsUnsigned.c
new file mode 100644
index 000000000000..ba7820a0db6c
--- /dev/null
+++ b/test/CodeGen/2006-01-16-BitCountIntrinsicsUnsigned.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+
+unsigned t2(unsigned X) {
+ // CHECK: t2
+ // CHECK: llvm.ctlz.i32
+ return __builtin_clz(X);
+}
+int t1(int X) {
+ // CHECK: t1
+ // CHECK: llvm.ctlz.i32
+ return __builtin_clz(X);
+}
diff --git a/test/CodeGen/2006-01-23-FileScopeAsm.c b/test/CodeGen/2006-01-23-FileScopeAsm.c
new file mode 100644
index 000000000000..472b46496710
--- /dev/null
+++ b/test/CodeGen/2006-01-23-FileScopeAsm.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: module asm "foo1"
+__asm__ ("foo1");
+// CHECK: module asm "foo2"
+__asm__ ("foo2");
+// CHECK: module asm "foo3"
+__asm__ ("foo3");
+// CHECK: module asm "foo4"
+__asm__ ("foo4");
+// CHECK: module asm "foo5"
+__asm__ ("foo5");
diff --git a/test/CodeGen/2006-03-03-MissingInitializer.c b/test/CodeGen/2006-03-03-MissingInitializer.c
new file mode 100644
index 000000000000..d2317d3acc41
--- /dev/null
+++ b/test/CodeGen/2006-03-03-MissingInitializer.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+struct X { int *XX; int Y;};
+
+void foo() {
+ // CHECK: @foo.nate = internal global i32 0
+ static int nate = 0;
+ struct X bob = { &nate, 14 };
+ bar(&bob);
+}
diff --git a/test/CodeGen/2006-03-16-VectorCtor.c b/test/CodeGen/2006-03-16-VectorCtor.c
new file mode 100644
index 000000000000..c04d4b977a2e
--- /dev/null
+++ b/test/CodeGen/2006-03-16-VectorCtor.c
@@ -0,0 +1,10 @@
+// Test that basic generic vector support works
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+typedef int v4si __attribute__ ((__vector_size__ (16)));
+void test(v4si *P, v4si *Q, float X) {
+ *P = (v4si){ X, X, X, X } * *Q;
+}
+
+v4si G = (v4si){ 0.1, 1.2, 4.2, 17.2 };
+
diff --git a/test/CodeGen/2006-03-17-KnRMismatch.c b/test/CodeGen/2006-03-17-KnRMismatch.c
new file mode 100644
index 000000000000..f678e9f11d81
--- /dev/null
+++ b/test/CodeGen/2006-03-17-KnRMismatch.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+void regnode(int op);
+
+void regnode(op)
+char op;
+{
+}
diff --git a/test/CodeGen/2006-05-19-SingleEltReturn.c b/test/CodeGen/2006-05-19-SingleEltReturn.c
new file mode 100644
index 000000000000..819237ce53be
--- /dev/null
+++ b/test/CodeGen/2006-05-19-SingleEltReturn.c
@@ -0,0 +1,23 @@
+// Test returning a single element aggregate value containing a double.
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+struct X {
+ double D;
+};
+
+struct Y {
+ struct X x;
+};
+
+struct Y bar();
+
+void foo(struct Y *P) {
+ *P = bar();
+}
+
+struct Y bar() {
+ struct Y a;
+ a.x.D = 0;
+ return a;
+}
+
diff --git a/test/CodeGen/2006-07-31-PR854.c b/test/CodeGen/2006-07-31-PR854.c
new file mode 100644
index 000000000000..b3b4d8eb616c
--- /dev/null
+++ b/test/CodeGen/2006-07-31-PR854.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple i686-linux-gnu -w %s -emit-llvm -o -
+
+// PR854
+ struct kernel_symbol {
+ unsigned long value;
+ };
+ unsigned long loops_per_jiffy = (1<<12);
+ static const char __kstrtab_loops_per_jiffy[]
+__attribute__((section("__ksymtab_strings"))) = "loops_per_jiffy";
+ static const struct kernel_symbol __ksymtab_loops_per_jiffy
+__attribute__((__used__)) __attribute__((section("__ksymtab"))) = { (unsigned
+long)&loops_per_jiffy, __kstrtab_loops_per_jiffy };
diff --git a/test/CodeGen/2006-09-11-BitfieldRefCrash.c b/test/CodeGen/2006-09-11-BitfieldRefCrash.c
new file mode 100644
index 000000000000..3d45d8bfd202
--- /dev/null
+++ b/test/CodeGen/2006-09-11-BitfieldRefCrash.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+// PR906
+
+struct state_struct {
+ unsigned long long phys_frame: 50;
+ unsigned valid : 2;
+} s;
+
+int mem_access(struct state_struct *p) {
+ return p->valid;
+}
+
diff --git a/test/CodeGen/2006-09-18-fwrite-cast-crash.c b/test/CodeGen/2006-09-18-fwrite-cast-crash.c
new file mode 100644
index 000000000000..a12fd0befe11
--- /dev/null
+++ b/test/CodeGen/2006-09-18-fwrite-cast-crash.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -emit-llvm -o /dev/null
+// PR910
+
+struct l_struct_2E_FILE { char x; };
+unsigned fwrite(signed char *, unsigned , unsigned , signed char *);
+static signed char str301[39];
+static void Usage(signed char *ltmp_611_6) {
+ struct l_struct_2E_FILE *ltmp_6202_16;
+ unsigned ltmp_6203_92;
+ ltmp_6203_92 = /*tail*/ ((unsigned (*) (signed char *, unsigned , unsigned ,
+struct l_struct_2E_FILE *))(void*)fwrite)((&(str301[0u])), 38u, 1u, ltmp_6202_16);
+}
diff --git a/test/CodeGen/2006-09-21-IncompleteElementType.c b/test/CodeGen/2006-09-21-IncompleteElementType.c
new file mode 100644
index 000000000000..1c71ea1ee9fa
--- /dev/null
+++ b/test/CodeGen/2006-09-21-IncompleteElementType.c
@@ -0,0 +1,3 @@
+// RUN: not %clang_cc1 %s -emit-llvm -o /dev/null
+
+struct A X[(927 - 37) / sizeof(struct A)];
diff --git a/test/CodeGen/2006-09-25-DebugFilename.c b/test/CodeGen/2006-09-25-DebugFilename.c
new file mode 100644
index 000000000000..2edb63f84dd8
--- /dev/null
+++ b/test/CodeGen/2006-09-25-DebugFilename.c
@@ -0,0 +1,4 @@
+// RUN: not %clang_cc1 %s -emit-llvm -o /dev/null
+#include "2006-09-25-DebugFilename.h"
+int func1() { return hfunc1(); }
+int func2() { fluffy; return hfunc1(); } // expected-error {{use of undeclared identifier 'fluffy'}}
diff --git a/test/CodeGen/2006-09-25-DebugFilename.h b/test/CodeGen/2006-09-25-DebugFilename.h
new file mode 100644
index 000000000000..9b03666b3c27
--- /dev/null
+++ b/test/CodeGen/2006-09-25-DebugFilename.h
@@ -0,0 +1,6 @@
+extern int exfunc(int a);
+
+static inline int hfunc1()
+{
+ return exfunc(1);
+}
diff --git a/test/CodeGen/2006-09-28-SimpleAsm.c b/test/CodeGen/2006-09-28-SimpleAsm.c
new file mode 100644
index 000000000000..c3983af5c98d
--- /dev/null
+++ b/test/CodeGen/2006-09-28-SimpleAsm.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// PR924
+
+void bar() {
+ // Extended asm
+ // CHECK: call void asm sideeffect "ext: xorl %eax, eax; movl eax, fs; movl eax, gs %blah
+ asm volatile ("ext: xorl %%eax, eax; movl eax, fs; movl eax, gs %%blah %= %\
+% " : : "r"(1));
+ // CHECK: call void asm sideeffect "nonext: xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs %%blah %= %%
+ // Non-extended asm.
+ asm volatile ("nonext: xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs %%blah %= %% ");
+}
diff --git a/test/CodeGen/2006-10-30-ArrayCrash.c b/test/CodeGen/2006-10-30-ArrayCrash.c
new file mode 100644
index 000000000000..67446fd0567b
--- /dev/null
+++ b/test/CodeGen/2006-10-30-ArrayCrash.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -O3 -emit-llvm -o - %s
+// PR954, PR911
+
+extern void foo();
+
+struct S {
+ short f1[3];
+ unsigned int f2 : 1;
+};
+
+void bar()
+{
+ struct S *A;
+
+ if (A->f2)
+ foo();
+}
diff --git a/test/CodeGen/2006-12-14-ordered_expr.c b/test/CodeGen/2006-12-14-ordered_expr.c
new file mode 100644
index 000000000000..c46ba8578941
--- /dev/null
+++ b/test/CodeGen/2006-12-14-ordered_expr.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -O3 -emit-llvm %s -o - | FileCheck %s
+
+int test2(float X, float Y) {
+ // CHECK: fcmp ord float %X, %Y
+ return !__builtin_isunordered(X, Y);
+}
diff --git a/test/CodeGen/2007-01-06-KNR-Proto.c b/test/CodeGen/2007-01-06-KNR-Proto.c
new file mode 100644
index 000000000000..d56a786fce53
--- /dev/null
+++ b/test/CodeGen/2007-01-06-KNR-Proto.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s
+// PR1083
+
+int svc_register (void (*dispatch) (int));
+
+int svc_register (dispatch)
+ void (*dispatch) ();
+{
+}
+
diff --git a/test/CodeGen/2007-01-20-VectorICE.c b/test/CodeGen/2007-01-20-VectorICE.c
new file mode 100644
index 000000000000..286b8a1b3de0
--- /dev/null
+++ b/test/CodeGen/2007-01-20-VectorICE.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+typedef float __m128 __attribute__((__vector_size__(16)));
+typedef long long __v2di __attribute__((__vector_size__(16)));
+typedef int __v4si __attribute__((__vector_size__(16)));
+
+__v2di bar(void);
+void foo(int X, __v4si *P) {
+ *P = X == 2 ? bar() : bar();
+}
+
diff --git a/test/CodeGen/2007-01-24-InlineAsmCModifier.c b/test/CodeGen/2007-01-24-InlineAsmCModifier.c
new file mode 100644
index 000000000000..5158898f5dc8
--- /dev/null
+++ b/test/CodeGen/2007-01-24-InlineAsmCModifier.c
@@ -0,0 +1,12 @@
+// Verify that the %c modifier works and strips off any prefixes from
+// immediates.
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+
+void foo() {
+ // CHECK: i32 789514
+ __asm__ volatile("/* " "pickANumber" ": %c0 */"::"i"(0xC0C0A));
+
+ // Check that non-c modifiers work also
+ // CHECK: i32 123
+ __asm__ volatile("/* " "pickANumber2 " ": %0 */"::"i"(123));
+}
diff --git a/test/CodeGen/2007-02-04-AddrLValue-2.c b/test/CodeGen/2007-02-04-AddrLValue-2.c
new file mode 100644
index 000000000000..bc44d1465f47
--- /dev/null
+++ b/test/CodeGen/2007-02-04-AddrLValue-2.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 %s -O3 -emit-llvm -o -
+// PR1173
+
+struct S { char s; };
+struct T { struct S t; };
+
+struct S *const p = &((struct T * const) (0x4000))->t;
+
+void
+foo (void)
+{
+ p->s = 0;
+}
diff --git a/test/CodeGen/2007-02-04-AddrLValue.c b/test/CodeGen/2007-02-04-AddrLValue.c
new file mode 100644
index 000000000000..400dcb60a73c
--- /dev/null
+++ b/test/CodeGen/2007-02-04-AddrLValue.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 %s -O3 -emit-llvm -o -
+// PR1176
+
+typedef struct
+{
+ char *key;
+ char *value;
+} T1;
+
+typedef struct
+{
+ long type;
+ char *value;
+} T3;
+
+T1 a[] =
+{
+ {
+ "",
+ ((char *)&((T3) {1, (char *) 1}))
+ }
+};
+
diff --git a/test/CodeGen/2007-02-04-EmptyStruct.c b/test/CodeGen/2007-02-04-EmptyStruct.c
new file mode 100644
index 000000000000..2b2896f6d11a
--- /dev/null
+++ b/test/CodeGen/2007-02-04-EmptyStruct.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -O3 -emit-llvm -o -
+// PR1175
+
+struct empty { };
+
+void foo(struct empty *p) {
+ p++;
+}
+
diff --git a/test/CodeGen/2007-02-07-AddrLabel.c b/test/CodeGen/2007-02-07-AddrLabel.c
new file mode 100644
index 000000000000..25eb89433679
--- /dev/null
+++ b/test/CodeGen/2007-02-07-AddrLabel.c
@@ -0,0 +1,10 @@
+// PR947
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+void foo() {
+ void *ptr;
+ label:
+ ptr = &&label;
+
+ goto *ptr;
+ }
diff --git a/test/CodeGen/2007-02-16-VoidPtrDiff.c b/test/CodeGen/2007-02-16-VoidPtrDiff.c
new file mode 100644
index 000000000000..c9f6714c253c
--- /dev/null
+++ b/test/CodeGen/2007-02-16-VoidPtrDiff.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+void foo(void *ptr, int test) {
+ (ptr - ((void *) test + 0x2000));
+}
diff --git a/test/CodeGen/2007-02-25-C-DotDotDot.c b/test/CodeGen/2007-02-25-C-DotDotDot.c
new file mode 100644
index 000000000000..7b2e418f4918
--- /dev/null
+++ b/test/CodeGen/2007-02-25-C-DotDotDot.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -O0 %s -emit-llvm -o - | FileCheck %s
+
+// Make sure the call to foo is compiled as:
+// call float @foo()
+// not
+// call float (...)* bitcast (float ()* @foo to float (...)*)( )
+
+static float foo() { return 0.0; }
+// CHECK: call float @foo
+float bar() { return foo()*10.0;}
diff --git a/test/CodeGen/2007-03-01-VarSizeArrayIdx.c b/test/CodeGen/2007-03-01-VarSizeArrayIdx.c
new file mode 100644
index 000000000000..7a9f89a66e26
--- /dev/null
+++ b/test/CodeGen/2007-03-01-VarSizeArrayIdx.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -O3 -emit-llvm -o - | grep mul
+// PR1233
+
+float foo(int w, float A[][w], int g, int h) {
+ return A[g][0];
+}
+
diff --git a/test/CodeGen/2007-03-05-DataLayout.c b/test/CodeGen/2007-03-05-DataLayout.c
new file mode 100644
index 000000000000..751962457379
--- /dev/null
+++ b/test/CodeGen/2007-03-05-DataLayout.c
@@ -0,0 +1,55 @@
+// Testcase for PR1242
+// RUN: %clang_cc1 -emit-llvm %s -o - | grep datalayout | \
+// RUN: not grep {"\[Ee\]-p:\[36\]\[24\]:\[36\]\[24\]"}
+// END.
+
+typedef __SIZE_TYPE__ size_t;
+void * malloc(size_t size);
+#define NDIM 3
+#define BODY 01
+typedef double vector[NDIM];
+typedef struct bnode* bodyptr;
+// { i16, double, [3 x double], i32, i32, [3 x double], [3 x double], [3 x
+// double], double, \2 *, \2 * }
+struct bnode {
+ short int type;
+ double mass;
+ vector pos;
+ int proc;
+ int new_proc;
+ vector vel;
+ vector acc;
+ vector new_acc;
+ double phi;
+ bodyptr next;
+ bodyptr proc_next;
+} body;
+
+#define Type(x) ((x)->type)
+#define Mass(x) ((x)->mass)
+#define Pos(x) ((x)->pos)
+#define Proc(x) ((x)->proc)
+#define New_Proc(x) ((x)->new_proc)
+#define Vel(x) ((x)->vel)
+#define Acc(x) ((x)->acc)
+#define New_Acc(x) ((x)->new_acc)
+#define Phi(x) ((x)->phi)
+#define Next(x) ((x)->next)
+#define Proc_Next(x) ((x)->proc_next)
+
+bodyptr ubody_alloc(int p)
+{
+ register bodyptr tmp;
+ tmp = (bodyptr)malloc(sizeof(body));
+
+ Type(tmp) = BODY;
+ Proc(tmp) = p;
+ Proc_Next(tmp) = NULL;
+ New_Proc(tmp) = p;
+ return tmp;
+}
+
+int main(int argc, char** argv) {
+ bodyptr b = ubody_alloc(17);
+ return 0;
+}
diff --git a/test/CodeGen/2007-03-26-BitfieldAfterZeroWidth.c b/test/CodeGen/2007-03-26-BitfieldAfterZeroWidth.c
new file mode 100644
index 000000000000..b4a42d989294
--- /dev/null
+++ b/test/CodeGen/2007-03-26-BitfieldAfterZeroWidth.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+struct W {};
+struct Y {
+ struct W w;
+ int i:1;
+} __attribute__ ((packed)) y;
diff --git a/test/CodeGen/2007-03-26-ZeroWidthBitfield.c b/test/CodeGen/2007-03-26-ZeroWidthBitfield.c
new file mode 100644
index 000000000000..0bf42ad4f954
--- /dev/null
+++ b/test/CodeGen/2007-03-26-ZeroWidthBitfield.c
@@ -0,0 +1,2 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+struct Z { int :0; } z;
diff --git a/test/CodeGen/2007-03-27-VarLengthArray.c b/test/CodeGen/2007-03-27-VarLengthArray.c
new file mode 100644
index 000000000000..ec11f55e6725
--- /dev/null
+++ b/test/CodeGen/2007-03-27-VarLengthArray.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: getelementptr inbounds i32* %{{vla|[0-9]}}
+extern void f(int *);
+int e(int m, int n) {
+ int x[n];
+ f(x);
+ return x[m];
+}
diff --git a/test/CodeGen/2007-04-05-PackedBitFields-2.c b/test/CodeGen/2007-04-05-PackedBitFields-2.c
new file mode 100644
index 000000000000..41e6b7def91e
--- /dev/null
+++ b/test/CodeGen/2007-04-05-PackedBitFields-2.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+# define pck __attribute__((packed))
+
+
+struct pck F {
+ unsigned long long i : 12,
+ j : 23,
+ k : 27,
+ l;
+};
+struct F f1;
+
+void foo() {
+ f1.l = 5;
+}
diff --git a/test/CodeGen/2007-04-05-PackedBitFields.c b/test/CodeGen/2007-04-05-PackedBitFields.c
new file mode 100644
index 000000000000..5c824a3e08f1
--- /dev/null
+++ b/test/CodeGen/2007-04-05-PackedBitFields.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+# define pck __attribute__((packed))
+
+
+struct pck E {
+ unsigned long long l,
+ i : 12,
+ j : 23,
+ k : 29; };
+
+struct E e1;
+
+void foo() {
+ e1.k = 5;
+}
diff --git a/test/CodeGen/2007-04-05-PackedStruct.c b/test/CodeGen/2007-04-05-PackedStruct.c
new file mode 100644
index 000000000000..1e9171e4235e
--- /dev/null
+++ b/test/CodeGen/2007-04-05-PackedStruct.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+#pragma pack(push, 2)
+
+enum {
+ tA = 0,
+ tB = 1
+};
+
+struct MyStruct {
+ unsigned long A;
+ char C;
+ void * B;
+};
+
+void bar(){
+struct MyStruct MS = { tB, 0 };
+}
diff --git a/test/CodeGen/2007-04-05-PadBeforeZeroLengthField.c b/test/CodeGen/2007-04-05-PadBeforeZeroLengthField.c
new file mode 100644
index 000000000000..f3005b5adaac
--- /dev/null
+++ b/test/CodeGen/2007-04-05-PadBeforeZeroLengthField.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+struct c__ { unsigned int type:4; };
+union A { struct c__ c; } __attribute__((aligned(8)));
+struct B {
+ unsigned int retainCount;
+ union A objects[];
+};
+void foo(union A * objects, struct B *array, unsigned long k)
+{ array->objects[k] = objects[k]; }
diff --git a/test/CodeGen/2007-04-05-UnPackedStruct.c b/test/CodeGen/2007-04-05-UnPackedStruct.c
new file mode 100644
index 000000000000..e7a8df623947
--- /dev/null
+++ b/test/CodeGen/2007-04-05-UnPackedStruct.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+
+enum {
+ tA = 0,
+ tB = 1
+};
+
+struct MyStruct {
+ unsigned long A;
+ void * B;
+};
+
+void bar(){
+struct MyStruct MS = { tB, 0 };
+}
diff --git a/test/CodeGen/2007-04-11-InlineAsmStruct.c b/test/CodeGen/2007-04-11-InlineAsmStruct.c
new file mode 100644
index 000000000000..d617feeed9f9
--- /dev/null
+++ b/test/CodeGen/2007-04-11-InlineAsmStruct.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+struct V { short X, Y; };
+int bar() {
+ struct V bar;
+ __asm__ volatile("foo %0\n" : "=r"(bar));
+ return bar.X;
+}
diff --git a/test/CodeGen/2007-04-11-InlineAsmUnion.c b/test/CodeGen/2007-04-11-InlineAsmUnion.c
new file mode 100644
index 000000000000..6d24d938abb3
--- /dev/null
+++ b/test/CodeGen/2007-04-11-InlineAsmUnion.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+union U { int x; float p; };
+void foo() {
+ union U bar;
+ __asm__ volatile("foo %0\n" : "=r"(bar));
+}
diff --git a/test/CodeGen/2007-04-11-PR1321.c b/test/CodeGen/2007-04-11-PR1321.c
new file mode 100644
index 000000000000..6207ecc1161f
--- /dev/null
+++ b/test/CodeGen/2007-04-11-PR1321.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -emit-llvm -o /dev/null
+
+struct X {
+ unsigned int e0 : 17;
+ unsigned int e1 : 17;
+ unsigned int e2 : 17;
+ unsigned int e3 : 17;
+ unsigned int e4 : 17;
+ unsigned int e5 : 17;
+ unsigned int e6 : 17;
+ unsigned int e7 : 17;
+} __attribute__((packed)) x;
diff --git a/test/CodeGen/2007-04-13-InlineAsmStruct2.c b/test/CodeGen/2007-04-13-InlineAsmStruct2.c
new file mode 100644
index 000000000000..c9a87ffd55fb
--- /dev/null
+++ b/test/CodeGen/2007-04-13-InlineAsmStruct2.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+struct V { short X, Y; };
+int bar() {
+ struct V bar;
+ // CHECK: call void asm
+ __asm__ volatile("foo %0\n" :: "r"(bar));
+ return bar.X;
+}
diff --git a/test/CodeGen/2007-04-13-InlineAsmUnion2.c b/test/CodeGen/2007-04-13-InlineAsmUnion2.c
new file mode 100644
index 000000000000..a8983b61d71f
--- /dev/null
+++ b/test/CodeGen/2007-04-13-InlineAsmUnion2.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+union U { int x; char* p; };
+void foo() {
+ union U bar;
+ // CHECK: call void asm
+ __asm__ volatile("foo %0\n" :: "r"(bar));
+}
diff --git a/test/CodeGen/2007-04-14-FNoBuiltin.c b/test/CodeGen/2007-04-14-FNoBuiltin.c
new file mode 100644
index 000000000000..a5fda6306f28
--- /dev/null
+++ b/test/CodeGen/2007-04-14-FNoBuiltin.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -emit-llvm %s -O2 -fno-builtin -o - | grep call.*printf
+// Check that -fno-builtin is honored.
+
+extern int printf(const char*, ...);
+void foo(const char *msg) {
+ printf("%s\n",msg);
+}
diff --git a/test/CodeGen/2007-04-17-ZeroSizeBitFields.c b/test/CodeGen/2007-04-17-ZeroSizeBitFields.c
new file mode 100644
index 000000000000..91b45828dbb6
--- /dev/null
+++ b/test/CodeGen/2007-04-17-ZeroSizeBitFields.c
@@ -0,0 +1,4 @@
+// PR 1332
+// RUN: %clang_cc1 %s -emit-llvm -o /dev/null
+
+struct Z { int a:1; int :0; int c:1; } z;
diff --git a/test/CodeGen/2007-04-24-VolatileStructCopy.c b/test/CodeGen/2007-04-24-VolatileStructCopy.c
new file mode 100644
index 000000000000..5eeecce99d29
--- /dev/null
+++ b/test/CodeGen/2007-04-24-VolatileStructCopy.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+// PR1352
+
+struct foo {
+ int x;
+};
+
+void copy(volatile struct foo *p, struct foo *q) {
+ // CHECK: call void @llvm.memcpy
+ *p = *q;
+}
diff --git a/test/CodeGen/2007-04-24-bit-not-expr.c b/test/CodeGen/2007-04-24-bit-not-expr.c
new file mode 100644
index 000000000000..9d99caffb536
--- /dev/null
+++ b/test/CodeGen/2007-04-24-bit-not-expr.c
@@ -0,0 +1,7 @@
+// PR 1346
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+extern bar(void *);
+
+void f(void *cd) {
+ bar(((void *)((unsigned long)(cd) ^ -1)));
+}
diff --git a/test/CodeGen/2007-04-24-str-const.c b/test/CodeGen/2007-04-24-str-const.c
new file mode 100644
index 000000000000..1d86d1c251d3
--- /dev/null
+++ b/test/CodeGen/2007-04-24-str-const.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+static char *str;
+
+static const struct {
+ const char *name;
+ unsigned type;
+} scan_special[] = {
+ {"shift", 1},
+ {0, 0}
+};
+
+static void
+sb(void)
+{
+ while (*str == ' ' || *str == '\t')
+ str++;
+}
diff --git a/test/CodeGen/2007-05-07-PaddingElements.c b/test/CodeGen/2007-05-07-PaddingElements.c
new file mode 100644
index 000000000000..574a37760a38
--- /dev/null
+++ b/test/CodeGen/2007-05-07-PaddingElements.c
@@ -0,0 +1,12 @@
+// PR 1278
+// RUN: %clang_cc1 %s -emit-llvm -O0 -o - | grep {struct.s} | not grep "4 x i8] zeroinitializer"
+// RUN: %clang_cc1 %s -emit-llvm -O0 -o - | not grep "i32 0, i32 2"
+struct s {
+ double d1;
+ int s1;
+};
+
+struct s foo(void) {
+ struct s S = {1.1, 2};
+ return S;
+}
diff --git a/test/CodeGen/2007-05-08-PCH.c b/test/CodeGen/2007-05-08-PCH.c
new file mode 100644
index 000000000000..c45d57c42f6f
--- /dev/null
+++ b/test/CodeGen/2007-05-08-PCH.c
@@ -0,0 +1,7 @@
+// PR 1400
+// RUN: %clang_cc1 -x c-header %s -o /dev/null
+
+int main() {
+ return 0;
+}
+
diff --git a/test/CodeGen/2007-05-11-str-const.c b/test/CodeGen/2007-05-11-str-const.c
new file mode 100644
index 000000000000..731496d34686
--- /dev/null
+++ b/test/CodeGen/2007-05-11-str-const.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -emit-llvm -g %s -o /dev/null
+
+static unsigned char out[]={0,1};
+static const unsigned char str1[]="1";
+
diff --git a/test/CodeGen/2007-05-15-PaddingElement.c b/test/CodeGen/2007-05-15-PaddingElement.c
new file mode 100644
index 000000000000..5aa4f2e091ce
--- /dev/null
+++ b/test/CodeGen/2007-05-15-PaddingElement.c
@@ -0,0 +1,23 @@
+// PR 1419
+
+// RUN: %clang_cc1 -O2 %s -emit-llvm -o - | grep "ret i32 1"
+struct A {
+ short x;
+ long long :0;
+};
+
+struct B {
+ char a;
+ char b;
+ unsigned char i;
+};
+
+union X { struct A a; struct B b; };
+
+int check(void) {
+ union X x, y;
+
+ y.b.i = 0xff;
+ x = y;
+ return (x.b.i == 0xff);
+}
diff --git a/test/CodeGen/2007-05-16-EmptyStruct.c b/test/CodeGen/2007-05-16-EmptyStruct.c
new file mode 100644
index 000000000000..14aaff007ebd
--- /dev/null
+++ b/test/CodeGen/2007-05-16-EmptyStruct.c
@@ -0,0 +1,5 @@
+// PR 1417
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: global %struct.anon* null
+struct { } *X;
diff --git a/test/CodeGen/2007-05-29-UnionCopy.c b/test/CodeGen/2007-05-29-UnionCopy.c
new file mode 100644
index 000000000000..9f71687b40a5
--- /dev/null
+++ b/test/CodeGen/2007-05-29-UnionCopy.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | grep memcpy
+// PR1421
+
+struct A {
+ char c;
+ int i;
+};
+
+struct B {
+ int c;
+ unsigned char x;
+};
+
+union U { struct A a; struct B b; };
+
+void check(union U *u, union U *v) {
+ *u = *v;
+}
diff --git a/test/CodeGen/2007-06-05-NoInlineAttribute.c b/test/CodeGen/2007-06-05-NoInlineAttribute.c
new file mode 100644
index 000000000000..26aad88e8146
--- /dev/null
+++ b/test/CodeGen/2007-06-05-NoInlineAttribute.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -O2 -emit-llvm %s -o - | grep call
+
+static int bar(int x, int y) __attribute__((noinline));
+
+static int bar(int x, int y)
+{
+ return x + y;
+}
+
+int foo(int a, int b) {
+ return bar(b, a);
+}
+
diff --git a/test/CodeGen/2007-06-15-AnnotateAttribute.c b/test/CodeGen/2007-06-15-AnnotateAttribute.c
new file mode 100644
index 000000000000..de34866783ba
--- /dev/null
+++ b/test/CodeGen/2007-06-15-AnnotateAttribute.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | grep llvm.global.annotations
+// RUN: %clang_cc1 -emit-llvm %s -o - | grep llvm.var.annotation | count 3
+
+/* Global variable with attribute */
+int X __attribute__((annotate("GlobalValAnnotation")));
+
+/* Function with attribute */
+int foo(int y) __attribute__((annotate("GlobalValAnnotation")))
+ __attribute__((noinline));
+
+int foo(int y __attribute__((annotate("LocalValAnnotation")))) {
+ int x __attribute__((annotate("LocalValAnnotation")));
+ x = 34;
+ return y + x;
+}
+
+int main() {
+ static int a __attribute__((annotate("GlobalValAnnotation")));
+ a = foo(2);
+ return 0;
+}
diff --git a/test/CodeGen/2007-06-18-SextAttrAggregate.c b/test/CodeGen/2007-06-18-SextAttrAggregate.c
new file mode 100644
index 000000000000..27ae6a9b76a6
--- /dev/null
+++ b/test/CodeGen/2007-06-18-SextAttrAggregate.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -o - -emit-llvm | FileCheck %s
+// PR1513
+
+struct s{
+long a;
+long b;
+};
+
+void f(struct s a, char *b, signed char C) {
+ // CHECK: i8 signext
+
+}
diff --git a/test/CodeGen/2007-07-29-RestrictPtrArg.c b/test/CodeGen/2007-07-29-RestrictPtrArg.c
new file mode 100644
index 000000000000..b6d61a714a69
--- /dev/null
+++ b/test/CodeGen/2007-07-29-RestrictPtrArg.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | grep noalias
+
+void foo(int * __restrict myptr1, int * myptr2) {
+ myptr1[0] = 0;
+ myptr2[0] = 0;
+}
diff --git a/test/CodeGen/2007-08-01-LoadStoreAlign.c b/test/CodeGen/2007-08-01-LoadStoreAlign.c
new file mode 100644
index 000000000000..87cf163d4d9b
--- /dev/null
+++ b/test/CodeGen/2007-08-01-LoadStoreAlign.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+struct p {
+ char a;
+ int b;
+} __attribute__ ((packed));
+
+struct p t = { 1, 10 };
+struct p u;
+
+int main () {
+ // CHECK: align 1
+ // CHECK: align 1
+ int tmp = t.b;
+ u.b = tmp;
+ return tmp;
+
+}
diff --git a/test/CodeGen/2007-08-21-ComplexCst.c b/test/CodeGen/2007-08-21-ComplexCst.c
new file mode 100644
index 000000000000..cd9ceb198baa
--- /dev/null
+++ b/test/CodeGen/2007-08-21-ComplexCst.c
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -O2 -emit-llvm %s -o /dev/null
+void f(_Complex float z);
+void g() { f(1.0i); }
diff --git a/test/CodeGen/2007-08-22-CTTZ.c b/test/CodeGen/2007-08-22-CTTZ.c
new file mode 100644
index 000000000000..9067c5a767e3
--- /dev/null
+++ b/test/CodeGen/2007-08-22-CTTZ.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+int bork(unsigned long long x) {
+ // CHECK: llvm.cttz.i64
+ // CHECK: llvm.cttz.i64
+ // CHECK-NOT: lshr
+ return __builtin_ctzll(x);
+}
diff --git a/test/CodeGen/2007-09-05-ConstCtor.c b/test/CodeGen/2007-09-05-ConstCtor.c
new file mode 100644
index 000000000000..138b81887560
--- /dev/null
+++ b/test/CodeGen/2007-09-05-ConstCtor.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -Os -emit-llvm %s -o /dev/null
+// PR1641
+
+struct A {
+ unsigned long l;
+};
+
+void bar(struct A *a);
+
+void bork() {
+ const unsigned long vcgt = 1234;
+ struct A a = { vcgt };
+ bar(&a);
+}
diff --git a/test/CodeGen/2007-09-12-PragmaPack.c b/test/CodeGen/2007-09-12-PragmaPack.c
new file mode 100644
index 000000000000..71c7537e9dca
--- /dev/null
+++ b/test/CodeGen/2007-09-12-PragmaPack.c
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+
+#pragma pack(push, 1)
+typedef struct
+{
+ uint32_t a;
+} foo;
+
+typedef struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t build;
+} VERSION;
+
+typedef struct {
+ uint8_t a[5];
+ VERSION version;
+ uint8_t b;
+ foo d;
+ uint32_t guard;
+} bar;
+#pragma pack(pop)
+
+
+unsigned barsize(void) {
+ // CHECK: ret i32 18
+ return sizeof(bar);
+}
diff --git a/test/CodeGen/2007-09-14-NegatePointer.c b/test/CodeGen/2007-09-14-NegatePointer.c
new file mode 100644
index 000000000000..52367e6c667b
--- /dev/null
+++ b/test/CodeGen/2007-09-14-NegatePointer.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+// PR1662
+
+int foo(unsigned char *test) {
+ return 0U - (unsigned int )test;
+}
+
diff --git a/test/CodeGen/2007-09-17-WeakRef.c b/test/CodeGen/2007-09-17-WeakRef.c
new file mode 100644
index 000000000000..3047b7f954ef
--- /dev/null
+++ b/test/CodeGen/2007-09-17-WeakRef.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -O1 -emit-llvm %s -o - | grep icmp
+// PR1678
+
+extern void B (void);
+static __typeof(B) A __attribute__ ((__weakref__("B")));
+int active (void)
+{
+ static void *const p = __extension__ (void *) &A;
+ return p != 0;
+}
diff --git a/test/CodeGen/2007-09-26-Alignment.c b/test/CodeGen/2007-09-26-Alignment.c
new file mode 100644
index 000000000000..8ab130b0a708
--- /dev/null
+++ b/test/CodeGen/2007-09-26-Alignment.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+extern p(int *);
+int q(void) {
+ // CHECK: alloca i32, align 16
+ int x __attribute__ ((aligned (16)));
+ p(&x);
+ return x;
+}
diff --git a/test/CodeGen/2007-09-27-ComplexIntCompare.c b/test/CodeGen/2007-09-27-ComplexIntCompare.c
new file mode 100644
index 000000000000..d07aa0cf7c36
--- /dev/null
+++ b/test/CodeGen/2007-09-27-ComplexIntCompare.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+// PR1708
+
+void __attribute__((noreturn)) abort(void);
+
+struct s { _Complex unsigned short x; };
+struct s gs = { 100 + 200i };
+struct s __attribute__((noinline)) foo (void) { return gs; }
+
+int main ()
+{
+ if (foo ().x != gs.x)
+ abort ();
+ exit (0);
+}
diff --git a/test/CodeGen/2007-09-28-PackedUnionMember.c b/test/CodeGen/2007-09-28-PackedUnionMember.c
new file mode 100644
index 000000000000..943480e4d882
--- /dev/null
+++ b/test/CodeGen/2007-09-28-PackedUnionMember.c
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+#pragma pack(push, 2)
+struct H {
+ unsigned long f1;
+ unsigned long f2;
+ union {
+ struct opaque1 *f3;
+ struct opaque2 *f4;
+ struct {
+ struct opaque3 *f5;
+ unsigned short f6;
+ } f7;
+ } f8;
+};
+#pragma pack(pop)
+
+struct E {
+ unsigned long f1;
+ unsigned long f2;
+};
+
+typedef long (*FuncPtr) ();
+
+extern long bork(FuncPtr handler, const struct E *list);
+
+static long hndlr()
+{
+ struct H cmd = { 4, 412 };
+ return 0;
+}
+void foo(void *inWindow) {
+ static const struct E events[] = {
+ { 123124, 1 }
+ };
+ bork(hndlr, events);
+}
+
diff --git a/test/CodeGen/2007-10-02-VolatileArray.c b/test/CodeGen/2007-10-02-VolatileArray.c
new file mode 100644
index 000000000000..b1dcb7ea7d0b
--- /dev/null
+++ b/test/CodeGen/2007-10-02-VolatileArray.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | grep volatile
+// PR1647
+
+void foo(volatile int *p)
+{
+p[0] = 0;
+}
diff --git a/test/CodeGen/2007-10-15-VoidPtr.c b/test/CodeGen/2007-10-15-VoidPtr.c
new file mode 100644
index 000000000000..0bbff3da318d
--- /dev/null
+++ b/test/CodeGen/2007-10-15-VoidPtr.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+void bork(void **data) {
+ (*(unsigned short *) (&(data[37])[927]) = 0);
+}
diff --git a/test/CodeGen/2007-10-30-Volatile.c b/test/CodeGen/2007-10-30-Volatile.c
new file mode 100644
index 000000000000..17aac1a987c2
--- /dev/null
+++ b/test/CodeGen/2007-10-30-Volatile.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null -Wall -Werror
+void bork() {
+ char * volatile p = 0;
+ volatile int cc = 0;
+ p += cc;
+}
diff --git a/test/CodeGen/2007-11-07-AlignedMemcpy.c b/test/CodeGen/2007-11-07-AlignedMemcpy.c
new file mode 100644
index 000000000000..829b60cb0ef0
--- /dev/null
+++ b/test/CodeGen/2007-11-07-AlignedMemcpy.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+void bork() {
+ int Qux[33] = {0};
+}
diff --git a/test/CodeGen/2007-11-07-CopyAggregateAlign.c b/test/CodeGen/2007-11-07-CopyAggregateAlign.c
new file mode 100644
index 000000000000..08d97702e69a
--- /dev/null
+++ b/test/CodeGen/2007-11-07-CopyAggregateAlign.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+struct A { char s, t, u, v; short a; };
+// CHECK: %a = alloca %struct.A, align 2
+// CHECK: %b = alloca %struct.A, align 2
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.{{.*}}, i32 2, i1 false)
+
+void q() { struct A a, b; a = b; }
diff --git a/test/CodeGen/2007-11-07-ZeroAggregateAlign.c b/test/CodeGen/2007-11-07-ZeroAggregateAlign.c
new file mode 100644
index 000000000000..b059607ba586
--- /dev/null
+++ b/test/CodeGen/2007-11-07-ZeroAggregateAlign.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+struct A { short s; short t; int i; };
+// CHECK: %a = alloca %struct.A, align 4
+// CHECK: call void @llvm.memset.p0i8.{{.*}}i32 4, i1 false)
+void q() { struct A a = {0}; }
diff --git a/test/CodeGen/2007-11-28-GlobalInitializer.c b/test/CodeGen/2007-11-28-GlobalInitializer.c
new file mode 100644
index 000000000000..a79ccddbe9e4
--- /dev/null
+++ b/test/CodeGen/2007-11-28-GlobalInitializer.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+// PR1744
+typedef struct foo { int x; char *p; } FOO;
+extern FOO yy[];
+
+int *y = &((yy + 1)->x);
+void *z = &((yy + 1)->x);
+
diff --git a/test/CodeGen/2007-12-16-AsmNoUnwind.c b/test/CodeGen/2007-12-16-AsmNoUnwind.c
new file mode 100644
index 000000000000..de078a28dd48
--- /dev/null
+++ b/test/CodeGen/2007-12-16-AsmNoUnwind.c
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | grep nounwind
+
+void bar() { asm (""); }
diff --git a/test/CodeGen/2008-01-04-WideBitfield.c b/test/CodeGen/2008-01-04-WideBitfield.c
new file mode 100644
index 000000000000..e1c7a38a12e6
--- /dev/null
+++ b/test/CodeGen/2008-01-04-WideBitfield.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s
+// PR1386
+typedef unsigned long long uint64_t;
+struct X {
+ unsigned char pad : 4;
+ uint64_t a : 64;
+} __attribute__((packed)) x;
+
+uint64_t f(void)
+{
+ return x.a;
+}
diff --git a/test/CodeGen/2008-01-07-UnusualIntSize.c b/test/CodeGen/2008-01-07-UnusualIntSize.c
new file mode 100644
index 000000000000..bf0ca5575a6a
--- /dev/null
+++ b/test/CodeGen/2008-01-07-UnusualIntSize.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// PR1721
+
+struct s {
+ unsigned long long u33: 33;
+} a, b;
+
+// 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-NOT: and i64 [[TMP1]], 8589934591
+ // CHECK: and i64 %{{[0-9]}}, 8589934591
+ return a.u33 + b.u33 != 0;
+}
diff --git a/test/CodeGen/2008-01-11-ChainConsistency.c b/test/CodeGen/2008-01-11-ChainConsistency.c
new file mode 100644
index 000000000000..9ae021f6da58
--- /dev/null
+++ b/test/CodeGen/2008-01-11-ChainConsistency.c
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -fnested-functions | not grep nest
+
+void n1(void) { void a(void) { a(); } a(); }
diff --git a/test/CodeGen/2008-01-21-PackedBitFields.c b/test/CodeGen/2008-01-21-PackedBitFields.c
new file mode 100644
index 000000000000..a649475e8df2
--- /dev/null
+++ b/test/CodeGen/2008-01-21-PackedBitFields.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+typedef double Al1Double __attribute__((aligned(1)));
+struct x { int a:23; Al1Double v; };
+struct x X = { 5, 3.0 };
+double foo() { return X.v; }
+
diff --git a/test/CodeGen/2008-01-21-PackedStructField.c b/test/CodeGen/2008-01-21-PackedStructField.c
new file mode 100644
index 000000000000..aa1bee4abbe1
--- /dev/null
+++ b/test/CodeGen/2008-01-21-PackedStructField.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+struct X { long double b; unsigned char c; double __attribute__((packed)) d; };
+struct X x = { 3.0L, 5, 3.0 };
+
+
+struct S2504 {
+ int e:17;
+ __attribute__((packed)) unsigned long long int f;
+} ;
+int fails;
+ extern struct S2504 s2504;
+void check2504va (int z) {
+ struct S2504 arg, *p;
+ long long int i = 0;
+ arg.f = i;
+}
+
diff --git a/test/CodeGen/2008-01-24-StructAlignAndBitFields.c b/test/CodeGen/2008-01-24-StructAlignAndBitFields.c
new file mode 100644
index 000000000000..eae48b3cad90
--- /dev/null
+++ b/test/CodeGen/2008-01-24-StructAlignAndBitFields.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+struct U { char a; short b; int c:25; char d; } u;
+
diff --git a/test/CodeGen/2008-01-25-ByValReadNone.c b/test/CodeGen/2008-01-25-ByValReadNone.c
new file mode 100644
index 000000000000..06ad1eef00f1
--- /dev/null
+++ b/test/CodeGen/2008-01-25-ByValReadNone.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | not grep readonly
+// RUN: %clang_cc1 -emit-llvm -o - %s | not grep readnone
+
+// XFAIL: arm
+
+// The struct being passed byval means that we cannot mark the
+// function readnone. Readnone would allow stores to the arg to
+// be deleted in the caller. We also don't allow readonly since
+// the callee might write to the byval parameter. The inliner
+// would have to assume the worse and introduce an explicit
+// temporary when inlining such a function, which is costly for
+// the common case in which the byval argument is not written.
+struct S { int A[1000]; };
+int __attribute__ ((const)) f(struct S x) { x.A[1] = 0; return x.A[0]; }
+int g(struct S x) __attribute__ ((pure));
+int h(struct S x) { return g(x); }
diff --git a/test/CodeGen/2008-01-25-ZeroSizedAggregate.c b/test/CodeGen/2008-01-25-ZeroSizedAggregate.c
new file mode 100644
index 000000000000..d9059856254f
--- /dev/null
+++ b/test/CodeGen/2008-01-25-ZeroSizedAggregate.c
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+// Aggregates of size zero should be dropped from argument list.
+typedef long int Tlong;
+struct S2411 {
+ __attribute__((aligned)) Tlong:0;
+};
+
+extern struct S2411 a2411[5];
+extern void checkx2411(struct S2411);
+void test2411(void) {
+ checkx2411(a2411[0]);
+}
+
+// Proper handling of zero sized fields during type conversion.
+typedef unsigned long long int Tal2ullong __attribute__((aligned(2)));
+struct S2525 {
+ Tal2ullong: 0;
+ struct {
+ } e;
+};
+struct S2525 s2525;
+
+struct {
+ signed char f;
+ char :0;
+ struct{}h;
+ char * i[5];
+} data;
+
+// Taking address of a zero sized field.
+struct Z {};
+struct Y {
+ int i;
+ struct Z z;
+};
+void *f(struct Y *y) {
+ return &y->z;
+}
diff --git a/test/CodeGen/2008-01-28-PragmaMark.c b/test/CodeGen/2008-01-28-PragmaMark.c
new file mode 100644
index 000000000000..399af958fcf1
--- /dev/null
+++ b/test/CodeGen/2008-01-28-PragmaMark.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -Werror -emit-llvm %s -o /dev/null
+#pragma mark LLVM's world
+#ifdef DO_ERROR
+#error LLVM's world
+#endif
+int i;
diff --git a/test/CodeGen/2008-01-28-UnionSize.c b/test/CodeGen/2008-01-28-UnionSize.c
new file mode 100644
index 000000000000..14f363dbc05c
--- /dev/null
+++ b/test/CodeGen/2008-01-28-UnionSize.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+// PR 1861
+
+typedef unsigned char __u8;
+typedef unsigned int __u32;
+typedef unsigned short u16;
+typedef __u32 __le32;
+struct bcm43xx_plcp_hdr6 {
+ union {
+ __le32 data;
+ __u8 raw[6];
+ }
+ __attribute__((__packed__));
+}
+ __attribute__((__packed__));
+struct bcm43xx_txhdr {
+ union {
+ struct {
+ struct bcm43xx_plcp_hdr6 plcp;
+ };
+ };
+}
+ __attribute__((__packed__));
+static void bcm43xx_generate_rts(struct bcm43xx_txhdr *txhdr ) { }
diff --git a/test/CodeGen/2008-03-03-CtorAttrType.c b/test/CodeGen/2008-03-03-CtorAttrType.c
new file mode 100644
index 000000000000..dbd7bc0a7270
--- /dev/null
+++ b/test/CodeGen/2008-03-03-CtorAttrType.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | grep llvm.global_ctors
+int __attribute__((constructor)) foo(void) {
+ return 0;
+}
+void __attribute__((constructor)) bar(void) {}
+
diff --git a/test/CodeGen/2008-03-05-syncPtr.c b/test/CodeGen/2008-03-05-syncPtr.c
new file mode 100644
index 000000000000..784295ce6890
--- /dev/null
+++ b/test/CodeGen/2008-03-05-syncPtr.c
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+int* foo(int** a, int* b, int* c) {
+return __sync_val_compare_and_swap (a, b, c);
+}
+// CHECK: define i32* @foo
+// CHECK: cmpxchg
+
+int foo2(int** a, int* b, int* c) {
+return __sync_bool_compare_and_swap (a, b, c);
+}
+// CHECK: define i32 @foo2
+// CHECK: cmpxchg
+
+int* foo3(int** a, int b) {
+ return __sync_fetch_and_add (a, b);
+}
+// CHECK: define i32* @foo3
+// CHECK: atomicrmw add
+
+
+int* foo4(int** a, int b) {
+ return __sync_fetch_and_sub (a, b);
+}
+// CHECK: define i32* @foo4
+// CHECK: atomicrmw sub
+
+
+int* foo5(int** a, int* b) {
+ return __sync_lock_test_and_set (a, b);
+}
+// CHECK: define i32* @foo5
+// CHECK: atomicrmw xchg
+
+
+int* foo6(int** a, int*** b) {
+ return __sync_lock_test_and_set (a, b);
+}
+// CHECK: define i32* @foo6
+// CHECK: atomicrmw xchg
diff --git a/test/CodeGen/2008-03-24-BitField-And-Alloca.c b/test/CodeGen/2008-03-24-BitField-And-Alloca.c
new file mode 100644
index 000000000000..cb80d76e0596
--- /dev/null
+++ b/test/CodeGen/2008-03-24-BitField-And-Alloca.c
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -O2 -emit-llvm %s -o - | not grep alloca
+// RUN: %clang_cc1 -m32 -O2 -emit-llvm %s -o - | not grep {store }
+
+enum {
+ PP_C,
+ PP_D,
+ PP_R,
+ PP_2D,
+ PP_1D,
+ PP_SR,
+ PP_S2D,
+ PP_S1D,
+ PP_SC
+};
+
+enum {
+ G_VP,
+ G_FP,
+ G_VS,
+ G_GS,
+ G_FS
+};
+
+enum {
+ G_NONE,
+ G_B,
+ G_R
+};
+
+typedef union _Key {
+ struct {
+ unsigned int count : 2;
+ unsigned int Aconst : 1;
+ unsigned int Bconst : 1;
+ unsigned int Cconst : 1;
+ unsigned int Xused : 1;
+ unsigned int Yused : 1;
+ unsigned int Zused : 1;
+ unsigned int Wused : 1;
+ unsigned int ttype : 3;
+ unsigned int scalar : 1;
+ unsigned int AType : 4;
+ unsigned int BType : 4;
+ unsigned int CType : 4;
+ unsigned int RType : 4;
+ unsigned int Size : 2;
+ unsigned int prec : 1;
+
+ unsigned int ASize : 2;
+ unsigned int BSize : 2;
+ unsigned int CSize : 2;
+ unsigned int tTex : 4;
+ unsigned int proj : 1;
+ unsigned int lod : 2;
+ unsigned int dvts : 1;
+ unsigned int uipad : 18;
+ } key_io;
+ struct {
+ unsigned int key0;
+ unsigned int key1;
+ } key;
+ unsigned long long lkey;
+} Key;
+
+static void foo(const Key iospec, int* ret)
+{
+ *ret=0;
+ if(((iospec.key_io.lod == G_B) &&
+ (iospec.key_io.ttype != G_VS) &&
+ (iospec.key_io.ttype != G_GS) &&
+ (iospec.key_io.ttype != G_FS)) ||
+
+ (((iospec.key_io.tTex == PP_C) ||
+ (iospec.key_io.tTex == PP_SC)) &&
+ ((iospec.key_io.tTex == PP_SR) ||
+ (iospec.key_io.tTex == PP_S2D) ||
+ (iospec.key_io.tTex == PP_S1D) ||
+ (iospec.key_io.tTex == PP_SC))))
+ *ret=1;
+}
+
+
+extern int bar(unsigned long long key_token2)
+{
+ int ret;
+ __attribute__ ((unused)) Key iospec = (Key) key_token2;
+ foo(iospec, &ret);
+ return ret;
+}
diff --git a/test/CodeGen/2008-03-26-PackedBitFields.c b/test/CodeGen/2008-03-26-PackedBitFields.c
new file mode 100644
index 000000000000..72e5cb17de2e
--- /dev/null
+++ b/test/CodeGen/2008-03-26-PackedBitFields.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+
+struct S1757 {
+ long double c;
+ long int __attribute__((packed)) e:28;
+} x;
diff --git a/test/CodeGen/2008-04-08-NoExceptions.c b/test/CodeGen/2008-04-08-NoExceptions.c
new file mode 100644
index 000000000000..6d5d20ff8541
--- /dev/null
+++ b/test/CodeGen/2008-04-08-NoExceptions.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+void f(void);
+void g(void) {
+ // CHECK: define void @g() nounwind
+ // CHECK-NOT: call void @f() nounwind
+ f();
+}
+
+// CHECK-NOT: declare void @f() nounwind
diff --git a/test/CodeGen/2008-05-06-CFECrash.c b/test/CodeGen/2008-05-06-CFECrash.c
new file mode 100644
index 000000000000..11775673a7cc
--- /dev/null
+++ b/test/CodeGen/2008-05-06-CFECrash.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -emit-llvm -O2 %s -o /dev/null
+// PR2292.
+__inline__ __attribute__ ((__pure__)) int g (void) {}
+void f (int k) { k = g (); }
diff --git a/test/CodeGen/2008-05-12-TempUsedBeforeDef.c b/test/CodeGen/2008-05-12-TempUsedBeforeDef.c
new file mode 100644
index 000000000000..bc2886effc20
--- /dev/null
+++ b/test/CodeGen/2008-05-12-TempUsedBeforeDef.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -w -emit-llvm -o /dev/null %s
+// PR2264.
+unsigned foo = 8L;
+unsigned bar = 0L;
+volatile unsigned char baz = 6L;
+int test() {
+ char qux = 1L;
+ for (; baz >= -29; baz--)
+ bork(bar && foo, qux);
+}
diff --git a/test/CodeGen/2008-05-19-AlwaysInline.c b/test/CodeGen/2008-05-19-AlwaysInline.c
new file mode 100644
index 000000000000..73a7691aed76
--- /dev/null
+++ b/test/CodeGen/2008-05-19-AlwaysInline.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -emit-llvm -fno-unit-at-a-time -O0 -o - | not grep sabrina
+// RUN: %clang_cc1 %s -emit-llvm -funit-at-a-time -O0 -o - | not grep sabrina
+
+static inline int sabrina (void) __attribute__((always_inline));
+static inline int sabrina (void)
+{
+ return 13;
+}
+int bar (void)
+{
+ return sabrina () + 68;
+}
diff --git a/test/CodeGen/2008-08-07-AlignPadding1.c b/test/CodeGen/2008-08-07-AlignPadding1.c
new file mode 100644
index 000000000000..2bb2e61be0db
--- /dev/null
+++ b/test/CodeGen/2008-08-07-AlignPadding1.c
@@ -0,0 +1,32 @@
+/* RUN: %clang_cc1 %s -emit-llvm -triple x86_64-apple-darwin -o - | FileCheck %s
+
+The FE must generate padding here both at the end of each PyG_Head and
+between array elements. Reduced from Python. */
+
+typedef union _gc_head {
+ struct {
+ union _gc_head *gc_next;
+ union _gc_head *gc_prev;
+ long gc_refs;
+ } gc;
+ int dummy __attribute__((aligned(16)));
+} PyGC_Head;
+
+struct gc_generation {
+ PyGC_Head head;
+ int threshold;
+ int count;
+};
+
+#define GEN_HEAD(n) (&generations[n].head)
+
+// The idea is that there are 6 undefs in this structure initializer to cover
+// the padding between elements.
+// CHECK: @generations = global [3 x %struct.gc_generation] [%struct.gc_generation { %union._gc_head { %struct.anon { %union._gc_head* getelementptr inbounds ([3 x %struct.gc_generation]* @generations, i32 0, i32 0, i32 0), %union._gc_head* getelementptr inbounds ([3 x %struct.gc_generation]* @generations, i32 0, i32 0, i32 0), i64 0 }, [8 x i8] undef }, i32 700, i32 0, [8 x i8] undef }, %struct.gc_generation { %union._gc_head { %struct.anon { %union._gc_head* bitcast (i8* getelementptr (i8* bitcast ([3 x %struct.gc_generation]* @generations to i8*), i64 48) to %union._gc_head*), %union._gc_head* bitcast (i8* getelementptr (i8* bitcast ([3 x %struct.gc_generation]* @generations to i8*), i64 48) to %union._gc_head*), i64 0 }, [8 x i8] undef }, i32 10, i32 0, [8 x i8] undef }, %struct.gc_generation { %union._gc_head { %struct.anon { %union._gc_head* bitcast (i8* getelementptr (i8* bitcast ([3 x %struct.gc_generation]* @generations to i8*), i64 96) to %union._gc_head*), %union._gc_head* bitcast (i8* getelementptr (i8* bitcast ([3 x %struct.gc_generation]* @generations to i8*), i64 96) to %union._gc_head*), i64 0 }, [8 x i8] undef }, i32 10, i32 0, [8 x i8] undef }]
+/* linked lists of container objects */
+struct gc_generation generations[3] = {
+ /* PyGC_Head, threshold, count */
+ {{{GEN_HEAD(0), GEN_HEAD(0), 0}}, 700, 0},
+ {{{GEN_HEAD(1), GEN_HEAD(1), 0}}, 10, 0},
+ {{{GEN_HEAD(2), GEN_HEAD(2), 0}}, 10, 0},
+};
diff --git a/test/CodeGen/2008-08-07-AlignPadding2.c b/test/CodeGen/2008-08-07-AlignPadding2.c
new file mode 100644
index 000000000000..ecf28dd72de0
--- /dev/null
+++ b/test/CodeGen/2008-08-07-AlignPadding2.c
@@ -0,0 +1,18 @@
+/* RUN: %clang_cc1 %s -emit-llvm -o - -O0 | grep zeroinitializer | count 1
+
+The FE must not generate padding here between array elements. PR 2533. */
+
+typedef struct {
+ const char *name;
+ int flags;
+ union {
+ int x;
+ } u;
+} OptionDef;
+
+const OptionDef options[] = {
+ /* main options */
+ { "a", 0, {3} },
+ { "b", 0, {4} },
+ { 0, },
+};
diff --git a/test/CodeGen/2008-08-07-GEPIntToPtr.c b/test/CodeGen/2008-08-07-GEPIntToPtr.c
new file mode 100644
index 000000000000..6892be033a98
--- /dev/null
+++ b/test/CodeGen/2008-08-07-GEPIntToPtr.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+// PR2603
+
+struct A {
+ char num_fields;
+};
+
+struct B {
+ char a, b[1];
+};
+
+const struct A Foo = {
+ // CHECK: i8 1
+ (char *)(&( (struct B *)(16) )->b[0]) - (char *)(16)
+};
diff --git a/test/CodeGen/2008-09-03-WeakAlias.c b/test/CodeGen/2008-09-03-WeakAlias.c
new file mode 100644
index 000000000000..4712a0138cb6
--- /dev/null
+++ b/test/CodeGen/2008-09-03-WeakAlias.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -emit-llvm -O1 -o - %s | grep icmp
+// PR1678
+extern void B (void);
+static __typeof(B) A __attribute__ ((__weakref__("B")));
+int active (void)
+{
+ static void *const p = __extension__ (void *) &A;
+ return p != 0;
+}
diff --git a/test/CodeGen/2008-10-13-FrontendCrash.c b/test/CodeGen/2008-10-13-FrontendCrash.c
new file mode 100644
index 000000000000..cdd122970583
--- /dev/null
+++ b/test/CodeGen/2008-10-13-FrontendCrash.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+// PR2797
+
+unsigned int
+func_48 (signed char p_49)
+{
+ signed char l_340;
+ func_44 (1&((1 ^ 1 == (lshift_u_s (1)) != (l_340 < 1)) & 1L));
+}
diff --git a/test/CodeGen/2008-10-30-ZeroPlacement.c b/test/CodeGen/2008-10-30-ZeroPlacement.c
new file mode 100644
index 000000000000..f3806d499d52
--- /dev/null
+++ b/test/CodeGen/2008-10-30-ZeroPlacement.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+// PR2987
+struct S2045
+{
+ unsigned short int a;
+ union { } b;
+ union __attribute__ ((aligned (4))) { } c[0];
+};
+struct S2045 s2045;
diff --git a/test/CodeGen/2008-11-02-WeakAlias.c b/test/CodeGen/2008-11-02-WeakAlias.c
new file mode 100644
index 000000000000..63fd4e15eac9
--- /dev/null
+++ b/test/CodeGen/2008-11-02-WeakAlias.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple=i686-pc-linux-gnu -emit-llvm -o - %s | FileCheck %s
+// PR2691
+
+// CHECK: weak
+void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ")));
+void native_init_IRQ(void) {}
diff --git a/test/CodeGen/2008-11-08-InstCombineSelect.c b/test/CodeGen/2008-11-08-InstCombineSelect.c
new file mode 100644
index 000000000000..3f4428e572ee
--- /dev/null
+++ b/test/CodeGen/2008-11-08-InstCombineSelect.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 %s -emit-llvm -O2 -o -
+// PR3028
+
+int g_187;
+int g_204;
+int g_434;
+
+int func_89 (void)
+{
+ return 1;
+}
+
+void func_20 (int p_22)
+{
+ if (1 & p_22 | g_204 & (1 < g_187) - func_89 ())
+ g_434 = 1;
+}
diff --git a/test/CodeGen/2008-12-23-AsmIntPointerTie.c b/test/CodeGen/2008-12-23-AsmIntPointerTie.c
new file mode 100644
index 000000000000..df646b7801f7
--- /dev/null
+++ b/test/CodeGen/2008-12-23-AsmIntPointerTie.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -emit-llvm -O1 -o -
+
+typedef long intptr_t;
+int test(void *b) {
+ intptr_t a;
+ __asm__ __volatile__ ("%0 %1 " : "=r" (a): "0" (b));
+ return a;
+}
diff --git a/test/CodeGen/2009-01-05-BlockInlining.c b/test/CodeGen/2009-01-05-BlockInlining.c
new file mode 100644
index 000000000000..2ae9b70bb8fd
--- /dev/null
+++ b/test/CodeGen/2009-01-05-BlockInlining.c
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 %s -emit-llvm -fblocks -o - | FileCheck %s
+// rdar://5865221
+
+// These will be inlined by the optimizers provided the block descriptors
+// and block literals are internal constants.
+// CHECK: @__block_descriptor_tmp = internal constant
+// CHECK: @__block_literal_global = internal constant
+// CHECK: @__block_descriptor_tmp1 = internal constant
+// CHECK: @__block_literal_global2 = internal constant
+static int fun(int x) {
+ return x+1;
+}
+
+static int block(int x) {
+ return (^(int x){return x+1;})(x);
+}
+
+static void print(int result) {
+ printf("%d\n", result);
+}
+
+int main (int argc, const char * argv[]) {
+ int x = argc-1;
+ print(fun(x));
+ print(block(x));
+ int (^block_inline)(int) = ^(int x){return x+1;};
+ print(block_inline(x));
+ return 0;
+}
diff --git a/test/CodeGen/2009-01-21-InvalidIterator.c b/test/CodeGen/2009-01-21-InvalidIterator.c
new file mode 100644
index 000000000000..f857b4d8bd00
--- /dev/null
+++ b/test/CodeGen/2009-01-21-InvalidIterator.c
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 %s -emit-llvm -g -o /dev/null
+
+typedef long unsigned int size_t;
+typedef unsigned short int uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long int uint64_t;
+typedef uint16_t Elf64_Half;
+typedef uint32_t Elf64_Word;
+typedef uint64_t Elf64_Xword;
+typedef uint64_t Elf64_Addr;
+typedef uint64_t Elf64_Off;
+typedef struct
+{
+ Elf64_Word p_type;
+ Elf64_Off p_offset;
+ Elf64_Addr p_vaddr;
+ Elf64_Xword p_align;
+}
+Elf64_Phdr;
+struct dl_phdr_info
+{
+ const char *dlpi_name;
+ const Elf64_Phdr *dlpi_phdr;
+ Elf64_Half dlpi_phnum;
+ unsigned long long int dlpi_adds;
+};
+typedef unsigned _Unwind_Ptr;
+struct object
+{
+ union
+ {
+ const struct dwarf_fde *single;
+ struct dwarf_fde **array;
+ struct fde_vector *sort;
+ }
+ u;
+ union
+ {
+ struct
+ {
+ }
+ b;
+ }
+ s;
+ struct object *next;
+};
+typedef int sword;
+typedef unsigned int uword;
+struct dwarf_fde
+{
+ uword length;
+ sword CIE_delta;
+ unsigned char pc_begin[];
+};
+typedef struct dwarf_fde fde;
+struct unw_eh_callback_data
+{
+ const fde *ret;
+ struct frame_hdr_cache_element *link;
+}
+frame_hdr_cache[8];
+
+_Unwind_Ptr
+base_from_cb_data (struct unw_eh_callback_data *data)
+{
+}
+
+void
+_Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
+{
+ const unsigned char *p;
+ const struct unw_eh_frame_hdr *hdr;
+ struct object ob;
+}
diff --git a/test/CodeGen/2009-02-13-zerosize-union-field-ppc.c b/test/CodeGen/2009-02-13-zerosize-union-field-ppc.c
new file mode 100644
index 000000000000..21b47052813e
--- /dev/null
+++ b/test/CodeGen/2009-02-13-zerosize-union-field-ppc.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 %s -m32 -emit-llvm -o - | grep {i32 32} | count 3
+// XFAIL: *
+// XTARGET: powerpc
+// Every printf has 'i32 0' for the GEP of the string; no point counting those.
+typedef unsigned int Foo __attribute__((aligned(32)));
+typedef union{Foo:0;}a;
+typedef union{int x; Foo:0;}b;
+extern int printf(const char*, ...);
+main() {
+ printf("%ld\n", sizeof(a));
+ printf("%ld\n", __alignof__(a));
+ printf("%ld\n", sizeof(b));
+ printf("%ld\n", __alignof__(b));
+}
diff --git a/test/CodeGen/2009-02-13-zerosize-union-field.c b/test/CodeGen/2009-02-13-zerosize-union-field.c
new file mode 100644
index 000000000000..b39a231c65e1
--- /dev/null
+++ b/test/CodeGen/2009-02-13-zerosize-union-field.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -triple i686-apple-darwin -emit-llvm -o - | FileCheck %s
+// Every printf has 'i32 0' for the GEP of the string; no point counting those.
+typedef unsigned int Foo __attribute__((aligned(32)));
+typedef union{Foo:0;}a;
+typedef union{int x; Foo:0;}b;
+extern int printf(const char*, ...);
+int main() {
+ // CHECK: getelementptr inbounds ([5 x i8]* @.str, i32 0, i32 0), i32 0
+ printf("%ld\n", sizeof(a));
+ // CHECK: getelementptr inbounds ([5 x i8]* @.str, i32 0, i32 0), i32 1
+ printf("%ld\n", __alignof__(a));
+ // CHECK: getelementptr inbounds ([5 x i8]* @.str, i32 0, i32 0), i32 4
+ printf("%ld\n", sizeof(b));
+ // CHECK: getelementptr inbounds ([5 x i8]* @.str, i32 0, i32 0), i32 4
+ printf("%ld\n", __alignof__(b));
+}
diff --git a/test/CodeGen/2009-03-01-MallocNoAlias.c b/test/CodeGen/2009-03-01-MallocNoAlias.c
new file mode 100644
index 000000000000..1c4878a8189c
--- /dev/null
+++ b/test/CodeGen/2009-03-01-MallocNoAlias.c
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | grep noalias
+
+void * __attribute__ ((malloc)) foo (void) { return 0; }
diff --git a/test/CodeGen/2009-03-08-ZeroEltStructCrash.c b/test/CodeGen/2009-03-08-ZeroEltStructCrash.c
new file mode 100644
index 000000000000..b530eb7ce1e5
--- /dev/null
+++ b/test/CodeGen/2009-03-08-ZeroEltStructCrash.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+// PR3744
+struct Empty {};
+struct Union {
+ union {
+ int zero_arr[0];
+ } contents;
+};
+static inline void Foo(struct Union *u) {
+ int *array = u->contents.zero_arr;
+}
+static void Bar(struct Union *u) {
+ Foo(u);
+}
diff --git a/test/CodeGen/2009-03-13-dbg.c b/test/CodeGen/2009-03-13-dbg.c
new file mode 100644
index 000000000000..8f48830e8e2f
--- /dev/null
+++ b/test/CodeGen/2009-03-13-dbg.c
@@ -0,0 +1,2 @@
+// RUN: %clang_cc1 %s -emit-llvm -g -o /dev/null
+void foo() {}
diff --git a/test/CodeGen/2009-04-28-UnionArrayCrash.c b/test/CodeGen/2009-04-28-UnionArrayCrash.c
new file mode 100644
index 000000000000..4296b918cbcc
--- /dev/null
+++ b/test/CodeGen/2009-04-28-UnionArrayCrash.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+// PR4082
+union U {
+ int I;
+ double F;
+};
+
+union U arr[] = { { .I = 4 }, { .F = 123.} };
+union U *P = &arr[0];
+
+
diff --git a/test/CodeGen/2009-05-04-EnumInreg.c b/test/CodeGen/2009-05-04-EnumInreg.c
new file mode 100644
index 000000000000..2abc747caf27
--- /dev/null
+++ b/test/CodeGen/2009-05-04-EnumInreg.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -emit-llvm -triple i686-apple-darwin -mregparm 3 %s -o - | FileCheck %s
+// PR3967
+
+enum kobject_action {
+ KOBJ_ADD,
+ KOBJ_REMOVE,
+ KOBJ_CHANGE,
+ KOBJ_MOVE,
+ KOBJ_ONLINE,
+ KOBJ_OFFLINE,
+ KOBJ_MAX
+};
+
+struct kobject;
+
+// CHECK: i32 inreg %action
+int kobject_uevent(struct kobject *kobj, enum kobject_action action) {}
diff --git a/test/CodeGen/2009-06-14-HighlyAligned.c b/test/CodeGen/2009-06-14-HighlyAligned.c
new file mode 100644
index 000000000000..b5a7f5e733ff
--- /dev/null
+++ b/test/CodeGen/2009-06-14-HighlyAligned.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -emit-llvm -o /dev/null
+// PR4332
+
+static int highly_aligned __attribute__((aligned(4096)));
+
+int f() {
+ return highly_aligned;
+}
diff --git a/test/CodeGen/2009-06-18-StaticInitTailPadPack.c b/test/CodeGen/2009-06-18-StaticInitTailPadPack.c
new file mode 100644
index 000000000000..be103ec8e347
--- /dev/null
+++ b/test/CodeGen/2009-06-18-StaticInitTailPadPack.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+// rdar://6983634
+
+ typedef struct A *Foo;
+#pragma pack(push, 2)
+ struct Bar {
+ Foo f1;
+ unsigned short f2;
+ float f3;
+ };
+ struct Baz {
+ struct Bar f1;
+ struct Bar f2;
+ };
+ struct Qux {
+ unsigned long f1;
+ struct Baz f2;
+ };
+extern const struct Qux Bork;
+const struct Qux Bork = {
+ 0,
+ {
+ {0},
+ {0}
+ }
+};
diff --git a/test/CodeGen/2009-07-14-VoidPtr.c b/test/CodeGen/2009-07-14-VoidPtr.c
new file mode 100644
index 000000000000..5e8b23d3aab6
--- /dev/null
+++ b/test/CodeGen/2009-07-14-VoidPtr.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+// PR4556
+
+extern void foo;
+void *bar = &foo;
+
diff --git a/test/CodeGen/2009-07-15-pad-wchar_t-array.c b/test/CodeGen/2009-07-15-pad-wchar_t-array.c
new file mode 100644
index 000000000000..df12cae90ea0
--- /dev/null
+++ b/test/CodeGen/2009-07-15-pad-wchar_t-array.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+// This bit is taken from Sema/wchar.c so we can avoid the wchar.h include.
+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(__sun) || defined(__AuroraUX__)
+ #define WCHAR_T_TYPE long
+#else /* Solaris or AuroraUX. */
+ #define WCHAR_T_TYPE int
+#endif
+
+signed short _iodbcdm_sqlerror( )
+{
+ wchar_t _sqlState[6] = { L"\0" };
+}
diff --git a/test/CodeGen/2009-07-22-StructLayout.c b/test/CodeGen/2009-07-22-StructLayout.c
new file mode 100644
index 000000000000..7b7b82c40a5f
--- /dev/null
+++ b/test/CodeGen/2009-07-22-StructLayout.c
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 %s -triple i686-pc-linux-gnu -emit-llvm -o /dev/null
+// PR4590
+
+typedef unsigned char __u8;
+typedef unsigned int __le32;
+typedef unsigned int __u32;
+typedef unsigned short __le16;
+typedef unsigned short __u16;
+
+struct usb_cdc_ether_desc {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __u8 iMACAddress;
+ __le32 bmEthernetStatistics;
+ __le16 wMaxSegmentSize;
+ __le16 wNumberMCFilters;
+ __u8 bNumberPowerFilters;
+} __attribute__ ((packed));
+
+
+static struct usb_cdc_ether_desc ecm_desc __attribute__ ((__section__(".init.data"))) = {
+ .bLength = sizeof ecm_desc,
+ .bDescriptorType = ((0x01 << 5) | 0x04),
+ .bDescriptorSubType = 0x0f,
+
+
+
+ .bmEthernetStatistics = (( __le32)(__u32)(0)),
+ .wMaxSegmentSize = (( __le16)(__u16)(1514)),
+ .wNumberMCFilters = (( __le16)(__u16)(0)),
+ .bNumberPowerFilters = 0,
+};
diff --git a/test/CodeGen/2009-09-24-SqrtErrno.c b/test/CodeGen/2009-09-24-SqrtErrno.c
new file mode 100644
index 000000000000..b4a04ff6b6ab
--- /dev/null
+++ b/test/CodeGen/2009-09-24-SqrtErrno.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -fmath-errno | FileCheck %s
+// llvm.sqrt has undefined behavior on negative inputs, so it is
+// inappropriate to translate C/C++ sqrt to this.
+
+float sqrtf(float x);
+float foo(float X) {
+// CHECK: foo
+// CHECK-NOT: readonly
+// CHECK: call float @sqrtf
+ // Check that this is not marked readonly when errno is used.
+ return sqrtf(X);
+}
diff --git a/test/CodeGen/2009-12-07-BitFieldAlignment.c b/test/CodeGen/2009-12-07-BitFieldAlignment.c
new file mode 100644
index 000000000000..72c30e13c955
--- /dev/null
+++ b/test/CodeGen/2009-12-07-BitFieldAlignment.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple i686-apple-darwin %s -emit-llvm -o - | FileCheck %s
+// Set alignment on bitfield accesses.
+
+struct S {
+ int a, b;
+ void *c;
+ unsigned d : 8;
+ unsigned e : 8;
+};
+
+void f0(struct S *a) {
+// CHECK: load {{.*}}, align 4
+// CHECK: store {{.*}}, align 4
+ a->e = 0;
+}
diff --git a/test/CodeGen/2010-01-13-MemBarrier.c b/test/CodeGen/2010-01-13-MemBarrier.c
new file mode 100644
index 000000000000..c2b0acdab3cb
--- /dev/null
+++ b/test/CodeGen/2010-01-13-MemBarrier.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// XFAIL: sparc
+// rdar://7536390
+
+typedef unsigned __INT32_TYPE__ uint32_t;
+
+unsigned t(uint32_t *ptr, uint32_t val) {
+ // CHECK: @t
+ // CHECK: atomicrmw xchg i32* {{.*}} seq_cst
+ return __sync_lock_test_and_set(ptr, val);
+}
diff --git a/test/CodeGen/2010-01-14-FnType-DebugInfo.c b/test/CodeGen/2010-01-14-FnType-DebugInfo.c
new file mode 100644
index 000000000000..964c031d27c0
--- /dev/null
+++ b/test/CodeGen/2010-01-14-FnType-DebugInfo.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 %s -emit-llvm -g -o /dev/null
+typedef void (*sigcatch_t)( struct sigcontext *);
+sigcatch_t sigcatch[50] = {(sigcatch_t) 0};
+
diff --git a/test/CodeGen/2010-01-18-Inlined-Debug.c b/test/CodeGen/2010-01-18-Inlined-Debug.c
new file mode 100644
index 000000000000..cf00be7752cf
--- /dev/null
+++ b/test/CodeGen/2010-01-18-Inlined-Debug.c
@@ -0,0 +1,12 @@
+// PR: 6058
+// RUN: %clang_cc1 -g -emit-llvm %s -O0 -o /dev/null
+
+static inline int foo(double) __attribute__ ((always_inline));
+static inline int foo(double __x) { return __x; }
+
+void bar(double x) {
+ foo(x);
+}
+
+
+
diff --git a/test/CodeGen/2010-02-10-PointerName.c b/test/CodeGen/2010-02-10-PointerName.c
new file mode 100644
index 000000000000..910dd30fc603
--- /dev/null
+++ b/test/CodeGen/2010-02-10-PointerName.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -emit-llvm -g -o - | grep DW_TAG_pointer_type | grep -v char
+
+char i = 1;
+void foo() {
+ char *cp = &i;
+}
+
diff --git a/test/CodeGen/2010-02-15-DbgStaticVar.c b/test/CodeGen/2010-02-15-DbgStaticVar.c
new file mode 100644
index 000000000000..facd14e03ee6
--- /dev/null
+++ b/test/CodeGen/2010-02-15-DbgStaticVar.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -g -emit-llvm %s -o - | grep "metadata ..b., metadata ..b., metadata ...,"
+// Test to check intentionally empty linkage name for a static variable.
+// Radar 7651244.
+static int foo(int a)
+{
+ static int b = 1;
+ return b+a;
+}
+
+int main() {
+ int j = foo(1);
+ return 0;
+}
diff --git a/test/CodeGen/2010-03-5-LexicalScope.c b/test/CodeGen/2010-03-5-LexicalScope.c
new file mode 100644
index 000000000000..0f63ff6914b2
--- /dev/null
+++ b/test/CodeGen/2010-03-5-LexicalScope.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm -O0 -g %s -o - | grep DW_TAG_lexical_block | count 3
+int foo(int i) {
+ if (i) {
+ int j = 2;
+ }
+ else {
+ int j = 3;
+ }
+ return i;
+}
diff --git a/test/CodeGen/2010-05-26-AsmSideEffect.c b/test/CodeGen/2010-05-26-AsmSideEffect.c
new file mode 100644
index 000000000000..7dd86aeb54d7
--- /dev/null
+++ b/test/CodeGen/2010-05-26-AsmSideEffect.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -emit-llvm -triple arm-apple-darwin -o - | FileCheck %s
+// Radar 8026855
+
+int test (void *src) {
+ register int w0 asm ("0");
+ // CHECK: call i32 asm "ldr $0, [$1]", "={r0}{{.*}}(i8*
+ asm ("ldr %0, [%1]": "=r" (w0): "r" (src));
+ return w0;
+}
diff --git a/test/CodeGen/2010-06-11-SaveExpr.c b/test/CodeGen/2010-06-11-SaveExpr.c
new file mode 100644
index 000000000000..bfe0f35e269c
--- /dev/null
+++ b/test/CodeGen/2010-06-11-SaveExpr.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+// Test case by Eric Postpischil!
+void foo(void)
+{
+ char a[1];
+ int t = 1;
+ ((char (*)[t]) a)[0][0] = 0;
+}
diff --git a/test/CodeGen/2010-06-17-asmcrash.c b/test/CodeGen/2010-06-17-asmcrash.c
new file mode 100644
index 000000000000..8e9485bba9b8
--- /dev/null
+++ b/test/CodeGen/2010-06-17-asmcrash.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | llc -mtriple=x86_64-apple-darwin | FileCheck %s
+// XFAIL: *
+// XTARGET: x86,i386,i686
+
+typedef long long int64_t;
+typedef unsigned char uint8_t;
+typedef int64_t x86_reg;
+
+void avg_pixels8_mmx2(uint8_t *block, const uint8_t *pixels, int line_size, int h)
+{
+ __asm__ volatile("# %0 %1 %2 %3"
+ :"+g"(h), "+S"(pixels), "+D"(block)
+ :"r" ((x86_reg)line_size)
+ :"%""rax", "memory");
+// CHECK: # %ecx %rsi %rdi %rdx
+ }
diff --git a/test/CodeGen/2010-07-08-DeclDebugLineNo.c b/test/CodeGen/2010-07-08-DeclDebugLineNo.c
new file mode 100644
index 000000000000..1637a4936747
--- /dev/null
+++ b/test/CodeGen/2010-07-08-DeclDebugLineNo.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm -O0 -g %s -o - | FileCheck %s
+// Insure that dbg.declare lines for locals refer to correct line number records.
+// Radar 8152866.
+void foo() {
+ int l = 0; // line #4: CHECK: {{call.*llvm.dbg.declare.*%l.*\!dbg }}[[variable_l:![0-9]+]]
+ int p = 0; // line #5: CHECK: {{call.*llvm.dbg.declare.*%p.*\!dbg }}[[variable_p:![0-9]+]]
+}
+// Now match the line number records:
+// CHECK: {{^}}[[variable_l]]{{ = metadata ![{]i32 5,}}
+// CHECK: {{^}}[[variable_p]]{{ = metadata ![{]i32 6,}}
diff --git a/test/CodeGen/2010-07-14-overconservative-align.c b/test/CodeGen/2010-07-14-overconservative-align.c
new file mode 100644
index 000000000000..5c8c05645178
--- /dev/null
+++ b/test/CodeGen/2010-07-14-overconservative-align.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s
+// PR 5995
+struct s {
+ int word;
+ struct {
+ int filler __attribute__ ((aligned (8)));
+ };
+};
+
+void func (struct s *s)
+{
+ // CHECK: load %struct.s**{{.*}}align 8
+ s->word = 0;
+}
diff --git a/test/CodeGen/2010-07-14-ref-off-end.c b/test/CodeGen/2010-07-14-ref-off-end.c
new file mode 100644
index 000000000000..580ae889d8f2
--- /dev/null
+++ b/test/CodeGen/2010-07-14-ref-off-end.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 %s -emit-llvm -triple i386-apple-darwin -o - | FileCheck %s
+extern void abort();
+extern void exit(int);
+struct T
+{
+unsigned i:8;
+unsigned c:24;
+};
+f(struct T t)
+{
+struct T s[1];
+s[0]=t;
+return(char)s->c;
+}
+main()
+{
+// CHECK: getelementptr inbounds [1 x %struct.T]* %s, i32 0, i32 0
+// CHECK: getelementptr inbounds [1 x %struct.T]* %s, i32 0, i32 0
+struct T t;
+t.i=0xff;
+t.c=0xffff11;
+if(f(t)!=0x11)abort();
+exit(0);
+}
diff --git a/test/CodeGen/2010-08-12-asm-aggr-arg.c b/test/CodeGen/2010-08-12-asm-aggr-arg.c
new file mode 100644
index 000000000000..5ddc4122d60f
--- /dev/null
+++ b/test/CodeGen/2010-08-12-asm-aggr-arg.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -emit-llvm -O0 -o - | FileCheck %s
+// Radar 8288710: A small aggregate can be passed as an integer. Make sure
+// we don't get an error with "input constraint with a matching output
+// constraint of incompatible type!"
+
+struct wrapper {
+ int i;
+};
+
+// CHECK: xyz
+int test(int i) {
+ struct wrapper w;
+ w.i = i;
+ __asm__("xyz" : "=r" (w) : "0" (w));
+ return w.i;
+}
diff --git a/test/CodeGen/2010-12-01-CommonGlobal.c b/test/CodeGen/2010-12-01-CommonGlobal.c
new file mode 100644
index 000000000000..5eadbae6e3a6
--- /dev/null
+++ b/test/CodeGen/2010-12-01-CommonGlobal.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+// Don't crash on a common-linkage constant global.
+extern const int kABSourceTypeProperty;
+int foo(void) {
+ return kABSourceTypeProperty;
+}
+const int kABSourceTypeProperty;
diff --git a/test/CodeGen/2011-02-21-DATA-common.c b/test/CodeGen/2011-02-21-DATA-common.c
new file mode 100644
index 000000000000..5079561c868c
--- /dev/null
+++ b/test/CodeGen/2011-02-21-DATA-common.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+struct rtxc_snapshot {
+ int a, b, c, d;
+};
+__attribute__ ((section("__DATA, __common"))) static struct rtxc_snapshot rtxc_log_A[4];
diff --git a/test/CodeGen/2011-03-02-UnionInitializer.c b/test/CodeGen/2011-03-02-UnionInitializer.c
new file mode 100644
index 000000000000..3c112e0a47f0
--- /dev/null
+++ b/test/CodeGen/2011-03-02-UnionInitializer.c
@@ -0,0 +1,2 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+union { int :3; double f; } u17_017 = {17.17};
diff --git a/test/CodeGen/2011-03-08-ZeroFieldUnionInitializer.c b/test/CodeGen/2011-03-08-ZeroFieldUnionInitializer.c
new file mode 100644
index 000000000000..ff570d8abb42
--- /dev/null
+++ b/test/CodeGen/2011-03-08-ZeroFieldUnionInitializer.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+typedef struct {
+ union {
+ struct { } __attribute((packed));
+ };
+} fenv_t;
+const fenv_t _FE_DFL_ENV = {{{ 0, 0, 0, 0 }}};
diff --git a/test/CodeGen/2011-03-31-ArrayRefFolding.c b/test/CodeGen/2011-03-31-ArrayRefFolding.c
new file mode 100644
index 000000000000..31c0a681a4dc
--- /dev/null
+++ b/test/CodeGen/2011-03-31-ArrayRefFolding.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -emit-llvm -o - -triple i386-apple-darwin %s | FileCheck %s
+// PR9571
+
+struct t {
+ int x;
+};
+
+extern struct t *cfun;
+
+int f(void) {
+ if (!(cfun + 0))
+ // CHECK: icmp ne %struct.t*
+ return 0;
+ return cfun->x;
+}
diff --git a/test/CodeGen/Atomics.c b/test/CodeGen/Atomics.c
new file mode 100644
index 000000000000..c440b6c1909e
--- /dev/null
+++ b/test/CodeGen/Atomics.c
@@ -0,0 +1,203 @@
+// Test frontend handling of __sync builtins.
+// Modified from a gcc testcase.
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+
+signed char sc;
+unsigned char uc;
+signed short ss;
+unsigned short us;
+signed int si;
+unsigned int ui;
+signed long long sll;
+unsigned long long ull;
+
+void test_op_ignore (void) // CHECK: define void @test_op_ignore
+{
+ (void) __sync_fetch_and_add (&sc, 1); // CHECK: atomicrmw add i8
+ (void) __sync_fetch_and_add (&uc, 1); // CHECK: atomicrmw add i8
+ (void) __sync_fetch_and_add (&ss, 1); // CHECK: atomicrmw add i16
+ (void) __sync_fetch_and_add (&us, 1); // CHECK: atomicrmw add i16
+ (void) __sync_fetch_and_add (&si, 1); // CHECK: atomicrmw add i32
+ (void) __sync_fetch_and_add (&ui, 1); // CHECK: atomicrmw add i32
+ (void) __sync_fetch_and_add (&sll, 1); // CHECK: atomicrmw add i64
+ (void) __sync_fetch_and_add (&ull, 1); // CHECK: atomicrmw add i64
+
+ (void) __sync_fetch_and_sub (&sc, 1); // CHECK: atomicrmw sub i8
+ (void) __sync_fetch_and_sub (&uc, 1); // CHECK: atomicrmw sub i8
+ (void) __sync_fetch_and_sub (&ss, 1); // CHECK: atomicrmw sub i16
+ (void) __sync_fetch_and_sub (&us, 1); // CHECK: atomicrmw sub i16
+ (void) __sync_fetch_and_sub (&si, 1); // CHECK: atomicrmw sub i32
+ (void) __sync_fetch_and_sub (&ui, 1); // CHECK: atomicrmw sub i32
+ (void) __sync_fetch_and_sub (&sll, 1); // CHECK: atomicrmw sub i64
+ (void) __sync_fetch_and_sub (&ull, 1); // CHECK: atomicrmw sub i64
+
+ (void) __sync_fetch_and_or (&sc, 1); // CHECK: atomicrmw or i8
+ (void) __sync_fetch_and_or (&uc, 1); // CHECK: atomicrmw or i8
+ (void) __sync_fetch_and_or (&ss, 1); // CHECK: atomicrmw or i16
+ (void) __sync_fetch_and_or (&us, 1); // CHECK: atomicrmw or i16
+ (void) __sync_fetch_and_or (&si, 1); // CHECK: atomicrmw or i32
+ (void) __sync_fetch_and_or (&ui, 1); // CHECK: atomicrmw or i32
+ (void) __sync_fetch_and_or (&sll, 1); // CHECK: atomicrmw or i64
+ (void) __sync_fetch_and_or (&ull, 1); // CHECK: atomicrmw or i64
+
+ (void) __sync_fetch_and_xor (&sc, 1); // CHECK: atomicrmw xor i8
+ (void) __sync_fetch_and_xor (&uc, 1); // CHECK: atomicrmw xor i8
+ (void) __sync_fetch_and_xor (&ss, 1); // CHECK: atomicrmw xor i16
+ (void) __sync_fetch_and_xor (&us, 1); // CHECK: atomicrmw xor i16
+ (void) __sync_fetch_and_xor (&si, 1); // CHECK: atomicrmw xor i32
+ (void) __sync_fetch_and_xor (&ui, 1); // CHECK: atomicrmw xor i32
+ (void) __sync_fetch_and_xor (&sll, 1); // CHECK: atomicrmw xor i64
+ (void) __sync_fetch_and_xor (&ull, 1); // CHECK: atomicrmw xor i64
+
+ (void) __sync_fetch_and_and (&sc, 1); // CHECK: atomicrmw and i8
+ (void) __sync_fetch_and_and (&uc, 1); // CHECK: atomicrmw and i8
+ (void) __sync_fetch_and_and (&ss, 1); // CHECK: atomicrmw and i16
+ (void) __sync_fetch_and_and (&us, 1); // CHECK: atomicrmw and i16
+ (void) __sync_fetch_and_and (&si, 1); // CHECK: atomicrmw and i32
+ (void) __sync_fetch_and_and (&ui, 1); // CHECK: atomicrmw and i32
+ (void) __sync_fetch_and_and (&sll, 1); // CHECK: atomicrmw and i64
+ (void) __sync_fetch_and_and (&ull, 1); // CHECK: atomicrmw and i64
+
+}
+
+void test_fetch_and_op (void) // CHECK: define void @test_fetch_and_op
+{
+ sc = __sync_fetch_and_add (&sc, 11); // CHECK: atomicrmw add
+ uc = __sync_fetch_and_add (&uc, 11); // CHECK: atomicrmw add
+ ss = __sync_fetch_and_add (&ss, 11); // CHECK: atomicrmw add
+ us = __sync_fetch_and_add (&us, 11); // CHECK: atomicrmw add
+ si = __sync_fetch_and_add (&si, 11); // CHECK: atomicrmw add
+ ui = __sync_fetch_and_add (&ui, 11); // CHECK: atomicrmw add
+ sll = __sync_fetch_and_add (&sll, 11); // CHECK: atomicrmw add
+ ull = __sync_fetch_and_add (&ull, 11); // CHECK: atomicrmw add
+
+ sc = __sync_fetch_and_sub (&sc, 11); // CHECK: atomicrmw sub
+ uc = __sync_fetch_and_sub (&uc, 11); // CHECK: atomicrmw sub
+ ss = __sync_fetch_and_sub (&ss, 11); // CHECK: atomicrmw sub
+ us = __sync_fetch_and_sub (&us, 11); // CHECK: atomicrmw sub
+ si = __sync_fetch_and_sub (&si, 11); // CHECK: atomicrmw sub
+ ui = __sync_fetch_and_sub (&ui, 11); // CHECK: atomicrmw sub
+ sll = __sync_fetch_and_sub (&sll, 11); // CHECK: atomicrmw sub
+ ull = __sync_fetch_and_sub (&ull, 11); // CHECK: atomicrmw sub
+
+ sc = __sync_fetch_and_or (&sc, 11); // CHECK: atomicrmw or
+ uc = __sync_fetch_and_or (&uc, 11); // CHECK: atomicrmw or
+ ss = __sync_fetch_and_or (&ss, 11); // CHECK: atomicrmw or
+ us = __sync_fetch_and_or (&us, 11); // CHECK: atomicrmw or
+ si = __sync_fetch_and_or (&si, 11); // CHECK: atomicrmw or
+ ui = __sync_fetch_and_or (&ui, 11); // CHECK: atomicrmw or
+ sll = __sync_fetch_and_or (&sll, 11); // CHECK: atomicrmw or
+ ull = __sync_fetch_and_or (&ull, 11); // CHECK: atomicrmw or
+
+ sc = __sync_fetch_and_xor (&sc, 11); // CHECK: atomicrmw xor
+ uc = __sync_fetch_and_xor (&uc, 11); // CHECK: atomicrmw xor
+ ss = __sync_fetch_and_xor (&ss, 11); // CHECK: atomicrmw xor
+ us = __sync_fetch_and_xor (&us, 11); // CHECK: atomicrmw xor
+ si = __sync_fetch_and_xor (&si, 11); // CHECK: atomicrmw xor
+ ui = __sync_fetch_and_xor (&ui, 11); // CHECK: atomicrmw xor
+ sll = __sync_fetch_and_xor (&sll, 11); // CHECK: atomicrmw xor
+ ull = __sync_fetch_and_xor (&ull, 11); // CHECK: atomicrmw xor
+
+ sc = __sync_fetch_and_and (&sc, 11); // CHECK: atomicrmw and
+ uc = __sync_fetch_and_and (&uc, 11); // CHECK: atomicrmw and
+ ss = __sync_fetch_and_and (&ss, 11); // CHECK: atomicrmw and
+ us = __sync_fetch_and_and (&us, 11); // CHECK: atomicrmw and
+ si = __sync_fetch_and_and (&si, 11); // CHECK: atomicrmw and
+ ui = __sync_fetch_and_and (&ui, 11); // CHECK: atomicrmw and
+ sll = __sync_fetch_and_and (&sll, 11); // CHECK: atomicrmw and
+ ull = __sync_fetch_and_and (&ull, 11); // CHECK: atomicrmw and
+
+}
+
+void test_op_and_fetch (void)
+{
+ sc = __sync_add_and_fetch (&sc, uc); // CHECK: atomicrmw add
+ uc = __sync_add_and_fetch (&uc, uc); // CHECK: atomicrmw add
+ ss = __sync_add_and_fetch (&ss, uc); // CHECK: atomicrmw add
+ us = __sync_add_and_fetch (&us, uc); // CHECK: atomicrmw add
+ si = __sync_add_and_fetch (&si, uc); // CHECK: atomicrmw add
+ ui = __sync_add_and_fetch (&ui, uc); // CHECK: atomicrmw add
+ sll = __sync_add_and_fetch (&sll, uc); // CHECK: atomicrmw add
+ ull = __sync_add_and_fetch (&ull, uc); // CHECK: atomicrmw add
+
+ sc = __sync_sub_and_fetch (&sc, uc); // CHECK: atomicrmw sub
+ uc = __sync_sub_and_fetch (&uc, uc); // CHECK: atomicrmw sub
+ ss = __sync_sub_and_fetch (&ss, uc); // CHECK: atomicrmw sub
+ us = __sync_sub_and_fetch (&us, uc); // CHECK: atomicrmw sub
+ si = __sync_sub_and_fetch (&si, uc); // CHECK: atomicrmw sub
+ ui = __sync_sub_and_fetch (&ui, uc); // CHECK: atomicrmw sub
+ sll = __sync_sub_and_fetch (&sll, uc); // CHECK: atomicrmw sub
+ ull = __sync_sub_and_fetch (&ull, uc); // CHECK: atomicrmw sub
+
+ sc = __sync_or_and_fetch (&sc, uc); // CHECK: atomicrmw or
+ uc = __sync_or_and_fetch (&uc, uc); // CHECK: atomicrmw or
+ ss = __sync_or_and_fetch (&ss, uc); // CHECK: atomicrmw or
+ us = __sync_or_and_fetch (&us, uc); // CHECK: atomicrmw or
+ si = __sync_or_and_fetch (&si, uc); // CHECK: atomicrmw or
+ ui = __sync_or_and_fetch (&ui, uc); // CHECK: atomicrmw or
+ sll = __sync_or_and_fetch (&sll, uc); // CHECK: atomicrmw or
+ ull = __sync_or_and_fetch (&ull, uc); // CHECK: atomicrmw or
+
+ sc = __sync_xor_and_fetch (&sc, uc); // CHECK: atomicrmw xor
+ uc = __sync_xor_and_fetch (&uc, uc); // CHECK: atomicrmw xor
+ ss = __sync_xor_and_fetch (&ss, uc); // CHECK: atomicrmw xor
+ us = __sync_xor_and_fetch (&us, uc); // CHECK: atomicrmw xor
+ si = __sync_xor_and_fetch (&si, uc); // CHECK: atomicrmw xor
+ ui = __sync_xor_and_fetch (&ui, uc); // CHECK: atomicrmw xor
+ sll = __sync_xor_and_fetch (&sll, uc); // CHECK: atomicrmw xor
+ ull = __sync_xor_and_fetch (&ull, uc); // CHECK: atomicrmw xor
+
+ sc = __sync_and_and_fetch (&sc, uc); // CHECK: atomicrmw and
+ uc = __sync_and_and_fetch (&uc, uc); // CHECK: atomicrmw and
+ ss = __sync_and_and_fetch (&ss, uc); // CHECK: atomicrmw and
+ us = __sync_and_and_fetch (&us, uc); // CHECK: atomicrmw and
+ si = __sync_and_and_fetch (&si, uc); // CHECK: atomicrmw and
+ ui = __sync_and_and_fetch (&ui, uc); // CHECK: atomicrmw and
+ sll = __sync_and_and_fetch (&sll, uc); // CHECK: atomicrmw and
+ ull = __sync_and_and_fetch (&ull, uc); // CHECK: atomicrmw and
+
+}
+
+void test_compare_and_swap (void)
+{
+ sc = __sync_val_compare_and_swap (&sc, uc, sc); // CHECK: cmpxchg i8
+ uc = __sync_val_compare_and_swap (&uc, uc, sc); // CHECK: cmpxchg i8
+ ss = __sync_val_compare_and_swap (&ss, uc, sc); // CHECK: cmpxchg i16
+ us = __sync_val_compare_and_swap (&us, uc, sc); // CHECK: cmpxchg i16
+ si = __sync_val_compare_and_swap (&si, uc, sc); // CHECK: cmpxchg i32
+ ui = __sync_val_compare_and_swap (&ui, uc, sc); // CHECK: cmpxchg i32
+ sll = __sync_val_compare_and_swap (&sll, uc, sc); // CHECK: cmpxchg i64
+ ull = __sync_val_compare_and_swap (&ull, uc, sc); // CHECK: cmpxchg i64
+
+ ui = __sync_bool_compare_and_swap (&sc, uc, sc); // CHECK: cmpxchg
+ ui = __sync_bool_compare_and_swap (&uc, uc, sc); // CHECK: cmpxchg
+ ui = __sync_bool_compare_and_swap (&ss, uc, sc); // CHECK: cmpxchg
+ ui = __sync_bool_compare_and_swap (&us, uc, sc); // CHECK: cmpxchg
+ ui = __sync_bool_compare_and_swap (&si, uc, sc); // CHECK: cmpxchg
+ ui = __sync_bool_compare_and_swap (&ui, uc, sc); // CHECK: cmpxchg
+ ui = __sync_bool_compare_and_swap (&sll, uc, sc); // CHECK: cmpxchg
+ ui = __sync_bool_compare_and_swap (&ull, uc, sc); // CHECK: cmpxchg
+}
+
+void test_lock (void)
+{
+ sc = __sync_lock_test_and_set (&sc, 1); // CHECK: atomicrmw xchg i8
+ uc = __sync_lock_test_and_set (&uc, 1); // CHECK: atomicrmw xchg i8
+ ss = __sync_lock_test_and_set (&ss, 1); // CHECK: atomicrmw xchg i16
+ us = __sync_lock_test_and_set (&us, 1); // CHECK: atomicrmw xchg i16
+ si = __sync_lock_test_and_set (&si, 1); // CHECK: atomicrmw xchg i32
+ ui = __sync_lock_test_and_set (&ui, 1); // CHECK: atomicrmw xchg i32
+ sll = __sync_lock_test_and_set (&sll, 1); // CHECK: atomicrmw xchg i64
+ ull = __sync_lock_test_and_set (&ull, 1); // CHECK: atomicrmw xchg i64
+
+ __sync_synchronize (); // CHECK: fence seq_cst
+
+ __sync_lock_release (&sc); // CHECK: store atomic {{.*}} release, align 1
+ __sync_lock_release (&uc); // CHECK: store atomic {{.*}} release, align 1
+ __sync_lock_release (&ss); // CHECK: store atomic {{.*}} release, align 2
+ __sync_lock_release (&us); /// CHECK: store atomic {{.*}} release, align 2
+ __sync_lock_release (&si); // CHECK: store atomic {{.*}} release, align 4
+ __sync_lock_release (&ui); // CHECK: store atomic {{.*}} release, align 4
+ __sync_lock_release (&sll); // CHECK: store atomic {{.*}} release, align 8
+ __sync_lock_release (&ull); // CHECK: store atomic {{.*}} release, align 8
+}
diff --git a/test/CodeGen/BasicInstrs.c b/test/CodeGen/BasicInstrs.c
new file mode 100644
index 000000000000..2b8a6f67981a
--- /dev/null
+++ b/test/CodeGen/BasicInstrs.c
@@ -0,0 +1,25 @@
+// This file can be used to see what a native C compiler is generating for a
+// variety of interesting operations.
+//
+// RUN: %clang_cc1 -emit-llvm %s -o -
+
+unsigned int udiv(unsigned int X, unsigned int Y) {
+ return X/Y;
+}
+int sdiv(int X, int Y) {
+ return X/Y;
+}
+unsigned int urem(unsigned int X, unsigned int Y) {
+ return X%Y;
+}
+int srem(int X, int Y) {
+ return X%Y;
+}
+
+_Bool setlt(int X, int Y) {
+ return X < Y;
+}
+
+_Bool setgt(int X, int Y) {
+ return X > Y;
+}
diff --git a/test/CodeGen/always-inline.c b/test/CodeGen/always-inline.c
new file mode 100644
index 000000000000..dc74be5e8c21
--- /dev/null
+++ b/test/CodeGen/always-inline.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | grep call | not grep foo
+
+void bar() {
+}
+
+inline void __attribute__((__always_inline__)) foo() {
+ bar();
+}
+
+void i_want_bar() {
+ foo();
+}
diff --git a/test/CodeGen/annotate.c b/test/CodeGen/annotate.c
deleted file mode 100644
index 9ed187d1d170..000000000000
--- a/test/CodeGen/annotate.c
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
-
-__attribute((annotate("foo"))) char foo;
-void a(char *a) {
- __attribute__((annotate("bar"))) static char bar;
-}
-
-// CHECK: private unnamed_addr global
-// CHECK: private unnamed_addr global
-// CHECK: @llvm.global.annotations = appending global [2 x { i8*, i8*, i8*, i32 }]
diff --git a/test/CodeGen/annotations-builtin.c b/test/CodeGen/annotations-builtin.c
new file mode 100644
index 000000000000..42421a0a5200
--- /dev/null
+++ b/test/CodeGen/annotations-builtin.c
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+// END.
+
+static long long llfoo;
+static int intfoo;
+static short shortfoo;
+static char charfoo;
+
+// CHECK: private unnamed_addr constant [13 x i8] {{.*}}annotation_a{{.*}} section "llvm.metadata"
+// CHECK-NOT: {{.*}}annotation_a{{.*}}
+
+static int foo(int a) {
+ return a + 1;
+}
+
+int main(int argc, char **argv) {
+ char barray[16];
+ char *b = (char *) __builtin_annotation((int)barray, "annotation_a");
+// CHECK: ptrtoint i8* {{.*}} to i32
+// CHECK-NEXT: call i32 @llvm.annotation.i32
+// CHECK: inttoptr {{.*}} to i8*
+
+ int call = __builtin_annotation(foo(argc), "annotation_a");
+// CHECK: call {{.*}} @foo
+// CHECK: call i32 @llvm.annotation.i32
+
+ long long lla = __builtin_annotation(llfoo, "annotation_a");
+// CHECK: trunc i64 {{.*}} to i32
+// CHECK-NEXT: call i32 @llvm.annotation.i32
+// CHECK-NEXT: zext i32 {{.*}} to i64
+
+ int inta = __builtin_annotation(intfoo, "annotation_a");
+// CHECK: load i32* @intfoo
+// CHECK-NEXT: call i32 @llvm.annotation.i32
+// CHECK-NEXT: store
+
+ short shorta = __builtin_annotation(shortfoo, "annotation_a");
+// CHECK: sext i16 {{.*}} to i32
+// CHECK-NEXT: call i32 @llvm.annotation.i32
+// CHECK-NEXT: trunc i32 {{.*}} to i16
+
+ char chara = __builtin_annotation(charfoo, "annotation_a");
+// CHECK: sext i8 {{.*}} to i32
+// CHECK-NEXT: call i32 @llvm.annotation.i32
+// CHECK-NEXT: trunc i32 {{.*}} to i8
+//
+ char **arg = (char**) __builtin_annotation((int) argv, "annotation_a");
+// CHECK: ptrtoint i8** {{.*}} to
+// CHECK: call i32 @llvm.annotation.i32
+// CHECK: inttoptr {{.*}} to i8**
+ return 0;
+}
diff --git a/test/CodeGen/annotations-field.c b/test/CodeGen/annotations-field.c
new file mode 100644
index 000000000000..6b443675850c
--- /dev/null
+++ b/test/CodeGen/annotations-field.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+// END.
+
+// CHECK: private unnamed_addr constant [8 x i8] c"v_ann_{{.}}\00", section "llvm.metadata"
+// CHECK: private unnamed_addr constant [8 x i8] c"v_ann_{{.}}\00", section "llvm.metadata"
+
+struct foo {
+ int v __attribute__((annotate("v_ann_0"))) __attribute__((annotate("v_ann_1")));
+};
+
+static struct foo gf;
+
+int main(int argc, char **argv) {
+ struct foo f;
+ f.v = argc;
+// CHECK: getelementptr inbounds %struct.foo* %f, i32 0, i32 0
+// CHECK-NEXT: bitcast i32* {{.*}} to i8*
+// CHECK-NEXT: call i8* @llvm.ptr.annotation.p0i8({{.*}}str{{.*}}str{{.*}}i32 8)
+// CHECK-NEXT: bitcast i8* {{.*}} to i32*
+// CHECK-NEXT: bitcast i32* {{.*}} to i8*
+// CHECK-NEXT: call i8* @llvm.ptr.annotation.p0i8({{.*}}str{{.*}}str{{.*}}i32 8)
+// CHECK-NEXT: bitcast i8* {{.*}} to i32*
+ gf.v = argc;
+// CHECK: bitcast i32* getelementptr inbounds (%struct.foo* @gf, i32 0, i32 0) to i8*
+// CHECK-NEXT: call i8* @llvm.ptr.annotation.p0i8({{.*}}str{{.*}}str{{.*}}i32 8)
+ return 0;
+}
diff --git a/test/CodeGen/annotations-global.c b/test/CodeGen/annotations-global.c
new file mode 100644
index 000000000000..2782525ed915
--- /dev/null
+++ b/test/CodeGen/annotations-global.c
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 %s -emit-llvm -o %t1
+// RUN: FileCheck --check-prefix=FOO %s < %t1
+// RUN: FileCheck --check-prefix=A %s < %t1
+// RUN: FileCheck --check-prefix=BAR %s < %t1
+// RUN: FileCheck --check-prefix=FOOS %s < %t1
+// END.
+
+static __attribute((annotate("sfoo_0"))) __attribute((annotate("sfoo_1"))) char sfoo;
+__attribute((annotate("foo_0"))) __attribute((annotate("foo_1"))) char foo;
+
+void __attribute((annotate("ann_a_0"))) __attribute((annotate("ann_a_1"))) __attribute((annotate("ann_a_2"))) __attribute((annotate("ann_a_3"))) a(char *a);
+void __attribute((annotate("ann_a_0"))) __attribute((annotate("ann_a_1"))) a(char *a) {
+ __attribute__((annotate("bar_0"))) __attribute__((annotate("bar_1"))) static char bar;
+ sfoo = 0;
+}
+
+// FOOS: target triple
+// FOOS: private unnamed_addr constant [7 x i8] c"sfoo_{{.}}\00", section "llvm.metadata"
+// FOOS: private unnamed_addr constant [7 x i8] c"sfoo_{{.}}\00", section "llvm.metadata"
+// FOOS-NOT: sfoo_
+// FOOS: @llvm.global.annotations = appending global [10 x { i8*, i8*, i8*, i32 }] {{.*}}i8* @sfoo{{.*}}i8* @sfoo{{.*}}, section "llvm.metadata"
+
+// FOO: target triple
+// FOO: private unnamed_addr constant [6 x i8] c"foo_{{.}}\00", section "llvm.metadata"
+// FOO: private unnamed_addr constant [6 x i8] c"foo_{{.}}\00", section "llvm.metadata"
+// FOO-NOT: foo_
+// FOO: @llvm.global.annotations = appending global [10 x { i8*, i8*, i8*, i32 }] {{.*}}i8* @foo{{.*}}i8* @foo{{.*}}, section "llvm.metadata"
+
+// A: target triple
+// A: private unnamed_addr constant [8 x i8] c"ann_a_{{.}}\00", section "llvm.metadata"
+// A: private unnamed_addr constant [8 x i8] c"ann_a_{{.}}\00", section "llvm.metadata"
+// A: private unnamed_addr constant [8 x i8] c"ann_a_{{.}}\00", section "llvm.metadata"
+// A: private unnamed_addr constant [8 x i8] c"ann_a_{{.}}\00", section "llvm.metadata"
+// A-NOT: ann_a_
+// A: @llvm.global.annotations = appending global [10 x { i8*, i8*, i8*, i32 }] {{.*}}i8* bitcast (void (i8*)* @a to i8*){{.*}}i8* bitcast (void (i8*)* @a to i8*){{.*}}i8* bitcast (void (i8*)* @a to i8*){{.*}}i8* bitcast (void (i8*)* @a to i8*){{.*}}, section "llvm.metadata"
+
+// BAR: target triple
+// BAR: private unnamed_addr constant [6 x i8] c"bar_{{.}}\00", section "llvm.metadata"
+// BAR: private unnamed_addr constant [6 x i8] c"bar_{{.}}\00", section "llvm.metadata"
+// BAR-NOT: bar_
+// BAR: @llvm.global.annotations = appending global [10 x { i8*, i8*, i8*, i32 }] {{.*}}i8* @a.bar{{.*}}i8* @a.bar{{.*}}, section "llvm.metadata"
diff --git a/test/CodeGen/annotations-loc.c b/test/CodeGen/annotations-loc.c
new file mode 100644
index 000000000000..4644f0e1d2ca
--- /dev/null
+++ b/test/CodeGen/annotations-loc.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+// END.
+# 1 "t.c"
+# 1 "<built-in>"
+# 1 "<command-line>"
+# 1 "t.c"
+int __attribute((annotate("foo"))) foo(void) { return 0; }
+
+// CHECK: private unnamed_addr constant [4 x i8] c"t.c\00"
+// CHECK: @llvm.global.annotations = {{.*}}, i32 1 }
diff --git a/test/CodeGen/annotations-var.c b/test/CodeGen/annotations-var.c
new file mode 100644
index 000000000000..b8ada9fc0f3e
--- /dev/null
+++ b/test/CodeGen/annotations-var.c
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o %t1 %s
+// RUN: FileCheck --check-prefix=LOCAL %s < %t1
+// RUN: FileCheck --check-prefix=UNDEF %s < %t1
+// RUN: FileCheck --check-prefix=PARAM %s < %t1
+// END.
+
+// LOCAL: private unnamed_addr constant [15 x i8] c"localvar_ann_{{.}}\00", section "llvm.metadata"
+// LOCAL: private unnamed_addr constant [15 x i8] c"localvar_ann_{{.}}\00", section "llvm.metadata"
+
+// UNDEF: private unnamed_addr constant [15 x i8] c"undefvar_ann_0\00", section "llvm.metadata"
+
+// PARAM: private unnamed_addr constant [12 x i8] c"param_ann_{{.}}\00", section "llvm.metadata"
+// PARAM: private unnamed_addr constant [12 x i8] c"param_ann_{{.}}\00", section "llvm.metadata"
+// PARAM: private unnamed_addr constant [12 x i8] c"param_ann_{{.}}\00", section "llvm.metadata"
+// PARAM: private unnamed_addr constant [12 x i8] c"param_ann_{{.}}\00", section "llvm.metadata"
+
+int foo(int v __attribute__((annotate("param_ann_2"))) __attribute__((annotate("param_ann_3"))));
+int foo(int v __attribute__((annotate("param_ann_0"))) __attribute__((annotate("param_ann_1")))) {
+ return v + 1;
+// PARAM: define {{.*}}@foo
+// PARAM: [[V:%.*]] = alloca i32
+// PARAM: bitcast i32* [[V]] to i8*
+// PARAM-NEXT: call void @llvm.var.annotation(
+// PARAM-NEXT: bitcast i32* [[V]] to i8*
+// PARAM-NEXT: call void @llvm.var.annotation(
+// PARAM-NEXT: bitcast i32* [[V]] to i8*
+// PARAM-NEXT: call void @llvm.var.annotation(
+// PARAM-NEXT: bitcast i32* [[V]] to i8*
+// PARAM-NEXT: call void @llvm.var.annotation(
+}
+
+void local(void) {
+ int localvar __attribute__((annotate("localvar_ann_0"))) __attribute__((annotate("localvar_ann_1"))) = 3;
+// LOCAL: define void @local()
+// LOCAL: [[LOCALVAR:%.*]] = alloca i32,
+// LOCAL-NEXT: [[T0:%.*]] = bitcast i32* [[LOCALVAR]] to i8*
+// LOCAL-NEXT: call void @llvm.var.annotation(i8* [[T0]], i8* getelementptr inbounds ([15 x i8]* @{{.*}}), i8* getelementptr inbounds ({{.*}}), i32 33)
+// LOCAL-NEXT: [[T0:%.*]] = bitcast i32* [[LOCALVAR]] to i8*
+// LOCAL-NEXT: call void @llvm.var.annotation(i8* [[T0]], i8* getelementptr inbounds ([15 x i8]* @{{.*}}), i8* getelementptr inbounds ({{.*}}), i32 33)
+}
+
+void undef(void) {
+ int undefvar __attribute__((annotate("undefvar_ann_0")));
+// UNDEF: define void @undef()
+// UNDEF: [[UNDEFVAR:%.*]] = alloca i32,
+// UNDEF-NEXT: [[T0:%.*]] = bitcast i32* [[UNDEFVAR]] to i8*
+// UNDEF-NEXT: call void @llvm.var.annotation(i8* [[T0]], i8* getelementptr inbounds ([15 x i8]* @{{.*}}), i8* getelementptr inbounds ({{.*}}), i32 43)
+}
diff --git a/test/CodeGen/arm-aapcs-vfp.c b/test/CodeGen/arm-aapcs-vfp.c
new file mode 100644
index 000000000000..20b8a742dd41
--- /dev/null
+++ b/test/CodeGen/arm-aapcs-vfp.c
@@ -0,0 +1,82 @@
+// RUN: %clang_cc1 -triple thumbv7-apple-darwin9 \
+// RUN: -target-abi aapcs \
+// RUN: -target-cpu cortex-a8 \
+// RUN: -mfloat-abi hard \
+// RUN: -ffreestanding \
+// RUN: -emit-llvm -w -o - %s | FileCheck %s
+
+#include <arm_neon.h>
+
+struct homogeneous_struct {
+ float f[2];
+ float f3;
+ float f4;
+};
+// CHECK: define arm_aapcs_vfpcc void @test_struct(float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}})
+extern void struct_callee(struct homogeneous_struct);
+void test_struct(struct homogeneous_struct arg) {
+ struct_callee(arg);
+}
+
+struct nested_array {
+ double d[4];
+};
+// CHECK: define arm_aapcs_vfpcc void @test_array(double %{{.*}}, double %{{.*}}, double %{{.*}}, double %{{.*}})
+extern void array_callee(struct nested_array);
+void test_array(struct nested_array arg) {
+ array_callee(arg);
+}
+
+extern void complex_callee(__complex__ double);
+// CHECK: define arm_aapcs_vfpcc void @test_complex(double %{{.*}}, double %{{.*}})
+void test_complex(__complex__ double cd) {
+ complex_callee(cd);
+}
+
+// Structs with more than 4 elements of the base type are not treated
+// as homogeneous aggregates. Test that.
+
+struct big_struct {
+ float f1;
+ float f[2];
+ float f3;
+ float f4;
+};
+// CHECK: define arm_aapcs_vfpcc void @test_big([5 x i32] %{{.*}})
+extern void big_callee(struct big_struct);
+void test_big(struct big_struct arg) {
+ big_callee(arg);
+}
+
+// Make sure that aggregates with multiple base types are not treated as
+// homogeneous aggregates.
+
+struct heterogeneous_struct {
+ float f1;
+ int i2;
+};
+// CHECK: define arm_aapcs_vfpcc void @test_hetero([2 x i32] %{{.*}})
+extern void hetero_callee(struct heterogeneous_struct);
+void test_hetero(struct heterogeneous_struct arg) {
+ hetero_callee(arg);
+}
+
+// Neon multi-vector types are homogeneous aggregates.
+// CHECK: define arm_aapcs_vfpcc <16 x i8> @f0(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, <16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+int8x16_t f0(int8x16x4_t v4) {
+ return vaddq_s8(v4.val[0], v4.val[3]);
+}
+
+// ...and it doesn't matter whether the vectors are exactly the same, as long
+// as they have the same size.
+
+struct neon_struct {
+ int8x8x2_t v12;
+ int32x2_t v3;
+ int16x4_t v4;
+};
+// CHECK: define arm_aapcs_vfpcc void @test_neon(<8 x i8> %{{.*}}, <8 x i8> %{{.*}}, <2 x i32> %{{.*}}, <4 x i16> %{{.*}})
+extern void neon_callee(struct neon_struct);
+void test_neon(struct neon_struct arg) {
+ neon_callee(arg);
+}
diff --git a/test/CodeGen/arm-apcs-zerolength-bitfield.c b/test/CodeGen/arm-apcs-zerolength-bitfield.c
new file mode 100644
index 000000000000..3f9452539408
--- /dev/null
+++ b/test/CodeGen/arm-apcs-zerolength-bitfield.c
@@ -0,0 +1,240 @@
+// RUN: %clang_cc1 -target-abi apcs-gnu -triple armv7-apple-darwin10 %s -verify
+//
+// Note: gcc forces the alignment to 4 bytes, regardless of the type of the
+// zero length bitfield.
+// rdar://9859156
+
+#include <stddef.h>
+
+struct t1
+{
+ int foo : 1;
+ char : 0;
+ char bar;
+};
+static int arr1_offset[(offsetof(struct t1, bar) == 4) ? 0 : -1];
+static int arr1_sizeof[(sizeof(struct t1) == 8) ? 0 : -1];
+
+struct t2
+{
+ int foo : 1;
+ short : 0;
+ char bar;
+};
+static int arr2_offset[(offsetof(struct t2, bar) == 4) ? 0 : -1];
+static int arr2_sizeof[(sizeof(struct t2) == 8) ? 0 : -1];
+
+struct t3
+{
+ int foo : 1;
+ int : 0;
+ char bar;
+};
+static int arr3_offset[(offsetof(struct t3, bar) == 4) ? 0 : -1];
+static int arr3_sizeof[(sizeof(struct t3) == 8) ? 0 : -1];
+
+struct t4
+{
+ int foo : 1;
+ long : 0;
+ char bar;
+};
+static int arr4_offset[(offsetof(struct t4, bar) == 4) ? 0 : -1];
+static int arr4_sizeof[(sizeof(struct t4) == 8) ? 0 : -1];
+
+struct t5
+{
+ int foo : 1;
+ long long : 0;
+ char bar;
+};
+static int arr5_offset[(offsetof(struct t5, bar) == 4) ? 0 : -1];
+static int arr5_sizeof[(sizeof(struct t5) == 8) ? 0 : -1];
+
+struct t6
+{
+ int foo : 1;
+ char : 0;
+ char bar : 1;
+ char bar2;
+};
+static int arr6_offset[(offsetof(struct t6, bar2) == 5) ? 0 : -1];
+static int arr6_sizeof[(sizeof(struct t6) == 8) ? 0 : -1];
+
+struct t7
+{
+ int foo : 1;
+ short : 0;
+ char bar1 : 1;
+ char bar2;
+};
+static int arr7_offset[(offsetof(struct t7, bar2) == 5) ? 0 : -1];
+static int arr7_sizeof[(sizeof(struct t7) == 8) ? 0 : -1];
+
+struct t8
+{
+ int foo : 1;
+ int : 0;
+ char bar1 : 1;
+ char bar2;
+};
+static int arr8_offset[(offsetof(struct t8, bar2) == 5) ? 0 : -1];
+static int arr8_sizeof[(sizeof(struct t8) == 8) ? 0 : -1];
+
+struct t9
+{
+ int foo : 1;
+ long : 0;
+ char bar1 : 1;
+ char bar2;
+};
+static int arr9_offset[(offsetof(struct t9, bar2) == 5) ? 0 : -1];
+static int arr9_sizeof[(sizeof(struct t9) == 8) ? 0 : -1];
+
+struct t10
+{
+ int foo : 1;
+ long long : 0;
+ char bar1 : 1;
+ char bar2;
+};
+static int arr10_offset[(offsetof(struct t10, bar2) == 5) ? 0 : -1];
+static int arr10_sizeof[(sizeof(struct t10) == 8) ? 0 : -1];
+
+struct t11
+{
+ int foo : 1;
+ long long : 0;
+ char : 0;
+ char bar1 : 1;
+ char bar2;
+};
+static int arr11_offset[(offsetof(struct t11, bar2) == 5) ? 0 : -1];
+static int arr11_sizeof[(sizeof(struct t11) == 8) ? 0 : -1];
+
+struct t12
+{
+ int foo : 1;
+ char : 0;
+ long long : 0;
+ char : 0;
+ char bar;
+};
+static int arr12_offset[(offsetof(struct t12, bar) == 4) ? 0 : -1];
+static int arr12_sizeof[(sizeof(struct t12) == 8) ? 0 : -1];
+
+struct t13
+{
+ char foo;
+ long : 0;
+ char bar;
+};
+static int arr13_offset[(offsetof(struct t13, bar) == 4) ? 0 : -1];
+static int arr13_sizeof[(sizeof(struct t13) == 8) ? 0 : -1];
+
+struct t14
+{
+ char foo1;
+ int : 0;
+ char foo2 : 1;
+ short foo3 : 16;
+ char : 0;
+ short foo4 : 16;
+ char bar1;
+ int : 0;
+ char bar2;
+};
+static int arr14_bar1_offset[(offsetof(struct t14, bar1) == 10) ? 0 : -1];
+static int arr14_bar2_offset[(offsetof(struct t14, bar2) == 12) ? 0 : -1];
+static int arr14_sizeof[(sizeof(struct t14) == 16) ? 0 : -1];
+
+struct t15
+{
+ char foo;
+ char : 0;
+ int : 0;
+ char bar;
+ long : 0;
+ char : 0;
+};
+static int arr15_offset[(offsetof(struct t15, bar) == 4) ? 0 : -1];
+static int arr15_sizeof[(sizeof(struct t15) == 8) ? 0 : -1];
+
+struct t16
+{
+ long : 0;
+ char bar;
+};
+static int arr16_offset[(offsetof(struct t16, bar) == 0) ? 0 : -1];
+static int arr16_sizeof[(sizeof(struct t16) == 4) ? 0 : -1];
+
+struct t17
+{
+ char foo;
+ long : 0;
+ long : 0;
+ char : 0;
+ char bar;
+};
+static int arr17_offset[(offsetof(struct t17, bar) == 4) ? 0 : -1];
+static int arr17_sizeof[(sizeof(struct t17) == 8) ? 0 : -1];
+
+struct t18
+{
+ long : 0;
+ long : 0;
+ char : 0;
+};
+static int arr18_sizeof[(sizeof(struct t18) == 0) ? 0 : -1];
+
+struct t19
+{
+ char foo1;
+ long foo2 : 1;
+ char : 0;
+ long foo3 : 32;
+ char bar;
+};
+static int arr19_offset[(offsetof(struct t19, bar) == 8) ? 0 : -1];
+static int arr19_sizeof[(sizeof(struct t19) == 12) ? 0 : -1];
+
+struct t20
+{
+ short : 0;
+ int foo : 1;
+ long : 0;
+ char bar;
+};
+static int arr20_offset[(offsetof(struct t20, bar) == 4) ? 0 : -1];
+static int arr20_sizeof[(sizeof(struct t20) == 8) ? 0 : -1];
+
+struct t21
+{
+ short : 0;
+ int foo1 : 1;
+ char : 0;
+ int foo2 : 16;
+ long : 0;
+ char bar1;
+ int bar2;
+ long bar3;
+ char foo3 : 8;
+ char : 0;
+ long : 0;
+ int foo4 : 32;
+ short foo5: 1;
+ long bar4;
+ short foo6: 16;
+ short foo7: 16;
+ short foo8: 16;
+};
+static int arr21_bar1_offset[(offsetof(struct t21, bar1) == 8) ? 0 : -1];
+static int arr21_bar2_offset[(offsetof(struct t21, bar2) == 12) ? 0 : -1];
+static int arr21_bar3_offset[(offsetof(struct t21, bar3) == 16) ? 0 : -1];
+static int arr21_bar4_offset[(offsetof(struct t21, bar4) == 32) ? 0 : -1];
+static int arr21_sizeof[(sizeof(struct t21) == 44) ? 0 : -1];
+
+int main() {
+ return 0;
+}
+
diff --git a/test/CodeGen/arm-arguments.c b/test/CodeGen/arm-arguments.c
index 081bc89dcda7..3ae3b8ecd21f 100644
--- a/test/CodeGen/arm-arguments.c
+++ b/test/CodeGen/arm-arguments.c
@@ -28,13 +28,13 @@ struct s4 { struct s4_0 { int f0; } f0; };
struct s4 f4(void) {}
// APCS-GNU: define void @f5(
-// APCS-GNU: struct.s5* sret
+// APCS-GNU: struct.s5* noalias sret
// AAPCS: define arm_aapcscc i32 @f5()
struct s5 { struct { } f0; int f1; };
struct s5 f5(void) {}
// APCS-GNU: define void @f6(
-// APCS-GNU: struct.s6* sret
+// APCS-GNU: struct.s6* noalias sret
// AAPCS: define arm_aapcscc i32 @f6()
struct s6 { int f0[1]; };
struct s6 f6(void) {}
@@ -45,7 +45,7 @@ struct s7 { struct { int : 0; } f0; };
struct s7 f7(void) {}
// APCS-GNU: define void @f8(
-// APCS-GNU: struct.s8* sret
+// APCS-GNU: struct.s8* noalias sret
// AAPCS: define arm_aapcscc void @f8()
struct s8 { struct { int : 0; } f0[1]; };
struct s8 f8(void) {}
@@ -61,7 +61,7 @@ struct s10 { int f0; int : 0; int : 0; };
struct s10 f10(void) {}
// APCS-GNU: define void @f11(
-// APCS-GNU: struct.s11* sret
+// APCS-GNU: struct.s11* noalias sret
// AAPCS: define arm_aapcscc i32 @f11()
struct s11 { int : 0; int f0; };
struct s11 f11(void) {}
@@ -72,7 +72,7 @@ union u12 { char f0; short f1; int f2; };
union u12 f12(void) {}
// APCS-GNU: define void @f13(
-// APCS-GNU: struct.s13* sret
+// APCS-GNU: struct.s13* noalias sret
// FIXME: This should return a float.
// AAPCS-FIXME: darm_aapcscc efine float @f13()
@@ -80,7 +80,7 @@ struct s13 { float f0; };
struct s13 f13(void) {}
// APCS-GNU: define void @f14(
-// APCS-GNU: union.u14* sret
+// APCS-GNU: union.u14* noalias sret
// AAPCS: define arm_aapcscc i32 @f14()
union u14 { float f0; };
union u14 f14(void) {}
@@ -104,13 +104,13 @@ struct s18 { short f0; char f1 : 4; };
struct s18 f18(void) {}
// APCS-GNU: define void @f19(
-// APCS-GNU: struct.s19* sret
+// APCS-GNU: struct.s19* noalias sret
// AAPCS: define arm_aapcscc i32 @f19()
struct s19 { int f0; struct s8 f1; };
struct s19 f19(void) {}
// APCS-GNU: define void @f20(
-// APCS-GNU: struct.s20* sret
+// APCS-GNU: struct.s20* noalias sret
// AAPCS: define arm_aapcscc i32 @f20()
struct s20 { struct s8 f1; int f0; };
struct s20 f20(void) {}
@@ -128,10 +128,10 @@ struct s21 f21(void) {}
// APCS-GNU: define i128 @f27()
// AAPCS: define arm_aapcscc i16 @f22()
// AAPCS: define arm_aapcscc i32 @f23()
-// AAPCS: define arm_aapcscc void @f24({{.*}} sret
-// AAPCS: define arm_aapcscc void @f25({{.*}} sret
-// AAPCS: define arm_aapcscc void @f26({{.*}} sret
-// AAPCS: define arm_aapcscc void @f27({{.*}} sret
+// AAPCS: define arm_aapcscc void @f24({{.*}} noalias sret
+// AAPCS: define arm_aapcscc void @f25({{.*}} noalias sret
+// AAPCS: define arm_aapcscc void @f26({{.*}} noalias sret
+// AAPCS: define arm_aapcscc void @f27({{.*}} noalias sret
_Complex char f22(void) {}
_Complex short f23(void) {}
_Complex int f24(void) {}
@@ -149,7 +149,7 @@ struct s28 f28() {}
struct s29 { _Complex short f0; };
struct s29 f29() {}
-// APCS-GNU: define void @f30({{.*}} sret
-// AAPCS: define arm_aapcscc void @f30({{.*}} sret
+// APCS-GNU: define void @f30({{.*}} noalias sret
+// AAPCS: define arm_aapcscc void @f30({{.*}} noalias sret
struct s30 { _Complex int f0; };
struct s30 f30() {}
diff --git a/test/CodeGen/arm-inline-asm.c b/test/CodeGen/arm-inline-asm.c
new file mode 100644
index 000000000000..0152b050fd7f
--- /dev/null
+++ b/test/CodeGen/arm-inline-asm.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple armv7-apple-darwin9 -emit-llvm -w -o - %s | FileCheck %s
+
+void t1 (void *f, int g) {
+ // CHECK: call void asm "str $1, $0", "=*Q,r"
+ asm("str %1, %0" : "=Q"(f) : "r"(g));
+}
diff --git a/test/CodeGen/arm-vaarg-align.c b/test/CodeGen/arm-vaarg-align.c
new file mode 100644
index 000000000000..1187c022914f
--- /dev/null
+++ b/test/CodeGen/arm-vaarg-align.c
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple arm -target-abi aapcs %s -emit-llvm -o - | FileCheck -check-prefix=AAPCS %s
+// RUN: %clang_cc1 -triple arm -target-abi apcs-gnu %s -emit-llvm -o - | FileCheck -check-prefix=APCS-GNU %s
+/*
+ * Check that va_arg accesses stack according to ABI alignment
+ * long long and double require 8-byte alignment under AAPCS
+ * however, they only require 4-byte alignment under APCS
+ */
+long long t1(int i, ...) {
+ // AAPCS: t1
+ // APCS-GNU: t1
+ __builtin_va_list ap;
+ __builtin_va_start(ap, i);
+ // AAPCS: add i32 %{{.*}} 7
+ // AAPCS: and i32 %{{.*}} -8
+ // APCS-GNU-NOT: add i32 %{{.*}} 7
+ // APCS-GNU-NOT: and i32 %{{.*}} -8
+ long long ll = __builtin_va_arg(ap, long long);
+ __builtin_va_end(ap);
+ return ll;
+}
+double t2(int i, ...) {
+ // AAPCS: t2
+ // APCS-GNU: t2
+ __builtin_va_list ap;
+ __builtin_va_start(ap, i);
+ // AAPCS: add i32 %{{.*}} 7
+ // AAPCS: and i32 %{{.*}} -8
+ // APCS-GNU-NOT: add i32 %{{.*}} 7
+ // APCS-GNU-NOT: and i32 %{{.*}} -8
+ double ll = __builtin_va_arg(ap, double);
+ __builtin_va_end(ap);
+ return ll;
+}
diff --git a/test/CodeGen/arm-vector-arguments.c b/test/CodeGen/arm-vector-arguments.c
index c5ac0a7ad1b7..6bfb2f48a7f1 100644
--- a/test/CodeGen/arm-vector-arguments.c
+++ b/test/CodeGen/arm-vector-arguments.c
@@ -8,7 +8,7 @@
#include <arm_neon.h>
-// CHECK: define void @f0(%struct.int8x16x2_t* sret %agg.result, <16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+// CHECK: define void @f0(%struct.int8x16x2_t* noalias sret %agg.result, <16 x i8> %{{.*}}, <16 x i8> %{{.*}})
int8x16x2_t f0(int8x16_t a0, int8x16_t a1) {
return vzipq_s8(a0, a1);
}
@@ -24,7 +24,7 @@ typedef float T_float32x16 __attribute__ ((__vector_size__ (64)));
T_float32x2 f1_0(T_float32x2 a0) { return a0; }
// CHECK: define <4 x float> @f1_1(<4 x float> %{{.*}})
T_float32x4 f1_1(T_float32x4 a0) { return a0; }
-// CHECK: define void @f1_2(<8 x float>* sret %{{.*}}, <8 x float> %{{.*}})
+// CHECK: define void @f1_2(<8 x float>* noalias sret %{{.*}}, <8 x float> %{{.*}})
T_float32x8 f1_2(T_float32x8 a0) { return a0; }
-// CHECK: define void @f1_3(<16 x float>* sret %{{.*}}, <16 x float> %{{.*}})
+// CHECK: define void @f1_3(<16 x float>* noalias sret %{{.*}}, <16 x float> %{{.*}})
T_float32x16 f1_3(T_float32x16 a0) { return a0; }
diff --git a/test/CodeGen/arrayderef.c b/test/CodeGen/arrayderef.c
new file mode 100644
index 000000000000..effc0a6de4a8
--- /dev/null
+++ b/test/CodeGen/arrayderef.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -emit-llvm -O1 -o - | FileCheck %s
+// The load here was getting lost because this code was close
+// enough to the traditional (wrong) implementation of offsetof
+// to confuse the gcc FE. 8629268.
+
+struct foo {
+ int x;
+ int *y;
+};
+
+struct foo Foo[1];
+
+int * bar(unsigned int ix) {
+// CHECK: load
+ return &Foo->y[ix];
+}
diff --git a/test/CodeGen/asm-reg-var-local.c b/test/CodeGen/asm-reg-var-local.c
new file mode 100644
index 000000000000..9060e120ffc9
--- /dev/null
+++ b/test/CodeGen/asm-reg-var-local.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s
+// Exercise various use cases for local asm "register variables".
+
+int foo() {
+// CHECK: [[A:%[a-zA-Z0-9]+]] = alloca i32
+
+ register int a asm("rsi")=5;
+// CHECK: store i32 5, i32* [[A]]
+
+ asm volatile("; %0 This asm defines rsi" : "=r"(a));
+// CHECK: [[Z:%[a-zA-Z0-9]+]] = call i32 asm sideeffect "; $0 This asm defines rsi", "={rsi},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: store i32 [[Z]], i32* [[A]]
+
+ a = 42;
+// CHECK: store i32 42, i32* [[A]]
+
+ asm volatile("; %0 This asm uses rsi" : : "r"(a));
+// CHECK: [[TMP:%[a-zA-Z0-9]+]] = load i32* [[A]]
+// CHECK: call void asm sideeffect "; $0 This asm uses rsi", "{rsi},~{dirflag},~{fpsr},~{flags}"(i32 [[TMP]])
+
+ return a;
+// CHECK: [[TMP1:%[a-zA-Z0-9]+]] = load i32* [[A]]
+// CHECK: ret i32 [[TMP1]]
+}
diff --git a/test/CodeGen/asm.c b/test/CodeGen/asm.c
index 7199f09e1a3c..019eb9ca3e67 100644
--- a/test/CodeGen/asm.c
+++ b/test/CodeGen/asm.c
@@ -1,4 +1,13 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+
+// PR10415
+__asm__ ("foo1");
+__asm__ ("foo2");
+__asm__ ("foo3");
+// CHECK: module asm "foo1"
+// CHECK-NEXT: module asm "foo2"
+// CHECK-NEXT: module asm "foo3"
+
void t1(int len) {
__asm__ volatile("" : "=&r"(len), "+&r"(len));
}
@@ -191,6 +200,15 @@ unsigned char t23(unsigned char a, unsigned char b) {
return res;
}
+void *t24(char c) {
+ void *addr;
+ // CHECK: @t24
+ // CHECK: zext i8 {{.*}} to i32
+ // CHECK-NEXT: call i8* asm "foobar"
+ __asm__ ("foobar" : "=a" (addr) : "0" (c));
+ return addr;
+}
+
// PR10299 - fpsr, fpcr
void test(void)
diff --git a/test/CodeGen/assign.c b/test/CodeGen/assign.c
index 05141bb0bb60..fc008963c317 100644
--- a/test/CodeGen/assign.c
+++ b/test/CodeGen/assign.c
@@ -21,9 +21,9 @@ void f0() {
// CHECK: define void @f1()
// CHECK: [[x_1:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[y_1:%.*]] = alloca i32, align 4
-// CHECK-NEXT: volatile store i32 1, i32* [[x_1]]
-// CHECK-NEXT: volatile store i32 1, i32* [[x_1]]
-// CHECK-NEXT: volatile store i32 1, i32* [[y_1]]
+// CHECK-NEXT: store volatile i32 1, i32* [[x_1]]
+// CHECK-NEXT: store volatile i32 1, i32* [[x_1]]
+// CHECK-NEXT: store volatile i32 1, i32* [[y_1]]
// CHECK: }
void f1() {
volatile int x, y;
diff --git a/test/CodeGen/atomic-ops.c b/test/CodeGen/atomic-ops.c
new file mode 100644
index 000000000000..e2904cf10e81
--- /dev/null
+++ b/test/CodeGen/atomic-ops.c
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-apple-darwin9 | FileCheck %s
+
+// Basic IRGen tests for __atomic_*
+
+// FIXME: Need to implement __atomic_is_lock_free
+
+typedef enum memory_order {
+ memory_order_relaxed, memory_order_consume, memory_order_acquire,
+ memory_order_release, memory_order_acq_rel, memory_order_seq_cst
+} memory_order;
+
+int fi1(_Atomic(int) *i) {
+ // CHECK: @fi1
+ // CHECK: load atomic i32* {{.*}} seq_cst
+ return __atomic_load(i, memory_order_seq_cst);
+}
+
+void fi2(_Atomic(int) *i) {
+ // CHECK: @fi2
+ // CHECK: store atomic i32 {{.*}} seq_cst
+ __atomic_store(i, 1, memory_order_seq_cst);
+}
+
+void fi3(_Atomic(int) *i) {
+ // CHECK: @fi3
+ // CHECK: atomicrmw and
+ __atomic_fetch_and(i, 1, memory_order_seq_cst);
+}
+
+void fi4(_Atomic(int) *i) {
+ // CHECK: @fi4
+ // CHECK: cmpxchg i32*
+ int cmp = 0;
+ __atomic_compare_exchange_strong(i, &cmp, 1, memory_order_acquire, memory_order_acquire);
+}
+
+float ff1(_Atomic(float) *d) {
+ // CHECK: @ff1
+ // CHECK: load atomic i32* {{.*}} monotonic
+ return __atomic_load(d, memory_order_relaxed);
+}
+
+void ff2(_Atomic(float) *d) {
+ // CHECK: @ff2
+ // CHECK: store atomic i32 {{.*}} release
+ __atomic_store(d, 1, memory_order_release);
+}
+
+float ff3(_Atomic(float) *d) {
+ return __atomic_exchange(d, 2, memory_order_seq_cst);
+}
+
+int* fp1(_Atomic(int*) *p) {
+ // CHECK: @fp1
+ // CHECK: load atomic i32* {{.*}} seq_cst
+ return __atomic_load(p, memory_order_seq_cst);
+}
+
+int* fp2(_Atomic(int*) *p) {
+ // CHECK: @fp2
+ // CHECK: store i32 4
+ // CHECK: atomicrmw add {{.*}} monotonic
+ return __atomic_fetch_add(p, 1, memory_order_relaxed);
+}
+
+_Complex float fc(_Atomic(_Complex float) *c) {
+ // CHECK: @fc
+ // CHECK: atomicrmw xchg i64*
+ return __atomic_exchange(c, 2, memory_order_seq_cst);
+}
+
+typedef struct X { int x; } X;
+X fs(_Atomic(X) *c) {
+ // CHECK: @fs
+ // CHECK: atomicrmw xchg i32*
+ return __atomic_exchange(c, (X){2}, memory_order_seq_cst);
+}
diff --git a/test/CodeGen/atomic.c b/test/CodeGen/atomic.c
index 8ce2d96043f2..c8f4fd09bbc5 100644
--- a/test/CodeGen/atomic.c
+++ b/test/CodeGen/atomic.c
@@ -10,118 +10,75 @@ int atomic(void) {
int cmp = 0;
old = __sync_fetch_and_add(&val, 1);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i32 @llvm.atomic.load.add.i32.p0i32(i32* %val, i32 1)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: atomicrmw add i32* %val, i32 1 seq_cst
old = __sync_fetch_and_sub(&valc, 2);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i8 @llvm.atomic.load.sub.i8.p0i8(i8* %valc, i8 2)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: atomicrmw sub i8* %valc, i8 2 seq_cst
old = __sync_fetch_and_min(&val, 3);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i32 @llvm.atomic.load.min.i32.p0i32(i32* %val, i32 3)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: atomicrmw min i32* %val, i32 3 seq_cst
old = __sync_fetch_and_max(&val, 4);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i32 @llvm.atomic.load.max.i32.p0i32(i32* %val, i32 4)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: atomicrmw max i32* %val, i32 4 seq_cst
old = __sync_fetch_and_umin(&uval, 5u);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i32 @llvm.atomic.load.umin.i32.p0i32(i32* %uval, i32 5)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: atomicrmw umin i32* %uval, i32 5 seq_cst
old = __sync_fetch_and_umax(&uval, 6u);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i32 @llvm.atomic.load.umax.i32.p0i32(i32* %uval, i32 6)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: atomicrmw umax i32* %uval, i32 6 seq_cst
old = __sync_lock_test_and_set(&val, 7);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i32 @llvm.atomic.swap.i32.p0i32(i32* %val, i32 7)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: atomicrmw xchg i32* %val, i32 7 seq_cst
old = __sync_swap(&val, 8);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i32 @llvm.atomic.swap.i32.p0i32(i32* %val, i32 8)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: atomicrmw xchg i32* %val, i32 8 seq_cst
old = __sync_val_compare_and_swap(&val, 4, 1976);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i32 @llvm.atomic.cmp.swap.i32.p0i32(i32* %val, i32 4, i32 1976)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: cmpxchg i32* %val, i32 4, i32 1976 seq_cst
old = __sync_bool_compare_and_swap(&val, 4, 1976);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i32 @llvm.atomic.cmp.swap.i32.p0i32(i32* %val, i32 4, i32 1976)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: cmpxchg i32* %val, i32 4, i32 1976 seq_cst
old = __sync_fetch_and_and(&val, 0x9);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i32 @llvm.atomic.load.and.i32.p0i32(i32* %val, i32 9)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: atomicrmw and i32* %val, i32 9 seq_cst
old = __sync_fetch_and_or(&val, 0xa);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i32 @llvm.atomic.load.or.i32.p0i32(i32* %val, i32 10)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: atomicrmw or i32* %val, i32 10 seq_cst
old = __sync_fetch_and_xor(&val, 0xb);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i32 @llvm.atomic.load.xor.i32.p0i32(i32* %val, i32 11)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: atomicrmw xor i32* %val, i32 11 seq_cst
old = __sync_add_and_fetch(&val, 1);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i32 @llvm.atomic.load.add.i32.p0i32(i32* %val, i32 1)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: atomicrmw add i32* %val, i32 1 seq_cst
old = __sync_sub_and_fetch(&val, 2);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i32 @llvm.atomic.load.sub.i32.p0i32(i32* %val, i32 2)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: atomicrmw sub i32* %val, i32 2 seq_cst
old = __sync_and_and_fetch(&valc, 3);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i8 @llvm.atomic.load.and.i8.p0i8(i8* %valc, i8 3)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: atomicrmw and i8* %valc, i8 3 seq_cst
old = __sync_or_and_fetch(&valc, 4);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i8 @llvm.atomic.load.or.i8.p0i8(i8* %valc, i8 4)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: atomicrmw or i8* %valc, i8 4 seq_cst
old = __sync_xor_and_fetch(&valc, 5);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i8 @llvm.atomic.load.xor.i8.p0i8(i8* %valc, i8 5)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
-
+ // CHECK: atomicrmw xor i8* %valc, i8 5 seq_cst
__sync_val_compare_and_swap((void **)0, (void *)0, (void *)0);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i32 @llvm.atomic.cmp.swap.i32.p0i32(i32* null, i32 0, i32 0)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: cmpxchg i32* null, i32 0, i32 0 seq_cst
if ( __sync_val_compare_and_swap(&valb, 0, 1)) {
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i8 @llvm.atomic.cmp.swap.i8.p0i8(i8* %valb, i8 0, i8 1)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: cmpxchg i8* %valb, i8 0, i8 1 seq_cst
old = 42;
}
__sync_bool_compare_and_swap((void **)0, (void *)0, (void *)0);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i32 @llvm.atomic.cmp.swap.i32.p0i32(i32* null, i32 0, i32 0)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: cmpxchg i32* null, i32 0, i32 0 seq_cst
__sync_lock_release(&val);
- // CHECK: volatile store i32 0, i32*
+ // CHECK: store atomic {{.*}} release, align 4
__sync_synchronize ();
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 false)
+ // CHECK: fence seq_cst
return old;
}
@@ -130,7 +87,7 @@ int atomic(void) {
void release_return(int *lock) {
// Ensure this is actually returning void all the way through.
return __sync_lock_release(lock);
- // CHECK: volatile store i32 0, i32*
+ // CHECK: store atomic {{.*}} release, align 4
}
@@ -138,21 +95,11 @@ void release_return(int *lock) {
// CHECK: @addrspace
void addrspace(int __attribute__((address_space(256))) * P) {
__sync_bool_compare_and_swap(P, 0, 1);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i32 @llvm.atomic.cmp.swap.i32.p256i32(i32 addrspace(256)*{{.*}}, i32 0, i32 1)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
-
-
+ // CHECK: cmpxchg i32 addrspace(256)*{{.*}}, i32 0, i32 1 seq_cst
+
__sync_val_compare_and_swap(P, 0, 1);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i32 @llvm.atomic.cmp.swap.i32.p256i32(i32 addrspace(256)*{{.*}}, i32 0, i32 1)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
-
-
+ // CHECK: cmpxchg i32 addrspace(256)*{{.*}}, i32 0, i32 1 seq_cst
+
__sync_xor_and_fetch(P, 123);
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
- // CHECK: call i32 @llvm.atomic.load.xor.i32.p256i32(i32 addrspace(256)* {{.*}}, i32 123)
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
-
+ // CHECK: atomicrmw xor i32 addrspace(256)*{{.*}}, i32 123 seq_cst
}
-
diff --git a/test/CodeGen/attr-naked.c b/test/CodeGen/attr-naked.c
index bccacc9916f1..2387d288eca8 100644
--- a/test/CodeGen/attr-naked.c
+++ b/test/CodeGen/attr-naked.c
@@ -1,9 +1,16 @@
-// RUN: %clang_cc1 -g -emit-llvm -o %t %s
-// RUN: grep 'naked' %t
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7.0 %s -emit-llvm -o - | FileCheck %s
void t1() __attribute__((naked));
+// Basic functionality check
+// (Note that naked needs to imply noinline to work properly.)
+// CHECK: define void @t1() nounwind noinline naked {
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 {
+__attribute((naked, always_inline)) void t2() {
+}
diff --git a/test/CodeGen/attribute_constructor.c b/test/CodeGen/attribute_constructor.c
new file mode 100644
index 000000000000..c82c263dda19
--- /dev/null
+++ b/test/CodeGen/attribute_constructor.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | grep llvm.global_ctors
+
+void foo() __attribute__((constructor));
+void foo() {
+ bar();
+}
diff --git a/test/CodeGen/avx-shuffle-builtins.c b/test/CodeGen/avx-shuffle-builtins.c
new file mode 100644
index 000000000000..c11780a5e392
--- /dev/null
+++ b/test/CodeGen/avx-shuffle-builtins.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -O3 -triple=x86_64-apple-darwin -target-feature +avx -emit-llvm -o - | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <immintrin.h>
+
+//
+// Test LLVM IR codegen of shuffle instructions
+//
+
+__m256 x(__m256 a, __m256 b) {
+ // Check if the mask is correct
+ // CHECK: shufflevector{{.*}}<i32 3, i32 2, i32 8, i32 11, i32 7, i32 6, i32 12, i32 15>
+ return _mm256_shuffle_ps(a, b, 203);
+}
diff --git a/test/CodeGen/block-3.c b/test/CodeGen/block-3.c
new file mode 100644
index 000000000000..95cb6a735c73
--- /dev/null
+++ b/test/CodeGen/block-3.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -fblocks -triple x86_64-apple-darwin10
+// rdar://10001085
+
+int main() {
+ ^{
+ __attribute__((__blocks__(byref))) int index = ({ int __a; int __b; __a < __b ? __b : __a; });
+ };
+}
diff --git a/test/CodeGen/block-copy.c b/test/CodeGen/block-copy.c
new file mode 100644
index 000000000000..fba76ad21a14
--- /dev/null
+++ b/test/CodeGen/block-copy.c
@@ -0,0 +1,20 @@
+/* RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+ This should compile into a memcpy from a global, not 128 stores. */
+
+
+
+void foo();
+
+float bar() {
+ float lookupTable[] = {-1,-1,-1,0, -1,-1,0,-1, -1,-1,0,1, -1,-1,1,0,
+ -1,0,-1,-1, -1,0,-1,1, -1,0,1,-1, -1,0,1,1,
+ -1,1,-1,0, -1,1,0,-1, -1,1,0,1, -1,1,1,0,
+ 0,-1,-1,-1, 0,-1,-1,1, 0,-1,1,-1, 0,-1,1,1,
+ 1,-1,-1,0, 1,-1,0,-1, 1,-1,0,1, 1,-1,1,0,
+ 1,0,-1,-1, 1,0,-1,1, 1,0,1,-1, 1,0,1,1,
+ 1,1,-1,0, 1,1,0,-1, 1,1,0,1, 1,1,1,0,
+ 0,1,-1,-1, 0,1,-1,1, 0,1,1,-1, 0,1,1,1};
+ // CHECK: memcpy
+ foo(lookupTable);
+}
diff --git a/test/CodeGen/block-decl-merging.c b/test/CodeGen/block-decl-merging.c
deleted file mode 100644
index 1e7a9f4e92cb..000000000000
--- a/test/CodeGen/block-decl-merging.c
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -fblocks -emit-llvm -o - %s | \
-// RUN: FileCheck %s
-
-// CHECK: @_NSConcreteGlobalBlock = extern_weak global
-extern void * _NSConcreteStackBlock[32] __attribute__((weak_import));
-// CHECK: @_NSConcreteStackBlock = extern_weak global
-extern void * _NSConcreteGlobalBlock[32] __attribute__((weak_import));
-extern void _Block_object_dispose(const void *, const int) __attribute__((weak_import));
-// CHECK: declare extern_weak void @_Block_object_assign
-extern void _Block_object_assign(void *, const void *, const int) __attribute__((weak_import));
-// CHECK: declare extern_weak void @_Block_object_dispose
-
-void *x = ^(){};
-
-void f1(void (^a0)(void));
-
-void f0() {
- __block int x;
- f1(^(void){ x = 1; });
-}
diff --git a/test/CodeGen/blocks.c b/test/CodeGen/blocks.c
index b7b6a2d505ef..bef44c369015 100644
--- a/test/CodeGen/blocks.c
+++ b/test/CodeGen/blocks.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o %t -fblocks
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - -fblocks | FileCheck %s
void (^f)(void) = ^{};
// rdar://6768379
@@ -12,7 +12,7 @@ struct s0 {
int a[64];
};
-// RUN: grep 'internal void @__f2_block_invoke_0(.struct.s0\* sret .*, .*, .* byval .*)' %t
+// CHECK: define internal void @__f2_block_invoke_0(%struct.s0* noalias sret {{%.*}}, i8* {{%.*}}, %struct.s0* byval align 4 {{.*}})
struct s0 f2(struct s0 a0) {
return ^(struct s0 a1){ return a1; }(a0);
}
diff --git a/test/CodeGen/builtin-attributes.c b/test/CodeGen/builtin-attributes.c
index 822b8eecf7d7..3781eba26694 100644
--- a/test/CodeGen/builtin-attributes.c
+++ b/test/CodeGen/builtin-attributes.c
@@ -15,3 +15,44 @@ void f1() {
char* f2(char* a, char* b) {
return __builtin_strstr(a, b);
}
+
+// frexp is NOT readnone. It writes to its pointer argument.
+// <rdar://problem/10070234>
+//
+// CHECK: f3
+// CHECK: call double @frexp(double %
+// CHECK-NOT: readnone
+// CHECK: call float @frexpf(float %
+// CHECK-NOT: readnone
+// CHECK: call double @frexpl(double %
+// CHECK-NOT: readnone
+//
+// Same thing for modf and friends.
+//
+// CHECK: call double @modf(double %
+// CHECK-NOT: readnone
+// CHECK: call float @modff(float %
+// CHECK-NOT: readnone
+// CHECK: call double @modfl(double %
+// CHECK-NOT: readnone
+//
+// CHECK: call double @remquo(double %
+// CHECK-NOT: readnone
+// CHECK: call float @remquof(float %
+// CHECK-NOT: readnone
+// CHECK: call double @remquol(double %
+// CHECK-NOT: readnone
+// CHECK: ret
+int f3(double x) {
+ int e;
+ __builtin_frexp(x, &e);
+ __builtin_frexpf(x, &e);
+ __builtin_frexpl(x, &e);
+ __builtin_modf(x, &e);
+ __builtin_modff(x, &e);
+ __builtin_modfl(x, &e);
+ __builtin_remquo(x, x, &e);
+ __builtin_remquof(x, x, &e);
+ __builtin_remquol(x, x, &e);
+ return e;
+}
diff --git a/test/CodeGen/capture-complex-expr-in-block.c b/test/CodeGen/capture-complex-expr-in-block.c
new file mode 100644
index 000000000000..9ce7570a4486
--- /dev/null
+++ b/test/CodeGen/capture-complex-expr-in-block.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -fblocks -triple x86_64-apple-darwin10 | FileCheck %s
+// rdar://10033986
+
+typedef void (^BLOCK)(void);
+int main ()
+{
+ _Complex double c;
+ BLOCK b = ^() {
+ _Complex double z;
+ z = z + c;
+ };
+ b();
+}
+
+// CHECK: define internal void @__main_block_invoke_0
+// CHECK: [[C1:%.*]] = alloca { double, double }, align 8
+// CHECK: [[RP:%.*]] = getelementptr inbounds { double, double }* [[C1]], i32 0, i32 0
+// CHECK-NEXT: [[R:%.*]] = load double* [[RP]]
+// CHECK-NEXT: [[IP:%.*]] = getelementptr inbounds { double, double }* [[C1]], i32 0, i32 1
+// CHECK-NEXT: [[I:%.*]] = load double* [[IP]]
diff --git a/test/CodeGen/char-literal.c b/test/CodeGen/char-literal.c
index 322041c0049a..5963ede392af 100644
--- a/test/CodeGen/char-literal.c
+++ b/test/CodeGen/char-literal.c
@@ -1,35 +1,93 @@
-// RUN: %clang_cc1 -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s
-// Runs in c++ mode so that wchar_t is available.
+// 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
+
+#include <stddef.h>
int main() {
- // CHECK: store i8 97
+ // CHECK-C: store i8 97
+ // CHECK-CPP0X: store i8 97
char a = 'a';
// Should pick second character.
- // CHECK: store i8 98
+ // CHECK-C: store i8 98
+ // CHECK-CPP0X: store i8 98
char b = 'ab';
- // CHECK: store i32 97
+ // CHECK-C: store i32 97
+ // CHECK-CPP0X: store i32 97
wchar_t wa = L'a';
// Should pick second character.
- // CHECK: store i32 98
+ // CHECK-C: store i32 98
+ // CHECK-CPP0X: store i32 98
wchar_t wb = L'ab';
+#if __cplusplus >= 201103L
+ // CHECK-CPP0X: store i16 97
+ char16_t ua = u'a';
+
+ // Should pick second character.
+ // CHECK-CPP0X: store i16 98
+ char16_t ub = u'ab';
+
+ // CHECK-CPP0X: store i32 97
+ char32_t Ua = U'a';
+
+ // Should pick second character.
+ // CHECK-CPP0X: store i32 98
+ char32_t Ub = U'ab';
+#endif
+
// Should pick last character and store its lowest byte.
// This does not match gcc, which takes the last character, converts it to
// utf8, and then picks the second-lowest byte of that (they probably store
// the utf8 in uint16_ts internally and take the lower byte of that).
- // CHECK: store i8 48
+ // CHECK-C: store i8 48
+ // CHECK-CPP0X: store i8 48
char c = '\u1120\u0220\U00102030';
- // CHECK: store i32 61451
+ // CHECK-C: store i32 61451
+ // CHECK-CPP0X: store i32 61451
wchar_t wc = L'\uF00B';
- // CHECK: store i32 1110027
+#if __cplusplus >= 201103L
+ // -4085 == 0xf00b
+ // CHECK-CPP0X: store i16 -4085
+ char16_t uc = u'\uF00B';
+
+ // CHECK-CPP0X: store i32 61451
+ char32_t Uc = U'\uF00B';
+#endif
+
+ // CHECK-C: store i32 1110027
+ // CHECK-CPP0X: store i32 1110027
wchar_t wd = L'\U0010F00B';
+#if __cplusplus >= 201103L
+ // Should take lower word of the 4byte UNC sequence. This does not match
+ // gcc. I don't understand what gcc does (it looks like it converts to utf16,
+ // then takes the second (!) utf16 word, swaps the lower two nibbles, and
+ // stores that?).
+ // CHECK-CPP0X: store i16 -4085
+ char16_t ud = u'\U0010F00B'; // has utf16 encoding dbc8 dcb0
+
+ // CHECK-CPP0X: store i32 1110027
+ char32_t Ud = U'\U0010F00B';
+#endif
+
// Should pick second character.
- // CHECK: store i32 1110027
+ // CHECK-C: store i32 1110027
+ // CHECK-CPP0X: store i32 1110027
wchar_t we = L'\u1234\U0010F00B';
+
+#if __cplusplus >= 201103L
+ // Should pick second character.
+ // CHECK-CPP0X: store i16 -4085
+ char16_t ue = u'\u1234\U0010F00B';
+
+ // Should pick second character.
+ // CHECK-CPP0X: store i32 1110027
+ char32_t Ue = U'\u1234\U0010F00B';
+#endif
}
diff --git a/test/CodeGen/complex-init-list.c b/test/CodeGen/complex-init-list.c
new file mode 100644
index 000000000000..819d4f9432de
--- /dev/null
+++ b/test/CodeGen/complex-init-list.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 | FileCheck %s
+
+// This file tests the clang extension which allows initializing the components
+// of a complex number individually using an initialization list. (There is a
+// extensive description and test in test/Sema/complex-init-list.c.)
+
+_Complex float x = { 1.0f, 1.0f/0.0f };
+// CHECK: @x = global { float, float } { float 1.000000e+00, float 0x7FF0000000000000 }, align 4
+
+_Complex float f(float x, float y) { _Complex float z = { x, y }; return z; }
+// CHECK: define <2 x float> @f
+// CHECK: alloca { float, float } \ No newline at end of file
diff --git a/test/CodeGen/debug-dead-local-var.c b/test/CodeGen/debug-dead-local-var.c
new file mode 100644
index 000000000000..f9ca8f2f297d
--- /dev/null
+++ b/test/CodeGen/debug-dead-local-var.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -mllvm -asm-verbose -S -O2 -g %s -o - | FileCheck %s
+// Radar 8122864
+
+// Code is not generated for function foo, but preserve type information of
+// local variable xyz.
+static void foo() {
+// CHECK: DW_TAG_structure_type
+ struct X { int a; int b; } xyz;
+}
+
+int bar() {
+ foo();
+ return 1;
+}
diff --git a/test/CodeGen/debug-info-iv.c b/test/CodeGen/debug-info-iv.c
index 92654738cfc5..1d9bf32c2cda 100644
--- a/test/CodeGen/debug-info-iv.c
+++ b/test/CodeGen/debug-info-iv.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-darwin-apple -Os -S -g -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -Os -S -g -o - %s | FileCheck %s
int calculate(int);
static void test_indvars(int *Array1, int Array2[100][200]) {
@@ -14,22 +14,22 @@ static void test_indvars(int *Array1, int Array2[100][200]) {
for (i = 13; i < 100; i++)
for (j = 0; j < 100; j+=3) /* 2d array access */
Array2[i][j/3] = Array2[i][i];
-}
+}
int main() {
int Array[100][200], i, j;
double sum = 0.0;
-
+
for (i=0; i < 100; i+=2)
for (j=0; j < 200; j++)
Array[i][j] = 0;
test_indvars(Array[0], Array);
-//CHECK: .loc 2 30 3
+//CHECK: .loc 2 30 8
for (i=0; i < 100; i+=2)
for (j=0; j < 200; j++)
sum += Array[i][j];
-
+
return calculate(sum);
}
diff --git a/test/CodeGen/debug-info-line.c b/test/CodeGen/debug-info-line.c
index b255d90b34c8..9e6e9714aa47 100644
--- a/test/CodeGen/debug-info-line.c
+++ b/test/CodeGen/debug-info-line.c
@@ -1,8 +1,9 @@
-// RUN: %clang -emit-llvm -S -g %s -o %t
-// RUN: grep DW_TAG_lexical_block %t | count 3
+// RUN: %clang -emit-llvm -S -g %s -o - | FileCheck %s
// Radar 8396182
-// There are three lexical blocks in this test case.
+// 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.
int foo() {
int i = 1;
@@ -13,3 +14,10 @@ int foo() {
# 5 "m.c" 2
return i + j;
}
+
+// CHECK: DW_TAG_lexical_block
+// CHECK: DW_TAG_lexical_block
+// CHECK: !"m.h"
+// CHECK: DW_TAG_lexical_block
+// CHECK: !"m.c"
+// CHECK-NOT: DW_TAG_lexical_block
diff --git a/test/CodeGen/debug-info-line3.c b/test/CodeGen/debug-info-line3.c
new file mode 100644
index 000000000000..645ffb9e7485
--- /dev/null
+++ b/test/CodeGen/debug-info-line3.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -g -S -emit-llvm %s -o - | FileCheck %s
+
+void func(char c, char* d)
+{
+ *d = c + 1;
+ return;
+
+
+
+
+
+
+}
+
+// CHECK: ret void, !dbg !19
+// CHECK: !19 = metadata !{i32 6,
diff --git a/test/CodeGen/debug-info-member.c b/test/CodeGen/debug-info-member.c
index 54066fa53060..43d26f858d2c 100644
--- a/test/CodeGen/debug-info-member.c
+++ b/test/CodeGen/debug-info-member.c
@@ -1,3 +1,3 @@
-// RUN: %clang_cc1 -emit-llvm -g < %s | grep DW_TAG_member | grep \!3
+// RUN: %clang_cc1 -emit-llvm -g < %s | grep DW_TAG_member
struct A { int x; } a;
diff --git a/test/CodeGen/decl.c b/test/CodeGen/decl.c
index 21b75797f0c3..2065e3364bcd 100644
--- a/test/CodeGen/decl.c
+++ b/test/CodeGen/decl.c
@@ -1,11 +1,11 @@
// RUN: %clang_cc1 -w -emit-llvm < %s | FileCheck %s
// CHECK: @test1.x = internal constant [12 x i32] [i32 1
-// CHECK: @test2.x = internal unnamed_addr constant [13 x i32] [i32 1,
+// CHECK: @test2.x = private unnamed_addr constant [13 x i32] [i32 1,
// CHECK: @test5w = global { i32, [4 x i8] } { i32 2, [4 x i8] undef }
// CHECK: @test5y = global { double } { double 7.300000e+0{{[0]*}}1 }
-// CHECK: @test6.x = internal unnamed_addr constant %struct.SelectDest { i8 1, i8 2, i32 3, i32 0 }
+// CHECK: @test6.x = private unnamed_addr constant %struct.SelectDest { i8 1, i8 2, i32 3, i32 0 }
// CHECK: @test7 = global [2 x %struct.test7s] [%struct.test7s { i32 1, i32 2 }, %struct.test7s { i32 4, i32 0 }]
@@ -24,7 +24,7 @@ void test2() {
// This should codegen as a "@test2.x" global + memcpy.
int x[] = { 1, 2, 3, 4, 6, 8, 9, 10, 123, 231, 123,23, 24 };
foo(x);
-
+
// CHECK: @test2()
// CHECK: %x = alloca [13 x i32]
// CHECK: call void @llvm.memcpy
@@ -36,7 +36,7 @@ void test3() {
// This should codegen as a memset.
int x[100] = { 0 };
foo(x);
-
+
// CHECK: @test3()
// CHECK: %x = alloca [100 x i32]
// CHECK: call void @llvm.memset
diff --git a/test/CodeGen/exact-div-expr.c b/test/CodeGen/exact-div-expr.c
new file mode 100644
index 000000000000..a2c12a0b3f6e
--- /dev/null
+++ b/test/CodeGen/exact-div-expr.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -O1 | grep ashr
+// RUN: %clang_cc1 -emit-llvm %s -o - -O1 | not grep sdiv
+
+long long test(int *A, int *B) {
+ return A-B;
+}
diff --git a/test/CodeGen/exceptions.c b/test/CodeGen/exceptions.c
index 018b975395b9..20eb706a03b1 100644
--- a/test/CodeGen/exceptions.c
+++ b/test/CodeGen/exceptions.c
@@ -14,6 +14,8 @@ void test1() {
// CHECK-ARM: invoke arm_aapcscc void @test1_helper(
test1_helper(^(int v) { x = v; });
- // CHECK: call {{.*}} @llvm.eh.selector({{.*}}, i8* bitcast (i32 (...)* @__gcc_personality_v0 to i8*)
- // CHECK-ARM: call {{.*}} @llvm.eh.selector({{.*}}, i8* bitcast (i32 (...)* @__gcc_personality_sj0 to i8*)
+ // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gcc_personality_v0 to i8*)
+ // CHECK-NEXT: cleanup
+ // CHECK-ARM: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gcc_personality_sj0 to i8*)
+ // CHECK-ARM-NEXT: cleanup
}
diff --git a/test/CodeGen/extern-weak.c b/test/CodeGen/extern-weak.c
new file mode 100644
index 000000000000..6a78a33af65a
--- /dev/null
+++ b/test/CodeGen/extern-weak.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -O3 -emit-llvm -o - %s | grep extern_weak
+// RUN: %clang_cc1 -O3 -emit-llvm -o - %s | llc
+
+#if !defined(__linux__) && !defined(__FreeBSD__) && \
+ !defined(__OpenBSD__) && !defined(__CYGWIN__) && !defined(__DragonFly__)
+void foo() __attribute__((weak_import));
+#else
+void foo() __attribute__((weak));
+#endif
+
+void bar() { foo(); }
+
diff --git a/test/CodeGen/fp16-ops.c b/test/CodeGen/fp16-ops.c
new file mode 100644
index 000000000000..cbbfb884df50
--- /dev/null
+++ b/test/CodeGen/fp16-ops.c
@@ -0,0 +1,283 @@
+// RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-linux-gnueabi %s | FileCheck %s
+typedef unsigned cond_t;
+
+volatile cond_t test;
+volatile __fp16 h0 = 0.0, h1 = 1.0, h2;
+volatile float f0, f1, f2;
+
+void foo(void) {
+ // CHECK: define void @foo()
+
+ // Check unary ops
+
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK fptoi float
+ test = (h0);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp une float
+ test = (!h1);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fsub float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1 = -h1;
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1 = +h1;
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fadd float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1++;
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fadd float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ ++h1;
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fadd float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ --h1;
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fadd float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1--;
+
+ // Check binary ops with various operands
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fmul float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1 = h0 * h2;
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call i16 @llvm.convert.to.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fmul float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1 = h0 * (__fp16) -2.0;
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fmul float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1 = h0 * f2;
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fmul float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1 = f0 * h2;
+
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fdiv float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1 = (h0 / h2);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fdiv float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1 = (h0 / (__fp16) -2.0);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fdiv float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1 = (h0 / f2);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fdiv float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1 = (f0 / h2);
+
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fadd float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1 = (h2 + h0);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fadd float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1 = ((__fp16)-2.0 + h0);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fadd float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1 = (h2 + f0);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fadd float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1 = (f2 + h0);
+
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fsub float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1 = (h2 - h0);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fsub float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1 = ((__fp16)-2.0 - h0);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fsub float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1 = (h2 - f0);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fsub float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1 = (f2 - h0);
+
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp olt
+ test = (h2 < h0);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp olt
+ test = (h2 < (__fp16)42.0);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp olt
+ test = (h2 < f0);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp olt
+ test = (f2 < h0);
+
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp ogt
+ test = (h0 > h2);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp ogt
+ test = ((__fp16)42.0 > h2);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp ogt
+ test = (h0 > f2);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp ogt
+ test = (f0 > h2);
+
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp ole
+ test = (h2 <= h0);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp ole
+ test = (h2 <= (__fp16)42.0);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp ole
+ test = (h2 <= f0);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp ole
+ test = (f2 <= h0);
+
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp oge
+ test = (h0 >= h2);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp oge
+ test = (h0 >= (__fp16)-2.0);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp oge
+ test = (h0 >= f2);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp oge
+ test = (f0 >= h2);
+
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp oeq
+ test = (h1 == h2);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp oeq
+ test = (h1 == (__fp16)1.0);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp oeq
+ test = (h1 == f1);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp oeq
+ test = (f1 == h1);
+
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp une
+ test = (h1 != h2);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp une
+ test = (h1 != (__fp16)1.0);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp une
+ test = (h1 != f1);
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp une
+ test = (f1 != h1);
+
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fcmp une
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h1 = (h1 ? h2 : h0);
+ // Check assignments (inc. compound)
+ h0 = h1;
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h0 = (__fp16)-2.0;
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h0 = f0;
+
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fadd float
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h0 += h1;
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fadd
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h0 += (__fp16)1.0;
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fadd
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h0 += f2;
+
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fsub
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h0 -= h1;
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fsub
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h0 -= (__fp16)1.0;
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fsub
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h0 -= f2;
+
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fmul
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h0 *= h1;
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fmul
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h0 *= (__fp16)1.0;
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fmul
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h0 *= f2;
+
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fdiv
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h0 /= h1;
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fdiv
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h0 /= (__fp16)1.0;
+ // CHECK: call float @llvm.convert.from.fp16
+ // CHECK: fdiv
+ // CHECK: call i16 @llvm.convert.to.fp16
+ h0 /= f2;
+}
diff --git a/test/CodeGen/func-aligned.c b/test/CodeGen/func-aligned.c
new file mode 100644
index 000000000000..f8a4a29d9d2c
--- /dev/null
+++ b/test/CodeGen/func-aligned.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+// rdar://7270273
+void foo() __attribute__((aligned (64)));
+void foo() {
+// CHECK: define void @foo() {{.*}} align 64
+}
diff --git a/test/CodeGen/funccall.c b/test/CodeGen/funccall.c
new file mode 100644
index 000000000000..9735e3470570
--- /dev/null
+++ b/test/CodeGen/funccall.c
@@ -0,0 +1,17 @@
+
+static int q;
+
+void foo() {
+ int t = q;
+ q = t + 1;
+}
+int main() {
+ q = 0;
+ foo();
+ q = q - 1;
+
+ return q;
+}
+
+// This is the source that corresponds to funccall.ll
+// RUN: echo foo
diff --git a/test/CodeGen/function-attributes.c b/test/CodeGen/function-attributes.c
index 3a1030a61b90..6cbf40ba220f 100644
--- a/test/CodeGen/function-attributes.c
+++ b/test/CodeGen/function-attributes.c
@@ -89,3 +89,25 @@ void f15(void) {
void __attribute__((force_align_arg_pointer)) f16(void) {
}
+// PR11038
+// CHECK: define void @f18()
+// CHECK: returns_twice
+// CHECK: {
+// CHECK: call void @f17()
+// CHECK: returns_twice
+// CHECK: ret void
+__attribute__ ((returns_twice)) void f17(void);
+__attribute__ ((returns_twice)) void f18(void) {
+ f17();
+}
+
+// CHECK: define void @f19()
+// CHECK: {
+// CHECK: call i32 @setjmp(i32* null)
+// CHECK: returns_twice
+// CHECK: ret void
+typedef int jmp_buf[((9 * 2) + 3 + 16)];
+int setjmp(jmp_buf);
+void f19(void) {
+ setjmp(0);
+}
diff --git a/test/CodeGen/functions.c b/test/CodeGen/functions.c
index e51f93e57411..28e4bd0c8296 100644
--- a/test/CodeGen/functions.c
+++ b/test/CodeGen/functions.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - -verify | FileCheck %s
+// RUN: %clang_cc1 %s -triple i386-unknown-unknown -emit-llvm -o - -verify | FileCheck %s
int g();
@@ -24,7 +24,7 @@ void f0() {}
void f1();
void f2(void) {
-// CHECK: call void @f1()
+// CHECK: call void bitcast (void ()* @f1 to void (i32, i32, i32)*)(i32 1, i32 2, i32 3)
f1(1, 2, 3);
}
// CHECK: define void @f1()
diff --git a/test/CodeGen/hidden-visibility.c b/test/CodeGen/hidden-visibility.c
new file mode 100644
index 000000000000..65e6616ef19f
--- /dev/null
+++ b/test/CodeGen/hidden-visibility.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: hidden global
+int X __attribute__ ((__visibility__ ("hidden"))) = 123;
diff --git a/test/CodeGen/implicit-arg.c b/test/CodeGen/implicit-arg.c
new file mode 100644
index 000000000000..52ab58ec9801
--- /dev/null
+++ b/test/CodeGen/implicit-arg.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 %s -emit-llvm -O0 -o -
+// RUN: %clang_cc1 %s -emit-llvm -O1 -o -
+// rdar://6518089
+
+static int bar();
+void foo() {
+ int a = bar();
+}
+int bar(unsigned a) {
+}
diff --git a/test/CodeGen/inline-asm-mrv.c b/test/CodeGen/inline-asm-mrv.c
new file mode 100644
index 000000000000..929dd90fde60
--- /dev/null
+++ b/test/CodeGen/inline-asm-mrv.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -O | not grep alloca
+// PR2094
+
+int sad16_sse2(void *v, unsigned char *blk2, unsigned char *blk1,
+ int stride, int h) {
+ int ret;
+ asm volatile( "%0 %1 %2 %3"
+ : "+r" (h), "+r" (blk1), "+r" (blk2)
+ : "r" ((long)stride));
+ asm volatile("set %0 %1" : "=r"(ret) : "r"(blk1));
+ return ret;
+}
diff --git a/test/CodeGen/inline.c b/test/CodeGen/inline.c
index 96f9c5c9d4bb..6bc583df8c96 100644
--- a/test/CodeGen/inline.c
+++ b/test/CodeGen/inline.c
@@ -12,9 +12,10 @@
// 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: echo "\nC99 tests:"
-// RUN: %clang %s -O1 -emit-llvm -S -o %t -std=c99
+// RUN: %clang %s -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
@@ -27,6 +28,8 @@
// 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 available_externally i.. @strlcpy" %t
// RUN: echo "\nC++ tests:"
// RUN: %clang -x c++ %s -O1 -emit-llvm -S -o %t -std=c++98
@@ -84,3 +87,18 @@ extern __inline int __attribute__ ((__gnu_inline__)) test5(void)
}
void test_test5() { test5(); }
+
+// PR10233
+
+__inline int test6() { return 0; }
+extern int test6();
+
+
+// No PR#, but this once crashed clang in C99 mode due to buggy extern inline
+// redeclaration detection.
+void test7() { }
+void test7();
+
+// PR11062; the fact that the function is named strlcpy matters here.
+inline __typeof(sizeof(int)) strlcpy(char *dest, const char *src, __typeof(sizeof(int)) size) { return 3; }
+void test8() { strlcpy(0,0,0); }
diff --git a/test/CodeGen/kr-call.c b/test/CodeGen/kr-call.c
new file mode 100644
index 000000000000..ea4e3d3d70f0
--- /dev/null
+++ b/test/CodeGen/kr-call.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple s390x-unknown-linux -emit-llvm -o - %s | FileCheck %s
+
+// Test that we don't crash. The s390x-unknown-linux target happens
+// to need to set a sext argument attribute on this call, and we need
+// to make sure that rewriting it correctly keeps that attribute.
+void test0_helper();
+void test0() {
+ // CHECK: call void bitcast (void ()* @test0_helper to void (i32)*)(i32 signext 1)
+ test0_helper(1);
+}
+void test0_helper() {}
+
diff --git a/test/CodeGen/libcalls-d.c b/test/CodeGen/libcalls-d.c
new file mode 100644
index 000000000000..b375f2bb83a6
--- /dev/null
+++ b/test/CodeGen/libcalls-d.c
@@ -0,0 +1,16 @@
+// llvm-gcc -O1+ should run simplify libcalls, O0 shouldn't
+// and -fno-builtins shouldn't.
+// -fno-math-errno should emit an llvm intrinsic, -fmath-errno should not.
+// RUN: %clang_cc1 %s -emit-llvm -fno-math-errno -O0 -o - | grep {call.*exp2\\.f64}
+// RUN: %clang_cc1 %s -emit-llvm -fmath-errno -O0 -o - | grep {call.*exp2}
+// RUN: %clang_cc1 %s -emit-llvm -O1 -o - | grep {call.*ldexp}
+// RUN: %clang_cc1 %s -emit-llvm -O3 -fno-builtin -o - | grep {call.*exp2}
+
+// clang doesn't support this yet.
+// XFAIL: *
+
+double exp2(double);
+
+double t4(unsigned char x) {
+ return exp2(x);
+}
diff --git a/test/CodeGen/libcalls-ld.c b/test/CodeGen/libcalls-ld.c
new file mode 100644
index 000000000000..2758761b5ee1
--- /dev/null
+++ b/test/CodeGen/libcalls-ld.c
@@ -0,0 +1,19 @@
+// llvm-gcc -O1+ should run simplify libcalls, O0 shouldn't
+// and -fno-builtins shouldn't.
+// -fno-math-errno should emit an llvm intrinsic, -fmath-errno should not.
+// RUN: %clang_cc1 %s -emit-llvm -fno-math-errno -O0 -o - | grep {call.*exp2\\..*f}
+// RUN: %clang_cc1 %s -emit-llvm -fmath-errno -O0 -o - | grep {call.*exp2l}
+// RUN: %clang_cc1 %s -emit-llvm -O1 -o - | grep {call.*ldexp}
+// RUN: %clang_cc1 %s -emit-llvm -O3 -fno-builtin -o - | grep {call.*exp2l}
+
+// clang doesn't support this yet.
+// XFAIL: *
+
+// If this fails for you because your target doesn't support long double,
+// please xfail the test.
+
+long double exp2l(long double);
+
+long double t4(unsigned char x) {
+ return exp2l(x);
+}
diff --git a/test/CodeGen/libcalls.c b/test/CodeGen/libcalls.c
index 5ff684fd5b66..458c591837ff 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) readnone
-// CHECK-NO: declare double @sqrt(double) readnone
-// CHECK-NO: declare x86_fp80 @sqrtl(x86_fp80) readnone
+// 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-YES: define void @test_pow
// CHECK-NO: define void @test_pow
diff --git a/test/CodeGen/microsoft-call-conv.c b/test/CodeGen/microsoft-call-conv.c
index 95f5fa3f83b5..390c3be05e61 100644
--- a/test/CodeGen/microsoft-call-conv.c
+++ b/test/CodeGen/microsoft-call-conv.c
@@ -46,5 +46,5 @@ int main(void) {
void __stdcall f7(foo) int foo; {}
void f8(void) {
f7(0);
- // CHECK: call x86_stdcallcc void (...)* bitcast
+ // CHECK: call x86_stdcallcc void @f7(i32 0)
}
diff --git a/test/CodeGen/misaligned-param.c b/test/CodeGen/misaligned-param.c
new file mode 100644
index 000000000000..53f1f290f5c2
--- /dev/null
+++ b/test/CodeGen/misaligned-param.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 %s -triple i386-apple-darwin -emit-llvm -o - | FileCheck %s
+// Misaligned parameter must be memcpy'd to correctly aligned temporary.
+
+struct s { int x; long double y; };
+long double foo(struct s x, int i, struct s y) {
+// CHECK: foo
+// CHECK: %x = alloca %struct.s, align 16
+// CHECK: %y = alloca %struct.s, align 16
+// CHECK: memcpy
+// CHECK: memcpy
+// CHECK: bar
+ return bar(&x, &y);
+}
diff --git a/test/CodeGen/mrtd.c b/test/CodeGen/mrtd.c
index 2cc71bb0086f..d7729a525068 100644
--- a/test/CodeGen/mrtd.c
+++ b/test/CodeGen/mrtd.c
@@ -4,7 +4,7 @@ void baz(int arg);
// CHECK: define x86_stdcallcc void @foo(i32 %arg) nounwind
void foo(int arg) {
-// CHECK: call x86_stdcallcc i32 (...)* @bar(i32
+// CHECK: call x86_stdcallcc i32 bitcast (i32 (...)* @bar to i32 (i32)*)(
bar(arg);
// CHECK: call x86_stdcallcc void @baz(i32
baz(arg);
diff --git a/test/CodeGen/ms_struct-bitfield-1.c b/test/CodeGen/ms_struct-bitfield-1.c
index 0b15a24f0337..25c0ba233261 100644
--- a/test/CodeGen/ms_struct-bitfield-1.c
+++ b/test/CodeGen/ms_struct-bitfield-1.c
@@ -4,26 +4,26 @@
#define ATTR __attribute__((__ms_struct__))
struct {
- unsigned int bf_1 : 12;
- unsigned int : 0;
- unsigned int bf_2 : 12;
+ unsigned int bf_1 : 12;
+ unsigned int : 0;
+ unsigned int bf_2 : 12;
} ATTR t1;
static int a1[(sizeof(t1) == 8) -1];
struct
{
- char foo : 4;
- short : 0;
- char bar;
+ char foo : 4;
+ short : 0;
+ char bar;
} ATTR t2;
static int a2[(sizeof(t2) == 4) -1];
#pragma ms_struct on
struct
{
- char foo : 4;
- short : 0;
- char bar;
+ char foo : 4;
+ short : 0;
+ char bar;
} t3;
#pragma ms_struct off
static int a3[(sizeof(t3) == 4) -1];
@@ -45,47 +45,47 @@ static int a5[(sizeof(t5) == 4) -1];
struct
{
- char foo : 4;
- short : 0;
- long :0;
- char bar;
+ char foo : 4;
+ short : 0;
+ long : 0;
+ char bar;
} ATTR t6;
static int a6[(sizeof(t6) == 4) -1];
struct
{
- char foo : 4;
- long :0;
- short : 0;
- char bar;
+ char foo : 4;
+ long : 0;
+ short : 0;
+ char bar;
} ATTR t7;
static int a7[(sizeof(t7) == 16) -1];
struct
{
- char foo : 4;
- short : 0;
- long :0;
- char bar:7;
+ char foo : 4;
+ short : 0;
+ long : 0;
+ char bar:7;
} ATTR t8;
static int a8[(sizeof(t8) == 4) -1];
struct
{
- char foo : 4;
- long :0;
- short : 0;
- char bar: 8;
+ char foo : 4;
+ long : 0;
+ short : 0;
+ char bar: 8;
} ATTR t9;
static int a9[(sizeof(t9) == 16) -1];
struct
{
- char foo : 4;
- char : 0;
- short : 0;
- int : 0;
- long :0;
- char bar;
+ char foo : 4;
+ char : 0;
+ short : 0;
+ int : 0;
+ long :0;
+ char bar;
} ATTR t10;
static int a10[(sizeof(t10) == 2) -1];
diff --git a/test/CodeGen/pascal-wchar-string.c b/test/CodeGen/pascal-wchar-string.c
index 7a03463d2cf1..a6b619643e1f 100644
--- a/test/CodeGen/pascal-wchar-string.c
+++ b/test/CodeGen/pascal-wchar-string.c
@@ -35,7 +35,7 @@ int main(int argc, char* argv[])
// PR8856 - -fshort-wchar makes wchar_t be unsigned.
// CHECK: @test2
-// CHECK: volatile store i32 1, i32* %isUnsigned
+// CHECK: store volatile i32 1, i32* %isUnsigned
void test2() {
volatile int isUnsigned = (wchar_t)-1 > (wchar_t)0;
}
diff --git a/test/CodeGen/pr2394.c b/test/CodeGen/pr2394.c
new file mode 100644
index 000000000000..e43281a3cd3e
--- /dev/null
+++ b/test/CodeGen/pr2394.c
@@ -0,0 +1,7 @@
+// 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
+ return g->a;
+}
diff --git a/test/CodeGen/pr3518.c b/test/CodeGen/pr3518.c
new file mode 100644
index 000000000000..f96a5aa65f19
--- /dev/null
+++ b/test/CodeGen/pr3518.c
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 %s -emit-llvm -O0 -o - | FileCheck %s
+// PR 3518
+// Some of the objects were coming out as unintialized (external) before 3518
+// was fixed. Internal names are different between llvm-gcc and clang so they
+// are not tested.
+
+extern void abort (void);
+
+// CHECK: @.compoundliteral = internal global %struct.A { i32 1, i32 2 }
+// CHECK: @.compoundliteral1 = internal global %struct.A { i32 3, i32 4 }
+// CHECK: @.compoundliteral2 = internal global %struct.B { %struct.A* @.compoundliteral, %struct.A* @.compoundliteral1 }
+// CHECK: @.compoundliteral3 = internal global %struct.A { i32 5, i32 6 }
+
+struct A { int i; int j; };
+struct B { struct A *a; struct A *b; };
+struct C { struct B *c; struct A *d; };
+struct C e = { &(struct B) { &(struct A) { 1, 2 }, &(struct A) { 3, 4 } }, &(struct A) { 5, 6 } };
+
+int
+main (void)
+{
+ if (e.c->a->i != 1 || e.c->a->j != 2)
+ abort ();
+ if (e.c->b->i != 3 || e.c->b->j != 4)
+ abort ();
+ if (e.d->i != 5 || e.d->j != 6)
+ abort ();
+ return 0;
+}
diff --git a/test/CodeGen/pr4349.c b/test/CodeGen/pr4349.c
new file mode 100644
index 000000000000..94b4fbd5db46
--- /dev/null
+++ b/test/CodeGen/pr4349.c
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 %s -emit-llvm -O0 -o - | FileCheck %s
+// PR 4349
+
+union reg
+{
+ unsigned char b[2][2];
+ unsigned short w[2];
+ unsigned int d;
+};
+struct cpu
+{
+ union reg pc;
+};
+extern struct cpu cpu;
+struct svar
+{
+ void *ptr;
+};
+// CHECK: @svars1 = global [1 x %struct.svar] [%struct.svar { i8* bitcast (%struct.cpu* @cpu to i8*) }]
+struct svar svars1[] =
+{
+ { &((cpu.pc).w[0]) }
+};
+// CHECK: @svars2 = global [1 x %struct.svar] [%struct.svar { i8* getelementptr (i8* bitcast (%struct.cpu* @cpu to i8*), i64 1) }]
+struct svar svars2[] =
+{
+ { &((cpu.pc).b[0][1]) }
+};
+// CHECK: @svars3 = global [1 x %struct.svar] [%struct.svar { i8* getelementptr (i8* bitcast (%struct.cpu* @cpu to i8*), i64 2) }]
+struct svar svars3[] =
+{
+ { &((cpu.pc).w[1]) }
+};
+// CHECK: @svars4 = global [1 x %struct.svar] [%struct.svar { i8* getelementptr (i8* bitcast (%struct.cpu* @cpu to i8*), i64 3) }]
+struct svar svars4[] =
+{
+ { &((cpu.pc).b[1][1]) }
+};
diff --git a/test/CodeGen/pr5406.c b/test/CodeGen/pr5406.c
new file mode 100644
index 000000000000..da74d6b64fe5
--- /dev/null
+++ b/test/CodeGen/pr5406.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 %s -emit-llvm -triple arm-apple-darwin -o - | FileCheck %s
+// PR 5406
+
+typedef struct { char x[3]; } A0;
+void foo (int i, ...);
+
+
+// CHECK: call arm_aapcscc void (i32, ...)* @foo(i32 1, [1 x i32] {{.*}})
+int main (void)
+{
+ A0 a3;
+ a3.x[0] = 0;
+ a3.x[0] = 0;
+ a3.x[2] = 26;
+ foo (1, a3 );
+ return 0;
+}
diff --git a/test/CodeGen/pragma-weak.c b/test/CodeGen/pragma-weak.c
index 1de60e106a95..7ad2b77d8e7e 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()
+// CHECK: define void @__a1() {{.*}} noinline
// attributes introduced BEFORE a combination of #pragma weak and alias()
// hold...
@@ -144,13 +144,20 @@ void __a3(void) __attribute((noinline));
#pragma weak a3 = __a3
void a3(void) __attribute((alias("__a3")));
void __a3(void) {}
-// CHECK: define void @__a3()
+// CHECK: define void @__a3() {{.*}} noinline
#pragma weak xxx = __xxx
__attribute((pure,noinline,const,fastcall)) void __xxx(void) { }
-// CHECK: void @__xxx()
+// CHECK: void @__xxx() {{.*}} noinline
-/// TODO: stuff that still doesn't work
+///////////// PR10878: Make sure we can call a weak alias
+void SHA512Pad(void *context) {}
+#pragma weak SHA384Pad = SHA512Pad
+void PR10878() { SHA384Pad(0); }
+// CHECK: call void @SHA384Pad(i8* null)
+
+
+///////////// TODO: stuff that still doesn't work
// due to the fact that disparate TopLevelDecls cannot affect each other
// (due to clang's Parser and ASTConsumer behavior, and quite reasonable)
diff --git a/test/CodeGen/redef-ext-inline.c b/test/CodeGen/redef-ext-inline.c
new file mode 100644
index 000000000000..b8e2f365ff41
--- /dev/null
+++ b/test/CodeGen/redef-ext-inline.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -std=gnu89
+// rdar://7208839
+
+extern inline int f1 (void) {return 1;}
+int f3 (void) {return f1();}
+int f1 (void) {return 0;}
diff --git a/test/CodeGen/sret.c b/test/CodeGen/sret.c
new file mode 100644
index 000000000000..ed1f9a44ef14
--- /dev/null
+++ b/test/CodeGen/sret.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 %s -emit-llvm -O0 -o - | grep sret | count 5
+
+struct abc {
+ long a;
+ long b;
+ long c;
+};
+
+struct abc foo1(void);
+struct abc foo2();
+
+void bar() {
+ struct abc dummy1 = foo1();
+ struct abc dummy2 = foo2();
+}
diff --git a/test/CodeGen/sret2.c b/test/CodeGen/sret2.c
new file mode 100644
index 000000000000..c96ce4d5c4e0
--- /dev/null
+++ b/test/CodeGen/sret2.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -emit-llvm -O0 -o - | grep sret | count 2
+
+struct abc {
+ long a;
+ long b;
+ long c;
+};
+
+struct abc foo2(){}
diff --git a/test/CodeGen/sse-builtins.c b/test/CodeGen/sse-builtins.c
new file mode 100644
index 000000000000..64ee4c970fe0
--- /dev/null
+++ b/test/CodeGen/sse-builtins.c
@@ -0,0 +1,104 @@
+// RUN: %clang_cc1 -ffreestanding -triple i386-apple-darwin9 -target-cpu pentium4 -target-feature +sse4.1 -g -emit-llvm %s -o - | FileCheck %s
+
+#include <emmintrin.h>
+
+__m128 test_loadl_pi(__m128 x, void* y) {
+ // CHECK: define {{.*}} @test_loadl_pi
+ // CHECK: load <2 x float>* {{.*}}, align 1{{$}}
+ // CHECK: shufflevector {{.*}} <4 x i32> <i32 0, i32 1
+ // CHECK: shufflevector {{.*}} <4 x i32> <i32 4, i32 5, i32 2, i32 3>
+ return _mm_loadl_pi(x,y);
+}
+
+__m128 test_loadh_pi(__m128 x, void* y) {
+ // CHECK: define {{.*}} @test_loadh_pi
+ // CHECK: load <2 x float>* {{.*}}, align 1{{$}}
+ // CHECK: shufflevector {{.*}} <4 x i32> <i32 0, i32 1
+ // CHECK: shufflevector {{.*}} <4 x i32> <i32 0, i32 1, i32 4, i32 5>
+ return _mm_loadh_pi(x,y);
+}
+
+__m128 test_load_ss(void* y) {
+ // CHECK: define {{.*}} @test_load_ss
+ // CHECK: load float* {{.*}}, align 1{{$}}
+ return _mm_load_ss(y);
+}
+
+__m128 test_load1_ps(void* y) {
+ // CHECK: define {{.*}} @test_load1_ps
+ // CHECK: load float* {{.*}}, align 1{{$}}
+ return _mm_load1_ps(y);
+}
+
+void test_store_ss(__m128 x, void* y) {
+ // CHECK: define void @test_store_ss
+ // CHECK: store {{.*}} float* {{.*}}, align 1,
+ _mm_store_ss(y, x);
+}
+
+__m128d test_load1_pd(__m128 x, void* y) {
+ // CHECK: define {{.*}} @test_load1_pd
+ // CHECK: load double* {{.*}}, align 1{{$}}
+ return _mm_load1_pd(y);
+}
+
+__m128d test_loadr_pd(__m128 x, void* y) {
+ // CHECK: define {{.*}} @test_loadr_pd
+ // CHECK: load <2 x double>* {{.*}}, align 16{{$}}
+ return _mm_loadr_pd(y);
+}
+
+__m128d test_load_sd(void* y) {
+ // CHECK: define {{.*}} @test_load_sd
+ // CHECK: load double* {{.*}}, align 1{{$}}
+ return _mm_load_sd(y);
+}
+
+__m128d test_loadh_pd(__m128d x, void* y) {
+ // CHECK: define {{.*}} @test_loadh_pd
+ // CHECK: load double* {{.*}}, align 1{{$}}
+ return _mm_loadh_pd(x, y);
+}
+
+__m128d test_loadl_pd(__m128d x, void* y) {
+ // CHECK: define {{.*}} @test_loadl_pd
+ // CHECK: load double* {{.*}}, align 1{{$}}
+ return _mm_loadl_pd(x, y);
+}
+
+void test_store_sd(__m128d x, void* y) {
+ // CHECK: define void @test_store_sd
+ // CHECK: store {{.*}} double* {{.*}}, align 1{{$}}
+ _mm_store_sd(y, x);
+}
+
+void test_store1_pd(__m128d x, void* y) {
+ // CHECK: define void @test_store1_pd
+ // CHECK: store {{.*}} double* {{.*}}, align 1{{$}}
+ // CHECK: store {{.*}} double* {{.*}}, align 1{{$}}
+ _mm_store1_pd(y, x);
+}
+
+void test_storer_pd(__m128d x, void* y) {
+ // CHECK: define void @test_storer_pd
+ // CHECK: store {{.*}} <2 x double>* {{.*}}, align 16{{$}}
+ _mm_storer_pd(y, x);
+}
+
+void test_storeh_pd(__m128d x, void* y) {
+ // CHECK: define void @test_storeh_pd
+ // CHECK: store {{.*}} double* {{.*}}, align 1{{$}}
+ _mm_storeh_pd(y, x);
+}
+
+void test_storel_pd(__m128d x, void* y) {
+ // CHECK: define void @test_storel_pd
+ // CHECK: store {{.*}} double* {{.*}}, align 1{{$}}
+ _mm_storel_pd(y, x);
+}
+
+__m128i test_loadl_epi64(void* y) {
+ // CHECK: define {{.*}} @test_loadl_epi64
+ // CHECK: load i64* {{.*}}, align 1{{$}}
+ return _mm_loadl_epi64(y);
+}
diff --git a/test/CodeGen/stdcall-fastcall.c b/test/CodeGen/stdcall-fastcall.c
index 6f3b00328771..3de7b6727bc2 100644
--- a/test/CodeGen/stdcall-fastcall.c
+++ b/test/CodeGen/stdcall-fastcall.c
@@ -46,5 +46,5 @@ int main(void) {
void __attribute((stdcall)) f7(foo) int foo; {}
void f8(void) {
f7(0);
- // CHECK: call x86_stdcallcc void (...)* bitcast
+ // CHECK: call x86_stdcallcc void @f7(i32 0)
}
diff --git a/test/CodeGen/string-literal-short-wstring.c b/test/CodeGen/string-literal-short-wstring.c
index ce2990492ad7..770c3d426871 100644
--- a/test/CodeGen/string-literal-short-wstring.c
+++ b/test/CodeGen/string-literal-short-wstring.c
@@ -3,7 +3,7 @@
int main() {
// This should convert to utf8.
- // CHECK: internal unnamed_addr constant [10 x i8] c"\E1\84\A0\C8\A0\F4\82\80\B0\00", align 1
+ // CHECK: 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: private unnamed_addr constant [6 x i8] c"A\00B\00\00\00"
diff --git a/test/CodeGen/string-literal.c b/test/CodeGen/string-literal.c
index cc6c0943d95a..fa8f28a766c4 100644
--- a/test/CodeGen/string-literal.c
+++ b/test/CodeGen/string-literal.c
@@ -1,16 +1,80 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+// 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
+
+#include <stddef.h>
int main() {
- // CHECK: internal unnamed_addr constant [10 x i8] c"abc\00\00\00\00\00\00\00", align 1
+ // 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
char a[10] = "abc";
// This should convert to utf8.
- // CHECK: internal unnamed_addr constant [10 x i8] c"\E1\84\A0\C8\A0\F4\82\80\B0\00", align 1
+ // 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
char b[10] = "\u1120\u0220\U00102030";
- // CHECK: private unnamed_addr constant [12 x i8] c"A\00\00\00B\00\00\00\00\00\00\00", align 1
- void *foo = L"AB";
+ // CHECK-C: private unnamed_addr constant [12 x i8] c"A\00\00\00B\00\00\00\00\00\00\00", align 4
+ // CHECK-CPP0X: private unnamed_addr constant [12 x i8] c"A\00\00\00B\00\00\00\00\00\00\00", align 4
+ const wchar_t *foo = L"AB";
+
+ // CHECK-C: private unnamed_addr constant [12 x i8] c"4\12\00\00\0B\F0\10\00\00\00\00\00", align 4
+ // CHECK-CPP0X: private unnamed_addr constant [12 x i8] c"4\12\00\00\0B\F0\10\00\00\00\00\00", align 4
+ const wchar_t *bar = L"\u1234\U0010F00B";
+
+ // CHECK-C: private unnamed_addr constant [12 x i8] c"4\12\00\00\0C\F0\10\00\00\00\00\00", align 4
+ // CHECK-CPP0X: private unnamed_addr constant [12 x i8] c"4\12\00\00\0C\F0\10\00\00\00\00\00", align 4
+ const wchar_t *baz = L"\u1234" "\U0010F00C";
+
+#if __cplusplus >= 201103L
+ // CHECK-CPP0X: private unnamed_addr constant [12 x i8] c"C\00\00\00D\00\00\00\00\00\00\00", align 4
+ const char32_t *c = U"CD";
+
+ // CHECK-CPP0X: private unnamed_addr constant [12 x i8] c"5\12\00\00\0C\F0\10\00\00\00\00\00", align 4
+ const char32_t *d = U"\u1235\U0010F00C";
+
+ // CHECK-CPP0X: private unnamed_addr constant [12 x i8] c"5\12\00\00\0B\F0\10\00\00\00\00\00", align 4
+ const char32_t *o = "\u1235" U"\U0010F00B";
+
+ // CHECK-CPP0X: private unnamed_addr constant [6 x i8] c"E\00F\00\00\00", align 2
+ const char16_t *e = u"EF";
+
+ // This should convert to utf16.
+ // CHECK-CPP0X: private unnamed_addr constant [10 x i8] c" \11 \02\C8\DB0\DC\00\00", align 2
+ const char16_t *f = u"\u1120\u0220\U00102030";
+
+ // This should convert to utf16.
+ // CHECK-CPP0X: private unnamed_addr constant [10 x i8] c" \11 \03\C8\DB0\DC\00\00", align 2
+ const char16_t *p = u"\u1120\u0320" "\U00102030";
+
+ // CHECK-CPP0X: 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
+ const char *h = R"foo(ghi)foo";
+
+ // CHECK-CPP0X: 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 [6 x i8] c"G\00H\00\00\00", align 2
+ const char16_t *j = uR"foo(GH)foo";
+
+ // CHECK-CPP0X: private unnamed_addr constant [12 x i8] c"I\00\00\00J\00\00\00\00\00\00\00", align 4
+ const char32_t *k = UR"bar(IJ)bar";
+
+ // CHECK-CPP0X: private unnamed_addr constant [12 x i8] c"K\00\00\00L\00\00\00\00\00\00\00", 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
+ const char *m = R"(abc\ndef)";
+
+ // CHECK-CPP0X: 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
+ const char *q = R"(abc
+def)" "ghi";
- // CHECK: private unnamed_addr constant [12 x i8] c"4\12\00\00\0B\F0\10\00\00\00\00\00", align 1
- void *bar = L"\u1234\U0010F00B";
+#endif
}
diff --git a/test/CodeGen/struct-init.c b/test/CodeGen/struct-init.c
index 8a605c1b67c8..6247729c17b7 100644
--- a/test/CodeGen/struct-init.c
+++ b/test/CodeGen/struct-init.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -S -triple armv7-apple-darwin %s -emit-llvm -o - | FileCheck %s
typedef struct _zend_ini_entry zend_ini_entry;
struct _zend_ini_entry {
@@ -23,17 +23,15 @@ typedef __attribute__(( ext_vector_type(2) )) unsigned int uint2;
typedef __attribute__(( __vector_size__(8) )) unsigned int __neon_uint32x2_t;
// rdar://8183908
-typedef struct __simd64_uint32_t {
- __neon_uint32x2_t val;
-} uint32x2_t;
+typedef unsigned int uint32_t;
+typedef __attribute__((neon_vector_type(2))) uint32_t uint32x2_t;
void foo() {
const uint32x2_t signBit = { (uint2) 0x80000000 };
}
-// CHECK: %struct.fp_struct_foo = type { void (i32)* }
+// CHECK: %struct.fp_struct_foo = type { void ([1 x i32])* }
struct fp_struct_bar { int a; };
struct fp_struct_foo {
void (*FP)(struct fp_struct_bar);
} G;
-
diff --git a/test/CodeGen/struct-matching-constraint.c b/test/CodeGen/struct-matching-constraint.c
new file mode 100644
index 000000000000..40c444f2b40d
--- /dev/null
+++ b/test/CodeGen/struct-matching-constraint.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -S -emit-llvm -triple armv7a-apple-darwin %s -o /dev/null
+typedef unsigned short uint16_t;
+typedef __attribute__((neon_vector_type(8))) uint16_t uint16x8_t;
+
+void b(uint16x8_t sat, uint16x8_t luma)
+{
+ __asm__("vmov.16 %1, %0 \n\t"
+ "vtrn.16 %0, %1 \n\t"
+ :"=w"(luma), "=w"(sat)
+ :"0"(luma)
+ );
+
+}
diff --git a/test/CodeGen/struct-passing.c b/test/CodeGen/struct-passing.c
index 8e5c0adcfc10..efb00efd53ab 100644
--- a/test/CodeGen/struct-passing.c
+++ b/test/CodeGen/struct-passing.c
@@ -16,8 +16,8 @@ void __attribute__((pure)) f5(T1 a);
void *ps[] = { f0, f1, f2, f3, f4, f5 };
-// CHECK: declare i32 @f0() readnone
-// CHECK: declare i32 @f1() readonly
+// CHECK: declare i32 @f0() nounwind readnone
+// CHECK: declare i32 @f1() nounwind readonly
// CHECK: declare void @f2({{.*}} sret)
// CHECK: declare void @f3({{.*}} sret)
// CHECK: declare void @f4({{.*}} byval align 4)
diff --git a/test/CodeGen/target-data.c b/test/CodeGen/target-data.c
index 8139a4efc599..fc8f758afa59 100644
--- a/test/CodeGen/target-data.c
+++ b/test/CodeGen/target-data.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -triple i686-unknown-unknown -emit-llvm -o %t %s
-// RUN: grep 'target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32"' %t
+// RUN: grep 'target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128"' %t
// RUN: %clang_cc1 -triple i686-apple-darwin9 -emit-llvm -o %t %s
-// RUN: grep 'target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32"' %t
+// RUN: grep 'target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32-S128"' %t
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o %t %s
-// RUN: grep 'target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"' %t
+// RUN: grep 'target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"' %t
diff --git a/test/CodeGen/unaligned-memcpy.c b/test/CodeGen/unaligned-memcpy.c
new file mode 100644
index 000000000000..0373b5617e05
--- /dev/null
+++ b/test/CodeGen/unaligned-memcpy.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+void bork() {
+ char Qux[33] = {0};
+}
diff --git a/test/CodeGen/union-align.c b/test/CodeGen/union-align.c
new file mode 100644
index 000000000000..89a9456e609d
--- /dev/null
+++ b/test/CodeGen/union-align.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | grep load | grep "4 x float" | not grep "align 4"
+// RUN: %clang_cc1 -emit-llvm %s -o - | grep load | grep "4 x float" | grep "align 16"
+// PR3432
+// rdar://6536377
+
+typedef float __m128 __attribute__ ((__vector_size__ (16)));
+
+typedef union
+{
+ int i[4];
+ float f[4];
+ __m128 v;
+} u_t;
+
+__m128 t(u_t *a) {
+ return a->v;
+}
diff --git a/test/CodeGen/vla-2.c b/test/CodeGen/vla-2.c
new file mode 100644
index 000000000000..0a74907f7b2d
--- /dev/null
+++ b/test/CodeGen/vla-2.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=gnu99 %s -emit-llvm -o - | grep ".*alloca.*align 16"
+
+extern void bar(int[]);
+
+void foo(int a)
+{
+ int var[a] __attribute__((__aligned__(16)));
+ bar(var);
+ return;
+}
diff --git a/test/CodeGen/vla-3.c b/test/CodeGen/vla-3.c
new file mode 100644
index 000000000000..4927b464231f
--- /dev/null
+++ b/test/CodeGen/vla-3.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -std=gnu99 %s -emit-llvm -o - | grep ".*alloca.*align 16"
+
+void adr(char *);
+
+void vlaalign(int size)
+{
+ char __attribute__((aligned(16))) tmp[size+32];
+ char tmp2[size+16];
+
+ adr(tmp);
+}
diff --git a/test/CodeGen/volatile-1.c b/test/CodeGen/volatile-1.c
index 7c7a822e880c..65511593d32a 100644
--- a/test/CodeGen/volatile-1.c
+++ b/test/CodeGen/volatile-1.c
@@ -24,182 +24,182 @@ int printf(const char *, ...);
// CHECK: define void @test()
void test() {
- // CHECK: volatile load [[INT]]* @i
+ // CHECK: load volatile [[INT]]* @i
i;
- // CHECK-NEXT: volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
// CHECK-NEXT: sitofp [[INT]]
(float)(ci);
- // CHECK-NEXT: volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
(void)ci;
// CHECK-NEXT: bitcast
// CHECK-NEXT: memcpy
(void)a;
- // CHECK-NEXT: [[R:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: [[I:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
- // CHECK-NEXT: volatile store [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: volatile store [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
(void)(ci=ci);
- // CHECK-NEXT: [[T:%.*]] = volatile load [[INT]]* @j
- // CHECK-NEXT: volatile store [[INT]] [[T]], [[INT]]* @i
+ // CHECK-NEXT: [[T:%.*]] = load volatile [[INT]]* @j
+ // CHECK-NEXT: store volatile [[INT]] [[T]], [[INT]]* @i
(void)(i=j);
- // CHECK-NEXT: [[R1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: [[I1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
- // CHECK-NEXT: [[R2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: [[I2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
// Not sure why they're ordered this way.
// CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]]
// CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]]
- // CHECK-NEXT: volatile store [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: volatile store [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
ci+=ci;
- // CHECK-NEXT: [[R1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: [[I1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
- // CHECK-NEXT: [[R2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: [[I2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
// CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]]
// CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]]
- // CHECK-NEXT: volatile store [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: volatile store [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
- // CHECK-NEXT: [[R2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: [[I2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
// These additions can be elided
// CHECK-NEXT: add [[INT]] [[R]], [[R2]]
// CHECK-NEXT: add [[INT]] [[I]], [[I2]]
(ci += ci) + ci;
// CHECK-NEXT: call void asm
asm("nop");
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: add nsw [[INT]]
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: add nsw [[INT]]
(i += j) + k;
// CHECK-NEXT: call void asm
asm("nop");
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: add nsw [[INT]]
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: store volatile
// CHECK-NEXT: add nsw [[INT]]
(i += j) + 1;
// CHECK-NEXT: call void asm
asm("nop");
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: add [[INT]]
// CHECK-NEXT: add [[INT]]
ci+ci;
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
__real i;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ci;
// CHECK-NEXT: call void asm
asm("nop");
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
(void)(i=i);
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
// CHECK-NEXT: sitofp
(float)(i=i);
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
(void)i;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
i=i;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
i=i=i;
#ifndef __cplusplus
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
(void)__builtin_choose_expr(0, i=i, j=j);
#endif
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: icmp
// CHECK-NEXT: br i1
- // CHECK: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK: load volatile
+ // CHECK-NEXT: store volatile
// CHECK-NEXT: br label
- // CHECK: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK: load volatile
+ // CHECK-NEXT: store volatile
// CHECK-NEXT: br label
k ? (i=i) : (j=j);
// CHECK: phi
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
(void)(i,(i=i));
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
i=i,i;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
(i=j,k=j);
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
(i=j,k);
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
(i,j);
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: trunc
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: store volatile
// CHECK-NEXT: sext
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: store volatile
i=c=k;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: add nsw [[INT]]
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: store volatile
i+=k;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
ci;
#ifndef __cplusplus
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
(int)ci;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: icmp ne
// CHECK-NEXT: icmp ne
// CHECK-NEXT: or i1
(_Bool)ci;
#endif
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
ci=ci;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
ci=ci=ci;
- // CHECK-NEXT: [[T:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
- // CHECK-NEXT: volatile store [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
- // CHECK-NEXT: volatile store [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[T:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: store volatile [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: store volatile [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
__imag ci = __imag ci = __imag ci;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
__real (i = j);
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
__imag i;
// ============================================================
@@ -224,71 +224,71 @@ void test() {
// Not a use. gcc got this wrong in 4.2 and omitted the side effects
// entirely, but it is fixed in 4.4.0.
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
__imag (i = j);
#ifndef __cplusplus
// A use of the real part
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
// CHECK-NEXT: sitofp
(float)(ci=ci);
// Not a use, bug? gcc treats this as not a use, that's probably a bug due to
// tree folding ignoring volatile.
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
(int)(ci=ci);
#endif
// A use.
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
// CHECK-NEXT: sitofp
(float)(i=i);
// A use. gcc treats this as not a use, that's probably a bug due to tree
// folding ignoring volatile.
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
(int)(i=i);
// A use.
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
// CHECK-NEXT: sub
-(i=j);
// A use. gcc treats this a not a use, that's probably a bug due to tree
// folding ignoring volatile.
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+(i=k);
// A use. gcc treats this a not a use, that's probably a bug due to tree
// folding ignoring volatile.
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
__real (ci=ci);
// A use.
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: add
i + 0;
// A use.
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: add
(i=j) + i;
// A use. gcc treats this as not a use, that's probably a bug due to tree
// folding ignoring volatile.
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
// CHECK-NEXT: add
(i=j) + 0;
diff --git a/test/CodeGen/volatile-2.c b/test/CodeGen/volatile-2.c
index 490b7d776b9f..3d342de69005 100644
--- a/test/CodeGen/volatile-2.c
+++ b/test/CodeGen/volatile-2.c
@@ -3,8 +3,8 @@
void test0() {
// CHECK: define void @test0()
// CHECK: [[F:%.*]] = alloca float
- // CHECK-NEXT: [[REAL:%.*]] = volatile load float* getelementptr inbounds ({ float, float }* @test0_v, i32 0, i32 0)
- // CHECK-NEXT: volatile load float* getelementptr inbounds ({{.*}} @test0_v, i32 0, i32 1)
+ // CHECK-NEXT: [[REAL:%.*]] = load volatile float* getelementptr inbounds ({ float, float }* @test0_v, i32 0, i32 0)
+ // CHECK-NEXT: load volatile float* getelementptr inbounds ({{.*}} @test0_v, i32 0, i32 1)
// CHECK-NEXT: store float [[REAL]], float* [[F]], align 4
// CHECK-NEXT: ret void
extern volatile _Complex float test0_v;
@@ -13,10 +13,10 @@ void test0() {
void test1() {
// CHECK: define void @test1()
- // CHECK: [[REAL:%.*]] = volatile load float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 0)
- // CHECK-NEXT: [[IMAG:%.*]] = volatile load float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 1)
- // CHECK-NEXT: volatile store float [[REAL]], float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 0)
- // CHECK-NEXT: volatile store float [[IMAG]], float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 1)
+ // CHECK: [[REAL:%.*]] = load volatile float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 0)
+ // CHECK-NEXT: [[IMAG:%.*]] = load volatile float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 1)
+ // CHECK-NEXT: store volatile float [[REAL]], float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 0)
+ // CHECK-NEXT: store volatile float [[IMAG]], float* getelementptr inbounds ({{.*}} @test1_v, i32 0, i32 1)
// CHECK-NEXT: ret void
extern volatile _Complex float test1_v;
test1_v = test1_v;
diff --git a/test/CodeGen/wchar-const.c b/test/CodeGen/wchar-const.c
new file mode 100644
index 000000000000..b672b15360a2
--- /dev/null
+++ b/test/CodeGen/wchar-const.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple i386-pc-win32 | FileCheck %s --check-prefix=WIN
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-apple-darwin | FileCheck %s --check-prefix=DAR
+// This should pass for any endianness combination of host and target.
+
+// This bit is taken from Sema/wchar.c so we can avoid the wchar.h include.
+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(__sun) || defined(__AuroraUX__)
+ #define WCHAR_T_TYPE long
+#else /* Solaris or AuroraUX. */
+ #define WCHAR_T_TYPE int
+#endif
+
+
+// CHECK-DAR: private unnamed_addr constant [72 x i8] c"
+// CHECK-WIN: private unnamed_addr constant [36 x i8] c"
+extern void foo(const wchar_t* p);
+int main (int argc, const char * argv[])
+{
+ foo(L"This is some text");
+ return 0;
+}
diff --git a/test/CodeGen/weak_constant.c b/test/CodeGen/weak_constant.c
new file mode 100644
index 000000000000..726d2ef122e1
--- /dev/null
+++ b/test/CodeGen/weak_constant.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -w -emit-llvm %s -O1 -o - | FileCheck %s
+// Check for bug compatibility with gcc.
+
+const int x __attribute((weak)) = 123;
+
+int* f(void) {
+ return &x;
+}
+
+int g(void) {
+ // CHECK: ret i32 123
+ return *f();
+}
diff --git a/test/CodeGen/x86_32-arguments-darwin.c b/test/CodeGen/x86_32-arguments-darwin.c
index 731d4f613f26..7727c43f6e8d 100644
--- a/test/CodeGen/x86_32-arguments-darwin.c
+++ b/test/CodeGen/x86_32-arguments-darwin.c
@@ -71,7 +71,7 @@ struct s10 {
// Small vectors and 1 x {i64,double} are returned in registers
// CHECK: i32 @f11()
-// CHECK: void @f12(<2 x i32>* sret %agg.result)
+// CHECK: void @f12(<2 x i32>* noalias sret %agg.result)
// CHECK: i64 @f13()
// CHECK: i64 @f14()
// CHECK: <2 x i64> @f15()
@@ -93,11 +93,11 @@ T16 f16(void) { while (1) {} }
// 128-bits).
// CHECK: i32 @f17()
-// CHECK: void @f18(%{{.*}}* sret %agg.result)
-// CHECK: void @f19(%{{.*}}* sret %agg.result)
-// CHECK: void @f20(%{{.*}}* sret %agg.result)
-// CHECK: void @f21(%{{.*}}* sret %agg.result)
-// CHECK: void @f22(%{{.*}}* sret %agg.result)
+// CHECK: void @f18(%{{.*}}* noalias sret %agg.result)
+// CHECK: void @f19(%{{.*}}* noalias sret %agg.result)
+// CHECK: void @f20(%{{.*}}* noalias sret %agg.result)
+// CHECK: void @f21(%{{.*}}* noalias sret %agg.result)
+// CHECK: void @f22(%{{.*}}* noalias sret %agg.result)
struct { T11 a; } f17(void) { while (1) {} }
struct { T12 a; } f18(void) { while (1) {} }
struct { T13 a; } f19(void) { while (1) {} }
@@ -116,11 +116,11 @@ struct { struct {} a; struct { float a[1]; } b; } f25(void) { while (1) {} }
// Small structures are handled recursively
// CHECK: i32 @f26()
-// CHECK: void @f27(%struct.s27* sret %agg.result)
+// CHECK: void @f27(%struct.s27* noalias sret %agg.result)
struct s26 { struct { char a, b; } a; struct { char a, b; } b; } f26(void) { while (1) {} }
struct s27 { struct { char a, b, c; } a; struct { char a; } b; } f27(void) { while (1) {} }
-// CHECK: void @f28(%struct.s28* sret %agg.result)
+// CHECK: void @f28(%struct.s28* noalias sret %agg.result)
struct s28 { int a; int b[]; } f28(void) { while (1) {} }
// CHECK: define i16 @f29()
@@ -150,7 +150,7 @@ struct s36 { struct { int : 0; } a[2][10]; char b; char c; } f36(void) { while (
// CHECK: define float @f37()
struct s37 { float c[1][1]; } f37(void) { while (1) {} }
-// CHECK: define void @f38(%struct.s38* sret %agg.result)
+// CHECK: define void @f38(%struct.s38* noalias sret %agg.result)
struct s38 { char a[3]; short b; } f38(void) { while (1) {} }
// CHECK: define void @f39(%struct.s39* byval align 16 %x)
diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c
index 221c7d38a73d..8571ac965552 100644
--- a/test/CodeGen/x86_64-arguments.c
+++ b/test/CodeGen/x86_64-arguments.c
@@ -42,7 +42,7 @@ void f7(e7 a0) {
// Test merging/passing of upper eightbyte with X87 class.
//
-// CHECK: define void @f8_1(%union.u8* sret %agg.result)
+// CHECK: define void @f8_1(%union.u8* noalias sret %agg.result)
// CHECK: define void @f8_2(%union.u8* byval align 16 %a0)
union u8 {
long double a;
@@ -58,7 +58,7 @@ struct s9 { int a; int b; int : 0; } f9(void) { while (1) {} }
struct s10 { int a; int b; int : 0; };
void f10(struct s10 a0) {}
-// CHECK: define void @f11(%union.anon* sret %agg.result)
+// CHECK: define void @f11(%union.anon* noalias sret %agg.result)
union { long double a; float b; } f11() { while (1) {} }
// CHECK: define i32 @f12_0()
@@ -69,7 +69,7 @@ void f12_1(struct s12 a0) {}
// Check that sret parameter is accounted for when checking available integer
// registers.
-// CHECK: define void @f13(%struct.s13_0* sret %agg.result, i32 %a, i32 %b, i32 %c, i32 %d, {{.*}}* byval align 8 %e, i32 %f)
+// CHECK: define void @f13(%struct.s13_0* noalias sret %agg.result, i32 %a, i32 %b, i32 %c, i32 %d, {{.*}}* byval align 8 %e, i32 %f)
struct s13_0 { long long f0[3]; };
struct s13_1 { long long f0[2]; };
diff --git a/test/CodeGenCUDA/device-stub.cu b/test/CodeGenCUDA/device-stub.cu
new file mode 100644
index 000000000000..af73ea993f45
--- /dev/null
+++ b/test/CodeGenCUDA/device-stub.cu
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+
+#include "../SemaCUDA/cuda.h"
+
+// Test that we build the correct number of calls to cudaSetupArgument followed
+// by a call to cudaLaunch.
+
+// CHECK: define{{.*}}kernelfunc
+// CHECK: call{{.*}}cudaSetupArgument
+// CHECK: call{{.*}}cudaSetupArgument
+// CHECK: call{{.*}}cudaSetupArgument
+// CHECK: call{{.*}}cudaLaunch
+__global__ void kernelfunc(int i, int j, int k) {}
diff --git a/test/CodeGenCUDA/filter-decl.cu b/test/CodeGenCUDA/filter-decl.cu
new file mode 100644
index 000000000000..b758632d12f7
--- /dev/null
+++ b/test/CodeGenCUDA/filter-decl.cu
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-HOST %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -fcuda-is-device | FileCheck -check-prefix=CHECK-DEVICE %s
+
+#include "../SemaCUDA/cuda.h"
+
+// CHECK-HOST-NOT: constantdata = global
+// CHECK-DEVICE: constantdata = global
+__constant__ char constantdata[256];
+
+// CHECK-HOST-NOT: devicedata = global
+// CHECK-DEVICE: devicedata = global
+__device__ char devicedata[256];
+
+// CHECK-HOST-NOT: shareddata = global
+// CHECK-DEVICE: shareddata = global
+__shared__ char shareddata[256];
+
+// CHECK-HOST: hostdata = global
+// CHECK-DEVICE-NOT: hostdata = global
+char hostdata[256];
+
+// CHECK-HOST: define{{.*}}implicithostonlyfunc
+// CHECK-DEVICE-NOT: define{{.*}}implicithostonlyfunc
+void implicithostonlyfunc(void) {}
+
+// CHECK-HOST: define{{.*}}explicithostonlyfunc
+// CHECK-DEVICE-NOT: define{{.*}}explicithostonlyfunc
+__host__ void explicithostonlyfunc(void) {}
+
+// CHECK-HOST-NOT: define{{.*}}deviceonlyfunc
+// CHECK-DEVICE: define{{.*}}deviceonlyfunc
+__device__ void deviceonlyfunc(void) {}
+
+// CHECK-HOST: define{{.*}}hostdevicefunc
+// CHECK-DEVICE: define{{.*}}hostdevicefunc
+__host__ __device__ void hostdevicefunc(void) {}
+
+// CHECK-HOST: define{{.*}}globalfunc
+// CHECK-DEVICE: define{{.*}}globalfunc
+__global__ void globalfunc(void) {}
diff --git a/test/CodeGenCUDA/kernel-call.cu b/test/CodeGenCUDA/kernel-call.cu
new file mode 100644
index 000000000000..f134624eec19
--- /dev/null
+++ b/test/CodeGenCUDA/kernel-call.cu
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+
+#include "../SemaCUDA/cuda.h"
+
+__global__ void g1(int x) {}
+
+int main(void) {
+ // CHECK: call{{.*}}cudaConfigureCall
+ // CHECK: icmp
+ // CHECK: br
+ // CHECK: call{{.*}}g1
+ g1<<<1, 1>>>(42);
+}
diff --git a/test/CodeGenCUDA/ptx-kernels.cu b/test/CodeGenCUDA/ptx-kernels.cu
new file mode 100644
index 000000000000..ecca8519af63
--- /dev/null
+++ b/test/CodeGenCUDA/ptx-kernels.cu
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -triple ptx32-unknown-unknown -fcuda-is-device -emit-llvm -o - | FileCheck %s
+
+#include "../SemaCUDA/cuda.h"
+
+// CHECK: define ptx_device{{.*}}device_function
+__device__ void device_function() {}
+
+// CHECK: define ptx_kernel{{.*}}global_function
+__global__ void global_function() {
+ // CHECK: call ptx_device{{.*}}device_function
+ device_function();
+}
diff --git a/test/CodeGenCXX/2003-11-02-WeakLinkage.cpp b/test/CodeGenCXX/2003-11-02-WeakLinkage.cpp
new file mode 100644
index 000000000000..02f9fc6e911d
--- /dev/null
+++ b/test/CodeGenCXX/2003-11-02-WeakLinkage.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+// The template should compile to linkonce linkage, not weak linkage.
+
+// CHECK-NOT: weak
+template<class T>
+void thefunc();
+
+template<class T>
+inline void thefunc() {}
+
+void test() {
+ thefunc<int>();
+}
diff --git a/test/CodeGenCXX/2003-11-18-PtrMemConstantInitializer.cpp b/test/CodeGenCXX/2003-11-18-PtrMemConstantInitializer.cpp
new file mode 100644
index 000000000000..9cecf4861163
--- /dev/null
+++ b/test/CodeGenCXX/2003-11-18-PtrMemConstantInitializer.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+
+struct Gfx {
+ void opMoveSetShowText();
+};
+
+struct Operator {
+ void (Gfx::*func)();
+};
+
+Operator opTab[] = {
+ {&Gfx::opMoveSetShowText},
+};
diff --git a/test/CodeGenCXX/2003-11-27-MultipleInheritanceThunk.cpp b/test/CodeGenCXX/2003-11-27-MultipleInheritanceThunk.cpp
new file mode 100644
index 000000000000..3e5339732767
--- /dev/null
+++ b/test/CodeGenCXX/2003-11-27-MultipleInheritanceThunk.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+
+
+struct CallSite {
+ int X;
+
+ CallSite(const CallSite &CS);
+};
+
+struct AliasAnalysis {
+ int TD;
+
+ virtual int getModRefInfo(CallSite CS);
+};
+
+
+struct Pass {
+ int X;
+ virtual int foo();
+};
+
+struct AliasAnalysisCounter : public Pass, public AliasAnalysis {
+ int getModRefInfo(CallSite CS) {
+ return 0;
+ }
+};
+
+AliasAnalysisCounter AAC;
diff --git a/test/CodeGenCXX/2003-11-29-DuplicatedCleanupTest.cpp b/test/CodeGenCXX/2003-11-29-DuplicatedCleanupTest.cpp
new file mode 100644
index 000000000000..45325bc65c61
--- /dev/null
+++ b/test/CodeGenCXX/2003-11-29-DuplicatedCleanupTest.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+
+
+void doesntThrow() throw();
+struct F {
+ ~F() { doesntThrow(); }
+};
+
+void atest() {
+ F A;
+lab:
+ F B;
+ goto lab;
+}
+
+void test(int val) {
+label: {
+ F A;
+ F B;
+ if (val == 0) goto label;
+ if (val == 1) goto label;
+}
+}
+
+void test3(int val) {
+label: {
+ F A;
+ F B;
+ if (val == 0) { doesntThrow(); goto label; }
+ if (val == 1) { doesntThrow(); goto label; }
+}
+}
+
+void test4(int val) {
+label: {
+ F A;
+ F B;
+ if (val == 0) { F C; goto label; }
+ if (val == 1) { F D; goto label; }
+}
+}
diff --git a/test/CodeGenCXX/2003-12-08-ArrayOfPtrToMemberFunc.cpp b/test/CodeGenCXX/2003-12-08-ArrayOfPtrToMemberFunc.cpp
new file mode 100644
index 000000000000..38de271b6132
--- /dev/null
+++ b/test/CodeGenCXX/2003-12-08-ArrayOfPtrToMemberFunc.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+
+struct Evil {
+ void fun ();
+};
+int foo();
+typedef void (Evil::*memfunptr) ();
+static memfunptr jumpTable[] = { &Evil::fun };
+
+void Evil::fun() {
+ (this->*jumpTable[foo()]) ();
+}
diff --git a/test/CodeGenCXX/2004-01-11-DynamicInitializedConstant.cpp b/test/CodeGenCXX/2004-01-11-DynamicInitializedConstant.cpp
new file mode 100644
index 000000000000..0c9333fb6d7a
--- /dev/null
+++ b/test/CodeGenCXX/2004-01-11-DynamicInitializedConstant.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+// CHECK-NOT: constant
+extern int X;
+const int Y = X;
+const int* foo() { return &Y; }
diff --git a/test/CodeGenCXX/2004-03-08-ReinterpretCastCopy.cpp b/test/CodeGenCXX/2004-03-08-ReinterpretCastCopy.cpp
new file mode 100644
index 000000000000..a6e2e30dd59b
--- /dev/null
+++ b/test/CodeGenCXX/2004-03-08-ReinterpretCastCopy.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+
+struct A {
+ virtual void Method() = 0;
+};
+
+struct B : public A {
+ virtual void Method() { }
+};
+
+typedef void (A::*fn_type_a)(void);
+typedef void (B::*fn_type_b)(void);
+
+int main(int argc, char **argv)
+{
+ fn_type_a f = reinterpret_cast<fn_type_a>(&B::Method);
+ fn_type_b g = reinterpret_cast<fn_type_b>(f);
+ B b;
+ (b.*g)();
+ return 0;
+}
diff --git a/test/CodeGenCXX/2004-03-09-UnmangledBuiltinMethods.cpp b/test/CodeGenCXX/2004-03-09-UnmangledBuiltinMethods.cpp
new file mode 100644
index 000000000000..5d8c8b004b79
--- /dev/null
+++ b/test/CodeGenCXX/2004-03-09-UnmangledBuiltinMethods.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: _ZN11AccessFlags6strlenEv
+struct AccessFlags {
+ void strlen();
+};
+
+void AccessFlags::strlen() { }
diff --git a/test/CodeGenCXX/2004-03-15-CleanupsAndGotos.cpp b/test/CodeGenCXX/2004-03-15-CleanupsAndGotos.cpp
new file mode 100644
index 000000000000..01350c00b9bd
--- /dev/null
+++ b/test/CodeGenCXX/2004-03-15-CleanupsAndGotos.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+
+// Testcase from Bug 291
+
+struct X {
+ ~X();
+};
+
+void foo() {
+ X v;
+
+TryAgain:
+ goto TryAgain;
+}
diff --git a/test/CodeGenCXX/2004-06-08-LateTemplateInstantiation.cpp b/test/CodeGenCXX/2004-06-08-LateTemplateInstantiation.cpp
new file mode 100644
index 000000000000..97254c18a51a
--- /dev/null
+++ b/test/CodeGenCXX/2004-06-08-LateTemplateInstantiation.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+
+
+template<typename Ty>
+struct normal_iterator {
+ int FIELD;
+};
+
+void foo(normal_iterator<int>);
+normal_iterator<int> baz();
+
+void bar() {
+ foo(baz());
+}
+
+void *bar2() {
+ return (void*)foo;
+}
diff --git a/test/CodeGenCXX/2004-09-27-DidntEmitTemplate.cpp b/test/CodeGenCXX/2004-09-27-DidntEmitTemplate.cpp
new file mode 100644
index 000000000000..618894fd7248
--- /dev/null
+++ b/test/CodeGenCXX/2004-09-27-DidntEmitTemplate.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+
+// This is a testcase for LLVM PR445, which was a problem where the
+// instantiation of callDefaultCtor was not being emitted correctly.
+
+// CHECK-NOT: declare{{.*}}callDefaultCtor
+struct Pass {};
+
+template<typename PassName>
+Pass *callDefaultCtor() { return new Pass(); }
+
+void foo(Pass *(*C)());
+
+struct basic_string {
+ bool empty() const { return true; }
+};
+
+
+bool foo2(basic_string &X) {
+ return X.empty();
+}
+void baz() { foo(callDefaultCtor<Pass>); }
diff --git a/test/CodeGenCXX/2004-11-27-ExceptionCleanupAssertion.cpp b/test/CodeGenCXX/2004-11-27-ExceptionCleanupAssertion.cpp
new file mode 100644
index 000000000000..ebcce7796e71
--- /dev/null
+++ b/test/CodeGenCXX/2004-11-27-ExceptionCleanupAssertion.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 %s -emit-llvm -o /dev/null
+
+// This is PR421
+
+struct Strongbad {
+ Strongbad(const char *str );
+ ~Strongbad();
+ operator const char *() const;
+};
+
+void TheCheat () {
+ Strongbad foo(0);
+ Strongbad dirs[] = { Strongbad(0) + 1};
+}
diff --git a/test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp b/test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp
new file mode 100644
index 000000000000..3bfecd54b780
--- /dev/null
+++ b/test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+// PR447
+
+namespace nm {
+ struct str {
+ friend int foo(int arg = 0);
+ };
+}
diff --git a/test/CodeGenCXX/2005-01-03-StaticInitializers.cpp b/test/CodeGenCXX/2005-01-03-StaticInitializers.cpp
new file mode 100644
index 000000000000..875c412c6b48
--- /dev/null
+++ b/test/CodeGenCXX/2005-01-03-StaticInitializers.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+
+struct S {
+ int A[2];
+};
+
+// CHECK-NOT: llvm.global_ctor
+int XX = (int)(long)&(((struct S*)0)->A[1]);
diff --git a/test/CodeGenCXX/2005-02-11-AnonymousUnion.cpp b/test/CodeGenCXX/2005-02-11-AnonymousUnion.cpp
new file mode 100644
index 000000000000..dee581736050
--- /dev/null
+++ b/test/CodeGenCXX/2005-02-11-AnonymousUnion.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+// Test anonymous union with members of the same size.
+int test1(float F) {
+ union {
+ float G;
+ int i;
+ };
+ G = F;
+ return i;
+}
+
+// test anonymous union with members of differing size.
+int test2(short F) {
+ volatile union {
+ short G;
+ int i;
+ };
+ G = F;
+ return i;
+}
+
+// Make sure that normal unions work. duh :)
+volatile union U_t {
+ short S;
+ int i;
+} U;
+
+int test3(short s) {
+ U.S = s;
+ return U.i;
+}
diff --git a/test/CodeGenCXX/2005-02-13-BadDynamicInit.cpp b/test/CodeGenCXX/2005-02-13-BadDynamicInit.cpp
new file mode 100644
index 000000000000..b1db67aebfd3
--- /dev/null
+++ b/test/CodeGenCXX/2005-02-13-BadDynamicInit.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// This testcase corresponds to PR509
+struct Data {
+ unsigned *data;
+ unsigned array[1];
+};
+
+// CHECK-NOT: llvm.global_ctors
+Data shared_null = { shared_null.array };
diff --git a/test/CodeGenCXX/2005-02-14-BitFieldOffset.cpp b/test/CodeGenCXX/2005-02-14-BitFieldOffset.cpp
new file mode 100644
index 000000000000..c37f5dce32b2
--- /dev/null
+++ b/test/CodeGenCXX/2005-02-14-BitFieldOffset.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+
+// CHECK-NOT: i32 6
+struct QVectorTypedData {
+ int size;
+ unsigned int sharable : 1;
+ unsigned short array[1];
+};
+
+void foo(QVectorTypedData *X) {
+ X->array[0] = 123;
+}
diff --git a/test/CodeGenCXX/2005-02-19-BitfieldStructCrash.cpp b/test/CodeGenCXX/2005-02-19-BitfieldStructCrash.cpp
new file mode 100644
index 000000000000..937a300b5dfb
--- /dev/null
+++ b/test/CodeGenCXX/2005-02-19-BitfieldStructCrash.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+
+struct QChar {unsigned short X; QChar(unsigned short); } ;
+
+struct Command {
+ Command(QChar c) : c(c) {}
+ unsigned int type : 4;
+ QChar c;
+ };
+
+Command X(QChar('c'));
+
+void Foo(QChar );
+void bar() { Foo(X.c); }
diff --git a/test/CodeGenCXX/2005-02-19-UnnamedVirtualThunkArgument.cpp b/test/CodeGenCXX/2005-02-19-UnnamedVirtualThunkArgument.cpp
new file mode 100644
index 000000000000..986001ada0da
--- /dev/null
+++ b/test/CodeGenCXX/2005-02-19-UnnamedVirtualThunkArgument.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+struct Foo {
+ Foo();
+ virtual ~Foo();
+};
+
+struct Bar {
+ Bar();
+ virtual ~Bar();
+ virtual bool test(bool) const;
+};
+
+struct Baz : public Foo, public Bar {
+ Baz();
+ virtual ~Baz();
+ virtual bool test(bool) const;
+};
+
+bool Baz::test(bool) const {
+ return true;
+}
diff --git a/test/CodeGenCXX/2005-02-20-BrokenReferenceTest.cpp b/test/CodeGenCXX/2005-02-20-BrokenReferenceTest.cpp
new file mode 100644
index 000000000000..36f911e227fe
--- /dev/null
+++ b/test/CodeGenCXX/2005-02-20-BrokenReferenceTest.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+void test(unsigned char *b, int rb) {
+ typedef unsigned char imgfoo[10][rb];
+ imgfoo &br = *(imgfoo *)b;
+
+ br[0][0] = 1;
+
+ rb = br[0][0];
+}
diff --git a/test/CodeGenCXX/2006-03-01-GimplifyCrash.cpp b/test/CodeGenCXX/2006-03-01-GimplifyCrash.cpp
new file mode 100644
index 000000000000..b809751cd0f2
--- /dev/null
+++ b/test/CodeGenCXX/2006-03-01-GimplifyCrash.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+
+struct PrefMapElem {
+ virtual ~PrefMapElem();
+ unsigned int fPrefId;
+};
+
+int foo() {
+ PrefMapElem* fMap;
+ if (fMap[0].fPrefId == 1)
+ return 1;
+
+ return 0;
+}
diff --git a/test/CodeGenCXX/2006-03-06-C++RecurseCrash.cpp b/test/CodeGenCXX/2006-03-06-C++RecurseCrash.cpp
new file mode 100644
index 000000000000..01476b7ff0c2
--- /dev/null
+++ b/test/CodeGenCXX/2006-03-06-C++RecurseCrash.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+namespace std {
+ class exception { };
+
+ class type_info {
+ public:
+ virtual ~type_info();
+ };
+
+}
+
+namespace __cxxabiv1 {
+ class __si_class_type_info : public std::type_info {
+ ~__si_class_type_info();
+ };
+}
+
+class recursive_init: public std::exception {
+public:
+ virtual ~recursive_init() throw ();
+};
+
+recursive_init::~recursive_init() throw() { }
diff --git a/test/CodeGenCXX/2006-09-12-OpaqueStructCrash.cpp b/test/CodeGenCXX/2006-09-12-OpaqueStructCrash.cpp
new file mode 100644
index 000000000000..bd270dd60238
--- /dev/null
+++ b/test/CodeGenCXX/2006-09-12-OpaqueStructCrash.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s
+
+struct A {
+ virtual ~A();
+};
+
+template <typename Ty>
+struct B : public A {
+ ~B () { delete [] val; }
+private:
+ Ty* val;
+};
+
+template <typename Ty>
+struct C : public A {
+ C ();
+ ~C ();
+};
+
+template <typename Ty>
+struct D : public A {
+ D () {}
+ private:
+ B<C<Ty> > blocks;
+};
+
+template class D<double>;
diff --git a/test/CodeGenCXX/2006-10-30-ClassBitfield.cpp b/test/CodeGenCXX/2006-10-30-ClassBitfield.cpp
new file mode 100644
index 000000000000..8f61f7b10a81
--- /dev/null
+++ b/test/CodeGenCXX/2006-10-30-ClassBitfield.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+// PR954
+
+struct _Refcount_Base {
+ unsigned long _M_ref_count;
+ int _M_ref_count_lock;
+ _Refcount_Base() : _M_ref_count(0) {}
+};
+
+struct _Rope_RopeRep : public _Refcount_Base
+{
+public:
+ int _M_tag:8;
+};
+
+int foo(_Rope_RopeRep* r) { return r->_M_tag; }
diff --git a/test/CodeGenCXX/2006-11-20-GlobalSymbols.cpp b/test/CodeGenCXX/2006-11-20-GlobalSymbols.cpp
new file mode 100644
index 000000000000..34594f43a0b9
--- /dev/null
+++ b/test/CodeGenCXX/2006-11-20-GlobalSymbols.cpp
@@ -0,0 +1,11 @@
+// PR1013
+// Check to make sure debug symbols use the correct name for globals and
+// functions. Will not assemble if it fails to.
+// RUN: %clang_cc1 -emit-llvm -g -o - %s | FileCheck %s
+
+// CHECK: f\01oo"
+int foo __asm__("f\001oo");
+
+int bar() {
+ return foo;
+}
diff --git a/test/CodeGenCXX/2006-11-30-ConstantExprCrash.cpp b/test/CodeGenCXX/2006-11-30-ConstantExprCrash.cpp
new file mode 100644
index 000000000000..2088e63fd5f8
--- /dev/null
+++ b/test/CodeGenCXX/2006-11-30-ConstantExprCrash.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+// PR1027
+
+struct sys_var {
+ unsigned name_length;
+
+ bool no_support_one_shot;
+ sys_var() {}
+};
+
+
+struct sys_var_thd : public sys_var {
+};
+
+extern sys_var_thd sys_auto_is_null;
+
+sys_var *getsys_variables() {
+ return &sys_auto_is_null;
+}
+
+sys_var *sys_variables = &sys_auto_is_null;
diff --git a/test/CodeGenCXX/2007-01-02-UnboundedArray.cpp b/test/CodeGenCXX/2007-01-02-UnboundedArray.cpp
new file mode 100644
index 000000000000..0cd83fa7ed4c
--- /dev/null
+++ b/test/CodeGenCXX/2007-01-02-UnboundedArray.cpp
@@ -0,0 +1,14 @@
+// Make sure unbounded arrays compile with debug information.
+//
+// RUN: %clang_cc1 -emit-llvm -g %s -o -
+
+// PR1068
+
+struct Object {
+ char buffer[];
+};
+
+int main(int argc, char** argv) {
+ new Object;
+ return 0;
+}
diff --git a/test/CodeGenCXX/2007-01-06-PtrMethodInit.cpp b/test/CodeGenCXX/2007-01-06-PtrMethodInit.cpp
new file mode 100644
index 000000000000..f3aa51e725b1
--- /dev/null
+++ b/test/CodeGenCXX/2007-01-06-PtrMethodInit.cpp
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+// PR1084
+
+extern "C"
+{
+ typedef unsigned char PRUint8;
+ typedef unsigned int PRUint32;
+}
+typedef PRUint32 nsresult;
+struct nsID
+{
+};
+typedef nsID nsIID;
+class nsISupports
+{
+};
+extern "C++"
+{
+ template < class T > struct nsCOMTypeInfo
+ {
+ static const nsIID & GetIID ()
+ {
+ }
+ };
+}
+
+class nsIDOMEvent:public nsISupports
+{
+};
+class nsIDOMEventListener:public nsISupports
+{
+public:static const nsIID & GetIID ()
+ {
+ }
+ virtual nsresult
+ __attribute__ ((regparm (0), cdecl)) HandleEvent (nsIDOMEvent * event) =
+ 0;
+};
+class nsIDOMMouseListener:public nsIDOMEventListener
+{
+public:static const nsIID & GetIID ()
+ {
+ static const nsIID iid = {
+ };
+ }
+ virtual nsresult
+ __attribute__ ((regparm (0),
+ cdecl)) MouseDown (nsIDOMEvent * aMouseEvent) = 0;
+};
+typedef
+typeof (&nsIDOMEventListener::HandleEvent)
+ GenericHandler;
+ struct EventDispatchData
+ {
+ PRUint32 message;
+ GenericHandler method;
+ PRUint8 bits;
+ };
+ struct EventTypeData
+ {
+ const EventDispatchData *events;
+ int numEvents;
+ const nsIID *iid;
+ };
+ static const EventDispatchData sMouseEvents[] = {
+ {
+ (300 + 2),
+ reinterpret_cast < GenericHandler > (&nsIDOMMouseListener::MouseDown),
+ 0x01}
+ };
+static const EventTypeData sEventTypes[] = {
+ {
+ sMouseEvents, (sizeof (sMouseEvents) / sizeof (sMouseEvents[0])),
+ &nsCOMTypeInfo < nsIDOMMouseListener >::GetIID ()}
+};
diff --git a/test/CodeGenCXX/2007-04-05-PackedBitFields-1.cpp b/test/CodeGenCXX/2007-04-05-PackedBitFields-1.cpp
new file mode 100644
index 000000000000..6c39b55fd33e
--- /dev/null
+++ b/test/CodeGenCXX/2007-04-05-PackedBitFields-1.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+
+#ifdef PACKED
+#define P __attribute__((packed))
+#else
+#define P
+#endif
+
+struct P M_Packed {
+ unsigned int l_Packed;
+ unsigned short k_Packed : 6,
+ i_Packed : 15,
+ j_Packed : 11;
+
+};
+
+struct M_Packed sM_Packed;
+
+int testM_Packed (void) {
+ struct M_Packed x;
+ return (x.i_Packed != 0);
+}
diff --git a/test/CodeGenCXX/2007-04-05-PackedBitFieldsOverlap-2.cpp b/test/CodeGenCXX/2007-04-05-PackedBitFieldsOverlap-2.cpp
new file mode 100644
index 000000000000..d7b0eaeae1a2
--- /dev/null
+++ b/test/CodeGenCXX/2007-04-05-PackedBitFieldsOverlap-2.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+
+#ifdef PACKED
+#define P __attribute__((packed))
+#else
+#define P
+#endif
+
+struct P M_Packed {
+ unsigned long sorted : 1;
+ unsigned long from_array : 1;
+ unsigned long mixed_encoding : 1;
+ unsigned long encoding : 8;
+ unsigned long count : 21;
+
+};
+
+struct M_Packed sM_Packed;
+
+int testM_Packed (void) {
+ struct M_Packed x;
+ return (x.count != 0);
+}
diff --git a/test/CodeGenCXX/2007-04-05-PackedBitFieldsOverlap.cpp b/test/CodeGenCXX/2007-04-05-PackedBitFieldsOverlap.cpp
new file mode 100644
index 000000000000..691176739259
--- /dev/null
+++ b/test/CodeGenCXX/2007-04-05-PackedBitFieldsOverlap.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+
+
+#ifdef PACKED
+#define P __attribute__((packed))
+#else
+#define P
+#endif
+
+struct P M_Packed {
+ unsigned int l_Packed;
+ unsigned short k_Packed : 6,
+ i_Packed : 15;
+ char c;
+
+};
+
+struct M_Packed sM_Packed;
+
+int testM_Packed (void) {
+ struct M_Packed x;
+ return (x.i_Packed != 0);
+}
diff --git a/test/CodeGenCXX/2007-04-05-PackedBitFieldsSmall.cpp b/test/CodeGenCXX/2007-04-05-PackedBitFieldsSmall.cpp
new file mode 100644
index 000000000000..b31f95fa3b8a
--- /dev/null
+++ b/test/CodeGenCXX/2007-04-05-PackedBitFieldsSmall.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+
+
+#ifdef PACKED
+// This is an example where size of Packed struct is smaller then
+// the size of bit field type.
+#define P __attribute__((packed))
+#else
+#define P
+#endif
+
+struct P M_Packed {
+ unsigned long long X:50;
+ unsigned Y:2;
+};
+
+struct M_Packed sM_Packed;
+
+int testM_Packed (void) {
+ struct M_Packed x;
+ return (0 != x.Y);
+}
+
+int testM_Packed2 (void) {
+ struct M_Packed x;
+ return (0 != x.X);
+}
diff --git a/test/CodeGenCXX/2007-04-05-StructPackedFieldUnpacked.cpp b/test/CodeGenCXX/2007-04-05-StructPackedFieldUnpacked.cpp
new file mode 100644
index 000000000000..c848e7cb7dd9
--- /dev/null
+++ b/test/CodeGenCXX/2007-04-05-StructPackedFieldUnpacked.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+
+#ifdef PACKED
+#define P __attribute__((packed))
+#else
+#define P
+#endif
+
+struct UnPacked {
+ int X;
+ int Y;
+};
+
+struct P M_Packed {
+ unsigned char A;
+ struct UnPacked B;
+};
+
+struct M_Packed sM_Packed;
+
+int testM_Packed (void) {
+ struct M_Packed x;
+ return (x.B.Y != 0);
+}
diff --git a/test/CodeGenCXX/2007-04-10-PackedUnion.cpp b/test/CodeGenCXX/2007-04-10-PackedUnion.cpp
new file mode 100644
index 000000000000..863fc82692e9
--- /dev/null
+++ b/test/CodeGenCXX/2007-04-10-PackedUnion.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+extern "C" {
+
+#pragma pack(push, 2)
+ typedef struct ABC* abc;
+
+ struct ABCS {
+ float red;
+ float green;
+ float blue;
+ float alpha;
+ };
+
+ typedef void (*XYZ)();
+#pragma pack(pop)
+}
+
+
+union ABCU {
+ ABCS color;
+ XYZ bg;
+};
+
+struct AData {
+ ABCU data;
+};
+
+class L {
+ public:
+ L() {}
+ L(const L& other);
+
+ private:
+ AData fdata;
+};
+
+
+L::L(const L& other)
+{
+ fdata = other.fdata;
+}
diff --git a/test/CodeGenCXX/2007-04-14-FNoBuiltin.cpp b/test/CodeGenCXX/2007-04-14-FNoBuiltin.cpp
new file mode 100644
index 000000000000..4475fda95c08
--- /dev/null
+++ b/test/CodeGenCXX/2007-04-14-FNoBuiltin.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm %s -fno-builtin -o - | FileCheck %s
+// Check that -fno-builtin is honored.
+
+extern "C" int printf(const char*, ...);
+void foo(const char *msg) {
+ // CHECK: call{{.*}}printf
+ printf("%s\n",msg);
+}
diff --git a/test/CodeGenCXX/2007-05-03-VectorInit.cpp b/test/CodeGenCXX/2007-05-03-VectorInit.cpp
new file mode 100644
index 000000000000..5bc196f30fe2
--- /dev/null
+++ b/test/CodeGenCXX/2007-05-03-VectorInit.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -emit-llvm %s -O0 -o -
+// PR1378
+
+typedef float v4sf __attribute__((vector_size(16)));
+
+typedef v4sf float4;
+
+static float4 splat4(float a)
+{
+ float4 tmp = {a,a,a,a};
+ return tmp;
+}
+
+float4 foo(float a)
+{
+ return splat4(a);
+}
diff --git a/test/CodeGenCXX/2007-07-29-RestrictPtrArg.cpp b/test/CodeGenCXX/2007-07-29-RestrictPtrArg.cpp
new file mode 100644
index 000000000000..d7c96f562acc
--- /dev/null
+++ b/test/CodeGenCXX/2007-07-29-RestrictPtrArg.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+
+void foo(int * __restrict myptr1, int * myptr2) {
+ // CHECK: noalias
+ myptr1[0] = 0;
+ myptr2[0] = 0;
+}
diff --git a/test/CodeGenCXX/2007-07-29-RestrictRefArg.cpp b/test/CodeGenCXX/2007-07-29-RestrictRefArg.cpp
new file mode 100644
index 000000000000..aa9f48bb0abc
--- /dev/null
+++ b/test/CodeGenCXX/2007-07-29-RestrictRefArg.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+
+void foo(int & __restrict myptr1, int & myptr2) {
+ // CHECK: noalias
+ myptr1 = 0;
+ myptr2 = 0;
+}
diff --git a/test/CodeGenCXX/2007-09-10-RecursiveTypeResolution.cpp b/test/CodeGenCXX/2007-09-10-RecursiveTypeResolution.cpp
new file mode 100644
index 000000000000..ec8a516c696b
--- /dev/null
+++ b/test/CodeGenCXX/2007-09-10-RecursiveTypeResolution.cpp
@@ -0,0 +1,87 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+// PR1634
+
+namespace Manta
+{
+ class CallbackHandle
+ {
+ protected:virtual ~ CallbackHandle (void)
+ {
+ }
+ };
+template < typename Data1 > class CallbackBase_1Data:public CallbackHandle
+ {
+ };
+}
+
+namespace __gnu_cxx
+{
+ template < typename _Iterator, typename _Container >
+ class __normal_iterator
+ {
+ _Iterator _M_current;
+ };
+}
+
+namespace std
+{
+ template < typename _Tp > struct allocator
+ {
+ typedef _Tp *pointer;
+ };
+ template < typename _InputIterator,
+ typename _Tp > inline void find (_InputIterator __last,
+ const _Tp & __val)
+ {
+ };
+}
+
+namespace Manta
+{
+ template < typename _Tp, typename _Alloc> struct _Vector_base
+ {
+ struct _Vector_impl
+ {
+ _Tp *_M_start;
+ };
+ public:
+ _Vector_impl _M_impl;
+ };
+ template < typename _Tp, typename _Alloc = std::allocator < _Tp > >
+ class vector:protected _Vector_base < _Tp,_Alloc >
+ {
+ public:
+ typedef __gnu_cxx::__normal_iterator < typename _Alloc::pointer,
+ vector < _Tp, _Alloc > > iterator;
+ iterator end ()
+ {
+ }
+ };
+ class MantaInterface
+ {
+ };
+ class RTRT
+ {
+ virtual CallbackHandle *registerTerminationCallback (CallbackBase_1Data <
+ MantaInterface * >*);
+ virtual void unregisterCallback (CallbackHandle *);
+ typedef vector < CallbackBase_1Data < int >*>PRCallbackMapType;
+ PRCallbackMapType parallelPreRenderCallbacks;
+ };
+}
+using namespace Manta;
+CallbackHandle *
+RTRT::registerTerminationCallback (CallbackBase_1Data < MantaInterface * >*cb)
+{
+ return cb;
+}
+
+void
+RTRT::unregisterCallback (CallbackHandle * callback)
+{
+ {
+ typedef CallbackBase_1Data < int > callback_t;
+ callback_t *cb = static_cast < callback_t * >(callback);
+ find (parallelPreRenderCallbacks.end (), cb);
+ }
+}
diff --git a/test/CodeGenCXX/2007-10-01-StructResize.cpp b/test/CodeGenCXX/2007-10-01-StructResize.cpp
new file mode 100644
index 000000000000..8e5750d3c4ef
--- /dev/null
+++ b/test/CodeGenCXX/2007-10-01-StructResize.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+#pragma pack(4)
+
+struct Bork {
+ unsigned int f1 : 3;
+ unsigned int f2 : 30;
+};
+
+int Foo(Bork *hdr) {
+ hdr->f1 = 7;
+ hdr->f2 = 927;
+}
diff --git a/test/CodeGenCXX/2008-01-12-VecInit.cpp b/test/CodeGenCXX/2008-01-12-VecInit.cpp
new file mode 100644
index 000000000000..92bfd51d1ba8
--- /dev/null
+++ b/test/CodeGenCXX/2008-01-12-VecInit.cpp
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+// rdar://5685492
+
+typedef int __attribute__((vector_size(16))) v;
+v vt = {1, 2, 3, 4};
diff --git a/test/CodeGenCXX/2008-05-07-CrazyOffsetOf.cpp b/test/CodeGenCXX/2008-05-07-CrazyOffsetOf.cpp
new file mode 100644
index 000000000000..f842f958e9e6
--- /dev/null
+++ b/test/CodeGenCXX/2008-05-07-CrazyOffsetOf.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+// rdar://5914926
+
+struct bork {
+ struct bork *next_local;
+ char * query;
+};
+int offset = (char *) &(((struct bork *) 0x10)->query) - (char *) 0x10;
diff --git a/test/CodeGenCXX/2009-03-17-dbg.cpp b/test/CodeGenCXX/2009-03-17-dbg.cpp
new file mode 100644
index 000000000000..e2e6c5a2dd29
--- /dev/null
+++ b/test/CodeGenCXX/2009-03-17-dbg.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null -g
+
+template <typename T1,typename T2>
+inline void f(const T1&,const T2&) { }
+
+template <typename T1,typename T2,void F(const T1&,const T2&)>
+struct A {
+ template <typename T> void g(T& i) { }
+};
+
+int main() {
+ int i;
+ A<int,int,f> a;
+ a.g(i);
+}
diff --git a/test/CodeGenCXX/2009-04-23-bool2.cpp b/test/CodeGenCXX/2009-04-23-bool2.cpp
new file mode 100644
index 000000000000..cf81cc42eae4
--- /dev/null
+++ b/test/CodeGenCXX/2009-04-23-bool2.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+// g++.old-deja/g++.jason/bool2.C from gcc testsuite.
+// Crashed before 67975 went in.
+struct F {
+ bool b1 : 1;
+ bool b2 : 7;
+};
+
+int main()
+{
+ F f = { true, true };
+
+ if (int (f.b1) != 1)
+ return 1;
+}
diff --git a/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp b/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp
new file mode 100644
index 000000000000..8361680546f3
--- /dev/null
+++ b/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fexceptions -emit-llvm %s -o - | FileCheck %s
+int c(void) __attribute__((const));
+int p(void) __attribute__((pure));
+int t(void);
+
+// CHECK: define i32 @_Z1fv() {
+int f(void) {
+ // CHECK: call i32 @_Z1cv() nounwind readnone
+ // CHECK: call i32 @_Z1pv() nounwind readonly
+ return c() + p() + t();
+}
+
+// CHECK: declare i32 @_Z1cv() nounwind readnone
+// CHECK: declare i32 @_Z1pv() nounwind readonly
+// CHECK-NOT: declare i32 @_Z1tv() nounwind
diff --git a/test/CodeGenCXX/2009-06-16-DebugInfoCrash.cpp b/test/CodeGenCXX/2009-06-16-DebugInfoCrash.cpp
new file mode 100644
index 000000000000..500520b567f5
--- /dev/null
+++ b/test/CodeGenCXX/2009-06-16-DebugInfoCrash.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null -g
+// This crashes if we try to emit debug info for TEMPLATE_DECL members.
+template <class T> class K2PtrVectorBase {};
+template <class T> class K2Vector {};
+template <class U > class K2Vector<U*> : public K2PtrVectorBase<U*> {};
+class ScriptInfoManager {
+ void PostRegister() ;
+ template <class SI> short ReplaceExistingElement(K2Vector<SI*>& v);
+};
+void ScriptInfoManager::PostRegister() {}
diff --git a/test/CodeGenCXX/2009-07-16-Using.cpp b/test/CodeGenCXX/2009-07-16-Using.cpp
new file mode 100644
index 000000000000..a692d4dbc32e
--- /dev/null
+++ b/test/CodeGenCXX/2009-07-16-Using.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+namespace A {
+ typedef int B;
+}
+struct B {
+};
+using ::A::B;
diff --git a/test/CodeGenCXX/2009-08-05-ZeroInitWidth.cpp b/test/CodeGenCXX/2009-08-05-ZeroInitWidth.cpp
new file mode 100644
index 000000000000..4404d4a8d518
--- /dev/null
+++ b/test/CodeGenCXX/2009-08-05-ZeroInitWidth.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+// rdar://7114564
+struct A {
+ unsigned long long : (sizeof(unsigned long long) * 8) - 16;
+};
+struct B {
+ A a;
+};
+struct B b = {
+ {}
+};
diff --git a/test/CodeGenCXX/2009-08-11-VectorRetTy.cpp b/test/CodeGenCXX/2009-08-11-VectorRetTy.cpp
new file mode 100644
index 000000000000..21b88c93ad7f
--- /dev/null
+++ b/test/CodeGenCXX/2009-08-11-VectorRetTy.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 %s -emit-llvm -o /dev/null
+// <rdar://problem/7096460>
+typedef void (*Func) ();
+typedef long long m64 __attribute__((__vector_size__(8), __may_alias__));
+static inline m64 __attribute__((__always_inline__, __nodebug__)) _mm_set1_pi16() {}
+template <class MM>
+static void Bork() {
+ const m64 mmx_0x00ff = _mm_set1_pi16();
+}
+struct A {};
+Func arr[] = {
+ Bork<A>
+};
diff --git a/test/CodeGenCXX/2009-09-09-packed-layout.cpp b/test/CodeGenCXX/2009-09-09-packed-layout.cpp
new file mode 100644
index 000000000000..9de2f61420c4
--- /dev/null
+++ b/test/CodeGenCXX/2009-09-09-packed-layout.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -emit-llvm -triple i386-apple-darwin11 %s -o /dev/null
+class X {
+ public:
+ virtual ~X();
+ short y;
+};
+#pragma pack(push, 1)
+class Z : public X {
+ public: enum { foo = ('x') };
+ virtual int y() const;
+};
+#pragma pack(pop)
+class Y : public X {
+public: enum { foo = ('y'), bar = 0 };
+};
+X x;
+Y y;
+Z z;
diff --git a/test/CodeGenCXX/2009-10-27-crash.cpp b/test/CodeGenCXX/2009-10-27-crash.cpp
new file mode 100644
index 000000000000..482bb752995f
--- /dev/null
+++ b/test/CodeGenCXX/2009-10-27-crash.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+// Radar 7328944
+
+typedef struct
+{
+ unsigned short a : 1;
+ unsigned short b : 2;
+ unsigned short c : 1;
+ unsigned short d : 1;
+ unsigned short e : 1;
+ unsigned short f : 1;
+ unsigned short g : 2;
+ unsigned short : 7;
+ union
+ {
+ struct
+ {
+ unsigned char h : 1;
+ unsigned char i : 1;
+ unsigned char j : 1;
+ unsigned char : 5;
+ };
+ struct
+ {
+ unsigned char k : 3;
+ unsigned char : 5;
+ };
+ };
+ unsigned char : 8;
+} tt;
+
+typedef struct
+{
+ unsigned char s;
+ tt t;
+ unsigned int u;
+} ttt;
+
+ttt X = {
+ 4,
+ { 0 },
+ 55,
+};
diff --git a/test/CodeGenCXX/2009-12-23-MissingSext.cpp b/test/CodeGenCXX/2009-12-23-MissingSext.cpp
new file mode 100644
index 000000000000..e6ff7b3952c5
--- /dev/null
+++ b/test/CodeGenCXX/2009-12-23-MissingSext.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -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.
+struct foo {
+ char x:8;
+ signed int y:24;
+};
+int bar(struct foo p, int x) {
+// CHECK: bar
+// CHECK: and {{.*}} 16777215
+// CHECK: and {{.*}} 16777215
+ x = (p.y > x ? x : p.y);
+ return x;
+// CHECK: ret
+}
diff --git a/test/CodeGenCXX/2010-05-10-Var-DbgInfo.cpp b/test/CodeGenCXX/2010-05-10-Var-DbgInfo.cpp
new file mode 100644
index 000000000000..7c05535b3587
--- /dev/null
+++ b/test/CodeGenCXX/2010-05-10-Var-DbgInfo.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -emit-llvm -O0 -g %s -o /dev/null
+// PR 7104
+
+struct A {
+ int Ai;
+};
+
+struct B : public A {};
+struct C : public B {};
+
+const char * f(int C::*){ return ""; }
+int f(int B::*) { return 1; }
+
+struct D : public C {};
+
+const char * g(int B::*){ return ""; }
+int g(int D::*) { return 1; }
+
+void test()
+{
+ int i = f(&A::Ai);
+
+ const char * str = g(&A::Ai);
+}
+
+// conversion of B::* to C::* is better than conversion of A::* to C::*
+typedef void (A::*pmfa)();
+typedef void (B::*pmfb)();
+typedef void (C::*pmfc)();
+
+struct X {
+ operator pmfa();
+ operator pmfb();
+};
+
+
+void g(pmfc);
+
+void test2(X x)
+{
+ g(x);
+}
diff --git a/test/CodeGenCXX/2010-05-11-alwaysinlineinstantiation.cpp b/test/CodeGenCXX/2010-05-11-alwaysinlineinstantiation.cpp
new file mode 100644
index 000000000000..fe0740b7cb5c
--- /dev/null
+++ b/test/CodeGenCXX/2010-05-11-alwaysinlineinstantiation.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+
+// CHECK-NOT: ZN12basic_stringIcEC1Ev
+// CHECK: ZN12basic_stringIcED1Ev
+// CHECK: ZN12basic_stringIcED1Ev
+template<class charT>
+class basic_string
+{
+public:
+ basic_string();
+ ~basic_string();
+};
+
+template <class charT>
+__attribute__ ((__visibility__("hidden"), __always_inline__)) inline
+basic_string<charT>::basic_string()
+{
+}
+
+template <class charT>
+inline
+basic_string<charT>::~basic_string()
+{
+}
+
+typedef basic_string<char> string;
+
+extern template class basic_string<char>;
+
+int main()
+{
+ string s;
+}
diff --git a/test/CodeGenCXX/2010-05-12-PtrToMember-Dbg.cpp b/test/CodeGenCXX/2010-05-12-PtrToMember-Dbg.cpp
new file mode 100644
index 000000000000..048811f6e641
--- /dev/null
+++ b/test/CodeGenCXX/2010-05-12-PtrToMember-Dbg.cpp
@@ -0,0 +1,17 @@
+//RUN: %clang_cc1 -emit-llvm -g -o - %s | FileCheck %s
+//CHECK: DW_TAG_auto_variable
+class Foo
+{
+ public:
+ int x;
+ int y;
+ Foo (int i, int j) { x = i; y = j; }
+};
+
+
+Foo foo(10, 11);
+
+int main() {
+ int Foo::* pmi = &Foo::y;
+ return foo.*pmi;
+}
diff --git a/test/CodeGenCXX/2010-06-21-LocalVarDbg.cpp b/test/CodeGenCXX/2010-06-21-LocalVarDbg.cpp
new file mode 100644
index 000000000000..2542378e909a
--- /dev/null
+++ b/test/CodeGenCXX/2010-06-21-LocalVarDbg.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -g -emit-llvm %s -o - | FileCheck %s
+// Do not use function name to create named metadata used to hold
+// local variable info. For example. llvm.dbg.lv.~A is an invalid name.
+
+// CHECK-NOT: llvm.dbg.lv.~A
+class A {
+public:
+ ~A() { int i = 0; i++; }
+};
+
+int foo(int i) {
+ A a;
+ return 0;
+}
diff --git a/test/CodeGenCXX/2010-06-22-BitfieldInit.cpp b/test/CodeGenCXX/2010-06-22-BitfieldInit.cpp
new file mode 100644
index 000000000000..f82e527844fd
--- /dev/null
+++ b/test/CodeGenCXX/2010-06-22-BitfieldInit.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -emit-llvm -g %s -o -
+struct TEST2
+{
+ int subid:32;
+ int :0;
+};
+
+typedef struct _TEST3
+{
+ TEST2 foo;
+ TEST2 foo2;
+} TEST3;
+
+TEST3 test =
+ {
+ {0},
+ {0}
+ };
+
+int main() { return 0; }
diff --git a/test/CodeGenCXX/2010-06-22-ZeroBitfield.cpp b/test/CodeGenCXX/2010-06-22-ZeroBitfield.cpp
new file mode 100644
index 000000000000..c2f37f740549
--- /dev/null
+++ b/test/CodeGenCXX/2010-06-22-ZeroBitfield.cpp
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -emit-llvm -g %s -o -
+struct s8_0 { unsigned : 0; };
+struct s8_1 { double x; };
+struct s8 { s8_0 a; s8_1 b; };
+s8 f8() { return s8(); }
diff --git a/test/CodeGenCXX/2010-07-23-DeclLoc.cpp b/test/CodeGenCXX/2010-07-23-DeclLoc.cpp
new file mode 100644
index 000000000000..74054481cdb4
--- /dev/null
+++ b/test/CodeGenCXX/2010-07-23-DeclLoc.cpp
@@ -0,0 +1,86 @@
+// 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]+]],
+// Second: Require that filehandle refer to the correct filename:
+// CHECK: {{^!}}[[filehandle]] = metadata {{![{].*}} metadata !"decl_should_be_here.hpp",
+typedef long unsigned int __darwin_size_t;
+typedef __darwin_size_t size_t;
+typedef unsigned char uint8_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+namespace std {
+ template<typename _Tp> class auto_ptr {
+ _Tp* _M_ptr;
+ public:
+ typedef _Tp element_type;
+ auto_ptr(element_type* __p = 0) throw() : _M_ptr(__p) { }
+ element_type& operator*() const throw() { }
+ };
+}
+class Pointer32 {
+public:
+ typedef uint32_t ptr_t;
+ typedef uint32_t size_t;
+};
+class Pointer64 {
+public:
+ typedef uint64_t ptr_t;
+ typedef uint64_t size_t;
+};
+class BigEndian {};
+class LittleEndian {};
+template <typename _SIZE, typename _ENDIANNESS> class SizeAndEndianness {
+public:
+ typedef _SIZE SIZE;
+};
+typedef SizeAndEndianness<Pointer32, LittleEndian> ISA32Little;
+typedef SizeAndEndianness<Pointer32, BigEndian> ISA32Big;
+typedef SizeAndEndianness<Pointer64, LittleEndian> ISA64Little;
+typedef SizeAndEndianness<Pointer64, BigEndian> ISA64Big;
+template <typename SIZE> class TRange {
+protected:
+ typename SIZE::ptr_t _location;
+ typename SIZE::size_t _length;
+ TRange(typename SIZE::ptr_t location, typename SIZE::size_t length) : _location(location), _length(length) { }
+};
+template <typename SIZE, typename T> class TRangeValue : public TRange<SIZE> {
+ T _value;
+public:
+ TRangeValue(typename SIZE::ptr_t location, typename SIZE::size_t length, T value) : TRange<SIZE>(location, length), _value(value) {};
+};
+template <typename SIZE> class TAddressRelocator {};
+class CSCppSymbolOwner{};
+class CSCppSymbolOwnerData{};
+template <typename SIZE> class TRawSymbolOwnerData
+{
+ TRangeValue< SIZE, uint8_t* > _TEXT_text_section;
+ const char* _dsym_path;
+ uint32_t _dylib_current_version;
+ uint32_t _dylib_compatibility_version;
+public:
+ TRawSymbolOwnerData() :
+ _TEXT_text_section(0, 0, __null), _dsym_path(__null), _dylib_current_version(0), _dylib_compatibility_version(0) {}
+};
+template <typename SIZE_AND_ENDIANNESS> class TExtendedMachOHeader {};
+# 16 "decl_should_be_here.hpp"
+template <typename SIZE_AND_ENDIANNESS> void extract_dwarf_data_from_header(TExtendedMachOHeader<SIZE_AND_ENDIANNESS>& header,
+ TRawSymbolOwnerData<typename SIZE_AND_ENDIANNESS::SIZE>& symbol_owner_data,
+ TAddressRelocator<typename SIZE_AND_ENDIANNESS::SIZE>* address_relocator) {}
+struct CSCppSymbolOwnerHashFunctor {
+ size_t operator()(const CSCppSymbolOwner& symbol_owner) const {
+# 97 "wrong_place_for_decl.cpp"
+ }
+};
+template <typename SIZE_AND_ENDIANNESS> CSCppSymbolOwnerData* create_symbol_owner_data_arch_specific(CSCppSymbolOwner* symbol_owner, const char* dsym_path) {
+ typedef typename SIZE_AND_ENDIANNESS::SIZE SIZE;
+ std::auto_ptr< TRawSymbolOwnerData<SIZE> > data(new TRawSymbolOwnerData<SIZE>());
+ std::auto_ptr< TExtendedMachOHeader<SIZE_AND_ENDIANNESS> > header;
+ extract_dwarf_data_from_header(*header, *data, (TAddressRelocator<typename SIZE_AND_ENDIANNESS::SIZE>*)__null);
+}
+CSCppSymbolOwnerData* create_symbol_owner_data2(CSCppSymbolOwner* symbol_owner, const char* dsym_path) {
+ create_symbol_owner_data_arch_specific< ISA32Little >(symbol_owner, dsym_path);
+ create_symbol_owner_data_arch_specific< ISA32Big >(symbol_owner, dsym_path);
+ create_symbol_owner_data_arch_specific< ISA64Little >(symbol_owner, dsym_path);
+ create_symbol_owner_data_arch_specific< ISA64Big >(symbol_owner, dsym_path);
+}
diff --git a/test/CodeGenCXX/PR5050-constructor-conversion.cpp b/test/CodeGenCXX/PR5050-constructor-conversion.cpp
index 9b993f2506c6..c50dafbbab20 100644
--- a/test/CodeGenCXX/PR5050-constructor-conversion.cpp
+++ b/test/CodeGenCXX/PR5050-constructor-conversion.cpp
@@ -1,7 +1,7 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
+// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
struct A { A(const A&, int i1 = 1); };
diff --git a/test/CodeGenCXX/abstract-class-ctors-dtors.cpp b/test/CodeGenCXX/abstract-class-ctors-dtors.cpp
index e1c1a75e4790..012c2231551d 100644
--- a/test/CodeGenCXX/abstract-class-ctors-dtors.cpp
+++ b/test/CodeGenCXX/abstract-class-ctors-dtors.cpp
@@ -9,7 +9,7 @@ struct A {
// CHECK-NOT: define void @_ZN1AC1Ev
// CHECK: define void @_ZN1AC2Ev
-// CHECK-NOT: define void @_ZN1AD1Ev
+// CHECK: define void @_ZN1AD1Ev
// CHECK: define void @_ZN1AD2Ev
A::A() { }
diff --git a/test/CodeGenCXX/anonymous-union-member-initializer.cpp b/test/CodeGenCXX/anonymous-union-member-initializer.cpp
index 324ff4aee2b7..a12ae53f395f 100644
--- a/test/CodeGenCXX/anonymous-union-member-initializer.cpp
+++ b/test/CodeGenCXX/anonymous-union-member-initializer.cpp
@@ -67,6 +67,55 @@ namespace test2 {
// CHECK: }
}
+namespace PR10512 {
+ struct A {
+ A();
+ A(int);
+ A(long);
+
+ struct {
+ struct {int x;};
+ struct {int y;};
+ };
+ };
+
+ // CHECK: define void @_ZN7PR105121AC2Ev
+ // CHECK: [[THISADDR:%[a-zA-z0-9.]+]] = alloca [[A:%"struct[A-Za-z0-9:.]+"]]
+ // CHECK-NEXT: store [[A]]* [[THIS:%[a-zA-z0-9.]+]], [[A]]** [[THISADDR]]
+ // CHECK-NEXT: [[THIS1:%[a-zA-z0-9.]+]] = load [[A]]** [[THISADDR]]
+ // CHECK-NEXT: ret void
+ A::A() {}
+
+ // CHECK: define void @_ZN7PR105121AC2Ei
+ // CHECK: [[THISADDR:%[a-zA-z0-9.]+]] = alloca [[A:%"struct[A-Za-z0-9:.]+"]]
+ // CHECK-NEXT: [[XADDR:%[a-zA-z0-9.]+]] = alloca i32
+ // CHECK-NEXT: store [[A]]* [[THIS:%[a-zA-z0-9.]+]], [[A]]** [[THISADDR]]
+ // CHECK-NEXT: store i32 [[X:%[a-zA-z0-9.]+]], i32* [[XADDR]]
+ // CHECK-NEXT: [[THIS1:%[a-zA-z0-9.]+]] = load [[A]]** [[THISADDR]]
+ // CHECK-NEXT: {{getelementptr inbounds.*i32 0, i32 0}}
+ // CHECK-NEXT: {{getelementptr inbounds.*i32 0, i32 0}}
+ // CHECK-NEXT: {{getelementptr inbounds.*i32 0, i32 0}}
+ // CHECK-NEXT: [[TMP:%[a-zA-z0-9.]+]] = load i32* [[XADDR]]
+ // CHECK-NEXT: store i32 [[TMP]]
+ // CHECK-NEXT: ret void
+ A::A(int x) : x(x) { }
+
+ // CHECK: define void @_ZN7PR105121AC2El
+ // CHECK: [[THISADDR:%[a-zA-z0-9.]+]] = alloca [[A:%"struct[A-Za-z0-9:.]+"]]
+ // CHECK-NEXT: [[XADDR:%[a-zA-z0-9.]+]] = alloca i64
+ // CHECK-NEXT: store [[A]]* [[THIS:%[a-zA-z0-9.]+]], [[A]]** [[THISADDR]]
+ // CHECK-NEXT: store i64 [[X:%[a-zA-z0-9.]+]], i64* [[XADDR]]
+ // CHECK-NEXT: [[THIS1:%[a-zA-z0-9.]+]] = load [[A]]** [[THISADDR]]
+ // CHECK-NEXT: {{getelementptr inbounds.*i32 0, i32 0}}
+ // CHECK-NEXT: {{getelementptr inbounds.*i32 0, i32 1}}
+ // CHECK-NEXT: {{getelementptr inbounds.*i32 0, i32 0}}
+ // CHECK-NEXT: [[TMP:%[a-zA-z0-9.]+]] = load i64* [[XADDR]]
+ // CHECK-NEXT: [[CONV:%[a-zA-z0-9.]+]] = trunc i64 [[TMP]] to i32
+ // CHECK-NEXT: store i32 [[CONV]]
+ // CHECK-NEXT: ret void
+ A::A(long y) : y(y) { }
+}
+
namespace test3 {
struct A {
union {
diff --git a/test/CodeGenCXX/apple-kext-linkage.C b/test/CodeGenCXX/apple-kext-linkage.C
index 9df11511762c..59d228e2300c 100644
--- a/test/CodeGenCXX/apple-kext-linkage.C
+++ b/test/CodeGenCXX/apple-kext-linkage.C
@@ -13,13 +13,21 @@ void foo() {
Derived d1; // ok
}
+// CHECK: define internal i32 @_Z1fj(
inline unsigned f(unsigned n) { return n == 0 ? 0 : n + f(n-1); }
unsigned g(unsigned n) { return f(n); }
+// rdar://problem/10133200: give explicit instantiations external linkage in kernel mode
+// CHECK: define void @_Z3barIiEvv()
+template <typename T> void bar() {}
+template void bar<int>();
+// CHECK: define internal i32 @_Z5identIiET_S0_(
template <typename X> X ident(X x) { return x; }
+
int foo(int n) { return ident(n); }
-// CHECK-NOT: define linkonce_odr
-// CHECK 5 : define internal
+// CHECK: define internal void @_ZN7DerivedD1Ev(
+// CHECK: define internal void @_ZN7DerivedD0Ev(
+// CHECK: define internal void @_ZN7DeriveddlEPv(
diff --git a/test/CodeGenCXX/arm.cpp b/test/CodeGenCXX/arm.cpp
index dcb27ce0dab3..a767f425553b 100644
--- a/test/CodeGenCXX/arm.cpp
+++ b/test/CodeGenCXX/arm.cpp
@@ -308,9 +308,10 @@ namespace test7 {
// CHECK: ret void
static int x = foo();
- // CHECK: call i8* @llvm.eh.exception()
+ // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ // CHECK-NEXT: cleanup
// CHECK: call void @__cxa_guard_abort(i32* @_ZGVZN5test74testEvE1x)
- // CHECK: call void @llvm.eh.resume(
+ // CHECK: resume { i8*, i32 }
}
}
@@ -347,9 +348,10 @@ namespace test8 {
// CHECK: ret void
static A x;
- // CHECK: call i8* @llvm.eh.exception()
+ // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ // CHECK-NEXT: cleanup
// CHECK: call void @__cxa_guard_abort(i32* @_ZGVZN5test84testEvE1x)
- // CHECK: call void @llvm.eh.resume(
+ // CHECK: resume { i8*, i32 }
}
}
diff --git a/test/CodeGenCXX/array-construction.cpp b/test/CodeGenCXX/array-construction.cpp
index 5efe18322d85..7b565a490c11 100644
--- a/test/CodeGenCXX/array-construction.cpp
+++ b/test/CodeGenCXX/array-construction.cpp
@@ -1,7 +1,7 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
+// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/array-operator-delete-call.cpp b/test/CodeGenCXX/array-operator-delete-call.cpp
index 41b0118fe8a9..1b23c4d137aa 100644
--- a/test/CodeGenCXX/array-operator-delete-call.cpp
+++ b/test/CodeGenCXX/array-operator-delete-call.cpp
@@ -1,7 +1,7 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
+// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/blocks.cpp b/test/CodeGenCXX/blocks.cpp
index 0e310bdbbc13..cc56525e1d54 100644
--- a/test/CodeGenCXX/blocks.cpp
+++ b/test/CodeGenCXX/blocks.cpp
@@ -104,3 +104,27 @@ namespace test3 {
consume(^{ (void) b; });
}
}
+
+// rdar://problem/9971485
+namespace test4 {
+ struct A {
+ A();
+ ~A();
+ };
+
+ void foo(A a);
+
+ void test() {
+ extern void consume(void(^)());
+ consume(^{ return foo(A()); });
+ }
+ // CHECK: define void @_ZN5test44testEv()
+ // CHECK: define internal void @__test_block_invoke
+ // CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1
+ // CHECK-NEXT: bitcast i8*
+ // CHECK-NEXT: call void @_ZN5test41AC1Ev([[A]]* [[TMP]])
+ // CHECK-NEXT: call void @_ZN5test43fooENS_1AE([[A]]* [[TMP]])
+ // CHECK-NEXT: call void @_ZN5test41AD1Ev([[A]]* [[TMP]])
+ // CHECK-NEXT: ret void
+}
+
diff --git a/test/CodeGenCXX/builtins.cpp b/test/CodeGenCXX/builtins.cpp
index 0629c31015c7..4542563717a1 100644
--- a/test/CodeGenCXX/builtins.cpp
+++ b/test/CodeGenCXX/builtins.cpp
@@ -7,3 +7,15 @@ int main() {
// CHECK: call signext i8 @memmove()
return memmove();
}
+
+// <rdar://problem/10063539>
+
+template<int (*Compare)(const char *s1, const char *s2)>
+int equal(const char *s1, const char *s2) {
+ return Compare(s1, s2) == 0;
+}
+
+// CHECK: define weak_odr i32 @_Z5equalIXadL_Z16__builtin_strcmpPKcS1_EEEiS1_S1_
+// CHECK: call i32 @strcmp
+template int equal<&__builtin_strcmp>(const char*, const char*);
+
diff --git a/test/CodeGenCXX/cast-conversion.cpp b/test/CodeGenCXX/cast-conversion.cpp
index b7a9740ddf1c..d023b9abfee0 100644
--- a/test/CodeGenCXX/cast-conversion.cpp
+++ b/test/CodeGenCXX/cast-conversion.cpp
@@ -1,7 +1,7 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
+// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
struct A {
diff --git a/test/CodeGenCXX/class-layout.cpp b/test/CodeGenCXX/class-layout.cpp
index 9569f476dd87..dac0a0ae5467 100644
--- a/test/CodeGenCXX/class-layout.cpp
+++ b/test/CodeGenCXX/class-layout.cpp
@@ -45,3 +45,35 @@ namespace Test5 {
char c;
} *b;
}
+
+// PR10912: don't crash
+namespace Test6 {
+ template <typename T> class A {
+ // If T is complete, IR-gen will want to translate it recursively
+ // when translating T*.
+ T *foo;
+ };
+
+ class B;
+
+ // This causes IR-gen to have an incomplete translation of A<B>
+ // sitting around.
+ A<B> *a;
+
+ class C {};
+ class B : public C {
+ // This forces Sema to instantiate A<B>, which triggers a callback
+ // to IR-gen. Because of the previous, incomplete translation,
+ // IR-gen actually cares, and it immediately tries to complete
+ // A<B>'s IR type. That, in turn, causes the translation of B*.
+ // B isn't complete yet, but it has a definition, and if we try to
+ // compute a record layout for that definition then we'll really
+ // regret it later.
+ A<B> a;
+ };
+
+ // The derived class E and empty base class C are required to
+ // provoke the original assertion.
+ class E : public B {};
+ E *e;
+}
diff --git a/test/CodeGenCXX/conditional-expr-lvalue.cpp b/test/CodeGenCXX/conditional-expr-lvalue.cpp
index a0843c40f071..96aa8b07a664 100644
--- a/test/CodeGenCXX/conditional-expr-lvalue.cpp
+++ b/test/CodeGenCXX/conditional-expr-lvalue.cpp
@@ -5,3 +5,16 @@ void f(bool flag) {
(flag ? a : b) = 3;
}
+
+// PR10756
+namespace test0 {
+ struct A {
+ A(const A &);
+ A &operator=(const A &);
+ A sub() const;
+ void foo() const;
+ };
+ void foo(bool cond, const A &a) {
+ (cond ? a : a.sub()).foo();
+ }
+}
diff --git a/test/CodeGenCXX/constructor-conversion.cpp b/test/CodeGenCXX/constructor-conversion.cpp
index 58d0d39c8107..f50346328500 100644
--- a/test/CodeGenCXX/constructor-conversion.cpp
+++ b/test/CodeGenCXX/constructor-conversion.cpp
@@ -1,7 +1,7 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
+// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/constructor-convert.cpp b/test/CodeGenCXX/constructor-convert.cpp
index 9122dae128ec..7feeaa900af6 100644
--- a/test/CodeGenCXX/constructor-convert.cpp
+++ b/test/CodeGenCXX/constructor-convert.cpp
@@ -2,6 +2,7 @@
// PR5775
class Twine {
+public:
Twine(const char *Str) { }
};
diff --git a/test/CodeGenCXX/constructor-default-arg.cpp b/test/CodeGenCXX/constructor-default-arg.cpp
index dc0ab50ba5c6..32086c1ad37c 100644
--- a/test/CodeGenCXX/constructor-default-arg.cpp
+++ b/test/CodeGenCXX/constructor-default-arg.cpp
@@ -1,7 +1,7 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
+// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/constructor-for-array-members.cpp b/test/CodeGenCXX/constructor-for-array-members.cpp
index ef5900e59c11..7a365cd26da4 100644
--- a/test/CodeGenCXX/constructor-for-array-members.cpp
+++ b/test/CodeGenCXX/constructor-for-array-members.cpp
@@ -1,7 +1,7 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
+// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/constructor-init.cpp b/test/CodeGenCXX/constructor-init.cpp
index a195afe0692f..6af5188a41f6 100644
--- a/test/CodeGenCXX/constructor-init.cpp
+++ b/test/CodeGenCXX/constructor-init.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 %s -emit-llvm -o %t
+// RUN: FileCheck %s < %t
+// RUN: FileCheck -check-prefix=CHECK-PR10720 %s < %t
extern "C" int printf(...);
@@ -149,3 +151,73 @@ template<typename T>
X<T>::X(const X &other) : start(0), end(0) { }
X<int> get_X(X<int> x) { return x; }
+
+namespace PR10720 {
+ struct X {
+ X(const X&);
+ X(X&&);
+ X& operator=(const X&);
+ X& operator=(X&&);
+ ~X();
+ };
+
+ struct pair2 {
+ X second[4];
+
+ // CHECK-PR10720: define linkonce_odr {{.*}} @_ZN7PR107205pair2aSERKS0_
+ // CHECK-PR10720: load
+ // CHECK-PR10720: icmp ne
+ // CHECK-PR10720-NEXT: br i1
+ // CHECK-PR10720: call {{.*}} @_ZN7PR107201XaSERKS0_
+ // CHECK-PR10720: ret
+ pair2 &operator=(const pair2&) = default;
+
+ // CHECK-PR10720: define linkonce_odr {{.*}} @_ZN7PR107205pair2aSEOS0_
+ // CHECK-PR10720: load
+ // CHECK-PR10720: icmp ne
+ // CHECK-PR10720-NEXT: br i1
+ // CHECK-PR10720: call {{.*}} @_ZN7PR107201XaSEOS0_
+ // CHECK-PR10720: ret
+ pair2 &operator=(pair2&&) = default;
+
+ // CHECK-PR10720: define linkonce_odr void @_ZN7PR107205pair2C2EOS0_
+ // CHECK-PR10720-NOT: ret
+ // CHECK-PR10720: load
+ // CHECK-PR10720: icmp ult
+ // CHECK-PR10720-NEXT: br i1
+ // CHECK-PR10720: call void @_ZN7PR107201XC1EOS0_
+ // CHECK-PR10720-NEXT: br label
+ // CHECK-PR10720: ret void
+ pair2(pair2&&) = default;
+
+ // CHECK-PR10720: define linkonce_odr void @_ZN7PR107205pair2C2ERKS0_
+ // CHECK-PR10720-NOT: ret
+ // CHECK-PR10720: load
+ // CHECK-PR10720: icmp ult
+ // CHECK-PR10720-NEXT: br i1
+ // CHECK-PR10720: call void @_ZN7PR107201XC1ERKS0_
+ // CHECK-PR10720-NEXT: br label
+ // CHECK-PR10720: ret void
+ pair2(const pair2&) = default;
+ };
+
+ struct pair {
+ int second[4];
+ // CHECK-PR10720: define linkonce_odr void @_ZN7PR107204pairC2ERKS0_
+ // CHECK-PR10720-NOT: ret
+ // CHECK-PR10720: call void @llvm.memcpy
+ // CHECK-PR10720-NEXT: ret void
+ pair(const pair&) = default;
+ };
+
+ void foo(const pair &x, const pair2 &x2) {
+ pair y(x);
+ pair2 y2(x2);
+ pair2 y2m(static_cast<pair2&&>(y2));
+
+ y2 = x2;
+ y2m = static_cast<pair2&&>(y2);
+ }
+
+}
+
diff --git a/test/CodeGenCXX/constructor-template.cpp b/test/CodeGenCXX/constructor-template.cpp
index 7472d7e5bc63..fe4687c1b303 100644
--- a/test/CodeGenCXX/constructor-template.cpp
+++ b/test/CodeGenCXX/constructor-template.cpp
@@ -1,7 +1,7 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
+// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
// PR4826
diff --git a/test/CodeGenCXX/conversion-function.cpp b/test/CodeGenCXX/conversion-function.cpp
index e2f8f7e17b93..76d9e027d997 100644
--- a/test/CodeGenCXX/conversion-function.cpp
+++ b/test/CodeGenCXX/conversion-function.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
+// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
// XFAIL: *
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/convert-to-fptr.cpp b/test/CodeGenCXX/convert-to-fptr.cpp
index c1c9f63079f9..425f79de5067 100644
--- a/test/CodeGenCXX/convert-to-fptr.cpp
+++ b/test/CodeGenCXX/convert-to-fptr.cpp
@@ -1,7 +1,7 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
+// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/copy-assign-synthesis-1.cpp b/test/CodeGenCXX/copy-assign-synthesis-1.cpp
index 17abeb90d4b3..46d048364118 100644
--- a/test/CodeGenCXX/copy-assign-synthesis-1.cpp
+++ b/test/CodeGenCXX/copy-assign-synthesis-1.cpp
@@ -1,7 +1,7 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
+// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/copy-assign-volatile-synthesis.cpp b/test/CodeGenCXX/copy-assign-volatile-synthesis.cpp
new file mode 100644
index 000000000000..eb13503fdc3f
--- /dev/null
+++ b/test/CodeGenCXX/copy-assign-volatile-synthesis.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+// rdar://9894548
+
+typedef unsigned long word_t;
+typedef unsigned long u64_t;
+typedef unsigned int u32_t;
+
+class ioapic_redir_t {
+public:
+ union {
+ struct {
+ word_t vector : 8;
+
+ word_t delivery_mode : 3;
+ word_t dest_mode : 1;
+
+ word_t delivery_status : 1;
+ word_t polarity : 1;
+ word_t irr : 1;
+ word_t trigger_mode : 1;
+
+ word_t mask : 1;
+ word_t _pad0 : 15;
+
+ word_t dest : 8;
+ };
+ volatile u32_t raw[2];
+ volatile u64_t raw64;
+ };
+};
+
+struct ioapic_shadow_struct
+{
+ ioapic_redir_t redirs[24];
+} ioapic_shadow[16];
+
+void init_ioapic(unsigned long ioapic_id)
+{
+ ioapic_redir_t entry;
+ ioapic_shadow[ioapic_id].redirs[3] = entry;
+}
+
+// CHECK: call void @llvm.memcpy
diff --git a/test/CodeGenCXX/cxx0x-defaulted-templates.cpp b/test/CodeGenCXX/cxx0x-defaulted-templates.cpp
index 09eb4fe7a7f6..f4d5ccc0e331 100644
--- a/test/CodeGenCXX/cxx0x-defaulted-templates.cpp
+++ b/test/CodeGenCXX/cxx0x-defaulted-templates.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s | FileCheck %s
template <typename T>
struct X {
diff --git a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
index 0bac492796f8..f5684d93abd9 100644
--- a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
+++ b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -fexceptions -fcxx-exceptions -std=c++0x -o - %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -fexceptions -fcxx-exceptions -std=c++11 -o - %s | FileCheck %s
struct non_trivial {
non_trivial();
diff --git a/test/CodeGenCXX/cxx0x-initializer-scalars.cpp b/test/CodeGenCXX/cxx0x-initializer-scalars.cpp
new file mode 100644
index 000000000000..10c696604867
--- /dev/null
+++ b/test/CodeGenCXX/cxx0x-initializer-scalars.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s
+
+void f()
+{
+ // CHECK: store i32 0
+ int i{};
+}
diff --git a/test/CodeGenCXX/debug-info-char16.cpp b/test/CodeGenCXX/debug-info-char16.cpp
new file mode 100644
index 000000000000..da8ca051da84
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-char16.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -S -std=c++11 -masm-verbose -g %s -o -| FileCheck %s
+
+//CHECK: .ascii "char16_t"
+//CHECK-NEXT: .byte 0
+//CHECK-NEXT: .byte 16
+
+// 16 is DW_ATE_UTF (0x10) encoding attribute.
+char16_t char_a = u'h';
+
diff --git a/test/CodeGenCXX/debug-info-cxx0x.cpp b/test/CodeGenCXX/debug-info-cxx0x.cpp
index 5753b05d728e..37ccdb01c5c0 100644
--- a/test/CodeGenCXX/debug-info-cxx0x.cpp
+++ b/test/CodeGenCXX/debug-info-cxx0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm-only -std=c++0x -g %s
+// RUN: %clang_cc1 -emit-llvm-only -std=c++11 -g %s
namespace PR9414 {
int f() {
diff --git a/test/CodeGenCXX/debug-info-nullptr.cpp b/test/CodeGenCXX/debug-info-nullptr.cpp
new file mode 100644
index 000000000000..588dc5f3c399
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-nullptr.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -S -std=c++11 -masm-verbose -g %s -o -| FileCheck %s
+
+//CHECK: DW_TAG_unspecified_type
+//CHECK-NEXT: "nullptr_t"
+
+void foo() {
+ decltype(nullptr) t = 0;
+ }
diff --git a/test/CodeGenCXX/debug-info-wchar.cpp b/test/CodeGenCXX/debug-info-wchar.cpp
new file mode 100644
index 000000000000..6f5384966b99
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-wchar.cpp
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -emit-llvm -g %s -o -| FileCheck %s
+void foo() {
+// CHECK: metadata !"wchar_t",
+ const wchar_t w = L'x';
+}
diff --git a/test/CodeGenCXX/debug-info.cpp b/test/CodeGenCXX/debug-info.cpp
index 71c8603a9faa..33b52789caf2 100644
--- a/test/CodeGenCXX/debug-info.cpp
+++ b/test/CodeGenCXX/debug-info.cpp
@@ -55,3 +55,15 @@ void foo() {
const wchar_t c = L'x';
wchar_t d = c;
}
+
+namespace b5249287 {
+template <typename T> class A {
+ struct B;
+};
+
+class Cls {
+ template <typename T> friend class A<T>::B;
+};
+
+Cls obj;
+}
diff --git a/test/CodeGenCXX/delete.cpp b/test/CodeGenCXX/delete.cpp
index 08ce0de3b5c3..5a88f9f92437 100644
--- a/test/CodeGenCXX/delete.cpp
+++ b/test/CodeGenCXX/delete.cpp
@@ -30,7 +30,7 @@ void t4(T *t) {
// PR5102
template <typename T>
class A {
- operator T *() const;
+ public: operator T *() const;
};
void f() {
@@ -122,3 +122,14 @@ namespace test4 {
::delete xp;
}
}
+
+namespace test5 {
+ struct Incomplete;
+ // CHECK: define void @_ZN5test523array_delete_incompleteEPNS_10IncompleteES1_
+ void array_delete_incomplete(Incomplete *p1, Incomplete *p2) {
+ // CHECK: call void @_ZdlPv
+ delete p1;
+ // CHECK: call void @_ZdaPv
+ delete [] p2;
+ }
+}
diff --git a/test/CodeGenCXX/derived-to-base-conv.cpp b/test/CodeGenCXX/derived-to-base-conv.cpp
index c47c83180906..8c51809e0427 100644
--- a/test/CodeGenCXX/derived-to-base-conv.cpp
+++ b/test/CodeGenCXX/derived-to-base-conv.cpp
@@ -1,7 +1,7 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
+// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp
index 33819858149b..d9962e615ec5 100644
--- a/test/CodeGenCXX/destructors.cpp
+++ b/test/CodeGenCXX/destructors.cpp
@@ -237,7 +237,6 @@ namespace test5 {
// CHECK: [[ELEMS:%.*]] = alloca [5 x [[A:%.*]]], align
// CHECK-NEXT: [[EXN:%.*]] = alloca i8*
// CHECK-NEXT: [[SEL:%.*]] = alloca i32
- // CHECK-NEXT: [[EHCLEANUP:%.*]] = alloca i32
// CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [5 x [[A]]]* [[ELEMS]], i32 0, i32 0
// CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 5
// CHECK-NEXT: br label
@@ -323,7 +322,32 @@ namespace test7 {
// CHECK: invoke void @_ZN5test71DD1Ev(
// CHECK: call void @_ZN5test71AD2Ev(
B::~B() {}
+}
+
+// PR10467
+namespace test8 {
+ struct A { A(); ~A(); };
+ void die() __attribute__((noreturn));
+ void test() {
+ A x;
+ while (1) {
+ A y;
+ goto l;
+ }
+ l: die();
+ }
+
+ // CHECK: define void @_ZN5test84testEv()
+ // CHECK: [[X:%.*]] = alloca [[A:%.*]], align 1
+ // CHECK-NEXT: [[Y:%.*]] = alloca [[A:%.*]], align 1
+ // CHECK: call void @_ZN5test81AC1Ev([[A]]* [[X]])
+ // CHECK-NEXT: br label
+ // CHECK: invoke void @_ZN5test81AC1Ev([[A]]* [[Y]])
+ // CHECK: invoke void @_ZN5test81AD1Ev([[A]]* [[Y]])
+ // CHECK-NOT: switch
+ // CHECK: invoke void @_ZN5test83dieEv()
+ // CHECK: unreachable
}
// Checks from test3:
@@ -332,9 +356,10 @@ namespace test7 {
// CHECK: invoke void @_ZN5test312_GLOBAL__N_11DD1Ev(
// CHECK: call void @_ZdlPv({{.*}}) nounwind
// CHECK: ret void
- // CHECK: call i8* @llvm.eh.exception(
+ // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ // CHECK-NEXT: cleanup
// CHECK: call void @_ZdlPv({{.*}}) nounwind
- // CHECK: call void @llvm.eh.resume(
+ // CHECK: resume { i8*, i32 }
// Checked at top of file:
// @_ZN5test312_GLOBAL__N_11DD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11DD2Ev
@@ -362,9 +387,10 @@ namespace test7 {
// CHECK: invoke void @_ZN5test312_GLOBAL__N_11CD1Ev(
// CHECK: call void @_ZdlPv({{.*}}) nounwind
// CHECK: ret void
- // CHECK: call i8* @llvm.eh.exception()
+ // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ // CHECK-NEXT: cleanup
// CHECK: call void @_ZdlPv({{.*}}) nounwind
- // CHECK: call void @llvm.eh.resume(
+ // CHECK: resume { i8*, i32 }
// CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev(
// CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
diff --git a/test/CodeGenCXX/dynamic-cast-always-null.cpp b/test/CodeGenCXX/dynamic-cast-always-null.cpp
index e4e86942181d..2c3ea13d1957 100644
--- a/test/CodeGenCXX/dynamic-cast-always-null.cpp
+++ b/test/CodeGenCXX/dynamic-cast-always-null.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions -std=c++0x -o - | FileCheck %s
+// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions -std=c++11 -o - | FileCheck %s
struct A { virtual ~A(); };
struct B final : A { };
struct C { virtual ~C(); int c; };
diff --git a/test/CodeGenCXX/dynamic-cast.cpp b/test/CodeGenCXX/dynamic-cast.cpp
index e84bb9b4ff50..813e36e941b7 100644
--- a/test/CodeGenCXX/dynamic-cast.cpp
+++ b/test/CodeGenCXX/dynamic-cast.cpp
@@ -11,7 +11,8 @@ const B& f(A *a) {
// CHECK: invoke void @__cxa_bad_cast() noreturn
dynamic_cast<const B&>(*a);
} catch (...) {
- // CHECK: call i8* @llvm.eh.exception
+ // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ // CHECK-NEXT: catch i8* null
}
return fail;
}
diff --git a/test/CodeGenCXX/eh.cpp b/test/CodeGenCXX/eh.cpp
index 58cb44515ddf..584af40da62d 100644
--- a/test/CodeGenCXX/eh.cpp
+++ b/test/CodeGenCXX/eh.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin -std=c++0x -emit-llvm %s -o %t.ll
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin -std=c++11 -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s
struct test1_D {
@@ -32,7 +32,6 @@ void test2() {
// CHECK: define void @_Z5test2v()
// CHECK: [[EXNVAR:%.*]] = alloca i8*
// CHECK-NEXT: [[SELECTORVAR:%.*]] = alloca i32
-// CHECK-NEXT: [[CLEANUPDESTVAR:%.*]] = alloca i32
// CHECK-NEXT: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 16)
// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]]
// CHECK-NEXT: invoke void @_ZN7test2_DC1ERKS_([[DSTAR]] [[EXN]], [[DSTAR]] @d2)
@@ -107,7 +106,6 @@ namespace test7 {
// CHECK: [[CAUGHTEXNVAR:%.*]] = alloca i8*
// CHECK-NEXT: [[SELECTORVAR:%.*]] = alloca i32
// CHECK-NEXT: [[INTCATCHVAR:%.*]] = alloca i32
-// CHECK-NEXT: [[EHCLEANUPDESTVAR:%.*]] = alloca i32
try {
try {
// CHECK-NEXT: [[EXNALLOC:%.*]] = call i8* @__cxa_allocate_exception
@@ -117,25 +115,34 @@ namespace test7 {
throw 1;
}
-// CHECK: [[CAUGHTEXN:%.*]] = call i8* @llvm.eh.exception()
+// CHECK: [[CAUGHTVAL:%.*]] = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+// CHECK-NEXT: catch i8* bitcast (i8** @_ZTIi to i8*)
+// CHECK-NEXT: catch i8* null
+// CHECK-NEXT: [[CAUGHTEXN:%.*]] = extractvalue { i8*, i32 } [[CAUGHTVAL]], 0
// CHECK-NEXT: store i8* [[CAUGHTEXN]], i8** [[CAUGHTEXNVAR]]
-// CHECK-NEXT: [[SELECTOR:%.*]] = call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* [[CAUGHTEXN]], i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*), i8* null)
+// CHECK-NEXT: [[SELECTOR:%.*]] = extractvalue { i8*, i32 } [[CAUGHTVAL]], 1
// CHECK-NEXT: store i32 [[SELECTOR]], i32* [[SELECTORVAR]]
-// CHECK-NEXT: call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
-// CHECK-NEXT: icmp eq
+// CHECK-NEXT: br label
+// CHECK: [[SELECTOR:%.*]] = load i32* [[SELECTORVAR]]
+// CHECK-NEXT: [[T0:%.*]] = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
+// CHECK-NEXT: icmp eq i32 [[SELECTOR]], [[T0]]
// CHECK-NEXT: br i1
-// CHECK: load i8** [[CAUGHTEXNVAR]]
-// CHECK-NEXT: call i8* @__cxa_begin_catch
-// CHECK: invoke void @__cxa_rethrow
+// CHECK: [[T0:%.*]] = load i8** [[CAUGHTEXNVAR]]
+// CHECK-NEXT: [[T1:%.*]] = call i8* @__cxa_begin_catch(i8* [[T0]])
+// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to i32*
+// CHECK-NEXT: [[T3:%.*]] = load i32* [[T2]]
+// CHECK-NEXT: store i32 [[T3]], i32* {{%.*}}, align 4
+// CHECK-NEXT: invoke void @__cxa_rethrow
catch (int) {
throw;
}
}
-// CHECK: [[CAUGHTEXN:%.*]] = call i8* @llvm.eh.exception()
+// CHECK: [[CAUGHTVAL:%.*]] = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+// CHECK-NEXT: catch i8* null
+// CHECK-NEXT: [[CAUGHTEXN:%.*]] = extractvalue { i8*, i32 } [[CAUGHTVAL]], 0
// CHECK-NEXT: store i8* [[CAUGHTEXN]], i8** [[CAUGHTEXNVAR]]
-// CHECK-NEXT: [[SELECTOR:%.*]] = call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* [[CAUGHTEXN]], i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* null)
+// CHECK-NEXT: [[SELECTOR:%.*]] = extractvalue { i8*, i32 } [[CAUGHTVAL]], 1
// CHECK-NEXT: store i32 [[SELECTOR]], i32* [[SELECTORVAR]]
-// CHECK-NEXT: store i32 1, i32* [[EHCLEANUPDESTVAR]]
// CHECK-NEXT: call void @__cxa_end_catch()
// CHECK-NEXT: br label
// CHECK: load i8** [[CAUGHTEXNVAR]]
@@ -186,15 +193,14 @@ namespace test9 {
// CHECK: invoke void @_ZN5test96opaqueEv()
opaque();
} catch (int x) {
+ // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ // CHECK-NEXT: catch i8* bitcast (i8** @_ZTIi to i8*)
+
// CHECK: call i8* @__cxa_begin_catch
// CHECK: invoke void @_ZN5test96opaqueEv()
// CHECK: invoke void @__cxa_rethrow()
opaque();
}
-
- // landing pad from first call to invoke
- // CHECK: call i8* @llvm.eh.exception
- // CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* {{.*}}, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*))
}
// __cxa_end_catch can throw for some kinds of caught exceptions.
@@ -296,10 +302,7 @@ namespace test12 {
// CHECK: invoke void @_ZN6test121AD1Ev([[A]]* [[Z]])
// CHECK: invoke void @_ZN6test121AD1Ev([[A]]* [[Y]])
-
- // It'd be great if something eliminated this switch.
- // CHECK: load i32* [[CLEANUPDEST]]
- // CHECK-NEXT: switch i32
+ // CHECK-NOT: switch
goto success;
}
@@ -409,7 +412,6 @@ namespace test16 {
// CHECK-NEXT: [[TEMP:%.*]] = alloca [[A:%.*]],
// CHECK-NEXT: [[EXNSLOT:%.*]] = alloca i8*
// CHECK-NEXT: [[SELECTORSLOT:%.*]] = alloca i32
- // CHECK-NEXT: [[EHDEST:%.*]] = alloca i32
// CHECK-NEXT: [[TEMP_ACTIVE:%.*]] = alloca i1
cond() ? throw B(A()) : foo();
diff --git a/test/CodeGenCXX/exceptions.cpp b/test/CodeGenCXX/exceptions.cpp
index b32b90bf7412..0fbb09c2624a 100644
--- a/test/CodeGenCXX/exceptions.cpp
+++ b/test/CodeGenCXX/exceptions.cpp
@@ -276,7 +276,6 @@ namespace test5 {
// CHECK-NEXT: [[SELECTORSLOT:%.*]] = alloca i32
// CHECK-NEXT: [[A:%.*]] = alloca [[A_T:%.*]], align 1
// CHECK-NEXT: [[T:%.*]] = alloca [[T_T:%.*]], align 1
- // CHECK-NEXT: alloca i32
// CHECK-NEXT: invoke void @_ZN5test53fooEv()
// CHECK: [[EXN:%.*]] = load i8** [[EXNSLOT]]
// CHECK-NEXT: [[ADJ:%.*]] = call i8* @__cxa_get_exception_ptr(i8* [[EXN]])
@@ -325,7 +324,6 @@ namespace test7 {
// CHECK-NEXT: alloca [[A:%.*]],
// CHECK-NEXT: alloca i8*
// CHECK-NEXT: alloca i32
- // CHECK-NEXT: alloca i32
// CHECK-NEXT: [[OUTER_A:%.*]] = alloca i1
// CHECK-NEXT: alloca i8*
// CHECK-NEXT: [[INNER_NEW:%.*]] = alloca i1
@@ -392,3 +390,38 @@ namespace test7 {
return new B(A(), new B(A(), 0));
}
}
+
+// Just don't crash.
+namespace test8 {
+ struct A {
+ // Having both of these is required to trigger the assert we're
+ // trying to avoid.
+ A(const A&);
+ A&operator=(const A&);
+
+ ~A();
+ };
+
+ A makeA();
+ void test() {
+ throw makeA();
+ }
+ // CHECK: define void @_ZN5test84testEv
+}
+
+// Make sure we generate the correct code for the delete[] call which
+// happens if A::A() throws. (We were previously calling delete[] on
+// a pointer to the first array element, not the pointer returned by new[].)
+// PR10870
+namespace test9 {
+ struct A {
+ A();
+ ~A();
+ };
+ A* test() {
+ return new A[10];
+ }
+ // CHECK: define {{%.*}}* @_ZN5test94testEv
+ // CHECK: [[TEST9_NEW:%.*]] = call noalias i8* @_Znam
+ // CHECK: call void @_ZdaPv(i8* [[TEST9_NEW]])
+}
diff --git a/test/CodeGenCXX/for-range-temporaries.cpp b/test/CodeGenCXX/for-range-temporaries.cpp
index be594ce5223d..c705702f4f51 100644
--- a/test/CodeGenCXX/for-range-temporaries.cpp
+++ b/test/CodeGenCXX/for-range-temporaries.cpp
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++0x -emit-llvm -o - -UDESUGAR %s | opt -instnamer -S | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++0x -emit-llvm -o - -DDESUGAR %s | opt -instnamer -S | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR %s | opt -instnamer -S | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR %s | opt -instnamer -S | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE %s | opt -instnamer -S | FileCheck %s
struct A {
A();
@@ -65,6 +66,9 @@ struct I {
void body(const I &);
+#ifdef TEMPLATE
+template<typename D>
+#endif
void for_temps() {
A a;
#ifdef DESUGAR
@@ -83,7 +87,11 @@ void for_temps() {
#endif
}
-// CHECK: define void @_Z9for_tempsv()
+#ifdef TEMPLATE
+template void for_temps<D>();
+#endif
+
+// CHECK: define {{.*}}for_temps
// CHECK: call void @_ZN1AC1Ev(
// CHECK: call void @_ZN1BC1Ev(
// CHECK: call void @_ZN1CC1ERK1B(
diff --git a/test/CodeGenCXX/for-range.cpp b/test/CodeGenCXX/for-range.cpp
index ab1a2317ba93..0f35dda737fe 100644
--- a/test/CodeGenCXX/for-range.cpp
+++ b/test/CodeGenCXX/for-range.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++0x -emit-llvm -o - %s | opt -instnamer -S | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - %s | opt -instnamer -S | FileCheck %s
struct A {
A();
diff --git a/test/CodeGenCXX/fp16-mangle.cpp b/test/CodeGenCXX/fp16-mangle.cpp
new file mode 100644
index 000000000000..4a056d6c6bbb
--- /dev/null
+++ b/test/CodeGenCXX/fp16-mangle.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-linux-gnueabi %s | FileCheck %s
+
+// CHECK: @_ZN1SIDhDhE1iE = global i32 3
+template <typename T, typename U> struct S { static int i; };
+template <> int S<__fp16, __fp16>::i = 3;
+
+// CHECK: define void @_Z1fPDh(i16* %x)
+void f (__fp16 *x) { }
+
+// CHECK: define void @_Z1gPDhS_(i16* %x, i16* %y)
+void g (__fp16 *x, __fp16 *y) { }
+
diff --git a/test/CodeGenCXX/fp16-overload.cpp b/test/CodeGenCXX/fp16-overload.cpp
new file mode 100644
index 000000000000..75622109c175
--- /dev/null
+++ b/test/CodeGenCXX/fp16-overload.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-linux-gnueabi %s | FileCheck %s
+
+extern int foo(float x);
+extern int foo(double x);
+
+__fp16 a;
+
+// CHECK: call i32 @_Z3foof
+// CHECK-NOT: call i32 @_Z3food
+int bar (void) { return foo(a); }
diff --git a/test/CodeGenCXX/global-array-destruction.cpp b/test/CodeGenCXX/global-array-destruction.cpp
index bbe574daa588..5b5dfac0f228 100644
--- a/test/CodeGenCXX/global-array-destruction.cpp
+++ b/test/CodeGenCXX/global-array-destruction.cpp
@@ -1,5 +1,5 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/goto.cpp b/test/CodeGenCXX/goto.cpp
index 9a12a9125398..f32847d122bc 100644
--- a/test/CodeGenCXX/goto.cpp
+++ b/test/CodeGenCXX/goto.cpp
@@ -13,7 +13,6 @@ namespace test0 {
// CHECK-NEXT: [[Z:%.*]] = alloca [[A]]
// CHECK-NEXT: [[EXN:%.*]] = alloca i8*
// CHECK-NEXT: [[SEL:%.*]] = alloca i32
- // CHECK-NEXT: alloca i32
// CHECK-NEXT: [[V:%.*]] = alloca [[V:%.*]]*,
// CHECK-NEXT: [[TMP:%.*]] = alloca [[A]]
// CHECK-NEXT: [[CLEANUPACTIVE:%.*]] = alloca i1
diff --git a/test/CodeGenCXX/init-incomplete-type.cpp b/test/CodeGenCXX/incomplete-types.cpp
index 1755dfb7beb1..1d4f430e5cb5 100644
--- a/test/CodeGenCXX/init-incomplete-type.cpp
+++ b/test/CodeGenCXX/incomplete-types.cpp
@@ -28,4 +28,16 @@ namespace incomplete_type_refs {
return &g[1];
}
-} \ No newline at end of file
+}
+
+namespace PR10395 {
+ struct T;
+ extern T x[];
+ T* f() { return x; }
+}
+
+namespace PR10384 {
+ struct X;
+ extern X x[1];
+ X* f() { return x; }
+}
diff --git a/test/CodeGenCXX/m64-ptr.cpp b/test/CodeGenCXX/m64-ptr.cpp
new file mode 100644
index 000000000000..29916bf32a65
--- /dev/null
+++ b/test/CodeGenCXX/m64-ptr.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 %s -emit-llvm -triple x86_64-apple-darwin -o - | FileCheck %s
+
+// Make sure pointers are passed as pointers, not converted to int.
+// The first load should be of type i8** in either 32 or 64 bit mode.
+// This formerly happened on x86-64, 7375899.
+
+class StringRef {
+public:
+ const char *Data;
+ long Len;
+};
+void foo(StringRef X);
+void bar(StringRef &A) {
+// CHECK: @_Z3barR9StringRef
+// CHECK: load i8**
+ foo(A);
+// CHECK: ret void
+}
diff --git a/test/CodeGenCXX/mangle-alias-template.cpp b/test/CodeGenCXX/mangle-alias-template.cpp
index 2020a0a584e1..1143ea114a1a 100644
--- a/test/CodeGenCXX/mangle-alias-template.cpp
+++ b/test/CodeGenCXX/mangle-alias-template.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
template<typename T> struct alloc {};
template<typename T> using Alloc = alloc<T>;
diff --git a/test/CodeGenCXX/mangle-exprs.cpp b/test/CodeGenCXX/mangle-exprs.cpp
index 75294e059c55..c5f72d83c750 100644
--- a/test/CodeGenCXX/mangle-exprs.cpp
+++ b/test/CodeGenCXX/mangle-exprs.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s
template < bool condition, typename T = void >
struct enable_if { typedef T type; };
diff --git a/test/CodeGenCXX/mangle-ref-qualifiers.cpp b/test/CodeGenCXX/mangle-ref-qualifiers.cpp
index b3f37d7db31a..568cf9f24700 100644
--- a/test/CodeGenCXX/mangle-ref-qualifiers.cpp
+++ b/test/CodeGenCXX/mangle-ref-qualifiers.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
struct X {
int f() &;
int g() &&;
diff --git a/test/CodeGenCXX/mangle-subst-std.cpp b/test/CodeGenCXX/mangle-subst-std.cpp
index 30b579ceb823..04e3e84304e8 100644
--- a/test/CodeGenCXX/mangle-subst-std.cpp
+++ b/test/CodeGenCXX/mangle-subst-std.cpp
@@ -3,14 +3,14 @@
// Check mangling of Vtables, VTTs, and construction vtables that
// involve standard substitutions.
-// CHECK: @_ZTTSd = linkonce_odr unnamed_addr constant
// CHECK: @_ZTVSd = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTTSd = linkonce_odr unnamed_addr constant
// CHECK: @_ZTCSd0_Si = linkonce_odr unnamed_addr constant
// CHECK: @_ZTCSd16_So = linkonce_odr unnamed_addr constant
-// CHECK: @_ZTTSo = linkonce_odr unnamed_addr constant
// CHECK: @_ZTVSo = linkonce_odr unnamed_addr constant
-// CHECK: @_ZTTSi = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTTSo = linkonce_odr unnamed_addr constant
// CHECK: @_ZTVSi = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTTSi = linkonce_odr unnamed_addr constant
namespace std {
struct A { A(); };
diff --git a/test/CodeGenCXX/mangle-unnameable-conversions.cpp b/test/CodeGenCXX/mangle-unnameable-conversions.cpp
index 2132eff5e511..2ecded05d979 100644
--- a/test/CodeGenCXX/mangle-unnameable-conversions.cpp
+++ b/test/CodeGenCXX/mangle-unnameable-conversions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
template<typename T> using id = T;
struct S {
diff --git a/test/CodeGenCXX/mangle-variadic-templates.cpp b/test/CodeGenCXX/mangle-variadic-templates.cpp
index a987b49a1281..b5bdae234445 100644
--- a/test/CodeGenCXX/mangle-variadic-templates.cpp
+++ b/test/CodeGenCXX/mangle-variadic-templates.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -emit-llvm -triple=x86_64-apple-darwin9 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -emit-llvm -triple=x86_64-apple-darwin9 -o - %s | FileCheck %s
template<unsigned I, typename ...Types>
struct X { };
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
index 453b7b713ac6..47c42a7347fa 100644
--- a/test/CodeGenCXX/mangle.cpp
+++ b/test/CodeGenCXX/mangle.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -fblocks -std=c++0x | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -fblocks -std=c++11 | FileCheck %s
struct X { };
struct Y { };
@@ -533,17 +533,6 @@ namespace test15 {
template void f<7>(S<7 + e>);
}
-// rdar://problem/8125400. Don't crash.
-namespace test16 {
- static union {};
- static union { union {}; };
- static union { struct {}; };
- static union { union { union {}; }; };
- static union { union { struct {}; }; };
- static union { struct { union {}; }; };
- static union { struct { struct {}; }; };
-}
-
// rdar://problem/8302148
namespace test17 {
template <int N> struct A {};
diff --git a/test/CodeGenCXX/member-alignment.cpp b/test/CodeGenCXX/member-alignment.cpp
new file mode 100644
index 000000000000..8e120f712507
--- /dev/null
+++ b/test/CodeGenCXX/member-alignment.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+// XFAIL: arm,powerpc
+
+// rdar://7268289
+
+class t {
+public:
+ virtual void foo(void);
+ void bar(void);
+};
+
+void
+t::bar(void) {
+// CHECK: _ZN1t3barEv{{.*}} align 2
+}
+
+void
+t::foo(void) {
+// CHECK: _ZN1t3fooEv{{.*}} align 2
+}
diff --git a/test/CodeGenCXX/member-function-pointers.cpp b/test/CodeGenCXX/member-function-pointers.cpp
index 4c42bd8283ae..5ce5fbf760db 100644
--- a/test/CodeGenCXX/member-function-pointers.cpp
+++ b/test/CodeGenCXX/member-function-pointers.cpp
@@ -33,7 +33,7 @@ void f() {
pa = 0;
// Is this okay? What are LLVM's volatile semantics for structs?
- // CHECK: volatile store { i64, i64 } zeroinitializer, { i64, i64 }* @vpa
+ // CHECK: store volatile { i64, i64 } zeroinitializer, { i64, i64 }* @vpa
vpa = 0;
// CHECK: [[TMP:%.*]] = load { i64, i64 }* @pa, align 8
diff --git a/test/CodeGenCXX/member-init-anon-union.cpp b/test/CodeGenCXX/member-init-anon-union.cpp
new file mode 100644
index 000000000000..1ff7537387c2
--- /dev/null
+++ b/test/CodeGenCXX/member-init-anon-union.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - | FileCheck %s
+
+// PR10531.
+
+static union {
+ int a = 42;
+ char *b;
+};
+
+int f() { return a; }
+
+// CHECK: define internal void @__cxx_global_var_init
+// CHECK-NOT: }
+// CHECK: call {{.*}}@"[[CONSTRUCT_GLOBAL:.*]]C1Ev"
+
+
+int g() {
+ union {
+ int a;
+ int b = 81;
+ };
+ // CHECK: define {{.*}}_Z1gv
+ // CHECK-NOT: }
+ // CHECK: call {{.*}}@"[[CONSTRUCT_LOCAL:.*]]C1Ev"
+ return b;
+}
+
+
+// CHECK: define {{.*}}@"[[CONSTRUCT_LOCAL]]C2Ev"
+// CHECK-NOT: }
+// CHECK: store i32 81
+
+// CHECK: define {{.*}}@"[[CONSTRUCT_GLOBAL]]C2Ev"
+// CHECK-NOT: }
+// CHECK: store i32 42
diff --git a/test/CodeGenCXX/member-init-ctor.cpp b/test/CodeGenCXX/member-init-ctor.cpp
index d70947bcab00..21723942571f 100644
--- a/test/CodeGenCXX/member-init-ctor.cpp
+++ b/test/CodeGenCXX/member-init-ctor.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -std=c++0x -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - | FileCheck %s
bool b();
struct S {
diff --git a/test/CodeGenCXX/nrvo.cpp b/test/CodeGenCXX/nrvo.cpp
index 0efb35538038..57bf27ab7aff 100644
--- a/test/CodeGenCXX/nrvo.cpp
+++ b/test/CodeGenCXX/nrvo.cpp
@@ -68,8 +68,10 @@ X test2(bool B) {
// -> %cleanup, %lpad1
// %lpad: landing pad for ctor of 'y', dtor of 'y'
- // CHECK-EH: call i8* @llvm.eh.exception()
- // CHECK-EH: call i32 (i8*, i8*, ...)* @llvm.eh.selector
+ // CHECK-EH: [[CAUGHTVAL:%.*]] = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ // CHECK-EH-NEXT: cleanup
+ // CHECK-EH-NEXT: extractvalue { i8*, i32 } [[CAUGHTVAL]], 0
+ // CHECK-EH-NEXT: extractvalue { i8*, i32 } [[CAUGHTVAL]], 1
// CHECK-EH-NEXT: br label
// -> %eh.cleanup
@@ -95,12 +97,11 @@ X test2(bool B) {
// %invoke.cont17: rethrow block for %eh.cleanup.
// This really should be elsewhere in the function.
- // CHECK-EH: call void @llvm.eh.resume(
- // CHECK-EH-NEXT: unreachable
+ // CHECK-EH: resume { i8*, i32 }
// %terminate.lpad: terminate landing pad.
- // CHECK-EH: call i8* @llvm.eh.exception()
- // CHECK-EH-NEXT: call i32 (i8*, i8*, ...)* @llvm.eh.selector
+ // CHECK-EH: 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: unreachable
diff --git a/test/CodeGenCXX/nullptr.cpp b/test/CodeGenCXX/nullptr.cpp
index 1ea23ec0a95b..e93f7061bdda 100644
--- a/test/CodeGenCXX/nullptr.cpp
+++ b/test/CodeGenCXX/nullptr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -triple x86_64-apple-darwin10 -I%S -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -I%S -emit-llvm -o - %s | FileCheck %s
#include <typeinfo>
diff --git a/test/CodeGenCXX/partial-destruction.cpp b/test/CodeGenCXX/partial-destruction.cpp
index 82deca06cf80..f232a159eda5 100644
--- a/test/CodeGenCXX/partial-destruction.cpp
+++ b/test/CodeGenCXX/partial-destruction.cpp
@@ -16,7 +16,6 @@ namespace test0 {
// CHECK-NEXT: [[ENDVAR:%.*]] = alloca [[A]]*
// CHECK-NEXT: [[EXN:%.*]] = alloca i8*
// CHECK-NEXT: [[SEL:%.*]] = alloca i32
- // CHECK-NEXT: [[CLEANUP:%.*]] = alloca i32
// Initialize.
// CHECK-NEXT: [[E_BEGIN:%.*]] = getelementptr inbounds [10 x [[A]]]* [[AS]], i64 0, i64 0
@@ -51,7 +50,8 @@ namespace test0 {
// CHECK: ret void
// Partial destroy for initialization.
- // CHECK: llvm.eh.selector({{.*}}, i32 0)
+ // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ // CHECK-NEXT: cleanup
// CHECK: [[PARTIAL_END:%.*]] = load [[A]]** [[ENDVAR]]
// CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[E_BEGIN]], [[PARTIAL_END]]
// CHECK-NEXT: br i1 [[T0]],
@@ -62,7 +62,8 @@ namespace test0 {
// CHECK-NEXT: br i1 [[T0]],
// Primary EH destructor.
- // CHECK: llvm.eh.selector({{.*}}, i32 0)
+ // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ // CHECK-NEXT: cleanup
// CHECK: [[E0:%.*]] = getelementptr inbounds [10 x [[A]]]* [[AS]], i32 0, i32 0
// CHECK-NEXT: [[E_END:%.*]] = getelementptr inbounds [[A]]* [[E0]], i64 10
// CHECK-NEXT: br label
@@ -71,7 +72,8 @@ namespace test0 {
// FIXME: There's some really bad block ordering here which causes
// the partial destroy for the primary normal destructor to fall
// within the primary EH destructor.
- // CHECK: llvm.eh.selector({{.*}}, i32 0)
+ // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ // CHECK-NEXT: cleanup
// CHECK: [[T0:%.*]] = icmp eq [[A]]* [[ED_BEGIN]], [[ED_CUR]]
// CHECK-NEXT: br i1 [[T0]]
// CHECK: [[EDD_AFTER:%.*]] = phi [[A]]* [ [[ED_CUR]], {{%.*}} ], [ [[EDD_CUR:%.*]], {{%.*}} ]
@@ -100,7 +102,6 @@ namespace test1 {
// CHECK: [[V:%.*]] = alloca [[B:%.*]], align 4
// CHECK-NEXT: alloca i8*
// CHECK-NEXT: alloca i32
- // CHECK-NEXT: alloca i32
// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds [[B]]* [[V]], i32 0, i32 0
// CHECK-NEXT: call void @_ZN5test11AC1Ei([[A:%.*]]* [[X]], i32 5)
// CHECK-NEXT: [[Y:%.*]] = getelementptr inbounds [[B]]* [[V]], i32 0, i32 1
@@ -113,8 +114,10 @@ namespace test1 {
// CHECK-NEXT: ret void
// FIXME: again, the block ordering is pretty bad here
- // CHECK: eh.selector({{.*}}, i32 0)
- // CHECK: eh.selector({{.*}}, i32 0)
+ // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ // CHECK-NEXT: cleanup
+ // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ // CHECK-NEXT: cleanup
// CHECK: invoke void @_ZN5test11AD1Ev([[A]]* [[Y]])
// CHECK: invoke void @_ZN5test11AD1Ev([[A]]* [[X]])
}
@@ -129,7 +132,6 @@ namespace test2 {
// CHECK: [[V:%.*]] = alloca [4 x [7 x [[A:%.*]]]], align 1
// CHECK-NEXT: alloca i8*
// CHECK-NEXT: alloca i32
- // CHECK-NEXT: alloca i32
// Main initialization loop.
// CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [4 x [7 x [[A]]]]* [[V]], i32 0, i32 0, i32 0
@@ -142,7 +144,8 @@ namespace test2 {
// CHECK-NEXT: br i1 [[DONE]],
// Partial destruction landing pad.
- // CHECK: llvm.eh.exception()
+ // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ // CHECK-NEXT: cleanup
// CHECK: [[EMPTY:%.*]] = icmp eq [[A]]* [[BEGIN]], [[CUR]]
// CHECK-NEXT: br i1 [[EMPTY]],
// CHECK: [[PAST:%.*]] = phi [[A]]* [ [[CUR]], {{%.*}} ], [ [[DEL:%.*]], {{%.*}} ]
diff --git a/test/CodeGenCXX/pr9965.cpp b/test/CodeGenCXX/pr9965.cpp
index 596dee9caaa3..145fd4e424f4 100644
--- a/test/CodeGenCXX/pr9965.cpp
+++ b/test/CodeGenCXX/pr9965.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s | FileCheck %s
template<typename T>
struct X
{
diff --git a/test/CodeGenCXX/ptr-to-member-function.cpp b/test/CodeGenCXX/ptr-to-member-function.cpp
index d012fb9c59b5..3989c0362889 100644
--- a/test/CodeGenCXX/ptr-to-member-function.cpp
+++ b/test/CodeGenCXX/ptr-to-member-function.cpp
@@ -1,7 +1,7 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
+// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s
// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
// 13.3.3.2 Ranking implicit conversion sequences
diff --git a/test/CodeGenCXX/reference-cast.cpp b/test/CodeGenCXX/reference-cast.cpp
index 585d1dbd4084..1d08b2b2e4b7 100644
--- a/test/CodeGenCXX/reference-cast.cpp
+++ b/test/CodeGenCXX/reference-cast.cpp
@@ -168,3 +168,27 @@ const _Complex float &f1() {
// CHECK: store float
return get_complex_double();
}
+
+// CHECK: define i32 @_Z7pr10592RKi(i32*
+unsigned pr10592(const int &v) {
+ // CHECK: [[VADDR:%[a-zA-Z0-9.]+]] = alloca i32*
+ // CHECK-NEXT: [[REFTMP:%[a-zA-Z0-9.]+]] = alloca i32
+ // CHECK-NEXT: store i32* [[V:%[a-zA-Z0-9.]+]], i32** [[VADDR]]
+ // CHECK-NEXT: [[VADDR_1:%[a-zA-Z0-9.]+]] = load i32** [[VADDR]]
+ // CHECK-NEXT: [[VVAL:%[a-zA-Z0-9.]+]] = load i32* [[VADDR_1]]
+ // CHECK-NEXT: store i32 [[VVAL]], i32* [[REFTMP]]
+ // CHECK-NEXT: [[VVAL_I:%[a-zA-Z0-9.]+]] = load i32* [[REFTMP]]
+ // CHECK-NEXT: ret i32 [[VVAL_I]]
+ return static_cast<const unsigned &>(v);
+}
+
+namespace PR10650 {
+ struct Helper {
+ unsigned long long id();
+ };
+ unsigned long long test(Helper *obj) {
+ return static_cast<const unsigned long long&>(obj->id());
+ }
+ // CHECK: define i64 @_ZN7PR106504testEPNS_6HelperE
+ // CHECK: store i64
+}
diff --git a/test/CodeGenCXX/reinterpret-cast.cpp b/test/CodeGenCXX/reinterpret-cast.cpp
index ff5679248c25..dafa67529f77 100644
--- a/test/CodeGenCXX/reinterpret-cast.cpp
+++ b/test/CodeGenCXX/reinterpret-cast.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s -std=c++0x
+// RUN: %clang_cc1 -emit-llvm -o - %s -std=c++11
void *f1(unsigned long l) {
return reinterpret_cast<void *>(l);
}
diff --git a/test/CodeGenCXX/rvalue-references.cpp b/test/CodeGenCXX/rvalue-references.cpp
index e15172355ebd..1c25543beabc 100644
--- a/test/CodeGenCXX/rvalue-references.cpp
+++ b/test/CodeGenCXX/rvalue-references.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
struct Spacer { int x; };
@@ -83,3 +83,29 @@ C test_move_return() {
// CHECK: call void @_ZN1CD1Ev
//CHECK: ret void
}
+
+// PR10800: don't crash
+namespace test1 {
+ int &&move(int&);
+
+ struct A { A(int); };
+ struct B {
+ A a;
+ B(int i);
+ };
+
+ // CHECK: define void @_ZN5test11BC2Ei(
+ // CHECK: [[T0:%.*]] = call i32* @_ZN5test14moveERi(
+ // CHECK-NEXT: [[T1:%.*]] = load i32* [[T0]]
+ // CHECK-NEXT: call void @_ZN5test11AC1Ei({{.*}}, i32 [[T1]])
+ // CHECK-NEXT: ret void
+ B::B(int i) : a(move(i)) {}
+}
+
+// PR11009
+struct MoveConvertible {
+ operator int&& () const;
+};
+void moveConstruct() {
+ (void)(int)MoveConvertible();
+}
diff --git a/test/CodeGenCXX/scoped-enums.cpp b/test/CodeGenCXX/scoped-enums.cpp
index d40ab3651116..fca05098923c 100644
--- a/test/CodeGenCXX/scoped-enums.cpp
+++ b/test/CodeGenCXX/scoped-enums.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -emit-llvm -o - %s
+// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s
// PR9923
enum class Color { red, blue, green };
diff --git a/test/CodeGenCXX/sizeof-unwind-exception.cpp b/test/CodeGenCXX/sizeof-unwind-exception.cpp
new file mode 100644
index 000000000000..5db4df7c75ac
--- /dev/null
+++ b/test/CodeGenCXX/sizeof-unwind-exception.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions %s -O2 -o - | FileCheck %s --check-prefix=X86-64
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions %s -O2 -o - | FileCheck %s --check-prefix=X86-32
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions %s -O2 -o - | FileCheck %s --check-prefix=ARM-DARWIN
+// RUN: %clang_cc1 -triple arm-unknown-gnueabi -emit-llvm -fcxx-exceptions -fexceptions %s -O2 -o - | FileCheck %s --check-prefix=ARM-EABI
+// RUN: %clang_cc1 -triple mipsel-unknown-unknown -emit-llvm -fcxx-exceptions -fexceptions %s -O2 -o - | FileCheck %s --check-prefix=MIPS
+
+void foo();
+void test() {
+ try {
+ foo();
+ } catch (int *&i) {
+ *i = 5;
+ }
+}
+
+// PR10789: different platforms have different sizes for struct UnwindException.
+
+// X86-64: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) nounwind
+// X86-64-NEXT: [[T1:%.*]] = getelementptr i8* [[EXN]], i64 32
+// X86-32: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) nounwind
+// X86-32-NEXT: [[T1:%.*]] = getelementptr i8* [[EXN]], i64 32
+// ARM-DARWIN: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) nounwind
+// ARM-DARWIN-NEXT: [[T1:%.*]] = getelementptr i8* [[EXN]], i64 32
+// ARM-EABI: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) nounwind
+// ARM-EABI-NEXT: [[T1:%.*]] = getelementptr i8* [[EXN]], i32 88
+// MIPS: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) nounwind
+// MIPS-NEXT: [[T1:%.*]] = getelementptr i8* [[EXN]], i32 24
+
diff --git a/test/CodeGenCXX/static-assert.cpp b/test/CodeGenCXX/static-assert.cpp
index dbb8f34d8414..53dc9a73805f 100644
--- a/test/CodeGenCXX/static-assert.cpp
+++ b/test/CodeGenCXX/static-assert.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - -std=c++0x -verify
+// RUN: %clang_cc1 %s -emit-llvm -o - -std=c++11 -verify
static_assert(true, "");
diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp
index d488e636696e..9e2673cc967d 100644
--- a/test/CodeGenCXX/static-init.cpp
+++ b/test/CodeGenCXX/static-init.cpp
@@ -12,13 +12,11 @@ struct A {
};
void f() {
+ // CHECK: load atomic i8* bitcast (i64* @_ZGVZ1fvE1a to i8*) acquire, align 1
// CHECK: call i32 @__cxa_guard_acquire
// CHECK: call void @_ZN1AC1Ev
// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @_ZZ1fvE1a, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
// CHECK: call void @__cxa_guard_release
-
- // rdar://problem/9496726
- // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 false, i1 false, i1 false)
static A a;
}
diff --git a/test/CodeGenCXX/template-instantiation.cpp b/test/CodeGenCXX/template-instantiation.cpp
index cc30af0aba4b..09b3a4fcc544 100644
--- a/test/CodeGenCXX/template-instantiation.cpp
+++ b/test/CodeGenCXX/template-instantiation.cpp
@@ -17,6 +17,19 @@
// CHECK: define linkonce_odr void @_ZN5test21CIiE6foobarIdEEvT_(
// CHECK: define available_externally void @_ZN5test21CIiE6zedbarEd(
+// CHECK: define linkonce_odr void @_ZN7PR106662g1ENS_1SILi1EEE()
+// CHECK: define linkonce_odr void @_ZN7PR106662g1ENS_1SILi2EEE()
+// CHECK: define linkonce_odr void @_ZN7PR106662g1ENS_1SILi3EEE()
+// CHECK: define linkonce_odr void @_ZN7PR106662g2ENS_1SILi1EEE()
+// CHECK: define linkonce_odr void @_ZN7PR106662g2ENS_1SILi2EEE()
+// CHECK: define linkonce_odr void @_ZN7PR106662g2ENS_1SILi3EEE()
+// CHECK: declare void @_ZN7PR106662h1ENS_1SILi1EEE()
+// CHECK: declare void @_ZN7PR106662h1ENS_1SILi2EEE()
+// CHECK: declare void @_ZN7PR106662h1ENS_1SILi3EEE()
+// CHECK: declare void @_ZN7PR106662h2ENS_1SILi1EEE()
+// CHECK: declare void @_ZN7PR106662h2ENS_1SILi2EEE()
+// CHECK: declare void @_ZN7PR106662h2ENS_1SILi3EEE()
+
namespace test0 {
struct basic_streambuf {
virtual ~basic_streambuf();
@@ -152,3 +165,26 @@ namespace PR10001 {
int x = S<int>::f();
}
+
+// Ensure that definitions are emitted for all friend functions defined within
+// class templates. Order of declaration is extremely important here. Different
+// instantiations of the class happen at different points during the deferred
+// method body parsing and afterward. Those different points of instantiation
+// change the exact form the class template appears to have.
+namespace PR10666 {
+ template <int N> struct S {
+ void f1() { S<1> s; }
+ friend void g1(S s) {}
+ friend void h1(S s);
+ void f2() { S<2> s; }
+ friend void g2(S s) {}
+ friend void h2(S s);
+ void f3() { S<3> s; }
+ };
+ void test(S<1> s1, S<2> s2, S<3> s3) {
+ g1(s1); g1(s2); g1(s3);
+ g2(s1); g2(s2); g2(s3);
+ h1(s1); h1(s2); h1(s3);
+ h2(s1); h2(s2); h2(s3);
+ }
+}
diff --git a/test/CodeGenCXX/temporaries.cpp b/test/CodeGenCXX/temporaries.cpp
index 8aeca653da55..98e5ae3e6ee7 100644
--- a/test/CodeGenCXX/temporaries.cpp
+++ b/test/CodeGenCXX/temporaries.cpp
@@ -395,7 +395,7 @@ namespace Elision {
// CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[I]])
}
- // CHECK: define void @_ZN7Elision5test2Ev([[A]]* sret
+ // CHECK: define void @_ZN7Elision5test2Ev([[A]]* noalias sret
A test2() {
// CHECK: call void @_ZN7Elision3fooEv()
// CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[RET:%.*]])
@@ -403,7 +403,7 @@ namespace Elision {
return (foo(), A());
}
- // CHECK: define void @_ZN7Elision5test3EiNS_1AE([[A]]* sret
+ // CHECK: define void @_ZN7Elision5test3EiNS_1AE([[A]]* noalias sret
A test3(int v, A x) {
if (v < 5)
// CHECK: call void @_ZN7Elision1AC1Ev([[A]]* [[RET:%.*]])
@@ -444,7 +444,7 @@ namespace Elision {
}
// rdar://problem/8433352
- // CHECK: define void @_ZN7Elision5test5Ev([[A]]* sret
+ // CHECK: define void @_ZN7Elision5test5Ev([[A]]* noalias sret
struct B { A a; B(); };
A test5() {
// CHECK: [[AT0:%.*]] = alloca [[A]], align 8
diff --git a/test/CodeGenCXX/threadsafe-statics-exceptions.cpp b/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
index aa79a4f6dd3d..769d120be323 100644
--- a/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
+++ b/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
@@ -21,9 +21,8 @@ void f() {
throw Y();
// Finally, the landing pad.
- // CHECK: call i8* @llvm.eh.exception()
- // CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector
+ // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ // CHECK: cleanup
// CHECK: call void @__cxa_guard_abort(i64* @_ZGVZ1fvE1x)
- // CHECK: call void @llvm.eh.resume(
- // CHECK: unreachable
+ // CHECK: resume { i8*, i32 }
}
diff --git a/test/CodeGenCXX/thunk-linkonce-odr.cpp b/test/CodeGenCXX/thunk-linkonce-odr.cpp
new file mode 100644
index 000000000000..4f4d61d5a9a8
--- /dev/null
+++ b/test/CodeGenCXX/thunk-linkonce-odr.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// <rdar://problem/7929157> & <rdar://problem/8104369>
+
+struct A {
+ virtual int f() { return 1; }
+};
+
+struct B {
+ virtual int f() { return 2; }
+};
+
+struct C : A, B {
+ virtual int f() { return 3; }
+};
+
+struct D : C {
+ virtual int f() { return 4; }
+};
+
+static int f(D* d) {
+ B* b = d;
+ return b->f();
+};
+
+int g() {
+ D d;
+ return f(&d);
+}
+
+// Thunks should be marked as "linkonce ODR" not "weak".
+//
+// CHECK: define linkonce_odr i32 @_ZThn{{[48]}}_N1D1fEv
+// CHECK: define linkonce_odr i32 @_ZThn{{[48]}}_N1C1fEv
diff --git a/test/CodeGenCXX/typeid.cpp b/test/CodeGenCXX/typeid.cpp
index 1af96705ba41..7ebf41c09f6c 100644
--- a/test/CodeGenCXX/typeid.cpp
+++ b/test/CodeGenCXX/typeid.cpp
@@ -13,7 +13,8 @@ const char *f() {
// CHECK: invoke void @__cxa_bad_typeid() noreturn
return typeid(*static_cast<A *>(0)).name();
} catch (...) {
- // CHECK: call i8* @llvm.eh.exception
+ // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ // CHECK-NEXT: catch i8* null
}
return 0;
diff --git a/test/CodeGenCXX/union-dtor.cpp b/test/CodeGenCXX/union-dtor.cpp
new file mode 100644
index 000000000000..a0b822aa54dd
--- /dev/null
+++ b/test/CodeGenCXX/union-dtor.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -std=c++11 %s -S -o - -emit-llvm | FileCheck %s
+
+// PR10304: destructors should not call destructors for variant members.
+
+template<bool b = false>
+struct Foo {
+ Foo() { static_assert(b, "Foo::Foo used"); }
+ ~Foo() { static_assert(b, "Foo::~Foo used"); }
+};
+
+struct Bar {
+ Bar();
+ ~Bar();
+};
+
+union FooBar {
+ FooBar() {}
+ ~FooBar() {}
+ Foo<> foo;
+ Bar bar;
+};
+
+struct Variant {
+ Variant() {}
+ ~Variant() {}
+ union {
+ Foo<> foo;
+ Bar bar;
+ };
+};
+
+FooBar foobar;
+Variant variant;
+
+// The ctor and dtor of Foo<> and Bar should not be mentioned in the resulting
+// code.
+//
+// CHECK-NOT: 3FooILb1EEC1
+// CHECK-NOT: 3BarC1
+//
+// CHECK-NOT: 3FooILb1EED1
+// CHECK-NOT: 3BarD1
diff --git a/test/CodeGenCXX/value-init.cpp b/test/CodeGenCXX/value-init.cpp
index 04a18b3fa801..fb981d1ff717 100644
--- a/test/CodeGenCXX/value-init.cpp
+++ b/test/CodeGenCXX/value-init.cpp
@@ -238,6 +238,25 @@ namespace test6 {
// CHECK: ret void
}
+namespace PR11124 {
+ // Make sure C::C doesn't overwrite parts of A while it is zero-initializing B
+ struct A { int a; A(); A(int); };
+ struct B : virtual A { int b; };
+ struct C : B { C(); };
+ C::C() : A(3), B() {}
+ // CHECK: define void @_ZN7PR111241CC1Ev
+ // CHECK: call void @llvm.memset.p0i8.i64(i8* {{.*}}, i8 0, i64 12, i32 8, i1 false)
+ // CHECK-NEXT: call void @_ZN7PR111241BC2Ev
+ // Make sure C::C doesn't overwrite parts of A while it is zero-initializing B
+
+ struct B2 : virtual A { int B::*b; };
+ struct C2 : B2 { C2(); };
+ C2::C2() : A(3), B2() {}
+ // CHECK: define void @_ZN7PR111242C2C1Ev
+ // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.*}}, i8* {{.*}}, i64 16, i32 8, i1 false)
+ // CHECK-NEXT: call void @_ZN7PR111242B2C2Ev
+}
+
// 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/vararg-conversion-ctor.cpp b/test/CodeGenCXX/vararg-conversion-ctor.cpp
index 7e42859ac93e..a49b1dba9961 100644
--- a/test/CodeGenCXX/vararg-conversion-ctor.cpp
+++ b/test/CodeGenCXX/vararg-conversion-ctor.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -emit-llvm %s -o %t-64.ll
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm %s -o %t-64.ll
// RUN: FileCheck -check-prefix LPLL64 --input-file=%t-64.ll %s
extern "C" int printf(...);
diff --git a/test/CodeGenCXX/varargs.cpp b/test/CodeGenCXX/varargs.cpp
new file mode 100644
index 000000000000..af34336a0ae2
--- /dev/null
+++ b/test/CodeGenCXX/varargs.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s
+
+// rdar://7309675
+// PR4678
+namespace test0 {
+ // test1 should be compmiled to be a varargs function in the IR even
+ // though there is no way to do a va_begin. Otherwise, the optimizer
+ // will warn about 'dropped arguments' at the call site.
+
+ // CHECK: define i32 @_ZN5test05test1Ez(...)
+ int test1(...) {
+ return -1;
+ }
+
+ // CHECK: call i32 (...)* @_ZN5test05test1Ez(i32 0)
+ void test() {
+ test1(0);
+ }
+}
+
+namespace test1 {
+ struct A {
+ int x;
+ int y;
+ };
+
+ void foo(...);
+
+ void test() {
+ A x;
+ foo(x);
+ }
+ // CHECK: define void @_ZN5test14testEv()
+ // CHECK: [[X:%.*]] = alloca [[A:%.*]], align 4
+ // CHECK-NEXT: [[TMP:%.*]] = alloca [[A]], align 4
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[TMP]] to i8*
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[X]] to i8*
+ // CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[T0]], i8* [[T1]], i64 8, i32 4, i1 false)
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[TMP]] to i64*
+ // CHECK-NEXT: [[T1:%.*]] = load i64* [[T0]], align 1
+ // CHECK-NEXT: call void (...)* @_ZN5test13fooEz(i64 [[T1]])
+ // CHECK-NEXT: ret void
+}
diff --git a/test/CodeGenCXX/variadic-templates.cpp b/test/CodeGenCXX/variadic-templates.cpp
index 90c837067559..c56bec33a0f8 100644
--- a/test/CodeGenCXX/variadic-templates.cpp
+++ b/test/CodeGenCXX/variadic-templates.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
template<typename ...Types>
int get_num_types(Types...) {
diff --git a/test/CodeGenCXX/visibility.cpp b/test/CodeGenCXX/visibility.cpp
index fdccd4604545..0f36a6a75324 100644
--- a/test/CodeGenCXX/visibility.cpp
+++ b/test/CodeGenCXX/visibility.cpp
@@ -26,8 +26,8 @@
// CHECK: @_ZGVZN6Test193fooIiEEvvE1a = linkonce_odr global i64
// CHECK-HIDDEN: @_ZZN6Test193fooIiEEvvE1a = linkonce_odr hidden global
// CHECK-HIDDEN: @_ZGVZN6Test193fooIiEEvvE1a = linkonce_odr hidden global i64
-// CHECK-HIDDEN: @_ZTTN6Test161AIcEE = external unnamed_addr constant
// CHECK-HIDDEN: @_ZTVN6Test161AIcEE = external unnamed_addr constant
+// CHECK-HIDDEN: @_ZTTN6Test161AIcEE = external unnamed_addr constant
// CHECK: @_ZTVN5Test63fooE = linkonce_odr hidden unnamed_addr constant
namespace Test1 {
diff --git a/test/CodeGenCXX/volatile-1.cpp b/test/CodeGenCXX/volatile-1.cpp
index 1a69648d42a7..71ff1ed7d689 100644
--- a/test/CodeGenCXX/volatile-1.cpp
+++ b/test/CodeGenCXX/volatile-1.cpp
@@ -26,8 +26,8 @@ void test() {
i;
(float)(ci);
- // CHECK-NEXT: volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
// CHECK-NEXT: sitofp [[INT]]
// These are not uses in C++:
@@ -37,202 +37,202 @@ void test() {
(void)a;
(void)(ci=ci);
- // CHECK-NEXT: [[R:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: [[I:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
- // CHECK-NEXT: volatile store [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: volatile store [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
(void)(i=j);
- // CHECK-NEXT: [[T:%.*]] = volatile load [[INT]]* @j
- // CHECK-NEXT: volatile store [[INT]] [[T]], [[INT]]* @i
+ // CHECK-NEXT: [[T:%.*]] = load volatile [[INT]]* @j
+ // CHECK-NEXT: store volatile [[INT]] [[T]], [[INT]]* @i
ci+=ci;
- // CHECK-NEXT: [[R1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: [[I1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
- // CHECK-NEXT: [[R2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: [[I2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
// Not sure why they're ordered this way.
// CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]]
// CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]]
- // CHECK-NEXT: volatile store [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: volatile store [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
- // Note that C++ requires an extra volatile load over C from the LHS of the '+'.
+ // Note that C++ requires an extra load volatile over C from the LHS of the '+'.
(ci += ci) + ci;
- // CHECK-NEXT: [[R1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: [[I1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
- // CHECK-NEXT: [[R2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: [[I2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
// CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]]
// CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]]
- // CHECK-NEXT: volatile store [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: volatile store [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
- // CHECK-NEXT: [[R1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: [[I1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
- // CHECK-NEXT: [[R2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
- // CHECK-NEXT: [[I2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
// These additions can be elided.
// CHECK-NEXT: add [[INT]] [[R1]], [[R2]]
// CHECK-NEXT: add [[INT]] [[I1]], [[I2]]
asm("nop"); // CHECK-NEXT: call void asm
- // Extra volatile load in C++.
+ // Extra load volatile in C++.
(i += j) + k;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: add nsw [[INT]]
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: add nsw [[INT]]
asm("nop"); // CHECK-NEXT: call void asm
- // Extra volatile load in C++.
+ // Extra load volatile in C++.
(i += j) + 1;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: add nsw [[INT]]
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: add nsw [[INT]]
asm("nop"); // CHECK-NEXT: call void asm
ci+ci;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: add [[INT]]
// CHECK-NEXT: add [[INT]]
__real i;
+ci;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
asm("nop"); // CHECK-NEXT: call void asm
(void)(i=i);
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
(float)(i=i);
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: sitofp
(void)i;
i=i;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
- // Extra volatile load in C++.
+ // Extra load volatile in C++.
i=i=i;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
(void)__builtin_choose_expr(0, i=i, j=j);
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
k ? (i=i) : (j=j);
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: icmp
// CHECK-NEXT: br i1
- // CHECK: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK: load volatile
+ // CHECK-NEXT: store volatile
// CHECK-NEXT: br label
- // CHECK: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK: load volatile
+ // CHECK-NEXT: store volatile
// CHECK-NEXT: br label
// CHECK: phi
(void)(i,(i=i));
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
i=i,k;
- // CHECK-NEXT: volatile load [[INT]]* @i
- // CHECK-NEXT: volatile store {{.*}}, [[INT]]* @i
+ // CHECK-NEXT: load volatile [[INT]]* @i
+ // CHECK-NEXT: store volatile {{.*}}, [[INT]]* @i
(i=j,k=j);
- // CHECK-NEXT: volatile load [[INT]]* @j
- // CHECK-NEXT: volatile store {{.*}}, [[INT]]* @i
- // CHECK-NEXT: volatile load [[INT]]* @j
- // CHECK-NEXT: volatile store {{.*}}, [[INT]]* @k
+ // CHECK-NEXT: load volatile [[INT]]* @j
+ // CHECK-NEXT: store volatile {{.*}}, [[INT]]* @i
+ // CHECK-NEXT: load volatile [[INT]]* @j
+ // CHECK-NEXT: store volatile {{.*}}, [[INT]]* @k
(i=j,k);
- // CHECK-NEXT: volatile load [[INT]]* @j
- // CHECK-NEXT: volatile store {{.*}}, [[INT]]* @i
+ // CHECK-NEXT: load volatile [[INT]]* @j
+ // CHECK-NEXT: store volatile {{.*}}, [[INT]]* @i
(i,j);
// Extra load in C++.
i=c=k;
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: trunc
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: sext
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: store volatile
i+=k;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: add nsw [[INT]]
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: store volatile
ci;
asm("nop"); // CHECK-NEXT: call void asm
(int)ci;
- // CHECK-NEXT: volatile load {{.*}} @ci, i32 0, i32 0
- // CHECK-NEXT: volatile load {{.*}} @ci, i32 0, i32 1
+ // CHECK-NEXT: load volatile {{.*}} @ci, i32 0, i32 0
+ // CHECK-NEXT: load volatile {{.*}} @ci, i32 0, i32 1
(bool)ci;
- // CHECK-NEXT: volatile load {{.*}} @ci, i32 0, i32 0
- // CHECK-NEXT: volatile load {{.*}} @ci, i32 0, i32 1
+ // CHECK-NEXT: load volatile {{.*}} @ci, i32 0, i32 0
+ // CHECK-NEXT: load volatile {{.*}} @ci, i32 0, i32 1
// CHECK-NEXT: icmp ne
// CHECK-NEXT: icmp ne
// CHECK-NEXT: or i1
ci=ci;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
asm("nop"); // CHECK-NEXT: call void asm
// Extra load in C++.
ci=ci=ci;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
__imag ci = __imag ci = __imag ci;
- // CHECK-NEXT: [[T:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
- // CHECK-NEXT: volatile store [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
- // CHECK-NEXT: [[T:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
- // CHECK-NEXT: volatile store [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[T:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: store volatile [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[T:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: store volatile [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
__real (i = j);
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
__imag i;
@@ -258,95 +258,95 @@ void test() {
// Not a use. gcc got this wrong in 4.2 and omitted the side effects
// entirely, but it is fixed in 4.4.0.
__imag (i = j);
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
// C++ does an extra load here. Note that we have to do full loads.
(float)(ci=ci);
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: sitofp
// Not a use, bug? gcc treats this as not a use, that's probably a
// bug due to tree folding ignoring volatile.
(int)(ci=ci);
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
// A use.
(float)(i=i);
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: sitofp
// A use. gcc treats this as not a use, that's probably a bug due to tree
// folding ignoring volatile.
(int)(i=i);
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
// A use.
-(i=j);
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: sub
// A use. gcc treats this a not a use, that's probably a bug due to tree
// folding ignoring volatile.
+(i=k);
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
// A use. gcc treats this a not a use, that's probably a bug due to tree
// folding ignoring volatile.
__real (ci=ci);
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile store
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: store volatile
// A use.
i + 0;
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: add
// A use.
(i=j) + i;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: add
// A use. gcc treats this as not a use, that's probably a bug due to tree
// folding ignoring volatile.
(i=j) + 0;
- // CHECK-NEXT: volatile load
- // CHECK-NEXT: volatile store
- // CHECK-NEXT: volatile load
+ // CHECK-NEXT: load volatile
+ // CHECK-NEXT: store volatile
+ // CHECK-NEXT: load volatile
// CHECK-NEXT: add
(i,j)=k;
- // CHECK-NEXT: volatile load [[INT]]* @k
- // CHECK-NEXT: volatile store {{.*}}, [[INT]]* @j
+ // CHECK-NEXT: load volatile [[INT]]* @k
+ // CHECK-NEXT: store volatile {{.*}}, [[INT]]* @j
(j=k,i)=i;
- // CHECK-NEXT: volatile load [[INT]]* @i
- // CHECK-NEXT: volatile load [[INT]]* @k
- // CHECK-NEXT: volatile store {{.*}}, [[INT]]* @j
- // CHECK-NEXT: volatile store {{.*}}, [[INT]]* @i
+ // CHECK-NEXT: load volatile [[INT]]* @i
+ // CHECK-NEXT: load volatile [[INT]]* @k
+ // CHECK-NEXT: store volatile {{.*}}, [[INT]]* @j
+ // CHECK-NEXT: store volatile {{.*}}, [[INT]]* @i
// CHECK-NEXT: ret void
}
diff --git a/test/CodeGenCXX/vtable-layout-abi-examples.cpp b/test/CodeGenCXX/vtable-layout-abi-examples.cpp
index c01c5ef72cc5..8f084a9c5b7b 100644
--- a/test/CodeGenCXX/vtable-layout-abi-examples.cpp
+++ b/test/CodeGenCXX/vtable-layout-abi-examples.cpp
@@ -1,4 +1,15 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts 2>&1 | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts > %t 2>&1
+// RUN: FileCheck --check-prefix=CHECK-1 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-2 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-3 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-4 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-5 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-6 %s < %t
+// 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-10 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-11 %s < %t
/// Examples from the Itanium C++ ABI specification.
/// http://www.codesourcery.com/public/cxx-abi/
@@ -7,13 +18,13 @@ namespace Test1 {
// This is from http://www.codesourcery.com/public/cxx-abi/cxx-vtable-ex.html
-// CHECK: Vtable for 'Test1::A' (5 entries).
-// CHECK-NEXT: 0 | offset_to_top (0)
-// CHECK-NEXT: 1 | Test1::A RTTI
-// CHECK-NEXT: -- (Test1::A, 0) vtable address --
-// CHECK-NEXT: 2 | void Test1::A::f()
-// CHECK-NEXT: 3 | void Test1::A::g()
-// CHECK-NEXT: 4 | void Test1::A::h()
+// CHECK-1: Vtable for 'Test1::A' (5 entries).
+// CHECK-1-NEXT: 0 | offset_to_top (0)
+// CHECK-1-NEXT: 1 | Test1::A RTTI
+// CHECK-1-NEXT: -- (Test1::A, 0) vtable address --
+// CHECK-1-NEXT: 2 | void Test1::A::f()
+// CHECK-1-NEXT: 3 | void Test1::A::g()
+// CHECK-1-NEXT: 4 | void Test1::A::h()
struct A {
virtual void f ();
virtual void g ();
@@ -22,24 +33,24 @@ struct A {
};
void A::f() {}
-// CHECK: Vtable for 'Test1::B' (13 entries).
-// CHECK-NEXT: 0 | vbase_offset (16)
-// CHECK-NEXT: 1 | offset_to_top (0)
-// CHECK-NEXT: 2 | Test1::B RTTI
-// CHECK-NEXT: -- (Test1::B, 0) vtable address --
-// CHECK-NEXT: 3 | void Test1::B::f()
-// CHECK-NEXT: 4 | void Test1::B::h()
-// CHECK-NEXT: 5 | vcall_offset (-16)
-// CHECK-NEXT: 6 | vcall_offset (0)
-// CHECK-NEXT: 7 | vcall_offset (-16)
-// CHECK-NEXT: 8 | offset_to_top (-16)
-// CHECK-NEXT: 9 | Test1::B RTTI
-// CHECK-NEXT: -- (Test1::A, 16) vtable address --
-// CHECK-NEXT: 10 | void Test1::B::f()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
-// CHECK-NEXT: 11 | void Test1::A::g()
-// CHECK-NEXT: 12 | void Test1::B::h()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -40 vcall offset offset]
+// CHECK-2: Vtable for 'Test1::B' (13 entries).
+// CHECK-2-NEXT: 0 | vbase_offset (16)
+// CHECK-2-NEXT: 1 | offset_to_top (0)
+// CHECK-2-NEXT: 2 | Test1::B RTTI
+// CHECK-2-NEXT: -- (Test1::B, 0) vtable address --
+// CHECK-2-NEXT: 3 | void Test1::B::f()
+// CHECK-2-NEXT: 4 | void Test1::B::h()
+// CHECK-2-NEXT: 5 | vcall_offset (-16)
+// CHECK-2-NEXT: 6 | vcall_offset (0)
+// CHECK-2-NEXT: 7 | vcall_offset (-16)
+// CHECK-2-NEXT: 8 | offset_to_top (-16)
+// CHECK-2-NEXT: 9 | Test1::B RTTI
+// CHECK-2-NEXT: -- (Test1::A, 16) vtable address --
+// CHECK-2-NEXT: 10 | void Test1::B::f()
+// CHECK-2-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-2-NEXT: 11 | void Test1::A::g()
+// CHECK-2-NEXT: 12 | void Test1::B::h()
+// CHECK-2-NEXT: [this adjustment: 0 non-virtual, -40 vcall offset offset]
struct B: public virtual A {
void f ();
void h ();
@@ -47,24 +58,24 @@ struct B: public virtual A {
};
void B::f() {}
-// CHECK: Vtable for 'Test1::C' (13 entries).
-// CHECK-NEXT: 0 | vbase_offset (16)
-// CHECK-NEXT: 1 | offset_to_top (0)
-// CHECK-NEXT: 2 | Test1::C RTTI
-// CHECK-NEXT: -- (Test1::C, 0) vtable address --
-// CHECK-NEXT: 3 | void Test1::C::g()
-// CHECK-NEXT: 4 | void Test1::C::h()
-// CHECK-NEXT: 5 | vcall_offset (-16)
-// CHECK-NEXT: 6 | vcall_offset (-16)
-// CHECK-NEXT: 7 | vcall_offset (0)
-// CHECK-NEXT: 8 | offset_to_top (-16)
-// CHECK-NEXT: 9 | Test1::C RTTI
-// CHECK-NEXT: -- (Test1::A, 16) vtable address --
-// CHECK-NEXT: 10 | void Test1::A::f()
-// CHECK-NEXT: 11 | void Test1::C::g()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
-// CHECK-NEXT: 12 | void Test1::C::h()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -40 vcall offset offset]
+// CHECK-3: Vtable for 'Test1::C' (13 entries).
+// CHECK-3-NEXT: 0 | vbase_offset (16)
+// CHECK-3-NEXT: 1 | offset_to_top (0)
+// CHECK-3-NEXT: 2 | Test1::C RTTI
+// CHECK-3-NEXT: -- (Test1::C, 0) vtable address --
+// CHECK-3-NEXT: 3 | void Test1::C::g()
+// CHECK-3-NEXT: 4 | void Test1::C::h()
+// CHECK-3-NEXT: 5 | vcall_offset (-16)
+// CHECK-3-NEXT: 6 | vcall_offset (-16)
+// CHECK-3-NEXT: 7 | vcall_offset (0)
+// CHECK-3-NEXT: 8 | offset_to_top (-16)
+// CHECK-3-NEXT: 9 | Test1::C RTTI
+// CHECK-3-NEXT: -- (Test1::A, 16) vtable address --
+// CHECK-3-NEXT: 10 | void Test1::A::f()
+// CHECK-3-NEXT: 11 | void Test1::C::g()
+// CHECK-3-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
+// CHECK-3-NEXT: 12 | void Test1::C::h()
+// CHECK-3-NEXT: [this adjustment: 0 non-virtual, -40 vcall offset offset]
struct C: public virtual A {
void g ();
void h ();
@@ -72,33 +83,33 @@ struct C: public virtual A {
};
void C::g() {}
-// CHECK: Vtable for 'Test1::D' (18 entries).
-// CHECK-NEXT: 0 | vbase_offset (32)
-// CHECK-NEXT: 1 | offset_to_top (0)
-// CHECK-NEXT: 2 | Test1::D RTTI
-// CHECK-NEXT: -- (Test1::B, 0) vtable address --
-// CHECK-NEXT: -- (Test1::D, 0) vtable address --
-// CHECK-NEXT: 3 | void Test1::B::f()
-// CHECK-NEXT: 4 | void Test1::D::h()
-// CHECK-NEXT: 5 | vbase_offset (16)
-// CHECK-NEXT: 6 | offset_to_top (-16)
-// CHECK-NEXT: 7 | Test1::D RTTI
-// CHECK-NEXT: -- (Test1::C, 16) vtable address --
-// CHECK-NEXT: 8 | void Test1::C::g()
-// CHECK-NEXT: 9 | void Test1::D::h()
-// CHECK-NEXT: [this adjustment: -16 non-virtual]
-// CHECK-NEXT: 10 | vcall_offset (-32)
-// CHECK-NEXT: 11 | vcall_offset (-16)
-// CHECK-NEXT: 12 | vcall_offset (-32)
-// CHECK-NEXT: 13 | offset_to_top (-32)
-// CHECK-NEXT: 14 | Test1::D RTTI
-// CHECK-NEXT: -- (Test1::A, 32) vtable address --
-// CHECK-NEXT: 15 | void Test1::B::f()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
-// CHECK-NEXT: 16 | void Test1::C::g()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
-// CHECK-NEXT: 17 | void Test1::D::h()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -40 vcall offset offset]
+// CHECK-4: Vtable for 'Test1::D' (18 entries).
+// CHECK-4-NEXT: 0 | vbase_offset (32)
+// CHECK-4-NEXT: 1 | offset_to_top (0)
+// CHECK-4-NEXT: 2 | Test1::D RTTI
+// CHECK-4-NEXT: -- (Test1::B, 0) vtable address --
+// CHECK-4-NEXT: -- (Test1::D, 0) vtable address --
+// CHECK-4-NEXT: 3 | void Test1::B::f()
+// CHECK-4-NEXT: 4 | void Test1::D::h()
+// CHECK-4-NEXT: 5 | vbase_offset (16)
+// CHECK-4-NEXT: 6 | offset_to_top (-16)
+// CHECK-4-NEXT: 7 | Test1::D RTTI
+// CHECK-4-NEXT: -- (Test1::C, 16) vtable address --
+// CHECK-4-NEXT: 8 | void Test1::C::g()
+// CHECK-4-NEXT: 9 | void Test1::D::h()
+// CHECK-4-NEXT: [this adjustment: -16 non-virtual]
+// CHECK-4-NEXT: 10 | vcall_offset (-32)
+// CHECK-4-NEXT: 11 | vcall_offset (-16)
+// CHECK-4-NEXT: 12 | vcall_offset (-32)
+// CHECK-4-NEXT: 13 | offset_to_top (-32)
+// CHECK-4-NEXT: 14 | Test1::D RTTI
+// CHECK-4-NEXT: -- (Test1::A, 32) vtable address --
+// CHECK-4-NEXT: 15 | void Test1::B::f()
+// CHECK-4-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-4-NEXT: 16 | void Test1::C::g()
+// CHECK-4-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
+// CHECK-4-NEXT: 17 | void Test1::D::h()
+// CHECK-4-NEXT: [this adjustment: 0 non-virtual, -40 vcall offset offset]
struct D: public B, public C {
void h ();
int id;
@@ -110,43 +121,43 @@ struct X {
virtual void x();
};
-// CHECK: Vtable for 'Test1::E' (24 entries).
-// CHECK-NEXT: 0 | vbase_offset (56)
-// CHECK-NEXT: 1 | offset_to_top (0)
-// CHECK-NEXT: 2 | Test1::E RTTI
-// CHECK-NEXT: -- (Test1::E, 0) vtable address --
-// CHECK-NEXT: -- (Test1::X, 0) vtable address --
-// CHECK-NEXT: 3 | void Test1::X::x()
-// CHECK-NEXT: 4 | void Test1::E::f()
-// CHECK-NEXT: 5 | void Test1::E::h()
-// CHECK-NEXT: 6 | vbase_offset (40)
-// CHECK-NEXT: 7 | offset_to_top (-16)
-// CHECK-NEXT: 8 | Test1::E RTTI
-// CHECK-NEXT: -- (Test1::B, 16) vtable address --
-// CHECK-NEXT: -- (Test1::D, 16) vtable address --
-// CHECK-NEXT: 9 | void Test1::E::f()
-// CHECK-NEXT: [this adjustment: -16 non-virtual]
-// CHECK-NEXT: 10 | void Test1::E::h()
-// CHECK-NEXT: [this adjustment: -16 non-virtual]
-// CHECK-NEXT: 11 | vbase_offset (24)
-// CHECK-NEXT: 12 | offset_to_top (-32)
-// CHECK-NEXT: 13 | Test1::E RTTI
-// CHECK-NEXT: -- (Test1::C, 32) vtable address --
-// CHECK-NEXT: 14 | void Test1::C::g()
-// CHECK-NEXT: 15 | void Test1::E::h()
-// CHECK-NEXT: [this adjustment: -32 non-virtual]
-// CHECK-NEXT: 16 | vcall_offset (-56)
-// CHECK-NEXT: 17 | vcall_offset (-24)
-// CHECK-NEXT: 18 | vcall_offset (-56)
-// CHECK-NEXT: 19 | offset_to_top (-56)
-// CHECK-NEXT: 20 | Test1::E RTTI
-// CHECK-NEXT: -- (Test1::A, 56) vtable address --
-// CHECK-NEXT: 21 | void Test1::E::f()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
-// CHECK-NEXT: 22 | void Test1::C::g()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
-// CHECK-NEXT: 23 | void Test1::E::h()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -40 vcall offset offset]
+// CHECK-5: Vtable for 'Test1::E' (24 entries).
+// CHECK-5-NEXT: 0 | vbase_offset (56)
+// CHECK-5-NEXT: 1 | offset_to_top (0)
+// CHECK-5-NEXT: 2 | Test1::E RTTI
+// CHECK-5-NEXT: -- (Test1::E, 0) vtable address --
+// CHECK-5-NEXT: -- (Test1::X, 0) vtable address --
+// CHECK-5-NEXT: 3 | void Test1::X::x()
+// CHECK-5-NEXT: 4 | void Test1::E::f()
+// CHECK-5-NEXT: 5 | void Test1::E::h()
+// CHECK-5-NEXT: 6 | vbase_offset (40)
+// CHECK-5-NEXT: 7 | offset_to_top (-16)
+// CHECK-5-NEXT: 8 | Test1::E RTTI
+// CHECK-5-NEXT: -- (Test1::B, 16) vtable address --
+// CHECK-5-NEXT: -- (Test1::D, 16) vtable address --
+// CHECK-5-NEXT: 9 | void Test1::E::f()
+// CHECK-5-NEXT: [this adjustment: -16 non-virtual]
+// CHECK-5-NEXT: 10 | void Test1::E::h()
+// CHECK-5-NEXT: [this adjustment: -16 non-virtual]
+// CHECK-5-NEXT: 11 | vbase_offset (24)
+// CHECK-5-NEXT: 12 | offset_to_top (-32)
+// CHECK-5-NEXT: 13 | Test1::E RTTI
+// CHECK-5-NEXT: -- (Test1::C, 32) vtable address --
+// CHECK-5-NEXT: 14 | void Test1::C::g()
+// CHECK-5-NEXT: 15 | void Test1::E::h()
+// CHECK-5-NEXT: [this adjustment: -32 non-virtual]
+// CHECK-5-NEXT: 16 | vcall_offset (-56)
+// CHECK-5-NEXT: 17 | vcall_offset (-24)
+// CHECK-5-NEXT: 18 | vcall_offset (-56)
+// CHECK-5-NEXT: 19 | offset_to_top (-56)
+// CHECK-5-NEXT: 20 | Test1::E RTTI
+// CHECK-5-NEXT: -- (Test1::A, 56) vtable address --
+// CHECK-5-NEXT: 21 | void Test1::E::f()
+// CHECK-5-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-5-NEXT: 22 | void Test1::C::g()
+// CHECK-5-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
+// CHECK-5-NEXT: 23 | void Test1::E::h()
+// CHECK-5-NEXT: [this adjustment: 0 non-virtual, -40 vcall offset offset]
struct E : X, D {
int ie;
void f();
@@ -164,22 +175,22 @@ struct A { virtual void f(); };
struct B : virtual public A { int i; };
struct C : virtual public A { int j; };
-// CHECK: Vtable for 'Test2::D' (11 entries).
-// CHECK-NEXT: 0 | vbase_offset (0)
-// CHECK-NEXT: 1 | vcall_offset (0)
-// CHECK-NEXT: 2 | offset_to_top (0)
-// CHECK-NEXT: 3 | Test2::D RTTI
-// CHECK-NEXT: -- (Test2::A, 0) vtable address --
-// CHECK-NEXT: -- (Test2::B, 0) vtable address --
-// CHECK-NEXT: -- (Test2::D, 0) vtable address --
-// CHECK-NEXT: 4 | void Test2::A::f()
-// CHECK-NEXT: 5 | void Test2::D::d()
-// CHECK-NEXT: 6 | vbase_offset (-16)
-// CHECK-NEXT: 7 | vcall_offset (-16)
-// CHECK-NEXT: 8 | offset_to_top (-16)
-// CHECK-NEXT: 9 | Test2::D RTTI
-// CHECK-NEXT: -- (Test2::C, 16) vtable address --
-// CHECK-NEXT: 10 | [unused] void Test2::A::f()
+// CHECK-6: Vtable for 'Test2::D' (11 entries).
+// CHECK-6-NEXT: 0 | vbase_offset (0)
+// CHECK-6-NEXT: 1 | vcall_offset (0)
+// CHECK-6-NEXT: 2 | offset_to_top (0)
+// CHECK-6-NEXT: 3 | Test2::D RTTI
+// CHECK-6-NEXT: -- (Test2::A, 0) vtable address --
+// CHECK-6-NEXT: -- (Test2::B, 0) vtable address --
+// CHECK-6-NEXT: -- (Test2::D, 0) vtable address --
+// CHECK-6-NEXT: 4 | void Test2::A::f()
+// CHECK-6-NEXT: 5 | void Test2::D::d()
+// CHECK-6-NEXT: 6 | vbase_offset (-16)
+// CHECK-6-NEXT: 7 | vcall_offset (-16)
+// CHECK-6-NEXT: 8 | offset_to_top (-16)
+// CHECK-6-NEXT: 9 | Test2::D RTTI
+// CHECK-6-NEXT: -- (Test2::C, 16) vtable address --
+// CHECK-6-NEXT: 10 | [unused] void Test2::A::f()
struct D : public B, public C {
virtual void d();
};
@@ -201,40 +212,40 @@ struct V2 : virtual V1 {
virtual void f();
};
-// CHECK: Vtable for 'Test3::C' (14 entries).
-// CHECK-NEXT: 0 | vbase_offset (32)
-// CHECK-NEXT: 1 | vbase_offset (16)
-// CHECK-NEXT: 2 | offset_to_top (0)
-// CHECK-NEXT: 3 | Test3::C RTTI
-// CHECK-NEXT: -- (Test3::C, 0) vtable address --
-// CHECK-NEXT: 4 | void Test3::C::f()
-// CHECK-NEXT: 5 | vcall_offset (-16)
-// CHECK-NEXT: 6 | offset_to_top (-16)
-// CHECK-NEXT: 7 | Test3::C RTTI
-// CHECK-NEXT: -- (Test3::V1, 16) vtable address --
-// CHECK-NEXT: 8 | void Test3::C::f()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
-// CHECK-NEXT: 9 | vcall_offset (-32)
-// CHECK-NEXT: 10 | vbase_offset (-16)
-// CHECK-NEXT: 11 | offset_to_top (-32)
-// CHECK-NEXT: 12 | Test3::C RTTI
-// CHECK-NEXT: -- (Test3::V2, 32) vtable address --
-// CHECK-NEXT: 13 | void Test3::C::f()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
+// CHECK-7: Vtable for 'Test3::C' (14 entries).
+// CHECK-7-NEXT: 0 | vbase_offset (32)
+// CHECK-7-NEXT: 1 | vbase_offset (16)
+// CHECK-7-NEXT: 2 | offset_to_top (0)
+// CHECK-7-NEXT: 3 | Test3::C RTTI
+// CHECK-7-NEXT: -- (Test3::C, 0) vtable address --
+// CHECK-7-NEXT: 4 | void Test3::C::f()
+// CHECK-7-NEXT: 5 | vcall_offset (-16)
+// CHECK-7-NEXT: 6 | offset_to_top (-16)
+// CHECK-7-NEXT: 7 | Test3::C RTTI
+// CHECK-7-NEXT: -- (Test3::V1, 16) vtable address --
+// CHECK-7-NEXT: 8 | void Test3::C::f()
+// CHECK-7-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-7-NEXT: 9 | vcall_offset (-32)
+// CHECK-7-NEXT: 10 | vbase_offset (-16)
+// CHECK-7-NEXT: 11 | offset_to_top (-32)
+// CHECK-7-NEXT: 12 | Test3::C RTTI
+// CHECK-7-NEXT: -- (Test3::V2, 32) vtable address --
+// CHECK-7-NEXT: 13 | void Test3::C::f()
+// CHECK-7-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
-// CHECK: Construction vtable for ('Test3::V2', 32) in 'Test3::C' (9 entries).
-// CHECK-NEXT: 0 | vcall_offset (0)
-// CHECK-NEXT: 1 | vbase_offset (-16)
-// CHECK-NEXT: 2 | offset_to_top (0)
-// CHECK-NEXT: 3 | Test3::V2 RTTI
-// CHECK-NEXT: -- (Test3::V2, 32) vtable address --
-// CHECK-NEXT: 4 | void Test3::V2::f()
-// CHECK-NEXT: 5 | vcall_offset (16)
-// CHECK-NEXT: 6 | offset_to_top (16)
-// CHECK-NEXT: 7 | Test3::V2 RTTI
-// CHECK-NEXT: -- (Test3::V1, 16) vtable address --
-// CHECK-NEXT: 8 | void Test3::V2::f()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-8: Construction vtable for ('Test3::V2', 32) in 'Test3::C' (9 entries).
+// CHECK-8-NEXT: 0 | vcall_offset (0)
+// CHECK-8-NEXT: 1 | vbase_offset (-16)
+// CHECK-8-NEXT: 2 | offset_to_top (0)
+// CHECK-8-NEXT: 3 | Test3::V2 RTTI
+// CHECK-8-NEXT: -- (Test3::V2, 32) vtable address --
+// CHECK-8-NEXT: 4 | void Test3::V2::f()
+// CHECK-8-NEXT: 5 | vcall_offset (16)
+// CHECK-8-NEXT: 6 | offset_to_top (16)
+// CHECK-8-NEXT: 7 | Test3::V2 RTTI
+// CHECK-8-NEXT: -- (Test3::V1, 16) vtable address --
+// CHECK-8-NEXT: 8 | void Test3::V2::f()
+// CHECK-8-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
struct C : virtual V1, virtual V2 {
int c;
virtual void f();
@@ -245,63 +256,63 @@ struct B {
int b;
};
-// CHECK: Vtable for 'Test3::D' (15 entries).
-// CHECK-NEXT: 0 | vbase_offset (40)
-// CHECK-NEXT: 1 | vbase_offset (24)
-// CHECK-NEXT: 2 | offset_to_top (0)
-// CHECK-NEXT: 3 | Test3::D RTTI
-// CHECK-NEXT: -- (Test3::C, 0) vtable address --
-// CHECK-NEXT: -- (Test3::D, 0) vtable address --
-// CHECK-NEXT: 4 | void Test3::C::f()
-// CHECK-NEXT: 5 | void Test3::D::g()
-// CHECK-NEXT: 6 | vcall_offset (-24)
-// CHECK-NEXT: 7 | offset_to_top (-24)
-// CHECK-NEXT: 8 | Test3::D RTTI
-// CHECK-NEXT: -- (Test3::V1, 24) vtable address --
-// CHECK-NEXT: 9 | void Test3::C::f()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
-// CHECK-NEXT: 10 | vcall_offset (-40)
-// CHECK-NEXT: 11 | vbase_offset (-16)
-// CHECK-NEXT: 12 | offset_to_top (-40)
-// CHECK-NEXT: 13 | Test3::D RTTI
-// CHECK-NEXT: -- (Test3::V2, 40) vtable address --
-// CHECK-NEXT: 14 | void Test3::C::f()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
+// CHECK-9: Vtable for 'Test3::D' (15 entries).
+// CHECK-9-NEXT: 0 | vbase_offset (40)
+// CHECK-9-NEXT: 1 | vbase_offset (24)
+// CHECK-9-NEXT: 2 | offset_to_top (0)
+// CHECK-9-NEXT: 3 | Test3::D RTTI
+// CHECK-9-NEXT: -- (Test3::C, 0) vtable address --
+// CHECK-9-NEXT: -- (Test3::D, 0) vtable address --
+// CHECK-9-NEXT: 4 | void Test3::C::f()
+// CHECK-9-NEXT: 5 | void Test3::D::g()
+// CHECK-9-NEXT: 6 | vcall_offset (-24)
+// CHECK-9-NEXT: 7 | offset_to_top (-24)
+// CHECK-9-NEXT: 8 | Test3::D RTTI
+// CHECK-9-NEXT: -- (Test3::V1, 24) vtable address --
+// CHECK-9-NEXT: 9 | void Test3::C::f()
+// CHECK-9-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-9-NEXT: 10 | vcall_offset (-40)
+// CHECK-9-NEXT: 11 | vbase_offset (-16)
+// CHECK-9-NEXT: 12 | offset_to_top (-40)
+// CHECK-9-NEXT: 13 | Test3::D RTTI
+// CHECK-9-NEXT: -- (Test3::V2, 40) vtable address --
+// CHECK-9-NEXT: 14 | void Test3::C::f()
+// CHECK-9-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
-// CHECK: Construction vtable for ('Test3::C', 0) in 'Test3::D' (14 entries).
-// CHECK-NEXT: 0 | vbase_offset (40)
-// CHECK-NEXT: 1 | vbase_offset (24)
-// CHECK-NEXT: 2 | offset_to_top (0)
-// CHECK-NEXT: 3 | Test3::C RTTI
-// CHECK-NEXT: -- (Test3::C, 0) vtable address --
-// CHECK-NEXT: 4 | void Test3::C::f()
-// CHECK-NEXT: 5 | vcall_offset (-24)
-// CHECK-NEXT: 6 | offset_to_top (-24)
-// CHECK-NEXT: 7 | Test3::C RTTI
-// CHECK-NEXT: -- (Test3::V1, 24) vtable address --
-// CHECK-NEXT: 8 | void Test3::C::f()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
-// CHECK-NEXT: 9 | vcall_offset (-40)
-// CHECK-NEXT: 10 | vbase_offset (-16)
-// CHECK-NEXT: 11 | offset_to_top (-40)
-// CHECK-NEXT: 12 | Test3::C RTTI
-// CHECK-NEXT: -- (Test3::V2, 40) vtable address --
-// CHECK-NEXT: 13 | void Test3::C::f()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
+// CHECK-10: Construction vtable for ('Test3::C', 0) in 'Test3::D' (14 entries).
+// CHECK-10-NEXT: 0 | vbase_offset (40)
+// CHECK-10-NEXT: 1 | vbase_offset (24)
+// CHECK-10-NEXT: 2 | offset_to_top (0)
+// CHECK-10-NEXT: 3 | Test3::C RTTI
+// CHECK-10-NEXT: -- (Test3::C, 0) vtable address --
+// CHECK-10-NEXT: 4 | void Test3::C::f()
+// CHECK-10-NEXT: 5 | vcall_offset (-24)
+// CHECK-10-NEXT: 6 | offset_to_top (-24)
+// CHECK-10-NEXT: 7 | Test3::C RTTI
+// CHECK-10-NEXT: -- (Test3::V1, 24) vtable address --
+// CHECK-10-NEXT: 8 | void Test3::C::f()
+// CHECK-10-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-10-NEXT: 9 | vcall_offset (-40)
+// CHECK-10-NEXT: 10 | vbase_offset (-16)
+// CHECK-10-NEXT: 11 | offset_to_top (-40)
+// CHECK-10-NEXT: 12 | Test3::C RTTI
+// CHECK-10-NEXT: -- (Test3::V2, 40) vtable address --
+// CHECK-10-NEXT: 13 | void Test3::C::f()
+// CHECK-10-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
-// CHECK: Construction vtable for ('Test3::V2', 40) in 'Test3::D' (9 entries).
-// CHECK-NEXT: 0 | vcall_offset (0)
-// CHECK-NEXT: 1 | vbase_offset (-16)
-// CHECK-NEXT: 2 | offset_to_top (0)
-// CHECK-NEXT: 3 | Test3::V2 RTTI
-// CHECK-NEXT: -- (Test3::V2, 40) vtable address --
-// CHECK-NEXT: 4 | void Test3::V2::f()
-// CHECK-NEXT: 5 | vcall_offset (16)
-// CHECK-NEXT: 6 | offset_to_top (16)
-// CHECK-NEXT: 7 | Test3::V2 RTTI
-// CHECK-NEXT: -- (Test3::V1, 24) vtable address --
-// CHECK-NEXT: 8 | void Test3::V2::f()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-11: Construction vtable for ('Test3::V2', 40) in 'Test3::D' (9 entries).
+// CHECK-11-NEXT: 0 | vcall_offset (0)
+// CHECK-11-NEXT: 1 | vbase_offset (-16)
+// CHECK-11-NEXT: 2 | offset_to_top (0)
+// CHECK-11-NEXT: 3 | Test3::V2 RTTI
+// CHECK-11-NEXT: -- (Test3::V2, 40) vtable address --
+// CHECK-11-NEXT: 4 | void Test3::V2::f()
+// CHECK-11-NEXT: 5 | vcall_offset (16)
+// CHECK-11-NEXT: 6 | offset_to_top (16)
+// CHECK-11-NEXT: 7 | Test3::V2 RTTI
+// CHECK-11-NEXT: -- (Test3::V1, 24) vtable address --
+// CHECK-11-NEXT: 8 | void Test3::V2::f()
+// CHECK-11-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
struct D : B, C {
int d;
virtual void g();
diff --git a/test/CodeGenCXX/weak-external.cpp b/test/CodeGenCXX/weak-external.cpp
new file mode 100644
index 000000000000..dad54f6861b0
--- /dev/null
+++ b/test/CodeGenCXX/weak-external.cpp
@@ -0,0 +1,66 @@
+// RUN: %clang -fexceptions %s -S -emit-llvm -o - | FileCheck %s
+// PR4262
+
+// CHECK-NOT: _ZNSs12_S_constructIPKcEEPcT_S3_RKSaIcESt20forward_iterator_tag
+
+// The "basic_string" extern template instantiation declaration is supposed to
+// suppress the implicit instantiation of non-inline member functions. Make sure
+// that we suppress the implicit instantiation of non-inline member functions
+// defined out-of-line. That we aren't instantiating the basic_string
+// constructor when we shouldn't be. Such an instantiation forces the implicit
+// instantiation of _S_construct<const char*>. Since _S_construct is a member
+// template, it's instantiation is *not* suppressed (despite being in
+// basic_string<char>), so we would emit it as a weak definition.
+
+#define _LIBCPP_EXCEPTION_ABI __attribute__ ((__visibility__("default")))
+#define _LIBCPP_INLINE_VISIBILITY __attribute__ ((__visibility__("hidden"), __always_inline__))
+#define _LIBCPP_VISIBLE __attribute__ ((__visibility__("default")))
+#if (__has_feature(cxx_noexcept))
+# define _NOEXCEPT noexcept
+# define _NOEXCEPT_(x) noexcept(x)
+#else
+# define _NOEXCEPT throw()
+# define _NOEXCEPT_(x)
+#endif
+
+namespace std // purposefully not using versioning namespace
+{
+
+template<class charT> struct char_traits;
+template<class T> class allocator;
+template <class _CharT,
+ class _Traits = char_traits<_CharT>,
+ class _Allocator = allocator<_CharT> >
+ class _LIBCPP_VISIBLE basic_string;
+typedef basic_string<char, char_traits<char>, allocator<char> > string;
+
+class _LIBCPP_EXCEPTION_ABI exception
+{
+public:
+ _LIBCPP_INLINE_VISIBILITY exception() _NOEXCEPT {}
+ virtual ~exception() _NOEXCEPT;
+ virtual const char* what() const _NOEXCEPT;
+};
+
+class _LIBCPP_EXCEPTION_ABI runtime_error
+ : public exception
+{
+private:
+ void* __imp_;
+public:
+ explicit runtime_error(const string&);
+ explicit runtime_error(const char*);
+
+ runtime_error(const runtime_error&) _NOEXCEPT;
+ runtime_error& operator=(const runtime_error&) _NOEXCEPT;
+
+ virtual ~runtime_error() _NOEXCEPT;
+
+ virtual const char* what() const _NOEXCEPT;
+};
+
+}
+
+void dummysymbol() {
+ throw(std::runtime_error("string"));
+}
diff --git a/test/CodeGenCXX/x86-64-abi-sret-vs-2word-struct-param.cpp b/test/CodeGenCXX/x86-64-abi-sret-vs-2word-struct-param.cpp
new file mode 100644
index 000000000000..1aa80f2d6e6f
--- /dev/null
+++ b/test/CodeGenCXX/x86-64-abi-sret-vs-2word-struct-param.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+// XTARGET: x86
+// PR4242
+// (PR 4242 bug is on 64-bit only, test passes on x86-32 as well)
+
+struct S {
+ void* data[3];
+};
+
+struct T {
+ void* data[2];
+};
+
+// CHECK: %struct.T* byval
+extern "C" S fail(int, int, int, int, T t, void* p) {
+ S s;
+ s.data[0] = t.data[0];
+ s.data[1] = t.data[1];
+ s.data[2] = p;
+ return s;
+}
+
+// CHECK: %struct.T* byval
+extern "C" S* succeed(S* sret, int, int, int, int, T t, void* p) {
+ sret->data[0] = t.data[0];
+ sret->data[1] = t.data[1];
+ sret->data[2] = p;
+ return sret;
+}
diff --git a/test/CodeGenCXX/x86_32-arguments.cpp b/test/CodeGenCXX/x86_32-arguments.cpp
index 4d4339381dbe..1cbeb71b2285 100644
--- a/test/CodeGenCXX/x86_32-arguments.cpp
+++ b/test/CodeGenCXX/x86_32-arguments.cpp
@@ -6,7 +6,7 @@ struct S {
short s;
};
-// CHECK: define void @_Z1fv(%struct.S* sret %
+// CHECK: define void @_Z1fv(%struct.S* noalias sret %
S f() { return S(); }
// CHECK: define void @_Z1f1S(%struct.S*)
void f(S) { }
@@ -18,7 +18,7 @@ public:
double c;
};
-// CHECK: define void @_Z1gv(%class.C* sret %
+// CHECK: define void @_Z1gv(%class.C* noalias sret %
C g() { return C(); }
// CHECK: define void @_Z1f1C(%class.C*)
@@ -103,13 +103,13 @@ struct s7_1 { double x; };
struct s7 : s7_0, s7_1 { };
s7 f7() { return s7(); }
-// CHECK: define void @_Z2f8v(%struct.s8* sret %agg.result)
+// CHECK: define void @_Z2f8v(%struct.s8* noalias sret %agg.result)
struct s8_0 { };
struct s8_1 { double x; };
struct s8 { s8_0 a; s8_1 b; };
s8 f8() { return s8(); }
-// CHECK: define void @_Z2f9v(%struct.s9* sret %agg.result)
+// CHECK: define void @_Z2f9v(%struct.s9* noalias sret %agg.result)
struct s9_0 { unsigned : 0; };
struct s9_1 { double x; };
struct s9 { s9_0 a; s9_1 b; };
diff --git a/test/CodeGenObjC/2007-04-03-ObjcEH.m b/test/CodeGenObjC/2007-04-03-ObjcEH.m
new file mode 100644
index 000000000000..f86ff49bbbd5
--- /dev/null
+++ b/test/CodeGenObjC/2007-04-03-ObjcEH.m
@@ -0,0 +1,27 @@
+// RUN: %clang -fexceptions -S -emit-llvm %s -o -
+
+@interface B
+-(int)bar;
+@end
+
+@interface A
+-(void) Foo:(int) state;
+@end
+
+@implementation A
+- (void) Foo:(int) state {
+
+ int wasResponded = 0;
+ @try {
+ if (state) {
+ B * b = 0;
+ @try { }
+ @finally {
+ wasResponded = ![b bar];
+ }
+ }
+ }
+ @finally {
+ }
+}
+@end
diff --git a/test/CodeGenObjC/2007-05-02-Strong.m b/test/CodeGenObjC/2007-05-02-Strong.m
new file mode 100644
index 000000000000..31553df6130a
--- /dev/null
+++ b/test/CodeGenObjC/2007-05-02-Strong.m
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -S %s -fobjc-gc -o /dev/null
+typedef int NSInteger;
+typedef struct _NSRect {
+ int origin;
+ int size;
+} NSRect;
+
+__attribute__((objc_gc(strong))) NSRect *_cachedRectArray;
+extern const NSRect NSZeroRect;
+@interface A{
+}
+-(void)bar:(NSInteger *)rectCount;
+@end
+
+@implementation A
+
+-(void)bar:(NSInteger *)rectCount {
+ NSRect appendRect = NSZeroRect;
+
+ _cachedRectArray[*rectCount - 1] = NSZeroRect;
+}
+
+@end
diff --git a/test/CodeGenObjC/2007-10-18-ProDescriptor.m b/test/CodeGenObjC/2007-10-18-ProDescriptor.m
new file mode 100644
index 000000000000..35a0df3a1a9f
--- /dev/null
+++ b/test/CodeGenObjC/2007-10-18-ProDescriptor.m
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+@protocol O
+@end
+@interface O < O > {
+}
+@end
+struct A {
+};
+@protocol AB
+- (unsigned) ver;
+@end
+@interface AGy:O < AB > {
+}
+@end
+@implementation AGy
+- (unsigned) ver {
+}
+@end
diff --git a/test/CodeGenObjC/2007-10-23-GC-WriteBarrier.m b/test/CodeGenObjC/2007-10-23-GC-WriteBarrier.m
new file mode 100644
index 000000000000..af8508b6463a
--- /dev/null
+++ b/test/CodeGenObjC/2007-10-23-GC-WriteBarrier.m
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null -fobjc-gc
+// rdar://5541393
+
+typedef unsigned int NSUInteger;
+__attribute__((objc_gc(strong))) float *_scores;
+
+void foo(int i, float f) {
+ _scores[i] = f;
+}
diff --git a/test/CodeGenObjC/2008-10-3-EhValue.m b/test/CodeGenObjC/2008-10-3-EhValue.m
new file mode 100644
index 000000000000..0ed0d8993977
--- /dev/null
+++ b/test/CodeGenObjC/2008-10-3-EhValue.m
@@ -0,0 +1,50 @@
+// RUN: %clang -fexceptions -S -emit-llvm %s -o /dev/null
+
+@interface Object {
+@public
+ Class isa;
+}
++initialize;
++alloc;
++new;
++free;
+-free;
++(Class)class;
+-(Class)class;
+-init;
+-superclass;
+-(const char *)name;
+@end
+
+@interface Frob: Object
+@end
+
+@implementation Frob: Object
+@end
+
+static Frob* _connection = ((void *)0);
+
+extern void abort(void);
+
+void test (Object* sendPort)
+{
+ int cleanupPorts = 1;
+ Frob* receivePort = ((void *)0);
+
+ @try {
+ receivePort = (Frob *) -1;
+ _connection = (Frob *) -1;
+ receivePort = ((void *)0);
+ sendPort = ((void *)0);
+ cleanupPorts = 0;
+ @throw [Object new];
+ }
+ @catch(Frob *obj) {
+ if(!(0)) abort();
+ }
+ @catch(id exc) {
+ if(!(!receivePort)) abort();
+ if(!(!sendPort)) abort();
+ if(!(!cleanupPorts)) abort();
+ }
+}
diff --git a/test/CodeGenObjC/2008-11-12-Metadata.m b/test/CodeGenObjC/2008-11-12-Metadata.m
new file mode 100644
index 000000000000..afd7ce035aea
--- /dev/null
+++ b/test/CodeGenObjC/2008-11-12-Metadata.m
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin -fobjc-fragile-abi %s -o /dev/null
+
+@interface A
+@end
+@protocol P
+@end
+@interface B : A <P>
+{
+}
+@end
+@implementation B
+- (void)test {
+}
+@end
diff --git a/test/CodeGenObjC/2008-11-24-ConstCFStrings.m b/test/CodeGenObjC/2008-11-24-ConstCFStrings.m
new file mode 100644
index 000000000000..b37f66c29707
--- /dev/null
+++ b/test/CodeGenObjC/2008-11-24-ConstCFStrings.m
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin -fobjc-fragile-abi %s -o - | FileCheck %s
+
+// CHECK: _unnamed_cfstring_
+
+@class NSString;
+
+@interface A
+- (void)bork:(NSString*)msg;
+@end
+
+void func(A *a) {
+ [a bork:@"Hello world!"];
+}
diff --git a/test/CodeGenObjC/2008-11-25-Blocks.m b/test/CodeGenObjC/2008-11-25-Blocks.m
new file mode 100644
index 000000000000..39364d5de00a
--- /dev/null
+++ b/test/CodeGenObjC/2008-11-25-Blocks.m
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fblocks -emit-llvm %s -o /dev/null
+// rdar://6394879
+
+@interface bork
+- (id)B:(void (^)())blk;
+- (void)C;
+@end
+@implementation bork
+- (id)B:(void (^)())blk {
+ __attribute__((__blocks__(byref))) bork* new = ((void *)0);
+ blk();
+}
+- (void)C {
+ __attribute__((__blocks__(byref))) id var;
+ [self B:^() {}];
+}
+@end
diff --git a/test/CodeGenObjC/2009-01-26-WriteBarrier-2.m b/test/CodeGenObjC/2009-01-26-WriteBarrier-2.m
new file mode 100644
index 000000000000..d7219f185ba7
--- /dev/null
+++ b/test/CodeGenObjC/2009-01-26-WriteBarrier-2.m
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fblocks -emit-llvm %s -fobjc-gc -o - | FileCheck %s
+
+// CHECK: objc_assign_strongCast
+// rdar://5541393
+
+typedef __SIZE_TYPE__ size_t;
+void * malloc(size_t size);
+
+typedef struct {
+ void (^ivarBlock)(void);
+} StructWithBlock_t;
+
+int main(int argc, char *argv[]) {
+ StructWithBlock_t *swbp = (StructWithBlock_t *)malloc(sizeof(StructWithBlock_t*));
+ __block int i = 10;
+ // assigning a Block into an struct slot should elicit a write-barrier under GC
+ swbp->ivarBlock = ^ { ++i; };
+ return 0;
+}
diff --git a/test/CodeGenObjC/2009-02-05-VolatileProp.m b/test/CodeGenObjC/2009-02-05-VolatileProp.m
new file mode 100644
index 000000000000..1f696ac7c2d0
--- /dev/null
+++ b/test/CodeGenObjC/2009-02-05-VolatileProp.m
@@ -0,0 +1,10 @@
+// RUN: %clang -fexceptions -S -emit-llvm %s -o /dev/null -pedantic-errors
+// rdar://6551276
+
+void foo(const unsigned short *);
+void bar() {
+ unsigned short *s[3];
+ int i;
+ @try { } @catch (id anException) { }
+ foo(2+s[i]);
+}
diff --git a/test/CodeGenObjC/2009-08-05-utf16.m b/test/CodeGenObjC/2009-08-05-utf16.m
new file mode 100644
index 000000000000..38c9c82e7835
--- /dev/null
+++ b/test/CodeGenObjC/2009-08-05-utf16.m
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -emit-llvm -w -x objective-c %s -o - | FileCheck %s
+// rdar://7095855 rdar://7115749
+
+// CHECK: internal unnamed_addr constant [12 x i8]
+void *P = @"iPodâ„¢";
diff --git a/test/CodeGenObjC/2010-02-01-utf16-with-null.m b/test/CodeGenObjC/2010-02-01-utf16-with-null.m
new file mode 100644
index 000000000000..1863984c216e
--- /dev/null
+++ b/test/CodeGenObjC/2010-02-01-utf16-with-null.m
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+// rdar://7589850
+
+// CHECK-NOT: __ustring
+void *P = @"good\0bye";
diff --git a/test/CodeGenObjC/2010-02-23-DbgInheritance.m b/test/CodeGenObjC/2010-02-23-DbgInheritance.m
new file mode 100644
index 000000000000..7d31b30cce5f
--- /dev/null
+++ b/test/CodeGenObjC/2010-02-23-DbgInheritance.m
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm %s -g -o - | FileCheck %s
+// CHECK-NOT: DW_TAG_member
+// Interface P should not be a member of interface I in debug info.
+@interface P
+@end
+
+@interface I : P
+@end
+
+void fn(I *iptr) {}
diff --git a/test/CodeGenObjC/2010-03-17-StructRef.m b/test/CodeGenObjC/2010-03-17-StructRef.m
new file mode 100644
index 000000000000..fd0e6462ce2e
--- /dev/null
+++ b/test/CodeGenObjC/2010-03-17-StructRef.m
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 %s -emit-llvm -triple x86_64-apple-darwin -fobjc-fragile-abi -o - | FileCheck %s
+// Bitfield references must not touch memory outside of the enclosing
+// struct. Radar 7639995
+typedef signed char BOOL;
+@protocol NSObject
+- (id)init;
+@end
+@interface NSObject <NSObject> {}
+@end
+@interface IMAVChatParticipant : NSObject {
+ int _ardRole;
+ int _state;
+ int _avRelayStatus;
+ int _chatEndedReason;
+ int _chatError;
+ unsigned _sendingAudio:1;
+ unsigned _sendingVideo:1;
+ unsigned _sendingAuxVideo:1;
+ unsigned _audioMuted:1;
+ unsigned _videoPaused:1;
+ unsigned _networkStalled:1;
+ unsigned _isInitiator:1;
+ unsigned _isAOLInterop:1;
+ unsigned _isRecording:1;
+ unsigned _isUsingICE:1;
+}
+@end
+@implementation IMAVChatParticipant
+- (id) init {
+ self = [super init];
+ if ( self ) {
+ BOOL blah = (BOOL)1;
+ // We're expecting these three bitfield assignments will generate i8 stores.
+ _sendingAudio = (BOOL)1;
+ _isUsingICE = (BOOL)1;
+ _isUsingICE = blah;
+ // CHECK: store i8
+ // CHECK: store i8
+ // CHECK: store i8
+ }
+ return self;
+}
+@end
diff --git a/test/CodeGenObjC/2011-03-08-IVarLookup.m b/test/CodeGenObjC/2011-03-08-IVarLookup.m
new file mode 100644
index 000000000000..a24b98c3ac6c
--- /dev/null
+++ b/test/CodeGenObjC/2011-03-08-IVarLookup.m
@@ -0,0 +1,30 @@
+// RUN: %clang -S -emit-llvm -m64 -fobjc-abi-version=2 %s -o /dev/null
+
+typedef unsigned int UInt_t;
+
+@interface A
+{
+@protected
+ UInt_t _f1;
+}
+@end
+
+@interface B : A { }
+@end
+
+@interface A ()
+@property (assign) UInt_t f1;
+@end
+
+@interface B ()
+@property (assign) int x;
+@end
+
+@implementation B
+@synthesize x;
+- (id) init
+{
+ _f1 = 0;
+ return self;
+}
+@end
diff --git a/test/CodeGenObjC/arc-arm.m b/test/CodeGenObjC/arc-arm.m
index a3d55c28f400..23da3be2a5dd 100644
--- a/test/CodeGenObjC/arc-arm.m
+++ b/test/CodeGenObjC/arc-arm.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple armv7-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple armv7-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -o - %s | FileCheck %s
id test0(void) {
extern id test0_helper(void);
diff --git a/test/CodeGenObjC/arc-block-copy-escape.m b/test/CodeGenObjC/arc-block-copy-escape.m
new file mode 100644
index 000000000000..15c0d1d0f496
--- /dev/null
+++ b/test/CodeGenObjC/arc-block-copy-escape.m
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fobjc-arc -fblocks -emit-llvm %s -o - | FileCheck %s
+
+typedef void (^block_t)(void);
+void use_block(block_t);
+void use_int(int);
+
+// rdar://problem/10211676
+
+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: ret void
+}
+
+void test1(int i) {
+ id block = ^{ use_int(i); };
+ // CHECK: define void @test1(
+ // CHECK: call i8* @objc_retainBlock(i8* {{%.*}}) nounwind
+ // CHECK-NOT: !clang.arc.copy_on_escape
+ // CHECK: ret void
+}
diff --git a/test/CodeGenObjC/arc-block-ivar-layout.m b/test/CodeGenObjC/arc-block-ivar-layout.m
index 50c35bacda06..6c82f2969823 100644
--- a/test/CodeGenObjC/arc-block-ivar-layout.m
+++ b/test/CodeGenObjC/arc-block-ivar-layout.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-nonfragile-abi -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -emit-llvm %s -o %t-64.s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -emit-llvm %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// rdar://8991729
diff --git a/test/CodeGenObjC/arc-bridged-cast.m b/test/CodeGenObjC/arc-bridged-cast.m
index 3354bda5bf00..eb9045d3d840 100644
--- a/test/CodeGenObjC/arc-bridged-cast.m
+++ b/test/CodeGenObjC/arc-bridged-cast.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
typedef const void *CFTypeRef;
typedef const struct __CFString *CFStringRef;
diff --git a/test/CodeGenObjC/arc-compound-stmt.m b/test/CodeGenObjC/arc-compound-stmt.m
index 946d72f00591..573ee449aaae 100644
--- a/test/CodeGenObjC/arc-compound-stmt.m
+++ b/test/CodeGenObjC/arc-compound-stmt.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fobjc-arc -o - %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -o - %s
// rdar://9694706
typedef unsigned long NSUInteger;
diff --git a/test/CodeGenObjC/arc-foreach.m b/test/CodeGenObjC/arc-foreach.m
index f9d7782fbedd..9449b3d2d602 100644
--- a/test/CodeGenObjC/arc-foreach.m
+++ b/test/CodeGenObjC/arc-foreach.m
@@ -1,11 +1,17 @@
-// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-nonfragile-abi -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -emit-llvm %s -o %t-64.s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -emit-llvm %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// rdar://9503326
// rdar://9606600
extern void use(id);
extern void use_block(void (^)(void));
-@class NSArray;
+
+struct NSFastEnumerationState;
+@interface NSArray
+- (unsigned long) countByEnumeratingWithState: (struct NSFastEnumerationState*) state
+ objects: (id*) buffer
+ count: (unsigned long) bufferSize;
+@end;
void test0(NSArray *array) {
// 'x' should be initialized without a retain.
@@ -17,12 +23,37 @@ void test0(NSArray *array) {
}
// CHECK-LP64: define void @test0(
-// CHECK-LP64: alloca [[ARRAY_T:%.*]]*,
+// CHECK-LP64: [[ARRAY:%.*]] = alloca [[ARRAY_T:%.*]]*,
// CHECK-LP64-NEXT: [[X:%.*]] = alloca i8*,
// CHECK-LP64-NEXT: [[STATE:%.*]] = alloca [[STATE_T:%.*]],
-// CHECK-LP64-NEXT: alloca [16 x i8*], align 8
+// CHECK-LP64-NEXT: [[BUFFER:%.*]] = alloca [16 x i8*], align 8
// 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
+
+// Initialize the fast enumaration state.
+// CHECK-LP64-NEXT: [[T0:%.*]] = bitcast [[STATE_T]]* [[STATE]] to i8*
+// CHECK-LP64-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 64, i32 8, i1 false)
+
+// Evaluate the collection expression and retain.
+// CHECK-LP64-NEXT: [[T0:%.*]] = load [[ARRAY_T]]** [[ARRAY]], align 8
+// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[T0]] to i8*
+// CHECK-LP64-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
+// CHECK-LP64-NEXT: [[SAVED_ARRAY:%.*]] = bitcast i8* [[T2]] to [[ARRAY_T]]*
+
+// Call the enumeration method.
+// CHECK-LP64-NEXT: [[T0:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[SAVED_ARRAY]] to i8*
+// CHECK-LP64-NEXT: [[SIZE:%.*]] = call i64 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i64 (i8*, i8*, [[STATE_T]]*, [16 x i8*]*, i64)*)(i8* [[T1]], i8* [[T0]], [[STATE_T]]* [[STATE]], [16 x i8*]* [[BUFFER]], i64 16)
+
+// Check for a nonzero result.
+// CHECK-LP64-NEXT: [[T0:%.*]] = icmp eq i64 [[SIZE]], 0
+// CHECK-LP64-NEXT: br i1 [[T0]]
+
// CHECK-LP64: [[T0:%.*]] = getelementptr inbounds [[STATE_T]]* [[STATE]], i32 0, i32 1
// CHECK-LP64-NEXT: [[T1:%.*]] = load i8*** [[T0]]
// CHECK-LP64-NEXT: [[T2:%.*]] = getelementptr i8** [[T1]], i64
@@ -38,6 +69,20 @@ void test0(NSArray *array) {
// CHECK-LP64-NEXT: [[T1:%.*]] = load i8** [[T0]]
// CHECK-LP64-NEXT: call void @objc_release(i8* [[T1]])
+// CHECK-LP64: [[T0:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[SAVED_ARRAY]] to i8*
+// CHECK-LP64-NEXT: [[SIZE:%.*]] = call i64 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i64 (i8*, i8*, [[STATE_T]]*, [16 x i8*]*, i64)*)(i8* [[T1]], i8* [[T0]], [[STATE_T]]* [[STATE]], [16 x i8*]* [[BUFFER]], i64 16)
+
+// Release the array.
+// CHECK-LP64: [[T0:%.*]] = bitcast [[ARRAY_T]]* [[SAVED_ARRAY]] to i8*
+// CHECK-LP64-NEXT: call void @objc_release(i8* [[T0]])
+
+// Destroy 'array'.
+// CHECK-LP64: [[T0:%.*]] = load [[ARRAY_T]]** [[ARRAY]]
+// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[T0]] to i8*
+// CHECK-LP64-NEXT: call void @objc_release(i8* [[T1]])
+// CHECK-LP64-NEXT: ret void
+
// 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
@@ -70,3 +115,57 @@ void test1(NSArray *array) {
// CHECK-LP64: call void @use_block
// CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[T0]])
// CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[X]])
+
+// rdar://problem/9817306
+@interface Test2
+- (NSArray *) array;
+@end
+void test2(Test2 *a) {
+ for (id x in a.array) {
+ use(x);
+ }
+}
+
+// CHECK-LP64: define void @test2(
+// CHECK-LP64: [[T0:%.*]] = call [[ARRAY_T]]* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to [[ARRAY_T]]* (i8*, i8*)*)(
+// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[T0]] to i8*
+// CHECK-LP64-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-LP64-NEXT: [[COLL:%.*]] = bitcast i8* [[T2]] to [[ARRAY_T]]*
+
+// Make sure it's not immediately released before starting the iteration.
+// CHECK-LP64-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+// CHECK-LP64-NEXT: [[T0:%.*]] = bitcast [[ARRAY_T]]* [[COLL]] to i8*
+// CHECK-LP64-NEXT: @objc_msgSend
+
+// This bitcast is for the mutation check.
+// CHECK-LP64: [[T0:%.*]] = bitcast [[ARRAY_T]]* [[COLL]] to i8*
+// CHECK-LP64-NEXT: @objc_enumerationMutation
+
+// This bitcast is for the 'next' message send.
+// CHECK-LP64: [[T0:%.*]] = bitcast [[ARRAY_T]]* [[COLL]] to i8*
+// CHECK-LP64-NEXT: @objc_msgSend
+
+// This bitcast is for the final release.
+// CHECK-LP64: [[T0:%.*]] = bitcast [[ARRAY_T]]* [[COLL]] to i8*
+// CHECK-LP64-NEXT: call void @objc_release(i8* [[T0]])
+
+
+// Check that the 'continue' label is positioned appropriately
+// relative to the collection clenaup.
+void test3(NSArray *array) {
+ for (id x in array) {
+ if (!x) continue;
+ use(x);
+ }
+
+ // CHECK-LP64: define void @test3(
+ // CHECK-LP64: [[ARRAY:%.*]] = alloca [[ARRAY_T]]*, align 8
+ // CHECK-LP64-NEXT: [[X:%.*]] = alloca i8*, align 8
+ // CHECK-LP64: [[T0:%.*]] = load i8** [[X]], align 8
+ // CHECK-LP64-NEXT: [[T1:%.*]] = icmp ne i8* [[T0]], null
+ // CHECK-LP64-NEXT: br i1 [[T1]],
+ // CHECK-LP64: br label [[L:%[^ ]+]]
+ // CHECK-LP64: [[T0:%.*]] = load i8** [[X]], align 8
+ // CHECK-LP64-NEXT: call void @use(i8* [[T0]])
+ // CHECK-LP64-NEXT: br label [[L]]
+}
diff --git a/test/CodeGenObjC/arc-ivar-layout.m b/test/CodeGenObjC/arc-ivar-layout.m
index cb930fe3d365..30c90fac9e40 100644
--- a/test/CodeGenObjC/arc-ivar-layout.m
+++ b/test/CodeGenObjC/arc-ivar-layout.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-arc -fobjc-nonfragile-abi -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -S %s -o %t-64.s
+// RUN: %clang_cc1 -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// rdar://8991729
diff --git a/test/CodeGenObjC/arc-no-runtime.m b/test/CodeGenObjC/arc-no-runtime.m
index 39f7da3460e5..3c85e8783cb8 100644
--- a/test/CodeGenObjC/arc-no-runtime.m
+++ b/test/CodeGenObjC/arc-no-runtime.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-arc -fobjc-nonfragile-abi -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-arc -emit-llvm %s -o - | FileCheck %s
// rdar://problem/9224855
void test0() {
diff --git a/test/CodeGenObjC/arc-related-result-type.m b/test/CodeGenObjC/arc-related-result-type.m
index c51757df5d8d..f73aa5049f5c 100644
--- a/test/CodeGenObjC/arc-related-result-type.m
+++ b/test/CodeGenObjC/arc-related-result-type.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -o - %s | FileCheck %s
@interface Test0
- (id) self;
diff --git a/test/CodeGenObjC/arc-unbridged-cast.m b/test/CodeGenObjC/arc-unbridged-cast.m
index 0f3db09f1ffd..5ab5d02fffee 100644
--- a/test/CodeGenObjC/arc-unbridged-cast.m
+++ b/test/CodeGenObjC/arc-unbridged-cast.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -emit-llvm -fobjc-nonfragile-abi -fobjc-arc -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -emit-llvm -fobjc-arc -o - %s | FileCheck %s
// rdar://9744349
typedef const struct __CFString * CFStringRef;
@@ -29,8 +29,6 @@ CFStringRef SomeOtherFunc() __attribute__((cf_returns_retained));
id MMM()
{
id obj = (id)((CFStringRef) __builtin___CFStringMakeConstantString ("" "Some CF String" ""));
- if (obj)
- return (id) SomeOtherFunc();
return 0;
}
diff --git a/test/CodeGenObjC/arc-unopt.m b/test/CodeGenObjC/arc-unopt.m
index ed46052af848..c319bf260f6b 100644
--- a/test/CodeGenObjC/arc-unopt.m
+++ b/test/CodeGenObjC/arc-unopt.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck %s
// A test to ensure that we generate fused calls at -O0.
diff --git a/test/CodeGenObjC/arc-weak-property.m b/test/CodeGenObjC/arc-weak-property.m
index c0796046446e..0a6b2a63bfc6 100644
--- a/test/CodeGenObjC/arc-weak-property.m
+++ b/test/CodeGenObjC/arc-weak-property.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck %s
// rdar://8899430
@interface WeakPropertyTest {
diff --git a/test/CodeGenObjC/arc-with-atthrow.m b/test/CodeGenObjC/arc-with-atthrow.m
new file mode 100644
index 000000000000..213b05bffded
--- /dev/null
+++ b/test/CodeGenObjC/arc-with-atthrow.m
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fobjc-exceptions -o - %s | FileCheck %s
+// pr10411
+// rdar://10042689
+
+id make(void);
+void test() {
+ @throw make();
+}
+
+// TODO: We should probably emit this specific pattern without the reclaim.
+
+// CHECK: define void @test()
+// CHECK: [[T0:%.*]] = call i8* @make()
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_autorelease(i8* [[T1]])
+// CHECK-NEXT: call void @objc_exception_throw(i8* [[T2]]) noreturn
+// CHECK-NEXT: unreachable
diff --git a/test/CodeGenObjC/arc.m b/test/CodeGenObjC/arc.m
index 407b3eb77167..e97e625b06eb 100644
--- a/test/CodeGenObjC/arc.m
+++ b/test/CodeGenObjC/arc.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -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 -fobjc-nonfragile-abi -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-GLOBALS %s
+// 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
// CHECK: define void @test0
void test0(id x) {
@@ -578,18 +578,18 @@ void test22(_Bool cond) {
// CHECK: define void @test22(
// CHECK: [[COND:%.*]] = alloca i8,
// CHECK-NEXT: [[X:%.*]] = alloca i8*,
- // CHECK-NEXT: [[RELCOND:%.*]] = alloca i1
// CHECK-NEXT: [[RELVAL:%.*]] = alloca i8*
- // CHECK-NEXT: store i1 false, i1* [[RELCOND]]
+ // 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 i1 true, i1* [[RELCOND]]
// 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
@@ -1552,3 +1552,387 @@ void test54(int first, ...) {
// CHECK: define internal void @"\01-[Test55(Category) dealloc]"(
// CHECK-NOT: ret
// CHECK: call void bitcast (i8* ({{%.*}}*, i8*, ...)* @objc_msgSendSuper2 to void ({{%.*}}*, i8*)*)(
+
+// rdar://problem/8024350
+@protocol Test56Protocol
++ (id) make __attribute__((ns_returns_retained));
+@end
+@interface Test56<Test56Protocol> @end
+@implementation Test56
+// CHECK: define internal i8* @"\01+[Test56 make]"(
++ (id) make {
+ extern id test56_helper(void);
+ // CHECK: [[T0:%.*]] = call i8* @test56_helper()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: ret i8* [[T1]]
+ return test56_helper();
+}
+@end
+void test56_test(void) {
+ id x = [Test56 make];
+ // CHECK: define void @test56_test()
+ // CHECK: [[X:%.*]] = alloca i8*, align 8
+ // CHECK: [[T0:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(
+ // CHECK-NEXT: store i8* [[T0]], i8** [[X]]
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+ // CHECK-NEXT: ret void
+}
+
+// rdar://problem/9784964
+@interface Test57
+@property (nonatomic, strong) id strong;
+@property (nonatomic, weak) id weak;
+@property (nonatomic, unsafe_unretained) id unsafe;
+@end
+@implementation Test57
+@synthesize strong, weak, unsafe;
+@end
+// CHECK: define internal i8* @"\01-[Test57 strong]"(
+// CHECK: [[T0:%.*]] = load [[TEST57:%.*]]** {{%.*}}
+// CHECK-NEXT: [[T1:%.*]] = load i64* @"OBJC_IVAR_$_Test57.strong"
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST57]]* [[T0]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8* [[T2]], i64 [[T1]]
+// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to i8**
+// CHECK-NEXT: [[T5:%.*]] = load i8** [[T4]]
+// CHECK-NEXT: ret i8* [[T5]]
+
+// CHECK: define internal i8* @"\01-[Test57 weak]"(
+// CHECK: [[T0:%.*]] = load [[TEST57]]** {{%.*}}
+// CHECK-NEXT: [[T1:%.*]] = load i64* @"OBJC_IVAR_$_Test57.weak"
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST57]]* [[T0]] to i8*
+// 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: ret i8* [[T6]]
+
+// CHECK: define internal i8* @"\01-[Test57 unsafe]"(
+// CHECK: [[T0:%.*]] = load [[TEST57]]** {{%.*}}
+// CHECK-NEXT: [[T1:%.*]] = load i64* @"OBJC_IVAR_$_Test57.unsafe"
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST57]]* [[T0]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8* [[T2]], i64 [[T1]]
+// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to i8**
+// 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);
+ extern void test59_body(void);
+ @synchronized (test59_getlock()) {
+ test59_body();
+ }
+
+ // CHECK: define void @test59()
+ // CHECK: [[T0:%.*]] = call i8* @test59_getlock()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: call void @objc_sync_enter(i8* [[T1]])
+ // CHECK-NEXT: call void @test59_body()
+ // CHECK-NEXT: call void @objc_sync_exit(i8* [[T1]])
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+ // CHECK-NEXT: ret void
+}
+
+// rdar://problem/9814099
+// Test that we correctly initialize __block variables
+// when the initialization captures the variable.
+void test60a(void) {
+ __block void (^block)(void) = ^{ block(); };
+ // CHECK: define void @test60a()
+ // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]],
+
+ // Zero-initialization before running the initializer.
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
+ // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8
+
+ // Run the initializer as an assignment.
+ // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8*
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainBlock(i8* [[T0]])
+ // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()*
+ // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 1
+ // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]** [[T3]]
+ // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T4]], i32 0, i32 6
+ // CHECK-NEXT: [[T6:%.*]] = load void ()** [[T5]], align 8
+ // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8
+ // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T7]])
+
+ // Destroy at end of function.
+ // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8*
+ // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
+ // 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
+}
+
+// Test that we correctly assign to __block variables when the
+// assignment captures the variable.
+void test60b(void) {
+ __block void (^block)(void);
+ block = ^{ block(); };
+
+ // CHECK: define void @test60b()
+ // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]],
+
+ // Zero-initialize.
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
+ // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8
+
+ // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
+
+ // The assignment.
+ // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8*
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainBlock(i8* [[T0]])
+ // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()*
+ // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 1
+ // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]** [[T3]]
+ // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T4]], i32 0, i32 6
+ // CHECK-NEXT: [[T6:%.*]] = load void ()** [[T5]], align 8
+ // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8
+ // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T7]])
+
+ // Destroy at end of function.
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8*
+ // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
+ // 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
+}
+
+// Verify that we don't try to reclaim the result of performSelector.
+// rdar://problem/9887545
+@interface Test61
+- (id) performSelector: (SEL) selector;
+- (void) test61_void;
+- (id) test61_id;
+@end
+void test61(void) {
+ // CHECK: define void @test61()
+ // CHECK: [[Y:%.*]] = alloca i8*, align 8
+
+ extern id test61_make(void);
+
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @test61_make()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: [[T2:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[T3:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[T4:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i8*)*)(i8* [[T1]], i8* [[T3]], i8* [[T2]])
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+ [test61_make() performSelector: @selector(test61_void)];
+
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @test61_make()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: [[T2:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[T3:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[T4:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i8*)*)(i8* [[T1]], i8* [[T3]], i8* [[T2]])
+ // CHECK-NEXT: [[T5:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T4]])
+ // CHECK-NEXT: store i8* [[T5]], i8** [[Y]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+ id y = [test61_make() performSelector: @selector(test61_id)];
+
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[Y]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+ // CHECK-NEXT: ret void
+}
+
+// rdar://problem/9891815
+void test62(void) {
+ // CHECK: define void @test62()
+ // CHECK: [[I:%.*]] = alloca i32, align 4
+ // CHECK-NEXT: [[CLEANUP_VALUE:%.*]] = alloca i8*
+ // CHECK-NEXT: [[CLEANUP_REQUIRED:%.*]] = alloca i1
+ extern id test62_make(void);
+ extern void test62_body(void);
+
+ // CHECK-NEXT: store i32 0, i32* [[I]], align 4
+ // CHECK-NEXT: br label
+
+ // CHECK: [[T0:%.*]] = load i32* [[I]], align 4
+ // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 20
+ // CHECK-NEXT: br i1 [[T1]],
+
+ for (unsigned i = 0; i != 20; ++i) {
+ // CHECK: [[T0:%.*]] = load i32* [[I]], align 4
+ // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0
+ // CHECK-NEXT: store i1 false, i1* [[CLEANUP_REQUIRED]]
+ // CHECK-NEXT: br i1 [[T1]],
+ // CHECK: [[T0:%.*]] = call i8* @test62_make()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: store i8* [[T1]], i8** [[CLEANUP_VALUE]]
+ // CHECK-NEXT: store i1 true, i1* [[CLEANUP_REQUIRED]]
+ // CHECK-NEXT: [[T2:%.*]] = icmp ne i8* [[T1]], null
+ // CHECK-NEXT: br label
+ // CHECK: [[COND:%.*]] = phi i1 [ false, {{%.*}} ], [ [[T2]], {{%.*}} ]
+ // CHECK-NEXT: [[T0:%.*]] = load i1* [[CLEANUP_REQUIRED]]
+ // CHECK-NEXT: br i1 [[T0]],
+ // CHECK: [[T0:%.*]] = load i8** [[CLEANUP_VALUE]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+ // CHECK-NEXT: br label
+ // CHECK: br i1 [[COND]]
+ // CHECK: call void @test62_body()
+ // CHECK-NEXT: br label
+ // CHECK: br label
+ if (i != 0 && test62_make() != 0)
+ test62_body();
+ }
+
+ // CHECK: [[T0:%.*]] = load i32* [[I]], align 4
+ // CHECK-NEXT: [[T1:%.*]] = add i32 [[T0]], 1
+ // CHECK-NEXT: store i32 [[T1]], i32* [[I]]
+ // CHECK-NEXT: br label
+
+ // CHECK: ret void
+}
+
+// rdar://9971982
+@class NSString;
+
+@interface Person {
+ NSString *name;
+}
+@property NSString *address;
+@end
+
+@implementation Person
+@synthesize address;
+@end
+// CHECK: call i8* @objc_getProperty
+// CHECK: call void @objc_setProperty
+
+// rdar://problem/10088932
+void test64_helper(id);
+void test64a(void) {
+ int x;
+ test64_helper(^{ (void) x; });
+
+ // CHECK: define void @test64a()
+ // CHECK: [[X:%.*]] = alloca i32, align 4
+ // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8
+ // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
+ // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
+ // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()*
+ // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8*
+ // CHECK-NEXT: call void @test64_helper(i8* [[T4]])
+ // CHECK-NEXT: [[T5:%.*]] = bitcast void ()* [[T3]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T5]])
+ // CHECK-NEXT: ret void
+}
+void test64b(void) {
+ int x;
+ id b = ^{ (void) x; };
+
+ // CHECK: define void @test64b()
+ // CHECK: [[X:%.*]] = alloca i32, align 4
+ // CHECK-NEXT: [[B:%.*]] = alloca i8*, align 8
+ // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8
+ // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
+ // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
+ // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()*
+ // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8*
+ // 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
+}
+
+// rdar://problem/9979150
+@interface Test65
+@property (strong) void(^ablock)(void);
+@property (nonatomic, strong) void(^nblock)(void);
+@end
+@implementation Test65
+@synthesize ablock, nblock;
+// CHECK: define internal void ()* @"\01-[Test65 ablock]"(
+// CHECK: call i8* @objc_getProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i1 zeroext true)
+
+// CHECK: define internal void @"\01-[Test65 setAblock:]"(
+// CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext true, i1 zeroext true)
+
+// CHECK: define internal void ()* @"\01-[Test65 nblock]"(
+// CHECK: call i8* @objc_getProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i1 zeroext false)
+
+// CHECK: define internal void @"\01-[Test65 setNblock:]"(
+// CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext false, i1 zeroext true)
+@end
+
+// Verify that we successfully parse and preserve this attribute in
+// this position.
+@interface Test66
+- (void) consume: (id __attribute__((ns_consumed))) ptr;
+@end
+void test66(void) {
+ extern Test66 *test66_receiver(void);
+ extern id test66_arg(void);
+ [test66_receiver() consume: test66_arg()];
+}
+// CHECK: define void @test66()
+// CHECK: [[T0:%.*]] = call [[TEST66:%.*]]* @test66_receiver()
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST66]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST66]]*
+// CHECK-NEXT: [[T4:%.*]] = call i8* @test66_arg()
+// CHECK-NEXT: [[T5:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T4]])
+// CHECK-NEXT: [[T6:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+// CHECK-NEXT: [[T7:%.*]] = bitcast [[TEST66]]* [[T3]] to i8*
+// CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*)*)(i8* [[T7]], i8* [[T6]], i8* [[T5]])
+// CHECK-NEXT: [[T8:%.*]] = bitcast [[TEST66]]* [[T3]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T8]])
+// CHECK-NEXT: ret void
diff --git a/test/CodeGenObjC/arm-atomic-scalar-setter-getter.m b/test/CodeGenObjC/arm-atomic-scalar-setter-getter.m
index 2515c706a9bf..535cbbb85c4f 100644
--- a/test/CodeGenObjC/arm-atomic-scalar-setter-getter.m
+++ b/test/CodeGenObjC/arm-atomic-scalar-setter-getter.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple armv7-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-ARM %s
+// RUN: %clang_cc1 -triple armv7-apple-darwin10 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-ARM %s
// rdar://7761305
@interface I
diff --git a/test/CodeGenObjC/assign.m b/test/CodeGenObjC/assign.m
index 87e3834fc874..82da800e7399 100644
--- a/test/CodeGenObjC/assign.m
+++ b/test/CodeGenObjC/assign.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck %s
struct s0 {
int x;
diff --git a/test/CodeGenObjC/atomic-aggregate-property.m b/test/CodeGenObjC/atomic-aggregate-property.m
index 3cd12a5c2c1a..978299b45a6d 100644
--- a/test/CodeGenObjC/atomic-aggregate-property.m
+++ b/test/CodeGenObjC/atomic-aggregate-property.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
// rdar: // 7849824
struct s {
@@ -23,7 +23,20 @@ struct s1 {
@synthesize y;
@synthesize z;
@end
-// CHECK-LP64: call void @objc_copyStruct
-// CHECK-LP64: call void @objc_copyStruct
-// CHECK-LP64: call void @objc_copyStruct
-// CHECK-LP64: call i8* @objc_memmove_collectable
+// CHECK-LP64: define internal double @"\01-[A x]"(
+// CHECK-LP64: load atomic i64* {{%.*}} unordered, align 8
+
+// CHECK-LP64: define internal void @"\01-[A setX:]"(
+// CHECK-LP64: store atomic i64 {{%.*}}, i64* {{%.*}} unordered, align 8
+
+// CHECK-LP64: define internal void @"\01-[A y]"(
+// CHECK-LP64: call void @objc_copyStruct(i8* {{%.*}}, i8* {{%.*}}, i64 32, i1 zeroext true, i1 zeroext false)
+
+// CHECK-LP64: define internal void @"\01-[A setY:]"(
+// CHECK-LP64: call void @objc_copyStruct(i8* {{%.*}}, i8* {{%.*}}, i64 32, i1 zeroext true, i1 zeroext false)
+
+// CHECK-LP64: define internal void @"\01-[A z]"(
+// CHECK-LP64: call i8* @objc_memmove_collectable(
+
+// CHECK-LP64: define internal void @"\01-[A setZ:]"(
+// CHECK-LP64: call i8* @objc_memmove_collectable(
diff --git a/test/CodeGenObjC/attr-availability.m b/test/CodeGenObjC/attr-availability.m
index d2b2973c78d3..375a5be4fadd 100644
--- a/test/CodeGenObjC/attr-availability.m
+++ b/test/CodeGenObjC/attr-availability.m
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fvisibility hidden -fobjc-nonfragile-abi "-triple" "x86_64-apple-darwin8.0.0" -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-10_4 %s
-// RUN: %clang_cc1 -fvisibility hidden -fobjc-nonfragile-abi "-triple" "x86_64-apple-darwin9.0.0" -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-10_5 %s
-// RUN: %clang_cc1 -fvisibility hidden -fobjc-nonfragile-abi "-triple" "x86_64-apple-darwin10.0.0" -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-10_6 %s
+// RUN: %clang_cc1 -fvisibility hidden "-triple" "x86_64-apple-darwin8.0.0" -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-10_4 %s
+// RUN: %clang_cc1 -fvisibility hidden "-triple" "x86_64-apple-darwin9.0.0" -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-10_5 %s
+// RUN: %clang_cc1 -fvisibility hidden "-triple" "x86_64-apple-darwin10.0.0" -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-10_6 %s
// CHECK-10_4: @"OBJC_CLASS_$_WeakClass1" = extern_weak global
// CHECK-10_5: @"OBJC_CLASS_$_WeakClass1" = external global
diff --git a/test/CodeGenObjC/autorelease.m b/test/CodeGenObjC/autorelease.m
index 7bf40f11ffd1..9260c3fafe8b 100644
--- a/test/CodeGenObjC/autorelease.m
+++ b/test/CodeGenObjC/autorelease.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fobjc-nonfragile-abi -fobjc-runtime-has-arc -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -emit-llvm -fobjc-nonfragile-abi -fobjc-runtime-has-arc -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fobjc-runtime-has-arc -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -emit-llvm -fobjc-runtime-has-arc -o - %s | FileCheck %s
// rdar://8881826
// rdar://9412038
diff --git a/test/CodeGenObjC/bitfield-1.m b/test/CodeGenObjC/bitfield-1.m
index 978b3cc30403..648ab2a374db 100644
--- a/test/CodeGenObjC/bitfield-1.m
+++ b/test/CodeGenObjC/bitfield-1.m
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o %t %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o %t %s
-// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple i386-pc-linux-gnu -fobjc-fragile-abi -emit-llvm -o %t %s
@interface Object
- (id) alloc;
diff --git a/test/CodeGenObjC/bitfield-access.m b/test/CodeGenObjC/bitfield-access.m
index ab776abd4ea6..521d2e52a6fa 100644
--- a/test/CodeGenObjC/bitfield-access.m
+++ b/test/CodeGenObjC/bitfield-access.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -emit-llvm -o %t1 %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o %t1 %s
// RUN: FileCheck -check-prefix=CHECK-I386 < %t1 %s
-// RUN: %clang_cc1 -triple armv6-apple-darwin10 -target-abi apcs-gnu -emit-llvm -o %t2 %s
+// RUN: %clang_cc1 -triple armv6-apple-darwin10 -fobjc-fragile-abi -target-abi apcs-gnu -emit-llvm -o %t2 %s
// RUN: FileCheck -check-prefix=CHECK-ARM < %t2 %s
@interface I0 {
diff --git a/test/CodeGenObjC/bitfield-ivar-offsets.m b/test/CodeGenObjC/bitfield-ivar-offsets.m
index ce6f17b8a725..b0c848fd7e3c 100644
--- a/test/CodeGenObjC/bitfield-ivar-offsets.m
+++ b/test/CodeGenObjC/bitfield-ivar-offsets.m
@@ -1,5 +1,5 @@
// RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s &&
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -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
// RUN: grep -F '@"OBJC_IVAR_$_I0._b2" = global i64 1, section "__DATA, __objc_ivar", align 8' %t
diff --git a/test/CodeGenObjC/bitfield_encoding.m b/test/CodeGenObjC/bitfield_encoding.m
index 03cf9bfba722..17fd4a4108b7 100644
--- a/test/CodeGenObjC/bitfield_encoding.m
+++ b/test/CodeGenObjC/bitfield_encoding.m
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fobjc-fragile-abi -emit-llvm -o %t %s
// RUN: grep "ib1b14" %t | count 1
-// RUN: %clang_cc1 -triple i386-unknown-unknown -fgnu-runtime -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fobjc-fragile-abi -fgnu-runtime -emit-llvm -o %t %s
// RUN: grep "ib32i1b33i14" %t | count 1
struct foo{
diff --git a/test/CodeGenObjC/block-6.m b/test/CodeGenObjC/block-6.m
index 44c7a78e698e..140fa8831937 100644
--- a/test/CodeGenObjC/block-6.m
+++ b/test/CodeGenObjC/block-6.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - -fblocks -triple x86_64-apple-darwin10 | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -fblocks -triple x86_64-apple-darwin10 -fobjc-fragile-abi | FileCheck %s
// rdar://8893785
void MYFUNC() {
diff --git a/test/CodeGenObjC/block-var-layout.m b/test/CodeGenObjC/block-var-layout.m
index 466dee1e9e96..1d0ce2d373ad 100644
--- a/test/CodeGenObjC/block-var-layout.m
+++ b/test/CodeGenObjC/block-var-layout.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fblocks -fobjc-gc -triple x86_64-apple-darwin -O0 -emit-llvm %s -o %t-64.s
+// RUN: %clang_cc1 -fblocks -fobjc-gc -triple x86_64-apple-darwin -fobjc-fragile-abi -O0 -emit-llvm %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
struct S {
diff --git a/test/CodeGenObjC/blocks-1.m b/test/CodeGenObjC/blocks-1.m
index 55ce38fe9ef9..64da3594c271 100644
--- a/test/CodeGenObjC/blocks-1.m
+++ b/test/CodeGenObjC/blocks-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o %t -fobjc-gc -fblocks -triple i386-apple-darwin10
+// RUN: %clang_cc1 %s -emit-llvm -o %t -fobjc-gc -fblocks -triple i386-apple-darwin10 -fobjc-fragile-abi
// RUN: grep "_Block_object_dispose" %t | count 6
// RUN: grep "__copy_helper_block_" %t | count 4
// RUN: grep "__destroy_helper_block_" %t | count 4
@@ -8,7 +8,7 @@
// RUN: grep "_Block_object_assign" %t | count 4
// RUN: grep "objc_read_weak" %t | count 2
// RUN: grep "objc_assign_weak" %t | count 3
-// RUN: %clang_cc1 -x objective-c++ %s -emit-llvm -o %t -fobjc-gc -fblocks -triple i386-apple-darwin10
+// RUN: %clang_cc1 -x objective-c++ %s -emit-llvm -o %t -fobjc-gc -fblocks -triple i386-apple-darwin10 -fobjc-fragile-abi
// RUN: grep "_Block_object_dispose" %t | count 6
// RUN: grep "__copy_helper_block_" %t | count 4
// RUN: grep "__destroy_helper_block_" %t | count 4
diff --git a/test/CodeGenObjC/blocks-2.m b/test/CodeGenObjC/blocks-2.m
index 5d63e919fb31..591d63bf37da 100644
--- a/test/CodeGenObjC/blocks-2.m
+++ b/test/CodeGenObjC/blocks-2.m
@@ -1,6 +1,6 @@
// We run this twice, once as Objective-C and once as Objective-C++.
-// RUN: %clang_cc1 %s -emit-llvm -o - -fobjc-gc -fblocks -fexceptions -triple i386-apple-darwin10 | FileCheck %s
-// RUN: %clang_cc1 %s -emit-llvm -o - -fobjc-gc -fblocks -fexceptions -triple i386-apple-darwin10 -x objective-c++ | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -fobjc-gc -fblocks -fexceptions -triple i386-apple-darwin10 -fobjc-fragile-abi | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -fobjc-gc -fblocks -fexceptions -triple i386-apple-darwin10 -fobjc-fragile-abi -x objective-c++ | FileCheck %s
// CHECK: define i8* @{{.*}}test0
@@ -30,8 +30,9 @@ void test1() {
// CHECK-NEXT: call void @_Block_object_dispose(i8* [[T1]], i32 8)
// CHECK-NEXT: ret void
- // CHECK: call i8* @llvm.eh.exception()
+ // CHECK: landingpad { i8*, i32 } personality
+ // CHECK-NEXT: cleanup
// CHECK: [[T1:%.*]] = bitcast [[N_T]]* [[N]] to i8*
// CHECK-NEXT: call void @_Block_object_dispose(i8* [[T1]], i32 8)
- // CHECK: call void @llvm.eh.resume(
+ // CHECK: resume { i8*, i32 }
}
diff --git a/test/CodeGenObjC/blocks-3.m b/test/CodeGenObjC/blocks-3.m
index a0b693dc810b..55e215c7e6ab 100644
--- a/test/CodeGenObjC/blocks-3.m
+++ b/test/CodeGenObjC/blocks-3.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -fblocks -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-fragile-abi -emit-llvm -fblocks -o %t %s
// 1x for the declaration
// 1x for the object-pointer byref copy helper
diff --git a/test/CodeGenObjC/blocks-4.m b/test/CodeGenObjC/blocks-4.m
index f2d6e21a1ce1..b3d099811cf0 100644
--- a/test/CodeGenObjC/blocks-4.m
+++ b/test/CodeGenObjC/blocks-4.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -fobjc-exceptions -fblocks -o %t %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -emit-llvm -fobjc-exceptions -fblocks -o %t %s
// rdar://7590273
void EXIT(id e);
diff --git a/test/CodeGenObjC/blocks-5.m b/test/CodeGenObjC/blocks-5.m
index 2d48b46a4316..caa8d664455e 100644
--- a/test/CodeGenObjC/blocks-5.m
+++ b/test/CodeGenObjC/blocks-5.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -fblocks -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-fragile-abi -emit-llvm -fblocks -o %t %s
// rdar: // 8064140
diff --git a/test/CodeGenObjC/blocks.m b/test/CodeGenObjC/blocks.m
index 47d47cca2e8c..f478c07f78fb 100644
--- a/test/CodeGenObjC/blocks.m
+++ b/test/CodeGenObjC/blocks.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -fblocks -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -emit-llvm -fblocks -o - %s | FileCheck %s
// test1. All of this is somehow testing rdar://6676764
struct S {
diff --git a/test/CodeGenObjC/builtins.m b/test/CodeGenObjC/builtins.m
new file mode 100644
index 000000000000..cb2995da52a5
--- /dev/null
+++ b/test/CodeGenObjC/builtins.m
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck %s
+
+void test0(id receiver, SEL sel, const char *str) {
+ short s = ((short (*)(id, SEL, const char*)) objc_msgSend)(receiver, sel, str);
+}
+// CHECK: define void @test0(
+// CHECK: call signext i16 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i16 (i8*, i8*, i8*)*)(
diff --git a/test/CodeGenObjC/category-class.m b/test/CodeGenObjC/category-class.m
index 22d197380f32..5a82c1425504 100644
--- a/test/CodeGenObjC/category-class.m
+++ b/test/CodeGenObjC/category-class.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck %s
// PR7431
// CHECK: module asm "\09.lazy_reference .objc_class_name_A"
diff --git a/test/CodeGenObjC/class-type.m b/test/CodeGenObjC/class-type.m
index 192a80832783..45aae254bd33 100644
--- a/test/CodeGenObjC/class-type.m
+++ b/test/CodeGenObjC/class-type.m
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o - %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o - %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fobjc-fragile-abi -emit-llvm -o - %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o - %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o - %s
@interface I0 {
diff --git a/test/CodeGenObjC/complex-property.m b/test/CodeGenObjC/complex-property.m
index 5a2b78b5977a..8c3aef9e24bd 100644
--- a/test/CodeGenObjC/complex-property.m
+++ b/test/CodeGenObjC/complex-property.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
// rdar: // 7351147
@interface A
diff --git a/test/CodeGenObjC/constant-string-class-1.m b/test/CodeGenObjC/constant-string-class-1.m
index 8ff605ec6934..5f1e882d0d2e 100644
--- a/test/CodeGenObjC/constant-string-class-1.m
+++ b/test/CodeGenObjC/constant-string-class-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fno-constant-cfstrings -fconstant-string-class OFConstantString -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fno-constant-cfstrings -fconstant-string-class OFConstantString -emit-llvm -o %t %s
// pr9914
@interface OFConstantString
diff --git a/test/CodeGenObjC/constant-string-class.m b/test/CodeGenObjC/constant-string-class.m
index 489f511e7813..ea049a51e12b 100644
--- a/test/CodeGenObjC/constant-string-class.m
+++ b/test/CodeGenObjC/constant-string-class.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fno-constant-cfstrings -fconstant-string-class Foo -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -fno-constant-cfstrings -fconstant-string-class Foo -emit-llvm -o %t %s
// RUN: FileCheck --check-prefix CHECK-FRAGILE < %t %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fno-constant-cfstrings -fconstant-string-class Foo -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fno-constant-cfstrings -fconstant-string-class Foo -emit-llvm -o %t %s
// RUN: FileCheck --check-prefix CHECK-NONFRAGILE < %t %s
// rdar: // 8564463
diff --git a/test/CodeGenObjC/deadcode_strip_used_var.m b/test/CodeGenObjC/deadcode_strip_used_var.m
index 01e6bd4feb33..3137ceb22298 100644
--- a/test/CodeGenObjC/deadcode_strip_used_var.m
+++ b/test/CodeGenObjC/deadcode_strip_used_var.m
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 %s -emit-llvm -o %t -triple i386-apple-darwin10
+// RUN: %clang_cc1 %s -emit-llvm -o %t -triple i386-apple-darwin10 -fobjc-fragile-abi
// RUN: grep "llvm.used" %t | count 1
-// RUN: %clang_cc1 %s -emit-llvm -o %t -triple x86_64-apple-darwin10
+// RUN: %clang_cc1 %s -emit-llvm -o %t -triple x86_64-apple-darwin10 -fobjc-fragile-abi
// RUN: grep "llvm.used" %t | count 1
diff --git a/test/CodeGenObjC/debug-info-block-helper.m b/test/CodeGenObjC/debug-info-block-helper.m
index 136af14bff8b..644e458bbd2c 100644
--- a/test/CodeGenObjC/debug-info-block-helper.m
+++ b/test/CodeGenObjC/debug-info-block-helper.m
@@ -1,5 +1,5 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 -masm-verbose -S -fblocks -g -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
+// RUN: %clang_cc1 -masm-verbose -S -fblocks -g -triple x86_64-apple-darwin10 -fobjc-fragile-abi %s -o - | FileCheck %s
extern void foo(void(^)(void));
// CHECK: .ascii "__destroy_helper_block_" ## DW_AT_name
diff --git a/test/CodeGenObjC/debug-info-blocks.m b/test/CodeGenObjC/debug-info-blocks.m
index fc8e9629734f..71ae8a610ee8 100644
--- a/test/CodeGenObjC/debug-info-blocks.m
+++ b/test/CodeGenObjC/debug-info-blocks.m
@@ -1,5 +1,5 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 -masm-verbose -S -fblocks -g -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-dispatch-method=mixed %s -o - | FileCheck %s
+// 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
diff --git a/test/CodeGenObjC/debug-info-class-extension.m b/test/CodeGenObjC/debug-info-class-extension.m
index cf0445d539b5..e1573f063377 100644
--- a/test/CodeGenObjC/debug-info-class-extension.m
+++ b/test/CodeGenObjC/debug-info-class-extension.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -masm-verbose -S -g %s -o - | FileCheck %s
+// RUN: %clang_cc1 -masm-verbose -S -g %s -o - | FileCheck %s
// CHECK: AT_APPLE_objc_complete_type
diff --git a/test/CodeGenObjC/debug-info-class-extension2.m b/test/CodeGenObjC/debug-info-class-extension2.m
index 4cef88f1637a..bae12dce4e4d 100644
--- a/test/CodeGenObjC/debug-info-class-extension2.m
+++ b/test/CodeGenObjC/debug-info-class-extension2.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -masm-verbose -S -g %s -o - | FileCheck %s
+// RUN: %clang_cc1 -masm-verbose -S -g %s -o - | FileCheck %s
// CHECK: AT_APPLE_objc_complete_type
@interface Foo {} @end
diff --git a/test/CodeGenObjC/debug-info-class-extension3.m b/test/CodeGenObjC/debug-info-class-extension3.m
index 595c7bd2c6bc..f49bef82a24f 100644
--- a/test/CodeGenObjC/debug-info-class-extension3.m
+++ b/test/CodeGenObjC/debug-info-class-extension3.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -masm-verbose -S -g %s -o - | FileCheck %s
+// RUN: %clang_cc1 -masm-verbose -S -g %s -o - | FileCheck %s
// CHECK-NOT: AT_APPLE_objc_complete_type
diff --git a/test/CodeGenObjC/debug-info-crash-2.m b/test/CodeGenObjC/debug-info-crash-2.m
new file mode 100644
index 000000000000..a2acd9dc9170
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-crash-2.m
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -g -S %s -o -
+@class Bar;
+@interface Foo
+@property (strong, nonatomic) Bar *window;
+@end
+
+@interface Foo__ : Foo
+@end
+@implementation Foo__
+@end
+
+@implementation Foo
+@synthesize window = _window;
+@end
+
diff --git a/test/CodeGenObjC/debug-info-crash.m b/test/CodeGenObjC/debug-info-crash.m
index eb2143faed6c..5504356d2e3a 100644
--- a/test/CodeGenObjC/debug-info-crash.m
+++ b/test/CodeGenObjC/debug-info-crash.m
@@ -1,5 +1,5 @@
// REQUIRES: x86-registered-target
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -fblocks -g -S %s -o -
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -fobjc-fragile-abi -fblocks -g -S %s -o -
// rdar://7556129
@implementation test
diff --git a/test/CodeGenObjC/debug-info-default-synth-ivar.m b/test/CodeGenObjC/debug-info-default-synth-ivar.m
index 967a361d6c48..30d751e67d1e 100644
--- a/test/CodeGenObjC/debug-info-default-synth-ivar.m
+++ b/test/CodeGenObjC/debug-info-default-synth-ivar.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-default-synthesize-properties -emit-llvm -g %s -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-default-synthesize-properties -emit-llvm -g %s -o %t
// RUN: grep DW_TAG_member %t | count 5
// rdar://8493239
diff --git a/test/CodeGenObjC/debug-info-fnname.m b/test/CodeGenObjC/debug-info-fnname.m
deleted file mode 100644
index f336d6b26875..000000000000
--- a/test/CodeGenObjC/debug-info-fnname.m
+++ /dev/null
@@ -1,15 +0,0 @@
-// RUN: %clang_cc1 -emit-llvm -Os -g %s -o - | FileCheck %s
-// Radar 8653152
-@interface A {
-}
-@end
-
-
-// CHECK: llvm.dbg.lv.-.A.title.
-@implementation A
--(int) title {
- int x = 1;
- return x;
-}
-@end
-
diff --git a/test/CodeGenObjC/debug-info-getter-name.m b/test/CodeGenObjC/debug-info-getter-name.m
index ec784e372bf8..e7d3a9a8749e 100644
--- a/test/CodeGenObjC/debug-info-getter-name.m
+++ b/test/CodeGenObjC/debug-info-getter-name.m
@@ -1,5 +1,5 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 -fno-dwarf2-cfi-asm -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -S -g %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fno-dwarf2-cfi-asm -triple x86_64-apple-darwin10 -fexceptions -fobjc-exceptions -S -g %s -o - | FileCheck %s
//CHECK: "-[InstanceVariablesEverywhereButTheInterface someString]":
//CHECK: .quad "-[InstanceVariablesEverywhereButTheInterface someString]"
diff --git a/test/CodeGenObjC/debug-info-property2.m b/test/CodeGenObjC/debug-info-property2.m
new file mode 100644
index 000000000000..4cd76c1ca6dc
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-property2.m
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -masm-verbose -S -g %s -o - | FileCheck %s
+
+// CHECK: AT_APPLE_property_name
+@interface C {
+ int _base;
+}
+@property int base;
+@end
+
+@implementation C
+@synthesize base = _base;
+@end
+
+void foo(C *cptr) {}
diff --git a/test/CodeGenObjC/debug-info-static-var.m b/test/CodeGenObjC/debug-info-static-var.m
index 94513f227884..1f281d042d10 100644
--- a/test/CodeGenObjC/debug-info-static-var.m
+++ b/test/CodeGenObjC/debug-info-static-var.m
@@ -1,5 +1,5 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 -g -triple x86_64-apple-darwin10 -S -masm-verbose -o - %s | FileCheck %s
+// RUN: %clang_cc1 -g -triple x86_64-apple-darwin10 -fobjc-fragile-abi -S -masm-verbose -o - %s | FileCheck %s
// Radar 8801045
// Do not emit AT_MIPS_linkage_name for static variable i
diff --git a/test/CodeGenObjC/default-property-synthesis.m b/test/CodeGenObjC/default-property-synthesis.m
index 72acb768a11a..7d7296b5df78 100644
--- a/test/CodeGenObjC/default-property-synthesis.m
+++ b/test/CodeGenObjC/default-property-synthesis.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o %t %s
// rdar://7923851.
// Superclass declares property. Subclass redeclares the same property.
diff --git a/test/CodeGenObjC/encode-cstyle-method.m b/test/CodeGenObjC/encode-cstyle-method.m
index 187c9bfa9d63..ea630230b541 100644
--- a/test/CodeGenObjC/encode-cstyle-method.m
+++ b/test/CodeGenObjC/encode-cstyle-method.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
// rdar: // 7445205
@interface Foo
diff --git a/test/CodeGenObjC/encode-test-4.m b/test/CodeGenObjC/encode-test-4.m
index 117e1733486e..2624bc71fce2 100644
--- a/test/CodeGenObjC/encode-test-4.m
+++ b/test/CodeGenObjC/encode-test-4.m
@@ -1,5 +1,10 @@
// RUN: %clang_cc1 -emit-llvm -o - %s -O2 | grep "ret i32 1"
+typedef long Integer;
+typedef enum : Integer { Red, Green, Blue} Color;
+typedef enum { Cyan, Magenta, Yellow, Key } PrintColor;
int a() {
- return @encode(int) == @encode(int);
+ return @encode(int) == @encode(int) &&
+ @encode(Color) == @encode(long) &&
+ @encode(PrintColor) == @encode(int);
}
diff --git a/test/CodeGenObjC/encode-test.m b/test/CodeGenObjC/encode-test.m
index f30fb26a1e65..02af5daa2265 100644
--- a/test/CodeGenObjC/encode-test.m
+++ b/test/CodeGenObjC/encode-test.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple=i686-apple-darwin9 -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o %t %s
// RUN: FileCheck < %t %s
//
// CHECK: @"\01L_OBJC_METH_VAR_TYPE_34" = internal global [16 x i8] c"v12@0:4[3[4@]]8\00"
diff --git a/test/CodeGenObjC/exceptions-nonfragile.m b/test/CodeGenObjC/exceptions-nonfragile.m
index 2557aab25219..1f3892699839 100644
--- a/test/CodeGenObjC/exceptions-nonfragile.m
+++ b/test/CodeGenObjC/exceptions-nonfragile.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fexceptions -fobjc-exceptions -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fexceptions -fobjc-exceptions -o - %s | FileCheck %s
// rdar://problem/8535238
// CHECK: declare void @objc_exception_rethrow()
diff --git a/test/CodeGenObjC/exceptions.m b/test/CodeGenObjC/exceptions.m
index d378f848f861..2472869ff58b 100644
--- a/test/CodeGenObjC/exceptions.m
+++ b/test/CodeGenObjC/exceptions.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fexceptions -fobjc-exceptions -O2 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -fexceptions -fobjc-exceptions -O2 -o - %s | FileCheck %s
//
// <rdar://problem/7471679> [irgen] [eh] Exception code built with clang (x86_64) crashes
diff --git a/test/CodeGenObjC/forward-class-impl-metadata.m b/test/CodeGenObjC/forward-class-impl-metadata.m
index 0ab7a8166453..e9e08589d19f 100644
--- a/test/CodeGenObjC/forward-class-impl-metadata.m
+++ b/test/CodeGenObjC/forward-class-impl-metadata.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -emit-llvm -o %t %s
+// RUN: %clang_cc1 -emit-llvm -o %t %s
@interface BASE {
@private
diff --git a/test/CodeGenObjC/fpret.m b/test/CodeGenObjC/fpret.m
index bde0caa8ff3a..bf111e001d04 100644
--- a/test/CodeGenObjC/fpret.m
+++ b/test/CodeGenObjC/fpret.m
@@ -1,10 +1,10 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o - %s | \
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o - %s | \
// RUN: FileCheck --check-prefix=CHECK-X86_32 %s
//
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | \
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - %s | \
// RUN: FileCheck --check-prefix=CHECK-X86_64 %s
//
-// RUN: %clang_cc1 -triple armv7-apple-darwin10 -emit-llvm -target-abi apcs-gnu -o - %s | \
+// RUN: %clang_cc1 -triple armv7-apple-darwin10 -fobjc-fragile-abi -emit-llvm -target-abi apcs-gnu -o - %s | \
// RUN: FileCheck --check-prefix=CHECK-ARMV7 %s
@interface A
diff --git a/test/CodeGenObjC/gc-weak-attribute.m b/test/CodeGenObjC/gc-weak-attribute.m
new file mode 100644
index 000000000000..032c7c6beb4f
--- /dev/null
+++ b/test/CodeGenObjC/gc-weak-attribute.m
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o - %s | FileCheck %s
+// rdar://10073896
+
+@interface I
+{
+ __weak id wObject;
+}
+@property (readwrite, weak) id representedObject;
+@property (readwrite, weak) id wObject;
+@property (readwrite, weak) __weak id wRandom;
+@property (readwrite, assign) __weak id wAnother;
+@end
+
+@implementation I
+@synthesize representedObject;
+@synthesize wObject;
+@synthesize wRandom;
+@synthesize wAnother;
+@end
+// CHECK: call i8* @objc_read_weak
+// CHECK: call i8* @objc_assign_weak
+// CHECK: call i8* @objc_read_weak
+// CHECK: call i8* @objc_assign_weak
+// CHECK: call i8* @objc_read_weak
+// CHECK: call i8* @objc_assign_weak
+// CHECK: call i8* @objc_read_weak
+// CHECK: call i8* @objc_assign_weak
+
diff --git a/test/CodeGenObjC/gc.m b/test/CodeGenObjC/gc.m
index 93554e65b880..b6721813c17e 100644
--- a/test/CodeGenObjC/gc.m
+++ b/test/CodeGenObjC/gc.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o - %s | FileCheck %s
void test0(void) {
extern id test0_helper(void);
diff --git a/test/CodeGenObjC/gnu-exceptions.m b/test/CodeGenObjC/gnu-exceptions.m
index 7f3ae9df467e..8917bf3120da 100644
--- a/test/CodeGenObjC/gnu-exceptions.m
+++ b/test/CodeGenObjC/gnu-exceptions.m
@@ -14,9 +14,9 @@ void test0() {
// CHECK: call void @log(i32 1)
} @catch (C *c) {
- // CHECK: call i8* @llvm.eh.exception()
- // CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector({{.*}} @__gnu_objc_personality_v0
- // CHECK: br i1
+ // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gnu_objc_personality_v0 to i8*)
+ // CHECK-NEXT: catch i8* getelementptr inbounds ([2 x i8]* @0, i64 0, i64 0)
+ // CHECK: br i1
// CHECK: call void @log(i32 0)
diff --git a/test/CodeGenObjC/hidden-visibility.m b/test/CodeGenObjC/hidden-visibility.m
index 5e08ef9d55d2..9f5071d5ffaa 100644
--- a/test/CodeGenObjC/hidden-visibility.m
+++ b/test/CodeGenObjC/hidden-visibility.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fvisibility hidden -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fvisibility hidden -emit-llvm -o - %s | FileCheck %s
// CHECK: @"OBJC_IVAR_$_I.P" = hidden
// CHECK: @"OBJC_CLASS_$_I" = hidden
// CHECK: @"OBJC_METACLASS_$_I" = hidden
diff --git a/test/CodeGenObjC/id-isa-codegen.m b/test/CodeGenObjC/id-isa-codegen.m
index e4f5fd9ab571..8cac750773c4 100644
--- a/test/CodeGenObjC/id-isa-codegen.m
+++ b/test/CodeGenObjC/id-isa-codegen.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o - %s | FileCheck -check-prefix LP32 %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck -check-prefix LP32 %s
typedef struct objc_class *Class;
diff --git a/test/CodeGenObjC/image-info.m b/test/CodeGenObjC/image-info.m
index 2777723f736f..22f7229b6950 100644
--- a/test/CodeGenObjC/image-info.m
+++ b/test/CodeGenObjC/image-info.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o %t %s
// RUN: FileCheck --check-prefix CHECK-FRAGILE < %t %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o %t %s
// RUN: FileCheck --check-prefix CHECK-NONFRAGILE < %t %s
// CHECK-FRAGILE: @"\01L_OBJC_IMAGE_INFO" = internal constant [2 x i32] [i32 0, i32 16], section "__OBJC, __image_info,regular"
diff --git a/test/CodeGenObjC/implicit-objc_msgSend.m b/test/CodeGenObjC/implicit-objc_msgSend.m
index 322f82e920a0..aff0fe45a009 100644
--- a/test/CodeGenObjC/implicit-objc_msgSend.m
+++ b/test/CodeGenObjC/implicit-objc_msgSend.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o %t %s
// RUN: grep -F 'declare i8* @objc_msgSend(i8*, i8*, ...)' %t
typedef struct objc_selector *SEL;
diff --git a/test/CodeGenObjC/instance-method-metadata.m b/test/CodeGenObjC/instance-method-metadata.m
index 4e752c0061b9..ec24c287a36d 100644
--- a/test/CodeGenObjC/instance-method-metadata.m
+++ b/test/CodeGenObjC/instance-method-metadata.m
@@ -1,5 +1,5 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -S -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -S -o %t %s
// RUN: FileCheck < %t %s
// rdar://9072317
diff --git a/test/CodeGenObjC/interface-layout-64.m b/test/CodeGenObjC/interface-layout-64.m
index 5158c61c5bdb..4fdda4559d14 100644
--- a/test/CodeGenObjC/interface-layout-64.m
+++ b/test/CodeGenObjC/interface-layout-64.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o %t %s
// RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s &&
// RUN: grep '@"OBJC_IVAR_$_I3._iv2" = global i64 8, section "__DATA, __objc_ivar", align 8' %t
diff --git a/test/CodeGenObjC/interface.m b/test/CodeGenObjC/interface.m
index 17d56f7b1db4..0ca64ecd3ffc 100644
--- a/test/CodeGenObjC/interface.m
+++ b/test/CodeGenObjC/interface.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -O3 -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -O3 -emit-llvm -o %t %s
// RUN: grep 'ret i32 385' %t
void *alloca();
diff --git a/test/CodeGenObjC/ivar-layout-64-bitfields.m b/test/CodeGenObjC/ivar-layout-64-bitfields.m
index 700ce18d74cb..acc734a575de 100644
--- a/test/CodeGenObjC/ivar-layout-64-bitfields.m
+++ b/test/CodeGenObjC/ivar-layout-64-bitfields.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
#ifdef __cplusplus
typedef bool _Bool;
diff --git a/test/CodeGenObjC/ivar-layout-64.m b/test/CodeGenObjC/ivar-layout-64.m
index f227bfc30d36..ea4cdce4b8b2 100644
--- a/test/CodeGenObjC/ivar-layout-64.m
+++ b/test/CodeGenObjC/ivar-layout-64.m
@@ -1,11 +1,11 @@
// RUNX: llvm-gcc -m64 -fobjc-gc -emit-llvm -S -o %t %s &&
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"A\\00"' %t
// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"\\11q\\10\\00"' %t
// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"!q\\00"' %t
// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"\\01\\14\\00"' %t
// RUNX: llvm-gcc -ObjC++ -m64 -fobjc-gc -emit-llvm -S -o %t %s &&
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"A\\00"' %t
// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"\\11q\\10\\00"' %t
// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"!q\\00"' %t
diff --git a/test/CodeGenObjC/ivar-layout-array0-struct.m b/test/CodeGenObjC/ivar-layout-array0-struct.m
index a9ae0ac73389..7ef32f634237 100644
--- a/test/CodeGenObjC/ivar-layout-array0-struct.m
+++ b/test/CodeGenObjC/ivar-layout-array0-struct.m
@@ -1,5 +1,5 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin -O0 -S %s -o %t-64.s
+// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin -fobjc-fragile-abi -O0 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// rdar://8800513
diff --git a/test/CodeGenObjC/ivar-layout-no-optimize.m b/test/CodeGenObjC/ivar-layout-no-optimize.m
index 2851e7942798..85bba8abaaa9 100644
--- a/test/CodeGenObjC/ivar-layout-no-optimize.m
+++ b/test/CodeGenObjC/ivar-layout-no-optimize.m
@@ -1,7 +1,7 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin -O0 -S %s -o %t-64.s
+// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin -fobjc-fragile-abi -O0 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -x objective-c++ -fobjc-gc -triple x86_64-apple-darwin -O0 -S %s -o %t-64.s
+// RUN: %clang_cc1 -x objective-c++ -fobjc-gc -triple x86_64-apple-darwin -fobjc-fragile-abi -O0 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
@interface NSObject {
diff --git a/test/CodeGenObjC/ivar-layout-nonfragile-abi2.m b/test/CodeGenObjC/ivar-layout-nonfragile-abi2.m
index 012ccadd9f92..65e17a84f163 100644
--- a/test/CodeGenObjC/ivar-layout-nonfragile-abi2.m
+++ b/test/CodeGenObjC/ivar-layout-nonfragile-abi2.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -emit-llvm -o %t %s
// rdar: // 7824380
@interface Super {
diff --git a/test/CodeGenObjC/ivars.m b/test/CodeGenObjC/ivars.m
index 98c39b7a844b..6c8a72d0f100 100644
--- a/test/CodeGenObjC/ivars.m
+++ b/test/CodeGenObjC/ivars.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o - %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o - %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o - %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o - %s
// RUN: %clang_cc1 -fobjc-gc -emit-llvm -o - %s
// rdar://6800926
diff --git a/test/CodeGenObjC/link-errors.m b/test/CodeGenObjC/link-errors.m
index a82f0ceaf76d..0d19681ec109 100644
--- a/test/CodeGenObjC/link-errors.m
+++ b/test/CodeGenObjC/link-errors.m
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o %t %s
// RUN: grep '.lazy_reference .objc_class_name_A' %t | count 1
// RUN: grep '.lazy_reference .objc_class_name_Unknown' %t | count 1
// RUN: grep '.lazy_reference .objc_class_name_Protocol' %t | count 1
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -DWITH_IMPL -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -DWITH_IMPL -emit-llvm -o %t %s
// RUN: grep '.lazy_reference .objc_class_name_Root' %t | count 1
@interface Root
diff --git a/test/CodeGenObjC/local-static-block.m b/test/CodeGenObjC/local-static-block.m
index a40abb26ea79..7a7b6f6e087b 100644
--- a/test/CodeGenObjC/local-static-block.m
+++ b/test/CodeGenObjC/local-static-block.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin -emit-llvm %s -o %t-64.ll
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin -fobjc-fragile-abi -emit-llvm %s -o %t-64.ll
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.ll %s
// rdar: // 8390455
diff --git a/test/CodeGenObjC/messages-2.m b/test/CodeGenObjC/messages-2.m
index e4e8cfb5e202..7c9d81cc9d71 100644
--- a/test/CodeGenObjC/messages-2.m
+++ b/test/CodeGenObjC/messages-2.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-NF
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-NF
// Most of this test is apparently just verifying that we don't crash.
diff --git a/test/CodeGenObjC/messages.m b/test/CodeGenObjC/messages.m
index a921dc774ad1..6f39602d9c96 100644
--- a/test/CodeGenObjC/messages.m
+++ b/test/CodeGenObjC/messages.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-MAC
-// RUN: %clang_cc1 -emit-llvm -fobjc-nonfragile-abi -o - %s | FileCheck %s -check-prefix=CHECK-MAC-NF
-// RUN: %clang_cc1 -fgnu-runtime -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-GNU
-// RUN: %clang_cc1 -fgnu-runtime -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-GNU-NF
+// RUN: %clang_cc1 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-MAC
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-MAC-NF
+// RUN: %clang_cc1 -fobjc-fragile-abi -fgnu-runtime -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-GNU
+// RUN: %clang_cc1 -fgnu-runtime -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-GNU-NF
typedef struct {
int x;
diff --git a/test/CodeGenObjC/metadata-symbols-32.m b/test/CodeGenObjC/metadata-symbols-32.m
index 34cc83da315a..a7bcf01926b2 100644
--- a/test/CodeGenObjC/metadata-symbols-32.m
+++ b/test/CodeGenObjC/metadata-symbols-32.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -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
diff --git a/test/CodeGenObjC/metadata-symbols-64.m b/test/CodeGenObjC/metadata-symbols-64.m
index 4bc41fa443da..57f5d508ab1c 100644
--- a/test/CodeGenObjC/metadata-symbols-64.m
+++ b/test/CodeGenObjC/metadata-symbols-64.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-dispatch-method=mixed -emit-llvm -o %t %s
+// 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
diff --git a/test/CodeGenObjC/metadata_symbols.m b/test/CodeGenObjC/metadata_symbols.m
index 370ca6eccbe9..576a55b13693 100644
--- a/test/CodeGenObjC/metadata_symbols.m
+++ b/test/CodeGenObjC/metadata_symbols.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -fexceptions -fobjc-exceptions -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fexceptions -fobjc-exceptions -o %t %s
// RUN: FileCheck -check-prefix=CHECK-X86_64 < %t %s
// RUN: grep '@"OBJC_EHTYPE_$_EH3"' %t | count 3
@@ -12,7 +12,7 @@
// CHECK-X86_64: define internal void @"\01-[A im0]"
// CHECK-X86_64: define internal void @"\01-[A(Cat) im1]"
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-exceptions -fvisibility hidden -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-exceptions -fvisibility hidden -emit-llvm -o %t %s
// RUN: FileCheck -check-prefix=CHECK-X86_64-HIDDEN < %t %s
// CHECK-X86_64-HIDDEN: @"OBJC_CLASS_$_A" = hidden global {{.*}}, section "__DATA, __objc_data", align 8
@@ -23,7 +23,7 @@
// CHECK-X86_64-HIDDEN: define internal void @"\01-[A im0]"
// CHECK-X86_64-HIDDEN: define internal void @"\01-[A(Cat) im1]"
-// RUN: %clang_cc1 -triple armv6-apple-darwin10 -target-abi apcs-gnu -fobjc-nonfragile-abi -fobjc-exceptions -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple armv6-apple-darwin10 -target-abi apcs-gnu -fobjc-exceptions -emit-llvm -o %t %s
// RUN: FileCheck -check-prefix=CHECK-ARMV6 < %t %s
// CHECK-ARMV6: @"OBJC_CLASS_$_A" = global {{.*}}, section "__DATA, __objc_data", align 4
diff --git a/test/CodeGenObjC/misc-atomic-property.m b/test/CodeGenObjC/misc-atomic-property.m
index 26402d355b59..f2645dcaef84 100644
--- a/test/CodeGenObjC/misc-atomic-property.m
+++ b/test/CodeGenObjC/misc-atomic-property.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck %s
// rdar: //8808439
typedef struct {
diff --git a/test/CodeGenObjC/mrr-autorelease.m b/test/CodeGenObjC/mrr-autorelease.m
index 10f549fcec5e..f7a13fd8dcf2 100644
--- a/test/CodeGenObjC/mrr-autorelease.m
+++ b/test/CodeGenObjC/mrr-autorelease.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck %s
// rdar://8881826
// rdar://9423507
diff --git a/test/CodeGenObjC/nested-rethrow.m b/test/CodeGenObjC/nested-rethrow.m
index af5154a24c27..5576c1640d18 100644
--- a/test/CodeGenObjC/nested-rethrow.m
+++ b/test/CodeGenObjC/nested-rethrow.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -fobjc-exceptions %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -emit-llvm -fobjc-exceptions %s -o - | FileCheck %s
extern int printf(const char*, ...);
diff --git a/test/CodeGenObjC/next-objc-dispatch.m b/test/CodeGenObjC/next-objc-dispatch.m
index a3e8e19641eb..4288b2da0cb2 100644
--- a/test/CodeGenObjC/next-objc-dispatch.m
+++ b/test/CodeGenObjC/next-objc-dispatch.m
@@ -1,17 +1,17 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o - %s \
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o - %s \
// RUN: -fobjc-dispatch-method=legacy | \
// RUN: FileCheck -check-prefix CHECK-FRAGILE_LEGACY %s
//
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o - %s \
-// RUN: -fobjc-nonfragile-abi -fobjc-dispatch-method=legacy | \
+// RUN: -fobjc-dispatch-method=legacy | \
// RUN: FileCheck -check-prefix CHECK-NONFRAGILE_LEGACY %s
//
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o - %s \
-// RUN: -fobjc-nonfragile-abi -fobjc-dispatch-method=non-legacy | \
+// RUN: -fobjc-dispatch-method=non-legacy | \
// RUN: FileCheck -check-prefix CHECK-NONFRAGILE_NONLEGACY %s
//
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o - %s \
-// RUN: -fobjc-nonfragile-abi -fobjc-dispatch-method=mixed | \
+// RUN: -fobjc-dispatch-method=mixed | \
// RUN: FileCheck -check-prefix CHECK-NONFRAGILE_MIXED %s
//
// <rdar://problem/7866951>
diff --git a/test/CodeGenObjC/no-category-class.m b/test/CodeGenObjC/no-category-class.m
index 0bd999689dd1..3969f917e2f3 100644
--- a/test/CodeGenObjC/no-category-class.m
+++ b/test/CodeGenObjC/no-category-class.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fobjc-fragile-abi -emit-llvm -o %t %s
@interface NSObject
@end
diff --git a/test/CodeGenObjC/no-vararg-messaging.m b/test/CodeGenObjC/no-vararg-messaging.m
index 6747c0c9e4ef..3f9d934ec88f 100644
--- a/test/CodeGenObjC/no-vararg-messaging.m
+++ b/test/CodeGenObjC/no-vararg-messaging.m
@@ -1,5 +1,5 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -S -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -S -o - %s | FileCheck %s
// rdar://9048030
@interface Foo
diff --git a/test/CodeGenObjC/non-lazy-classes.m b/test/CodeGenObjC/non-lazy-classes.m
index 512ad897c7fe..5d8290155e32 100644
--- a/test/CodeGenObjC/non-lazy-classes.m
+++ b/test/CodeGenObjC/non-lazy-classes.m
@@ -1,5 +1,5 @@
// RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s &&
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -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 3d7ba10dc5e8..73157c77c030 100644
--- a/test/CodeGenObjC/nonlazy-msgSend.m
+++ b/test/CodeGenObjC/nonlazy-msgSend.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o %t %s
// RUN: grep -F 'declare i8* @objc_msgSend(i8*, i8*, ...) nonlazybind' %t
void f0(id x) {
diff --git a/test/CodeGenObjC/ns-constant-strings.m b/test/CodeGenObjC/ns-constant-strings.m
index 389132bd05ee..d04793c8c239 100644
--- a/test/CodeGenObjC/ns-constant-strings.m
+++ b/test/CodeGenObjC/ns-constant-strings.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fno-constant-cfstrings -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -fno-constant-cfstrings -emit-llvm -o %t %s
// RUN: FileCheck --check-prefix CHECK-FRAGILE < %t %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fno-constant-cfstrings -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fno-constant-cfstrings -emit-llvm -o %t %s
// RUN: FileCheck --check-prefix CHECK-NONFRAGILE < %t %s
@interface NSString @end
diff --git a/test/CodeGenObjC/objc-align.m b/test/CodeGenObjC/objc-align.m
index ff3f2a0a9088..f07272516f1c 100644
--- a/test/CodeGenObjC/objc-align.m
+++ b/test/CodeGenObjC/objc-align.m
@@ -1,7 +1,7 @@
// 32-bit
// RUNX: llvm-gcc -m32 -emit-llvm -S -o %t %s &&
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -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
// RUN: grep '@"\\01L_OBJC_CLASS_C" = internal global .*, section "__OBJC,__class,regular,no_dead_strip", align 4' %t
diff --git a/test/CodeGenObjC/objc-assign-ivar.m b/test/CodeGenObjC/objc-assign-ivar.m
index aefe97d0f2a7..d0a1a0fceefe 100644
--- a/test/CodeGenObjC/objc-assign-ivar.m
+++ b/test/CodeGenObjC/objc-assign-ivar.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
// RUN: grep -F '@objc_assign_ivar' %t | count 14
typedef struct {
diff --git a/test/CodeGenObjC/objc-gc-aggr-assign.m b/test/CodeGenObjC/objc-gc-aggr-assign.m
index 9fd64d5645c8..dfdf02e2a5a6 100644
--- a/test/CodeGenObjC/objc-gc-aggr-assign.m
+++ b/test/CodeGenObjC/objc-gc-aggr-assign.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix C %s
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix CP %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix C %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix CP %s
static int count;
diff --git a/test/CodeGenObjC/objc-read-weak-byref.m b/test/CodeGenObjC/objc-read-weak-byref.m
index c89fcd520e5e..8fe1436567b1 100644
--- a/test/CodeGenObjC/objc-read-weak-byref.m
+++ b/test/CodeGenObjC/objc-read-weak-byref.m
@@ -1,7 +1,7 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
-// RUN: %clang_cc1 -fblocks -fobjc-gc -triple x86_64-apple-darwin -S %s -o %t-64.s
+// RUN: %clang_cc1 -fblocks -fobjc-gc -triple x86_64-apple-darwin -fobjc-fragile-abi -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -fblocks -fobjc-gc -triple i386-apple-darwin -S %s -o %t-32.s
+// RUN: %clang_cc1 -fblocks -fobjc-gc -triple i386-apple-darwin -fobjc-fragile-abi -S %s -o %t-32.s
// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
@interface NSObject
diff --git a/test/CodeGenObjC/objc2-assign-global.m b/test/CodeGenObjC/objc2-assign-global.m
index ff3ecef72d8d..36c95f792dae 100644
--- a/test/CodeGenObjC/objc2-assign-global.m
+++ b/test/CodeGenObjC/objc2-assign-global.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
// RUN: grep -F '@objc_assign_global' %t | count 26
@class NSObject;
diff --git a/test/CodeGenObjC/objc2-ivar-assign.m b/test/CodeGenObjC/objc2-ivar-assign.m
index e50cc5b53729..af768007212b 100644
--- a/test/CodeGenObjC/objc2-ivar-assign.m
+++ b/test/CodeGenObjC/objc2-ivar-assign.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -fobjc-gc -emit-llvm -o %t %s
// RUN: grep objc_assign_ivar %t | count 6
@interface I @end
diff --git a/test/CodeGenObjC/objc2-legacy-dispatch.m b/test/CodeGenObjC/objc2-legacy-dispatch.m
index 7a99d15ba0dc..a6b20000d802 100644
--- a/test/CodeGenObjC/objc2-legacy-dispatch.m
+++ b/test/CodeGenObjC/objc2-legacy-dispatch.m
@@ -1,11 +1,11 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-dispatch-method=mixed -triple i386-apple-darwin10 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK_NEW_DISPATCH %s
+// RUN: %clang_cc1 -fobjc-dispatch-method=mixed -triple i386-apple-darwin10 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK_NEW_DISPATCH %s
//
// CHECK_NEW_DISPATCH: define void @f0
// CHECK_NEW_DISPATCH: bitcast {{.*}}objc_msgSend_fixup_alloc
// CHECK_NEW_DISPATCH: define void @f1
// CHECK_NEW_DISPATCH: load {{.*}}OBJC_SELECTOR_REFERENCES
//
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-dispatch-method=legacy -emit-llvm -o - %s | FileCheck -check-prefix=CHECK_OLD_DISPATCH %s
+// RUN: %clang_cc1 -fobjc-dispatch-method=legacy -emit-llvm -o - %s | FileCheck -check-prefix=CHECK_OLD_DISPATCH %s
//
// CHECK_OLD_DISPATCH: define void @f0
// CHECK_OLD_DISPATCH: load {{.*}}OBJC_SELECTOR_REFERENCES
diff --git a/test/CodeGenObjC/objc2-new-gc-api-strongcast.m b/test/CodeGenObjC/objc2-new-gc-api-strongcast.m
index 0413910855e5..1044ba529857 100644
--- a/test/CodeGenObjC/objc2-new-gc-api-strongcast.m
+++ b/test/CodeGenObjC/objc2-new-gc-api-strongcast.m
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -fblocks -fobjc-gc -emit-llvm -o %t %s
// RUN: grep -F '@objc_assign_strongCast' %t | count 4
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fblocks -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-fragile-abi -fblocks -fobjc-gc -emit-llvm -o %t %s
// RUN: grep -F '@objc_assign_strongCast' %t | count 4
@interface DSATextSearch @end
diff --git a/test/CodeGenObjC/objc2-no-write-barrier.m b/test/CodeGenObjC/objc2-no-write-barrier.m
index a0ebc100fb2f..d439368cc608 100644
--- a/test/CodeGenObjC/objc2-no-write-barrier.m
+++ b/test/CodeGenObjC/objc2-no-write-barrier.m
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
// RUN: grep 'objc_assign' %t | count 0
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
// RUN: grep 'objc_assign' %t | count 0
typedef struct {
diff --git a/test/CodeGenObjC/objc2-nonfragile-abi-impl.m b/test/CodeGenObjC/objc2-nonfragile-abi-impl.m
index cb830b8dcc92..c785a5d47642 100644
--- a/test/CodeGenObjC/objc2-nonfragile-abi-impl.m
+++ b/test/CodeGenObjC/objc2-nonfragile-abi-impl.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o %t %s
// rdar://7547942.
@interface Base @end
diff --git a/test/CodeGenObjC/objc2-retain-codegen.m b/test/CodeGenObjC/objc2-retain-codegen.m
index 9f6620619ecd..d5b473e33473 100644
--- a/test/CodeGenObjC/objc2-retain-codegen.m
+++ b/test/CodeGenObjC/objc2-retain-codegen.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fobjc-gc-only -emit-llvm -o %t %s
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-unknown-unknown -fobjc-gc-only -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fobjc-fragile-abi -fobjc-gc-only -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-unknown-unknown -fobjc-fragile-abi -fobjc-gc-only -emit-llvm -o %t %s
@interface I0 {
I0 *_f0;
diff --git a/test/CodeGenObjC/objc2-strong-cast-1.m b/test/CodeGenObjC/objc2-strong-cast-1.m
index b79f8a00f7a3..9bb750fd0523 100644
--- a/test/CodeGenObjC/objc2-strong-cast-1.m
+++ b/test/CodeGenObjC/objc2-strong-cast-1.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fobjc-gc -emit-llvm -o %t %s
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-unknown-unknown -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-unknown-unknown -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
@interface I {
__attribute__((objc_gc(strong))) int *i_IdocumentIDs;
diff --git a/test/CodeGenObjC/objc2-strong-cast-block-import.m b/test/CodeGenObjC/objc2-strong-cast-block-import.m
new file mode 100644
index 000000000000..adec3762012b
--- /dev/null
+++ b/test/CodeGenObjC/objc2-strong-cast-block-import.m
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc-only -fblocks -emit-llvm -o - %s | FileCheck %s
+// rdar://10150823
+
+@interface Test {
+@package
+ Test ** __strong objects;
+}
+@end
+
+id newObject();
+void runWithBlock(void(^)(int i));
+
+@implementation Test
+
+- (void)testWithObjectInBlock {
+ Test **children = objects;
+ runWithBlock(^(int i){
+ children[i] = newObject();
+ });
+}
+
+@end
+// CHECK: call i8* @objc_assign_strongCast
+// CHECK: call i8* @objc_assign_strongCast
+
diff --git a/test/CodeGenObjC/objc2-weak-assign.m b/test/CodeGenObjC/objc2-weak-assign.m
index 74c0c00c7caa..e5c67c58d64a 100644
--- a/test/CodeGenObjC/objc2-weak-assign.m
+++ b/test/CodeGenObjC/objc2-weak-assign.m
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
// RUN: grep -e "objc_assign_weak" %t | grep -e "call" | count 6
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
// RUN: grep -e "objc_assign_weak" %t | grep -e "call" | count 6
__weak id* x;
diff --git a/test/CodeGenObjC/objc2-weak-block-call.m b/test/CodeGenObjC/objc2-weak-block-call.m
index 8cd233e286b2..94c54e7f3ba2 100644
--- a/test/CodeGenObjC/objc2-weak-block-call.m
+++ b/test/CodeGenObjC/objc2-weak-block-call.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fblocks -fobjc-gc -triple x86_64-apple-darwin -emit-llvm %s -o - | FileCheck -check-prefix LP64 %s
-// RUN: %clang_cc1 -fblocks -fobjc-gc -triple i386-apple-darwin -emit-llvm %s -o - | FileCheck -check-prefix LP64 %s
+// RUN: %clang_cc1 -fblocks -fobjc-gc -triple x86_64-apple-darwin -fobjc-fragile-abi -emit-llvm %s -o - | FileCheck -check-prefix LP64 %s
+// RUN: %clang_cc1 -fblocks -fobjc-gc -triple i386-apple-darwin -fobjc-fragile-abi -emit-llvm %s -o - | FileCheck -check-prefix LP64 %s
@interface MyView
- (void)MyView_sharedInit;
diff --git a/test/CodeGenObjC/objc2-weak-compare.m b/test/CodeGenObjC/objc2-weak-compare.m
index 8cba1a986094..75cf689737b4 100644
--- a/test/CodeGenObjC/objc2-weak-compare.m
+++ b/test/CodeGenObjC/objc2-weak-compare.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
-// RUN: %clang_cc1 -x objective-c++ -triple i386-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -triple i386-apple-darwin9 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
@interface PBXTarget
{
diff --git a/test/CodeGenObjC/objc2-weak-import-attribute.m b/test/CodeGenObjC/objc2-weak-import-attribute.m
index 946c79b5bcc5..201e24b9e5ec 100644
--- a/test/CodeGenObjC/objc2-weak-import-attribute.m
+++ b/test/CodeGenObjC/objc2-weak-import-attribute.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-X86-64 %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-X86-64 %s
__attribute__((weak_import)) @interface WeakRootClass @end
diff --git a/test/CodeGenObjC/objc2-weak-ivar-debug.m b/test/CodeGenObjC/objc2-weak-ivar-debug.m
index 8f7acd7619ac..83262a82a61b 100644
--- a/test/CodeGenObjC/objc2-weak-ivar-debug.m
+++ b/test/CodeGenObjC/objc2-weak-ivar-debug.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-gc -g -emit-llvm -o - %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-gc -g -emit-llvm -o - %s
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-gc -g -emit-llvm -o - %s
-// RUN: %clang_cc1 -x objective-c++ -triple i386-apple-darwin9 -fobjc-gc -g -emit-llvm -o - %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-fragile-abi -fobjc-gc -g -emit-llvm -o - %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -fobjc-gc -g -emit-llvm -o - %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-fragile-abi -fobjc-gc -g -emit-llvm -o - %s
+// RUN: %clang_cc1 -x objective-c++ -triple i386-apple-darwin9 -fobjc-fragile-abi -fobjc-gc -g -emit-llvm -o - %s
// rdar://7252252
@interface Loop {
diff --git a/test/CodeGenObjC/objc2-weak-ivar.m b/test/CodeGenObjC/objc2-weak-ivar.m
index 8c91a80b6863..78ccdf8876cc 100644
--- a/test/CodeGenObjC/objc2-weak-ivar.m
+++ b/test/CodeGenObjC/objc2-weak-ivar.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
@class NSObject;
@interface Foo {
diff --git a/test/CodeGenObjC/objc2-write-barrier-2.m b/test/CodeGenObjC/objc2-write-barrier-2.m
index 74cd7eafad4f..eae2551aa074 100644
--- a/test/CodeGenObjC/objc2-write-barrier-2.m
+++ b/test/CodeGenObjC/objc2-write-barrier-2.m
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
// RUN: grep -F '@objc_assign_global' %t | count 7
// RUN: grep -F '@objc_assign_ivar' %t | count 5
// RUN: grep -F '@objc_assign_strongCast' %t | count 8
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
// RUN: grep -F '@objc_assign_global' %t | count 7
// RUN: grep -F '@objc_assign_ivar' %t | count 5
// RUN: grep -F '@objc_assign_strongCast' %t | count 8
diff --git a/test/CodeGenObjC/objc2-write-barrier-3.m b/test/CodeGenObjC/objc2-write-barrier-3.m
index cb72cc06e55c..4ef1b8aa1e86 100644
--- a/test/CodeGenObjC/objc2-write-barrier-3.m
+++ b/test/CodeGenObjC/objc2-write-barrier-3.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -fobjc-gc -emit-llvm -o %t %s
// RUN: grep objc_assign_ivar %t | count 3
// RUN: grep objc_assign_strongCast %t | count 6
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fblocks -fobjc-gc -emit-llvm -o %t %s
// RUN: grep objc_assign_ivar %t | count 3
// RUN: grep objc_assign_strongCast %t | count 6
diff --git a/test/CodeGenObjC/objc2-write-barrier-4.m b/test/CodeGenObjC/objc2-write-barrier-4.m
index ab30649bec2b..4089920b0925 100644
--- a/test/CodeGenObjC/objc2-write-barrier-4.m
+++ b/test/CodeGenObjC/objc2-write-barrier-4.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
// RUN: grep objc_assign_global %t | count 3
// RUN: grep objc_assign_strongCast %t | count 2
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
// RUN: grep objc_assign_global %t | count 3
// RUN: grep objc_assign_strongCast %t | count 2
diff --git a/test/CodeGenObjC/objc2-write-barrier-5.m b/test/CodeGenObjC/objc2-write-barrier-5.m
index 373df0cc16b9..122fa9f3c0b7 100644
--- a/test/CodeGenObjC/objc2-write-barrier-5.m
+++ b/test/CodeGenObjC/objc2-write-barrier-5.m
@@ -1,9 +1,9 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
// RUN: grep objc_assign_ivar %t | count 0
-// RUN: grep objc_assign_strongCast %t | count 5
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
+// RUN: grep objc_assign_strongCast %t | count 8
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
// RUN: grep objc_assign_ivar %t | count 0
-// RUN: grep objc_assign_strongCast %t | count 5
+// RUN: grep objc_assign_strongCast %t | count 8
@interface TestUnarchiver
{
@@ -27,3 +27,20 @@ struct unarchive_list {
}
@end
+
+// rdar://10191569
+@interface I
+{
+ struct S {
+ id _timer;
+ } *p_animationState;
+}
+@end
+
+@implementation I
+- (void) Meth {
+ p_animationState->_timer = 0;
+ (*p_animationState)._timer = 0;
+ (&(*p_animationState))->_timer = 0;
+}
+@end
diff --git a/test/CodeGenObjC/objc2-write-barrier.m b/test/CodeGenObjC/objc2-write-barrier.m
index 08b65deaa38d..bf2dfb9b14f9 100644
--- a/test/CodeGenObjC/objc2-write-barrier.m
+++ b/test/CodeGenObjC/objc2-write-barrier.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
// RUN: grep -F '@objc_assign_global' %t | count 21
// RUN: grep -F '@objc_assign_ivar' %t | count 11
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o %t %s
// RUN: grep -F '@objc_assign_global' %t | count 21
// RUN: grep -F '@objc_assign_ivar' %t | count 11
diff --git a/test/CodeGenObjC/object-incr-decr-1.m b/test/CodeGenObjC/object-incr-decr-1.m
index 6369076174b3..19c12cb315a2 100644
--- a/test/CodeGenObjC/object-incr-decr-1.m
+++ b/test/CodeGenObjC/object-incr-decr-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm %s -o %t
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -emit-llvm %s -o %t
@interface Foo
{
diff --git a/test/CodeGenObjC/predefined-expr.m b/test/CodeGenObjC/predefined-expr.m
index 43d329e2ab1d..009bbcdb013c 100644
--- a/test/CodeGenObjC/predefined-expr.m
+++ b/test/CodeGenObjC/predefined-expr.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi %s -emit-llvm -o - | FileCheck %s
// CHECK: @"__func__.-[Foo instanceTest1]" = private unnamed_addr constant [21 x i8] c"-[Foo instanceTest1]\00"
// CHECK: @"__func__.-[Foo instanceTest2:]" = private unnamed_addr constant [22 x i8] c"-[Foo instanceTest2:]\00"
diff --git a/test/CodeGenObjC/property-aggr-type.m b/test/CodeGenObjC/property-aggr-type.m
deleted file mode 100644
index 8ba87de3534a..000000000000
--- a/test/CodeGenObjC/property-aggr-type.m
+++ /dev/null
@@ -1,50 +0,0 @@
-// RUN: %clang_cc1 -emit-llvm -o %t %s
-
-@interface Object
-- (id) new;
-@end
-
-typedef struct {int x, y, w, h;} st1;
-typedef struct {int x, y, w, h;} st2;
-
-@interface bar : Object
-- (void)setFrame:(st1)frameRect;
-@end
-
-@interface bar1 : Object
-- (void)setFrame:(int)frameRect;
-@end
-
-@interface foo : Object
-{
- st2 ivar;
-}
-@property (assign) st2 frame;
-@end
-
-@implementation foo
-@synthesize frame = ivar;
-@end
-
-extern void abort();
-
-static st2 r = {1,2,3,4};
-st2 test (void)
-{
- foo *obj = [foo new];
- id objid = [foo new];;
-
- obj.frame = r;
-
- ((foo*)objid).frame = obj.frame;
-
- return ((foo*)objid).frame;
-}
-
-int main ()
-{
- st2 res = test ();
- if (res.x != 1 || res.h != 4)
- abort();
- return 0;
-}
diff --git a/test/CodeGenObjC/property-aggregate.m b/test/CodeGenObjC/property-aggregate.m
new file mode 100644
index 000000000000..f4211b6b62bd
--- /dev/null
+++ b/test/CodeGenObjC/property-aggregate.m
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm %s -o - | FileCheck %s
+
+// This structure's size is not a power of two, so the property does
+// not get native atomics, even though x86-64 can do unaligned atomics
+// with a lock prefix.
+struct s3 { char c[3]; };
+
+// This structure's size is, so it does, because it can.
+// FIXME: But we don't at the moment; the backend doesn't know how to generate
+// correct code.
+struct s4 { char c[4]; };
+
+@interface Test0
+@property struct s3 s3;
+@property struct s4 s4;
+@end
+@implementation Test0
+@synthesize s3, s4;
+@end
+
+// CHECK: define internal i24 @"\01-[Test0 s3]"(
+// CHECK: call void @objc_copyStruct
+
+// CHECK: define internal void @"\01-[Test0 setS3:]"(
+// CHECK: call void @objc_copyStruct
+
+// CHECK: define internal i32 @"\01-[Test0 s4]"(
+// CHECK: call void @objc_copyStruct
+
+// CHECK: define internal void @"\01-[Test0 setS4:]"(
+// CHECK: call void @objc_copyStruct
diff --git a/test/CodeGenObjC/property-category-impl.m b/test/CodeGenObjC/property-category-impl.m
index 80a18cb1daab..734f9a37a24c 100644
--- a/test/CodeGenObjC/property-category-impl.m
+++ b/test/CodeGenObjC/property-category-impl.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
// rdar : // 8093297
diff --git a/test/CodeGenObjC/property-complex.m b/test/CodeGenObjC/property-complex.m
index 071d0b1d24d2..3cdd2ecfd15d 100644
--- a/test/CodeGenObjC/property-complex.m
+++ b/test/CodeGenObjC/property-complex.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o %t %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o %t %s
@interface I0 {
@public
diff --git a/test/CodeGenObjC/property-list-in-class.m b/test/CodeGenObjC/property-list-in-class.m
index 05210588ba9b..e8014855af7e 100644
--- a/test/CodeGenObjC/property-list-in-class.m
+++ b/test/CodeGenObjC/property-list-in-class.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s
// CHECK: l_OBJC_$_PROP_LIST_C2" = internal global { i32, i32, [3 x %struct._prop_t] } { i32 16, i32 3
@protocol P
diff --git a/test/CodeGenObjC/property-ref-cast-to-void.m b/test/CodeGenObjC/property-ref-cast-to-void.m
index a365aa56e84d..ad1689fd6243 100644
--- a/test/CodeGenObjC/property-ref-cast-to-void.m
+++ b/test/CodeGenObjC/property-ref-cast-to-void.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck %s
// rdar: // 8399655
@interface TestClass
diff --git a/test/CodeGenObjC/property-type-mismatch.m b/test/CodeGenObjC/property-type-mismatch.m
index 7045947b1abf..b920b45aef95 100644
--- a/test/CodeGenObjC/property-type-mismatch.m
+++ b/test/CodeGenObjC/property-type-mismatch.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
// rdar://8966864
@interface Foo
diff --git a/test/CodeGenObjC/property.m b/test/CodeGenObjC/property.m
index dd0786eb30ee..3cc9200f333c 100644
--- a/test/CodeGenObjC/property.m
+++ b/test/CodeGenObjC/property.m
@@ -103,3 +103,12 @@ void test4(Test4 *t) {
// CHECK-NEXT: ret void
test4_printf("%.2f", t.f);
}
+
+@interface Test5 {
+ unsigned _x : 5;
+}
+@property unsigned x;
+@end
+@implementation Test5
+@synthesize x = _x;
+@end
diff --git a/test/CodeGenObjC/protocol-in-extended-class.m b/test/CodeGenObjC/protocol-in-extended-class.m
index daf4d4ccf578..a92408463deb 100644
--- a/test/CodeGenObjC/protocol-in-extended-class.m
+++ b/test/CodeGenObjC/protocol-in-extended-class.m
@@ -1,7 +1,7 @@
// REQUIRES: x86-registered-target,x86-64-registered-target
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -S %s -o %t-64.s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -triple i386-apple-darwin -S %s -o %t-32.s
+// RUN: %clang_cc1 -triple i386-apple-darwin -fobjc-fragile-abi -S %s -o %t-32.s
// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
@protocol MyProtocol
diff --git a/test/CodeGenObjC/protocol-property-synth.m b/test/CodeGenObjC/protocol-property-synth.m
index 8566949e5c94..c998d631677a 100644
--- a/test/CodeGenObjC/protocol-property-synth.m
+++ b/test/CodeGenObjC/protocol-property-synth.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -emit-llvm -o %t %s
+// RUN: %clang_cc1 -emit-llvm -o %t %s
@interface BaseClass {
id _delegate;
diff --git a/test/CodeGenObjC/protocols-lazy.m b/test/CodeGenObjC/protocols-lazy.m
index 2038e60c4e61..1c551fbeec11 100644
--- a/test/CodeGenObjC/protocols-lazy.m
+++ b/test/CodeGenObjC/protocols-lazy.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -triple=i686-apple-darwin8 -o %t %s
+// RUN: %clang_cc1 -emit-llvm -triple i686-apple-darwin8 -fobjc-fragile-abi -o %t %s
// RUNX: llvm-gcc -S -emit-llvm -o %t %s &&
// No object generated
diff --git a/test/CodeGenObjC/rdr-6732143-dangling-block-reference.m b/test/CodeGenObjC/rdr-6732143-dangling-block-reference.m
index fd812dd38823..a93ca033c13c 100644
--- a/test/CodeGenObjC/rdr-6732143-dangling-block-reference.m
+++ b/test/CodeGenObjC/rdr-6732143-dangling-block-reference.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -fobjc-exceptions %s -o -
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-fragile-abi -emit-llvm -fobjc-exceptions %s -o -
void f0(id x) {
@synchronized (x) {
diff --git a/test/CodeGenObjC/simplify-exceptions.mm b/test/CodeGenObjC/simplify-exceptions.mm
index a35b10d73d2d..d0baf808531c 100644
--- a/test/CodeGenObjC/simplify-exceptions.mm
+++ b/test/CodeGenObjC/simplify-exceptions.mm
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm \
-// RUN: -fexceptions -fobjc-exceptions -fobjc-nonfragile-abi \
+// RUN: -fexceptions -fobjc-exceptions \
// RUN: -o %t %s
// RUN: FileCheck < %t %s
//
diff --git a/test/CodeGenObjC/stand-alone-implementation.m b/test/CodeGenObjC/stand-alone-implementation.m
index a51949578b37..8245f01028b9 100644
--- a/test/CodeGenObjC/stand-alone-implementation.m
+++ b/test/CodeGenObjC/stand-alone-implementation.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-X86-64 %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-X86-64 %s
// radar 7547942
// Allow injection of ivars into implementation's implicit class.
diff --git a/test/CodeGenObjC/super-dotsyntax-struct-property.m b/test/CodeGenObjC/super-dotsyntax-struct-property.m
index aac4c1de06a3..a7910a047be8 100644
--- a/test/CodeGenObjC/super-dotsyntax-struct-property.m
+++ b/test/CodeGenObjC/super-dotsyntax-struct-property.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s
// rdar: // 8203426
diff --git a/test/CodeGenObjC/super-message-fragileabi.m b/test/CodeGenObjC/super-message-fragileabi.m
index 5efc234dcafd..0135919b8946 100644
--- a/test/CodeGenObjC/super-message-fragileabi.m
+++ b/test/CodeGenObjC/super-message-fragileabi.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -emit-llvm %s -o - | FileCheck %s
@class Some;
diff --git a/test/CodeGenObjC/synchronized.m b/test/CodeGenObjC/synchronized.m
index 2a809063fe03..4997bb77525e 100644
--- a/test/CodeGenObjC/synchronized.m
+++ b/test/CodeGenObjC/synchronized.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -triple=i686-apple-darwin9 -o - %s -O2 | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -triple i686-apple-darwin9 -fobjc-fragile-abi -o - %s -O2 | FileCheck %s
@interface MyClass
{
diff --git a/test/CodeGenObjC/synthesize_ivar-cont-class.m b/test/CodeGenObjC/synthesize_ivar-cont-class.m
index f85320279bc4..6bc7ac8170ef 100644
--- a/test/CodeGenObjC/synthesize_ivar-cont-class.m
+++ b/test/CodeGenObjC/synthesize_ivar-cont-class.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -emit-llvm -o %t %s
+// RUN: %clang_cc1 -emit-llvm -o %t %s
// RUN: grep '@"OBJC_IVAR_$_XCOrganizerDeviceNodeInfo.viewController"' %t
@interface XCOrganizerNodeInfo
diff --git a/test/CodeGenObjC/synthesize_ivar.m b/test/CodeGenObjC/synthesize_ivar.m
index 5dd90ab618bb..e4fbe101a648 100644
--- a/test/CodeGenObjC/synthesize_ivar.m
+++ b/test/CodeGenObjC/synthesize_ivar.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -emit-llvm -o %t %s
+// RUN: %clang_cc1 -emit-llvm -o %t %s
@interface I
@property int IP;
diff --git a/test/CodeGenObjC/terminate.m b/test/CodeGenObjC/terminate.m
index f04eb6a92bb7..a86205839d45 100644
--- a/test/CodeGenObjC/terminate.m
+++ b/test/CodeGenObjC/terminate.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fexceptions -fobjc-exceptions -fobjc-runtime-has-terminate -o - %s | FileCheck %s -check-prefix=CHECK-WITH
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fexceptions -fobjc-exceptions -o - %s | FileCheck %s -check-prefix=CHECK-WITHOUT
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -fexceptions -fobjc-exceptions -fobjc-runtime-has-terminate -o - %s | FileCheck %s -check-prefix=CHECK-WITH
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -fexceptions -fobjc-exceptions -o - %s | FileCheck %s -check-prefix=CHECK-WITHOUT
void destroy(void**);
@@ -14,8 +14,8 @@ void test0(void) {
// CHECK-WITH: call void @destroy(i8** [[PTR]])
// CHECK-WITH-NEXT: ret void
// CHECK-WITH: invoke void @destroy(i8** [[PTR]])
- // CHECK-WITH: call i8* @llvm.eh.exception()
- // CHECK-WITH-NEXT: @llvm.eh.selector
+ // CHECK-WITH: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gcc_personality_v0 to i8*)
+ // CHECK-WITH-NEXT: catch i8* null
// CHECK-WITH-NEXT: call void @objc_terminate()
// CHECK-WITHOUT: define void @test0()
@@ -23,7 +23,7 @@ void test0(void) {
// CHECK-WITHOUT: call void @destroy(i8** [[PTR]])
// CHECK-WITHOUT-NEXT: ret void
// CHECK-WITHOUT: invoke void @destroy(i8** [[PTR]])
- // CHECK-WITHOUT: call i8* @llvm.eh.exception()
- // CHECK-WITHOUT-NEXT: @llvm.eh.selector
+ // CHECK-WITHOUT: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gcc_personality_v0 to i8*)
+ // CHECK-WITHOUT-NEXT: catch i8* null
// CHECK-WITHOUT-NEXT: call void @abort()
}
diff --git a/test/CodeGenObjC/variadic-sends.m b/test/CodeGenObjC/variadic-sends.m
index 6b04b50ca152..7e557b0178d8 100644
--- a/test/CodeGenObjC/variadic-sends.m
+++ b/test/CodeGenObjC/variadic-sends.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-X86-32 %s
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-X86-64 %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-X86-32 %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-X86-64 %s
@interface A
-(void) im0;
diff --git a/test/CodeGenObjC/x86_64-struct-return-gc.m b/test/CodeGenObjC/x86_64-struct-return-gc.m
index 8022d5903ecf..76407d6654e0 100644
--- a/test/CodeGenObjC/x86_64-struct-return-gc.m
+++ b/test/CodeGenObjC/x86_64-struct-return-gc.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -fobjc-gc -emit-llvm -o - %s | FileCheck %s
struct Coerce {
id a;
};
diff --git a/test/CodeGenObjCXX/2007-10-03-MetadataPointers.mm b/test/CodeGenObjCXX/2007-10-03-MetadataPointers.mm
new file mode 100644
index 000000000000..2564d67ee501
--- /dev/null
+++ b/test/CodeGenObjCXX/2007-10-03-MetadataPointers.mm
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+
+@class NSImage;
+void bork() {
+ NSImage *nsimage;
+ [nsimage release];
+}
diff --git a/test/CodeGenObjCXX/2010-08-04-Template.mm b/test/CodeGenObjCXX/2010-08-04-Template.mm
new file mode 100644
index 000000000000..c53e3cb6da44
--- /dev/null
+++ b/test/CodeGenObjCXX/2010-08-04-Template.mm
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+struct TRunSoon {
+ template <class P1> static void Post() {}
+};
+
+@implementation TPrivsTableViewMainController
+- (void) applyToEnclosed {
+ TRunSoon::Post<int>();
+}
+@end
diff --git a/test/CodeGenObjCXX/2010-08-06-X.Y-syntax.mm b/test/CodeGenObjCXX/2010-08-06-X.Y-syntax.mm
new file mode 100644
index 000000000000..290aaf67bbfd
--- /dev/null
+++ b/test/CodeGenObjCXX/2010-08-06-X.Y-syntax.mm
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -emit-llvm %s -o -
+struct TFENode {
+ TFENode(const TFENode& inNode);
+};
+
+@interface TIconViewController
+- (const TFENode&) target;
+@end
+
+void sortAllChildrenForNode(const TFENode&node);
+
+@implementation TIconViewController
+- (void) setArrangeBy {
+ sortAllChildrenForNode(self.target);
+}
+@end
diff --git a/test/CodeGenObjCXX/arc-globals.mm b/test/CodeGenObjCXX/arc-globals.mm
index 7167dbc366d0..958d1d872c28 100644
--- a/test/CodeGenObjCXX/arc-globals.mm
+++ b/test/CodeGenObjCXX/arc-globals.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
// Test that we're properly retaining lifetime-qualified pointers
// initialized statically and wrapping up those initialization in an
diff --git a/test/CodeGenObjCXX/arc-mangle.mm b/test/CodeGenObjCXX/arc-mangle.mm
index 1955348f1c32..c2b5817c73b3 100644
--- a/test/CodeGenObjCXX/arc-mangle.mm
+++ b/test/CodeGenObjCXX/arc-mangle.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-arc -fobjc-runtime-has-weak -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fobjc-arc -fobjc-runtime-has-weak -emit-llvm -o - %s | FileCheck %s
// CHECK: define void @_Z1fPU8__strongP11objc_object(i8**)
void f(__strong id *) {}
diff --git a/test/CodeGenObjCXX/arc-move.mm b/test/CodeGenObjCXX/arc-move.mm
index 70469e6a8586..cf3051dd1fe6 100644
--- a/test/CodeGenObjCXX/arc-move.mm
+++ b/test/CodeGenObjCXX/arc-move.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -O2 -std=c++0x -disable-llvm-optzns -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -O2 -std=c++11 -disable-llvm-optzns -o - %s | FileCheck %s
// define void @_Z11simple_moveRU8__strongP11objc_objectS2_
void simple_move(__strong id &x, __strong id &y) {
diff --git a/test/CodeGenObjCXX/arc-new-delete.mm b/test/CodeGenObjCXX/arc-new-delete.mm
index 4597985f8dfe..a778bcad8fa7 100644
--- a/test/CodeGenObjCXX/arc-new-delete.mm
+++ b/test/CodeGenObjCXX/arc-new-delete.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-arc -fobjc-runtime-has-weak -fblocks -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fobjc-arc -fobjc-runtime-has-weak -fblocks -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s | FileCheck %s
typedef __strong id strong_id;
typedef __weak id weak_id;
diff --git a/test/CodeGenObjCXX/arc-pseudo-destructors.mm b/test/CodeGenObjCXX/arc-pseudo-destructors.mm
index 4023e90b7dc7..2f8d9e1878bb 100644
--- a/test/CodeGenObjCXX/arc-pseudo-destructors.mm
+++ b/test/CodeGenObjCXX/arc-pseudo-destructors.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-arc -fobjc-runtime-has-weak -fblocks -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fobjc-arc -fobjc-runtime-has-weak -fblocks -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s | FileCheck %s
// CHECK: define void @_Z28test_objc_object_pseudo_dtorPU8__strongP11objc_objectPU6__weakS0_
void test_objc_object_pseudo_dtor(__strong id *ptr, __weak id *wptr) {
diff --git a/test/CodeGenObjCXX/arc-references.mm b/test/CodeGenObjCXX/arc-references.mm
index 3d0313d13ac8..954c02abf23a 100644
--- a/test/CodeGenObjCXX/arc-references.mm
+++ b/test/CodeGenObjCXX/arc-references.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
@interface A
@end
@@ -61,8 +61,9 @@ void sink(__strong A* &&);
// CHECK: define void @_Z5test5RU8__strongP11objc_object
void test5(__strong id &x) {
- // CHECK: [[OBJ_ID:%[a-zA-Z0-9]+]] = call i8* @objc_retain
- // CHECK-NEXT: [[OBJ_A:%[a-zA-Z0-9]+]] = bitcast i8* [[OBJ_ID]] to [[A:%[a-zA-Z0-9]+]]*
+ // CHECK: [[REFTMP:%.*]] = alloca {{%.*}}*, align 8
+ // CHECK: [[OBJ_ID:%.*]] = call i8* @objc_retain(
+ // CHECK-NEXT: [[OBJ_A:%.*]] = bitcast i8* [[OBJ_ID]] to [[A:%[a-zA-Z0-9]+]]*
// CHECK-NEXT: store [[A]]* [[OBJ_A]], [[A]]** [[REFTMP:%[a-zA-Z0-9]+]]
// CHECK-NEXT: call void @_Z4sinkOU8__strongP1A
sink(x);
diff --git a/test/CodeGenObjCXX/arc-returns-inner-reference-ptr.mm b/test/CodeGenObjCXX/arc-returns-inner-reference-ptr.mm
new file mode 100644
index 000000000000..c4ab34ea0e8b
--- /dev/null
+++ b/test/CodeGenObjCXX/arc-returns-inner-reference-ptr.mm
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -o - %s | FileCheck %s
+// rdar://10139365
+
+@interface Test58
+- (char* &) interior __attribute__((objc_returns_inner_pointer));
+- (int&)reference_to_interior_int __attribute__((objc_returns_inner_pointer));
+@end
+
+void foo() {
+ Test58 *ptr;
+ char *c = [(ptr) interior];
+
+ int i = [(ptr) reference_to_interior_int];
+}
+
+// CHECK: [[T0:%.*]] = load {{%.*}} {{%.*}}, align 8
+// CHECK: [[T1:%.*]] = bitcast {{%.*}} [[T0]] to i8*
+// call i8* @objc_retainAutorelease(i8* [[T1]]) nounwind
+// CHECK: [[T2:%.*]] = load {{%.*}} {{%.*}}, align 8
+// CHECK: [[T3:%.*]] = bitcast {{%.*}} [[T2]] to i8*
+// call i8* @objc_retainAutorelease(i8* [[T3]]) nounwind
+
diff --git a/test/CodeGenObjCXX/arc-special-member-functions.mm b/test/CodeGenObjCXX/arc-special-member-functions.mm
index d88a2bd62ffc..421a9fedffac 100644
--- a/test/CodeGenObjCXX/arc-special-member-functions.mm
+++ b/test/CodeGenObjCXX/arc-special-member-functions.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-arc -fblocks -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fobjc-arc -fblocks -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s | FileCheck %s
struct ObjCMember {
id member;
@@ -92,12 +92,16 @@ void test_ObjCBlockMember_copy_assign(ObjCBlockMember m1, ObjCBlockMember m2) {
// Implicitly-generated copy assignment operator for ObjCBlockMember
// CHECK: define linkonce_odr {{%.*}}* @_ZN15ObjCBlockMemberaSERKS_(
-// CHECK: [[T0:%.*]] = call i8* @objc_retainBlock(
-// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i32 (i32)*
-// CHECK-NEXT: [[T2:%.*]] = load {{.*}} [[SLOT:%.*]],
-// CHECK: store
-// CHECK-NEXT: [[T3:%.*]] = bitcast
-// CHECK-NEXT: call void @objc_release(i8* [[T3]])
+// CHECK: [[T0:%.*]] = getelementptr inbounds [[T:%.*]]* {{%.*}}, i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = load i32 (i32)** [[T0]], align 8
+// CHECK-NEXT: [[T2:%.*]] = bitcast i32 (i32)* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retainBlock(i8* [[T2]])
+// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to i32 (i32)*
+// CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[T]]* {{%.*}}, i32 0, i32 0
+// CHECK-NEXT: [[T6:%.*]] = load i32 (i32)** [[T5]], align 8
+// CHECK-NEXT: store i32 (i32)* [[T4]], i32 (i32)** [[T5]]
+// CHECK-NEXT: [[T7:%.*]] = bitcast i32 (i32)* [[T6]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T7]])
// CHECK-NEXT: ret
// Implicitly-generated copy constructor for ObjCBlockMember
diff --git a/test/CodeGenObjCXX/arc.mm b/test/CodeGenObjCXX/arc.mm
index 0c5466a4cea3..8f3aa711d65d 100644
--- a/test/CodeGenObjCXX/arc.mm
+++ b/test/CodeGenObjCXX/arc.mm
@@ -1,4 +1,15 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+
+struct NSFastEnumerationState;
+@interface NSArray
+- (unsigned long) countByEnumeratingWithState: (struct NSFastEnumerationState*) state
+ objects: (id*) buffer
+ count: (unsigned long) bufferSize;
+@end;
+NSArray *nsarray() { return 0; }
+// CHECK: define [[NSARRAY:%.*]]* @_Z7nsarrayv()
+
+void use(id);
// rdar://problem/9315552
// The analogous ObjC testcase test46 in arr.m.
@@ -164,3 +175,37 @@ id test36(id z) {
// CHECK: objc_autoreleaseReturnValue
return z;
}
+
+// Template instantiation side of rdar://problem/9817306
+@interface Test37
+- (NSArray *) array;
+@end
+template <class T> void test37(T *a) {
+ for (id x in a.array) {
+ use(x);
+ }
+}
+extern template void test37<Test37>(Test37 *a);
+template void test37<Test37>(Test37 *a);
+// CHECK: define weak_odr void @_Z6test37I6Test37EvPT_(
+// CHECK-LP64: [[T0:%.*]] = call [[NSARRAY]]* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to [[NSARRAY]]* (i8*, i8*)*)(
+// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[NSARRAY]]* [[T0]] to i8*
+// CHECK-LP64-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-LP64-NEXT: [[COLL:%.*]] = bitcast i8* [[T2]] to [[NSARRAY]]*
+
+// Make sure it's not immediately released before starting the iteration.
+// CHECK-LP64-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+// CHECK-LP64-NEXT: [[T0:%.*]] = bitcast [[NSARRAY]]* [[COLL]] to i8*
+// CHECK-LP64-NEXT: @objc_msgSend
+
+// This bitcast is for the mutation check.
+// CHECK-LP64: [[T0:%.*]] = bitcast [[NSARRAY]]* [[COLL]] to i8*
+// CHECK-LP64-NEXT: @objc_enumerationMutation
+
+// This bitcast is for the 'next' message send.
+// CHECK-LP64: [[T0:%.*]] = bitcast [[NSARRAY]]* [[COLL]] to i8*
+// CHECK-LP64-NEXT: @objc_msgSend
+
+// This bitcast is for the final release.
+// CHECK-LP64: [[T0:%.*]] = bitcast [[NSARRAY]]* [[COLL]] to i8*
+// CHECK-LP64-NEXT: call void @objc_release(i8* [[T0]])
diff --git a/test/CodeGenObjCXX/block-in-template-inst.mm b/test/CodeGenObjCXX/block-in-template-inst.mm
index 72042fc03330..93a0e4907d29 100644
--- a/test/CodeGenObjCXX/block-in-template-inst.mm
+++ b/test/CodeGenObjCXX/block-in-template-inst.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm-only -std=c++0x -fblocks -o - -triple x86_64-apple-darwin10 %s
+// RUN: %clang_cc1 -emit-llvm-only -std=c++11 -fblocks -o - -triple x86_64-apple-darwin10 -fobjc-fragile-abi %s
// rdar://9362021
@class DYFuture;
diff --git a/test/CodeGenObjCXX/block-var-layout.mm b/test/CodeGenObjCXX/block-var-layout.mm
index 363e21497ec7..a8f8be0ea8a3 100644
--- a/test/CodeGenObjCXX/block-var-layout.mm
+++ b/test/CodeGenObjCXX/block-var-layout.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -fblocks -fobjc-gc -triple x86_64-apple-darwin -emit-llvm %s -o %t-64.ll
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fobjc-gc -triple x86_64-apple-darwin -fobjc-fragile-abi -emit-llvm %s -o %t-64.ll
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.ll %s
// See commentary in test/CodeGenObjC/block-var-layout.m, from which
diff --git a/test/CodeGenObjCXX/blocks.mm b/test/CodeGenObjCXX/blocks.mm
index e220753ff788..126931d51fad 100644
--- a/test/CodeGenObjCXX/blocks.mm
+++ b/test/CodeGenObjCXX/blocks.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -fblocks -triple x86_64-apple-darwin %s -verify -emit-llvm -o %t
+// RUN: %clang_cc1 -x objective-c++ -fblocks -triple x86_64-apple-darwin -fobjc-fragile-abi %s -verify -emit-llvm -o %t
// rdar://8979379
@interface A
@@ -30,7 +30,7 @@ void foo(id <NSObject>(^objectCreationBlock)(void)) {
// Test4
struct S {
- S *(^a)() = ^{ // expected-warning {{C++0x}}
+ S *(^a)() = ^{ // expected-warning {{C++11}}
return this;
};
};
@@ -40,7 +40,7 @@ S s;
struct X {
void f() {
^ {
- struct Nested { Nested *ptr = this; }; // expected-warning {{C++0x}}
+ struct Nested { Nested *ptr = this; }; // expected-warning {{C++11}}
} ();
};
};
diff --git a/test/CodeGenObjCXX/catch-id-type.mm b/test/CodeGenObjCXX/catch-id-type.mm
index ece342bb8720..a5fa3e78fb59 100644
--- a/test/CodeGenObjCXX/catch-id-type.mm
+++ b/test/CodeGenObjCXX/catch-id-type.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-macosx10.6.6 -emit-llvm -fobjc-exceptions -fcxx-exceptions -fexceptions -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-apple-macosx10.6.6 -fobjc-fragile-abi -emit-llvm -fobjc-exceptions -fcxx-exceptions -fexceptions -o - %s | FileCheck %s
// rdar://8940528
@interface ns_array
@@ -30,7 +30,10 @@ id FUNC() {
}
catch( id error )
{
- // CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector({{.*}} @__gxx_personality_v0 {{.*}} @_ZTIP4INTF {{.*}} @_ZTIP11objc_object {{.*}} @_ZTIP10objc_class
+ // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ // CHECK-NEXT: catch i8* bitcast ({ i8*, i8*, i32, i8* }* @_ZTIP4INTF to i8*)
+ // CHECK-NEXT: catch i8* bitcast ({ i8*, i8*, i32, i8* }* @_ZTIP11objc_object to i8*)
+ // CHECK-NEXT: catch i8* bitcast ({ i8*, i8*, i32, i8* }* @_ZTIP10objc_class to i8*)
error = error;
groups = [ns_array array];
}
diff --git a/test/CodeGenObjCXX/copy.mm b/test/CodeGenObjCXX/copy.mm
index 133910f25dcf..a61ccd4e5daa 100644
--- a/test/CodeGenObjCXX/copy.mm
+++ b/test/CodeGenObjCXX/copy.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck %s
// rdar://problem/9158302
// This should not use a memmove_collectable in non-GC mode.
@@ -24,3 +24,18 @@ namespace test0 {
}
}
+
+// rdar://9780211
+@protocol bork
+@end
+
+namespace test1 {
+template<typename T> struct RetainPtr {
+ RetainPtr() {}
+};
+
+
+RetainPtr<id<bork> > x;
+RetainPtr<id> y;
+
+}
diff --git a/test/CodeGenObjCXX/copyable-property-object.mm b/test/CodeGenObjCXX/copyable-property-object.mm
index 8962c536ea29..03c0c06a41ee 100644
--- a/test/CodeGenObjCXX/copyable-property-object.mm
+++ b/test/CodeGenObjCXX/copyable-property-object.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck %s
struct POD {
int array[3][4];
diff --git a/test/CodeGenObjCXX/encode.mm b/test/CodeGenObjCXX/encode.mm
index 2c10fbcb9753..8391c04b7da8 100644
--- a/test/CodeGenObjCXX/encode.mm
+++ b/test/CodeGenObjCXX/encode.mm
@@ -105,6 +105,27 @@ namespace rdar9624314 {
const char g2[] = @encode(S2);
}
+namespace test {
+ class Foo {
+ public:
+ virtual void f() {};
+ };
+
+ class Bar {
+ public:
+ virtual void g() {};
+ };
+
+ class Zoo : virtual public Foo, virtual public Bar {
+ public:
+ int x;
+ int y;
+ };
+
+ // CHECK: @_ZN4testL3ecdE = internal constant [15 x i8] c"{Zoo=^^?ii^^?}\00"
+ const char ecd[] = @encode(Zoo);
+}
+
struct Base1 {
char x;
};
@@ -146,3 +167,23 @@ _Alloc_hider _M_dataplus;
// CHECK: @_ZL2g5 = internal constant [32 x i8] c"{basic_string={_Alloc_hider=*}}\00"
const char g5[] = @encode(basic_string);
+
+
+// PR10990
+class CefBase {
+ virtual ~CefBase() {}
+};
+class CefBrowser : public virtual CefBase {};
+class CefBrowserImpl : public CefBrowser {};
+// CHECK: @_ZL2g6 = internal constant [21 x i8] c"{CefBrowserImpl=^^?}\00"
+const char g6[] = @encode(CefBrowserImpl);
+
+// PR10990_2
+class CefBase2 {
+ virtual ~CefBase2() {}
+ int i;
+};
+class CefBrowser2 : public virtual CefBase2 {};
+class CefBrowserImpl2 : public CefBrowser2 {};
+// CHECK: @_ZL2g7 = internal constant [26 x i8] c"{CefBrowserImpl2=^^?^^?i}\00"
+const char g7[] = @encode(CefBrowserImpl2);
diff --git a/test/CodeGenObjCXX/exceptions.mm b/test/CodeGenObjCXX/exceptions.mm
index d4c0756cb89f..ce6d20aa98b6 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 -fobjc-nonfragile-abi -fcxx-exceptions -fexceptions -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions -o - %s | FileCheck %s
@interface OCType @end
void opaque();
@@ -11,7 +11,8 @@ namespace test0 {
// CHECK: invoke void @_Z6opaquev
opaque();
} catch (OCType *T) {
- // CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector({{.*}} @__objc_personality_v0 {{.*}} @"OBJC_EHTYPE_$_OCType"
+ // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
+ // CHECK-NEXT: catch %struct._objc_typeinfo* @"OBJC_EHTYPE_$_OCType"
}
}
}
diff --git a/test/CodeGenObjCXX/gc.mm b/test/CodeGenObjCXX/gc.mm
index aa293dacf3a7..1e9fe00fd060 100644
--- a/test/CodeGenObjCXX/gc.mm
+++ b/test/CodeGenObjCXX/gc.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck %s
namespace test0 {
extern id x;
diff --git a/test/CodeGenObjCXX/implicit-copy-assign-operator.mm b/test/CodeGenObjCXX/implicit-copy-assign-operator.mm
index 16ae1472ddfd..0a6e08e2ff62 100644
--- a/test/CodeGenObjCXX/implicit-copy-assign-operator.mm
+++ b/test/CodeGenObjCXX/implicit-copy-assign-operator.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-gc -emit-llvm -triple x86_64-apple-darwin10.0.0 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fobjc-gc -emit-llvm -triple x86_64-apple-darwin10.0.0 -fobjc-fragile-abi -o - %s | FileCheck %s
struct A {
A &operator=(const A&);
A &operator=(A&);
diff --git a/test/CodeGenObjCXX/implicit-copy-constructor.mm b/test/CodeGenObjCXX/implicit-copy-constructor.mm
index 10eb644ddb22..63dd4f084cd8 100644
--- a/test/CodeGenObjCXX/implicit-copy-constructor.mm
+++ b/test/CodeGenObjCXX/implicit-copy-constructor.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck %s
struct A {
A();
diff --git a/test/CodeGenObjCXX/mangle-blocks.mm b/test/CodeGenObjCXX/mangle-blocks.mm
index 9f57557f8f67..fcbc60860884 100644
--- a/test/CodeGenObjCXX/mangle-blocks.mm
+++ b/test/CodeGenObjCXX/mangle-blocks.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -fblocks -o - -triple x86_64-apple-darwin10 %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -fblocks -o - -triple x86_64-apple-darwin10 -fobjc-fragile-abi %s | FileCheck %s
// CHECK: @_ZGVN3foo20__foo_block_invoke_05valueE = internal global i64 0
diff --git a/test/CodeGenObjCXX/message-reference.mm b/test/CodeGenObjCXX/message-reference.mm
index b7cf98d88c66..fa41fef4c909 100644
--- a/test/CodeGenObjCXX/message-reference.mm
+++ b/test/CodeGenObjCXX/message-reference.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck %s
// rdar://8604515
@interface I {}
diff --git a/test/CodeGenObjCXX/nrvo.mm b/test/CodeGenObjCXX/nrvo.mm
new file mode 100644
index 000000000000..ef5052eea603
--- /dev/null
+++ b/test/CodeGenObjCXX/nrvo.mm
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -emit-llvm -o - -fblocks %s -O1 -triple x86_64-apple-darwin10.0.0 -fobjc-fragile-abi | FileCheck %s
+
+// PR10835 / <rdar://problem/10050178>
+struct X {
+ X();
+ X(const X&);
+ ~X();
+};
+
+@interface NRVO
+@end
+
+@implementation NRVO
+// CHECK: define internal void @"\01-[NRVO getNRVO]"
+- (X)getNRVO {
+ X x;
+ // CHECK: tail call void @_ZN1XC1Ev
+ // CHECK-NEXT: ret void
+ return x;
+}
+@end
+
+X blocksNRVO() {
+ return ^{
+ // CHECK: define internal void @__blocksNRVO_block_invoke_0
+ X x;
+ // CHECK: tail call void @_ZN1XC1Ev
+ // CHECK-NEXT: ret void
+ return x;
+ }() ;
+}
+
diff --git a/test/CodeGenObjCXX/property-derived-to-base-conv.mm b/test/CodeGenObjCXX/property-derived-to-base-conv.mm
index d7c743c69068..ddca857fbab0 100644
--- a/test/CodeGenObjCXX/property-derived-to-base-conv.mm
+++ b/test/CodeGenObjCXX/property-derived-to-base-conv.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin10 -emit-llvm -o - %s
+// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - %s
// rdar: // 7501812
struct A {
diff --git a/test/CodeGenObjCXX/property-dot-copy.mm b/test/CodeGenObjCXX/property-dot-copy.mm
index 9b23c58ca17b..c0ff258e8585 100644
--- a/test/CodeGenObjCXX/property-dot-copy.mm
+++ b/test/CodeGenObjCXX/property-dot-copy.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
// rdar://8427922
struct Vector3D
diff --git a/test/CodeGenObjCXX/property-dot-reference.mm b/test/CodeGenObjCXX/property-dot-reference.mm
index 6b53639f54cb..e64b397cc026 100644
--- a/test/CodeGenObjCXX/property-dot-reference.mm
+++ b/test/CodeGenObjCXX/property-dot-reference.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fexceptions -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fexceptions -o - %s | FileCheck %s
// rdar://8409336
struct TFENode {
diff --git a/test/CodeGenObjCXX/property-object-conditional-exp.mm b/test/CodeGenObjCXX/property-object-conditional-exp.mm
index 5d8a8826355c..281076e47f4d 100644
--- a/test/CodeGenObjCXX/property-object-conditional-exp.mm
+++ b/test/CodeGenObjCXX/property-object-conditional-exp.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck %s
struct CGRect {
char* origin;
diff --git a/test/CodeGenObjCXX/property-object-reference.mm b/test/CodeGenObjCXX/property-object-reference.mm
new file mode 100644
index 000000000000..b87ce2303b5e
--- /dev/null
+++ b/test/CodeGenObjCXX/property-object-reference.mm
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - | FileCheck %s
+// rdar://10188258
+
+struct Foo {int i;};
+
+@interface ObjCTest { }
+@property (nonatomic, readonly) Foo& FooRefProperty;
+@end
+
+
+@implementation ObjCTest
+@dynamic FooRefProperty;
+
+-(void) test {
+ Foo& f = self.FooRefProperty;
+}
+@end
+
+// CHECK: [[T0:%.*]] = load {{%.*}} [[S0:%.*]]
+// CHECK: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+// CHECK: [[T2:%.*]] = bitcast {{%.*}} [[T0]] to i8*
+// CHECK: @objc_msgSend
+
diff --git a/test/CodeGenObjCXX/property-objects.mm b/test/CodeGenObjCXX/property-objects.mm
index 1f4311763595..6dfcc27f1921 100644
--- a/test/CodeGenObjCXX/property-objects.mm
+++ b/test/CodeGenObjCXX/property-objects.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
// CHECK-NOT: callq _objc_msgSend_stret
// CHECK: call void @_ZN1SC1ERKS_
// CHECK: call %class.S* @_ZN1SaSERKS_
diff --git a/test/CodeGenObjCXX/property-reference.mm b/test/CodeGenObjCXX/property-reference.mm
index 7c235cb9b4ef..bc3bb475f5f7 100644
--- a/test/CodeGenObjCXX/property-reference.mm
+++ b/test/CodeGenObjCXX/property-reference.mm
@@ -1,16 +1,14 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - | FileCheck %s
// rdar://9208606
-struct MyStruct
-{
- int x;
- int y;
- int z;
+struct MyStruct {
+ int x;
+ int y;
+ int z;
};
-@interface MyClass
-{
- MyStruct _foo;
+@interface MyClass {
+ MyStruct _foo;
}
@property (assign, readwrite) const MyStruct& foo;
@@ -19,16 +17,38 @@ struct MyStruct
- (void) setFoo:(const MyStruct&)inFoo;
@end
-int main()
-{
- MyClass* myClass;
- MyStruct myStruct;
+void test0() {
+ MyClass* myClass;
+ MyStruct myStruct;
- myClass.foo = myStruct;
+ myClass.foo = myStruct;
- const MyStruct& currentMyStruct = myClass.foo;
- return 0;
+ const MyStruct& currentMyStruct = myClass.foo;
}
// CHECK: [[C:%.*]] = call %struct.MyStruct* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
// CHECK: store %struct.MyStruct* [[C]], %struct.MyStruct** [[D:%.*]]
+
+namespace test1 {
+ struct A { A(); A(const A&); A&operator=(const A&); ~A(); };
+}
+@interface Test1 {
+ test1::A ivar;
+}
+@property const test1::A &prop1;
+@end
+@implementation Test1
+@synthesize prop1 = ivar;
+@end
+// CHECK: define internal [[A:%.*]]* @"\01-[Test1 prop1]"(
+// CHECK: [[SELF:%.*]] = alloca [[TEST1:%.*]]*, align 8
+// CHECK: [[T0:%.*]] = load [[TEST1]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i8* [[T1]], i64 0
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT: ret [[A]]* [[T3]]
+
+// CHECK: define internal void @"\01-[Test1 setProp1:]"(
+// CHECK: call [[A]]* @_ZN5test11AaSERKS0_(
+// CHECK-NEXT: ret void
+
diff --git a/test/CodeGenObjCXX/refence-assign-write-barrier.mm b/test/CodeGenObjCXX/refence-assign-write-barrier.mm
index b295eb25672f..206ecb0c29e3 100644
--- a/test/CodeGenObjCXX/refence-assign-write-barrier.mm
+++ b/test/CodeGenObjCXX/refence-assign-write-barrier.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck %s
// rdar://8681766
@interface NSArray
diff --git a/test/CodeGenObjCXX/selector-expr-lvalue.mm b/test/CodeGenObjCXX/selector-expr-lvalue.mm
index 030545119be4..3e3bf4ecf20e 100644
--- a/test/CodeGenObjCXX/selector-expr-lvalue.mm
+++ b/test/CodeGenObjCXX/selector-expr-lvalue.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - %s
// PR7390
@interface NSObject {}
diff --git a/test/CodeGenObjCXX/write-barrier-global-assign.mm b/test/CodeGenObjCXX/write-barrier-global-assign.mm
index a14804ffe104..cb563f339565 100644
--- a/test/CodeGenObjCXX/write-barrier-global-assign.mm
+++ b/test/CodeGenObjCXX/write-barrier-global-assign.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - %s | FileCheck %s
// rdar://8761767
@class CPDestUser;
diff --git a/test/CodeGenOpenCL/local.cl b/test/CodeGenOpenCL/local.cl
new file mode 100644
index 000000000000..32fa7be0f764
--- /dev/null
+++ b/test/CodeGenOpenCL/local.cl
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -ffake-address-space-map -emit-llvm -o - | FileCheck %s
+
+__kernel void foo(void) {
+ // CHECK: @foo.i = internal addrspace(2)
+ __local int i;
+ ++i;
+}
diff --git a/test/CodeGenOpenCL/ptx-calls.cl b/test/CodeGenOpenCL/ptx-calls.cl
new file mode 100644
index 000000000000..6f336405c301
--- /dev/null
+++ b/test/CodeGenOpenCL/ptx-calls.cl
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -triple ptx32-unknown-unknown -emit-llvm -O0 -o - | FileCheck %s
+
+void device_function() {
+}
+// CHECK: define ptx_device void @device_function()
+
+__kernel void kernel_function() {
+ device_function();
+}
+// CHECK: define ptx_kernel void @kernel_function()
+// CHECK: call ptx_device void @device_function()
+
diff --git a/test/CodeGenOpenCL/ptx-kernels.cl b/test/CodeGenOpenCL/ptx-kernels.cl
new file mode 100644
index 000000000000..4d6fa1084d4b
--- /dev/null
+++ b/test/CodeGenOpenCL/ptx-kernels.cl
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 %s -triple ptx32-unknown-unknown -emit-llvm -o - | FileCheck %s
+
+void device_function() {
+}
+// CHECK: define ptx_device void @device_function()
+
+__kernel void kernel_function() {
+}
+// CHECK: define ptx_kernel void @kernel_function()
+
diff --git a/test/Driver/Inputs/basic_linux_tree/lib/.keep b/test/Driver/Inputs/basic_linux_tree/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_linux_tree/lib/.keep
diff --git a/test/Driver/Inputs/basic_linux_tree/usr/i386-unknown-linux/lib/.keep b/test/Driver/Inputs/basic_linux_tree/usr/i386-unknown-linux/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_linux_tree/usr/i386-unknown-linux/lib/.keep
diff --git a/test/Driver/Inputs/basic_linux_tree/usr/lib/.keep b/test/Driver/Inputs/basic_linux_tree/usr/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_linux_tree/usr/lib/.keep
diff --git a/test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/crtbegin.o b/test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/crtbegin.o
diff --git a/test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbegin.o b/test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbegin.o
diff --git a/test/Driver/Inputs/basic_linux_tree/usr/x86_64-unknown-linux/lib/.keep b/test/Driver/Inputs/basic_linux_tree/usr/x86_64-unknown-linux/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_linux_tree/usr/x86_64-unknown-linux/lib/.keep
diff --git a/test/Driver/Inputs/fake_install_tree/bin/.keep b/test/Driver/Inputs/fake_install_tree/bin/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/fake_install_tree/bin/.keep
diff --git a/test/Driver/Inputs/fake_install_tree/lib/gcc/i386-unknown-linux/4.7.0/crtbegin.o b/test/Driver/Inputs/fake_install_tree/lib/gcc/i386-unknown-linux/4.7.0/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/fake_install_tree/lib/gcc/i386-unknown-linux/4.7.0/crtbegin.o
diff --git a/test/Driver/Inputs/fake_install_tree/lib/gcc/x86_64-unknown-linux/4.5.0/crtbegin.o b/test/Driver/Inputs/fake_install_tree/lib/gcc/x86_64-unknown-linux/4.5.0/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/fake_install_tree/lib/gcc/x86_64-unknown-linux/4.5.0/crtbegin.o
diff --git a/test/Driver/Inputs/gcc_version_parsing1/bin/.keep b/test/Driver/Inputs/gcc_version_parsing1/bin/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/gcc_version_parsing1/bin/.keep
diff --git a/test/Driver/Inputs/gcc_version_parsing1/lib/gcc/i386-unknown-linux/4.7/crtbegin.o b/test/Driver/Inputs/gcc_version_parsing1/lib/gcc/i386-unknown-linux/4.7/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/gcc_version_parsing1/lib/gcc/i386-unknown-linux/4.7/crtbegin.o
diff --git a/test/Driver/Inputs/gcc_version_parsing2/bin/.keep b/test/Driver/Inputs/gcc_version_parsing2/bin/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/gcc_version_parsing2/bin/.keep
diff --git a/test/Driver/Inputs/gcc_version_parsing2/lib/gcc/i386-unknown-linux/4.7.x/crtbegin.o b/test/Driver/Inputs/gcc_version_parsing2/lib/gcc/i386-unknown-linux/4.7.x/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/gcc_version_parsing2/lib/gcc/i386-unknown-linux/4.7.x/crtbegin.o
diff --git a/test/Driver/Inputs/gcc_version_parsing3/bin/.keep b/test/Driver/Inputs/gcc_version_parsing3/bin/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/gcc_version_parsing3/bin/.keep
diff --git a/test/Driver/Inputs/gcc_version_parsing3/lib/gcc/i386-unknown-linux/4.7.99-rc5/crtbegin.o b/test/Driver/Inputs/gcc_version_parsing3/lib/gcc/i386-unknown-linux/4.7.99-rc5/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/gcc_version_parsing3/lib/gcc/i386-unknown-linux/4.7.99-rc5/crtbegin.o
diff --git a/test/Driver/Inputs/multilib_32bit_linux_tree/lib/.keep b/test/Driver/Inputs/multilib_32bit_linux_tree/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_32bit_linux_tree/lib/.keep
diff --git a/test/Driver/Inputs/multilib_32bit_linux_tree/lib32/.keep b/test/Driver/Inputs/multilib_32bit_linux_tree/lib32/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_32bit_linux_tree/lib32/.keep
diff --git a/test/Driver/Inputs/multilib_32bit_linux_tree/lib64/.keep b/test/Driver/Inputs/multilib_32bit_linux_tree/lib64/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_32bit_linux_tree/lib64/.keep
diff --git a/test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/lib/.keep b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/lib/.keep
diff --git a/test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/lib32/.keep b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/lib32/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/lib32/.keep
diff --git a/test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/lib64/.keep b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/lib64/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/i386-unknown-linux/lib64/.keep
diff --git a/test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib/.keep b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib/.keep
diff --git a/test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/64/crtbegin.o b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/64/crtbegin.o
diff --git a/test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/crtbegin.o b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib/gcc/i386-unknown-linux/4.6.0/crtbegin.o
diff --git a/test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib32/.keep b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib32/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib32/.keep
diff --git a/test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib64/.keep b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib64/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_32bit_linux_tree/usr/lib64/.keep
diff --git a/test/Driver/Inputs/multilib_64bit_linux_tree/lib/.keep b/test/Driver/Inputs/multilib_64bit_linux_tree/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_64bit_linux_tree/lib/.keep
diff --git a/test/Driver/Inputs/multilib_64bit_linux_tree/lib32/.keep b/test/Driver/Inputs/multilib_64bit_linux_tree/lib32/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_64bit_linux_tree/lib32/.keep
diff --git a/test/Driver/Inputs/multilib_64bit_linux_tree/lib64/.keep b/test/Driver/Inputs/multilib_64bit_linux_tree/lib64/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_64bit_linux_tree/lib64/.keep
diff --git a/test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib/.keep b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib/.keep
diff --git a/test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/32/crtbegin.o b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/32/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/32/crtbegin.o
diff --git a/test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbegin.o b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbegin.o
diff --git a/test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib32/.keep b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib32/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib32/.keep
diff --git a/test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib64/.keep b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib64/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/lib64/.keep
diff --git a/test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/lib/.keep b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/lib/.keep
diff --git a/test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/lib32/.keep b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/lib32/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/lib32/.keep
diff --git a/test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/lib64/.keep b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/lib64/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multilib_64bit_linux_tree/usr/x86_64-unknown-linux/lib64/.keep
diff --git a/test/Driver/apple-kext-i386.cpp b/test/Driver/apple-kext-i386.cpp
index dc4e6a641f0d..8ce9f87dab38 100644
--- a/test/Driver/apple-kext-i386.cpp
+++ b/test/Driver/apple-kext-i386.cpp
@@ -7,3 +7,36 @@
// CHECK: cc1plus"
// CHECK: "-fapple-kext"
+
+// RUN: %clang -ccc-host-triple i386-apple-darwin10 \
+// RUN: -mkernel -### -fsyntax-only %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-MKERNEL < %t %s
+
+// CHECK-MKERNEL: cc1plus"
+// CHECK-MKERNEL: "-mkernel"
+
+// RUN: %clang -ccc-host-triple i386-apple-darwin10 \
+// RUN: -Wno-self-assign -Wc++0x-extensions -Wno-microsoft -Wmicrosoft -Wvla \
+// RUN: -faltivec -mthumb -mcpu=G4 -mlongcall -mno-longcall -msoft-float \
+// RUN: -fapple-kext -### -fsyntax-only %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED < %t %s
+
+// CHECK-UNSUPPORTED: cc1plus"
+// CHECK-UNSUPPORTED-NOT: "-Wno-self-assign"
+// CHECK-UNSUPPORTED-NOT: "-Wc++0x-extensions"
+// CHECK-UNSUPPORTED-NOT: "-Wno-microsoft"
+// CHECK-UNSUPPORTED-NOT: "-Wmicrosoft"
+// CHECK-UNSUPPORTED-NOT: "-Wvla"
+// CHECK-UNSUPPORTED-NOT: "-faltivec"
+// CHECK-UNSUPPORTED-NOT: "-mthumb"
+// CHECK-UNSUPPORTED-NOT: "-mlongcall"
+// CHECK-UNSUPPORTED: "-mno-longcall"
+// CHECK-UNSUPPORTED: "-msoft-float"
+
+// RUN: %clang -ccc-host-triple i386-apple-darwin10 \
+// RUN: -Wconstant-logical-operand -save-temps \
+// RUN: -fapple-kext -### -fsyntax-only %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED2 < %t %s
+
+// CHECK-UNSUPPORTED2: cc1plus"
+// CHECK-UNSUPPORTED2-NOT: "-Wconstant-logical-operand"
diff --git a/test/Driver/cc-log-diagnostics.c b/test/Driver/cc-log-diagnostics.c
index 6c1b8ed896f1..2fdbe5133c5b 100644
--- a/test/Driver/cc-log-diagnostics.c
+++ b/test/Driver/cc-log-diagnostics.c
@@ -17,7 +17,7 @@ int f0() {}
// CHECK: <key>level</key>
// CHECK: <string>warning</string>
// CHECK: <key>message</key>
-// CHECK: <string>unknown warning option '-Wfoobar'</string>
+// CHECK: <string>unknown warning option &apos;-Wfoobar&apos;</string>
// CHECK: </dict>
// CHECK: <dict>
// CHECK: <key>level</key>
diff --git a/test/Driver/ccc-host-triple-no-integrated-as.c b/test/Driver/ccc-host-triple-no-integrated-as.c
new file mode 100644
index 000000000000..a94dea3a7da2
--- /dev/null
+++ b/test/Driver/ccc-host-triple-no-integrated-as.c
@@ -0,0 +1,17 @@
+// Check that -no-integrated-as works when -ccc-host-triple i386-pc-win32-macho or
+// -ccc-host-triple x86_64-pc-win32-macho is specified.
+
+// RUN: %clang -### -c -ccc-host-triple i386-pc-win32-macho -no-integrated-as %s 2> %t1
+// RUN: FileCheck -check-prefix=X86 < %t1 %s
+// RUN: %clang -### -c -ccc-host-triple x86_64-pc-win32-macho -no-integrated-as %s 2> %t2
+// RUN: FileCheck -check-prefix=X86_64 < %t2 %s
+//
+// X86: "-cc1"
+// X86-NOT: "-cc1as"
+// X86: "-arch"
+// X86: "i386"
+//
+// X86_64: "-cc1"
+// X86_64-NOT: "-cc1as"
+// X86_64: "-arch"
+// X86_64: "x86_64"
diff --git a/test/Driver/cpath.c b/test/Driver/cpath.c
new file mode 100644
index 000000000000..7caa014b2afc
--- /dev/null
+++ b/test/Driver/cpath.c
@@ -0,0 +1,20 @@
+// RUN: mkdir -p %T/test1 %T/test2
+
+// RUN: env CPATH=%T/test1 %clang -x c -E -v %s 2>&1 | FileCheck %s -check-prefix=CPATH
+// CPATH: -I {{.*}}/test1
+// CPATH: search starts here
+// CPATH: test1
+
+// RUN: env OBJC_INCLUDE_PATH=%T/test1 OBJCPLUS_INCLUDE_PATH=%T/test1 CPLUS_INCLUDE_PATH=%T/test1 C_INCLUDE_PATH=%T/test2 %clang -x c -E -v %s 2>&1 | FileCheck %s -check-prefix=C_INCLUDE_PATH
+// C_INCLUDE_PATH: -c-isystem {{"?.*}}/test2{{"?}} -cxx-isystem {{"?.*}}/test1{{"?}} -objc-isystem {{"?.*}}/test1{{"?}} -objcxx-isystem {{"?.*}}/test1{{"?}}
+// C_INCLUDE_PATH: search starts here
+// C_INCLUDE_PATH-NOT: test1
+// C_INCLUDE_PATH: test2
+// C_INCLUDE_PATH-NOT: test1
+
+// RUN: env OBJC_INCLUDE_PATH=%T/test1 OBJCPLUS_INCLUDE_PATH=%T/test2 CPLUS_INCLUDE_PATH=%T/test2 C_INCLUDE_PATH=%T/test1 %clang -x objective-c++ -E -v %s 2>&1 | FileCheck %s -check-prefix=OBJCPLUS_INCLUDE_PATH
+// OBJCPLUS_INCLUDE_PATH: -c-isystem {{"?.*}}/test1{{"?}} -cxx-isystem {{"?.*}}/test2{{"?}} -objc-isystem {{"?.*}}/test1{{"?}} -objcxx-isystem {{"?.*}}/test2{{"?}}
+// OBJCPLUS_INCLUDE_PATH: search starts here
+// OBJCPLUS_INCLUDE_PATH-NOT: test1
+// OBJCPLUS_INCLUDE_PATH: test2
+// OBJCPLUS_INCLUDE_PATH-NOT: test1
diff --git a/test/Driver/darwin-objc-defaults.m b/test/Driver/darwin-objc-defaults.m
index 4cf83a121d19..dc062aea36e9 100644
--- a/test/Driver/darwin-objc-defaults.m
+++ b/test/Driver/darwin-objc-defaults.m
@@ -7,7 +7,7 @@
// RUN: FileCheck --check-prefix CHECK-I386_OSX10_5 < %t %s
// CHECK-CHECK-I386_OSX10_5: "-cc1"
-// CHECK-CHECK-I386_OSX10_5-NOT: -fobjc-nonfragile-abi
+// CHECK-CHECK-I386_OSX10_5: -fobjc-fragile-abi
// CHECK-CHECK-I386_OSX10_5-NOT: -fobjc-dispatch-method
// CHECK-CHECK-I386_OSX10_5: darwin-objc-defaults
@@ -16,7 +16,7 @@
// RUN: FileCheck --check-prefix CHECK-I386_OSX10_6 < %t %s
// CHECK-CHECK-I386_OSX10_6: "-cc1"
-// CHECK-CHECK-I386_OSX10_6-NOT: -fobjc-nonfragile-abi
+// CHECK-CHECK-I386_OSX10_6: -fobjc-fragile-abi
// CHECK-CHECK-I386_OSX10_6-NOT: -fobjc-dispatch-method
// CHECK-CHECK-I386_OSX10_6: darwin-objc-defaults
@@ -25,7 +25,7 @@
// RUN: FileCheck --check-prefix CHECK-I386_IPHONE3_0 < %t %s
// CHECK-CHECK-I386_IPHONE3_0: "-cc1"
-// CHECK-CHECK-I386_IPHONE3_0-NOT: -fobjc-nonfragile-abi
+// CHECK-CHECK-I386_IPHONE3_0: -fobjc-fragile-abi
// CHECK-CHECK-I386_IPHONE3_0-NOT: -fobjc-dispatch-method
// CHECK-CHECK-I386_IPHONE3_0: darwin-objc-defaults
@@ -36,7 +36,7 @@
// RUN: FileCheck --check-prefix CHECK-X86_64_OSX10_5 < %t %s
// CHECK-CHECK-X86_64_OSX10_5: "-cc1"
-// CHECK-CHECK-X86_64_OSX10_5: -fobjc-nonfragile-abi
+// CHECK-CHECK-X86_64_OSX10_5-NOT: -fobjc-fragile-abi
// CHECK-CHECK-X86_64_OSX10_5: -fobjc-dispatch-method=non-legacy
// CHECK-CHECK-X86_64_OSX10_5: darwin-objc-defaults
@@ -45,7 +45,7 @@
// RUN: FileCheck --check-prefix CHECK-X86_64_OSX10_6 < %t %s
// CHECK-CHECK-X86_64_OSX10_6: "-cc1"
-// CHECK-CHECK-X86_64_OSX10_6: -fobjc-nonfragile-abi
+// CHECK-CHECK-X86_64_OSX10_6-NOT: -fobjc-fragile-abi
// CHECK-CHECK-X86_64_OSX10_6: -fobjc-dispatch-method=mixed
// CHECK-CHECK-X86_64_OSX10_6: darwin-objc-defaults
@@ -54,7 +54,7 @@
// RUN: FileCheck --check-prefix CHECK-X86_64_IPHONE3_0 < %t %s
// CHECK-CHECK-X86_64_IPHONE3_0: "-cc1"
-// CHECK-CHECK-X86_64_IPHONE3_0: -fobjc-nonfragile-abi
+// CHECK-CHECK-X86_64_IPHONE3_0-NOT: -fobjc-fragile-abi
// CHECK-CHECK-X86_64_IPHONE3_0: -fobjc-dispatch-method=mixed
// CHECK-CHECK-X86_64_IPHONE3_0: darwin-objc-defaults
@@ -65,7 +65,7 @@
// RUN: FileCheck --check-prefix CHECK-ARMV7_OSX10_5 < %t %s
// CHECK-CHECK-ARMV7_OSX10_5: "-cc1"
-// CHECK-CHECK-ARMV7_OSX10_5: -fobjc-nonfragile-abi
+// CHECK-CHECK-ARMV7_OSX10_5-NOT: -fobjc-fragile-abi
// CHECK-CHECK-ARMV7_OSX10_5-NOT: -fobjc-dispatch-method
// CHECK-CHECK-ARMV7_OSX10_5: darwin-objc-defaults
@@ -74,7 +74,7 @@
// RUN: FileCheck --check-prefix CHECK-ARMV7_OSX10_6 < %t %s
// CHECK-CHECK-ARMV7_OSX10_6: "-cc1"
-// CHECK-CHECK-ARMV7_OSX10_6: -fobjc-nonfragile-abi
+// CHECK-CHECK-ARMV7_OSX10_6-NOT: -fobjc-fragile-abi
// CHECK-CHECK-ARMV7_OSX10_6-NOT: -fobjc-dispatch-method
// CHECK-CHECK-ARMV7_OSX10_6: darwin-objc-defaults
@@ -83,6 +83,6 @@
// RUN: FileCheck --check-prefix CHECK-ARMV7_IPHONE3_0 < %t %s
// CHECK-CHECK-ARMV7_IPHONE3_0: "-cc1"
-// CHECK-CHECK-ARMV7_IPHONE3_0: -fobjc-nonfragile-abi
+// CHECK-CHECK-ARMV7_IPHONE3_0-NOT: -fobjc-fragile-abi
// CHECK-CHECK-ARMV7_IPHONE3_0-NOT: -fobjc-dispatch-method
// CHECK-CHECK-ARMV7_IPHONE3_0: darwin-objc-defaults
diff --git a/test/Driver/darwin-objc-options.m b/test/Driver/darwin-objc-options.m
index 50daa72333e8..a62a62c4fa70 100644
--- a/test/Driver/darwin-objc-options.m
+++ b/test/Driver/darwin-objc-options.m
@@ -5,7 +5,7 @@
// RUN: FileCheck --check-prefix CHECK-X86_64_ABI1 < %t %s
// CHECK-CHECK-X86_64_ABI1: "-cc1"
-// CHECK-CHECK-X86_64_ABI1-NOT: -fobjc-nonfragile-abi
+// CHECK-CHECK-X86_64_ABI1: -fobjc-fragile-abi
// CHECK-CHECK-X86_64_ABI1-NOT: -fobjc-dispatch-method
// CHECK-CHECK-X86_64_ABI1: darwin-objc-options
@@ -14,7 +14,7 @@
// RUN: FileCheck --check-prefix CHECK-I386_ABI2 < %t %s
// CHECK-CHECK-I386_ABI2: "-cc1"
-// CHECK-CHECK-I386_ABI2: -fobjc-nonfragile-abi
+// CHECK-CHECK-I386_ABI2-NOT: -fobjc-fragile-abi
// CHECK-CHECK-I386_ABI2: -fobjc-exceptions
// CHECK-CHECK-I386_ABI2: -fexceptions
// CHECK-CHECK-I386_ABI2-NOT: -fobjc-dispatch-method
diff --git a/test/Driver/darwin-verify-debug.c b/test/Driver/darwin-verify-debug.c
new file mode 100644
index 000000000000..1e4eff8c83f1
--- /dev/null
+++ b/test/Driver/darwin-verify-debug.c
@@ -0,0 +1,34 @@
+// Check that we verify debug output properly with multiple -arch options.
+//
+// REQUIRES: asserts
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -ccc-print-phases \
+// RUN: -verify -arch i386 -arch x86_64 %s -g 2> %t
+// RUN: FileCheck -check-prefix=CHECK-MULTIARCH-ACTIONS < %t %s
+//
+// CHECK-MULTIARCH-ACTIONS: 0: input, "{{.*}}darwin-verify-debug.c", c
+// CHECK-MULTIARCH-ACTIONS: 8: dsymutil, {7}, dSYM
+// CHECK-MULTIARCH-ACTIONS: 9: verify, {8}, none
+//
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -ccc-print-bindings \
+// RUN: -verify -arch i386 -arch x86_64 %s -g 2> %t
+// RUN: FileCheck -check-prefix=CHECK-MULTIARCH-BINDINGS < %t %s
+//
+// CHECK-MULTIARCH-BINDINGS: # "x86_64-apple-darwin10" - "darwin::Dsymutil", inputs: ["a.out"], output: "a.out.dSYM"
+// CHECK-MULTIARCH-BINDINGS: # "x86_64-apple-darwin10" - "darwin::VerifyDebug", inputs: ["a.out.dSYM"], output: (nothing)
+
+// Check output name derivation.
+//
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -ccc-print-bindings \
+// RUN: -verify -o foo %s -g 2> %t
+// RUN: FileCheck -check-prefix=CHECK-OUTPUT-NAME < %t %s
+//
+// CHECK-OUTPUT-NAME: "x86_64-apple-darwin10" - "darwin::Link", inputs: [{{.*}}], output: "foo"
+// CHECK-OUTPUT-NAME: "x86_64-apple-darwin10" - "darwin::Dsymutil", inputs: ["foo"], output: "foo.dSYM"
+// CHECK-OUTPUT-NAME: "x86_64-apple-darwin10" - "darwin::VerifyDebug", inputs: ["foo.dSYM"], output: (nothing)
+
+// Check that we only verify when needed.
+//
+// RUN: touch %t.o
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -ccc-print-bindings \
+// RUN: -verify -o foo %t.o -g 2> %t
+// RUN: grep "Verify" %t | count 0
diff --git a/test/Driver/index-header-map.c b/test/Driver/index-header-map.c
new file mode 100644
index 000000000000..8bd677a0ba98
--- /dev/null
+++ b/test/Driver/index-header-map.c
@@ -0,0 +1,4 @@
+// RUN: %clang -I%S/Before -index-header-map -I%S/Index -I%S/After %s -### 2>> %t.log
+// RUN: FileCheck %s < %t.log
+
+// CHECK: {{-I.*Before.*-index-header-map.*-I.*Index.*-I.*After}}
diff --git a/test/Driver/le32-unknown-nacl.cpp b/test/Driver/le32-unknown-nacl.cpp
new file mode 100644
index 000000000000..bc31802410db
--- /dev/null
+++ b/test/Driver/le32-unknown-nacl.cpp
@@ -0,0 +1,141 @@
+// RUN: %clang -ccc-host-triple le32-unknown-nacl -ccc-clang-archs le32 -ccc-echo %s -emit-llvm-only -c 2>&1 | FileCheck %s -check-prefix=ECHO
+// RUN: %clang -ccc-host-triple le32-unknown-nacl -ccc-clang-archs le32 %s -emit-llvm -S -c -o - | FileCheck %s
+// RUN: %clang -ccc-host-triple le32-unknown-nacl -ccc-clang-archs le32 %s -emit-llvm -S -c -pthread -o - | FileCheck %s -check-prefix=THREADS
+
+// ECHO: {{.*}} -cc1 {{.*}}le32-unknown-nacl.c
+
+// Check platform defines
+#include <stdarg.h>
+#include <stddef.h>
+
+extern "C" {
+
+// CHECK: @align_c = global i32 1
+int align_c = __alignof(char);
+
+// CHECK: @align_s = global i32 2
+int align_s = __alignof(short);
+
+// CHECK: @align_i = global i32 4
+int align_i = __alignof(int);
+
+// CHECK: @align_l = global i32 4
+int align_l = __alignof(long);
+
+// CHECK: @align_ll = global i32 8
+int align_ll = __alignof(long long);
+
+// CHECK: @align_p = global i32 4
+int align_p = __alignof(void*);
+
+// CHECK: @align_f = global i32 4
+int align_f = __alignof(float);
+
+// CHECK: @align_d = global i32 8
+int align_d = __alignof(double);
+
+// CHECK: @align_ld = global i32 8
+int align_ld = __alignof(long double);
+
+// CHECK: @align_vl = global i32 4
+int align_vl = __alignof(va_list);
+
+// CHECK: __native_client__defined
+#ifdef __native_client__
+void __native_client__defined() {}
+#endif
+
+// CHECK: __le32__defined
+#ifdef __le32__
+void __le32__defined() {}
+#endif
+
+// CHECK: __pnacl__defined
+#ifdef __pnacl__
+void __pnacl__defined() {}
+#endif
+
+// CHECK: unixdefined
+#ifdef unix
+void unixdefined() {}
+#endif
+
+// CHECK: __ELF__defined
+#ifdef __ELF__
+void __ELF__defined() {}
+#endif
+
+// CHECK: _GNU_SOURCEdefined
+#ifdef _GNU_SOURCE
+void _GNU_SOURCEdefined() {}
+#endif
+
+// THREADS: _REENTRANTdefined
+// CHECK: _REENTRANTundefined
+#ifdef _REENTRANT
+void _REENTRANTdefined() {}
+#else
+void _REENTRANTundefined() {}
+#endif
+
+// Check types
+
+// CHECK: signext i8 @check_char()
+char check_char() { return 0; }
+
+// CHECK: signext i16 @check_short()
+short check_short() { return 0; }
+
+// CHECK: i32 @check_int()
+int check_int() { return 0; }
+
+// CHECK: i32 @check_long()
+long check_long() { return 0; }
+
+// CHECK: i64 @check_longlong()
+long long check_longlong() { return 0; }
+
+// CHECK: zeroext i8 @check_uchar()
+unsigned char check_uchar() { return 0; }
+
+// CHECK: zeroext i16 @check_ushort()
+unsigned short check_ushort() { return 0; }
+
+// CHECK: i32 @check_uint()
+unsigned int check_uint() { return 0; }
+
+// CHECK: i32 @check_ulong()
+unsigned long check_ulong() { return 0; }
+
+// CHECK: i64 @check_ulonglong()
+unsigned long long check_ulonglong() { return 0; }
+
+// CHECK: i32 @check_size_t()
+size_t check_size_t() { return 0; }
+
+// CHECK: float @check_float()
+float check_float() { return 0; }
+
+// CHECK: double @check_double()
+double check_double() { return 0; }
+
+// CHECK: double @check_longdouble()
+long double check_longdouble() { return 0; }
+
+}
+
+template<int> void Switch();
+template<> void Switch<4>();
+template<> void Switch<8>();
+template<> void Switch<16>();
+
+void check_pointer_size() {
+ // CHECK: SwitchILi4
+ Switch<sizeof(void*)>();
+
+ // CHECK: SwitchILi8
+ Switch<sizeof(long long)>();
+
+ // CHECK: SwitchILi16
+ Switch<sizeof(va_list)>();
+}
diff --git a/test/Driver/linux-ld.c b/test/Driver/linux-ld.c
new file mode 100644
index 000000000000..46fbe7f52dea
--- /dev/null
+++ b/test/Driver/linux-ld.c
@@ -0,0 +1,139 @@
+// General tests that ld invocations on Linux targets sane. Note that we use
+// sysroot to make these tests independent of the host system.
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -ccc-host-triple i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-LD-32 %s
+// 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"
+// CHECK-LD-32: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/lib"
+// CHECK-LD-32: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/../../.."
+// CHECK-LD-32: "-L[[SYSROOT]]/lib"
+// CHECK-LD-32: "-L[[SYSROOT]]/usr/lib"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -ccc-host-triple x86_64-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-LD-64 %s
+// CHECK-LD-64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// 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"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -ccc-host-triple i386-unknown-linux -m32 \
+// RUN: --sysroot=%S/Inputs/multilib_32bit_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-32-TO-32 %s
+// CHECK-32-TO-32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-32-TO-32: "{{.*}}/usr/lib/gcc/i386-unknown-linux/4.6.0/crtbegin.o"
+// CHECK-32-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0"
+// CHECK-32-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/lib/../lib32"
+// CHECK-32-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../lib32"
+// CHECK-32-TO-32: "-L[[SYSROOT]]/lib/../lib32"
+// CHECK-32-TO-32: "-L[[SYSROOT]]/usr/lib/../lib32"
+// CHECK-32-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/lib"
+// CHECK-32-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/../../.."
+// CHECK-32-TO-32: "-L[[SYSROOT]]/lib"
+// CHECK-32-TO-32: "-L[[SYSROOT]]/usr/lib"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -ccc-host-triple i386-unknown-linux -m64 \
+// RUN: --sysroot=%S/Inputs/multilib_32bit_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-32-TO-64 %s
+// CHECK-32-TO-64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-32-TO-64: "{{.*}}/usr/lib/gcc/i386-unknown-linux/4.6.0/64/crtbegin.o"
+// CHECK-32-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/64"
+// CHECK-32-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/lib/../lib64"
+// CHECK-32-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../lib64"
+// CHECK-32-TO-64: "-L[[SYSROOT]]/lib/../lib64"
+// CHECK-32-TO-64: "-L[[SYSROOT]]/usr/lib/../lib64"
+// CHECK-32-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0"
+// CHECK-32-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/../../../../i386-unknown-linux/lib"
+// CHECK-32-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0/../../.."
+// CHECK-32-TO-64: "-L[[SYSROOT]]/lib"
+// CHECK-32-TO-64: "-L[[SYSROOT]]/usr/lib"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -ccc-host-triple x86_64-unknown-linux -m64 \
+// RUN: --sysroot=%S/Inputs/multilib_64bit_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-64-TO-64 %s
+// CHECK-64-TO-64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-64-TO-64: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbegin.o"
+// CHECK-64-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0"
+// CHECK-64-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib/../lib64"
+// CHECK-64-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../lib64"
+// CHECK-64-TO-64: "-L[[SYSROOT]]/lib/../lib64"
+// CHECK-64-TO-64: "-L[[SYSROOT]]/usr/lib/../lib64"
+// CHECK-64-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib"
+// CHECK-64-TO-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../.."
+// CHECK-64-TO-64: "-L[[SYSROOT]]/lib"
+// CHECK-64-TO-64: "-L[[SYSROOT]]/usr/lib"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -ccc-host-triple x86_64-unknown-linux -m32 \
+// RUN: --sysroot=%S/Inputs/multilib_64bit_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-64-TO-32 %s
+// CHECK-64-TO-32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-64-TO-32: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/32/crtbegin.o"
+// CHECK-64-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/32"
+// CHECK-64-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib/../lib32"
+// CHECK-64-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../lib32"
+// CHECK-64-TO-32: "-L[[SYSROOT]]/lib/../lib32"
+// CHECK-64-TO-32: "-L[[SYSROOT]]/usr/lib/../lib32"
+// CHECK-64-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0"
+// CHECK-64-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib"
+// CHECK-64-TO-32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../.."
+// CHECK-64-TO-32: "-L[[SYSROOT]]/lib"
+// CHECK-64-TO-32: "-L[[SYSROOT]]/usr/lib"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -ccc-host-triple i386-unknown-linux -m32 \
+// RUN: -ccc-install-dir %S/Inputs/fake_install_tree/bin \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-INSTALL-DIR-32 %s
+// CHECK-INSTALL-DIR-32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-INSTALL-DIR-32: "{{.*}}/Inputs/fake_install_tree/bin/../lib/gcc/i386-unknown-linux/4.7.0/crtbegin.o"
+// CHECK-INSTALL-DIR-32: "-L{{.*}}/Inputs/fake_install_tree/bin/../lib/gcc/i386-unknown-linux/4.7.0"
+//
+// Check that with 64-bit builds, we don't actually use the install directory
+// as its version of GCC is lower than our sysrooted version.
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -ccc-host-triple x86_64-unknown-linux -m64 \
+// RUN: -ccc-install-dir %S/Inputs/fake_install_tree/bin \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-INSTALL-DIR-64 %s
+// CHECK-INSTALL-DIR-64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-INSTALL-DIR-64: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbegin.o"
+// CHECK-INSTALL-DIR-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0"
+//
+// Check that we support unusual patch version formats, including missing that
+// component.
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -ccc-host-triple i386-unknown-linux -m32 \
+// RUN: -ccc-install-dir %S/Inputs/gcc_version_parsing1/bin \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-GCC-VERSION1 %s
+// CHECK-GCC-VERSION1: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-GCC-VERSION1: "{{.*}}/Inputs/gcc_version_parsing1/bin/../lib/gcc/i386-unknown-linux/4.7/crtbegin.o"
+// CHECK-GCC-VERSION1: "-L{{.*}}/Inputs/gcc_version_parsing1/bin/../lib/gcc/i386-unknown-linux/4.7"
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -ccc-host-triple i386-unknown-linux -m32 \
+// RUN: -ccc-install-dir %S/Inputs/gcc_version_parsing2/bin \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-GCC-VERSION2 %s
+// CHECK-GCC-VERSION2: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-GCC-VERSION2: "{{.*}}/Inputs/gcc_version_parsing2/bin/../lib/gcc/i386-unknown-linux/4.7.x/crtbegin.o"
+// CHECK-GCC-VERSION2: "-L{{.*}}/Inputs/gcc_version_parsing2/bin/../lib/gcc/i386-unknown-linux/4.7.x"
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -ccc-host-triple i386-unknown-linux -m32 \
+// RUN: -ccc-install-dir %S/Inputs/gcc_version_parsing3/bin \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-GCC-VERSION3 %s
+// CHECK-GCC-VERSION3: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-GCC-VERSION3: "{{.*}}/Inputs/gcc_version_parsing3/bin/../lib/gcc/i386-unknown-linux/4.7.99-rc5/crtbegin.o"
+// CHECK-GCC-VERSION3: "-L{{.*}}/Inputs/gcc_version_parsing3/bin/../lib/gcc/i386-unknown-linux/4.7.99-rc5"
diff --git a/test/Driver/mno-global-merge.c b/test/Driver/mno-global-merge.c
new file mode 100644
index 000000000000..b4d8f8757281
--- /dev/null
+++ b/test/Driver/mno-global-merge.c
@@ -0,0 +1,12 @@
+// RUN: %clang -ccc-host-triple armv7-apple-darwin10 \
+// RUN: -mno-global-merge -### -fsyntax-only %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-NGM < %t %s
+
+// CHECK-NGM: "-mno-global-merge"
+
+// RUN: %clang -ccc-host-triple armv7-apple-darwin10 \
+// RUN: -mglobal-merge -### -fsyntax-only %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-GM < %t %s
+
+// CHECK-GM-NOT: "-mglobal-merge"
+
diff --git a/test/Driver/nostdlibinc.c b/test/Driver/nostdlibinc.c
new file mode 100644
index 000000000000..f7ee712d866c
--- /dev/null
+++ b/test/Driver/nostdlibinc.c
@@ -0,0 +1,10 @@
+// RUN: %clang -ccc-host-triple x86_64-unknown-unknown \
+// RUN: -nostdlibinc -ffreestanding -fsyntax-only %s
+
+#if !__has_include("stddef.h")
+#error "expected to be able to find compiler builtin headers!"
+#endif
+
+#if __has_include("stdlib.h")
+#error "expected to *not* be able to find standard C headers"
+#endif
diff --git a/test/Driver/objc++-cpp-output.mm b/test/Driver/objc++-cpp-output.mm
new file mode 100644
index 000000000000..bb8814428ac4
--- /dev/null
+++ b/test/Driver/objc++-cpp-output.mm
@@ -0,0 +1,8 @@
+// RUN: %clang -x objc++-cpp-output -c %s -o /dev/null
+
+// Should compile without errors
+@protocol P
+- (void)m;
+@end
+void f() {}
+class C {};
diff --git a/test/Driver/objc-cpp-output.m b/test/Driver/objc-cpp-output.m
new file mode 100644
index 000000000000..6d974838c150
--- /dev/null
+++ b/test/Driver/objc-cpp-output.m
@@ -0,0 +1,7 @@
+// RUN: %clang -x objc-cpp-output -c %s -o /dev/null
+
+// Should compile without errors
+@protocol P
+- (void)m;
+@end
+void f() {}
diff --git a/test/Driver/rewrite-objc.m b/test/Driver/rewrite-objc.m
index c47b52334c91..80190917c9c2 100644
--- a/test/Driver/rewrite-objc.m
+++ b/test/Driver/rewrite-objc.m
@@ -1,9 +1,9 @@
-// RUN: %clang -ccc-host-triple unknown -rewrite-objc %s -o - -### 2>&1 | \
+// RUN: %clang -ccc-host-triple x86_64-apple-macosx10.7.0 -rewrite-objc %s -o - -### 2>&1 | \
// RUN: FileCheck -check-prefix=TEST0 %s
// TEST0: clang{{.*}}" "-cc1"
// TEST0: "-rewrite-objc"
// FIXME: CHECK-NOT is broken somehow, it doesn't work here. Check adjacency instead.
-// TEST0: "-fmessage-length" "0" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fdiagnostics-show-option"
+// TEST0: "-fmessage-length" "0" "-stack-protector" "1" "-fblocks" "-fobjc-fragile-abi" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fdiagnostics-show-option"
// TEST0: rewrite-objc.m"
// RUN: not %clang -ccc-no-clang -ccc-host-triple unknown -rewrite-objc %s -o - -### 2>&1 | \
diff --git a/test/Driver/std.cpp b/test/Driver/std.cpp
new file mode 100644
index 000000000000..7704c8dda1ea
--- /dev/null
+++ b/test/Driver/std.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang -std=c++98 %s -Wno-c++0x-compat -fsyntax-only 2>&1 | FileCheck -check-prefix=CXX98 %s
+// RUN: %clang -std=gnu++98 %s -Wno-c++0x-compat -fsyntax-only 2>&1 | FileCheck -check-prefix=GNUXX98 %s
+// RUN: %clang -std=c++03 %s -Wno-c++0x-compat -fsyntax-only 2>&1 | FileCheck -check-prefix=CXX98 %s
+// RUN: %clang -std=c++0x %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CXX11 %s
+// RUN: %clang -std=gnu++0x %s -fsyntax-only 2>&1 | FileCheck -check-prefix=GNUXX11 %s
+// RUN: %clang -std=c++11 %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CXX11 %s
+// RUN: %clang -std=gnu++11 %s -fsyntax-only 2>&1 | FileCheck -check-prefix=GNUXX11 %s
+
+void f(int n) {
+ typeof(n)();
+ decltype(n)();
+}
+
+// CXX98: undeclared identifier 'typeof'
+// CXX98: undeclared identifier 'decltype'
+
+// GNUXX98-NOT: undeclared identifier 'typeof'
+// GNUXX98: undeclared identifier 'decltype'
+
+// CXX11: undeclared identifier 'typeof'
+// CXX11-NOT: undeclared identifier 'decltype'
+
+// GNUXX11-NOT: undeclared identifier 'typeof'
+// GNUXX11-NOT: undeclared identifier 'decltype'
diff --git a/test/FixIt/dereference-addressof.c b/test/FixIt/dereference-addressof.c
new file mode 100644
index 000000000000..950fadc83055
--- /dev/null
+++ b/test/FixIt/dereference-addressof.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: cp %s %t
+// RUN: not %clang_cc1 -fsyntax-only -fixit -x c %t
+// RUN: %clang_cc1 -fsyntax-only -pedantic -x c %t
+
+void ip(int *aPtr) {} // expected-note{{passing argument to parameter 'aPtr' here}}
+void i(int a) {} // expected-note{{passing argument to parameter 'a' here}}
+void ii(int a) {} // expected-note{{passing argument to parameter 'a' here}}
+void fp(float *aPtr) {} // expected-note{{passing argument to parameter 'aPtr' here}}
+void f(float a) {} // expected-note{{passing argument to parameter 'a' here}}
+
+void f2(int *aPtr, int a, float *bPtr, char c) {
+ float fl = 0;
+ ip(a); // expected-warning{{incompatible integer to pointer conversion passing 'int' to parameter of type 'int *'; take the address with &}}
+ i(aPtr); // expected-warning{{incompatible pointer to integer conversion passing 'int *' to parameter of type 'int'; dereference with *}}
+ ii(&a); // expected-warning{{incompatible pointer to integer conversion passing 'int *' to parameter of type 'int'; remove &}}
+ fp(*bPtr); // expected-error{{passing 'float' to parameter of incompatible type 'float *'; remove *}}
+ f(bPtr); // expected-error{{passing 'float *' to parameter of incompatible type 'float'; dereference with *}}
+ a = aPtr; // expected-warning{{incompatible pointer to integer conversion assigning to 'int' from 'int *'; dereference with *}}
+ fl = bPtr + a; // expected-error{{assigning to 'float' from incompatible type 'float *'; dereference with *}}
+ bPtr = bPtr[a]; // expected-error{{assigning to 'float *' from incompatible type 'float'; take the address with &}}
+}
diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp
index 77e9e5815c2f..73316457b18f 100644
--- a/test/FixIt/fixit-cxx0x.cpp
+++ b/test/FixIt/fixit-cxx0x.cpp
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -verify -std=c++0x %s
+// RUN: %clang_cc1 -verify -std=c++11 %s
// RUN: cp %s %t
-// RUN: %clang_cc1 -x c++ -std=c++0x -fixit %t || true
-// RUN: %clang_cc1 -Wall -pedantic -x c++ -std=c++0x %t
+// RUN: not %clang_cc1 -x c++ -std=c++11 -fixit %t
+// RUN: %clang_cc1 -Wall -pedantic -x c++ -std=c++11 %t
/* This is a test of the various code modification hints that only
apply in C++0x. */
@@ -17,3 +17,38 @@ void x() {
using ::T = void; // expected-error {{name defined in alias declaration must be an identifier}}
using typename U = void; // expected-error {{name defined in alias declaration must be an identifier}}
using typename ::V = void; // expected-error {{name defined in alias declaration must be an identifier}}
+
+namespace Constexpr {
+ extern constexpr int a; // expected-error {{must be a definition}}
+ // -> extern const int a;
+
+ extern constexpr int *b; // expected-error {{must be a definition}}
+ // -> extern int *const b;
+
+ extern constexpr int &c; // expected-error {{must be a definition}}
+ // -> extern int &b;
+
+ extern constexpr const int d; // expected-error {{must be a definition}}
+ // -> extern const int d;
+
+ int z;
+ constexpr int a = 0;
+ constexpr int *b = &z;
+ constexpr int &c = z;
+ constexpr int d = a;
+
+ // FIXME: Provide FixIts for static data members too.
+#if 0
+ struct S {
+ static constexpr int b; // xpected-error {{requires an initializer}}
+ // -> const int b;
+ };
+
+ constexpr int S::b = 0;
+#endif
+
+ struct S {
+ static char *const p = 0; // expected-error {{requires 'constexpr' specifier}}
+ // -> constexpr static char *const p = 0;
+ };
+}
diff --git a/test/FixIt/fixit-errors.c b/test/FixIt/fixit-errors.c
index f8e2295d496a..356e862ff606 100644
--- a/test/FixIt/fixit-errors.c
+++ b/test/FixIt/fixit-errors.c
@@ -1,5 +1,5 @@
// RUN: cp %s %t
-// RUN: true || %clang_cc1 -pedantic -verify -fixit -x c %t
+// RUN: %clang_cc1 -pedantic -verify -fixit -x c %t
// RUN: %clang_cc1 -pedantic -Werror -x c %t
// XFAIL: *
diff --git a/test/FixIt/fixit-function-call.cpp b/test/FixIt/fixit-function-call.cpp
new file mode 100644
index 000000000000..273e4a41ec8d
--- /dev/null
+++ b/test/FixIt/fixit-function-call.cpp
@@ -0,0 +1,118 @@
+// RUN: not %clang_cc1 -fdiagnostics-parseable-fixits -x c++ %s 2> %t
+// RUN: FileCheck %s < %t
+// PR5941
+// END.
+
+/* Test fixits for * and & mismatch in function arguments.
+ * Since fixits are on the notes, they cannot be applied automatically. */
+
+typedef int intTy;
+typedef int intTy2;
+
+void f0(int *a);
+void f1(double *a);
+void f1(intTy &a);
+
+void f2(intTy2 *a) {
+// CHECK: error: no matching function for call to 'f1
+// CHECK: dereference the argument with *
+// CHECK: void f1(intTy &a);
+// CHECK: fix-it{{.*}}*(
+// CHECK-NEXT: fix-it{{.*}})
+// CHECK: void f1(double *a);
+ f1(a + 1);
+
+// This call cannot be fixed since without resulting in null pointer dereference.
+// CHECK: error: no matching function for call to 'f1
+// CHECK-NOT: dereference the argument with *
+// CHECK-NOT: fix-it
+ f1((int *)0);
+}
+
+void f3(int &a) {
+// CHECK: error: no matching function for call to 'f0
+// CHECK: fix-it{{.*}}&
+ f0(a);
+}
+
+
+void m(int *a, const int *b); // match 2
+void m(double *a, int *b); // no match
+void m(int *a, double *b); // no match
+void m(intTy &a, int *b); // match 1
+
+void mcaller(intTy2 a, int b) {
+// CHECK: error: no matching function for call to 'm
+// CHECK: take the address of the argument with &
+// CHECK: fix-it{{.*}}&
+// CHECK: take the address of the argument with &
+// CHECK: fix-it{{.*}}&
+// CHECK: fix-it{{.*}}&
+ m(a, b);
+
+// This call cannot be fixed because (a + 1) is not an l-value.
+// CHECK: error: no matching function for call to 'm
+// CHECK-NOT: fix-it
+ m(a + 1, b);
+}
+
+// Test derived to base conversions.
+struct A {
+ int xx;
+};
+
+struct B : public A {
+ double y;
+};
+
+class C : A {};
+
+bool br(A &a);
+bool bp(A *a);
+bool dv(B b);
+
+void u(int x);
+void u(const C *x);
+void u(double x);
+
+void dbcaller(A *ptra, B *ptrb, C &c, B &refb) {
+ B b;
+
+// CHECK: error: no matching function for call to 'br
+// CHECK: fix-it{{.*}}*
+ br(ptrb); // good
+
+// CHECK: error: no matching function for call to 'bp
+// CHECK: fix-it{{.*}}&
+ bp(b); // good
+
+// CHECK: error: no matching function for call to 'dv
+// CHECK-NOT: fix-it
+ dv(ptra); // bad: base to derived
+
+// CHECK: error: no matching function for call to 'dv
+// CHECK: remove &
+ dv(&b);
+
+// CHECK: error: no matching function for call to 'bp
+// CHECK: remove *
+ bp(*ptra);
+
+// CHECK: error: no viable overloaded '='
+// CHECK: remove &
+ b = &refb;
+
+// TODO: Test that we do not provide a fixit when inheritance is private.
+// CHECK: error: no matching function for call to 'bp
+// There should not be a fixit here:
+// CHECK: fix-it
+ bp(c);
+
+// CHECK: no matching function for call to 'u'
+// CHECK: candidate function not viable: no known conversion from 'C' to 'const C *' for 1st argument; take the address of the argument with &
+// CHECK: candidate function not viable
+// CHECK: candidate function not viable
+ u(c);
+}
+
+// CHECK: errors generated
diff --git a/test/FixIt/fixit-missing-method-return-type.m b/test/FixIt/fixit-missing-method-return-type.m
new file mode 100644
index 000000000000..027c89572ff9
--- /dev/null
+++ b/test/FixIt/fixit-missing-method-return-type.m
@@ -0,0 +1,24 @@
+// Objective-C recovery
+// RUN: cp %s %t
+// RUN: %clang_cc1 -Wmissing-method-return-type -fixit -x objective-c %t
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Wmissing-method-return-type -Werror -x objective-c %t
+
+// Objective-C++ recovery
+// RUN: cp %s %t
+// RUN: %clang_cc1 -Wmissing-method-return-type -fixit -x objective-c++ %t
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Wmissing-method-return-type -Werror -x objective-c++ %t
+// rdar://9615045
+
+@interface I
+- initWithFoo:(id)foo; // expected-warning {{method has no return type specified; defaults to 'id' [-Wmissing-method-return-type]}}
+- Meth;
+-Meth1;
+@end
+
+@implementation I
+- initWithFoo:(id)foo { return 0; } // expected-warning {{method has no return type specified; defaults to 'id' [-Wmissing-method-return-type]}}
+
+-Meth { return 0;}
+- Meth1 { return 0;}
+@end
+
diff --git a/test/FixIt/fixit-objc-message.m b/test/FixIt/fixit-objc-message.m
index 1fef3cc56d5e..a3680e475ee2 100644
--- a/test/FixIt/fixit-objc-message.m
+++ b/test/FixIt/fixit-objc-message.m
@@ -1,11 +1,11 @@
// Objective-C recovery
// RUN: cp %s %t
-// RUN: %clang_cc1 -pedantic -Wall -fixit -x objective-c %t || true
+// RUN: not %clang_cc1 -pedantic -Wall -fixit -x objective-c %t
// RUN: %clang_cc1 -fsyntax-only -pedantic -Wall -Werror -x objective-c %t
// Objective-C++ recovery
// RUN: cp %s %t
-// RUN: %clang_cc1 -pedantic -Wall -fixit -x objective-c++ %t || true
+// RUN: not %clang_cc1 -pedantic -Wall -fixit -x objective-c++ %t
// RUN: %clang_cc1 -fsyntax-only -pedantic -Wall -Werror -x objective-c++ %t
@interface A
diff --git a/test/FixIt/fixit-objc.m b/test/FixIt/fixit-objc.m
index 2e8bfaea6aa3..df591c792296 100644
--- a/test/FixIt/fixit-objc.m
+++ b/test/FixIt/fixit-objc.m
@@ -53,3 +53,17 @@ int f0(Radar7861841 *a) { return a.x; } // expected-error {{property 'x' not fou
int f1(Radar7861841 *a) { return a->y; } // expected-error {{property 'y' found on object of type 'Radar7861841 *'; did you mean to access it with the "." operator?}}
+
+#define nil ((void*)0)
+#define NULL ((void*)0)
+
+void sentinel(int x, ...) __attribute__((sentinel)); // expected-note{{function has been explicitly marked sentinel here}}
+
+@interface Sentinel
+- (void)sentinel:(int)x, ... __attribute__((sentinel)); // expected-note{{method has been explicitly marked sentinel here}}
+@end
+
+void sentinel_test(Sentinel *a) {
+ sentinel(1, 2, 3); // expected-warning{{missing sentinel in function call}}
+ [a sentinel:1, 2, 3]; // expected-warning{{missing sentinel in method dispatch}}
+}
diff --git a/test/FixIt/fixit-static-object-decl.m b/test/FixIt/fixit-static-object-decl.m
new file mode 100644
index 000000000000..e13900fa786f
--- /dev/null
+++ b/test/FixIt/fixit-static-object-decl.m
@@ -0,0 +1,29 @@
+// Objective-C recovery
+// RUN: cp %s %t
+// RUN: not %clang_cc1 -fixit -x objective-c %t
+// RUN: %clang_cc1 -fsyntax-only -Werror -x objective-c %t
+
+// Objective-C++ recovery
+// RUN: cp %s %t
+// RUN: not %clang_cc1 -fixit -x objective-c++ %t
+// RUN: %clang_cc1 -fsyntax-only -Werror -x objective-c++ %t
+// rdar://9603056
+
+@interface S @end
+
+@interface NSArray
+{
+@public
+ S iS;
+}
++ (id) arrayWithObjects;
+@end
+
+NSArray func() {
+ NSArray P;
+ return P;
+}
+
+int main() {
+ NSArray pluginNames = [NSArray arrayWithObjects];
+}
diff --git a/test/FixIt/fixit.c b/test/FixIt/fixit.c
index ba45cf28e694..5ba0aac4509b 100644
--- a/test/FixIt/fixit.c
+++ b/test/FixIt/fixit.c
@@ -1,7 +1,7 @@
// RUN: cp %s %t
-// RUN: %clang_cc1 -pedantic -fixit -x c %t || true
+// RUN: not %clang_cc1 -pedantic -Wunused-label -fixit -x c %t
// RUN: grep -v CHECK %t > %t2
-// RUN: %clang_cc1 -pedantic -Werror -x c %t
+// RUN: %clang_cc1 -pedantic -Wunused-label -Werror -x c %t
// RUN: FileCheck -input-file=%t2 %t
/* This is a test of the various code modification hints that are
@@ -59,3 +59,14 @@ struct test_struct {
// CHECK: struct test_struct *struct_ptr;
test_struct *struct_ptr; // expected-error {{must use 'struct' tag to refer to type 'test_struct'}}
};
+
+void removeUnusedLabels(char c) {
+ L0 /*removed comment*/: c++;
+ removeUnusedLabels(c);
+ L1:
+ c++;
+ /*preserved comment*/ L2 : c++;
+ LL
+ : c++;
+ c = c + 3; L4: return;
+}
diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp
index ac749859ea05..785b92b2d817 100644
--- a/test/FixIt/fixit.cpp
+++ b/test/FixIt/fixit.cpp
@@ -1,5 +1,5 @@
// RUN: cp %s %t
-// RUN: %clang_cc1 -pedantic -Wall -fixit -x c++ %t || true
+// RUN: not %clang_cc1 -pedantic -Wall -fixit -x c++ %t
// RUN: %clang_cc1 -fsyntax-only -pedantic -Wall -Werror -x c++ %t
/* This is a test of the various code modification hints that are
@@ -96,4 +96,15 @@ void f(){
typename F1<T>:: /*template*/ Iterator<0> Mypos; // expected-error {{use 'template' keyword to treat 'Iterator' as a dependent template name}}
}
+// Tests for &/* fixits radar 7113438.
+class AD {};
+class BD: public AD {};
+
+void test (BD &br) {
+ AD* aPtr;
+ BD b;
+ aPtr = b; // expected-error {{assigning to 'AD *' from incompatible type 'BD'; take the address with &}}
+ aPtr = br; // expected-error {{assigning to 'A *' from incompatible type 'B'; take the address with &}}
+}
+
diff --git a/test/FixIt/typo-crash.cpp b/test/FixIt/typo-crash.cpp
index b156e1b44c45..92d20377e886 100644
--- a/test/FixIt/typo-crash.cpp
+++ b/test/FixIt/typo-crash.cpp
@@ -3,9 +3,10 @@
// FIXME: The diagnostics and recovery here are very, very poor.
// PR10355
-template<typename T> void template_id1() {
- template_id2<> t; // expected-error 2{{use of undeclared identifier 'template_id2'; did you mean 'template_id1'?}} \
- // expected-error{{expected expression}} \
- // expected-error{{use of undeclared identifier 't'}}
+template<typename T> void template_id1() { // expected-note {{'template_id1' declared here}} \
+ // expected-note {{possible target for call}}
+ template_id2<> t; // expected-error {{no template named 'template_id2'; did you mean 'template_id1'?}} \
+ // expected-error {{expected ';' after expression}} \
+ // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} \
+ // expected-error {{use of undeclared identifier 't'}}
}
-
diff --git a/test/FixIt/typo.m b/test/FixIt/typo.m
index ecb207ee3917..a474035021e6 100644
--- a/test/FixIt/typo.m
+++ b/test/FixIt/typo.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -DNON_FIXITS -verify %s
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -DNON_FIXITS -verify %s
// RUN: cp %s %t
-// RUN: not %clang_cc1 -x objective-c -fsyntax-only -fobjc-nonfragile-abi -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fixit %t
-// RUN: %clang_cc1 -x objective-c -fsyntax-only -fobjc-nonfragile-abi -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -pedantic -Werror %t
+// RUN: not %clang_cc1 -x objective-c -fsyntax-only -triple x86_64-apple-darwin10 -fixit %t
+// RUN: %clang_cc1 -x objective-c -fsyntax-only -triple x86_64-apple-darwin10 -pedantic -Werror %t
// RUN: grep "@implementation Sub3" %t
@interface NSString // expected-note 2{{'NSString' declared here}}
diff --git a/test/Frontend/Weverything.c b/test/Frontend/Weverything.c
new file mode 100644
index 000000000000..32f314720b24
--- /dev/null
+++ b/test/Frontend/Weverything.c
@@ -0,0 +1,9 @@
+// Regression check that -pedantic-errors doesn't cause other diagnostics to
+// become errors.
+//
+// RUN: %clang_cc1 -verify -Weverything -pedantic-errors %s
+
+int f0(int, unsigned);
+int f0(int x, unsigned y) {
+ return x < y; // expected-warning {{comparison of integers}}
+}
diff --git a/test/Frontend/diagnostics-option-names.c b/test/Frontend/diagnostics-option-names.c
new file mode 100644
index 000000000000..ed0d2ed8ef9e
--- /dev/null
+++ b/test/Frontend/diagnostics-option-names.c
@@ -0,0 +1,8 @@
+// RUN: not %clang_cc1 -fdiagnostics-show-option -Werror -Weverything %s 2> %t
+// RUN: FileCheck < %t %s
+
+int f0(int, unsigned);
+int f0(int x, unsigned y) {
+// CHECK: comparison of integers of different signs{{.*}} [-Werror,-Wsign-compare]
+ return x < y; // expected-error {{ : 'int' and 'unsigned int' }}
+}
diff --git a/test/Frontend/warning-mapping-1.c b/test/Frontend/warning-mapping-1.c
new file mode 100644
index 000000000000..883dafb1f500
--- /dev/null
+++ b/test/Frontend/warning-mapping-1.c
@@ -0,0 +1,6 @@
+// Check that -w has higher priority than -Werror.
+// RUN: %clang_cc1 -verify -Wsign-compare -Werror -w %s
+
+int f0(int x, unsigned y) {
+ return x < y;
+}
diff --git a/test/Frontend/warning-mapping-2.c b/test/Frontend/warning-mapping-2.c
new file mode 100644
index 000000000000..39ba4997a4fa
--- /dev/null
+++ b/test/Frontend/warning-mapping-2.c
@@ -0,0 +1,5 @@
+// Check that -w has lower priority than -pedantic-errors.
+// RUN: %clang_cc1 -verify -pedantic-errors -w %s
+
+void f0() { f1(); } // expected-error {{implicit declaration of function}}
+
diff --git a/test/Frontend/warning-mapping-3.c b/test/Frontend/warning-mapping-3.c
new file mode 100644
index 000000000000..8c701903f4e8
--- /dev/null
+++ b/test/Frontend/warning-mapping-3.c
@@ -0,0 +1,10 @@
+// Check that -Werror and -Wfatal-error interact properly.
+//
+// Verify mode doesn't work with fatal errors, just use FileCheck here.
+//
+// RUN: not %clang_cc1 -Wunused-function -Werror -Wfatal-errors %s 2> %t.err
+// RUN: FileCheck < %t.err %s
+// CHECK: fatal error: unused function
+// CHECK: 1 error generated
+
+static void f0(void) {} // expected-fatal {{unused function}}
diff --git a/test/Frontend/warning-mapping-4.c b/test/Frontend/warning-mapping-4.c
new file mode 100644
index 000000000000..d8d2769fc535
--- /dev/null
+++ b/test/Frontend/warning-mapping-4.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -verify -Wno-error=sign-compare %s
+// RUN: %clang_cc1 -verify -Wsign-compare -w -Wno-error=sign-compare %s
+
+int f0(int x, unsigned y) {
+ return x < y;
+}
diff --git a/test/Frontend/warning-mapping-5.c b/test/Frontend/warning-mapping-5.c
new file mode 100644
index 000000000000..27d53dc18915
--- /dev/null
+++ b/test/Frontend/warning-mapping-5.c
@@ -0,0 +1,9 @@
+// Check that #pragma diagnostic warning overrides -Werror. This matches GCC's
+// original documentation, but not its earlier implementations.
+//
+// RUN: %clang_cc1 -verify -Werror %s
+
+#pragma clang diagnostic warning "-Wsign-compare"
+int f0(int x, unsigned y) {
+ return x < y; // expected-warning {{comparison of integers}}
+}
diff --git a/test/Headers/wchar_limits.cpp b/test/Headers/wchar_limits.cpp
new file mode 100644
index 000000000000..93a99ad78f2b
--- /dev/null
+++ b/test/Headers/wchar_limits.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -ffreestanding -fsyntax-only -verify %s
+// RUN: %clang_cc1 -ffreestanding -fsyntax-only -verify -fshort-wchar %s
+
+#include <stdint.h>
+
+const bool swchar = (wchar_t)-1 > (wchar_t)0;
+
+int max_test[WCHAR_MAX == (swchar ? -(WCHAR_MIN+1) : (wchar_t)-1)];
+int min_test[WCHAR_MIN == (swchar ? 0 : -WCHAR_MAX-1)];
diff --git a/test/Index/IBOutletCollection.m b/test/Index/IBOutletCollection.m
new file mode 100644
index 000000000000..a95df8694c78
--- /dev/null
+++ b/test/Index/IBOutletCollection.m
@@ -0,0 +1,18 @@
+#define IBOutletCollection(ClassName) __attribute__((iboutletcollection(ClassName)))
+
+@interface Test {
+ IBOutletCollection(Test) Test *anOutletCollection;
+}
+@end
+
+// RUN: c-index-test -cursor-at=%s:4:24 %s | FileCheck -check-prefix=CHECK-CURSOR %s
+// CHECK-CURSOR: ObjCClassRef=Test:3:12
+
+// 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
+// CHECK-TOK: Identifier: "Test" [4:22 - 4:26] ObjCClassRef=Test:3:12
+// CHECK-TOK: Punctuation: ")" [4:26 - 4:27] ObjCIvarDecl=anOutletCollection:4:34 (Definition)
+// 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/preamble_macro_template.h b/test/Index/Inputs/preamble_macro_template.h
new file mode 100644
index 000000000000..18b076d95cfc
--- /dev/null
+++ b/test/Index/Inputs/preamble_macro_template.h
@@ -0,0 +1,6 @@
+#define STATIC_CAST static_cast
+
+template<typename T>
+void foo(T *p) {
+ (void)STATIC_CAST<T*>(0);
+}
diff --git a/test/Index/TestClassDecl.m b/test/Index/TestClassDecl.m
index 2e11191dca63..e94a5c12fa39 100644
--- a/test/Index/TestClassDecl.m
+++ b/test/Index/TestClassDecl.m
@@ -25,7 +25,7 @@ void function(Foo * arg)
// CHECK-scan: [13:15 - 13:18] ObjCClassRef=Foo:10:12
// CHECK-scan: [13:18 - 13:24] ParmDecl=arg:13:21 (Definition)
// CHECK-scan: [13:24 - 14:1] FunctionDecl=function:13:6 (Definition)
-// CHECK-scan: [14:1 - 16:2] UnexposedStmt=
+// CHECK-scan: [14:1 - 16:2] CompoundStmt=
// CHECK-load: TestClassDecl.m:10:12: ObjCInterfaceDecl=Foo:10:12 Extent=[10:1 - 11:5]
// CHECK-load: TestClassDecl.m:13:6: FunctionDecl=function:13:6 (Definition) Extent=[13:1 - 16:2]
diff --git a/test/Index/TestClassForwardDecl.m b/test/Index/TestClassForwardDecl.m
index 8a8314078999..d3d720c2bafa 100644
--- a/test/Index/TestClassForwardDecl.m
+++ b/test/Index/TestClassForwardDecl.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -emit-pch -x objective-c %s -o %t.ast
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -emit-pch -x objective-c %s -o %t.ast
// RUN: c-index-test -test-file-scan %t.ast %s | FileCheck -check-prefix=scan %s
// RUN: c-index-test -test-load-tu %t.ast local | FileCheck -check-prefix=load %s
@@ -20,7 +20,7 @@ void function(Foo * arg)
// CHECK-scan: [10:15 - 10:18] ObjCClassRef=Foo:8:8
// CHECK-scan: [10:18 - 10:24] ParmDecl=arg:10:21 (Definition)
// CHECK-scan: [10:24 - 11:1] FunctionDecl=function:10:6 (Definition)
-// CHECK-scan: [11:1 - 13:2] UnexposedStmt=
+// CHECK: [11:1 - 13:2] CompundStmt=
diff --git a/test/Index/annotate-attribute.cpp b/test/Index/annotate-attribute.cpp
new file mode 100644
index 000000000000..6721371ca754
--- /dev/null
+++ b/test/Index/annotate-attribute.cpp
@@ -0,0 +1,33 @@
+// RUN: c-index-test -test-load-source all %s | FileCheck %s
+
+class Test {
+public:
+ __attribute__((annotate("spiffy_method"))) void aMethod();
+
+public __attribute__((annotate("works"))):
+ void anotherMethod(); // annotation attribute should be propagated.
+
+private __attribute__((annotate("investigations"))):
+ //propagated annotation should have changed from "works" to "investigations"
+ void inlineMethod() {}
+
+protected:
+ // attribute propagation should have stopped here
+ void methodWithoutAttribute();
+};
+
+// CHECK: ClassDecl=Test:3:7 (Definition) Extent=[3:1 - 17:2]
+// CHECK: CXXAccessSpecifier=:4:1 (Definition) Extent=[4:1 - 4:8]
+// CHECK: CXXMethod=aMethod:5:51 Extent=[5:3 - 5:60]
+// CHECK: attribute(annotate)=spiffy_method Extent=[5:18 - 5:43]
+// CHECK: CXXAccessSpecifier=:7:1 (Definition) Extent=[7:1 - 7:43]
+// CHECK: attribute(annotate)=works Extent=[7:23 - 7:40]
+// CHECK: CXXMethod=anotherMethod:8:8 Extent=[8:3 - 8:23]
+// CHECK: attribute(annotate)=works Extent=[7:23 - 7:40]
+// CHECK: CXXAccessSpecifier=:10:1 (Definition) Extent=[10:1 - 10:53]
+// CHECK: attribute(annotate)=investigations Extent=[10:24 - 10:50]
+// CHECK: CXXMethod=inlineMethod:12:8 (Definition) Extent=[12:3 - 12:25]
+// CHECK: attribute(annotate)=investigations Extent=[10:24 - 10:50]
+// CHECK: CompoundStmt= Extent=[12:23 - 12:25]
+// CHECK: CXXAccessSpecifier=:14:1 (Definition) Extent=[14:1 - 14:11]
+// CHECK: CXXMethod=methodWithoutAttribute:16:8 Extent=[16:3 - 16:32]
diff --git a/test/Index/annotate-context-sensitive.cpp b/test/Index/annotate-context-sensitive.cpp
index 151914cde4a4..34e67a2264b1 100644
--- a/test/Index/annotate-context-sensitive.cpp
+++ b/test/Index/annotate-context-sensitive.cpp
@@ -22,7 +22,7 @@ struct Derived2 : Base2 {
// CHECK-OVERRIDE-FINAL: Keyword: "class" [6:1 - 6:6] ClassDecl=Derived:6:7 (Definition)
// CHECK-OVERRIDE-FINAL: Identifier: "Derived" [6:7 - 6:14] ClassDecl=Derived:6:7 (Definition)
-// CHECK-OVERRIDE-FINAL: Keyword: "final" [6:15 - 6:20] ClassDecl=Derived:6:7 (Definition)
+// CHECK-OVERRIDE-FINAL: Keyword: "final" [6:15 - 6:20] attribute(final)=
// CHECK-OVERRIDE-FINAL: Punctuation: ":" [6:21 - 6:22] ClassDecl=Derived:6:7 (Definition)
// 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
@@ -32,8 +32,8 @@ struct Derived2 : Base2 {
// 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]
// CHECK-OVERRIDE-FINAL: Punctuation: ")" [7:18 - 7:19] CXXMethod=f:7:16 (virtual) [Overrides @3:16]
-// CHECK-OVERRIDE-FINAL: Keyword: "override" [7:20 - 7:28] CXXMethod=f:7:16 (virtual) [Overrides @3:16]
-// CHECK-OVERRIDE-FINAL: Keyword: "final" [7:29 - 7:34] CXXMethod=f:7:16 (virtual) [Overrides @3:16]
+// CHECK-OVERRIDE-FINAL: Keyword: "override" [7:20 - 7:28] attribute(override)=
+// CHECK-OVERRIDE-FINAL: Keyword: "final" [7:29 - 7:34] attribute(final)=
// CHECK-OVERRIDE-FINAL: Punctuation: ";" [7:34 - 7:35] ClassDecl=Derived:6:7 (Definition)
// CHECK-OVERRIDE-FINAL: Keyword: "struct" [9:3 - 9:9] StructDecl=final:9:10 (Definition)
// CHECK-OVERRIDE-FINAL: Identifier: "final" [9:10 - 9:15] StructDecl=final:9:10 (Definition)
diff --git a/test/Index/annotate-macro-args.h b/test/Index/annotate-macro-args.h
new file mode 100644
index 000000000000..40ec8dc0b81f
--- /dev/null
+++ b/test/Index/annotate-macro-args.h
@@ -0,0 +1,16 @@
+@interface MyClass
++(void)meth;
+@end
+
+#define MACRO2(x) x
+#define MACRO(x) MACRO2(x)
+
+void test() {
+ MACRO([MyClass meth]);
+}
+
+#define INVOKE(METHOD, CLASS) [CLASS METHOD]
+
+void test2() {
+ INVOKE(meth, MyClass);
+}
diff --git a/test/Index/annotate-macro-args.m b/test/Index/annotate-macro-args.m
new file mode 100644
index 000000000000..6adfb8ded1c5
--- /dev/null
+++ b/test/Index/annotate-macro-args.m
@@ -0,0 +1,23 @@
+// Test without PCH
+// RUN: c-index-test -test-annotate-tokens=%S/annotate-macro-args.h:9:1:10:1 %s -include annotate-macro-args.h | FileCheck -check-prefix=CHECK1 %s
+// RUN: c-index-test -test-annotate-tokens=%S/annotate-macro-args.h:15:1:16:1 %s -include annotate-macro-args.h | FileCheck -check-prefix=CHECK2 %s
+
+// Test with PCH
+// RUN: c-index-test -write-pch %t.pch -x objective-c-header %S/annotate-macro-args.h -Xclang -detailed-preprocessing-record
+// RUN: c-index-test -test-annotate-tokens=%S/annotate-macro-args.h:9:1:10:1 %s -include-pch %t.pch | FileCheck -check-prefix=CHECK1 %s
+// RUN: c-index-test -test-annotate-tokens=%S/annotate-macro-args.h:15:1:16:1 %s -include-pch %t.pch | FileCheck -check-prefix=CHECK2 %s
+
+// CHECK1: Identifier: "MACRO" [9:3 - 9:8] macro expansion=MACRO:6:9
+// CHECK1: Punctuation: "(" [9:8 - 9:9]
+// CHECK1: Punctuation: "[" [9:9 - 9:10] ObjCMessageExpr=meth:2:1
+// CHECK1: Identifier: "MyClass" [9:10 - 9:17] ObjCClassRef=MyClass:1:12
+// CHECK1: Identifier: "meth" [9:18 - 9:22] ObjCMessageExpr=meth:2:1
+// CHECK1: Punctuation: "]" [9:22 - 9:23] ObjCMessageExpr=meth:2:1
+// CHECK1: Punctuation: ")" [9:23 - 9:24]
+
+// CHECK2: Identifier: "INVOKE" [15:3 - 15:9] macro expansion=INVOKE:12:9
+// CHECK2: Punctuation: "(" [15:9 - 15:10]
+// CHECK2: Identifier: "meth" [15:10 - 15:14] ObjCMessageExpr=meth:2:1
+// CHECK2: Punctuation: "," [15:14 - 15:15]
+// CHECK2: Identifier: "MyClass" [15:16 - 15:23] ObjCClassRef=MyClass:1:12
+// CHECK2: Punctuation: ")" [15:23 - 15:24]
diff --git a/test/Index/annotate-nested-name-specifier.cpp b/test/Index/annotate-nested-name-specifier.cpp
index 7c83740f0888..c4f60e399216 100644
--- a/test/Index/annotate-nested-name-specifier.cpp
+++ b/test/Index/annotate-nested-name-specifier.cpp
@@ -137,7 +137,7 @@ struct X9 : X8 {
}
};
-// RUN: c-index-test -test-annotate-tokens=%s:13:1:137:1 %s | FileCheck %s
+// RUN: c-index-test -test-annotate-tokens=%s:13:1:137:1 -fno-delayed-template-parsing %s | FileCheck %s
// CHECK: Keyword: "using" [14:1 - 14:6] UsingDeclaration=vector[4:12]
// CHECK: Identifier: "outer_alias" [14:7 - 14:18] NamespaceRef=outer_alias:10:11
@@ -200,7 +200,7 @@ struct X9 : X8 {
// CHECK: Punctuation: "::" [35:30 - 35:32] VarDecl=max_size:35:32 (Definition)
// CHECK: Identifier: "max_size" [35:32 - 35:40] VarDecl=max_size:35:32 (Definition)
// CHECK: Punctuation: "=" [35:41 - 35:42] VarDecl=max_size:35:32 (Definition)
-// CHECK: Literal: "17" [35:43 - 35:45] UnexposedExpr=
+// CHECK: Literal: "17" [35:43 - 35:45] IntegerLiteral=
// CHECK: Punctuation: ";" [35:45 - 35:46]
// CHECK: Keyword: "using" [40:3 - 40:8] UsingDeclaration=iterator:40:46
@@ -250,56 +250,56 @@ struct X9 : X8 {
// Pseudo-destructor
// CHECK: Identifier: "t" [57:5 - 57:6] DeclRefExpr=t:56:13
-// CHECK: Punctuation: "->" [57:6 - 57:8] UnexposedExpr=
-// CHECK: Punctuation: "::" [57:8 - 57:10] UnexposedExpr=
+// CHECK: Punctuation: "->" [57:6 - 57:8] MemberRefExpr=
+// CHECK: Punctuation: "::" [57:8 - 57:10] MemberRefExpr=
// CHECK: Identifier: "outer_alias" [57:10 - 57:21] NamespaceRef=outer_alias:10:11
-// CHECK: Punctuation: "::" [57:21 - 57:23] UnexposedExpr=
+// CHECK: Punctuation: "::" [57:21 - 57:23] MemberRefExpr=
// CHECK: Identifier: "inner" [57:23 - 57:28] NamespaceRef=inner:45:13
-// CHECK: Punctuation: "::" [57:28 - 57:30] UnexposedExpr=
-// CHECK: Keyword: "template" [57:30 - 57:38] UnexposedExpr=
+// CHECK: Punctuation: "::" [57:28 - 57:30] MemberRefExpr=
+// CHECK: Keyword: "template" [57:30 - 57:38] MemberRefExpr=
// CHECK: Identifier: "vector" [57:39 - 57:45] TemplateRef=vector:4:12
-// CHECK: Punctuation: "<" [57:45 - 57:46] UnexposedExpr=
+// CHECK: Punctuation: "<" [57:45 - 57:46] MemberRefExpr=
// CHECK: Identifier: "T" [57:46 - 57:47] TypeRef=T:54:19
-// CHECK: Punctuation: ">" [57:47 - 57:48] UnexposedExpr=
-// CHECK: Punctuation: "::" [57:48 - 57:50] UnexposedExpr=
-// CHECK: Punctuation: "~" [57:50 - 57:51] UnexposedExpr=
+// CHECK: Punctuation: ">" [57:47 - 57:48] MemberRefExpr=
+// CHECK: Punctuation: "::" [57:48 - 57:50] MemberRefExpr=
+// CHECK: Punctuation: "~" [57:50 - 57:51] MemberRefExpr=
// CHECK: Identifier: "vector" [57:51 - 57:57] TemplateRef=vector:4:12
-// CHECK: Punctuation: "<" [57:57 - 57:58] UnexposedExpr=
+// CHECK: Punctuation: "<" [57:57 - 57:58] MemberRefExpr=
// CHECK: Identifier: "T" [57:58 - 57:59] TypeRef=T:54:19
// CHECK: Punctuation: ">" [57:59 - 57:60] CallExpr=
// CHECK: Punctuation: "(" [57:60 - 57:61] CallExpr=
// CHECK: Punctuation: ")" [57:61 - 57:62] CallExpr=
// Unresolved member and non-member references
-// CHECK: Punctuation: "::" [75:5 - 75:7] UnexposedExpr=[63:10, 64:10]
+// CHECK: Punctuation: "::" [75:5 - 75:7] DeclRefExpr=[63:10, 64:10]
// CHECK: Identifier: "outer_alias" [75:7 - 75:18] NamespaceRef=outer_alias:10:11
-// CHECK: Punctuation: "::" [75:18 - 75:20] UnexposedExpr=[63:10, 64:10]
+// CHECK: Punctuation: "::" [75:18 - 75:20] DeclRefExpr=[63:10, 64:10]
// CHECK: Identifier: "inner" [75:20 - 75:25] NamespaceRef=inner:62:13
-// CHECK: Punctuation: "::" [75:25 - 75:27] UnexposedExpr=[63:10, 64:10]
+// CHECK: Punctuation: "::" [75:25 - 75:27] DeclRefExpr=[63:10, 64:10]
// CHECK: Identifier: "f" [75:27 - 75:28] OverloadedDeclRef=f[63:10, 64:10]
// CHECK: Punctuation: "(" [75:28 - 75:29] CallExpr=
// CHECK: Identifier: "t" [75:29 - 75:30] DeclRefExpr=t:74:12
// CHECK: Punctuation: ")" [75:30 - 75:31] CallExpr=
-// CHECK: Punctuation: "::" [76:5 - 76:7] UnexposedExpr=[71:8, 72:8]
+// CHECK: Punctuation: "::" [76:5 - 76:7] MemberRefExpr=[71:8, 72:8]
// CHECK: Identifier: "X4" [76:7 - 76:9] TemplateRef=X4:69:8
-// CHECK: Punctuation: "<" [76:9 - 76:10] UnexposedExpr=[71:8, 72:8]
+// CHECK: Punctuation: "<" [76:9 - 76:10] MemberRefExpr=[71:8, 72:8]
// CHECK: Identifier: "type" [76:10 - 76:14] TypeRef=type:70:13
-// CHECK: Punctuation: ">" [76:14 - 76:15] UnexposedExpr=[71:8, 72:8]
-// CHECK: Punctuation: "::" [76:15 - 76:17] UnexposedExpr=[71:8, 72:8]
+// CHECK: Punctuation: ">" [76:14 - 76:15] MemberRefExpr=[71:8, 72:8]
+// CHECK: Punctuation: "::" [76:15 - 76:17] MemberRefExpr=[71:8, 72:8]
// CHECK: Identifier: "g" [76:17 - 76:18] OverloadedDeclRef=g[71:8, 72:8]
// CHECK: Punctuation: "(" [76:18 - 76:19] CallExpr=
// CHECK: Identifier: "t" [76:19 - 76:20] DeclRefExpr=t:74:12
// CHECK: Punctuation: ")" [76:20 - 76:21] CallExpr=
-// CHECK: Punctuation: ";" [76:21 - 76:22] UnexposedStmt=
-// CHECK: Keyword: "this" [77:5 - 77:9] UnexposedExpr=
-// CHECK: Punctuation: "->" [77:9 - 77:11] UnexposedExpr=
-// CHECK: Punctuation: "::" [77:11 - 77:13] UnexposedExpr=
+// CHECK: Punctuation: ";" [76:21 - 76:22] CompoundStmt=
+// CHECK: Keyword: "this" [77:5 - 77:9] CXXThisExpr=
+// CHECK: Punctuation: "->" [77:9 - 77:11] MemberRefExpr=
+// CHECK: Punctuation: "::" [77:11 - 77:13] MemberRefExpr=
// CHECK: Identifier: "X4" [77:13 - 77:15] TemplateRef=X4:69:8
-// CHECK: Punctuation: "<" [77:15 - 77:16] UnexposedExpr=
+// CHECK: Punctuation: "<" [77:15 - 77:16] MemberRefExpr=
// CHECK: Identifier: "type" [77:16 - 77:20] TypeRef=type:70:13
-// CHECK: Punctuation: ">" [77:20 - 77:21] UnexposedExpr=
-// CHECK: Punctuation: "::" [77:21 - 77:23] UnexposedExpr=
-// CHECK: Identifier: "g" [77:23 - 77:24] UnexposedExpr=
+// CHECK: Punctuation: ">" [77:20 - 77:21] MemberRefExpr=
+// CHECK: Punctuation: "::" [77:21 - 77:23] MemberRefExpr=
+// CHECK: Identifier: "g" [77:23 - 77:24] MemberRefExpr=
// CHECK: Punctuation: "(" [77:24 - 77:25] CallExpr=
// CHECK: Identifier: "t" [77:25 - 77:26] DeclRefExpr=t:74:12
// CHECK: Punctuation: ")" [77:26 - 77:27] CallExpr=
@@ -314,7 +314,7 @@ struct X9 : X8 {
// CHECK: Punctuation: "(" [90:28 - 90:29] CallExpr=f:63:10
// CHECK: Identifier: "t" [90:29 - 90:30] DeclRefExpr=t:89:15
// CHECK: Punctuation: ")" [90:30 - 90:31] CallExpr=f:63:10
-// CHECK: Punctuation: ";" [90:31 - 90:32] UnexposedStmt=
+// CHECK: Punctuation: ";" [90:31 - 90:32] CompoundStmt=
// CHECK: Punctuation: "::" [91:5 - 91:7] MemberRefExpr=g:86:8
// CHECK: Identifier: "X4" [91:7 - 91:9] TemplateRef=X4:69:8
// CHECK: Punctuation: "<" [91:9 - 91:10] MemberRefExpr=g:86:8
@@ -325,8 +325,8 @@ struct X9 : X8 {
// CHECK: Punctuation: "(" [91:18 - 91:19] CallExpr=g:86:8
// CHECK: Identifier: "t" [91:19 - 91:20] DeclRefExpr=t:89:15
// CHECK: Punctuation: ")" [91:20 - 91:21] CallExpr=g:86:8
-// CHECK: Punctuation: ";" [91:21 - 91:22] UnexposedStmt=
-// CHECK: Keyword: "this" [92:5 - 92:9] UnexposedExpr=
+// CHECK: Punctuation: ";" [91:21 - 91:22] CompoundStmt=
+// CHECK: Keyword: "this" [92:5 - 92:9] CXXThisExpr=
// CHECK: Punctuation: "->" [92:9 - 92:11] MemberRefExpr=g:86:8
// CHECK: Punctuation: "::" [92:11 - 92:13] MemberRefExpr=g:86:8
// CHECK: Identifier: "X4" [92:13 - 92:15] TemplateRef=X4:69:8
diff --git a/test/Index/annotate-tokens-cxx0x.cpp b/test/Index/annotate-tokens-cxx0x.cpp
index 5dea3514c2b8..89876b28eab3 100644
--- a/test/Index/annotate-tokens-cxx0x.cpp
+++ b/test/Index/annotate-tokens-cxx0x.cpp
@@ -3,6 +3,14 @@ int f(Args ...args) {
return sizeof...(args) + sizeof...(Args);
}
-// RUN: c-index-test -test-annotate-tokens=%s:1:1:5:1 -std=c++0x %s | FileCheck %s
-// CHECK: Identifier: "args" [3:20 - 3:24] UnexposedExpr=args:2:15
+void test() {
+ int a;
+ decltype(a) b;
+}
+
+// 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
+
+// RUN: c-index-test -test-annotate-tokens=%s:8:1:9:1 -std=c++11 %s | FileCheck -check-prefix=CHECK-DECLTYPE %s
+// CHECK-DECLTYPE: Identifier: "a" [8:12 - 8:13] DeclRefExpr=a:7:7
diff --git a/test/Index/annotate-tokens-pp.c b/test/Index/annotate-tokens-pp.c
index e6bb0869d0b1..45988270f0e6 100644
--- a/test/Index/annotate-tokens-pp.c
+++ b/test/Index/annotate-tokens-pp.c
@@ -28,7 +28,10 @@ void test() {
#include "pragma-once.h"
#include "guarded.h"
-// RUN: c-index-test -test-annotate-tokens=%s:2:1:30:1 -I%S/Inputs %s | FileCheck %s
+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
// 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
@@ -101,45 +104,47 @@ void test() {
// CHECK: Identifier: "test_macro_args" [13:6 - 13:21] FunctionDecl=test_macro_args:13:6 (Definition)
// CHECK: Punctuation: "(" [13:21 - 13:22] FunctionDecl=test_macro_args:13:6 (Definition)
// CHECK: Punctuation: ")" [13:22 - 13:23] FunctionDecl=test_macro_args:13:6 (Definition)
-// CHECK: Punctuation: "{" [13:24 - 13:25] UnexposedStmt=
+// CHECK: Punctuation: "{" [13:24 - 13:25] CompoundStmt=
// CHECK: Keyword: "int" [14:3 - 14:6] VarDecl=z:14:7 (Definition)
// CHECK: Identifier: "z" [14:7 - 14:8] VarDecl=z:14:7 (Definition)
// CHECK: Punctuation: "=" [14:9 - 14:10] VarDecl=z:14:7 (Definition)
-// CHECK: Literal: "1" [14:11 - 14:12] UnexposedExpr=
-// CHECK: Punctuation: ";" [14:12 - 14:13] UnexposedStmt=
+// CHECK: Literal: "1" [14:11 - 14:12] IntegerLiteral=
+// CHECK: Punctuation: ";" [14:12 - 14:13] DeclStmt=
// CHECK: Keyword: "int" [15:3 - 15:6] VarDecl=t:15:7 (Definition)
// CHECK: Identifier: "t" [15:7 - 15:8] VarDecl=t:15:7 (Definition)
// CHECK: Punctuation: "=" [15:9 - 15:10] VarDecl=t:15:7 (Definition)
-// CHECK: Literal: "2" [15:11 - 15:12] UnexposedExpr=
-// CHECK: Punctuation: ";" [15:12 - 15:13] UnexposedStmt=
+// CHECK: Literal: "2" [15:11 - 15:12] IntegerLiteral=
+// CHECK: Punctuation: ";" [15:12 - 15:13] DeclStmt=
// CHECK: Keyword: "int" [16:3 - 16:6] VarDecl=k:16:7 (Definition)
// CHECK: Identifier: "k" [16:7 - 16:8] VarDecl=k:16:7 (Definition)
// CHECK: Punctuation: "=" [16:9 - 16:10] VarDecl=k:16:7 (Definition)
// CHECK: Identifier: "REVERSE_MACRO" [16:11 - 16:24] macro expansion=REVERSE_MACRO:10:9
-// CHECK: Punctuation: "(" [16:24 - 16:25] UnexposedStmt=
+// CHECK: Punctuation: "(" [16:24 - 16:25]
// CHECK: Identifier: "t" [16:25 - 16:26] DeclRefExpr=t:15:7
-// CHECK: Punctuation: "," [16:26 - 16:27] UnexposedStmt=
+// CHECK: Punctuation: "," [16:26 - 16:27]
// CHECK: Identifier: "z" [16:27 - 16:28] DeclRefExpr=z:14:7
-// CHECK: Punctuation: ")" [16:28 - 16:29] UnexposedStmt=
-// CHECK: Punctuation: ";" [16:29 - 16:30] UnexposedStmt=
+// FIXME: The token below should really be annotated as "macro expansion=REVERSE_MACRO:10:9"
+// CHECK: Punctuation: ")" [16:28 - 16:29] VarDecl=k:16:7 (Definition)
+// CHECK: Punctuation: ";" [16:29 - 16:30] DeclStmt=
// CHECK: Keyword: "int" [17:3 - 17:6] VarDecl=j:17:7 (Definition)
// CHECK: Identifier: "j" [17:7 - 17:8] VarDecl=j:17:7 (Definition)
// CHECK: Punctuation: "=" [17:9 - 17:10] VarDecl=j:17:7 (Definition)
// CHECK: Identifier: "TWICE_MACRO" [17:11 - 17:22] macro expansion=TWICE_MACRO:11:9
-// CHECK: Punctuation: "(" [17:22 - 17:23] UnexposedStmt=
+// CHECK: Punctuation: "(" [17:22 - 17:23]
// CHECK: Identifier: "k" [17:23 - 17:24] DeclRefExpr=k:16:7
-// CHECK: Punctuation: "+" [17:25 - 17:26] UnexposedStmt=
+// CHECK: Punctuation: "+" [17:25 - 17:26] BinaryOperator=
// CHECK: Identifier: "k" [17:27 - 17:28] DeclRefExpr=k:16:7
-// CHECK: Punctuation: ")" [17:28 - 17:29] UnexposedStmt=
-// CHECK: Punctuation: ";" [17:29 - 17:30] UnexposedStmt=
+// FIXME: The token below should really be annotated as "macro expansion=TWICE_MACRO:11:9"
+// CHECK: Punctuation: ")" [17:28 - 17:29] VarDecl=j:17:7 (Definition)
+// CHECK: Punctuation: ";" [17:29 - 17:30] DeclStmt=
// CHECK: Keyword: "int" [18:3 - 18:6] VarDecl=w:18:7 (Definition)
// CHECK: Identifier: "w" [18:7 - 18:8] VarDecl=w:18:7 (Definition)
// CHECK: Punctuation: "=" [18:9 - 18:10] VarDecl=w:18:7 (Definition)
// CHECK: Identifier: "j" [18:11 - 18:12] DeclRefExpr=j:17:7
-// CHECK: Punctuation: "+" [18:13 - 18:14] UnexposedExpr=
+// CHECK: Punctuation: "+" [18:13 - 18:14] BinaryOperator=
// CHECK: Identifier: "j" [18:15 - 18:16] DeclRefExpr=j:17:7
-// CHECK: Punctuation: ";" [18:16 - 18:17] UnexposedStmt=
-// CHECK: Punctuation: "}" [19:1 - 19:2] UnexposedStmt=
+// CHECK: Punctuation: ";" [18:16 - 18:17] DeclStmt=
+// CHECK: Punctuation: "}" [19:1 - 19:2] CompoundStmt=
// CHECK: Punctuation: "#" [21:1 - 21:2] preprocessing directive=
// CHECK: Identifier: "define" [21:2 - 21:8] preprocessing directive=
// CHECK: Identifier: "fun_with_macro_bodies" [21:9 - 21:30] macro definition=fun_with_macro_bodies
@@ -164,28 +169,29 @@ void test() {
// CHECK: Identifier: "test" [23:6 - 23:10] FunctionDecl=test:23:6 (Definition)
// CHECK: Punctuation: "(" [23:10 - 23:11] FunctionDecl=test:23:6 (Definition)
// CHECK: Punctuation: ")" [23:11 - 23:12] FunctionDecl=test:23:6 (Definition)
-// CHECK: Punctuation: "{" [23:13 - 23:14] UnexposedStmt=
+// CHECK: Punctuation: "{" [23:13 - 23:14] CompoundStmt=
// CHECK: Keyword: "int" [24:3 - 24:6] VarDecl=x:24:7 (Definition)
// CHECK: Identifier: "x" [24:7 - 24:8] VarDecl=x:24:7 (Definition)
// CHECK: Punctuation: "=" [24:9 - 24:10] VarDecl=x:24:7 (Definition)
-// CHECK: Literal: "10" [24:11 - 24:13] UnexposedExpr=
-// CHECK: Punctuation: ";" [24:13 - 24:14] UnexposedStmt=
+// CHECK: Literal: "10" [24:11 - 24:13] IntegerLiteral=
+// CHECK: Punctuation: ";" [24:13 - 24:14] DeclStmt=
// CHECK: Identifier: "fun_with_macro_bodies" [25:3 - 25:24] macro expansion=fun_with_macro_bodies:21:9
-// CHECK: Punctuation: "(" [25:24 - 25:25] UnexposedStmt=
+// CHECK: Punctuation: "(" [25:24 - 25:25] CompoundStmt=
// CHECK: Identifier: "x" [25:25 - 25:26] DeclRefExpr=x:24:7
-// CHECK: Punctuation: "," [25:26 - 25:27] UnexposedStmt=
-// CHECK: Punctuation: "{" [25:28 - 25:29] UnexposedStmt=
-// CHECK: Keyword: "int" [25:30 - 25:33] UnexposedStmt=
+// CHECK: Punctuation: "," [25:26 - 25:27]
+// CHECK: Punctuation: "{" [25:28 - 25:29] CompoundStmt=
+// CHECK: Keyword: "int" [25:30 - 25:33] DeclStmt=
// CHECK: Identifier: "z" [25:34 - 25:35] VarDecl=z:25:34 (Definition)
-// CHECK: Punctuation: "=" [25:36 - 25:37] UnexposedStmt=
+// CHECK: Punctuation: "=" [25:36 - 25:37] VarDecl=z:25:34 (Definition)
// CHECK: Identifier: "x" [25:38 - 25:39] DeclRefExpr=x:24:7
-// CHECK: Punctuation: ";" [25:39 - 25:40] UnexposedStmt=
-// CHECK: Punctuation: "++" [25:41 - 25:43] UnexposedExpr=
+// CHECK: Punctuation: ";" [25:39 - 25:40] DeclStmt=
+// CHECK: Punctuation: "++" [25:41 - 25:43] UnaryOperator=
// CHECK: Identifier: "z" [25:43 - 25:44] DeclRefExpr=z:25:3
-// CHECK: Punctuation: ";" [25:44 - 25:45] UnexposedStmt=
-// CHECK: Punctuation: "}" [25:46 - 25:47] UnexposedStmt=
-// CHECK: Punctuation: ")" [25:47 - 25:48] UnexposedStmt=
-// CHECK: Punctuation: ";" [25:48 - 25:49] UnexposedStmt=
-// CHECK: Punctuation: "}" [26:1 - 26:2] UnexposedStmt=
+// CHECK: Punctuation: ";" [25:44 - 25:45] CompoundStmt=
+// CHECK: Punctuation: "}" [25:46 - 25:47] CompoundStmt=
+// CHECK: Punctuation: ")" [25:47 - 25:48] DoStmt=
+// CHECK: Punctuation: ";" [25:48 - 25:49] CompoundStmt=
+// CHECK: Punctuation: "}" [26:1 - 26:2] CompoundStmt=
// 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__
diff --git a/test/Index/annotate-tokens-preamble.c b/test/Index/annotate-tokens-preamble.c
new file mode 100644
index 000000000000..aa222bdee32d
--- /dev/null
+++ b/test/Index/annotate-tokens-preamble.c
@@ -0,0 +1,20 @@
+// A comment line.
+
+void f(void *ptr) {
+}
+
+
+// RUN: c-index-test -test-annotate-tokens=%s:1:1:5:1 %s | FileCheck %s
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-annotate-tokens=%s:1:1:5:1 %s | FileCheck %s
+// CHECK: Comment: "// A comment line." [1:1 - 1:19]
+// CHECK: Keyword: "void" [3:1 - 3:5] FunctionDecl=f:3:6 (Definition)
+// CHECK: Identifier: "f" [3:6 - 3:7] FunctionDecl=f:3:6 (Definition)
+// CHECK: Punctuation: "(" [3:7 - 3:8] FunctionDecl=f:3:6 (Definition)
+// CHECK: Keyword: "void" [3:8 - 3:12] ParmDecl=ptr:3:14 (Definition)
+// CHECK: Punctuation: "*" [3:13 - 3:14] ParmDecl=ptr:3:14 (Definition)
+// CHECK: Identifier: "ptr" [3:14 - 3:17] ParmDecl=ptr:3:14 (Definition)
+// CHECK: Punctuation: ")" [3:17 - 3:18] FunctionDecl=f:3:6 (Definition)
+// CHECK: Punctuation: "{" [3:19 - 3:20] CompoundStmt=
+// CHECK: Punctuation: "}" [4:1 - 4:2] CompoundStmt=
+
+
diff --git a/test/Index/annotate-tokens-with-default-args.cpp b/test/Index/annotate-tokens-with-default-args.cpp
new file mode 100644
index 000000000000..d5ca7066e15c
--- /dev/null
+++ b/test/Index/annotate-tokens-with-default-args.cpp
@@ -0,0 +1,16 @@
+#include "annotate-tokens-with-default-args.h"
+
+void Foo::m(Foo *f) {}
+
+// RUN: c-index-test -test-annotate-tokens=%s:3:1:4:1 %s | FileCheck %s
+// CHECK: Keyword: "void" [3:1 - 3:5] CXXMethod=m:3:11 (Definition)
+// CHECK: Identifier: "Foo" [3:6 - 3:9] TypeRef=struct Foo:1:8
+// CHECK: Punctuation: "::" [3:9 - 3:11] CXXMethod=m:3:11 (Definition)
+// CHECK: Identifier: "m" [3:11 - 3:12] CXXMethod=m:3:11 (Definition)
+// CHECK: Punctuation: "(" [3:12 - 3:13] CXXMethod=m:3:11 (Definition)
+// CHECK: Identifier: "Foo" [3:13 - 3:16] TypeRef=struct Foo:1:8
+// CHECK: Punctuation: "*" [3:17 - 3:18] ParmDecl=f:3:18 (Definition)
+// CHECK: Identifier: "f" [3:18 - 3:19] ParmDecl=f:3:18 (Definition)
+// CHECK: Punctuation: ")" [3:19 - 3:20] CXXMethod=m:3:11 (Definition)
+// CHECK: Punctuation: "{" [3:21 - 3:22] CompoundStmt=
+// CHECK: Punctuation: "}" [3:22 - 3:23] CompoundStmt=
diff --git a/test/Index/annotate-tokens-with-default-args.h b/test/Index/annotate-tokens-with-default-args.h
new file mode 100644
index 000000000000..323c519351ff
--- /dev/null
+++ b/test/Index/annotate-tokens-with-default-args.h
@@ -0,0 +1,3 @@
+struct Foo {
+ void m(Foo *f = 0);
+};
diff --git a/test/Index/annotate-tokens.c b/test/Index/annotate-tokens.c
index 162a224ed684..0b5f3d477366 100644
--- a/test/Index/annotate-tokens.c
+++ b/test/Index/annotate-tokens.c
@@ -38,35 +38,32 @@ enum Color g(int i, ...) {
// 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)
// CHECK: Punctuation: "=" [4:12 - 4:13] VarDecl=t_ptr:4:6 (Definition)
-// CHECK: Punctuation: "(" [4:14 - 4:15] UnexposedExpr=ptr:3:14
+// CHECK: Punctuation: "(" [4:14 - 4:15] CStyleCastExpr=
// CHECK: Identifier: "T" [4:15 - 4:16] TypeRef=T:1:13
-// CHECK: Punctuation: "*" [4:17 - 4:18] UnexposedExpr=ptr:3:14
-// CHECK: Punctuation: ")" [4:18 - 4:19] UnexposedExpr=ptr:3:14
// CHECK: Identifier: "ptr" [4:19 - 4:22] DeclRefExpr=ptr:3:14
-// CHECK: Punctuation: ";" [4:22 - 4:23] UnexposedStmt=
-// CHECK: Punctuation: "(" [5:3 - 5:4] UnexposedExpr=
-// CHECK: Keyword: "void" [5:4 - 5:8] UnexposedExpr=
-// CHECK: Punctuation: ")" [5:8 - 5:9] UnexposedExpr=
+// CHECK: Punctuation: ";" [4:22 - 4:23] DeclStmt=
+// CHECK: Punctuation: "(" [5:3 - 5:4] CStyleCastExpr=
+// CHECK: Keyword: "void" [5:4 - 5:8] CStyleCastExpr=
+// CHECK: Punctuation: ")" [5:8 - 5:9] CStyleCastExpr=
// CHECK: Keyword: "sizeof" [5:9 - 5:15] UnexposedExpr=
// CHECK: Punctuation: "(" [5:15 - 5:16] UnexposedExpr=
// CHECK: Identifier: "T" [5:16 - 5:17] TypeRef=T:1:13
// CHECK: Punctuation: ")" [5:17 - 5:18] UnexposedExpr=
-// CHECK: Punctuation: ";" [5:18 - 5:19] UnexposedStmt=
-// CHECK: Comment: "/* A comment */" [6:3 - 6:18] UnexposedStmt=
+// CHECK: Punctuation: ";" [5:18 - 5:19] CompoundStmt=
// CHECK: Keyword: "struct" [7:3 - 7:9] VarDecl=x:7:12 (Definition)
// CHECK: Identifier: "X" [7:10 - 7:11] TypeRef=struct X:2:8
// CHECK: Identifier: "x" [7:12 - 7:13] VarDecl=x:7:12 (Definition)
// CHECK: Punctuation: "=" [7:14 - 7:15] VarDecl=x:7:12 (Definition)
-// CHECK: Punctuation: "(" [7:16 - 7:17] UnexposedExpr=
-// CHECK: Keyword: "struct" [7:17 - 7:23] UnexposedExpr=
+// CHECK: Punctuation: "(" [7:16 - 7:17] CompoundLiteralExpr=
+// CHECK: Keyword: "struct" [7:17 - 7:23] CompoundLiteralExpr=
// CHECK: Identifier: "X" [7:24 - 7:25] TypeRef=struct X:2:8
-// CHECK: Punctuation: ")" [7:25 - 7:26] UnexposedExpr=
-// CHECK: Punctuation: "{" [7:26 - 7:27] UnexposedExpr=
-// CHECK: Literal: "1" [7:27 - 7:28] UnexposedExpr=
-// CHECK: Punctuation: "," [7:28 - 7:29] UnexposedExpr=
-// CHECK: Literal: "2" [7:30 - 7:31] UnexposedExpr=
-// CHECK: Punctuation: "}" [7:31 - 7:32] UnexposedExpr=
-// CHECK: Punctuation: ";" [7:32 - 7:33] UnexposedStmt=
+// CHECK: Punctuation: ")" [7:25 - 7:26] CompoundLiteralExpr=
+// CHECK: Punctuation: "{" [7:26 - 7:27] InitListExpr=
+// CHECK: Literal: "1" [7:27 - 7:28] IntegerLiteral=
+// CHECK: Punctuation: "," [7:28 - 7:29] InitListExpr=
+// CHECK: Literal: "2" [7:30 - 7:31] IntegerLiteral=
+// CHECK: Punctuation: "}" [7:31 - 7:32] InitListExpr=
+// CHECK: Punctuation: ";" [7:32 - 7:33] DeclStmt=
// CHECK: Keyword: "void" [8:3 - 8:7] VarDecl=xx:8:9 (Definition)
// CHECK: Punctuation: "*" [8:8 - 8:9] VarDecl=xx:8:9 (Definition)
// CHECK: Identifier: "xx" [8:9 - 8:11] VarDecl=xx:8:9 (Definition)
@@ -74,17 +71,17 @@ enum Color g(int i, ...) {
// CHECK: Identifier: "ptr" [8:14 - 8:17] DeclRefExpr=ptr:3:14
// CHECK: Punctuation: "?" [8:18 - 8:19] UnexposedExpr=
// CHECK: Punctuation: ":" [8:20 - 8:21] UnexposedExpr=
-// CHECK: Punctuation: "&" [8:22 - 8:23] UnexposedExpr=
+// CHECK: Punctuation: "&" [8:22 - 8:23] UnaryOperator=
// CHECK: Identifier: "x" [8:23 - 8:24] DeclRefExpr=x:7:12
-// CHECK: Punctuation: ";" [8:24 - 8:25] UnexposedStmt=
-// CHECK: Keyword: "const" [9:3 - 9:8] UnexposedStmt=
+// CHECK: Punctuation: ";" [8:24 - 8:25] DeclStmt=
+// CHECK: Keyword: "const" [9:3 - 9:8] DeclStmt=
// 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)
// CHECK: Punctuation: "=" [9:22 - 9:23] VarDecl=hello:9:16 (Definition)
-// CHECK: Literal: ""Hello"" [9:24 - 9:31] UnexposedExpr=
-// CHECK: Punctuation: ";" [9:31 - 9:32] UnexposedStmt=
-// CHECK: Punctuation: "}" [10:1 - 10:2] UnexposedStmt=
+// CHECK: Literal: ""Hello"" [9:24 - 9:31] StringLiteral=
+// CHECK: Punctuation: ";" [9:31 - 9:32] DeclStmt=
+// CHECK: Punctuation: "}" [10:1 - 10:2] CompoundStmt=
// CHECK: Keyword: "__builtin_va_arg" [15:9 - 15:25] UnexposedExpr=
// CHECK: Identifier: "Int" [15:30 - 15:33] TypeRef=Int:12:13
// CHECK: Keyword: "__builtin_types_compatible_p" [16:9 - 16:37] UnexposedExpr=
@@ -94,15 +91,15 @@ enum Color g(int i, ...) {
// CHECK: Keyword: "struct" [18:3 - 18:9] VarDecl=x:18:12 (Definition)
// CHECK: Identifier: "X" [18:10 - 18:11] TypeRef=struct X:2:8
// CHECK: Identifier: "x" [18:12 - 18:13] VarDecl=x:18:12 (Definition)
-// CHECK: Keyword: "do" [19:3 - 19:5] UnexposedStmt=
+// CHECK: Keyword: "do" [19:3 - 19:5] DoStmt=
// CHECK: Identifier: "x" [20:5 - 20:6] DeclRefExpr=x:18:12
// CHECK: Punctuation: "." [20:6 - 20:7] MemberRefExpr=a:2:16
// CHECK: Identifier: "a" [20:7 - 20:8] MemberRefExpr=a:2:16
-// CHECK: Punctuation: "++" [20:8 - 20:10] UnexposedExpr=
-// CHECK: Punctuation: ";" [20:10 - 20:11] UnexposedStmt=
-// CHECK: Punctuation: "}" [21:3 - 21:4] UnexposedStmt=
-// CHECK: Keyword: "while" [21:5 - 21:10] UnexposedStmt=
-// CHECK: Punctuation: "(" [21:11 - 21:12] UnexposedStmt=
+// CHECK: Punctuation: "++" [20:8 - 20:10] UnaryOperator=
+// CHECK: Punctuation: ";" [20:10 - 20:11] CompoundStmt=
+// CHECK: Punctuation: "}" [21:3 - 21:4] CompoundStmt=
+// CHECK: Keyword: "while" [21:5 - 21:10] DoStmt=
+// CHECK: Punctuation: "(" [21:11 - 21:12] DoStmt=
// CHECK: Identifier: "x" [21:12 - 21:13] DeclRefExpr=x:18:12
// CHECK: Punctuation: "." [21:13 - 21:14] MemberRefExpr=a:2:16
// CHECK: Identifier: "a" [21:14 - 21:15] MemberRefExpr=a:2:16
@@ -110,30 +107,30 @@ enum Color g(int i, ...) {
// CHECK: Keyword: "enum" [23:3 - 23:7] VarDecl=c:23:14 (Definition)
// CHECK: Identifier: "Color" [23:8 - 23:13] TypeRef=enum Color:11:6
// CHECK: Identifier: "c" [23:14 - 23:15] VarDecl=c:23:14 (Definition)
-// CHECK: Punctuation: ";" [23:15 - 23:16] UnexposedStmt=
-// CHECK: Keyword: "switch" [24:3 - 24:9] UnexposedStmt=
-// CHECK: Punctuation: "(" [24:10 - 24:11] UnexposedStmt=
+// CHECK: Punctuation: ";" [23:15 - 23:16] DeclStmt=
+// CHECK: Keyword: "switch" [24:3 - 24:9] SwitchStmt=
+// CHECK: Punctuation: "(" [24:10 - 24:11] SwitchStmt=
// CHECK: Identifier: "c" [24:11 - 24:12] DeclRefExpr=c:23:14
-// CHECK: Punctuation: ")" [24:12 - 24:13] UnexposedStmt=
-// CHECK: Punctuation: "{" [24:14 - 24:15] UnexposedStmt=
-// CHECK: Keyword: "case" [25:3 - 25:7] UnexposedStmt=
+// CHECK: Punctuation: ")" [24:12 - 24:13] SwitchStmt=
+// CHECK: Punctuation: "{" [24:14 - 24:15] CompoundStmt=
+// CHECK: Keyword: "case" [25:3 - 25:7] CaseStmt=
// CHECK: Identifier: "Red" [25:8 - 25:11] DeclRefExpr=Red:11:14
-// CHECK: Punctuation: ":" [25:11 - 25:12] UnexposedStmt=
-// CHECK: Keyword: "return" [26:5 - 26:11] UnexposedStmt=
+// CHECK: Punctuation: ":" [25:11 - 25:12] CaseStmt=
+// CHECK: Keyword: "return" [26:5 - 26:11] ReturnStmt=
// CHECK: Identifier: "Green" [26:12 - 26:17] DeclRefExpr=Green:11:19
-// CHECK: Punctuation: ";" [26:17 - 26:18] UnexposedStmt=
-// CHECK: Keyword: "case" [28:3 - 28:7] UnexposedStmt=
+// CHECK: Punctuation: ";" [26:17 - 26:18] CompoundStmt=
+// CHECK: Keyword: "case" [28:3 - 28:7] CaseStmt=
// CHECK: Identifier: "Green" [28:8 - 28:13] DeclRefExpr=Green:11:19
-// CHECK: Punctuation: ":" [28:13 - 28:14] UnexposedStmt=
-// CHECK: Keyword: "return" [29:5 - 29:11] UnexposedStmt=
+// CHECK: Punctuation: ":" [28:13 - 28:14] CaseStmt=
+// CHECK: Keyword: "return" [29:5 - 29:11] ReturnStmt=
// CHECK: Identifier: "Blue" [29:12 - 29:16] DeclRefExpr=Blue:11:26
-// CHECK: Punctuation: ";" [29:16 - 29:17] UnexposedStmt=
-// CHECK: Keyword: "case" [31:3 - 31:7] UnexposedStmt=
+// CHECK: Punctuation: ";" [29:16 - 29:17] CompoundStmt=
+// CHECK: Keyword: "case" [31:3 - 31:7] CaseStmt=
// CHECK: Identifier: "Blue" [31:8 - 31:12] DeclRefExpr=Blue:11:26
-// CHECK: Punctuation: ":" [31:12 - 31:13] UnexposedStmt=
-// CHECK: Keyword: "return" [32:5 - 32:11] UnexposedStmt=
+// CHECK: Punctuation: ":" [31:12 - 31:13] CaseStmt=
+// CHECK: Keyword: "return" [32:5 - 32:11] ReturnStmt=
// CHECK: Identifier: "Red" [32:12 - 32:15] DeclRefExpr=Red:11:14
-// CHECK: Punctuation: ";" [32:15 - 32:16] UnexposedStmt=
+// CHECK: Punctuation: ";" [32:15 - 32:16] CompoundStmt=
// 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
diff --git a/test/Index/annotate-tokens.cpp b/test/Index/annotate-tokens.cpp
index 165420ab39ce..5a8f5e201d0f 100644
--- a/test/Index/annotate-tokens.cpp
+++ b/test/Index/annotate-tokens.cpp
@@ -32,19 +32,19 @@ void test3(S2 s2) {
// CHECK: Identifier: "bonk" [2:11 - 2:15] TypeRef=struct bonk:1:8
// CHECK: Identifier: "X" [2:16 - 2:17] ParmDecl=X:2:16 (Definition)
// CHECK: Punctuation: ")" [2:17 - 2:18] FunctionDecl=test:2:6 (Definition)
-// CHECK: Punctuation: "{" [2:19 - 2:20] UnexposedStmt=
+// CHECK: Punctuation: "{" [2:19 - 2:20] CompoundStmt=
// CHECK: Identifier: "X" [3:5 - 3:6] DeclRefExpr=X:2:16
// CHECK: Punctuation: "=" [3:7 - 3:8] CallExpr=operator=:1:8
// CHECK: Identifier: "X" [3:9 - 3:10] DeclRefExpr=X:2:16
-// CHECK: Punctuation: ";" [3:10 - 3:11] UnexposedStmt=
+// CHECK: Punctuation: ";" [3:10 - 3:11] CompoundStmt=
// CHECK: Keyword: "__is_base_of" [4:5 - 4:17] UnexposedExpr=
// CHECK: Punctuation: "(" [4:17 - 4:18] UnexposedExpr=
// CHECK: Identifier: "bonk" [4:18 - 4:22] TypeRef=struct bonk:1:8
// CHECK: Punctuation: "," [4:22 - 4:23] UnexposedExpr=
// CHECK: Identifier: "bonk" [4:24 - 4:28] TypeRef=struct bonk:1:8
// CHECK: Punctuation: ")" [4:28 - 4:29] UnexposedExpr=
-// CHECK: Punctuation: ";" [4:29 - 4:30] UnexposedStmt=
-// CHECK: Punctuation: "}" [5:1 - 5:2] UnexposedStmt=
+// CHECK: Punctuation: ";" [4:29 - 4:30] CompoundStmt=
+// CHECK: Punctuation: "}" [5:1 - 5:2] CompoundStmt=
// CHECK: Keyword: "struct" [7:1 - 7:7] StructDecl=X:7:8 (Definition)
// CHECK: Identifier: "X" [7:8 - 7:9] StructDecl=X:7:8 (Definition)
// CHECK: Punctuation: "{" [7:10 - 7:11] StructDecl=X:7:8 (Definition)
@@ -69,18 +69,18 @@ void test3(S2 s2) {
// CHECK: Identifier: "X" [11:12 - 11:13] TypeRef=struct X:7:8
// CHECK: Identifier: "x" [11:14 - 11:15] ParmDecl=x:11:14 (Definition)
// CHECK: Punctuation: ")" [11:15 - 11:16] FunctionDecl=test2:11:6 (Definition)
-// CHECK: Punctuation: "{" [11:17 - 11:18] UnexposedStmt=
+// CHECK: Punctuation: "{" [11:17 - 11:18] CompoundStmt=
// CHECK: Punctuation: "++" [12:3 - 12:5] CallExpr=operator++:8:5
-// CHECK: Punctuation: "(" [12:5 - 12:6] UnexposedExpr=
+// CHECK: Punctuation: "(" [12:5 - 12:6] ParenExpr=
// CHECK: Identifier: "x" [12:6 - 12:7] DeclRefExpr=x:11:14
-// CHECK: Punctuation: ")" [12:7 - 12:8] UnexposedExpr=
-// CHECK: Punctuation: ";" [12:8 - 12:9] UnexposedStmt=
-// CHECK: Punctuation: "(" [13:3 - 13:4] UnexposedExpr=
+// CHECK: Punctuation: ")" [12:7 - 12:8] ParenExpr=
+// CHECK: Punctuation: ";" [12:8 - 12:9] CompoundStmt=
+// CHECK: Punctuation: "(" [13:3 - 13:4] ParenExpr=
// CHECK: Identifier: "x" [13:4 - 13:5] DeclRefExpr=x:11:14
-// CHECK: Punctuation: ")" [13:5 - 13:6] UnexposedExpr=
+// CHECK: Punctuation: ")" [13:5 - 13:6] ParenExpr=
// CHECK: Punctuation: "++" [13:6 - 13:8] CallExpr=operator++:9:5
-// CHECK: Punctuation: ";" [13:8 - 13:9] UnexposedStmt=
-// CHECK: Punctuation: "}" [14:1 - 14:2] UnexposedStmt=
+// CHECK: Punctuation: ";" [13:8 - 13:9] CompoundStmt=
+// CHECK: Punctuation: "}" [14:1 - 14:2] CompoundStmt=
// CHECK: Keyword: "struct" [16:1 - 16:7] StructDecl=S1:16:8 (Definition)
// CHECK: Identifier: "S1" [16:8 - 16:10] StructDecl=S1:16:8 (Definition)
// CHECK: Punctuation: "{" [16:11 - 16:12] StructDecl=S1:16:8 (Definition)
@@ -109,14 +109,14 @@ void test3(S2 s2) {
// CHECK: Identifier: "S2" [18:12 - 18:14] TypeRef=struct S2:17:8
// CHECK: Identifier: "s2" [18:15 - 18:17] ParmDecl=s2:18:15 (Definition)
// CHECK: Punctuation: ")" [18:17 - 18:18] FunctionDecl=test3:18:6 (Definition)
-// CHECK: Punctuation: "{" [18:19 - 18:20] UnexposedStmt=
+// CHECK: Punctuation: "{" [18:19 - 18:20] CompoundStmt=
// CHECK: Identifier: "s2" [19:3 - 19:5] DeclRefExpr=s2:18:15
// CHECK: Punctuation: "->" [19:5 - 19:7] MemberRefExpr=f:16:18
// CHECK: Identifier: "f" [19:7 - 19:8] MemberRefExpr=f:16:18
// CHECK: Punctuation: "(" [19:8 - 19:9] CallExpr=f:16:18
// CHECK: Punctuation: ")" [19:9 - 19:10] CallExpr=f:16:18
-// CHECK: Punctuation: ";" [19:10 - 19:11] UnexposedStmt=
+// CHECK: Punctuation: ";" [19:10 - 19:11] CompoundStmt=
// CHECK: Identifier: "X" [20:3 - 20:4] TypeRef=struct X:7:8
// CHECK: Identifier: "foo" [20:5 - 20:8] VarDecl=foo:20:5 (Definition)
-// CHECK: Punctuation: ";" [20:8 - 20:9] UnexposedStmt=
-// CHECK: Punctuation: "}" [21:1 - 21:2] UnexposedStmt=
+// CHECK: Punctuation: ";" [20:8 - 20:9] DeclStmt=
+// CHECK: Punctuation: "}" [21:1 - 21:2] CompoundStmt=
diff --git a/test/Index/annotate-tokens.m b/test/Index/annotate-tokens.m
index 1dc762123207..34115d6d54b3 100644
--- a/test/Index/annotate-tokens.m
+++ b/test/Index/annotate-tokens.m
@@ -137,6 +137,11 @@ static Rdar8595462_A * Rdar8595462_staticVar;
@property (readonly, atomic) Foo *abah;
@end
+@interface rdar9535717 {
+ __weak Foo *foo;
+}
+@end
+
// RUN: c-index-test -test-annotate-tokens=%s:1:1:118:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' | FileCheck %s
// CHECK: Punctuation: "@" [1:1 - 1:2] ObjCInterfaceDecl=Foo:1:12
// CHECK: Keyword: "interface" [1:2 - 1:11] ObjCInterfaceDecl=Foo:1:12
@@ -155,9 +160,9 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Punctuation: ";" [2:27 - 2:28] ObjCInstanceMethodDecl=compare::2:1
// CHECK: Punctuation: "@" [3:1 - 3:2] ObjCInterfaceDecl=Foo:1:12
// CHECK: Keyword: "end" [3:2 - 3:5] ObjCInterfaceDecl=Foo:1:12
-// CHECK: Punctuation: "@" [5:1 - 5:2] ObjCImplementationDecl=Foo:5:1 (Definition)
-// CHECK: Keyword: "implementation" [5:2 - 5:16] ObjCImplementationDecl=Foo:5:1 (Definition)
-// CHECK: Identifier: "Foo" [5:17 - 5:20] ObjCImplementationDecl=Foo:5:1 (Definition)
+// CHECK: Punctuation: "@" [5:1 - 5:2] ObjCImplementationDecl=Foo:5:17 (Definition)
+// CHECK: Keyword: "implementation" [5:2 - 5:16] ObjCImplementationDecl=Foo:5:17 (Definition)
+// CHECK: Identifier: "Foo" [5:17 - 5:20] ObjCImplementationDecl=Foo:5:17 (Definition)
// CHECK: Punctuation: "-" [6:1 - 6:2] ObjCInstanceMethodDecl=compare::6:1 (Definition)
// CHECK: Punctuation: "(" [6:3 - 6:4] ObjCInstanceMethodDecl=compare::6:1 (Definition)
// CHECK: Keyword: "int" [6:4 - 6:7] ObjCInstanceMethodDecl=compare::6:1 (Definition)
@@ -169,21 +174,21 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Punctuation: "*" [6:20 - 6:21] ParmDecl=other:6:22 (Definition)
// CHECK: Punctuation: ")" [6:21 - 6:22] ParmDecl=other:6:22 (Definition)
// CHECK: Identifier: "other" [6:22 - 6:27] ParmDecl=other:6:22 (Definition)
-// CHECK: Punctuation: "{" [6:28 - 6:29] UnexposedStmt=
-// CHECK: Keyword: "return" [7:3 - 7:9] UnexposedStmt=
-// CHECK: Literal: "0" [7:10 - 7:11] UnexposedExpr=
-// CHECK: Punctuation: ";" [7:11 - 7:12] UnexposedStmt=
-// CHECK: Punctuation: "(" [8:3 - 8:4] UnexposedExpr=
-// CHECK: Keyword: "void" [8:4 - 8:8] UnexposedExpr=
-// CHECK: Punctuation: ")" [8:8 - 8:9] UnexposedExpr=
-// CHECK: Punctuation: "@" [8:9 - 8:10] UnexposedExpr=
-// CHECK: Keyword: "encode" [8:10 - 8:16] UnexposedExpr=
-// CHECK: Punctuation: "(" [8:16 - 8:17] UnexposedExpr=
+// CHECK: Punctuation: "{" [6:28 - 6:29] CompoundStmt=
+// CHECK: Keyword: "return" [7:3 - 7:9] ReturnStmt=
+// CHECK: Literal: "0" [7:10 - 7:11] IntegerLiteral=
+// CHECK: Punctuation: ";" [7:11 - 7:12] CompoundStmt=
+// CHECK: Punctuation: "(" [8:3 - 8:4] CStyleCastExpr=
+// CHECK: Keyword: "void" [8:4 - 8:8] CStyleCastExpr=
+// CHECK: Punctuation: ")" [8:8 - 8:9] CStyleCastExpr=
+// CHECK: Punctuation: "@" [8:9 - 8:10] ObjCEncodeExpr=
+// CHECK: Keyword: "encode" [8:10 - 8:16] ObjCEncodeExpr=
+// CHECK: Punctuation: "(" [8:16 - 8:17] ObjCEncodeExpr=
// CHECK: Identifier: "Foo" [8:17 - 8:20] ObjCClassRef=Foo:1:12
-// CHECK: Punctuation: ")" [8:20 - 8:21] UnexposedExpr=
-// CHECK: Punctuation: ";" [8:21 - 8:22] UnexposedStmt=
-// CHECK: Punctuation: "}" [9:1 - 9:2] UnexposedStmt=
-// CHECK: Punctuation: "@" [10:1 - 10:2] ObjCImplementationDecl=Foo:5:1 (Definition)
+// CHECK: Punctuation: ")" [8:20 - 8:21] ObjCEncodeExpr=
+// CHECK: Punctuation: ";" [8:21 - 8:22] CompoundStmt=
+// CHECK: Punctuation: "}" [9:1 - 9:2] CompoundStmt=
+// CHECK: Punctuation: "@" [10:1 - 10:2] ObjCImplementationDecl=Foo:5:17 (Definition)
// CHECK: Keyword: "end" [10:2 - 10:5]
// CHECK: Keyword: "typedef" [14:1 - 14:8]
// CHECK: Keyword: "int" [14:9 - 14:12]
@@ -205,22 +210,22 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Punctuation: "}" [19:1 - 19:2] ObjCInterfaceDecl=Bar:15:12
// CHECK: Punctuation: "@" [20:1 - 20:2] ObjCInterfaceDecl=Bar:15:12
// CHECK: Keyword: "end" [20:2 - 20:5] ObjCInterfaceDecl=Bar:15:12
-// CHECK: Punctuation: "@" [21:1 - 21:2] ObjCImplementationDecl=Bar:21:1 (Definition)
-// CHECK: Keyword: "implementation" [21:2 - 21:16] ObjCImplementationDecl=Bar:21:1 (Definition)
-// CHECK: Identifier: "Bar" [21:17 - 21:20] ObjCImplementationDecl=Bar:21:1 (Definition)
+// CHECK: Punctuation: "@" [21:1 - 21:2] ObjCImplementationDecl=Bar:21:17 (Definition)
+// CHECK: Keyword: "implementation" [21:2 - 21:16] ObjCImplementationDecl=Bar:21:17 (Definition)
+// CHECK: Identifier: "Bar" [21:17 - 21:20] ObjCImplementationDecl=Bar:21:17 (Definition)
// CHECK: Punctuation: "-" [22:1 - 22:2] ObjCInstanceMethodDecl=method:22:1 (Definition)
// CHECK: Punctuation: "(" [22:3 - 22:4] ObjCInstanceMethodDecl=method:22:1 (Definition)
// CHECK: Keyword: "void" [22:4 - 22:8] ObjCInstanceMethodDecl=method:22:1 (Definition)
// CHECK: Punctuation: ")" [22:8 - 22:9] ObjCInstanceMethodDecl=method:22:1 (Definition)
// CHECK: Identifier: "method" [22:10 - 22:16] ObjCInstanceMethodDecl=method:22:1 (Definition)
-// CHECK: Punctuation: "{" [23:1 - 23:2] UnexposedStmt=
+// CHECK: Punctuation: "{" [23:1 - 23:2] CompoundStmt=
// CHECK: Identifier: "barType" [24:5 - 24:12] TypeRef=barType:14:15
// CHECK: Identifier: "local" [24:13 - 24:18] VarDecl=local:24:13 (Definition)
// CHECK: Punctuation: "=" [24:19 - 24:20] VarDecl=local:24:13 (Definition)
// CHECK: Identifier: "iVar" [24:21 - 24:25] MemberRefExpr=iVar:17:13
-// CHECK: Punctuation: ";" [24:25 - 24:26] UnexposedStmt=
-// CHECK: Punctuation: "}" [25:1 - 25:2] UnexposedStmt=
-// CHECK: Punctuation: "@" [26:1 - 26:2] ObjCImplementationDecl=Bar:21:1 (Definition)
+// CHECK: Punctuation: ";" [24:25 - 24:26] DeclStmt=
+// CHECK: Punctuation: "}" [25:1 - 25:2] CompoundStmt=
+// CHECK: Punctuation: "@" [26:1 - 26:2] ObjCImplementationDecl=Bar:21:17 (Definition)
// CHECK: Keyword: "end" [26:2 - 26:5]
// CHECK: Punctuation: "@" [32:1 - 32:2] ObjCInterfaceDecl=IBActionTests:32:12
// CHECK: Keyword: "interface" [32:2 - 32:11] ObjCInterfaceDecl=IBActionTests:32:12
@@ -257,9 +262,9 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Keyword: "void" [36:26 - 36:30] FunctionDecl=ibaction_test:36:12
// CHECK: Punctuation: ")" [36:30 - 36:31] FunctionDecl=ibaction_test:36:12
// CHECK: Punctuation: ";" [36:31 - 36:32]
-// CHECK: Punctuation: "@" [37:1 - 37:2] ObjCImplementationDecl=IBActionTests:37:1 (Definition)
-// CHECK: Keyword: "implementation" [37:2 - 37:16] ObjCImplementationDecl=IBActionTests:37:1 (Definition)
-// CHECK: Identifier: "IBActionTests" [37:17 - 37:30] ObjCImplementationDecl=IBActionTests:37:1 (Definition)
+// CHECK: Punctuation: "@" [37:1 - 37:2] ObjCImplementationDecl=IBActionTests:37:17 (Definition)
+// CHECK: Keyword: "implementation" [37:2 - 37:16] ObjCImplementationDecl=IBActionTests:37:17 (Definition)
+// CHECK: Identifier: "IBActionTests" [37:17 - 37:30] ObjCImplementationDecl=IBActionTests:37:17 (Definition)
// CHECK: Punctuation: "-" [38:1 - 38:2] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
// CHECK: Punctuation: "(" [38:3 - 38:4] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
// CHECK: Identifier: "IBAction" [38:4 - 38:12] macro expansion=IBAction
@@ -270,19 +275,19 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Identifier: "id" [38:31 - 38:33] TypeRef=id:0:0
// CHECK: Punctuation: ")" [38:33 - 38:34] ParmDecl=arg:38:34 (Definition)
// CHECK: Identifier: "arg" [38:34 - 38:37] ParmDecl=arg:38:34 (Definition)
-// CHECK: Punctuation: "{" [39:1 - 39:2] UnexposedStmt=
+// CHECK: Punctuation: "{" [39:1 - 39:2] CompoundStmt=
// CHECK: Identifier: "ibaction_test" [40:5 - 40:18] DeclRefExpr=ibaction_test:36:12
// CHECK: Punctuation: "(" [40:18 - 40:19] CallExpr=ibaction_test:36:12
// CHECK: Punctuation: ")" [40:19 - 40:20] CallExpr=ibaction_test:36:12
-// CHECK: Punctuation: ";" [40:20 - 40:21] UnexposedStmt=
+// CHECK: Punctuation: ";" [40:20 - 40:21] CompoundStmt=
// CHECK: Punctuation: "[" [41:5 - 41:6] ObjCMessageExpr=foo::34:1
// CHECK: Identifier: "self" [41:6 - 41:10] DeclRefExpr=self:0:0
// CHECK: Identifier: "foo" [41:11 - 41:14] ObjCMessageExpr=foo::34:1
// CHECK: Punctuation: ":" [41:14 - 41:15] ObjCMessageExpr=foo::34:1
-// CHECK: Literal: "0" [41:15 - 41:16] UnexposedExpr=
+// CHECK: Literal: "0" [41:15 - 41:16] IntegerLiteral=
// CHECK: Punctuation: "]" [41:16 - 41:17] ObjCMessageExpr=foo::34:1
-// CHECK: Punctuation: ";" [41:17 - 41:18] UnexposedStmt=
-// CHECK: Punctuation: "}" [42:1 - 42:2] UnexposedStmt=
+// CHECK: Punctuation: ";" [41:17 - 41:18] CompoundStmt=
+// CHECK: Punctuation: "}" [42:1 - 42:2] CompoundStmt=
// CHECK: Punctuation: "-" [43:1 - 43:2] ObjCInstanceMethodDecl=foo::43:1 (Definition)
// CHECK: Punctuation: "(" [43:3 - 43:4] ObjCInstanceMethodDecl=foo::43:1 (Definition)
// CHECK: Keyword: "void" [43:4 - 43:8] ObjCInstanceMethodDecl=foo::43:1 (Definition)
@@ -293,14 +298,14 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Keyword: "int" [43:15 - 43:18] ParmDecl=x:43:19 (Definition)
// CHECK: Punctuation: ")" [43:18 - 43:19] ParmDecl=x:43:19 (Definition)
// CHECK: Identifier: "x" [43:19 - 43:20] ParmDecl=x:43:19 (Definition)
-// CHECK: Punctuation: "{" [44:1 - 44:2] UnexposedStmt=
-// CHECK: Punctuation: "(" [45:3 - 45:4] UnexposedExpr=x:43:19
-// CHECK: Keyword: "void" [45:4 - 45:8] UnexposedExpr=x:43:19
-// CHECK: Punctuation: ")" [45:8 - 45:9] UnexposedExpr=x:43:19
+// CHECK: Punctuation: "{" [44:1 - 44:2] CompoundStmt=
+// CHECK: Punctuation: "(" [45:3 - 45:4] CStyleCastExpr=
+// CHECK: Keyword: "void" [45:4 - 45:8] CStyleCastExpr=
+// CHECK: Punctuation: ")" [45:8 - 45:9] CStyleCastExpr=
// CHECK: Identifier: "x" [45:10 - 45:11] DeclRefExpr=x:43:19
-// CHECK: Punctuation: ";" [45:11 - 45:12] UnexposedStmt=
-// CHECK: Punctuation: "}" [46:1 - 46:2] UnexposedStmt=
-// CHECK: Punctuation: "@" [47:1 - 47:2] ObjCImplementationDecl=IBActionTests:37:1 (Definition)
+// CHECK: Punctuation: ";" [45:11 - 45:12] CompoundStmt=
+// CHECK: Punctuation: "}" [46:1 - 46:2] CompoundStmt=
+// CHECK: Punctuation: "@" [47:1 - 47:2] ObjCImplementationDecl=IBActionTests:37:17 (Definition)
// CHECK: Keyword: "end" [47:2 - 47:5]
// CHECK: Punctuation: "@" [51:1 - 51:2] ObjCInterfaceDecl=IBOutletTests:51:12
// CHECK: Keyword: "interface" [51:2 - 51:11] ObjCInterfaceDecl=IBOutletTests:51:12
@@ -358,9 +363,9 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Punctuation: ";" [67:15 - 67:16] ObjCInstanceMethodDecl=method:67:1
// CHECK: Punctuation: "@" [68:1 - 68:2] ObjCInterfaceDecl=R7974151:65:12
// CHECK: Keyword: "end" [68:2 - 68:5] ObjCInterfaceDecl=R7974151:65:12
-// CHECK: Punctuation: "@" [70:1 - 70:2] ObjCImplementationDecl=R7974151:70:1 (Definition)
-// CHECK: Keyword: "implementation" [70:2 - 70:16] ObjCImplementationDecl=R7974151:70:1 (Definition)
-// CHECK: Identifier: "R7974151" [70:17 - 70:25] ObjCImplementationDecl=R7974151:70:1 (Definition)
+// CHECK: Punctuation: "@" [70:1 - 70:2] ObjCImplementationDecl=R7974151:70:17 (Definition)
+// CHECK: Keyword: "implementation" [70:2 - 70:16] ObjCImplementationDecl=R7974151:70:17 (Definition)
+// CHECK: Identifier: "R7974151" [70:17 - 70:25] ObjCImplementationDecl=R7974151:70:17 (Definition)
// CHECK: Punctuation: "-" [71:1 - 71:2] ObjCInstanceMethodDecl=foo::71:1 (Definition)
// CHECK: Punctuation: "(" [71:3 - 71:4] ObjCInstanceMethodDecl=foo::71:1 (Definition)
// CHECK: Keyword: "int" [71:4 - 71:7] ObjCInstanceMethodDecl=foo::71:1 (Definition)
@@ -371,17 +376,17 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Keyword: "int" [71:14 - 71:17] ParmDecl=arg:71:18 (Definition)
// CHECK: Punctuation: ")" [71:17 - 71:18] ParmDecl=arg:71:18 (Definition)
// CHECK: Identifier: "arg" [71:18 - 71:21] ParmDecl=arg:71:18 (Definition)
-// CHECK: Punctuation: "{" [71:22 - 71:23] UnexposedStmt=
-// CHECK: Keyword: "return" [72:3 - 72:9] UnexposedStmt=
+// CHECK: Punctuation: "{" [71:22 - 71:23] CompoundStmt=
+// CHECK: Keyword: "return" [72:3 - 72:9] ReturnStmt=
// CHECK: Identifier: "arg" [72:10 - 72:13] DeclRefExpr=arg:71:18
-// CHECK: Punctuation: ";" [72:13 - 72:14] UnexposedStmt=
-// CHECK: Punctuation: "}" [73:1 - 73:2] UnexposedStmt=
+// CHECK: Punctuation: ";" [72:13 - 72:14] CompoundStmt=
+// CHECK: Punctuation: "}" [73:1 - 73:2] CompoundStmt=
// CHECK: Punctuation: "-" [74:1 - 74:2] ObjCInstanceMethodDecl=method:74:1 (Definition)
// CHECK: Punctuation: "(" [74:3 - 74:4] ObjCInstanceMethodDecl=method:74:1 (Definition)
// CHECK: Keyword: "int" [74:4 - 74:7] ObjCInstanceMethodDecl=method:74:1 (Definition)
// CHECK: Punctuation: ")" [74:7 - 74:8] ObjCInstanceMethodDecl=method:74:1 (Definition)
// CHECK: Identifier: "method" [74:9 - 74:15] ObjCInstanceMethodDecl=method:74:1 (Definition)
-// CHECK: Punctuation: "{" [75:1 - 75:2] UnexposedStmt=
+// CHECK: Punctuation: "{" [75:1 - 75:2] CompoundStmt=
// CHECK: Keyword: "int" [76:5 - 76:8] VarDecl=local:76:9 (Definition)
// CHECK: Identifier: "local" [76:9 - 76:14] VarDecl=local:76:9 (Definition)
// CHECK: Punctuation: "=" [76:15 - 76:16] VarDecl=local:76:9 (Definition)
@@ -391,7 +396,7 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Punctuation: ":" [76:26 - 76:27] ObjCMessageExpr=foo::66:1
// CHECK: Identifier: "VAL" [76:27 - 76:30] macro expansion=VAL:63:9
// CHECK: Punctuation: "]" [76:30 - 76:31] ObjCMessageExpr=foo::66:1
-// CHECK: Punctuation: ";" [76:31 - 76:32] UnexposedStmt=
+// CHECK: Punctuation: ";" [76:31 - 76:32] DeclStmt=
// CHECK: Keyword: "int" [77:5 - 77:8] VarDecl=second:77:9 (Definition)
// CHECK: Identifier: "second" [77:9 - 77:15] VarDecl=second:77:9 (Definition)
// CHECK: Punctuation: "=" [77:16 - 77:17] VarDecl=second:77:9 (Definition)
@@ -399,13 +404,13 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Identifier: "self" [77:19 - 77:23] DeclRefExpr=self:0:0
// CHECK: Identifier: "foo" [77:24 - 77:27] ObjCMessageExpr=foo::66:1
// CHECK: Punctuation: ":" [77:27 - 77:28] ObjCMessageExpr=foo::66:1
-// CHECK: Literal: "0" [77:28 - 77:29] UnexposedExpr=
+// CHECK: Literal: "0" [77:28 - 77:29] IntegerLiteral=
// CHECK: Punctuation: "]" [77:29 - 77:30] ObjCMessageExpr=foo::66:1
-// CHECK: Punctuation: ";" [77:30 - 77:31] UnexposedStmt=
-// CHECK: Keyword: "return" [78:5 - 78:11] UnexposedStmt=
+// CHECK: Punctuation: ";" [77:30 - 77:31] DeclStmt=
+// CHECK: Keyword: "return" [78:5 - 78:11] ReturnStmt=
// CHECK: Identifier: "local" [78:12 - 78:17] DeclRefExpr=local:76:9
-// CHECK: Punctuation: ";" [78:17 - 78:18] UnexposedStmt=
-// CHECK: Punctuation: "}" [79:1 - 79:2] UnexposedStmt=
+// CHECK: Punctuation: ";" [78:17 - 78:18] CompoundStmt=
+// CHECK: Punctuation: "}" [79:1 - 79:2] CompoundStmt=
// CHECK: Punctuation: "-" [80:1 - 80:2] ObjCInstanceMethodDecl=othermethod::80:1 (Definition)
// CHECK: Punctuation: "(" [80:3 - 80:4] ObjCInstanceMethodDecl=othermethod::80:1 (Definition)
// CHECK: Keyword: "int" [80:4 - 80:7] ObjCInstanceMethodDecl=othermethod::80:1 (Definition)
@@ -417,36 +422,36 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Punctuation: "*" [80:35 - 80:36] ParmDecl=ibt:80:37 (Definition)
// CHECK: Punctuation: ")" [80:36 - 80:37] ParmDecl=ibt:80:37 (Definition)
// CHECK: Identifier: "ibt" [80:37 - 80:40] ParmDecl=ibt:80:37 (Definition)
-// CHECK: Punctuation: "{" [80:41 - 80:42] UnexposedStmt=
-// CHECK: Keyword: "return" [81:3 - 81:9] UnexposedStmt=
-// CHECK: Punctuation: "*" [81:10 - 81:11] UnexposedExpr=
+// CHECK: Punctuation: "{" [80:41 - 80:42] CompoundStmt=
+// CHECK: Keyword: "return" [81:3 - 81:9] ReturnStmt=
+// CHECK: Punctuation: "*" [81:10 - 81:11] UnaryOperator=
// CHECK: Identifier: "ibt" [81:11 - 81:14] DeclRefExpr=ibt:80:37
// CHECK: Punctuation: "." [81:14 - 81:15] MemberRefExpr=aPropOutlet:56:26
// CHECK: Identifier: "aPropOutlet" [81:15 - 81:26] MemberRefExpr=aPropOutlet:56:26
-// CHECK: Punctuation: ";" [81:26 - 81:27] UnexposedStmt=
-// CHECK: Punctuation: "}" [82:1 - 82:2] UnexposedStmt=
-// CHECK: Punctuation: "@" [83:1 - 83:2] ObjCImplementationDecl=R7974151:70:1 (Definition)
+// CHECK: Punctuation: ";" [81:26 - 81:27] CompoundStmt=
+// CHECK: Punctuation: "}" [82:1 - 82:2] CompoundStmt=
+// CHECK: Punctuation: "@" [83:1 - 83:2] ObjCImplementationDecl=R7974151:70:17 (Definition)
// CHECK: Keyword: "end" [83:2 - 83:5]
-// CHECK: Punctuation: "@" [85:1 - 85:2] ObjCProtocolDecl=Proto:85:1 (Definition)
-// CHECK: Keyword: "protocol" [85:2 - 85:10] ObjCProtocolDecl=Proto:85:1 (Definition)
-// CHECK: Identifier: "Proto" [85:11 - 85:16] ObjCProtocolDecl=Proto:85:1 (Definition)
-// CHECK: Punctuation: "@" [85:17 - 85:18] ObjCProtocolDecl=Proto:85:1 (Definition)
-// CHECK: Keyword: "end" [85:18 - 85:21] ObjCProtocolDecl=Proto:85:1 (Definition)
+// CHECK: Punctuation: "@" [85:1 - 85:2] ObjCProtocolDecl=Proto:85:11 (Definition)
+// CHECK: Keyword: "protocol" [85:2 - 85:10] ObjCProtocolDecl=Proto:85:11 (Definition)
+// CHECK: Identifier: "Proto" [85:11 - 85:16] ObjCProtocolDecl=Proto:85:11 (Definition)
+// CHECK: Punctuation: "@" [85:17 - 85:18] ObjCProtocolDecl=Proto:85:11 (Definition)
+// CHECK: Keyword: "end" [85:18 - 85:21] ObjCProtocolDecl=Proto:85:11 (Definition)
// CHECK: Keyword: "void" [87:1 - 87:5] FunctionDecl=f:87:6 (Definition)
// CHECK: Identifier: "f" [87:6 - 87:7] FunctionDecl=f:87:6 (Definition)
// CHECK: Punctuation: "(" [87:7 - 87:8] FunctionDecl=f:87:6 (Definition)
// CHECK: Punctuation: ")" [87:8 - 87:9] FunctionDecl=f:87:6 (Definition)
-// CHECK: Punctuation: "{" [87:10 - 87:11] UnexposedStmt=
-// CHECK: Punctuation: "(" [88:3 - 88:4] UnexposedExpr=Proto:85:1
-// CHECK: Keyword: "void" [88:4 - 88:8] UnexposedExpr=Proto:85:1
-// CHECK: Punctuation: ")" [88:8 - 88:9] UnexposedExpr=Proto:85:1
-// CHECK: Punctuation: "@" [88:9 - 88:10] UnexposedExpr=Proto:85:1
-// CHECK: Keyword: "protocol" [88:10 - 88:18] UnexposedExpr=Proto:85:1
-// CHECK: Punctuation: "(" [88:18 - 88:19] UnexposedExpr=Proto:85:1
-// CHECK: Identifier: "Proto" [88:19 - 88:24] UnexposedExpr=Proto:85:1
-// CHECK: Punctuation: ")" [88:24 - 88:25] UnexposedExpr=Proto:85:1
-// CHECK: Punctuation: ";" [88:25 - 88:26] UnexposedStmt=
-// CHECK: Punctuation: "}" [89:1 - 89:2] UnexposedStmt=
+// CHECK: Punctuation: "{" [87:10 - 87:11] CompoundStmt=
+// CHECK: Punctuation: "(" [88:3 - 88:4] CStyleCastExpr=
+// CHECK: Keyword: "void" [88:4 - 88:8] CStyleCastExpr=
+// CHECK: Punctuation: ")" [88:8 - 88:9] CStyleCastExpr=
+// CHECK: Punctuation: "@" [88:9 - 88:10] ObjCProtocolExpr=Proto:85:1
+// CHECK: Keyword: "protocol" [88:10 - 88:18] ObjCProtocolExpr=Proto:85:1
+// CHECK: Punctuation: "(" [88:18 - 88:19] ObjCProtocolExpr=Proto:85:1
+// CHECK: Identifier: "Proto" [88:19 - 88:24] ObjCProtocolExpr=Proto:85:1
+// CHECK: Punctuation: ")" [88:24 - 88:25] ObjCProtocolExpr=Proto:85:1
+// CHECK: Punctuation: ";" [88:25 - 88:26] CompoundStmt=
+// CHECK: Punctuation: "}" [89:1 - 89:2] CompoundStmt=
// CHECK: Punctuation: "@" [93:1 - 93:2] UnexposedDecl=[93:8]
// CHECK: Keyword: "class" [93:2 - 93:7] UnexposedDecl=[93:8]
// CHECK: Identifier: "Rdar8595462_A" [93:8 - 93:21] ObjCClassRef=Rdar8595462_A:93:8
@@ -456,31 +461,31 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Identifier: "Rdar8595462_B" [94:12 - 94:25] ObjCInterfaceDecl=Rdar8595462_B:94:12
// CHECK: Punctuation: "@" [95:1 - 95:2] ObjCInterfaceDecl=Rdar8595462_B:94:12
// CHECK: Keyword: "end" [95:2 - 95:5] ObjCInterfaceDecl=Rdar8595462_B:94:12
-// CHECK: Punctuation: "@" [97:1 - 97:2] ObjCImplementationDecl=Rdar8595462_B:97:1 (Definition)
-// CHECK: Keyword: "implementation" [97:2 - 97:16] ObjCImplementationDecl=Rdar8595462_B:97:1 (Definition)
-// CHECK: Identifier: "Rdar8595462_B" [97:17 - 97:30] ObjCImplementationDecl=Rdar8595462_B:97:1 (Definition)
+// CHECK: Punctuation: "@" [97:1 - 97:2] ObjCImplementationDecl=Rdar8595462_B:97:17 (Definition)
+// CHECK: Keyword: "implementation" [97:2 - 97:16] ObjCImplementationDecl=Rdar8595462_B:97:17 (Definition)
+// CHECK: Identifier: "Rdar8595462_B" [97:17 - 97:30] ObjCImplementationDecl=Rdar8595462_B:97:17 (Definition)
// CHECK: Identifier: "Rdar8595462_A" [98:1 - 98:14] ObjCClassRef=Rdar8595462_A:93:8
// CHECK: Punctuation: "*" [98:15 - 98:16] FunctionDecl=Rdar8595462_aFunction:98:17 (Definition)
// CHECK: Identifier: "Rdar8595462_aFunction" [98:17 - 98:38] FunctionDecl=Rdar8595462_aFunction:98:17 (Definition)
// CHECK: Punctuation: "(" [98:38 - 98:39] FunctionDecl=Rdar8595462_aFunction:98:17 (Definition)
// CHECK: Punctuation: ")" [98:39 - 98:40] FunctionDecl=Rdar8595462_aFunction:98:17 (Definition)
-// CHECK: Punctuation: "{" [98:41 - 98:42] UnexposedStmt=
+// CHECK: Punctuation: "{" [98:41 - 98:42] CompoundStmt=
// CHECK: Identifier: "Rdar8595462_A" [99:3 - 99:16] ObjCClassRef=Rdar8595462_A:93:8
// CHECK: Punctuation: "*" [99:17 - 99:18] VarDecl=localVar:99:19 (Definition)
// CHECK: Identifier: "localVar" [99:19 - 99:27] VarDecl=localVar:99:19 (Definition)
// CHECK: Punctuation: "=" [99:28 - 99:29] VarDecl=localVar:99:19 (Definition)
-// CHECK: Literal: "0" [99:30 - 99:31] UnexposedExpr=
-// CHECK: Punctuation: ";" [99:31 - 99:32] UnexposedStmt=
-// CHECK: Keyword: "return" [100:3 - 100:9] UnexposedStmt=
+// CHECK: Literal: "0" [99:30 - 99:31] IntegerLiteral=
+// CHECK: Punctuation: ";" [99:31 - 99:32] DeclStmt=
+// CHECK: Keyword: "return" [100:3 - 100:9] ReturnStmt=
// CHECK: Identifier: "localVar" [100:10 - 100:18] DeclRefExpr=localVar:99:19
-// CHECK: Punctuation: ";" [100:18 - 100:19] UnexposedStmt=
-// CHECK: Punctuation: "}" [101:1 - 101:2] UnexposedStmt=
-// CHECK: Keyword: "static" [102:1 - 102:7] ObjCImplementationDecl=Rdar8595462_B:97:1 (Definition)
+// 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: 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
-// CHECK: Punctuation: ";" [102:45 - 102:46] ObjCImplementationDecl=Rdar8595462_B:97:1 (Definition)
-// CHECK: Punctuation: "@" [103:1 - 103:2] ObjCImplementationDecl=Rdar8595462_B:97:1 (Definition)
+// CHECK: Punctuation: ";" [102:45 - 102:46] ObjCImplementationDecl=Rdar8595462_B:97:17 (Definition)
+// CHECK: Punctuation: "@" [103:1 - 103:2] ObjCImplementationDecl=Rdar8595462_B:97:17 (Definition)
// CHECK: Keyword: "end" [103:2 - 103:5]
// CHECK: Punctuation: "@" [110:1 - 110:2] ObjCPropertyDecl=foo:110:33
@@ -506,7 +511,7 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Identifier: "foo" [115:13 - 115:16] ObjCSynthesizeDecl=foo:110:33 (Definition)
// CHECK: Punctuation: "=" [115:17 - 115:18] ObjCSynthesizeDecl=foo:110:33 (Definition)
// CHECK: Identifier: "_foo" [115:19 - 115:23] MemberRef=_foo:107:8
-// CHECK: Punctuation: ";" [115:23 - 115:24] ObjCImplementationDecl=Rdar8595386:114:1 (Definition)
+// CHECK: Punctuation: ";" [115:23 - 115:24] ObjCImplementationDecl=Rdar8595386:114:17 (Definition)
// RUN: c-index-test -test-annotate-tokens=%s:127:1:130:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' | FileCheck -check-prefix=CHECK-INSIDE_BLOCK %s
// CHECK-INSIDE_BLOCK: Keyword: "int" [127:5 - 127:8] VarDecl=result:127:9 (Definition)
@@ -516,11 +521,11 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK-INSIDE_BLOCK: Identifier: "self" [127:19 - 127:23] DeclRefExpr=self:0:0
// CHECK-INSIDE_BLOCK: Identifier: "blah" [127:24 - 127:28] ObjCMessageExpr=blah::124:1
// CHECK-INSIDE_BLOCK: Punctuation: ":" [127:28 - 127:29] ObjCMessageExpr=blah::124:1
-// CHECK-INSIDE_BLOCK: Literal: "5" [127:29 - 127:30] UnexposedExpr=
+// CHECK-INSIDE_BLOCK: Literal: "5" [127:29 - 127:30] IntegerLiteral=
// CHECK-INSIDE_BLOCK: Punctuation: "," [127:30 - 127:31] ObjCMessageExpr=blah::124:1
// CHECK-INSIDE_BLOCK: Identifier: "x" [127:32 - 127:33] DeclRefExpr=x:125:19
// CHECK-INSIDE_BLOCK: Punctuation: "]" [127:33 - 127:34] ObjCMessageExpr=blah::124:1
-// CHECK-INSIDE_BLOCK: Punctuation: ";" [127:34 - 127:35] UnexposedStmt=
+// CHECK-INSIDE_BLOCK: Punctuation: ";" [127:34 - 127:35] DeclStmt=
// CHECK-INSIDE_BLOCK: Identifier: "Rdar8778404" [128:5 - 128:16] ObjCClassRef=Rdar8778404:120:12
// CHECK-INSIDE_BLOCK: Punctuation: "*" [128:17 - 128:18] VarDecl=a:128:18 (Definition)
// CHECK-INSIDE_BLOCK: Identifier: "a" [128:18 - 128:19] VarDecl=a:128:18 (Definition)
@@ -561,3 +566,11 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK-PROP-AFTER-METHOD: Identifier: "abah" [137:35 - 137:39] ObjCPropertyDecl=abah:137:35
// CHECK-PROP-AFTER-METHOD: Punctuation: ";" [137:39 - 137:40] ObjCInterfaceDecl=Rdar8062781:134:12
// CHECK-PROP-AFTER-METHOD: Punctuation: "@" [138:1 - 138:2] ObjCInterfaceDecl=Rdar8062781:134:12
+
+// RUN: c-index-test -test-annotate-tokens=%s:141:1:142:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' -ccc-host-triple x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-WITH-WEAK %s
+// CHECK-WITH-WEAK: Identifier: "__weak" [141:3 - 141:9] macro expansion
+// CHECK-WITH-WEAK: Identifier: "Foo" [141:10 - 141:13] ObjCClassRef=Foo:1:12
+// CHECK-WITH-WEAK: Punctuation: "*" [141:14 - 141:15] ObjCIvarDecl=foo:141:15 (Definition)
+// CHECK-WITH-WEAK: Identifier: "foo" [141:15 - 141:18] ObjCIvarDecl=foo:141:15 (Definition)
+// CHECK-WITH-WEAK: Punctuation: ";" [141:18 - 141:19] ObjCInterfaceDecl=rdar9535717:140:12
+// CHECK-WITH-WEAK: Punctuation: "}" [142:1 - 142:2] ObjCInterfaceDecl=rdar9535717:140:12
diff --git a/test/Index/blocks.c b/test/Index/blocks.c
index 633e171ffa37..3f33e48e4ced 100644
--- a/test/Index/blocks.c
+++ b/test/Index/blocks.c
@@ -10,25 +10,25 @@ void test() {
}
// CHECK: blocks.c:6:6: FunctionDecl=test:6:6 (Definition) Extent=[6:1 - 10:2]
-// CHECK: blocks.c:6:13: UnexposedStmt= Extent=[6:13 - 10:2]
-// CHECK: blocks.c:7:3: UnexposedStmt= Extent=[7:3 - 7:26]
+// CHECK: blocks.c:6:13: CompoundStmt= Extent=[6:13 - 10:2]
+// CHECK: blocks.c:7:3: DeclStmt= Extent=[7:3 - 7:26]
// CHECK: blocks.c:7:21: VarDecl=_foo:7:21 (Definition) Extent=[7:3 - 7:25]
// CHECK: blocks.c:7:17: TypeRef=struct foo:4:8 Extent=[7:17 - 7:20]
// CHECK: blocks.c:8:11: VarDecl=i:8:11 (Definition) Extent=[8:3 - 8:16]
-// CHECK: blocks.c:8:15: UnexposedExpr= Extent=[8:15 - 8:16]
+// CHECK: blocks.c:8:15: IntegerLiteral= Extent=[8:15 - 8:16]
// CHECK: blocks.c:9:3: CallExpr= Extent=[9:3 - 9:65]
-// CHECK: blocks.c:9:3: UnexposedExpr= Extent=[9:3 - 9:58]
+// CHECK: blocks.c:9:3: BlockExpr= Extent=[9:3 - 9:58]
// CHECK: blocks.c:9:5: TypeRef=int_t:3:13 Extent=[9:5 - 9:10]
// CHECK: blocks.c:9:23: ParmDecl=foo:9:23 (Definition) Extent=[9:11 - 9:26]
// CHECK: blocks.c:9:18: TypeRef=struct foo:4:8 Extent=[9:18 - 9:21]
-// CHECK: blocks.c:9:28: UnexposedStmt= Extent=[9:28 - 9:58]
-// CHECK: blocks.c:9:30: UnexposedStmt= Extent=[9:30 - 9:55]
-// CHECK: blocks.c:9:37: UnexposedExpr= Extent=[9:37 - 9:55]
-// CHECK: blocks.c:9:37: UnexposedExpr=x:4:19 Extent=[9:37 - 9:51]
+// CHECK: blocks.c:9:28: CompoundStmt= Extent=[9:28 - 9:58]
+// CHECK: blocks.c:9:30: ReturnStmt= Extent=[9:30 - 9:55]
+// CHECK: blocks.c:9:37: BinaryOperator= Extent=[9:37 - 9:55]
+// CHECK: blocks.c:9:37: CStyleCastExpr= Extent=[9:37 - 9:51]
// CHECK: blocks.c:9:38: TypeRef=int_t:3:13 Extent=[9:38 - 9:43]
-// CHECK: blocks.c:9:50: MemberRefExpr=x:4:19 Extent=[9:45 - 9:51]
+// CHECK: blocks.c:9:50: MemberRefExpr=x:4:19 SingleRefName=[9:50 - 9:51] RefName=[9:50 - 9:51] Extent=[9:45 - 9:51]
// CHECK: blocks.c:9:45: DeclRefExpr=foo:9:23 Extent=[9:45 - 9:48]
// CHECK: blocks.c:9:54: DeclRefExpr=i:8:11 Extent=[9:54 - 9:55]
-// CHECK: blocks.c:9:59: UnexposedExpr= Extent=[9:59 - 9:64]
+// CHECK: blocks.c:9:59: UnaryOperator= Extent=[9:59 - 9:64]
// CHECK: blocks.c:9:60: DeclRefExpr=_foo:7:21 Extent=[9:60 - 9:64]
diff --git a/test/Index/c-index-api-loadTU-test.m b/test/Index/c-index-api-loadTU-test.m
index ab5f9a9ed6f9..62cc4d422ca2 100644
--- a/test/Index/c-index-api-loadTU-test.m
+++ b/test/Index/c-index-api-loadTU-test.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -emit-pch -x objective-c %s -o %t.ast
+// 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
@interface Foo
@@ -60,7 +60,7 @@ int main (int argc, const char * argv[]) {
#define IBAction void)__attribute__((ibaction)
@interface TestAttributes {
- IBOutlet char * anOutlet;
+ IBOutlet id anOutlet;
IBOutletCollection(id) id anOutletCollection;
}
- (IBAction) actionMethod:(id)arg;
@@ -92,14 +92,14 @@ struct X0 {};
// CHECK: c-index-api-loadTU-test.m:21:1: ObjCInstanceMethodDecl=catMethodWithFloat::21:1 Extent=[21:1 - 21:41]
// CHECK: c-index-api-loadTU-test.m:21:36: ParmDecl=fArg:21:36 (Definition) Extent=[21:29 - 21:40]
// CHECK: c-index-api-loadTU-test.m:22:1: ObjCInstanceMethodDecl=floatMethod:22:1 Extent=[22:1 - 22:23]
-// CHECK: c-index-api-loadTU-test.m:25:1: ObjCProtocolDecl=Proto:25:1 (Definition) Extent=[25:1 - 27:5]
+// CHECK: c-index-api-loadTU-test.m:25:11: ObjCProtocolDecl=Proto:25:11 (Definition) Extent=[25:1 - 27:5]
// CHECK: c-index-api-loadTU-test.m:26:1: ObjCInstanceMethodDecl=pMethod:26:1 Extent=[26:1 - 26:11]
-// CHECK: c-index-api-loadTU-test.m:29:1: ObjCProtocolDecl=SubP:29:1 (Definition) Extent=[29:1 - 31:5]
-// CHECK: c-index-api-loadTU-test.m:29:17: ObjCProtocolRef=Proto:25:1 Extent=[29:17 - 29:22]
+// CHECK: c-index-api-loadTU-test.m:29:11: ObjCProtocolDecl=SubP:29:11 (Definition) Extent=[29:1 - 31:5]
+// CHECK: c-index-api-loadTU-test.m:29:17: ObjCProtocolRef=Proto:25:11 Extent=[29:17 - 29:22]
// CHECK: c-index-api-loadTU-test.m:30:1: ObjCInstanceMethodDecl=spMethod:30:1 Extent=[30:1 - 30:12]
// CHECK: c-index-api-loadTU-test.m:33:12: ObjCInterfaceDecl=Baz:33:12 Extent=[33:1 - 40:5]
// CHECK: c-index-api-loadTU-test.m:33:18: ObjCSuperClassRef=Bar:14:12 Extent=[33:18 - 33:21]
-// CHECK: c-index-api-loadTU-test.m:33:23: ObjCProtocolRef=SubP:29:1 Extent=[33:23 - 33:27]
+// CHECK: c-index-api-loadTU-test.m:33:23: ObjCProtocolRef=SubP:29:11 Extent=[33:23 - 33:27]
// CHECK: c-index-api-loadTU-test.m:35:9: ObjCIvarDecl=_anIVar:35:9 (Definition) Extent=[35:5 - 35:16]
// CHECK: c-index-api-loadTU-test.m:38:1: ObjCInstanceMethodDecl=bazMethod:38:1 Extent=[38:1 - 38:21]
// CHECK: c-index-api-loadTU-test.m:38:4: ObjCClassRef=Foo:4:12 Extent=[38:4 - 38:7]
@@ -116,14 +116,14 @@ struct X0 {};
// 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: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:1 Extent=[49:6 - 49:10]
+// 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:1 Extent=[49:16 - 49:26]
// CHECK: c-index-api-loadTU-test.m:49:16: ObjCMessageExpr=fooC:10:1 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: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:1 Extent=[50:6 - 50:11]
-// CHECK: c-index-api-loadTU-test.m:51:2: UnexposedExpr= Extent=[51:2 - 51:7]
+// 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: DeclRefExpr=c:49:12 Extent=[51:6 - 51:7]
@@ -137,10 +137,10 @@ struct X0 {};
// 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: UnexposedExpr=bee:47:8 Extent=[54:18 - 54:36]
+// CHECK: c-index-api-loadTU-test.m:54:18: CStyleCastExpr= Extent=[54:18 - 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:19: ObjCIvarDecl=anOutlet:63:19 (Definition) Extent=[58:18 - 63:27]
+// 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]
diff --git a/test/Index/c-index-getCursor-pp.c b/test/Index/c-index-getCursor-pp.c
index df61ec0329e5..0a10450af5cd 100644
--- a/test/Index/c-index-getCursor-pp.c
+++ b/test/Index/c-index-getCursor-pp.c
@@ -13,6 +13,8 @@ void OBSCURE(func)(int x) {
B(int x);
+const char *fname = __FILE__;
+
// 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
@@ -27,6 +29,8 @@ B(int x);
// CHECK-6: inclusion directive=a.h
// RUN: c-index-test -cursor-at=%s:14:1 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-7 %s
// CHECK-7: macro expansion=B:12:9
+// RUN: c-index-test -cursor-at=%s:16:25 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-8 %s
+// CHECK-8: macro expansion=__FILE__
// Same tests, but with "editing" optimizations
// RUN: env CINDEXTEST_EDITING=1 c-index-test -cursor-at=%s:1:11 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-1 %s
diff --git a/test/Index/c-index-getCursor-test.m b/test/Index/c-index-getCursor-test.m
index 6df8c1abfeed..c7410c9bbfa3 100644
--- a/test/Index/c-index-getCursor-test.m
+++ b/test/Index/c-index-getCursor-test.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -emit-pch -x objective-c %s -detailed-preprocessing-record -o %t.ast
+// 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
@interface Foo
{
@@ -80,15 +80,15 @@ void f() {
// CHECK: [20:1 - 20:23] ObjCInstanceMethodDecl=floatMethod:20:1
// CHECK: [20:23 - 21:5] ObjCCategoryDecl=FooCat:18:12
// CHECK: [21:5 - 23:1] Invalid Cursor => NoDeclFound
-// CHECK: [23:1 - 24:1] ObjCProtocolDecl=Proto:23:1 (Definition)
+// CHECK: [23:1 - 24:1] ObjCProtocolDecl=Proto:23:11 (Definition)
// CHECK: [24:1 - 24:11] ObjCInstanceMethodDecl=pMethod:24:1
-// CHECK: [24:11 - 25:5] ObjCProtocolDecl=Proto:23:1 (Definition)
+// CHECK: [24:11 - 25:5] ObjCProtocolDecl=Proto:23:11 (Definition)
// CHECK: [25:5 - 27:1] Invalid Cursor => NoDeclFound
-// CHECK: [27:1 - 27:17] ObjCProtocolDecl=SubP:27:1 (Definition)
+// CHECK: [27:1 - 27:17] ObjCProtocolDecl=SubP:27:11 (Definition)
// CHECK: [27:17 - 27:22] ObjCProtocolRef=Proto:23:1
-// CHECK: [27:22 - 28:1] ObjCProtocolDecl=SubP:27:1 (Definition)
+// CHECK: [27:22 - 28:1] ObjCProtocolDecl=SubP:27:11 (Definition)
// CHECK: [28:1 - 28:12] ObjCInstanceMethodDecl=spMethod:28:1
-// CHECK: [28:12 - 29:5] ObjCProtocolDecl=SubP:27:1 (Definition)
+// CHECK: [28:12 - 29:5] ObjCProtocolDecl=SubP:27:11 (Definition)
// CHECK: [29:5 - 31:1] Invalid Cursor => NoDeclFound
// CHECK: [31:1 - 31:18] ObjCInterfaceDecl=Baz:31:12
// CHECK: [31:18 - 31:21] ObjCSuperClassRef=Bar:12:12
@@ -111,18 +111,18 @@ void f() {
// CHECK: [44:19 - 44:21] FunctionDecl=main:44:5 (Definition)
// CHECK: [44:21 - 44:40] ParmDecl=argv:44:34 (Definition)
// CHECK: [44:40 - 44:42] FunctionDecl=main:44:5 (Definition)
-// CHECK: [44:42 - 45:2] UnexposedStmt=
+// CHECK: [44:42 - 45:2] CompoundStmt=
// CHECK: [45:2 - 45:5] ObjCClassRef=Baz:31:12
// CHECK: [45:5 - 45:11] VarDecl=bee:45:8 (Definition)
-// CHECK: [45:11 - 45:12] UnexposedStmt=
-// CHECK: [45:12 - 46:2] UnexposedStmt=
+// CHECK: [45:11 - 45:12] DeclStmt=
+// CHECK: [45:12 - 46:2] CompoundStmt=
// CHECK: [46:2 - 46:4] TypeRef=id:0:0
// CHECK: [46:4 - 46:9] VarDecl=a:46:5 (Definition)
// CHECK: [46:9 - 46:10] ObjCMessageExpr=foo:7:1
// CHECK: [46:10 - 46:13] DeclRefExpr=bee:45:8
// CHECK: [46:13 - 46:18] ObjCMessageExpr=foo:7:1
-// CHECK: [46:18 - 46:19] UnexposedStmt=
-// CHECK: [46:19 - 47:2] UnexposedStmt=
+// CHECK: [46:18 - 46:19] DeclStmt=
+// CHECK: [46:19 - 47:2] CompoundStmt=
// CHECK: [47:2 - 47:4] TypeRef=id:0:0
// CHECK: [47:4 - 47:6] VarDecl=c:47:12 (Definition)
// CHECK: [47:6 - 47:10] ObjCProtocolRef=SubP:27:1
@@ -130,22 +130,22 @@ void f() {
// CHECK: [47:16 - 47:17] ObjCMessageExpr=fooC:8:1
// CHECK: [47:17 - 47:20] ObjCClassRef=Foo:3:12
// CHECK: [47:20 - 47:26] ObjCMessageExpr=fooC:8:1
-// CHECK: [47:26 - 47:27] UnexposedStmt=
-// CHECK: [47:27 - 48:2] UnexposedStmt=
+// CHECK: [47:26 - 47:27] DeclStmt=
+// CHECK: [47:27 - 48:2] CompoundStmt=
// CHECK: [48:2 - 48:4] TypeRef=id:0:0
// CHECK: [48:4 - 48:6] VarDecl=d:48:13 (Definition)
// CHECK: [48:6 - 48:11] ObjCProtocolRef=Proto:23:1
// CHECK: [48:11 - 48:14] VarDecl=d:48:13 (Definition)
-// CHECK: [48:14 - 48:15] UnexposedStmt=
-// CHECK: [48:15 - 49:2] UnexposedStmt=
+// CHECK: [48:14 - 48:15] DeclStmt=
+// CHECK: [48:15 - 49:2] CompoundStmt=
// CHECK: [49:2 - 49:3] DeclRefExpr=d:48:13
-// CHECK: [49:3 - 49:6] UnexposedExpr=
+// CHECK: [49:3 - 49:6] BinaryOperator=
// CHECK: [49:6 - 49:7] DeclRefExpr=c:47:12
-// CHECK: [49:7 - 50:2] UnexposedStmt=
+// CHECK: [49:7 - 50:2] CompoundStmt=
// CHECK: [50:2 - 50:3] ObjCMessageExpr=pMethod:24:1
// CHECK: [50:3 - 50:4] DeclRefExpr=d:48:13
// CHECK: [50:4 - 50:13] ObjCMessageExpr=pMethod:24:1
-// CHECK: [50:13 - 51:2] UnexposedStmt=
+// CHECK: [50:13 - 51:2] CompoundStmt=
// CHECK: [51:2 - 51:3] ObjCMessageExpr=catMethodWithFloat::19:1
// CHECK: [51:3 - 51:6] DeclRefExpr=bee:45:8
// CHECK: [51:6 - 51:26] ObjCMessageExpr=catMethodWithFloat::19:1
@@ -153,16 +153,16 @@ void f() {
// CHECK: [51:27 - 51:30] DeclRefExpr=bee:45:8
// CHECK: [51:30 - 51:43] ObjCMessageExpr=floatMethod:20:1
// CHECK: [51:43 - 51:44] ObjCMessageExpr=catMethodWithFloat::19:1
-// CHECK: [51:44 - 52:3] UnexposedStmt=
+// CHECK: [51:44 - 52:3] CompoundStmt=
// CHECK: [52:3 - 52:7] DeclRefExpr=main:44:5
// CHECK: [52:7 - 52:8] CallExpr=main:44:5
// CHECK: [52:8 - 52:16] DeclRefExpr=someEnum:41:3
// CHECK: [52:16 - 52:18] CallExpr=main:44:5
-// CHECK: [52:18 - 52:33] UnexposedExpr=bee:45:8
+// CHECK: [52:18 - 52:33] CStyleCastExpr=
// CHECK: [52:33 - 52:36] DeclRefExpr=bee:45:8
// CHECK: [52:36 - 52:37] CallExpr=main:44:5
-// CHECK: [52:37 - 53:2] UnexposedStmt=
+// CHECK: [52:37 - 53:2] CompoundStmt=
// CHECK: [55:9 - 55:26] macro definition=CONCAT
// CHECK: [57:1 - 57:10] FunctionDecl=f:57:6 (Definition)
// CHECK: [58:4 - 58:8] VarDecl=my_var:58:8 (Definition)
-// CHECK: [58:8 - 58:14] macro expansion=CONCAT:55:9
+// CHECK: [58:8 - 58:15] macro expansion=CONCAT:55:9
diff --git a/test/Index/c-index-pch.c b/test/Index/c-index-pch.c
index 2037fc58802c..313fae88f4f9 100644
--- a/test/Index/c-index-pch.c
+++ b/test/Index/c-index-pch.c
@@ -1,14 +1,9 @@
// RUN: %clang_cc1 -emit-pch -x c -o %t.pch %S/Inputs/c-index-pch.h
// RUN: %clang_cc1 -include-pch %t.pch -x c -emit-pch -o %t.ast %s
// RUN: c-index-test -test-load-tu %t.ast all | FileCheck -check-prefix=ALL %s
-// RUN: c-index-test -test-load-tu %t.ast local | FileCheck -check-prefix=LOCAL %s
// ALL: FunctionDecl=foo
// ALL: VarDecl=bar
// ALL: FunctionDecl=wibble
// ALL: FunctionDecl=wonka
-// LOCAL-NOT: FunctionDecl=foo
-// LOCAL-NOT: VarDecl=bar
-// LOCAL: FunctionDecl=wibble
-// LOCAL: FunctionDecl=wonka
void wibble(int i);
void wonka(float);
diff --git a/test/Index/code-completion.cpp b/test/Index/code-completion.cpp
index f75d61f1b04b..5789d3b9fa07 100644
--- a/test/Index/code-completion.cpp
+++ b/test/Index/code-completion.cpp
@@ -54,6 +54,9 @@ Z::operator int() const {
// CHECK-MEMBER: CXXDestructor:{ResultType void}{TypedText ~Z}{LeftParen (}{RightParen )}
// CHECK-MEMBER: Completion contexts:
// CHECK-MEMBER-NEXT: Dot member access
+// CHECK-MEMBER-NEXT: Container Kind: StructDecl
+// CHECK-MEMBER-NEXT: Container is complete
+// CHECK-MEMBER-NEXT: Container USR: c:@S@Z
// CHECK-OVERLOAD: NotImplemented:{ResultType int &}{Text overloaded}{LeftParen (}{Text Z z}{Comma , }{CurrentParameter int second}{RightParen )}
// CHECK-OVERLOAD: NotImplemented:{ResultType float &}{Text overloaded}{LeftParen (}{Text int i}{Comma , }{CurrentParameter long second}{RightParen )}
diff --git a/test/Index/complete-access-checks.cpp b/test/Index/complete-access-checks.cpp
new file mode 100644
index 000000000000..c77a5d656a97
--- /dev/null
+++ b/test/Index/complete-access-checks.cpp
@@ -0,0 +1,89 @@
+struct X {
+ int member1;
+ void func1();
+protected:
+ int member2;
+ void func2();
+private:
+ int member3;
+ void func3();
+};
+
+struct Y: protected X {
+ void doSomething();
+};
+
+class Z {
+public:
+ int member1;
+ void func1();
+protected:
+ int member2;
+ void func2();
+private:
+ int member3;
+ void func3();
+};
+
+void Y::doSomething() {
+ // RUN: c-index-test -code-completion-at=%s:30:9 %s | FileCheck -check-prefix=CHECK-SUPER-ACCESS %s
+ this->;
+
+ Z that;
+ // RUN: c-index-test -code-completion-at=%s:34:8 %s | FileCheck -check-prefix=CHECK-ACCESS %s
+ that.
+}
+
+// CHECK-SUPER-ACCESS: CXXMethod:{ResultType void}{TypedText doSomething}{LeftParen (}{RightParen )} (34)
+// CHECK-SUPER-ACCESS: CXXMethod:{ResultType void}{Informative X::}{TypedText func1}{LeftParen (}{RightParen )} (36)
+// CHECK-SUPER-ACCESS: CXXMethod:{ResultType void}{Informative X::}{TypedText func2}{LeftParen (}{RightParen )} (36) (inaccessible)
+// CHECK-SUPER-ACCESS: CXXMethod:{ResultType void}{Informative X::}{TypedText func3}{LeftParen (}{RightParen )} (36) (inaccessible)
+// CHECK-SUPER-ACCESS: FieldDecl:{ResultType int}{Informative X::}{TypedText member1} (37)
+// CHECK-SUPER-ACCESS: FieldDecl:{ResultType int}{Informative X::}{TypedText member2} (37) (inaccessible)
+// CHECK-SUPER-ACCESS: FieldDecl:{ResultType int}{Informative X::}{TypedText member3} (37) (inaccessible)
+// CHECK-SUPER-ACCESS: CXXMethod:{ResultType Y &}{TypedText operator=}{LeftParen (}{Placeholder const Y &}{RightParen )} (34)
+// CHECK-SUPER-ACCESS: CXXMethod:{ResultType X &}{Text X::}{TypedText operator=}{LeftParen (}{Placeholder const X &}{RightParen )} (36)
+// CHECK-SUPER-ACCESS: StructDecl:{TypedText X}{Text ::} (77)
+// CHECK-SUPER-ACCESS: StructDecl:{TypedText Y}{Text ::} (75)
+// CHECK-SUPER-ACCESS: CXXDestructor:{ResultType void}{Informative X::}{TypedText ~X}{LeftParen (}{RightParen )} (36)
+// CHECK-SUPER-ACCESS: CXXDestructor:{ResultType void}{TypedText ~Y}{LeftParen (}{RightParen )} (34)
+
+// CHECK-ACCESS: CXXMethod:{ResultType void}{TypedText func1}{LeftParen (}{RightParen )} (34)
+// CHECK-ACCESS: CXXMethod:{ResultType void}{TypedText func2}{LeftParen (}{RightParen )} (34) (inaccessible)
+// CHECK-ACCESS: CXXMethod:{ResultType void}{TypedText func3}{LeftParen (}{RightParen )} (34) (inaccessible)
+// CHECK-ACCESS: FieldDecl:{ResultType int}{TypedText member1} (35)
+// CHECK-ACCESS: FieldDecl:{ResultType int}{TypedText member2} (35) (inaccessible)
+// CHECK-ACCESS: FieldDecl:{ResultType int}{TypedText member3} (35) (inaccessible)
+// CHECK-ACCESS: CXXMethod:{ResultType Z &}{TypedText operator=}{LeftParen (}{Placeholder const Z &}{RightParen )} (34)
+// CHECK-ACCESS: ClassDecl:{TypedText Z}{Text ::} (75)
+// CHECK-ACCESS: CXXDestructor:{ResultType void}{TypedText ~Z}{LeftParen (}{RightParen )} (34)
+
+class P {
+protected:
+ int member;
+};
+
+class Q : public P {
+public:
+ using P::member;
+};
+
+void f(P x, Q y) {
+ // RUN: c-index-test -code-completion-at=%s:73:5 %s | FileCheck -check-prefix=CHECK-USING-INACCESSIBLE %s
+ x.; // member is inaccessible
+ // RUN: c-index-test -code-completion-at=%s:75:5 %s | FileCheck -check-prefix=CHECK-USING-ACCESSIBLE %s
+ y.; // member is accessible
+}
+
+// CHECK-USING-INACCESSIBLE: FieldDecl:{ResultType int}{TypedText member} (35) (inaccessible)
+// CHECK-USING-INACCESSIBLE: CXXMethod:{ResultType P &}{TypedText operator=}{LeftParen (}{Placeholder const P &}{RightParen )} (34)
+// CHECK-USING-INACCESSIBLE: ClassDecl:{TypedText P}{Text ::} (75)
+// CHECK-USING-INACCESSIBLE: CXXDestructor:{ResultType void}{TypedText ~P}{LeftParen (}{RightParen )} (34)
+
+// CHECK-USING-ACCESSIBLE: FieldDecl:{ResultType int}{TypedText member} (35)
+// CHECK-USING-ACCESSIBLE: CXXMethod:{ResultType Q &}{TypedText operator=}{LeftParen (}{Placeholder const Q &}{RightParen )} (34)
+// CHECK-USING-ACCESSIBLE: CXXMethod:{ResultType P &}{Text P::}{TypedText operator=}{LeftParen (}{Placeholder const P &}{RightParen )} (36)
+// CHECK-USING-ACCESSIBLE: ClassDecl:{TypedText P}{Text ::} (77)
+// CHECK-USING-ACCESSIBLE: ClassDecl:{TypedText Q}{Text ::} (75)
+// CHECK-USING-ACCESSIBLE: CXXDestructor:{ResultType void}{Informative P::}{TypedText ~P}{LeftParen (}{RightParen )} (36)
+// CHECK-USING-ACCESSIBLE: CXXDestructor:{ResultType void}{TypedText ~Q}{LeftParen (}{RightParen )} (34)
diff --git a/test/Index/complete-cxx-inline-methods.cpp b/test/Index/complete-cxx-inline-methods.cpp
new file mode 100644
index 000000000000..e25949df4cab
--- /dev/null
+++ b/test/Index/complete-cxx-inline-methods.cpp
@@ -0,0 +1,24 @@
+class MyCls {
+ void in_foo() {
+ vec.x = 0;
+ }
+ void out_foo();
+
+ struct Vec { int x, y; };
+ Vec vec;
+};
+
+void MyCls::out_foo() {
+ vec.x = 0;
+}
+
+// RUN: c-index-test -code-completion-at=%s:3:9 %s | FileCheck %s
+// RUN: c-index-test -code-completion-at=%s:12:7 %s | FileCheck %s
+// CHECK: CXXMethod:{ResultType MyCls::Vec &}{TypedText operator=}{LeftParen (}{Placeholder const MyCls::Vec &}{RightParen )} (34)
+// CHECK-NEXT: StructDecl:{TypedText Vec}{Text ::} (75)
+// CHECK-NEXT: FieldDecl:{ResultType int}{TypedText x} (35)
+// CHECK-NEXT: FieldDecl:{ResultType int}{TypedText y} (35)
+// CHECK-NEXT: CXXDestructor:{ResultType void}{TypedText ~Vec}{LeftParen (}{RightParen )} (34)
+// CHECK-NEXT: Completion contexts:
+// CHECK-NEXT: Dot member access
+// CHECK-NEXT: Container Kind: StructDecl
diff --git a/test/Index/complete-exprs.m b/test/Index/complete-exprs.m
index dfa114dcc095..08ec019003f3 100644
--- a/test/Index/complete-exprs.m
+++ b/test/Index/complete-exprs.m
@@ -10,7 +10,7 @@ typedef signed char BOOL;
__strong id global;
@implementation A
- (int)method:(id)param1 {
- void foo(id (^block)(id x, A* y));
+ void foo(bool (^block)(id x, A* y));
for(BOOL B = YES; ; ) { }
}
@end
@@ -29,6 +29,6 @@ __strong id global;
// CHECK-CC2: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
// RUN: c-index-test -code-completion-at=%s:15:1 -fobjc-arc -fobjc-nonfragile-abi %s | FileCheck -check-prefix=CHECK-CC3 %s
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:15:1 -fobjc-arc -fobjc-nonfragile-abi %s | FileCheck -check-prefix=CHECK-CC3 %s
-// CHECK-CC3: FunctionDecl:{ResultType void}{TypedText foo}{LeftParen (}{Placeholder ^id(id x, A *y)block}{RightParen )} (34)
+// CHECK-CC3: FunctionDecl:{ResultType void}{TypedText foo}{LeftParen (}{Placeholder ^bool(id x, A *y)block}{RightParen )} (34)
// CHECK-CC3: VarDecl:{ResultType id}{TypedText global} (50)
// CHECK-CC3: ParmDecl:{ResultType id}{TypedText param1} (34)
diff --git a/test/Index/complete-in-stringify.c b/test/Index/complete-in-stringify.c
new file mode 100644
index 000000000000..d5185496f8b7
--- /dev/null
+++ b/test/Index/complete-in-stringify.c
@@ -0,0 +1,17 @@
+const char *func(const char *);
+
+#define MORE __FILE__
+
+#define M(x) "1"#x
+#define N(x) func("2"#x MORE)
+
+void foo(const char *);
+
+int test() {
+ foo(M(x()));
+ foo(N(x()));
+}
+
+// RUN: c-index-test -code-completion-at=%s:11:11 %s | FileCheck %s
+// RUN: c-index-test -code-completion-at=%s:12:11 %s | FileCheck %s
+// CHECK: Natural language
diff --git a/test/Index/complete-interfaces.m b/test/Index/complete-interfaces.m
index 229ec2dcbe27..2f86c3d8f43c 100644
--- a/test/Index/complete-interfaces.m
+++ b/test/Index/complete-interfaces.m
@@ -27,6 +27,7 @@
// RUN: c-index-test -code-completion-at=%s:11:12 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: ObjCInterfaceDecl:{TypedText Int1}
// CHECK-CC2-NEXT: ObjCInterfaceDecl:{TypedText Int2}
+// CHECK-CC2-NEXT: ObjCInterfaceDecl:{TypedText Int3}
// CHECK-CC2-NEXT: ObjCInterfaceDecl:{TypedText Int4}
// RUN: c-index-test -code-completion-at=%s:11:19 %s | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: ObjCInterfaceDecl:{TypedText Int1}
@@ -41,3 +42,6 @@
// CHECK-CC5: ObjCInterfaceDecl:{TypedText Int1}
// CHECK-CC5-NEXT: ObjCInterfaceDecl:{TypedText Int3}
// CHECK-CC5-NEXT: ObjCInterfaceDecl:{TypedText Int4}
+
+
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:11:12 %s | FileCheck -check-prefix=CHECK-CC2 %s
diff --git a/test/Index/complete-macro-args.c b/test/Index/complete-macro-args.c
new file mode 100644
index 000000000000..ca36af1f1043
--- /dev/null
+++ b/test/Index/complete-macro-args.c
@@ -0,0 +1,22 @@
+struct Point {
+ float x;
+ float y;
+ float z;
+};
+
+#define MACRO2(x) x
+#define MACRO(x) MACRO2(x)
+
+void test(struct Point *p) {
+ p->x;
+ MACRO(p->x);
+}
+
+// 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
+// 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
diff --git a/test/Index/complete-macros.c b/test/Index/complete-macros.c
index eff42cad75a1..f1c1346a7db8 100644
--- a/test/Index/complete-macros.c
+++ b/test/Index/complete-macros.c
@@ -15,6 +15,15 @@ void f2() {
g(nil);
}
+#define variadic1(...)
+#define variadic2(args...)
+#define variadic3(args, ...)
+#define variadic4(first, second, args, ...)
+
+void test_variadic() {
+
+}
+
// RUN: c-index-test -code-completion-at=%s:7:1 %s | FileCheck -check-prefix=CHECK-CC1 %s
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:7:1 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: macro definition:{TypedText FOO}{LeftParen (}{Placeholder Arg1}{Comma , }{Placeholder Arg2}{RightParen )}
@@ -25,3 +34,8 @@ void f2() {
// RUN: c-index-test -code-completion-at=%s:15:5 %s | FileCheck -check-prefix=CHECK-CC3 %s
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:15:5 %s | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: macro definition:{TypedText nil} (65)
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:24:2 %s | FileCheck -check-prefix=CHECK-VARIADIC %s
+// CHECK-VARIADIC: macro definition:{TypedText variadic1}{LeftParen (}{Placeholder ...}{RightParen )} (70)
+// CHECK-VARIADIC: macro definition:{TypedText variadic2}{LeftParen (}{Placeholder args...}{RightParen )} (70)
+// CHECK-VARIADIC: macro definition:{TypedText variadic3}{LeftParen (}{Placeholder args, ...}{RightParen )} (70)
+// CHECK-VARIADIC: macro definition:{TypedText variadic4}{LeftParen (}{Placeholder first}{Comma , }{Placeholder second...}{Placeholder first, second...}{RightParen )} (70)
diff --git a/test/Index/complete-member-access.m b/test/Index/complete-member-access.m
index bd68deb5d115..48156d93ffba 100644
--- a/test/Index/complete-member-access.m
+++ b/test/Index/complete-member-access.m
@@ -37,11 +37,26 @@ int test_more_props(Sub *s) {
// RUN: c-index-test -code-completion-at=%s:21:7 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: ObjCPropertyDecl:{ResultType int}{TypedText prop1}
// CHECK-CC1: ObjCPropertyDecl:{ResultType float}{TypedText ProtoProp}
+// CHECK-CC1: Completion contexts:
+// CHECK-CC1-NEXT: Objective-C property access
+// CHECK-CC1-NEXT: Container Kind: ObjCInterfaceDecl
+// CHECK-CC1-NEXT: Container is complete
+// CHECK-CC1-NEXT: Container USR: c:objc(cs)Int
// RUN: c-index-test -code-completion-at=%s:22:8 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: ObjCIvarDecl:{ResultType int}{TypedText IVar} (35)
// CHECK-CC2: ObjCIvarDecl:{ResultType int}{TypedText SuperIVar} (37)
+// CHECK-CC2: Completion contexts:
+// CHECK-CC2-NEXT: Arrow member access
+// CHECK-CC2-NEXT: Container Kind: ObjCInterfaceDecl
+// CHECK-CC2-NEXT: Container is complete
+// CHECK-CC2-NEXT: Container USR: c:objc(cs)Int
// RUN: c-index-test -code-completion-at=%s:34:12 %s | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: ObjCInstanceMethodDecl:{ResultType int}{TypedText myOtherPropLikeThing} (37)
// CHECK-CC3: ObjCPropertyDecl:{ResultType int}{TypedText myProp} (35)
// CHECK-CC3: ObjCPropertyDecl:{ResultType int}{TypedText prop1} (35)
// CHECK-CC3: ObjCPropertyDecl:{ResultType float}{TypedText ProtoProp} (35)
+// CHECK-CC3: Completion contexts:
+// CHECK-CC3-NEXT: Objective-C property access
+// CHECK-CC3-NEXT: Container Kind: ObjCInterfaceDecl
+// CHECK-CC3-NEXT: Container is complete
+// CHECK-CC3-NEXT: Container USR: c:objc(cs)Sub \ No newline at end of file
diff --git a/test/Index/complete-objc-message.m b/test/Index/complete-objc-message.m
index 0ea33850560e..955ab6f144f9 100644
--- a/test/Index/complete-objc-message.m
+++ b/test/Index/complete-objc-message.m
@@ -181,16 +181,34 @@ void test_block_invoke(A *(^block1)(int),
[block1(5) init];
}
+@interface DO
+- (void)method:(in bycopy A*)ain result:(out byref A**)aout;
+@end
+
+void test_DO(DO *d, A* a) {
+ [d method:a aout:&a];
+}
+
// RUN: c-index-test -code-completion-at=%s:23:19 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: {TypedText categoryClassMethod}
// CHECK-CC1: {TypedText classMethod1:}{Placeholder (id)}{HorizontalSpace }{TypedText withKeyword:}{Placeholder (int)}
// CHECK-CC1: {TypedText classMethod2}
// CHECK-CC1: {TypedText new}
// CHECK-CC1: {TypedText protocolClassMethod}
+// CHECK-CC1: Completion contexts:
+// CHECK-CC1-NEXT: Objective-C class method
+// CHECK-CC1-NEXT: Container Kind: ObjCInterfaceDecl
+// CHECK-CC1-NEXT: Container is complete
+// CHECK-CC1-NEXT: Container USR: c:objc(cs)Foo
// RUN: c-index-test -code-completion-at=%s:24:8 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: {TypedText categoryInstanceMethod}
// CHECK-CC2: {TypedText instanceMethod1}
// CHECK-CC2: {TypedText protocolInstanceMethod:}{Placeholder (int)}
+// CHECK-CC2: Completion contexts:
+// CHECK-CC2-NEXT: Objective-C instance method
+// CHECK-CC2-NEXT: Container Kind: ObjCInterfaceDecl
+// CHECK-CC2-NEXT: Container is complete
+// CHECK-CC2-NEXT: Container USR: c:objc(cs)Foo
// RUN: c-index-test -code-completion-at=%s:61:16 %s | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: ObjCClassMethodDecl:{ResultType int}{TypedText MyClassMethod:}{Placeholder (id)}
// CHECK-CC3: ObjCClassMethodDecl:{ResultType int}{TypedText MyPrivateMethod}
@@ -218,6 +236,7 @@ void test_block_invoke(A *(^block1)(int),
// RUN: c-index-test -code-completion-at=%s:95:24 %s | FileCheck -check-prefix=CHECK-CC9 %s
// CHECK-CC9: ObjCInstanceMethodDecl:{ResultType int}{Informative Method:}{Informative Arg1:}{TypedText Arg2:}{Placeholder (int)}
// 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}
@@ -243,6 +262,7 @@ void test_block_invoke(A *(^block1)(int),
// CHECK-CCD: ObjCClassMethodDecl:{ResultType int}{Informative Method:}{TypedText Arg1:}{Placeholder (int)}{HorizontalSpace }{TypedText OtherArg:}{Placeholder (id)}
// CHECK-CCD: ObjCClassMethodDecl:{ResultType int}{Informative Method:}{TypedText SomeArg:}{Placeholder (int)}{HorizontalSpace }{TypedText OtherArg:}{Placeholder (id)}
// CHECK-CCD-NOT: ObjCClassMethodDecl:{ResultType int}{Informative Method:}{TypedText }
+// CHECK-CCD: Objective-C selector: Method:
// RUN: c-index-test -code-completion-at=%s:116:30 %s | FileCheck -check-prefix=CHECK-CCE %s
// CHECK-CCE: ObjCClassMethodDecl:{ResultType int}{Informative Method:}{Informative Arg1:}{TypedText Arg2:}{Placeholder (int)}
// CHECK-CCE: ObjCClassMethodDecl:{ResultType int}{Informative Method:}{Informative Arg1:}{TypedText OtherArg:}{Placeholder (id)}
@@ -311,3 +331,6 @@ void test_block_invoke(A *(^block1)(int),
// RUN: c-index-test -code-completion-at=%s:141:30 %s | FileCheck -check-prefix=CHECK-CCE %s
// RUN: c-index-test -code-completion-at=%s:175:12 %s | FileCheck -check-prefix=CHECK-CLASS-RESULT %s
+
+// RUN: c-index-test -code-completion-at=%s:189:6 %s | FileCheck -check-prefix=CHECK-DISTRIB-OBJECTS %s
+// CHECK-DISTRIB-OBJECTS: ObjCInstanceMethodDecl:{ResultType void}{TypedText method:}{Placeholder (in bycopyA *)}{HorizontalSpace }{TypedText result:}{Placeholder (out byrefA **)} (35)
diff --git a/test/Index/complete-qualified.cpp b/test/Index/complete-qualified.cpp
new file mode 100644
index 000000000000..20f5105a8c1c
--- /dev/null
+++ b/test/Index/complete-qualified.cpp
@@ -0,0 +1,20 @@
+template <typename X, typename Y>
+class C
+{
+};
+
+class Foo
+{
+public:
+ C<Foo, class Bar> c;
+};
+
+void foo()
+{
+ Foo::
+
+// RUN: c-index-test -code-completion-at=%s:14:8 %s -o - | FileCheck -check-prefix=CC1 %s
+// CHECK-CC1: FieldDecl:{ResultType C<Foo, class Bar>}{TypedText c} (35)
+// CHECK-CC1: ClassDecl:{TypedText Foo} (35)
+// CHECK-CC1: CXXMethod:{ResultType Foo &}{TypedText operator=}{LeftParen (}{Placeholder const Foo &}{RightParen )} (35)
+// CHECK-CC1: CXXDestructor:{ResultType void}{TypedText ~Foo}{LeftParen (}{RightParen )} (35)
diff --git a/test/Index/complete-stmt.c b/test/Index/complete-stmt.c
new file mode 100644
index 000000000000..98fa9df44db3
--- /dev/null
+++ b/test/Index/complete-stmt.c
@@ -0,0 +1,12 @@
+// Note: the run lines follow their respective tests, since line/column
+// matter in this test.
+
+
+void f(int x) {
+ if (x) {
+ }
+}
+
+// RUN: c-index-test -code-completion-at=%s:7:4 %s | FileCheck -check-prefix=CHECK-IF-ELSE %s
+// CHECK-IF-ELSE: NotImplemented:{TypedText else}{HorizontalSpace }{LeftBrace {}{VerticalSpace }{Placeholder statements}{VerticalSpace }{RightBrace }} (40)
+// CHECK-IF-ELSE: NotImplemented:{TypedText else}{HorizontalSpace }{Text if}{HorizontalSpace }{LeftParen (}{Placeholder expression}{RightParen )}{HorizontalSpace }{LeftBrace {}{VerticalSpace }{Placeholder statements}{VerticalSpace }{RightBrace }} (40)
diff --git a/test/Index/complete-synthesized.m b/test/Index/complete-synthesized.m
index 1a4858449f42..81f1ba186f1d 100644
--- a/test/Index/complete-synthesized.m
+++ b/test/Index/complete-synthesized.m
@@ -27,7 +27,7 @@
@dynamic prop3;
- (short)method2 {
- return prop4;
+ return _prop4;
}
- (short)method3 {
@@ -35,22 +35,12 @@
}
@end
-// RUN: c-index-test -code-completion-at=%s:24:1 -Xclang -fobjc-nonfragile-abi %s | FileCheck -check-prefix=CHECK-CC1 %s
-// CHECK-CC1: NotImplemented:{TypedText _Bool} (50)
-// CHECK-CC1: ObjCIvarDecl:{ResultType float}{TypedText _prop2} (35)
-// CHECK-CC1-NOT: prop2
-// CHECK-CC1: ObjCPropertyDecl:{ResultType short}{TypedText prop3} (35)
-// CHECK-CC1: ObjCPropertyDecl:{ResultType double}{TypedText prop4} (35)
-
-// RUN: c-index-test -code-completion-at=%s:30:2 -Xclang -fobjc-nonfragile-abi %s | FileCheck -check-prefix=CHECK-CC2 %s
-// CHECK-CC2: NotImplemented:{TypedText _Bool} (50)
-// CHECK-CC2: ObjCIvarDecl:{ResultType float}{TypedText _prop2} (35)
-// CHECK-CC2-NOT: prop3
-// CHECK-CC2: ObjCPropertyDecl:{ResultType double}{TypedText prop4} (35)
-
-// RUN: c-index-test -code-completion-at=%s:34:2 -Xclang -fobjc-nonfragile-abi %s | FileCheck -check-prefix=CHECK-CC3 %s
-// CHECK-CC3: NotImplemented:{TypedText _Bool} (50)
-// CHECK-CC3: ObjCIvarDecl:{ResultType float}{TypedText _prop2} (35)
-// CHECK-CC3: ObjCPropertyDecl:{ResultType double}{TypedText prop4}
-// CHECK-CC3-NOT: ObjCPropertyDecl:{ResultType double}{TypedText prop4} (35)
-// CHECK-CC1: restrict
+// RUN: c-index-test -code-completion-at=%s:24:1 -fobjc-nonfragile-abi -fobjc-default-synthesize-properties %s | FileCheck %s
+// RUN: c-index-test -code-completion-at=%s:30:2 -fobjc-nonfragile-abi -fobjc-default-synthesize-properties %s | FileCheck %s
+// RUN: c-index-test -code-completion-at=%s:34:2 -fobjc-nonfragile-abi -fobjc-default-synthesize-properties %s | FileCheck %s
+
+// CHECK: NotImplemented:{TypedText _Bool} (50)
+// CHECK: ObjCIvarDecl:{ResultType float}{TypedText _prop2} (35)
+// CHECK-NOT: prop2
+// CHECK-NOT: prop3
+// CHECK: ObjCIvarDecl:{ResultType double}{TypedText _prop4} (37)
diff --git a/test/Index/complete-with-annotations.cpp b/test/Index/complete-with-annotations.cpp
new file mode 100644
index 000000000000..afa8d9ed6607
--- /dev/null
+++ b/test/Index/complete-with-annotations.cpp
@@ -0,0 +1,23 @@
+class X {
+ void doSomething();
+
+ int field __attribute((annotate("one"), annotate("two"), annotate("three")));
+
+public __attribute__((annotate("some annotation"))):
+ void func2();
+ int member2 __attribute__((annotate("another annotation")));
+};
+
+void X::doSomething() {
+ // RUN: c-index-test -code-completion-at=%s:13:9 %s | FileCheck %s
+ this->;
+}
+
+// CHECK: CXXMethod:{ResultType void}{TypedText doSomething}{LeftParen (}{RightParen )} (34)
+// CHECK: FieldDecl:{ResultType int}{TypedText field} (35) ("three", "two", "one")
+// CHECK: CXXMethod:{ResultType void}{TypedText func2}{LeftParen (}{RightParen )} (34) ("some annotation")
+// CHECK: FieldDecl:{ResultType int}{TypedText member2} (35) ("another annotation", "some annotation")
+// CHECK: CXXMethod:{ResultType X &}{TypedText operator=}{LeftParen (}{Placeholder const X &}{RightParen )} (34)
+// CHECK: ClassDecl:{TypedText X}{Text ::} (75)
+// CHECK: CXXDestructor:{ResultType void}{TypedText ~X}{LeftParen (}{RightParen )} (34)
+
diff --git a/test/Index/cursor-ref-names.cpp b/test/Index/cursor-ref-names.cpp
new file mode 100644
index 000000000000..26174bca1afa
--- /dev/null
+++ b/test/Index/cursor-ref-names.cpp
@@ -0,0 +1,47 @@
+template <typename T>
+struct Base {
+ void func();
+ int operator[](T);
+};
+
+struct Sub: public Base<int> {
+ void func();
+};
+
+template <typename T>
+inline T myMax(T a, T b)
+{ return (a > b) ? a : b; }
+
+int main()
+{
+ Sub inst;
+ inst.func();
+ inst[1];
+ inst.operator[](1);
+
+ inst.Base<int>::operator[](1);
+ myMax<int>(1, 2);
+
+ return 0;
+}
+
+// RUN: c-index-test -test-load-source all %s | FileCheck %s
+// CHECK: cursor-ref-names.cpp:17:5: DeclStmt= Extent=[17:5 - 17:14]
+// CHECK: cursor-ref-names.cpp:17:9: VarDecl=inst:17:9 (Definition) Extent=[17:5 - 17:13]
+// CHECK: cursor-ref-names.cpp:17:5: TypeRef=struct Sub:7:8 Extent=[17:5 - 17:8]
+// CHECK: cursor-ref-names.cpp:17:9: CallExpr=Sub:7:8 Extent=[17:9 - 17:13]
+// CHECK: cursor-ref-names.cpp:18:5: CallExpr=func:8:10 Extent=[18:5 - 18:16]
+// CHECK: cursor-ref-names.cpp:18:10: MemberRefExpr=func:8:10 SingleRefName=[18:10 - 18:14] RefName=[18:10 - 18:14] Extent=[18:5 - 18:14]
+// CHECK: cursor-ref-names.cpp:18:5: DeclRefExpr=inst:17:9 Extent=[18:5 - 18:9]
+// CHECK: cursor-ref-names.cpp:19:5: CallExpr=operator[]:4:9 SingleRefName=[19:9 - 19:12] RefName=[19:9 - 19:10] RefName=[19:11 - 19:12] Extent=[19:5 - 19:12]
+// CHECK: cursor-ref-names.cpp:19:5: DeclRefExpr=inst:17:9 Extent=[19:5 - 19:9]
+// CHECK: cursor-ref-names.cpp:19:9: DeclRefExpr=operator[]:4:9 RefName=[19:9 - 19:10] RefName=[19:11 - 19:12] Extent=[19:9 - 19:12]
+// CHECK: cursor-ref-names.cpp:20:5: CallExpr=operator[]:4:9 Extent=[20:5 - 20:23]
+// CHECK: cursor-ref-names.cpp:20:10: MemberRefExpr=operator[]:4:9 SingleRefName=[20:10 - 20:20] RefName=[20:10 - 20:18] RefName=[20:18 - 20:19] RefName=[20:19 - 20:20] Extent=[20:5 - 20:20]
+// CHECK: cursor-ref-names.cpp:20:5: DeclRefExpr=inst:17:9 Extent=[20:5 - 20:9]
+// CHECK: cursor-ref-names.cpp:22:5: CallExpr=operator[]:4:9 Extent=[22:5 - 22:34]
+// CHECK: cursor-ref-names.cpp:22:21: MemberRefExpr=operator[]:4:9 SingleRefName=[22:10 - 22:31] RefName=[22:10 - 22:21] RefName=[22:21 - 22:29] RefName=[22:29 - 22:30] RefName=[22:30 - 22:31] Extent=[22:5 - 22:31]
+// CHECK: cursor-ref-names.cpp:22:5: DeclRefExpr=inst:17:9 Extent=[22:5 - 22:9]
+// CHECK: cursor-ref-names.cpp:22:10: TemplateRef=Base:2:8 Extent=[22:10 - 22:14]
+// CHECK: cursor-ref-names.cpp:23:5: CallExpr=myMax:12:10 Extent=[23:5 - 23:21]
+// CHECK: cursor-ref-names.cpp:23:5: DeclRefExpr=myMax:12:10 RefName=[23:5 - 23:10] RefName=[23:10 - 23:15] Extent=[23:5 - 23:15]
diff --git a/test/Index/file-refs.c b/test/Index/file-refs.c
new file mode 100644
index 000000000000..23042ea06f69
--- /dev/null
+++ b/test/Index/file-refs.c
@@ -0,0 +1,57 @@
+enum {
+ VALUE = 3
+};
+
+extern int glob_x;
+
+int f(int x) {
+ return x+glob_x+VALUE;
+}
+
+typedef struct {
+ int x;
+ int y;
+} Vector;
+
+int vector_get_x(Vector v) {
+ int x = v.x;
+ return x;
+}
+
+int f(int);
+int f(int);
+
+// RUN: c-index-test \
+
+// RUN: -file-refs-at=%s:2:5 \
+// CHECK: EnumConstantDecl=VALUE:2:3 (Definition)
+// CHECK-NEXT: EnumConstantDecl=VALUE:2:3 (Definition) =[2:3 - 2:8]
+// CHECK-NEXT: DeclRefExpr=VALUE:2:3 =[8:19 - 8:24]
+
+// RUN: -file-refs-at=%s:8:15 \
+// CHECK-NEXT: DeclRefExpr=glob_x:5:12
+// CHECK-NEXT: VarDecl=glob_x:5:12 =[5:12 - 5:18]
+// CHECK-NEXT: DeclRefExpr=glob_x:5:12 =[8:12 - 8:18]
+
+// RUN: -file-refs-at=%s:8:10 \
+// CHECK-NEXT: DeclRefExpr=x:7:11
+// CHECK-NEXT: ParmDecl=x:7:11 (Definition) =[7:11 - 7:12]
+// CHECK-NEXT: DeclRefExpr=x:7:11 =[8:10 - 8:11]
+
+// RUN: -file-refs-at=%s:12:7 \
+// CHECK-NEXT: FieldDecl=x:12:7 (Definition)
+// CHECK-NEXT: FieldDecl=x:12:7 (Definition) =[12:7 - 12:8]
+// CHECK-NEXT: MemberRefExpr=x:12:7 {{.*}} =[17:13 - 17:14]
+
+// RUN: -file-refs-at=%s:16:21 \
+// CHECK-NEXT: TypeRef=Vector:14:3
+// CHECK-NEXT: TypedefDecl=Vector:14:3 (Definition) =[14:3 - 14:9]
+// CHECK-NEXT: TypeRef=Vector:14:3 =[16:18 - 16:24]
+
+// RUN: -file-refs-at=%s:21:5 \
+// CHECK-NEXT: FunctionDecl=f:21:5
+// CHECK-NEXT: FunctionDecl=f:7:5 (Definition) =[7:5 - 7:6]
+// CHECK-NEXT: FunctionDecl=f:21:5 =[21:5 - 21:6]
+// CHECK-NEXT: FunctionDecl=f:22:5 =[22:5 - 22:6]
+
+// RUN: %s | FileCheck %s
diff --git a/test/Index/file-refs.cpp b/test/Index/file-refs.cpp
new file mode 100644
index 000000000000..a96d27c63071
--- /dev/null
+++ b/test/Index/file-refs.cpp
@@ -0,0 +1,104 @@
+namespace NS {
+ class C {
+ public:
+ C() { }
+ void m();
+ };
+}
+
+void NS::C::m() {
+ C c;
+ c.m();
+}
+
+void f() {
+ NS::C c1();
+ NS::C c2 = NS::C();
+}
+
+void over(int);
+void over(float);
+
+void test_over() {
+ over(0);
+ over(0.0f);
+}
+
+template <typename T>
+T tf(T t) {
+ return t;
+}
+
+namespace Test2 {
+
+struct S {
+ S(int x, int y);
+ S();
+};
+
+typedef S Cake;
+
+void f() {
+ Cake p;
+ p = Test2::S(0,2);
+ p = Test2::Cake(0,2);
+}
+
+}
+
+// RUN: c-index-test \
+
+// RUN: -file-refs-at=%s:9:7 \
+// CHECK: NamespaceRef=NS:1:11
+// CHECK-NEXT: Namespace=NS:1:11 (Definition) =[1:11 - 1:13]
+// CHECK-NEXT: NamespaceRef=NS:1:11 =[9:6 - 9:8]
+// CHECK-NEXT: NamespaceRef=NS:1:11 =[15:3 - 15:5]
+// CHECK-NEXT: NamespaceRef=NS:1:11 =[16:3 - 16:5]
+// CHECK-NEXT: NamespaceRef=NS:1:11 =[16:14 - 16:16]
+
+// RUN: -file-refs-at=%s:2:9 \
+// CHECK-NEXT: ClassDecl=C:2:9 (Definition)
+// CHECK-NEXT: ClassDecl=C:2:9 (Definition) =[2:9 - 2:10]
+// CHECK-NEXT: CXXConstructor=C:4:5 (Definition) =[4:5 - 4:6]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[9:10 - 9:11]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[10:3 - 10:4]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[15:7 - 15:8]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[16:7 - 16:8]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[16:18 - 16:19]
+
+// RUN: -file-refs-at=%s:16:18 \
+// CHECK-NEXT: CallExpr=C:4:5
+// CHECK-NEXT: ClassDecl=C:2:9 (Definition) =[2:9 - 2:10]
+// CHECK-NEXT: CXXConstructor=C:4:5 (Definition) =[4:5 - 4:6]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[9:10 - 9:11]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[10:3 - 10:4]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[15:7 - 15:8]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[16:7 - 16:8]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[16:18 - 16:19]
+
+// RUN: -file-refs-at=%s:20:8 \
+// CHECK-NEXT: FunctionDecl=over:20:6
+// CHECK-NEXT: FunctionDecl=over:20:6 =[20:6 - 20:10]
+// CHECK-NEXT: DeclRefExpr=over:20:6 =[24:3 - 24:7]
+
+// RUN: -file-refs-at=%s:28:1 \
+// CHECK-NEXT: TypeRef=T:27:20
+// FIXME: Missing TemplateTypeParameter=T:27:20 (Definition)
+// CHECK-NEXT: TypeRef=T:27:20 =[28:1 - 28:2]
+// CHECK-NEXT: TypeRef=T:27:20 =[28:6 - 28:7]
+
+// RUN: -file-refs-at=%s:43:14 \
+// CHECK-NEXT: CallExpr=S:35:3
+// CHECK-NEXT: StructDecl=S:34:8 (Definition) =[34:8 - 34:9]
+// CHECK-NEXT: CXXConstructor=S:35:3 =[35:3 - 35:4]
+// CHECK-NEXT: CXXConstructor=S:36:3 =[36:3 - 36:4]
+// CHECK-NEXT: TypeRef=struct Test2::S:34:8 =[39:9 - 39:10]
+// CHECK-NEXT: TypeRef=struct Test2::S:34:8 =[43:14 - 43:15]
+
+// RUN: -file-refs-at=%s:44:16 \
+// CHECK-NEXT: CallExpr=S:35:3
+// CHECK-NEXT: TypedefDecl=Cake:39:11 (Definition) =[39:11 - 39:15]
+// CHECK-NEXT: TypeRef=Cake:39:11 =[42:3 - 42:7]
+// CHECK-NEXT: TypeRef=Cake:39:11 =[44:14 - 44:18]
+
+// RUN: %s | FileCheck %s
diff --git a/test/Index/file-refs.m b/test/Index/file-refs.m
new file mode 100644
index 000000000000..2267259d58a2
--- /dev/null
+++ b/test/Index/file-refs.m
@@ -0,0 +1,87 @@
+@class Foo;
+
+@interface Foo
+-(id)setWithInt:(int)i andFloat:(float)f;
+@end
+
+@implementation Foo
+-(id)setWithInt:(int)i andFloat:(float)f {
+ return self;
+}
+@end
+
+void test(Foo *foo) {
+ [foo setWithInt:0 andFloat:0];
+ [foo setWithInt: 2 andFloat: 3];
+}
+
+@protocol Prot1
+-(void)protMeth;
+@end
+
+@protocol Prot2<Prot1>
+@end
+
+@interface Base<Prot2>
+@end
+
+@interface Sub : Base
+-(void)protMeth;
+@end
+
+@implementation Sub
+-(void)protMeth {}
+@end
+
+void test2(Sub *s, id<Prot1> p) {
+ [s protMeth];
+ [p protMeth];
+}
+
+
+// RUN: c-index-test \
+
+// RUN: -file-refs-at=%s:7:18 \
+// CHECK: ObjCImplementationDecl=Foo:7:17 (Definition)
+// CHECK-NEXT: ObjCClassRef=Foo:3:12 =[1:8 - 1:11]
+// CHECK-NEXT: ObjCInterfaceDecl=Foo:3:12 =[3:12 - 3:15]
+// CHECK-NEXT: ObjCImplementationDecl=Foo:7:17 (Definition) =[7:17 - 7:20]
+// CHECK-NEXT: ObjCClassRef=Foo:3:12 =[13:11 - 13:14]
+
+// RUN: -file-refs-at=%s:4:10 \
+// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::4:1
+// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::4:1 =[4:6 - 4:16]
+// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::8:1 (Definition) [Overrides @4:1] =[8:6 - 8:16]
+// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:1 =[14:8 - 14:18]
+// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:1 =[15:8 - 15:18]
+
+// RUN: -file-refs-at=%s:15:27 \
+// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:1
+// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::4:1 =[4:24 - 4:32]
+// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::8:1 (Definition) [Overrides @4:1] =[8:24 - 8:32]
+// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:1 =[14:21 - 14:29]
+// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:1 =[15:22 - 15:30]
+
+// RUN: -file-refs-at=%s:18:13 \
+// CHECK-NEXT: ObjCProtocolDecl=Prot1:18:11 (Definition)
+// CHECK-NEXT: ObjCProtocolDecl=Prot1:18:11 (Definition) =[18:11 - 18:16]
+// CHECK-NEXT: ObjCProtocolRef=Prot1:18:11 =[22:17 - 22:22]
+// CHECK-NEXT: ObjCProtocolRef=Prot1:18:11 =[36:23 - 36:28]
+
+// RUN: -file-refs-at=%s:38:10 \
+// CHECK-NEXT: ObjCMessageExpr=protMeth:19:1
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:19:1 =[19:8 - 19:16]
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:29:1 [Overrides @19:1] =[29:8 - 29:16]
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:33:1 (Definition) [Overrides @29:1] =[33:8 - 33:16]
+// CHECK-NEXT: ObjCMessageExpr=protMeth:29:1 =[37:6 - 37:14]
+// CHECK-NEXT: ObjCMessageExpr=protMeth:19:1 =[38:6 - 38:14]
+
+// RUN: -file-refs-at=%s:33:12 \
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:33:1 (Definition) [Overrides @29:1]
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:19:1 =[19:8 - 19:16]
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:29:1 [Overrides @19:1] =[29:8 - 29:16]
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:33:1 (Definition) [Overrides @29:1] =[33:8 - 33:16]
+// CHECK-NEXT: ObjCMessageExpr=protMeth:29:1 =[37:6 - 37:14]
+// CHECK-NEXT: ObjCMessageExpr=protMeth:19:1 =[38:6 - 38:14]
+
+// RUN: %s | FileCheck %s
diff --git a/test/Index/get-cursor-macro-args.h b/test/Index/get-cursor-macro-args.h
new file mode 100644
index 000000000000..40ec8dc0b81f
--- /dev/null
+++ b/test/Index/get-cursor-macro-args.h
@@ -0,0 +1,16 @@
+@interface MyClass
++(void)meth;
+@end
+
+#define MACRO2(x) x
+#define MACRO(x) MACRO2(x)
+
+void test() {
+ MACRO([MyClass meth]);
+}
+
+#define INVOKE(METHOD, CLASS) [CLASS METHOD]
+
+void test2() {
+ INVOKE(meth, MyClass);
+}
diff --git a/test/Index/get-cursor-macro-args.m b/test/Index/get-cursor-macro-args.m
new file mode 100644
index 000000000000..4e0ac78fe059
--- /dev/null
+++ b/test/Index/get-cursor-macro-args.m
@@ -0,0 +1,19 @@
+// Test without PCH
+// RUN: c-index-test -cursor-at=%S/get-cursor-macro-args.h:9:12 \
+// RUN: -cursor-at=%S/get-cursor-macro-args.h:9:21 \
+// RUN: -cursor-at=%S/get-cursor-macro-args.h:15:12 \
+// RUN: -cursor-at=%S/get-cursor-macro-args.h:15:20 \
+// RUN: %s -include get-cursor-macro-args.h | FileCheck %s
+
+// Test with PCH
+// RUN: c-index-test -write-pch %t.pch -x objective-c-header %S/get-cursor-macro-args.h
+// RUN: c-index-test -cursor-at=%S/get-cursor-macro-args.h:9:12 \
+// RUN: -cursor-at=%S/get-cursor-macro-args.h:9:21 \
+// RUN: -cursor-at=%S/get-cursor-macro-args.h:15:12 \
+// RUN: -cursor-at=%S/get-cursor-macro-args.h:15:20 \
+// RUN: %s -include-pch %t.pch | FileCheck %s
+
+// CHECK: ObjCClassRef=MyClass:1:12
+// CHECK-NEXT: ObjCMessageExpr=meth:2:1
+// CHECK-NEXT: ObjCMessageExpr=meth:2:1
+// CHECK-NEXT: ObjCClassRef=MyClass:1:12
diff --git a/test/Index/get-cursor.c b/test/Index/get-cursor.c
new file mode 100644
index 000000000000..23a4b5cb5370
--- /dev/null
+++ b/test/Index/get-cursor.c
@@ -0,0 +1,14 @@
+struct _MyS {
+ int foo;
+} MyS;
+
+struct _MyS ww;
+
+// RUN: c-index-test -cursor-at=%s:1:9 \
+// RUN: -cursor-at=%s:2:9 \
+// RUN: -cursor-at=%s:5:9 \
+// RUN: %s | FileCheck %s
+
+// CHECK: StructDecl=_MyS:1:8 (Definition)
+// CHECK: FieldDecl=foo:2:7 (Definition)
+// CHECK: TypeRef=struct _MyS:1:8
diff --git a/test/Index/get-cursor.cpp b/test/Index/get-cursor.cpp
index 2aa76c472569..441ed1cdabe6 100644
--- a/test/Index/get-cursor.cpp
+++ b/test/Index/get-cursor.cpp
@@ -35,6 +35,14 @@ void test() {
X foo;
}
+// RUN: c-index-test -cursor-at=%s:6:4 %s | FileCheck -check-prefix=CHECK-COMPLETION-1 %s
+// CHECK-COMPLETION-1: CXXConstructor=X:6:3
+// CHECK-COMPLETION-1-NEXT: Completion string: {TypedText X}{LeftParen (}{Placeholder int}{Comma , }{Placeholder int}{RightParen )}
+
+// RUN: c-index-test -cursor-at=%s:31:16 %s | FileCheck -check-prefix=CHECK-COMPLETION-2 %s
+// CHECK-COMPLETION-2: CXXMethod=getAnotherX:31:5 (Definition)
+// CHECK-COMPLETION-2-NEXT: Completion string: {ResultType X}{TypedText getAnotherX}{LeftParen (}{RightParen )}
+
// RUN: c-index-test -cursor-at=%s:12:20 %s | FileCheck -check-prefix=CHECK-VALUE-REF %s
// RUN: c-index-test -cursor-at=%s:13:21 %s | FileCheck -check-prefix=CHECK-VALUE-REF %s
// RUN: c-index-test -cursor-at=%s:13:28 %s | FileCheck -check-prefix=CHECK-VALUE-REF %s
@@ -68,3 +76,7 @@ void test() {
// RUN: c-index-test -cursor-at=%s:35:5 %s | FileCheck -check-prefix=CHECK-DECL %s
// CHECK-DECL: VarDecl=foo:35:5
+
+// RUN: c-index-test -cursor-at=%s:21:3 %s | FileCheck -check-prefix=CHECK-MEMBER %s
+// CHECK-MEMBER: FieldDecl=member:21:7 (Definition)
+// CHECK-MEMBER-NEXT: Completion string: {ResultType int}{TypedText member}
diff --git a/test/Index/get-cursor.m b/test/Index/get-cursor.m
new file mode 100644
index 000000000000..69e4f251e821
--- /dev/null
+++ b/test/Index/get-cursor.m
@@ -0,0 +1,37 @@
+// Test is line- and column-sensitive. Run lines are below.
+
+@interface rdar9771715
+@property (readonly) int foo1;
+@property (readwrite) int foo2;
+@end
+
+@class Foo;
+
+@interface rdar9535717 {
+ __weak Foo *foo;
+}
+@end
+
+@interface Test1 {
+ id _name;
+}
+@end
+@interface Test1 ()
+- (id)name;
+@end
+@interface Test1 ()
+@property (copy) id name;
+@end
+@implementation Test1
+@synthesize name = _name;
+@end
+
+// RUN: c-index-test -cursor-at=%s:4:28 -cursor-at=%s:5:28 %s | FileCheck -check-prefix=CHECK-PROP %s
+// CHECK-PROP: ObjCPropertyDecl=foo1:4:26
+// CHECK-PROP: ObjCPropertyDecl=foo2:5:27
+
+// RUN: c-index-test -cursor-at=%s:11:11 %s -ccc-host-triple x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-WITH-WEAK %s
+// CHECK-WITH-WEAK: ObjCClassRef=Foo:8:8
+
+// RUN: c-index-test -cursor-at=%s:20:10 %s | FileCheck -check-prefix=CHECK-METHOD %s
+// CHECK-METHOD: ObjCInstanceMethodDecl=name:20:1
diff --git a/test/Index/getcursor-pp-pch.c b/test/Index/getcursor-pp-pch.c
new file mode 100644
index 000000000000..d68384c66067
--- /dev/null
+++ b/test/Index/getcursor-pp-pch.c
@@ -0,0 +1,43 @@
+
+
+
+typedef int T;
+void OBSCURE(func)(int x) {
+ OBSCURE(T) DECORATION value;
+}
+
+
+// Without PCH
+// RUN: c-index-test -cursor-at=%s.h:1:11 \
+// RUN: -cursor-at=%s.h:2:14 \
+// RUN: -cursor-at=%s.h:4:5 \
+// RUN: -cursor-at=%s.h:5:5 \
+// RUN: -cursor-at=%s.h:5:14 \
+// RUN: -cursor-at=%s:5:7 \
+// RUN: -cursor-at=%s:6:6 \
+// RUN: -cursor-at=%s:6:19 \
+// RUN: -include %s.h %s | FileCheck %s
+
+// With PCH
+// RUN: c-index-test -write-pch %t.h.pch %s.h -Xclang -detailed-preprocessing-record
+// RUN: c-index-test -cursor-at=%s.h:1:11 \
+// RUN: -cursor-at=%s.h:2:14 \
+// RUN: -cursor-at=%s.h:4:5 \
+// RUN: -cursor-at=%s.h:5:5 \
+// RUN: -cursor-at=%s.h:5:14 \
+// RUN: -cursor-at=%s:5:7 \
+// RUN: -cursor-at=%s:6:6 \
+// RUN: -cursor-at=%s:6:19 \
+// RUN: -include %t.h %s | FileCheck %s
+
+// From header
+// CHECK: macro definition=OBSCURE
+// CHECK: macro definition=DECORATION
+// CHECK: macro expansion=DECORATION:2:9
+// CHECK: macro expansion=OBSCURE:1:9
+// CHECK: macro expansion=DECORATION:2:9
+
+// From main file
+// CHECK: macro expansion=OBSCURE:1:9
+// CHECK: macro expansion=OBSCURE:1:9
+// CHECK: macro expansion=DECORATION:2:9
diff --git a/test/Index/getcursor-pp-pch.c.h b/test/Index/getcursor-pp-pch.c.h
new file mode 100644
index 000000000000..c24a39c0e9db
--- /dev/null
+++ b/test/Index/getcursor-pp-pch.c.h
@@ -0,0 +1,5 @@
+#define OBSCURE(X) X
+#define DECORATION
+
+DECORATION
+OBSCURE(DECORATION)
diff --git a/test/Index/in-class-init.cpp b/test/Index/in-class-init.cpp
new file mode 100644
index 000000000000..61431caafd75
--- /dev/null
+++ b/test/Index/in-class-init.cpp
@@ -0,0 +1,6 @@
+struct S {
+ int field = 2;
+};
+
+// RUN: c-index-test -test-load-source all -std=c++11 %s | FileCheck %s
+// CHECK: 2:7: FieldDecl=field:2:7 (Definition) Extent=[2:3 - 2:16]
diff --git a/test/Index/index-templates.cpp b/test/Index/index-templates.cpp
index abc95545c53b..05068df5c599 100644
--- a/test/Index/index-templates.cpp
+++ b/test/Index/index-templates.cpp
@@ -100,7 +100,7 @@ template class Pair<int, int>;
template<typename T, typename U>
struct SuperPair : Pair<int, int>, Pair<T, U> { };
-// RUN: c-index-test -test-load-source all %s | FileCheck -check-prefix=CHECK-LOAD %s
+// RUN: c-index-test -test-load-source all -fno-delayed-template-parsing %s | FileCheck -check-prefix=CHECK-LOAD %s
// CHECK-LOAD: index-templates.cpp:4:6: FunctionTemplate=f:4:6 Extent=[3:1 - 4:22]
// CHECK-LOAD: index-templates.cpp:3:19: TemplateTypeParameter=T:3:19 (Definition) Extent=[3:10 - 3:20]
// CHECK-LOAD: index-templates.cpp:3:24: NonTypeTemplateParameter=Value:3:24 (Definition) Extent=[3:22 - 3:29]
@@ -135,7 +135,7 @@ struct SuperPair : Pair<int, int>, Pair<T, U> { };
// CHECK-LOAD: index-templates.cpp:30:21: TypeRef=struct Z2:20:8 Extent=[30:21 - 30:23]
// CHECK-LOAD: index-templates.cpp:35:16: VarDecl=OneDimension:35:16 (Definition) Extent=[35:1 - 35:32]
// CHECK-LOAD: index-templates.cpp:35:31: UnexposedExpr= Extent=[35:31 - 35:32]
-// CHECK-LOAD: index-templates.cpp:35:31: UnexposedExpr= Extent=[35:31 - 35:32]
+// CHECK-LOAD: index-templates.cpp:35:31: IntegerLiteral= Extent=[35:31 - 35:32]
// CHECK-LOAD: index-templates.cpp:37:8: ClassTemplate=array:37:8 (Definition) Extent=[36:1 - 37:17]
// CHECK-LOAD: index-templates.cpp:36:19: TemplateTypeParameter=T:36:19 (Definition) Extent=[36:10 - 36:20]
// CHECK-LOAD: index-templates.cpp:36:31: NonTypeTemplateParameter=Dimensions:36:31 (Definition) Extent=[36:22 - 36:56]
@@ -157,11 +157,11 @@ struct SuperPair : Pair<int, int>, Pair<T, U> { };
// CHECK-LOAD: index-templates.cpp:53:6: FunctionDecl=template_exprs:53:6 (Definition)
// CHECK-LOAD: index-templates.cpp:54:3: CallExpr=f:4:6 Extent=[54:3 - 54:68]
// CHECK-LOAD: index-templates.cpp:54:3: UnexposedExpr=f:4:6 Extent=[54:3 - 54:35]
-// CHECK-LOAD: index-templates.cpp:54:3: DeclRefExpr=f:4:6 Extent=[54:3 - 54:35]
+// CHECK-LOAD: index-templates.cpp:54:3: DeclRefExpr=f:4:6 RefName=[54:3 - 54:4] RefName=[54:4 - 54:35] Extent=[54:3 - 54:35]
// CHECK-LOAD: index-templates.cpp:54:5: TypeRef=Unsigned:42:18 Extent=[54:5 - 54:13]
// CHECK-LOAD: index-templates.cpp:54:15: DeclRefExpr=OneDimension:35:16 Extent=[54:15 - 54:27]
// CHECK-LOAD: index-templates.cpp:54:29: TemplateRef=array:37:8 Extent=[54:29 - 54:34]
-// CHECK-LOAD: index-templates.cpp:55:8: MemberRefExpr=getAs:50:26 Extent=[55:3 - 55:23]
+// CHECK-LOAD: index-templates.cpp:55:8: MemberRefExpr=getAs:50:26 SingleRefName=[55:8 - 55:13] RefName=[55:8 - 55:13] Extent=[55:3 - 55:23]
// CHECK-LOAD: index-templates.cpp:55:3: CallExpr=Z4:49:8 Extent=[55:3 - 55:7]
// CHECK-LOAD: index-templates.cpp:55:14: TypeRef=Unsigned:42:18 Extent=[55:14 - 55:22]
// CHECK-LOAD: index-templates.cpp:68:6: FunctionTemplate=unresolved_exprs:68:6 (Definition)
@@ -180,7 +180,7 @@ struct SuperPair : Pair<int, int>, Pair<T, U> { };
// CHECK-LOAD: index-templates.cpp:101:36: C++ base class specifier=Pair<T, U>:76:8 [access=public isVirtual=false] Extent=[101:36 - 101:46]
-// RUN: c-index-test -test-load-source-usrs all %s | FileCheck -check-prefix=CHECK-USRS %s
+// RUN: c-index-test -test-load-source-usrs all -fno-delayed-template-parsing %s | FileCheck -check-prefix=CHECK-USRS %s
// CHECK-USRS: index-templates.cpp c:@FT@>3#T#Nt0.0#t>2#T#Nt1.0f#>t0.22S0_# Extent=[3:1 - 4:22]
// CHECK-USRS: index-templates.cpp c:index-templates.cpp@70 Extent=[3:10 - 3:20]
// CHECK-USRS: index-templates.cpp c:index-templates.cpp@82 Extent=[3:22 - 3:29]
diff --git a/test/Index/load-stmts.cpp b/test/Index/load-stmts.cpp
index cb9d3f2b609f..ed0debdd762b 100644
--- a/test/Index/load-stmts.cpp
+++ b/test/Index/load-stmts.cpp
@@ -117,7 +117,7 @@ void casts(int *ip) {
(void)reinterpret_cast<float *>(ip);
}
-// RUN: c-index-test -test-load-source all %s | FileCheck %s
+// RUN: c-index-test -test-load-source all -fno-delayed-template-parsing %s | FileCheck %s
// CHECK: load-stmts.cpp:1:13: TypedefDecl=T:1:13 (Definition) Extent=[1:1 - 1:14]
// CHECK: load-stmts.cpp:2:8: StructDecl=X:2:8 (Definition) Extent=[2:1 - 2:23]
// CHECK: load-stmts.cpp:2:16: FieldDecl=a:2:16 (Definition) Extent=[2:12 - 2:17]
@@ -132,17 +132,17 @@ void casts(int *ip) {
// CHECK: load-stmts.cpp:4:23: DeclRefExpr=x:3:12 Extent=[4:23 - 4:24]
// CHECK: load-stmts.cpp:4:19: UnexposedExpr=z:4:19 Extent=[4:19 - 4:20]
// CHECK: load-stmts.cpp:4:19: DeclRefExpr=z:4:19 Extent=[4:19 - 4:20]
-// CHECK: load-stmts.cpp:4:26: UnexposedExpr= Extent=[4:26 - 4:29]
+// CHECK: load-stmts.cpp:4:26: UnaryOperator= Extent=[4:26 - 4:29]
// CHECK: load-stmts.cpp:4:28: DeclRefExpr=x:3:12 Extent=[4:28 - 4:29]
// CHECK: load-stmts.cpp:6:10: VarDecl=z2:6:10 (Definition) Extent=[6:7 - 6:17]
// CHECK: load-stmts.cpp:6:7: TypeRef=T:1:13 Extent=[6:7 - 6:8]
-// CHECK: load-stmts.cpp:6:15: UnexposedExpr= Extent=[6:15 - 6:17]
+// CHECK: load-stmts.cpp:6:15: UnaryOperator= Extent=[6:15 - 6:17]
// CHECK: load-stmts.cpp:6:16: DeclRefExpr=x:3:12 Extent=[6:16 - 6:17]
// CHECK: load-stmts.cpp:6:10: UnexposedExpr=z2:6:10 Extent=[6:10 - 6:12]
// CHECK: load-stmts.cpp:6:10: DeclRefExpr=z2:6:10 Extent=[6:10 - 6:12]
// CHECK: load-stmts.cpp:7:13: VarDecl=z3:7:13 (Definition) Extent=[7:10 - 7:20]
// CHECK: load-stmts.cpp:7:10: TypeRef=T:1:13 Extent=[7:10 - 7:11]
-// CHECK: load-stmts.cpp:7:18: UnexposedExpr= Extent=[7:18 - 7:20]
+// CHECK: load-stmts.cpp:7:18: UnaryOperator= Extent=[7:18 - 7:20]
// CHECK: load-stmts.cpp:7:19: DeclRefExpr=x:3:12 Extent=[7:19 - 7:20]
// CHECK: load-stmts.cpp:7:13: UnexposedExpr=z3:7:13 Extent=[7:13 - 7:15]
// CHECK: load-stmts.cpp:7:13: DeclRefExpr=z3:7:13 Extent=[7:13 - 7:15]
@@ -150,7 +150,7 @@ void casts(int *ip) {
// CHECK: load-stmts.cpp:8:11: TypeRef=T:1:13 Extent=[8:11 - 8:12]
// CHECK: load-stmts.cpp:8:18: DeclRefExpr=x:3:12 Extent=[8:18 - 8:19]
// CHECK: load-stmts.cpp:8:13: DeclRefExpr=z4:8:13 Extent=[8:13 - 8:15]
-// CHECK: load-stmts.cpp:9:8: UnexposedExpr= Extent=[9:8 - 9:10]
+// CHECK: load-stmts.cpp:9:8: IntegerLiteral= Extent=[9:8 - 9:10]
// CHECK: load-stmts.cpp:14:7: ClassDecl=A:14:7 (Definition) Extent=[14:1 - 16:2]
// CHECK: load-stmts.cpp:15:8: CXXMethod=doA:15:8 Extent=[15:3 - 15:13]
// CHECK: load-stmts.cpp:18:7: ClassDecl=B:18:7 (Definition) Extent=[18:1 - 20:2]
@@ -202,8 +202,9 @@ void casts(int *ip) {
// CHECK: load-stmts.cpp:80:21: DeclRefExpr=j:79:44 Extent=[80:21 - 80:22]
// CHECK: load-stmts.cpp:82:9: TypeRef=Integer:81:15 Extent=[82:9 - 82:16]
// CHECK: load-stmts.cpp:82:17: DeclRefExpr=i:79:37 Extent=[82:17 - 82:18]
-// CHECK: load-stmts.cpp:83:3: UnexposedExpr=i:79:37 Extent=[83:3 - 83:13]
+// CHECK: load-stmts.cpp:83:3: CStyleCastExpr= Extent=[83:3 - 83:13]
// CHECK: load-stmts.cpp:83:4: TypeRef=Integer:81:15 Extent=[83:4 - 83:11]
+// CHECK: load-stmts.cpp:83:12: UnexposedExpr=i:79:37 Extent=[83:12 - 83:13]
// CHECK: load-stmts.cpp:83:12: DeclRefExpr=i:79:37 Extent=[83:12 - 83:13]
// CHECK: load-stmts.cpp:84:3: UnexposedExpr= Extent=[84:3 - 84:12]
// CHECK: load-stmts.cpp:84:3: TypeRef=Integer:81:15 Extent=[84:3 - 84:10]
@@ -225,5 +226,6 @@ void casts(int *ip) {
// CHECK: load-stmts.cpp:108:2: LabelStmt=start_over Extent=[108:2 - 109:28]
// CHECK: load-stmts.cpp:109:17: LabelRef=start_over:108:2 Extent=[109:17 - 109:27]
// CHECK: load-stmts.cpp:113:10: LabelRef=start_over:108:2 Extent=[113:10 - 113:20]
-// CHECK: load-stmts.cpp:117:9: UnexposedExpr=ip:116:17 Extent=[117:9 - 117:38]
+// CHECK: load-stmts.cpp:117:35: UnexposedExpr=ip:116:17 Extent=[117:35 - 117:37]
+// CHECK: load-stmts.cpp:117:35: DeclRefExpr=ip:116:17 Extent=[117:35 - 117:37]
diff --git a/test/Index/local-symbols.m b/test/Index/local-symbols.m
index 3a479522944e..01c8305c2af3 100644
--- a/test/Index/local-symbols.m
+++ b/test/Index/local-symbols.m
@@ -31,14 +31,14 @@
// CHECK: local-symbols.m:7:3: TypeRef=id:0:0 Extent=[7:3 - 7:5]
// CHECK: local-symbols.m:9:1: ObjCInstanceMethodDecl=bar:9:1 Extent=[9:1 - 9:12]
// CHECK: local-symbols.m:9:4: TypeRef=id:0:0 Extent=[9:4 - 9:6]
-// CHECK: local-symbols.m:12:1: ObjCImplementationDecl=Foo:12:1 (Definition) Extent=[12:1 - 16:2]
+// CHECK: local-symbols.m:12:17: ObjCImplementationDecl=Foo:12:17 (Definition) Extent=[12:1 - 16:2]
// CHECK: local-symbols.m:13:1: ObjCInstanceMethodDecl=bar:13:1 (Definition) [Overrides @9:1] Extent=[13:1 - 15:2]
// CHECK: local-symbols.m:13:4: TypeRef=id:0:0 Extent=[13:4 - 13:6]
// CHECK: local-symbols.m:14:10: UnexposedExpr= Extent=[14:10 - 14:11]
-// CHECK: local-symbols.m:14:10: UnexposedExpr= Extent=[14:10 - 14:11]
-// CHECK: local-symbols.m:20:1: ObjCProtocolDecl=Prot8380046:20:1 (Definition) Extent=[20:1 - 21:5]
+// CHECK: local-symbols.m:14:10: IntegerLiteral= Extent=[14:10 - 14:11]
+// CHECK: local-symbols.m:20:11: ObjCProtocolDecl=Prot8380046:20:11 (Definition) Extent=[20:1 - 21:5]
// CHECK: local-symbols.m:23:12: ObjCInterfaceDecl=R8380046:23:12 Extent=[23:1 - 24:5]
// CHECK: local-symbols.m:26:12: ObjCCategoryDecl=:26:12 Extent=[26:1 - 27:5]
// CHECK: local-symbols.m:26:12: ObjCClassRef=R8380046:23:12 Extent=[26:12 - 26:20]
-// CHECK: local-symbols.m:26:25: ObjCProtocolRef=Prot8380046:20:1 Extent=[26:25 - 26:36]
+// CHECK: local-symbols.m:26:25: ObjCProtocolRef=Prot8380046:20:11 Extent=[26:25 - 26:36]
diff --git a/test/Index/nested-binaryoperators.cpp b/test/Index/nested-binaryoperators.cpp
index db5efe2cc8c2..57adc6b54664 100644
--- a/test/Index/nested-binaryoperators.cpp
+++ b/test/Index/nested-binaryoperators.cpp
@@ -165,1818 +165,1819 @@ int foo(uint c) {
// CHECK: 2:5: FunctionDecl=foo:2:5 (Definition) Extent=[2:1 - 161:2]
// CHECK: 2:14: ParmDecl=c:2:14 (Definition) Extent=[2:9 - 2:15]
// CHECK: 2:9: TypeRef=uint:1:22 Extent=[2:9 - 2:13]
-// CHECK: 2:17: UnexposedStmt= Extent=[2:17 - 161:2]
-// CHECK: 3:3: UnexposedStmt= Extent=[3:3 - 160:52]
+// CHECK: 2:17: CompoundStmt= Extent=[2:17 - 161:2]
+// CHECK: 3:3: ReturnStmt= Extent=[3:3 - 160:52]
// CHECK: 3:10: UnexposedExpr= Extent=[3:10 - 160:52]
-// CHECK: 3:10: UnexposedExpr= Extent=[3:10 - 160:52]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 160:51]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 160:19]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 159:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 158:51]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 158:19]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 157:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 156:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 155:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 154:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 153:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 152:51]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 152:19]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 151:51]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 151:19]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 150:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 149:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 148:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 147:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 146:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 145:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 144:51]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 144:19]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 143:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 142:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 141:81]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 141:49]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 141:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 141:19]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 140:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 139:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 138:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 137:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 136:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 135:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 134:81]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 134:49]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 134:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 134:19]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 133:51]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 133:19]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 132:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 131:33]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 130:64]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 130:49]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 130:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 130:19]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 129:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 128:33]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 127:64]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 127:49]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 127:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 127:19]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 126:51]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 126:19]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 125:63]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 125:31]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 125:16]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 124:64]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 124:49]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 124:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 124:19]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 123:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 122:51]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 122:19]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 121:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 120:51]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 120:19]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 119:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 118:36]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 117:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 116:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 115:48]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 115:18]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 114:48]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 114:18]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 113:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 112:62]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 112:32]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 112:18]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 111:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 110:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 109:62]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 109:32]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 109:18]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 108:48]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 108:18]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 107:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 106:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 105:48]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 105:18]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 104:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 103:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 102:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 101:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 100:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 99:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 98:48]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 98:18]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 97:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 96:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 95:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 94:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 93:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 92:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 91:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 90:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 89:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 88:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 87:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 86:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 85:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 84:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 83:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 82:48]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 82:18]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 81:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 80:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 79:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 78:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 77:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 76:48]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 76:18]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 75:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 74:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 73:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 72:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 71:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 70:62]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 70:32]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 70:18]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 69:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 68:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 67:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 66:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 65:48]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 65:18]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 64:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 63:48]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 63:18]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 62:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 61:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 60:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 59:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 58:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 57:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 56:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 55:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 54:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 53:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 52:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 51:48]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 51:18]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 50:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 49:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 48:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 47:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 46:48]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 46:18]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 45:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 44:48]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 44:18]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 43:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 42:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 41:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 40:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 39:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 38:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 37:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 36:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 35:48]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 35:18]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 34:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 33:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 32:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 31:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 30:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 29:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 28:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 27:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 26:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 25:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 24:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 23:45]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 23:15]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 22:46]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 22:32]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 22:18]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 21:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 20:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 19:48]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 19:18]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 18:48]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 18:18]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 17:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 16:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 15:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 14:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 13:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 12:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 11:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 10:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 9:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 8:34]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 7:32]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 6:32]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 5:32]
-// CHECK: 3:11: UnexposedExpr= Extent=[3:11 - 4:32]
-// CHECK: 3:12: UnexposedExpr= Extent=[3:12 - 3:34]
-// CHECK: 3:12: UnexposedExpr= Extent=[3:12 - 3:21]
+// CHECK: 3:10: ParenExpr= Extent=[3:10 - 160:52]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 160:51]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 160:19]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 159:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 158:51]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 158:19]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 157:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 156:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 155:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 154:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 153:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 152:51]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 152:19]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 151:51]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 151:19]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 150:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 149:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 148:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 147:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 146:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 145:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 144:51]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 144:19]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 143:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 142:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 141:81]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 141:49]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 141:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 141:19]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 140:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 139:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 138:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 137:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 136:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 135:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 134:81]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 134:49]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 134:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 134:19]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 133:51]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 133:19]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 132:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 131:33]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 130:64]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 130:49]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 130:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 130:19]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 129:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 128:33]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 127:64]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 127:49]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 127:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 127:19]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 126:51]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 126:19]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 125:63]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 125:31]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 125:16]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 124:64]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 124:49]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 124:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 124:19]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 123:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 122:51]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 122:19]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 121:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 120:51]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 120:19]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 119:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 118:36]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 117:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 116:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 115:48]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 115:18]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 114:48]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 114:18]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 113:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 112:62]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 112:32]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 112:18]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 111:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 110:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 109:62]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 109:32]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 109:18]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 108:48]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 108:18]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 107:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 106:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 105:48]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 105:18]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 104:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 103:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 102:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 101:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 100:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 99:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 98:48]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 98:18]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 97:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 96:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 95:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 94:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 93:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 92:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 91:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 90:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 89:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 88:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 87:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 86:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 85:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 84:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 83:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 82:48]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 82:18]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 81:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 80:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 79:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 78:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 77:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 76:48]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 76:18]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 75:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 74:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 73:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 72:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 71:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 70:62]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 70:32]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 70:18]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 69:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 68:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 67:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 66:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 65:48]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 65:18]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 64:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 63:48]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 63:18]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 62:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 61:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 60:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 59:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 58:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 57:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 56:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 55:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 54:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 53:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 52:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 51:48]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 51:18]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 50:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 49:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 48:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 47:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 46:48]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 46:18]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 45:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 44:48]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 44:18]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 43:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 42:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 41:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 40:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 39:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 38:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 37:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 36:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 35:48]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 35:18]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 34:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 33:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 32:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 31:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 30:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 29:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 28:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 27:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 26:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 25:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 24:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 23:45]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 23:15]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 22:46]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 22:32]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 22:18]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 21:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 20:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 19:48]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 19:18]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 18:48]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 18:18]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 17:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 16:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 15:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 14:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 13:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 12:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 11:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 10:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 9:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 8:34]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 7:32]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 6:32]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 5:32]
+// CHECK: 3:11: BinaryOperator= Extent=[3:11 - 4:32]
+// CHECK: 3:12: BinaryOperator= Extent=[3:12 - 3:34]
+// CHECK: 3:12: BinaryOperator= Extent=[3:12 - 3:21]
// CHECK: 3:12: DeclRefExpr=c:2:14 Extent=[3:12 - 3:13]
// CHECK: 3:17: UnexposedExpr= Extent=[3:17 - 3:21]
-// CHECK: 3:17: UnexposedExpr= Extent=[3:17 - 3:21]
-// CHECK: 3:25: UnexposedExpr= Extent=[3:25 - 3:34]
+// CHECK: 3:17: IntegerLiteral= Extent=[3:17 - 3:21]
+// CHECK: 3:25: BinaryOperator= Extent=[3:25 - 3:34]
// CHECK: 3:25: DeclRefExpr=c:2:14 Extent=[3:25 - 3:26]
// CHECK: 3:30: UnexposedExpr= Extent=[3:30 - 3:34]
-// CHECK: 3:30: UnexposedExpr= Extent=[3:30 - 3:34]
-// CHECK: 4:9: UnexposedExpr= Extent=[4:9 - 4:31]
-// CHECK: 4:9: UnexposedExpr= Extent=[4:9 - 4:18]
+// CHECK: 3:30: IntegerLiteral= Extent=[3:30 - 3:34]
+// CHECK: 4:9: BinaryOperator= Extent=[4:9 - 4:31]
+// CHECK: 4:9: BinaryOperator= Extent=[4:9 - 4:18]
// CHECK: 4:9: DeclRefExpr=c:2:14 Extent=[4:9 - 4:10]
// CHECK: 4:14: UnexposedExpr= Extent=[4:14 - 4:18]
-// CHECK: 4:14: UnexposedExpr= Extent=[4:14 - 4:18]
-// CHECK: 4:22: UnexposedExpr= Extent=[4:22 - 4:31]
+// CHECK: 4:14: IntegerLiteral= Extent=[4:14 - 4:18]
+// CHECK: 4:22: BinaryOperator= Extent=[4:22 - 4:31]
// CHECK: 4:22: DeclRefExpr=c:2:14 Extent=[4:22 - 4:23]
// CHECK: 4:27: UnexposedExpr= Extent=[4:27 - 4:31]
-// CHECK: 4:27: UnexposedExpr= Extent=[4:27 - 4:31]
-// CHECK: 5:9: UnexposedExpr= Extent=[5:9 - 5:31]
-// CHECK: 5:9: UnexposedExpr= Extent=[5:9 - 5:18]
+// CHECK: 4:27: IntegerLiteral= Extent=[4:27 - 4:31]
+// CHECK: 5:8: ParenExpr= Extent=[5:8 - 5:32]
+// CHECK: 5:9: BinaryOperator= Extent=[5:9 - 5:31]
+// CHECK: 5:9: BinaryOperator= Extent=[5:9 - 5:18]
// CHECK: 5:9: DeclRefExpr=c:2:14 Extent=[5:9 - 5:10]
// CHECK: 5:14: UnexposedExpr= Extent=[5:14 - 5:18]
-// CHECK: 5:14: UnexposedExpr= Extent=[5:14 - 5:18]
-// CHECK: 5:22: UnexposedExpr= Extent=[5:22 - 5:31]
+// CHECK: 5:14: IntegerLiteral= Extent=[5:14 - 5:18]
+// CHECK: 5:22: BinaryOperator= Extent=[5:22 - 5:31]
// CHECK: 5:22: DeclRefExpr=c:2:14 Extent=[5:22 - 5:23]
// CHECK: 5:27: UnexposedExpr= Extent=[5:27 - 5:31]
-// CHECK: 5:27: UnexposedExpr= Extent=[5:27 - 5:31]
-// CHECK: 6:9: UnexposedExpr= Extent=[6:9 - 6:31]
-// CHECK: 6:9: UnexposedExpr= Extent=[6:9 - 6:18]
+// CHECK: 5:27: IntegerLiteral= Extent=[5:27 - 5:31]
+// CHECK: 6:9: BinaryOperator= Extent=[6:9 - 6:31]
+// CHECK: 6:9: BinaryOperator= Extent=[6:9 - 6:18]
// CHECK: 6:9: DeclRefExpr=c:2:14 Extent=[6:9 - 6:10]
// CHECK: 6:14: UnexposedExpr= Extent=[6:14 - 6:18]
-// CHECK: 6:14: UnexposedExpr= Extent=[6:14 - 6:18]
-// CHECK: 6:22: UnexposedExpr= Extent=[6:22 - 6:31]
+// CHECK: 6:14: IntegerLiteral= Extent=[6:14 - 6:18]
+// CHECK: 6:22: BinaryOperator= Extent=[6:22 - 6:31]
// CHECK: 6:22: DeclRefExpr=c:2:14 Extent=[6:22 - 6:23]
// CHECK: 6:27: UnexposedExpr= Extent=[6:27 - 6:31]
-// CHECK: 6:27: UnexposedExpr= Extent=[6:27 - 6:31]
-// CHECK: 7:9: UnexposedExpr= Extent=[7:9 - 7:31]
-// CHECK: 7:9: UnexposedExpr= Extent=[7:9 - 7:18]
+// CHECK: 6:27: IntegerLiteral= Extent=[6:27 - 6:31]
+// CHECK: 7:9: BinaryOperator= Extent=[7:9 - 7:31]
+// CHECK: 7:9: BinaryOperator= Extent=[7:9 - 7:18]
// CHECK: 7:9: DeclRefExpr=c:2:14 Extent=[7:9 - 7:10]
// CHECK: 7:14: UnexposedExpr= Extent=[7:14 - 7:18]
-// CHECK: 7:14: UnexposedExpr= Extent=[7:14 - 7:18]
-// CHECK: 7:22: UnexposedExpr= Extent=[7:22 - 7:31]
+// CHECK: 7:14: IntegerLiteral= Extent=[7:14 - 7:18]
+// CHECK: 7:22: BinaryOperator= Extent=[7:22 - 7:31]
// CHECK: 7:22: DeclRefExpr=c:2:14 Extent=[7:22 - 7:23]
// CHECK: 7:27: UnexposedExpr= Extent=[7:27 - 7:31]
-// CHECK: 7:27: UnexposedExpr= Extent=[7:27 - 7:31]
-// CHECK: 8:9: UnexposedExpr= Extent=[8:9 - 8:33]
-// CHECK: 8:9: UnexposedExpr= Extent=[8:9 - 8:19]
+// CHECK: 7:27: IntegerLiteral= Extent=[7:27 - 7:31]
+// CHECK: 8:9: BinaryOperator= Extent=[8:9 - 8:33]
+// CHECK: 8:9: BinaryOperator= Extent=[8:9 - 8:19]
// CHECK: 8:9: DeclRefExpr=c:2:14 Extent=[8:9 - 8:10]
// CHECK: 8:14: UnexposedExpr= Extent=[8:14 - 8:19]
-// CHECK: 8:14: UnexposedExpr= Extent=[8:14 - 8:19]
-// CHECK: 8:23: UnexposedExpr= Extent=[8:23 - 8:33]
+// CHECK: 8:14: IntegerLiteral= Extent=[8:14 - 8:19]
+// CHECK: 8:23: BinaryOperator= Extent=[8:23 - 8:33]
// CHECK: 8:23: DeclRefExpr=c:2:14 Extent=[8:23 - 8:24]
// CHECK: 8:28: UnexposedExpr= Extent=[8:28 - 8:33]
-// CHECK: 8:28: UnexposedExpr= Extent=[8:28 - 8:33]
-// CHECK: 9:9: UnexposedExpr= Extent=[9:9 - 9:33]
-// CHECK: 9:9: UnexposedExpr= Extent=[9:9 - 9:19]
+// CHECK: 8:28: IntegerLiteral= Extent=[8:28 - 8:33]
+// CHECK: 9:9: BinaryOperator= Extent=[9:9 - 9:33]
+// CHECK: 9:9: BinaryOperator= Extent=[9:9 - 9:19]
// CHECK: 9:9: DeclRefExpr=c:2:14 Extent=[9:9 - 9:10]
// CHECK: 9:14: UnexposedExpr= Extent=[9:14 - 9:19]
-// CHECK: 9:14: UnexposedExpr= Extent=[9:14 - 9:19]
-// CHECK: 9:23: UnexposedExpr= Extent=[9:23 - 9:33]
+// CHECK: 9:14: IntegerLiteral= Extent=[9:14 - 9:19]
+// CHECK: 9:23: BinaryOperator= Extent=[9:23 - 9:33]
// CHECK: 9:23: DeclRefExpr=c:2:14 Extent=[9:23 - 9:24]
// CHECK: 9:28: UnexposedExpr= Extent=[9:28 - 9:33]
-// CHECK: 9:28: UnexposedExpr= Extent=[9:28 - 9:33]
-// CHECK: 10:9: UnexposedExpr= Extent=[10:9 - 10:33]
-// CHECK: 10:9: UnexposedExpr= Extent=[10:9 - 10:19]
+// CHECK: 9:28: IntegerLiteral= Extent=[9:28 - 9:33]
+// CHECK: 10:9: BinaryOperator= Extent=[10:9 - 10:33]
+// CHECK: 10:9: BinaryOperator= Extent=[10:9 - 10:19]
// CHECK: 10:9: DeclRefExpr=c:2:14 Extent=[10:9 - 10:10]
// CHECK: 10:14: UnexposedExpr= Extent=[10:14 - 10:19]
-// CHECK: 10:14: UnexposedExpr= Extent=[10:14 - 10:19]
-// CHECK: 10:23: UnexposedExpr= Extent=[10:23 - 10:33]
+// CHECK: 10:14: IntegerLiteral= Extent=[10:14 - 10:19]
+// CHECK: 10:23: BinaryOperator= Extent=[10:23 - 10:33]
// CHECK: 10:23: DeclRefExpr=c:2:14 Extent=[10:23 - 10:24]
// CHECK: 10:28: UnexposedExpr= Extent=[10:28 - 10:33]
-// CHECK: 10:28: UnexposedExpr= Extent=[10:28 - 10:33]
-// CHECK: 11:9: UnexposedExpr= Extent=[11:9 - 11:33]
-// CHECK: 11:9: UnexposedExpr= Extent=[11:9 - 11:19]
+// CHECK: 10:28: IntegerLiteral= Extent=[10:28 - 10:33]
+// CHECK: 11:9: BinaryOperator= Extent=[11:9 - 11:33]
+// CHECK: 11:9: BinaryOperator= Extent=[11:9 - 11:19]
// CHECK: 11:9: DeclRefExpr=c:2:14 Extent=[11:9 - 11:10]
// CHECK: 11:14: UnexposedExpr= Extent=[11:14 - 11:19]
-// CHECK: 11:14: UnexposedExpr= Extent=[11:14 - 11:19]
-// CHECK: 11:23: UnexposedExpr= Extent=[11:23 - 11:33]
+// CHECK: 11:14: IntegerLiteral= Extent=[11:14 - 11:19]
+// CHECK: 11:23: BinaryOperator= Extent=[11:23 - 11:33]
// CHECK: 11:23: DeclRefExpr=c:2:14 Extent=[11:23 - 11:24]
// CHECK: 11:28: UnexposedExpr= Extent=[11:28 - 11:33]
-// CHECK: 11:28: UnexposedExpr= Extent=[11:28 - 11:33]
-// CHECK: 12:9: UnexposedExpr= Extent=[12:9 - 12:33]
-// CHECK: 12:9: UnexposedExpr= Extent=[12:9 - 12:19]
+// CHECK: 11:28: IntegerLiteral= Extent=[11:28 - 11:33]
+// CHECK: 12:9: BinaryOperator= Extent=[12:9 - 12:33]
+// CHECK: 12:9: BinaryOperator= Extent=[12:9 - 12:19]
// CHECK: 12:9: DeclRefExpr=c:2:14 Extent=[12:9 - 12:10]
// CHECK: 12:14: UnexposedExpr= Extent=[12:14 - 12:19]
-// CHECK: 12:14: UnexposedExpr= Extent=[12:14 - 12:19]
-// CHECK: 12:23: UnexposedExpr= Extent=[12:23 - 12:33]
+// CHECK: 12:14: IntegerLiteral= Extent=[12:14 - 12:19]
+// CHECK: 12:23: BinaryOperator= Extent=[12:23 - 12:33]
// CHECK: 12:23: DeclRefExpr=c:2:14 Extent=[12:23 - 12:24]
// CHECK: 12:28: UnexposedExpr= Extent=[12:28 - 12:33]
-// CHECK: 12:28: UnexposedExpr= Extent=[12:28 - 12:33]
-// CHECK: 13:9: UnexposedExpr= Extent=[13:9 - 13:33]
-// CHECK: 13:9: UnexposedExpr= Extent=[13:9 - 13:19]
+// CHECK: 12:28: IntegerLiteral= Extent=[12:28 - 12:33]
+// CHECK: 13:9: BinaryOperator= Extent=[13:9 - 13:33]
+// CHECK: 13:9: BinaryOperator= Extent=[13:9 - 13:19]
// CHECK: 13:9: DeclRefExpr=c:2:14 Extent=[13:9 - 13:10]
// CHECK: 13:14: UnexposedExpr= Extent=[13:14 - 13:19]
-// CHECK: 13:14: UnexposedExpr= Extent=[13:14 - 13:19]
-// CHECK: 13:23: UnexposedExpr= Extent=[13:23 - 13:33]
+// CHECK: 13:14: IntegerLiteral= Extent=[13:14 - 13:19]
+// CHECK: 13:23: BinaryOperator= Extent=[13:23 - 13:33]
// CHECK: 13:23: DeclRefExpr=c:2:14 Extent=[13:23 - 13:24]
// CHECK: 13:28: UnexposedExpr= Extent=[13:28 - 13:33]
-// CHECK: 13:28: UnexposedExpr= Extent=[13:28 - 13:33]
-// CHECK: 14:9: UnexposedExpr= Extent=[14:9 - 14:33]
-// CHECK: 14:9: UnexposedExpr= Extent=[14:9 - 14:19]
+// CHECK: 13:28: IntegerLiteral= Extent=[13:28 - 13:33]
+// CHECK: 14:9: BinaryOperator= Extent=[14:9 - 14:33]
+// CHECK: 14:9: BinaryOperator= Extent=[14:9 - 14:19]
// CHECK: 14:9: DeclRefExpr=c:2:14 Extent=[14:9 - 14:10]
// CHECK: 14:14: UnexposedExpr= Extent=[14:14 - 14:19]
-// CHECK: 14:14: UnexposedExpr= Extent=[14:14 - 14:19]
-// CHECK: 14:23: UnexposedExpr= Extent=[14:23 - 14:33]
+// CHECK: 14:14: IntegerLiteral= Extent=[14:14 - 14:19]
+// CHECK: 14:23: BinaryOperator= Extent=[14:23 - 14:33]
// CHECK: 14:23: DeclRefExpr=c:2:14 Extent=[14:23 - 14:24]
// CHECK: 14:28: UnexposedExpr= Extent=[14:28 - 14:33]
-// CHECK: 14:28: UnexposedExpr= Extent=[14:28 - 14:33]
-// CHECK: 15:9: UnexposedExpr= Extent=[15:9 - 15:33]
-// CHECK: 15:9: UnexposedExpr= Extent=[15:9 - 15:19]
+// CHECK: 14:28: IntegerLiteral= Extent=[14:28 - 14:33]
+// CHECK: 15:9: BinaryOperator= Extent=[15:9 - 15:33]
+// CHECK: 15:9: BinaryOperator= Extent=[15:9 - 15:19]
// CHECK: 15:9: DeclRefExpr=c:2:14 Extent=[15:9 - 15:10]
// CHECK: 15:14: UnexposedExpr= Extent=[15:14 - 15:19]
-// CHECK: 15:14: UnexposedExpr= Extent=[15:14 - 15:19]
-// CHECK: 15:23: UnexposedExpr= Extent=[15:23 - 15:33]
+// CHECK: 15:14: IntegerLiteral= Extent=[15:14 - 15:19]
+// CHECK: 15:23: BinaryOperator= Extent=[15:23 - 15:33]
// CHECK: 15:23: DeclRefExpr=c:2:14 Extent=[15:23 - 15:24]
// CHECK: 15:28: UnexposedExpr= Extent=[15:28 - 15:33]
-// CHECK: 15:28: UnexposedExpr= Extent=[15:28 - 15:33]
-// CHECK: 16:9: UnexposedExpr= Extent=[16:9 - 16:33]
-// CHECK: 16:9: UnexposedExpr= Extent=[16:9 - 16:19]
+// CHECK: 15:28: IntegerLiteral= Extent=[15:28 - 15:33]
+// CHECK: 16:9: BinaryOperator= Extent=[16:9 - 16:33]
+// CHECK: 16:9: BinaryOperator= Extent=[16:9 - 16:19]
// CHECK: 16:9: DeclRefExpr=c:2:14 Extent=[16:9 - 16:10]
// CHECK: 16:14: UnexposedExpr= Extent=[16:14 - 16:19]
-// CHECK: 16:14: UnexposedExpr= Extent=[16:14 - 16:19]
-// CHECK: 16:23: UnexposedExpr= Extent=[16:23 - 16:33]
+// CHECK: 16:14: IntegerLiteral= Extent=[16:14 - 16:19]
+// CHECK: 16:23: BinaryOperator= Extent=[16:23 - 16:33]
// CHECK: 16:23: DeclRefExpr=c:2:14 Extent=[16:23 - 16:24]
// CHECK: 16:28: UnexposedExpr= Extent=[16:28 - 16:33]
-// CHECK: 16:28: UnexposedExpr= Extent=[16:28 - 16:33]
-// CHECK: 17:9: UnexposedExpr= Extent=[17:9 - 17:33]
-// CHECK: 17:9: UnexposedExpr= Extent=[17:9 - 17:19]
+// CHECK: 16:28: IntegerLiteral= Extent=[16:28 - 16:33]
+// CHECK: 17:9: BinaryOperator= Extent=[17:9 - 17:33]
+// CHECK: 17:9: BinaryOperator= Extent=[17:9 - 17:19]
// CHECK: 17:9: DeclRefExpr=c:2:14 Extent=[17:9 - 17:10]
// CHECK: 17:14: UnexposedExpr= Extent=[17:14 - 17:19]
-// CHECK: 17:14: UnexposedExpr= Extent=[17:14 - 17:19]
-// CHECK: 17:23: UnexposedExpr= Extent=[17:23 - 17:33]
+// CHECK: 17:14: IntegerLiteral= Extent=[17:14 - 17:19]
+// CHECK: 17:23: BinaryOperator= Extent=[17:23 - 17:33]
// CHECK: 17:23: DeclRefExpr=c:2:14 Extent=[17:23 - 17:24]
// CHECK: 17:28: UnexposedExpr= Extent=[17:28 - 17:33]
-// CHECK: 17:28: UnexposedExpr= Extent=[17:28 - 17:33]
-// CHECK: 18:8: UnexposedExpr= Extent=[18:8 - 18:18]
+// CHECK: 17:28: IntegerLiteral= Extent=[17:28 - 17:33]
+// CHECK: 18:8: BinaryOperator= Extent=[18:8 - 18:18]
// CHECK: 18:8: DeclRefExpr=c:2:14 Extent=[18:8 - 18:9]
// CHECK: 18:13: UnexposedExpr= Extent=[18:13 - 18:18]
-// CHECK: 18:13: UnexposedExpr= Extent=[18:13 - 18:18]
-// CHECK: 18:23: UnexposedExpr= Extent=[18:23 - 18:47]
-// CHECK: 18:23: UnexposedExpr= Extent=[18:23 - 18:33]
+// CHECK: 18:13: IntegerLiteral= Extent=[18:13 - 18:18]
+// CHECK: 18:23: BinaryOperator= Extent=[18:23 - 18:47]
+// CHECK: 18:23: BinaryOperator= Extent=[18:23 - 18:33]
// CHECK: 18:23: DeclRefExpr=c:2:14 Extent=[18:23 - 18:24]
// CHECK: 18:28: UnexposedExpr= Extent=[18:28 - 18:33]
-// CHECK: 18:28: UnexposedExpr= Extent=[18:28 - 18:33]
-// CHECK: 18:37: UnexposedExpr= Extent=[18:37 - 18:47]
+// CHECK: 18:28: IntegerLiteral= Extent=[18:28 - 18:33]
+// CHECK: 18:37: BinaryOperator= Extent=[18:37 - 18:47]
// CHECK: 18:37: DeclRefExpr=c:2:14 Extent=[18:37 - 18:38]
// CHECK: 18:42: UnexposedExpr= Extent=[18:42 - 18:47]
-// CHECK: 18:42: UnexposedExpr= Extent=[18:42 - 18:47]
-// CHECK: 19:8: UnexposedExpr= Extent=[19:8 - 19:18]
+// CHECK: 18:42: IntegerLiteral= Extent=[18:42 - 18:47]
+// CHECK: 19:8: BinaryOperator= Extent=[19:8 - 19:18]
// CHECK: 19:8: DeclRefExpr=c:2:14 Extent=[19:8 - 19:9]
// CHECK: 19:13: UnexposedExpr= Extent=[19:13 - 19:18]
-// CHECK: 19:13: UnexposedExpr= Extent=[19:13 - 19:18]
-// CHECK: 19:23: UnexposedExpr= Extent=[19:23 - 19:47]
-// CHECK: 19:23: UnexposedExpr= Extent=[19:23 - 19:33]
+// CHECK: 19:13: IntegerLiteral= Extent=[19:13 - 19:18]
+// CHECK: 19:23: BinaryOperator= Extent=[19:23 - 19:47]
+// CHECK: 19:23: BinaryOperator= Extent=[19:23 - 19:33]
// CHECK: 19:23: DeclRefExpr=c:2:14 Extent=[19:23 - 19:24]
// CHECK: 19:28: UnexposedExpr= Extent=[19:28 - 19:33]
-// CHECK: 19:28: UnexposedExpr= Extent=[19:28 - 19:33]
-// CHECK: 19:37: UnexposedExpr= Extent=[19:37 - 19:47]
+// CHECK: 19:28: IntegerLiteral= Extent=[19:28 - 19:33]
+// CHECK: 19:37: BinaryOperator= Extent=[19:37 - 19:47]
// CHECK: 19:37: DeclRefExpr=c:2:14 Extent=[19:37 - 19:38]
// CHECK: 19:42: UnexposedExpr= Extent=[19:42 - 19:47]
-// CHECK: 19:42: UnexposedExpr= Extent=[19:42 - 19:47]
-// CHECK: 20:9: UnexposedExpr= Extent=[20:9 - 20:33]
-// CHECK: 20:9: UnexposedExpr= Extent=[20:9 - 20:19]
+// CHECK: 19:42: IntegerLiteral= Extent=[19:42 - 19:47]
+// CHECK: 20:9: BinaryOperator= Extent=[20:9 - 20:33]
+// CHECK: 20:9: BinaryOperator= Extent=[20:9 - 20:19]
// CHECK: 20:9: DeclRefExpr=c:2:14 Extent=[20:9 - 20:10]
// CHECK: 20:14: UnexposedExpr= Extent=[20:14 - 20:19]
-// CHECK: 20:14: UnexposedExpr= Extent=[20:14 - 20:19]
-// CHECK: 20:23: UnexposedExpr= Extent=[20:23 - 20:33]
+// CHECK: 20:14: IntegerLiteral= Extent=[20:14 - 20:19]
+// CHECK: 20:23: BinaryOperator= Extent=[20:23 - 20:33]
// CHECK: 20:23: DeclRefExpr=c:2:14 Extent=[20:23 - 20:24]
// CHECK: 20:28: UnexposedExpr= Extent=[20:28 - 20:33]
-// CHECK: 20:28: UnexposedExpr= Extent=[20:28 - 20:33]
-// CHECK: 21:9: UnexposedExpr= Extent=[21:9 - 21:33]
-// CHECK: 21:9: UnexposedExpr= Extent=[21:9 - 21:19]
+// CHECK: 20:28: IntegerLiteral= Extent=[20:28 - 20:33]
+// CHECK: 21:9: BinaryOperator= Extent=[21:9 - 21:33]
+// CHECK: 21:9: BinaryOperator= Extent=[21:9 - 21:19]
// CHECK: 21:9: DeclRefExpr=c:2:14 Extent=[21:9 - 21:10]
// CHECK: 21:14: UnexposedExpr= Extent=[21:14 - 21:19]
-// CHECK: 21:14: UnexposedExpr= Extent=[21:14 - 21:19]
-// CHECK: 21:23: UnexposedExpr= Extent=[21:23 - 21:33]
+// CHECK: 21:14: IntegerLiteral= Extent=[21:14 - 21:19]
+// CHECK: 21:23: BinaryOperator= Extent=[21:23 - 21:33]
// CHECK: 21:23: DeclRefExpr=c:2:14 Extent=[21:23 - 21:24]
// CHECK: 21:28: UnexposedExpr= Extent=[21:28 - 21:33]
-// CHECK: 21:28: UnexposedExpr= Extent=[21:28 - 21:33]
-// CHECK: 22:8: UnexposedExpr= Extent=[22:8 - 22:18]
+// CHECK: 21:28: IntegerLiteral= Extent=[21:28 - 21:33]
+// CHECK: 22:8: BinaryOperator= Extent=[22:8 - 22:18]
// CHECK: 22:8: DeclRefExpr=c:2:14 Extent=[22:8 - 22:9]
// CHECK: 22:13: UnexposedExpr= Extent=[22:13 - 22:18]
-// CHECK: 22:13: UnexposedExpr= Extent=[22:13 - 22:18]
-// CHECK: 22:22: UnexposedExpr= Extent=[22:22 - 22:32]
+// CHECK: 22:13: IntegerLiteral= Extent=[22:13 - 22:18]
+// CHECK: 22:22: BinaryOperator= Extent=[22:22 - 22:32]
// CHECK: 22:22: DeclRefExpr=c:2:14 Extent=[22:22 - 22:23]
// CHECK: 22:27: UnexposedExpr= Extent=[22:27 - 22:32]
-// CHECK: 22:27: UnexposedExpr= Extent=[22:27 - 22:32]
-// CHECK: 22:36: UnexposedExpr= Extent=[22:36 - 22:46]
+// CHECK: 22:27: IntegerLiteral= Extent=[22:27 - 22:32]
+// CHECK: 22:36: BinaryOperator= Extent=[22:36 - 22:46]
// CHECK: 22:36: DeclRefExpr=c:2:14 Extent=[22:36 - 22:37]
// CHECK: 22:41: UnexposedExpr= Extent=[22:41 - 22:46]
-// CHECK: 22:41: UnexposedExpr= Extent=[22:41 - 22:46]
-// CHECK: 23:5: UnexposedExpr= Extent=[23:5 - 23:15]
+// CHECK: 22:41: IntegerLiteral= Extent=[22:41 - 22:46]
+// CHECK: 23:5: BinaryOperator= Extent=[23:5 - 23:15]
// CHECK: 23:5: DeclRefExpr=c:2:14 Extent=[23:5 - 23:6]
// CHECK: 23:10: UnexposedExpr= Extent=[23:10 - 23:15]
-// CHECK: 23:10: UnexposedExpr= Extent=[23:10 - 23:15]
-// CHECK: 23:20: UnexposedExpr= Extent=[23:20 - 23:44]
-// CHECK: 23:20: UnexposedExpr= Extent=[23:20 - 23:30]
+// CHECK: 23:10: IntegerLiteral= Extent=[23:10 - 23:15]
+// CHECK: 23:20: BinaryOperator= Extent=[23:20 - 23:44]
+// CHECK: 23:20: BinaryOperator= Extent=[23:20 - 23:30]
// CHECK: 23:20: DeclRefExpr=c:2:14 Extent=[23:20 - 23:21]
// CHECK: 23:25: UnexposedExpr= Extent=[23:25 - 23:30]
-// CHECK: 23:25: UnexposedExpr= Extent=[23:25 - 23:30]
-// CHECK: 23:34: UnexposedExpr= Extent=[23:34 - 23:44]
+// CHECK: 23:25: IntegerLiteral= Extent=[23:25 - 23:30]
+// CHECK: 23:34: BinaryOperator= Extent=[23:34 - 23:44]
// CHECK: 23:34: DeclRefExpr=c:2:14 Extent=[23:34 - 23:35]
// CHECK: 23:39: UnexposedExpr= Extent=[23:39 - 23:44]
-// CHECK: 23:39: UnexposedExpr= Extent=[23:39 - 23:44]
-// CHECK: 24:9: UnexposedExpr= Extent=[24:9 - 24:33]
-// CHECK: 24:9: UnexposedExpr= Extent=[24:9 - 24:19]
+// CHECK: 23:39: IntegerLiteral= Extent=[23:39 - 23:44]
+// CHECK: 24:9: BinaryOperator= Extent=[24:9 - 24:33]
+// CHECK: 24:9: BinaryOperator= Extent=[24:9 - 24:19]
// CHECK: 24:9: DeclRefExpr=c:2:14 Extent=[24:9 - 24:10]
// CHECK: 24:14: UnexposedExpr= Extent=[24:14 - 24:19]
-// CHECK: 24:14: UnexposedExpr= Extent=[24:14 - 24:19]
-// CHECK: 24:23: UnexposedExpr= Extent=[24:23 - 24:33]
+// CHECK: 24:14: IntegerLiteral= Extent=[24:14 - 24:19]
+// CHECK: 24:23: BinaryOperator= Extent=[24:23 - 24:33]
// CHECK: 24:23: DeclRefExpr=c:2:14 Extent=[24:23 - 24:24]
// CHECK: 24:28: UnexposedExpr= Extent=[24:28 - 24:33]
-// CHECK: 24:28: UnexposedExpr= Extent=[24:28 - 24:33]
-// CHECK: 25:9: UnexposedExpr= Extent=[25:9 - 25:33]
-// CHECK: 25:9: UnexposedExpr= Extent=[25:9 - 25:19]
+// CHECK: 24:28: IntegerLiteral= Extent=[24:28 - 24:33]
+// CHECK: 25:9: BinaryOperator= Extent=[25:9 - 25:33]
+// CHECK: 25:9: BinaryOperator= Extent=[25:9 - 25:19]
// CHECK: 25:9: DeclRefExpr=c:2:14 Extent=[25:9 - 25:10]
// CHECK: 25:14: UnexposedExpr= Extent=[25:14 - 25:19]
-// CHECK: 25:14: UnexposedExpr= Extent=[25:14 - 25:19]
-// CHECK: 25:23: UnexposedExpr= Extent=[25:23 - 25:33]
+// CHECK: 25:14: IntegerLiteral= Extent=[25:14 - 25:19]
+// CHECK: 25:23: BinaryOperator= Extent=[25:23 - 25:33]
// CHECK: 25:23: DeclRefExpr=c:2:14 Extent=[25:23 - 25:24]
// CHECK: 25:28: UnexposedExpr= Extent=[25:28 - 25:33]
-// CHECK: 25:28: UnexposedExpr= Extent=[25:28 - 25:33]
-// CHECK: 26:9: UnexposedExpr= Extent=[26:9 - 26:33]
-// CHECK: 26:9: UnexposedExpr= Extent=[26:9 - 26:19]
+// CHECK: 25:28: IntegerLiteral= Extent=[25:28 - 25:33]
+// CHECK: 26:9: BinaryOperator= Extent=[26:9 - 26:33]
+// CHECK: 26:9: BinaryOperator= Extent=[26:9 - 26:19]
// CHECK: 26:9: DeclRefExpr=c:2:14 Extent=[26:9 - 26:10]
// CHECK: 26:14: UnexposedExpr= Extent=[26:14 - 26:19]
-// CHECK: 26:14: UnexposedExpr= Extent=[26:14 - 26:19]
-// CHECK: 26:23: UnexposedExpr= Extent=[26:23 - 26:33]
+// CHECK: 26:14: IntegerLiteral= Extent=[26:14 - 26:19]
+// CHECK: 26:23: BinaryOperator= Extent=[26:23 - 26:33]
// CHECK: 26:23: DeclRefExpr=c:2:14 Extent=[26:23 - 26:24]
// CHECK: 26:28: UnexposedExpr= Extent=[26:28 - 26:33]
-// CHECK: 26:28: UnexposedExpr= Extent=[26:28 - 26:33]
-// CHECK: 27:9: UnexposedExpr= Extent=[27:9 - 27:33]
-// CHECK: 27:9: UnexposedExpr= Extent=[27:9 - 27:19]
+// CHECK: 26:28: IntegerLiteral= Extent=[26:28 - 26:33]
+// CHECK: 27:9: BinaryOperator= Extent=[27:9 - 27:33]
+// CHECK: 27:9: BinaryOperator= Extent=[27:9 - 27:19]
// CHECK: 27:9: DeclRefExpr=c:2:14 Extent=[27:9 - 27:10]
// CHECK: 27:14: UnexposedExpr= Extent=[27:14 - 27:19]
-// CHECK: 27:14: UnexposedExpr= Extent=[27:14 - 27:19]
-// CHECK: 27:23: UnexposedExpr= Extent=[27:23 - 27:33]
+// CHECK: 27:14: IntegerLiteral= Extent=[27:14 - 27:19]
+// CHECK: 27:23: BinaryOperator= Extent=[27:23 - 27:33]
// CHECK: 27:23: DeclRefExpr=c:2:14 Extent=[27:23 - 27:24]
// CHECK: 27:28: UnexposedExpr= Extent=[27:28 - 27:33]
-// CHECK: 27:28: UnexposedExpr= Extent=[27:28 - 27:33]
-// CHECK: 28:9: UnexposedExpr= Extent=[28:9 - 28:33]
-// CHECK: 28:9: UnexposedExpr= Extent=[28:9 - 28:19]
+// CHECK: 27:28: IntegerLiteral= Extent=[27:28 - 27:33]
+// CHECK: 28:9: BinaryOperator= Extent=[28:9 - 28:33]
+// CHECK: 28:9: BinaryOperator= Extent=[28:9 - 28:19]
// CHECK: 28:9: DeclRefExpr=c:2:14 Extent=[28:9 - 28:10]
// CHECK: 28:14: UnexposedExpr= Extent=[28:14 - 28:19]
-// CHECK: 28:14: UnexposedExpr= Extent=[28:14 - 28:19]
-// CHECK: 28:23: UnexposedExpr= Extent=[28:23 - 28:33]
+// CHECK: 28:14: IntegerLiteral= Extent=[28:14 - 28:19]
+// CHECK: 28:23: BinaryOperator= Extent=[28:23 - 28:33]
// CHECK: 28:23: DeclRefExpr=c:2:14 Extent=[28:23 - 28:24]
// CHECK: 28:28: UnexposedExpr= Extent=[28:28 - 28:33]
-// CHECK: 28:28: UnexposedExpr= Extent=[28:28 - 28:33]
-// CHECK: 29:9: UnexposedExpr= Extent=[29:9 - 29:33]
-// CHECK: 29:9: UnexposedExpr= Extent=[29:9 - 29:19]
+// CHECK: 28:28: IntegerLiteral= Extent=[28:28 - 28:33]
+// CHECK: 29:9: BinaryOperator= Extent=[29:9 - 29:33]
+// CHECK: 29:9: BinaryOperator= Extent=[29:9 - 29:19]
// CHECK: 29:9: DeclRefExpr=c:2:14 Extent=[29:9 - 29:10]
// CHECK: 29:14: UnexposedExpr= Extent=[29:14 - 29:19]
-// CHECK: 29:14: UnexposedExpr= Extent=[29:14 - 29:19]
-// CHECK: 29:23: UnexposedExpr= Extent=[29:23 - 29:33]
+// CHECK: 29:14: IntegerLiteral= Extent=[29:14 - 29:19]
+// CHECK: 29:23: BinaryOperator= Extent=[29:23 - 29:33]
// CHECK: 29:23: DeclRefExpr=c:2:14 Extent=[29:23 - 29:24]
// CHECK: 29:28: UnexposedExpr= Extent=[29:28 - 29:33]
-// CHECK: 29:28: UnexposedExpr= Extent=[29:28 - 29:33]
-// CHECK: 30:9: UnexposedExpr= Extent=[30:9 - 30:33]
-// CHECK: 30:9: UnexposedExpr= Extent=[30:9 - 30:19]
+// CHECK: 29:28: IntegerLiteral= Extent=[29:28 - 29:33]
+// CHECK: 30:9: BinaryOperator= Extent=[30:9 - 30:33]
+// CHECK: 30:9: BinaryOperator= Extent=[30:9 - 30:19]
// CHECK: 30:9: DeclRefExpr=c:2:14 Extent=[30:9 - 30:10]
// CHECK: 30:14: UnexposedExpr= Extent=[30:14 - 30:19]
-// CHECK: 30:14: UnexposedExpr= Extent=[30:14 - 30:19]
-// CHECK: 30:23: UnexposedExpr= Extent=[30:23 - 30:33]
+// CHECK: 30:14: IntegerLiteral= Extent=[30:14 - 30:19]
+// CHECK: 30:23: BinaryOperator= Extent=[30:23 - 30:33]
// CHECK: 30:23: DeclRefExpr=c:2:14 Extent=[30:23 - 30:24]
// CHECK: 30:28: UnexposedExpr= Extent=[30:28 - 30:33]
-// CHECK: 30:28: UnexposedExpr= Extent=[30:28 - 30:33]
-// CHECK: 31:9: UnexposedExpr= Extent=[31:9 - 31:33]
-// CHECK: 31:9: UnexposedExpr= Extent=[31:9 - 31:19]
+// CHECK: 30:28: IntegerLiteral= Extent=[30:28 - 30:33]
+// CHECK: 31:9: BinaryOperator= Extent=[31:9 - 31:33]
+// CHECK: 31:9: BinaryOperator= Extent=[31:9 - 31:19]
// CHECK: 31:9: DeclRefExpr=c:2:14 Extent=[31:9 - 31:10]
// CHECK: 31:14: UnexposedExpr= Extent=[31:14 - 31:19]
-// CHECK: 31:14: UnexposedExpr= Extent=[31:14 - 31:19]
-// CHECK: 31:23: UnexposedExpr= Extent=[31:23 - 31:33]
+// CHECK: 31:14: IntegerLiteral= Extent=[31:14 - 31:19]
+// CHECK: 31:23: BinaryOperator= Extent=[31:23 - 31:33]
// CHECK: 31:23: DeclRefExpr=c:2:14 Extent=[31:23 - 31:24]
// CHECK: 31:28: UnexposedExpr= Extent=[31:28 - 31:33]
-// CHECK: 31:28: UnexposedExpr= Extent=[31:28 - 31:33]
-// CHECK: 32:9: UnexposedExpr= Extent=[32:9 - 32:33]
-// CHECK: 32:9: UnexposedExpr= Extent=[32:9 - 32:19]
+// CHECK: 31:28: IntegerLiteral= Extent=[31:28 - 31:33]
+// CHECK: 32:9: BinaryOperator= Extent=[32:9 - 32:33]
+// CHECK: 32:9: BinaryOperator= Extent=[32:9 - 32:19]
// CHECK: 32:9: DeclRefExpr=c:2:14 Extent=[32:9 - 32:10]
// CHECK: 32:14: UnexposedExpr= Extent=[32:14 - 32:19]
-// CHECK: 32:14: UnexposedExpr= Extent=[32:14 - 32:19]
-// CHECK: 32:23: UnexposedExpr= Extent=[32:23 - 32:33]
+// CHECK: 32:14: IntegerLiteral= Extent=[32:14 - 32:19]
+// CHECK: 32:23: BinaryOperator= Extent=[32:23 - 32:33]
// CHECK: 32:23: DeclRefExpr=c:2:14 Extent=[32:23 - 32:24]
// CHECK: 32:28: UnexposedExpr= Extent=[32:28 - 32:33]
-// CHECK: 32:28: UnexposedExpr= Extent=[32:28 - 32:33]
-// CHECK: 33:9: UnexposedExpr= Extent=[33:9 - 33:33]
-// CHECK: 33:9: UnexposedExpr= Extent=[33:9 - 33:19]
+// CHECK: 32:28: IntegerLiteral= Extent=[32:28 - 32:33]
+// CHECK: 33:9: BinaryOperator= Extent=[33:9 - 33:33]
+// CHECK: 33:9: BinaryOperator= Extent=[33:9 - 33:19]
// CHECK: 33:9: DeclRefExpr=c:2:14 Extent=[33:9 - 33:10]
// CHECK: 33:14: UnexposedExpr= Extent=[33:14 - 33:19]
-// CHECK: 33:14: UnexposedExpr= Extent=[33:14 - 33:19]
-// CHECK: 33:23: UnexposedExpr= Extent=[33:23 - 33:33]
+// CHECK: 33:14: IntegerLiteral= Extent=[33:14 - 33:19]
+// CHECK: 33:23: BinaryOperator= Extent=[33:23 - 33:33]
// CHECK: 33:23: DeclRefExpr=c:2:14 Extent=[33:23 - 33:24]
// CHECK: 33:28: UnexposedExpr= Extent=[33:28 - 33:33]
-// CHECK: 33:28: UnexposedExpr= Extent=[33:28 - 33:33]
-// CHECK: 34:9: UnexposedExpr= Extent=[34:9 - 34:33]
-// CHECK: 34:9: UnexposedExpr= Extent=[34:9 - 34:19]
+// CHECK: 33:28: IntegerLiteral= Extent=[33:28 - 33:33]
+// CHECK: 34:9: BinaryOperator= Extent=[34:9 - 34:33]
+// CHECK: 34:9: BinaryOperator= Extent=[34:9 - 34:19]
// CHECK: 34:9: DeclRefExpr=c:2:14 Extent=[34:9 - 34:10]
// CHECK: 34:14: UnexposedExpr= Extent=[34:14 - 34:19]
-// CHECK: 34:14: UnexposedExpr= Extent=[34:14 - 34:19]
-// CHECK: 34:23: UnexposedExpr= Extent=[34:23 - 34:33]
+// CHECK: 34:14: IntegerLiteral= Extent=[34:14 - 34:19]
+// CHECK: 34:23: BinaryOperator= Extent=[34:23 - 34:33]
// CHECK: 34:23: DeclRefExpr=c:2:14 Extent=[34:23 - 34:24]
// CHECK: 34:28: UnexposedExpr= Extent=[34:28 - 34:33]
-// CHECK: 34:28: UnexposedExpr= Extent=[34:28 - 34:33]
-// CHECK: 35:8: UnexposedExpr= Extent=[35:8 - 35:18]
+// CHECK: 34:28: IntegerLiteral= Extent=[34:28 - 34:33]
+// CHECK: 35:8: BinaryOperator= Extent=[35:8 - 35:18]
// CHECK: 35:8: DeclRefExpr=c:2:14 Extent=[35:8 - 35:9]
// CHECK: 35:13: UnexposedExpr= Extent=[35:13 - 35:18]
-// CHECK: 35:13: UnexposedExpr= Extent=[35:13 - 35:18]
-// CHECK: 35:23: UnexposedExpr= Extent=[35:23 - 35:47]
-// CHECK: 35:23: UnexposedExpr= Extent=[35:23 - 35:33]
+// CHECK: 35:13: IntegerLiteral= Extent=[35:13 - 35:18]
+// CHECK: 35:23: BinaryOperator= Extent=[35:23 - 35:47]
+// CHECK: 35:23: BinaryOperator= Extent=[35:23 - 35:33]
// CHECK: 35:23: DeclRefExpr=c:2:14 Extent=[35:23 - 35:24]
// CHECK: 35:28: UnexposedExpr= Extent=[35:28 - 35:33]
-// CHECK: 35:28: UnexposedExpr= Extent=[35:28 - 35:33]
-// CHECK: 35:37: UnexposedExpr= Extent=[35:37 - 35:47]
+// CHECK: 35:28: IntegerLiteral= Extent=[35:28 - 35:33]
+// CHECK: 35:37: BinaryOperator= Extent=[35:37 - 35:47]
// CHECK: 35:37: DeclRefExpr=c:2:14 Extent=[35:37 - 35:38]
// CHECK: 35:42: UnexposedExpr= Extent=[35:42 - 35:47]
-// CHECK: 35:42: UnexposedExpr= Extent=[35:42 - 35:47]
-// CHECK: 36:9: UnexposedExpr= Extent=[36:9 - 36:33]
-// CHECK: 36:9: UnexposedExpr= Extent=[36:9 - 36:19]
+// CHECK: 35:42: IntegerLiteral= Extent=[35:42 - 35:47]
+// CHECK: 36:9: BinaryOperator= Extent=[36:9 - 36:33]
+// CHECK: 36:9: BinaryOperator= Extent=[36:9 - 36:19]
// CHECK: 36:9: DeclRefExpr=c:2:14 Extent=[36:9 - 36:10]
// CHECK: 36:14: UnexposedExpr= Extent=[36:14 - 36:19]
-// CHECK: 36:14: UnexposedExpr= Extent=[36:14 - 36:19]
-// CHECK: 36:23: UnexposedExpr= Extent=[36:23 - 36:33]
+// CHECK: 36:14: IntegerLiteral= Extent=[36:14 - 36:19]
+// CHECK: 36:23: BinaryOperator= Extent=[36:23 - 36:33]
// CHECK: 36:23: DeclRefExpr=c:2:14 Extent=[36:23 - 36:24]
// CHECK: 36:28: UnexposedExpr= Extent=[36:28 - 36:33]
-// CHECK: 36:28: UnexposedExpr= Extent=[36:28 - 36:33]
-// CHECK: 37:9: UnexposedExpr= Extent=[37:9 - 37:33]
-// CHECK: 37:9: UnexposedExpr= Extent=[37:9 - 37:19]
+// CHECK: 36:28: IntegerLiteral= Extent=[36:28 - 36:33]
+// CHECK: 37:9: BinaryOperator= Extent=[37:9 - 37:33]
+// CHECK: 37:9: BinaryOperator= Extent=[37:9 - 37:19]
// CHECK: 37:9: DeclRefExpr=c:2:14 Extent=[37:9 - 37:10]
// CHECK: 37:14: UnexposedExpr= Extent=[37:14 - 37:19]
-// CHECK: 37:14: UnexposedExpr= Extent=[37:14 - 37:19]
-// CHECK: 37:23: UnexposedExpr= Extent=[37:23 - 37:33]
+// CHECK: 37:14: IntegerLiteral= Extent=[37:14 - 37:19]
+// CHECK: 37:23: BinaryOperator= Extent=[37:23 - 37:33]
// CHECK: 37:23: DeclRefExpr=c:2:14 Extent=[37:23 - 37:24]
// CHECK: 37:28: UnexposedExpr= Extent=[37:28 - 37:33]
-// CHECK: 37:28: UnexposedExpr= Extent=[37:28 - 37:33]
-// CHECK: 38:9: UnexposedExpr= Extent=[38:9 - 38:33]
-// CHECK: 38:9: UnexposedExpr= Extent=[38:9 - 38:19]
+// CHECK: 37:28: IntegerLiteral= Extent=[37:28 - 37:33]
+// CHECK: 38:9: BinaryOperator= Extent=[38:9 - 38:33]
+// CHECK: 38:9: BinaryOperator= Extent=[38:9 - 38:19]
// CHECK: 38:9: DeclRefExpr=c:2:14 Extent=[38:9 - 38:10]
// CHECK: 38:14: UnexposedExpr= Extent=[38:14 - 38:19]
-// CHECK: 38:14: UnexposedExpr= Extent=[38:14 - 38:19]
-// CHECK: 38:23: UnexposedExpr= Extent=[38:23 - 38:33]
+// CHECK: 38:14: IntegerLiteral= Extent=[38:14 - 38:19]
+// CHECK: 38:23: BinaryOperator= Extent=[38:23 - 38:33]
// CHECK: 38:23: DeclRefExpr=c:2:14 Extent=[38:23 - 38:24]
// CHECK: 38:28: UnexposedExpr= Extent=[38:28 - 38:33]
-// CHECK: 38:28: UnexposedExpr= Extent=[38:28 - 38:33]
-// CHECK: 39:9: UnexposedExpr= Extent=[39:9 - 39:33]
-// CHECK: 39:9: UnexposedExpr= Extent=[39:9 - 39:19]
+// CHECK: 38:28: IntegerLiteral= Extent=[38:28 - 38:33]
+// CHECK: 39:9: BinaryOperator= Extent=[39:9 - 39:33]
+// CHECK: 39:9: BinaryOperator= Extent=[39:9 - 39:19]
// CHECK: 39:9: DeclRefExpr=c:2:14 Extent=[39:9 - 39:10]
// CHECK: 39:14: UnexposedExpr= Extent=[39:14 - 39:19]
-// CHECK: 39:14: UnexposedExpr= Extent=[39:14 - 39:19]
-// CHECK: 39:23: UnexposedExpr= Extent=[39:23 - 39:33]
+// CHECK: 39:14: IntegerLiteral= Extent=[39:14 - 39:19]
+// CHECK: 39:23: BinaryOperator= Extent=[39:23 - 39:33]
// CHECK: 39:23: DeclRefExpr=c:2:14 Extent=[39:23 - 39:24]
// CHECK: 39:28: UnexposedExpr= Extent=[39:28 - 39:33]
-// CHECK: 39:28: UnexposedExpr= Extent=[39:28 - 39:33]
-// CHECK: 40:9: UnexposedExpr= Extent=[40:9 - 40:33]
-// CHECK: 40:9: UnexposedExpr= Extent=[40:9 - 40:19]
+// CHECK: 39:28: IntegerLiteral= Extent=[39:28 - 39:33]
+// CHECK: 40:9: BinaryOperator= Extent=[40:9 - 40:33]
+// CHECK: 40:9: BinaryOperator= Extent=[40:9 - 40:19]
// CHECK: 40:9: DeclRefExpr=c:2:14 Extent=[40:9 - 40:10]
// CHECK: 40:14: UnexposedExpr= Extent=[40:14 - 40:19]
-// CHECK: 40:14: UnexposedExpr= Extent=[40:14 - 40:19]
-// CHECK: 40:23: UnexposedExpr= Extent=[40:23 - 40:33]
+// CHECK: 40:14: IntegerLiteral= Extent=[40:14 - 40:19]
+// CHECK: 40:23: BinaryOperator= Extent=[40:23 - 40:33]
// CHECK: 40:23: DeclRefExpr=c:2:14 Extent=[40:23 - 40:24]
// CHECK: 40:28: UnexposedExpr= Extent=[40:28 - 40:33]
-// CHECK: 40:28: UnexposedExpr= Extent=[40:28 - 40:33]
-// CHECK: 41:9: UnexposedExpr= Extent=[41:9 - 41:33]
-// CHECK: 41:9: UnexposedExpr= Extent=[41:9 - 41:19]
+// CHECK: 40:28: IntegerLiteral= Extent=[40:28 - 40:33]
+// CHECK: 41:9: BinaryOperator= Extent=[41:9 - 41:33]
+// CHECK: 41:9: BinaryOperator= Extent=[41:9 - 41:19]
// CHECK: 41:9: DeclRefExpr=c:2:14 Extent=[41:9 - 41:10]
// CHECK: 41:14: UnexposedExpr= Extent=[41:14 - 41:19]
-// CHECK: 41:14: UnexposedExpr= Extent=[41:14 - 41:19]
-// CHECK: 41:23: UnexposedExpr= Extent=[41:23 - 41:33]
+// CHECK: 41:14: IntegerLiteral= Extent=[41:14 - 41:19]
+// CHECK: 41:23: BinaryOperator= Extent=[41:23 - 41:33]
// CHECK: 41:23: DeclRefExpr=c:2:14 Extent=[41:23 - 41:24]
// CHECK: 41:28: UnexposedExpr= Extent=[41:28 - 41:33]
-// CHECK: 41:28: UnexposedExpr= Extent=[41:28 - 41:33]
-// CHECK: 42:9: UnexposedExpr= Extent=[42:9 - 42:33]
-// CHECK: 42:9: UnexposedExpr= Extent=[42:9 - 42:19]
+// CHECK: 41:28: IntegerLiteral= Extent=[41:28 - 41:33]
+// CHECK: 42:9: BinaryOperator= Extent=[42:9 - 42:33]
+// CHECK: 42:9: BinaryOperator= Extent=[42:9 - 42:19]
// CHECK: 42:9: DeclRefExpr=c:2:14 Extent=[42:9 - 42:10]
// CHECK: 42:14: UnexposedExpr= Extent=[42:14 - 42:19]
-// CHECK: 42:14: UnexposedExpr= Extent=[42:14 - 42:19]
-// CHECK: 42:23: UnexposedExpr= Extent=[42:23 - 42:33]
+// CHECK: 42:14: IntegerLiteral= Extent=[42:14 - 42:19]
+// CHECK: 42:23: BinaryOperator= Extent=[42:23 - 42:33]
// CHECK: 42:23: DeclRefExpr=c:2:14 Extent=[42:23 - 42:24]
// CHECK: 42:28: UnexposedExpr= Extent=[42:28 - 42:33]
-// CHECK: 42:28: UnexposedExpr= Extent=[42:28 - 42:33]
-// CHECK: 43:9: UnexposedExpr= Extent=[43:9 - 43:33]
-// CHECK: 43:9: UnexposedExpr= Extent=[43:9 - 43:19]
+// CHECK: 42:28: IntegerLiteral= Extent=[42:28 - 42:33]
+// CHECK: 43:9: BinaryOperator= Extent=[43:9 - 43:33]
+// CHECK: 43:9: BinaryOperator= Extent=[43:9 - 43:19]
// CHECK: 43:9: DeclRefExpr=c:2:14 Extent=[43:9 - 43:10]
// CHECK: 43:14: UnexposedExpr= Extent=[43:14 - 43:19]
-// CHECK: 43:14: UnexposedExpr= Extent=[43:14 - 43:19]
-// CHECK: 43:23: UnexposedExpr= Extent=[43:23 - 43:33]
+// CHECK: 43:14: IntegerLiteral= Extent=[43:14 - 43:19]
+// CHECK: 43:23: BinaryOperator= Extent=[43:23 - 43:33]
// CHECK: 43:23: DeclRefExpr=c:2:14 Extent=[43:23 - 43:24]
// CHECK: 43:28: UnexposedExpr= Extent=[43:28 - 43:33]
-// CHECK: 43:28: UnexposedExpr= Extent=[43:28 - 43:33]
-// CHECK: 44:8: UnexposedExpr= Extent=[44:8 - 44:18]
+// CHECK: 43:28: IntegerLiteral= Extent=[43:28 - 43:33]
+// CHECK: 44:8: BinaryOperator= Extent=[44:8 - 44:18]
// CHECK: 44:8: DeclRefExpr=c:2:14 Extent=[44:8 - 44:9]
// CHECK: 44:13: UnexposedExpr= Extent=[44:13 - 44:18]
-// CHECK: 44:13: UnexposedExpr= Extent=[44:13 - 44:18]
-// CHECK: 44:23: UnexposedExpr= Extent=[44:23 - 44:47]
-// CHECK: 44:23: UnexposedExpr= Extent=[44:23 - 44:33]
+// CHECK: 44:13: IntegerLiteral= Extent=[44:13 - 44:18]
+// CHECK: 44:23: BinaryOperator= Extent=[44:23 - 44:47]
+// CHECK: 44:23: BinaryOperator= Extent=[44:23 - 44:33]
// CHECK: 44:23: DeclRefExpr=c:2:14 Extent=[44:23 - 44:24]
// CHECK: 44:28: UnexposedExpr= Extent=[44:28 - 44:33]
-// CHECK: 44:28: UnexposedExpr= Extent=[44:28 - 44:33]
-// CHECK: 44:37: UnexposedExpr= Extent=[44:37 - 44:47]
+// CHECK: 44:28: IntegerLiteral= Extent=[44:28 - 44:33]
+// CHECK: 44:37: BinaryOperator= Extent=[44:37 - 44:47]
// CHECK: 44:37: DeclRefExpr=c:2:14 Extent=[44:37 - 44:38]
// CHECK: 44:42: UnexposedExpr= Extent=[44:42 - 44:47]
-// CHECK: 44:42: UnexposedExpr= Extent=[44:42 - 44:47]
-// CHECK: 45:9: UnexposedExpr= Extent=[45:9 - 45:33]
-// CHECK: 45:9: UnexposedExpr= Extent=[45:9 - 45:19]
+// CHECK: 44:42: IntegerLiteral= Extent=[44:42 - 44:47]
+// CHECK: 45:9: BinaryOperator= Extent=[45:9 - 45:33]
+// CHECK: 45:9: BinaryOperator= Extent=[45:9 - 45:19]
// CHECK: 45:9: DeclRefExpr=c:2:14 Extent=[45:9 - 45:10]
// CHECK: 45:14: UnexposedExpr= Extent=[45:14 - 45:19]
-// CHECK: 45:14: UnexposedExpr= Extent=[45:14 - 45:19]
-// CHECK: 45:23: UnexposedExpr= Extent=[45:23 - 45:33]
+// CHECK: 45:14: IntegerLiteral= Extent=[45:14 - 45:19]
+// CHECK: 45:23: BinaryOperator= Extent=[45:23 - 45:33]
// CHECK: 45:23: DeclRefExpr=c:2:14 Extent=[45:23 - 45:24]
// CHECK: 45:28: UnexposedExpr= Extent=[45:28 - 45:33]
-// CHECK: 45:28: UnexposedExpr= Extent=[45:28 - 45:33]
-// CHECK: 46:8: UnexposedExpr= Extent=[46:8 - 46:18]
+// CHECK: 45:28: IntegerLiteral= Extent=[45:28 - 45:33]
+// CHECK: 46:8: BinaryOperator= Extent=[46:8 - 46:18]
// CHECK: 46:8: DeclRefExpr=c:2:14 Extent=[46:8 - 46:9]
// CHECK: 46:13: UnexposedExpr= Extent=[46:13 - 46:18]
-// CHECK: 46:13: UnexposedExpr= Extent=[46:13 - 46:18]
-// CHECK: 46:23: UnexposedExpr= Extent=[46:23 - 46:47]
-// CHECK: 46:23: UnexposedExpr= Extent=[46:23 - 46:33]
+// CHECK: 46:13: IntegerLiteral= Extent=[46:13 - 46:18]
+// CHECK: 46:23: BinaryOperator= Extent=[46:23 - 46:47]
+// CHECK: 46:23: BinaryOperator= Extent=[46:23 - 46:33]
// CHECK: 46:23: DeclRefExpr=c:2:14 Extent=[46:23 - 46:24]
// CHECK: 46:28: UnexposedExpr= Extent=[46:28 - 46:33]
-// CHECK: 46:28: UnexposedExpr= Extent=[46:28 - 46:33]
-// CHECK: 46:37: UnexposedExpr= Extent=[46:37 - 46:47]
+// CHECK: 46:28: IntegerLiteral= Extent=[46:28 - 46:33]
+// CHECK: 46:37: BinaryOperator= Extent=[46:37 - 46:47]
// CHECK: 46:37: DeclRefExpr=c:2:14 Extent=[46:37 - 46:38]
// CHECK: 46:42: UnexposedExpr= Extent=[46:42 - 46:47]
-// CHECK: 46:42: UnexposedExpr= Extent=[46:42 - 46:47]
-// CHECK: 47:9: UnexposedExpr= Extent=[47:9 - 47:33]
-// CHECK: 47:9: UnexposedExpr= Extent=[47:9 - 47:19]
+// CHECK: 46:42: IntegerLiteral= Extent=[46:42 - 46:47]
+// CHECK: 47:9: BinaryOperator= Extent=[47:9 - 47:33]
+// CHECK: 47:9: BinaryOperator= Extent=[47:9 - 47:19]
// CHECK: 47:9: DeclRefExpr=c:2:14 Extent=[47:9 - 47:10]
// CHECK: 47:14: UnexposedExpr= Extent=[47:14 - 47:19]
-// CHECK: 47:14: UnexposedExpr= Extent=[47:14 - 47:19]
-// CHECK: 47:23: UnexposedExpr= Extent=[47:23 - 47:33]
+// CHECK: 47:14: IntegerLiteral= Extent=[47:14 - 47:19]
+// CHECK: 47:23: BinaryOperator= Extent=[47:23 - 47:33]
// CHECK: 47:23: DeclRefExpr=c:2:14 Extent=[47:23 - 47:24]
// CHECK: 47:28: UnexposedExpr= Extent=[47:28 - 47:33]
-// CHECK: 47:28: UnexposedExpr= Extent=[47:28 - 47:33]
-// CHECK: 48:9: UnexposedExpr= Extent=[48:9 - 48:33]
-// CHECK: 48:9: UnexposedExpr= Extent=[48:9 - 48:19]
+// CHECK: 47:28: IntegerLiteral= Extent=[47:28 - 47:33]
+// CHECK: 48:9: BinaryOperator= Extent=[48:9 - 48:33]
+// CHECK: 48:9: BinaryOperator= Extent=[48:9 - 48:19]
// CHECK: 48:9: DeclRefExpr=c:2:14 Extent=[48:9 - 48:10]
// CHECK: 48:14: UnexposedExpr= Extent=[48:14 - 48:19]
-// CHECK: 48:14: UnexposedExpr= Extent=[48:14 - 48:19]
-// CHECK: 48:23: UnexposedExpr= Extent=[48:23 - 48:33]
+// CHECK: 48:14: IntegerLiteral= Extent=[48:14 - 48:19]
+// CHECK: 48:23: BinaryOperator= Extent=[48:23 - 48:33]
// CHECK: 48:23: DeclRefExpr=c:2:14 Extent=[48:23 - 48:24]
// CHECK: 48:28: UnexposedExpr= Extent=[48:28 - 48:33]
-// CHECK: 48:28: UnexposedExpr= Extent=[48:28 - 48:33]
-// CHECK: 49:9: UnexposedExpr= Extent=[49:9 - 49:33]
-// CHECK: 49:9: UnexposedExpr= Extent=[49:9 - 49:19]
+// CHECK: 48:28: IntegerLiteral= Extent=[48:28 - 48:33]
+// CHECK: 49:9: BinaryOperator= Extent=[49:9 - 49:33]
+// CHECK: 49:9: BinaryOperator= Extent=[49:9 - 49:19]
// CHECK: 49:9: DeclRefExpr=c:2:14 Extent=[49:9 - 49:10]
// CHECK: 49:14: UnexposedExpr= Extent=[49:14 - 49:19]
-// CHECK: 49:14: UnexposedExpr= Extent=[49:14 - 49:19]
-// CHECK: 49:23: UnexposedExpr= Extent=[49:23 - 49:33]
+// CHECK: 49:14: IntegerLiteral= Extent=[49:14 - 49:19]
+// CHECK: 49:23: BinaryOperator= Extent=[49:23 - 49:33]
// CHECK: 49:23: DeclRefExpr=c:2:14 Extent=[49:23 - 49:24]
// CHECK: 49:28: UnexposedExpr= Extent=[49:28 - 49:33]
-// CHECK: 49:28: UnexposedExpr= Extent=[49:28 - 49:33]
-// CHECK: 50:9: UnexposedExpr= Extent=[50:9 - 50:33]
-// CHECK: 50:9: UnexposedExpr= Extent=[50:9 - 50:19]
+// CHECK: 49:28: IntegerLiteral= Extent=[49:28 - 49:33]
+// CHECK: 50:9: BinaryOperator= Extent=[50:9 - 50:33]
+// CHECK: 50:9: BinaryOperator= Extent=[50:9 - 50:19]
// CHECK: 50:9: DeclRefExpr=c:2:14 Extent=[50:9 - 50:10]
// CHECK: 50:14: UnexposedExpr= Extent=[50:14 - 50:19]
-// CHECK: 50:14: UnexposedExpr= Extent=[50:14 - 50:19]
-// CHECK: 50:23: UnexposedExpr= Extent=[50:23 - 50:33]
+// CHECK: 50:14: IntegerLiteral= Extent=[50:14 - 50:19]
+// CHECK: 50:23: BinaryOperator= Extent=[50:23 - 50:33]
// CHECK: 50:23: DeclRefExpr=c:2:14 Extent=[50:23 - 50:24]
// CHECK: 50:28: UnexposedExpr= Extent=[50:28 - 50:33]
-// CHECK: 50:28: UnexposedExpr= Extent=[50:28 - 50:33]
-// CHECK: 51:8: UnexposedExpr= Extent=[51:8 - 51:18]
+// CHECK: 50:28: IntegerLiteral= Extent=[50:28 - 50:33]
+// CHECK: 51:8: BinaryOperator= Extent=[51:8 - 51:18]
// CHECK: 51:8: DeclRefExpr=c:2:14 Extent=[51:8 - 51:9]
// CHECK: 51:13: UnexposedExpr= Extent=[51:13 - 51:18]
-// CHECK: 51:13: UnexposedExpr= Extent=[51:13 - 51:18]
-// CHECK: 51:23: UnexposedExpr= Extent=[51:23 - 51:47]
-// CHECK: 51:23: UnexposedExpr= Extent=[51:23 - 51:33]
+// CHECK: 51:13: IntegerLiteral= Extent=[51:13 - 51:18]
+// CHECK: 51:23: BinaryOperator= Extent=[51:23 - 51:47]
+// CHECK: 51:23: BinaryOperator= Extent=[51:23 - 51:33]
// CHECK: 51:23: DeclRefExpr=c:2:14 Extent=[51:23 - 51:24]
// CHECK: 51:28: UnexposedExpr= Extent=[51:28 - 51:33]
-// CHECK: 51:28: UnexposedExpr= Extent=[51:28 - 51:33]
-// CHECK: 51:37: UnexposedExpr= Extent=[51:37 - 51:47]
+// CHECK: 51:28: IntegerLiteral= Extent=[51:28 - 51:33]
+// CHECK: 51:37: BinaryOperator= Extent=[51:37 - 51:47]
// CHECK: 51:37: DeclRefExpr=c:2:14 Extent=[51:37 - 51:38]
// CHECK: 51:42: UnexposedExpr= Extent=[51:42 - 51:47]
-// CHECK: 51:42: UnexposedExpr= Extent=[51:42 - 51:47]
-// CHECK: 52:9: UnexposedExpr= Extent=[52:9 - 52:33]
-// CHECK: 52:9: UnexposedExpr= Extent=[52:9 - 52:19]
+// CHECK: 51:42: IntegerLiteral= Extent=[51:42 - 51:47]
+// CHECK: 52:9: BinaryOperator= Extent=[52:9 - 52:33]
+// CHECK: 52:9: BinaryOperator= Extent=[52:9 - 52:19]
// CHECK: 52:9: DeclRefExpr=c:2:14 Extent=[52:9 - 52:10]
// CHECK: 52:14: UnexposedExpr= Extent=[52:14 - 52:19]
-// CHECK: 52:14: UnexposedExpr= Extent=[52:14 - 52:19]
-// CHECK: 52:23: UnexposedExpr= Extent=[52:23 - 52:33]
+// CHECK: 52:14: IntegerLiteral= Extent=[52:14 - 52:19]
+// CHECK: 52:23: BinaryOperator= Extent=[52:23 - 52:33]
// CHECK: 52:23: DeclRefExpr=c:2:14 Extent=[52:23 - 52:24]
// CHECK: 52:28: UnexposedExpr= Extent=[52:28 - 52:33]
-// CHECK: 52:28: UnexposedExpr= Extent=[52:28 - 52:33]
-// CHECK: 53:9: UnexposedExpr= Extent=[53:9 - 53:33]
-// CHECK: 53:9: UnexposedExpr= Extent=[53:9 - 53:19]
+// CHECK: 52:28: IntegerLiteral= Extent=[52:28 - 52:33]
+// CHECK: 53:9: BinaryOperator= Extent=[53:9 - 53:33]
+// CHECK: 53:9: BinaryOperator= Extent=[53:9 - 53:19]
// CHECK: 53:9: DeclRefExpr=c:2:14 Extent=[53:9 - 53:10]
// CHECK: 53:14: UnexposedExpr= Extent=[53:14 - 53:19]
-// CHECK: 53:14: UnexposedExpr= Extent=[53:14 - 53:19]
-// CHECK: 53:23: UnexposedExpr= Extent=[53:23 - 53:33]
+// CHECK: 53:14: IntegerLiteral= Extent=[53:14 - 53:19]
+// CHECK: 53:23: BinaryOperator= Extent=[53:23 - 53:33]
// CHECK: 53:23: DeclRefExpr=c:2:14 Extent=[53:23 - 53:24]
// CHECK: 53:28: UnexposedExpr= Extent=[53:28 - 53:33]
-// CHECK: 53:28: UnexposedExpr= Extent=[53:28 - 53:33]
-// CHECK: 54:9: UnexposedExpr= Extent=[54:9 - 54:33]
-// CHECK: 54:9: UnexposedExpr= Extent=[54:9 - 54:19]
+// CHECK: 53:28: IntegerLiteral= Extent=[53:28 - 53:33]
+// CHECK: 54:9: BinaryOperator= Extent=[54:9 - 54:33]
+// CHECK: 54:9: BinaryOperator= Extent=[54:9 - 54:19]
// CHECK: 54:9: DeclRefExpr=c:2:14 Extent=[54:9 - 54:10]
// CHECK: 54:14: UnexposedExpr= Extent=[54:14 - 54:19]
-// CHECK: 54:14: UnexposedExpr= Extent=[54:14 - 54:19]
-// CHECK: 54:23: UnexposedExpr= Extent=[54:23 - 54:33]
+// CHECK: 54:14: IntegerLiteral= Extent=[54:14 - 54:19]
+// CHECK: 54:23: BinaryOperator= Extent=[54:23 - 54:33]
// CHECK: 54:23: DeclRefExpr=c:2:14 Extent=[54:23 - 54:24]
// CHECK: 54:28: UnexposedExpr= Extent=[54:28 - 54:33]
-// CHECK: 54:28: UnexposedExpr= Extent=[54:28 - 54:33]
-// CHECK: 55:9: UnexposedExpr= Extent=[55:9 - 55:33]
-// CHECK: 55:9: UnexposedExpr= Extent=[55:9 - 55:19]
+// CHECK: 54:28: IntegerLiteral= Extent=[54:28 - 54:33]
+// CHECK: 55:9: BinaryOperator= Extent=[55:9 - 55:33]
+// CHECK: 55:9: BinaryOperator= Extent=[55:9 - 55:19]
// CHECK: 55:9: DeclRefExpr=c:2:14 Extent=[55:9 - 55:10]
// CHECK: 55:14: UnexposedExpr= Extent=[55:14 - 55:19]
-// CHECK: 55:14: UnexposedExpr= Extent=[55:14 - 55:19]
-// CHECK: 55:23: UnexposedExpr= Extent=[55:23 - 55:33]
+// CHECK: 55:14: IntegerLiteral= Extent=[55:14 - 55:19]
+// CHECK: 55:23: BinaryOperator= Extent=[55:23 - 55:33]
// CHECK: 55:23: DeclRefExpr=c:2:14 Extent=[55:23 - 55:24]
// CHECK: 55:28: UnexposedExpr= Extent=[55:28 - 55:33]
-// CHECK: 55:28: UnexposedExpr= Extent=[55:28 - 55:33]
-// CHECK: 56:9: UnexposedExpr= Extent=[56:9 - 56:33]
-// CHECK: 56:9: UnexposedExpr= Extent=[56:9 - 56:19]
+// CHECK: 55:28: IntegerLiteral= Extent=[55:28 - 55:33]
+// CHECK: 56:9: BinaryOperator= Extent=[56:9 - 56:33]
+// CHECK: 56:9: BinaryOperator= Extent=[56:9 - 56:19]
// CHECK: 56:9: DeclRefExpr=c:2:14 Extent=[56:9 - 56:10]
// CHECK: 56:14: UnexposedExpr= Extent=[56:14 - 56:19]
-// CHECK: 56:14: UnexposedExpr= Extent=[56:14 - 56:19]
-// CHECK: 56:23: UnexposedExpr= Extent=[56:23 - 56:33]
+// CHECK: 56:14: IntegerLiteral= Extent=[56:14 - 56:19]
+// CHECK: 56:23: BinaryOperator= Extent=[56:23 - 56:33]
// CHECK: 56:23: DeclRefExpr=c:2:14 Extent=[56:23 - 56:24]
// CHECK: 56:28: UnexposedExpr= Extent=[56:28 - 56:33]
-// CHECK: 56:28: UnexposedExpr= Extent=[56:28 - 56:33]
-// CHECK: 57:9: UnexposedExpr= Extent=[57:9 - 57:33]
-// CHECK: 57:9: UnexposedExpr= Extent=[57:9 - 57:19]
+// CHECK: 56:28: IntegerLiteral= Extent=[56:28 - 56:33]
+// CHECK: 57:9: BinaryOperator= Extent=[57:9 - 57:33]
+// CHECK: 57:9: BinaryOperator= Extent=[57:9 - 57:19]
// CHECK: 57:9: DeclRefExpr=c:2:14 Extent=[57:9 - 57:10]
// CHECK: 57:14: UnexposedExpr= Extent=[57:14 - 57:19]
-// CHECK: 57:14: UnexposedExpr= Extent=[57:14 - 57:19]
-// CHECK: 57:23: UnexposedExpr= Extent=[57:23 - 57:33]
+// CHECK: 57:14: IntegerLiteral= Extent=[57:14 - 57:19]
+// CHECK: 57:23: BinaryOperator= Extent=[57:23 - 57:33]
// CHECK: 57:23: DeclRefExpr=c:2:14 Extent=[57:23 - 57:24]
// CHECK: 57:28: UnexposedExpr= Extent=[57:28 - 57:33]
-// CHECK: 57:28: UnexposedExpr= Extent=[57:28 - 57:33]
-// CHECK: 58:9: UnexposedExpr= Extent=[58:9 - 58:33]
-// CHECK: 58:9: UnexposedExpr= Extent=[58:9 - 58:19]
+// CHECK: 57:28: IntegerLiteral= Extent=[57:28 - 57:33]
+// CHECK: 58:9: BinaryOperator= Extent=[58:9 - 58:33]
+// CHECK: 58:9: BinaryOperator= Extent=[58:9 - 58:19]
// CHECK: 58:9: DeclRefExpr=c:2:14 Extent=[58:9 - 58:10]
// CHECK: 58:14: UnexposedExpr= Extent=[58:14 - 58:19]
-// CHECK: 58:14: UnexposedExpr= Extent=[58:14 - 58:19]
-// CHECK: 58:23: UnexposedExpr= Extent=[58:23 - 58:33]
+// CHECK: 58:14: IntegerLiteral= Extent=[58:14 - 58:19]
+// CHECK: 58:23: BinaryOperator= Extent=[58:23 - 58:33]
// CHECK: 58:23: DeclRefExpr=c:2:14 Extent=[58:23 - 58:24]
// CHECK: 58:28: UnexposedExpr= Extent=[58:28 - 58:33]
-// CHECK: 58:28: UnexposedExpr= Extent=[58:28 - 58:33]
-// CHECK: 59:9: UnexposedExpr= Extent=[59:9 - 59:33]
-// CHECK: 59:9: UnexposedExpr= Extent=[59:9 - 59:19]
+// CHECK: 58:28: IntegerLiteral= Extent=[58:28 - 58:33]
+// CHECK: 59:9: BinaryOperator= Extent=[59:9 - 59:33]
+// CHECK: 59:9: BinaryOperator= Extent=[59:9 - 59:19]
// CHECK: 59:9: DeclRefExpr=c:2:14 Extent=[59:9 - 59:10]
// CHECK: 59:14: UnexposedExpr= Extent=[59:14 - 59:19]
-// CHECK: 59:14: UnexposedExpr= Extent=[59:14 - 59:19]
-// CHECK: 59:23: UnexposedExpr= Extent=[59:23 - 59:33]
+// CHECK: 59:14: IntegerLiteral= Extent=[59:14 - 59:19]
+// CHECK: 59:23: BinaryOperator= Extent=[59:23 - 59:33]
// CHECK: 59:23: DeclRefExpr=c:2:14 Extent=[59:23 - 59:24]
// CHECK: 59:28: UnexposedExpr= Extent=[59:28 - 59:33]
-// CHECK: 59:28: UnexposedExpr= Extent=[59:28 - 59:33]
-// CHECK: 60:9: UnexposedExpr= Extent=[60:9 - 60:33]
-// CHECK: 60:9: UnexposedExpr= Extent=[60:9 - 60:19]
+// CHECK: 59:28: IntegerLiteral= Extent=[59:28 - 59:33]
+// CHECK: 60:9: BinaryOperator= Extent=[60:9 - 60:33]
+// CHECK: 60:9: BinaryOperator= Extent=[60:9 - 60:19]
// CHECK: 60:9: DeclRefExpr=c:2:14 Extent=[60:9 - 60:10]
// CHECK: 60:14: UnexposedExpr= Extent=[60:14 - 60:19]
-// CHECK: 60:14: UnexposedExpr= Extent=[60:14 - 60:19]
-// CHECK: 60:23: UnexposedExpr= Extent=[60:23 - 60:33]
+// CHECK: 60:14: IntegerLiteral= Extent=[60:14 - 60:19]
+// CHECK: 60:23: BinaryOperator= Extent=[60:23 - 60:33]
// CHECK: 60:23: DeclRefExpr=c:2:14 Extent=[60:23 - 60:24]
// CHECK: 60:28: UnexposedExpr= Extent=[60:28 - 60:33]
-// CHECK: 60:28: UnexposedExpr= Extent=[60:28 - 60:33]
-// CHECK: 61:9: UnexposedExpr= Extent=[61:9 - 61:33]
-// CHECK: 61:9: UnexposedExpr= Extent=[61:9 - 61:19]
+// CHECK: 60:28: IntegerLiteral= Extent=[60:28 - 60:33]
+// CHECK: 61:9: BinaryOperator= Extent=[61:9 - 61:33]
+// CHECK: 61:9: BinaryOperator= Extent=[61:9 - 61:19]
// CHECK: 61:9: DeclRefExpr=c:2:14 Extent=[61:9 - 61:10]
// CHECK: 61:14: UnexposedExpr= Extent=[61:14 - 61:19]
-// CHECK: 61:14: UnexposedExpr= Extent=[61:14 - 61:19]
-// CHECK: 61:23: UnexposedExpr= Extent=[61:23 - 61:33]
+// CHECK: 61:14: IntegerLiteral= Extent=[61:14 - 61:19]
+// CHECK: 61:23: BinaryOperator= Extent=[61:23 - 61:33]
// CHECK: 61:23: DeclRefExpr=c:2:14 Extent=[61:23 - 61:24]
// CHECK: 61:28: UnexposedExpr= Extent=[61:28 - 61:33]
-// CHECK: 61:28: UnexposedExpr= Extent=[61:28 - 61:33]
-// CHECK: 62:9: UnexposedExpr= Extent=[62:9 - 62:33]
-// CHECK: 62:9: UnexposedExpr= Extent=[62:9 - 62:19]
+// CHECK: 61:28: IntegerLiteral= Extent=[61:28 - 61:33]
+// CHECK: 62:9: BinaryOperator= Extent=[62:9 - 62:33]
+// CHECK: 62:9: BinaryOperator= Extent=[62:9 - 62:19]
// CHECK: 62:9: DeclRefExpr=c:2:14 Extent=[62:9 - 62:10]
// CHECK: 62:14: UnexposedExpr= Extent=[62:14 - 62:19]
-// CHECK: 62:14: UnexposedExpr= Extent=[62:14 - 62:19]
-// CHECK: 62:23: UnexposedExpr= Extent=[62:23 - 62:33]
+// CHECK: 62:14: IntegerLiteral= Extent=[62:14 - 62:19]
+// CHECK: 62:23: BinaryOperator= Extent=[62:23 - 62:33]
// CHECK: 62:23: DeclRefExpr=c:2:14 Extent=[62:23 - 62:24]
// CHECK: 62:28: UnexposedExpr= Extent=[62:28 - 62:33]
-// CHECK: 62:28: UnexposedExpr= Extent=[62:28 - 62:33]
-// CHECK: 63:8: UnexposedExpr= Extent=[63:8 - 63:18]
+// CHECK: 62:28: IntegerLiteral= Extent=[62:28 - 62:33]
+// CHECK: 63:8: BinaryOperator= Extent=[63:8 - 63:18]
// CHECK: 63:8: DeclRefExpr=c:2:14 Extent=[63:8 - 63:9]
// CHECK: 63:13: UnexposedExpr= Extent=[63:13 - 63:18]
-// CHECK: 63:13: UnexposedExpr= Extent=[63:13 - 63:18]
-// CHECK: 63:23: UnexposedExpr= Extent=[63:23 - 63:47]
-// CHECK: 63:23: UnexposedExpr= Extent=[63:23 - 63:33]
+// CHECK: 63:13: IntegerLiteral= Extent=[63:13 - 63:18]
+// CHECK: 63:23: BinaryOperator= Extent=[63:23 - 63:47]
+// CHECK: 63:23: BinaryOperator= Extent=[63:23 - 63:33]
// CHECK: 63:23: DeclRefExpr=c:2:14 Extent=[63:23 - 63:24]
// CHECK: 63:28: UnexposedExpr= Extent=[63:28 - 63:33]
-// CHECK: 63:28: UnexposedExpr= Extent=[63:28 - 63:33]
-// CHECK: 63:37: UnexposedExpr= Extent=[63:37 - 63:47]
+// CHECK: 63:28: IntegerLiteral= Extent=[63:28 - 63:33]
+// CHECK: 63:37: BinaryOperator= Extent=[63:37 - 63:47]
// CHECK: 63:37: DeclRefExpr=c:2:14 Extent=[63:37 - 63:38]
// CHECK: 63:42: UnexposedExpr= Extent=[63:42 - 63:47]
-// CHECK: 63:42: UnexposedExpr= Extent=[63:42 - 63:47]
-// CHECK: 64:9: UnexposedExpr= Extent=[64:9 - 64:33]
-// CHECK: 64:9: UnexposedExpr= Extent=[64:9 - 64:19]
+// CHECK: 63:42: IntegerLiteral= Extent=[63:42 - 63:47]
+// CHECK: 64:9: BinaryOperator= Extent=[64:9 - 64:33]
+// CHECK: 64:9: BinaryOperator= Extent=[64:9 - 64:19]
// CHECK: 64:9: DeclRefExpr=c:2:14 Extent=[64:9 - 64:10]
// CHECK: 64:14: UnexposedExpr= Extent=[64:14 - 64:19]
-// CHECK: 64:14: UnexposedExpr= Extent=[64:14 - 64:19]
-// CHECK: 64:23: UnexposedExpr= Extent=[64:23 - 64:33]
+// CHECK: 64:14: IntegerLiteral= Extent=[64:14 - 64:19]
+// CHECK: 64:23: BinaryOperator= Extent=[64:23 - 64:33]
// CHECK: 64:23: DeclRefExpr=c:2:14 Extent=[64:23 - 64:24]
// CHECK: 64:28: UnexposedExpr= Extent=[64:28 - 64:33]
-// CHECK: 64:28: UnexposedExpr= Extent=[64:28 - 64:33]
-// CHECK: 65:8: UnexposedExpr= Extent=[65:8 - 65:18]
+// CHECK: 64:28: IntegerLiteral= Extent=[64:28 - 64:33]
+// CHECK: 65:8: BinaryOperator= Extent=[65:8 - 65:18]
// CHECK: 65:8: DeclRefExpr=c:2:14 Extent=[65:8 - 65:9]
// CHECK: 65:13: UnexposedExpr= Extent=[65:13 - 65:18]
-// CHECK: 65:13: UnexposedExpr= Extent=[65:13 - 65:18]
-// CHECK: 65:23: UnexposedExpr= Extent=[65:23 - 65:47]
-// CHECK: 65:23: UnexposedExpr= Extent=[65:23 - 65:33]
+// CHECK: 65:13: IntegerLiteral= Extent=[65:13 - 65:18]
+// CHECK: 65:23: BinaryOperator= Extent=[65:23 - 65:47]
+// CHECK: 65:23: BinaryOperator= Extent=[65:23 - 65:33]
// CHECK: 65:23: DeclRefExpr=c:2:14 Extent=[65:23 - 65:24]
// CHECK: 65:28: UnexposedExpr= Extent=[65:28 - 65:33]
-// CHECK: 65:28: UnexposedExpr= Extent=[65:28 - 65:33]
-// CHECK: 65:37: UnexposedExpr= Extent=[65:37 - 65:47]
+// CHECK: 65:28: IntegerLiteral= Extent=[65:28 - 65:33]
+// CHECK: 65:37: BinaryOperator= Extent=[65:37 - 65:47]
// CHECK: 65:37: DeclRefExpr=c:2:14 Extent=[65:37 - 65:38]
// CHECK: 65:42: UnexposedExpr= Extent=[65:42 - 65:47]
-// CHECK: 65:42: UnexposedExpr= Extent=[65:42 - 65:47]
-// CHECK: 66:9: UnexposedExpr= Extent=[66:9 - 66:33]
-// CHECK: 66:9: UnexposedExpr= Extent=[66:9 - 66:19]
+// CHECK: 65:42: IntegerLiteral= Extent=[65:42 - 65:47]
+// CHECK: 66:9: BinaryOperator= Extent=[66:9 - 66:33]
+// CHECK: 66:9: BinaryOperator= Extent=[66:9 - 66:19]
// CHECK: 66:9: DeclRefExpr=c:2:14 Extent=[66:9 - 66:10]
// CHECK: 66:14: UnexposedExpr= Extent=[66:14 - 66:19]
-// CHECK: 66:14: UnexposedExpr= Extent=[66:14 - 66:19]
-// CHECK: 66:23: UnexposedExpr= Extent=[66:23 - 66:33]
+// CHECK: 66:14: IntegerLiteral= Extent=[66:14 - 66:19]
+// CHECK: 66:23: BinaryOperator= Extent=[66:23 - 66:33]
// CHECK: 66:23: DeclRefExpr=c:2:14 Extent=[66:23 - 66:24]
// CHECK: 66:28: UnexposedExpr= Extent=[66:28 - 66:33]
-// CHECK: 66:28: UnexposedExpr= Extent=[66:28 - 66:33]
-// CHECK: 67:9: UnexposedExpr= Extent=[67:9 - 67:33]
-// CHECK: 67:9: UnexposedExpr= Extent=[67:9 - 67:19]
+// CHECK: 66:28: IntegerLiteral= Extent=[66:28 - 66:33]
+// CHECK: 67:9: BinaryOperator= Extent=[67:9 - 67:33]
+// CHECK: 67:9: BinaryOperator= Extent=[67:9 - 67:19]
// CHECK: 67:9: DeclRefExpr=c:2:14 Extent=[67:9 - 67:10]
// CHECK: 67:14: UnexposedExpr= Extent=[67:14 - 67:19]
-// CHECK: 67:14: UnexposedExpr= Extent=[67:14 - 67:19]
-// CHECK: 67:23: UnexposedExpr= Extent=[67:23 - 67:33]
+// CHECK: 67:14: IntegerLiteral= Extent=[67:14 - 67:19]
+// CHECK: 67:23: BinaryOperator= Extent=[67:23 - 67:33]
// CHECK: 67:23: DeclRefExpr=c:2:14 Extent=[67:23 - 67:24]
// CHECK: 67:28: UnexposedExpr= Extent=[67:28 - 67:33]
-// CHECK: 67:28: UnexposedExpr= Extent=[67:28 - 67:33]
-// CHECK: 68:9: UnexposedExpr= Extent=[68:9 - 68:33]
-// CHECK: 68:9: UnexposedExpr= Extent=[68:9 - 68:19]
+// CHECK: 67:28: IntegerLiteral= Extent=[67:28 - 67:33]
+// CHECK: 68:9: BinaryOperator= Extent=[68:9 - 68:33]
+// CHECK: 68:9: BinaryOperator= Extent=[68:9 - 68:19]
// CHECK: 68:9: DeclRefExpr=c:2:14 Extent=[68:9 - 68:10]
// CHECK: 68:14: UnexposedExpr= Extent=[68:14 - 68:19]
-// CHECK: 68:14: UnexposedExpr= Extent=[68:14 - 68:19]
-// CHECK: 68:23: UnexposedExpr= Extent=[68:23 - 68:33]
+// CHECK: 68:14: IntegerLiteral= Extent=[68:14 - 68:19]
+// CHECK: 68:23: BinaryOperator= Extent=[68:23 - 68:33]
// CHECK: 68:23: DeclRefExpr=c:2:14 Extent=[68:23 - 68:24]
// CHECK: 68:28: UnexposedExpr= Extent=[68:28 - 68:33]
-// CHECK: 68:28: UnexposedExpr= Extent=[68:28 - 68:33]
-// CHECK: 69:9: UnexposedExpr= Extent=[69:9 - 69:33]
-// CHECK: 69:9: UnexposedExpr= Extent=[69:9 - 69:19]
+// CHECK: 68:28: IntegerLiteral= Extent=[68:28 - 68:33]
+// CHECK: 69:9: BinaryOperator= Extent=[69:9 - 69:33]
+// CHECK: 69:9: BinaryOperator= Extent=[69:9 - 69:19]
// CHECK: 69:9: DeclRefExpr=c:2:14 Extent=[69:9 - 69:10]
// CHECK: 69:14: UnexposedExpr= Extent=[69:14 - 69:19]
-// CHECK: 69:14: UnexposedExpr= Extent=[69:14 - 69:19]
-// CHECK: 69:23: UnexposedExpr= Extent=[69:23 - 69:33]
+// CHECK: 69:14: IntegerLiteral= Extent=[69:14 - 69:19]
+// CHECK: 69:23: BinaryOperator= Extent=[69:23 - 69:33]
// CHECK: 69:23: DeclRefExpr=c:2:14 Extent=[69:23 - 69:24]
// CHECK: 69:28: UnexposedExpr= Extent=[69:28 - 69:33]
-// CHECK: 69:28: UnexposedExpr= Extent=[69:28 - 69:33]
-// CHECK: 70:8: UnexposedExpr= Extent=[70:8 - 70:18]
+// CHECK: 69:28: IntegerLiteral= Extent=[69:28 - 69:33]
+// CHECK: 70:8: BinaryOperator= Extent=[70:8 - 70:18]
// CHECK: 70:8: DeclRefExpr=c:2:14 Extent=[70:8 - 70:9]
// CHECK: 70:13: UnexposedExpr= Extent=[70:13 - 70:18]
-// CHECK: 70:13: UnexposedExpr= Extent=[70:13 - 70:18]
-// CHECK: 70:22: UnexposedExpr= Extent=[70:22 - 70:32]
+// CHECK: 70:13: IntegerLiteral= Extent=[70:13 - 70:18]
+// CHECK: 70:22: BinaryOperator= Extent=[70:22 - 70:32]
// CHECK: 70:22: DeclRefExpr=c:2:14 Extent=[70:22 - 70:23]
// CHECK: 70:27: UnexposedExpr= Extent=[70:27 - 70:32]
-// CHECK: 70:27: UnexposedExpr= Extent=[70:27 - 70:32]
-// CHECK: 70:37: UnexposedExpr= Extent=[70:37 - 70:61]
-// CHECK: 70:37: UnexposedExpr= Extent=[70:37 - 70:47]
+// CHECK: 70:27: IntegerLiteral= Extent=[70:27 - 70:32]
+// CHECK: 70:37: BinaryOperator= Extent=[70:37 - 70:61]
+// CHECK: 70:37: BinaryOperator= Extent=[70:37 - 70:47]
// CHECK: 70:37: DeclRefExpr=c:2:14 Extent=[70:37 - 70:38]
// CHECK: 70:42: UnexposedExpr= Extent=[70:42 - 70:47]
-// CHECK: 70:42: UnexposedExpr= Extent=[70:42 - 70:47]
-// CHECK: 70:51: UnexposedExpr= Extent=[70:51 - 70:61]
+// CHECK: 70:42: IntegerLiteral= Extent=[70:42 - 70:47]
+// CHECK: 70:51: BinaryOperator= Extent=[70:51 - 70:61]
// CHECK: 70:51: DeclRefExpr=c:2:14 Extent=[70:51 - 70:52]
// CHECK: 70:56: UnexposedExpr= Extent=[70:56 - 70:61]
-// CHECK: 70:56: UnexposedExpr= Extent=[70:56 - 70:61]
-// CHECK: 71:9: UnexposedExpr= Extent=[71:9 - 71:33]
-// CHECK: 71:9: UnexposedExpr= Extent=[71:9 - 71:19]
+// CHECK: 70:56: IntegerLiteral= Extent=[70:56 - 70:61]
+// CHECK: 71:9: BinaryOperator= Extent=[71:9 - 71:33]
+// CHECK: 71:9: BinaryOperator= Extent=[71:9 - 71:19]
// CHECK: 71:9: DeclRefExpr=c:2:14 Extent=[71:9 - 71:10]
// CHECK: 71:14: UnexposedExpr= Extent=[71:14 - 71:19]
-// CHECK: 71:14: UnexposedExpr= Extent=[71:14 - 71:19]
-// CHECK: 71:23: UnexposedExpr= Extent=[71:23 - 71:33]
+// CHECK: 71:14: IntegerLiteral= Extent=[71:14 - 71:19]
+// CHECK: 71:23: BinaryOperator= Extent=[71:23 - 71:33]
// CHECK: 71:23: DeclRefExpr=c:2:14 Extent=[71:23 - 71:24]
// CHECK: 71:28: UnexposedExpr= Extent=[71:28 - 71:33]
-// CHECK: 71:28: UnexposedExpr= Extent=[71:28 - 71:33]
-// CHECK: 72:9: UnexposedExpr= Extent=[72:9 - 72:33]
-// CHECK: 72:9: UnexposedExpr= Extent=[72:9 - 72:19]
+// CHECK: 71:28: IntegerLiteral= Extent=[71:28 - 71:33]
+// CHECK: 72:9: BinaryOperator= Extent=[72:9 - 72:33]
+// CHECK: 72:9: BinaryOperator= Extent=[72:9 - 72:19]
// CHECK: 72:9: DeclRefExpr=c:2:14 Extent=[72:9 - 72:10]
// CHECK: 72:14: UnexposedExpr= Extent=[72:14 - 72:19]
-// CHECK: 72:14: UnexposedExpr= Extent=[72:14 - 72:19]
-// CHECK: 72:23: UnexposedExpr= Extent=[72:23 - 72:33]
+// CHECK: 72:14: IntegerLiteral= Extent=[72:14 - 72:19]
+// CHECK: 72:23: BinaryOperator= Extent=[72:23 - 72:33]
// CHECK: 72:23: DeclRefExpr=c:2:14 Extent=[72:23 - 72:24]
// CHECK: 72:28: UnexposedExpr= Extent=[72:28 - 72:33]
-// CHECK: 72:28: UnexposedExpr= Extent=[72:28 - 72:33]
-// CHECK: 73:9: UnexposedExpr= Extent=[73:9 - 73:33]
-// CHECK: 73:9: UnexposedExpr= Extent=[73:9 - 73:19]
+// CHECK: 72:28: IntegerLiteral= Extent=[72:28 - 72:33]
+// CHECK: 73:9: BinaryOperator= Extent=[73:9 - 73:33]
+// CHECK: 73:9: BinaryOperator= Extent=[73:9 - 73:19]
// CHECK: 73:9: DeclRefExpr=c:2:14 Extent=[73:9 - 73:10]
// CHECK: 73:14: UnexposedExpr= Extent=[73:14 - 73:19]
-// CHECK: 73:14: UnexposedExpr= Extent=[73:14 - 73:19]
-// CHECK: 73:23: UnexposedExpr= Extent=[73:23 - 73:33]
+// CHECK: 73:14: IntegerLiteral= Extent=[73:14 - 73:19]
+// CHECK: 73:23: BinaryOperator= Extent=[73:23 - 73:33]
// CHECK: 73:23: DeclRefExpr=c:2:14 Extent=[73:23 - 73:24]
// CHECK: 73:28: UnexposedExpr= Extent=[73:28 - 73:33]
-// CHECK: 73:28: UnexposedExpr= Extent=[73:28 - 73:33]
-// CHECK: 74:9: UnexposedExpr= Extent=[74:9 - 74:33]
-// CHECK: 74:9: UnexposedExpr= Extent=[74:9 - 74:19]
+// CHECK: 73:28: IntegerLiteral= Extent=[73:28 - 73:33]
+// CHECK: 74:9: BinaryOperator= Extent=[74:9 - 74:33]
+// CHECK: 74:9: BinaryOperator= Extent=[74:9 - 74:19]
// CHECK: 74:9: DeclRefExpr=c:2:14 Extent=[74:9 - 74:10]
// CHECK: 74:14: UnexposedExpr= Extent=[74:14 - 74:19]
-// CHECK: 74:14: UnexposedExpr= Extent=[74:14 - 74:19]
-// CHECK: 74:23: UnexposedExpr= Extent=[74:23 - 74:33]
+// CHECK: 74:14: IntegerLiteral= Extent=[74:14 - 74:19]
+// CHECK: 74:23: BinaryOperator= Extent=[74:23 - 74:33]
// CHECK: 74:23: DeclRefExpr=c:2:14 Extent=[74:23 - 74:24]
// CHECK: 74:28: UnexposedExpr= Extent=[74:28 - 74:33]
-// CHECK: 74:28: UnexposedExpr= Extent=[74:28 - 74:33]
-// CHECK: 75:9: UnexposedExpr= Extent=[75:9 - 75:33]
-// CHECK: 75:9: UnexposedExpr= Extent=[75:9 - 75:19]
+// CHECK: 74:28: IntegerLiteral= Extent=[74:28 - 74:33]
+// CHECK: 75:9: BinaryOperator= Extent=[75:9 - 75:33]
+// CHECK: 75:9: BinaryOperator= Extent=[75:9 - 75:19]
// CHECK: 75:9: DeclRefExpr=c:2:14 Extent=[75:9 - 75:10]
// CHECK: 75:14: UnexposedExpr= Extent=[75:14 - 75:19]
-// CHECK: 75:14: UnexposedExpr= Extent=[75:14 - 75:19]
-// CHECK: 75:23: UnexposedExpr= Extent=[75:23 - 75:33]
+// CHECK: 75:14: IntegerLiteral= Extent=[75:14 - 75:19]
+// CHECK: 75:23: BinaryOperator= Extent=[75:23 - 75:33]
// CHECK: 75:23: DeclRefExpr=c:2:14 Extent=[75:23 - 75:24]
// CHECK: 75:28: UnexposedExpr= Extent=[75:28 - 75:33]
-// CHECK: 75:28: UnexposedExpr= Extent=[75:28 - 75:33]
-// CHECK: 76:8: UnexposedExpr= Extent=[76:8 - 76:18]
+// CHECK: 75:28: IntegerLiteral= Extent=[75:28 - 75:33]
+// CHECK: 76:8: BinaryOperator= Extent=[76:8 - 76:18]
// CHECK: 76:8: DeclRefExpr=c:2:14 Extent=[76:8 - 76:9]
// CHECK: 76:13: UnexposedExpr= Extent=[76:13 - 76:18]
-// CHECK: 76:13: UnexposedExpr= Extent=[76:13 - 76:18]
-// CHECK: 76:23: UnexposedExpr= Extent=[76:23 - 76:47]
-// CHECK: 76:23: UnexposedExpr= Extent=[76:23 - 76:33]
+// CHECK: 76:13: IntegerLiteral= Extent=[76:13 - 76:18]
+// CHECK: 76:23: BinaryOperator= Extent=[76:23 - 76:47]
+// CHECK: 76:23: BinaryOperator= Extent=[76:23 - 76:33]
// CHECK: 76:23: DeclRefExpr=c:2:14 Extent=[76:23 - 76:24]
// CHECK: 76:28: UnexposedExpr= Extent=[76:28 - 76:33]
-// CHECK: 76:28: UnexposedExpr= Extent=[76:28 - 76:33]
-// CHECK: 76:37: UnexposedExpr= Extent=[76:37 - 76:47]
+// CHECK: 76:28: IntegerLiteral= Extent=[76:28 - 76:33]
+// CHECK: 76:37: BinaryOperator= Extent=[76:37 - 76:47]
// CHECK: 76:37: DeclRefExpr=c:2:14 Extent=[76:37 - 76:38]
// CHECK: 76:42: UnexposedExpr= Extent=[76:42 - 76:47]
-// CHECK: 76:42: UnexposedExpr= Extent=[76:42 - 76:47]
-// CHECK: 77:9: UnexposedExpr= Extent=[77:9 - 77:33]
-// CHECK: 77:9: UnexposedExpr= Extent=[77:9 - 77:19]
+// CHECK: 76:42: IntegerLiteral= Extent=[76:42 - 76:47]
+// CHECK: 77:9: BinaryOperator= Extent=[77:9 - 77:33]
+// CHECK: 77:9: BinaryOperator= Extent=[77:9 - 77:19]
// CHECK: 77:9: DeclRefExpr=c:2:14 Extent=[77:9 - 77:10]
// CHECK: 77:14: UnexposedExpr= Extent=[77:14 - 77:19]
-// CHECK: 77:14: UnexposedExpr= Extent=[77:14 - 77:19]
-// CHECK: 77:23: UnexposedExpr= Extent=[77:23 - 77:33]
+// CHECK: 77:14: IntegerLiteral= Extent=[77:14 - 77:19]
+// CHECK: 77:23: BinaryOperator= Extent=[77:23 - 77:33]
// CHECK: 77:23: DeclRefExpr=c:2:14 Extent=[77:23 - 77:24]
// CHECK: 77:28: UnexposedExpr= Extent=[77:28 - 77:33]
-// CHECK: 77:28: UnexposedExpr= Extent=[77:28 - 77:33]
-// CHECK: 78:9: UnexposedExpr= Extent=[78:9 - 78:33]
-// CHECK: 78:9: UnexposedExpr= Extent=[78:9 - 78:19]
+// CHECK: 77:28: IntegerLiteral= Extent=[77:28 - 77:33]
+// CHECK: 78:9: BinaryOperator= Extent=[78:9 - 78:33]
+// CHECK: 78:9: BinaryOperator= Extent=[78:9 - 78:19]
// CHECK: 78:9: DeclRefExpr=c:2:14 Extent=[78:9 - 78:10]
// CHECK: 78:14: UnexposedExpr= Extent=[78:14 - 78:19]
-// CHECK: 78:14: UnexposedExpr= Extent=[78:14 - 78:19]
-// CHECK: 78:23: UnexposedExpr= Extent=[78:23 - 78:33]
+// CHECK: 78:14: IntegerLiteral= Extent=[78:14 - 78:19]
+// CHECK: 78:23: BinaryOperator= Extent=[78:23 - 78:33]
// CHECK: 78:23: DeclRefExpr=c:2:14 Extent=[78:23 - 78:24]
// CHECK: 78:28: UnexposedExpr= Extent=[78:28 - 78:33]
-// CHECK: 78:28: UnexposedExpr= Extent=[78:28 - 78:33]
-// CHECK: 79:9: UnexposedExpr= Extent=[79:9 - 79:33]
-// CHECK: 79:9: UnexposedExpr= Extent=[79:9 - 79:19]
+// CHECK: 78:28: IntegerLiteral= Extent=[78:28 - 78:33]
+// CHECK: 79:9: BinaryOperator= Extent=[79:9 - 79:33]
+// CHECK: 79:9: BinaryOperator= Extent=[79:9 - 79:19]
// CHECK: 79:9: DeclRefExpr=c:2:14 Extent=[79:9 - 79:10]
// CHECK: 79:14: UnexposedExpr= Extent=[79:14 - 79:19]
-// CHECK: 79:14: UnexposedExpr= Extent=[79:14 - 79:19]
-// CHECK: 79:23: UnexposedExpr= Extent=[79:23 - 79:33]
+// CHECK: 79:14: IntegerLiteral= Extent=[79:14 - 79:19]
+// CHECK: 79:23: BinaryOperator= Extent=[79:23 - 79:33]
// CHECK: 79:23: DeclRefExpr=c:2:14 Extent=[79:23 - 79:24]
// CHECK: 79:28: UnexposedExpr= Extent=[79:28 - 79:33]
-// CHECK: 79:28: UnexposedExpr= Extent=[79:28 - 79:33]
-// CHECK: 80:9: UnexposedExpr= Extent=[80:9 - 80:33]
-// CHECK: 80:9: UnexposedExpr= Extent=[80:9 - 80:19]
+// CHECK: 79:28: IntegerLiteral= Extent=[79:28 - 79:33]
+// CHECK: 80:9: BinaryOperator= Extent=[80:9 - 80:33]
+// CHECK: 80:9: BinaryOperator= Extent=[80:9 - 80:19]
// CHECK: 80:9: DeclRefExpr=c:2:14 Extent=[80:9 - 80:10]
// CHECK: 80:14: UnexposedExpr= Extent=[80:14 - 80:19]
-// CHECK: 80:14: UnexposedExpr= Extent=[80:14 - 80:19]
-// CHECK: 80:23: UnexposedExpr= Extent=[80:23 - 80:33]
+// CHECK: 80:14: IntegerLiteral= Extent=[80:14 - 80:19]
+// CHECK: 80:23: BinaryOperator= Extent=[80:23 - 80:33]
// CHECK: 80:23: DeclRefExpr=c:2:14 Extent=[80:23 - 80:24]
// CHECK: 80:28: UnexposedExpr= Extent=[80:28 - 80:33]
-// CHECK: 80:28: UnexposedExpr= Extent=[80:28 - 80:33]
-// CHECK: 81:9: UnexposedExpr= Extent=[81:9 - 81:33]
-// CHECK: 81:9: UnexposedExpr= Extent=[81:9 - 81:19]
+// CHECK: 80:28: IntegerLiteral= Extent=[80:28 - 80:33]
+// CHECK: 81:9: BinaryOperator= Extent=[81:9 - 81:33]
+// CHECK: 81:9: BinaryOperator= Extent=[81:9 - 81:19]
// CHECK: 81:9: DeclRefExpr=c:2:14 Extent=[81:9 - 81:10]
// CHECK: 81:14: UnexposedExpr= Extent=[81:14 - 81:19]
-// CHECK: 81:14: UnexposedExpr= Extent=[81:14 - 81:19]
-// CHECK: 81:23: UnexposedExpr= Extent=[81:23 - 81:33]
+// CHECK: 81:14: IntegerLiteral= Extent=[81:14 - 81:19]
+// CHECK: 81:23: BinaryOperator= Extent=[81:23 - 81:33]
// CHECK: 81:23: DeclRefExpr=c:2:14 Extent=[81:23 - 81:24]
// CHECK: 81:28: UnexposedExpr= Extent=[81:28 - 81:33]
-// CHECK: 81:28: UnexposedExpr= Extent=[81:28 - 81:33]
-// CHECK: 82:8: UnexposedExpr= Extent=[82:8 - 82:18]
+// CHECK: 81:28: IntegerLiteral= Extent=[81:28 - 81:33]
+// CHECK: 82:8: BinaryOperator= Extent=[82:8 - 82:18]
// CHECK: 82:8: DeclRefExpr=c:2:14 Extent=[82:8 - 82:9]
// CHECK: 82:13: UnexposedExpr= Extent=[82:13 - 82:18]
-// CHECK: 82:13: UnexposedExpr= Extent=[82:13 - 82:18]
-// CHECK: 82:23: UnexposedExpr= Extent=[82:23 - 82:47]
-// CHECK: 82:23: UnexposedExpr= Extent=[82:23 - 82:33]
+// CHECK: 82:13: IntegerLiteral= Extent=[82:13 - 82:18]
+// CHECK: 82:23: BinaryOperator= Extent=[82:23 - 82:47]
+// CHECK: 82:23: BinaryOperator= Extent=[82:23 - 82:33]
// CHECK: 82:23: DeclRefExpr=c:2:14 Extent=[82:23 - 82:24]
// CHECK: 82:28: UnexposedExpr= Extent=[82:28 - 82:33]
-// CHECK: 82:28: UnexposedExpr= Extent=[82:28 - 82:33]
-// CHECK: 82:37: UnexposedExpr= Extent=[82:37 - 82:47]
+// CHECK: 82:28: IntegerLiteral= Extent=[82:28 - 82:33]
+// CHECK: 82:37: BinaryOperator= Extent=[82:37 - 82:47]
// CHECK: 82:37: DeclRefExpr=c:2:14 Extent=[82:37 - 82:38]
// CHECK: 82:42: UnexposedExpr= Extent=[82:42 - 82:47]
-// CHECK: 82:42: UnexposedExpr= Extent=[82:42 - 82:47]
-// CHECK: 83:9: UnexposedExpr= Extent=[83:9 - 83:33]
-// CHECK: 83:9: UnexposedExpr= Extent=[83:9 - 83:19]
+// CHECK: 82:42: IntegerLiteral= Extent=[82:42 - 82:47]
+// CHECK: 83:9: BinaryOperator= Extent=[83:9 - 83:33]
+// CHECK: 83:9: BinaryOperator= Extent=[83:9 - 83:19]
// CHECK: 83:9: DeclRefExpr=c:2:14 Extent=[83:9 - 83:10]
// CHECK: 83:14: UnexposedExpr= Extent=[83:14 - 83:19]
-// CHECK: 83:14: UnexposedExpr= Extent=[83:14 - 83:19]
-// CHECK: 83:23: UnexposedExpr= Extent=[83:23 - 83:33]
+// CHECK: 83:14: IntegerLiteral= Extent=[83:14 - 83:19]
+// CHECK: 83:23: BinaryOperator= Extent=[83:23 - 83:33]
// CHECK: 83:23: DeclRefExpr=c:2:14 Extent=[83:23 - 83:24]
// CHECK: 83:28: UnexposedExpr= Extent=[83:28 - 83:33]
-// CHECK: 83:28: UnexposedExpr= Extent=[83:28 - 83:33]
-// CHECK: 84:9: UnexposedExpr= Extent=[84:9 - 84:33]
-// CHECK: 84:9: UnexposedExpr= Extent=[84:9 - 84:19]
+// CHECK: 83:28: IntegerLiteral= Extent=[83:28 - 83:33]
+// CHECK: 84:9: BinaryOperator= Extent=[84:9 - 84:33]
+// CHECK: 84:9: BinaryOperator= Extent=[84:9 - 84:19]
// CHECK: 84:9: DeclRefExpr=c:2:14 Extent=[84:9 - 84:10]
// CHECK: 84:14: UnexposedExpr= Extent=[84:14 - 84:19]
-// CHECK: 84:14: UnexposedExpr= Extent=[84:14 - 84:19]
-// CHECK: 84:23: UnexposedExpr= Extent=[84:23 - 84:33]
+// CHECK: 84:14: IntegerLiteral= Extent=[84:14 - 84:19]
+// CHECK: 84:23: BinaryOperator= Extent=[84:23 - 84:33]
// CHECK: 84:23: DeclRefExpr=c:2:14 Extent=[84:23 - 84:24]
// CHECK: 84:28: UnexposedExpr= Extent=[84:28 - 84:33]
-// CHECK: 84:28: UnexposedExpr= Extent=[84:28 - 84:33]
-// CHECK: 85:9: UnexposedExpr= Extent=[85:9 - 85:33]
-// CHECK: 85:9: UnexposedExpr= Extent=[85:9 - 85:19]
+// CHECK: 84:28: IntegerLiteral= Extent=[84:28 - 84:33]
+// CHECK: 85:9: BinaryOperator= Extent=[85:9 - 85:33]
+// CHECK: 85:9: BinaryOperator= Extent=[85:9 - 85:19]
// CHECK: 85:9: DeclRefExpr=c:2:14 Extent=[85:9 - 85:10]
// CHECK: 85:14: UnexposedExpr= Extent=[85:14 - 85:19]
-// CHECK: 85:14: UnexposedExpr= Extent=[85:14 - 85:19]
-// CHECK: 85:23: UnexposedExpr= Extent=[85:23 - 85:33]
+// CHECK: 85:14: IntegerLiteral= Extent=[85:14 - 85:19]
+// CHECK: 85:23: BinaryOperator= Extent=[85:23 - 85:33]
// CHECK: 85:23: DeclRefExpr=c:2:14 Extent=[85:23 - 85:24]
// CHECK: 85:28: UnexposedExpr= Extent=[85:28 - 85:33]
-// CHECK: 85:28: UnexposedExpr= Extent=[85:28 - 85:33]
-// CHECK: 86:9: UnexposedExpr= Extent=[86:9 - 86:33]
-// CHECK: 86:9: UnexposedExpr= Extent=[86:9 - 86:19]
+// CHECK: 85:28: IntegerLiteral= Extent=[85:28 - 85:33]
+// CHECK: 86:9: BinaryOperator= Extent=[86:9 - 86:33]
+// CHECK: 86:9: BinaryOperator= Extent=[86:9 - 86:19]
// CHECK: 86:9: DeclRefExpr=c:2:14 Extent=[86:9 - 86:10]
// CHECK: 86:14: UnexposedExpr= Extent=[86:14 - 86:19]
-// CHECK: 86:14: UnexposedExpr= Extent=[86:14 - 86:19]
-// CHECK: 86:23: UnexposedExpr= Extent=[86:23 - 86:33]
+// CHECK: 86:14: IntegerLiteral= Extent=[86:14 - 86:19]
+// CHECK: 86:23: BinaryOperator= Extent=[86:23 - 86:33]
// CHECK: 86:23: DeclRefExpr=c:2:14 Extent=[86:23 - 86:24]
// CHECK: 86:28: UnexposedExpr= Extent=[86:28 - 86:33]
-// CHECK: 86:28: UnexposedExpr= Extent=[86:28 - 86:33]
-// CHECK: 87:9: UnexposedExpr= Extent=[87:9 - 87:33]
-// CHECK: 87:9: UnexposedExpr= Extent=[87:9 - 87:19]
+// CHECK: 86:28: IntegerLiteral= Extent=[86:28 - 86:33]
+// CHECK: 87:9: BinaryOperator= Extent=[87:9 - 87:33]
+// CHECK: 87:9: BinaryOperator= Extent=[87:9 - 87:19]
// CHECK: 87:9: DeclRefExpr=c:2:14 Extent=[87:9 - 87:10]
// CHECK: 87:14: UnexposedExpr= Extent=[87:14 - 87:19]
-// CHECK: 87:14: UnexposedExpr= Extent=[87:14 - 87:19]
-// CHECK: 87:23: UnexposedExpr= Extent=[87:23 - 87:33]
+// CHECK: 87:14: IntegerLiteral= Extent=[87:14 - 87:19]
+// CHECK: 87:23: BinaryOperator= Extent=[87:23 - 87:33]
// CHECK: 87:23: DeclRefExpr=c:2:14 Extent=[87:23 - 87:24]
// CHECK: 87:28: UnexposedExpr= Extent=[87:28 - 87:33]
-// CHECK: 87:28: UnexposedExpr= Extent=[87:28 - 87:33]
-// CHECK: 88:9: UnexposedExpr= Extent=[88:9 - 88:33]
-// CHECK: 88:9: UnexposedExpr= Extent=[88:9 - 88:19]
+// CHECK: 87:28: IntegerLiteral= Extent=[87:28 - 87:33]
+// CHECK: 88:9: BinaryOperator= Extent=[88:9 - 88:33]
+// CHECK: 88:9: BinaryOperator= Extent=[88:9 - 88:19]
// CHECK: 88:9: DeclRefExpr=c:2:14 Extent=[88:9 - 88:10]
// CHECK: 88:14: UnexposedExpr= Extent=[88:14 - 88:19]
-// CHECK: 88:14: UnexposedExpr= Extent=[88:14 - 88:19]
-// CHECK: 88:23: UnexposedExpr= Extent=[88:23 - 88:33]
+// CHECK: 88:14: IntegerLiteral= Extent=[88:14 - 88:19]
+// CHECK: 88:23: BinaryOperator= Extent=[88:23 - 88:33]
// CHECK: 88:23: DeclRefExpr=c:2:14 Extent=[88:23 - 88:24]
// CHECK: 88:28: UnexposedExpr= Extent=[88:28 - 88:33]
-// CHECK: 88:28: UnexposedExpr= Extent=[88:28 - 88:33]
-// CHECK: 89:9: UnexposedExpr= Extent=[89:9 - 89:33]
-// CHECK: 89:9: UnexposedExpr= Extent=[89:9 - 89:19]
+// CHECK: 88:28: IntegerLiteral= Extent=[88:28 - 88:33]
+// CHECK: 89:9: BinaryOperator= Extent=[89:9 - 89:33]
+// CHECK: 89:9: BinaryOperator= Extent=[89:9 - 89:19]
// CHECK: 89:9: DeclRefExpr=c:2:14 Extent=[89:9 - 89:10]
// CHECK: 89:14: UnexposedExpr= Extent=[89:14 - 89:19]
-// CHECK: 89:14: UnexposedExpr= Extent=[89:14 - 89:19]
-// CHECK: 89:23: UnexposedExpr= Extent=[89:23 - 89:33]
+// CHECK: 89:14: IntegerLiteral= Extent=[89:14 - 89:19]
+// CHECK: 89:23: BinaryOperator= Extent=[89:23 - 89:33]
// CHECK: 89:23: DeclRefExpr=c:2:14 Extent=[89:23 - 89:24]
// CHECK: 89:28: UnexposedExpr= Extent=[89:28 - 89:33]
-// CHECK: 89:28: UnexposedExpr= Extent=[89:28 - 89:33]
-// CHECK: 90:9: UnexposedExpr= Extent=[90:9 - 90:33]
-// CHECK: 90:9: UnexposedExpr= Extent=[90:9 - 90:19]
+// CHECK: 89:28: IntegerLiteral= Extent=[89:28 - 89:33]
+// CHECK: 90:9: BinaryOperator= Extent=[90:9 - 90:33]
+// CHECK: 90:9: BinaryOperator= Extent=[90:9 - 90:19]
// CHECK: 90:9: DeclRefExpr=c:2:14 Extent=[90:9 - 90:10]
// CHECK: 90:14: UnexposedExpr= Extent=[90:14 - 90:19]
-// CHECK: 90:14: UnexposedExpr= Extent=[90:14 - 90:19]
-// CHECK: 90:23: UnexposedExpr= Extent=[90:23 - 90:33]
+// CHECK: 90:14: IntegerLiteral= Extent=[90:14 - 90:19]
+// CHECK: 90:23: BinaryOperator= Extent=[90:23 - 90:33]
// CHECK: 90:23: DeclRefExpr=c:2:14 Extent=[90:23 - 90:24]
// CHECK: 90:28: UnexposedExpr= Extent=[90:28 - 90:33]
-// CHECK: 90:28: UnexposedExpr= Extent=[90:28 - 90:33]
-// CHECK: 91:9: UnexposedExpr= Extent=[91:9 - 91:33]
-// CHECK: 91:9: UnexposedExpr= Extent=[91:9 - 91:19]
+// CHECK: 90:28: IntegerLiteral= Extent=[90:28 - 90:33]
+// CHECK: 91:9: BinaryOperator= Extent=[91:9 - 91:33]
+// CHECK: 91:9: BinaryOperator= Extent=[91:9 - 91:19]
// CHECK: 91:9: DeclRefExpr=c:2:14 Extent=[91:9 - 91:10]
// CHECK: 91:14: UnexposedExpr= Extent=[91:14 - 91:19]
-// CHECK: 91:14: UnexposedExpr= Extent=[91:14 - 91:19]
-// CHECK: 91:23: UnexposedExpr= Extent=[91:23 - 91:33]
+// CHECK: 91:14: IntegerLiteral= Extent=[91:14 - 91:19]
+// CHECK: 91:23: BinaryOperator= Extent=[91:23 - 91:33]
// CHECK: 91:23: DeclRefExpr=c:2:14 Extent=[91:23 - 91:24]
// CHECK: 91:28: UnexposedExpr= Extent=[91:28 - 91:33]
-// CHECK: 91:28: UnexposedExpr= Extent=[91:28 - 91:33]
-// CHECK: 92:9: UnexposedExpr= Extent=[92:9 - 92:33]
-// CHECK: 92:9: UnexposedExpr= Extent=[92:9 - 92:19]
+// CHECK: 91:28: IntegerLiteral= Extent=[91:28 - 91:33]
+// CHECK: 92:9: BinaryOperator= Extent=[92:9 - 92:33]
+// CHECK: 92:9: BinaryOperator= Extent=[92:9 - 92:19]
// CHECK: 92:9: DeclRefExpr=c:2:14 Extent=[92:9 - 92:10]
// CHECK: 92:14: UnexposedExpr= Extent=[92:14 - 92:19]
-// CHECK: 92:14: UnexposedExpr= Extent=[92:14 - 92:19]
-// CHECK: 92:23: UnexposedExpr= Extent=[92:23 - 92:33]
+// CHECK: 92:14: IntegerLiteral= Extent=[92:14 - 92:19]
+// CHECK: 92:23: BinaryOperator= Extent=[92:23 - 92:33]
// CHECK: 92:23: DeclRefExpr=c:2:14 Extent=[92:23 - 92:24]
// CHECK: 92:28: UnexposedExpr= Extent=[92:28 - 92:33]
-// CHECK: 92:28: UnexposedExpr= Extent=[92:28 - 92:33]
-// CHECK: 93:9: UnexposedExpr= Extent=[93:9 - 93:33]
-// CHECK: 93:9: UnexposedExpr= Extent=[93:9 - 93:19]
+// CHECK: 92:28: IntegerLiteral= Extent=[92:28 - 92:33]
+// CHECK: 93:9: BinaryOperator= Extent=[93:9 - 93:33]
+// CHECK: 93:9: BinaryOperator= Extent=[93:9 - 93:19]
// CHECK: 93:9: DeclRefExpr=c:2:14 Extent=[93:9 - 93:10]
// CHECK: 93:14: UnexposedExpr= Extent=[93:14 - 93:19]
-// CHECK: 93:14: UnexposedExpr= Extent=[93:14 - 93:19]
-// CHECK: 93:23: UnexposedExpr= Extent=[93:23 - 93:33]
+// CHECK: 93:14: IntegerLiteral= Extent=[93:14 - 93:19]
+// CHECK: 93:23: BinaryOperator= Extent=[93:23 - 93:33]
// CHECK: 93:23: DeclRefExpr=c:2:14 Extent=[93:23 - 93:24]
// CHECK: 93:28: UnexposedExpr= Extent=[93:28 - 93:33]
-// CHECK: 93:28: UnexposedExpr= Extent=[93:28 - 93:33]
-// CHECK: 94:9: UnexposedExpr= Extent=[94:9 - 94:33]
-// CHECK: 94:9: UnexposedExpr= Extent=[94:9 - 94:19]
+// CHECK: 93:28: IntegerLiteral= Extent=[93:28 - 93:33]
+// CHECK: 94:9: BinaryOperator= Extent=[94:9 - 94:33]
+// CHECK: 94:9: BinaryOperator= Extent=[94:9 - 94:19]
// CHECK: 94:9: DeclRefExpr=c:2:14 Extent=[94:9 - 94:10]
// CHECK: 94:14: UnexposedExpr= Extent=[94:14 - 94:19]
-// CHECK: 94:14: UnexposedExpr= Extent=[94:14 - 94:19]
-// CHECK: 94:23: UnexposedExpr= Extent=[94:23 - 94:33]
+// CHECK: 94:14: IntegerLiteral= Extent=[94:14 - 94:19]
+// CHECK: 94:23: BinaryOperator= Extent=[94:23 - 94:33]
// CHECK: 94:23: DeclRefExpr=c:2:14 Extent=[94:23 - 94:24]
// CHECK: 94:28: UnexposedExpr= Extent=[94:28 - 94:33]
-// CHECK: 94:28: UnexposedExpr= Extent=[94:28 - 94:33]
-// CHECK: 95:9: UnexposedExpr= Extent=[95:9 - 95:33]
-// CHECK: 95:9: UnexposedExpr= Extent=[95:9 - 95:19]
+// CHECK: 94:28: IntegerLiteral= Extent=[94:28 - 94:33]
+// CHECK: 95:9: BinaryOperator= Extent=[95:9 - 95:33]
+// CHECK: 95:9: BinaryOperator= Extent=[95:9 - 95:19]
// CHECK: 95:9: DeclRefExpr=c:2:14 Extent=[95:9 - 95:10]
// CHECK: 95:14: UnexposedExpr= Extent=[95:14 - 95:19]
-// CHECK: 95:14: UnexposedExpr= Extent=[95:14 - 95:19]
-// CHECK: 95:23: UnexposedExpr= Extent=[95:23 - 95:33]
+// CHECK: 95:14: IntegerLiteral= Extent=[95:14 - 95:19]
+// CHECK: 95:23: BinaryOperator= Extent=[95:23 - 95:33]
// CHECK: 95:23: DeclRefExpr=c:2:14 Extent=[95:23 - 95:24]
// CHECK: 95:28: UnexposedExpr= Extent=[95:28 - 95:33]
-// CHECK: 95:28: UnexposedExpr= Extent=[95:28 - 95:33]
-// CHECK: 96:9: UnexposedExpr= Extent=[96:9 - 96:33]
-// CHECK: 96:9: UnexposedExpr= Extent=[96:9 - 96:19]
+// CHECK: 95:28: IntegerLiteral= Extent=[95:28 - 95:33]
+// CHECK: 96:9: BinaryOperator= Extent=[96:9 - 96:33]
+// CHECK: 96:9: BinaryOperator= Extent=[96:9 - 96:19]
// CHECK: 96:9: DeclRefExpr=c:2:14 Extent=[96:9 - 96:10]
// CHECK: 96:14: UnexposedExpr= Extent=[96:14 - 96:19]
-// CHECK: 96:14: UnexposedExpr= Extent=[96:14 - 96:19]
-// CHECK: 96:23: UnexposedExpr= Extent=[96:23 - 96:33]
+// CHECK: 96:14: IntegerLiteral= Extent=[96:14 - 96:19]
+// CHECK: 96:23: BinaryOperator= Extent=[96:23 - 96:33]
// CHECK: 96:23: DeclRefExpr=c:2:14 Extent=[96:23 - 96:24]
// CHECK: 96:28: UnexposedExpr= Extent=[96:28 - 96:33]
-// CHECK: 96:28: UnexposedExpr= Extent=[96:28 - 96:33]
-// CHECK: 97:9: UnexposedExpr= Extent=[97:9 - 97:33]
-// CHECK: 97:9: UnexposedExpr= Extent=[97:9 - 97:19]
+// CHECK: 96:28: IntegerLiteral= Extent=[96:28 - 96:33]
+// CHECK: 97:9: BinaryOperator= Extent=[97:9 - 97:33]
+// CHECK: 97:9: BinaryOperator= Extent=[97:9 - 97:19]
// CHECK: 97:9: DeclRefExpr=c:2:14 Extent=[97:9 - 97:10]
// CHECK: 97:14: UnexposedExpr= Extent=[97:14 - 97:19]
-// CHECK: 97:14: UnexposedExpr= Extent=[97:14 - 97:19]
-// CHECK: 97:23: UnexposedExpr= Extent=[97:23 - 97:33]
+// CHECK: 97:14: IntegerLiteral= Extent=[97:14 - 97:19]
+// CHECK: 97:23: BinaryOperator= Extent=[97:23 - 97:33]
// CHECK: 97:23: DeclRefExpr=c:2:14 Extent=[97:23 - 97:24]
// CHECK: 97:28: UnexposedExpr= Extent=[97:28 - 97:33]
-// CHECK: 97:28: UnexposedExpr= Extent=[97:28 - 97:33]
-// CHECK: 98:8: UnexposedExpr= Extent=[98:8 - 98:18]
+// CHECK: 97:28: IntegerLiteral= Extent=[97:28 - 97:33]
+// CHECK: 98:8: BinaryOperator= Extent=[98:8 - 98:18]
// CHECK: 98:8: DeclRefExpr=c:2:14 Extent=[98:8 - 98:9]
// CHECK: 98:13: UnexposedExpr= Extent=[98:13 - 98:18]
-// CHECK: 98:13: UnexposedExpr= Extent=[98:13 - 98:18]
-// CHECK: 98:23: UnexposedExpr= Extent=[98:23 - 98:47]
-// CHECK: 98:23: UnexposedExpr= Extent=[98:23 - 98:33]
+// CHECK: 98:13: IntegerLiteral= Extent=[98:13 - 98:18]
+// CHECK: 98:23: BinaryOperator= Extent=[98:23 - 98:47]
+// CHECK: 98:23: BinaryOperator= Extent=[98:23 - 98:33]
// CHECK: 98:23: DeclRefExpr=c:2:14 Extent=[98:23 - 98:24]
// CHECK: 98:28: UnexposedExpr= Extent=[98:28 - 98:33]
-// CHECK: 98:28: UnexposedExpr= Extent=[98:28 - 98:33]
-// CHECK: 98:37: UnexposedExpr= Extent=[98:37 - 98:47]
+// CHECK: 98:28: IntegerLiteral= Extent=[98:28 - 98:33]
+// CHECK: 98:37: BinaryOperator= Extent=[98:37 - 98:47]
// CHECK: 98:37: DeclRefExpr=c:2:14 Extent=[98:37 - 98:38]
// CHECK: 98:42: UnexposedExpr= Extent=[98:42 - 98:47]
-// CHECK: 98:42: UnexposedExpr= Extent=[98:42 - 98:47]
-// CHECK: 99:9: UnexposedExpr= Extent=[99:9 - 99:33]
-// CHECK: 99:9: UnexposedExpr= Extent=[99:9 - 99:19]
+// CHECK: 98:42: IntegerLiteral= Extent=[98:42 - 98:47]
+// CHECK: 99:9: BinaryOperator= Extent=[99:9 - 99:33]
+// CHECK: 99:9: BinaryOperator= Extent=[99:9 - 99:19]
// CHECK: 99:9: DeclRefExpr=c:2:14 Extent=[99:9 - 99:10]
// CHECK: 99:14: UnexposedExpr= Extent=[99:14 - 99:19]
-// CHECK: 99:14: UnexposedExpr= Extent=[99:14 - 99:19]
-// CHECK: 99:23: UnexposedExpr= Extent=[99:23 - 99:33]
+// CHECK: 99:14: IntegerLiteral= Extent=[99:14 - 99:19]
+// CHECK: 99:23: BinaryOperator= Extent=[99:23 - 99:33]
// CHECK: 99:23: DeclRefExpr=c:2:14 Extent=[99:23 - 99:24]
// CHECK: 99:28: UnexposedExpr= Extent=[99:28 - 99:33]
-// CHECK: 99:28: UnexposedExpr= Extent=[99:28 - 99:33]
-// CHECK: 100:9: UnexposedExpr= Extent=[100:9 - 100:33]
-// CHECK: 100:9: UnexposedExpr= Extent=[100:9 - 100:19]
+// CHECK: 99:28: IntegerLiteral= Extent=[99:28 - 99:33]
+// CHECK: 100:9: BinaryOperator= Extent=[100:9 - 100:33]
+// CHECK: 100:9: BinaryOperator= Extent=[100:9 - 100:19]
// CHECK: 100:9: DeclRefExpr=c:2:14 Extent=[100:9 - 100:10]
// CHECK: 100:14: UnexposedExpr= Extent=[100:14 - 100:19]
-// CHECK: 100:14: UnexposedExpr= Extent=[100:14 - 100:19]
-// CHECK: 100:23: UnexposedExpr= Extent=[100:23 - 100:33]
+// CHECK: 100:14: IntegerLiteral= Extent=[100:14 - 100:19]
+// CHECK: 100:23: BinaryOperator= Extent=[100:23 - 100:33]
// CHECK: 100:23: DeclRefExpr=c:2:14 Extent=[100:23 - 100:24]
// CHECK: 100:28: UnexposedExpr= Extent=[100:28 - 100:33]
-// CHECK: 100:28: UnexposedExpr= Extent=[100:28 - 100:33]
-// CHECK: 101:9: UnexposedExpr= Extent=[101:9 - 101:33]
-// CHECK: 101:9: UnexposedExpr= Extent=[101:9 - 101:19]
+// CHECK: 100:28: IntegerLiteral= Extent=[100:28 - 100:33]
+// CHECK: 101:9: BinaryOperator= Extent=[101:9 - 101:33]
+// CHECK: 101:9: BinaryOperator= Extent=[101:9 - 101:19]
// CHECK: 101:9: DeclRefExpr=c:2:14 Extent=[101:9 - 101:10]
// CHECK: 101:14: UnexposedExpr= Extent=[101:14 - 101:19]
-// CHECK: 101:14: UnexposedExpr= Extent=[101:14 - 101:19]
-// CHECK: 101:23: UnexposedExpr= Extent=[101:23 - 101:33]
+// CHECK: 101:14: IntegerLiteral= Extent=[101:14 - 101:19]
+// CHECK: 101:23: BinaryOperator= Extent=[101:23 - 101:33]
// CHECK: 101:23: DeclRefExpr=c:2:14 Extent=[101:23 - 101:24]
// CHECK: 101:28: UnexposedExpr= Extent=[101:28 - 101:33]
-// CHECK: 101:28: UnexposedExpr= Extent=[101:28 - 101:33]
-// CHECK: 102:9: UnexposedExpr= Extent=[102:9 - 102:33]
-// CHECK: 102:9: UnexposedExpr= Extent=[102:9 - 102:19]
+// CHECK: 101:28: IntegerLiteral= Extent=[101:28 - 101:33]
+// CHECK: 102:9: BinaryOperator= Extent=[102:9 - 102:33]
+// CHECK: 102:9: BinaryOperator= Extent=[102:9 - 102:19]
// CHECK: 102:9: DeclRefExpr=c:2:14 Extent=[102:9 - 102:10]
// CHECK: 102:14: UnexposedExpr= Extent=[102:14 - 102:19]
-// CHECK: 102:14: UnexposedExpr= Extent=[102:14 - 102:19]
-// CHECK: 102:23: UnexposedExpr= Extent=[102:23 - 102:33]
+// CHECK: 102:14: IntegerLiteral= Extent=[102:14 - 102:19]
+// CHECK: 102:23: BinaryOperator= Extent=[102:23 - 102:33]
// CHECK: 102:23: DeclRefExpr=c:2:14 Extent=[102:23 - 102:24]
// CHECK: 102:28: UnexposedExpr= Extent=[102:28 - 102:33]
-// CHECK: 102:28: UnexposedExpr= Extent=[102:28 - 102:33]
-// CHECK: 103:9: UnexposedExpr= Extent=[103:9 - 103:33]
-// CHECK: 103:9: UnexposedExpr= Extent=[103:9 - 103:19]
+// CHECK: 102:28: IntegerLiteral= Extent=[102:28 - 102:33]
+// CHECK: 103:9: BinaryOperator= Extent=[103:9 - 103:33]
+// CHECK: 103:9: BinaryOperator= Extent=[103:9 - 103:19]
// CHECK: 103:9: DeclRefExpr=c:2:14 Extent=[103:9 - 103:10]
// CHECK: 103:14: UnexposedExpr= Extent=[103:14 - 103:19]
-// CHECK: 103:14: UnexposedExpr= Extent=[103:14 - 103:19]
-// CHECK: 103:23: UnexposedExpr= Extent=[103:23 - 103:33]
+// CHECK: 103:14: IntegerLiteral= Extent=[103:14 - 103:19]
+// CHECK: 103:23: BinaryOperator= Extent=[103:23 - 103:33]
// CHECK: 103:23: DeclRefExpr=c:2:14 Extent=[103:23 - 103:24]
// CHECK: 103:28: UnexposedExpr= Extent=[103:28 - 103:33]
-// CHECK: 103:28: UnexposedExpr= Extent=[103:28 - 103:33]
-// CHECK: 104:9: UnexposedExpr= Extent=[104:9 - 104:33]
-// CHECK: 104:9: UnexposedExpr= Extent=[104:9 - 104:19]
+// CHECK: 103:28: IntegerLiteral= Extent=[103:28 - 103:33]
+// CHECK: 104:9: BinaryOperator= Extent=[104:9 - 104:33]
+// CHECK: 104:9: BinaryOperator= Extent=[104:9 - 104:19]
// CHECK: 104:9: DeclRefExpr=c:2:14 Extent=[104:9 - 104:10]
// CHECK: 104:14: UnexposedExpr= Extent=[104:14 - 104:19]
-// CHECK: 104:14: UnexposedExpr= Extent=[104:14 - 104:19]
-// CHECK: 104:23: UnexposedExpr= Extent=[104:23 - 104:33]
+// CHECK: 104:14: IntegerLiteral= Extent=[104:14 - 104:19]
+// CHECK: 104:23: BinaryOperator= Extent=[104:23 - 104:33]
// CHECK: 104:23: DeclRefExpr=c:2:14 Extent=[104:23 - 104:24]
// CHECK: 104:28: UnexposedExpr= Extent=[104:28 - 104:33]
-// CHECK: 104:28: UnexposedExpr= Extent=[104:28 - 104:33]
-// CHECK: 105:8: UnexposedExpr= Extent=[105:8 - 105:18]
+// CHECK: 104:28: IntegerLiteral= Extent=[104:28 - 104:33]
+// CHECK: 105:8: BinaryOperator= Extent=[105:8 - 105:18]
// CHECK: 105:8: DeclRefExpr=c:2:14 Extent=[105:8 - 105:9]
// CHECK: 105:13: UnexposedExpr= Extent=[105:13 - 105:18]
-// CHECK: 105:13: UnexposedExpr= Extent=[105:13 - 105:18]
-// CHECK: 105:23: UnexposedExpr= Extent=[105:23 - 105:47]
-// CHECK: 105:23: UnexposedExpr= Extent=[105:23 - 105:33]
+// CHECK: 105:13: IntegerLiteral= Extent=[105:13 - 105:18]
+// CHECK: 105:23: BinaryOperator= Extent=[105:23 - 105:47]
+// CHECK: 105:23: BinaryOperator= Extent=[105:23 - 105:33]
// CHECK: 105:23: DeclRefExpr=c:2:14 Extent=[105:23 - 105:24]
// CHECK: 105:28: UnexposedExpr= Extent=[105:28 - 105:33]
-// CHECK: 105:28: UnexposedExpr= Extent=[105:28 - 105:33]
-// CHECK: 105:37: UnexposedExpr= Extent=[105:37 - 105:47]
+// CHECK: 105:28: IntegerLiteral= Extent=[105:28 - 105:33]
+// CHECK: 105:37: BinaryOperator= Extent=[105:37 - 105:47]
// CHECK: 105:37: DeclRefExpr=c:2:14 Extent=[105:37 - 105:38]
// CHECK: 105:42: UnexposedExpr= Extent=[105:42 - 105:47]
-// CHECK: 105:42: UnexposedExpr= Extent=[105:42 - 105:47]
-// CHECK: 106:9: UnexposedExpr= Extent=[106:9 - 106:33]
-// CHECK: 106:9: UnexposedExpr= Extent=[106:9 - 106:19]
+// CHECK: 105:42: IntegerLiteral= Extent=[105:42 - 105:47]
+// CHECK: 106:9: BinaryOperator= Extent=[106:9 - 106:33]
+// CHECK: 106:9: BinaryOperator= Extent=[106:9 - 106:19]
// CHECK: 106:9: DeclRefExpr=c:2:14 Extent=[106:9 - 106:10]
// CHECK: 106:14: UnexposedExpr= Extent=[106:14 - 106:19]
-// CHECK: 106:14: UnexposedExpr= Extent=[106:14 - 106:19]
-// CHECK: 106:23: UnexposedExpr= Extent=[106:23 - 106:33]
+// CHECK: 106:14: IntegerLiteral= Extent=[106:14 - 106:19]
+// CHECK: 106:23: BinaryOperator= Extent=[106:23 - 106:33]
// CHECK: 106:23: DeclRefExpr=c:2:14 Extent=[106:23 - 106:24]
// CHECK: 106:28: UnexposedExpr= Extent=[106:28 - 106:33]
-// CHECK: 106:28: UnexposedExpr= Extent=[106:28 - 106:33]
-// CHECK: 107:9: UnexposedExpr= Extent=[107:9 - 107:33]
-// CHECK: 107:9: UnexposedExpr= Extent=[107:9 - 107:19]
+// CHECK: 106:28: IntegerLiteral= Extent=[106:28 - 106:33]
+// CHECK: 107:9: BinaryOperator= Extent=[107:9 - 107:33]
+// CHECK: 107:9: BinaryOperator= Extent=[107:9 - 107:19]
// CHECK: 107:9: DeclRefExpr=c:2:14 Extent=[107:9 - 107:10]
// CHECK: 107:14: UnexposedExpr= Extent=[107:14 - 107:19]
-// CHECK: 107:14: UnexposedExpr= Extent=[107:14 - 107:19]
-// CHECK: 107:23: UnexposedExpr= Extent=[107:23 - 107:33]
+// CHECK: 107:14: IntegerLiteral= Extent=[107:14 - 107:19]
+// CHECK: 107:23: BinaryOperator= Extent=[107:23 - 107:33]
// CHECK: 107:23: DeclRefExpr=c:2:14 Extent=[107:23 - 107:24]
// CHECK: 107:28: UnexposedExpr= Extent=[107:28 - 107:33]
-// CHECK: 107:28: UnexposedExpr= Extent=[107:28 - 107:33]
-// CHECK: 108:8: UnexposedExpr= Extent=[108:8 - 108:18]
+// CHECK: 107:28: IntegerLiteral= Extent=[107:28 - 107:33]
+// CHECK: 108:8: BinaryOperator= Extent=[108:8 - 108:18]
// CHECK: 108:8: DeclRefExpr=c:2:14 Extent=[108:8 - 108:9]
// CHECK: 108:13: UnexposedExpr= Extent=[108:13 - 108:18]
-// CHECK: 108:13: UnexposedExpr= Extent=[108:13 - 108:18]
-// CHECK: 108:23: UnexposedExpr= Extent=[108:23 - 108:47]
-// CHECK: 108:23: UnexposedExpr= Extent=[108:23 - 108:33]
+// CHECK: 108:13: IntegerLiteral= Extent=[108:13 - 108:18]
+// CHECK: 108:23: BinaryOperator= Extent=[108:23 - 108:47]
+// CHECK: 108:23: BinaryOperator= Extent=[108:23 - 108:33]
// CHECK: 108:23: DeclRefExpr=c:2:14 Extent=[108:23 - 108:24]
// CHECK: 108:28: UnexposedExpr= Extent=[108:28 - 108:33]
-// CHECK: 108:28: UnexposedExpr= Extent=[108:28 - 108:33]
-// CHECK: 108:37: UnexposedExpr= Extent=[108:37 - 108:47]
+// CHECK: 108:28: IntegerLiteral= Extent=[108:28 - 108:33]
+// CHECK: 108:37: BinaryOperator= Extent=[108:37 - 108:47]
// CHECK: 108:37: DeclRefExpr=c:2:14 Extent=[108:37 - 108:38]
// CHECK: 108:42: UnexposedExpr= Extent=[108:42 - 108:47]
-// CHECK: 108:42: UnexposedExpr= Extent=[108:42 - 108:47]
-// CHECK: 109:8: UnexposedExpr= Extent=[109:8 - 109:18]
+// CHECK: 108:42: IntegerLiteral= Extent=[108:42 - 108:47]
+// CHECK: 109:8: BinaryOperator= Extent=[109:8 - 109:18]
// CHECK: 109:8: DeclRefExpr=c:2:14 Extent=[109:8 - 109:9]
// CHECK: 109:13: UnexposedExpr= Extent=[109:13 - 109:18]
-// CHECK: 109:13: UnexposedExpr= Extent=[109:13 - 109:18]
-// CHECK: 109:22: UnexposedExpr= Extent=[109:22 - 109:32]
+// CHECK: 109:13: IntegerLiteral= Extent=[109:13 - 109:18]
+// CHECK: 109:22: BinaryOperator= Extent=[109:22 - 109:32]
// CHECK: 109:22: DeclRefExpr=c:2:14 Extent=[109:22 - 109:23]
// CHECK: 109:27: UnexposedExpr= Extent=[109:27 - 109:32]
-// CHECK: 109:27: UnexposedExpr= Extent=[109:27 - 109:32]
-// CHECK: 109:37: UnexposedExpr= Extent=[109:37 - 109:61]
-// CHECK: 109:37: UnexposedExpr= Extent=[109:37 - 109:47]
+// CHECK: 109:27: IntegerLiteral= Extent=[109:27 - 109:32]
+// CHECK: 109:37: BinaryOperator= Extent=[109:37 - 109:61]
+// CHECK: 109:37: BinaryOperator= Extent=[109:37 - 109:47]
// CHECK: 109:37: DeclRefExpr=c:2:14 Extent=[109:37 - 109:38]
// CHECK: 109:42: UnexposedExpr= Extent=[109:42 - 109:47]
-// CHECK: 109:42: UnexposedExpr= Extent=[109:42 - 109:47]
-// CHECK: 109:51: UnexposedExpr= Extent=[109:51 - 109:61]
+// CHECK: 109:42: IntegerLiteral= Extent=[109:42 - 109:47]
+// CHECK: 109:51: BinaryOperator= Extent=[109:51 - 109:61]
// CHECK: 109:51: DeclRefExpr=c:2:14 Extent=[109:51 - 109:52]
// CHECK: 109:56: UnexposedExpr= Extent=[109:56 - 109:61]
-// CHECK: 109:56: UnexposedExpr= Extent=[109:56 - 109:61]
-// CHECK: 110:9: UnexposedExpr= Extent=[110:9 - 110:33]
-// CHECK: 110:9: UnexposedExpr= Extent=[110:9 - 110:19]
+// CHECK: 109:56: IntegerLiteral= Extent=[109:56 - 109:61]
+// CHECK: 110:9: BinaryOperator= Extent=[110:9 - 110:33]
+// CHECK: 110:9: BinaryOperator= Extent=[110:9 - 110:19]
// CHECK: 110:9: DeclRefExpr=c:2:14 Extent=[110:9 - 110:10]
// CHECK: 110:14: UnexposedExpr= Extent=[110:14 - 110:19]
-// CHECK: 110:14: UnexposedExpr= Extent=[110:14 - 110:19]
-// CHECK: 110:23: UnexposedExpr= Extent=[110:23 - 110:33]
+// CHECK: 110:14: IntegerLiteral= Extent=[110:14 - 110:19]
+// CHECK: 110:23: BinaryOperator= Extent=[110:23 - 110:33]
// CHECK: 110:23: DeclRefExpr=c:2:14 Extent=[110:23 - 110:24]
// CHECK: 110:28: UnexposedExpr= Extent=[110:28 - 110:33]
-// CHECK: 110:28: UnexposedExpr= Extent=[110:28 - 110:33]
-// CHECK: 111:9: UnexposedExpr= Extent=[111:9 - 111:33]
-// CHECK: 111:9: UnexposedExpr= Extent=[111:9 - 111:19]
+// CHECK: 110:28: IntegerLiteral= Extent=[110:28 - 110:33]
+// CHECK: 111:9: BinaryOperator= Extent=[111:9 - 111:33]
+// CHECK: 111:9: BinaryOperator= Extent=[111:9 - 111:19]
// CHECK: 111:9: DeclRefExpr=c:2:14 Extent=[111:9 - 111:10]
// CHECK: 111:14: UnexposedExpr= Extent=[111:14 - 111:19]
-// CHECK: 111:14: UnexposedExpr= Extent=[111:14 - 111:19]
-// CHECK: 111:23: UnexposedExpr= Extent=[111:23 - 111:33]
+// CHECK: 111:14: IntegerLiteral= Extent=[111:14 - 111:19]
+// CHECK: 111:23: BinaryOperator= Extent=[111:23 - 111:33]
// CHECK: 111:23: DeclRefExpr=c:2:14 Extent=[111:23 - 111:24]
// CHECK: 111:28: UnexposedExpr= Extent=[111:28 - 111:33]
-// CHECK: 111:28: UnexposedExpr= Extent=[111:28 - 111:33]
-// CHECK: 112:8: UnexposedExpr= Extent=[112:8 - 112:18]
+// CHECK: 111:28: IntegerLiteral= Extent=[111:28 - 111:33]
+// CHECK: 112:8: BinaryOperator= Extent=[112:8 - 112:18]
// CHECK: 112:8: DeclRefExpr=c:2:14 Extent=[112:8 - 112:9]
// CHECK: 112:13: UnexposedExpr= Extent=[112:13 - 112:18]
-// CHECK: 112:13: UnexposedExpr= Extent=[112:13 - 112:18]
-// CHECK: 112:22: UnexposedExpr= Extent=[112:22 - 112:32]
+// CHECK: 112:13: IntegerLiteral= Extent=[112:13 - 112:18]
+// CHECK: 112:22: BinaryOperator= Extent=[112:22 - 112:32]
// CHECK: 112:22: DeclRefExpr=c:2:14 Extent=[112:22 - 112:23]
// CHECK: 112:27: UnexposedExpr= Extent=[112:27 - 112:32]
-// CHECK: 112:27: UnexposedExpr= Extent=[112:27 - 112:32]
-// CHECK: 112:37: UnexposedExpr= Extent=[112:37 - 112:61]
-// CHECK: 112:37: UnexposedExpr= Extent=[112:37 - 112:47]
+// CHECK: 112:27: IntegerLiteral= Extent=[112:27 - 112:32]
+// CHECK: 112:37: BinaryOperator= Extent=[112:37 - 112:61]
+// CHECK: 112:37: BinaryOperator= Extent=[112:37 - 112:47]
// CHECK: 112:37: DeclRefExpr=c:2:14 Extent=[112:37 - 112:38]
// CHECK: 112:42: UnexposedExpr= Extent=[112:42 - 112:47]
-// CHECK: 112:42: UnexposedExpr= Extent=[112:42 - 112:47]
-// CHECK: 112:51: UnexposedExpr= Extent=[112:51 - 112:61]
+// CHECK: 112:42: IntegerLiteral= Extent=[112:42 - 112:47]
+// CHECK: 112:51: BinaryOperator= Extent=[112:51 - 112:61]
// CHECK: 112:51: DeclRefExpr=c:2:14 Extent=[112:51 - 112:52]
// CHECK: 112:56: UnexposedExpr= Extent=[112:56 - 112:61]
-// CHECK: 112:56: UnexposedExpr= Extent=[112:56 - 112:61]
-// CHECK: 113:9: UnexposedExpr= Extent=[113:9 - 113:33]
-// CHECK: 113:9: UnexposedExpr= Extent=[113:9 - 113:19]
+// CHECK: 112:56: IntegerLiteral= Extent=[112:56 - 112:61]
+// CHECK: 113:9: BinaryOperator= Extent=[113:9 - 113:33]
+// CHECK: 113:9: BinaryOperator= Extent=[113:9 - 113:19]
// CHECK: 113:9: DeclRefExpr=c:2:14 Extent=[113:9 - 113:10]
// CHECK: 113:14: UnexposedExpr= Extent=[113:14 - 113:19]
-// CHECK: 113:14: UnexposedExpr= Extent=[113:14 - 113:19]
-// CHECK: 113:23: UnexposedExpr= Extent=[113:23 - 113:33]
+// CHECK: 113:14: IntegerLiteral= Extent=[113:14 - 113:19]
+// CHECK: 113:23: BinaryOperator= Extent=[113:23 - 113:33]
// CHECK: 113:23: DeclRefExpr=c:2:14 Extent=[113:23 - 113:24]
// CHECK: 113:28: UnexposedExpr= Extent=[113:28 - 113:33]
-// CHECK: 113:28: UnexposedExpr= Extent=[113:28 - 113:33]
-// CHECK: 114:8: UnexposedExpr= Extent=[114:8 - 114:18]
+// CHECK: 113:28: IntegerLiteral= Extent=[113:28 - 113:33]
+// CHECK: 114:8: BinaryOperator= Extent=[114:8 - 114:18]
// CHECK: 114:8: DeclRefExpr=c:2:14 Extent=[114:8 - 114:9]
// CHECK: 114:13: UnexposedExpr= Extent=[114:13 - 114:18]
-// CHECK: 114:13: UnexposedExpr= Extent=[114:13 - 114:18]
-// CHECK: 114:23: UnexposedExpr= Extent=[114:23 - 114:47]
-// CHECK: 114:23: UnexposedExpr= Extent=[114:23 - 114:33]
+// CHECK: 114:13: IntegerLiteral= Extent=[114:13 - 114:18]
+// CHECK: 114:23: BinaryOperator= Extent=[114:23 - 114:47]
+// CHECK: 114:23: BinaryOperator= Extent=[114:23 - 114:33]
// CHECK: 114:23: DeclRefExpr=c:2:14 Extent=[114:23 - 114:24]
// CHECK: 114:28: UnexposedExpr= Extent=[114:28 - 114:33]
-// CHECK: 114:28: UnexposedExpr= Extent=[114:28 - 114:33]
-// CHECK: 114:37: UnexposedExpr= Extent=[114:37 - 114:47]
+// CHECK: 114:28: IntegerLiteral= Extent=[114:28 - 114:33]
+// CHECK: 114:37: BinaryOperator= Extent=[114:37 - 114:47]
// CHECK: 114:37: DeclRefExpr=c:2:14 Extent=[114:37 - 114:38]
// CHECK: 114:42: UnexposedExpr= Extent=[114:42 - 114:47]
-// CHECK: 114:42: UnexposedExpr= Extent=[114:42 - 114:47]
-// CHECK: 115:8: UnexposedExpr= Extent=[115:8 - 115:18]
+// CHECK: 114:42: IntegerLiteral= Extent=[114:42 - 114:47]
+// CHECK: 115:8: BinaryOperator= Extent=[115:8 - 115:18]
// CHECK: 115:8: DeclRefExpr=c:2:14 Extent=[115:8 - 115:9]
// CHECK: 115:13: UnexposedExpr= Extent=[115:13 - 115:18]
-// CHECK: 115:13: UnexposedExpr= Extent=[115:13 - 115:18]
-// CHECK: 115:23: UnexposedExpr= Extent=[115:23 - 115:47]
-// CHECK: 115:23: UnexposedExpr= Extent=[115:23 - 115:33]
+// CHECK: 115:13: IntegerLiteral= Extent=[115:13 - 115:18]
+// CHECK: 115:23: BinaryOperator= Extent=[115:23 - 115:47]
+// CHECK: 115:23: BinaryOperator= Extent=[115:23 - 115:33]
// CHECK: 115:23: DeclRefExpr=c:2:14 Extent=[115:23 - 115:24]
// CHECK: 115:28: UnexposedExpr= Extent=[115:28 - 115:33]
-// CHECK: 115:28: UnexposedExpr= Extent=[115:28 - 115:33]
-// CHECK: 115:37: UnexposedExpr= Extent=[115:37 - 115:47]
+// CHECK: 115:28: IntegerLiteral= Extent=[115:28 - 115:33]
+// CHECK: 115:37: BinaryOperator= Extent=[115:37 - 115:47]
// CHECK: 115:37: DeclRefExpr=c:2:14 Extent=[115:37 - 115:38]
// CHECK: 115:42: UnexposedExpr= Extent=[115:42 - 115:47]
-// CHECK: 115:42: UnexposedExpr= Extent=[115:42 - 115:47]
-// CHECK: 116:9: UnexposedExpr= Extent=[116:9 - 116:33]
-// CHECK: 116:9: UnexposedExpr= Extent=[116:9 - 116:19]
+// CHECK: 115:42: IntegerLiteral= Extent=[115:42 - 115:47]
+// CHECK: 116:9: BinaryOperator= Extent=[116:9 - 116:33]
+// CHECK: 116:9: BinaryOperator= Extent=[116:9 - 116:19]
// CHECK: 116:9: DeclRefExpr=c:2:14 Extent=[116:9 - 116:10]
// CHECK: 116:14: UnexposedExpr= Extent=[116:14 - 116:19]
-// CHECK: 116:14: UnexposedExpr= Extent=[116:14 - 116:19]
-// CHECK: 116:23: UnexposedExpr= Extent=[116:23 - 116:33]
+// CHECK: 116:14: IntegerLiteral= Extent=[116:14 - 116:19]
+// CHECK: 116:23: BinaryOperator= Extent=[116:23 - 116:33]
// CHECK: 116:23: DeclRefExpr=c:2:14 Extent=[116:23 - 116:24]
// CHECK: 116:28: UnexposedExpr= Extent=[116:28 - 116:33]
-// CHECK: 116:28: UnexposedExpr= Extent=[116:28 - 116:33]
-// CHECK: 117:9: UnexposedExpr= Extent=[117:9 - 117:33]
-// CHECK: 117:9: UnexposedExpr= Extent=[117:9 - 117:19]
+// CHECK: 116:28: IntegerLiteral= Extent=[116:28 - 116:33]
+// CHECK: 117:9: BinaryOperator= Extent=[117:9 - 117:33]
+// CHECK: 117:9: BinaryOperator= Extent=[117:9 - 117:19]
// CHECK: 117:9: DeclRefExpr=c:2:14 Extent=[117:9 - 117:10]
// CHECK: 117:14: UnexposedExpr= Extent=[117:14 - 117:19]
-// CHECK: 117:14: UnexposedExpr= Extent=[117:14 - 117:19]
-// CHECK: 117:23: UnexposedExpr= Extent=[117:23 - 117:33]
+// CHECK: 117:14: IntegerLiteral= Extent=[117:14 - 117:19]
+// CHECK: 117:23: BinaryOperator= Extent=[117:23 - 117:33]
// CHECK: 117:23: DeclRefExpr=c:2:14 Extent=[117:23 - 117:24]
// CHECK: 117:28: UnexposedExpr= Extent=[117:28 - 117:33]
-// CHECK: 117:28: UnexposedExpr= Extent=[117:28 - 117:33]
-// CHECK: 118:9: UnexposedExpr= Extent=[118:9 - 118:35]
-// CHECK: 118:9: UnexposedExpr= Extent=[118:9 - 118:20]
+// CHECK: 117:28: IntegerLiteral= Extent=[117:28 - 117:33]
+// CHECK: 118:9: BinaryOperator= Extent=[118:9 - 118:35]
+// CHECK: 118:9: BinaryOperator= Extent=[118:9 - 118:20]
// CHECK: 118:9: DeclRefExpr=c:2:14 Extent=[118:9 - 118:10]
// CHECK: 118:14: UnexposedExpr= Extent=[118:14 - 118:20]
-// CHECK: 118:14: UnexposedExpr= Extent=[118:14 - 118:20]
-// CHECK: 118:24: UnexposedExpr= Extent=[118:24 - 118:35]
+// CHECK: 118:14: IntegerLiteral= Extent=[118:14 - 118:20]
+// CHECK: 118:24: BinaryOperator= Extent=[118:24 - 118:35]
// CHECK: 118:24: DeclRefExpr=c:2:14 Extent=[118:24 - 118:25]
// CHECK: 118:29: UnexposedExpr= Extent=[118:29 - 118:35]
-// CHECK: 118:29: UnexposedExpr= Extent=[118:29 - 118:35]
-// CHECK: 119:9: UnexposedExpr= Extent=[119:9 - 119:35]
-// CHECK: 119:9: UnexposedExpr= Extent=[119:9 - 119:20]
+// CHECK: 118:29: IntegerLiteral= Extent=[118:29 - 118:35]
+// CHECK: 119:9: BinaryOperator= Extent=[119:9 - 119:35]
+// CHECK: 119:9: BinaryOperator= Extent=[119:9 - 119:20]
// CHECK: 119:9: DeclRefExpr=c:2:14 Extent=[119:9 - 119:10]
// CHECK: 119:14: UnexposedExpr= Extent=[119:14 - 119:20]
-// CHECK: 119:14: UnexposedExpr= Extent=[119:14 - 119:20]
-// CHECK: 119:24: UnexposedExpr= Extent=[119:24 - 119:35]
+// CHECK: 119:14: IntegerLiteral= Extent=[119:14 - 119:20]
+// CHECK: 119:24: BinaryOperator= Extent=[119:24 - 119:35]
// CHECK: 119:24: DeclRefExpr=c:2:14 Extent=[119:24 - 119:25]
// CHECK: 119:29: UnexposedExpr= Extent=[119:29 - 119:35]
-// CHECK: 119:29: UnexposedExpr= Extent=[119:29 - 119:35]
-// CHECK: 120:8: UnexposedExpr= Extent=[120:8 - 120:19]
+// CHECK: 119:29: IntegerLiteral= Extent=[119:29 - 119:35]
+// CHECK: 120:8: BinaryOperator= Extent=[120:8 - 120:19]
// CHECK: 120:8: DeclRefExpr=c:2:14 Extent=[120:8 - 120:9]
// CHECK: 120:13: UnexposedExpr= Extent=[120:13 - 120:19]
-// CHECK: 120:13: UnexposedExpr= Extent=[120:13 - 120:19]
-// CHECK: 120:24: UnexposedExpr= Extent=[120:24 - 120:50]
-// CHECK: 120:24: UnexposedExpr= Extent=[120:24 - 120:35]
+// CHECK: 120:13: IntegerLiteral= Extent=[120:13 - 120:19]
+// CHECK: 120:24: BinaryOperator= Extent=[120:24 - 120:50]
+// CHECK: 120:24: BinaryOperator= Extent=[120:24 - 120:35]
// CHECK: 120:24: DeclRefExpr=c:2:14 Extent=[120:24 - 120:25]
// CHECK: 120:29: UnexposedExpr= Extent=[120:29 - 120:35]
-// CHECK: 120:29: UnexposedExpr= Extent=[120:29 - 120:35]
-// CHECK: 120:39: UnexposedExpr= Extent=[120:39 - 120:50]
+// CHECK: 120:29: IntegerLiteral= Extent=[120:29 - 120:35]
+// CHECK: 120:39: BinaryOperator= Extent=[120:39 - 120:50]
// CHECK: 120:39: DeclRefExpr=c:2:14 Extent=[120:39 - 120:40]
// CHECK: 120:44: UnexposedExpr= Extent=[120:44 - 120:50]
-// CHECK: 120:44: UnexposedExpr= Extent=[120:44 - 120:50]
-// CHECK: 121:9: UnexposedExpr= Extent=[121:9 - 121:35]
-// CHECK: 121:9: UnexposedExpr= Extent=[121:9 - 121:20]
+// CHECK: 120:44: IntegerLiteral= Extent=[120:44 - 120:50]
+// CHECK: 121:9: BinaryOperator= Extent=[121:9 - 121:35]
+// CHECK: 121:9: BinaryOperator= Extent=[121:9 - 121:20]
// CHECK: 121:9: DeclRefExpr=c:2:14 Extent=[121:9 - 121:10]
// CHECK: 121:14: UnexposedExpr= Extent=[121:14 - 121:20]
-// CHECK: 121:14: UnexposedExpr= Extent=[121:14 - 121:20]
-// CHECK: 121:24: UnexposedExpr= Extent=[121:24 - 121:35]
+// CHECK: 121:14: IntegerLiteral= Extent=[121:14 - 121:20]
+// CHECK: 121:24: BinaryOperator= Extent=[121:24 - 121:35]
// CHECK: 121:24: DeclRefExpr=c:2:14 Extent=[121:24 - 121:25]
// CHECK: 121:29: UnexposedExpr= Extent=[121:29 - 121:35]
-// CHECK: 121:29: UnexposedExpr= Extent=[121:29 - 121:35]
-// CHECK: 122:8: UnexposedExpr= Extent=[122:8 - 122:19]
+// CHECK: 121:29: IntegerLiteral= Extent=[121:29 - 121:35]
+// CHECK: 122:8: BinaryOperator= Extent=[122:8 - 122:19]
// CHECK: 122:8: DeclRefExpr=c:2:14 Extent=[122:8 - 122:9]
// CHECK: 122:13: UnexposedExpr= Extent=[122:13 - 122:19]
-// CHECK: 122:13: UnexposedExpr= Extent=[122:13 - 122:19]
-// CHECK: 122:24: UnexposedExpr= Extent=[122:24 - 122:50]
-// CHECK: 122:24: UnexposedExpr= Extent=[122:24 - 122:35]
+// CHECK: 122:13: IntegerLiteral= Extent=[122:13 - 122:19]
+// CHECK: 122:24: BinaryOperator= Extent=[122:24 - 122:50]
+// CHECK: 122:24: BinaryOperator= Extent=[122:24 - 122:35]
// CHECK: 122:24: DeclRefExpr=c:2:14 Extent=[122:24 - 122:25]
// CHECK: 122:29: UnexposedExpr= Extent=[122:29 - 122:35]
-// CHECK: 122:29: UnexposedExpr= Extent=[122:29 - 122:35]
-// CHECK: 122:39: UnexposedExpr= Extent=[122:39 - 122:50]
+// CHECK: 122:29: IntegerLiteral= Extent=[122:29 - 122:35]
+// CHECK: 122:39: BinaryOperator= Extent=[122:39 - 122:50]
// CHECK: 122:39: DeclRefExpr=c:2:14 Extent=[122:39 - 122:40]
// CHECK: 122:44: UnexposedExpr= Extent=[122:44 - 122:50]
-// CHECK: 122:44: UnexposedExpr= Extent=[122:44 - 122:50]
-// CHECK: 123:9: UnexposedExpr= Extent=[123:9 - 123:35]
-// CHECK: 123:9: UnexposedExpr= Extent=[123:9 - 123:20]
+// CHECK: 122:44: IntegerLiteral= Extent=[122:44 - 122:50]
+// CHECK: 123:9: BinaryOperator= Extent=[123:9 - 123:35]
+// CHECK: 123:9: BinaryOperator= Extent=[123:9 - 123:20]
// CHECK: 123:9: DeclRefExpr=c:2:14 Extent=[123:9 - 123:10]
// CHECK: 123:14: UnexposedExpr= Extent=[123:14 - 123:20]
-// CHECK: 123:14: UnexposedExpr= Extent=[123:14 - 123:20]
-// CHECK: 123:24: UnexposedExpr= Extent=[123:24 - 123:35]
+// CHECK: 123:14: IntegerLiteral= Extent=[123:14 - 123:20]
+// CHECK: 123:24: BinaryOperator= Extent=[123:24 - 123:35]
// CHECK: 123:24: DeclRefExpr=c:2:14 Extent=[123:24 - 123:25]
// CHECK: 123:29: UnexposedExpr= Extent=[123:29 - 123:35]
-// CHECK: 123:29: UnexposedExpr= Extent=[123:29 - 123:35]
-// CHECK: 124:8: UnexposedExpr= Extent=[124:8 - 124:19]
+// CHECK: 123:29: IntegerLiteral= Extent=[123:29 - 123:35]
+// CHECK: 124:8: BinaryOperator= Extent=[124:8 - 124:19]
// CHECK: 124:8: DeclRefExpr=c:2:14 Extent=[124:8 - 124:9]
// CHECK: 124:13: UnexposedExpr= Extent=[124:13 - 124:19]
-// CHECK: 124:13: UnexposedExpr= Extent=[124:13 - 124:19]
-// CHECK: 124:23: UnexposedExpr= Extent=[124:23 - 124:34]
+// CHECK: 124:13: IntegerLiteral= Extent=[124:13 - 124:19]
+// CHECK: 124:23: BinaryOperator= Extent=[124:23 - 124:34]
// CHECK: 124:23: DeclRefExpr=c:2:14 Extent=[124:23 - 124:24]
// CHECK: 124:28: UnexposedExpr= Extent=[124:28 - 124:34]
-// CHECK: 124:28: UnexposedExpr= Extent=[124:28 - 124:34]
-// CHECK: 124:38: UnexposedExpr= Extent=[124:38 - 124:49]
+// CHECK: 124:28: IntegerLiteral= Extent=[124:28 - 124:34]
+// CHECK: 124:38: BinaryOperator= Extent=[124:38 - 124:49]
// CHECK: 124:38: DeclRefExpr=c:2:14 Extent=[124:38 - 124:39]
// CHECK: 124:43: UnexposedExpr= Extent=[124:43 - 124:49]
-// CHECK: 124:43: UnexposedExpr= Extent=[124:43 - 124:49]
-// CHECK: 124:53: UnexposedExpr= Extent=[124:53 - 124:64]
+// CHECK: 124:43: IntegerLiteral= Extent=[124:43 - 124:49]
+// CHECK: 124:53: BinaryOperator= Extent=[124:53 - 124:64]
// CHECK: 124:53: DeclRefExpr=c:2:14 Extent=[124:53 - 124:54]
// CHECK: 124:58: UnexposedExpr= Extent=[124:58 - 124:64]
-// CHECK: 124:58: UnexposedExpr= Extent=[124:58 - 124:64]
-// CHECK: 125:5: UnexposedExpr= Extent=[125:5 - 125:16]
+// CHECK: 124:58: IntegerLiteral= Extent=[124:58 - 124:64]
+// CHECK: 125:5: BinaryOperator= Extent=[125:5 - 125:16]
// CHECK: 125:5: DeclRefExpr=c:2:14 Extent=[125:5 - 125:6]
// CHECK: 125:10: UnexposedExpr= Extent=[125:10 - 125:16]
-// CHECK: 125:10: UnexposedExpr= Extent=[125:10 - 125:16]
-// CHECK: 125:20: UnexposedExpr= Extent=[125:20 - 125:31]
+// CHECK: 125:10: IntegerLiteral= Extent=[125:10 - 125:16]
+// CHECK: 125:20: BinaryOperator= Extent=[125:20 - 125:31]
// CHECK: 125:20: DeclRefExpr=c:2:14 Extent=[125:20 - 125:21]
// CHECK: 125:25: UnexposedExpr= Extent=[125:25 - 125:31]
-// CHECK: 125:25: UnexposedExpr= Extent=[125:25 - 125:31]
-// CHECK: 125:36: UnexposedExpr= Extent=[125:36 - 125:62]
-// CHECK: 125:36: UnexposedExpr= Extent=[125:36 - 125:47]
+// CHECK: 125:25: IntegerLiteral= Extent=[125:25 - 125:31]
+// CHECK: 125:36: BinaryOperator= Extent=[125:36 - 125:62]
+// CHECK: 125:36: BinaryOperator= Extent=[125:36 - 125:47]
// CHECK: 125:36: DeclRefExpr=c:2:14 Extent=[125:36 - 125:37]
// CHECK: 125:41: UnexposedExpr= Extent=[125:41 - 125:47]
-// CHECK: 125:41: UnexposedExpr= Extent=[125:41 - 125:47]
-// CHECK: 125:51: UnexposedExpr= Extent=[125:51 - 125:62]
+// CHECK: 125:41: IntegerLiteral= Extent=[125:41 - 125:47]
+// CHECK: 125:51: BinaryOperator= Extent=[125:51 - 125:62]
// CHECK: 125:51: DeclRefExpr=c:2:14 Extent=[125:51 - 125:52]
// CHECK: 125:56: UnexposedExpr= Extent=[125:56 - 125:62]
-// CHECK: 125:56: UnexposedExpr= Extent=[125:56 - 125:62]
-// CHECK: 126:8: UnexposedExpr= Extent=[126:8 - 126:19]
+// CHECK: 125:56: IntegerLiteral= Extent=[125:56 - 125:62]
+// CHECK: 126:8: BinaryOperator= Extent=[126:8 - 126:19]
// CHECK: 126:8: DeclRefExpr=c:2:14 Extent=[126:8 - 126:9]
// CHECK: 126:13: UnexposedExpr= Extent=[126:13 - 126:19]
-// CHECK: 126:13: UnexposedExpr= Extent=[126:13 - 126:19]
-// CHECK: 126:24: UnexposedExpr= Extent=[126:24 - 126:50]
-// CHECK: 126:24: UnexposedExpr= Extent=[126:24 - 126:35]
+// CHECK: 126:13: IntegerLiteral= Extent=[126:13 - 126:19]
+// CHECK: 126:24: BinaryOperator= Extent=[126:24 - 126:50]
+// CHECK: 126:24: BinaryOperator= Extent=[126:24 - 126:35]
// CHECK: 126:24: DeclRefExpr=c:2:14 Extent=[126:24 - 126:25]
// CHECK: 126:29: UnexposedExpr= Extent=[126:29 - 126:35]
-// CHECK: 126:29: UnexposedExpr= Extent=[126:29 - 126:35]
-// CHECK: 126:39: UnexposedExpr= Extent=[126:39 - 126:50]
+// CHECK: 126:29: IntegerLiteral= Extent=[126:29 - 126:35]
+// CHECK: 126:39: BinaryOperator= Extent=[126:39 - 126:50]
// CHECK: 126:39: DeclRefExpr=c:2:14 Extent=[126:39 - 126:40]
// CHECK: 126:44: UnexposedExpr= Extent=[126:44 - 126:50]
-// CHECK: 126:44: UnexposedExpr= Extent=[126:44 - 126:50]
-// CHECK: 127:8: UnexposedExpr= Extent=[127:8 - 127:19]
+// CHECK: 126:44: IntegerLiteral= Extent=[126:44 - 126:50]
+// CHECK: 127:8: BinaryOperator= Extent=[127:8 - 127:19]
// CHECK: 127:8: DeclRefExpr=c:2:14 Extent=[127:8 - 127:9]
// CHECK: 127:13: UnexposedExpr= Extent=[127:13 - 127:19]
-// CHECK: 127:13: UnexposedExpr= Extent=[127:13 - 127:19]
-// CHECK: 127:23: UnexposedExpr= Extent=[127:23 - 127:34]
+// CHECK: 127:13: IntegerLiteral= Extent=[127:13 - 127:19]
+// CHECK: 127:23: BinaryOperator= Extent=[127:23 - 127:34]
// CHECK: 127:23: DeclRefExpr=c:2:14 Extent=[127:23 - 127:24]
// CHECK: 127:28: UnexposedExpr= Extent=[127:28 - 127:34]
-// CHECK: 127:28: UnexposedExpr= Extent=[127:28 - 127:34]
-// CHECK: 127:38: UnexposedExpr= Extent=[127:38 - 127:49]
+// CHECK: 127:28: IntegerLiteral= Extent=[127:28 - 127:34]
+// CHECK: 127:38: BinaryOperator= Extent=[127:38 - 127:49]
// CHECK: 127:38: DeclRefExpr=c:2:14 Extent=[127:38 - 127:39]
// CHECK: 127:43: UnexposedExpr= Extent=[127:43 - 127:49]
-// CHECK: 127:43: UnexposedExpr= Extent=[127:43 - 127:49]
-// CHECK: 127:53: UnexposedExpr= Extent=[127:53 - 127:64]
+// CHECK: 127:43: IntegerLiteral= Extent=[127:43 - 127:49]
+// CHECK: 127:53: BinaryOperator= Extent=[127:53 - 127:64]
// CHECK: 127:53: DeclRefExpr=c:2:14 Extent=[127:53 - 127:54]
// CHECK: 127:58: UnexposedExpr= Extent=[127:58 - 127:64]
-// CHECK: 127:58: UnexposedExpr= Extent=[127:58 - 127:64]
-// CHECK: 128:6: UnexposedExpr= Extent=[128:6 - 128:32]
-// CHECK: 128:6: UnexposedExpr= Extent=[128:6 - 128:17]
+// CHECK: 127:58: IntegerLiteral= Extent=[127:58 - 127:64]
+// CHECK: 128:6: BinaryOperator= Extent=[128:6 - 128:32]
+// CHECK: 128:6: BinaryOperator= Extent=[128:6 - 128:17]
// CHECK: 128:6: DeclRefExpr=c:2:14 Extent=[128:6 - 128:7]
// CHECK: 128:11: UnexposedExpr= Extent=[128:11 - 128:17]
-// CHECK: 128:11: UnexposedExpr= Extent=[128:11 - 128:17]
-// CHECK: 128:21: UnexposedExpr= Extent=[128:21 - 128:32]
+// CHECK: 128:11: IntegerLiteral= Extent=[128:11 - 128:17]
+// CHECK: 128:21: BinaryOperator= Extent=[128:21 - 128:32]
// CHECK: 128:21: DeclRefExpr=c:2:14 Extent=[128:21 - 128:22]
// CHECK: 128:26: UnexposedExpr= Extent=[128:26 - 128:32]
-// CHECK: 128:26: UnexposedExpr= Extent=[128:26 - 128:32]
-// CHECK: 129:9: UnexposedExpr= Extent=[129:9 - 129:35]
-// CHECK: 129:9: UnexposedExpr= Extent=[129:9 - 129:20]
+// CHECK: 128:26: IntegerLiteral= Extent=[128:26 - 128:32]
+// CHECK: 129:9: BinaryOperator= Extent=[129:9 - 129:35]
+// CHECK: 129:9: BinaryOperator= Extent=[129:9 - 129:20]
// CHECK: 129:9: DeclRefExpr=c:2:14 Extent=[129:9 - 129:10]
// CHECK: 129:14: UnexposedExpr= Extent=[129:14 - 129:20]
-// CHECK: 129:14: UnexposedExpr= Extent=[129:14 - 129:20]
-// CHECK: 129:24: UnexposedExpr= Extent=[129:24 - 129:35]
+// CHECK: 129:14: IntegerLiteral= Extent=[129:14 - 129:20]
+// CHECK: 129:24: BinaryOperator= Extent=[129:24 - 129:35]
// CHECK: 129:24: DeclRefExpr=c:2:14 Extent=[129:24 - 129:25]
// CHECK: 129:29: UnexposedExpr= Extent=[129:29 - 129:35]
-// CHECK: 129:29: UnexposedExpr= Extent=[129:29 - 129:35]
-// CHECK: 130:8: UnexposedExpr= Extent=[130:8 - 130:19]
+// CHECK: 129:29: IntegerLiteral= Extent=[129:29 - 129:35]
+// CHECK: 130:8: BinaryOperator= Extent=[130:8 - 130:19]
// CHECK: 130:8: DeclRefExpr=c:2:14 Extent=[130:8 - 130:9]
// CHECK: 130:13: UnexposedExpr= Extent=[130:13 - 130:19]
-// CHECK: 130:13: UnexposedExpr= Extent=[130:13 - 130:19]
-// CHECK: 130:23: UnexposedExpr= Extent=[130:23 - 130:34]
+// CHECK: 130:13: IntegerLiteral= Extent=[130:13 - 130:19]
+// CHECK: 130:23: BinaryOperator= Extent=[130:23 - 130:34]
// CHECK: 130:23: DeclRefExpr=c:2:14 Extent=[130:23 - 130:24]
// CHECK: 130:28: UnexposedExpr= Extent=[130:28 - 130:34]
-// CHECK: 130:28: UnexposedExpr= Extent=[130:28 - 130:34]
-// CHECK: 130:38: UnexposedExpr= Extent=[130:38 - 130:49]
+// CHECK: 130:28: IntegerLiteral= Extent=[130:28 - 130:34]
+// CHECK: 130:38: BinaryOperator= Extent=[130:38 - 130:49]
// CHECK: 130:38: DeclRefExpr=c:2:14 Extent=[130:38 - 130:39]
// CHECK: 130:43: UnexposedExpr= Extent=[130:43 - 130:49]
-// CHECK: 130:43: UnexposedExpr= Extent=[130:43 - 130:49]
-// CHECK: 130:53: UnexposedExpr= Extent=[130:53 - 130:64]
+// CHECK: 130:43: IntegerLiteral= Extent=[130:43 - 130:49]
+// CHECK: 130:53: BinaryOperator= Extent=[130:53 - 130:64]
// CHECK: 130:53: DeclRefExpr=c:2:14 Extent=[130:53 - 130:54]
// CHECK: 130:58: UnexposedExpr= Extent=[130:58 - 130:64]
-// CHECK: 130:58: UnexposedExpr= Extent=[130:58 - 130:64]
-// CHECK: 131:6: UnexposedExpr= Extent=[131:6 - 131:32]
-// CHECK: 131:6: UnexposedExpr= Extent=[131:6 - 131:17]
+// CHECK: 130:58: IntegerLiteral= Extent=[130:58 - 130:64]
+// CHECK: 131:6: BinaryOperator= Extent=[131:6 - 131:32]
+// CHECK: 131:6: BinaryOperator= Extent=[131:6 - 131:17]
// CHECK: 131:6: DeclRefExpr=c:2:14 Extent=[131:6 - 131:7]
// CHECK: 131:11: UnexposedExpr= Extent=[131:11 - 131:17]
-// CHECK: 131:11: UnexposedExpr= Extent=[131:11 - 131:17]
-// CHECK: 131:21: UnexposedExpr= Extent=[131:21 - 131:32]
+// CHECK: 131:11: IntegerLiteral= Extent=[131:11 - 131:17]
+// CHECK: 131:21: BinaryOperator= Extent=[131:21 - 131:32]
// CHECK: 131:21: DeclRefExpr=c:2:14 Extent=[131:21 - 131:22]
// CHECK: 131:26: UnexposedExpr= Extent=[131:26 - 131:32]
-// CHECK: 131:26: UnexposedExpr= Extent=[131:26 - 131:32]
-// CHECK: 132:9: UnexposedExpr= Extent=[132:9 - 132:35]
-// CHECK: 132:9: UnexposedExpr= Extent=[132:9 - 132:20]
+// CHECK: 131:26: IntegerLiteral= Extent=[131:26 - 131:32]
+// CHECK: 132:9: BinaryOperator= Extent=[132:9 - 132:35]
+// CHECK: 132:9: BinaryOperator= Extent=[132:9 - 132:20]
// CHECK: 132:9: DeclRefExpr=c:2:14 Extent=[132:9 - 132:10]
// CHECK: 132:14: UnexposedExpr= Extent=[132:14 - 132:20]
-// CHECK: 132:14: UnexposedExpr= Extent=[132:14 - 132:20]
-// CHECK: 132:24: UnexposedExpr= Extent=[132:24 - 132:35]
+// CHECK: 132:14: IntegerLiteral= Extent=[132:14 - 132:20]
+// CHECK: 132:24: BinaryOperator= Extent=[132:24 - 132:35]
// CHECK: 132:24: DeclRefExpr=c:2:14 Extent=[132:24 - 132:25]
// CHECK: 132:29: UnexposedExpr= Extent=[132:29 - 132:35]
-// CHECK: 132:29: UnexposedExpr= Extent=[132:29 - 132:35]
-// CHECK: 133:8: UnexposedExpr= Extent=[133:8 - 133:19]
+// CHECK: 132:29: IntegerLiteral= Extent=[132:29 - 132:35]
+// CHECK: 133:8: BinaryOperator= Extent=[133:8 - 133:19]
// CHECK: 133:8: DeclRefExpr=c:2:14 Extent=[133:8 - 133:9]
// CHECK: 133:13: UnexposedExpr= Extent=[133:13 - 133:19]
-// CHECK: 133:13: UnexposedExpr= Extent=[133:13 - 133:19]
-// CHECK: 133:24: UnexposedExpr= Extent=[133:24 - 133:50]
-// CHECK: 133:24: UnexposedExpr= Extent=[133:24 - 133:35]
+// CHECK: 133:13: IntegerLiteral= Extent=[133:13 - 133:19]
+// CHECK: 133:24: BinaryOperator= Extent=[133:24 - 133:50]
+// CHECK: 133:24: BinaryOperator= Extent=[133:24 - 133:35]
// CHECK: 133:24: DeclRefExpr=c:2:14 Extent=[133:24 - 133:25]
// CHECK: 133:29: UnexposedExpr= Extent=[133:29 - 133:35]
-// CHECK: 133:29: UnexposedExpr= Extent=[133:29 - 133:35]
-// CHECK: 133:39: UnexposedExpr= Extent=[133:39 - 133:50]
+// CHECK: 133:29: IntegerLiteral= Extent=[133:29 - 133:35]
+// CHECK: 133:39: BinaryOperator= Extent=[133:39 - 133:50]
// CHECK: 133:39: DeclRefExpr=c:2:14 Extent=[133:39 - 133:40]
// CHECK: 133:44: UnexposedExpr= Extent=[133:44 - 133:50]
-// CHECK: 133:44: UnexposedExpr= Extent=[133:44 - 133:50]
-// CHECK: 134:8: UnexposedExpr= Extent=[134:8 - 134:19]
+// CHECK: 133:44: IntegerLiteral= Extent=[133:44 - 133:50]
+// CHECK: 134:8: BinaryOperator= Extent=[134:8 - 134:19]
// CHECK: 134:8: DeclRefExpr=c:2:14 Extent=[134:8 - 134:9]
// CHECK: 134:13: UnexposedExpr= Extent=[134:13 - 134:19]
-// CHECK: 134:13: UnexposedExpr= Extent=[134:13 - 134:19]
-// CHECK: 134:23: UnexposedExpr= Extent=[134:23 - 134:34]
+// CHECK: 134:13: IntegerLiteral= Extent=[134:13 - 134:19]
+// CHECK: 134:23: BinaryOperator= Extent=[134:23 - 134:34]
// CHECK: 134:23: DeclRefExpr=c:2:14 Extent=[134:23 - 134:24]
// CHECK: 134:28: UnexposedExpr= Extent=[134:28 - 134:34]
-// CHECK: 134:28: UnexposedExpr= Extent=[134:28 - 134:34]
-// CHECK: 134:38: UnexposedExpr= Extent=[134:38 - 134:49]
+// CHECK: 134:28: IntegerLiteral= Extent=[134:28 - 134:34]
+// CHECK: 134:38: BinaryOperator= Extent=[134:38 - 134:49]
// CHECK: 134:38: DeclRefExpr=c:2:14 Extent=[134:38 - 134:39]
// CHECK: 134:43: UnexposedExpr= Extent=[134:43 - 134:49]
-// CHECK: 134:43: UnexposedExpr= Extent=[134:43 - 134:49]
-// CHECK: 134:54: UnexposedExpr= Extent=[134:54 - 134:80]
-// CHECK: 134:54: UnexposedExpr= Extent=[134:54 - 134:65]
+// CHECK: 134:43: IntegerLiteral= Extent=[134:43 - 134:49]
+// CHECK: 134:54: BinaryOperator= Extent=[134:54 - 134:80]
+// CHECK: 134:54: BinaryOperator= Extent=[134:54 - 134:65]
// CHECK: 134:54: DeclRefExpr=c:2:14 Extent=[134:54 - 134:55]
// CHECK: 134:59: UnexposedExpr= Extent=[134:59 - 134:65]
-// CHECK: 134:59: UnexposedExpr= Extent=[134:59 - 134:65]
-// CHECK: 134:69: UnexposedExpr= Extent=[134:69 - 134:80]
+// CHECK: 134:59: IntegerLiteral= Extent=[134:59 - 134:65]
+// CHECK: 134:69: BinaryOperator= Extent=[134:69 - 134:80]
// CHECK: 134:69: DeclRefExpr=c:2:14 Extent=[134:69 - 134:70]
// CHECK: 134:74: UnexposedExpr= Extent=[134:74 - 134:80]
-// CHECK: 134:74: UnexposedExpr= Extent=[134:74 - 134:80]
-// CHECK: 135:9: UnexposedExpr= Extent=[135:9 - 135:35]
-// CHECK: 135:9: UnexposedExpr= Extent=[135:9 - 135:20]
+// CHECK: 134:74: IntegerLiteral= Extent=[134:74 - 134:80]
+// CHECK: 135:9: BinaryOperator= Extent=[135:9 - 135:35]
+// CHECK: 135:9: BinaryOperator= Extent=[135:9 - 135:20]
// CHECK: 135:9: DeclRefExpr=c:2:14 Extent=[135:9 - 135:10]
// CHECK: 135:14: UnexposedExpr= Extent=[135:14 - 135:20]
-// CHECK: 135:14: UnexposedExpr= Extent=[135:14 - 135:20]
-// CHECK: 135:24: UnexposedExpr= Extent=[135:24 - 135:35]
+// CHECK: 135:14: IntegerLiteral= Extent=[135:14 - 135:20]
+// CHECK: 135:24: BinaryOperator= Extent=[135:24 - 135:35]
// CHECK: 135:24: DeclRefExpr=c:2:14 Extent=[135:24 - 135:25]
// CHECK: 135:29: UnexposedExpr= Extent=[135:29 - 135:35]
-// CHECK: 135:29: UnexposedExpr= Extent=[135:29 - 135:35]
-// CHECK: 136:9: UnexposedExpr= Extent=[136:9 - 136:35]
-// CHECK: 136:9: UnexposedExpr= Extent=[136:9 - 136:20]
+// CHECK: 135:29: IntegerLiteral= Extent=[135:29 - 135:35]
+// CHECK: 136:9: BinaryOperator= Extent=[136:9 - 136:35]
+// CHECK: 136:9: BinaryOperator= Extent=[136:9 - 136:20]
// CHECK: 136:9: DeclRefExpr=c:2:14 Extent=[136:9 - 136:10]
// CHECK: 136:14: UnexposedExpr= Extent=[136:14 - 136:20]
-// CHECK: 136:14: UnexposedExpr= Extent=[136:14 - 136:20]
-// CHECK: 136:24: UnexposedExpr= Extent=[136:24 - 136:35]
+// CHECK: 136:14: IntegerLiteral= Extent=[136:14 - 136:20]
+// CHECK: 136:24: BinaryOperator= Extent=[136:24 - 136:35]
// CHECK: 136:24: DeclRefExpr=c:2:14 Extent=[136:24 - 136:25]
// CHECK: 136:29: UnexposedExpr= Extent=[136:29 - 136:35]
-// CHECK: 136:29: UnexposedExpr= Extent=[136:29 - 136:35]
-// CHECK: 137:9: UnexposedExpr= Extent=[137:9 - 137:35]
-// CHECK: 137:9: UnexposedExpr= Extent=[137:9 - 137:20]
+// CHECK: 136:29: IntegerLiteral= Extent=[136:29 - 136:35]
+// CHECK: 137:9: BinaryOperator= Extent=[137:9 - 137:35]
+// CHECK: 137:9: BinaryOperator= Extent=[137:9 - 137:20]
// CHECK: 137:9: DeclRefExpr=c:2:14 Extent=[137:9 - 137:10]
// CHECK: 137:14: UnexposedExpr= Extent=[137:14 - 137:20]
-// CHECK: 137:14: UnexposedExpr= Extent=[137:14 - 137:20]
-// CHECK: 137:24: UnexposedExpr= Extent=[137:24 - 137:35]
+// CHECK: 137:14: IntegerLiteral= Extent=[137:14 - 137:20]
+// CHECK: 137:24: BinaryOperator= Extent=[137:24 - 137:35]
// CHECK: 137:24: DeclRefExpr=c:2:14 Extent=[137:24 - 137:25]
// CHECK: 137:29: UnexposedExpr= Extent=[137:29 - 137:35]
-// CHECK: 137:29: UnexposedExpr= Extent=[137:29 - 137:35]
-// CHECK: 138:9: UnexposedExpr= Extent=[138:9 - 138:35]
-// CHECK: 138:9: UnexposedExpr= Extent=[138:9 - 138:20]
+// CHECK: 137:29: IntegerLiteral= Extent=[137:29 - 137:35]
+// CHECK: 138:9: BinaryOperator= Extent=[138:9 - 138:35]
+// CHECK: 138:9: BinaryOperator= Extent=[138:9 - 138:20]
// CHECK: 138:9: DeclRefExpr=c:2:14 Extent=[138:9 - 138:10]
// CHECK: 138:14: UnexposedExpr= Extent=[138:14 - 138:20]
-// CHECK: 138:14: UnexposedExpr= Extent=[138:14 - 138:20]
-// CHECK: 138:24: UnexposedExpr= Extent=[138:24 - 138:35]
+// CHECK: 138:14: IntegerLiteral= Extent=[138:14 - 138:20]
+// CHECK: 138:24: BinaryOperator= Extent=[138:24 - 138:35]
// CHECK: 138:24: DeclRefExpr=c:2:14 Extent=[138:24 - 138:25]
// CHECK: 138:29: UnexposedExpr= Extent=[138:29 - 138:35]
-// CHECK: 138:29: UnexposedExpr= Extent=[138:29 - 138:35]
-// CHECK: 139:9: UnexposedExpr= Extent=[139:9 - 139:35]
-// CHECK: 139:9: UnexposedExpr= Extent=[139:9 - 139:20]
+// CHECK: 138:29: IntegerLiteral= Extent=[138:29 - 138:35]
+// CHECK: 139:9: BinaryOperator= Extent=[139:9 - 139:35]
+// CHECK: 139:9: BinaryOperator= Extent=[139:9 - 139:20]
// CHECK: 139:9: DeclRefExpr=c:2:14 Extent=[139:9 - 139:10]
// CHECK: 139:14: UnexposedExpr= Extent=[139:14 - 139:20]
-// CHECK: 139:14: UnexposedExpr= Extent=[139:14 - 139:20]
-// CHECK: 139:24: UnexposedExpr= Extent=[139:24 - 139:35]
+// CHECK: 139:14: IntegerLiteral= Extent=[139:14 - 139:20]
+// CHECK: 139:24: BinaryOperator= Extent=[139:24 - 139:35]
// CHECK: 139:24: DeclRefExpr=c:2:14 Extent=[139:24 - 139:25]
// CHECK: 139:29: UnexposedExpr= Extent=[139:29 - 139:35]
-// CHECK: 139:29: UnexposedExpr= Extent=[139:29 - 139:35]
-// CHECK: 140:9: UnexposedExpr= Extent=[140:9 - 140:35]
-// CHECK: 140:9: UnexposedExpr= Extent=[140:9 - 140:20]
+// CHECK: 139:29: IntegerLiteral= Extent=[139:29 - 139:35]
+// CHECK: 140:9: BinaryOperator= Extent=[140:9 - 140:35]
+// CHECK: 140:9: BinaryOperator= Extent=[140:9 - 140:20]
// CHECK: 140:9: DeclRefExpr=c:2:14 Extent=[140:9 - 140:10]
// CHECK: 140:14: UnexposedExpr= Extent=[140:14 - 140:20]
-// CHECK: 140:14: UnexposedExpr= Extent=[140:14 - 140:20]
-// CHECK: 140:24: UnexposedExpr= Extent=[140:24 - 140:35]
+// CHECK: 140:14: IntegerLiteral= Extent=[140:14 - 140:20]
+// CHECK: 140:24: BinaryOperator= Extent=[140:24 - 140:35]
// CHECK: 140:24: DeclRefExpr=c:2:14 Extent=[140:24 - 140:25]
// CHECK: 140:29: UnexposedExpr= Extent=[140:29 - 140:35]
-// CHECK: 140:29: UnexposedExpr= Extent=[140:29 - 140:35]
-// CHECK: 141:8: UnexposedExpr= Extent=[141:8 - 141:19]
+// CHECK: 140:29: IntegerLiteral= Extent=[140:29 - 140:35]
+// CHECK: 141:8: BinaryOperator= Extent=[141:8 - 141:19]
// CHECK: 141:8: DeclRefExpr=c:2:14 Extent=[141:8 - 141:9]
// CHECK: 141:13: UnexposedExpr= Extent=[141:13 - 141:19]
-// CHECK: 141:13: UnexposedExpr= Extent=[141:13 - 141:19]
-// CHECK: 141:23: UnexposedExpr= Extent=[141:23 - 141:34]
+// CHECK: 141:13: IntegerLiteral= Extent=[141:13 - 141:19]
+// CHECK: 141:23: BinaryOperator= Extent=[141:23 - 141:34]
// CHECK: 141:23: DeclRefExpr=c:2:14 Extent=[141:23 - 141:24]
// CHECK: 141:28: UnexposedExpr= Extent=[141:28 - 141:34]
-// CHECK: 141:28: UnexposedExpr= Extent=[141:28 - 141:34]
-// CHECK: 141:38: UnexposedExpr= Extent=[141:38 - 141:49]
+// CHECK: 141:28: IntegerLiteral= Extent=[141:28 - 141:34]
+// CHECK: 141:38: BinaryOperator= Extent=[141:38 - 141:49]
// CHECK: 141:38: DeclRefExpr=c:2:14 Extent=[141:38 - 141:39]
// CHECK: 141:43: UnexposedExpr= Extent=[141:43 - 141:49]
-// CHECK: 141:43: UnexposedExpr= Extent=[141:43 - 141:49]
-// CHECK: 141:54: UnexposedExpr= Extent=[141:54 - 141:80]
-// CHECK: 141:54: UnexposedExpr= Extent=[141:54 - 141:65]
+// CHECK: 141:43: IntegerLiteral= Extent=[141:43 - 141:49]
+// CHECK: 141:54: BinaryOperator= Extent=[141:54 - 141:80]
+// CHECK: 141:54: BinaryOperator= Extent=[141:54 - 141:65]
// CHECK: 141:54: DeclRefExpr=c:2:14 Extent=[141:54 - 141:55]
// CHECK: 141:59: UnexposedExpr= Extent=[141:59 - 141:65]
-// CHECK: 141:59: UnexposedExpr= Extent=[141:59 - 141:65]
-// CHECK: 141:69: UnexposedExpr= Extent=[141:69 - 141:80]
+// CHECK: 141:59: IntegerLiteral= Extent=[141:59 - 141:65]
+// CHECK: 141:69: BinaryOperator= Extent=[141:69 - 141:80]
// CHECK: 141:69: DeclRefExpr=c:2:14 Extent=[141:69 - 141:70]
// CHECK: 141:74: UnexposedExpr= Extent=[141:74 - 141:80]
-// CHECK: 141:74: UnexposedExpr= Extent=[141:74 - 141:80]
-// CHECK: 142:9: UnexposedExpr= Extent=[142:9 - 142:35]
-// CHECK: 142:9: UnexposedExpr= Extent=[142:9 - 142:20]
+// CHECK: 141:74: IntegerLiteral= Extent=[141:74 - 141:80]
+// CHECK: 142:9: BinaryOperator= Extent=[142:9 - 142:35]
+// CHECK: 142:9: BinaryOperator= Extent=[142:9 - 142:20]
// CHECK: 142:9: DeclRefExpr=c:2:14 Extent=[142:9 - 142:10]
// CHECK: 142:14: UnexposedExpr= Extent=[142:14 - 142:20]
-// CHECK: 142:14: UnexposedExpr= Extent=[142:14 - 142:20]
-// CHECK: 142:24: UnexposedExpr= Extent=[142:24 - 142:35]
+// CHECK: 142:14: IntegerLiteral= Extent=[142:14 - 142:20]
+// CHECK: 142:24: BinaryOperator= Extent=[142:24 - 142:35]
// CHECK: 142:24: DeclRefExpr=c:2:14 Extent=[142:24 - 142:25]
// CHECK: 142:29: UnexposedExpr= Extent=[142:29 - 142:35]
-// CHECK: 142:29: UnexposedExpr= Extent=[142:29 - 142:35]
-// CHECK: 143:9: UnexposedExpr= Extent=[143:9 - 143:35]
-// CHECK: 143:9: UnexposedExpr= Extent=[143:9 - 143:20]
+// CHECK: 142:29: IntegerLiteral= Extent=[142:29 - 142:35]
+// CHECK: 143:9: BinaryOperator= Extent=[143:9 - 143:35]
+// CHECK: 143:9: BinaryOperator= Extent=[143:9 - 143:20]
// CHECK: 143:9: DeclRefExpr=c:2:14 Extent=[143:9 - 143:10]
// CHECK: 143:14: UnexposedExpr= Extent=[143:14 - 143:20]
-// CHECK: 143:14: UnexposedExpr= Extent=[143:14 - 143:20]
-// CHECK: 143:24: UnexposedExpr= Extent=[143:24 - 143:35]
+// CHECK: 143:14: IntegerLiteral= Extent=[143:14 - 143:20]
+// CHECK: 143:24: BinaryOperator= Extent=[143:24 - 143:35]
// CHECK: 143:24: DeclRefExpr=c:2:14 Extent=[143:24 - 143:25]
// CHECK: 143:29: UnexposedExpr= Extent=[143:29 - 143:35]
-// CHECK: 143:29: UnexposedExpr= Extent=[143:29 - 143:35]
-// CHECK: 144:8: UnexposedExpr= Extent=[144:8 - 144:19]
+// CHECK: 143:29: IntegerLiteral= Extent=[143:29 - 143:35]
+// CHECK: 144:8: BinaryOperator= Extent=[144:8 - 144:19]
// CHECK: 144:8: DeclRefExpr=c:2:14 Extent=[144:8 - 144:9]
// CHECK: 144:13: UnexposedExpr= Extent=[144:13 - 144:19]
-// CHECK: 144:13: UnexposedExpr= Extent=[144:13 - 144:19]
-// CHECK: 144:24: UnexposedExpr= Extent=[144:24 - 144:50]
-// CHECK: 144:24: UnexposedExpr= Extent=[144:24 - 144:35]
+// CHECK: 144:13: IntegerLiteral= Extent=[144:13 - 144:19]
+// CHECK: 144:24: BinaryOperator= Extent=[144:24 - 144:50]
+// CHECK: 144:24: BinaryOperator= Extent=[144:24 - 144:35]
// CHECK: 144:24: DeclRefExpr=c:2:14 Extent=[144:24 - 144:25]
// CHECK: 144:29: UnexposedExpr= Extent=[144:29 - 144:35]
-// CHECK: 144:29: UnexposedExpr= Extent=[144:29 - 144:35]
-// CHECK: 144:39: UnexposedExpr= Extent=[144:39 - 144:50]
+// CHECK: 144:29: IntegerLiteral= Extent=[144:29 - 144:35]
+// CHECK: 144:39: BinaryOperator= Extent=[144:39 - 144:50]
// CHECK: 144:39: DeclRefExpr=c:2:14 Extent=[144:39 - 144:40]
// CHECK: 144:44: UnexposedExpr= Extent=[144:44 - 144:50]
-// CHECK: 144:44: UnexposedExpr= Extent=[144:44 - 144:50]
-// CHECK: 145:9: UnexposedExpr= Extent=[145:9 - 145:35]
-// CHECK: 145:9: UnexposedExpr= Extent=[145:9 - 145:20]
+// CHECK: 144:44: IntegerLiteral= Extent=[144:44 - 144:50]
+// CHECK: 145:9: BinaryOperator= Extent=[145:9 - 145:35]
+// CHECK: 145:9: BinaryOperator= Extent=[145:9 - 145:20]
// CHECK: 145:9: DeclRefExpr=c:2:14 Extent=[145:9 - 145:10]
// CHECK: 145:14: UnexposedExpr= Extent=[145:14 - 145:20]
-// CHECK: 145:14: UnexposedExpr= Extent=[145:14 - 145:20]
-// CHECK: 145:24: UnexposedExpr= Extent=[145:24 - 145:35]
+// CHECK: 145:14: IntegerLiteral= Extent=[145:14 - 145:20]
+// CHECK: 145:24: BinaryOperator= Extent=[145:24 - 145:35]
// CHECK: 145:24: DeclRefExpr=c:2:14 Extent=[145:24 - 145:25]
// CHECK: 145:29: UnexposedExpr= Extent=[145:29 - 145:35]
-// CHECK: 145:29: UnexposedExpr= Extent=[145:29 - 145:35]
-// CHECK: 146:9: UnexposedExpr= Extent=[146:9 - 146:35]
-// CHECK: 146:9: UnexposedExpr= Extent=[146:9 - 146:20]
+// CHECK: 145:29: IntegerLiteral= Extent=[145:29 - 145:35]
+// CHECK: 146:9: BinaryOperator= Extent=[146:9 - 146:35]
+// CHECK: 146:9: BinaryOperator= Extent=[146:9 - 146:20]
// CHECK: 146:9: DeclRefExpr=c:2:14 Extent=[146:9 - 146:10]
// CHECK: 146:14: UnexposedExpr= Extent=[146:14 - 146:20]
-// CHECK: 146:14: UnexposedExpr= Extent=[146:14 - 146:20]
-// CHECK: 146:24: UnexposedExpr= Extent=[146:24 - 146:35]
+// CHECK: 146:14: IntegerLiteral= Extent=[146:14 - 146:20]
+// CHECK: 146:24: BinaryOperator= Extent=[146:24 - 146:35]
// CHECK: 146:24: DeclRefExpr=c:2:14 Extent=[146:24 - 146:25]
// CHECK: 146:29: UnexposedExpr= Extent=[146:29 - 146:35]
-// CHECK: 146:29: UnexposedExpr= Extent=[146:29 - 146:35]
-// CHECK: 147:9: UnexposedExpr= Extent=[147:9 - 147:35]
-// CHECK: 147:9: UnexposedExpr= Extent=[147:9 - 147:20]
+// CHECK: 146:29: IntegerLiteral= Extent=[146:29 - 146:35]
+// CHECK: 147:9: BinaryOperator= Extent=[147:9 - 147:35]
+// CHECK: 147:9: BinaryOperator= Extent=[147:9 - 147:20]
// CHECK: 147:9: DeclRefExpr=c:2:14 Extent=[147:9 - 147:10]
// CHECK: 147:14: UnexposedExpr= Extent=[147:14 - 147:20]
-// CHECK: 147:14: UnexposedExpr= Extent=[147:14 - 147:20]
-// CHECK: 147:24: UnexposedExpr= Extent=[147:24 - 147:35]
+// CHECK: 147:14: IntegerLiteral= Extent=[147:14 - 147:20]
+// CHECK: 147:24: BinaryOperator= Extent=[147:24 - 147:35]
// CHECK: 147:24: DeclRefExpr=c:2:14 Extent=[147:24 - 147:25]
// CHECK: 147:29: UnexposedExpr= Extent=[147:29 - 147:35]
-// CHECK: 147:29: UnexposedExpr= Extent=[147:29 - 147:35]
-// CHECK: 148:9: UnexposedExpr= Extent=[148:9 - 148:35]
-// CHECK: 148:9: UnexposedExpr= Extent=[148:9 - 148:20]
+// CHECK: 147:29: IntegerLiteral= Extent=[147:29 - 147:35]
+// CHECK: 148:9: BinaryOperator= Extent=[148:9 - 148:35]
+// CHECK: 148:9: BinaryOperator= Extent=[148:9 - 148:20]
// CHECK: 148:9: DeclRefExpr=c:2:14 Extent=[148:9 - 148:10]
// CHECK: 148:14: UnexposedExpr= Extent=[148:14 - 148:20]
-// CHECK: 148:14: UnexposedExpr= Extent=[148:14 - 148:20]
-// CHECK: 148:24: UnexposedExpr= Extent=[148:24 - 148:35]
+// CHECK: 148:14: IntegerLiteral= Extent=[148:14 - 148:20]
+// CHECK: 148:24: BinaryOperator= Extent=[148:24 - 148:35]
// CHECK: 148:24: DeclRefExpr=c:2:14 Extent=[148:24 - 148:25]
// CHECK: 148:29: UnexposedExpr= Extent=[148:29 - 148:35]
-// CHECK: 148:29: UnexposedExpr= Extent=[148:29 - 148:35]
-// CHECK: 149:9: UnexposedExpr= Extent=[149:9 - 149:35]
-// CHECK: 149:9: UnexposedExpr= Extent=[149:9 - 149:20]
+// CHECK: 148:29: IntegerLiteral= Extent=[148:29 - 148:35]
+// CHECK: 149:9: BinaryOperator= Extent=[149:9 - 149:35]
+// CHECK: 149:9: BinaryOperator= Extent=[149:9 - 149:20]
// CHECK: 149:9: DeclRefExpr=c:2:14 Extent=[149:9 - 149:10]
// CHECK: 149:14: UnexposedExpr= Extent=[149:14 - 149:20]
-// CHECK: 149:14: UnexposedExpr= Extent=[149:14 - 149:20]
-// CHECK: 149:24: UnexposedExpr= Extent=[149:24 - 149:35]
+// CHECK: 149:14: IntegerLiteral= Extent=[149:14 - 149:20]
+// CHECK: 149:24: BinaryOperator= Extent=[149:24 - 149:35]
// CHECK: 149:24: DeclRefExpr=c:2:14 Extent=[149:24 - 149:25]
// CHECK: 149:29: UnexposedExpr= Extent=[149:29 - 149:35]
-// CHECK: 149:29: UnexposedExpr= Extent=[149:29 - 149:35]
-// CHECK: 150:9: UnexposedExpr= Extent=[150:9 - 150:35]
-// CHECK: 150:9: UnexposedExpr= Extent=[150:9 - 150:20]
+// CHECK: 149:29: IntegerLiteral= Extent=[149:29 - 149:35]
+// CHECK: 150:9: BinaryOperator= Extent=[150:9 - 150:35]
+// CHECK: 150:9: BinaryOperator= Extent=[150:9 - 150:20]
// CHECK: 150:9: DeclRefExpr=c:2:14 Extent=[150:9 - 150:10]
// CHECK: 150:14: UnexposedExpr= Extent=[150:14 - 150:20]
-// CHECK: 150:14: UnexposedExpr= Extent=[150:14 - 150:20]
-// CHECK: 150:24: UnexposedExpr= Extent=[150:24 - 150:35]
+// CHECK: 150:14: IntegerLiteral= Extent=[150:14 - 150:20]
+// CHECK: 150:24: BinaryOperator= Extent=[150:24 - 150:35]
// CHECK: 150:24: DeclRefExpr=c:2:14 Extent=[150:24 - 150:25]
// CHECK: 150:29: UnexposedExpr= Extent=[150:29 - 150:35]
-// CHECK: 150:29: UnexposedExpr= Extent=[150:29 - 150:35]
-// CHECK: 151:8: UnexposedExpr= Extent=[151:8 - 151:19]
+// CHECK: 150:29: IntegerLiteral= Extent=[150:29 - 150:35]
+// CHECK: 151:8: BinaryOperator= Extent=[151:8 - 151:19]
// CHECK: 151:8: DeclRefExpr=c:2:14 Extent=[151:8 - 151:9]
// CHECK: 151:13: UnexposedExpr= Extent=[151:13 - 151:19]
-// CHECK: 151:13: UnexposedExpr= Extent=[151:13 - 151:19]
-// CHECK: 151:24: UnexposedExpr= Extent=[151:24 - 151:50]
-// CHECK: 151:24: UnexposedExpr= Extent=[151:24 - 151:35]
+// CHECK: 151:13: IntegerLiteral= Extent=[151:13 - 151:19]
+// CHECK: 151:24: BinaryOperator= Extent=[151:24 - 151:50]
+// CHECK: 151:24: BinaryOperator= Extent=[151:24 - 151:35]
// CHECK: 151:24: DeclRefExpr=c:2:14 Extent=[151:24 - 151:25]
// CHECK: 151:29: UnexposedExpr= Extent=[151:29 - 151:35]
-// CHECK: 151:29: UnexposedExpr= Extent=[151:29 - 151:35]
-// CHECK: 151:39: UnexposedExpr= Extent=[151:39 - 151:50]
+// CHECK: 151:29: IntegerLiteral= Extent=[151:29 - 151:35]
+// CHECK: 151:39: BinaryOperator= Extent=[151:39 - 151:50]
// CHECK: 151:39: DeclRefExpr=c:2:14 Extent=[151:39 - 151:40]
// CHECK: 151:44: UnexposedExpr= Extent=[151:44 - 151:50]
-// CHECK: 151:44: UnexposedExpr= Extent=[151:44 - 151:50]
-// CHECK: 152:8: UnexposedExpr= Extent=[152:8 - 152:19]
+// CHECK: 151:44: IntegerLiteral= Extent=[151:44 - 151:50]
+// CHECK: 152:8: BinaryOperator= Extent=[152:8 - 152:19]
// CHECK: 152:8: DeclRefExpr=c:2:14 Extent=[152:8 - 152:9]
// CHECK: 152:13: UnexposedExpr= Extent=[152:13 - 152:19]
-// CHECK: 152:13: UnexposedExpr= Extent=[152:13 - 152:19]
-// CHECK: 152:24: UnexposedExpr= Extent=[152:24 - 152:50]
-// CHECK: 152:24: UnexposedExpr= Extent=[152:24 - 152:35]
+// CHECK: 152:13: IntegerLiteral= Extent=[152:13 - 152:19]
+// CHECK: 152:24: BinaryOperator= Extent=[152:24 - 152:50]
+// CHECK: 152:24: BinaryOperator= Extent=[152:24 - 152:35]
// CHECK: 152:24: DeclRefExpr=c:2:14 Extent=[152:24 - 152:25]
// CHECK: 152:29: UnexposedExpr= Extent=[152:29 - 152:35]
-// CHECK: 152:29: UnexposedExpr= Extent=[152:29 - 152:35]
-// CHECK: 152:39: UnexposedExpr= Extent=[152:39 - 152:50]
+// CHECK: 152:29: IntegerLiteral= Extent=[152:29 - 152:35]
+// CHECK: 152:39: BinaryOperator= Extent=[152:39 - 152:50]
// CHECK: 152:39: DeclRefExpr=c:2:14 Extent=[152:39 - 152:40]
// CHECK: 152:44: UnexposedExpr= Extent=[152:44 - 152:50]
-// CHECK: 152:44: UnexposedExpr= Extent=[152:44 - 152:50]
-// CHECK: 153:9: UnexposedExpr= Extent=[153:9 - 153:35]
-// CHECK: 153:9: UnexposedExpr= Extent=[153:9 - 153:20]
+// CHECK: 152:44: IntegerLiteral= Extent=[152:44 - 152:50]
+// CHECK: 153:9: BinaryOperator= Extent=[153:9 - 153:35]
+// CHECK: 153:9: BinaryOperator= Extent=[153:9 - 153:20]
// CHECK: 153:9: DeclRefExpr=c:2:14 Extent=[153:9 - 153:10]
// CHECK: 153:14: UnexposedExpr= Extent=[153:14 - 153:20]
-// CHECK: 153:14: UnexposedExpr= Extent=[153:14 - 153:20]
-// CHECK: 153:24: UnexposedExpr= Extent=[153:24 - 153:35]
+// CHECK: 153:14: IntegerLiteral= Extent=[153:14 - 153:20]
+// CHECK: 153:24: BinaryOperator= Extent=[153:24 - 153:35]
// CHECK: 153:24: DeclRefExpr=c:2:14 Extent=[153:24 - 153:25]
// CHECK: 153:29: UnexposedExpr= Extent=[153:29 - 153:35]
-// CHECK: 153:29: UnexposedExpr= Extent=[153:29 - 153:35]
-// CHECK: 154:9: UnexposedExpr= Extent=[154:9 - 154:35]
-// CHECK: 154:9: UnexposedExpr= Extent=[154:9 - 154:20]
+// CHECK: 153:29: IntegerLiteral= Extent=[153:29 - 153:35]
+// CHECK: 154:9: BinaryOperator= Extent=[154:9 - 154:35]
+// CHECK: 154:9: BinaryOperator= Extent=[154:9 - 154:20]
// CHECK: 154:9: DeclRefExpr=c:2:14 Extent=[154:9 - 154:10]
// CHECK: 154:14: UnexposedExpr= Extent=[154:14 - 154:20]
-// CHECK: 154:14: UnexposedExpr= Extent=[154:14 - 154:20]
-// CHECK: 154:24: UnexposedExpr= Extent=[154:24 - 154:35]
+// CHECK: 154:14: IntegerLiteral= Extent=[154:14 - 154:20]
+// CHECK: 154:24: BinaryOperator= Extent=[154:24 - 154:35]
// CHECK: 154:24: DeclRefExpr=c:2:14 Extent=[154:24 - 154:25]
// CHECK: 154:29: UnexposedExpr= Extent=[154:29 - 154:35]
-// CHECK: 154:29: UnexposedExpr= Extent=[154:29 - 154:35]
-// CHECK: 155:9: UnexposedExpr= Extent=[155:9 - 155:35]
-// CHECK: 155:9: UnexposedExpr= Extent=[155:9 - 155:20]
+// CHECK: 154:29: IntegerLiteral= Extent=[154:29 - 154:35]
+// CHECK: 155:9: BinaryOperator= Extent=[155:9 - 155:35]
+// CHECK: 155:9: BinaryOperator= Extent=[155:9 - 155:20]
// CHECK: 155:9: DeclRefExpr=c:2:14 Extent=[155:9 - 155:10]
// CHECK: 155:14: UnexposedExpr= Extent=[155:14 - 155:20]
-// CHECK: 155:14: UnexposedExpr= Extent=[155:14 - 155:20]
-// CHECK: 155:24: UnexposedExpr= Extent=[155:24 - 155:35]
+// CHECK: 155:14: IntegerLiteral= Extent=[155:14 - 155:20]
+// CHECK: 155:24: BinaryOperator= Extent=[155:24 - 155:35]
// CHECK: 155:24: DeclRefExpr=c:2:14 Extent=[155:24 - 155:25]
// CHECK: 155:29: UnexposedExpr= Extent=[155:29 - 155:35]
-// CHECK: 155:29: UnexposedExpr= Extent=[155:29 - 155:35]
-// CHECK: 156:9: UnexposedExpr= Extent=[156:9 - 156:35]
-// CHECK: 156:9: UnexposedExpr= Extent=[156:9 - 156:20]
+// CHECK: 155:29: IntegerLiteral= Extent=[155:29 - 155:35]
+// CHECK: 156:9: BinaryOperator= Extent=[156:9 - 156:35]
+// CHECK: 156:9: BinaryOperator= Extent=[156:9 - 156:20]
// CHECK: 156:9: DeclRefExpr=c:2:14 Extent=[156:9 - 156:10]
// CHECK: 156:14: UnexposedExpr= Extent=[156:14 - 156:20]
-// CHECK: 156:14: UnexposedExpr= Extent=[156:14 - 156:20]
-// CHECK: 156:24: UnexposedExpr= Extent=[156:24 - 156:35]
+// CHECK: 156:14: IntegerLiteral= Extent=[156:14 - 156:20]
+// CHECK: 156:24: BinaryOperator= Extent=[156:24 - 156:35]
// CHECK: 156:24: DeclRefExpr=c:2:14 Extent=[156:24 - 156:25]
// CHECK: 156:29: UnexposedExpr= Extent=[156:29 - 156:35]
-// CHECK: 156:29: UnexposedExpr= Extent=[156:29 - 156:35]
-// CHECK: 157:9: UnexposedExpr= Extent=[157:9 - 157:35]
-// CHECK: 157:9: UnexposedExpr= Extent=[157:9 - 157:20]
+// CHECK: 156:29: IntegerLiteral= Extent=[156:29 - 156:35]
+// CHECK: 157:9: BinaryOperator= Extent=[157:9 - 157:35]
+// CHECK: 157:9: BinaryOperator= Extent=[157:9 - 157:20]
// CHECK: 157:9: DeclRefExpr=c:2:14 Extent=[157:9 - 157:10]
// CHECK: 157:14: UnexposedExpr= Extent=[157:14 - 157:20]
-// CHECK: 157:14: UnexposedExpr= Extent=[157:14 - 157:20]
-// CHECK: 157:24: UnexposedExpr= Extent=[157:24 - 157:35]
+// CHECK: 157:14: IntegerLiteral= Extent=[157:14 - 157:20]
+// CHECK: 157:24: BinaryOperator= Extent=[157:24 - 157:35]
// CHECK: 157:24: DeclRefExpr=c:2:14 Extent=[157:24 - 157:25]
// CHECK: 157:29: UnexposedExpr= Extent=[157:29 - 157:35]
-// CHECK: 157:29: UnexposedExpr= Extent=[157:29 - 157:35]
-// CHECK: 158:8: UnexposedExpr= Extent=[158:8 - 158:19]
+// CHECK: 157:29: IntegerLiteral= Extent=[157:29 - 157:35]
+// CHECK: 158:8: BinaryOperator= Extent=[158:8 - 158:19]
// CHECK: 158:8: DeclRefExpr=c:2:14 Extent=[158:8 - 158:9]
// CHECK: 158:13: UnexposedExpr= Extent=[158:13 - 158:19]
-// CHECK: 158:13: UnexposedExpr= Extent=[158:13 - 158:19]
-// CHECK: 158:24: UnexposedExpr= Extent=[158:24 - 158:50]
-// CHECK: 158:24: UnexposedExpr= Extent=[158:24 - 158:35]
+// CHECK: 158:13: IntegerLiteral= Extent=[158:13 - 158:19]
+// CHECK: 158:24: BinaryOperator= Extent=[158:24 - 158:50]
+// CHECK: 158:24: BinaryOperator= Extent=[158:24 - 158:35]
// CHECK: 158:24: DeclRefExpr=c:2:14 Extent=[158:24 - 158:25]
// CHECK: 158:29: UnexposedExpr= Extent=[158:29 - 158:35]
-// CHECK: 158:29: UnexposedExpr= Extent=[158:29 - 158:35]
-// CHECK: 158:39: UnexposedExpr= Extent=[158:39 - 158:50]
+// CHECK: 158:29: IntegerLiteral= Extent=[158:29 - 158:35]
+// CHECK: 158:39: BinaryOperator= Extent=[158:39 - 158:50]
// CHECK: 158:39: DeclRefExpr=c:2:14 Extent=[158:39 - 158:40]
// CHECK: 158:44: UnexposedExpr= Extent=[158:44 - 158:50]
-// CHECK: 158:44: UnexposedExpr= Extent=[158:44 - 158:50]
-// CHECK: 159:9: UnexposedExpr= Extent=[159:9 - 159:35]
-// CHECK: 159:9: UnexposedExpr= Extent=[159:9 - 159:20]
+// CHECK: 158:44: IntegerLiteral= Extent=[158:44 - 158:50]
+// CHECK: 159:9: BinaryOperator= Extent=[159:9 - 159:35]
+// CHECK: 159:9: BinaryOperator= Extent=[159:9 - 159:20]
// CHECK: 159:9: DeclRefExpr=c:2:14 Extent=[159:9 - 159:10]
// CHECK: 159:14: UnexposedExpr= Extent=[159:14 - 159:20]
-// CHECK: 159:14: UnexposedExpr= Extent=[159:14 - 159:20]
-// CHECK: 159:24: UnexposedExpr= Extent=[159:24 - 159:35]
+// CHECK: 159:14: IntegerLiteral= Extent=[159:14 - 159:20]
+// CHECK: 159:24: BinaryOperator= Extent=[159:24 - 159:35]
// CHECK: 159:24: DeclRefExpr=c:2:14 Extent=[159:24 - 159:25]
// CHECK: 159:29: UnexposedExpr= Extent=[159:29 - 159:35]
-// CHECK: 159:29: UnexposedExpr= Extent=[159:29 - 159:35]
-// CHECK: 160:8: UnexposedExpr= Extent=[160:8 - 160:19]
+// CHECK: 159:29: IntegerLiteral= Extent=[159:29 - 159:35]
+// CHECK: 160:8: BinaryOperator= Extent=[160:8 - 160:19]
// CHECK: 160:8: DeclRefExpr=c:2:14 Extent=[160:8 - 160:9]
// CHECK: 160:13: UnexposedExpr= Extent=[160:13 - 160:19]
-// CHECK: 160:13: UnexposedExpr= Extent=[160:13 - 160:19]
-// CHECK: 160:23: UnexposedExpr= Extent=[160:23 - 160:51]
-// CHECK: 160:24: UnexposedExpr= Extent=[160:24 - 160:50]
-// CHECK: 160:24: UnexposedExpr= Extent=[160:24 - 160:35]
+// CHECK: 160:13: IntegerLiteral= Extent=[160:13 - 160:19]
+// CHECK: 160:23: ParenExpr= Extent=[160:23 - 160:51]
+// CHECK: 160:24: BinaryOperator= Extent=[160:24 - 160:50]
+// CHECK: 160:24: BinaryOperator= Extent=[160:24 - 160:35]
// CHECK: 160:24: DeclRefExpr=c:2:14 Extent=[160:24 - 160:25]
// CHECK: 160:29: UnexposedExpr= Extent=[160:29 - 160:35]
-// CHECK: 160:29: UnexposedExpr= Extent=[160:29 - 160:35]
-// CHECK: 160:39: UnexposedExpr= Extent=[160:39 - 160:50]
+// CHECK: 160:29: IntegerLiteral= Extent=[160:29 - 160:35]
+// CHECK: 160:39: BinaryOperator= Extent=[160:39 - 160:50]
// CHECK: 160:39: DeclRefExpr=c:2:14 Extent=[160:39 - 160:40]
// CHECK: 160:44: UnexposedExpr= Extent=[160:44 - 160:50]
-// CHECK: 160:44: UnexposedExpr= Extent=[160:44 - 160:50]
+// CHECK: 160:44: IntegerLiteral= Extent=[160:44 - 160:50]
diff --git a/test/Index/nested-macro-instantiations.cpp b/test/Index/nested-macro-instantiations.cpp
index 9d0c0521f404..0ed84dd00800 100644
--- a/test/Index/nested-macro-instantiations.cpp
+++ b/test/Index/nested-macro-instantiations.cpp
@@ -7,7 +7,7 @@ WIBBLE(int x);
// RUN: env CINDEXTEST_NESTED_MACROS=1 c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITH-NESTED %s
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_NESTED_MACROS=1 c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITH-NESTED %s
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_NESTED_MACROS=1 c-index-test -test-load-source-reparse 5 all %s | FileCheck -check-prefix CHECK-WITH-NESTED %s
-// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:5:1: macro expansion=WIBBLE:3:9 Extent=[5:1 - 5:7]
+// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:5:1: macro expansion=WIBBLE:3:9 Extent=[5:1 - 5:14]
// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:3:19: macro expansion=BAR:2:9 Extent=[3:19 - 5:14]
// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:2:16: macro expansion=FOO:1:9 Extent=[2:16 - 5:14]
// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:5:1: VarDecl=x:5:1 (Definition) Extent=[5:1 - 5:14]
@@ -15,6 +15,6 @@ WIBBLE(int x);
// RUN: c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITHOUT-NESTED %s
// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITHOUT-NESTED %s
// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 all %s | FileCheck -check-prefix CHECK-WITHOUT-NESTED %s
-// CHECK-WITHOUT-NESTED: nested-macro-instantiations.cpp:5:1: macro expansion=WIBBLE:3:9 Extent=[5:1 - 5:7]
+// CHECK-WITHOUT-NESTED: nested-macro-instantiations.cpp:5:1: macro expansion=WIBBLE:3:9 Extent=[5:1 - 5:14]
// CHECK-WITHOUT-NESTED-NOT: nested-macro-instantiations.cpp:3:19: macro expansion=BAR:2:9 Extent=[3:19 - 5:14]
// CHECK-WITHOUT-NESTED: nested-macro-instantiations.cpp:5:1: VarDecl=x:5:1 (Definition) Extent=[5:1 - 5:14]
diff --git a/test/Index/preamble-reparse-cmd-define.c b/test/Index/preamble-reparse-cmd-define.c
new file mode 100644
index 000000000000..67ffde1a0cb8
--- /dev/null
+++ b/test/Index/preamble-reparse-cmd-define.c
@@ -0,0 +1,9 @@
+// RUN: c-index-test -write-pch %t.h.pch %s.h
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_REMAP_AFTER_TRIAL=1 c-index-test -test-load-source-reparse 3 local \
+// RUN: "-remap-file=%s;%s.remap" %s -include %t.h -D CMD_MACRO=1 2>&1 | FileCheck %s
+
+// CHECK-NOT: error:
+
+int foo() {
+ return x;
+}
diff --git a/test/Index/preamble-reparse-cmd-define.c.h b/test/Index/preamble-reparse-cmd-define.c.h
new file mode 100644
index 000000000000..2497af651c2e
--- /dev/null
+++ b/test/Index/preamble-reparse-cmd-define.c.h
@@ -0,0 +1 @@
+extern int x;
diff --git a/test/Index/preamble-reparse-cmd-define.c.remap b/test/Index/preamble-reparse-cmd-define.c.remap
new file mode 100644
index 000000000000..35c140d08211
--- /dev/null
+++ b/test/Index/preamble-reparse-cmd-define.c.remap
@@ -0,0 +1,8 @@
+
+#ifndef CMD_MACRO
+#error CMD_MACRO undefined
+#endif
+
+int foo() {
+ return x;
+}
diff --git a/test/Index/preamble.c b/test/Index/preamble.c
index 119bdb58e759..8a158e9b30ce 100644
--- a/test/Index/preamble.c
+++ b/test/Index/preamble.c
@@ -9,11 +9,11 @@ void f(int x) {
// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 local -I %S/Inputs -include %t %s 2> %t.stderr.txt | FileCheck %s
// RUN: FileCheck -check-prefix CHECK-DIAG %s < %t.stderr.txt
// CHECK: preamble.h:1:12: FunctionDecl=bar:1:12 (Definition) Extent=[1:1 - 6:2]
-// CHECK: preamble.h:4:3: UnexposedExpr= Extent=[4:3 - 4:13]
+// CHECK: preamble.h:4:3: BinaryOperator= Extent=[4:3 - 4:13]
// CHECK: preamble.h:4:3: DeclRefExpr=ptr:2:8 Extent=[4:3 - 4:6]
// CHECK: preamble.h:4:9: UnexposedExpr=ptr1:3:10 Extent=[4:9 - 4:13]
// CHECK: preamble.h:4:9: DeclRefExpr=ptr1:3:10 Extent=[4:9 - 4:13]
-// CHECK: preamble.h:5:10: UnexposedExpr= Extent=[5:10 - 5:11]
+// CHECK: preamble.h:5:10: IntegerLiteral= Extent=[5:10 - 5:11]
// CHECK: preamble.c:3:5: FunctionDecl=wibble:3:5 Extent=[3:1 - 3:16]
// CHECK: preamble.c:3:15: ParmDecl=:3:15 (Definition) Extent=[3:12 - 3:16]
// CHECK-DIAG: preamble.h:4:7:{4:9-4:13}: warning: incompatible pointer types assigning to 'int *' from 'float *'
diff --git a/test/Index/preamble_macro_template.cpp b/test/Index/preamble_macro_template.cpp
new file mode 100644
index 000000000000..ee1b41376bb8
--- /dev/null
+++ b/test/Index/preamble_macro_template.cpp
@@ -0,0 +1,15 @@
+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
+// 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: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]
+// CHECK: preamble_macro_template.cpp:3:12: CompoundStmt= Extent=[3:12 - 3:15]
diff --git a/test/Index/print-typekind.c b/test/Index/print-typekind.c
index 30bd409b090f..c6583dbff38b 100644
--- a/test/Index/print-typekind.c
+++ b/test/Index/print-typekind.c
@@ -5,6 +5,7 @@ int *f(int *p, char *x, FooType 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]
@@ -14,14 +15,14 @@ typedef double OtherType;
// 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: UnexposedStmt= typekind=Invalid [isPOD=0]
-// CHECK: UnexposedStmt= typekind=Invalid [isPOD=0]
+// 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: UnexposedStmt= typekind=Invalid [isPOD=0]
-// CHECK: UnexposedExpr= typekind=Pointer [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/properties-class-extensions.m b/test/Index/properties-class-extensions.m
index de612425c270..7b1e90fcd6fe 100644
--- a/test/Index/properties-class-extensions.m
+++ b/test/Index/properties-class-extensions.m
@@ -72,12 +72,12 @@
// CHECK: properties-class-extensions.m:19:26: ParmDecl=bar:19:26 (Definition) Extent=[19:26 - 19:29]
// CHECK: properties-class-extensions.m:24:1: UnexposedDecl=[24:8] Extent=[24:1 - 24:23]
// CHECK: properties-class-extensions.m:24:8: ObjCClassRef=Rdar8467189_Bar:24:8 Extent=[24:8 - 24:23]
-// CHECK: properties-class-extensions.m:25:1: ObjCProtocolDecl=Rdar8467189_FooProtocol:25:1 (Definition) Extent=[25:1 - 27:5]
+// CHECK: properties-class-extensions.m:25:11: ObjCProtocolDecl=Rdar8467189_FooProtocol:25:11 (Definition) Extent=[25:1 - 27:5]
// CHECK: properties-class-extensions.m:26:39: ObjCPropertyDecl=Rdar8467189_Bar:26:39 Extent=[26:1 - 26:54]
// CHECK: properties-class-extensions.m:26:22: ObjCClassRef=Rdar8467189_Bar:24:8 Extent=[26:22 - 26:37]
// CHECK: properties-class-extensions.m:26:39: ObjCInstanceMethodDecl=Rdar8467189_Bar:26:39 Extent=[26:39 - 26:54]
// CHECK: properties-class-extensions.m:28:12: ObjCInterfaceDecl=Rdar8467189_Foo:28:12 Extent=[28:1 - 29:5]
-// CHECK: properties-class-extensions.m:28:29: ObjCProtocolRef=Rdar8467189_FooProtocol:25:1 Extent=[28:29 - 28:52]
+// CHECK: properties-class-extensions.m:28:29: ObjCProtocolRef=Rdar8467189_FooProtocol:25:11 Extent=[28:29 - 28:52]
// CHECK-NOT: properties-class-extensions.m:31:40: ObjCPropertyDecl=Rdar8467189_Bar:31:40 Extent=[31:40 - 31:55]
// CHECK-NOT: properties-class-extensions.m:31:23: ObjCClassRef=Rdar8467189_Bar:24:8 Extent=[31:23 - 31:38]
// CHECK: properties-class-extensions.m:30:12: ObjCCategoryDecl=:30:12 Extent=[30:1 - 32:5]
diff --git a/test/Index/rdar-8288645-invalid-code.mm b/test/Index/rdar-8288645-invalid-code.mm
index 74e2365edcfe..ec4564130a52 100644
--- a/test/Index/rdar-8288645-invalid-code.mm
+++ b/test/Index/rdar-8288645-invalid-code.mm
@@ -5,4 +5,3 @@
extern "C" { @implementation Foo - (id)initWithBar:(Baz<WozBar>)pepper {
// CHECK: warning: cannot find interface declaration for 'Foo'
-// CHECK: error: '@end' is missing in implementation context
diff --git a/test/Index/recursive-cxx-member-calls.cpp b/test/Index/recursive-cxx-member-calls.cpp
index 4c24083efd71..adaaae9cdd19 100644
--- a/test/Index/recursive-cxx-member-calls.cpp
+++ b/test/Index/recursive-cxx-member-calls.cpp
@@ -28,7 +28,7 @@ namespace clang {
AT_unavailable, AT_unused, AT_used, AT_vecreturn, AT_vector_size,
AT_visibility, AT_warn_unused_result, AT_weak, AT_weakref,
AT_weak_import, AT_reqd_wg_size, AT_init_priority,
- IgnoredAttribute, UnknownAttribute
+ AT_returns_twice, IgnoredAttribute, UnknownAttribute
};
static Kind getKind(const IdentifierInfo * Name);
};
@@ -157,7 +157,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
.Case("overloadable", AT_overloadable)
.Case("address_space", AT_address_space)
.Case("always_inline", AT_always_inline)
- .Case("returns_twice", IgnoredAttribute)
+ .Case("returns_twice", AT_returns_twice)
.Case("vec_type_hint", IgnoredAttribute)
.Case("objc_exception", AT_objc_exception)
.Case("ext_vector_type", AT_ext_vector_type)
@@ -392,9 +392,9 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: "," [30:38 - 30:39] EnumDecl=Kind:13:10 (Definition)
// CHECK-tokens: Identifier: "AT_init_priority" [30:40 - 30:56] EnumConstantDecl=AT_init_priority:30:40 (Definition)
// CHECK-tokens: Punctuation: "," [30:56 - 30:57] EnumDecl=Kind:13:10 (Definition)
-// CHECK-tokens: Identifier: "IgnoredAttribute" [31:7 - 31:23] EnumConstantDecl=IgnoredAttribute:31:7 (Definition)
+// CHECK-tokens: Identifier: "AT_returns_twice" [31:7 - 31:23] EnumConstantDecl=AT_returns_twice:31:7 (Definition)
// CHECK-tokens: Punctuation: "," [31:23 - 31:24] EnumDecl=Kind:13:10 (Definition)
-// CHECK-tokens: Identifier: "UnknownAttribute" [31:25 - 31:41] EnumConstantDecl=UnknownAttribute:31:25 (Definition)
+// 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)
@@ -425,8 +425,8 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Keyword: "class" [38:1 - 38:6] ClassDecl=StringRef:38:7 (Definition)
// CHECK-tokens: Identifier: "StringRef" [38:7 - 38:16] ClassDecl=StringRef:38:7 (Definition)
// CHECK-tokens: Punctuation: "{" [38:17 - 38:18] ClassDecl=StringRef:38:7 (Definition)
-// CHECK-tokens: Keyword: "public" [39:1 - 39:7] UnexposedDecl=:39:1 (Definition)
-// CHECK-tokens: Punctuation: ":" [39:7 - 39:8] UnexposedDecl=:39:1 (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: "char" [40:17 - 40:21] TypedefDecl=iterator:40:23 (Definition)
@@ -438,14 +438,14 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// 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
-// CHECK-tokens: Punctuation: "~" [41:30 - 41:31] UnexposedExpr=
+// CHECK-tokens: Punctuation: "~" [41:30 - 41:31] UnaryOperator=
// CHECK-tokens: Identifier: "size_t" [41:31 - 41:37] TypeRef=size_t:2:25
-// CHECK-tokens: Punctuation: "(" [41:37 - 41:38] UnexposedExpr=
-// CHECK-tokens: Literal: "0" [41:38 - 41:39] UnexposedExpr=
-// CHECK-tokens: Punctuation: ")" [41:39 - 41:40] UnexposedExpr=
+// CHECK-tokens: Punctuation: "(" [41:37 - 41:38] CXXFunctionalCastExpr=
+// CHECK-tokens: Literal: "0" [41:38 - 41:39] IntegerLiteral=
+// CHECK-tokens: Punctuation: ")" [41:39 - 41:40] CXXFunctionalCastExpr
// CHECK-tokens: Punctuation: ";" [41:40 - 41:41] ClassDecl=StringRef:38:7 (Definition)
-// CHECK-tokens: Keyword: "private" [42:1 - 42:8] UnexposedDecl=:42:1 (Definition)
-// CHECK-tokens: Punctuation: ":" [42:8 - 42:9] UnexposedDecl=:42:1 (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: "char" [43:9 - 43:13] FieldDecl=Data:43:15 (Definition)
// CHECK-tokens: Punctuation: "*" [43:14 - 43:15] FieldDecl=Data:43:15 (Definition)
@@ -464,34 +464,34 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Identifier: "size_t" [45:31 - 45:37] TypeRef=size_t:2:25
// CHECK-tokens: Identifier: "b" [45:38 - 45:39] ParmDecl=b:45:38 (Definition)
// CHECK-tokens: Punctuation: ")" [45:39 - 45:40] CXXMethod=min:45:17 (Definition) (static)
-// CHECK-tokens: Punctuation: "{" [45:41 - 45:42] UnexposedStmt=
-// CHECK-tokens: Keyword: "return" [45:43 - 45:49] UnexposedStmt=
+// CHECK-tokens: Punctuation: "{" [45:41 - 45:42] CompoundStmt=
+// CHECK-tokens: Keyword: "return" [45:43 - 45:49] ReturnStmt=
// CHECK-tokens: Identifier: "a" [45:50 - 45:51] DeclRefExpr=a:45:28
-// CHECK-tokens: Punctuation: "<" [45:52 - 45:53] UnexposedExpr=
+// CHECK-tokens: Punctuation: "<" [45:52 - 45:53] BinaryOperator=
// CHECK-tokens: Identifier: "b" [45:54 - 45:55] DeclRefExpr=b:45:38
-// CHECK-tokens: Punctuation: "?" [45:56 - 45:57] UnexposedExpr=
+// CHECK-tokens: Punctuation: "?" [45:56 - 45:57] ConditionalOperator=
// CHECK-tokens: Identifier: "a" [45:58 - 45:59] DeclRefExpr=a:45:28
-// CHECK-tokens: Punctuation: ":" [45:60 - 45:61] UnexposedExpr=
+// CHECK-tokens: Punctuation: ":" [45:60 - 45:61] ConditionalOperator
// CHECK-tokens: Identifier: "b" [45:62 - 45:63] DeclRefExpr=b:45:38
-// CHECK-tokens: Punctuation: ";" [45:63 - 45:64] UnexposedStmt=
-// CHECK-tokens: Punctuation: "}" [45:65 - 45:66] UnexposedStmt=
-// CHECK-tokens: Keyword: "public" [46:1 - 46:7] UnexposedDecl=:46:1 (Definition)
-// CHECK-tokens: Punctuation: ":" [46:7 - 46:8] UnexposedDecl=:46:1 (Definition)
+// CHECK-tokens: Punctuation: ";" [45:63 - 45:64] CompoundStmt=
+// CHECK-tokens: Punctuation: "}" [45:65 - 45:66] CompoundStmt=
+// CHECK-tokens: Keyword: "public" [46:1 - 46:7] CXXAccessSpecifier=:46:1 (Definition)
+// CHECK-tokens: Punctuation: ":" [46:7 - 46:8] CXXAccessSpecifier=:46:1 (Definition)
// CHECK-tokens: Identifier: "StringRef" [47:3 - 47:12] CXXConstructor=StringRef:47:3 (Definition)
// CHECK-tokens: Punctuation: "(" [47:12 - 47:13] CXXConstructor=StringRef:47:3 (Definition)
// CHECK-tokens: Punctuation: ")" [47:13 - 47:14] CXXConstructor=StringRef:47:3 (Definition)
// CHECK-tokens: Punctuation: ":" [47:14 - 47:15] CXXConstructor=StringRef:47:3 (Definition)
// CHECK-tokens: Identifier: "Data" [47:16 - 47:20] MemberRef=Data:43:15
// CHECK-tokens: Punctuation: "(" [47:20 - 47:21] CXXConstructor=StringRef:47:3 (Definition)
-// CHECK-tokens: Literal: "0" [47:21 - 47:22] UnexposedExpr=
+// CHECK-tokens: Literal: "0" [47:21 - 47:22] IntegerLiteral=
// CHECK-tokens: Punctuation: ")" [47:22 - 47:23] CXXConstructor=StringRef:47:3 (Definition)
// CHECK-tokens: Punctuation: "," [47:23 - 47:24] CXXConstructor=StringRef:47:3 (Definition)
// CHECK-tokens: Identifier: "Length" [47:25 - 47:31] MemberRef=Length:44:10
// CHECK-tokens: Punctuation: "(" [47:31 - 47:32] CXXConstructor=StringRef:47:3 (Definition)
-// CHECK-tokens: Literal: "0" [47:32 - 47:33] UnexposedExpr=
+// CHECK-tokens: Literal: "0" [47:32 - 47:33] IntegerLiteral=
// CHECK-tokens: Punctuation: ")" [47:33 - 47:34] CXXConstructor=StringRef:47:3 (Definition)
-// CHECK-tokens: Punctuation: "{" [47:35 - 47:36] UnexposedStmt=
-// CHECK-tokens: Punctuation: "}" [47:36 - 47:37] UnexposedStmt=
+// CHECK-tokens: Punctuation: "{" [47:35 - 47:36] CompoundStmt=
+// 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)
@@ -512,8 +512,8 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Identifier: "Str" [48:63 - 48:66] DeclRefExpr=Str:48:25
// CHECK-tokens: Punctuation: ")" [48:66 - 48:67] CallExpr=magic_length:36:8
// CHECK-tokens: Punctuation: ")" [48:67 - 48:68] CXXConstructor=StringRef:48:3 (Definition)
-// CHECK-tokens: Punctuation: "{" [48:69 - 48:70] UnexposedStmt=
-// CHECK-tokens: Punctuation: "}" [48:70 - 48:71] UnexposedStmt=
+// CHECK-tokens: Punctuation: "{" [48:69 - 48:70] CompoundStmt=
+// 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)
@@ -534,28 +534,28 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: "(" [49:66 - 49:67] CXXConstructor=StringRef:49:3 (Definition)
// CHECK-tokens: Identifier: "length" [49:67 - 49:73] DeclRefExpr=length:49:38
// CHECK-tokens: Punctuation: ")" [49:73 - 49:74] CXXConstructor=StringRef:49:3 (Definition)
-// CHECK-tokens: Punctuation: "{" [49:75 - 49:76] UnexposedStmt=
-// CHECK-tokens: Punctuation: "}" [49:76 - 49:77] UnexposedStmt=
+// CHECK-tokens: Punctuation: "{" [49:75 - 49:76] CompoundStmt=
+// CHECK-tokens: Punctuation: "}" [49:76 - 49:77] CompoundStmt=
// CHECK-tokens: Identifier: "iterator" [50:3 - 50:11] TypeRef=iterator:40:23
// CHECK-tokens: Identifier: "end" [50:12 - 50:15] CXXMethod=end:50:12 (Definition)
// CHECK-tokens: Punctuation: "(" [50:15 - 50:16] CXXMethod=end:50:12 (Definition)
// CHECK-tokens: Punctuation: ")" [50:16 - 50:17] CXXMethod=end:50:12 (Definition)
// CHECK-tokens: Keyword: "const" [50:18 - 50:23] CXXMethod=end:50:12 (Definition)
-// CHECK-tokens: Punctuation: "{" [50:24 - 50:25] UnexposedStmt=
-// CHECK-tokens: Keyword: "return" [50:26 - 50:32] UnexposedStmt=
+// CHECK-tokens: Punctuation: "{" [50:24 - 50:25] CompoundStmt=
+// CHECK-tokens: Keyword: "return" [50:26 - 50:32] ReturnStmt=
// CHECK-tokens: Identifier: "Data" [50:33 - 50:37] MemberRefExpr=Data:43:15
-// CHECK-tokens: Punctuation: ";" [50:37 - 50:38] UnexposedStmt=
-// CHECK-tokens: Punctuation: "}" [50:39 - 50:40] UnexposedStmt=
+// CHECK-tokens: Punctuation: ";" [50:37 - 50:38] CompoundStmt=
+// CHECK-tokens: Punctuation: "}" [50:39 - 50:40] CompoundStmt=
// CHECK-tokens: Identifier: "size_t" [51:3 - 51:9] TypeRef=size_t:2:25
// CHECK-tokens: Identifier: "size" [51:10 - 51:14] CXXMethod=size:51:10 (Definition)
// CHECK-tokens: Punctuation: "(" [51:14 - 51:15] CXXMethod=size:51:10 (Definition)
// CHECK-tokens: Punctuation: ")" [51:15 - 51:16] CXXMethod=size:51:10 (Definition)
// CHECK-tokens: Keyword: "const" [51:17 - 51:22] CXXMethod=size:51:10 (Definition)
-// CHECK-tokens: Punctuation: "{" [51:23 - 51:24] UnexposedStmt=
-// CHECK-tokens: Keyword: "return" [51:25 - 51:31] UnexposedStmt=
+// CHECK-tokens: Punctuation: "{" [51:23 - 51:24] CompoundStmt=
+// CHECK-tokens: Keyword: "return" [51:25 - 51:31] ReturnStmt=
// CHECK-tokens: Identifier: "Length" [51:32 - 51:38] MemberRefExpr=Length:44:10
-// CHECK-tokens: Punctuation: ";" [51:38 - 51:39] UnexposedStmt=
-// CHECK-tokens: Punctuation: "}" [51:40 - 51:41] UnexposedStmt=
+// CHECK-tokens: Punctuation: ";" [51:38 - 51:39] CompoundStmt=
+// CHECK-tokens: Punctuation: "}" [51:40 - 51:41] CompoundStmt=
// CHECK-tokens: Keyword: "bool" [52:3 - 52:7] CXXMethod=startswith:52:8 (Definition)
// CHECK-tokens: Identifier: "startswith" [52:8 - 52:18] CXXMethod=startswith:52:8 (Definition)
// CHECK-tokens: Punctuation: "(" [52:18 - 52:19] CXXMethod=startswith:52:8 (Definition)
@@ -563,14 +563,14 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Identifier: "Prefix" [52:29 - 52:35] ParmDecl=Prefix:52:29 (Definition)
// CHECK-tokens: Punctuation: ")" [52:35 - 52:36] CXXMethod=startswith:52:8 (Definition)
// CHECK-tokens: Keyword: "const" [52:37 - 52:42] CXXMethod=startswith:52:8 (Definition)
-// CHECK-tokens: Punctuation: "{" [52:43 - 52:44] UnexposedStmt=
-// CHECK-tokens: Keyword: "return" [53:5 - 53:11] UnexposedStmt=
+// CHECK-tokens: Punctuation: "{" [52:43 - 52:44] CompoundStmt=
+// CHECK-tokens: Keyword: "return" [53:5 - 53:11] ReturnStmt=
// CHECK-tokens: Identifier: "Length" [53:12 - 53:18] MemberRefExpr=Length:44:10
-// CHECK-tokens: Punctuation: ">=" [53:19 - 53:21] UnexposedExpr=
+// CHECK-tokens: Punctuation: ">=" [53:19 - 53:21] BinaryOperator=
// CHECK-tokens: Identifier: "Prefix" [53:22 - 53:28] DeclRefExpr=Prefix:52:29
// CHECK-tokens: Punctuation: "." [53:28 - 53:29] MemberRefExpr=Length:44:10
// CHECK-tokens: Identifier: "Length" [53:29 - 53:35] MemberRefExpr=Length:44:10
-// CHECK-tokens: Punctuation: "&&" [53:36 - 53:38] UnexposedExpr=
+// CHECK-tokens: Punctuation: "&&" [53:36 - 53:38] BinaryOperator=
// CHECK-tokens: Identifier: "memcmp" [54:11 - 54:17] DeclRefExpr=memcmp:7:7
// CHECK-tokens: Punctuation: "(" [54:17 - 54:18] CallExpr=memcmp:7:7
// CHECK-tokens: Identifier: "Data" [54:18 - 54:22] MemberRefExpr=Data:43:15
@@ -583,10 +583,10 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: "." [54:43 - 54:44] MemberRefExpr=Length:44:10
// CHECK-tokens: Identifier: "Length" [54:44 - 54:50] MemberRefExpr=Length:44:10
// CHECK-tokens: Punctuation: ")" [54:50 - 54:51] CallExpr=memcmp:7:7
-// CHECK-tokens: Punctuation: "==" [54:52 - 54:54] UnexposedExpr=
-// CHECK-tokens: Literal: "0" [54:55 - 54:56] UnexposedExpr=
-// CHECK-tokens: Punctuation: ";" [54:56 - 54:57] UnexposedStmt=
-// CHECK-tokens: Punctuation: "}" [55:3 - 55:4] UnexposedStmt=
+// CHECK-tokens: Punctuation: "==" [54:52 - 54:54] BinaryOperator=
+// CHECK-tokens: Literal: "0" [54:55 - 54:56] IntegerLiteral=
+// CHECK-tokens: Punctuation: ";" [54:56 - 54:57] CompoundStmt=
+// CHECK-tokens: Punctuation: "}" [55:3 - 55:4] CompoundStmt=
// CHECK-tokens: Keyword: "bool" [56:3 - 56:7] CXXMethod=endswith:56:8 (Definition)
// CHECK-tokens: Identifier: "endswith" [56:8 - 56:16] CXXMethod=endswith:56:8 (Definition)
// CHECK-tokens: Punctuation: "(" [56:16 - 56:17] CXXMethod=endswith:56:8 (Definition)
@@ -594,20 +594,20 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Identifier: "Suffix" [56:27 - 56:33] ParmDecl=Suffix:56:27 (Definition)
// CHECK-tokens: Punctuation: ")" [56:33 - 56:34] CXXMethod=endswith:56:8 (Definition)
// CHECK-tokens: Keyword: "const" [56:35 - 56:40] CXXMethod=endswith:56:8 (Definition)
-// CHECK-tokens: Punctuation: "{" [56:41 - 56:42] UnexposedStmt=
-// CHECK-tokens: Keyword: "return" [57:5 - 57:11] UnexposedStmt=
+// CHECK-tokens: Punctuation: "{" [56:41 - 56:42] CompoundStmt=
+// CHECK-tokens: Keyword: "return" [57:5 - 57:11] ReturnStmt=
// CHECK-tokens: Identifier: "Length" [57:12 - 57:18] MemberRefExpr=Length:44:10
-// CHECK-tokens: Punctuation: ">=" [57:19 - 57:21] UnexposedExpr=
+// CHECK-tokens: Punctuation: ">=" [57:19 - 57:21] BinaryOperator=
// CHECK-tokens: Identifier: "Suffix" [57:22 - 57:28] DeclRefExpr=Suffix:56:27
// CHECK-tokens: Punctuation: "." [57:28 - 57:29] MemberRefExpr=Length:44:10
// CHECK-tokens: Identifier: "Length" [57:29 - 57:35] MemberRefExpr=Length:44:10
-// CHECK-tokens: Punctuation: "&&" [57:36 - 57:38] UnexposedExpr=
+// CHECK-tokens: Punctuation: "&&" [57:36 - 57:38] BinaryOperator=
// CHECK-tokens: Identifier: "memcmp" [58:7 - 58:13] DeclRefExpr=memcmp:7:7
// CHECK-tokens: Punctuation: "(" [58:13 - 58:14] CallExpr=memcmp:7:7
// CHECK-tokens: Identifier: "end" [58:14 - 58:17] MemberRefExpr=end:50:12
// CHECK-tokens: Punctuation: "(" [58:17 - 58:18] CallExpr=end:50:12
// CHECK-tokens: Punctuation: ")" [58:18 - 58:19] CallExpr=end:50:12
-// CHECK-tokens: Punctuation: "-" [58:20 - 58:21] UnexposedExpr=
+// CHECK-tokens: Punctuation: "-" [58:20 - 58:21] BinaryOperator=
// CHECK-tokens: Identifier: "Suffix" [58:22 - 58:28] DeclRefExpr=Suffix:56:27
// CHECK-tokens: Punctuation: "." [58:28 - 58:29] MemberRefExpr=Length:44:10
// CHECK-tokens: Identifier: "Length" [58:29 - 58:35] MemberRefExpr=Length:44:10
@@ -620,10 +620,10 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: "." [58:56 - 58:57] MemberRefExpr=Length:44:10
// CHECK-tokens: Identifier: "Length" [58:57 - 58:63] MemberRefExpr=Length:44:10
// CHECK-tokens: Punctuation: ")" [58:63 - 58:64] CallExpr=memcmp:7:7
-// CHECK-tokens: Punctuation: "==" [58:65 - 58:67] UnexposedExpr=
-// CHECK-tokens: Literal: "0" [58:68 - 58:69] UnexposedExpr=
-// CHECK-tokens: Punctuation: ";" [58:69 - 58:70] UnexposedStmt=
-// CHECK-tokens: Punctuation: "}" [59:3 - 59:4] UnexposedStmt=
+// CHECK-tokens: Punctuation: "==" [58:65 - 58:67] BinaryOperator=
+// CHECK-tokens: Literal: "0" [58:68 - 58:69] IntegerLiteral=
+// CHECK-tokens: Punctuation: ";" [58:69 - 58:70] CompoundStmt=
+// CHECK-tokens: Punctuation: "}" [59:3 - 59:4] CompoundStmt=
// CHECK-tokens: Identifier: "StringRef" [60:3 - 60:12] TypeRef=class llvm::StringRef:38:7
// CHECK-tokens: Identifier: "substr" [60:13 - 60:19] CXXMethod=substr:60:13 (Definition)
// CHECK-tokens: Punctuation: "(" [60:19 - 60:20] CXXMethod=substr:60:13 (Definition)
@@ -636,12 +636,12 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Identifier: "npos" [60:45 - 60:49] DeclRefExpr=npos:41:23
// CHECK-tokens: Punctuation: ")" [60:49 - 60:50] CXXMethod=substr:60:13 (Definition)
// CHECK-tokens: Keyword: "const" [60:51 - 60:56] CXXMethod=substr:60:13 (Definition)
-// CHECK-tokens: Punctuation: "{" [60:57 - 60:58] UnexposedStmt=
-// CHECK-tokens: Keyword: "return" [61:5 - 61:11] UnexposedStmt=
+// CHECK-tokens: Punctuation: "{" [60:57 - 60:58] CompoundStmt=
+// CHECK-tokens: Keyword: "return" [61:5 - 61:11] ReturnStmt=
// CHECK-tokens: Identifier: "StringRef" [61:12 - 61:21] TypeRef=class llvm::StringRef:38:7
// CHECK-tokens: Punctuation: "(" [61:21 - 61:22] CallExpr=StringRef:49:3
// CHECK-tokens: Identifier: "Data" [61:22 - 61:26] MemberRefExpr=Data:43:15
-// CHECK-tokens: Punctuation: "+" [61:27 - 61:28] UnexposedExpr=
+// CHECK-tokens: Punctuation: "+" [61:27 - 61:28] BinaryOperator=
// CHECK-tokens: Identifier: "Start" [61:29 - 61:34] DeclRefExpr=Start:60:27
// CHECK-tokens: Punctuation: "," [61:34 - 61:35] CallExpr=StringRef:49:3
// CHECK-tokens: Identifier: "min" [61:36 - 61:39] DeclRefExpr=min:45:17
@@ -649,12 +649,12 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Identifier: "N" [61:40 - 61:41] DeclRefExpr=N:60:41
// CHECK-tokens: Punctuation: "," [61:41 - 61:42] CallExpr=min:45:17
// CHECK-tokens: Identifier: "Length" [61:43 - 61:49] MemberRefExpr=Length:44:10
-// CHECK-tokens: Punctuation: "-" [61:50 - 61:51] UnexposedExpr=
+// CHECK-tokens: Punctuation: "-" [61:50 - 61:51] BinaryOperator=
// CHECK-tokens: Identifier: "Start" [61:52 - 61:57] DeclRefExpr=Start:60:27
// CHECK-tokens: Punctuation: ")" [61:57 - 61:58] CallExpr=min:45:17
// CHECK-tokens: Punctuation: ")" [61:58 - 61:59] CallExpr=StringRef:49:3
-// CHECK-tokens: Punctuation: ";" [61:59 - 61:60] UnexposedStmt=
-// CHECK-tokens: Punctuation: "}" [62:3 - 62:4] UnexposedStmt=
+// CHECK-tokens: Punctuation: ";" [61:59 - 61:60] CompoundStmt=
+// CHECK-tokens: Punctuation: "}" [62:3 - 62:4] CompoundStmt=
// CHECK-tokens: Punctuation: "}" [63:1 - 63:2] ClassDecl=StringRef:38:7 (Definition)
// CHECK-tokens: Punctuation: ";" [63:2 - 63:3] Namespace=llvm:37:11 (Definition)
// CHECK-tokens: Punctuation: "}" [64:1 - 64:2] Namespace=llvm:37:11 (Definition)
@@ -664,8 +664,8 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Keyword: "class" [66:1 - 66:6] ClassDecl=IdentifierInfo:66:7 (Definition)
// CHECK-tokens: Identifier: "IdentifierInfo" [66:7 - 66:21] ClassDecl=IdentifierInfo:66:7 (Definition)
// CHECK-tokens: Punctuation: "{" [66:22 - 66:23] ClassDecl=IdentifierInfo:66:7 (Definition)
-// CHECK-tokens: Keyword: "public" [67:1 - 67:7] UnexposedDecl=:67:1 (Definition)
-// CHECK-tokens: Punctuation: ":" [67:7 - 67:8] UnexposedDecl=:67:1 (Definition)
+// CHECK-tokens: Keyword: "public" [67:1 - 67:7] CXXAccessSpecifier=:67:1 (Definition)
+// CHECK-tokens: Punctuation: ":" [67:7 - 67:8] CXXAccessSpecifier=:67:1 (Definition)
// CHECK-tokens: Identifier: "IdentifierInfo" [67:8 - 67:22] CXXConstructor=IdentifierInfo:67:8
// CHECK-tokens: Punctuation: "(" [67:22 - 67:23] CXXConstructor=IdentifierInfo:67:8
// CHECK-tokens: Punctuation: ")" [67:23 - 67:24] CXXConstructor=IdentifierInfo:67:8
@@ -677,8 +677,8 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: "(" [68:27 - 68:28] CXXMethod=getNameStart:68:15 (Definition)
// 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] UnexposedStmt=
-// CHECK-tokens: Keyword: "typedef" [69:5 - 69:12] UnexposedStmt=
+// CHECK-tokens: Punctuation: "{" [68:36 - 68:37] CompoundStmt=
+// CHECK-tokens: Keyword: "typedef" [69:5 - 69:12] DeclStmt=
// 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
@@ -690,27 +690,27 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: "*" [69:52 - 69:53] TypedefDecl=actualtype:69:54 (Definition)
// CHECK-tokens: Punctuation: ">" [69:53 - 69:54] TypedefDecl=actualtype:69:54 (Definition)
// CHECK-tokens: Identifier: "actualtype" [69:54 - 69:64] TypedefDecl=actualtype:69:54 (Definition)
-// CHECK-tokens: Punctuation: ";" [69:64 - 69:65] UnexposedStmt=
-// CHECK-tokens: Keyword: "return" [70:5 - 70:11] UnexposedStmt=
-// CHECK-tokens: Punctuation: "(" [70:12 - 70:13] UnexposedExpr=
-// CHECK-tokens: Punctuation: "(" [70:13 - 70:14] UnexposedExpr=
-// CHECK-tokens: Keyword: "const" [70:14 - 70:19] UnexposedExpr=
+// CHECK-tokens: Punctuation: ";" [69:64 - 69:65] DeclStmt=
+// CHECK-tokens: Keyword: "return" [70:5 - 70:11] ReturnStmt=
+// CHECK-tokens: Punctuation: "(" [70:12 - 70:13] ParenExpr=
+// CHECK-tokens: Punctuation: "(" [70:13 - 70:14] CStyleCastExpr=
+// CHECK-tokens: Keyword: "const" [70:14 - 70:19] CStyleCastExpr=
// CHECK-tokens: Identifier: "actualtype" [70:20 - 70:30] TypeRef=actualtype:69:54
-// CHECK-tokens: Punctuation: "*" [70:31 - 70:32] UnexposedExpr=
-// CHECK-tokens: Punctuation: ")" [70:32 - 70:33] UnexposedExpr=
-// CHECK-tokens: Keyword: "this" [70:34 - 70:38] UnexposedExpr=
-// CHECK-tokens: Punctuation: ")" [70:38 - 70:39] UnexposedExpr=
+// CHECK-tokens: Punctuation: "*" [70:31 - 70:32] CStyleCastExpr=
+// CHECK-tokens: Punctuation: ")" [70:32 - 70:33] CStyleCastExpr=
+// CHECK-tokens: Keyword: "this" [70:34 - 70:38] CXXThisExpr=
+// CHECK-tokens: Punctuation: ")" [70:38 - 70:39] ParenExpr=
// CHECK-tokens: Punctuation: "->" [70:39 - 70:41] MemberRefExpr=second:4:55
// CHECK-tokens: Identifier: "second" [70:41 - 70:47] MemberRefExpr=second:4:55
-// CHECK-tokens: Punctuation: ";" [70:47 - 70:48] UnexposedStmt=
-// CHECK-tokens: Punctuation: "}" [71:3 - 71:4] UnexposedStmt=
+// CHECK-tokens: Punctuation: ";" [70:47 - 70:48] CompoundStmt=
+// CHECK-tokens: Punctuation: "}" [71:3 - 71:4] CompoundStmt=
// CHECK-tokens: Keyword: "unsigned" [72:3 - 72:11] CXXMethod=getLength:72:12 (Definition)
// CHECK-tokens: Identifier: "getLength" [72:12 - 72:21] CXXMethod=getLength:72:12 (Definition)
// CHECK-tokens: Punctuation: "(" [72:21 - 72:22] CXXMethod=getLength:72:12 (Definition)
// 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] UnexposedStmt=
-// CHECK-tokens: Keyword: "typedef" [73:5 - 73:12] UnexposedStmt=
+// CHECK-tokens: Punctuation: "{" [72:30 - 72:31] CompoundStmt=
+// CHECK-tokens: Keyword: "typedef" [73:5 - 73:12] DeclStmt=
// 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
@@ -722,55 +722,55 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: "*" [73:52 - 73:53] TypedefDecl=actualtype:73:54 (Definition)
// 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] UnexposedStmt=
-// CHECK-tokens: Keyword: "const" [74:5 - 74:10] UnexposedStmt=
+// CHECK-tokens: Punctuation: ";" [73:64 - 73:65] DeclStmt=
+// CHECK-tokens: Keyword: "const" [74:5 - 74:10] DeclStmt=
// 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)
// CHECK-tokens: Punctuation: "=" [74:19 - 74:20] VarDecl=p:74:17 (Definition)
-// CHECK-tokens: Punctuation: "(" [74:21 - 74:22] UnexposedExpr=
-// CHECK-tokens: Punctuation: "(" [74:22 - 74:23] UnexposedExpr=
-// CHECK-tokens: Keyword: "const" [74:23 - 74:28] UnexposedExpr=
+// CHECK-tokens: Punctuation: "(" [74:21 - 74:22] ParenExpr=
+// CHECK-tokens: Punctuation: "(" [74:22 - 74:23] CStyleCastExpr=
+// CHECK-tokens: Keyword: "const" [74:23 - 74:28] CStyleCastExpr=
// CHECK-tokens: Identifier: "actualtype" [74:29 - 74:39] TypeRef=actualtype:73:54
-// CHECK-tokens: Punctuation: "*" [74:40 - 74:41] UnexposedExpr=
-// CHECK-tokens: Punctuation: ")" [74:41 - 74:42] UnexposedExpr=
-// CHECK-tokens: Keyword: "this" [74:43 - 74:47] UnexposedExpr=
-// CHECK-tokens: Punctuation: ")" [74:47 - 74:48] UnexposedExpr=
+// CHECK-tokens: Punctuation: "*" [74:40 - 74:41] CStyleCastExpr=
+// CHECK-tokens: Punctuation: ")" [74:41 - 74:42] CStyleCastExpr=
+// CHECK-tokens: Keyword: "this" [74:43 - 74:47] CXXThisExpr=
+// CHECK-tokens: Punctuation: ")" [74:47 - 74:48] ParenExpr=
// CHECK-tokens: Punctuation: "->" [74:48 - 74:50] MemberRefExpr=second:4:55
// CHECK-tokens: Identifier: "second" [74:50 - 74:56] MemberRefExpr=second:4:55
-// CHECK-tokens: Punctuation: "-" [74:57 - 74:58] UnexposedExpr=
-// CHECK-tokens: Literal: "2" [74:59 - 74:60] UnexposedExpr=
-// CHECK-tokens: Punctuation: ";" [74:60 - 74:61] UnexposedStmt=
-// CHECK-tokens: Keyword: "return" [75:5 - 75:11] UnexposedStmt=
-// CHECK-tokens: Punctuation: "(" [75:12 - 75:13] UnexposedExpr=
-// CHECK-tokens: Punctuation: "(" [75:13 - 75:14] UnexposedExpr=
-// CHECK-tokens: Punctuation: "(" [75:14 - 75:15] UnexposedExpr=
-// CHECK-tokens: Keyword: "unsigned" [75:15 - 75:23] UnexposedExpr=
-// CHECK-tokens: Punctuation: ")" [75:23 - 75:24] UnexposedExpr=
+// CHECK-tokens: Punctuation: "-" [74:57 - 74:58] BinaryOperator=
+// CHECK-tokens: Literal: "2" [74:59 - 74:60] IntegerLiteral=
+// CHECK-tokens: Punctuation: ";" [74:60 - 74:61] DeclStmt=
+// CHECK-tokens: Keyword: "return" [75:5 - 75:11] ReturnStmt=
+// CHECK-tokens: Punctuation: "(" [75:12 - 75:13] ParenExpr=
+// CHECK-tokens: Punctuation: "(" [75:13 - 75:14] ParenExpr=
+// CHECK-tokens: Punctuation: "(" [75:14 - 75:15] CStyleCastExpr=
+// CHECK-tokens: Keyword: "unsigned" [75:15 - 75:23] CStyleCastExpr=
+// CHECK-tokens: Punctuation: ")" [75:23 - 75:24] CStyleCastExpr=
// CHECK-tokens: Identifier: "p" [75:25 - 75:26] DeclRefExpr=p:74:17
-// CHECK-tokens: Punctuation: "[" [75:26 - 75:27] UnexposedExpr=
-// CHECK-tokens: Literal: "0" [75:27 - 75:28] UnexposedExpr=
-// CHECK-tokens: Punctuation: "]" [75:28 - 75:29] UnexposedExpr=
-// CHECK-tokens: Punctuation: ")" [75:29 - 75:30] UnexposedExpr=
-// CHECK-tokens: Punctuation: "|" [75:31 - 75:32] UnexposedExpr=
-// CHECK-tokens: Punctuation: "(" [75:33 - 75:34] UnexposedExpr=
-// CHECK-tokens: Punctuation: "(" [75:34 - 75:35] UnexposedExpr=
-// CHECK-tokens: Punctuation: "(" [75:35 - 75:36] UnexposedExpr=
-// CHECK-tokens: Keyword: "unsigned" [75:36 - 75:44] UnexposedExpr=
-// CHECK-tokens: Punctuation: ")" [75:44 - 75:45] UnexposedExpr=
+// CHECK-tokens: Punctuation: "[" [75:26 - 75:27] ArraySubscriptExpr=
+// CHECK-tokens: Literal: "0" [75:27 - 75:28] IntegerLiteral=
+// CHECK-tokens: Punctuation: "]" [75:28 - 75:29] ArraySubscriptExpr=
+// CHECK-tokens: Punctuation: ")" [75:29 - 75:30] ParenExpr=
+// CHECK-tokens: Punctuation: "|" [75:31 - 75:32] BinaryOperator=
+// CHECK-tokens: Punctuation: "(" [75:33 - 75:34] ParenExpr=
+// CHECK-tokens: Punctuation: "(" [75:34 - 75:35] ParenExpr=
+// CHECK-tokens: Punctuation: "(" [75:35 - 75:36] CStyleCastExpr=
+// CHECK-tokens: Keyword: "unsigned" [75:36 - 75:44] CStyleCastExpr=
+// CHECK-tokens: Punctuation: ")" [75:44 - 75:45] CStyleCastExpr=
// CHECK-tokens: Identifier: "p" [75:46 - 75:47] DeclRefExpr=p:74:17
-// CHECK-tokens: Punctuation: "[" [75:47 - 75:48] UnexposedExpr=
-// CHECK-tokens: Literal: "1" [75:48 - 75:49] UnexposedExpr=
-// CHECK-tokens: Punctuation: "]" [75:49 - 75:50] UnexposedExpr=
-// CHECK-tokens: Punctuation: ")" [75:50 - 75:51] UnexposedExpr=
-// CHECK-tokens: Punctuation: "<<" [75:52 - 75:54] UnexposedExpr=
-// CHECK-tokens: Literal: "8" [75:55 - 75:56] UnexposedExpr=
-// CHECK-tokens: Punctuation: ")" [75:56 - 75:57] UnexposedExpr=
-// CHECK-tokens: Punctuation: ")" [75:57 - 75:58] UnexposedExpr=
-// CHECK-tokens: Punctuation: "-" [75:59 - 75:60] UnexposedExpr=
-// CHECK-tokens: Literal: "1" [75:61 - 75:62] UnexposedExpr=
-// CHECK-tokens: Punctuation: ";" [75:62 - 75:63] UnexposedStmt=
-// CHECK-tokens: Punctuation: "}" [76:3 - 76:4] UnexposedStmt=
+// CHECK-tokens: Punctuation: "[" [75:47 - 75:48] ArraySubscriptExpr=
+// CHECK-tokens: Literal: "1" [75:48 - 75:49] IntegerLiteral=
+// CHECK-tokens: Punctuation: "]" [75:49 - 75:50] ArraySubscriptExpr=
+// CHECK-tokens: Punctuation: ")" [75:50 - 75:51] ParenExpr=
+// CHECK-tokens: Punctuation: "<<" [75:52 - 75:54] BinaryOperator=
+// CHECK-tokens: Literal: "8" [75:55 - 75:56] IntegerLiteral=
+// CHECK-tokens: Punctuation: ")" [75:56 - 75:57] ParenExpr=
+// CHECK-tokens: Punctuation: ")" [75:57 - 75:58] ParenExpr=
+// CHECK-tokens: Punctuation: "-" [75:59 - 75:60] BinaryOperator=
+// CHECK-tokens: Literal: "1" [75:61 - 75:62] IntegerLiteral=
+// CHECK-tokens: Punctuation: ";" [75:62 - 75:63] CompoundStmt=
+// CHECK-tokens: Punctuation: "}" [76:3 - 76:4] CompoundStmt=
// CHECK-tokens: Identifier: "llvm" [77:3 - 77:7] NamespaceRef=llvm:37:11
// CHECK-tokens: Punctuation: "::" [77:7 - 77:9] CXXMethod=getName:77:19 (Definition)
// CHECK-tokens: Identifier: "StringRef" [77:9 - 77:18] TypeRef=class llvm::StringRef:38:7
@@ -778,8 +778,8 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: "(" [77:26 - 77:27] CXXMethod=getName:77:19 (Definition)
// CHECK-tokens: Punctuation: ")" [77:27 - 77:28] CXXMethod=getName:77:19 (Definition)
// CHECK-tokens: Keyword: "const" [77:29 - 77:34] CXXMethod=getName:77:19 (Definition)
-// CHECK-tokens: Punctuation: "{" [77:35 - 77:36] UnexposedStmt=
-// CHECK-tokens: Keyword: "return" [78:5 - 78:11] UnexposedStmt=
+// CHECK-tokens: Punctuation: "{" [77:35 - 77:36] CompoundStmt=
+// CHECK-tokens: Keyword: "return" [78:5 - 78:11] ReturnStmt=
// CHECK-tokens: Identifier: "llvm" [78:12 - 78:16] NamespaceRef=llvm:37:11
// CHECK-tokens: Punctuation: "::" [78:16 - 78:18] CallExpr=StringRef:49:3
// CHECK-tokens: Identifier: "StringRef" [78:18 - 78:27] TypeRef=class llvm::StringRef:38:7
@@ -792,8 +792,8 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: "(" [78:53 - 78:54] CallExpr=getLength:72:12
// CHECK-tokens: Punctuation: ")" [78:54 - 78:55] CallExpr=getLength:72:12
// CHECK-tokens: Punctuation: ")" [78:55 - 78:56] CallExpr=StringRef:49:3
-// CHECK-tokens: Punctuation: ";" [78:56 - 78:57] UnexposedStmt=
-// CHECK-tokens: Punctuation: "}" [79:3 - 79:4] UnexposedStmt=
+// CHECK-tokens: Punctuation: ";" [78:56 - 78:57] CompoundStmt=
+// CHECK-tokens: Punctuation: "}" [79:3 - 79:4] CompoundStmt=
// CHECK-tokens: Punctuation: "}" [80:1 - 80:2] ClassDecl=IdentifierInfo:66:7 (Definition)
// CHECK-tokens: Punctuation: ";" [80:2 - 80:3] Namespace=clang:65:11 (Definition)
// CHECK-tokens: Punctuation: "}" [81:1 - 81:2] Namespace=clang:65:11 (Definition)
@@ -821,8 +821,8 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// 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)
// CHECK-tokens: Punctuation: ";" [85:18 - 85:19] ClassTemplate=StringSwitch:83:47 (Definition)
-// CHECK-tokens: Keyword: "public" [86:1 - 86:7] UnexposedDecl=:86:1 (Definition)
-// CHECK-tokens: Punctuation: ":" [86:7 - 86:8] UnexposedDecl=:86:1 (Definition)
+// CHECK-tokens: Keyword: "public" [86:1 - 86:7] CXXAccessSpecifier=:86:1 (Definition)
+// CHECK-tokens: Punctuation: ":" [86:7 - 86:8] CXXAccessSpecifier=:86:1 (Definition)
// CHECK-tokens: Keyword: "explicit" [87:3 - 87:11] CXXConstructor=StringSwitch<T, R>:87:12 (Definition)
// CHECK-tokens: Identifier: "StringSwitch" [87:12 - 87:24] CXXConstructor=StringSwitch<T, R>:87:12 (Definition)
// CHECK-tokens: Punctuation: "(" [87:24 - 87:25] CXXConstructor=StringSwitch<T, R>:87:12 (Definition)
@@ -837,16 +837,16 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// 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=
-// CHECK-tokens: Literal: "0" [87:59 - 87:60] UnexposedExpr=
+// CHECK-tokens: Literal: "0" [87:59 - 87:60] IntegerLiteral=
// CHECK-tokens: Punctuation: ")" [87:60 - 87:61] UnexposedExpr=
-// CHECK-tokens: Punctuation: "{" [87:62 - 87:63] UnexposedStmt=
-// CHECK-tokens: Punctuation: "}" [87:63 - 87:64] UnexposedStmt=
+// CHECK-tokens: Punctuation: "{" [87:62 - 87:63] CompoundStmt=
+// CHECK-tokens: Punctuation: "}" [87:63 - 87:64] CompoundStmt=
// CHECK-tokens: Keyword: "template" [88:3 - 88:11] FunctionTemplate=Case:88:42 (Definition)
// CHECK-tokens: Punctuation: "<" [88:12 - 88:13] FunctionTemplate=Case:88:42 (Definition)
// CHECK-tokens: Keyword: "unsigned" [88:14 - 88:22] NonTypeTemplateParameter=N:88:23 (Definition)
// CHECK-tokens: Identifier: "N" [88:23 - 88:24] NonTypeTemplateParameter=N:88:23 (Definition)
// CHECK-tokens: Punctuation: ">" [88:25 - 88:26] FunctionTemplate=Case:88:42 (Definition)
-// CHECK-tokens: Identifier: "StringSwitch" [88:27 - 88:39] FunctionTemplate=Case:88:42 (Definition)
+// CHECK-tokens: Identifier: "StringSwitch" [88:27 - 88:39] TypeRef=StringSwitch<T, R>:83:47
// 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)
@@ -865,12 +865,12 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// 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)
// CHECK-tokens: Punctuation: ")" [89:62 - 89:63] FunctionTemplate=Case:88:42 (Definition)
-// CHECK-tokens: Punctuation: "{" [89:64 - 89:65] UnexposedStmt=
-// CHECK-tokens: Keyword: "return" [90:5 - 90:11] UnexposedStmt=
-// CHECK-tokens: Punctuation: "*" [90:12 - 90:13] UnexposedExpr=
-// CHECK-tokens: Keyword: "this" [90:13 - 90:17] UnexposedExpr=
-// CHECK-tokens: Punctuation: ";" [90:17 - 90:18] UnexposedStmt=
-// CHECK-tokens: Punctuation: "}" [91:3 - 91:4] UnexposedStmt=
+// CHECK-tokens: Punctuation: "{" [89:64 - 89:65] CompoundStmt=
+// CHECK-tokens: Keyword: "return" [90:5 - 90:11] ReturnStmt=
+// CHECK-tokens: Punctuation: "*" [90:12 - 90:13] UnaryOperator=
+// CHECK-tokens: Keyword: "this" [90:13 - 90:17] CXXThisExpr=
+// CHECK-tokens: Punctuation: ";" [90:17 - 90:18] CompoundStmt=
+// CHECK-tokens: Punctuation: "}" [91:3 - 91:4] CompoundStmt=
// 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)
@@ -880,11 +880,11 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Identifier: "Value" [92:23 - 92:28] ParmDecl=Value:92:23 (Definition)
// CHECK-tokens: Punctuation: ")" [92:28 - 92:29] CXXMethod=Default:92:5 (Definition)
// CHECK-tokens: Keyword: "const" [92:30 - 92:35] CXXMethod=Default:92:5 (Definition)
-// CHECK-tokens: Punctuation: "{" [92:36 - 92:37] UnexposedStmt=
-// CHECK-tokens: Keyword: "return" [93:5 - 93:11] UnexposedStmt=
+// CHECK-tokens: Punctuation: "{" [92:36 - 92:37] CompoundStmt=
+// CHECK-tokens: Keyword: "return" [93:5 - 93:11] ReturnStmt=
// CHECK-tokens: Identifier: "Value" [93:12 - 93:17] DeclRefExpr=Value:92:23
-// CHECK-tokens: Punctuation: ";" [93:17 - 93:18] UnexposedStmt=
-// CHECK-tokens: Punctuation: "}" [94:3 - 94:4] UnexposedStmt=
+// CHECK-tokens: Punctuation: ";" [93:17 - 93:18] CompoundStmt=
+// CHECK-tokens: Punctuation: "}" [94:3 - 94:4] CompoundStmt=
// CHECK-tokens: Punctuation: "}" [95:1 - 95:2] ClassTemplate=StringSwitch:83:47 (Definition)
// CHECK-tokens: Punctuation: ";" [95:2 - 95:3] Namespace=llvm:82:11 (Definition)
// CHECK-tokens: Punctuation: "}" [96:1 - 96:2] Namespace=llvm:82:11 (Definition)
@@ -904,7 +904,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// 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)
// CHECK-tokens: Punctuation: ")" [100:71 - 100:72] CXXMethod=getKind:100:36 (Definition) (static)
-// CHECK-tokens: Punctuation: "{" [100:73 - 100:74] UnexposedStmt=
+// CHECK-tokens: Punctuation: "{" [100:73 - 100:74] CompoundStmt=
// CHECK-tokens: Identifier: "llvm" [101:3 - 101:7] NamespaceRef=llvm:82:11
// CHECK-tokens: Punctuation: "::" [101:7 - 101:9] VarDecl=AttrName:101:19 (Definition)
// CHECK-tokens: Identifier: "StringRef" [101:9 - 101:18] TypeRef=class llvm::StringRef:38:7
@@ -915,613 +915,613 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Identifier: "getName" [101:36 - 101:43] MemberRefExpr=getName:77:19
// CHECK-tokens: Punctuation: "(" [101:43 - 101:44] CallExpr=getName:77:19
// CHECK-tokens: Punctuation: ")" [101:44 - 101:45] CallExpr=getName:77:19
-// CHECK-tokens: Punctuation: ";" [101:45 - 101:46] UnexposedStmt=
-// CHECK-tokens: Keyword: "if" [102:3 - 102:5] UnexposedStmt=
-// CHECK-tokens: Punctuation: "(" [102:6 - 102:7] UnexposedStmt=
+// CHECK-tokens: Punctuation: ";" [101:45 - 101:46] DeclStmt=
+// CHECK-tokens: Keyword: "if" [102:3 - 102:5] IfStmt=
+// CHECK-tokens: Punctuation: "(" [102:6 - 102:7] IfStmt=
// CHECK-tokens: Identifier: "AttrName" [102:7 - 102:15] DeclRefExpr=AttrName:101:19
// CHECK-tokens: Punctuation: "." [102:15 - 102:16] MemberRefExpr=startswith:52:8
// CHECK-tokens: Identifier: "startswith" [102:16 - 102:26] MemberRefExpr=startswith:52:8
// CHECK-tokens: Punctuation: "(" [102:26 - 102:27] CallExpr=startswith:52:8
-// CHECK-tokens: Literal: ""__"" [102:27 - 102:31] UnexposedExpr=
+// CHECK-tokens: Literal: ""__"" [102:27 - 102:31] StringLiteral=
// CHECK-tokens: Punctuation: ")" [102:31 - 102:32] CallExpr=startswith:52:8
-// CHECK-tokens: Punctuation: "&&" [102:33 - 102:35] UnexposedExpr=
+// CHECK-tokens: Punctuation: "&&" [102:33 - 102:35] BinaryOperator=
// CHECK-tokens: Identifier: "AttrName" [102:36 - 102:44] DeclRefExpr=AttrName:101:19
// CHECK-tokens: Punctuation: "." [102:44 - 102:45] MemberRefExpr=endswith:56:8
// CHECK-tokens: Identifier: "endswith" [102:45 - 102:53] MemberRefExpr=endswith:56:8
// CHECK-tokens: Punctuation: "(" [102:53 - 102:54] CallExpr=endswith:56:8
-// CHECK-tokens: Literal: ""__"" [102:54 - 102:58] UnexposedExpr=
+// CHECK-tokens: Literal: ""__"" [102:54 - 102:58] StringLiteral=
// CHECK-tokens: Punctuation: ")" [102:58 - 102:59] CallExpr=endswith:56:8
-// CHECK-tokens: Punctuation: ")" [102:59 - 102:60] UnexposedStmt=
+// CHECK-tokens: Punctuation: ")" [102:59 - 102:60] IfStmt=
// CHECK-tokens: Identifier: "AttrName" [103:5 - 103:13] DeclRefExpr=AttrName:101:19
// CHECK-tokens: Punctuation: "=" [103:14 - 103:15] CallExpr=operator=:38:7
// CHECK-tokens: Identifier: "AttrName" [103:16 - 103:24] DeclRefExpr=AttrName:101:19
// CHECK-tokens: Punctuation: "." [103:24 - 103:25] MemberRefExpr=substr:60:13
// CHECK-tokens: Identifier: "substr" [103:25 - 103:31] MemberRefExpr=substr:60:13
// CHECK-tokens: Punctuation: "(" [103:31 - 103:32] CallExpr=substr:60:13
-// CHECK-tokens: Literal: "2" [103:32 - 103:33] UnexposedExpr=
+// CHECK-tokens: Literal: "2" [103:32 - 103:33] IntegerLiteral=
// CHECK-tokens: Punctuation: "," [103:33 - 103:34] CallExpr=substr:60:13
// CHECK-tokens: Identifier: "AttrName" [103:35 - 103:43] DeclRefExpr=AttrName:101:19
// CHECK-tokens: Punctuation: "." [103:43 - 103:44] MemberRefExpr=size:51:10
// CHECK-tokens: Identifier: "size" [103:44 - 103:48] MemberRefExpr=size:51:10
// CHECK-tokens: Punctuation: "(" [103:48 - 103:49] CallExpr=size:51:10
// CHECK-tokens: Punctuation: ")" [103:49 - 103:50] CallExpr=size:51:10
-// CHECK-tokens: Punctuation: "-" [103:51 - 103:52] UnexposedExpr=
-// CHECK-tokens: Literal: "4" [103:53 - 103:54] UnexposedExpr=
+// CHECK-tokens: Punctuation: "-" [103:51 - 103:52] BinaryOperator=
+// CHECK-tokens: Literal: "4" [103:53 - 103:54] IntegerLiteral=
// CHECK-tokens: Punctuation: ")" [103:54 - 103:55] CallExpr=substr:60:13
-// CHECK-tokens: Punctuation: ";" [103:55 - 103:56] UnexposedStmt=
-// CHECK-tokens: Keyword: "return" [105:3 - 105:9] UnexposedStmt=
+// CHECK-tokens: Punctuation: ";" [103:55 - 103:56] CompoundStmt=
+// CHECK-tokens: Keyword: "return" [105:3 - 105:9] ReturnStmt=
// FIXME: Missing "llvm" namespace reference below
// CHECK-tokens: Identifier: "llvm" [105:10 - 105:14] NamespaceRef=llvm:82:11
-// CHECK-tokens: Punctuation: "::" [105:14 - 105:16] UnexposedExpr=StringSwitch:87:12
+// CHECK-tokens: Punctuation: "::" [105:14 - 105:16] CXXFunctionalCastExpr=
// CHECK-tokens: Identifier: "StringSwitch" [105:16 - 105:28] TemplateRef=StringSwitch:83:47
-// CHECK-tokens: Punctuation: "<" [105:29 - 105:30] UnexposedExpr=StringSwitch:87:12
+// CHECK-tokens: Punctuation: "<" [105:29 - 105:30] CXXFunctionalCastExpr=
// CHECK-tokens: Identifier: "AttributeList" [105:31 - 105:44] TypeRef=class clang::AttributeList:12:9
-// CHECK-tokens: Punctuation: "::" [105:44 - 105:46] UnexposedExpr=StringSwitch:87:12
+// CHECK-tokens: Punctuation: "::" [105:44 - 105:46] CXXFunctionalCastExpr=
// CHECK-tokens: Identifier: "Kind" [105:46 - 105:50] TypeRef=enum clang::AttributeList::Kind:13:10
// CHECK-tokens: Punctuation: ">" [105:51 - 105:52] CallExpr=StringSwitch:87:12
// CHECK-tokens: Punctuation: "(" [105:53 - 105:54] CallExpr=StringSwitch:87:12
// CHECK-tokens: Identifier: "AttrName" [105:54 - 105:62] DeclRefExpr=AttrName:101:19
-// CHECK-tokens: Punctuation: ")" [105:62 - 105:63] UnexposedExpr=StringSwitch:87:12
+// CHECK-tokens: Punctuation: ")" [105:62 - 105:63] CXXFunctionalCastExpr=
// CHECK-tokens: Punctuation: "." [106:5 - 106:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [106:6 - 106:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [106:10 - 106:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""weak"" [106:11 - 106:17] UnexposedExpr=
+// CHECK-tokens: Literal: ""weak"" [106:11 - 106:17] StringLiteral=
// CHECK-tokens: Punctuation: "," [106:17 - 106:18] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_weak" [106:19 - 106:26] DeclRefExpr=AT_weak:29:45
// CHECK-tokens: Punctuation: ")" [106:26 - 106:27] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [107:5 - 107:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [107:6 - 107:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [107:10 - 107:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""weakref"" [107:11 - 107:20] UnexposedExpr=
+// CHECK-tokens: Literal: ""weakref"" [107:11 - 107:20] StringLiteral=
// CHECK-tokens: Punctuation: "," [107:20 - 107:21] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_weakref" [107:22 - 107:32] DeclRefExpr=AT_weakref:29:54
// CHECK-tokens: Punctuation: ")" [107:32 - 107:33] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [108:5 - 108:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [108:6 - 108:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [108:10 - 108:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""pure"" [108:11 - 108:17] UnexposedExpr=
+// CHECK-tokens: Literal: ""pure"" [108:11 - 108:17] StringLiteral=
// CHECK-tokens: Punctuation: "," [108:17 - 108:18] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_pure" [108:19 - 108:26] DeclRefExpr=AT_pure:26:49
// CHECK-tokens: Punctuation: ")" [108:26 - 108:27] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [109:5 - 109:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [109:6 - 109:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [109:10 - 109:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""mode"" [109:11 - 109:17] UnexposedExpr=
+// CHECK-tokens: Literal: ""mode"" [109:11 - 109:17] StringLiteral=
// CHECK-tokens: Punctuation: "," [109:17 - 109:18] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_mode" [109:19 - 109:26] DeclRefExpr=AT_mode:20:44
// CHECK-tokens: Punctuation: ")" [109:26 - 109:27] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [110:5 - 110:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [110:6 - 110:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [110:10 - 110:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""used"" [110:11 - 110:17] UnexposedExpr=
+// CHECK-tokens: Literal: ""used"" [110:11 - 110:17] StringLiteral=
// CHECK-tokens: Punctuation: "," [110:17 - 110:18] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_used" [110:19 - 110:26] DeclRefExpr=AT_used:28:34
// CHECK-tokens: Punctuation: ")" [110:26 - 110:27] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [111:5 - 111:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [111:6 - 111:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [111:10 - 111:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""alias"" [111:11 - 111:18] UnexposedExpr=
+// CHECK-tokens: Literal: ""alias"" [111:11 - 111:18] StringLiteral=
// CHECK-tokens: Punctuation: "," [111:18 - 111:19] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_alias" [111:20 - 111:28] DeclRefExpr=AT_alias:15:25
// CHECK-tokens: Punctuation: ")" [111:28 - 111:29] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [112:5 - 112:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [112:6 - 112:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [112:10 - 112:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""align"" [112:11 - 112:18] UnexposedExpr=
+// CHECK-tokens: Literal: ""align"" [112:11 - 112:18] StringLiteral=
// CHECK-tokens: Punctuation: "," [112:18 - 112:19] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_aligned" [112:20 - 112:30] DeclRefExpr=AT_aligned:15:35
// CHECK-tokens: Punctuation: ")" [112:30 - 112:31] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [113:5 - 113:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [113:6 - 113:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [113:10 - 113:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""final"" [113:11 - 113:18] UnexposedExpr=
+// CHECK-tokens: Literal: ""final"" [113:11 - 113:18] StringLiteral=
// CHECK-tokens: Punctuation: "," [113:18 - 113:19] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_final" [113:20 - 113:28] DeclRefExpr=AT_final:19:40
// CHECK-tokens: Punctuation: ")" [113:28 - 113:29] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [114:5 - 114:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [114:6 - 114:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [114:10 - 114:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""cdecl"" [114:11 - 114:18] UnexposedExpr=
+// CHECK-tokens: Literal: ""cdecl"" [114:11 - 114:18] StringLiteral=
// CHECK-tokens: Punctuation: "," [114:18 - 114:19] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_cdecl" [114:20 - 114:28] DeclRefExpr=AT_cdecl:17:30
// CHECK-tokens: Punctuation: ")" [114:28 - 114:29] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [115:5 - 115:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [115:6 - 115:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [115:10 - 115:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""const"" [115:11 - 115:18] UnexposedExpr=
+// CHECK-tokens: Literal: ""const"" [115:11 - 115:18] StringLiteral=
// CHECK-tokens: Punctuation: "," [115:18 - 115:19] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_const" [115:20 - 115:28] DeclRefExpr=AT_const:17:52
// CHECK-tokens: Punctuation: ")" [115:28 - 115:29] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [116:5 - 116:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [116:6 - 116:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [116:10 - 116:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""__const"" [116:11 - 116:20] UnexposedExpr=
+// CHECK-tokens: Literal: ""__const"" [116:11 - 116:20] StringLiteral=
// CHECK-tokens: Punctuation: "," [116:20 - 116:21] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_const" [116:22 - 116:30] DeclRefExpr=AT_const:17:52
// CHECK-tokens: Punctuation: ")" [116:30 - 116:31] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [117:5 - 117:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [117:6 - 117:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [117:10 - 117:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""blocks"" [117:11 - 117:19] UnexposedExpr=
+// CHECK-tokens: Literal: ""blocks"" [117:11 - 117:19] StringLiteral=
// CHECK-tokens: Punctuation: "," [117:19 - 117:20] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_blocks" [117:21 - 117:30] DeclRefExpr=AT_blocks:16:57
// CHECK-tokens: Punctuation: ")" [117:30 - 117:31] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [118:5 - 118:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [118:6 - 118:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [118:10 - 118:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""format"" [118:11 - 118:19] UnexposedExpr=
+// CHECK-tokens: Literal: ""format"" [118:11 - 118:19] StringLiteral=
// CHECK-tokens: Punctuation: "," [118:19 - 118:20] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_format" [118:21 - 118:30] DeclRefExpr=AT_format:19:50
// CHECK-tokens: Punctuation: ")" [118:30 - 118:31] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [119:5 - 119:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [119:6 - 119:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [119:10 - 119:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""hiding"" [119:11 - 119:19] UnexposedExpr=
+// CHECK-tokens: Literal: ""hiding"" [119:11 - 119:19] StringLiteral=
// CHECK-tokens: Punctuation: "," [119:19 - 119:20] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_hiding" [119:21 - 119:30] DeclRefExpr=AT_hiding:20:22
// CHECK-tokens: Punctuation: ")" [119:30 - 119:31] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [120:5 - 120:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [120:6 - 120:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [120:10 - 120:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""malloc"" [120:11 - 120:19] UnexposedExpr=
+// CHECK-tokens: Literal: ""malloc"" [120:11 - 120:19] StringLiteral=
// CHECK-tokens: Punctuation: "," [120:19 - 120:20] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_malloc" [120:21 - 120:30] DeclRefExpr=AT_malloc:20:33
// CHECK-tokens: Punctuation: ")" [120:30 - 120:31] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [121:5 - 121:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [121:6 - 121:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [121:10 - 121:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""packed"" [121:11 - 121:19] UnexposedExpr=
+// CHECK-tokens: Literal: ""packed"" [121:11 - 121:19] StringLiteral=
// CHECK-tokens: Punctuation: "," [121:19 - 121:20] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_packed" [121:21 - 121:30] DeclRefExpr=AT_packed:26:27
// CHECK-tokens: Punctuation: ")" [121:30 - 121:31] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [122:5 - 122:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [122:6 - 122:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [122:10 - 122:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""unused"" [122:11 - 122:19] UnexposedExpr=
+// CHECK-tokens: Literal: ""unused"" [122:11 - 122:19] StringLiteral=
// CHECK-tokens: Punctuation: "," [122:19 - 122:20] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_unused" [122:21 - 122:30] DeclRefExpr=AT_unused:28:23
// CHECK-tokens: Punctuation: ")" [122:30 - 122:31] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [123:5 - 123:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [123:6 - 123:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [123:10 - 123:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""aligned"" [123:11 - 123:20] UnexposedExpr=
+// CHECK-tokens: Literal: ""aligned"" [123:11 - 123:20] StringLiteral=
// CHECK-tokens: Punctuation: "," [123:20 - 123:21] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_aligned" [123:22 - 123:32] DeclRefExpr=AT_aligned:15:35
// CHECK-tokens: Punctuation: ")" [123:32 - 123:33] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [124:5 - 124:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [124:6 - 124:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [124:10 - 124:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""cleanup"" [124:11 - 124:20] UnexposedExpr=
+// CHECK-tokens: Literal: ""cleanup"" [124:11 - 124:20] StringLiteral=
// CHECK-tokens: Punctuation: "," [124:20 - 124:21] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_cleanup" [124:22 - 124:32] DeclRefExpr=AT_cleanup:17:40
// CHECK-tokens: Punctuation: ")" [124:32 - 124:33] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [125:5 - 125:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [125:6 - 125:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [125:10 - 125:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""naked"" [125:11 - 125:18] UnexposedExpr=
+// CHECK-tokens: Literal: ""naked"" [125:11 - 125:18] StringLiteral=
// CHECK-tokens: Punctuation: "," [125:18 - 125:19] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_naked" [125:20 - 125:28] DeclRefExpr=AT_naked:20:53
// CHECK-tokens: Punctuation: ")" [125:28 - 125:29] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [126:5 - 126:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [126:6 - 126:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [126:10 - 126:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""nodebug"" [126:11 - 126:20] UnexposedExpr=
+// CHECK-tokens: Literal: ""nodebug"" [126:11 - 126:20] StringLiteral=
// CHECK-tokens: Punctuation: "," [126:20 - 126:21] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_nodebug" [126:22 - 126:32] DeclRefExpr=AT_nodebug:20:63
// CHECK-tokens: Punctuation: ")" [126:32 - 126:33] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [127:5 - 127:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [127:6 - 127:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [127:10 - 127:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""nonnull"" [127:11 - 127:20] UnexposedExpr=
+// CHECK-tokens: Literal: ""nonnull"" [127:11 - 127:20] StringLiteral=
// CHECK-tokens: Punctuation: "," [127:20 - 127:21] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_nonnull" [127:22 - 127:32] DeclRefExpr=AT_nonnull:21:47
// CHECK-tokens: Punctuation: ")" [127:32 - 127:33] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [128:5 - 128:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [128:6 - 128:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [128:10 - 128:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""nothrow"" [128:11 - 128:20] UnexposedExpr=
+// CHECK-tokens: Literal: ""nothrow"" [128:11 - 128:20] StringLiteral=
// CHECK-tokens: Punctuation: "," [128:20 - 128:21] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_nothrow" [128:22 - 128:32] DeclRefExpr=AT_nothrow:22:7
// CHECK-tokens: Punctuation: ")" [128:32 - 128:33] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [129:5 - 129:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [129:6 - 129:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [129:10 - 129:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""objc_gc"" [129:11 - 129:20] UnexposedExpr=
+// CHECK-tokens: Literal: ""objc_gc"" [129:11 - 129:20] StringLiteral=
// CHECK-tokens: Punctuation: "," [129:20 - 129:21] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_objc_gc" [129:22 - 129:32] DeclRefExpr=AT_objc_gc:24:59
// CHECK-tokens: Punctuation: ")" [129:32 - 129:33] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [130:5 - 130:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [130:6 - 130:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [130:10 - 130:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""regparm"" [130:11 - 130:20] UnexposedExpr=
+// CHECK-tokens: Literal: ""regparm"" [130:11 - 130:20] StringLiteral=
// CHECK-tokens: Punctuation: "," [130:20 - 130:21] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_regparm" [130:22 - 130:32] DeclRefExpr=AT_regparm:26:58
// CHECK-tokens: Punctuation: ")" [130:32 - 130:33] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [131:5 - 131:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [131:6 - 131:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [131:10 - 131:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""section"" [131:11 - 131:20] UnexposedExpr=
+// CHECK-tokens: Literal: ""section"" [131:11 - 131:20] StringLiteral=
// CHECK-tokens: Punctuation: "," [131:20 - 131:21] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_section" [131:22 - 131:32] DeclRefExpr=AT_section:27:7
// CHECK-tokens: Punctuation: ")" [131:32 - 131:33] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [132:5 - 132:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [132:6 - 132:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [132:10 - 132:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""stdcall"" [132:11 - 132:20] UnexposedExpr=
+// CHECK-tokens: Literal: ""stdcall"" [132:11 - 132:20] StringLiteral=
// CHECK-tokens: Punctuation: "," [132:20 - 132:21] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_stdcall" [132:22 - 132:32] DeclRefExpr=AT_stdcall:27:32
// CHECK-tokens: Punctuation: ")" [132:32 - 132:33] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [133:5 - 133:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [133:6 - 133:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [133:10 - 133:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""annotate"" [133:11 - 133:21] UnexposedExpr=
+// CHECK-tokens: Literal: ""annotate"" [133:11 - 133:21] StringLiteral=
// CHECK-tokens: Punctuation: "," [133:21 - 133:22] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_annotate" [133:23 - 133:34] DeclRefExpr=AT_annotate:16:29
// CHECK-tokens: Punctuation: ")" [133:34 - 133:35] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [134:5 - 134:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [134:6 - 134:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [134:10 - 134:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""fastcall"" [134:11 - 134:21] UnexposedExpr=
+// CHECK-tokens: Literal: ""fastcall"" [134:11 - 134:21] StringLiteral=
// CHECK-tokens: Punctuation: "," [134:21 - 134:22] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_fastcall" [134:23 - 134:34] DeclRefExpr=AT_fastcall:19:27
// CHECK-tokens: Punctuation: ")" [134:34 - 134:35] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [135:5 - 135:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [135:6 - 135:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [135:10 - 135:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""ibaction"" [135:11 - 135:21] UnexposedExpr=
+// CHECK-tokens: Literal: ""ibaction"" [135:11 - 135:21] StringLiteral=
// CHECK-tokens: Punctuation: "," [135:21 - 135:22] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_IBAction" [135:23 - 135:34] DeclRefExpr=AT_IBAction:14:7
// CHECK-tokens: Punctuation: ")" [135:34 - 135:35] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [136:5 - 136:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [136:6 - 136:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [136:10 - 136:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""iboutlet"" [136:11 - 136:21] UnexposedExpr=
+// CHECK-tokens: Literal: ""iboutlet"" [136:11 - 136:21] StringLiteral=
// CHECK-tokens: Punctuation: "," [136:21 - 136:22] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_IBOutlet" [136:23 - 136:34] DeclRefExpr=AT_IBOutlet:14:20
// CHECK-tokens: Punctuation: ")" [136:34 - 136:35] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [137:5 - 137:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [137:6 - 137:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [137:10 - 137:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""iboutletcollection"" [137:11 - 137:31] UnexposedExpr=
+// CHECK-tokens: Literal: ""iboutletcollection"" [137:11 - 137:31] StringLiteral=
// CHECK-tokens: Punctuation: "," [137:31 - 137:32] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_IBOutletCollection" [137:33 - 137:54] DeclRefExpr=AT_IBOutletCollection:14:33
// CHECK-tokens: Punctuation: ")" [137:54 - 137:55] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [138:5 - 138:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [138:6 - 138:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [138:10 - 138:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""noreturn"" [138:11 - 138:21] UnexposedExpr=
+// CHECK-tokens: Literal: ""noreturn"" [138:11 - 138:21] StringLiteral=
// CHECK-tokens: Punctuation: "," [138:21 - 138:22] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_noreturn" [138:23 - 138:34] DeclRefExpr=AT_noreturn:21:59
// CHECK-tokens: Punctuation: ")" [138:34 - 138:35] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [139:5 - 139:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [139:6 - 139:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [139:10 - 139:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""noinline"" [139:11 - 139:21] UnexposedExpr=
+// CHECK-tokens: Literal: ""noinline"" [139:11 - 139:21] StringLiteral=
// CHECK-tokens: Punctuation: "," [139:21 - 139:22] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_noinline" [139:23 - 139:34] DeclRefExpr=AT_noinline:21:7
// CHECK-tokens: Punctuation: ")" [139:34 - 139:35] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [140:5 - 140:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [140:6 - 140:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [140:10 - 140:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""override"" [140:11 - 140:21] UnexposedExpr=
+// CHECK-tokens: Literal: ""override"" [140:11 - 140:21] StringLiteral=
// CHECK-tokens: Punctuation: "," [140:21 - 140:22] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_override" [140:23 - 140:34] DeclRefExpr=AT_override:22:51
// CHECK-tokens: Punctuation: ")" [140:34 - 140:35] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [141:5 - 141:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [141:6 - 141:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [141:10 - 141:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""sentinel"" [141:11 - 141:21] UnexposedExpr=
+// CHECK-tokens: Literal: ""sentinel"" [141:11 - 141:21] StringLiteral=
// CHECK-tokens: Punctuation: "," [141:21 - 141:22] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_sentinel" [141:23 - 141:34] DeclRefExpr=AT_sentinel:27:19
// CHECK-tokens: Punctuation: ")" [141:34 - 141:35] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [142:5 - 142:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [142:6 - 142:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [142:10 - 142:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""NSObject"" [142:11 - 142:21] UnexposedExpr=
+// CHECK-tokens: Literal: ""NSObject"" [142:11 - 142:21] StringLiteral=
// CHECK-tokens: Punctuation: "," [142:21 - 142:22] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_nsobject" [142:23 - 142:34] DeclRefExpr=AT_nsobject:22:19
// CHECK-tokens: Punctuation: ")" [142:34 - 142:35] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [143:5 - 143:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [143:6 - 143:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [143:10 - 143:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""dllimport"" [143:11 - 143:22] UnexposedExpr=
+// CHECK-tokens: Literal: ""dllimport"" [143:11 - 143:22] StringLiteral=
// CHECK-tokens: Punctuation: "," [143:22 - 143:23] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_dllimport" [143:24 - 143:36] DeclRefExpr=AT_dllimport:18:51
// CHECK-tokens: Punctuation: ")" [143:36 - 143:37] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [144:5 - 144:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [144:6 - 144:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [144:10 - 144:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""dllexport"" [144:11 - 144:22] UnexposedExpr=
+// CHECK-tokens: Literal: ""dllexport"" [144:11 - 144:22] StringLiteral=
// CHECK-tokens: Punctuation: "," [144:22 - 144:23] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_dllexport" [144:24 - 144:36] DeclRefExpr=AT_dllexport:18:37
// CHECK-tokens: Punctuation: ")" [144:36 - 144:37] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [145:5 - 145:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [145:6 - 145:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [145:10 - 145:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""may_alias"" [145:11 - 145:22] UnexposedExpr=
+// CHECK-tokens: Literal: ""may_alias"" [145:11 - 145:22] StringLiteral=
// CHECK-tokens: Punctuation: "," [145:22 - 145:23] CallExpr=Case:88:42
-// CHECK-tokens: Identifier: "IgnoredAttribute" [145:24 - 145:40] DeclRefExpr=IgnoredAttribute:31:7
+// CHECK-tokens: Identifier: "IgnoredAttribute" [145:24 - 145:40] DeclRefExpr=IgnoredAttribute:31:25
// CHECK-tokens: Punctuation: ")" [145:40 - 145:41] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [146:5 - 146:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [146:6 - 146:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [146:10 - 146:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""base_check"" [146:11 - 146:23] UnexposedExpr=
+// CHECK-tokens: Literal: ""base_check"" [146:11 - 146:23] StringLiteral=
// CHECK-tokens: Punctuation: "," [146:23 - 146:24] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_base_check" [146:25 - 146:38] DeclRefExpr=AT_base_check:16:42
// CHECK-tokens: Punctuation: ")" [146:38 - 146:39] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [147:5 - 147:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [147:6 - 147:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [147:10 - 147:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""deprecated"" [147:11 - 147:23] UnexposedExpr=
+// CHECK-tokens: Literal: ""deprecated"" [147:11 - 147:23] StringLiteral=
// CHECK-tokens: Punctuation: "," [147:23 - 147:24] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_deprecated" [147:25 - 147:38] DeclRefExpr=AT_deprecated:18:7
// CHECK-tokens: Punctuation: ")" [147:38 - 147:39] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [148:5 - 148:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [148:6 - 148:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [148:10 - 148:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""visibility"" [148:11 - 148:23] UnexposedExpr=
+// CHECK-tokens: Literal: ""visibility"" [148:11 - 148:23] StringLiteral=
// CHECK-tokens: Punctuation: "," [148:23 - 148:24] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_visibility" [148:25 - 148:38] DeclRefExpr=AT_visibility:29:7
// CHECK-tokens: Punctuation: ")" [148:38 - 148:39] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [149:5 - 149:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [149:6 - 149:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [149:10 - 149:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""destructor"" [149:11 - 149:23] UnexposedExpr=
+// CHECK-tokens: Literal: ""destructor"" [149:11 - 149:23] StringLiteral=
// CHECK-tokens: Punctuation: "," [149:23 - 149:24] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_destructor" [149:25 - 149:38] DeclRefExpr=AT_destructor:18:22
// CHECK-tokens: Punctuation: ")" [149:38 - 149:39] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [150:5 - 150:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [150:6 - 150:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [150:10 - 150:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""format_arg"" [150:11 - 150:23] UnexposedExpr=
+// CHECK-tokens: Literal: ""format_arg"" [150:11 - 150:23] StringLiteral=
// CHECK-tokens: Punctuation: "," [150:23 - 150:24] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_format_arg" [150:25 - 150:38] DeclRefExpr=AT_format_arg:19:61
// CHECK-tokens: Punctuation: ")" [150:38 - 150:39] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [151:5 - 151:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [151:6 - 151:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [151:10 - 151:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""gnu_inline"" [151:11 - 151:23] UnexposedExpr=
+// CHECK-tokens: Literal: ""gnu_inline"" [151:11 - 151:23] StringLiteral=
// CHECK-tokens: Punctuation: "," [151:23 - 151:24] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_gnu_inline" [151:25 - 151:38] DeclRefExpr=AT_gnu_inline:20:7
// CHECK-tokens: Punctuation: ")" [151:38 - 151:39] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [152:5 - 152:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [152:6 - 152:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [152:10 - 152:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""weak_import"" [152:11 - 152:24] UnexposedExpr=
+// CHECK-tokens: Literal: ""weak_import"" [152:11 - 152:24] StringLiteral=
// CHECK-tokens: Punctuation: "," [152:24 - 152:25] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_weak_import" [152:26 - 152:40] DeclRefExpr=AT_weak_import:30:7
// CHECK-tokens: Punctuation: ")" [152:40 - 152:41] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [153:5 - 153:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [153:6 - 153:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [153:10 - 153:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""vecreturn"" [153:11 - 153:22] UnexposedExpr=
+// CHECK-tokens: Literal: ""vecreturn"" [153:11 - 153:22] StringLiteral=
// CHECK-tokens: Punctuation: "," [153:22 - 153:23] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_vecreturn" [153:24 - 153:36] DeclRefExpr=AT_vecreturn:28:43
// CHECK-tokens: Punctuation: ")" [153:36 - 153:37] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [154:5 - 154:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [154:6 - 154:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [154:10 - 154:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""vector_size"" [154:11 - 154:24] UnexposedExpr=
+// CHECK-tokens: Literal: ""vector_size"" [154:11 - 154:24] StringLiteral=
// CHECK-tokens: Punctuation: "," [154:24 - 154:25] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_vector_size" [154:26 - 154:40] DeclRefExpr=AT_vector_size:28:57
// CHECK-tokens: Punctuation: ")" [154:40 - 154:41] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [155:5 - 155:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [155:6 - 155:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [155:10 - 155:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""constructor"" [155:11 - 155:24] UnexposedExpr=
+// CHECK-tokens: Literal: ""constructor"" [155:11 - 155:24] StringLiteral=
// CHECK-tokens: Punctuation: "," [155:24 - 155:25] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_constructor" [155:26 - 155:40] DeclRefExpr=AT_constructor:17:62
// CHECK-tokens: Punctuation: ")" [155:40 - 155:41] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [156:5 - 156:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [156:6 - 156:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [156:10 - 156:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""unavailable"" [156:11 - 156:24] UnexposedExpr=
+// CHECK-tokens: Literal: ""unavailable"" [156:11 - 156:24] StringLiteral=
// CHECK-tokens: Punctuation: "," [156:24 - 156:25] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_unavailable" [156:26 - 156:40] DeclRefExpr=AT_unavailable:28:7
// CHECK-tokens: Punctuation: ")" [156:40 - 156:41] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [157:5 - 157:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [157:6 - 157:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [157:10 - 157:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""overloadable"" [157:11 - 157:25] UnexposedExpr=
+// CHECK-tokens: Literal: ""overloadable"" [157:11 - 157:25] StringLiteral=
// CHECK-tokens: Punctuation: "," [157:25 - 157:26] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_overloadable" [157:27 - 157:42] DeclRefExpr=AT_overloadable:25:7
// CHECK-tokens: Punctuation: ")" [157:42 - 157:43] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [158:5 - 158:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [158:6 - 158:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [158:10 - 158:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""address_space"" [158:11 - 158:26] UnexposedExpr=
+// CHECK-tokens: Literal: ""address_space"" [158:11 - 158:26] StringLiteral=
// CHECK-tokens: Punctuation: "," [158:26 - 158:27] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_address_space" [158:28 - 158:44] DeclRefExpr=AT_address_space:15:7
// CHECK-tokens: Punctuation: ")" [158:44 - 158:45] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [159:5 - 159:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [159:6 - 159:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [159:10 - 159:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""always_inline"" [159:11 - 159:26] UnexposedExpr=
+// CHECK-tokens: Literal: ""always_inline"" [159:11 - 159:26] StringLiteral=
// CHECK-tokens: Punctuation: "," [159:26 - 159:27] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_always_inline" [159:28 - 159:44] DeclRefExpr=AT_always_inline:15:47
// CHECK-tokens: Punctuation: ")" [159:44 - 159:45] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [160:5 - 160:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [160:6 - 160:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [160:10 - 160:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""returns_twice"" [160:11 - 160:26] UnexposedExpr=
+// CHECK-tokens: Literal: ""returns_twice"" [160:11 - 160:26] StringLiteral=
// CHECK-tokens: Punctuation: "," [160:26 - 160:27] CallExpr=Case:88:42
-// CHECK-tokens: Identifier: "IgnoredAttribute" [160:28 - 160:44] DeclRefExpr=IgnoredAttribute:31:7
+// CHECK-tokens: Identifier: "AT_returns_twice" [160:28 - 160:44] DeclRefExpr=AT_returns_twice:31:7
// CHECK-tokens: Punctuation: ")" [160:44 - 160:45] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [161:5 - 161:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [161:6 - 161:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [161:10 - 161:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""vec_type_hint"" [161:11 - 161:26] UnexposedExpr=
+// CHECK-tokens: Literal: ""vec_type_hint"" [161:11 - 161:26] StringLiteral=
// CHECK-tokens: Punctuation: "," [161:26 - 161:27] CallExpr=Case:88:42
-// CHECK-tokens: Identifier: "IgnoredAttribute" [161:28 - 161:44] DeclRefExpr=IgnoredAttribute:31:7
+// CHECK-tokens: Identifier: "IgnoredAttribute" [161:28 - 161:44] DeclRefExpr=IgnoredAttribute:31:25
// CHECK-tokens: Punctuation: ")" [161:44 - 161:45] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [162:5 - 162:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [162:6 - 162:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [162:10 - 162:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""objc_exception"" [162:11 - 162:27] UnexposedExpr=
+// CHECK-tokens: Literal: ""objc_exception"" [162:11 - 162:27] StringLiteral=
// CHECK-tokens: Punctuation: "," [162:27 - 162:28] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_objc_exception" [162:29 - 162:46] DeclRefExpr=AT_objc_exception:22:32
// CHECK-tokens: Punctuation: ")" [162:46 - 162:47] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [163:5 - 163:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [163:6 - 163:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [163:10 - 163:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""ext_vector_type"" [163:11 - 163:28] UnexposedExpr=
+// CHECK-tokens: Literal: ""ext_vector_type"" [163:11 - 163:28] StringLiteral=
// CHECK-tokens: Punctuation: "," [163:28 - 163:29] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_ext_vector_type" [163:30 - 163:48] DeclRefExpr=AT_ext_vector_type:19:7
// CHECK-tokens: Punctuation: ")" [163:48 - 163:49] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [164:5 - 164:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [164:6 - 164:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [164:10 - 164:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""transparent_union"" [164:11 - 164:30] UnexposedExpr=
+// CHECK-tokens: Literal: ""transparent_union"" [164:11 - 164:30] StringLiteral=
// CHECK-tokens: Punctuation: "," [164:30 - 164:31] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_transparent_union" [164:32 - 164:52] DeclRefExpr=AT_transparent_union:27:57
// CHECK-tokens: Punctuation: ")" [164:52 - 164:53] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [165:5 - 165:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [165:6 - 165:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [165:10 - 165:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""analyzer_noreturn"" [165:11 - 165:30] UnexposedExpr=
+// CHECK-tokens: Literal: ""analyzer_noreturn"" [165:11 - 165:30] StringLiteral=
// CHECK-tokens: Punctuation: "," [165:30 - 165:31] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_analyzer_noreturn" [165:32 - 165:52] DeclRefExpr=AT_analyzer_noreturn:16:7
// CHECK-tokens: Punctuation: ")" [165:52 - 165:53] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [166:5 - 166:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [166:6 - 166:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [166:10 - 166:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""warn_unused_result"" [166:11 - 166:31] UnexposedExpr=
+// CHECK-tokens: Literal: ""warn_unused_result"" [166:11 - 166:31] StringLiteral=
// CHECK-tokens: Punctuation: "," [166:31 - 166:32] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_warn_unused_result" [166:33 - 166:54] DeclRefExpr=AT_warn_unused_result:29:22
// CHECK-tokens: Punctuation: ")" [166:54 - 166:55] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [167:5 - 167:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [167:6 - 167:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [167:10 - 167:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""carries_dependency"" [167:11 - 167:31] UnexposedExpr=
+// CHECK-tokens: Literal: ""carries_dependency"" [167:11 - 167:31] StringLiteral=
// CHECK-tokens: Punctuation: "," [167:31 - 167:32] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_carries_dependency" [167:33 - 167:54] DeclRefExpr=AT_carries_dependency:17:7
// CHECK-tokens: Punctuation: ")" [167:54 - 167:55] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [168:5 - 168:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [168:6 - 168:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [168:10 - 168:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""ns_returns_not_retained"" [168:11 - 168:36] UnexposedExpr=
+// CHECK-tokens: Literal: ""ns_returns_not_retained"" [168:11 - 168:36] StringLiteral=
// CHECK-tokens: Punctuation: "," [168:36 - 168:37] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_ns_returns_not_retained" [168:38 - 168:64] DeclRefExpr=AT_ns_returns_not_retained:24:7
// CHECK-tokens: Punctuation: ")" [168:64 - 168:65] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [169:5 - 169:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [169:6 - 169:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [169:10 - 169:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""ns_returns_retained"" [169:11 - 169:32] UnexposedExpr=
+// CHECK-tokens: Literal: ""ns_returns_retained"" [169:11 - 169:32] StringLiteral=
// CHECK-tokens: Punctuation: "," [169:32 - 169:33] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_ns_returns_retained" [169:34 - 169:56] DeclRefExpr=AT_ns_returns_retained:24:35
// CHECK-tokens: Punctuation: ")" [169:56 - 169:57] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [170:5 - 170:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [170:6 - 170:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [170:10 - 170:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""cf_returns_not_retained"" [170:11 - 170:36] UnexposedExpr=
+// CHECK-tokens: Literal: ""cf_returns_not_retained"" [170:11 - 170:36] StringLiteral=
// CHECK-tokens: Punctuation: "," [170:36 - 170:37] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_cf_returns_not_retained" [170:38 - 170:64] DeclRefExpr=AT_cf_returns_not_retained:23:7
// CHECK-tokens: Punctuation: ")" [170:64 - 170:65] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [171:5 - 171:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [171:6 - 171:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [171:10 - 171:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""cf_returns_retained"" [171:11 - 171:32] UnexposedExpr=
+// CHECK-tokens: Literal: ""cf_returns_retained"" [171:11 - 171:32] StringLiteral=
// CHECK-tokens: Punctuation: "," [171:32 - 171:33] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_cf_returns_retained" [171:34 - 171:56] DeclRefExpr=AT_cf_returns_retained:23:35
// CHECK-tokens: Punctuation: ")" [171:56 - 171:57] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [172:5 - 172:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [172:6 - 172:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [172:10 - 172:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""ownership_returns"" [172:11 - 172:30] UnexposedExpr=
+// CHECK-tokens: Literal: ""ownership_returns"" [172:11 - 172:30] StringLiteral=
// CHECK-tokens: Punctuation: "," [172:30 - 172:31] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_ownership_returns" [172:32 - 172:52] DeclRefExpr=AT_ownership_returns:25:44
// CHECK-tokens: Punctuation: ")" [172:52 - 172:53] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [173:5 - 173:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [173:6 - 173:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [173:10 - 173:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""ownership_holds"" [173:11 - 173:28] UnexposedExpr=
+// CHECK-tokens: Literal: ""ownership_holds"" [173:11 - 173:28] StringLiteral=
// CHECK-tokens: Punctuation: "," [173:28 - 173:29] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_ownership_holds" [173:30 - 173:48] DeclRefExpr=AT_ownership_holds:25:24
// CHECK-tokens: Punctuation: ")" [173:48 - 173:49] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [174:5 - 174:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [174:6 - 174:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [174:10 - 174:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""ownership_takes"" [174:11 - 174:28] UnexposedExpr=
+// CHECK-tokens: Literal: ""ownership_takes"" [174:11 - 174:28] StringLiteral=
// CHECK-tokens: Punctuation: "," [174:28 - 174:29] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_ownership_takes" [174:30 - 174:48] DeclRefExpr=AT_ownership_takes:26:7
// CHECK-tokens: Punctuation: ")" [174:48 - 174:49] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [175:5 - 175:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [175:6 - 175:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [175:10 - 175:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""reqd_work_group_size"" [175:11 - 175:33] UnexposedExpr=
+// CHECK-tokens: Literal: ""reqd_work_group_size"" [175:11 - 175:33] StringLiteral=
// CHECK-tokens: Punctuation: "," [175:33 - 175:34] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_reqd_wg_size" [175:35 - 175:50] DeclRefExpr=AT_reqd_wg_size:30:23
// CHECK-tokens: Punctuation: ")" [175:50 - 175:51] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [176:5 - 176:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [176:6 - 176:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [176:10 - 176:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""init_priority"" [176:11 - 176:26] UnexposedExpr=
+// CHECK-tokens: Literal: ""init_priority"" [176:11 - 176:26] StringLiteral=
// CHECK-tokens: Punctuation: "," [176:26 - 176:27] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_init_priority" [176:28 - 176:44] DeclRefExpr=AT_init_priority:30:40
// CHECK-tokens: Punctuation: ")" [176:44 - 176:45] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [177:5 - 177:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [177:6 - 177:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [177:10 - 177:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""no_instrument_function"" [177:11 - 177:35] UnexposedExpr=
+// CHECK-tokens: Literal: ""no_instrument_function"" [177:11 - 177:35] StringLiteral=
// CHECK-tokens: Punctuation: "," [177:35 - 177:36] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_no_instrument_function" [177:37 - 177:62] DeclRefExpr=AT_no_instrument_function:21:20
// CHECK-tokens: Punctuation: ")" [177:62 - 177:63] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [178:5 - 178:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [178:6 - 178:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [178:10 - 178:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""thiscall"" [178:11 - 178:21] UnexposedExpr=
+// CHECK-tokens: Literal: ""thiscall"" [178:11 - 178:21] StringLiteral=
// CHECK-tokens: Punctuation: "," [178:21 - 178:22] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_thiscall" [178:23 - 178:34] DeclRefExpr=AT_thiscall:27:44
// CHECK-tokens: Punctuation: ")" [178:34 - 178:35] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [179:5 - 179:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [179:6 - 179:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [179:10 - 179:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""pascal"" [179:11 - 179:19] UnexposedExpr=
+// CHECK-tokens: Literal: ""pascal"" [179:11 - 179:19] StringLiteral=
// CHECK-tokens: Punctuation: "," [179:19 - 179:20] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_pascal" [179:21 - 179:30] DeclRefExpr=AT_pascal:26:38
// CHECK-tokens: Punctuation: ")" [179:30 - 179:31] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [180:5 - 180:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [180:6 - 180:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [180:10 - 180:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""__cdecl"" [180:11 - 180:20] UnexposedExpr=
+// CHECK-tokens: Literal: ""__cdecl"" [180:11 - 180:20] StringLiteral=
// CHECK-tokens: Punctuation: "," [180:20 - 180:21] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_cdecl" [180:22 - 180:30] DeclRefExpr=AT_cdecl:17:30
// CHECK-tokens: Punctuation: ")" [180:30 - 180:31] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [181:5 - 181:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [181:6 - 181:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [181:10 - 181:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""__stdcall"" [181:11 - 181:22] UnexposedExpr=
+// CHECK-tokens: Literal: ""__stdcall"" [181:11 - 181:22] StringLiteral=
// CHECK-tokens: Punctuation: "," [181:22 - 181:23] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_stdcall" [181:24 - 181:34] DeclRefExpr=AT_stdcall:27:32
// CHECK-tokens: Punctuation: ")" [181:34 - 181:35] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [182:5 - 182:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [182:6 - 182:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [182:10 - 182:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""__fastcall"" [182:11 - 182:23] UnexposedExpr=
+// CHECK-tokens: Literal: ""__fastcall"" [182:11 - 182:23] StringLiteral=
// CHECK-tokens: Punctuation: "," [182:23 - 182:24] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_fastcall" [182:25 - 182:36] DeclRefExpr=AT_fastcall:19:27
// CHECK-tokens: Punctuation: ")" [182:36 - 182:37] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [183:5 - 183:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [183:6 - 183:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [183:10 - 183:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""__thiscall"" [183:11 - 183:23] UnexposedExpr=
+// CHECK-tokens: Literal: ""__thiscall"" [183:11 - 183:23] StringLiteral=
// CHECK-tokens: Punctuation: "," [183:23 - 183:24] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_thiscall" [183:25 - 183:36] DeclRefExpr=AT_thiscall:27:44
// CHECK-tokens: Punctuation: ")" [183:36 - 183:37] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [184:5 - 184:6] MemberRefExpr=Case:88:42
// CHECK-tokens: Identifier: "Case" [184:6 - 184:10] MemberRefExpr=Case:88:42
// CHECK-tokens: Punctuation: "(" [184:10 - 184:11] CallExpr=Case:88:42
-// CHECK-tokens: Literal: ""__pascal"" [184:11 - 184:21] UnexposedExpr=
+// CHECK-tokens: Literal: ""__pascal"" [184:11 - 184:21] StringLiteral=
// CHECK-tokens: Punctuation: "," [184:21 - 184:22] CallExpr=Case:88:42
// CHECK-tokens: Identifier: "AT_pascal" [184:23 - 184:32] DeclRefExpr=AT_pascal:26:38
// CHECK-tokens: Punctuation: ")" [184:32 - 184:33] CallExpr=Case:88:42
// CHECK-tokens: Punctuation: "." [185:5 - 185:6] MemberRefExpr=Default:92:5
// CHECK-tokens: Identifier: "Default" [185:6 - 185:13] MemberRefExpr=Default:92:5
// CHECK-tokens: Punctuation: "(" [185:13 - 185:14] CallExpr=Default:92:5
-// CHECK-tokens: Identifier: "UnknownAttribute" [185:14 - 185:30] DeclRefExpr=UnknownAttribute:31:25
+// CHECK-tokens: Identifier: "UnknownAttribute" [185:14 - 185:30] DeclRefExpr=UnknownAttribute:31:43
// CHECK-tokens: Punctuation: ")" [185:30 - 185:31] CallExpr=Default:92:5
-// CHECK-tokens: Punctuation: ";" [185:31 - 185:32] UnexposedStmt=
-// CHECK-tokens: Punctuation: "}" [186:1 - 186:2] UnexposedStmt=
+// CHECK-tokens: Punctuation: ";" [185:31 - 185:32] CompoundStmt=
+// CHECK-tokens: Punctuation: "}" [186:1 - 186:2] CompoundStmt=
// RUN: c-index-test -test-load-source all %s 2>&1 | FileCheck %s
// CHECK: 1:27: TypedefDecl=__darwin_size_t:1:27 (Definition) Extent=[1:1 - 1:42]
@@ -1614,8 +1614,8 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 30:7: EnumConstantDecl=AT_weak_import:30:7 (Definition) Extent=[30:7 - 30:21]
// CHECK: 30:23: EnumConstantDecl=AT_reqd_wg_size:30:23 (Definition) Extent=[30:23 - 30:38]
// CHECK: 30:40: EnumConstantDecl=AT_init_priority:30:40 (Definition) Extent=[30:40 - 30:56]
-// CHECK: 31:7: EnumConstantDecl=IgnoredAttribute:31:7 (Definition) Extent=[31:7 - 31:23]
-// CHECK: 31:25: EnumConstantDecl=UnknownAttribute:31:25 (Definition) Extent=[31:25 - 31:41]
+// CHECK: 31:7: EnumConstantDecl=AT_returns_twice:31:7 (Definition) Extent=[31:7 - 31:23]
+// CHECK: 31:25: EnumConstantDecl=IgnoredAttribute:31:25 (Definition) Extent=[31:25 - 31:41]
// CHECK: 33:17: CXXMethod=getKind:33:17 (static) Extent=[33:5 - 33:53]
// CHECK: 33:12: TypeRef=enum clang::AttributeList::Kind:13:10 Extent=[33:12 - 33:16]
// CHECK: 33:48: ParmDecl=Name:33:48 (Definition) Extent=[33:25 - 33:52]
@@ -1625,16 +1625,16 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 36:33: ParmDecl=s:36:33 (Definition) Extent=[36:21 - 36:34]
// CHECK: 37:11: Namespace=llvm:37:11 (Definition) Extent=[37:1 - 64:2]
// CHECK: 38:7: ClassDecl=StringRef:38:7 (Definition) Extent=[38:1 - 63:2]
-// CHECK: 39:1: UnexposedDecl=:39:1 (Definition) Extent=[39:1 - 39:8]
+// CHECK: 39:1: CXXAccessSpecifier=:39:1 (Definition) Extent=[39:1 - 39:8]
// CHECK: 40:23: TypedefDecl=iterator:40:23 (Definition) Extent=[40:3 - 40:31]
// CHECK: 41:23: VarDecl=npos:41:23 Extent=[41:3 - 41:40]
// CHECK: 41:16: TypeRef=size_t:2:25 Extent=[41:16 - 41:22]
-// CHECK: 41:30: UnexposedExpr= Extent=[41:30 - 41:40]
-// CHECK: 41:31: UnexposedExpr= Extent=[41:31 - 41:40]
+// CHECK: 41:30: UnaryOperator= Extent=[41:30 - 41:40]
+// CHECK: 41:31: CXXFunctionalCastExpr= Extent=[41:31 - 41:40]
// CHECK: 41:31: TypeRef=size_t:2:25 Extent=[41:31 - 41:37]
// CHECK: 41:38: UnexposedExpr= Extent=[41:38 - 41:39]
-// CHECK: 41:38: UnexposedExpr= Extent=[41:38 - 41:39]
-// CHECK: 42:1: UnexposedDecl=:42:1 (Definition) Extent=[42:1 - 42:9]
+// CHECK: 41:38: IntegerLiteral= Extent=[41:38 - 41:39]
+// CHECK: 42:1: CXXAccessSpecifier=:42:1 (Definition) Extent=[42:1 - 42:9]
// CHECK: 43:15: FieldDecl=Data:43:15 (Definition) Extent=[43:3 - 43:19]
// CHECK: 44:10: FieldDecl=Length:44:10 (Definition) Extent=[44:3 - 44:16]
// CHECK: 44:3: TypeRef=size_t:2:25 Extent=[44:3 - 44:9]
@@ -1644,23 +1644,23 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 45:21: TypeRef=size_t:2:25 Extent=[45:21 - 45:27]
// CHECK: 45:38: ParmDecl=b:45:38 (Definition) Extent=[45:31 - 45:39]
// CHECK: 45:31: TypeRef=size_t:2:25 Extent=[45:31 - 45:37]
-// CHECK: 45:41: UnexposedStmt= Extent=[45:41 - 45:66]
-// CHECK: 45:43: UnexposedStmt= Extent=[45:43 - 45:63]
-// CHECK: 45:50: UnexposedExpr= Extent=[45:50 - 45:63]
-// CHECK: 45:50: UnexposedExpr= Extent=[45:50 - 45:55]
+// CHECK: 45:41: CompoundStmt= Extent=[45:41 - 45:66]
+// CHECK: 45:43: ReturnStmt= Extent=[45:43 - 45:63]
+// CHECK: 45:50: ConditionalOperator= Extent=[45:50 - 45:63]
+// CHECK: 45:50: BinaryOperator= Extent=[45:50 - 45:55]
// CHECK: 45:50: DeclRefExpr=a:45:28 Extent=[45:50 - 45:51]
// CHECK: 45:54: DeclRefExpr=b:45:38 Extent=[45:54 - 45:55]
// CHECK: 45:58: DeclRefExpr=a:45:28 Extent=[45:58 - 45:59]
// CHECK: 45:62: DeclRefExpr=b:45:38 Extent=[45:62 - 45:63]
-// CHECK: 46:1: UnexposedDecl=:46:1 (Definition) Extent=[46:1 - 46:8]
+// CHECK: 46:1: CXXAccessSpecifier=:46:1 (Definition) Extent=[46:1 - 46:8]
// CHECK: 47:3: CXXConstructor=StringRef:47:3 (Definition) Extent=[47:3 - 47:37]
// CHECK: 47:16: MemberRef=Data:43:15 Extent=[47:16 - 47:20]
// CHECK: 47:21: UnexposedExpr= Extent=[47:21 - 47:22]
-// CHECK: 47:21: UnexposedExpr= Extent=[47:21 - 47:22]
+// CHECK: 47:21: IntegerLiteral= Extent=[47:21 - 47:22]
// CHECK: 47:25: MemberRef=Length:44:10 Extent=[47:25 - 47:31]
// CHECK: 47:32: UnexposedExpr= Extent=[47:32 - 47:33]
-// CHECK: 47:32: UnexposedExpr= Extent=[47:32 - 47:33]
-// CHECK: 47:35: UnexposedStmt= Extent=[47:35 - 47:37]
+// CHECK: 47:32: IntegerLiteral= Extent=[47:32 - 47:33]
+// CHECK: 47:35: CompoundStmt= Extent=[47:35 - 47:37]
// CHECK: 48:3: CXXConstructor=StringRef:48:3 (Definition) Extent=[48:3 - 48:71]
// CHECK: 48:25: ParmDecl=Str:48:25 (Definition) Extent=[48:13 - 48:28]
// CHECK: 48:32: MemberRef=Data:43:15 Extent=[48:32 - 48:36]
@@ -1670,7 +1670,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 48:50: UnexposedExpr=magic_length:36:8 Extent=[48:50 - 48:62]
// CHECK: 48:50: DeclRefExpr=magic_length:36:8 Extent=[48:50 - 48:62]
// CHECK: 48:63: DeclRefExpr=Str:48:25 Extent=[48:63 - 48:66]
-// CHECK: 48:69: UnexposedStmt= Extent=[48:69 - 48:71]
+// CHECK: 48:69: CompoundStmt= Extent=[48:69 - 48:71]
// CHECK: 49:3: CXXConstructor=StringRef:49:3 (Definition) Extent=[49:3 - 49:77]
// CHECK: 49:25: ParmDecl=data:49:25 (Definition) Extent=[49:13 - 49:29]
// CHECK: 49:38: ParmDecl=length:49:38 (Definition) Extent=[49:31 - 49:44]
@@ -1679,67 +1679,67 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 49:53: DeclRefExpr=data:49:25 Extent=[49:53 - 49:57]
// CHECK: 49:60: MemberRef=Length:44:10 Extent=[49:60 - 49:66]
// CHECK: 49:67: DeclRefExpr=length:49:38 Extent=[49:67 - 49:73]
-// CHECK: 49:75: UnexposedStmt= Extent=[49:75 - 49:77]
+// CHECK: 49:75: CompoundStmt= Extent=[49:75 - 49:77]
// CHECK: 50:12: CXXMethod=end:50:12 (Definition) Extent=[50:3 - 50:40]
// CHECK: 50:3: TypeRef=iterator:40:23 Extent=[50:3 - 50:11]
-// CHECK: 50:24: UnexposedStmt= Extent=[50:24 - 50:40]
-// CHECK: 50:26: UnexposedStmt= Extent=[50:26 - 50:37]
+// CHECK: 50:24: CompoundStmt= Extent=[50:24 - 50:40]
+// CHECK: 50:26: ReturnStmt= Extent=[50:26 - 50:37]
// CHECK: 50:33: MemberRefExpr=Data:43:15 Extent=[50:33 - 50:37]
// CHECK: 51:10: CXXMethod=size:51:10 (Definition) Extent=[51:3 - 51:41]
// CHECK: 51:3: TypeRef=size_t:2:25 Extent=[51:3 - 51:9]
-// CHECK: 51:23: UnexposedStmt= Extent=[51:23 - 51:41]
-// CHECK: 51:25: UnexposedStmt= Extent=[51:25 - 51:38]
+// CHECK: 51:23: CompoundStmt= Extent=[51:23 - 51:41]
+// CHECK: 51:25: ReturnStmt= Extent=[51:25 - 51:38]
// CHECK: 51:32: MemberRefExpr=Length:44:10 Extent=[51:32 - 51:38]
// CHECK: 52:8: CXXMethod=startswith:52:8 (Definition) Extent=[52:3 - 55:4]
// CHECK: 52:29: ParmDecl=Prefix:52:29 (Definition) Extent=[52:19 - 52:35]
// CHECK: 52:19: TypeRef=class llvm::StringRef:38:7 Extent=[52:19 - 52:28]
-// CHECK: 52:43: UnexposedStmt= Extent=[52:43 - 55:4]
-// CHECK: 53:5: UnexposedStmt= Extent=[53:5 - 54:56]
-// CHECK: 53:12: UnexposedExpr= Extent=[53:12 - 54:56]
-// CHECK: 53:12: UnexposedExpr= Extent=[53:12 - 53:35]
+// CHECK: 52:43: CompoundStmt= Extent=[52:43 - 55:4]
+// CHECK: 53:5: ReturnStmt= Extent=[53:5 - 54:56]
+// CHECK: 53:12: BinaryOperator= Extent=[53:12 - 54:56]
+// CHECK: 53:12: BinaryOperator= Extent=[53:12 - 53:35]
// CHECK: 53:12: UnexposedExpr=Length:44:10 Extent=[53:12 - 53:18]
// CHECK: 53:12: MemberRefExpr=Length:44:10 Extent=[53:12 - 53:18]
-// CHECK: 53:29: MemberRefExpr=Length:44:10 Extent=[53:22 - 53:35]
+// CHECK: 53:29: MemberRefExpr=Length:44:10 SingleRefName=[53:29 - 53:35] RefName=[53:29 - 53:35] Extent=[53:22 - 53:35]
// CHECK: 53:22: DeclRefExpr=Prefix:52:29 Extent=[53:22 - 53:28]
-// CHECK: 54:11: UnexposedExpr= Extent=[54:11 - 54:56]
+// CHECK: 54:11: BinaryOperator= Extent=[54:11 - 54:56]
// CHECK: 54:11: CallExpr=memcmp:7:7 Extent=[54:11 - 54:51]
// CHECK: 54:11: UnexposedExpr=memcmp:7:7 Extent=[54:11 - 54:17]
// CHECK: 54:11: DeclRefExpr=memcmp:7:7 Extent=[54:11 - 54:17]
// CHECK: 54:18: UnexposedExpr=Data:43:15 Extent=[54:18 - 54:22]
// CHECK: 54:18: MemberRefExpr=Data:43:15 Extent=[54:18 - 54:22]
-// CHECK: 54:24: UnexposedExpr=Data:43:15 Extent=[54:24 - 54:35]
-// CHECK: 54:31: MemberRefExpr=Data:43:15 Extent=[54:24 - 54:35]
+// CHECK: 54:31: UnexposedExpr=Data:43:15 Extent=[54:24 - 54:35]
+// CHECK: 54:31: MemberRefExpr=Data:43:15 SingleRefName=[54:31 - 54:35] RefName=[54:31 - 54:35] Extent=[54:24 - 54:35]
// CHECK: 54:24: DeclRefExpr=Prefix:52:29 Extent=[54:24 - 54:30]
-// CHECK: 54:44: MemberRefExpr=Length:44:10 Extent=[54:37 - 54:50]
+// CHECK: 54:44: MemberRefExpr=Length:44:10 SingleRefName=[54:44 - 54:50] RefName=[54:44 - 54:50] Extent=[54:37 - 54:50]
// CHECK: 54:37: DeclRefExpr=Prefix:52:29 Extent=[54:37 - 54:43]
-// CHECK: 54:55: UnexposedExpr= Extent=[54:55 - 54:56]
+// CHECK: 54:55: IntegerLiteral= Extent=[54:55 - 54:56]
// CHECK: 56:8: CXXMethod=endswith:56:8 (Definition) Extent=[56:3 - 59:4]
// CHECK: 56:27: ParmDecl=Suffix:56:27 (Definition) Extent=[56:17 - 56:33]
// CHECK: 56:17: TypeRef=class llvm::StringRef:38:7 Extent=[56:17 - 56:26]
-// CHECK: 56:41: UnexposedStmt= Extent=[56:41 - 59:4]
-// CHECK: 57:5: UnexposedStmt= Extent=[57:5 - 58:69]
-// CHECK: 57:12: UnexposedExpr= Extent=[57:12 - 58:69]
-// CHECK: 57:12: UnexposedExpr= Extent=[57:12 - 57:35]
+// CHECK: 56:41: CompoundStmt= Extent=[56:41 - 59:4]
+// CHECK: 57:5: ReturnStmt= Extent=[57:5 - 58:69]
+// CHECK: 57:12: BinaryOperator= Extent=[57:12 - 58:69]
+// CHECK: 57:12: BinaryOperator= Extent=[57:12 - 57:35]
// CHECK: 57:12: UnexposedExpr=Length:44:10 Extent=[57:12 - 57:18]
// CHECK: 57:12: MemberRefExpr=Length:44:10 Extent=[57:12 - 57:18]
-// CHECK: 57:29: MemberRefExpr=Length:44:10 Extent=[57:22 - 57:35]
+// CHECK: 57:29: MemberRefExpr=Length:44:10 SingleRefName=[57:29 - 57:35] RefName=[57:29 - 57:35] Extent=[57:22 - 57:35]
// CHECK: 57:22: DeclRefExpr=Suffix:56:27 Extent=[57:22 - 57:28]
-// CHECK: 58:7: UnexposedExpr= Extent=[58:7 - 58:69]
+// CHECK: 58:7: BinaryOperator= Extent=[58:7 - 58:69]
// CHECK: 58:7: CallExpr=memcmp:7:7 Extent=[58:7 - 58:64]
// CHECK: 58:7: UnexposedExpr=memcmp:7:7 Extent=[58:7 - 58:13]
// CHECK: 58:7: DeclRefExpr=memcmp:7:7 Extent=[58:7 - 58:13]
// CHECK: 58:14: UnexposedExpr= Extent=[58:14 - 58:35]
-// CHECK: 58:14: UnexposedExpr= Extent=[58:14 - 58:35]
+// CHECK: 58:14: BinaryOperator= Extent=[58:14 - 58:35]
// CHECK: 58:14: CallExpr=end:50:12 Extent=[58:14 - 58:19]
// CHECK: 58:14: MemberRefExpr=end:50:12 Extent=[58:14 - 58:17]
-// CHECK: 58:29: MemberRefExpr=Length:44:10 Extent=[58:22 - 58:35]
+// CHECK: 58:29: MemberRefExpr=Length:44:10 SingleRefName=[58:29 - 58:35] RefName=[58:29 - 58:35] Extent=[58:22 - 58:35]
// CHECK: 58:22: DeclRefExpr=Suffix:56:27 Extent=[58:22 - 58:28]
-// CHECK: 58:37: UnexposedExpr=Data:43:15 Extent=[58:37 - 58:48]
-// CHECK: 58:44: MemberRefExpr=Data:43:15 Extent=[58:37 - 58:48]
+// CHECK: 58:44: UnexposedExpr=Data:43:15 Extent=[58:37 - 58:48]
+// CHECK: 58:44: MemberRefExpr=Data:43:15 SingleRefName=[58:44 - 58:48] RefName=[58:44 - 58:48] Extent=[58:37 - 58:48]
// CHECK: 58:37: DeclRefExpr=Suffix:56:27 Extent=[58:37 - 58:43]
-// CHECK: 58:57: MemberRefExpr=Length:44:10 Extent=[58:50 - 58:63]
+// CHECK: 58:57: MemberRefExpr=Length:44:10 SingleRefName=[58:57 - 58:63] RefName=[58:57 - 58:63] Extent=[58:50 - 58:63]
// CHECK: 58:50: DeclRefExpr=Suffix:56:27 Extent=[58:50 - 58:56]
-// CHECK: 58:68: UnexposedExpr= Extent=[58:68 - 58:69]
+// CHECK: 58:68: IntegerLiteral= Extent=[58:68 - 58:69]
// CHECK: 60:13: CXXMethod=substr:60:13 (Definition) Extent=[60:3 - 62:4]
// CHECK: 60:3: TypeRef=class llvm::StringRef:38:7 Extent=[60:3 - 60:12]
// CHECK: 60:27: ParmDecl=Start:60:27 (Definition) Extent=[60:20 - 60:32]
@@ -1747,13 +1747,13 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 60:41: ParmDecl=N:60:41 (Definition) Extent=[60:34 - 60:49]
// CHECK: 60:34: TypeRef=size_t:2:25 Extent=[60:34 - 60:40]
// CHECK: 60:45: DeclRefExpr=npos:41:23 Extent=[60:45 - 60:49]
-// CHECK: 60:57: UnexposedStmt= Extent=[60:57 - 62:4]
-// CHECK: 61:5: UnexposedStmt= Extent=[61:5 - 61:59]
+// CHECK: 60:57: CompoundStmt= Extent=[60:57 - 62:4]
+// CHECK: 61:5: ReturnStmt= Extent=[61:5 - 61:59]
// CHECK: 61:12: CallExpr= Extent=[61:12 - 61:59]
// CHECK: 61:12: UnexposedExpr=StringRef:49:3 Extent=[61:12 - 61:59]
// CHECK: 61:12: CallExpr=StringRef:49:3 Extent=[61:12 - 61:59]
// CHECK: 61:12: TypeRef=class llvm::StringRef:38:7 Extent=[61:12 - 61:21]
-// CHECK: 61:22: UnexposedExpr= Extent=[61:22 - 61:34]
+// CHECK: 61:22: BinaryOperator= Extent=[61:22 - 61:34]
// CHECK: 61:22: UnexposedExpr=Data:43:15 Extent=[61:22 - 61:26]
// CHECK: 61:22: MemberRefExpr=Data:43:15 Extent=[61:22 - 61:26]
// CHECK: 61:29: DeclRefExpr=Start:60:27 Extent=[61:29 - 61:34]
@@ -1761,68 +1761,68 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 61:36: UnexposedExpr=min:45:17 Extent=[61:36 - 61:39]
// CHECK: 61:36: DeclRefExpr=min:45:17 Extent=[61:36 - 61:39]
// CHECK: 61:40: DeclRefExpr=N:60:41 Extent=[61:40 - 61:41]
-// CHECK: 61:43: UnexposedExpr= Extent=[61:43 - 61:57]
+// CHECK: 61:43: BinaryOperator= Extent=[61:43 - 61:57]
// CHECK: 61:43: UnexposedExpr=Length:44:10 Extent=[61:43 - 61:49]
// CHECK: 61:43: MemberRefExpr=Length:44:10 Extent=[61:43 - 61:49]
// CHECK: 61:52: DeclRefExpr=Start:60:27 Extent=[61:52 - 61:57]
// CHECK: 65:11: Namespace=clang:65:11 (Definition) Extent=[65:1 - 81:2]
// CHECK: 66:7: ClassDecl=IdentifierInfo:66:7 (Definition) Extent=[66:1 - 80:2]
-// CHECK: 67:1: UnexposedDecl=:67:1 (Definition) Extent=[67:1 - 67:8]
+// CHECK: 67:1: CXXAccessSpecifier=:67:1 (Definition) Extent=[67:1 - 67:8]
// CHECK: 67:8: CXXConstructor=IdentifierInfo:67:8 Extent=[67:8 - 67:24]
// CHECK: 68:15: CXXMethod=getNameStart:68:15 (Definition) Extent=[68:3 - 71:4]
-// CHECK: 68:36: UnexposedStmt= Extent=[68:36 - 71:4]
-// CHECK: 69:5: UnexposedStmt= Extent=[69:5 - 69:65]
+// CHECK: 68:36: CompoundStmt= Extent=[68:36 - 71:4]
+// CHECK: 69:5: DeclStmt= Extent=[69:5 - 69:65]
// CHECK: 69:54: TypedefDecl=actualtype:69:54 (Definition) Extent=[69:5 - 69:64]
// CHECK: 69:18: TemplateRef=pair:4:44 Extent=[69:18 - 69:22]
// CHECK: 69:25: TypeRef=class clang::IdentifierInfo:66:7 Extent=[69:25 - 69:39]
-// CHECK: 70:5: UnexposedStmt= Extent=[70:5 - 70:47]
-// CHECK: 70:41: MemberRefExpr=second:4:55 Extent=[70:12 - 70:47]
-// CHECK: 70:12: UnexposedExpr= Extent=[70:12 - 70:39]
-// CHECK: 70:13: UnexposedExpr= Extent=[70:13 - 70:38]
+// CHECK: 70:5: ReturnStmt= Extent=[70:5 - 70:47]
+// CHECK: 70:41: MemberRefExpr=second:4:55 SingleRefName=[70:41 - 70:47] RefName=[70:41 - 70:47] Extent=[70:12 - 70:47]
+// CHECK: 70:12: ParenExpr= Extent=[70:12 - 70:39]
+// CHECK: 70:13: CStyleCastExpr= Extent=[70:13 - 70:38]
// CHECK: 70:20: TypeRef=actualtype:69:54 Extent=[70:20 - 70:30]
-// CHECK: 70:34: UnexposedExpr= Extent=[70:34 - 70:38]
+// CHECK: 70:34: CXXThisExpr= Extent=[70:34 - 70:38]
// CHECK: 72:12: CXXMethod=getLength:72:12 (Definition) Extent=[72:3 - 76:4]
-// CHECK: 72:30: UnexposedStmt= Extent=[72:30 - 76:4]
-// CHECK: 73:5: UnexposedStmt= Extent=[73:5 - 73:65]
+// CHECK: 72:30: CompoundStmt= Extent=[72:30 - 76:4]
+// CHECK: 73:5: DeclStmt= Extent=[73:5 - 73:65]
// CHECK: 73:54: TypedefDecl=actualtype:73:54 (Definition) Extent=[73:5 - 73:64]
// CHECK: 73:18: TemplateRef=pair:4:44 Extent=[73:18 - 73:22]
// CHECK: 73:25: TypeRef=class clang::IdentifierInfo:66:7 Extent=[73:25 - 73:39]
-// CHECK: 74:5: UnexposedStmt= Extent=[74:5 - 74:61]
+// CHECK: 74:5: DeclStmt= Extent=[74:5 - 74:61]
// CHECK: 74:17: VarDecl=p:74:17 (Definition) Extent=[74:5 - 74:60]
-// CHECK: 74:21: UnexposedExpr= Extent=[74:21 - 74:60]
-// CHECK: 74:21: UnexposedExpr=second:4:55 Extent=[74:21 - 74:56]
-// CHECK: 74:50: MemberRefExpr=second:4:55 Extent=[74:21 - 74:56]
-// CHECK: 74:21: UnexposedExpr= Extent=[74:21 - 74:48]
-// CHECK: 74:22: UnexposedExpr= Extent=[74:22 - 74:47]
+// CHECK: 74:21: BinaryOperator= Extent=[74:21 - 74:60]
+// CHECK: 74:50: UnexposedExpr=second:4:55 Extent=[74:21 - 74:56]
+// CHECK: 74:50: MemberRefExpr=second:4:55 SingleRefName=[74:50 - 74:56] RefName=[74:50 - 74:56] Extent=[74:21 - 74:56]
+// CHECK: 74:21: ParenExpr= Extent=[74:21 - 74:48]
+// CHECK: 74:22: CStyleCastExpr= Extent=[74:22 - 74:47]
// CHECK: 74:29: TypeRef=actualtype:73:54 Extent=[74:29 - 74:39]
-// CHECK: 74:43: UnexposedExpr= Extent=[74:43 - 74:47]
-// CHECK: 74:59: UnexposedExpr= Extent=[74:59 - 74:60]
-// CHECK: 75:5: UnexposedStmt= Extent=[75:5 - 75:62]
-// CHECK: 75:12: UnexposedExpr= Extent=[75:12 - 75:62]
-// CHECK: 75:12: UnexposedExpr= Extent=[75:12 - 75:58]
-// CHECK: 75:13: UnexposedExpr= Extent=[75:13 - 75:57]
-// CHECK: 75:13: UnexposedExpr= Extent=[75:13 - 75:30]
-// CHECK: 75:14: UnexposedExpr= Extent=[75:14 - 75:29]
-// CHECK: 75:25: UnexposedExpr= Extent=[75:25 - 75:29]
+// CHECK: 74:43: CXXThisExpr= Extent=[74:43 - 74:47]
+// CHECK: 74:59: IntegerLiteral= Extent=[74:59 - 74:60]
+// CHECK: 75:5: ReturnStmt= Extent=[75:5 - 75:62]
+// CHECK: 75:12: BinaryOperator= Extent=[75:12 - 75:62]
+// CHECK: 75:12: ParenExpr= Extent=[75:12 - 75:58]
+// CHECK: 75:13: BinaryOperator= Extent=[75:13 - 75:57]
+// CHECK: 75:13: ParenExpr= Extent=[75:13 - 75:30]
+// CHECK: 75:14: CStyleCastExpr= Extent=[75:14 - 75:29]
// CHECK: 75:25: UnexposedExpr= Extent=[75:25 - 75:29]
// CHECK: 75:25: UnexposedExpr= Extent=[75:25 - 75:29]
+// CHECK: 75:25: ArraySubscriptExpr= Extent=[75:25 - 75:29]
// CHECK: 75:25: DeclRefExpr=p:74:17 Extent=[75:25 - 75:26]
-// CHECK: 75:27: UnexposedExpr= Extent=[75:27 - 75:28]
-// CHECK: 75:33: UnexposedExpr= Extent=[75:33 - 75:57]
-// CHECK: 75:34: UnexposedExpr= Extent=[75:34 - 75:56]
-// CHECK: 75:34: UnexposedExpr= Extent=[75:34 - 75:51]
-// CHECK: 75:35: UnexposedExpr= Extent=[75:35 - 75:50]
-// CHECK: 75:46: UnexposedExpr= Extent=[75:46 - 75:50]
+// CHECK: 75:27: IntegerLiteral= Extent=[75:27 - 75:28]
+// CHECK: 75:33: ParenExpr= Extent=[75:33 - 75:57]
+// CHECK: 75:34: BinaryOperator= Extent=[75:34 - 75:56]
+// CHECK: 75:34: ParenExpr= Extent=[75:34 - 75:51]
+// CHECK: 75:35: CStyleCastExpr= Extent=[75:35 - 75:50]
// CHECK: 75:46: UnexposedExpr= Extent=[75:46 - 75:50]
// CHECK: 75:46: UnexposedExpr= Extent=[75:46 - 75:50]
+// CHECK: 75:46: ArraySubscriptExpr= Extent=[75:46 - 75:50]
// CHECK: 75:46: DeclRefExpr=p:74:17 Extent=[75:46 - 75:47]
-// CHECK: 75:48: UnexposedExpr= Extent=[75:48 - 75:49]
-// CHECK: 75:55: UnexposedExpr= Extent=[75:55 - 75:56]
-// CHECK: 75:61: UnexposedExpr= Extent=[75:61 - 75:62]
+// CHECK: 75:48: IntegerLiteral= Extent=[75:48 - 75:49]
+// CHECK: 75:55: IntegerLiteral= Extent=[75:55 - 75:56]
// CHECK: 75:61: UnexposedExpr= Extent=[75:61 - 75:62]
+// CHECK: 75:61: IntegerLiteral= Extent=[75:61 - 75:62]
// CHECK: 77:19: CXXMethod=getName:77:19 (Definition) Extent=[77:3 - 79:4]
-// CHECK: 77:35: UnexposedStmt= Extent=[77:35 - 79:4]
-// CHECK: 78:5: UnexposedStmt= Extent=[78:5 - 78:56]
+// CHECK: 77:35: CompoundStmt= Extent=[77:35 - 79:4]
+// CHECK: 78:5: ReturnStmt= Extent=[78:5 - 78:56]
// CHECK: 78:12: CallExpr= Extent=[78:12 - 78:56]
// CHECK: 78:12: UnexposedExpr=StringRef:49:3 Extent=[78:12 - 78:56]
// CHECK: 78:12: CallExpr=StringRef:49:3 Extent=[78:12 - 78:56]
@@ -1838,7 +1838,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 84:13: FieldDecl=Str:84:13 (Definition) Extent=[84:3 - 84:16]
// CHECK: 84:3: TypeRef=class llvm::StringRef:38:7 Extent=[84:3 - 84:12]
// CHECK: 85:12: FieldDecl=Result:85:12 (Definition) Extent=[85:3 - 85:18]
-// CHECK: 86:1: UnexposedDecl=:86:1 (Definition) Extent=[86:1 - 86:8]
+// CHECK: 86:1: CXXAccessSpecifier=:86:1 (Definition) Extent=[86:1 - 86:8]
// CHECK: 87:12: CXXConstructor=StringSwitch<T, R>:87:12 (Definition) Extent=[87:3 - 87:64]
// 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]
@@ -1847,21 +1847,21 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// 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]
-// CHECK: 87:59: UnexposedExpr= Extent=[87:59 - 87:60]
-// CHECK: 87:62: UnexposedStmt= Extent=[87:62 - 87:64]
+// CHECK: 87:59: IntegerLiteral= Extent=[87:59 - 87:60]
+// CHECK: 87:62: CompoundStmt= Extent=[87:62 - 87:64]
// CHECK: 88:42: FunctionTemplate=Case:88:42 (Definition) Extent=[88:3 - 91:4]
// CHECK: 88:23: NonTypeTemplateParameter=N:88:23 (Definition) Extent=[88:14 - 88:24]
// CHECK: 88:60: ParmDecl=S:88:60 (Definition) Extent=[88:47 - 88:65]
// CHECK: 88:63: DeclRefExpr=N:88:23 Extent=[88:63 - 88:64]
// CHECK: 89:57: ParmDecl=Value:89:57 (Definition) Extent=[89:47 - 89:62]
-// CHECK: 89:64: UnexposedStmt= Extent=[89:64 - 91:4]
-// CHECK: 90:5: UnexposedStmt= Extent=[90:5 - 90:17]
-// CHECK: 90:12: UnexposedExpr= Extent=[90:12 - 90:17]
-// CHECK: 90:13: UnexposedExpr= Extent=[90:13 - 90:17]
+// CHECK: 89:64: CompoundStmt= Extent=[89:64 - 91:4]
+// CHECK: 90:5: ReturnStmt= Extent=[90:5 - 90:17]
+// CHECK: 90:12: UnaryOperator= Extent=[90:12 - 90:17]
+// CHECK: 90:13: CXXThisExpr= Extent=[90:13 - 90:17]
// CHECK: 92:5: CXXMethod=Default:92:5 (Definition) Extent=[92:3 - 94:4]
// CHECK: 92:23: ParmDecl=Value:92:23 (Definition) Extent=[92:13 - 92:28]
-// CHECK: 92:36: UnexposedStmt= Extent=[92:36 - 94:4]
-// CHECK: 93:5: UnexposedStmt= Extent=[93:5 - 93:17]
+// CHECK: 92:36: CompoundStmt= Extent=[92:36 - 94:4]
+// CHECK: 93:5: ReturnStmt= Extent=[93:5 - 93:17]
// CHECK: 93:12: DeclRefExpr=Value:92:23 Extent=[93:12 - 93:17]
// CHECK: 98:17: UsingDirective=:98:17 Extent=[98:1 - 98:22]
// CHECK: 98:17: NamespaceRef=clang:10:17 Extent=[98:17 - 98:22]
@@ -1869,18 +1869,18 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 100:21: TypeRef=class clang::AttributeList:12:9 Extent=[100:21 - 100:34]
// CHECK: 100:67: ParmDecl=Name:100:67 (Definition) Extent=[100:44 - 100:71]
// CHECK: 100:50: TypeRef=class clang::IdentifierInfo:66:7 Extent=[100:50 - 100:64]
-// CHECK: 100:73: UnexposedStmt= Extent=[100:73 - 186:2]
-// CHECK: 101:3: UnexposedStmt= Extent=[101:3 - 101:46]
+// CHECK: 100:73: CompoundStmt= Extent=[100:73 - 186:2]
+// CHECK: 101:3: DeclStmt= Extent=[101:3 - 101:46]
// CHECK: 101:19: VarDecl=AttrName:101:19 (Definition) Extent=[101:3 - 101:45]
// CHECK: 101:30: CallExpr= Extent=[101:30 - 101:45]
// CHECK: 101:30: UnexposedExpr=getName:77:19 Extent=[101:30 - 101:45]
// CHECK: 101:30: CallExpr=getName:77:19 Extent=[101:30 - 101:45]
-// CHECK: 101:36: MemberRefExpr=getName:77:19 Extent=[101:30 - 101:43]
+// CHECK: 101:36: MemberRefExpr=getName:77:19 SingleRefName=[101:36 - 101:43] RefName=[101:36 - 101:43] Extent=[101:30 - 101:43]
// CHECK: 101:30: DeclRefExpr=Name:100:67 Extent=[101:30 - 101:34]
-// CHECK: 102:3: UnexposedStmt= Extent=[102:3 - 103:55]
-// CHECK: 102:7: UnexposedExpr= Extent=[102:7 - 102:59]
+// CHECK: 102:3: IfStmt= Extent=[102:3 - 103:55]
+// CHECK: 102:7: BinaryOperator= Extent=[102:7 - 102:59]
// CHECK: 102:7: CallExpr=startswith:52:8 Extent=[102:7 - 102:32]
-// CHECK: 102:16: MemberRefExpr=startswith:52:8 Extent=[102:7 - 102:26]
+// CHECK: 102:16: MemberRefExpr=startswith:52:8 SingleRefName=[102:16 - 102:26] RefName=[102:16 - 102:26] Extent=[102:7 - 102:26]
// CHECK: 102:7: UnexposedExpr=AttrName:101:19 Extent=[102:7 - 102:15]
// CHECK: 102:7: DeclRefExpr=AttrName:101:19 Extent=[102:7 - 102:15]
// CHECK: 102:27: CallExpr= Extent=[102:27 - 102:31]
@@ -1888,9 +1888,9 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 102:27: UnexposedExpr=StringRef:48:3 Extent=[102:27 - 102:31]
// CHECK: 102:27: CallExpr=StringRef:48:3 Extent=[102:27 - 102:31]
// CHECK: 102:27: UnexposedExpr= Extent=[102:27 - 102:31]
-// CHECK: 102:27: UnexposedExpr= Extent=[102:27 - 102:31]
+// CHECK: 102:27: StringLiteral= Extent=[102:27 - 102:31]
// CHECK: 102:36: CallExpr=endswith:56:8 Extent=[102:36 - 102:59]
-// CHECK: 102:45: MemberRefExpr=endswith:56:8 Extent=[102:36 - 102:53]
+// CHECK: 102:45: MemberRefExpr=endswith:56:8 SingleRefName=[102:45 - 102:53] RefName=[102:45 - 102:53] Extent=[102:36 - 102:53]
// CHECK: 102:36: UnexposedExpr=AttrName:101:19 Extent=[102:36 - 102:44]
// CHECK: 102:36: DeclRefExpr=AttrName:101:19 Extent=[102:36 - 102:44]
// CHECK: 102:54: CallExpr= Extent=[102:54 - 102:58]
@@ -1898,350 +1898,346 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 102:54: UnexposedExpr=StringRef:48:3 Extent=[102:54 - 102:58]
// CHECK: 102:54: CallExpr=StringRef:48:3 Extent=[102:54 - 102:58]
// CHECK: 102:54: UnexposedExpr= Extent=[102:54 - 102:58]
-// CHECK: 102:54: UnexposedExpr= Extent=[102:54 - 102:58]
+// CHECK: 102:54: StringLiteral= Extent=[102:54 - 102:58]
// CHECK: 103:5: CallExpr=operator=:38:7 Extent=[103:5 - 103:55]
// CHECK: 103:5: DeclRefExpr=AttrName:101:19 Extent=[103:5 - 103:13]
// CHECK: 103:14: UnexposedExpr=operator=:38:7
// CHECK: 103:14: DeclRefExpr=operator=:38:7
// CHECK: 103:16: UnexposedExpr=substr:60:13 Extent=[103:16 - 103:55]
// CHECK: 103:16: CallExpr=substr:60:13 Extent=[103:16 - 103:55]
-// CHECK: 103:25: MemberRefExpr=substr:60:13 Extent=[103:16 - 103:31]
+// CHECK: 103:25: MemberRefExpr=substr:60:13 SingleRefName=[103:25 - 103:31] RefName=[103:25 - 103:31] Extent=[103:16 - 103:31]
// CHECK: 103:16: UnexposedExpr=AttrName:101:19 Extent=[103:16 - 103:24]
// CHECK: 103:16: DeclRefExpr=AttrName:101:19 Extent=[103:16 - 103:24]
// CHECK: 103:32: UnexposedExpr= Extent=[103:32 - 103:33]
-// CHECK: 103:32: UnexposedExpr= Extent=[103:32 - 103:33]
-// CHECK: 103:35: UnexposedExpr= Extent=[103:35 - 103:54]
+// CHECK: 103:32: IntegerLiteral= Extent=[103:32 - 103:33]
+// CHECK: 103:35: BinaryOperator= Extent=[103:35 - 103:54]
// CHECK: 103:35: CallExpr=size:51:10 Extent=[103:35 - 103:50]
-// CHECK: 103:44: MemberRefExpr=size:51:10 Extent=[103:35 - 103:48]
+// CHECK: 103:44: MemberRefExpr=size:51:10 SingleRefName=[103:44 - 103:48] RefName=[103:44 - 103:48] Extent=[103:35 - 103:48]
// CHECK: 103:35: UnexposedExpr=AttrName:101:19 Extent=[103:35 - 103:43]
// CHECK: 103:35: DeclRefExpr=AttrName:101:19 Extent=[103:35 - 103:43]
// CHECK: 103:53: UnexposedExpr= Extent=[103:53 - 103:54]
-// CHECK: 103:53: UnexposedExpr= Extent=[103:53 - 103:54]
-// CHECK: 105:3: UnexposedStmt= Extent=[105:3 - 185:31]
+// CHECK: 103:53: IntegerLiteral= Extent=[103:53 - 103:54]
+// CHECK: 105:3: ReturnStmt= Extent=[105:3 - 185:31]
// CHECK: 105:10: CallExpr=Default:92:5 Extent=[105:10 - 185:31]
-// CHECK: 185:6: MemberRefExpr=Default:92:5 Extent=[105:10 - 185:13]
+// CHECK: 185:6: MemberRefExpr=Default:92:5 SingleRefName=[185:6 - 185:13] RefName=[185:6 - 185:13] Extent=[105:10 - 185:13]
// CHECK: 105:10: UnexposedExpr=Case:88:42 Extent=[105:10 - 184:33]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 184:33]
-// CHECK: 184:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 184:10]
+// CHECK: 184:6: MemberRefExpr=Case:88:42 SingleRefName=[184:6 - 184:10] RefName=[184:6 - 184:10] Extent=[105:10 - 184:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 183:37]
-// CHECK: 183:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 183:10]
+// CHECK: 183:6: MemberRefExpr=Case:88:42 SingleRefName=[183:6 - 183:10] RefName=[183:6 - 183:10] Extent=[105:10 - 183:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 182:37]
-// CHECK: 182:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 182:10]
+// CHECK: 182:6: MemberRefExpr=Case:88:42 SingleRefName=[182:6 - 182:10] RefName=[182:6 - 182:10] Extent=[105:10 - 182:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 181:35]
-// CHECK: 181:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 181:10]
+// CHECK: 181:6: MemberRefExpr=Case:88:42 SingleRefName=[181:6 - 181:10] RefName=[181:6 - 181:10] Extent=[105:10 - 181:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 180:31]
-// CHECK: 180:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 180:10]
+// CHECK: 180:6: MemberRefExpr=Case:88:42 SingleRefName=[180:6 - 180:10] RefName=[180:6 - 180:10] Extent=[105:10 - 180:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 179:31]
-// CHECK: 179:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 179:10]
+// CHECK: 179:6: MemberRefExpr=Case:88:42 SingleRefName=[179:6 - 179:10] RefName=[179:6 - 179:10] Extent=[105:10 - 179:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 178:35]
-// CHECK: 178:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 178:10]
+// CHECK: 178:6: MemberRefExpr=Case:88:42 SingleRefName=[178:6 - 178:10] RefName=[178:6 - 178:10] Extent=[105:10 - 178:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 177:63]
-// CHECK: 177:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 177:10]
+// CHECK: 177:6: MemberRefExpr=Case:88:42 SingleRefName=[177:6 - 177:10] RefName=[177:6 - 177:10] Extent=[105:10 - 177:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 176:45]
-// CHECK: 176:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 176:10]
+// CHECK: 176:6: MemberRefExpr=Case:88:42 SingleRefName=[176:6 - 176:10] RefName=[176:6 - 176:10] Extent=[105:10 - 176:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 175:51]
-// CHECK: 175:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 175:10]
+// CHECK: 175:6: MemberRefExpr=Case:88:42 SingleRefName=[175:6 - 175:10] RefName=[175:6 - 175:10] Extent=[105:10 - 175:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 174:49]
-// CHECK: 174:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 174:10]
+// CHECK: 174:6: MemberRefExpr=Case:88:42 SingleRefName=[174:6 - 174:10] RefName=[174:6 - 174:10] Extent=[105:10 - 174:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 173:49]
-// CHECK: 173:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 173:10]
+// CHECK: 173:6: MemberRefExpr=Case:88:42 SingleRefName=[173:6 - 173:10] RefName=[173:6 - 173:10] Extent=[105:10 - 173:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 172:53]
-// CHECK: 172:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 172:10]
+// CHECK: 172:6: MemberRefExpr=Case:88:42 SingleRefName=[172:6 - 172:10] RefName=[172:6 - 172:10] Extent=[105:10 - 172:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 171:57]
-// CHECK: 171:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 171:10]
+// CHECK: 171:6: MemberRefExpr=Case:88:42 SingleRefName=[171:6 - 171:10] RefName=[171:6 - 171:10] Extent=[105:10 - 171:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 170:65]
-// CHECK: 170:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 170:10]
+// CHECK: 170:6: MemberRefExpr=Case:88:42 SingleRefName=[170:6 - 170:10] RefName=[170:6 - 170:10] Extent=[105:10 - 170:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 169:57]
-// CHECK: 169:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 169:10]
+// CHECK: 169:6: MemberRefExpr=Case:88:42 SingleRefName=[169:6 - 169:10] RefName=[169:6 - 169:10] Extent=[105:10 - 169:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 168:65]
-// CHECK: 168:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 168:10]
+// CHECK: 168:6: MemberRefExpr=Case:88:42 SingleRefName=[168:6 - 168:10] RefName=[168:6 - 168:10] Extent=[105:10 - 168:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 167:55]
-// CHECK: 167:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 167:10]
+// CHECK: 167:6: MemberRefExpr=Case:88:42 SingleRefName=[167:6 - 167:10] RefName=[167:6 - 167:10] Extent=[105:10 - 167:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 166:55]
-// CHECK: 166:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 166:10]
+// CHECK: 166:6: MemberRefExpr=Case:88:42 SingleRefName=[166:6 - 166:10] RefName=[166:6 - 166:10] Extent=[105:10 - 166:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 165:53]
-// CHECK: 165:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 165:10]
+// CHECK: 165:6: MemberRefExpr=Case:88:42 SingleRefName=[165:6 - 165:10] RefName=[165:6 - 165:10] Extent=[105:10 - 165:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 164:53]
-// CHECK: 164:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 164:10]
+// CHECK: 164:6: MemberRefExpr=Case:88:42 SingleRefName=[164:6 - 164:10] RefName=[164:6 - 164:10] Extent=[105:10 - 164:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 163:49]
-// CHECK: 163:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 163:10]
+// CHECK: 163:6: MemberRefExpr=Case:88:42 SingleRefName=[163:6 - 163:10] RefName=[163:6 - 163:10] Extent=[105:10 - 163:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 162:47]
-// CHECK: 162:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 162:10]
+// CHECK: 162:6: MemberRefExpr=Case:88:42 SingleRefName=[162:6 - 162:10] RefName=[162:6 - 162:10] Extent=[105:10 - 162:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 161:45]
-// CHECK: 161:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 161:10]
+// CHECK: 161:6: MemberRefExpr=Case:88:42 SingleRefName=[161:6 - 161:10] RefName=[161:6 - 161:10] Extent=[105:10 - 161:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 160:45]
-// CHECK: 160:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 160:10]
+// CHECK: 160:6: MemberRefExpr=Case:88:42 SingleRefName=[160:6 - 160:10] RefName=[160:6 - 160:10] Extent=[105:10 - 160:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 159:45]
-// CHECK: 159:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 159:10]
+// CHECK: 159:6: MemberRefExpr=Case:88:42 SingleRefName=[159:6 - 159:10] RefName=[159:6 - 159:10] Extent=[105:10 - 159:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 158:45]
-// CHECK: 158:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 158:10]
+// CHECK: 158:6: MemberRefExpr=Case:88:42 SingleRefName=[158:6 - 158:10] RefName=[158:6 - 158:10] Extent=[105:10 - 158:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 157:43]
-// CHECK: 157:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 157:10]
+// CHECK: 157:6: MemberRefExpr=Case:88:42 SingleRefName=[157:6 - 157:10] RefName=[157:6 - 157:10] Extent=[105:10 - 157:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 156:41]
-// CHECK: 156:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 156:10]
+// CHECK: 156:6: MemberRefExpr=Case:88:42 SingleRefName=[156:6 - 156:10] RefName=[156:6 - 156:10] Extent=[105:10 - 156:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 155:41]
-// CHECK: 155:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 155:10]
+// CHECK: 155:6: MemberRefExpr=Case:88:42 SingleRefName=[155:6 - 155:10] RefName=[155:6 - 155:10] Extent=[105:10 - 155:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 154:41]
-// CHECK: 154:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 154:10]
+// CHECK: 154:6: MemberRefExpr=Case:88:42 SingleRefName=[154:6 - 154:10] RefName=[154:6 - 154:10] Extent=[105:10 - 154:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 153:37]
-// CHECK: 153:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 153:10]
+// CHECK: 153:6: MemberRefExpr=Case:88:42 SingleRefName=[153:6 - 153:10] RefName=[153:6 - 153:10] Extent=[105:10 - 153:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 152:41]
-// CHECK: 152:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 152:10]
+// CHECK: 152:6: MemberRefExpr=Case:88:42 SingleRefName=[152:6 - 152:10] RefName=[152:6 - 152:10] Extent=[105:10 - 152:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 151:39]
-// CHECK: 151:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 151:10]
+// CHECK: 151:6: MemberRefExpr=Case:88:42 SingleRefName=[151:6 - 151:10] RefName=[151:6 - 151:10] Extent=[105:10 - 151:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 150:39]
-// CHECK: 150:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 150:10]
+// CHECK: 150:6: MemberRefExpr=Case:88:42 SingleRefName=[150:6 - 150:10] RefName=[150:6 - 150:10] Extent=[105:10 - 150:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 149:39]
-// CHECK: 149:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 149:10]
+// CHECK: 149:6: MemberRefExpr=Case:88:42 SingleRefName=[149:6 - 149:10] RefName=[149:6 - 149:10] Extent=[105:10 - 149:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 148:39]
-// CHECK: 148:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 148:10]
+// CHECK: 148:6: MemberRefExpr=Case:88:42 SingleRefName=[148:6 - 148:10] RefName=[148:6 - 148:10] Extent=[105:10 - 148:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 147:39]
-// CHECK: 147:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 147:10]
+// CHECK: 147:6: MemberRefExpr=Case:88:42 SingleRefName=[147:6 - 147:10] RefName=[147:6 - 147:10] Extent=[105:10 - 147:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 146:39]
-// CHECK: 146:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 146:10]
+// CHECK: 146:6: MemberRefExpr=Case:88:42 SingleRefName=[146:6 - 146:10] RefName=[146:6 - 146:10] Extent=[105:10 - 146:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 145:41]
-// CHECK: 145:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 145:10]
+// CHECK: 145:6: MemberRefExpr=Case:88:42 SingleRefName=[145:6 - 145:10] RefName=[145:6 - 145:10] Extent=[105:10 - 145:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 144:37]
-// CHECK: 144:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 144:10]
+// CHECK: 144:6: MemberRefExpr=Case:88:42 SingleRefName=[144:6 - 144:10] RefName=[144:6 - 144:10] Extent=[105:10 - 144:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 143:37]
-// CHECK: 143:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 143:10]
+// CHECK: 143:6: MemberRefExpr=Case:88:42 SingleRefName=[143:6 - 143:10] RefName=[143:6 - 143:10] Extent=[105:10 - 143:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 142:35]
-// CHECK: 142:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 142:10]
+// CHECK: 142:6: MemberRefExpr=Case:88:42 SingleRefName=[142:6 - 142:10] RefName=[142:6 - 142:10] Extent=[105:10 - 142:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 141:35]
-// CHECK: 141:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 141:10]
+// CHECK: 141:6: MemberRefExpr=Case:88:42 SingleRefName=[141:6 - 141:10] RefName=[141:6 - 141:10] Extent=[105:10 - 141:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 140:35]
-// CHECK: 140:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 140:10]
+// CHECK: 140:6: MemberRefExpr=Case:88:42 SingleRefName=[140:6 - 140:10] RefName=[140:6 - 140:10] Extent=[105:10 - 140:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 139:35]
-// CHECK: 139:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 139:10]
+// CHECK: 139:6: MemberRefExpr=Case:88:42 SingleRefName=[139:6 - 139:10] RefName=[139:6 - 139:10] Extent=[105:10 - 139:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 138:35]
-// CHECK: 138:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 138:10]
+// CHECK: 138:6: MemberRefExpr=Case:88:42 SingleRefName=[138:6 - 138:10] RefName=[138:6 - 138:10] Extent=[105:10 - 138:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 137:55]
-// CHECK: 137:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 137:10]
+// CHECK: 137:6: MemberRefExpr=Case:88:42 SingleRefName=[137:6 - 137:10] RefName=[137:6 - 137:10] Extent=[105:10 - 137:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 136:35]
-// CHECK: 136:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 136:10]
+// CHECK: 136:6: MemberRefExpr=Case:88:42 SingleRefName=[136:6 - 136:10] RefName=[136:6 - 136:10] Extent=[105:10 - 136:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 135:35]
-// CHECK: 135:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 135:10]
+// CHECK: 135:6: MemberRefExpr=Case:88:42 SingleRefName=[135:6 - 135:10] RefName=[135:6 - 135:10] Extent=[105:10 - 135:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 134:35]
-// CHECK: 134:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 134:10]
+// CHECK: 134:6: MemberRefExpr=Case:88:42 SingleRefName=[134:6 - 134:10] RefName=[134:6 - 134:10] Extent=[105:10 - 134:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 133:35]
-// CHECK: 133:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 133:10]
+// CHECK: 133:6: MemberRefExpr=Case:88:42 SingleRefName=[133:6 - 133:10] RefName=[133:6 - 133:10] Extent=[105:10 - 133:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 132:33]
-// CHECK: 132:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 132:10]
+// CHECK: 132:6: MemberRefExpr=Case:88:42 SingleRefName=[132:6 - 132:10] RefName=[132:6 - 132:10] Extent=[105:10 - 132:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 131:33]
-// CHECK: 131:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 131:10]
+// CHECK: 131:6: MemberRefExpr=Case:88:42 SingleRefName=[131:6 - 131:10] RefName=[131:6 - 131:10] Extent=[105:10 - 131:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 130:33]
-// CHECK: 130:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 130:10]
+// CHECK: 130:6: MemberRefExpr=Case:88:42 SingleRefName=[130:6 - 130:10] RefName=[130:6 - 130:10] Extent=[105:10 - 130:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 129:33]
-// CHECK: 129:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 129:10]
+// CHECK: 129:6: MemberRefExpr=Case:88:42 SingleRefName=[129:6 - 129:10] RefName=[129:6 - 129:10] Extent=[105:10 - 129:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 128:33]
-// CHECK: 128:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 128:10]
+// CHECK: 128:6: MemberRefExpr=Case:88:42 SingleRefName=[128:6 - 128:10] RefName=[128:6 - 128:10] Extent=[105:10 - 128:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 127:33]
-// CHECK: 127:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 127:10]
+// CHECK: 127:6: MemberRefExpr=Case:88:42 SingleRefName=[127:6 - 127:10] RefName=[127:6 - 127:10] Extent=[105:10 - 127:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 126:33]
-// CHECK: 126:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 126:10]
+// CHECK: 126:6: MemberRefExpr=Case:88:42 SingleRefName=[126:6 - 126:10] RefName=[126:6 - 126:10] Extent=[105:10 - 126:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 125:29]
-// CHECK: 125:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 125:10]
+// CHECK: 125:6: MemberRefExpr=Case:88:42 SingleRefName=[125:6 - 125:10] RefName=[125:6 - 125:10] Extent=[105:10 - 125:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 124:33]
-// CHECK: 124:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 124:10]
+// CHECK: 124:6: MemberRefExpr=Case:88:42 SingleRefName=[124:6 - 124:10] RefName=[124:6 - 124:10] Extent=[105:10 - 124:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 123:33]
-// CHECK: 123:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 123:10]
+// CHECK: 123:6: MemberRefExpr=Case:88:42 SingleRefName=[123:6 - 123:10] RefName=[123:6 - 123:10] Extent=[105:10 - 123:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 122:31]
-// CHECK: 122:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 122:10]
+// CHECK: 122:6: MemberRefExpr=Case:88:42 SingleRefName=[122:6 - 122:10] RefName=[122:6 - 122:10] Extent=[105:10 - 122:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 121:31]
-// CHECK: 121:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 121:10]
+// CHECK: 121:6: MemberRefExpr=Case:88:42 SingleRefName=[121:6 - 121:10] RefName=[121:6 - 121:10] Extent=[105:10 - 121:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 120:31]
-// CHECK: 120:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 120:10]
+// CHECK: 120:6: MemberRefExpr=Case:88:42 SingleRefName=[120:6 - 120:10] RefName=[120:6 - 120:10] Extent=[105:10 - 120:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 119:31]
-// CHECK: 119:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 119:10]
+// CHECK: 119:6: MemberRefExpr=Case:88:42 SingleRefName=[119:6 - 119:10] RefName=[119:6 - 119:10] Extent=[105:10 - 119:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 118:31]
-// CHECK: 118:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 118:10]
+// CHECK: 118:6: MemberRefExpr=Case:88:42 SingleRefName=[118:6 - 118:10] RefName=[118:6 - 118:10] Extent=[105:10 - 118:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 117:31]
-// CHECK: 117:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 117:10]
+// CHECK: 117:6: MemberRefExpr=Case:88:42 SingleRefName=[117:6 - 117:10] RefName=[117:6 - 117:10] Extent=[105:10 - 117:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 116:31]
-// CHECK: 116:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 116:10]
+// CHECK: 116:6: MemberRefExpr=Case:88:42 SingleRefName=[116:6 - 116:10] RefName=[116:6 - 116:10] Extent=[105:10 - 116:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 115:29]
-// CHECK: 115:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 115:10]
+// CHECK: 115:6: MemberRefExpr=Case:88:42 SingleRefName=[115:6 - 115:10] RefName=[115:6 - 115:10] Extent=[105:10 - 115:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 114:29]
-// CHECK: 114:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 114:10]
+// CHECK: 114:6: MemberRefExpr=Case:88:42 SingleRefName=[114:6 - 114:10] RefName=[114:6 - 114:10] Extent=[105:10 - 114:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 113:29]
-// CHECK: 113:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 113:10]
+// CHECK: 113:6: MemberRefExpr=Case:88:42 SingleRefName=[113:6 - 113:10] RefName=[113:6 - 113:10] Extent=[105:10 - 113:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 112:31]
-// CHECK: 112:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 112:10]
+// CHECK: 112:6: MemberRefExpr=Case:88:42 SingleRefName=[112:6 - 112:10] RefName=[112:6 - 112:10] Extent=[105:10 - 112:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 111:29]
-// CHECK: 111:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 111:10]
+// CHECK: 111:6: MemberRefExpr=Case:88:42 SingleRefName=[111:6 - 111:10] RefName=[111:6 - 111:10] Extent=[105:10 - 111:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 110:27]
-// CHECK: 110:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 110:10]
+// CHECK: 110:6: MemberRefExpr=Case:88:42 SingleRefName=[110:6 - 110:10] RefName=[110:6 - 110:10] Extent=[105:10 - 110:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 109:27]
-// CHECK: 109:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 109:10]
+// CHECK: 109:6: MemberRefExpr=Case:88:42 SingleRefName=[109:6 - 109:10] RefName=[109:6 - 109:10] Extent=[105:10 - 109:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 108:27]
-// CHECK: 108:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 108:10]
+// CHECK: 108:6: MemberRefExpr=Case:88:42 SingleRefName=[108:6 - 108:10] RefName=[108:6 - 108:10] Extent=[105:10 - 108:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 107:33]
-// CHECK: 107:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 107:10]
+// CHECK: 107:6: MemberRefExpr=Case:88:42 SingleRefName=[107:6 - 107:10] RefName=[107:6 - 107:10] Extent=[105:10 - 107:10]
// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 106:27]
-// CHECK: 106:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 106:10]
-// CHECK: 105:10: UnexposedExpr=StringSwitch:87:12 Extent=[105:10 - 105:63]
+// CHECK: 106:6: MemberRefExpr=Case:88:42 SingleRefName=[106:6 - 106:10] RefName=[106:6 - 106:10] Extent=[105:10 - 106:10]
+// CHECK: 105:10: CXXFunctionalCastExpr= Extent=[105:10 - 105:63]
// CHECK: 105:16: TemplateRef=StringSwitch:83:47 Extent=[105:16 - 105:28]
// CHECK: 105:10: CallExpr=StringSwitch:87:12 Extent=[105:10 - 105:62]
// CHECK: 105:54: CallExpr=StringRef:38:7 Extent=[105:54 - 105:62]
// CHECK: 105:54: UnexposedExpr=AttrName:101:19 Extent=[105:54 - 105:62]
// CHECK: 105:54: DeclRefExpr=AttrName:101:19 Extent=[105:54 - 105:62]
-// CHECK: 106:11: UnexposedExpr= Extent=[106:11 - 106:17]
+// CHECK: 106:11: StringLiteral= Extent=[106:11 - 106:17]
// CHECK: 106:19: DeclRefExpr=AT_weak:29:45 Extent=[106:19 - 106:26]
-// CHECK: 107:11: UnexposedExpr= Extent=[107:11 - 107:20]
+// CHECK: 107:11: StringLiteral= Extent=[107:11 - 107:20]
// CHECK: 107:22: DeclRefExpr=AT_weakref:29:54 Extent=[107:22 - 107:32]
-// CHECK: 108:11: UnexposedExpr= Extent=[108:11 - 108:17]
+// CHECK: 108:11: StringLiteral= Extent=[108:11 - 108:17]
// CHECK: 108:19: DeclRefExpr=AT_pure:26:49 Extent=[108:19 - 108:26]
-// CHECK: 109:11: UnexposedExpr= Extent=[109:11 - 109:17]
+// CHECK: 109:11: StringLiteral= Extent=[109:11 - 109:17]
// CHECK: 109:19: DeclRefExpr=AT_mode:20:44 Extent=[109:19 - 109:26]
-// CHECK: 110:11: UnexposedExpr= Extent=[110:11 - 110:17]
+// CHECK: 110:11: StringLiteral= Extent=[110:11 - 110:17]
// CHECK: 110:19: DeclRefExpr=AT_used:28:34 Extent=[110:19 - 110:26]
-// CHECK: 111:11: UnexposedExpr= Extent=[111:11 - 111:18]
+// CHECK: 111:11: StringLiteral= Extent=[111:11 - 111:18]
// CHECK: 111:20: DeclRefExpr=AT_alias:15:25 Extent=[111:20 - 111:28]
-// CHECK: 112:11: UnexposedExpr= Extent=[112:11 - 112:18]
+// CHECK: 112:11: StringLiteral= Extent=[112:11 - 112:18]
// CHECK: 112:20: DeclRefExpr=AT_aligned:15:35 Extent=[112:20 - 112:30]
-// CHECK: 113:11: UnexposedExpr= Extent=[113:11 - 113:18]
+// CHECK: 113:11: StringLiteral= Extent=[113:11 - 113:18]
// CHECK: 113:20: DeclRefExpr=AT_final:19:40 Extent=[113:20 - 113:28]
-// CHECK: 114:11: UnexposedExpr= Extent=[114:11 - 114:18]
+// CHECK: 114:11: StringLiteral= Extent=[114:11 - 114:18]
// CHECK: 114:20: DeclRefExpr=AT_cdecl:17:30 Extent=[114:20 - 114:28]
-// CHECK: 115:11: UnexposedExpr= Extent=[115:11 - 115:18]
+// CHECK: 115:11: StringLiteral= Extent=[115:11 - 115:18]
// CHECK: 115:20: DeclRefExpr=AT_const:17:52 Extent=[115:20 - 115:28]
-// CHECK: 116:11: UnexposedExpr= Extent=[116:11 - 116:20]
+// CHECK: 116:11: StringLiteral= Extent=[116:11 - 116:20]
// CHECK: 116:22: DeclRefExpr=AT_const:17:52 Extent=[116:22 - 116:30]
-// CHECK: 117:11: UnexposedExpr= Extent=[117:11 - 117:19]
+// CHECK: 117:11: StringLiteral= Extent=[117:11 - 117:19]
// CHECK: 117:21: DeclRefExpr=AT_blocks:16:57 Extent=[117:21 - 117:30]
-// CHECK: 118:11: UnexposedExpr= Extent=[118:11 - 118:19]
+// CHECK: 118:11: StringLiteral= Extent=[118:11 - 118:19]
// CHECK: 118:21: DeclRefExpr=AT_format:19:50 Extent=[118:21 - 118:30]
-// CHECK: 119:11: UnexposedExpr= Extent=[119:11 - 119:19]
+// CHECK: 119:11: StringLiteral= Extent=[119:11 - 119:19]
// CHECK: 119:21: DeclRefExpr=AT_hiding:20:22 Extent=[119:21 - 119:30]
-// CHECK: 120:11: UnexposedExpr= Extent=[120:11 - 120:19]
+// CHECK: 120:11: StringLiteral= Extent=[120:11 - 120:19]
// CHECK: 120:21: DeclRefExpr=AT_malloc:20:33 Extent=[120:21 - 120:30]
-// CHECK: 121:11: UnexposedExpr= Extent=[121:11 - 121:19]
+// CHECK: 121:11: StringLiteral= Extent=[121:11 - 121:19]
// CHECK: 121:21: DeclRefExpr=AT_packed:26:27 Extent=[121:21 - 121:30]
-// CHECK: 122:11: UnexposedExpr= Extent=[122:11 - 122:19]
+// CHECK: 122:11: StringLiteral= Extent=[122:11 - 122:19]
// CHECK: 122:21: DeclRefExpr=AT_unused:28:23 Extent=[122:21 - 122:30]
-// CHECK: 123:11: UnexposedExpr= Extent=[123:11 - 123:20]
+// CHECK: 123:11: StringLiteral= Extent=[123:11 - 123:20]
// CHECK: 123:22: DeclRefExpr=AT_aligned:15:35 Extent=[123:22 - 123:32]
-// CHECK: 124:11: UnexposedExpr= Extent=[124:11 - 124:20]
+// CHECK: 124:11: StringLiteral= Extent=[124:11 - 124:20]
// CHECK: 124:22: DeclRefExpr=AT_cleanup:17:40 Extent=[124:22 - 124:32]
-// CHECK: 125:11: UnexposedExpr= Extent=[125:11 - 125:18]
+// CHECK: 125:11: StringLiteral= Extent=[125:11 - 125:18]
// CHECK: 125:20: DeclRefExpr=AT_naked:20:53 Extent=[125:20 - 125:28]
-// CHECK: 126:11: UnexposedExpr= Extent=[126:11 - 126:20]
+// CHECK: 126:11: StringLiteral= Extent=[126:11 - 126:20]
// CHECK: 126:22: DeclRefExpr=AT_nodebug:20:63 Extent=[126:22 - 126:32]
-// CHECK: 127:11: UnexposedExpr= Extent=[127:11 - 127:20]
+// CHECK: 127:11: StringLiteral= Extent=[127:11 - 127:20]
// CHECK: 127:22: DeclRefExpr=AT_nonnull:21:47 Extent=[127:22 - 127:32]
-// CHECK: 128:11: UnexposedExpr= Extent=[128:11 - 128:20]
+// CHECK: 128:11: StringLiteral= Extent=[128:11 - 128:20]
// CHECK: 128:22: DeclRefExpr=AT_nothrow:22:7 Extent=[128:22 - 128:32]
-// CHECK: 129:11: UnexposedExpr= Extent=[129:11 - 129:20]
+// CHECK: 129:11: StringLiteral= Extent=[129:11 - 129:20]
// CHECK: 129:22: DeclRefExpr=AT_objc_gc:24:59 Extent=[129:22 - 129:32]
-// CHECK: 130:11: UnexposedExpr= Extent=[130:11 - 130:20]
+// CHECK: 130:11: StringLiteral= Extent=[130:11 - 130:20]
// CHECK: 130:22: DeclRefExpr=AT_regparm:26:58 Extent=[130:22 - 130:32]
-// CHECK: 131:11: UnexposedExpr= Extent=[131:11 - 131:20]
+// CHECK: 131:11: StringLiteral= Extent=[131:11 - 131:20]
// CHECK: 131:22: DeclRefExpr=AT_section:27:7 Extent=[131:22 - 131:32]
-// CHECK: 132:11: UnexposedExpr= Extent=[132:11 - 132:20]
+// CHECK: 132:11: StringLiteral= Extent=[132:11 - 132:20]
// CHECK: 132:22: DeclRefExpr=AT_stdcall:27:32 Extent=[132:22 - 132:32]
-// CHECK: 133:11: UnexposedExpr= Extent=[133:11 - 133:21]
+// CHECK: 133:11: StringLiteral= Extent=[133:11 - 133:21]
// CHECK: 133:23: DeclRefExpr=AT_annotate:16:29 Extent=[133:23 - 133:34]
-// CHECK: 134:11: UnexposedExpr= Extent=[134:11 - 134:21]
+// CHECK: 134:11: StringLiteral= Extent=[134:11 - 134:21]
// CHECK: 134:23: DeclRefExpr=AT_fastcall:19:27 Extent=[134:23 - 134:34]
-// CHECK: 135:11: UnexposedExpr= Extent=[135:11 - 135:21]
+// CHECK: 135:11: StringLiteral= Extent=[135:11 - 135:21]
// CHECK: 135:23: DeclRefExpr=AT_IBAction:14:7 Extent=[135:23 - 135:34]
-// CHECK: 136:11: UnexposedExpr= Extent=[136:11 - 136:21]
+// CHECK: 136:11: StringLiteral= Extent=[136:11 - 136:21]
// CHECK: 136:23: DeclRefExpr=AT_IBOutlet:14:20 Extent=[136:23 - 136:34]
-// CHECK: 137:11: UnexposedExpr= Extent=[137:11 - 137:31]
+// CHECK: 137:11: StringLiteral= Extent=[137:11 - 137:31]
// CHECK: 137:33: DeclRefExpr=AT_IBOutletCollection:14:33 Extent=[137:33 - 137:54]
-// CHECK: 138:11: UnexposedExpr= Extent=[138:11 - 138:21]
+// CHECK: 138:11: StringLiteral= Extent=[138:11 - 138:21]
// CHECK: 138:23: DeclRefExpr=AT_noreturn:21:59 Extent=[138:23 - 138:34]
-// CHECK: 139:11: UnexposedExpr= Extent=[139:11 - 139:21]
+// CHECK: 139:11: StringLiteral= Extent=[139:11 - 139:21]
// CHECK: 139:23: DeclRefExpr=AT_noinline:21:7 Extent=[139:23 - 139:34]
-// CHECK: 140:11: UnexposedExpr= Extent=[140:11 - 140:21]
+// CHECK: 140:11: StringLiteral= Extent=[140:11 - 140:21]
// CHECK: 140:23: DeclRefExpr=AT_override:22:51 Extent=[140:23 - 140:34]
-// CHECK: 141:11: UnexposedExpr= Extent=[141:11 - 141:21]
+// CHECK: 141:11: StringLiteral= Extent=[141:11 - 141:21]
// CHECK: 141:23: DeclRefExpr=AT_sentinel:27:19 Extent=[141:23 - 141:34]
-// CHECK: 142:11: UnexposedExpr= Extent=[142:11 - 142:21]
+// CHECK: 142:11: StringLiteral= Extent=[142:11 - 142:21]
// CHECK: 142:23: DeclRefExpr=AT_nsobject:22:19 Extent=[142:23 - 142:34]
-// CHECK: 143:11: UnexposedExpr= Extent=[143:11 - 143:22]
+// CHECK: 143:11: StringLiteral= Extent=[143:11 - 143:22]
// CHECK: 143:24: DeclRefExpr=AT_dllimport:18:51 Extent=[143:24 - 143:36]
-// CHECK: 144:11: UnexposedExpr= Extent=[144:11 - 144:22]
+// CHECK: 144:11: StringLiteral= Extent=[144:11 - 144:22]
// CHECK: 144:24: DeclRefExpr=AT_dllexport:18:37 Extent=[144:24 - 144:36]
-// CHECK: 145:11: UnexposedExpr= Extent=[145:11 - 145:22]
-// CHECK: 145:24: DeclRefExpr=IgnoredAttribute:31:7 Extent=[145:24 - 145:40]
-// CHECK: 146:11: UnexposedExpr= Extent=[146:11 - 146:23]
+// CHECK: 145:11: StringLiteral= Extent=[145:11 - 145:22]
+// CHECK: 146:11: StringLiteral= Extent=[146:11 - 146:23]
// CHECK: 146:25: DeclRefExpr=AT_base_check:16:42 Extent=[146:25 - 146:38]
-// CHECK: 147:11: UnexposedExpr= Extent=[147:11 - 147:23]
+// CHECK: 147:11: StringLiteral= Extent=[147:11 - 147:23]
// CHECK: 147:25: DeclRefExpr=AT_deprecated:18:7 Extent=[147:25 - 147:38]
-// CHECK: 148:11: UnexposedExpr= Extent=[148:11 - 148:23]
+// CHECK: 148:11: StringLiteral= Extent=[148:11 - 148:23]
// CHECK: 148:25: DeclRefExpr=AT_visibility:29:7 Extent=[148:25 - 148:38]
-// CHECK: 149:11: UnexposedExpr= Extent=[149:11 - 149:23]
+// CHECK: 149:11: StringLiteral= Extent=[149:11 - 149:23]
// CHECK: 149:25: DeclRefExpr=AT_destructor:18:22 Extent=[149:25 - 149:38]
-// CHECK: 150:11: UnexposedExpr= Extent=[150:11 - 150:23]
+// CHECK: 150:11: StringLiteral= Extent=[150:11 - 150:23]
// CHECK: 150:25: DeclRefExpr=AT_format_arg:19:61 Extent=[150:25 - 150:38]
-// CHECK: 151:11: UnexposedExpr= Extent=[151:11 - 151:23]
+// CHECK: 151:11: StringLiteral= Extent=[151:11 - 151:23]
// CHECK: 151:25: DeclRefExpr=AT_gnu_inline:20:7 Extent=[151:25 - 151:38]
-// CHECK: 152:11: UnexposedExpr= Extent=[152:11 - 152:24]
+// CHECK: 152:11: StringLiteral= Extent=[152:11 - 152:24]
// CHECK: 152:26: DeclRefExpr=AT_weak_import:30:7 Extent=[152:26 - 152:40]
-// CHECK: 153:11: UnexposedExpr= Extent=[153:11 - 153:22]
+// CHECK: 153:11: StringLiteral= Extent=[153:11 - 153:22]
// CHECK: 153:24: DeclRefExpr=AT_vecreturn:28:43 Extent=[153:24 - 153:36]
-// CHECK: 154:11: UnexposedExpr= Extent=[154:11 - 154:24]
+// CHECK: 154:11: StringLiteral= Extent=[154:11 - 154:24]
// CHECK: 154:26: DeclRefExpr=AT_vector_size:28:57 Extent=[154:26 - 154:40]
-// CHECK: 155:11: UnexposedExpr= Extent=[155:11 - 155:24]
+// CHECK: 155:11: StringLiteral= Extent=[155:11 - 155:24]
// CHECK: 155:26: DeclRefExpr=AT_constructor:17:62 Extent=[155:26 - 155:40]
-// CHECK: 156:11: UnexposedExpr= Extent=[156:11 - 156:24]
+// CHECK: 156:11: StringLiteral= Extent=[156:11 - 156:24]
// CHECK: 156:26: DeclRefExpr=AT_unavailable:28:7 Extent=[156:26 - 156:40]
-// CHECK: 157:11: UnexposedExpr= Extent=[157:11 - 157:25]
+// CHECK: 157:11: StringLiteral= Extent=[157:11 - 157:25]
// CHECK: 157:27: DeclRefExpr=AT_overloadable:25:7 Extent=[157:27 - 157:42]
-// CHECK: 158:11: UnexposedExpr= Extent=[158:11 - 158:26]
+// CHECK: 158:11: StringLiteral= Extent=[158:11 - 158:26]
// CHECK: 158:28: DeclRefExpr=AT_address_space:15:7 Extent=[158:28 - 158:44]
-// CHECK: 159:11: UnexposedExpr= Extent=[159:11 - 159:26]
+// CHECK: 159:11: StringLiteral= Extent=[159:11 - 159:26]
// CHECK: 159:28: DeclRefExpr=AT_always_inline:15:47 Extent=[159:28 - 159:44]
-// CHECK: 160:11: UnexposedExpr= Extent=[160:11 - 160:26]
-// CHECK: 160:28: DeclRefExpr=IgnoredAttribute:31:7 Extent=[160:28 - 160:44]
-// CHECK: 161:11: UnexposedExpr= Extent=[161:11 - 161:26]
-// CHECK: 161:28: DeclRefExpr=IgnoredAttribute:31:7 Extent=[161:28 - 161:44]
-// CHECK: 162:11: UnexposedExpr= Extent=[162:11 - 162:27]
+// CHECK: 160:11: StringLiteral= Extent=[160:11 - 160:26]
+// CHECK: 161:11: StringLiteral= Extent=[161:11 - 161:26]
+// CHECK: 162:11: StringLiteral= Extent=[162:11 - 162:27]
// CHECK: 162:29: DeclRefExpr=AT_objc_exception:22:32 Extent=[162:29 - 162:46]
-// CHECK: 163:11: UnexposedExpr= Extent=[163:11 - 163:28]
+// CHECK: 163:11: StringLiteral= Extent=[163:11 - 163:28]
// CHECK: 163:30: DeclRefExpr=AT_ext_vector_type:19:7 Extent=[163:30 - 163:48]
-// CHECK: 164:11: UnexposedExpr= Extent=[164:11 - 164:30]
+// CHECK: 164:11: StringLiteral= Extent=[164:11 - 164:30]
// CHECK: 164:32: DeclRefExpr=AT_transparent_union:27:57 Extent=[164:32 - 164:52]
-// CHECK: 165:11: UnexposedExpr= Extent=[165:11 - 165:30]
+// CHECK: 165:11: StringLiteral= Extent=[165:11 - 165:30]
// CHECK: 165:32: DeclRefExpr=AT_analyzer_noreturn:16:7 Extent=[165:32 - 165:52]
-// CHECK: 166:11: UnexposedExpr= Extent=[166:11 - 166:31]
+// CHECK: 166:11: StringLiteral= Extent=[166:11 - 166:31]
// CHECK: 166:33: DeclRefExpr=AT_warn_unused_result:29:22 Extent=[166:33 - 166:54]
-// CHECK: 167:11: UnexposedExpr= Extent=[167:11 - 167:31]
+// CHECK: 167:11: StringLiteral= Extent=[167:11 - 167:31]
// CHECK: 167:33: DeclRefExpr=AT_carries_dependency:17:7 Extent=[167:33 - 167:54]
-// CHECK: 168:11: UnexposedExpr= Extent=[168:11 - 168:36]
+// CHECK: 168:11: StringLiteral= Extent=[168:11 - 168:36]
// CHECK: 168:38: DeclRefExpr=AT_ns_returns_not_retained:24:7 Extent=[168:38 - 168:64]
-// CHECK: 169:11: UnexposedExpr= Extent=[169:11 - 169:32]
+// CHECK: 169:11: StringLiteral= Extent=[169:11 - 169:32]
// CHECK: 169:34: DeclRefExpr=AT_ns_returns_retained:24:35 Extent=[169:34 - 169:56]
-// CHECK: 170:11: UnexposedExpr= Extent=[170:11 - 170:36]
+// CHECK: 170:11: StringLiteral= Extent=[170:11 - 170:36]
// CHECK: 170:38: DeclRefExpr=AT_cf_returns_not_retained:23:7 Extent=[170:38 - 170:64]
-// CHECK: 171:11: UnexposedExpr= Extent=[171:11 - 171:32]
+// CHECK: 171:11: StringLiteral= Extent=[171:11 - 171:32]
// CHECK: 171:34: DeclRefExpr=AT_cf_returns_retained:23:35 Extent=[171:34 - 171:56]
-// CHECK: 172:11: UnexposedExpr= Extent=[172:11 - 172:30]
+// CHECK: 172:11: StringLiteral= Extent=[172:11 - 172:30]
// CHECK: 172:32: DeclRefExpr=AT_ownership_returns:25:44 Extent=[172:32 - 172:52]
-// CHECK: 173:11: UnexposedExpr= Extent=[173:11 - 173:28]
+// CHECK: 173:11: StringLiteral= Extent=[173:11 - 173:28]
// CHECK: 173:30: DeclRefExpr=AT_ownership_holds:25:24 Extent=[173:30 - 173:48]
-// CHECK: 174:11: UnexposedExpr= Extent=[174:11 - 174:28]
+// CHECK: 174:11: StringLiteral= Extent=[174:11 - 174:28]
// CHECK: 174:30: DeclRefExpr=AT_ownership_takes:26:7 Extent=[174:30 - 174:48]
-// CHECK: 175:11: UnexposedExpr= Extent=[175:11 - 175:33]
+// CHECK: 175:11: StringLiteral= Extent=[175:11 - 175:33]
// CHECK: 175:35: DeclRefExpr=AT_reqd_wg_size:30:23 Extent=[175:35 - 175:50]
-// CHECK: 176:11: UnexposedExpr= Extent=[176:11 - 176:26]
+// CHECK: 176:11: StringLiteral= Extent=[176:11 - 176:26]
// CHECK: 176:28: DeclRefExpr=AT_init_priority:30:40 Extent=[176:28 - 176:44]
-// CHECK: 177:11: UnexposedExpr= Extent=[177:11 - 177:35]
+// CHECK: 177:11: StringLiteral= Extent=[177:11 - 177:35]
// CHECK: 177:37: DeclRefExpr=AT_no_instrument_function:21:20 Extent=[177:37 - 177:62]
-// CHECK: 178:11: UnexposedExpr= Extent=[178:11 - 178:21]
+// CHECK: 178:11: StringLiteral= Extent=[178:11 - 178:21]
// CHECK: 178:23: DeclRefExpr=AT_thiscall:27:44 Extent=[178:23 - 178:34]
-// CHECK: 179:11: UnexposedExpr= Extent=[179:11 - 179:19]
+// CHECK: 179:11: StringLiteral= Extent=[179:11 - 179:19]
// CHECK: 179:21: DeclRefExpr=AT_pascal:26:38 Extent=[179:21 - 179:30]
-// CHECK: 180:11: UnexposedExpr= Extent=[180:11 - 180:20]
+// CHECK: 180:11: StringLiteral= Extent=[180:11 - 180:20]
// CHECK: 180:22: DeclRefExpr=AT_cdecl:17:30 Extent=[180:22 - 180:30]
-// CHECK: 181:11: UnexposedExpr= Extent=[181:11 - 181:22]
+// CHECK: 181:11: StringLiteral= Extent=[181:11 - 181:22]
// CHECK: 181:24: DeclRefExpr=AT_stdcall:27:32 Extent=[181:24 - 181:34]
-// CHECK: 182:11: UnexposedExpr= Extent=[182:11 - 182:23]
+// CHECK: 182:11: StringLiteral= Extent=[182:11 - 182:23]
// CHECK: 182:25: DeclRefExpr=AT_fastcall:19:27 Extent=[182:25 - 182:36]
-// CHECK: 183:11: UnexposedExpr= Extent=[183:11 - 183:23]
+// CHECK: 183:11: StringLiteral= Extent=[183:11 - 183:23]
// CHECK: 183:25: DeclRefExpr=AT_thiscall:27:44 Extent=[183:25 - 183:36]
-// CHECK: 184:11: UnexposedExpr= Extent=[184:11 - 184:21]
+// CHECK: 184:11: StringLiteral= Extent=[184:11 - 184:21]
// CHECK: 184:23: DeclRefExpr=AT_pascal:26:38 Extent=[184:23 - 184:32]
-// CHECK: 185:14: DeclRefExpr=UnknownAttribute:31:25 Extent=[185:14 - 185:30]
diff --git a/test/Index/recursive-member-access.c b/test/Index/recursive-member-access.c
index 87855ca36159..6a19f578d707 100644
--- a/test/Index/recursive-member-access.c
+++ b/test/Index/recursive-member-access.c
@@ -131,126 +131,126 @@ int test_rdar8650865(struct rdar8650865 *s) {
// CHECK: 6:5: FunctionDecl=test_rdar8650865:6:5 (Definition) Extent=[6:1 - 124:2]
// CHECK: 6:42: ParmDecl=s:6:42 (Definition) Extent=[6:22 - 6:43]
// CHECK: 6:29: TypeRef=struct rdar8650865:1:8 Extent=[6:29 - 6:40]
-// CHECK: 6:45: UnexposedStmt= Extent=[6:45 - 124:2]
-// CHECK: 7:3: UnexposedStmt= Extent=[7:3 - 123:8]
-// CHECK: 123:7: MemberRefExpr=x:3:7 Extent=[7:10 - 123:8]
-// CHECK: 122:7: MemberRefExpr=first:2:23 Extent=[7:10 - 122:12]
-// CHECK: 121:7: MemberRefExpr=first:2:23 Extent=[7:10 - 121:12]
-// CHECK: 120:7: MemberRefExpr=first:2:23 Extent=[7:10 - 120:12]
-// CHECK: 119:7: MemberRefExpr=first:2:23 Extent=[7:10 - 119:12]
-// CHECK: 118:7: MemberRefExpr=first:2:23 Extent=[7:10 - 118:12]
-// CHECK: 117:7: MemberRefExpr=first:2:23 Extent=[7:10 - 117:12]
-// CHECK: 116:7: MemberRefExpr=first:2:23 Extent=[7:10 - 116:12]
-// CHECK: 115:7: MemberRefExpr=first:2:23 Extent=[7:10 - 115:12]
-// CHECK: 114:7: MemberRefExpr=first:2:23 Extent=[7:10 - 114:12]
-// CHECK: 113:7: MemberRefExpr=first:2:23 Extent=[7:10 - 113:12]
-// CHECK: 112:7: MemberRefExpr=first:2:23 Extent=[7:10 - 112:12]
-// CHECK: 111:7: MemberRefExpr=first:2:23 Extent=[7:10 - 111:12]
-// CHECK: 110:7: MemberRefExpr=first:2:23 Extent=[7:10 - 110:12]
-// CHECK: 109:7: MemberRefExpr=first:2:23 Extent=[7:10 - 109:12]
-// CHECK: 108:7: MemberRefExpr=first:2:23 Extent=[7:10 - 108:12]
-// CHECK: 107:7: MemberRefExpr=first:2:23 Extent=[7:10 - 107:12]
-// CHECK: 106:7: MemberRefExpr=first:2:23 Extent=[7:10 - 106:12]
-// CHECK: 105:7: MemberRefExpr=first:2:23 Extent=[7:10 - 105:12]
-// CHECK: 104:7: MemberRefExpr=first:2:23 Extent=[7:10 - 104:12]
-// CHECK: 103:7: MemberRefExpr=first:2:23 Extent=[7:10 - 103:12]
-// CHECK: 102:7: MemberRefExpr=first:2:23 Extent=[7:10 - 102:12]
-// CHECK: 101:7: MemberRefExpr=first:2:23 Extent=[7:10 - 101:12]
-// CHECK: 100:7: MemberRefExpr=first:2:23 Extent=[7:10 - 100:12]
-// CHECK: 99:7: MemberRefExpr=first:2:23 Extent=[7:10 - 99:12]
-// CHECK: 98:7: MemberRefExpr=first:2:23 Extent=[7:10 - 98:12]
-// CHECK: 97:7: MemberRefExpr=first:2:23 Extent=[7:10 - 97:12]
-// CHECK: 96:7: MemberRefExpr=first:2:23 Extent=[7:10 - 96:12]
-// CHECK: 95:7: MemberRefExpr=first:2:23 Extent=[7:10 - 95:12]
-// CHECK: 94:7: MemberRefExpr=first:2:23 Extent=[7:10 - 94:12]
-// CHECK: 93:7: MemberRefExpr=first:2:23 Extent=[7:10 - 93:12]
-// CHECK: 92:7: MemberRefExpr=first:2:23 Extent=[7:10 - 92:12]
-// CHECK: 91:7: MemberRefExpr=first:2:23 Extent=[7:10 - 91:12]
-// CHECK: 90:7: MemberRefExpr=first:2:23 Extent=[7:10 - 90:12]
-// CHECK: 89:7: MemberRefExpr=first:2:23 Extent=[7:10 - 89:12]
-// CHECK: 88:7: MemberRefExpr=first:2:23 Extent=[7:10 - 88:12]
-// CHECK: 87:7: MemberRefExpr=first:2:23 Extent=[7:10 - 87:12]
-// CHECK: 86:7: MemberRefExpr=first:2:23 Extent=[7:10 - 86:12]
-// CHECK: 85:7: MemberRefExpr=first:2:23 Extent=[7:10 - 85:12]
-// CHECK: 84:7: MemberRefExpr=first:2:23 Extent=[7:10 - 84:12]
-// CHECK: 83:7: MemberRefExpr=first:2:23 Extent=[7:10 - 83:12]
-// CHECK: 82:7: MemberRefExpr=first:2:23 Extent=[7:10 - 82:12]
-// CHECK: 81:7: MemberRefExpr=first:2:23 Extent=[7:10 - 81:12]
-// CHECK: 80:7: MemberRefExpr=first:2:23 Extent=[7:10 - 80:12]
-// CHECK: 79:7: MemberRefExpr=first:2:23 Extent=[7:10 - 79:12]
-// CHECK: 78:7: MemberRefExpr=first:2:23 Extent=[7:10 - 78:12]
-// CHECK: 77:7: MemberRefExpr=first:2:23 Extent=[7:10 - 77:12]
-// CHECK: 76:7: MemberRefExpr=first:2:23 Extent=[7:10 - 76:12]
-// CHECK: 75:7: MemberRefExpr=first:2:23 Extent=[7:10 - 75:12]
-// CHECK: 74:7: MemberRefExpr=first:2:23 Extent=[7:10 - 74:12]
-// CHECK: 73:7: MemberRefExpr=first:2:23 Extent=[7:10 - 73:12]
-// CHECK: 72:7: MemberRefExpr=first:2:23 Extent=[7:10 - 72:12]
-// CHECK: 71:7: MemberRefExpr=first:2:23 Extent=[7:10 - 71:12]
-// CHECK: 70:7: MemberRefExpr=first:2:23 Extent=[7:10 - 70:12]
-// CHECK: 69:7: MemberRefExpr=first:2:23 Extent=[7:10 - 69:12]
-// CHECK: 68:7: MemberRefExpr=first:2:23 Extent=[7:10 - 68:12]
-// CHECK: 67:7: MemberRefExpr=first:2:23 Extent=[7:10 - 67:12]
-// CHECK: 66:7: MemberRefExpr=first:2:23 Extent=[7:10 - 66:12]
-// CHECK: 65:7: MemberRefExpr=first:2:23 Extent=[7:10 - 65:12]
-// CHECK: 64:7: MemberRefExpr=first:2:23 Extent=[7:10 - 64:12]
-// CHECK: 63:7: MemberRefExpr=first:2:23 Extent=[7:10 - 63:12]
-// CHECK: 62:7: MemberRefExpr=first:2:23 Extent=[7:10 - 62:12]
-// CHECK: 61:7: MemberRefExpr=first:2:23 Extent=[7:10 - 61:12]
-// CHECK: 60:7: MemberRefExpr=first:2:23 Extent=[7:10 - 60:12]
-// CHECK: 59:7: MemberRefExpr=first:2:23 Extent=[7:10 - 59:12]
-// CHECK: 58:7: MemberRefExpr=first:2:23 Extent=[7:10 - 58:12]
-// CHECK: 57:7: MemberRefExpr=first:2:23 Extent=[7:10 - 57:12]
-// CHECK: 56:7: MemberRefExpr=first:2:23 Extent=[7:10 - 56:12]
-// CHECK: 55:7: MemberRefExpr=first:2:23 Extent=[7:10 - 55:12]
-// CHECK: 54:7: MemberRefExpr=first:2:23 Extent=[7:10 - 54:12]
-// CHECK: 53:7: MemberRefExpr=first:2:23 Extent=[7:10 - 53:12]
-// CHECK: 52:7: MemberRefExpr=first:2:23 Extent=[7:10 - 52:12]
-// CHECK: 51:7: MemberRefExpr=first:2:23 Extent=[7:10 - 51:12]
-// CHECK: 50:7: MemberRefExpr=first:2:23 Extent=[7:10 - 50:12]
-// CHECK: 49:7: MemberRefExpr=first:2:23 Extent=[7:10 - 49:12]
-// CHECK: 48:7: MemberRefExpr=first:2:23 Extent=[7:10 - 48:12]
-// CHECK: 47:7: MemberRefExpr=first:2:23 Extent=[7:10 - 47:12]
-// CHECK: 46:7: MemberRefExpr=first:2:23 Extent=[7:10 - 46:12]
-// CHECK: 45:7: MemberRefExpr=first:2:23 Extent=[7:10 - 45:12]
-// CHECK: 44:7: MemberRefExpr=first:2:23 Extent=[7:10 - 44:12]
-// CHECK: 43:7: MemberRefExpr=first:2:23 Extent=[7:10 - 43:12]
-// CHECK: 42:7: MemberRefExpr=first:2:23 Extent=[7:10 - 42:12]
-// CHECK: 41:7: MemberRefExpr=first:2:23 Extent=[7:10 - 41:12]
-// CHECK: 40:7: MemberRefExpr=first:2:23 Extent=[7:10 - 40:12]
-// CHECK: 39:7: MemberRefExpr=first:2:23 Extent=[7:10 - 39:12]
-// CHECK: 38:7: MemberRefExpr=first:2:23 Extent=[7:10 - 38:12]
-// CHECK: 37:7: MemberRefExpr=first:2:23 Extent=[7:10 - 37:12]
-// CHECK: 36:7: MemberRefExpr=first:2:23 Extent=[7:10 - 36:12]
-// CHECK: 35:7: MemberRefExpr=first:2:23 Extent=[7:10 - 35:12]
-// CHECK: 34:7: MemberRefExpr=first:2:23 Extent=[7:10 - 34:12]
-// CHECK: 33:7: MemberRefExpr=first:2:23 Extent=[7:10 - 33:12]
-// CHECK: 32:7: MemberRefExpr=first:2:23 Extent=[7:10 - 32:12]
-// CHECK: 31:7: MemberRefExpr=first:2:23 Extent=[7:10 - 31:12]
-// CHECK: 30:7: MemberRefExpr=first:2:23 Extent=[7:10 - 30:12]
-// CHECK: 29:7: MemberRefExpr=first:2:23 Extent=[7:10 - 29:12]
-// CHECK: 28:7: MemberRefExpr=first:2:23 Extent=[7:10 - 28:12]
-// CHECK: 27:7: MemberRefExpr=first:2:23 Extent=[7:10 - 27:12]
-// CHECK: 26:7: MemberRefExpr=first:2:23 Extent=[7:10 - 26:12]
-// CHECK: 25:7: MemberRefExpr=first:2:23 Extent=[7:10 - 25:12]
-// CHECK: 24:7: MemberRefExpr=first:2:23 Extent=[7:10 - 24:12]
-// CHECK: 23:7: MemberRefExpr=first:2:23 Extent=[7:10 - 23:12]
-// CHECK: 22:7: MemberRefExpr=first:2:23 Extent=[7:10 - 22:12]
-// CHECK: 21:7: MemberRefExpr=first:2:23 Extent=[7:10 - 21:12]
-// CHECK: 20:7: MemberRefExpr=first:2:23 Extent=[7:10 - 20:12]
-// CHECK: 19:7: MemberRefExpr=first:2:23 Extent=[7:10 - 19:12]
-// CHECK: 18:7: MemberRefExpr=first:2:23 Extent=[7:10 - 18:12]
-// CHECK: 17:7: MemberRefExpr=first:2:23 Extent=[7:10 - 17:12]
-// CHECK: 16:7: MemberRefExpr=first:2:23 Extent=[7:10 - 16:12]
-// CHECK: 15:7: MemberRefExpr=first:2:23 Extent=[7:10 - 15:12]
-// CHECK: 14:7: MemberRefExpr=first:2:23 Extent=[7:10 - 14:12]
-// CHECK: 13:7: MemberRefExpr=first:2:23 Extent=[7:10 - 13:12]
-// CHECK: 12:7: MemberRefExpr=first:2:23 Extent=[7:10 - 12:12]
-// CHECK: 11:7: MemberRefExpr=first:2:23 Extent=[7:11 - 11:12]
-// CHECK: 10:7: MemberRefExpr=first:2:23 Extent=[7:12 - 10:12]
-// CHECK: 9:7: MemberRefExpr=first:2:23 Extent=[7:13 - 9:12]
-// CHECK: 8:7: MemberRefExpr=first:2:23 Extent=[7:14 - 8:12]
-// CHECK: 7:27: MemberRefExpr=first:2:23 Extent=[7:15 - 7:32]
-// CHECK: 7:19: MemberRefExpr=first:2:23 Extent=[7:16 - 7:24]
+// CHECK: 6:45: CompoundStmt= Extent=[6:45 - 124:2]
+// CHECK: 7:3: ReturnStmt= Extent=[7:3 - 123:8]
+// CHECK: 123:7: MemberRefExpr=x:3:7 SingleRefName=[123:7 - 123:8] RefName=[123:7 - 123:8] Extent=[7:10 - 123:8]
+// CHECK: 122:7: MemberRefExpr=first:2:23 SingleRefName=[122:7 - 122:12] RefName=[122:7 - 122:12] Extent=[7:10 - 122:12]
+// CHECK: 121:7: MemberRefExpr=first:2:23 SingleRefName=[121:7 - 121:12] RefName=[121:7 - 121:12] Extent=[7:10 - 121:12]
+// CHECK: 120:7: MemberRefExpr=first:2:23 SingleRefName=[120:7 - 120:12] RefName=[120:7 - 120:12] Extent=[7:10 - 120:12]
+// CHECK: 119:7: MemberRefExpr=first:2:23 SingleRefName=[119:7 - 119:12] RefName=[119:7 - 119:12] Extent=[7:10 - 119:12]
+// CHECK: 118:7: MemberRefExpr=first:2:23 SingleRefName=[118:7 - 118:12] RefName=[118:7 - 118:12] Extent=[7:10 - 118:12]
+// CHECK: 117:7: MemberRefExpr=first:2:23 SingleRefName=[117:7 - 117:12] RefName=[117:7 - 117:12] Extent=[7:10 - 117:12]
+// CHECK: 116:7: MemberRefExpr=first:2:23 SingleRefName=[116:7 - 116:12] RefName=[116:7 - 116:12] Extent=[7:10 - 116:12]
+// CHECK: 115:7: MemberRefExpr=first:2:23 SingleRefName=[115:7 - 115:12] RefName=[115:7 - 115:12] Extent=[7:10 - 115:12]
+// CHECK: 114:7: MemberRefExpr=first:2:23 SingleRefName=[114:7 - 114:12] RefName=[114:7 - 114:12] Extent=[7:10 - 114:12]
+// CHECK: 113:7: MemberRefExpr=first:2:23 SingleRefName=[113:7 - 113:12] RefName=[113:7 - 113:12] Extent=[7:10 - 113:12]
+// CHECK: 112:7: MemberRefExpr=first:2:23 SingleRefName=[112:7 - 112:12] RefName=[112:7 - 112:12] Extent=[7:10 - 112:12]
+// CHECK: 111:7: MemberRefExpr=first:2:23 SingleRefName=[111:7 - 111:12] RefName=[111:7 - 111:12] Extent=[7:10 - 111:12]
+// CHECK: 110:7: MemberRefExpr=first:2:23 SingleRefName=[110:7 - 110:12] RefName=[110:7 - 110:12] Extent=[7:10 - 110:12]
+// CHECK: 109:7: MemberRefExpr=first:2:23 SingleRefName=[109:7 - 109:12] RefName=[109:7 - 109:12] Extent=[7:10 - 109:12]
+// CHECK: 108:7: MemberRefExpr=first:2:23 SingleRefName=[108:7 - 108:12] RefName=[108:7 - 108:12] Extent=[7:10 - 108:12]
+// CHECK: 107:7: MemberRefExpr=first:2:23 SingleRefName=[107:7 - 107:12] RefName=[107:7 - 107:12] Extent=[7:10 - 107:12]
+// CHECK: 106:7: MemberRefExpr=first:2:23 SingleRefName=[106:7 - 106:12] RefName=[106:7 - 106:12] Extent=[7:10 - 106:12]
+// CHECK: 105:7: MemberRefExpr=first:2:23 SingleRefName=[105:7 - 105:12] RefName=[105:7 - 105:12] Extent=[7:10 - 105:12]
+// CHECK: 104:7: MemberRefExpr=first:2:23 SingleRefName=[104:7 - 104:12] RefName=[104:7 - 104:12] Extent=[7:10 - 104:12]
+// CHECK: 103:7: MemberRefExpr=first:2:23 SingleRefName=[103:7 - 103:12] RefName=[103:7 - 103:12] Extent=[7:10 - 103:12]
+// CHECK: 102:7: MemberRefExpr=first:2:23 SingleRefName=[102:7 - 102:12] RefName=[102:7 - 102:12] Extent=[7:10 - 102:12]
+// CHECK: 101:7: MemberRefExpr=first:2:23 SingleRefName=[101:7 - 101:12] RefName=[101:7 - 101:12] Extent=[7:10 - 101:12]
+// CHECK: 100:7: MemberRefExpr=first:2:23 SingleRefName=[100:7 - 100:12] RefName=[100:7 - 100:12] Extent=[7:10 - 100:12]
+// CHECK: 99:7: MemberRefExpr=first:2:23 SingleRefName=[99:7 - 99:12] RefName=[99:7 - 99:12] Extent=[7:10 - 99:12]
+// CHECK: 98:7: MemberRefExpr=first:2:23 SingleRefName=[98:7 - 98:12] RefName=[98:7 - 98:12] Extent=[7:10 - 98:12]
+// CHECK: 97:7: MemberRefExpr=first:2:23 SingleRefName=[97:7 - 97:12] RefName=[97:7 - 97:12] Extent=[7:10 - 97:12]
+// CHECK: 96:7: MemberRefExpr=first:2:23 SingleRefName=[96:7 - 96:12] RefName=[96:7 - 96:12] Extent=[7:10 - 96:12]
+// CHECK: 95:7: MemberRefExpr=first:2:23 SingleRefName=[95:7 - 95:12] RefName=[95:7 - 95:12] Extent=[7:10 - 95:12]
+// CHECK: 94:7: MemberRefExpr=first:2:23 SingleRefName=[94:7 - 94:12] RefName=[94:7 - 94:12] Extent=[7:10 - 94:12]
+// CHECK: 93:7: MemberRefExpr=first:2:23 SingleRefName=[93:7 - 93:12] RefName=[93:7 - 93:12] Extent=[7:10 - 93:12]
+// CHECK: 92:7: MemberRefExpr=first:2:23 SingleRefName=[92:7 - 92:12] RefName=[92:7 - 92:12] Extent=[7:10 - 92:12]
+// CHECK: 91:7: MemberRefExpr=first:2:23 SingleRefName=[91:7 - 91:12] RefName=[91:7 - 91:12] Extent=[7:10 - 91:12]
+// CHECK: 90:7: MemberRefExpr=first:2:23 SingleRefName=[90:7 - 90:12] RefName=[90:7 - 90:12] Extent=[7:10 - 90:12]
+// CHECK: 89:7: MemberRefExpr=first:2:23 SingleRefName=[89:7 - 89:12] RefName=[89:7 - 89:12] Extent=[7:10 - 89:12]
+// CHECK: 88:7: MemberRefExpr=first:2:23 SingleRefName=[88:7 - 88:12] RefName=[88:7 - 88:12] Extent=[7:10 - 88:12]
+// CHECK: 87:7: MemberRefExpr=first:2:23 SingleRefName=[87:7 - 87:12] RefName=[87:7 - 87:12] Extent=[7:10 - 87:12]
+// CHECK: 86:7: MemberRefExpr=first:2:23 SingleRefName=[86:7 - 86:12] RefName=[86:7 - 86:12] Extent=[7:10 - 86:12]
+// CHECK: 85:7: MemberRefExpr=first:2:23 SingleRefName=[85:7 - 85:12] RefName=[85:7 - 85:12] Extent=[7:10 - 85:12]
+// CHECK: 84:7: MemberRefExpr=first:2:23 SingleRefName=[84:7 - 84:12] RefName=[84:7 - 84:12] Extent=[7:10 - 84:12]
+// CHECK: 83:7: MemberRefExpr=first:2:23 SingleRefName=[83:7 - 83:12] RefName=[83:7 - 83:12] Extent=[7:10 - 83:12]
+// CHECK: 82:7: MemberRefExpr=first:2:23 SingleRefName=[82:7 - 82:12] RefName=[82:7 - 82:12] Extent=[7:10 - 82:12]
+// CHECK: 81:7: MemberRefExpr=first:2:23 SingleRefName=[81:7 - 81:12] RefName=[81:7 - 81:12] Extent=[7:10 - 81:12]
+// CHECK: 80:7: MemberRefExpr=first:2:23 SingleRefName=[80:7 - 80:12] RefName=[80:7 - 80:12] Extent=[7:10 - 80:12]
+// CHECK: 79:7: MemberRefExpr=first:2:23 SingleRefName=[79:7 - 79:12] RefName=[79:7 - 79:12] Extent=[7:10 - 79:12]
+// CHECK: 78:7: MemberRefExpr=first:2:23 SingleRefName=[78:7 - 78:12] RefName=[78:7 - 78:12] Extent=[7:10 - 78:12]
+// CHECK: 77:7: MemberRefExpr=first:2:23 SingleRefName=[77:7 - 77:12] RefName=[77:7 - 77:12] Extent=[7:10 - 77:12]
+// CHECK: 76:7: MemberRefExpr=first:2:23 SingleRefName=[76:7 - 76:12] RefName=[76:7 - 76:12] Extent=[7:10 - 76:12]
+// CHECK: 75:7: MemberRefExpr=first:2:23 SingleRefName=[75:7 - 75:12] RefName=[75:7 - 75:12] Extent=[7:10 - 75:12]
+// CHECK: 74:7: MemberRefExpr=first:2:23 SingleRefName=[74:7 - 74:12] RefName=[74:7 - 74:12] Extent=[7:10 - 74:12]
+// CHECK: 73:7: MemberRefExpr=first:2:23 SingleRefName=[73:7 - 73:12] RefName=[73:7 - 73:12] Extent=[7:10 - 73:12]
+// CHECK: 72:7: MemberRefExpr=first:2:23 SingleRefName=[72:7 - 72:12] RefName=[72:7 - 72:12] Extent=[7:10 - 72:12]
+// CHECK: 71:7: MemberRefExpr=first:2:23 SingleRefName=[71:7 - 71:12] RefName=[71:7 - 71:12] Extent=[7:10 - 71:12]
+// CHECK: 70:7: MemberRefExpr=first:2:23 SingleRefName=[70:7 - 70:12] RefName=[70:7 - 70:12] Extent=[7:10 - 70:12]
+// CHECK: 69:7: MemberRefExpr=first:2:23 SingleRefName=[69:7 - 69:12] RefName=[69:7 - 69:12] Extent=[7:10 - 69:12]
+// CHECK: 68:7: MemberRefExpr=first:2:23 SingleRefName=[68:7 - 68:12] RefName=[68:7 - 68:12] Extent=[7:10 - 68:12]
+// CHECK: 67:7: MemberRefExpr=first:2:23 SingleRefName=[67:7 - 67:12] RefName=[67:7 - 67:12] Extent=[7:10 - 67:12]
+// CHECK: 66:7: MemberRefExpr=first:2:23 SingleRefName=[66:7 - 66:12] RefName=[66:7 - 66:12] Extent=[7:10 - 66:12]
+// CHECK: 65:7: MemberRefExpr=first:2:23 SingleRefName=[65:7 - 65:12] RefName=[65:7 - 65:12] Extent=[7:10 - 65:12]
+// CHECK: 64:7: MemberRefExpr=first:2:23 SingleRefName=[64:7 - 64:12] RefName=[64:7 - 64:12] Extent=[7:10 - 64:12]
+// CHECK: 63:7: MemberRefExpr=first:2:23 SingleRefName=[63:7 - 63:12] RefName=[63:7 - 63:12] Extent=[7:10 - 63:12]
+// CHECK: 62:7: MemberRefExpr=first:2:23 SingleRefName=[62:7 - 62:12] RefName=[62:7 - 62:12] Extent=[7:10 - 62:12]
+// CHECK: 61:7: MemberRefExpr=first:2:23 SingleRefName=[61:7 - 61:12] RefName=[61:7 - 61:12] Extent=[7:10 - 61:12]
+// CHECK: 60:7: MemberRefExpr=first:2:23 SingleRefName=[60:7 - 60:12] RefName=[60:7 - 60:12] Extent=[7:10 - 60:12]
+// CHECK: 59:7: MemberRefExpr=first:2:23 SingleRefName=[59:7 - 59:12] RefName=[59:7 - 59:12] Extent=[7:10 - 59:12]
+// CHECK: 58:7: MemberRefExpr=first:2:23 SingleRefName=[58:7 - 58:12] RefName=[58:7 - 58:12] Extent=[7:10 - 58:12]
+// CHECK: 57:7: MemberRefExpr=first:2:23 SingleRefName=[57:7 - 57:12] RefName=[57:7 - 57:12] Extent=[7:10 - 57:12]
+// CHECK: 56:7: MemberRefExpr=first:2:23 SingleRefName=[56:7 - 56:12] RefName=[56:7 - 56:12] Extent=[7:10 - 56:12]
+// CHECK: 55:7: MemberRefExpr=first:2:23 SingleRefName=[55:7 - 55:12] RefName=[55:7 - 55:12] Extent=[7:10 - 55:12]
+// CHECK: 54:7: MemberRefExpr=first:2:23 SingleRefName=[54:7 - 54:12] RefName=[54:7 - 54:12] Extent=[7:10 - 54:12]
+// CHECK: 53:7: MemberRefExpr=first:2:23 SingleRefName=[53:7 - 53:12] RefName=[53:7 - 53:12] Extent=[7:10 - 53:12]
+// CHECK: 52:7: MemberRefExpr=first:2:23 SingleRefName=[52:7 - 52:12] RefName=[52:7 - 52:12] Extent=[7:10 - 52:12]
+// CHECK: 51:7: MemberRefExpr=first:2:23 SingleRefName=[51:7 - 51:12] RefName=[51:7 - 51:12] Extent=[7:10 - 51:12]
+// CHECK: 50:7: MemberRefExpr=first:2:23 SingleRefName=[50:7 - 50:12] RefName=[50:7 - 50:12] Extent=[7:10 - 50:12]
+// CHECK: 49:7: MemberRefExpr=first:2:23 SingleRefName=[49:7 - 49:12] RefName=[49:7 - 49:12] Extent=[7:10 - 49:12]
+// CHECK: 48:7: MemberRefExpr=first:2:23 SingleRefName=[48:7 - 48:12] RefName=[48:7 - 48:12] Extent=[7:10 - 48:12]
+// CHECK: 47:7: MemberRefExpr=first:2:23 SingleRefName=[47:7 - 47:12] RefName=[47:7 - 47:12] Extent=[7:10 - 47:12]
+// CHECK: 46:7: MemberRefExpr=first:2:23 SingleRefName=[46:7 - 46:12] RefName=[46:7 - 46:12] Extent=[7:10 - 46:12]
+// CHECK: 45:7: MemberRefExpr=first:2:23 SingleRefName=[45:7 - 45:12] RefName=[45:7 - 45:12] Extent=[7:10 - 45:12]
+// CHECK: 44:7: MemberRefExpr=first:2:23 SingleRefName=[44:7 - 44:12] RefName=[44:7 - 44:12] Extent=[7:10 - 44:12]
+// CHECK: 43:7: MemberRefExpr=first:2:23 SingleRefName=[43:7 - 43:12] RefName=[43:7 - 43:12] Extent=[7:10 - 43:12]
+// CHECK: 42:7: MemberRefExpr=first:2:23 SingleRefName=[42:7 - 42:12] RefName=[42:7 - 42:12] Extent=[7:10 - 42:12]
+// CHECK: 41:7: MemberRefExpr=first:2:23 SingleRefName=[41:7 - 41:12] RefName=[41:7 - 41:12] Extent=[7:10 - 41:12]
+// CHECK: 40:7: MemberRefExpr=first:2:23 SingleRefName=[40:7 - 40:12] RefName=[40:7 - 40:12] Extent=[7:10 - 40:12]
+// CHECK: 39:7: MemberRefExpr=first:2:23 SingleRefName=[39:7 - 39:12] RefName=[39:7 - 39:12] Extent=[7:10 - 39:12]
+// CHECK: 38:7: MemberRefExpr=first:2:23 SingleRefName=[38:7 - 38:12] RefName=[38:7 - 38:12] Extent=[7:10 - 38:12]
+// CHECK: 37:7: MemberRefExpr=first:2:23 SingleRefName=[37:7 - 37:12] RefName=[37:7 - 37:12] Extent=[7:10 - 37:12]
+// CHECK: 36:7: MemberRefExpr=first:2:23 SingleRefName=[36:7 - 36:12] RefName=[36:7 - 36:12] Extent=[7:10 - 36:12]
+// CHECK: 35:7: MemberRefExpr=first:2:23 SingleRefName=[35:7 - 35:12] RefName=[35:7 - 35:12] Extent=[7:10 - 35:12]
+// CHECK: 34:7: MemberRefExpr=first:2:23 SingleRefName=[34:7 - 34:12] RefName=[34:7 - 34:12] Extent=[7:10 - 34:12]
+// CHECK: 33:7: MemberRefExpr=first:2:23 SingleRefName=[33:7 - 33:12] RefName=[33:7 - 33:12] Extent=[7:10 - 33:12]
+// CHECK: 32:7: MemberRefExpr=first:2:23 SingleRefName=[32:7 - 32:12] RefName=[32:7 - 32:12] Extent=[7:10 - 32:12]
+// CHECK: 31:7: MemberRefExpr=first:2:23 SingleRefName=[31:7 - 31:12] RefName=[31:7 - 31:12] Extent=[7:10 - 31:12]
+// CHECK: 30:7: MemberRefExpr=first:2:23 SingleRefName=[30:7 - 30:12] RefName=[30:7 - 30:12] Extent=[7:10 - 30:12]
+// CHECK: 29:7: MemberRefExpr=first:2:23 SingleRefName=[29:7 - 29:12] RefName=[29:7 - 29:12] Extent=[7:10 - 29:12]
+// CHECK: 28:7: MemberRefExpr=first:2:23 SingleRefName=[28:7 - 28:12] RefName=[28:7 - 28:12] Extent=[7:10 - 28:12]
+// CHECK: 27:7: MemberRefExpr=first:2:23 SingleRefName=[27:7 - 27:12] RefName=[27:7 - 27:12] Extent=[7:10 - 27:12]
+// CHECK: 26:7: MemberRefExpr=first:2:23 SingleRefName=[26:7 - 26:12] RefName=[26:7 - 26:12] Extent=[7:10 - 26:12]
+// CHECK: 25:7: MemberRefExpr=first:2:23 SingleRefName=[25:7 - 25:12] RefName=[25:7 - 25:12] Extent=[7:10 - 25:12]
+// CHECK: 24:7: MemberRefExpr=first:2:23 SingleRefName=[24:7 - 24:12] RefName=[24:7 - 24:12] Extent=[7:10 - 24:12]
+// CHECK: 23:7: MemberRefExpr=first:2:23 SingleRefName=[23:7 - 23:12] RefName=[23:7 - 23:12] Extent=[7:10 - 23:12]
+// CHECK: 22:7: MemberRefExpr=first:2:23 SingleRefName=[22:7 - 22:12] RefName=[22:7 - 22:12] Extent=[7:10 - 22:12]
+// CHECK: 21:7: MemberRefExpr=first:2:23 SingleRefName=[21:7 - 21:12] RefName=[21:7 - 21:12] Extent=[7:10 - 21:12]
+// CHECK: 20:7: MemberRefExpr=first:2:23 SingleRefName=[20:7 - 20:12] RefName=[20:7 - 20:12] Extent=[7:10 - 20:12]
+// CHECK: 19:7: MemberRefExpr=first:2:23 SingleRefName=[19:7 - 19:12] RefName=[19:7 - 19:12] Extent=[7:10 - 19:12]
+// CHECK: 18:7: MemberRefExpr=first:2:23 SingleRefName=[18:7 - 18:12] RefName=[18:7 - 18:12] Extent=[7:10 - 18:12]
+// CHECK: 17:7: MemberRefExpr=first:2:23 SingleRefName=[17:7 - 17:12] RefName=[17:7 - 17:12] Extent=[7:10 - 17:12]
+// CHECK: 16:7: MemberRefExpr=first:2:23 SingleRefName=[16:7 - 16:12] RefName=[16:7 - 16:12] Extent=[7:10 - 16:12]
+// CHECK: 15:7: MemberRefExpr=first:2:23 SingleRefName=[15:7 - 15:12] RefName=[15:7 - 15:12] Extent=[7:10 - 15:12]
+// CHECK: 14:7: MemberRefExpr=first:2:23 SingleRefName=[14:7 - 14:12] RefName=[14:7 - 14:12] Extent=[7:10 - 14:12]
+// CHECK: 13:7: MemberRefExpr=first:2:23 SingleRefName=[13:7 - 13:12] RefName=[13:7 - 13:12] Extent=[7:10 - 13:12]
+// CHECK: 12:7: MemberRefExpr=first:2:23 SingleRefName=[12:7 - 12:12] RefName=[12:7 - 12:12] Extent=[7:10 - 12:12]
+// CHECK: 11:7: MemberRefExpr=first:2:23 SingleRefName=[11:7 - 11:12] RefName=[11:7 - 11:12] Extent=[7:11 - 11:12]
+// CHECK: 10:7: MemberRefExpr=first:2:23 SingleRefName=[10:7 - 10:12] RefName=[10:7 - 10:12] Extent=[7:12 - 10:12]
+// CHECK: 9:7: MemberRefExpr=first:2:23 SingleRefName=[9:7 - 9:12] RefName=[9:7 - 9:12] Extent=[7:13 - 9:12]
+// CHECK: 8:7: MemberRefExpr=first:2:23 SingleRefName=[8:7 - 8:12] RefName=[8:7 - 8:12] Extent=[7:14 - 8:12]
+// CHECK: 7:27: MemberRefExpr=first:2:23 SingleRefName=[7:27 - 7:32] RefName=[7:27 - 7:32] Extent=[7:15 - 7:32]
+// CHECK: 7:19: MemberRefExpr=first:2:23 SingleRefName=[7:19 - 7:24] RefName=[7:19 - 7:24] Extent=[7:16 - 7:24]
// CHECK: 7:16: DeclRefExpr=s:6:42 Extent=[7:16 - 7:17]
// RUN: c-index-test -test-annotate-tokens=%s:1:1:124:1 %s | FileCheck -check-prefix=CHECK-tokens %s
@@ -275,33 +275,33 @@ int test_rdar8650865(struct rdar8650865 *s) {
// CHECK-tokens: Punctuation: "*" [6:41 - 6:42] ParmDecl=s:6:42 (Definition)
// CHECK-tokens: Identifier: "s" [6:42 - 6:43] ParmDecl=s:6:42 (Definition)
// CHECK-tokens: Punctuation: ")" [6:43 - 6:44] FunctionDecl=test_rdar8650865:6:5 (Definition)
-// CHECK-tokens: Punctuation: "{" [6:45 - 6:46] UnexposedStmt=
-// CHECK-tokens: Keyword: "return" [7:3 - 7:9] UnexposedStmt=
-// CHECK-tokens: Punctuation: "(" [7:10 - 7:11] UnexposedExpr=
-// CHECK-tokens: Punctuation: "(" [7:11 - 7:12] UnexposedExpr=
-// CHECK-tokens: Punctuation: "(" [7:12 - 7:13] UnexposedExpr=
-// CHECK-tokens: Punctuation: "(" [7:13 - 7:14] UnexposedExpr=
-// CHECK-tokens: Punctuation: "(" [7:14 - 7:15] UnexposedExpr=
-// CHECK-tokens: Punctuation: "(" [7:15 - 7:16] UnexposedExpr=
+// CHECK-tokens: Punctuation: "{" [6:45 - 6:46] CompoundStmt=
+// CHECK-tokens: Keyword: "return" [7:3 - 7:9] ReturnStmt=
+// CHECK-tokens: Punctuation: "(" [7:10 - 7:11] ParenExpr=
+// CHECK-tokens: Punctuation: "(" [7:11 - 7:12] ParenExpr=
+// CHECK-tokens: Punctuation: "(" [7:12 - 7:13] ParenExpr=
+// CHECK-tokens: Punctuation: "(" [7:13 - 7:14] ParenExpr=
+// CHECK-tokens: Punctuation: "(" [7:14 - 7:15] ParenExpr=
+// CHECK-tokens: Punctuation: "(" [7:15 - 7:16] ParenExpr=
// CHECK-tokens: Identifier: "s" [7:16 - 7:17] DeclRefExpr=s:6:42
// CHECK-tokens: Punctuation: "->" [7:17 - 7:19] MemberRefExpr=first:2:23
// CHECK-tokens: Identifier: "first" [7:19 - 7:24] MemberRefExpr=first:2:23
-// CHECK-tokens: Punctuation: ")" [7:24 - 7:25] UnexposedExpr=
+// CHECK-tokens: Punctuation: ")" [7:24 - 7:25] ParenExpr=
// CHECK-tokens: Punctuation: "->" [7:25 - 7:27] MemberRefExpr=first:2:23
// CHECK-tokens: Identifier: "first" [7:27 - 7:32] MemberRefExpr=first:2:23
-// CHECK-tokens: Punctuation: ")" [7:32 - 7:33] UnexposedExpr=
+// CHECK-tokens: Punctuation: ")" [7:32 - 7:33] ParenExpr=
// CHECK-tokens: Punctuation: "->" [8:5 - 8:7] MemberRefExpr=first:2:23
// CHECK-tokens: Identifier: "first" [8:7 - 8:12] MemberRefExpr=first:2:23
-// CHECK-tokens: Punctuation: ")" [8:12 - 8:13] UnexposedExpr=
+// CHECK-tokens: Punctuation: ")" [8:12 - 8:13] ParenExpr=
// CHECK-tokens: Punctuation: "->" [9:5 - 9:7] MemberRefExpr=first:2:23
// CHECK-tokens: Identifier: "first" [9:7 - 9:12] MemberRefExpr=first:2:23
-// CHECK-tokens: Punctuation: ")" [9:12 - 9:13] UnexposedExpr=
+// CHECK-tokens: Punctuation: ")" [9:12 - 9:13] ParenExpr=
// CHECK-tokens: Punctuation: "->" [10:5 - 10:7] MemberRefExpr=first:2:23
// CHECK-tokens: Identifier: "first" [10:7 - 10:12] MemberRefExpr=first:2:23
-// CHECK-tokens: Punctuation: ")" [10:12 - 10:13] UnexposedExpr=
+// CHECK-tokens: Punctuation: ")" [10:12 - 10:13] ParenExpr=
// CHECK-tokens: Punctuation: "->" [11:5 - 11:7] MemberRefExpr=first:2:23
// CHECK-tokens: Identifier: "first" [11:7 - 11:12] MemberRefExpr=first:2:23
-// CHECK-tokens: Punctuation: ")" [11:12 - 11:13] UnexposedExpr=
+// CHECK-tokens: Punctuation: ")" [11:12 - 11:13] ParenExpr=
// CHECK-tokens: Punctuation: "->" [12:5 - 12:7] MemberRefExpr=first:2:23
// CHECK-tokens: Identifier: "first" [12:7 - 12:12] MemberRefExpr=first:2:23
// CHECK-tokens: Punctuation: "->" [13:5 - 13:7] MemberRefExpr=first:2:23
@@ -526,7 +526,7 @@ int test_rdar8650865(struct rdar8650865 *s) {
// CHECK-tokens: Identifier: "first" [122:7 - 122:12] MemberRefExpr=first:2:23
// CHECK-tokens: Punctuation: "->" [123:5 - 123:7] MemberRefExpr=x:3:7
// CHECK-tokens: Identifier: "x" [123:7 - 123:8] MemberRefExpr=x:3:7
-// CHECK-tokens: Punctuation: ";" [123:8 - 123:9] UnexposedStmt=
-// CHECK-tokens: Punctuation: "}" [124:1 - 124:2] UnexposedStmt=
+// CHECK-tokens: Punctuation: ";" [123:8 - 123:9] CompoundStmt=
+// CHECK-tokens: Punctuation: "}" [124:1 - 124:2] CompoundStmt=
diff --git a/test/Index/remap-load.c b/test/Index/remap-load.c
index 5a8f46b7f3d8..260887469f6c 100644
--- a/test/Index/remap-load.c
+++ b/test/Index/remap-load.c
@@ -4,7 +4,7 @@
// CHECK: remap-load.c:1:13: ParmDecl=parm1:1:13 (Definition) Extent=[1:9 - 1:18]
// CHECK: remap-load.c:1:26: ParmDecl=parm2:1:26 (Definition) Extent=[1:20 - 1:31]
// CHECK: remap-load.c:2:10: UnexposedExpr= Extent=[2:10 - 2:23]
-// CHECK: remap-load.c:2:10: UnexposedExpr= Extent=[2:10 - 2:23]
+// CHECK: remap-load.c:2:10: BinaryOperator= Extent=[2:10 - 2:23]
// CHECK: remap-load.c:2:10: UnexposedExpr=parm1:1:13 Extent=[2:10 - 2:15]
// CHECK: remap-load.c:2:10: DeclRefExpr=parm1:1:13 Extent=[2:10 - 2:15]
// CHECK: remap-load.c:2:18: DeclRefExpr=parm2:1:26 Extent=[2:18 - 2:23]
diff --git a/test/Index/usrs-cxx0x.cpp b/test/Index/usrs-cxx0x.cpp
index 50aee0968867..a48b4467b731 100644
--- a/test/Index/usrs-cxx0x.cpp
+++ b/test/Index/usrs-cxx0x.cpp
@@ -3,6 +3,6 @@ struct tuple { };
void f(tuple<int, float, double>);
-// RUN: c-index-test -test-load-source-usrs all -std=c++0x %s | FileCheck %s
+// RUN: c-index-test -test-load-source-usrs all -std=c++11 %s | FileCheck %s
// CHECK: usrs-cxx0x.cpp c:@ST>1#pT@tuple Extent=[1:1 - 2:17]
// CHECK: usrs-cxx0x.cpp c:@F@f#$@S@tuple>#p3Ifd# Extent=[4:1 - 4:34]
diff --git a/test/Index/usrs.m b/test/Index/usrs.m
index 283064701918..826abb53f37c 100644
--- a/test/Index/usrs.m
+++ b/test/Index/usrs.m
@@ -142,9 +142,9 @@ int test_multi_declaration(void) {
// CHECK-source: usrs.m:3:19: FunctionDecl=my_helper:3:19 (Definition) Extent=[3:1 - 3:60]
// CHECK-source: usrs.m:3:33: ParmDecl=x:3:33 (Definition) Extent=[3:29 - 3:34]
// CHECK-source: usrs.m:3:40: ParmDecl=y:3:40 (Definition) Extent=[3:36 - 3:41]
-// CHECK-source: usrs.m:3:43: UnexposedStmt= Extent=[3:43 - 3:60]
-// CHECK-source: usrs.m:3:45: UnexposedStmt= Extent=[3:45 - 3:57]
-// CHECK-source: usrs.m:3:52: UnexposedExpr= Extent=[3:52 - 3:57]
+// CHECK-source: usrs.m:3:43: CompoundStmt= Extent=[3:43 - 3:60]
+// CHECK-source: usrs.m:3:45: ReturnStmt= Extent=[3:45 - 3:57]
+// CHECK-source: usrs.m:3:52: BinaryOperator= Extent=[3:52 - 3:57]
// CHECK-source: usrs.m:3:52: DeclRefExpr=x:3:33 Extent=[3:52 - 3:53]
// CHECK-source: usrs.m:3:56: DeclRefExpr=y:3:40 Extent=[3:56 - 3:57]
// CHECK-source: usrs.m:5:1: EnumDecl=:5:1 (Definition) Extent=[5:1 - 8:2]
@@ -153,11 +153,10 @@ int test_multi_declaration(void) {
// CHECK-source: usrs.m:10:1: EnumDecl=:10:1 (Definition) Extent=[10:1 - 13:2]
// CHECK-source: usrs.m:11:3: EnumConstantDecl=FOO:11:3 (Definition) Extent=[11:3 - 11:6]
// CHECK-source: usrs.m:12:3: EnumConstantDecl=BAR:12:3 (Definition) Extent=[12:3 - 12:6]
+// CHECK-source: usrs.m:18:3: TypedefDecl=MyStruct:18:3 (Definition) Extent=[15:1 - 18:11]
// CHECK-source: usrs.m:15:9: StructDecl=:15:9 (Definition) Extent=[15:9 - 18:2]
// CHECK-source: usrs.m:16:7: FieldDecl=wa:16:7 (Definition) Extent=[16:3 - 16:9]
// CHECK-source: usrs.m:17:7: FieldDecl=moo:17:7 (Definition) Extent=[17:3 - 17:10]
-// CHECK-source: usrs.m:18:3: TypedefDecl=MyStruct:18:3 (Definition) Extent=[15:1 - 18:11]
-// CHECK-source: usrs.m:15:9: TypeRef=MyStruct:15:9 Extent=[15:9 - 15:15]
// CHECK-source: usrs.m:20:6: EnumDecl=Pizza:20:6 (Definition) Extent=[20:1 - 23:2]
// CHECK-source: usrs.m:21:3: EnumConstantDecl=CHEESE:21:3 (Definition) Extent=[21:3 - 21:9]
// CHECK-source: usrs.m:22:3: EnumConstantDecl=MUSHROOMS:22:3 (Definition) Extent=[22:3 - 22:12]
@@ -174,33 +173,33 @@ int test_multi_declaration(void) {
// CHECK-source: usrs.m:31:15: ObjCInstanceMethodDecl=d1:31:15 Extent=[31:15 - 31:17]
// CHECK-source: usrs.m:31:15: ObjCInstanceMethodDecl=setD1::31:15 Extent=[31:15 - 31:17]
// CHECK-source: usrs.m:31:15: ParmDecl=d1:31:15 (Definition) Extent=[31:15 - 31:17]
-// CHECK-source: usrs.m:34:1: ObjCImplementationDecl=Foo:34:1 (Definition) Extent=[34:1 - 45:2]
+// CHECK-source: usrs.m:34:17: ObjCImplementationDecl=Foo:34:17 (Definition) Extent=[34:1 - 45:2]
// CHECK-source: usrs.m:35:1: ObjCInstanceMethodDecl=godzilla:35:1 (Definition) [Overrides @29:1] Extent=[35:1 - 39:2]
// CHECK-source: usrs.m:35:4: TypeRef=id:0:0 Extent=[35:4 - 35:6]
-// CHECK-source: usrs.m:35:17: UnexposedStmt= Extent=[35:17 - 39:2]
-// CHECK-source: usrs.m:36:3: UnexposedStmt= Extent=[36:3 - 36:20]
+// CHECK-source: usrs.m:35:17: CompoundStmt= Extent=[35:17 - 39:2]
+// CHECK-source: usrs.m:36:3: DeclStmt= Extent=[36:3 - 36:20]
// CHECK-source: usrs.m:36:14: VarDecl=a:36:14 (Definition) Extent=[36:3 - 36:19]
-// CHECK-source: usrs.m:36:18: UnexposedExpr= Extent=[36:18 - 36:19]
-// CHECK-source: usrs.m:37:3: UnexposedStmt= Extent=[37:3 - 37:16]
+// CHECK-source: usrs.m:36:18: IntegerLiteral= Extent=[36:18 - 36:19]
+// CHECK-source: usrs.m:37:3: DeclStmt= Extent=[37:3 - 37:16]
// CHECK-source: usrs.m:37:14: VarDecl=z:37:14 Extent=[37:3 - 37:15]
-// CHECK-source: usrs.m:38:3: UnexposedStmt= Extent=[38:3 - 38:11]
-// CHECK-source: usrs.m:38:10: UnexposedExpr= Extent=[38:10 - 38:11]
+// CHECK-source: usrs.m:38:3: ReturnStmt= Extent=[38:3 - 38:11]
// CHECK-source: usrs.m:38:10: UnexposedExpr= Extent=[38:10 - 38:11]
+// CHECK-source: usrs.m:38:10: IntegerLiteral= Extent=[38:10 - 38:11]
// CHECK-source: usrs.m:40:1: ObjCClassMethodDecl=kingkong:40:1 (Definition) [Overrides @30:1] Extent=[40:1 - 43:2]
// CHECK-source: usrs.m:40:4: TypeRef=id:0:0 Extent=[40:4 - 40:6]
-// CHECK-source: usrs.m:40:17: UnexposedStmt= Extent=[40:17 - 43:2]
-// CHECK-source: usrs.m:41:3: UnexposedStmt= Extent=[41:3 - 41:17]
+// CHECK-source: usrs.m:40:17: CompoundStmt= Extent=[40:17 - 43:2]
+// CHECK-source: usrs.m:41:3: DeclStmt= Extent=[41:3 - 41:17]
// CHECK-source: usrs.m:41:7: VarDecl=local_var:41:7 (Definition) Extent=[41:3 - 41:16]
-// CHECK-source: usrs.m:42:3: UnexposedStmt= Extent=[42:3 - 42:11]
-// CHECK-source: usrs.m:42:10: UnexposedExpr= Extent=[42:10 - 42:11]
+// CHECK-source: usrs.m:42:3: ReturnStmt= Extent=[42:3 - 42:11]
// CHECK-source: usrs.m:42:10: UnexposedExpr= Extent=[42:10 - 42:11]
+// CHECK-source: usrs.m:42:10: IntegerLiteral= Extent=[42:10 - 42:11]
// CHECK-source: usrs.m:44:13: ObjCIvarDecl=d1:44:13 (Definition) Extent=[44:13 - 44:15]
// CHECK-source: usrs.m:44:13: ObjCSynthesizeDecl=d1:31:15 (Definition) Extent=[44:1 - 44:15]
// CHECK-source: usrs.m:47:5: VarDecl=z:47:5 Extent=[47:1 - 47:6]
// CHECK-source: usrs.m:49:12: FunctionDecl=local_func:49:12 (Definition) Extent=[49:1 - 49:43]
// CHECK-source: usrs.m:49:27: ParmDecl=x:49:27 (Definition) Extent=[49:23 - 49:28]
-// CHECK-source: usrs.m:49:30: UnexposedStmt= Extent=[49:30 - 49:43]
-// CHECK-source: usrs.m:49:32: UnexposedStmt= Extent=[49:32 - 49:40]
+// CHECK-source: usrs.m:49:30: CompoundStmt= Extent=[49:30 - 49:43]
+// CHECK-source: usrs.m:49:32: ReturnStmt= Extent=[49:32 - 49:40]
// CHECK-source: usrs.m:49:39: DeclRefExpr=x:49:27 Extent=[49:39 - 49:40]
// CHECK-source: usrs.m:51:12: ObjCInterfaceDecl=CWithExt:51:12 Extent=[51:1 - 53:5]
// CHECK-source: usrs.m:52:1: ObjCInstanceMethodDecl=meth1:52:1 Extent=[52:1 - 52:14]
@@ -217,54 +216,54 @@ int test_multi_declaration(void) {
// CHECK-source: usrs.m:60:12: ObjCClassRef=CWithExt:51:12 Extent=[60:12 - 60:20]
// CHECK-source: usrs.m:61:1: ObjCInstanceMethodDecl=meth4:61:1 Extent=[61:1 - 61:14]
// CHECK-source: usrs.m:61:4: TypeRef=id:0:0 Extent=[61:4 - 61:6]
-// CHECK-source: usrs.m:63:1: ObjCImplementationDecl=CWithExt:63:1 (Definition) Extent=[63:1 - 67:2]
+// CHECK-source: usrs.m:63:17: ObjCImplementationDecl=CWithExt:63:17 (Definition) Extent=[63:1 - 67:2]
// CHECK-source: usrs.m:64:1: ObjCInstanceMethodDecl=meth1:64:1 (Definition) [Overrides @52:1] Extent=[64:1 - 64:27]
// CHECK-source: usrs.m:64:4: TypeRef=id:0:0 Extent=[64:4 - 64:6]
-// CHECK-source: usrs.m:64:14: UnexposedStmt= Extent=[64:14 - 64:27]
-// CHECK-source: usrs.m:64:16: UnexposedStmt= Extent=[64:16 - 64:24]
-// CHECK-source: usrs.m:64:23: UnexposedExpr= Extent=[64:23 - 64:24]
+// CHECK-source: usrs.m:64:14: CompoundStmt= Extent=[64:14 - 64:27]
+// CHECK-source: usrs.m:64:16: ReturnStmt= Extent=[64:16 - 64:24]
// CHECK-source: usrs.m:64:23: UnexposedExpr= Extent=[64:23 - 64:24]
+// CHECK-source: usrs.m:64:23: IntegerLiteral= Extent=[64:23 - 64:24]
// CHECK-source: usrs.m:65:1: ObjCInstanceMethodDecl=meth2:65:1 (Definition) [Overrides @55:1] Extent=[65:1 - 65:27]
// CHECK-source: usrs.m:65:4: TypeRef=id:0:0 Extent=[65:4 - 65:6]
-// CHECK-source: usrs.m:65:14: UnexposedStmt= Extent=[65:14 - 65:27]
-// CHECK-source: usrs.m:65:16: UnexposedStmt= Extent=[65:16 - 65:24]
-// CHECK-source: usrs.m:65:23: UnexposedExpr= Extent=[65:23 - 65:24]
+// CHECK-source: usrs.m:65:14: CompoundStmt= Extent=[65:14 - 65:27]
+// CHECK-source: usrs.m:65:16: ReturnStmt= Extent=[65:16 - 65:24]
// CHECK-source: usrs.m:65:23: UnexposedExpr= Extent=[65:23 - 65:24]
+// CHECK-source: usrs.m:65:23: IntegerLiteral= Extent=[65:23 - 65:24]
// CHECK-source: usrs.m:66:1: ObjCInstanceMethodDecl=meth3:66:1 (Definition) [Overrides @58:1] Extent=[66:1 - 66:27]
// CHECK-source: usrs.m:66:4: TypeRef=id:0:0 Extent=[66:4 - 66:6]
-// CHECK-source: usrs.m:66:14: UnexposedStmt= Extent=[66:14 - 66:27]
-// CHECK-source: usrs.m:66:16: UnexposedStmt= Extent=[66:16 - 66:24]
+// CHECK-source: usrs.m:66:14: CompoundStmt= Extent=[66:14 - 66:27]
+// CHECK-source: usrs.m:66:16: ReturnStmt= Extent=[66:16 - 66:24]
// CHECK-source: usrs.m:66:23: UnexposedExpr= Extent=[66:23 - 66:24]
-// CHECK-source: usrs.m:66:23: UnexposedExpr= Extent=[66:23 - 66:24]
-// CHECK-source: usrs.m:68:1: ObjCCategoryImplDecl=Bar:68:1 (Definition) Extent=[68:1 - 70:2]
-// CHECK-source: usrs.m:68:1: ObjCClassRef=CWithExt:51:12 Extent=[68:1 - 68:2]
+// CHECK-source: usrs.m:66:23: IntegerLiteral= Extent=[66:23 - 66:24]
+// CHECK-source: usrs.m:68:17: ObjCCategoryImplDecl=Bar:68:17 (Definition) Extent=[68:1 - 70:2]
+// CHECK-source: usrs.m:68:17: ObjCClassRef=CWithExt:51:12 Extent=[68:17 - 68:25]
// CHECK-source: usrs.m:69:1: ObjCInstanceMethodDecl=meth4:69:1 (Definition) [Overrides @61:1] Extent=[69:1 - 69:27]
// CHECK-source: usrs.m:69:4: TypeRef=id:0:0 Extent=[69:4 - 69:6]
-// CHECK-source: usrs.m:69:14: UnexposedStmt= Extent=[69:14 - 69:27]
-// CHECK-source: usrs.m:69:16: UnexposedStmt= Extent=[69:16 - 69:24]
-// CHECK-source: usrs.m:69:23: UnexposedExpr= Extent=[69:23 - 69:24]
+// CHECK-source: usrs.m:69:14: CompoundStmt= Extent=[69:14 - 69:27]
+// CHECK-source: usrs.m:69:16: ReturnStmt= Extent=[69:16 - 69:24]
// CHECK-source: usrs.m:69:23: UnexposedExpr= Extent=[69:23 - 69:24]
+// CHECK-source: usrs.m:69:23: IntegerLiteral= Extent=[69:23 - 69:24]
// CHECK-source: usrs.m:72:6: FunctionDecl=aux_1:72:6 Extent=[72:1 - 72:26]
// CHECK-source: usrs.m:72:15: ParmDecl=:72:15 (Definition) Extent=[72:12 - 72:16]
// CHECK-source: usrs.m:72:20: ParmDecl=:72:20 (Definition) Extent=[72:17 - 72:21]
// CHECK-source: usrs.m:72:25: ParmDecl=:72:25 (Definition) Extent=[72:22 - 72:26]
// CHECK-source: usrs.m:73:5: FunctionDecl=test_multi_declaration:73:5 (Definition) Extent=[73:1 - 77:2]
-// CHECK-source: usrs.m:73:34: UnexposedStmt= Extent=[73:34 - 77:2]
-// CHECK-source: usrs.m:74:3: UnexposedStmt= Extent=[74:3 - 74:33]
+// CHECK-source: usrs.m:73:34: CompoundStmt= Extent=[73:34 - 77:2]
+// CHECK-source: usrs.m:74:3: DeclStmt= Extent=[74:3 - 74:33]
// CHECK-source: usrs.m:74:7: VarDecl=foo:74:7 (Definition) Extent=[74:3 - 74:14]
-// CHECK-source: usrs.m:74:13: UnexposedExpr= Extent=[74:13 - 74:14]
+// CHECK-source: usrs.m:74:13: IntegerLiteral= Extent=[74:13 - 74:14]
// CHECK-source: usrs.m:74:16: VarDecl=bar:74:16 Extent=[74:16 - 74:23]
-// CHECK-source: usrs.m:74:22: UnexposedExpr= Extent=[74:22 - 74:23]
+// CHECK-source: usrs.m:74:22: IntegerLiteral= Extent=[74:22 - 74:23]
// CHECK-source: usrs.m:74:25: VarDecl=baz:74:25 Extent=[74:25 - 74:32]
-// CHECK-source: usrs.m:74:31: UnexposedExpr= Extent=[74:31 - 74:32]
+// CHECK-source: usrs.m:74:31: IntegerLiteral= Extent=[74:31 - 74:32]
// CHECK-source: usrs.m:75:3: CallExpr=aux_1:72:6 Extent=[75:3 - 75:23]
// CHECK-source: usrs.m:75:3: UnexposedExpr=aux_1:72:6 Extent=[75:3 - 75:8]
// CHECK-source: usrs.m:75:3: DeclRefExpr=aux_1:72:6 Extent=[75:3 - 75:8]
// CHECK-source: usrs.m:75:9: DeclRefExpr=foo:74:7 Extent=[75:9 - 75:12]
// CHECK-source: usrs.m:75:14: DeclRefExpr=bar:74:16 Extent=[75:14 - 75:17]
// CHECK-source: usrs.m:75:19: DeclRefExpr=baz:74:25 Extent=[75:19 - 75:22]
-// CHECK-source: usrs.m:76:3: UnexposedStmt= Extent=[76:3 - 76:11]
-// CHECK-source: usrs.m:76:10: UnexposedExpr= Extent=[76:10 - 76:11]
-// CHECK-source: usrs.m:79:1: ObjCProtocolDecl=P1:79:1 (Definition) Extent=[79:1 - 81:5]
+// CHECK-source: usrs.m:76:3: ReturnStmt= Extent=[76:3 - 76:11]
+// CHECK-source: usrs.m:76:10: IntegerLiteral= Extent=[76:10 - 76:11]
+// CHECK-source: usrs.m:79:11: ObjCProtocolDecl=P1:79:11 (Definition) Extent=[79:1 - 81:5]
// CHECK-source: usrs.m:80:1: ObjCInstanceMethodDecl=method:80:1 Extent=[80:1 - 80:16]
diff --git a/test/Lexer/bcpl-escaped-newline.c b/test/Lexer/bcpl-escaped-newline.c
new file mode 100644
index 000000000000..4d4a7b5e89eb
--- /dev/null
+++ b/test/Lexer/bcpl-escaped-newline.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -Eonly -trigraphs %s
+// RUN: %clang_cc1 -Eonly -verify %s
+
+//\
+#error bar
+
+//??/
+#error qux // expected-error {{qux}}
+
+// Trailing whitespace!
+//\
+#error quux
diff --git a/test/Lexer/constants.c b/test/Lexer/constants.c
index 3d2da2c764e6..013103b1f5dd 100644
--- a/test/Lexer/constants.c
+++ b/test/Lexer/constants.c
@@ -65,3 +65,5 @@ double t1[] = {
// PR7888
double g = 1e100000000; // expected-warning {{too large}}
+
+char h = '\u1234'; // expected-warning {{character unicode escape sequence too long for its type}}
diff --git a/test/Lexer/cxx0x_keyword.cpp b/test/Lexer/cxx0x_keyword.cpp
index c27925bcfee4..e6841ef7665d 100644
--- a/test/Lexer/cxx0x_keyword.cpp
+++ b/test/Lexer/cxx0x_keyword.cpp
@@ -1,2 +1,2 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s 2>&1
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s 2>&1
int static_assert; /* expected-error {{expected unqualified-id}} */
diff --git a/test/Lexer/cxx0x_keyword_as_cxx98.cpp b/test/Lexer/cxx0x_keyword_as_cxx98.cpp
index 0223b039be92..d87d3dc7faff 100644
--- a/test/Lexer/cxx0x_keyword_as_cxx98.cpp
+++ b/test/Lexer/cxx0x_keyword_as_cxx98.cpp
@@ -1,3 +1,36 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only
-int static_assert;
-int char16_t;
+
+#define constexpr const
+constexpr int x = 0;
+#undef constexpr
+
+namespace lib {
+ struct nullptr_t;
+ typedef nullptr_t nullptr; // expected-warning {{'nullptr' is a keyword in C++11}}
+}
+
+#define CONCAT(X,Y) CONCAT2(X,Y)
+#define CONCAT2(X,Y) X ## Y
+int CONCAT(constexpr,ession);
+
+#define ID(X) X
+extern int ID(decltype); // expected-warning {{'decltype' is a keyword in C++11}}
+
+extern int CONCAT(align,of); // expected-warning {{'alignof' is a keyword in C++11}}
+
+#define static_assert(b, s) int CONCAT(check, __LINE__)[(b) ? 1 : 0];
+static_assert(1 > 0, "hello"); // ok
+
+#define IF_CXX11(CXX11, CXX03) CXX03
+typedef IF_CXX11(char16_t, wchar_t) my_wide_char_t; // ok
+
+int alignas; // expected-warning {{'alignas' is a keyword in C++11}}
+int alignof; // already diagnosed in this TU
+int char16_t; // expected-warning {{'char16_t' is a keyword in C++11}}
+int char32_t; // expected-warning {{'char32_t' is a keyword in C++11}}
+int constexpr; // expected-warning {{'constexpr' is a keyword in C++11}}
+int decltype; // already diagnosed in this TU
+int noexcept; // expected-warning {{'noexcept' is a keyword in C++11}}
+int nullptr; // already diagnosed in this TU
+int static_assert; // expected-warning {{'static_assert' is a keyword in C++11}}
+int thread_local; // expected-warning {{'thread_local' is a keyword in C++11}}
diff --git a/test/Lexer/cxx0x_raw_string_delim_length.cpp b/test/Lexer/cxx0x_raw_string_delim_length.cpp
new file mode 100644
index 000000000000..e7d5c6f8cd27
--- /dev/null
+++ b/test/Lexer/cxx0x_raw_string_delim_length.cpp
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -std=c++11 -E %s 2>&1 | grep 'error: raw string delimiter longer than 16 characters'
+
+const char *str = R"abcdefghijkmnopqrstuvwxyz(abcdef)abcdefghijkmnopqrstuvwxyz";
diff --git a/test/Lexer/cxx0x_raw_string_unterminated.cpp b/test/Lexer/cxx0x_raw_string_unterminated.cpp
new file mode 100644
index 000000000000..dfbaaeee1e72
--- /dev/null
+++ b/test/Lexer/cxx0x_raw_string_unterminated.cpp
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -std=c++11 -E %s 2>&1 | grep 'error: raw string missing terminating delimiter )foo"'
+
+const char *str = R"foo(abc
+def)bar";
diff --git a/test/Lexer/has_extension.c b/test/Lexer/has_extension.c
index bc75a4a1c546..4c322c7ce7a3 100644
--- a/test/Lexer/has_extension.c
+++ b/test/Lexer/has_extension.c
@@ -28,3 +28,11 @@ int has_c_generic_selections();
int no_c_generic_selections();
#endif
+// CHECK-PED-NONE: has_c_alignas
+// CHECK-PED-ERR: no_c_alignas
+#if __has_extension(c_alignas)
+int has_c_alignas();
+#else
+int no_c_alignas();
+#endif
+
diff --git a/test/Lexer/has_extension_cxx.cpp b/test/Lexer/has_extension_cxx.cpp
index 77efa357938c..5481b596cc4a 100644
--- a/test/Lexer/has_extension_cxx.cpp
+++ b/test/Lexer/has_extension_cxx.cpp
@@ -25,6 +25,11 @@ int has_inline_namespaces();
int has_override_control();
#endif
+// CHECK: has_range_for
+#if __has_extension(cxx_range_for)
+int has_range_for();
+#endif
+
// CHECK: has_reference_qualified_functions
#if __has_extension(cxx_reference_qualified_functions)
int has_reference_qualified_functions();
diff --git a/test/Lexer/has_feature_c1x.c b/test/Lexer/has_feature_c1x.c
index 6c0fb212cce3..ca4e9b95ad04 100644
--- a/test/Lexer/has_feature_c1x.c
+++ b/test/Lexer/has_feature_c1x.c
@@ -18,3 +18,12 @@ int no_generic_selections();
// CHECK-1X: has_generic_selections
// CHECK-NO-1X: no_generic_selections
+
+#if __has_feature(c_alignas)
+int has_alignas();
+#else
+int no_alignas();
+#endif
+
+// CHECK-1X: has_alignas
+// CHECK-NO-1X: no_alignas
diff --git a/test/Lexer/has_feature_cxx0x.cpp b/test/Lexer/has_feature_cxx0x.cpp
index ca5f868d9b05..f2b4576b57e9 100644
--- a/test/Lexer/has_feature_cxx0x.cpp
+++ b/test/Lexer/has_feature_cxx0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -E -std=c++0x %s -o - | FileCheck --check-prefix=CHECK-0X %s
+// RUN: %clang_cc1 -E -std=c++11 %s -o - | FileCheck --check-prefix=CHECK-0X %s
// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-0X %s
#if __has_feature(cxx_lambdas)
@@ -164,3 +164,21 @@ int no_alias_templates();
// CHECK-0X: has_alias_templates
// CHECK-NO-0X: no_alias_templates
+
+#if __has_feature(cxx_implicit_moves)
+int has_implicit_moves();
+#else
+int no_implicit_moves();
+#endif
+
+// CHECK-0X: has_implicit_moves
+// CHECK-NO-0X: no_implicit_moves
+
+#if __has_feature(cxx_alignas)
+int has_alignas();
+#else
+int no_alignas();
+#endif
+
+// CHECK-0X: has_alignas
+// CHECK-NO-0X: no_alignas
diff --git a/test/Lexer/has_feature_objc_arc.m b/test/Lexer/has_feature_objc_arc.m
index cd41900c60b7..279b91af39cd 100644
--- a/test/Lexer/has_feature_objc_arc.m
+++ b/test/Lexer/has_feature_objc_arc.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -E %s -fobjc-nonfragile-abi -fobjc-arc "-triple" "x86_64-apple-macosx10.7.0" -fobjc-runtime-has-weak | FileCheck --check-prefix=CHECK-ARC %s
-// RUN: %clang_cc1 -E %s -fobjc-nonfragile-abi -fobjc-arc "-triple" "x86_64-apple-macosx10.6.0" | FileCheck --check-prefix=CHECK-ARCLITE %s
+// RUN: %clang_cc1 -E %s -fobjc-arc "-triple" "x86_64-apple-macosx10.7.0" -fobjc-runtime-has-weak | FileCheck --check-prefix=CHECK-ARC %s
+// RUN: %clang_cc1 -E %s -fobjc-arc "-triple" "x86_64-apple-macosx10.6.0" | FileCheck --check-prefix=CHECK-ARCLITE %s
#if __has_feature(objc_arc)
void has_objc_arc_feature();
diff --git a/test/Lexer/has_feature_type_traits.cpp b/test/Lexer/has_feature_type_traits.cpp
index 5da845f06512..53056a02b72a 100644
--- a/test/Lexer/has_feature_type_traits.cpp
+++ b/test/Lexer/has_feature_type_traits.cpp
@@ -99,3 +99,8 @@ int is_standard_layout();
int is_trivially_copyable();
#endif
// CHECK: int is_trivially_copyable();
+
+#if __has_feature(underlying_type)
+int underlying_type();
+#endif
+// CHECK: int underlying_type();
diff --git a/test/Lexer/hexfloat.cpp b/test/Lexer/hexfloat.cpp
index 493b64e62740..23daa49ad210 100644
--- a/test/Lexer/hexfloat.cpp
+++ b/test/Lexer/hexfloat.cpp
@@ -1,9 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
-// XFAIL: *
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -pedantic %s
+float f = 0x1p+1; // expected-warning{{hexadecimal floating constants are a C99 feature}}
-#ifndef __GXX_EXPERIMENTAL_CXX0X__
-float f = 0x1p+1; // expected-warning {{incompatible with C++0x}}
-#else
-float f = 0x1p+1; // expected-warning {{invalid suffix}}
-#endif
diff --git a/test/Lexer/newline-eof.c b/test/Lexer/newline-eof.c
new file mode 100644
index 000000000000..2f95dc7593c7
--- /dev/null
+++ b/test/Lexer/newline-eof.c
@@ -0,0 +1,5 @@
+// RUN: %clang -fsyntax-only -Wnewline-eof -verify %s
+// rdar://9133072
+
+// The following line isn't terminated, don't fix it.
+void foo() {} // expected-warning{{No newline at end of file}} \ No newline at end of file
diff --git a/test/Lexer/preamble.c b/test/Lexer/preamble.c
index 7735b475e1ae..5b2739abefcc 100644
--- a/test/Lexer/preamble.c
+++ b/test/Lexer/preamble.c
@@ -1,5 +1,5 @@
// Preamble detection test: see below for comments and test commands.
-//
+//* A BCPL comment that includes '/*'
#include <blah>
#ifndef FOO
#else
@@ -24,7 +24,7 @@ int foo();
// RUN: FileCheck < %t %s
// CHECK: // Preamble detection test: see below for comments and test commands.
-// CHECK-NEXT: //
+// CHECK-NEXT: //* A BCPL comment that includes '/*'
// CHECK-NEXT: #include <blah>
// CHECK-NEXT: #ifndef FOO
// CHECK-NEXT: #else
diff --git a/test/Lexer/string_concat.cpp b/test/Lexer/string_concat.cpp
new file mode 100644
index 000000000000..43782bce8c50
--- /dev/null
+++ b/test/Lexer/string_concat.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+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 }}
+ 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 }}
+
+ 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 }}
+ 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 }}
+
+ 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 }}
+ 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 }}
+
+ 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 }}
+ 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 }}
+}
+
diff --git a/test/Lexer/utf8-char-literal.cpp b/test/Lexer/utf8-char-literal.cpp
new file mode 100644
index 000000000000..c4ea5fc3c3e9
--- /dev/null
+++ b/test/Lexer/utf8-char-literal.cpp
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -fsyntax-only -verify %s
+
+int array0[u'ñ' == u'\xf1'? 1 : -1];
+int array1['ñ' != u'\xf1'? 1 : -1];
diff --git a/test/Lexer/wchar.c b/test/Lexer/wchar.c
index ac82c1f73b4d..648a38ef3f9a 100644
--- a/test/Lexer/wchar.c
+++ b/test/Lexer/wchar.c
@@ -5,8 +5,8 @@ void f() {
(void)L'\U00010000'; // expected-warning {{character unicode escape sequence too long for its type}}
- (void)L'ab'; // expected-warning {{extraneous characters in wide character constant ignored}}
+ (void)L'ab'; // expected-warning {{extraneous characters in character constant ignored}}
- (void)L'a\u1000'; // expected-warning {{extraneous characters in wide character constant ignored}}
+ (void)L'a\u1000'; // expected-warning {{extraneous characters in character constant ignored}}
}
diff --git a/test/Misc/ast-dump-templates.cpp b/test/Misc/ast-dump-templates.cpp
new file mode 100644
index 000000000000..7d56e7b04eb2
--- /dev/null
+++ b/test/Misc/ast-dump-templates.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -ast-dump %s > %t
+// RUN: FileCheck < %t %s -check-prefix=CHECK1
+// RUN: FileCheck < %t %s -check-prefix=CHECK2
+
+template <int X, typename Y, int Z = 5>
+struct foo {
+ int constant;
+ foo() {}
+ Y getSum() { return Y(X + Z); }
+};
+
+template <int A, typename B>
+B bar() {
+ return B(A);
+}
+
+void baz() {
+ int x = bar<5, int>();
+ int y = foo<5, int>().getSum();
+ double z = foo<2, double, 3>().getSum();
+}
+
+// Template instantiation - foo
+// Since the order of instantiation may vary during runs, run FileCheck twice
+// to make sure each instantiation is in the correct spot.
+// CHECK1: template <int X = 5, typename Y = int, int Z = 5> struct foo {
+// 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)
+
+// Template instantiation - bar
+// CHECK1: template <int A = 5, typename B = int> int bar()
+// CHECK2: template <int A = 5, typename B = int> int bar()
+
+// Template definition - bar
+// CHECK1: template <int A, typename B> B bar()
+// CHECK2: template <int A, typename B> B bar()
diff --git a/test/Misc/caret-diags-macros.c b/test/Misc/caret-diags-macros.c
index ac83ecc69525..3d2e576d6414 100644
--- a/test/Misc/caret-diags-macros.c
+++ b/test/Misc/caret-diags-macros.c
@@ -113,11 +113,8 @@ void test3() {
// CHECK: {{.*}}:102:41: note: expanded from:
variadic_pasting_args3a(1, 2, 3, 4);
- // FIXME: It'd be really nice to retain the start location of the first token
- // involved in the token paste instead of falling back on the full macro
- // location in the first two locations here.
- // CHECK: {{.*}}:115:3: warning: expression result unused
- // CHECK: {{.*}}:106:44: note: expanded from:
- // CHECK: {{.*}}:104:72: note: expanded from:
+ // CHECK: {{.*}}:115:30: warning: expression result unused
+ // CHECK: {{.*}}:106:71: note: expanded from:
+ // CHECK: {{.*}}:104:70: note: expanded from:
// CHECK: {{.*}}:102:41: note: expanded from:
}
diff --git a/test/Misc/diag-aka-types.cpp b/test/Misc/diag-aka-types.cpp
index 042c70b18a75..0339b7b63e82 100644
--- a/test/Misc/diag-aka-types.cpp
+++ b/test/Misc/diag-aka-types.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++0x
+// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++11
struct X {};
typedef X foo_t;
diff --git a/test/Misc/diag-line-wrapping.cpp b/test/Misc/diag-line-wrapping.cpp
new file mode 100644
index 000000000000..830aa1340831
--- /dev/null
+++ b/test/Misc/diag-line-wrapping.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -fmessage-length 60 %s 2>&1 | FileCheck %s
+
+struct B { void f(); };
+struct D1 : B {};
+struct D2 : B {};
+struct DD : D1, D2 {
+ void g() { f(); }
+ // Ensure that after line-wrapping takes place, we preserve artificial
+ // newlines introduced to manually format a section of the diagnostic text.
+ // CHECK: {{.*}}: error:
+ // CHECK: struct DD -> struct D1 -> struct B
+ // CHECK: struct DD -> struct D2 -> struct B
+}
diff --git a/test/Misc/error-limit-multiple-notes.cpp b/test/Misc/error-limit-multiple-notes.cpp
new file mode 100644
index 000000000000..019b4dde2633
--- /dev/null
+++ b/test/Misc/error-limit-multiple-notes.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -ferror-limit 1 -fsyntax-only %s 2>&1 | FileCheck %s
+
+// error and three notes emitted
+void foo(int);
+void foo(double);
+void foo(int, int);
+
+int main()
+{
+ foo();
+}
+
+// error and note suppressed by error-limit
+struct s1{};
+struct s1{};
+
+// CHECK: 10:5: error: no matching function for call to 'foo'
+// CHECK: 6:6: note: candidate function not viable: requires 2 arguments, but 0 were provided
+// CHECK: 5:6: note: candidate function not viable: requires 1 argument, but 0 were provided
+// CHECK: 4:6: note: candidate function not viable: requires 1 argument, but 0 were provided
+// CHECK: fatal error: too many errors emitted, stopping now
+// CHECK-NOT: 15:8: error: redefinition of 's1'
+// CHECK-NOT: 14:8: note: previous definition is here
diff --git a/test/Misc/error-limit.c b/test/Misc/error-limit.c
new file mode 100644
index 000000000000..26f4ac1d8a5e
--- /dev/null
+++ b/test/Misc/error-limit.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -ferror-limit 1 -fsyntax-only %s 2>&1 | FileCheck %s
+
+// error and note emitted
+struct s1{};
+struct s1{};
+
+// error and note suppressed by error-limit
+struct s2{};
+struct s2{};
+
+// CHECK: 5:8: error: redefinition of 's1'
+// CHECK: 4:8: note: previous definition is here
+// CHECK: fatal error: too many errors emitted, stopping now
+// CHECK-NOT: 9:8: error: redefinition of 's2'
+// CHECK-NOT: 8:8: note: previous definition is here
diff --git a/test/Misc/show-diag-options.c b/test/Misc/show-diag-options.c
new file mode 100644
index 000000000000..f0404a8555de
--- /dev/null
+++ b/test/Misc/show-diag-options.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fsyntax-only %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=BASE
+// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-show-option %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=OPTION
+// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-show-option -Werror %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=OPTION_ERROR
+// RUN: %clang_cc1 -fsyntax-only -std=c89 -pedantic -fdiagnostics-show-option %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=OPTION_PEDANTIC
+// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-show-category id %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CATEGORY_ID
+// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-show-category name %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CATEGORY_NAME
+// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-show-option -fdiagnostics-show-category name -Werror %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=OPTION_ERROR_CATEGORY
+
+void test(int x, int y) {
+ if (x = y) ++x;
+ // BASE: {{.*}}: warning: {{[a-z ]+$}}
+ // OPTION: {{.*}}: warning: {{[a-z ]+}} [-Wparentheses]
+ // OPTION_ERROR: {{.*}}: error: {{[a-z ]+}} [-Werror,-Wparentheses]
+ // CATEGORY_ID: {{.*}}: warning: {{[a-z ]+}} [2]
+ // CATEGORY_NAME: {{.*}}: warning: {{[a-z ]+}} [Semantic Issue]
+ // OPTION_ERROR_CATEGORY: {{.*}}: error: {{[a-z ]+}} [-Werror,-Wparentheses,Semantic Issue]
+
+ // Leverage the fact that all these '//'s get warned about in C89 pedantic.
+ // OPTION_PEDANTIC: {{.*}}: warning: {{[/a-z ]+}} [-pedantic,-Wcomment]
+}
diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c
new file mode 100644
index 000000000000..2f7103ab1cd2
--- /dev/null
+++ b/test/Misc/warning-flags.c
@@ -0,0 +1,317 @@
+RUN: diagtool list-warnings 2>&1 | FileCheck %s
+
+This test serves two purposes:
+
+(1) It documents all existing warnings that currently have no associated -W flag,
+ and ensures that the list never grows.
+
+ If take an existing warning and add a flag, this test will fail. To
+ fix this test, simply remove that warning from the list below.
+
+(2) It prevents us adding new warnings to Clang that have no -W flag. All
+ new warnings should have -W flags.
+
+ If you add a new warning without a flag, this test will fail. To fix
+ this test, simply add a warning group to that warning.
+
+
+The list of warnings below should NEVER grow. It should gradually shrink to 0.
+
+CHECK: Warnings without flags (297):
+CHECK-NEXT: backslash_newline_space
+CHECK-NEXT: charize_microsoft_ext
+CHECK-NEXT: ext_anon_param_requires_type_specifier
+CHECK-NEXT: ext_anonymous_struct_union_qualified
+CHECK-NEXT: ext_array_init_copy
+CHECK-NEXT: ext_auto_storage_class
+CHECK-NEXT: ext_binary_literal
+CHECK-NEXT: ext_c99_array_usage
+CHECK-NEXT: ext_c99_compound_literal
+CHECK-NEXT: ext_c99_variable_decl_in_for_loop
+CHECK-NEXT: ext_c99_whitespace_required_after_macro_name
+CHECK-NEXT: ext_cast_fn_obj
+CHECK-NEXT: ext_catch_incomplete_ptr
+CHECK-NEXT: ext_catch_incomplete_ref
+CHECK-NEXT: ext_delete_void_ptr_operand
+CHECK-NEXT: ext_designated_init
+CHECK-NEXT: ext_designated_init_cxx
+CHECK-NEXT: ext_dollar_in_identifier
+CHECK-NEXT: ext_duplicate_declspec
+CHECK-NEXT: ext_ellipsis_exception_spec
+CHECK-NEXT: ext_embedded_directive
+CHECK-NEXT: ext_empty_fnmacro_arg
+CHECK-NEXT: ext_empty_source_file
+CHECK-NEXT: ext_enum_friend
+CHECK-NEXT: ext_enum_value_not_int
+CHECK-NEXT: ext_enumerator_list_comma
+CHECK-NEXT: ext_expected_semi_decl_list
+CHECK-NEXT: ext_explicit_instantiation_without_qualified_id
+CHECK-NEXT: ext_explicit_specialization_storage_class
+CHECK-NEXT: ext_expr_not_ice
+CHECK-NEXT: ext_extra_ivar_semi
+CHECK-NEXT: ext_extra_struct_semi
+CHECK-NEXT: ext_flexible_array_in_array
+CHECK-NEXT: ext_flexible_array_in_struct
+CHECK-NEXT: ext_forward_ref_enum
+CHECK-NEXT: ext_freestanding_complex
+CHECK-NEXT: ext_hexconstant_invalid
+CHECK-NEXT: ext_ident_list_in_param
+CHECK-NEXT: ext_imaginary_constant
+CHECK-NEXT: ext_implicit_lib_function_decl
+CHECK-NEXT: ext_in_class_initializer_non_constant
+CHECK-NEXT: ext_integer_complement_complex
+CHECK-NEXT: ext_integer_complex
+CHECK-NEXT: ext_integer_increment_complex
+CHECK-NEXT: ext_invalid_sign_spec
+CHECK-NEXT: ext_missing_declspec
+CHECK-NEXT: ext_missing_varargs_arg
+CHECK-NEXT: ext_missing_whitespace_after_macro_name
+CHECK-NEXT: ext_new_paren_array_nonconst
+CHECK-NEXT: ext_nonstandard_escape
+CHECK-NEXT: ext_offsetof_extended_field_designator
+CHECK-NEXT: ext_param_not_declared
+CHECK-NEXT: ext_param_promoted_not_compatible_with_prototype
+CHECK-NEXT: ext_paste_comma
+CHECK-NEXT: ext_plain_complex
+CHECK-NEXT: ext_pp_bad_vaargs_use
+CHECK-NEXT: ext_pp_comma_expr
+CHECK-NEXT: ext_pp_ident_directive
+CHECK-NEXT: ext_pp_import_directive
+CHECK-NEXT: ext_pp_include_next_directive
+CHECK-NEXT: ext_pp_line_too_big
+CHECK-NEXT: ext_pp_macro_redef
+CHECK-NEXT: ext_pp_warning_directive
+CHECK-NEXT: ext_return_has_void_expr
+CHECK-NEXT: ext_subscript_non_lvalue
+CHECK-NEXT: ext_template_arg_extra_parens
+CHECK-NEXT: ext_thread_before
+CHECK-NEXT: ext_top_level_semi
+CHECK-NEXT: ext_typecheck_addrof_void
+CHECK-NEXT: ext_typecheck_cast_nonscalar
+CHECK-NEXT: ext_typecheck_cast_to_union
+CHECK-NEXT: ext_typecheck_comparison_of_distinct_pointers
+CHECK-NEXT: ext_typecheck_comparison_of_distinct_pointers_nonstandard
+CHECK-NEXT: ext_typecheck_comparison_of_fptr_to_void
+CHECK-NEXT: ext_typecheck_comparison_of_pointer_integer
+CHECK-NEXT: ext_typecheck_cond_incompatible_operands
+CHECK-NEXT: ext_typecheck_cond_incompatible_operands_nonstandard
+CHECK-NEXT: ext_typecheck_cond_one_void
+CHECK-NEXT: ext_typecheck_convert_int_pointer
+CHECK-NEXT: ext_typecheck_convert_pointer_int
+CHECK-NEXT: ext_typecheck_convert_pointer_void_func
+CHECK-NEXT: ext_typecheck_ordered_comparison_of_function_pointers
+CHECK-NEXT: ext_typecheck_ordered_comparison_of_pointer_and_zero
+CHECK-NEXT: ext_typecheck_ordered_comparison_of_pointer_integer
+CHECK-NEXT: ext_typecheck_zero_array_size
+CHECK-NEXT: ext_unknown_escape
+CHECK-NEXT: ext_using_undefined_std
+CHECK-NEXT: ext_vla_folded_to_constant
+CHECK-NEXT: null_in_char
+CHECK-NEXT: null_in_file
+CHECK-NEXT: null_in_string
+CHECK-NEXT: pp_include_next_absolute_path
+CHECK-NEXT: pp_include_next_in_primary
+CHECK-NEXT: pp_invalid_string_literal
+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
+CHECK-NEXT: warn_asm_label_on_auto_decl
+CHECK-NEXT: warn_attribute_ibaction
+CHECK-NEXT: warn_attribute_iboutlet
+CHECK-NEXT: warn_attribute_ignored
+CHECK-NEXT: warn_attribute_ignored_for_field_of_type
+CHECK-NEXT: warn_attribute_malloc_pointer_only
+CHECK-NEXT: warn_attribute_method_def
+CHECK-NEXT: warn_attribute_nonnull_no_pointers
+CHECK-NEXT: warn_attribute_precede_definition
+CHECK-NEXT: warn_attribute_sentinel_named_arguments
+CHECK-NEXT: warn_attribute_sentinel_not_variadic
+CHECK-NEXT: warn_attribute_type_not_supported
+CHECK-NEXT: warn_attribute_unknown_visibility
+CHECK-NEXT: warn_attribute_void_function_method
+CHECK-NEXT: warn_attribute_weak_import_invalid_on_definition
+CHECK-NEXT: warn_attribute_weak_on_field
+CHECK-NEXT: warn_attribute_weak_on_local
+CHECK-NEXT: warn_attribute_wrong_decl_type
+CHECK-NEXT: warn_availability_and_unavailable
+CHECK-NEXT: warn_availability_unknown_platform
+CHECK-NEXT: warn_availability_version_ordering
+CHECK-NEXT: warn_bad_receiver_type
+CHECK-NEXT: warn_bitfield_width_exceeds_type_size
+CHECK-NEXT: warn_bool_switch_condition
+CHECK-NEXT: warn_braces_around_scalar_init
+CHECK-NEXT: warn_builtin_unknown
+CHECK-NEXT: warn_c_kext
+CHECK-NEXT: warn_call_to_pure_virtual_member_function_from_ctor_dtor
+CHECK-NEXT: warn_call_wrong_number_of_arguments
+CHECK-NEXT: warn_case_empty_range
+CHECK-NEXT: warn_char_constant_too_large
+CHECK-NEXT: warn_class_method_not_found
+CHECK-NEXT: warn_cmdline_missing_macro_defs
+CHECK-NEXT: warn_collection_expr_type
+CHECK-NEXT: warn_conflicting_param_types
+CHECK-NEXT: warn_conflicting_ret_types
+CHECK-NEXT: warn_conflicting_variadic
+CHECK-NEXT: warn_conv_to_base_not_used
+CHECK-NEXT: warn_conv_to_self_not_used
+CHECK-NEXT: warn_conv_to_void_not_used
+CHECK-NEXT: warn_cxx0x_right_shift_in_template_arg
+CHECK-NEXT: warn_decl_in_param_list
+CHECK-NEXT: warn_delete_array_type
+CHECK-NEXT: warn_delete_incomplete
+CHECK-NEXT: warn_division_by_zero
+CHECK-NEXT: warn_double_const_requires_fp64
+CHECK-NEXT: warn_drv_assuming_mfloat_abi_is
+CHECK-NEXT: warn_drv_clang_unsupported
+CHECK-NEXT: warn_drv_conflicting_deployment_targets
+CHECK-NEXT: warn_drv_input_file_unused
+CHECK-NEXT: warn_drv_not_using_clang_arch
+CHECK-NEXT: warn_drv_not_using_clang_cpp
+CHECK-NEXT: warn_drv_not_using_clang_cxx
+CHECK-NEXT: warn_drv_objc_gc_unsupported
+CHECK-NEXT: warn_drv_pch_not_first_include
+CHECK-NEXT: warn_drv_pipe_ignored_with_save_temps
+CHECK-NEXT: warn_drv_preprocessed_input_file_unused
+CHECK-NEXT: warn_drv_unsupported_option_argument
+CHECK-NEXT: warn_drv_unused_argument
+CHECK-NEXT: warn_dup_category_def
+CHECK-NEXT: warn_duplicate_protocol_def
+CHECK-NEXT: warn_enum_too_large
+CHECK-NEXT: warn_enum_value_overflow
+CHECK-NEXT: warn_enumerator_too_large
+CHECK-NEXT: warn_exception_caught_by_earlier_handler
+CHECK-NEXT: warn_excess_initializers
+CHECK-NEXT: warn_excess_initializers_in_char_array_initializer
+CHECK-NEXT: warn_expected_qualified_after_typename
+CHECK-NEXT: warn_extern_init
+CHECK-NEXT: warn_extraneous_char_constant
+CHECK-NEXT: warn_fe_cc_log_diagnostics_failure
+CHECK-NEXT: warn_fe_cc_print_header_failure
+CHECK-NEXT: warn_fe_macro_contains_embedded_newline
+CHECK-NEXT: warn_file_asm_volatile
+CHECK-NEXT: warn_function_attribute_wrong_type
+CHECK-NEXT: warn_gc_attribute_weak_on_local
+CHECK-NEXT: warn_gnu_inline_attribute_requires_inline
+CHECK-NEXT: warn_hex_escape_too_large
+CHECK-NEXT: warn_ignoring_ftabstop_value
+CHECK-NEXT: warn_illegal_constant_array_size
+CHECK-NEXT: warn_implements_nscopying
+CHECK-NEXT: warn_implicit_decl_requires_setjmp
+CHECK-NEXT: warn_implicit_decl_requires_stdio
+CHECK-NEXT: warn_incompatible_qualified_id
+CHECK-NEXT: warn_initializer_string_for_char_array_too_long
+CHECK-NEXT: warn_inline_namespace_reopened_noninline
+CHECK-NEXT: warn_inst_method_not_found
+CHECK-NEXT: warn_instance_method_on_class_found
+CHECK-NEXT: warn_integer_too_large
+CHECK-NEXT: warn_integer_too_large_for_signed
+CHECK-NEXT: warn_invalid_asm_cast_lvalue
+CHECK-NEXT: warn_label_attribute_not_unused
+CHECK-NEXT: warn_many_braces_around_scalar_init
+CHECK-NEXT: warn_maynot_respond
+CHECK-NEXT: warn_member_extra_qualification
+CHECK-NEXT: warn_method_param_redefinition
+CHECK-NEXT: warn_mismatched_exception_spec
+CHECK-NEXT: warn_missing_case_for_condition
+CHECK-NEXT: warn_missing_dependent_template_keyword
+CHECK-NEXT: warn_missing_exception_specification
+CHECK-NEXT: warn_missing_whitespace_after_macro_name
+CHECK-NEXT: warn_multiple_method_decl
+CHECK-NEXT: warn_no_constructor_for_refconst
+CHECK-NEXT: warn_nonnull_pointers_only
+CHECK-NEXT: warn_not_compound_assign
+CHECK-NEXT: warn_ns_attribute_wrong_parameter_type
+CHECK-NEXT: warn_ns_attribute_wrong_return_type
+CHECK-NEXT: warn_objc_object_attribute_wrong_type
+CHECK-NEXT: warn_objc_property_copy_missing_on_block
+CHECK-NEXT: warn_objc_property_default_assign_on_object
+CHECK-NEXT: warn_objc_property_no_assignment_attribute
+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_parens_disambiguated_as_function_decl
+CHECK-NEXT: warn_partial_specs_not_deducible
+CHECK-NEXT: warn_pointer_attribute_wrong_type
+CHECK-NEXT: warn_pp_convert_lhs_to_positive
+CHECK-NEXT: warn_pp_convert_rhs_to_positive
+CHECK-NEXT: warn_pp_expr_overflow
+CHECK-NEXT: warn_pp_line_decimal
+CHECK-NEXT: warn_pragma_align_expected_equal
+CHECK-NEXT: warn_pragma_align_invalid_option
+CHECK-NEXT: warn_pragma_debug_unexpected_command
+CHECK-NEXT: warn_pragma_expected_colon
+CHECK-NEXT: warn_pragma_expected_enable_disable
+CHECK-NEXT: warn_pragma_expected_identifier
+CHECK-NEXT: warn_pragma_expected_lparen
+CHECK-NEXT: warn_pragma_expected_rparen
+CHECK-NEXT: warn_pragma_extra_tokens_at_eol
+CHECK-NEXT: warn_pragma_ms_struct
+CHECK-NEXT: warn_pragma_options_align_reset_failed
+CHECK-NEXT: warn_pragma_options_align_unsupported_option
+CHECK-NEXT: warn_pragma_options_expected_align
+CHECK-NEXT: warn_pragma_pack_invalid_action
+CHECK-NEXT: warn_pragma_pack_invalid_alignment
+CHECK-NEXT: warn_pragma_pack_invalid_constant
+CHECK-NEXT: warn_pragma_pack_malformed
+CHECK-NEXT: warn_pragma_pack_pop_failed
+CHECK-NEXT: warn_pragma_pack_pop_identifer_and_alignment
+CHECK-NEXT: warn_pragma_pack_show
+CHECK-NEXT: warn_pragma_pop_macro_no_push
+CHECK-NEXT: warn_pragma_unknown_extension
+CHECK-NEXT: warn_pragma_unused_expected_punc
+CHECK-NEXT: warn_pragma_unused_expected_var
+CHECK-NEXT: warn_pragma_unused_expected_var_arg
+CHECK-NEXT: warn_pragma_unused_undeclared_var
+CHECK-NEXT: warn_previous_alias_decl
+CHECK-NEXT: warn_printf_asterisk_missing_arg
+CHECK-NEXT: warn_property_attr_mismatch
+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_receiver_forward_class
+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_remainder_by_zero
+CHECK-NEXT: warn_root_inst_method_not_found
+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_setter_getter_impl_required
+CHECK-NEXT: warn_setter_getter_impl_required_in_category
+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
+CHECK-NEXT: warn_template_spec_extra_headers
+CHECK-NEXT: warn_tentative_incomplete_array
+CHECK-NEXT: warn_transparent_union_attribute_field_size_align
+CHECK-NEXT: warn_transparent_union_attribute_floating
+CHECK-NEXT: warn_transparent_union_attribute_not_definition
+CHECK-NEXT: warn_transparent_union_attribute_zero_fields
+CHECK-NEXT: warn_transparent_union_nonpointer
+CHECK-NEXT: warn_typecheck_function_qualifiers
+CHECK-NEXT: warn_ucn_escape_too_large
+CHECK-NEXT: warn_ucn_not_valid_in_c89
+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_uninit_val
+CHECK-NEXT: warn_unknown_analyzer_checker
+CHECK-NEXT: warn_unknown_method_family
+CHECK-NEXT: warn_unterminated_char
+CHECK-NEXT: warn_unterminated_string
+CHECK-NEXT: warn_use_out_of_scope_declaration
+CHECK-NEXT: warn_weak_identifier_undeclared
+CHECK-NEXT: warn_weak_import
diff --git a/test/Modules/Inputs/CmdLine.framework/Headers/CmdLine.h b/test/Modules/Inputs/CmdLine.framework/Headers/CmdLine.h
new file mode 100644
index 000000000000..46b8fc0425a6
--- /dev/null
+++ b/test/Modules/Inputs/CmdLine.framework/Headers/CmdLine.h
@@ -0,0 +1,6 @@
+#ifdef FOO_RETURNS_INT_PTR
+int *foo(void);
+#else
+float *foo(void);
+#endif
+
diff --git a/test/Modules/Inputs/DependsOnModule.framework/Headers/DependsOnModule.h b/test/Modules/Inputs/DependsOnModule.framework/Headers/DependsOnModule.h
new file mode 100644
index 000000000000..fa4069774561
--- /dev/null
+++ b/test/Modules/Inputs/DependsOnModule.framework/Headers/DependsOnModule.h
@@ -0,0 +1,3 @@
+#include <Module/Module.h>
+
+#define DEPENDS_ON_MODULE 1
diff --git a/test/Modules/Inputs/Module.framework/Headers/Module.h b/test/Modules/Inputs/Module.framework/Headers/Module.h
new file mode 100644
index 000000000000..7c7ef6ea10e9
--- /dev/null
+++ b/test/Modules/Inputs/Module.framework/Headers/Module.h
@@ -0,0 +1,12 @@
+const char *getModuleVersion(void);
+
+#ifdef FOO
+# error Module should have been built without -DFOO
+#endif
+
+@interface Module
++(const char *)version; // retrieve module version
++alloc;
+@end
+
+#define MODULE_H_MACRO 1
diff --git a/test/Modules/Inputs/MutuallyRecursive1.framework/Headers/MutuallyRecursive1.h b/test/Modules/Inputs/MutuallyRecursive1.framework/Headers/MutuallyRecursive1.h
new file mode 100644
index 000000000000..2a8282cc0119
--- /dev/null
+++ b/test/Modules/Inputs/MutuallyRecursive1.framework/Headers/MutuallyRecursive1.h
@@ -0,0 +1,3 @@
+
+__import_module__ MutuallyRecursive2;
+
diff --git a/test/Modules/Inputs/MutuallyRecursive2.framework/Headers/MutuallyRecursive2.h b/test/Modules/Inputs/MutuallyRecursive2.framework/Headers/MutuallyRecursive2.h
new file mode 100644
index 000000000000..98008533f307
--- /dev/null
+++ b/test/Modules/Inputs/MutuallyRecursive2.framework/Headers/MutuallyRecursive2.h
@@ -0,0 +1,6 @@
+
+
+__import_module__ MutuallyRecursive1;
+
+
+
diff --git a/test/Modules/Inputs/diamond_bottom.h b/test/Modules/Inputs/diamond_bottom.h
new file mode 100644
index 000000000000..e0b06d6cd972
--- /dev/null
+++ b/test/Modules/Inputs/diamond_bottom.h
@@ -0,0 +1,4 @@
+__import_module__ diamond_left;
+__import_module__ diamond_right;
+
+char bottom(char *x);
diff --git a/test/Modules/Inputs/diamond_left.h b/test/Modules/Inputs/diamond_left.h
new file mode 100644
index 000000000000..88cbf60977b3
--- /dev/null
+++ b/test/Modules/Inputs/diamond_left.h
@@ -0,0 +1,9 @@
+__import_module__ diamond_top;
+
+float left(float *);
+
+int top_left(char *c);
+
+int left_and_right(int*);
+
+
diff --git a/test/Modules/Inputs/diamond_right.h b/test/Modules/Inputs/diamond_right.h
new file mode 100644
index 000000000000..6f8bb82f8d24
--- /dev/null
+++ b/test/Modules/Inputs/diamond_right.h
@@ -0,0 +1,7 @@
+__import_module__ diamond_top;
+
+double right(double *);
+
+struct left_and_right {
+ int left, right;
+};
diff --git a/test/Modules/Inputs/diamond_top.h b/test/Modules/Inputs/diamond_top.h
new file mode 100644
index 000000000000..34998cd4324b
--- /dev/null
+++ b/test/Modules/Inputs/diamond_top.h
@@ -0,0 +1,4 @@
+int top(int *);
+
+int top_left(char *c);
+
diff --git a/test/Modules/Inputs/load_failure.h b/test/Modules/Inputs/load_failure.h
new file mode 100644
index 000000000000..5bcb44dcb3dc
--- /dev/null
+++ b/test/Modules/Inputs/load_failure.h
@@ -0,0 +1 @@
+int fail(int);
diff --git a/test/Modules/Inputs/lookup_left.h b/test/Modules/Inputs/lookup_left.h
new file mode 100644
index 000000000000..01723d40aa7a
--- /dev/null
+++ b/test/Modules/Inputs/lookup_left.h
@@ -0,0 +1,3 @@
+@interface A
+- (int)method;
+@end
diff --git a/test/Modules/Inputs/lookup_left.hpp b/test/Modules/Inputs/lookup_left.hpp
new file mode 100644
index 000000000000..66d6206137b8
--- /dev/null
+++ b/test/Modules/Inputs/lookup_left.hpp
@@ -0,0 +1,5 @@
+int *f0(int*);
+
+#pragma weak weak_identifier // expected-warning{{weak identifier 'weak_identifier' never declared}}
+
+
diff --git a/test/Modules/Inputs/lookup_right.h b/test/Modules/Inputs/lookup_right.h
new file mode 100644
index 000000000000..f8f0c97d6818
--- /dev/null
+++ b/test/Modules/Inputs/lookup_right.h
@@ -0,0 +1,5 @@
+
+@interface B
+- (double)method;
+@end
+
diff --git a/test/Modules/Inputs/lookup_right.hpp b/test/Modules/Inputs/lookup_right.hpp
new file mode 100644
index 000000000000..884534747f69
--- /dev/null
+++ b/test/Modules/Inputs/lookup_right.hpp
@@ -0,0 +1 @@
+float *f0(float*);
diff --git a/test/Modules/Inputs/point.h b/test/Modules/Inputs/point.h
new file mode 100644
index 000000000000..eab23d5867a8
--- /dev/null
+++ b/test/Modules/Inputs/point.h
@@ -0,0 +1,2 @@
+struct Point { int x, y; };
+
diff --git a/test/Modules/auto-module-import.c b/test/Modules/auto-module-import.c
new file mode 100644
index 000000000000..018717423876
--- /dev/null
+++ b/test/Modules/auto-module-import.c
@@ -0,0 +1,13 @@
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c -fmodule-cache-path %t -fauto-module-import -F %S/Inputs -verify %s
+
+#include <DependsOnModule/DependsOnModule.h>
+
+#ifdef MODULE_H_MACRO
+# error MODULE_H_MACRO should have been hidden
+#endif
+
+#ifdef DEPENDS_ON_MODULE
+# error DEPENDS_ON_MODULE should have been hidden
+#endif
diff --git a/test/Modules/cycles.c b/test/Modules/cycles.c
new file mode 100644
index 000000000000..8e3e9c631617
--- /dev/null
+++ b/test/Modules/cycles.c
@@ -0,0 +1,12 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodule-cache-path %t -F %S/Inputs %s 2>&1 | FileCheck %s
+
+__import_module__ 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:19: fatal error: cyclic dependency in module 'MutuallyRecursive1': MutuallyRecursive1 -> MutuallyRecursive2 -> MutuallyRecursive1
+// CHECK: MutuallyRecursive1.h:2:19: fatal error: could not build module 'MutuallyRecursive2'
+// CHECK: cycles.c:4:19: fatal error: could not build module 'MutuallyRecursive1'
+
diff --git a/test/Modules/diamond.c b/test/Modules/diamond.c
new file mode 100644
index 000000000000..482836c44978
--- /dev/null
+++ b/test/Modules/diamond.c
@@ -0,0 +1,27 @@
+
+
+
+// in diamond-bottom.h: expected-note{{passing argument to parameter 'x' here}}
+
+__import_module__ diamond_bottom;
+
+void test_diamond(int i, float f, double d, char c) {
+ top(&i);
+ left(&f);
+ right(&d);
+ bottom(&c);
+ bottom(&d); // expected-warning{{incompatible pointer types passing 'double *' to parameter of type 'char *'}}
+
+ // Names in multiple places in the diamond.
+ top_left(&c);
+
+ left_and_right(&i);
+ struct left_and_right lr;
+ lr.left = 17;
+}
+
+// RUN: %clang_cc1 -emit-module -o %T/diamond_top.pcm %S/Inputs/diamond_top.h
+// RUN: %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash -emit-module -o %T/diamond_left.pcm %S/Inputs/diamond_left.h
+// RUN: %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash -emit-module -o %T/diamond_right.pcm %S/Inputs/diamond_right.h
+// RUN: %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash -emit-module -o %T/diamond_bottom.pcm %S/Inputs/diamond_bottom.h
+// RUN: %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash %s -verify
diff --git a/test/Modules/driver.c b/test/Modules/driver.c
new file mode 100644
index 000000000000..de10cd0cecca
--- /dev/null
+++ b/test/Modules/driver.c
@@ -0,0 +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
+
+// CHECK-NO_MODULE_CACHE: {{clang.*"-fmodule-cache-path"}}
+
+// CHECK-WITH_MODULE_CACHE: {{clang.*"-fmodule-cache-path" "blarg"}}
diff --git a/test/Modules/header-import.m b/test/Modules/header-import.m
new file mode 100644
index 000000000000..9996dc75c8b7
--- /dev/null
+++ b/test/Modules/header-import.m
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodule-cache-path %t -F %S/Inputs -I %S/Inputs -verify %s
+
+#import "point.h"
+__import_module__ Module;
+#import "point.h"
+
diff --git a/test/Modules/irgen.c b/test/Modules/irgen.c
new file mode 100644
index 000000000000..0debf05f5934
--- /dev/null
+++ b/test/Modules/irgen.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -emit-module -triple x86_64-apple-darwin10 -o %t/module.pcm -DBUILD_MODULE %s
+// RUN: %clang_cc1 -fmodule-cache-path %t -triple x86_64-apple-darwin10 -fdisable-module-hash -emit-llvm -o - %s | FileCheck %s
+
+#ifdef BUILD_MODULE
+static inline int triple(int x) { return x * 3; }
+#else
+__import_module__ module;
+
+// CHECK: define void @triple_value
+void triple_value(int *px) {
+ *px = triple(*px);
+}
+
+// CHECK: define internal i32 @triple(i32
+#endif
diff --git a/test/Modules/load_failure.c b/test/Modules/load_failure.c
new file mode 100644
index 000000000000..d16bba7628b1
--- /dev/null
+++ b/test/Modules/load_failure.c
@@ -0,0 +1,19 @@
+#ifdef NONEXISTENT
+__import_module__ load_nonexistent;
+#endif
+
+#ifdef FAILURE
+__import_module__ load_failure;
+#endif
+
+// RUN: %clang_cc1 -x c++ -emit-module -o %T/load_failure.pcm %S/Inputs/load_failure.h
+// RUN: %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash %s -DNONEXISTENT 2>&1 | FileCheck -check-prefix=CHECK-NONEXISTENT %s
+// CHECK-NONEXISTENT: load_failure.c:2:19: fatal error: module 'load_nonexistent' not found
+
+// RUN: not %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash %s -DFAILURE 2> %t
+// RUN: FileCheck -check-prefix=CHECK-FAILURE %s < %t
+
+// FIXME: Clean up diagnostic text below and give it a location
+// CHECK-FAILURE: error: C99 was disabled in PCH file but is currently enabled
+
+
diff --git a/test/Modules/lookup.cpp b/test/Modules/lookup.cpp
new file mode 100644
index 000000000000..d3245f2935f9
--- /dev/null
+++ b/test/Modules/lookup.cpp
@@ -0,0 +1,25 @@
+
+#define import __import_module__
+import lookup_left_cxx;
+#define IMPORT(X) __import_module__ X
+IMPORT(lookup_right_cxx);
+
+void test(int i, float f) {
+ // unqualified lookup
+ f0(&i);
+ f0(&f);
+
+ // qualified lookup into the translation unit
+ ::f0(&i);
+ ::f0(&f);
+}
+
+// RUN: %clang_cc1 -emit-module -x c++ -verify -o %T/lookup_left_cxx.pcm %S/Inputs/lookup_left.hpp
+// RUN: %clang_cc1 -emit-module -x c++ -o %T/lookup_right_cxx.pcm %S/Inputs/lookup_right.hpp
+// RUN: %clang_cc1 -x c++ -fmodule-cache-path %T -fdisable-module-hash %s -verify
+// RUN: %clang_cc1 -ast-print -x c++ -fmodule-cache-path %T -fdisable-module-hash %s | FileCheck -check-prefix=CHECK-PRINT %s
+
+// CHECK-PRINT: int *f0(int *);
+// CHECK-PRINT: float *f0(float *);
+// CHECK-PRINT: void test(int i, float f)
+
diff --git a/test/Modules/lookup.m b/test/Modules/lookup.m
new file mode 100644
index 000000000000..d45f93661b9a
--- /dev/null
+++ b/test/Modules/lookup.m
@@ -0,0 +1,19 @@
+
+// lookup_left.h: expected-note{{using}}
+// lookup_right.h: expected-note{{also found}}
+__import_module__ lookup_left_objc;
+__import_module__ lookup_right_objc;
+
+void test(id x) {
+ [x method]; // expected-warning{{multiple methods named 'method' found}}
+}
+
+// RUN: %clang_cc1 -emit-module -x objective-c -o %T/lookup_left_objc.pcm %S/Inputs/lookup_left.h
+// RUN: %clang_cc1 -emit-module -x objective-c -o %T/lookup_right_objc.pcm %S/Inputs/lookup_right.h
+// RUN: %clang_cc1 -x objective-c -fmodule-cache-path %T -fdisable-module-hash -verify %s
+// RUN: %clang_cc1 -ast-print -x objective-c -fmodule-cache-path %T -fdisable-module-hash %s | FileCheck -check-prefix=CHECK-PRINT %s
+
+// CHECK-PRINT: - (int) method;
+// CHECK-PRINT: - (double) method
+// CHECK-PRINT: void test(id x)
+
diff --git a/test/Modules/macros.c b/test/Modules/macros.c
new file mode 100644
index 000000000000..899c19bb29c9
--- /dev/null
+++ b/test/Modules/macros.c
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -emit-module -o %t/macros.pcm -DMODULE %s
+// RUN: %clang_cc1 -verify -fmodule-cache-path %t -fdisable-module-hash %s
+// RUN: %clang_cc1 -E -fmodule-cache-path %t -fdisable-module-hash %s | FileCheck -check-prefix CHECK-PREPROCESSED %s
+
+#if defined(MODULE)
+#define INTEGER(X) int
+#define FLOAT float
+#define DOUBLE double
+
+#__export_macro__ INTEGER
+#__export_macro__ DOUBLE
+
+int (INTEGER);
+
+#else
+
+__import_module__ macros;
+
+#ifndef INTEGER
+# error INTEGER macro should be visible
+#endif
+
+#ifdef FLOAT
+# error FLOAT macro should not be visible
+#endif
+
+#ifdef MODULE
+# error MODULE macro should not be visible
+#endif
+
+// CHECK-PREPROCESSED: double d
+double d;
+DOUBLE *dp = &d;
+
+#__export_macro__ WIBBLE // expected-error{{no macro named 'WIBBLE' to export}}
+
+void f() {
+ // CHECK-PREPROCESSED: int i = INTEGER;
+ int i = INTEGER; // the value was exported, the macro was not.
+}
+#endif
diff --git a/test/Modules/module-private.cpp b/test/Modules/module-private.cpp
new file mode 100644
index 000000000000..7bd2a205c055
--- /dev/null
+++ b/test/Modules/module-private.cpp
@@ -0,0 +1,140 @@
+// RUN: mkdir -p %t
+// RUN: %clang_cc1 -x c++ -emit-module -o %t/left.pcm %s -D MODULE_LEFT
+// RUN: %clang_cc1 -x c++ -emit-module -o %t/right.pcm %s -D MODULE_RIGHT
+// RUN: %clang_cc1 -fmodule-cache-path %t -fdisable-module-hash %s -verify
+
+#if defined(MODULE_LEFT)
+
+__module_private__ struct HiddenStruct;
+
+struct HiddenStruct {
+};
+
+
+int &f0(int);
+
+template<typename T>
+__module_private__ void f1(T*);
+
+template<typename T>
+void f1(T*);
+
+template<typename T>
+__module_private__ class vector;
+
+template<typename T>
+class vector {
+};
+
+vector<float> vec_float;
+
+typedef __module_private__ int Integer;
+typedef int Integer;
+
+#elif defined(MODULE_RIGHT)
+__module_private__ double &f0(double);
+double &f0(double);
+
+__module_private__ int hidden_var;
+
+inline void test_f0_in_right() {
+ double &dr = f0(hidden_var);
+}
+
+struct VisibleStruct {
+ __module_private__ int field;
+ __module_private__ virtual void setField(int f);
+};
+
+#else
+__import_module__ left;
+__import_module__ right;
+
+void test() {
+ int &ir = f0(1.0); // okay: f0() from 'right' is not visible
+}
+
+int test_broken() {
+ HiddenStruct hidden; // expected-error{{use of undeclared identifier 'HiddenStruct'}}
+
+ Integer i; // expected-error{{use of undeclared identifier 'Integer'}}
+
+ int *ip = 0;
+ f1(ip); // expected-error{{use of undeclared identifier 'f1'}}
+
+ vector<int> vec; // expected-error{{use of undeclared identifier 'vector'}} \
+ // expected-error{{expected '(' for function-style cast or type construction}} \
+ // expected-error{{use of undeclared identifier 'vec'}}
+
+ VisibleStruct vs;
+ vs.field = 0; // expected-error{{no member named 'field' in 'VisibleStruct'}}
+ vs.setField(1); // expected-error{{no member named 'setField' in 'VisibleStruct'}}
+
+ return hidden_var; // expected-error{{use of undeclared identifier 'hidden_var'}}
+}
+
+// Check for private redeclarations of public entities.
+template<typename T>
+class public_class_template; // expected-note{{previous declaration is here}}
+
+template<typename T>
+__module_private__ class public_class_template; // expected-error{{__module_private__ declaration of 'public_class_template' follows public declaration}}
+
+
+typedef int public_typedef; // expected-note{{previous declaration is here}}
+typedef __module_private__ int public_typedef; // expected-error{{__module_private__ declaration of 'public_typedef' follows public declaration}}
+
+extern int public_var; // expected-note{{previous declaration is here}}
+extern __module_private__ int public_var; // expected-error{{__module_private__ declaration of 'public_var' follows public declaration}}
+
+void public_func(); // expected-note{{previous declaration is here}}
+__module_private__ void public_func(); // expected-error{{__module_private__ declaration of 'public_func' follows public declaration}}
+
+template<typename T>
+void public_func_template(); // expected-note{{previous declaration is here}}
+template<typename T>
+__module_private__ void public_func_template(); // expected-error{{__module_private__ declaration of 'public_func_template' follows public declaration}}
+
+struct public_struct; // expected-note{{previous declaration is here}}
+__module_private__ struct public_struct; // expected-error{{__module_private__ declaration of 'public_struct' follows public declaration}}
+
+// Check for attempts to make specializations private
+template<> __module_private__ void public_func_template<int>(); // expected-error{{template specialization cannot be declared __module_private__}}
+
+template<typename T>
+struct public_class {
+ struct inner_struct;
+ static int static_var;
+
+ friend __module_private__ void public_func_friend();
+ friend __module_private__ struct public_struct_friend;
+};
+
+template<> __module_private__ struct public_class<int>::inner_struct { }; // expected-error{{member specialization cannot be declared __module_private__}}
+template<> __module_private__ int public_class<int>::static_var = 17; // expected-error{{member specialization cannot be declared __module_private__}}
+
+template<>
+__module_private__ struct public_class<float> { }; // expected-error{{template specialization cannot be declared __module_private__}}
+
+template<typename T>
+__module_private__ struct public_class<T *> { }; // expected-error{{partial specialization cannot be declared __module_private__}}
+
+// Check for attempts to make parameters and variables with automatic
+// storage module-private.
+
+void local_var_private(__module_private__ int param) { // expected-error{{parameter 'param' cannot be declared __module_private__}}
+ __module_private__ struct Local { int x, y; } local; //expected-error{{local variable 'local' cannot be declared __module_private__}}
+
+ __module_private__ struct OtherLocal { int x; }; // expected-error{{local struct cannot be declared __module_private__}}
+
+ typedef __module_private__ int local_typedef; // expected-error{{typedef 'local_typedef' cannot be declared __module_private__}}
+}
+
+// Check struct size
+struct LikeVisibleStruct {
+ int field;
+ virtual void setField(int f);
+};
+
+int check_struct_size[sizeof(VisibleStruct) == sizeof(LikeVisibleStruct)? 1 : -1];
+#endif
diff --git a/test/Modules/objc-categories.m b/test/Modules/objc-categories.m
new file mode 100644
index 000000000000..87aaa5c12cae
--- /dev/null
+++ b/test/Modules/objc-categories.m
@@ -0,0 +1,89 @@
+// RUN: mkdir -p %t
+// RUN: %clang_cc1 -emit-module -o %t/diamond_top.pcm %s -D MODULE_TOP
+// RUN: %clang_cc1 -fmodule-cache-path %t -fdisable-module-hash -emit-module -o %t/diamond_left.pcm %s -D MODULE_LEFT
+// RUN: %clang_cc1 -fmodule-cache-path %t -fdisable-module-hash -emit-module -o %t/diamond_right.pcm %s -D MODULE_RIGHT
+// RUN: %clang_cc1 -fmodule-cache-path %t -fdisable-module-hash -emit-module -o %t/diamond_bottom.pcm %s -D MODULE_BOTTOM
+// RUN: %clang_cc1 -fmodule-cache-path %t -fdisable-module-hash %s -verify
+
+/*============================================================================*/
+#ifdef MODULE_TOP
+
+@interface Foo
+@end
+
+@interface Foo(Top)
+-(void)top;
+@end
+
+/*============================================================================*/
+#elif defined(MODULE_LEFT)
+
+__import_module__ diamond_top;
+
+@interface Foo(Left)
+-(void)left;
+@end
+
+@interface LeftFoo
+-(void)left;
+@end
+
+@interface Foo(Duplicate) // expected-note {{previous definition}}
+@end
+
+@interface Foo(Duplicate)
+@end
+
+/*============================================================================*/
+#elif defined(MODULE_RIGHT)
+
+__import_module__ diamond_top;
+
+@interface Foo(Right1)
+-(void)right1;
+@end
+
+@interface Foo(Right2)
+-(void)right2;
+@end
+
+@interface Foo(Duplicate) // expected-warning {{duplicate definition of category}}
+@end
+
+/*============================================================================*/
+#elif defined(MODULE_BOTTOM)
+
+__import_module__ diamond_left;
+
+@interface Foo(Bottom)
+-(void)bottom;
+@end
+
+__import_module__ diamond_right;
+
+@interface LeftFoo(Bottom)
+-(void)bottom;
+@end
+
+/*============================================================================*/
+#else
+
+__import_module__ diamond_bottom;
+
+@interface Foo(Source)
+-(void)source;
+@end
+
+void test(Foo *foo, LeftFoo *leftFoo) {
+ [foo source];
+ [foo bottom];
+ [foo left];
+ [foo right1];
+ [foo right2];
+ [foo top];
+
+ [leftFoo left];
+ [leftFoo bottom];
+}
+
+#endif
diff --git a/test/Modules/on-demand-build-warnings.m b/test/Modules/on-demand-build-warnings.m
new file mode 100644
index 000000000000..aa122dbd8559
--- /dev/null
+++ b/test/Modules/on-demand-build-warnings.m
@@ -0,0 +1,5 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fno-objc-infer-related-result-type -Wmodule-build -fmodule-cache-path %t -F %S/Inputs -verify %s
+
+__import_module__ Module; // expected-warning{{building module 'Module' from source}}
+
diff --git a/test/Modules/on-demand-build.m b/test/Modules/on-demand-build.m
new file mode 100644
index 000000000000..649caa8a7d80
--- /dev/null
+++ b/test/Modules/on-demand-build.m
@@ -0,0 +1,17 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fno-objc-infer-related-result-type -Werror -fmodule-cache-path %t -F %S/Inputs -verify %s
+// RUN: %clang_cc1 -fno-objc-infer-related-result-type -Werror -x objective-c++ -fmodule-cache-path %t -F %S/Inputs -verify %s
+// RUN: %clang_cc1 -fno-objc-infer-related-result-type -Werror -fmodule-cache-path %t -F %S/Inputs -verify %s
+#define FOO
+__import_module__ Module;
+@interface OtherClass
+@end
+// in module: expected-note{{class method 'alloc' is assumed to return an instance of its receiver type ('Module *')}}
+void test_getModuleVersion() {
+ const char *version = getModuleVersion();
+ const char *version2 = [Module version];
+
+ OtherClass *other = [Module alloc]; // expected-error{{init}}
+}
+
+
diff --git a/test/Modules/on-demand-macros.m b/test/Modules/on-demand-macros.m
new file mode 100644
index 000000000000..96abb2331f10
--- /dev/null
+++ b/test/Modules/on-demand-macros.m
@@ -0,0 +1,13 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodule-cache-path %t -F %S/Inputs -DFOO_RETURNS_INT_PTR -verify %s
+// RUN: %clang_cc1 -fmodule-cache-path %t -F %S/Inputs -verify %s
+
+__import_module__ CmdLine;
+
+void test() {
+#ifdef FOO_RETURNS_INT_PTR
+ int *ip = foo();
+#else
+ float *fp = foo();
+#endif
+}
diff --git a/test/PCH/Inputs/cxx-method.h b/test/PCH/Inputs/cxx-method.h
new file mode 100644
index 000000000000..6adb8591707d
--- /dev/null
+++ b/test/PCH/Inputs/cxx-method.h
@@ -0,0 +1,6 @@
+struct S {
+ void m(int x);
+
+ operator const char*();
+ operator char*();
+};
diff --git a/test/PCH/arc.m b/test/PCH/arc.m
index 6f7b8704d9ea..64b390c30715 100644
--- a/test/PCH/arc.m
+++ b/test/PCH/arc.m
@@ -1,9 +1,17 @@
// Test this without pch.
-// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-arc -include %S/Inputs/arc.h -fsyntax-only -emit-llvm -o - %s
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -fobjc-arc -include %S/Inputs/arc.h -fsyntax-only -emit-llvm-only %s
// Test with pch.
-// RUN: %clang_cc1 -emit-pch -fblocks -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-arc -x objective-c-header -o %t %S/Inputs/arc.h
-// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-arc -include-pch %t -fsyntax-only -emit-llvm -o - %s
+// RUN: %clang_cc1 -emit-pch -fblocks -triple x86_64-apple-darwin11 -fobjc-arc -x objective-c-header -o %t %S/Inputs/arc.h
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -fobjc-arc -include-pch %t -fsyntax-only -emit-llvm-only %s
+
+// Test error when pch's -fobjc-arc state is different.
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -include-pch %t -fsyntax-only -emit-llvm-only %s 2>&1 | FileCheck -check-prefix=ERR1 %s
+// RUN: %clang_cc1 -emit-pch -fblocks -triple x86_64-apple-darwin11 -x objective-c-header -o %t %S/Inputs/arc.h
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -fobjc-arc -include-pch %t -fsyntax-only -emit-llvm-only %s 2>&1 | FileCheck -check-prefix=ERR2 %s
array0 a0;
array1 a1;
+
+// CHECK-ERR1: Objective-C automated reference counting was enabled in PCH file but is currently disabled
+// CHECK-ERR2: Objective-C automated reference counting was disabled in PCH file but is currently enabled
diff --git a/test/PCH/chain-categories.m b/test/PCH/chain-categories.m
new file mode 100644
index 000000000000..1b91c732b4d0
--- /dev/null
+++ b/test/PCH/chain-categories.m
@@ -0,0 +1,51 @@
+// Without PCH
+// RUN: %clang_cc1 -fsyntax-only -verify -include %s -include %s %s
+
+// With PCH
+// RUN: %clang_cc1 -fsyntax-only -verify %s -chain-include %s -chain-include %s
+
+#ifndef HEADER1
+#define HEADER1
+//===----------------------------------------------------------------------===//
+// Primary header
+
+@interface NSObject
+- (id)init;
+- (void)finalize;
+@end
+
+//===----------------------------------------------------------------------===//
+#elif !defined(HEADER2)
+#define HEADER2
+#if !defined(HEADER1)
+#error Header inclusion order messed up
+#endif
+
+//===----------------------------------------------------------------------===//
+// Dependent header
+
+@interface MyClass : NSObject
++(void)meth;
+@end
+
+@interface NSObject(ObjExt)
+-(void)extMeth;
+@end
+
+//===----------------------------------------------------------------------===//
+#else
+//===----------------------------------------------------------------------===//
+
+@implementation MyClass
++(void)meth {}
+-(void)finalize {
+ [super finalize];
+}
+@end
+
+void test(NSObject *o) {
+ [o extMeth];
+}
+
+//===----------------------------------------------------------------------===//
+#endif
diff --git a/test/PCH/chain-conversion-lookup.cpp b/test/PCH/chain-conversion-lookup.cpp
new file mode 100644
index 000000000000..db9d8fc33eaf
--- /dev/null
+++ b/test/PCH/chain-conversion-lookup.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -chain-include %s -chain-include %s
+
+#if !defined(PASS1)
+#define PASS1
+struct X {
+ operator int*();
+};
+
+struct Z {
+ operator int*();
+};
+#elif !defined(PASS2)
+#define PASS2
+struct Y {
+ operator int *();
+};
+#else
+int main() {
+ X x;
+ int *ip = x.operator int*();
+ Y y;
+ int *ip2 = y.operator int*();
+ Z z;
+ int *ip3 = z.operator int*();
+}
+#endif
diff --git a/test/PCH/chain-decls.c b/test/PCH/chain-decls.c
index b3daa4a7b7cd..f5724c4c1343 100644
--- a/test/PCH/chain-decls.c
+++ b/test/PCH/chain-decls.c
@@ -3,7 +3,7 @@
// Test with pch.
// RUN: %clang_cc1 -emit-pch -o %t1 %S/Inputs/chain-decls1.h
-// RUN: %clang_cc1 -emit-pch -o %t2 %S/Inputs/chain-decls2.h -include-pch %t1 -chained-pch
+// RUN: %clang_cc1 -emit-pch -o %t2 %S/Inputs/chain-decls2.h -include-pch %t1
// RUN: %clang_cc1 -include-pch %t2 -fsyntax-only -verify %s
// RUN: %clang_cc1 -ast-print -include-pch %t2 %s | FileCheck %s
diff --git a/test/PCH/chain-ext_vector.c b/test/PCH/chain-ext_vector.c
index 263507003d18..d99a732f2ffa 100644
--- a/test/PCH/chain-ext_vector.c
+++ b/test/PCH/chain-ext_vector.c
@@ -3,7 +3,7 @@
// Test with pch.
// RUN: %clang_cc1 -emit-pch -o %t1 %S/Inputs/chain-ext_vector1.h
-// RUN: %clang_cc1 -emit-pch -o %t2 %S/Inputs/chain-ext_vector2.h -include-pch %t1 -chained-pch
+// RUN: %clang_cc1 -emit-pch -o %t2 %S/Inputs/chain-ext_vector2.h -include-pch %t1
// RUN: %clang_cc1 -include-pch %t2 -fsyntax-only -verify %s
int test(float4 f4) {
diff --git a/test/PCH/chain-external-defs.c b/test/PCH/chain-external-defs.c
index dd92d8e63ac6..742229442865 100644
--- a/test/PCH/chain-external-defs.c
+++ b/test/PCH/chain-external-defs.c
@@ -1,6 +1,6 @@
// Test with pch.
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-pch -o %t1.pch %S/Inputs/chain-external-defs1.h
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-pch -o %t2.pch %S/Inputs/chain-external-defs2.h -include-pch %t1.pch -chained-pch
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-pch -o %t2.pch %S/Inputs/chain-external-defs2.h -include-pch %t1.pch
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -include-pch %t2.pch -emit-llvm -o %t %s
// RUN: echo FINI >> %t
// RUN: FileCheck -input-file=%t -check-prefix=Z %s
diff --git a/test/PCH/chain-friend-instantiation.cpp b/test/PCH/chain-friend-instantiation.cpp
new file mode 100644
index 000000000000..294d97911236
--- /dev/null
+++ b/test/PCH/chain-friend-instantiation.cpp
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 %s -ast-print -o - -chain-include %s -chain-include %s
+
+#if !defined(PASS1)
+#define PASS1
+
+template <class T> class TClass;
+
+namespace NS {
+ template <class X, class Y> TClass<X> problematic(X * ptr, const TClass<Y> &src);
+
+ template <class T>
+ class TBaseClass
+ {
+ protected:
+ template <class X, class Y> friend TClass<X> problematic(X * ptr, const TClass<Y> &src);
+ };
+}
+
+template <class T>
+class TClass: public NS::TBaseClass<T>
+{
+public:
+ inline TClass() { }
+};
+
+
+namespace NS {
+ template <class X, class T>
+ TClass<X> problematic(X *ptr, const TClass<T> &src);
+}
+
+template <class X, class T>
+TClass<X> unconst(const TClass<T> &src);
+
+#elif !defined(PASS2)
+#define PASS2
+
+namespace std {
+class s {};
+}
+
+
+typedef TClass<std::s> TStr;
+
+struct crash {
+ TStr str;
+
+ crash(const TClass<std::s> p)
+ {
+ unconst<TStr>(p);
+ }
+};
+
+#else
+
+void f() {
+ const TStr p;
+ crash c(p);
+}
+
+#endif
diff --git a/test/PCH/chain-macro-override.c b/test/PCH/chain-macro-override.c
index 8e208815fb26..2713e7084a9d 100644
--- a/test/PCH/chain-macro-override.c
+++ b/test/PCH/chain-macro-override.c
@@ -3,7 +3,7 @@
// Test with pch.
// RUN: %clang_cc1 -emit-pch -o %t1 %S/Inputs/chain-macro-override1.h -detailed-preprocessing-record
-// RUN: %clang_cc1 -emit-pch -o %t2 %S/Inputs/chain-macro-override2.h -include-pch %t1 -chained-pch -detailed-preprocessing-record
+// RUN: %clang_cc1 -emit-pch -o %t2 %S/Inputs/chain-macro-override2.h -include-pch %t1 -detailed-preprocessing-record
// RUN: %clang_cc1 -include-pch %t2 -fsyntax-only -verify %s
int foo() {
diff --git a/test/PCH/chain-macro.c b/test/PCH/chain-macro.c
index 68b18deb0811..18356f75a0e2 100644
--- a/test/PCH/chain-macro.c
+++ b/test/PCH/chain-macro.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -emit-pch -o %t1 -detailed-preprocessing-record %S/Inputs/chain-macro1.h
-// RUN: %clang_cc1 -emit-pch -o %t2 -detailed-preprocessing-record %S/Inputs/chain-macro2.h -include-pch %t1 -chained-pch
+// RUN: %clang_cc1 -emit-pch -o %t2 -detailed-preprocessing-record %S/Inputs/chain-macro2.h -include-pch %t1
// RUN: %clang_cc1 -fsyntax-only -verify -include-pch %t2 %s
// RUN: %clang_cc1 -ast-print -include-pch %t2 %s | FileCheck %s
diff --git a/test/PCH/chain-predecl.m b/test/PCH/chain-predecl.m
index 2b0444e15a2c..6723b6f6f253 100644
--- a/test/PCH/chain-predecl.m
+++ b/test/PCH/chain-predecl.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -emit-pch -o %t1 %S/chain-predecl.h -x objective-c
-// RUN: %clang_cc1 -emit-pch -o %t2 %s -x objective-c -include-pch %t1 -chained-pch
+// RUN: %clang_cc1 -emit-pch -o %t2 %s -x objective-c -include-pch %t1
// Test predeclarations across chained PCH.
@interface Foo
diff --git a/test/PCH/chain-remap-types.m b/test/PCH/chain-remap-types.m
index a45a79d75c7f..585da4486502 100644
--- a/test/PCH/chain-remap-types.m
+++ b/test/PCH/chain-remap-types.m
@@ -1,11 +1,11 @@
// RUN: %clang_cc1 -emit-pch -x objective-c-header -o %t1 %S/Inputs/chain-remap-types1.h
-// RUN: %clang_cc1 -emit-pch -x objective-c-header -o %t2 %S/Inputs/chain-remap-types2.h -include-pch %t1 -chained-pch
+// RUN: %clang_cc1 -emit-pch -x objective-c-header -o %t2 %S/Inputs/chain-remap-types2.h -include-pch %t1
// RUN: %clang_cc1 -include-pch %t2 -fsyntax-only -verify %s
// RUN: %clang_cc1 -ast-print -include-pch %t2 %s | FileCheck %s
// CHECK: @class X;
// CHECK: struct Y
-// CHECK: @property ( assign,readwrite ) X * prop
+// CHECK: @property ( assign,readwrite,atomic ) X * prop
// CHECK: void h(X *);
// CHECK: @interface X(Blah)
// CHECK: void g(X *);
diff --git a/test/PCH/chain-selectors.m b/test/PCH/chain-selectors.m
index 3b19172799c5..c543b7106d5a 100644
--- a/test/PCH/chain-selectors.m
+++ b/test/PCH/chain-selectors.m
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -Wselector -include %S/Inputs/chain-selectors1.h -include %S/Inputs/chain-selectors2.h
// RUN: %clang_cc1 -x objective-c -emit-pch -o %t1 %S/Inputs/chain-selectors1.h
-// RUN: %clang_cc1 -x objective-c -emit-pch -o %t2 %S/Inputs/chain-selectors2.h -include-pch %t1 -chained-pch
+// RUN: %clang_cc1 -x objective-c -emit-pch -o %t2 %S/Inputs/chain-selectors2.h -include-pch %t1
// RUN: %clang_cc1 -fsyntax-only -verify %s -Wselector -include-pch %t2
@implementation X
diff --git a/test/PCH/chain-trivial.c b/test/PCH/chain-trivial.c
index c78b0e44ef30..85b1eabd86f8 100644
--- a/test/PCH/chain-trivial.c
+++ b/test/PCH/chain-trivial.c
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-pch -o %t1 %S/Inputs/chain-trivial1.h
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-pch -o %t2 -include-pch %t1 -chained-pch %S/Inputs/chain-trivial2.h
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-pch -o %t2 -include-pch %t1 %S/Inputs/chain-trivial2.h
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ast-print -include-pch %t2 %s | FileCheck %s
// CHECK: struct __va_list_tag {
diff --git a/test/PCH/cxx-alias-decl.cpp b/test/PCH/cxx-alias-decl.cpp
index e30311c58b7b..872658f7edfa 100644
--- a/test/PCH/cxx-alias-decl.cpp
+++ b/test/PCH/cxx-alias-decl.cpp
@@ -1,9 +1,9 @@
// Test this without pch.
-// RUN: %clang_cc1 -x c++ -std=c++0x -include %S/cxx-alias-decl.h -fsyntax-only -emit-llvm -o - %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -include %S/cxx-alias-decl.h -fsyntax-only -emit-llvm -o - %s
// Test with pch.
-// RUN: %clang_cc1 -x c++ -std=c++0x -emit-pch -o %t %S/cxx-alias-decl.h
-// RUN: %clang_cc1 -x c++ -std=c++0x -include-pch %t -fsyntax-only -emit-llvm -o - %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -emit-pch -o %t %S/cxx-alias-decl.h
+// RUN: %clang_cc1 -x c++ -std=c++11 -include-pch %t -fsyntax-only -emit-llvm -o - %s
template struct T<S>;
C<A>::A<char> a;
diff --git a/test/PCH/cxx-for-range.cpp b/test/PCH/cxx-for-range.cpp
index 46e217c574cb..48310dbc55ce 100644
--- a/test/PCH/cxx-for-range.cpp
+++ b/test/PCH/cxx-for-range.cpp
@@ -1,9 +1,9 @@
// Test this without pch.
-// RUN: %clang_cc1 -x c++ -std=c++0x -include %S/cxx-for-range.h -fsyntax-only -emit-llvm -o - %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -include %S/cxx-for-range.h -fsyntax-only -emit-llvm -o - %s
// Test with pch.
-// RUN: %clang_cc1 -x c++ -std=c++0x -emit-pch -o %t %S/cxx-for-range.h
-// RUN: %clang_cc1 -x c++ -std=c++0x -include-pch %t -fsyntax-only -emit-llvm -o - %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -emit-pch -o %t %S/cxx-for-range.h
+// RUN: %clang_cc1 -x c++ -std=c++11 -include-pch %t -fsyntax-only -emit-llvm -o - %s
void h() {
f();
diff --git a/test/PCH/cxx-implicit-moves.cpp b/test/PCH/cxx-implicit-moves.cpp
new file mode 100644
index 000000000000..ccdc874cb1fa
--- /dev/null
+++ b/test/PCH/cxx-implicit-moves.cpp
@@ -0,0 +1,23 @@
+// Test with PCH
+// RUN: %clang_cc1 -std=c++11 -x c++-header -emit-pch -o %t %s
+// RUN: %clang_cc1 -std=c++11 -include-pch %t -verify %s
+
+// PR10847
+#ifndef HEADER
+#define HEADER
+struct NSSize {
+ double width;
+ double height;
+};
+typedef struct NSSize NSSize;
+
+static inline NSSize NSMakeSize(double w, double h) {
+ NSSize s = { w, h };
+ return s;
+}
+#else
+float test(float v1, float v2) {
+ NSSize s = NSMakeSize(v1, v2);
+ return s.width;
+}
+#endif
diff --git a/test/PCH/cxx-member-init.cpp b/test/PCH/cxx-member-init.cpp
index 70392a283261..28206652b8ff 100644
--- a/test/PCH/cxx-member-init.cpp
+++ b/test/PCH/cxx-member-init.cpp
@@ -1,9 +1,9 @@
// Test this without pch.
-// RUN: %clang_cc1 -x c++ -std=c++0x -DHEADER -DSOURCE -fsyntax-only -emit-llvm -o - %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -DHEADER -DSOURCE -fsyntax-only -emit-llvm -o - %s
// Test with pch.
-// RUN: %clang_cc1 -x c++ -std=c++0x -DHEADER -emit-pch -o %t %s
-// RUN: %clang_cc1 -x c++ -std=c++0x -DHEADER -include-pch %t -fsyntax-only -emit-llvm -o - %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -DHEADER -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -DHEADER -include-pch %t -fsyntax-only -emit-llvm -o - %s
#ifdef HEADER
int n;
diff --git a/test/PCH/cxx-method.cpp b/test/PCH/cxx-method.cpp
index 37dabcc466a8..6ec65b248618 100644
--- a/test/PCH/cxx-method.cpp
+++ b/test/PCH/cxx-method.cpp
@@ -1,7 +1,8 @@
-// RUN: %clang_cc1 -emit-pch %s -o %t
-
-struct S {
- void m(int x);
-};
+// RUN: %clang_cc1 -x c++ -emit-pch %S/Inputs/cxx-method.h -o %t
+// RUN: %clang_cc1 -include-pch %t -verify %s
void S::m(int x) { }
+
+S::operator char *() { return 0; }
+
+S::operator const char *() { return 0; }
diff --git a/test/PCH/cxx-ms-function-specialization-class-scope.cpp b/test/PCH/cxx-ms-function-specialization-class-scope.cpp
new file mode 100644
index 000000000000..1803a11b96b8
--- /dev/null
+++ b/test/PCH/cxx-ms-function-specialization-class-scope.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fms-extensions -triple i386-unknown-unknown -x c++-header -emit-pch -o %t %S/cxx-ms-function-specialization-class-scope.h
+// RUN: %clang_cc1 -fms-extensions -triple i386-unknown-unknown -include-pch %t -fsyntax-only -verify %s
+
+
+void test2()
+{
+ B<char> b(3);
+ char* ptr;
+ b.f(ptr);
+ b.f<int>(99);
+ b.f(100);
+}
+
diff --git a/test/PCH/cxx-ms-function-specialization-class-scope.h b/test/PCH/cxx-ms-function-specialization-class-scope.h
new file mode 100644
index 000000000000..7668e7338423
--- /dev/null
+++ b/test/PCH/cxx-ms-function-specialization-class-scope.h
@@ -0,0 +1,29 @@
+
+
+
+template <class T>
+class B {
+public:
+ template <class U>
+ B(U p) {
+ }
+ template <>
+ B(int p) { // expected-warning{{explicit specialization of 'B<T>' within class scope is a Microsoft extension}}
+ }
+
+ template <class U>
+ void f(U p) {
+ T y = 9;
+ }
+
+
+ template <>
+ void f(int p) { // expected-warning{{explicit specialization of 'f' within class scope is a Microsoft extension}}
+ T a = 3;
+ }
+
+ void f(int p) {
+ T a = 3;
+ }
+};
+
diff --git a/test/PCH/cxx-reference.cpp b/test/PCH/cxx-reference.cpp
index 2dfbcdc1382b..a1a44e6893df 100644
--- a/test/PCH/cxx-reference.cpp
+++ b/test/PCH/cxx-reference.cpp
@@ -1,6 +1,6 @@
// Test this without pch.
-// RUN: %clang_cc1 -x c++ -std=c++0x -include %S/cxx-reference.h -fsyntax-only -emit-llvm -o - %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -include %S/cxx-reference.h -fsyntax-only -emit-llvm -o - %s
// Test with pch.
-// RUN: %clang_cc1 -x c++ -std=c++0x -emit-pch -o %t %S/cxx-reference.h
-// RUN: %clang_cc1 -x c++ -std=c++0x -include-pch %t -fsyntax-only -emit-llvm -o - %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -emit-pch -o %t %S/cxx-reference.h
+// RUN: %clang_cc1 -x c++ -std=c++11 -include-pch %t -fsyntax-only -emit-llvm -o - %s
diff --git a/test/PCH/cxx-static_assert.cpp b/test/PCH/cxx-static_assert.cpp
index 464da405c3e2..ace12e0922d4 100644
--- a/test/PCH/cxx-static_assert.cpp
+++ b/test/PCH/cxx-static_assert.cpp
@@ -1,9 +1,9 @@
// Test this without pch.
-// RUN: %clang_cc1 -include %s -verify -std=c++0x %s
+// RUN: %clang_cc1 -include %s -verify -std=c++11 %s
// Test with pch.
-// RUN: %clang_cc1 -std=c++0x -emit-pch -o %t %s
-// RUN: %clang_cc1 -include-pch %t -verify -std=c++0x %s
+// RUN: %clang_cc1 -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -include-pch %t -verify -std=c++11 %s
#ifndef HEADER
#define HEADER
diff --git a/test/PCH/cxx-variadic-templates.cpp b/test/PCH/cxx-variadic-templates.cpp
index 9b1df9a737f9..5b586931d541 100644
--- a/test/PCH/cxx-variadic-templates.cpp
+++ b/test/PCH/cxx-variadic-templates.cpp
@@ -1,11 +1,11 @@
// Test this without pch.
-// RUN: %clang_cc1 -std=c++0x -include %S/cxx-variadic-templates.h -verify %s -ast-dump -o -
-// RUN: %clang_cc1 -std=c++0x -include %S/cxx-variadic-templates.h %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -include %S/cxx-variadic-templates.h -verify %s -ast-dump -o -
+// RUN: %clang_cc1 -std=c++11 -include %S/cxx-variadic-templates.h %s -emit-llvm -o - | FileCheck %s
// Test with pch.
-// RUN: %clang_cc1 -std=c++0x -x c++-header -emit-pch -o %t %S/cxx-variadic-templates.h
-// RUN: %clang_cc1 -std=c++0x -include-pch %t -verify %s -ast-dump -o -
-// RUN: %clang_cc1 -std=c++0x -include-pch %t %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -x c++-header -emit-pch -o %t %S/cxx-variadic-templates.h
+// RUN: %clang_cc1 -std=c++11 -include-pch %t -verify %s -ast-dump -o -
+// RUN: %clang_cc1 -std=c++11 -include-pch %t %s -emit-llvm -o - | FileCheck %s
// CHECK: allocate_shared
shared_ptr<int> spi = shared_ptr<int>::allocate_shared(1, 2);
diff --git a/test/PCH/cxx0x-default-delete.cpp b/test/PCH/cxx0x-default-delete.cpp
index 753ac4736c70..3ecb19c29572 100644
--- a/test/PCH/cxx0x-default-delete.cpp
+++ b/test/PCH/cxx0x-default-delete.cpp
@@ -1,8 +1,8 @@
// Without PCH
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify -include %s %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -include %s %s
// With PCH
-// RUN: %clang_cc1 -x c++-header -std=c++0x -emit-pch -o %t %s
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify -include-pch %t %s
+// RUN: %clang_cc1 -x c++-header -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -include-pch %t %s
#ifndef PASS1
#define PASS1
diff --git a/test/PCH/cxx0x-delegating-ctors.cpp b/test/PCH/cxx0x-delegating-ctors.cpp
index 15311f852944..f2b7e9036252 100644
--- a/test/PCH/cxx0x-delegating-ctors.cpp
+++ b/test/PCH/cxx0x-delegating-ctors.cpp
@@ -1,9 +1,9 @@
// Test this without pch.
-// RUN: %clang_cc1 -include %s -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -include %s -std=c++11 -fsyntax-only -verify %s
// Test with pch.
-// RUN: %clang_cc1 -x c++-header -std=c++0x -emit-pch -o %t %s
-// RUN: %clang_cc1 -std=c++0x -include-pch %t -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x c++-header -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -std=c++11 -include-pch %t -fsyntax-only -verify %s
#ifndef PASS1
#define PASS1
diff --git a/test/PCH/cxx_exprs.cpp b/test/PCH/cxx_exprs.cpp
index 49df80db4fed..4cd9bae1fa4c 100644
--- a/test/PCH/cxx_exprs.cpp
+++ b/test/PCH/cxx_exprs.cpp
@@ -1,9 +1,9 @@
// Test this without pch.
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -include %S/cxx_exprs.h -std=c++0x -fsyntax-only -verify %s -ast-dump
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -include %S/cxx_exprs.h -std=c++11 -fsyntax-only -verify %s -ast-dump
// Test with pch. Use '-ast-dump' to force deserialization of function bodies.
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -x c++-header -std=c++0x -emit-pch -o %t %S/cxx_exprs.h
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++0x -include-pch %t -fsyntax-only -verify %s -ast-dump
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -x c++-header -std=c++11 -emit-pch -o %t %S/cxx_exprs.h
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-dump
int integer;
double floating;
diff --git a/test/PCH/functions.c b/test/PCH/functions.c
index 23becb60e8ed..35e39210585b 100644
--- a/test/PCH/functions.c
+++ b/test/PCH/functions.c
@@ -4,7 +4,7 @@
// Test with pch.
// RUN: %clang_cc1 -emit-pch -o %t %S/functions.h
// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
-
+// expected-note{{'f1' declared here}}
int f0(int x0, int y0, ...) { return x0 + y0; }
// expected-note{{passing argument to parameter here}}
float *test_f1(int val, double x, double y) {
diff --git a/test/PCH/method-redecls.m b/test/PCH/method-redecls.m
new file mode 100644
index 000000000000..a11bf5aff7dc
--- /dev/null
+++ b/test/PCH/method-redecls.m
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -x objective-c -emit-pch -o %t
+// RUN: %clang_cc1 -x objective-c -emit-pch -o %t -D IMPL
+
+// Avoid infinite loop because of method redeclarations.
+
+@interface Foo
+-(void)meth;
+-(void)meth;
+-(void)meth;
+@end
+
+#ifdef IMPL
+
+@implementation Foo
+-(void)meth { }
+@end
+
+#endif
diff --git a/test/PCH/modified-header-error.c b/test/PCH/modified-header-error.c
index 6335fb1b4539..34f04bfb8bf9 100644
--- a/test/PCH/modified-header-error.c
+++ b/test/PCH/modified-header-error.c
@@ -9,3 +9,5 @@
#include "header2.h"
// CHECK: fatal error: file {{.*}} has been modified since the precompiled header was built
+// DISABLE: win32
+
diff --git a/test/PCH/objc_methods.h b/test/PCH/objc_methods.h
index bd775354349f..c9b1ad4342c6 100644
--- a/test/PCH/objc_methods.h
+++ b/test/PCH/objc_methods.h
@@ -2,7 +2,7 @@
@interface TestPCH
+ alloc;
-- (id)init;
+- (instancetype)instMethod;
@end
@class TestForwardClassDecl;
diff --git a/test/PCH/objc_methods.m b/test/PCH/objc_methods.m
index 3311813c98df..e90a463dce6b 100644
--- a/test/PCH/objc_methods.m
+++ b/test/PCH/objc_methods.m
@@ -12,5 +12,5 @@ void func() {
// AliasForTestPCH *zz;
xx = [TestPCH alloc];
- [xx init];
+ [xx instMethod];
}
diff --git a/test/PCH/preamble.c b/test/PCH/preamble.c
index bdc0aea65639..6a61fa10ffa1 100644
--- a/test/PCH/preamble.c
+++ b/test/PCH/preamble.c
@@ -1,7 +1,7 @@
// Check that using the preamble option actually skips the preamble.
-// RUN: %clang_cc1 -emit-pch -o %t %S/Inputs/preamble.h
-// RUN: %clang_cc1 -include-pch %t -preamble-bytes=278,1 -DFOO=f -verify %s
+// RUN: %clang_cc1 -emit-pch -o %t %S/Inputs/preamble.h -DFOO=f
+// RUN: %clang_cc1 -include-pch %t -preamble-bytes=317,1 -DFOO=f -verify %s -emit-llvm -o - | FileCheck %s
float f(int); // Not an error, because we skip this via the preamble!
@@ -19,3 +19,5 @@ float f(int); // Not an error, because we skip this via the preamble!
int g(int x) {
return FOO(x);
}
+
+// CHECK: call {{.*}} @f(
diff --git a/test/PCH/reinclude.cpp b/test/PCH/reinclude.cpp
index 71f90282ba57..97e22cf9d6f1 100644
--- a/test/PCH/reinclude.cpp
+++ b/test/PCH/reinclude.cpp
@@ -4,7 +4,7 @@
// RUN: %clang_cc1 -x c++-header %S/reinclude1.h -emit-pch -o %t1
// RUN: %clang_cc1 -x c++-header %S/reinclude2.h -include-pch %t1 -emit-pch -o %t2
// RUN: %clang_cc1 %s -include-pch %t2 -fsyntax-only -verify
-// RUN: %clang_cc1 -x c++-header %S/reinclude2.h -include-pch %t1 -emit-pch -o %t2 -chained-pch
+// RUN: %clang_cc1 -x c++-header %S/reinclude2.h -include-pch %t1 -emit-pch -o %t2
// RUN: %clang_cc1 %s -include-pch %t2 -fsyntax-only -verify
int q2 = A::y;
diff --git a/test/PCH/types.c b/test/PCH/types.c
index ba00dc6824e1..fc37a9c33d05 100644
--- a/test/PCH/types.c
+++ b/test/PCH/types.c
@@ -14,12 +14,14 @@ __attribute__((address_space(1))) int int_as_one;
ASInt *as_int_ptr1 = &int_value; // expected-error{{changes address space of pointer}}
ASInt *as_int_ptr2 = &int_as_one;
-// FIXME: TYPE_FIXED_WIDTH_INT
-
// TYPE_COMPLEX
_Complex float Cfloat_val;
Cfloat *Cfloat_ptr = &Cfloat_val;
+// TYPE_ATOMIC
+_Atomic(int) AtomicInt_val;
+AtomicInt *AtomicInt_ptr = &AtomicInt_val;
+
// TYPE_POINTER
int_ptr int_value_ptr = &int_value;
diff --git a/test/PCH/types.h b/test/PCH/types.h
index ab42331fe413..7df3f99700f6 100644
--- a/test/PCH/types.h
+++ b/test/PCH/types.h
@@ -3,11 +3,12 @@
// TYPE_EXT_QUAL
typedef __attribute__((address_space(1))) int ASInt;
-// FIXME: TYPE_FIXED_WIDTH_INT
-
// TYPE_COMPLEX
typedef _Complex float Cfloat;
+// TYPE_ATOMIC
+typedef _Atomic(int) AtomicInt;
+
// TYPE_POINTER
typedef int * int_ptr;
diff --git a/test/Parser/DelayedTemplateParsing.cpp b/test/Parser/DelayedTemplateParsing.cpp
index b447fff2f1c0..b02c4026c048 100644
--- a/test/Parser/DelayedTemplateParsing.cpp
+++ b/test/Parser/DelayedTemplateParsing.cpp
@@ -1,11 +1,11 @@
-// RUN: %clang_cc1 -fdelayed-template-parsing -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fms-extensions -fdelayed-template-parsing -fsyntax-only -verify %s
template <class T>
class A {
void foo() {
undeclared();
}
- void foo2();
+ void foo2();
};
template <class T>
@@ -40,3 +40,22 @@ void undeclared()
template <class T> void foo5() {} //expected-note {{previous definition is here}}
template <class T> void foo5() {} // expected-error {{redefinition of 'foo5'}}
+
+
+
+namespace Inner_Outer_same_template_param_name {
+
+template <class T>
+class Outmost {
+public:
+ template <class T>
+ class Inner {
+ public:
+ void f() {
+ T* var;
+ }
+ };
+};
+
+}
+
diff --git a/test/Parser/MicrosoftExtensions.c b/test/Parser/MicrosoftExtensions.c
index 2b8451b26dda..a0f15e9d8634 100644
--- a/test/Parser/MicrosoftExtensions.c
+++ b/test/Parser/MicrosoftExtensions.c
@@ -8,10 +8,16 @@ extern __declspec(dllimport) void __stdcall VarR4FromDec();
__declspec(deprecated) __declspec(deprecated) char * __cdecl ltoa( long _Val, char * _DstBuf, int _Radix);
__declspec(noalias) __declspec(restrict) void * __cdecl xxx( void * _Memory );
typedef __w64 unsigned long ULONG_PTR, *PULONG_PTR;
+
void * __ptr64 PtrToPtr64(const void *p)
{
- return((void * __ptr64) (unsigned __int64) (ULONG_PTR)p );
+ return((void * __ptr64) (unsigned __int64) (ULONG_PTR)p ); // expected-warning {{unknown attribute '__ptr64' ignored}}
+}
+void * __ptr32 PtrToPtr32(const void *p)
+{
+ return((void * __ptr32) (unsigned __int32) (ULONG_PTR)p ); // expected-warning {{unknown attribute '__ptr32' ignored}}
}
+
void __forceinline InterlockedBitTestAndSet (long *Base, long Bit)
{
__asm {
diff --git a/test/Parser/PR11000.cpp b/test/Parser/PR11000.cpp
new file mode 100644
index 000000000000..7dae99621bbb
--- /dev/null
+++ b/test/Parser/PR11000.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -std=c++11 %s 2>&1 | FileCheck %s
+
+// PR11000: Don't crash.
+class tuple<>
+{
+ template <class _Alloc>
+ tuple(allocator_arg_t, const _Alloc&) {}
+
+// CHECK: 6 errors generated.
diff --git a/test/Parser/access-spec-attrs.cpp b/test/Parser/access-spec-attrs.cpp
new file mode 100644
index 000000000000..4fa597581165
--- /dev/null
+++ b/test/Parser/access-spec-attrs.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify
+
+struct X {
+public __attribute__((unavailable)): // expected-error {{access specifier can only have annotation attributes}}
+ void foo();
+private __attribute__((annotate("foobar"))):
+ void bar();
+};
+
+void f(X x) {
+ x.foo();
+}
diff --git a/test/Parser/c1x-alignas.c b/test/Parser/c1x-alignas.c
new file mode 100644
index 000000000000..5dccc99035ad
--- /dev/null
+++ b/test/Parser/c1x-alignas.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -std=c1x -fsyntax-only -verify %s
+
+_Alignas(4) char c1;
+unsigned _Alignas(long) char c2;
+char _Alignas(16) c3;
+
+char c4 _Alignas(32); // expected-error {{expected ';' after top level declarator}}
diff --git a/test/Parser/char-literal-printing.c b/test/Parser/char-literal-printing.c
index 5843e5f40157..27dd63a4fc49 100644
--- a/test/Parser/char-literal-printing.c
+++ b/test/Parser/char-literal-printing.c
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -ast-print %s
+// RUN: %clang_cc1 -x c++ -ast-print %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -ast-print %s
#include <stddef.h>
@@ -29,3 +31,37 @@ char test23(void) { return '\x3'; }
wchar_t test24(void) { return L'\x3'; }
wchar_t test25(void) { return L'\x333'; }
+
+#if __cplusplus >= 201103L
+char16_t test26(void) { return u'\\'; }
+char16_t test27(void) { return u'\''; }
+char16_t test28(void) { return u'\a'; }
+char16_t test29(void) { return u'\b'; }
+char16_t test30(void) { return u'\e'; }
+char16_t test31(void) { return u'\f'; }
+char16_t test32(void) { return u'\n'; }
+char16_t test33(void) { return u'\r'; }
+char16_t test34(void) { return u'\t'; }
+char16_t test35(void) { return u'\v'; }
+
+char16_t test36(void) { return u'c'; }
+char16_t test37(void) { return u'\x3'; }
+
+char16_t test38(void) { return u'\x333'; }
+
+char32_t test39(void) { return U'\\'; }
+char32_t test40(void) { return U'\''; }
+char32_t test41(void) { return U'\a'; }
+char32_t test42(void) { return U'\b'; }
+char32_t test43(void) { return U'\e'; }
+char32_t test44(void) { return U'\f'; }
+char32_t test45(void) { return U'\n'; }
+char32_t test46(void) { return U'\r'; }
+char32_t test47(void) { return U'\t'; }
+char32_t test48(void) { return U'\v'; }
+
+char32_t test49(void) { return U'c'; }
+char32_t test50(void) { return U'\x3'; }
+
+char32_t test51(void) { return U'\x333'; }
+#endif
diff --git a/test/Parser/cxx-casting.cpp b/test/Parser/cxx-casting.cpp
index 4a0bb4d1e4e5..42ad12ee94f3 100644
--- a/test/Parser/cxx-casting.cpp
+++ b/test/Parser/cxx-casting.cpp
@@ -67,3 +67,26 @@ void test2(char x, struct B * b) {
test1::A LCC B> e; // expected-error{{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
(void)static_cast LCC c>(&x); // expected-error{{found '<::' after a static_cast which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
}
+
+ // This note comes from "::D[:F> A5;"
+template <class T> class D {}; // expected-note{{template is declared here}}
+template <class T> void E() {};
+class F {};
+
+void test3() {
+ ::D<::F> A1; // expected-error{{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+ D<::F> A2; // expected-error{{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+ ::E<::F>(); // expected-error{{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+ E<::F>(); // expected-error{{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+
+ ::D< ::F> A3;
+ D< ::F> A4;
+ ::E< ::F>();
+ E< ::F>();
+
+ // Make sure that parser doesn't expand '[:' to '< ::'
+ ::D[:F> A5; // expected-error {{cannot refer to class template 'D' without a template argument list}} \
+ // expected-error {{expected expression}} \
+ // expected-error {{expected ']'}} \
+ // expected-note {{to match this '['}}
+}
diff --git a/test/Parser/cxx-class.cpp b/test/Parser/cxx-class.cpp
index f863bd198e50..1c0d862b3096 100644
--- a/test/Parser/cxx-class.cpp
+++ b/test/Parser/cxx-class.cpp
@@ -40,3 +40,20 @@ typedef union {
} y;
} bug3177;
+// check that we don't consume the token after the access specifier
+// when it's not a colon
+class D {
+public // expected-error{{expected ':'}}
+ int i;
+};
+
+// consume the token after the access specifier if it's a semicolon
+// that was meant to be a colon
+class E {
+public; // expected-error{{expected ':'}}
+ int i;
+};
+
+// PR11109 must appear at the end of the source file
+class pr11109r3 { // expected-note{{to match this '{'}}
+ public // expected-error{{expected ':'}} expected-error{{expected '}'}} expected-error{{expected ';' after class}}
diff --git a/test/Parser/cxx-default-delete.cpp b/test/Parser/cxx-default-delete.cpp
index a3d5b2c1d9b2..f34f6fb014f2 100644
--- a/test/Parser/cxx-default-delete.cpp
+++ b/test/Parser/cxx-default-delete.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
int i = delete; // expected-error{{only functions}}
int j = default; // expected-error{{special member functions}}
diff --git a/test/Parser/cxx-ext-delete-default.cpp b/test/Parser/cxx-ext-delete-default.cpp
index 062723851496..be6efee24163 100644
--- a/test/Parser/cxx-ext-delete-default.cpp
+++ b/test/Parser/cxx-ext-delete-default.cpp
@@ -1,11 +1,11 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
struct A {
- A(const A&) = delete; // expected-warning {{accepted as a C++0x extension}}
- A& operator=(const A&) = delete; // expected-warning {{accepted as a C++0x extension}}
- A() = default; // expected-warning {{accepted as a C++0x extension}}
+ A(const A&) = delete; // expected-warning {{accepted as a C++11 extension}}
+ A& operator=(const A&) = delete; // expected-warning {{accepted as a C++11 extension}}
+ A() = default; // expected-warning {{accepted as a C++11 extension}}
~A();
};
-void f() = delete; // expected-warning {{accepted as a C++0x extension}}
-A::~A() = default; //expected-warning {{accepted as a C++0x extension}}
+void f() = delete; // expected-warning {{accepted as a C++11 extension}}
+A::~A() = default; //expected-warning {{accepted as a C++11 extension}}
diff --git a/test/Parser/cxx-member-init-missing-paren-crash.cpp b/test/Parser/cxx-member-init-missing-paren-crash.cpp
new file mode 100644
index 000000000000..5485e7d2d5c3
--- /dev/null
+++ b/test/Parser/cxx-member-init-missing-paren-crash.cpp
@@ -0,0 +1,12 @@
+// RUN: not %clang_cc1 -fsyntax-only %s
+// Note: The important part here is that we don't crash, not any specific errors
+class Test {
+ public:
+ Test() : ab_(false {};
+
+ bool ab() {
+ return ab_;
+ }
+ private:
+ bool ab_;
+}
diff --git a/test/Parser/cxx-member-initializers.cpp b/test/Parser/cxx-member-initializers.cpp
index 34a725ff43af..5c3906836c49 100644
--- a/test/Parser/cxx-member-initializers.cpp
+++ b/test/Parser/cxx-member-initializers.cpp
@@ -8,3 +8,8 @@ struct y {
int a;
y() : a(4) ; // expected-error {{expected '{'}}
};
+
+struct z {
+ int a;
+ z() : a {} // expected-error {{expected '('}}
+};
diff --git a/test/Parser/cxx-reference.cpp b/test/Parser/cxx-reference.cpp
index fae938bcaab0..d21412cec0fc 100644
--- a/test/Parser/cxx-reference.cpp
+++ b/test/Parser/cxx-reference.cpp
@@ -18,4 +18,4 @@ int & volatile Y = val; // expected-error {{'volatile' qualifier may not be appl
int & const volatile Z = val; /* expected-error {{'const' qualifier may not be applied}} \
expected-error {{'volatile' qualifier may not be applied}} */
-typedef int && RV; // expected-warning {{rvalue references are a C++0x extension}}
+typedef int && RV; // expected-warning {{rvalue references are a C++11 extension}}
diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp
index f65e29070957..e762b57a93d6 100644
--- a/test/Parser/cxx0x-attributes.cpp
+++ b/test/Parser/cxx0x-attributes.cpp
@@ -1,23 +1,26 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 %s
// Declaration syntax checks
[[]] int before_attr;
+int [[]] between_attr;
int after_attr [[]];
int * [[]] ptr_attr;
int array_attr [1] [[]];
-[[align(8)]] int aligned_attr;
+alignas(8) int aligned_attr;
[[test::valid(for 42 [very] **** '+' symbols went on a trip; the end.)]]
int garbage_attr;
void fn_attr () [[]];
class [[]] class_attr {};
extern "C++" [[]] int extern_attr;
template <typename T> [[]] void template_attr ();
+[[]] [[]] int [[]] [[]] multi_attr [[]] [[]];
int comma_attr [[,]]; // expected-error {{expected identifier}}
int scope_attr [[foo::]]; // expected-error {{expected identifier}}
+unsigned [[]] int attr_in_decl_spec; // expected-error {{expected unqualified-id}}
int & [[]] ref_attr = after_attr; // expected-error {{an attribute list cannot appear here}}
class foo {
- void after_const_attr () const [[]]; // expected-error {{expected expression}}
+ void after_const_attr () const [[]]; // expected-error {{expected body of lambda expression}} expected-error {{array has incomplete element type 'void'}}
};
extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}}
[[]] template <typename T> void before_template_attr (); // expected-error {{an attribute list cannot appear here}}
@@ -29,8 +32,8 @@ extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}}
[[]] using namespace ns;
// Argument tests
-[[align]] int aligned_no_params; // expected-error {{C++0x attribute 'align' must have an argument list}}
-[[align(i)]] int aligned_nonconst; // expected-error {{'aligned' attribute requires integer constant}}
+alignas int aligned_no_params; // expected-error {{expected '('}}
+alignas(i) int aligned_nonconst; // expected-error {{'aligned' attribute requires integer constant}}
// Statement tests
void foo () {
diff --git a/test/Parser/cxx0x-in-cxx98.cpp b/test/Parser/cxx0x-in-cxx98.cpp
index e0cbc23f5811..9e41a700a982 100644
--- a/test/Parser/cxx0x-in-cxx98.cpp
+++ b/test/Parser/cxx0x-in-cxx98.cpp
@@ -1,10 +1,10 @@
// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify %s
-inline namespace N { // expected-warning{{inline namespaces are a C++0x feature}}
+inline namespace N { // expected-warning{{inline namespaces are a C++11 feature}}
struct X {
- template<typename ...Args> // expected-warning{{variadic templates are a C++0x extension}}
- void f(Args &&...) &; // expected-warning{{rvalue references are a C++0x extension}} \
- // expected-warning{{reference qualifiers on functions are a C++0x extension}}
+ template<typename ...Args> // expected-warning{{variadic templates are a C++11 extension}}
+ void f(Args &&...) &; // expected-warning{{rvalue references are a C++11 extension}} \
+ // expected-warning{{reference qualifiers on functions are a C++11 extension}}
};
}
diff --git a/test/Parser/cxx0x-lambda-expressions.cpp b/test/Parser/cxx0x-lambda-expressions.cpp
new file mode 100644
index 000000000000..b4fe4cca7d11
--- /dev/null
+++ b/test/Parser/cxx0x-lambda-expressions.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+class C {
+
+ int f() {
+ int foo, bar;
+
+ []; // expected-error {{expected body of lambda expression}}
+ [+] {}; // expected-error {{expected variable name or 'this' in lambda capture list}}
+ [foo+] {}; // expected-error {{expected ',' or ']' in lambda capture list}}
+ [foo,&this] {}; // expected-error {{'this' cannot be captured by reference}}
+ [&this] {}; // expected-error {{'this' cannot be captured by reference}}
+ [&,] {}; // expected-error {{ expected variable name or 'this' in lambda capture list}}
+ [=,] {}; // expected-error {{ expected variable name or 'this' in lambda capture list}}
+ [] {};
+ [=] (int i) {};
+ [&] (int) mutable -> void {};
+ [foo,bar] () { return 3; };
+ [=,&foo] () {};
+ [&,foo] () {};
+ [this] () {};
+
+ return 1;
+ }
+
+};
+
diff --git a/test/Parser/cxx0x-literal-operators.cpp b/test/Parser/cxx0x-literal-operators.cpp
index 30b290382cb4..4fcbad490d38 100644
--- a/test/Parser/cxx0x-literal-operators.cpp
+++ b/test/Parser/cxx0x-literal-operators.cpp
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
void operator "" (const char *); // expected-error {{expected identifier}}
-void operator "k" foo(const char *); // expected-error {{string literal after 'operator' must be '""'}}
-void operator "" tester (const char *);
+void operator "k" foo(const char *); // expected-error {{string literal after 'operator' must be '""'}} \
+// expected-warning{{user-defined literal with suffix 'foo' is preempted by C99 hexfloat extension}}
+void operator "" tester (const char *); // expected-warning{{user-defined literal with suffix 'tester' is preempted by C99 hexfloat extension}}
diff --git a/test/Parser/cxx0x-member-initializers.cpp b/test/Parser/cxx0x-member-initializers.cpp
index 6c3492ef2133..a324f974bcaf 100644
--- a/test/Parser/cxx0x-member-initializers.cpp
+++ b/test/Parser/cxx0x-member-initializers.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// Make sure we don't run off the end of the stream when parsing a deferred
// initializer.
@@ -13,3 +13,17 @@ struct T {
int b = 2;
int c = b; // expected-error {{undeclared identifier}}
};
+
+// Test recovery for bad constructor initializers
+
+struct R1 {
+ int a;
+ R1() : a {}
+}; // expected-error {{expected '{' or ','}}
+
+// Test correct parsing.
+
+struct V1 {
+ int a, b;
+ V1() : a(), b{} {}
+};
diff --git a/test/Parser/cxx0x-override-control-keywords.cpp b/test/Parser/cxx0x-override-control-keywords.cpp
index 91d5132febe8..444862a5c853 100644
--- a/test/Parser/cxx0x-override-control-keywords.cpp
+++ b/test/Parser/cxx0x-override-control-keywords.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct Base {
virtual void override();
diff --git a/test/Parser/cxx0x-rvalue-reference.cpp b/test/Parser/cxx0x-rvalue-reference.cpp
index ae568e8859c0..e57e6013e5e7 100644
--- a/test/Parser/cxx0x-rvalue-reference.cpp
+++ b/test/Parser/cxx0x-rvalue-reference.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
int && r1(int &&a);
diff --git a/test/Parser/ms-inline-asm.c b/test/Parser/ms-inline-asm.c
new file mode 100644
index 000000000000..b1af23e47280
--- /dev/null
+++ b/test/Parser/ms-inline-asm.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 %s -verify -fms-extensions
+
+#define M __asm int 0x2c
+#define M2 int
+
+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 {
+ int 0x2c ; } asm comments are fun! }{
+ }
+ __asm {}
+}
+int t6() {
+ __asm int 3 ; } comments for single-line asm
+ __asm {}
+
+ __asm int 4
+ return 10;
+}
+int t7() { // expected-note {{to match this}}
+ __asm
+ __asm { // expected-error 3 {{expected}} expected-note {{to match this}}
diff --git a/test/Parser/objc-init.m b/test/Parser/objc-init.m
index 32ba948f472d..074820526c93 100644
--- a/test/Parser/objc-init.m
+++ b/test/Parser/objc-init.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -pedantic
-// RUN: %clang_cc1 -fsyntax-only -verify -x objective-c++ %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-fragile-abi -verify %s -pedantic
+// RUN: %clang_cc1 -fsyntax-only -fobjc-fragile-abi -verify -x objective-c++ %s
// rdar://5707001
@interface NSNumber;
diff --git a/test/Parser/objc-messaging-neg-1.m b/test/Parser/objc-messaging-neg-1.m
index 4ddadb816f0d..bb496e96914e 100644
--- a/test/Parser/objc-messaging-neg-1.m
+++ b/test/Parser/objc-messaging-neg-1.m
@@ -9,4 +9,5 @@ int main() {
[a bla:0 6:7]; // expected-error {{expected ']'}}
[A foo bar]; // expected-error {{expected ':'}}
[A foo bar bar1]; // expected-error {{expected ':'}}
+ [] {}; // expected-error {{expected expression}}
}
diff --git a/test/Parser/objcxx-lambda-expressions-neg.mm b/test/Parser/objcxx-lambda-expressions-neg.mm
new file mode 100644
index 000000000000..864cc6b8fbf5
--- /dev/null
+++ b/test/Parser/objcxx-lambda-expressions-neg.mm
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int main() {
+ []{}; // expected-error {{expected expression}}
+}
diff --git a/test/Parser/objcxx0x-lambda-expressions.mm b/test/Parser/objcxx0x-lambda-expressions.mm
new file mode 100644
index 000000000000..937464918b6a
--- /dev/null
+++ b/test/Parser/objcxx0x-lambda-expressions.mm
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+class C {
+
+ void f() {
+ int foo, bar;
+
+ // fail to parse as a lambda introducer, so we get objc message parsing errors instead
+ [foo,+] {}; // expected-error {{expected expression}}
+
+ []; // 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}}
+ [] {};
+ [=] (int i) {};
+ [&] (int) mutable -> void {};
+ // FIXME: this error occurs because we do not yet handle lambda scopes
+ // properly. I did not anticipate it because I thought it was a semantic (not
+ // syntactic) check.
+ [foo,bar] () { return 3; }; // expected-error {{void function 'f' should not return a value}}
+ [=,&foo] () {};
+ [this] () {};
+ }
+
+};
+
diff --git a/test/Parser/opencl-pragma.cl b/test/Parser/opencl-pragma.cl
index 5b6c55ab0743..19460771137b 100644
--- a/test/Parser/opencl-pragma.cl
+++ b/test/Parser/opencl-pragma.cl
@@ -4,6 +4,9 @@
#pragma OPENCL EXTENSION cl_no_such_extension : disable /* expected-warning {{unknown OpenCL extension 'cl_no_such_extension' - ignoring}} */
+#pragma OPENCL EXTENSION all : disable
+#pragma OPENCL EXTENSION all : enable /* expected-warning {{unknown OpenCL extension 'all' - ignoring}} */
+
#pragma OPENCL EXTENSION cl_khr_fp64 : on /* expected-warning {{expected 'enable' or 'disable' - ignoring}} */
#pragma OPENCL FP_CONTRACT ON
diff --git a/test/Parser/opencl-storage-class.cl b/test/Parser/opencl-storage-class.cl
index d479358f0024..874329b62d5a 100644
--- a/test/Parser/opencl-storage-class.cl
+++ b/test/Parser/opencl-storage-class.cl
@@ -6,4 +6,10 @@ void test_storage_class_specs()
register int b; // expected-error {{OpenCL does not support the 'register' storage class specifier}}
extern int c; // expected-error {{OpenCL does not support the 'extern' storage class specifier}}
auto int d; // expected-error {{OpenCL does not support the 'auto' storage class specifier}}
+
+#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable
+ static int e;
+ register int f;
+ extern int g;
+ auto int h;
}
diff --git a/test/Parser/parser_overflow.c b/test/Parser/parser_overflow.c
new file mode 100644
index 000000000000..d2006ea5575e
--- /dev/null
+++ b/test/Parser/parser_overflow.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -fsyntax-only 2>&1 | FileCheck %s
+
+void foo(void) {
+ {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+}
+
+// CHECK: fatal error: parser recursion limit reached, program too complex
diff --git a/test/Parser/pragma-visibility2.c b/test/Parser/pragma-visibility2.c
new file mode 100644
index 000000000000..bcef09ff2b99
--- /dev/null
+++ b/test/Parser/pragma-visibility2.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -emit-llvm -triple i386-linux-gnu -o %t %s
+// RUN: FileCheck --input-file=%t %s
+// PR10392
+
+#define push(foo) push(default)
+#pragma GCC visibility push(hidden)
+
+int v1;
+// CHECK: @v1 = common hidden global i32 0, align 4
+
+#pragma GCC visibility pop
+
+int v2;
+// CHECK: @v2 = common global i32 0, align 4
+
+_Pragma("GCC visibility push(hidden)");
+
+int v3;
+// CHECK: @v3 = common hidden global i32 0, align 4
diff --git a/test/Parser/switch-recovery.cpp b/test/Parser/switch-recovery.cpp
index a1df4261db45..84ac0c899e55 100644
--- a/test/Parser/switch-recovery.cpp
+++ b/test/Parser/switch-recovery.cpp
@@ -79,7 +79,7 @@ int test7(int i) {
case false ? 1 : 2:
true ? 1 : 2: // expected-error {{expected 'case' keyword before expression}}
case 10:
- 14 ? 3 : 4;
+ 14 ? 3 : 4; // expected-warning {{expression result unused}}
default:
return 1;
}
diff --git a/test/Parser/top-level-semi-cxx0x.cpp b/test/Parser/top-level-semi-cxx0x.cpp
index 592483c86bb6..be342a225704 100644
--- a/test/Parser/top-level-semi-cxx0x.cpp
+++ b/test/Parser/top-level-semi-cxx0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++0x -verify %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++11 -verify %s
void foo();
diff --git a/test/Preprocessor/comment_save_if.c b/test/Preprocessor/comment_save_if.c
index 2f35bcb9e8c6..4946122a3f0c 100644
--- a/test/Preprocessor/comment_save_if.c
+++ b/test/Preprocessor/comment_save_if.c
@@ -1,6 +1,11 @@
-// RUN: %clang_cc1 %s -E -CC -pedantic 2>&1 | grep -v '^/' | not grep warning
+// RUN: %clang_cc1 %s -E -CC -pedantic -verify
#if 1 /*bar */
#endif /*foo*/
+#if /*foo*/ defined /*foo*/ FOO /*foo*/
+#if /*foo*/ defined /*foo*/ ( /*foo*/ FOO /*foo*/ ) /*foo*/
+#endif
+#endif
+
diff --git a/test/Preprocessor/expr_define_expansion.c b/test/Preprocessor/expr_define_expansion.c
new file mode 100644
index 000000000000..38c0384092ae
--- /dev/null
+++ b/test/Preprocessor/expr_define_expansion.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 %s -E -CC -pedantic -verify
+
+#define FOO && 1
+#if defined FOO FOO
+#endif
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index f0920c9dedbd..11218154ea1c 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -9,7 +9,7 @@
// BLOCKS:#define __block __attribute__((__blocks__(byref)))
//
//
-// RUN: %clang_cc1 -x c++ -std=c++0x -E -dM < /dev/null | FileCheck -check-prefix CXX0X %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -E -dM < /dev/null | FileCheck -check-prefix CXX0X %s
//
// CXX0X:#define __GNUG__
// CXX0X:#define __GXX_EXPERIMENTAL_CXX0X__ 1
@@ -76,7 +76,7 @@
// C94:#define __STDC_VERSION__ 199409L
//
//
-// RUN: %clang_cc1 -fms-extensions -triple i686-pc-win32 -E -dM < /dev/null | FileCheck -check-prefix MSEXT %s
+// RUN: %clang_cc1 -fms-extensions -triple i686-pc-win32 -fobjc-fragile-abi -E -dM < /dev/null | FileCheck -check-prefix MSEXT %s
//
// MSEXT-NOT:#define __STDC__
// MSEXT:#define _INTEGRAL_MAX_BITS 64
@@ -94,7 +94,7 @@
// OBJCGC:#define __OBJC_GC__ 1
//
//
-// RUN: %clang_cc1 -x objective-c -fobjc-nonfragile-abi -E -dM < /dev/null | FileCheck -check-prefix NONFRAGILE %s
+// RUN: %clang_cc1 -x objective-c -fobjc-exceptions -E -dM < /dev/null | FileCheck -check-prefix NONFRAGILE %s
//
// NONFRAGILE:#define OBJC_ZEROCOST_EXCEPTIONS 1
// NONFRAGILE:#define __OBJC2__ 1
@@ -410,9 +410,6 @@
// I386:#define __WINT_WIDTH__ 32
// I386:#define __i386 1
// I386:#define __i386__ 1
-// I386:#define __nocona 1
-// I386:#define __nocona__ 1
-// I386:#define __tune_nocona__ 1
// I386:#define i386 1
//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i386-pc-linux-gnu < /dev/null | FileCheck -check-prefix I386-LINUX %s
@@ -508,9 +505,6 @@
// I386-LINUX:#define __WINT_WIDTH__ 32
// I386-LINUX:#define __i386 1
// I386-LINUX:#define __i386__ 1
-// I386-LINUX:#define __nocona 1
-// I386-LINUX:#define __nocona__ 1
-// I386-LINUX:#define __tune_nocona__ 1
// I386-LINUX:#define i386 1
//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=msp430-none-none < /dev/null | FileCheck -check-prefix MSP430 %s
@@ -1183,9 +1177,6 @@
// X86_64:#define __WINT_WIDTH__ 32
// X86_64:#define __amd64 1
// X86_64:#define __amd64__ 1
-// X86_64:#define __nocona 1
-// X86_64:#define __nocona__ 1
-// X86_64:#define __tune_nocona__ 1
// X86_64:#define __x86_64 1
// X86_64:#define __x86_64__ 1
//
@@ -1289,13 +1280,10 @@
// X86_64-LINUX:#define __WINT_WIDTH__ 32
// X86_64-LINUX:#define __amd64 1
// X86_64-LINUX:#define __amd64__ 1
-// X86_64-LINUX:#define __nocona 1
-// X86_64-LINUX:#define __nocona__ 1
-// X86_64-LINUX:#define __tune_nocona__ 1
// X86_64-LINUX:#define __x86_64 1
// X86_64-LINUX:#define __x86_64__ 1
//
-// RUN: %clang_cc1 -x c++ -triple i686-pc-linux-gnu -E -dM < /dev/null | FileCheck -check-prefix GNUSOURCE %s
+// RUN: %clang_cc1 -x c++ -triple i686-pc-linux-gnu -fobjc-fragile-abi -E -dM < /dev/null | FileCheck -check-prefix GNUSOURCE %s
// GNUSOURCE:#define _GNU_SOURCE 1
//
// RUN: %clang_cc1 -x c++ -std=c++98 -fno-rtti -E -dM < /dev/null | FileCheck -check-prefix NORTTI %s
diff --git a/test/Preprocessor/missing-system-header.c b/test/Preprocessor/missing-system-header.c
new file mode 100644
index 000000000000..69cb1314eaef
--- /dev/null
+++ b/test/Preprocessor/missing-system-header.c
@@ -0,0 +1,2 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s
+#include "missing-system-header.h"
diff --git a/test/Preprocessor/missing-system-header.h b/test/Preprocessor/missing-system-header.h
new file mode 100644
index 000000000000..393ab2b5c979
--- /dev/null
+++ b/test/Preprocessor/missing-system-header.h
@@ -0,0 +1,2 @@
+#pragma clang system_header
+#include "not exist" // expected-error {{file not found}}
diff --git a/test/Preprocessor/non_fragile_feature.m b/test/Preprocessor/non_fragile_feature.m
index 1f67ed3f09bd..cf64df2bf880 100644
--- a/test/Preprocessor/non_fragile_feature.m
+++ b/test/Preprocessor/non_fragile_feature.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi %s
+// RUN: %clang_cc1 %s
#ifndef __has_feature
#error Should have __has_feature
#endif
diff --git a/test/Preprocessor/non_fragile_feature1.m b/test/Preprocessor/non_fragile_feature1.m
index 89b52ed53bf5..79cc488a0b6e 100644
--- a/test/Preprocessor/non_fragile_feature1.m
+++ b/test/Preprocessor/non_fragile_feature1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fobjc-fragile-abi %s
#ifndef __has_feature
#error Should have __has_feature
#endif
diff --git a/test/Preprocessor/pp-record.c b/test/Preprocessor/pp-record.c
new file mode 100644
index 000000000000..dcb52b56b7d9
--- /dev/null
+++ b/test/Preprocessor/pp-record.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -detailed-preprocessing-record %s
+
+// http://llvm.org/PR11120
+
+#define FILE_HEADER_NAME "pp-record.h"
+
+#if defined(FILE_HEADER_NAME)
+#include FILE_HEADER_NAME
+#endif
diff --git a/test/Preprocessor/pp-record.h b/test/Preprocessor/pp-record.h
new file mode 100644
index 000000000000..34158bd20527
--- /dev/null
+++ b/test/Preprocessor/pp-record.h
@@ -0,0 +1 @@
+// Only useful for #inclusion.
diff --git a/test/Preprocessor/predefined-arch-macros.c b/test/Preprocessor/predefined-arch-macros.c
new file mode 100644
index 000000000000..b063f7fe089a
--- /dev/null
+++ b/test/Preprocessor/predefined-arch-macros.c
@@ -0,0 +1,866 @@
+// These tests are generated by running utils/generate_arch_predefine_tests.sh
+// to observe GCC's behavior (or some other system compiler's behavior).
+//
+// Begin X86/GCC/Linux tests ----------------
+//
+// RUN: %clang -march=i386 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_I386_M32
+// CHECK_I386_M32: #define __i386 1
+// CHECK_I386_M32: #define __i386__ 1
+// CHECK_I386_M32: #define __tune_i386__ 1
+// CHECK_I386_M32: #define i386 1
+// RUN: %clang -march=i386 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_I386_M64
+// CHECK_I386_M64: error:
+//
+// RUN: %clang -march=i486 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_I486_M32
+// CHECK_I486_M32: #define __i386 1
+// CHECK_I486_M32: #define __i386__ 1
+// CHECK_I486_M32: #define __i486 1
+// CHECK_I486_M32: #define __i486__ 1
+// CHECK_I486_M32: #define __tune_i486__ 1
+// CHECK_I486_M32: #define i386 1
+// RUN: %clang -march=i486 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_I486_M64
+// CHECK_I486_M64: error:
+//
+// RUN: %clang -march=i586 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_I586_M32
+// CHECK_I586_M32: #define __i386 1
+// CHECK_I586_M32: #define __i386__ 1
+// CHECK_I586_M32: #define __i586 1
+// CHECK_I586_M32: #define __i586__ 1
+// CHECK_I586_M32: #define __pentium 1
+// CHECK_I586_M32: #define __pentium__ 1
+// CHECK_I586_M32: #define __tune_i586__ 1
+// CHECK_I586_M32: #define __tune_pentium__ 1
+// CHECK_I586_M32: #define i386 1
+// RUN: %clang -march=i586 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_I586_M64
+// CHECK_I586_M64: error:
+//
+// RUN: %clang -march=pentium -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM_M32
+// CHECK_PENTIUM_M32: #define __i386 1
+// CHECK_PENTIUM_M32: #define __i386__ 1
+// CHECK_PENTIUM_M32: #define __i586 1
+// CHECK_PENTIUM_M32: #define __i586__ 1
+// CHECK_PENTIUM_M32: #define __pentium 1
+// CHECK_PENTIUM_M32: #define __pentium__ 1
+// CHECK_PENTIUM_M32: #define __tune_i586__ 1
+// CHECK_PENTIUM_M32: #define __tune_pentium__ 1
+// CHECK_PENTIUM_M32: #define i386 1
+// RUN: %clang -march=pentium -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM_M64
+// CHECK_PENTIUM_M64: error:
+//
+// RUN: %clang -march=pentium-mmx -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM_MMX_M32
+// CHECK_PENTIUM_MMX_M32: #define __MMX__ 1
+// CHECK_PENTIUM_MMX_M32: #define __i386 1
+// CHECK_PENTIUM_MMX_M32: #define __i386__ 1
+// CHECK_PENTIUM_MMX_M32: #define __i586 1
+// CHECK_PENTIUM_MMX_M32: #define __i586__ 1
+// CHECK_PENTIUM_MMX_M32: #define __pentium 1
+// CHECK_PENTIUM_MMX_M32: #define __pentium__ 1
+// CHECK_PENTIUM_MMX_M32: #define __pentium_mmx__ 1
+// CHECK_PENTIUM_MMX_M32: #define __tune_i586__ 1
+// CHECK_PENTIUM_MMX_M32: #define __tune_pentium__ 1
+// CHECK_PENTIUM_MMX_M32: #define __tune_pentium_mmx__ 1
+// CHECK_PENTIUM_MMX_M32: #define i386 1
+// RUN: %clang -march=pentium-mmx -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM_MMX_M64
+// CHECK_PENTIUM_MMX_M64: error:
+//
+// RUN: %clang -march=winchip-c6 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_WINCHIP_C6_M32
+// CHECK_WINCHIP_C6_M32: #define __MMX__ 1
+// CHECK_WINCHIP_C6_M32: #define __i386 1
+// CHECK_WINCHIP_C6_M32: #define __i386__ 1
+// CHECK_WINCHIP_C6_M32: #define __i486 1
+// CHECK_WINCHIP_C6_M32: #define __i486__ 1
+// CHECK_WINCHIP_C6_M32: #define __tune_i486__ 1
+// CHECK_WINCHIP_C6_M32: #define i386 1
+// RUN: %clang -march=winchip-c6 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_WINCHIP_C6_M64
+// CHECK_WINCHIP_C6_M64: error:
+//
+// RUN: %clang -march=winchip2 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_WINCHIP2_M32
+// CHECK_WINCHIP2_M32: #define __3dNOW__ 1
+// CHECK_WINCHIP2_M32: #define __MMX__ 1
+// CHECK_WINCHIP2_M32: #define __i386 1
+// CHECK_WINCHIP2_M32: #define __i386__ 1
+// CHECK_WINCHIP2_M32: #define __i486 1
+// CHECK_WINCHIP2_M32: #define __i486__ 1
+// CHECK_WINCHIP2_M32: #define __tune_i486__ 1
+// CHECK_WINCHIP2_M32: #define i386 1
+// RUN: %clang -march=winchip2 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_WINCHIP2_M64
+// CHECK_WINCHIP2_M64: error:
+//
+// RUN: %clang -march=c3 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_C3_M32
+// CHECK_C3_M32: #define __3dNOW__ 1
+// CHECK_C3_M32: #define __MMX__ 1
+// CHECK_C3_M32: #define __i386 1
+// CHECK_C3_M32: #define __i386__ 1
+// CHECK_C3_M32: #define __i486 1
+// CHECK_C3_M32: #define __i486__ 1
+// CHECK_C3_M32: #define __tune_i486__ 1
+// CHECK_C3_M32: #define i386 1
+// RUN: %clang -march=c3 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_C3_M64
+// CHECK_C3_M64: error:
+//
+// RUN: %clang -march=c3-2 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_C3_2_M32
+// CHECK_C3_2_M32: #define __MMX__ 1
+// CHECK_C3_2_M32: #define __SSE__ 1
+// CHECK_C3_2_M32: #define __i386 1
+// CHECK_C3_2_M32: #define __i386__ 1
+// CHECK_C3_2_M32: #define __i686 1
+// CHECK_C3_2_M32: #define __i686__ 1
+// CHECK_C3_2_M32: #define __pentiumpro 1
+// CHECK_C3_2_M32: #define __pentiumpro__ 1
+// CHECK_C3_2_M32: #define __tune_i686__ 1
+// CHECK_C3_2_M32: #define __tune_pentium2__ 1
+// CHECK_C3_2_M32: #define __tune_pentiumpro__ 1
+// CHECK_C3_2_M32: #define i386 1
+// RUN: %clang -march=c3-2 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_C3_2_M64
+// CHECK_C3_2_M64: error:
+//
+// RUN: %clang -march=i686 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_I686_M32
+// CHECK_I686_M32: #define __i386 1
+// CHECK_I686_M32: #define __i386__ 1
+// CHECK_I686_M32: #define __i686 1
+// CHECK_I686_M32: #define __i686__ 1
+// CHECK_I686_M32: #define __pentiumpro 1
+// CHECK_I686_M32: #define __pentiumpro__ 1
+// CHECK_I686_M32: #define i386 1
+// RUN: %clang -march=i686 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_I686_M64
+// CHECK_I686_M64: error:
+//
+// RUN: %clang -march=pentiumpro -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUMPRO_M32
+// CHECK_PENTIUMPRO_M32: #define __i386 1
+// CHECK_PENTIUMPRO_M32: #define __i386__ 1
+// CHECK_PENTIUMPRO_M32: #define __i686 1
+// CHECK_PENTIUMPRO_M32: #define __i686__ 1
+// CHECK_PENTIUMPRO_M32: #define __pentiumpro 1
+// CHECK_PENTIUMPRO_M32: #define __pentiumpro__ 1
+// CHECK_PENTIUMPRO_M32: #define __tune_i686__ 1
+// CHECK_PENTIUMPRO_M32: #define __tune_pentiumpro__ 1
+// CHECK_PENTIUMPRO_M32: #define i386 1
+// RUN: %clang -march=pentiumpro -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUMPRO_M64
+// CHECK_PENTIUMPRO_M64: error:
+//
+// RUN: %clang -march=pentium2 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM2_M32
+// CHECK_PENTIUM2_M32: #define __MMX__ 1
+// CHECK_PENTIUM2_M32: #define __i386 1
+// CHECK_PENTIUM2_M32: #define __i386__ 1
+// CHECK_PENTIUM2_M32: #define __i686 1
+// CHECK_PENTIUM2_M32: #define __i686__ 1
+// CHECK_PENTIUM2_M32: #define __pentiumpro 1
+// CHECK_PENTIUM2_M32: #define __pentiumpro__ 1
+// CHECK_PENTIUM2_M32: #define __tune_i686__ 1
+// CHECK_PENTIUM2_M32: #define __tune_pentium2__ 1
+// CHECK_PENTIUM2_M32: #define __tune_pentiumpro__ 1
+// CHECK_PENTIUM2_M32: #define i386 1
+// RUN: %clang -march=pentium2 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM2_M64
+// CHECK_PENTIUM2_M64: error:
+//
+// RUN: %clang -march=pentium3 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM3_M32
+// CHECK_PENTIUM3_M32: #define __MMX__ 1
+// CHECK_PENTIUM3_M32: #define __SSE__ 1
+// CHECK_PENTIUM3_M32: #define __i386 1
+// CHECK_PENTIUM3_M32: #define __i386__ 1
+// CHECK_PENTIUM3_M32: #define __i686 1
+// CHECK_PENTIUM3_M32: #define __i686__ 1
+// CHECK_PENTIUM3_M32: #define __pentiumpro 1
+// CHECK_PENTIUM3_M32: #define __pentiumpro__ 1
+// CHECK_PENTIUM3_M32: #define __tune_i686__ 1
+// CHECK_PENTIUM3_M32: #define __tune_pentium2__ 1
+// CHECK_PENTIUM3_M32: #define __tune_pentium3__ 1
+// CHECK_PENTIUM3_M32: #define __tune_pentiumpro__ 1
+// CHECK_PENTIUM3_M32: #define i386 1
+// RUN: %clang -march=pentium3 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM3_M64
+// CHECK_PENTIUM3_M64: error:
+//
+// RUN: %clang -march=pentium3m -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM3M_M32
+// CHECK_PENTIUM3M_M32: #define __MMX__ 1
+// CHECK_PENTIUM3M_M32: #define __SSE__ 1
+// CHECK_PENTIUM3M_M32: #define __i386 1
+// CHECK_PENTIUM3M_M32: #define __i386__ 1
+// CHECK_PENTIUM3M_M32: #define __i686 1
+// CHECK_PENTIUM3M_M32: #define __i686__ 1
+// CHECK_PENTIUM3M_M32: #define __pentiumpro 1
+// CHECK_PENTIUM3M_M32: #define __pentiumpro__ 1
+// CHECK_PENTIUM3M_M32: #define __tune_i686__ 1
+// CHECK_PENTIUM3M_M32: #define __tune_pentiumpro__ 1
+// CHECK_PENTIUM3M_M32: #define i386 1
+// RUN: %clang -march=pentium3m -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM3M_M64
+// CHECK_PENTIUM3M_M64: error:
+//
+// RUN: %clang -march=pentium-m -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM_M_M32
+// CHECK_PENTIUM_M_M32: #define __MMX__ 1
+// CHECK_PENTIUM_M_M32: #define __SSE2__ 1
+// CHECK_PENTIUM_M_M32: #define __SSE__ 1
+// CHECK_PENTIUM_M_M32: #define __i386 1
+// CHECK_PENTIUM_M_M32: #define __i386__ 1
+// CHECK_PENTIUM_M_M32: #define __i686 1
+// CHECK_PENTIUM_M_M32: #define __i686__ 1
+// CHECK_PENTIUM_M_M32: #define __pentiumpro 1
+// CHECK_PENTIUM_M_M32: #define __pentiumpro__ 1
+// CHECK_PENTIUM_M_M32: #define __tune_i686__ 1
+// CHECK_PENTIUM_M_M32: #define __tune_pentiumpro__ 1
+// CHECK_PENTIUM_M_M32: #define i386 1
+// RUN: %clang -march=pentium-m -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM_M_M64
+// CHECK_PENTIUM_M_M64: error:
+//
+// RUN: %clang -march=pentium4 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM4_M32
+// CHECK_PENTIUM4_M32: #define __MMX__ 1
+// CHECK_PENTIUM4_M32: #define __SSE2__ 1
+// CHECK_PENTIUM4_M32: #define __SSE__ 1
+// CHECK_PENTIUM4_M32: #define __i386 1
+// CHECK_PENTIUM4_M32: #define __i386__ 1
+// CHECK_PENTIUM4_M32: #define __pentium4 1
+// CHECK_PENTIUM4_M32: #define __pentium4__ 1
+// CHECK_PENTIUM4_M32: #define __tune_pentium4__ 1
+// CHECK_PENTIUM4_M32: #define i386 1
+// RUN: %clang -march=pentium4 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM4_M64
+// CHECK_PENTIUM4_M64: error:
+//
+// RUN: %clang -march=pentium4m -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM4M_M32
+// CHECK_PENTIUM4M_M32: #define __MMX__ 1
+// CHECK_PENTIUM4M_M32: #define __SSE2__ 1
+// CHECK_PENTIUM4M_M32: #define __SSE__ 1
+// CHECK_PENTIUM4M_M32: #define __i386 1
+// CHECK_PENTIUM4M_M32: #define __i386__ 1
+// CHECK_PENTIUM4M_M32: #define __pentium4 1
+// CHECK_PENTIUM4M_M32: #define __pentium4__ 1
+// CHECK_PENTIUM4M_M32: #define __tune_pentium4__ 1
+// CHECK_PENTIUM4M_M32: #define i386 1
+// RUN: %clang -march=pentium4m -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PENTIUM4M_M64
+// CHECK_PENTIUM4M_M64: error:
+//
+// RUN: %clang -march=prescott -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PRESCOTT_M32
+// CHECK_PRESCOTT_M32: #define __MMX__ 1
+// CHECK_PRESCOTT_M32: #define __SSE2__ 1
+// CHECK_PRESCOTT_M32: #define __SSE3__ 1
+// CHECK_PRESCOTT_M32: #define __SSE__ 1
+// CHECK_PRESCOTT_M32: #define __i386 1
+// CHECK_PRESCOTT_M32: #define __i386__ 1
+// CHECK_PRESCOTT_M32: #define __nocona 1
+// CHECK_PRESCOTT_M32: #define __nocona__ 1
+// CHECK_PRESCOTT_M32: #define __tune_nocona__ 1
+// CHECK_PRESCOTT_M32: #define i386 1
+// RUN: %clang -march=prescott -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_PRESCOTT_M64
+// CHECK_PRESCOTT_M64: error:
+//
+// RUN: %clang -march=nocona -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_NOCONA_M32
+// CHECK_NOCONA_M32: #define __MMX__ 1
+// CHECK_NOCONA_M32: #define __SSE2__ 1
+// CHECK_NOCONA_M32: #define __SSE3__ 1
+// CHECK_NOCONA_M32: #define __SSE__ 1
+// CHECK_NOCONA_M32: #define __i386 1
+// CHECK_NOCONA_M32: #define __i386__ 1
+// CHECK_NOCONA_M32: #define __nocona 1
+// CHECK_NOCONA_M32: #define __nocona__ 1
+// CHECK_NOCONA_M32: #define __tune_nocona__ 1
+// CHECK_NOCONA_M32: #define i386 1
+// RUN: %clang -march=nocona -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_NOCONA_M64
+// CHECK_NOCONA_M64: #define __MMX__ 1
+// CHECK_NOCONA_M64: #define __SSE2_MATH__ 1
+// CHECK_NOCONA_M64: #define __SSE2__ 1
+// CHECK_NOCONA_M64: #define __SSE3__ 1
+// CHECK_NOCONA_M64: #define __SSE_MATH__ 1
+// CHECK_NOCONA_M64: #define __SSE__ 1
+// CHECK_NOCONA_M64: #define __amd64 1
+// CHECK_NOCONA_M64: #define __amd64__ 1
+// CHECK_NOCONA_M64: #define __nocona 1
+// CHECK_NOCONA_M64: #define __nocona__ 1
+// CHECK_NOCONA_M64: #define __tune_nocona__ 1
+// CHECK_NOCONA_M64: #define __x86_64 1
+// CHECK_NOCONA_M64: #define __x86_64__ 1
+//
+// RUN: %clang -march=core2 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_CORE2_M32
+// CHECK_CORE2_M32: #define __MMX__ 1
+// CHECK_CORE2_M32: #define __SSE2__ 1
+// CHECK_CORE2_M32: #define __SSE3__ 1
+// CHECK_CORE2_M32: #define __SSE__ 1
+// CHECK_CORE2_M32: #define __SSSE3__ 1
+// CHECK_CORE2_M32: #define __core2 1
+// CHECK_CORE2_M32: #define __core2__ 1
+// CHECK_CORE2_M32: #define __i386 1
+// CHECK_CORE2_M32: #define __i386__ 1
+// CHECK_CORE2_M32: #define __tune_core2__ 1
+// CHECK_CORE2_M32: #define i386 1
+// RUN: %clang -march=core2 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_CORE2_M64
+// CHECK_CORE2_M64: #define __MMX__ 1
+// CHECK_CORE2_M64: #define __SSE2_MATH__ 1
+// CHECK_CORE2_M64: #define __SSE2__ 1
+// CHECK_CORE2_M64: #define __SSE3__ 1
+// CHECK_CORE2_M64: #define __SSE_MATH__ 1
+// CHECK_CORE2_M64: #define __SSE__ 1
+// CHECK_CORE2_M64: #define __SSSE3__ 1
+// CHECK_CORE2_M64: #define __amd64 1
+// CHECK_CORE2_M64: #define __amd64__ 1
+// CHECK_CORE2_M64: #define __core2 1
+// CHECK_CORE2_M64: #define __core2__ 1
+// CHECK_CORE2_M64: #define __tune_core2__ 1
+// CHECK_CORE2_M64: #define __x86_64 1
+// CHECK_CORE2_M64: #define __x86_64__ 1
+//
+// RUN: %clang -march=corei7 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_COREI7_M32
+// CHECK_COREI7_M32: #define __MMX__ 1
+// CHECK_COREI7_M32: #define __SSE2__ 1
+// CHECK_COREI7_M32: #define __SSE3__ 1
+// CHECK_COREI7_M32: #define __SSE4_1__ 1
+// CHECK_COREI7_M32: #define __SSE4_2__ 1
+// CHECK_COREI7_M32: #define __SSE__ 1
+// CHECK_COREI7_M32: #define __SSSE3__ 1
+// CHECK_COREI7_M32: #define __corei7 1
+// CHECK_COREI7_M32: #define __corei7__ 1
+// CHECK_COREI7_M32: #define __i386 1
+// CHECK_COREI7_M32: #define __i386__ 1
+// CHECK_COREI7_M32: #define __tune_corei7__ 1
+// CHECK_COREI7_M32: #define i386 1
+// RUN: %clang -march=corei7 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_COREI7_M64
+// CHECK_COREI7_M64: #define __MMX__ 1
+// CHECK_COREI7_M64: #define __SSE2_MATH__ 1
+// CHECK_COREI7_M64: #define __SSE2__ 1
+// CHECK_COREI7_M64: #define __SSE3__ 1
+// CHECK_COREI7_M64: #define __SSE4_1__ 1
+// CHECK_COREI7_M64: #define __SSE4_2__ 1
+// CHECK_COREI7_M64: #define __SSE_MATH__ 1
+// CHECK_COREI7_M64: #define __SSE__ 1
+// CHECK_COREI7_M64: #define __SSSE3__ 1
+// CHECK_COREI7_M64: #define __amd64 1
+// CHECK_COREI7_M64: #define __amd64__ 1
+// CHECK_COREI7_M64: #define __corei7 1
+// CHECK_COREI7_M64: #define __corei7__ 1
+// CHECK_COREI7_M64: #define __tune_corei7__ 1
+// CHECK_COREI7_M64: #define __x86_64 1
+// CHECK_COREI7_M64: #define __x86_64__ 1
+//
+// RUN: %clang -march=corei7-avx -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_COREI7_AVX_M32
+// CHECK_COREI7_AVX_M32: #define __AES__ 1
+// FIXME: AVX is not yet enabled with Clang.
+// CHECK_COREI7_AVX_M32-NOT: #define __AVX__ 1
+// CHECK_COREI7_AVX_M32: #define __MMX__ 1
+// CHECK_COREI7_AVX_M32: #define __SSE2__ 1
+// CHECK_COREI7_AVX_M32: #define __SSE3__ 1
+// CHECK_COREI7_AVX_M32: #define __SSE4_1__ 1
+// CHECK_COREI7_AVX_M32: #define __SSE4_2__ 1
+// CHECK_COREI7_AVX_M32: #define __SSE__ 1
+// CHECK_COREI7_AVX_M32: #define __SSSE3__ 1
+// CHECK_COREI7_AVX_M32: #define __corei7 1
+// CHECK_COREI7_AVX_M32: #define __corei7__ 1
+// CHECK_COREI7_AVX_M32: #define __i386 1
+// CHECK_COREI7_AVX_M32: #define __i386__ 1
+// CHECK_COREI7_AVX_M32: #define __tune_corei7__ 1
+// CHECK_COREI7_AVX_M32: #define i386 1
+// RUN: %clang -march=corei7-avx -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_COREI7_AVX_M64
+// CHECK_COREI7_AVX_M64: #define __AES__ 1
+// FIXME: AVX is not yet enabled with Clang.
+// CHECK_COREI7_AVX_M64-NOT: #define __AVX__ 1
+// CHECK_COREI7_AVX_M64: #define __MMX__ 1
+// CHECK_COREI7_AVX_M64: #define __SSE2_MATH__ 1
+// CHECK_COREI7_AVX_M64: #define __SSE2__ 1
+// CHECK_COREI7_AVX_M64: #define __SSE3__ 1
+// CHECK_COREI7_AVX_M64: #define __SSE4_1__ 1
+// CHECK_COREI7_AVX_M64: #define __SSE4_2__ 1
+// CHECK_COREI7_AVX_M64: #define __SSE_MATH__ 1
+// CHECK_COREI7_AVX_M64: #define __SSE__ 1
+// CHECK_COREI7_AVX_M64: #define __SSSE3__ 1
+// CHECK_COREI7_AVX_M64: #define __amd64 1
+// CHECK_COREI7_AVX_M64: #define __amd64__ 1
+// CHECK_COREI7_AVX_M64: #define __corei7 1
+// CHECK_COREI7_AVX_M64: #define __corei7__ 1
+// CHECK_COREI7_AVX_M64: #define __tune_corei7__ 1
+// CHECK_COREI7_AVX_M64: #define __x86_64 1
+// CHECK_COREI7_AVX_M64: #define __x86_64__ 1
+//
+// RUN: %clang -march=core-avx-i -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_CORE_AVX_I_M32
+// CHECK_CORE_AVX_I_M32: #define __AES__ 1
+// FIXME: AVX is not yet enabled with Clang.
+// CHECK_CORE_AVX_I_M32-NOT: #define __AVX__ 1
+// CHECK_CORE_AVX_I_M32: #define __MMX__ 1
+// CHECK_CORE_AVX_I_M32: #define __SSE2__ 1
+// CHECK_CORE_AVX_I_M32: #define __SSE3__ 1
+// CHECK_CORE_AVX_I_M32: #define __SSE4_1__ 1
+// CHECK_CORE_AVX_I_M32: #define __SSE4_2__ 1
+// CHECK_CORE_AVX_I_M32: #define __SSE__ 1
+// CHECK_CORE_AVX_I_M32: #define __SSSE3__ 1
+// CHECK_CORE_AVX_I_M32: #define __corei7 1
+// CHECK_CORE_AVX_I_M32: #define __corei7__ 1
+// CHECK_CORE_AVX_I_M32: #define __i386 1
+// CHECK_CORE_AVX_I_M32: #define __i386__ 1
+// CHECK_CORE_AVX_I_M32: #define __tune_corei7__ 1
+// CHECK_CORE_AVX_I_M32: #define i386 1
+// RUN: %clang -march=core-avx-i -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_CORE_AVX_I_M64
+// CHECK_CORE_AVX_I_M64: #define __AES__ 1
+// FIXME: AVX is not yet enabled with Clang.
+// CHECK_CORE_AVX_I_M64-NOT: #define __AVX__ 1
+// CHECK_CORE_AVX_I_M64: #define __MMX__ 1
+// CHECK_CORE_AVX_I_M64: #define __SSE2_MATH__ 1
+// CHECK_CORE_AVX_I_M64: #define __SSE2__ 1
+// CHECK_CORE_AVX_I_M64: #define __SSE3__ 1
+// CHECK_CORE_AVX_I_M64: #define __SSE4_1__ 1
+// CHECK_CORE_AVX_I_M64: #define __SSE4_2__ 1
+// CHECK_CORE_AVX_I_M64: #define __SSE_MATH__ 1
+// CHECK_CORE_AVX_I_M64: #define __SSE__ 1
+// CHECK_CORE_AVX_I_M64: #define __SSSE3__ 1
+// CHECK_CORE_AVX_I_M64: #define __amd64 1
+// CHECK_CORE_AVX_I_M64: #define __amd64__ 1
+// CHECK_CORE_AVX_I_M64: #define __corei7 1
+// CHECK_CORE_AVX_I_M64: #define __corei7__ 1
+// CHECK_CORE_AVX_I_M64: #define __tune_corei7__ 1
+// CHECK_CORE_AVX_I_M64: #define __x86_64 1
+// CHECK_CORE_AVX_I_M64: #define __x86_64__ 1
+//
+// RUN: %clang -march=atom -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_ATOM_M32
+// CHECK_ATOM_M32: #define __MMX__ 1
+// CHECK_ATOM_M32: #define __SSE2__ 1
+// CHECK_ATOM_M32: #define __SSE3__ 1
+// CHECK_ATOM_M32: #define __SSE__ 1
+// CHECK_ATOM_M32: #define __SSSE3__ 1
+// CHECK_ATOM_M32: #define __atom 1
+// CHECK_ATOM_M32: #define __atom__ 1
+// CHECK_ATOM_M32: #define __i386 1
+// CHECK_ATOM_M32: #define __i386__ 1
+// CHECK_ATOM_M32: #define __tune_atom__ 1
+// CHECK_ATOM_M32: #define i386 1
+// RUN: %clang -march=atom -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_ATOM_M64
+// CHECK_ATOM_M64: #define __MMX__ 1
+// CHECK_ATOM_M64: #define __SSE2_MATH__ 1
+// CHECK_ATOM_M64: #define __SSE2__ 1
+// CHECK_ATOM_M64: #define __SSE3__ 1
+// CHECK_ATOM_M64: #define __SSE_MATH__ 1
+// CHECK_ATOM_M64: #define __SSE__ 1
+// CHECK_ATOM_M64: #define __SSSE3__ 1
+// CHECK_ATOM_M64: #define __amd64 1
+// CHECK_ATOM_M64: #define __amd64__ 1
+// CHECK_ATOM_M64: #define __atom 1
+// CHECK_ATOM_M64: #define __atom__ 1
+// CHECK_ATOM_M64: #define __tune_atom__ 1
+// CHECK_ATOM_M64: #define __x86_64 1
+// CHECK_ATOM_M64: #define __x86_64__ 1
+//
+// RUN: %clang -march=geode -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_GEODE_M32
+// CHECK_GEODE_M32: #define __3dNOW_A__ 1
+// CHECK_GEODE_M32: #define __3dNOW__ 1
+// CHECK_GEODE_M32: #define __MMX__ 1
+// CHECK_GEODE_M32: #define __geode 1
+// CHECK_GEODE_M32: #define __geode__ 1
+// CHECK_GEODE_M32: #define __i386 1
+// CHECK_GEODE_M32: #define __i386__ 1
+// CHECK_GEODE_M32: #define __tune_geode__ 1
+// CHECK_GEODE_M32: #define i386 1
+// RUN: %clang -march=geode -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_GEODE_M64
+// CHECK_GEODE_M64: error:
+//
+// RUN: %clang -march=k6 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_K6_M32
+// CHECK_K6_M32: #define __MMX__ 1
+// CHECK_K6_M32: #define __i386 1
+// CHECK_K6_M32: #define __i386__ 1
+// CHECK_K6_M32: #define __k6 1
+// CHECK_K6_M32: #define __k6__ 1
+// CHECK_K6_M32: #define __tune_k6__ 1
+// CHECK_K6_M32: #define i386 1
+// RUN: %clang -march=k6 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_K6_M64
+// CHECK_K6_M64: error:
+//
+// RUN: %clang -march=k6-2 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_K6_2_M32
+// CHECK_K6_2_M32: #define __3dNOW__ 1
+// CHECK_K6_2_M32: #define __MMX__ 1
+// CHECK_K6_2_M32: #define __i386 1
+// CHECK_K6_2_M32: #define __i386__ 1
+// CHECK_K6_2_M32: #define __k6 1
+// CHECK_K6_2_M32: #define __k6_2__ 1
+// CHECK_K6_2_M32: #define __k6__ 1
+// CHECK_K6_2_M32: #define __tune_k6_2__ 1
+// CHECK_K6_2_M32: #define __tune_k6__ 1
+// CHECK_K6_2_M32: #define i386 1
+// RUN: %clang -march=k6-2 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_K6_2_M64
+// CHECK_K6_2_M64: error:
+//
+// RUN: %clang -march=k6-3 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_K6_3_M32
+// CHECK_K6_3_M32: #define __3dNOW__ 1
+// CHECK_K6_3_M32: #define __MMX__ 1
+// CHECK_K6_3_M32: #define __i386 1
+// CHECK_K6_3_M32: #define __i386__ 1
+// CHECK_K6_3_M32: #define __k6 1
+// CHECK_K6_3_M32: #define __k6_3__ 1
+// CHECK_K6_3_M32: #define __k6__ 1
+// CHECK_K6_3_M32: #define __tune_k6_3__ 1
+// CHECK_K6_3_M32: #define __tune_k6__ 1
+// CHECK_K6_3_M32: #define i386 1
+// RUN: %clang -march=k6-3 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_K6_3_M64
+// CHECK_K6_3_M64: error:
+//
+// RUN: %clang -march=athlon -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON_M32
+// CHECK_ATHLON_M32: #define __3dNOW_A__ 1
+// CHECK_ATHLON_M32: #define __3dNOW__ 1
+// CHECK_ATHLON_M32: #define __MMX__ 1
+// CHECK_ATHLON_M32: #define __athlon 1
+// CHECK_ATHLON_M32: #define __athlon__ 1
+// CHECK_ATHLON_M32: #define __i386 1
+// CHECK_ATHLON_M32: #define __i386__ 1
+// CHECK_ATHLON_M32: #define __tune_athlon__ 1
+// CHECK_ATHLON_M32: #define i386 1
+// RUN: %clang -march=athlon -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON_M64
+// CHECK_ATHLON_M64: error:
+//
+// RUN: %clang -march=athlon-tbird -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON_TBIRD_M32
+// CHECK_ATHLON_TBIRD_M32: #define __3dNOW_A__ 1
+// CHECK_ATHLON_TBIRD_M32: #define __3dNOW__ 1
+// CHECK_ATHLON_TBIRD_M32: #define __MMX__ 1
+// CHECK_ATHLON_TBIRD_M32: #define __athlon 1
+// CHECK_ATHLON_TBIRD_M32: #define __athlon__ 1
+// CHECK_ATHLON_TBIRD_M32: #define __i386 1
+// CHECK_ATHLON_TBIRD_M32: #define __i386__ 1
+// CHECK_ATHLON_TBIRD_M32: #define __tune_athlon__ 1
+// CHECK_ATHLON_TBIRD_M32: #define i386 1
+// RUN: %clang -march=athlon-tbird -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON_TBIRD_M64
+// CHECK_ATHLON_TBIRD_M64: error:
+//
+// RUN: %clang -march=athlon-4 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON_4_M32
+// CHECK_ATHLON_4_M32: #define __3dNOW_A__ 1
+// CHECK_ATHLON_4_M32: #define __3dNOW__ 1
+// CHECK_ATHLON_4_M32: #define __MMX__ 1
+// CHECK_ATHLON_4_M32: #define __SSE__ 1
+// CHECK_ATHLON_4_M32: #define __athlon 1
+// CHECK_ATHLON_4_M32: #define __athlon__ 1
+// CHECK_ATHLON_4_M32: #define __athlon_sse__ 1
+// CHECK_ATHLON_4_M32: #define __i386 1
+// CHECK_ATHLON_4_M32: #define __i386__ 1
+// CHECK_ATHLON_4_M32: #define __tune_athlon__ 1
+// CHECK_ATHLON_4_M32: #define __tune_athlon_sse__ 1
+// CHECK_ATHLON_4_M32: #define i386 1
+// RUN: %clang -march=athlon-4 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON_4_M64
+// CHECK_ATHLON_4_M64: error:
+//
+// RUN: %clang -march=athlon-xp -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON_XP_M32
+// CHECK_ATHLON_XP_M32: #define __3dNOW_A__ 1
+// CHECK_ATHLON_XP_M32: #define __3dNOW__ 1
+// CHECK_ATHLON_XP_M32: #define __MMX__ 1
+// CHECK_ATHLON_XP_M32: #define __SSE__ 1
+// CHECK_ATHLON_XP_M32: #define __athlon 1
+// CHECK_ATHLON_XP_M32: #define __athlon__ 1
+// CHECK_ATHLON_XP_M32: #define __athlon_sse__ 1
+// CHECK_ATHLON_XP_M32: #define __i386 1
+// CHECK_ATHLON_XP_M32: #define __i386__ 1
+// CHECK_ATHLON_XP_M32: #define __tune_athlon__ 1
+// CHECK_ATHLON_XP_M32: #define __tune_athlon_sse__ 1
+// CHECK_ATHLON_XP_M32: #define i386 1
+// RUN: %clang -march=athlon-xp -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON_XP_M64
+// CHECK_ATHLON_XP_M64: error:
+//
+// RUN: %clang -march=athlon-mp -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON_MP_M32
+// CHECK_ATHLON_MP_M32: #define __3dNOW_A__ 1
+// CHECK_ATHLON_MP_M32: #define __3dNOW__ 1
+// CHECK_ATHLON_MP_M32: #define __MMX__ 1
+// CHECK_ATHLON_MP_M32: #define __SSE__ 1
+// CHECK_ATHLON_MP_M32: #define __athlon 1
+// CHECK_ATHLON_MP_M32: #define __athlon__ 1
+// CHECK_ATHLON_MP_M32: #define __athlon_sse__ 1
+// CHECK_ATHLON_MP_M32: #define __i386 1
+// CHECK_ATHLON_MP_M32: #define __i386__ 1
+// CHECK_ATHLON_MP_M32: #define __tune_athlon__ 1
+// CHECK_ATHLON_MP_M32: #define __tune_athlon_sse__ 1
+// CHECK_ATHLON_MP_M32: #define i386 1
+// RUN: %clang -march=athlon-mp -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON_MP_M64
+// CHECK_ATHLON_MP_M64: error:
+//
+// RUN: %clang -march=x86-64 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_X86_64_M32
+// CHECK_X86_64_M32: #define __MMX__ 1
+// CHECK_X86_64_M32: #define __SSE2__ 1
+// CHECK_X86_64_M32: #define __SSE__ 1
+// CHECK_X86_64_M32: #define __i386 1
+// CHECK_X86_64_M32: #define __i386__ 1
+// CHECK_X86_64_M32: #define __k8 1
+// CHECK_X86_64_M32: #define __k8__ 1
+// CHECK_X86_64_M32: #define i386 1
+// RUN: %clang -march=x86-64 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_X86_64_M64
+// CHECK_X86_64_M64: #define __MMX__ 1
+// CHECK_X86_64_M64: #define __SSE2_MATH__ 1
+// CHECK_X86_64_M64: #define __SSE2__ 1
+// CHECK_X86_64_M64: #define __SSE_MATH__ 1
+// CHECK_X86_64_M64: #define __SSE__ 1
+// CHECK_X86_64_M64: #define __amd64 1
+// CHECK_X86_64_M64: #define __amd64__ 1
+// CHECK_X86_64_M64: #define __k8 1
+// CHECK_X86_64_M64: #define __k8__ 1
+// CHECK_X86_64_M64: #define __x86_64 1
+// CHECK_X86_64_M64: #define __x86_64__ 1
+//
+// RUN: %clang -march=k8 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_K8_M32
+// CHECK_K8_M32: #define __3dNOW_A__ 1
+// CHECK_K8_M32: #define __3dNOW__ 1
+// CHECK_K8_M32: #define __MMX__ 1
+// CHECK_K8_M32: #define __SSE2__ 1
+// CHECK_K8_M32: #define __SSE__ 1
+// CHECK_K8_M32: #define __i386 1
+// CHECK_K8_M32: #define __i386__ 1
+// CHECK_K8_M32: #define __k8 1
+// CHECK_K8_M32: #define __k8__ 1
+// CHECK_K8_M32: #define __tune_k8__ 1
+// CHECK_K8_M32: #define i386 1
+// RUN: %clang -march=k8 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_K8_M64
+// CHECK_K8_M64: #define __3dNOW_A__ 1
+// CHECK_K8_M64: #define __3dNOW__ 1
+// CHECK_K8_M64: #define __MMX__ 1
+// CHECK_K8_M64: #define __SSE2_MATH__ 1
+// CHECK_K8_M64: #define __SSE2__ 1
+// CHECK_K8_M64: #define __SSE_MATH__ 1
+// CHECK_K8_M64: #define __SSE__ 1
+// CHECK_K8_M64: #define __amd64 1
+// CHECK_K8_M64: #define __amd64__ 1
+// CHECK_K8_M64: #define __k8 1
+// CHECK_K8_M64: #define __k8__ 1
+// CHECK_K8_M64: #define __tune_k8__ 1
+// CHECK_K8_M64: #define __x86_64 1
+// CHECK_K8_M64: #define __x86_64__ 1
+//
+// RUN: %clang -march=k8-sse3 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_K8_SSE3_M32
+// CHECK_K8_SSE3_M32: #define __3dNOW_A__ 1
+// CHECK_K8_SSE3_M32: #define __3dNOW__ 1
+// CHECK_K8_SSE3_M32: #define __MMX__ 1
+// CHECK_K8_SSE3_M32: #define __SSE2__ 1
+// CHECK_K8_SSE3_M32: #define __SSE3__ 1
+// CHECK_K8_SSE3_M32: #define __SSE__ 1
+// CHECK_K8_SSE3_M32: #define __i386 1
+// CHECK_K8_SSE3_M32: #define __i386__ 1
+// CHECK_K8_SSE3_M32: #define __k8 1
+// CHECK_K8_SSE3_M32: #define __k8__ 1
+// CHECK_K8_SSE3_M32: #define __tune_k8__ 1
+// CHECK_K8_SSE3_M32: #define i386 1
+// RUN: %clang -march=k8-sse3 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_K8_SSE3_M64
+// CHECK_K8_SSE3_M64: #define __3dNOW_A__ 1
+// CHECK_K8_SSE3_M64: #define __3dNOW__ 1
+// CHECK_K8_SSE3_M64: #define __MMX__ 1
+// CHECK_K8_SSE3_M64: #define __SSE2_MATH__ 1
+// CHECK_K8_SSE3_M64: #define __SSE2__ 1
+// CHECK_K8_SSE3_M64: #define __SSE3__ 1
+// CHECK_K8_SSE3_M64: #define __SSE_MATH__ 1
+// CHECK_K8_SSE3_M64: #define __SSE__ 1
+// CHECK_K8_SSE3_M64: #define __amd64 1
+// CHECK_K8_SSE3_M64: #define __amd64__ 1
+// CHECK_K8_SSE3_M64: #define __k8 1
+// CHECK_K8_SSE3_M64: #define __k8__ 1
+// CHECK_K8_SSE3_M64: #define __tune_k8__ 1
+// CHECK_K8_SSE3_M64: #define __x86_64 1
+// CHECK_K8_SSE3_M64: #define __x86_64__ 1
+//
+// RUN: %clang -march=opteron -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_OPTERON_M32
+// CHECK_OPTERON_M32: #define __3dNOW_A__ 1
+// CHECK_OPTERON_M32: #define __3dNOW__ 1
+// CHECK_OPTERON_M32: #define __MMX__ 1
+// CHECK_OPTERON_M32: #define __SSE2__ 1
+// CHECK_OPTERON_M32: #define __SSE__ 1
+// CHECK_OPTERON_M32: #define __i386 1
+// CHECK_OPTERON_M32: #define __i386__ 1
+// CHECK_OPTERON_M32: #define __k8 1
+// CHECK_OPTERON_M32: #define __k8__ 1
+// CHECK_OPTERON_M32: #define __tune_k8__ 1
+// CHECK_OPTERON_M32: #define i386 1
+// RUN: %clang -march=opteron -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_OPTERON_M64
+// CHECK_OPTERON_M64: #define __3dNOW_A__ 1
+// CHECK_OPTERON_M64: #define __3dNOW__ 1
+// CHECK_OPTERON_M64: #define __MMX__ 1
+// CHECK_OPTERON_M64: #define __SSE2_MATH__ 1
+// CHECK_OPTERON_M64: #define __SSE2__ 1
+// CHECK_OPTERON_M64: #define __SSE_MATH__ 1
+// CHECK_OPTERON_M64: #define __SSE__ 1
+// CHECK_OPTERON_M64: #define __amd64 1
+// CHECK_OPTERON_M64: #define __amd64__ 1
+// CHECK_OPTERON_M64: #define __k8 1
+// CHECK_OPTERON_M64: #define __k8__ 1
+// CHECK_OPTERON_M64: #define __tune_k8__ 1
+// CHECK_OPTERON_M64: #define __x86_64 1
+// CHECK_OPTERON_M64: #define __x86_64__ 1
+//
+// RUN: %clang -march=opteron-sse3 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_OPTERON_SSE3_M32
+// CHECK_OPTERON_SSE3_M32: #define __3dNOW_A__ 1
+// CHECK_OPTERON_SSE3_M32: #define __3dNOW__ 1
+// CHECK_OPTERON_SSE3_M32: #define __MMX__ 1
+// CHECK_OPTERON_SSE3_M32: #define __SSE2__ 1
+// CHECK_OPTERON_SSE3_M32: #define __SSE3__ 1
+// CHECK_OPTERON_SSE3_M32: #define __SSE__ 1
+// CHECK_OPTERON_SSE3_M32: #define __i386 1
+// CHECK_OPTERON_SSE3_M32: #define __i386__ 1
+// CHECK_OPTERON_SSE3_M32: #define __k8 1
+// CHECK_OPTERON_SSE3_M32: #define __k8__ 1
+// CHECK_OPTERON_SSE3_M32: #define __tune_k8__ 1
+// CHECK_OPTERON_SSE3_M32: #define i386 1
+// RUN: %clang -march=opteron-sse3 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_OPTERON_SSE3_M64
+// CHECK_OPTERON_SSE3_M64: #define __3dNOW_A__ 1
+// CHECK_OPTERON_SSE3_M64: #define __3dNOW__ 1
+// CHECK_OPTERON_SSE3_M64: #define __MMX__ 1
+// CHECK_OPTERON_SSE3_M64: #define __SSE2_MATH__ 1
+// CHECK_OPTERON_SSE3_M64: #define __SSE2__ 1
+// CHECK_OPTERON_SSE3_M64: #define __SSE3__ 1
+// CHECK_OPTERON_SSE3_M64: #define __SSE_MATH__ 1
+// CHECK_OPTERON_SSE3_M64: #define __SSE__ 1
+// CHECK_OPTERON_SSE3_M64: #define __amd64 1
+// CHECK_OPTERON_SSE3_M64: #define __amd64__ 1
+// CHECK_OPTERON_SSE3_M64: #define __k8 1
+// CHECK_OPTERON_SSE3_M64: #define __k8__ 1
+// CHECK_OPTERON_SSE3_M64: #define __tune_k8__ 1
+// CHECK_OPTERON_SSE3_M64: #define __x86_64 1
+// CHECK_OPTERON_SSE3_M64: #define __x86_64__ 1
+//
+// RUN: %clang -march=athlon64 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON64_M32
+// CHECK_ATHLON64_M32: #define __3dNOW_A__ 1
+// CHECK_ATHLON64_M32: #define __3dNOW__ 1
+// CHECK_ATHLON64_M32: #define __MMX__ 1
+// CHECK_ATHLON64_M32: #define __SSE2__ 1
+// CHECK_ATHLON64_M32: #define __SSE__ 1
+// CHECK_ATHLON64_M32: #define __i386 1
+// CHECK_ATHLON64_M32: #define __i386__ 1
+// CHECK_ATHLON64_M32: #define __k8 1
+// CHECK_ATHLON64_M32: #define __k8__ 1
+// CHECK_ATHLON64_M32: #define __tune_k8__ 1
+// CHECK_ATHLON64_M32: #define i386 1
+// RUN: %clang -march=athlon64 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON64_M64
+// CHECK_ATHLON64_M64: #define __3dNOW_A__ 1
+// CHECK_ATHLON64_M64: #define __3dNOW__ 1
+// CHECK_ATHLON64_M64: #define __MMX__ 1
+// CHECK_ATHLON64_M64: #define __SSE2_MATH__ 1
+// CHECK_ATHLON64_M64: #define __SSE2__ 1
+// CHECK_ATHLON64_M64: #define __SSE_MATH__ 1
+// CHECK_ATHLON64_M64: #define __SSE__ 1
+// CHECK_ATHLON64_M64: #define __amd64 1
+// CHECK_ATHLON64_M64: #define __amd64__ 1
+// CHECK_ATHLON64_M64: #define __k8 1
+// CHECK_ATHLON64_M64: #define __k8__ 1
+// CHECK_ATHLON64_M64: #define __tune_k8__ 1
+// CHECK_ATHLON64_M64: #define __x86_64 1
+// CHECK_ATHLON64_M64: #define __x86_64__ 1
+//
+// RUN: %clang -march=athlon64-sse3 -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON64_SSE3_M32
+// CHECK_ATHLON64_SSE3_M32: #define __3dNOW_A__ 1
+// CHECK_ATHLON64_SSE3_M32: #define __3dNOW__ 1
+// CHECK_ATHLON64_SSE3_M32: #define __MMX__ 1
+// CHECK_ATHLON64_SSE3_M32: #define __SSE2__ 1
+// CHECK_ATHLON64_SSE3_M32: #define __SSE3__ 1
+// CHECK_ATHLON64_SSE3_M32: #define __SSE__ 1
+// CHECK_ATHLON64_SSE3_M32: #define __i386 1
+// CHECK_ATHLON64_SSE3_M32: #define __i386__ 1
+// CHECK_ATHLON64_SSE3_M32: #define __k8 1
+// CHECK_ATHLON64_SSE3_M32: #define __k8__ 1
+// CHECK_ATHLON64_SSE3_M32: #define __tune_k8__ 1
+// CHECK_ATHLON64_SSE3_M32: #define i386 1
+// RUN: %clang -march=athlon64-sse3 -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON64_SSE3_M64
+// CHECK_ATHLON64_SSE3_M64: #define __3dNOW_A__ 1
+// CHECK_ATHLON64_SSE3_M64: #define __3dNOW__ 1
+// CHECK_ATHLON64_SSE3_M64: #define __MMX__ 1
+// CHECK_ATHLON64_SSE3_M64: #define __SSE2_MATH__ 1
+// CHECK_ATHLON64_SSE3_M64: #define __SSE2__ 1
+// CHECK_ATHLON64_SSE3_M64: #define __SSE3__ 1
+// CHECK_ATHLON64_SSE3_M64: #define __SSE_MATH__ 1
+// CHECK_ATHLON64_SSE3_M64: #define __SSE__ 1
+// CHECK_ATHLON64_SSE3_M64: #define __amd64 1
+// CHECK_ATHLON64_SSE3_M64: #define __amd64__ 1
+// CHECK_ATHLON64_SSE3_M64: #define __k8 1
+// CHECK_ATHLON64_SSE3_M64: #define __k8__ 1
+// CHECK_ATHLON64_SSE3_M64: #define __tune_k8__ 1
+// CHECK_ATHLON64_SSE3_M64: #define __x86_64 1
+// CHECK_ATHLON64_SSE3_M64: #define __x86_64__ 1
+//
+// RUN: %clang -march=athlon-fx -m32 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON_FX_M32
+// CHECK_ATHLON_FX_M32: #define __3dNOW_A__ 1
+// CHECK_ATHLON_FX_M32: #define __3dNOW__ 1
+// CHECK_ATHLON_FX_M32: #define __MMX__ 1
+// CHECK_ATHLON_FX_M32: #define __SSE2__ 1
+// CHECK_ATHLON_FX_M32: #define __SSE__ 1
+// CHECK_ATHLON_FX_M32: #define __i386 1
+// CHECK_ATHLON_FX_M32: #define __i386__ 1
+// CHECK_ATHLON_FX_M32: #define __k8 1
+// CHECK_ATHLON_FX_M32: #define __k8__ 1
+// CHECK_ATHLON_FX_M32: #define __tune_k8__ 1
+// CHECK_ATHLON_FX_M32: #define i386 1
+// RUN: %clang -march=athlon-fx -m64 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK_ATHLON_FX_M64
+// CHECK_ATHLON_FX_M64: #define __3dNOW_A__ 1
+// CHECK_ATHLON_FX_M64: #define __3dNOW__ 1
+// CHECK_ATHLON_FX_M64: #define __MMX__ 1
+// CHECK_ATHLON_FX_M64: #define __SSE2_MATH__ 1
+// CHECK_ATHLON_FX_M64: #define __SSE2__ 1
+// CHECK_ATHLON_FX_M64: #define __SSE_MATH__ 1
+// CHECK_ATHLON_FX_M64: #define __SSE__ 1
+// CHECK_ATHLON_FX_M64: #define __amd64 1
+// CHECK_ATHLON_FX_M64: #define __amd64__ 1
+// CHECK_ATHLON_FX_M64: #define __k8 1
+// CHECK_ATHLON_FX_M64: #define __k8__ 1
+// CHECK_ATHLON_FX_M64: #define __tune_k8__ 1
+// CHECK_ATHLON_FX_M64: #define __x86_64 1
+// CHECK_ATHLON_FX_M64: #define __x86_64__ 1
+//
+// End X86/GCC/Linux tests ------------------
diff --git a/test/Preprocessor/predefined-exceptions.m b/test/Preprocessor/predefined-exceptions.m
new file mode 100644
index 000000000000..c13f429e3763
--- /dev/null
+++ b/test/Preprocessor/predefined-exceptions.m
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -x objective-c -fobjc-exceptions -fexceptions -E -dM %s | FileCheck -check-prefix=CHECK-OBJC-NOCXX %s
+// CHECK-OBJC-NOCXX: #define OBJC_ZEROCOST_EXCEPTIONS 1
+// CHECK-OBJC-NOCXX-NOT: #define __EXCEPTIONS 1
+
+// RUN: %clang_cc1 -x objective-c++ -fobjc-exceptions -fexceptions -fcxx-exceptions -E -dM %s | FileCheck -check-prefix=CHECK-OBJC-CXX %s
+// CHECK-OBJC-CXX: #define OBJC_ZEROCOST_EXCEPTIONS 1
+// CHECK-OBJC-CXX: #define __EXCEPTIONS 1
+
+// RUN: %clang_cc1 -x objective-c++ -fexceptions -fcxx-exceptions -E -dM %s | FileCheck -check-prefix=CHECK-NOOBJC-CXX %s
+// CHECK-NOOBJC-CXX-NOT: #define OBJC_ZEROCOST_EXCEPTIONS 1
+// CHECK-NOOBJC-CXX: #define __EXCEPTIONS 1
+
+// RUN: %clang_cc1 -x objective-c -E -dM %s | FileCheck -check-prefix=CHECK-NOOBJC-NOCXX %s
+// CHECK-NOOBJC-NOCXX-NOT: #define OBJC_ZEROCOST_EXCEPTIONS 1
+// CHECK-NOOBJC-NOCXX-NOT: #define __EXCEPTIONS 1
diff --git a/test/Preprocessor/warning_tests.c b/test/Preprocessor/warning_tests.c
new file mode 100644
index 000000000000..96b96efc7e69
--- /dev/null
+++ b/test/Preprocessor/warning_tests.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsyntax-only %s -verify
+#ifndef __has_warning
+#error Should have __has_warning
+#endif
+
+#if __has_warning("not valid") // expected-warning {{__has_warning expected option name}}
+#endif
+
+#if __has_warning("-Wparentheses")
+#warning Should have -Wparentheses // expected-warning {{Should have -Wparentheses}}
+#endif
+
+#if __has_warning(-Wfoo) // expected-error {{builtin warning check macro requires a parenthesized string}}
+#endif
+
+#if __has_warning("-Wnot-a-valid-warning-flag-at-all")
+#else
+#warning Not a valid warning flag // expected-warning {{Not a valid warning flag}}
+#endif \ No newline at end of file
diff --git a/test/Rewriter/inner-block-helper-funcs.mm b/test/Rewriter/inner-block-helper-funcs.mm
new file mode 100644
index 000000000000..33567bc3d7aa
--- /dev/null
+++ b/test/Rewriter/inner-block-helper-funcs.mm
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
+// rdar://9846759
+
+typedef void (^dispatch_block_t)(void);
+
+extern int printf(const char*, ...);
+
+extern "C" dispatch_block_t Block_copy(dispatch_block_t aBlock);
+
+int main (int argc, char *argv[]) {
+
+ dispatch_block_t innerBlock = ^{printf("argc = %d\n", argc); };
+ id innerObject = 0;
+
+ printf("innerBlock is %x\n", innerBlock);
+
+ dispatch_block_t wrapperBlock = ^{
+ printf("innerBlock is %x %x\n", innerBlock, innerObject);
+ };
+
+ wrapperBlock();
+
+ dispatch_block_t copiedBlock = Block_copy(wrapperBlock);
+ copiedBlock();
+
+ return 0;
+}
+// CHECK-LP: _Block_object_assign((void*)&dst->innerBlock, (void*)src->innerBlock, 7
+// CHECK-LP: _Block_object_dispose((void*)src->innerBlock, 7
+// CHECK-LP: _Block_object_assign((void*)&dst->innerObject, (void*)src->innerObject, 3
+// CHECK-LP: _Block_object_dispose((void*)src->innerObject, 3
diff --git a/test/Rewriter/instancetype-test.mm b/test/Rewriter/instancetype-test.mm
new file mode 100644
index 000000000000..97fbe0950da5
--- /dev/null
+++ b/test/Rewriter/instancetype-test.mm
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+
+void *sel_registerName(const char *);
+
+@interface Root
++ (instancetype)alloc;
+- (instancetype)init; // expected-note{{overridden method is part of the 'init' method family}}
+- (instancetype)self;
+- (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
+ [[Subclass1<Proto1> alloc] methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
+ [[Subclass1<Proto2> 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
+ // Message sends to Class.
+ // FIXME. This is not supported due to missing capability in rewriter and not due to instancetype issues
+ // 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];
+
+ [sc1proto1.selfProp methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
+ [sc1proto2.selfProp methodInProto2];
+}
diff --git a/test/Rewriter/protocol-rewrite-2.m b/test/Rewriter/protocol-rewrite-2.m
new file mode 100644
index 000000000000..b3eb16a5f119
--- /dev/null
+++ b/test/Rewriter/protocol-rewrite-2.m
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -rewrite-objc %s -o %t.cpp
+// RUN: %clang_cc1 -fsyntax-only %t.cpp
+
+// rdar://10234024
+@protocol Foo;
+@protocol Foo
+@end
diff --git a/test/Rewriter/rewrite-cast-to-bool.mm b/test/Rewriter/rewrite-cast-to-bool.mm
new file mode 100644
index 000000000000..0e9f3640fb39
--- /dev/null
+++ b/test/Rewriter/rewrite-cast-to-bool.mm
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+// radar 9899834
+
+void *sel_registerName(const char *);
+
+@interface NSURLDownload
+-(void)setBool:(bool)Arg;
+@end
+
+@implementation NSURLDownload
+- (void) Meth
+{
+ [self setBool:(signed char)1];
+}
+@end
+
diff --git a/test/Rewriter/rewrite-foreach-in-block.mm b/test/Rewriter/rewrite-foreach-in-block.mm
new file mode 100644
index 000000000000..971330c6bfe9
--- /dev/null
+++ b/test/Rewriter/rewrite-foreach-in-block.mm
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+// rdar:// 9878420
+
+void objc_enumerationMutation(id);
+void *sel_registerName(const char *);
+typedef void (^CoreDAVCompletionBlock)(void);
+
+@interface I
+- (void)M;
+- (id) ARR;
+@property (readwrite, copy, nonatomic) CoreDAVCompletionBlock c;
+@end
+
+@implementation I
+- (void)M {
+ I* ace;
+ self.c = ^() {
+ // sanity test for the changes.
+ [ace ARR];
+ for (I *privilege in [ace ARR]) { }
+ };
+ self.c = ^() {
+ // sanity test for the changes.
+ [ace ARR];
+ };
+}
+@end
diff --git a/test/Rewriter/rewrite-forward-class.m b/test/Rewriter/rewrite-forward-class.m
index 5a50f53a480f..1d3af6f366c3 100644
--- a/test/Rewriter/rewrite-forward-class.m
+++ b/test/Rewriter/rewrite-forward-class.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -rewrite-objc -o - %s
+// RUN: %clang_cc1 -x objective-c -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
// rdar://6969189
@class XX;
@@ -6,3 +7,29 @@
@class ISyncClient, SMSession, ISyncManager, ISyncSession, SMDataclassInfo, SMClientInfo,
DMCConfiguration, DMCStatusEntry;
+@interface QQ
+
+@end
+
+@interface SMDataclassInfo : QQ
+- (XX*) Meth;
+- (DMCStatusEntry*)Meth2;
+@end
+
+@implementation SMDataclassInfo
+- (XX*) Meth { return 0; }
+- (DMCStatusEntry*)Meth2 { return 0; }
+@end
+
+@interface YY
+{
+ ISyncClient *p1;
+ ISyncSession *p2;
+}
+@property (copy) ISyncClient *p1;
+@end
+
+@implementation YY
+@synthesize p1;
+@end
+
diff --git a/test/Rewriter/rewrite-forward-class.mm b/test/Rewriter/rewrite-forward-class.mm
new file mode 100644
index 000000000000..74c0508fc78a
--- /dev/null
+++ b/test/Rewriter/rewrite-forward-class.mm
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+
+extern "C" {
+@class XX;
+@class YY, ZZ, QQ;
+@class ISyncClient, SMSession, ISyncManager, ISyncSession, SMDataclassInfo, SMClientInfo,
+ DMCConfiguration, DMCStatusEntry;
+
+@interface QQ
+
+@end
+
+@interface SMDataclassInfo : QQ
+- (XX*) Meth;
+- (DMCStatusEntry*)Meth2;
+@end
+
+@implementation SMDataclassInfo
+- (XX*) Meth { return 0; }
+- (DMCStatusEntry*)Meth2 { return 0; }
+@end
+
+@interface YY
+{
+ ISyncClient *p1;
+ ISyncSession *p2;
+}
+@property (copy) ISyncClient *p1;
+@end
+
+@implementation YY
+@synthesize p1;
+@end
+
+extern "C" {
+@class CCC;
+@class Protocol, P , Q;
+int I,J,K;
+};
+
+};
+
+
diff --git a/test/Sema/2007-10-01-BuildArrayRef.c b/test/Sema/2007-10-01-BuildArrayRef.c
new file mode 100644
index 000000000000..4692731b5c25
--- /dev/null
+++ b/test/Sema/2007-10-01-BuildArrayRef.c
@@ -0,0 +1,20 @@
+// RUN: not %clang_cc1_only -c %s -o - > /dev/null
+// PR 1603
+void func()
+{
+ const int *arr;
+ arr[0] = 1; // expected-error {{assignment of read-only location}}
+}
+
+struct foo {
+ int bar;
+};
+struct foo sfoo = { 0 };
+
+int func2()
+{
+ const struct foo *fp;
+ fp = &sfoo;
+ fp[0].bar = 1; // expected-error {{ assignment of read-only member}}
+ return sfoo.bar;
+}
diff --git a/test/Sema/2009-03-09-WeakDeclarations-1.c b/test/Sema/2009-03-09-WeakDeclarations-1.c
new file mode 100644
index 000000000000..f219de6b848f
--- /dev/null
+++ b/test/Sema/2009-03-09-WeakDeclarations-1.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -triple i686-apple-darwin
+// Insist upon warnings for inappropriate weak attributes.
+
+// O.K.
+extern int ext_weak_import __attribute__ ((__weak_import__));
+
+// These are inappropriate, and should generate warnings:
+int decl_weak_import __attribute__ ((__weak_import__)); // expected-warning {'weak_import' attribute cannot be specified on a definition}
+int decl_initialized_weak_import __attribute__ ((__weak_import__)) = 13; // expected-warning {'weak_import' attribute cannot be specified on a definition}
+
+// O.K.
+extern int ext_f(void) __attribute__ ((__weak_import__));
+
+// These are inappropriate, and should generate warnings:
+int def_f(void) __attribute__ ((__weak_import__));
+int __attribute__ ((__weak_import__)) decl_f(void) {return 0;};
diff --git a/test/Sema/2009-04-22-UnknownSize.c b/test/Sema/2009-04-22-UnknownSize.c
new file mode 100644
index 000000000000..9f717408b5ea
--- /dev/null
+++ b/test/Sema/2009-04-22-UnknownSize.c
@@ -0,0 +1,4 @@
+// RUN: not %clang_cc1 %s -emit-llvm -o -
+// PR2958
+static struct foo s; // expected-error { tentative definition has type 'struct foo' that is never completed }
+struct foo *p = &s;
diff --git a/test/Sema/2009-07-17-VoidParameter.c b/test/Sema/2009-07-17-VoidParameter.c
new file mode 100644
index 000000000000..68d1b1ec33ad
--- /dev/null
+++ b/test/Sema/2009-07-17-VoidParameter.c
@@ -0,0 +1,4 @@
+// RUN: not %clang_cc1 -emit-llvm %s -o -
+// PR4214
+typedef void vt;
+void (*func_ptr)(vt my_vt); // expected-error {argument may not have 'void' type}
diff --git a/test/Sema/2010-05-31-palignr.c b/test/Sema/2010-05-31-palignr.c
new file mode 100644
index 000000000000..12be29af95c0
--- /dev/null
+++ b/test/Sema/2010-05-31-palignr.c
@@ -0,0 +1,22 @@
+// RUN: not %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o /dev/null %s
+
+#include <tmmintrin.h>
+
+extern int i;
+
+int main ()
+{
+#if defined( __SSSE3__ )
+
+ typedef int16_t vSInt16 __attribute__ ((__vector_size__ (16)));
+
+ short dtbl[] = {1,2,3,4,5,6,7,8};
+ vSInt16 *vdtbl = (vSInt16*) dtbl;
+
+ vSInt16 v0;
+ v0 = *vdtbl;
+ v0 = _mm_alignr_epi8(v0, v0, i); // expected-error {{argument to '__builtin_ia32_palignr128' must be a constant integer}}
+
+ return 0;
+#endif
+}
diff --git a/test/Sema/Inputs/pragma-arc-cf-code-audited.h b/test/Sema/Inputs/pragma-arc-cf-code-audited.h
new file mode 100644
index 000000000000..6ea360c34bb5
--- /dev/null
+++ b/test/Sema/Inputs/pragma-arc-cf-code-audited.h
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#pragma clang arc_cf_code_audited begin
diff --git a/test/Sema/address_spaces.c b/test/Sema/address_spaces.c
index a53bb4da0003..24799daa9e50 100644
--- a/test/Sema/address_spaces.c
+++ b/test/Sema/address_spaces.c
@@ -44,3 +44,7 @@ void test3(void) {
extern void test3_helper(char *p); // expected-note {{passing argument to parameter 'p' here}}
test3_helper(test3_array); // expected-error {{changes address space of pointer}}
}
+
+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}}
diff --git a/test/Sema/alignas.c b/test/Sema/alignas.c
new file mode 100644
index 000000000000..5832393e3b61
--- /dev/null
+++ b/test/Sema/alignas.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c1x %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) unsigned _Alignas(8) int _Alignas(1) align_multiple;
+
+struct align_member {
+ _Alignas(8) int member;
+};
+
+typedef _Alignas(8) char align_typedef; // FIXME: this should be rejected
+
+_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/annotate.c b/test/Sema/annotate.c
index 6f81491f1ffa..5b2727752bbd 100644
--- a/test/Sema/annotate.c
+++ b/test/Sema/annotate.c
@@ -4,4 +4,7 @@ void __attribute__((annotate("foo"))) foo(float *a) {
__attribute__((annotate("bar"))) int x;
__attribute__((annotate(1))) int y; // expected-error {{argument to annotate attribute was not a string literal}}
__attribute__((annotate("bar", 1))) int z; // expected-error {{attribute takes one argument}}
+ int u = __builtin_annotation(z, (char*) 0); // expected-error {{__builtin_annotation requires a non wide string constant}}
+ int v = __builtin_annotation(z, (char*) L"bar"); // expected-error {{__builtin_annotation requires a non wide string constant}}
+ int w = __builtin_annotation(z, "foo");
}
diff --git a/test/Sema/array-bounds-ptr-arith.c b/test/Sema/array-bounds-ptr-arith.c
new file mode 100644
index 000000000000..c0e0d0ea785d
--- /dev/null
+++ b/test/Sema/array-bounds-ptr-arith.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -verify -Warray-bounds-pointer-arithmetic %s
+
+// Test case from PR10615
+struct ext2_super_block{
+ unsigned char s_uuid[8]; // expected-note {{declared here}}
+};
+void* ext2_statfs (struct ext2_super_block *es,int a)
+{
+ return (void *)es->s_uuid + sizeof(int); // no-warning
+}
+void* broken (struct ext2_super_block *es,int a)
+{
+ return (void *)es->s_uuid + 80; // expected-warning {{refers past the end of the array}}
+}
diff --git a/test/Sema/array-init.c b/test/Sema/array-init.c
index 345ab6981b17..bc958c3eea60 100644
--- a/test/Sema/array-init.c
+++ b/test/Sema/array-init.c
@@ -53,7 +53,7 @@ void func() {
void test() {
int y1[3] = {
- { 1, 2, 3 } // expected-warning{{braces around scalar initializer}} expected-warning{{excess elements in scalar initializer}}
+ { 1, 2, 3 } // expected-warning{{excess elements in scalar initializer}}
};
int y3[4][3] = {
{ 1, 3, 5 },
diff --git a/test/Sema/atomic-ops.c b/test/Sema/atomic-ops.c
new file mode 100644
index 000000000000..51b46bd5d0ea
--- /dev/null
+++ b/test/Sema/atomic-ops.c
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+
+// Basic parsing/Sema tests for __atomic_*
+
+// FIXME: Need to implement __atomic_is_lock_free
+
+typedef enum memory_order {
+ memory_order_relaxed, memory_order_consume, memory_order_acquire,
+ memory_order_release, memory_order_acq_rel, memory_order_seq_cst
+} memory_order;
+
+void f(_Atomic(int) *i, _Atomic(int*) *p, _Atomic(float) *d) {
+ __atomic_load(0); // expected-error {{too few arguments to function}}
+ __atomic_load(0,0,0); // expected-error {{too many arguments to function}}
+ __atomic_store(0,0,0); // expected-error {{first argument to atomic operation}}
+ __atomic_store((int*)0,0,0); // expected-error {{first argument to atomic operation}}
+
+ __atomic_load(i, memory_order_seq_cst);
+ __atomic_load(p, memory_order_seq_cst);
+ __atomic_load(d, memory_order_seq_cst);
+
+ __atomic_store(i, 1, memory_order_seq_cst);
+ __atomic_store(p, 1, memory_order_seq_cst); // expected-warning {{incompatible integer to pointer conversion}}
+ (int)__atomic_store(d, 1, memory_order_seq_cst); // expected-error {{operand of type 'void'}}
+
+ __atomic_fetch_add(i, 1, memory_order_seq_cst);
+ __atomic_fetch_add(p, 1, memory_order_seq_cst);
+ __atomic_fetch_add(d, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer or pointer}}
+
+ __atomic_fetch_and(i, 1, memory_order_seq_cst);
+ __atomic_fetch_and(p, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer}}
+ __atomic_fetch_and(d, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer}}
+
+ __atomic_compare_exchange_strong(i, 0, 1, memory_order_seq_cst, memory_order_seq_cst);
+ __atomic_compare_exchange_strong(p, 0, (int*)1, memory_order_seq_cst, memory_order_seq_cst);
+ __atomic_compare_exchange_strong(d, (int*)0, 1, memory_order_seq_cst, memory_order_seq_cst); // expected-warning {{incompatible pointer types}}
+}
diff --git a/test/Sema/atomic-type.c b/test/Sema/atomic-type.c
new file mode 100644
index 000000000000..8e725403ae90
--- /dev/null
+++ b/test/Sema/atomic-type.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+
+// Basic parsing/Sema tests for _Atomic
+// No operations are actually supported on objects of this type yet.
+// The qualifier syntax is not supported yet.
+_Atomic(int) t1;
+_Atomic(int) *t2 = &t1;
+void testf(void*);
+void f(void) {
+ _Atomic(_Atomic(int)*) t3;
+ _Atomic(_Atomic(int)*) *t4[2] = { &t3, 0 };
+ testf(t4);
+}
+extern _Atomic(int (*)(int(*)[], int(*)[10])) mergetest;
+extern _Atomic(int (*)(int(*)[10], int(*)[])) mergetest;
+extern _Atomic(int (*)(int(*)[10], int(*)[10])) mergetest;
+
+_Atomic(int()) error1; // expected-error {{_Atomic cannot be applied to function type}}
+_Atomic(struct ErrorS) error2; // expected-error {{_Atomic cannot be applied to incomplete type}}
+_Atomic(int[10]) error3; // expected-error {{_Atomic cannot be applied to array type}}
+_Atomic(const int) error4; // expected-error {{_Atomic cannot be applied to qualified type}}
+_Atomic(_Atomic(int)) error5; // expected-error {{_Atomic cannot be applied to atomic type}}
diff --git a/test/Sema/attr-availability.c b/test/Sema/attr-availability.c
index 1314cf5a5b03..f6ed13190ed8 100644
--- a/test/Sema/attr-availability.c
+++ b/test/Sema/attr-availability.c
@@ -2,5 +2,6 @@
void f0() __attribute__((availability(macosx,introduced=10.4,deprecated=10.2))); // expected-warning{{feature cannot be deprecated in Mac OS X version 10.2 before it was introduced in version 10.4; attribute ignored}}
void f1() __attribute__((availability(ios,obsoleted=2.1,deprecated=3.0))); // expected-warning{{feature cannot be obsoleted in iOS version 2.1 before it was deprecated in version 3.0; attribute ignored}}
+void f2() __attribute__((availability(ios,introduced=2.1,deprecated=2.1)));
-void f2() __attribute__((availability(otheros,introduced=2.2))); // expected-warning{{unknown platform 'otheros' in availability macro}}
+void f3() __attribute__((availability(otheros,introduced=2.2))); // expected-warning{{unknown platform 'otheros' in availability macro}}
diff --git a/test/Sema/attr-deprecated.c b/test/Sema/attr-deprecated.c
index eeef0d757a70..2889f8fa1146 100644
--- a/test/Sema/attr-deprecated.c
+++ b/test/Sema/attr-deprecated.c
@@ -109,7 +109,7 @@ enum __attribute__((deprecated)) Test20 {
void test20() {
enum Test20 f; // expected-warning {{'Test20' is deprecated}}
f = test20_a; // expected-warning {{'test20_a' is deprecated}}
- f = test20_b;
+ f = test20_b; // expected-warning {{'Test20' is deprecated}}
}
char test21[__has_feature(attribute_deprecated_with_message) ? 1 : -1];
diff --git a/test/Sema/attr-returns-twice.c b/test/Sema/attr-returns-twice.c
new file mode 100644
index 000000000000..13f53e36de79
--- /dev/null
+++ b/test/Sema/attr-returns-twice.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+
+int a __attribute__((returns_twice)); // expected-warning {{'returns_twice' attribute only applies to functions}}
+
+__attribute__((returns_twice)) void t0(void) {
+}
+
+void t1() __attribute__((returns_twice));
+
+void t2() __attribute__((returns_twice(2))); // expected-error {{attribute takes no arguments}}
+
+typedef void (*t3)(void) __attribute__((returns_twice)); // expected-warning {{'returns_twice' attribute only applies to functions}}
diff --git a/test/Sema/attr-sentinel.c b/test/Sema/attr-sentinel.c
index 5ca6a8d00113..abc108fdc785 100644
--- a/test/Sema/attr-sentinel.c
+++ b/test/Sema/attr-sentinel.c
@@ -4,13 +4,15 @@
#define ATTR __attribute__ ((__sentinel__))
-void foo1 (int x, ...) ATTR; // expected-note 2 {{function has been explicitly marked sentinel here}}
+void foo1 (int x, ...) ATTR; // expected-note 3 {{function has been explicitly marked sentinel here}}
void foo5 (int x, ...) __attribute__ ((__sentinel__(1))); // expected-note {{function has been explicitly marked sentinel here}}
void foo6 (int x, ...) __attribute__ ((__sentinel__(5))); // expected-note {{function has been explicitly marked sentinel here}}
void foo7 (int x, ...) __attribute__ ((__sentinel__(0))); // expected-note {{function has been explicitly marked sentinel here}}
void foo10 (int x, ...) __attribute__ ((__sentinel__(1,1)));
void foo12 (int x, ... ) ATTR; // expected-note {{function has been explicitly marked sentinel here}}
+#define FOOMACRO(...) foo1(__VA_ARGS__)
+
void test1() {
foo1(1, NULL); // OK
foo1(1, 0) ; // expected-warning {{missing sentinel in function call}}
@@ -30,6 +32,9 @@ void test1() {
struct A a, b, c;
foo1(3, &a, &b, &c); // expected-warning {{missing sentinel in function call}}
foo1(3, &a, &b, &c, (struct A*) 0);
+
+ // PR11002
+ FOOMACRO(1, 2); // expected-warning {{missing sentinel in function call}}
}
diff --git a/test/Sema/attr-unavailable-message.c b/test/Sema/attr-unavailable-message.c
index 9f663fc4efd4..9b0c3debd8a7 100644
--- a/test/Sema/attr-unavailable-message.c
+++ b/test/Sema/attr-unavailable-message.c
@@ -26,3 +26,24 @@ void unavail(void) {
void (*fp)() = &bar;
double (*fp4)(double) = dfoo;
}
+
+// rdar://10201690
+enum foo {
+ a = 1,
+ b __attribute__((deprecated())) = 2,
+ c = 3
+}__attribute__((deprecated()));
+
+enum fee { // expected-note 2 {{declaration has been explicitly marked unavailable here}}
+ r = 1,
+ s = 2,
+ t = 3
+}__attribute__((unavailable()));
+
+enum fee f() { // expected-error {{error: 'fee' is unavailable}}
+ int i = a; // expected-warning {{'foo' is deprecated }}
+
+ i = b; // expected-warning {{'b' is deprecated}}
+
+ return r; // expected-error {{'fee' is unavailable}}
+}
diff --git a/test/Sema/complex-init-list.c b/test/Sema/complex-init-list.c
new file mode 100644
index 000000000000..5b5d7ce1436b
--- /dev/null
+++ b/test/Sema/complex-init-list.c
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -pedantic
+
+// This file tests the clang extension which allows initializing the components
+// of a complex number individually using an initialization list. Basically,
+// if you have an explicit init list for a complex number that contains two
+// initializers, this extension kicks in to turn it into component-wise
+// initialization.
+//
+// This extension is useful because there isn't any way to accurately build
+// a complex number at the moment besides setting the components with
+// __real__ and __imag__, which is inconvenient and not usable for constants.
+// (Of course, there are other extensions we could implement that would
+// allow this, like some sort of __builtin_build_complex.)
+//
+// FIXME: It would be a good idea to have a warnings for implicit
+// real->complex and complex->real conversions; as-is, it's way too easy
+// to get implicit conversions when they are not intended.
+
+// Basic testcase
+_Complex float valid1 = { 1.0f, 2.0f }; // expected-warning {{specifying real and imaginary components is an extension}}
+
+
+// Struct for nesting tests
+struct teststruct { _Complex float x; };
+
+
+// Random other valid stuff
+_Complex int valid2 = { 1, 2 }; // expected-warning {{complex integer}} expected-warning {{specifying real and imaginary components is an extension}}
+struct teststruct valid3 = { { 1.0f, 2.0f} }; // expected-warning {{specifying real and imaginary components is an extension}}
+_Complex float valid4[2] = { {1.0f, 1.0f}, {1.0f, 1.0f} }; // expected-warning 2 {{specifying real and imaginary components is an extension}}
+// FIXME: We need some sort of warning for valid5
+_Complex float valid5 = {1.0f, 1.0fi}; // expected-warning {{imaginary constants}} expected-warning {{specifying real and imaginary components is an extension}}
+
+
+// Random invalid stuff
+struct teststruct invalid1 = { 1, 2 }; // expected-warning {{excess elements}}
+_Complex float invalid2 = { 1, 2, 3 }; // expected-warning {{excess elements}}
+_Complex float invalid3 = {}; // expected-error {{scalar initializer cannot be empty}} expected-warning {{GNU empty initializer}}
+
+
+// Check incomplete array sizing
+_Complex float sizetest1[] = { {1.0f, 1.0f}, {1.0f, 1.0f} }; // expected-warning 2 {{specifying real and imaginary components is an extension}}
+_Complex float sizecheck1[(sizeof(sizetest1) == sizeof(*sizetest1)*2) ? 1 : -1];
+_Complex float sizetest2[] = { 1.0f, 1.0f, {1.0f, 1.0f} }; // expected-warning {{specifying real and imaginary components is an extension}}
+_Complex float sizecheck2[(sizeof(sizetest2) == sizeof(*sizetest2)*3) ? 1 : -1];
diff --git a/test/Sema/conditional-expr.c b/test/Sema/conditional-expr.c
index 7a8c9e9f3612..436ecdbebce8 100644
--- a/test/Sema/conditional-expr.c
+++ b/test/Sema/conditional-expr.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -Wsign-compare %s
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -Wsign-conversion %s
void foo() {
*(0 ? (double *)0 : (void *)0) = 0;
// FIXME: GCC doesn't consider the the following two statements to be errors.
@@ -36,12 +36,12 @@ void foo() {
*(0 ? (asdf) 0 : &x) = 10;
unsigned long test0 = 5;
- test0 = test0 ? (long) test0 : test0; // expected-warning {{operands of ? are integers of different signs}}
- test0 = test0 ? (int) test0 : test0; // expected-warning {{operands of ? are integers of different signs}}
- test0 = test0 ? (short) test0 : test0; // expected-warning {{operands of ? are integers of different signs}}
- test0 = test0 ? test0 : (long) test0; // expected-warning {{operands of ? are integers of different signs}}
- test0 = test0 ? test0 : (int) test0; // expected-warning {{operands of ? are integers of different signs}}
- test0 = test0 ? test0 : (short) test0; // expected-warning {{operands of ? are integers of different signs}}
+ test0 = test0 ? (long) test0 : test0; // expected-warning {{operand of ? changes signedness: 'long' to 'unsigned long'}}
+ test0 = test0 ? (int) test0 : test0; // expected-warning {{operand of ? changes signedness: 'int' to 'unsigned long'}}
+ test0 = test0 ? (short) test0 : test0; // expected-warning {{operand of ? changes signedness: 'short' to 'unsigned long'}}
+ test0 = test0 ? test0 : (long) test0; // expected-warning {{operand of ? changes signedness: 'long' to 'unsigned long'}}
+ test0 = test0 ? test0 : (int) test0; // expected-warning {{operand of ? changes signedness: 'int' to 'unsigned long'}}
+ test0 = test0 ? test0 : (short) test0; // expected-warning {{operand of ? changes signedness: 'short' to 'unsigned long'}}
test0 = test0 ? test0 : (long) 10;
test0 = test0 ? test0 : (int) 10;
test0 = test0 ? test0 : (short) 10;
@@ -49,12 +49,17 @@ void foo() {
test0 = test0 ? (int) 10 : test0;
test0 = test0 ? (short) 10 : test0;
+ int test1;
enum Enum { EVal };
test0 = test0 ? EVal : test0;
- test0 = test0 ? EVal : (int) test0; // okay: EVal is an int
- test0 = test0 ? // expected-warning {{operands of ? are integers of different signs}}
+ test1 = test0 ? EVal : (int) test0;
+ test0 = test0 ?
(unsigned) EVal
- : (int) test0;
+ : (int) test0; // expected-warning {{operand of ? changes signedness: 'int' to 'unsigned long'}}
+
+ test0 = test0 ? EVal : test1; // expected-warning {{operand of ? changes signedness: 'int' to 'unsigned long'}}
+ test0 = test0 ? test1 : EVal; // expected-warning {{operand of ? changes signedness: 'int' to 'unsigned long'}}
+
}
int Postgresql() {
diff --git a/test/Sema/conversion.c b/test/Sema/conversion.c
index 03204c63e965..842641bf1056 100644
--- a/test/Sema/conversion.c
+++ b/test/Sema/conversion.c
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wconversion -nostdinc -isystem %S/Inputs -triple x86_64-apple-darwin %s -Wno-unreachable-code
+// RUN: %clang_cc1 -fsyntax-only -verify -Wconversion \
+// RUN: -nostdsysteminc -nobuiltininc -isystem %S/Inputs \
+// RUN: -triple x86_64-apple-darwin %s -Wno-unreachable-code
#include <conversion.h>
diff --git a/test/Sema/crash-invalid-array.c b/test/Sema/crash-invalid-array.c
new file mode 100644
index 000000000000..a3bc03b70b56
--- /dev/null
+++ b/test/Sema/crash-invalid-array.c
@@ -0,0 +1,17 @@
+// RUN: not %clang_cc1 -O1 %s -emit-llvm
+// PR6913
+
+#include <stdio.h>
+
+int main()
+{
+ int x[10][10];
+ int (*p)[] = x; // expected-error {{invalid use of array with unspecified bounds}
+
+ int i;
+
+ for(i = 0; i < 10; ++i)
+ {
+ p[i][i] = i;
+ }
+}
diff --git a/test/Sema/dllimport-dllexport.c b/test/Sema/dllimport-dllexport.c
index f09e3cf69ab5..610059ec9f6b 100644
--- a/test/Sema/dllimport-dllexport.c
+++ b/test/Sema/dllimport-dllexport.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple i386-mingw32 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-mingw32 -fsyntax-only -verify %s
inline void __attribute__((dllexport)) foo1(){} // expected-warning{{dllexport attribute ignored}}
inline void __attribute__((dllimport)) foo2(){} // expected-warning{{dllimport attribute ignored}}
diff --git a/test/Sema/exprs.c b/test/Sema/exprs.c
index 9ce1481f16c5..72cff65f4837 100644
--- a/test/Sema/exprs.c
+++ b/test/Sema/exprs.c
@@ -163,7 +163,7 @@ void test17(int x) {
}
// PR6501
-void test18_a(int a); // expected-note {{'test18_a' declared here}}
+void test18_a(int a); // expected-note 2 {{'test18_a' declared here}}
void test18(int b) {
test18_a(b, b); // expected-error {{too many arguments to function call, expected 1, have 2}}
test18_a(); // expected-error {{too few arguments to function call, expected 1, have 0}}
@@ -183,7 +183,9 @@ void test19() {
}
int test20(int x) {
- return x && 4; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+ return x && 4; // expected-warning {{use of logical '&&' with constant operand}} \
+ // expected-note {{use '&' for a bitwise operation}} \
+ // expected-note {{remove constant to silence this warning}}
return x && sizeof(int) == 4; // no warning, RHS is logical op.
@@ -192,20 +194,32 @@ int test20(int x) {
return x || 0;
return x || 1;
- return x || -1; // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
- return x || 5; // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
+ return x || -1; // expected-warning {{use of logical '||' with constant operand}} \
+ // expected-note {{use '|' for a bitwise operation}}
+ return x || 5; // expected-warning {{use of logical '||' with constant operand}} \
+ // expected-note {{use '|' for a bitwise operation}}
return x && 0;
return x && 1;
- return x && -1; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
- return x && 5; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+ return x && -1; // expected-warning {{use of logical '&&' with constant operand}} \
+ // expected-note {{use '&' for a bitwise operation}} \
+ // expected-note {{remove constant to silence this warning}}
+ return x && 5; // expected-warning {{use of logical '&&' with constant operand}} \
+ // expected-note {{use '&' for a bitwise operation}} \
+ // expected-note {{remove constant to silence this warning}}
return x || (0);
return x || (1);
- return x || (-1); // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
- return x || (5); // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
+ return x || (-1); // expected-warning {{use of logical '||' with constant operand}} \
+ // expected-note {{use '|' for a bitwise operation}}
+ return x || (5); // expected-warning {{use of logical '||' with constant operand}} \
+ // expected-note {{use '|' for a bitwise operation}}
return x && (0);
return x && (1);
- return x && (-1); // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
- return x && (5); // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+ return x && (-1); // expected-warning {{use of logical '&&' with constant operand}} \
+ // expected-note {{use '&' for a bitwise operation}} \
+ // expected-note {{remove constant to silence this warning}}
+ return x && (5); // expected-warning {{use of logical '&&' with constant operand}} \
+ // expected-note {{use '&' for a bitwise operation}} \
+ // expected-note {{remove constant to silence this warning}}
}
diff --git a/test/Sema/flexible-array-init.c b/test/Sema/flexible-array-init.c
index 12f5d4f5d605..78fc7c5e0df3 100644
--- a/test/Sema/flexible-array-init.c
+++ b/test/Sema/flexible-array-init.c
@@ -7,9 +7,7 @@ struct one {
struct one x2 = { 5, 1, 2, 3 }; // expected-warning{{flexible array initialization is a GNU extension}}
void test() {
- struct one x3 = {5, {1, 2, 3}}; // \
- // expected-warning{{flexible array initialization is a GNU extension}} \
- // expected-error {{non-static initialization of a variable with flexible array member}}
+ struct one x3 = {5, {1, 2, 3}}; // expected-error{{initialization of flexible array member is not allowed}}
struct one x3a = { 5 };
struct one x3b = { .a = 5 };
struct one x3c = { 5, {} }; // expected-warning{{use of GNU empty initializer extension}} \
@@ -19,22 +17,23 @@ void test() {
struct foo {
int x;
- int y[]; // expected-note 6 {{initialized flexible array member 'y' is here}}
+ int y[]; // expected-note 8 {{initialized flexible array member 'y' is here}}
};
struct bar { struct foo z; }; // expected-warning {{'z' may not be nested in a struct due to flexible array member}}
struct foo a = { 1, { 2, 3, 4 } }; // expected-warning{{flexible array initialization is a GNU extension}}
-struct bar b = { { 1, { 2, 3, 4 } } }; // expected-error{{non-empty initialization of flexible array member inside subobject}}
+struct bar b = { { 1, { 2, 3, 4 } } }; // expected-error{{initialization of flexible array member is not allowed}}
struct bar c = { { 1, { } } }; // // expected-warning{{flexible array initialization is a GNU extension}} \
// expected-warning{{use of GNU empty initializer extension}} \
// expected-warning{{zero size arrays are an extension}}
struct foo d[1] = { { 1, { 2, 3, 4 } } }; // expected-warning{{'struct foo' may not be used as an array element due to flexible array member}} \
- // expected-error{{non-empty initialization of flexible array member inside subobject}}
+ // expected-error{{initialization of flexible array member is not allowed}}
-struct foo desig_foo = { .y = {2, 3, 4} };
+struct foo desig_foo = { .y = {2, 3, 4} }; // expected-warning{{flexible array initialization is a GNU extension}}
struct bar desig_bar = { .z.y = { } }; // expected-warning{{use of GNU empty initializer extension}} \
- // expected-warning{{zero size arrays are an extension}}
-struct bar desig_bar2 = { .z.y = { 2, 3, 4} }; // expected-error{{non-empty initialization of flexible array member inside subobject}}
+ // expected-warning{{zero size arrays are an extension}} \
+ // expected-warning{{flexible array initialization is a GNU extension}}
+struct bar desig_bar2 = { .z.y = { 2, 3, 4} }; // expected-error{{initialization of flexible array member is not allowed}}
struct foo design_foo2 = { .y = 2 }; // expected-error{{flexible array requires brace-enclosed initializer}}
struct point {
@@ -68,13 +67,25 @@ struct Y {
// PR8217
struct PR8217a {
int i;
- char v[];
+ char v[]; // expected-note 2 {{initialized flexible array member 'v' is here}}
};
void PR8217() {
- struct PR8217a foo1 = { .i = 0, .v = "foo" }; // expected-error {{non-static initialization of a variable with flexible array member}}
+ struct PR8217a foo1 = { .i = 0, .v = "foo" }; // expected-error {{initialization of flexible array member is not allowed}}
struct PR8217a foo2 = { .i = 0 };
- struct PR8217a foo3 = { .i = 0, .v = { 'b', 'a', 'r', '\0' } }; // expected-error {{non-static initialization of a variable with flexible array member}}
+ struct PR8217a foo3 = { .i = 0, .v = { 'b', 'a', 'r', '\0' } }; // expected-error {{initialization of flexible array member is not allowed}}
struct PR8217a bar;
}
+typedef struct PR10648 {
+ unsigned long n;
+ int v[]; // expected-note {{initialized flexible array member 'v' is here}}
+} PR10648;
+int f10648() {
+ return (PR10648){2, {3, 4}}.v[1]; // expected-error {{initialization of flexible array member is not allowed}}
+}
+
+struct FlexWithUnnamedBitfield { int : 10; int x; int y[]; }; // expected-note {{initialized flexible array member 'y' is here}}
+void TestFlexWithUnnamedBitfield() {
+ struct FlexWithUnnamedBitfield x = {10, {3}}; // expected-error {{initialization of flexible array member is not allowed}}
+}
diff --git a/test/Sema/format-strings-fixit.c b/test/Sema/format-strings-fixit.c
index c2fa2f770745..d03cccb601f3 100644
--- a/test/Sema/format-strings-fixit.c
+++ b/test/Sema/format-strings-fixit.c
@@ -1,5 +1,5 @@
// RUN: cp %s %t
-// RUN: %clang_cc1 -pedantic -Wall -fixit %t || true
+// RUN: %clang_cc1 -pedantic -Wall -fixit %t
// RUN: %clang_cc1 -fsyntax-only -pedantic -Wall -Werror %t
// RUN: %clang_cc1 -E -o - %t | FileCheck %s
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c
index b47d3ca2616c..6b5f7e2c2662 100644
--- a/test/Sema/format-strings.c
+++ b/test/Sema/format-strings.c
@@ -87,7 +87,12 @@ void check_empty_format_string(char* buf, ...)
va_list ap;
va_start(ap,buf);
vprintf("",ap); // expected-warning {{format string is empty}}
- sprintf(buf,""); // expected-warning {{format string is empty}}
+ sprintf(buf, "", 1); // expected-warning {{format string is empty}}
+
+ // Don't warn about empty format strings when there are no data arguments.
+ // This can arise from macro expansions and non-standard format string
+ // functions.
+ sprintf(buf, ""); // no-warning
}
void check_wide_string(char* b, ...)
@@ -372,3 +377,13 @@ void check_char(unsigned char x, signed char y) {
printf("%c", x); // no-warning
printf("%hhu", y); // no-warning
}
+
+// Test suppression of individual warnings.
+
+void test_suppress_invalid_specifier() {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wformat-invalid-specifier"
+ printf("%@", 12); // no-warning
+#pragma clang diagnostic pop
+}
+
diff --git a/test/Sema/fp16-sema.c b/test/Sema/fp16-sema.c
new file mode 100644
index 000000000000..e678f9a829e4
--- /dev/null
+++ b/test/Sema/fp16-sema.c
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// Functions cannot have parameters of type __fp16.
+extern void f (__fp16); // expected-error {{parameters cannot have __fp16 type; did you forget * ?}}
+extern void g (__fp16 *);
+
+extern void (*pf) (__fp16); // expected-error {{parameters cannot have __fp16 type; did you forget * ?}}
+extern void (*pg) (__fp16*);
+
+typedef void(*tf) (__fp16); // expected-error {{parameters cannot have __fp16 type; did you forget * ?}}
+typedef void(*tg) (__fp16*);
+
+void kf(a)
+ __fp16 a; { // expected-error {{parameters cannot have __fp16 type; did you forget * ?}}
+}
+
+void kg(a)
+ __fp16 *a; {
+}
+
+// Functions cannot return type __fp16.
+extern __fp16 f1 (void); // expected-error {{function return value cannot have __fp16 type; did you forget * ?}}
+extern __fp16 *g1 (void);
+
+extern __fp16 (*pf1) (void); // expected-error {{function return value cannot have __fp16 type; did you forget * ?}}
+extern __fp16 *(*gf1) (void);
+
+typedef __fp16 (*tf1) (void); // expected-error {{function return value cannot have __fp16 type; did you forget * ?}}
+typedef __fp16 *(*tg1) (void);
+
diff --git a/test/Sema/fpack-struct.c b/test/Sema/fpack-struct.c
new file mode 100644
index 000000000000..37c8444ae9f8
--- /dev/null
+++ b/test/Sema/fpack-struct.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -DEXPECTED_STRUCT_SIZE=5 -fpack-struct 1 %s
+// RUN: %clang_cc1 -DEXPECTED_STRUCT_SIZE=6 -fpack-struct 2 %s
+
+struct s0 {
+ int x;
+ char c;
+};
+
+int t0[sizeof(struct s0) == EXPECTED_STRUCT_SIZE ?: -1];
diff --git a/test/Sema/i-c-e.c b/test/Sema/i-c-e.c
index 1aac51e204f1..9b50916f85ff 100644
--- a/test/Sema/i-c-e.c
+++ b/test/Sema/i-c-e.c
@@ -53,7 +53,8 @@ char z[__builtin_constant_p(4) ? 1 : -1];
// Comma tests
int comma1[0?1,2:3]; // expected-warning {{expression result unused}}
int comma2[1||(1,2)]; // expected-warning {{expression result unused}} \
- // expected-warning {{use of logical || with constant operand}}
+ // expected-warning {{use of logical '||' with constant operand}} \
+ // expected-note {{use '|' for a bitwise operation}}
int comma3[(1,2)]; // expected-warning {{size of static array must be an integer constant expression}} \
// expected-warning {{expression result unused}}
diff --git a/test/Sema/implicit-int.c b/test/Sema/implicit-int.c
index 1bb9a8385306..3063db66ed85 100644
--- a/test/Sema/implicit-int.c
+++ b/test/Sema/implicit-int.c
@@ -24,9 +24,5 @@ h19_insline(n) // expected-warning {{parameter 'n' was not declared, defaulting
}
struct foo {
- __extension__ __attribute__((packed)) x : 4;
+ __extension__ __attribute__((packed)) x : 4; // expected-warning {{type specifier missing, defaults to 'int'}}
};
-
-
-
-
diff --git a/test/Sema/init.c b/test/Sema/init.c
index f8110079d0eb..2527e14fcbe9 100644
--- a/test/Sema/init.c
+++ b/test/Sema/init.c
@@ -144,3 +144,7 @@ int PR4386_b = ((void *) PR4386_foo) != 0; // expected-error{{initializer elemen
int PR4386_c = ((void *) PR4386_zed) != 0;
int PR4386_zed() __attribute((weak));
+// <rdar://problem/10185490> (derived from SPEC vortex benchmark)
+typedef char strty[10];
+struct vortexstruct { strty s; };
+struct vortexstruct vortexvar = { "asdf" };
diff --git a/test/Sema/initialize-noreturn.c b/test/Sema/initialize-noreturn.c
new file mode 100644
index 000000000000..55578628716b
--- /dev/null
+++ b/test/Sema/initialize-noreturn.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify
+// rdar://10095762
+
+typedef void (*Fn_noret)(void) __attribute__((noreturn));
+typedef void (*Fn_ret)(void);
+
+void foo(void);
+void foo_noret(void) __attribute__((noreturn));
+
+void test() {
+ Fn_noret fn2 = &foo; // expected-warning {{incompatible pointer types initializing 'Fn_noret'}}
+ Fn_noret fn3 = &foo_noret;
+ Fn_ret fn4 = &foo_noret;
+ Fn_ret fn5 = &foo;
+}
+
diff --git a/test/Sema/knr-def-call.c b/test/Sema/knr-def-call.c
index 6243af619398..f41275d1e618 100644
--- a/test/Sema/knr-def-call.c
+++ b/test/Sema/knr-def-call.c
@@ -36,8 +36,6 @@ void proto(x)
}
void use_proto() {
- proto(42.0); // expected-warning{{implicit conversion turns literal floating-point number into integer}} \
- // expected-note {{this can be rewritten as an integer literal with the exact same value}}
- (&proto)(42.0); // expected-warning{{implicit conversion turns literal floating-point number into integer}} \
- // expected-note {{this can be rewritten as an integer literal with the exact same value}}
+ proto(42.1); // expected-warning{{implicit conversion turns literal floating-point number into integer}}
+ (&proto)(42.1); // expected-warning{{implicit conversion turns literal floating-point number into integer}}
}
diff --git a/test/Sema/many-parameters.c b/test/Sema/many-parameters.c
new file mode 100644
index 000000000000..1473c941109a
--- /dev/null
+++ b/test/Sema/many-parameters.c
@@ -0,0 +1,310 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c99 %s
+
+// This test simply tests that the compiler does not crash. An optimization
+// in ParmVarDecls means that functions with fewer than 256 parameters use a fast path,
+// while those with >= 256 parameters use a slow path.
+//
+// Crash was reported in PR 10538.
+
+void foo(
+int x0,
+int x1,
+int x2,
+int x3,
+int x4,
+int x5,
+int x6,
+int x7,
+int x8,
+int x9,
+int x10,
+int x11,
+int x12,
+int x13,
+int x14,
+int x15,
+int x16,
+int x17,
+int x18,
+int x19,
+int x20,
+int x21,
+int x22,
+int x23,
+int x24,
+int x25,
+int x26,
+int x27,
+int x28,
+int x29,
+int x30,
+int x31,
+int x32,
+int x33,
+int x34,
+int x35,
+int x36,
+int x37,
+int x38,
+int x39,
+int x40,
+int x41,
+int x42,
+int x43,
+int x44,
+int x45,
+int x46,
+int x47,
+int x48,
+int x49,
+int x50,
+int x51,
+int x52,
+int x53,
+int x54,
+int x55,
+int x56,
+int x57,
+int x58,
+int x59,
+int x60,
+int x61,
+int x62,
+int x63,
+int x64,
+int x65,
+int x66,
+int x67,
+int x68,
+int x69,
+int x70,
+int x71,
+int x72,
+int x73,
+int x74,
+int x75,
+int x76,
+int x77,
+int x78,
+int x79,
+int x80,
+int x81,
+int x82,
+int x83,
+int x84,
+int x85,
+int x86,
+int x87,
+int x88,
+int x89,
+int x90,
+int x91,
+int x92,
+int x93,
+int x94,
+int x95,
+int x96,
+int x97,
+int x98,
+int x99,
+int x100,
+int x101,
+int x102,
+int x103,
+int x104,
+int x105,
+int x106,
+int x107,
+int x108,
+int x109,
+int x110,
+int x111,
+int x112,
+int x113,
+int x114,
+int x115,
+int x116,
+int x117,
+int x118,
+int x119,
+int x120,
+int x121,
+int x122,
+int x123,
+int x124,
+int x125,
+int x126,
+int x127,
+int x128,
+int x129,
+int x130,
+int x131,
+int x132,
+int x133,
+int x134,
+int x135,
+int x136,
+int x137,
+int x138,
+int x139,
+int x140,
+int x141,
+int x142,
+int x143,
+int x144,
+int x145,
+int x146,
+int x147,
+int x148,
+int x149,
+int x150,
+int x151,
+int x152,
+int x153,
+int x154,
+int x155,
+int x156,
+int x157,
+int x158,
+int x159,
+int x160,
+int x161,
+int x162,
+int x163,
+int x164,
+int x165,
+int x166,
+int x167,
+int x168,
+int x169,
+int x170,
+int x171,
+int x172,
+int x173,
+int x174,
+int x175,
+int x176,
+int x177,
+int x178,
+int x179,
+int x180,
+int x181,
+int x182,
+int x183,
+int x184,
+int x185,
+int x186,
+int x187,
+int x188,
+int x189,
+int x190,
+int x191,
+int x192,
+int x193,
+int x194,
+int x195,
+int x196,
+int x197,
+int x198,
+int x199,
+int x200,
+int x201,
+int x202,
+int x203,
+int x204,
+int x205,
+int x206,
+int x207,
+int x208,
+int x209,
+int x210,
+int x211,
+int x212,
+int x213,
+int x214,
+int x215,
+int x216,
+int x217,
+int x218,
+int x219,
+int x220,
+int x221,
+int x222,
+int x223,
+int x224,
+int x225,
+int x226,
+int x227,
+int x228,
+int x229,
+int x230,
+int x231,
+int x232,
+int x233,
+int x234,
+int x235,
+int x236,
+int x237,
+int x238,
+int x239,
+int x240,
+int x241,
+int x242,
+int x243,
+int x244,
+int x245,
+int x246,
+int x247,
+int x248,
+int x249,
+int x250,
+int x251,
+int x252,
+int x253,
+int x254,
+int x255,
+int x256,
+int x257,
+int x258,
+int x259,
+int x260,
+int x261,
+int x262,
+int x263,
+int x264,
+int x265,
+int x266,
+int x267,
+int x268,
+int x269,
+int x270,
+int x271,
+int x272,
+int x273,
+int x274,
+int x275,
+int x276,
+int x277,
+int x278,
+int x279,
+int x280,
+int x281,
+int x282,
+int x283,
+int x284,
+int x285,
+int x286,
+int x287,
+int x288,
+int x289,
+int x290,
+int x291,
+int x292,
+int x293,
+int x294,
+int x295,
+int x296,
+int x297,
+int x298,
+int x299
+);
diff --git a/test/Sema/ms-fuzzy-asm.c b/test/Sema/ms-fuzzy-asm.c
deleted file mode 100644
index 250e3222564d..000000000000
--- a/test/Sema/ms-fuzzy-asm.c
+++ /dev/null
@@ -1,9 +0,0 @@
-// RUN: %clang_cc1 %s -verify -fms-extensions
-
-#define M __asm int 0x2c
-#define M2 int
-
-void t1(void) { M }
-void t2(void) { __asm int 0x2c }
-void t3(void) { __asm M2 0x2c }
-void* t4(void) { __asm mov eax, fs:[0x10] }
diff --git a/test/Sema/ms_class_layout.cpp b/test/Sema/ms_class_layout.cpp
new file mode 100644
index 000000000000..13c90b0c9ed1
--- /dev/null
+++ b/test/Sema/ms_class_layout.cpp
@@ -0,0 +1,176 @@
+// RUN: %clang_cc1 -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -cxx-abi microsoft %s 2>&1 \
+// RUN: | FileCheck %s
+
+#pragma pack(push, 8)
+
+class B {
+public:
+ virtual void b(){}
+ int b_field;
+protected:
+private:
+};
+
+class A : public B {
+public:
+ int a_field;
+ virtual void a(){}
+ char one;
+protected:
+private:
+};
+
+class D {
+public:
+ virtual void b(){}
+ double a;
+};
+
+class C : public virtual A,
+ public D, public B {
+public:
+ double c1_field;
+ int c2_field;
+ double c3_field;
+ int c4_field;
+ virtual void foo(){}
+ virtual void bar(){}
+protected:
+private:
+};
+
+struct BaseStruct
+{
+ BaseStruct(){}
+ double v0;
+ float v1;
+ C fg;
+};
+
+struct DerivedStruct : public BaseStruct {
+ int x;
+};
+
+struct G
+{
+ virtual ~G(){}
+ int a;
+ double b;
+};
+
+#pragma pack(pop)
+
+// This needs only for building layouts.
+// Without this clang doesn`t dump record layouts.
+int main() {
+ // This avoid "Can't yet mangle constructors!" for MS ABI.
+ C* c;
+ c->foo();
+ DerivedStruct* v;
+ G* g;
+ BaseStruct* u;
+ return 0;
+}
+
+// CHECK: 0 | class D
+// CHECK-NEXT: 0 | (D vtable pointer)
+// CHECK-NEXT: 8 | double a
+
+// CHECK-NEXT: sizeof=16, dsize=16, align=8
+// CHECK-NEXT: nvsize=16, nvalign=8
+
+// CHECK: 0 | class B
+// CHECK-NEXT: 0 | (B vtable pointer)
+// CHECK-NEXT: 4 | int b_field
+
+// CHECK-NEXT: sizeof=8, dsize=8, align=4
+// CHECK-NEXT: nvsize=8, nvalign=4
+
+// CHECK: 0 | class A
+// CHECK-NEXT: 0 | class B (primary base)
+// CHECK-NEXT: 0 | (B vtable pointer)
+// CHECK-NEXT: 4 | int b_field
+// CHECK-NEXT: 8 | int a_field
+// CHECK-NEXT: 12 | char one
+
+// CHECK-NEXT: sizeof=16, dsize=16, align=4
+// CHECK-NEXT: nvsize=16, nvalign=4
+
+// CHECK: 0 | class C
+// CHECK-NEXT: 0 | class D (primary base)
+// CHECK-NEXT: 0 | (D vtable pointer)
+// CHECK-NEXT: 8 | double a
+// CHECK-NEXT: 16 | class B (base)
+// CHECK-NEXT: 16 | (B vtable pointer)
+// CHECK-NEXT: 20 | int b_field
+// CHECK-NEXT: 24 | (C vbtable pointer)
+// CHECK-NEXT: 32 | double c1_field
+// CHECK-NEXT: 40 | int c2_field
+// CHECK-NEXT: 48 | double c3_field
+// CHECK-NEXT: 56 | int c4_field
+// CHECK-NEXT: 64 | class A (virtual base)
+// CHECK-NEXT: 64 | class B (primary base)
+// CHECK-NEXT: 64 | (B vtable pointer)
+// CHECK-NEXT: 68 | int b_field
+// CHECK-NEXT: 72 | int a_field
+// CHECK-NEXT: 76 | char one
+
+// CHECK-NEXT: sizeof=80, dsize=80, align=8
+// CHECK-NEXT: nvsize=80, nvalign=8
+
+// CHECK: 0 | struct BaseStruct
+// CHECK-NEXT: 0 | double v0
+// CHECK-NEXT: 8 | float v1
+// CHECK-NEXT: 16 | class C fg
+// CHECK-NEXT: 16 | class D (primary base)
+// CHECK-NEXT: 16 | (D vtable pointer)
+// CHECK-NEXT: 24 | double a
+// CHECK-NEXT: 32 | class B (base)
+// CHECK-NEXT: 32 | (B vtable pointer)
+// CHECK-NEXT: 36 | int b_field
+// CHECK-NEXT: 40 | (C vbtable pointer)
+// CHECK-NEXT: 48 | double c1_field
+// CHECK-NEXT: 56 | int c2_field
+// CHECK-NEXT: 64 | double c3_field
+// CHECK-NEXT: 72 | int c4_field
+// CHECK-NEXT: 80 | class A (virtual base)
+// CHECK-NEXT: 80 | class B (primary base)
+// CHECK-NEXT: 80 | (B vtable pointer)
+// CHECK-NEXT: 84 | int b_field
+// CHECK-NEXT: 88 | int a_field
+// CHECK-NEXT: 92 | char one
+
+// CHECK-NEXT: sizeof=80, dsize=80, align=8
+// CHECK-NEXT: nvsize=80, nvalign=8
+
+// CHECK: sizeof=96, dsize=96, align=8
+// CHECK-NEXT: nvsize=96, nvalign=8
+
+// CHECK: 0 | struct DerivedStruct
+// CHECK-NEXT: 0 | struct BaseStruct (base)
+// CHECK-NEXT: 0 | double v0
+// CHECK-NEXT: 8 | float v1
+// CHECK-NEXT: 16 | class C fg
+// CHECK-NEXT: 16 | class D (primary base)
+// CHECK-NEXT: 16 | (D vtable pointer)
+// CHECK-NEXT: 24 | double a
+// CHECK-NEXT: 32 | class B (base)
+// CHECK-NEXT: 32 | (B vtable pointer)
+// CHECK-NEXT: 36 | int b_field
+// CHECK-NEXT: 40 | (C vbtable pointer)
+// CHECK-NEXT: 48 | double c1_field
+// CHECK-NEXT: 56 | int c2_field
+// CHECK-NEXT: 64 | double c3_field
+// CHECK-NEXT: 72 | int c4_field
+// CHECK-NEXT: 80 | class A (virtual base)
+// CHECK-NEXT: 80 | class B (primary base)
+// CHECK-NEXT: 80 | (B vtable pointer)
+// CHECK-NEXT: 84 | int b_field
+// CHECK-NEXT: 88 | int a_field
+// CHECK-NEXT: 92 | char one
+// CHECK-NEXT: sizeof=80, dsize=80, align=8
+// CHECK-NEXT: nvsize=80, nvalign=8
+
+// CHECK: 96 | int x
+// CHECK-NEXT: sizeof=104, dsize=104, align=8
+// CHECK-NEXT: nvsize=104, nvalign=8
diff --git a/test/Sema/parentheses.c b/test/Sema/parentheses.c
index 13ea3ecbe16a..9751336018b7 100644
--- a/test/Sema/parentheses.c
+++ b/test/Sema/parentheses.c
@@ -52,6 +52,8 @@ void conditional_op(int x, int y, _Bool b) {
// expected-note {{place parentheses around the '?:' expression to evaluate it first}} \
// expected-note {{place parentheses around the '+' expression to silence this warning}}
+ (void)((x + someConditionFunc()) ? 1 : 2); // no warning
+
(void)(x - b ? 1 : 2); // expected-warning {{operator '?:' has lower precedence than '-'}} \
// expected-note {{place parentheses around the '?:' expression to evaluate it first}} \
// expected-note {{place parentheses around the '-' expression to silence this warning}}
@@ -64,7 +66,6 @@ void conditional_op(int x, int y, _Bool b) {
// expected-note {{place parentheses around the '?:' expression to evaluate it first}} \
// expected-note {{place parentheses around the '/' expression to silence this warning}}
-
(void)(x % 2 ? 1 : 2); // no warning
}
diff --git a/test/Sema/parentheses.cpp b/test/Sema/parentheses.cpp
index 252455dcad49..767416677e00 100644
--- a/test/Sema/parentheses.cpp
+++ b/test/Sema/parentheses.cpp
@@ -40,6 +40,8 @@ void test(S *s, bool (S::*m_ptr)()) {
// expected-note {{place parentheses around the '?:' expression to evaluate it first}} \
// expected-note {{place parentheses around the '+' expression to silence this warning}}
+ (void)((*s + true) ? "foo" : "bar"); // No warning.
+
// Don't crash on unusual member call expressions.
(void)((s->*m_ptr)() ? "foo" : "bar");
}
diff --git a/test/Sema/pragma-arc-cf-code-audited.c b/test/Sema/pragma-arc-cf-code-audited.c
new file mode 100644
index 000000000000..b646e8966c61
--- /dev/null
+++ b/test/Sema/pragma-arc-cf-code-audited.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#pragma clang arc_cf_code_audited foo // expected-error {{expected 'begin' or 'end'}}
+
+#pragma clang arc_cf_code_audited begin foo // expected-warning {{extra tokens at end of #pragma directive}}
+
+#pragma clang arc_cf_code_audited end
+#pragma clang arc_cf_code_audited end // expected-error {{not currently inside '#pragma clang arc_cf_code_audited'}}
+
+#pragma clang arc_cf_code_audited begin // expected-note {{#pragma entered here}}
+#pragma clang arc_cf_code_audited begin // expected-error {{already inside '#pragma clang arc_cf_code_audited'}} expected-note {{#pragma entered here}}
+
+#include "Inputs/pragma-arc-cf-code-audited.h" // expected-error {{cannot #include files inside '#pragma clang arc_cf_code_audited'}}
+
+// This is actually on the #pragma line in the header.
+// expected-error {{'#pragma clang arc_cf_code_audited' was not ended within this file}}
+
+#pragma clang arc_cf_code_audited begin // expected-error {{'#pragma clang arc_cf_code_audited' was not ended within this file}}
diff --git a/test/Sema/return-noreturn.c b/test/Sema/return-noreturn.c
index ff43754a4299..448fce77cd85 100644
--- a/test/Sema/return-noreturn.c
+++ b/test/Sema/return-noreturn.c
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -fblocks -Wmissing-noreturn -Wno-unreachable-code
int j;
-void test1() { // expected-warning {{function could be attribute 'noreturn'}}
- ^ (void) { while (1) { } }(); // expected-warning {{block could be attribute 'noreturn'}}
+void test1() { // expected-warning {{function 'test1' could be declared with attribute 'noreturn'}}
+ ^ (void) { while (1) { } }(); // expected-warning {{block could be declared with attribute 'noreturn'}}
^ (void) { if (j) while (1) { } }();
while (1) { }
}
diff --git a/test/Sema/types.c b/test/Sema/types.c
index f3244f7799b6..332b525e33a8 100644
--- a/test/Sema/types.c
+++ b/test/Sema/types.c
@@ -37,3 +37,16 @@ _Decimal32 x; // expected-error {{GNU decimal type extension not supported}}
// rdar://6880951
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}}
+}
+
+// http://llvm.org/PR11082
+//
+// FIXME: This may or may not be the correct approach (no warning or error),
+// but large amounts of Linux and FreeBSD code need this attribute to not be
+// a hard error in order to work correctly.
+void test2(int i) {
+ char c = (char __attribute__((may_alias))) i;
+}
diff --git a/test/Sema/uninit-variables.c b/test/Sema/uninit-variables.c
index 0caab3df18c0..49af4f322629 100644
--- a/test/Sema/uninit-variables.c
+++ b/test/Sema/uninit-variables.c
@@ -1,7 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -Wuninitialized -Wconditional-uninitialized -fsyntax-only -fblocks %s -verify
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+
int test1() {
- int x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
+ int x; // expected-note{{initialize the variable 'x' to silence this warning}}
return x; // expected-warning{{variable 'x' is uninitialized when used here}}
}
@@ -17,25 +20,25 @@ int test3() {
}
int test4() {
- int x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
+ int x; // expected-note{{initialize the variable 'x' to silence this warning}}
++x; // expected-warning{{variable 'x' is uninitialized when used here}}
return x;
}
int test5() {
- int x, y; // expected-note{{variable 'y' is declared here}} expected-note{{add initialization to silence this warning}}
+ int x, y; // expected-note{{initialize the variable 'y' to silence this warning}}
x = y; // expected-warning{{variable 'y' is uninitialized when used here}}
return x;
}
int test6() {
- int x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
+ int x; // expected-note{{initialize the variable 'x' to silence this warning}}
x += 2; // expected-warning{{variable 'x' is uninitialized when used here}}
return x;
}
int test7(int y) {
- int x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
+ int x; // expected-note{{initialize the variable 'x' to silence this warning}}
if (y)
x = 1;
return x; // expected-warning{{variable 'x' may be uninitialized when used here}}
@@ -51,7 +54,7 @@ int test8(int y) {
}
int test9(int n) {
- int x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
+ int x; // expected-note{{initialize the variable 'x' to silence this warning}}
for (unsigned i = 0 ; i < n; ++i) {
if (i == n - 1)
break;
@@ -61,7 +64,7 @@ int test9(int n) {
}
int test10(unsigned n) {
- int x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
+ int x; // expected-note{{initialize the variable 'x' to silence this warning}}
for (unsigned i = 0 ; i < n; ++i) {
x = 1;
}
@@ -69,7 +72,7 @@ int test10(unsigned n) {
}
int test11(unsigned n) {
- int x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
+ int x; // expected-note{{initialize the variable 'x' to silence this warning}}
for (unsigned i = 0 ; i <= n; ++i) {
x = 1;
}
@@ -77,7 +80,7 @@ int test11(unsigned n) {
}
void test12(unsigned n) {
- for (unsigned i ; n ; ++i) ; // expected-warning{{variable 'i' may be uninitialized when used here}} expected-note{{variable 'i' is declared here}} expected-note{{add initialization to silence this warning}}
+ for (unsigned i ; n ; ++i) ; // expected-warning{{variable 'i' is uninitialized when used here}} expected-note{{initialize the variable 'i' to silence this warning}}
}
int test13() {
@@ -91,10 +94,15 @@ void test14() {
for (;;) {}
}
-int test15() {
- int x = x; // no-warning: signals intended lack of initialization. \
- // expected-note{{variable 'x' is declared here}}
- return x; // expected-warning{{variable 'x' is uninitialized when used here}}
+void test15() {
+ int x = x; // no-warning: signals intended lack of initialization.
+}
+
+int test15b() {
+ // Warn here with the self-init, since it does result in a use of
+ // an unintialized variable and this is the root cause.
+ int x = x; // expected-warning {{variable 'x' is uninitialized when used within its own initialization}}
+ return x;
}
// Don't warn in the following example; shows dataflow confluence.
@@ -108,7 +116,7 @@ void test16() {
void test17() {
// Don't warn multiple times about the same uninitialized variable
// along the same path.
- int *x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
+ int *x; // expected-note{{initialize the variable 'x' to silence this warning}}
*x = 1; // expected-warning{{variable 'x' is uninitialized when used here}}
*x = 1; // no-warning
}
@@ -132,14 +140,14 @@ int test19() {
}
int test20() {
- int z; // expected-note{{variable 'z' is declared here}} expected-note{{add initialization to silence this warning}}
+ int z; // expected-note{{initialize the variable 'z' to silence this warning}}
if ((test19_aux1() + test19_aux2() && test19_aux1()) || test19_aux3(&z))
return z; // expected-warning{{variable 'z' may be uninitialized when used here}}
return 0;
}
int test21(int x, int y) {
- int z; // expected-note{{variable 'z' is declared here}} expected-note{{add initialization to silence this warning}}
+ int z; // expected-note{{initialize the variable 'z' to silence this warning}}
if ((x && y) || test19_aux3(&z) || test19_aux2())
return z; // expected-warning{{variable 'z' may be uninitialized when used here}}
return 0;
@@ -164,7 +172,7 @@ int test23() {
// conditionals. This possibly can be handled by making the CFG itself
// represent such control-dependencies, but it is a niche case.
int test24(int flag) {
- unsigned val; // expected-note{{variable 'val' is declared here}} expected-note{{add initialization to silence this warning}}
+ unsigned val; // expected-note{{initialize the variable 'val' to silence this warning}}
if (flag)
val = 1;
if (!flag)
@@ -173,13 +181,13 @@ int test24(int flag) {
}
float test25() {
- float x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
+ float x; // expected-note{{initialize the variable 'x' to silence this warning}}
return x; // expected-warning{{variable 'x' is uninitialized when used here}}
}
typedef int MyInt;
MyInt test26() {
- MyInt x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
+ MyInt x; // expected-note{{initialize the variable 'x' to silence this warning}}
return x; // expected-warning{{variable 'x' is uninitialized when used here}}
}
@@ -190,12 +198,12 @@ int test27() {
}
int test28() {
- int len; // expected-note{{variable 'len' is declared here}} expected-note{{add initialization to silence this warning}}
+ int len; // expected-note{{initialize the variable 'len' to silence this warning}}
return sizeof(int[len]); // expected-warning{{variable 'len' is uninitialized when used here}}
}
void test29() {
- int x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
+ int x; // expected-note{{initialize the variable 'x' to silence this warning}}
(void) ^{ (void) x; }; // expected-warning{{variable 'x' is uninitialized when captured by block}}
}
@@ -220,7 +228,7 @@ void test_33() {
}
int test_34() {
- int x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
+ int x; // expected-note{{initialize the variable 'x' to silence this warning}}
(void) x;
return x; // expected-warning{{variable 'x' is uninitialized when used here}}
}
@@ -234,10 +242,10 @@ void test35(int x) {
// Test handling of indirect goto.
void test36()
{
- void **pc; // expected-note{{variable 'pc' is declared here}} expected-note{{add initialization to silence this warning}}
+ void **pc; // expected-note{{initialize the variable 'pc' to silence this warning}}
void *dummy[] = { &&L1, &&L2 };
L1:
- goto *pc; // expected-warning{{variable 'pc' may be uninitialized when used here}}
+ goto *pc; // expected-warning{{variable 'pc' is uninitialized when used here}}
L2:
goto *pc;
}
@@ -263,19 +271,19 @@ int test38(int r, int x, int y)
}
int test39(int x) {
- int y; // expected-note {{variable 'y' is declared here}} expected-note{{add initialization to silence this warning}}
+ int y; // expected-note{{initialize the variable 'y' to silence this warning}}
int z = x + y; // expected-warning {{variable 'y' is uninitialized when used here}}
return z;
}
int test40(int x) {
- int y; // expected-note {{variable 'y' is declared here}} expected-note{{add initialization to silence this warning}}
+ int y; // expected-note{{initialize the variable 'y' to silence this warning}}
return x ? 1 : y; // expected-warning {{variable 'y' is uninitialized when used here}}
}
int test41(int x) {
- int y; // expected-note {{variable 'y' is declared here}} expected-note{{add initialization to silence this warning}}
+ int y; // expected-note{{initialize the variable 'y' to silence this warning}}
if (x) y = 1; // no-warning
return y; // expected-warning {{variable 'y' may be uninitialized when used here}}
}
@@ -287,17 +295,17 @@ void test42() {
void test43_aux(int x);
void test43(int i) {
- int x; // expected-note {{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
+ int x; // expected-note{{initialize the variable 'x' to silence this warning}}
for (i = 0 ; i < 10; i++)
- test43_aux(x++); // expected-warning {{variable 'x' may be uninitialized when used here}}
+ test43_aux(x++); // expected-warning {{variable 'x' is uninitialized when used here}}
}
void test44(int i) {
int x = i;
- int y; // expected-note {{variable 'y' is declared here}} expected-note{{add initialization to silence this warning}}
+ int y; // expected-note{{initialize the variable 'y' to silence this warning}}
for (i = 0; i < 10; i++ ) {
test43_aux(x++); // no-warning
- x += y; // expected-warning {{variable 'y' may be uninitialized when used here}}
+ x += y; // expected-warning {{variable 'y' is uninitialized when used here}}
}
}
@@ -310,7 +318,7 @@ int test45(int j) {
void test46()
{
- int i; // expected-note {{variable 'i' is declared here}} expected-note{{add initialization to silence this warning}}
+ int i; // expected-note{{initialize the variable 'i' to silence this warning}}
int j = i ? : 1; // expected-warning {{variable 'i' is uninitialized when used here}}
}
@@ -341,7 +349,7 @@ int test51(void)
// FIXME: This is a false positive, but it tests logical operations in switch statements.
int test52(int a, int b) {
- int x; // expected-note {{variable 'x' is declared here}} expected-note {{add initialization to silence this warning}}
+ int x; // expected-note {{initialize the variable 'x' to silence this warning}}
switch (a || b) { // expected-warning {{switch condition has boolean value}}
case 0:
x = 1;
@@ -353,10 +361,15 @@ int test52(int a, int b) {
return x; // expected-warning {{variable 'x' may be uninitialized when used here}}
}
+void test53() {
+ int x; // expected-note {{initialize the variable 'x' to silence this warning}}
+ int y = (x); // expected-warning {{variable 'x' is uninitialized when used here}}
+}
+
// This CFG caused the uninitialized values warning to inf-loop.
extern int PR10379_g();
void PR10379_f(int *len) {
- int new_len; // expected-note {{variable 'new_len' is declared here}} expected-note{{add initialization to silence this warning}}
+ int new_len; // expected-note{{initialize the variable 'new_len' to silence this warning}}
for (int i = 0; i < 42 && PR10379_g() == 0; i++) {
if (PR10379_g() == 1)
continue;
@@ -367,3 +380,39 @@ void PR10379_f(int *len) {
*len += new_len; // expected-warning {{variable 'new_len' may be uninitialized when used here}}
}
}
+
+// Test that sizeof(VLA) doesn't trigger a warning.
+void test_vla_sizeof(int x) {
+ double (*memory)[2][x] = malloc(sizeof(*memory)); // no-warning
+}
+
+// Test absurd case of deadcode + use of blocks. This previously was a false positive
+// due to an analysis bug.
+int test_block_and_dead_code() {
+ __block int x;
+ ^{ x = 1; }();
+ if (0)
+ return x;
+ return x; // no-warning
+}
+
+// This previously triggered an infinite loop in the analysis.
+void PR11069(int a, int b) {
+ unsigned long flags;
+ for (;;) {
+ if (a && !b)
+ break;
+ }
+ for (;;) {
+ // This does not trigger a warning because it isn't a real use.
+ (void)(flags); // no-warning
+ }
+}
+
+// Test uninitialized value used in loop condition.
+void rdar9432305(float *P) {
+ int i; // expected-note {{initialize the variable 'i' to silence this warning}}
+ for (; i < 10000; ++i) // expected-warning {{variable 'i' is uninitialized when used here}}
+ P[i] = 0.0f;
+}
+
diff --git a/test/Sema/unused-expr.c b/test/Sema/unused-expr.c
index 9949887b23e7..97611168f1a2 100644
--- a/test/Sema/unused-expr.c
+++ b/test/Sema/unused-expr.c
@@ -7,11 +7,11 @@ double sqrt(double X); // implicitly const because of no -fmath-errno!
void bar(volatile int *VP, int *P, int A,
_Complex double C, volatile _Complex double VC) {
- VP == P; // expected-warning {{expression result unused}}
+ VP < P; // expected-warning {{expression result unused}}
(void)A;
(void)foo(1,2); // no warning.
- A == foo(1, 2); // expected-warning {{expression result unused}}
+ A < foo(1, 2); // expected-warning {{expression result unused}}
foo(1,2)+foo(4,3); // expected-warning {{expression result unused}}
@@ -54,23 +54,23 @@ void t4(int a) {
int b = 0;
if (a)
- b == 1; // expected-warning{{expression result unused}}
+ b < 1; // expected-warning{{expression result unused}}
else
- b == 2; // expected-warning{{expression result unused}}
+ b < 2; // expected-warning{{expression result unused}}
while (1)
- b == 3; // expected-warning{{expression result unused}}
+ b < 3; // expected-warning{{expression result unused}}
do
- b == 4; // expected-warning{{expression result unused}}
+ b < 4; // expected-warning{{expression result unused}}
while (1);
for (;;)
- b == 5; // expected-warning{{expression result unused}}
+ b < 5; // expected-warning{{expression result unused}}
- for (b == 1;;) {} // expected-warning{{expression result unused}}
- for (;b == 1;) {}
- for (;;b == 1) {} // expected-warning{{expression result unused}}
+ for (b < 1;;) {} // expected-warning{{expression result unused}}
+ for (;b < 1;) {}
+ for (;;b < 1) {} // expected-warning{{expression result unused}}
}
// rdar://7186119
diff --git a/test/Sema/warn-cast-align.c b/test/Sema/warn-cast-align.c
index 11e3c4163642..93352c253a2e 100644
--- a/test/Sema/warn-cast-align.c
+++ b/test/Sema/warn-cast-align.c
@@ -28,7 +28,7 @@ void test1(void *P) {
}
// Aligned struct.
-__attribute__((align(16))) struct A {
+__attribute__((aligned(16))) struct A {
char buffer[16];
};
void test2(char *P) {
diff --git a/test/Sema/warn-strlcpycat-size.c b/test/Sema/warn-strlcpycat-size.c
new file mode 100644
index 000000000000..8babdde276fa
--- /dev/null
+++ b/test/Sema/warn-strlcpycat-size.c
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -Wstrlcpy-strlcat-size -verify -fsyntax-only %s
+
+typedef __SIZE_TYPE__ size_t;
+size_t strlcpy (char * restrict dst, const char * restrict src, size_t size);
+size_t strlcat (char * restrict dst, const char * restrict src, size_t size);
+size_t strlen (const char *s);
+
+char s1[100];
+char s2[200];
+char * s3;
+
+struct {
+ char f1[100];
+ char f2[100][3];
+} s4, **s5;
+
+int x;
+
+void f(void)
+{
+ strlcpy(s1, s2, sizeof(s1)); // no warning
+ strlcpy(s1, s2, sizeof(s2)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}} expected-note {{change size argument to be the size of the destination}}
+ strlcpy(s1, s3, strlen(s3)+1); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}} expected-note {{change size argument to be the size of the destination}}
+ strlcat(s2, s3, sizeof(s3)); // expected-warning {{size argument in 'strlcat' call appears to be size of the source; expected the size of the destination}} expected-note {{change size argument to be the size of the destination}}
+ strlcpy(s4.f1, s2, sizeof(s2)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}} expected-note {{change size argument to be the size of the destination}}
+ strlcpy((*s5)->f2[x], s2, sizeof(s2)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}} expected-note {{change size argument to be the size of the destination}}
+ strlcpy(s1+3, s2, sizeof(s2)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}}
+}
+
+// Don't issue FIXIT for flexible arrays.
+struct S {
+ int y;
+ char x[];
+};
+
+void flexible_arrays(struct S *s) {
+ char str[] = "hi";
+ strlcpy(s->x, str, sizeof(str)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}}
+}
+
+// Don't issue FIXIT for destinations of size 1.
+void size_1() {
+ char z[1];
+ char str[] = "hi";
+
+ strlcpy(z, str, sizeof(str)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}}
+}
+
+// Support VLAs.
+void vlas(int size) {
+ char z[size];
+ char str[] = "hi";
+
+ strlcpy(z, str, sizeof(str)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}} expected-note {{change size argument to be the size of the destination}}
+}
diff --git a/test/Sema/warn-unreachable.c b/test/Sema/warn-unreachable.c
index 20e0c3172401..8db36b710012 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}}
+ ];
}
}
}
@@ -114,3 +114,15 @@ int test_enum_cases(enum Cases C) {
}
}
+// Handle unreachable code triggered by macro expansions.
+void __myassert_rtn(const char *, const char *, int, const char *) __attribute__((__noreturn__));
+
+#define myassert(e) \
+ (__builtin_expect(!(e), 0) ? __myassert_rtn(__func__, __FILE__, __LINE__, #e) : (void)0)
+
+void test_assert() {
+ myassert(0 && "unreachable");
+ return; // no-warning
+}
+
+
diff --git a/test/Sema/warn-unused-parameters.c b/test/Sema/warn-unused-parameters.c
index e47ddd5e00d5..af048e77e886 100644
--- a/test/Sema/warn-unused-parameters.c
+++ b/test/Sema/warn-unused-parameters.c
@@ -19,4 +19,12 @@ static void achor() {};
// CHECK: 5:12: warning: unused parameter 'y'
// CHECK: 12:15: warning: unused parameter 'y'
-// CHECK-unused: 1 warning generated \ No newline at end of file
+// CHECK-unused: 1 warning generated
+
+// RUN: %clang_cc1 -fblocks -fsyntax-only -Weverything %s 2>&1 | FileCheck -check-prefix=CHECK-everything %s
+// RUN: %clang_cc1 -fblocks -fsyntax-only -Weverything -Werror %s 2>&1 | FileCheck -check-prefix=CHECK-everything-error %s
+// RUN: %clang_cc1 -fblocks -fsyntax-only -Weverything -Wno-unused %s 2>&1 | FileCheck -check-prefix=CHECK-everything-no-unused %s
+// CHECK-everything: 6 warnings generated
+// CHECK-everything-error: 5 errors generated
+// CHECK-everything-no-unused: 5 warnings generated
+
diff --git a/test/SemaCUDA/cuda.h b/test/SemaCUDA/cuda.h
index e3aeb99ed220..26a8df0440f1 100644
--- a/test/SemaCUDA/cuda.h
+++ b/test/SemaCUDA/cuda.h
@@ -10,7 +10,7 @@
struct dim3 {
unsigned x, y, z;
- dim3(unsigned x, unsigned y = 1, unsigned z = 1) : x(x), y(y), z(z) {}
+ __host__ __device__ dim3(unsigned x, unsigned y = 1, unsigned z = 1) : x(x), y(y), z(z) {}
};
typedef struct cudaStream *cudaStream_t;
diff --git a/test/SemaCUDA/function-target.cu b/test/SemaCUDA/function-target.cu
new file mode 100644
index 000000000000..c7a55e2fad83
--- /dev/null
+++ b/test/SemaCUDA/function-target.cu
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#include "cuda.h"
+
+__host__ void h1h(void);
+__device__ void h1d(void); // expected-note {{candidate function not viable: call to __device__ function from __host__ function}}
+__host__ __device__ void h1hd(void);
+__global__ void h1g(void);
+
+struct h1ds { // expected-note {{requires 1 argument}}
+ __device__ h1ds(); // expected-note {{candidate constructor not viable: call to __device__ function from __host__ function}}
+};
+
+__host__ void h1(void) {
+ h1h();
+ h1d(); // expected-error {{no matching function}}
+ h1hd();
+ h1g<<<1, 1>>>();
+ h1ds x; // expected-error {{no matching constructor}}
+}
+
+__host__ void d1h(void); // expected-note {{candidate function not viable: call to __host__ function from __device__ function}}
+__device__ void d1d(void);
+__host__ __device__ void d1hd(void);
+__global__ void d1g(void); // expected-note {{'d1g' declared here}}
+
+__device__ void d1(void) {
+ d1h(); // expected-error {{no matching function}}
+ d1d();
+ d1hd();
+ d1g<<<1, 1>>>(); // expected-error {{reference to __global__ function 'd1g' in __device__ function}}
+}
+
+__host__ void hd1h(void); // expected-note {{candidate function not viable: call to __host__ function from __host__ __device__ function}}
+__device__ void hd1d(void); // expected-note {{candidate function not viable: call to __device__ function from __host__ __device__ function}}
+__host__ __device__ void hd1hd(void);
+__global__ void hd1g(void); // expected-note {{'hd1g' declared here}}
+
+__host__ __device__ void hd1(void) {
+ hd1h(); // expected-error {{no matching function}}
+ hd1d(); // expected-error {{no matching function}}
+ hd1hd();
+ hd1g<<<1, 1>>>(); // expected-error {{reference to __global__ function 'hd1g' in __host__ __device__ function}}
+}
diff --git a/test/SemaCUDA/kernel-call.cu b/test/SemaCUDA/kernel-call.cu
index 7bc7ae113159..91b1d49e2d06 100644
--- a/test/SemaCUDA/kernel-call.cu
+++ b/test/SemaCUDA/kernel-call.cu
@@ -13,6 +13,9 @@ int h2(int x) { return 1; }
int main(void) {
g1<<<1, 1>>>(42);
+ g1(42); // expected-error {{call to global function g1 not configured}}
+ g1<<<1>>>(42); // expected-error {{too few execution configuration arguments to kernel function call}}
+ g1<<<1, 1, 0, 0, 0>>>(42); // expected-error {{too many execution configuration arguments to kernel function call}}
t1(1);
diff --git a/test/SemaCXX/2008-01-11-BadWarning.cpp b/test/SemaCXX/2008-01-11-BadWarning.cpp
new file mode 100644
index 000000000000..b84e7c1cf862
--- /dev/null
+++ b/test/SemaCXX/2008-01-11-BadWarning.cpp
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wall %s
+// rdar://5683899
+void** f(void **Buckets, unsigned NumBuckets) {
+ return Buckets + NumBuckets;
+}
diff --git a/test/SemaCXX/MicrosoftCompatibility.cpp b/test/SemaCXX/MicrosoftCompatibility.cpp
new file mode 100644
index 000000000000..dfc47d6fc956
--- /dev/null
+++ b/test/SemaCXX/MicrosoftCompatibility.cpp
@@ -0,0 +1,158 @@
+// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -Wmicrosoft -verify -fms-compatibility -fexceptions -fcxx-exceptions
+
+
+
+namespace ms_conversion_rules {
+
+void f(float a);
+void f(int a);
+
+void test()
+{
+ long a = 0;
+ f((long)0);
+ f(a);
+}
+
+}
+
+
+
+namespace ms_protected_scope {
+ struct C { C(); };
+
+ int jump_over_variable_init(bool b) {
+ if (b)
+ goto foo; // expected-warning {{illegal goto into protected scope}}
+ C c; // expected-note {{jump bypasses variable initialization}}
+ foo:
+ return 1;
+ }
+
+struct Y {
+ ~Y();
+};
+
+void jump_over_var_with_dtor() {
+ goto end; // expected-warning{{goto into protected scope}}
+ Y y; // expected-note {{jump bypasses variable initialization}}
+ end:
+ ;
+}
+
+ void jump_over_variable_case(int c) {
+ switch (c) {
+ case 0:
+ int x = 56; // expected-note {{jump bypasses variable initialization}}
+ case 1: // expected-error {{switch case is in protected scope}}
+ x = 10;
+ }
+ }
+
+
+void exception_jump() {
+ goto l2; // expected-error {{illegal goto into protected scope}}
+ try { // expected-note {{jump bypasses initialization of try block}}
+ l2: ;
+ } catch(int) {
+ }
+}
+
+int jump_over_indirect_goto() {
+ static void *ps[] = { &&a0 };
+ goto *&&a0; // expected-warning {{goto into protected scope}}
+ int a = 3; // expected-note {{jump bypasses variable initialization}}
+ a0:
+ return 0;
+}
+
+}
+
+
+
+namespace ms_using_declaration_bug {
+
+class A {
+public:
+ int f();
+};
+
+class B : public A {
+private:
+ using A::f;
+};
+
+class C : public B {
+private:
+ using B::f; // expected-warning {{using declaration refers to inaccessible member 'ms_using_declaration_bug::B::f', which refers to accessible member 'ms_using_declaration_bug::A::f', accepted for Microsoft compatibility}}
+};
+
+}
+
+
+namespace MissingTypename {
+
+template<class T> class A {
+public:
+ typedef int TYPE;
+};
+
+template<class T> class B {
+public:
+ typedef int TYPE;
+};
+
+
+template<class T, class U>
+class C : private A<T>, public B<U> {
+public:
+ typedef A<T> Base1;
+ typedef B<U> Base2;
+ typedef A<U> Base3;
+
+ A<T>::TYPE a1; // expected-warning {{missing 'typename' prior to dependent type name}}
+ Base1::TYPE a2; // expected-warning {{missing 'typename' prior to dependent type name}}
+
+ B<U>::TYPE a3; // expected-warning {{missing 'typename' prior to dependent type name}}
+ Base2::TYPE a4; // expected-warning {{missing 'typename' prior to dependent type name}}
+
+ A<U>::TYPE a5; // expected-error {{missing 'typename' prior to dependent type name}}
+ Base3::TYPE a6; // expected-error {{missing 'typename' prior to dependent type name}}
+ };
+
+class D {
+public:
+ typedef int Type;
+};
+
+template <class T>
+void function_missing_typename(const T::Type param)// expected-warning {{missing 'typename' prior to dependent type name}}
+{
+ const T::Type var = 2; // expected-warning {{missing 'typename' prior to dependent type name}}
+}
+
+template void function_missing_typename<D>(const D::Type param);
+
+}
+
+
+
+namespace lookup_dependent_bases_id_expr {
+
+template<class T> class A {
+public:
+ int var;
+};
+
+
+template<class T>
+class B : public A<T> {
+public:
+ void f() {
+ var = 3;
+ }
+};
+
+template class B<int>;
+
+} \ No newline at end of file
diff --git a/test/SemaCXX/MicrosoftExtensions.cpp b/test/SemaCXX/MicrosoftExtensions.cpp
index 9b03feb53909..63e058b36daa 100644
--- a/test/SemaCXX/MicrosoftExtensions.cpp
+++ b/test/SemaCXX/MicrosoftExtensions.cpp
@@ -81,6 +81,10 @@ struct M {
float __stdcall subtractP();
};
+// __unaligned handling
+typedef char __unaligned *aligned_type;
+
+
template<typename T> void h1(T (__stdcall M::* const )()) { }
void m1() {
@@ -148,40 +152,6 @@ template <class T>
void BB<T>::f(int g = 0) { } // expected-warning {{redefinition of default argument}}
-namespace MissingTypename {
-
-template<class T> class A {
-public:
- typedef int TYPE;
-};
-
-template<class T> class B {
-public:
- typedef int TYPE;
-};
-
-
-template<class T, class U>
-class C : private A<T>, public B<U> {
-public:
- typedef A<T> Base1;
- typedef B<U> Base2;
- typedef A<U> Base3;
-
- A<T>::TYPE a1; // expected-warning {{missing 'typename' prior to dependent type name}}
- Base1::TYPE a2; // expected-warning {{missing 'typename' prior to dependent type name}}
-
- B<U>::TYPE a3; // expected-warning {{missing 'typename' prior to dependent type name}}
- Base2::TYPE a4; // expected-warning {{missing 'typename' prior to dependent type name}}
-
- A<U>::TYPE a5; // expected-error {{missing 'typename' prior to dependent type name}}
- Base3::TYPE a6; // expected-error {{missing 'typename' prior to dependent type name}}
- };
-
-}
-
-
-
extern void static_func();
void static_func(); // expected-note {{previous declaration is here}}
@@ -209,26 +179,6 @@ void pointer_to_integral_type_conv(char* ptr) {
sh = (short)ptr;
}
-namespace ms_using_declaration_bug {
-
-class A {
-public:
- int f();
-};
-
-class B : public A {
-private:
- using A::f;
-};
-
-class C : public B {
-private:
- using B::f; // expected-warning {{using declaration refers to inaccessible member 'ms_using_declaration_bug::B::f', which refers to accessible member 'ms_using_declaration_bug::A::f', accepted for Microsoft compatibility}}
-};
-
-}
-
-
namespace friend_as_a_forward_decl {
@@ -251,4 +201,5 @@ void f()
Z* b;
}
- } \ No newline at end of file
+}
+
diff --git a/test/SemaCXX/PR10243.cpp b/test/SemaCXX/PR10243.cpp
index 9a5851049803..129ff80e2d2e 100644
--- a/test/SemaCXX/PR10243.cpp
+++ b/test/SemaCXX/PR10243.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct S; // expected-note 4{{forward declaration of 'S'}}
diff --git a/test/SemaCXX/PR10458.cpp b/test/SemaCXX/PR10458.cpp
new file mode 100644
index 000000000000..57588ebcf1f0
--- /dev/null
+++ b/test/SemaCXX/PR10458.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98
+
+void f() {
+ int arr[] = { 1, 2, 3 };
+ for (auto &i : arr) { // expected-warning {{'auto' type specifier is a C++11 extension}} expected-warning {{range-based for loop is a C++11 extension}}
+ }
+}
diff --git a/test/SemaCXX/PR5086-ambig-resolution-enum.cpp b/test/SemaCXX/PR5086-ambig-resolution-enum.cpp
index 720566a69b05..b5aac5f09c16 100644
--- a/test/SemaCXX/PR5086-ambig-resolution-enum.cpp
+++ b/test/SemaCXX/PR5086-ambig-resolution-enum.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
class C {
public:
diff --git a/test/SemaCXX/PR7944.cpp b/test/SemaCXX/PR7944.cpp
index a998a15c3e0b..51b3f6bccec0 100644
--- a/test/SemaCXX/PR7944.cpp
+++ b/test/SemaCXX/PR7944.cpp
@@ -8,5 +8,5 @@ struct A { B* b() { return new B; } };
void g() {
A a;
- MACRO(a.b->f()); // expected-error{{base of member reference is a function}}
+ MACRO(a.b->f()); // expected-error{{reference to non-static member function must be called; did you mean to call it with no arguments?}}
}
diff --git a/test/SemaCXX/PR8012.cpp b/test/SemaCXX/PR8012.cpp
index f2f07ad36400..9cfc2b000c01 100644
--- a/test/SemaCXX/PR8012.cpp
+++ b/test/SemaCXX/PR8012.cpp
@@ -1,3 +1,3 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
void foo (int operator+); // expected-error{{cannot be the name of a parameter}}
diff --git a/test/SemaCXX/PR9572.cpp b/test/SemaCXX/PR9572.cpp
index 25c0c017b7f6..b0bbfa6318cd 100644
--- a/test/SemaCXX/PR9572.cpp
+++ b/test/SemaCXX/PR9572.cpp
@@ -3,7 +3,7 @@ class Base {
virtual ~Base(); // expected-note {{implicitly declared private here}}
};
struct Foo : public Base { // expected-error {{base class 'Base' has private destructor}}
- const int kBlah = 3; // expected-warning {{accepted as a C++0x extension}}
+ const int kBlah = 3; // expected-warning {{accepted as a C++11 extension}}
Foo();
};
struct Bar : public Foo {
diff --git a/test/SemaCXX/PR9902.cpp b/test/SemaCXX/PR9902.cpp
index ec76789b9657..80086e445c5d 100644
--- a/test/SemaCXX/PR9902.cpp
+++ b/test/SemaCXX/PR9902.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template <class _Tp, class _Up, bool = false>
struct __allocator_traits_rebind
diff --git a/test/SemaCXX/PR9908.cpp b/test/SemaCXX/PR9908.cpp
index 3b98b724dd87..fc090cc42f92 100644
--- a/test/SemaCXX/PR9908.cpp
+++ b/test/SemaCXX/PR9908.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template <class _Tp, class _Up>
struct __allocator_traits_rebind
diff --git a/test/SemaCXX/abstract.cpp b/test/SemaCXX/abstract.cpp
index c262230962f9..b164d9eda6a5 100644
--- a/test/SemaCXX/abstract.cpp
+++ b/test/SemaCXX/abstract.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
#ifndef __GXX_EXPERIMENTAL_CXX0X__
#define __CONCAT(__X, __Y) __CONCAT1(__X, __Y)
diff --git a/test/SemaCXX/address-of.cpp b/test/SemaCXX/address-of.cpp
index a7e712b04c1d..69fcaff8f1ed 100644
--- a/test/SemaCXX/address-of.cpp
+++ b/test/SemaCXX/address-of.cpp
@@ -33,3 +33,14 @@ void test2() {
// PR clang/3222
void xpto();
void (*xyz)(void) = &xpto;
+
+struct PR11066 {
+ static int foo(short);
+ static int foo(float);
+ void test();
+};
+
+void PR11066::test() {
+ int (PR11066::*ptr)(int) = & &PR11066::foo; // expected-error{{address expression must be an lvalue or a function designator}}
+}
+
diff --git a/test/SemaCXX/aggregate-initialization.cpp b/test/SemaCXX/aggregate-initialization.cpp
index b9e69b00b7fe..3c0e4483c441 100644
--- a/test/SemaCXX/aggregate-initialization.cpp
+++ b/test/SemaCXX/aggregate-initialization.cpp
@@ -1,9 +1,9 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// Verify that we can't initialize non-aggregates with an initializer
// list.
-// FIXME: Note that due to a (likely) standard bug, this is technically an
-// aggregate.
+// Note that due to a (likely) standard bug, this is technically an aggregate,
+// but we do not treat it as one.
struct NonAggr1 {
NonAggr1(int) { }
@@ -24,7 +24,7 @@ struct NonAggr4 {
virtual void f();
};
-NonAggr1 na1 = { 17 };
+NonAggr1 na1 = { 17 }; // expected-error{{non-aggregate type 'NonAggr1' cannot be initialized with an initializer list}}
NonAggr2 na2 = { 17 }; // expected-error{{non-aggregate type 'NonAggr2' cannot be initialized with an initializer list}}
NonAggr3 na3 = { 17 }; // expected-error{{non-aggregate type 'NonAggr3' cannot be initialized with an initializer list}}
NonAggr4 na4 = { 17 }; // expected-error{{non-aggregate type 'NonAggr4' cannot be initialized with an initializer list}}
diff --git a/test/SemaCXX/alias-template.cpp b/test/SemaCXX/alias-template.cpp
index f29a9327dab3..6cff4206faa4 100644
--- a/test/SemaCXX/alias-template.cpp
+++ b/test/SemaCXX/alias-template.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -std=c++0x %s
+// RUN: %clang_cc1 -verify -std=c++11 %s
namespace RedeclAliasTypedef {
template<typename U> using T = int;
diff --git a/test/SemaCXX/alignof-sizeof-reference.cpp b/test/SemaCXX/alignof-sizeof-reference.cpp
index 93ba203ae112..ccdf45e52dd7 100644
--- a/test/SemaCXX/alignof-sizeof-reference.cpp
+++ b/test/SemaCXX/alignof-sizeof-reference.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
struct s0; // expected-note {{forward declaration}}
char ar[sizeof(s0&)]; // expected-error {{invalid application of 'sizeof' to an incomplete type}}
@@ -8,14 +8,15 @@ void test() {
static_assert(sizeof(r) == 1, "bad size");
}
-void f(); // expected-note{{candidate function}}
-void f(int); // expected-note{{candidate function}}
+void f(); // expected-note{{possible target for call}}
+void f(int); // expected-note{{possible target for call}}
void g() {
- sizeof(&f); // expected-error{{cannot resolve overloaded function 'f' from context}}
+ sizeof(&f); // expected-error{{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}} \
+ // expected-warning{{expression result unused}}
}
-template<typename T> void f_template(); // expected-note{{candidate function}}
-template<typename T> void f_template(T*); // expected-note{{candidate function}}
+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{{cannot resolve overloaded function 'f_template' from context}}
+ (void)alignof(f_template<int>); // expected-error{{reference to overloaded function could not be resolved; did you mean to call it?}}
}
diff --git a/test/SemaCXX/ambig-user-defined-conversions.cpp b/test/SemaCXX/ambig-user-defined-conversions.cpp
index bf45e5d4d888..1a3c102f034c 100644
--- a/test/SemaCXX/ambig-user-defined-conversions.cpp
+++ b/test/SemaCXX/ambig-user-defined-conversions.cpp
@@ -53,7 +53,7 @@ namespace test1 {
E b;
f1(b); // expected-error {{call to 'f1' is ambiguous}}
// ambiguous because b -> C via constructor and
- // b → A via constructor or conversion function.
+ // b -> A via constructor or conversion function.
}
}
diff --git a/test/SemaCXX/ambiguous-builtin-unary-operator.cpp b/test/SemaCXX/ambiguous-builtin-unary-operator.cpp
index 836e319f8404..6e96e03f7245 100644
--- a/test/SemaCXX/ambiguous-builtin-unary-operator.cpp
+++ b/test/SemaCXX/ambiguous-builtin-unary-operator.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
struct A {
operator int&();
diff --git a/test/SemaCXX/array-bounds-ptr-arith.cpp b/test/SemaCXX/array-bounds-ptr-arith.cpp
new file mode 100644
index 000000000000..ce1ace6f2fb6
--- /dev/null
+++ b/test/SemaCXX/array-bounds-ptr-arith.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -verify -Warray-bounds-pointer-arithmetic %s
+
+void swallow (const char *x) { (void)x; }
+void test_pointer_arithmetic(int n) {
+ const char hello[] = "Hello world!"; // expected-note 2 {{declared here}}
+ const char *helloptr = hello;
+
+ swallow("Hello world!" + 6); // no-warning
+ swallow("Hello world!" - 6); // expected-warning {{refers before the beginning of the array}}
+ swallow("Hello world!" + 14); // expected-warning {{refers past the end of the array}}
+ swallow("Hello world!" + 13); // no-warning
+
+ swallow(hello + 6); // no-warning
+ swallow(hello - 6); // expected-warning {{refers before the beginning of the array}}
+ swallow(hello + 14); // expected-warning {{refers past the end of the array}}
+ swallow(hello + 13); // no-warning
+
+ swallow(helloptr + 6); // no-warning
+ swallow(helloptr - 6); // no-warning
+ swallow(helloptr + 14); // no-warning
+ swallow(helloptr + 13); // no-warning
+
+ double numbers[2]; // expected-note {{declared here}}
+ swallow((char*)numbers + sizeof(double)); // no-warning
+ swallow((char*)numbers + 60); // expected-warning {{refers past the end of the array}}
+
+ char buffer[5]; // expected-note 2 {{declared here}}
+ // TODO: Add FixIt notes for adding parens around non-ptr part of arith expr
+ swallow(buffer + sizeof("Hello")-1); // expected-warning {{refers past the end of the array}}
+ swallow(buffer + (sizeof("Hello")-1)); // no-warning
+ if (n > 0 && n <= 6) swallow(buffer + 6 - n); // expected-warning {{refers past the end of the array}}
+ if (n > 0 && n <= 6) swallow(buffer + (6 - n)); // no-warning
+}
diff --git a/test/SemaCXX/array-bounds.cpp b/test/SemaCXX/array-bounds.cpp
index 3bd6c35420d7..555ac33af559 100644
--- a/test/SemaCXX/array-bounds.cpp
+++ b/test/SemaCXX/array-bounds.cpp
@@ -3,9 +3,11 @@
int foo() {
int x[2]; // expected-note 4 {{array 'x' declared here}}
int y[2]; // expected-note 2 {{array 'y' declared here}}
+ int z[1]; // expected-note {{array 'z' declared here}}
int *p = &y[2]; // no-warning
(void) sizeof(x[2]); // no-warning
y[2] = 2; // expected-warning {{array index of '2' indexes past the end of an array (that contains 2 elements)}}
+ z[1] = 'x'; // expected-warning {{array index of '1' indexes past the end of an array (that contains 1 element)}}
return x[2] + // expected-warning {{array index of '2' indexes past the end of an array (that contains 2 elements)}}
y[-1] + // expected-warning {{array index of '-1' indexes before the beginning of the array}}
x[sizeof(x)] + // expected-warning {{array index of '8' indexes past the end of an array (that contains 2 elements)}}
@@ -24,8 +26,8 @@ void f1(int a[1]) {
int val = a[3]; // no warning for function argumnet
}
-void f2(const int (&a)[1]) { // expected-note {{declared here}}
- int val = a[3]; // expected-warning {{array index of '3' indexes past the end of an array (that contains 1 elements)}}
+void f2(const int (&a)[2]) { // expected-note {{declared here}}
+ int val = a[3]; // expected-warning {{array index of '3' indexes past the end of an array (that contains 2 elements)}}
}
void test() {
@@ -35,15 +37,20 @@ void test() {
s2.a[3] = 0; // no warning for 0-sized array
union {
- short a[2]; // expected-note {{declared here}}
+ short a[2]; // expected-note 4 {{declared here}}
char c[4];
} u;
u.a[3] = 1; // expected-warning {{array index of '3' indexes past the end of an array (that contains 2 elements)}}
u.c[3] = 1; // no warning
+ short *p = &u.a[2]; // no warning
+ p = &u.a[3]; // expected-warning {{array index of '3' indexes past the end of an array (that contains 2 elements)}}
+ *(&u.a[2]) = 1; // expected-warning {{array index of '2' indexes past the end of an array (that contains 2 elements)}}
+ *(&u.a[3]) = 1; // expected-warning {{array index of '3' indexes past the end of an array (that contains 2 elements)}}
+ *(&u.c[3]) = 1; // no warning
const int const_subscript = 3;
- int array[1]; // expected-note {{declared here}}
- array[const_subscript] = 0; // expected-warning {{array index of '3' indexes past the end of an array (that contains 1 elements)}}
+ int array[2]; // expected-note {{declared here}}
+ array[const_subscript] = 0; // expected-warning {{array index of '3' indexes past the end of an array (that contains 2 elements)}}
int *ptr;
ptr[3] = 0; // no warning for pointer references
@@ -58,8 +65,8 @@ void test() {
const char str2[] = "foo"; // expected-note {{declared here}}
char c2 = str2[5]; // expected-warning {{array index of '5' indexes past the end of an array (that contains 4 elements)}}
- int (*array_ptr)[1];
- (*array_ptr)[3] = 1; // expected-warning {{array index of '3' indexes past the end of an array (that contains 1 elements)}}
+ int (*array_ptr)[2];
+ (*array_ptr)[3] = 1; // expected-warning {{array index of '3' indexes past the end of an array (that contains 2 elements)}}
}
template <int I> struct S {
@@ -151,8 +158,7 @@ void test_switch() {
enum enumA { enumA_A, enumA_B, enumA_C, enumA_D, enumA_E };
enum enumB { enumB_X, enumB_Y, enumB_Z };
static enum enumB myVal = enumB_X;
-void test_nested_switch()
-{
+void test_nested_switch() {
switch (enumA_E) { // expected-warning {{no case matching constant}}
switch (myVal) { // expected-warning {{enumeration values 'enumB_X' and 'enumB_Z' not handled in switch}}
case enumB_Y: ;
@@ -173,3 +179,59 @@ void test_all_enums_covered(enum Values v) {
}
x[2] = 0; // no-warning
}
+
+namespace tailpad {
+ struct foo {
+ char c1[1]; // expected-note {{declared here}}
+ int x;
+ char c2[1];
+ };
+
+ char bar(struct foo *F) {
+ return F->c1[3]; // expected-warning {{array index of '3' indexes past the end of an array (that contains 1 element)}}
+ return F->c2[3]; // no warning, foo could have tail padding allocated.
+ }
+}
+
+namespace metaprogramming {
+#define ONE 1
+ struct foo { char c[ONE]; }; // expected-note {{declared here}}
+ template <int N> struct bar { char c[N]; }; // expected-note {{declared here}}
+
+ char test(foo *F, bar<1> *B) {
+ return F->c[3] + // expected-warning {{array index of '3' indexes past the end of an array (that contains 1 element)}}
+ B->c[3]; // expected-warning {{array index of '3' indexes past the end of an array (that contains 1 element)}}
+ }
+}
+
+void bar(int x) {}
+int test_more() {
+ int foo[5]; // expected-note 5 {{array 'foo' declared here}}
+ bar(foo[5]); // expected-warning {{array index of '5' indexes past the end of an array (that contains 5 elements)}}
+ ++foo[5]; // expected-warning {{array index of '5' indexes past the end of an array (that contains 5 elements)}}
+ if (foo[6]) // expected-warning {{array index of '6' indexes past the end of an array (that contains 5 elements)}}
+ return --foo[6]; // expected-warning {{array index of '6' indexes past the end of an array (that contains 5 elements)}}
+ else
+ return foo[5]; // expected-warning {{array index of '5' indexes past the end of an array (that contains 5 elements)}}
+}
+
+void test_pr10771() {
+ double foo[4096]; // expected-note {{array 'foo' declared here}}
+
+ ((char*)foo)[sizeof(foo) - 1] = '\0'; // no-warning
+ *(((char*)foo) + sizeof(foo) - 1) = '\0'; // no-warning
+
+ ((char*)foo)[sizeof(foo)] = '\0'; // expected-warning {{array index of '32768' indexes past the end of an array (that contains 32768 elements)}}
+
+ // TODO: This should probably warn, too.
+ *(((char*)foo) + sizeof(foo)) = '\0'; // no-warning
+}
+
+int test_pr11007_aux(const char * restrict, ...);
+
+// Test checking with varargs.
+void test_pr11007() {
+ double a[5]; // expected-note {{array 'a' declared here}}
+ test_pr11007_aux("foo", a[1000]); // expected-warning {{array index of '1000' indexes past the end of an array}}
+}
+
diff --git a/test/SemaCXX/attr-cxx0x.cpp b/test/SemaCXX/attr-cxx0x.cpp
index 725f0182db50..de9d7d1c2a6e 100644
--- a/test/SemaCXX/attr-cxx0x.cpp
+++ b/test/SemaCXX/attr-cxx0x.cpp
@@ -1,15 +1,15 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-int align_illegal [[align(3)]]; //expected-error {{requested alignment is not a power of 2}}
-char align_big [[align(int)]];
-int align_small [[align(1)]]; // FIXME: this should be rejected
-int align_multiple [[align(1), align(8), align(1)]];
+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_multiple alignas(1) alignas(8) alignas(1);
struct align_member {
- int member [[align(8)]];
+ int member alignas(8);
};
-typedef char align_typedef [[align(8)]];
+typedef char align_typedef alignas(8);
template<typename T> using align_alias_template = align_typedef;
static_assert(alignof(align_big) == alignof(int), "k's alignment is wrong");
diff --git a/test/SemaCXX/attr-deprecated.cpp b/test/SemaCXX/attr-deprecated.cpp
index fe7c833d322b..945aff363eb1 100644
--- a/test/SemaCXX/attr-deprecated.cpp
+++ b/test/SemaCXX/attr-deprecated.cpp
@@ -198,7 +198,7 @@ namespace test6 {
};
void testA() {
A x; // expected-warning {{'A' is deprecated}}
- x = a0;
+ x = a0; // expected-warning {{'A' is deprecated}}
}
enum B {
@@ -218,7 +218,7 @@ namespace test6 {
};
void testC() {
C<int>::Enum x; // expected-warning {{'Enum' is deprecated}}
- x = C<int>::c0;
+ x = C<int>::c0; // expected-warning {{'Enum' is deprecated}}
}
template <class T> struct D {
diff --git a/test/SemaCXX/auto-cxx0x.cpp b/test/SemaCXX/auto-cxx0x.cpp
index f9246beff92a..a8f9e84423a7 100644
--- a/test/SemaCXX/auto-cxx0x.cpp
+++ b/test/SemaCXX/auto-cxx0x.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
void f() {
- auto int a; // expected-warning {{'auto' storage class specifier is redundant and will be removed in future releases}}
+ auto int a; // expected-warning {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
int auto b; // expected-error{{cannot combine with previous 'int' declaration specifier}}
}
diff --git a/test/SemaCXX/auto-cxx98.cpp b/test/SemaCXX/auto-cxx98.cpp
index fe028114880a..6c401ba11a93 100644
--- a/test/SemaCXX/auto-cxx98.cpp
+++ b/test/SemaCXX/auto-cxx98.cpp
@@ -1,5 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98
void f() {
- auto int a;
- int auto b;
+ auto int a; // expected-warning {{'auto' storage class specifier is redundant and incompatible with C++11}}
+ int auto b; // expected-warning {{'auto' storage class specifier is redundant and incompatible with C++11}}
+ auto c; // expected-warning {{C++11 extension}} expected-error {{requires an initializer}}
+ static auto d = 0; // expected-warning {{C++11 extension}}
+ auto static e = 0; // expected-warning {{C++11 extension}}
}
diff --git a/test/SemaCXX/auto-subst-failure.cpp b/test/SemaCXX/auto-subst-failure.cpp
index 442c7e82ccdb..b323dfc6b049 100644
--- a/test/SemaCXX/auto-subst-failure.cpp
+++ b/test/SemaCXX/auto-subst-failure.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
void f() {
auto a = f(); // expected-error {{variable has incomplete type 'void'}}
diff --git a/test/SemaCXX/bool.cpp b/test/SemaCXX/bool.cpp
index 726fa6cb60fc..2b3ab68848eb 100644
--- a/test/SemaCXX/bool.cpp
+++ b/test/SemaCXX/bool.cpp
@@ -25,6 +25,9 @@ void static_assert_arg_is_bool(T x) {
void test2() {
int n = 2;
- static_assert_arg_is_bool(n && 4); // expected-warning {{use of logical && with constant operand}}
- static_assert_arg_is_bool(n || 5); // expected-warning {{use of logical || with constant operand}}
+ static_assert_arg_is_bool(n && 4); // expected-warning {{use of logical '&&' with constant operand}} \
+ // expected-note {{use '&' for a bitwise operation}} \
+ // expected-note {{remove constant to silence this warning}}
+ static_assert_arg_is_bool(n || 5); // expected-warning {{use of logical '||' with constant operand}} \
+ // expected-note {{use '|' for a bitwise operation}}
}
diff --git a/test/SemaCXX/builtin-ptrtomember-ambig.cpp b/test/SemaCXX/builtin-ptrtomember-ambig.cpp
index 32a893dafcef..61e347879a75 100644
--- a/test/SemaCXX/builtin-ptrtomember-ambig.cpp
+++ b/test/SemaCXX/builtin-ptrtomember-ambig.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
struct A {};
diff --git a/test/SemaCXX/builtin-ptrtomember-overload-1.cpp b/test/SemaCXX/builtin-ptrtomember-overload-1.cpp
index f736394a4caa..2d93c6b2dff3 100644
--- a/test/SemaCXX/builtin-ptrtomember-overload-1.cpp
+++ b/test/SemaCXX/builtin-ptrtomember-overload-1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
struct A {};
struct E {};
diff --git a/test/SemaCXX/builtin-ptrtomember-overload.cpp b/test/SemaCXX/builtin-ptrtomember-overload.cpp
index 6c132366199b..c7b5173a4fbe 100644
--- a/test/SemaCXX/builtin-ptrtomember-overload.cpp
+++ b/test/SemaCXX/builtin-ptrtomember-overload.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
struct A {};
diff --git a/test/SemaCXX/cast-conversion.cpp b/test/SemaCXX/cast-conversion.cpp
index 80707d13d20b..dd2bc98e02cc 100644
--- a/test/SemaCXX/cast-conversion.cpp
+++ b/test/SemaCXX/cast-conversion.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
struct R {
R(int);
@@ -8,7 +8,8 @@ struct A {
A(R);
};
-struct B { // expected-note 3 {{candidate constructor (the implicit copy constructor) not viable}}
+struct B { // expected-note 3 {{candidate constructor (the implicit copy constructor) not viable}} \
+ expected-note 3 {{candidate constructor (the implicit move constructor) not viable}}
B(A); // expected-note 3 {{candidate constructor not viable}}
};
diff --git a/test/SemaCXX/class.cpp b/test/SemaCXX/class.cpp
index 44fa0ce7ec9f..160f365f4bbf 100644
--- a/test/SemaCXX/class.cpp
+++ b/test/SemaCXX/class.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
class C {
public:
- auto int errx; // expected-error {{error: storage class specified for a member declaration}}
+ auto int errx; // expected-error {{error: storage class specified for a member declaration}} expected-warning {{'auto' storage class specifier is redundant}}
register int erry; // expected-error {{error: storage class specified for a member declaration}}
extern int errz; // expected-error {{error: storage class specified for a member declaration}}
@@ -34,11 +34,12 @@ public:
enum E1 { en1, en2 };
- int i = 0; // expected-warning {{in-class initialization of non-static data member accepted as a C++0x extension}}
+ int i = 0; // expected-warning {{in-class initialization of non-static data member accepted as a C++11 extension}}
static int si = 0; // expected-error {{non-const static data member must be initialized out of line}}
static const NestedC ci = 0; // expected-error {{static data member of type 'const C::NestedC' must be initialized out of line}}
static const int nci = vs; // expected-error {{in-class initializer is not a constant expression}}
static const int vi = 0;
+ static const volatile int cvi = 0; // ok, illegal in C++11
static const E evi = 0;
void m() {
@@ -172,8 +173,8 @@ namespace rdar8367341 {
float foo();
struct A {
- static const float x = 5.0f; // expected-warning {{in-class initializer for static data member of type 'const float' is a C++0x extension}}
- static const float y = foo(); // expected-warning {{in-class initializer for static data member of type 'const float' is a C++0x extension}} expected-error {{in-class initializer is not a constant expression}}
+ static const float x = 5.0f; // expected-warning {{in-class initializer for static data member of type 'const float' is a GNU extension}}
+ static const float y = foo(); // expected-warning {{in-class initializer for static data member of type 'const float' is a GNU extension}} expected-error {{in-class initializer is not a constant expression}}
};
}
@@ -188,3 +189,7 @@ void f() {
S::c; // expected-error {{invalid use of nonstatic data member}}
}
}
+
+struct PR9989 {
+ static int const PR9989_Member = sizeof PR9989_Member;
+};
diff --git a/test/SemaCXX/compare.cpp b/test/SemaCXX/compare.cpp
index ca8af2186f74..28e2dd0ad51a 100644
--- a/test/SemaCXX/compare.cpp
+++ b/test/SemaCXX/compare.cpp
@@ -212,3 +212,14 @@ static const unsigned int kMax = 0;
int pr7536() {
return (kMax > 0);
}
+
+// -Wsign-compare should not warn when ?: operands have different signedness.
+// This will be caught by -Wsign-conversion
+void test3() {
+ unsigned long a;
+ signed long b;
+ (void) (true ? a : b);
+ (void) (true ? (unsigned int)a : (signed int)b);
+ (void) (true ? b : a);
+ (void) (true ? (unsigned char)b : (signed char)a);
+}
diff --git a/test/SemaCXX/complex-init-list.cpp b/test/SemaCXX/complex-init-list.cpp
new file mode 100644
index 000000000000..e75833a37dbc
--- /dev/null
+++ b/test/SemaCXX/complex-init-list.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -pedantic
+
+// This file tests the clang extension which allows initializing the components
+// of a complex number individually using an initialization list. Basically,
+// if you have an explicit init list for a complex number that contains two
+// initializers, this extension kicks in to turn it into component-wise
+// initialization.
+//
+// See also the testcase for the C version of this extension in
+// test/Sema/complex-init-list.c.
+
+// Basic testcase
+// (No pedantic warning is necessary because _Complex is not part of C++.)
+_Complex float valid1 = { 1.0f, 2.0f };
diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp
index b95700e9ba18..5648d022b522 100644
--- a/test/SemaCXX/conditional-expr.cpp
+++ b/test/SemaCXX/conditional-expr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++0x -Wsign-compare %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -Wsign-conversion %s
// C++ rules for ?: are a lot stricter than C rules, and have to take into
// account more conversion options.
@@ -180,12 +180,12 @@ void test()
unsigned long test0 = 5;
- test0 = test0 ? (long) test0 : test0; // expected-warning {{operands of ? are integers of different signs}}
- test0 = test0 ? (int) test0 : test0; // expected-warning {{operands of ? are integers of different signs}}
- test0 = test0 ? (short) test0 : test0; // expected-warning {{operands of ? are integers of different signs}}
- test0 = test0 ? test0 : (long) test0; // expected-warning {{operands of ? are integers of different signs}}
- test0 = test0 ? test0 : (int) test0; // expected-warning {{operands of ? are integers of different signs}}
- test0 = test0 ? test0 : (short) test0; // expected-warning {{operands of ? are integers of different signs}}
+ test0 = test0 ? (long) test0 : test0; // expected-warning {{operand of ? changes signedness: 'long' to 'unsigned long'}}
+ test0 = test0 ? (int) test0 : test0; // expected-warning {{operand of ? changes signedness: 'int' to 'unsigned long'}}
+ test0 = test0 ? (short) test0 : test0; // expected-warning {{operand of ? changes signedness: 'short' to 'unsigned long'}}
+ test0 = test0 ? test0 : (long) test0; // expected-warning {{operand of ? changes signedness: 'long' to 'unsigned long'}}
+ test0 = test0 ? test0 : (int) test0; // expected-warning {{operand of ? changes signedness: 'int' to 'unsigned long'}}
+ test0 = test0 ? test0 : (short) test0; // expected-warning {{operand of ? changes signedness: 'short' to 'unsigned long'}}
test0 = test0 ? test0 : (long) 10;
test0 = test0 ? test0 : (int) 10;
test0 = test0 ? test0 : (short) 10;
@@ -193,8 +193,15 @@ void test()
test0 = test0 ? (int) 10 : test0;
test0 = test0 ? (short) 10 : test0;
+ int test1;
test0 = test0 ? EVal : test0;
- test0 = test0 ? EVal : (int) test0;
+ test1 = test0 ? EVal : (int) test0;
+
+ test0 = test0 ? EVal : test1; // expected-warning {{operand of ? changes signedness: 'int' to 'unsigned long'}}
+ test0 = test0 ? test1 : EVal; // expected-warning {{operand of ? changes signedness: 'int' to 'unsigned long'}}
+
+ test1 = test0 ? EVal : (int) test0;
+ test1 = test0 ? (int) test0 : EVal;
// Note the thing that this does not test: since DR446, various situations
// *must* create a separate temporary copy of class objects. This can only
diff --git a/test/SemaCXX/conversion-delete-expr.cpp b/test/SemaCXX/conversion-delete-expr.cpp
index 862ae5ae02bb..0f298a819fa3 100644
--- a/test/SemaCXX/conversion-delete-expr.cpp
+++ b/test/SemaCXX/conversion-delete-expr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// Test1
struct B {
diff --git a/test/SemaCXX/convert-to-bool.cpp b/test/SemaCXX/convert-to-bool.cpp
index 4cd22e90c0e0..c9a355549fdf 100644
--- a/test/SemaCXX/convert-to-bool.cpp
+++ b/test/SemaCXX/convert-to-bool.cpp
@@ -8,7 +8,7 @@ struct ConvToInt {
};
struct ExplicitConvToBool {
- explicit operator bool(); // expected-warning{{explicit conversion functions are a C++0x extension}}
+ explicit operator bool(); // expected-warning{{explicit conversion functions are a C++11 extension}}
};
void test_conv_to_bool(ConvToBool ctb, ConvToInt cti, ExplicitConvToBool ecb) {
@@ -39,7 +39,7 @@ void test_conv_to_bool(ConvToBool ctb, ConvToInt cti, ExplicitConvToBool ecb) {
void accepts_bool(bool) { } // expected-note{{candidate function}}
struct ExplicitConvToRef {
- explicit operator int&(); // expected-warning{{explicit conversion functions are a C++0x extension}}
+ explicit operator int&(); // expected-warning{{explicit conversion functions are a C++11 extension}}
};
void test_explicit_bool(ExplicitConvToBool ecb) {
@@ -56,7 +56,7 @@ void test_explicit_conv_to_ref(ExplicitConvToRef ecr) {
struct A { };
struct B { };
struct C {
- explicit operator A&(); // expected-warning{{explicit conversion functions are a C++0x extension}}
+ explicit operator A&(); // expected-warning{{explicit conversion functions are a C++11 extension}}
operator B&(); // expected-note{{candidate}}
};
diff --git a/test/SemaCXX/cxx0x-class.cpp b/test/SemaCXX/cxx0x-class.cpp
new file mode 100644
index 000000000000..3527ccb55577
--- /dev/null
+++ b/test/SemaCXX/cxx0x-class.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+int vs = 0;
+
+class C {
+public:
+ struct NestedC {
+ NestedC(int);
+ };
+
+ int i = 0;
+ static int si = 0; // expected-error {{non-const static data member must be initialized out of line}}
+ static const NestedC ci = 0; // expected-error {{static data member of type 'const C::NestedC' must be initialized out of line}}
+ static const int nci = vs; // expected-error {{in-class initializer is not a constant expression}}
+ static const int vi = 0;
+ static const volatile int cvi = 0; // expected-error {{static const volatile data member must be initialized out of line}}
+};
+
+namespace rdar8367341 {
+ float foo();
+
+ 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 is not a constant expression}}
+ static constexpr float x2 = 5.0f;
+ static constexpr float y2 = foo(); // expected-error {{must be initialized by a constant expression}}
+ };
+}
diff --git a/test/SemaCXX/cxx0x-compat.cpp b/test/SemaCXX/cxx0x-compat.cpp
new file mode 100644
index 000000000000..a01b26c5f91b
--- /dev/null
+++ b/test/SemaCXX/cxx0x-compat.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Wc++0x-compat -verify %s
+
+namespace N {
+ template<typename T> void f(T) {} // expected-note {{here}}
+ namespace M {
+ template void f<int>(int); // expected-warning {{explicit instantiation of 'N::f' must occur in namespace 'N'}}
+ }
+}
+
+template<typename T> void f(T) {} // expected-note {{here}}
+namespace M {
+ template void f<int>(int); // expected-warning {{explicit instantiation of 'f' must occur in the global namespace}}
+}
+
+void f() {
+ auto int n = 0; // expected-warning {{'auto' storage class specifier is redundant and incompatible with C++11}}
+}
+
+int n;
+struct S {
+ char c;
+}
+s = { n }, // expected-warning {{non-constant-expression cannot be narrowed from type 'int' to 'char' in initializer list in C++11}} expected-note {{explicit cast}}
+t = { 1234 }; // expected-warning {{constant expression evaluates to 1234 which cannot be narrowed to type 'char' in C++11}} expected-warning {{changes value}} expected-note {{explicit cast}}
diff --git a/test/SemaCXX/cxx0x-constexpr-const.cpp b/test/SemaCXX/cxx0x-constexpr-const.cpp
index 79e6dda3e11c..197edeb097b6 100644
--- a/test/SemaCXX/cxx0x-constexpr-const.cpp
+++ b/test/SemaCXX/cxx0x-constexpr-const.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
constexpr int x = 1;
constexpr int id(int x) { return x; }
diff --git a/test/SemaCXX/cxx0x-cursory-default-delete.cpp b/test/SemaCXX/cxx0x-cursory-default-delete.cpp
index 61aee0e45633..17933c2f009a 100644
--- a/test/SemaCXX/cxx0x-cursory-default-delete.cpp
+++ b/test/SemaCXX/cxx0x-cursory-default-delete.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
struct non_copiable {
non_copiable(const non_copiable&) = delete; // expected-note {{marked deleted here}}
@@ -35,7 +35,7 @@ struct bad_decls {
bad_decls(volatile bad_decls&) = default; // expected-error {{may not be volatile}}
bad_decls&& operator = (bad_decls) = default; // expected-error 2{{lvalue reference}}
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' or 'volatile' qualifiers}}
+ bad_decls& operator = (const bad_decls&) const = default; // expected-error {{may not have 'const', 'constexpr' or 'volatile' qualifiers}}
};
struct A {}; struct B {};
diff --git a/test/SemaCXX/cxx0x-defaulted-functions.cpp b/test/SemaCXX/cxx0x-defaulted-functions.cpp
index 86c5fd10e23c..d01f63bedb6b 100644
--- a/test/SemaCXX/cxx0x-defaulted-functions.cpp
+++ b/test/SemaCXX/cxx0x-defaulted-functions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
void fn() = default; // expected-error {{only special member}}
struct foo {
diff --git a/test/SemaCXX/cxx0x-delegating-ctors.cpp b/test/SemaCXX/cxx0x-delegating-ctors.cpp
index a3e6ff3b4f92..2d49f0fc599d 100644
--- a/test/SemaCXX/cxx0x-delegating-ctors.cpp
+++ b/test/SemaCXX/cxx0x-delegating-ctors.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
struct foo {
int i;
diff --git a/test/SemaCXX/cxx0x-deleted-default-ctor.cpp b/test/SemaCXX/cxx0x-deleted-default-ctor.cpp
index dcb6ba2790be..16c56642c06b 100644
--- a/test/SemaCXX/cxx0x-deleted-default-ctor.cpp
+++ b/test/SemaCXX/cxx0x-deleted-default-ctor.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
struct non_trivial {
non_trivial();
@@ -118,3 +118,15 @@ struct late_delete {
late_delete();
};
late_delete::late_delete() = default; // expected-error {{would delete it}}
+
+// See also rdar://problem/8125400.
+namespace empty {
+ static union {}; // expected-error {{deleted constructor}} expected-note {{here}}
+ static union { union {}; };
+ static union { struct {}; };
+ static union { union { union {}; }; };
+ static union { union { struct {}; }; };
+ static union { struct { union {}; }; }; // expected-error {{deleted constructor}} expected-note {{here}}
+ static union { struct { struct {}; }; };
+}
+
diff --git a/test/SemaCXX/cxx0x-initializer-scalars.cpp b/test/SemaCXX/cxx0x-initializer-scalars.cpp
new file mode 100644
index 000000000000..41fc2193891c
--- /dev/null
+++ b/test/SemaCXX/cxx0x-initializer-scalars.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+namespace integral {
+
+ void initialization() {
+ { const int a{}; static_assert(a == 0, ""); }
+ { const int a = {}; static_assert(a == 0, ""); }
+ { const int a{1}; static_assert(a == 1, ""); }
+ { const int a = {1}; static_assert(a == 1, ""); }
+ { const int a{1, 2}; } // expected-error {{excess elements}}
+ { const int a = {1, 2}; } // expected-error {{excess elements}}
+ // FIXME: Redundant warnings.
+ { const short a{100000}; } // expected-error {{cannot be narrowed}} expected-note {{inserting an explicit cast}} expected-warning {{changes value}}
+ { const short a = {100000}; } // expected-error {{cannot be narrowed}} expected-note {{inserting an explicit cast}} expected-warning {{changes value}}
+ }
+
+ int direct_usage() {
+ int ar[10];
+ (void) ar[{1}]; // expected-error {{array subscript is not an integer}}
+
+ return {1};
+ }
+
+ void inline_init() {
+ (void) int{1};
+ (void) new int{1};
+ }
+
+ struct A {
+ int i;
+ A() : i{1} {}
+ };
+
+}
diff --git a/test/SemaCXX/cxx0x-nontrivial-union.cpp b/test/SemaCXX/cxx0x-nontrivial-union.cpp
index 666e64be66ab..6275af6bac52 100644
--- a/test/SemaCXX/cxx0x-nontrivial-union.cpp
+++ b/test/SemaCXX/cxx0x-nontrivial-union.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
struct non_trivial {
non_trivial();
diff --git a/test/SemaCXX/cxx0x-return-init-list.cpp b/test/SemaCXX/cxx0x-return-init-list.cpp
index 2005a7f9f676..b786922b71a8 100644
--- a/test/SemaCXX/cxx0x-return-init-list.cpp
+++ b/test/SemaCXX/cxx0x-return-init-list.cpp
@@ -1,17 +1,17 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// This test checks for a teeny tiny subset of the functionality in
-// the C++0x generalized initializer lists feature, which happens to
+// the C++11 generalized initializer lists feature, which happens to
// be used in libstdc++ 4.5. We accept only this syntax so that Clang
// can handle the libstdc++ 4.5 headers.
int test0(int i) {
- return { i }; // expected-warning{{generalized initializer lists are a C++0x extension unsupported in Clang}}
+ return { i }; // expected-warning{{generalized initializer lists are a C++11 extension unsupported in Clang}}
}
template<typename T, typename U>
T test1(U u) {
- return { u }; // expected-warning{{generalized initializer lists are a C++0x extension unsupported in Clang}}
+ return { u }; // expected-warning{{generalized initializer lists are a C++11 extension unsupported in Clang}}
}
template int test1(char);
diff --git a/test/SemaCXX/cxx0x-type-convert-construct.cpp b/test/SemaCXX/cxx0x-type-convert-construct.cpp
new file mode 100644
index 000000000000..6a7fe45281f5
--- /dev/null
+++ b/test/SemaCXX/cxx0x-type-convert-construct.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -std=gnu++11 -fsyntax-only -verify %s
+
+void f() {
+ char *u8str;
+ u8str = u8"a UTF-8 string"; // expected-error {{assigning to 'char *' from incompatible type 'const char [15]'}}
+ char16_t *ustr;
+ ustr = u"a UTF-16 string"; // expected-error {{assigning to 'char16_t *' from incompatible type 'const char16_t [16]'}}
+ char32_t *Ustr;
+ Ustr = U"a UTF-32 string"; // expected-error {{assigning to 'char32_t *' from incompatible type 'const char32_t [16]'}}
+
+ char *Rstr;
+ Rstr = R"foo(a raw string)foo"; // expected-warning{{conversion from string literal to 'char *' is deprecated}}
+ wchar_t *LRstr;
+ LRstr = LR"foo(a wide raw string)foo"; // expected-warning{{conversion from string literal to 'wchar_t *' is deprecated}}
+ char *u8Rstr;
+ u8Rstr = u8R"foo(a UTF-8 raw string)foo"; // expected-error {{assigning to 'char *' from incompatible type 'const char [19]'}}
+ char16_t *uRstr;
+ uRstr = uR"foo(a UTF-16 raw string)foo"; // expected-error {{assigning to 'char16_t *' from incompatible type 'const char16_t [20]'}}
+ char32_t *URstr;
+ URstr = UR"foo(a UTF-32 raw string)foo"; // expected-error {{assigning to 'char32_t *' from incompatible type 'const char32_t [20]'}}
+}
diff --git a/test/SemaCXX/cxx98-compat-pedantic.cpp b/test/SemaCXX/cxx98-compat-pedantic.cpp
new file mode 100644
index 000000000000..2ca0ae4d1ec8
--- /dev/null
+++ b/test/SemaCXX/cxx98-compat-pedantic.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat-pedantic -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Werror %s
+
+// -Wc++98-compat-pedantic warns on C++11 features which we accept without a
+// warning in C++98 mode.
+
+#line 32767 // ok
+#line 32768 // expected-warning {{#line number greater than 32767 is incompatible with C++98}}
+
+#define VA_MACRO(x, ...) x // expected-warning {{variadic macros are incompatible with C++98}}
+VA_MACRO(,x) // expected-warning {{empty macro argument list is incompatible with C++98}}
diff --git a/test/SemaCXX/cxx98-compat.cpp b/test/SemaCXX/cxx98-compat.cpp
new file mode 100644
index 000000000000..6a3881cf4217
--- /dev/null
+++ b/test/SemaCXX/cxx98-compat.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -verify %s
+
+template<typename ...T> // expected-warning {{variadic templates are incompatible with C++98}}
+class Variadic1 {};
+
+template<template<typename> class ...T> // expected-warning {{variadic templates are incompatible with C++98}}
+class Variadic2 {};
+
+template<int ...I> // expected-warning {{variadic templates are incompatible with C++98}}
+class Variadic3 {};
+
+int alignas(8) with_alignas; // expected-warning {{'alignas' is incompatible with C++98}}
+int with_attribute [[ ]]; // expected-warning {{attributes are incompatible with C++98}}
+
+void Literals() {
+ (void)u8"str"; // expected-warning {{unicode literals are incompatible with C++98}}
+ (void)u"str"; // expected-warning {{unicode literals are incompatible with C++98}}
+ (void)U"str"; // expected-warning {{unicode literals are incompatible with C++98}}
+ (void)u'x'; // expected-warning {{unicode literals are incompatible with C++98}}
+ (void)U'x'; // expected-warning {{unicode literals are incompatible with C++98}}
+
+ (void)u8R"X(str)X"; // expected-warning {{raw string literals are incompatible with C++98}}
+ (void)uR"X(str)X"; // expected-warning {{raw string literals are incompatible with C++98}}
+ (void)UR"X(str)X"; // expected-warning {{raw string literals are incompatible with C++98}}
+ (void)R"X(str)X"; // expected-warning {{raw string literals are incompatible with C++98}}
+ (void)LR"X(str)X"; // expected-warning {{raw string literals are incompatible with C++98}}
+}
+
+template<typename T> struct S {};
+S<::S<void> > s; // expected-warning {{'<::' is treated as digraph '<:' (aka '[') followed by ':' in C++98}}
diff --git a/test/SemaCXX/decl-init-ref.cpp b/test/SemaCXX/decl-init-ref.cpp
index 34c4578e9d6d..4c635c1a2447 100644
--- a/test/SemaCXX/decl-init-ref.cpp
+++ b/test/SemaCXX/decl-init-ref.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct A {};
diff --git a/test/SemaCXX/decltype-crash.cpp b/test/SemaCXX/decltype-crash.cpp
index f94ba453ffb4..50b3e49b78a5 100644
--- a/test/SemaCXX/decltype-crash.cpp
+++ b/test/SemaCXX/decltype-crash.cpp
@@ -3,5 +3,5 @@
int& a();
void f() {
- decltype(a()) c; // expected-error {{use of undeclared identifier 'decltype'}}
+ decltype(a()) c; // expected-warning {{'decltype' is a keyword in C++11}} expected-error {{use of undeclared identifier 'decltype'}}
}
diff --git a/test/SemaCXX/decltype-overloaded-functions.cpp b/test/SemaCXX/decltype-overloaded-functions.cpp
index f4aacd64ddbc..b0a43a999bb6 100644
--- a/test/SemaCXX/decltype-overloaded-functions.cpp
+++ b/test/SemaCXX/decltype-overloaded-functions.cpp
@@ -1,15 +1,15 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
-void f(); // expected-note{{candidate function}}
-void f(int); // expected-note{{candidate function}}
-decltype(f) a; // expected-error{{cannot resolve overloaded function 'f' from context}}
+void f(); // expected-note{{possible target for call}}
+void f(int); // expected-note{{possible target for call}}
+decltype(f) a; // expected-error{{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}} expected-error {{variable has incomplete type 'decltype(f())' (aka 'void')}}
template<typename T> struct S {
- decltype(T::f) * f; // expected-error{{cannot resolve overloaded function 'f' from context}}
+ decltype(T::f) * f; // expected-error{{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}} expected-error {{call to non-static member function without an object argument}}
};
struct K {
- void f(); // expected-note{{candidate function}}
- void f(int); // expected-note{{candidate function}}
+ void f(); // expected-note{{possible target for call}}
+ void f(int); // expected-note{{possible target for call}}
};
S<K> b; // expected-note{{in instantiation of template class 'S<K>' requested here}}
diff --git a/test/SemaCXX/decltype-pr4444.cpp b/test/SemaCXX/decltype-pr4444.cpp
index 456b22c5f7f2..2f95075067a4 100644
--- a/test/SemaCXX/decltype-pr4444.cpp
+++ b/test/SemaCXX/decltype-pr4444.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
template<typename T, T t>
struct TestStruct {
diff --git a/test/SemaCXX/decltype-pr4448.cpp b/test/SemaCXX/decltype-pr4448.cpp
index ead24ce0ca86..9d33ce7341a2 100644
--- a/test/SemaCXX/decltype-pr4448.cpp
+++ b/test/SemaCXX/decltype-pr4448.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
template< typename T, T t, decltype(t+2) v >
struct Convoluted {};
diff --git a/test/SemaCXX/decltype-this.cpp b/test/SemaCXX/decltype-this.cpp
index f9bf49973b5c..a13416f089dd 100644
--- a/test/SemaCXX/decltype-this.cpp
+++ b/test/SemaCXX/decltype-this.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<typename T, typename U> struct is_same {
static const bool value = false;
diff --git a/test/SemaCXX/decltype.cpp b/test/SemaCXX/decltype.cpp
index f61a92b71e1e..78fb8ef02078 100644
--- a/test/SemaCXX/decltype.cpp
+++ b/test/SemaCXX/decltype.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// PR5290
int const f0();
diff --git a/test/SemaCXX/defaulted-ctor-loop.cpp b/test/SemaCXX/defaulted-ctor-loop.cpp
index 6a41972cf75a..6416336c6eed 100644
--- a/test/SemaCXX/defaulted-ctor-loop.cpp
+++ b/test/SemaCXX/defaulted-ctor-loop.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// WARNING: This test may recurse infinitely if failing.
diff --git a/test/SemaCXX/delete.cpp b/test/SemaCXX/delete.cpp
index 4567888a37b1..5824facc507b 100644
--- a/test/SemaCXX/delete.cpp
+++ b/test/SemaCXX/delete.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: cp %s %t
// RUN: %clang_cc1 -fixit -x c++ %t
-// RUN: FileCheck -input-file=%t %s
+// RUN: %clang_cc1 -E -o - %t | FileCheck %s
void f(int a[10][20]) {
// CHECK: delete[] a;
diff --git a/test/SemaCXX/deleted-function.cpp b/test/SemaCXX/deleted-function.cpp
index 6a8965ceb578..4620a19d46fb 100644
--- a/test/SemaCXX/deleted-function.cpp
+++ b/test/SemaCXX/deleted-function.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
int i = delete; // expected-error {{only functions can have deleted definitions}}
diff --git a/test/SemaCXX/deleted-operator.cpp b/test/SemaCXX/deleted-operator.cpp
new file mode 100644
index 000000000000..e357401bf942
--- /dev/null
+++ b/test/SemaCXX/deleted-operator.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+struct PR10757 {
+ bool operator~() = delete; // expected-note {{explicitly deleted}}
+ bool operator==(const PR10757&) = delete; // expected-note {{explicitly deleted}}
+ operator float();
+};
+int PR10757f() {
+ PR10757 a1;
+ // FIXME: We get a ridiculous number of "built-in candidate" notes here...
+ if(~a1) {} // expected-error {{overload resolution selected deleted operator}} expected-note 6 {{built-in candidate}}
+ if(a1==a1) {} // expected-error {{overload resolution selected deleted operator}} expected-note 81 {{built-in candidate}}
+}
diff --git a/test/SemaCXX/dependent-auto.cpp b/test/SemaCXX/dependent-auto.cpp
index 52b15eda7324..1be1566bb3b0 100644
--- a/test/SemaCXX/dependent-auto.cpp
+++ b/test/SemaCXX/dependent-auto.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
template<typename T>
struct only {
diff --git a/test/SemaCXX/dependent-noexcept-unevaluated.cpp b/test/SemaCXX/dependent-noexcept-unevaluated.cpp
index 5bf6f9e96a12..8066b859f189 100644
--- a/test/SemaCXX/dependent-noexcept-unevaluated.cpp
+++ b/test/SemaCXX/dependent-noexcept-unevaluated.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s
template <class T>
T&&
diff --git a/test/SemaCXX/dependent-types.cpp b/test/SemaCXX/dependent-types.cpp
index 053e79bb6981..13ed72f7231e 100644
--- a/test/SemaCXX/dependent-types.cpp
+++ b/test/SemaCXX/dependent-types.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -pedantic -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -verify -std=c++11 %s
template<typename T> using U = int &;
diff --git a/test/SemaCXX/destructor.cpp b/test/SemaCXX/destructor.cpp
index ec0539b81901..14a0cda8df35 100644
--- a/test/SemaCXX/destructor.cpp
+++ b/test/SemaCXX/destructor.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -verify %s
class A {
public:
~A();
diff --git a/test/SemaCXX/enum-bitfield.cpp b/test/SemaCXX/enum-bitfield.cpp
index a766116b1c3c..1a657408f8a6 100644
--- a/test/SemaCXX/enum-bitfield.cpp
+++ b/test/SemaCXX/enum-bitfield.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++0x -verify -triple x86_64-apple-darwin %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++11 -verify -triple x86_64-apple-darwin %s
enum E {};
diff --git a/test/SemaCXX/enum-scoped.cpp b/test/SemaCXX/enum-scoped.cpp
index 73e7578ecb6e..35ba1b4017ae 100644
--- a/test/SemaCXX/enum-scoped.cpp
+++ b/test/SemaCXX/enum-scoped.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++0x -verify -triple x86_64-apple-darwin %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++11 -verify -triple x86_64-apple-darwin %s
enum class E1 {
Val1 = 1L
diff --git a/test/SemaCXX/explicit.cpp b/test/SemaCXX/explicit.cpp
index 717ed1e3caf2..11b9672a8501 100644
--- a/test/SemaCXX/explicit.cpp
+++ b/test/SemaCXX/explicit.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
namespace Constructor {
struct A {
A(int);
@@ -36,4 +36,149 @@ namespace Conversion {
void f(A a, B b) {
b.f(a);
}
+
+ void testExplicit()
+ {
+ // Taken from 12.3.2p2
+ class Y { }; // expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y &' for 1st argument}} \
+ expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y &&' for 1st argument}} \
+ expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y &' for 1st argument}} \
+ expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y' for 1st argument}} \
+ expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y' for 1st argument}} \
+ expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y' for 1st argument}} \
+ expected-note {{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}} \
+ expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y' for 1st argument}} \
+ expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y' for 1st argument}} \
+ expected-note {{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}} \
+ expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y' for 1st argument}} \
+ expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y &&' for 1st argument}} \
+ expected-note {{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}}
+ struct Z {
+ explicit operator Y() const;
+ explicit operator int() const;
+ };
+
+ Z z;
+ // 13.3.1.4p1 & 8.5p16:
+ Y y2 = z; // expected-error {{no viable conversion from 'Conversion::Z' to 'Conversion::Y'}}
+ // FIXME: These are well-formed per C++0x 13.3.1.4p1 (see DR899).
+ Y y3 = (Y)z; // expected-error {{no matching conversion for C-style cast from 'Conversion::Z' to 'Conversion::Y''}}
+ Y y4 = Y(z); // expected-error {{no matching conversion for functional-style cast from 'Conversion::Z' to 'Conversion::Y'}}
+ Y y5 = static_cast<Y>(z); // expected-error {{no matching conversion for static_cast from 'Conversion::Z' to 'Conversion::Y'}}
+ // 13.3.1.5p1 & 8.5p16:
+ int i1 = (int)z;
+ int i2 = int(z);
+ int i3 = static_cast<int>(z);
+ int i4(z);
+ // 13.3.1.6p1 & 8.5.3p5:
+ const Y& y6 = z; // expected-error {{no viable conversion from 'Conversion::Z' to 'const Conversion::Y'}}
+ const int& y7(z);
+ }
+
+ void testBool() {
+ struct Bool {
+ operator bool();
+ };
+
+ struct NotBool {
+ explicit operator bool(); // expected-note {{conversion to integral type 'bool'}}
+ };
+ Bool b;
+ NotBool n;
+
+ (void) (1 + b);
+ (void) (1 + n); // expected-error {{invalid operands to binary expression ('int' and 'Conversion::NotBool')}}
+
+ // 5.3.1p9:
+ (void) (!b);
+ (void) (!n);
+
+ // 5.14p1:
+ (void) (b && true);
+ (void) (n && true);
+
+ // 5.15p1:
+ (void) (b || true);
+ (void) (n || true);
+
+ // 5.16p1:
+ (void) (b ? 0 : 1);
+ (void) (n ? 0: 1);
+
+ // 5.19p5:
+ // TODO: After constexpr has been implemented
+
+ // 6.4p4:
+ if (b) {}
+ if (n) {}
+
+ // 6.4.2p2:
+ switch (b) {} // expected-warning {{switch condition has boolean value}}
+ switch (n) {} // expected-error {{switch condition type 'Conversion::NotBool' requires explicit conversion to 'bool'}} \
+ expected-warning {{switch condition has boolean value}}
+
+ // 6.5.1:
+ while (b) {}
+ while (n) {}
+
+ // 6.5.2p1:
+ do {} while (b);
+ do {} while (n);
+
+ // 6.5.3:
+ for (;b;) {}
+ for (;n;) {}
+ }
+
+ void testNew()
+ {
+ // 5.3.4p6:
+ struct Int {
+ operator int();
+ };
+ struct NotInt {
+ explicit operator int(); // expected-note {{conversion to integral type 'int' declared here}}
+ };
+
+ Int i;
+ NotInt ni;
+
+ new int[i];
+ new int[ni]; // expected-error {{array size expression of type 'Conversion::NotInt' requires explicit conversion to type 'int'}}
+ }
+
+ void testDelete()
+ {
+ // 5.3.5pp2:
+ struct Ptr {
+ operator int*();
+ };
+ struct NotPtr {
+ explicit operator int*();
+ };
+
+ Ptr p;
+ NotPtr np;
+
+ delete p;
+ delete np; // expected-error {{cannot delete expression of type 'Conversion::NotPtr'}}
+ }
+
+ void testFunctionPointer()
+ {
+ // 13.3.1.1.2p2:
+ using Func = void(*)(int);
+
+ struct FP {
+ operator Func();
+ };
+ struct NotFP {
+ explicit operator Func();
+ };
+
+ FP fp;
+ NotFP nfp;
+ fp(1);
+ nfp(1); // expected-error {{type 'Conversion::NotFP' does not provide a call operator}}
+ }
}
diff --git a/test/SemaCXX/expression-traits.cpp b/test/SemaCXX/expression-traits.cpp
index 4555192280f0..32b3ff91e95b 100644
--- a/test/SemaCXX/expression-traits.cpp
+++ b/test/SemaCXX/expression-traits.cpp
@@ -136,7 +136,7 @@ void conv_ptr_1()
void expr_6()
{
- // expr/6: If an expression initially has the type “reference to Tâ€
+ // expr/6: If an expression initially has the type "reference to T"
// (8.3.2, 8.5.3), ... the expression is an lvalue.
int x = 0;
int& referenceToInt = x;
@@ -185,8 +185,8 @@ struct Class : BaseClass
template <class T>
struct NestedClassTemplate {};
- template <class T>
- static int& NestedFuncTemplate() { return variable; } // expected-note{{candidate function}}
+ template <class T> // expected-note{{possible target for call}}
+ static int& NestedFuncTemplate() { return variable; }
template <class T>
int& NestedMemfunTemplate() { return variable; }
@@ -234,13 +234,13 @@ struct Class : BaseClass
// doesn't come up in legal pure C++ programs). This language
// extension simply rejects them as requiring additional context
__is_lvalue_expr(::Class::NestedFuncTemplate); // qualified-id: template \
- // expected-error{{cannot resolve overloaded function 'NestedFuncTemplate' from context}}
+ // expected-error{{reference to overloaded function could not be resolved; did you mean to call it?}}
__is_lvalue_expr(::Class::NestedMemfunTemplate); // qualified-id: template \
- // expected-error{{a bound member function may only be called}}
+ // expected-error{{reference to non-static member function must be called}}
__is_lvalue_expr(::Class::operator+); // operator-function-id: template \
- // expected-error{{a bound member function may only be called}}
+ // expected-error{{reference to non-static member function must be called}}
//ASSERT_RVALUE(::Class::operator*); // operator-function-id: member function
}
@@ -310,9 +310,9 @@ void expr_sub_1(int* pointer)
{
// expr.sub/1 A postfix expression followed by an expression in
// square brackets is a postfix expression. One of the expressions
- // shall have the type “pointer to T†and the other shall have
+ // shall have the type "pointer to T" and the other shall have
// enumeration or integral type. The result is an lvalue of type
- // “T.â€
+ // "T."
ASSERT_LVALUE(pointer[1]);
// The expression E1[E2] is identical (by definition) to *((E1)+(E2)).
@@ -348,32 +348,32 @@ void expr_ref_4()
{
// Applies to expressions of the form E1.E2
- // If E2 is declared to have type “reference to Tâ€, then E1.E2 is
+ // If E2 is declared to have type "reference to T", then E1.E2 is
// an lvalue;.... Otherwise, one of the following rules applies.
ASSERT_LVALUE(Class().staticReferenceDataMember);
ASSERT_LVALUE(Class().referenceDataMember);
- // — If E2 is a static data member, and the type of E2 is T, then
+ // - If E2 is a static data member, and the type of E2 is T, then
// E1.E2 is an lvalue; ...
ASSERT_LVALUE(Class().staticNonreferenceDataMember);
ASSERT_LVALUE(Class().staticReferenceDataMember);
- // — If E2 is a non-static data member, ... If E1 is an lvalue,
+ // - If E2 is a non-static data member, ... If E1 is an lvalue,
// then E1.E2 is an lvalue...
Class lvalue;
ASSERT_LVALUE(lvalue.dataMember);
ASSERT_RVALUE(Class().dataMember);
- // — If E1.E2 refers to a static member function, ... then E1.E2
+ // - If E1.E2 refers to a static member function, ... then E1.E2
// is an lvalue
ASSERT_LVALUE(Class().StaticMemberFunction);
- // — Otherwise, if E1.E2 refers to a non-static member function,
+ // - Otherwise, if E1.E2 refers to a non-static member function,
// then E1.E2 is not an lvalue.
//ASSERT_RVALUE(Class().NonstaticMemberFunction);
- // — If E2 is a member enumerator, and the type of E2 is T, the
+ // - If E2 is a member enumerator, and the type of E2 is T, the
// expression E1.E2 is not an lvalue. The type of E1.E2 is T.
ASSERT_RVALUE(Class().Enumerator);
ASSERT_RVALUE(lvalue.Enumerator);
@@ -404,8 +404,8 @@ void expr_dynamic_cast_2()
void expr_dynamic_cast_5()
{
- // expr.dynamic.cast/5: If T is “reference to cv1 B†and v has type
- // “cv2 D†such that B is a base class of D, the result is an
+ // expr.dynamic.cast/5: If T is "reference to cv1 B" and v has type
+ // "cv2 D" such that B is a base class of D, the result is an
// lvalue for the unique B sub-object of the D object referred
// to by v.
typedef BaseClass B;
@@ -416,13 +416,13 @@ void expr_dynamic_cast_5()
// expr.dynamic.cast/8: The run-time check logically executes as follows:
//
-// — If, in the most derived object pointed (referred) to by v, v
+// - If, in the most derived object pointed (referred) to by v, v
// points (refers) to a public base class subobject of a T object, and
// if only one object of type T is derived from the sub-object pointed
// (referred) to by v, the result is a pointer (an lvalue referring)
// to that T object.
//
-// — Otherwise, if v points (refers) to a public base class sub-object
+// - Otherwise, if v points (refers) to a public base class sub-object
// of the most derived object, and the type of the most derived object
// has a base class, of type T, that is unambiguous and public, the
// result is a pointer (an lvalue referring) to the T sub-object of
@@ -525,7 +525,7 @@ void expr_cond(bool cond)
// conversions are performed on the second and third operands, and one
// of the following shall hold:
//
- // — The second or the third operand (but not both) is a
+ // - The second or the third operand (but not both) is a
// throw-expression (15.1); the result is of the type of the other and
// is an rvalue.
@@ -535,7 +535,7 @@ void expr_cond(bool cond)
ASSERT_RVALUE(cond ? throw 1 : classLvalue);
ASSERT_RVALUE(cond ? classLvalue : throw 1);
- // — Both the second and the third operands have type void; the result
+ // - Both the second and the third operands have type void; the result
// is of type void and is an rvalue. [Note: this includes the case
// where both operands are throw-expressions. ]
ASSERT_RVALUE(cond ? (void)1 : (void)0);
diff --git a/test/SemaCXX/expressions.cpp b/test/SemaCXX/expressions.cpp
index 8a294face380..355833e693fa 100644
--- a/test/SemaCXX/expressions.cpp
+++ b/test/SemaCXX/expressions.cpp
@@ -34,7 +34,9 @@ namespace test1 {
}
int test2(int x) {
- return x && 4; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+ return x && 4; // expected-warning {{use of logical '&&' with constant operand}} \
+ // expected-note {{use '&' for a bitwise operation}} \
+ // expected-note {{remove constant to silence this warning}}
return x && sizeof(int) == 4; // no warning, RHS is logical op.
return x && true;
@@ -42,38 +44,69 @@ int test2(int x) {
return x || true;
return x || false;
- return x && (unsigned)0; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+ return x && (unsigned)0; // expected-warning {{use of logical '&&' with constant operand}} \
+ // expected-note {{use '&' for a bitwise operation}} \
+ // expected-note {{remove constant to silence this warning}}
- return x || (unsigned)1; // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
+ return x || (unsigned)1; // expected-warning {{use of logical '||' with constant operand}} \
+ // expected-note {{use '|' for a bitwise operation}}
- return x || 0; // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
- return x || 1; // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
- return x || -1; // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
- return x || 5; // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
- return x && 0; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
- return x && 1; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
- return x && -1; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
- return x && 5; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
- return x || (0); // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
- return x || (1); // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
- return x || (-1); // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
- return x || (5); // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
- return x && (0); // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
- return x && (1); // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
- return x && (-1); // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
- return x && (5); // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+ return x || 0; // expected-warning {{use of logical '||' with constant operand}} \
+ // expected-note {{use '|' for a bitwise operation}}
+ return x || 1; // expected-warning {{use of logical '||' with constant operand}} \
+ // expected-note {{use '|' for a bitwise operation}}
+ return x || -1; // expected-warning {{use of logical '||' with constant operand}} \
+ // expected-note {{use '|' for a bitwise operation}}
+ return x || 5; // expected-warning {{use of logical '||' with constant operand}} \
+ // expected-note {{use '|' for a bitwise operation}}
+ return x && 0; // expected-warning {{use of logical '&&' with constant operand}} \
+ // expected-note {{use '&' for a bitwise operation}} \
+ // expected-note {{remove constant to silence this warning}}
+ return x && 1; // expected-warning {{use of logical '&&' with constant operand}} \
+ // expected-note {{use '&' for a bitwise operation}} \
+ // expected-note {{remove constant to silence this warning}}
+ return x && -1; // expected-warning {{use of logical '&&' with constant operand}} \
+ // expected-note {{use '&' for a bitwise operation}} \
+ // expected-note {{remove constant to silence this warning}}
+ return x && 5; // expected-warning {{use of logical '&&' with constant operand}} \
+ // expected-note {{use '&' for a bitwise operation}} \
+ // expected-note {{remove constant to silence this warning}}
+ return x || (0); // expected-warning {{use of logical '||' with constant operand}} \
+ // expected-note {{use '|' for a bitwise operation}}
+ return x || (1); // expected-warning {{use of logical '||' with constant operand}} \
+ // expected-note {{use '|' for a bitwise operation}}
+ return x || (-1); // expected-warning {{use of logical '||' with constant operand}} \
+ // expected-note {{use '|' for a bitwise operation}}
+ return x || (5); // expected-warning {{use of logical '||' with constant operand}} \
+ // expected-note {{use '|' for a bitwise operation}}
+ return x && (0); // expected-warning {{use of logical '&&' with constant operand}} \
+ // expected-note {{use '&' for a bitwise operation}} \
+ // expected-note {{remove constant to silence this warning}}
+ return x && (1); // expected-warning {{use of logical '&&' with constant operand}} \
+ // expected-note {{use '&' for a bitwise operation}} \
+ // expected-note {{remove constant to silence this warning}}
+ return x && (-1); // expected-warning {{use of logical '&&' with constant operand}} \
+ // expected-note {{use '&' for a bitwise operation}} \
+ // expected-note {{remove constant to silence this warning}}
+ return x && (5); // expected-warning {{use of logical '&&' with constant operand}} \
+ // expected-note {{use '&' for a bitwise operation}} \
+ // expected-note {{remove constant to silence this warning}}
}
template<unsigned int A, unsigned int B> struct S
{
enum {
e1 = A && B,
- e2 = A && 7 // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+ e2 = A && 7 // expected-warning {{use of logical '&&' with constant operand}} \
+ // expected-note {{use '&' for a bitwise operation}} \
+ // expected-note {{remove constant to silence this warning}}
};
int foo() {
int x = A && B;
- int y = B && 3; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+ int y = B && 3; // expected-warning {{use of logical '&&' with constant operand}} \
+ // expected-note {{use '&' for a bitwise operation}} \
+ // expected-note {{remove constant to silence this warning}}
return x + y;
}
diff --git a/test/SemaCXX/for-range-examples.cpp b/test/SemaCXX/for-range-examples.cpp
index 810f1de441a1..b994e8c10bd6 100644
--- a/test/SemaCXX/for-range-examples.cpp
+++ b/test/SemaCXX/for-range-examples.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
namespace value_range_detail {
template<typename T>
diff --git a/test/SemaCXX/for-range-no-std.cpp b/test/SemaCXX/for-range-no-std.cpp
index 8cc71e5111a2..dae41f1bb296 100644
--- a/test/SemaCXX/for-range-no-std.cpp
+++ b/test/SemaCXX/for-range-no-std.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++0x-extensions
struct S {
int *begin();
diff --git a/test/SemaCXX/for-range-unused.cpp b/test/SemaCXX/for-range-unused.cpp
index 7b7d84d3f9c8..ce6b379cc192 100644
--- a/test/SemaCXX/for-range-unused.cpp
+++ b/test/SemaCXX/for-range-unused.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x -Wunused
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -Wunused
// PR9968: We used to warn that __range is unused in a dependent for-range.
diff --git a/test/SemaCXX/function-overload-typo-crash.cpp b/test/SemaCXX/function-overload-typo-crash.cpp
index 0fea312a97f2..8c5cec8af3a9 100644
--- a/test/SemaCXX/function-overload-typo-crash.cpp
+++ b/test/SemaCXX/function-overload-typo-crash.cpp
@@ -1,12 +1,28 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// PR10283
-void min();
+void min(); //expected-note {{'min' declared here}}
void min(int);
-template <typename T> void max(T);
+template <typename T> void max(T); //expected-note {{'max' declared here}}
void f() {
fin(); //expected-error {{use of undeclared identifier 'fin'; did you mean 'min'}}
fax(0); //expected-error {{use of undeclared identifier 'fax'; did you mean 'max'}}
}
+
+template <typename T> void somefunc(T*, T*); //expected-note {{'somefunc' declared here}}
+template <typename T> void somefunc(const T[]); //expected-note {{'somefunc' declared here}}
+template <typename T1, typename T2> void somefunc(T1*, T2*); //expected-note {{'somefunc' declared here}}
+template <typename T1, typename T2> void somefunc(T1*, const T2[]); //expected-note 2 {{'somefunc' declared here}}
+
+void c() {
+ int *i = 0, *j = 0;
+ const int x[] = {1, 2, 3};
+ long *l = 0;
+ somefun(i, j); //expected-error {{use of undeclared identifier 'somefun'; did you mean 'somefunc'?}}
+ somefun(x); //expected-error {{use of undeclared identifier 'somefun'; did you mean 'somefunc'?}}
+ somefun(i, l); //expected-error {{use of undeclared identifier 'somefun'; did you mean 'somefunc'?}}
+ somefun(l, x); //expected-error {{use of undeclared identifier 'somefun'; did you mean 'somefunc'?}}
+ somefun(i, x); //expected-error {{use of undeclared identifier 'somefun'; did you mean 'somefunc'?}}
+}
diff --git a/test/SemaCXX/function-redecl.cpp b/test/SemaCXX/function-redecl.cpp
index b15d86616585..0d9ecf334e6a 100644
--- a/test/SemaCXX/function-redecl.cpp
+++ b/test/SemaCXX/function-redecl.cpp
@@ -24,3 +24,74 @@ namespace N {
}
}
}
+
+class A {
+ void typocorrection(); // expected-note {{'typocorrection' declared here}}
+};
+
+void A::Notypocorrection() { // expected-error {{out-of-line definition of 'Notypocorrection' does not match any declaration in 'A'; did you mean 'typocorrection'}}
+}
+
+
+namespace test0 {
+ void dummy() {
+ void Bar(); // expected-note {{'Bar' declared here}}
+ class A {
+ friend void bar(); // expected-error {{no matching function 'bar' found in local scope; did you mean 'Bar'}}
+ };
+ }
+}
+
+
+class B {
+ void typocorrection(const int); // expected-note {{'typocorrection' declared here}}
+ void typocorrection(double);
+};
+
+void B::Notypocorrection(int) { // expected-error {{out-of-line definition of 'Notypocorrection' does not match any declaration in 'B'; did you mean 'typocorrection'}}
+}
+
+struct X { int f(); };
+struct Y : public X {};
+int Y::f() { return 3; } // expected-error {{out-of-line definition of 'f' does not match any declaration in 'Y'}}
+
+namespace test1 {
+struct Foo {
+ class Inner { };
+};
+}
+
+class Bar {
+ void f(test1::Foo::Inner foo) const; // expected-note {{member declaration does not match because it is const qualified}}
+};
+
+using test1::Foo;
+
+void Bar::f(Foo::Inner foo) { // expected-error {{out-of-line definition of 'f' does not match any declaration in 'Bar'}}
+ (void)foo;
+}
+
+class Crash {
+ public:
+ void GetCart(int count) const;
+};
+// This out-of-line definition was fine...
+void Crash::cart(int count) const {} // expected-error {{out-of-line definition of 'cart' does not match any declaration in 'Crash'}}
+// ...while this one crashed clang
+void Crash::chart(int count) const {} // expected-error {{out-of-line definition of 'chart' does not match any declaration in 'Crash'}}
+
+class TestConst {
+ public:
+ int getit() const; // expected-note {{member declaration does not match because it is const qualified}}
+ void setit(int); // expected-note {{member declaration does not match because it is not const qualified}}
+};
+
+int TestConst::getit() { // expected-error {{out-of-line definition of 'getit' does not match any declaration in 'TestConst'}}
+ return 1;
+}
+
+void TestConst::setit(int) const { // expected-error {{out-of-line definition of 'setit' does not match any declaration in 'TestConst'}}
+}
+
+struct J { int typo() const; };
+int J::typo_() { return 3; } // expected-error {{out-of-line definition of 'typo_' does not match any declaration in 'J'}}
diff --git a/test/SemaCXX/generalized-initializers.cpp b/test/SemaCXX/generalized-initializers.cpp
index 6e2bee7e301d..a1891c9c322e 100644
--- a/test/SemaCXX/generalized-initializers.cpp
+++ b/test/SemaCXX/generalized-initializers.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// XFAIL: *
template <typename T, typename U>
@@ -40,25 +40,9 @@ namespace std {
namespace integral {
- void initialization() {
- { const int a{}; static_assert(a == 0, ""); }
- { const int a = {}; static_assert(a == 0, ""); }
- { const int a{1}; static_assert(a == 1, ""); }
- { const int a = {1}; static_assert(a == 1, ""); }
- { const int a{1, 2}; } // expected-error {{excess elements}}
- { const int a = {1, 2}; } // expected-error {{excess elements}}
- { const short a{100000}; } // expected-error {{narrowing conversion}}
- { const short a = {100000}; } // expected-error {{narrowing conversion}}
- }
-
int function_call() {
void takes_int(int);
takes_int({1});
-
- int ar[10];
- (void) ar[{1}]; // expected-error {{initializer list is illegal with the built-in index operator}}
-
- return {1};
}
void inline_init() {
@@ -76,11 +60,6 @@ namespace integral {
for (int i : {1, 2, 3, 4}) {}
}
- struct A {
- int i;
- A() : i{1} {}
- };
-
}
namespace objects {
diff --git a/test/SemaCXX/generic-selection.cpp b/test/SemaCXX/generic-selection.cpp
index b171fce540d8..c0a5d89fff67 100644
--- a/test/SemaCXX/generic-selection.cpp
+++ b/test/SemaCXX/generic-selection.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
template <typename T, typename U = void*>
struct A {
diff --git a/test/SemaCXX/i-c-e-cxx.cpp b/test/SemaCXX/i-c-e-cxx.cpp
index 186e32126a39..4d02ca8f174e 100644
--- a/test/SemaCXX/i-c-e-cxx.cpp
+++ b/test/SemaCXX/i-c-e-cxx.cpp
@@ -54,4 +54,10 @@ struct A {
int foo() { return A::B; }
}
+// PR11040
+const int x = 10;
+int* y = reinterpret_cast<const char&>(x); // expected-error {{cannot initialize}}
+// This isn't an integral constant expression, but make sure it folds anyway.
+struct PR8836 { char _; long long a; };
+int PR8836test[(__typeof(sizeof(int)))&reinterpret_cast<const volatile char&>((((PR8836*)0)->a))];
diff --git a/test/SemaCXX/implicit-exception-spec.cpp b/test/SemaCXX/implicit-exception-spec.cpp
index 81babc043ff7..559c3013f7e9 100644
--- a/test/SemaCXX/implicit-exception-spec.cpp
+++ b/test/SemaCXX/implicit-exception-spec.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++0x -Wall %s
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++11 -Wall %s
template<bool b> struct ExceptionIf { static int f(); };
template<> struct ExceptionIf<false> { typedef int f; };
diff --git a/test/SemaCXX/issue547.cpp b/test/SemaCXX/issue547.cpp
index 03c5b7c978aa..5b82dc6b145e 100644
--- a/test/SemaCXX/issue547.cpp
+++ b/test/SemaCXX/issue547.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
template<typename T>
struct classify_function {
diff --git a/test/SemaCXX/libstdcxx_is_pod_hack.cpp b/test/SemaCXX/libstdcxx_is_pod_hack.cpp
index 3581c796ce91..3ac233627ccb 100644
--- a/test/SemaCXX/libstdcxx_is_pod_hack.cpp
+++ b/test/SemaCXX/libstdcxx_is_pod_hack.cpp
@@ -27,3 +27,7 @@ struct test_is_signed {
};
bool check_signed = test_is_signed::__is_signed;
+
+#if __has_feature(is_pod)
+# error __is_pod won't work now anyway
+#endif
diff --git a/test/SemaCXX/linkage-spec.cpp b/test/SemaCXX/linkage-spec.cpp
index b5a10a795ebc..cb7e32c05d88 100644
--- a/test/SemaCXX/linkage-spec.cpp
+++ b/test/SemaCXX/linkage-spec.cpp
@@ -89,3 +89,16 @@ extern "C++" using N::value;
// PR7076
extern "C" const char *Version_string = "2.9";
+
+namespace PR9162 {
+ extern "C" {
+ typedef struct _ArtsSink ArtsSink;
+ struct _ArtsSink {
+ int sink;
+ };
+ }
+ int arts_sink_get_type()
+ {
+ return sizeof(ArtsSink);
+ }
+}
diff --git a/test/SemaCXX/literal-operators.cpp b/test/SemaCXX/literal-operators.cpp
index ec585a61da9f..06ef49fc0ae1 100644
--- a/test/SemaCXX/literal-operators.cpp
+++ b/test/SemaCXX/literal-operators.cpp
@@ -1,41 +1,41 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
#include <stddef.h>
struct tag {
- void operator "" tag_bad (const char *); // expected-error {{literal operator 'operator "" tag_bad' must be in a namespace or global scope}}
- friend void operator "" tag_good (const char *);
+ void operator "" _tag_bad (const char *); // expected-error {{literal operator 'operator "" _tag_bad' must be in a namespace or global scope}}
+ friend void operator "" _tag_good (const char *);
};
-namespace ns { void operator "" ns_good (const char *); }
+namespace ns { void operator "" _ns_good (const char *); }
// Check extern "C++" declarations
-extern "C++" void operator "" extern_good (const char *);
-extern "C++" { void operator "" extern_good (const char *); }
+extern "C++" void operator "" _extern_good (const char *);
+extern "C++" { void operator "" _extern_good (const char *); }
-void fn () { void operator "" fn_bad (const char *); } // expected-error {{literal operator 'operator "" fn_bad' must be in a namespace or global scope}}
+void fn () { void operator "" _fn_bad (const char *); } // expected-error {{literal operator 'operator "" _fn_bad' must be in a namespace or global scope}}
// One-param declarations (const char * was already checked)
-void operator "" good (char);
-void operator "" good (wchar_t);
-void operator "" good (char16_t);
-void operator "" good (char32_t);
-void operator "" good (unsigned long long);
-void operator "" good (long double);
+void operator "" _good (char);
+void operator "" _good (wchar_t);
+void operator "" _good (char16_t);
+void operator "" _good (char32_t);
+void operator "" _good (unsigned long long);
+void operator "" _good (long double);
// Two-param declarations
-void operator "" good (const char *, size_t);
-void operator "" good (const wchar_t *, size_t);
-void operator "" good (const char16_t *, size_t);
-void operator "" good (const char32_t *, size_t);
+void operator "" _good (const char *, size_t);
+void operator "" _good (const wchar_t *, size_t);
+void operator "" _good (const char16_t *, size_t);
+void operator "" _good (const char32_t *, size_t);
// Check typedef and array equivalences
-void operator "" good (const char[]);
+void operator "" _good (const char[]);
typedef const char c;
-void operator "" good (c*);
+void operator "" _good (c*);
// Check extra cv-qualifiers
-void operator "" cv_good (volatile const char *, const size_t);
+void operator "" _cv_good (volatile const char *, const size_t);
// Template delcaration (not implemented yet)
// template <char...> void operator "" good ();
diff --git a/test/SemaCXX/literal-type.cpp b/test/SemaCXX/literal-type.cpp
index 6a61823adb28..60bfcf00cf0b 100644
--- a/test/SemaCXX/literal-type.cpp
+++ b/test/SemaCXX/literal-type.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
static_assert(__is_literal(int), "fail");
static_assert(__is_literal_type(int), "fail"); // alternate spelling for GCC
diff --git a/test/SemaCXX/member-expr.cpp b/test/SemaCXX/member-expr.cpp
index 981bae7c770b..2e3fd73d7ff5 100644
--- a/test/SemaCXX/member-expr.cpp
+++ b/test/SemaCXX/member-expr.cpp
@@ -28,7 +28,7 @@ struct B {
A *f0();
};
int f0(B *b) {
- return b->f0->f0; // expected-error{{perhaps you meant to call it with no arguments}}
+ return b->f0->f0; // expected-error{{did you mean to call it with no arguments}}
}
int i;
@@ -118,32 +118,32 @@ namespace rdar8231724 {
namespace PR9025 {
struct S { int x; };
- S fun();
- int fun(int i);
+ S fun(); // expected-note{{possible target for call}}
+ int fun(int i); // expected-note{{possible target for call}}
int g() {
- return fun.x; // expected-error{{base of member reference is an overloaded function; perhaps you meant to call it with no arguments?}}
+ return fun.x; // expected-error{{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}}
}
- S fun2();
- S fun2(int i);
+ S fun2(); // expected-note{{possible target for call}}
+ S fun2(int i); // expected-note{{possible target for call}}
int g2() {
- return fun2.x; // expected-error{{base of member reference is an overloaded function; perhaps you meant to call it with no arguments?}}
+ return fun2.x; // expected-error{{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}}
}
- S fun3(int i=0);
- int fun3(int i, int j);
+ S fun3(int i=0); // expected-note{{possible target for call}}
+ int fun3(int i, int j); // expected-note{{possible target for call}}
int g3() {
- return fun3.x; // expected-error{{base of member reference is an overloaded function; perhaps you meant to call it with no arguments?}}
+ return fun3.x; // expected-error{{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}}
}
- template <typename T> S fun4();
+ template <typename T> S fun4(); // expected-note{{possible target for call}}
int g4() {
- return fun4.x; // expected-error{{base of member reference is a function; perhaps you meant to call it?}}
+ return fun4.x; // expected-error{{reference to overloaded function could not be resolved; did you mean to call it?}}
}
- S fun5(int i); // expected-note{{possibly valid overload here}}
- S fun5(float f); // expected-note{{possibly valid overload here}}
+ S fun5(int i); // expected-note{{possible target for call}}
+ S fun5(float f); // expected-note{{possible target for call}}
int g5() {
- return fun5.x; // expected-error{{base of member reference is an overloaded function; perhaps you meant to call it?}}
+ return fun5.x; // expected-error{{reference to overloaded function could not be resolved; did you mean to call it?}}
}
}
diff --git a/test/SemaCXX/member-init.cpp b/test/SemaCXX/member-init.cpp
index 7ca1f0e4513e..819c8d13db89 100644
--- a/test/SemaCXX/member-init.cpp
+++ b/test/SemaCXX/member-init.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++0x -Wall %s
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++11 -Wall %s
struct Bitfield {
int n : 3 = 7; // expected-error {{bitfield member cannot have an in-class initializer}}
@@ -52,3 +52,21 @@ struct CheckExcSpecFail {
struct TypedefInit {
typedef int A = 0; // expected-error {{illegal initializer}}
};
+
+// PR10578 / <rdar://problem/9877267>
+namespace PR10578 {
+ template<typename T>
+ struct X {
+ X() {
+ T* x = 1; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}}
+ }
+ };
+
+ struct Y : X<int> {
+ Y();
+ };
+
+ Y::Y() try { // expected-note{{in instantiation of member function 'PR10578::X<int>::X' requested here}}
+ } catch(...) {
+ }
+}
diff --git a/test/SemaCXX/microsoft-cxx0x.cpp b/test/SemaCXX/microsoft-cxx0x.cpp
new file mode 100644
index 000000000000..3f78eda79cd5
--- /dev/null
+++ b/test/SemaCXX/microsoft-cxx0x.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -Wc++0x-narrowing -Wmicrosoft -verify -fms-extensions -std=c++11
+
+
+struct A {
+ unsigned int a;
+};
+int b = 3;
+A var = { b }; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+
+
diff --git a/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp b/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
index fd0c976bdd78..76ceea1d4d5b 100644
--- a/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
+++ b/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
@@ -1,8 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++0x-extensions %s
-namespace fizbin { class Foobar; } // expected-note{{'fizbin::Foobar' declared here}}
-Foobar *my_bar = new Foobar; // expected-error{{unknown type name 'Foobar'; did you mean 'fizbin::Foobar'?}} \
- // expected-error{{expected a type}}
+namespace fizbin { class Foobar {}; } // expected-note 2 {{'fizbin::Foobar' declared here}} \
+ // expected-note {{'Foobar' declared here}}
+Foobar *my_bar // expected-error{{unknown type name 'Foobar'; did you mean 'fizbin::Foobar'?}}
+ = new Foobar; // expected-error{{unknown type name 'Foobar'; did you mean 'fizbin::Foobar'?}}
+fizbin::Foobar *my_foo = new fizbin::FooBar; // expected-error{{unknown type name 'FooBar'; did you mean 'Foobar'?}}
namespace barstool { int toFoobar() { return 1; } } // expected-note 3 {{'barstool::toFoobar' declared here}}
int Double(int x) { return x + x; }
@@ -62,11 +64,13 @@ void f() {
// Test case from http://llvm.org/bugs/show_bug.cgi?id=10318
namespace llvm {
- template <typename T> class GraphWriter {}; // expected-note{{'llvm::GraphWriter' declared here}}
+ template <typename T> class GraphWriter {}; // expected-note {{'llvm::GraphWriter' declared here}} \
+ // expected-note {{'GraphWriter' declared here}}
}
struct S {};
void bar() {
GraphWriter<S> x; //expected-error{{no template named 'GraphWriter'; did you mean 'llvm::GraphWriter'?}}
-
+ (void)new llvm::GraphWriter; // expected-error {{expected a type}}
+ (void)new llvm::Graphwriter<S>; // expected-error {{no template named 'Graphwriter' in namespace 'llvm'; did you mean 'GraphWriter'?}}
}
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index ee6ca8857374..e13030cc38a8 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -27,10 +27,10 @@ int A::C::cx = 17;
static int A::C::cx2 = 17; // expected-error{{'static' can}}
class C2 {
- void m(); // expected-note{{member declaration nearly matches}}
+ void m(); // expected-note{{member declaration does not match because it is not const qualified}}
- void f(const int& parm); // expected-note{{member declaration nearly matches}}
- void f(int) const; // expected-note{{member declaration nearly matches}}
+ void f(const int& parm); // expected-note{{type of 1st parameter of member declaration does not match definition ('const int &' vs 'int')}}
+ void f(int) const; // expected-note{{member declaration does not match because it is const qualified}}
void f(float);
int x;
@@ -121,7 +121,7 @@ namespace E {
class Operators {
- Operators operator+(const Operators&) const; // expected-note{{member declaration nearly matches}}
+ Operators operator+(const Operators&) const; // expected-note{{member declaration does not match because it is const qualified}}
operator bool();
};
@@ -140,7 +140,7 @@ Operators::operator bool() {
}
namespace A {
- void g(int&); // expected-note{{member declaration nearly matches}}
+ void g(int&); // expected-note{{type of 1st parameter of member declaration does not match definition ('int &' vs 'const int &')}}
}
void A::f() {} // expected-error{{out-of-line definition of 'f' does not match any declaration in namespace 'A'}}
diff --git a/test/SemaCXX/new-array-size-conv.cpp b/test/SemaCXX/new-array-size-conv.cpp
index 80219a906209..e8bb67955f97 100644
--- a/test/SemaCXX/new-array-size-conv.cpp
+++ b/test/SemaCXX/new-array-size-conv.cpp
@@ -19,8 +19,8 @@ struct IndirectValueInt : ValueInt { };
struct TwoValueInts : ValueInt, IndirectValueInt { };
void test() {
- (void)new int[ValueInt(10)]; // expected-warning{{implicit conversion from array size expression of type 'ValueInt' to integral type 'int' is a C++0x extension}}
- (void)new int[ValueEnum()]; // expected-warning{{implicit conversion from array size expression of type 'ValueEnum' to enumeration type 'E' is a C++0x extension}}
+ (void)new int[ValueInt(10)]; // expected-warning{{implicit conversion from array size expression of type 'ValueInt' to integral type 'int' is a C++11 extension}}
+ (void)new int[ValueEnum()]; // expected-warning{{implicit conversion from array size expression of type 'ValueEnum' to enumeration type 'E' is a C++11 extension}}
(void)new int[ValueBoth()]; // expected-error{{ambiguous conversion of array size expression of type 'ValueBoth' to an integral or enumeration type}}
(void)new int[TwoValueInts()]; // expected-error{{ambiguous conversion of array size expression of type 'TwoValueInts' to an integral or enumeration type}}
diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp
index efdfa0f066db..748ce7770097 100644
--- a/test/SemaCXX/new-delete.cpp
+++ b/test/SemaCXX/new-delete.cpp
@@ -397,3 +397,22 @@ namespace ArrayNewNeedsDtor {
return new B[5]; // expected-note {{implicit default destructor for 'ArrayNewNeedsDtor::B' first required here}}
}
}
+
+namespace DeleteIncompleteClass {
+ struct A; // expected-note {{forward declaration}}
+ extern A x;
+ void f() { delete x; } // expected-error {{deleting incomplete class type}}
+}
+
+namespace DeleteIncompleteClassPointerError {
+ struct A; // expected-note {{forward declaration}}
+ void f(A *x) { 1+delete x; } // expected-warning {{deleting pointer to incomplete type}} \
+ // expected-error {{invalid operands to binary expression}}
+}
+
+namespace PR10504 {
+ struct A {
+ virtual void foo() = 0;
+ };
+ void f(A *x) { delete x; } // expected-warning {{delete called on 'PR10504::A' that is abstract but has non-virtual destructor}}
+}
diff --git a/test/SemaCXX/null_in_arithmetic_ops.cpp b/test/SemaCXX/null_in_arithmetic_ops.cpp
index fab6f10ab785..24590ce633f2 100644
--- a/test/SemaCXX/null_in_arithmetic_ops.cpp
+++ b/test/SemaCXX/null_in_arithmetic_ops.cpp
@@ -64,12 +64,12 @@ void f() {
a |= NULL; // expected-warning{{use of NULL in arithmetic operation}}
a ^= NULL; // expected-warning{{use of NULL in arithmetic operation}}
- b = a < NULL || NULL < a; // expected-warning 2{{use of NULL in arithmetic operation}}
- b = a > NULL || NULL > a; // expected-warning 2{{use of NULL in arithmetic operation}}
- b = a <= NULL || NULL <= a; // expected-warning 2{{use of NULL in arithmetic operation}}
- b = a >= NULL || NULL >= a; // expected-warning 2{{use of NULL in arithmetic operation}}
- b = a == NULL || NULL == a; // expected-warning 2{{use of NULL in arithmetic operation}}
- b = a != NULL || NULL != a; // expected-warning 2{{use of NULL in arithmetic operation}}
+ b = a < NULL || a > NULL; // expected-warning 2{{comparison between NULL and non-pointer ('int' and NULL)}}
+ b = NULL < a || NULL > a; // expected-warning 2{{comparison between NULL and non-pointer (NULL and 'int')}}
+ b = a <= NULL || a >= NULL; // expected-warning 2{{comparison between NULL and non-pointer ('int' and NULL)}}
+ b = NULL <= a || NULL >= a; // expected-warning 2{{comparison between NULL and non-pointer (NULL and 'int')}}
+ b = a == NULL || a != NULL; // expected-warning 2{{comparison between NULL and non-pointer ('int' and NULL)}}
+ b = NULL == a || NULL != a; // expected-warning 2{{comparison between NULL and non-pointer (NULL and 'int')}}
b = &a < NULL || NULL < &a || &a > NULL || NULL > &a;
b = &a <= NULL || NULL <= &a || &a >= NULL || NULL >= &a;
@@ -82,7 +82,7 @@ void f() {
b = NULL <= NULL || NULL >= NULL;
b = NULL == NULL || NULL != NULL;
- b = ((NULL)) != a; // expected-warning{{use of NULL in arithmetic operation}}
+ b = ((NULL)) != a; // expected-warning{{comparison between NULL and non-pointer (NULL and 'int')}}
// Check that even non-standard pointers don't warn.
b = c == NULL || NULL == c || c != NULL || NULL != c;
diff --git a/test/SemaCXX/nullptr.cpp b/test/SemaCXX/nullptr.cpp
index d69af588a7d0..6f660366e998 100644
--- a/test/SemaCXX/nullptr.cpp
+++ b/test/SemaCXX/nullptr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++0x -ffreestanding %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -ffreestanding %s
#include <stdint.h>
typedef decltype(nullptr) nullptr_t;
diff --git a/test/SemaCXX/nullptr_in_arithmetic_ops.cpp b/test/SemaCXX/nullptr_in_arithmetic_ops.cpp
index e839ed116f8d..9671353907c7 100644
--- a/test/SemaCXX/nullptr_in_arithmetic_ops.cpp
+++ b/test/SemaCXX/nullptr_in_arithmetic_ops.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fblocks -std=c++0x -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fblocks -std=c++11 -verify %s
void foo() {
int a;
diff --git a/test/SemaCXX/out-of-line-def-mismatch.cpp b/test/SemaCXX/out-of-line-def-mismatch.cpp
new file mode 100644
index 000000000000..6ade5b802b65
--- /dev/null
+++ b/test/SemaCXX/out-of-line-def-mismatch.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -verify %s
+
+namespace N2 {
+ struct S1;
+
+ namespace N1 {
+ class C1 {};
+
+ struct S2 {
+ void func(S1*); // expected-note {{type of 1st parameter of member declaration does not match definition ('N2::S1 *' vs 'N2::N1::S1 *')}}
+ void func(C1&, unsigned, const S1*); // expected-note {{type of 3rd parameter of member declaration does not match definition ('const N2::S1 *' vs 'const N2::N1::S1 *')}}
+ void func(const S1*, unsigned); //expected-note {{type of 1st parameter of member declaration does not match definition ('const N2::S1 *' vs 'N2::N1::S1')}}
+ void func(unsigned, const S1*); // expected-note {{type of 1st parameter of member declaration does not match definition ('unsigned int' vs 'unsigned int *')}}
+ };
+
+ struct S1 {};
+ }
+}
+
+void N2::N1::S2::func(S1*) {} // expected-error {{out-of-line definition of 'func' does not match any declaration in 'N2::N1::S2'}}
+void N2::N1::S2::func(C1&, unsigned, const S1*) {} // expected-error {{out-of-line definition of 'func' does not match any declaration in 'N2::N1::S2'}}
+void N2::N1::S2::func(S1*, double) {} // expected-error {{out-of-line definition of 'func' does not match any declaration in 'N2::N1::S2'}}
+void N2::N1::S2::func(S1, unsigned) {} // expected-error {{out-of-line definition of 'func' does not match any declaration in 'N2::N1::S2'}}
+void N2::N1::S2::func(unsigned*, S1*) {} // expected-error {{out-of-line definition of 'func' does not match any declaration in 'N2::N1::S2'}}
diff --git a/test/SemaCXX/overload-0x.cpp b/test/SemaCXX/overload-0x.cpp
new file mode 100644
index 000000000000..677d16a32c12
--- /dev/null
+++ b/test/SemaCXX/overload-0x.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+namespace test0 {
+ struct A { // expected-note {{candidate function (the implicit copy assignment operator) not viable: 'this' argument has type 'const test0::A', but method is not marked const}} expected-note {{candidate function (the implicit move assignment operator) not viable: 'this' argument has type 'const test0::A', but method is not marked const}}
+ A &operator=(void*); // expected-note {{candidate function not viable: 'this' argument has type 'const test0::A', but method is not marked const}}
+ };
+
+ void test(const A &a) {
+ a = "help"; // expected-error {{no viable overloaded '='}}
+ }
+}
diff --git a/test/SemaCXX/overload-call.cpp b/test/SemaCXX/overload-call.cpp
index 9cc48993fde9..00f6a9460a7a 100644
--- a/test/SemaCXX/overload-call.cpp
+++ b/test/SemaCXX/overload-call.cpp
@@ -525,3 +525,12 @@ namespace PR9507 {
f(n); // expected-error{{call to 'f' is ambiguous}}
}
}
+
+namespace rdar9803316 {
+ void foo(float);
+ int &foo(int);
+
+ void bar() {
+ int &ir = (&foo)(0);
+ }
+}
diff --git a/test/SemaCXX/overloaded-builtin-operators-0x.cpp b/test/SemaCXX/overloaded-builtin-operators-0x.cpp
index 32f199529064..6a5a162af679 100644
--- a/test/SemaCXX/overloaded-builtin-operators-0x.cpp
+++ b/test/SemaCXX/overloaded-builtin-operators-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fshow-overloads=best -std=c++0x -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fshow-overloads=best -std=c++11 -verify %s
template <class T>
struct X
diff --git a/test/SemaCXX/overloaded-name.cpp b/test/SemaCXX/overloaded-name.cpp
index 73f12a902723..a5ec51ced23d 100644
--- a/test/SemaCXX/overloaded-name.cpp
+++ b/test/SemaCXX/overloaded-name.cpp
@@ -1,15 +1,15 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-int ovl(int); // expected-note 3{{candidate function}}
-float ovl(float); // expected-note 3{{candidate function}}
+int ovl(int); // expected-note 3{{possible target for call}}
+float ovl(float); // expected-note 3{{possible target for call}}
-template<typename T> T ovl(T); // expected-note 3{{candidate function}}
+template<typename T> T ovl(T); // expected-note 3{{possible target for call}}
void test(bool b) {
- (void)((void)0, ovl); // expected-error{{cannot resolve overloaded function 'ovl' from context}}
+ (void)((void)0, ovl); // expected-error{{reference to overloaded function could not be resolved; did you mean to call it?}}
// PR7863
- (void)(b? ovl : &ovl); // expected-error{{cannot resolve overloaded function 'ovl' from context}}
- (void)(b? ovl<float> : &ovl); // expected-error{{cannot resolve overloaded function 'ovl' from context}}
+ (void)(b? ovl : &ovl); // expected-error{{reference to overloaded function could not be resolved; did you mean to call it?}}
+ (void)(b? ovl<float> : &ovl); // expected-error{{reference to overloaded function could not be resolved; did you mean to call it?}}
(void)(b? ovl<float> : ovl<float>);
}
@@ -21,10 +21,11 @@ namespace rdar9623945 {
public:
const char* text(void);
void g(void) {
+ // FIXME: why 2x?
f(text());
- f(text); // expected-error{{a bound member function may only be called}}
+ f(text); // expected-error 2{{reference to non-static member function must be called; did you mean to call it with no arguments?}}
f(text());
- f(text); // expected-error{{a bound member function may only be called}}
+ f(text); // expected-error 2{{reference to non-static member function must be called; did you mean to call it with no arguments?}}
}
};
}
diff --git a/test/SemaCXX/overloaded-operator-decl.cpp b/test/SemaCXX/overloaded-operator-decl.cpp
index 5f8655cee70c..4519a2d1f9ad 100644
--- a/test/SemaCXX/overloaded-operator-decl.cpp
+++ b/test/SemaCXX/overloaded-operator-decl.cpp
@@ -43,3 +43,8 @@ namespace PR6238 {
void operator()();
} plus;
}
+
+struct PR10839 {
+ operator int; // expected-error{{'operator int' cannot be the name of a variable or data member}}
+ int operator+; // expected-error{{'operator+' cannot be the name of a variable or data member}}
+};
diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp
index 462d0234f39f..1e4a3b7514ba 100644
--- a/test/SemaCXX/overloaded-operator.cpp
+++ b/test/SemaCXX/overloaded-operator.cpp
@@ -36,7 +36,7 @@ A make_A();
bool operator==(A&, Z&); // expected-note 3{{candidate function}}
void h(A a, const A ac, Z z) {
- make_A() == z;
+ make_A() == z; // expected-warning{{equality comparison result unused}}
a == z; // expected-error{{use of overloaded operator '==' is ambiguous}}
ac == z; // expected-error{{invalid operands to binary expression ('const A' and 'Z')}}
}
@@ -45,7 +45,7 @@ struct B {
bool operator==(const B&) const;
void test(Z z) {
- make_A() == z;
+ make_A() == z; // expected-warning{{equality comparison result unused}}
}
};
@@ -396,7 +396,7 @@ namespace rdar9136502 {
};
void f(X x, Y y) {
- y << x.i; // expected-error{{a bound member function may only be called}}
+ y << x.i; // expected-error{{reference to non-static member function must be called}}
}
}
diff --git a/test/SemaCXX/ptrtomember-overload-resolution.cpp b/test/SemaCXX/ptrtomember-overload-resolution.cpp
index 4c7908e1137e..787e33022aa3 100644
--- a/test/SemaCXX/ptrtomember-overload-resolution.cpp
+++ b/test/SemaCXX/ptrtomember-overload-resolution.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
// 13.3.3.2 Ranking implicit conversion sequences
// conversion of A::* to B::* is better than conversion of A::* to C::*,
diff --git a/test/SemaCXX/ptrtomember.cpp b/test/SemaCXX/ptrtomember.cpp
index c3917333a540..aee535e5593b 100644
--- a/test/SemaCXX/ptrtomember.cpp
+++ b/test/SemaCXX/ptrtomember.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
struct S {
int i;
@@ -22,12 +22,12 @@ struct S3 {
};
void f3(S3* p, void (S3::*m)()) {
- p->*m; // expected-error {{a bound member function may only be called}}
- (void)(p->*m); // expected-error {{a bound member function may only be called}}
- (void)(void*)(p->*m); // expected-error {{a bound member function may only be called}}
- (void)reinterpret_cast<void*>(p->*m); // expected-error {{a bound member function may only be called}}
- if (p->*m) {} // expected-error {{a bound member function may only be called}}
- if (!(p->*m)) {} // expected-error {{a bound member function may only be called}}
- if (p->m) {}; // expected-error {{a bound member function may only be called}}
- if (!p->m) {}; // expected-error {{a bound member function may only be called}}
+ p->*m; // expected-error {{reference to non-static member function must be called}}
+ (void)(p->*m); // expected-error {{reference to non-static member function must be called}}
+ (void)(void*)(p->*m); // expected-error {{reference to non-static member function must be called}} expected-error {{cannot cast from type 'void' to pointer type 'void *'}}
+ (void)reinterpret_cast<void*>(p->*m); // expected-error {{reference to non-static member function must be called}} expected-error {{reinterpret_cast from 'void' to 'void *' is not allowed}}
+ if (p->*m) {} // expected-error {{reference to non-static member function must be called}} expected-error {{value of type 'void' is not contextually convertible to 'bool'}}
+ if (!(p->*m)) {} // expected-error {{reference to non-static member function must be called}} expected-error {{invalid argument type 'void' to unary expression}}
+ if (p->m) {}; // expected-error {{reference to non-static member function must be called}} expected-error {{value of type 'void' is not contextually convertible to 'bool'}}
+ if (!p->m) {}; // expected-error {{reference to non-static member function must be called}} expected-error {{invalid argument type 'void' to unary expression}}
}
diff --git a/test/SemaCXX/redeclared-alias-template.cpp b/test/SemaCXX/redeclared-alias-template.cpp
index b368fcfe5508..09e9d0d83bf5 100644
--- a/test/SemaCXX/redeclared-alias-template.cpp
+++ b/test/SemaCXX/redeclared-alias-template.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<typename T> using A = int; // expected-note 2{{previous}}
template<typename T> using A = char; // expected-error {{type alias template redefinition with different types ('char' vs 'int')}}
diff --git a/test/SemaCXX/redeclared-auto.cpp b/test/SemaCXX/redeclared-auto.cpp
index 34de54c0f01d..87ad6bd7e5d8 100644
--- a/test/SemaCXX/redeclared-auto.cpp
+++ b/test/SemaCXX/redeclared-auto.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
extern int a;
auto a = 0; // expected-note 2{{here}}
diff --git a/test/SemaCXX/ref-init-ambiguous.cpp b/test/SemaCXX/ref-init-ambiguous.cpp
index 752a3484d025..ce47e10c9ae3 100644
--- a/test/SemaCXX/ref-init-ambiguous.cpp
+++ b/test/SemaCXX/ref-init-ambiguous.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
enum E2 { };
diff --git a/test/SemaCXX/references.cpp b/test/SemaCXX/references.cpp
index ab44e78453b2..70d3799a0ea5 100644
--- a/test/SemaCXX/references.cpp
+++ b/test/SemaCXX/references.cpp
@@ -134,3 +134,6 @@ namespace PR7149 {
namespace PR8608 {
bool& f(unsigned char& c) { return (bool&)c; }
}
+
+// The following crashed trying to recursively evaluate the LValue.
+const int &do_not_crash = do_not_crash;
diff --git a/test/SemaCXX/return-noreturn.cpp b/test/SemaCXX/return-noreturn.cpp
index 53ed0d724527..e06ba403efec 100644
--- a/test/SemaCXX/return-noreturn.cpp
+++ b/test/SemaCXX/return-noreturn.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code
+// RUN: %clang_cc1 %s -fsyntax-only -std=c++11 -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code
// A destructor may be marked noreturn and should still influence the CFG.
void pr6884_abort() __attribute__((noreturn));
@@ -8,23 +9,93 @@ struct pr6884_abort_struct {
~pr6884_abort_struct() __attribute__((noreturn)) { pr6884_abort(); }
};
-int pr6884_f(int x) {
- switch (x) { default: pr6884_abort(); }
-}
+struct other { ~other() {} };
-int pr6884_g(int x) {
- switch (x) { default: pr6884_abort_struct(); }
-}
+// Ensure that destructors from objects are properly modeled in the CFG despite
+// the presence of switches, case statements, labels, and blocks. These tests
+// try to cover bugs reported in both PR6884 and PR10063.
+namespace abort_struct_complex_cfgs {
+ int basic(int x) {
+ switch (x) { default: pr6884_abort(); }
+ }
+ int f1(int x) {
+ switch (x) default: pr6884_abort_struct();
+ }
+ int f2(int x) {
+ switch (x) { default: pr6884_abort_struct(); }
+ }
+ int f2_positive(int x) {
+ switch (x) { default: ; }
+ } // expected-warning {{control reaches end of non-void function}}
+ int f3(int x) {
+ switch (x) { default: { pr6884_abort_struct(); } }
+ }
+ int f4(int x) {
+ switch (x) default: L1: L2: case 4: pr6884_abort_struct();
+ }
+ int f5(int x) {
+ switch (x) default: L1: { L2: case 4: pr6884_abort_struct(); }
+ }
+ int f6(int x) {
+ switch (x) default: L1: L2: case 4: { pr6884_abort_struct(); }
+ }
-int pr6884_g_positive(int x) {
- switch (x) { default: ; }
-} // expected-warning {{control reaches end of non-void function}}
+ // Test that these constructs work even when extraneous blocks are created
+ // before and after the switch due to implicit destructors.
+ int g1(int x) {
+ other o;
+ switch (x) default: pr6884_abort_struct();
+ }
+ int g2(int x) {
+ other o;
+ switch (x) { default: pr6884_abort_struct(); }
+ }
+ int g2_positive(int x) {
+ other o;
+ switch (x) { default: ; }
+ } // expected-warning {{control reaches end of non-void function}}
+ int g3(int x) {
+ other o;
+ switch (x) { default: { pr6884_abort_struct(); } }
+ }
+ int g4(int x) {
+ other o;
+ switch (x) default: L1: L2: case 4: pr6884_abort_struct();
+ }
+ int g5(int x) {
+ other o;
+ switch (x) default: L1: { L2: case 4: pr6884_abort_struct(); }
+ }
+ int g6(int x) {
+ other o;
+ switch (x) default: L1: L2: case 4: { pr6884_abort_struct(); }
+ }
-int pr6884_h(int x) {
- switch (x) {
- default: {
- pr6884_abort_struct a;
- }
+ // Test that these constructs work even with variables carrying the no-return
+ // destructor instead of temporaries.
+ int h1(int x) {
+ other o;
+ switch (x) default: pr6884_abort_struct a;
+ }
+ int h2(int x) {
+ other o;
+ switch (x) { default: pr6884_abort_struct a; }
+ }
+ int h3(int x) {
+ other o;
+ switch (x) { default: { pr6884_abort_struct a; } }
+ }
+ int h4(int x) {
+ other o;
+ switch (x) default: L1: L2: case 4: pr6884_abort_struct a;
+ }
+ int h5(int x) {
+ other o;
+ switch (x) default: L1: { L2: case 4: pr6884_abort_struct a; }
+ }
+ int h6(int x) {
+ other o;
+ switch (x) default: L1: L2: case 4: { pr6884_abort_struct a; }
}
}
diff --git a/test/SemaCXX/rval-references-examples.cpp b/test/SemaCXX/rval-references-examples.cpp
index f4921a9b5168..110ae26fb5d2 100644
--- a/test/SemaCXX/rval-references-examples.cpp
+++ b/test/SemaCXX/rval-references-examples.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
template<typename T>
class unique_ptr {
diff --git a/test/SemaCXX/rval-references.cpp b/test/SemaCXX/rval-references.cpp
index 74afdbe41043..fc341e87f4a4 100644
--- a/test/SemaCXX/rval-references.cpp
+++ b/test/SemaCXX/rval-references.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 %s
typedef int&& irr;
typedef irr& ilr_c1; // Collapses to int&
diff --git a/test/SemaCXX/scope-check.cpp b/test/SemaCXX/scope-check.cpp
index 3a90cc08f6a2..ad109f4d4e03 100644
--- a/test/SemaCXX/scope-check.cpp
+++ b/test/SemaCXX/scope-check.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s -Wno-unreachable-code
-// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -std=gnu++0x %s -Wno-unreachable-code
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -std=gnu++11 %s -Wno-unreachable-code
namespace test0 {
struct D { ~D(); };
@@ -171,3 +171,39 @@ namespace test9 {
}
}
}
+
+// http://llvm.org/PR10462
+namespace PR10462 {
+enum MyEnum {
+ something_valid,
+ something_invalid
+};
+
+bool recurse() {
+ MyEnum K;
+ switch (K) { // expected-warning {{enumeration value 'something_invalid' not handled in switch}}
+ case something_valid:
+ case what_am_i_thinking: // expected-error {{use of undeclared identifier}}
+ int *X = 0;
+ if (recurse()) {
+ }
+
+ break;
+ }
+}
+
+
+namespace test10 {
+
+int test() {
+ static void *ps[] = { &&a0 };
+ goto *&&a0; // expected-error {{goto into protected scope}}
+ int a = 3; // expected-note {{jump bypasses variable initialization}}
+ a0:
+ return 0;
+}
+
+}
+
+}
+
diff --git a/test/SemaCXX/static-assert.cpp b/test/SemaCXX/static-assert.cpp
index 516243ec70e1..0991a5f89cc8 100644
--- a/test/SemaCXX/static-assert.cpp
+++ b/test/SemaCXX/static-assert.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
int f();
diff --git a/test/SemaCXX/switch-0x.cpp b/test/SemaCXX/switch-0x.cpp
index adaeb85bce17..2e74da0a4634 100644
--- a/test/SemaCXX/switch-0x.cpp
+++ b/test/SemaCXX/switch-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// PR5518
struct A {
diff --git a/test/SemaCXX/trailing-return-0x.cpp b/test/SemaCXX/trailing-return-0x.cpp
index b52b240da35d..e25939fa3ebf 100644
--- a/test/SemaCXX/trailing-return-0x.cpp
+++ b/test/SemaCXX/trailing-return-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template <class T>
struct only
diff --git a/test/SemaCXX/trivial-constructor.cpp b/test/SemaCXX/trivial-constructor.cpp
index 494d1ec0843f..bda206b61f9a 100644
--- a/test/SemaCXX/trivial-constructor.cpp
+++ b/test/SemaCXX/trivial-constructor.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
struct T1 {
};
static_assert(__has_trivial_constructor(T1), "T1 has trivial constructor!");
diff --git a/test/SemaCXX/trivial-destructor.cpp b/test/SemaCXX/trivial-destructor.cpp
index 29358d8bd228..db415cf9050a 100644
--- a/test/SemaCXX/trivial-destructor.cpp
+++ b/test/SemaCXX/trivial-destructor.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
struct T1 {
};
static_assert(__has_trivial_destructor(T1), "T1 has trivial destructor!");
diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp
index 30cc6a3f1ce2..0914c7cf94e3 100644
--- a/test/SemaCXX/type-traits.cpp
+++ b/test/SemaCXX/type-traits.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++0x %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++11 %s
#define T(b) (b) ? 1 : -1
#define F(b) (b) ? -1 : 1
@@ -89,6 +89,13 @@ struct HasVirtDest { virtual ~HasVirtDest(); };
struct DerivedVirtDest : HasVirtDest {};
typedef HasVirtDest VirtDestAr[1];
+class AllPrivate {
+ AllPrivate() throw();
+ AllPrivate(const AllPrivate&) throw();
+ AllPrivate &operator=(const AllPrivate &) throw();
+ ~AllPrivate() throw();
+};
+
void is_pod()
{
{ int arr[T(__is_pod(int))]; }
@@ -1102,6 +1109,7 @@ void has_trivial_default_constructor() {
{ int arr[F(__has_trivial_constructor(void))]; }
{ int arr[F(__has_trivial_constructor(cvoid))]; }
{ int arr[F(__has_trivial_constructor(HasTemplateCons))]; }
+ { int arr[F(__has_trivial_constructor(AllPrivate))]; }
}
void has_trivial_copy_constructor() {
@@ -1129,6 +1137,7 @@ void has_trivial_copy_constructor() {
{ int arr[F(__has_trivial_copy(VirtAr))]; }
{ int arr[F(__has_trivial_copy(void))]; }
{ int arr[F(__has_trivial_copy(cvoid))]; }
+ { int arr[F(__has_trivial_copy(AllPrivate))]; }
}
void has_trivial_copy_assignment() {
@@ -1155,6 +1164,7 @@ void has_trivial_copy_assignment() {
{ int arr[F(__has_trivial_assign(VirtAr))]; }
{ int arr[F(__has_trivial_assign(void))]; }
{ int arr[F(__has_trivial_assign(cvoid))]; }
+ { int arr[F(__has_trivial_assign(AllPrivate))]; }
}
void has_trivial_destructor() {
@@ -1181,6 +1191,7 @@ void has_trivial_destructor() {
{ int arr[F(__has_trivial_destructor(HasDest))]; }
{ int arr[F(__has_trivial_destructor(void))]; }
{ int arr[F(__has_trivial_destructor(cvoid))]; }
+ { int arr[F(__has_trivial_destructor(AllPrivate))]; }
}
struct A { ~A() {} };
@@ -1191,6 +1202,23 @@ void f() {
{ int arr[F(__has_trivial_destructor(B<int>))]; }
}
+class PR11110 {
+ template <int> int operator=( int );
+ int operator=(PR11110);
+};
+
+class UsingAssign;
+
+class UsingAssignBase {
+protected:
+ UsingAssign &operator=(const UsingAssign&) throw();
+};
+
+class UsingAssign : public UsingAssignBase {
+public:
+ using UsingAssignBase::operator=;
+};
+
void has_nothrow_assign() {
{ int arr[T(__has_nothrow_assign(Int))]; }
{ int arr[T(__has_nothrow_assign(IntAr))]; }
@@ -1208,6 +1236,8 @@ void has_nothrow_assign() {
{ int arr[T(__has_nothrow_assign(HasNoThrowCopyAssign))]; }
{ int arr[T(__has_nothrow_assign(HasMultipleNoThrowCopyAssign))]; }
{ int arr[T(__has_nothrow_assign(HasVirtDest))]; }
+ { int arr[T(__has_nothrow_assign(AllPrivate))]; }
+ { int arr[T(__has_nothrow_assign(UsingAssign))]; }
{ int arr[F(__has_nothrow_assign(IntRef))]; }
{ int arr[F(__has_nothrow_assign(HasCopyAssign))]; }
@@ -1219,6 +1249,7 @@ void has_nothrow_assign() {
{ int arr[F(__has_nothrow_assign(VirtAr))]; }
{ int arr[F(__has_nothrow_assign(void))]; }
{ int arr[F(__has_nothrow_assign(cvoid))]; }
+ { int arr[F(__has_nothrow_assign(PR11110))]; }
}
void has_nothrow_copy() {
@@ -1243,6 +1274,7 @@ void has_nothrow_copy() {
{ int arr[T(__has_nothrow_copy(HasMultipleNoThrowCopy))]; }
{ int arr[T(__has_nothrow_copy(HasVirtDest))]; }
{ int arr[T(__has_nothrow_copy(HasTemplateCons))]; }
+ { int arr[T(__has_nothrow_copy(AllPrivate))]; }
{ int arr[F(__has_nothrow_copy(HasCopy))]; }
{ int arr[F(__has_nothrow_copy(HasMultipleCopy))]; }
@@ -1272,6 +1304,7 @@ void has_nothrow_constructor() {
{ int arr[T(__has_nothrow_constructor(HasNoThrowConstructor))]; }
{ int arr[T(__has_nothrow_constructor(HasVirtDest))]; }
// { int arr[T(__has_nothrow_constructor(VirtAr))]; } // not implemented
+ { int arr[T(__has_nothrow_constructor(AllPrivate))]; }
{ int arr[F(__has_nothrow_constructor(HasCons))]; }
{ int arr[F(__has_nothrow_constructor(HasRef))]; }
@@ -1316,6 +1349,7 @@ void has_virtual_destructor() {
{ int arr[F(__has_virtual_destructor(VirtDestAr))]; }
{ int arr[F(__has_virtual_destructor(void))]; }
{ int arr[F(__has_virtual_destructor(cvoid))]; }
+ { int arr[F(__has_virtual_destructor(AllPrivate))]; }
}
diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp
new file mode 100644
index 000000000000..fa32c57fc7ed
--- /dev/null
+++ b/test/SemaCXX/typo-correction.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++0x-extensions %s
+
+struct errc {
+ int v_;
+ operator int() const {return v_;}
+};
+
+class error_condition
+{
+ int _val_;
+public:
+ error_condition() : _val_(0) {}
+
+ error_condition(int _val)
+ : _val_(_val) {}
+
+ template <class E>
+ error_condition(E _e) {
+ // make_error_condition must not be typo corrected to error_condition
+ // even though the first declaration of make_error_condition has not
+ // yet been encountered. This was a bug in the first version of the type
+ // name typo correction patch that wasn't noticed until building LLVM with
+ // Clang failed.
+ *this = make_error_condition(_e);
+ }
+
+};
+
+inline error_condition make_error_condition(errc _e) {
+ return error_condition(static_cast<int>(_e));
+}
diff --git a/test/SemaCXX/underlying_type.cpp b/test/SemaCXX/underlying_type.cpp
index 607d9ad843a4..dcfaab3c8b4d 100644
--- a/test/SemaCXX/underlying_type.cpp
+++ b/test/SemaCXX/underlying_type.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -ffreestanding -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -ffreestanding -fsyntax-only -verify -std=c++11 %s
#include "limits.h"
diff --git a/test/SemaCXX/uninit-variables-conditional.cpp b/test/SemaCXX/uninit-variables-conditional.cpp
index 3324215621bf..3c44c7249d51 100644
--- a/test/SemaCXX/uninit-variables-conditional.cpp
+++ b/test/SemaCXX/uninit-variables-conditional.cpp
@@ -15,7 +15,7 @@ int init(double *);
// the destructor in Foo fouls about the minor bit of path-sensitivity in
// -Wuninitialized.
double test() {
- double x; // expected-note {{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
+ double x; // expected-note{{initialize the variable 'x' to silence this warning}}
if (bar() || baz() || Foo() || init(&x))
return 1.0;
diff --git a/test/SemaCXX/uninit-variables.cpp b/test/SemaCXX/uninit-variables.cpp
index a0180e3d3a15..358a5723563f 100644
--- a/test/SemaCXX/uninit-variables.cpp
+++ b/test/SemaCXX/uninit-variables.cpp
@@ -26,7 +26,7 @@ void unevaluated_tests() {
// Warn for glvalue arguments to typeid whose type is polymorphic.
struct A { virtual ~A() {} };
void polymorphic_test() {
- A *a; // expected-note{{declared here}} expected-note{{add initialization}}
+ A *a; // expected-note{{initialize the variable 'a' to silence this warning}}
(void)typeid(*a); // expected-warning{{variable 'a' is uninitialized when used here }}
}
@@ -50,7 +50,7 @@ unsigned test3_b() {
return x; // no-warning
}
unsigned test3_c() {
- unsigned x; // expected-note{{declared here}} expected-note{{add initialization}}
+ unsigned x; // expected-note{{initialize the variable 'x' to silence this warning}}
const bool flag = false;
if (flag && (x = test3_aux()) == 0) {
x = 1;
@@ -66,6 +66,16 @@ test4_A test4() {
return a; // expected-warning{{variable 'a' is uninitialized when used here}}
}
+// Test variables getting invalidated by function calls with reference arguments
+// *AND* there are multiple invalidated arguments.
+void test5_aux(int &, int &);
+
+int test5() {
+ int x, y;
+ test5_aux(x, y);
+ return x + y; // no-warning
+}
+
// This test previously crashed Sema.
class Rdar9188004A {
public:
@@ -108,4 +118,26 @@ void RDar9251392() {
}
}
+// Test handling of "no-op" casts.
+void test_noop_cast()
+{
+ int x = 1;
+ int y = (int&)x; // no-warning
+}
+
+void test_noop_cast2() {
+ int x; // expected-note {{initialize the variable 'x' to silence this warning}}
+ int y = (int&)x; // expected-warning {{uninitialized when used here}}
+}
+
+// Test handling of bit casts.
+void test_bitcasts() {
+ int x = 1;
+ int y = (float &)x; // no-warning
+}
+
+void test_bitcasts_2() {
+ int x; // expected-note {{initialize the variable 'x' to silence this warning}}
+ int y = (float &)x; // expected-warning {{uninitialized when used here}}
+}
diff --git a/test/SemaCXX/uninitialized.cpp b/test/SemaCXX/uninitialized.cpp
index 0a3b5d938dd3..c25bd201d626 100644
--- a/test/SemaCXX/uninitialized.cpp
+++ b/test/SemaCXX/uninitialized.cpp
@@ -24,6 +24,78 @@ int i = boo(i);
int j = far(j);
int k = __alignof__(k);
+
+// Test self-references with record types.
+class A {
+ // Non-POD class.
+ public:
+ enum count { ONE, TWO, THREE };
+ int num;
+ static int count;
+ int get() const { return num; }
+ void set(int x) { num = x; }
+ static int zero() { return 0; }
+
+ A() {}
+ A(A const &a) {}
+ A(int x) {}
+ A(int *x) {}
+ A(A *a) {}
+};
+
+A getA() { return A(); }
+A getA(int x) { return A(); }
+A getA(A* a) { return A(); }
+
+void setupA() {
+ A a1;
+ a1.set(a1.get());
+ A a2(a1.get());
+ A a3(a1);
+ A a4(&a4);
+ A a5(a5.zero());
+ A a6(a6.ONE);
+ A a7 = getA();
+ A a8 = getA(a8.TWO);
+ A a9 = getA(&a9);
+ A a10(a10.count);
+
+ A a11(a11); // expected-warning {{variable 'a11' is uninitialized when used within its own initialization}}
+ A a12(a12.get()); // expected-warning {{variable 'a12' is uninitialized when used within its own initialization}}
+ A a13(a13.num); // expected-warning {{variable 'a13' is uninitialized when used within its own initialization}}
+ A a14 = A(a14); // expected-warning {{variable 'a14' is uninitialized when used within its own initialization}}
+ A a15 = getA(a15.num); // expected-warning {{variable 'a15' is uninitialized when used within its own initialization}}
+ A a16(&a16.num); // expected-warning {{variable 'a16' is uninitialized when used within its own initialization}}
+}
+
+struct B {
+ // POD struct.
+ int x;
+ int *y;
+};
+
+B getB() { return B(); };
+B getB(int x) { return B(); };
+B getB(int *x) { return B(); };
+B getB(B *b) { return B(); };
+
+void setupB() {
+ B b1;
+ B b2(b1);
+ B b3 = { 5, &b3.x };
+ B b4 = getB();
+ B b5 = getB(&b5);
+ B b6 = getB(&b6.x);
+
+ // Silence unused warning
+ (void) b2;
+ (void) b4;
+
+ B b7(b7); // expected-warning {{variable 'b7' is uninitialized when used within its own initialization}}
+ B b8 = getB(b8.x); // expected-warning {{variable 'b8' is uninitialized when used within its own initialization}}
+ B b9 = getB(b9.y); // expected-warning {{variable 'b9' is uninitialized when used within its own initialization}}
+}
+
// Also test similar constructs in a field's initializer.
struct S {
int x;
@@ -43,3 +115,5 @@ struct S {
S(char (*)[5]) : x(boo(x)) {}
S(char (*)[6]) : x(far(x)) {}
};
+
+struct C { char a[100], *e; } car = { .e = car.a };
diff --git a/test/SemaCXX/unknown-anytype.cpp b/test/SemaCXX/unknown-anytype.cpp
index b0a2981f470d..ba52122bc490 100644
--- a/test/SemaCXX/unknown-anytype.cpp
+++ b/test/SemaCXX/unknown-anytype.cpp
@@ -34,3 +34,14 @@ namespace test3 {
((void(void)) foo)(); // expected-error {{variable 'foo' with unknown type cannot be given a function type}}
}
}
+
+// rdar://problem/9899447
+namespace test4 {
+ extern __unknown_anytype test0(...);
+ extern __unknown_anytype test1(...);
+
+ void test() {
+ void (*fn)(int) = (void(*)(int)) test0;
+ int x = (int) test1; // expected-error {{function 'test1' with unknown type must be given a function type}}
+ }
+}
diff --git a/test/SemaCXX/unused-functions.cpp b/test/SemaCXX/unused-functions.cpp
index f164bf276846..359808203892 100644
--- a/test/SemaCXX/unused-functions.cpp
+++ b/test/SemaCXX/unused-functions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -Wunused -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wunused -verify %s
static int foo(int x) { return x; }
diff --git a/test/SemaCXX/user-defined-conversions.cpp b/test/SemaCXX/user-defined-conversions.cpp
index 5de7f44be92c..43ec5a3d4ab9 100644
--- a/test/SemaCXX/user-defined-conversions.cpp
+++ b/test/SemaCXX/user-defined-conversions.cpp
@@ -82,3 +82,18 @@ float &f(...);
void g(X2 b) {
int &ir = f(b); // expected-error{{no viable constructor copying parameter of type 'X1'}}
}
+
+namespace rdar10202900 {
+ class A {
+ public:
+ A();
+
+ private:
+ A(int i); // expected-note{{declared private here}}
+ };
+
+ void testA(A a) {
+ int b = 10;
+ a = b; // expected-error{{calling a private constructor of class 'rdar10202900::A'}}
+ }
+}
diff --git a/test/SemaCXX/using-decl-templates.cpp b/test/SemaCXX/using-decl-templates.cpp
index 7b4da9d50d03..2f8abca02d6e 100644
--- a/test/SemaCXX/using-decl-templates.cpp
+++ b/test/SemaCXX/using-decl-templates.cpp
@@ -63,3 +63,20 @@ template <class T> struct Bar : public Foo<T>, Baz {
};
template int Bar<int>::foo();
}
+
+// PR10883
+namespace PR10883 {
+ template <typename T>
+ class Base {
+ public:
+ typedef long Container;
+ };
+
+ template <typename T>
+ class Derived : public Base<T> {
+ public:
+ using Base<T>::Container;
+
+ void foo(const Container& current); // expected-error {{unknown type name 'Container'}}
+ };
+}
diff --git a/test/SemaCXX/value-initialization.cpp b/test/SemaCXX/value-initialization.cpp
index dfe0f46ea255..19be03af8f46 100644
--- a/test/SemaCXX/value-initialization.cpp
+++ b/test/SemaCXX/value-initialization.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
struct A { //expected-note {{marked deleted here}} \
// expected-warning {{does not declare any constructor to initialize}}
diff --git a/test/SemaCXX/vararg-non-pod.cpp b/test/SemaCXX/vararg-non-pod.cpp
index 3ca07b0215c3..42c27fb30e1b 100644
--- a/test/SemaCXX/vararg-non-pod.cpp
+++ b/test/SemaCXX/vararg-non-pod.cpp
@@ -118,4 +118,3 @@ void t8(int n, ...) {
(void)__builtin_va_arg(list, Abstract); // expected-error{{second argument to 'va_arg' is of abstract type 'Abstract'}}
__builtin_va_end(list);
}
-
diff --git a/test/SemaCXX/virtual-override.cpp b/test/SemaCXX/virtual-override.cpp
index 23d86d37426e..b477438ee988 100644
--- a/test/SemaCXX/virtual-override.cpp
+++ b/test/SemaCXX/virtual-override.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
namespace T1 {
class A {
diff --git a/test/SemaCXX/virtuals.cpp b/test/SemaCXX/virtuals.cpp
index d8c26efcfb42..ea7d203ca70f 100644
--- a/test/SemaCXX/virtuals.cpp
+++ b/test/SemaCXX/virtuals.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++11 %s
class A {
virtual void f();
diff --git a/test/SemaCXX/warn-assignment-condition.cpp b/test/SemaCXX/warn-assignment-condition.cpp
index c0ef35b252d8..04f2e7952547 100644
--- a/test/SemaCXX/warn-assignment-condition.cpp
+++ b/test/SemaCXX/warn-assignment-condition.cpp
@@ -109,6 +109,12 @@ void test() {
if ((x == 5)) {} // expected-warning {{equality comparison with extraneous parentheses}} \
// expected-note {{use '=' to turn this equality comparison into an assignment}} \
// expected-note {{remove extraneous parentheses around the comparison to silence this warning}}
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wparentheses-equality"
+ if ((x == 5)) {} // no-warning
+#pragma clang diagnostic pop
+
if ((5 == x)) {}
#define EQ(x,y) ((x) == (y))
diff --git a/test/SemaCXX/warn-bad-memaccess.cpp b/test/SemaCXX/warn-bad-memaccess.cpp
index 9a998f020cb4..3a02c84e9fc4 100644
--- a/test/SemaCXX/warn-bad-memaccess.cpp
+++ b/test/SemaCXX/warn-bad-memaccess.cpp
@@ -3,6 +3,7 @@
extern "C" void *memset(void *, int, unsigned);
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);
// Several types that should not warn.
struct S1 {} s1;
@@ -27,16 +28,22 @@ void test_warn() {
// expected-note {{explicitly cast the pointer to silence this warning}}
memmove(&x1, 0, sizeof x1); // \
- // expected-warning{{destination for this 'memmove' call is a pointer to dynamic class}} \
+ // expected-warning{{destination for this 'memmove' call is a pointer to dynamic class 'struct X1'; vtable pointer will be overwritten}} \
// expected-note {{explicitly cast the pointer to silence this warning}}
memmove(0, &x1, sizeof x1); // \
- // expected-warning{{source of this 'memmove' call is a pointer to dynamic class}} \
+ // expected-warning{{source of this 'memmove' call is a pointer to dynamic class 'struct X1'; vtable pointer will be moved}} \
// expected-note {{explicitly cast the pointer to silence this warning}}
memcpy(&x1, 0, sizeof x1); // \
- // expected-warning{{destination for this 'memcpy' call is a pointer to dynamic class}} \
+ // expected-warning{{destination for this 'memcpy' call is a pointer to dynamic class 'struct X1'; vtable pointer will be overwritten}} \
// expected-note {{explicitly cast the pointer to silence this warning}}
memcpy(0, &x1, sizeof x1); // \
- // expected-warning{{source of this 'memcpy' call is a pointer to dynamic class}} \
+ // expected-warning{{source of this 'memcpy' call is a pointer to dynamic class 'struct X1'; vtable pointer will be copied}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ memcmp(&x1, 0, sizeof x1); // \
+ // expected-warning{{first operand of this 'memcmp' call is a pointer to dynamic class 'struct X1'; vtable pointer will be compared}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ memcmp(0, &x1, sizeof x1); // \
+ // expected-warning{{second operand of this 'memcmp' call is a pointer to dynamic class 'struct X1'; vtable pointer will be compared}} \
// expected-note {{explicitly cast the pointer to silence this warning}}
__builtin_memset(&x1, 0, sizeof x1); // \
@@ -108,5 +115,3 @@ namespace N {
N::memset(&x1, 0, sizeof x1);
}
}
-
-
diff --git a/test/SemaCXX/warn-bool-conversion.cpp b/test/SemaCXX/warn-bool-conversion.cpp
index f6fa9f28369d..595c749bcecd 100644
--- a/test/SemaCXX/warn-bool-conversion.cpp
+++ b/test/SemaCXX/warn-bool-conversion.cpp
@@ -1,18 +1,18 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-int* j = false; // expected-warning{{ initialization of pointer of type 'int *' to NULL from a constant boolean expression}}
+int* j = false; // expected-warning{{ initialization of pointer of type 'int *' to null from a constant boolean expression}}
-void foo(int* i, int *j=(false)) // expected-warning{{ initialization of pointer of type 'int *' to NULL from a constant boolean expression}}
+void foo(int* i, int *j=(false)) // expected-warning{{ initialization of pointer of type 'int *' to null from a constant boolean expression}}
{
- foo(false); // expected-warning{{ initialization of pointer of type 'int *' to NULL from a constant boolean expression}}
+ foo(false); // expected-warning{{ initialization of pointer of type 'int *' to null from a constant boolean expression}}
foo((int*)false); // no-warning: explicit cast
foo(0); // no-warning: not a bool, even though its convertible to bool
- foo(false == true); // expected-warning{{ initialization of pointer of type 'int *' to NULL from a constant boolean expression}}
- foo((42 + 24) < 32); // expected-warning{{ initialization of pointer of type 'int *' to NULL from a constant boolean expression}}
+ foo(false == true); // expected-warning{{ initialization of pointer of type 'int *' to null from a constant boolean expression}}
+ foo((42 + 24) < 32); // expected-warning{{ initialization of pointer of type 'int *' to null from a constant boolean expression}}
const bool kFlag = false;
- foo(kFlag); // expected-warning{{ initialization of pointer of type 'int *' to NULL from a constant boolean expression}}
+ foo(kFlag); // expected-warning{{ initialization of pointer of type 'int *' to null from a constant boolean expression}}
}
char f(struct Undefined*);
diff --git a/test/SemaCXX/warn-dangling-field.cpp b/test/SemaCXX/warn-dangling-field.cpp
new file mode 100644
index 000000000000..95f8c61ebb77
--- /dev/null
+++ b/test/SemaCXX/warn-dangling-field.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fsyntax-only -Wdangling-field -verify %s
+
+struct X {
+ X(int);
+};
+struct Y {
+ operator X*();
+ operator X&();
+};
+
+struct S {
+ int &x, *y; // expected-note {{reference member declared here}} \
+ // expected-note {{pointer member declared here}}
+ S(int i)
+ : x(i), // expected-warning {{binding reference member 'x' to stack allocated parameter 'i'}}
+ y(&i) {} // expected-warning {{initializing pointer member 'y' with the stack address of parameter 'i'}}
+ S(int &i) : x(i), y(&i) {} // no-warning: reference parameter
+ S(int *i) : x(*i), y(i) {} // no-warning: pointer parameter
+};
+
+struct S2 {
+ const X &x; // expected-note {{reference member declared here}}
+ S2(int i) : x(i) {} // expected-warning {{binding reference member 'x' to a temporary}}
+};
+
+struct S3 {
+ X &x1, *x2;
+ S3(Y y) : x1(y), x2(y) {} // no-warning: conversion operator
+};
+
+template <typename T> struct S4 {
+ T x; // expected-note {{reference member declared here}}
+ S4(int i) : x(i) {} // expected-warning {{binding reference member 'x' to stack allocated parameter 'i'}}
+};
+
+template struct S4<int>; // no warning from this instantiation
+template struct S4<int&>; // expected-note {{in instantiation}}
diff --git a/test/SemaCXX/warn-literal-conversion.cpp b/test/SemaCXX/warn-literal-conversion.cpp
index b9c952873b9f..5fcae5dc80e6 100644
--- a/test/SemaCXX/warn-literal-conversion.cpp
+++ b/test/SemaCXX/warn-literal-conversion.cpp
@@ -8,18 +8,13 @@ void test0() {
int y0 = 1.2222F; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
int y1 = (1.2222F); // expected-warning {{implicit conversion turns literal floating-point number into integer}}
int y2 = (((1.2222F))); // expected-warning {{implicit conversion turns literal floating-point number into integer}}
- int y3 = 12E1F; // expected-warning {{implicit conversion turns literal floating-point number into integer}} \
- // expected-note {{this can be rewritten as an integer literal with the exact same value}}
- int y4 = 1.2E1F; // expected-warning {{implicit conversion turns literal floating-point number into integer}} \
- // expected-note {{this can be rewritten as an integer literal with the exact same value}}
+ int y3 = 12E-1F; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
+ int y4 = 1.23E1F; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
// Double
int y5 = 1.2222; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
- int y6 = 12E1; // expected-warning {{implicit conversion turns literal floating-point number into integer}} \
- // expected-note {{this can be rewritten as an integer literal with the exact same value}}
- int y7 = 1.2E1; // expected-warning {{implicit conversion turns literal floating-point number into integer}} \
- // expected-note {{this can be rewritten as an integer literal with the exact same value}}
- int y8 = (1.2E1); // expected-warning {{implicit conversion turns literal floating-point number into integer}} \
- // expected-note {{this can be rewritten as an integer literal with the exact same value}}
+ int y6 = 12E-1; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
+ int y7 = 1.23E1; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
+ int y8 = (1.23E1); // expected-warning {{implicit conversion turns literal floating-point number into integer}}
// Test assignment to an existing variable.
y8 = 2.22F; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
@@ -30,8 +25,7 @@ void test0() {
// Test passing a literal floating-point value to a function that takes an integer.
foo(1.2F); // expected-warning {{implicit conversion turns literal floating-point number into integer}}
- // FIXME: -Wconversion-literal doesn't catch "-1.2F".
- int y10 = -1.2F;
+ int y10 = -1.2F; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
// -Wconversion-literal does NOT catch const values.
// (-Wconversion DOES catch them.)
diff --git a/test/SemaCXX/warn-memset-bad-sizeof.cpp b/test/SemaCXX/warn-memset-bad-sizeof.cpp
index 90ac50472e98..a018223cbdae 100644
--- a/test/SemaCXX/warn-memset-bad-sizeof.cpp
+++ b/test/SemaCXX/warn-memset-bad-sizeof.cpp
@@ -3,6 +3,7 @@
extern "C" void *memset(void *, int, unsigned);
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);
struct S {int a, b, c, d;};
typedef S* PS;
@@ -51,6 +52,11 @@ void f(Mat m, const Foo& const_foo, char *buffer) {
memcpy(0, &s, sizeof(&s)); // \
// expected-warning {{argument to 'sizeof' in 'memcpy' call is the same expression as the source}}
+ memmove(ps, 0, sizeof(ps)); // \
+ // expected-warning {{argument to 'sizeof' in 'memmove' call is the same expression as the destination}}
+ memcmp(ps, 0, sizeof(ps)); // \
+ // expected-warning {{argument to 'sizeof' in 'memcmp' call is the same expression as the destination}}
+
/* Shouldn't warn */
memset((void*)&s, 0, sizeof(&s));
memset(&s, 0, sizeof(s));
@@ -99,3 +105,35 @@ void f(Mat m, const Foo& const_foo, char *buffer) {
memcpy(&foo, &arr, sizeof(Foo));
memcpy(&arr, &foo, sizeof(Foo));
}
+
+namespace ns {
+void memset(void* s, char c, int n);
+void f(int* i) {
+ memset(i, 0, sizeof(i));
+}
+}
+
+extern "C" int strncmp(const char *s1, const char *s2, unsigned n);
+extern "C" int strncasecmp(const char *s1, const char *s2, unsigned n);
+extern "C" char *strncpy(char *det, const char *src, unsigned n);
+extern "C" char *strncat(char *dst, const char *src, unsigned n);
+extern "C" char *strndup(const char *src, unsigned n);
+
+void strcpy_and_friends() {
+ const char* FOO = "<- should be an array instead";
+ const char* BAR = "<- this, too";
+
+ strncmp(FOO, BAR, sizeof(FOO)); // \
+ // expected-warning {{argument to 'sizeof' in 'strncmp' call is the same expression as the destination}}
+ strncasecmp(FOO, BAR, sizeof(FOO)); // \
+ // expected-warning {{argument to 'sizeof' in 'strncasecmp' call is the same expression as the destination}}
+
+ char buff[80];
+
+ strncpy(buff, BAR, sizeof(BAR)); // \
+ // expected-warning {{argument to 'sizeof' in 'strncpy' call is the same expression as the source}}
+ strncat(buff, BAR, sizeof(BAR)); // \
+ // expected-warning {{argument to 'sizeof' in 'strncat' call is the same expression as the source}}
+ strndup(FOO, sizeof(FOO)); // \
+ // expected-warning {{argument to 'sizeof' in 'strndup' call is the same expression as the source}}
+}
diff --git a/test/SemaCXX/warn-missing-noreturn.cpp b/test/SemaCXX/warn-missing-noreturn.cpp
index 4caff66af703..8072ac6b8249 100644
--- a/test/SemaCXX/warn-missing-noreturn.cpp
+++ b/test/SemaCXX/warn-missing-noreturn.cpp
@@ -1,27 +1,27 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -Wmissing-noreturn -Wreturn-type
void f() __attribute__((noreturn));
-template<typename T> void g(T) { // expected-warning {{function could be attribute 'noreturn'}}
+template<typename T> void g(T) {
f();
}
-template void g<int>(int); // expected-note {{in instantiation of function template specialization 'g<int>' requested here}}
+template void g<int>(int);
template<typename T> struct A {
- void g() { // expected-warning {{function could be attribute 'noreturn'}}
+ void g() {
f();
}
};
-template struct A<int>; // expected-note {{in instantiation of member function 'A<int>::g' requested here}}
+template struct A<int>;
struct B {
- template<typename T> void g(T) { // expected-warning {{function could be attribute 'noreturn'}}
+ template<typename T> void g(T) {
f();
}
};
-template void B::g<int>(int); // expected-note {{in instantiation of function template specialization 'B::g<int>' requested here}}
+template void B::g<int>(int);
// We don't want a warning here.
struct X {
@@ -61,7 +61,7 @@ namespace test2 {
void *f;
A() : f(0) { }
- A(int) : f(h()) { } // expected-warning {{function could be attribute 'noreturn'}}
+ A(int) : f(h()) { } // expected-warning {{function 'A' could be declared with attribute 'noreturn'}}
A(char) : f(j()) { }
A(bool b) : f(b ? h() : j()) { }
};
@@ -103,3 +103,23 @@ rdar8875247_B test_rdar8875247_B() {
return f;
} // no-warning
+namespace PR10801 {
+ struct Foo {
+ void wibble() __attribute((__noreturn__));
+ };
+
+ struct Bar {
+ void wibble();
+ };
+
+ template <typename T> void thingy(T thing) {
+ thing.wibble();
+ }
+
+ void test() {
+ Foo f;
+ Bar b;
+ thingy(f);
+ thingy(b);
+ }
+}
diff --git a/test/SemaCXX/warn-sign-compare.cpp b/test/SemaCXX/warn-sign-compare.cpp
deleted file mode 100644
index 3042bfde6e06..000000000000
--- a/test/SemaCXX/warn-sign-compare.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-// RUN: %clang_cc1 -verify -fsyntax-only -Wsign-compare %s
-
-// NOTE: When a 'enumeral mismatch' warning is implemented then expect several
-// of the following cases to be impacted.
-
-// namespace for anonymous enums tests
-namespace test1 {
- enum { A };
- enum { B = -1 };
-
- template <typename T> struct Foo {
- enum { C };
- enum { D = ~0U };
- };
-
- enum { E = ~0U };
-
- void doit_anonymous( int i ) {
- int a1 = 1 ? i : A;
- int a2 = 1 ? A : i;
-
- int b1 = 1 ? i : B;
- int b2 = 1 ? B : i;
-
- int c1 = 1 ? i : Foo<bool>::C;
- int c2 = 1 ? Foo<bool>::C : i;
-
- int d1 = 1 ? i : Foo<bool>::D; // expected-warning {{operands of ? are integers of different signs}}
- int d2 = 1 ? Foo<bool>::D : i; // expected-warning {{operands of ? are integers of different signs}}
- int d3 = 1 ? B : Foo<bool>::D; // expected-warning {{operands of ? are integers of different signs}}
- int d4 = 1 ? Foo<bool>::D : B; // expected-warning {{operands of ? are integers of different signs}}
-
- int e1 = 1 ? i : E; // expected-warning {{operands of ? are integers of different signs}}
- int e2 = 1 ? E : i; // expected-warning {{operands of ? are integers of different signs}}
- int e3 = 1 ? E : B; // expected-warning {{operands of ? are integers of different signs}}
- int e4 = 1 ? B : E; // expected-warning {{operands of ? are integers of different signs}}
- }
-}
-
-// namespace for named enums tests
-namespace test2 {
- enum Named1 { A };
- enum Named2 { B = -1 };
-
- template <typename T> struct Foo {
- enum Named3 { C };
- enum Named4 { D = ~0U };
- };
-
- enum Named5 { E = ~0U };
-
- void doit_anonymous( int i ) {
- int a1 = 1 ? i : A;
- int a2 = 1 ? A : i;
-
- int b1 = 1 ? i : B;
- int b2 = 1 ? B : i;
-
- int c1 = 1 ? i : Foo<bool>::C;
- int c2 = 1 ? Foo<bool>::C : i;
-
- int d1 = 1 ? i : Foo<bool>::D; // expected-warning {{operands of ? are integers of different signs}}
- int d2 = 1 ? Foo<bool>::D : i; // expected-warning {{operands of ? are integers of different signs}}
- int d3 = 1 ? B : Foo<bool>::D; // expected-warning {{operands of ? are integers of different signs}}
- int d4 = 1 ? Foo<bool>::D : B; // expected-warning {{operands of ? are integers of different signs}}
-
- int e1 = 1 ? i : E; // expected-warning {{operands of ? are integers of different signs}}
- int e2 = 1 ? E : i; // expected-warning {{operands of ? are integers of different signs}}
- int e3 = 1 ? E : B; // expected-warning {{operands of ? are integers of different signs}}
- int e4 = 1 ? B : E; // expected-warning {{operands of ? are integers of different signs}}
- }
-}
diff --git a/test/SemaCXX/warn-sign-conversion.cpp b/test/SemaCXX/warn-sign-conversion.cpp
new file mode 100644
index 000000000000..ba2bc9b3d026
--- /dev/null
+++ b/test/SemaCXX/warn-sign-conversion.cpp
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -Wsign-conversion %s
+
+// NOTE: When a 'enumeral mismatch' warning is implemented then expect several
+// of the following cases to be impacted.
+
+// namespace for anonymous enums tests
+namespace test1 {
+ enum { A };
+ enum { B = -1 };
+
+ template <typename T> struct Foo {
+ enum { C };
+ enum { D = ~0U };
+ };
+
+ enum { E = ~0U };
+
+ void doit_anonymous( int i ) {
+ int a1 = 1 ? i : A;
+ int a2 = 1 ? A : i;
+
+ int b1 = 1 ? i : B;
+ int b2 = 1 ? B : i;
+
+ int c1 = 1 ? i : Foo<bool>::C;
+ int c2 = 1 ? Foo<bool>::C : i;
+
+ int d1a = 1 ? i : Foo<bool>::D; // expected-warning {{test1::Foo<bool>::<anonymous enum at }}
+ int d1b = 1 ? i : Foo<bool>::D; // expected-warning {{warn-sign-conversion.cpp:13:5>' to 'int'}}
+ int d2a = 1 ? Foo<bool>::D : i; // expected-warning {{operand of ? changes signedness: 'test1::Foo<bool>::<anonymous enum at }}
+ int d2b = 1 ? Foo<bool>::D : i; // expected-warning {{warn-sign-conversion.cpp:13:5>' to 'int'}}
+ int d3a = 1 ? B : Foo<bool>::D; // expected-warning {{operand of ? changes signedness: 'test1::Foo<bool>::<anonymous enum at }}
+ int d3b = 1 ? B : Foo<bool>::D; // expected-warning {{warn-sign-conversion.cpp:13:5>' to 'int'}}
+ int d4a = 1 ? Foo<bool>::D : B; // expected-warning {{operand of ? changes signedness: 'test1::Foo<bool>::<anonymous enum at }}
+ int d4b = 1 ? Foo<bool>::D : B; // expected-warning {{warn-sign-conversion.cpp:13:5>' to 'int'}}
+
+ int e1a = 1 ? i : E; // expected-warning {{operand of ? changes signedness: 'test1::<anonymous enum at }}
+ int e1b = 1 ? i : E; // expected-warning {{warn-sign-conversion.cpp:16:3>' to 'int'}}
+ int e2a = 1 ? E : i; // expected-warning {{operand of ? changes signedness: 'test1::<anonymous enum at }}
+ int e2b = 1 ? E : i; // expected-warning {{warn-sign-conversion.cpp:16:3>' to 'int'}}
+ int e3a = 1 ? E : B; // expected-warning {{operand of ? changes signedness: 'test1::<anonymous enum at }}
+ int e3b = 1 ? E : B; // expected-warning {{warn-sign-conversion.cpp:16:3>' to 'int'}}
+ int e4a = 1 ? B : E; // expected-warning {{operand of ? changes signedness: 'test1::<anonymous enum at }}
+ int e4b = 1 ? B : E; // expected-warning {{warn-sign-conversion.cpp:16:3>' to 'int'}}
+ }
+}
+
+// namespace for named enums tests
+namespace test2 {
+ enum Named1 { A };
+ enum Named2 { B = -1 };
+
+ template <typename T> struct Foo {
+ enum Named3 { C };
+ enum Named4 { D = ~0U };
+ };
+
+ enum Named5 { E = ~0U };
+
+ void doit_anonymous( int i ) {
+ int a1 = 1 ? i : A;
+ int a2 = 1 ? A : i;
+
+ int b1 = 1 ? i : B;
+ int b2 = 1 ? B : i;
+
+ int c1 = 1 ? i : Foo<bool>::C;
+ int c2 = 1 ? Foo<bool>::C : i;
+
+ int d1 = 1 ? i : Foo<bool>::D; // expected-warning {{operand of ? changes signedness: 'test2::Foo<bool>::Named4' to 'int'}}
+ int d2 = 1 ? Foo<bool>::D : i; // expected-warning {{operand of ? changes signedness: 'test2::Foo<bool>::Named4' to 'int'}}
+ int d3 = 1 ? B : Foo<bool>::D; // expected-warning {{operand of ? changes signedness: 'test2::Foo<bool>::Named4' to 'int'}}
+ int d4 = 1 ? Foo<bool>::D : B; // expected-warning {{operand of ? changes signedness: 'test2::Foo<bool>::Named4' to 'int'}}
+
+ int e1 = 1 ? i : E; // expected-warning {{operand of ? changes signedness: 'test2::Named5' to 'int'}}
+ int e2 = 1 ? E : i; // expected-warning {{operand of ? changes signedness: 'test2::Named5' to 'int'}}
+ int e3 = 1 ? E : B; // expected-warning {{operand of ? changes signedness: 'test2::Named5' to 'int'}}
+ int e4 = 1 ? B : E; // expected-warning {{operand of ? changes signedness: 'test2::Named5' to 'int'}}
+ }
+}
diff --git a/test/SemaCXX/warn-string-conversion.cpp b/test/SemaCXX/warn-string-conversion.cpp
new file mode 100644
index 000000000000..23960e48df61
--- /dev/null
+++ b/test/SemaCXX/warn-string-conversion.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -Wstring-conversion -verify %s
+
+// Warn on cases where a string literal is converted into a bool.
+// An exception is made for this in logical operators.
+void assert(bool condition);
+void test0() {
+ bool b0 = "hi"; // expected-warning{{implicit conversion turns string literal into bool: 'const char [3]' to 'bool'}}
+ b0 = ""; // expected-warning{{implicit conversion turns string literal into bool: 'const char [1]' to 'bool'}}
+ b0 = 0 && "";
+ assert("error"); // expected-warning{{implicit conversion turns string literal into bool: 'const char [6]' to 'bool'}}
+ assert(0 && "error");
+
+ while("hi") {} // expected-warning{{implicit conversion turns string literal into bool: 'const char [3]' to 'bool'}}
+ do {} while("hi"); // expected-warning{{implicit conversion turns string literal into bool: 'const char [3]' to 'bool'}}
+ for (;"hi";); // expected-warning{{implicit conversion turns string literal into bool: 'const char [3]' to 'bool'}}
+ if("hi") {} // expected-warning{{implicit conversion turns string literal into bool: 'const char [3]' to 'bool'}}
+}
+
diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp
new file mode 100644
index 000000000000..90a8933150ac
--- /dev/null
+++ b/test/SemaCXX/warn-thread-safety-analysis.cpp
@@ -0,0 +1,1422 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety %s
+
+#define LOCKABLE __attribute__ ((lockable))
+#define SCOPED_LOCKABLE __attribute__ ((scoped_lockable))
+#define GUARDED_BY(x) __attribute__ ((guarded_by(x)))
+#define GUARDED_VAR __attribute__ ((guarded_var))
+#define PT_GUARDED_BY(x) __attribute__ ((pt_guarded_by(x)))
+#define PT_GUARDED_VAR __attribute__ ((pt_guarded_var))
+#define ACQUIRED_AFTER(...) __attribute__ ((acquired_after(__VA_ARGS__)))
+#define ACQUIRED_BEFORE(...) __attribute__ ((acquired_before(__VA_ARGS__)))
+#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__ ((exclusive_lock_function(__VA_ARGS__)))
+#define SHARED_LOCK_FUNCTION(...) __attribute__ ((shared_lock_function(__VA_ARGS__)))
+#define 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))
+
+//-----------------------------------------//
+// Helper fields
+//-----------------------------------------//
+
+
+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));
+};
+
+
+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)));
+};
+
+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-warning{{mutex 'sls_mu' is still locked at the end of function 'sls_fun_bad_3'}}
+}
+
+void sls_fun_bad_4() {
+ if (getBool())
+ sls_mu.Lock(); // \
+ // expected-warning{{mutex 'sls_mu' is still locked at the end of its scope}}
+ else
+ sls_mu2.Lock(); // \
+ // expected-warning{{mutex 'sls_mu2' is still locked at the end of its scope}}
+}
+
+void sls_fun_bad_5() {
+ sls_mu.Lock(); // \
+ // expected-warning{{mutex 'sls_mu' is still locked at the end of its scope}}
+ if (getBool())
+ sls_mu.Unlock();
+}
+
+void sls_fun_bad_6() {
+ if (getBool()) {
+ sls_mu.Lock(); // \
+ // expected-warning{{mutex 'sls_mu' is still locked at the end of its scope}}
+ } else {
+ if (getBool()) {
+ getBool(); // EMPTY
+ } else {
+ getBool(); // EMPTY
+ }
+ }
+ sls_mu.Unlock(); // \
+ // expected-warning{{unlocking 'sls_mu' that was not locked}}
+}
+
+void sls_fun_bad_7() {
+ sls_mu.Lock(); // \
+ // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+ while (getBool()) {
+ sls_mu.Unlock();
+ if (getBool()) {
+ if (getBool()) {
+ continue;
+ }
+ }
+ sls_mu.Lock(); // \
+ // expected-warning{{mutex 'sls_mu' is still locked at the end of its scope}}
+ }
+ sls_mu.Unlock();
+}
+
+void sls_fun_bad_8() {
+ sls_mu.Lock(); // \
+ // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+ do {
+ sls_mu.Unlock();
+ } 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}}
+ } while (getBool());
+ sls_mu.Unlock();
+}
+
+void sls_fun_bad_10() {
+ sls_mu.Lock(); // \
+ // expected-warning{{mutex 'sls_mu' is still locked at the end of function 'sls_fun_bad_10'}} \
+ // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+ while(getBool()) {
+ sls_mu.Unlock();
+ }
+}
+
+void sls_fun_bad_11() {
+ while (getBool()) {
+ sls_mu.Lock(); // \
+ // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+ }
+ sls_mu.Unlock(); // \
+ // expected-warning{{unlocking 'sls_mu' that was not locked}}
+}
+
+//-----------------------------------------//
+// Handling lock expressions in attribute args
+// -------------------------------------------//
+
+Mutex aa_mu;
+
+class GlobalLocker {
+public:
+ void globalLock() __attribute__((exclusive_lock_function(aa_mu)));
+ void globalUnlock() __attribute__((unlock_function(aa_mu)));
+};
+
+GlobalLocker glock;
+
+void aa_fun_1() {
+ glock.globalLock();
+ glock.globalUnlock();
+}
+
+void aa_fun_bad_1() {
+ glock.globalUnlock(); // \
+ // expected-warning{{unlocking 'aa_mu' that was not locked}}
+}
+
+void aa_fun_bad_2() {
+ glock.globalLock();
+ glock.globalLock(); // \
+ // expected-warning{{locking 'aa_mu' that is already locked}}
+ glock.globalUnlock();
+}
+
+void aa_fun_bad_3() {
+ glock.globalLock(); // \
+ // expected-warning{{mutex 'aa_mu' is still locked at the end of function 'aa_fun_bad_3'}}
+}
+
+//--------------------------------------------------//
+// Regression tests for unusual method names
+//--------------------------------------------------//
+
+Mutex wmu;
+
+// Test diagnostics for other method names.
+class WeirdMethods {
+ WeirdMethods() {
+ wmu.Lock(); // \
+ // expected-warning {{mutex 'wmu' is still locked at the end of function 'WeirdMethods'}}
+ }
+ ~WeirdMethods() {
+ wmu.Lock(); // \
+ // expected-warning {{mutex 'wmu' is still locked at the end of function '~WeirdMethods'}}
+ }
+ void operator++() {
+ wmu.Lock(); // \
+ // expected-warning {{mutex 'wmu' is still locked at the end of function 'operator++'}}
+ }
+ operator int*() {
+ wmu.Lock(); // \
+ // expected-warning {{mutex 'wmu' is still locked at the end of function 'operator int *'}}
+ return 0;
+ }
+};
+
+//-----------------------------------------------//
+// Errors for guarded by or guarded var variables
+// ----------------------------------------------//
+
+int *pgb_gvar __attribute__((pt_guarded_var));
+int *pgb_var __attribute__((pt_guarded_by(sls_mu)));
+
+class PGBFoo {
+ public:
+ int x;
+ int *pgb_field __attribute__((guarded_by(sls_mu2)))
+ __attribute__((pt_guarded_by(sls_mu)));
+ void testFoo() {
+ pgb_field = &x; // \
+ // expected-warning {{writing variable 'pgb_field' requires locking 'sls_mu2' exclusively}}
+ *pgb_field = x; // expected-warning {{reading variable 'pgb_field' requires locking 'sls_mu2'}} \
+ // expected-warning {{writing the value pointed to by 'pgb_field' requires locking 'sls_mu' exclusively}}
+ x = *pgb_field; // expected-warning {{reading variable 'pgb_field' requires locking 'sls_mu2'}} \
+ // expected-warning {{reading the value pointed to by 'pgb_field' requires locking 'sls_mu'}}
+ (*pgb_field)++; // expected-warning {{reading variable 'pgb_field' requires locking 'sls_mu2'}} \
+ // expected-warning {{writing the value pointed to by 'pgb_field' requires locking 'sls_mu' exclusively}}
+ }
+};
+
+class GBFoo {
+ public:
+ int gb_field __attribute__((guarded_by(sls_mu)));
+
+ void testFoo() {
+ gb_field = 0; // \
+ // expected-warning {{writing variable 'gb_field' requires locking 'sls_mu' exclusively}}
+ }
+
+ void testNoAnal() __attribute__((no_thread_safety_analysis)) {
+ gb_field = 0;
+ }
+};
+
+GBFoo GlobalGBFoo __attribute__((guarded_by(sls_mu)));
+
+void gb_fun_0() {
+ sls_mu.Lock();
+ int x = *pgb_var;
+ sls_mu.Unlock();
+}
+
+void gb_fun_1() {
+ sls_mu.Lock();
+ *pgb_var = 2;
+ sls_mu.Unlock();
+}
+
+void gb_fun_2() {
+ int x;
+ pgb_var = &x;
+}
+
+void gb_fun_3() {
+ int *x = pgb_var;
+}
+
+void gb_bad_0() {
+ sls_guard_var = 1; // \
+ // expected-warning{{writing variable 'sls_guard_var' requires locking any mutex exclusively}}
+}
+
+void gb_bad_1() {
+ int x = sls_guard_var; // \
+ // expected-warning{{reading variable 'sls_guard_var' requires locking any mutex}}
+}
+
+void gb_bad_2() {
+ sls_guardby_var = 1; // \
+ // expected-warning {{writing variable 'sls_guardby_var' requires locking 'sls_mu' exclusively}}
+}
+
+void gb_bad_3() {
+ int x = sls_guardby_var; // \
+ // expected-warning {{reading variable 'sls_guardby_var' requires locking 'sls_mu'}}
+}
+
+void gb_bad_4() {
+ *pgb_gvar = 1; // \
+ // expected-warning {{writing the value pointed to by 'pgb_gvar' requires locking any mutex exclusively}}
+}
+
+void gb_bad_5() {
+ int x = *pgb_gvar; // \
+ // expected-warning {{reading the value pointed to by 'pgb_gvar' requires locking any mutex}}
+}
+
+void gb_bad_6() {
+ *pgb_var = 1; // \
+ // expected-warning {{writing the value pointed to by 'pgb_var' requires locking 'sls_mu' exclusively}}
+}
+
+void gb_bad_7() {
+ int x = *pgb_var; // \
+ // expected-warning {{reading the value pointed to by 'pgb_var' requires locking 'sls_mu'}}
+}
+
+void gb_bad_8() {
+ GBFoo G;
+ G.gb_field = 0; // \
+ // expected-warning {{writing variable 'gb_field' requires locking 'sls_mu'}}
+}
+
+void gb_bad_9() {
+ sls_guard_var++; // \
+ // expected-warning{{writing variable 'sls_guard_var' requires locking any mutex exclusively}}
+ sls_guard_var--; // \
+ // expected-warning{{writing variable 'sls_guard_var' requires locking any mutex exclusively}}
+ ++sls_guard_var; // \
+ // expected-warning{{writing variable 'sls_guard_var' requires locking any mutex exclusively}}
+ --sls_guard_var;// \
+ // expected-warning{{writing variable 'sls_guard_var' requires locking any mutex exclusively}}
+}
+
+//-----------------------------------------------//
+// Warnings on variables with late parsed attributes
+// ----------------------------------------------//
+
+class LateFoo {
+public:
+ int a __attribute__((guarded_by(mu)));
+ int b;
+
+ void foo() __attribute__((exclusive_locks_required(mu))) { }
+
+ void test() {
+ a = 0; // \
+ // expected-warning{{writing variable 'a' requires locking 'mu' exclusively}}
+ b = a; // \
+ // expected-warning {{reading variable 'a' requires locking 'mu'}}
+ c = 0; // \
+ // expected-warning {{writing variable 'c' requires locking 'mu' exclusively}}
+ }
+
+ int c __attribute__((guarded_by(mu)));
+
+ Mutex mu;
+};
+
+class LateBar {
+ public:
+ int a_ __attribute__((guarded_by(mu1_)));
+ int b_;
+ int *q __attribute__((pt_guarded_by(mu)));
+ Mutex mu1_;
+ Mutex mu;
+ LateFoo Foo;
+ LateFoo Foo2;
+ LateFoo *FooPointer;
+};
+
+LateBar b1, *b3;
+
+void late_0() {
+ LateFoo FooA;
+ LateFoo FooB;
+ FooA.mu.Lock();
+ FooA.a = 5;
+ FooA.mu.Unlock();
+}
+
+void late_1() {
+ LateBar BarA;
+ BarA.FooPointer->mu.Lock();
+ BarA.FooPointer->a = 2;
+ BarA.FooPointer->mu.Unlock();
+}
+
+void late_bad_0() {
+ LateFoo fooA;
+ LateFoo fooB;
+ fooA.mu.Lock();
+ fooB.a = 5; // \
+ // expected-warning{{writing variable 'a' requires locking 'mu' exclusively}}
+ fooA.mu.Unlock();
+}
+
+void late_bad_1() {
+ Mutex mu;
+ mu.Lock();
+ b1.mu1_.Lock();
+ int res = b1.a_ + b3->b_;
+ b3->b_ = *b1.q; // \
+ // expected-warning{{reading the value pointed to by 'q' requires locking 'mu'}}
+ b1.mu1_.Unlock();
+ b1.b_ = res;
+ mu.Unlock();
+}
+
+void late_bad_2() {
+ LateBar BarA;
+ BarA.FooPointer->mu.Lock();
+ BarA.Foo.a = 2; // \
+ // expected-warning{{writing variable 'a' requires locking 'mu' exclusively}}
+ BarA.FooPointer->mu.Unlock();
+}
+
+void late_bad_3() {
+ LateBar BarA;
+ BarA.Foo.mu.Lock();
+ BarA.FooPointer->a = 2; // \
+ // expected-warning{{writing variable 'a' requires locking 'mu' exclusively}}
+ BarA.Foo.mu.Unlock();
+}
+
+void late_bad_4() {
+ LateBar BarA;
+ BarA.Foo.mu.Lock();
+ BarA.Foo2.a = 2; // \
+ // expected-warning{{writing variable 'a' requires locking 'mu' exclusively}}
+ BarA.Foo.mu.Unlock();
+}
+
+//-----------------------------------------------//
+// Extra warnings for shared vs. exclusive locks
+// ----------------------------------------------//
+
+void shared_fun_0() {
+ sls_mu.Lock();
+ do {
+ sls_mu.Unlock();
+ sls_mu.Lock();
+ } while (getBool());
+ sls_mu.Unlock();
+}
+
+void shared_fun_1() {
+ sls_mu.ReaderLock(); // \
+ // expected-warning {{mutex 'sls_mu' is locked exclusively and shared in the same scope}}
+ do {
+ sls_mu.Unlock();
+ sls_mu.Lock(); // \
+ // expected-note {{the other lock of mutex 'sls_mu' is here}}
+ } while (getBool());
+ sls_mu.Unlock();
+}
+
+void shared_fun_3() {
+ if (getBool())
+ sls_mu.Lock();
+ else
+ sls_mu.Lock();
+ *pgb_var = 1;
+ sls_mu.Unlock();
+}
+
+void shared_fun_4() {
+ if (getBool())
+ sls_mu.ReaderLock();
+ else
+ sls_mu.ReaderLock();
+ int x = sls_guardby_var;
+ sls_mu.Unlock();
+}
+
+void shared_fun_8() {
+ if (getBool())
+ sls_mu.Lock(); // \
+ // expected-warning {{mutex 'sls_mu' is locked exclusively and shared in the same scope}}
+ else
+ sls_mu.ReaderLock(); // \
+ // expected-note {{the other lock of mutex 'sls_mu' is here}}
+ sls_mu.Unlock();
+}
+
+void shared_bad_0() {
+ sls_mu.Lock(); // \
+ // expected-warning {{mutex 'sls_mu' is locked exclusively and shared in the same scope}}
+ do {
+ sls_mu.Unlock();
+ sls_mu.ReaderLock(); // \
+ // expected-note {{the other lock of mutex 'sls_mu' is here}}
+ } while (getBool());
+ sls_mu.Unlock();
+}
+
+void shared_bad_1() {
+ if (getBool())
+ sls_mu.Lock(); // \
+ // expected-warning {{mutex 'sls_mu' is locked exclusively and shared in the same scope}}
+ else
+ sls_mu.ReaderLock(); // \
+ // expected-note {{the other lock of mutex 'sls_mu' is here}}
+ *pgb_var = 1;
+ sls_mu.Unlock();
+}
+
+void shared_bad_2() {
+ if (getBool())
+ sls_mu.ReaderLock(); // \
+ // expected-warning {{mutex 'sls_mu' is locked exclusively and shared in the same scope}}
+ else
+ sls_mu.Lock(); // \
+ // expected-note {{the other lock of mutex 'sls_mu' is here}}
+ *pgb_var = 1;
+ sls_mu.Unlock();
+}
+
+// FIXME: Add support for functions (not only methods)
+class LRBar {
+ public:
+ void aa_elr_fun() __attribute__((exclusive_locks_required(aa_mu)));
+ void aa_elr_fun_s() __attribute__((shared_locks_required(aa_mu)));
+ void le_fun() __attribute__((locks_excluded(sls_mu)));
+};
+
+class LRFoo {
+ public:
+ void test() __attribute__((exclusive_locks_required(sls_mu)));
+ void testShared() __attribute__((shared_locks_required(sls_mu2)));
+};
+
+void elr_fun() __attribute__((exclusive_locks_required(sls_mu)));
+void elr_fun() {}
+
+LRFoo MyLRFoo;
+LRBar Bar;
+
+void es_fun_0() {
+ aa_mu.Lock();
+ Bar.aa_elr_fun();
+ aa_mu.Unlock();
+}
+
+void es_fun_1() {
+ aa_mu.Lock();
+ Bar.aa_elr_fun_s();
+ aa_mu.Unlock();
+}
+
+void es_fun_2() {
+ aa_mu.ReaderLock();
+ Bar.aa_elr_fun_s();
+ aa_mu.Unlock();
+}
+
+void es_fun_3() {
+ sls_mu.Lock();
+ MyLRFoo.test();
+ sls_mu.Unlock();
+}
+
+void es_fun_4() {
+ sls_mu2.Lock();
+ MyLRFoo.testShared();
+ sls_mu2.Unlock();
+}
+
+void es_fun_5() {
+ sls_mu2.ReaderLock();
+ MyLRFoo.testShared();
+ sls_mu2.Unlock();
+}
+
+void es_fun_6() {
+ Bar.le_fun();
+}
+
+void es_fun_7() {
+ sls_mu.Lock();
+ elr_fun();
+ sls_mu.Unlock();
+}
+
+void es_fun_8() __attribute__((no_thread_safety_analysis));
+
+void es_fun_8() {
+ Bar.aa_elr_fun_s();
+}
+
+void es_fun_9() __attribute__((shared_locks_required(aa_mu)));
+void es_fun_9() {
+ Bar.aa_elr_fun_s();
+}
+
+void es_fun_10() __attribute__((exclusive_locks_required(aa_mu)));
+void es_fun_10() {
+ Bar.aa_elr_fun_s();
+}
+
+void es_bad_0() {
+ Bar.aa_elr_fun(); // \
+ // expected-warning {{calling function 'aa_elr_fun' requires exclusive lock on 'aa_mu'}}
+}
+
+void es_bad_1() {
+ aa_mu.ReaderLock();
+ Bar.aa_elr_fun(); // \
+ // expected-warning {{calling function 'aa_elr_fun' requires exclusive lock on 'aa_mu'}}
+ aa_mu.Unlock();
+}
+
+void es_bad_2() {
+ Bar.aa_elr_fun_s(); // \
+ // expected-warning {{calling function 'aa_elr_fun_s' requires shared lock on 'aa_mu'}}
+}
+
+void es_bad_3() {
+ MyLRFoo.test(); // \
+ // expected-warning {{calling function 'test' requires exclusive lock on 'sls_mu'}}
+}
+
+void es_bad_4() {
+ MyLRFoo.testShared(); // \
+ // expected-warning {{calling function 'testShared' requires shared lock on 'sls_mu2'}}
+}
+
+void es_bad_5() {
+ sls_mu.ReaderLock();
+ MyLRFoo.test(); // \
+ // expected-warning {{calling function 'test' requires exclusive lock on 'sls_mu'}}
+ sls_mu.Unlock();
+}
+
+void es_bad_6() {
+ sls_mu.Lock();
+ Bar.le_fun(); // \
+ // expected-warning {{cannot call function 'le_fun' while mutex 'sls_mu' is locked}}
+ sls_mu.Unlock();
+}
+
+void es_bad_7() {
+ sls_mu.ReaderLock();
+ Bar.le_fun(); // \
+ // expected-warning {{cannot call function 'le_fun' while mutex 'sls_mu' is locked}}
+ sls_mu.Unlock();
+}
+
+//-----------------------------------------------//
+// Unparseable lock expressions
+// ----------------------------------------------//
+
+Mutex UPmu;
+// FIXME: add support for lock expressions involving arrays.
+Mutex mua[5];
+
+int x __attribute__((guarded_by(UPmu = sls_mu))); // \
+ // expected-warning{{cannot resolve lock expression to a specific lockable object}}
+int y __attribute__((guarded_by(mua[0]))); // \
+ // expected-warning{{cannot resolve lock expression to a specific lockable object}}
+
+
+void testUnparse() {
+ // no errors, since the lock expressions are not resolved
+ x = 5;
+ y = 5;
+}
+
+void testUnparse2() {
+ mua[0].Lock(); // \
+ // expected-warning{{cannot resolve lock expression to a specific lockable object}}
+ (&(mua[0]) + 4)->Lock(); // \
+ // expected-warning{{cannot resolve lock expression to a specific lockable object}}
+}
+
+
+//----------------------------------------------------------------------------//
+// The following test cases are ported from the gcc thread safety implementation
+// They are each wrapped inside a namespace with the test number of the gcc test
+//
+// FIXME: add all the gcc tests, once this analysis passes them.
+//----------------------------------------------------------------------------//
+
+//-----------------------------------------//
+// Good testcases (no errors)
+//-----------------------------------------//
+
+namespace thread_annot_lock_20 {
+class Bar {
+ public:
+ static int func1() EXCLUSIVE_LOCKS_REQUIRED(mu1_);
+ static int b_ GUARDED_BY(mu1_);
+ static Mutex mu1_;
+ static int a_ GUARDED_BY(mu1_);
+};
+
+Bar b1;
+
+int Bar::func1()
+{
+ int res = 5;
+
+ if (a_ == 4)
+ res = b_;
+ return res;
+}
+} // end namespace thread_annot_lock_20
+
+namespace thread_annot_lock_22 {
+// Test various usage of GUARDED_BY and PT_GUARDED_BY annotations, especially
+// uses in class definitions.
+Mutex mu;
+
+class Bar {
+ public:
+ int a_ GUARDED_BY(mu1_);
+ int b_;
+ int *q PT_GUARDED_BY(mu);
+ Mutex mu1_ ACQUIRED_AFTER(mu);
+};
+
+Bar b1, *b3;
+int *p GUARDED_BY(mu) PT_GUARDED_BY(mu);
+int res GUARDED_BY(mu) = 5;
+
+int func(int i)
+{
+ int x;
+ mu.Lock();
+ b1.mu1_.Lock();
+ res = b1.a_ + b3->b_;
+ *p = i;
+ b1.a_ = res + b3->b_;
+ b3->b_ = *b1.q;
+ b1.mu1_.Unlock();
+ b1.b_ = res;
+ x = res;
+ mu.Unlock();
+ return x;
+}
+} // end namespace thread_annot_lock_22
+
+namespace thread_annot_lock_27_modified {
+// test lock annotations applied to function definitions
+// Modified: applied annotations only to function declarations
+Mutex mu1;
+Mutex mu2 ACQUIRED_AFTER(mu1);
+
+class Foo {
+ public:
+ int method1(int i) SHARED_LOCKS_REQUIRED(mu2) EXCLUSIVE_LOCKS_REQUIRED(mu1);
+};
+
+int Foo::method1(int i) {
+ return i;
+}
+
+
+int foo(int i) EXCLUSIVE_LOCKS_REQUIRED(mu2) SHARED_LOCKS_REQUIRED(mu1);
+int foo(int i) {
+ return i;
+}
+
+static int bar(int i) EXCLUSIVE_LOCKS_REQUIRED(mu1);
+static int bar(int i) {
+ return i;
+}
+
+void main() {
+ Foo a;
+
+ mu1.Lock();
+ mu2.Lock();
+ a.method1(1);
+ foo(2);
+ mu2.Unlock();
+ bar(3);
+ mu1.Unlock();
+}
+} // end namespace thread_annot_lock_27_modified
+
+
+namespace thread_annot_lock_38 {
+// Test the case where a template member function is annotated with lock
+// attributes in a non-template class.
+class Foo {
+ public:
+ void func1(int y) LOCKS_EXCLUDED(mu_);
+ template <typename T> void func2(T x) LOCKS_EXCLUDED(mu_);
+ private:
+ Mutex mu_;
+};
+
+Foo *foo;
+
+void main()
+{
+ foo->func1(5);
+ foo->func2(5);
+}
+} // end namespace thread_annot_lock_38
+
+namespace thread_annot_lock_43 {
+// Tests lock canonicalization
+class Foo {
+ public:
+ Mutex *mu_;
+};
+
+class FooBar {
+ public:
+ Foo *foo_;
+ int GetA() EXCLUSIVE_LOCKS_REQUIRED(foo_->mu_) { return a_; }
+ int a_ GUARDED_BY(foo_->mu_);
+};
+
+FooBar *fb;
+
+void main()
+{
+ int x;
+ fb->foo_->mu_->Lock();
+ x = fb->GetA();
+ fb->foo_->mu_->Unlock();
+}
+} // end namespace thread_annot_lock_43
+
+namespace thread_annot_lock_49 {
+// Test the support for use of lock expression in the annotations
+class Foo {
+ public:
+ Mutex foo_mu_;
+};
+
+class Bar {
+ private:
+ Foo *foo;
+ Mutex bar_mu_ ACQUIRED_AFTER(foo->foo_mu_);
+
+ public:
+ void Test1() {
+ foo->foo_mu_.Lock();
+ bar_mu_.Lock();
+ bar_mu_.Unlock();
+ foo->foo_mu_.Unlock();
+ }
+};
+
+void main() {
+ Bar bar;
+ bar.Test1();
+}
+} // end namespace thread_annot_lock_49
+
+namespace thread_annot_lock_61_modified {
+ // Modified to fix the compiler errors
+ // Test the fix for a bug introduced by the support of pass-by-reference
+ // paramters.
+ struct Foo { Foo &operator<< (bool) {return *this;} };
+ Foo &getFoo();
+ struct Bar { Foo &func () {return getFoo();} };
+ struct Bas { void operator& (Foo &) {} };
+ void mumble()
+ {
+ Bas() & Bar().func() << "" << "";
+ Bas() & Bar().func() << "";
+ }
+} // end namespace thread_annot_lock_61_modified
+
+
+namespace thread_annot_lock_65 {
+// Test the fix for a bug in the support of allowing reader locks for
+// non-const, non-modifying overload functions. (We didn't handle the builtin
+// properly.)
+enum MyFlags {
+ Zero,
+ One,
+ Two,
+ Three,
+ Four,
+ Five,
+ Six,
+ Seven,
+ Eight,
+ Nine
+};
+
+inline MyFlags
+operator|(MyFlags a, MyFlags b)
+{
+ return MyFlags(static_cast<int>(a) | static_cast<int>(b));
+}
+
+inline MyFlags&
+operator|=(MyFlags& a, MyFlags b)
+{
+ return a = a | b;
+}
+} // end namespace thread_annot_lock_65
+
+namespace thread_annot_lock_66_modified {
+// Modified: Moved annotation to function defn
+// Test annotations on out-of-line definitions of member functions where the
+// annotations refer to locks that are also data members in the class.
+Mutex mu;
+
+class Foo {
+ public:
+ int method1(int i) SHARED_LOCKS_REQUIRED(mu1, mu, mu2);
+ int data GUARDED_BY(mu1);
+ Mutex *mu1;
+ Mutex *mu2;
+};
+
+int Foo::method1(int i)
+{
+ return data + i;
+}
+
+void main()
+{
+ Foo a;
+
+ a.mu2->Lock();
+ a.mu1->Lock();
+ mu.Lock();
+ a.method1(1);
+ mu.Unlock();
+ a.mu1->Unlock();
+ a.mu2->Unlock();
+}
+} // end namespace thread_annot_lock_66_modified
+
+namespace thread_annot_lock_68_modified {
+// Test a fix to a bug in the delayed name binding with nested template
+// instantiation. We use a stack to make sure a name is not resolved to an
+// inner context.
+template <typename T>
+class Bar {
+ Mutex mu_;
+};
+
+template <typename T>
+class Foo {
+ public:
+ void func(T x) {
+ mu_.Lock();
+ count_ = x;
+ mu_.Unlock();
+ }
+
+ private:
+ T count_ GUARDED_BY(mu_);
+ Bar<T> bar_;
+ Mutex mu_;
+};
+
+void main()
+{
+ Foo<int> *foo;
+ foo->func(5);
+}
+} // end namespace thread_annot_lock_68_modified
+
+namespace thread_annot_lock_30_modified {
+// Test delay parsing of lock attribute arguments with nested classes.
+// Modified: trylocks replaced with exclusive_lock_fun
+int a = 0;
+
+class Bar {
+ struct Foo;
+
+ public:
+ void MyLock() EXCLUSIVE_LOCK_FUNCTION(mu);
+
+ int func() {
+ MyLock();
+// if (foo == 0) {
+// return 0;
+// }
+ a = 5;
+ mu.Unlock();
+ return 1;
+ }
+
+ class FooBar {
+ int x;
+ int y;
+ };
+
+ private:
+ Mutex mu;
+};
+
+Bar *bar;
+
+void main()
+{
+ bar->func();
+}
+} // end namespace thread_annot_lock_30_modified
+
+namespace thread_annot_lock_47 {
+// Test the support for annotations on virtual functions.
+// This is a good test case. (i.e. There should be no warning emitted by the
+// compiler.)
+class Base {
+ public:
+ virtual void func1() EXCLUSIVE_LOCKS_REQUIRED(mu_);
+ virtual void func2() LOCKS_EXCLUDED(mu_);
+ Mutex mu_;
+};
+
+class Child : public Base {
+ public:
+ virtual void func1() EXCLUSIVE_LOCKS_REQUIRED(mu_);
+ virtual void func2() LOCKS_EXCLUDED(mu_);
+};
+
+void main() {
+ Child *c;
+ Base *b = c;
+
+ b->mu_.Lock();
+ b->func1();
+ b->mu_.Unlock();
+ b->func2();
+
+ c->mu_.Lock();
+ c->func1();
+ c->mu_.Unlock();
+ c->func2();
+}
+} // end namespace thread_annot_lock_47
+
+//-----------------------------------------//
+// Tests which produce errors
+//-----------------------------------------//
+
+namespace thread_annot_lock_13 {
+Mutex mu1;
+Mutex mu2;
+
+int g GUARDED_BY(mu1);
+int w GUARDED_BY(mu2);
+
+class Foo {
+ public:
+ void bar() LOCKS_EXCLUDED(mu_, mu1);
+ int foo() SHARED_LOCKS_REQUIRED(mu_) EXCLUSIVE_LOCKS_REQUIRED(mu2);
+
+ private:
+ int a_ GUARDED_BY(mu_);
+ public:
+ Mutex mu_ ACQUIRED_AFTER(mu1);
+};
+
+int Foo::foo()
+{
+ int res;
+ w = 5.2;
+ res = a_ + 5;
+ return res;
+}
+
+void Foo::bar()
+{
+ int x;
+ mu_.Lock();
+ x = foo(); // expected-warning {{calling function 'foo' requires exclusive lock on 'mu2'}}
+ a_ = x + 1;
+ mu_.Unlock();
+ if (x > 5) {
+ mu1.Lock();
+ g = 2.3;
+ mu1.Unlock();
+ }
+}
+
+void main()
+{
+ Foo f1, *f2;
+ f1.mu_.Lock();
+ f1.bar(); // expected-warning {{cannot call function 'bar' while mutex 'mu_' is locked}}
+ mu2.Lock();
+ f1.foo();
+ mu2.Unlock();
+ f1.mu_.Unlock();
+ f2->mu_.Lock();
+ f2->bar(); // expected-warning {{cannot call function 'bar' while mutex 'mu_' is locked}}
+ f2->mu_.Unlock();
+ mu2.Lock();
+ w = 2.5;
+ mu2.Unlock();
+}
+} // end namespace thread_annot_lock_13
+
+namespace thread_annot_lock_18_modified {
+// Modified: Trylocks removed
+// Test the ability to distnguish between the same lock field of
+// different objects of a class.
+ class Bar {
+ public:
+ bool MyLock() EXCLUSIVE_LOCK_FUNCTION(mu1_);
+ void MyUnlock() UNLOCK_FUNCTION(mu1_);
+ int a_ GUARDED_BY(mu1_);
+
+ private:
+ Mutex mu1_;
+};
+
+Bar *b1, *b2;
+
+void func()
+{
+ b1->MyLock();
+ b1->a_ = 5;
+ b2->a_ = 3; // expected-warning {{writing variable 'a_' requires locking 'mu1_' exclusively}}
+ b2->MyLock();
+ b2->MyUnlock();
+ b1->MyUnlock();
+}
+} // end namespace thread_annot_lock_18_modified
+
+namespace thread_annot_lock_21 {
+// Test various usage of GUARDED_BY and PT_GUARDED_BY annotations, especially
+// uses in class definitions.
+Mutex mu;
+
+class Bar {
+ public:
+ int a_ GUARDED_BY(mu1_);
+ int b_;
+ int *q PT_GUARDED_BY(mu);
+ Mutex mu1_ ACQUIRED_AFTER(mu);
+};
+
+Bar b1, *b3;
+int *p GUARDED_BY(mu) PT_GUARDED_BY(mu);
+
+int res GUARDED_BY(mu) = 5;
+
+int func(int i)
+{
+ int x;
+ b3->mu1_.Lock();
+ res = b1.a_ + b3->b_; // expected-warning {{reading variable 'a_' requires locking 'mu1_'}} \
+ // expected-warning {{writing variable 'res' requires locking 'mu' exclusively}}
+ *p = i; // expected-warning {{reading variable 'p' requires locking 'mu'}} \
+ // expected-warning {{writing the value pointed to by 'p' requires locking 'mu' exclusively}}
+ b1.a_ = res + b3->b_; // expected-warning {{reading variable 'res' requires locking 'mu'}} \
+ // expected-warning {{writing variable 'a_' requires locking 'mu1_' exclusively}}
+ b3->b_ = *b1.q; // expected-warning {{reading the value pointed to by 'q' requires locking 'mu'}}
+ b3->mu1_.Unlock();
+ b1.b_ = res; // expected-warning {{reading variable 'res' requires locking 'mu'}}
+ x = res; // expected-warning {{reading variable 'res' requires locking 'mu'}}
+ return x;
+}
+} // end namespace thread_annot_lock_21
+
+namespace thread_annot_lock_35_modified {
+// Test the analyzer's ability to distinguish the lock field of different
+// objects.
+class Foo {
+ private:
+ Mutex lock_;
+ int a_ GUARDED_BY(lock_);
+
+ public:
+ void Func(Foo* child) LOCKS_EXCLUDED(lock_) {
+ Foo *new_foo = new Foo;
+
+ lock_.Lock();
+
+ child->Func(new_foo); // There shouldn't be any warning here as the
+ // acquired lock is not in child.
+ child->bar(7); // expected-warning {{calling function 'bar' requires exclusive lock on 'lock_'}}
+ child->a_ = 5; // expected-warning {{writing variable 'a_' requires locking 'lock_' exclusively}}
+ lock_.Unlock();
+ }
+
+ void bar(int y) EXCLUSIVE_LOCKS_REQUIRED(lock_) {
+ a_ = y;
+ }
+};
+
+Foo *x;
+
+void main() {
+ Foo *child = new Foo;
+ x->Func(child);
+}
+} // end namespace thread_annot_lock_35_modified
+
+namespace thread_annot_lock_36_modified {
+// Modified to move the annotations to function defns.
+// Test the analyzer's ability to distinguish the lock field of different
+// objects
+class Foo {
+ private:
+ Mutex lock_;
+ int a_ GUARDED_BY(lock_);
+
+ public:
+ void Func(Foo* child) LOCKS_EXCLUDED(lock_);
+ void bar(int y) EXCLUSIVE_LOCKS_REQUIRED(lock_);
+};
+
+void Foo::Func(Foo* child) {
+ Foo *new_foo = new Foo;
+
+ lock_.Lock();
+
+ child->lock_.Lock();
+ child->Func(new_foo); // expected-warning {{cannot call function 'Func' while mutex 'lock_' is locked}}
+ child->bar(7);
+ child->a_ = 5;
+ child->lock_.Unlock();
+
+ lock_.Unlock();
+}
+
+void Foo::bar(int y) {
+ a_ = y;
+}
+
+
+Foo *x;
+
+void main() {
+ Foo *child = new Foo;
+ x->Func(child);
+}
+} // end namespace thread_annot_lock_36_modified
+
+
+namespace thread_annot_lock_42 {
+// Test support of multiple lock attributes of the same kind on a decl.
+class Foo {
+ private:
+ Mutex mu1, mu2, mu3;
+ int x GUARDED_BY(mu1) GUARDED_BY(mu2);
+ int y GUARDED_BY(mu2);
+
+ void f2() LOCKS_EXCLUDED(mu1) LOCKS_EXCLUDED(mu2) LOCKS_EXCLUDED(mu3) {
+ mu2.Lock();
+ y = 2;
+ mu2.Unlock();
+ }
+
+ public:
+ void f1() EXCLUSIVE_LOCKS_REQUIRED(mu2) EXCLUSIVE_LOCKS_REQUIRED(mu1) {
+ x = 5;
+ f2(); // expected-warning {{cannot call function 'f2' while mutex 'mu1' is locked}} \
+ // expected-warning {{cannot call function 'f2' while mutex 'mu2' is locked}}
+ }
+};
+
+Foo *foo;
+
+void func()
+{
+ foo->f1(); // expected-warning {{calling function 'f1' requires exclusive lock on 'mu2'}} \
+ // expected-warning {{calling function 'f1' requires exclusive lock on 'mu1'}}
+}
+} // end namespace thread_annot_lock_42
+
+namespace thread_annot_lock_46 {
+// Test the support for annotations on virtual functions.
+class Base {
+ public:
+ virtual void func1() EXCLUSIVE_LOCKS_REQUIRED(mu_);
+ virtual void func2() LOCKS_EXCLUDED(mu_);
+ Mutex mu_;
+};
+
+class Child : public Base {
+ public:
+ virtual void func1() EXCLUSIVE_LOCKS_REQUIRED(mu_);
+ virtual void func2() LOCKS_EXCLUDED(mu_);
+};
+
+void main() {
+ Child *c;
+ Base *b = c;
+
+ b->func1(); // expected-warning {{calling function 'func1' requires exclusive lock on 'mu_'}}
+ b->mu_.Lock();
+ b->func2(); // expected-warning {{cannot call function 'func2' while mutex 'mu_' is locked}}
+ b->mu_.Unlock();
+
+ c->func1(); // expected-warning {{calling function 'func1' requires exclusive lock on 'mu_'}}
+ c->mu_.Lock();
+ c->func2(); // expected-warning {{cannot call function 'func2' while mutex 'mu_' is locked}}
+ c->mu_.Unlock();
+}
+} // end namespace thread_annot_lock_46
+
+namespace thread_annot_lock_67_modified {
+// Modified: attributes on definitions moved to declarations
+// Test annotations on out-of-line definitions of member functions where the
+// annotations refer to locks that are also data members in the class.
+Mutex mu;
+Mutex mu3;
+
+class Foo {
+ public:
+ int method1(int i) SHARED_LOCKS_REQUIRED(mu1, mu, mu2, mu3);
+ int data GUARDED_BY(mu1);
+ Mutex *mu1;
+ Mutex *mu2;
+};
+
+int Foo::method1(int i) {
+ return data + i;
+}
+
+void main()
+{
+ Foo a;
+ a.method1(1); // expected-warning {{calling function 'method1' requires shared lock on 'mu1'}} \
+ // expected-warning {{calling function 'method1' requires shared lock on 'mu'}} \
+ // expected-warning {{calling function 'method1' requires shared lock on 'mu2'}} \
+ // expected-warning {{calling function 'method1' requires shared lock on 'mu3'}}
+}
+} // end namespace thread_annot_lock_67_modified
+
+
diff --git a/test/SemaCXX/warn-thread-safety-parsing.cpp b/test/SemaCXX/warn-thread-safety-parsing.cpp
new file mode 100644
index 000000000000..67882d08996e
--- /dev/null
+++ b/test/SemaCXX/warn-thread-safety-parsing.cpp
@@ -0,0 +1,1255 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety %s
+
+
+//-----------------------------------------//
+// Helper fields
+//-----------------------------------------//
+
+class __attribute__((lockable)) Mu {
+ public:
+ void Lock();
+};
+
+class UnlockableMu{
+};
+
+class MuWrapper {
+ public:
+ Mu mu;
+ Mu getMu() {
+ return mu;
+ }
+ Mu * getMuPointer() {
+ return &mu;
+ }
+};
+
+
+class MuDoubleWrapper {
+ public:
+ MuWrapper* muWrapper;
+ MuWrapper* getWrapper() {
+ return muWrapper;
+ }
+};
+
+Mu mu1;
+UnlockableMu umu;
+Mu mu2;
+MuWrapper muWrapper;
+MuDoubleWrapper muDoubleWrapper;
+Mu* muPointer;
+Mu ** muDoublePointer = & muPointer;
+Mu& muRef = mu1;
+
+//---------------------------------------//
+// Scoping tests
+//--------------------------------------//
+
+class Foo {
+ Mu foomu;
+ void needLock() __attribute__((exclusive_lock_function(foomu)));
+};
+
+class Foo2 {
+ void needLock() __attribute__((exclusive_lock_function(foomu)));
+ Mu foomu;
+};
+
+class Bar {
+ Mu barmu;
+ Mu barmu2 __attribute__((acquired_after(barmu)));
+};
+
+
+//-----------------------------------------//
+// No Thread Safety Analysis (noanal) //
+//-----------------------------------------//
+
+// FIXME: Right now we cannot parse attributes put on function definitions
+// We would like to patch this at some point.
+
+#if !__has_attribute(no_thread_safety_analysis)
+#error "Should support no_thread_safety_analysis attribute"
+#endif
+
+void noanal_fun() __attribute__((no_thread_safety_analysis));
+
+void noanal_fun_args() __attribute__((no_thread_safety_analysis(1))); // \
+ // expected-error {{attribute takes no arguments}}
+
+int noanal_testfn(int y) __attribute__((no_thread_safety_analysis));
+
+int noanal_testfn(int y) {
+ int x __attribute__((no_thread_safety_analysis)) = y; // \
+ // expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}}
+ return x;
+};
+
+int noanal_test_var __attribute__((no_thread_safety_analysis)); // \
+ // expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}}
+
+class NoanalFoo {
+ private:
+ int test_field __attribute__((no_thread_safety_analysis)); // \
+ // expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}}
+ void test_method() __attribute__((no_thread_safety_analysis));
+};
+
+class __attribute__((no_thread_safety_analysis)) NoanalTestClass { // \
+ // expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}}
+};
+
+void noanal_fun_params(int lvar __attribute__((no_thread_safety_analysis))); // \
+ // expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}}
+
+
+//-----------------------------------------//
+// Guarded Var Attribute (gv)
+//-----------------------------------------//
+
+#if !__has_attribute(guarded_var)
+#error "Should support guarded_var attribute"
+#endif
+
+int gv_var_noargs __attribute__((guarded_var));
+
+int gv_var_args __attribute__((guarded_var(1))); // \
+ // expected-error {{attribute takes no arguments}}
+
+class GVFoo {
+ private:
+ int gv_field_noargs __attribute__((guarded_var));
+ int gv_field_args __attribute__((guarded_var(1))); // \
+ // expected-error {{attribute takes no arguments}}
+};
+
+class __attribute__((guarded_var)) GV { // \
+ // expected-warning {{'guarded_var' attribute only applies to fields and global variables}}
+};
+
+void gv_function() __attribute__((guarded_var)); // \
+ // expected-warning {{'guarded_var' attribute only applies to fields and global variables}}
+
+void gv_function_params(int gv_lvar __attribute__((guarded_var))); // \
+ // expected-warning {{'guarded_var' attribute only applies to fields and global variables}}
+
+int gv_testfn(int y){
+ int x __attribute__((guarded_var)) = y; // \
+ // expected-warning {{'guarded_var' attribute only applies to fields and global variables}}
+ return x;
+}
+
+//-----------------------------------------//
+// Pt Guarded Var Attribute (pgv)
+//-----------------------------------------//
+
+//FIXME: add support for boost::scoped_ptr<int> fancyptr and references
+
+#if !__has_attribute(pt_guarded_var)
+#error "Should support pt_guarded_var attribute"
+#endif
+
+int *pgv_pt_var_noargs __attribute__((pt_guarded_var));
+
+int pgv_var_noargs __attribute__((pt_guarded_var)); // \
+ // expected-warning {{'pt_guarded_var' only applies to pointer types; type here is 'int'}}
+
+class PGVFoo {
+ private:
+ int *pt_field_noargs __attribute__((pt_guarded_var));
+ int field_noargs __attribute__((pt_guarded_var)); // \
+ // expected-warning {{'pt_guarded_var' only applies to pointer types; type here is 'int'}}
+ int *gv_field_args __attribute__((pt_guarded_var(1))); // \
+ // expected-error {{attribute takes no arguments}}
+};
+
+class __attribute__((pt_guarded_var)) PGV { // \
+ // expected-warning {{'pt_guarded_var' attribute only applies to fields and global variables}}
+};
+
+int *pgv_var_args __attribute__((pt_guarded_var(1))); // \
+ // expected-error {{attribute takes no arguments}}
+
+
+void pgv_function() __attribute__((pt_guarded_var)); // \
+ // expected-warning {{'pt_guarded_var' attribute only applies to fields and global variables}}
+
+void pgv_function_params(int *gv_lvar __attribute__((pt_guarded_var))); // \
+ // expected-warning {{'pt_guarded_var' attribute only applies to fields and global variables}}
+
+void pgv_testfn(int y){
+ int *x __attribute__((pt_guarded_var)) = new int(0); // \
+ // expected-warning {{'pt_guarded_var' attribute only applies to fields and global variables}}
+ delete x;
+}
+
+//-----------------------------------------//
+// Lockable Attribute (l)
+//-----------------------------------------//
+
+//FIXME: In future we may want to add support for structs, ObjC classes, etc.
+
+#if !__has_attribute(lockable)
+#error "Should support lockable attribute"
+#endif
+
+class __attribute__((lockable)) LTestClass {
+};
+
+class __attribute__((lockable (1))) LTestClass_args { // \
+ // expected-error {{attribute takes no arguments}}
+};
+
+void l_test_function() __attribute__((lockable)); // \
+ // expected-warning {{'lockable' attribute only applies to classes}}
+
+int l_testfn(int y) {
+ int x __attribute__((lockable)) = y; // \
+ // expected-warning {{'lockable' attribute only applies to classes}}
+ return x;
+}
+
+int l_test_var __attribute__((lockable)); // \
+ // expected-warning {{'lockable' attribute only applies to classes}}
+
+class LFoo {
+ private:
+ int test_field __attribute__((lockable)); // \
+ // expected-warning {{'lockable' attribute only applies to classes}}
+ void test_method() __attribute__((lockable)); // \
+ // expected-warning {{'lockable' attribute only applies to classes}}
+};
+
+
+void l_function_params(int lvar __attribute__((lockable))); // \
+ // expected-warning {{'lockable' attribute only applies to classes}}
+
+
+//-----------------------------------------//
+// Scoped Lockable Attribute (sl)
+//-----------------------------------------//
+
+#if !__has_attribute(scoped_lockable)
+#error "Should support scoped_lockable attribute"
+#endif
+
+class __attribute__((scoped_lockable)) SLTestClass {
+};
+
+class __attribute__((scoped_lockable (1))) SLTestClass_args { // \
+ // expected-error {{attribute takes no arguments}}
+};
+
+void sl_test_function() __attribute__((scoped_lockable)); // \
+ // expected-warning {{'scoped_lockable' attribute only applies to classes}}
+
+int sl_testfn(int y) {
+ int x __attribute__((scoped_lockable)) = y; // \
+ // expected-warning {{'scoped_lockable' attribute only applies to classes}}
+ return x;
+}
+
+int sl_test_var __attribute__((scoped_lockable)); // \
+ // expected-warning {{'scoped_lockable' attribute only applies to classes}}
+
+class SLFoo {
+ private:
+ int test_field __attribute__((scoped_lockable)); // \
+ // expected-warning {{'scoped_lockable' attribute only applies to classes}}
+ void test_method() __attribute__((scoped_lockable)); // \
+ // expected-warning {{'scoped_lockable' attribute only applies to classes}}
+};
+
+
+void sl_function_params(int lvar __attribute__((scoped_lockable))); // \
+ // expected-warning {{'scoped_lockable' attribute only applies to classes}}
+
+
+//-----------------------------------------//
+// Guarded By Attribute (gb)
+//-----------------------------------------//
+
+// FIXME: Eventually, would we like this attribute to take more than 1 arg?
+
+#if !__has_attribute(guarded_by)
+#error "Should support guarded_by attribute"
+#endif
+
+//1. Check applied to the right types & argument number
+
+int gb_var_arg __attribute__((guarded_by(mu1)));
+
+int gb_var_args __attribute__((guarded_by(mu1, mu2))); // \
+ // expected-error {{attribute takes one argument}}
+
+int gb_var_noargs __attribute__((guarded_by)); // \
+ // expected-error {{attribute takes one argument}}
+
+class GBFoo {
+ private:
+ int gb_field_noargs __attribute__((guarded_by)); // \
+ // expected-error {{attribute takes one argument}}
+ int gb_field_args __attribute__((guarded_by(mu1)));
+};
+
+class __attribute__((guarded_by(mu1))) GB { // \
+ // expected-warning {{'guarded_by' attribute only applies to fields and global variables}}
+};
+
+void gb_function() __attribute__((guarded_by(mu1))); // \
+ // expected-warning {{'guarded_by' attribute only applies to fields and global variables}}
+
+void gb_function_params(int gv_lvar __attribute__((guarded_by(mu1)))); // \
+ // expected-warning {{'guarded_by' attribute only applies to fields and global variables}}
+
+int gb_testfn(int y){
+ int x __attribute__((guarded_by(mu1))) = y; // \
+ // expected-warning {{'guarded_by' attribute only applies to fields and global variables}}
+ return x;
+}
+
+//2. Check argument parsing.
+
+// legal attribute arguments
+int gb_var_arg_1 __attribute__((guarded_by(muWrapper.mu)));
+int gb_var_arg_2 __attribute__((guarded_by(muDoubleWrapper.muWrapper->mu)));
+int gb_var_arg_3 __attribute__((guarded_by(muWrapper.getMu())));
+int gb_var_arg_4 __attribute__((guarded_by(*muWrapper.getMuPointer())));
+int gb_var_arg_5 __attribute__((guarded_by(&mu1)));
+int gb_var_arg_6 __attribute__((guarded_by(muRef)));
+int gb_var_arg_7 __attribute__((guarded_by(muDoubleWrapper.getWrapper()->getMu())));
+int gb_var_arg_8 __attribute__((guarded_by(muPointer)));
+
+
+// illegal attribute arguments
+int gb_var_arg_bad_1 __attribute__((guarded_by(1))); // \
+ // expected-error {{'guarded_by' attribute requires arguments that are class type or point to class type}}
+int gb_var_arg_bad_2 __attribute__((guarded_by("mu"))); // \
+ // expected-error {{'guarded_by' attribute requires arguments that are class type or point to class type}}
+int gb_var_arg_bad_3 __attribute__((guarded_by(muDoublePointer))); // \
+ // expected-error {{'guarded_by' attribute requires arguments that are class type or point to class type}}
+int gb_var_arg_bad_4 __attribute__((guarded_by(umu))); // \
+ // expected-error {{'guarded_by' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+//3.
+// Thread Safety analysis tests
+
+
+//-----------------------------------------//
+// Pt Guarded By Attribute (pgb)
+//-----------------------------------------//
+
+#if !__has_attribute(pt_guarded_by)
+#error "Should support pt_guarded_by attribute"
+#endif
+
+//1. Check applied to the right types & argument number
+
+int *pgb_var_noargs __attribute__((pt_guarded_by)); // \
+ // expected-error {{attribute takes one argument}}
+
+int *pgb_ptr_var_arg __attribute__((pt_guarded_by(mu1)));
+
+int *pgb_ptr_var_args __attribute__((guarded_by(mu1, mu2))); // \
+ // expected-error {{attribute takes one argument}}
+
+int pgb_var_args __attribute__((pt_guarded_by(mu1))); // \
+ // expected-warning {{'pt_guarded_by' only applies to pointer types; type here is 'int'}}
+
+class PGBFoo {
+ private:
+ int *pgb_field_noargs __attribute__((pt_guarded_by)); // \
+ // expected-error {{attribute takes one argument}}
+ int *pgb_field_args __attribute__((pt_guarded_by(mu1)));
+};
+
+class __attribute__((pt_guarded_by(mu1))) PGB { // \
+ // expected-warning {{'pt_guarded_by' attribute only applies to fields and global variables}}
+};
+
+void pgb_function() __attribute__((pt_guarded_by(mu1))); // \
+ // expected-warning {{'pt_guarded_by' attribute only applies to fields and global variables}}
+
+void pgb_function_params(int gv_lvar __attribute__((pt_guarded_by(mu1)))); // \
+ // expected-warning {{'pt_guarded_by' attribute only applies to fields and global variables}}
+
+void pgb_testfn(int y){
+ int *x __attribute__((pt_guarded_by(mu1))) = new int(0); // \
+ // expected-warning {{'pt_guarded_by' attribute only applies to fields and global variables}}
+ delete x;
+}
+
+//2. Check argument parsing.
+
+// legal attribute arguments
+int * pgb_var_arg_1 __attribute__((pt_guarded_by(muWrapper.mu)));
+int * pgb_var_arg_2 __attribute__((pt_guarded_by(muDoubleWrapper.muWrapper->mu)));
+int * pgb_var_arg_3 __attribute__((pt_guarded_by(muWrapper.getMu())));
+int * pgb_var_arg_4 __attribute__((pt_guarded_by(*muWrapper.getMuPointer())));
+int * pgb_var_arg_5 __attribute__((pt_guarded_by(&mu1)));
+int * pgb_var_arg_6 __attribute__((pt_guarded_by(muRef)));
+int * pgb_var_arg_7 __attribute__((pt_guarded_by(muDoubleWrapper.getWrapper()->getMu())));
+int * pgb_var_arg_8 __attribute__((pt_guarded_by(muPointer)));
+
+
+// illegal attribute arguments
+int * pgb_var_arg_bad_1 __attribute__((pt_guarded_by(1))); // \
+ // expected-error {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}}
+int * pgb_var_arg_bad_2 __attribute__((pt_guarded_by("mu"))); // \
+ // expected-error {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}}
+int * pgb_var_arg_bad_3 __attribute__((pt_guarded_by(muDoublePointer))); // \
+ // expected-error {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}}
+int * pgb_var_arg_bad_4 __attribute__((pt_guarded_by(umu))); // \
+ // expected-error {{'pt_guarded_by' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+
+//-----------------------------------------//
+// Acquired After (aa)
+//-----------------------------------------//
+
+// FIXME: Would we like this attribute to take more than 1 arg?
+
+#if !__has_attribute(acquired_after)
+#error "Should support acquired_after attribute"
+#endif
+
+Mu mu_aa __attribute__((acquired_after(mu1)));
+
+Mu aa_var_noargs __attribute__((acquired_after)); // \
+ // expected-error {{attribute takes at least 1 argument}}
+
+class AAFoo {
+ private:
+ Mu aa_field_noargs __attribute__((acquired_after)); // \
+ // expected-error {{attribute takes at least 1 argument}}
+ Mu aa_field_args __attribute__((acquired_after(mu1)));
+};
+
+class __attribute__((acquired_after(mu1))) AA { // \
+ // expected-warning {{'acquired_after' attribute only applies to fields and global variables}}
+};
+
+void aa_function() __attribute__((acquired_after(mu1))); // \
+ // expected-warning {{'acquired_after' attribute only applies to fields and global variables}}
+
+void aa_function_params(int gv_lvar __attribute__((acquired_after(mu1)))); // \
+ // expected-warning {{'acquired_after' attribute only applies to fields and global variables}}
+
+void aa_testfn(int y){
+ Mu x __attribute__((acquired_after(mu1))) = Mu(); // \
+ // expected-warning {{'acquired_after' attribute only applies to fields and global variables}}
+}
+
+//Check argument parsing.
+
+// legal attribute arguments
+Mu aa_var_arg_1 __attribute__((acquired_after(muWrapper.mu)));
+Mu aa_var_arg_2 __attribute__((acquired_after(muDoubleWrapper.muWrapper->mu)));
+Mu aa_var_arg_3 __attribute__((acquired_after(muWrapper.getMu())));
+Mu aa_var_arg_4 __attribute__((acquired_after(*muWrapper.getMuPointer())));
+Mu aa_var_arg_5 __attribute__((acquired_after(&mu1)));
+Mu aa_var_arg_6 __attribute__((acquired_after(muRef)));
+Mu aa_var_arg_7 __attribute__((acquired_after(muDoubleWrapper.getWrapper()->getMu())));
+Mu aa_var_arg_8 __attribute__((acquired_after(muPointer)));
+
+
+// illegal attribute arguments
+Mu aa_var_arg_bad_1 __attribute__((acquired_after(1))); // \
+ // expected-error {{'acquired_after' attribute requires arguments that are class type or point to class type}}
+Mu aa_var_arg_bad_2 __attribute__((acquired_after("mu"))); // \
+ // expected-error {{'acquired_after' attribute requires arguments that are class type or point to class type}}
+Mu aa_var_arg_bad_3 __attribute__((acquired_after(muDoublePointer))); // \
+ // expected-error {{'acquired_after' attribute requires arguments that are class type or point to class type}}
+Mu aa_var_arg_bad_4 __attribute__((acquired_after(umu))); // \
+ // expected-error {{'acquired_after' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+UnlockableMu aa_var_arg_bad_5 __attribute__((acquired_after(mu_aa))); // \
+ // expected-error {{'acquired_after' attribute can only be applied in a context annotated with 'lockable' attribute}}
+
+//-----------------------------------------//
+// Acquired Before (ab)
+//-----------------------------------------//
+
+#if !__has_attribute(acquired_before)
+#error "Should support acquired_before attribute"
+#endif
+
+Mu mu_ab __attribute__((acquired_before(mu1)));
+
+Mu ab_var_noargs __attribute__((acquired_before)); // \
+ // expected-error {{attribute takes at least 1 argument}}
+
+class ABFoo {
+ private:
+ Mu ab_field_noargs __attribute__((acquired_before)); // \
+ // expected-error {{attribute takes at least 1 argument}}
+ Mu ab_field_args __attribute__((acquired_before(mu1)));
+};
+
+class __attribute__((acquired_before(mu1))) AB { // \
+ // expected-warning {{'acquired_before' attribute only applies to fields and global variables}}
+};
+
+void ab_function() __attribute__((acquired_before(mu1))); // \
+ // expected-warning {{'acquired_before' attribute only applies to fields and global variables}}
+
+void ab_function_params(int gv_lvar __attribute__((acquired_before(mu1)))); // \
+ // expected-warning {{'acquired_before' attribute only applies to fields and global variables}}
+
+void ab_testfn(int y){
+ Mu x __attribute__((acquired_before(mu1))) = Mu(); // \
+ // expected-warning {{'acquired_before' attribute only applies to fields and global variables}}
+}
+
+// Note: illegal int ab_int __attribute__((acquired_before(mu1))) will
+// be taken care of by warnings that ab__int is not lockable.
+
+//Check argument parsing.
+
+// legal attribute arguments
+Mu ab_var_arg_1 __attribute__((acquired_before(muWrapper.mu)));
+Mu ab_var_arg_2 __attribute__((acquired_before(muDoubleWrapper.muWrapper->mu)));
+Mu ab_var_arg_3 __attribute__((acquired_before(muWrapper.getMu())));
+Mu ab_var_arg_4 __attribute__((acquired_before(*muWrapper.getMuPointer())));
+Mu ab_var_arg_5 __attribute__((acquired_before(&mu1)));
+Mu ab_var_arg_6 __attribute__((acquired_before(muRef)));
+Mu ab_var_arg_7 __attribute__((acquired_before(muDoubleWrapper.getWrapper()->getMu())));
+Mu ab_var_arg_8 __attribute__((acquired_before(muPointer)));
+
+
+// illegal attribute arguments
+Mu ab_var_arg_bad_1 __attribute__((acquired_before(1))); // \
+ // expected-error {{'acquired_before' attribute requires arguments that are class type or point to class type}}
+Mu ab_var_arg_bad_2 __attribute__((acquired_before("mu"))); // \
+ // expected-error {{'acquired_before' attribute requires arguments that are class type or point to class type}}
+Mu ab_var_arg_bad_3 __attribute__((acquired_before(muDoublePointer))); // \
+ // expected-error {{'acquired_before' attribute requires arguments that are class type or point to class type}}
+Mu ab_var_arg_bad_4 __attribute__((acquired_before(umu))); // \
+ // expected-error {{'acquired_before' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+UnlockableMu ab_var_arg_bad_5 __attribute__((acquired_before(mu_ab))); // \
+ // expected-error {{'acquired_before' attribute can only be applied in a context annotated with 'lockable' attribute}}
+
+
+//-----------------------------------------//
+// Exclusive Lock Function (elf)
+//-----------------------------------------//
+
+#if !__has_attribute(exclusive_lock_function)
+#error "Should support exclusive_lock_function attribute"
+#endif
+
+// takes zero or more arguments, all locks (vars/fields)
+
+void elf_function() __attribute__((exclusive_lock_function));
+
+void elf_function_args() __attribute__((exclusive_lock_function(mu1, mu2)));
+
+int elf_testfn(int y) __attribute__((exclusive_lock_function));
+
+int elf_testfn(int y) {
+ int x __attribute__((exclusive_lock_function)) = y; // \
+ // expected-warning {{'exclusive_lock_function' attribute only applies to functions and methods}}
+ return x;
+};
+
+int elf_test_var __attribute__((exclusive_lock_function)); // \
+ // expected-warning {{'exclusive_lock_function' attribute only applies to functions and methods}}
+
+class ElfFoo {
+ private:
+ int test_field __attribute__((exclusive_lock_function)); // \
+ // expected-warning {{'exclusive_lock_function' attribute only applies to functions and methods}}
+ void test_method() __attribute__((exclusive_lock_function));
+};
+
+class __attribute__((exclusive_lock_function)) ElfTestClass { // \
+ // expected-warning {{'exclusive_lock_function' attribute only applies to functions and methods}}
+};
+
+void elf_fun_params(int lvar __attribute__((exclusive_lock_function))); // \
+ // expected-warning {{'exclusive_lock_function' attribute only applies to functions and methods}}
+
+// Check argument parsing.
+
+// legal attribute arguments
+int elf_function_1() __attribute__((exclusive_lock_function(muWrapper.mu)));
+int elf_function_2() __attribute__((exclusive_lock_function(muDoubleWrapper.muWrapper->mu)));
+int elf_function_3() __attribute__((exclusive_lock_function(muWrapper.getMu())));
+int elf_function_4() __attribute__((exclusive_lock_function(*muWrapper.getMuPointer())));
+int elf_function_5() __attribute__((exclusive_lock_function(&mu1)));
+int elf_function_6() __attribute__((exclusive_lock_function(muRef)));
+int elf_function_7() __attribute__((exclusive_lock_function(muDoubleWrapper.getWrapper()->getMu())));
+int elf_function_8() __attribute__((exclusive_lock_function(muPointer)));
+int elf_function_9(Mu x) __attribute__((exclusive_lock_function(1)));
+int elf_function_9(Mu x, Mu y) __attribute__((exclusive_lock_function(1,2)));
+
+
+// illegal attribute arguments
+int elf_function_bad_2() __attribute__((exclusive_lock_function("mu"))); // \
+ // expected-error {{'exclusive_lock_function' attribute requires arguments that are class type or point to class type}}
+int elf_function_bad_3() __attribute__((exclusive_lock_function(muDoublePointer))); // \
+ // expected-error {{'exclusive_lock_function' attribute requires arguments that are class type or point to class type}}
+int elf_function_bad_4() __attribute__((exclusive_lock_function(umu))); // \
+ // expected-error {{'exclusive_lock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+int elf_function_bad_1() __attribute__((exclusive_lock_function(1))); // \
+ // expected-error {{'exclusive_lock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
+int elf_function_bad_5(Mu x) __attribute__((exclusive_lock_function(0))); // \
+ // expected-error {{'exclusive_lock_function' attribute parameter 1 is out of bounds: can only be 1, since there is one parameter}}
+int elf_function_bad_6(Mu x, Mu y) __attribute__((exclusive_lock_function(0))); // \
+ // expected-error {{'exclusive_lock_function' attribute parameter 1 is out of bounds: must be between 1 and 2}}
+int elf_function_bad_7() __attribute__((exclusive_lock_function(0))); // \
+ // expected-error {{'exclusive_lock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
+
+
+//-----------------------------------------//
+// Shared Lock Function (slf)
+//-----------------------------------------//
+
+#if !__has_attribute(shared_lock_function)
+#error "Should support shared_lock_function attribute"
+#endif
+
+// takes zero or more arguments, all locks (vars/fields)
+
+void slf_function() __attribute__((shared_lock_function));
+
+void slf_function_args() __attribute__((shared_lock_function(mu1, mu2)));
+
+int slf_testfn(int y) __attribute__((shared_lock_function));
+
+int slf_testfn(int y) {
+ int x __attribute__((shared_lock_function)) = y; // \
+ // expected-warning {{'shared_lock_function' attribute only applies to functions and methods}}
+ return x;
+};
+
+int slf_test_var __attribute__((shared_lock_function)); // \
+ // expected-warning {{'shared_lock_function' attribute only applies to functions and methods}}
+
+void slf_fun_params(int lvar __attribute__((shared_lock_function))); // \
+ // expected-warning {{'shared_lock_function' attribute only applies to functions and methods}}
+
+class SlfFoo {
+ private:
+ int test_field __attribute__((shared_lock_function)); // \
+ // expected-warning {{'shared_lock_function' attribute only applies to functions and methods}}
+ void test_method() __attribute__((shared_lock_function));
+};
+
+class __attribute__((shared_lock_function)) SlfTestClass { // \
+ // expected-warning {{'shared_lock_function' attribute only applies to functions and methods}}
+};
+
+// Check argument parsing.
+
+// legal attribute arguments
+int slf_function_1() __attribute__((shared_lock_function(muWrapper.mu)));
+int slf_function_2() __attribute__((shared_lock_function(muDoubleWrapper.muWrapper->mu)));
+int slf_function_3() __attribute__((shared_lock_function(muWrapper.getMu())));
+int slf_function_4() __attribute__((shared_lock_function(*muWrapper.getMuPointer())));
+int slf_function_5() __attribute__((shared_lock_function(&mu1)));
+int slf_function_6() __attribute__((shared_lock_function(muRef)));
+int slf_function_7() __attribute__((shared_lock_function(muDoubleWrapper.getWrapper()->getMu())));
+int slf_function_8() __attribute__((shared_lock_function(muPointer)));
+int slf_function_9(Mu x) __attribute__((shared_lock_function(1)));
+int slf_function_9(Mu x, Mu y) __attribute__((shared_lock_function(1,2)));
+
+
+// illegal attribute arguments
+int slf_function_bad_2() __attribute__((shared_lock_function("mu"))); // \
+ // expected-error {{'shared_lock_function' attribute requires arguments that are class type or point to class type}}
+int slf_function_bad_3() __attribute__((shared_lock_function(muDoublePointer))); // \
+ // expected-error {{'shared_lock_function' attribute requires arguments that are class type or point to class type}}
+int slf_function_bad_4() __attribute__((shared_lock_function(umu))); // \
+ // expected-error {{'shared_lock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+int slf_function_bad_1() __attribute__((shared_lock_function(1))); // \
+ // expected-error {{'shared_lock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
+int slf_function_bad_5(Mu x) __attribute__((shared_lock_function(0))); // \
+ // expected-error {{'shared_lock_function' attribute parameter 1 is out of bounds: can only be 1, since there is one parameter}}
+int slf_function_bad_6(Mu x, Mu y) __attribute__((shared_lock_function(0))); // \
+ // expected-error {{'shared_lock_function' attribute parameter 1 is out of bounds: must be between 1 and 2}}
+int slf_function_bad_7() __attribute__((shared_lock_function(0))); // \
+ // expected-error {{'shared_lock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
+
+
+//-----------------------------------------//
+// Exclusive TryLock Function (etf)
+//-----------------------------------------//
+
+#if !__has_attribute(exclusive_trylock_function)
+#error "Should support exclusive_trylock_function attribute"
+#endif
+
+// takes a mandatory boolean or integer argument specifying the retval
+// plus an optional list of locks (vars/fields)
+
+void etf_function() __attribute__((exclusive_trylock_function)); // \
+ // expected-error {{attribute takes attribute takes at least 1 argument arguments}}
+
+void etf_function_args() __attribute__((exclusive_trylock_function(1, mu2)));
+
+void etf_function_arg() __attribute__((exclusive_trylock_function(1)));
+
+int etf_testfn(int y) __attribute__((exclusive_trylock_function(1)));
+
+int etf_testfn(int y) {
+ int x __attribute__((exclusive_trylock_function(1))) = y; // \
+ // expected-warning {{'exclusive_trylock_function' attribute only applies to functions and methods}}
+ return x;
+};
+
+int etf_test_var __attribute__((exclusive_trylock_function(1))); // \
+ // expected-warning {{'exclusive_trylock_function' attribute only applies to functions and methods}}
+
+class EtfFoo {
+ private:
+ int test_field __attribute__((exclusive_trylock_function(1))); // \
+ // expected-warning {{'exclusive_trylock_function' attribute only applies to functions and methods}}
+ void test_method() __attribute__((exclusive_trylock_function(1)));
+};
+
+class __attribute__((exclusive_trylock_function(1))) EtfTestClass { // \
+ // expected-warning {{'exclusive_trylock_function' attribute only applies to functions and methods}}
+};
+
+void etf_fun_params(int lvar __attribute__((exclusive_trylock_function(1)))); // \
+ // expected-warning {{'exclusive_trylock_function' attribute only applies to functions and methods}}
+
+// Check argument parsing.
+
+// legal attribute arguments
+int etf_function_1() __attribute__((exclusive_trylock_function(1, muWrapper.mu)));
+int etf_function_2() __attribute__((exclusive_trylock_function(1, muDoubleWrapper.muWrapper->mu)));
+int etf_function_3() __attribute__((exclusive_trylock_function(1, muWrapper.getMu())));
+int etf_function_4() __attribute__((exclusive_trylock_function(1, *muWrapper.getMuPointer())));
+int etf_function_5() __attribute__((exclusive_trylock_function(1, &mu1)));
+int etf_function_6() __attribute__((exclusive_trylock_function(1, muRef)));
+int etf_function_7() __attribute__((exclusive_trylock_function(1, muDoubleWrapper.getWrapper()->getMu())));
+int etf_functetfn_8() __attribute__((exclusive_trylock_function(1, muPointer)));
+int etf_function_9() __attribute__((exclusive_trylock_function(true)));
+
+
+// illegal attribute arguments
+int etf_function_bad_1() __attribute__((exclusive_trylock_function(mu1))); // \
+ // expected-error {{'exclusive_trylock_function' attribute first argument must be of int or bool type}}
+int etf_function_bad_2() __attribute__((exclusive_trylock_function("mu"))); // \
+ // expected-error {{'exclusive_trylock_function' attribute first argument must be of int or bool type}}
+int etf_function_bad_3() __attribute__((exclusive_trylock_function(muDoublePointer))); // \
+ // expected-error {{'exclusive_trylock_function' attribute first argument must be of int or bool type}}
+
+int etf_function_bad_4() __attribute__((exclusive_trylock_function(1, "mu"))); // \
+ // expected-error {{'exclusive_trylock_function' attribute requires arguments that are class type or point to class type}}
+int etf_function_bad_5() __attribute__((exclusive_trylock_function(1, muDoublePointer))); // \
+ // expected-error {{'exclusive_trylock_function' attribute requires arguments that are class type or point to class type}}
+int etf_function_bad_6() __attribute__((exclusive_trylock_function(1, umu))); // \
+ // expected-error {{'exclusive_trylock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+
+//-----------------------------------------//
+// Shared TryLock Function (stf)
+//-----------------------------------------//
+
+#if !__has_attribute(shared_trylock_function)
+#error "Should support shared_trylock_function attribute"
+#endif
+
+// takes a mandatory boolean or integer argument specifying the retval
+// plus an optional list of locks (vars/fields)
+
+void stf_function() __attribute__((shared_trylock_function)); // \
+ // expected-error {{attribute takes at least 1 argument}}
+
+void stf_function_args() __attribute__((shared_trylock_function(1, mu2)));
+
+void stf_function_arg() __attribute__((shared_trylock_function(1)));
+
+int stf_testfn(int y) __attribute__((shared_trylock_function(1)));
+
+int stf_testfn(int y) {
+ int x __attribute__((shared_trylock_function(1))) = y; // \
+ // expected-warning {{'shared_trylock_function' attribute only applies to functions and methods}}
+ return x;
+};
+
+int stf_test_var __attribute__((shared_trylock_function(1))); // \
+ // expected-warning {{'shared_trylock_function' attribute only applies to functions and methods}}
+
+void stf_fun_params(int lvar __attribute__((shared_trylock_function(1)))); // \
+ // expected-warning {{'shared_trylock_function' attribute only applies to functions and methods}}
+
+
+class StfFoo {
+ private:
+ int test_field __attribute__((shared_trylock_function(1))); // \
+ // expected-warning {{'shared_trylock_function' attribute only applies to functions and methods}}
+ void test_method() __attribute__((shared_trylock_function(1)));
+};
+
+class __attribute__((shared_trylock_function(1))) StfTestClass { // \
+ // expected-warning {{'shared_trylock_function' attribute only applies to functions and methods}}
+};
+
+// Check argument parsing.
+
+// legal attribute arguments
+int stf_function_1() __attribute__((shared_trylock_function(1, muWrapper.mu)));
+int stf_function_2() __attribute__((shared_trylock_function(1, muDoubleWrapper.muWrapper->mu)));
+int stf_function_3() __attribute__((shared_trylock_function(1, muWrapper.getMu())));
+int stf_function_4() __attribute__((shared_trylock_function(1, *muWrapper.getMuPointer())));
+int stf_function_5() __attribute__((shared_trylock_function(1, &mu1)));
+int stf_function_6() __attribute__((shared_trylock_function(1, muRef)));
+int stf_function_7() __attribute__((shared_trylock_function(1, muDoubleWrapper.getWrapper()->getMu())));
+int stf_function_8() __attribute__((shared_trylock_function(1, muPointer)));
+int stf_function_9() __attribute__((shared_trylock_function(true)));
+
+
+// illegal attribute arguments
+int stf_function_bad_1() __attribute__((shared_trylock_function(mu1))); // \
+ // expected-error {{'shared_trylock_function' attribute first argument must be of int or bool type}}
+int stf_function_bad_2() __attribute__((shared_trylock_function("mu"))); // \
+ // expected-error {{'shared_trylock_function' attribute first argument must be of int or bool type}}
+int stf_function_bad_3() __attribute__((shared_trylock_function(muDoublePointer))); // \
+ // expected-error {{'shared_trylock_function' attribute first argument must be of int or bool type}}
+
+int stf_function_bad_4() __attribute__((shared_trylock_function(1, "mu"))); // \
+ // expected-error {{'shared_trylock_function' attribute requires arguments that are class type or point to class type}}
+int stf_function_bad_5() __attribute__((shared_trylock_function(1, muDoublePointer))); // \
+ // expected-error {{'shared_trylock_function' attribute requires arguments that are class type or point to class type}}
+int stf_function_bad_6() __attribute__((shared_trylock_function(1, umu))); // \
+ // expected-error {{'shared_trylock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+
+//-----------------------------------------//
+// Unlock Function (uf)
+//-----------------------------------------//
+
+#if !__has_attribute(unlock_function)
+#error "Should support unlock_function attribute"
+#endif
+
+// takes zero or more arguments, all locks (vars/fields)
+
+void uf_function() __attribute__((unlock_function));
+
+void uf_function_args() __attribute__((unlock_function(mu1, mu2)));
+
+int uf_testfn(int y) __attribute__((unlock_function));
+
+int uf_testfn(int y) {
+ int x __attribute__((unlock_function)) = y; // \
+ // expected-warning {{'unlock_function' attribute only applies to functions and methods}}
+ return x;
+};
+
+int uf_test_var __attribute__((unlock_function)); // \
+ // expected-warning {{'unlock_function' attribute only applies to functions and methods}}
+
+class UfFoo {
+ private:
+ int test_field __attribute__((unlock_function)); // \
+ // expected-warning {{'unlock_function' attribute only applies to functions and methods}}
+ void test_method() __attribute__((unlock_function));
+};
+
+class __attribute__((no_thread_safety_analysis)) UfTestClass { // \
+ // expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}}
+};
+
+void uf_fun_params(int lvar __attribute__((unlock_function))); // \
+ // expected-warning {{'unlock_function' attribute only applies to functions and methods}}
+
+// Check argument parsing.
+
+// legal attribute arguments
+int uf_function_1() __attribute__((unlock_function(muWrapper.mu)));
+int uf_function_2() __attribute__((unlock_function(muDoubleWrapper.muWrapper->mu)));
+int uf_function_3() __attribute__((unlock_function(muWrapper.getMu())));
+int uf_function_4() __attribute__((unlock_function(*muWrapper.getMuPointer())));
+int uf_function_5() __attribute__((unlock_function(&mu1)));
+int uf_function_6() __attribute__((unlock_function(muRef)));
+int uf_function_7() __attribute__((unlock_function(muDoubleWrapper.getWrapper()->getMu())));
+int uf_function_8() __attribute__((unlock_function(muPointer)));
+int uf_function_9(Mu x) __attribute__((unlock_function(1)));
+int uf_function_9(Mu x, Mu y) __attribute__((unlock_function(1,2)));
+
+
+// illegal attribute arguments
+int uf_function_bad_2() __attribute__((unlock_function("mu"))); // \
+ // expected-error {{'unlock_function' attribute requires arguments that are class type or point to class type}}
+int uf_function_bad_3() __attribute__((unlock_function(muDoublePointer))); // \
+ // expected-error {{'unlock_function' attribute requires arguments that are class type or point to class type}}
+int uf_function_bad_4() __attribute__((unlock_function(umu))); // \
+ // expected-error {{'unlock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+int uf_function_bad_1() __attribute__((unlock_function(1))); // \
+ // expected-error {{'unlock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
+int uf_function_bad_5(Mu x) __attribute__((unlock_function(0))); // \
+ // expected-error {{'unlock_function' attribute parameter 1 is out of bounds: can only be 1, since there is one parameter}}
+int uf_function_bad_6(Mu x, Mu y) __attribute__((unlock_function(0))); // \
+ // expected-error {{'unlock_function' attribute parameter 1 is out of bounds: must be between 1 and 2}}
+int uf_function_bad_7() __attribute__((unlock_function(0))); // \
+ // expected-error {{'unlock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
+
+
+//-----------------------------------------//
+// Lock Returned (lr)
+//-----------------------------------------//
+
+#if !__has_attribute(lock_returned)
+#error "Should support lock_returned attribute"
+#endif
+
+// Takes exactly one argument, a var/field
+
+void lr_function() __attribute__((lock_returned)); // \
+ // expected-error {{attribute takes one argument}}
+
+void lr_function_arg() __attribute__((lock_returned(mu1)));
+
+void lr_function_args() __attribute__((lock_returned(mu1, mu2))); // \
+ // expected-error {{attribute takes one argument}}
+
+int lr_testfn(int y) __attribute__((lock_returned(mu1)));
+
+int lr_testfn(int y) {
+ int x __attribute__((lock_returned(mu1))) = y; // \
+ // expected-warning {{'lock_returned' attribute only applies to functions and methods}}
+ return x;
+};
+
+int lr_test_var __attribute__((lock_returned(mu1))); // \
+ // expected-warning {{'lock_returned' attribute only applies to functions and methods}}
+
+void lr_fun_params(int lvar __attribute__((lock_returned(mu1)))); // \
+ // expected-warning {{'lock_returned' attribute only applies to functions and methods}}
+
+class LrFoo {
+ private:
+ int test_field __attribute__((lock_returned(mu1))); // \
+ // expected-warning {{'lock_returned' attribute only applies to functions and methods}}
+ void test_method() __attribute__((lock_returned(mu1)));
+};
+
+class __attribute__((lock_returned(mu1))) LrTestClass { // \
+ // expected-warning {{'lock_returned' attribute only applies to functions and methods}}
+};
+
+// Check argument parsing.
+
+// legal attribute arguments
+int lr_function_1() __attribute__((lock_returned(muWrapper.mu)));
+int lr_function_2() __attribute__((lock_returned(muDoubleWrapper.muWrapper->mu)));
+int lr_function_3() __attribute__((lock_returned(muWrapper.getMu())));
+int lr_function_4() __attribute__((lock_returned(*muWrapper.getMuPointer())));
+int lr_function_5() __attribute__((lock_returned(&mu1)));
+int lr_function_6() __attribute__((lock_returned(muRef)));
+int lr_function_7() __attribute__((lock_returned(muDoubleWrapper.getWrapper()->getMu())));
+int lr_function_8() __attribute__((lock_returned(muPointer)));
+
+
+// illegal attribute arguments
+int lr_function_bad_1() __attribute__((lock_returned(1))); // \
+ // expected-error {{'lock_returned' attribute requires arguments that are class type or point to class type}}
+int lr_function_bad_2() __attribute__((lock_returned("mu"))); // \
+ // expected-error {{'lock_returned' attribute requires arguments that are class type or point to class type}}
+int lr_function_bad_3() __attribute__((lock_returned(muDoublePointer))); // \
+ // expected-error {{'lock_returned' attribute requires arguments that are class type or point to class type}}
+int lr_function_bad_4() __attribute__((lock_returned(umu))); // \
+ // expected-error {{'lock_returned' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+
+
+//-----------------------------------------//
+// Locks Excluded (le)
+//-----------------------------------------//
+
+#if !__has_attribute(locks_excluded)
+#error "Should support locks_excluded attribute"
+#endif
+
+// takes one or more arguments, all locks (vars/fields)
+
+void le_function() __attribute__((locks_excluded)); // \
+ // expected-error {{attribute takes at least 1 argument}}
+
+void le_function_arg() __attribute__((locks_excluded(mu1)));
+
+void le_function_args() __attribute__((locks_excluded(mu1, mu2)));
+
+int le_testfn(int y) __attribute__((locks_excluded(mu1)));
+
+int le_testfn(int y) {
+ int x __attribute__((locks_excluded(mu1))) = y; // \
+ // expected-warning {{'locks_excluded' attribute only applies to functions and methods}}
+ return x;
+};
+
+int le_test_var __attribute__((locks_excluded(mu1))); // \
+ // expected-warning {{'locks_excluded' attribute only applies to functions and methods}}
+
+void le_fun_params(int lvar __attribute__((locks_excluded(mu1)))); // \
+ // expected-warning {{'locks_excluded' attribute only applies to functions and methods}}
+
+class LeFoo {
+ private:
+ int test_field __attribute__((locks_excluded(mu1))); // \
+ // expected-warning {{'locks_excluded' attribute only applies to functions and methods}}
+ void test_method() __attribute__((locks_excluded(mu1)));
+};
+
+class __attribute__((locks_excluded(mu1))) LeTestClass { // \
+ // expected-warning {{'locks_excluded' attribute only applies to functions and methods}}
+};
+
+// Check argument parsing.
+
+// legal attribute arguments
+int le_function_1() __attribute__((locks_excluded(muWrapper.mu)));
+int le_function_2() __attribute__((locks_excluded(muDoubleWrapper.muWrapper->mu)));
+int le_function_3() __attribute__((locks_excluded(muWrapper.getMu())));
+int le_function_4() __attribute__((locks_excluded(*muWrapper.getMuPointer())));
+int le_function_5() __attribute__((locks_excluded(&mu1)));
+int le_function_6() __attribute__((locks_excluded(muRef)));
+int le_function_7() __attribute__((locks_excluded(muDoubleWrapper.getWrapper()->getMu())));
+int le_function_8() __attribute__((locks_excluded(muPointer)));
+
+
+// illegal attribute arguments
+int le_function_bad_1() __attribute__((locks_excluded(1))); // \
+ // expected-error {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
+int le_function_bad_2() __attribute__((locks_excluded("mu"))); // \
+ // expected-error {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
+int le_function_bad_3() __attribute__((locks_excluded(muDoublePointer))); // \
+ // expected-error {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
+int le_function_bad_4() __attribute__((locks_excluded(umu))); // \
+ // expected-error {{'locks_excluded' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+
+
+//-----------------------------------------//
+// Exclusive Locks Required (elr)
+//-----------------------------------------//
+
+#if !__has_attribute(exclusive_locks_required)
+#error "Should support exclusive_locks_required attribute"
+#endif
+
+// takes one or more arguments, all locks (vars/fields)
+
+void elr_function() __attribute__((exclusive_locks_required)); // \
+ // expected-error {{attribute takes at least 1 argument}}
+
+void elr_function_arg() __attribute__((exclusive_locks_required(mu1)));
+
+void elr_function_args() __attribute__((exclusive_locks_required(mu1, mu2)));
+
+int elr_testfn(int y) __attribute__((exclusive_locks_required(mu1)));
+
+int elr_testfn(int y) {
+ int x __attribute__((exclusive_locks_required(mu1))) = y; // \
+ // expected-warning {{'exclusive_locks_required' attribute only applies to functions and methods}}
+ return x;
+};
+
+int elr_test_var __attribute__((exclusive_locks_required(mu1))); // \
+ // expected-warning {{'exclusive_locks_required' attribute only applies to functions and methods}}
+
+void elr_fun_params(int lvar __attribute__((exclusive_locks_required(mu1)))); // \
+ // expected-warning {{'exclusive_locks_required' attribute only applies to functions and methods}}
+
+class ElrFoo {
+ private:
+ int test_field __attribute__((exclusive_locks_required(mu1))); // \
+ // expected-warning {{'exclusive_locks_required' attribute only applies to functions and methods}}
+ void test_method() __attribute__((exclusive_locks_required(mu1)));
+};
+
+class __attribute__((exclusive_locks_required(mu1))) ElrTestClass { // \
+ // expected-warning {{'exclusive_locks_required' attribute only applies to functions and methods}}
+};
+
+// Check argument parsing.
+
+// legal attribute arguments
+int elr_function_1() __attribute__((exclusive_locks_required(muWrapper.mu)));
+int elr_function_2() __attribute__((exclusive_locks_required(muDoubleWrapper.muWrapper->mu)));
+int elr_function_3() __attribute__((exclusive_locks_required(muWrapper.getMu())));
+int elr_function_4() __attribute__((exclusive_locks_required(*muWrapper.getMuPointer())));
+int elr_function_5() __attribute__((exclusive_locks_required(&mu1)));
+int elr_function_6() __attribute__((exclusive_locks_required(muRef)));
+int elr_function_7() __attribute__((exclusive_locks_required(muDoubleWrapper.getWrapper()->getMu())));
+int elr_function_8() __attribute__((exclusive_locks_required(muPointer)));
+
+
+// illegal attribute arguments
+int elr_function_bad_1() __attribute__((exclusive_locks_required(1))); // \
+ // expected-error {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}}
+int elr_function_bad_2() __attribute__((exclusive_locks_required("mu"))); // \
+ // expected-error {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}}
+int elr_function_bad_3() __attribute__((exclusive_locks_required(muDoublePointer))); // \
+ // expected-error {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}}
+int elr_function_bad_4() __attribute__((exclusive_locks_required(umu))); // \
+ // expected-error {{'exclusive_locks_required' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+
+
+
+//-----------------------------------------//
+// Shared Locks Required (slr)
+//-----------------------------------------//
+
+#if !__has_attribute(shared_locks_required)
+#error "Should support shared_locks_required attribute"
+#endif
+
+// takes one or more arguments, all locks (vars/fields)
+
+void slr_function() __attribute__((shared_locks_required)); // \
+ // expected-error {{attribute takes at least 1 argument}}
+
+void slr_function_arg() __attribute__((shared_locks_required(mu1)));
+
+void slr_function_args() __attribute__((shared_locks_required(mu1, mu2)));
+
+int slr_testfn(int y) __attribute__((shared_locks_required(mu1)));
+
+int slr_testfn(int y) {
+ int x __attribute__((shared_locks_required(mu1))) = y; // \
+ // expected-warning {{'shared_locks_required' attribute only applies to functions and methods}}
+ return x;
+};
+
+int slr_test_var __attribute__((shared_locks_required(mu1))); // \
+ // expected-warning {{'shared_locks_required' attribute only applies to functions and methods}}
+
+void slr_fun_params(int lvar __attribute__((shared_locks_required(mu1)))); // \
+ // expected-warning {{'shared_locks_required' attribute only applies to functions and methods}}
+
+class SlrFoo {
+ private:
+ int test_field __attribute__((shared_locks_required(mu1))); // \
+ // expected-warning {{'shared_locks_required' attribute only applies to functions and methods}}
+ void test_method() __attribute__((shared_locks_required(mu1)));
+};
+
+class __attribute__((shared_locks_required(mu1))) SlrTestClass { // \
+ // expected-warning {{'shared_locks_required' attribute only applies to functions and methods}}
+};
+
+// Check argument parsing.
+
+// legal attribute arguments
+int slr_function_1() __attribute__((shared_locks_required(muWrapper.mu)));
+int slr_function_2() __attribute__((shared_locks_required(muDoubleWrapper.muWrapper->mu)));
+int slr_function_3() __attribute__((shared_locks_required(muWrapper.getMu())));
+int slr_function_4() __attribute__((shared_locks_required(*muWrapper.getMuPointer())));
+int slr_function_5() __attribute__((shared_locks_required(&mu1)));
+int slr_function_6() __attribute__((shared_locks_required(muRef)));
+int slr_function_7() __attribute__((shared_locks_required(muDoubleWrapper.getWrapper()->getMu())));
+int slr_function_8() __attribute__((shared_locks_required(muPointer)));
+
+
+// illegal attribute arguments
+int slr_function_bad_1() __attribute__((shared_locks_required(1))); // \
+ // expected-error {{'shared_locks_required' attribute requires arguments that are class type or point to class type}}
+int slr_function_bad_2() __attribute__((shared_locks_required("mu"))); // \
+ // expected-error {{'shared_locks_required' attribute requires arguments that are class type or point to class type}}
+int slr_function_bad_3() __attribute__((shared_locks_required(muDoublePointer))); // \
+ // expected-error {{'shared_locks_required' attribute requires arguments that are class type or point to class type}}
+int slr_function_bad_4() __attribute__((shared_locks_required(umu))); // \
+ // expected-error {{'shared_locks_required' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+
+//-----------------------------------------//
+// Regression tests for unusual cases.
+//-----------------------------------------//
+
+int trivially_false_edges(bool b) {
+ // Create NULL (never taken) edges in CFG
+ if (false) return 1;
+ else return 2;
+}
+
+// Possible Clang bug -- method pointer in template parameter
+class UnFoo {
+public:
+ void foo();
+};
+
+template<void (UnFoo::*methptr)()>
+class MCaller {
+public:
+ static void call_method_ptr(UnFoo *f) {
+ // FIXME: Possible Clang bug:
+ // getCalleeDecl() returns NULL in the following case:
+ (f->*methptr)();
+ }
+};
+
+void call_method_ptr_inst(UnFoo* f) {
+ MCaller<&UnFoo::foo>::call_method_ptr(f);
+}
+
+int temp;
+void empty_back_edge() {
+ // Create a back edge to a block with with no statements
+ for (;;) {
+ ++temp;
+ if (temp > 10) break;
+ }
+}
+
+struct Foomger {
+ void operator++();
+};
+
+struct Foomgoper {
+ Foomger f;
+
+ bool done();
+ void invalid_back_edge() {
+ do {
+ // FIXME: Possible Clang bug:
+ // The first statement in this basic block has no source location
+ ++f;
+ } while (!done());
+ }
+};
+
+
+//-----------------------------------------------------
+// Parsing of member variables and function parameters
+//------------------------------------------------------
+
+Mu gmu;
+
+class StaticMu {
+ static Mu statmu;
+};
+
+class FooLate {
+public:
+ void foo1() __attribute__((exclusive_locks_required(gmu))) { }
+ void foo2() __attribute__((exclusive_locks_required(mu))) { }
+ void foo3(Mu *m) __attribute__((exclusive_locks_required(m))) { }
+ void foo3(FooLate *f) __attribute__((exclusive_locks_required(f->mu))) { }
+ void foo4(FooLate *f) __attribute__((exclusive_locks_required(f->mu)));
+
+ static void foo5() __attribute__((exclusive_locks_required(mu))); // \
+ // expected-error {{invalid use of member 'mu' in static member function}}
+
+ template <class T>
+ void foo6() __attribute__((exclusive_locks_required(T::statmu))) { }
+
+ template <class T>
+ void foo7(T* f) __attribute__((exclusive_locks_required(f->mu))) { }
+
+ int a __attribute__((guarded_by(gmu)));
+ int b __attribute__((guarded_by(mu)));
+ int c __attribute__((guarded_by(this->mu)));
+
+ Mu mu;
+};
+
diff --git a/test/SemaCXX/warn-unreachable.cpp b/test/SemaCXX/warn-unreachable.cpp
index ea6755f2d6ce..604a3c0da381 100644
--- a/test/SemaCXX/warn-unreachable.cpp
+++ b/test/SemaCXX/warn-unreachable.cpp
@@ -45,8 +45,8 @@ void test3() {
?
dead() : dead();
live(),
- float // expected-warning {{will never be executed}}
- (halt());
+ float
+ (halt()); // expected-warning {{will never be executed}}
}
void test4() {
@@ -73,6 +73,6 @@ void test6() {
S(int i) { }
};
live(),
- S // expected-warning {{will never be executed}}
- (halt());
+ S
+ (halt()); // expected-warning {{will never be executed}}
}
diff --git a/test/SemaCXX/warn-unused-comparison.cpp b/test/SemaCXX/warn-unused-comparison.cpp
new file mode 100644
index 000000000000..0153f213ba1f
--- /dev/null
+++ b/test/SemaCXX/warn-unused-comparison.cpp
@@ -0,0 +1,94 @@
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -Wno-unused -Wunused-comparison %s
+
+struct A {
+ bool operator==(const A&);
+ bool operator!=(const A&);
+ A operator|=(const A&);
+ operator bool();
+};
+
+void test() {
+ int x, *p;
+ A a, b;
+
+ x == 7; // expected-warning {{equality comparison result unused}} \
+ // expected-note {{use '=' to turn this equality comparison into an assignment}}
+ x != 7; // expected-warning {{inequality comparison result unused}} \
+ // expected-note {{use '|=' to turn this inequality comparison into an or-assignment}}
+ 7 == x; // expected-warning {{equality comparison result unused}}
+ p == p; // expected-warning {{equality comparison result unused}} \
+ // expected-note {{use '=' to turn this equality comparison into an assignment}} \
+ // expected-warning {{self-comparison always evaluates to true}}
+ a == a; // expected-warning {{equality comparison result unused}} \
+ // expected-note {{use '=' to turn this equality comparison into an assignment}}
+ a == b; // expected-warning {{equality comparison result unused}} \
+ // expected-note {{use '=' to turn this equality comparison into an assignment}}
+ a != b; // expected-warning {{inequality comparison result unused}} \
+ // expected-note {{use '|=' to turn this inequality comparison into an or-assignment}}
+ A() == b; // expected-warning {{equality comparison result unused}}
+ if (42) x == 7; // expected-warning {{equality comparison result unused}} \
+ // expected-note {{use '=' to turn this equality comparison into an assignment}}
+ else if (42) x == 7; // expected-warning {{equality comparison result unused}} \
+ // expected-note {{use '=' to turn this equality comparison into an assignment}}
+ else x == 7; // expected-warning {{equality comparison result unused}} \
+ // expected-note {{use '=' to turn this equality comparison into an assignment}}
+ do x == 7; // expected-warning {{equality comparison result unused}} \
+ // expected-note {{use '=' to turn this equality comparison into an assignment}}
+ while (false);
+ while (false) x == 7; // expected-warning {{equality comparison result unused}} \
+ // expected-note {{use '=' to turn this equality comparison into an assignment}}
+ for (x == 7; // expected-warning {{equality comparison result unused}} \
+ // expected-note {{use '=' to turn this equality comparison into an assignment}}
+ x == 7; // No warning -- result is used
+ x == 7) // expected-warning {{equality comparison result unused}} \
+ // expected-note {{use '=' to turn this equality comparison into an assignment}}
+ x == 7; // expected-warning {{equality comparison result unused}} \
+ // expected-note {{use '=' to turn this equality comparison into an assignment}}
+ switch (42) default: x == 7; // expected-warning {{equality comparison result unused}} \
+ // expected-note {{use '=' to turn this equality comparison into an assignment}}
+ switch (42) case 42: x == 7; // expected-warning {{equality comparison result unused}} \
+ // expected-note {{use '=' to turn this equality comparison into an assignment}}
+ switch (42) {
+ case 1:
+ case 2:
+ default:
+ case 3:
+ case 4:
+ x == 7; // expected-warning {{equality comparison result unused}} \
+ // expected-note {{use '=' to turn this equality comparison into an assignment}}
+ }
+
+ (void)(x == 7);
+ (void)(p == p); // expected-warning {{self-comparison always evaluates to true}}
+ { bool b = x == 7; }
+
+ { bool b = ({ x == 7; // expected-warning {{equality comparison result unused}} \
+ // expected-note {{use '=' to turn this equality comparison into an assignment}}
+ x == 7; }); } // no warning on the second, its result is used!
+
+#define EQ(x,y) (x) == (y)
+ EQ(x, 5);
+#undef EQ
+}
+
+namespace PR10291 {
+ template<typename T>
+ class X
+ {
+ public:
+
+ X() : i(0) { }
+
+ void foo()
+ {
+ throw
+ i == 0u ?
+ 5 : 6;
+ }
+
+ private:
+ int i;
+ };
+
+ X<int> x;
+}
diff --git a/test/SemaCXX/warn-unused-value.cpp b/test/SemaCXX/warn-unused-value.cpp
index 775c3cf01f24..80298ec6664a 100644
--- a/test/SemaCXX/warn-unused-value.cpp
+++ b/test/SemaCXX/warn-unused-value.cpp
@@ -15,3 +15,18 @@ namespace test0 {
box->j;
}
}
+
+namespace test1 {
+struct Foo {
+ int i;
+ bool operator==(const Foo& rhs) {
+ return i == rhs.i;
+ }
+};
+
+#define NOP(x) (x)
+void b(Foo f1, Foo f2) {
+ NOP(f1 == f2); // expected-warning {{expression result unused}}
+}
+#undef NOP
+}
diff --git a/test/SemaCXX/warn-weak-vtables.cpp b/test/SemaCXX/warn-weak-vtables.cpp
index c0cfd74a3e52..912622f5a7e4 100644
--- a/test/SemaCXX/warn-weak-vtables.cpp
+++ b/test/SemaCXX/warn-weak-vtables.cpp
@@ -29,3 +29,30 @@ void uses(A &a, B<int> &b, C &c) {
b.f();
c.f();
}
+
+// <rdar://problem/9979458>
+class Parent {
+public:
+ Parent() {}
+ virtual ~Parent();
+ virtual void * getFoo() const = 0;
+};
+
+class Derived : public Parent {
+public:
+ Derived();
+ void * getFoo() const;
+};
+
+class VeryDerived : public Derived { // expected-warning{{'VeryDerived' has no out-of-line virtual method definitions; its vtable will be emitted in every translation unit}}
+public:
+ void * getFoo() const { return 0; }
+};
+
+Parent::~Parent() {}
+
+void uses(Parent &p, Derived &d, VeryDerived &vd) {
+ p.getFoo();
+ d.getFoo();
+ vd.getFoo();
+}
diff --git a/test/SemaObjC/arc-bridged-cast.m b/test/SemaObjC/arc-bridged-cast.m
index e883406db908..47476c83064d 100644
--- a/test/SemaObjC/arc-bridged-cast.m
+++ b/test/SemaObjC/arc-bridged-cast.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fblocks -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fblocks %s
typedef const void *CFTypeRef;
typedef const struct __CFString *CFStringRef;
diff --git a/test/SemaObjC/arc-cf.m b/test/SemaObjC/arc-cf.m
new file mode 100644
index 000000000000..c1df3e0489f1
--- /dev/null
+++ b/test/SemaObjC/arc-cf.m
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify %s
+
+typedef const void *CFTypeRef;
+typedef const struct __CFString *CFStringRef;
+
+extern CFStringRef CFMakeString0(void);
+extern CFStringRef CFCreateString0(void);
+void test0() {
+ id x;
+ x = (id) CFMakeString0(); // expected-error {{requires a bridged cast}} expected-note {{__bridge to convert directly}} expected-note {{__bridge_transfer to transfer}}
+ x = (id) CFCreateString0(); // expected-error {{requires a bridged cast}} expected-note {{__bridge to convert directly}} expected-note {{__bridge_transfer to transfer}}
+}
+
+extern CFStringRef CFMakeString1(void) __attribute__((cf_returns_not_retained));
+extern CFStringRef CFCreateString1(void) __attribute__((cf_returns_retained));
+void test1() {
+ id x;
+ x = (id) CFMakeString1();
+ x = (id) CFCreateString1(); // expected-error {{requires a bridged cast}} expected-note {{__bridge to convert directly}} expected-note {{__bridge_transfer to transfer}}
+}
diff --git a/test/SemaObjC/arc-decls.m b/test/SemaObjC/arc-decls.m
index e713d239a0cf..1084db86268f 100644
--- a/test/SemaObjC/arc-decls.m
+++ b/test/SemaObjC/arc-decls.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-nonfragile-abi -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify %s
// rdar://8843524
@@ -62,3 +62,22 @@ void func()
- new {return 0; };
@end
+
+// rdar://10187884
+@interface Super
+- (void)bar:(id)b; // expected-note {{parameter declared here}}
+- (void)bar1:(id) __attribute((ns_consumed)) b;
+- (void)ok:(id) __attribute((ns_consumed)) b;
+- (id)ns_non; // expected-note {{method declared here}}
+- (id)not_ret:(id) b __attribute((ns_returns_not_retained)); // expected-note {{method declared here}}
+- (id)both__returns_not_retained:(id) b __attribute((ns_returns_not_retained));
+@end
+
+@interface Sub : Super
+- (void)bar:(id) __attribute((ns_consumed)) b; // expected-error {{overriding method has mismatched ns_consumed attribute on its parameter}}
+- (void)bar1:(id)b;
+- (void)ok:(id) __attribute((ns_consumed)) b;
+- (id)ns_non __attribute((ns_returns_not_retained)); // expected-error {{overriding method has mismatched ns_returns_not_retained attributes}}
+- (id)not_ret:(id) b __attribute((ns_returns_retained)); // expected-error {{overriding method has mismatched ns_returns_retained attributes}}
+- (id)both__returns_not_retained:(id) b __attribute((ns_returns_not_retained));
+@end
diff --git a/test/SemaObjC/arc-jump-block.m b/test/SemaObjC/arc-jump-block.m
index 1c7b21e4e8cd..9b44606c59d3 100644
--- a/test/SemaObjC/arc-jump-block.m
+++ b/test/SemaObjC/arc-jump-block.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -verify %s
// rdar://9535237
typedef struct dispatch_queue_s *dispatch_queue_t;
diff --git a/test/SemaObjC/arc-no-runtime.m b/test/SemaObjC/arc-no-runtime.m
index 94299e235e81..49c439b16760 100644
--- a/test/SemaObjC/arc-no-runtime.m
+++ b/test/SemaObjC/arc-no-runtime.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-arc -fobjc-nonfragile-abi -verify %s
+// RUN: %clang_cc1 -fobjc-arc -verify %s
// rdar://problem/9150784
void test(void) {
diff --git a/test/SemaObjC/arc-non-pod-memaccess.m b/test/SemaObjC/arc-non-pod-memaccess.m
index c9a77519694d..2b1223abbe78 100644
--- a/test/SemaObjC/arc-non-pod-memaccess.m
+++ b/test/SemaObjC/arc-non-pod-memaccess.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
-// RUN: %clang_cc1 -x objective-c++ -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
#ifdef __cplusplus
extern "C" {
@@ -53,3 +53,11 @@ void test(id __strong *sip, id __weak *wip, id __autoreleasing *aip,
// expected-note{{explicitly cast the pointer to silence this warning}}
memmove(ptr, uip, 17);
}
+
+void rdar9772982(int i, ...) {
+ __builtin_va_list ap;
+
+ __builtin_va_start(ap, i);
+ __builtin_va_arg(ap, __strong id); // expected-error{{second argument to 'va_arg' is of ARC ownership-qualified type '__strong id'}}
+ __builtin_va_end(ap);
+}
diff --git a/test/SemaObjC/arc-nsconsumed-errors.m b/test/SemaObjC/arc-nsconsumed-errors.m
new file mode 100644
index 000000000000..62e74aabaffd
--- /dev/null
+++ b/test/SemaObjC/arc-nsconsumed-errors.m
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
+// rdar://10187884
+
+typedef void (^blk)(id arg1, __attribute((ns_consumed)) id arg2);
+typedef void (^blk1)(__attribute((ns_consumed))id arg1, __attribute((ns_consumed)) id arg2);
+blk a = ^void (__attribute((ns_consumed)) id arg1, __attribute((ns_consumed)) id arg2){}; // expected-error {{incompatible block pointer types initializing}}
+
+blk b = ^void (id arg1, __attribute((ns_consumed)) id arg2){};
+
+blk c = ^void (__attribute((ns_consumed)) id arg1, __attribute((ns_consumed)) id arg2){}; // expected-error {{incompatible block pointer types initializing}}
+
+blk d = ^void (id arg1, id arg2) {}; // expected-error {{incompatible block pointer types initializing}}
+
+blk1 a1 = ^void (__attribute((ns_consumed)) id arg1, id arg2){}; // expected-error {{incompatible block pointer types initializing}}
+
+blk1 b2 = ^void (id arg1, __attribute((ns_consumed)) id arg2){}; // expected-error {{incompatible block pointer types initializing}}
+
+blk1 c3 = ^void (__attribute((ns_consumed)) id arg1, __attribute((ns_consumed)) id arg2){};
+
+blk1 d4 = ^void (id arg1, id arg2) {}; // expected-error {{incompatible block pointer types initializing}}
diff --git a/test/SemaObjC/arc-peformselector.m b/test/SemaObjC/arc-peformselector.m
index e637f3d76ff4..c015eb871150 100644
--- a/test/SemaObjC/arc-peformselector.m
+++ b/test/SemaObjC/arc-peformselector.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -verify %s
// rdar://9659270
@interface NSObject
diff --git a/test/SemaObjC/arc-property-decl-attrs.m b/test/SemaObjC/arc-property-decl-attrs.m
index 0dd74b8ad5ce..1386241dd73c 100644
--- a/test/SemaObjC/arc-property-decl-attrs.m
+++ b/test/SemaObjC/arc-property-decl-attrs.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify %s
// rdar://9340606
@interface Foo {
@@ -65,3 +65,17 @@
@property(unsafe_unretained) __weak id y; // expected-error {{property attributes 'unsafe_unretained' and 'weak' are mutually exclusive}}
@property(unsafe_unretained) __autoreleasing id z; // expected-error {{unsafe_unretained property 'z' may not also be declared __autoreleasing}}
@end
+
+// rdar://9396329
+@interface Super
+@property (readonly, retain) id foo;
+@property (readonly, weak) id fee;
+@property (readonly, strong) id frr;
+@end
+
+@interface Bugg : Super
+@property (readwrite) id foo;
+@property (readwrite) id fee;
+@property (readwrite) id frr;
+@end
+
diff --git a/test/SemaObjC/arc-property-lifetime.m b/test/SemaObjC/arc-property-lifetime.m
index b1c84c75c058..9cc3ada15fad 100644
--- a/test/SemaObjC/arc-property-lifetime.m
+++ b/test/SemaObjC/arc-property-lifetime.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify %s
// rdar://9340606
@interface Foo {
@@ -79,7 +79,7 @@
@implementation Gorf
@synthesize x;
-@synthesize y; // expected-error {{existing ivar 'y' for unsafe_unretained property 'y' must be __unsafe_unretained}}
+@synthesize y; // expected-error {{existing ivar 'y' for property 'y' with assign attribute must be __unsafe_unretained}}
@synthesize z;
@end
@@ -94,7 +94,7 @@
@implementation Gorf2
@synthesize x;
-@synthesize y; // expected-error {{existing ivar 'y' for unsafe_unretained property 'y' must be __unsafe_unretained}}
+@synthesize y; // expected-error {{existing ivar 'y' for property 'y' with unsafe_unretained attribute must be __unsafe_unretained}}
@synthesize z;
@end
@@ -110,3 +110,18 @@
@synthesize isAutosaving = _isAutosaving;
@end
+// rdar://10239594
+// Test for 'Class' properties being unretained.
+@interface MyClass {
+@private
+ Class _controllerClass;
+ id _controllerId;
+}
+@property (copy) Class controllerClass;
+@property (copy) id controllerId;
+@end
+
+@implementation MyClass
+@synthesize controllerClass = _controllerClass;
+@synthesize controllerId = _controllerId;
+@end
diff --git a/test/SemaObjC/arc-property.m b/test/SemaObjC/arc-property.m
index 0651f1808dc9..299311859203 100644
--- a/test/SemaObjC/arc-property.m
+++ b/test/SemaObjC/arc-property.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -fblocks -verify %s
// rdar://9309489
@interface MyClass {
diff --git a/test/SemaObjC/arc-retain-block-property.m b/test/SemaObjC/arc-retain-block-property.m
new file mode 100644
index 000000000000..c7d043004948
--- /dev/null
+++ b/test/SemaObjC/arc-retain-block-property.m
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -fsyntax-only -fblocks -fobjc-arc -verify %s
+// rdar://9829425
+
+extern void doSomething();
+
+@interface Test
+{
+@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 (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}}
+@end
+
+@implementation Test
+@synthesize aBlock;
+@dynamic aBlockW, aBlockS, aBlockR, aBlockC, aBlockA;
+@end
+
+int main() {
+ Test *t;
+ t.aBlock = ^{ doSomething(); };
+ t.aBlockW = ^{ doSomething(); };
+ t.aBlockS = ^{ doSomething(); };
+}
+
diff --git a/test/SemaObjC/arc-setter-property-match.m b/test/SemaObjC/arc-setter-property-match.m
new file mode 100644
index 000000000000..0de0a11f1bbe
--- /dev/null
+++ b/test/SemaObjC/arc-setter-property-match.m
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -verify %s
+// rdar://10156674
+
+@class NSArray;
+
+@interface MyClass2 {
+@private
+ NSArray *_names1;
+ NSArray *_names2;
+ NSArray *_names3;
+ NSArray *_names4;
+}
+@property (readwrite, strong) NSArray *names1; // <-- warning: Type of property....
+- (void)setNames1:(NSArray *)names;
+@property (readwrite, strong) __strong NSArray *names2; // <-- warning: Type of property....
+- (void)setNames2:(NSArray *)names;
+@property (readwrite, strong) __strong NSArray *names3; // <-- OK
+- (void)setNames3:(__strong NSArray *)names;
+@property (readwrite, strong) NSArray *names4; // <-- warning: Type of property....
+- (void)setNames4:(__strong NSArray *)names;
+
+@end
+
+@implementation MyClass2
+- (NSArray *)names1 { return _names1; }
+- (void)setNames1:(NSArray *)names {}
+- (NSArray *)names2 { return _names2; }
+- (void)setNames2:(NSArray *)names {}
+- (NSArray *)names3 { return _names3; }
+- (void)setNames3:(__strong NSArray *)names {}
+- (NSArray *)names4 { return _names4; }
+- (void)setNames4:(__strong NSArray *)names {}
+
+@end
+
diff --git a/test/SemaObjC/arc-system-header.m b/test/SemaObjC/arc-system-header.m
index 3f176577156f..1a7c39d4e1cd 100644
--- a/test/SemaObjC/arc-system-header.m
+++ b/test/SemaObjC/arc-system-header.m
@@ -1,6 +1,6 @@
// silly workaround expected-note {{marked unavailable here}}
-// RUN: %clang_cc1 -fobjc-arc -fobjc-nonfragile-abi -isystem %S/Inputs %s -DNO_USE
-// RUN: %clang_cc1 -fobjc-arc -fobjc-nonfragile-abi -isystem %S/Inputs %s -verify
+// RUN: %clang_cc1 -fobjc-arc -isystem %S/Inputs %s -DNO_USE
+// RUN: %clang_cc1 -fobjc-arc -isystem %S/Inputs %s -verify
// another silly workaround expected-note {{marked unavailable here}}
#include <arc-system-header.h>
diff --git a/test/SemaObjC/arc-type-conversion.m b/test/SemaObjC/arc-type-conversion.m
index 103db5695f49..01f61bd4b674 100644
--- a/test/SemaObjC/arc-type-conversion.m
+++ b/test/SemaObjC/arc-type-conversion.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-nonfragile-abi -fobjc-runtime-has-weak -verify -fblocks %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -verify -fblocks %s
void * cvt(id arg)
{
diff --git a/test/SemaObjC/arc-unavailable-for-weakref.m b/test/SemaObjC/arc-unavailable-for-weakref.m
index 104314e6b1d3..6db2155f8c64 100644
--- a/test/SemaObjC/arc-unavailable-for-weakref.m
+++ b/test/SemaObjC/arc-unavailable-for-weakref.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify %s
// rdar://9693477
__attribute__((objc_arc_weak_reference_unavailable))
diff --git a/test/SemaObjC/arc-unavailable-system-function.m b/test/SemaObjC/arc-unavailable-system-function.m
new file mode 100644
index 000000000000..b0b70db641cb
--- /dev/null
+++ b/test/SemaObjC/arc-unavailable-system-function.m
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin11 -fobjc-arc -verify %s
+// rdar://10186625
+
+# 1 "<command line>"
+# 1 "/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h" 1 3
+id * foo(); // expected-note {{function has been explicitly marked unavailable here}}
+
+# 1 "arc-unavailable-system-function.m" 2
+void ret() {
+ foo(); // expected-error {{'foo' is unavailable: this system declaration uses an unsupported type}}
+}
+
+
diff --git a/test/SemaObjC/arc-unbridged-cast.m b/test/SemaObjC/arc-unbridged-cast.m
index 03c84cfce336..8b835a14986d 100644
--- a/test/SemaObjC/arc-unbridged-cast.m
+++ b/test/SemaObjC/arc-unbridged-cast.m
@@ -1,18 +1,72 @@
-// // RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify %s
-// rdar://9744349
+// // RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -verify %s
typedef const struct __CFString * CFStringRef;
-@interface I
-@property CFStringRef P;
+@interface Object
+@property CFStringRef property;
+- (CFStringRef) implicitProperty;
+- (CFStringRef) newString;
+- (CFStringRef) makeString;
@end
-@implementation I
-@synthesize P;
-- (id) Meth {
- I* p1 = (id)[p1 P];
- id p2 = (__bridge_transfer id)[p1 P];
- id p3 = (__bridge I*)[p1 P];
- return (id) p1.P;
+extern Object *object;
+
+// rdar://9744349
+id test0(void) {
+ id p1 = (id)[object property];
+ id p2 = (__bridge_transfer id)[object property];
+ id p3 = (__bridge id)[object property];
+ return (id) object.property;
+}
+
+// rdar://10140692
+CFStringRef unauditedString(void);
+CFStringRef plusOneString(void) __attribute__((cf_returns_retained));
+
+#pragma clang arc_cf_code_audited begin
+CFStringRef auditedString(void);
+CFStringRef auditedCreateString(void);
+#pragma clang arc_cf_code_audited end
+
+void test1(int cond) {
+ id x;
+ x = (id) auditedString();
+ x = (id) (cond ? auditedString() : (void*) 0);
+ x = (id) (cond ? (void*) 0 : auditedString());
+ x = (id) (cond ? (CFStringRef) @"help" : auditedString());
+
+ x = (id) unauditedString(); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}}
+ x = (id) (cond ? unauditedString() : (void*) 0); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}}
+ x = (id) (cond ? (void*) 0 : unauditedString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}}
+ x = (id) (cond ? (CFStringRef) @"help" : unauditedString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}}
+
+ x = (id) auditedCreateString(); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}}
+ x = (id) (cond ? auditedCreateString() : (void*) 0); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}}
+ x = (id) (cond ? (void*) 0 : auditedCreateString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}}
+ x = (id) (cond ? (CFStringRef) @"help" : auditedCreateString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}}
+
+ x = (id) [object property];
+ x = (id) (cond ? [object property] : (void*) 0);
+ x = (id) (cond ? (void*) 0 : [object property]);
+ x = (id) (cond ? (CFStringRef) @"help" : [object property]);
+
+ x = (id) object.property;
+ x = (id) (cond ? object.property : (void*) 0);
+ x = (id) (cond ? (void*) 0 : object.property);
+ x = (id) (cond ? (CFStringRef) @"help" : object.property);
+
+ x = (id) object.implicitProperty;
+ x = (id) (cond ? object.implicitProperty : (void*) 0);
+ x = (id) (cond ? (void*) 0 : object.implicitProperty);
+ x = (id) (cond ? (CFStringRef) @"help" : object.implicitProperty);
+
+ x = (id) [object makeString];
+ x = (id) (cond ? [object makeString] : (void*) 0);
+ x = (id) (cond ? (void*) 0 : [object makeString]);
+ x = (id) (cond ? (CFStringRef) @"help" : [object makeString]);
+
+ x = (id) [object newString];
+ x = (id) (cond ? [object newString] : (void*) 0);
+ x = (id) (cond ? (void*) 0 : [object newString]);
+ x = (id) (cond ? (CFStringRef) @"help" : [object newString]); // a bit questionable
}
-@end
diff --git a/test/SemaObjC/arc-unsafe-assigns.m b/test/SemaObjC/arc-unsafe-assigns.m
index be8f90295e8b..6dba18ba073b 100644
--- a/test/SemaObjC/arc-unsafe-assigns.m
+++ b/test/SemaObjC/arc-unsafe-assigns.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -verify %s
// rdar://9495837
@interface Foo {
diff --git a/test/SemaObjC/arc-unsafe_unretained.m b/test/SemaObjC/arc-unsafe_unretained.m
index 77bdded1763b..a6c5f985df8f 100644
--- a/test/SemaObjC/arc-unsafe_unretained.m
+++ b/test/SemaObjC/arc-unsafe_unretained.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -fblocks -fobjc-nonfragile-abi %s
-// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -fobjc-nonfragile-abi -fobjc-arc %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -fblocks %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -fobjc-arc %s
struct X {
__unsafe_unretained id object;
diff --git a/test/SemaObjC/arc.m b/test/SemaObjC/arc.m
index 3d190e5c53a0..ed6e60d8dc2f 100644
--- a/test/SemaObjC/arc.m
+++ b/test/SemaObjC/arc.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -fblocks -verify %s
typedef unsigned long NSUInteger;
@@ -41,10 +41,10 @@ __weak __strong id x; // expected-error {{the type '__strong id' already has ret
// rdar://8843638
@interface I
-- (id)retain;
-- (id)autorelease;
-- (oneway void)release;
-- (NSUInteger)retainCount;
+- (id)retain; // expected-note {{method declared here}}
+- (id)autorelease; // expected-note {{method declared here}}
+- (oneway void)release; // expected-note {{method declared here}}
+- (NSUInteger)retainCount; // expected-note {{method declared here}}
@end
@implementation I
@@ -55,10 +55,14 @@ __weak __strong id x; // expected-error {{the type '__strong id' already has ret
@end
@implementation I(CAT)
-- (id)retain{return 0;} // expected-error {{ARC forbids implementation of 'retain'}}
-- (id)autorelease{return 0;} // expected-error {{ARC forbids implementation of 'autorelease'}}
-- (oneway void)release{} // expected-error {{ARC forbids implementation of 'release'}}
-- (NSUInteger)retainCount{ return 0; } // expected-error {{ARC forbids implementation of 'retainCount'}}
+- (id)retain{return 0;} // expected-error {{ARC forbids implementation of 'retain'}} \
+ // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
+- (id)autorelease{return 0;} // expected-error {{ARC forbids implementation of 'autorelease'}} \
+ // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
+- (oneway void)release{} // expected-error {{ARC forbids implementation of 'release'}} \
+ // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
+- (NSUInteger)retainCount{ return 0; } // expected-error {{ARC forbids implementation of 'retainCount'}} \
+ // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
@end
// rdar://8861761
@@ -483,19 +487,29 @@ void test26(id y) {
@end
// rdar://9525555
-@interface Test27
-@property id x; // expected-warning {{no 'assign', 'retain', or 'copy' attribute is specified - 'assign' is assumed}} \
- // expected-warning {{default property attribute 'assign' not appropriate for non-gc object}} \
- // expected-note {{declared here}}
+@interface Test27 {
+ __weak id _myProp1;
+ id myProp2;
+}
+@property id x;
@property (readonly) id ro; // expected-note {{declared here}}
@property (readonly) id custom_ro;
@property int y;
+
+@property (readonly) id myProp1;
+@property (readonly) id myProp2;
+@property (readonly) __strong id myProp3;
@end
@implementation Test27
-@synthesize x; // expected-error {{ARC forbids synthesizing a property of an Objective-C object with unspecified storage attribute}}
-@synthesize ro; // expected-error {{ARC forbids synthesizing a property of an Objective-C object with unspecified storage attribute}}
+@synthesize x;
+@synthesize ro; // expected-error {{ARC forbids synthesizing a property of an Objective-C object with unspecified ownership or storage attribute}}
@synthesize y;
+
+@synthesize myProp1 = _myProp1;
+@synthesize myProp2;
+@synthesize myProp3;
+
-(id)custom_ro { return 0; }
@end
@@ -626,3 +640,48 @@ void test36(int first, ...) {
id obj = __builtin_va_arg(arglist, id);
__builtin_va_end(arglist);
}
+
+@class Test37;
+void test37(Test37 *c) {
+ for (id y in c) { // expected-error {{collection expression type 'Test37' is a forward declaration}}
+ (void) y;
+ }
+
+ (void)sizeof(id*); // no error.
+}
+
+// rdar://problem/9887979
+@interface Test38
+@property int value;
+@end
+void test38() {
+ extern Test38 *test38_helper(void);
+ switch (test38_helper().value) {
+ case 0:
+ case 1:
+ ;
+ }
+}
+
+// rdar://10186536
+@class NSColor;
+void _NSCalc(NSColor* color, NSColor* bezelColors[]) __attribute__((unavailable("not available in automatic reference counting mode")));
+
+void _NSCalcBeze(NSColor* color, NSColor* bezelColors[]); // expected-error {{must explicitly describe intended ownership of an object array parameter}}
+
+// rdar://9970739
+@interface RestaurantTableViewCell
+- (void) restaurantLocation;
+@end
+
+@interface Radar9970739
+- (void) Meth;
+@end
+
+@implementation Radar9970739
+- (void) Meth {
+ RestaurantTableViewCell *cell;
+ [cell restaurantLocatoin]; // expected-error {{no visible @interface for 'RestaurantTableViewCell' declares the selector 'restaurantLocatoin'}}
+}
+@end
+
diff --git a/test/SemaObjC/assign-rvalue-message.m b/test/SemaObjC/assign-rvalue-message.m
index 7e05c89afa43..8cbce8e2ee54 100644
--- a/test/SemaObjC/assign-rvalue-message.m
+++ b/test/SemaObjC/assign-rvalue-message.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -fobjc-nonfragile-abi %s
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fsyntax-only -verify -fobjc-nonfragile-abi %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
// rdar://9005189
@interface Foo
diff --git a/test/SemaObjC/at-defs.m b/test/SemaObjC/at-defs.m
index bfa212375050..4c0c586fe838 100644
--- a/test/SemaObjC/at-defs.m
+++ b/test/SemaObjC/at-defs.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown %s -fsyntax-only
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fobjc-fragile-abi %s -fsyntax-only
@interface Test {
double a;
diff --git a/test/SemaObjC/atomoic-property-synnthesis-rules.m b/test/SemaObjC/atomoic-property-synnthesis-rules.m
index af790e3159ad..2061a779dc57 100644
--- a/test/SemaObjC/atomoic-property-synnthesis-rules.m
+++ b/test/SemaObjC/atomoic-property-synnthesis-rules.m
@@ -240,8 +240,10 @@
GET(GetSet)
SET(GetSet)
-GET(Get) // expected-warning {{writable atomic property 'Get' cannot pair a synthesized setter/getter with a user defined setter/getter}}
-SET(Set) // expected-warning {{writable atomic property 'Set' cannot pair a synthesized setter/getter with a user defined setter/getter}}
+GET(Get) // expected-warning {{writable atomic property 'Get' cannot pair a synthesized setter with a user defined getter}} \
+ // expected-note {{setter and getter must both be synthesized}}
+SET(Set) // expected-warning {{writable atomic property 'Set' cannot pair a synthesized getter with a user defined setter}} \
+ // expected-note {{setter and getter must both be synthesized}}
GET(GetSet_Nonatomic)
SET(GetSet_Nonatomic)
GET(Get_Nonatomic)
@@ -258,8 +260,10 @@ SET(Set_Nonatomic_ReadOnly)
GET(GetSet_ReadWriteInExt)
SET(GetSet_ReadWriteInExt)
-GET(Get_ReadWriteInExt) // expected-warning {{writable atomic property 'Get_ReadWriteInExt' cannot pair a synthesized setter/getter with a user defined setter/getter}}
-SET(Set_ReadWriteInExt) // expected-warning {{writable atomic property 'Set_ReadWriteInExt' cannot pair a synthesized setter/getter with a user defined setter/getter}}
+GET(Get_ReadWriteInExt) // expected-warning {{writable atomic property 'Get_ReadWriteInExt' cannot pair a synthesized setter with a user defined getter}} \
+ // expected-note {{setter and getter must both be synthesized}}
+SET(Set_ReadWriteInExt) // expected-warning {{writable atomic property 'Set_ReadWriteInExt' cannot pair a synthesized getter with a user defined setter}} \
+ // expected-note {{setter and getter must both be synthesized}}
GET(GetSet_Nonatomic_ReadWriteInExt)
SET(GetSet_Nonatomic_ReadWriteInExt)
GET(Get_Nonatomic_ReadWriteInExt)
@@ -268,8 +272,10 @@ SET(Set_Nonatomic_ReadWriteInExt)
GET(GetSet_LateSynthesize)
SET(GetSet_LateSynthesize)
-GET(Get_LateSynthesize) // expected-warning {{writable atomic property 'Get_LateSynthesize' cannot pair a synthesized setter/getter with a user defined setter/getter}}
-SET(Set_LateSynthesize) // expected-warning {{writable atomic property 'Set_LateSynthesize' cannot pair a synthesized setter/getter with a user defined setter/getter}}
+GET(Get_LateSynthesize) // expected-warning {{writable atomic property 'Get_LateSynthesize' cannot pair a synthesized setter with a user defined getter}} \
+ // expected-note {{setter and getter must both be synthesized}}
+SET(Set_LateSynthesize) // expected-warning {{writable atomic property 'Set_LateSynthesize' cannot pair a synthesized getter with a user defined setter}} \
+ // expected-note {{setter and getter must both be synthesized}}
GET(GetSet_Nonatomic_LateSynthesize)
SET(GetSet_Nonatomic_LateSynthesize)
GET(Get_Nonatomic_LateSynthesize)
@@ -286,8 +292,10 @@ SET(Set_Nonatomic_ReadOnly_LateSynthesize)
GET(GetSet_ReadWriteInExt_LateSynthesize)
SET(GetSet_ReadWriteInExt_LateSynthesize)
-GET(Get_ReadWriteInExt_LateSynthesize) // expected-warning {{writable atomic property 'Get_ReadWriteInExt_LateSynthesize' cannot pair a synthesized setter/getter with a user defined setter/getter}}
-SET(Set_ReadWriteInExt_LateSynthesize) // expected-warning {{writable atomic property 'Set_ReadWriteInExt_LateSynthesize' cannot pair a synthesized setter/getter with a user defined setter/getter}}
+GET(Get_ReadWriteInExt_LateSynthesize) // expected-warning {{writable atomic property 'Get_ReadWriteInExt_LateSynthesize' cannot pair a synthesized setter with a user defined getter}} \
+ // expected-note {{setter and getter must both be synthesized}}
+SET(Set_ReadWriteInExt_LateSynthesize) // expected-warning {{writable atomic property 'Set_ReadWriteInExt_LateSynthesize' cannot pair a synthesized getter with a user defined setter}} \
+ // expected-note {{setter and getter must both be synthesized}}
GET(GetSet_Nonatomic_ReadWriteInExt_LateSynthesize)
SET(GetSet_Nonatomic_ReadWriteInExt_LateSynthesize)
GET(Get_Nonatomic_ReadWriteInExt_LateSynthesize)
diff --git a/test/SemaObjC/attr-availability.m b/test/SemaObjC/attr-availability.m
new file mode 100644
index 000000000000..d857bda77234
--- /dev/null
+++ b/test/SemaObjC/attr-availability.m
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9.0.0 -fsyntax-only -verify %s
+@interface A
+- (void)method __attribute__((availability(macosx,introduced=10.1,deprecated=10.2)));
+@end
+
+@interface B : A
+- (void)method;
+@end
+
+void f(A *a, B *b) {
+ [a method]; // expected-warning{{'method' is deprecated: first deprecated in Mac OS X 10.2}}
+ [b method];
+}
diff --git a/test/SemaObjC/attr-deprecated.m b/test/SemaObjC/attr-deprecated.m
index d3d5f9537b73..ca267599288e 100644
--- a/test/SemaObjC/attr-deprecated.m
+++ b/test/SemaObjC/attr-deprecated.m
@@ -85,12 +85,21 @@ int t5() {
__attribute ((deprecated))
@interface DEPRECATED {
@public int ivar;
+ DEPRECATED *ivar2; // no warning.
}
- (int) instancemethod;
+- (DEPRECATED *) meth; // no warning.
@property int prop;
@end
-@interface DEPRECATED (Category) // expected-warning {{warning: 'DEPRECATED' is deprecated}}
+@interface DEPRECATED (Category) // no warning.
+- (DEPRECATED *) meth2; // no warning.
+@end
+
+@interface DEPRECATED (Category2) // no warning.
+@end
+
+@implementation DEPRECATED (Category2) // expected-warning {{warning: 'DEPRECATED' is deprecated}}
@end
@interface NS : DEPRECATED // expected-warning {{warning: 'DEPRECATED' is deprecated}}
@@ -108,3 +117,7 @@ void test(Test2 *foo) {
foo.test2 = x; // expected-warning {{'test2' is deprecated}}
[foo setTest2: x]; // expected-warning {{'setTest2:' is deprecated}}
}
+
+__attribute__((deprecated))
+@interface A(Blah) // expected-error{{attributes may not be specified on a category}}
+@end
diff --git a/test/SemaObjC/attr-ns-bridged.m b/test/SemaObjC/attr-ns-bridged.m
new file mode 100644
index 000000000000..1ab60a2b0d80
--- /dev/null
+++ b/test/SemaObjC/attr-ns-bridged.m
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef struct __attribute__((ns_bridged)) test0s *test0ref;
+
+void test0func(void) __attribute__((ns_bridged)); // expected-error {{'ns_bridged' attribute only applies to structs}}
+
+union __attribute__((ns_bridged)) test0u; // expected-error {{'ns_bridged' attribute only applies to structs}}
+
+struct __attribute__((ns_bridged(Test1))) test1s;
+
+@class Test2;
+struct __attribute__((ns_bridged(Test2))) test2s;
+
+void Test3(void); // expected-note {{declared here}}
+struct __attribute__((ns_bridged(Test3))) test3s; // expected-error {{parameter of 'ns_bridged' attribute does not name an Objective-C class}}
diff --git a/test/SemaObjC/bad-property-synthesis-crash.m b/test/SemaObjC/bad-property-synthesis-crash.m
new file mode 100644
index 000000000000..577faea9dadc
--- /dev/null
+++ b/test/SemaObjC/bad-property-synthesis-crash.m
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://10177744
+
+@interface Foo
+@property (nonatomic, retain) NSString* what; // expected-error {{unknown type name 'NSString'}} \
+ // expected-error {{property with}} \
+ // expected-note {{previous definition is here}}
+@end
+
+@implementation Foo
+- (void) setWhat: (NSString*) value { // expected-error {{expected a type}} \
+ // expected-warning {{conflicting parameter types in implementation of}}
+ __what; // expected-error {{use of undeclared identifier}} \
+ // expected-warning {{expression result unused}}
+}
+@synthesize what; // expected-note 2 {{'what' declared here}}
+@end
+
+@implementation Bar // expected-warning {{cannot find interface declaration for}}
+- (NSString*) what { // expected-error {{expected a type}}
+ return __what; // expected-error {{use of undeclared identifier}}
+}
+@end
diff --git a/test/SemaObjC/blocks.m b/test/SemaObjC/blocks.m
index 15aa5811cc53..2d77a20fce03 100644
--- a/test/SemaObjC/blocks.m
+++ b/test/SemaObjC/blocks.m
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s
+
+#define bool _Bool
@protocol NSObject;
void bar(id(^)(void));
@@ -21,9 +23,13 @@ void foo4(id (^objectCreationBlock)(int)) {
return bar4(objectCreationBlock);
}
-void bar5(id(^)(void)); // expected-note{{passing argument to parameter here}}
-void foo5(id (^objectCreationBlock)(int)) {
- return bar5(objectCreationBlock); // expected-error {{incompatible block pointer types passing 'id (^)(int)' to parameter of type 'id (^)(void)'}}
+void bar5(id(^)(void)); // expected-note 3{{passing argument to parameter here}}
+void foo5(id (^objectCreationBlock)(bool)) {
+ bar5(objectCreationBlock); // expected-error {{incompatible block pointer types passing 'id (^)(bool)' to parameter of type 'id (^)(void)'}}
+#undef bool
+ bar5(objectCreationBlock); // expected-error {{incompatible block pointer types passing 'id (^)(_Bool)' to parameter of type 'id (^)(void)'}}
+#define bool int
+ bar5(objectCreationBlock); // expected-error {{incompatible block pointer types passing 'id (^)(_Bool)' to parameter of type 'id (^)(void)'}}
}
void bar6(id(^)(int));
diff --git a/test/SemaObjC/builtin_objc_assign_ivar.m b/test/SemaObjC/builtin_objc_assign_ivar.m
new file mode 100644
index 000000000000..5839bf444419
--- /dev/null
+++ b/test/SemaObjC/builtin_objc_assign_ivar.m
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -x objective-c %s -fsyntax-only -verify
+// rdar://9362887
+
+typedef __typeof__(((int*)0)-((int*)0)) ptrdiff_t;
+extern id objc_assign_ivar(id value, id dest, ptrdiff_t offset);
+
diff --git a/test/SemaObjC/class-bitfield.m b/test/SemaObjC/class-bitfield.m
index c0393c2287c1..ae12e0498eea 100644
--- a/test/SemaObjC/class-bitfield.m
+++ b/test/SemaObjC/class-bitfield.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify
+// RUN: %clang_cc1 %s -fobjc-fragile-abi -fsyntax-only -verify
@interface X
{
diff --git a/test/SemaObjC/class-protocol-method-match.m b/test/SemaObjC/class-protocol-method-match.m
new file mode 100644
index 000000000000..04243e967757
--- /dev/null
+++ b/test/SemaObjC/class-protocol-method-match.m
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -Woverriding-method-mismatch -fsyntax-only -verify %s
+// rdar://9352731
+
+@protocol Bar
+@required
+- (bycopy id)bud; // expected-note {{previous declaration is here}}
+- (unsigned char) baz; // expected-note {{previous declaration is here}}
+- (char) ok;
+- (void) also_ok;
+@end
+
+@protocol Bar1
+@required
+- (unsigned char) baz; // expected-note {{previous declaration is here}}
+- (unsigned char) also_ok; // expected-note {{previous declaration is here}}
+- (void) ban : (int) arg, ...; // expected-note {{previous declaration is here}}
+@end
+
+@protocol Baz <Bar, Bar1>
+- (void) bar : (unsigned char)arg; // expected-note {{previous declaration is here}}
+- (void) ok;
+- (char) bak; // expected-note {{previous declaration is here}}
+@end
+
+@interface Foo <Baz>
+- (id)bud; // expected-warning {{conflicting distributed object modifiers on return type in declaration of 'bud'}}
+- (void) baz; // expected-warning 2 {{conflicting return type in declaration of 'baz': 'unsigned char' vs 'void'}}
+- (void) bar : (unsigned char*)arg; // expected-warning {{conflicting parameter types in declaration of 'bar:': 'unsigned char' vs 'unsigned char *'}}
+- (void) ok;
+- (void) also_ok; // expected-warning {{conflicting return type in declaration of 'also_ok': 'unsigned char' vs 'void'}}
+- (void) still_ok;
+- (void) ban : (int) arg; // expected-warning {{conflicting variadic declaration of method and its implementation}}
+@end
+
+@interface Foo()
+- (void) bak;
+@end
+
+@implementation Foo
+- (bycopy id)bud { return 0; }
+- (void) baz {}
+- (void) bar : (unsigned char*)arg {}
+- (void) ok {}
+- (void) also_ok {}
+- (void) still_ok {}
+- (void) ban : (int) arg {}
+- (void) bak {} // expected-warning {{conflicting return type in declaration of 'bak': 'char' vs 'void'}}
+@end
diff --git a/test/SemaObjC/class-unavail-warning.m b/test/SemaObjC/class-unavail-warning.m
index 408647ac11c1..b2bd38831101 100644
--- a/test/SemaObjC/class-unavail-warning.m
+++ b/test/SemaObjC/class-unavail-warning.m
@@ -2,17 +2,35 @@
// rdar://9092208
__attribute__((unavailable("not available")))
-@interface MyClass { // expected-note 5 {{declaration has been explicitly marked unavailable here}}
+@interface MyClass { // expected-note 8 {{declaration has been explicitly marked unavailable here}}
@public
void *_test;
+ MyClass *ivar; // no error.
}
- (id)self;
- new;
+ (void)addObject:(id)anObject;
+- (MyClass *)meth; // no error.
@end
+@interface Foo {
+ MyClass *ivar; // expected-error {{unavailable}}
+}
+- (MyClass *)meth; // expected-error {{unavailable}}
+@end
+
+@interface MyClass (Cat1)
+- (MyClass *)meth; // no error.
+@end
+
+@interface MyClass (Cat2) // no error.
+@end
+
+@implementation MyClass (Cat2) // expected-error {{unavailable}}
+@end
+
int main() {
[MyClass new]; // expected-error {{'MyClass' is unavailable: not available}}
[MyClass self]; // expected-error {{'MyClass' is unavailable: not available}}
diff --git a/test/SemaObjC/comptypes-10.m b/test/SemaObjC/comptypes-10.m
index 0a2219099fb6..1a6533a600ea 100644
--- a/test/SemaObjC/comptypes-10.m
+++ b/test/SemaObjC/comptypes-10.m
@@ -32,3 +32,21 @@ void test(id <NSCopying, NSPROTO, NSPROTO2> bar)
{
NSObject <NSCopying> *Init = bar; // expected-warning {{initializing 'NSObject<NSCopying> *' with an expression of incompatible type 'id<NSCopying,NSPROTO,NSPROTO2>'}}
}
+
+// rdar://8843851
+@interface NSObject (CAT)
++ (struct S*)Meth : (struct S*)arg;
+@end
+
+struct S {
+ char *types;
+};
+
+@interface I
+@end
+
+@implementation I
+- (struct S *)Meth : (struct S*)a {
+ return [NSObject Meth : a];
+}
+@end
diff --git a/test/SemaObjC/comptypes-7.m b/test/SemaObjC/comptypes-7.m
index df627e5300ad..ef0f158c49ee 100644
--- a/test/SemaObjC/comptypes-7.m
+++ b/test/SemaObjC/comptypes-7.m
@@ -30,7 +30,7 @@ int main()
obj_p = i; // expected-warning {{incompatible integer to pointer conversion assigning to 'id<MyProtocol>' from 'int'}}
obj_p = j; // expected-warning {{ incompatible pointer types assigning to 'id<MyProtocol>' from 'int *'}}
- obj_c = i; // expected-warning {{ incompatible integer to pointer conversion assigning to 'MyClass *' from 'int'}}
+ obj_c = i; // expected-warning {{incompatible integer to pointer conversion assigning to 'MyClass *' from 'int'}}
obj_c = j; // expected-warning {{incompatible pointer types assigning to 'MyClass *' from 'int *'}}
obj_C = i; // expected-warning {{incompatible integer to pointer conversion assigning to 'Class' from 'int'}}
diff --git a/test/SemaObjC/conflict-atomic-property.m b/test/SemaObjC/conflict-atomic-property.m
new file mode 100644
index 000000000000..033980c38c73
--- /dev/null
+++ b/test/SemaObjC/conflict-atomic-property.m
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://10260017
+
+@interface Foo
+@property (nonatomic, assign, atomic) float dummy; // expected-error {{property attributes 'atomic' and 'nonatomic' are mutually exclusive}}
+@property (nonatomic, assign) float d1;
+@property (atomic, assign) float d2;
+@property (assign) float d3;
+@property (atomic, nonatomic, assign) float d4; // expected-error {{property attributes 'atomic' and 'nonatomic' are mutually exclusive}}
+@end
diff --git a/test/SemaObjC/conflict-nonfragile-abi2.m b/test/SemaObjC/conflict-nonfragile-abi2.m
index 5d6b2810fc10..7c95d5d57b5e 100644
--- a/test/SemaObjC/conflict-nonfragile-abi2.m
+++ b/test/SemaObjC/conflict-nonfragile-abi2.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -verify -fsyntax-only %s
+// RUN: %clang_cc1 -verify -fsyntax-only %s
// rdar://8225011
int glob;
diff --git a/test/SemaObjC/conflicting-ivar-test-1.m b/test/SemaObjC/conflicting-ivar-test-1.m
index 1c68a23d7e28..01b35314aa98 100644
--- a/test/SemaObjC/conflicting-ivar-test-1.m
+++ b/test/SemaObjC/conflicting-ivar-test-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fobjc-fragile-abi -fsyntax-only -verify %s
@interface INTF
{
diff --git a/test/SemaObjC/continuation-class-property.m b/test/SemaObjC/continuation-class-property.m
index c48a23d62a9b..a579184060b7 100644
--- a/test/SemaObjC/continuation-class-property.m
+++ b/test/SemaObjC/continuation-class-property.m
@@ -22,3 +22,22 @@
@property (readwrite, copy) id foos;
@end
+
+// rdar://10142679
+@class NSString;
+
+typedef struct {
+ float width;
+ float length;
+} NSRect;
+
+@interface MyClass {
+}
+@property (readonly) NSRect foo; // expected-note {{property declared here}}
+@property (readonly, strong) NSString *bar; // expected-note {{property declared here}}
+@end
+
+@interface MyClass ()
+@property (readwrite) NSString *foo; // expected-warning {{type of property 'NSString *' in continuation class does not match property type in primary class}}
+@property (readwrite, strong) NSRect bar; // expected-warning {{type of property 'NSRect' in continuation class does not match property type in primary class}}
+@end
diff --git a/test/SemaObjC/crash-label.m b/test/SemaObjC/crash-label.m
index 405d6bfd49e4..b0ca5b508ca4 100644
--- a/test/SemaObjC/crash-label.m
+++ b/test/SemaObjC/crash-label.m
@@ -1,10 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
- - (NSDictionary*) _executeScript:(NSString *)source { // expected-error 2 {{expected a type}} \
- // expected-error {{missing context for method declaration}}
-Exit: [nilArgs release]; // expected-error {{use of undeclared identifier}}
+ - (NSDictionary*) _executeScript:(NSString *)source { // expected-error 2 {{expected a type}} \
+ // expected-error {{missing context for method declaration}}
+Exit: [nilArgs release];
}
- (NSDictionary *) _setupKernelStandardMode:(NSString *)source { // expected-error 2 {{expected a type}} \
-expected-error {{missing context for method declaration}} \
-expected-note{{to match this '{'}}
- Exit: if(_ciKernel && !success ) { // expected-error {{use of undeclared identifier}} // expected-error 2 {{expected}} expected-note{{to match this '{'}} expected-error{{use of undeclared identifier 'success'}}
+ // expected-error {{missing context for method declaration}}
+ Exit: if(_ciKernel && !success ) {
diff --git a/test/SemaObjC/default-synthesize-1.m b/test/SemaObjC/default-synthesize-1.m
index a55834dd3016..1e763af62c0a 100644
--- a/test/SemaObjC/default-synthesize-1.m
+++ b/test/SemaObjC/default-synthesize-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify %s
@interface NSObject
- (void) release;
@@ -25,12 +25,12 @@
//@synthesize howMany, what;
- (int) howMany {
- return howMany;
+ return _howMany;
}
// - (void) setHowMany: (int) value
- (NSString*) what {
- return what;
+ return _what;
}
// - (void) setWhat: (NSString*) value
@end
@@ -46,14 +46,14 @@
// - (int) howMany
- (void) setHowMany: (int) value {
- howMany = value;
+ _howMany = value;
}
// - (NSString*) what
- (void) setWhat: (NSString*) value {
- if (what != value) {
- [what release];
- what = [value retain];
+ if (_what != value) {
+ [_what release];
+ _what = [value retain];
}
}
@end
@@ -68,19 +68,19 @@
//@synthesize howMany, what; // REM: Redundant anyway
- (int) howMany {
- return howMany;
+ return howMany; // expected-error {{use of undeclared identifier 'howMany'}}
}
- (void) setHowMany: (int) value {
- howMany = value;
+ howMany = value; // expected-error {{use of undeclared identifier 'howMany'}}
}
- (NSString*) what {
- return what;
+ return what; // expected-error {{use of undeclared identifier 'what'}}
}
- (void) setWhat: (NSString*) value {
- if (what != value) {
- [what release];
- what = [value retain];
+ if (what != value) { // expected-error {{use of undeclared identifier 'what'}}
+ [what release]; // expected-error {{use of undeclared identifier 'what'}}
+ what = [value retain]; // expected-error {{use of undeclared identifier 'what'}}
}
}
@end
diff --git a/test/SemaObjC/default-synthesize-2.m b/test/SemaObjC/default-synthesize-2.m
new file mode 100644
index 000000000000..1ea492ef5795
--- /dev/null
+++ b/test/SemaObjC/default-synthesize-2.m
@@ -0,0 +1,116 @@
+// RUN: %clang_cc1 -x objective-c -fsyntax-only -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -fobjc-default-synthesize-properties -verify %s
+// rdar://8843851
+
+@interface StopAccessingIvarsDirectlyExample
+@property(strong) id name, rank, serialNumber;
+@end
+
+@implementation StopAccessingIvarsDirectlyExample
+
+- (void)identifyYourSelf {
+ if (self.name && self.rank && self.serialNumber)
+ self.name = 0;
+}
+
+// @synthesize name, rank, serialNumber;
+// default synthesis allows direct access to property ivars.
+- (id)init {
+ _name = _rank = _serialNumber = 0;
+ return self;
+}
+
+- (void)dealloc {
+}
+@end
+
+
+// Test2
+@interface Test2
+@property(strong, nonatomic) id object;
+@end
+
+// object has user declared setter/getter so it won't be
+// default synthesized; thus causing user error.
+@implementation Test2
+- (id) bar { return object; } // expected-error {{use of undeclared identifier 'object'}}
+- (void)setObject:(id)newObject {}
+- (id)object { return 0; }
+@end
+
+// Test3
+@interface Test3
+{
+ id uid;
+}
+@property (readwrite, assign) id uid;
+@end
+
+@implementation Test3
+// Oops, forgot to write @synthesize! will be default synthesized
+- (void) myMethod {
+ self.uid = 0; // Use of the “setterâ€
+ uid = 0; // Use of the wrong instance variable
+ _uid = 0; // Use of the property instance variable
+}
+@end
+
+@interface Test4 {
+ id _var;
+}
+@property (readwrite, assign) id var;
+@end
+
+
+// default synthesize property named 'var'
+@implementation Test4
+- (id) myMethod {
+ return self->_var; // compiles because 'var' is synthesized by default
+}
+@end
+
+@interface Test5
+{
+ id _var;
+}
+@property (readwrite, assign) id var;
+@end
+
+// default synthesis of property 'var'
+@implementation Test5
+- (id) myMethod {
+ Test5 *foo = 0;
+ return foo->_var; // OK
+}
+@end
+
+@interface Test6
+{
+ id _var; // expected-note {{'_var' declared here}}
+}
+@property (readwrite, assign) id var;
+@end
+
+// no default synthesis. So error is expected.
+@implementation Test6
+- (id) myMethod
+{
+ return var; // expected-error {{use of undeclared identifier 'var'}}
+}
+@synthesize var = _var;
+@end
+
+int* _object;
+
+@interface Test7
+@property (readwrite, assign) id object;
+@end
+
+// With default synthesis, '_object' is be the synthesized ivar not the global
+// 'int*' object. So no error.
+@implementation Test7
+- (id) myMethod {
+ return _object;
+}
+@end
+
diff --git a/test/SemaObjC/default-synthesize.m b/test/SemaObjC/default-synthesize.m
index 33e3bd6f3464..0d2f47339900 100644
--- a/test/SemaObjC/default-synthesize.m
+++ b/test/SemaObjC/default-synthesize.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify %s
@interface NSString @end
@@ -97,10 +97,10 @@
// rdar://7920807
@interface C @end
@interface C (Category)
-@property int p; // expected-warning {{property 'p' requires method 'p' to be defined }} \
- // expected-warning {{property 'p' requires method 'setP:' to be defined}}
+@property int p; // expected-note 2 {{property declared here}}
@end
-@implementation C (Category) // expected-note 2 {{implementation is here}}
+@implementation C (Category) // expected-warning {{property 'p' requires method 'p' to be defined}} \
+ // expected-warning {{property 'p' requires method 'setP:' to be defined}}
@end
// Don't complain if a property is already @synthesized by usr.
diff --git a/test/SemaObjC/deref-interface.m b/test/SemaObjC/deref-interface.m
index 255e1d079814..490e3a565d2e 100644
--- a/test/SemaObjC/deref-interface.m
+++ b/test/SemaObjC/deref-interface.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -verify -fsyntax-only %s
+// RUN: %clang_cc1 -verify -fsyntax-only %s
@interface NSView
- (id)initWithView:(id)realView;
diff --git a/test/SemaObjC/direct-synthesized-ivar-access.m b/test/SemaObjC/direct-synthesized-ivar-access.m
index a72fb5f19c7a..7e57a29b18ac 100644
--- a/test/SemaObjC/direct-synthesized-ivar-access.m
+++ b/test/SemaObjC/direct-synthesized-ivar-access.m
@@ -1,14 +1,15 @@
-// RUN: %clang_cc1 -Wnonfragile-abi2 -fsyntax-only -fobjc-nonfragile-abi -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -Wnonfragile-abi2 -fsyntax-only -fobjc-default-synthesize-properties -verify %s
// rdar://8673791
+// rdar://9943851
@interface I {
}
-@property int IVAR; // expected-note {{property declared here}}
+@property int IVAR;
- (int) OK;
@end
@implementation I
-- (int) Meth { return IVAR; } // expected-warning {{direct access of synthesized ivar by using property access 'IVAR'}}
+- (int) Meth { return _IVAR; }
- (int) OK { return self.IVAR; }
@end
diff --git a/test/SemaObjC/duplicate-ivar-in-class-extension.m b/test/SemaObjC/duplicate-ivar-in-class-extension.m
index 0507b352f602..9b9d58cc671d 100644
--- a/test/SemaObjC/duplicate-ivar-in-class-extension.m
+++ b/test/SemaObjC/duplicate-ivar-in-class-extension.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
@interface Root @end
diff --git a/test/SemaObjC/enum-fixed-type.m b/test/SemaObjC/enum-fixed-type.m
new file mode 100644
index 000000000000..530ee0fe9995
--- /dev/null
+++ b/test/SemaObjC/enum-fixed-type.m
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#if !__has_feature(objc_fixed_enum)
+# error Enumerations with a fixed underlying type are not supported
+#endif
+
+typedef long Integer;
+
+typedef enum : Integer { Enumerator1, Enumerator2 } Enumeration;
+
+int array[sizeof(Enumeration) == sizeof(long)? 1 : -1];
+
+
+enum Color { Red, Green, Blue };
+
+struct X {
+ enum Color : 4;
+ enum Color field1: 4;
+ enum Other : Integer field2;
+ enum Other : Integer field3 : 4;
+ enum : Integer { Blah, Blarg } field4 : 4;
+};
+
+void test() {
+ long value = 2;
+ Enumeration e = value;
+}
diff --git a/test/SemaObjC/error-property-gc-attr.m b/test/SemaObjC/error-property-gc-attr.m
index 829c08228747..25fee051174b 100644
--- a/test/SemaObjC/error-property-gc-attr.m
+++ b/test/SemaObjC/error-property-gc-attr.m
@@ -3,7 +3,7 @@
@interface INTF
{
- id IVAR;
+ id IVAR; // expected-note {{ivar is declared here}}
__weak id II;
__weak id WID;
id ID;
diff --git a/test/SemaObjC/iboutletcollection-attr.m b/test/SemaObjC/iboutletcollection-attr.m
index 5c82c8308a43..6bfe31389546 100644
--- a/test/SemaObjC/iboutletcollection-attr.m
+++ b/test/SemaObjC/iboutletcollection-attr.m
@@ -19,12 +19,13 @@ typedef void *PV;
__attribute__((iboutletcollection(I, 1))) id ivar1; // expected-error {{attribute takes one argument}}
__attribute__((iboutletcollection(B))) id ivar2; // expected-error {{invalid type 'B' as argument of iboutletcollection attribute}}
__attribute__((iboutletcollection(PV))) id ivar3; // expected-error {{invalid type 'PV' as argument of iboutletcollection attribute}}
- __attribute__((iboutletcollection(PV))) void *ivar4; // expected-error {{ivar with iboutletcollection attribute must have object type (invalid 'void *')}}
+ __attribute__((iboutletcollection(PV))) void *ivar4; // expected-error {{ivar with 'iboutletcollection' attribute must be an object type (invalid 'void *')}}
__attribute__((iboutletcollection(int))) id ivar5; // expected-error {{type argument of iboutletcollection attribute cannot be a builtin type}}
+ __attribute__((iboutlet)) int ivar6; // expected-error {{ivar with 'iboutlet' attribute must be an object type}}
}
@property (nonatomic, retain) __attribute__((iboutletcollection(I,2,3))) id prop1; // expected-error {{attribute takes one argument}}
@property (nonatomic, retain) __attribute__((iboutletcollection(B))) id prop2; // expected-error {{invalid type 'B' as argument of iboutletcollection attribute}}
-@property __attribute__((iboutletcollection(BAD))) int prop3; // expected-error {{property with iboutletcollection attribute must have object type (invalid 'int')}}
+@property __attribute__((iboutletcollection(BAD))) int prop3; // expected-error {{property with 'iboutletcollection' attribute must be an object type (invalid 'int')}}
@end
diff --git a/test/SemaObjC/id-isa-ref.m b/test/SemaObjC/id-isa-ref.m
index a75f2f336751..dfc0a5b9fdac 100644
--- a/test/SemaObjC/id-isa-ref.m
+++ b/test/SemaObjC/id-isa-ref.m
@@ -22,7 +22,7 @@ static void func() {
Whatever *y;
// GCC allows this, with the following warning:
- // instance variable ‘isa’ is @protected; this will be a hard error in the future
+ // 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.
[(*y).isa self]; // expected-error {{instance variable 'isa' is protected}} \
diff --git a/test/SemaObjC/incomplete-implementation.m b/test/SemaObjC/incomplete-implementation.m
index 612c331ae8c2..f5c5a7cc1813 100644
--- a/test/SemaObjC/incomplete-implementation.m
+++ b/test/SemaObjC/incomplete-implementation.m
@@ -1,26 +1,27 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
@interface I
-- Meth; // expected-note{{method definition for 'Meth' not found}}
+- Meth; // expected-note{{method definition for 'Meth' not found}} \
+ // expected-note{{method declared here}}
@end
@implementation I // expected-warning{{incomplete implementation}}
@end
@implementation I(CAT)
-- Meth {return 0;}
+- Meth {return 0;} // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
@end
#pragma GCC diagnostic ignored "-Wincomplete-implementation"
@interface I2
-- Meth;
+- Meth; // expected-note{{method declared here}}
@end
@implementation I2
@end
@implementation I2(CAT)
-- Meth {return 0;}
+- Meth {return 0;} // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
@end
diff --git a/test/SemaObjC/instancetype.m b/test/SemaObjC/instancetype.m
new file mode 100644
index 000000000000..13d6e0309f82
--- /dev/null
+++ b/test/SemaObjC/instancetype.m
@@ -0,0 +1,190 @@
+// 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;
+- (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; // 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
+
+- (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 {
+ Subclass1 *sc1 = [[Subclass1 alloc] init];
+ 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 returning 'Subclass1 *' from a function with result type 'Subclass2 *'}}
+}
+@end
+
+@interface MyClass : Root
++ (int)myClassMethod;
+@end
+
+@implementation MyClass
++ (int)myClassMethod { return 0; }
+
+- (void)blah {
+ int i = [[MyClass self] myClassMethod];
+}
+
+@end
+
diff --git a/test/SemaObjC/interface-1.m b/test/SemaObjC/interface-1.m
index 91586c9bb34a..87c230742e35 100644
--- a/test/SemaObjC/interface-1.m
+++ b/test/SemaObjC/interface-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 %s -fsyntax-only -verify
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi %s -fsyntax-only -verify
// rdar://5957506
@interface NSWhatever :
diff --git a/test/SemaObjC/interface-layout.m b/test/SemaObjC/interface-layout.m
index 72a7155644a0..a8a93f0a6eb3 100644
--- a/test/SemaObjC/interface-layout.m
+++ b/test/SemaObjC/interface-layout.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -triple i386-apple-darwin9
+// RUN: %clang_cc1 %s -fsyntax-only -verify -triple i386-apple-darwin9 -fobjc-fragile-abi
typedef struct objc_object {} *id;
typedef signed char BOOL;
typedef unsigned int NSUInteger;
diff --git a/test/SemaObjC/ivar-in-class-extension-error.m b/test/SemaObjC/ivar-in-class-extension-error.m
index 23a7491aafb1..cecaa33bcfcc 100644
--- a/test/SemaObjC/ivar-in-class-extension-error.m
+++ b/test/SemaObjC/ivar-in-class-extension-error.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fobjc-fragile-abi -fsyntax-only -verify %s
// rdar://6812436
@interface A @end
diff --git a/test/SemaObjC/ivar-in-class-extension.m b/test/SemaObjC/ivar-in-class-extension.m
index b5772f6a4ca3..c9f138f40752 100644
--- a/test/SemaObjC/ivar-in-class-extension.m
+++ b/test/SemaObjC/ivar-in-class-extension.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
@interface SomeClass @end
diff --git a/test/SemaObjC/ivar-in-implementations.m b/test/SemaObjC/ivar-in-implementations.m
index 74db3224007a..c4cfc10d5e40 100644
--- a/test/SemaObjC/ivar-in-implementations.m
+++ b/test/SemaObjC/ivar-in-implementations.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
@interface Super @end
diff --git a/test/SemaObjC/ivar-sem-check-2.m b/test/SemaObjC/ivar-sem-check-2.m
index 28c795ee7fe1..bf884b3d9d27 100644
--- a/test/SemaObjC/ivar-sem-check-2.m
+++ b/test/SemaObjC/ivar-sem-check-2.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
@interface Super {
id value2; // expected-note {{previously declared 'value2' here}}
diff --git a/test/SemaObjC/method-no-context.m b/test/SemaObjC/method-no-context.m
index 3c45beef0426..c0875493b44b 100644
--- a/test/SemaObjC/method-no-context.m
+++ b/test/SemaObjC/method-no-context.m
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-- im0 { // expected-note{{to match this '{'}} expected-error{{missing context for method declaration}}
+- im0 { // expected-error{{missing context for method declaration}}
int a; return 0;
-// expected-error{{expected '}'}}
diff --git a/test/SemaObjC/missing-atend-metadata.m b/test/SemaObjC/missing-atend-metadata.m
index 434706d3fafc..9b79c52d9629 100644
--- a/test/SemaObjC/missing-atend-metadata.m
+++ b/test/SemaObjC/missing-atend-metadata.m
@@ -10,7 +10,7 @@
@end
@implementation I1 // expected-error {{'@end' is missing in implementation context}}
--(void) im0 { self = [super init]; } // expected-warning {{nstance method '-init' not found }}
+-(void) im0 { self = [super init]; }
@interface I2 : I0
- I2meth;
diff --git a/test/SemaObjC/missing-method-return-type.m b/test/SemaObjC/missing-method-return-type.m
new file mode 100644
index 000000000000..b62a0466ad35
--- /dev/null
+++ b/test/SemaObjC/missing-method-return-type.m
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -Wmissing-method-return-type -fsyntax-only -verify %s
+// rdar://9615045
+
+@interface I
+- initWithFoo:(id)foo; // expected-warning {{method has no return type specified; defaults to 'id' [-Wmissing-method-return-type]}}
+@end
+
+@implementation I
+- initWithFoo:(id)foo { return 0; } // expected-warning {{method has no return type specified; defaults to 'id' [-Wmissing-method-return-type]}}
+@end
+
diff --git a/test/SemaObjC/nested-typedef-decl.m b/test/SemaObjC/nested-typedef-decl.m
new file mode 100644
index 000000000000..70ca3a12cc0f
--- /dev/null
+++ b/test/SemaObjC/nested-typedef-decl.m
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -x objective-c -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify %s
+// rdar://10041908
+
+@interface Bar {
+ struct _A *_hardlinkList;
+}
+@end
+@implementation Bar
+typedef struct _A {
+ int dev;
+ int inode;
+} A;
+
+- (void) idx:(int)idx ino:(int)ino dev:(int)dev
+{
+ _hardlinkList[idx].inode = ino;
+ _hardlinkList[idx].dev = dev;
+}
+@end
+
diff --git a/test/SemaObjC/objc-buffered-methods.m b/test/SemaObjC/objc-buffered-methods.m
new file mode 100644
index 000000000000..78912aed8605
--- /dev/null
+++ b/test/SemaObjC/objc-buffered-methods.m
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://8843851
+
+int* global;
+
+@interface I
+- (void) Meth;
+@property int prop;
+@property int prop1;
+@end
+
+@implementation I
++ (void) _defaultMinSize { };
+static void _initCommon() {
+ Class graphicClass;
+ [graphicClass _defaultMinSize];
+}
+
+- (void) Meth { [self Forw]; } // No warning now
+- (void) Forw {}
+- (int) func { return prop; } // compiles - synthesized ivar will be accessible here.
+- (int)get_g { return global; } // No warning here - synthesized ivar will be accessible here.
+@synthesize prop;
+@synthesize prop1=global;
+@end
diff --git a/test/SemaObjC/property-and-class-extension.m b/test/SemaObjC/property-and-class-extension.m
index 926538af61c9..7040078416cd 100644
--- a/test/SemaObjC/property-and-class-extension.m
+++ b/test/SemaObjC/property-and-class-extension.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
/**
When processing @synthesize, treat ivars in a class extension the same as ivars in the class @interface,
diff --git a/test/SemaObjC/property-and-ivar-use.m b/test/SemaObjC/property-and-ivar-use.m
index 70e553469907..12874e7d201e 100644
--- a/test/SemaObjC/property-and-ivar-use.m
+++ b/test/SemaObjC/property-and-ivar-use.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
// Do not issue error if 'ivar' used previously belongs to the inherited class
// and has same name as @dynalic property in current class.
diff --git a/test/SemaObjC/property-category-1.m b/test/SemaObjC/property-category-1.m
index 26e73136d01f..6382826080fb 100644
--- a/test/SemaObjC/property-category-1.m
+++ b/test/SemaObjC/property-category-1.m
@@ -37,7 +37,7 @@ int main(int argc, char **argv) {
///
@interface I0
-@property(readonly) int p0; // expected-warning {{property 'p0' requires method 'p0' to be defined}}
+@property(readonly) int p0; // expected-note {{property declared here}}
@end
@interface I0 (Cat0)
@@ -46,7 +46,7 @@ int main(int argc, char **argv) {
@interface I0 (Cat1)
@end
-@implementation I0 // expected-note {{implementation is here}}
+@implementation I0 // expected-warning {{property 'p0' requires method 'p0' to be define}}
- (void) foo {
self.p0 = 0; // expected-error {{assigning to property with 'readonly' attribute not allowed}}
}
diff --git a/test/SemaObjC/property-category-2.m b/test/SemaObjC/property-category-2.m
index e63672bb0ad7..ecc368162bfa 100644
--- a/test/SemaObjC/property-category-2.m
+++ b/test/SemaObjC/property-category-2.m
@@ -4,8 +4,7 @@
@protocol MyProtocol
@property float myFloat;
-@property float anotherFloat; // expected-warning {{property 'anotherFloat' requires method 'anotherFloat' to be defined - use @dynamic}} \
- // expected-warning {{property 'anotherFloat' requires method 'setAnotherFloat:' to be defined }}
+@property float anotherFloat; // expected-note 2 {{property declared}}
@end
@interface MyObject { float anotherFloat; }
@@ -14,7 +13,8 @@
@interface MyObject (CAT) <MyProtocol>
@end
-@implementation MyObject (CAT) // expected-note 2 {{implementation is here}}
+@implementation MyObject (CAT) // expected-warning {{property 'anotherFloat' requires method}} \
+ // expected-warning {{property 'anotherFloat' requires method 'setAnotherFloat:'}}
@dynamic myFloat; // OK
@synthesize anotherFloat; // expected-error {{@synthesize not allowed in a category's implementation}}
@end
diff --git a/test/SemaObjC/property-category-3.m b/test/SemaObjC/property-category-3.m
index 237de0f1f5fb..2a61d9272477 100644
--- a/test/SemaObjC/property-category-3.m
+++ b/test/SemaObjC/property-category-3.m
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
@protocol P
- @property(readonly) int X;
+ @property(readonly) int X; // expected-note {{property declared here}}
@end
@protocol P1<P>
diff --git a/test/SemaObjC/property-category-impl.m b/test/SemaObjC/property-category-impl.m
index 997949778c6e..21fdf1b6d4be 100644
--- a/test/SemaObjC/property-category-impl.m
+++ b/test/SemaObjC/property-category-impl.m
@@ -24,8 +24,8 @@
@end
@interface MyClass (public)
-@property(readwrite) int foo; // expected-warning {{property 'foo' requires method 'setFoo:' to be defined }}
+@property(readwrite) int foo; // expected-note {{property declared here}}
@end
-@implementation MyClass (public)// expected-note {{implementation is here}}
+@implementation MyClass (public)// expected-warning {{property 'foo' requires method 'setFoo:' to be defined }}
@end
diff --git a/test/SemaObjC/property-inherited.m b/test/SemaObjC/property-inherited.m
index 11ef2befa99b..f5f1b420c229 100644
--- a/test/SemaObjC/property-inherited.m
+++ b/test/SemaObjC/property-inherited.m
@@ -21,7 +21,7 @@
id _delegate;
}
@property(nonatomic, assign) id<FooDelegate> delegate;
-@property(nonatomic, assign) id<BarDelegate> delegate2;
+@property(nonatomic, assign) id<BarDelegate> delegate2; // expected-note {{property declared here}}
@end
@interface Bar : Foo {
}
@@ -36,7 +36,7 @@
@interface Base : NSData
@property(assign) id ref;
@property(assign) Base *p_base;
-@property(assign) NSMutableData *p_data;
+@property(assign) NSMutableData *p_data; // expected-note {{property declared here}}
@end
@interface Data : Base
diff --git a/test/SemaObjC/property-nonfragile-abi.m b/test/SemaObjC/property-nonfragile-abi.m
index ae82cb7d9295..55bf91f383d4 100644
--- a/test/SemaObjC/property-nonfragile-abi.m
+++ b/test/SemaObjC/property-nonfragile-abi.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
typedef signed char BOOL;
diff --git a/test/SemaObjC/property-ns-returns-not-retained-attr.m b/test/SemaObjC/property-ns-returns-not-retained-attr.m
index 187c93f3d3af..a209da884ed7 100644
--- a/test/SemaObjC/property-ns-returns-not-retained-attr.m
+++ b/test/SemaObjC/property-ns-returns-not-retained-attr.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -verify %s
// rdar://9636091
@interface I
diff --git a/test/SemaObjC/property.m b/test/SemaObjC/property.m
index 4d00bd2b522d..7d1cb7a36160 100644
--- a/test/SemaObjC/property.m
+++ b/test/SemaObjC/property.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -fsyntax-only -verify %s
@interface I
{
@@ -11,8 +11,7 @@
@end
@interface I(CAT)
-@property int d1; // expected-warning {{property 'd1' requires method 'd1' to be defined }} \
- // expected-warning {{property 'd1' requires method 'setD1:' to be defined }}
+@property int d1; // expected-note 2 {{property declared here}}
@end
@implementation I
@@ -23,7 +22,8 @@
@synthesize name; // OK! property with same name as an accessible ivar of same name
@end
-@implementation I(CAT) // expected-note 2 {{implementation is here}}
+@implementation I(CAT) // expected-warning {{property 'd1' requires method 'd1' to be defined }} \
+ // expected-warning {{property 'd1' requires method 'setD1:' to be defined }}
@synthesize d1; // expected-error {{@synthesize not allowed in a category's implementation}}
@dynamic bad; // expected-error {{property implementation must have its declaration in the category 'CAT'}}
@end
@@ -63,3 +63,5 @@ typedef id BYObjectIdentifier;
@property int treeController; // expected-error {{property has a previous declaration}}
@end
+// rdar://10127639
+@synthesize window; // expected-error {{missing context for property implementation declaration}}
diff --git a/test/SemaObjC/protocol-archane.m b/test/SemaObjC/protocol-archane.m
index 138c43d1a83a..992d3e4798c1 100644
--- a/test/SemaObjC/protocol-archane.m
+++ b/test/SemaObjC/protocol-archane.m
@@ -33,3 +33,10 @@ typedef struct objc_class *Class;
Class <SomeProtocol> UnfortunateGCCExtension;
+// rdar://10238337
+@protocol Broken @end
+@interface Crash @end
+@implementation Crash
+- (void)crashWith:(<Broken>)a { // expected-warning {{protocol qualifiers without 'id' is archaic}}
+}
+@end
diff --git a/test/SemaObjC/protocol-implementing-class-methods.m b/test/SemaObjC/protocol-implementing-class-methods.m
new file mode 100644
index 000000000000..f08a5a97d8b7
--- /dev/null
+++ b/test/SemaObjC/protocol-implementing-class-methods.m
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://7020493
+
+@protocol P1
+@optional
+- (int) PMeth;
+@required
+- (void) : (double) arg; // expected-note {{method declared here}}
+@end
+
+@interface NSImage <P1>
+- (void) initialize; // expected-note {{method declared here}}
+@end
+
+@interface NSImage (AirPortUI)
+- (void) initialize;
+@end
+
+@interface NSImage()
+- (void) CEMeth; // expected-note {{method declared here}}
+@end
+
+@implementation NSImage (AirPortUI)
+- (void) initialize {NSImage *p=0; [p initialize]; } // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
+- (int) PMeth{ return 0; }
+- (void) : (double) arg{}; // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
+- (void) CEMeth {}; // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
+@end
+
+// rdar://10014946
+typedef char BOOL;
+@interface I
+{
+ BOOL allowsDeleting;
+}
+@property (nonatomic, assign, readwrite) BOOL allowsDeleting;
+@end
+
+@implementation I(CAT)
+- (BOOL) allowsDeleting { return 1; }
+@end
diff --git a/test/SemaObjC/provisional-ivar-lookup.m b/test/SemaObjC/provisional-ivar-lookup.m
index 04d6a4193095..007c21b726a5 100644
--- a/test/SemaObjC/provisional-ivar-lookup.m
+++ b/test/SemaObjC/provisional-ivar-lookup.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -fobjc-nonfragile-abi -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify %s
// rdar:// 8565343
@interface Foo {
diff --git a/test/SemaObjC/qualified-protocol-method-conflicts.m b/test/SemaObjC/qualified-protocol-method-conflicts.m
new file mode 100644
index 000000000000..0cff3ff46841
--- /dev/null
+++ b/test/SemaObjC/qualified-protocol-method-conflicts.m
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -Woverriding-method-mismatch -fsyntax-only -verify %s
+// rdar://6191214
+
+@protocol Xint
+-(void) setX: (int) arg0; // expected-note {{previous declaration is here}}
++(int) C; // expected-note {{previous declaration is here}}
+@end
+
+@protocol Xfloat
+-(void) setX: (float) arg0; // expected-note 2 {{previous declaration is here}}
++(float) C; // expected-note 2 {{previous declaration is here}}
+@end
+
+@interface A <Xint, Xfloat>
+@end
+
+@implementation A
+-(void) setX: (int) arg0 { } // expected-warning {{conflicting parameter types in declaration of 'setX:': 'float' vs 'int'}}
++(int) C {return 0; } // expected-warning {{conflicting return type in declaration of 'C': 'float' vs 'int'}}
+@end
+
+@interface B <Xfloat, Xint>
+@end
+
+@implementation B
+-(void) setX: (float) arg0 { } // expected-warning {{conflicting parameter types in declaration of 'setX:': 'int' vs 'float'}}
++ (float) C {return 0.0; } // expected-warning {{conflicting return type in declaration of 'C': 'int' vs 'float'}}
+@end
+
+@protocol Xint_float<Xint, Xfloat>
+@end
+
+@interface C<Xint_float>
+@end
+
+@implementation C
+-(void) setX: (int) arg0 { } // expected-warning {{conflicting parameter types in declaration of 'setX:': 'float' vs 'int'}}
++ (int) C {return 0;} // expected-warning {{conflicting return type in declaration of 'C': 'float' vs 'int'}}
+@end
diff --git a/test/SemaObjC/related-result-type-inference.m b/test/SemaObjC/related-result-type-inference.m
index 094f19a67129..11b4b9602e14 100644
--- a/test/SemaObjC/related-result-type-inference.m
+++ b/test/SemaObjC/related-result-type-inference.m
@@ -149,8 +149,8 @@ void test_inference() {
@end
// <rdar://problem/9340699>
-@interface G
-- (id)_ABC_init __attribute__((objc_method_family(init)));
+@interface G
+- (id)_ABC_init __attribute__((objc_method_family(init))); // expected-note {{method declared here}}
@end
@interface G (Additions)
@@ -158,7 +158,7 @@ void test_inference() {
@end
@implementation G (Additions)
-- (id)_ABC_init {
+- (id)_ABC_init { // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
return 0;
}
- (id)_ABC_init2 {
diff --git a/test/SemaObjC/return.m b/test/SemaObjC/return.m
index 3a626e369603..4e70bde1edc1 100644
--- a/test/SemaObjC/return.m
+++ b/test/SemaObjC/return.m
@@ -14,7 +14,7 @@ void test2(int a) {
}
// PR5286
-void test3(int a) { // expected-warning {{function could be attribute 'noreturn'}}
+void test3(int a) { // expected-warning {{function 'test3' could be declared with attribute 'noreturn'}}
while (1) {
if (a)
@throw (id)0;
@@ -39,3 +39,12 @@ NSString *rdar_4289832() { // no-warning
}
}
+void exit(int) __attribute__((noreturn));
+@interface rdar10098695
+@end
+
+@implementation rdar10098695
+- (void)method { // expected-warning{{method 'method' could be declared with attribute 'noreturn'}}
+ exit(1);
+}
+@end
diff --git a/test/SemaObjC/self-declared-in-block.m b/test/SemaObjC/self-declared-in-block.m
index 21310953c2c5..25ce8ba59933 100644
--- a/test/SemaObjC/self-declared-in-block.m
+++ b/test/SemaObjC/self-declared-in-block.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -fblocks -fobjc-nonfragile-abi -verify %s
-// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -triple x86_64-apple-darwin10 -fblocks -fobjc-nonfragile-abi -verify %s
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -fblocks -verify %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -triple x86_64-apple-darwin10 -fblocks -verify %s
// rdar://9154582
@interface Blocky @end
diff --git a/test/SemaObjC/sizeof-interface.m b/test/SemaObjC/sizeof-interface.m
index 65c8e49e0b87..43870a17a30f 100644
--- a/test/SemaObjC/sizeof-interface.m
+++ b/test/SemaObjC/sizeof-interface.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -verify -fsyntax-only %s
+// RUN: %clang_cc1 -verify -fsyntax-only %s
@class I0;
diff --git a/test/SemaObjC/super-class-protocol-conformance.m b/test/SemaObjC/super-class-protocol-conformance.m
index bf19c837f46a..32d5392ad4e0 100644
--- a/test/SemaObjC/super-class-protocol-conformance.m
+++ b/test/SemaObjC/super-class-protocol-conformance.m
@@ -4,7 +4,7 @@
@interface NSObject @end
@protocol TopProtocol
- @property (readonly) id myString; // expected-warning {{property 'myString' requires method 'myString' to be defined}}
+ @property (readonly) id myString; // expected-note {{property}}
@end
@protocol SubProtocol <TopProtocol>
@@ -21,7 +21,7 @@
@implementation SubClass1 @end // Test1 - No Warning
-@implementation TopClass // expected-note {{implementation is here}}
+@implementation TopClass // expected-warning {{property 'myString' requires method 'myString' to be defined}}
@end
@implementation SubClass // Test3 - No Warning
@@ -39,11 +39,11 @@
@implementation SubClass4 @end // Test 5 - No Warning
@protocol NewProtocol
- @property (readonly) id myNewString; // expected-warning {{property 'myNewString' requires method 'myNewString' to be defined}}
+ @property (readonly) id myNewString; // expected-note {{property}}
@end
@interface SubClass5 : SubClass4 <NewProtocol> @end
-@implementation SubClass5 @end // expected-note {{implementation is here}}
+@implementation SubClass5 @end // expected-warning {{property 'myNewString' requires method 'myNewString' to be defined}}
// Radar 8035776
@@ -54,10 +54,10 @@
@end
@protocol ProtocolWithProperty <SuperProtocol>
-@property (readonly, assign) id invalidationBacktrace; // expected-warning {{property 'invalidationBacktrace' requires method 'invalidationBacktrace' to be defined}}
+@property (readonly, assign) id invalidationBacktrace; // expected-note {{property}}
@end
@interface INTF : Super <ProtocolWithProperty>
@end
-@implementation INTF @end // expected-note {{implementation is here}}
+@implementation INTF @end // expected-warning{{property 'invalidationBacktrace' requires method 'invalidationBacktrace' to be defined}}
diff --git a/test/SemaObjC/synth-provisional-ivars-1.m b/test/SemaObjC/synth-provisional-ivars-1.m
index 33de173cc14b..8bf687811fd2 100644
--- a/test/SemaObjC/synth-provisional-ivars-1.m
+++ b/test/SemaObjC/synth-provisional-ivars-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify %s
// rdar://8913053
typedef unsigned char BOOL;
diff --git a/test/SemaObjC/synth-provisional-ivars.m b/test/SemaObjC/synth-provisional-ivars.m
index e8179aaa00dd..696eb9b38558 100644
--- a/test/SemaObjC/synth-provisional-ivars.m
+++ b/test/SemaObjC/synth-provisional-ivars.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify %s
int bar;
@@ -18,7 +18,7 @@ int bar;
@end
@implementation I
-- (int) Meth { return PROP; } // expected-note 2{{'PROP' declared here}}
+- (int) Meth { return _PROP; }
@dynamic PROP1;
- (int) Meth1 { return PROP1; } // expected-error {{use of undeclared identifier 'PROP1'}}
@@ -30,12 +30,12 @@ int bar;
@synthesize PROP3=IVAR;
- (int) Meth4 { return PROP4; }
-@synthesize PROP4=PROP4;
+@synthesize PROP4=PROP4; // expected-note 4 {{'PROP4' declared here}}
-- (int) Meth5 { return bar; } // expected-error {{use of undeclared identifier 'bar'}}
+- (int) Meth5 { return bar; }
@synthesize bar = _bar;
-- (int) Meth6 { return bar1; }
+- (int) Meth6 { return _bar1; }
@end
@@ -45,6 +45,6 @@ int bar;
@implementation I(r8251648)
- (int) Meth1: (int) bar {
- return bar; // expected-warning {{local declaration of 'bar' hides instance variable}}
+ return bar;
}
@end
diff --git a/test/SemaObjC/synthesized-ivar.m b/test/SemaObjC/synthesized-ivar.m
index 4786d808fa2f..745fe77449ac 100644
--- a/test/SemaObjC/synthesized-ivar.m
+++ b/test/SemaObjC/synthesized-ivar.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify %s
@interface I
{
}
@@ -31,8 +31,8 @@ int f0(I *a) { return a->IP; } // expected-error {{instance variable 'IP' is pri
@implementation I1
- (int) Meth {
- PROP_INMAIN = 1;
- PROP_INCLASSEXT = 2;
+ _PROP_INMAIN = 1;
+ _PROP_INCLASSEXT = 2;
protected_ivar = 1; // OK
return private_ivar; // OK
}
@@ -45,8 +45,8 @@ int f0(I *a) { return a->IP; } // expected-error {{instance variable 'IP' is pri
@implementation DER
- (int) Meth {
protected_ivar = 1; // OK
- PROP_INMAIN = 1; // expected-error {{instance variable 'PROP_INMAIN' is private}}
- PROP_INCLASSEXT = 2; // expected-error {{instance variable 'PROP_INCLASSEXT' is private}}
+ _PROP_INMAIN = 1; // expected-error {{instance variable '_PROP_INMAIN' is private}}
+ _PROP_INCLASSEXT = 2; // expected-error {{instance variable '_PROP_INCLASSEXT' is private}}
return private_ivar; // expected-error {{instance variable 'private_ivar' is private}}
}
@end
diff --git a/test/SemaObjC/undeclared-selector.m b/test/SemaObjC/undeclared-selector.m
index 758e1d7f5602..af52fde8806e 100644
--- a/test/SemaObjC/undeclared-selector.m
+++ b/test/SemaObjC/undeclared-selector.m
@@ -18,7 +18,7 @@ typedef struct objc_selector *SEL;
+ (void) methodD
{
SEL d = @selector(methodD); /* Ok */
- SEL e = @selector(methodE); // expected-warning {{undeclared selector 'methodE'}}
+ SEL e = @selector(methodE);
}
- (void) methodE
diff --git a/test/SemaObjC/unimplemented-protocol-prop.m b/test/SemaObjC/unimplemented-protocol-prop.m
index d3de50efea58..fa3ed8ef121c 100644
--- a/test/SemaObjC/unimplemented-protocol-prop.m
+++ b/test/SemaObjC/unimplemented-protocol-prop.m
@@ -2,14 +2,12 @@
@protocol PROTOCOL0
@required
-@property float MyProperty0; // expected-warning {{property 'MyProperty0' requires method 'MyProperty0' to be defined }} \
- // expected-warning {{property 'MyProperty0' requires method 'setMyProperty0:' to be defined}}
+@property float MyProperty0; // expected-note 2 {{property declared}}
@end
@protocol PROTOCOL<PROTOCOL0>
@required
-@property float MyProperty; // expected-warning {{property 'MyProperty' requires method 'MyProperty' to be defined}} \
- // expected-warning {{property 'MyProperty' requires method 'setMyProperty:' to be defined}}
+@property float MyProperty; // expected-note 2 {{property declared}}
@optional
@property float OptMyProperty;
@end
@@ -17,4 +15,25 @@
@interface I <PROTOCOL>
@end
-@implementation I @end // expected-note 4 {{implementation is here}}
+@implementation I @end // expected-warning {{property 'MyProperty0' requires method 'MyProperty0' to be defined}} \
+ // expected-warning {{property 'MyProperty0' requires method 'setMyProperty0:' to be defined}}\
+ // expected-warning {{property 'MyProperty' requires method 'MyProperty' to be defined}} \
+ // expected-warning {{property 'MyProperty' requires method 'setMyProperty:' to be defined}}
+
+// rdar://10120691
+// property is implemented in super class. No warning
+
+@protocol PROTOCOL1
+@property int MyProp;
+@end
+
+@interface superclass
+@property int MyProp;
+@end
+
+@interface childclass : superclass <PROTOCOL1>
+@end
+
+@implementation childclass
+@end
+
diff --git a/test/SemaObjC/uninit-variables.m b/test/SemaObjC/uninit-variables.m
index b5c49184f4bc..cad0f54b2dd3 100644
--- a/test/SemaObjC/uninit-variables.m
+++ b/test/SemaObjC/uninit-variables.m
@@ -3,7 +3,7 @@
// Duplicated from uninit-variables.c.
// Test just to ensure the analysis is working.
int test1() {
- int x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization}}
+ int x; // expected-note{{initialize the variable 'x' to silence this warning}}
return x; // expected-warning{{variable 'x' is uninitialized when used here}}
}
diff --git a/test/SemaObjC/warn-deprecated-implementations.m b/test/SemaObjC/warn-deprecated-implementations.m
index 7bcd10cc3e06..60da7b0c41dc 100644
--- a/test/SemaObjC/warn-deprecated-implementations.m
+++ b/test/SemaObjC/warn-deprecated-implementations.m
@@ -26,7 +26,8 @@ __attribute__((deprecated))
@implementation CL // expected-warning {{Implementing deprecated class}}
@end
-@implementation CL ( SomeCategory ) // expected-warning {{Implementing deprecated category}}
+@implementation CL ( SomeCategory ) // expected-warning {{'CL' is deprecated}} \
+ // expected-warning {{Implementing deprecated category}}
@end
@interface CL_SUB : CL // expected-warning {{'CL' is deprecated}}
diff --git a/test/SemaObjC/warn-implicit-atomic-property.m b/test/SemaObjC/warn-implicit-atomic-property.m
index 0b4590a42db7..ec8e84e20f0c 100644
--- a/test/SemaObjC/warn-implicit-atomic-property.m
+++ b/test/SemaObjC/warn-implicit-atomic-property.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wimplicit-atomic-properties -fobjc-nonfragile-abi -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wimplicit-atomic-properties -fobjc-default-synthesize-properties -verify %s
// rdar://8774580
@interface Super
diff --git a/test/SemaObjC/warn-missing-super.m b/test/SemaObjC/warn-missing-super.m
new file mode 100644
index 000000000000..0169a6157258
--- /dev/null
+++ b/test/SemaObjC/warn-missing-super.m
@@ -0,0 +1,57 @@
+@protocol NSCopying @end
+
+@interface NSObject <NSCopying>
+- (void)dealloc;
+@end
+
+@implementation NSObject
+- (void)dealloc {
+ // Root class, shouldn't warn
+}
+- (void)finalize {
+ // Root class, shouldn't warn
+}
+@end
+
+@interface Subclass1 : NSObject
+- (void)dealloc;
+- (void)finalize;
+@end
+
+@implementation Subclass1
+- (void)dealloc {
+}
+- (void)finalize {
+}
+@end
+
+@interface Subclass2 : NSObject
+- (void)dealloc;
+- (void)finalize;
+@end
+
+@implementation Subclass2
+- (void)dealloc {
+ [super dealloc]; // Shouldn't warn
+}
+- (void)finalize {
+ [super finalize]; // Shouldn't warn
+}
+@end
+
+// RUN: %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck %s
+// CHECK: warn-missing-super.m:23:1: warning: method possibly missing a [super dealloc] call
+// CHECK: 1 warning generated.
+
+// RUN: %clang_cc1 -fsyntax-only -fobjc-gc %s 2>&1 | FileCheck --check-prefix=CHECK-GC %s
+// CHECK-GC: warn-missing-super.m:23:1: warning: method possibly missing a [super dealloc] call
+// CHECK-GC: warn-missing-super.m:25:1: warning: method possibly missing a [super finalize] call
+// CHECK-GC: 2 warnings generated.
+
+// RUN: %clang_cc1 -fsyntax-only -fobjc-gc-only %s 2>&1 | FileCheck --check-prefix=CHECK-GC-ONLY %s
+// CHECK-GC-ONLY: warn-missing-super.m:25:1: warning: method possibly missing a [super finalize] call
+// CHECK-GC-ONLY: 1 warning generated.
+
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -fobjc-arc %s 2>&1 | FileCheck --check-prefix=CHECK-ARC %s
+// CHECK-ARC: warn-missing-super.m:35:4: error: ARC forbids explicit message send of 'dealloc'
+// CHECK-ARC: 1 error generated.
diff --git a/test/SemaObjC/warn-retain-cycle.m b/test/SemaObjC/warn-retain-cycle.m
index 71385b8400bb..596858f83a3e 100644
--- a/test/SemaObjC/warn-retain-cycle.m
+++ b/test/SemaObjC/warn-retain-cycle.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify %s
@interface Test0
- (void) setBlock: (void(^)(void)) block;
@@ -27,7 +27,7 @@ void test0(Test0 *x) {
}
@interface BlockOwner
-@property (retain) void (^strong)(void);
+@property (retain) void (^strong)(void); // expected-warning {{retain'ed block property does not copy the block - use copy attribute instead}}
@end
@interface Test1 {
diff --git a/test/SemaObjC/weak-property.m b/test/SemaObjC/weak-property.m
index f0006076413d..bea66281ea7b 100644
--- a/test/SemaObjC/weak-property.m
+++ b/test/SemaObjC/weak-property.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fobjc-arc -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -verify %s
// rdar://8899430
@interface WeakPropertyTest {
diff --git a/test/SemaObjCXX/arc-0x.mm b/test/SemaObjCXX/arc-0x.mm
index fa022af522e9..be9f1dc2e28c 100644
--- a/test/SemaObjCXX/arc-0x.mm
+++ b/test/SemaObjCXX/arc-0x.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify -fblocks -fobjc-exceptions %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fobjc-arc -verify -fblocks -fobjc-exceptions %s
// "Move" semantics, trivial version.
void move_it(__strong id &&from) {
diff --git a/test/SemaObjCXX/arc-bool-conversion.mm b/test/SemaObjCXX/arc-bool-conversion.mm
index 86da3ca90cf1..d8f840e871e5 100644
--- a/test/SemaObjCXX/arc-bool-conversion.mm
+++ b/test/SemaObjCXX/arc-bool-conversion.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
// rdar://9310049
bool fn(id obj) {
diff --git a/test/SemaObjCXX/arc-bridged-cast.mm b/test/SemaObjCXX/arc-bridged-cast.mm
index cbbe79eb2744..1ea67a347edd 100644
--- a/test/SemaObjCXX/arc-bridged-cast.mm
+++ b/test/SemaObjCXX/arc-bridged-cast.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -verify %s
typedef const void *CFTypeRef;
typedef const struct __CFString *CFStringRef;
diff --git a/test/SemaObjCXX/arc-libcxx.mm b/test/SemaObjCXX/arc-libcxx.mm
deleted file mode 100644
index 7992f602f51a..000000000000
--- a/test/SemaObjCXX/arc-libcxx.mm
+++ /dev/null
@@ -1,11 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-arc-cxxlib=libc++ -fobjc-nonfragile-abi -fobjc-runtime-has-weak -verify %s
-
-@interface A @end
-
-void f(__strong id &sir, __weak id &wir, __autoreleasing id &air,
- __unsafe_unretained id &uir) {
- __strong id *sip = std::addressof(sir);
- __weak id *wip = std::addressof(wir);
- __autoreleasing id *aip = std::addressof(air);
- __unsafe_unretained id *uip = std::addressof(uir);
-}
diff --git a/test/SemaObjCXX/arc-libstdcxx.mm b/test/SemaObjCXX/arc-libstdcxx.mm
index edb7a9ef486a..71771b4b1375 100644
--- a/test/SemaObjCXX/arc-libstdcxx.mm
+++ b/test/SemaObjCXX/arc-libstdcxx.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-arc-cxxlib=libstdc++ -fobjc-nonfragile-abi -fobjc-runtime-has-weak -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-arc-cxxlib=libstdc++ -fobjc-runtime-has-weak -verify %s
@interface A @end
diff --git a/test/SemaObjCXX/arc-memfunc.mm b/test/SemaObjCXX/arc-memfunc.mm
index 75b94c64e727..274f873fd48a 100644
--- a/test/SemaObjCXX/arc-memfunc.mm
+++ b/test/SemaObjCXX/arc-memfunc.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify -fblocks %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify -fblocks %s
struct X0 {
static id makeObject1() __attribute__((ns_returns_retained));
diff --git a/test/SemaObjCXX/arc-non-pod.mm b/test/SemaObjCXX/arc-non-pod.mm
index 6a47b3d85664..1c5cf7af3a18 100644
--- a/test/SemaObjCXX/arc-non-pod.mm
+++ b/test/SemaObjCXX/arc-non-pod.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -Warc-abi -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -Warc-abi -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
// Classes that have an Objective-C object pointer.
struct HasObjectMember0 { // expected-warning{{'HasObjectMember0' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
diff --git a/test/SemaObjCXX/arc-nsconsumed-errors.mm b/test/SemaObjCXX/arc-nsconsumed-errors.mm
new file mode 100644
index 000000000000..93f5d999675e
--- /dev/null
+++ b/test/SemaObjCXX/arc-nsconsumed-errors.mm
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
+// rdar://10187884
+
+typedef void (^blk)(id, __attribute((ns_consumed)) id);
+typedef void (^blk1)(__attribute((ns_consumed))id, __attribute((ns_consumed)) id);
+blk a = ^void (__attribute((ns_consumed)) id, __attribute((ns_consumed)) id){}; // expected-error {{cannot initialize a variable of type '__strong blk'}}
+
+blk b = ^void (id, __attribute((ns_consumed)) id){};
+
+blk c = ^void (__attribute((ns_consumed)) id, __attribute((ns_consumed)) id){}; // expected-error {{cannot initialize a variable of type '__strong blk'}}
+
+blk d = ^void (id, id) {}; // expected-error {{cannot initialize a variable of type '__strong blk'}}
+
+blk1 a1 = ^void (__attribute((ns_consumed)) id, id){}; // expected-error {{cannot initialize a variable of type '__strong blk1'}}
+
+blk1 b2 = ^void (id, __attribute((ns_consumed)) id){}; // expected-error {{cannot initialize a variable of type '__strong blk1'}}
+
+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'}}
diff --git a/test/SemaObjCXX/arc-object-init-destroy.mm b/test/SemaObjCXX/arc-object-init-destroy.mm
index 196f49371847..e10e3eac9fc7 100644
--- a/test/SemaObjCXX/arc-object-init-destroy.mm
+++ b/test/SemaObjCXX/arc-object-init-destroy.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -Warc-abi -fblocks -triple x86_64-apple-darwin10.0.0 %s
+// RUN: %clang_cc1 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -Warc-abi -fblocks -triple x86_64-apple-darwin10.0.0 %s
typedef __strong id strong_id;
typedef __weak id weak_id;
diff --git a/test/SemaObjCXX/arc-overloading.mm b/test/SemaObjCXX/arc-overloading.mm
index 06b332cec85f..dad5d0f7051f 100644
--- a/test/SemaObjCXX/arc-overloading.mm
+++ b/test/SemaObjCXX/arc-overloading.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -fblocks %s
+// RUN: %clang_cc1 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -fblocks %s
// Simple ownership conversions + diagnostics.
int &f0(id __strong const *); // expected-note{{candidate function not viable: 1st argument ('__weak id *') has __weak ownership, but parameter has __strong ownership}}
@@ -173,3 +173,30 @@ void test_f9() {
const __autoreleasing id& ar3 = unsafe_unretained_a;
const __autoreleasing id& ar4 = weak_a;
}
+
+// rdar://9790531
+void f9790531(void *inClientData); // expected-note {{candidate function not viable: cannot implicitly convert argument of type 'MixerEQGraphTestDelegate *const __strong' to 'void *' for 1st argument under ARC}}
+void f9790531_1(struct S*inClientData); // expected-note {{candidate function not viable}}
+void f9790531_2(char * inClientData); // expected-note {{candidate function not viable}}
+
+@class UIApplication;
+
+@interface MixerEQGraphTestDelegate
+- (void)applicationDidFinishLaunching;
+@end
+
+@implementation MixerEQGraphTestDelegate
+- (void)applicationDidFinishLaunching {
+ f9790531(self); // expected-error {{no matching function for call to 'f9790531'}}
+ f9790531_1(self); // expected-error {{no matching function for call to 'f9790531_1'}}
+ f9790531_2(self); // expected-error {{no matching function for call to 'f9790531_2'}}
+}
+@end
+
+class rdar10142572 {
+ id f() __attribute__((ns_returns_retained));
+ id g(); // expected-note{{previous declaration}}
+};
+
+id rdar10142572::f() { return 0; } // okay: merged down
+id __attribute__((ns_returns_retained)) rdar10142572::g() { return 0; } // expected-error{{function declared with the ns_returns_retained attribute was previously declared without the ns_returns_retained attribute}}
diff --git a/test/SemaObjCXX/arc-system-header.mm b/test/SemaObjCXX/arc-system-header.mm
index cb2b85868ce1..107b5b5a53d2 100644
--- a/test/SemaObjCXX/arc-system-header.mm
+++ b/test/SemaObjCXX/arc-system-header.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-arc -fobjc-nonfragile-abi -isystem %S/Inputs %s -verify
+// RUN: %clang_cc1 -fobjc-arc -isystem %S/Inputs %s -verify
#include <arc-system-header.h>
diff --git a/test/SemaObjCXX/arc-templates.mm b/test/SemaObjCXX/arc-templates.mm
index fa4e0a777642..931b21f5d47a 100644
--- a/test/SemaObjCXX/arc-templates.mm
+++ b/test/SemaObjCXX/arc-templates.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -fblocks %s
+// RUN: %clang_cc1 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -fblocks %s
@interface A
@end
@@ -252,3 +252,17 @@ void test_qual_vs_unqual_a() {
float &fr3 = qual_vs_unqual_ref(*aap);
float &fr4 = qual_vs_unqual_ref(*uap);
}
+
+namespace rdar9828157 {
+ // Template argument deduction involving lifetime qualifiers and
+ // non-lifetime types.
+ class A { };
+
+ template<typename T> float& f(T&);
+ template<typename T> int& f(__strong T&);
+ template<typename T> double& f(__weak T&);
+
+ void test_f(A* ap) {
+ float &fr = (f)(ap);
+ }
+}
diff --git a/test/SemaObjCXX/arc-type-conversion.mm b/test/SemaObjCXX/arc-type-conversion.mm
index f52f54a50cc4..48d1e4833b4c 100644
--- a/test/SemaObjCXX/arc-type-conversion.mm
+++ b/test/SemaObjCXX/arc-type-conversion.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -fblocks %s
+// RUN: %clang_cc1 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -fblocks %s
// rdar://8843600
void * cvt(id arg) // expected-note{{candidate function not viable: cannot convert argument of incomplete type 'void *' to '__strong id'}}
diff --git a/test/SemaObjCXX/arc-type-traits.mm b/test/SemaObjCXX/arc-type-traits.mm
index f50904b03c73..b876018e2574 100644
--- a/test/SemaObjCXX/arc-type-traits.mm
+++ b/test/SemaObjCXX/arc-type-traits.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-nonfragile-abi -fobjc-runtime-has-weak -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -verify %s
// Check the results of the various type-trait query functions on
// lifetime-qualified types in ARC.
diff --git a/test/SemaObjCXX/arc-unavailable-for-weakref.mm b/test/SemaObjCXX/arc-unavailable-for-weakref.mm
index a7b357006843..24593ce5e4ed 100644
--- a/test/SemaObjCXX/arc-unavailable-for-weakref.mm
+++ b/test/SemaObjCXX/arc-unavailable-for-weakref.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify %s
// rdar://9693477
__attribute__((objc_arc_weak_reference_unavailable))
diff --git a/test/SemaObjCXX/exceptions-fragile.mm b/test/SemaObjCXX/exceptions-fragile.mm
index 71e259aa6bba..91b70774e401 100644
--- a/test/SemaObjCXX/exceptions-fragile.mm
+++ b/test/SemaObjCXX/exceptions-fragile.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fobjc-fragile-abi -fsyntax-only -verify %s
@interface NSException @end
void opaque();
diff --git a/test/SemaObjCXX/linkage-spec.mm b/test/SemaObjCXX/linkage-spec.mm
index 1454e6a6782c..584571de9636 100644
--- a/test/SemaObjCXX/linkage-spec.mm
+++ b/test/SemaObjCXX/linkage-spec.mm
@@ -10,3 +10,12 @@ extern "C" {
@interface I
@end
+
+// rdar://10015110
+@protocol VKAnnotation;
+extern "C" {
+
+@protocol VKAnnotation
+ @property (nonatomic, assign) id coordinate;
+@end
+}
diff --git a/test/SemaObjCXX/message.mm b/test/SemaObjCXX/message.mm
index 4f7f8bca5eb1..51a15d5773ba 100644
--- a/test/SemaObjCXX/message.mm
+++ b/test/SemaObjCXX/message.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-fragile-abi -verify %s
@interface I1
- (int*)method;
@end
diff --git a/test/SemaObjCXX/nullptr.mm b/test/SemaObjCXX/nullptr.mm
index 4a9d1a07de9d..2b29b043923a 100644
--- a/test/SemaObjCXX/nullptr.mm
+++ b/test/SemaObjCXX/nullptr.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fblocks -fsyntax-only -verify %s
@interface A
@end
diff --git a/test/SemaObjCXX/propert-dot-error.mm b/test/SemaObjCXX/propert-dot-error.mm
index 7a5feb42e5b1..747efeb536b4 100644
--- a/test/SemaObjCXX/propert-dot-error.mm
+++ b/test/SemaObjCXX/propert-dot-error.mm
@@ -50,3 +50,20 @@ void g(B *b) {
b->operator+ = 17; // expected-error{{'B' does not have a member named 'operator+'}}
}
@end
+
+// PR9759
+class Forward;
+@interface D {
+@public
+ int ivar;
+}
+
+@property int property;
+@end
+
+void testD(D *d) {
+ d.Forward::property = 17; // expected-error{{property access cannot be qualified with 'Forward::'}}
+ d->Forward::ivar = 12; // expected-error{{ivar access cannot be qualified with 'Forward::'}}
+ d.D::property = 17; // expected-error{{expected a class or namespace}}
+ d->D::ivar = 12; // expected-error{{expected a class or namespace}}
+}
diff --git a/test/SemaObjCXX/property-reference.mm b/test/SemaObjCXX/property-reference.mm
index 5dc8061de70b..236dba61fc2d 100644
--- a/test/SemaObjCXX/property-reference.mm
+++ b/test/SemaObjCXX/property-reference.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fsyntax-only -verify -fobjc-nonfragile-abi %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
// rdar://9070460
class TCPPObject
@@ -29,7 +29,7 @@ typedef const TCPPObject& CREF_TCPPObject;
@implementation TNSObject
@synthesize cppObjectNonAtomic;
-@synthesize cppObjectAtomic;
+@synthesize cppObjectAtomic; // expected-warning{{atomic property of type 'CREF_TCPPObject' (aka 'const TCPPObject &') synthesizing setter using non-trivial assignment operator}}
@dynamic cppObjectDynamic;
- (const TCPPObject&) cppObjectNonAtomic
diff --git a/test/SemaObjCXX/property-synthesis-error.mm b/test/SemaObjCXX/property-synthesis-error.mm
index c7a279cfd7a0..5ba4b70a2b69 100644
--- a/test/SemaObjCXX/property-synthesis-error.mm
+++ b/test/SemaObjCXX/property-synthesis-error.mm
@@ -10,7 +10,7 @@
NSMutableArray * _array;
}
-@property (readonly) NSArray * array;
+@property (readonly) NSMutableArray * array;
@end
@@ -30,3 +30,45 @@ int main(void)
{
return 0;
}
+
+// rdar://6137845
+class TCPPObject
+{
+public:
+ TCPPObject(const TCPPObject& inObj);
+ TCPPObject();
+ ~TCPPObject();
+ TCPPObject& operator=(const TCPPObject& inObj);
+private:
+ void* fData;
+};
+
+class Trivial
+{
+public:
+ Trivial(const Trivial& inObj);
+ Trivial();
+ ~Trivial();
+private:
+ void* fData;
+};
+
+@interface MyDocument
+{
+@private
+ TCPPObject _cppObject;
+ TCPPObject _ncppObject;
+ Trivial _tcppObject;
+}
+@property (assign, readwrite) const TCPPObject& cppObject;
+@property (assign, readwrite, nonatomic) const TCPPObject& ncppObject;
+@property (assign, readwrite) const Trivial& tcppObject;
+@end
+
+@implementation MyDocument
+
+@synthesize cppObject = _cppObject; // expected-warning {{atomic property of type 'const TCPPObject &' synthesizing setter using non-trivial assignment operator}}
+@synthesize ncppObject = _ncppObject;
+
+@synthesize tcppObject = _tcppObject;
+@end
diff --git a/test/SemaObjCXX/unknown-anytype.mm b/test/SemaObjCXX/unknown-anytype.mm
new file mode 100644
index 000000000000..163dddee708f
--- /dev/null
+++ b/test/SemaObjCXX/unknown-anytype.mm
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fdebugger-support -funknown-anytype -fsyntax-only -verify %s
+
+// rdar://problem/9416370
+namespace test0 {
+ void test(id x) {
+ [x foo]; // expected-error {{no known method '-foo'; cast the message send to the method's return type}}
+ }
+}
diff --git a/test/SemaOpenCL/local.cl b/test/SemaOpenCL/local.cl
new file mode 100644
index 000000000000..8637cfff30d1
--- /dev/null
+++ b/test/SemaOpenCL/local.cl
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+
+__kernel void foo(void) {
+ __local int i;
+ __local int j = 2; // expected-error {{'__local' variable cannot have an initializer}}
+}
diff --git a/test/SemaOpenCL/vector_conv_invalid.cl b/test/SemaOpenCL/vector_conv_invalid.cl
new file mode 100644
index 000000000000..e6ef5a492f8c
--- /dev/null
+++ b/test/SemaOpenCL/vector_conv_invalid.cl
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -verify %s
+
+typedef unsigned int uint4 __attribute((ext_vector_type(4)));
+typedef int int4 __attribute((ext_vector_type(4)));
+typedef int int3 __attribute((ext_vector_type(3)));
+typedef unsigned uint3 __attribute((ext_vector_type(3)));
+
+void vector_conv_invalid() {
+ uint4 u = (uint4)(1);
+ int4 i = u; // expected-error{{initializing 'int4' with an expression of incompatible type 'uint4'}}
+ int4 e = (int4)u; // expected-error{{invalid conversion between ext-vector type 'int4' and 'uint4'}}
+
+ uint3 u4 = (uint3)u; // expected-error{{invalid conversion between ext-vector type 'uint3' and 'uint4'}}
+}
diff --git a/test/SemaOpenCL/vector_literals_invalid.cl b/test/SemaOpenCL/vector_literals_invalid.cl
index 957680f44ffe..e4e23cd85f00 100644
--- a/test/SemaOpenCL/vector_literals_invalid.cl
+++ b/test/SemaOpenCL/vector_literals_invalid.cl
@@ -8,6 +8,6 @@ void vector_literals_invalid()
{
int4 a = (int4)(1,2,3); // expected-error{{too few elements}}
int4 b = (int4)(1,2,3,4,5); // expected-error{{excess elements in vector}}
- ((float4)(1.0f))++; // expected-error{{expression is not assignable}}
+ ((float4)(1.0f))++; // expected-error{{cannot increment value of type 'float4'}}
int8 d = (int8)(a,(float4)(1)); // expected-error{{initializing 'int' with an expression of incompatible type 'float4'}}
}
diff --git a/test/SemaTemplate/alias-church-numerals.cpp b/test/SemaTemplate/alias-church-numerals.cpp
index 751cac73ae0f..69d77163ab67 100644
--- a/test/SemaTemplate/alias-church-numerals.cpp
+++ b/test/SemaTemplate/alias-church-numerals.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
template<template<template<typename> class, typename> class T, template<typename> class V> struct PartialApply {
template<typename W> using R = T<V, W>;
diff --git a/test/SemaTemplate/alias-nested-nontag.cpp b/test/SemaTemplate/alias-nested-nontag.cpp
index 1bb5ce336f90..4b5226b26ebb 100644
--- a/test/SemaTemplate/alias-nested-nontag.cpp
+++ b/test/SemaTemplate/alias-nested-nontag.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<typename T> using Id = T; // expected-note {{type alias template 'Id' declared here}}
struct U { static Id<int> V; };
diff --git a/test/SemaTemplate/alias-template-template-param.cpp b/test/SemaTemplate/alias-template-template-param.cpp
index a847b0672a2a..c22fccb6788e 100644
--- a/test/SemaTemplate/alias-template-template-param.cpp
+++ b/test/SemaTemplate/alias-template-template-param.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<template<typename> class D> using C = D<int>;
diff --git a/test/SemaTemplate/alias-templates.cpp b/test/SemaTemplate/alias-templates.cpp
index f4c917c5ebc2..79d6849a6efe 100644
--- a/test/SemaTemplate/alias-templates.cpp
+++ b/test/SemaTemplate/alias-templates.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
template<typename S>
struct A {
diff --git a/test/SemaTemplate/atomics.cpp b/test/SemaTemplate/atomics.cpp
new file mode 100644
index 000000000000..7165bbe591e9
--- /dev/null
+++ b/test/SemaTemplate/atomics.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// PR8345
+template<typename T> T f(T* value) {
+ return __sync_add_and_fetch(value, 1);
+}
+int g(long long* x) { return f(x); }
+int g(int* x) { return f(x); }
diff --git a/test/SemaTemplate/attributes.cpp b/test/SemaTemplate/attributes.cpp
index e208bd2b8990..495f4a7ad389 100644
--- a/test/SemaTemplate/attributes.cpp
+++ b/test/SemaTemplate/attributes.cpp
@@ -19,3 +19,16 @@ namespace attribute_aligned {
check_alignment<3>::t c3; // expected-note 2 {{in instantiation}}
check_alignment<4>::t c4;
}
+
+namespace PR9049 {
+ extern const void *CFRetain(const void *ref);
+
+ template<typename T> __attribute__((cf_returns_retained))
+ inline T WBCFRetain(T aValue) { return aValue ? (T)CFRetain(aValue) : (T)0; }
+
+
+ extern void CFRelease(const void *ref);
+
+ template<typename T>
+ inline void WBCFRelease(__attribute__((cf_consumed)) T aValue) { if(aValue) CFRelease(aValue); }
+}
diff --git a/test/SemaTemplate/canonical-expr-type-0x.cpp b/test/SemaTemplate/canonical-expr-type-0x.cpp
index 73cf3c29665c..94ae360b43ef 100644
--- a/test/SemaTemplate/canonical-expr-type-0x.cpp
+++ b/test/SemaTemplate/canonical-expr-type-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
void f();
diff --git a/test/SemaTemplate/current-instantiation.cpp b/test/SemaTemplate/current-instantiation.cpp
index fe7213f14385..ccef811e2224 100644
--- a/test/SemaTemplate/current-instantiation.cpp
+++ b/test/SemaTemplate/current-instantiation.cpp
@@ -215,3 +215,23 @@ namespace PR9255 {
};
};
}
+
+namespace rdar10194295 {
+ template<typename XT>
+ class X {
+ public:
+ enum Enum { Yes, No };
+ template<Enum> void foo();
+ template<Enum> class Inner;
+ };
+
+ template<typename XT>
+ template<typename X<XT>::Enum>
+ void X<XT>::foo()
+ {
+ }
+
+ template<typename XT>
+ template<typename X<XT>::Enum>
+ class X<XT>::Inner { };
+}
diff --git a/test/SemaTemplate/default-arguments-cxx0x.cpp b/test/SemaTemplate/default-arguments-cxx0x.cpp
index 0f7ba4678b8e..77143136c3d2 100644
--- a/test/SemaTemplate/default-arguments-cxx0x.cpp
+++ b/test/SemaTemplate/default-arguments-cxx0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
// Test default template arguments for function templates.
template<typename T = int>
diff --git a/test/SemaTemplate/delegating-constructors.cpp b/test/SemaTemplate/delegating-constructors.cpp
new file mode 100644
index 000000000000..d82343402b74
--- /dev/null
+++ b/test/SemaTemplate/delegating-constructors.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+
+namespace PR10457 {
+
+ class string
+ {
+ string(const char* str, unsigned);
+
+ public:
+ template <unsigned N>
+ string(const char (&str)[N])
+ : string(str) {} // expected-error{{constructor for 'string<6>' creates a delegation cycle}}
+ };
+
+ void f() {
+ string s("hello");
+ }
+}
diff --git a/test/SemaTemplate/dependent-names.cpp b/test/SemaTemplate/dependent-names.cpp
index 7bab5d18d1ad..36e1ad8f17f0 100644
--- a/test/SemaTemplate/dependent-names.cpp
+++ b/test/SemaTemplate/dependent-names.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
typedef double A;
template<typename T> class B {
diff --git a/test/SemaTemplate/instantiate-array.cpp b/test/SemaTemplate/instantiate-array.cpp
index 97ea6cbb8e53..b8229d3f641a 100644
--- a/test/SemaTemplate/instantiate-array.cpp
+++ b/test/SemaTemplate/instantiate-array.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
#ifndef __GXX_EXPERIMENTAL_CXX0X__
#define __CONCAT(__X, __Y) __CONCAT1(__X, __Y)
diff --git a/test/SemaTemplate/instantiate-expr-1.cpp b/test/SemaTemplate/instantiate-expr-1.cpp
index 7af59fd2d11b..896437488d68 100644
--- a/test/SemaTemplate/instantiate-expr-1.cpp
+++ b/test/SemaTemplate/instantiate-expr-1.cpp
@@ -170,3 +170,16 @@ namespace PR6424 {
template void Y2<3>::f();
}
+
+namespace PR10864 {
+ template<typename T> class Vals {};
+ template<> class Vals<int> { public: static const int i = 1; };
+ template<> class Vals<float> { public: static const double i; };
+ template<typename T> void test_asm_tied(T o) {
+ __asm("addl $1, %0" : "=r" (o) : "0"(Vals<T>::i)); // expected-error {{input with type 'double' matching output with type 'float'}}
+ }
+ void test_asm_tied() {
+ test_asm_tied(1);
+ test_asm_tied(1.f); // expected-note {{instantiation of}}
+ }
+}
diff --git a/test/SemaTemplate/instantiate-expr-4.cpp b/test/SemaTemplate/instantiate-expr-4.cpp
index 521d2180d7ab..9483f9b28366 100644
--- a/test/SemaTemplate/instantiate-expr-4.cpp
+++ b/test/SemaTemplate/instantiate-expr-4.cpp
@@ -135,6 +135,23 @@ namespace PR5755 {
}
}
+namespace PR10480 {
+ template<typename T>
+ struct X {
+ X();
+ ~X() {
+ T *ptr = 1; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}}
+ }
+ };
+
+ template<typename T>
+ void f() {
+ new X<int>[1]; // expected-note{{in instantiation of member function 'PR10480::X<int>::~X' requested here}}
+ }
+
+ template void f<int>();
+}
+
// ---------------------------------------------------------------------
// throw expressions
// ---------------------------------------------------------------------
diff --git a/test/SemaTemplate/instantiate-expr-basic.cpp b/test/SemaTemplate/instantiate-expr-basic.cpp
index 074fe6941490..a266a6584b06 100644
--- a/test/SemaTemplate/instantiate-expr-basic.cpp
+++ b/test/SemaTemplate/instantiate-expr-basic.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -std=c++11 %s
template <typename T>
struct S {
diff --git a/test/SemaTemplate/instantiate-function-2.cpp b/test/SemaTemplate/instantiate-function-2.cpp
index 087ede2b89cb..19a8b61ff193 100644
--- a/test/SemaTemplate/instantiate-function-2.cpp
+++ b/test/SemaTemplate/instantiate-function-2.cpp
@@ -46,7 +46,7 @@ namespace PR9654 {
namespace AliasTagDef {
template<typename T>
T f() {
- using S = struct { // expected-warning {{C++0x}}
+ using S = struct { // expected-warning {{C++11}}
T g() {
return T();
}
diff --git a/test/SemaTemplate/instantiate-member-class.cpp b/test/SemaTemplate/instantiate-member-class.cpp
index 1028b45cc0e1..c67eb4022a47 100644
--- a/test/SemaTemplate/instantiate-member-class.cpp
+++ b/test/SemaTemplate/instantiate-member-class.cpp
@@ -108,7 +108,7 @@ namespace test2 {
namespace AliasTagDef {
template<typename T>
struct F {
- using S = struct U { // expected-warning {{C++0x}}
+ using S = struct U { // expected-warning {{C++11}}
T g() {
return T();
}
diff --git a/test/SemaTemplate/instantiate-static-var.cpp b/test/SemaTemplate/instantiate-static-var.cpp
index 0c0607524834..d2b0459ccc58 100644
--- a/test/SemaTemplate/instantiate-static-var.cpp
+++ b/test/SemaTemplate/instantiate-static-var.cpp
@@ -11,7 +11,7 @@ X<int, 0> xi0; // expected-note{{in instantiation of template class 'X<int, 0>'
template<typename T>
class Y {
- static const T value = 0; // expected-warning{{in-class initializer for static data member of type 'const float' is a C++0x extension}}
+ static const T value = 0; // expected-warning{{in-class initializer for static data member of type 'const float' is a GNU extension}}
};
Y<float> fy; // expected-note{{in instantiation of template class 'Y<float>' requested here}}
diff --git a/test/SemaTemplate/instantiate-try-catch.cpp b/test/SemaTemplate/instantiate-try-catch.cpp
index f4ce0e173146..89cae03af08f 100644
--- a/test/SemaTemplate/instantiate-try-catch.cpp
+++ b/test/SemaTemplate/instantiate-try-catch.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -std=c++0x -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -std=c++11 -verify %s
template<typename T> struct TryCatch0 {
void f() {
diff --git a/test/SemaTemplate/lookup-dependent-bases.cpp b/test/SemaTemplate/lookup-dependent-bases.cpp
new file mode 100644
index 000000000000..2710caf22125
--- /dev/null
+++ b/test/SemaTemplate/lookup-dependent-bases.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify %s
+
+class C {
+public:
+ static void foo2() { }
+};
+template <class T>
+class A {
+public:
+ typedef C D;
+};
+
+template <class T>
+class B : public A<T> {
+public:
+ void foo() {
+ D::foo2();
+ }
+};
diff --git a/test/SemaTemplate/member-inclass-init-value-dependent.cpp b/test/SemaTemplate/member-inclass-init-value-dependent.cpp
index d1ae4f2ded5f..5bff7f209579 100644
--- a/test/SemaTemplate/member-inclass-init-value-dependent.cpp
+++ b/test/SemaTemplate/member-inclass-init-value-dependent.cpp
@@ -9,3 +9,10 @@ void test() {
foo<4> bar;
}
+struct S {
+ S(int n);
+};
+template<typename> struct T {
+ S s = 0;
+};
+T<int> t;
diff --git a/test/SemaTemplate/missing-class-keyword-crash.cpp b/test/SemaTemplate/missing-class-keyword-crash.cpp
new file mode 100644
index 000000000000..f0eee2ba2f8a
--- /dev/null
+++ b/test/SemaTemplate/missing-class-keyword-crash.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+class G {};
+template <Foo> // expected-error{{unknown type name 'Foo'}} \
+ // expected-note{{template parameter is declared here}}
+class Bar {};
+
+class Bar<G> blah_test; // expected-error{{template argument for non-type template parameter must be an expression}}
diff --git a/test/SemaTemplate/ms-function-specialization-class-scope.cpp b/test/SemaTemplate/ms-function-specialization-class-scope.cpp
new file mode 100644
index 000000000000..bda87f99c9a1
--- /dev/null
+++ b/test/SemaTemplate/ms-function-specialization-class-scope.cpp
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify %s
+
+
+class A {
+public:
+ template <class U>
+ A(U p) {
+ }
+ template <>
+ A(int p) { // expected-warning{{explicit specialization of 'A' within class scope is a Microsoft extension}}
+ }
+
+ template <class U>
+ void f(U p) {
+ }
+
+ template <>
+ void f(int p) { // expected-warning{{explicit specialization of 'f' within class scope is a Microsoft extension}}
+ }
+
+ void f(int p) {
+ }
+};
+
+void test1()
+{
+ A a(3);
+ char* b ;
+ a.f(b);
+ a.f<int>(99);
+ a.f(100);
+}
+
+
+
+
+template <class T>
+class B {
+public:
+ template <class U>
+ B(U p) {
+ }
+ template <>
+ B(int p) { // expected-warning{{explicit specialization of 'B<T>' within class scope is a Microsoft extension}}
+ }
+
+ template <class U>
+ void f(U p) {
+ T y = 9;
+ }
+
+
+ template <>
+ void f(int p) { // expected-warning{{explicit specialization of 'f' within class scope is a Microsoft extension}}
+ T a = 3;
+ }
+
+ void f(int p) {
+ T a = 3;
+ }
+};
+
+void test2()
+{
+ B<char> b(3);
+ char* ptr;
+ b.f(ptr);
+ b.f<int>(99);
+ b.f(100);
+}
+
diff --git a/test/SemaTemplate/ms-lookup-template-base-classes.cpp b/test/SemaTemplate/ms-lookup-template-base-classes.cpp
new file mode 100644
index 000000000000..910fa37e80d8
--- /dev/null
+++ b/test/SemaTemplate/ms-lookup-template-base-classes.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify %s
+
+
+template <class T>
+class A {
+public:
+ void f(T a) { }// expected-note {{must qualify identifier to find this declaration in dependent base class}}
+ void g();// expected-note {{must qualify identifier to find this declaration in dependent base class}}
+};
+
+
+template <class T>
+class B : public A<T> {
+public:
+ void z(T a)
+ {
+ f(a); // expected-warning {{use of identifier 'f' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
+ g(); // expected-warning {{use of identifier 'g' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
+ }
+};
+
+template class B<int>; // expected-note {{requested here}}
+template class B<char>;
+
+void test()
+{
+ B<int> b;
+ b.z(3);
+}
+
+
diff --git a/test/SemaTemplate/nested-template.cpp b/test/SemaTemplate/nested-template.cpp
index 01ede32f9a08..ab647aa22675 100644
--- a/test/SemaTemplate/nested-template.cpp
+++ b/test/SemaTemplate/nested-template.cpp
@@ -125,4 +125,20 @@ X2<int>::Inner<X2_arg> x2i1;
X2<float> x2a; // expected-note{{instantiation}}
X2<long>::Inner<X2_arg> x2i3; // expected-error{{template template argument has different}}
+namespace PR10896 {
+ template<typename TN>
+ class Foo {
+
+ public:
+ void foo() {}
+ private:
+
+ template<typename T>
+ T SomeField; // expected-error {{member 'SomeField' declared as a template}}
+ };
+ void g() {
+ Foo<int> f;
+ f.foo();
+ }
+}
diff --git a/test/SemaTemplate/operator-template.cpp b/test/SemaTemplate/operator-template.cpp
index 4300755cf711..777b0f5f42a1 100644
--- a/test/SemaTemplate/operator-template.cpp
+++ b/test/SemaTemplate/operator-template.cpp
@@ -2,7 +2,8 @@
// Make sure we accept this
template<class X>struct A{typedef X Y;};
-template<class X>bool operator==(A<X>,typename A<X>::Y);
+template<class X>bool operator==(A<X>,typename A<X>::Y); // expected-note{{candidate template ignored: failed template argument deduction}}
+
int a(A<int> x) { return operator==(x,1); }
int a0(A<int> x) { return x == 1; }
@@ -10,7 +11,8 @@ int a0(A<int> x) { return x == 1; }
// FIXME: the location information for the note isn't very good
template<class X>struct B{typedef X Y;};
template<class X>bool operator==(B<X>*,typename B<X>::Y); // \
-expected-error{{overloaded 'operator==' must have at least one parameter of class or enumeration type}} \
-expected-note{{in instantiation of function template specialization}}
-int a(B<int> x) { return operator==(&x,1); }
+// expected-error{{overloaded 'operator==' must have at least one parameter of class or enumeration type}} \
+// expected-note{{in instantiation of function template specialization}} \
+// expected-note{{candidate template ignored: substitution failure [with X = int]}}
+int a(B<int> x) { return operator==(&x,1); } // expected-error{{no matching function for call to 'operator=='}}
diff --git a/test/SemaTemplate/overload-uneval.cpp b/test/SemaTemplate/overload-uneval.cpp
index 632d1cd521d9..8d8a2f42cf28 100644
--- a/test/SemaTemplate/overload-uneval.cpp
+++ b/test/SemaTemplate/overload-uneval.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-unused %s
// Tests that overload resolution is treated as an unevaluated context.
// PR5541
diff --git a/test/SemaTemplate/resolve-single-template-id.cpp b/test/SemaTemplate/resolve-single-template-id.cpp
index ef0a76307670..b9833d8609ef 100644
--- a/test/SemaTemplate/resolve-single-template-id.cpp
+++ b/test/SemaTemplate/resolve-single-template-id.cpp
@@ -1,15 +1,15 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
namespace std {
class type_info {};
}
void one() { }
-void two() { } // expected-note 3{{candidate}}
-void two(int) { } // expected-note 3{{candidate}}
+void two() { } // expected-note 4{{possible target for call}}
+void two(int) { } // expected-note 4{{possible target for call}}
-template<class T> void twoT() { } // expected-note 5{{candidate}}
-template<class T> void twoT(int) { } // expected-note 5{{candidate}}
+template<class T> void twoT() { } // expected-note 5{{possible target for call}}
+template<class T> void twoT(int) { } // expected-note 5{{possible target for call}}
template<class T> void oneT() { }
template<class T, class U> void oneT(U) { }
@@ -29,29 +29,30 @@ template<void (*p)(int)> struct test { };
int main()
{
one; // expected-warning {{expression result unused}}
- two; // expected-error {{cannot resolve overloaded function 'two' from context}}
+ two; // expected-error {{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}}
oneT<int>; // expected-warning {{expression result unused}}
- twoT<int>; // expected-error {{cannot resolve overloaded function 'twoT' from context}}
+ twoT<int>; // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}}
typeid(oneT<int>); // expected-warning{{expression result unused}}
sizeof(oneT<int>); // expected-warning {{expression result unused}}
- sizeof(twoT<int>); //expected-error {{cannot resolve overloaded function 'twoT' from context}}
+ sizeof(twoT<int>); //expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}}
decltype(oneT<int>)* fun = 0;
*one; // expected-warning {{expression result unused}}
*oneT<int>; // expected-warning {{expression result unused}}
- *two; //expected-error {{cannot resolve overloaded function 'two' from context}}
- *twoT<int>; //expected-error {{cannot resolve overloaded function 'twoT' from context}}
+ *two; //expected-error {{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}} expected-error {{indirection requires pointer operand}}
+ *twoT<int>; //expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}}
!oneT<int>; // expected-warning {{expression result unused}}
+oneT<int>; // expected-warning {{expression result unused}}
-oneT<int>; //expected-error {{invalid argument type}}
- oneT<int> == 0; // expected-warning {{expression result unused}}
- 0 == oneT<int>; // expected-warning {{expression result unused}}
- 0 != oneT<int>; // expected-warning {{expression result unused}}
+ oneT<int> == 0; // expected-warning {{equality comparison result unused}} \
+ // expected-note {{use '=' to turn this equality comparison into an assignment}}
+ 0 == oneT<int>; // expected-warning {{equality comparison result unused}}
+ 0 != oneT<int>; // expected-warning {{inequality comparison result unused}}
(false ? one : oneT<int>); // expected-warning {{expression result unused}}
void (*p1)(int); p1 = oneT<int>;
int i = (int) (false ? (void (*)(int))twoT<int> : oneT<int>); //expected-error {{incompatible operand}}
- (twoT<int>) == oneT<int>; //expected-error {{cannot resolve overloaded function 'twoT' from context}}
+ (twoT<int>) == oneT<int>; //expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} {{cannot resolve overloaded function 'twoT' from context}}
bool b = oneT<int>;
void (*p)() = oneT<int>;
test<oneT<int> > ti;
@@ -65,9 +66,10 @@ int main()
oneT<int> < oneT<int>; //expected-warning {{self-comparison always evaluates to false}} \
//expected-warning {{expression result unused}}
- two < two; //expected-error {{cannot resolve overloaded function 'two' from context}}
- twoT<int> < twoT<int>; //expected-error {{cannot resolve overloaded function 'twoT' from context}}
- oneT<int> == 0; // expected-warning {{expression result unused}}
+ two < two; //expected-error 2 {{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}} expected-error {{invalid operands to binary expression ('void' and 'void')}}
+ twoT<int> < twoT<int>; //expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} {{cannot resolve overloaded function 'twoT' from context}}
+ oneT<int> == 0; // expected-warning {{equality comparison result unused}} \
+ // expected-note {{use '=' to turn this equality comparison into an assignment}}
}
@@ -76,5 +78,5 @@ struct rdar9108698 {
};
void test_rdar9108698(rdar9108698 x) {
- x.f<int>; // expected-error{{a bound member function may only be called}}
+ x.f<int>; // expected-error{{reference to non-static member function must be called}}
}
diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp
index 5be5a1303136..747ddcc4618e 100644
--- a/test/SemaTemplate/temp_arg_nontype.cpp
+++ b/test/SemaTemplate/temp_arg_nontype.cpp
@@ -7,7 +7,7 @@ A<int()> *a1; // expected-error{{template argument for non-type template paramet
A<int> *a2; // expected-error{{template argument for non-type template parameter must be an expression}}
-A<1 >> 2> *a3; // expected-warning{{use of right-shift operator ('>>') in template argument will require parentheses in C++0x}}
+A<1 >> 2> *a3; // expected-warning{{use of right-shift operator ('>>') in template argument will require parentheses in C++11}}
// C++ [temp.arg.nontype]p5:
A<A> *a4; // expected-error{{must be an expression}}
@@ -170,7 +170,7 @@ namespace pr6249 {
namespace PR6723 {
template<unsigned char C> void f(int (&a)[C]); // expected-note {{candidate template ignored}} \
- // expected-note{{candidate function [with C = '\x00'] not viable: no known conversion from 'int [512]' to 'int (&)[0]' for 1st argument}}
+ // expected-note{{substitution failure [with C = '\x00']}}
void g() {
int arr512[512];
f(arr512); // expected-error{{no matching function for call}}
@@ -263,3 +263,63 @@ namespace PR9227 {
void test_char_single_quote() { enable_if_char<'\''>::type i; } // expected-error{{enable_if_char<'\''>}}
void test_char_backslash() { enable_if_char<'\\'>::type i; } // expected-error{{enable_if_char<'\\'>}}
}
+
+namespace PR10579 {
+ namespace fcppt
+ {
+ namespace container
+ {
+ namespace bitfield
+ {
+
+ template<
+ typename Enum,
+ Enum Size
+ >
+ class basic;
+
+ template<
+ typename Enum,
+ Enum Size
+ >
+ class basic
+ {
+ public:
+ basic()
+ {
+ }
+ };
+
+ }
+ }
+ }
+
+ namespace
+ {
+
+ namespace testenum
+ {
+ enum type
+ {
+ foo,
+ bar,
+ size
+ };
+ }
+
+ }
+
+ int main()
+ {
+ typedef fcppt::container::bitfield::basic<
+ testenum::type,
+ testenum::size
+ > bitfield_foo;
+
+ bitfield_foo obj;
+ }
+
+}
+
+template <int& I> struct PR10766 { static int *ip; };
+template <int& I> int* PR10766<I>::ip = &I;
diff --git a/test/SemaTemplate/temp_explicit_cxx0x.cpp b/test/SemaTemplate/temp_explicit_cxx0x.cpp
index 215d2cfa0820..9d6dc80b5b0a 100644
--- a/test/SemaTemplate/temp_explicit_cxx0x.cpp
+++ b/test/SemaTemplate/temp_explicit_cxx0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
namespace N1 {
template<typename T> struct X0 { }; // expected-note{{here}}
diff --git a/test/SemaTemplate/typename-specifier.cpp b/test/SemaTemplate/typename-specifier.cpp
index 7898a20d6e17..9eb4f33de0b9 100644
--- a/test/SemaTemplate/typename-specifier.cpp
+++ b/test/SemaTemplate/typename-specifier.cpp
@@ -102,3 +102,16 @@ struct H {
};
G<H> struct_G;
+
+namespace PR10925 {
+ template< int mydim, typename Traits >
+ class BasicGeometry
+ {
+ typedef int some_type_t;
+ };
+
+ template<class ctype, int mydim, int coorddim>
+ class MockGeometry : BasicGeometry<mydim, int>{
+ using typename BasicGeometry<mydim, int>::operator[]; // expected-error {{typename is allowed for identifiers only}}
+ };
+}
diff --git a/test/SemaTemplate/unresolved-construct.cpp b/test/SemaTemplate/unresolved-construct.cpp
index 0d1ba17a0179..bb9ed8e4e081 100644
--- a/test/SemaTemplate/unresolved-construct.cpp
+++ b/test/SemaTemplate/unresolved-construct.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
class A
{
public:
diff --git a/test/lit.cfg b/test/lit.cfg
index e18105df1916..8062aa72c1f1 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -165,7 +165,9 @@ config.substitutions.append(
###
# Set available features we allow tests to conditionalize on.
-if platform.system() != 'Windows':
+#
+# As of 2011.08, crash-recovery tests still do not pass on FreeBSD.
+if platform.system() not in ['FreeBSD']:
config.available_features.add('crash-recovery')
# Shell execution
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index aff437fd467a..117d10a603f3 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -2,4 +2,5 @@ add_subdirectory(libclang)
add_subdirectory(c-index-test)
add_subdirectory(arcmt-test)
add_subdirectory(c-arcmt-test)
+add_subdirectory(diagtool)
add_subdirectory(driver)
diff --git a/tools/Makefile b/tools/Makefile
index bfd2a641ec1e..4ea2cdd32d21 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -8,7 +8,7 @@
##===----------------------------------------------------------------------===##
CLANG_LEVEL := ..
-DIRS := driver libclang c-index-test arcmt-test c-arcmt-test
+DIRS := driver libclang c-index-test arcmt-test c-arcmt-test diagtool
include $(CLANG_LEVEL)/../../Makefile.config
diff --git a/tools/arcmt-test/arcmt-test.cpp b/tools/arcmt-test/arcmt-test.cpp
index eb0f56943f96..d27483f29142 100644
--- a/tools/arcmt-test/arcmt-test.cpp
+++ b/tools/arcmt-test/arcmt-test.cpp
@@ -10,7 +10,7 @@
#include "clang/ARCMigrate/ARCMT.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "clang/Frontend/VerifyDiagnosticsClient.h"
+#include "clang/Frontend/VerifyDiagnosticConsumer.h"
#include "clang/Frontend/Utils.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -69,24 +69,24 @@ llvm::sys::Path GetExecutablePath(const char *Argv0) {
}
static void printSourceLocation(SourceLocation loc, ASTContext &Ctx,
- llvm::raw_ostream &OS);
+ raw_ostream &OS);
static void printSourceRange(CharSourceRange range, ASTContext &Ctx,
- llvm::raw_ostream &OS);
+ raw_ostream &OS);
namespace {
class PrintTransforms : public MigrationProcess::RewriteListener {
ASTContext *Ctx;
- llvm::raw_ostream &OS;
+ raw_ostream &OS;
public:
- PrintTransforms(llvm::raw_ostream &OS)
+ PrintTransforms(raw_ostream &OS)
: Ctx(0), OS(OS) { }
virtual void start(ASTContext &ctx) { Ctx = &ctx; }
virtual void finish() { Ctx = 0; }
- virtual void insert(SourceLocation loc, llvm::StringRef text) {
+ virtual void insert(SourceLocation loc, StringRef text) {
assert(Ctx);
OS << "Insert: ";
printSourceLocation(loc, *Ctx, OS);
@@ -103,16 +103,17 @@ public:
} // anonymous namespace
-static bool checkForMigration(llvm::StringRef resourcesPath,
- llvm::ArrayRef<const char *> Args) {
- DiagnosticClient *DiagClient =
+static bool checkForMigration(StringRef resourcesPath,
+ ArrayRef<const char *> Args) {
+ DiagnosticConsumer *DiagClient =
new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic(DiagID, DiagClient));
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, DiagClient));
// Chain in -verify checker, if requested.
- VerifyDiagnosticsClient *verifyDiag = 0;
+ VerifyDiagnosticConsumer *verifyDiag = 0;
if (VerifyDiags) {
- verifyDiag = new VerifyDiagnosticsClient(*Diags, Diags->takeClient());
+ verifyDiag = new VerifyDiagnosticConsumer(*Diags);
Diags->setClient(verifyDiag);
}
@@ -134,7 +135,7 @@ static bool checkForMigration(llvm::StringRef resourcesPath,
return Diags->getClient()->getNumErrors() > 0;
}
-static void printResult(FileRemapper &remapper, llvm::raw_ostream &OS) {
+static void printResult(FileRemapper &remapper, raw_ostream &OS) {
CompilerInvocation CI;
remapper.applyMappings(CI);
PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
@@ -145,16 +146,17 @@ static void printResult(FileRemapper &remapper, llvm::raw_ostream &OS) {
}
}
-static bool performTransformations(llvm::StringRef resourcesPath,
- llvm::ArrayRef<const char *> Args) {
+static bool performTransformations(StringRef resourcesPath,
+ ArrayRef<const char *> Args) {
// Check first.
if (checkForMigration(resourcesPath, Args))
return true;
- DiagnosticClient *DiagClient =
+ DiagnosticConsumer *DiagClient =
new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<Diagnostic> TopDiags(new Diagnostic(DiagID, DiagClient));
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> TopDiags(
+ new DiagnosticsEngine(DiagID, DiagClient));
CompilerInvocation origCI;
CompilerInvocation::CreateFromArgs(origCI, Args.begin(), Args.end(),
@@ -199,7 +201,7 @@ static bool performTransformations(llvm::StringRef resourcesPath,
return false;
}
-static bool filesCompareEqual(llvm::StringRef fname1, llvm::StringRef fname2) {
+static bool filesCompareEqual(StringRef fname1, StringRef fname2) {
using namespace llvm;
OwningPtr<MemoryBuffer> file1;
@@ -215,7 +217,7 @@ static bool filesCompareEqual(llvm::StringRef fname1, llvm::StringRef fname2) {
return file1->getBuffer() == file2->getBuffer();
}
-static bool verifyTransformedFiles(llvm::ArrayRef<std::string> resultFiles) {
+static bool verifyTransformedFiles(ArrayRef<std::string> resultFiles) {
using namespace llvm;
assert(!resultFiles.empty());
@@ -303,7 +305,7 @@ static bool verifyTransformedFiles(llvm::ArrayRef<std::string> resultFiles) {
//===----------------------------------------------------------------------===//
static void printSourceLocation(SourceLocation loc, ASTContext &Ctx,
- llvm::raw_ostream &OS) {
+ raw_ostream &OS) {
SourceManager &SM = Ctx.getSourceManager();
PresumedLoc PL = SM.getPresumedLoc(loc);
@@ -313,7 +315,7 @@ static void printSourceLocation(SourceLocation loc, ASTContext &Ctx,
}
static void printSourceRange(CharSourceRange range, ASTContext &Ctx,
- llvm::raw_ostream &OS) {
+ raw_ostream &OS) {
SourceManager &SM = Ctx.getSourceManager();
const LangOptions &langOpts = Ctx.getLangOptions();
@@ -338,7 +340,6 @@ static void printSourceRange(CharSourceRange range, ASTContext &Ctx,
//===----------------------------------------------------------------------===//
int main(int argc, const char **argv) {
- using llvm::StringRef;
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
llvm::sys::PrintStackTraceOnErrorSignal();
@@ -365,7 +366,7 @@ int main(int argc, const char **argv) {
return 1;
}
- llvm::ArrayRef<const char*> Args(argv+optargc+1, argc-optargc-1);
+ ArrayRef<const char*> Args(argv+optargc+1, argc-optargc-1);
if (CheckOnly)
return checkForMigration(resourcesPath, Args);
diff --git a/tools/c-index-test/CMakeLists.txt b/tools/c-index-test/CMakeLists.txt
index 45ad9e35c6ef..c44b34b82050 100644
--- a/tools/c-index-test/CMakeLists.txt
+++ b/tools/c-index-test/CMakeLists.txt
@@ -13,3 +13,4 @@ set_target_properties(c-index-test
PROPERTIES
LINKER_LANGUAGE CXX)
+install(TARGETS c-index-test RUNTIME DESTINATION bin)
diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile
index 5e5b8570c812..c21b3279a287 100644
--- a/tools/c-index-test/Makefile
+++ b/tools/c-index-test/Makefile
@@ -13,9 +13,6 @@ TOOLNAME = c-index-test
# No plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
-# Don't install this. It is used for tests.
-NO_INSTALL = 1
-
LINK_COMPONENTS := support mc
USEDLIBS = clang.a clangIndex.a clangFrontend.a clangDriver.a \
clangSerialization.a clangParse.a clangSema.a \
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 6e0aaac73cc3..2a3584b892b8 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -158,9 +158,25 @@ int parse_remapped_files(int argc, const char **argv, int start_arg,
/* Pretty-printing. */
/******************************************************************************/
+static void PrintRange(CXSourceRange R, const char *str) {
+ CXFile begin_file, end_file;
+ unsigned begin_line, begin_column, end_line, end_column;
+
+ clang_getSpellingLocation(clang_getRangeStart(R),
+ &begin_file, &begin_line, &begin_column, 0);
+ clang_getSpellingLocation(clang_getRangeEnd(R),
+ &end_file, &end_line, &end_column, 0);
+ if (!begin_file || !end_file)
+ return;
+
+ printf(" %s=", str);
+ PrintExtent(stdout, begin_line, begin_column, end_line, end_column);
+}
+
int want_display_name = 0;
-static void PrintCursor(CXTranslationUnit TU, CXCursor Cursor) {
+static void PrintCursor(CXCursor Cursor) {
+ CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
if (clang_isInvalid(Cursor.kind)) {
CXString ks = clang_getCursorKindSpelling(Cursor.kind);
printf("Invalid Cursor => %s", clang_getCString(ks));
@@ -173,6 +189,9 @@ static void PrintCursor(CXTranslationUnit TU, CXCursor Cursor) {
CXCursor SpecializationOf;
CXCursor *overridden;
unsigned num_overridden;
+ unsigned RefNameRangeNr;
+ CXSourceRange CursorExtent;
+ CXSourceRange RefNameRange;
ks = clang_getCursorKindSpelling(Cursor.kind);
string = want_display_name? clang_getCursorDisplayName(Cursor)
@@ -219,6 +238,10 @@ static void PrintCursor(CXTranslationUnit TU, CXCursor Cursor) {
case CXAvailability_NotAvailable:
printf(" (unavailable)");
break;
+
+ case CXAvailability_NotAccessible:
+ printf(" (inaccessible)");
+ break;
}
if (clang_CXXMethod_isStatic(Cursor))
@@ -288,6 +311,26 @@ static void PrintCursor(CXTranslationUnit TU, CXCursor Cursor) {
if (clang_isFileMultipleIncludeGuarded(TU, File))
printf(" [multi-include guarded]");
}
+
+ CursorExtent = clang_getCursorExtent(Cursor);
+ RefNameRange = clang_getCursorReferenceNameRange(Cursor,
+ CXNameRange_WantQualifier
+ | CXNameRange_WantSinglePiece
+ | CXNameRange_WantTemplateArgs,
+ 0);
+ if (!clang_equalRanges(CursorExtent, RefNameRange))
+ PrintRange(RefNameRange, "SingleRefName");
+
+ for (RefNameRangeNr = 0; 1; RefNameRangeNr++) {
+ RefNameRange = clang_getCursorReferenceNameRange(Cursor,
+ CXNameRange_WantQualifier
+ | CXNameRange_WantTemplateArgs,
+ RefNameRangeNr);
+ if (clang_equalRanges(clang_getNullRange(), RefNameRange))
+ break;
+ if (!clang_equalRanges(CursorExtent, RefNameRange))
+ PrintRange(RefNameRange, "RefName");
+ }
}
}
@@ -381,7 +424,7 @@ void PrintDiagnostics(CXTranslationUnit TU) {
}
void PrintMemoryUsage(CXTranslationUnit TU) {
- unsigned long total = 0.0;
+ unsigned long total = 0;
unsigned i = 0;
CXTUResourceUsage usage = clang_getCXTUResourceUsage(TU);
fprintf(stderr, "Memory usage:\n");
@@ -405,18 +448,7 @@ static const char *FileCheckPrefix = "CHECK";
static void PrintCursorExtent(CXCursor C) {
CXSourceRange extent = clang_getCursorExtent(C);
- CXFile begin_file, end_file;
- unsigned begin_line, begin_column, end_line, end_column;
-
- clang_getSpellingLocation(clang_getRangeStart(extent),
- &begin_file, &begin_line, &begin_column, 0);
- clang_getSpellingLocation(clang_getRangeEnd(extent),
- &end_file, &end_line, &end_column, 0);
- if (!begin_file || !end_file)
- return;
-
- printf(" Extent=");
- PrintExtent(stdout, begin_line, begin_column, end_line, end_column);
+ PrintRange(extent, "Extent");
}
/* Data used by all of the visitors. */
@@ -436,7 +468,7 @@ enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor,
clang_getSpellingLocation(Loc, 0, &line, &column, 0);
printf("// %s: %s:%d:%d: ", FileCheckPrefix,
GetCursorSource(Cursor), line, column);
- PrintCursor(Data->TU, Cursor);
+ PrintCursor(Cursor);
PrintCursorExtent(Cursor);
printf("\n");
return CXChildVisit_Recurse;
@@ -489,7 +521,7 @@ static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor,
} else if (Ref.kind != CXCursor_FunctionDecl) {
printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref),
curLine, curColumn);
- PrintCursor(Data->TU, Ref);
+ PrintCursor(Ref);
printf("\n");
}
}
@@ -564,8 +596,6 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
CXClientData d) {
const char *linkage = 0;
- VisitorData *Data = (VisitorData *)d;
-
if (clang_isInvalid(clang_getCursorKind(cursor)))
return CXChildVisit_Recurse;
@@ -578,7 +608,7 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
}
if (linkage) {
- PrintCursor(Data->TU, cursor);
+ PrintCursor(cursor);
printf("linkage=%s\n", linkage);
}
@@ -591,12 +621,10 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p,
CXClientData d) {
- VisitorData *Data = (VisitorData *)d;
-
if (!clang_isInvalid(clang_getCursorKind(cursor))) {
CXType T = clang_getCursorType(cursor);
CXString S = clang_getTypeKindSpelling(T.kind);
- PrintCursor(Data->TU, cursor);
+ PrintCursor(cursor);
printf(" typekind=%s", clang_getCString(S));
if (clang_isConstQualifiedType(T))
printf(" const");
@@ -747,6 +775,8 @@ int perform_test_reparse_source(int argc, const char **argv, int trials,
int num_unsaved_files = 0;
int result;
int trial;
+ int remap_after_trial = 0;
+ char *endptr = 0;
Idx = clang_createIndex(/* excludeDeclsFromPCH */
!strcmp(filter, "local") ? 1 : 0,
@@ -770,8 +800,15 @@ int perform_test_reparse_source(int argc, const char **argv, int trials,
return 1;
}
+ if (getenv("CINDEXTEST_REMAP_AFTER_TRIAL")) {
+ remap_after_trial =
+ strtol(getenv("CINDEXTEST_REMAP_AFTER_TRIAL"), &endptr, 10);
+ }
+
for (trial = 0; trial < trials; ++trial) {
- if (clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
+ if (clang_reparseTranslationUnit(TU,
+ trial >= remap_after_trial ? num_unsaved_files : 0,
+ trial >= remap_after_trial ? unsaved_files : 0,
clang_defaultReparseOptions(TU))) {
fprintf(stderr, "Unable to reparse translation unit!\n");
clang_disposeTranslationUnit(TU);
@@ -800,7 +837,7 @@ static void print_cursor_file_scan(CXTranslationUnit TU, CXCursor cursor,
printf("-%s", prefix);
PrintExtent(stdout, start_line, start_col, end_line, end_col);
printf(" ");
- PrintCursor(TU, cursor);
+ PrintCursor(cursor);
printf("\n");
}
@@ -996,6 +1033,7 @@ void print_completion_result(CXCompletionResult *completion_result,
CXClientData client_data) {
FILE *file = (FILE *)client_data;
CXString ks = clang_getCursorKindSpelling(completion_result->CursorKind);
+ unsigned annotationCount;
fprintf(file, "%s:", clang_getCString(ks));
clang_disposeString(ks);
@@ -1014,7 +1052,27 @@ void print_completion_result(CXCompletionResult *completion_result,
case CXAvailability_NotAvailable:
fprintf(file, " (unavailable)");
break;
+
+ case CXAvailability_NotAccessible:
+ fprintf(file, " (inaccessible)");
+ break;
+ }
+
+ annotationCount = clang_getCompletionNumAnnotations(
+ completion_result->CompletionString);
+ if (annotationCount) {
+ unsigned i;
+ fprintf(file, " (");
+ for (i = 0; i < annotationCount; ++i) {
+ if (i != 0)
+ fprintf(file, ", ");
+ fprintf(file, "\"%s\"",
+ clang_getCString(clang_getCompletionAnnotation(
+ completion_result->CompletionString, i)));
+ }
+ fprintf(file, ")");
}
+
fprintf(file, "\n");
}
@@ -1171,8 +1229,11 @@ int perform_code_completion(int argc, const char **argv, int timing_only) {
}
if (results) {
- unsigned i, n = results->NumResults;
+ unsigned i, n = results->NumResults, containerIsIncomplete = 0;
unsigned long long contexts;
+ enum CXCursorKind containerKind;
+ CXString objCSelector;
+ const char *selectorString;
if (!timing_only) {
/* Sort the code-completion results based on the typed text. */
clang_sortCodeCompletionResults(results->Results, results->NumResults);
@@ -1190,6 +1251,35 @@ int perform_code_completion(int argc, const char **argv, int timing_only) {
contexts = clang_codeCompleteGetContexts(results);
print_completion_contexts(contexts, stdout);
+ containerKind = clang_codeCompleteGetContainerKind(results,
+ &containerIsIncomplete);
+
+ if (containerKind != CXCursor_InvalidCode) {
+ /* We have found a container */
+ CXString containerUSR, containerKindSpelling;
+ containerKindSpelling = clang_getCursorKindSpelling(containerKind);
+ printf("Container Kind: %s\n", clang_getCString(containerKindSpelling));
+ clang_disposeString(containerKindSpelling);
+
+ if (containerIsIncomplete) {
+ printf("Container is incomplete\n");
+ }
+ else {
+ printf("Container is complete\n");
+ }
+
+ containerUSR = clang_codeCompleteGetContainerUSR(results);
+ printf("Container USR: %s\n", clang_getCString(containerUSR));
+ clang_disposeString(containerUSR);
+ }
+
+ objCSelector = clang_codeCompleteGetObjCSelector(results);
+ selectorString = clang_getCString(objCSelector);
+ if (selectorString && strlen(selectorString) > 0) {
+ printf("Objective-C selector: %s\n", selectorString);
+ }
+ clang_disposeString(objCSelector);
+
clang_disposeCodeCompleteResults(results);
}
clang_disposeTranslationUnit(TU);
@@ -1207,7 +1297,7 @@ typedef struct {
unsigned column;
} CursorSourceLocation;
-int inspect_cursor_at(int argc, const char **argv) {
+static int inspect_cursor_at(int argc, const char **argv) {
CXIndex CIdx;
int errorCode;
struct CXUnsavedFile *unsaved_files = 0;
@@ -1274,7 +1364,13 @@ int inspect_cursor_at(int argc, const char **argv) {
clang_getLocation(TU, file, Locations[Loc].line,
Locations[Loc].column));
if (I + 1 == Repeats) {
- PrintCursor(TU, Cursor);
+ CXCompletionString completionString = clang_getCursorCompletionString(
+ Cursor);
+ PrintCursor(Cursor);
+ if (completionString != NULL) {
+ printf("\nCompletion string: ");
+ print_completion_string(completionString, stdout);
+ }
printf("\n");
free(Locations[Loc].filename);
}
@@ -1289,6 +1385,101 @@ int inspect_cursor_at(int argc, const char **argv) {
return 0;
}
+static enum CXVisitorResult findFileRefsVisit(void *context,
+ CXCursor cursor, CXSourceRange range) {
+ if (clang_Range_isNull(range))
+ return CXVisit_Continue;
+
+ PrintCursor(cursor);
+ PrintRange(range, "");
+ printf("\n");
+ return CXVisit_Continue;
+}
+
+static int find_file_refs_at(int argc, const char **argv) {
+ CXIndex CIdx;
+ int errorCode;
+ struct CXUnsavedFile *unsaved_files = 0;
+ int num_unsaved_files = 0;
+ CXTranslationUnit TU;
+ CXCursor Cursor;
+ CursorSourceLocation *Locations = 0;
+ unsigned NumLocations = 0, Loc;
+ unsigned Repeats = 1;
+ unsigned I;
+
+ /* Count the number of locations. */
+ while (strstr(argv[NumLocations+1], "-file-refs-at=") == argv[NumLocations+1])
+ ++NumLocations;
+
+ /* Parse the locations. */
+ assert(NumLocations > 0 && "Unable to count locations?");
+ Locations = (CursorSourceLocation *)malloc(
+ NumLocations * sizeof(CursorSourceLocation));
+ for (Loc = 0; Loc < NumLocations; ++Loc) {
+ const char *input = argv[Loc + 1] + strlen("-file-refs-at=");
+ if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
+ &Locations[Loc].line,
+ &Locations[Loc].column, 0, 0)))
+ return errorCode;
+ }
+
+ if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files,
+ &num_unsaved_files))
+ return -1;
+
+ if (getenv("CINDEXTEST_EDITING"))
+ Repeats = 5;
+
+ /* 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 + NumLocations,
+ argc - num_unsaved_files - 2 - NumLocations,
+ unsaved_files,
+ Repeats > 1? 0 : num_unsaved_files,
+ getDefaultParsingOptions());
+
+ if (!TU) {
+ fprintf(stderr, "unable to parse input\n");
+ 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;
+ }
+
+ for (Loc = 0; Loc < NumLocations; ++Loc) {
+ CXFile file = clang_getFile(TU, Locations[Loc].filename);
+ if (!file)
+ continue;
+
+ Cursor = clang_getCursor(TU,
+ clang_getLocation(TU, file, Locations[Loc].line,
+ Locations[Loc].column));
+ if (I + 1 == Repeats) {
+ CXCursorAndRangeVisitor visitor = { 0, findFileRefsVisit };
+ PrintCursor(Cursor);
+ printf("\n");
+ clang_findReferencesInFile(Cursor, file, visitor);
+ free(Locations[Loc].filename);
+ }
+ }
+ }
+
+ PrintDiagnostics(TU);
+ clang_disposeTranslationUnit(TU);
+ clang_disposeIndex(CIdx);
+ free(Locations);
+ free_remapped_files(unsaved_files, num_unsaved_files);
+ return 0;
+}
+
int perform_token_annotation(int argc, const char **argv) {
const char *input = argv[1];
char *filename = 0;
@@ -1331,6 +1522,17 @@ int perform_token_annotation(int argc, const char **argv) {
}
errorCode = 0;
+ if (getenv("CINDEXTEST_EDITING")) {
+ for (i = 0; i < 5; ++i) {
+ if (clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
+ clang_defaultReparseOptions(TU))) {
+ fprintf(stderr, "Unable to reparse translation unit!\n");
+ errorCode = -1;
+ goto teardown;
+ }
+ }
+ }
+
file = clang_getFile(TU, filename);
if (!file) {
fprintf(stderr, "file %s is not in this translation unit\n", filename);
@@ -1379,7 +1581,7 @@ int perform_token_annotation(int argc, const char **argv) {
PrintExtent(stdout, start_line, start_column, end_line, end_column);
if (!clang_isInvalid(cursors[i].kind)) {
printf(" ");
- PrintCursor(TU, cursors[i]);
+ PrintCursor(cursors[i]);
}
printf("\n");
}
@@ -1645,8 +1847,10 @@ static void print_usage(void) {
"usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
" c-index-test -code-completion-timing=<site> <compiler arguments>\n"
" c-index-test -cursor-at=<site> <compiler arguments>\n"
+ " c-index-test -file-refs-at=<site> <compiler arguments>\n"
" c-index-test -test-file-scan <AST file> <source file> "
- "[FileCheck prefix]\n"
+ "[FileCheck prefix]\n");
+ fprintf(stderr,
" c-index-test -test-load-tu <AST file> <symbol filter> "
"[FileCheck prefix]\n"
" c-index-test -test-load-tu-usrs <AST file> <symbol filter> "
@@ -1691,6 +1895,8 @@ int cindextest_main(int argc, const char **argv) {
return perform_code_completion(argc, argv, 1);
if (argc > 2 && strstr(argv[1], "-cursor-at=") == argv[1])
return inspect_cursor_at(argc, argv);
+ if (argc > 2 && strstr(argv[1], "-file-refs-at=") == argv[1])
+ return find_file_refs_at(argc, argv);
else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) {
CXCursorVisitor I = GetVisitor(argv[1] + 13);
if (I)
diff --git a/tools/diagtool/CMakeLists.txt b/tools/diagtool/CMakeLists.txt
new file mode 100644
index 000000000000..f1fd9de03be0
--- /dev/null
+++ b/tools/diagtool/CMakeLists.txt
@@ -0,0 +1,24 @@
+set( LLVM_LINK_COMPONENTS
+ support
+ )
+
+set( LLVM_USED_LIBS
+ clangBasic
+ clangLex
+ clangSema
+ )
+
+add_clang_executable(diagtool
+ diagtool_main.cpp
+ DiagTool.cpp
+ ListWarnings.cpp
+)
+
+if(UNIX)
+ set(CLANGXX_LINK_OR_COPY create_symlink)
+else()
+ set(CLANGXX_LINK_OR_COPY copy)
+endif()
+
+install(TARGETS diagtool
+ RUNTIME DESTINATION bin)
diff --git a/tools/diagtool/DiagTool.cpp b/tools/diagtool/DiagTool.cpp
new file mode 100644
index 000000000000..36e72a2ded5a
--- /dev/null
+++ b/tools/diagtool/DiagTool.cpp
@@ -0,0 +1,68 @@
+//===- DiagTool.cpp - Classes for defining diagtool tools -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the boilerplate for defining diagtool tools.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DiagTool.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/SmallString.h"
+#include <vector>
+
+using namespace diagtool;
+
+DiagTool::DiagTool(llvm::StringRef toolCmd,
+ llvm::StringRef toolDesc)
+ : cmd(toolCmd), description(toolDesc) {}
+
+DiagTool::~DiagTool() {}
+
+typedef llvm::StringMap<DiagTool *> ToolMap;
+static inline ToolMap *getTools(void *v) { return static_cast<ToolMap*>(v); }
+
+DiagTools::DiagTools() : tools(new ToolMap()) {}
+DiagTools::~DiagTools() { delete getTools(tools); }
+
+DiagTool *DiagTools::getTool(llvm::StringRef toolCmd) {
+ ToolMap::iterator it = getTools(tools)->find(toolCmd);
+ return (it == getTools(tools)->end()) ? 0 : it->getValue();
+}
+
+void DiagTools::registerTool(DiagTool *tool) {
+ getTools(tools)->GetOrCreateValue(tool->getName(), tool);
+}
+
+void DiagTools::printCommands(llvm::raw_ostream &out) {
+ std::vector<llvm::StringRef> toolNames;
+ unsigned maxName = 0;
+ for (ToolMap::iterator it = getTools(tools)->begin(),
+ ei = getTools(tools)->end(); it != ei; ++it) {
+ toolNames.push_back(it->getKey());
+ unsigned len = it->getKey().size();
+ if (len > maxName)
+ maxName = len;
+ }
+ std::sort(toolNames.begin(), toolNames.end());
+
+ for (std::vector<llvm::StringRef>::iterator it = toolNames.begin(),
+ ei = toolNames.end(); it != ei; ++it) {
+
+ out << " " << (*it);
+ unsigned spaces = (maxName + 3) - (it->size());
+ for (unsigned i = 0; i < spaces; ++i)
+ out << ' ';
+
+ out << getTool(*it)->getDescription() << '\n';
+ }
+}
+
+namespace diagtool {
+ llvm::ManagedStatic<DiagTools> diagTools;
+}
diff --git a/tools/diagtool/DiagTool.h b/tools/diagtool/DiagTool.h
new file mode 100644
index 000000000000..dcb6ac7c76cb
--- /dev/null
+++ b/tools/diagtool/DiagTool.h
@@ -0,0 +1,70 @@
+//===- DiagTool.h - Classes for defining diagtool tools -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the boilerplate for defining diagtool tools.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef DIAGTOOL_DIAGTOOL_H
+#define DIAGTOOL_DIAGTOOL_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/ManagedStatic.h"
+#include <string>
+
+
+namespace diagtool {
+
+class DiagTool {
+ const std::string cmd;
+ const std::string description;
+public:
+ DiagTool(llvm::StringRef toolCmd, llvm::StringRef toolDesc);
+ virtual ~DiagTool();
+
+ llvm::StringRef getName() const { return cmd; }
+ llvm::StringRef getDescription() const { return description; }
+
+ virtual int run(unsigned argc, char *argv[], llvm::raw_ostream &out) = 0;
+};
+
+class DiagTools {
+ void *tools;
+public:
+ DiagTools();
+ ~DiagTools();
+
+ DiagTool *getTool(llvm::StringRef toolCmd);
+ void registerTool(DiagTool *tool);
+ void printCommands(llvm::raw_ostream &out);
+};
+
+extern llvm::ManagedStatic<DiagTools> diagTools;
+
+template <typename DIAGTOOL>
+class RegisterDiagTool {
+public:
+ RegisterDiagTool() { diagTools->registerTool(new DIAGTOOL()); }
+};
+
+} // end diagtool namespace
+
+#define DEF_DIAGTOOL(NAME, DESC, CLSNAME)\
+namespace {\
+class CLSNAME : public diagtool::DiagTool {\
+public:\
+ CLSNAME() : DiagTool(NAME, DESC) {}\
+ virtual ~CLSNAME() {}\
+ virtual int run(unsigned argc, char *argv[], llvm::raw_ostream &out);\
+};\
+diagtool::RegisterDiagTool<CLSNAME> Register##CLSNAME;\
+}
+
+#endif
diff --git a/tools/diagtool/ListWarnings.cpp b/tools/diagtool/ListWarnings.cpp
new file mode 100644
index 000000000000..7f7db8ef10b6
--- /dev/null
+++ b/tools/diagtool/ListWarnings.cpp
@@ -0,0 +1,106 @@
+//===- ListWarnings.h - diagtool tool for printing warning flags ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides a diagtool tool that displays warning flags for
+// diagnostics.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DiagTool.h"
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/Support/Format.h"
+#include "llvm/ADT/StringMap.h"
+
+DEF_DIAGTOOL("list-warnings",
+ "List warnings and their corresponding flags",
+ ListWarnings)
+
+using namespace clang;
+
+
+namespace {
+struct Entry {
+ llvm::StringRef DiagName;
+ llvm::StringRef Flag;
+
+ Entry(llvm::StringRef diagN, llvm::StringRef flag)
+ : DiagName(diagN), Flag(flag) {}
+
+ bool operator<(const Entry &x) const { return DiagName < x.DiagName; }
+};
+}
+
+static void printEntries(std::vector<Entry> &entries, llvm::raw_ostream &out) {
+ for (std::vector<Entry>::iterator it = entries.begin(), ei = entries.end();
+ it != ei; ++it) {
+ out << " " << it->DiagName;
+ if (!it->Flag.empty())
+ out << " [-W" << it->Flag << "]";
+ out << '\n';
+ }
+}
+
+int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
+ llvm::IntrusiveRefCntPtr<DiagnosticIDs> Diags(new DiagnosticIDs);
+ DiagnosticsEngine D(Diags);
+
+ std::vector<Entry> Flagged, Unflagged;
+ llvm::StringMap<std::vector<unsigned> > flagHistogram;
+
+ for (DiagnosticIDs::diag_iterator di = DiagnosticIDs::diags_begin(),
+ de = DiagnosticIDs::diags_end(); di != de; ++di) {
+
+ unsigned diagID = di.getDiagID();
+
+ if (DiagnosticIDs::isBuiltinNote(diagID))
+ continue;
+
+ if (!DiagnosticIDs::isBuiltinWarningOrExtension(diagID))
+ continue;
+
+ Entry entry(di.getDiagName(),
+ DiagnosticIDs::getWarningOptionForDiag(diagID));
+
+ if (entry.Flag.empty())
+ Unflagged.push_back(entry);
+ else {
+ Flagged.push_back(entry);
+ flagHistogram.GetOrCreateValue(entry.Flag).getValue().push_back(diagID);
+ }
+ }
+
+ std::sort(Flagged.begin(), Flagged.end());
+ std::sort(Unflagged.begin(), Unflagged.end());
+
+ out << "Warnings with flags (" << Flagged.size() << "):\n";
+ printEntries(Flagged, out);
+
+ out << "Warnings without flags (" << Unflagged.size() << "):\n";
+ printEntries(Unflagged, out);
+
+ out << "\nSTATISTICS:\n\n";
+
+ double percentFlagged = ((double) Flagged.size())
+ / (Flagged.size() + Unflagged.size()) * 100.0;
+
+ out << " Percentage of warnings with flags: "
+ << llvm::format("%.4g",percentFlagged) << "%\n";
+
+ out << " Number of unique flags: "
+ << flagHistogram.size() << '\n';
+
+ double avgDiagsPerFlag = (double) Flagged.size() / flagHistogram.size();
+ out << " Average number of diagnostics per flag: "
+ << llvm::format("%.4g", avgDiagsPerFlag) << '\n';
+
+ out << '\n';
+
+ return 0;
+}
+
diff --git a/tools/diagtool/Makefile b/tools/diagtool/Makefile
new file mode 100644
index 000000000000..22d74110e444
--- /dev/null
+++ b/tools/diagtool/Makefile
@@ -0,0 +1,25 @@
+##===- tools/driver/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 = diagtool
+
+# No plugins, optimize startup time.
+TOOL_NO_EXPORTS := 1
+
+# Don't install this.
+NO_INSTALL = 1
+
+LINK_COMPONENTS := support
+
+USEDLIBS = clangCodeGen.a clangParse.a clangSema.a \
+ clangAST.a clangLex.a clangBasic.a
+
+include $(CLANG_LEVEL)/Makefile
+
diff --git a/tools/diagtool/diagtool_main.cpp b/tools/diagtool/diagtool_main.cpp
new file mode 100644
index 000000000000..e34f0dc06c65
--- /dev/null
+++ b/tools/diagtool/diagtool_main.cpp
@@ -0,0 +1,26 @@
+//===- diagtool_main.h - Entry point for invoking all diagnostic tools ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the main function for diagtool.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DiagTool.h"
+
+using namespace diagtool;
+
+int main(int argc, char *argv[]) {
+ if (argc > 1)
+ if (DiagTool *tool = diagTools->getTool(argv[1]))
+ return tool->run(argc - 1, &argv[2], llvm::errs());
+
+ llvm::errs() << "usage: diagtool <command> [<args>]\n\n";
+ diagTools->printCommands(llvm::errs());
+ return 1;
+}
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index 1ba8bc24d1fb..6b34a991bf18 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -9,13 +9,7 @@
CLANG_LEVEL := ../..
TOOLNAME = clang
-ifndef CLANG_IS_PRODUCTION
TOOLALIAS = clang++
-else
- ifdef CLANGXX_IS_PRODUCTION
- TOOLALIAS = clang++
- endif
-endif
# We don't currently expect production Clang builds to be interested in
# plugins. This is important for startup performance.
@@ -73,6 +67,3 @@ endif
ifdef CLANG_IS_PRODUCTION
CPP.Defines += -DCLANG_IS_PRODUCTION
endif
-ifdef CLANGXX_IS_PRODUCTION
-CPP.Defines += -DCLANGXX_IS_PRODUCTION
-endif
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index 9ad4af1436ca..27f79b7e6677 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -27,9 +27,9 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetSelect.h"
#include <cstdio>
using namespace clang;
@@ -38,7 +38,7 @@ using namespace clang;
//===----------------------------------------------------------------------===//
static void LLVMErrorHandler(void *UserData, const std::string &Message) {
- Diagnostic &Diags = *static_cast<Diagnostic*>(UserData);
+ DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
Diags.Report(diag::err_fe_error_backend) << Message;
@@ -47,7 +47,7 @@ static void LLVMErrorHandler(void *UserData, const std::string &Message) {
}
// FIXME: Define the need for this testing away.
-static int cc1_test(Diagnostic &Diags,
+static int cc1_test(DiagnosticsEngine &Diags,
const char **ArgBegin, const char **ArgEnd) {
using namespace clang::driver;
@@ -83,7 +83,7 @@ static int cc1_test(Diagnostic &Diags,
Invocation.toArgs(InvocationArgs);
// Dump the converted arguments.
- llvm::SmallVector<const char*, 32> Invocation2Args;
+ SmallVector<const char*, 32> Invocation2Args;
llvm::errs() << "invocation argv :";
for (unsigned i = 0, e = InvocationArgs.size(); i != e; ++i) {
Invocation2Args.push_back(InvocationArgs[i].c_str());
@@ -118,23 +118,22 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
// Run clang -cc1 test.
- if (ArgBegin != ArgEnd && llvm::StringRef(ArgBegin[0]) == "-cc1test") {
- Diagnostic Diags(DiagID, new TextDiagnosticPrinter(llvm::errs(),
+ if (ArgBegin != ArgEnd && StringRef(ArgBegin[0]) == "-cc1test") {
+ DiagnosticsEngine Diags(DiagID, new TextDiagnosticPrinter(llvm::errs(),
DiagnosticOptions()));
return cc1_test(Diags, ArgBegin + 1, ArgEnd);
}
// Initialize targets first, so that --version shows registered targets.
llvm::InitializeAllTargets();
- llvm::InitializeAllMCAsmInfos();
- llvm::InitializeAllMCSubtargetInfos();
+ llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmPrinters();
llvm::InitializeAllAsmParsers();
// Buffer diagnostics from argument parsing so that we can output them using a
// well formed diagnostic object.
TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
- Diagnostic Diags(DiagID, DiagsBuffer);
+ DiagnosticsEngine Diags(DiagID, DiagsBuffer);
CompilerInvocation::CreateFromArgs(Clang->getInvocation(), ArgBegin, ArgEnd,
Diags);
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index 358d746986c8..7cc42aa62768 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -30,8 +30,12 @@
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCTargetAsmParser.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/ErrorHandling.h"
@@ -39,23 +43,15 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/SourceMgr.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/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 "llvm/Target/TargetAsmBackend.h"
-#include "llvm/Target/TargetAsmInfo.h"
-#include "llvm/Target/TargetAsmParser.h"
#include "llvm/Target/TargetData.h"
-#include "llvm/Target/TargetInstrInfo.h"
-#include "llvm/Target/TargetLowering.h"
-#include "llvm/Target/TargetLoweringObjectFile.h"
-#include "llvm/Target/TargetMachine.h"
-#include "llvm/Target/TargetRegistry.h"
-#include "llvm/Target/TargetSelect.h"
-#include "llvm/Target/TargetSubtargetInfo.h"
using namespace clang;
using namespace clang::driver;
using namespace llvm;
@@ -125,7 +121,7 @@ public:
}
static void CreateFromArgs(AssemblerInvocation &Res, const char **ArgBegin,
- const char **ArgEnd, Diagnostic &Diags);
+ const char **ArgEnd, DiagnosticsEngine &Diags);
};
}
@@ -133,7 +129,7 @@ public:
void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
const char **ArgBegin,
const char **ArgEnd,
- Diagnostic &Diags) {
+ DiagnosticsEngine &Diags) {
using namespace clang::driver::cc1asoptions;
// Parse the arguments.
OwningPtr<OptTable> OptTbl(createCC1AsOptTable());
@@ -207,7 +203,7 @@ void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
}
static formatted_raw_ostream *GetOutputStream(AssemblerInvocation &Opts,
- Diagnostic &Diags,
+ DiagnosticsEngine &Diags,
bool Binary) {
if (Opts.OutputPath.empty())
Opts.OutputPath = "-";
@@ -230,7 +226,8 @@ static formatted_raw_ostream *GetOutputStream(AssemblerInvocation &Opts,
return new formatted_raw_ostream(*Out, formatted_raw_ostream::DELETE_STREAM);
}
-static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) {
+static bool ExecuteAssembler(AssemblerInvocation &Opts,
+ DiagnosticsEngine &Diags) {
// Get the target specific parser.
std::string Error;
const Target *TheTarget(TargetRegistry::lookupTarget(Opts.Triple, Error));
@@ -259,64 +256,60 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) {
OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(Opts.Triple));
assert(MAI && "Unable to create target asm info!");
+ OwningPtr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(Opts.Triple));
+ assert(MRI && "Unable to create target register info!");
+
bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
formatted_raw_ostream *Out = GetOutputStream(Opts, Diags, IsBinary);
if (!Out)
return false;
- // FIXME: We shouldn't need to do this (and link in codegen).
- OwningPtr<TargetMachine> TM(TheTarget->createTargetMachine(Opts.Triple,
- "", ""));
- if (!TM) {
- Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
- return false;
- }
-
- const TargetAsmInfo *tai = new TargetAsmInfo(*TM);
- MCContext Ctx(*MAI, tai);
+ // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
+ // MCObjectFileInfo needs a MCContext reference in order to initialize itself.
+ OwningPtr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
+ MCContext Ctx(*MAI, *MRI, MOFI.get());
+ // FIXME: Assembler behavior can change with -static.
+ MOFI->InitMCObjectFileInfo(Opts.Triple,
+ Reloc::Default, CodeModel::Default, Ctx);
if (Opts.SaveTemporaryLabels)
Ctx.setAllowTemporaryLabels(false);
OwningPtr<MCStreamer> Str;
- const TargetLoweringObjectFile &TLOF =
- TM->getTargetLowering()->getObjFileLowering();
- const_cast<TargetLoweringObjectFile&>(TLOF).Initialize(Ctx, *TM);
-
- const MCSubtargetInfo &STI = TM->getSubtarget<MCSubtargetInfo>();
+ OwningPtr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
+ OwningPtr<MCSubtargetInfo>
+ STI(TheTarget->createMCSubtargetInfo(Opts.Triple, "", ""));
// FIXME: There is a bit of code duplication with addPassesToEmitFile.
if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
MCInstPrinter *IP =
- TheTarget->createMCInstPrinter(Opts.OutputAsmVariant, *MAI);
+ TheTarget->createMCInstPrinter(Opts.OutputAsmVariant, *MAI, *STI);
MCCodeEmitter *CE = 0;
- TargetAsmBackend *TAB = 0;
+ MCAsmBackend *MAB = 0;
if (Opts.ShowEncoding) {
- CE = TheTarget->createCodeEmitter(*TM->getInstrInfo(), STI, Ctx);
- TAB = TheTarget->createAsmBackend(Opts.Triple);
+ CE = TheTarget->createMCCodeEmitter(*MCII, *STI, Ctx);
+ MAB = TheTarget->createMCAsmBackend(Opts.Triple);
}
Str.reset(TheTarget->createAsmStreamer(Ctx, *Out, /*asmverbose*/true,
/*useLoc*/ true,
- /*useCFI*/ true, IP, CE, TAB,
+ /*useCFI*/ true, IP, CE, MAB,
Opts.ShowInst));
} else if (Opts.OutputType == AssemblerInvocation::FT_Null) {
Str.reset(createNullStreamer(Ctx));
} else {
assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
"Invalid file type!");
- MCCodeEmitter *CE = TheTarget->createCodeEmitter(*TM->getInstrInfo(),
- STI, Ctx);
- TargetAsmBackend *TAB = TheTarget->createAsmBackend(Opts.Triple);
- Str.reset(TheTarget->createObjectStreamer(Opts.Triple, Ctx, *TAB, *Out,
- CE, Opts.RelaxAll,
- Opts.NoExecStack));
+ MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *STI, Ctx);
+ MCAsmBackend *MAB = TheTarget->createMCAsmBackend(Opts.Triple);
+ Str.reset(TheTarget->createMCObjectStreamer(Opts.Triple, Ctx, *MAB, *Out,
+ CE, Opts.RelaxAll,
+ Opts.NoExecStack));
Str.get()->InitSections();
}
- OwningPtr<MCAsmParser> Parser(createMCAsmParser(*TheTarget, SrcMgr, Ctx,
+ OwningPtr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx,
*Str.get(), *MAI));
- OwningPtr<TargetAsmParser>
- TAP(TheTarget->createAsmParser(const_cast<MCSubtargetInfo&>(STI), *Parser));
+ OwningPtr<MCTargetAsmParser> TAP(TheTarget->createMCAsmParser(*STI, *Parser));
if (!TAP) {
Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
return false;
@@ -337,7 +330,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) {
}
static void LLVMErrorHandler(void *UserData, const std::string &Message) {
- Diagnostic &Diags = *static_cast<Diagnostic*>(UserData);
+ DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
Diags.Report(diag::err_fe_error_backend) << Message;
@@ -354,12 +347,7 @@ int cc1as_main(const char **ArgBegin, const char **ArgEnd,
// Initialize targets and assembly printers/parsers.
InitializeAllTargetInfos();
- // FIXME: We shouldn't need to initialize the Target(Machine)s.
- InitializeAllTargets();
- InitializeAllMCAsmInfos();
- InitializeAllMCInstrInfos();
- InitializeAllMCSubtargetInfos();
- InitializeAllAsmPrinters();
+ InitializeAllTargetMCs();
InitializeAllAsmParsers();
// Construct our diagnostic client.
@@ -367,7 +355,7 @@ int cc1as_main(const char **ArgBegin, const char **ArgEnd,
= new TextDiagnosticPrinter(errs(), DiagnosticOptions());
DiagClient->setPrefix("clang -cc1as");
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- Diagnostic Diags(DiagID, DiagClient);
+ DiagnosticsEngine Diags(DiagID, DiagClient);
// Set an error handler, so that any LLVM backend diagnostics go through our
// error handler.
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index ca8982619e94..bd1d2a2f5f35 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -35,9 +35,9 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/system_error.h"
-#include "llvm/Target/TargetRegistry.h"
-#include "llvm/Target/TargetSelect.h"
#include <cctype>
using namespace clang;
using namespace clang::driver;
@@ -53,7 +53,7 @@ llvm::sys::Path GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
}
static const char *SaveStringInSet(std::set<std::string> &SavedStrings,
- llvm::StringRef S) {
+ StringRef S) {
return SavedStrings.insert(S).first->c_str();
}
@@ -84,9 +84,9 @@ static const char *SaveStringInSet(std::set<std::string> &SavedStrings,
/// \param Args - The vector of command line arguments.
/// \param Edit - The override command to perform.
/// \param SavedStrings - Set to use for storing string representations.
-static void ApplyOneQAOverride(llvm::raw_ostream &OS,
- llvm::SmallVectorImpl<const char*> &Args,
- llvm::StringRef Edit,
+static void ApplyOneQAOverride(raw_ostream &OS,
+ SmallVectorImpl<const char*> &Args,
+ StringRef Edit,
std::set<std::string> &SavedStrings) {
// This does not need to be efficient.
@@ -101,9 +101,9 @@ static void ApplyOneQAOverride(llvm::raw_ostream &OS,
OS << "### Adding argument " << Str << " at end\n";
Args.push_back(Str);
} else if (Edit[0] == 's' && Edit[1] == '/' && Edit.endswith("/") &&
- Edit.slice(2, Edit.size()-1).find('/') != llvm::StringRef::npos) {
- llvm::StringRef MatchPattern = Edit.substr(2).split('/').first;
- llvm::StringRef ReplPattern = Edit.substr(2).split('/').second;
+ Edit.slice(2, Edit.size()-1).find('/') != StringRef::npos) {
+ StringRef MatchPattern = Edit.substr(2).split('/').first;
+ StringRef ReplPattern = Edit.substr(2).split('/').second;
ReplPattern = ReplPattern.slice(0, ReplPattern.size()-1);
for (unsigned i = 1, e = Args.size(); i != e; ++i) {
@@ -151,10 +151,10 @@ static void ApplyOneQAOverride(llvm::raw_ostream &OS,
/// ApplyQAOverride - Apply a comma separate list of edits to the
/// input argument lists. See ApplyOneQAOverride.
-static void ApplyQAOverride(llvm::SmallVectorImpl<const char*> &Args,
+static void ApplyQAOverride(SmallVectorImpl<const char*> &Args,
const char *OverrideStr,
std::set<std::string> &SavedStrings) {
- llvm::raw_ostream *OS = &llvm::errs();
+ raw_ostream *OS = &llvm::errs();
if (OverrideStr[0] == '#') {
++OverrideStr;
@@ -184,7 +184,7 @@ extern int cc1as_main(const char **ArgBegin, const char **ArgEnd,
const char *Argv0, void *MainAddr);
static void ExpandArgsFromBuf(const char *Arg,
- llvm::SmallVectorImpl<const char*> &ArgVector,
+ SmallVectorImpl<const char*> &ArgVector,
std::set<std::string> &SavedStrings) {
const char *FName = Arg + 1;
llvm::OwningPtr<llvm::MemoryBuffer> MemBuf;
@@ -242,7 +242,7 @@ static void ExpandArgsFromBuf(const char *Arg,
}
static void ExpandArgv(int argc, const char **argv,
- llvm::SmallVectorImpl<const char*> &ArgVector,
+ SmallVectorImpl<const char*> &ArgVector,
std::set<std::string> &SavedStrings) {
for (int i = 0; i < argc; ++i) {
const char *Arg = argv[i];
@@ -255,7 +255,7 @@ static void ExpandArgv(int argc, const char **argv,
}
}
-static void ParseProgName(llvm::SmallVectorImpl<const char *> &ArgVector,
+static void ParseProgName(SmallVectorImpl<const char *> &ArgVector,
std::set<std::string> &SavedStrings,
Driver &TheDriver)
{
@@ -290,8 +290,8 @@ static void ParseProgName(llvm::SmallVectorImpl<const char *> &ArgVector,
{ "++", true, false },
};
std::string ProgName(llvm::sys::path::stem(ArgVector[0]));
- llvm::StringRef ProgNameRef(ProgName);
- llvm::StringRef Prefix;
+ StringRef ProgNameRef(ProgName);
+ StringRef Prefix;
for (int Components = 2; Components; --Components) {
bool FoundMatch = false;
@@ -309,15 +309,15 @@ static void ParseProgName(llvm::SmallVectorImpl<const char *> &ArgVector,
}
if (FoundMatch) {
- llvm::StringRef::size_type LastComponent = ProgNameRef.rfind('-',
+ StringRef::size_type LastComponent = ProgNameRef.rfind('-',
ProgNameRef.size() - strlen(suffixes[i].Suffix));
- if (LastComponent != llvm::StringRef::npos)
+ if (LastComponent != StringRef::npos)
Prefix = ProgNameRef.slice(0, LastComponent);
break;
}
- llvm::StringRef::size_type LastComponent = ProgNameRef.rfind('-');
- if (LastComponent == llvm::StringRef::npos)
+ StringRef::size_type LastComponent = ProgNameRef.rfind('-');
+ if (LastComponent == StringRef::npos)
break;
ProgNameRef = ProgNameRef.slice(0, LastComponent);
}
@@ -327,7 +327,7 @@ static void ParseProgName(llvm::SmallVectorImpl<const char *> &ArgVector,
std::string IgnoredError;
if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) {
- llvm::SmallVectorImpl<const char *>::iterator it = ArgVector.begin();
+ SmallVectorImpl<const char *>::iterator it = ArgVector.begin();
if (it != ArgVector.end())
++it;
ArgVector.insert(it, SaveStringInSet(SavedStrings, Prefix));
@@ -341,13 +341,13 @@ int main(int argc_, const char **argv_) {
llvm::PrettyStackTraceProgram X(argc_, argv_);
std::set<std::string> SavedStrings;
- llvm::SmallVector<const char*, 256> argv;
+ SmallVector<const char*, 256> argv;
ExpandArgv(argc_, argv_, argv, SavedStrings);
// Handle -cc1 integrated tools.
- if (argv.size() > 1 && llvm::StringRef(argv[1]).startswith("-cc1")) {
- llvm::StringRef Tool = argv[1] + 4;
+ if (argv.size() > 1 && StringRef(argv[1]).startswith("-cc1")) {
+ StringRef Tool = argv[1] + 4;
if (Tool == "")
return cc1_main(argv.data()+2, argv.data()+argv.size(), argv[0],
@@ -363,7 +363,7 @@ int main(int argc_, const char **argv_) {
bool CanonicalPrefixes = true;
for (int i = 1, size = argv.size(); i < size; ++i) {
- if (llvm::StringRef(argv[i]) == "-no-canonical-prefixes") {
+ if (StringRef(argv[i]) == "-no-canonical-prefixes") {
CanonicalPrefixes = false;
break;
}
@@ -375,22 +375,15 @@ int main(int argc_, const char **argv_) {
= new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
DiagClient->setPrefix(llvm::sys::path::stem(Path.str()));
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- Diagnostic Diags(DiagID, DiagClient);
+ DiagnosticsEngine Diags(DiagID, DiagClient);
#ifdef CLANG_IS_PRODUCTION
const bool IsProduction = true;
-# ifdef CLANGXX_IS_PRODUCTION
- const bool CXXIsProduction = true;
-# else
- const bool CXXIsProduction = false;
-# endif
#else
const bool IsProduction = false;
- const bool CXXIsProduction = false;
#endif
Driver TheDriver(Path.str(), llvm::sys::getHostTriple(),
- "a.out", IsProduction, CXXIsProduction,
- Diags);
+ "a.out", IsProduction, 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
@@ -458,9 +451,15 @@ int main(int argc_, const char **argv_) {
llvm::OwningPtr<Compilation> C(TheDriver.BuildCompilation(argv));
int Res = 0;
+ const Command *FailingCommand = 0;
if (C.get())
- Res = TheDriver.ExecuteCompilation(*C);
-
+ Res = TheDriver.ExecuteCompilation(*C, 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);
+
// If any timers were active but haven't been destroyed yet, print their
// results now. This happens in -disable-free mode.
llvm::TimerGroup::printAll(llvm::errs());
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 50d56fccb9c5..46ba3d55340d 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -51,8 +51,9 @@
using namespace clang;
using namespace clang::cxcursor;
using namespace clang::cxstring;
+using namespace clang::cxtu;
-static CXTranslationUnit MakeCXTranslationUnit(ASTUnit *TU) {
+CXTranslationUnit cxtu::MakeCXTranslationUnit(ASTUnit *TU) {
if (!TU)
return 0;
CXTranslationUnit D = new CXTranslationUnitImpl();
@@ -117,10 +118,10 @@ CXSourceRange cxloc::translateSourceRange(const SourceManager &SM,
// location accordingly.
SourceLocation EndLoc = R.getEnd();
if (EndLoc.isValid() && EndLoc.isMacroID())
- EndLoc = SM.getInstantiationRange(EndLoc).second;
+ EndLoc = SM.getExpansionRange(EndLoc).second;
if (R.isTokenRange() && !EndLoc.isInvalid() && EndLoc.isFileID()) {
unsigned Length = Lexer::MeasureTokenLength(EndLoc, SM, LangOpts);
- EndLoc = EndLoc.getFileLocWithOffset(Length);
+ EndLoc = EndLoc.getLocWithOffset(Length);
}
CXSourceRange Result = { { (void *)&SM, (void *)&LangOpts },
@@ -141,7 +142,6 @@ public:
TypeLocVisitKind, OverloadExprPartsKind,
DeclRefExprPartsKind, LabelRefVisitKind,
ExplicitTemplateArgsVisitKind,
- NestedNameSpecifierVisitKind,
NestedNameSpecifierLocVisitKind,
DeclarationNameInfoVisitKind,
MemberRefVisitKind, SizeOfPackExprPartsKind };
@@ -161,7 +161,7 @@ public:
static bool classof(VisitorJob *VJ) { return true; }
};
-typedef llvm::SmallVector<VisitorJob, 10> VisitorWorkList;
+typedef SmallVector<VisitorJob, 10> VisitorWorkList;
// Cursor visitor.
class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
@@ -184,11 +184,6 @@ class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
/// \brief The opaque client data, to be passed along to the visitor.
CXClientData ClientData;
- // MaxPCHLevel - the maximum PCH level of declarations that we will pass on
- // to the visitor. Declarations with a PCH level greater than this value will
- // be suppressed.
- unsigned MaxPCHLevel;
-
/// \brief Whether we should visit the preprocessing record entries last,
/// after visiting other declarations.
bool VisitPreprocessorLast;
@@ -203,8 +198,8 @@ class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
DeclContext::decl_iterator DE_current;
// Cache of pre-allocated worklists for data-recursion walk of Stmts.
- llvm::SmallVector<VisitorWorkList*, 5> WorkListFreeList;
- llvm::SmallVector<VisitorWorkList*, 5> WorkListCache;
+ SmallVector<VisitorWorkList*, 5> WorkListFreeList;
+ SmallVector<VisitorWorkList*, 5> WorkListCache;
using DeclVisitor<CursorVisitor, bool>::Visit;
using TypeLocVisitor<CursorVisitor, bool>::Visit;
@@ -239,12 +234,11 @@ class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
public:
CursorVisitor(CXTranslationUnit TU, CXCursorVisitor Visitor,
CXClientData ClientData,
- unsigned MaxPCHLevel,
bool VisitPreprocessorLast,
SourceRange RegionOfInterest = SourceRange())
: TU(TU), AU(static_cast<ASTUnit*>(TU->TUData)),
Visitor(Visitor), ClientData(ClientData),
- MaxPCHLevel(MaxPCHLevel), VisitPreprocessorLast(VisitPreprocessorLast),
+ VisitPreprocessorLast(VisitPreprocessorLast),
RegionOfInterest(RegionOfInterest), DI_current(0)
{
Parent.kind = CXCursor_NoDeclFound;
@@ -256,7 +250,7 @@ public:
~CursorVisitor() {
// Free the pre-allocated worklists for data-recursion.
- for (llvm::SmallVectorImpl<VisitorWorkList*>::iterator
+ for (SmallVectorImpl<VisitorWorkList*>::iterator
I = WorkListCache.begin(), E = WorkListCache.end(); I != E; ++I) {
delete *I;
}
@@ -267,8 +261,10 @@ public:
bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false);
- std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
- getPreprocessedEntities();
+ bool visitPreprocessedEntitiesInRegion();
+
+ template<typename InputIterator>
+ bool visitPreprocessedEntities(InputIterator First, InputIterator Last);
bool VisitChildren(CXCursor Parent);
@@ -327,35 +323,15 @@ public:
bool VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL);
// Type visitors
- bool VisitQualifiedTypeLoc(QualifiedTypeLoc TL);
- bool VisitBuiltinTypeLoc(BuiltinTypeLoc TL);
- bool VisitTypedefTypeLoc(TypedefTypeLoc TL);
- bool VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL);
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc);
+#include "clang/AST/TypeLocNodes.def"
+
bool VisitTagTypeLoc(TagTypeLoc TL);
- bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL);
- bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL);
- bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL);
- bool VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL);
- bool VisitParenTypeLoc(ParenTypeLoc TL);
- bool VisitPointerTypeLoc(PointerTypeLoc TL);
- bool VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL);
- bool VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL);
- bool VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL);
- bool VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL);
- bool VisitFunctionTypeLoc(FunctionTypeLoc TL, bool SkipResultType = false);
bool VisitArrayTypeLoc(ArrayTypeLoc TL);
- bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL);
- // FIXME: Implement visitors here when the unimplemented TypeLocs get
- // implemented
- bool VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL);
- bool VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL);
- bool VisitTypeOfTypeLoc(TypeOfTypeLoc TL);
- bool VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL);
- bool VisitDependentNameTypeLoc(DependentNameTypeLoc TL);
- bool VisitDependentTemplateSpecializationTypeLoc(
- DependentTemplateSpecializationTypeLoc TL);
- bool VisitElaboratedTypeLoc(ElaboratedTypeLoc TL);
-
+ bool VisitFunctionTypeLoc(FunctionTypeLoc TL, bool SkipResultType = false);
+
// Data-recursive visitor functions.
bool IsInRegionOfInterest(CXCursor C);
bool RunVisitorWorkList(VisitorWorkList &WL);
@@ -390,10 +366,9 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) {
if (clang_isDeclaration(Cursor.kind)) {
Decl *D = getCursorDecl(Cursor);
assert(D && "Invalid declaration cursor");
- if (D->getPCHLevel() > MaxPCHLevel)
- return false;
-
- if (D->isImplicit())
+ // Ignore implicit declarations, unless it's an objc method because
+ // currently we should report implicit methods for properties when indexing.
+ if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
return false;
}
@@ -419,65 +394,53 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) {
return false;
}
-std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
-CursorVisitor::getPreprocessedEntities() {
+bool CursorVisitor::visitPreprocessedEntitiesInRegion() {
PreprocessingRecord &PPRec
= *AU->getPreprocessor().getPreprocessingRecord();
+ if (RegionOfInterest.isValid()) {
+ SourceRange MappedRange = AU->mapRangeToPreamble(RegionOfInterest);
+ std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+ Entities = PPRec.getPreprocessedEntitiesInRange(MappedRange);
+ return visitPreprocessedEntities(Entities.first, Entities.second);
+ }
+
bool OnlyLocalDecls
= !AU->isMainFileAST() && AU->getOnlyLocalDecls();
- if (OnlyLocalDecls && RegionOfInterest.isValid()) {
- // If we would only look at local declarations but we have a region of
- // interest, check whether that region of interest is in the main file.
- // If not, we should traverse all declarations.
- // FIXME: My kingdom for a proper binary search approach to finding
- // cursors!
- std::pair<FileID, unsigned> Location
- = AU->getSourceManager().getDecomposedInstantiationLoc(
- RegionOfInterest.getBegin());
- if (Location.first != AU->getSourceManager().getMainFileID())
- OnlyLocalDecls = false;
- }
-
- PreprocessingRecord::iterator StartEntity, EndEntity;
- if (OnlyLocalDecls) {
- StartEntity = AU->pp_entity_begin();
- EndEntity = AU->pp_entity_end();
- } else {
- StartEntity = PPRec.begin();
- EndEntity = PPRec.end();
- }
-
- // There is no region of interest; we have to walk everything.
- if (RegionOfInterest.isInvalid())
- return std::make_pair(StartEntity, EndEntity);
-
- // Find the file in which the region of interest lands.
- SourceManager &SM = AU->getSourceManager();
- std::pair<FileID, unsigned> Begin
- = SM.getDecomposedInstantiationLoc(RegionOfInterest.getBegin());
- std::pair<FileID, unsigned> End
- = SM.getDecomposedInstantiationLoc(RegionOfInterest.getEnd());
-
- // The region of interest spans files; we have to walk everything.
- if (Begin.first != End.first)
- return std::make_pair(StartEntity, EndEntity);
+ if (OnlyLocalDecls)
+ return visitPreprocessedEntities(PPRec.local_begin(), PPRec.local_end());
+
+ return visitPreprocessedEntities(PPRec.begin(), PPRec.end());
+}
+
+template<typename InputIterator>
+bool CursorVisitor::visitPreprocessedEntities(InputIterator First,
+ InputIterator Last) {
+ for (; First != Last; ++First) {
+ if (MacroExpansion *ME = dyn_cast<MacroExpansion>(*First)) {
+ if (Visit(MakeMacroExpansionCursor(ME, TU)))
+ return true;
+
+ continue;
+ }
+
+ if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*First)) {
+ if (Visit(MakeMacroDefinitionCursor(MD, TU)))
+ return true;
+
+ continue;
+ }
- ASTUnit::PreprocessedEntitiesByFileMap &ByFileMap
- = AU->getPreprocessedEntitiesByFile();
- if (ByFileMap.empty()) {
- // Build the mapping from files to sets of preprocessed entities.
- for (PreprocessingRecord::iterator E = StartEntity; E != EndEntity; ++E) {
- std::pair<FileID, unsigned> P
- = SM.getDecomposedInstantiationLoc((*E)->getSourceRange().getBegin());
+ if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*First)) {
+ if (Visit(MakeInclusionDirectiveCursor(ID, TU)))
+ return true;
- ByFileMap[P.first].push_back(*E);
+ continue;
}
}
- return std::make_pair(ByFileMap[Begin.first].begin(),
- ByFileMap[Begin.first].end());
+ return false;
}
/// \brief Visit the children of the given cursor.
@@ -529,7 +492,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), true))
+ if (Visit(MakeCXCursor(*TL, tu, RegionOfInterest), true))
return true;
}
} else if (VisitDeclContext(
@@ -539,33 +502,8 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
}
// Walk the preprocessing record.
- if (CXXUnit->getPreprocessor().getPreprocessingRecord()) {
- // FIXME: Once we have the ability to deserialize a preprocessing record,
- // do so.
- PreprocessingRecord::iterator E, EEnd;
- for (llvm::tie(E, EEnd) = getPreprocessedEntities(); E != EEnd; ++E) {
- if (MacroExpansion *ME = dyn_cast<MacroExpansion>(*E)) {
- if (Visit(MakeMacroExpansionCursor(ME, tu)))
- return true;
-
- continue;
- }
-
- if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*E)) {
- if (Visit(MakeMacroDefinitionCursor(MD, tu)))
- return true;
-
- continue;
- }
-
- if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*E)) {
- if (Visit(MakeInclusionDirectiveCursor(ID, tu)))
- return true;
-
- continue;
- }
- }
- }
+ if (CXXUnit->getPreprocessor().getPreprocessingRecord())
+ visitPreprocessedEntitiesInRegion();
}
return false;
@@ -578,7 +516,15 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
}
}
}
-
+
+ if (Cursor.kind == CXCursor_IBOutletCollectionAttr) {
+ IBOutletCollectionAttr *A =
+ cast<IBOutletCollectionAttr>(cxcursor::getCursorAttr(Cursor));
+ if (const ObjCInterfaceType *InterT = A->getInterface()->getAs<ObjCInterfaceType>())
+ return Visit(cxcursor::MakeCursorObjCClassRef(InterT->getInterface(),
+ A->getInterfaceLoc(), TU));
+ }
+
// Nothing to visit at the moment.
return false;
}
@@ -589,7 +535,7 @@ bool CursorVisitor::VisitBlockDecl(BlockDecl *B) {
return true;
if (Stmt *Body = B->getBody())
- return Visit(MakeCXCursor(Body, StmtParent, TU));
+ return Visit(MakeCXCursor(Body, StmtParent, TU, RegionOfInterest));
return false;
}
@@ -629,7 +575,7 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
Decl *D = *I;
if (D->getLexicalDeclContext() != DC)
continue;
- CXCursor Cursor = MakeCXCursor(D, TU);
+ CXCursor Cursor = MakeCXCursor(D, TU, RegionOfInterest);
const llvm::Optional<bool> &V = shouldVisitCursor(Cursor);
if (!V.hasValue())
continue;
@@ -727,7 +673,7 @@ bool CursorVisitor::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
bool CursorVisitor::VisitEnumConstantDecl(EnumConstantDecl *D) {
if (Expr *Init = D->getInitExpr())
- return Visit(MakeCXCursor(Init, StmtParent, TU));
+ return Visit(MakeCXCursor(Init, StmtParent, TU, RegionOfInterest));
return false;
}
@@ -794,7 +740,7 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
if (ND->doesThisDeclarationHaveABody() && !ND->isLateTemplateParsed()) {
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(ND)) {
// Find the initializers that were written in the source.
- llvm::SmallVector<CXXCtorInitializer *, 4> WrittenInits;
+ SmallVector<CXXCtorInitializer *, 4> WrittenInits;
for (CXXConstructorDecl::init_iterator I = Constructor->init_begin(),
IEnd = Constructor->init_end();
I != IEnd; ++I) {
@@ -822,12 +768,12 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
// Visit the initializer value.
if (Expr *Initializer = Init->getInit())
- if (Visit(MakeCXCursor(Initializer, ND, TU)))
+ if (Visit(MakeCXCursor(Initializer, ND, TU, RegionOfInterest)))
return true;
}
}
- if (Visit(MakeCXCursor(ND->getBody(), StmtParent, TU)))
+ if (Visit(MakeCXCursor(ND->getBody(), StmtParent, TU, RegionOfInterest)))
return true;
}
@@ -839,7 +785,7 @@ bool CursorVisitor::VisitFieldDecl(FieldDecl *D) {
return true;
if (Expr *BitWidth = D->getBitWidth())
- return Visit(MakeCXCursor(BitWidth, StmtParent, TU));
+ return Visit(MakeCXCursor(BitWidth, StmtParent, TU, RegionOfInterest));
return false;
}
@@ -849,7 +795,7 @@ bool CursorVisitor::VisitVarDecl(VarDecl *D) {
return true;
if (Expr *Init = D->getInit())
- return Visit(MakeCXCursor(Init, StmtParent, TU));
+ return Visit(MakeCXCursor(Init, StmtParent, TU, RegionOfInterest));
return false;
}
@@ -860,7 +806,7 @@ bool CursorVisitor::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
if (Expr *DefArg = D->getDefaultArgument())
- return Visit(MakeCXCursor(DefArg, StmtParent, TU));
+ return Visit(MakeCXCursor(DefArg, StmtParent, TU, RegionOfInterest));
return false;
}
@@ -902,12 +848,12 @@ bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) {
for (ObjCMethodDecl::param_iterator P = ND->param_begin(),
PEnd = ND->param_end();
P != PEnd; ++P) {
- if (Visit(MakeCXCursor(*P, TU)))
+ if (Visit(MakeCXCursor(*P, TU, RegionOfInterest)))
return true;
}
if (ND->isThisDeclarationADefinition() &&
- Visit(MakeCXCursor(ND->getBody(), StmtParent, TU)))
+ Visit(MakeCXCursor(ND->getBody(), StmtParent, TU, RegionOfInterest)))
return true;
return false;
@@ -938,7 +884,7 @@ bool CursorVisitor::VisitObjCContainerDecl(ObjCContainerDecl *D) {
// in the current DeclContext. If any fall within the
// container's lexical region, stash them into a vector
// for later processing.
- llvm::SmallVector<Decl *, 24> DeclsInContainer;
+ SmallVector<Decl *, 24> DeclsInContainer;
SourceLocation EndLoc = D->getSourceRange().getEnd();
SourceManager &SM = AU->getSourceManager();
if (EndLoc.isValid()) {
@@ -979,9 +925,9 @@ bool CursorVisitor::VisitObjCContainerDecl(ObjCContainerDecl *D) {
ContainerDeclsSort(SM));
// Now visit the decls.
- for (llvm::SmallVectorImpl<Decl*>::iterator I = DeclsInContainer.begin(),
+ for (SmallVectorImpl<Decl*>::iterator I = DeclsInContainer.begin(),
E = DeclsInContainer.end(); I != E; ++I) {
- CXCursor Cursor = MakeCXCursor(*I, TU);
+ CXCursor Cursor = MakeCXCursor(*I, TU, RegionOfInterest);
const llvm::Optional<bool> &V = shouldVisitCursor(Cursor);
if (!V.hasValue())
continue;
@@ -1043,12 +989,12 @@ bool CursorVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *PD) {
// the @interface.
if (ObjCMethodDecl *MD = prevDecl->getGetterMethodDecl())
if (MD->isSynthesized() && MD->getLexicalDeclContext() == CDecl)
- if (Visit(MakeCXCursor(MD, TU)))
+ if (Visit(MakeCXCursor(MD, TU, RegionOfInterest)))
return true;
if (ObjCMethodDecl *MD = prevDecl->getSetterMethodDecl())
if (MD->isSynthesized() && MD->getLexicalDeclContext() == CDecl)
- if (Visit(MakeCXCursor(MD, TU)))
+ if (Visit(MakeCXCursor(MD, TU, RegionOfInterest)))
return true;
return false;
@@ -1110,10 +1056,9 @@ bool CursorVisitor::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
}
bool CursorVisitor::VisitObjCClassDecl(ObjCClassDecl *D) {
- for (ObjCClassDecl::iterator C = D->begin(), CEnd = D->end(); C != CEnd; ++C)
- if (Visit(MakeCursorObjCClassRef(C->getInterface(), C->getLocation(), TU)))
+ if (Visit(MakeCursorObjCClassRef(D->getForwardInterfaceDecl(),
+ D->getForwardDecl()->getLocation(), TU)))
return true;
-
return false;
}
@@ -1254,7 +1199,7 @@ bool CursorVisitor::VisitNestedNameSpecifier(NestedNameSpecifier *NNS,
bool
CursorVisitor::VisitNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier) {
- llvm::SmallVector<NestedNameSpecifierLoc, 4> Qualifiers;
+ SmallVector<NestedNameSpecifierLoc, 4> Qualifiers;
for (; Qualifier; Qualifier = Qualifier.getPrefix())
Qualifiers.push_back(Qualifier);
@@ -1302,7 +1247,7 @@ bool CursorVisitor::VisitTemplateParameters(
for (TemplateParameterList::const_iterator P = Params->begin(),
PEnd = Params->end();
P != PEnd; ++P) {
- if (Visit(MakeCXCursor(*P, TU)))
+ if (Visit(MakeCXCursor(*P, TU, RegionOfInterest)))
return true;
}
@@ -1359,12 +1304,12 @@ bool CursorVisitor::VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL) {
case TemplateArgument::Declaration:
if (Expr *E = TAL.getSourceDeclExpression())
- return Visit(MakeCXCursor(E, StmtParent, TU));
+ return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest));
return false;
case TemplateArgument::Expression:
if (Expr *E = TAL.getSourceExpression())
- return Visit(MakeCXCursor(E, StmtParent, TU));
+ return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest));
return false;
case TemplateArgument::Template:
@@ -1414,6 +1359,7 @@ bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
case BuiltinType::Long:
case BuiltinType::LongLong:
case BuiltinType::Int128:
+ case BuiltinType::Half:
case BuiltinType::Float:
case BuiltinType::Double:
case BuiltinType::LongDouble:
@@ -1455,6 +1401,9 @@ bool CursorVisitor::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
}
bool CursorVisitor::VisitTagTypeLoc(TagTypeLoc TL) {
+ if (TL.isDefinition())
+ return Visit(MakeCXCursor(TL.getDecl(), TU, RegionOfInterest));
+
return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU));
}
@@ -1510,6 +1459,10 @@ bool CursorVisitor::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
return Visit(TL.getPointeeLoc());
}
+bool CursorVisitor::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
+ return Visit(TL.getModifiedLoc());
+}
+
bool CursorVisitor::VisitFunctionTypeLoc(FunctionTypeLoc TL,
bool SkipResultType) {
if (!SkipResultType && Visit(TL.getResultLoc()))
@@ -1517,7 +1470,7 @@ bool CursorVisitor::VisitFunctionTypeLoc(FunctionTypeLoc TL,
for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I)
if (Decl *D = TL.getArg(I))
- if (Visit(MakeCXCursor(D, TU)))
+ if (Visit(MakeCXCursor(D, TU, RegionOfInterest)))
return true;
return false;
@@ -1528,7 +1481,7 @@ bool CursorVisitor::VisitArrayTypeLoc(ArrayTypeLoc TL) {
return true;
if (Expr *Size = TL.getSizeExpr())
- return Visit(MakeCXCursor(Size, StmtParent, TU));
+ return Visit(MakeCXCursor(Size, StmtParent, TU, RegionOfInterest));
return false;
}
@@ -1599,13 +1552,49 @@ bool CursorVisitor::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) {
return Visit(TL.getPatternLoc());
}
+bool CursorVisitor::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
+ if (Expr *E = TL.getUnderlyingExpr())
+ return Visit(MakeCXCursor(E, StmtParent, TU));
+
+ return false;
+}
+
+bool CursorVisitor::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
+ return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU));
+}
+
+bool CursorVisitor::VisitAtomicTypeLoc(AtomicTypeLoc TL) {
+ return Visit(TL.getValueLoc());
+}
+
+#define DEFAULT_TYPELOC_IMPL(CLASS, PARENT) \
+bool CursorVisitor::Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { \
+ return Visit##PARENT##Loc(TL); \
+}
+
+DEFAULT_TYPELOC_IMPL(Complex, Type)
+DEFAULT_TYPELOC_IMPL(ConstantArray, ArrayType)
+DEFAULT_TYPELOC_IMPL(IncompleteArray, ArrayType)
+DEFAULT_TYPELOC_IMPL(VariableArray, ArrayType)
+DEFAULT_TYPELOC_IMPL(DependentSizedArray, ArrayType)
+DEFAULT_TYPELOC_IMPL(DependentSizedExtVector, Type)
+DEFAULT_TYPELOC_IMPL(Vector, Type)
+DEFAULT_TYPELOC_IMPL(ExtVector, VectorType)
+DEFAULT_TYPELOC_IMPL(FunctionProto, FunctionType)
+DEFAULT_TYPELOC_IMPL(FunctionNoProto, FunctionType)
+DEFAULT_TYPELOC_IMPL(Record, TagType)
+DEFAULT_TYPELOC_IMPL(Enum, TagType)
+DEFAULT_TYPELOC_IMPL(SubstTemplateTypeParm, Type)
+DEFAULT_TYPELOC_IMPL(SubstTemplateTypeParmPack, Type)
+DEFAULT_TYPELOC_IMPL(Auto, Type)
+
bool CursorVisitor::VisitCXXRecordDecl(CXXRecordDecl *D) {
// Visit the nested-name-specifier, if present.
if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc())
if (VisitNestedNameSpecifierLoc(QualifierLoc))
return true;
- if (D->isDefinition()) {
+ if (D->isCompleteDefinition()) {
for (CXXRecordDecl::base_class_iterator I = D->bases_begin(),
E = D->bases_end(); I != E; ++I) {
if (Visit(cxcursor::MakeCursorCXXBaseSpecifier(I, TU)))
@@ -1642,7 +1631,7 @@ DEF_JOB(StmtVisit, Stmt, StmtVisitKind)
DEF_JOB(MemberExprParts, MemberExpr, MemberExprPartsKind)
DEF_JOB(DeclRefExprParts, DeclRefExpr, DeclRefExprPartsKind)
DEF_JOB(OverloadExprParts, OverloadExpr, OverloadExprPartsKind)
-DEF_JOB(ExplicitTemplateArgsVisit, ExplicitTemplateArgumentList,
+DEF_JOB(ExplicitTemplateArgsVisit, ASTTemplateArgumentListInfo,
ExplicitTemplateArgsVisitKind)
DEF_JOB(SizeOfPackExprParts, SizeOfPackExpr, SizeOfPackExprPartsKind)
#undef DEF_JOB
@@ -1687,27 +1676,6 @@ public:
SourceLocation getLoc() const {
return SourceLocation::getFromPtrEncoding(data[1]); }
};
-class NestedNameSpecifierVisit : public VisitorJob {
-public:
- NestedNameSpecifierVisit(NestedNameSpecifier *NS, SourceRange R,
- CXCursor parent)
- : VisitorJob(parent, VisitorJob::NestedNameSpecifierVisitKind,
- NS, R.getBegin().getPtrEncoding(),
- R.getEnd().getPtrEncoding()) {}
- static bool classof(const VisitorJob *VJ) {
- return VJ->getKind() == VisitorJob::NestedNameSpecifierVisitKind;
- }
- NestedNameSpecifier *get() const {
- return static_cast<NestedNameSpecifier*>(data[0]);
- }
- SourceRange getSourceRange() const {
- SourceLocation A =
- SourceLocation::getFromRawEncoding((unsigned)(uintptr_t) data[1]);
- SourceLocation B =
- SourceLocation::getFromRawEncoding((unsigned)(uintptr_t) data[2]);
- return SourceRange(A, B);
- }
-};
class NestedNameSpecifierLocVisit : public VisitorJob {
public:
@@ -1809,9 +1777,8 @@ public:
private:
void AddDeclarationNameInfo(Stmt *S);
- void AddNestedNameSpecifier(NestedNameSpecifier *NS, SourceRange R);
void AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier);
- void AddExplicitTemplateArgs(const ExplicitTemplateArgumentList *A);
+ void AddExplicitTemplateArgs(const ASTTemplateArgumentListInfo *A);
void AddMemberRef(FieldDecl *D, SourceLocation L);
void AddStmt(Stmt *S);
void AddDecl(Decl *D, bool isFirst = true);
@@ -1825,11 +1792,6 @@ void EnqueueVisitor::AddDeclarationNameInfo(Stmt *S) {
// statement we are visiting.
WL.push_back(DeclarationNameInfoVisit(S, Parent));
}
-void EnqueueVisitor::AddNestedNameSpecifier(NestedNameSpecifier *N,
- SourceRange R) {
- if (N)
- WL.push_back(NestedNameSpecifierVisit(N, R, Parent));
-}
void
EnqueueVisitor::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier) {
@@ -1846,10 +1808,10 @@ void EnqueueVisitor::AddDecl(Decl *D, bool isFirst) {
WL.push_back(DeclVisit(D, Parent, isFirst));
}
void EnqueueVisitor::
- AddExplicitTemplateArgs(const ExplicitTemplateArgumentList *A) {
+ AddExplicitTemplateArgs(const ASTTemplateArgumentListInfo *A) {
if (A)
WL.push_back(ExplicitTemplateArgsVisit(
- const_cast<ExplicitTemplateArgumentList*>(A), Parent));
+ const_cast<ASTTemplateArgumentListInfo*>(A), Parent));
}
void EnqueueVisitor::AddMemberRef(FieldDecl *D, SourceLocation L) {
if (D)
@@ -2114,7 +2076,7 @@ void EnqueueVisitor::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
}
void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, Stmt *S) {
- EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU)).Visit(S);
+ EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S);
}
bool CursorVisitor::IsInRegionOfInterest(CXCursor C) {
@@ -2142,13 +2104,14 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
continue;
// For now, perform default visitation for Decls.
- if (Visit(MakeCXCursor(D, TU, cast<DeclVisit>(&LI)->isFirst())))
+ if (Visit(MakeCXCursor(D, TU, RegionOfInterest,
+ cast<DeclVisit>(&LI)->isFirst())))
return true;
continue;
}
case VisitorJob::ExplicitTemplateArgsVisitKind: {
- const ExplicitTemplateArgumentList *ArgList =
+ const ASTTemplateArgumentListInfo *ArgList =
cast<ExplicitTemplateArgsVisit>(&LI)->get();
for (const TemplateArgumentLoc *Arg = ArgList->getTemplateArgs(),
*ArgEnd = Arg + ArgList->NumTemplateArgs;
@@ -2174,14 +2137,7 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
}
continue;
}
-
- case VisitorJob::NestedNameSpecifierVisitKind: {
- NestedNameSpecifierVisit *V = cast<NestedNameSpecifierVisit>(&LI);
- if (VisitNestedNameSpecifier(V->get(), V->getSourceRange()))
- return true;
- continue;
- }
-
+
case VisitorJob::NestedNameSpecifierLocVisitKind: {
NestedNameSpecifierLocVisit *V = cast<NestedNameSpecifierLocVisit>(&LI);
if (VisitNestedNameSpecifierLoc(V->get()))
@@ -2207,7 +2163,7 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
continue;
// Update the current cursor.
- CXCursor Cursor = MakeCXCursor(S, StmtParent, TU);
+ CXCursor Cursor = MakeCXCursor(S, StmtParent, TU, RegionOfInterest);
if (!IsInRegionOfInterest(Cursor))
continue;
switch (Visitor(Cursor, Parent, ClientData)) {
@@ -2313,6 +2269,47 @@ bool CursorVisitor::Visit(Stmt *S) {
return result;
}
+namespace {
+typedef llvm::SmallVector<SourceRange, 4> RefNamePieces;
+RefNamePieces buildPieces(unsigned NameFlags, bool IsMemberRefExpr,
+ const DeclarationNameInfo &NI,
+ const SourceRange &QLoc,
+ const ASTTemplateArgumentListInfo *TemplateArgs = 0){
+ const bool WantQualifier = NameFlags & CXNameRange_WantQualifier;
+ const bool WantTemplateArgs = NameFlags & CXNameRange_WantTemplateArgs;
+ const bool WantSinglePiece = NameFlags & CXNameRange_WantSinglePiece;
+
+ const DeclarationName::NameKind Kind = NI.getName().getNameKind();
+
+ RefNamePieces Pieces;
+
+ if (WantQualifier && QLoc.isValid())
+ Pieces.push_back(QLoc);
+
+ if (Kind != DeclarationName::CXXOperatorName || IsMemberRefExpr)
+ Pieces.push_back(NI.getLoc());
+
+ if (WantTemplateArgs && TemplateArgs)
+ Pieces.push_back(SourceRange(TemplateArgs->LAngleLoc,
+ TemplateArgs->RAngleLoc));
+
+ if (Kind == DeclarationName::CXXOperatorName) {
+ Pieces.push_back(SourceLocation::getFromRawEncoding(
+ NI.getInfo().CXXOperatorName.BeginOpNameLoc));
+ Pieces.push_back(SourceLocation::getFromRawEncoding(
+ NI.getInfo().CXXOperatorName.EndOpNameLoc));
+ }
+
+ if (WantSinglePiece) {
+ SourceRange R(Pieces.front().getBegin(), Pieces.back().getEnd());
+ Pieces.clear();
+ Pieces.push_back(R);
+ }
+
+ return Pieces;
+}
+}
+
//===----------------------------------------------------------------------===//
// Misc. API hooks.
//===----------------------------------------------------------------------===//
@@ -2369,7 +2366,7 @@ CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx,
FileSystemOptions FileSystemOpts;
FileSystemOpts.WorkingDir = CXXIdx->getWorkingDirectory();
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags;
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
ASTUnit *TU = ASTUnit::LoadFromASTFile(ast_filename, Diags, FileSystemOpts,
CXXIdx->getOnlyLocalDecls(),
0, 0, true);
@@ -2378,9 +2375,7 @@ CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx,
unsigned clang_defaultEditingTranslationUnitOptions() {
return CXTranslationUnit_PrecompiledPreamble |
- CXTranslationUnit_CacheCompletionResults |
- CXTranslationUnit_CXXPrecompiledPreamble |
- CXTranslationUnit_CXXChainedPCH;
+ CXTranslationUnit_CacheCompletionResults;
}
CXTranslationUnit
@@ -2426,24 +2421,21 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
bool PrecompilePreamble = options & CXTranslationUnit_PrecompiledPreamble;
- bool CompleteTranslationUnit
- = ((options & CXTranslationUnit_Incomplete) == 0);
+ // FIXME: Add a flag for modules.
+ TranslationUnitKind TUKind
+ = (options & CXTranslationUnit_Incomplete)? TU_Prefix : TU_Complete;
bool CacheCodeCompetionResults
= options & CXTranslationUnit_CacheCompletionResults;
- bool CXXPrecompilePreamble
- = options & CXTranslationUnit_CXXPrecompiledPreamble;
- bool CXXChainedPCH
- = options & CXTranslationUnit_CXXChainedPCH;
// Configure the diagnostics.
DiagnosticOptions DiagOpts;
- llvm::IntrusiveRefCntPtr<Diagnostic>
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine>
Diags(CompilerInstance::createDiagnostics(DiagOpts, num_command_line_args,
command_line_args));
// Recover resources if we crash before exiting this function.
- llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic,
- llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> >
+ llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
+ llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
DiagCleanup(Diags.getPtr());
llvm::OwningPtr<std::vector<ASTUnit::RemappedFile> >
@@ -2454,7 +2446,7 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
std::vector<ASTUnit::RemappedFile> > RemappedCleanup(RemappedFiles.get());
for (unsigned I = 0; I != num_unsaved_files; ++I) {
- llvm::StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length);
+ StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length);
const llvm::MemoryBuffer *Buffer
= llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename);
RemappedFiles->push_back(std::make_pair(unsaved_files[I].Filename,
@@ -2517,10 +2509,8 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
RemappedFiles->size(),
/*RemappedFilesKeepOriginalName=*/true,
PrecompilePreamble,
- CompleteTranslationUnit,
+ TUKind,
CacheCodeCompetionResults,
- CXXPrecompilePreamble,
- CXXChainedPCH,
NestedMacroExpansions));
if (NumErrors != Diags->getClient()->getNumErrors()) {
@@ -2651,7 +2641,7 @@ static void clang_reparseTranslationUnit_Impl(void *UserData) {
std::vector<ASTUnit::RemappedFile> > RemappedCleanup(RemappedFiles.get());
for (unsigned I = 0; I != num_unsaved_files; ++I) {
- llvm::StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length);
+ StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length);
const llvm::MemoryBuffer *Buffer
= llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename);
RemappedFiles->push_back(std::make_pair(unsaved_files[I].Filename,
@@ -2691,7 +2681,7 @@ CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) {
}
CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) {
- CXCursor Result = { CXCursor_TranslationUnit, { 0, 0, TU } };
+ CXCursor Result = { CXCursor_TranslationUnit, 0, { 0, 0, TU } };
return Result;
}
@@ -2722,9 +2712,9 @@ CXSourceLocation clang_getLocation(CXTranslationUnit tu,
bool Logging = ::getenv("LIBCLANG_LOGGING");
ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
const FileEntry *File = static_cast<const FileEntry *>(file);
- SourceLocation SLoc
- = CXXUnit->getSourceManager().getLocation(File, line, column);
+ SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
if (SLoc.isInvalid()) {
if (Logging)
llvm::errs() << "clang_getLocation(\"" << File->getName()
@@ -2747,14 +2737,8 @@ CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu,
return clang_getNullLocation();
ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
- SourceLocation Start
- = CXXUnit->getSourceManager().getLocation(
- static_cast<const FileEntry *>(file),
- 1, 1);
- if (Start.isInvalid()) return clang_getNullLocation();
-
- SourceLocation SLoc = Start.getFileLocWithOffset(offset);
-
+ SourceLocation SLoc
+ = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
if (SLoc.isInvalid()) return clang_getNullLocation();
return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
@@ -2774,6 +2758,19 @@ CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
begin.int_data, end.int_data };
return Result;
}
+
+unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2)
+{
+ return range1.ptr_data[0] == range2.ptr_data[0]
+ && range1.ptr_data[1] == range2.ptr_data[1]
+ && range1.begin_int_data == range2.begin_int_data
+ && range1.end_int_data == range2.end_int_data;
+}
+
+int clang_Range_isNull(CXSourceRange range) {
+ return clang_equalRanges(range, clang_getNullRange());
+}
+
} // end: extern "C"
static void createNullLocation(CXFile *file, unsigned *line,
@@ -2790,11 +2787,11 @@ static void createNullLocation(CXFile *file, unsigned *line,
}
extern "C" {
-void clang_getInstantiationLocation(CXSourceLocation location,
- CXFile *file,
- unsigned *line,
- unsigned *column,
- unsigned *offset) {
+void clang_getExpansionLocation(CXSourceLocation location,
+ CXFile *file,
+ unsigned *line,
+ unsigned *column,
+ unsigned *offset) {
SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
if (!location.ptr_data[0] || Loc.isInvalid()) {
@@ -2804,11 +2801,11 @@ void clang_getInstantiationLocation(CXSourceLocation location,
const SourceManager &SM =
*static_cast<const SourceManager*>(location.ptr_data[0]);
- SourceLocation InstLoc = SM.getInstantiationLoc(Loc);
+ SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
// Check that the FileID is invalid on the expansion location.
// This can manifest in invalid code.
- FileID fileID = SM.getFileID(InstLoc);
+ FileID fileID = SM.getFileID(ExpansionLoc);
bool Invalid = false;
const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
if (!sloc.isFile() || Invalid) {
@@ -2819,11 +2816,48 @@ void clang_getInstantiationLocation(CXSourceLocation location,
if (file)
*file = (void *)SM.getFileEntryForSLocEntry(sloc);
if (line)
- *line = SM.getInstantiationLineNumber(InstLoc);
+ *line = SM.getExpansionLineNumber(ExpansionLoc);
if (column)
- *column = SM.getInstantiationColumnNumber(InstLoc);
+ *column = SM.getExpansionColumnNumber(ExpansionLoc);
if (offset)
- *offset = SM.getDecomposedLoc(InstLoc).second;
+ *offset = SM.getDecomposedLoc(ExpansionLoc).second;
+}
+
+void clang_getPresumedLocation(CXSourceLocation location,
+ CXString *filename,
+ unsigned *line,
+ unsigned *column) {
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
+
+ if (!location.ptr_data[0] || Loc.isInvalid()) {
+ if (filename)
+ *filename = createCXString("");
+ if (line)
+ *line = 0;
+ if (column)
+ *column = 0;
+ }
+ else {
+ const SourceManager &SM =
+ *static_cast<const SourceManager*>(location.ptr_data[0]);
+ PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
+
+ if (filename)
+ *filename = createCXString(PreLoc.getFilename());
+ if (line)
+ *line = PreLoc.getLine();
+ if (column)
+ *column = PreLoc.getColumn();
+ }
+}
+
+void clang_getInstantiationLocation(CXSourceLocation location,
+ CXFile *file,
+ unsigned *line,
+ unsigned *column,
+ unsigned *offset) {
+ // Redirect to new API.
+ clang_getExpansionLocation(location, file, line, column, offset);
}
void clang_getSpellingLocation(CXSourceLocation location,
@@ -2845,7 +2879,7 @@ void clang_getSpellingLocation(CXSourceLocation location,
SM.getFileEntryForID(SM.getDecomposedLoc(SimpleSpellingLoc).first))
SpellLoc = SimpleSpellingLoc;
else
- SpellLoc = SM.getInstantiationLoc(SpellLoc);
+ SpellLoc = SM.getExpansionLoc(SpellLoc);
}
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
@@ -2927,7 +2961,7 @@ unsigned clang_isFileMultipleIncludeGuarded(CXTranslationUnit tu, CXFile file) {
//===----------------------------------------------------------------------===//
static Decl *getDeclFromExpr(Stmt *E) {
- if (CastExpr *CE = dyn_cast<CastExpr>(E))
+ if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E))
return getDeclFromExpr(CE->getSubExpr());
if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E))
@@ -2943,7 +2977,7 @@ static Decl *getDeclFromExpr(Stmt *E) {
if (CallExpr *CE = dyn_cast<CallExpr>(E))
return getDeclFromExpr(CE->getCallee());
- if (CXXConstructExpr *CE = llvm::dyn_cast<CXXConstructExpr>(E))
+ if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E))
if (!CE->isElidable())
return CE->getConstructor();
if (ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(E))
@@ -2963,6 +2997,9 @@ static Decl *getDeclFromExpr(Stmt *E) {
}
static SourceLocation getLocationFromExpr(Expr *E) {
+ if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E))
+ return getLocationFromExpr(CE->getSubExpr());
+
if (ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E))
return /*FIXME:*/Msg->getLeftLoc();
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
@@ -2985,7 +3022,6 @@ unsigned clang_visitChildren(CXCursor parent,
CXCursorVisitor visitor,
CXClientData client_data) {
CursorVisitor CursorVis(getCursorTU(parent), visitor, client_data,
- getCursorASTUnit(parent)->getMaxPCHLevel(),
false);
return CursorVis.VisitChildren(parent);
}
@@ -3030,7 +3066,7 @@ unsigned clang_visitChildrenWithBlock(CXCursor parent,
static CXString getDeclSpelling(Decl *D) {
NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D);
if (!ND) {
- if (ObjCPropertyImplDecl *PropImpl =llvm::dyn_cast<ObjCPropertyImplDecl>(D))
+ if (ObjCPropertyImplDecl *PropImpl =dyn_cast<ObjCPropertyImplDecl>(D))
if (ObjCPropertyDecl *Property = PropImpl->getPropertyDecl())
return createCXString(Property->getIdentifier()->getName());
@@ -3165,6 +3201,11 @@ CXString clang_getCursorSpelling(CXCursor C) {
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());
+ }
+
return createCXString("");
}
@@ -3176,7 +3217,7 @@ CXString clang_getCursorDisplayName(CXCursor C) {
if (!D)
return createCXString("");
- PrintingPolicy &Policy = getCursorContext(C).PrintingPolicy;
+ PrintingPolicy Policy = getCursorContext(C).getPrintingPolicy();
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D))
D = FunTmpl->getTemplatedDecl();
@@ -3314,10 +3355,86 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("LabelRef");
case CXCursor_OverloadedDeclRef:
return createCXString("OverloadedDeclRef");
- case CXCursor_UnexposedExpr:
- return createCXString("UnexposedExpr");
+ case CXCursor_IntegerLiteral:
+ return createCXString("IntegerLiteral");
+ case CXCursor_FloatingLiteral:
+ return createCXString("FloatingLiteral");
+ case CXCursor_ImaginaryLiteral:
+ return createCXString("ImaginaryLiteral");
+ case CXCursor_StringLiteral:
+ return createCXString("StringLiteral");
+ case CXCursor_CharacterLiteral:
+ return createCXString("CharacterLiteral");
+ case CXCursor_ParenExpr:
+ return createCXString("ParenExpr");
+ case CXCursor_UnaryOperator:
+ return createCXString("UnaryOperator");
+ case CXCursor_ArraySubscriptExpr:
+ return createCXString("ArraySubscriptExpr");
+ case CXCursor_BinaryOperator:
+ return createCXString("BinaryOperator");
+ case CXCursor_CompoundAssignOperator:
+ return createCXString("CompoundAssignOperator");
+ case CXCursor_ConditionalOperator:
+ return createCXString("ConditionalOperator");
+ case CXCursor_CStyleCastExpr:
+ return createCXString("CStyleCastExpr");
+ case CXCursor_CompoundLiteralExpr:
+ return createCXString("CompoundLiteralExpr");
+ case CXCursor_InitListExpr:
+ return createCXString("InitListExpr");
+ case CXCursor_AddrLabelExpr:
+ return createCXString("AddrLabelExpr");
+ case CXCursor_StmtExpr:
+ return createCXString("StmtExpr");
+ case CXCursor_GenericSelectionExpr:
+ return createCXString("GenericSelectionExpr");
+ case CXCursor_GNUNullExpr:
+ return createCXString("GNUNullExpr");
+ case CXCursor_CXXStaticCastExpr:
+ return createCXString("CXXStaticCastExpr");
+ case CXCursor_CXXDynamicCastExpr:
+ return createCXString("CXXDynamicCastExpr");
+ case CXCursor_CXXReinterpretCastExpr:
+ return createCXString("CXXReinterpretCastExpr");
+ case CXCursor_CXXConstCastExpr:
+ return createCXString("CXXConstCastExpr");
+ case CXCursor_CXXFunctionalCastExpr:
+ return createCXString("CXXFunctionalCastExpr");
+ case CXCursor_CXXTypeidExpr:
+ return createCXString("CXXTypeidExpr");
+ case CXCursor_CXXBoolLiteralExpr:
+ return createCXString("CXXBoolLiteralExpr");
+ case CXCursor_CXXNullPtrLiteralExpr:
+ return createCXString("CXXNullPtrLiteralExpr");
+ case CXCursor_CXXThisExpr:
+ return createCXString("CXXThisExpr");
+ case CXCursor_CXXThrowExpr:
+ return createCXString("CXXThrowExpr");
+ case CXCursor_CXXNewExpr:
+ return createCXString("CXXNewExpr");
+ case CXCursor_CXXDeleteExpr:
+ return createCXString("CXXDeleteExpr");
+ case CXCursor_UnaryExpr:
+ return createCXString("UnaryExpr");
+ case CXCursor_ObjCStringLiteral:
+ return createCXString("ObjCStringLiteral");
+ case CXCursor_ObjCEncodeExpr:
+ return createCXString("ObjCEncodeExpr");
+ case CXCursor_ObjCSelectorExpr:
+ return createCXString("ObjCSelectorExpr");
+ case CXCursor_ObjCProtocolExpr:
+ return createCXString("ObjCProtocolExpr");
+ case CXCursor_ObjCBridgedCastExpr:
+ return createCXString("ObjCBridgedCastExpr");
case CXCursor_BlockExpr:
return createCXString("BlockExpr");
+ case CXCursor_PackExpansionExpr:
+ return createCXString("PackExpansionExpr");
+ case CXCursor_SizeOfPackExpr:
+ return createCXString("SizeOfPackExpr");
+ case CXCursor_UnexposedExpr:
+ return createCXString("UnexposedExpr");
case CXCursor_DeclRefExpr:
return createCXString("DeclRefExpr");
case CXCursor_MemberRefExpr:
@@ -3328,8 +3445,66 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("ObjCMessageExpr");
case CXCursor_UnexposedStmt:
return createCXString("UnexposedStmt");
+ case CXCursor_DeclStmt:
+ return createCXString("DeclStmt");
case CXCursor_LabelStmt:
return createCXString("LabelStmt");
+ case CXCursor_CompoundStmt:
+ return createCXString("CompoundStmt");
+ case CXCursor_CaseStmt:
+ return createCXString("CaseStmt");
+ case CXCursor_DefaultStmt:
+ return createCXString("DefaultStmt");
+ case CXCursor_IfStmt:
+ return createCXString("IfStmt");
+ case CXCursor_SwitchStmt:
+ return createCXString("SwitchStmt");
+ case CXCursor_WhileStmt:
+ return createCXString("WhileStmt");
+ case CXCursor_DoStmt:
+ return createCXString("DoStmt");
+ case CXCursor_ForStmt:
+ return createCXString("ForStmt");
+ case CXCursor_GotoStmt:
+ return createCXString("GotoStmt");
+ case CXCursor_IndirectGotoStmt:
+ return createCXString("IndirectGotoStmt");
+ case CXCursor_ContinueStmt:
+ return createCXString("ContinueStmt");
+ case CXCursor_BreakStmt:
+ return createCXString("BreakStmt");
+ case CXCursor_ReturnStmt:
+ return createCXString("ReturnStmt");
+ case CXCursor_AsmStmt:
+ return createCXString("AsmStmt");
+ case CXCursor_ObjCAtTryStmt:
+ return createCXString("ObjCAtTryStmt");
+ case CXCursor_ObjCAtCatchStmt:
+ return createCXString("ObjCAtCatchStmt");
+ case CXCursor_ObjCAtFinallyStmt:
+ return createCXString("ObjCAtFinallyStmt");
+ case CXCursor_ObjCAtThrowStmt:
+ return createCXString("ObjCAtThrowStmt");
+ case CXCursor_ObjCAtSynchronizedStmt:
+ return createCXString("ObjCAtSynchronizedStmt");
+ case CXCursor_ObjCAutoreleasePoolStmt:
+ return createCXString("ObjCAutoreleasePoolStmt");
+ case CXCursor_ObjCForCollectionStmt:
+ return createCXString("ObjCForCollectionStmt");
+ case CXCursor_CXXCatchStmt:
+ return createCXString("CXXCatchStmt");
+ case CXCursor_CXXTryStmt:
+ return createCXString("CXXTryStmt");
+ case CXCursor_CXXForRangeStmt:
+ return createCXString("CXXForRangeStmt");
+ case CXCursor_SEHTryStmt:
+ return createCXString("SEHTryStmt");
+ case CXCursor_SEHExceptStmt:
+ return createCXString("SEHExceptStmt");
+ case CXCursor_SEHFinallyStmt:
+ return createCXString("SEHFinallyStmt");
+ case CXCursor_NullStmt:
+ return createCXString("NullStmt");
case CXCursor_InvalidFile:
return createCXString("InvalidFile");
case CXCursor_InvalidCode:
@@ -3348,6 +3523,12 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("attribute(iboutlet)");
case CXCursor_IBOutletCollectionAttr:
return createCXString("attribute(iboutletcollection)");
+ case CXCursor_CXXFinalAttr:
+ return createCXString("attribute(final)");
+ case CXCursor_CXXOverrideAttr:
+ return createCXString("attribute(override)");
+ case CXCursor_AnnotateAttr:
+ return createCXString("attribute(annotate)");
case CXCursor_PreprocessingDirective:
return createCXString("preprocessing directive");
case CXCursor_MacroDefinition:
@@ -3392,6 +3573,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("ObjCSynthesizeDecl");
case CXCursor_ObjCDynamicDecl:
return createCXString("ObjCDynamicDecl");
+ case CXCursor_CXXAccessSpecifier:
+ return createCXString("CXXAccessSpecifier");
}
llvm_unreachable("Unhandled CXCursorKind");
@@ -3400,18 +3583,35 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
struct GetCursorData {
SourceLocation TokenBeginLoc;
+ bool PointsAtMacroArgExpansion;
CXCursor &BestCursor;
- GetCursorData(SourceLocation tokenBegin, CXCursor &outputCursor)
- : TokenBeginLoc(tokenBegin), BestCursor(outputCursor) { }
+ GetCursorData(SourceManager &SM,
+ SourceLocation tokenBegin, CXCursor &outputCursor)
+ : TokenBeginLoc(tokenBegin), BestCursor(outputCursor) {
+ PointsAtMacroArgExpansion = SM.isMacroArgExpansion(tokenBegin);
+ }
};
-enum CXChildVisitResult GetCursorVisitor(CXCursor cursor,
- CXCursor parent,
- CXClientData client_data) {
+static enum CXChildVisitResult GetCursorVisitor(CXCursor cursor,
+ CXCursor parent,
+ CXClientData client_data) {
GetCursorData *Data = static_cast<GetCursorData *>(client_data);
CXCursor *BestCursor = &Data->BestCursor;
+ // If we point inside a macro argument we should provide info of what the
+ // token is so use the actual cursor, don't replace it with a macro expansion
+ // cursor.
+ if (cursor.kind == CXCursor_MacroExpansion && Data->PointsAtMacroArgExpansion)
+ return CXChildVisit_Recurse;
+
+ if (clang_isDeclaration(cursor.kind)) {
+ // Avoid having the implicit methods override the property decls.
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(getCursorDecl(cursor)))
+ if (MD->isImplicit())
+ return CXChildVisit_Break;
+ }
+
if (clang_isExpression(cursor.kind) &&
clang_isDeclaration(BestCursor->kind)) {
Decl *D = getCursorDecl(*BestCursor);
@@ -3431,14 +3631,12 @@ enum CXChildVisitResult GetCursorVisitor(CXCursor cursor,
// clang_getCursor() to point at the constructor.
if (clang_isExpression(BestCursor->kind) &&
isa<CXXTemporaryObjectExpr>(getCursorExpr(*BestCursor)) &&
- cursor.kind == CXCursor_TypeRef)
- return CXChildVisit_Recurse;
-
- // Don't override a preprocessing cursor with another preprocessing
- // cursor; we want the outermost preprocessing cursor.
- if (clang_isPreprocessing(cursor.kind) &&
- clang_isPreprocessing(BestCursor->kind))
+ cursor.kind == CXCursor_TypeRef) {
+ // Keep the cursor pointing at CXXTemporaryObjectExpr but also mark it
+ // as having the actual point on the type reference.
+ *BestCursor = getTypeRefedCallExprCursor(*BestCursor);
return CXChildVisit_Recurse;
+ }
*BestCursor = cursor;
return CXChildVisit_Recurse;
@@ -3451,31 +3649,10 @@ CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) {
ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
ASTUnit::ConcurrencyCheck Check(*CXXUnit);
- // Translate the given source location to make it point at the beginning of
- // the token under the cursor.
SourceLocation SLoc = cxloc::translateSourceLocation(Loc);
-
- // Guard against an invalid SourceLocation, or we may assert in one
- // of the following calls.
- if (SLoc.isInvalid())
- return clang_getNullCursor();
+ CXCursor Result = cxcursor::getCursor(TU, SLoc);
bool Logging = getenv("LIBCLANG_LOGGING");
- SLoc = Lexer::GetBeginningOfToken(SLoc, CXXUnit->getSourceManager(),
- CXXUnit->getASTContext().getLangOptions());
-
- CXCursor Result = MakeCXCursorInvalid(CXCursor_NoDeclFound);
- if (SLoc.isValid()) {
- // FIXME: Would be great to have a "hint" cursor, then walk from that
- // hint cursor upward until we find a cursor whose source range encloses
- // the region of interest, rather than starting from the translation unit.
- GetCursorData ResultData(SLoc, Result);
- CXCursor Parent = clang_getTranslationUnitCursor(TU);
- CursorVisitor CursorVis(TU, GetCursorVisitor, &ResultData,
- Decl::MaxPCHLevel, true, SourceLocation(SLoc));
- CursorVis.VisitChildren(Parent);
- }
-
if (Logging) {
CXFile SearchFile;
unsigned SearchLine, SearchColumn;
@@ -3485,10 +3662,9 @@ CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) {
const char *IsDef = clang_isCursorDefinition(Result)? " (Definition)" : "";
CXSourceLocation ResultLoc = clang_getCursorLocation(Result);
- clang_getInstantiationLocation(Loc, &SearchFile, &SearchLine, &SearchColumn,
- 0);
- clang_getInstantiationLocation(ResultLoc, &ResultFile, &ResultLine,
- &ResultColumn, 0);
+ clang_getExpansionLocation(Loc, &SearchFile, &SearchLine, &SearchColumn, 0);
+ clang_getExpansionLocation(ResultLoc, &ResultFile, &ResultLine,
+ &ResultColumn, 0);
SearchFileName = clang_getFileName(SearchFile);
ResultFileName = clang_getFileName(ResultFile);
KindSpelling = clang_getCursorKindSpelling(Result.kind);
@@ -3510,8 +3686,8 @@ CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) {
= clang_getCursorKindSpelling(Definition.kind);
CXFile DefinitionFile;
unsigned DefinitionLine, DefinitionColumn;
- clang_getInstantiationLocation(DefinitionLoc, &DefinitionFile,
- &DefinitionLine, &DefinitionColumn, 0);
+ clang_getExpansionLocation(DefinitionLoc, &DefinitionFile,
+ &DefinitionLine, &DefinitionColumn, 0);
CXString DefinitionFileName = clang_getFileName(DefinitionFile);
fprintf(stderr, " -> %s(%s:%d:%d)\n",
clang_getCString(DefinitionKindSpelling),
@@ -3694,8 +3870,6 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
Decl *D = getCursorDecl(C);
SourceLocation Loc = D->getLocation();
- if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(D))
- Loc = Class->getClassLoc();
// FIXME: Multiple variables declared in a single declaration
// currently lack the information needed to correctly determine their
// ranges when accounting for the type-specifier. We use context
@@ -3711,6 +3885,37 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
} // end extern "C"
+CXCursor cxcursor::getCursor(CXTranslationUnit TU, SourceLocation SLoc) {
+ assert(TU);
+
+ // Guard against an invalid SourceLocation, or we may assert in one
+ // of the following calls.
+ if (SLoc.isInvalid())
+ return clang_getNullCursor();
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+
+ // Translate the given source location to make it point at the beginning of
+ // the token under the cursor.
+ SLoc = Lexer::GetBeginningOfToken(SLoc, CXXUnit->getSourceManager(),
+ CXXUnit->getASTContext().getLangOptions());
+
+ CXCursor Result = MakeCXCursorInvalid(CXCursor_NoDeclFound);
+ if (SLoc.isValid()) {
+ // FIXME: Would be great to have a "hint" cursor, then walk from that
+ // hint cursor upward until we find a cursor whose source range encloses
+ // the region of interest, rather than starting from the translation unit.
+ GetCursorData ResultData(CXXUnit->getSourceManager(), SLoc, Result);
+ CXCursor Parent = clang_getTranslationUnitCursor(TU);
+ CursorVisitor CursorVis(TU, GetCursorVisitor, &ResultData,
+ /*VisitPreprocessorLast=*/true,
+ SourceLocation(SLoc));
+ CursorVis.VisitChildren(Parent);
+ }
+
+ return Result;
+}
+
static SourceRange getRawCursorExtent(CXCursor C) {
if (clang_isReference(C.kind)) {
switch (C.kind) {
@@ -3756,17 +3961,29 @@ static SourceRange getRawCursorExtent(CXCursor C) {
if (clang_isStatement(C.kind))
return getCursorStmt(C)->getSourceRange();
+ if (clang_isAttribute(C.kind))
+ return getCursorAttr(C)->getRange();
+
if (C.kind == CXCursor_PreprocessingDirective)
return cxcursor::getCursorPreprocessingDirective(C);
- if (C.kind == CXCursor_MacroExpansion)
- return cxcursor::getCursorMacroExpansion(C)->getSourceRange();
+ if (C.kind == CXCursor_MacroExpansion) {
+ ASTUnit *TU = getCursorASTUnit(C);
+ SourceRange Range = cxcursor::getCursorMacroExpansion(C)->getSourceRange();
+ return TU->mapRangeFromPreamble(Range);
+ }
- if (C.kind == CXCursor_MacroDefinition)
- return cxcursor::getCursorMacroDefinition(C)->getSourceRange();
+ if (C.kind == CXCursor_MacroDefinition) {
+ ASTUnit *TU = getCursorASTUnit(C);
+ SourceRange Range = cxcursor::getCursorMacroDefinition(C)->getSourceRange();
+ return TU->mapRangeFromPreamble(Range);
+ }
- if (C.kind == CXCursor_InclusionDirective)
- return cxcursor::getCursorInclusionDirective(C)->getSourceRange();
+ if (C.kind == CXCursor_InclusionDirective) {
+ ASTUnit *TU = getCursorASTUnit(C);
+ SourceRange Range = cxcursor::getCursorInclusionDirective(C)->getSourceRange();
+ return TU->mapRangeFromPreamble(Range);
+ }
if (C.kind >= CXCursor_FirstDecl && C.kind <= CXCursor_LastDecl) {
Decl *D = cxcursor::getCursorDecl(C);
@@ -3847,7 +4064,7 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
if (ObjCForwardProtocolDecl *Protocols
= dyn_cast<ObjCForwardProtocolDecl>(D))
return MakeCursorOverloadedDeclRef(Protocols, D->getLocation(), tu);
- if (ObjCPropertyImplDecl *PropImpl =llvm::dyn_cast<ObjCPropertyImplDecl>(D))
+ if (ObjCPropertyImplDecl *PropImpl =dyn_cast<ObjCPropertyImplDecl>(D))
if (ObjCPropertyDecl *Property = PropImpl->getPropertyDecl())
return MakeCXCursor(Property, tu);
@@ -3857,8 +4074,12 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
if (clang_isExpression(C.kind)) {
Expr *E = getCursorExpr(C);
Decl *D = getDeclFromExpr(E);
- if (D)
- return MakeCXCursor(D, tu);
+ if (D) {
+ CXCursor declCursor = MakeCXCursor(D, tu);
+ declCursor = getSelectorIdentifierCursor(getSelectorIdentifierIndex(C),
+ declCursor);
+ return declCursor;
+ }
if (OverloadExpr *Ovl = dyn_cast_or_null<OverloadExpr>(E))
return MakeCursorOverloadedDeclRef(Ovl, tu);
@@ -3981,6 +4202,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::StaticAssert:
case Decl::Block:
case Decl::Label: // FIXME: Is this right??
+ case Decl::ClassScopeFunctionSpecialization:
return C;
// Declaration kinds that don't make any sense here, but are
@@ -4171,8 +4393,8 @@ unsigned clang_getNumOverloadedDecls(CXCursor C) {
Decl *D = Storage.get<Decl*>();
if (UsingDecl *Using = dyn_cast<UsingDecl>(D))
return Using->shadow_size();
- if (ObjCClassDecl *Classes = dyn_cast<ObjCClassDecl>(D))
- return Classes->size();
+ if (isa<ObjCClassDecl>(D))
+ return 1;
if (ObjCForwardProtocolDecl *Protocols =dyn_cast<ObjCForwardProtocolDecl>(D))
return Protocols->protocol_size();
@@ -4202,10 +4424,8 @@ CXCursor clang_getOverloadedDecl(CXCursor cursor, unsigned index) {
std::advance(Pos, index);
return MakeCXCursor(cast<UsingShadowDecl>(*Pos)->getTargetDecl(), TU);
}
-
if (ObjCClassDecl *Classes = dyn_cast<ObjCClassDecl>(D))
- return MakeCXCursor(Classes->begin()[index].getInterface(), TU);
-
+ return MakeCXCursor(Classes->getForwardInterfaceDecl(), TU);
if (ObjCForwardProtocolDecl *Protocols = dyn_cast<ObjCForwardProtocolDecl>(D))
return MakeCXCursor(Protocols->protocol_begin()[index], TU);
@@ -4233,6 +4453,54 @@ void clang_getDefinitionSpellingAndExtent(CXCursor C,
*endColumn = SM.getSpellingColumnNumber(Body->getRBracLoc());
}
+
+CXSourceRange clang_getCursorReferenceNameRange(CXCursor C, unsigned NameFlags,
+ unsigned PieceIndex) {
+ RefNamePieces Pieces;
+
+ switch (C.kind) {
+ case CXCursor_MemberRefExpr:
+ if (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)))
+ Pieces = buildPieces(NameFlags, false, E->getNameInfo(),
+ E->getQualifierLoc().getSourceRange(),
+ E->getExplicitTemplateArgsOpt());
+ break;
+
+ case CXCursor_CallExpr:
+ if (CXXOperatorCallExpr *OCE =
+ dyn_cast<CXXOperatorCallExpr>(getCursorExpr(C))) {
+ Expr *Callee = OCE->getCallee();
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Callee))
+ Callee = ICE->getSubExpr();
+
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Callee))
+ Pieces = buildPieces(NameFlags, false, DRE->getNameInfo(),
+ DRE->getQualifierLoc().getSourceRange());
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (Pieces.empty()) {
+ if (PieceIndex == 0)
+ return clang_getCursorExtent(C);
+ } else if (PieceIndex < Pieces.size()) {
+ SourceRange R = Pieces[PieceIndex];
+ if (R.isValid())
+ return cxloc::translateSourceRange(getCursorContext(C), R);
+ }
+
+ return clang_getNullRange();
+}
+
void clang_enableStackTraces(void) {
llvm::sys::PrintStackTraceOnErrorSignal();
}
@@ -4273,7 +4541,7 @@ CXString clang_getTokenSpelling(CXTranslationUnit TU, CXToken CXTok) {
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(llvm::StringRef(Text, CXTok.int_data[2]));
+ return createCXString(StringRef(Text, CXTok.int_data[2]));
}
case CXToken_Punctuation:
@@ -4289,9 +4557,9 @@ CXString clang_getTokenSpelling(CXTranslationUnit TU, CXToken CXTok) {
SourceLocation Loc = SourceLocation::getFromRawEncoding(CXTok.int_data[1]);
std::pair<FileID, unsigned> LocInfo
- = CXXUnit->getSourceManager().getDecomposedLoc(Loc);
+ = CXXUnit->getSourceManager().getDecomposedSpellingLoc(Loc);
bool Invalid = false;
- llvm::StringRef Buffer
+ StringRef Buffer
= CXXUnit->getSourceManager().getBufferData(LocInfo.first, &Invalid);
if (Invalid)
return createCXString("");
@@ -4317,28 +4585,13 @@ CXSourceRange clang_getTokenExtent(CXTranslationUnit TU, CXToken CXTok) {
SourceLocation::getFromRawEncoding(CXTok.int_data[1]));
}
-void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
- CXToken **Tokens, unsigned *NumTokens) {
- if (Tokens)
- *Tokens = 0;
- if (NumTokens)
- *NumTokens = 0;
-
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
- if (!CXXUnit || !Tokens || !NumTokens)
- return;
-
- ASTUnit::ConcurrencyCheck Check(*CXXUnit);
-
- SourceRange R = cxloc::translateCXSourceRange(Range);
- if (R.isInvalid())
- return;
-
+static void getTokens(ASTUnit *CXXUnit, SourceRange Range,
+ SmallVectorImpl<CXToken> &CXTokens) {
SourceManager &SourceMgr = CXXUnit->getSourceManager();
std::pair<FileID, unsigned> BeginLocInfo
- = SourceMgr.getDecomposedLoc(R.getBegin());
+ = SourceMgr.getDecomposedLoc(Range.getBegin());
std::pair<FileID, unsigned> EndLocInfo
- = SourceMgr.getDecomposedLoc(R.getEnd());
+ = SourceMgr.getDecomposedLoc(Range.getEnd());
// Cannot tokenize across files.
if (BeginLocInfo.first != EndLocInfo.first)
@@ -4346,7 +4599,7 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
// Create a lexer
bool Invalid = false;
- llvm::StringRef Buffer
+ StringRef Buffer
= SourceMgr.getBufferData(BeginLocInfo.first, &Invalid);
if (Invalid)
return;
@@ -4358,7 +4611,6 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
// Lex tokens until we hit the end of the range.
const char *EffectiveBufferEnd = Buffer.data() + EndLocInfo.second;
- llvm::SmallVector<CXToken, 32> CXTokens;
Token Tok;
bool previousWasAt = false;
do {
@@ -4403,6 +4655,27 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
CXTokens.push_back(CXTok);
previousWasAt = Tok.is(tok::at);
} while (Lex.getBufferLocation() <= EffectiveBufferEnd);
+}
+
+void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
+ CXToken **Tokens, unsigned *NumTokens) {
+ if (Tokens)
+ *Tokens = 0;
+ if (NumTokens)
+ *NumTokens = 0;
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ if (!CXXUnit || !Tokens || !NumTokens)
+ return;
+
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+
+ SourceRange R = cxloc::translateCXSourceRange(Range);
+ if (R.isInvalid())
+ return;
+
+ SmallVector<CXToken, 32> CXTokens;
+ getTokens(CXXUnit, R, CXTokens);
if (CXTokens.empty())
return;
@@ -4445,6 +4718,16 @@ class AnnotateTokensWorker {
SourceLocation GetTokenLoc(unsigned tokI) {
return SourceLocation::getFromRawEncoding(Tokens[tokI].int_data[1]);
}
+ bool isFunctionMacroToken(unsigned tokI) const {
+ return Tokens[tokI].int_data[3] != 0;
+ }
+ SourceLocation getFunctionMacroTokenLoc(unsigned tokI) const {
+ return SourceLocation::getFromRawEncoding(Tokens[tokI].int_data[3]);
+ }
+
+ void annotateAndAdvanceTokens(CXCursor, RangeComparisonResult, SourceRange);
+ void annotateAndAdvanceFunctionMacroTokens(CXCursor, RangeComparisonResult,
+ SourceRange);
public:
AnnotateTokensWorker(AnnotateTokensData &annotated,
@@ -4453,8 +4736,7 @@ public:
: Annotated(annotated), Tokens(tokens), Cursors(cursors),
NumTokens(numTokens), TokIdx(0), PreprocessingTokIdx(0),
AnnotateVis(tu,
- AnnotateTokensVisitor, this,
- Decl::MaxPCHLevel, true, RegionOfInterest),
+ AnnotateTokensVisitor, this, true, RegionOfInterest),
SrcMgr(static_cast<ASTUnit*>(tu->TUData)->getSourceManager()),
HasContextSensitiveKeywords(false) { }
@@ -4497,6 +4779,65 @@ void AnnotateTokensWorker::AnnotateTokens(CXCursor parent) {
}
}
+/// \brief It annotates and advances tokens with a cursor until the comparison
+//// between the cursor location and the source range is the same as
+/// \arg compResult.
+///
+/// Pass RangeBefore to annotate tokens with a cursor until a range is reached.
+/// Pass RangeOverlap to annotate tokens inside a range.
+void AnnotateTokensWorker::annotateAndAdvanceTokens(CXCursor updateC,
+ RangeComparisonResult compResult,
+ SourceRange range) {
+ while (MoreTokens()) {
+ const unsigned I = NextToken();
+ if (isFunctionMacroToken(I))
+ return annotateAndAdvanceFunctionMacroTokens(updateC, compResult, range);
+
+ SourceLocation TokLoc = GetTokenLoc(I);
+ if (LocationCompare(SrcMgr, TokLoc, range) == compResult) {
+ Cursors[I] = updateC;
+ AdvanceToken();
+ continue;
+ }
+ break;
+ }
+}
+
+/// \brief Special annotation handling for macro argument tokens.
+void AnnotateTokensWorker::annotateAndAdvanceFunctionMacroTokens(
+ CXCursor updateC,
+ RangeComparisonResult compResult,
+ SourceRange range) {
+ assert(MoreTokens());
+ assert(isFunctionMacroToken(NextToken()) &&
+ "Should be called only for macro arg tokens");
+
+ // This works differently than annotateAndAdvanceTokens; because expanded
+ // macro arguments can have arbitrary translation-unit source order, we do not
+ // advance the token index one by one until a token fails the range test.
+ // We only advance once past all of the macro arg tokens if all of them
+ // pass the range test. If one of them fails we keep the token index pointing
+ // at the start of the macro arg tokens so that the failing token will be
+ // annotated by a subsequent annotation try.
+
+ bool atLeastOneCompFail = false;
+
+ unsigned I = NextToken();
+ for (; I < NumTokens && isFunctionMacroToken(I); ++I) {
+ SourceLocation TokLoc = getFunctionMacroTokenLoc(I);
+ if (TokLoc.isFileID())
+ continue; // not macro arg token, it's parens or comma.
+ if (LocationCompare(SrcMgr, TokLoc, range) == compResult) {
+ if (clang_isInvalid(clang_getCursorKind(Cursors[I])))
+ Cursors[I] = updateC;
+ } else
+ atLeastOneCompFail = true;
+ }
+
+ if (!atLeastOneCompFail)
+ TokIdx = I; // All of the tokens were handled, advance beyond all of them.
+}
+
enum CXChildVisitResult
AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
CXSourceLocation Loc = clang_getCursorLocation(cursor);
@@ -4584,7 +4925,7 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
SourceLocation TokLoc = GetTokenLoc(I);
switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) {
case RangeBefore:
- assert(0 && "Infeasible");
+ llvm_unreachable("Infeasible");
case RangeAfter:
break;
case RangeOverlap:
@@ -4611,12 +4952,6 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
const enum CXCursorKind cursorK = clang_getCursorKind(cursor);
if (cursorK >= CXCursor_FirstDecl && cursorK <= CXCursor_LastDecl) {
Decl *D = cxcursor::getCursorDecl(cursor);
- // Don't visit synthesized ObjC methods, since they have no syntatic
- // representation in the source.
- if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- if (MD->isSynthesized())
- return CXChildVisit_Continue;
- }
SourceLocation StartLoc;
if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
@@ -4654,20 +4989,7 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
(clang_isInvalid(K) || K == CXCursor_TranslationUnit)
? clang_getNullCursor() : parent;
- while (MoreTokens()) {
- const unsigned I = NextToken();
- SourceLocation TokLoc = GetTokenLoc(I);
- switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) {
- case RangeBefore:
- Cursors[I] = updateC;
- AdvanceToken();
- continue;
- case RangeAfter:
- case RangeOverlap:
- break;
- }
- break;
- }
+ annotateAndAdvanceTokens(updateC, RangeBefore, cursorRange);
// Avoid having the cursor of an expression "overwrite" the annotation of the
// variable declaration that it belongs to.
@@ -4692,46 +5014,19 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
VisitChildren(cursor);
const unsigned AfterChildren = NextToken();
- // Adjust 'Last' to the last token within the extent of the cursor.
- while (MoreTokens()) {
- const unsigned I = NextToken();
- SourceLocation TokLoc = GetTokenLoc(I);
- switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) {
- case RangeBefore:
- assert(0 && "Infeasible");
- case RangeAfter:
- break;
- case RangeOverlap:
- Cursors[I] = updateC;
- AdvanceToken();
- continue;
- }
- break;
- }
- const unsigned Last = NextToken();
+ // Scan the tokens that are at the end of the cursor, but are not captured
+ // but the child cursors.
+ annotateAndAdvanceTokens(cursor, RangeOverlap, cursorRange);
// Scan the tokens that are at the beginning of the cursor, but are not
// capture by the child cursors.
-
- // For AST elements within macros, rely on a post-annotate pass to
- // to correctly annotate the tokens with cursors. Otherwise we can
- // get confusing results of having tokens that map to cursors that really
- // are expanded by an instantiation.
- if (L.isMacroID())
- cursor = clang_getNullCursor();
-
for (unsigned I = BeforeChildren; I != AfterChildren; ++I) {
if (!clang_isInvalid(clang_getCursorKind(Cursors[I])))
break;
Cursors[I] = cursor;
}
- // Scan the tokens that are at the end of the cursor, but are not captured
- // but the child cursors.
- for (unsigned I = AfterChildren; I != Last; ++I)
- Cursors[I] = cursor;
- TokIdx = Last;
return CXChildVisit_Continue;
}
@@ -4742,6 +5037,74 @@ static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
}
namespace {
+
+/// \brief Uses the macro expansions in the preprocessing record to find
+/// and mark tokens that are macro arguments. This info is used by the
+/// AnnotateTokensWorker.
+class MarkMacroArgTokensVisitor {
+ SourceManager &SM;
+ CXToken *Tokens;
+ unsigned NumTokens;
+ unsigned CurIdx;
+
+public:
+ MarkMacroArgTokensVisitor(SourceManager &SM,
+ CXToken *tokens, unsigned numTokens)
+ : SM(SM), Tokens(tokens), NumTokens(numTokens), CurIdx(0) { }
+
+ CXChildVisitResult visit(CXCursor cursor, CXCursor parent) {
+ if (cursor.kind != CXCursor_MacroExpansion)
+ return CXChildVisit_Continue;
+
+ SourceRange macroRange = getCursorMacroExpansion(cursor)->getSourceRange();
+ if (macroRange.getBegin() == macroRange.getEnd())
+ return CXChildVisit_Continue; // it's not a function macro.
+
+ for (; CurIdx < NumTokens; ++CurIdx) {
+ if (!SM.isBeforeInTranslationUnit(getTokenLoc(CurIdx),
+ macroRange.getBegin()))
+ break;
+ }
+
+ if (CurIdx == NumTokens)
+ return CXChildVisit_Break;
+
+ for (; CurIdx < NumTokens; ++CurIdx) {
+ SourceLocation tokLoc = getTokenLoc(CurIdx);
+ if (!SM.isBeforeInTranslationUnit(tokLoc, macroRange.getEnd()))
+ break;
+
+ setFunctionMacroTokenLoc(CurIdx, SM.getMacroArgExpandedLocation(tokLoc));
+ }
+
+ if (CurIdx == NumTokens)
+ return CXChildVisit_Break;
+
+ return CXChildVisit_Continue;
+ }
+
+private:
+ SourceLocation getTokenLoc(unsigned tokI) {
+ return SourceLocation::getFromRawEncoding(Tokens[tokI].int_data[1]);
+ }
+
+ void setFunctionMacroTokenLoc(unsigned tokI, SourceLocation loc) {
+ // The third field is reserved and currently not used. Use it here
+ // to mark macro arg expanded tokens with their expanded locations.
+ Tokens[tokI].int_data[3] = loc.getRawEncoding();
+ }
+};
+
+} // end anonymous namespace
+
+static CXChildVisitResult
+MarkMacroArgTokensVisitorDelegate(CXCursor cursor, CXCursor parent,
+ CXClientData client_data) {
+ return static_cast<MarkMacroArgTokensVisitor*>(client_data)->visit(cursor,
+ parent);
+}
+
+namespace {
struct clang_annotateTokens_Data {
CXTranslationUnit TU;
ASTUnit *CXXUnit;
@@ -4751,6 +5114,73 @@ namespace {
};
}
+static void annotatePreprocessorTokens(CXTranslationUnit TU,
+ SourceRange RegionOfInterest,
+ AnnotateTokensData &Annotated) {
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+
+ SourceManager &SourceMgr = CXXUnit->getSourceManager();
+ std::pair<FileID, unsigned> BeginLocInfo
+ = SourceMgr.getDecomposedLoc(RegionOfInterest.getBegin());
+ std::pair<FileID, unsigned> EndLocInfo
+ = SourceMgr.getDecomposedLoc(RegionOfInterest.getEnd());
+
+ if (BeginLocInfo.first != EndLocInfo.first)
+ return;
+
+ StringRef Buffer;
+ bool Invalid = false;
+ Buffer = SourceMgr.getBufferData(BeginLocInfo.first, &Invalid);
+ if (Buffer.empty() || Invalid)
+ return;
+
+ Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
+ CXXUnit->getASTContext().getLangOptions(),
+ Buffer.begin(), Buffer.data() + BeginLocInfo.second,
+ Buffer.end());
+ Lex.SetCommentRetentionState(true);
+
+ // 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);
+
+ 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.
+ //
+ // 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;
+ }
+
+ if (Tok.isAtStartOfLine())
+ goto reprocess;
+
+ continue;
+ }
+
+ if (Tok.is(tok::eof))
+ break;
+ }
+}
+
// This gets run a separate thread to avoid stack blowout.
static void clang_annotateTokensImpl(void *UserData) {
CXTranslationUnit TU = ((clang_annotateTokens_Data*)UserData)->TU;
@@ -4770,65 +5200,19 @@ static void clang_annotateTokensImpl(void *UserData) {
// 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.
- SourceManager &SourceMgr = CXXUnit->getSourceManager();
- std::pair<FileID, unsigned> BeginLocInfo
- = SourceMgr.getDecomposedLoc(RegionOfInterest.getBegin());
- std::pair<FileID, unsigned> EndLocInfo
- = SourceMgr.getDecomposedLoc(RegionOfInterest.getEnd());
+ annotatePreprocessorTokens(TU, RegionOfInterest, Annotated);
- llvm::StringRef Buffer;
- bool Invalid = false;
- if (BeginLocInfo.first == EndLocInfo.first &&
- ((Buffer = SourceMgr.getBufferData(BeginLocInfo.first, &Invalid)),true) &&
- !Invalid) {
- Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
- CXXUnit->getASTContext().getLangOptions(),
- Buffer.begin(), Buffer.data() + BeginLocInfo.second,
- Buffer.end());
- Lex.SetCommentRetentionState(true);
-
- // 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);
-
- 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.
- //
- // FIXME: Some simple tests here could identify macro definitions and
- // #undefs, to provide specific cursor kinds for those.
- llvm::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;
- }
-
- if (Tok.isAtStartOfLine())
- goto reprocess;
-
- continue;
- }
-
- if (Tok.is(tok::eof))
- break;
- }
+ if (CXXUnit->getPreprocessor().getPreprocessingRecord()) {
+ // Search and mark tokens that are macro argument expansions.
+ MarkMacroArgTokensVisitor Visitor(CXXUnit->getSourceManager(),
+ Tokens, NumTokens);
+ CursorVisitor MacroArgMarker(TU,
+ MarkMacroArgTokensVisitorDelegate, &Visitor,
+ true, RegionOfInterest);
+ MacroArgMarker.visitPreprocessedEntitiesInRegion();
}
// Annotate all of the source locations in the region of interest that map to
@@ -4888,44 +5272,10 @@ static void clang_annotateTokensImpl(void *UserData) {
Tokens[I].int_data[0] = CXToken_Keyword;
continue;
}
-
- if (Cursors[I].kind == CXCursor_CXXMethod) {
- IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data);
- if (CXXMethodDecl *Method
- = dyn_cast_or_null<CXXMethodDecl>(getCursorDecl(Cursors[I]))) {
- if ((Method->hasAttr<FinalAttr>() ||
- Method->hasAttr<OverrideAttr>()) &&
- Method->getLocation().getRawEncoding() != Tokens[I].int_data[1] &&
- llvm::StringSwitch<bool>(II->getName())
- .Case("final", true)
- .Case("override", true)
- .Default(false))
- Tokens[I].int_data[0] = CXToken_Keyword;
- }
- continue;
- }
-
- if (Cursors[I].kind == CXCursor_ClassDecl ||
- Cursors[I].kind == CXCursor_StructDecl ||
- Cursors[I].kind == CXCursor_ClassTemplate) {
- IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data);
- if (II->getName() == "final") {
- // We have to be careful with 'final', since it could be the name
- // of a member class rather than the context-sensitive keyword.
- // So, check whether the cursor associated with this
- Decl *D = getCursorDecl(Cursors[I]);
- if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(D)) {
- if ((Record->hasAttr<FinalAttr>()) &&
- Record->getIdentifier() != II)
- Tokens[I].int_data[0] = CXToken_Keyword;
- } else if (ClassTemplateDecl *ClassTemplate
- = dyn_cast_or_null<ClassTemplateDecl>(D)) {
- CXXRecordDecl *Record = ClassTemplate->getTemplatedDecl();
- if ((Record->hasAttr<FinalAttr>()) &&
- Record->getIdentifier() != II)
- Tokens[I].int_data[0] = CXToken_Keyword;
- }
- }
+
+ if (Cursors[I].kind == CXCursor_CXXFinalAttr ||
+ Cursors[I].kind == CXCursor_CXXOverrideAttr) {
+ Tokens[I].int_data[0] = CXToken_Keyword;
continue;
}
}
@@ -5122,62 +5472,6 @@ CXCursor clang_getCursorLexicalParent(CXCursor cursor) {
return clang_getNullCursor();
}
-static void CollectOverriddenMethods(DeclContext *Ctx,
- ObjCMethodDecl *Method,
- llvm::SmallVectorImpl<ObjCMethodDecl *> &Methods) {
- if (!Ctx)
- return;
-
- // If we have a class or category implementation, jump straight to the
- // interface.
- if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(Ctx))
- return CollectOverriddenMethods(Impl->getClassInterface(), Method, Methods);
-
- ObjCContainerDecl *Container = dyn_cast<ObjCContainerDecl>(Ctx);
- if (!Container)
- return;
-
- // Check whether we have a matching method at this level.
- if (ObjCMethodDecl *Overridden = Container->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
- if (Method != Overridden) {
- // We found an override at this level; there is no need to look
- // into other protocols or categories.
- Methods.push_back(Overridden);
- return;
- }
-
- if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
- for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(),
- PEnd = Protocol->protocol_end();
- P != PEnd; ++P)
- CollectOverriddenMethods(*P, Method, Methods);
- }
-
- if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) {
- for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(),
- PEnd = Category->protocol_end();
- P != PEnd; ++P)
- CollectOverriddenMethods(*P, Method, Methods);
- }
-
- if (ObjCInterfaceDecl *Interface = dyn_cast<ObjCInterfaceDecl>(Container)) {
- for (ObjCInterfaceDecl::protocol_iterator P = Interface->protocol_begin(),
- PEnd = Interface->protocol_end();
- P != PEnd; ++P)
- CollectOverriddenMethods(*P, Method, Methods);
-
- for (ObjCCategoryDecl *Category = Interface->getCategoryList();
- Category; Category = Category->getNextClassCategory())
- CollectOverriddenMethods(Category, Method, Methods);
-
- // We only look into the superclass if we haven't found anything yet.
- if (Methods.empty())
- if (ObjCInterfaceDecl *Super = Interface->getSuperClass())
- return CollectOverriddenMethods(Super, Method, Methods);
- }
-}
-
void clang_getOverriddenCursors(CXCursor cursor,
CXCursor **overridden,
unsigned *num_overridden) {
@@ -5188,45 +5482,12 @@ void clang_getOverriddenCursors(CXCursor cursor,
if (!overridden || !num_overridden)
return;
- if (!clang_isDeclaration(cursor.kind))
- return;
-
- Decl *D = getCursorDecl(cursor);
- if (!D)
- return;
+ SmallVector<CXCursor, 8> Overridden;
+ cxcursor::getOverriddenCursors(cursor, Overridden);
- // Handle C++ member functions.
- CXTranslationUnit TU = getCursorTU(cursor);
- if (CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) {
- *num_overridden = CXXMethod->size_overridden_methods();
- if (!*num_overridden)
- return;
-
- *overridden = new CXCursor [*num_overridden];
- unsigned I = 0;
- for (CXXMethodDecl::method_iterator
- M = CXXMethod->begin_overridden_methods(),
- MEnd = CXXMethod->end_overridden_methods();
- M != MEnd; (void)++M, ++I)
- (*overridden)[I] = MakeCXCursor(const_cast<CXXMethodDecl*>(*M), TU);
- return;
- }
-
- ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D);
- if (!Method)
- return;
-
- // Handle Objective-C methods.
- llvm::SmallVector<ObjCMethodDecl *, 4> Methods;
- CollectOverriddenMethods(Method->getDeclContext(), Method, Methods);
-
- if (Methods.empty())
- return;
-
- *num_overridden = Methods.size();
- *overridden = new CXCursor [Methods.size()];
- for (unsigned I = 0, N = Methods.size(); I != N; ++I)
- (*overridden)[I] = MakeCXCursor(Methods[I], TU);
+ *num_overridden = Overridden.size();
+ *overridden = new CXCursor [Overridden.size()];
+ std::copy(Overridden.begin(), Overridden.end(), *overridden);
}
void clang_disposeOverriddenCursors(CXCursor *overridden) {
@@ -5274,7 +5535,6 @@ unsigned clang_CXXMethod_isVirtual(CXCursor C) {
Method = dyn_cast_or_null<CXXMethodDecl>(D);
return (Method && Method->isVirtual()) ? 1 : 0;
}
-
} // end: extern "C"
//===----------------------------------------------------------------------===//
@@ -5289,7 +5549,7 @@ CXType clang_getIBOutletCollectionType(CXCursor C) {
IBOutletCollectionAttr *A =
cast<IBOutletCollectionAttr>(cxcursor::getCursorAttr(C));
- return cxtype::MakeCXType(A->getInterFace(), cxcursor::getCursorTU(C));
+ return cxtype::MakeCXType(A->getInterface(), cxcursor::getCursorTU(C));
}
} // end: extern "C"
@@ -5347,6 +5607,12 @@ const char *clang_getTUResourceUsageName(CXTUResourceUsageKind kind) {
case CXTUResourceUsage_PreprocessingRecord:
str = "Preprocessor: PreprocessingRecord";
break;
+ case CXTUResourceUsage_SourceManager_DataStructures:
+ str = "SourceManager: data structures and tables";
+ break;
+ case CXTUResourceUsage_Preprocessor_HeaderSearch:
+ str = "Preprocessor: header search tables";
+ break;
}
return str;
}
@@ -5399,9 +5665,13 @@ CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU) {
createCXTUResourceUsageEntry(*entries,
CXTUResourceUsage_SourceManager_Membuffer_Malloc,
(unsigned long) srcBufs.malloc_bytes);
- createCXTUResourceUsageEntry(*entries,
+ createCXTUResourceUsageEntry(*entries,
CXTUResourceUsage_SourceManager_Membuffer_MMap,
(unsigned long) srcBufs.mmap_bytes);
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_SourceManager_DataStructures,
+ (unsigned long) astContext.getSourceManager()
+ .getDataStructureSizes());
// How much memory is being used by the ExternalASTSource?
if (ExternalASTSource *esrc = astContext.getExternalSource()) {
@@ -5428,6 +5698,9 @@ CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU) {
pRec->getTotalMemory());
}
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_Preprocessor_HeaderSearch,
+ pp.getHeaderSearchInfo().getTotalMemory());
CXTUResourceUsage usage = { (void*) entries.get(),
(unsigned) entries->size(),
diff --git a/tools/libclang/CIndexCXX.cpp b/tools/libclang/CIndexCXX.cpp
index 0f49f65c2b80..fb0ccb146f7d 100644
--- a/tools/libclang/CIndexCXX.cpp
+++ b/tools/libclang/CIndexCXX.cpp
@@ -31,11 +31,16 @@ unsigned clang_isVirtualBase(CXCursor C) {
}
enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor C) {
- if (C.kind != CXCursor_CXXBaseSpecifier)
+ AccessSpecifier spec = AS_none;
+
+ if (C.kind == CXCursor_CXXAccessSpecifier)
+ spec = getCursorDecl(C)->getAccess();
+ else if (C.kind == CXCursor_CXXBaseSpecifier)
+ spec = getCursorCXXBaseSpecifier(C)->getAccessSpecifier();
+ else
return CX_CXXInvalidAccessSpecifier;
- CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C);
- switch (B->getAccessSpecifier()) {
+ switch (spec) {
case AS_public: return CX_CXXPublic;
case AS_protected: return CX_CXXProtected;
case AS_private: return CX_CXXPrivate;
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index 832e2f2f7147..c19b3404920f 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -15,7 +15,12 @@
#include "CIndexer.h"
#include "CXTranslationUnit.h"
#include "CXString.h"
+#include "CXCursor.h"
+#include "CXString.h"
#include "CIndexDiagnostic.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Frontend/ASTUnit.h"
@@ -198,6 +203,20 @@ clang_getCompletionAvailability(CXCompletionString completion_string) {
: CXAvailability_Available;
}
+unsigned clang_getCompletionNumAnnotations(CXCompletionString completion_string)
+{
+ CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+ return CCStr ? CCStr->getAnnotationCount() : 0;
+}
+
+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);
+}
+
+
/// \brief The CXCodeCompleteResults structure we allocate internally;
/// the client only sees the initial CXCodeCompleteResults structure.
struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
@@ -205,10 +224,10 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
~AllocatedCXCodeCompleteResults();
/// \brief Diagnostics produced while performing code completion.
- llvm::SmallVector<StoredDiagnostic, 8> Diagnostics;
+ SmallVector<StoredDiagnostic, 8> Diagnostics;
/// \brief Diag object
- llvm::IntrusiveRefCntPtr<Diagnostic> Diag;
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diag;
/// \brief Language options used to adjust source locations.
LangOptions LangOpts;
@@ -227,7 +246,7 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
/// \brief Temporary buffers that will be deleted once we have finished with
/// the code-completion results.
- llvm::SmallVector<const llvm::MemoryBuffer *, 1> TemporaryBuffers;
+ SmallVector<const llvm::MemoryBuffer *, 1> TemporaryBuffers;
/// \brief Allocator used to store globally cached code-completion results.
llvm::IntrusiveRefCntPtr<clang::GlobalCodeCompletionAllocator>
@@ -242,6 +261,18 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
/// \brief A bitfield representing the acceptable completions for the
/// current context.
unsigned long long Contexts;
+
+ /// \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;
+ /// \brief a boolean value indicating whether there is complete information
+ /// about the container
+ unsigned ContainerIsIncomplete;
+
+ /// \brief A string containing the Objective-C selector entered thus far for a
+ /// message send.
+ std::string Selector;
};
/// \brief Tracks the number of code-completion result objects that are
@@ -253,11 +284,16 @@ static llvm::sys::cas_flag CodeCompletionResultObjects;
AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults(
const FileSystemOptions& FileSystemOpts)
: CXCodeCompleteResults(),
- Diag(new Diagnostic(
+ Diag(new DiagnosticsEngine(
llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs))),
FileSystemOpts(FileSystemOpts),
FileMgr(new FileManager(FileSystemOpts)),
- SourceMgr(new SourceManager(*Diag, *FileMgr)) {
+ SourceMgr(new SourceManager(*Diag, *FileMgr)),
+ Contexts(CXCompletionContext_Unknown),
+ ContainerKind(CXCursor_InvalidCode),
+ ContainerUSR(createCXString("")),
+ ContainerIsIncomplete(1)
+{
if (getenv("LIBCLANG_OBJTRACKING")) {
llvm::sys::AtomicIncrement(&CodeCompletionResultObjects);
fprintf(stderr, "+++ %d completion results\n", CodeCompletionResultObjects);
@@ -267,6 +303,8 @@ 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)
@@ -420,7 +458,7 @@ static unsigned long long getContextsForContextKind(
contexts = CXCompletionContext_ObjCClassMessage;
break;
}
- case CodeCompletionContext::CCC_ObjCSuperclass: {
+ case CodeCompletionContext::CCC_ObjCInterfaceName: {
contexts = CXCompletionContext_ObjCInterface;
break;
}
@@ -454,11 +492,13 @@ static unsigned long long getContextsForContextKind(
namespace {
class CaptureCompletionResults : public CodeCompleteConsumer {
AllocatedCXCodeCompleteResults &AllocatedResults;
- llvm::SmallVector<CXCompletionResult, 16> StoredResults;
+ SmallVector<CXCompletionResult, 16> StoredResults;
+ CXTranslationUnit *TU;
public:
- CaptureCompletionResults(AllocatedCXCodeCompleteResults &Results)
+ CaptureCompletionResults(AllocatedCXCodeCompleteResults &Results,
+ CXTranslationUnit *TranslationUnit)
: CodeCompleteConsumer(true, false, true, false),
- AllocatedResults(Results) { }
+ AllocatedResults(Results), TU(TranslationUnit) { }
~CaptureCompletionResults() { Finish(); }
virtual void ProcessCodeCompleteResults(Sema &S,
@@ -477,10 +517,77 @@ namespace {
StoredResults.push_back(R);
}
- enum CodeCompletionContext::Kind kind = Context.getKind();
+ enum CodeCompletionContext::Kind contextKind = Context.getKind();
- AllocatedResults.ContextKind = kind;
- AllocatedResults.Contexts = getContextsForContextKind(kind, S);
+ AllocatedResults.ContextKind = contextKind;
+ AllocatedResults.Contexts = getContextsForContextKind(contextKind, S);
+
+ AllocatedResults.Selector = "";
+ if (Context.getNumSelIdents() > 0) {
+ for (unsigned i = 0; i < Context.getNumSelIdents(); i++) {
+ IdentifierInfo *selIdent = Context.getSelIdents()[i];
+ if (selIdent != NULL) {
+ StringRef selectorString = Context.getSelIdents()[i]->getName();
+ AllocatedResults.Selector += selectorString;
+ }
+ AllocatedResults.Selector += ":";
+ }
+ }
+
+ QualType baseType = Context.getBaseType();
+ NamedDecl *D = NULL;
+
+ if (!baseType.isNull()) {
+ // Get the declaration for a class/struct/union/enum type
+ if (const TagType *Tag = baseType->getAs<TagType>())
+ D = Tag->getDecl();
+ // Get the @interface declaration for a (possibly-qualified) Objective-C
+ // object pointer type, e.g., NSString*
+ else if (const ObjCObjectPointerType *ObjPtr =
+ baseType->getAs<ObjCObjectPointerType>())
+ D = ObjPtr->getInterfaceDecl();
+ // Get the @interface declaration for an Objective-C object type
+ else if (const ObjCObjectType *Obj = baseType->getAs<ObjCObjectType>())
+ D = Obj->getInterface();
+ // Get the class for a C++ injected-class-name
+ else if (const InjectedClassNameType *Injected =
+ baseType->getAs<InjectedClassNameType>())
+ D = Injected->getDecl();
+ }
+
+ 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;
+
+ const Type *type = baseType.getTypePtrOrNull();
+ if (type != NULL) {
+ AllocatedResults.ContainerIsIncomplete = type->isIncompleteType();
+ }
+ else {
+ AllocatedResults.ContainerIsIncomplete = 1;
+ }
+ }
+ else {
+ AllocatedResults.ContainerKind = CXCursor_InvalidCode;
+ AllocatedResults.ContainerUSR = createCXString("");
+ AllocatedResults.ContainerIsIncomplete = 1;
+ }
}
virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
@@ -551,9 +658,9 @@ void clang_codeCompleteAt_Impl(void *UserData) {
ASTUnit::ConcurrencyCheck Check(*AST);
// Perform the remapping of source files.
- llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles;
+ SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles;
for (unsigned I = 0; I != num_unsaved_files; ++I) {
- llvm::StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length);
+ StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length);
const llvm::MemoryBuffer *Buffer
= llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename);
RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename,
@@ -571,7 +678,7 @@ void clang_codeCompleteAt_Impl(void *UserData) {
Results->NumResults = 0;
// Create a code-completion consumer to capture the results.
- CaptureCompletionResults Capture(*Results);
+ CaptureCompletionResults Capture(*Results, &TU);
// Perform completion.
AST->CodeComplete(complete_filename, complete_line, complete_column,
@@ -621,7 +728,7 @@ void clang_codeCompleteAt_Impl(void *UserData) {
}
pchName.push_back('\0');
struct stat stat_results;
- if (stat(pchName.data(), &stat_results) == 0)
+ if (stat(pchName.str().c_str(), &stat_results) == 0)
usesPCH = true;
continue;
}
@@ -639,7 +746,7 @@ void clang_codeCompleteAt_Impl(void *UserData) {
os << ", \"clangVer\": \"" << getClangFullVersion() << '"';
os << " }";
- llvm::StringRef res = os.str();
+ StringRef res = os.str();
if (res.size() > 0) {
do {
// Setup the UDP socket.
@@ -731,6 +838,40 @@ clang_codeCompleteGetContexts(CXCodeCompleteResults *ResultsIn) {
return Results->Contexts;
}
+enum CXCursorKind clang_codeCompleteGetContainerKind(
+ CXCodeCompleteResults *ResultsIn,
+ unsigned *IsIncomplete) {
+ AllocatedCXCodeCompleteResults *Results =
+ static_cast<AllocatedCXCodeCompleteResults *>(ResultsIn);
+ if (!Results)
+ return CXCursor_InvalidCode;
+
+ if (IsIncomplete != NULL) {
+ *IsIncomplete = Results->ContainerIsIncomplete;
+ }
+
+ return Results->ContainerKind;
+}
+
+CXString clang_codeCompleteGetContainerUSR(CXCodeCompleteResults *ResultsIn) {
+ AllocatedCXCodeCompleteResults *Results =
+ static_cast<AllocatedCXCodeCompleteResults *>(ResultsIn);
+ if (!Results)
+ return createCXString("");
+
+ return createCXString(clang_getCString(Results->ContainerUSR));
+}
+
+
+CXString clang_codeCompleteGetObjCSelector(CXCodeCompleteResults *ResultsIn) {
+ AllocatedCXCodeCompleteResults *Results =
+ static_cast<AllocatedCXCodeCompleteResults *>(ResultsIn);
+ if (!Results)
+ return createCXString("");
+
+ return createCXString(Results->Selector);
+}
+
} // end extern "C"
/// \brief Simple utility function that appends a \p New string to the given
@@ -744,7 +885,7 @@ clang_codeCompleteGetContexts(CXCodeCompleteResults *ResultsIn) {
///
/// \param Buffer A buffer that stores the actual, concatenated string. It will
/// be used if the old string is already-non-empty.
-static void AppendToString(llvm::StringRef &Old, llvm::StringRef New,
+static void AppendToString(StringRef &Old, StringRef New,
llvm::SmallString<256> &Buffer) {
if (Old.empty()) {
Old = New;
@@ -764,9 +905,9 @@ static void AppendToString(llvm::StringRef &Old, llvm::StringRef New,
/// concatenated.
///
/// \param Buffer A buffer used for storage of the completed name.
-static llvm::StringRef GetTypedName(CodeCompletionString *String,
+static StringRef GetTypedName(CodeCompletionString *String,
llvm::SmallString<256> &Buffer) {
- llvm::StringRef Result;
+ StringRef Result;
for (CodeCompletionString::iterator C = String->begin(), CEnd = String->end();
C != CEnd; ++C) {
if (C->Kind == CodeCompletionString::CK_TypedText)
@@ -786,9 +927,9 @@ namespace {
= (CodeCompletionString *)YR.CompletionString;
llvm::SmallString<256> XBuffer;
- llvm::StringRef XText = GetTypedName(X, XBuffer);
+ StringRef XText = GetTypedName(X, XBuffer);
llvm::SmallString<256> YBuffer;
- llvm::StringRef YText = GetTypedName(Y, YBuffer);
+ StringRef YText = GetTypedName(Y, YBuffer);
if (XText.empty() || YText.empty())
return !XText.empty();
diff --git a/tools/libclang/CIndexDiagnostic.cpp b/tools/libclang/CIndexDiagnostic.cpp
index 0fcdab70bebc..26f69b06c195 100644
--- a/tools/libclang/CIndexDiagnostic.cpp
+++ b/tools/libclang/CIndexDiagnostic.cpp
@@ -106,7 +106,7 @@ CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
/* Print warning/error/etc. */
switch (Severity) {
- case CXDiagnostic_Ignored: assert(0 && "impossible"); break;
+ case CXDiagnostic_Ignored: llvm_unreachable("impossible");
case CXDiagnostic_Note: Out << "note: "; break;
case CXDiagnostic_Warning: Out << "warning: "; break;
case CXDiagnostic_Error: Out << "error: "; break;
@@ -182,11 +182,11 @@ enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
return CXDiagnostic_Ignored;
switch (StoredDiag->Diag.getLevel()) {
- case Diagnostic::Ignored: return CXDiagnostic_Ignored;
- case Diagnostic::Note: return CXDiagnostic_Note;
- case Diagnostic::Warning: return CXDiagnostic_Warning;
- case Diagnostic::Error: return CXDiagnostic_Error;
- case Diagnostic::Fatal: return CXDiagnostic_Fatal;
+ case DiagnosticsEngine::Ignored: return CXDiagnostic_Ignored;
+ case DiagnosticsEngine::Note: return CXDiagnostic_Note;
+ case DiagnosticsEngine::Warning: return CXDiagnostic_Warning;
+ case DiagnosticsEngine::Error: return CXDiagnostic_Error;
+ case DiagnosticsEngine::Fatal: return CXDiagnostic_Fatal;
}
llvm_unreachable("Invalid diagnostic level");
@@ -220,11 +220,11 @@ CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) {
return createCXString("");
unsigned ID = StoredDiag->Diag.getID();
- llvm::StringRef Option = DiagnosticIDs::getWarningOptionForDiag(ID);
+ StringRef Option = DiagnosticIDs::getWarningOptionForDiag(ID);
if (!Option.empty()) {
if (Disable)
- *Disable = createCXString((llvm::Twine("-Wno-") + Option).str());
- return createCXString((llvm::Twine("-W") + Option).str());
+ *Disable = createCXString((Twine("-Wno-") + Option).str());
+ return createCXString((Twine("-W") + Option).str());
}
if (ID == diag::fatal_too_many_errors) {
diff --git a/tools/libclang/CIndexHigh.cpp b/tools/libclang/CIndexHigh.cpp
new file mode 100644
index 000000000000..b5a05eaafc0b
--- /dev/null
+++ b/tools/libclang/CIndexHigh.cpp
@@ -0,0 +1,315 @@
+//===- CIndexHigh.cpp - Higher level API functions ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Index_Internal.h"
+#include "CXCursor.h"
+#include "CXSourceLocation.h"
+#include "CXTranslationUnit.h"
+
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/AST/DeclObjC.h"
+
+using namespace clang;
+
+static void getTopOverriddenMethods(CXTranslationUnit TU,
+ Decl *D,
+ SmallVectorImpl<Decl *> &Methods) {
+ if (!isa<ObjCMethodDecl>(D) && !isa<CXXMethodDecl>(D))
+ return;
+
+ SmallVector<CXCursor, 8> Overridden;
+ cxcursor::getOverriddenCursors(cxcursor::MakeCXCursor(D, TU), Overridden);
+
+ if (Overridden.empty()) {
+ Methods.push_back(D->getCanonicalDecl());
+ return;
+ }
+
+ for (SmallVector<CXCursor, 8>::iterator
+ I = Overridden.begin(), E = Overridden.end(); I != E; ++I)
+ getTopOverriddenMethods(TU, cxcursor::getCursorDecl(*I), Methods);
+}
+
+namespace {
+
+struct FindFileIdRefVisitData {
+ CXTranslationUnit TU;
+ FileID FID;
+ Decl *Dcl;
+ int SelectorIdIdx;
+ CXCursorAndRangeVisitor visitor;
+
+ typedef SmallVector<Decl *, 8> TopMethodsTy;
+ TopMethodsTy TopMethods;
+
+ FindFileIdRefVisitData(CXTranslationUnit TU, FileID FID,
+ Decl *D, int selectorIdIdx,
+ CXCursorAndRangeVisitor visitor)
+ : TU(TU), FID(FID), SelectorIdIdx(selectorIdIdx), visitor(visitor) {
+ Dcl = getCanonical(D);
+ getTopOverriddenMethods(TU, Dcl, TopMethods);
+ }
+
+ ASTContext &getASTContext() const {
+ return static_cast<ASTUnit *>(TU->TUData)->getASTContext();
+ }
+
+ /// \brief We are looking to find all semantically relevant identifiers,
+ /// so the definition of "canonical" here is different than in the AST, e.g.
+ ///
+ /// \code
+ /// class C {
+ /// C() {}
+ /// };
+ /// \endcode
+ ///
+ /// 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 {
+ D = D->getCanonicalDecl();
+
+ if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D))
+ return getCanonical(ImplD->getClassInterface());
+ if (CXXConstructorDecl *CXXCtorD = dyn_cast<CXXConstructorDecl>(D))
+ return getCanonical(CXXCtorD->getParent());
+
+ return D;
+ }
+
+ bool isHit(Decl *D) const {
+ D = getCanonical(D);
+ if (D == Dcl)
+ return true;
+
+ if (isa<ObjCMethodDecl>(D) || isa<CXXMethodDecl>(D))
+ return isOverriddingMethod(D);
+
+ return false;
+ }
+
+private:
+ bool isOverriddingMethod(Decl *D) const {
+ if (std::find(TopMethods.begin(), TopMethods.end(), D) !=
+ TopMethods.end())
+ return true;
+
+ TopMethodsTy methods;
+ getTopOverriddenMethods(TU, D, methods);
+ for (TopMethodsTy::iterator
+ I = methods.begin(), E = methods.end(); I != E; ++I) {
+ if (std::find(TopMethods.begin(), TopMethods.end(), *I) !=
+ TopMethods.end())
+ return true;
+ }
+
+ return false;
+ }
+};
+
+} // end anonymous namespace.
+
+/// \brief For a macro \arg Loc, returns the file spelling location and sets
+/// to \arg isMacroArg whether the spelling resides inside a macro definition or
+/// a macro argument.
+static SourceLocation getFileSpellingLoc(SourceManager &SM,
+ SourceLocation Loc,
+ bool &isMacroArg) {
+ assert(Loc.isMacroID());
+ SourceLocation SpellLoc = SM.getImmediateSpellingLoc(Loc);
+ if (SpellLoc.isMacroID())
+ return getFileSpellingLoc(SM, SpellLoc, isMacroArg);
+
+ isMacroArg = SM.isMacroArgExpansion(Loc);
+ return SpellLoc;
+}
+
+static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor,
+ CXCursor parent,
+ CXClientData client_data) {
+ CXCursor declCursor = clang_getCursorReferenced(cursor);
+ if (!clang_isDeclaration(declCursor.kind))
+ return CXChildVisit_Recurse;
+
+ Decl *D = cxcursor::getCursorDecl(declCursor);
+ FindFileIdRefVisitData *data = (FindFileIdRefVisitData *)client_data;
+ if (data->isHit(D)) {
+ cursor = cxcursor::getSelectorIdentifierCursor(data->SelectorIdIdx, cursor);
+
+ // We are looking for identifiers to highlight so for objc methods (and
+ // not a parameter) we can only highlight the selector identifiers.
+ if ((cursor.kind == CXCursor_ObjCClassMethodDecl ||
+ cursor.kind == CXCursor_ObjCInstanceMethodDecl) &&
+ cxcursor::getSelectorIdentifierIndex(cursor) == -1)
+ return CXChildVisit_Recurse;
+
+ if (clang_isExpression(cursor.kind)) {
+ if (cursor.kind == CXCursor_DeclRefExpr ||
+ cursor.kind == CXCursor_MemberRefExpr) {
+ // continue..
+
+ } else if (cursor.kind == CXCursor_ObjCMessageExpr &&
+ cxcursor::getSelectorIdentifierIndex(cursor) != -1) {
+ // continue..
+
+ } else
+ return CXChildVisit_Recurse;
+ }
+
+ SourceLocation
+ Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor));
+ SourceLocation SelIdLoc = cxcursor::getSelectorIdentifierLoc(cursor);
+ if (SelIdLoc.isValid())
+ Loc = SelIdLoc;
+
+ SourceManager &SM = data->getASTContext().getSourceManager();
+ bool isInMacroDef = false;
+ if (Loc.isMacroID()) {
+ bool isMacroArg;
+ Loc = getFileSpellingLoc(SM, Loc, isMacroArg);
+ isInMacroDef = !isMacroArg;
+ }
+
+ // We are looking for identifiers in a specific file.
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ if (LocInfo.first != data->FID)
+ return CXChildVisit_Recurse;
+
+ if (isInMacroDef) {
+ // FIXME: For a macro definition make sure that all expansions
+ // of it expand to the same reference before allowing to point to it.
+ Loc = SourceLocation();
+ }
+
+ data->visitor.visit(data->visitor.context, cursor,
+ cxloc::translateSourceRange(D->getASTContext(), Loc));
+ }
+ return CXChildVisit_Recurse;
+}
+
+static void findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor,
+ const FileEntry *File,
+ CXCursorAndRangeVisitor Visitor) {
+ assert(clang_isDeclaration(declCursor.kind));
+ ASTUnit *Unit = static_cast<ASTUnit*>(TU->TUData);
+ ASTContext &Ctx = Unit->getASTContext();
+ SourceManager &SM = Unit->getSourceManager();
+
+ FileID FID = SM.translateFile(File);
+ Decl *Dcl = cxcursor::getCursorDecl(declCursor);
+ 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 (FID == SM.getMainFileID() && !Unit->isMainFileAST()) {
+ SourceLocation FileLoc = SM.getLocForStartOfFile(FID);
+ TranslationUnitDecl *TUD = Ctx.getTranslationUnitDecl();
+ CXCursor TUCursor = clang_getTranslationUnitCursor(TU);
+ for (DeclContext::decl_iterator
+ I = TUD->noload_decls_begin(), E = TUD->noload_decls_end();
+ I != E; ++I) {
+ Decl *D = *I;
+
+ SourceRange R = D->getSourceRange();
+ if (R.isInvalid())
+ continue;
+ if (SM.isBeforeInTranslationUnit(R.getEnd(), FileLoc))
+ continue;
+
+ if (TagDecl *TD = dyn_cast<TagDecl>(D))
+ if (!TD->isFreeStanding())
+ continue;
+
+ CXCursor CurCursor = cxcursor::MakeCXCursor(D, TU);
+ findFileIdRefVisit(CurCursor, TUCursor, &data);
+ clang_visitChildren(CurCursor, findFileIdRefVisit, &data);
+ }
+ return;
+ }
+
+ clang_visitChildren(clang_getTranslationUnitCursor(TU),
+ findFileIdRefVisit, &data);
+}
+
+
+//===----------------------------------------------------------------------===//
+// libclang public APIs.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+
+void clang_findReferencesInFile(CXCursor cursor, CXFile file,
+ CXCursorAndRangeVisitor visitor) {
+ bool Logging = ::getenv("LIBCLANG_LOGGING");
+
+ if (clang_Cursor_isNull(cursor)) {
+ if (Logging)
+ llvm::errs() << "clang_findReferencesInFile: Null cursor\n";
+ return;
+ }
+ if (!file) {
+ if (Logging)
+ llvm::errs() << "clang_findReferencesInFile: Null file\n";
+ return;
+ }
+ if (!visitor.visit) {
+ if (Logging)
+ llvm::errs() << "clang_findReferencesInFile: Null visitor\n";
+ return;
+ }
+
+ // We are interested in semantics of identifiers so for C++ constructor exprs
+ // prefer type references, e.g.:
+ //
+ // return MyStruct();
+ //
+ // for 'MyStruct' we'll have a cursor pointing at the constructor decl but
+ // we are actually interested in the type declaration.
+ cursor = cxcursor::getTypeRefCursor(cursor);
+
+ CXCursor refCursor = clang_getCursorReferenced(cursor);
+
+ if (!clang_isDeclaration(refCursor.kind)) {
+ if (Logging)
+ llvm::errs() << "clang_findReferencesInFile: cursor is not referencing a "
+ "declaration\n";
+ return;
+ }
+
+ ASTUnit *CXXUnit = cxcursor::getCursorASTUnit(cursor);
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+
+ findIdRefsInFile(cxcursor::getCursorTU(cursor),
+ refCursor,
+ static_cast<const FileEntry *>(file),
+ visitor);
+}
+
+static enum CXVisitorResult _visitCursorAndRange(void *context,
+ CXCursor cursor,
+ CXSourceRange range) {
+ CXCursorAndRangeVisitorBlock block = (CXCursorAndRangeVisitorBlock)context;
+ return INVOKE_BLOCK2(block, cursor, range);
+}
+
+void clang_findReferencesInFileWithBlock(CXCursor cursor,
+ CXFile file,
+ CXCursorAndRangeVisitorBlock block) {
+ CXCursorAndRangeVisitor visitor = { block,
+ block ? _visitCursorAndRange : 0 };
+ return clang_findReferencesInFile(cursor, file, visitor);
+}
+
+} // end: extern "C"
+
diff --git a/tools/libclang/CIndexInclusionStack.cpp b/tools/libclang/CIndexInclusionStack.cpp
index 6bc4f2e776a3..848ca31a5e32 100644
--- a/tools/libclang/CIndexInclusionStack.cpp
+++ b/tools/libclang/CIndexInclusionStack.cpp
@@ -29,19 +29,22 @@ void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB,
SourceManager &SM = CXXUnit->getSourceManager();
ASTContext &Ctx = CXXUnit->getASTContext();
- llvm::SmallVector<CXSourceLocation, 10> InclusionStack;
- unsigned i = SM.sloc_loaded_entry_size();
- unsigned n = SM.sloc_entry_size();
+ SmallVector<CXSourceLocation, 10> InclusionStack;
+ unsigned n = SM.local_sloc_entry_size();
// In the case where all the SLocEntries are in an external source, traverse
// those SLocEntries as well. This is the case where we are looking
// at the inclusion stack of an AST/PCH file.
- if (i >= n)
- i = 0;
-
- for ( ; i < n ; ++i) {
+ const SrcMgr::SLocEntry &(SourceManager::*Getter)(unsigned, bool*) const;
+ if (n == 1) {
+ Getter = &SourceManager::getLoadedSLocEntry;
+ n = SM.loaded_sloc_entry_size();
+ } else
+ Getter = &SourceManager::getLocalSLocEntry;
+
+ for (unsigned i = 0 ; i < n ; ++i) {
bool Invalid = false;
- const SrcMgr::SLocEntry &SL = SM.getSLocEntry(i, &Invalid);
+ const SrcMgr::SLocEntry &SL = (SM.*Getter)(i, &Invalid);
if (!SL.isFile() || Invalid)
continue;
diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp
index 4f1f071c1dd2..121d67d1d2e7 100644
--- a/tools/libclang/CIndexUSRs.cpp
+++ b/tools/libclang/CIndexUSRs.cpp
@@ -31,28 +31,28 @@ using namespace clang::cxstring;
namespace {
class USRGenerator : public DeclVisitor<USRGenerator> {
llvm::OwningPtr<llvm::SmallString<128> > OwnedBuf;
- llvm::SmallVectorImpl<char> &Buf;
+ SmallVectorImpl<char> &Buf;
llvm::raw_svector_ostream Out;
bool IgnoreResults;
- ASTUnit *AU;
+ ASTContext *Context;
bool generatedLoc;
llvm::DenseMap<const Type *, unsigned> TypeSubstitutions;
public:
- USRGenerator(const CXCursor *C = 0, llvm::SmallVectorImpl<char> *extBuf = 0)
+ explicit USRGenerator(ASTContext *Ctx = 0, SmallVectorImpl<char> *extBuf = 0)
: OwnedBuf(extBuf ? 0 : new llvm::SmallString<128>()),
Buf(extBuf ? *extBuf : *OwnedBuf.get()),
Out(Buf),
IgnoreResults(false),
- AU(C ? cxcursor::getCursorASTUnit(*C) : 0),
+ Context(Ctx),
generatedLoc(false)
{
// Add the USR space prefix.
Out << "c:";
}
- llvm::StringRef str() {
+ StringRef str() {
return Out.str();
}
@@ -114,19 +114,19 @@ public:
/// itself.
/// Generate a USR for an Objective-C class.
- void GenObjCClass(llvm::StringRef cls);
+ void GenObjCClass(StringRef cls);
/// Generate a USR for an Objective-C class category.
- void GenObjCCategory(llvm::StringRef cls, llvm::StringRef cat);
+ void GenObjCCategory(StringRef cls, StringRef cat);
/// Generate a USR fragment for an Objective-C instance variable. The
/// complete USR can be created by concatenating the USR for the
/// encompassing class with this USR fragment.
- void GenObjCIvar(llvm::StringRef ivar);
+ void GenObjCIvar(StringRef ivar);
/// Generate a USR fragment for an Objective-C method.
- void GenObjCMethod(llvm::StringRef sel, bool isInstanceMethod);
+ void GenObjCMethod(StringRef sel, bool isInstanceMethod);
/// Generate a USR fragment for an Objective-C property.
- void GenObjCProperty(llvm::StringRef prop);
+ void GenObjCProperty(StringRef prop);
/// Generate a USR for an Objective-C protocol.
- void GenObjCProtocol(llvm::StringRef prot);
+ void GenObjCProtocol(StringRef prot);
void VisitType(QualType T);
void VisitTemplateParameterList(const TemplateParameterList *Params);
@@ -190,7 +190,7 @@ void USRGenerator::VisitFunctionDecl(FunctionDecl *D) {
Out << "@F@";
D->printName(Out);
- ASTContext &Ctx = AU->getASTContext();
+ ASTContext &Ctx = *Context;
if (!Ctx.getLangOptions().CPlusPlus || D->isExternC())
return;
@@ -235,7 +235,7 @@ void USRGenerator::VisitVarDecl(VarDecl *D) {
VisitDeclContext(D->getDeclContext());
// Variables always have simple names.
- llvm::StringRef s = D->getName();
+ StringRef s = D->getName();
// The string can be empty if the declaration has no name; e.g., it is
// the ParmDecl with no name for declaration of a function pointer type, e.g.:
@@ -320,7 +320,7 @@ void USRGenerator::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) {
switch (D->getKind()) {
default:
- assert(false && "Invalid ObjC container.");
+ llvm_unreachable("Invalid ObjC container.");
case Decl::ObjCInterface:
case Decl::ObjCImplementation:
GenObjCClass(D->getName());
@@ -433,7 +433,7 @@ void USRGenerator::VisitTagDecl(TagDecl *D) {
if (EmitDeclName(D)) {
if (const TypedefNameDecl *TD = D->getTypedefNameForAnonDecl()) {
Buf[off] = 'A';
- Out << '@' << TD;
+ Out << '@' << *TD;
}
else
Buf[off] = 'a';
@@ -480,13 +480,13 @@ bool USRGenerator::GenLoc(const Decl *D) {
// Use the location of canonical decl.
D = D->getCanonicalDecl();
- const SourceManager &SM = AU->getSourceManager();
+ const SourceManager &SM = Context->getSourceManager();
SourceLocation L = D->getLocStart();
if (L.isInvalid()) {
IgnoreResults = true;
return true;
}
- L = SM.getInstantiationLoc(L);
+ L = SM.getExpansionLoc(L);
const std::pair<FileID, unsigned> &Decomposed = SM.getDecomposedLoc(L);
const FileEntry *FE = SM.getFileEntryForID(Decomposed.first);
if (FE) {
@@ -508,7 +508,7 @@ void USRGenerator::VisitType(QualType T) {
// This method mangles in USR information for types. It can possibly
// just reuse the naming-mangling logic used by codegen, although the
// requirements for USRs might not be the same.
- ASTContext &Ctx = AU->getASTContext();
+ ASTContext &Ctx = *Context;
do {
T = Ctx.getCanonicalType(T);
@@ -570,6 +570,8 @@ void USRGenerator::VisitType(QualType T) {
c = 'K'; break;
case BuiltinType::Int128:
c = 'J'; break;
+ case BuiltinType::Half:
+ c = 'h'; break;
case BuiltinType::Float:
c = 'f'; break;
case BuiltinType::Double:
@@ -755,27 +757,27 @@ void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) {
// General purpose USR generation methods.
//===----------------------------------------------------------------------===//
-void USRGenerator::GenObjCClass(llvm::StringRef cls) {
+void USRGenerator::GenObjCClass(StringRef cls) {
Out << "objc(cs)" << cls;
}
-void USRGenerator::GenObjCCategory(llvm::StringRef cls, llvm::StringRef cat) {
+void USRGenerator::GenObjCCategory(StringRef cls, StringRef cat) {
Out << "objc(cy)" << cls << '@' << cat;
}
-void USRGenerator::GenObjCIvar(llvm::StringRef ivar) {
+void USRGenerator::GenObjCIvar(StringRef ivar) {
Out << '@' << ivar;
}
-void USRGenerator::GenObjCMethod(llvm::StringRef meth, bool isInstanceMethod) {
+void USRGenerator::GenObjCMethod(StringRef meth, bool isInstanceMethod) {
Out << (isInstanceMethod ? "(im)" : "(cm)") << meth;
}
-void USRGenerator::GenObjCProperty(llvm::StringRef prop) {
+void USRGenerator::GenObjCProperty(StringRef prop) {
Out << "(py)" << prop;
}
-void USRGenerator::GenObjCProtocol(llvm::StringRef prot) {
+void USRGenerator::GenObjCProtocol(StringRef prot) {
Out << "objc(pl)" << prot;
}
@@ -783,16 +785,14 @@ void USRGenerator::GenObjCProtocol(llvm::StringRef prot) {
// API hooks.
//===----------------------------------------------------------------------===//
-static inline llvm::StringRef extractUSRSuffix(llvm::StringRef s) {
+static inline StringRef extractUSRSuffix(StringRef s) {
return s.startswith("c:") ? s.substr(2) : "";
}
-static CXString getDeclCursorUSR(const CXCursor &C) {
- Decl *D = cxcursor::getCursorDecl(C);
-
+bool cxcursor::getDeclCursorUSR(Decl *D, SmallVectorImpl<char> &Buf) {
// Don't generate USRs for things with invalid locations.
if (!D || D->getLocStart().isInvalid())
- return createCXString("");
+ return true;
// Check if the cursor has 'NoLinkage'.
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
@@ -817,27 +817,15 @@ static CXString getDeclCursorUSR(const CXCursor &C) {
break;
}
- CXTranslationUnit TU = cxcursor::getCursorTU(C);
- if (!TU)
- return createCXString("");
-
- CXStringBuf *buf = cxstring::getCXStringBuf(TU);
- if (!buf)
- return createCXString("");
-
{
- USRGenerator UG(&C, &buf->Data);
+ USRGenerator UG(&D->getASTContext(), &Buf);
UG->Visit(D);
- if (UG->ignoreResults()) {
- disposeCXStringBuf(buf);
- return createCXString("");
- }
+ if (UG->ignoreResults())
+ return true;
}
- // Return the C-string, but don't make a copy since it is already in
- // the string buffer.
- buf->Data.push_back('\0');
- return createCXString(buf);
+
+ return false;
}
extern "C" {
@@ -845,8 +833,27 @@ extern "C" {
CXString clang_getCursorUSR(CXCursor C) {
const CXCursorKind &K = clang_getCursorKind(C);
- if (clang_isDeclaration(K))
- return getDeclCursorUSR(C);
+ if (clang_isDeclaration(K)) {
+ Decl *D = cxcursor::getCursorDecl(C);
+ CXTranslationUnit TU = cxcursor::getCursorTU(C);
+ if (!TU)
+ return createCXString("");
+
+ CXStringBuf *buf = cxstring::getCXStringBuf(TU);
+ if (!buf)
+ return createCXString("");
+
+ bool Ignore = cxcursor::getDeclCursorUSR(D, buf->Data);
+ if (Ignore) {
+ disposeCXStringBuf(buf);
+ return createCXString("");
+ }
+
+ // Return the C-string, but don't make a copy since it is already in
+ // the string buffer.
+ buf->Data.push_back('\0');
+ return createCXString(buf);
+ }
if (K == CXCursor_MacroDefinition) {
CXTranslationUnit TU = cxcursor::getCursorTU(C);
@@ -858,7 +865,8 @@ CXString clang_getCursorUSR(CXCursor C) {
return createCXString("");
{
- USRGenerator UG(&C, &buf->Data);
+ USRGenerator UG(&cxcursor::getCursorASTUnit(C)->getASTContext(),
+ &buf->Data);
UG << "macro@"
<< cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart();
}
diff --git a/tools/libclang/CIndexer.cpp b/tools/libclang/CIndexer.cpp
index 56974b9e999b..995a8febb088 100644
--- a/tools/libclang/CIndexer.cpp
+++ b/tools/libclang/CIndexer.cpp
@@ -74,7 +74,7 @@ std::string CIndexer::getClangResourcesPath() {
// This silly cast below avoids a C++ warning.
Dl_info info;
if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) == 0)
- assert(0 && "Call to dladdr() failed");
+ llvm_unreachable("Call to dladdr() failed");
llvm::sys::Path LibClangPath(info.dli_fname);
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index f45389f0b9f4..f754e980b93f 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -21,6 +21,7 @@ set(SOURCES
CIndexCXX.cpp
CIndexCodeCompletion.cpp
CIndexDiagnostic.cpp
+ CIndexHigh.cpp
CIndexInclusionStack.cpp
CIndexUSRs.cpp
CIndexer.cpp
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index b3c57dc9344f..db2750014351 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -20,8 +20,10 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
#include "clang-c/Index.h"
#include "llvm/Support/ErrorHandling.h"
@@ -30,7 +32,7 @@ using namespace cxcursor;
CXCursor cxcursor::MakeCXCursorInvalid(CXCursorKind K) {
assert(K >= CXCursor_FirstInvalid && K <= CXCursor_LastInvalid);
- CXCursor C = { K, { 0, 0, 0 } };
+ CXCursor C = { K, 0, { 0, 0, 0 } };
return C;
}
@@ -41,6 +43,9 @@ static CXCursorKind GetCursorKind(const Attr *A) {
case attr::IBAction: return CXCursor_IBActionAttr;
case attr::IBOutlet: return CXCursor_IBOutletAttr;
case attr::IBOutletCollection: return CXCursor_IBOutletCollectionAttr;
+ case attr::Final: return CXCursor_CXXFinalAttr;
+ case attr::Override: return CXCursor_CXXOverrideAttr;
+ case attr::Annotate: return CXCursor_AnnotateAttr;
}
return CXCursor_UnexposedAttr;
@@ -49,152 +54,369 @@ static CXCursorKind GetCursorKind(const Attr *A) {
CXCursor cxcursor::MakeCXCursor(const Attr *A, Decl *Parent,
CXTranslationUnit TU) {
assert(A && Parent && TU && "Invalid arguments!");
- CXCursor C = { GetCursorKind(A), { Parent, (void*)A, TU } };
+ CXCursor C = { GetCursorKind(A), 0, { Parent, (void*)A, TU } };
return C;
}
CXCursor cxcursor::MakeCXCursor(Decl *D, CXTranslationUnit TU,
+ SourceRange RegionOfInterest,
bool FirstInDeclGroup) {
assert(D && TU && "Invalid arguments!");
- CXCursor C = { getCursorKindForDecl(D),
- { D, (void*)(intptr_t) (FirstInDeclGroup ? 1 : 0), TU }
- };
+
+ CXCursorKind K = getCursorKindForDecl(D);
+
+ if (K == CXCursor_ObjCClassMethodDecl ||
+ K == CXCursor_ObjCInstanceMethodDecl) {
+ int SelectorIdIndex = -1;
+ // Check if cursor points to a selector id.
+ if (RegionOfInterest.isValid() &&
+ RegionOfInterest.getBegin() == RegionOfInterest.getEnd()) {
+ SmallVector<SourceLocation, 16> SelLocs;
+ cast<ObjCMethodDecl>(D)->getSelectorLocs(SelLocs);
+ SmallVector<SourceLocation, 16>::iterator
+ I=std::find(SelLocs.begin(), SelLocs.end(),RegionOfInterest.getBegin());
+ if (I != SelLocs.end())
+ SelectorIdIndex = I - SelLocs.begin();
+ }
+ CXCursor C = { K, SelectorIdIndex,
+ { D, (void*)(intptr_t) (FirstInDeclGroup ? 1 : 0), TU }};
+ return C;
+ }
+
+ CXCursor C = { K, 0, { D, (void*)(intptr_t) (FirstInDeclGroup ? 1 : 0), TU }};
return C;
}
-CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
- CXTranslationUnit TU) {
+CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
+ SourceRange RegionOfInterest) {
assert(S && TU && "Invalid arguments!");
CXCursorKind K = CXCursor_NotImplemented;
switch (S->getStmtClass()) {
case Stmt::NoStmtClass:
break;
-
- case Stmt::NullStmtClass:
- case Stmt::CompoundStmtClass:
+
case Stmt::CaseStmtClass:
+ K = CXCursor_CaseStmt;
+ break;
+
case Stmt::DefaultStmtClass:
- case Stmt::IfStmtClass:
- case Stmt::SwitchStmtClass:
- case Stmt::WhileStmtClass:
- case Stmt::DoStmtClass:
- case Stmt::ForStmtClass:
- case Stmt::GotoStmtClass:
+ K = CXCursor_DefaultStmt;
+ break;
+
+ case Stmt::IfStmtClass:
+ K = CXCursor_IfStmt;
+ break;
+
+ case Stmt::SwitchStmtClass:
+ K = CXCursor_SwitchStmt;
+ break;
+
+ case Stmt::WhileStmtClass:
+ K = CXCursor_WhileStmt;
+ break;
+
+ case Stmt::DoStmtClass:
+ K = CXCursor_DoStmt;
+ break;
+
+ case Stmt::ForStmtClass:
+ K = CXCursor_ForStmt;
+ break;
+
+ case Stmt::GotoStmtClass:
+ K = CXCursor_GotoStmt;
+ break;
+
case Stmt::IndirectGotoStmtClass:
- case Stmt::ContinueStmtClass:
- case Stmt::BreakStmtClass:
- case Stmt::ReturnStmtClass:
- case Stmt::DeclStmtClass:
- case Stmt::AsmStmtClass:
- case Stmt::ObjCAtTryStmtClass:
- case Stmt::ObjCAtCatchStmtClass:
- case Stmt::ObjCAtFinallyStmtClass:
- case Stmt::ObjCAtThrowStmtClass:
- case Stmt::ObjCAtSynchronizedStmtClass:
- case Stmt::ObjCAutoreleasePoolStmtClass:
+ K = CXCursor_IndirectGotoStmt;
+ break;
+
+ case Stmt::ContinueStmtClass:
+ K = CXCursor_ContinueStmt;
+ break;
+
+ case Stmt::BreakStmtClass:
+ K = CXCursor_BreakStmt;
+ break;
+
+ case Stmt::ReturnStmtClass:
+ K = CXCursor_ReturnStmt;
+ break;
+
+ case Stmt::AsmStmtClass:
+ K = CXCursor_AsmStmt;
+ break;
+
+ case Stmt::ObjCAtTryStmtClass:
+ K = CXCursor_ObjCAtTryStmt;
+ break;
+
+ case Stmt::ObjCAtCatchStmtClass:
+ K = CXCursor_ObjCAtCatchStmt;
+ break;
+
+ case Stmt::ObjCAtFinallyStmtClass:
+ K = CXCursor_ObjCAtFinallyStmt;
+ break;
+
+ case Stmt::ObjCAtThrowStmtClass:
+ K = CXCursor_ObjCAtThrowStmt;
+ break;
+
+ case Stmt::ObjCAtSynchronizedStmtClass:
+ K = CXCursor_ObjCAtSynchronizedStmt;
+ break;
+
+ case Stmt::ObjCAutoreleasePoolStmtClass:
+ K = CXCursor_ObjCAutoreleasePoolStmt;
+ break;
+
case Stmt::ObjCForCollectionStmtClass:
+ K = CXCursor_ObjCForCollectionStmt;
+ break;
+
case Stmt::CXXCatchStmtClass:
- case Stmt::CXXTryStmtClass:
- case Stmt::CXXForRangeStmtClass:
+ K = CXCursor_CXXCatchStmt;
+ break;
+
+ case Stmt::CXXTryStmtClass:
+ K = CXCursor_CXXTryStmt;
+ break;
+
+ case Stmt::CXXForRangeStmtClass:
+ K = CXCursor_CXXForRangeStmt;
+ break;
+
case Stmt::SEHTryStmtClass:
+ K = CXCursor_SEHTryStmt;
+ break;
+
case Stmt::SEHExceptStmtClass:
+ K = CXCursor_SEHExceptStmt;
+ break;
+
case Stmt::SEHFinallyStmtClass:
+ K = CXCursor_SEHFinallyStmt;
+ break;
+
+ case Stmt::ArrayTypeTraitExprClass:
+ case Stmt::AsTypeExprClass:
+ case Stmt::AtomicExprClass:
+ case Stmt::BinaryConditionalOperatorClass:
+ case Stmt::BinaryTypeTraitExprClass:
+ case Stmt::CXXBindTemporaryExprClass:
+ case Stmt::CXXDefaultArgExprClass:
+ case Stmt::CXXScalarValueInitExprClass:
+ case Stmt::CXXUuidofExprClass:
+ case Stmt::ChooseExprClass:
+ case Stmt::DesignatedInitExprClass:
+ case Stmt::ExprWithCleanupsClass:
+ case Stmt::ExpressionTraitExprClass:
+ case Stmt::ExtVectorElementExprClass:
+ case Stmt::ImplicitCastExprClass:
+ case Stmt::ImplicitValueInitExprClass:
case Stmt::MaterializeTemporaryExprClass:
- K = CXCursor_UnexposedStmt;
+ case Stmt::ObjCIndirectCopyRestoreExprClass:
+ case Stmt::OffsetOfExprClass:
+ case Stmt::OpaqueValueExprClass:
+ case Stmt::ParenListExprClass:
+ case Stmt::PredefinedExprClass:
+ case Stmt::ShuffleVectorExprClass:
+ case Stmt::UnaryExprOrTypeTraitExprClass:
+ case Stmt::UnaryTypeTraitExprClass:
+ case Stmt::VAArgExprClass:
+ K = CXCursor_UnexposedExpr;
+ break;
+
+ case Stmt::CompoundStmtClass:
+ K = CXCursor_CompoundStmt;
break;
- case Stmt::LabelStmtClass:
- K = CXCursor_LabelStmt;
+ case Stmt::NullStmtClass:
+ K = CXCursor_NullStmt;
break;
- case Stmt::PredefinedExprClass:
- case Stmt::IntegerLiteralClass:
- case Stmt::FloatingLiteralClass:
- case Stmt::ImaginaryLiteralClass:
- case Stmt::StringLiteralClass:
- case Stmt::CharacterLiteralClass:
- case Stmt::ParenExprClass:
+ case Stmt::LabelStmtClass:
+ K = CXCursor_LabelStmt;
+ break;
+
+ case Stmt::DeclStmtClass:
+ K = CXCursor_DeclStmt;
+ break;
+
+ case Stmt::IntegerLiteralClass:
+ K = CXCursor_IntegerLiteral;
+ break;
+
+ case Stmt::FloatingLiteralClass:
+ K = CXCursor_FloatingLiteral;
+ break;
+
+ case Stmt::ImaginaryLiteralClass:
+ K = CXCursor_ImaginaryLiteral;
+ break;
+
+ case Stmt::StringLiteralClass:
+ K = CXCursor_StringLiteral;
+ break;
+
+ case Stmt::CharacterLiteralClass:
+ K = CXCursor_CharacterLiteral;
+ break;
+
+ case Stmt::ParenExprClass:
+ K = CXCursor_ParenExpr;
+ break;
+
case Stmt::UnaryOperatorClass:
- case Stmt::OffsetOfExprClass:
- case Stmt::UnaryExprOrTypeTraitExprClass:
- case Stmt::ArraySubscriptExprClass:
- case Stmt::BinaryOperatorClass:
+ K = CXCursor_UnaryOperator;
+ break;
+
+ case Stmt::CXXNoexceptExprClass:
+ K = CXCursor_UnaryExpr;
+ break;
+
+ case Stmt::ArraySubscriptExprClass:
+ K = CXCursor_ArraySubscriptExpr;
+ break;
+
+ case Stmt::BinaryOperatorClass:
+ K = CXCursor_BinaryOperator;
+ break;
+
case Stmt::CompoundAssignOperatorClass:
- case Stmt::ConditionalOperatorClass:
- case Stmt::BinaryConditionalOperatorClass:
- case Stmt::ImplicitCastExprClass:
+ K = CXCursor_CompoundAssignOperator;
+ break;
+
+ case Stmt::ConditionalOperatorClass:
+ K = CXCursor_ConditionalOperator;
+ break;
+
case Stmt::CStyleCastExprClass:
- case Stmt::CompoundLiteralExprClass:
- case Stmt::ExtVectorElementExprClass:
- case Stmt::InitListExprClass:
- case Stmt::DesignatedInitExprClass:
- case Stmt::ImplicitValueInitExprClass:
- case Stmt::ParenListExprClass:
- case Stmt::VAArgExprClass:
- case Stmt::AddrLabelExprClass:
- case Stmt::StmtExprClass:
- case Stmt::ChooseExprClass:
+ K = CXCursor_CStyleCastExpr;
+ break;
+
+ case Stmt::CompoundLiteralExprClass:
+ K = CXCursor_CompoundLiteralExpr;
+ break;
+
+ case Stmt::InitListExprClass:
+ K = CXCursor_InitListExpr;
+ break;
+
+ case Stmt::AddrLabelExprClass:
+ K = CXCursor_AddrLabelExpr;
+ break;
+
+ case Stmt::StmtExprClass:
+ K = CXCursor_StmtExpr;
+ break;
+
case Stmt::GenericSelectionExprClass:
- case Stmt::GNUNullExprClass:
- case Stmt::CXXStaticCastExprClass:
- case Stmt::CXXDynamicCastExprClass:
- case Stmt::CXXReinterpretCastExprClass:
- case Stmt::CXXConstCastExprClass:
+ K = CXCursor_GenericSelectionExpr;
+ break;
+
+ case Stmt::GNUNullExprClass:
+ K = CXCursor_GNUNullExpr;
+ break;
+
+ case Stmt::CXXStaticCastExprClass:
+ K = CXCursor_CXXStaticCastExpr;
+ break;
+
+ case Stmt::CXXDynamicCastExprClass:
+ K = CXCursor_CXXDynamicCastExpr;
+ break;
+
+ case Stmt::CXXReinterpretCastExprClass:
+ K = CXCursor_CXXReinterpretCastExpr;
+ break;
+
+ case Stmt::CXXConstCastExprClass:
+ K = CXCursor_CXXConstCastExpr;
+ break;
+
case Stmt::CXXFunctionalCastExprClass:
- case Stmt::CXXTypeidExprClass:
- case Stmt::CXXUuidofExprClass:
- case Stmt::CXXBoolLiteralExprClass:
- case Stmt::CXXNullPtrLiteralExprClass:
- case Stmt::CXXThisExprClass:
- case Stmt::CXXThrowExprClass:
- case Stmt::CXXDefaultArgExprClass:
- case Stmt::CXXScalarValueInitExprClass:
- case Stmt::CXXNewExprClass:
- case Stmt::CXXDeleteExprClass:
- case Stmt::CXXPseudoDestructorExprClass:
- case Stmt::UnresolvedLookupExprClass:
- case Stmt::UnaryTypeTraitExprClass:
- case Stmt::BinaryTypeTraitExprClass:
- case Stmt::ArrayTypeTraitExprClass:
- case Stmt::ExpressionTraitExprClass:
- case Stmt::DependentScopeDeclRefExprClass:
- case Stmt::CXXBindTemporaryExprClass:
- case Stmt::ExprWithCleanupsClass:
- case Stmt::CXXUnresolvedConstructExprClass:
- case Stmt::CXXDependentScopeMemberExprClass:
- case Stmt::UnresolvedMemberExprClass:
- case Stmt::CXXNoexceptExprClass:
- case Stmt::ObjCStringLiteralClass:
- case Stmt::ObjCEncodeExprClass:
- case Stmt::ObjCSelectorExprClass:
- case Stmt::ObjCProtocolExprClass:
- case Stmt::ObjCIsaExprClass:
- case Stmt::ObjCIndirectCopyRestoreExprClass:
+ K = CXCursor_CXXFunctionalCastExpr;
+ break;
+
+ case Stmt::CXXTypeidExprClass:
+ K = CXCursor_CXXTypeidExpr;
+ break;
+
+ case Stmt::CXXBoolLiteralExprClass:
+ K = CXCursor_CXXBoolLiteralExpr;
+ break;
+
+ case Stmt::CXXNullPtrLiteralExprClass:
+ K = CXCursor_CXXNullPtrLiteralExpr;
+ break;
+
+ case Stmt::CXXThisExprClass:
+ K = CXCursor_CXXThisExpr;
+ break;
+
+ case Stmt::CXXThrowExprClass:
+ K = CXCursor_CXXThrowExpr;
+ break;
+
+ case Stmt::CXXNewExprClass:
+ K = CXCursor_CXXNewExpr;
+ break;
+
+ case Stmt::CXXDeleteExprClass:
+ K = CXCursor_CXXDeleteExpr;
+ break;
+
+ case Stmt::ObjCStringLiteralClass:
+ K = CXCursor_ObjCStringLiteral;
+ break;
+
+ case Stmt::ObjCEncodeExprClass:
+ K = CXCursor_ObjCEncodeExpr;
+ break;
+
+ case Stmt::ObjCSelectorExprClass:
+ K = CXCursor_ObjCSelectorExpr;
+ break;
+
+ case Stmt::ObjCProtocolExprClass:
+ K = CXCursor_ObjCProtocolExpr;
+ break;
+
case Stmt::ObjCBridgedCastExprClass:
- case Stmt::ShuffleVectorExprClass:
- case Stmt::BlockExprClass:
- case Stmt::OpaqueValueExprClass:
+ K = CXCursor_ObjCBridgedCastExpr;
+ break;
+
+ case Stmt::BlockExprClass:
+ K = CXCursor_BlockExpr;
+ break;
+
case Stmt::PackExpansionExprClass:
+ K = CXCursor_PackExpansionExpr;
+ break;
+
case Stmt::SizeOfPackExprClass:
- case Stmt::AsTypeExprClass:
- K = CXCursor_UnexposedExpr;
+ K = CXCursor_SizeOfPackExpr;
break;
-
- case Stmt::DeclRefExprClass:
+
case Stmt::BlockDeclRefExprClass:
+ case Stmt::DeclRefExprClass:
+ case Stmt::DependentScopeDeclRefExprClass:
case Stmt::SubstNonTypeTemplateParmExprClass:
case Stmt::SubstNonTypeTemplateParmPackExprClass:
- // FIXME: UnresolvedLookupExpr?
- // FIXME: DependentScopeDeclRefExpr?
+ case Stmt::UnresolvedLookupExprClass:
K = CXCursor_DeclRefExpr;
break;
+ case Stmt::CXXDependentScopeMemberExprClass:
+ case Stmt::CXXPseudoDestructorExprClass:
case Stmt::MemberExprClass:
+ case Stmt::ObjCIsaExprClass:
case Stmt::ObjCIvarRefExprClass:
case Stmt::ObjCPropertyRefExprClass:
- // FIXME: UnresolvedMemberExpr?
- // FIXME: CXXDependentScopeMemberExpr?
+ case Stmt::UnresolvedMemberExprClass:
K = CXCursor_MemberRefExpr;
break;
@@ -204,16 +426,28 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
case Stmt::CUDAKernelCallExprClass:
case Stmt::CXXConstructExprClass:
case Stmt::CXXTemporaryObjectExprClass:
- // FIXME: CXXUnresolvedConstructExpr
+ case Stmt::CXXUnresolvedConstructExprClass:
K = CXCursor_CallExpr;
break;
case Stmt::ObjCMessageExprClass:
K = CXCursor_ObjCMessageExpr;
- break;
+ int SelectorIdIndex = -1;
+ // Check if cursor points to a selector id.
+ if (RegionOfInterest.isValid() &&
+ RegionOfInterest.getBegin() == RegionOfInterest.getEnd()) {
+ SmallVector<SourceLocation, 16> SelLocs;
+ cast<ObjCMessageExpr>(S)->getSelectorLocs(SelLocs);
+ SmallVector<SourceLocation, 16>::iterator
+ I=std::find(SelLocs.begin(), SelLocs.end(),RegionOfInterest.getBegin());
+ if (I != SelLocs.end())
+ SelectorIdIndex = I - SelLocs.begin();
+ }
+ CXCursor C = { K, 0, { Parent, S, TU } };
+ return getSelectorIdentifierCursor(SelectorIdIndex, C);
}
- CXCursor C = { K, { Parent, S, TU } };
+ CXCursor C = { K, 0, { Parent, S, TU } };
return C;
}
@@ -222,7 +456,7 @@ CXCursor cxcursor::MakeCursorObjCSuperClassRef(ObjCInterfaceDecl *Super,
CXTranslationUnit TU) {
assert(Super && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_ObjCSuperClassRef, { Super, RawLoc, TU } };
+ CXCursor C = { CXCursor_ObjCSuperClassRef, 0, { Super, RawLoc, TU } };
return C;
}
@@ -239,7 +473,7 @@ CXCursor cxcursor::MakeCursorObjCProtocolRef(ObjCProtocolDecl *Super,
CXTranslationUnit TU) {
assert(Super && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_ObjCProtocolRef, { Super, RawLoc, TU } };
+ CXCursor C = { CXCursor_ObjCProtocolRef, 0, { Super, RawLoc, TU } };
return C;
}
@@ -259,7 +493,7 @@ CXCursor cxcursor::MakeCursorObjCClassRef(ObjCInterfaceDecl *Class,
return MakeCXCursorInvalid(CXCursor_InvalidCode);
assert(TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_ObjCClassRef, { Class, RawLoc, TU } };
+ CXCursor C = { CXCursor_ObjCClassRef, 0, { Class, RawLoc, TU } };
return C;
}
@@ -275,7 +509,7 @@ CXCursor cxcursor::MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc,
CXTranslationUnit TU) {
assert(Type && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_TypeRef, { Type, RawLoc, TU } };
+ CXCursor C = { CXCursor_TypeRef, 0, { Type, RawLoc, TU } };
return C;
}
@@ -292,7 +526,7 @@ CXCursor cxcursor::MakeCursorTemplateRef(TemplateDecl *Template,
CXTranslationUnit TU) {
assert(Template && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_TemplateRef, { Template, RawLoc, TU } };
+ CXCursor C = { CXCursor_TemplateRef, 0, { Template, RawLoc, TU } };
return C;
}
@@ -310,7 +544,7 @@ CXCursor cxcursor::MakeCursorNamespaceRef(NamedDecl *NS, SourceLocation Loc,
assert(NS && (isa<NamespaceDecl>(NS) || isa<NamespaceAliasDecl>(NS)) && TU &&
"Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_NamespaceRef, { NS, RawLoc, TU } };
+ CXCursor C = { CXCursor_NamespaceRef, 0, { NS, RawLoc, TU } };
return C;
}
@@ -327,7 +561,7 @@ CXCursor cxcursor::MakeCursorMemberRef(FieldDecl *Field, SourceLocation Loc,
assert(Field && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_MemberRef, { Field, RawLoc, TU } };
+ CXCursor C = { CXCursor_MemberRef, 0, { Field, RawLoc, TU } };
return C;
}
@@ -341,7 +575,7 @@ cxcursor::getCursorMemberRef(CXCursor C) {
CXCursor cxcursor::MakeCursorCXXBaseSpecifier(CXXBaseSpecifier *B,
CXTranslationUnit TU){
- CXCursor C = { CXCursor_CXXBaseSpecifier, { B, 0, TU } };
+ CXCursor C = { CXCursor_CXXBaseSpecifier, 0, { B, 0, TU } };
return C;
}
@@ -352,7 +586,7 @@ CXXBaseSpecifier *cxcursor::getCursorCXXBaseSpecifier(CXCursor C) {
CXCursor cxcursor::MakePreprocessingDirectiveCursor(SourceRange Range,
CXTranslationUnit TU) {
- CXCursor C = { CXCursor_PreprocessingDirective,
+ CXCursor C = { CXCursor_PreprocessingDirective, 0,
{ reinterpret_cast<void *>(Range.getBegin().getRawEncoding()),
reinterpret_cast<void *>(Range.getEnd().getRawEncoding()),
TU }
@@ -362,15 +596,17 @@ CXCursor cxcursor::MakePreprocessingDirectiveCursor(SourceRange Range,
SourceRange cxcursor::getCursorPreprocessingDirective(CXCursor C) {
assert(C.kind == CXCursor_PreprocessingDirective);
- return SourceRange(SourceLocation::getFromRawEncoding(
+ SourceRange Range = SourceRange(SourceLocation::getFromRawEncoding(
reinterpret_cast<uintptr_t> (C.data[0])),
SourceLocation::getFromRawEncoding(
reinterpret_cast<uintptr_t> (C.data[1])));
+ ASTUnit *TU = getCursorASTUnit(C);
+ return TU->mapRangeFromPreamble(Range);
}
CXCursor cxcursor::MakeMacroDefinitionCursor(MacroDefinition *MI,
CXTranslationUnit TU) {
- CXCursor C = { CXCursor_MacroDefinition, { MI, 0, TU } };
+ CXCursor C = { CXCursor_MacroDefinition, 0, { MI, 0, TU } };
return C;
}
@@ -381,7 +617,7 @@ MacroDefinition *cxcursor::getCursorMacroDefinition(CXCursor C) {
CXCursor cxcursor::MakeMacroExpansionCursor(MacroExpansion *MI,
CXTranslationUnit TU) {
- CXCursor C = { CXCursor_MacroExpansion, { MI, 0, TU } };
+ CXCursor C = { CXCursor_MacroExpansion, 0, { MI, 0, TU } };
return C;
}
@@ -392,7 +628,7 @@ MacroExpansion *cxcursor::getCursorMacroExpansion(CXCursor C) {
CXCursor cxcursor::MakeInclusionDirectiveCursor(InclusionDirective *ID,
CXTranslationUnit TU) {
- CXCursor C = { CXCursor_InclusionDirective, { ID, 0, TU } };
+ CXCursor C = { CXCursor_InclusionDirective, 0, { ID, 0, TU } };
return C;
}
@@ -406,7 +642,7 @@ CXCursor cxcursor::MakeCursorLabelRef(LabelStmt *Label, SourceLocation Loc,
assert(Label && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_LabelRef, { Label, RawLoc, TU } };
+ CXCursor C = { CXCursor_LabelRef, 0, { Label, RawLoc, TU } };
return C;
}
@@ -424,7 +660,7 @@ CXCursor cxcursor::MakeCursorOverloadedDeclRef(OverloadExpr *E,
OverloadedDeclRefStorage Storage(E);
void *RawLoc = reinterpret_cast<void *>(E->getNameLoc().getRawEncoding());
CXCursor C = {
- CXCursor_OverloadedDeclRef,
+ CXCursor_OverloadedDeclRef, 0,
{ Storage.getOpaqueValue(), RawLoc, TU }
};
return C;
@@ -437,7 +673,7 @@ CXCursor cxcursor::MakeCursorOverloadedDeclRef(Decl *D,
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
OverloadedDeclRefStorage Storage(D);
CXCursor C = {
- CXCursor_OverloadedDeclRef,
+ CXCursor_OverloadedDeclRef, 0,
{ Storage.getOpaqueValue(), RawLoc, TU }
};
return C;
@@ -450,7 +686,7 @@ CXCursor cxcursor::MakeCursorOverloadedDeclRef(TemplateName Name,
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
OverloadedDeclRefStorage Storage(Name.getAsOverloadedTemplate());
CXCursor C = {
- CXCursor_OverloadedDeclRef,
+ CXCursor_OverloadedDeclRef, 0,
{ Storage.getOpaqueValue(), RawLoc, TU }
};
return C;
@@ -502,6 +738,173 @@ CXTranslationUnit cxcursor::getCursorTU(CXCursor Cursor) {
return static_cast<CXTranslationUnit>(Cursor.data[2]);
}
+static void CollectOverriddenMethods(CXTranslationUnit TU,
+ DeclContext *Ctx,
+ ObjCMethodDecl *Method,
+ SmallVectorImpl<CXCursor> &Methods) {
+ if (!Ctx)
+ return;
+
+ // If we have a class or category implementation, jump straight to the
+ // interface.
+ if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(Ctx))
+ return CollectOverriddenMethods(TU, Impl->getClassInterface(),
+ Method, Methods);
+
+ ObjCContainerDecl *Container = dyn_cast<ObjCContainerDecl>(Ctx);
+ if (!Container)
+ return;
+
+ // Check whether we have a matching method at this level.
+ if (ObjCMethodDecl *Overridden = Container->getMethod(Method->getSelector(),
+ Method->isInstanceMethod()))
+ if (Method != Overridden) {
+ // We found an override at this level; there is no need to look
+ // into other protocols or categories.
+ Methods.push_back(MakeCXCursor(Overridden, TU));
+ return;
+ }
+
+ if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
+ for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(),
+ PEnd = Protocol->protocol_end();
+ P != PEnd; ++P)
+ CollectOverriddenMethods(TU, *P, Method, Methods);
+ }
+
+ if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) {
+ for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(),
+ PEnd = Category->protocol_end();
+ P != PEnd; ++P)
+ CollectOverriddenMethods(TU, *P, Method, Methods);
+ }
+
+ if (ObjCInterfaceDecl *Interface = dyn_cast<ObjCInterfaceDecl>(Container)) {
+ for (ObjCInterfaceDecl::protocol_iterator P = Interface->protocol_begin(),
+ PEnd = Interface->protocol_end();
+ P != PEnd; ++P)
+ CollectOverriddenMethods(TU, *P, Method, Methods);
+
+ for (ObjCCategoryDecl *Category = Interface->getCategoryList();
+ Category; Category = Category->getNextClassCategory())
+ CollectOverriddenMethods(TU, Category, Method, Methods);
+
+ // We only look into the superclass if we haven't found anything yet.
+ if (Methods.empty())
+ if (ObjCInterfaceDecl *Super = Interface->getSuperClass())
+ return CollectOverriddenMethods(TU, Super, Method, Methods);
+ }
+}
+
+void cxcursor::getOverriddenCursors(CXCursor cursor,
+ SmallVectorImpl<CXCursor> &overridden) {
+ if (!clang_isDeclaration(cursor.kind))
+ return;
+
+ Decl *D = getCursorDecl(cursor);
+ if (!D)
+ return;
+
+ // Handle C++ member functions.
+ CXTranslationUnit TU = getCursorTU(cursor);
+ if (CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) {
+ for (CXXMethodDecl::method_iterator
+ M = CXXMethod->begin_overridden_methods(),
+ MEnd = CXXMethod->end_overridden_methods();
+ M != MEnd; ++M)
+ overridden.push_back(MakeCXCursor(const_cast<CXXMethodDecl*>(*M), TU));
+ return;
+ }
+
+ ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D);
+ if (!Method)
+ return;
+
+ // Handle Objective-C methods.
+ CollectOverriddenMethods(TU, Method->getDeclContext(), Method, overridden);
+}
+
+std::pair<int, SourceLocation>
+cxcursor::getSelectorIdentifierIndexAndLoc(CXCursor cursor) {
+ if (cursor.kind == CXCursor_ObjCMessageExpr) {
+ if (cursor.xdata != -1)
+ return std::make_pair(cursor.xdata,
+ cast<ObjCMessageExpr>(getCursorExpr(cursor))
+ ->getSelectorLoc(cursor.xdata));
+ } else if (cursor.kind == CXCursor_ObjCClassMethodDecl ||
+ cursor.kind == CXCursor_ObjCInstanceMethodDecl) {
+ if (cursor.xdata != -1)
+ return std::make_pair(cursor.xdata,
+ cast<ObjCMethodDecl>(getCursorDecl(cursor))
+ ->getSelectorLoc(cursor.xdata));
+ }
+
+ return std::make_pair(-1, SourceLocation());
+}
+
+CXCursor cxcursor::getSelectorIdentifierCursor(int SelIdx, CXCursor cursor) {
+ CXCursor newCursor = cursor;
+
+ if (cursor.kind == CXCursor_ObjCMessageExpr) {
+ if (SelIdx == -1 ||
+ unsigned(SelIdx) >= cast<ObjCMessageExpr>(getCursorExpr(cursor))
+ ->getNumSelectorLocs())
+ newCursor.xdata = -1;
+ else
+ newCursor.xdata = SelIdx;
+ } else if (cursor.kind == CXCursor_ObjCClassMethodDecl ||
+ cursor.kind == CXCursor_ObjCInstanceMethodDecl) {
+ if (SelIdx == -1 ||
+ unsigned(SelIdx) >= cast<ObjCMethodDecl>(getCursorDecl(cursor))
+ ->getNumSelectorLocs())
+ newCursor.xdata = -1;
+ else
+ newCursor.xdata = SelIdx;
+ }
+
+ return newCursor;
+}
+
+CXCursor cxcursor::getTypeRefCursor(CXCursor cursor) {
+ if (cursor.kind != CXCursor_CallExpr)
+ return cursor;
+
+ if (cursor.xdata == 0)
+ return cursor;
+
+ Expr *E = getCursorExpr(cursor);
+ TypeSourceInfo *Type = 0;
+ if (CXXUnresolvedConstructExpr *
+ UnCtor = dyn_cast<CXXUnresolvedConstructExpr>(E)) {
+ Type = UnCtor->getTypeSourceInfo();
+ } else if (CXXTemporaryObjectExpr *Tmp = dyn_cast<CXXTemporaryObjectExpr>(E)){
+ Type = Tmp->getTypeSourceInfo();
+ }
+
+ if (!Type)
+ return cursor;
+
+ CXTranslationUnit TU = getCursorTU(cursor);
+ QualType Ty = Type->getType();
+ TypeLoc TL = Type->getTypeLoc();
+ SourceLocation Loc = TL.getBeginLoc();
+
+ if (const ElaboratedType *ElabT = Ty->getAs<ElaboratedType>()) {
+ Ty = ElabT->getNamedType();
+ ElaboratedTypeLoc ElabTL = cast<ElaboratedTypeLoc>(TL);
+ Loc = ElabTL.getNamedTypeLoc().getBeginLoc();
+ }
+
+ if (const TypedefType *Typedef = Ty->getAs<TypedefType>())
+ return MakeCursorTypeRef(Typedef->getDecl(), Loc, TU);
+ if (const TagType *Tag = Ty->getAs<TagType>())
+ return MakeCursorTypeRef(Tag->getDecl(), Loc, TU);
+ if (const TemplateTypeParmType *TemplP = Ty->getAs<TemplateTypeParmType>())
+ return MakeCursorTypeRef(TemplP->getDecl(), Loc, TU);
+
+ return cursor;
+}
+
bool cxcursor::operator==(CXCursor X, CXCursor Y) {
return X.kind == Y.kind && X.data[0] == Y.data[0] && X.data[1] == Y.data[1] &&
X.data[2] == Y.data[2];
@@ -515,6 +918,22 @@ bool cxcursor::isFirstInDeclGroup(CXCursor C) {
}
//===----------------------------------------------------------------------===//
+// libclang CXCursor APIs
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+
+int clang_Cursor_isNull(CXCursor cursor) {
+ return clang_equalCursors(cursor, clang_getNullCursor());
+}
+
+CXTranslationUnit clang_Cursor_getTranslationUnit(CXCursor cursor) {
+ return getCursorTU(cursor);
+}
+
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
// CXCursorSet.
//===----------------------------------------------------------------------===//
@@ -577,4 +996,40 @@ unsigned clang_CXCursorSet_insert(CXCursorSet set, CXCursor cursor) {
entry = 1;
return flag;
}
+
+CXCompletionString clang_getCursorCompletionString(CXCursor cursor) {
+ enum CXCursorKind kind = clang_getCursorKind(cursor);
+ if (clang_isDeclaration(kind)) {
+ Decl *decl = getCursorDecl(cursor);
+ if (isa<NamedDecl>(decl)) {
+ NamedDecl *namedDecl = (NamedDecl *)decl;
+ ASTUnit *unit = getCursorASTUnit(cursor);
+ if (unit->hasSema()) {
+ Sema &S = unit->getSema();
+ CodeCompletionAllocator *Allocator
+ = unit->getCursorCompletionAllocator().getPtr();
+ CodeCompletionResult Result(namedDecl);
+ CodeCompletionString *String
+ = Result.CreateCodeCompletionString(S, *Allocator);
+ return String;
+ }
+ }
+ }
+ else if (kind == CXCursor_MacroDefinition) {
+ MacroDefinition *definition = getCursorMacroDefinition(cursor);
+ const IdentifierInfo *MacroInfo = definition->getName();
+ ASTUnit *unit = getCursorASTUnit(cursor);
+ if (unit->hasSema()) {
+ Sema &S = unit->getSema();
+ CodeCompletionAllocator *Allocator
+ = unit->getCursorCompletionAllocator().getPtr();
+ CodeCompletionResult Result(const_cast<IdentifierInfo *>(MacroInfo));
+ CodeCompletionString *String
+ = Result.CreateCodeCompletionString(S, *Allocator);
+ return String;
+ }
+ }
+ return NULL;
+}
+
} // end: extern "C"
diff --git a/tools/libclang/CXCursor.h b/tools/libclang/CXCursor.h
index 68d09e76c1c0..e402d7f970ca 100644
--- a/tools/libclang/CXCursor.h
+++ b/tools/libclang/CXCursor.h
@@ -43,13 +43,17 @@ class TemplateName;
class TypeDecl;
namespace cxcursor {
+
+CXCursor getCursor(CXTranslationUnit, SourceLocation);
CXCursor MakeCXCursor(const clang::Attr *A, clang::Decl *Parent,
CXTranslationUnit TU);
CXCursor MakeCXCursor(clang::Decl *D, CXTranslationUnit TU,
+ SourceRange RegionOfInterest = SourceRange(),
bool FirstInDeclGroup = true);
CXCursor MakeCXCursor(clang::Stmt *S, clang::Decl *Parent,
- CXTranslationUnit TU);
+ CXTranslationUnit TU,
+ SourceRange RegionOfInterest = SourceRange());
CXCursor MakeCXCursorInvalid(CXCursorKind K);
/// \brief Create an Objective-C superclass reference at the given location.
@@ -189,7 +193,36 @@ Decl *getCursorParentDecl(CXCursor Cursor);
ASTContext &getCursorContext(CXCursor Cursor);
ASTUnit *getCursorASTUnit(CXCursor Cursor);
CXTranslationUnit getCursorTU(CXCursor Cursor);
-
+
+void getOverriddenCursors(CXCursor cursor,
+ SmallVectorImpl<CXCursor> &overridden);
+
+/// \brief Returns a index/location pair for a selector identifier if the cursor
+/// points to one.
+std::pair<int, SourceLocation> getSelectorIdentifierIndexAndLoc(CXCursor);
+static inline int getSelectorIdentifierIndex(CXCursor cursor) {
+ return getSelectorIdentifierIndexAndLoc(cursor).first;
+}
+static inline SourceLocation getSelectorIdentifierLoc(CXCursor cursor) {
+ return getSelectorIdentifierIndexAndLoc(cursor).second;
+}
+
+CXCursor getSelectorIdentifierCursor(int SelIdx, CXCursor cursor);
+
+static inline CXCursor getTypeRefedCallExprCursor(CXCursor cursor) {
+ CXCursor newCursor = cursor;
+ if (cursor.kind == CXCursor_CallExpr)
+ newCursor.xdata = 1;
+ return newCursor;
+}
+
+CXCursor getTypeRefCursor(CXCursor cursor);
+
+/// \brief Generate a USR for \arg D and put it in \arg Buf.
+/// \returns true if no USR was computed or the result should be ignored,
+/// false otherwise.
+bool getDeclCursorUSR(Decl *D, SmallVectorImpl<char> &Buf);
+
bool operator==(CXCursor X, CXCursor Y);
inline bool operator!=(CXCursor X, CXCursor Y) {
diff --git a/tools/libclang/CXString.cpp b/tools/libclang/CXString.cpp
index f2a6b091ece4..bb09cd5cdc22 100644
--- a/tools/libclang/CXString.cpp
+++ b/tools/libclang/CXString.cpp
@@ -41,7 +41,7 @@ CXString cxstring::createCXString(const char *String, bool DupString){
return Str;
}
-CXString cxstring::createCXString(llvm::StringRef String, bool DupString) {
+CXString cxstring::createCXString(StringRef String, bool DupString) {
CXString Result;
if (DupString || (!String.empty() && String.data()[String.size()] != 0)) {
char *Spelling = (char *)malloc(String.size() + 1);
@@ -101,6 +101,10 @@ void cxstring::disposeCXStringBuf(CXStringBuf *buf) {
static_cast<CXStringPool*>(buf->TU->StringPool)->push_back(buf);
}
+bool cxstring::isManagedByPool(CXString str) {
+ return ((CXStringFlag) str.private_flags) == CXS_StringBuf;
+}
+
//===----------------------------------------------------------------------===//
// libClang public APIs.
//===----------------------------------------------------------------------===//
diff --git a/tools/libclang/CXString.h b/tools/libclang/CXString.h
index f03a6b290384..d36c7c1e68ba 100644
--- a/tools/libclang/CXString.h
+++ b/tools/libclang/CXString.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_CXSTRING_H
#include "clang-c/Index.h"
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallString.h"
@@ -31,7 +32,7 @@ struct CXStringBuf {
CXString createCXString(const char *String, bool DupString = false);
/// \brief Create a CXString object from a StringRef.
-CXString createCXString(llvm::StringRef String, bool DupString = true);
+CXString createCXString(StringRef String, bool DupString = true);
/// \brief Create a CXString object that is backed by a string buffer.
CXString createCXString(CXStringBuf *buf);
@@ -46,6 +47,9 @@ 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 6df85b7d4dc9..2b8f977539c2 100644
--- a/tools/libclang/CXTranslationUnit.h
+++ b/tools/libclang/CXTranslationUnit.h
@@ -21,4 +21,13 @@ struct CXTranslationUnitImpl {
};
}
+namespace clang {
+ class ASTUnit;
+
+namespace cxtu {
+
+CXTranslationUnitImpl *MakeCXTranslationUnit(ASTUnit *TU);
+
+}} // end namespace clang::cxtu
+
#endif
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index 45c73468d971..0e62e2734b0c 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -84,6 +84,7 @@ static CXTypeKind GetTypeKind(QualType T) {
TKCASE(ObjCObjectPointer);
TKCASE(FunctionNoProto);
TKCASE(FunctionProto);
+ TKCASE(ConstantArray);
default:
return CXType_Unexposed;
}
@@ -330,6 +331,7 @@ CXString clang_getTypeKindSpelling(enum CXTypeKind K) {
TKIND(ObjCObjectPointer);
TKIND(FunctionNoProto);
TKIND(FunctionProto);
+ TKIND(ConstantArray);
}
#undef TKIND
return cxstring::createCXString(s);
@@ -373,6 +375,40 @@ unsigned clang_isPODType(CXType X) {
return T.isPODType(AU->getASTContext()) ? 1 : 0;
}
+CXType clang_getArrayElementType(CXType CT) {
+ QualType ET = QualType();
+ QualType T = GetQualType(CT);
+ const Type *TP = T.getTypePtrOrNull();
+
+ if (TP) {
+ switch (TP->getTypeClass()) {
+ case Type::ConstantArray:
+ ET = cast<ConstantArrayType> (TP)->getElementType();
+ break;
+ default:
+ break;
+ }
+ }
+ return MakeCXType(ET, GetTU(CT));
+}
+
+long long clang_getArraySize(CXType CT) {
+ long long result = -1;
+ QualType T = GetQualType(CT);
+ const Type *TP = T.getTypePtrOrNull();
+
+ if (TP) {
+ switch (TP->getTypeClass()) {
+ case Type::ConstantArray:
+ result = cast<ConstantArrayType> (TP)->getSize().getSExtValue();
+ break;
+ default:
+ break;
+ }
+ }
+ return result;
+}
+
CXString clang_getDeclObjCTypeEncoding(CXCursor C) {
if ((C.kind < CXCursor_FirstDecl) || (C.kind > CXCursor_LastDecl))
return cxstring::createCXString("");
diff --git a/tools/libclang/Index_Internal.h b/tools/libclang/Index_Internal.h
new file mode 100644
index 000000000000..df54d7c87965
--- /dev/null
+++ b/tools/libclang/Index_Internal.h
@@ -0,0 +1,43 @@
+//===- CXString.h - Routines for manipulating CXStrings -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines routines for manipulating CXStrings.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBCLANG_INDEX_INTERNAL_H
+#define LLVM_LIBCLANG_INDEX_INTERNAL_H
+
+#include "clang-c/Index.h"
+
+#ifndef __has_feature
+#define __has_feature(x) 0
+#endif
+
+#if __has_feature(blocks)
+
+#define INVOKE_BLOCK2(block, arg1, arg2) block(arg1, arg2)
+
+#else
+// If we are compiled with a compiler that doesn't have native blocks support,
+// define and call the block manually.
+
+#define INVOKE_BLOCK2(block, arg1, arg2) block->invoke(block, arg1, arg2)
+
+typedef struct _CXCursorAndRangeVisitorBlock {
+ void *isa;
+ int flags;
+ int reserved;
+ enum CXVisitorResult (*invoke)(_CXCursorAndRangeVisitorBlock *,
+ CXCursor, CXSourceRange);
+} *CXCursorAndRangeVisitorBlock;
+
+#endif // !__has_feature(blocks)
+
+#endif
diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports
deleted file mode 100644
index bfc5be9c078b..000000000000
--- a/tools/libclang/libclang.darwin.exports
+++ /dev/null
@@ -1,143 +0,0 @@
-_clang_CXCursorSet_contains
-_clang_CXCursorSet_insert
-_clang_CXXMethod_isStatic
-_clang_CXXMethod_isVirtual
-_clang_annotateTokens
-_clang_codeCompleteAt
-_clang_codeCompleteGetDiagnostic
-_clang_codeCompleteGetNumDiagnostics
-_clang_codeCompleteGetContexts
-_clang_constructUSR_ObjCCategory
-_clang_constructUSR_ObjCClass
-_clang_constructUSR_ObjCIvar
-_clang_constructUSR_ObjCMethod
-_clang_constructUSR_ObjCProperty
-_clang_constructUSR_ObjCProtocol
-_clang_createCXCursorSet
-_clang_createIndex
-_clang_createTranslationUnit
-_clang_createTranslationUnitFromSourceFile
-_clang_defaultCodeCompleteOptions
-_clang_defaultDiagnosticDisplayOptions
-_clang_defaultEditingTranslationUnitOptions
-_clang_defaultReparseOptions
-_clang_defaultSaveOptions
-_clang_disposeCXCursorSet
-_clang_disposeCXTUResourceUsage
-_clang_disposeCodeCompleteResults
-_clang_disposeDiagnostic
-_clang_disposeIndex
-_clang_disposeOverriddenCursors
-_clang_disposeString
-_clang_disposeTokens
-_clang_disposeTranslationUnit
-_clang_enableStackTraces
-_clang_equalCursors
-_clang_equalLocations
-_clang_equalTypes
-_clang_executeOnThread
-_clang_formatDiagnostic
-_clang_getCString
-_clang_getCXTUResourceUsage
-_clang_getCXXAccessSpecifier
-_clang_getCanonicalCursor
-_clang_getCanonicalType
-_clang_getClangVersion
-_clang_getCompletionAvailability
-_clang_getCompletionChunkCompletionString
-_clang_getCompletionChunkKind
-_clang_getCompletionChunkText
-_clang_getCompletionPriority
-_clang_getCursor
-_clang_getCursorAvailability
-_clang_getCursorDefinition
-_clang_getCursorDisplayName
-_clang_getCursorExtent
-_clang_getCursorKind
-_clang_getCursorKindSpelling
-_clang_getCursorLanguage
-_clang_getCursorLexicalParent
-_clang_getCursorLinkage
-_clang_getCursorLocation
-_clang_getCursorReferenced
-_clang_getCursorResultType
-_clang_getCursorSemanticParent
-_clang_getCursorSpelling
-_clang_getCursorType
-_clang_getCursorUSR
-_clang_getDeclObjCTypeEncoding
-_clang_getDefinitionSpellingAndExtent
-_clang_getDiagnostic
-_clang_getDiagnosticCategory
-_clang_getDiagnosticCategoryName
-_clang_getDiagnosticFixIt
-_clang_getDiagnosticLocation
-_clang_getDiagnosticNumFixIts
-_clang_getDiagnosticNumRanges
-_clang_getDiagnosticOption
-_clang_getDiagnosticRange
-_clang_getDiagnosticSeverity
-_clang_getDiagnosticSpelling
-_clang_getFile
-_clang_getFileName
-_clang_getFileTime
-_clang_getIBOutletCollectionType
-_clang_getIncludedFile
-_clang_getInclusions
-_clang_getInstantiationLocation
-_clang_getLocation
-_clang_getLocationForOffset
-_clang_getNullCursor
-_clang_getNullLocation
-_clang_getNullRange
-_clang_getNumCompletionChunks
-_clang_getNumDiagnostics
-_clang_getNumOverloadedDecls
-_clang_getOverloadedDecl
-_clang_getOverriddenCursors
-_clang_getPointeeType
-_clang_getRange
-_clang_getRangeEnd
-_clang_getRangeStart
-_clang_getResultType
-_clang_getSpecializedCursorTemplate
-_clang_getSpellingLocation
-_clang_getTUResourceUsageName
-_clang_getTemplateCursorKind
-_clang_getTokenExtent
-_clang_getTokenKind
-_clang_getTokenLocation
-_clang_getTokenSpelling
-_clang_getTranslationUnitCursor
-_clang_getTranslationUnitSpelling
-_clang_getTypeDeclaration
-_clang_getTypeKindSpelling
-_clang_hashCursor
-_clang_isAttribute
-_clang_isConstQualifiedType
-_clang_isCursorDefinition
-_clang_isDeclaration
-_clang_isExpression
-_clang_isFileMultipleIncludeGuarded
-_clang_isInvalid
-_clang_isPODType
-_clang_isPreprocessing
-_clang_isReference
-_clang_isRestrictQualifiedType
-_clang_isStatement
-_clang_isTranslationUnit
-_clang_isUnexposed
-_clang_isVirtualBase
-_clang_isVolatileQualifiedType
-_clang_parseTranslationUnit
-_clang_reparseTranslationUnit
-_clang_saveTranslationUnit
-_clang_sortCodeCompletionResults
-_clang_toggleCrashRecovery
-_clang_tokenize
-_clang_visitChildren
-_clang_visitChildrenWithBlock
-_clang_getRemappings
-_clang_remap_getNumFiles
-_clang_remap_getFilenames
-_clang_remap_dispose
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 47b703011c76..989ed837ea24 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -4,9 +4,12 @@ clang_CXXMethod_isStatic
clang_CXXMethod_isVirtual
clang_annotateTokens
clang_codeCompleteAt
+clang_codeCompleteGetContainerKind
+clang_codeCompleteGetContainerUSR
+clang_codeCompleteGetContexts
clang_codeCompleteGetDiagnostic
clang_codeCompleteGetNumDiagnostics
-clang_codeCompleteGetContexts
+clang_codeCompleteGetObjCSelector
clang_constructUSR_ObjCCategory
clang_constructUSR_ObjCClass
clang_constructUSR_ObjCIvar
@@ -17,6 +20,8 @@ clang_createCXCursorSet
clang_createIndex
clang_createTranslationUnit
clang_createTranslationUnitFromSourceFile
+clang_Cursor_getTranslationUnit
+clang_Cursor_isNull
clang_defaultCodeCompleteOptions
clang_defaultDiagnosticDisplayOptions
clang_defaultEditingTranslationUnitOptions
@@ -34,9 +39,14 @@ clang_disposeTranslationUnit
clang_enableStackTraces
clang_equalCursors
clang_equalLocations
+clang_equalRanges
clang_equalTypes
clang_executeOnThread
+clang_findReferencesInFile
+clang_findReferencesInFileWithBlock
clang_formatDiagnostic
+clang_getArrayElementType
+clang_getArraySize
clang_getCString
clang_getCXTUResourceUsage
clang_getCXXAccessSpecifier
@@ -44,12 +54,15 @@ clang_getCanonicalCursor
clang_getCanonicalType
clang_getClangVersion
clang_getCompletionAvailability
+clang_getCompletionAnnotation
clang_getCompletionChunkCompletionString
clang_getCompletionChunkKind
clang_getCompletionChunkText
+clang_getCompletionNumAnnotations
clang_getCompletionPriority
clang_getCursor
clang_getCursorAvailability
+clang_getCursorCompletionString
clang_getCursorDefinition
clang_getCursorDisplayName
clang_getCursorExtent
@@ -59,6 +72,7 @@ clang_getCursorLanguage
clang_getCursorLexicalParent
clang_getCursorLinkage
clang_getCursorLocation
+clang_getCursorReferenceNameRange
clang_getCursorReferenced
clang_getCursorResultType
clang_getCursorSemanticParent
@@ -96,9 +110,11 @@ clang_getNumOverloadedDecls
clang_getOverloadedDecl
clang_getOverriddenCursors
clang_getPointeeType
+clang_getPresumedLocation
clang_getRange
clang_getRangeEnd
clang_getRangeStart
+clang_getRemappings
clang_getResultType
clang_getSpecializedCursorTemplate
clang_getSpellingLocation
@@ -130,6 +146,10 @@ clang_isUnexposed
clang_isVirtualBase
clang_isVolatileQualifiedType
clang_parseTranslationUnit
+clang_Range_isNull
+clang_remap_dispose
+clang_remap_getFilenames
+clang_remap_getNumFiles
clang_reparseTranslationUnit
clang_saveTranslationUnit
clang_sortCodeCompletionResults
@@ -137,7 +157,3 @@ clang_toggleCrashRecovery
clang_tokenize
clang_visitChildren
clang_visitChildrenWithBlock
-clang_getRemappings
-clang_remap_getNumFiles
-clang_remap_getFilenames
-clang_remap_dispose
diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer
index 5697b214a2d7..c39e4179514e 100755
--- a/tools/scan-build/ccc-analyzer
+++ b/tools/scan-build/ccc-analyzer
@@ -55,7 +55,10 @@ my $ResultFile;
# Remove any stale files at exit.
END {
- if (defined $CleanupFile && -z $CleanupFile) {
+ if (defined $ResultFile && -z $ResultFile) {
+ `rm -f $ResultFile`;
+ }
+ if (defined $CleanupFile) {
`rm -f $CleanupFile`;
}
}
@@ -365,9 +368,11 @@ my %LangMap = (
'cp' => 'c++',
'cpp' => 'c++',
'cc' => 'c++',
+ 'ii' => 'c++',
'i' => 'c-cpp-output',
'm' => 'objective-c',
- 'mi' => 'objective-c-cpp-output'
+ 'mi' => 'objective-c-cpp-output',
+ 'mm' => 'objective-c++'
);
my %UniqueOptions = (
@@ -380,14 +385,11 @@ my %UniqueOptions = (
my %LangsAccepted = (
"objective-c" => 1,
- "c" => 1
+ "c" => 1,
+ "c++" => 1,
+ "objective-c++" => 1
);
-if (defined $ENV{'CCC_ANALYZER_CPLUSPLUS'}) {
- $LangsAccepted{"c++"} = 1;
- $LangsAccepted{"objective-c++"} = 1;
-}
-
##----------------------------------------------------------------------------##
# Main Logic.
##----------------------------------------------------------------------------##
@@ -621,9 +623,9 @@ if ($Action eq 'compile' or $Action eq 'link') {
push @AnalyzeArgs, "-analyzer-constraints=$ConstraintsModel";
}
-# if (defined $Analyses) {
-# push @AnalyzeArgs, split '\s+', $Analyses;
-# }
+ if (defined $Analyses) {
+ push @AnalyzeArgs, split '\s+', $Analyses;
+ }
if (defined $OutputFormat) {
push @AnalyzeArgs, "-analyzer-output=" . $OutputFormat;
@@ -632,7 +634,10 @@ if ($Action eq 'compile' or $Action eq 'link') {
my ($h, $f) = tempfile("report-XXXXXX", SUFFIX => ".plist",
DIR => $HtmlDir);
$ResultFile = $f;
- $CleanupFile = $f;
+ # If the HtmlDir is not set, we sould clean up the plist files.
+ if (!defined $HtmlDir || -z $HtmlDir) {
+ $CleanupFile = $f;
+ }
}
}
diff --git a/tools/scan-build/scan-build b/tools/scan-build/scan-build
index f835ca3520c4..dae86f4b5e9c 100755
--- a/tools/scan-build/scan-build
+++ b/tools/scan-build/scan-build
@@ -61,7 +61,7 @@ sub DiagCrashes {
Diag ("The analyzer encountered problems on some source files.\n");
Diag ("Preprocessed versions of these sources were deposited in '$Dir/failures'.\n");
Diag ("Please consider submitting a bug report using these files:\n");
- Diag (" http://clang.llvm.org/StaticAnalysisUsage.html#filingbugs\n")
+ Diag (" http://clang-analyzer.llvm.org/filing_bugs.html\n")
}
sub DieDiag {
@@ -802,7 +802,7 @@ ENDTEXT
}
print OUT "</table>\n";
}
- print OUT "<p>Please consider submitting preprocessed files as <a href=\"http://clang.llvm.org/StaticAnalysisUsage.html#filingbugs\">bug reports</a>. <!-- REPORTCRASHES --> </p>\n";
+ print OUT "<p>Please consider submitting preprocessed files as <a href=\"http://clang-analyzer.llvm.org/filing_bugs.html\">bug reports</a>. <!-- REPORTCRASHES --> </p>\n";
}
print OUT "</body></html>\n";
diff --git a/unittests/AST/APValueTest.cpp b/unittests/AST/APValueTest.cpp
new file mode 100644
index 000000000000..5ac454de5f13
--- /dev/null
+++ b/unittests/AST/APValueTest.cpp
@@ -0,0 +1,83 @@
+//===- unittests/AST/APValueTest.cpp - APValue tests ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/APValue.h"
+
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+
+namespace {
+
+class DiagnosticOutputGetter {
+ class LastDiagnosticString : public DiagnosticConsumer {
+ SmallString<64> LastDiagnostic;
+ public:
+ virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) {
+ LastDiagnostic.clear();
+ Info.FormatDiagnostic(LastDiagnostic);
+ }
+
+ StringRef get() const { return LastDiagnostic; }
+
+ virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
+ return new LastDiagnosticString();
+ }
+ };
+
+ const IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs;
+ const unsigned diag_just_format;
+ LastDiagnosticString LastDiagnostic;
+ DiagnosticsEngine Diag;
+
+public:
+ DiagnosticOutputGetter()
+ : DiagIDs(new DiagnosticIDs),
+ diag_just_format(DiagIDs->getCustomDiagID(DiagnosticIDs::Error, "%0")),
+ Diag(DiagIDs, &LastDiagnostic, false) {
+ }
+
+ template<typename T>
+ std::string operator()(const T& value) {
+ Diag.Report(diag_just_format) << value;
+ return LastDiagnostic.get().str();
+ }
+};
+
+TEST(APValue, Diagnostics) {
+ DiagnosticOutputGetter GetDiagnosticOutput;
+
+ EXPECT_EQ("Uninitialized", GetDiagnosticOutput(APValue()));
+ EXPECT_EQ("5", GetDiagnosticOutput(APValue(APSInt(APInt(16, 5)))));
+ EXPECT_EQ("3.141590e+00",
+ GetDiagnosticOutput(APValue(APFloat(APFloat::IEEEdouble,
+ "3.14159"))));
+ EXPECT_EQ("3+4i",
+ GetDiagnosticOutput(APValue(APSInt(APInt(16, 3)),
+ APSInt(APInt(16, 4)))));
+ EXPECT_EQ("3.200000e+00+5.700000e+00i",
+ GetDiagnosticOutput(APValue(
+ APFloat(APFloat::IEEEdouble, "3.2"),
+ APFloat(APFloat::IEEEdouble, "5.7"))));
+ APValue V[] = {
+ APValue(APSInt(APInt(16, 3))),
+ APValue(APSInt(APInt(16, 4))),
+ APValue(APSInt(APInt(16, 5)))
+ };
+ EXPECT_EQ("[3, 4, 5]",
+ GetDiagnosticOutput(APValue(V, array_lengthof(V))));
+}
+
+} // anonymous namespace
diff --git a/unittests/AST/Makefile b/unittests/AST/Makefile
new file mode 100644
index 000000000000..74191d037f51
--- /dev/null
+++ b/unittests/AST/Makefile
@@ -0,0 +1,15 @@
+##===- unittests/Frontend/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 = AST
+LINK_COMPONENTS := support mc
+USEDLIBS = clangAST.a clangBasic.a
+
+include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/Basic/FileManagerTest.cpp b/unittests/Basic/FileManagerTest.cpp
index a725a437f6b7..91998b638859 100644
--- a/unittests/Basic/FileManagerTest.cpp
+++ b/unittests/Basic/FileManagerTest.cpp
@@ -28,7 +28,8 @@ private:
llvm::StringMap<struct stat, llvm::BumpPtrAllocator> StatCalls;
void InjectFileOrDirectory(const char *Path, ino_t INode, bool IsFile) {
- struct stat statBuf = {};
+ struct stat statBuf;
+ memset(&statBuf, 0, sizeof(statBuf));
statBuf.st_dev = 1;
#ifndef _WIN32 // struct stat has no st_ino field on Windows.
statBuf.st_ino = INode;
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index cb44dc59dcfc..901f167f3563 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -50,6 +50,11 @@ if(SUPPORTS_NO_VARIADIC_MACROS_FLAG)
add_definitions("-Wno-variadic-macros")
endif()
+add_clang_unittest(AST
+ AST/APValueTest.cpp
+ USED_LIBS gtest gtest_main clangAST
+ )
+
add_clang_unittest(Basic
Basic/FileManagerTest.cpp
USED_LIBS gtest gtest_main clangBasic
diff --git a/unittests/Makefile b/unittests/Makefile
index 951e17e21771..f4ce6adaa725 100644
--- a/unittests/Makefile
+++ b/unittests/Makefile
@@ -14,7 +14,7 @@ ifndef CLANG_LEVEL
IS_UNITTEST_LEVEL := 1
CLANG_LEVEL := ..
-PARALLEL_DIRS = Basic Frontend
+PARALLEL_DIRS = AST Basic Frontend
endif # CLANG_LEVEL
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt
new file mode 100644
index 000000000000..75a616700405
--- /dev/null
+++ b/utils/TableGen/CMakeLists.txt
@@ -0,0 +1,12 @@
+set(LLVM_REQUIRES_EH 1)
+set(LLVM_REQUIRES_RTTI 1)
+
+add_tablegen(clang-tblgen CLANG
+ ClangASTNodesEmitter.cpp
+ ClangAttrEmitter.cpp
+ ClangDiagnosticsEmitter.cpp
+ ClangSACheckersEmitter.cpp
+ NeonEmitter.cpp
+ OptParserEmitter.cpp
+ TableGen.cpp
+ )
diff --git a/utils/TableGen/ClangASTNodesEmitter.cpp b/utils/TableGen/ClangASTNodesEmitter.cpp
new file mode 100644
index 000000000000..d9d5a3ccd907
--- /dev/null
+++ b/utils/TableGen/ClangASTNodesEmitter.cpp
@@ -0,0 +1,168 @@
+//=== ClangASTNodesEmitter.cpp - Generate Clang AST node tables -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These tablegen backends emit Clang AST node tables
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangASTNodesEmitter.h"
+#include <set>
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+// Statement Node Tables (.inc file) generation.
+//===----------------------------------------------------------------------===//
+
+// Returns the first and last non-abstract subrecords
+// Called recursively to ensure that nodes remain contiguous
+std::pair<Record *, Record *> ClangASTNodesEmitter::EmitNode(
+ const ChildMap &Tree,
+ raw_ostream &OS,
+ Record *Base) {
+ std::string BaseName = macroName(Base->getName());
+
+ ChildIterator i = Tree.lower_bound(Base), e = Tree.upper_bound(Base);
+
+ Record *First = 0, *Last = 0;
+ // This might be the pseudo-node for Stmt; don't assume it has an Abstract
+ // bit
+ if (Base->getValue("Abstract") && !Base->getValueAsBit("Abstract"))
+ First = Last = Base;
+
+ for (; i != e; ++i) {
+ Record *R = i->second;
+ bool Abstract = R->getValueAsBit("Abstract");
+ std::string NodeName = macroName(R->getName());
+
+ OS << "#ifndef " << NodeName << "\n";
+ OS << "# define " << NodeName << "(Type, Base) "
+ << BaseName << "(Type, Base)\n";
+ OS << "#endif\n";
+
+ if (Abstract)
+ OS << "ABSTRACT_" << macroName(Root.getName()) << "(" << NodeName << "("
+ << R->getName() << ", " << baseName(*Base) << "))\n";
+ else
+ OS << NodeName << "(" << R->getName() << ", "
+ << baseName(*Base) << ")\n";
+
+ if (Tree.find(R) != Tree.end()) {
+ const std::pair<Record *, Record *> &Result
+ = EmitNode(Tree, OS, R);
+ if (!First && Result.first)
+ First = Result.first;
+ if (Result.second)
+ Last = Result.second;
+ } else {
+ if (!Abstract) {
+ Last = R;
+
+ if (!First)
+ First = R;
+ }
+ }
+
+ OS << "#undef " << NodeName << "\n\n";
+ }
+
+ if (First) {
+ assert (Last && "Got a first node but not a last node for a range!");
+ if (Base == &Root)
+ OS << "LAST_" << macroName(Root.getName()) << "_RANGE(";
+ else
+ OS << macroName(Root.getName()) << "_RANGE(";
+ OS << Base->getName() << ", " << First->getName() << ", "
+ << Last->getName() << ")\n\n";
+ }
+
+ return std::make_pair(First, Last);
+}
+
+void ClangASTNodesEmitter::run(raw_ostream &OS) {
+ // Write the preamble
+ OS << "#ifndef ABSTRACT_" << macroName(Root.getName()) << "\n";
+ OS << "# define ABSTRACT_" << macroName(Root.getName()) << "(Type) Type\n";
+ OS << "#endif\n";
+
+ OS << "#ifndef " << macroName(Root.getName()) << "_RANGE\n";
+ OS << "# define "
+ << macroName(Root.getName()) << "_RANGE(Base, First, Last)\n";
+ OS << "#endif\n\n";
+
+ OS << "#ifndef LAST_" << macroName(Root.getName()) << "_RANGE\n";
+ OS << "# define LAST_"
+ << macroName(Root.getName()) << "_RANGE(Base, First, Last) "
+ << macroName(Root.getName()) << "_RANGE(Base, First, Last)\n";
+ OS << "#endif\n\n";
+
+ // Emit statements
+ const std::vector<Record*> Stmts
+ = Records.getAllDerivedDefinitions(Root.getName());
+
+ ChildMap Tree;
+
+ for (unsigned i = 0, e = Stmts.size(); i != e; ++i) {
+ Record *R = Stmts[i];
+
+ if (R->getValue("Base"))
+ Tree.insert(std::make_pair(R->getValueAsDef("Base"), R));
+ else
+ Tree.insert(std::make_pair(&Root, R));
+ }
+
+ EmitNode(Tree, OS, &Root);
+
+ OS << "#undef " << macroName(Root.getName()) << "\n";
+ OS << "#undef " << macroName(Root.getName()) << "_RANGE\n";
+ OS << "#undef LAST_" << macroName(Root.getName()) << "_RANGE\n";
+ OS << "#undef ABSTRACT_" << macroName(Root.getName()) << "\n";
+}
+
+void ClangDeclContextEmitter::run(raw_ostream &OS) {
+ // FIXME: Find a .td file format to allow for this to be represented better.
+
+ OS << "#ifndef DECL_CONTEXT\n";
+ OS << "# define DECL_CONTEXT(DECL)\n";
+ OS << "#endif\n";
+
+ OS << "#ifndef DECL_CONTEXT_BASE\n";
+ OS << "# define DECL_CONTEXT_BASE(DECL) DECL_CONTEXT(DECL)\n";
+ OS << "#endif\n";
+
+ typedef std::set<Record*> RecordSet;
+ typedef std::vector<Record*> RecordVector;
+
+ RecordVector DeclContextsVector
+ = Records.getAllDerivedDefinitions("DeclContext");
+ RecordVector Decls = Records.getAllDerivedDefinitions("Decl");
+ RecordSet DeclContexts (DeclContextsVector.begin(), DeclContextsVector.end());
+
+ for (RecordVector::iterator i = Decls.begin(), e = Decls.end(); i != e; ++i) {
+ Record *R = *i;
+
+ if (R->getValue("Base")) {
+ Record *B = R->getValueAsDef("Base");
+ if (DeclContexts.find(B) != DeclContexts.end()) {
+ OS << "DECL_CONTEXT_BASE(" << B->getName() << ")\n";
+ DeclContexts.erase(B);
+ }
+ }
+ }
+
+ // To keep identical order, RecordVector may be used
+ // instead of RecordSet.
+ for (RecordVector::iterator
+ i = DeclContextsVector.begin(), e = DeclContextsVector.end();
+ i != e; ++i)
+ if (DeclContexts.find(*i) != DeclContexts.end())
+ OS << "DECL_CONTEXT(" << (*i)->getName() << ")\n";
+
+ OS << "#undef DECL_CONTEXT\n";
+ OS << "#undef DECL_CONTEXT_BASE\n";
+}
diff --git a/utils/TableGen/ClangASTNodesEmitter.h b/utils/TableGen/ClangASTNodesEmitter.h
new file mode 100644
index 000000000000..edd9316544ea
--- /dev/null
+++ b/utils/TableGen/ClangASTNodesEmitter.h
@@ -0,0 +1,84 @@
+//===- ClangASTNodesEmitter.h - Generate Clang AST node tables -*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These tablegen backends emit Clang AST node tables
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANGAST_EMITTER_H
+#define CLANGAST_EMITTER_H
+
+#include "llvm/TableGen/TableGenBackend.h"
+#include "llvm/TableGen/Record.h"
+#include <string>
+#include <cctype>
+#include <map>
+
+namespace llvm {
+
+/// ClangASTNodesEmitter - The top-level class emits .inc files containing
+/// declarations of Clang statements.
+///
+class ClangASTNodesEmitter : public TableGenBackend {
+ // A map from a node to each of its derived nodes.
+ typedef std::multimap<Record*, Record*> ChildMap;
+ typedef ChildMap::const_iterator ChildIterator;
+
+ RecordKeeper &Records;
+ Record Root;
+ const std::string &BaseSuffix;
+
+ // Create a macro-ized version of a name
+ static std::string macroName(std::string S) {
+ for (unsigned i = 0; i < S.size(); ++i)
+ S[i] = std::toupper(S[i]);
+
+ return S;
+ }
+
+ // Return the name to be printed in the base field. Normally this is
+ // the record's name plus the base suffix, but if it is the root node and
+ // the suffix is non-empty, it's just the suffix.
+ std::string baseName(Record &R) {
+ if (&R == &Root && !BaseSuffix.empty())
+ return BaseSuffix;
+
+ return R.getName() + BaseSuffix;
+ }
+
+ std::pair<Record *, Record *> EmitNode (const ChildMap &Tree, raw_ostream& OS,
+ Record *Base);
+public:
+ explicit ClangASTNodesEmitter(RecordKeeper &R, const std::string &N,
+ const std::string &S)
+ : Records(R), Root(N, SMLoc(), R), BaseSuffix(S)
+ {}
+
+ // run - Output the .inc file contents
+ void run(raw_ostream &OS);
+};
+
+/// ClangDeclContextEmitter - Emits an addendum to a .inc file to enumerate the
+/// clang declaration contexts.
+///
+class ClangDeclContextEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+
+public:
+ explicit ClangDeclContextEmitter(RecordKeeper &R)
+ : Records(R)
+ {}
+
+ // run - Output the .inc file contents
+ void run(raw_ostream &OS);
+};
+
+} // End llvm namespace
+
+#endif
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
new file mode 100644
index 000000000000..5c236be559f1
--- /dev/null
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -0,0 +1,788 @@
+//===- ClangAttrEmitter.cpp - Generate Clang attribute handling =-*- C++ -*--=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These tablegen backends emit Clang attribute processing code
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangAttrEmitter.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/TableGen/Record.h"
+#include <algorithm>
+#include <cctype>
+
+using namespace llvm;
+
+static const std::vector<StringRef>
+getValueAsListOfStrings(Record &R, StringRef FieldName) {
+ ListInit *List = R.getValueAsListInit(FieldName);
+ assert (List && "Got a null ListInit");
+
+ std::vector<StringRef> Strings;
+ Strings.reserve(List->getSize());
+
+ for (ListInit::const_iterator i = List->begin(), e = List->end();
+ i != e;
+ ++i) {
+ assert(*i && "Got a null element in a ListInit");
+ if (StringInit *S = dynamic_cast<StringInit *>(*i))
+ Strings.push_back(S->getValue());
+ else if (CodeInit *C = dynamic_cast<CodeInit *>(*i))
+ Strings.push_back(C->getValue());
+ else
+ assert(false && "Got a non-string, non-code element in a ListInit");
+ }
+
+ return Strings;
+}
+
+static std::string ReadPCHRecord(StringRef type) {
+ return StringSwitch<std::string>(type)
+ .EndsWith("Decl *", "GetLocalDeclAs<"
+ + std::string(type, 0, type.size()-1) + ">(F, Record[Idx++])")
+ .Case("QualType", "getLocalType(F, Record[Idx++])")
+ .Case("Expr *", "ReadSubExpr()")
+ .Case("IdentifierInfo *", "GetIdentifierInfo(F, Record, Idx)")
+ .Case("SourceLocation", "ReadSourceLocation(F, Record, Idx)")
+ .Default("Record[Idx++]");
+}
+
+// Assumes that the way to get the value is SA->getname()
+static std::string WritePCHRecord(StringRef type, StringRef name) {
+ return StringSwitch<std::string>(type)
+ .EndsWith("Decl *", "AddDeclRef(" + std::string(name) +
+ ", Record);\n")
+ .Case("QualType", "AddTypeRef(" + std::string(name) + ", Record);\n")
+ .Case("Expr *", "AddStmt(" + std::string(name) + ");\n")
+ .Case("IdentifierInfo *",
+ "AddIdentifierRef(" + std::string(name) + ", Record);\n")
+ .Case("SourceLocation",
+ "AddSourceLocation(" + std::string(name) + ", Record);\n")
+ .Default("Record.push_back(" + std::string(name) + ");\n");
+}
+
+namespace {
+ class Argument {
+ std::string lowerName, upperName;
+ StringRef attrName;
+
+ public:
+ Argument(Record &Arg, StringRef Attr)
+ : lowerName(Arg.getValueAsString("Name")), upperName(lowerName),
+ attrName(Attr) {
+ if (!lowerName.empty()) {
+ lowerName[0] = std::tolower(lowerName[0]);
+ upperName[0] = std::toupper(upperName[0]);
+ }
+ }
+ virtual ~Argument() {}
+
+ StringRef getLowerName() const { return lowerName; }
+ StringRef getUpperName() const { return upperName; }
+ StringRef getAttrName() const { return attrName; }
+
+ // These functions print the argument contents formatted in different ways.
+ virtual void writeAccessors(raw_ostream &OS) const = 0;
+ virtual void writeAccessorDefinitions(raw_ostream &OS) const {}
+ virtual void writeCloneArgs(raw_ostream &OS) const = 0;
+ virtual void writeCtorBody(raw_ostream &OS) const {}
+ virtual void writeCtorInitializers(raw_ostream &OS) const = 0;
+ virtual void writeCtorParameters(raw_ostream &OS) const = 0;
+ virtual void writeDeclarations(raw_ostream &OS) const = 0;
+ virtual void writePCHReadArgs(raw_ostream &OS) const = 0;
+ virtual void writePCHReadDecls(raw_ostream &OS) const = 0;
+ virtual void writePCHWrite(raw_ostream &OS) const = 0;
+ };
+
+ class SimpleArgument : public Argument {
+ std::string type;
+
+ public:
+ SimpleArgument(Record &Arg, StringRef Attr, std::string T)
+ : Argument(Arg, Attr), type(T)
+ {}
+
+ void writeAccessors(raw_ostream &OS) const {
+ OS << " " << type << " get" << getUpperName() << "() const {\n";
+ OS << " return " << getLowerName() << ";\n";
+ OS << " }";
+ }
+ void writeCloneArgs(raw_ostream &OS) const {
+ OS << getLowerName();
+ }
+ void writeCtorInitializers(raw_ostream &OS) const {
+ OS << getLowerName() << "(" << getUpperName() << ")";
+ }
+ void writeCtorParameters(raw_ostream &OS) const {
+ OS << type << " " << getUpperName();
+ }
+ void writeDeclarations(raw_ostream &OS) const {
+ OS << type << " " << getLowerName() << ";";
+ }
+ void writePCHReadDecls(raw_ostream &OS) const {
+ std::string read = ReadPCHRecord(type);
+ OS << " " << type << " " << getLowerName() << " = " << read << ";\n";
+ }
+ void writePCHReadArgs(raw_ostream &OS) const {
+ OS << getLowerName();
+ }
+ void writePCHWrite(raw_ostream &OS) const {
+ OS << " " << WritePCHRecord(type, "SA->get" +
+ std::string(getUpperName()) + "()");
+ }
+ };
+
+ class StringArgument : public Argument {
+ public:
+ StringArgument(Record &Arg, StringRef Attr)
+ : Argument(Arg, Attr)
+ {}
+
+ void writeAccessors(raw_ostream &OS) const {
+ OS << " llvm::StringRef get" << getUpperName() << "() const {\n";
+ OS << " return llvm::StringRef(" << getLowerName() << ", "
+ << getLowerName() << "Length);\n";
+ OS << " }\n";
+ OS << " unsigned get" << getUpperName() << "Length() const {\n";
+ OS << " return " << getLowerName() << "Length;\n";
+ OS << " }\n";
+ OS << " void set" << getUpperName()
+ << "(ASTContext &C, llvm::StringRef S) {\n";
+ OS << " " << getLowerName() << "Length = S.size();\n";
+ OS << " this->" << getLowerName() << " = new (C, 1) char ["
+ << getLowerName() << "Length];\n";
+ OS << " std::memcpy(this->" << getLowerName() << ", S.data(), "
+ << getLowerName() << "Length);\n";
+ OS << " }";
+ }
+ void writeCloneArgs(raw_ostream &OS) const {
+ OS << "get" << getUpperName() << "()";
+ }
+ void writeCtorBody(raw_ostream &OS) const {
+ OS << " std::memcpy(" << getLowerName() << ", " << getUpperName()
+ << ".data(), " << getLowerName() << "Length);";
+ }
+ void writeCtorInitializers(raw_ostream &OS) const {
+ OS << getLowerName() << "Length(" << getUpperName() << ".size()),"
+ << getLowerName() << "(new (Ctx, 1) char[" << getLowerName()
+ << "Length])";
+ }
+ void writeCtorParameters(raw_ostream &OS) const {
+ OS << "llvm::StringRef " << getUpperName();
+ }
+ void writeDeclarations(raw_ostream &OS) const {
+ OS << "unsigned " << getLowerName() << "Length;\n";
+ OS << "char *" << getLowerName() << ";";
+ }
+ void writePCHReadDecls(raw_ostream &OS) const {
+ OS << " std::string " << getLowerName()
+ << "= ReadString(Record, Idx);\n";
+ }
+ void writePCHReadArgs(raw_ostream &OS) const {
+ OS << getLowerName();
+ }
+ void writePCHWrite(raw_ostream &OS) const {
+ OS << " AddString(SA->get" << getUpperName() << "(), Record);\n";
+ }
+ };
+
+ class AlignedArgument : public Argument {
+ public:
+ AlignedArgument(Record &Arg, StringRef Attr)
+ : Argument(Arg, Attr)
+ {}
+
+ void writeAccessors(raw_ostream &OS) const {
+ OS << " bool is" << getUpperName() << "Dependent() const;\n";
+
+ OS << " unsigned get" << getUpperName() << "(ASTContext &Ctx) const;\n";
+
+ OS << " bool is" << getUpperName() << "Expr() const {\n";
+ OS << " return is" << getLowerName() << "Expr;\n";
+ OS << " }\n";
+
+ OS << " Expr *get" << getUpperName() << "Expr() const {\n";
+ OS << " assert(is" << getLowerName() << "Expr);\n";
+ OS << " return " << getLowerName() << "Expr;\n";
+ OS << " }\n";
+
+ OS << " TypeSourceInfo *get" << getUpperName() << "Type() const {\n";
+ OS << " assert(!is" << getLowerName() << "Expr);\n";
+ OS << " return " << getLowerName() << "Type;\n";
+ OS << " }";
+ }
+ void writeAccessorDefinitions(raw_ostream &OS) const {
+ OS << "bool " << getAttrName() << "Attr::is" << getUpperName()
+ << "Dependent() const {\n";
+ OS << " if (is" << getLowerName() << "Expr)\n";
+ OS << " return " << getLowerName() << "Expr && (" << getLowerName()
+ << "Expr->isValueDependent() || " << getLowerName()
+ << "Expr->isTypeDependent());\n";
+ OS << " else\n";
+ OS << " return " << getLowerName()
+ << "Type->getType()->isDependentType();\n";
+ OS << "}\n";
+
+ // FIXME: Do not do the calculation here
+ // FIXME: Handle types correctly
+ // A null pointer means maximum alignment
+ // FIXME: Load the platform-specific maximum alignment, rather than
+ // 16, the x86 max.
+ OS << "unsigned " << getAttrName() << "Attr::get" << getUpperName()
+ << "(ASTContext &Ctx) const {\n";
+ OS << " assert(!is" << getUpperName() << "Dependent());\n";
+ OS << " if (is" << getLowerName() << "Expr)\n";
+ OS << " return (" << getLowerName() << "Expr ? " << getLowerName()
+ << "Expr->EvaluateKnownConstInt(Ctx).getZExtValue() : 16)"
+ << "* Ctx.getCharWidth();\n";
+ OS << " else\n";
+ OS << " return 0; // FIXME\n";
+ OS << "}\n";
+ }
+ void writeCloneArgs(raw_ostream &OS) const {
+ OS << "is" << getLowerName() << "Expr, is" << getLowerName()
+ << "Expr ? static_cast<void*>(" << getLowerName()
+ << "Expr) : " << getLowerName()
+ << "Type";
+ }
+ void writeCtorBody(raw_ostream &OS) const {
+ OS << " if (is" << getLowerName() << "Expr)\n";
+ OS << " " << getLowerName() << "Expr = reinterpret_cast<Expr *>("
+ << getUpperName() << ");\n";
+ OS << " else\n";
+ OS << " " << getLowerName()
+ << "Type = reinterpret_cast<TypeSourceInfo *>(" << getUpperName()
+ << ");";
+ }
+ void writeCtorInitializers(raw_ostream &OS) const {
+ OS << "is" << getLowerName() << "Expr(Is" << getUpperName() << "Expr)";
+ }
+ void writeCtorParameters(raw_ostream &OS) const {
+ OS << "bool Is" << getUpperName() << "Expr, void *" << getUpperName();
+ }
+ void writeDeclarations(raw_ostream &OS) const {
+ OS << "bool is" << getLowerName() << "Expr;\n";
+ OS << "union {\n";
+ OS << "Expr *" << getLowerName() << "Expr;\n";
+ OS << "TypeSourceInfo *" << getLowerName() << "Type;\n";
+ OS << "};";
+ }
+ void writePCHReadArgs(raw_ostream &OS) const {
+ OS << "is" << getLowerName() << "Expr, " << getLowerName() << "Ptr";
+ }
+ void writePCHReadDecls(raw_ostream &OS) const {
+ OS << " bool is" << getLowerName() << "Expr = Record[Idx++];\n";
+ OS << " void *" << getLowerName() << "Ptr;\n";
+ OS << " if (is" << getLowerName() << "Expr)\n";
+ OS << " " << getLowerName() << "Ptr = ReadExpr(F);\n";
+ OS << " else\n";
+ OS << " " << getLowerName()
+ << "Ptr = GetTypeSourceInfo(F, Record, Idx);\n";
+ }
+ void writePCHWrite(raw_ostream &OS) const {
+ OS << " Record.push_back(SA->is" << getUpperName() << "Expr());\n";
+ OS << " if (SA->is" << getUpperName() << "Expr())\n";
+ OS << " AddStmt(SA->get" << getUpperName() << "Expr());\n";
+ OS << " else\n";
+ OS << " AddTypeSourceInfo(SA->get" << getUpperName()
+ << "Type(), Record);\n";
+ }
+ };
+
+ class VariadicArgument : public Argument {
+ std::string type;
+
+ public:
+ VariadicArgument(Record &Arg, StringRef Attr, std::string T)
+ : Argument(Arg, Attr), type(T)
+ {}
+
+ std::string getType() const { return type; }
+
+ void writeAccessors(raw_ostream &OS) const {
+ OS << " typedef " << type << "* " << getLowerName() << "_iterator;\n";
+ OS << " " << getLowerName() << "_iterator " << getLowerName()
+ << "_begin() const {\n";
+ OS << " return " << getLowerName() << ";\n";
+ OS << " }\n";
+ OS << " " << getLowerName() << "_iterator " << getLowerName()
+ << "_end() const {\n";
+ OS << " return " << getLowerName() << " + " << getLowerName()
+ << "Size;\n";
+ OS << " }\n";
+ OS << " unsigned " << getLowerName() << "_size() const {\n"
+ << " return " << getLowerName() << "Size;\n;";
+ OS << " }";
+ }
+ void writeCloneArgs(raw_ostream &OS) const {
+ OS << getLowerName() << ", " << getLowerName() << "Size";
+ }
+ void writeCtorBody(raw_ostream &OS) const {
+ // FIXME: memcpy is not safe on non-trivial types.
+ OS << " std::memcpy(" << getLowerName() << ", " << getUpperName()
+ << ", " << getLowerName() << "Size * sizeof(" << getType() << "));\n";
+ }
+ void writeCtorInitializers(raw_ostream &OS) const {
+ OS << getLowerName() << "Size(" << getUpperName() << "Size), "
+ << getLowerName() << "(new (Ctx, 16) " << getType() << "["
+ << getLowerName() << "Size])";
+ }
+ void writeCtorParameters(raw_ostream &OS) const {
+ OS << getType() << " *" << getUpperName() << ", unsigned "
+ << getUpperName() << "Size";
+ }
+ void writeDeclarations(raw_ostream &OS) const {
+ OS << " unsigned " << getLowerName() << "Size;\n";
+ OS << " " << getType() << " *" << getLowerName() << ";";
+ }
+ void writePCHReadDecls(raw_ostream &OS) const {
+ OS << " unsigned " << getLowerName() << "Size = Record[Idx++];\n";
+ OS << " llvm::SmallVector<" << type << ", 4> " << getLowerName()
+ << ";\n";
+ OS << " " << getLowerName() << ".reserve(" << getLowerName()
+ << "Size);\n";
+ OS << " for (unsigned i = " << getLowerName() << "Size; i; --i)\n";
+
+ std::string read = ReadPCHRecord(type);
+ OS << " " << getLowerName() << ".push_back(" << read << ");\n";
+ }
+ void writePCHReadArgs(raw_ostream &OS) const {
+ OS << getLowerName() << ".data(), " << getLowerName() << "Size";
+ }
+ void writePCHWrite(raw_ostream &OS) const{
+ OS << " Record.push_back(SA->" << getLowerName() << "_size());\n";
+ OS << " for (" << getAttrName() << "Attr::" << getLowerName()
+ << "_iterator i = SA->" << getLowerName() << "_begin(), e = SA->"
+ << getLowerName() << "_end(); i != e; ++i)\n";
+ OS << " " << WritePCHRecord(type, "(*i)");
+ }
+ };
+
+ class EnumArgument : public Argument {
+ std::string type;
+ std::vector<StringRef> values, enums;
+ public:
+ EnumArgument(Record &Arg, StringRef Attr)
+ : Argument(Arg, Attr), type(Arg.getValueAsString("Type")),
+ values(getValueAsListOfStrings(Arg, "Values")),
+ enums(getValueAsListOfStrings(Arg, "Enums"))
+ {}
+
+ void writeAccessors(raw_ostream &OS) const {
+ OS << " " << type << " get" << getUpperName() << "() const {\n";
+ OS << " return " << getLowerName() << ";\n";
+ OS << " }";
+ }
+ void writeCloneArgs(raw_ostream &OS) const {
+ OS << getLowerName();
+ }
+ void writeCtorInitializers(raw_ostream &OS) const {
+ OS << getLowerName() << "(" << getUpperName() << ")";
+ }
+ void writeCtorParameters(raw_ostream &OS) const {
+ 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();
+ // The last one needs to not have a comma.
+ --e;
+
+ OS << "public:\n";
+ OS << " enum " << type << " {\n";
+ for (; i != e; ++i)
+ OS << " " << *i << ",\n";
+ OS << " " << *e << "\n";
+ OS << " };\n";
+ OS << "private:\n";
+ OS << " " << type << " " << getLowerName() << ";";
+ }
+ void writePCHReadDecls(raw_ostream &OS) const {
+ OS << " " << getAttrName() << "Attr::" << type << " " << getLowerName()
+ << "(static_cast<" << getAttrName() << "Attr::" << type
+ << ">(Record[Idx++]));\n";
+ }
+ void writePCHReadArgs(raw_ostream &OS) const {
+ OS << getLowerName();
+ }
+ void writePCHWrite(raw_ostream &OS) const {
+ OS << "Record.push_back(SA->get" << getUpperName() << "());\n";
+ }
+ };
+
+ class VersionArgument : public Argument {
+ public:
+ VersionArgument(Record &Arg, StringRef Attr)
+ : Argument(Arg, Attr)
+ {}
+
+ void writeAccessors(raw_ostream &OS) const {
+ OS << " VersionTuple get" << getUpperName() << "() const {\n";
+ OS << " return " << getLowerName() << ";\n";
+ OS << " }\n";
+ OS << " void set" << getUpperName()
+ << "(ASTContext &C, VersionTuple V) {\n";
+ OS << " " << getLowerName() << " = V;\n";
+ OS << " }";
+ }
+ void writeCloneArgs(raw_ostream &OS) const {
+ OS << "get" << getUpperName() << "()";
+ }
+ void writeCtorBody(raw_ostream &OS) const {
+ }
+ void writeCtorInitializers(raw_ostream &OS) const {
+ OS << getLowerName() << "(" << getUpperName() << ")";
+ }
+ void writeCtorParameters(raw_ostream &OS) const {
+ OS << "VersionTuple " << getUpperName();
+ }
+ void writeDeclarations(raw_ostream &OS) const {
+ OS << "VersionTuple " << getLowerName() << ";\n";
+ }
+ void writePCHReadDecls(raw_ostream &OS) const {
+ OS << " VersionTuple " << getLowerName()
+ << "= ReadVersionTuple(Record, Idx);\n";
+ }
+ void writePCHReadArgs(raw_ostream &OS) const {
+ OS << getLowerName();
+ }
+ void writePCHWrite(raw_ostream &OS) const {
+ OS << " AddVersionTuple(SA->get" << getUpperName() << "(), Record);\n";
+ }
+ };
+}
+
+static Argument *createArgument(Record &Arg, StringRef Attr,
+ Record *Search = 0) {
+ if (!Search)
+ Search = &Arg;
+
+ Argument *Ptr = 0;
+ llvm::StringRef ArgName = Search->getName();
+
+ if (ArgName == "AlignedArgument") Ptr = new AlignedArgument(Arg, Attr);
+ else if (ArgName == "EnumArgument") Ptr = new EnumArgument(Arg, Attr);
+ else if (ArgName == "ExprArgument") Ptr = new SimpleArgument(Arg, Attr,
+ "Expr *");
+ else if (ArgName == "FunctionArgument")
+ Ptr = new SimpleArgument(Arg, Attr, "FunctionDecl *");
+ else if (ArgName == "IdentifierArgument")
+ Ptr = new SimpleArgument(Arg, Attr, "IdentifierInfo *");
+ else if (ArgName == "BoolArgument") Ptr = new SimpleArgument(Arg, Attr,
+ "bool");
+ else if (ArgName == "IntArgument") Ptr = new SimpleArgument(Arg, Attr, "int");
+ else if (ArgName == "StringArgument") Ptr = new StringArgument(Arg, Attr);
+ else if (ArgName == "TypeArgument")
+ Ptr = new SimpleArgument(Arg, Attr, "QualType");
+ else if (ArgName == "UnsignedArgument")
+ Ptr = new SimpleArgument(Arg, Attr, "unsigned");
+ else if (ArgName == "SourceLocArgument")
+ Ptr = new SimpleArgument(Arg, Attr, "SourceLocation");
+ else if (ArgName == "VariadicUnsignedArgument")
+ Ptr = new VariadicArgument(Arg, Attr, "unsigned");
+ else if (ArgName == "VariadicExprArgument")
+ Ptr = new VariadicArgument(Arg, Attr, "Expr *");
+ else if (ArgName == "VersionArgument")
+ Ptr = new VersionArgument(Arg, Attr);
+
+ if (!Ptr) {
+ std::vector<Record*> Bases = Search->getSuperClasses();
+ for (std::vector<Record*>::iterator i = Bases.begin(), e = Bases.end();
+ i != e; ++i) {
+ Ptr = createArgument(Arg, Attr, *i);
+ if (Ptr)
+ break;
+ }
+ }
+ return Ptr;
+}
+
+void ClangAttrClassEmitter::run(raw_ostream &OS) {
+ OS << "// This file is generated by TableGen. Do not edit.\n\n";
+ OS << "#ifndef LLVM_CLANG_ATTR_CLASSES_INC\n";
+ OS << "#define LLVM_CLANG_ATTR_CLASSES_INC\n\n";
+
+ std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+
+ for (std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end();
+ i != e; ++i) {
+ Record &R = **i;
+ const std::string &SuperName = R.getSuperClasses().back()->getName();
+
+ OS << "class " << R.getName() << "Attr : public " << SuperName << " {\n";
+
+ std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
+ std::vector<Argument*> Args;
+ std::vector<Argument*>::iterator ai, ae;
+ Args.reserve(ArgRecords.size());
+
+ for (std::vector<Record*>::iterator ri = ArgRecords.begin(),
+ re = ArgRecords.end();
+ ri != re; ++ri) {
+ Record &ArgRecord = **ri;
+ Argument *Arg = createArgument(ArgRecord, R.getName());
+ assert(Arg);
+ Args.push_back(Arg);
+
+ Arg->writeDeclarations(OS);
+ OS << "\n\n";
+ }
+
+ ae = Args.end();
+
+ OS << "\n public:\n";
+ OS << " " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n";
+
+ for (ai = Args.begin(); ai != ae; ++ai) {
+ OS << " , ";
+ (*ai)->writeCtorParameters(OS);
+ OS << "\n";
+ }
+
+ OS << " )\n";
+ OS << " : " << SuperName << "(attr::" << R.getName() << ", R)\n";
+
+ for (ai = Args.begin(); ai != ae; ++ai) {
+ OS << " , ";
+ (*ai)->writeCtorInitializers(OS);
+ OS << "\n";
+ }
+
+ OS << " {\n";
+
+ for (ai = Args.begin(); ai != ae; ++ai) {
+ (*ai)->writeCtorBody(OS);
+ OS << "\n";
+ }
+ OS << " }\n\n";
+
+ OS << " virtual " << R.getName() << "Attr *clone (ASTContext &C) const;\n";
+
+ for (ai = Args.begin(); ai != ae; ++ai) {
+ (*ai)->writeAccessors(OS);
+ OS << "\n\n";
+ }
+
+ OS << R.getValueAsCode("AdditionalMembers");
+ OS << "\n\n";
+
+ OS << " static bool classof(const Attr *A) { return A->getKind() == "
+ << "attr::" << R.getName() << "; }\n";
+ OS << " static bool classof(const " << R.getName()
+ << "Attr *) { return true; }\n";
+ OS << "};\n\n";
+ }
+
+ OS << "#endif\n";
+}
+
+void ClangAttrImplEmitter::run(raw_ostream &OS) {
+ OS << "// This file is generated by TableGen. Do not edit.\n\n";
+
+ std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+ std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(), ri, re;
+ std::vector<Argument*>::iterator ai, ae;
+
+ for (; i != e; ++i) {
+ Record &R = **i;
+ std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
+ std::vector<Argument*> Args;
+ for (ri = ArgRecords.begin(), re = ArgRecords.end(); ri != re; ++ri)
+ Args.push_back(createArgument(**ri, R.getName()));
+
+ for (ai = Args.begin(), ae = Args.end(); ai != ae; ++ai)
+ (*ai)->writeAccessorDefinitions(OS);
+
+ OS << R.getName() << "Attr *" << R.getName()
+ << "Attr::clone(ASTContext &C) const {\n";
+ OS << " return new (C) " << R.getName() << "Attr(getLocation(), C";
+ for (ai = Args.begin(); ai != ae; ++ai) {
+ OS << ", ";
+ (*ai)->writeCloneArgs(OS);
+ }
+ OS << ");\n}\n\n";
+ }
+}
+
+static void EmitAttrList(raw_ostream &OS, StringRef Class,
+ const std::vector<Record*> &AttrList) {
+ std::vector<Record*>::const_iterator i = AttrList.begin(), e = AttrList.end();
+
+ if (i != e) {
+ // Move the end iterator back to emit the last attribute.
+ for(--e; i != e; ++i)
+ OS << Class << "(" << (*i)->getName() << ")\n";
+
+ OS << "LAST_" << Class << "(" << (*i)->getName() << ")\n\n";
+ }
+}
+
+void ClangAttrListEmitter::run(raw_ostream &OS) {
+ OS << "// This file is generated by TableGen. Do not edit.\n\n";
+
+ OS << "#ifndef LAST_ATTR\n";
+ OS << "#define LAST_ATTR(NAME) ATTR(NAME)\n";
+ OS << "#endif\n\n";
+
+ OS << "#ifndef INHERITABLE_ATTR\n";
+ OS << "#define INHERITABLE_ATTR(NAME) ATTR(NAME)\n";
+ OS << "#endif\n\n";
+
+ OS << "#ifndef LAST_INHERITABLE_ATTR\n";
+ OS << "#define LAST_INHERITABLE_ATTR(NAME) INHERITABLE_ATTR(NAME)\n";
+ OS << "#endif\n\n";
+
+ OS << "#ifndef INHERITABLE_PARAM_ATTR\n";
+ OS << "#define INHERITABLE_PARAM_ATTR(NAME) ATTR(NAME)\n";
+ OS << "#endif\n\n";
+
+ OS << "#ifndef LAST_INHERITABLE_PARAM_ATTR\n";
+ OS << "#define LAST_INHERITABLE_PARAM_ATTR(NAME)"
+ " INHERITABLE_PARAM_ATTR(NAME)\n";
+ OS << "#endif\n\n";
+
+ Record *InhClass = Records.getClass("InheritableAttr");
+ Record *InhParamClass = Records.getClass("InheritableParamAttr");
+ std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"),
+ NonInhAttrs, InhAttrs, InhParamAttrs;
+ for (std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end();
+ i != e; ++i) {
+ if ((*i)->isSubClassOf(InhParamClass))
+ InhParamAttrs.push_back(*i);
+ else if ((*i)->isSubClassOf(InhClass))
+ InhAttrs.push_back(*i);
+ else
+ NonInhAttrs.push_back(*i);
+ }
+
+ EmitAttrList(OS, "INHERITABLE_PARAM_ATTR", InhParamAttrs);
+ EmitAttrList(OS, "INHERITABLE_ATTR", InhAttrs);
+ EmitAttrList(OS, "ATTR", NonInhAttrs);
+
+ OS << "#undef LAST_ATTR\n";
+ OS << "#undef INHERITABLE_ATTR\n";
+ OS << "#undef LAST_INHERITABLE_ATTR\n";
+ OS << "#undef LAST_INHERITABLE_PARAM_ATTR\n";
+ OS << "#undef ATTR\n";
+}
+
+void ClangAttrPCHReadEmitter::run(raw_ostream &OS) {
+ OS << "// This file is generated by TableGen. Do not edit.\n\n";
+
+ Record *InhClass = Records.getClass("InheritableAttr");
+ std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"),
+ ArgRecords;
+ std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(), ai, ae;
+ std::vector<Argument*> Args;
+ std::vector<Argument*>::iterator ri, re;
+
+ OS << " switch (Kind) {\n";
+ OS << " default:\n";
+ OS << " assert(0 && \"Unknown attribute!\");\n";
+ OS << " break;\n";
+ for (; i != e; ++i) {
+ Record &R = **i;
+ OS << " case attr::" << R.getName() << ": {\n";
+ if (R.isSubClassOf(InhClass))
+ OS << " bool isInherited = Record[Idx++];\n";
+ ArgRecords = R.getValueAsListOfDefs("Args");
+ Args.clear();
+ for (ai = ArgRecords.begin(), ae = ArgRecords.end(); ai != ae; ++ai) {
+ Argument *A = createArgument(**ai, R.getName());
+ Args.push_back(A);
+ A->writePCHReadDecls(OS);
+ }
+ OS << " New = new (Context) " << R.getName() << "Attr(Range, Context";
+ for (ri = Args.begin(), re = Args.end(); ri != re; ++ri) {
+ OS << ", ";
+ (*ri)->writePCHReadArgs(OS);
+ }
+ OS << ");\n";
+ if (R.isSubClassOf(InhClass))
+ OS << " cast<InheritableAttr>(New)->setInherited(isInherited);\n";
+ OS << " break;\n";
+ OS << " }\n";
+ }
+ OS << " }\n";
+}
+
+void ClangAttrPCHWriteEmitter::run(raw_ostream &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;
+
+ OS << " switch (A->getKind()) {\n";
+ OS << " default:\n";
+ OS << " llvm_unreachable(\"Unknown attribute kind!\");\n";
+ OS << " break;\n";
+ for (; i != e; ++i) {
+ Record &R = **i;
+ OS << " case attr::" << R.getName() << ": {\n";
+ Args = R.getValueAsListOfDefs("Args");
+ if (R.isSubClassOf(InhClass) || !Args.empty())
+ OS << " const " << R.getName() << "Attr *SA = cast<" << R.getName()
+ << "Attr>(A);\n";
+ if (R.isSubClassOf(InhClass))
+ OS << " Record.push_back(SA->isInherited());\n";
+ for (ai = Args.begin(), ae = Args.end(); ai != ae; ++ai)
+ createArgument(**ai, R.getName())->writePCHWrite(OS);
+ OS << " break;\n";
+ OS << " }\n";
+ }
+ OS << " }\n";
+}
+
+void ClangAttrSpellingListEmitter::run(raw_ostream &OS) {
+ OS << "// This file is generated by TableGen. Do not edit.\n\n";
+
+ std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+
+ for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); I != E; ++I) {
+ Record &Attr = **I;
+
+ std::vector<StringRef> Spellings = getValueAsListOfStrings(Attr, "Spellings");
+
+ for (std::vector<StringRef>::const_iterator I = Spellings.begin(), E = Spellings.end(); I != E; ++I) {
+ StringRef Spelling = *I;
+ OS << ".Case(\"" << Spelling << "\", true)\n";
+ }
+ }
+
+}
+
+void ClangAttrLateParsedListEmitter::run(raw_ostream &OS) {
+ OS << "// This file is generated by TableGen. Do not edit.\n\n";
+
+ std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+
+ for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end();
+ I != E; ++I) {
+ Record &Attr = **I;
+
+ bool LateParsed = Attr.getValueAsBit("LateParsed");
+
+ if (LateParsed) {
+ std::vector<StringRef> Spellings =
+ getValueAsListOfStrings(Attr, "Spellings");
+
+ for (std::vector<StringRef>::const_iterator I = Spellings.begin(),
+ E = Spellings.end(); I != E; ++I) {
+ OS << ".Case(\"" << (*I) << "\", " << LateParsed << ")\n";
+ }
+ }
+ }
+}
diff --git a/utils/TableGen/ClangAttrEmitter.h b/utils/TableGen/ClangAttrEmitter.h
new file mode 100644
index 000000000000..5acca560f013
--- /dev/null
+++ b/utils/TableGen/ClangAttrEmitter.h
@@ -0,0 +1,114 @@
+//===- ClangAttrEmitter.h - Generate Clang attribute handling =-*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These tablegen backends emit Clang attribute processing code
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANGATTR_EMITTER_H
+#define CLANGATTR_EMITTER_H
+
+#include "llvm/TableGen/TableGenBackend.h"
+
+namespace llvm {
+
+/// ClangAttrClassEmitter - class emits the class defintions for attributes for
+/// clang.
+class ClangAttrClassEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+
+ public:
+ explicit ClangAttrClassEmitter(RecordKeeper &R)
+ : Records(R)
+ {}
+
+ void run(raw_ostream &OS);
+};
+
+/// ClangAttrImplEmitter - class emits the class method defintions for
+/// attributes for clang.
+class ClangAttrImplEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+
+ public:
+ explicit ClangAttrImplEmitter(RecordKeeper &R)
+ : Records(R)
+ {}
+
+ void run(raw_ostream &OS);
+};
+
+/// ClangAttrListEmitter - class emits the enumeration list for attributes for
+/// clang.
+class ClangAttrListEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+
+ public:
+ explicit ClangAttrListEmitter(RecordKeeper &R)
+ : Records(R)
+ {}
+
+ void run(raw_ostream &OS);
+};
+
+/// ClangAttrPCHReadEmitter - class emits the code to read an attribute from
+/// a clang precompiled header.
+class ClangAttrPCHReadEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+
+public:
+ explicit ClangAttrPCHReadEmitter(RecordKeeper &R)
+ : Records(R)
+ {}
+
+ void run(raw_ostream &OS);
+};
+
+/// ClangAttrPCHWriteEmitter - class emits the code to read an attribute from
+/// a clang precompiled header.
+class ClangAttrPCHWriteEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+
+public:
+ explicit ClangAttrPCHWriteEmitter(RecordKeeper &R)
+ : Records(R)
+ {}
+
+ void run(raw_ostream &OS);
+};
+
+/// ClangAttrSpellingListEmitter - class emits the list of spellings for attributes for
+/// clang.
+class ClangAttrSpellingListEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+
+ public:
+ explicit ClangAttrSpellingListEmitter(RecordKeeper &R)
+ : Records(R)
+ {}
+
+ void run(raw_ostream &OS);
+};
+
+/// ClangAttrLateParsedListEmitter emits the LateParsed property for attributes
+/// for clang.
+class ClangAttrLateParsedListEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+
+ public:
+ explicit ClangAttrLateParsedListEmitter(RecordKeeper &R)
+ : Records(R)
+ {}
+
+ void run(raw_ostream &OS);
+};
+
+}
+
+#endif
diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp
new file mode 100644
index 000000000000..da2fb70b4a57
--- /dev/null
+++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -0,0 +1,378 @@
+//=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*-
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These tablegen backends emit Clang diagnostics tables.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangDiagnosticsEmitter.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/VectorExtras.h"
+#include <map>
+#include <algorithm>
+#include <functional>
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+// Diagnostic category computation code.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class DiagGroupParentMap {
+ RecordKeeper &Records;
+ std::map<const Record*, std::vector<Record*> > Mapping;
+public:
+ DiagGroupParentMap(RecordKeeper &records) : Records(records) {
+ std::vector<Record*> DiagGroups
+ = Records.getAllDerivedDefinitions("DiagGroup");
+ for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
+ std::vector<Record*> SubGroups =
+ DiagGroups[i]->getValueAsListOfDefs("SubGroups");
+ for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
+ Mapping[SubGroups[j]].push_back(DiagGroups[i]);
+ }
+ }
+
+ const std::vector<Record*> &getParents(const Record *Group) {
+ return Mapping[Group];
+ }
+};
+} // end anonymous namespace.
+
+
+static std::string
+getCategoryFromDiagGroup(const Record *Group,
+ DiagGroupParentMap &DiagGroupParents) {
+ // If the DiagGroup has a category, return it.
+ std::string CatName = Group->getValueAsString("CategoryName");
+ if (!CatName.empty()) return CatName;
+
+ // The diag group may the subgroup of one or more other diagnostic groups,
+ // check these for a category as well.
+ const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
+ for (unsigned i = 0, e = Parents.size(); i != e; ++i) {
+ CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents);
+ if (!CatName.empty()) return CatName;
+ }
+ return "";
+}
+
+/// getDiagnosticCategory - Return the category that the specified diagnostic
+/// lives in.
+static std::string getDiagnosticCategory(const Record *R,
+ DiagGroupParentMap &DiagGroupParents) {
+ // If the diagnostic is in a group, and that group has a category, use it.
+ if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group"))) {
+ // Check the diagnostic's diag group for a category.
+ std::string CatName = getCategoryFromDiagGroup(Group->getDef(),
+ DiagGroupParents);
+ if (!CatName.empty()) return CatName;
+ }
+
+ // If the diagnostic itself has a category, get it.
+ return R->getValueAsString("CategoryName");
+}
+
+namespace {
+ class DiagCategoryIDMap {
+ RecordKeeper &Records;
+ StringMap<unsigned> CategoryIDs;
+ std::vector<std::string> CategoryStrings;
+ public:
+ DiagCategoryIDMap(RecordKeeper &records) : Records(records) {
+ DiagGroupParentMap ParentInfo(Records);
+
+ // The zero'th category is "".
+ CategoryStrings.push_back("");
+ CategoryIDs[""] = 0;
+
+ std::vector<Record*> Diags =
+ Records.getAllDerivedDefinitions("Diagnostic");
+ for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
+ std::string Category = getDiagnosticCategory(Diags[i], ParentInfo);
+ if (Category.empty()) continue; // Skip diags with no category.
+
+ unsigned &ID = CategoryIDs[Category];
+ if (ID != 0) continue; // Already seen.
+
+ ID = CategoryStrings.size();
+ CategoryStrings.push_back(Category);
+ }
+ }
+
+ unsigned getID(StringRef CategoryString) {
+ return CategoryIDs[CategoryString];
+ }
+
+ typedef std::vector<std::string>::iterator iterator;
+ iterator begin() { return CategoryStrings.begin(); }
+ iterator end() { return CategoryStrings.end(); }
+ };
+} // end anonymous namespace.
+
+
+//===----------------------------------------------------------------------===//
+// Warning Tables (.inc file) generation.
+//===----------------------------------------------------------------------===//
+
+void ClangDiagsDefsEmitter::run(raw_ostream &OS) {
+ // Write the #if guard
+ if (!Component.empty()) {
+ std::string ComponentName = UppercaseString(Component);
+ OS << "#ifdef " << ComponentName << "START\n";
+ OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
+ << ",\n";
+ OS << "#undef " << ComponentName << "START\n";
+ OS << "#endif\n\n";
+ }
+
+ const std::vector<Record*> &Diags =
+ Records.getAllDerivedDefinitions("Diagnostic");
+
+ DiagCategoryIDMap CategoryIDs(Records);
+ DiagGroupParentMap DGParentMap(Records);
+
+ for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
+ const Record &R = *Diags[i];
+ // Filter by component.
+ if (!Component.empty() && Component != R.getValueAsString("Component"))
+ continue;
+
+ OS << "DIAG(" << R.getName() << ", ";
+ OS << R.getValueAsDef("Class")->getName();
+ OS << ", diag::" << R.getValueAsDef("DefaultMapping")->getName();
+
+ // Description string.
+ OS << ", \"";
+ OS.write_escaped(R.getValueAsString("Text")) << '"';
+
+ // Warning associated with the diagnostic.
+ if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) {
+ OS << ", \"";
+ OS.write_escaped(DI->getDef()->getValueAsString("GroupName")) << '"';
+ } else {
+ OS << ", \"\"";
+ }
+
+ // SFINAE bit
+ if (R.getValueAsBit("SFINAE"))
+ OS << ", true";
+ else
+ OS << ", false";
+
+ // Access control bit
+ if (R.getValueAsBit("AccessControl"))
+ OS << ", true";
+ else
+ OS << ", false";
+
+ // FIXME: This condition is just to avoid temporary revlock, it can be
+ // removed.
+ if (R.getValue("WarningNoWerror")) {
+ // Default warning has no Werror bit.
+ if (R.getValueAsBit("WarningNoWerror"))
+ OS << ", true";
+ else
+ OS << ", false";
+
+ // Default warning show in system header bit.
+ if (R.getValueAsBit("WarningShowInSystemHeader"))
+ OS << ", true";
+ else
+ OS << ", false";
+ }
+
+ // Category number.
+ OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
+
+ // Brief
+ OS << ", \"";
+ OS.write_escaped(R.getValueAsString("Brief")) << '"';
+
+ // Explanation
+ OS << ", \"";
+ OS.write_escaped(R.getValueAsString("Explanation")) << '"';
+ OS << ")\n";
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Warning Group Tables generation
+//===----------------------------------------------------------------------===//
+
+static std::string getDiagCategoryEnum(llvm::StringRef name) {
+ if (name.empty())
+ return "DiagCat_None";
+ llvm::SmallString<256> enumName = llvm::StringRef("DiagCat_");
+ for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
+ enumName += isalnum(*I) ? *I : '_';
+ return enumName.str();
+}
+
+namespace {
+struct GroupInfo {
+ std::vector<const Record*> DiagsInGroup;
+ std::vector<std::string> SubGroups;
+ unsigned IDNo;
+};
+} // end anonymous namespace.
+
+void ClangDiagGroupsEmitter::run(raw_ostream &OS) {
+ // Compute a mapping from a DiagGroup to all of its parents.
+ DiagGroupParentMap DGParentMap(Records);
+
+ // Invert the 1-[0/1] mapping of diags to group into a one to many mapping of
+ // groups to diags in the group.
+ std::map<std::string, GroupInfo> DiagsInGroup;
+
+ std::vector<Record*> Diags =
+ Records.getAllDerivedDefinitions("Diagnostic");
+ for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
+ const Record *R = Diags[i];
+ DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group"));
+ if (DI == 0) continue;
+ std::string GroupName = DI->getDef()->getValueAsString("GroupName");
+ DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
+ }
+
+ // 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).
+ std::vector<Record*> DiagGroups
+ = Records.getAllDerivedDefinitions("DiagGroup");
+ for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
+ Record *Group = DiagGroups[i];
+ GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
+
+ 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"));
+ }
+
+ // Assign unique ID numbers to the groups.
+ unsigned IDNo = 0;
+ for (std::map<std::string, GroupInfo>::iterator
+ I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo)
+ I->second.IDNo = IDNo;
+
+ // Walk through the groups emitting an array for each diagnostic of the diags
+ // that are mapped to.
+ OS << "\n#ifdef GET_DIAG_ARRAYS\n";
+ unsigned MaxLen = 0;
+ for (std::map<std::string, GroupInfo>::iterator
+ I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
+ MaxLen = std::max(MaxLen, (unsigned)I->first.size());
+
+ std::vector<const Record*> &V = I->second.DiagsInGroup;
+ if (!V.empty()) {
+ OS << "static const short DiagArray" << I->second.IDNo << "[] = { ";
+ for (unsigned i = 0, e = V.size(); i != e; ++i)
+ OS << "diag::" << V[i]->getName() << ", ";
+ OS << "-1 };\n";
+ }
+
+ const std::vector<std::string> &SubGroups = I->second.SubGroups;
+ if (!SubGroups.empty()) {
+ OS << "static const short DiagSubGroup" << I->second.IDNo << "[] = { ";
+ for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) {
+ std::map<std::string, GroupInfo>::iterator RI =
+ DiagsInGroup.find(SubGroups[i]);
+ assert(RI != DiagsInGroup.end() && "Referenced without existing?");
+ OS << RI->second.IDNo << ", ";
+ }
+ OS << "-1 };\n";
+ }
+ }
+ OS << "#endif // GET_DIAG_ARRAYS\n\n";
+
+ // Emit the table now.
+ OS << "\n#ifdef GET_DIAG_TABLE\n";
+ for (std::map<std::string, GroupInfo>::iterator
+ I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
+ // Group option string.
+ OS << " { ";
+ OS << I->first.size() << ", ";
+ OS << "\"";
+ OS.write_escaped(I->first) << "\","
+ << std::string(MaxLen-I->first.size()+1, ' ');
+
+ // Diagnostics in the group.
+ if (I->second.DiagsInGroup.empty())
+ OS << "0, ";
+ else
+ OS << "DiagArray" << I->second.IDNo << ", ";
+
+ // Subgroups.
+ if (I->second.SubGroups.empty())
+ OS << 0;
+ else
+ OS << "DiagSubGroup" << I->second.IDNo;
+ OS << " },\n";
+ }
+ OS << "#endif // GET_DIAG_TABLE\n\n";
+
+ // Emit the category table next.
+ DiagCategoryIDMap CategoriesByID(Records);
+ OS << "\n#ifdef GET_CATEGORY_TABLE\n";
+ for (DiagCategoryIDMap::iterator I = CategoriesByID.begin(),
+ E = CategoriesByID.end(); I != E; ++I)
+ OS << "CATEGORY(\"" << *I << "\", " << getDiagCategoryEnum(*I) << ")\n";
+ OS << "#endif // GET_CATEGORY_TABLE\n\n";
+}
+
+//===----------------------------------------------------------------------===//
+// Diagnostic name index generation
+//===----------------------------------------------------------------------===//
+
+namespace {
+struct RecordIndexElement
+{
+ RecordIndexElement() {}
+ explicit RecordIndexElement(Record const &R):
+ Name(R.getName()) {}
+
+ std::string Name;
+};
+
+struct RecordIndexElementSorter :
+ public std::binary_function<RecordIndexElement, RecordIndexElement, bool> {
+
+ bool operator()(RecordIndexElement const &Lhs,
+ RecordIndexElement const &Rhs) const {
+ return Lhs.Name < Rhs.Name;
+ }
+
+};
+
+} // end anonymous namespace.
+
+void ClangDiagsIndexNameEmitter::run(raw_ostream &OS) {
+ const std::vector<Record*> &Diags =
+ Records.getAllDerivedDefinitions("Diagnostic");
+
+ std::vector<RecordIndexElement> Index;
+ Index.reserve(Diags.size());
+ for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
+ const Record &R = *(Diags[i]);
+ Index.push_back(RecordIndexElement(R));
+ }
+
+ std::sort(Index.begin(), Index.end(), RecordIndexElementSorter());
+
+ for (unsigned i = 0, e = Index.size(); i != e; ++i) {
+ const RecordIndexElement &R = Index[i];
+
+ OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
+ }
+}
diff --git a/utils/TableGen/ClangDiagnosticsEmitter.h b/utils/TableGen/ClangDiagnosticsEmitter.h
new file mode 100644
index 000000000000..73d3c4dc0e97
--- /dev/null
+++ b/utils/TableGen/ClangDiagnosticsEmitter.h
@@ -0,0 +1,54 @@
+//===- ClangDiagnosticsEmitter.h - Generate Clang diagnostics tables -*- C++ -*-
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These tablegen backends emit Clang diagnostics tables.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANGDIAGS_EMITTER_H
+#define CLANGDIAGS_EMITTER_H
+
+#include "llvm/TableGen/TableGenBackend.h"
+
+namespace llvm {
+
+/// ClangDiagsDefsEmitter - The top-level class emits .def files containing
+/// declarations of Clang diagnostics.
+///
+class ClangDiagsDefsEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+ const std::string& Component;
+public:
+ explicit ClangDiagsDefsEmitter(RecordKeeper &R, const std::string& component)
+ : Records(R), Component(component) {}
+
+ // run - Output the .def file contents
+ void run(raw_ostream &OS);
+};
+
+class ClangDiagGroupsEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+public:
+ explicit ClangDiagGroupsEmitter(RecordKeeper &R) : Records(R) {}
+
+ void run(raw_ostream &OS);
+};
+
+class ClangDiagsIndexNameEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+public:
+ explicit ClangDiagsIndexNameEmitter(RecordKeeper &R) : Records(R) {}
+
+ void run(raw_ostream &OS);
+};
+
+
+} // End llvm namespace
+
+#endif
diff --git a/utils/TableGen/ClangSACheckersEmitter.cpp b/utils/TableGen/ClangSACheckersEmitter.cpp
new file mode 100644
index 000000000000..423b68a64842
--- /dev/null
+++ b/utils/TableGen/ClangSACheckersEmitter.cpp
@@ -0,0 +1,319 @@
+//=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers tables -*- C++ -*-
+//
+// 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 Clang Static Analyzer checkers tables.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckersEmitter.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/ADT/DenseSet.h"
+#include <map>
+#include <string>
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+// Static Analyzer Checkers Tables generation
+//===----------------------------------------------------------------------===//
+
+/// \brief True if it is specified hidden or a parent package is specified
+/// as hidden, otherwise false.
+static bool isHidden(const Record &R) {
+ if (R.getValueAsBit("Hidden"))
+ return true;
+ // Not declared as hidden, check the parent package if it is hidden.
+ if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("ParentPackage")))
+ return isHidden(*DI->getDef());
+
+ return false;
+}
+
+static bool isCheckerNamed(const Record *R) {
+ return !R->getValueAsString("CheckerName").empty();
+}
+
+static std::string getPackageFullName(const Record *R);
+
+static std::string getParentPackageFullName(const Record *R) {
+ std::string name;
+ if (DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("ParentPackage")))
+ name = getPackageFullName(DI->getDef());
+ return name;
+}
+
+static std::string getPackageFullName(const Record *R) {
+ std::string name = getParentPackageFullName(R);
+ if (!name.empty()) name += ".";
+ return name + R->getValueAsString("PackageName");
+}
+
+static std::string getCheckerFullName(const Record *R) {
+ std::string name = getParentPackageFullName(R);
+ if (isCheckerNamed(R)) {
+ if (!name.empty()) name += ".";
+ name += R->getValueAsString("CheckerName");
+ }
+ return name;
+}
+
+static std::string getStringValue(const Record &R, StringRef field) {
+ if (StringInit *
+ SI = dynamic_cast<StringInit*>(R.getValueInit(field)))
+ return SI->getValue();
+ return std::string();
+}
+
+namespace {
+struct GroupInfo {
+ llvm::DenseSet<const Record*> Checkers;
+ llvm::DenseSet<const Record *> SubGroups;
+ bool Hidden;
+ unsigned Index;
+
+ GroupInfo() : Hidden(false) { }
+};
+}
+
+static void addPackageToCheckerGroup(const Record *package, const Record *group,
+ llvm::DenseMap<const Record *, GroupInfo *> &recordGroupMap) {
+ llvm::DenseSet<const Record *> &checkers = recordGroupMap[package]->Checkers;
+ for (llvm::DenseSet<const Record *>::iterator
+ I = checkers.begin(), E = checkers.end(); I != E; ++I)
+ recordGroupMap[group]->Checkers.insert(*I);
+
+ llvm::DenseSet<const Record *> &subGroups = recordGroupMap[package]->SubGroups;
+ for (llvm::DenseSet<const Record *>::iterator
+ I = subGroups.begin(), E = subGroups.end(); I != E; ++I)
+ addPackageToCheckerGroup(*I, group, recordGroupMap);
+}
+
+void ClangSACheckersEmitter::run(raw_ostream &OS) {
+ std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker");
+ llvm::DenseMap<const Record *, unsigned> checkerRecIndexMap;
+ for (unsigned i = 0, e = checkers.size(); i != e; ++i)
+ checkerRecIndexMap[checkers[i]] = i;
+
+ // Invert the mapping of checkers to package/group into a one to many
+ // mapping of packages/groups to checkers.
+ std::map<std::string, GroupInfo> groupInfoByName;
+ llvm::DenseMap<const Record *, GroupInfo *> recordGroupMap;
+
+ std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package");
+ for (unsigned i = 0, e = packages.size(); i != e; ++i) {
+ Record *R = packages[i];
+ std::string fullName = getPackageFullName(R);
+ if (!fullName.empty()) {
+ GroupInfo &info = groupInfoByName[fullName];
+ info.Hidden = isHidden(*R);
+ recordGroupMap[R] = &info;
+ }
+ }
+
+ std::vector<Record*>
+ checkerGroups = Records.getAllDerivedDefinitions("CheckerGroup");
+ for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i) {
+ Record *R = checkerGroups[i];
+ std::string name = R->getValueAsString("GroupName");
+ if (!name.empty()) {
+ GroupInfo &info = groupInfoByName[name];
+ recordGroupMap[R] = &info;
+ }
+ }
+
+ for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
+ Record *R = checkers[i];
+ Record *package = 0;
+ if (DefInit *
+ DI = dynamic_cast<DefInit*>(R->getValueInit("ParentPackage")))
+ package = DI->getDef();
+ if (!isCheckerNamed(R) && !package)
+ throw "Checker '" + R->getName() + "' is neither named, nor in a package!";
+
+ if (isCheckerNamed(R)) {
+ // Create a pseudo-group to hold this checker.
+ std::string fullName = getCheckerFullName(R);
+ GroupInfo &info = groupInfoByName[fullName];
+ info.Hidden = R->getValueAsBit("Hidden");
+ recordGroupMap[R] = &info;
+ info.Checkers.insert(R);
+ } else {
+ recordGroupMap[package]->Checkers.insert(R);
+ }
+
+ Record *currR = isCheckerNamed(R) ? R : package;
+ // Insert the checker and its parent packages into the subgroups set of
+ // the corresponding parent package.
+ while (DefInit *DI
+ = dynamic_cast<DefInit*>(currR->getValueInit("ParentPackage"))) {
+ Record *parentPackage = DI->getDef();
+ recordGroupMap[parentPackage]->SubGroups.insert(currR);
+ currR = parentPackage;
+ }
+ // Insert the checker into the set of its group.
+ if (DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group")))
+ recordGroupMap[DI->getDef()]->Checkers.insert(R);
+ }
+
+ // If a package is in group, add all its checkers and its sub-packages
+ // checkers into the group.
+ for (unsigned i = 0, e = packages.size(); i != e; ++i)
+ if (DefInit *DI = dynamic_cast<DefInit*>(packages[i]->getValueInit("Group")))
+ addPackageToCheckerGroup(packages[i], DI->getDef(), recordGroupMap);
+
+ typedef std::map<std::string, const Record *> SortedRecords;
+ typedef llvm::DenseMap<const Record *, unsigned> RecToSortIndex;
+
+ SortedRecords sortedGroups;
+ RecToSortIndex groupToSortIndex;
+ OS << "\n#ifdef GET_GROUPS\n";
+ {
+ for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i)
+ sortedGroups[checkerGroups[i]->getValueAsString("GroupName")]
+ = checkerGroups[i];
+
+ unsigned sortIndex = 0;
+ for (SortedRecords::iterator
+ I = sortedGroups.begin(), E = sortedGroups.end(); I != E; ++I) {
+ const Record *R = I->second;
+
+ OS << "GROUP(" << "\"";
+ OS.write_escaped(R->getValueAsString("GroupName")) << "\"";
+ OS << ")\n";
+
+ groupToSortIndex[R] = sortIndex++;
+ }
+ }
+ OS << "#endif // GET_GROUPS\n\n";
+
+ OS << "\n#ifdef GET_PACKAGES\n";
+ {
+ SortedRecords sortedPackages;
+ for (unsigned i = 0, e = packages.size(); i != e; ++i)
+ sortedPackages[getPackageFullName(packages[i])] = packages[i];
+
+ for (SortedRecords::iterator
+ I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) {
+ const Record &R = *I->second;
+
+ OS << "PACKAGE(" << "\"";
+ OS.write_escaped(getPackageFullName(&R)) << "\", ";
+ // Group index
+ if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group")))
+ OS << groupToSortIndex[DI->getDef()] << ", ";
+ else
+ OS << "-1, ";
+ // Hidden bit
+ if (isHidden(R))
+ OS << "true";
+ else
+ OS << "false";
+ OS << ")\n";
+ }
+ }
+ OS << "#endif // GET_PACKAGES\n\n";
+
+ OS << "\n#ifdef GET_CHECKERS\n";
+ for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
+ const Record &R = *checkers[i];
+
+ OS << "CHECKER(" << "\"";
+ std::string name;
+ if (isCheckerNamed(&R))
+ name = getCheckerFullName(&R);
+ OS.write_escaped(name) << "\", ";
+ OS << R.getName() << ", ";
+ OS << getStringValue(R, "DescFile") << ", ";
+ OS << "\"";
+ OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
+ // Group index
+ if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group")))
+ OS << groupToSortIndex[DI->getDef()] << ", ";
+ else
+ OS << "-1, ";
+ // Hidden bit
+ if (isHidden(R))
+ OS << "true";
+ else
+ OS << "false";
+ OS << ")\n";
+ }
+ OS << "#endif // GET_CHECKERS\n\n";
+
+ unsigned index = 0;
+ for (std::map<std::string, GroupInfo>::iterator
+ I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I)
+ I->second.Index = index++;
+
+ // Walk through the packages/groups/checkers emitting an array for each
+ // set of checkers and an array for each set of subpackages.
+
+ OS << "\n#ifdef GET_MEMBER_ARRAYS\n";
+ unsigned maxLen = 0;
+ for (std::map<std::string, GroupInfo>::iterator
+ I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) {
+ maxLen = std::max(maxLen, (unsigned)I->first.size());
+
+ llvm::DenseSet<const Record *> &checkers = I->second.Checkers;
+ if (!checkers.empty()) {
+ OS << "static const short CheckerArray" << I->second.Index << "[] = { ";
+ // Make the output order deterministic.
+ std::map<int, const Record *> sorted;
+ for (llvm::DenseSet<const Record *>::iterator
+ I = checkers.begin(), E = checkers.end(); I != E; ++I)
+ sorted[(*I)->getID()] = *I;
+
+ for (std::map<int, const Record *>::iterator
+ I = sorted.begin(), E = sorted.end(); I != E; ++I)
+ OS << checkerRecIndexMap[I->second] << ", ";
+ OS << "-1 };\n";
+ }
+
+ llvm::DenseSet<const Record *> &subGroups = I->second.SubGroups;
+ if (!subGroups.empty()) {
+ OS << "static const short SubPackageArray" << I->second.Index << "[] = { ";
+ // Make the output order deterministic.
+ std::map<int, const Record *> sorted;
+ for (llvm::DenseSet<const Record *>::iterator
+ I = subGroups.begin(), E = subGroups.end(); I != E; ++I)
+ sorted[(*I)->getID()] = *I;
+
+ for (std::map<int, const Record *>::iterator
+ I = sorted.begin(), E = sorted.end(); I != E; ++I) {
+ OS << recordGroupMap[I->second]->Index << ", ";
+ }
+ OS << "-1 };\n";
+ }
+ }
+ OS << "#endif // GET_MEMBER_ARRAYS\n\n";
+
+ OS << "\n#ifdef GET_CHECKNAME_TABLE\n";
+ for (std::map<std::string, GroupInfo>::iterator
+ I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) {
+ // Group option string.
+ OS << " { \"";
+ OS.write_escaped(I->first) << "\","
+ << std::string(maxLen-I->first.size()+1, ' ');
+
+ if (I->second.Checkers.empty())
+ OS << "0, ";
+ else
+ OS << "CheckerArray" << I->second.Index << ", ";
+
+ // Subgroups.
+ if (I->second.SubGroups.empty())
+ OS << "0, ";
+ else
+ OS << "SubPackageArray" << I->second.Index << ", ";
+
+ OS << (I->second.Hidden ? "true" : "false");
+
+ OS << " },\n";
+ }
+ OS << "#endif // GET_CHECKNAME_TABLE\n\n";
+}
diff --git a/utils/TableGen/ClangSACheckersEmitter.h b/utils/TableGen/ClangSACheckersEmitter.h
new file mode 100644
index 000000000000..5a0e14811124
--- /dev/null
+++ b/utils/TableGen/ClangSACheckersEmitter.h
@@ -0,0 +1,31 @@
+//===- ClangSACheckersEmitter.h - Generate Clang SA checkers tables -*- C++ -*-
+//
+// 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 Clang Static Analyzer checkers tables.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANGSACHECKERS_EMITTER_H
+#define CLANGSACHECKERS_EMITTER_H
+
+#include "llvm/TableGen/TableGenBackend.h"
+
+namespace llvm {
+
+class ClangSACheckersEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+public:
+ explicit ClangSACheckersEmitter(RecordKeeper &R) : Records(R) {}
+
+ void run(raw_ostream &OS);
+};
+
+} // End llvm namespace
+
+#endif
diff --git a/utils/TableGen/Makefile b/utils/TableGen/Makefile
new file mode 100644
index 000000000000..9790efc061ef
--- /dev/null
+++ b/utils/TableGen/Makefile
@@ -0,0 +1,19 @@
+##===- utils/TableGen/Makefile -----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../../..
+TOOLNAME = clang-tblgen
+USEDLIBS = LLVMTableGen.a LLVMSupport.a
+REQUIRES_EH := 1
+REQUIRES_RTTI := 1
+
+# This tool has no plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+include $(LEVEL)/Makefile.common
diff --git a/utils/TableGen/NeonEmitter.cpp b/utils/TableGen/NeonEmitter.cpp
new file mode 100644
index 000000000000..66845ccacb32
--- /dev/null
+++ b/utils/TableGen/NeonEmitter.cpp
@@ -0,0 +1,1551 @@
+//===- NeonEmitter.cpp - Generate arm_neon.h for use with clang -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend is responsible for emitting arm_neon.h, which includes
+// a declaration and definition of each function specified by the ARM NEON
+// compiler interface. See ARM document DUI0348B.
+//
+// Each NEON instruction is implemented in terms of 1 or more functions which
+// are suffixed with the element type of the input vectors. Functions may be
+// implemented in terms of generic vector operations such as +, *, -, etc. or
+// by calling a __builtin_-prefixed function which will be handled by clang's
+// CodeGen library.
+//
+// Additional validation code can be generated by this file when runHeader() is
+// called, rather than the normal run() entry point. A complete set of tests
+// for Neon intrinsics can be generated by calling the runTests() entry point.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NeonEmitter.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include <string>
+
+using namespace llvm;
+
+/// ParseTypes - break down a string such as "fQf" into a vector of StringRefs,
+/// which each StringRef representing a single type declared in the string.
+/// for "fQf" we would end up with 2 StringRefs, "f", and "Qf", representing
+/// 2xfloat and 4xfloat respectively.
+static void ParseTypes(Record *r, std::string &s,
+ SmallVectorImpl<StringRef> &TV) {
+ const char *data = s.data();
+ int len = 0;
+
+ for (unsigned i = 0, e = s.size(); i != e; ++i, ++len) {
+ if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U')
+ continue;
+
+ switch (data[len]) {
+ case 'c':
+ case 's':
+ case 'i':
+ case 'l':
+ case 'h':
+ case 'f':
+ break;
+ default:
+ throw TGError(r->getLoc(),
+ "Unexpected letter: " + std::string(data + len, 1));
+ break;
+ }
+ TV.push_back(StringRef(data, len + 1));
+ data += len + 1;
+ len = -1;
+ }
+}
+
+/// Widen - Convert a type code into the next wider type. char -> short,
+/// short -> int, etc.
+static char Widen(const char t) {
+ switch (t) {
+ case 'c':
+ return 's';
+ case 's':
+ return 'i';
+ case 'i':
+ return 'l';
+ case 'h':
+ return 'f';
+ default: throw "unhandled type in widen!";
+ }
+ return '\0';
+}
+
+/// Narrow - Convert a type code into the next smaller type. short -> char,
+/// float -> half float, etc.
+static char Narrow(const char t) {
+ switch (t) {
+ case 's':
+ return 'c';
+ case 'i':
+ return 's';
+ case 'l':
+ return 'i';
+ case 'f':
+ return 'h';
+ default: throw "unhandled type in narrow!";
+ }
+ return '\0';
+}
+
+/// For a particular StringRef, return the base type code, and whether it has
+/// the quad-vector, polynomial, or unsigned modifiers set.
+static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) {
+ unsigned off = 0;
+
+ // remember quad.
+ if (ty[off] == 'Q') {
+ quad = true;
+ ++off;
+ }
+
+ // remember poly.
+ if (ty[off] == 'P') {
+ poly = true;
+ ++off;
+ }
+
+ // remember unsigned.
+ if (ty[off] == 'U') {
+ usgn = true;
+ ++off;
+ }
+
+ // base type to get the type string for.
+ return ty[off];
+}
+
+/// ModType - Transform a type code and its modifiers based on a mod code. The
+/// mod code definitions may be found at the top of arm_neon.td.
+static char ModType(const char mod, char type, bool &quad, bool &poly,
+ bool &usgn, bool &scal, bool &cnst, bool &pntr) {
+ switch (mod) {
+ case 't':
+ if (poly) {
+ poly = false;
+ usgn = true;
+ }
+ break;
+ case 'u':
+ usgn = true;
+ poly = false;
+ if (type == 'f')
+ type = 'i';
+ break;
+ case 'x':
+ usgn = false;
+ poly = false;
+ if (type == 'f')
+ type = 'i';
+ break;
+ case 'f':
+ if (type == 'h')
+ quad = true;
+ type = 'f';
+ usgn = false;
+ break;
+ case 'g':
+ quad = false;
+ break;
+ case 'w':
+ type = Widen(type);
+ quad = true;
+ break;
+ case 'n':
+ type = Widen(type);
+ break;
+ case 'i':
+ type = 'i';
+ scal = true;
+ break;
+ case 'l':
+ type = 'l';
+ scal = true;
+ usgn = true;
+ break;
+ case 's':
+ case 'a':
+ scal = true;
+ break;
+ case 'k':
+ quad = true;
+ break;
+ case 'c':
+ cnst = true;
+ case 'p':
+ pntr = true;
+ scal = true;
+ break;
+ case 'h':
+ type = Narrow(type);
+ if (type == 'h')
+ quad = false;
+ break;
+ case 'e':
+ type = Narrow(type);
+ usgn = true;
+ break;
+ default:
+ break;
+ }
+ return type;
+}
+
+/// TypeString - for a modifier and type, generate the name of the typedef for
+/// that type. QUc -> uint8x8_t.
+static std::string TypeString(const char mod, StringRef typestr) {
+ bool quad = false;
+ bool poly = false;
+ bool usgn = false;
+ bool scal = false;
+ bool cnst = false;
+ bool pntr = false;
+
+ if (mod == 'v')
+ return "void";
+ if (mod == 'i')
+ return "int";
+
+ // base type to get the type string for.
+ char type = ClassifyType(typestr, quad, poly, usgn);
+
+ // Based on the modifying character, change the type and width if necessary.
+ type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
+
+ SmallString<128> s;
+
+ if (usgn)
+ s.push_back('u');
+
+ switch (type) {
+ case 'c':
+ s += poly ? "poly8" : "int8";
+ if (scal)
+ break;
+ s += quad ? "x16" : "x8";
+ break;
+ case 's':
+ s += poly ? "poly16" : "int16";
+ if (scal)
+ break;
+ s += quad ? "x8" : "x4";
+ break;
+ case 'i':
+ s += "int32";
+ if (scal)
+ break;
+ s += quad ? "x4" : "x2";
+ break;
+ case 'l':
+ s += "int64";
+ if (scal)
+ break;
+ s += quad ? "x2" : "x1";
+ break;
+ case 'h':
+ s += "float16";
+ if (scal)
+ break;
+ s += quad ? "x8" : "x4";
+ break;
+ case 'f':
+ s += "float32";
+ if (scal)
+ break;
+ s += quad ? "x4" : "x2";
+ break;
+ default:
+ throw "unhandled type!";
+ break;
+ }
+
+ if (mod == '2')
+ s += "x2";
+ if (mod == '3')
+ s += "x3";
+ if (mod == '4')
+ s += "x4";
+
+ // Append _t, finishing the type string typedef type.
+ s += "_t";
+
+ if (cnst)
+ s += " const";
+
+ if (pntr)
+ s += " *";
+
+ return s.str();
+}
+
+/// BuiltinTypeString - for a modifier and type, generate the clang
+/// BuiltinsARM.def prototype code for the function. See the top of clang's
+/// Builtins.def for a description of the type strings.
+static std::string BuiltinTypeString(const char mod, StringRef typestr,
+ ClassKind ck, bool ret) {
+ bool quad = false;
+ bool poly = false;
+ bool usgn = false;
+ bool scal = false;
+ bool cnst = false;
+ bool pntr = false;
+
+ if (mod == 'v')
+ return "v"; // void
+ if (mod == 'i')
+ return "i"; // int
+
+ // base type to get the type string for.
+ char type = ClassifyType(typestr, quad, poly, usgn);
+
+ // Based on the modifying character, change the type and width if necessary.
+ type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
+
+ // All pointers are void* pointers. Change type to 'v' now.
+ if (pntr) {
+ usgn = false;
+ poly = false;
+ type = 'v';
+ }
+ // Treat half-float ('h') types as unsigned short ('s') types.
+ if (type == 'h') {
+ type = 's';
+ usgn = true;
+ }
+ usgn = usgn | poly | ((ck == ClassI || ck == ClassW) && scal && type != 'f');
+
+ if (scal) {
+ SmallString<128> s;
+
+ if (usgn)
+ s.push_back('U');
+ else if (type == 'c')
+ s.push_back('S'); // make chars explicitly signed
+
+ if (type == 'l') // 64-bit long
+ s += "LLi";
+ else
+ s.push_back(type);
+
+ if (cnst)
+ s.push_back('C');
+ if (pntr)
+ s.push_back('*');
+ return s.str();
+ }
+
+ // Since the return value must be one type, return a vector type of the
+ // appropriate width which we will bitcast. An exception is made for
+ // returning structs of 2, 3, or 4 vectors which are returned in a sret-like
+ // fashion, storing them to a pointer arg.
+ if (ret) {
+ if (mod >= '2' && mod <= '4')
+ return "vv*"; // void result with void* first argument
+ if (mod == 'f' || (ck != ClassB && type == 'f'))
+ return quad ? "V4f" : "V2f";
+ if (ck != ClassB && type == 's')
+ return quad ? "V8s" : "V4s";
+ if (ck != ClassB && type == 'i')
+ return quad ? "V4i" : "V2i";
+ if (ck != ClassB && type == 'l')
+ return quad ? "V2LLi" : "V1LLi";
+
+ return quad ? "V16Sc" : "V8Sc";
+ }
+
+ // Non-return array types are passed as individual vectors.
+ if (mod == '2')
+ return quad ? "V16ScV16Sc" : "V8ScV8Sc";
+ if (mod == '3')
+ return quad ? "V16ScV16ScV16Sc" : "V8ScV8ScV8Sc";
+ if (mod == '4')
+ return quad ? "V16ScV16ScV16ScV16Sc" : "V8ScV8ScV8ScV8Sc";
+
+ if (mod == 'f' || (ck != ClassB && type == 'f'))
+ return quad ? "V4f" : "V2f";
+ if (ck != ClassB && type == 's')
+ return quad ? "V8s" : "V4s";
+ if (ck != ClassB && type == 'i')
+ return quad ? "V4i" : "V2i";
+ if (ck != ClassB && type == 'l')
+ return quad ? "V2LLi" : "V1LLi";
+
+ return quad ? "V16Sc" : "V8Sc";
+}
+
+/// MangleName - Append a type or width suffix to a base neon function name,
+/// and insert a 'q' in the appropriate location if the operation works on
+/// 128b rather than 64b. E.g. turn "vst2_lane" into "vst2q_lane_f32", etc.
+static std::string MangleName(const std::string &name, StringRef typestr,
+ ClassKind ck) {
+ if (name == "vcvt_f32_f16")
+ return name;
+
+ bool quad = false;
+ bool poly = false;
+ bool usgn = false;
+ char type = ClassifyType(typestr, quad, poly, usgn);
+
+ std::string s = name;
+
+ switch (type) {
+ case 'c':
+ switch (ck) {
+ case ClassS: s += poly ? "_p8" : usgn ? "_u8" : "_s8"; break;
+ case ClassI: s += "_i8"; break;
+ case ClassW: s += "_8"; break;
+ default: break;
+ }
+ break;
+ case 's':
+ switch (ck) {
+ case ClassS: s += poly ? "_p16" : usgn ? "_u16" : "_s16"; break;
+ case ClassI: s += "_i16"; break;
+ case ClassW: s += "_16"; break;
+ default: break;
+ }
+ break;
+ case 'i':
+ switch (ck) {
+ case ClassS: s += usgn ? "_u32" : "_s32"; break;
+ case ClassI: s += "_i32"; break;
+ case ClassW: s += "_32"; break;
+ default: break;
+ }
+ break;
+ case 'l':
+ switch (ck) {
+ case ClassS: s += usgn ? "_u64" : "_s64"; break;
+ case ClassI: s += "_i64"; break;
+ case ClassW: s += "_64"; break;
+ default: break;
+ }
+ break;
+ case 'h':
+ switch (ck) {
+ case ClassS:
+ case ClassI: s += "_f16"; break;
+ case ClassW: s += "_16"; break;
+ default: break;
+ }
+ break;
+ case 'f':
+ switch (ck) {
+ case ClassS:
+ case ClassI: s += "_f32"; break;
+ case ClassW: s += "_32"; break;
+ default: break;
+ }
+ break;
+ default:
+ throw "unhandled type!";
+ break;
+ }
+ if (ck == ClassB)
+ s += "_v";
+
+ // Insert a 'q' before the first '_' character so that it ends up before
+ // _lane or _n on vector-scalar operations.
+ if (quad) {
+ size_t pos = s.find('_');
+ s = s.insert(pos, "q");
+ }
+ return s;
+}
+
+/// UseMacro - Examine the prototype string to determine if the intrinsic
+/// should be defined as a preprocessor macro instead of an inline function.
+static bool UseMacro(const std::string &proto) {
+ // If this builtin takes an immediate argument, we need to #define it rather
+ // than use a standard declaration, so that SemaChecking can range check
+ // the immediate passed by the user.
+ if (proto.find('i') != std::string::npos)
+ return true;
+
+ // Pointer arguments need to use macros to avoid hiding aligned attributes
+ // from the pointer type.
+ if (proto.find('p') != std::string::npos ||
+ proto.find('c') != std::string::npos)
+ return true;
+
+ return false;
+}
+
+/// MacroArgUsedDirectly - Return true if argument i for an intrinsic that is
+/// defined as a macro should be accessed directly instead of being first
+/// assigned to a local temporary.
+static bool MacroArgUsedDirectly(const std::string &proto, unsigned i) {
+ // True for constant ints (i), pointers (p) and const pointers (c).
+ return (proto[i] == 'i' || proto[i] == 'p' || proto[i] == 'c');
+}
+
+// Generate the string "(argtype a, argtype b, ...)"
+static std::string GenArgs(const std::string &proto, StringRef typestr) {
+ bool define = UseMacro(proto);
+ char arg = 'a';
+
+ std::string s;
+ s += "(";
+
+ for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
+ if (define) {
+ // Some macro arguments are used directly instead of being assigned
+ // to local temporaries; prepend an underscore prefix to make their
+ // names consistent with the local temporaries.
+ if (MacroArgUsedDirectly(proto, i))
+ s += "__";
+ } else {
+ s += TypeString(proto[i], typestr) + " __";
+ }
+ s.push_back(arg);
+ if ((i + 1) < e)
+ s += ", ";
+ }
+
+ s += ")";
+ return s;
+}
+
+// Macro arguments are not type-checked like inline function arguments, so
+// assign them to local temporaries to get the right type checking.
+static std::string GenMacroLocals(const std::string &proto, StringRef typestr) {
+ char arg = 'a';
+ std::string s;
+ bool generatedLocal = false;
+
+ for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
+ // Do not create a temporary for an immediate argument.
+ // That would defeat the whole point of using a macro!
+ // FIXME: For other (non-immediate) arguments that are used directly, a
+ // local temporary (or some other method) is still needed to get the
+ // correct type checking, even if that temporary is not used for anything.
+ // This is omitted for now because it turns out the the use of
+ // "__extension__" in the macro disables any warnings from the pointer
+ // assignment.
+ if (MacroArgUsedDirectly(proto, i))
+ continue;
+ generatedLocal = true;
+
+ s += TypeString(proto[i], typestr) + " __";
+ s.push_back(arg);
+ s += " = (";
+ s.push_back(arg);
+ s += "); ";
+ }
+
+ if (generatedLocal)
+ s += "\\\n ";
+ return s;
+}
+
+// Use the vmovl builtin to sign-extend or zero-extend a vector.
+static std::string Extend(StringRef typestr, const std::string &a) {
+ std::string s;
+ s = MangleName("vmovl", typestr, ClassS);
+ s += "(" + a + ")";
+ return s;
+}
+
+static std::string Duplicate(unsigned nElts, StringRef typestr,
+ const std::string &a) {
+ std::string s;
+
+ s = "(" + TypeString('d', typestr) + "){ ";
+ for (unsigned i = 0; i != nElts; ++i) {
+ s += a;
+ if ((i + 1) < nElts)
+ s += ", ";
+ }
+ s += " }";
+
+ return s;
+}
+
+static std::string SplatLane(unsigned nElts, const std::string &vec,
+ const std::string &lane) {
+ std::string s = "__builtin_shufflevector(" + vec + ", " + vec;
+ for (unsigned i = 0; i < nElts; ++i)
+ s += ", " + lane;
+ s += ")";
+ return s;
+}
+
+static unsigned GetNumElements(StringRef typestr, bool &quad) {
+ quad = false;
+ bool dummy = false;
+ char type = ClassifyType(typestr, quad, dummy, dummy);
+ unsigned nElts = 0;
+ switch (type) {
+ case 'c': nElts = 8; break;
+ case 's': nElts = 4; break;
+ case 'i': nElts = 2; break;
+ case 'l': nElts = 1; break;
+ case 'h': nElts = 4; break;
+ case 'f': nElts = 2; break;
+ default:
+ throw "unhandled type!";
+ break;
+ }
+ if (quad) nElts <<= 1;
+ return nElts;
+}
+
+// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd.
+static std::string GenOpString(OpKind op, const std::string &proto,
+ StringRef typestr) {
+ bool quad;
+ unsigned nElts = GetNumElements(typestr, quad);
+ bool define = UseMacro(proto);
+
+ std::string ts = TypeString(proto[0], typestr);
+ std::string s;
+ if (!define) {
+ s = "return ";
+ }
+
+ switch(op) {
+ case OpAdd:
+ s += "__a + __b;";
+ break;
+ case OpAddl:
+ s += Extend(typestr, "__a") + " + " + Extend(typestr, "__b") + ";";
+ break;
+ case OpAddw:
+ s += "__a + " + Extend(typestr, "__b") + ";";
+ break;
+ case OpSub:
+ s += "__a - __b;";
+ break;
+ case OpSubl:
+ s += Extend(typestr, "__a") + " - " + Extend(typestr, "__b") + ";";
+ break;
+ case OpSubw:
+ s += "__a - " + Extend(typestr, "__b") + ";";
+ break;
+ case OpMulN:
+ s += "__a * " + Duplicate(nElts, typestr, "__b") + ";";
+ break;
+ case OpMulLane:
+ s += "__a * " + SplatLane(nElts, "__b", "__c") + ";";
+ break;
+ case OpMul:
+ s += "__a * __b;";
+ break;
+ case OpMullLane:
+ s += MangleName("vmull", typestr, ClassS) + "(__a, " +
+ SplatLane(nElts, "__b", "__c") + ");";
+ break;
+ case OpMlaN:
+ s += "__a + (__b * " + Duplicate(nElts, typestr, "__c") + ");";
+ break;
+ case OpMlaLane:
+ s += "__a + (__b * " + SplatLane(nElts, "__c", "__d") + ");";
+ break;
+ case OpMla:
+ s += "__a + (__b * __c);";
+ break;
+ case OpMlalN:
+ s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " +
+ Duplicate(nElts, typestr, "__c") + ");";
+ break;
+ case OpMlalLane:
+ s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " +
+ SplatLane(nElts, "__c", "__d") + ");";
+ break;
+ case OpMlal:
+ s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
+ break;
+ case OpMlsN:
+ s += "__a - (__b * " + Duplicate(nElts, typestr, "__c") + ");";
+ break;
+ case OpMlsLane:
+ s += "__a - (__b * " + SplatLane(nElts, "__c", "__d") + ");";
+ break;
+ case OpMls:
+ s += "__a - (__b * __c);";
+ break;
+ case OpMlslN:
+ s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " +
+ Duplicate(nElts, typestr, "__c") + ");";
+ break;
+ case OpMlslLane:
+ s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " +
+ SplatLane(nElts, "__c", "__d") + ");";
+ break;
+ case OpMlsl:
+ s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
+ break;
+ case OpQDMullLane:
+ s += MangleName("vqdmull", typestr, ClassS) + "(__a, " +
+ SplatLane(nElts, "__b", "__c") + ");";
+ break;
+ case OpQDMlalLane:
+ s += MangleName("vqdmlal", typestr, ClassS) + "(__a, __b, " +
+ SplatLane(nElts, "__c", "__d") + ");";
+ break;
+ case OpQDMlslLane:
+ s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, __b, " +
+ SplatLane(nElts, "__c", "__d") + ");";
+ break;
+ case OpQDMulhLane:
+ s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " +
+ SplatLane(nElts, "__b", "__c") + ");";
+ break;
+ case OpQRDMulhLane:
+ s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " +
+ SplatLane(nElts, "__b", "__c") + ");";
+ break;
+ case OpEq:
+ s += "(" + ts + ")(__a == __b);";
+ break;
+ case OpGe:
+ s += "(" + ts + ")(__a >= __b);";
+ break;
+ case OpLe:
+ s += "(" + ts + ")(__a <= __b);";
+ break;
+ case OpGt:
+ s += "(" + ts + ")(__a > __b);";
+ break;
+ case OpLt:
+ s += "(" + ts + ")(__a < __b);";
+ break;
+ case OpNeg:
+ s += " -__a;";
+ break;
+ case OpNot:
+ s += " ~__a;";
+ break;
+ case OpAnd:
+ s += "__a & __b;";
+ break;
+ case OpOr:
+ s += "__a | __b;";
+ break;
+ case OpXor:
+ s += "__a ^ __b;";
+ break;
+ case OpAndNot:
+ s += "__a & ~__b;";
+ break;
+ case OpOrNot:
+ s += "__a | ~__b;";
+ break;
+ case OpCast:
+ s += "(" + ts + ")__a;";
+ break;
+ case OpConcat:
+ s += "(" + ts + ")__builtin_shufflevector((int64x1_t)__a";
+ s += ", (int64x1_t)__b, 0, 1);";
+ break;
+ case OpHi:
+ s += "(" + ts +
+ ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 1);";
+ break;
+ case OpLo:
+ s += "(" + ts +
+ ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 0);";
+ break;
+ case OpDup:
+ s += Duplicate(nElts, typestr, "__a") + ";";
+ break;
+ case OpDupLane:
+ s += SplatLane(nElts, "__a", "__b") + ";";
+ break;
+ case OpSelect:
+ // ((0 & 1) | (~0 & 2))
+ s += "(" + ts + ")";
+ ts = TypeString(proto[1], typestr);
+ s += "((__a & (" + ts + ")__b) | ";
+ s += "(~__a & (" + ts + ")__c));";
+ break;
+ case OpRev16:
+ s += "__builtin_shufflevector(__a, __a";
+ for (unsigned i = 2; i <= nElts; i += 2)
+ for (unsigned j = 0; j != 2; ++j)
+ s += ", " + utostr(i - j - 1);
+ s += ");";
+ break;
+ case OpRev32: {
+ unsigned WordElts = nElts >> (1 + (int)quad);
+ s += "__builtin_shufflevector(__a, __a";
+ for (unsigned i = WordElts; i <= nElts; i += WordElts)
+ for (unsigned j = 0; j != WordElts; ++j)
+ s += ", " + utostr(i - j - 1);
+ s += ");";
+ break;
+ }
+ case OpRev64: {
+ unsigned DblWordElts = nElts >> (int)quad;
+ s += "__builtin_shufflevector(__a, __a";
+ for (unsigned i = DblWordElts; i <= nElts; i += DblWordElts)
+ for (unsigned j = 0; j != DblWordElts; ++j)
+ s += ", " + utostr(i - j - 1);
+ s += ");";
+ break;
+ }
+ case OpAbdl: {
+ std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)";
+ if (typestr[0] != 'U') {
+ // vabd results are always unsigned and must be zero-extended.
+ std::string utype = "U" + typestr.str();
+ s += "(" + TypeString(proto[0], typestr) + ")";
+ abd = "(" + TypeString('d', utype) + ")" + abd;
+ s += Extend(utype, abd) + ";";
+ } else {
+ s += Extend(typestr, abd) + ";";
+ }
+ break;
+ }
+ case OpAba:
+ s += "__a + " + MangleName("vabd", typestr, ClassS) + "(__b, __c);";
+ break;
+ case OpAbal: {
+ s += "__a + ";
+ std::string abd = MangleName("vabd", typestr, ClassS) + "(__b, __c)";
+ if (typestr[0] != 'U') {
+ // vabd results are always unsigned and must be zero-extended.
+ std::string utype = "U" + typestr.str();
+ s += "(" + TypeString(proto[0], typestr) + ")";
+ abd = "(" + TypeString('d', utype) + ")" + abd;
+ s += Extend(utype, abd) + ";";
+ } else {
+ s += Extend(typestr, abd) + ";";
+ }
+ break;
+ }
+ default:
+ throw "unknown OpKind!";
+ break;
+ }
+ return s;
+}
+
+static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
+ unsigned mod = proto[0];
+ unsigned ret = 0;
+
+ if (mod == 'v' || mod == 'f')
+ mod = proto[1];
+
+ bool quad = false;
+ bool poly = false;
+ bool usgn = false;
+ bool scal = false;
+ bool cnst = false;
+ bool pntr = false;
+
+ // Base type to get the type string for.
+ char type = ClassifyType(typestr, quad, poly, usgn);
+
+ // Based on the modifying character, change the type and width if necessary.
+ type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
+
+ if (usgn)
+ ret |= 0x08;
+ if (quad && proto[1] != 'g')
+ ret |= 0x10;
+
+ switch (type) {
+ case 'c':
+ ret |= poly ? 5 : 0;
+ break;
+ case 's':
+ ret |= poly ? 6 : 1;
+ break;
+ case 'i':
+ ret |= 2;
+ break;
+ case 'l':
+ ret |= 3;
+ break;
+ case 'h':
+ ret |= 7;
+ break;
+ case 'f':
+ ret |= 4;
+ break;
+ default:
+ throw "unhandled type!";
+ break;
+ }
+ return ret;
+}
+
+// Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a)
+static std::string GenBuiltin(const std::string &name, const std::string &proto,
+ StringRef typestr, ClassKind ck) {
+ std::string s;
+
+ // If this builtin returns a struct 2, 3, or 4 vectors, pass it as an implicit
+ // sret-like argument.
+ bool sret = (proto[0] >= '2' && proto[0] <= '4');
+
+ bool define = UseMacro(proto);
+
+ // Check if the prototype has a scalar operand with the type of the vector
+ // elements. If not, bitcasting the args will take care of arg checking.
+ // The actual signedness etc. will be taken care of with special enums.
+ if (proto.find('s') == std::string::npos)
+ ck = ClassB;
+
+ if (proto[0] != 'v') {
+ std::string ts = TypeString(proto[0], typestr);
+
+ if (define) {
+ if (sret)
+ s += ts + " r; ";
+ else
+ s += "(" + ts + ")";
+ } else if (sret) {
+ s += ts + " r; ";
+ } else {
+ s += "return (" + ts + ")";
+ }
+ }
+
+ bool splat = proto.find('a') != std::string::npos;
+
+ s += "__builtin_neon_";
+ if (splat) {
+ // Call the non-splat builtin: chop off the "_n" suffix from the name.
+ std::string vname(name, 0, name.size()-2);
+ s += MangleName(vname, typestr, ck);
+ } else {
+ s += MangleName(name, typestr, ck);
+ }
+ s += "(";
+
+ // Pass the address of the return variable as the first argument to sret-like
+ // builtins.
+ if (sret)
+ s += "&r, ";
+
+ char arg = 'a';
+ for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
+ std::string args = std::string(&arg, 1);
+
+ // Use the local temporaries instead of the macro arguments.
+ args = "__" + args;
+
+ bool argQuad = false;
+ bool argPoly = false;
+ bool argUsgn = false;
+ bool argScalar = false;
+ bool dummy = false;
+ char argType = ClassifyType(typestr, argQuad, argPoly, argUsgn);
+ argType = ModType(proto[i], argType, argQuad, argPoly, argUsgn, argScalar,
+ dummy, dummy);
+
+ // Handle multiple-vector values specially, emitting each subvector as an
+ // argument to the __builtin.
+ if (proto[i] >= '2' && proto[i] <= '4') {
+ // Check if an explicit cast is needed.
+ if (argType != 'c' || argPoly || argUsgn)
+ args = (argQuad ? "(int8x16_t)" : "(int8x8_t)") + args;
+
+ for (unsigned vi = 0, ve = proto[i] - '0'; vi != ve; ++vi) {
+ s += args + ".val[" + utostr(vi) + "]";
+ if ((vi + 1) < ve)
+ s += ", ";
+ }
+ if ((i + 1) < e)
+ s += ", ";
+
+ continue;
+ }
+
+ if (splat && (i + 1) == e)
+ args = Duplicate(GetNumElements(typestr, argQuad), typestr, args);
+
+ // Check if an explicit cast is needed.
+ if ((splat || !argScalar) &&
+ ((ck == ClassB && argType != 'c') || argPoly || argUsgn)) {
+ std::string argTypeStr = "c";
+ if (ck != ClassB)
+ argTypeStr = argType;
+ if (argQuad)
+ argTypeStr = "Q" + argTypeStr;
+ args = "(" + TypeString('d', argTypeStr) + ")" + args;
+ }
+
+ s += args;
+ if ((i + 1) < e)
+ s += ", ";
+ }
+
+ // Extra constant integer to hold type class enum for this function, e.g. s8
+ if (ck == ClassB)
+ s += ", " + utostr(GetNeonEnum(proto, typestr));
+
+ s += ");";
+
+ if (proto[0] != 'v' && sret) {
+ if (define)
+ s += " r;";
+ else
+ s += " return r;";
+ }
+ return s;
+}
+
+static std::string GenBuiltinDef(const std::string &name,
+ const std::string &proto,
+ StringRef typestr, ClassKind ck) {
+ std::string s("BUILTIN(__builtin_neon_");
+
+ // If all types are the same size, bitcasting the args will take care
+ // of arg checking. The actual signedness etc. will be taken care of with
+ // special enums.
+ if (proto.find('s') == std::string::npos)
+ ck = ClassB;
+
+ s += MangleName(name, typestr, ck);
+ s += ", \"";
+
+ for (unsigned i = 0, e = proto.size(); i != e; ++i)
+ s += BuiltinTypeString(proto[i], typestr, ck, i == 0);
+
+ // Extra constant integer to hold type class enum for this function, e.g. s8
+ if (ck == ClassB)
+ s += "i";
+
+ s += "\", \"n\")";
+ return s;
+}
+
+static std::string GenIntrinsic(const std::string &name,
+ const std::string &proto,
+ StringRef outTypeStr, StringRef inTypeStr,
+ OpKind kind, ClassKind classKind) {
+ assert(!proto.empty() && "");
+ bool define = UseMacro(proto);
+ std::string s;
+
+ // static always inline + return type
+ if (define)
+ s += "#define ";
+ else
+ s += "__ai " + TypeString(proto[0], outTypeStr) + " ";
+
+ // Function name with type suffix
+ std::string mangledName = MangleName(name, outTypeStr, ClassS);
+ if (outTypeStr != inTypeStr) {
+ // If the input type is different (e.g., for vreinterpret), append a suffix
+ // for the input type. String off a "Q" (quad) prefix so that MangleName
+ // does not insert another "q" in the name.
+ unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0);
+ StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff);
+ mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
+ }
+ s += mangledName;
+
+ // Function arguments
+ s += GenArgs(proto, inTypeStr);
+
+ // Definition.
+ if (define) {
+ s += " __extension__ ({ \\\n ";
+ s += GenMacroLocals(proto, inTypeStr);
+ } else {
+ s += " { \\\n ";
+ }
+
+ if (kind != OpNone)
+ s += GenOpString(kind, proto, outTypeStr);
+ else
+ s += GenBuiltin(name, proto, outTypeStr, classKind);
+ if (define)
+ s += " })";
+ else
+ s += " }";
+ s += "\n";
+ return s;
+}
+
+/// run - Read the records in arm_neon.td and output arm_neon.h. arm_neon.h
+/// is comprised of type definitions and function declarations.
+void NeonEmitter::run(raw_ostream &OS) {
+ OS <<
+ "/*===---- arm_neon.h - ARM Neon intrinsics ------------------------------"
+ "---===\n"
+ " *\n"
+ " * Permission is hereby granted, free of charge, to any person obtaining "
+ "a copy\n"
+ " * of this software and associated documentation files (the \"Software\"),"
+ " to deal\n"
+ " * in the Software without restriction, including without limitation the "
+ "rights\n"
+ " * to use, copy, modify, merge, publish, distribute, sublicense, "
+ "and/or sell\n"
+ " * copies of the Software, and to permit persons to whom the Software is\n"
+ " * furnished to do so, subject to the following conditions:\n"
+ " *\n"
+ " * The above copyright notice and this permission notice shall be "
+ "included in\n"
+ " * all copies or substantial portions of the Software.\n"
+ " *\n"
+ " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, "
+ "EXPRESS OR\n"
+ " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF "
+ "MERCHANTABILITY,\n"
+ " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT "
+ "SHALL THE\n"
+ " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR "
+ "OTHER\n"
+ " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, "
+ "ARISING FROM,\n"
+ " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER "
+ "DEALINGS IN\n"
+ " * THE SOFTWARE.\n"
+ " *\n"
+ " *===--------------------------------------------------------------------"
+ "---===\n"
+ " */\n\n";
+
+ OS << "#ifndef __ARM_NEON_H\n";
+ OS << "#define __ARM_NEON_H\n\n";
+
+ OS << "#ifndef __ARM_NEON__\n";
+ OS << "#error \"NEON support not enabled\"\n";
+ OS << "#endif\n\n";
+
+ OS << "#include <stdint.h>\n\n";
+
+ // Emit NEON-specific scalar typedefs.
+ OS << "typedef float float32_t;\n";
+ OS << "typedef int8_t poly8_t;\n";
+ OS << "typedef int16_t poly16_t;\n";
+ OS << "typedef uint16_t float16_t;\n";
+
+ // Emit Neon vector typedefs.
+ std::string TypedefTypes("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfPcQPcPsQPs");
+ SmallVector<StringRef, 24> TDTypeVec;
+ ParseTypes(0, TypedefTypes, TDTypeVec);
+
+ // Emit vector typedefs.
+ for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
+ bool dummy, quad = false, poly = false;
+ (void) ClassifyType(TDTypeVec[i], quad, poly, dummy);
+ if (poly)
+ OS << "typedef __attribute__((neon_polyvector_type(";
+ else
+ OS << "typedef __attribute__((neon_vector_type(";
+
+ unsigned nElts = GetNumElements(TDTypeVec[i], quad);
+ OS << utostr(nElts) << "))) ";
+ if (nElts < 10)
+ OS << " ";
+
+ OS << TypeString('s', TDTypeVec[i]);
+ OS << " " << TypeString('d', TDTypeVec[i]) << ";\n";
+ }
+ OS << "\n";
+
+ // Emit struct typedefs.
+ for (unsigned vi = 2; vi != 5; ++vi) {
+ for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
+ std::string ts = TypeString('d', TDTypeVec[i]);
+ std::string vs = TypeString('0' + vi, TDTypeVec[i]);
+ OS << "typedef struct " << vs << " {\n";
+ OS << " " << ts << " val";
+ OS << "[" << utostr(vi) << "]";
+ OS << ";\n} ";
+ OS << vs << ";\n\n";
+ }
+ }
+
+ OS<<"#define __ai static __attribute__((__always_inline__, __nodebug__))\n\n";
+
+ std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
+
+ // Emit vmovl, vmull and vabd intrinsics first so they can be used by other
+ // intrinsics. (Some of the saturating multiply instructions are also
+ // used to implement the corresponding "_lane" variants, but tablegen
+ // sorts the records into alphabetical order so that the "_lane" variants
+ // come after the intrinsics they use.)
+ emitIntrinsic(OS, Records.getDef("VMOVL"));
+ emitIntrinsic(OS, Records.getDef("VMULL"));
+ emitIntrinsic(OS, Records.getDef("VABD"));
+
+ for (unsigned i = 0, e = RV.size(); i != e; ++i) {
+ Record *R = RV[i];
+ if (R->getName() != "VMOVL" &&
+ R->getName() != "VMULL" &&
+ R->getName() != "VABD")
+ emitIntrinsic(OS, R);
+ }
+
+ OS << "#undef __ai\n\n";
+ OS << "#endif /* __ARM_NEON_H */\n";
+}
+
+/// emitIntrinsic - Write out the arm_neon.h header file definitions for the
+/// intrinsics specified by record R.
+void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R) {
+ std::string name = R->getValueAsString("Name");
+ std::string Proto = R->getValueAsString("Prototype");
+ std::string Types = R->getValueAsString("Types");
+
+ SmallVector<StringRef, 16> TypeVec;
+ ParseTypes(R, Types, TypeVec);
+
+ OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
+
+ ClassKind classKind = ClassNone;
+ if (R->getSuperClasses().size() >= 2)
+ classKind = ClassMap[R->getSuperClasses()[1]];
+ if (classKind == ClassNone && kind == OpNone)
+ throw TGError(R->getLoc(), "Builtin has no class kind");
+
+ for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
+ if (kind == OpReinterpret) {
+ bool outQuad = false;
+ bool dummy = false;
+ (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy);
+ for (unsigned srcti = 0, srcte = TypeVec.size();
+ srcti != srcte; ++srcti) {
+ bool inQuad = false;
+ (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
+ if (srcti == ti || inQuad != outQuad)
+ continue;
+ OS << GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[srcti],
+ OpCast, ClassS);
+ }
+ } else {
+ OS << GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[ti],
+ kind, classKind);
+ }
+ }
+ OS << "\n";
+}
+
+static unsigned RangeFromType(const char mod, StringRef typestr) {
+ // base type to get the type string for.
+ bool quad = false, dummy = false;
+ char type = ClassifyType(typestr, quad, dummy, dummy);
+ type = ModType(mod, type, quad, dummy, dummy, dummy, dummy, dummy);
+
+ switch (type) {
+ case 'c':
+ return (8 << (int)quad) - 1;
+ case 'h':
+ case 's':
+ return (4 << (int)quad) - 1;
+ case 'f':
+ case 'i':
+ return (2 << (int)quad) - 1;
+ case 'l':
+ return (1 << (int)quad) - 1;
+ default:
+ throw "unhandled type!";
+ break;
+ }
+ assert(0 && "unreachable");
+ return 0;
+}
+
+/// runHeader - Emit a file with sections defining:
+/// 1. the NEON section of BuiltinsARM.def.
+/// 2. the SemaChecking code for the type overload checking.
+/// 3. the SemaChecking code for validation of intrinsic immedate arguments.
+void NeonEmitter::runHeader(raw_ostream &OS) {
+ std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
+
+ StringMap<OpKind> EmittedMap;
+
+ // Generate BuiltinsARM.def for NEON
+ OS << "#ifdef GET_NEON_BUILTINS\n";
+ for (unsigned i = 0, e = RV.size(); i != e; ++i) {
+ Record *R = RV[i];
+ OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
+ if (k != OpNone)
+ continue;
+
+ std::string Proto = R->getValueAsString("Prototype");
+
+ // Functions with 'a' (the splat code) in the type prototype should not get
+ // their own builtin as they use the non-splat variant.
+ if (Proto.find('a') != std::string::npos)
+ continue;
+
+ std::string Types = R->getValueAsString("Types");
+ SmallVector<StringRef, 16> TypeVec;
+ ParseTypes(R, Types, TypeVec);
+
+ if (R->getSuperClasses().size() < 2)
+ throw TGError(R->getLoc(), "Builtin has no class kind");
+
+ std::string name = R->getValueAsString("Name");
+ ClassKind ck = ClassMap[R->getSuperClasses()[1]];
+
+ for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
+ // Generate the BuiltinsARM.def declaration for this builtin, ensuring
+ // that each unique BUILTIN() macro appears only once in the output
+ // stream.
+ std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck);
+ if (EmittedMap.count(bd))
+ continue;
+
+ EmittedMap[bd] = OpNone;
+ OS << bd << "\n";
+ }
+ }
+ OS << "#endif\n\n";
+
+ // Generate the overloaded type checking code for SemaChecking.cpp
+ OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n";
+ for (unsigned i = 0, e = RV.size(); i != e; ++i) {
+ Record *R = RV[i];
+ OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
+ if (k != OpNone)
+ continue;
+
+ std::string Proto = R->getValueAsString("Prototype");
+ std::string Types = R->getValueAsString("Types");
+ std::string name = R->getValueAsString("Name");
+
+ // Functions with 'a' (the splat code) in the type prototype should not get
+ // their own builtin as they use the non-splat variant.
+ if (Proto.find('a') != std::string::npos)
+ continue;
+
+ // Functions which have a scalar argument cannot be overloaded, no need to
+ // check them if we are emitting the type checking code.
+ if (Proto.find('s') != std::string::npos)
+ continue;
+
+ SmallVector<StringRef, 16> TypeVec;
+ ParseTypes(R, Types, TypeVec);
+
+ if (R->getSuperClasses().size() < 2)
+ throw TGError(R->getLoc(), "Builtin has no class kind");
+
+ int si = -1, qi = -1;
+ unsigned mask = 0, qmask = 0;
+ for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
+ // Generate the switch case(s) for this builtin for the type validation.
+ bool quad = false, poly = false, usgn = false;
+ (void) ClassifyType(TypeVec[ti], quad, poly, usgn);
+
+ if (quad) {
+ qi = ti;
+ qmask |= 1 << GetNeonEnum(Proto, TypeVec[ti]);
+ } else {
+ si = ti;
+ mask |= 1 << GetNeonEnum(Proto, TypeVec[ti]);
+ }
+ }
+ if (mask)
+ OS << "case ARM::BI__builtin_neon_"
+ << MangleName(name, TypeVec[si], ClassB)
+ << ": mask = " << "0x" << utohexstr(mask) << "; break;\n";
+ if (qmask)
+ OS << "case ARM::BI__builtin_neon_"
+ << MangleName(name, TypeVec[qi], ClassB)
+ << ": mask = " << "0x" << utohexstr(qmask) << "; break;\n";
+ }
+ OS << "#endif\n\n";
+
+ // Generate the intrinsic range checking code for shift/lane immediates.
+ OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n";
+ for (unsigned i = 0, e = RV.size(); i != e; ++i) {
+ Record *R = RV[i];
+
+ OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
+ if (k != OpNone)
+ continue;
+
+ std::string name = R->getValueAsString("Name");
+ std::string Proto = R->getValueAsString("Prototype");
+ std::string Types = R->getValueAsString("Types");
+
+ // Functions with 'a' (the splat code) in the type prototype should not get
+ // their own builtin as they use the non-splat variant.
+ if (Proto.find('a') != std::string::npos)
+ continue;
+
+ // Functions which do not have an immediate do not need to have range
+ // checking code emitted.
+ size_t immPos = Proto.find('i');
+ if (immPos == std::string::npos)
+ continue;
+
+ SmallVector<StringRef, 16> TypeVec;
+ ParseTypes(R, Types, TypeVec);
+
+ if (R->getSuperClasses().size() < 2)
+ throw TGError(R->getLoc(), "Builtin has no class kind");
+
+ ClassKind ck = ClassMap[R->getSuperClasses()[1]];
+
+ for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
+ std::string namestr, shiftstr, rangestr;
+
+ if (R->getValueAsBit("isVCVT_N")) {
+ // VCVT between floating- and fixed-point values takes an immediate
+ // in the range 1 to 32.
+ ck = ClassB;
+ rangestr = "l = 1; u = 31"; // upper bound = l + u
+ } else if (Proto.find('s') == std::string::npos) {
+ // Builtins which are overloaded by type will need to have their upper
+ // bound computed at Sema time based on the type constant.
+ ck = ClassB;
+ if (R->getValueAsBit("isShift")) {
+ shiftstr = ", true";
+
+ // Right shifts have an 'r' in the name, left shifts do not.
+ if (name.find('r') != std::string::npos)
+ rangestr = "l = 1; ";
+ }
+ rangestr += "u = RFT(TV" + shiftstr + ")";
+ } else {
+ // The immediate generally refers to a lane in the preceding argument.
+ assert(immPos > 0 && "unexpected immediate operand");
+ rangestr = "u = " + utostr(RangeFromType(Proto[immPos-1], TypeVec[ti]));
+ }
+ // Make sure cases appear only once by uniquing them in a string map.
+ namestr = MangleName(name, TypeVec[ti], ck);
+ if (EmittedMap.count(namestr))
+ continue;
+ EmittedMap[namestr] = OpNone;
+
+ // Calculate the index of the immediate that should be range checked.
+ unsigned immidx = 0;
+
+ // Builtins that return a struct of multiple vectors have an extra
+ // leading arg for the struct return.
+ if (Proto[0] >= '2' && Proto[0] <= '4')
+ ++immidx;
+
+ // Add one to the index for each argument until we reach the immediate
+ // to be checked. Structs of vectors are passed as multiple arguments.
+ for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) {
+ switch (Proto[ii]) {
+ default: immidx += 1; break;
+ case '2': immidx += 2; break;
+ case '3': immidx += 3; break;
+ case '4': immidx += 4; break;
+ case 'i': ie = ii + 1; break;
+ }
+ }
+ OS << "case ARM::BI__builtin_neon_" << MangleName(name, TypeVec[ti], ck)
+ << ": i = " << immidx << "; " << rangestr << "; break;\n";
+ }
+ }
+ OS << "#endif\n\n";
+}
+
+/// GenTest - Write out a test for the intrinsic specified by the name and
+/// type strings, including the embedded patterns for FileCheck to match.
+static std::string GenTest(const std::string &name,
+ const std::string &proto,
+ StringRef outTypeStr, StringRef inTypeStr,
+ bool isShift) {
+ assert(!proto.empty() && "");
+ std::string s;
+
+ // Function name with type suffix
+ std::string mangledName = MangleName(name, outTypeStr, ClassS);
+ if (outTypeStr != inTypeStr) {
+ // If the input type is different (e.g., for vreinterpret), append a suffix
+ // for the input type. String off a "Q" (quad) prefix so that MangleName
+ // does not insert another "q" in the name.
+ unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0);
+ StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff);
+ mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
+ }
+
+ // Emit the FileCheck patterns.
+ s += "// CHECK: test_" + mangledName + "\n";
+ // s += "// CHECK: \n"; // FIXME: + expected instruction opcode.
+
+ // Emit the start of the test function.
+ s += TypeString(proto[0], outTypeStr) + " test_" + mangledName + "(";
+ char arg = 'a';
+ std::string comma;
+ for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
+ // Do not create arguments for values that must be immediate constants.
+ if (proto[i] == 'i')
+ continue;
+ s += comma + TypeString(proto[i], inTypeStr) + " ";
+ s.push_back(arg);
+ comma = ", ";
+ }
+ s += ") { \\\n ";
+
+ if (proto[0] != 'v')
+ s += "return ";
+ s += mangledName + "(";
+ arg = 'a';
+ for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
+ if (proto[i] == 'i') {
+ // For immediate operands, test the maximum value.
+ if (isShift)
+ s += "1"; // FIXME
+ else
+ // The immediate generally refers to a lane in the preceding argument.
+ s += utostr(RangeFromType(proto[i-1], inTypeStr));
+ } else {
+ s.push_back(arg);
+ }
+ if ((i + 1) < e)
+ s += ", ";
+ }
+ s += ");\n}\n\n";
+ return s;
+}
+
+/// runTests - Write out a complete set of tests for all of the Neon
+/// intrinsics.
+void NeonEmitter::runTests(raw_ostream &OS) {
+ OS <<
+ "// RUN: %clang_cc1 -triple thumbv7-apple-darwin \\\n"
+ "// RUN: -target-cpu cortex-a9 -ffreestanding -S -o - %s | FileCheck %s\n"
+ "\n"
+ "#include <arm_neon.h>\n"
+ "\n";
+
+ std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
+ for (unsigned i = 0, e = RV.size(); i != e; ++i) {
+ Record *R = RV[i];
+ std::string name = R->getValueAsString("Name");
+ std::string Proto = R->getValueAsString("Prototype");
+ std::string Types = R->getValueAsString("Types");
+ bool isShift = R->getValueAsBit("isShift");
+
+ SmallVector<StringRef, 16> TypeVec;
+ ParseTypes(R, Types, TypeVec);
+
+ OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
+ for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
+ if (kind == OpReinterpret) {
+ bool outQuad = false;
+ bool dummy = false;
+ (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy);
+ for (unsigned srcti = 0, srcte = TypeVec.size();
+ srcti != srcte; ++srcti) {
+ bool inQuad = false;
+ (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
+ if (srcti == ti || inQuad != outQuad)
+ continue;
+ OS << GenTest(name, Proto, TypeVec[ti], TypeVec[srcti], isShift);
+ }
+ } else {
+ OS << GenTest(name, Proto, TypeVec[ti], TypeVec[ti], isShift);
+ }
+ }
+ OS << "\n";
+ }
+}
+
diff --git a/utils/TableGen/NeonEmitter.h b/utils/TableGen/NeonEmitter.h
new file mode 100644
index 000000000000..708ad3c06a0f
--- /dev/null
+++ b/utils/TableGen/NeonEmitter.h
@@ -0,0 +1,176 @@
+//===- NeonEmitter.h - Generate arm_neon.h for use with clang ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend is responsible for emitting arm_neon.h, which includes
+// a declaration and definition of each function specified by the ARM NEON
+// compiler interface. See ARM document DUI0348B.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef NEON_EMITTER_H
+#define NEON_EMITTER_H
+
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+
+enum OpKind {
+ OpNone,
+ OpAdd,
+ OpAddl,
+ OpAddw,
+ OpSub,
+ OpSubl,
+ OpSubw,
+ OpMul,
+ OpMla,
+ OpMlal,
+ OpMls,
+ OpMlsl,
+ OpMulN,
+ OpMlaN,
+ OpMlsN,
+ OpMlalN,
+ OpMlslN,
+ OpMulLane,
+ OpMullLane,
+ OpMlaLane,
+ OpMlsLane,
+ OpMlalLane,
+ OpMlslLane,
+ OpQDMullLane,
+ OpQDMlalLane,
+ OpQDMlslLane,
+ OpQDMulhLane,
+ OpQRDMulhLane,
+ OpEq,
+ OpGe,
+ OpLe,
+ OpGt,
+ OpLt,
+ OpNeg,
+ OpNot,
+ OpAnd,
+ OpOr,
+ OpXor,
+ OpAndNot,
+ OpOrNot,
+ OpCast,
+ OpConcat,
+ OpDup,
+ OpDupLane,
+ OpHi,
+ OpLo,
+ OpSelect,
+ OpRev16,
+ OpRev32,
+ OpRev64,
+ OpReinterpret,
+ OpAbdl,
+ OpAba,
+ OpAbal
+};
+
+enum ClassKind {
+ ClassNone,
+ ClassI, // generic integer instruction, e.g., "i8" suffix
+ ClassS, // signed/unsigned/poly, e.g., "s8", "u8" or "p8" suffix
+ ClassW, // width-specific instruction, e.g., "8" suffix
+ ClassB // bitcast arguments with enum argument to specify type
+};
+
+namespace llvm {
+
+ class NeonEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+ StringMap<OpKind> OpMap;
+ DenseMap<Record*, ClassKind> ClassMap;
+
+ public:
+ NeonEmitter(RecordKeeper &R) : Records(R) {
+ OpMap["OP_NONE"] = OpNone;
+ OpMap["OP_ADD"] = OpAdd;
+ OpMap["OP_ADDL"] = OpAddl;
+ OpMap["OP_ADDW"] = OpAddw;
+ OpMap["OP_SUB"] = OpSub;
+ OpMap["OP_SUBL"] = OpSubl;
+ OpMap["OP_SUBW"] = OpSubw;
+ OpMap["OP_MUL"] = OpMul;
+ OpMap["OP_MLA"] = OpMla;
+ OpMap["OP_MLAL"] = OpMlal;
+ OpMap["OP_MLS"] = OpMls;
+ OpMap["OP_MLSL"] = OpMlsl;
+ OpMap["OP_MUL_N"] = OpMulN;
+ OpMap["OP_MLA_N"] = OpMlaN;
+ OpMap["OP_MLS_N"] = OpMlsN;
+ OpMap["OP_MLAL_N"] = OpMlalN;
+ OpMap["OP_MLSL_N"] = OpMlslN;
+ OpMap["OP_MUL_LN"]= OpMulLane;
+ OpMap["OP_MULL_LN"] = OpMullLane;
+ OpMap["OP_MLA_LN"]= OpMlaLane;
+ OpMap["OP_MLS_LN"]= OpMlsLane;
+ OpMap["OP_MLAL_LN"] = OpMlalLane;
+ OpMap["OP_MLSL_LN"] = OpMlslLane;
+ OpMap["OP_QDMULL_LN"] = OpQDMullLane;
+ OpMap["OP_QDMLAL_LN"] = OpQDMlalLane;
+ OpMap["OP_QDMLSL_LN"] = OpQDMlslLane;
+ OpMap["OP_QDMULH_LN"] = OpQDMulhLane;
+ OpMap["OP_QRDMULH_LN"] = OpQRDMulhLane;
+ OpMap["OP_EQ"] = OpEq;
+ OpMap["OP_GE"] = OpGe;
+ OpMap["OP_LE"] = OpLe;
+ OpMap["OP_GT"] = OpGt;
+ OpMap["OP_LT"] = OpLt;
+ OpMap["OP_NEG"] = OpNeg;
+ OpMap["OP_NOT"] = OpNot;
+ OpMap["OP_AND"] = OpAnd;
+ OpMap["OP_OR"] = OpOr;
+ OpMap["OP_XOR"] = OpXor;
+ OpMap["OP_ANDN"] = OpAndNot;
+ OpMap["OP_ORN"] = OpOrNot;
+ OpMap["OP_CAST"] = OpCast;
+ OpMap["OP_CONC"] = OpConcat;
+ OpMap["OP_HI"] = OpHi;
+ OpMap["OP_LO"] = OpLo;
+ OpMap["OP_DUP"] = OpDup;
+ OpMap["OP_DUP_LN"] = OpDupLane;
+ OpMap["OP_SEL"] = OpSelect;
+ OpMap["OP_REV16"] = OpRev16;
+ OpMap["OP_REV32"] = OpRev32;
+ OpMap["OP_REV64"] = OpRev64;
+ OpMap["OP_REINT"] = OpReinterpret;
+ OpMap["OP_ABDL"] = OpAbdl;
+ OpMap["OP_ABA"] = OpAba;
+ OpMap["OP_ABAL"] = OpAbal;
+
+ Record *SI = R.getClass("SInst");
+ Record *II = R.getClass("IInst");
+ Record *WI = R.getClass("WInst");
+ ClassMap[SI] = ClassS;
+ ClassMap[II] = ClassI;
+ ClassMap[WI] = ClassW;
+ }
+
+ // run - Emit arm_neon.h.inc
+ void run(raw_ostream &o);
+
+ // runHeader - Emit all the __builtin prototypes used in arm_neon.h
+ void runHeader(raw_ostream &o);
+
+ // runTests - Emit tests for all the Neon intrinsics.
+ void runTests(raw_ostream &o);
+
+ private:
+ void emitIntrinsic(raw_ostream &OS, Record *R);
+ };
+
+} // End llvm namespace
+
+#endif
diff --git a/utils/TableGen/OptParserEmitter.cpp b/utils/TableGen/OptParserEmitter.cpp
new file mode 100644
index 000000000000..dea22d388612
--- /dev/null
+++ b/utils/TableGen/OptParserEmitter.cpp
@@ -0,0 +1,194 @@
+//===- OptParserEmitter.cpp - Table Driven Command Line Parsing -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "OptParserEmitter.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/ADT/STLExtras.h"
+using namespace llvm;
+
+static int StrCmpOptionName(const char *A, const char *B) {
+ char a = *A, b = *B;
+ while (a == b) {
+ if (a == '\0')
+ return 0;
+
+ a = *++A;
+ b = *++B;
+ }
+
+ if (a == '\0') // A is a prefix of B.
+ return 1;
+ if (b == '\0') // B is a prefix of A.
+ return -1;
+
+ // Otherwise lexicographic.
+ return (a < b) ? -1 : 1;
+}
+
+static int CompareOptionRecords(const void *Av, const void *Bv) {
+ const Record *A = *(Record**) Av;
+ const Record *B = *(Record**) Bv;
+
+ // Sentinel options precede all others and are only ordered by precedence.
+ bool ASent = A->getValueAsDef("Kind")->getValueAsBit("Sentinel");
+ bool BSent = B->getValueAsDef("Kind")->getValueAsBit("Sentinel");
+ if (ASent != BSent)
+ return ASent ? -1 : 1;
+
+ // Compare options by name, unless they are sentinels.
+ if (!ASent)
+ if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").c_str(),
+ B->getValueAsString("Name").c_str()))
+ return Cmp;
+
+ // Then by the kind precedence;
+ int APrec = A->getValueAsDef("Kind")->getValueAsInt("Precedence");
+ int BPrec = B->getValueAsDef("Kind")->getValueAsInt("Precedence");
+ assert(APrec != BPrec && "Options are equivalent!");
+ return APrec < BPrec ? -1 : 1;
+}
+
+static const std::string getOptionName(const Record &R) {
+ // Use the record name unless EnumName is defined.
+ if (dynamic_cast<UnsetInit*>(R.getValueInit("EnumName")))
+ return R.getName();
+
+ return R.getValueAsString("EnumName");
+}
+
+static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) {
+ OS << '"';
+ OS.write_escaped(Str);
+ OS << '"';
+ return OS;
+}
+
+void OptParserEmitter::run(raw_ostream &OS) {
+ // Get the option groups and options.
+ const std::vector<Record*> &Groups =
+ Records.getAllDerivedDefinitions("OptionGroup");
+ std::vector<Record*> Opts = Records.getAllDerivedDefinitions("Option");
+
+ if (GenDefs)
+ EmitSourceFileHeader("Option Parsing Definitions", OS);
+ else
+ EmitSourceFileHeader("Option Parsing Table", OS);
+
+ array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords);
+ if (GenDefs) {
+ OS << "#ifndef OPTION\n";
+ OS << "#error \"Define OPTION prior to including this file!\"\n";
+ OS << "#endif\n\n";
+
+ OS << "/////////\n";
+ OS << "// Groups\n\n";
+ for (unsigned i = 0, e = Groups.size(); i != e; ++i) {
+ const Record &R = *Groups[i];
+
+ // Start a single option entry.
+ OS << "OPTION(";
+
+ // The option string.
+ OS << '"' << R.getValueAsString("Name") << '"';
+
+ // The option identifier name.
+ OS << ", "<< getOptionName(R);
+
+ // The option kind.
+ OS << ", Group";
+
+ // The containing option group (if any).
+ OS << ", ";
+ if (const DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group")))
+ OS << getOptionName(*DI->getDef());
+ else
+ OS << "INVALID";
+
+ // The other option arguments (unused for groups).
+ OS << ", INVALID, 0, 0";
+
+ // The option help text.
+ if (!dynamic_cast<UnsetInit*>(R.getValueInit("HelpText"))) {
+ OS << ",\n";
+ OS << " ";
+ write_cstring(OS, R.getValueAsString("HelpText"));
+ } else
+ OS << ", 0";
+
+ // The option meta-variable name (unused).
+ OS << ", 0)\n";
+ }
+ OS << "\n";
+
+ OS << "//////////\n";
+ OS << "// Options\n\n";
+ for (unsigned i = 0, e = Opts.size(); i != e; ++i) {
+ const Record &R = *Opts[i];
+
+ // Start a single option entry.
+ OS << "OPTION(";
+
+ // The option string.
+ write_cstring(OS, R.getValueAsString("Name"));
+
+ // The option identifier name.
+ OS << ", "<< getOptionName(R);
+
+ // The option kind.
+ OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name");
+
+ // The containing option group (if any).
+ OS << ", ";
+ if (const DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group")))
+ OS << getOptionName(*DI->getDef());
+ else
+ OS << "INVALID";
+
+ // The option alias (if any).
+ OS << ", ";
+ if (const DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Alias")))
+ OS << getOptionName(*DI->getDef());
+ else
+ OS << "INVALID";
+
+ // The option flags.
+ const ListInit *LI = R.getValueAsListInit("Flags");
+ if (LI->empty()) {
+ OS << ", 0";
+ } else {
+ OS << ", ";
+ for (unsigned i = 0, e = LI->size(); i != e; ++i) {
+ if (i)
+ OS << " | ";
+ OS << dynamic_cast<DefInit*>(LI->getElement(i))->getDef()->getName();
+ }
+ }
+
+ // The option parameter field.
+ OS << ", " << R.getValueAsInt("NumArgs");
+
+ // The option help text.
+ if (!dynamic_cast<UnsetInit*>(R.getValueInit("HelpText"))) {
+ OS << ",\n";
+ OS << " ";
+ write_cstring(OS, R.getValueAsString("HelpText"));
+ } else
+ OS << ", 0";
+
+ // The option meta-variable name.
+ OS << ", ";
+ if (!dynamic_cast<UnsetInit*>(R.getValueInit("MetaVarName")))
+ write_cstring(OS, R.getValueAsString("MetaVarName"));
+ else
+ OS << "0";
+
+ OS << ")\n";
+ }
+ }
+}
diff --git a/utils/TableGen/OptParserEmitter.h b/utils/TableGen/OptParserEmitter.h
new file mode 100644
index 000000000000..ca667caf439c
--- /dev/null
+++ b/utils/TableGen/OptParserEmitter.h
@@ -0,0 +1,34 @@
+//===- OptParserEmitter.h - Table Driven Command Line Parsing ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef UTILS_TABLEGEN_OPTPARSEREMITTER_H
+#define UTILS_TABLEGEN_OPTPARSEREMITTER_H
+
+#include "llvm/TableGen/TableGenBackend.h"
+
+namespace llvm {
+ /// OptParserEmitter - This tablegen backend takes an input .td file
+ /// describing a list of options and emits a data structure for parsing and
+ /// working with those options when given an input command line.
+ class OptParserEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+ bool GenDefs;
+
+ public:
+ OptParserEmitter(RecordKeeper &R, bool _GenDefs)
+ : Records(R), GenDefs(_GenDefs) {}
+
+ /// run - Output the option parsing information.
+ ///
+ /// \param GenHeader - Generate the header describing the option IDs.x
+ void run(raw_ostream &OS);
+ };
+}
+
+#endif
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
new file mode 100644
index 000000000000..5c016d32ddd7
--- /dev/null
+++ b/utils/TableGen/TableGen.cpp
@@ -0,0 +1,176 @@
+//===- TableGen.cpp - Top-Level TableGen implementation for Clang ---------===//
+//
+// 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 main function for Clang's TableGen.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangASTNodesEmitter.h"
+#include "ClangAttrEmitter.h"
+#include "ClangDiagnosticsEmitter.h"
+#include "ClangSACheckersEmitter.h"
+#include "NeonEmitter.h"
+#include "OptParserEmitter.h"
+
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Main.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenAction.h"
+
+using namespace llvm;
+
+enum ActionType {
+ GenClangAttrClasses,
+ GenClangAttrImpl,
+ GenClangAttrList,
+ GenClangAttrPCHRead,
+ GenClangAttrPCHWrite,
+ GenClangAttrSpellingList,
+ GenClangAttrLateParsedList,
+ GenClangDiagsDefs,
+ GenClangDiagGroups,
+ GenClangDiagsIndexName,
+ GenClangDeclNodes,
+ GenClangStmtNodes,
+ GenClangSACheckers,
+ GenOptParserDefs, GenOptParserImpl,
+ GenArmNeon,
+ GenArmNeonSema,
+ GenArmNeonTest
+};
+
+namespace {
+ cl::opt<ActionType>
+ Action(cl::desc("Action to perform:"),
+ cl::values(clEnumValN(GenOptParserDefs, "gen-opt-parser-defs",
+ "Generate option definitions"),
+ clEnumValN(GenOptParserImpl, "gen-opt-parser-impl",
+ "Generate option parser implementation"),
+ clEnumValN(GenClangAttrClasses, "gen-clang-attr-classes",
+ "Generate clang attribute clases"),
+ clEnumValN(GenClangAttrImpl, "gen-clang-attr-impl",
+ "Generate clang attribute implementations"),
+ clEnumValN(GenClangAttrList, "gen-clang-attr-list",
+ "Generate a clang attribute list"),
+ clEnumValN(GenClangAttrPCHRead, "gen-clang-attr-pch-read",
+ "Generate clang PCH attribute reader"),
+ clEnumValN(GenClangAttrPCHWrite, "gen-clang-attr-pch-write",
+ "Generate clang PCH attribute writer"),
+ clEnumValN(GenClangAttrSpellingList,
+ "gen-clang-attr-spelling-list",
+ "Generate a clang attribute spelling list"),
+ clEnumValN(GenClangAttrLateParsedList,
+ "gen-clang-attr-late-parsed-list",
+ "Generate a clang attribute LateParsed list"),
+ clEnumValN(GenClangDiagsDefs, "gen-clang-diags-defs",
+ "Generate Clang diagnostics definitions"),
+ clEnumValN(GenClangDiagGroups, "gen-clang-diag-groups",
+ "Generate Clang diagnostic groups"),
+ clEnumValN(GenClangDiagsIndexName,
+ "gen-clang-diags-index-name",
+ "Generate Clang diagnostic name index"),
+ clEnumValN(GenClangDeclNodes, "gen-clang-decl-nodes",
+ "Generate Clang AST declaration nodes"),
+ clEnumValN(GenClangStmtNodes, "gen-clang-stmt-nodes",
+ "Generate Clang AST statement nodes"),
+ clEnumValN(GenClangSACheckers, "gen-clang-sa-checkers",
+ "Generate Clang Static Analyzer checkers"),
+ clEnumValN(GenArmNeon, "gen-arm-neon",
+ "Generate arm_neon.h for clang"),
+ clEnumValN(GenArmNeonSema, "gen-arm-neon-sema",
+ "Generate ARM NEON sema support for clang"),
+ clEnumValN(GenArmNeonTest, "gen-arm-neon-test",
+ "Generate ARM NEON tests for clang"),
+ clEnumValEnd));
+
+ cl::opt<std::string>
+ ClangComponent("clang-component",
+ cl::desc("Only use warnings from specified component"),
+ cl::value_desc("component"), cl::Hidden);
+}
+
+class ClangTableGenAction : public TableGenAction {
+public:
+ bool operator()(raw_ostream &OS, RecordKeeper &Records) {
+ switch (Action) {
+ case GenClangAttrClasses:
+ ClangAttrClassEmitter(Records).run(OS);
+ break;
+ case GenClangAttrImpl:
+ ClangAttrImplEmitter(Records).run(OS);
+ break;
+ case GenClangAttrList:
+ ClangAttrListEmitter(Records).run(OS);
+ break;
+ case GenClangAttrPCHRead:
+ ClangAttrPCHReadEmitter(Records).run(OS);
+ break;
+ case GenClangAttrPCHWrite:
+ ClangAttrPCHWriteEmitter(Records).run(OS);
+ break;
+ case GenClangAttrSpellingList:
+ ClangAttrSpellingListEmitter(Records).run(OS);
+ break;
+ case GenClangAttrLateParsedList:
+ ClangAttrLateParsedListEmitter(Records).run(OS);
+ break;
+ case GenClangDiagsDefs:
+ ClangDiagsDefsEmitter(Records, ClangComponent).run(OS);
+ break;
+ case GenClangDiagGroups:
+ ClangDiagGroupsEmitter(Records).run(OS);
+ break;
+ case GenClangDiagsIndexName:
+ ClangDiagsIndexNameEmitter(Records).run(OS);
+ break;
+ case GenClangDeclNodes:
+ ClangASTNodesEmitter(Records, "Decl", "Decl").run(OS);
+ ClangDeclContextEmitter(Records).run(OS);
+ break;
+ case GenClangStmtNodes:
+ ClangASTNodesEmitter(Records, "Stmt", "").run(OS);
+ break;
+ case GenClangSACheckers:
+ ClangSACheckersEmitter(Records).run(OS);
+ break;
+ case GenOptParserDefs:
+ OptParserEmitter(Records, true).run(OS);
+ break;
+ case GenOptParserImpl:
+ OptParserEmitter(Records, false).run(OS);
+ break;
+ case GenArmNeon:
+ NeonEmitter(Records).run(OS);
+ break;
+ case GenArmNeonSema:
+ NeonEmitter(Records).runHeader(OS);
+ break;
+ case GenArmNeonTest:
+ NeonEmitter(Records).runTests(OS);
+ break;
+ default:
+ assert(1 && "Invalid Action");
+ return true;
+ }
+
+ return false;
+ }
+};
+
+int main(int argc, char **argv) {
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc, argv);
+ cl::ParseCommandLineOptions(argc, argv);
+
+ ClangTableGenAction Action;
+ return TableGenMain(argv[0], Action);
+}
diff --git a/utils/analyzer/CmpRuns b/utils/analyzer/CmpRuns.py
index 739d5847734d..8eba9ebc7bcd 100755
--- a/utils/analyzer/CmpRuns
+++ b/utils/analyzer/CmpRuns.py
@@ -44,6 +44,11 @@ class multidict:
#
+class CmpOptions:
+ def __init__(self, verboseLog=None, root=""):
+ self.root = root
+ self.verboseLog = verboseLog
+
class AnalysisReport:
def __init__(self, run, files):
self.run = run
@@ -85,7 +90,7 @@ class AnalysisRun:
return path[len(self.opts.root):]
return path
-def loadResults(path, opts):
+def loadResults(path, opts, deleteEmpty=True):
run = AnalysisRun(path, opts)
for f in os.listdir(path):
@@ -96,8 +101,10 @@ def loadResults(path, opts):
p = os.path.join(path, f)
data = plistlib.readPlist(p)
- # Ignore empty reports.
+ # Ignore/delete empty reports.
if not data['files']:
+ if deleteEmpty == True:
+ os.remove(p)
continue
# Extract the HTML reports, if they exists.
@@ -170,26 +177,10 @@ def compareResults(A, B):
return res
-def main():
- from optparse import OptionParser
- parser = OptionParser("usage: %prog [options] [dir A] [dir B]")
- parser.add_option("", "--root", dest="root",
- help="Prefix to ignore on source files",
- action="store", type=str, default="")
- parser.add_option("", "--verbose-log", dest="verboseLog",
- help="Write additional information to LOG [default=None]",
- action="store", type=str, default=None,
- metavar="LOG")
- (opts, args) = parser.parse_args()
-
- if len(args) != 2:
- parser.error("invalid number of arguments")
-
- dirA,dirB = args
-
+def cmpScanBuildResults(dirA, dirB, opts, deleteEmpty=True):
# Load the run results.
- resultsA = loadResults(dirA, opts)
- resultsB = loadResults(dirB, opts)
+ resultsA = loadResults(dirA, opts, deleteEmpty)
+ resultsB = loadResults(dirB, opts, deleteEmpty)
# Open the verbose log, if given.
if opts.verboseLog:
@@ -198,21 +189,25 @@ def main():
auxLog = None
diff = compareResults(resultsA, resultsB)
+ foundDiffs = False
for res in diff:
a,b,confidence = res
if a is None:
print "ADDED: %r" % b.getReadableName()
+ foundDiffs = True
if auxLog:
print >>auxLog, ("('ADDED', %r, %r)" % (b.getReadableName(),
b.getReportData()))
elif b is None:
print "REMOVED: %r" % a.getReadableName()
+ foundDiffs = True
if auxLog:
print >>auxLog, ("('REMOVED', %r, %r)" % (a.getReadableName(),
a.getReportData()))
elif confidence:
print "CHANGED: %r to %r" % (a.getReadableName(),
b.getReadableName())
+ foundDiffs = True
if auxLog:
print >>auxLog, ("('CHANGED', %r, %r, %r, %r)"
% (a.getReadableName(),
@@ -224,7 +219,28 @@ def main():
print "TOTAL REPORTS: %r" % len(resultsB.diagnostics)
if auxLog:
- print >>auxLog, "('TOTAL', %r)" % len(resultsB.diagnostics)
+ print >>auxLog, "('TOTAL REPORTS', %r)" % len(resultsB.diagnostics)
+
+ return foundDiffs
+
+def main():
+ from optparse import OptionParser
+ parser = OptionParser("usage: %prog [options] [dir A] [dir B]")
+ parser.add_option("", "--root", dest="root",
+ help="Prefix to ignore on source files",
+ action="store", type=str, default="")
+ parser.add_option("", "--verbose-log", dest="verboseLog",
+ help="Write additional information to LOG [default=None]",
+ action="store", type=str, default=None,
+ metavar="LOG")
+ (opts, args) = parser.parse_args()
+
+ if len(args) != 2:
+ parser.error("invalid number of arguments")
+
+ dirA,dirB = args
+
+ cmpScanBuildResults(dirA, dirB, opts)
if __name__ == '__main__':
main()
diff --git a/utils/analyzer/SATestAdd.py b/utils/analyzer/SATestAdd.py
new file mode 100644
index 000000000000..9fab07bfa9f0
--- /dev/null
+++ b/utils/analyzer/SATestAdd.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+
+"""
+Static Analyzer qualification infrastructure: adding a new project to
+the Repository Directory.
+
+ Add a new project for testing: build it and add to the Project Map file.
+ Assumes it's being run from the Repository Directory.
+ The project directory should be added inside the Repository Directory and
+ have the same name as the project ID
+
+ The project should use the following files for set up:
+ - pre_run_static_analyzer.sh - prepare the build environment.
+ Ex: make clean can be a part of it.
+ - run_static_analyzer.cmd - a list of commands to run through scan-build.
+ Each command should be on a separate line.
+ Choose from: configure, make, xcodebuild
+"""
+import SATestBuild
+
+import os
+import csv
+import sys
+
+# Add a new project for testing: build it and add to the Project Map file.
+# Params:
+# Dir is the directory where the sources are.
+# ID is a short string used to identify a project.
+def addNewProject(ID) :
+ CurDir = os.path.abspath(os.curdir)
+ Dir = SATestBuild.getProjectDir(ID)
+ if not os.path.exists(Dir):
+ print "Error: Project directory is missing: %s" % Dir
+ sys.exit(-1)
+
+ # Build the project.
+ SATestBuild.testProject(ID, True, Dir)
+
+ # Add the project ID to the project map.
+ ProjectMapPath = os.path.join(CurDir, SATestBuild.ProjectMapFile)
+ if os.path.exists(ProjectMapPath):
+ PMapFile = open(ProjectMapPath, "r+b")
+ else:
+ print "Warning: Creating the Project Map file!!"
+ PMapFile = open(ProjectMapPath, "w+b")
+ try:
+ PMapReader = csv.reader(PMapFile)
+ for I in PMapReader:
+ IID = I[0]
+ if ID == IID:
+ print >> sys.stderr, 'Warning: Project with ID \'', ID, \
+ '\' already exists.'
+ sys.exit(-1)
+
+ PMapWriter = csv.writer(PMapFile)
+ PMapWriter.writerow( (ID, Dir) );
+ finally:
+ PMapFile.close()
+
+ print "The project map is updated: ", ProjectMapPath
+
+
+# TODO: Add an option not to build.
+# TODO: Set the path to the Repository directory.
+if __name__ == '__main__':
+ if len(sys.argv) < 2:
+ print >> sys.stderr, 'Usage: ', sys.argv[0],\
+ '[project ID]'
+ sys.exit(-1)
+
+ addNewProject(sys.argv[1])
diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py
new file mode 100644
index 000000000000..c2209cc93cfc
--- /dev/null
+++ b/utils/analyzer/SATestBuild.py
@@ -0,0 +1,307 @@
+#!/usr/bin/env python
+
+"""
+Static Analyzer qualification infrastructure.
+
+The goal is to test the analyzer against different projects, check for failures,
+compare results, and measure performance.
+
+Repository Directory will contain sources of the projects as well as the
+information on how to build them and the expected output.
+Repository Directory structure:
+ - ProjectMap file
+ - Historical Performance Data
+ - Project Dir1
+ - ReferenceOutput
+ - Project Dir2
+ - ReferenceOutput
+ ..
+
+To test the build of the analyzer one would:
+ - Copy over a copy of the Repository Directory. (TODO: Prefer to ensure that
+ the build directory does not pollute the repository to min network traffic).
+ - Build all projects, until error. Produce logs to report errors.
+ - Compare results.
+
+The files which should be kept around for failure investigations:
+ RepositoryCopy/Project DirI/ScanBuildResults
+ RepositoryCopy/Project DirI/run_static_analyzer.log
+
+Assumptions (TODO: shouldn't need to assume these.):
+ The script is being run from the Repository Directory.
+ The compiler for scan-build is in the PATH.
+ export PATH=/Users/zaks/workspace/c2llvm/build/Release+Asserts/bin:$PATH
+
+For more logging, set the env variables:
+ zaks:TI zaks$ export CCC_ANALYZER_LOG=1
+ zaks:TI zaks$ export CCC_ANALYZER_VERBOSE=1
+"""
+import CmpRuns
+
+import os
+import csv
+import sys
+import glob
+import shutil
+import time
+import plistlib
+from subprocess import check_call
+
+# Project map stores info about all the "registered" projects.
+ProjectMapFile = "projectMap.csv"
+
+# Names of the project specific scripts.
+# The script that needs to be executed before the build can start.
+PreprocessScript = "pre_run_static_analyzer.sh"
+# This is a file containing commands for scan-build.
+BuildScript = "run_static_analyzer.cmd"
+
+# The log file name.
+BuildLogName = "run_static_analyzer.log"
+# Summary file - contains the summary of the failures. Ex: This info can be be
+# displayed when buildbot detects a build failure.
+NumOfFailuresInSummary = 10
+FailuresSummaryFileName = "failures.txt"
+# Summary of the result diffs.
+DiffsSummaryFileName = "diffs.txt"
+
+# The scan-build result directory.
+SBOutputDirName = "ScanBuildResults"
+SBOutputDirReferencePrefix = "Ref"
+
+Verbose = 1
+
+def getProjectMapPath():
+ ProjectMapPath = os.path.join(os.path.abspath(os.curdir),
+ ProjectMapFile)
+ if not os.path.exists(ProjectMapPath):
+ print "Error: Cannot find the Project Map file " + ProjectMapPath +\
+ "\nRunning script for the wrong directory?"
+ sys.exit(-1)
+ return ProjectMapPath
+
+def getProjectDir(ID):
+ return os.path.join(os.path.abspath(os.curdir), ID)
+
+# Run pre-processing script if any.
+def runPreProcessingScript(Dir, PBuildLogFile):
+ ScriptPath = os.path.join(Dir, PreprocessScript)
+ if os.path.exists(ScriptPath):
+ try:
+ if Verbose == 1:
+ print " Executing: %s" % (ScriptPath,)
+ check_call("chmod +x %s" % ScriptPath, cwd = Dir,
+ stderr=PBuildLogFile,
+ stdout=PBuildLogFile,
+ shell=True)
+ check_call(ScriptPath, cwd = Dir, stderr=PBuildLogFile,
+ stdout=PBuildLogFile,
+ shell=True)
+ except:
+ print "Error: The pre-processing step failed. See ", \
+ PBuildLogFile.name, " for details."
+ sys.exit(-1)
+
+# Build the project with scan-build by reading in the commands and
+# prefixing them with the scan-build options.
+def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
+ BuildScriptPath = os.path.join(Dir, BuildScript)
+ if not os.path.exists(BuildScriptPath):
+ print "Error: build script is not defined: %s" % BuildScriptPath
+ sys.exit(-1)
+ SBOptions = "-plist -o " + SBOutputDir + " "
+ SBOptions += "-enable-checker core,deadcode.DeadStores"
+ try:
+ SBCommandFile = open(BuildScriptPath, "r")
+ SBPrefix = "scan-build " + SBOptions + " "
+ for Command in SBCommandFile:
+ SBCommand = SBPrefix + Command
+ if Verbose == 1:
+ print " Executing: %s" % (SBCommand,)
+ check_call(SBCommand, cwd = Dir, stderr=PBuildLogFile,
+ stdout=PBuildLogFile,
+ shell=True)
+ except:
+ print "Error: scan-build failed. See ",PBuildLogFile.name,\
+ " for details."
+ sys.exit(-1)
+
+def buildProject(Dir, SBOutputDir):
+ TBegin = time.time()
+
+ BuildLogPath = os.path.join(Dir, BuildLogName)
+ print "Log file: %s" % (BuildLogPath,)
+
+ # Clean up the log file.
+ if (os.path.exists(BuildLogPath)) :
+ RmCommand = "rm " + BuildLogPath
+ if Verbose == 1:
+ print " Executing: %s." % (RmCommand,)
+ check_call(RmCommand, shell=True)
+
+ # Open the log file.
+ PBuildLogFile = open(BuildLogPath, "wb+")
+ try:
+ # Clean up scan build results.
+ if (os.path.exists(SBOutputDir)) :
+ RmCommand = "rm -r " + SBOutputDir
+ if Verbose == 1:
+ print " Executing: %s" % (RmCommand,)
+ check_call(RmCommand, stderr=PBuildLogFile,
+ stdout=PBuildLogFile, shell=True)
+
+ runPreProcessingScript(Dir, PBuildLogFile)
+ runScanBuild(Dir, SBOutputDir, PBuildLogFile)
+ finally:
+ PBuildLogFile.close()
+
+ print "Build complete (time: %.2f). See the log for more details: %s" % \
+ ((time.time()-TBegin), BuildLogPath)
+
+# A plist file is created for each call to the analyzer(each source file).
+# We are only interested on the once that have bug reports, so delete the rest.
+def CleanUpEmptyPlists(SBOutputDir):
+ for F in glob.glob(SBOutputDir + "/*/*.plist"):
+ P = os.path.join(SBOutputDir, F)
+
+ Data = plistlib.readPlist(P)
+ # Delete empty reports.
+ if not Data['files']:
+ os.remove(P)
+ continue
+
+# Given the scan-build output directory, checks if the build failed
+# (by searching for the failures directories). If there are failures, it
+# creates a summary file in the output directory.
+def checkBuild(SBOutputDir):
+ # Check if there are failures.
+ Failures = glob.glob(SBOutputDir + "/*/failures/*.stderr.txt")
+ TotalFailed = len(Failures);
+ if TotalFailed == 0:
+ CleanUpEmptyPlists(SBOutputDir)
+ Plists = glob.glob(SBOutputDir + "/*/*.plist")
+ print "Number of bug reports (non empty plist files) produced: %d" %\
+ len(Plists)
+ return;
+
+ # Create summary file to display when the build fails.
+ SummaryPath = os.path.join(SBOutputDir, FailuresSummaryFileName);
+ if (Verbose > 0):
+ print " Creating the failures summary file %s." % (SummaryPath,)
+
+ SummaryLog = open(SummaryPath, "w+")
+ try:
+ SummaryLog.write("Total of %d failures discovered.\n" % (TotalFailed,))
+ if TotalFailed > NumOfFailuresInSummary:
+ SummaryLog.write("See the first %d below.\n"
+ % (NumOfFailuresInSummary,))
+ # TODO: Add a line "See the results folder for more."
+
+ FailuresCopied = NumOfFailuresInSummary
+ Idx = 0
+ for FailLogPathI in glob.glob(SBOutputDir + "/*/failures/*.stderr.txt"):
+ if Idx >= NumOfFailuresInSummary:
+ break;
+ Idx += 1
+ SummaryLog.write("\n-- Error #%d -----------\n" % (Idx,));
+ FailLogI = open(FailLogPathI, "r");
+ try:
+ shutil.copyfileobj(FailLogI, SummaryLog);
+ finally:
+ FailLogI.close()
+ finally:
+ SummaryLog.close()
+
+ print "Error: Scan-build failed. See ", \
+ os.path.join(SBOutputDir, FailuresSummaryFileName)
+ sys.exit(-1)
+
+# Auxiliary object to discard stdout.
+class Discarder(object):
+ def write(self, text):
+ pass # do nothing
+
+# Compare the warnings produced by scan-build.
+def runCmpResults(Dir):
+ TBegin = time.time()
+
+ RefDir = os.path.join(Dir, SBOutputDirReferencePrefix + SBOutputDirName)
+ NewDir = os.path.join(Dir, SBOutputDirName)
+
+ # We have to go one level down the directory tree.
+ RefList = glob.glob(RefDir + "/*")
+ NewList = glob.glob(NewDir + "/*")
+ if len(RefList) == 0 or len(NewList) == 0:
+ return False
+ assert(len(RefList) == len(NewList))
+
+ # There might be more then one folder underneath - one per each scan-build
+ # command (Ex: one for configure and one for make).
+ if (len(RefList) > 1):
+ # Assume that the corresponding folders have the same names.
+ RefList.sort()
+ NewList.sort()
+
+ # Iterate and find the differences.
+ HaveDiffs = False
+ PairList = zip(RefList, NewList)
+ for P in PairList:
+ RefDir = P[0]
+ NewDir = P[1]
+
+ assert(RefDir != NewDir)
+ if Verbose == 1:
+ print " Comparing Results: %s %s" % (RefDir, NewDir)
+
+ DiffsPath = os.path.join(NewDir, DiffsSummaryFileName)
+ Opts = CmpRuns.CmpOptions(DiffsPath)
+ # Discard everything coming out of stdout (CmpRun produces a lot of them).
+ OLD_STDOUT = sys.stdout
+ sys.stdout = Discarder()
+ # Scan the results, delete empty plist files.
+ HaveDiffs = CmpRuns.cmpScanBuildResults(RefDir, NewDir, Opts, False)
+ sys.stdout = OLD_STDOUT
+ if HaveDiffs:
+ print "Warning: difference in diagnostics. See %s" % (DiffsPath,)
+ HaveDiffs=True
+
+ print "Diagnostic comparison complete (time: %.2f)." % (time.time()-TBegin)
+ return HaveDiffs
+
+def testProject(ID, IsReferenceBuild, Dir=None):
+ TBegin = time.time()
+
+ if Dir is None :
+ Dir = getProjectDir(ID)
+ if Verbose == 1:
+ print " Build directory: %s." % (Dir,)
+
+ # Set the build results directory.
+ if IsReferenceBuild == True :
+ SBOutputDir = os.path.join(Dir, SBOutputDirReferencePrefix + \
+ SBOutputDirName)
+ else :
+ SBOutputDir = os.path.join(Dir, SBOutputDirName)
+
+ buildProject(Dir, SBOutputDir)
+
+ checkBuild(SBOutputDir)
+
+ if IsReferenceBuild == False:
+ runCmpResults(Dir)
+
+ print "Completed tests for project %s (time: %.2f)." % \
+ (ID, (time.time()-TBegin))
+
+def testAll(IsReferenceBuild=False):
+ PMapFile = open(getProjectMapPath(), "rb")
+ try:
+ PMapReader = csv.reader(PMapFile)
+ for I in PMapReader:
+ print " --- Building project %s" % (I[0],)
+ testProject(I[0], IsReferenceBuild)
+ finally:
+ PMapFile.close()
+
+if __name__ == '__main__':
+ testAll()
diff --git a/utils/clangVisualizers.txt b/utils/clangVisualizers.txt
new file mode 100644
index 000000000000..f9f834b76c50
--- /dev/null
+++ b/utils/clangVisualizers.txt
@@ -0,0 +1,44 @@
+
+[Visualizer]
+
+llvm::SmallVector<*,*>{
+ preview (
+ #(
+ "[",
+ ($T1*)$e.EndX - ($T1*)$e.BeginX,
+ "](",
+ #array(
+ expr: (($T1*)$e.BeginX)[$i],
+ size: ($T1*)$e.EndX - ($T1*)$e.BeginX
+ ),
+ ")"
+ )
+ )
+
+ children (
+ #(
+ #([size] : ($T1*)$e.EndX - ($T1*)$e.BeginX),
+ #([capacity] : ($T1*)$e.CapacityX - ($T1*)$e.BeginX),
+ #array(
+ expr: (($T1*)$e.BeginX)[$i],
+ size: ($T1*)$e.EndX - ($T1*)$e.BeginX
+ )
+ )
+ )
+}
+
+llvm::StringRef{
+ preview ([$e.Data,s])
+ stringview ([$e.Data,sb])
+
+ children (
+ #(
+ #([size] : $e.Length),
+ #array(expr: $e.Data[$i], size: $e.Length)
+ )
+ )
+}
+
+clang::Token{
+ preview((clang::tok::TokenKind)(int)$e.Kind)
+} \ No newline at end of file
diff --git a/www/OpenProjects.html b/www/OpenProjects.html
index b3e0841a73a1..fec23dc14aaa 100644
--- a/www/OpenProjects.html
+++ b/www/OpenProjects.html
@@ -78,8 +78,8 @@ improve the quality of clang by self-testing. Some examples:
</ul>
</li>
-<li><b>Continue work on C++'0x support</b>:
- C++'98 is feature complete, but there is still a lot of C++'0x featuers to
+<li><b>Continue work on C++'11 support</b>:
+ 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>
diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl
index 76b88ddd9041..8d7b58de215d 100644
--- a/www/analyzer/latest_checker.html.incl
+++ b/www/analyzer/latest_checker.html.incl
@@ -1 +1 @@
-<b><a href="/checker/checker-257.tar.bz2">checker-257.tar.bz2</a></b> (built May 25, 2011)
+<b><a href="/checker/checker-258.tar.bz2">checker-258.tar.bz2</a></b> (built October 13, 2011)
diff --git a/www/analyzer/release_notes.html b/www/analyzer/release_notes.html
index 4a568f51e471..311c5aecd5c8 100644
--- a/www/analyzer/release_notes.html
+++ b/www/analyzer/release_notes.html
@@ -15,6 +15,19 @@
<h1>Release notes for <tt>checker-XXX</tt> builds</h1>
+<h4 id="checker_258">checker-258</h4>
+
+<p><b>built:</b>October 13, 2011<br>
+<b>download:</b> <a href="/checker/checker-258.tar.bz2">checker-258.tar.bz2</a></p>
+<p><b>highlights:</b></p>
+
+<ul>
+ <li>Contains a newer version of the analyzer than the one shipped in Xcode 4.2.</li>
+ <li>Adds a new security checker for looking at correct uses of the Mac OS KeyChain API.</li>
+ <li>Supports ARC (please file bugs where you see issues)</li>
+ <li>Major under-the-cover changes. This should result in more precise results in some cases, but this is laying the groundwork for major improvements. Please file bugs where you see regressions or issues.</li>
+</ul>
+
<h4 id="checker_257">checker-257</h4>
<p><b>built:</b>May 25, 2011<br>
diff --git a/www/comparison.html b/www/comparison.html
index a7d4d75a2e59..4b72a8527179 100644
--- a/www/comparison.html
+++ b/www/comparison.html
@@ -50,7 +50,7 @@
<ul>
<li>GCC supports languages that clang does not aim to, such as Java, Ada,
FORTRAN, etc.</li>
- <li>GCC has a few <a href="cxx_status.html">C++'0x features</a> that Clang
+ <li>GCC has a few <a href="cxx_status.html">C++'11 features</a> that Clang
does not yet support.</li>
<li>GCC supports more targets than LLVM.</li>
<li>GCC is popular and widely adopted.</li>
@@ -133,7 +133,7 @@
<ul>
<li>Clang's C and C++ support is far more mature and practically useful than
- Elsa's, and includes many C++'0x features.</li>
+ Elsa's, and includes many C++'11 features.</li>
<li>The Elsa community is extremely small and major development work seems
to have ceased in 2005. Work continued to be used by other small
projects (e.g. Oink), but Oink is apparently dead now too. Clang has a
diff --git a/www/compatibility.html b/www/compatibility.html
index 783758f3ac80..2102ccca7e1d 100644
--- a/www/compatibility.html
+++ b/www/compatibility.html
@@ -60,6 +60,12 @@
<li><a href="#param_name_lookup">Parameter name lookup</a></li>
</ul>
</li>
+ <li><a href="#c++11">C++11 compatibility</a>
+ <ul>
+ <li><a href="#deleted-special-func">Deleted special member
+ functions</a></li>
+ </ul>
+ </li>
<li><a href="#objective-c++">Objective-C++ compatibility</a>
<ul>
<li><a href="#implicit-downcasts">Implicit downcasts</a></li>
@@ -755,7 +761,39 @@ void f(int a, int a);
<p>Clang diagnoses this error (where the parameter name has been redeclared). To fix this problem, rename one of the parameters.</p>
<!-- ======================================================================= -->
-<h2 id="objective-c++">Objective-C++ compatibility</h3>
+<h2 id="c++11">C++11 compatibility</h2>
+<!-- ======================================================================= -->
+
+<!-- ======================================================================= -->
+<h3 id="deleted-special-func">Deleted special member functions</h3>
+<!-- ======================================================================= -->
+
+<p>In C++11, the explicit declaration of a move constructor or a move
+assignment operator within a class disables the implicit declaration
+of the copy constructor and copy assignment operator. This change came
+fairly late in the C++11 standardization process, so early
+implementations of C++11 (including Clang before 3.0, GCC before 4.7,
+and Visual Studio 2010) do not implement this rule, leading them to
+accept this ill-formed code:</p>
+
+<pre>
+struct X {
+ X(X&amp;&amp;); <i>// suppresses implicit copy constructor</i>
+};
+
+void f(X x);
+void g(X x) {
+ f(x); <i>// error: X has no copy constructor</i>
+}
+</pre>
+
+<p>This affects some C++11 code, including Boost's popular <a
+href="http://www.boost.org/doc/libs/release/libs/smart_ptr/shared_ptr.htm"><tt>shared_ptr</tt></a>
+up to version 1.47.0. The fix for Boost's <tt>shared_ptr</tt> is
+<a href="https://svn.boost.org/trac/boost/changeset/73202">available here</a>.</p>
+
+<!-- ======================================================================= -->
+<h2 id="objective-c++">Objective-C++ compatibility</h2>
<!-- ======================================================================= -->
<!-- ======================================================================= -->
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 5998de822ebb..3fb1ef614bd0 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -3,7 +3,7 @@
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>Clang - C++ and C++'0x Status</title>
+ <title>Clang - C++ and C++'11 Status</title>
<link type="text/css" rel="stylesheet" href="menu.css">
<link type="text/css" rel="stylesheet" href="content.css">
<style type="text/css">
@@ -23,666 +23,347 @@
<div id="content">
<!--*************************************************************************-->
-<h1>C++ and C++'0x Support in Clang</h1>
+<h1>C++ and C++'11 Support in Clang</h1>
<!--*************************************************************************-->
-<p>Last updated: $Date: 2011-05-06 00:07:51 +0200 (Fri, 06 May 2011) $</p>
+<p>Last updated: $Date: 2011-10-15 01:35:48 +0200 (Sat, 15 Oct 2011) $</p>
- <ul>
- <li><a href="#projects">Projects Building with Clang</a></li>
- <li><a href="#specification">Implementation Status by Section</a></li>
- <li><a href="#cxx0x">C++0x Status</a></li>
- </ul>
-
-<p>Clang currently implements all of the ISO C++ 1998 standard (including
- the defects addressed in the ISO C++ 2003 standard) except for 'export'
- (which has been removed from the C++'0x draft).
- The <a href="http://llvm.org/bugs/">LLVM bug tracker</a>
- contains a Clang C++ component that tracks known Clang C++ bugs.</p>
+<p>Clang currently implements all of the ISO C++ 1998 standard
+ (including the defects addressed in the ISO C++ 2003 standard)
+ except for 'export' (which has been removed in C++'11)
+ and is considered a production-quality C++ compiler. The <a
+ href="http://llvm.org/bugs/">LLVM bug tracker</a> contains a Clang
+ C++ component that tracks known Clang C++ bugs.</p>
- <h2 id="projects">Projects Building with Clang</h2>
+<h2 id="cxx11">C++11 Implementation status</h2>
- <p>Clang is now capable of compiling large C++ projects, and the following
- table describes various projects that we have attempted to compile with
- Clang++.</p>
+ <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>
-<table width="689" border="1" cellspacing="0">
- <tr>
- <th>Project</th>
- <th>Status</th>
- <th>Last Tested</th>
- <th>Tracking Bug</th>
- </tr>
- <tr>
- <td><a href="http://clang.llvm.org">Clang</a> and <a href="http://llvm.org">LLVM</a></td>
- <td>Successful self-hosting achieved</td>
- <td>Continually</td>
- <td></td>
- </tr>
- <tr>
- <td><a href="http://www.cmake.org">CMake</a></td>
- <td>Compiles, passes regression tests (debug build)</td>
- <td>February 9, 2010</td>
- <td></td>
- </tr>
- <tr>
- <td><a href="http://www.boost.org">Boost</a></td>
- <td><a href="http://blog.llvm.org/2010/05/clang-builds-boost.html">Compiles
- and passes regression tests</a> on Darwin/X86-64.</td>
- <td>May 20, 2010</td>
- <td><a href="http://llvm.org/bugs/show_bug.cgi?id=6023"><del>PR6023</del></a></td>
- </tr>
- <tr>
- <td><a href="http://qt.nokia.com">Qt</a></td>
- <td>Partially compiles; miscompilation of uic prevents complete compilation, qmake works, some small examples also.</td>
- <td>February 9, 2010</td>
- <td><a href="http://llvm.org/bugs/show_bug.cgi?id=5881">PR5881</a></td>
- </tr>
-</table>
-
-<h2 id="cxx0x">C++0x Implementation status</h2>
-
-<p>Clang's development effort is focused primarily on fixing bugs in the current
-ISO C++ standard (1998/2003). This section tracks the status of various C++0x
-features.</p>
-
-<p>You can use clang in C++0x mode either
+<p>You can use Clang in C++11 mode either
with <a href="http://libcxx.llvm.org/">libc++</a> or with gcc's libstdc++.
libstdc++-4.4 requires <a href="libstdc++4.4-clang0x.patch">a patch</a> to work
with clang; other versions have not been tested.</p>
-
-<h2 id="specification">Implementation Status by Feature</h2>
-
-
-<!-- Within this table: The colors we're using to color-code our level
-of support for a given section:
-
- White (no background): not considered/tested.
- #C11B17: Broken.
- #F88017: Some useful examples work
- #FDD017: Many examples work
- #347C17: Nearly everything works
- #00FF00 + check mark: Implementation complete!
- -->
-
-<p>The following table is used to help track our implementation
- progress toward implementing the complete C++'0x standard. We use a
- simple, somewhat arbitrary color-coding scheme to describe the
- relative completeness of features:</p>
-
<table width="689" border="1" cellspacing="0">
- <tr>
- <th>Not started/not evaluated</th>
- <th>Not Applicable</th>
- <th>Broken</th>
- <th>Some examples work</th>
- <th>Many examples work</th>
- <th>Nearly everything works</th>
- <th>Complete</th>
-<!--
- <th>Complete (with tests for each paragraph)</th>
--->
- </tr>
- <tr>
- <td></td>
- <td class="na">N/A</td>
- <td class="broken"></td>
- <td class="basic"></td>
- <td class="medium"></td>
- <td class="advanced"></td>
- <td class="complete">rXXXXXX</td>
-<!--
- <td class="complete" align="center">&#x2713;</td>
--->
- </tr>
-</table>
-
-<p>In addition, boxes marked with &#x2713 have complete and passing tests.
- Similarly, boxes marked with &#x2717 have complete tests, some of which
- are failing, and a <b>?</b> indicates partial tests while not making any
- statement about passing status.</p>
-
-<p>A feature is "complete" when the appropriate Clang component (Parse, AST,
-Sema, CodeGen) implements the behavior described in all of the
-paragraphs in the relevant C++'0x draft standard. The major
-components are:</p>
-
-<dl>
- <dt>Parse</dt>
- <dd>Clang is able to parse the grammar of this feature (or the grammar
- described by this section), but does not necessarily do anything with the
- parsed result. Use Clang's <code>-fsyntax-only</code> option to parse C++
- programs.</dd>
+ <tr>
+ <th bgcolor="#ffddaa">Language Feature</th>
+ <th bgcolor="#ffddaa">C++0x Proposal</th>
+ <th bgcolor="#ffddaa">Available in Clang?</th>
+ </tr>
+ <tr>
+ <td>Rvalue references</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html">N2118</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;Rvalue references for <code>*this</code></td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2439.htm">N2439</a></td>
+ <td align="center">Clang 2.9<br/></td>
+ </tr>
+ <tr>
+ <td>Initialization of class objects by rvalues</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1610.html">N1610</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>Non-static data member initializers</td>
+ <td><a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2756.htm">N2756</a></td>
+ <td align="center">Clang 3.0</a></td>
+ </tr>
+ <tr>
+ <td>Variadic templates</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf">N2242</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;Extending variadic template template parameters</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf">N2555</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>Initializer lists</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2672.htm">N2672</a></td>
+ <td align="center">No</td>
+ </tr>
+ <tr>
+ <td>Static assertions</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html">N1720</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td><code>auto</code>-typed variables</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf">N1984</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;Multi-declarator <code>auto</code></td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1737.pdf">N1737</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;Removal of auto as a storage-class specifier</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2546.htm">N2546</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;New function declarator syntax</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm">N2541</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>New wording for C++0x lambdas</td>
+ <td><a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2927.pdf">N2927</a></td>
+ <td align="center">No</td>
+ </tr>
+ <tr>
+ <td>Declared type of an expression</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2343.pdf">N2343</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>Right angle brackets</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1757.html">N1757</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>Default template arguments for function templates</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#226">DR226</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>Solving the SFINAE problem for expressions</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.html">DR339</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>Alias templates</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf">N2258</a></td>
+ <td align="center">Clang 3.0</td>
+ </tr>
+ <tr>
+ <td>Extern templates</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1987.htm">N1987</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>Null pointer constant</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf">N2431</a></td>
+ <td align="center">Clang 3.0</td>
+ </tr>
+ <tr>
+ <td>Strongly-typed enums</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf">N2347</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>Forward declarations for enums</td>
+ <td>
+ <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf">N2764
+ </a></td>
+ <td align="center">No</td>
+ </tr>
+ <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 align="center">No</td>
+ </tr>
+ <tr>
+ <td>Generalized constant expressions</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf">N2235</a></td>
+ <td align="center">No</td>
+ </tr>
+ <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 align="center">Clang 3.0</td>
+ </tr>
+ <!-- Skipped N1627: Conditionally-support behavior -->
+ <!-- Skipped N1727: Changing Undefined Behavior into Diagnosable Errors -->
+ <tr>
+ <td>Delegating constructors</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986.pdf">N1986</a></td>
+ <td align="center">Clang 3.0<br/></td>
+ </tr>
+ <tr>
+ <td>Inheriting constructors</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm">N2540</a></td>
+ <td align="center">No</td>
+ </tr>
+ <tr>
+ <td>Explicit conversion operators</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf">N2437</a></td>
+ <td align="center">Clang 3.0</td>
+ </tr>
+ <tr>
+ <td>New character types</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2249.html">N2249</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>Unicode string literals</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm">N2442</a></td>
+ <td align="center">Clang 3.0</td>
+ </tr>
+ <tr>
+ <td>Raw string literals</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm">N2442</a></td>
+ <td align="center">Clang 3.0</td>
+ </tr>
+ <tr>
+ <td>Universal character name literals</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2170.html">N2170</a></td>
+ <td align="center">No</td>
+ </tr>
+ <tr>
+ <td>User-defined literals</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2765.pdf">N2765</a></td>
+ <td align="center">No</td>
+ </tr>
+ <tr>
+ <td>Standard Layout Types</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2342.htm">N2342</a></td>
+ <td align="center">Clang 3.0</td>
+ </tr>
+ <tr>
+ <td>Defaulted and deleted functions</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm">N2346</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>Extended friend declarations</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1791.pdf">N1791</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>Extending <code>sizeof</code></td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2253.html">N2253</a></td>
+ <td align="center">No</td>
+ </tr>
+ <tr>
+ <td>Inline namespaces</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2535.htm">N2535</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>Unrestricted unions</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf">N2544</a></td>
+ <td align="center">No</td>
+ </tr>
+ <tr>
+ <td>Local and unnamed types as template arguments</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm">N2657</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>Range-based for</td>
+ <td><a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2930.html">N2930</a></td>
+ <td align="center">Clang 3.0</td>
+ </tr>
+ <tr>
+ <td>Explicit virtual overrides</td>
+ <td><a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2928.htm">N2928</a>
+ <br/><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3206.htm">N3206</a>
+<br/><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3272.htm">N3272</a></td>
+ <td align="center">Clang 3.0</td>
+ </tr>
+ <tr>
+ <td>Minimal support for garbage collection and reachability-based leak detection</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2670.htm">N2670</a></td>
+ <td align="center">No</td>
+ </tr>
+ <tr>
+ <td>Allowing move constructors to throw [noexcept]</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3050.htm">N3050</a></td>
+ <td align="center">Clang 3.0</td>
+ </tr>
+ <tr>
+ <td>Defining move special member functions</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3053.htm">N3053</a></td>
+ <td align="center">Clang 3.0</td>
+ </tr>
- <dt>AST</dt>
- <dd>Clang builds an abstract syntax tree (AST) for the feature, but does not
- necessarily perform any type-checking. Use Clang's <code>-ast-print</code>
- option to print the resulting ASTs.</dd>
+ <tr class="separator">
+ <th align="center" colspan="3" bgcolor="#ffddaa">Concurrency</th>
+ </tr>
+ <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 align="center">No</td>
+ </tr>
+ <tr>
+ <td>Atomic operations</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2427.html">N2427</a></td>
+ <td align="center">No</td>
+ </tr>
+ <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 align="center">No</td>
+ </tr>
+ <tr>
+ <td>Bidirectional Fences</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2752.htm">N2752</a></td>
+ <td align="center">No</td>
+ </tr>
- <dt>Sema</dt>
- <dd>Clang parses and type-checks this feature and provides a well-formed AST
- annotated with types. Use Clang's <code>-fsyntax-only</code> to type-check
- code.</dd>
-
- <dt>CodeGen</dt>
- <dd>Clang parses, type-checks, and generates code for this feature, allowing
- one to compile and execute programs.</dd>
-</dl>
-
-<p>Updates to this table are welcome! Tests for the various features are also
-welcome!</p>
-
-<table width="689" border="1" cellspacing="0">
-<tr><td colspan="7" align="center" bgcolor="#ffddaa">C++0x Features (current draft report <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3291.pdf">here</a>)</td>
-</tr>
- <tr>
- <th>Feature</th>
- <th>Parse</th>
- <th>AST</th>
- <th>Sema</th>
- <th>CodeGen</th>
- <th>Standard Sections</th>
- <th>Notes</th>
- </tr>
-<tr><td colspan="7" class="category">Control Flow Modifications</td></tr>
-<tr>
- <td>Range-based for loop</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td>6.5.4</td>
- <td><a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2007/n2243.html">N2243</a>
- <a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2011/n3271.htm">N3271</a></td>
-</tr>
+ <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 align="center">No</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 align="center">No</td>
+ </tr>
+ <tr>
+ <td>Propagating exceptions</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html">N2179</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>Abandoning a process and at_quick_exit</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2440.htm">N2440</a></td>
+ <td align="center">No</td>
+ </tr>
+ <tr>
+ <td>Allow atomics use in signal handlers</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2547.htm">N2547</a></td>
+ <td align="center"><span class="unsupported">No</span></td>
+ </tr>
+ <tr>
+ <td>Thread-local storage</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2659.htm">N2659</a></td>
+ <td align="center">No</td>
+ </tr>
+ <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 align="center">No</td>
+ </tr>
-<tr><td colspan="7" class="category">Type System Modifications</td></tr>
-<tr>
- <td>rvalue references</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete"></td>
- <td>8.3.2</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html">N2118</a>,
- <a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2831.html">N2831</a> <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2439.htm">N2439</a>
- </td>
-</tr>
-<tr>
- <td>decltype</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td>7.1.6.2</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2343.pdf">N2343</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1478.pdf">N1478</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1978.pdf">N1978</a>
- </td>
-</tr>
-<tr>
- <td>auto type deduction</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td>7.1.6.2, 7.1.6.4</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf">N1984</a></td>
-</tr>
-<tr>
- <td>nullptr</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="medium" align="center"></td>
- <td class="broken"></td>
- <td>2.14.7, 4.10, 4.11</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf">N2431</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1488.pdf">N1488</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2214.pdf">N2214</a>
- </td>
-</tr>
-<tr>
- <td>enum classes</td>
- <td class="complete"></td>
- <td class="advanced"></td>
- <td class="advanced"></td>
- <td></td>
- <td>7.2</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1513.pdf">N1513</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf">N2347</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2499.pdf">N2499</a>
- Includes forward declaration capability
- </td>
-</tr>
-<tr>
- <td>long long</td>
- <td class="complete"></td>
- <td class="complete"></td>
- <td class="complete"></td>
- <td class="complete"></td>
- <td>3.9.1</td>
- <td>C99
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1811.pdf">N1811</a>
- </td>
-</tr>
-<tr>
- <td>constexpr</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td>3.6.2, 3.9, 5.19, 7.1.5</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1521.pdf">N1521</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf">N2235</a>
- </td>
-</tr>
-<tr>
- <td>char16_t/char32_t</td>
- <td class="medium"></td>
- <td class="medium"></td>
- <td class="medium"></td>
- <td class="medium"></td>
- <td></td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2249.html">N2249</a></td>
-</tr>
-<tr>
- <td>Unicode string literal types</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td>2.14.3, 2.14.5</td>
- <td></td>
-</tr>
-<tr>
- <td>Raw string literal types</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td>2.14.5</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2053.html">N2053</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.html">N2442</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2378.pdf">N2378</a>
- </td>
-</tr>
-<tr>
- <td>user-defined literal types</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td>2.14.8</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2378.pdf">N2378</a></td>
-</tr>
-<tr>
- <td>POD definition changes</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td>3.9, 9</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2294.html">N2294</a></td>
-</tr>
-<tr>
- <td>Unrestricted unions</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td>9.5</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf">N2544</a></td>
-</tr>
-<tr>
- <td>Tighter narrowing rules</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td>8.5.4</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1890.pdf">N1890</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2215.pdf">N2215</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2640.pdf">N2640</a>
- </td>
-</tr>
-<tr><td colspan="7" class="category">Class Modifications</td></tr>
-<tr>
- <td>delegating constructors</td>
- <td class="complete"></td>
- <td class="complete"></td>
- <td class="complete"></td>
- <td class="complete"></td>
- <td>12.6.2</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986">N1986</a></td>
-</tr>
-<tr>
- <td>inheriting constructors</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td>12.9</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1890.pdf">N1890</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1898.pdf">N1898</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2512.html">N2512</a>
- </td>
-</tr>
-<tr>
- <td>In-declaration member initialization</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2628.html">N2628</a></td>
-</tr>
-<tr>
- <td>Changes to implicitly generated methods</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td>Includes implicit generation of move operations</td>
-</tr>
-<tr>
- <td>defaulted methods</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1717.pdf">N1717</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2326.html">N2326</a>
- </td>
-</tr>
-<tr>
- <td>destructor defaults to noexcept</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>sizeof on members without object instance</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2150.html">N2150</a></td>
-</tr>
-<tr>
- <td>virtual function safety modifications</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>Explicit conversion operators</td>
- <td class="complete" align="center"></td>
- <td class="basic" align="center"></td>
- <td class="basic" align="center"></td>
- <td class="broken"></td>
- <td>12.3</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf">N2437</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2333.html">N2333</a>
- No name mangling; ASTs don't contain calls to conversion operators</td>
-</tr>
-<tr><td colspan="7" class="category">Template Modifications</td></tr>
-<tr>
- <td>Right angle brackets</td>
- <td class="complete" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td class="na">N/A</td>
- <td></td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1757.html">N1757</a></td>
-</tr>
-<tr>
- <td>variadic templates</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td>14.6.3</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2080.pdf">N2080</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2087.pdf">N2087</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf">N2242</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2488.pdf">N2488</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf">N2555</a>
- </td>
-</tr>
-<tr>
- <td>template aliases</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td>7.1.3, 14.6.7</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1489.pdf">N1489</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf">N2258</a>
- </td>
-</tr>
-<tr>
- <td>Removal of export</td>
- <td class="complete"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td></td>
- <td>This was never implemented in C++03</td>
-</tr>
-<tr>
- <td>extern templates</td>
- <td class="complete"></td>
- <td class="complete"></td>
- <td class="complete"></td>
- <td class="complete"></td>
- <td>14.8.2</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1987.htm">N1987</a></td>
-</tr>
-<tr>
- <td>Local classes as template parameters</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2402.pdf">N2402</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm">N2657</a>
- </td>
-</tr>
-<tr><td colspan="7" class="category">Exception Modifications</td></tr>
-<tr>
- <td>Deprecation of exception specifications</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td>15.4</td>
- <td></td>
-</tr>
-<tr>
- <td>noexcept</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="na">N/A</td>
- <td>5.3.7, 15.4</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3050.html">N3050</a></td>
-</tr>
-<tr><td colspan="7" class="category">Preprocessor Modifications</td></tr>
-<tr>
- <td>__STDC_HOSTED__</td>
- <td class="complete"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td>16.8</td>
- <td>C99
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1568.htm">N1568</a>
- </td>
-</tr>
-<tr>
- <td>_Pragma</td>
- <td class="complete"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td>16.9</td>
- <td>C99
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1568.htm">N1568</a>
- </td>
-</tr>
-<tr>
- <td>Variable argument macros</td>
- <td class="complete"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td>16.3</td>
- <td>C99
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1568.htm">N1568</a>
- </td>
-</tr>
-<tr>
- <td>Empty macro arguments</td>
- <td class="complete"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td>16.3</td>
- <td>C99
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1568.htm">N1568</a>
- </td>
-</tr>
-<tr>
- <td>__func__</td>
- <td class="complete"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td>8.4.1</td>
- <td>C99
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1568.htm">N1568</a>
- </td>
-</tr>
-<tr>
- <td>__cplusplus</td>
- <td class="complete"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td>16.8</td>
- <td></td>
-</tr>
-<tr><td colspan="7" class="category">Things Completely New</td></tr>
-<tr>
- <td>Late-specified return type</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="na">N/A</td>
- <td>8.3.5</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2445.html">N2445</a></td>
-</tr>
-<tr>
- <td>lambda expressions</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td>5.1.2</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1968.htm">N1968</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2550.pdf">N2550</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2859.pdf">N2859</a>
- </td>
-</tr>
-<tr>
- <td>Uniform initializers </td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td>12.6</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2215.pdf">N2215</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2640.pdf">N2640</a>
- </td>
-</tr>
-<tr>
- <td>Memory model</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td>1.7</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2556.html">N2556</a></td>
-</tr>
-<tr><td colspan="7" class="category">Miscellania</td></tr>
-<tr>
- <td>Standard attribute syntax</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2418.pdf">N2418</a></td>
-</tr>
-<tr>
- <td>alignment control</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>Deleted functions</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="medium" align="center"></td>
- <td class="na">N/A</td>
- <td>8.4.3</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2326.htm">N2326</a></br>
- This also includes class methods.</td>
-</tr>
-<tr>
- <td>static_assert</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na">N/A</td>
- <td>7</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1381.htm">N1381</a>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.pdf">N1720</a>
- </td>
-</tr>
-<tr>
- <td>Inline namespaces</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">N/A</td>
- <td>7.3.1</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2535.htm">N2535</a></td>
-</tr>
-<tr>
- <td>thread_local storage</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td>3.7.2, 7.1.1</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm">N2660</a></td>
-</tr>
-<tr><td colspan="7" class="category">Standard Library Modifications, see <a href="http://libcxx.llvm.org/index.html">libc++</a> or <a href="http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt01ch01.html#manual.intro.status.standard.200x">libstdc++</a> or <a href="http://blogs.msdn.com/b/vcblog/archive/2010/07/02/video-introduction-to-the-stl-part-1.aspx">VC++ 2010</a></td></tr>
+ <tr class="separator">
+ <th align="center" colspan="3" bgcolor="#ffddaa">C99 Features in C++0x</th>
+ </tr>
+ <tr>
+ <td><code>__func__</code> predefined identifier</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2340.htm">N2340</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>C99 preprocessor</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1653.htm">N1653</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td><code>long long</code></td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1811.pdf">N1811</a></td>
+ <td align="center">Clang 2.9</td>
+ </tr>
+ <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 align="center">No</td>
+ </tr>
</table>
<br />
</div>
diff --git a/www/demo/index.cgi b/www/demo/index.cgi
index b29efb60e9cc..901b009dbdea 100644
--- a/www/demo/index.cgi
+++ b/www/demo/index.cgi
@@ -269,7 +269,7 @@ sub try_run {
alarm 0;
};
if ( $@ and $@ =~ /timeout/ ) {
- barf("Program $program took too long, compile time limited for the web script, sorry!.\n");
+ barf("Program $program took too long, compile time limited for the web script, sorry!\n");
}
if ( -s $outputFile ) {
print scalar dumpFile( "Output from $program", $outputFile );
diff --git a/www/diagnostics.html b/www/diagnostics.html
index 48d222abb2f2..b3b168b88836 100644
--- a/www/diagnostics.html
+++ b/www/diagnostics.html
@@ -104,10 +104,8 @@ quickly.</p>
<h2>No Pretty Printing of Expressions in Diagnostics</h2>
<p>Since Clang has range highlighting, it never needs to pretty print your code
-back out to you. This is particularly bad in G++ (which often emits errors
-containing lowered vtable references), but even GCC can produce
-inscrutible error messages in some cases when it tries to do this. In this
-example P and Q have type "int*":</p>
+back out to you. GCC can produce inscrutible error messages in some cases when
+it tries to do this. In this example P and Q have type "int*":</p>
<pre>
$ <b>gcc-4.2 -fsyntax-only t.c</b>
@@ -118,6 +116,31 @@ example P and Q have type "int*":</p>
<font color="blue"> ~~~~~^</font>
</pre>
+<p>This can be particularly bad in G++, which often emits errors
+ containing lowered vtable references. For example:</p>
+
+<pre>
+ $ <b>cat t.cc</b>
+ struct a {
+ virtual int bar();
+ };
+
+ struct foo : public virtual a {
+ };
+
+ void test(foo *P) {
+ return P->bar() + *P;
+ }
+ $ <b>gcc-4.2 t.cc</b>
+ t.cc: In function 'void test(foo*)':
+ t.cc:9: error: no match for 'operator+' in '(((a*)P) + (*(long int*)(P-&gt;foo::&lt;anonymous&gt;.a::_vptr$a + -0x00000000000000020)))-&gt;a::bar() + * P'
+ t.cc:9: error: return-statement with a value, in function returning 'void'
+ $ <b>clang t.cc</b>
+ t.cc:9:18: <font color="red">error:</font> invalid operands to binary expression ('int' and 'foo')
+ <font color="darkgreen"> return P->bar() + *P;</font>
+ <font color="blue"> ~~~~~~~~ ^ ~~</font>
+</pre>
+
<h2>Typedef Preservation and Selective Unwrapping</h2>
@@ -169,7 +192,7 @@ namespace myapp {
}
using namespace myapp;
-void addHTTPService(servers::Server const &server, ::services::WebService const *http) {
+void addHTTPService(servers::Server const &amp;server, ::services::WebService const *http) {
server += http;
}
</pre>
diff --git a/www/get_involved.html b/www/get_involved.html
index a383d7013225..eb9a97945b06 100644
--- a/www/get_involved.html
+++ b/www/get_involved.html
@@ -54,7 +54,36 @@ href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits">cfe-commits mailing
list</a>. All of these lists have archives, so you can browse through previous
discussions or follow the list development on the web if you prefer.</p>
-<p>If you're looking for something to work on, check out our <a href="OpenProjects.html">Open Projects</a> page or go look through the <a href="http://llvm.org/bugs/">Bugzilla bug database.</p>
+<p>If you're looking for something to work on, check out our <a href="OpenProjects.html">Open Projects</a> page or go look through the <a href="http://llvm.org/bugs/">Bugzilla bug database</a>.</p>
+
+<h2 name="criteria">Contributing Extensions to Clang</h2>
+
+<p>Clang has always been designed as a platform for experimentation,
+allowing programmers to easily extend the compiler to support great
+new language features and tools. At some point, the authors of these
+extensions may propose that the extensions become a part of Clang
+itself, to benefit the whole Clang community. But not every idea--not
+even every great idea--should become part of Clang. Extensions
+(particularly language extensions) pose a long-term maintenance burden
+on Clang, and therefore the benefits of the extension must outweight
+those costs. Hence, these are the seven criteria used to evaluate the
+merits of a proposed extension:</p>
+
+<ol>
+ <li>Evidence of a significant user community: This is based on a number of factors, including an actual, existing user community, the perceived likelihood that users would adopt such a feature if it were available, and any "trickle-down" effects that come from, e.g., a library adopting the feature and providing benefits to its users.</li>
+
+ <li>A specific need to reside within the Clang tree: There are some extensions that would be better expressed as a separate tool, and should remain as separate tools even if they end up being hosted as part of the LLVM umbrella project.</li>
+
+ <li>A complete specification: The specification must be sufficient to understand the design of the feature as well as interpret the meaning of specific examples. The specification should be detailed enough that another compiler vendor could conceivably implement the feature.</li>
+
+ <li>Representation within the appropriate governing organization: For extensions to a language governed by a standards committee (C, C++, OpenCL), the extension itself must have an active proposal and proponent within that committee and have a reasonable chance of acceptance. Clang should drive the standard, not diverge from it. This criterion does not apply to all extensions, since some extensions fall outside of the realm of the standards bodies.</li>
+
+ <li>A long-term support plan: Contributing a non-trivial extension to Clang implies a commitment to supporting that extension, improving the implementation and specification as Clang evolves. The capacity of the contributor to make that commitment is as important as the commitment itself.</li>
+
+ <li>A high-quality implementation: The implementation must fit well into Clang's architecture, follow LLVM's coding conventions, and meet Clang's quality standards, including high-quality diagnostics and rich AST representations. This is particularly important for language extensions, because users will learn how those extensions work through the behavior of the compiler.</li>
+
+ <li>A proper test suite: Extensive testing is crucial to ensure that the language extension is not broken by ongoing maintenance in Clang. The test suite should be complete enough that another compiler vendor could conceivably validate their implementation of the feature against it.</li>
+</ol>
</div>
</body>
diff --git a/www/get_started.html b/www/get_started.html
index f8745f96bcbc..515cd57ce259 100644
--- a/www/get_started.html
+++ b/www/get_started.html
@@ -165,7 +165,7 @@ Visual Studio:</p>
more information on other configuration options for cmake.</li>
</li>
<li>The above, if successful, will have created an LLVM.sln file in the
- llvm directory.
+ <tt>build</tt> directory.
</ul>
<li>Build Clang:</li>
<ul>
diff --git a/www/hacking.html b/www/hacking.html
index 969a39c55998..b65768c9873a 100644
--- a/www/hacking.html
+++ b/www/hacking.html
@@ -86,6 +86,28 @@
</ul>
<!--=====================================================================-->
+ <h3 id="debuggingVisualStudio">Debugging using Visual Studio</h3>
+ <!--=====================================================================-->
+
+ <p>The file <tt>utils/clangVisualizers.txt</tt> provides debugger visualizers that make debugging
+ of more complex data types much easier.</p>
+ <p>There are two ways to install them:</p>
+
+ <ul>
+ <li>Put the path to <tt>clangVisualizers.txt</tt> in the environment variable called
+ <tt>_vcee_autoexp</tt>. This method should work for Visual Studio 2008 and above.
+ </li>
+ <li>Edit your local <tt>autoexp.dat</tt> (make sure you make a backup first!),
+ located in <tt>Visual Studio Directory\Common7\Packages\Debugger</tt> and append
+ the contents of <tt>clangVisuailzers.txt</tt> to it. This method should work for
+ Visual Studio 2005 and above.
+ </li>
+ </ul>
+
+ <p><i>[Note: To disable the visualizer for any specific variable, type
+ <tt>variable_name,!</tt> inside the watch window.]</i></p>
+
+ <!--=====================================================================-->
<h2 id="testing">Testing</h2>
<!--=====================================================================-->
diff --git a/www/index.html b/www/index.html
index 623f7198827a..095eed790df8 100644
--- a/www/index.html
+++ b/www/index.html
@@ -94,7 +94,7 @@
targeting X86-32, X86-64, and ARM (other targets may have caveats, but are
usually easy to fix). If you are looking for source analysis or
source-to-source transformation tools, clang is probably a great
- solution for you. Clang does not support C++'0x yet, please see the <a
+ solution for you. Clang does not support C++'11 yet, please see the <a
href="cxx_status.html">C++ status</a> page for more
information.</p>
diff --git a/www/menu.html.incl b/www/menu.html.incl
index 4acfbe54f966..878e678f64ac 100644
--- a/www/menu.html.incl
+++ b/www/menu.html.incl
@@ -53,8 +53,9 @@
</div>
<div class="submenu">
- <label>Events</label>
- <a href="http://llvm.org/devmtg/2009-10/">October 2, 2009 - LLVM/Clang Developer Meeting</a>
+ <label>Clang Events</label>
+ <a href="http://llvm.org/devmtg/2009-10/">October 2009</a>
+ <a href="http://llvm.org/devmtg/2010-11/">November 2010</a>
</div>
</div>